public override Type OutputType(out CompiledFragment newOperation){ newOperation=this; Type typeB=Input1.OutputType(out Input1); Type typeA=Input0.OutputType(out Input0); if(typeA!=typeB){ bool BString=(typeB==typeof(string)); if(typeA==typeof(string)||BString){ if(BString){ // This is alright - convert Input0 to a ToString operation. Input0=Types.ToStringMethod(Method,Input0,typeA); typeA=typeof(string); }else{ Input1=Types.ToStringMethod(Method,Input1,typeB); typeB=typeof(string); } } } if(typeA==typeof(string)&&typeB==typeof(string)){ // Adding two strings (concat). newOperation=new MethodOperation(Method,typeof(string).GetMethod("Concat",new Type[]{typeof(string),typeof(string)}),Input0,Input1); }else{ typeA=Numerical(typeA,typeB,"Addition",ref newOperation); } return typeA; }
public override Type OutputType(out CompiledFragment newOperation) { newOperation = this; Type typeB = Input1.OutputType(out Input1); Type typeA = Input0.OutputType(out Input0); if (typeA != typeB) { bool BString = (typeB == typeof(string)); if (typeA == typeof(string) || BString) { if (BString) { // This is alright - convert Input0 to a ToString operation. Input0 = Types.ToStringMethod(Method, Input0, typeA); typeA = typeof(string); } else { Input1 = Types.ToStringMethod(Method, Input1, typeB); typeB = typeof(string); } } } if (typeA == typeof(string) && typeB == typeof(string)) { // Adding two strings (concat). newOperation = new MethodOperation(Method, typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) }), Input0, Input1); } else { typeA = Numerical(typeA, typeB, "Addition", ref newOperation); } return(typeA); }
/// <summary>Looks for an overloaded numerical operator by the given name (e.g. "Addition"). /// The name will then have op_ appended to the start of it (as used internally by .NET). If found, /// the output type of the operation is returned.</summary> /// <param name="methodName">The name of the method to look for.</param> /// <param name="typeA">The type of the input on the left of the operator (Input0).</param> /// <param name="typeB">The type of the input on the right of the operator (Input1).</param> /// <param name="newOperation">A method call operation if it was found which is already correctly linked to Input0 and Input1.</param> /// <returns>The output type of the method if found.</returns> public Type FindOverload(string methodName, Type typeA, Type typeB, ref CompiledFragment newOperation) { if (typeA == null || typeB == null) { return(null); } methodName = "op_" + methodName; // Find an overloaded operator (always static): MethodInfo mI = typeA.GetMethod(methodName, new Type[] { typeA, typeB }); if (mI == null) { mI = typeB.GetMethod(methodName, new Type[] { typeB, typeA }); if (mI == null) { return(null); } newOperation = new MethodOperation(Method, mI, Input1, Input0); } else { newOperation = new MethodOperation(Method, mI, Input0, Input1); } return(newOperation.OutputType(out newOperation)); }
/// <summary>Gets the ToString method of the given type, being called on the given fragment.</summary> /// <param name="method">The function this operation is occuring in.</param> /// <param name="frag">The object that the ToString method is being called on.</param> /// <param name="type">The type that fragment contains and the one that the ToString operation must be found on.</param> /// <returns>A methodOperation representing the ToString call. Throws an error if frag is null.</returns> public static MethodOperation ToStringMethod(CompiledMethod method, CompiledFragment frag, Type type) { if (type == null) { frag.Error("Unable to convert null to a string."); } MethodOperation mo = new MethodOperation(method, type.GetMethod("ToString", new Type[0])); mo.CalledOn = frag; frag.ParentFragment = mo; return(mo); }
public override Type OutputType(out CompiledFragment v) { v = this; if (ElementType == null) { Type type = AppliedTo.OutputType(out AppliedTo); Type indexType = Index.OutputType(out Index); if (!type.IsArray) { // Using an index on something that isn't an array - this maps to the get_Item/set_Item functions. MethodInfo[] allMethods = type.GetMethods(); MethodOperation mOp = null; if (Input0 != null) { // Set. Input0 is the object we're setting. Type setType = Input0.OutputType(out Input0); MethodInfo mInfo = Types.GetOverload(allMethods, "set_Item", new Type[] { indexType, setType }); if (mInfo == null) { Error("This object does not support setting values with [" + indexType + "]=" + setType + "."); } mOp = new MethodOperation(Method, mInfo, Index, Input0); v = mOp; mOp.CalledOn = AppliedTo; return(setType); } else { // Get. MethodInfo mInfo = Types.GetOverload(allMethods, "get_Item", new Type[] { indexType }); if (mInfo == null) { Error("Unable to index [] something that as it is not an array."); } mOp = new MethodOperation(Method, mInfo, Index); v = mOp; mOp.CalledOn = AppliedTo; return(mInfo.ReturnType); } } else { EnforceType(ref Index, indexType, typeof(int)); } ElementType = type.GetElementType(); } return(ElementType); }
public override Type OutputType(out CompiledFragment v){ v=this; if(ElementType==null){ Type type=AppliedTo.OutputType(out AppliedTo); Type indexType=Index.OutputType(out Index); if(!type.IsArray){ // Using an index on something that isn't an array - this maps to the get_Item/set_Item functions. MethodInfo[] allMethods=type.GetMethods(); MethodOperation mOp=null; if(Input0!=null){ // Set. Input0 is the object we're setting. Type setType=Input0.OutputType(out Input0); MethodInfo mInfo=Types.GetOverload(allMethods,"set_Item",new Type[]{indexType,setType}); if(mInfo==null){ Error("This object does not support setting values with ["+indexType+"]="+setType+"."); } mOp=new MethodOperation(Method,mInfo,Index,Input0); v=mOp; mOp.CalledOn=AppliedTo; return setType; }else{ // Get. MethodInfo mInfo=Types.GetOverload(allMethods,"get_Item",new Type[]{indexType}); if(mInfo==null){ Error("Unable to index [] something that as it is not an array."); } mOp=new MethodOperation(Method,mInfo,Index); v=mOp; mOp.CalledOn=AppliedTo; return mInfo.ReturnType; } }else{ EnforceType(ref Index,indexType,typeof(int)); } ElementType=type.GetElementType(); } return ElementType; }
/// <summary>Gets the ToString method of the given type, being called on the given fragment.</summary> /// <param name="method">The function this operation is occuring in.</param> /// <param name="frag">The object that the ToString method is being called on.</param> /// <param name="type">The type that fragment contains and the one that the ToString operation must be found on.</param> /// <returns>A methodOperation representing the ToString call. Throws an error if frag is null.</returns> public static MethodOperation ToStringMethod(CompiledMethod method,CompiledFragment frag,Type type){ if(type==null){ frag.Error("Unable to convert null to a string."); } MethodOperation mo=new MethodOperation(method,type.GetMethod("ToString",new Type[0])); mo.CalledOn=frag; frag.ParentFragment=mo; return mo; }
public override Type OutputType(out CompiledFragment v) { v = this; Type type = OfType(); // Map to functionality: CompiledClass Class = null; bool isDynamic = Types.IsDynamic(type); // (Constant) binding flags: BindingFlags flags = BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static; if (Name == "length" && type.IsGenericType && !isDynamic) { // Does length actually exist as a field/ property? Field = type.GetField(Name, flags); if (Field == null) { Property = type.GetProperty(Name, flags); if (Property == null) { // Assume we meant count instead: Name = "Count"; } } } if (isDynamic) { Class = Method.Script.GetClass(type); } else if (!Method.Script.AllowUse(type)) { Error("Unable to access properties of type " + type + " as it has not been made accessible."); } if (isDynamic) { Field = Class.GetField(Name); } else { Field = type.GetField(Name, flags); } if (Field != null) { if (IsStatic && !Field.IsStatic) { Error("Property " + Name + " is not static. You must use an object reference to access it."); } return(Field.FieldType); } if (isDynamic) { Property = Class.GetProperty(Name); } else { Property = type.GetProperty(Name, flags); } if (Property != null) { if (IsStatic) { MethodInfo staticTest = Property.GetGetMethod(); if (staticTest == null) { staticTest = Property.GetSetMethod(); } if (!staticTest.IsStatic) { Error("Property " + Name + " is not static. You must use an object reference to access it."); } } return(Property.PropertyType); } if (isDynamic) { MethodReturnType = Class.MethodReturnType(Name); } else { MethodReturnType = Types.MethodReturnType(type, Name); } if (MethodReturnType != null) { if (Types.IsVoid(MethodReturnType)) { MethodReturnType = typeof(Void); } return(DynamicMethodCompiler.TypeFor(MethodReturnType)); } if (Of.GetType() == typeof(ThisOperation)) { // This was the first property - it can potentially be a static type name too. Type staticType = Method.Script.GetType(Name); if (staticType != null) { // It's a static type! Generate a new type operation to replace this one and return the type. v = new TypeOperation(Method, staticType); return(v.OutputType(out v)); } } if (Name == "this") { // This is handled here as it allows variables called "This". Use case: PowerUI. v = new ThisOperation(Method); return(v.OutputType(out v)); } // Does it support indexing? If so, Do Parent["property"] instead. MethodOperation mOp = null; if (Input0 != null) { // This is a set. Input0 is the object we're setting. Type setType = Input0.OutputType(out Input0); // Get the set method: MethodInfo mInfo; if (isDynamic) { mInfo = Class.FindMethodOverload("set_Item", new Type[] { typeof(string), setType }); } else { // Grab all the methods of the type: MethodInfo[] allMethods = type.GetMethods(); mInfo = Types.GetOverload(allMethods, "set_Item", new Type[] { typeof(string), setType }); } if (mInfo == null) { // Try finding the extension method: mInfo = FindExtensionMethod(type, "set"); if (mInfo == null) { // It doesn't exist! // Error("Property '"+ToString()+"' is not a property or extension of "+type.ToString()+"."); // Create as a global: Field = Method.Script.MainClass.DefineField(Name, true, setType); return(setType); } // Extension property or method. // -> We only know which based on MethodOperation later calling GetOverload. // Or OutputSet/ OutputIL being called. return(mInfo.ReturnType); } // It exists - create the method operation now. mOp = new MethodOperation(Method, mInfo, new CompiledFragment(Name), Input0); v = mOp; mOp.CalledOn = Of; return(setType); } else { // Get. // Get the get method: MethodInfo mInfo; if (isDynamic) { mInfo = Class.FindMethodOverload("get_Item", new Type[] { typeof(string) }); } else { // Grab all the methods of the type: MethodInfo[] allMethods = type.GetMethods(); mInfo = Types.GetOverload(allMethods, "get_Item", new Type[] { typeof(string) }); } if (mInfo == null) { // Try finding the extension method: mInfo = FindExtensionMethod(type, "get"); if (mInfo == null) { // It doesn't exist! // Error("Property '"+ToString()+"' is not a property or extension of "+type.ToString()+"."); // Create as a global: Field = Method.Script.MainClass.DefineField(Name, true, typeof(object)); return(typeof(object)); } // Extension property or method. // -> We only know which based on MethodOperation later calling GetOverload. // Or OutputSet/ OutputIL being called. return(mInfo.ReturnType); } // It exists - create the method operation now: mOp = new MethodOperation(Method, mInfo, new CompiledFragment(Name)); v = mOp; mOp.CalledOn = Of; return(mInfo.ReturnType); } }
public override Type OutputType(out CompiledFragment v){ v=this; Type type=OfType(); // Map to functionality: CompiledClass Class=null; bool isDynamic=Types.IsDynamic(type); if(!isDynamic){ if(!Method.Script.AllowUse(type)){ Error("Unable to access properties of type "+type+" as it has not been made accessible."); } }else{ Class=Method.Script.GetClass(type); } if(isDynamic){ Field=Class.GetField(Name); }else{ Field=type.GetField(Name,BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); } if(Field!=null){ if(IsStatic&&!Field.IsStatic){ Error("Property "+Name+" is not static. You must use an object reference to access it."); } return Field.FieldType; } if(isDynamic){ Property=Class.GetProperty(Name); }else{ Property=type.GetProperty(Name,BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); } if(Property!=null){ if(IsStatic){ MethodInfo staticTest=Property.GetGetMethod(); if(staticTest==null){ staticTest=Property.GetSetMethod(); } if(!staticTest.IsStatic){ Error("Property "+Name+" is not static. You must use an object reference to access it."); } } return Property.PropertyType; } if(isDynamic){ MethodReturnType=Class.MethodReturnType(Name); }else{ MethodReturnType=Types.MethodReturnType(type,Name); } if(MethodReturnType!=null){ if(Types.IsVoid(MethodReturnType)){ MethodReturnType=typeof(Void); } return DynamicMethodCompiler.TypeFor(MethodReturnType); } if(Of.GetType()==typeof(ThisOperation)){ // This was the first property - it can potentially be a static type name too. Type staticType=Method.Script.GetType(Name); if(staticType!=null){ // It's a static type! Generate a new type operation to replace this one and return the type. v=new TypeOperation(Method,staticType); return v.OutputType(out v); } } if(Name=="this"){ // This is handled here as it allows variables called "This". Use case: PowerUI. v=new ThisOperation(Method); return v.OutputType(out v); } // Does it support indexing? If so, Do Parent["property"] instead. MethodOperation mOp=null; if(Input0!=null){ // This is a set. Input0 is the object we're setting. Type setType=Input0.OutputType(out Input0); // Get the set method: MethodInfo mInfo; if(isDynamic){ mInfo=Class.FindMethodOverload("set_Item",new Type[]{typeof(string),setType}); }else{ // Grab all the methods of the type: MethodInfo[] allMethods=type.GetMethods(); mInfo=Types.GetOverload(allMethods,"set_Item",new Type[]{typeof(string),setType}); } if(mInfo==null){ // It doesn't exist! Error("Property '"+ToString()+"' is not a property of "+type.ToString()+"."); } // It exists - create the method operation now. mOp=new MethodOperation(Method,mInfo,new CompiledFragment(Name),Input0); v=mOp; mOp.CalledOn=Of; return setType; }else{ // Get. // Get the get method: MethodInfo mInfo; if(isDynamic){ mInfo=Class.FindMethodOverload("get_Item",new Type[]{typeof(string)}); }else{ // Grab all the methods of the type: MethodInfo[] allMethods=type.GetMethods(); mInfo=Types.GetOverload(allMethods,"get_Item",new Type[]{typeof(string)}); } if(mInfo==null){ // It doesn't exist! Error("'"+ToString()+"' is not a property of "+type.ToString()+"."); } // It exists - create the method operation now: mOp=new MethodOperation(Method,mInfo,new CompiledFragment(Name)); v=mOp; mOp.CalledOn=Of; return mInfo.ReturnType; } }
/// <summary>Looks for an overloaded numerical operator by the given name (e.g. "Addition"). /// The name will then have op_ appended to the start of it (as used internally by .NET). If found, /// the output type of the operation is returned.</summary> /// <param name="methodName">The name of the method to look for.</param> /// <param name="typeA">The type of the input on the left of the operator (Input0).</param> /// <param name="typeB">The type of the input on the right of the operator (Input1).</param> /// <param name="newOperation">A method call operation if it was found which is already correctly linked to Input0 and Input1.</param> /// <returns>The output type of the method if found.</returns> public Type FindOverload(string methodName,Type typeA,Type typeB,ref CompiledFragment newOperation){ if(typeA==null||typeB==null){ return null; } methodName="op_"+methodName; // Find an overloaded operator (always static): MethodInfo mI=typeA.GetMethod(methodName,new Type[]{typeA,typeB}); if(mI==null){ mI=typeB.GetMethod(methodName,new Type[]{typeB,typeA}); if(mI==null){ return null; } newOperation=new MethodOperation(Method,mI,Input1,Input0); }else{ newOperation=new MethodOperation(Method,mI,Input0,Input1); } return newOperation.OutputType(out newOperation); }