/// <param name="functionContext"> The function context to base this expression on. </param> internal void SetContext(FunctionMethodGenerator functionContext) { if (functionContext == null) { throw new ArgumentNullException("functionContext"); } this.context = functionContext; }
/// <summary> /// Saves the given generated method and returns an ID. For internal use only. /// </summary> /// <param name="generatedMethod"> The generated method to save. </param> /// <returns> The ID that was associated with the generated method. </returns> public static void SaveAs(long id, FunctionMethodGenerator generatedMethod) { if (generatedMethod == null) { throw new ArgumentNullException("generatedMethod"); } // Add to cache generatedMethodCache.Add(id, generatedMethod); }
public Type GetThisType(OptimizationInfo optimizationInfo, FunctionMethodGenerator methodGenerator) { // Note: This can't rely on either UserDefined or ResolvedMethod. // If methodGenerator is set then this is a new x() call, where x is always a user defined method. if (methodGenerator != null) { // This is a constructor call. The 'this' type is the same as the generators instance prototype: return(methodGenerator.GetInstancePrototype(optimizationInfo.Engine).Type); } return(typeof(object)); }
/// <summary> /// Counts how often search is called. /// </summary> // private static int SearchCount; /// <summary> /// A (slow!) search for the given MethodInfo. Used to find callee. Avoid unless expected to call repeatedly. /// </summary> public static UserDefinedFunction Search(MethodInfo mtd) { UserDefinedFunction udf; if (FastSearchCache != null) { if (FastSearchCache.TryGetValue(mtd, out udf)) { return(udf); } } // SearchCount++; foreach (KeyValuePair <long, FunctionMethodGenerator> kvp in generatedMethodCache) { FunctionMethodGenerator fmg = kvp.Value; if (fmg == null) { continue; } // Check if result uses the given method info. udf = fmg.Find(mtd); if (udf != null) { // Found it! if (FastSearchCache == null) { FastSearchCache = new Dictionary <MethodInfo, UserDefinedFunction>(); } // Add to cache: FastSearchCache[mtd] = udf; return(udf); } } return(null); }
/// <summary> /// Gets the set of types for each argument. /// </summary> internal Type[] GetArgumentTypes(OptimizationInfo optimizationInfo, bool includeThis, FunctionMethodGenerator methodGenerator) { // Get the args: Expression argumentsOperand = null; if (OperandCount > 1) { argumentsOperand = GetRawOperand(1); ListExpression argList = argumentsOperand as ListExpression; if (argList == null) { // Just one (or two, if it includes 'this'): if (includeThis) { return(new Type[] { GetThisType(optimizationInfo, methodGenerator), argumentsOperand.GetResultType(optimizationInfo) }); } return(new Type[] { argumentsOperand.GetResultType(optimizationInfo) }); } // Multiple parameters were recieved. IList <Expression> arguments = argList.Items; // Set the operand to null so it doesn't try to emit it as a single arg: argumentsOperand = null; int count = arguments.Count; // Include 'this' if needed: if (includeThis) { count++; } // Create the type set: Type[] result = new Type[count]; int start = 0; if (includeThis) { // Get the 'this' type: start = 1; result[0] = GetThisType(optimizationInfo, methodGenerator); } // Get the result type of each one: for (int i = start; i < count; i++) { result[i] = arguments[i - start].GetResultType(optimizationInfo); } return(result); } // Possibly just the 'this' keyword, if it's a UserDef: if (includeThis) { return(new Type[] { GetThisType(optimizationInfo, methodGenerator) }); } // No arguments. return(null); }
/// <summary> /// Resolves which function is being called where possible. /// </summary> internal override void ResolveVariables(OptimizationInfo optimizationInfo) { if (ResolvedMethod != null || UserDefined != null) { // Already resolved. return; } // Grab if this is a 'new' call: bool isConstructor = optimizationInfo.IsConstructCall; optimizationInfo.IsConstructCall = false; // Resolve kids: base.ResolveVariables(optimizationInfo); object resolvedMethod = null; if (this.Target is MemberAccessExpression) { // The function is a member access expression (e.g. "Math.cos()"). // Get the parent of the member (e.g. Math): MemberAccessExpression baseExpression = ((MemberAccessExpression)this.Target); // Get the property: Nitrassic.Library.PropertyVariable property = baseExpression.GetProperty(optimizationInfo); // It should be a callable method: if (property.Type == typeof(MethodGroup) || typeof(System.Reflection.MethodBase).IsAssignableFrom(property.Type)) { if (property.IsConstant) { // Great, grab the value: resolvedMethod = property.ConstantValue; } else { // This occurs when the method has collapsed. // The property is still a method though, so we know for sure it can be invoked. // It's now an instance property on the object. optimizationInfo.TypeError("Runtime method in use (not supported at the moment). Internal: #T1"); } } else if (property.Type == typeof(FunctionMethodGenerator)) { FunctionMethodGenerator fm = property.ConstantValue as FunctionMethodGenerator; if (fm != null) { // Get the arg types being passed into the method, including 'this': Type[] argTypes = GetArgumentTypes(optimizationInfo, true, isConstructor?fm:null); // Get a specific overload: Library.UserDefinedFunction udm = fm.GetCompiled(argTypes, optimizationInfo.Engine, isConstructor); resolvedMethod = udm.body; UserDefined = udm; } else { // Runtime resolve (property) optimizationInfo.TypeError("Runtime property in use (not supported at the moment). Internal: #T4"); } } else if (property.Type != typeof(object)) { throw new JavaScriptException( optimizationInfo.Engine, "TypeError", "Cannot run '" + property.Name + "' as a method because it's known to be a " + property.Type + "." ); } else { // Similar to above, but this time its something that might not even be a method optimizationInfo.TypeError("Runtime method in use (not supported at the moment). Internal: #T2"); } } if (resolvedMethod == null) { // Get target as a name expression: NameExpression nameExpr = Target as NameExpression; if (nameExpr != null && nameExpr.Variable != null) { if (nameExpr.Variable.IsConstant) { FunctionMethodGenerator fm = nameExpr.Variable.ConstantValue as FunctionMethodGenerator; if (fm != null) { // Get the arg types being passed into the method, including 'this': Type[] argTypes = GetArgumentTypes(optimizationInfo, true, isConstructor?fm:null); // Get a specific overload: Library.UserDefinedFunction udm = fm.GetCompiled(argTypes, optimizationInfo.Engine, isConstructor); resolvedMethod = udm.body; UserDefined = udm; } else { // This is a constructor for a built-in type. // Get the return type: Type returnType = Target.GetResultType(optimizationInfo); // Get the proto for it: Nitrassic.Library.Prototype proto = optimizationInfo.Engine.Prototypes.Get(returnType); // Note that these two special methods are always methods // or method groups so no checking is necessary. if (isConstructor) { resolvedMethod = proto.OnConstruct; } else { resolvedMethod = proto.OnCall; } } } else { #warning runtime resolve here. // -> E.g. new varName() or varName() optimizationInfo.TypeError("Runtime resolve in use (not supported at the moment). Internal: #T5"); } } else { // Something else (e.g. "eval()") // Get the return type: Type returnType = Target.GetResultType(optimizationInfo); // Get the proto for it: Nitrassic.Library.Prototype proto = optimizationInfo.Engine.Prototypes.Get(returnType); // Note that these two special methods are always methods // or method groups so no checking is necessary. if (isConstructor) { resolvedMethod = proto.OnConstruct; } else { resolvedMethod = proto.OnCall; } } } if (resolvedMethod == null) { // Runtime resolve only. ResolvedMethod = null; return; } // Note that it may be a MethodGroup, so let's resolve it further if needed. MethodGroup group = resolvedMethod as MethodGroup; if (group == null) { // It must be MethodBase - it can't be anything else: ResolvedMethod = resolvedMethod as System.Reflection.MethodBase; } else { // We have a group! Find the overload that we're after (excluding 'this' and it's never a constructor either): ResolvedMethod = group.Match(GetArgumentTypes(optimizationInfo, false, null)); } }