From de17102c03ec8f54b03a5b1fd8e79513d5a6ad8d Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Wed, 27 May 2026 00:17:51 +0400 Subject: [PATCH] =?UTF-8?q?fix=20#1685:=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE=D0=BA?= =?UTF-8?q?=20=D0=B2=20=D1=82=D0=B5=D0=BB=D0=B5=20=D0=BC=D0=BE=D0=B4=D1=83?= =?UTF-8?q?=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SyntaxAnalysis/DefaultBslParser.cs | 12 +++++++++--- .../SyntaxAnalysis/LocalizedErrors.cs | 4 ++++ .../OneScript.Language.Tests/ParserTests.cs | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs index ad0839376..94c19feed 100644 --- a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs +++ b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs @@ -516,7 +516,7 @@ private bool BuildDefaultParameterValue(NonTerminalNode param, NodeKind nodeKind private void BuildModuleBody() { - if (!_lexer.Iterator.MoveToContent()) + if (_lastExtractedLexem.Token == Token.EndOfText) return; var moduleBody = new NonTerminalNode(NodeKind.ModuleBody, _lastExtractedLexem); @@ -746,7 +746,11 @@ private void BuildComplexStructureStatement() } else { - AddError(LocalizedErrors.TokenExpected(_tokenStack.Peek())); + var expected = _tokenStack.Peek(); + if (expected.Length == 1 && expected[0] == Token.EndOfText) + AddError(LocalizedErrors.UnexpectedKeyword(_lastExtractedLexem.Token)); + else + AddError(LocalizedErrors.TokenExpected(expected)); } break; } @@ -1552,7 +1556,9 @@ private void SkipToNextStatement(Token[] additionalStops = null) private void AddError(CodeError err, bool doFastForward = true) { err.Position = _lexer.GetErrorPosition(); - err.Position.ColumnNumber -= _lastExtractedLexem.Content?.Length ?? 1; + var adjustColumn = _lastExtractedLexem.Content?.Length ?? 1; + if (err.Position.ColumnNumber >= adjustColumn) + err.Position.ColumnNumber -= adjustColumn; ErrorSink.AddError(err); if (doFastForward) diff --git a/src/OneScript.Language/SyntaxAnalysis/LocalizedErrors.cs b/src/OneScript.Language/SyntaxAnalysis/LocalizedErrors.cs index a6e23d267..864bd4ede 100644 --- a/src/OneScript.Language/SyntaxAnalysis/LocalizedErrors.cs +++ b/src/OneScript.Language/SyntaxAnalysis/LocalizedErrors.cs @@ -80,6 +80,10 @@ public static CodeError AwaitMustBeInAsyncMethod() => Create( public static CodeError NumberExpected() => Create("Ожидается числовая константа", "Numeric constant expected"); + public static CodeError UnexpectedKeyword(Token unexpected) => Create( + $"Неожиданное ключевое слово: {LanguageDef.GetTokenName(unexpected)}", + $"Unexpected keyword: {LanguageDef.GetTokenAlias(unexpected)}"); + public static CodeError UnexpectedEof() => Create("Неожиданный конец модуля", "Unexpected end of text"); diff --git a/src/Tests/OneScript.Language.Tests/ParserTests.cs b/src/Tests/OneScript.Language.Tests/ParserTests.cs index 92d498423..20381b820 100644 --- a/src/Tests/OneScript.Language.Tests/ParserTests.cs +++ b/src/Tests/OneScript.Language.Tests/ParserTests.cs @@ -1609,8 +1609,24 @@ public void Async_And_Await_Are_Ordinary_Identifiers_In_NonAsync_Scope() var asyncNode = validator.NextChild().Is(NodeKind.Assignment) .NextChildIs(NodeKind.Identifier) .ChildItself().Value.Should().Be("Асинх"); + } + + [Fact] + public void Throws_When_Error_In_Module_Body() + { + var code = @"Function F() + Return 0 + EndFunction + EndFunction"; + + var parser = PrepareParser(code); + parser.ParseStatefulModule(); + + parser.Errors.Should().NotBeEmpty("Expression syntax error"); + parser.Errors.First().ErrorId.Should().Be("UnexpectedKeyword"); } + private static void CatchParsingError(string code) { var parser = PrepareParser(code);