// An ObjExp is just a temporary node. But that's the best a Context-Free parse can // do. So now that we're building a symbol table, we can do a Context-Sensitive resolution // and figure out what type of node this really is. public Exp GetResolvedNode(ISemanticResolver s, bool fRight) { Exp eResolved = null; // Lookup the symbol and determine what we are //SymEntry sym = s.LookupSymbol(this.m_strId, true); string stName = this.m_strId.Text; SymEntry sym = s.LookupSymbolWithContext(this.m_strId, false); // allow methods // Namespace if (sym is NamespaceEntry) { eResolved = new NamespaceExp(sym as NamespaceEntry); } // Local Variable else if (sym is LocalVarExpEntry) { eResolved = new LocalExp(sym as LocalVarExpEntry); } // Parameter else if (sym is ParamVarExpEntry) { eResolved = new ParamExp(sym as ParamVarExpEntry); } // A type name else if (sym is TypeEntry) { eResolved = new TypeExp(sym as TypeEntry); } // A field (w/ an implied 'this' pointer) else if (sym is FieldExpEntry) { // When a single identifier resolves to a field, it can be either // an instance field with an implied 'this' ref, or a static field of this class. FieldExpEntry f = sym as FieldExpEntry; Exp expInstance = null; if (!f.IsStatic) { expInstance = new SimpleObjExp("this"); Exp.ResolveExpAsRight(ref expInstance, s); } eResolved = new FieldExp(f, expInstance); } // An event (w/ an implied 'this' ptr) else if (sym is EventExpEntry) { EventExpEntry e = (EventExpEntry) sym; Exp expInstance = null; if (!e.Mods.IsStatic) { expInstance = new SimpleObjExp("this"); Exp.ResolveExpAsRight(ref expInstance, s); } eResolved = new EventExp(e, expInstance); } // A property (w/ an implied 'this' ptr). // Properties will eventually be converted into method calls. else if (sym is PropertyExpEntry) { PropertyExpEntry p = (PropertyExpEntry) sym; Exp expInstance = null; if (!p.IsStatic) { expInstance = new SimpleObjExp("this"); Exp.ResolveExpAsRight(ref expInstance, s); } eResolved = new PropertyExp(p, expInstance); } // Not recognized. else { if (stName == "this") // check a common error case... Debug.Assert(false, "Can't access 'this'. Are we in a static?"); if (sym == null) { MethodHeaderEntry h = s.GetCurrentClass().LookupMethodHeader(this.m_strId.Text); if (h != null) { return this; } ThrowError(SymbolError.UndefinedSymbol(m_strId)); //Debug.Assert(false, "Unknown name in SimpleObjExp:" + stName); } Debug.Assert(false, "Unknown symbol type:" + ((sym == null) ? "null" : sym.ToString())); } Debug.Assert(eResolved != null); return eResolved; }
// 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; }