/// <summary>Declare an arg variable at the start of the args set.</summary> internal ArgVariable DeclareHoisted(string name, Type type) { // Create it: ArgVariable arg = new ArgVariable(name); // Set the type: arg.Type = type; // Add a blank arg to the end of the set: Arguments.Add(null); // Time to shift all the args over except for 'this' (arg 0)! for (int i = Arguments.Count - 1; i > 0; i--) { // Get it: ArgVariable currentArg = Arguments[i]; // Update the index: currentArg.ArgumentID = i + 1; // Set it back: Arguments[i + 1] = currentArg; } // Declare the arg in the scope: (InitialScope as DeclarativeScope).Declare(arg); return(arg); }
/// <summary>Gets the compiled function for the given args set. Note that this args set /// is the actual types and always includes the 'this' keywords type.</summary> public Library.UserDefinedFunction GetCompiled(Type[] args, ScriptEngine engine, bool isConstructor) { int genCount = GeneratedMethods.Count; for (int i = 0; i < genCount; i++) { if (GeneratedMethods[i].ArgsEqual(args)) { // Got a match! Already compiled it. return(GeneratedMethods[i]); } } // Need to compile it now with our given arg types. int argCount = args == null?0:args.Length; // The source contains a fixed number of args; it goes up to this: int maxArg = Arguments.Count; // First, map args to a block of ArgVariable objects: ArgVariable[] argsSet = new ArgVariable[argCount]; for (int i = 0; i < argCount; i++) { // Setup the arg variable: ArgVariable curArg; if (i < maxArg) { // Use the existing args object so it correctly updates in the scope: curArg = Arguments[i]; } else { // Need to create a fake one: curArg = new ArgVariable("@unused-arg-" + i); } // Apply type (a little different here as we have to account for null too): curArg.RawType = args[i]; // Apply to set: argsSet[i] = curArg; } // If we're passing less args than the source supports, update the types of those unused args to being 'Undefined': for (int i = argCount; i < maxArg; i++) { Arguments[i].Type = typeof(Nitrassic.Undefined); } // Create info: OptimizationInfo info = new OptimizationInfo(engine); info.IsConstructor = isConstructor; // Generate it! return(GenerateCode(argsSet, info)); }
/// <summary>Gets the compiled function for the given args set. Note that this args set /// is the actual values and always includes the 'this' keywords value.</summary> public Library.UserDefinedFunction GetCompiled(ScriptEngine engine, object[] args) { int genCount = GeneratedMethods.Count; for (int i = 0; i < genCount; i++) { if (GeneratedMethods[i].ArgsEqual(args)) { // Got a match! Already compiled it. return(GeneratedMethods[i]); } } // Need to compile it now with our given arg types. int argCount = args.Length; if (argCount > Arguments.Count) { // The actual source can only handle so many args. argCount = Arguments.Count; } // First, map args to Arguments: ArgVariable[] argsSet = new ArgVariable[argCount]; for (int i = 0; i < argCount; i++) { // Setup the arg variable: ArgVariable curArg = new ArgVariable(Arguments[i].Name); // Apply type: curArg.Type = args[i].GetType(); // Apply to set: argsSet[i] = curArg; } // Generate it! return(GenerateCode(argsSet, new OptimizationInfo(engine))); }
/// <summary> /// Generates IL for the script. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> protected override void GenerateCode(ArgVariable[] arguments, ILGenerator generator, OptimizationInfo optimizationInfo) { // Method signature: object FunctionDelegate(object thisObj, object[] arguments) // Transfer the function name into the scope. if (!string.IsNullOrEmpty(Name) && IncludeNameInScope && !HasArgument(Name) && optimizationInfo.MethodOptimizationHints.HasVariable(Name)) { var functionName = new NameExpression(InitialScope, Name); functionName.ApplyType(optimizationInfo, typeof(object)); functionName.GenerateSet(generator, optimizationInfo, false, typeof(object), delegate(bool two) { generator.LoadInt64(MethodID); generator.Call(ReflectionHelpers.MethodLookup_Load); if (two) { // Duplicate it: generator.Duplicate(); } }, false); } // Transfer the arguments object into the scope. if (MethodOptimizationHints.HasArguments && !HasArgument("arguments")) { var argsSet = new NameExpression(this.InitialScope, "arguments"); argsSet.ApplyType(optimizationInfo, typeof(object)); argsSet.GenerateSet(generator, optimizationInfo, false, typeof(object), delegate(bool two) { // argumentValues // Build an object[] from the arg values. // Define an array: int argCount = (arguments == null)?0 : arguments.Length; generator.LoadInt32(argCount); generator.NewArray(typeof(object)); for (int a = 0; a < argCount; a++) { // One of many args: ArgVariable currentArg = arguments[a]; generator.Duplicate(); generator.LoadInt32(a); currentArg.Get(generator); EmitConversion.ToAny(generator, currentArg.Type); generator.StoreArrayElement(typeof(object)); } generator.NewObject(ReflectionHelpers.Arguments_Constructor); if (two) { generator.Duplicate(); } }, false); } // Temp cache return var/target: var retVar = optimizationInfo.ReturnVariable; var retTarg = optimizationInfo.ReturnTarget; optimizationInfo.ReturnVariable = null; optimizationInfo.ReturnTarget = null; // Initialize any declarations. (this.InitialScope as DeclarativeScope).GenerateDeclarations(generator, optimizationInfo); // Generate code for the body of the function. this.AbstractSyntaxTree.GenerateCode(generator, optimizationInfo); // Define the return target - this is where the return statement jumps to. // ReturnTarget can be null if there were no return statements. if (optimizationInfo.ReturnTarget != null) { generator.DefineLabelPosition(optimizationInfo.ReturnTarget); } // Load the return value. If the variable is null, there were no return statements. if (optimizationInfo.ReturnVariable != null) { // Return the value stored in the variable. Will be null if execution hits the end // of the function without encountering any return statements. generator.LoadVariable(optimizationInfo.ReturnVariable); } // Restore: optimizationInfo.ReturnVariable = retVar; optimizationInfo.ReturnTarget = retTarg; }