//----------------------------------------------------------------------------- // 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; }
//----------------------------------------------------------------------------- // Parse a new Expression (either array or non-array) // -> 'new' id_list '(' exp, exp ... ')' // // -> 'new' id_list '[x]' '[]'* array_init? // -> 'new' id_list '[]'* array_init // // array_init-> '{' exp, exp, exp, ...'}' //----------------------------------------------------------------------------- protected Exp ParseNewExp() { ReadExpectedToken(Token.Type.cNew); // A typesig would allow [] to be part of the type // An id_list doesn't. Exp oe = ParseDottedIdList(); SimpleTypeSig type = new SimpleTypeSig(oe); Token t2 = m_lexer.PeekNextToken(); // If next is a '(', then this is a ctor call (and not an array) if (t2.TokenType == Token.Type.cLParen) { Exp [] eList = ParseExpList(); Exp e = new NewObjExp(type, eList); return e; } // Array case if (t2.TokenType == Token.Type.cLRSquare || t2.TokenType == Token.Type.cLSquare) { ArrayTypeSig typeArray = null; ArrayInitializer init = null; // dynamic size explicitly in rank specifier // -> 'new' id_list '[x]' '[]'* array_init? if (t2.TokenType == Token.Type.cLSquare) { Exp [] eList = ParseExpList(Token.Type.cLSquare, Token.Type.cRSquare); // includes [ and ] int dim = eList.Length; NonRefTypeSig s = ParseOptionalArrayDecl(type); typeArray = new ArrayTypeSig(s, dim); if (m_lexer.PeekNextToken().TokenType == Token.Type.cLCurly) { init = this.ParseArrayInitList(); } Exp e = new NewArrayObjExp(typeArray,eList,init); return e; } // static size implicitly from array_initializer // -> 'new' id_list '[]'* array_init else if (t2.TokenType == Token.Type.cLRSquare) { NonRefTypeSig t = ParseOptionalArrayDecl(type); typeArray = t.AsArraySig; init = this.ParseArrayInitList(); Exp e = new NewArrayObjExp(typeArray,init); return e; } } ThrowError(E_UnexpectedToken(t2)); return null; }
//----------------------------------------------------------------------------- // Helper to parse array decls. // For arrays, leftmost [] is the outermost // So X[][,,][,] is 1d of 3d of 2d of X // Because this is left to right (and not right to left), we have to be // stack based / recursive (instead of an iterative while) // // sigElemType is the type of the non-array portion (X in the above example) // Note that if this isn't an array type, we'll just return sigElemType //----------------------------------------------------------------------------- NonRefTypeSig ParseOptionalArrayDecl(NonRefTypeSig sigElemType) { Token t = m_lexer.PeekNextToken(); if (t.TokenType == Token.Type.cLRSquare) { ConsumeNextToken(); int dim = t.Dimension; NonRefTypeSig sig = ParseOptionalArrayDecl(sigElemType); sig = new ArrayTypeSig(sig, dim); string stTest = sig.ToString(); return sig; } else { return sigElemType; } }
public NewArrayObjExp( ArrayTypeSig tArrayType, // full array type (includes rank) Exp [] arExpSize, // rank to allocate, eval at runtime ArrayInitializer aInit // optional initilizer list ) { Debug.Assert(tArrayType != null); Debug.Assert(arExpSize != null); m_tFullType = tArrayType; this.m_arExpList = arExpSize; this.m_ArrayInit = aInit; // @todo - this is wrong m_filerange = tArrayType.Location; }
// Implicit size from init list public NewArrayObjExp( ArrayTypeSig tArrayType, // includes rank specifiers ArrayInitializer aInit // mandatory ) { Debug.Assert(tArrayType != null); Debug.Assert(aInit != null); m_tFullType = tArrayType; this.m_arExpList = null; this.m_ArrayInit = aInit; // @todo - this is wrong m_filerange = tArrayType.Location; }
// 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; }