/// <summary> /// Parse one line expression with ++ -- (postfix), function call, array subscript, slice subscript operators. /// Enumerator must be given with reversed ordering of arguments. This corresponds to Operator2Expression from Grammar. /// </summary> public static ExpressionNode ParseOperator2 <TSymbol>(IEnumerator <IParseTree <TSymbol> > opExpr) where TSymbol : ISymbol <TSymbol> { // O2 -> O1 ( "++" | "--" // | "(" (E ",")* E? ")" // | "[" E "]" // | "[" E? ".." E? "]" // )* if (opExpr.Current.Symbol.IsTerminal) { string curText = ASTBuilder.EatTerminal(opExpr); switch (curText) { case "++": case "--": return(OperatorNode.BuildUnaryOperator(2, curText, ParseOperator2(opExpr))); case ")": var args = new LinkedList <ExpressionNode>(); while (!ASTBuilder.EatSymbol("(", opExpr)) { ASTBuilder.EatSymbol(",", opExpr); // eat ',' before arg - f(x,y,z,) is also possible args.AddFirst(GetExpressionNode(opExpr.Current)); opExpr.MoveNext(); // move to next param with ',' } var res = new FunctionCallNode(); res.Arguments = new List <ExpressionNode>(args); // TODO: can something return a 'pointer' to function which we can call to execute? res.Name = opExpr.Current.Fragment.GetOriginText(); return(res); case "]": var toExpr = ASTBuilder.EatNonTerminal(opExpr); // slice to or index bool isSlice = ASTBuilder.EatSymbol("..", opExpr); var fromExpr = ASTBuilder.EatNonTerminal(opExpr); Debug.Assert(ASTBuilder.EatSymbol("[", opExpr)); if (isSlice) // slice subscript { return(SliceNode.CreateSliceNode(ParseOperator2(opExpr), GetExpressionOrNull(fromExpr), GetExpressionOrNull(toExpr))); } else // array subscript { return(ElementNode.Create(ParseOperator2(opExpr), GetExpressionNode(toExpr))); } default: Debug.Assert(false); break; } } else // non-terminal -> Operator1Expression { var op1 = opExpr.Current; Debug.Assert(!opExpr.MoveNext()); // it must be final symbol in this enumeration var node = ASTBuilder.FirstChild(op1); // Operator1Expression -> Operator0Expression // Operator0Expression -> AtomicExpression | "(" Expression ")"; var childs = ASTBuilder.ChildrenEnumerator(node); Debug.Assert(childs.MoveNext()); if (ASTBuilder.EatSymbol("(", childs)) { return(GetExpressionNode(childs.Current)); // Expression } else // proceed with AtomicExpression { return(ResolveAtomicExpression(childs.Current)); } } return(null); }