Browse Source

Merge pull request #7 from AnnulusGames/fix-bugs

Fix parser/compiler bugs
Annulus Games 1 year ago
parent
commit
4ed74937ec

+ 20 - 4
src/Lua/CodeAnalysis/Compilation/LuaCompiler.cs

@@ -79,11 +79,11 @@ public sealed class LuaCompiler : ISyntaxNodeVisitor<ScopeCompilationContext, bo
     // vararg
     public bool VisitVariableArgumentsExpressionNode(VariableArgumentsExpressionNode node, ScopeCompilationContext context)
     {
-        CompileVariableArgumentsExpression(node, context);
+        CompileVariableArgumentsExpression(node, context, 1);
         return true;
     }
 
-    void CompileVariableArgumentsExpression(VariableArgumentsExpressionNode node, ScopeCompilationContext context, int resultCount = -1)
+    void CompileVariableArgumentsExpression(VariableArgumentsExpressionNode node, ScopeCompilationContext context, int resultCount)
     {
         context.PushInstruction(Instruction.VarArg(context.StackPosition, (ushort)(resultCount == -1 ? 0 : resultCount + 1)), node.Position, true);
     }
@@ -213,16 +213,32 @@ public sealed class LuaCompiler : ISyntaxNodeVisitor<ScopeCompilationContext, bo
                     case ListTableConstructorField listItem:
                         context.StackPosition = (byte)(p + currentArrayChunkSize - 50 * (arrayBlock - 1));
 
-                        listItem.Expression.Accept(this, context);
-
                         // For the last element, we need to take into account variable arguments and multiple return values.
                         if (listItem == lastField)
                         {
+                            switch (listItem.Expression)
+                            {
+                                case CallFunctionExpressionNode call:
+                                    CompileCallFunctionExpression(call, context, false, -1);
+                                    break;
+                                case CallTableMethodExpressionNode method:
+                                    CompileTableMethod(method, context, false, -1);
+                                    break;
+                                case VariableArgumentsExpressionNode varArg:
+                                    CompileVariableArgumentsExpression(varArg, context, -1);
+                                    break;
+                                default:
+                                    listItem.Expression.Accept(this, context);
+                                    break;
+                            }
+
                             context.PushInstruction(Instruction.SetList(tableRegisterIndex, 0, arrayBlock), listItem.Position);
                             currentArrayChunkSize = 0;
                         }
                         else
                         {
+                            listItem.Expression.Accept(this, context);
+
                             currentArrayChunkSize++;
 
                             if (currentArrayChunkSize == 50)

+ 0 - 1
src/Lua/CodeAnalysis/Syntax/Lexer.cs

@@ -299,7 +299,6 @@ public ref struct Lexer
         {
             var quote = c1;
             var stringStartOffset = offset;
-            Advance(1);
 
             while (span.Length > offset)
             {

+ 34 - 48
src/Lua/CodeAnalysis/Syntax/Parser.cs

@@ -545,7 +545,7 @@ public ref struct Parser
         {
             SyntaxTokenType.Identifier => enumerator.GetNext(true).Type switch
             {
-                SyntaxTokenType.LParen or SyntaxTokenType.String => ParseCallFunctionExpression(ref enumerator),
+                SyntaxTokenType.LParen or SyntaxTokenType.String => ParseCallFunctionExpression(ref enumerator, null),
                 SyntaxTokenType.LSquare or SyntaxTokenType.Dot or SyntaxTokenType.Colon => ParseTableAccessExpression(ref enumerator, null),
                 _ => new IdentifierNode(enumerator.Current.Text, enumerator.Current.Position),
             },
@@ -565,15 +565,34 @@ public ref struct Parser
 
         if (result == null) return false;
 
-        while (true)
+        // nested table access & function call
+    RECURSIVE:
+        enumerator.SkipEoL();
+        
+        var nextType = enumerator.GetNext().Type;
+        if (nextType is SyntaxTokenType.LSquare or SyntaxTokenType.Dot or SyntaxTokenType.Colon)
         {
-            enumerator.SkipEoL();
+            MoveNextWithValidation(ref enumerator);
+            result = ParseTableAccessExpression(ref enumerator, result);
+            goto RECURSIVE;
+        }
+        else if (nextType is SyntaxTokenType.LParen)
+        {
+            MoveNextWithValidation(ref enumerator);
+            result = ParseCallFunctionExpression(ref enumerator, result);
+            goto RECURSIVE;
+        }
 
+        // binary expression
+        while (true)
+        {
             var opPrecedence = GetPrecedence(enumerator.GetNext().Type);
             if (precedence >= opPrecedence) break;
 
             MoveNextWithValidation(ref enumerator);
             result = ParseBinaryExpression(ref enumerator, opPrecedence, result);
+
+            enumerator.SkipEoL();
         }
 
         return true;
@@ -779,28 +798,6 @@ public ref struct Parser
             return null!; // dummy
         }
 
-        // parse child table element
-    PARSE_CHILD:
-        var nextType = enumerator.GetNext(true).Type;
-        if (nextType is SyntaxTokenType.Dot or SyntaxTokenType.LSquare or SyntaxTokenType.Colon)
-        {
-            enumerator.SkipEoL();
-            enumerator.MoveNext();
-            enumerator.SkipEoL();
-
-            result = ParseTableAccessExpression(ref enumerator, result);
-        }
-        if (nextType is SyntaxTokenType.LParen)
-        {
-            enumerator.SkipEoL();
-            enumerator.MoveNext();
-            enumerator.SkipEoL();
-
-            var parameters = ParseCallFunctionArguments(ref enumerator);
-            result = new CallFunctionExpressionNode(result, parameters);
-            goto PARSE_CHILD;
-        }
-
         return result;
     }
 
@@ -819,32 +816,21 @@ public ref struct Parser
         return expression;
     }
 
-    ExpressionNode ParseCallFunctionExpression(ref SyntaxTokenEnumerator enumerator)
+    ExpressionNode ParseCallFunctionExpression(ref SyntaxTokenEnumerator enumerator, ExpressionNode? function)
     {
         // parse name
-        CheckCurrent(ref enumerator, SyntaxTokenType.Identifier);
-        var function = new IdentifierNode(enumerator.Current.Text, enumerator.Current.Position);
-        enumerator.MoveNext();
-        enumerator.SkipEoL();
-
-        // parse parameters
-        var parameters = ParseCallFunctionArguments(ref enumerator);
-
-        var expression = new CallFunctionExpressionNode(function, parameters);
-
-        // parse table access expression
-        if (enumerator.GetNext(true).Type is SyntaxTokenType.LSquare or SyntaxTokenType.Dot or SyntaxTokenType.Colon)
+        if (function == null)
         {
-            enumerator.SkipEoL();
+            CheckCurrent(ref enumerator, SyntaxTokenType.Identifier);
+            function = new IdentifierNode(enumerator.Current.Text, enumerator.Current.Position);
             enumerator.MoveNext();
             enumerator.SkipEoL();
-
-            return ParseTableAccessExpression(ref enumerator, expression);
-        }
-        else
-        {
-            return expression;
         }
+
+        // parse parameters
+        var parameters = ParseCallFunctionArguments(ref enumerator);
+
+        return new CallFunctionExpressionNode(function, parameters);
     }
 
     FunctionDeclarationExpressionNode ParseFunctionDeclarationExpression(ref SyntaxTokenEnumerator enumerator)
@@ -877,10 +863,10 @@ public ref struct Parser
 
             MoveNextWithValidation(ref enumerator);
             enumerator.SkipEoL();
-        }
 
-        // check ')'
-        CheckCurrent(ref enumerator, SyntaxTokenType.RParen);
+            // check ')'
+            CheckCurrent(ref enumerator, SyntaxTokenType.RParen);
+        }
 
         return arguments;
     }

+ 1 - 0
tests/Lua.Tests/LexerTests.cs

@@ -67,6 +67,7 @@ public class LexerTests
     }
 
     [Test]
+    [TestCase("\"\"")]
     [TestCase("\"hello\"")]
     [TestCase("\"1.23\"")]
     [TestCase("\"1-2-3-4-5\"")]