} // set during AST construction #region implemented abstract members of Node /// <summary> /// Resolve type defined by this typeExpression. Type Expression must be given in reversed order. /// </summary> /// <returns>The resolved type.</returns> /// <param name="typeExpr">Enumerator of reversed type expresion enumeration.</param> public static TypeNode RecursiveResolveArrayType <TSymbol>(IEnumerator <IParseTree <TSymbol> > typeExpr) where TSymbol : ISymbol <TSymbol> { bool isMutable = ASTBuilder.EatSymbol("mutable", typeExpr); if (ASTBuilder.EatSymbol("]", typeExpr)) // if ] is present then create ArrayType { var resType = new ArrayTypeNode(); resType.IsConstant = !isMutable; resType.IsFixedSize = false; // we initialize all arrays as dynamic size if (ASTBuilder.EatSymbol("[", typeExpr)) // opening bracket, no length expression { resType.LengthExpression = null; } else // length expression present { resType.LengthExpression = ExpressionNode.GetExpressionNode(typeExpr.Current); typeExpr.MoveNext(); Debug.Assert(ASTBuilder.EatSymbol("[", typeExpr)); // eat opening bracket } resType.ElementType = RecursiveResolveArrayType(typeExpr); return(resType); } else { var resType = new NamedTypeNode(); resType.BuildNode(typeExpr.Current); resType.IsConstant = !isMutable; return(resType); } }
} // set during AST construction #region implemented abstract members of Node public override void BuildNode <TSymbol>(IParseTree <TSymbol> parseTree) { // Block -> "{" (Expression ";")* "}" var childs = ASTBuilder.ChildrenEnumerator(parseTree); childs.MoveNext(); // go to "{" Debug.Assert(childs.MoveNext()); // enter the brackets var elems = new List <ExpressionNode>(); while (!ASTBuilder.EatSymbol("}", childs)) // collect expressions until closing "}" { elems.Add(ExpressionNode.GetExpressionNode(childs.Current)); childs.MoveNext(); // go to the next symbol Debug.Assert(ASTBuilder.EatSymbol(";", childs)); // it must be ";" } Elements = elems; }
/// <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); }