// Debugging support public override void DebugCheck(ISemanticResolver s) { //Debug.Assert(AST.Node.m_DbgAllowNoCLRType || m_typeCLR != null); if (Node != null) { Debug.Assert(Node.Symbol == this); // Non-null means that we're a user method. So we'd better // have a scope Debug.Assert(m_scope != null); m_scope.DebugCheck(s); } else { // If Node is null, then we're imported. // Can't have a scope & body for an imported function... Debug.Assert(m_scope == null); } if (!IsCtor) { // Must have a return type (even Void is still non-null) Debug.Assert(RetType != null); RetType.DebugCheck(s); } // Must be defined in some class Debug.Assert(m_classDefined != null); }
protected virtual Exp ResolveExpAsLeft(ISemanticResolver s) { // Default impl - most expressions aren't valid on the LHS. //s.ThrowError_NotValidLHS(this.Location); ThrowError(SymbolError.NotValidLHS(this.Location)); return null; }
// Imported public MethodExpEntry( ISemanticResolver s, System.Reflection.MethodBase info // CLR info for this method ) { Debug.Assert(info != null); this.m_infoMethod = info; this.m_fIsSpecialName = info.IsSpecialName; this.m_strName = info.Name; this.m_classDefined = s.ResolveCLRTypeToBlueType(info.DeclaringType); // Set return type for non-constructors System.Reflection.MethodInfo mInfo = info as System.Reflection.MethodInfo; if (mInfo != null) { // not a ctor this.m_type = s.ResolveCLRTypeToBlueType(mInfo.ReturnType); } else { // ctor this.m_type = null; m_strName = m_classDefined.Name; } }
// Resolve this array initializer list. // Provide with the type that we expect each element in the list to be public void Resolve(ISemanticResolver s, TypeEntry tExpected) { // Each node must either be an expression or a nested array initializer list //foreach(Node n in List) for(int i = 0; i < m_list.Length; i++) { Node n = m_list[i]; if (n is Exp) { Exp e = (Exp) n; Exp.ResolveExpAsRight(ref e, s); m_list[i] = e; s.EnsureAssignable(e, tExpected.CLRType); } else if (n is ArrayInitializer) { Debug.Assert(tExpected.IsArray); // @todo -legit ArrayInitializer a = (ArrayInitializer) n; TypeEntry tNested = tExpected.AsArrayType.ElemType; a.Resolve(s, tNested); } else { // Error Debug.Assert(false); // @todo - legit } } }
public ResolvedTypeSig(System.Type t, ISemanticResolver s) { Debug.Assert(!t.IsByRef, "Don't expect ref types"); Debug.Assert(t != null); Debug.Assert(s != null); m_type = s.ResolveCLRTypeToBlueType(t); }
public override void DebugCheck(ISemanticResolver s) { foreach(Node n in List) { n.DebugCheck(s); } }
public override void DebugCheck(ISemanticResolver s) { Debug.Assert(m_type != null); TypeEntry t = BlueType; if (t.IsRef) return; System.Type clrType = t.CLRType; // Make sure that our CLR type matches our TypeEntry if (clrType != null) { // @todo - Enums aren't entered into the hash. if (!(t is EnumTypeEntry)) { TypeEntry t2 = s.ResolveCLRTypeToBlueType(clrType); Debug.Assert(t == t2); } } if (clrType == null) { // Even now, the only way we can have no clr type is if we // are a user declared class Debug.Assert(t.Node != null); } } // DebugCheck
// Semantic resolution public override void ResolveType(ISemanticResolver s) { if (m_ArrayTypeRec != null) return; m_sigBase.ResolveType(s); m_ArrayTypeRec = new ArrayTypeEntry(this, s); }
// Semantic resolution public override void ResolveType(ISemanticResolver s) { if (m_tRefEntry != null) return; m_tElem.ResolveType(s); m_tRefEntry = new RefTypeEntry(m_tElem.BlueType, s); }
// Semantic resolution public override void ResolveType(ISemanticResolver s) { if (m_type != null) return; Exp.ResolveExpAsRight(ref m_oeValue, s); Debug.Assert(m_oeValue is TypeExp); m_type = ((TypeExp) m_oeValue).Symbol; }
// Create an array node given an existing CLR array type public ArrayTypeSig(System.Type tArray, ISemanticResolver s) { Debug.Assert(tArray != null); m_filerange = null; m_cDimension = tArray.GetArrayRank(); Debug.Assert(m_cDimension == 1, "@todo - only 1d arrays currently implemented"); m_ArrayTypeRec = s.ResolveCLRTypeToBlueType(tArray).AsArrayType; m_sigBase = null; // left as null. }
// Verify integrity of all symbol elements in this scope public void DebugCheck(ISemanticResolver s) { System.Collections.IDictionaryEnumerator e = m_table.GetEnumerator(); while (e.MoveNext()) { string str = (string)e.Key; SymEntry sym = (SymEntry)e.Value; sym.DebugCheck(s); } }
// Imported field public FieldExpEntry( ISemanticResolver s, System.Reflection.FieldInfo fInfo ) { m_strName = fInfo.Name; m_type = s.ResolveCLRTypeToBlueType(fInfo.FieldType); m_nodeDecl = null; m_tClassDefined = s.ResolveCLRTypeToBlueType(fInfo.DeclaringType); m_info = fInfo; }
public override void DebugCheck(ISemanticResolver s) { Debug.Assert(Name != null); if (Node != null) { Debug.Assert(Node.Symbol == this); } Debug.Assert(Info != null); Debug.Assert(SymbolClass != null); Debug.Assert(FieldType != null); SymbolClass.DebugCheck(s); FieldType.DebugCheck(s); }
public override void DebugCheck(ISemanticResolver s) { ElemType.DebugCheck(s); Debug.Assert(m_ArrayTypeRec != null); // Parallel data structures: // (ArrayTypeSig : TypeSig) as (ArrayTypeEntry : TypeEntry) // So verify the integrity there if (m_sigBase != null) { Debug.Assert(m_sigBase.BlueType == m_ArrayTypeRec.ElemType); } } // DebugCheck
// For imported public LiteralFieldExpEntry( ISemanticResolver s, System.Reflection.FieldInfo fInfo ) : base(s, fInfo) { Debug.Assert(fInfo.IsLiteral && fInfo.IsStatic); object o = fInfo.GetValue(null); // For enum fields, their literal value is an Enum, not an int. Data = o; Type t = m_value.GetType(); string st = m_value.ToString(); }
// Resolve expression as a RHS value. The exp node can totally change on us // (operator overloading, constant folding, etc), so we must pass as a ref public static void ResolveExpAsRight(ref Exp e, ISemanticResolver s) { // Debugging helper. Useful when we want to break when resolving // a particular symbol. #if false // Set lTarget to a symbol that we want to see resolved. FileRange lTarget = new FileRange("SemanticChecker.cs", 143, 39, 143, 43); if (lTarget.Equals(e.Location)) { System.Diagnostics.Debugger.Break(); } #endif e = e.ResolveExpAsRight(s); Debug.Assert(e != null); }
// Ctor for imported properties public PropertyExpEntry( ISemanticResolver s, System.Reflection.PropertyInfo info ) { m_info = info; m_strName = m_info.Name; // Class that we're defined in? System.Type tClrClass = info.DeclaringType; m_tClassDefined = s.ResolveCLRTypeToBlueType(tClrClass); // Symbol type this.m_type = s.ResolveCLRTypeToBlueType(info.PropertyType); // Spoof accessors if (info.CanRead) // Has Get { System.Reflection.MethodInfo mGet = info.GetGetMethod(); m_symbolGet = new MethodExpEntry(s, mGet); } if (info.CanWrite) // Has Set { System.Reflection.MethodInfo mSet = info.GetSetMethod(); m_symbolSet = new MethodExpEntry(s, mSet); } // Get modifiers System.Reflection.MethodInfo [] m = info.GetAccessors(); m_mods = new Modifiers(m[0]); /* * m_mods = new Modifiers(); * if (m[0].IsStatic) m_mods.SetStatic(); * if (m[0].IsAbstract) m_mods.SetAbstract(); * if (m[0].IsVirtual) m_mods.SetVirtual(); */ }
// Imported events public EventExpEntry( System.Reflection.EventInfo eInfo, ISemanticResolver s ) { Debug.Assert(eInfo != null); Debug.Assert(s != null); this.m_strName = eInfo.Name; this.m_tClassDefined = s.ResolveCLRTypeToBlueType(eInfo.DeclaringType); this.m_type = s.ResolveCLRTypeToBlueType(eInfo.EventHandlerType); this.m_node = null; System.Reflection.MethodInfo mAdd = eInfo.GetAddMethod(); System.Reflection.MethodInfo mRemove = eInfo.GetRemoveMethod(); SetAddMethod(new MethodExpEntry(s, mAdd)); SetRemoveMethod(new MethodExpEntry(s, mRemove)); this.m_mods = new Modifiers(mAdd); }
// Resolve the expression as a LHS value protected override Exp ResolveExpAsLeft(ISemanticResolver s) { Debug.Assert(m_eFlow == EArgFlow.cOut | m_eFlow == EArgFlow.cRef); ResolveExpAsLeft(ref m_exp, s); CalcCLRType(s); return this; }
protected override Type CalcCLRTypeHelper(ISemanticResolver s) { // Get the type of our inner Type t = m_exp.CalcCLRType(s); // If we've already got a reference, then we're ok. // Also ok if we're null (since literals can't be passed as a ref/out) if ((t == null) || (t.IsByRef)) return t; // Ref & Out params are actually type 'T&', not 'T' if (Flow == EArgFlow.cRef || Flow == EArgFlow.cOut) { t = s.GetRefToType(t); } return t; }
// There's nothing to resolve here. No real action happens until // codegen... protected override Exp ResolveExpAsRight(ISemanticResolver s) { return this; }
//......................................................................... // Semantic resolution. Resolve the exp as either a LHS or RHS value. //......................................................................... // Resolve the expression as a LHS value public static void ResolveExpAsLeft(ref Exp e, ISemanticResolver s) { e = e.ResolveExpAsLeft(s); Debug.Assert(e != null); }
// Allow safe resolving on Statement Exp. Allowed to change to another StmtExp public static void ResolveExpAsRight(ref StatementExp se, ISemanticResolver s) { Exp e = se; Exp.ResolveExpAsRight(ref e, s); if (e is StatementExp) se = (StatementExp) e; else Debug.Assert(false, "Shouldn't have resolved to a non-stmtexp"); Debug.Assert(se != null); }
// Semantic resolution protected override Exp ResolveExpAsRight(ISemanticResolver s) { Debug.Assert(false); return null; }
// 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; }
// Semantic resolution // "a X= b" is semantically equivalent to "a = a X b" protected override Exp ResolveExpAsRight(ISemanticResolver s) { // Note that the left side ("a") of "a X= b" is both a // Left & Right side value ResolveExpAsLeft(ref this.m_eLeft, s); ResolveExpAsRight(ref this.m_expRight, s); CalcCLRType(s); // Ensure type match s.EnsureAssignable(m_expRight, Left.CLRType); return this; }
// Resolution public abstract void ResolveType(ISemanticResolver s);
protected override Exp ResolveExpAsRight(ISemanticResolver s) { for(int i = 0; i < m_eList.Length; i++) StatementExp.ResolveExpAsRight(ref m_eList[i], s); Exp.ResolveExpAsRight(ref m_eLast, s); CalcCLRType(s); return this; }
public override void DebugCheck(ISemanticResolver s) { BlueType.DebugCheck(s); }
// Resolve the expression as RHS value. protected override Exp ResolveExpAsRight(ISemanticResolver s) { //Debug.Assert(m_eFlow == EArgFlow.cIn | m_eFlow == EArgFlow.cRef); Exp.ResolveExpAsRight(ref m_exp, s); CalcCLRType(s); return this; }
// Type of an assignment is the type of the Right Side protected override Type CalcCLRTypeHelper(ISemanticResolver s) { return m_oeLeft.CLRType; }
public override void DebugCheck(ISemanticResolver s) { Debug.Assert(false); }
public override void DebugCheck(ISemanticResolver s) { base.DebugCheck(s); Debug.Assert(CLRType.IsByRef, "Ref type must wrap a ref"); Debug.Assert(!m_tElem.BlueType.CLRType.IsByRef, "Can't have ref to ref"); }
protected override Type CalcCLRTypeHelper(ISemanticResolver s) { Debug.Assert(false); return null; }
protected override Type CalcCLRTypeHelper(ISemanticResolver s) { return null; }
public DeclareLocalStmtExp(System.Type t, ISemanticResolver s) : this(s.ResolveCLRTypeToBlueType(t)) { }
// Determine the CLR type of the expression protected override Type CalcCLRTypeHelper(ISemanticResolver s) { return typeof(char); }
public override void DebugCheck(ISemanticResolver s) { }
public override void DebugCheck(ISemanticResolver s) { m_exp.DebugCheck(s); }
// Since we already have a symbol, we don't have anything to do // (symbols are resolved); public override void ResolveType(ISemanticResolver s) { }
// Debugging support - Validate each symbol entry // Allow recursive flag so that we don't get stuck in an infinite loop public virtual void DebugCheck(ISemanticResolver s) { }
public override void DebugCheck(ISemanticResolver s) { foreach(Exp e in m_eList) e.DebugCheck(s); m_eLast.DebugCheck(s); }
// This gets called by CalcCLRType() // Derived classes override this and return the clr type protected virtual Type CalcCLRTypeHelper(ISemanticResolver s) { // This should be implemented Debug.Assert(false, "@todo - impl"); return null; }
public override void DebugCheck(ISemanticResolver s) { Debug.Assert(Left != null); Debug.Assert(Right != null); Left.DebugCheck(s); Right.DebugCheck(s); }
// Determine the CLR type of this expression protected override Type CalcCLRTypeHelper(ISemanticResolver s) { switch(m_op) { case UnaryOp.cNegate: return typeof(int); case UnaryOp.cNot: return typeof(bool); case UnaryOp.cPreInc: return typeof(int); case UnaryOp.cPostInc: return typeof(int); case UnaryOp.cPreDec: return typeof(int); case UnaryOp.cPostDec: return typeof(int); default: Debug.Assert(false, "Illegal unary operator:" + m_op.ToString()); return null; } }
//----------------------------------------------------------------------------- // Debugging check //----------------------------------------------------------------------------- public override void DebugCheck(ISemanticResolver s) { Debug.Assert(m_oeLeft != null); Debug.Assert(m_expRight != null); m_oeLeft.DebugCheck(s); m_expRight.DebugCheck(s); }
//----------------------------------------------------------------------------- // Debugging check //----------------------------------------------------------------------------- public override void DebugCheck(ISemanticResolver s) { CalcCLRType(s); m_left.DebugCheck(s); }
// Helper to resolve the expression as RHS value. // Return the newly-resolved exp node. In most cases, that will just be // the old node, but in a resolved state. For things like operator overloading, // it will be a totally different node. // Note that we must expose this version because 'ref Exp' is not assignable // with any derived expression. protected abstract Exp ResolveExpAsRight(ISemanticResolver s);
// Nothing to resolve for literal expressions protected override Exp ResolveExpAsRight(ISemanticResolver s) { CalcCLRType(s); #if DEBUG m_fResolved = true; #endif return this; }
public override void DebugCheck(ISemanticResolver s) { Debug.Assert(Arg != null); Arg.DebugCheck(s); }
public override void DebugCheck(ISemanticResolver s) { Debug.Assert(Exp.CanBeNullType(this) || this.CLRType != null); #if DEBUG Debug.Assert(m_fResolved); #endif }