src/NFun/SyntaxParsing/SyntaxNodeReader.cs
/// <summary>
/// Reads node with specified syntax priority
/// throws FunParseException if underlying syntax is invalid,
/// or returns null if underlying syntax cannot be represented as node
/// (EOF for example)
/// </summary>
Reads node with specified syntax priority
throws FunParseException if underlying syntax is invalid,
or returns null if underlying syntax cannot be represented as node
(EOF for example)
Reads node with specified syntax priority throws FunParseException if underlying syntax is invalid or returns null if underlying syntax cannot be represented as node ( EOF for example )
private static ISyntaxNode ReadNodeOrNull(TokFlow flow, int priority) {
        if (priority < MinPriority)
            return ReadAtomicNodeOrNull(flow);
        var leftNode = ReadNodeOrNull(flow, priority - 1);
        while (true)
        {
            flow.SkipNewLines();
            if (flow.IsDone)
                return leftNode;
            var opToken = flow.Current;
            if (!Priorities.TryGetValue(opToken.Type, out var opPriority))
                return leftNode;
            if (opPriority > priority)
                return leftNode;
            if (leftNode == null)
                throw ErrorFactory.LeftBinaryArgumentIsMissing(opToken);
            if (opToken.Type == TokType.ArrOBr)
            {
                if (flow.IsPrevious(TokType.NewLine))
                    return leftNode;
                leftNode = ReadArraySliceNode(flow, leftNode);
            }
            else if (opToken.Type == TokType.Dot)
            {
                flow.MoveNext();
                if (!flow.MoveIf(TokType.Id, out var id))
                    throw ErrorFactory.FunctionOrStructMemberNameIsMissedAfterDot(opToken);
                var next = flow.Current?.Type;
                if (next == TokType.Obr || next == TokType.FiObr)
                    leftNode = ReadFunctionCall(flow, id, leftNode);
                else 
                    leftNode = SyntaxNodeFactory.FieldAccess(leftNode, id);
            }
            else if (opToken.Type == TokType.Obr)
            {
                if (flow.IsPrevious(TokType.NewLine))
                    return leftNode;
                if (!flow.IsPrevious(TokType.Cbr) && !flow.IsPrevious(TokType.FiCbr))
                    return leftNode;
                leftNode = ReadResultCall(flow, leftNode);
            }
            else
            {
                flow.MoveNext();
                var rightNode = ReadNodeOrNull(flow, priority - 1);
                if (rightNode == null)
                    throw ErrorFactory.RightBinaryArgumentIsMissing(leftNode, opToken);
                if (OperatorFunNames.ContainsKey(opToken.Type))
                    leftNode = SyntaxNodeFactory.OperatorFun(
                        OperatorFunNames[opToken.Type],
                        new[] { leftNode, rightNode },
                        leftNode.Interval.Start, rightNode.Interval.Finish);
                else
                    throw ErrorFactory.OperatorIsUnknown(opToken);
            }
        }
    }
private static ISyntaxNode ReadNodeOrNull ( TokFlow flow , int priority ) { if ( priority < MinPriority ) return ReadAtomicNodeOrNull ( flow ) ; var leftNode = ReadNodeOrNull ( flow , priority - 1 ) ; while ( true ) { flow . SkipNewLines ( ) ; if ( flow . IsDone ) return leftNode ; var opToken = flow . Current ; if ( ! Priorities . TryGetValue ( opToken . Type , out var opPriority ) ) return leftNode ; if ( opPriority > priority ) return leftNode ; if ( leftNode == null ) throw ErrorFactory . LeftBinaryArgumentIsMissing ( opToken ) ; if ( opToken . Type == TokType . ArrOBr ) { if ( flow . IsPrevious ( TokType . NewLine ) ) return leftNode ; leftNode = ReadArraySliceNode ( flow , leftNode ) ; } else if ( opToken . Type == TokType . Dot ) { flow . MoveNext ( ) ; if ( ! flow . MoveIf ( TokType . Id , out var id ) ) throw ErrorFactory . FunctionOrStructMemberNameIsMissedAfterDot ( opToken ) ; var next = flow . Current ? . Type ; if ( next == TokType . Obr || next == TokType . FiObr ) leftNode = ReadFunctionCall ( flow , id , leftNode ) ; else leftNode = SyntaxNodeFactory . FieldAccess ( leftNode , id ) ; } else if ( opToken . Type == TokType . Obr ) { if ( flow . IsPrevious ( TokType . NewLine ) ) return leftNode ; if ( ! flow . IsPrevious ( TokType . Cbr ) && ! flow . IsPrevious ( TokType . FiCbr ) ) return leftNode ; leftNode = ReadResultCall ( flow , leftNode ) ; } else { flow . MoveNext ( ) ; var rightNode = ReadNodeOrNull ( flow , priority - 1 ) ; if ( rightNode == null ) throw ErrorFactory . RightBinaryArgumentIsMissing ( leftNode , opToken ) ; if ( OperatorFunNames . ContainsKey ( opToken . Type ) ) leftNode = SyntaxNodeFactory . OperatorFun ( OperatorFunNames [ opToken . Type ] , new [ ] { leftNode , rightNode } , leftNode . Interval . Start , rightNode . Interval . Finish ) ; else throw ErrorFactory . OperatorIsUnknown ( opToken ) ; } } }
Reads node with specified syntax priority
throws FunParseException if underlying syntax is invalid,
or returns null if underlying syntax cannot be represented as node
(EOF for example)
Reads node with specified syntax priority throws FunParseException if underlying syntax is invalid or returns null if underlying syntax cannot be represented as node ( EOF for example )
//Lower priority is the special case //starting with left Node //building the syntax tree //if flow is done than current node is everything we got // example: // 1*2+3 {return whole expression } //if current token is not an operation //than expression is done //example: // 1*2 \r{return expression} y=... //if op has higher priority us //than expression is done // example: //2*3{stops here}-1 //We can use array slicing, only if there were no new lines before. //there is problem of choose between anonymous array init and array slice  //otherwise // Open bracket. It means call //else it is struct field //call result of previous expression: // (expr)(arg1, ... argN) //building the tree from the left                     //trace: //ReadNodeOrNull(priority: 3 ) // *,/,%,AND //0: {start} 4/2*5+1 //1: {l:4} /2*5+1 //2: {l:4}{op:/} 2*5+1 //3: {l:4}{op:/}{r:2} *5+1 //4: {l:(4/2)} *5+1 //5: {l:(4/2)}{op:*}5+1 //6: {l:(4/2)}{op:*}{r:5}+1 //7: {l:((4/2)*5)}{op:+} 1 //8: '+' priority is higter than 3: return l:((4/2)*5)
flow
TokFlow
priority
int