diff --git a/RobloxCS.Luau/AST/AST.cs b/RobloxCS.Luau/AST/AST.cs index b544f95..94272a7 100644 --- a/RobloxCS.Luau/AST/AST.cs +++ b/RobloxCS.Luau/AST/AST.cs @@ -1,21 +1,20 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class AST : Node { - public class AST : Node - { - public List Statements { get; } + public List Statements { get; } - public AST(List statements) - { - Statements = statements; - AddChildren(Statements); - } + public AST(List statements) + { + Statements = statements; + AddChildren(Statements); + } - public override void Render(LuauWriter luau) - { - foreach (var statement in Statements) - statement.Render(luau); + public override void Render(LuauWriter luau) + { + foreach (var statement in Statements) + statement.Render(luau); - luau.WriteReturn(); - } + luau.WriteReturn(); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/AnonymousFunction.cs b/RobloxCS.Luau/AST/AnonymousFunction.cs index 72fcd7c..706618d 100644 --- a/RobloxCS.Luau/AST/AnonymousFunction.cs +++ b/RobloxCS.Luau/AST/AnonymousFunction.cs @@ -1,35 +1,34 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class AnonymousFunction : Expression { - public class AnonymousFunction : Expression - { - public ParameterList ParameterList { get; } - public Block? Body { get; } - public TypeRef? ReturnType { get; } - public List AttributeLists { get; } + public ParameterList ParameterList { get; } + public Block? Body { get; } + public TypeRef? ReturnType { get; } + public List AttributeLists { get; } - public AnonymousFunction(ParameterList parameterList, TypeRef? returnType = null, - Block? body = null, - List? attributeLists = null) + public AnonymousFunction(ParameterList parameterList, TypeRef? returnType = null, + Block? body = null, + List? attributeLists = null) + { + ParameterList = parameterList; + Body = body; + Body = body; + ReturnType = returnType; + AttributeLists = attributeLists ?? []; AddChild(ParameterList); + AddChild(ParameterList); + if (ReturnType != null) + { + AddChild(ReturnType); + } + if (Body != null) { - ParameterList = parameterList; - Body = body; - Body = body; - ReturnType = returnType; - AttributeLists = attributeLists ?? []; AddChild(ParameterList); - AddChild(ParameterList); - if (ReturnType != null) - { - AddChild(ReturnType); - } - if (Body != null) - { - AddChild(Body); - } - AddChildren(AttributeLists); + AddChild(Body); } - - public override void Render(LuauWriter luau) => - luau.WriteFunction(null, false, ParameterList, ReturnType, Body, AttributeLists, - inlineAttributes: true, createNewline: false); + AddChildren(AttributeLists); } + + public override void Render(LuauWriter luau) => + luau.WriteFunction(null, false, ParameterList, ReturnType, Body, AttributeLists, + inlineAttributes: true, createNewline: false); } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/Argument.cs b/RobloxCS.Luau/AST/Argument.cs index e78f4fd..4dec381 100644 --- a/RobloxCS.Luau/AST/Argument.cs +++ b/RobloxCS.Luau/AST/Argument.cs @@ -1,18 +1,14 @@ -namespace RobloxCS.Luau -{ - public class Argument : Expression - { - public Expression Expression { get; set; } +namespace RobloxCS.Luau; - public Argument(Expression expression) - { - Expression = expression; - AddChild(Expression); - } +public class Argument : Expression +{ + public Expression Expression { get; set; } - public override void Render(LuauWriter luau) - { - Expression.Render(luau); - } + public Argument(Expression expression) + { + Expression = expression; + AddChild(Expression); } -} + + public override void Render(LuauWriter luau) => Expression.Render(luau); +} \ No newline at end of file diff --git a/RobloxCS.Luau/AST/ArgumentList.cs b/RobloxCS.Luau/AST/ArgumentList.cs index 84a52d2..756cbe7 100644 --- a/RobloxCS.Luau/AST/ArgumentList.cs +++ b/RobloxCS.Luau/AST/ArgumentList.cs @@ -1,20 +1,19 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class ArgumentList : Expression { - public class ArgumentList : Expression - { - public List Arguments { get; set; } + public List Arguments { get; set; } - public ArgumentList(List arguments) - { - Arguments = arguments; - AddChildren(Arguments.OfType().ToList()); - } + public ArgumentList(List arguments) + { + Arguments = arguments; + AddChildren(Arguments); + } - public override void Render(LuauWriter luau) - { - luau.Write('('); - luau.WriteNodesCommaSeparated(Arguments); - luau.Write(')'); - } + public override void Render(LuauWriter luau) + { + luau.Write('('); + luau.WriteNodesCommaSeparated(Arguments); + luau.Write(')'); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/ArrayType.cs b/RobloxCS.Luau/AST/ArrayType.cs index 12a6daf..2082cf6 100644 --- a/RobloxCS.Luau/AST/ArrayType.cs +++ b/RobloxCS.Luau/AST/ArrayType.cs @@ -1,13 +1,13 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class ArrayType : TypeRef { - public class ArrayType : TypeRef - { - public TypeRef ElementType { get; } + public TypeRef ElementType { get; } - public ArrayType(TypeRef elementType) - : base("{ " + elementType.Path + " }", true) - { - ElementType = elementType; - } + public ArrayType(TypeRef elementType) + : base("{ " + elementType.Path + " }", true) + { + ElementType = elementType; + AddChild(ElementType); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/Assignment.cs b/RobloxCS.Luau/AST/Assignment.cs index 9760f03..a98eeec 100644 --- a/RobloxCS.Luau/AST/Assignment.cs +++ b/RobloxCS.Luau/AST/Assignment.cs @@ -1,23 +1,22 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public sealed class Assignment : Expression { - public sealed class Assignment : Expression - { - public AssignmentTarget Target { get; } - public Expression Value { get; private set; } + public AssignmentTarget Target { get; } + public Expression Value { get; private set; } - public Assignment(AssignmentTarget target, Expression value) - { - Target = target; - Value = value; - AddChildren([Target, Value]); - } + public Assignment(AssignmentTarget target, Expression value) + { + Target = target; + Value = value; + AddChildren([Target, Value]); + } - public override void Render(LuauWriter luau) - { - Node value = Value; - luau.WriteDescendantStatements(ref value); - Value = (Expression)value; - luau.WriteAssignment(Target, Value); - } + public override void Render(LuauWriter luau) + { + Node value = Value; + luau.WriteDescendantStatements(ref value); + Value = (Expression)value; + luau.WriteAssignment(Target, Value); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/AssignmentFunctionName.cs b/RobloxCS.Luau/AST/AssignmentFunctionName.cs deleted file mode 100644 index 21f4297..0000000 --- a/RobloxCS.Luau/AST/AssignmentFunctionName.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace RobloxCS.Luau -{ - public class AssignmentFunctionName : Name - { - public Name Left { get; } - public char Operator { get; set; } - public SimpleName Right { get; } - - public AssignmentFunctionName(Name left, SimpleName right, char @operator = '.') - { - Left = left; - Right = right; - Operator = @operator; - AddChildren([Left, Right]); - } - - public override void Render(LuauWriter luau) - { - Left.Render(luau); - luau.Write(Operator); - Right.Render(luau); - } - - public override string ToString() - { - return Left.ToString() + Operator + Right.ToString(); - } - } -} \ No newline at end of file diff --git a/RobloxCS.Luau/AST/AssignmentTarget.cs b/RobloxCS.Luau/AST/AssignmentTarget.cs index 624b2ed..990a2e7 100644 --- a/RobloxCS.Luau/AST/AssignmentTarget.cs +++ b/RobloxCS.Luau/AST/AssignmentTarget.cs @@ -1,6 +1,3 @@ -namespace RobloxCS.Luau -{ - public abstract class AssignmentTarget : Expression - { - } -} \ No newline at end of file +namespace RobloxCS.Luau; + +public abstract class AssignmentTarget : Expression; \ No newline at end of file diff --git a/RobloxCS.Luau/AST/AttributeList.cs b/RobloxCS.Luau/AST/AttributeList.cs index e65545c..3ce7647 100644 --- a/RobloxCS.Luau/AST/AttributeList.cs +++ b/RobloxCS.Luau/AST/AttributeList.cs @@ -1,24 +1,30 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class AttributeList : Statement { - public class AttributeList : Statement - { - public List Attributes { get; } - public bool Inline { get; set; } = false; + public List Attributes { get; } + public bool Inline { get; set; } = false; - public AttributeList(List attributes) - { - Attributes = attributes; - } + public AttributeList(List attributes) + { + Attributes = attributes; + AddChildren(Attributes); + } - public override void Render(LuauWriter luau) + public override void Render(LuauWriter luau) + { + foreach (var attribute in Attributes) { - foreach (var attribute in Attributes) + if (attribute is BuiltInAttribute) { attribute.Render(luau); - if (!Inline) - { - luau.WriteLine(); - } + + if (Inline) continue; + luau.WriteLine(); + } + else + { + // TODO: user-defined attribute stuff } } } diff --git a/RobloxCS.Luau/AST/BaseAttribute.cs b/RobloxCS.Luau/AST/BaseAttribute.cs deleted file mode 100644 index 87265df..0000000 --- a/RobloxCS.Luau/AST/BaseAttribute.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace RobloxCS.Luau -{ - public abstract class BaseAttribute : Statement - { - } -} \ No newline at end of file diff --git a/RobloxCS.Luau/AST/BinaryOperator.cs b/RobloxCS.Luau/AST/BinaryOperator.cs index 08fc068..9c6016a 100644 --- a/RobloxCS.Luau/AST/BinaryOperator.cs +++ b/RobloxCS.Luau/AST/BinaryOperator.cs @@ -1,27 +1,23 @@ -namespace RobloxCS.Luau -{ - public class BinaryOperator : Expression - { - public Expression Left { get; } - public string Operator { get; } - public Expression Right { get; } +namespace RobloxCS.Luau; - public BinaryOperator(Expression left, string @operator, Expression right) - { - Left = left; - Operator = @operator; - Right = right; - AddChildren([Left, Right]); - } +public class BinaryOperator : Expression +{ + public Expression Left { get; } + public string Operator { get; } + public Expression Right { get; } - public override void Render(LuauWriter luau) - { - Left.Render(luau); - luau.Write($" {Operator} "); - Right.Render(luau); - } + public BinaryOperator(Expression left, string @operator, Expression right) + { + Left = left; + Operator = @operator; + Right = right; + AddChildren([Left, Right]); + } - public BinaryOperator WithLeft(Expression left) => new BinaryOperator(left, Operator, Right); - public BinaryOperator WithRight(Expression right) => new BinaryOperator(Left, Operator, right); + public override void Render(LuauWriter luau) + { + Left.Render(luau); + luau.Write($" {Operator} "); + Right.Render(luau); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/Block.cs b/RobloxCS.Luau/AST/Block.cs index 2aef145..cd39fd3 100644 --- a/RobloxCS.Luau/AST/Block.cs +++ b/RobloxCS.Luau/AST/Block.cs @@ -1,15 +1,14 @@ -namespace RobloxCS.Luau -{ - public class Block : Statement - { - public List Statements { get; } +namespace RobloxCS.Luau; - public Block(List statements) - { - Statements = statements; - AddChildren(Statements); - } +public class Block : Statement +{ + public List Statements { get; } - public override void Render(LuauWriter luau) => luau.WriteNodes(Statements); + public Block(List statements) + { + Statements = statements; + AddChildren(Statements); } -} + + public override void Render(LuauWriter luau) => luau.WriteNodes(Statements); +} \ No newline at end of file diff --git a/RobloxCS.Luau/AST/Break.cs b/RobloxCS.Luau/AST/Break.cs index 6743b1e..208e7e0 100644 --- a/RobloxCS.Luau/AST/Break.cs +++ b/RobloxCS.Luau/AST/Break.cs @@ -1,10 +1,6 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class Break : Statement { - public class Break : Statement - { - public override void Render(LuauWriter luau) - { - luau.WriteLine("break"); - } - } + public override void Render(LuauWriter luau) => luau.WriteLine("break"); } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/BuiltInAttribute.cs b/RobloxCS.Luau/AST/BuiltInAttribute.cs index b37aec1..20588e8 100644 --- a/RobloxCS.Luau/AST/BuiltInAttribute.cs +++ b/RobloxCS.Luau/AST/BuiltInAttribute.cs @@ -1,19 +1,23 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class BuiltInAttribute : Statement { - public class BuiltInAttribute : BaseAttribute + public Name Name { get; } + public bool Inline { get; } + + public BuiltInAttribute(Name name, bool inline = false) { - public Name Name { get; } + Name = name; + Inline = inline; + AddChild(name); + } - public BuiltInAttribute(Name name) - { - Name = name; - AddChild(name); - } + public override void Render(LuauWriter luau) + { + luau.Write('@'); + Name.Render(luau); - public override void Render(LuauWriter luau) - { - luau.Write('@'); - Name.Render(luau); - } + if (Inline) return; + luau.WriteLine(); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/Call.cs b/RobloxCS.Luau/AST/Call.cs index 2fb14c7..00cca98 100644 --- a/RobloxCS.Luau/AST/Call.cs +++ b/RobloxCS.Luau/AST/Call.cs @@ -19,8 +19,5 @@ public override void Render(LuauWriter luau) luau.WriteNodesCommaSeparated(ArgumentList.Arguments); luau.Write(')'); } - - public Call WithArgumentList(ArgumentList argumentList) => new(Callee, argumentList); - public Call WithCallee(Expression callee) => new(callee, ArgumentList); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/Continue.cs b/RobloxCS.Luau/AST/Continue.cs index a79126e..331d1a2 100644 --- a/RobloxCS.Luau/AST/Continue.cs +++ b/RobloxCS.Luau/AST/Continue.cs @@ -1,10 +1,6 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class Continue : Statement { - public class Continue : Statement - { - public override void Render(LuauWriter luau) - { - luau.WriteLine("continue"); - } - } + public override void Render(LuauWriter luau) => luau.WriteLine("continue"); } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/ElementAccess.cs b/RobloxCS.Luau/AST/ElementAccess.cs index 75a44e7..26b7b09 100644 --- a/RobloxCS.Luau/AST/ElementAccess.cs +++ b/RobloxCS.Luau/AST/ElementAccess.cs @@ -1,27 +1,26 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public sealed class ElementAccess : AssignmentTarget { - public sealed class ElementAccess : AssignmentTarget - { - public Expression Expression { get; } - public Expression Index { get; set; } + public Expression Expression { get; } + public Expression Index { get; set; } - public ElementAccess(Expression expression, Expression index) - { - Expression = expression; - Index = index; - AddChildren([Expression, Index]); - } + public ElementAccess(Expression expression, Expression index) + { + Expression = expression; + Index = index; + AddChildren([Expression, Index]); + } - public override void Render(LuauWriter luau) - { - Node index = Index; - luau.WriteDescendantStatements(ref index); - Index = (Expression)index; + public override void Render(LuauWriter luau) + { + Node index = Index; + luau.WriteDescendantStatements(ref index); + Index = (Expression)index; - Expression.Render(luau); - luau.Write('['); - Index.Render(luau); - luau.Write(']'); - } + Expression.Render(luau); + luau.Write('['); + Index.Render(luau); + luau.Write(']'); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/Expression.cs b/RobloxCS.Luau/AST/Expression.cs index 76ef19e..b4aee57 100644 --- a/RobloxCS.Luau/AST/Expression.cs +++ b/RobloxCS.Luau/AST/Expression.cs @@ -1,6 +1,3 @@ -namespace RobloxCS.Luau -{ - public abstract class Expression : Node - { - } -} +namespace RobloxCS.Luau; + +public abstract class Expression : Node; \ No newline at end of file diff --git a/RobloxCS.Luau/AST/ExpressionStatement.cs b/RobloxCS.Luau/AST/ExpressionStatement.cs index ef2ae9e..f02f1b4 100644 --- a/RobloxCS.Luau/AST/ExpressionStatement.cs +++ b/RobloxCS.Luau/AST/ExpressionStatement.cs @@ -1,19 +1,18 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class ExpressionStatement : Statement { - public class ExpressionStatement : Statement - { - public Expression Expression { get; } + public Expression Expression { get; } - public ExpressionStatement(Expression expression) - { - Expression = expression; - AddChild(Expression); - } + public ExpressionStatement(Expression expression) + { + Expression = expression; + AddChild(Expression); + } - public override void Render(LuauWriter luau) - { - Expression.Render(luau); - luau.WriteLine(); - } + public override void Render(LuauWriter luau) + { + Expression.Render(luau); + luau.WriteLine(); } -} +} \ No newline at end of file diff --git a/RobloxCS.Luau/AST/ExpressionalIf.cs b/RobloxCS.Luau/AST/ExpressionalIf.cs index e8ffdee..58a6ac3 100644 --- a/RobloxCS.Luau/AST/ExpressionalIf.cs +++ b/RobloxCS.Luau/AST/ExpressionalIf.cs @@ -1,57 +1,54 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class ExpressionalIf : Expression { - public class ExpressionalIf : Expression - { - public Expression Condition { get; } - public Expression Body { get; } - public Expression? ElseBranch { get; } - public bool IsCompact { get; } + public Expression Condition { get; } + public Expression Body { get; } + public Expression? ElseBranch { get; } + public bool IsCompact { get; } - public ExpressionalIf(Expression condition, Expression body, Expression? elseBranch = null, bool isCompact = false) - { - Condition = condition; - Body = body; - ElseBranch = elseBranch; - IsCompact = isCompact; + public ExpressionalIf(Expression condition, Expression body, Expression? elseBranch = null, bool isCompact = false) + { + Condition = condition; + Body = body; + ElseBranch = elseBranch; + IsCompact = isCompact; - AddChild(Condition); - AddChild(Body); - if (ElseBranch != null) - { - AddChild(ElseBranch); - } - } + AddChild(Condition); + AddChild(Body); + if (ElseBranch != null) + AddChild(ElseBranch); + } - public override void Render(LuauWriter luau) - { - luau.Write("if "); - Condition.Render(luau); - luau.Write(" then" + (IsCompact ? " " : '\n')); - luau.PushIndent(); + public override void Render(LuauWriter luau) + { + luau.Write("if "); + Condition.Render(luau); + luau.Write(" then" + (IsCompact ? " " : '\n')); + luau.PushIndent(); - Node body = IsCompact ? Body : new ExpressionStatement(Body); - body.Render(luau); + Node body = IsCompact ? Body : new ExpressionStatement(Body); + body.Render(luau); - var isElseIf = ElseBranch is ExpressionalIf; - if (ElseBranch == null) return; - - luau.PopIndent(); - if (IsCompact) - luau.Write(' '); + var isElseIf = ElseBranch is ExpressionalIf; + if (ElseBranch == null) return; - luau.Write("else"); - if (IsCompact && !isElseIf) - luau.Write(' '); - if (!isElseIf && !IsCompact) - { - luau.WriteLine(); - luau.PushIndent(); - } + luau.PopIndent(); + if (IsCompact) + luau.Write(' '); - Node elseBranch = IsCompact ? ElseBranch : new ExpressionStatement(ElseBranch); - elseBranch.Render(luau); - if (!isElseIf) - luau.PopIndent(); + luau.Write("else"); + if (IsCompact && !isElseIf) + luau.Write(' '); + if (!isElseIf && !IsCompact) + { + luau.WriteLine(); + luau.PushIndent(); } + + Node elseBranch = IsCompact ? ElseBranch : new ExpressionStatement(ElseBranch); + elseBranch.Render(luau); + if (!isElseIf) + luau.PopIndent(); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/FieldType.cs b/RobloxCS.Luau/AST/FieldType.cs index 6f03d83..86215bb 100644 --- a/RobloxCS.Luau/AST/FieldType.cs +++ b/RobloxCS.Luau/AST/FieldType.cs @@ -1,17 +1,17 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class FieldType : TypeRef { - public class FieldType : TypeRef - { - public string Name { get; } - public TypeRef ValueType { get; } - public bool IsReadOnly { get; } + public string Name { get; } + public TypeRef ValueType { get; } + public bool IsReadOnly { get; } - public FieldType(string name, TypeRef valueType, bool isReadOnly) - : base($"{(isReadOnly ? "read " : "")}{name}: {valueType.Path};", true) - { - Name = name; - ValueType = valueType; - IsReadOnly = isReadOnly; - } + public FieldType(string name, TypeRef valueType, bool isReadOnly) + : base($"{(isReadOnly ? "read " : "")}{name}: {valueType.Path};", true) + { + Name = name; + ValueType = valueType; + IsReadOnly = isReadOnly; + AddChild(ValueType); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/For.cs b/RobloxCS.Luau/AST/For.cs index 064d42a..2c88638 100644 --- a/RobloxCS.Luau/AST/For.cs +++ b/RobloxCS.Luau/AST/For.cs @@ -1,50 +1,47 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class For : Statement { - public class For : Statement + public List Names { get; } + public Expression Iterable { get; } + public Statement Body { get; } + + public For(List initializers, Expression iterable, Statement body) { - public List Names { get; } - public Expression Iterable { get; } - public Statement Body { get; } + Names = initializers; + Iterable = iterable; + Body = body; + AddChildren(Names); + AddChild(Iterable); + AddChild(Body); + } - public For(List initializers, Expression iterable, Statement body) - { - Names = initializers; - Iterable = iterable; - Body = body; - AddChildren(Names); - AddChild(Iterable); - AddChild(Body); - } + public override void Render(LuauWriter luau) + { + var singleValueIteration = Names.Count == 1; + luau.Write("for _, "); + if (singleValueIteration) + Names.First().Render(luau); + else + luau.Write("_binding"); + + luau.Write(" in "); + Iterable.Render(luau); + luau.WriteLine(" do"); + luau.PushIndent(); - public override void Render(LuauWriter luau) + if (!singleValueIteration) { - var singleValueIteration = Names.Count == 1; - luau.Write("for _, "); - if (singleValueIteration) + var index = 0; + foreach (var name in Names) { - Names.First().Render(luau); + var indexLiteral = new Literal((++index).ToString()); + luau.WriteVariable(name, true, new ElementAccess(new IdentifierName("_binding"), indexLiteral)); } - else - { - luau.Write("_binding"); - } - luau.Write(" in "); - Iterable.Render(luau); - luau.WriteLine(" do"); - luau.PushIndent(); - - if (!singleValueIteration) - { - foreach (var name in Names) - { - var index = new Literal((Names.IndexOf(name) + 1).ToString()); - new Variable(name, true, new ElementAccess(new IdentifierName("_binding"), index)).Render(luau); - } - } - Body.Render(luau); - - luau.PopIndent(); - luau.WriteLine("end"); } + + Body.Render(luau); + luau.PopIndent(); + luau.WriteLine("end"); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/Function.cs b/RobloxCS.Luau/AST/Function.cs index 4fee5ce..27b5c1f 100644 --- a/RobloxCS.Luau/AST/Function.cs +++ b/RobloxCS.Luau/AST/Function.cs @@ -1,43 +1,39 @@ -namespace RobloxCS.Luau -{ - public class Function : Statement - { - public Name Name { get; } - public bool IsLocal { get; } - public ParameterList ParameterList { get; } - public Block? Body { get; } - public TypeRef? ReturnType { get; } - public List AttributeLists { get; } +namespace RobloxCS.Luau; - public Function( - Name name, - bool isLocal, - ParameterList parameterList, - TypeRef? returnType = null, - Block? body = null, - List? attributeLists = null - ) - { - Name = name; - IsLocal = isLocal; - ParameterList = parameterList; - Body = body; - ReturnType = returnType; - AttributeLists = attributeLists ?? []; - AddChild(Name); - AddChild(ParameterList); - if (ReturnType != null) - { - AddChild(ReturnType); - } - if (Body != null) - { - AddChild(Body); - } - AddChildren(AttributeLists); - } +public class Function : Statement +{ + public Name Name { get; } + public bool IsLocal { get; } + public ParameterList ParameterList { get; } + public Block? Body { get; } + public TypeRef? ReturnType { get; } + public List AttributeLists { get; } - public override void Render(LuauWriter luau) => - luau.WriteFunction(Name, IsLocal, ParameterList, ReturnType, Body, AttributeLists); + public Function( + Name name, + bool isLocal, + ParameterList parameterList, + TypeRef? returnType = null, + Block? body = null, + List? attributeLists = null) + { + Name = name; + IsLocal = isLocal; + ParameterList = parameterList; + Body = body; + ReturnType = returnType; + AttributeLists = attributeLists ?? []; + + AddChild(Name); + AddChild(ParameterList); + if (ReturnType != null) + AddChild(ReturnType); + if (Body != null) + AddChild(Body); + + AddChildren(AttributeLists); } + + public override void Render(LuauWriter luau) => + luau.WriteFunction(Name, IsLocal, ParameterList, ReturnType, Body, AttributeLists); } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/FunctionType.cs b/RobloxCS.Luau/AST/FunctionType.cs index 6c7dc9e..727a176 100644 --- a/RobloxCS.Luau/AST/FunctionType.cs +++ b/RobloxCS.Luau/AST/FunctionType.cs @@ -1,16 +1,15 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class FunctionType : TypeRef { - public class FunctionType : TypeRef - { - public List ParameterTypes { get; } - public TypeRef ReturnType { get; } + public List ParameterTypes { get; } + public TypeRef ReturnType { get; } - public FunctionType(List parameterTypes, TypeRef returnType) - : base("", true) - { - ParameterTypes = parameterTypes; - ReturnType = returnType; - Path = $"({string.Join(", ", parameterTypes.Select(type => type.Path))}) -> {returnType.Path}"; - } + public FunctionType(List parameterTypes, TypeRef returnType) + : base("", true) + { + ParameterTypes = parameterTypes; + ReturnType = returnType; + Path = $"({string.Join(", ", parameterTypes.Select(type => type.Path))}) -> {returnType.Path}"; } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/GenericName.cs b/RobloxCS.Luau/AST/GenericName.cs index 1621219..dce46e6 100644 --- a/RobloxCS.Luau/AST/GenericName.cs +++ b/RobloxCS.Luau/AST/GenericName.cs @@ -1,12 +1,11 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class GenericName(string text, List typeArguments) : SimpleName { - public class GenericName(string text, List typeArguments) : SimpleName - { - public string Text { get; } = text; - public List TypeArguments { get; } = typeArguments; + public string Text { get; } = text; + public List TypeArguments { get; } = typeArguments; - public override void Render(LuauWriter luau) => luau.Write(ToString()); + public override void Render(LuauWriter luau) => luau.Write(ToString()); - public override string ToString() => Text + '<' + string.Join(", ", TypeArguments) + '>'; - } + public override string ToString() => Text + '<' + string.Join(", ", TypeArguments) + '>'; } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/IdentifierName.cs b/RobloxCS.Luau/AST/IdentifierName.cs index 5445f0b..10e6b6f 100644 --- a/RobloxCS.Luau/AST/IdentifierName.cs +++ b/RobloxCS.Luau/AST/IdentifierName.cs @@ -1,17 +1,10 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class IdentifierName(string text) : SimpleName { - public class IdentifierName(string text) : SimpleName - { - public string Text { get; } = text; + public string Text { get; } = text; - public override void Render(LuauWriter luau) - { - luau.Write(Text); - } + public override void Render(LuauWriter luau) => luau.Write(Text); - public override string ToString() - { - return Text; - } - } + public override string ToString() => Text; } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/If.cs b/RobloxCS.Luau/AST/If.cs index d372951..1ab7601 100644 --- a/RobloxCS.Luau/AST/If.cs +++ b/RobloxCS.Luau/AST/If.cs @@ -1,49 +1,46 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class If : Statement { - public class If : Statement + public Expression Condition { get; } + public Statement Body { get; } + public Statement? ElseBranch { get; } + + public If(Expression condition, Statement body, Statement? elseBranch = null) { - public Expression Condition { get; } - public Statement Body { get; } - public Statement? ElseBranch { get; } + Condition = condition; + Body = body; + ElseBranch = elseBranch; - public If(Expression condition, Statement body, Statement? elseBranch = null) - { - Condition = condition; - Body = body; - ElseBranch = elseBranch; + AddChildren([Condition, Body]); + if (ElseBranch != null) + AddChild(ElseBranch); + } - AddChildren([Condition, Body]); - if (ElseBranch != null) - { - AddChild(ElseBranch); - } - } + public override void Render(LuauWriter luau) + { + luau.Write("if "); + Condition.Render(luau); + luau.WriteLine(" then"); + luau.PushIndent(); + Body.Render(luau); - public override void Render(LuauWriter luau) + var isElseIf = ElseBranch is If; + if (ElseBranch != null) { - luau.Write("if "); - Condition.Render(luau); - luau.WriteLine(" then"); - luau.PushIndent(); - Body.Render(luau); - - var isElseIf = ElseBranch is If; - if (ElseBranch != null) - { - luau.PopIndent(); - luau.Write("else" + (isElseIf ? "" : '\n')); - if (!isElseIf) - { - luau.PushIndent(); - } - ElseBranch.Render(luau); - } - luau.PopIndent(); + luau.Write("else" + (isElseIf ? "" : '\n')); if (!isElseIf) { - luau.WriteLine("end"); + luau.PushIndent(); } + ElseBranch.Render(luau); + } + + luau.PopIndent(); + if (!isElseIf) + { + luau.WriteLine("end"); } } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/IndexCall.cs b/RobloxCS.Luau/AST/IndexCall.cs index c935935..67c8a2a 100644 --- a/RobloxCS.Luau/AST/IndexCall.cs +++ b/RobloxCS.Luau/AST/IndexCall.cs @@ -1,17 +1,16 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class IndexCall(TypeRef typeRef, TypeRef key) : TypeRef(typeRef.Path) { - public class IndexCall(TypeRef typeRef, TypeRef key) : TypeRef(typeRef.Path) - { - public TypeRef TypeRef { get; } = typeRef; - public TypeRef Key { get; } = key; + public TypeRef TypeRef { get; } = typeRef; + public TypeRef Key { get; } = key; - public override void Render(LuauWriter luau) - { - luau.Write("index<"); - TypeRef.Render(luau); - luau.Write(", "); - Key.Render(luau); - luau.Write(">"); - } + public override void Render(LuauWriter luau) + { + luau.Write("index<"); + TypeRef.Render(luau); + luau.Write(", "); + Key.Render(luau); + luau.Write(">"); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/InterfaceType.cs b/RobloxCS.Luau/AST/InterfaceType.cs index a784ead..1350549 100644 --- a/RobloxCS.Luau/AST/InterfaceType.cs +++ b/RobloxCS.Luau/AST/InterfaceType.cs @@ -1,28 +1,27 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class InterfaceType : TypeRef { - public class InterfaceType : TypeRef - { - public HashSet Fields { get; } - public MappedType? ExtraMapping { get; } - public bool IsCompact { get; } + public HashSet Fields { get; } + public MappedType? ExtraMapping { get; } + public bool IsCompact { get; } - public InterfaceType(HashSet fields, MappedType? extraMapping = null, bool isCompact = true) - : base("", true) - { - Fields = fields; - ExtraMapping = extraMapping; - IsCompact = Fields.Count == 0 && isCompact; - Path = ToString(); - } + public InterfaceType(HashSet fields, MappedType? extraMapping = null, bool isCompact = true) + : base("", true) + { + Fields = fields; + ExtraMapping = extraMapping; + IsCompact = Fields.Count == 0 && isCompact; + Path = ToString(); + } - public string ToString(uint indent = 0) - { - var tabsOutside = new string(' ', (int)indent * BaseWriter.IndentSize); - var tabsInside = new string(' ', ((int)indent + 1) * BaseWriter.IndentSize); - var newline = (IsCompact ? "" : "\n"); - return tabsOutside + "{" + newline - + string.Join(newline, Fields.Select(field => tabsInside + field.Path)) - + tabsOutside + newline + "}"; - } + public string ToString(int indent = 0) + { + var tabsOutside = new string(' ', indent * BaseWriter.IndentSize); + var tabsInside = new string(' ', (indent + 1) * BaseWriter.IndentSize); + var newline = IsCompact ? "" : "\n"; + return tabsOutside + "{" + newline + + string.Join(newline, Fields.Select(field => tabsInside + field.Path)) + + tabsOutside + newline + "}"; } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/InterpolatedString.cs b/RobloxCS.Luau/AST/InterpolatedString.cs index 4b0c141..6d9d6b6 100644 --- a/RobloxCS.Luau/AST/InterpolatedString.cs +++ b/RobloxCS.Luau/AST/InterpolatedString.cs @@ -1,22 +1,21 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class InterpolatedString : Expression { - public class InterpolatedString : Expression - { - public List Parts { get; } + public List Parts { get; } - public InterpolatedString(List parts) - { - Parts = parts; - AddChildren(Parts); - } + public InterpolatedString(List parts) + { + Parts = parts; + AddChildren(Parts); + } - public override void Render(LuauWriter luau) - { - luau.Write('`'); - foreach (var part in Parts) - part.Render(luau); + public override void Render(LuauWriter luau) + { + luau.Write('`'); + foreach (var part in Parts) + part.Render(luau); - luau.Write('`'); - } + luau.Write('`'); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/KeyOfCall.cs b/RobloxCS.Luau/AST/KeyOfCall.cs index 3b1b545..b606660 100644 --- a/RobloxCS.Luau/AST/KeyOfCall.cs +++ b/RobloxCS.Luau/AST/KeyOfCall.cs @@ -1,14 +1,19 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public sealed class KeyOfCall : TypeRef { - public sealed class KeyOfCall(TypeRef typeRef) : TypeRef(typeRef.Path) + public TypeRef TypeRef { get; } + + public KeyOfCall(TypeRef typeRef) : base(typeRef.Path) { - public TypeRef TypeRef { get; } = typeRef; + TypeRef = typeRef; + AddChild(TypeRef); + } - public override void Render(LuauWriter luau) - { - luau.Write("keyof<"); - TypeRef.Render(luau); - luau.Write(">"); - } + public override void Render(LuauWriter luau) + { + luau.Write("keyof<"); + TypeRef.Render(luau); + luau.Write(">"); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/Literal.cs b/RobloxCS.Luau/AST/Literal.cs index 7fda250..c3ac857 100644 --- a/RobloxCS.Luau/AST/Literal.cs +++ b/RobloxCS.Luau/AST/Literal.cs @@ -1,9 +1,8 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class Literal(string valueText) : Expression { - public class Literal(string valueText) : Expression - { - public string ValueText { get; } = valueText; + public string ValueText { get; } = valueText; - public override void Render(LuauWriter luau) => luau.Write(ValueText); - } + public override void Render(LuauWriter luau) => luau.Write(ValueText); } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/MappedType.cs b/RobloxCS.Luau/AST/MappedType.cs index b122ef2..7050133 100644 --- a/RobloxCS.Luau/AST/MappedType.cs +++ b/RobloxCS.Luau/AST/MappedType.cs @@ -1,15 +1,15 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class MappedType : TypeRef { - public class MappedType : TypeRef - { - public TypeRef KeyType { get; } - public TypeRef ValueType { get; } + public TypeRef KeyType { get; } + public TypeRef ValueType { get; } - public MappedType(TypeRef keyType, TypeRef valueType) - : base($"{{ [{keyType.Path}]: " + valueType.Path + "; }", true) - { - KeyType = keyType; - ValueType = valueType; - } + public MappedType(TypeRef keyType, TypeRef valueType) + : base($"{{ [{keyType.Path}]: " + valueType.Path + "; }", true) + { + KeyType = keyType; + ValueType = valueType; + AddChildren([KeyType, ValueType]); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/MemberAccess.cs b/RobloxCS.Luau/AST/MemberAccess.cs index 04f463d..e3dabcf 100644 --- a/RobloxCS.Luau/AST/MemberAccess.cs +++ b/RobloxCS.Luau/AST/MemberAccess.cs @@ -1,26 +1,23 @@ -using System.Linq.Expressions; +namespace RobloxCS.Luau; -namespace RobloxCS.Luau +public class MemberAccess : AssignmentTarget { - public class MemberAccess : AssignmentTarget - { - public Expression Expression { get; } - public char Operator { get; set; } - public SimpleName Name { get; } + public Expression Expression { get; } + public char Operator { get; set; } + public SimpleName Name { get; } - public MemberAccess(Expression expression, SimpleName name, char @operator = '.') - { - Expression = expression; - Operator = @operator; - Name = name; - AddChildren([Expression, Name]); - } + public MemberAccess(Expression expression, SimpleName name, char @operator = '.') + { + Expression = expression; + Operator = @operator; + Name = name; + AddChildren([Expression, Name]); + } - public override void Render(LuauWriter luau) - { - Expression.Render(luau); - luau.Write(Operator); - Name.Render(luau); - } + public override void Render(LuauWriter luau) + { + Expression.Render(luau); + luau.Write(Operator); + Name.Render(luau); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/Name.cs b/RobloxCS.Luau/AST/Name.cs index 7b58c50..8cd155a 100644 --- a/RobloxCS.Luau/AST/Name.cs +++ b/RobloxCS.Luau/AST/Name.cs @@ -1,7 +1,6 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public abstract class Name : AssignmentTarget { - public abstract class Name : AssignmentTarget - { - public abstract override string ToString(); - } + public abstract override string ToString(); } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/NoOp.cs b/RobloxCS.Luau/AST/NoOp.cs index 4b8c2eb..d77dd13 100644 --- a/RobloxCS.Luau/AST/NoOp.cs +++ b/RobloxCS.Luau/AST/NoOp.cs @@ -1,8 +1,11 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +/// Optionally renders a newline. +public sealed class NoOp(bool createNewline = true) : Statement { - /// Simply renders a newline. - public sealed class NoOp : Statement + public override void Render(LuauWriter luau) { - public override void Render(LuauWriter luau) => luau.WriteLine(); + if (!createNewline) return; + luau.WriteLine(); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/Node.cs b/RobloxCS.Luau/AST/Node.cs index fcee638..29f3dbf 100644 --- a/RobloxCS.Luau/AST/Node.cs +++ b/RobloxCS.Luau/AST/Node.cs @@ -1,47 +1,58 @@ using RobloxCS.Macros; +using RobloxCS.Shared; -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public abstract class Node { - public abstract class Node - { - public Node? Parent { get; private set; } = null; - public List Children { get; } = []; - public MacroKind? ExpandedByMacro { get; private set; } + public Node? Parent { get; private set; } = null; + public List Children { get; } = []; + public MacroKind? ExpandedByMacro { get; private set; } - private List _descendants = null!; - public List Descendants + private List? _descendants = null; + public List Descendants + { + get { - get - { - if (_descendants != null) - return _descendants; - - _descendants = []; - foreach (var child in Children) - { - _descendants.Add(child); - _descendants.AddRange(child.Descendants); - } - + if (_descendants != null) return _descendants; + + _descendants = []; + foreach (var child in Children) + { + _descendants.Add(child); + _descendants.AddRange(child.Descendants); } - set => _descendants = value; + + return _descendants; } + set => _descendants = value; + } - public abstract void Render(LuauWriter luau); + public abstract void Render(LuauWriter luau); - public void MarkExpanded(MacroKind macroKind) => ExpandedByMacro = macroKind; + public void MarkExpanded(MacroKind macroKind) + { + if (ExpandedByMacro != null) + throw Logger.CompilerError( + $""" + Attempted to mark macro-expanded node as expanded. + Current macro kind: {ExpandedByMacro} + Attempted expanding macro kind: {macroKind} + """); + + ExpandedByMacro = macroKind; + } - protected void AddChild(Node child) - { - child.Parent = this; - Children.Add(child); - } + protected void AddChild(Node child) + { + child.Parent = this; + Children.Add(child); + } - protected void AddChildren(IEnumerable children) - { - foreach (var child in children) - AddChild(child); - } + protected void AddChildren(IEnumerable children) + { + foreach (var child in children) + AddChild(child); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/NumericFor.cs b/RobloxCS.Luau/AST/NumericFor.cs index 51a7135..7aa3ccc 100644 --- a/RobloxCS.Luau/AST/NumericFor.cs +++ b/RobloxCS.Luau/AST/NumericFor.cs @@ -1,48 +1,47 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class NumericFor : Statement { - public class NumericFor : Statement - { - public IdentifierName Name { get; } - public Expression Minimum { get; } - public Expression Maximum { get; } - public Expression? IncrementBy { get; } - public Statement Body { get; } + public IdentifierName Name { get; } + public Expression Minimum { get; } + public Expression Maximum { get; } + public Expression? IncrementBy { get; } + public Statement Body { get; } - public NumericFor(IdentifierName name, Expression minimum, Expression maximum, Expression? incrementBy, Statement body) - { - Name = name; - Minimum = minimum; - Maximum = maximum; - IncrementBy = incrementBy; - Body = body; + public NumericFor(IdentifierName name, Expression minimum, Expression maximum, Expression? incrementBy, Statement body) + { + Name = name; + Minimum = minimum; + Maximum = maximum; + IncrementBy = incrementBy; + Body = body; - AddChildren([Name, Minimum, Maximum]); - if (IncrementBy != null) - AddChild(IncrementBy); + AddChildren([Name, Minimum, Maximum]); + if (IncrementBy != null) + AddChild(IncrementBy); - AddChild(Body); - } + AddChild(Body); + } - public override void Render(LuauWriter luau) + public override void Render(LuauWriter luau) + { + luau.Write("for "); + Name.Render(luau); + luau.Write(" = "); + Minimum.Render(luau); + luau.Write(", "); + Maximum.Render(luau); + if (IncrementBy != null) { - luau.Write("for "); - Name.Render(luau); - luau.Write(" = "); - Minimum.Render(luau); luau.Write(", "); - Maximum.Render(luau); - if (IncrementBy != null) - { - luau.Write(", "); - IncrementBy.Render(luau); - } - luau.WriteLine(" do"); - luau.PushIndent(); + IncrementBy.Render(luau); + } + luau.WriteLine(" do"); + luau.PushIndent(); - Body.Render(luau); + Body.Render(luau); - luau.PopIndent(); - luau.WriteLine("end"); - } + luau.PopIndent(); + luau.WriteLine("end"); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/OptionalType.cs b/RobloxCS.Luau/AST/OptionalType.cs index 18f4b68..579c6cc 100644 --- a/RobloxCS.Luau/AST/OptionalType.cs +++ b/RobloxCS.Luau/AST/OptionalType.cs @@ -1,13 +1,13 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class OptionalType : TypeRef { - public class OptionalType : TypeRef - { - public TypeRef NonNullableType { get; } + public TypeRef NonNullableType { get; } - public OptionalType(TypeRef nonNullableType) - : base(nonNullableType.Path + "?", true) - { - NonNullableType = nonNullableType; - } + public OptionalType(TypeRef nonNullableType) + : base(nonNullableType.Path + "?", true) + { + NonNullableType = nonNullableType; + AddChild(nonNullableType); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/Parameter.cs b/RobloxCS.Luau/AST/Parameter.cs index 8694549..f94c938 100644 --- a/RobloxCS.Luau/AST/Parameter.cs +++ b/RobloxCS.Luau/AST/Parameter.cs @@ -1,69 +1,66 @@ -using System.Text.RegularExpressions; +namespace RobloxCS.Luau; -namespace RobloxCS.Luau +public class Parameter : Statement { - public class Parameter : Statement - { - public IdentifierName Name { get; } - public Expression? Initializer { get; } - public TypeRef? Type { get; } - public bool IsVararg { get; } + public IdentifierName Name { get; } + public Expression? Initializer { get; } + public TypeRef? Type { get; } + public bool IsVararg { get; } - public Parameter(IdentifierName name, bool isVararg = false, Expression? initializer = null, TypeRef? type = null) - { - Name = name; - Initializer = initializer; - Type = type; - IsVararg = isVararg; + public Parameter(IdentifierName name, bool isVararg = false, Expression? initializer = null, TypeRef? type = null) + { + Name = name; + Initializer = initializer; + Type = type; + IsVararg = isVararg; - AddChild(Name); - if (Initializer != null) - { - AddChild(Initializer); - } - if (Type != null) - { - Type = FixType(Type); - AddChild(Type); - } + AddChild(Name); + if (Initializer != null) + { + AddChild(Initializer); + } + if (Type != null) + { + Type = FixType(Type); + AddChild(Type); } + } - public override void Render(LuauWriter luau) + public override void Render(LuauWriter luau) + { + if (IsVararg) { - if (IsVararg) - { - luau.Write("..."); - } - else - { - Name.Render(luau); - } - if (Type != null) - { - luau.Write(": "); - Type.Render(luau); - } + luau.Write("..."); + } + else + { + Name.Render(luau); + } + if (Type != null) + { + luau.Write(": "); + Type.Render(luau); } + } - private TypeRef FixType(TypeRef type) + private TypeRef FixType(TypeRef type) + { + while (true) { - while (true) + if (type is ArrayType arrayType && IsVararg) { - if (type is ArrayType arrayType && IsVararg) - { - type = arrayType.ElementType; - continue; - } - - var isOptional = type is OptionalType; - if (Initializer != null || isOptional) - { - return isOptional ? type : new OptionalType(type); - } + type = arrayType.ElementType; + continue; + } - return type; + var isOptional = type is OptionalType; + if (Initializer != null || isOptional) + { + return isOptional ? type : new OptionalType(type); } + + return type; } } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/ParameterList.cs b/RobloxCS.Luau/AST/ParameterList.cs index 5e5668a..e556a27 100644 --- a/RobloxCS.Luau/AST/ParameterList.cs +++ b/RobloxCS.Luau/AST/ParameterList.cs @@ -1,20 +1,19 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class ParameterList : Statement { - public class ParameterList : Statement - { - public List Parameters { get; } + public List Parameters { get; } - public ParameterList(List parameters) - { - Parameters = parameters; - AddChildren(Parameters); - } + public ParameterList(List parameters) + { + Parameters = parameters; + AddChildren(Parameters); + } - public override void Render(LuauWriter luau) - { - luau.Write('('); - luau.WriteNodesCommaSeparated(Parameters); - luau.Write(')'); - } + public override void Render(LuauWriter luau) + { + luau.Write('('); + luau.WriteNodesCommaSeparated(Parameters); + luau.Write(')'); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/ParameterType.cs b/RobloxCS.Luau/AST/ParameterType.cs index b1e007f..42d6fdd 100644 --- a/RobloxCS.Luau/AST/ParameterType.cs +++ b/RobloxCS.Luau/AST/ParameterType.cs @@ -1,15 +1,14 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class ParameterType : TypeRef { - public class ParameterType : TypeRef - { - public string? Name { get; } - public TypeRef Type { get; } + public string? Name { get; } + public TypeRef Type { get; } - public ParameterType(string? name, TypeRef type) - : base(name != null ? $"{name}: {type.Path}" : type.Path, true) - { - Name = name; - Type = type; - } + public ParameterType(string? name, TypeRef type) + : base(name != null ? $"{name}: {type.Path}" : type.Path, true) + { + Name = name; + Type = type; } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/Parenthesized.cs b/RobloxCS.Luau/AST/Parenthesized.cs index ebe3dda..5ab98cf 100644 --- a/RobloxCS.Luau/AST/Parenthesized.cs +++ b/RobloxCS.Luau/AST/Parenthesized.cs @@ -1,19 +1,18 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class Parenthesized : Expression { - public class Parenthesized : Expression - { - public Expression Expression { get; } + public Expression Expression { get; } - public Parenthesized(Expression expression) - { - Expression = expression; - } + public Parenthesized(Expression expression) + { + Expression = expression; + } - public override void Render(LuauWriter luau) - { - luau.Write('('); - Expression.Render(luau); - luau.Write(')'); - } + public override void Render(LuauWriter luau) + { + luau.Write('('); + Expression.Render(luau); + luau.Write(')'); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/QualifiedName.cs b/RobloxCS.Luau/AST/QualifiedName.cs index 14496ca..978ea8f 100644 --- a/RobloxCS.Luau/AST/QualifiedName.cs +++ b/RobloxCS.Luau/AST/QualifiedName.cs @@ -1,29 +1,28 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class QualifiedName : Name { - public class QualifiedName : Name - { - public Name Left { get; } - public char Operator { get; } - public SimpleName Right { get; } + public Name Left { get; } + public char Operator { get; } + public SimpleName Right { get; } - public QualifiedName(Name left, SimpleName right, char @operator = '.') - { - Left = left; - Right = right; - Operator = @operator; - AddChildren([Left, Right]); - } + public QualifiedName(Name left, SimpleName right, char @operator = '.') + { + Left = left; + Right = right; + Operator = @operator; + AddChildren([Left, Right]); + } - public override void Render(LuauWriter luau) - { - Left.Render(luau); - luau.Write(Operator); - Right.Render(luau); - } + public override void Render(LuauWriter luau) + { + Left.Render(luau); + luau.Write(Operator); + Right.Render(luau); + } - public override string ToString() - { - return Left.ToString() + Operator + Right.ToString(); - } + public override string ToString() + { + return Left.ToString() + Operator + Right.ToString(); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/Repeat.cs b/RobloxCS.Luau/AST/Repeat.cs index 139643e..aa24b86 100644 --- a/RobloxCS.Luau/AST/Repeat.cs +++ b/RobloxCS.Luau/AST/Repeat.cs @@ -1,27 +1,25 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class Repeat : Statement { - public class Repeat : Statement - { - public Expression UntilCondition { get; } - public Statement Body { get; } + public Expression UntilCondition { get; } + public Statement Body { get; } - public Repeat(Expression untilCondition, Statement body) - { - UntilCondition = untilCondition; - Body = body; - AddChild(untilCondition); - AddChild(body); - } + public Repeat(Expression untilCondition, Statement body) + { + UntilCondition = untilCondition; + Body = body; + AddChildren([UntilCondition, Body]); + } - public override void Render(LuauWriter luau) - { - luau.WriteLine("repeat "); - luau.PushIndent(); - Body.Render(luau); - luau.PopIndent(); - luau.Write("until "); - UntilCondition.Render(luau); - luau.WriteLine(""); // is there a better way to add a new line? - } + public override void Render(LuauWriter luau) + { + luau.WriteLine("repeat "); + luau.PushIndent(); + Body.Render(luau); + luau.PopIndent(); + luau.Write("until "); + UntilCondition.Render(luau); + luau.WriteLine(""); // is there a better way to add a new line? } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/Return.cs b/RobloxCS.Luau/AST/Return.cs index cee91f6..36f0ed1 100644 --- a/RobloxCS.Luau/AST/Return.cs +++ b/RobloxCS.Luau/AST/Return.cs @@ -8,14 +8,9 @@ public Return(Expression? expression = null) { Expression = expression; if (Expression != null) - { AddChild(Expression); - } } - public override void Render(LuauWriter luau) - { - luau.WriteReturn(Expression); - } + public override void Render(LuauWriter luau) => luau.WriteReturn(Expression); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/ScopedBlock.cs b/RobloxCS.Luau/AST/ScopedBlock.cs index 52d93ac..4fc4753 100644 --- a/RobloxCS.Luau/AST/ScopedBlock.cs +++ b/RobloxCS.Luau/AST/ScopedBlock.cs @@ -1,19 +1,13 @@ - -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class ScopedBlock(List statements) : Block(statements) { - public class ScopedBlock : Block + public override void Render(LuauWriter luau) { - public ScopedBlock(List statements) : base(statements) - { - } - - public override void Render(LuauWriter luau) - { - luau.WriteLine("do"); - luau.PushIndent(); - base.Render(luau); - luau.PopIndent(); - luau.WriteLine("end"); - } + luau.WriteLine("do"); + luau.PushIndent(); + base.Render(luau); + luau.PopIndent(); + luau.WriteLine("end"); } -} +} \ No newline at end of file diff --git a/RobloxCS.Luau/AST/SimpleName.cs b/RobloxCS.Luau/AST/SimpleName.cs index b268301..85aa3dc 100644 --- a/RobloxCS.Luau/AST/SimpleName.cs +++ b/RobloxCS.Luau/AST/SimpleName.cs @@ -1,10 +1,9 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +/// +/// A name that is singular and not a combination of multiple names +/// +public abstract class SimpleName : Name { - /// - /// A name that is singular and not a combination of multiple names - /// - public abstract class SimpleName : Name - { - public abstract override string ToString(); - } + public abstract override string ToString(); } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/Statement.cs b/RobloxCS.Luau/AST/Statement.cs index e494e86..2ef6cee 100644 --- a/RobloxCS.Luau/AST/Statement.cs +++ b/RobloxCS.Luau/AST/Statement.cs @@ -1,6 +1,3 @@ -namespace RobloxCS.Luau -{ - public abstract class Statement : Node - { - } -} +namespace RobloxCS.Luau; + +public abstract class Statement : Node; \ No newline at end of file diff --git a/RobloxCS.Luau/AST/TableInitializer.cs b/RobloxCS.Luau/AST/TableInitializer.cs index f8522d4..92d4716 100644 --- a/RobloxCS.Luau/AST/TableInitializer.cs +++ b/RobloxCS.Luau/AST/TableInitializer.cs @@ -1,57 +1,56 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class TableInitializer( + List? values = null, + List? keys = null, + bool treatIdentifiersAsKeyNames = false) : Expression { - public class TableInitializer(List? values = null, List? keys = null, bool treatIdentifiersAsKeyNames = false) - : Expression + public List Values { get; } = values ?? []; + public List Keys { get; } = keys ?? []; + + public override void Render(LuauWriter luau) { - public List Values { get; } = values ?? []; - public List Keys { get; } = keys ?? []; + var hasAnyKeys = Keys.Count > 0; - public override void Render(LuauWriter luau) + luau.Write('{'); + if (hasAnyKeys) { - var hasAnyKeys = Keys.Count > 0; - - luau.Write('{'); - if (hasAnyKeys) - { - luau.WriteLine(); - luau.PushIndent(); - } + luau.WriteLine(); + luau.PushIndent(); + } - foreach (var value in Values) + foreach (var value in Values) + { + var index = Values.IndexOf(value); + var key = Keys.ElementAtOrDefault(index); + if (key != null) { - var index = Values.IndexOf(value); - var key = Keys.ElementAtOrDefault(index); - if (key != null) - { - if (!treatIdentifiersAsKeyNames || key is not IdentifierName) - { - luau.Write('['); - } - key.Render(luau); - if (!treatIdentifiersAsKeyNames || key is not IdentifierName) - { - luau.Write(']'); - } - luau.Write(" = "); - } - - value.Render(luau); - if (value == Values.Last()) continue; + if (!treatIdentifiersAsKeyNames || key is not IdentifierName) + luau.Write('['); + + key.Render(luau); + if (!treatIdentifiersAsKeyNames || key is not IdentifierName) + luau.Write(']'); - luau.Write(','); - if (hasAnyKeys && value is not AnonymousFunction) - luau.WriteLine(); - else - luau.Write(' '); + luau.Write(" = "); } - - if (hasAnyKeys) - { - luau.PopIndent(); + + value.Render(luau); + if (value == Values.Last()) continue; + + luau.Write(','); + if (hasAnyKeys && value is not AnonymousFunction) luau.WriteLine(); - } + else + luau.Write(' '); + } - luau.Write('}'); + if (hasAnyKeys) + { + luau.PopIndent(); + luau.WriteLine(); } + + luau.Write('}'); } -} +} \ No newline at end of file diff --git a/RobloxCS.Luau/AST/TypeAlias.cs b/RobloxCS.Luau/AST/TypeAlias.cs index c67da31..364e37e 100644 --- a/RobloxCS.Luau/AST/TypeAlias.cs +++ b/RobloxCS.Luau/AST/TypeAlias.cs @@ -1,25 +1,24 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public sealed class TypeAlias : Statement { - public sealed class TypeAlias : Statement - { - public SimpleName Name { get; } - public TypeRef Type { get; } + public SimpleName Name { get; } + public TypeRef Type { get; } - public TypeAlias(SimpleName name, TypeRef type) - { - Name = name; - Type = type; + public TypeAlias(SimpleName name, TypeRef type) + { + Name = name; + Type = type; - AddChildren([Name, Type]); - } + AddChildren([Name, Type]); + } - public override void Render(LuauWriter luau) - { - luau.Write("type "); - Name.Render(luau); - luau.Write(" = "); - Type.Render(luau); - luau.WriteLine(); - } + public override void Render(LuauWriter luau) + { + luau.Write("type "); + Name.Render(luau); + luau.Write(" = "); + Type.Render(luau); + luau.WriteLine(); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/TypeCast.cs b/RobloxCS.Luau/AST/TypeCast.cs index a08a58d..a50cf34 100644 --- a/RobloxCS.Luau/AST/TypeCast.cs +++ b/RobloxCS.Luau/AST/TypeCast.cs @@ -1,17 +1,17 @@ -namespace RobloxCS.Luau -{ - public class TypeCast : Expression - { - public Expression Expression { get; } - public TypeRef Type { get; } +namespace RobloxCS.Luau; - public TypeCast(Expression expression, TypeRef type) - { - Expression = expression; - Type = type; - } +public class TypeCast : Expression +{ + public Expression Expression { get; } + public TypeRef Type { get; } - public override void Render(LuauWriter luau) => - luau.WriteTypeCast(Expression, Type); + public TypeCast(Expression expression, TypeRef type) + { + Expression = expression; + Type = type; + AddChildren([Expression, Type]); } + + public override void Render(LuauWriter luau) => + luau.WriteTypeCast(Expression, Type); } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/TypeOfCall.cs b/RobloxCS.Luau/AST/TypeOfCall.cs index 208031a..6a42cc2 100644 --- a/RobloxCS.Luau/AST/TypeOfCall.cs +++ b/RobloxCS.Luau/AST/TypeOfCall.cs @@ -1,14 +1,19 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public sealed class TypeOfCall : TypeRef { - public sealed class TypeOfCall(Expression expression) : TypeRef("") + public TypeOfCall(Expression expression) : base("") { - public Expression Expression { get; } = expression; + Expression = expression; + AddChild(Expression); + } - public override void Render(LuauWriter luau) - { - luau.Write("typeof("); - Expression.Render(luau); - luau.Write(")"); - } + public Expression Expression { get; } + + public override void Render(LuauWriter luau) + { + luau.Write("typeof("); + Expression.Render(luau); + luau.Write(")"); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/TypeRef.cs b/RobloxCS.Luau/AST/TypeRef.cs index 8617e4e..e9e9873 100644 --- a/RobloxCS.Luau/AST/TypeRef.cs +++ b/RobloxCS.Luau/AST/TypeRef.cs @@ -1,18 +1,10 @@ -namespace RobloxCS.Luau -{ - public class TypeRef : Expression - { - public string Path { get; protected set; } - public bool IsNullable { get; protected set; } +namespace RobloxCS.Luau; - public TypeRef(string path, bool rawPath = false) - { - Path = rawPath ? path : AstUtility.CreateTypeRef(path)!.Path; - } +public class TypeRef(string path, bool rawPath = false) : Name +{ + public string Path { get; protected init; } = rawPath ? path : AstUtility.CreateTypeRef(path)!.Path; - public override void Render(LuauWriter luau) - { - luau.Write(Path); - } - } + public override void Render(LuauWriter luau) => luau.Write(Path); + + public override string ToString() => Path; } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/UnaryOperator.cs b/RobloxCS.Luau/AST/UnaryOperator.cs index 8960b90..70468ef 100644 --- a/RobloxCS.Luau/AST/UnaryOperator.cs +++ b/RobloxCS.Luau/AST/UnaryOperator.cs @@ -1,21 +1,20 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class UnaryOperator : Expression { - public class UnaryOperator : Expression - { - public string Operator { get; } - public Expression Operand { get; } + public string Operator { get; } + public Expression Operand { get; } - public UnaryOperator(string @operator, Expression operand) - { - Operator = @operator; - Operand = operand; - AddChild(Operand); - } + public UnaryOperator(string @operator, Expression operand) + { + Operator = @operator; + Operand = operand; + AddChild(Operand); + } - public override void Render(LuauWriter luau) - { - luau.Write(Operator); - Operand.Render(luau); - } + public override void Render(LuauWriter luau) + { + luau.Write(Operator); + Operand.Render(luau); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/Variable.cs b/RobloxCS.Luau/AST/Variable.cs index 8718829..a4bbd1d 100644 --- a/RobloxCS.Luau/AST/Variable.cs +++ b/RobloxCS.Luau/AST/Variable.cs @@ -1,33 +1,26 @@ -namespace RobloxCS.Luau -{ - public sealed class Variable : Statement - { - public IdentifierName Name { get; } - public bool IsLocal { get; } - public Expression? Initializer; - public TypeRef? Type { get; } +namespace RobloxCS.Luau; - public Variable(IdentifierName name, bool isLocal, Expression? initializer = null, TypeRef? type = null) - { - Name = name; - IsLocal = isLocal; - Initializer = initializer; - Type = type; +public sealed class Variable : Statement +{ + public IdentifierName Name { get; } + public bool IsLocal { get; } + public Expression? Initializer; + public TypeRef? Type { get; } - AddChild(Name); - if (Initializer != null) - { - AddChild(Initializer); - } - if (Type != null) - { - AddChild(Type); - } - } + public Variable(IdentifierName name, bool isLocal, Expression? initializer = null, TypeRef? type = null) + { + Name = name; + IsLocal = isLocal; + Initializer = initializer; + Type = type; - public override void Render(LuauWriter luau) - { - luau.WriteVariable(Name, IsLocal, Initializer, Type); - } + AddChild(Name); + if (Initializer != null) + AddChild(Initializer); + if (Type != null) + AddChild(Type); } + + public override void Render(LuauWriter luau) => + luau.WriteVariable(Name, IsLocal, Initializer, Type); } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/VariableList.cs b/RobloxCS.Luau/AST/VariableList.cs index 1559788..20aa806 100644 --- a/RobloxCS.Luau/AST/VariableList.cs +++ b/RobloxCS.Luau/AST/VariableList.cs @@ -1,15 +1,14 @@ -namespace RobloxCS.Luau -{ - public class VariableList : Statement - { - public List Variables { get; } +namespace RobloxCS.Luau; - public VariableList(List variables) - { - Variables = variables; - AddChildren(Variables); - } +public class VariableList : Statement +{ + public List Variables { get; } - public override void Render(LuauWriter luau) => luau.WriteNodes(Variables); + public VariableList(List variables) + { + Variables = variables; + AddChildren(Variables); } + + public override void Render(LuauWriter luau) => luau.WriteNodes(Variables); } \ No newline at end of file diff --git a/RobloxCS.Luau/AST/While.cs b/RobloxCS.Luau/AST/While.cs index 97ed1d6..899eba8 100644 --- a/RobloxCS.Luau/AST/While.cs +++ b/RobloxCS.Luau/AST/While.cs @@ -1,26 +1,25 @@ -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class While : Statement { - public class While : Statement - { - public Expression Condition { get; } - public Statement Body { get; } + public Expression Condition { get; } + public Statement Body { get; } - public While(Expression condition, Statement body) - { - Condition = condition; - Body = body; - AddChildren([Condition, Body]); - } + public While(Expression condition, Statement body) + { + Condition = condition; + Body = body; + AddChildren([Condition, Body]); + } - public override void Render(LuauWriter luau) - { - luau.Write("while "); - Condition.Render(luau); - luau.WriteLine(" do"); - luau.PushIndent(); - Body.Render(luau); - luau.PopIndent(); - luau.WriteLine("end"); - } + public override void Render(LuauWriter luau) + { + luau.Write("while "); + Condition.Render(luau); + luau.WriteLine(" do"); + luau.PushIndent(); + Body.Render(luau); + luau.PopIndent(); + luau.WriteLine("end"); } } \ No newline at end of file diff --git a/RobloxCS.Luau/AstUtility.cs b/RobloxCS.Luau/AstUtility.cs index aa5ae46..e694363 100644 --- a/RobloxCS.Luau/AstUtility.cs +++ b/RobloxCS.Luau/AstUtility.cs @@ -5,430 +5,447 @@ using RobloxCS.Shared; using static RobloxCS.Shared.Constants; -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public static class AstUtility { - public static class AstUtility - { - // TODO: make per-scope - /// file path -> dictionary(identifier name, amount of times identifier is used) - private static readonly Dictionary> _identifierDeclarations = []; + // TODO: make per-scope + /// file path -> dictionary(identifier name, amount of times identifier is used) + private static readonly Dictionary> _identifierDeclarations = []; - /// Adds one to the expression - public static Expression AddOne(Expression expression) - { - return expression is Literal literal && int.TryParse(literal.ValueText, out var value) - ? new Literal((value + 1).ToString()) - : new BinaryOperator(expression, "+", new Literal("1")); - } + /// Adds one to the expression + public static Expression AddOne(Expression expression) + { + return expression is Literal literal && int.TryParse(literal.ValueText, out var value) + ? new Literal((value + 1).ToString()) + : new BinaryOperator(expression, "+", new Literal("1")); + } - /// Subtracts one from the expression - public static Expression SubtractOne(Expression expression) - { - return expression is Literal literal && int.TryParse(literal.ValueText, out var value) - ? new Literal((value - 1).ToString()) - : new BinaryOperator(expression, "-", new Literal("1")); - } + /// Subtracts one from the expression + public static Expression SubtractOne(Expression expression) + { + return expression is Literal literal && int.TryParse(literal.ValueText, out var value) + ? new Literal((value - 1).ToString()) + : new BinaryOperator(expression, "-", new Literal("1")); + } - /// - /// Creates type info table for runtime type objects - /// - public static Parenthesized CreateTypeInfo(Type type) - { - List keys = [ - new IdentifierName("Name"), - new IdentifierName("FullName"), - new IdentifierName("Namespace"), - new IdentifierName("AssemblyQualifiedName"), - new IdentifierName("TypeInitializer"), - new IdentifierName("ReflectedType"), - new IdentifierName("IsAbstract"), - new IdentifierName("IsAnsiClass"), - new IdentifierName("IsArray"), - new IdentifierName("IsSealed"), - new IdentifierName("IsInterface"), - new IdentifierName("IsGenericTypeParameter"), - new IdentifierName("IsGenericTypeDefinition"), - new IdentifierName("IsGenericType"), - new IdentifierName("IsGenericMethodParameter"), - new IdentifierName("IsConstructedGenericType"), - new IdentifierName("IsImport"), - new IdentifierName("IsClass"), - new IdentifierName("IsCollectible"), - new IdentifierName("IsByRef"), - new IdentifierName("IsByRefLike"), - new IdentifierName("IsAutoClass"), - new IdentifierName("IsAutoLayout"), - new IdentifierName("IsCOMObject"), - new IdentifierName("IsContextful"), - new IdentifierName("IsEnum"), - new IdentifierName("IsExplicitLayout"), - new IdentifierName("IsPointer"), - new IdentifierName("IsFunctionPointer"), - new IdentifierName("IsUnmanagedFunctionPointer"), - new IdentifierName("IsLayoutSequential"), - new IdentifierName("IsMarshalByRef"), - new IdentifierName("IsNested"), - new IdentifierName("IsNestedAssembly"), - new IdentifierName("IsNestedFamily"), - new IdentifierName("IsNestedFamANDAssem"), - new IdentifierName("IsNestedFamORAssem"), - new IdentifierName("IsNestedPrivate"), - new IdentifierName("IsNestedPublic"), - new IdentifierName("IsNotPublic"), - new IdentifierName("IsPublic"), - new IdentifierName("IsSZArray"), - new IdentifierName("IsSecurityCritical"), - new IdentifierName("IsSecuritySafeCritical"), - new IdentifierName("IsSecurityTransparent"), - new IdentifierName("IsSignatureType"), - new IdentifierName("IsSpecialName"), - new IdentifierName("IsTypeDefinition"), - new IdentifierName("IsUnicodeClass"), - new IdentifierName("IsValueType"), - new IdentifierName("IsVariableBoundArray"), - new IdentifierName("IsVisible"), - new IdentifierName("UnderlyingSystemType"), - new IdentifierName("BaseType"), - new IdentifierName("DeclaringType"), - new IdentifierName("ContainsGenericParameters"), - new IdentifierName("GenericTypeArguments"), - new IdentifierName("GUID"), - ]; + /// + /// Creates type info table for runtime type objects + /// + public static Parenthesized CreateTypeInfo(Type type) + { + List keys = [ + new IdentifierName("Name"), + new IdentifierName("FullName"), + new IdentifierName("Namespace"), + new IdentifierName("AssemblyQualifiedName"), + new IdentifierName("TypeInitializer"), + new IdentifierName("ReflectedType"), + new IdentifierName("IsAbstract"), + new IdentifierName("IsAnsiClass"), + new IdentifierName("IsArray"), + new IdentifierName("IsSealed"), + new IdentifierName("IsInterface"), + new IdentifierName("IsGenericTypeParameter"), + new IdentifierName("IsGenericTypeDefinition"), + new IdentifierName("IsGenericType"), + new IdentifierName("IsGenericMethodParameter"), + new IdentifierName("IsConstructedGenericType"), + new IdentifierName("IsImport"), + new IdentifierName("IsClass"), + new IdentifierName("IsCollectible"), + new IdentifierName("IsByRef"), + new IdentifierName("IsByRefLike"), + new IdentifierName("IsAutoClass"), + new IdentifierName("IsAutoLayout"), + new IdentifierName("IsCOMObject"), + new IdentifierName("IsContextful"), + new IdentifierName("IsEnum"), + new IdentifierName("IsExplicitLayout"), + new IdentifierName("IsPointer"), + new IdentifierName("IsFunctionPointer"), + new IdentifierName("IsUnmanagedFunctionPointer"), + new IdentifierName("IsLayoutSequential"), + new IdentifierName("IsMarshalByRef"), + new IdentifierName("IsNested"), + new IdentifierName("IsNestedAssembly"), + new IdentifierName("IsNestedFamily"), + new IdentifierName("IsNestedFamANDAssem"), + new IdentifierName("IsNestedFamORAssem"), + new IdentifierName("IsNestedPrivate"), + new IdentifierName("IsNestedPublic"), + new IdentifierName("IsNotPublic"), + new IdentifierName("IsPublic"), + new IdentifierName("IsSZArray"), + new IdentifierName("IsSecurityCritical"), + new IdentifierName("IsSecuritySafeCritical"), + new IdentifierName("IsSecurityTransparent"), + new IdentifierName("IsSignatureType"), + new IdentifierName("IsSpecialName"), + new IdentifierName("IsTypeDefinition"), + new IdentifierName("IsUnicodeClass"), + new IdentifierName("IsValueType"), + new IdentifierName("IsVariableBoundArray"), + new IdentifierName("IsVisible"), + new IdentifierName("UnderlyingSystemType"), + new IdentifierName("BaseType"), + new IdentifierName("DeclaringType"), + new IdentifierName("ContainsGenericParameters"), + new IdentifierName("GenericTypeArguments"), + new IdentifierName("GUID"), + ]; - List values = [ - new Literal($"\"{type.Name}\""), - type.FullName != null ? new Literal($"\"{type.FullName}\"") : Nil(), - type.Namespace != null ? new Literal($"\"{type.Namespace}\"") : Nil(), - type.AssemblyQualifiedName != null ? new Literal($"\"{type.AssemblyQualifiedName}\"") : Nil(), - type.TypeInitializer != null ? CreateConstructorInfo(type.TypeInitializer) : Nil(), - type.ReflectedType != null ? CreateTypeInfo(type.ReflectedType) : Nil(), - new Literal(type.IsAbstract.ToString().ToLower()), - new Literal(type.IsAnsiClass.ToString().ToLower()), - new Literal(type.IsArray.ToString().ToLower()), - new Literal(type.IsSealed.ToString().ToLower()), - new Literal(type.IsInterface.ToString().ToLower()), - new Literal(type.IsGenericTypeParameter.ToString().ToLower()), - new Literal(type.IsGenericTypeDefinition.ToString().ToLower()), - new Literal(type.IsGenericType.ToString().ToLower()), - new Literal(type.IsGenericMethodParameter.ToString().ToLower()), - new Literal(type.IsConstructedGenericType.ToString().ToLower()), - new Literal(type.IsImport.ToString().ToLower()), - new Literal(type.IsClass.ToString().ToLower()), - new Literal(type.IsCollectible.ToString().ToLower()), - new Literal(type.IsByRef.ToString().ToLower()), - new Literal(type.IsByRefLike.ToString().ToLower()), - new Literal(type.IsAutoClass.ToString().ToLower()), - new Literal(type.IsAutoLayout.ToString().ToLower()), - new Literal(type.IsCOMObject.ToString().ToLower()), - new Literal(type.IsContextful.ToString().ToLower()), - new Literal(type.IsEnum.ToString().ToLower()), - new Literal(type.IsExplicitLayout.ToString().ToLower()), - new Literal(type.IsPointer.ToString().ToLower()), - new Literal(type.IsFunctionPointer.ToString().ToLower()), - new Literal(type.IsUnmanagedFunctionPointer.ToString().ToLower()), - new Literal(type.IsLayoutSequential.ToString().ToLower()), - new Literal(type.IsMarshalByRef.ToString().ToLower()), - new Literal(type.IsNested.ToString().ToLower()), - new Literal(type.IsNestedAssembly.ToString().ToLower()), - new Literal(type.IsNestedFamily.ToString().ToLower()), - new Literal(type.IsNestedFamANDAssem.ToString().ToLower()), - new Literal(type.IsNestedFamORAssem.ToString().ToLower()), - new Literal(type.IsNestedPrivate.ToString().ToLower()), - new Literal(type.IsNestedPublic.ToString().ToLower()), - new Literal(type.IsNotPublic.ToString().ToLower()), - new Literal(type.IsPublic.ToString().ToLower()), - new Literal(type.IsSZArray.ToString().ToLower()), - new Literal(type.IsSecurityCritical.ToString().ToLower()), - new Literal(type.IsSecuritySafeCritical.ToString().ToLower()), - new Literal(type.IsSecurityTransparent.ToString().ToLower()), - new Literal(type.IsSignatureType.ToString().ToLower()), - new Literal(type.IsSpecialName.ToString().ToLower()), - new Literal(type.IsTypeDefinition.ToString().ToLower()), - new Literal(type.IsUnicodeClass.ToString().ToLower()), - new Literal(type.IsValueType.ToString().ToLower()), - new Literal(type.IsVariableBoundArray.ToString().ToLower()), - new Literal(type.IsVisible.ToString().ToLower()), - type != type.UnderlyingSystemType ? CreateTypeInfo(type.UnderlyingSystemType) : Nil(), - type.BaseType != null ? CreateTypeInfo(type.BaseType) : Nil(), - type.DeclaringType != null ? CreateTypeInfo(type.DeclaringType) : Nil(), - new Literal(type.ContainsGenericParameters.ToString().ToLower()), - new TableInitializer(type.GenericTypeArguments.Select(CreateTypeInfo).OfType().ToList()), - new Literal($"\"{type.GUID}\"") - ]; - - return new Parenthesized(new TableInitializer(values, keys)); - } + List values = [ + new Literal($"\"{type.Name}\""), + type.FullName != null ? new Literal($"\"{type.FullName}\"") : Nil(), + type.Namespace != null ? new Literal($"\"{type.Namespace}\"") : Nil(), + type.AssemblyQualifiedName != null ? new Literal($"\"{type.AssemblyQualifiedName}\"") : Nil(), + type.TypeInitializer != null ? CreateConstructorInfo(type.TypeInitializer) : Nil(), + type.ReflectedType != null ? CreateTypeInfo(type.ReflectedType) : Nil(), + new Literal(type.IsAbstract.ToString().ToLower()), + new Literal(type.IsAnsiClass.ToString().ToLower()), + new Literal(type.IsArray.ToString().ToLower()), + new Literal(type.IsSealed.ToString().ToLower()), + new Literal(type.IsInterface.ToString().ToLower()), + new Literal(type.IsGenericTypeParameter.ToString().ToLower()), + new Literal(type.IsGenericTypeDefinition.ToString().ToLower()), + new Literal(type.IsGenericType.ToString().ToLower()), + new Literal(type.IsGenericMethodParameter.ToString().ToLower()), + new Literal(type.IsConstructedGenericType.ToString().ToLower()), + new Literal(type.IsImport.ToString().ToLower()), + new Literal(type.IsClass.ToString().ToLower()), + new Literal(type.IsCollectible.ToString().ToLower()), + new Literal(type.IsByRef.ToString().ToLower()), + new Literal(type.IsByRefLike.ToString().ToLower()), + new Literal(type.IsAutoClass.ToString().ToLower()), + new Literal(type.IsAutoLayout.ToString().ToLower()), + new Literal(type.IsCOMObject.ToString().ToLower()), + new Literal(type.IsContextful.ToString().ToLower()), + new Literal(type.IsEnum.ToString().ToLower()), + new Literal(type.IsExplicitLayout.ToString().ToLower()), + new Literal(type.IsPointer.ToString().ToLower()), + new Literal(type.IsFunctionPointer.ToString().ToLower()), + new Literal(type.IsUnmanagedFunctionPointer.ToString().ToLower()), + new Literal(type.IsLayoutSequential.ToString().ToLower()), + new Literal(type.IsMarshalByRef.ToString().ToLower()), + new Literal(type.IsNested.ToString().ToLower()), + new Literal(type.IsNestedAssembly.ToString().ToLower()), + new Literal(type.IsNestedFamily.ToString().ToLower()), + new Literal(type.IsNestedFamANDAssem.ToString().ToLower()), + new Literal(type.IsNestedFamORAssem.ToString().ToLower()), + new Literal(type.IsNestedPrivate.ToString().ToLower()), + new Literal(type.IsNestedPublic.ToString().ToLower()), + new Literal(type.IsNotPublic.ToString().ToLower()), + new Literal(type.IsPublic.ToString().ToLower()), + new Literal(type.IsSZArray.ToString().ToLower()), + new Literal(type.IsSecurityCritical.ToString().ToLower()), + new Literal(type.IsSecuritySafeCritical.ToString().ToLower()), + new Literal(type.IsSecurityTransparent.ToString().ToLower()), + new Literal(type.IsSignatureType.ToString().ToLower()), + new Literal(type.IsSpecialName.ToString().ToLower()), + new Literal(type.IsTypeDefinition.ToString().ToLower()), + new Literal(type.IsUnicodeClass.ToString().ToLower()), + new Literal(type.IsValueType.ToString().ToLower()), + new Literal(type.IsVariableBoundArray.ToString().ToLower()), + new Literal(type.IsVisible.ToString().ToLower()), + type != type.UnderlyingSystemType ? CreateTypeInfo(type.UnderlyingSystemType) : Nil(), + type.BaseType != null ? CreateTypeInfo(type.BaseType) : Nil(), + type.DeclaringType != null ? CreateTypeInfo(type.DeclaringType) : Nil(), + new Literal(type.ContainsGenericParameters.ToString().ToLower()), + new TableInitializer(type.GenericTypeArguments.Select(CreateTypeInfo).OfType().ToList()), + new Literal($"\"{type.GUID}\"") + ]; + + return new Parenthesized(new TableInitializer(values, keys)); + } - /// - /// Creates constructor info table for runtime type objects (via .GetType() and typeof()) - /// - public static TableInitializer CreateConstructorInfo(ConstructorInfo type) - { - List keys = [ - new Literal("Name"), - ]; - List values = [ - new Literal(type.Name), - ]; + /// + /// Creates constructor info table for runtime type objects (via .GetType() and typeof()) + /// + private static TableInitializer CreateConstructorInfo(ConstructorInfo type) + { + List keys = [ + new Literal("Name"), + ]; + List values = [ + new Literal(type.Name), + ]; - return new TableInitializer(values, keys); - } + return new TableInitializer(values, keys); + } - /// CS.defineGlobal(name, value) - public static Call DefineGlobal(Name name, Expression value) => - CSCall("defineGlobal", new Literal($"\"{name}\""), value); - - /// CS.getGlobal(name) - public static Call GetGlobal(Name name) => - CSCall("getGlobal", new Literal($"\"{name}\"")); - - /// - /// Creates a call to a CS library method - /// - public static Call CSCall(string methodName, params Expression[] arguments) => - new Call( - new MemberAccess( - new IdentifierName("CS"), - new IdentifierName(methodName) - ), - CreateArgumentList(arguments.ToList()) - ); + /// CS.defineGlobal(name, value) + public static Call DefineGlobal(Name name, Expression value) => + CSCall("defineGlobal", String(name.ToString()), value); + + /// CS.getGlobal(name) + public static Call GetGlobal(Name name) => + CSCall("getGlobal", String(name.ToString())); + + /// + /// Creates a call to a CS library method + /// + public static Call CSCall(string methodName, params Expression[] arguments) => + new Call( + new MemberAccess( + new IdentifierName("CS"), + new IdentifierName(methodName) + ), + CreateArgumentList(arguments.ToList()) + ); + + public static Variable SignalImport() => + new( + new IdentifierName("Signal"), + true, + // temporary until RojoReader + RequireCall(new Luau.QualifiedName( + new IdentifierName("rbxcs_include"), + new IdentifierName("GoodSignal") + )) + ); - public static Call RequireCall(Expression modulePath) => - new( - new IdentifierName("require"), - new ArgumentList([new Argument(modulePath)]) - ); + public static Call RequireCall(Expression modulePath) => + new( + new IdentifierName("require"), + new ArgumentList([new Argument(modulePath)]) + ); - public static Call PrintCall(params List args) => - new( - new IdentifierName("print"), - new ArgumentList(args.ConvertAll(value => new Argument(value))) - ); - - /// - /// Creates a call to a bit32 library method - /// - public static Call Bit32Call(string methodName, params Expression[] arguments) => - new( - new MemberAccess( - new IdentifierName("bit32"), - new IdentifierName(methodName) - ), - CreateArgumentList(arguments.ToList()) - ); - - public static ArgumentList CreateArgumentList(List arguments) => - new(arguments.ConvertAll(expression => new Argument(expression))); - - public static SimpleName TypeNameFromSymbol(ITypeSymbol symbol) - { - if (symbol is not INamedTypeSymbol { TypeParameters.Length: > 0 } namedTypeSymbol) - return new IdentifierName(symbol.Name); + public static Call PrintCall(params List args) => + new( + new IdentifierName("print"), + new ArgumentList(args.ConvertAll(value => new Argument(value))) + ); + + /// + /// Creates a call to a bit32 library method + /// + public static Call Bit32Call(string methodName, params Expression[] arguments) => + new( + new MemberAccess( + new IdentifierName("bit32"), + new IdentifierName(methodName) + ), + CreateArgumentList(arguments.ToList()) + ); + + public static ArgumentList CreateArgumentList(List arguments) => + new(arguments.ConvertAll(expression => new Argument(expression))); + + public static SimpleName TypeNameFromSymbol(ITypeSymbol symbol) + { + if (symbol is not INamedTypeSymbol { TypeParameters.Length: > 0 } namedTypeSymbol) + return new IdentifierName(symbol.Name); - var typeParameters = namedTypeSymbol.TypeParameters.Select(typeParameter => TypeNameFromSymbol(typeParameter).ToString()).ToList(); - return new GenericName(symbol.Name, typeParameters); - } + var typeParameters = namedTypeSymbol.TypeParameters.Select(typeParameter => TypeNameFromSymbol(typeParameter).ToString()).ToList(); + return new GenericName(symbol.Name, typeParameters); + } - /// - /// Returns the full name of a C# node's parent. - /// This method is meant for getting the absolute location of classes, enums, etc. - /// For example a class under the namespace "Some.Namespace" would return a that transpiles to "Some.Namespace". - /// - public static Expression? GetFullParentName(SyntaxNode node) + /// + /// Returns the full name of a C# node's parent. + /// This method is meant for getting the absolute location of classes, enums, etc. + /// For example a class under the namespace "Some.Namespace" would return a that transpiles to "Some.Namespace". + /// + public static Expression? GetFullParentName(SyntaxNode node) + { + switch (node.Parent) { - switch (node.Parent) - { - case null: - case CompilationUnitSyntax: - return null; - } - - var parentName = CreateSimpleName(node.Parent); - var parentLocation = GetFullParentName(node.Parent); - return parentLocation == null - ? ( - node.Parent.SyntaxTree == node.SyntaxTree - ? parentName - : CSCall("getGlobal", new Literal($"\"{(parentName is GenericName genericName ? genericName.Text : parentName.ToString())}\"")) - ) - : new MemberAccess(parentLocation, parentName); + case null: + case CompilationUnitSyntax: + return null; } - /// - /// if name == nil then - /// name = initializer - /// end - /// - public static If Initializer(Name name, Expression initializer) => - new( - new BinaryOperator(name, "==", Nil()), - new ExpressionStatement(new Assignment(name, initializer)) - ); - - /// - /// Takes a and converts it into a , given that inherits from - /// - public static QualifiedName QualifiedNameFromMemberAccess(MemberAccess memberAccess) - { - var left = memberAccess.Expression is MemberAccess leftMemberAccess ? - QualifiedNameFromMemberAccess(leftMemberAccess) - : (Name)memberAccess.Expression; + var parentName = CreateSimpleName(node.Parent); + var parentLocation = GetFullParentName(node.Parent); + return parentLocation == null + ? ( + node.Parent.SyntaxTree == node.SyntaxTree + ? parentName + : CSCall("getGlobal", new Literal($"\"{(parentName is GenericName genericName ? genericName.Text : parentName.ToString())}\"")) + ) + : new MemberAccess(parentLocation, parentName); + } - return new QualifiedName(left, memberAccess.Name); - } + /// + /// if name == nil then + /// name = initializer + /// end + /// + public static If DefaultValueInitializer(Name name, Expression initializer) => + new( + new BinaryOperator(name, "==", Nil()), + new ExpressionStatement(new Assignment(name, initializer)) + ); + + /// + /// Takes a and converts it into a , given that inherits from + /// + public static QualifiedName QualifiedNameFromMemberAccess(MemberAccess memberAccess) + { + var left = memberAccess.Expression is MemberAccess leftMemberAccess ? + QualifiedNameFromMemberAccess(leftMemberAccess) + : (Name)memberAccess.Expression; - /// - /// Creates a discard variable if is an - /// - public static Node DiscardVariableIfExpressionStatement(SyntaxNode node, Node value, SyntaxNode? valueParent) => - valueParent is ExpressionStatementSyntax ? - DiscardVariable(node, (Expression)value) - : value; - - /// local _ = discardedValue - public static Variable DiscardVariable(SyntaxNode node, Expression value) => - new(CreateSimpleName(node, "_"), true, value); - - public static GenericName? GetGenericName(Name name) => - name switch - { - GenericName baseName => baseName, - QualifiedName { Right: GenericName rightName } => rightName, - _ => null - }; + return new QualifiedName(left, memberAccess.Name); + } + + /// + /// Creates a discard variable if is an + /// + public static Node DiscardVariableIfExpressionStatement(SyntaxNode node, Node value, SyntaxNode? valueParent) => + valueParent is ExpressionStatementSyntax ? + DiscardVariable(node, (Expression)value) + : value; + + /// local _ = discardedValue + public static Variable DiscardVariable(SyntaxNode node, Expression value) => + new(CreateSimpleName(node, "_"), true, value); - /// - /// Takes a Name and converts it into a non-generic Name - /// - public static Name GetNonGenericName(Name name) => - name switch - { - QualifiedName qualifiedName => GetNonGenericName(qualifiedName), - SimpleName simpleName => GetNonGenericName(simpleName), - _ => name - }; + public static GenericName? GetGenericName(Name name) => + name switch + { + GenericName baseName => baseName, + QualifiedName { Right: GenericName rightName } => rightName, + _ => null + }; - /// - /// Takes a QualifiedName and converts it into a non-generic QualifiedName - /// - public static QualifiedName GetNonGenericName(QualifiedName qualifiedName) + /// + /// Takes a Name and converts it into a non-generic Name + /// + public static Name GetNonGenericName(Name name) => + name switch { - if (qualifiedName.Right is IdentifierName) - return qualifiedName; + QualifiedName qualifiedName => GetNonGenericName(qualifiedName), + SimpleName simpleName => GetNonGenericName(simpleName), + _ => name + }; + + /// + /// Takes a QualifiedName and converts it into a non-generic QualifiedName + /// + public static QualifiedName GetNonGenericName(QualifiedName qualifiedName) + { + if (qualifiedName.Right is IdentifierName) + return qualifiedName; - var right = GetNonGenericName(qualifiedName.Right); - return new QualifiedName(qualifiedName.Left, right); - } + var right = GetNonGenericName(qualifiedName.Right); + return new QualifiedName(qualifiedName.Left, right); + } - /// - /// Takes a SimpleName (which GenericName extends from) and converts it into a standard IdentifierName - /// - public static IdentifierName GetNonGenericName(SimpleName simpleName) - { - if (simpleName is IdentifierName identifierName) - return identifierName; + /// + /// Takes a SimpleName (which GenericName extends from) and converts it into a standard IdentifierName + /// + public static IdentifierName GetNonGenericName(SimpleName simpleName) + { + if (simpleName is IdentifierName identifierName) + return identifierName; - return new IdentifierName(simpleName is GenericName genericName - ? genericName.Text - : simpleName.ToString()); - } + return new IdentifierName(simpleName is GenericName genericName + ? genericName.Text + : simpleName.ToString()); + } - public static Name CreateName(SyntaxNode node, string text, bool registerIdentifier = false, bool bypassReserved = false) - { - Name name = CreateSimpleName(node, text, registerIdentifier, bypassReserved); - var pieces = text.Split('.'); - if (pieces.Length <= 0) - return name; - - return pieces - .Skip(1) - .Aggregate(name, (current, piece) => new QualifiedName(current, CreateSimpleName(node, piece))); - } + public static Name CreateName(SyntaxNode node, string text, bool registerIdentifier = false, bool bypassReserved = false) + { + Name name = CreateSimpleName(node, text, registerIdentifier, bypassReserved); + var pieces = text.Split('.'); + if (pieces.Length <= 0) + return name; + + return pieces + .Skip(1) + .Aggregate(name, (current, piece) => new QualifiedName(current, CreateSimpleName(node, piece))); + } - public static TNameNode CreateSimpleName(SyntaxNode node, bool registerIdentifier = false, bool bypassReserved = false) - where TNameNode : SimpleName - { - return (TNameNode)CreateSimpleName(node, registerIdentifier, bypassReserved); - } + public static TNameNode CreateSimpleName(SyntaxNode node, bool registerIdentifier = false, bool bypassReserved = false) + where TNameNode : SimpleName + { + return (TNameNode)CreateSimpleName(node, registerIdentifier, bypassReserved); + } - public static TNameNode CreateSimpleName(SyntaxNode node, string name, bool registerIdentifier = false, bool bypassReserved = false) - where TNameNode : SimpleName - { - return (TNameNode)CreateSimpleName(node, name, registerIdentifier, bypassReserved); - } + public static TNameNode CreateSimpleName(SyntaxNode node, string name, bool registerIdentifier = false, bool bypassReserved = false) + where TNameNode : SimpleName + { + return (TNameNode)CreateSimpleName(node, name, registerIdentifier, bypassReserved); + } - public static SimpleName CreateSimpleName(SyntaxNode node, bool registerIdentifier = false,bool bypassReserved = false) - { - return CreateSimpleName(node, string.Join("", StandardUtility.GetNamesFromNode(node)), registerIdentifier, bypassReserved); - } + public static SimpleName CreateSimpleName(SyntaxNode node, bool registerIdentifier = false,bool bypassReserved = false) + { + return CreateSimpleName(node, string.Join("", StandardUtility.GetNamesFromNode(node)), registerIdentifier, bypassReserved); + } - public static SimpleName CreateSimpleName(SyntaxNode node, string name, bool registerIdentifier = false, bool bypassReserved = false) - { - if (RESERVED_IDENTIFIERS.Contains(name) && !bypassReserved) - Logger.UnsupportedError(node, $"Using '{name}' as an identifier", useIs: true, useYet: false); + public static SimpleName CreateSimpleName(SyntaxNode node, string name, bool registerIdentifier = false, bool bypassReserved = false) + { + if (RESERVED_IDENTIFIERS.Contains(name) && !bypassReserved) + Logger.UnsupportedError(node, $"Using '{name}' as an identifier", useIs: true, useYet: false); - var text = registerIdentifier ? FixIdentifierNameText(node, name, registerIdentifier) : name; - return name.Contains('<') && name.Contains('>') - ? new GenericName(text.Split('<').First(), StandardUtility.ExtractTypeArguments(text)) - : new IdentifierName(text); - } + var text = registerIdentifier ? FixIdentifierNameText(node, name, registerIdentifier) : name; + return name.Contains('<') && name.Contains('>') + ? new GenericName(text.Split('<').First(), StandardUtility.ExtractTypeArguments(text)) + : new IdentifierName(text); + } - // TODO: per-scope duplicate handling - public static string FixIdentifierNameText(SyntaxNode node, string name, bool registerIdentifier = false) - { - _identifierDeclarations.TryAdd(node.SyntaxTree.FilePath, []); + // TODO: per-scope duplicate handling + public static string FixIdentifierNameText(SyntaxNode node, string name, bool registerIdentifier = false) + { + _identifierDeclarations.TryAdd(node.SyntaxTree.FilePath, []); - var identifiersInFile = _identifierDeclarations[node.SyntaxTree.FilePath]; - identifiersInFile.TryAdd(name, 0); + var identifiersInFile = _identifierDeclarations[node.SyntaxTree.FilePath]; + identifiersInFile.TryAdd(name, 0); - var useCount = identifiersInFile[name]; - if (registerIdentifier) - identifiersInFile[name]++; + var useCount = identifiersInFile[name]; + if (registerIdentifier) + identifiersInFile[name]++; - if (useCount <= 0) - return name; + if (useCount <= 0) + return name; - if (!name.EndsWith('_')) - name += '_'; + if (!name.EndsWith('_')) + name += '_'; - name += useCount; - return name; + name += useCount; + return name; + } + + public static TypeRef? CreateTypeRef(string? typePath) + { + switch (typePath) + { + case null: + case "var": + return null; } - public static TypeRef? CreateTypeRef(string? typePath) + var mappedTypePath = StandardUtility.GetMappedType(typePath); + if (mappedTypePath.EndsWith('?')) + return new OptionalType(CreateTypeRef(mappedTypePath.TrimEnd('?'))!); + + var mappedTypeMatch = Regex.Match(mappedTypePath, @"\{\s*\[([a-zA-Z0-9]+)\]:\s*(.*)\s*\}"); + if (mappedTypeMatch.Success) { - switch (typePath) - { - case null: - case "var": - return null; - } - - var mappedType = StandardUtility.GetMappedType(typePath); - var arrayMatch = Regex.Match(mappedType, @"\{[a-zA-Z0-9]+\}"); - if (mappedType.EndsWith('?')) - return new OptionalType(CreateTypeRef(mappedType.Replace("?", ""))!); - else if (arrayMatch.Success) - return new ArrayType(CreateTypeRef(arrayMatch.Value.Trim())!); - - return new TypeRef(mappedType, rawPath: true); + var keyType = CreateTypeRef(mappedTypeMatch.Groups[1].Value)!; + var valueType = CreateTypeRef(mappedTypeMatch.Groups[2].Value)!; + return new MappedType(keyType, valueType); } + + var arrayMatch = Regex.Match(mappedTypePath, @"\{\s*(.*)\s*\}"); + if (arrayMatch.Success) + return new ArrayType(CreateTypeRef(arrayMatch.Groups[1].Value.Trim())!); - public static TypeRef? CreateTypeRef(TypeSyntax? type) => CreateTypeRef(type?.ToString()); + return new TypeRef(mappedTypePath, rawPath: true); + } + + public static TypeRef? CreateTypeRef(TypeSyntax? type) => CreateTypeRef(type?.ToString()); - public static Literal String(string text) => new($"\"{text}\""); + public static Literal String(string text) => new($"\"{text}\""); - public static Literal Vararg() => new("..."); + public static Literal Vararg() => new("..."); - public static Literal False() => new("false"); + public static Literal False() => new("false"); - public static Literal True() => new("true"); + public static Literal True() => new("true"); - public static Literal Nil() => new("nil"); + public static Literal Nil() => new("nil"); - public static TypeRef AnyType() => new("any"); - - - } + public static TypeRef AnyType() => new("any"); } \ No newline at end of file diff --git a/RobloxCS.Luau/BaseWriter.cs b/RobloxCS.Luau/BaseWriter.cs index 56d8f33..03f6db7 100644 --- a/RobloxCS.Luau/BaseWriter.cs +++ b/RobloxCS.Luau/BaseWriter.cs @@ -1,70 +1,54 @@ using System.Text; -namespace RobloxCS.Luau +namespace RobloxCS.Luau; + +public class BaseWriter { - public class BaseWriter + public const int IndentSize = 2; + private readonly StringBuilder _output = new(); + private int _indent; + + public override string ToString() { - public static readonly int IndentSize = 2; - private readonly StringBuilder _output = new(); - private int _indent = 0; + return _output.ToString(); + } - public override string ToString() - { - return _output.ToString(); - } + public void PushIndent() => _indent++; - public void PushIndent() - { - _indent++; - } + public void PopIndent() => _indent--; - public void PopIndent() - { - _indent--; - } + public void WriteLine() => Write('\n'); - public void WriteLine() + public void WriteLine(string text) + { + if (string.IsNullOrEmpty(text)) { - Write('\n'); + _output.AppendLine(); + return; } - public void WriteLine(string text) - { - if (string.IsNullOrEmpty(text)) - { - _output.AppendLine(); - return; - } + WriteIndent(); + _output.AppendLine(text); + } - WriteIndent(); - _output.AppendLine(text); - } + public void WriteLine(char text) => WriteLine(text.ToString()); - public void WriteLine(char text) - { - WriteLine(text.ToString()); - } + public void Write(string text) + { + WriteIndent(); + _output.Append(text); + } - public void Write(string text) - { - WriteIndent(); - _output.Append(text); - } + public void Write(char text) => Write(text.ToString()); - public void Write(char text) - { - Write(text.ToString()); - } + private void WriteIndent() => + _output.Append(MatchLastCharacter('\n') ? string.Concat(Enumerable.Repeat(" ", IndentSize * _indent)) : ""); - private void WriteIndent() - { - _output.Append(MatchLastCharacter('\n') ? string.Concat(Enumerable.Repeat(" ", IndentSize * _indent)) : ""); - } - - private bool MatchLastCharacter(char character) - { - if (_output.Length == 0) return false; - return _output[^1] == character; - } + private bool MatchLastCharacter(char character) + { + if (_output.Length == 0) + return false; + + return _output[^1] == character; } -} +} \ No newline at end of file diff --git a/RobloxCS.Luau/LuauWriter.cs b/RobloxCS.Luau/LuauWriter.cs index aef0b4a..c65a945 100644 --- a/RobloxCS.Luau/LuauWriter.cs +++ b/RobloxCS.Luau/LuauWriter.cs @@ -63,7 +63,7 @@ public void WriteFunction(Name? name, bool isLocal, ParameterList parameterList, } else if (parameter.Initializer != null) { - body.Statements.Insert(0, AstUtility.Initializer(parameter.Name, parameter.Initializer)); + body.Statements.Insert(0, AstUtility.DefaultValueInitializer(parameter.Name, parameter.Initializer)); } } body.Render(this); diff --git a/RobloxCS.Luau/SymbolMetadataManager.cs b/RobloxCS.Luau/SymbolMetadataManager.cs index 18949a5..4b3c9a6 100644 --- a/RobloxCS.Luau/SymbolMetadataManager.cs +++ b/RobloxCS.Luau/SymbolMetadataManager.cs @@ -1,6 +1,6 @@ using Microsoft.CodeAnalysis; -namespace RobloxCS; +namespace RobloxCS.Luau; public class SymbolMetadata { diff --git a/RobloxCS.Shared/Constants.cs b/RobloxCS.Shared/Constants.cs index fe05adf..cd065d1 100644 --- a/RobloxCS.Shared/Constants.cs +++ b/RobloxCS.Shared/Constants.cs @@ -5,6 +5,7 @@ namespace RobloxCS.Shared; public static class Constants { public const string HeaderComment = "Compiled with roblox-cs v2.0.0"; + public const string IncludeFolderName = "Include"; public static readonly HashSet UNSUPPORTED_BITWISE_TYPES = [ diff --git a/RobloxCS.Shared/StandardUtility.cs b/RobloxCS.Shared/StandardUtility.cs index 4a56422..84198f3 100644 --- a/RobloxCS.Shared/StandardUtility.cs +++ b/RobloxCS.Shared/StandardUtility.cs @@ -140,8 +140,10 @@ public static string GetMappedType(string csharpType) "object" => "any", "void" or "null" => "nil", "char" or "Char" or "String" => "string", - "double" or "float" => "number", - _ => INTEGER_TYPES.Contains(csharpType) ? "number" : csharpType + "bool" => "boolean", + _ => INTEGER_TYPES.Contains(csharpType) || DECIMAL_TYPES.Contains(csharpType) + ? "number" + : csharpType }; } diff --git a/RobloxCS.Tests/AstUtilityTest.cs b/RobloxCS.Tests/AstUtilityTest.cs new file mode 100644 index 0000000..06d54a6 --- /dev/null +++ b/RobloxCS.Tests/AstUtilityTest.cs @@ -0,0 +1,96 @@ +using RobloxCS.Luau; + +namespace RobloxCS.Tests; + +public class AstUtilityTest +{ + [Fact] + public void AddOne() + { + var expression = AstUtility.AddOne(new IdentifierName("a")); + Assert.IsType(expression); + + var binaryOperator = (BinaryOperator)expression; + Assert.IsType(binaryOperator.Left); + Assert.IsType(binaryOperator.Right); + Assert.Equal("+", binaryOperator.Operator); + + var identifier = (IdentifierName)binaryOperator.Left; + var literal = (Literal)binaryOperator.Right; + Assert.Equal("a", identifier.Text); + Assert.Equal("1", literal.ValueText); + } + + [Fact] + public void AddOne_AddsToLiteralValue() + { + var sum = AstUtility.AddOne(new Literal("1")); + Assert.IsType(sum); + + var literal = (Literal)sum; + Assert.Equal("2", literal.ValueText); + } + + [Fact] + public void SubtractOne() + { + var expression = AstUtility.SubtractOne(new IdentifierName("a")); + Assert.IsType(expression); + + var binaryOperator = (BinaryOperator)expression; + Assert.IsType(binaryOperator.Left); + Assert.IsType(binaryOperator.Right); + Assert.Equal("-", binaryOperator.Operator); + + var identifier = (IdentifierName)binaryOperator.Left; + var literal = (Literal)binaryOperator.Right; + Assert.Equal("a", identifier.Text); + Assert.Equal("1", literal.ValueText); + } + + [Fact] + public void SubtractOne_SubtractsFromLiteralValue() + { + var sum = AstUtility.SubtractOne(new Literal("2")); + Assert.IsType(sum); + + var literal = (Literal)sum; + Assert.Equal("1", literal.ValueText); + } + + [Theory] + [InlineData("var")] + [InlineData(null)] + public void CreateTypeRef_ReturnsNull(string? path) => + Assert.Null(AstUtility.CreateTypeRef(path)); + + [Theory] + [InlineData("string?", typeof(OptionalType))] + [InlineData("{ number }", typeof(ArrayType))] + [InlineData("{ [string]: number }", typeof(MappedType))] + public void CreateTypeRef_ReturnsCorrectTypeNode(string? path, Type typeNodeType) + { + var typeRef = AstUtility.CreateTypeRef(path); + Assert.NotNull(typeRef); + Assert.IsType(typeNodeType, typeRef); + } + + [Fact] + public void CreateTypeRef_HandlesNestedPatterns() + { + const string rawPath = "{ [string]: { bool } }??"; + var typeRef = AstUtility.CreateTypeRef(rawPath); + Assert.NotNull(typeRef); + Assert.IsType(typeRef); + + var optionalType = (OptionalType)typeRef; + Assert.IsType(optionalType.NonNullableType); + + var mappedType = (MappedType)optionalType.NonNullableType; + Assert.Equal("string", mappedType.KeyType.Path); + Assert.IsType(mappedType.ValueType); + + var arrayType = (ArrayType)mappedType.ValueType; + Assert.Equal("boolean", arrayType.ElementType.Path); + } +} \ No newline at end of file diff --git a/RobloxCS.Tests/GenerationTest.cs b/RobloxCS.Tests/GenerationTest.cs new file mode 100644 index 0000000..d3eea6f --- /dev/null +++ b/RobloxCS.Tests/GenerationTest.cs @@ -0,0 +1,38 @@ +using Microsoft.CodeAnalysis.CSharp; +using RobloxCS.Luau; + +namespace RobloxCS.Tests; + +public class GenerationTest +{ + [Theory] + [InlineData("69.420", "69.42")] + [InlineData("420", "420")] + [InlineData("\"abc\"", "\"abc\"")] + [InlineData("'a'", "\"a\"")] + [InlineData("true", "true")] + [InlineData("false", "false")] + [InlineData("null", "nil")] + public void Generates_Literals(string csharpValueText, string luauValueText) + { + var ast = Generate(csharpValueText); + Assert.NotEmpty(ast.Statements); + + var statement = ast.Statements.Skip(1).First(); + Assert.IsType(statement); + + var expressionStatement = (ExpressionStatement)statement; + Assert.IsType(expressionStatement.Expression); + + var literal = (Literal)expressionStatement.Expression; + Assert.Equal(luauValueText, literal.ValueText); + } + + private static AST Generate(string source) + { + var tree = SyntaxFactory.ParseSyntaxTree(source); + var compiler = TranspilerUtility.GetCompiler([tree], null); + + return TranspilerUtility.GetLuauAST(tree, compiler); + } +} \ No newline at end of file diff --git a/RobloxCS.Tests/RuntimeLibTest.cs b/RobloxCS.Tests/LuauTests.cs similarity index 93% rename from RobloxCS.Tests/RuntimeLibTest.cs rename to RobloxCS.Tests/LuauTests.cs index 701e726..2bb01a2 100644 --- a/RobloxCS.Tests/RuntimeLibTest.cs +++ b/RobloxCS.Tests/LuauTests.cs @@ -5,14 +5,14 @@ namespace RobloxCS.Tests; -public class RuntimeLibTest(ITestOutputHelper testOutputHelper) +public class LuauTests(ITestOutputHelper testOutputHelper) { private readonly string _cwd = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))))!; [Theory] [InlineData("RuntimeLibTest")] - public void RuntimeLib_PassesTests(string scriptName) + public void LuauTests_Pass(string scriptName) { var lunePath = Path.GetFullPath("lune" + (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : ""), _cwd); var runScriptArguments = $"run {scriptName}"; diff --git a/RobloxCS.Tests/RenderingTest.cs b/RobloxCS.Tests/RenderingTest.cs index a25b3f7..c5ae024 100644 --- a/RobloxCS.Tests/RenderingTest.cs +++ b/RobloxCS.Tests/RenderingTest.cs @@ -285,7 +285,7 @@ public void Renders_BuiltInAttributes() var attribute = new BuiltInAttribute(new IdentifierName("native")); var output = Render(attribute); - Assert.Equal("@native", output); + Assert.Equal("@native\n", output); } [Fact] @@ -417,22 +417,11 @@ public void Renders_Assignment() Assert.Equal("a[69] = 420", output); } - [Fact] - public void Renders_AssignmentFunctionName() - { - const string result = "Abc:myMethod"; - var functionName = new AssignmentFunctionName(new IdentifierName("Abc"), new IdentifierName("myMethod"), ':'); - var output = Render(functionName); - - Assert.Equal(result, output); - Assert.Equal(result, functionName.ToString()); - } - [Fact] public void Renders_QualifiedName() { - const string result = "Abc.myMethod"; - var name = new QualifiedName(new IdentifierName("Abc"), new IdentifierName("myMethod")); + const string result = "Abc:myMethod"; + var name = new QualifiedName(new IdentifierName("Abc"), new IdentifierName("myMethod"), ':'); var output = Render(name); Assert.Equal(result, output); @@ -617,6 +606,24 @@ public void Renders_Functions(bool isLocal) Assert.Equal(expectedOutput.Replace("\r", ""), output.Replace("\r", "")); } + [Fact] + public void Renders_Continue() + { + var @continue = new Continue(); + var output = Render(@continue); + + Assert.Equal("continue\n", output); + } + + [Fact] + public void Renders_Break() + { + var @break = new Break(); + var output = Render(@break); + + Assert.Equal("break\n", output); + } + private static string Render(Node node) { var writer = new LuauWriter(); diff --git a/RobloxCS/BaseGenerator.cs b/RobloxCS/BaseGenerator.cs index 2cc4c9d..e9134be 100644 --- a/RobloxCS/BaseGenerator.cs +++ b/RobloxCS/BaseGenerator.cs @@ -85,7 +85,7 @@ protected Function GenerateConstructor(ClassDeclarationSyntax classDeclaration, body.Statements.Add(new Return(AstUtility.Nil())); return new Function( - new AssignmentFunctionName(nonGenericName, className, ':'), + new QualifiedName(nonGenericName, className, ':'), false, parameterList, new OptionalType(AstUtility.CreateTypeRef(className.ToString())!), diff --git a/RobloxCS/LuauGenerator.cs b/RobloxCS/LuauGenerator.cs index 3d68036..60ffd50 100644 --- a/RobloxCS/LuauGenerator.cs +++ b/RobloxCS/LuauGenerator.cs @@ -25,19 +25,7 @@ public sealed class LuauGenerator(SyntaxTree tree, CSharpCompilation compiler) : public override Luau.AST VisitCompilationUnit(CompilationUnitSyntax node) { - List statements = [ - new Luau.SingleLineComment(Shared.Constants.HeaderComment + "\n\n"), - new Luau.Variable( - new Luau.IdentifierName("Signal"), - true, - // temporary until RojoReader - Luau.AstUtility.RequireCall(new Luau.QualifiedName( - new Luau.IdentifierName("rbxcs_include"), - new Luau.IdentifierName("GoodSignal") - )) - ), - new Luau.NoOp() // for the newline - ]; + List statements = [new Luau.SingleLineComment(Shared.Constants.HeaderComment + "\n\n")]; void visitStatement(MemberDeclarationSyntax member) { @@ -57,6 +45,14 @@ memberDeclarationSyntax is GlobalStatementSyntax globalStatement ); } + if (node.DescendantNodes().Any(descendant => + descendant.IsKind(SyntaxKind.EventDeclaration) || descendant.IsKind(SyntaxKind.EventFieldDeclaration))) + { + statements.Add(Luau.AstUtility.SignalImport()); + statements.Add(new Luau.NoOp()); // for the newline + } + + var hoistedNodes = node.Members.Where(checkGlobalKind); var regularNodes = node.Members.Where(member => !checkGlobalKind(member)); foreach (var member in hoistedNodes) @@ -67,8 +63,14 @@ memberDeclarationSyntax is GlobalStatementSyntax globalStatement return new Luau.AST(statements); } - public override Luau.Name VisitPredefinedType(PredefinedTypeSyntax node) => - new Luau.IdentifierName(node.Keyword.Text); + public override Luau.Name? VisitPredefinedType(PredefinedTypeSyntax node) => + Luau.AstUtility.CreateTypeRef(node.Keyword.Text); + + public override Luau.ArrayType VisitArrayType(ArrayTypeSyntax node) => + new(Luau.AstUtility.CreateTypeRef(Visit(node.ElementType).ToString())!); + + public override Luau.OptionalType VisitNullableType(NullableTypeSyntax node) => + new(Luau.AstUtility.CreateTypeRef(Visit(node.ElementType).ToString())!); public override Luau.Statement VisitPropertyDeclaration(PropertyDeclarationSyntax node) { @@ -219,7 +221,7 @@ [new Luau.IdentifierName("__tostring")], ) ), new Luau.Function( - new Luau.AssignmentFunctionName(nonGenericName, new Luau.IdentifierName("new")), + new Luau.QualifiedName(nonGenericName, new Luau.IdentifierName("new")), false, constructor.ParameterList, typeRef, @@ -286,6 +288,7 @@ [new Luau.IdentifierName("__tostring")], ) )); + statements.Add(new Luau.NoOp()); // for the newline return new Luau.Block(statements); } @@ -338,26 +341,31 @@ public override Luau.Block VisitEnumDeclaration(EnumDeclarationSyntax node) } return new Luau.Block([ - new Luau.Variable(Luau.AstUtility.GetNonGenericName(name), true, null), + new Luau.Variable(Luau.AstUtility.GetNonGenericName(name), true), new Luau.ScopedBlock(statements), - new Luau.TypeAlias(name, finalType) + new Luau.TypeAlias(name, finalType), + new Luau.NoOp() // for the newline ]); } public override Luau.Block VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) { var name = Luau.AstUtility.CreateSimpleName(node, registerIdentifier: true); - var members = new Luau.Block(node.Members.Select(Visit).ToList()); var typeRef = Luau.AstUtility.CreateTypeRef(name.ToString()); - List statements = [ + var members = new Luau.Block(node.Members.Select(Visit).ToList()); + List statements = + [ new Luau.Variable(Luau.AstUtility.GetNonGenericName(name), true, new Luau.TableInitializer(), typeRef) ]; if (IsGlobal(node)) statements.Add(new Luau.ExpressionStatement(Luau.AstUtility.DefineGlobal(name, name))); - statements.Add(new Luau.ScopedBlock(members.Statements)); - statements.Add(new Luau.TypeAlias(name, new Luau.TypeOfCall(name))); - + statements.AddRange( + new Luau.ScopedBlock(members.Statements), + new Luau.TypeAlias(name, new Luau.TypeOfCall(name)), + new Luau.NoOp() // for the newline + ); + return new Luau.Block(statements); } @@ -975,7 +983,7 @@ public override Luau.Function VisitLocalFunctionStatement(LocalFunctionStatement public override Luau.Parameter VisitParameter(ParameterSyntax node) { var name = Luau.AstUtility.CreateSimpleName(node, registerIdentifier: true); - var returnType = Luau.AstUtility.CreateTypeRef(node.Type); + var returnType = Luau.AstUtility.CreateTypeRef(Visit(node.Type).ToString()); var initializer = Visit(node.Default); var isParams = HasSyntax(node.Modifiers, SyntaxKind.ParamsKeyword); @@ -990,16 +998,12 @@ public override Luau.Parameter VisitParameter(ParameterSyntax node) return new Luau.BuiltInAttribute(new Luau.IdentifierName("native")); } - Logger.UnsupportedError(node, "Non-builtin attributes"); + Logger.UnsupportedError(node, "User-defined attributes"); return null; } - public override Luau.AttributeList VisitAttributeList(AttributeListSyntax node) - { - var attributes = node.Attributes.Select(Visit).ToList(); - - return new Luau.AttributeList(attributes); - } + public override Luau.AttributeList VisitAttributeList(AttributeListSyntax node) => + new(node.Attributes.Select(Visit).Where(luauNode => luauNode != null)!.ToList()); public override Luau.Statement VisitGlobalStatement(GlobalStatementSyntax node) { @@ -1013,14 +1017,13 @@ public override Luau.Statement VisitGlobalStatement(GlobalStatementSyntax node) } public override Luau.ParameterList VisitParameterList(ParameterListSyntax node) => - new Luau.ParameterList(node.Parameters.Select(Visit).OfType().ToList()); + new(node.Parameters.Select(Visit).OfType().ToList()); public override Luau.Statement VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node) => Visit(node.Declaration); public override Luau.VariableList VisitVariableDeclaration(VariableDeclarationSyntax node) { - var typeRef = Luau.AstUtility.CreateTypeRef(node.Type); var variables = node.Variables.Select(Visit).OfType().ToList(); return new Luau.VariableList(variables); diff --git a/RobloxCS/Transpiler.cs b/RobloxCS/Transpiler.cs index 3bec199..d318571 100644 --- a/RobloxCS/Transpiler.cs +++ b/RobloxCS/Transpiler.cs @@ -10,7 +10,8 @@ namespace RobloxCS; /// public static class Transpiler { - private const string _includeFolderName = "Include"; + + private static readonly HashSet _ignoredDiagnostics = [ "CS5001" // more than 2 entry points @@ -19,11 +20,12 @@ public static class Transpiler public static string Transpile(string source) { var tree = ParseSource(source); - var compiler = TranspilerUtility.GetCompiler([tree]); + var compiler = TranspilerUtility.GetCompiler([tree], null); // temporary null config!!!1 foreach (var diagnostic in compiler.GetDiagnostics().Where(diagnostic => !_ignoredDiagnostics.Contains(diagnostic.Id))) Logger.HandleDiagnostic(diagnostic); - return WriteLuaOutput(compiler); + + return TranspilerUtility.GenerateLuau(tree, compiler); } private static SyntaxTree ParseSource(string source) @@ -33,11 +35,4 @@ private static SyntaxTree ParseSource(string source) return TranspilerUtility.TransformTree(tree, transformers); } - - private static string WriteLuaOutput(CSharpCompilation compiler) - { - var tree = compiler.SyntaxTrees.First(); - var generatedLua = TranspilerUtility.GenerateLua(tree, compiler); - return generatedLua; - } } \ No newline at end of file diff --git a/RobloxCS/TranspilerUtility.cs b/RobloxCS/TranspilerUtility.cs index da28eaa..214f854 100644 --- a/RobloxCS/TranspilerUtility.cs +++ b/RobloxCS/TranspilerUtility.cs @@ -7,16 +7,21 @@ namespace RobloxCS; public static class TranspilerUtility { - public static string GenerateLua(SyntaxTree tree, CSharpCompilation compiler) + public static string GenerateLuau(SyntaxTree tree, CSharpCompilation compiler) { - var generator = new LuauGenerator(tree, compiler); - var luauAST = generator.GetLuauAST(); + var luauAST = GetLuauAST(tree, compiler); var luau = new LuauWriter(); return luau.Render(luauAST); } + + public static AST GetLuauAST(SyntaxTree tree, CSharpCompilation compiler) + { + var generator = new LuauGenerator(tree, compiler); + return generator.GetLuauAST(); + } - public static CSharpCompilation GetCompiler(List trees, ConfigData? config = null) + public static CSharpCompilation GetCompiler(List trees, ConfigData? config) { // config ??= ConfigReader.UnitTestingConfig;