void FixCtors( ISemanticResolver s, ICLRtypeProvider provider ) { // Add default ctor bool fFoundCtor = m_symbol.HasMethodHeader(Name); // Note that structs don't have a default ctor, but can have other ctors // But add a default ctor for classes if we don't have one. if (!fFoundCtor && IsClass) { CtorChainStatement stmtChain = new CtorChainStatement(); Modifiers mods = new Modifiers(); mods.SetPublic(); MethodDecl mdecl = new MethodDecl( new Identifier(Name, this.Location), null, null, new BlockStatement(new LocalVarDecl[0], new Statement[] { stmtChain }), //new AST.Modifiers(AST.Modifiers.EFlags.Public) mods ); stmtChain.FinishInit(mdecl); mdecl.ResolveMember(m_symbol,s, null); mdecl.Symbol.SetInfo(provider); // Add to the end of the m_alMethods array so that we get codegen'ed! AddMethodToList(mdecl); Debug.Assert(m_symbol.HasMethodHeader(Name)); } // @todo - perhaps we could just make the static initializer a static-ctor.. // If we don't have a static ctor, but we do have static data, then add // a static ctor if (m_nodeStaticInit != null) { bool fFoundStaticCtor = false; foreach(MethodDecl m in m_alMethods) { if (m.Mods.IsStatic && m.IsCtor) { fFoundStaticCtor = true; break; } } if (!fFoundStaticCtor) { Modifiers mods = new Modifiers(); mods.SetStatic(); mods.SetPublic(); MethodDecl mdecl2 = new MethodDecl( new Identifier(Name, this.Location), null, null, new BlockStatement(null, new Statement[]{}), //new Modifiers(AST.Modifiers.EFlags.Static | Modifiers.EFlags.Public) mods ); mdecl2.ResolveMember(m_symbol, s, null); mdecl2.Symbol.SetInfo(provider); AddMethodToList(mdecl2); } } // end check static ctor } // fix ctors
//----------------------------------------------------------------------------- // Do a partial parse of the method decl (includes ctor), // Pass in the parameters that we've already parsed, which is everything // before the first '('. // // ** Rules ** // methoddecl -> attrs type id '(' paramlist ')' '{' statementlist '}' // methoddecl -> attrs type id '(' paramlist ')' ';' // if abstract //----------------------------------------------------------------------------- protected MethodDecl PartialParseMethodDecl( Modifiers mods, TypeSig typeReturn, Identifier stMemberName, Genre genre // applies additional restrictions ) { // We should have already parsed the 'attrs type id'. So continue with param list ParamVarDecl [] arParams = ParseParamList(); // Structs can't define a default ctor if ((genre == Genre.cStruct) && (typeReturn == null) && (arParams.Length == 0)) { ThrowError(E_NoDefaultCtorForStructs(m_lexer.PeekNextToken().Location)); } CtorChainStatement chain = null; // If this is a constructor, then we can chain it // ctordecl -> mods type id '(' param_list ')' ':' (this|base) '(' param_list ')' '{' statementlist '}' // ctor can't be abstract / virtual. Can be static if (typeReturn == null) { Token t = m_lexer.PeekNextToken(); if (genre == Genre.cInterface) { ThrowError(E_NoCtorOnInterface(t.Location)); } if (t.TokenType == Token.Type.cColon) { ConsumeNextToken(); // Currently, 'base' & 'this' are just identifiers, not specific tokens Identifier id = this.ReadExpectedIdentifier(); Exp [] arParams2 = ParseExpList(); CtorChainStatement.ETarget eTarget = (CtorChainStatement.ETarget) (-1); if (id.Text == "this") eTarget = CtorChainStatement.ETarget.cThis; else if (id.Text == "base") { if (genre == Genre.cStruct) { ThrowError(E_NoBaseChainForStructs(id.Location)); } eTarget = CtorChainStatement.ETarget.cBase; } else { ThrowError(E_BadCtorChain(id)); } chain = new CtorChainStatement(eTarget, arParams2); } else { // If no explicit ctor chain, then we still have an implicit "base ()" // (except for static ctors, which can't be chained) if (!mods.IsStatic && (genre == Genre.cClass)) { chain = new CtorChainStatement(); } } // Static ctors can't be chained if (chain != null) { if (mods.IsStatic) { ThrowError(E_NoChainForStaticCtor(stMemberName.Location)); } } } // Parse body BlockStatement block = null; if (mods.IsAbstract) { // For abstract methods, no body. Just end with a ';' ReadExpectedToken(Token.Type.cSemi); } else { // Read method body. This will include the '{' ... '}' block = ParseStatementBlock(); } if (typeReturn == null) { if (mods.IsAbstract | mods.IsVirtual | (block == null)) { ThrowError(E_NoAbstractCtor(stMemberName)); } } // Allocate the method decl MethodDecl nodeMethod = new MethodDecl( stMemberName, typeReturn, arParams, block, mods); // If we have a chain, inject it into the statements if (chain != null) { nodeMethod.Body.InjectStatementAtHead(chain); chain.FinishInit(nodeMethod); } return nodeMethod; }