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/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/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/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/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 1d1a543c9..7179ea767 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,26 +178,23 @@ 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 { PopContext(); } + } private void BuildVariableDefinition() @@ -212,60 +207,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 +276,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; } @@ -303,21 +291,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 @@ -380,8 +364,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); @@ -389,8 +373,8 @@ private void BuildMethodBody() finally { PopContext(); - } - + } + CreateChild(CurrentParent, NodeKind.BlockEnd, _lastExtractedLexem); NextLexem(); } @@ -430,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) @@ -487,12 +477,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 +491,6 @@ private bool BuildDefaultParameterValue(NonTerminalNode param, NodeKind nodeKind } } - _lastExtractedLexem.Content = literalText; CreateChild(param, nodeKind, _lastExtractedLexem); NextLexem(); } @@ -545,6 +533,7 @@ private void BuildAnnotations() _annotations.Add(node); } } + private AnnotationNode BuildAnnotationDefinition() { var node = new AnnotationNode(NodeKind.Annotation, _lastExtractedLexem); NextLexem(); @@ -559,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; @@ -661,7 +658,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,8 +729,7 @@ private void BuildComplexStructureStatement() } else { - var expected = _tokenStack.Peek(); - AddError(LocalizedErrors.TokenExpected(expected)); + AddError(LocalizedErrors.TokenExpected(_tokenStack.Peek())); } break; } @@ -741,9 +737,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()); } @@ -757,9 +753,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) { @@ -768,8 +762,7 @@ private BslSyntaxNode BuildExpressionAwaitOperator(Lexem lexem) } else { - AddError(LocalizedErrors.ExpressionSyntax()); - return new ErrorTerminalNode(_lastExtractedLexem); + return CreateError(LocalizedErrors.ExpressionSyntax()); } } @@ -781,12 +774,13 @@ private void BuildGotoOperator() if (_lastExtractedLexem.Type != LexemType.LabelRef) { AddError(LocalizedErrors.LabelNameExpected()); + return; } gotoNode.AddChild(new LabelNode(_lastExtractedLexem)); NextLexem(); - _nodeContext.AddChild(gotoNode); + CurrentParent.AddChild(gotoNode); } private void CheckAsyncMethod() @@ -845,8 +839,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 { @@ -863,8 +858,7 @@ private void BuildWhileStatement() } private void BuildForStatement() - { - var lexem = _lastExtractedLexem; + { NextLexem(); NodeKind loopKind; @@ -904,8 +898,8 @@ private void BuildCountableForStatement(NonTerminalNode loopNode) AddError(LocalizedErrors.IdentifierExpected()); BuildBatchWithContext(loopNode, Token.EndLoop); return; - } - + } + var counter = _lastExtractedLexem; if (!NextExpected(Token.Equal)) { @@ -924,8 +918,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); @@ -1072,10 +1066,9 @@ 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) + if ((source.Kind != NodeKind.DereferenceOperation || !_lastDereferenceIsWritable) + && source.Kind != NodeKind.IndexAccess) { AddError(LocalizedErrors.WrongEventName()); return; @@ -1140,7 +1133,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; // одиночный идентификатор @@ -1153,7 +1146,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); @@ -1169,60 +1162,49 @@ 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) - { - CreateChild(argsList, NodeKind.CallArgument, _lastExtractedLexem); - - BuildLastDefaultArg(argsList); - } - else if (_lastExtractedLexem.Token != Token.ClosePar) + } + + 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)); + return; + } + } + } + + private void BuildOptionalCallArgument(NonTerminalNode argsList) + { + var arg = argsList.AddNode(new NonTerminalNode(NodeKind.CallArgument, _lastExtractedLexem)); + if (_lastExtractedLexem.Token == Token.Comma + || _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 BuildLastDefaultArg(NonTerminalNode argsList) - { - NextLexem(); - if (_lastExtractedLexem.Token == Token.ClosePar) - { - CreateChild(argsList, NodeKind.CallArgument, _lastExtractedLexem); - } + return; + } + + arg.AddNode( BuildExpression(0) ); } #endregion @@ -1233,134 +1215,68 @@ private BslSyntaxNode BuildExpression(NonTerminalNode parent, Token stopToken) { if (_lastExtractedLexem.Token == stopToken) { - AddError(LocalizedErrors.ExpressionExpected()); - return default; + return CreateError(LocalizedErrors.ExpressionExpected()); } - 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() - { - 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); + firstArg = new BinaryOperationNode(firstArg, secondArg, operationLexem); } return firstArg; - } - - private BslSyntaxNode BuildUnaryMathExpression() + } + + private BslSyntaxNode BuildPrimaryExpression() { - 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) + { + return CreateError(LocalizedErrors.ExpressionSyntax()); + } + + var arg = BuildExpression(prio); + return new UnaryOperationNode(arg, operation); + } + + private BslSyntaxNode BuildExpressionUpTo(NonTerminalNode parent, Token stopToken) { var node = BuildExpression(parent, stopToken); @@ -1372,14 +1288,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; @@ -1392,36 +1306,23 @@ 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) - { - 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) + { + return CreateError(LocalizedErrors.TokenExpected(Token.ClosePar)); + } + NextLexem(); + + return BuildDereference(expr); } #endregion @@ -1431,9 +1332,9 @@ private BslSyntaxNode TerminalNode() BslSyntaxNode node = SelectTerminalNode(_lastExtractedLexem, true); if (node == default) { - AddError(LocalizedErrors.ExpressionSyntax()); + return CreateError(LocalizedErrors.ExpressionSyntax()); } - + return node; } @@ -1442,59 +1343,51 @@ 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)) { node = BuildGlobalCall(currentLexem); } - else if(currentLexem.Token == Token.NewObject) + else if (currentLexem.Token == Token.NewObject) { 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); } - + return node; } private BslSyntaxNode BuildQuestionOperator() { var node = new NonTerminalNode(NodeKind.TernaryOperator, _lastExtractedLexem); - if(!NextExpected(Token.OpenPar)) - AddError(LocalizedErrors.TokenExpected(Token.OpenPar)); + if (!NextExpected(Token.OpenPar)) + return CreateError(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; + return CreateError(LocalizedErrors.ExpressionSyntax()); } - if (_lastExtractedLexem.Token != Token.ClosePar) - { - AddError(LocalizedErrors.TokenExpected(Token.ClosePar)); - return default; - } - NextLexem(); - return BuildDereference(node); } @@ -1508,15 +1401,14 @@ private BslSyntaxNode BuildDereference(BslSyntaxNode target) NextLexem(); if (!LanguageDef.IsValidPropertyName(_lastExtractedLexem)) { - AddError(LocalizedErrors.IdentifierExpected()); - return default; + return CreateError(LocalizedErrors.IdentifierExpected()); } var identifier = _lastExtractedLexem; 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); } @@ -1540,10 +1432,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; @@ -1568,8 +1459,7 @@ private BslSyntaxNode BuildNewObjectCreation() } else { - AddError(LocalizedErrors.IdentifierExpected()); - node = default; + return CreateError(LocalizedErrors.IdentifierExpected()); } return BuildDereference(node); @@ -1596,7 +1486,7 @@ private void NewObjectDynamicConstructor(NonTerminalNode node) // есть аргументы после имени NextLexem(); } - WalkCallArguments(callArgs); + BuildCallArguments(callArgs); node.AddChild(callArgs); NextLexem(); } @@ -1660,6 +1550,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); @@ -1676,11 +1573,10 @@ private Token[] PopStructureToken() return tok; } - private 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) diff --git a/src/Tests/OneScript.Language.Tests/ParserTests.cs b/src/Tests/OneScript.Language.Tests/ParserTests.cs index 23fef46f2..7d965101e 100644 --- a/src/Tests/OneScript.Language.Tests/ParserTests.cs +++ b/src/Tests/OneScript.Language.Tests/ParserTests.cs @@ -1243,9 +1243,38 @@ public void Check_Semicolon_Between_Statements() Ф = 2 КонецЕсли"; + CatchParsingError(code); + } + + [Fact] + 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() {