Skip to content

Commit

Permalink
feat: macro event += and -= to :Connect() and :Disconnect() respectively
Browse files Browse the repository at this point in the history
  • Loading branch information
R-unic committed Jan 8, 2025
1 parent 458e4cc commit bc49608
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 14 deletions.
8 changes: 4 additions & 4 deletions RobloxCS.Luau/AstUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -334,16 +334,16 @@ public static IdentifierName GetNonGenericName(SimpleName simpleName)
: simpleName.ToString());
}

public static Name CreateName(string text)
public static Name CreateName(SyntaxNode node, string text, bool registerIdentifier = false, bool bypassReserved = false)
{
Name expression = new IdentifierName(text);
Name name = CreateSimpleName(node, text, registerIdentifier, bypassReserved);
var pieces = text.Split('.');
if (pieces.Length <= 0)
return expression;
return name;

return pieces
.Skip(1)
.Aggregate(expression, (current, piece) => new QualifiedName(current, new IdentifierName(piece)));
.Aggregate(name, (current, piece) => new QualifiedName(current, CreateSimpleName(node, piece)));
}

public static TNameNode CreateSimpleName<TNameNode>(SyntaxNode node, bool registerIdentifier = false, bool bypassReserved = false)
Expand Down
72 changes: 71 additions & 1 deletion RobloxCS.Luau/Macros.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,83 @@ public enum MacroKind
ObjectMethod,
IEnumerableMethod,
ListMethod,
DictionaryMethod
DictionaryMethod,
BitOperation
}

public class Macro(SemanticModel semanticModel)
{
private SemanticModel _semanticModel { get; } = semanticModel;

public Node? Assignment(Func<SyntaxNode, Node?> visit, AssignmentExpressionSyntax assignment)
{
var mappedOperator = StandardUtility.GetMappedOperator(assignment.OperatorToken.Text);
var bit32MethodName = StandardUtility.GetBit32MethodName(mappedOperator);
if (bit32MethodName != null)
{
var target = (AssignmentTarget)visit(assignment.Left)!;
var value = (Expression)visit(assignment.Right)!;
var bit32Call = AstUtility.Bit32Call(bit32MethodName, target, value);
bit32Call.MarkExpanded(MacroKind.BitOperation);

return new Assignment(target, AstUtility.Bit32Call(bit32MethodName, target, value));
}

var leftSymbol = _semanticModel.GetSymbolInfo(assignment.Left).Symbol;
if (leftSymbol is IEventSymbol eventSymbol)
{
var symbolMetadata = SymbolMetadataManager.Get(eventSymbol);
symbolMetadata.EventConnectionName ??= AstUtility.CreateSimpleName<IdentifierName>(assignment, "conn_" + eventSymbol.Name, registerIdentifier: true);

var connectionName = symbolMetadata.EventConnectionName;
switch (mappedOperator)
{
case "+=":
{
var left = (Expression)visit(assignment.Left)!;
var right = (Expression)visit(assignment.Right)!;
return new Variable(
connectionName,
true,
new Call(
new MemberAccess(left, new IdentifierName("Connect"), ':'),
new ArgumentList([new Argument(right)])
)
);
}
case "-=":
{
return new Call(
new MemberAccess(connectionName, new IdentifierName("Disconnect"), ':'),
new ArgumentList([])
);
}
}
}

return null;
}

public Expression? BinaryExpression(Func<SyntaxNode, Node?> visit, BinaryExpressionSyntax binaryExpression)
{
var mappedOperator = StandardUtility.GetMappedOperator(binaryExpression.OperatorToken.Text);
var bit32MethodName = StandardUtility.GetBit32MethodName(mappedOperator);
if (bit32MethodName != null)
{
var left = (Expression)visit(binaryExpression.Left)!;
var right = (Expression)visit(binaryExpression.Right)!;
var bit32Call = AstUtility.Bit32Call(bit32MethodName, left, right);
bit32Call.MarkExpanded(MacroKind.BitOperation);

return bit32Call;
}

return null;
}

/// <summary>
/// Takes a C# generic name and expands the name into a macro'd type
/// </summary>
public Name? GenericName(Func<SyntaxNode, Node?> visit, GenericNameSyntax genericName)
{
var typeInfo = _semanticModel.GetTypeInfo(genericName);
Expand Down
22 changes: 22 additions & 0 deletions RobloxCS.Luau/SymbolMetadataManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Microsoft.CodeAnalysis;

namespace RobloxCS;

public class SymbolMetadata
{
public Luau.IdentifierName? EventConnectionName { get; set; }
}

public static class SymbolMetadataManager
{
private static readonly Dictionary<ISymbol, SymbolMetadata> _metadata = [];

public static SymbolMetadata Get(ISymbol symbol)
{
var metadata = _metadata.GetValueOrDefault(symbol);
if (metadata == null)
_metadata.Add(symbol, metadata = new SymbolMetadata());

return metadata;
}
}
18 changes: 9 additions & 9 deletions RobloxCS/LuauGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -588,16 +588,16 @@ public override Luau.Variable VisitAnonymousObjectMemberDeclarator(AnonymousObje

public override Luau.Node VisitAssignmentExpression(AssignmentExpressionSyntax node)
{
var expanded = _macro.Assignment(Visit, node);
if (expanded != null)
return expanded;

var mappedOperator = StandardUtility.GetMappedOperator(node.OperatorToken.Text);
var name = Visit<Luau.AssignmentTarget>(node.Left);
var value = Visit<Luau.Expression>(node.Right);
if (node.IsKind(SyntaxKind.SimpleAssignmentExpression))
return new Luau.Assignment(name, value);

var mappedOperator = StandardUtility.GetMappedOperator(node.OperatorToken.Text);
var bit32MethodName = StandardUtility.GetBit32MethodName(mappedOperator);
if (bit32MethodName != null)
return new Luau.Assignment(name, Luau.AstUtility.Bit32Call(bit32MethodName, name, value));

return new Luau.BinaryOperator(name, mappedOperator, value);
}

Expand Down Expand Up @@ -687,13 +687,13 @@ public override Luau.Block VisitBlock(BlockSyntax node)

public override Luau.Node VisitBinaryExpression(BinaryExpressionSyntax node)
{
var expanded = _macro.BinaryExpression(Visit, node);
if (expanded != null)
return expanded;

var left = Visit<Luau.Expression>(node.Left);
var right = Visit<Luau.Expression>(node.Right);
var mappedOperator = StandardUtility.GetMappedOperator(node.OperatorToken.Text);
var bit32MethodName = StandardUtility.GetBit32MethodName(mappedOperator);
if (bit32MethodName != null)
return Luau.AstUtility.Bit32Call(bit32MethodName, left, right);

return new Luau.BinaryOperator(left, mappedOperator, right);
}

Expand Down
3 changes: 3 additions & 0 deletions RobloxCS/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ Key:
- `?` -> will maybe be added

In no particular order:
- [ ] disallow method grouping with methods from objects/classes
- [ ] only generate interface declarations & inherit from interfaces if they have methods with implementations
- [ ] map `dynamic` to no type at all
- [ ] a LOT more testing
- [ ] generation tests
- [ ] luau rendering tests (mostly done)
- [ ] utility tests
- [ ] save navigation (`a?.b?.c`)
- [ ] macro `ToNumber()`, `ToUInt()`, `ToFloat()`, etc. (defined in Roblox.cs in RobloxCS.Types) to `tonumber()`
- [ ] prefix increment/decrement (`++a`, `--a`)
Expand Down

0 comments on commit bc49608

Please sign in to comment.