示例#1
0
        public void AppendExport(JST.NameSupply nameSupply, JST.Identifier rootId, CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, JST.Expression instance, Seq<JST.Statement> body, AppendCallExported appendCallExported)
        {
            var ctxt = CST.MessageContextBuilders.Member(env.Global, assemblyDef, typeDef, methodDef);
            if (methodDef.TypeArity > 0)
            {
                env.Log(new InvalidInteropMessage(ctxt, "polymorphic methods cannot be exported"));
                throw new DefinitionException();
            }
            if (typeDef.Arity > 0 && (methodDef.IsConstructor || methodDef.IsStatic))
            {
                env.Log
                    (new InvalidInteropMessage
                         (ctxt, "higher-kinded types cannot export static methods or instance constructors"));
                throw new DefinitionException();
            }

            CheckParameterAndReturnTypesAreImportableExportable(assemblyDef, typeDef, methodDef);

            var script = default(JST.Expression);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.ExportAttributeRef,
                 attributeHelper.TheScriptProperty,
                 true,
                 false,
                 ref script);
            var outer = typeDef.OuterPropertyOrEvent(methodDef.MethodSignature);

            if (!methodDef.IsStatic && methodDef.IsConstructor)
            {
                // Constructors
                if (methodDef.TypeArity > 0)
                    throw new InvalidOperationException("invalid constructor");
            }
            else if (outer != null)
            {
                var localScript = default(JST.Expression);
                var hasLocalScript = attributeHelper.GetValueFromMethod
                    (assemblyDef,
                     typeDef,
                     methodDef,
                     attributeHelper.ExportAttributeRef,
                     attributeHelper.TheScriptProperty,
                     false,
                     false,
                     ref localScript);
                switch (outer.Flavor)
                {
                case CST.MemberDefFlavor.Event:
                    {
                        var eventDef = (CST.EventDef)outer;
                        if (eventDef.Add != null && methodDef.Signature.Equals(eventDef.Add))
                            // Adder
                            script = hasLocalScript
                                         ? GetterSetterAdderRemoverNameFromMethod
                                               (assemblyDef, typeDef, methodDef, "add", localScript)
                                         : GetterSetterAdderRemoverNameFromPropertyEvent
                                               (assemblyDef, typeDef, methodDef, "add", script);
                        else if (eventDef.Remove != null && methodDef.Signature.Equals(eventDef.Remove))
                            // Remover
                            script = hasLocalScript
                                         ? GetterSetterAdderRemoverNameFromMethod
                                               (assemblyDef, typeDef, methodDef, "remove", localScript)
                                         : GetterSetterAdderRemoverNameFromPropertyEvent
                                               (assemblyDef, typeDef, methodDef, "remove", script);
                        else
                            throw new InvalidOperationException();
                        break;
                    }
                case CST.MemberDefFlavor.Property:
                    {
                        var propDef = (CST.PropertyDef)outer;
                        if (propDef.Get != null && methodDef.Signature.Equals(propDef.Get))
                            // Getter
                            script = hasLocalScript
                                         ? GetterSetterAdderRemoverNameFromMethod
                                               (assemblyDef, typeDef, methodDef, "get", localScript)
                                         : GetterSetterAdderRemoverNameFromPropertyEvent
                                               (assemblyDef, typeDef, methodDef, "get", script);
                        else if (propDef.Set != null && methodDef.Signature.Equals(propDef.Set))
                            // Setter
                            script = hasLocalScript
                                         ? GetterSetterAdderRemoverNameFromMethod
                                               (assemblyDef, typeDef, methodDef, "set", localScript)
                                         : GetterSetterAdderRemoverNameFromPropertyEvent
                                               (assemblyDef, typeDef, methodDef, "set", script);
                        else
                            throw new InvalidOperationException();
                        break;
                    }
                case CST.MemberDefFlavor.Field:
                case CST.MemberDefFlavor.Method:
                    throw new InvalidOperationException("not a property or event");
                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
            else
            {
                // Normal methods
                script = RecaseMethod(assemblyDef, typeDef, methodDef, script);
            }

            script = PrefixName(assemblyDef, typeDef, methodDef, script, true);
            AppendFinalExport
                (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, instance, body, appendCallExported);
        }
示例#2
0
        // 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));
            }
        }