From 6a842ede5704809b183e3415ee1c68cbbd11b58d Mon Sep 17 00:00:00 2001 From: Akeit0 <90429982+Akeit0@users.noreply.github.com> Date: Fri, 7 Mar 2025 21:56:11 +0900 Subject: [PATCH 1/2] Fix: backslash with real newline in short literal doesn't work --- src/Lua/CodeAnalysis/Syntax/Lexer.cs | 16 +++++++++++++++- src/Lua/Internal/StringHelper.cs | 10 +++------- tests/Lua.Tests/ParserTests.cs | 19 +++++++++++++++++++ 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/Lua/CodeAnalysis/Syntax/Lexer.cs b/src/Lua/CodeAnalysis/Syntax/Lexer.cs index 5ecbe7e7..c32a64ae 100644 --- a/src/Lua/CodeAnalysis/Syntax/Lexer.cs +++ b/src/Lua/CodeAnalysis/Syntax/Lexer.cs @@ -311,6 +311,7 @@ public bool MoveNext() var quote = c1; var stringStartOffset = offset; var isTerminated = false; + var escape = false; while (span.Length > offset) { @@ -318,12 +319,20 @@ public bool MoveNext() if (c is '\n' or '\r') { + if (escape) + { + escape = false; + Advance(1); + continue; + } + break; } if (c is '\\') { Advance(1); + escape = true; if (span.Length <= offset) break; } else if (c == quote) @@ -331,7 +340,12 @@ public bool MoveNext() isTerminated = true; break; } + else + { + escape = false; + } + Advance(1); } @@ -534,4 +548,4 @@ static bool IsIdentifier(char c) ('a' <= c && c <= 'z') || StringHelper.IsNumber(c); } -} +} \ No newline at end of file diff --git a/src/Lua/Internal/StringHelper.cs b/src/Lua/Internal/StringHelper.cs index 0342d289..427feb99 100644 --- a/src/Lua/Internal/StringHelper.cs +++ b/src/Lua/Internal/StringHelper.cs @@ -38,11 +38,6 @@ public static bool TryFromStringLiteral(ReadOnlySpan literal, [NotNullWhen break; case '\r': builder.Append('\r'); - // check CRLF - if (i + 1 < literal.Length && literal[i + 1] is '\n') - { - i++; - } break; case 'a': builder.Append('\a'); @@ -306,6 +301,7 @@ public static Regex ToRegex(ReadOnlySpan pattern) builder.Append(c); break; } + isEscapeSequence = false; } } @@ -358,7 +354,7 @@ public static bool IsNumber(char c) public static bool IsDigit(char c) { return IsNumber(c) || - ('a' <= c && c <= 'f') || - ('A' <= c && c <= 'F'); + ('a' <= c && c <= 'f') || + ('A' <= c && c <= 'F'); } } \ No newline at end of file diff --git a/tests/Lua.Tests/ParserTests.cs b/tests/Lua.Tests/ParserTests.cs index 1dcda7eb..45a683d2 100644 --- a/tests/Lua.Tests/ParserTests.cs +++ b/tests/Lua.Tests/ParserTests.cs @@ -25,5 +25,24 @@ elseif true then Assert.That(actual, Is.TypeOf()); Assert.That(actual.ToString(), Is.EqualTo(expected.ToString())); } + + [Test] + public void Test_MultiLine_ShortString() + { + var source = +""" +print "Hello,\ +World!" +"""; + var actual = LuaSyntaxTree.Parse(source).Nodes[0]; + Assert.That(actual, Is.TypeOf()); + var literal =((StringLiteralNode)((CallFunctionStatementNode)actual).Expression.ArgumentNodes[0]).Text.ToString(); + Assert.That(literal, Is.EqualTo( + """ + Hello,\ + World! + """ + )); + } } } \ No newline at end of file From cffddbe8424115f7c7b9c5e99829d3ae3222b332 Mon Sep 17 00:00:00 2001 From: Akeit0 <90429982+Akeit0@users.noreply.github.com> Date: Sat, 15 Mar 2025 09:23:28 +0900 Subject: [PATCH 2/2] Fix: new line codes in short literal --- src/Lua/CodeAnalysis/Syntax/Lexer.cs | 26 +++++++++----------------- src/Lua/Internal/StringHelper.cs | 7 ++++++- tests/Lua.Tests/ParserTests.cs | 19 ------------------- tests/Lua.Tests/StringTests.cs | 17 +++++++++++++++++ 4 files changed, 32 insertions(+), 37 deletions(-) create mode 100644 tests/Lua.Tests/StringTests.cs diff --git a/src/Lua/CodeAnalysis/Syntax/Lexer.cs b/src/Lua/CodeAnalysis/Syntax/Lexer.cs index c32a64ae..6ac4a4aa 100644 --- a/src/Lua/CodeAnalysis/Syntax/Lexer.cs +++ b/src/Lua/CodeAnalysis/Syntax/Lexer.cs @@ -311,7 +311,6 @@ public bool MoveNext() var quote = c1; var stringStartOffset = offset; var isTerminated = false; - var escape = false; while (span.Length > offset) { @@ -319,33 +318,26 @@ public bool MoveNext() if (c is '\n' or '\r') { - if (escape) - { - escape = false; - Advance(1); - continue; - } - break; } if (c is '\\') { Advance(1); - escape = true; + if (span.Length <= offset) break; + if (span[offset] == '\r') + { + if (span.Length<=offset +1) continue; + if (span[offset+1] == '\n')Advance(1); + } } else if (c == quote) { isTerminated = true; break; } - else - { - escape = false; - } - Advance(1); } @@ -544,8 +536,8 @@ void ReadNumber(ref ReadOnlySpan span, ref int offset, out int readCount) static bool IsIdentifier(char c) { return c == '_' || - ('A' <= c && c <= 'Z') || - ('a' <= c && c <= 'z') || - StringHelper.IsNumber(c); + ('A' <= c && c <= 'Z') || + ('a' <= c && c <= 'z') || + StringHelper.IsNumber(c); } } \ No newline at end of file diff --git a/src/Lua/Internal/StringHelper.cs b/src/Lua/Internal/StringHelper.cs index 427feb99..993dfc44 100644 --- a/src/Lua/Internal/StringHelper.cs +++ b/src/Lua/Internal/StringHelper.cs @@ -37,7 +37,12 @@ public static bool TryFromStringLiteral(ReadOnlySpan literal, [NotNullWhen builder.Append('\n'); break; case '\r': - builder.Append('\r'); + builder.Append('\n'); + // check CRLF + if (i + 1 < literal.Length && literal[i + 1] is '\n') + { + i++; + } break; case 'a': builder.Append('\a'); diff --git a/tests/Lua.Tests/ParserTests.cs b/tests/Lua.Tests/ParserTests.cs index 45a683d2..1dcda7eb 100644 --- a/tests/Lua.Tests/ParserTests.cs +++ b/tests/Lua.Tests/ParserTests.cs @@ -25,24 +25,5 @@ elseif true then Assert.That(actual, Is.TypeOf()); Assert.That(actual.ToString(), Is.EqualTo(expected.ToString())); } - - [Test] - public void Test_MultiLine_ShortString() - { - var source = -""" -print "Hello,\ -World!" -"""; - var actual = LuaSyntaxTree.Parse(source).Nodes[0]; - Assert.That(actual, Is.TypeOf()); - var literal =((StringLiteralNode)((CallFunctionStatementNode)actual).Expression.ArgumentNodes[0]).Text.ToString(); - Assert.That(literal, Is.EqualTo( - """ - Hello,\ - World! - """ - )); - } } } \ No newline at end of file diff --git a/tests/Lua.Tests/StringTests.cs b/tests/Lua.Tests/StringTests.cs new file mode 100644 index 00000000..921205d0 --- /dev/null +++ b/tests/Lua.Tests/StringTests.cs @@ -0,0 +1,17 @@ +using Lua.CodeAnalysis.Syntax; +using Lua.CodeAnalysis.Syntax.Nodes; + +namespace Lua.Tests; + +public class StringTests +{ + [TestCase("\r")] + [TestCase("\n")] + [TestCase("\r\n")] + public async Task Test_ShortString_RealNewLine(string newLine) + { + var result = await LuaState.Create().DoStringAsync($"return \"\\{newLine}\""); + Assert.That(result, Has.Length.EqualTo(1)); + Assert.That(result[0], Is.EqualTo(new LuaValue("\n"))); + } +} \ No newline at end of file