private IType ParseType() { //backup modifiers because ParseQualifiedIdentifier will consume ParseTypeParameter // and ParseTypeParameter consume modifiers ... Modifier backupModifiers = curmods; curmods = Modifier.Empty; IType result = new TypeNode(curtok); QualifiedIdentifierExpression ident = ParseQualifiedIdentifier(true, false, false); // if the ParseQualifiedIdentifier is can resolve the identifier to a type, // the parser does not need to wrappe the type in another typenode ... if ( ident.Expressions.Last is PredefinedTypeNode ) { result = (IType)ident.Expressions.Last; } else { ((TypeNode)result).Identifier = ident; // move the rank specifier if (((TypeNode)result).Identifier.IsType) { ((IType)result).RankSpecifiers = ((IType)((TypeNode)result).Identifier.Expressions.Last).RankSpecifiers; ((IType)((TypeNode)result).Identifier.Expressions.Last).RankSpecifiers = new List<int>(); } } if (curtok.ID == TokenID.Star) { result = new TypePointerNode( (ExpressionNode)result ); Advance(); } if (curtok.ID == TokenID.Question) { ((INullableType)result).IsNullableType = true; Advance(); } curmods = backupModifiers; return result; }
private ExpressionNode ParseExpressionOrType(bool inStatementContext) { // Can the interior be a type? (A.2.2) switch (curtok.ID) { // type-name case TokenID.Ident: // simple-type case TokenID.SByte: case TokenID.Byte: case TokenID.Short: case TokenID.UShort: case TokenID.Int: case TokenID.UInt: case TokenID.Long: case TokenID.ULong: case TokenID.Char: case TokenID.Float: case TokenID.Double: case TokenID.Decimal: case TokenID.Bool: // class-type case TokenID.Object: case TokenID.String: // yes, it can break; default: // no, it can not return ParseExpression(); } ExpressionNode expr = ParseIdentifierOrKeyword(false, false, false, false, false); if (curtok.ID == TokenID.ColonColon) { // id :: id type-parameter-list_opt QualifiedIdentifierExpression qualID = new QualifiedIdentifierExpression(curtok); // TODO: Replace by QualifiedAliasMember instance qualID.IsNamespaceAliasQualifier = true; qualID.Expressions.Add(expr); Advance(); // over ColonColon qualID.Expressions.Add(ParseMember(inStatementContext)); expr = qualID; } else if (ParsePossibleTypeParameterNode(false, false, false, inStatementContext)) { expr = new TypeNode(expr); ApplyTypeParameters((TypeNode)expr); } while (curtok.ID == TokenID.Dot) { Advance(); // over Dot if (curtok.ID != TokenID.Ident) { RecoverFromError(TokenID.Ident); return expr; } expr = new MemberAccessExpression(expr, ParseMember(inStatementContext), TokenID.Dot); } bool hasQuestionMark = false; int starCount = 0; bool hasBracket = false; if (curtok.ID == TokenID.Question) { Advance(); hasQuestionMark = true; } while (curtok.ID == TokenID.Star) { Advance(); starCount++; } // return (a * b); // return (a ? b : c); // a* b = c; // a? b = c; // a b = c; //if(curtok.ID == TokenID.Ident || (hasQuestionMark || starCount > 0) && curtok.ID == TokenID.RParen) goto foundType; if (curtok.ID == TokenID.Ident) { if (inStatementContext) goto foundType; else if (!hasQuestionMark && starCount == 0) goto foundType; // it is a parse error } else if (curtok.ID == TokenID.RParen) { if (hasQuestionMark || starCount > 0) goto foundType; } else if (curtok.ID == TokenID.LBracket) { Advance(); hasBracket = true; if (hasQuestionMark || starCount > 0 || curtok.ID == TokenID.Comma || curtok.ID == TokenID.RBracket) goto foundType; } // // treat as expression // if (hasQuestionMark) { // hasBracket is false ExpressionNode trueExpr = ParseSubexpression(starCount > 0 ? (int)PRECEDENCE_UNARY : 1); while (starCount-- > 0) trueExpr = new DereferenceExpression(trueExpr); AssertAndAdvance(TokenID.Colon); return new ConditionalExpression(expr, trueExpr, ParseExpression()); } else if (starCount > 0) { // hasBracket is false starCount--; ExpressionNode right = ParseSubexpression(starCount > 0 ? PRECEDENCE_UNARY : PRECEDENCE_MULTIPLICATIVE + ASSOC_LEFT); while (starCount-- > 0) right = new DereferenceExpression(right); expr = new BinaryExpression(TokenID.Star, expr, right); } else if (hasBracket) { expr = new ElementAccessExpression(expr, ParseExpressionList()); AssertAndAdvance(TokenID.RBracket); } return ParseSubexpression(1, expr); // // treat as type // foundType: TypeNode typeNode = new TypeNode(expr); if (hasQuestionMark) typeNode.IsNullableType = true; while (starCount-- > 0) typeNode = new TypePointerNode(typeNode); if (hasBracket) { while (true) { int numCommas = 0; while (curtok.ID == TokenID.Comma) { Advance(); numCommas++; } AssertAndAdvance(TokenID.RBracket); typeNode.RankSpecifiers.Add(numCommas); if (curtok.ID != TokenID.LBracket) break; Advance(); } } return typeNode; }
/* private TypeNode ParseTypeDeclarator(TypeNode type) { if(curtok.ID == TokenID.Question && curtok.NullableDeclaration) { Advance(); type.IsNullableType = true; } while(curtok.ID == TokenID.Star) { Advance(); type = new TypePointerNode(type); } // TODO: Parse rank specifiers return type; }*/ // note: this does NOT check for rank specifiers: MyType[,,] // to also do this use CheckRankSpecifier(TypeNode); private TypeNode ParseType(bool considerTrinary) { //backup modifiers because ParseQualifiedIdentifier will consume ParseTypeParameter // and ParseTypeParameter consume modifiers ... Modifier backupModifiers = curmods; curmods = Modifier.Empty; TypeNode result = null; QualifiedIdentifierExpression ident = ParseQualifiedIdentifier(true, false, false); // if the ParseQualifiedIdentifier can resolve the identifier to a type, // the parser does not need to wrap the type in another type node ... if (ident.Expressions.Last is PredefinedTypeNode) { result = (TypeNode)ident.Expressions.Last; } else { result = new TypeNode(curtok); result.Identifier = ident; // Edit Robin: I don't think ParseQualifiedIdentifier will ever have rank specifiers.. //// move the rank specifier //if (result.Identifier.IsType) //{ // result.RankSpecifiers = ((IType)result.Identifier.Expressions.Last).RankSpecifiers; // ((IType)result.Identifier.Expressions.Last).RankSpecifiers = new List<int>(); //} } if (curtok.ID == TokenID.Question && (!considerTrinary || curtok.NullableDeclaration)) { Advance(); result.IsNullableType = true; } while (curtok.ID == TokenID.Star) { Advance(); result = new TypePointerNode(result); } curmods = backupModifiers; return result; }
// statements private StatementNode ParseStatement() { // label ident : colon // localDecl type : ident // block LCurly // empty Semi // expression // -invoke pexpr : LParen // -objCre new : type // -assign uexpr : assignOp // -postInc pexpr : ++ // -postDec pexpr : -- // -preInc ++ : uexpr // -preDec -- : uexpr // // selection if : LParen // switch : LParen // // iteration while : LParen // do : LParen // for : LParen // foreach : LParen // // jump break : Semi // continue: Semi // goto : ident | case | default // return : expr // throw : expr // // try try : block // checked checked : block // unchecked unchecked : block // lock lock : LParen // using using : LParen StatementNode node; mayBeLocalDecl = false; switch (curtok.ID) { case TokenID.LCurly: // block BlockStatement newBlock = new BlockStatement(isUnsafe > 0, curtok); newBlock.IsUnsafe = isUnsafe > 0; node = newBlock; ParseBlock(newBlock); break; case TokenID.Semi: // empty statement node = new StatementNode(curtok); Advance(); // over semi break; case TokenID.If: // If statement node = ParseIf(); break; case TokenID.Switch: // Switch statement node = ParseSwitch(); break; case TokenID.While: // While statement node = ParseWhile(); break; case TokenID.Do: // Do statement node = ParseDo(); break; case TokenID.For: // For statement node = ParseFor(); break; case TokenID.Foreach: // Foreach statement node = ParseForEach(); break; case TokenID.Break: // Break statement node = ParseBreak(); break; case TokenID.Continue: // Continue statement node = ParseContinue(); break; case TokenID.Goto: // Goto statement node = ParseGoto(); break; case TokenID.Return: // Return statement node = ParseReturn(); break; case TokenID.Throw: // Throw statement node = ParseThrow(); break; case TokenID.Try: // Try statement node = ParseTry(); break; case TokenID.Checked: // Checked statement node = ParseChecked(); break; case TokenID.Unchecked: // Unchecked statement node = ParseUnchecked(); break; case TokenID.Lock: // Lock statement node = ParseLock(); break; case TokenID.Using: // Using statement node = ParseUsing(); break; case TokenID.Const: node = null; isLocalConst = true; Advance(); // over const break; case TokenID.StringLiteral: case TokenID.HexLiteral: case TokenID.IntLiteral: case TokenID.UIntLiteral: case TokenID.LongLiteral: case TokenID.ULongLiteral: case TokenID.True: case TokenID.False: case TokenID.Null: case TokenID.LParen: case TokenID.DecimalLiteral: case TokenID.RealLiteral: case TokenID.CharLiteral: case TokenID.PlusPlus: // PreInc statement case TokenID.MinusMinus:// PreDec statement case TokenID.This: case TokenID.Base: case TokenID.New: // creation statement node = new ExpressionStatement(ParseExpression()); AssertAndAdvance(TokenID.Semi); break; case TokenID.Void: // TODO: Special case void case TokenID.Bool: case TokenID.Byte: case TokenID.Char: case TokenID.Decimal: case TokenID.Double: case TokenID.Float: case TokenID.Int: case TokenID.Long: case TokenID.Object: case TokenID.SByte: case TokenID.Short: case TokenID.String: case TokenID.UInt: case TokenID.ULong: case TokenID.UShort: { TypeNode type = new PredefinedTypeNode(curtok.ID, curtok); Advance(); bool mustBeDecl = false; if (curtok.ID == TokenID.Question) { Advance(); type.IsNullableType = true; mustBeDecl = true; } else if (curtok.ID == TokenID.Star) { do { Advance(); type = new TypePointerNode(type); } while (curtok.ID == TokenID.Star); mustBeDecl = true; } if (curtok.ID == TokenID.LBracket) { do { Advance(); // over lbracket int commaCount = 0; while (curtok.ID == TokenID.Comma) { Advance(); commaCount++; } type.RankSpecifiers.Add(commaCount); AssertAndAdvance(TokenID.RBracket); } while (curtok.ID == TokenID.LBracket); mustBeDecl = true; } if (curtok.ID == TokenID.Ident) { node = ParseLocalDeclarationStatement(type); } else if (mustBeDecl) { RecoverFromError(TokenID.Ident); node = new StatementNode(curtok); } else { ExpressionNode expr = ParseSubexpression(1, type); if (!(expr is InvocationExpression)) { ReportError("Statement must be an invocation", expr.RelatedToken); } node = new ExpressionStatement(expr); } AssertAndAdvance(TokenID.Semi); break; } case TokenID.Ident: { if (strings[curtok.Data] == "yield") { node = ParseYieldStatement(); break; } ExpressionNode expr = ParseExpressionOrType(true); if (expr is IdentifierExpression && curtok.ID == TokenID.Colon) { Advance(); // advance over colon LabeledStatement lsnode = new LabeledStatement(curtok); lsnode.Name = (IdentifierExpression)expr; lsnode.Statement = ParseStatement(); node = lsnode; } else { if (expr is TypeNode) node = ParseLocalDeclarationStatement((IType)expr); else node = new ExpressionStatement(expr); AssertAndAdvance(TokenID.Semi); } /* ExpressionNode expr = ParseIdentifierOrKeyword(false, true, false, false); IdentifierExpression idExpr = expr as IdentifierExpression; if(idExpr != null && curtok.ID == TokenID.Colon) { Advance(); // advance over colon LabeledStatement lsnode = new LabeledStatement(curtok); lsnode.Name = idExpr; lsnode.Statement = ParseStatement(); node = lsnode; } else { mayBeLocalDecl = true; if(curtok.ID == TokenID.ColonColon) { Advance(); if(curtok.ID != TokenID.Ident) { RecoverFromError(TokenID.Ident); node = null; break; } expr = new MemberAccessExpression(expr, new IdentifierExpression(strings[curtok.Data], curtok), TokenID.ColonColon); Advance(); // over ident } while(curtok.ID == TokenID.Dot) { Advance(); if(curtok.ID != TokenID.Ident) { RecoverFromError(TokenID.Ident); node = null; break; } expr = new MemberAccessExpression(expr, new IdentifierExpression(strings[curtok.Data], curtok), TokenID.Dot); Advance(); // over ident } if(ParsePossibleTypeParameterNode(false, false, false)) { expr = new TypeNode(expr); ApplyTypeParameters((TypeNode) expr); } if(curtok.ID == TokenID.LBracket) { Advance(); if(curtok.ID == TokenID.Comma || curtok.ID == TokenID.RBracket) { TypeNode typeNode = expr as TypeNode; if(typeNode == null) expr = typeNode = new TypeNode(expr); while(true) { int numCommas = 0; while(curtok.ID == TokenID.Comma) { Advance(); numCommas++; } AssertAndAdvance(TokenID.RBracket); typeNode.RankSpecifiers.Add(numCommas); if(curtok.ID != TokenID.LBracket) break; Advance(); } } else { ExpressionList exprList = ParseExpressionList(); expr = new ElementAccessExpression(expr, exprList); AssertAndAdvance(TokenID.RBracket); } } if(curtok.ID == TokenID.Question) { Advance(); TypeNode typeNode = expr as TypeNode; if(typeNode == null) expr = typeNode = new TypeNode(expr); typeNode.IsNullableType = true; } else { while(curtok.ID == TokenID.Star) { Advance(); expr = new TypePointerNode(expr); } }*/ // expr = ParseSubexpression(PRECEDENCE_PRIMARY, expr); /* exprStack.Push(expr); ParseContinuingPrimary(); expr = exprStack.Pop();*/ /* if((expr is IdentifierExpression || expr is MemberAccessExpression || expr is TypeNode) && (curtok.ID == TokenID.Ident || curtok.ID == TokenID.Star || curtok.ID == TokenID.Question)) { node = ParseLocalDeclarationStatement((IType) expr); } else node = new ExpressionStatement(ParseSubexpression(1, expr)); AssertAndAdvance(TokenID.Semi); }*/ break; } case TokenID.Unsafe: // preprocessor directives node = ParseUnsafeCode(); break; case TokenID.Fixed: // preprocessor directives node = ParseFixedStatement(); break; case TokenID.Star: // dereference variable // introduced because of the mono file test-406.cs //private static uint DoOp2 (uint *u) { // *(u) += 100; // return *u; //} node = new ExpressionStatement(ParseExpression()); AssertAndAdvance(TokenID.Semi); break; case TokenID.SingleComment: case TokenID.MultiComment: case TokenID.DocComment: node = new CommentStatement(curtok, strings[curtok.Data], curtok.ID != TokenID.SingleComment); Advance(); // over comment token break; default: { Console.WriteLine("Unhandled case in statement parsing: \"" + curtok.ID + "\" in line: " + lineCount); // this is almost always an expression ExpressionStatement dnode = new ExpressionStatement(ParseExpression()); node = dnode; if (curtok.ID == TokenID.Semi) { Advance(); } break; } } return node; }
public virtual object VisitTypePointerReference(TypePointerNode typePointerReference, object data) { stackMap.Push(typePointerReference); typePointerReference.Expression.AcceptVisitor(this, data); ; stackMap.Pop(); return null; }