From b16a0dcd37b3ad4b0d927d35d20bb95bb7edec9c Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Fri, 23 Jan 2026 22:37:29 +0400 Subject: [PATCH 01/10] =?UTF-8?q?=D0=BF=D1=80=D0=B8=D0=BE=D1=80=D0=B8?= =?UTF-8?q?=D1=82=D0=B5=D1=82=20=D0=BE=D0=BF=D0=B5=D1=80=D0=B0=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20?= =?UTF-8?q?=D1=80=D0=B5=D0=BA=D1=83=D1=80=D1=81=D0=B8=D0=B2=D0=BD=D0=BE?= =?UTF-8?q?=D0=B3=D0=BE=20=D1=81=D0=BF=D1=83=D1=81=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/OneScript.Language/LanguageDef.cs | 26 ++- .../SyntaxAnalysis/DefaultBslParser.cs | 197 ++++++------------ 2 files changed, 90 insertions(+), 133 deletions(-) diff --git a/src/OneScript.Language/LanguageDef.cs b/src/OneScript.Language/LanguageDef.cs index 954101361..b32456fbd 100644 --- a/src/OneScript.Language/LanguageDef.cs +++ b/src/OneScript.Language/LanguageDef.cs @@ -282,7 +282,31 @@ public static Token GetToken(string tokText) public static int GetPriority(Token op) { return _priority[op]; - } + } + + public static int GetBinaryPriority(Token op) + { + return IsBinaryOperator(op) ? _priority[op] : -1; + } + + public static int GetUnaryPriority(Token op) + { + return op switch + { + Token.OpenPar => MAX_OPERATION_PRIORITY + 1, + + Token.Not => _priority[op], + Token.UnaryMinus => _priority[op], + Token.UnaryPlus => _priority[op], + + Token.Minus => _priority[Token.UnaryMinus], + Token.Plus => _priority[Token.UnaryPlus], + + _ => MAX_OPERATION_PRIORITY + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsBuiltInFunction(Token token) diff --git a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs index 1d1a543c9..70e0bf785 100644 --- a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs +++ b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs @@ -389,8 +389,8 @@ private void BuildMethodBody() finally { PopContext(); - } - + } + CreateChild(CurrentParent, NodeKind.BlockEnd, _lastExtractedLexem); NextLexem(); } @@ -1237,130 +1237,68 @@ private BslSyntaxNode BuildExpression(NonTerminalNode parent, Token stopToken) return default; } - var op = BuildOrExpression(); + var op = BuildExpression(0); parent.AddChild(op); return op; } - - private BslSyntaxNode BuildOrExpression() - { - var firstArg = BuildAndExpression(); - while (_lastExtractedLexem.Token == Token.Or) - { - var operationLexem = _lastExtractedLexem; - NextLexem(); - var secondArg = BuildAndExpression(); - firstArg = MakeBinaryOperationNode(firstArg, secondArg, operationLexem); - } - return firstArg; - } - - private BslSyntaxNode BuildAndExpression() + private BslSyntaxNode BuildExpression(int prio) { - var firstArg = BuildNotExpression(); - while (_lastExtractedLexem.Token == Token.And) + var firstArg = BuildPrimaryExpression(); + while (LanguageDef.GetBinaryPriority(_lastExtractedLexem.Token) > prio) { var operationLexem = _lastExtractedLexem; NextLexem(); - var secondArg = BuildNotExpression(); - firstArg = MakeBinaryOperationNode(firstArg, secondArg, operationLexem); - } + var secondArg = BuildExpression(LanguageDef.GetBinaryPriority(operationLexem.Token)); - return firstArg; - } - - private BslSyntaxNode BuildNotExpression() - { - if (_lastExtractedLexem.Token == Token.Not) - { - var operation = _lastExtractedLexem; - NextLexem(); - var op = new UnaryOperationNode(operation); - var argument = BuildLogicalComparison(); - op.AddChild(argument); - return op; - } - - return BuildLogicalComparison(); - } - - private BslSyntaxNode BuildLogicalComparison() - { - var firstArg = BuildAdditionExpression(); - while (_lastExtractedLexem.Token == Token.Equal || - _lastExtractedLexem.Token == Token.MoreThan || - _lastExtractedLexem.Token == Token.LessThan || - _lastExtractedLexem.Token == Token.MoreOrEqual || - _lastExtractedLexem.Token == Token.LessOrEqual || - _lastExtractedLexem.Token == Token.NotEqual) - { - var operationLexem = _lastExtractedLexem; - NextLexem(); - var secondArg = BuildAdditionExpression(); firstArg = MakeBinaryOperationNode(firstArg, secondArg, operationLexem); } return firstArg; - } - - private BslSyntaxNode BuildAdditionExpression() + } + + private BslSyntaxNode BuildPrimaryExpression() { - var firstArg = BuildMultiplyExpression(); - while (_lastExtractedLexem.Token == Token.Plus || - _lastExtractedLexem.Token == Token.Minus) - { - var operationLexem = _lastExtractedLexem; - NextLexem(); - var secondArg = BuildMultiplyExpression(); - firstArg = MakeBinaryOperationNode(firstArg, secondArg, operationLexem); - } - - return firstArg; - } - - private BslSyntaxNode BuildMultiplyExpression() - { - var firstArg = BuildUnaryMathExpression(); - while (_lastExtractedLexem.Token == Token.Multiply || - _lastExtractedLexem.Token == Token.Division || - _lastExtractedLexem.Token == Token.Modulo) - { - var operationLexem = _lastExtractedLexem; - NextLexem(); - var secondArg = BuildUnaryMathExpression(); - firstArg = MakeBinaryOperationNode(firstArg, secondArg, operationLexem); - } - - return firstArg; - } - - private BslSyntaxNode BuildUnaryMathExpression() - { - if (_lastExtractedLexem.Token == Token.Plus) - _lastExtractedLexem.Token = Token.UnaryPlus; - else if (_lastExtractedLexem.Token == Token.Minus) - _lastExtractedLexem.Token = Token.UnaryMinus; - else - return BuildParenthesis(); - - // Можно оптимизировать численный литерал до константы - var operation = _lastExtractedLexem; - NextLexem(); - if (_lastExtractedLexem.Type == LexemType.NumberLiteral) - { - if (operation.Token == Token.UnaryMinus) - _lastExtractedLexem.Content = '-' + _lastExtractedLexem.Content; - - return TerminalNode(); - } - - var op = new UnaryOperationNode(operation); - var argument = BuildParenthesis(); - op.AddChild(argument); - return op; - } - + if (_lastExtractedLexem.Token == Token.OpenPar) + { + return BuildParenthesis(); + } + + var operation = _lastExtractedLexem; + var prio = LanguageDef.GetUnaryPriority(operation.Token); + + if (prio == LanguageDef.MAX_OPERATION_PRIORITY) + { + return TerminalNode(); + } + + NextLexem(); + + if (operation.Token == Token.Plus) + operation.Token = Token.UnaryPlus; + else if (operation.Token == Token.Minus) + { + operation.Token = Token.UnaryMinus; + if (_lastExtractedLexem.Type == LexemType.NumberLiteral) //TODO:move it to lexer + { + _lastExtractedLexem.Content = '-' + _lastExtractedLexem.Content; + return TerminalNode(); + } + } + + if (LanguageDef.GetUnaryPriority(_lastExtractedLexem.Token) <= prio) + { + AddError(LocalizedErrors.ExpressionSyntax()); + return default; + } + + var arg = BuildExpression(prio); + var op = new UnaryOperationNode(operation); + op.AddChild(arg); + return op; + } + + private BslSyntaxNode BuildExpressionUpTo(NonTerminalNode parent, Token stopToken) { var node = BuildExpression(parent, stopToken); @@ -1392,36 +1330,31 @@ private void BuildOptionalExpression(NonTerminalNode parent, Token stopToken) return; } - var op = BuildOrExpression(); + var op = BuildExpression(0); parent.AddChild(op); } #region Operators - private static BslSyntaxNode MakeBinaryOperationNode(BslSyntaxNode firstArg, BslSyntaxNode secondArg, in Lexem lexem) + private static BinaryOperationNode MakeBinaryOperationNode(BslSyntaxNode firstArg, BslSyntaxNode secondArg, in Lexem lexem) { var node = new BinaryOperationNode(lexem); node.AddChild(firstArg); node.AddChild(secondArg); return node; - } - + } + private BslSyntaxNode BuildParenthesis() - { - if (_lastExtractedLexem.Token == Token.OpenPar) - { - NextLexem(); - var expr = BuildOrExpression(); - if (_lastExtractedLexem.Token != Token.ClosePar) - { - AddError(LocalizedErrors.TokenExpected(Token.ClosePar)); - } - NextLexem(); - - return BuildDereference(expr); - } - - return TerminalNode(); + { + NextLexem(); + var expr = BuildExpression(0); + if (_lastExtractedLexem.Token != Token.ClosePar) + { + AddError(LocalizedErrors.TokenExpected(Token.ClosePar)); + } + NextLexem(); + + return BuildDereference(expr); } #endregion @@ -1676,7 +1609,7 @@ private Token[] PopStructureToken() return tok; } - private BslSyntaxNode CreateChild(NonTerminalNode parent, NodeKind kind, in Lexem lex) + private static BslSyntaxNode CreateChild(NonTerminalNode parent, NodeKind kind, in Lexem lex) { var child = NodeBuilder.CreateNode(kind, lex); parent.AddChild(child); From c3ee3e3cbb921d7097ce3d889d2eba4eb817e756 Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Fri, 23 Jan 2026 23:22:39 +0400 Subject: [PATCH 02/10] =?UTF-8?q?=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BE=D0=BF=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B9?= =?UTF-8?q?=20=D0=B8=20=D1=82=D0=B5=D1=80=D0=BC=D0=B8=D0=BD=D0=B0=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=BA=D0=BE=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AstNodes/BinaryOperationNode.cs | 8 +++++++ .../AstNodes/UnaryOperationNode.cs | 8 ++++++- .../SyntaxAnalysis/DefaultBslParser.cs | 24 +++++-------------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/OneScript.Language/SyntaxAnalysis/AstNodes/BinaryOperationNode.cs b/src/OneScript.Language/SyntaxAnalysis/AstNodes/BinaryOperationNode.cs index f4cebbfbf..2582f31f0 100644 --- a/src/OneScript.Language/SyntaxAnalysis/AstNodes/BinaryOperationNode.cs +++ b/src/OneScript.Language/SyntaxAnalysis/AstNodes/BinaryOperationNode.cs @@ -17,5 +17,13 @@ public BinaryOperationNode(Lexem operation) : base(NodeKind.BinaryOperation, ope { Operation = operation.Token; } + + public BinaryOperationNode(BslSyntaxNode firstArg, BslSyntaxNode secondArg, Lexem operation) + : base(NodeKind.BinaryOperation, operation) + { + Operation = operation.Token; + AddChild(firstArg); + AddChild(secondArg); + } } } \ No newline at end of file diff --git a/src/OneScript.Language/SyntaxAnalysis/AstNodes/UnaryOperationNode.cs b/src/OneScript.Language/SyntaxAnalysis/AstNodes/UnaryOperationNode.cs index 05e9b80cd..d55774cf1 100644 --- a/src/OneScript.Language/SyntaxAnalysis/AstNodes/UnaryOperationNode.cs +++ b/src/OneScript.Language/SyntaxAnalysis/AstNodes/UnaryOperationNode.cs @@ -16,6 +16,12 @@ public class UnaryOperationNode : NonTerminalNode public UnaryOperationNode(Lexem operation) : base(NodeKind.UnaryOperation, operation) { Operation = operation.Token; - } + } + + public UnaryOperationNode(BslSyntaxNode arg, Lexem operation) : base(NodeKind.UnaryOperation, operation) + { + Operation = operation.Token; + AddChild(arg); + } } } \ No newline at end of file diff --git a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs index 70e0bf785..4b776bba6 100644 --- a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs +++ b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs @@ -757,9 +757,7 @@ private BslSyntaxNode BuildExpressionAwaitOperator(Lexem lexem) if (argument != default) { CheckAsyncMethod(); - var awaitOperator = new UnaryOperationNode(lexem); - awaitOperator.AddChild(argument); - return awaitOperator; + return new UnaryOperationNode(argument, lexem); } else if (!_isInAsyncMethod) { @@ -1140,7 +1138,7 @@ private BslSyntaxNode BuildGlobalCall(Lexem identifier) private BslSyntaxNode CallOrVariable(Lexem identifier) { - var target = NodeBuilder.CreateNode(NodeKind.Identifier, identifier); + BslSyntaxNode target = new TerminalNode(NodeKind.Identifier, identifier); if (_lastExtractedLexem.Token != Token.OpenPar) { _lastDereferenceIsWritable = true; // одиночный идентификатор @@ -1251,7 +1249,7 @@ private BslSyntaxNode BuildExpression(int prio) NextLexem(); var secondArg = BuildExpression(LanguageDef.GetBinaryPriority(operationLexem.Token)); - firstArg = MakeBinaryOperationNode(firstArg, secondArg, operationLexem); + firstArg = new BinaryOperationNode(firstArg, secondArg, operationLexem); } return firstArg; @@ -1293,9 +1291,7 @@ private BslSyntaxNode BuildPrimaryExpression() } var arg = BuildExpression(prio); - var op = new UnaryOperationNode(operation); - op.AddChild(arg); - return op; + return new UnaryOperationNode(arg, operation); } @@ -1336,14 +1332,6 @@ private void BuildOptionalExpression(NonTerminalNode parent, Token stopToken) #region Operators - private static BinaryOperationNode MakeBinaryOperationNode(BslSyntaxNode firstArg, BslSyntaxNode secondArg, in Lexem lexem) - { - var node = new BinaryOperationNode(lexem); - node.AddChild(firstArg); - node.AddChild(secondArg); - return node; - } - private BslSyntaxNode BuildParenthesis() { NextLexem(); @@ -1375,7 +1363,7 @@ private BslSyntaxNode SelectTerminalNode(in Lexem currentLexem, bool supportAwai BslSyntaxNode node = default; if (LanguageDef.IsLiteral(currentLexem)) { - node = NodeBuilder.CreateNode(NodeKind.Constant, currentLexem); + node = new TerminalNode(NodeKind.Constant, currentLexem); NextLexem(); } else if (LanguageDef.IsUserSymbol(currentLexem)) @@ -1449,7 +1437,7 @@ private BslSyntaxNode BuildDereference(BslSyntaxNode target) NextLexem(); if (_lastExtractedLexem.Token == Token.OpenPar) { - var ident = NodeBuilder.CreateNode(NodeKind.Identifier, identifier); + var ident = new TerminalNode(NodeKind.Identifier, identifier); var call = BuildCall(ident, NodeKind.MethodCall); dotNode.AddChild(call); } From 39da39647f7c8355bc386ea8b1a996f7cfe8a2d5 Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Sat, 24 Jan 2026 13:35:56 +0400 Subject: [PATCH 03/10] =?UTF-8?q?=D1=80=D0=B5=D1=84=D0=B0=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D0=BD=D0=B3:=20=D1=80=D0=B0=D0=BD=D0=BD?= =?UTF-8?q?=D0=B8=D0=B9=20=D0=B2=D1=8B=D1=85=D0=BE=D0=B4,=20=D0=BB=D0=B8?= =?UTF-8?q?=D1=88=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=BD=D1=8B=D0=B5=20=D0=B8=20=D0=B5=D1=89=D0=B5=20=D0=BC?= =?UTF-8?q?=D0=B5=D0=BB=D0=BE=D1=87=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SyntaxAnalysis/DefaultBslParser.cs | 125 ++++++++---------- 1 file changed, 58 insertions(+), 67 deletions(-) diff --git a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs index 4b776bba6..1d76af27b 100644 --- a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs +++ b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs @@ -212,60 +212,55 @@ private void BuildVariableDefinition() NextLexem(); - if (IsUserSymbol(_lastExtractedLexem)) - { - if (_inMethodScope) - { - if (_isStatementsDefined) - { - AddError(LocalizedErrors.LateVarDefinition()); - return; - } - } - else - { - if (_isMethodsDefined) - { - AddError(LocalizedErrors.LateVarDefinition()); - return; - } - } - - var symbolicName = _lastExtractedLexem.Content; - CreateChild(variable, NodeKind.Identifier, _lastExtractedLexem); - - NextLexem(); - if (_lastExtractedLexem.Token == Token.Export) - { - if (_inMethodScope) - { - AddError(LocalizedErrors.ExportedLocalVar(symbolicName)); - break; - } - CreateChild(variable, NodeKind.ExportFlag, _lastExtractedLexem); - NextLexem(); - } - - if (_lastExtractedLexem.Token == Token.Comma) - { - continue; - } - - if (_lastExtractedLexem.Token == Token.Semicolon) - { - NextLexem(); - } - else - { - AddError(LocalizedErrors.SemicolonExpected()); - } - - } - else - { - AddError(LocalizedErrors.IdentifierExpected()); - } - + if (!IsUserSymbol(_lastExtractedLexem)) + { + AddError(LocalizedErrors.IdentifierExpected()); + return; + } + + if (_inMethodScope) + { + if (_isStatementsDefined) + { + AddError(LocalizedErrors.LateVarDefinition()); + return; + } + } + else if (_isMethodsDefined) + { + AddError(LocalizedErrors.LateVarDefinition()); + return; + } + + var symbolicName = _lastExtractedLexem.Content; + CreateChild(variable, NodeKind.Identifier, _lastExtractedLexem); + + NextLexem(); + if (_lastExtractedLexem.Token == Token.Export) + { + if (_inMethodScope) + { + AddError(LocalizedErrors.ExportedLocalVar(symbolicName)); + return; + } + CreateChild(variable, NodeKind.ExportFlag, _lastExtractedLexem); + NextLexem(); + } + + if (_lastExtractedLexem.Token == Token.Comma) + { + continue; + } + + if (_lastExtractedLexem.Token == Token.Semicolon) + { + NextLexem(); + } + else + { + AddError(LocalizedErrors.SemicolonExpected()); + } + break; } } @@ -286,9 +281,7 @@ private void ApplyAnnotations(AnnotatableNode annotatable) private void BuildMethodsSection() { if (_lastExtractedLexem.Type != LexemType.Annotation - && _lastExtractedLexem.Token != Token.Procedure - && _lastExtractedLexem.Token != Token.Function - && _lastExtractedLexem.Token != Token.Async) + && !IsStartOfMethod(_lastExtractedLexem)) { return; } @@ -487,12 +480,11 @@ private bool BuildDefaultParameterValue(NonTerminalNode param, NodeKind nodeKind if (LanguageDef.IsLiteral(_lastExtractedLexem)) { - string literalText = _lastExtractedLexem.Content; if (hasSign) { if (_lastExtractedLexem.Type == LexemType.NumberLiteral && signIsMinus) { - literalText = '-' + literalText; + _lastExtractedLexem.Content = '-' + _lastExtractedLexem.Content; } else if (_lastExtractedLexem.Type == LexemType.StringLiteral || _lastExtractedLexem.Type == LexemType.DateLiteral) @@ -502,7 +494,6 @@ private bool BuildDefaultParameterValue(NonTerminalNode param, NodeKind nodeKind } } - _lastExtractedLexem.Content = literalText; CreateChild(param, nodeKind, _lastExtractedLexem); NextLexem(); } @@ -861,8 +852,7 @@ private void BuildWhileStatement() } private void BuildForStatement() - { - var lexem = _lastExtractedLexem; + { NextLexem(); NodeKind loopKind; @@ -902,8 +892,8 @@ private void BuildCountableForStatement(NonTerminalNode loopNode) AddError(LocalizedErrors.IdentifierExpected()); BuildBatchWithContext(loopNode, Token.EndLoop); return; - } - + } + var counter = _lastExtractedLexem; if (!NextExpected(Token.Equal)) { @@ -1073,7 +1063,8 @@ private void BuildEventHandlerOperation(Token token) if (source == null) return; - if ((source.Kind != NodeKind.DereferenceOperation || !_lastDereferenceIsWritable) && source.Kind != NodeKind.IndexAccess) + if ((source.Kind != NodeKind.DereferenceOperation || !_lastDereferenceIsWritable) + && source.Kind != NodeKind.IndexAccess) { AddError(LocalizedErrors.WrongEventName()); return; @@ -1151,7 +1142,7 @@ private BslSyntaxNode CallOrVariable(Lexem identifier) return BuildDereference(target); } - private BslSyntaxNode BuildCall(BslSyntaxNode target, NodeKind callKind) + private CallNode BuildCall(BslSyntaxNode target, NodeKind callKind) { var callNode = new CallNode(callKind, _lastExtractedLexem); callNode.AddChild(target); @@ -1200,7 +1191,7 @@ private void BuildCallArgument(NonTerminalNode argsList) if (_lastExtractedLexem.Token == Token.Comma) { CreateChild(argsList, NodeKind.CallArgument, _lastExtractedLexem); - + BuildLastDefaultArg(argsList); } else if (_lastExtractedLexem.Token != Token.ClosePar) From 269a431ae74ee5f82fd7410c247e09a76c3d9198 Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Sat, 24 Jan 2026 21:02:48 +0400 Subject: [PATCH 04/10] =?UTF-8?q?=D1=83=D0=BD=D0=B8=D1=84=D0=B8=D0=BA?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D1=83=D0=B7=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SyntaxAnalysis/AstNodes/MethodNode.cs | 2 +- .../AstNodes/MethodSignatureNode.cs | 2 +- .../SyntaxAnalysis/AstNodes/TerminalNode.cs | 4 +-- .../SyntaxAnalysis/DefaultBslParser.cs | 30 +++++++++---------- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/OneScript.Language/SyntaxAnalysis/AstNodes/MethodNode.cs b/src/OneScript.Language/SyntaxAnalysis/AstNodes/MethodNode.cs index 07aa269a3..7cea61576 100644 --- a/src/OneScript.Language/SyntaxAnalysis/AstNodes/MethodNode.cs +++ b/src/OneScript.Language/SyntaxAnalysis/AstNodes/MethodNode.cs @@ -30,7 +30,7 @@ public MethodNode() : base(NodeKind.Method) public IReadOnlyList VariableDefinitions() { if (VariableSection == default) - return new VariableDefinitionNode[0]; + return System.Array.Empty(); return VariableSection.Children .Cast() diff --git a/src/OneScript.Language/SyntaxAnalysis/AstNodes/MethodSignatureNode.cs b/src/OneScript.Language/SyntaxAnalysis/AstNodes/MethodSignatureNode.cs index 1272785b4..cc245493d 100644 --- a/src/OneScript.Language/SyntaxAnalysis/AstNodes/MethodSignatureNode.cs +++ b/src/OneScript.Language/SyntaxAnalysis/AstNodes/MethodSignatureNode.cs @@ -28,7 +28,7 @@ public IEnumerable GetParameters() { var paramList = Children.FirstOrDefault(x => x.Kind == NodeKind.MethodParameters); if (paramList == default) - return new MethodParameterNode[0]; + return System.Array.Empty(); return ((NonTerminalNode) paramList).Children.Cast(); } diff --git a/src/OneScript.Language/SyntaxAnalysis/AstNodes/TerminalNode.cs b/src/OneScript.Language/SyntaxAnalysis/AstNodes/TerminalNode.cs index a57fbe4cc..09fe2996f 100644 --- a/src/OneScript.Language/SyntaxAnalysis/AstNodes/TerminalNode.cs +++ b/src/OneScript.Language/SyntaxAnalysis/AstNodes/TerminalNode.cs @@ -26,8 +26,6 @@ public TerminalNode(NodeKind kind, Lexem lexem) Location = lexem.Location; } - public override IReadOnlyList Children => EmptyChildren; - - private static readonly BslSyntaxNode[] EmptyChildren = new BslSyntaxNode[0]; + public override IReadOnlyList Children => System.Array.Empty(); } } \ No newline at end of file diff --git a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs index 1d76af27b..803ad4e9f 100644 --- a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs +++ b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs @@ -373,8 +373,8 @@ private void BuildMethodVariablesSection() private void BuildMethodBody() { - var body = CreateChild(CurrentParent, NodeKind.CodeBatch, _lastExtractedLexem); - PushContext((NonTerminalNode)body); + var body = _nodeContext.AddChild(new CodeBatchNode(_lastExtractedLexem)); + PushContext(body); try { BuildCodeBatch(_isInFunctionScope ? Token.EndFunction : Token.EndProcedure); @@ -652,7 +652,7 @@ private void BuildCodeBatch(params Token[] endTokens) private void DefineLabel(Lexem label) { var node = new LabelNode(label); - _nodeContext.AddChild(node); + CurrentParent.AddChild(node); NextLexem(); } @@ -732,9 +732,9 @@ private void BuildComplexStructureStatement() private void BuildGlobalCallAwaitOperator() { - Debug.Assert(_lastExtractedLexem.Token == Token.Await); - - _nodeContext.AddChild(TerminalNode()); + Debug.Assert(_lastExtractedLexem.Token == Token.Await); + + CurrentParent.AddChild(TerminalNode()); } @@ -775,7 +775,7 @@ private void BuildGotoOperator() gotoNode.AddChild(new LabelNode(_lastExtractedLexem)); NextLexem(); - _nodeContext.AddChild(gotoNode); + CurrentParent.AddChild(gotoNode); } private void CheckAsyncMethod() @@ -834,8 +834,9 @@ private void BuildWhileStatement() var loopNode = _nodeContext.AddChild(new WhileLoopNode(_lastExtractedLexem)); NextLexem(); BuildExpressionUpTo(loopNode, Token.Loop); - var body = CreateChild(loopNode, NodeKind.CodeBatch, _lastExtractedLexem); - PushContext((NonTerminalNode)body); + var body = loopNode.AddNode(new CodeBatchNode(_lastExtractedLexem)); + + PushContext(body); var loopState = _isInLoopScope; try { @@ -912,8 +913,8 @@ private void BuildCountableForStatement(NonTerminalNode loopNode) var limit = new NonTerminalNode(NodeKind.ForLimit, _lastExtractedLexem); BuildExpressionUpTo(limit, Token.Loop); - loopNode.AddChild(limit); - + loopNode.AddChild(limit); + BuildBatchWithContext(loopNode, Token.EndLoop); CreateChild(loopNode, NodeKind.BlockEnd, _lastExtractedLexem); @@ -1190,7 +1191,7 @@ private void BuildCallArgument(NonTerminalNode argsList) { if (_lastExtractedLexem.Token == Token.Comma) { - CreateChild(argsList, NodeKind.CallArgument, _lastExtractedLexem); + argsList.AddChild(new NonTerminalNode(NodeKind.CallArgument, _lastExtractedLexem)); BuildLastDefaultArg(argsList); } @@ -1210,7 +1211,7 @@ private void BuildLastDefaultArg(NonTerminalNode argsList) NextLexem(); if (_lastExtractedLexem.Token == Token.ClosePar) { - CreateChild(argsList, NodeKind.CallArgument, _lastExtractedLexem); + argsList.AddChild(new NonTerminalNode(NodeKind.CallArgument, _lastExtractedLexem)); } } @@ -1588,11 +1589,10 @@ private Token[] PopStructureToken() return tok; } - private static BslSyntaxNode CreateChild(NonTerminalNode parent, NodeKind kind, in Lexem lex) + private static void CreateChild(NonTerminalNode parent, NodeKind kind, in Lexem lex) { var child = NodeBuilder.CreateNode(kind, lex); parent.AddChild(child); - return child; } private bool TryParseNode(Action action) From 2f378fec3a9b13026b3c026826e84652db8013a5 Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Sun, 25 Jan 2026 00:14:35 +0400 Subject: [PATCH 05/10] =?UTF-8?q?=D0=BF=D1=83=D1=81=D1=82=D1=8B=D0=B5=20?= =?UTF-8?q?=D0=BC=D0=B0=D1=81=D1=81=D0=B8=D0=B2=D1=8B=20=D0=B8=20=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D0=B8=D0=B9=20=D0=B2=D1=8B=D1=85=D0=BE=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SyntaxAnalysis/AstNodes/ConditionNode.cs | 2 +- .../SyntaxAnalysis/AstNodes/LineMarkerNode.cs | 2 +- .../SyntaxAnalysis/DefaultBslParser.cs | 79 ++++++++----------- 3 files changed, 36 insertions(+), 47 deletions(-) diff --git a/src/OneScript.Language/SyntaxAnalysis/AstNodes/ConditionNode.cs b/src/OneScript.Language/SyntaxAnalysis/AstNodes/ConditionNode.cs index 7e44d8112..86a41d118 100644 --- a/src/OneScript.Language/SyntaxAnalysis/AstNodes/ConditionNode.cs +++ b/src/OneScript.Language/SyntaxAnalysis/AstNodes/ConditionNode.cs @@ -26,7 +26,7 @@ public ConditionNode(Lexem startLexem) : base(NodeKind.Condition, startLexem) public IEnumerable GetAlternatives() { if(_alternativesStart == 0) - return new BslSyntaxNode[0]; + return System.Array.Empty(); return Children .Skip(_alternativesStart) diff --git a/src/OneScript.Language/SyntaxAnalysis/AstNodes/LineMarkerNode.cs b/src/OneScript.Language/SyntaxAnalysis/AstNodes/LineMarkerNode.cs index d67c85d4e..3399bc17f 100644 --- a/src/OneScript.Language/SyntaxAnalysis/AstNodes/LineMarkerNode.cs +++ b/src/OneScript.Language/SyntaxAnalysis/AstNodes/LineMarkerNode.cs @@ -18,6 +18,6 @@ public LineMarkerNode(CodeRange location, NodeKind kind) Kind = kind; } - public override IReadOnlyList Children => new BslSyntaxNode[0]; + public override IReadOnlyList Children => System.Array.Empty(); } } \ No newline at end of file diff --git a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs index 803ad4e9f..6191f470f 100644 --- a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs +++ b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs @@ -49,20 +49,20 @@ public DefaultBslParser( private IErrorSink ErrorSink { get; } - public IEnumerable Errors => ErrorSink.Errors ?? new CodeError[0]; + public IEnumerable Errors => ErrorSink.Errors ?? Array.Empty(); public BslSyntaxNode ParseStatefulModule() { ModuleNode node; _preprocessorHandlers.OnModuleEnter(); - NextLexem(); - + NextLexem(); + + node = new ModuleNode(_lexer.Iterator.Source, _lastExtractedLexem); + PushContext(node); try { - node = new ModuleNode(_lexer.Iterator.Source, _lastExtractedLexem); - PushContext(node); - ParseModuleSections(); + ParseModuleSections(); } finally { @@ -81,11 +81,9 @@ public BslSyntaxNode ParseCodeBatch(bool allowReturns = false) PushContext(node); try { - if (allowReturns) - { - _inMethodScope = true; - _isInFunctionScope = true; - } + _inMethodScope = allowReturns; + _isInFunctionScope = allowReturns; + BuildModuleBody(); } finally @@ -180,20 +178,16 @@ private void BuildVariableSection() while (true) { BuildAnnotations(); - if (_lastExtractedLexem.Token == Token.VarDef) - { - if (!hasVars) - { - hasVars = true; - parent.AddChild(allVarsSection); - } - - BuildVariableDefinition(); - } - else - { - break; - } + if (_lastExtractedLexem.Token != Token.VarDef) + break; + + if (!hasVars) + { + hasVars = true; + parent.AddChild(allVarsSection); + } + + BuildVariableDefinition(); } } finally @@ -296,21 +290,17 @@ private void BuildMethodsSection() while (true) { BuildAnnotations(); - if (IsStartOfMethod(_lastExtractedLexem)) - { - if (!sectionExist) - { - sectionExist = true; - _isMethodsDefined = true; - parent.AddChild(allMethodsSection); - } - - BuildMethod(); - } - else - { - break; - } + if (!IsStartOfMethod(_lastExtractedLexem)) + break; + + if (!sectionExist) + { + sectionExist = true; + _isMethodsDefined = true; + parent.AddChild(allMethodsSection); + } + + BuildMethod(); } } finally @@ -1160,7 +1150,6 @@ private void BuildCallParameters(NonTerminalNode callNode) { NextLexem(); // съели открывающую скобку WalkCallArguments(node); - NextLexem(); // съели закрывающую скобку } finally @@ -1366,14 +1355,14 @@ private BslSyntaxNode SelectTerminalNode(in Lexem currentLexem, bool supportAwai { node = BuildNewObjectCreation(); } - else if (currentLexem.Token == Token.Question) - { - node = BuildQuestionOperator(); - } else if (LanguageDef.IsBuiltInFunction(currentLexem.Token)) { node = BuildGlobalCall(currentLexem); } + else if (currentLexem.Token == Token.Question) + { + node = BuildQuestionOperator(); + } else if (supportAwait && currentLexem.Token == Token.Await) { node = BuildExpressionAwaitOperator(currentLexem); From 9ae791cf3bc532c53ec69b9c820912be75cd9b4c Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Sun, 25 Jan 2026 02:01:47 +0400 Subject: [PATCH 06/10] =?UTF-8?q?fix:=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D0=BA=D0=B0=20=D1=80=D0=B0=D0=B7=D0=B4=D0=B5=D0=BB=D0=B8?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D0=B5=D0=B9=20=D0=B2=20=D1=83=D1=81=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=D0=BD=D0=BE=D0=BC=20=D0=BE=D0=BF=D0=B5=D1=80=D0=B0?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SyntaxAnalysis/DefaultBslParser.cs | 22 ++++++------------- .../OneScript.Language.Tests/ParserTests.cs | 11 +++++++++- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs index 6191f470f..fb59f6e6a 100644 --- a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs +++ b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs @@ -1374,29 +1374,21 @@ private BslSyntaxNode SelectTerminalNode(in Lexem currentLexem, bool supportAwai private BslSyntaxNode BuildQuestionOperator() { var node = new NonTerminalNode(NodeKind.TernaryOperator, _lastExtractedLexem); - if(!NextExpected(Token.OpenPar)) - AddError(LocalizedErrors.TokenExpected(Token.OpenPar)); + if (!NextExpected(Token.OpenPar)) + AddError(LocalizedErrors.TokenExpected(Token.OpenPar)); + + NextLexem(); if (!TryParseNode(() => { - NextLexem(); - BuildExpression(node, Token.Comma); - NextLexem(); - BuildExpression(node, Token.Comma); - NextLexem(); - BuildExpression(node, Token.ClosePar); + BuildExpressionUpTo(node, Token.Comma); + BuildExpressionUpTo(node, Token.Comma); + BuildExpressionUpTo(node, Token.ClosePar); })) { return default; } - if (_lastExtractedLexem.Token != Token.ClosePar) - { - AddError(LocalizedErrors.TokenExpected(Token.ClosePar)); - return default; - } - NextLexem(); - return BuildDereference(node); } diff --git a/src/Tests/OneScript.Language.Tests/ParserTests.cs b/src/Tests/OneScript.Language.Tests/ParserTests.cs index 23fef46f2..1d8701f64 100644 --- a/src/Tests/OneScript.Language.Tests/ParserTests.cs +++ b/src/Tests/OneScript.Language.Tests/ParserTests.cs @@ -1243,9 +1243,18 @@ Если Ложь Тогда Ф = 2 КонецЕсли"; + CatchParsingError(code); + } + + [Fact] + public void Check_Question_Operator_Delimiters() + { + var code = @"Ф = ?(Истина? 1 ; 2);"; + CatchParsingError(code); } - + + [Fact] public void TestLocalExportVar() { From 7a991610dbfff82400c98535d4daceb6c69d8ed1 Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Mon, 26 Jan 2026 00:01:47 +0400 Subject: [PATCH 07/10] =?UTF-8?q?=D0=B7=D0=B0=D0=BC=D0=B5=D0=BD=D0=B0=20de?= =?UTF-8?q?fault=20=D0=BD=D0=B0=20=D1=83=D0=B7=D0=B5=D0=BB=20=D0=BE=D1=88?= =?UTF-8?q?=D0=B8=D0=B1=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SyntaxAnalysis/DefaultBslParser.cs | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs index fb59f6e6a..83eaccbfc 100644 --- a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs +++ b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs @@ -747,8 +747,7 @@ private BslSyntaxNode BuildExpressionAwaitOperator(Lexem lexem) } else { - AddError(LocalizedErrors.ExpressionSyntax()); - return new ErrorTerminalNode(_lastExtractedLexem); + return CreateError(LocalizedErrors.ExpressionSyntax()); } } @@ -1051,8 +1050,6 @@ private void BuildEventHandlerOperation(Token token) NextLexem(); var source = BuildExpressionUpTo(node, Token.Comma); - if (source == null) - return; if ((source.Kind != NodeKind.DereferenceOperation || !_lastDereferenceIsWritable) && source.Kind != NodeKind.IndexAccess) @@ -1212,8 +1209,7 @@ private BslSyntaxNode BuildExpression(NonTerminalNode parent, Token stopToken) { if (_lastExtractedLexem.Token == stopToken) { - AddError(LocalizedErrors.ExpressionExpected()); - return default; + return CreateError(LocalizedErrors.ExpressionExpected()); } var op = BuildExpression(0); @@ -1267,8 +1263,7 @@ private BslSyntaxNode BuildPrimaryExpression() if (LanguageDef.GetUnaryPriority(_lastExtractedLexem.Token) <= prio) { - AddError(LocalizedErrors.ExpressionSyntax()); - return default; + return CreateError(LocalizedErrors.ExpressionSyntax()); } var arg = BuildExpression(prio); @@ -1287,14 +1282,12 @@ private BslSyntaxNode BuildExpressionUpTo(NonTerminalNode parent, Token stopToke { if (_lastExtractedLexem.Token == Token.EndOfText) { - AddError(LocalizedErrors.UnexpectedEof()); + return CreateError(LocalizedErrors.UnexpectedEof()); } else { - AddError(LocalizedErrors.TokenExpected(stopToken), false); + return CreateError(LocalizedErrors.TokenExpected(stopToken), false); } - - node = default; } return node; @@ -1333,9 +1326,9 @@ private BslSyntaxNode TerminalNode() BslSyntaxNode node = SelectTerminalNode(_lastExtractedLexem, true); if (node == default) { - AddError(LocalizedErrors.ExpressionSyntax()); + return CreateError(LocalizedErrors.ExpressionSyntax()); } - + return node; } @@ -1351,7 +1344,7 @@ private BslSyntaxNode SelectTerminalNode(in Lexem currentLexem, bool supportAwai { node = BuildGlobalCall(currentLexem); } - else if(currentLexem.Token == Token.NewObject) + else if (currentLexem.Token == Token.NewObject) { node = BuildNewObjectCreation(); } @@ -1367,7 +1360,7 @@ private BslSyntaxNode SelectTerminalNode(in Lexem currentLexem, bool supportAwai { node = BuildExpressionAwaitOperator(currentLexem); } - + return node; } @@ -1375,7 +1368,7 @@ private BslSyntaxNode BuildQuestionOperator() { var node = new NonTerminalNode(NodeKind.TernaryOperator, _lastExtractedLexem); if (!NextExpected(Token.OpenPar)) - AddError(LocalizedErrors.TokenExpected(Token.OpenPar)); + return CreateError(LocalizedErrors.TokenExpected(Token.OpenPar)); NextLexem(); @@ -1386,7 +1379,7 @@ private BslSyntaxNode BuildQuestionOperator() BuildExpressionUpTo(node, Token.ClosePar); })) { - return default; + return CreateError(LocalizedErrors.ExpressionSyntax()); } return BuildDereference(node); @@ -1402,8 +1395,7 @@ private BslSyntaxNode BuildDereference(BslSyntaxNode target) NextLexem(); if (!LanguageDef.IsValidPropertyName(_lastExtractedLexem)) { - AddError(LocalizedErrors.IdentifierExpected()); - return default; + return CreateError(LocalizedErrors.IdentifierExpected()); } var identifier = _lastExtractedLexem; @@ -1434,10 +1426,9 @@ private BslSyntaxNode BuildIndexerAccess(BslSyntaxNode target) node.AddChild(target); NextLexem(); var expression = BuildExpression(node, Token.CloseBracket); - if (expression == default) + if (expression.Kind == NodeKind.Unknown) { - AddError(LocalizedErrors.ExpressionSyntax()); - return default; + return CreateError(LocalizedErrors.ExpressionSyntax()); } NextLexem(); _lastDereferenceIsWritable = true; @@ -1462,8 +1453,7 @@ private BslSyntaxNode BuildNewObjectCreation() } else { - AddError(LocalizedErrors.IdentifierExpected()); - node = default; + return CreateError(LocalizedErrors.IdentifierExpected()); } return BuildDereference(node); @@ -1554,6 +1544,13 @@ private void AddError(CodeError err, bool doFastForward = true) throw new InternalParseException(err); } + private ErrorTerminalNode CreateError(CodeError error, bool doFastForward = true) + { + var lexem = _lastExtractedLexem; + AddError(error, doFastForward); + return new ErrorTerminalNode(lexem); + } + private bool IsUserSymbol(in Lexem lex) { return LanguageDef.IsUserSymbol(in lex) || (!_isInAsyncMethod && lex.Token == Token.Await); From d571c76b2b175126718a06d7ece0cc45f8e5b4b6 Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Thu, 29 Jan 2026 14:05:58 +0400 Subject: [PATCH 08/10] =?UTF-8?q?fix=20#1654:=20=D1=81=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=BE=D0=BA=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=20=D1=82=D0=BE=D0=BB=D1=8C=D0=BA=D0=BE=20=D1=87?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=B7=20=D0=B7=D0=B0=D0=BF=D1=8F=D1=82=D1=83?= =?UTF-8?q?=D1=8E=20+=D1=82=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SyntaxAnalysis/DefaultBslParser.cs | 199 +++++++++--------- .../OneScript.Language.Tests/ParserTests.cs | 20 ++ 2 files changed, 122 insertions(+), 97 deletions(-) diff --git a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs index 83eaccbfc..8f136cc19 100644 --- a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs +++ b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs @@ -194,6 +194,7 @@ private void BuildVariableSection() { PopContext(); } + } private void BuildVariableDefinition() @@ -413,49 +414,55 @@ private void BuildMethodParameters(MethodSignatureNode signature) NextLexem(); // ( - var expectParameter = false; - while (_lastExtractedLexem.Token != Token.ClosePar) - { - BuildAnnotations(); - var param = new MethodParameterNode(); - paramList.AddChild(param); - ApplyAnnotations(param); - // [Знач] Identifier [= Literal],... - if (_lastExtractedLexem.Token == Token.ByValParam) - { - CreateChild(param, NodeKind.ByValModifier, _lastExtractedLexem); - NextLexem(); - } - - if (!IsUserSymbol(_lastExtractedLexem)) - { - AddError(LocalizedErrors.IdentifierExpected()); - return; - } - CreateChild(param, NodeKind.Identifier, _lastExtractedLexem); - NextLexem(); - if (_lastExtractedLexem.Token == Token.Equal) - { - NextLexem(); - if(!BuildDefaultParameterValue(param, NodeKind.ParameterDefaultValue)) - return; - } - - expectParameter = false; - if (_lastExtractedLexem.Token == Token.Comma) - { - NextLexem(); - expectParameter = true; - } - } - - if (expectParameter) - { - AddError(LocalizedErrors.IdentifierExpected(), false); - } - + if (_lastExtractedLexem.Token != Token.ClosePar) + while (true) + { + BuildMethodParameter(paramList); + + if (_lastExtractedLexem.Token == Token.ClosePar) + { + break; + } + + if (_lastExtractedLexem.Token == Token.Comma) + { + NextLexem(); + } + else + { + AddError(LocalizedErrors.TokenExpected(Token.ClosePar)); + return; + } + } + NextLexem(); // ) + } + private void BuildMethodParameter(NonTerminalNode paramList) + { + BuildAnnotations(); + var param = new MethodParameterNode(); + paramList.AddChild(param); + ApplyAnnotations(param); + // [Знач] Identifier [= Literal],... + if (_lastExtractedLexem.Token == Token.ByValParam) + { + CreateChild(param, NodeKind.ByValModifier, _lastExtractedLexem); + NextLexem(); + } + + if (!IsUserSymbol(_lastExtractedLexem)) + { + AddError(LocalizedErrors.IdentifierExpected()); + return; + } + CreateChild(param, NodeKind.Identifier, _lastExtractedLexem); + NextLexem(); + if (_lastExtractedLexem.Token == Token.Equal) + { + NextLexem(); + BuildDefaultParameterValue(param, NodeKind.ParameterDefaultValue); + } } private bool BuildDefaultParameterValue(NonTerminalNode param, NodeKind nodeKind) @@ -526,6 +533,7 @@ private void BuildAnnotations() _annotations.Add(node); } } + private AnnotationNode BuildAnnotationDefinition() { var node = new AnnotationNode(NodeKind.Annotation, _lastExtractedLexem); NextLexem(); @@ -540,23 +548,31 @@ private void BuildAnnotationParameters(AnnotationNode annotation) return; NextLexem(); - - while (_lastExtractedLexem.Token != Token.EndOfText) + + if (_lastExtractedLexem.Token != Token.ClosePar) + while (true) { - if (_lastExtractedLexem.Token == Token.ClosePar) - { - NextLexem(); - break; - } - - BuildAnnotationParameter(annotation); + BuildAnnotationParameter(annotation); + + if (_lastExtractedLexem.Token == Token.ClosePar) + { + break; + } + if (_lastExtractedLexem.Token == Token.Comma) { NextLexem(); } - } - } - + else + { + AddError(LocalizedErrors.TokenExpected(Token.ClosePar), false); + return; + } + } + + NextLexem(); // ) + } + private void BuildAnnotationParameter(AnnotationNode annotation) { bool success = true; @@ -1146,59 +1162,48 @@ private void BuildCallParameters(NonTerminalNode callNode) try { NextLexem(); // съели открывающую скобку - WalkCallArguments(node); + BuildCallArguments(node); NextLexem(); // съели закрывающую скобку } finally { PopStructureToken(); } - } - - private int WalkCallArguments(NonTerminalNode node) - { - int argCount = 0; - while (_lastExtractedLexem.Token != Token.ClosePar) - { - BuildCallArgument(node); - argCount++; - } - - if (_lastExtractedLexem.Token != Token.ClosePar) - { - AddError(LocalizedErrors.TokenExpected(Token.ClosePar)); - argCount = -1; - } - - return argCount; - } - - private void BuildCallArgument(NonTerminalNode argsList) - { - if (_lastExtractedLexem.Token == Token.Comma) - { - argsList.AddChild(new NonTerminalNode(NodeKind.CallArgument, _lastExtractedLexem)); + } - BuildLastDefaultArg(argsList); - } - else if (_lastExtractedLexem.Token != Token.ClosePar) - { - var node = argsList.AddNode(new NonTerminalNode(NodeKind.CallArgument, _lastExtractedLexem)); - BuildOptionalExpression(node, Token.Comma); - if (_lastExtractedLexem.Token == Token.Comma) - { - BuildLastDefaultArg(argsList); - } - } + private void BuildCallArguments(NonTerminalNode node) + { + if (_lastExtractedLexem.Token != Token.ClosePar) + while (true) + { + BuildOptionalCallArgument(node); + + if (_lastExtractedLexem.Token == Token.ClosePar) + { + break; + } + + if (_lastExtractedLexem.Token == Token.Comma) + { + NextLexem(); + } + else + { + AddError(LocalizedErrors.TokenExpected(Token.ClosePar)); + } + } } - private void BuildLastDefaultArg(NonTerminalNode argsList) - { - NextLexem(); - if (_lastExtractedLexem.Token == Token.ClosePar) + private void BuildOptionalCallArgument(NonTerminalNode argsList) + { + var arg = argsList.AddNode(new NonTerminalNode(NodeKind.CallArgument, _lastExtractedLexem)); + if (_lastExtractedLexem.Token == Token.Comma + || _lastExtractedLexem.Token == Token.ClosePar) { - argsList.AddChild(new NonTerminalNode(NodeKind.CallArgument, _lastExtractedLexem)); - } + return; + } + + arg.AddNode( BuildExpression(0) ); } #endregion @@ -1480,7 +1485,7 @@ private void NewObjectDynamicConstructor(NonTerminalNode node) // есть аргументы после имени NextLexem(); } - WalkCallArguments(callArgs); + BuildCallArguments(callArgs); node.AddChild(callArgs); NextLexem(); } diff --git a/src/Tests/OneScript.Language.Tests/ParserTests.cs b/src/Tests/OneScript.Language.Tests/ParserTests.cs index 1d8701f64..7d965101e 100644 --- a/src/Tests/OneScript.Language.Tests/ParserTests.cs +++ b/src/Tests/OneScript.Language.Tests/ParserTests.cs @@ -1251,9 +1251,29 @@ public void Check_Question_Operator_Delimiters() { var code = @"Ф = ?(Истина? 1 ; 2);"; + CatchParsingError(code); + } + + [Fact] + public void Check_Method_Definition_Delimiters() + { + var code = @"Процедура Проц1(арг1 арг2) + КонецПроцедуры"; + CatchParsingError(code); } + [Fact] + public void Check_Method_Call_Delimiters() + { + var code = @"Процедура Проц1(арг1, арг2) + КонецПроцедуры + Проц1(""1"" 2)"; + + CatchParsingError(code); + } + + [Fact] public void TestLocalExportVar() From e856bb2e3cb298f5d1c11a4fa0f207aa0d7b5f65 Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Thu, 29 Jan 2026 20:55:05 +0400 Subject: [PATCH 09/10] =?UTF-8?q?=D0=B2=D1=8B=D1=85=D0=BE=D0=B4=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B0=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs index 8f136cc19..2d1ea47e4 100644 --- a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs +++ b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs @@ -729,8 +729,7 @@ private void BuildComplexStructureStatement() } else { - var expected = _tokenStack.Peek(); - AddError(LocalizedErrors.TokenExpected(expected)); + AddError(LocalizedErrors.TokenExpected(_tokenStack.Peek())); } break; } @@ -775,6 +774,7 @@ private void BuildGotoOperator() if (_lastExtractedLexem.Type != LexemType.LabelRef) { AddError(LocalizedErrors.LabelNameExpected()); + return; } gotoNode.AddChild(new LabelNode(_lastExtractedLexem)); @@ -1190,6 +1190,7 @@ private void BuildCallArguments(NonTerminalNode node) else { AddError(LocalizedErrors.TokenExpected(Token.ClosePar)); + return; } } } @@ -1318,6 +1319,7 @@ private BslSyntaxNode BuildParenthesis() if (_lastExtractedLexem.Token != Token.ClosePar) { AddError(LocalizedErrors.TokenExpected(Token.ClosePar)); + return new ErrorTerminalNode(); } NextLexem(); From 43aac757ad609208d47178a8e3e00d2aac86468a Mon Sep 17 00:00:00 2001 From: Mr-Rm Date: Fri, 30 Jan 2026 23:23:27 +0400 Subject: [PATCH 10/10] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D0=B8=D0=BC=D0=B5=D1=8E?= =?UTF-8?q?=D1=89=D1=83=D1=8E=D1=81=D1=8F=20=D1=84=D1=83=D0=BD=D0=BA=D1=86?= =?UTF-8?q?=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs index 2d1ea47e4..7179ea767 100644 --- a/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs +++ b/src/OneScript.Language/SyntaxAnalysis/DefaultBslParser.cs @@ -1318,8 +1318,7 @@ private BslSyntaxNode BuildParenthesis() var expr = BuildExpression(0); if (_lastExtractedLexem.Token != Token.ClosePar) { - AddError(LocalizedErrors.TokenExpected(Token.ClosePar)); - return new ErrorTerminalNode(); + return CreateError(LocalizedErrors.TokenExpected(Token.ClosePar)); } NextLexem();