Browse Source

fix: parser

Akeit0 7 months ago
parent
commit
21eeb522ea

+ 4 - 4
src/Lua/CodeAnalysis/Compilation/Dump.cs

@@ -51,7 +51,7 @@ internal unsafe struct Header
         {
             if (!LuaSignature.SequenceEqual(new(signature, 4)))
             {
-                throw new Exception($"{name.ToString()}: is not a precompiled chunk");
+                throw new LuaParseException($"{name.ToString()}: is not a precompiled chunk");
             }
         }
 
@@ -59,7 +59,7 @@ internal unsafe struct Header
         var minor = Version & 0xF;
         if (major != Constants.VersionMajor || minor != Constants.VersionMinor)
         {
-            throw new Exception($"{name.ToString()}: version mismatch in precompiled chunk {major}.{minor} != {Constants.VersionMajor}.{Constants.VersionMinor}");
+            throw new LuaParseException($"{name.ToString()}: version mismatch in precompiled chunk {major}.{minor} != {Constants.VersionMajor}.{Constants.VersionMinor}");
         }
 
         if (IntSize != 4 || Format != 0 || IntegralNumber != 0 || PointerSize is not (4 or 8) || InstructionSize != 4 || NumberSize != 8)
@@ -77,7 +77,7 @@ internal unsafe struct Header
 
         return;
     ErrIncompatible:
-        throw new Exception($"{name.ToString()}: incompatible precompiled chunk");
+        throw new LuaParseException($"{name.ToString()}: incompatible precompiled chunk");
     }
 }
 
@@ -274,7 +274,7 @@ internal unsafe ref struct UnDumpState(ReadOnlySpan<byte> span,ReadOnlySpan<char
     int pointerSize;
     readonly ReadOnlySpan<char> name = name;
 
-    void Throw(string why) => throw new Exception($"{name.ToString()}: {why} precompiled chunk");
+    void Throw(string why) => throw new LuaParseException($"{name.ToString()}: {why} precompiled chunk");
     void ThrowTooShort() => Throw("truncate");
 
     [MethodImpl(MethodImplOptions.AggressiveInlining)]

+ 4 - 5
src/Lua/CodeAnalysis/Compilation/Parser.cs

@@ -106,10 +106,11 @@ internal class Parser : IPoolNode<Parser>, IDisposable
     public void LeaveLevel() => Scanner.L.CallCount--;
 
 
-    public void EnterLevel()
+    public TempBlock EnterLevel()
     {
         Scanner.L.CallCount++;
         CheckLimit(Scanner.L.CallCount, MaxCallCount, "Go levels");
+        return new TempBlock(Scanner.L);
     }
 
 
@@ -399,7 +400,7 @@ internal class Parser : IPoolNode<Parser>, IDisposable
 
     public (ExprDesc, int ) SubExpression(int limit)
     {
-        EnterLevel();
+        using var b = EnterLevel();
         ExprDesc e = default;
         int u = UnaryOp(T);
         if (u != OprNoUnary)
@@ -425,7 +426,6 @@ internal class Parser : IPoolNode<Parser>, IDisposable
             op = next;
         }
 
-        LeaveLevel();
         return (e, op);
     }
 
@@ -905,7 +905,7 @@ internal class Parser : IPoolNode<Parser>, IDisposable
     public void Statement()
     {
         var line = Scanner.LineNumber;
-        EnterLevel();
+        using var _ = EnterLevel();
         switch (T)
         {
             case ';':
@@ -962,7 +962,6 @@ internal class Parser : IPoolNode<Parser>, IDisposable
 
         Assert(Function.Proto.MaxStackSize >= Function.FreeRegisterCount && Function.FreeRegisterCount >= Function.ActiveVariableCount);
         Function.FreeRegisterCount = Function.ActiveVariableCount;
-        LeaveLevel();
     }
 
 

+ 12 - 32
src/Lua/CodeAnalysis/Compilation/Scanner.cs

@@ -26,32 +26,9 @@ internal struct Scanner
 
     static string ChunkID(string source)
     {
-        const int IdSize = 60;
-        switch (source[0])
-        {
-            case '=': // "literal" source
-                if (source.Length <= IdSize)
-                {
-                    return source[1..];
-                }
-
-                return source[1..IdSize];
-            case '@': // file name
-                if (source.Length <= IdSize)
-                {
-                    return source[1..];
-                }
-
-                return "..." + source[1..(IdSize - 3)];
-        }
-
-        source = source.Split('\n')[0];
-        if (source.Length > IdSize - 12)
-        {
-            return "[string \"" + source + "...\"]";
-        }
-
-        return "[string \"" + source + "\"]";
+        var shortSourceBuffer = (stackalloc char[59]);
+        var len = LuaDebug.WriteShortSource(source, shortSourceBuffer);
+        return shortSourceBuffer[..len].ToString();
     }
 
 
@@ -223,11 +200,11 @@ internal struct Scanner
                 case EndOfStream:
                     if (comment)
                     {
-                        ScanError("unfinished long comment", 0);
+                        ScanError("unfinished long comment", TkEOS);
                     }
                     else
                     {
-                        ScanError("unfinished long string", 0);
+                        ScanError("unfinished long string", TkEOS);
                     }
 
                     break;
@@ -237,7 +214,7 @@ internal struct Scanner
                         SaveAndAdvance();
                         if (!comment)
                         {
-                            var s = Buffer.ToString(2 + sep, Buffer.Length - (4 + sep));
+                            var s = Buffer.ToString(2 + sep, Buffer.Length - (4 + 2*sep));
                             Buffer.Clear();
                             return s;
                         }
@@ -436,6 +413,7 @@ internal struct Scanner
     public void EscapeError(ReadOnlySpan<int> c, string message)
     {
         Buffer.Clear();
+        Save('\'');
         Save('\\');
         foreach (var r in c)
         {
@@ -446,7 +424,9 @@ internal struct Scanner
 
             Save(r);
         }
-
+        Save('\'');
+        Token.S = Buffer.ToString();
+        Buffer.Clear();
         ScanError(message, TkString);
     }
 
@@ -825,11 +805,11 @@ internal struct Scanner
         }
     }
 
-    static bool IsWhiteSpace(int c) => c == ' ' || c == '\t' || c == '\n' || c == '\r';
+    static bool IsWhiteSpace(int c) => c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v';
     static bool IsDigit(int c) => c is >= '0' and <= '9';
 
     static bool IsLetter(int c)
     {
-        return c < ushort.MaxValue && (char.IsLetter((char)c));
+        return c < ushort.MaxValue && c is '_' or >= 'a' and <= 'z' or >= 'A' and <= 'Z';
     }
 }

+ 9 - 0
src/Lua/CodeAnalysis/Compilation/TempBlock.cs

@@ -0,0 +1,9 @@
+namespace Lua.CodeAnalysis.Compilation;
+
+internal readonly ref struct TempBlock(LuaState state)
+{
+    public void Dispose()
+    {
+        state.CallCount--;
+    }
+}