/// <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); }
/// <summary>Is the object in I0 mentioned anywhere in I1? Used to distinguish incrementals from straight sets.</summary> /// <returns>True if it is, false otherwise.</returns> public bool SelfReferencing() { if (Input1 == null || Input0 == null) { return(false); } // Try getting it as a variable: Variable variable = Input0.Value as Variable; if (variable != null) { // Great it's a variable! return(LookFor(Input1, variable)); } else { // Try as a property instead. PropertyOperation property = Input0 as PropertyOperation; if (property != null) { // it's a property - try searching that instead! return(LookFor(Input1, property)); } } return(false); }
/// <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."); } }
/// <summary>Does this property operation equal the given one? Compares value names.</summary> public bool Equals(PropertyOperation prop) { if (Name == prop.Name) { // So far so good! Match for Of's too? if (Of == null && prop.Of == null) { return(true); } if (Of != null && prop.Of != null) { // Compare those: if (Of.GetType() == prop.Of.GetType()) { return(Of.ToString() == prop.Of.ToString()); } } } return(false); }
/// <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. CalledOn.OutputType(out CalledOn); PropertyOperation prop = CalledOn as PropertyOperation; if (prop != null && (prop.MethodReturnType != null || prop.Methods != null)) { MethodToCall = prop.GetOverload(Arguments); if (MethodToCall == null) { Error("Method " + prop.Name + " was not found."); } CalledOn = MethodToCall.IsStatic?null:prop.Of; if (prop.Methods != null) { // Push the original called on into args set: if (Arguments == null) { // Create empty set: Arguments = new CompiledFragment[1]; } else { // Create the new args set: CompiledFragment[] args = new CompiledFragment[Arguments.Length + 1]; // Copy args into it: Array.Copy(Arguments, 0, args, 1, Arguments.Length); // Update it: Arguments = args; } // First one (propertyOp always puts it in as arg 0, for get/set properties): Arguments[0] = prop.Of; } } if (MethodToCall == null) { Error("Unable to run '" + Name + "' as a method."); } }
/// <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, fragType); 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) { // Is the parameter a delegate? if (typeof(Delegate).IsAssignableFrom(paramType) || typeof(MulticastDelegate).IsAssignableFrom(paramType)) { // Get the method info - argFrag should be a PropertyOperation: PropertyOperation propertyOp = (argFrag as PropertyOperation); if (propertyOp == null || propertyOp.Method == null) { argFrag.Error("Unrecognised object being used where a method (to use as a delegate) was expected."); } // Get the required set of parameters for the delegate: Type[] delegateTypes = SetToTypes(paramType.GetMethod("Invoke").GetParameters()); // Get the target method: MethodInfo targetMethod = propertyOp.GetOverload(delegateTypes); if (targetMethod == null) { argFrag.Error("Given method does not match delegate signature for " + paramType); } // Got a delegate. Delegate creation op: argFrag = new DelegateOperation(method, targetMethod, paramType); } else { CompiledFragment originalFragment = argFrag; argFrag = TryCast(method, argFrag, paramType, argType); 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); } }