Example #1
0
 // Nothing to resolve for literal expressions
 protected override Exp ResolveExpAsRight(ISemanticResolver s)
 {   
     // Always resolve our children     
     ResolveExpAsRight(ref m_left, s);
     ResolveExpAsRight(ref m_right, s);
     
     // If we don't match a predefined operator, then check for overloads
     if (!MatchesPredefinedOp(Op, this.Left.CLRType, this.Right.CLRType))
     {
         // Packagage Left & Right into parameters for a method call
         ArgExp [] args = new ArgExp [2] {
             new ArgExp(EArgFlow.cIn, m_left),
             new ArgExp(EArgFlow.cIn, m_right)
         };
                                 
         // Check for delegate combination
         // D operator+(D, D)
         // D operator-(D, D)            
         if (AST.DelegateDecl.IsDelegate(m_left.CLRType))
         {
             if (m_left.CLRType == m_right.CLRType)
             {
                 if (Op == BinaryOp.cAdd || Op == BinaryOp.cSub)
                 {
                     System.Type d = m_left.CLRType;
                     
                     // Translates to:
                     // op+ --> (D) System.Delegate.Combine(left, right)
                     // op- --> (D) System.Delegate.Remove(left, right)
                     
                     TypeEntry tDelegate = s.LookupSystemType("MulticastDelegate");
                     string stName = (Op == BinaryOp.cAdd) ? "Combine" : "Remove";
                     
                     bool dummy;
                     MethodExpEntry sym = tDelegate.LookupMethod(s, new Identifier(stName), 
                         new Type[] { d, d}, out dummy);
                     
                     
                     Exp call2 = new CastObjExp(
                         new ResolvedTypeSig(d, s),
                         new MethodCallExp(
                             null,sym, args, s)
                     );
                     
                     Exp.ResolveExpAsRight(ref call2, s);
                     return call2;                                
                 
                 }
             }
         
         } // end delgate op+ check
                                         
         // Check for System.String.Concat().
         // @todo - this should be able to compress an entire subtree, not just 2 args.
         // (ie, a+b+c -> String.Concat(a,b,c);
         // So we can't merge this into the SearchForOverload.
         // But for now we'll be lazy...
         if ((Op == BinaryOp.cAdd) && (Left.CLRType == typeof(string) || Right.CLRType == typeof(string)))
         {                
             Exp call2 = new MethodCallExp(                    
                     new DotObjExp(
                         new SimpleObjExp(
                             new Identifier("System", this.m_filerange)
                         ),
                         new Identifier("String", this.m_filerange)),
                     new Identifier("Concat", m_filerange),
                     args);
             call2.SetLocation(this.Location);
             Exp.ResolveExpAsRight(ref call2, s);
                     
             return call2;
         }
     
         MethodExpEntry  m = SearchForOverloadedOp(s);
         if (m == null && (Op == BinaryOp.cEqu || Op == BinaryOp.cNeq))
         {
             // If it's '==' or '!=', then it's ok if we didn't find 
             // an overload.
         } else 
         {
             // Couldn't find an overload, throw error
             if (m == null)
             {
                 //ThrowError_NoAcceptableOperator(s, this.Location, m_left.CLRType, m_right.CLRType, Op);
                 ThrowError(SymbolError.NoAcceptableOperator(this.Location, m_left.CLRType, m_right.CLRType, Op));
             }
             
             // Replace this node w/ the method call            
             MethodCallExp call = new MethodCallExp(null, m, args, s);
             call.SetLocation(this.Location);
             
             return call;
         }
     }
     
     
     CalcCLRType(s);
     
     return this;
 }
Example #2
0
 // Semantic resolution.
 // This is where we check for Set-Property transformations (where an
 // assignment gets changed into a methodcall)
 protected override Exp ResolveExpAsRight(ISemanticResolver s)
 {
     // Resolve the leftside of the operator                
     Exp.ResolveExpAsLeft(ref m_oeLeft, s);
     
     
     // Event transform  actually occurs in the assignment node.
     // A.e = A.e + d --> A.add_e(d)            
     // We have to do this before we resolve the RHS of the operator (Since we
     // can't resolve events as a RHS).
     if (m_oeLeft is EventExp)
     {   
         EventExp nodeEvent = (EventExp)m_oeLeft;
         EventExpEntry e = nodeEvent.Symbol;         
         
         // Here we just do some asserts.
         BinaryExp b = this.m_expRight as BinaryExp;
         Debug.Assert(b != null, "bad formed event +=,-=");  
      
         // By now, we know we have something of the form A = B + C   
         // Make sure that A=B. Since we resolved A as left, must resolve B as left too.
         Exp eTempLeft = b.Left;
         Exp.ResolveExpAsLeft(ref eTempLeft, s);
         Debug.Assert(eTempLeft is EventExp);
         Debug.Assert(Object.ReferenceEquals(((EventExp) eTempLeft).Symbol, e)); // symbols should be exact references
         
         // Resolve C (the delegate that we're adding to the event)
         Exp eTempRight = b.Right;
         Exp.ResolveExpAsRight(ref eTempRight, s);            
         Debug.Assert(AST.DelegateDecl.IsDelegate(eTempRight.CLRType), "Event only ops w/ delegates"); // @todo -legit/            
         
         Debug.Assert(b.Op == BinaryExp.BinaryOp.cAdd || b.Op == BinaryExp.BinaryOp.cSub);
             
         
         MethodExpEntry m2 = (b.Op == BinaryExp.BinaryOp.cAdd) ? e.AddMethod : e.RemoveMethod;
             
         Exp e2 = new MethodCallExp(
             nodeEvent.InstanceExp,
             m2,
             new ArgExp[] {
                 new ArgExp(EArgFlow.cIn, eTempRight)
             },
             s
         );
                 
         Exp.ResolveExpAsRight(ref e2, s);
         return e2;            
     }
     
     Exp.ResolveExpAsRight(ref m_expRight, s);
                     
     
     // Check for calling add_, remove on events
     // a.E += X 
     // a.E = a.E + X (parser transforms)
     // if E is a delegate, and RHS is structured like E + X
     // then transform to a.add_E(X) or a.remove_E(x)
     
     // @todo - use the EventInfo to get exact add / remove functions
     if (DelegateDecl.IsDelegate(m_oeLeft.CLRType))
     {   
         // Events can only exist on a class
         AST.FieldExp f = m_oeLeft as FieldExp;
         if (f == null)
             goto NotAnEvent;
             
         Exp eInstance = f.InstanceExp; // ok if static                
         
         BinaryExp rhs = m_expRight as BinaryExp;
         if (rhs == null)
             goto NotAnEvent;            
         
         // Check if RHS is a.E + X
         if ((rhs.Left != m_oeLeft) || (rhs.Right.CLRType != rhs.Left.CLRType))
             goto NotAnEvent;
         
                     
         string stEventName = f.Symbol.Name;
         string stOpName;
         if (rhs.Op == BinaryExp.BinaryOp.cAdd)
             stOpName = "add_" + stEventName;
         else if (rhs.Op == BinaryExp.BinaryOp.cSub)
             stOpName = "remove_" + stEventName;                        
         else
             goto NotAnEvent;                
          
         // a.add_E(X);    
         Exp e = new MethodCallExp(
             eInstance,
             new Identifier(stOpName),
             new ArgExp[] {
                 new ArgExp(EArgFlow.cIn, rhs.Right)
             }
         );            
         
         Exp.ResolveExpAsRight(ref e, s);
         e.SetLocation(this.Location);    
         return e;
                     
         
     NotAnEvent:
         ;            
     }
     
     // Check for set-indexer
     if (m_oeLeft is ArrayAccessExp)
     {
         ArrayAccessExp a = m_oeLeft as ArrayAccessExp;
         if (a.IsIndexer) 
         {
             // Leftside: get_Item(idx, value);
             System.Type [] alParams = new Type [] {
                 a.ExpIndex.CLRType,
                 m_expRight.CLRType
             };
         
             TypeEntry t = s.ResolveCLRTypeToBlueType(a.Left.CLRType);            
             MethodExpEntry m = t.LookupIndexer(a.Left.Location, s, alParams, true);
             
             Exp e = new MethodCallExp(
                 a.Left,
                 m,
                 new ArgExp[] { 
                     new ArgExp(EArgFlow.cIn, a.ExpIndex),
                     new ArgExp(EArgFlow.cIn, m_expRight) 
                 },
                 s);
             
             Exp.ResolveExpAsRight(ref e, s);
             e.SetLocation(this.Location);    
             return e;
         }        
     }
     
     // Check for transforming properties into MethodCalls
     if (m_oeLeft is PropertyExp)
     {
         PropertyExp p = (PropertyExp) m_oeLeft;
         
         Exp e = new MethodCallExp(
             p.InstanceExp, 
             p.Symbol.SymbolSet, 
             new ArgExp[] { 
                 new ArgExp(EArgFlow.cIn, m_expRight) 
             },
             s);
             
         Exp.ResolveExpAsRight(ref e, s);
         e.SetLocation(this.Location);
         return e;
     }
     
     CalcCLRType(s);
 
     // Ensure type match        
     s.EnsureAssignable(m_expRight, m_oeLeft.CLRType);        
     
     return this;
 }
Example #3
0
//-----------------------------------------------------------------------------
// Parse a single atom of an expression
// Atom expressions are the basic building blocks of expressions and
// don't contain any operators in them.
// Atoms are combined together to form more complex expressions.
// One caveat:
// Type casting & parenthesis look really similar...
//-----------------------------------------------------------------------------
    protected Exp ParseExpAtom()
    {
        // Parse a single term
        Token t = m_lexer.PeekNextToken();
                        
        // Either expression in parenthesis
        // could be a typecast
        if (t.TokenType == Token.Type.cLParen)
        {
            ConsumeNextToken();
            Exp e = ParseExp();
            ReadExpectedToken(Token.Type.cRParen);

        // Typecast if the next token is in the first set of an expression
        // --> (Type) exp
            t = m_lexer.PeekNextToken();
            if (IsStartOfExp(t))
            {
                TypeSig tSig = ConvertExpToType(e);                
                Exp eSource = this.ParsePrimaryExp();

                return new CastObjExp(tSig, eSource);
            }

            return e;        
        }
        
        // Check for 'new'
        if (t.TokenType == Token.Type.cNew)
            return ParseNewExp();
        
        
        // Check for identifier or methodcall
        // E -> i
        // E -> i ( ... )
        if (t.TokenType == Token.Type.cId)
        {
            Identifier id = ReadExpectedIdentifier();
            Token t2 = m_lexer.PeekNextToken();
            
            // if next char after id is a '(', then this is a method call
            // with an implied 'this' pointer on the left side
            if (t2.TokenType == Token.Type.cLParen)
            {
                ArgExp [] arParams = ParseArgList();
                MethodCallExp m = new MethodCallExp(null, id, arParams);
                return m;
            } 
            else 
            {
                return new SimpleObjExp(id);
            }
        } 
        
        // Check for literals
        if (t.TokenType == Token.Type.cNull)
        {
            ConsumeNextToken();
            return new NullExp(t.Location);
        }
        
        if (t.TokenType == Token.Type.cString)
        {
            ConsumeNextToken();
            return new StringExp(t.Text, t.Location);
        }
        
        if (t.TokenType == Token.Type.cInt)
        {
            ConsumeNextToken();            
            return new IntExp(t.IntValue, t.Location);
        }
        
        if (t.TokenType == Token.Type.cChar)
        {
            ConsumeNextToken();
            return new CharExp(t.CharValue, t.Location);
        }
        
        if (t.TokenType == Token.Type.cBool)
        {
            ConsumeNextToken();
            return new BoolExp(t.BoolValue, t.Location);
        }
                
        ThrowError(E_UnexpectedToken(t));
        return null;
    }
Example #4
0
//-----------------------------------------------------------------------------
// 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;
    }
Example #5
0
 protected override Exp ResolveExpAsRight(ISemanticResolver s)
 {
     //CalcCLRType(s);
     //return this; 
     // Transform into a get
     Exp eResolved = new MethodCallExp(
         this.InstanceExp, 
         Symbol.SymbolGet, 
         new ArgExp[0], 
         s
     );
     
     Exp.ResolveExpAsRight(ref eResolved, s);
     
     return eResolved;
 }
Example #6
0
 // Internal helper. Since the left & right cases are close enough
 // we want to merge them into a function.
 private Exp ResolveInternal(ISemanticResolver s, bool fIsLeft)
 {
     ResolveExpAsRight(ref m_oeLeft, s);
     ResolveExpAsRight(ref m_expIndex, s);
     
 // @todo - check that m_expIndex is an integer
 
 // Check for indexers:
 // If the Left is not an array, then we must be an indexer.
 // Strip references, So T[]& --> T[]
     System.Type t = m_oeLeft.CLRType;
     if (t.IsByRef)
         t = t.GetElementType();
         
     if (!t.IsArray)
     {            
         m_fIsIndexer = true;
         
         
         // If we're the leftside, we have a problem. We don't know the exp on the RS,
         // so we don't have a full signature, so we don't know what we're supposed to
         // change too. So just leave it that we're an indexer and let our parent
         // in the AST resolve us.
         // But this also means that we don't have a good thing to set our CLR type too.
         // So we just don't call CalcCLRType(). That's ok since our parent will drop
         // this node immediately anyways.
         if (fIsLeft)
         {
             return this;
         }
         
         // Rightside: get_Item(idx);
         System.Type [] alParams = new Type [] {
             this.ExpIndex.CLRType
         };
         
         TypeEntry tLeft = s.ResolveCLRTypeToBlueType(m_oeLeft.CLRType);            
         MethodExpEntry m = tLeft.LookupIndexer(m_oeLeft.Location, s, alParams, fIsLeft);
         
         
         Exp e = new MethodCallExp(
             this.Left,
             m,
             new ArgExp[] {
                 new ArgExp(EArgFlow.cIn, ExpIndex)
             },
             s);
             
         Exp.ResolveExpAsRight(ref e, s);
         return e;
         
     }
 
 
 
 
     CalcCLRType(s);
     
     return this;
 }
Example #7
0
    // 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;
    }