private Expression ParseNew(TokenSet followers){ SourceContext ctx = this.scanner.CurrentSourceContext; Debug.Assert(this.currentToken == Token.New); this.GetNextToken(); TypeNode allocator = null; if (this.currentToken == Token.LeftBracket) { this.GetNextToken(); if (this.currentToken == Token.RightBracket) { return this.ParseNewImplicitlyTypedArray(ctx, followers); } // parse [Delayed] annotation (or allocator) allocator = this.ParseBaseTypeExpression(null, followers|Token.RightBracket, false, false); if (allocator == null){this.SkipTo(followers, Error.None); return null;} this.Skip(Token.RightBracket); } if (this.currentToken == Token.LeftBrace) return this.ParseNewAnonymousTypeInstance(ctx, followers); Expression owner = null; // Allow owner argument for each constructor: "new <ow> ..." if (this.currentToken == Token.LessThan) { this.GetNextToken(); owner = this.ParsePrimaryExpression(followers | Token.GreaterThan); if (this.currentToken == Token.GreaterThan) this.GetNextToken(); } // Make it explicit that the base type stops at "!", which is handled by // the code below. TypeNode t = this.ParseBaseTypeExpression(null, followers|Parser.InfixOperators|Token.LeftBracket|Token.LeftParenthesis|Token.RightParenthesis|Token.LogicalNot, false, false); if (t == null){this.SkipTo(followers, Error.None); return null;} if (this.currentToken == Token.Conditional) { TypeNode type = t; t = new NullableTypeExpression(type); t.SourceContext = type.SourceContext; t.SourceContext.EndPos = this.scanner.endPos; this.GetNextToken(); }else if (this.currentToken == Token.LogicalNot){ TypeNode type = t; t = new NonNullableTypeExpression(type); t.SourceContext = type.SourceContext; t.SourceContext.EndPos = this.scanner.endPos; this.GetNextToken(); }else if (this.currentToken == Token.Multiply){ this.GetNextToken(); t = new PointerTypeExpression(t, t.SourceContext); t.SourceContext.EndPos = this.scanner.endPos; if (!this.inUnsafeCode) this.HandleError(t.SourceContext, Error.UnsafeNeeded); } ctx.EndPos = t.SourceContext.EndPos; // special hack [Delayed] in custom allocator position is used to mark the array as // a delayed construction. This annotation is used in the Definite Assignment analysis. // TypeExpression allocatorExp = allocator as TypeExpression; if (allocatorExp != null) { Identifier allocId = allocatorExp.Expression as Identifier; if (allocId != null && allocId.Name == "Delayed") { t = new RequiredModifierTypeExpression(t, TypeExpressionFor("Microsoft","Contracts","DelayedAttribute")); allocator = null; // not really a custom allocation } } int rank = this.ParseRankSpecifier(false, followers|Token.LeftBrace|Token.LeftBracket|Token.LeftParenthesis|Token.RightParenthesis); SourceContext lbCtx = ctx; while (rank > 0 && this.currentToken == Token.LeftBracket){ lbCtx = this.scanner.CurrentSourceContext; t = new ArrayTypeExpression(t, rank); rank = this.ParseRankSpecifier(false, followers|Token.LeftBrace|Token.LeftBracket); } if (rank > 0){ //new T[] {...} or new T[,] {{..} {...}...}, etc where T can also be an array type ConstructArray consArr = new ConstructArray(); consArr.SourceContext = ctx; consArr.ElementType = consArr.ElementTypeExpression = t; consArr.Rank = rank; if (this.currentToken == Token.LeftBrace) consArr.Initializers = this.ParseArrayInitializer(rank, t, followers); else{ if (Parser.UnaryStart[this.currentToken]) this.HandleError(Error.ExpectedLeftBrace); else this.HandleError(Error.MissingArraySize); while (Parser.UnaryStart[this.currentToken]){ this.ParseExpression(followers|Token.Comma|Token.RightBrace); if (this.currentToken != Token.Comma) break; this.GetNextToken(); } if (this.currentToken == Token.RightBrace) this.GetNextToken(); this.SkipTo(followers); } if (owner != null) { consArr.Owner = owner; } return consArr; } if (rank < 0){ //new T[x] or new T[x,y] etc. possibly followed by an initializer or element type rank specifier ConstructArray consArr = new ConstructArray(); consArr.SourceContext = ctx; consArr.Operands = this.ParseIndexList(followers|Token.LeftBrace|Token.LeftBracket, lbCtx, out consArr.SourceContext.EndPos); rank = consArr.Operands.Count; if (this.currentToken == Token.LeftBrace) consArr.Initializers = this.ParseArrayInitializer(rank, t, followers); else{ int elementRank = this.ParseRankSpecifier(true, followers); tryAgain: if (elementRank > 0) t = this.ParseArrayType(elementRank, t, followers); if (this.currentToken == Token.LeftBrace) consArr.Initializers = this.ParseArrayInitializer(rank, t, followers); else{ if (this.currentToken == Token.LeftBracket){ //new T[x][y] or something like that lbCtx = this.scanner.CurrentSourceContext; this.GetNextToken(); SourceContext sctx = this.scanner.CurrentSourceContext; this.ParseIndexList(followers, lbCtx, out sctx.EndPos); this.HandleError(sctx, Error.InvalidArray); elementRank = 1; goto tryAgain; }else this.SkipTo(followers); } } consArr.ElementType = consArr.ElementTypeExpression = t; consArr.Rank = rank; if (owner != null) { consArr.Owner = owner; } return consArr; } ExpressionList arguments = null; SourceContext lpCtx = this.scanner.CurrentSourceContext; bool sawLeftParenthesis = false; if (this.currentToken == Token.LeftParenthesis){ if (rank == 0 && t is NonNullableTypeExpression) { this.SkipTo(followers, Error.BadNewExpr); return null; } sawLeftParenthesis = true; this.GetNextToken(); arguments = this.ParseArgumentList(followers, lpCtx, out ctx.EndPos); }else if (this.currentToken == Token.LeftBrace){ Expression quant = this.ParseComprehension(followers); arguments = new ExpressionList(quant); }else{ this.SkipTo(followers, Error.BadNewExpr); Construct c = new Construct(); if (t is TypeExpression) c.Constructor = new MemberBinding(null, t, t.SourceContext); c.SourceContext = ctx; return c; } if (sawLeftParenthesis && this.currentToken == Token.LeftBrace){ } Construct cons = new Construct(new MemberBinding(null, t), arguments); cons.SourceContext = ctx; if (owner != null) cons.Owner = owner; return cons; }
private TypeNode ParseTypeExpression(Identifier id, TokenSet followers, bool returnNullIfError, bool AsOrIs, bool Typeof){ TokenSet followersOrTypeOperator = followers|Parser.TypeOperator; TypeNode type = this.ParseBaseTypeExpression(id, followersOrTypeOperator, returnNullIfError, Typeof); if (type == null){ if (!returnNullIfError) this.SkipTo(followers, Error.None); return null; } TypeNode baseType = type; int rank = this.ParseRankSpecifier(returnNullIfError, followersOrTypeOperator); if (rank > 0){ returnNullIfError = false; //No longer ambiguous type = this.ParseArrayType(rank, type, followersOrTypeOperator); }else if (this.currentToken == Token.LeftBracket && returnNullIfError) return null; else if (rank == -1){ this.currentToken = Token.LeftBracket; this.scanner.endPos = type.SourceContext.EndPos; this.GetNextToken(); goto done; } for(;;){ switch(this.currentToken){ case Token.BitwiseAnd: if (returnNullIfError) goto done; this.HandleError(Error.ExpectedIdentifier); //TODO: this matches C#, but a better error would be nice this.GetNextToken(); break; case Token.LeftBracket: returnNullIfError = false; rank = this.ParseRankSpecifier(false, followersOrTypeOperator); if (rank > 0) type = this.ParseArrayType(rank, type, followersOrTypeOperator); break; case Token.Multiply:{ TypeNode t = new PointerTypeExpression(type); t.DeclaringModule = this.module; t.SourceContext = type.SourceContext; t.SourceContext.EndPos = this.scanner.endPos; type = t; this.GetNextToken(); if (!this.inUnsafeCode){ if (!returnNullIfError) this.HandleError(t.SourceContext, Error.UnsafeNeeded); } break;} case Token.LogicalNot:{ TypeNode t = new NonNullableTypeExpression(type); t.SourceContext = type.SourceContext; t.SourceContext.EndPos = this.scanner.endPos; type = t; this.GetNextToken(); break;} case Token.Conditional:{ if (AsOrIs && Parser.NullableTypeNonFollower[PeekToken()]) goto done; TypeNode t = new NullableTypeExpression(type); t.SourceContext = type.SourceContext; t.SourceContext.EndPos = this.scanner.endPos; type = t; this.GetNextToken(); break;} default: goto done; } } done: if (returnNullIfError && !followers[this.currentToken]) return null; this.SkipTo(followers); return type; }