// Take account of: // - BindToPrototype // - PassRootAsArgument // - PassInstanceAsArgument // - InlineParamsArray private void AppendFinalExport(JST.NameSupply nameSupply, JST.Identifier rootId, CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, JST.Expression script, JST.Expression instance, ISeq<JST.Statement> body, AppendCallExported appendCallExported) { if (script == null) throw new InvalidOperationException("expecting default script value"); var ctxt = CST.MessageContextBuilders.Member(env.Global, assemblyDef, typeDef, methodDef); var isInstance = !methodDef.IsStatic && !methodDef.IsConstructor; if (isInstance) { if (typeDef.Style is CST.ValueTypeStyle) { env.Log(new InvalidInteropMessage(ctxt, "cannot export instance methods from value types")); throw new DefinitionException(); } } var inlineParams = default(bool); attributeHelper.GetValueFromMethod (assemblyDef, typeDef, methodDef, attributeHelper.ExportAttributeRef, attributeHelper.TheInlineParamsArrayProperty, true, false, ref inlineParams); var lastArgIsParamsArray = methodDef.HasParamsArray(rootEnv) && inlineParams; var isPassRoot = default(bool); attributeHelper.GetValueFromMethod (assemblyDef, typeDef, methodDef, attributeHelper.ExportAttributeRef, attributeHelper.ThePassRootAsArgumentProperty, true, false, ref isPassRoot); var isProto = default(bool); attributeHelper.GetValueFromMethod (assemblyDef, typeDef, methodDef, attributeHelper.ExportAttributeRef, attributeHelper.TheBindToPrototypeProperty, true, false, ref isProto); var isPassInstance = default(bool); attributeHelper.GetValueFromMethod (assemblyDef, typeDef, methodDef, attributeHelper.ExportAttributeRef, attributeHelper.ThePassInstanceAsArgumentProperty, true, false, ref isPassInstance); var bindToInstance = isInstance && !isProto; if (bindToInstance != (instance != null)) throw new InvalidOperationException("expecting instance"); var captureThis = isInstance && !isPassInstance; var funcScript = script as JST.FunctionExpression; // Build the function to export var funcBody = new Seq<JST.Statement>(); var funcParameters = new Seq<JST.Identifier>(); var funcCallArgs = new Seq<JST.Expression>(); var funcArity = methodDef.Arity; if ((methodDef.IsConstructor && !methodDef.IsStatic) || captureThis) // unmanaged will not pass the instance funcArity--; if (lastArgIsParamsArray) // managed params args will be extracted from remainder of unmanaged arguments funcArity--; if (captureThis) funcCallArgs.Add(new JST.ThisExpression()); for (var i = 0; i < funcArity; i++) { var id = nameSupply.GenSym(); funcParameters.Add(id); funcCallArgs.Add(id.ToE()); } if (lastArgIsParamsArray) { var iId = nameSupply.GenSym(); var arrId = nameSupply.GenSym(); funcBody.Add(JST.Statement.Var(arrId, new JST.ArrayLiteral())); funcBody.Add (new JST.ForStatement (new JST.ForVarLoopClause (iId, new JST.NumericLiteral(funcArity), new JST.BinaryExpression (iId.ToE(), JST.BinaryOp.LessThan, JST.Expression.Dot(Constants.arguments.ToE(), Constants.length)), new JST.UnaryExpression(iId.ToE(), JST.UnaryOp.PostIncrement)), new JST.Statements (JST.Statement.DotCall (arrId.ToE(), Constants.push, new JST.IndexExpression(Constants.arguments.ToE(), iId.ToE()))))); funcCallArgs.Add(arrId.ToE()); } appendCallExported(nameSupply, assemblyDef, typeDef, methodDef, funcBody, funcCallArgs); var func = new JST.FunctionExpression(funcParameters, new JST.Statements(funcBody)); // Export the above function if (funcScript != null) { var scriptArgs = new Seq<JST.Expression>(); if (isPassRoot) scriptArgs.Add(rootId.ToE()); if (bindToInstance) scriptArgs.Add(instance); scriptArgs.Add(func); if (funcScript.Parameters.Count != scriptArgs.Count) { env.Log(new InvalidInteropMessage(ctxt, "invalid function arity")); throw new DefinitionException(); } body.Add(new JST.ExpressionStatement(new JST.CallExpression(script, scriptArgs))); } else { if (bindToInstance) script = JST.Expression.Dot(instance, JST.Expression.ExplodePath(script)); EnsurePathExists(body, script, !bindToInstance); body.Add(JST.Statement.Assignment(script, func)); } }
// Take acccount of: // - PassRootAsArgument // - PassInstanceAsArgument // - InlineParamsArray private JST.Expression AppendFinalImport(JST.NameSupply nameSupply, JST.Identifier rootId, CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, JST.Expression script, ISeq<JST.Statement> body, IImSeq<JST.Expression> arguments) { var isInstanceMethod = !(methodDef.IsStatic || methodDef.IsConstructor); var scriptExpectsRoot = default(bool); attributeHelper.GetValueFromMethod (assemblyDef, typeDef, methodDef, attributeHelper.ImportAttributeRef, attributeHelper.ThePassRootAsArgumentProperty, true, false, ref scriptExpectsRoot); var passInstAsArg = default(bool); attributeHelper.GetValueFromMethod (assemblyDef, typeDef, methodDef, attributeHelper.ImportAttributeRef, attributeHelper.ThePassInstanceAsArgumentProperty, true, false, ref passInstAsArg); var instanceIsThis = isInstanceMethod && !passInstAsArg; var inlineParams = default(bool); attributeHelper.GetValueFromMethod (assemblyDef, typeDef, methodDef, attributeHelper.ImportAttributeRef, attributeHelper.TheInlineParamsArrayProperty, true, false, ref inlineParams); var lastArgIsParamsArray = methodDef.HasParamsArray(rootEnv) && inlineParams; var funcScript = script as JST.FunctionExpression; var nextArg = 0; var instArg = default(JST.Expression); if (instanceIsThis) { // Instance argument will be the first arg to 'call' or 'apply', or the target of a '.' call. instArg = arguments[nextArg++]; if (lastArgIsParamsArray && !instArg.IsDuplicatable) { // Make sure instance argument is evaluated before the remaining arguments var instId = nameSupply.GenSym(); body.Add(JST.Statement.Var(instId, instArg)); instArg = instId.ToE(); } } else { if (lastArgIsParamsArray) instArg = new JST.NullExpression(); } var knownArgs = 0; var call = default(JST.Expression); if (lastArgIsParamsArray) { // We mush build script args at runtime var argsId = nameSupply.GenSym(); body.Add(JST.Statement.Var(argsId, new JST.ArrayLiteral())); if (scriptExpectsRoot) { body.Add(JST.Statement.DotCall(argsId.ToE(), Constants.push, rootId.ToE())); knownArgs++; } while (nextArg < arguments.Count - 1) { body.Add(JST.Statement.DotCall(argsId.ToE(), Constants.push, arguments[nextArg++])); knownArgs++; } var arrArg = arguments[nextArg]; if (!arrArg.IsDuplicatable) { var arrId = nameSupply.GenSym(); body.Add(JST.Statement.Var(arrId, arrArg)); arrArg = arrId.ToE(); } var iId = nameSupply.GenSym(); body.Add (new JST.IfStatement (JST.Expression.IsNotNull(arrArg), new JST.Statements (new JST.ForStatement (new JST.ForVarLoopClause (iId, new JST.NumericLiteral(0), new JST.BinaryExpression (iId.ToE(), JST.BinaryOp.LessThan, JST.Expression.Dot(arrArg, Constants.length)), new JST.UnaryExpression(iId.ToE(), JST.UnaryOp.PostIncrement)), new JST.Statements (JST.Statement.DotCall (argsId.ToE(), Constants.push, new JST.IndexExpression(arrArg, iId.ToE()))))))); if (funcScript != null) { // var args = ...; var x = script; x.apply(this/null, args) var scriptId = nameSupply.GenSym(); body.Add(JST.Statement.Var(scriptId, funcScript)); call = JST.Expression.DotCall(scriptId.ToE(), Constants.apply, instArg, argsId.ToE()); } else { if (instanceIsThis) { // var args = ...; (this.script).apply(this, args); call = JST.Expression.DotCall (JST.Expression.Dot(instArg, JST.Expression.ExplodePath(script)), Constants.apply, instArg, argsId.ToE()); } else { // var args = ...; script.apply(null, args) call = JST.Expression.DotCall(script, Constants.apply, instArg, argsId.ToE()); } } } else { var callArgs = new Seq<JST.Expression>(); if (instanceIsThis && funcScript != null) callArgs.Add(instArg); if (scriptExpectsRoot) { callArgs.Add(rootId.ToE()); knownArgs++; } while (nextArg < arguments.Count) { callArgs.Add(arguments[nextArg++]); knownArgs++; } if (instanceIsThis) { if (funcScript != null) { // var x = script; x.call(this, arg1, ..., argn) var scriptId = nameSupply.GenSym(); body.Add(JST.Statement.Var(scriptId, funcScript)); call = JST.Expression.DotCall(scriptId.ToE(), Constants.call, callArgs); } else // this.script(arg1, ..., angn) call = new JST.CallExpression (JST.Expression.Dot(instArg, JST.Expression.ExplodePath(script)), callArgs); } else // script(arg1, ..., argn) call = new JST.CallExpression(script, callArgs); } if (funcScript != null) { if (funcScript.Parameters.Count < knownArgs) { var ctxt = CST.MessageContextBuilders.Member(env.Global, assemblyDef, typeDef, methodDef); env.Log(new InvalidInteropMessage(ctxt, "script accepts too few arguments")); throw new DefinitionException(); } } return call; }
public static TypeCompilerEnvironment EnterType (CompilerEnvironment env, JST.NameSupply nameSupply, JST.Identifier rootId, JST.Identifier assemblyId, JST.Identifier typeId, CST.TypeEnvironment typeEnv, TypeTrace typeTrace) { var typeBoundTypeParameterIds = new Seq<JST.Identifier>(); for (var i = 0; i < typeEnv.Type.Arity; i++) typeBoundTypeParameterIds.Add(nameSupply.GenSym()); var res = new TypeCompilerEnvironment (typeEnv.Global, typeEnv.SkolemDefs, typeEnv.Assembly, typeEnv.Type, typeEnv.TypeBoundArguments, env, nameSupply, rootId, assemblyId, typeId, typeBoundTypeParameterIds, typeTrace); res.BindSpecial(); return res; }