private void ParseProperty(TypeNode parentType, AttributeList attributes, TokenList modifierTokens, SourceContextList modifierContexts, object sctx, TypeNode type, TypeNode interfaceType, Identifier name, TokenSet followers){ SourceContext ctx = (SourceContext)sctx; ctx.EndPos = this.scanner.endPos; bool isIndexer = this.currentToken == Token.This && name.UniqueIdKey == StandardIds.Item.UniqueIdKey; Debug.Assert(this.currentToken == Token.LeftBrace || isIndexer); this.GetNextToken(); ParameterList paramList = null; if (isIndexer){ if (interfaceType == null){ AttributeNode defaultMember = new AttributeNode(); defaultMember.Constructor = new Literal(TypeExpressionFor("System", "Reflection", "DefaultMemberAttribute")); defaultMember.Expressions = new ExpressionList(1); defaultMember.Expressions.Add(new Literal("Item")); if (parentType.Attributes == null) parentType.Attributes = new AttributeList(1); parentType.Attributes.Add(defaultMember); } paramList = this.ParseParameters(Token.RightBracket, followers|Token.LeftBrace); this.Skip(Token.LeftBrace); } Property p = new Property(parentType, attributes, PropertyFlags.None, name, null, null); parentType.Members.Add(p); p.SourceContext = ctx; p.Documentation = this.LastDocComment; p.Type = p.TypeExpression = type; MethodFlags mflags; if (interfaceType != null){ p.ImplementedTypeExpressions = p.ImplementedTypes = new TypeNodeList(interfaceType); mflags = MethodFlags.Private|MethodFlags.HideBySig|MethodFlags.NewSlot|MethodFlags.Final|MethodFlags.Virtual|MethodFlags.SpecialName; for (int i = 0, n = modifierContexts == null ? 0 : modifierContexts.Length; i < n; i++) { if (modifierTokens[i] == Token.Extern) mflags |= MethodFlags.PInvokeImpl; else if (modifierTokens[i] == Token.Unsafe) { if (!this.allowUnsafeCode) { this.allowUnsafeCode = true; this.HandleError(modifierContexts[i], Error.IllegalUnsafe); } this.inUnsafeCode = true; } else this.HandleError(modifierContexts[i], Error.InvalidModifier, modifierContexts[i].SourceText); } }else mflags = this.GetMethodFlags(modifierTokens, modifierContexts, parentType, p)|MethodFlags.SpecialName; if ((mflags & MethodFlags.Static) != 0 && parentType is Interface){ this.HandleError(name.SourceContext, Error.InvalidModifier, "static"); mflags &= ~MethodFlags.Static; mflags |= MethodFlags.Abstract; } TokenSet followersOrRightBrace = followers|Token.RightBrace; bool accessorModifiersAlreadySpecified = false; MethodFlags accessorFlags = mflags; while (Parser.GetOrLeftBracketOrSetOrModifier[this.currentToken]){ SourceContext sc = this.scanner.CurrentSourceContext; AttributeList accessorAttrs = this.ParseAttributes(null, followers|Token.Get|Token.Set|Token.LeftBrace); switch (this.currentToken){ case Token.Get:{ if (p.Getter != null) this.HandleError(Error.DuplicateAccessor); SourceContext scntx = this.scanner.CurrentSourceContext; this.GetNextToken(); Method m = new Method(parentType, accessorAttrs, new Identifier("get_"+name.ToString()), paramList, type, null); m.SourceContext = sc; m.ReturnTypeExpression = type; m.Name.SourceContext = scntx; if ((accessorFlags & MethodFlags.Static) == 0) m.CallingConvention = CallingConventionFlags.HasThis; parentType.Members.Add(m); m.Flags = accessorFlags|MethodFlags.HideBySig; if (interfaceType != null) m.ImplementedTypeExpressions = m.ImplementedTypes = new TypeNodeList(interfaceType); bool swallowedSemicolonAlready = false; bool bodyAllowed = true; if (this.currentToken == Token.Semicolon){ m.SourceContext.EndPos = this.scanner.endPos; this.GetNextToken(); bodyAllowed = false; swallowedSemicolonAlready = true; } this.ParseMethodContract(m, followers|Token.LeftBrace|Token.Semicolon, ref swallowedSemicolonAlready); if (bodyAllowed) m.Body = this.ParseBody(m, sc, followersOrRightBrace|Token.Set, swallowedSemicolonAlready); else if (!swallowedSemicolonAlready) this.SkipSemiColon(followersOrRightBrace|Token.Set); p.Getter = m; m.DeclaringMember = p; accessorFlags = mflags; break;} case Token.Set:{ if (p.Setter != null) this.HandleError(Error.DuplicateAccessor); SourceContext scntx = this.scanner.CurrentSourceContext; this.GetNextToken(); ParameterList parList = new ParameterList(); if (paramList != null) for (int i = 0, n = paramList.Count; i < n; i++) parList.Add((Parameter)paramList[i].Clone()); parList.Add(new Parameter(null, ParameterFlags.None, Identifier.For("value"), type, null, null)); Method m = new Method(parentType, accessorAttrs, new Identifier("set_"+name.ToString()), parList, this.TypeExpressionFor(Token.Void), null); m.SourceContext = sc; m.Name.SourceContext = scntx; if ((accessorFlags & MethodFlags.Static) == 0) m.CallingConvention = CallingConventionFlags.HasThis; parentType.Members.Add(m); m.Flags = accessorFlags|MethodFlags.HideBySig; if (interfaceType != null) m.ImplementedTypeExpressions = m.ImplementedTypes = new TypeNodeList(interfaceType); bool swallowedSemicolonAlready = false; bool bodyAllowed = true; if (this.currentToken == Token.Semicolon) { m.SourceContext.EndPos = this.scanner.endPos; this.GetNextToken(); bodyAllowed = false; swallowedSemicolonAlready = true; } this.ParseMethodContract(m, followers|Token.LeftBrace|Token.Semicolon, ref swallowedSemicolonAlready); if (bodyAllowed) m.Body = this.ParseBody(m, sc, followersOrRightBrace|Token.Get, swallowedSemicolonAlready); else if (!swallowedSemicolonAlready) this.SkipSemiColon(followersOrRightBrace|Token.Get); p.Setter = m; m.DeclaringMember = p; accessorFlags = mflags; break;} case Token.Protected: case Token.Internal: case Token.Private: if (parentType is Interface || interfaceType != null || accessorModifiersAlreadySpecified) goto case Token.New; accessorFlags = this.ParseAccessorModifiers(mflags); accessorModifiersAlreadySpecified = true; break; case Token.Public: case Token.New: case Token.Abstract: case Token.Sealed: case Token.Static: case Token.Readonly: case Token.Volatile: case Token.Virtual: case Token.Override: case Token.Extern: case Token.Unsafe: this.HandleError(Error.NoModifiersOnAccessor); this.GetNextToken(); break; default: this.SkipTo(followersOrRightBrace, Error.GetOrSetExpected); break; } } p.SourceContext.EndPos = this.scanner.endPos; Error e = Error.GetOrSetExpected; if (p.Getter == null && p.Setter == null) p.Parameters = paramList; if (p.Getter != null && p.Setter != null) e = Error.ExpectedRightBrace; if ((p.Getter == null || p.Setter == null) && this.sink != null && this.currentToken == Token.Identifier){ p.SourceContext.EndPos = this.scanner.startPos-1; KeywordCompletionList keywords; if (p.Getter != null) keywords = new KeywordCompletionList(this.scanner.GetIdentifier(), new KeywordCompletion("set")); else if (p.Setter != null) keywords = new KeywordCompletionList(this.scanner.GetIdentifier(), new KeywordCompletion("get")); else keywords = new KeywordCompletionList(this.scanner.GetIdentifier(), new KeywordCompletion("get"), new KeywordCompletion("set")); parentType.Members.Add(keywords); this.GetNextToken(); this.SkipTo(followers); return; } this.ParseBracket(ctx, Token.RightBrace, followers, e); }
private void ParseEvent(TypeNode parentType, AttributeList attributes, TokenList modifierTokens, SourceContextList modifierContexts, object sctx, TokenSet followers){ Debug.Assert(this.currentToken == Token.Event); this.GetNextToken(); Event e = new Event(parentType, attributes, EventFlags.None, null, null, null, null, null); e.DeclaringType = parentType; e.Documentation = this.LastDocComment; TypeNode t = this.ParseTypeExpression(Identifier.Empty, followers|Parser.IdentifierOrNonReservedKeyword); //REVIEW: allow events with anonymous delegate type? e.HandlerType = e.HandlerTypeExpression = t; TypeExpression interfaceType = null; Identifier id = this.scanner.GetIdentifier(); this.SkipIdentifierOrNonReservedKeyword(); TypeNodeList templateArguments = null; int endPos = 0, arity = 0; while (this.currentToken == Token.Dot || this.currentToken == Token.LessThan) { if (interfaceType == null && this.ExplicitInterfaceImplementationIsAllowable(parentType, id)) { for (int i = 0, n = modifierContexts == null ? 0 : modifierContexts.Length; i < n; i++){ this.HandleError(modifierContexts[i], Error.InvalidModifier, modifierContexts[i].SourceText); modifierTokens = new TokenList(0); } } TypeExpression intfExpr = interfaceType; if (intfExpr == null) { intfExpr = new TypeExpression(id, id.SourceContext); } else if( templateArguments == null) { SourceContext ctx = intfExpr.Expression.SourceContext; ctx.EndPos = id.SourceContext.EndPos; intfExpr.Expression = new QualifiedIdentifier(intfExpr.Expression, id, ctx); } if (templateArguments != null) { intfExpr.TemplateArguments = templateArguments; intfExpr.SourceContext.EndPos = endPos; } if (this.currentToken == Token.LessThan) { templateArguments = this.ParseTypeArguments(true, false, followers | Token.Dot | Token.LeftParenthesis | Token.LeftBrace, out endPos, out arity); } else { // Dot templateArguments = null; this.GetNextToken(); id = this.scanner.GetIdentifier(); this.SkipIdentifierOrNonReservedKeyword(); if (intfExpr == null) id.SourceContext.Document = null; } interfaceType = intfExpr; } e.Name = id; MethodFlags mflags = this.GetMethodFlags(modifierTokens, modifierContexts, parentType, e); if ((mflags & MethodFlags.Static) != 0 && parentType is Interface){ this.HandleError(id.SourceContext, Error.InvalidModifier, "static"); mflags &= ~MethodFlags.Static; mflags |= MethodFlags.Abstract; } e.HandlerFlags = mflags|MethodFlags.SpecialName; bool hasAccessors = this.currentToken == Token.LeftBrace || interfaceType != null; if (hasAccessors){ if (interfaceType != null){ e.ImplementedTypeExpressions = e.ImplementedTypes = new TypeNodeList(interfaceType); if (this.currentToken != Token.LeftBrace){ this.HandleError(Error.ExplicitEventFieldImpl); hasAccessors = false; goto nextDeclarator; } } this.Skip(Token.LeftBrace); TokenSet followersOrRightBrace = followers|Token.RightBrace; bool alreadyGivenAddOrRemoveExpectedError = false; bool alreadyComplainedAboutAccessors = false; for(;;){ SourceContext sc = this.scanner.CurrentSourceContext; AttributeList accessorAttrs = this.ParseAttributes(null, followers|Parser.AddOrRemoveOrModifier|Token.LeftBrace); switch (this.currentToken){ case Token.Add: if (parentType is Interface && !alreadyComplainedAboutAccessors){ this.HandleError(Error.EventPropertyInInterface, parentType.FullName+"."+id); alreadyComplainedAboutAccessors = true; }else if (e.HandlerAdder != null) this.HandleError(Error.DuplicateAccessor); SourceContext scntx = this.scanner.CurrentSourceContext; this.GetNextToken(); ParameterList parList = new ParameterList(); parList.Add(new Parameter(null, ParameterFlags.None, StandardIds.Value, t, null, null)); Method m = new Method(parentType, accessorAttrs, new Identifier("add_"+id.ToString()), parList, this.TypeExpressionFor(Token.Void), null); m.HidesBaseClassMember = e.HidesBaseClassMember; m.OverridesBaseClassMember = e.OverridesBaseClassMember; m.Name.SourceContext = scntx; if ((mflags & MethodFlags.Static) == 0) m.CallingConvention = CallingConventionFlags.HasThis; m.Flags = mflags|MethodFlags.HideBySig|MethodFlags.SpecialName; if (interfaceType != null){ m.Flags = MethodFlags.Private|MethodFlags.HideBySig|MethodFlags.NewSlot|MethodFlags.Final|MethodFlags.Virtual|MethodFlags.SpecialName; m.ImplementedTypeExpressions = m.ImplementedTypes = new TypeNodeList(interfaceType); } if (this.currentToken != Token.LeftBrace){ this.SkipTo(followersOrRightBrace|Token.Remove, Error.AddRemoveMustHaveBody); alreadyGivenAddOrRemoveExpectedError = true; }else m.Body = this.ParseBody(m, sc, followersOrRightBrace|Token.Remove); if (!(parentType is Interface)){ e.HandlerAdder = m; m.DeclaringMember = e; parentType.Members.Add(m); } continue; case Token.Remove: if (parentType is Interface && !alreadyComplainedAboutAccessors){ this.HandleError(Error.EventPropertyInInterface, parentType.FullName+"."+id); alreadyComplainedAboutAccessors = true; }else if (e.HandlerRemover != null) this.HandleError(Error.DuplicateAccessor); scntx = this.scanner.CurrentSourceContext; this.GetNextToken(); parList = new ParameterList(); parList.Add(new Parameter(null, ParameterFlags.None, StandardIds.Value, t, null, null)); m = new Method(parentType, accessorAttrs, new Identifier("remove_"+id.ToString()), parList, this.TypeExpressionFor(Token.Void), null); m.HidesBaseClassMember = e.HidesBaseClassMember; m.OverridesBaseClassMember = e.OverridesBaseClassMember; m.Name.SourceContext = scntx; if ((mflags & MethodFlags.Static) == 0) m.CallingConvention = CallingConventionFlags.HasThis; m.Flags = mflags|MethodFlags.HideBySig|MethodFlags.SpecialName; if (interfaceType != null){ m.Flags = MethodFlags.Private|MethodFlags.HideBySig|MethodFlags.NewSlot|MethodFlags.Final|MethodFlags.Virtual|MethodFlags.SpecialName; m.ImplementedTypeExpressions = m.ImplementedTypes = new TypeNodeList(interfaceType); } if (this.currentToken != Token.LeftBrace){ this.SkipTo(followersOrRightBrace|Token.Add, Error.AddRemoveMustHaveBody); alreadyGivenAddOrRemoveExpectedError = true; }else m.Body = this.ParseBody(m, sc, followersOrRightBrace|Token.Add); if (!(parentType is Interface)){ e.HandlerRemover = m; m.DeclaringMember = e; parentType.Members.Add(m); } continue; case Token.New: case Token.Public: case Token.Protected: case Token.Internal: case Token.Private: case Token.Abstract: case Token.Sealed: case Token.Static: case Token.Readonly: case Token.Volatile: case Token.Virtual: case Token.Override: case Token.Extern: case Token.Unsafe: this.HandleError(Error.NoModifiersOnAccessor); this.GetNextToken(); break; default: if ((e.HandlerAdder == null || e.HandlerRemover == null) && this.sink != null && this.currentToken == Token.Identifier && this.scanner.endPos == this.scanner.maxPos){ e.SourceContext.EndPos = this.scanner.startPos; KeywordCompletionList keywords; if (e.HandlerAdder != null) keywords = new KeywordCompletionList(this.scanner.GetIdentifier(), new KeywordCompletion("remove")); else if (e.HandlerRemover != null) keywords = new KeywordCompletionList(this.scanner.GetIdentifier(), new KeywordCompletion("add")); else keywords = new KeywordCompletionList(this.scanner.GetIdentifier(), new KeywordCompletion("add"), new KeywordCompletion("remove")); parentType.Members.Add(keywords); this.GetNextToken(); } if (!alreadyGivenAddOrRemoveExpectedError && !alreadyComplainedAboutAccessors && (e.HandlerAdder == null || e.HandlerRemover == null)) { if (this.currentToken == Token.RightBrace) this.HandleError(id.SourceContext, Error.EventNeedsBothAccessors, parentType.FullName+"."+id.Name); else this.HandleError(Error.AddOrRemoveExpected); alreadyGivenAddOrRemoveExpectedError = true; if (!(Parser.EndOfFile|Token.LeftBrace|Token.RightBrace)[this.currentToken]) this.GetNextToken(); this.SkipTo(followersOrRightBrace|Token.LeftBrace, Error.None); if (this.currentToken == Token.LeftBrace){ this.ParseBlock(followersOrRightBrace|Token.Add|Token.Remove); continue; } } break; } break; } this.Skip(Token.RightBrace); //TODO: brace matching } nextDeclarator: e.Name = id; e.SourceContext = (SourceContext)sctx; e.SourceContext.EndPos = this.scanner.endPos; parentType.Members.Add(e); if (!hasAccessors){ switch(this.currentToken){ case Token.Assign: this.GetNextToken(); e.InitialHandler = this.ParseExpression(followers|Token.Semicolon); if (parentType is Interface && e.InitialHandler != null){ this.HandleError(e.InitialHandler.SourceContext, Error.InterfaceEventInitializer, parentType.FullName+"."+id); e.InitialHandler = null; } if (this.currentToken == Token.Comma) goto case Token.Comma; else goto default; case Token.Comma: this.GetNextToken(); id = this.scanner.GetIdentifier(); this.SkipIdentifierOrNonReservedKeyword(); //REVIEW: allow interface name? e = new Event(parentType, attributes, (EventFlags)0, null, null, null, null, null); e.HandlerFlags = mflags; e.HandlerType = e.HandlerTypeExpression = t; goto nextDeclarator; default: this.Skip(Token.Semicolon); break; } } }