private Expression ParsePrimaryExpression(TokenSet followers){ Expression expression = null; SourceContext sctx = this.scanner.CurrentSourceContext; switch(this.currentToken){ case Token.ArgList: this.GetNextToken(); expression = new ArglistExpression(sctx); break; case Token.Delegate:{ this.GetNextToken(); ParameterList parameters = null; if (this.currentToken == Token.LeftParenthesis) parameters = this.ParseParameters(Token.RightParenthesis, followers|Token.LeftBrace); Block block = null; if (this.currentToken == Token.LeftBrace) block = this.ParseBlock(this.scanner.CurrentSourceContext, followers); else this.SkipTo(followers, Error.ExpectedLeftBrace); sctx.EndPos = this.scanner.endPos; return new AnonymousNestedDelegate(parameters, block, sctx);} case Token.New: expression = this.ParseNew(followers|Token.Dot|Token.LeftBracket|Token.Arrow); break; case Token.Identifier: expression = this.scanner.GetIdentifier(); if (this.sink != null) { this.sink.StartName((Identifier)expression); } this.GetNextToken(); if (this.currentToken == Token.DoubleColon){ this.GetNextToken(); Identifier id = this.scanner.GetIdentifier(); id.Prefix = (Identifier)expression; id.SourceContext.StartPos = expression.SourceContext.StartPos; expression = id; if (this.currentToken != Token.EndOfFile) this.GetNextToken(); }else if (this.currentToken == Token.Lambda){ Parameter par = new Parameter((Identifier)expression, null); par.SourceContext = expression.SourceContext; return this.ParseLambdaExpression(par.SourceContext, new ParameterList(par), followers); } break; case Token.Null: expression = new Literal(null, null, sctx); this.GetNextToken(); break; case Token.True: expression = new Literal(true, null, sctx); this.GetNextToken(); break; case Token.False: expression = new Literal(false, null, sctx); this.GetNextToken(); break; case Token.CharLiteral: expression = new Literal(this.scanner.charLiteralValue, null, sctx); this.GetNextToken(); break; case Token.HexLiteral: expression = this.ParseHexLiteral(); break; case Token.IntegerLiteral: expression = this.ParseIntegerLiteral(); break; case Token.RealLiteral: expression = this.ParseRealLiteral(); break; case Token.StringLiteral: expression = this.scanner.GetStringLiteral(); this.GetNextToken(); break; case Token.This: expression = new This(sctx, false); if (this.sink != null) { this.sink.StartName(expression); } this.GetNextToken(); if (this.currentToken == Token.LeftParenthesis && (this.inInstanceConstructor==BaseOrThisCallKind.None || this.inInstanceConstructor==BaseOrThisCallKind.InCtorBodyThisSeen)){ QualifiedIdentifier thisCons = new QualifiedIdentifier(expression, StandardIds.Ctor, this.scanner.CurrentSourceContext); MethodCall thisConstructorCall = new MethodCall(thisCons, null, NodeType.Call); thisConstructorCall.SourceContext = sctx; SourceContext lpCtx = this.scanner.CurrentSourceContext; this.Skip(Token.LeftParenthesis); thisConstructorCall.Operands = this.ParseArgumentList(followers|Token.LeftBrace|Token.Semicolon, lpCtx, out thisConstructorCall.SourceContext.EndPos); expression = thisConstructorCall; this.inInstanceConstructor=BaseOrThisCallKind.InCtorBodyThisSeen; goto done; } break; case Token.Base: Base ba = new Base(sctx, false); expression = ba; if (this.sink != null) { this.sink.StartName(expression); } this.GetNextToken(); if (this.currentToken == Token.Semicolon && (this.inInstanceConstructor == BaseOrThisCallKind.ColonThisOrBaseSeen || this.inInstanceConstructor == BaseOrThisCallKind.None)) { // When there are non-null fields, then the base ctor call can happen only after they are // initialized. // In Spec#, we allow a base ctor call in the body of the ctor. But if someone is using // the C# comment convention, then they cannot do that. // So allow "base;" as a marker to indicate where the base ctor call should happen. // There may be an explicit "colon base call" or it may be implicit. // // Just leave expression as a bare "Base" node; later pipeline stages will all have // to ignore it. Mark the current ctor as having (at least) one of these bad boys // in it. ba.UsedAsMarker = true; this.currentCtor.ContainsBaseMarkerBecauseOfNonNullFields = true; goto done; } if (this.currentToken == Token.LeftParenthesis && (this.inInstanceConstructor==BaseOrThisCallKind.None || this.inInstanceConstructor==BaseOrThisCallKind.InCtorBodyBaseSeen)){ QualifiedIdentifier supCons = new QualifiedIdentifier(expression, StandardIds.Ctor, this.scanner.CurrentSourceContext); MethodCall superConstructorCall = new MethodCall(supCons, null, NodeType.Call); superConstructorCall.SourceContext = sctx; SourceContext lpCtx = this.scanner.CurrentSourceContext; this.Skip(Token.LeftParenthesis); superConstructorCall.Operands = this.ParseArgumentList(followers|Token.LeftBrace|Token.Semicolon, lpCtx, out superConstructorCall.SourceContext.EndPos); expression = superConstructorCall; this.inInstanceConstructor=BaseOrThisCallKind.InCtorBodyBaseSeen; goto done; } break; case Token.Typeof: case Token.Sizeof: case Token.Default:{ //if (this.currentToken == Token.Sizeof && !this.inUnsafeCode) //this.HandleError(Error.SizeofUnsafe); UnaryExpression uex = new UnaryExpression(null, this.currentToken == Token.Typeof ? NodeType.Typeof : this.currentToken == Token.Sizeof ? NodeType.Sizeof : NodeType.DefaultValue); uex.SourceContext = sctx; this.GetNextToken(); this.Skip(Token.LeftParenthesis); TypeNode t = null; if (this.currentToken == Token.Void && uex.NodeType == NodeType.Typeof){ t = this.TypeExpressionFor(Token.Void); this.GetNextToken(); }else t = this.ParseTypeExpression(null, followers|Token.RightParenthesis, false, false, uex.NodeType == NodeType.Typeof); if (t == null){this.SkipTo(followers); return null;} uex.Operand = new MemberBinding(null, t, t.SourceContext, null); uex.Operand.SourceContext = t.SourceContext; uex.SourceContext.EndPos = this.scanner.endPos; this.Skip(Token.RightParenthesis); expression = uex; break;} case Token.Stackalloc:{ this.GetNextToken(); TypeNode elementType = this.ParseBaseTypeExpression(null, followers|Token.LeftBracket, false, false); if (elementType == null){this.SkipTo(followers); return null;} Token openingDelimiter = this.currentToken; if (this.currentToken != Token.LeftBracket){ this.HandleError(Error.BadStackAllocExpr); if (this.currentToken == Token.LeftParenthesis) this.GetNextToken(); }else this.GetNextToken(); Expression numElements = this.ParseExpression(followers|Token.RightBracket|Token.RightParenthesis); sctx.EndPos = this.scanner.endPos; if (this.currentToken == Token.RightParenthesis && openingDelimiter == Token.LeftParenthesis) this.GetNextToken(); else this.Skip(Token.RightBracket); this.SkipTo(followers); return new StackAlloc(elementType, numElements, sctx);} case Token.Checked: case Token.Unchecked: //TODO: use NodeType.SkipCheck and NodeType.EnforceCheck Block b = new Block(new StatementList(1), this.currentToken == Token.Checked, this.currentToken == Token.Unchecked, this.inUnsafeCode); b.SourceContext = sctx; this.GetNextToken(); this.Skip(Token.LeftParenthesis); b.Statements.Add(new ExpressionStatement(this.ParseExpression(followers|Token.RightParenthesis))); this.Skip(Token.RightParenthesis); expression = new BlockExpression(b); expression.SourceContext = b.SourceContext; break; case Token.RefType:{ this.GetNextToken(); this.Skip(Token.LeftParenthesis); Expression e = this.ParseExpression(followers|Token.RightParenthesis); this.Skip(Token.RightParenthesis); expression = new RefTypeExpression(e, sctx); break; } case Token.RefValue:{ this.GetNextToken(); this.Skip(Token.LeftParenthesis); Expression e = this.ParseExpression(followers|Token.Comma); this.Skip(Token.Comma); TypeNode te = this.ParseTypeOrFunctionTypeExpression(followers|Token.RightParenthesis, false, true); Expression operand2 = new MemberBinding(null, te); if (te is TypeExpression) operand2.SourceContext = te.SourceContext; else operand2.SourceContext = sctx; this.Skip(Token.RightParenthesis); expression = new RefValueExpression(e, operand2, sctx); break; } case Token.Bool: case Token.Decimal: case Token.Sbyte: case Token.Byte: case Token.Short: case Token.Ushort: case Token.Int: case Token.Uint: case Token.Long: case Token.Ulong: case Token.Char: case Token.Float: case Token.Double: case Token.Object: case Token.String: MemberBinding mb = new MemberBinding(null, this.TypeExpressionFor(this.currentToken), sctx); this.GetNextToken(); expression = this.ParseIndexerCallOrSelector(mb, followers); goto done; case Token.LeftParenthesis: expression = this.ParseParenthesizedExpression(followers|Token.Dot|Token.LeftBracket|Token.Arrow, true); break; default: if (Parser.IdentifierOrNonReservedKeyword[this.currentToken]) goto case Token.Identifier; if (Parser.InfixOperators[this.currentToken]){ this.HandleError(Error.InvalidExprTerm, this.scanner.GetTokenSource()); this.GetNextToken(); }else this.SkipTo(followers|Parser.PrimaryStart, Error.InvalidExprTerm, this.scanner.GetTokenSource()); if (Parser.PrimaryStart[this.currentToken]) return this.ParsePrimaryExpression(followers); goto done; } if (expression is Base && this.currentToken != Token.Dot && this.currentToken != Token.LeftBracket){ this.HandleError(expression.SourceContext, Error.BaseIllegal); expression = null; } expression = this.ParseIndexerCallOrSelector(expression, followers|Token.AddOne|Token.SubtractOne); for(;;){ switch(this.currentToken){ case Token.AddOne: case Token.SubtractOne: SourceContext ctx = expression.SourceContext; ctx.EndPos = this.scanner.endPos; PostfixExpression pex = new PostfixExpression(expression, Parser.ConvertToBinaryNodeType(this.currentToken), ctx); this.GetNextToken(); expression = pex; break; case Token.Dot: expression = this.ParseIndexerCallOrSelector(expression, followers|Token.AddOne|Token.SubtractOne); break; default: goto done; } } done: this.SkipTo(followers); return expression; }
private void ParseConstructor(TypeNode parentType, AttributeList attributes, TokenList modifierTokens, SourceContextList modifierContexts, object sctx, SourceContext idCtx, TokenSet followers){ InstanceInitializer c = new InstanceInitializer(parentType, attributes, null, null, this.TypeExpressionFor(Token.Void)); this.currentCtor = c; c.Name = new Identifier(".ctor", idCtx); MethodFlags flags = this.GetMethodFlags(modifierTokens, modifierContexts, parentType, c); if ((flags & MethodFlags.Static) != 0){ this.currentCtor = null; // Can you call "base" in a static ctor? this.ParseStaticConstructor(parentType, attributes, modifierTokens, modifierContexts, flags, sctx, idCtx, followers); return; } parentType.Members.Add(c); c.Flags |= flags|MethodFlags.HideBySig; c.Parameters = this.ParseParameters(Token.RightParenthesis, followers|Token.LeftBrace|Token.Semicolon|Token.Colon|Parser.ContractStart|Token.Where); c.HasCompilerGeneratedSignature = false; c.Documentation = this.LastDocComment; QualifiedIdentifier supCons = new QualifiedIdentifier(new Base(), StandardIds.Ctor, this.scanner.CurrentSourceContext); MethodCall superConstructorCall = new MethodCall(supCons, null, NodeType.Call); superConstructorCall.SourceContext = this.scanner.CurrentSourceContext; StatementList slist = new StatementList(); Block body = new Block(slist, this.insideCheckedBlock, this.insideUncheckedBlock, this.inUnsafeCode); body.SourceContext = this.scanner.CurrentSourceContext; Block iblock = new Block(new StatementList(), this.insideCheckedBlock, this.insideUncheckedBlock, this.inUnsafeCode); if (this.currentToken == Token.Colon){ this.GetNextToken(); bool savedParsingStatement = this.parsingStatement; this.parsingStatement = true; superConstructorCall.SourceContext = this.scanner.CurrentSourceContext; supCons.SourceContext = this.scanner.CurrentSourceContext; bool init = false; this.inInstanceConstructor = BaseOrThisCallKind.ColonThisOrBaseSeen; if (this.currentToken == Token.This){ if (this.sink != null) this.sink.StartName(new Identifier(".ctor", this.scanner.CurrentSourceContext)); supCons.Qualifier = new This(this.scanner.CurrentSourceContext, true); this.GetNextToken(); }else if (this.currentToken == Token.Base){ if (parentType.IsValueType) this.HandleError(Error.StructWithBaseConstructorCall, new ErrorHandler(this.errors).GetMemberSignature(c)); else if (this.sink != null) this.sink.StartName(new Identifier(".ctor", this.scanner.CurrentSourceContext)); supCons.Qualifier = new Base(this.scanner.CurrentSourceContext, true); this.GetNextToken(); }else{ if (!init) this.SkipTo(followers|Token.LeftBrace|Token.Semicolon|Parser.ContractStart|Token.Where, Error.ThisOrBaseExpected); if (this.currentToken != Token.EndOfFile) this.parsingStatement = savedParsingStatement; goto parseBody; } SourceContext lpCtx = this.scanner.CurrentSourceContext; this.Skip(Token.LeftParenthesis); superConstructorCall.Operands = this.ParseArgumentList(followers|Token.LeftBrace|Token.Semicolon|Parser.ContractStart|Token.Where, lpCtx, out superConstructorCall.SourceContext.EndPos); if (this.currentToken != Token.EndOfFile) this.parsingStatement = savedParsingStatement; } else { // no colon ==> no "base" or "this" before body of ctor if (! parentType.IsValueType) this.inInstanceConstructor = BaseOrThisCallKind.None; } parseBody: superConstructorCall.SourceContext.EndPos = this.scanner.endPos; supCons.SourceContext.EndPos = this.scanner.endPos; bool swallowedSemicolonAlready = false; this.ParseMethodContract(c, followers|Token.LeftBrace|Token.Semicolon, ref swallowedSemicolonAlready); Block b; if (this.parsingContractAssembly) b = this.ParseBody(c, sctx, followers, swallowedSemicolonAlready); // only allow semicolon body in contract assemblies else b = this.ParseBody(c, sctx, followers); slist.Add(iblock); c.IsDeferringConstructor = supCons.Qualifier is This || this.inInstanceConstructor == BaseOrThisCallKind.InCtorBodyThisSeen; if (!c.IsDeferringConstructor){ slist.Add(new FieldInitializerBlock(parentType,false)); } Block baseOrDeferringCallBlock = new Block(new StatementList(1)); c.BaseOrDefferingCallBlock = baseOrDeferringCallBlock; slist.Add(baseOrDeferringCallBlock); if (this.inInstanceConstructor == BaseOrThisCallKind.None || this.inInstanceConstructor == BaseOrThisCallKind.ColonThisOrBaseSeen){ if (!(parentType.IsValueType || this.TypeIsSystemObject(parentType)) || supCons.Qualifier is This) baseOrDeferringCallBlock.Statements.Add(new ExpressionStatement(superConstructorCall, superConstructorCall.SourceContext)); } if (b != null){ slist.Add(b); body.SourceContext.EndPos = b.SourceContext.EndPos; if ((c.Flags & MethodFlags.PInvokeImpl) != 0 && b.Statements != null && b.Statements.Count > 0) body = null; else if (this.omitBodies) b.Statements = null; }else if ((c.Flags & MethodFlags.PInvokeImpl) != 0) body = null; c.Body = body; this.inInstanceConstructor = BaseOrThisCallKind.Disallowed; this.currentCtor = null; }