//----------------------------------------------------------------------------- // Parse a Type Sig // // ** rules ** // TypeSig -> id ('.' id)* '[ ','* ]'* //----------------------------------------------------------------------------- protected NonRefTypeSig ParseTypeSig() { // Currently, we implement this by parsing ObjExpressions. That's easier // for us, but may let us parse illegal things. That's ok. The TypeSig // container class along with semantic checking will still give us the // expected error control. NonRefTypeSig sig = null; Identifier stId = ReadExpectedIdentifier(); Exp o = new SimpleObjExp(stId); Token t = m_lexer.PeekNextToken(); while (t.TokenType == Token.Type.cDot) { ConsumeNextToken(); stId = ReadExpectedIdentifier(); o = new DotObjExp(o, stId); t = m_lexer.PeekNextToken(); } sig = new SimpleTypeSig(o); // Check for arrays while (t.TokenType == Token.Type.cLRSquare) { sig = new ArrayTypeSig(sig, 1); ConsumeNextToken(); t = m_lexer.PeekNextToken(); } return sig; }
//----------------------------------------------------------------------------- // E -> E . i // E -> E . i (...) // E -> E [ E] //----------------------------------------------------------------------------- protected Exp ParsePrimaryExp() { Exp eFinal = ParseExpAtom(); // Now, since ObjExp are left-linear, we can actually parse them recursively // We parsed the base case, so we just keep iterating through deciding // which rule to apply. eFinal contains the root of the ast we're building Token t; while(true) { t = m_lexer.PeekNextToken(); // If next char is '.', then we're either doing: // E -> E . i // E -> E . i (...) if (t.TokenType == Token.Type.cDot) { ConsumeNextToken(); // eat the dot Identifier stId = ReadExpectedIdentifier(); Token t2 = m_lexer.PeekNextToken(); // MethodCall - if next character is a '(' // E -> E . i (...) if (t2.TokenType == Token.Type.cLParen) { ArgExp [] arParams = ParseArgList(); eFinal = new MethodCallExp(eFinal, stId, arParams); continue; } // Dot operator - for all other cases // E -> E . i else { eFinal = new DotObjExp(eFinal, stId); continue; } } // If next char is a '[', then this is an array access // E -> E [ E ] else if (t.TokenType == Token.Type.cLSquare) { ConsumeNextToken(); Exp eIdx = ParseExp(); ReadExpectedToken(Token.Type.cRSquare); eFinal = new ArrayAccessExp(eFinal, eIdx); continue; } // If we got to here, then we're done so break out of loop break; } // end while // @hack // Since expressions can be types (ie, that's how we parse a TypeCast) // Check if this is an array type if (t.TokenType == Token.Type.cLRSquare) { NonRefTypeSig sigElemType = new SimpleTypeSig(eFinal); TypeSig tSig = ParseOptionalArrayDecl(sigElemType); return new TempTypeExp(tSig); } return eFinal; }
//----------------------------------------------------------------------------- // Parse a list of identifiers separated by dots // // ** rules ** // id ( '.' id )* //----------------------------------------------------------------------------- protected Exp ParseDottedIdList() { Identifier stId = ReadExpectedIdentifier(); Exp o = new SimpleObjExp(stId); Token t = m_lexer.PeekNextToken(); while (t.TokenType == Token.Type.cDot) { ConsumeNextToken(); stId = ReadExpectedIdentifier(); o = new DotObjExp(o, stId); t = m_lexer.PeekNextToken(); } return o; }
// Semantic resolution protected override Exp ResolveExpAsRight(ISemanticResolver s) { // Only resolve once. if (m_symbol != null) return this; // First, resolve our parameters (because of overloading) // We need to know the URT types for our parameters // in order to resolve between overloaded operators Type [] alParamTypes = new Type[m_arParams.Length]; for(int i = 0; i < m_arParams.Length; i++) { Exp e = m_arParams[i]; ResolveExpAsRight(ref e, s); Debug.Assert(e == m_arParams[i]); Type tParam = e.CLRType; //if ((tParam !=null) && tParam.IsByRef) // tParam = tParam.GetElementType(); alParamTypes[i] = tParam; //Debug.Assert(alParamTypes[i] != null); } TypeEntry tCur = s.GetCurrentClass(); TypeEntry tLeft = null; // Type to lookup in // Is this a 'base' access? // Convert to the real type and set a non-virtual flag if (m_objExp is SimpleObjExp) { SimpleObjExp e = m_objExp as SimpleObjExp; if (e.Name.Text == "base") { // Set the scope that we lookup in. tLeft = tCur.Super; // Still need to resolve the expression. m_objExp = new SimpleObjExp("this"); m_fIsNotPolymorphic = true; } } #if true // See if we have a delegate here Exp eDelegate = null; if (m_objExp == null) { Exp e = new SimpleObjExp(m_idName); Exp.ResolveExpAsRight(ref e, s); if (!(e is SimpleObjExp)) eDelegate = e; } else { // If it's an interface, then we know we can't have a delegate field on it, // so short-circuit now. Exp.ResolveExpAsRight(ref m_objExp, s); if (!m_objExp.CLRType.IsInterface) { Exp e = new DotObjExp(m_objExp, m_idName); Exp.ResolveExpAsRight(ref e, s); if (!(e is DotObjExp)) eDelegate = e; } } if (eDelegate != null) { if (!DelegateDecl.IsDelegate(eDelegate.CLRType)) { //Debug.Assert(false, "@todo - " + m_strName + " is not a delegate or function"); // @todo - legit // Just fall through for now, method resolution will decide if this is a valid function } else { Exp e = new MethodCallExp( eDelegate, new Identifier("Invoke"), this.m_arParams ); Exp.ResolveExpAsRight(ref e, s); return e; } } #endif // No delegate, carry on with a normal function call // If there's no objexp, then the function is a method // of the current class. // make it either a 'this' or a static call if (m_objExp == null) { // Lookup bool fIsVarArgDummy; MethodExpEntry sym = tCur.LookupMethod(s, m_idName, alParamTypes, out fIsVarArgDummy); if (sym.IsStatic) { m_objExp = new TypeExp(tCur); } else { m_objExp = new SimpleObjExp("this"); } } // Need to Lookup m_strName in m_objExp's scope (inherited scope) Exp.ResolveExpAsRight(ref m_objExp, s); // Get type of of left side object // This call can either be a field on a variable // or a static method on a class bool fIsStaticMember = false; // If we don't yet know what TypeEntry this methodcall is on, then figure // it out based off the expression if (tLeft == null) { if (m_objExp is TypeExp) { fIsStaticMember = true; tLeft = ((TypeExp) m_objExp).Symbol; } else { fIsStaticMember = false; tLeft = s.ResolveCLRTypeToBlueType(m_objExp.CLRType); } } // Here's the big lookup. This will jump through all sorts of hoops to match // parameters, search base classes, do implied conversions, varargs, // deal with abstract, etc. bool fIsVarArg; m_symbol = tLeft.LookupMethod(s, m_idName, alParamTypes, out fIsVarArg); Debug.Assert(m_symbol != null); if (m_fIsNotPolymorphic) { // of the form 'base.X(....)' if (m_symbol.IsStatic) ThrowError(SymbolError.BaseAccessCantBeStatic(this.Location, m_symbol)); // @todo - PrintError? } else { // normal method call /* if (fIsStaticMember && !m_symbol.IsStatic) ThrowError(SymbolError.ExpectInstanceMember(this.Location)); // @todo - PrintError? else if (!fIsStaticMember && m_symbol.IsStatic) ThrowError(SymbolError.ExpectStaticMember(this.Location)); // @todo - PrintError? */ Debug.Assert(fIsStaticMember == m_symbol.IsStatic, "@todo - user error. Mismatch between static & instance members on line."); } // If we have a vararg, then transform it if (fIsVarArg) { // Create the array int cDecl = m_symbol.ParamCount; int cCall = this.ParamExps.Length; ArrayTypeSig tSig = new ArrayTypeSig(m_symbol.ParamCLRType(cDecl - 1), s); Node [] list = new Node[cCall - cDecl + 1]; for(int i = 0; i < list.Length; i++) { list[i] = this.ParamExps[i + cDecl - 1]; } Exp eArray = new NewArrayObjExp( tSig, new ArrayInitializer( list ) ); Exp.ResolveExpAsRight(ref eArray, s); // Change the parameters to use the array ArgExp [] arParams = new ArgExp[cDecl]; for(int i = 0; i < cDecl - 1; i++) arParams[i] = m_arParams[i]; arParams[cDecl - 1] = new ArgExp(EArgFlow.cIn, eArray); m_arParams = arParams; } // end vararg transformation this.CalcCLRType(s); return this; }