/// <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)); } }