fix: 词法位置报错 (#53)
Co-authored-by: Huaps <1183155719@qq.com> Reviewed-on: PostGuard/Canon#53
This commit is contained in:
parent
d381f56e1d
commit
447a791793
|
@ -1,4 +1,4 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.LexicalParser;
|
namespace Canon.Core.LexicalParser;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ public class Lexer : ILexer
|
||||||
// 记录token
|
// 记录token
|
||||||
private SemanticToken? _semanticToken;
|
private SemanticToken? _semanticToken;
|
||||||
private readonly StringBuilder _tokenBuilder = new();
|
private readonly StringBuilder _tokenBuilder = new();
|
||||||
private readonly List<SemanticToken> _tokens = [];
|
private List<SemanticToken> _tokens = [];
|
||||||
|
|
||||||
// 状态机
|
// 状态机
|
||||||
private StateType _state = StateType.Start;
|
private StateType _state = StateType.Start;
|
||||||
|
@ -25,6 +25,7 @@ public class Lexer : ILexer
|
||||||
public IEnumerable<SemanticToken> Tokenize(ISourceReader reader)
|
public IEnumerable<SemanticToken> Tokenize(ISourceReader reader)
|
||||||
{
|
{
|
||||||
_reader = reader;
|
_reader = reader;
|
||||||
|
_tokens = [];
|
||||||
_state = StateType.Start;
|
_state = StateType.Start;
|
||||||
|
|
||||||
while (_state != StateType.Done)
|
while (_state != StateType.Done)
|
||||||
|
|
|
@ -38,8 +38,8 @@ namespace Canon.Tests.LexicalParserTests
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
//[InlineData("'\\x'", 1, 2, LexemeException.LexemeErrorType.InvalidEscapeSequence)]
|
//[InlineData("'\\x'", 1, 2, LexemeException.LexemeErrorType.InvalidEscapeSequence)]
|
||||||
[InlineData("'This is an unclosed string literal", 1, 36, LexemeErrorType.UnclosedStringLiteral)]
|
[InlineData("'This is an unclosed string literal", 1, 35, LexemeErrorType.UnclosedStringLiteral)]
|
||||||
[InlineData("'This", 1, 6, LexemeErrorType.UnclosedStringLiteral)]
|
[InlineData("'This", 1, 5, LexemeErrorType.UnclosedStringLiteral)]
|
||||||
[InlineData("x @", 1, 3, LexemeErrorType.UnknownCharacterOrString)]
|
[InlineData("x @", 1, 3, LexemeErrorType.UnknownCharacterOrString)]
|
||||||
//[InlineData("\"x\'", 1, 3, LexemeException.LexemeErrorType.UnclosedStringLiteral)]
|
//[InlineData("\"x\'", 1, 3, LexemeException.LexemeErrorType.UnclosedStringLiteral)]
|
||||||
public void TestParseCharacterError(string input, uint expectedLine, uint expectedCharPosition, LexemeErrorType expectedErrorType)
|
public void TestParseCharacterError(string input, uint expectedLine, uint expectedCharPosition, LexemeErrorType expectedErrorType)
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace Canon.Tests.LexicalParserTests
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("program main; var a: integer; begin a := 3#; end.", 1, 43, LexemeErrorType.IllegalNumberFormat)]
|
[InlineData("program main; var a: integer; begin a := 3#; end.", 1, 43, LexemeErrorType.IllegalNumberFormat)]
|
||||||
[InlineData("char c = 'abc;", 1, 15, LexemeErrorType.UnclosedStringLiteral)]
|
[InlineData("char c = 'abc;", 1, 14, LexemeErrorType.UnclosedStringLiteral)]
|
||||||
[InlineData("x := 10 @;", 1, 9, LexemeErrorType.UnknownCharacterOrString)]
|
[InlineData("x := 10 @;", 1, 9, LexemeErrorType.UnknownCharacterOrString)]
|
||||||
[InlineData("identifier_with_special_chars@#",1, 30, LexemeErrorType.UnknownCharacterOrString)]
|
[InlineData("identifier_with_special_chars@#",1, 30, LexemeErrorType.UnknownCharacterOrString)]
|
||||||
public void TestUnknownCharacterError(string pascalProgram, uint expectedLine, uint expectedCharPosition, LexemeErrorType expectedErrorType)
|
public void TestUnknownCharacterError(string pascalProgram, uint expectedLine, uint expectedCharPosition, LexemeErrorType expectedErrorType)
|
||||||
|
|
|
@ -45,8 +45,7 @@ public class LexicalFileTests(ITestOutputHelper testOutputHelper)
|
||||||
SemanticTokenType.Delimiter,
|
SemanticTokenType.Delimiter,
|
||||||
SemanticTokenType.Delimiter,
|
SemanticTokenType.Delimiter,
|
||||||
SemanticTokenType.Keyword,
|
SemanticTokenType.Keyword,
|
||||||
SemanticTokenType.Delimiter,
|
SemanticTokenType.Delimiter
|
||||||
SemanticTokenType.End
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,42 +139,11 @@ public class LexicalFileTests(ITestOutputHelper testOutputHelper)
|
||||||
SemanticTokenType.Delimiter,
|
SemanticTokenType.Delimiter,
|
||||||
SemanticTokenType.Delimiter,
|
SemanticTokenType.Delimiter,
|
||||||
SemanticTokenType.Keyword,
|
SemanticTokenType.Keyword,
|
||||||
SemanticTokenType.Delimiter,
|
|
||||||
SemanticTokenType.End
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void ReuseTest()
|
|
||||||
{
|
|
||||||
const string program1 = """
|
|
||||||
program main;
|
|
||||||
begin
|
|
||||||
end.
|
|
||||||
""";
|
|
||||||
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program1));
|
|
||||||
|
|
||||||
ValidateSemanticTokens(tokens, [
|
|
||||||
SemanticTokenType.Keyword,
|
|
||||||
SemanticTokenType.Identifier,
|
|
||||||
SemanticTokenType.Delimiter,
|
|
||||||
SemanticTokenType.Keyword,
|
|
||||||
SemanticTokenType.Keyword,
|
|
||||||
SemanticTokenType.Delimiter
|
|
||||||
]);
|
|
||||||
|
|
||||||
const string test = "program begin end.";
|
|
||||||
|
|
||||||
tokens = _lexer.Tokenize(new StringSourceReader(test));
|
|
||||||
|
|
||||||
ValidateSemanticTokens(tokens, [
|
|
||||||
SemanticTokenType.Keyword,
|
|
||||||
SemanticTokenType.Keyword,
|
|
||||||
SemanticTokenType.Keyword,
|
|
||||||
SemanticTokenType.Delimiter
|
SemanticTokenType.Delimiter
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void UnclosedCommentFirst()
|
public void UnclosedCommentFirst()
|
||||||
{
|
{
|
||||||
|
@ -193,7 +161,7 @@ public class LexicalFileTests(ITestOutputHelper testOutputHelper)
|
||||||
testOutputHelper.WriteLine(ex.ToString());
|
testOutputHelper.WriteLine(ex.ToString());
|
||||||
Assert.Equal(LexemeErrorType.UnclosedComment, ex.ErrorType);
|
Assert.Equal(LexemeErrorType.UnclosedComment, ex.ErrorType);
|
||||||
Assert.Equal((uint)7, ex.Line);
|
Assert.Equal((uint)7, ex.Line);
|
||||||
Assert.Equal((uint)5, ex.CharPosition);
|
Assert.Equal((uint)4, ex.CharPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -209,7 +177,7 @@ public class LexicalFileTests(ITestOutputHelper testOutputHelper)
|
||||||
testOutputHelper.WriteLine(ex.ToString());
|
testOutputHelper.WriteLine(ex.ToString());
|
||||||
Assert.Equal(LexemeErrorType.UnclosedComment, ex.ErrorType);
|
Assert.Equal(LexemeErrorType.UnclosedComment, ex.ErrorType);
|
||||||
Assert.Equal((uint)4, ex.Line);
|
Assert.Equal((uint)4, ex.Line);
|
||||||
Assert.Equal((uint)26, ex.CharPosition);
|
Assert.Equal((uint)25, ex.CharPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -313,7 +281,11 @@ public class LexicalFileTests(ITestOutputHelper testOutputHelper)
|
||||||
private static void ValidateSemanticTokens(IEnumerable<SemanticToken> actualTokens,
|
private static void ValidateSemanticTokens(IEnumerable<SemanticToken> actualTokens,
|
||||||
IEnumerable<SemanticTokenType> expectedTypes)
|
IEnumerable<SemanticTokenType> expectedTypes)
|
||||||
{
|
{
|
||||||
foreach ((SemanticTokenType type, SemanticToken token) in expectedTypes.Zip(actualTokens))
|
List<SemanticTokenType> types = [..expectedTypes, SemanticTokenType.End];
|
||||||
|
List<SemanticToken> tokens = actualTokens.ToList();
|
||||||
|
|
||||||
|
Assert.Equal(types.Count, tokens.Count);
|
||||||
|
foreach ((SemanticTokenType type, SemanticToken token) in types.Zip(tokens))
|
||||||
{
|
{
|
||||||
Assert.Equal(type, token.TokenType);
|
Assert.Equal(type, token.TokenType);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user