Browse Source

Update: support long string literal

AnnulusGames 1 year ago
parent
commit
62082b242c
1 changed files with 88 additions and 11 deletions
  1. 88 11
      src/Lua/CodeAnalysis/Syntax/Lexer.cs

+ 88 - 11
src/Lua/CodeAnalysis/Syntax/Lexer.cs

@@ -95,9 +95,6 @@ public ref struct Lexer
             case '}':
                 current = SyntaxToken.RCurly(position);
                 return true;
-            case '[':
-                current = SyntaxToken.LSquare(position);
-                return true;
             case ']':
                 current = SyntaxToken.RSquare(position);
                 return true;
@@ -294,35 +291,115 @@ public ref struct Lexer
             return true;
         }
 
-        // string
+        // short string literal
         if (c1 is '"' or '\'')
         {
             var quote = c1;
             var stringStartOffset = offset;
 
+            var isTerminated = false;
             while (span.Length > offset)
             {
                 var c = span[offset];
-                if (c == quote) break;
+                if (c == quote)
+                {
+                    isTerminated = true;
+                    break;
+                }
 
                 if (c is '\n' or '\r')
                 {
-                    throw new LuaParseException(ChunkName, this.position, "error: Unterminated string");
+                    break;
                 }
 
-                // if (c is '\\')
-                // {
-
-                // }
-
                 Advance(1);
             }
 
+            if (!isTerminated)
+            {
+                throw new LuaParseException(ChunkName, this.position, "error: Unterminated string");
+            }
+
             current = SyntaxToken.String(Source[stringStartOffset..offset], position);
             Advance(1);
             return true;
         }
 
+        // long string literal
+        if (c1 is '[')
+        {
+            if (c2 is '[' or '=')
+            {
+                var c = c2;
+                var level = 0;
+                while (c is '=')
+                {
+                    level++;
+                    Advance(1);
+                    c = span[offset];
+                }
+
+                Advance(1);
+                var stringStartOffset = offset;
+                var stringEndOffset = 0;
+
+                var isTerminated = false;
+                while (span.Length > offset + level + 1)
+                {
+                    var current = span[offset];
+
+                    // skip first newline
+                    if (offset == stringStartOffset)
+                    {
+                        if (current == '\r')
+                        {
+                            stringStartOffset += 2;
+                            Advance(span[offset + 1] == '\n' ? 2 : 1);
+                            continue;
+                        }
+                        else if (current == '\n')
+                        {
+                            stringStartOffset++;
+                            Advance(1);
+                            continue;
+                        }
+                    }
+
+                    if (current is ']')
+                    {
+                        stringEndOffset = offset;
+
+                        for (int i = 1; i <= level; i++)
+                        {
+                            if (span[offset + i] is not '=') goto CONTINUE;
+                        }
+
+                        if (span[offset + level + 1] is not ']') goto CONTINUE;
+
+                        Advance(level + 2);
+                        isTerminated = true;
+                        break;
+                    }
+
+                CONTINUE:
+                    Advance(1);
+                }
+
+                if (!isTerminated)
+                {
+                    throw new LuaParseException(ChunkName, this.position, "error: Unterminated string");
+                }
+
+                current = SyntaxToken.String(Source[stringStartOffset..stringEndOffset], position);
+                return true;
+            }
+            else
+            {
+                current = SyntaxToken.LSquare(position);
+                return true;
+            }
+        }
+
         // identifier
         if (IsIdentifier(c1))
         {