/// <summary>Compiles a set of parameters into an array of compiled fragments.</summary> /// <param name="brackets">The parent block which contains each parameter as a child.</param> /// <param name="parentBlock">The method the parameters are for.</param> /// <returns>A set of compiled fragments.</returns> public static CompiledFragment[] CompileParameters(CodeFragment brackets, CompiledMethod parentBlock) { if (!brackets.IsParent) { return(null); } int count = 0; brackets.Compile(parentBlock); CodeFragment child = brackets.FirstChild; CompiledFragment[] output = new CompiledFragment[brackets.ChildCount()]; while (child != null) { CompiledFragment frag = (CompiledFragment)child; if (frag == null) { return(null); } output[count] = frag; count++; child = child.NextChild; } return(output); }
/// <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>Defines a new field on this class.</summary> /// <param name="name">The name of the field.</param> /// <param name="type">The type of the value held by this field.</param> /// <returns>A new FieldBuilder.</returns> protected virtual void DefineField(string name, VariableFragment nameFragment, bool isPublic, CodeFragment defaultValue) { Type type = null; if (nameFragment.GivenType != null) { type = nameFragment.GivenType.FindType(Script); nameFragment.GivenType = null; if (type == null) { nameFragment.Error(name + " has a type that was not recognised."); } } else if (defaultValue != null) { // Try and compile it: CompiledFragment frag = defaultValue.Compile(GetInit()); // Get the output type: type = frag.OutputType(out frag); } if (type == null) { nameFragment.Error(name + "'s type isn't given. Should be e.g. " + name + ":String if it has no default value."); } FieldBuilder field = Builder.DefineField(name, type, isPublic?FieldAttributes.Public:FieldAttributes.Private); Fields[name] = field; }
public override Type OutputType(out CompiledFragment newOperation){ newOperation=this; if(FromType==null){ FromType=ToBox.OutputType(out ToBox); } return typeof(object); }
/// <summary>Looks for the use of the given property within this operation. E.g. this.hello=this.hello+1;</summary> /// <param name="cfrag">The fragment to look in, e.g. this.Input1.</param> /// <param name="findingProp">The property being searched for.</param> /// <returns>True if it was found in there, false otherwise.</returns> public bool LookFor(CompiledFragment cfrag, PropertyOperation findingProp) { if (cfrag == null) { return(false); } // Try as operation: Operation op = cfrag as Operation; if (op != null) { // Specifically a property operation? PropertyOperation prop = op as PropertyOperation; if (prop != null && prop.Equals(findingProp)) { // Got a match! return(true); } if (LookFor(op.Input0, findingProp)) { return(true); } if (LookFor(op.Input1, findingProp)) { return(true); } } return(false); }
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; }
protected override Operation Compile(CompiledFragment left,CompiledFragment right,CompiledMethod method){ CompiledFragment frag=left; if(left==null){ frag=right; } return new SetOperation(method,frag,new AddOperation(method,frag,new CompiledFragment(1))); }
/// <summary>Looks for the use of the given variable within this operation.</summary> /// <param name="cfrag">The fragment to look in, e.g. this.Input1.</param> /// <param name="findingVar">The variable being searched for.</param> /// <returns>True if it was found in there, false otherwise.</returns> public bool LookFor(CompiledFragment cfrag, Variable findingVar) { if (cfrag == null) { return(false); } if (cfrag.Value == null && Types.IsTypeOf(cfrag, typeof(Operation))) { Operation op = (Operation)cfrag; if (LookFor(op.Input0, findingVar)) { return(true); } if (LookFor(op.Input1, findingVar)) { return(true); } } else if (cfrag.Value != null && Types.IsTypeOf(cfrag.Value, typeof(Variable))) { return(((Variable)cfrag.Value).Equals(findingVar)); } return(false); }
public override Type OutputType(out CompiledFragment newOperation) { newOperation = this; if (Size != null && Size.OutputType(out Size) != typeof(int)) { Error("The size of a new array must be an integer."); } if (DefaultValues != null) { Type elementType = ArrayType.GetElementType(); for (int i = 0; i < DefaultValues.Length; i++) { CompiledFragment p = DefaultValues[i]; Type pType = p.OutputType(out p); if (pType == null) { if (elementType.IsValueType) { Error("Null cannot be used in an array of value types."); } } else if (!elementType.IsAssignableFrom(pType)) { Error("A value defined in an array is not a type that will go into the array."); } DefaultValues[i] = p; } } return(ArrayType); }
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 CompiledFragment Compile(CompiledMethod method) { if (FirstChild == null) { return(null); } // Apply the current line: method.CurrentLine = LineNumber; try{ // Compile operator chains: (d=a+b+c;) CompilationServices.CompileOperators(this, method); // Compile the now singular operator: CompiledFragment cFrag = FirstChild.Compile(method) as CompiledFragment; return(cFrag); }catch (CompilationException e) { if (e.LineNumber == -1) { // Setup line number: e.LineNumber = LineNumber; } // Rethrow: throw e; } }
/// <summary>Loads the MethodToCall value if it needs to.</summary> private void GetMethodInfo(){ if(MethodToCall!=null){ return; } if(Arguments!=null){ for(int i=0;i<Arguments.Length;i++){ CompiledFragment p=Arguments[i]; p.OutputType(out p); Arguments[i]=p; } } // Note: Most things go via a DynamicMethod here. // This is because CalledOn is mostly a PropertyOperation. // It's converted to a static singular MethodInfo with GetOverload below though. Type fragType=CalledOn.OutputType(out CalledOn); PropertyOperation prop=CalledOn as PropertyOperation; if(prop!=null&&prop.MethodReturnType!=null){ MethodToCall=prop.GetOverload(Arguments); if(MethodToCall==null){ Error("Method "+prop.Name+" was not found."); } CalledOn=MethodToCall.IsStatic?null:prop.Of; }else{ MethodToCall=Types.GetCallable(fragType); } if(MethodToCall==null){ Error("Unable to run '"+Name+"' as a method."); } }
public PropertyOperation(CompiledMethod method,CompiledFragment of,string name):base(method){ if(of!=null){ of.ParentFragment=this; } Of=(of!=null)?of:new ThisOperation(method); Name=name; }
/// <summary>Forces this operation to have a numerical output.</summary> /// <param name="input">A reference to this operation which may be replaced with a cast operation.</param> /// <param name="inputType">The current output type of this operation.</param> /// <param name="newType">The type that the output of this operation must be.</param> /// <returns>The new output type if successful. Throws an error otherwise.</returns> public Type Numerical(ref CompiledFragment input, Type inputType, Type defaultType) { if (Types.IsNumeric(inputType)) { return(inputType); } return(EnforceType(ref input, inputType, defaultType)); }
public override Type OutputType(out CompiledFragment v) { v = this; Type typeA = Input1.OutputType(out Input1); Type typeB = Input0.OutputType(out Input0); return(Numerical(typeA, typeB, "Division", ref v)); }
public override Type OutputType(out CompiledFragment newOperation) { newOperation = this; // No need to call ToDelegate.OutputType(out ToDelegate) here; it's certainly already been done. return(DelegateType); }
public override Type OutputType(out CompiledFragment v) { v = this; Type TypeA = Input1.OutputType(out Input1); Type TypeB = Input0.OutputType(out Input0); return(Numerical(TypeA, TypeB, "Multiply", ref v)); }
/// <summary>Outputs the given argument set into the given IL stream.</summary> /// <param name="args">The compiled set of arguments to be outputted.</param> /// <param name="method">The method that they are being used in.</param> /// <param name="into">The IL stream to output the arguments into.</param> /// <param name="parameters">The parameter info used to correctly match the location of the parameters.</param> public static void OutputParameters(CompiledFragment[] args, CompiledMethod method, NitroIL into, ParameterInfo[] parameters) { int argID = 0; int argCount = 0; if (args != null) { argCount = args.Length; } for (int paramID = 0; paramID < parameters.Length; paramID++) { ParameterInfo param = parameters[paramID]; Type paramType = param.ParameterType; if (IsParams(param)) { // The rest are going into an array Operation. // Get the type we want to cast them all to (because paramType at this stage must be an array): paramType = paramType.GetElementType(); CompiledFragment[] ops = new CompiledFragment[argCount - argID]; int Index = 0; for (int i = argID; i < argCount; i++) { CompiledFragment frag = args[i]; Type fragType = frag.OutputType(out frag); if (fragType != paramType) { frag = TryCast(method, frag, paramType); if (frag == null) { args[i].Error("Unable to box or cast " + fragType + " to " + paramType + " at parameter " + argID + ". Note that you can't null a value type."); } } ops[Index++] = frag; } CompiledFragment arrayOp = new ArrayOperation(method, paramType, ops); arrayOp.OutputType(out arrayOp); arrayOp.OutputIL(into); return; } CompiledFragment argFrag = args[argID++]; Type argType = argFrag.OutputType(out argFrag); if (argType != paramType) { CompiledFragment originalFragment = argFrag; argFrag = TryCast(method, argFrag, paramType); if (argFrag == null) { originalFragment.Error("Unable to box or cast " + argType + " to " + paramType + " at parameter " + argID + " of method call " + param.Member.Name + ". Note that you can't null a value type."); } } argFrag.OutputIL(into); } }
public IndexOperation(CompiledMethod method,CompiledFragment appliedTo,CompiledFragment[] indices):base(method){ AppliedTo=appliedTo; if(indices.Length==0){ Error("No index value given. must be e.g. array[1]."); }else if(indices.Length>1){ Error("Multidimension arrays are not currently supported."); } Index=indices[0]; }
public override Type OutputType(out CompiledFragment newOperation) { newOperation = this; if (FromType == null) { FromType = ToBox.OutputType(out ToBox); } return(typeof(object)); }
public PropertyOperation(CompiledMethod method, CompiledFragment of, string name) : base(method) { if (of != null) { of.ParentFragment = this; } Of = (of != null)?of:new ThisOperation(method); Name = name; }
/// <summary>Sets the default/ intial values for this array instance.</summary> /// <param name="defaultValues">The set of default values to use.</param> private void SetDefaults(CompiledFragment[] defaultValues){ if(defaultValues!=null&&defaultValues.Length==0){ defaultValues=null; } DefaultValues=defaultValues; if(Size==null&&defaultValues!=null){ DirectSize=defaultValues.Length; } }
public override Type OutputType(out CompiledFragment nv) { nv = this; GetMethodInfo(); if (Types.NoReturn(MethodToCall)) { Error("'" + Name + "' does not return anything"); } return(MethodToCall.ReturnType); }
/// <summary>Attempts to find the named numerical operation that the given types can perform.</summary> /// <param name="typeA">The type of the object on the left of the operator.</param> /// <param name="typeB">The type of the object on the right of the operator.</param> /// <param name="overloadMethod">The name of the method to look for, e.g. "Addition".</param> /// <param name="newOperation">The new method call if it was successfully found.</param> /// <returns>The new output type if successful. Throws an error otherwise.</returns> public Type Numerical(Type typeA, Type typeB, string overloadMethod, ref CompiledFragment newOperation) { Type type = FindOverload(overloadMethod, typeA, typeB, ref newOperation); if (type == null && ((type = MapNumerical(typeA, typeB)) == null)) { Error("Could not find a suitable method to use with " + typeA + " and " + typeB + " using this operator."); } return(type); }
protected override Operation Compile(CompiledFragment left, CompiledFragment right, CompiledMethod method) { CompiledFragment frag = left; if (left == null) { frag = right; } return(new SetOperation(method, frag, new AddOperation(method, frag, new CompiledFragment(1)))); }
public override Type OutputType(out CompiledFragment newOperation){ newOperation=this; Type typeB=Input1.OutputType(out Input1); if(Input0==null){ // Negation return Numerical(ref Input1,typeB,typeof(float)); } Type typeA=Input0.OutputType(out Input0); return Numerical(typeA,typeB,"Subtraction",ref newOperation); }
/// <summary>Attempts to make both Input0 and Input1 numerical, returning the output result of an operation if they are. /// Usually the returned type will be the one with higher accuracy. E.g. adding an int to a long will result in a long.</summary> /// <param name="typeA">The output type of Input0.</param> /// <param name="typeB">The output type of Input1.</param> /// <returns>The output result of a numerical operation with these types.</returns> public Type MapNumerical(Type typeA, Type typeB) { bool isExplicit = false; CompiledFragment frag0 = null; CompiledFragment frag1 = null; bool typeANumeric = Types.IsNumeric(typeA); bool typeBNumeric = Types.IsNumeric(typeB); if (typeANumeric && typeBNumeric) { if (typeA == typeB) { return(typeA); } else { // Which is higher accuracy? Map to that one and cast the other. frag0 = Types.TryCast(Method, Input0, typeB, typeA, out isExplicit); if (frag0 != null) { if (isExplicit) { // Other way is better: frag1 = Types.TryCast(Method, Input1, typeA, typeB); if (frag1 != null) { Input1 = frag1; return(typeA); } else { Input0 = frag0; return(typeB); } } else { Input0 = frag0; return(typeB); } } else { frag1 = Types.TryCast(Method, Input1, typeA, typeB); if (frag1 != null) { Input1 = frag1; return(typeA); } } } } return(null); }
public override Type OutputType(out CompiledFragment v){ v=this; if(Parameters!=null){ for(int i=0;i<Parameters.Length;i++){ CompiledFragment p=Parameters[i]; p.OutputType(out p); Parameters[i]=p; } } return ObjectType; }
public override CompiledFragment Compile(CompiledMethod method) { CompiledFragment cfrag = MethodName.Compile(method); if (!Types.IsTypeOf(cfrag.ActiveValue(), typeof(ISettable))) { Error("Unable to compile a method call - didn't recognise an invokable object."); } CompiledFragment[] parameters = CompilationServices.CompileParameters(Brackets, method); return(new MethodOperation(method, cfrag, parameters)); }
public override Type OutputType(out CompiledFragment v){ v=this; for(int i=0;i<Conditions.Length;i++){ CompiledFragment cond=Conditions[i]; cond.OutputType(out cond); Conditions[i]=cond; } return null; }
/// <summary>Returns the type that this fragment produces when it's executed. /// For example, int+int will output another int.</summary> /// <param name="v">In some cases, checking the output type will generate a new fragment. This value is the new fragment /// and it must always replace the original fragment that OutputType was called on.</param> /// <returns>The type that this fragment returns.</returns> public virtual Type OutputType(out CompiledFragment v){ v=this; if(Value==null){ return null; } Type type=Value.GetType(); if(Types.IsTypeOf(Value,typeof(Variable))){ type=((Variable)Value).Type(); } return type; }
public override Type OutputType(out CompiledFragment v){ v=this; Type typeA=Input0.OutputType(out Input0); Type typeB=Input1.OutputType(out Input1); CompiledFragment equalityOverload=null; FindOverload("Inequality",typeA,typeB,ref equalityOverload); if(equalityOverload!=null){ v=equalityOverload; } return typeof(bool); }
/// <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); }
/// <summary>Gets the constructor overload for the given type and using the given arguments.</summary> /// <param name="type">The type to get the constructor from.</param> /// <param name="args">The set of arguments being passed to the constructor. Used to find the right overload.</param> /// <returns>A ConstructorInfo if a matching constructor overload was found; null otherwise.</returns> public static ConstructorInfo GetConstructor(Type type,CompiledFragment[] args){ ConstructorInfo[] constructors=type.GetConstructors(); if(constructors==null){ return null; } Type[] paramSet=GetTypes(args); ConstructorInfo constructor=GetConstructor(constructors,paramSet,false); if(constructor!=null){ return constructor; } return GetConstructor(constructors,paramSet,true); }
public IndexOperation(CompiledMethod method, CompiledFragment appliedTo, CompiledFragment[] indices) : base(method) { AppliedTo = appliedTo; if (indices.Length == 0) { Error("No index value given. must be e.g. array[1]."); } else if (indices.Length > 1) { Error("Multidimension arrays are not currently supported."); } Index = indices[0]; }
public override Type OutputType(out CompiledFragment v) { v = this; for (int i = 0; i < Conditions.Length; i++) { CompiledFragment cond = Conditions[i]; cond.OutputType(out cond); Conditions[i] = cond; } return(null); }
public override Type OutputType(out CompiledFragment v){ v=this; Type typeA=Input0.OutputType(out Input0); Type typeB=Input1.OutputType(out Input1); CompiledFragment overload=null; FindOverload("GreaterThan",typeA,typeB,ref overload); if(overload!=null){ v=overload; } return typeof(bool); }
public override Type OutputType(out CompiledFragment newOperation) { newOperation = this; Type typeB = Input1.OutputType(out Input1); if (Input0 == null) { // Negation return(Numerical(ref Input1, typeB, typeof(float))); } Type typeA = Input0.OutputType(out Input0); return(Numerical(typeA, typeB, "Subtraction", ref newOperation)); }
/// <summary>Forces this operation to be a particular type by creating a cast.</summary> /// <param name="input">A reference to this operation which may be replaced with a cast operation.</param> /// <param name="inputType">The current output type of this operation.</param> /// <param name="newType">The type that the output of this operation must be.</param> /// <returns>The new output type if successful. Throws an error otherwise.</returns> public Type EnforceType(ref CompiledFragment input,Type inputType,Type newType){ // If inputType inherits newType, it's ok anyway: if(newType.IsAssignableFrom(inputType)){ return inputType; } bool isExplicit; CompiledFragment frag=Types.TryCast(Method,input,newType,out isExplicit); if(frag==null){ Error("Unable to enforce type '"+newType+"' on something that is a '"+inputType+"'"); }else{ input=frag; } return newType; }
public override Type OutputType(out CompiledFragment v) { v = this; if (Parameters != null) { for (int i = 0; i < Parameters.Length; i++) { CompiledFragment p = Parameters[i]; p.OutputType(out p); Parameters[i] = p; } } return(ObjectType); }
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>Returns the type that this fragment produces when it's executed. /// For example, int+int will output another int.</summary> /// <param name="v">In some cases, checking the output type will generate a new fragment. This value is the new fragment /// and it must always replace the original fragment that OutputType was called on.</param> /// <returns>The type that this fragment returns.</returns> public virtual Type OutputType(out CompiledFragment v) { v = this; if (Value == null) { return(null); } Type type = Value.GetType(); if (Types.IsTypeOf(Value, typeof(Variable))) { type = ((Variable)Value).Type(); } return(type); }
public override Type OutputType(out CompiledFragment v) { v = this; Type typeA = Input0.OutputType(out Input0); Type typeB = Input1.OutputType(out Input1); CompiledFragment equalityOverload = null; FindOverload("Equality", typeA, typeB, ref equalityOverload); if (equalityOverload != null) { v = equalityOverload; } return(typeof(bool)); }
public override Type OutputType(out CompiledFragment v){ v=this; if(Input0!=null){ Type i0Type=Input0.OutputType(out Input0); if(i0Type!=null && i0Type.IsValueType){ // Create a box operation: Input0=new BoxOperation(Method,Input0); } } return typeof(string); }
/// <summary>Converts the the given fragments into a compiled operation by first checking the fragments are ok for this operator.</summary> /// <param name="left">The fragment to the left of the operator.</param> /// <param name="right">The fragment to the right of the operation.</param> /// <param name="method">The method the operation will be compiled into.</param> public Operation ToOperation(CompiledFragment left,CompiledFragment right,CompiledMethod method){ bool leftNull=(left==null); bool rightNull=(right==null); if(leftNull&&rightNull){ return null; } if(leftNull&&!rightNull&&!RightOnly){ return null; } if(!leftNull&&rightNull&&!LeftOnly){ return null; } if(!leftNull&&!rightNull&&!LeftAndRight){ return null; } return Compile(left,right,method); }
public override Type OutputType(out CompiledFragment v) { v = this; if (Input0 != null) { Type i0Type = Input0.OutputType(out Input0); if (i0Type != null && i0Type.IsValueType) { // Create a box operation: Input0 = new BoxOperation(Method, Input0); } } return(typeof(string)); }
public override Type OutputType(out CompiledFragment v) { v = this; Type typeA = Input0.OutputType(out Input0); Type typeB = Input1.OutputType(out Input1); CompiledFragment overload = null; FindOverload("GreaterThan", typeA, typeB, ref overload); if (overload != null) { v = overload; } return(typeof(bool)); }
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>Looks for the use of the given variable within this operation.</summary> /// <param name="cfrag">The fragment to look in, e.g. this.Input1.</param> /// <param name="findingVar">The variable being searched for.</param> /// <returns>True if it was found in there, false otherwise.</returns> public bool LookFor(CompiledFragment cfrag,Variable findingVar){ if(cfrag==null){ return false; } if(cfrag.Value==null&&Types.IsTypeOf(cfrag,typeof(Operation))){ Operation op=(Operation)cfrag; if(LookFor(op.Input0,findingVar)){ return true; } if(LookFor(op.Input1,findingVar)){ return true; } }else if(cfrag.Value!=null&&Types.IsTypeOf(cfrag.Value,typeof(Variable))){ return ((Variable)cfrag.Value).Equals(findingVar); } return false; }
public override Type OutputType(out CompiledFragment newOperation){ newOperation=this; if(Size!=null&&Size.OutputType(out Size)!=typeof(int)){ Error("The size of a new array must be an integer."); } if(DefaultValues!=null){ Type elementType=ArrayType.GetElementType(); for(int i=0;i<DefaultValues.Length;i++){ CompiledFragment p=DefaultValues[i]; Type pType=p.OutputType(out p); if(pType==null){ if(elementType.IsValueType){ Error("Null cannot be used in an array of value types."); } }else if(!elementType.IsAssignableFrom(pType)){ Error("A value defined in an array is not a type that will go into the array."); } DefaultValues[i]=p; } } return ArrayType; }
/// <summary>Gets a particular method (it may be overloaded) from this class.</summary> /// <param name="name">The name of the method.</param> /// <param name=arguments">The set of arguments being used in calling this method.</param> /// <returns>The MethodInfo for the method if found; null otherwise.</returns> public MethodInfo FindMethodOverload(string name,CompiledFragment[] arguments){ MethodOverloads set=FindMethodSet(name); if(set==null){ return Types.GetOverload(Builder.BaseType.GetMethods(),name,Types.GetTypes(arguments),true); } return set.GetOverload(Types.GetTypes(arguments)); }
/// <summary>Attempts to generate a cast operation for the given fragment to the given type.</summary> /// <param name="method">The method this operation is occuring in.</param> /// <param name="frag">The fragment containing the object to cast.</param> /// <param name="to">The type to cast it to if possible.</param> /// <param name="isExplicit">True if the casting is explicit. False if it is implicit.</param> /// <returns>A cast operation if it is possible; throws an error otherwise.</returns> public static CompiledFragment TryCast(CompiledMethod method,CompiledFragment frag,Type to,out bool isExplicit){ isExplicit=false; Type from=frag.OutputType(out frag); if(from==null){ if(to.IsValueType){ return null; }else{ return frag; } } if(to==typeof(object) && from.IsValueType){ return new BoxOperation(method,frag); } if(from==to||to.IsAssignableFrom(from)){ return frag; } // IsAssignableFrom is true if TO inherits FROM: if(from.IsAssignableFrom(to)){ return new CastOperation(method,frag,to); } MethodInfo cast=IsCastableTo(from,to,out isExplicit); if(cast==null){ return null; }else{ return new MethodOperation(method,cast,frag); } }
/// <summary>Converts a set of compiled fragments into a set of their outputted types. /// E.g. if a certain fragment is "a string", one of the types will be a string.</summary> /// <param name="frags">The set of fragments to convert.</param> /// <returns>A set of types. Each one is the output type of each fragment.</returns> public static Type[] GetTypes(CompiledFragment[] frags){ if(frags==null){ return new Type[0]; } Type[] result=new Type[frags.Length]; for(int i=frags.Length-1;i>=0;i--){ result[i]=frags[i].OutputType(); } return result; }
public SetOperation(CompiledMethod method,CompiledFragment input0,CompiledFragment input1):base(method){ Input0=input0; Input1=input1; }
public override Type OutputType(out CompiledFragment v){ v=this; Output=true; return Input0.OutputType(out Input0); }
protected override Operation Compile(CompiledFragment left,CompiledFragment right,CompiledMethod method){ return new SetOperation(method,left,new SubtractOperation(method,left,right)); }
/// <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; }
/// <summary>Attempts to generate a cast operation for the given fragment to the given type.</summary> /// <param name="method">The method this operation is occuring in.</param> /// <param name="frag">The fragment containing the object to cast.</param> /// <param name="to">The type to cast it to if possible.</param> /// <returns>A cast operation if it is possible; throws an error otherwise.</returns> public static CompiledFragment TryCast(CompiledMethod method,CompiledFragment frag,Type to){ bool isExplicit; return TryCast(method,frag,to,out isExplicit); }
protected override Operation Compile(CompiledFragment left,CompiledFragment right,CompiledMethod method){ return new MultiplyOperation(method,left,right); }
protected override Operation Compile(CompiledFragment left,CompiledFragment right,CompiledMethod method){ return new GreaterThanOrEqualOperation(method,left,right); }