Esempio n. 1
0
        // Take account of:
        //  - BindToPrototype
        //  - PassRootAsArgument
        //  - PassInstanceAsArgument
        //  - InlineParamsArray
        private ExportMethodInfo FinalExportInfo(MessageContext ctxt, Func<JST.Identifier> gensym, JST.Identifier rootId, CCI.Method methodDefn, JST.Expression script)
        {
            if (script == null)
                throw new InvalidOperationException("expecting default script value");

            var isInstance = !methodDefn.IsStatic && !(methodDefn is CCI.InstanceInitializer);
            if (isInstance)
            {
                var declType = methodDefn.DeclaringType;
                if (declType.IsValueType)
                {
                    env.Log(new InvalidInteropMessage
                        (RewriterMsgContext.Method(ctxt, methodDefn), "cannot export instance methods from value types"));
                    throw new DefinitionException();
                }
            }

            var lastArgIsParamsArray = LastArgIsParamsArray(ctxt, methodDefn) &&
                                       interopTypes.GetValue
                                           (ctxt,
                                            methodDefn,
                                            env.ExportAttributeType,
                                            interopTypes.TheInlineParamsArrayProperty);
            var isPassRoot = interopTypes.GetValue
                (ctxt, methodDefn, env.ExportAttributeType, interopTypes.ThePassRootAsArgumentProperty);
            var isProto = interopTypes.GetValue
                (ctxt, methodDefn, env.ExportAttributeType, interopTypes.TheBindToPrototypeProperty);
            var isPassInstance = interopTypes.GetValue
                (ctxt, methodDefn, env.ExportAttributeType, interopTypes.ThePassInstanceAsArgumentProperty);
            var bindToInstance = isInstance && !isProto;
            var captureThis = isInstance && !isPassInstance;

            var expectedScriptArity = (isPassRoot ? 1 : 0) + (bindToInstance ? 1 : 0) + 1;
            CheckScriptArity(ctxt, methodDefn, script, expectedScriptArity);

            var function = default(JST.FunctionExpression);

            if (gensym != null)
            {
                var parameters = new Seq<JST.Identifier>();
                var body = new Seq<JST.Statement>();

                var callArgs = new Seq<JST.Expression>();
                if (isPassRoot)
                    callArgs.Add(rootId.ToE());
                var instArgId = default(JST.Identifier);
                if (bindToInstance)
                {
                    instArgId = gensym();
                    parameters.Add(instArgId);
                    callArgs.Add(instArgId.ToE());
                }
                var funcArgId = gensym();
                parameters.Add(funcArgId);

                if (captureThis || lastArgIsParamsArray)
                {
                    var innerParameters = new Seq<JST.Identifier>();
                    var innerBody = new Seq<JST.Statement>();
                    var innerArgs = new Seq<JST.Expression>();
                    var methodArity = Arity(methodDefn);
                    for (var i = 0; i < methodArity; i++)
                    {
                        if (i == 0 && captureThis)
                            innerArgs.Add(new JST.ThisExpression());
                        else if (i == methodArity - 1 && lastArgIsParamsArray)
                        {
                            var iId = gensym();
                            var arrId = gensym();
                            innerBody.Add(JST.Statement.Var(arrId, new JST.ArrayLiteral()));
                            innerBody.Add
                                (new JST.ForStatement
                                     (new JST.ForVarLoopClause
                                          (iId,
                                           new JST.NumericLiteral(methodArity - 1),
                                           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())))));
                            innerArgs.Add(arrId.ToE());
                        }
                        else
                        {
                            var innerArgId = gensym();
                            innerParameters.Add(innerArgId);
                            innerArgs.Add(innerArgId.ToE());
                        }
                    }
                    if (ReturnType(methodDefn) == null)
                    {
                        innerBody.Add(JST.Statement.Call(funcArgId.ToE(), innerArgs));
                        innerBody.Add(new JST.ReturnStatement());
                    }
                    else
                        innerBody.Add(new JST.ReturnStatement(new JST.CallExpression(funcArgId.ToE(), innerArgs)));
                    var innerFunction = new JST.FunctionExpression(innerParameters, new JST.Statements(innerBody));
                    callArgs.Add(innerFunction);
                }
                else
                    callArgs.Add(funcArgId.ToE());

                if (script is JST.FunctionExpression)
                    body.Add(new JST.ExpressionStatement(new JST.CallExpression(script, callArgs)));
                else
                {
                    var i = 0;
                    if (bindToInstance)
                        script = JST.Expression.Dot(callArgs[i++], JST.Expression.ExplodePath(script));
                    EnsurePathExists(body, script, !bindToInstance);
                    body.Add(JST.Statement.Assignment(script, callArgs[i]));
                }

                function = new JST.FunctionExpression(parameters, new JST.Statements(body));
            }

            return new ExportMethodInfo { MethodDefn = methodDefn, Script = function, BindToInstance = bindToInstance };
        }
Esempio n. 2
0
        // Take acccount of
        //   - PassRootAsArgument
        //   - PassInstanceAsArgument
        //   - InlineParamsArray
        private ImportMethodInfo FinalImportScript(MessageContext ctxt, Func<JST.Identifier> gensym, JST.Identifier rootId, CCI.Method methodDefn, JST.Expression script, bool isNew)
        {
            if (script == null)
                throw new InvalidOperationException("expecting default script value");

            var lastArgIsParamsArray = LastArgIsParamsArray(ctxt, methodDefn) && interopTypes.GetValue(ctxt, methodDefn, env.ImportAttributeType, interopTypes.TheInlineParamsArrayProperty);
            var methodArity = Arity(methodDefn);
            var isInstanceMethod = !(methodDefn.IsStatic || methodDefn is CCI.InstanceInitializer);
            var scriptExpectsRoot = interopTypes.GetValue
                (ctxt, methodDefn, env.ImportAttributeType, interopTypes.ThePassRootAsArgumentProperty);
            var instanceIsThis = isInstanceMethod &&
                                 !interopTypes.GetValue
                                      (ctxt,
                                       methodDefn,
                                       env.ImportAttributeType,
                                       interopTypes.ThePassInstanceAsArgumentProperty);
            var expectedScriptArity = methodArity - (lastArgIsParamsArray ? 1 : 0) + (scriptExpectsRoot ? 1 : 0) -
                                      (instanceIsThis ? 1 : 0);
            CheckScriptArity(ctxt, methodDefn, script, expectedScriptArity);

            var function = default(JST.FunctionExpression);
            if (gensym != null)
            {
                var parameters = new Seq<JST.Identifier>();
                var body = new Seq<JST.Statement>();

                var callArgs = new Seq<JST.Expression>();

                if (lastArgIsParamsArray)
                {
                    var argsId = gensym();
                    body.Add(JST.Statement.Var(argsId, new JST.ArrayLiteral()));

                    if (scriptExpectsRoot)
                        body.Add(JST.Statement.DotCall(argsId.ToE(), Constants.push, rootId.ToE()));

                    if (!isInstanceMethod)
                        callArgs.Add(new JST.NullExpression());

                    for (var i = 0; i < methodArity; i++)
                    {
                        var id = gensym();
                        parameters.Add(id);
                        if (isInstanceMethod && i == 0)
                        {
                            if (instanceIsThis)
                                callArgs.Add(id.ToE());
                            else
                            {
                                callArgs.Add(new JST.NullExpression());
                                body.Add(JST.Statement.DotCall(argsId.ToE(), Constants.push, id.ToE()));
                            }
                        }
                        else if (i == methodArity - 1)
                        {
                            var iId = gensym();
                            body.Add
                                (new JST.IfStatement
                                     (JST.Expression.IsNotNull(id.ToE()),
                                      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(id.ToE(), Constants.length)),
                                                     new JST.UnaryExpression(iId.ToE(), JST.UnaryOp.PostIncrement)),
                                                new JST.Statements
                                                    (JST.Statement.DotCall
                                                         (argsId.ToE(),
                                                          Constants.push,
                                                          new JST.IndexExpression(id.ToE(), iId.ToE())))))));
                        }
                        else
                            body.Add(JST.Statement.DotCall(argsId.ToE(), Constants.push, id.ToE()));
                    }
                    if (script is JST.FunctionExpression)
                    {
                        var funcId = gensym();
                        body.Add(JST.Statement.Var(funcId, script));
                        script = JST.Expression.Dot(funcId.ToE(), Constants.apply);
                    }
                    else
                        script = JST.Expression.Dot(script, Constants.apply);
                    callArgs.Add(argsId.ToE());
                }
                else
                {
                    if (scriptExpectsRoot)
                        callArgs.Add(rootId.ToE());

                    for (var i = 0; i < methodArity; i++)
                    {
                        var id = gensym();
                        parameters.Add(id);
                        if (i == 0 && instanceIsThis)
                        {
                            if (script is JST.FunctionExpression)
                            {
                                callArgs.Insert(0, id.ToE());
                                var funcId = gensym();
                                body.Add(JST.Statement.Var(funcId, script));
                                script = JST.Expression.Dot(funcId.ToE(), Constants.call);
                            }
                            else
                                script = JST.Expression.Dot(id.ToE(), JST.Expression.ExplodePath(script));
                        }
                        else
                            callArgs.Add(id.ToE());
                    }
                }

                var exp = (JST.Expression)new JST.CallExpression(script, callArgs);
                if (isNew)
                    exp = new JST.NewExpression(exp);

                if (ReturnType(methodDefn) == null)
                    body.Add(new JST.ExpressionStatement(exp));
                else
                    body.Add(new JST.ReturnStatement(exp));

                function = new JST.FunctionExpression(parameters, new JST.Statements(body));
            }
            return new ImportMethodInfo { MethodDefn = methodDefn, Script = function };
        }
Esempio n. 3
0
        public ImportMethodInfo ImportInfo(MessageContext ctxt, Func<JST.Identifier> gensym, JST.Identifier rootId, CCI.Method methodDefn)
        {
            if (!IsImported(ctxt, methodDefn))
                return null;

            if (gensym != null)
                CheckParameterAndReturnTypesAreImportableExportable(ctxt, methodDefn);

            var methodArity = Arity(methodDefn);
            var script = interopTypes.GetValue(ctxt, methodDefn, env.ImportAttributeType, interopTypes.TheScriptProperty);

            if (methodDefn is CCI.InstanceInitializer)
            {
                // XREF1171
                // Constructor
                if (script == null)
                {
                    switch (
                        interopTypes.GetValue
                            (ctxt, methodDefn, env.ImportAttributeType, interopTypes.TheCreationProperty))
                    {
                        case Creation.Constructor:
                            script = PrefixName(ctxt, methodDefn, null, false);
                            break;
                        case Creation.Object:
                            if (methodArity > 0)
                            {
                                env.Log(new InvalidInteropMessage
                                    (RewriterMsgContext.Method(ctxt, methodDefn),
                                     "imported constructors for object literals cannot have arguments"));
                                throw new DefinitionException();
                            }
                            script = Constants.Object.ToE();
                            break;
                        case Creation.Array:
                            script = Constants.Array.ToE();
                            break;
                        default:
                            throw new ArgumentOutOfRangeException();
                    }
                    return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, true);
                }
                else if (script is JST.FunctionExpression)
                    return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false);
                else
                {
                    script = PrefixName(ctxt, methodDefn, script, false);
                    return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, true);
                }
            }
            else
            {
                if (methodDefn.DeclaringMember != null)
                {
                    var isOnMethod = interopTypes.HasAttribute(methodDefn, env.ImportAttributeType, false);
                    var localScript = isOnMethod ? interopTypes.GetValue(ctxt, methodDefn, env.ImportAttributeType, interopTypes.TheScriptProperty, false) : default(JST.Expression);

                    var prop = methodDefn.DeclaringMember as CCI.Property;
                    if (prop != null)
                    {
                        // XREF1187
                        if (methodDefn == prop.Getter)
                        {
                            // Getter
                            if (isOnMethod)
                            {
                                script = PrefixName
                                    (ctxt,
                                     methodDefn,
                                     GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "get", localScript), false);
                                return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false);
                            }
                            else if (script != null && script is JST.FunctionExpression)
                            {
                                env.Log(new InvalidInteropMessage
                                    (RewriterMsgContext.Method(ctxt, methodDefn),
                                     "property import script cannot be a function"));
                                throw new DefinitionException();
                            }
                            else
                            {
                                var function = default(JST.FunctionExpression);
                                if (gensym != null)
                                {
                                    var parameters = new Seq<JST.Identifier>();
                                    var body = new Seq<JST.Statement>();

                                    for (var i = 0; i < methodArity; i++)
                                        parameters.Add(gensym());
                                    if (script == null && methodArity == 2 && !methodDefn.IsStatic)
                                        body.Add
                                            (new JST.ReturnStatement
                                                 (new JST.IndexExpression
                                                      (parameters[0].ToE(), parameters[1].ToE())));
                                    else
                                    {
                                        script = PrefixName
                                            (ctxt, methodDefn, RecasePropertyEvent(ctxt, methodDefn, script), false);
                                        if (methodDefn.IsStatic && methodArity == 0)
                                            body.Add(new JST.ReturnStatement(script));
                                        else if (!methodDefn.IsStatic && methodArity == 1)
                                            body.Add
                                                (new JST.ReturnStatement
                                                     (JST.Expression.Dot
                                                          (parameters[0].ToE(),
                                                           JST.Expression.ExplodePath(script))));
                                        else
                                        {
                                            env.Log(new InvalidInteropMessage
                                                (RewriterMsgContext.Method(ctxt, methodDefn),
                                                 "additional getter parameters not supported for default getters"));
                                            throw new DefinitionException();
                                        }
                                    }
                                    function = new JST.FunctionExpression(parameters, new JST.Statements(body));
                                }
                                return new ImportMethodInfo { MethodDefn = methodDefn, Script = function };
                            }
                        }
                        else if (methodDefn == prop.Setter)
                        {
                            // Setter
                            if (isOnMethod)
                            {
                                script = PrefixName
                                    (ctxt,
                                     methodDefn,
                                     GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "set", localScript), false);
                                return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false);
                            }
                            else if (script != null && script is JST.FunctionExpression)
                            {
                                env.Log(new InvalidInteropMessage
                                    (RewriterMsgContext.Method(ctxt, methodDefn),
                                     "property import script cannot be a function"));
                                throw new DefinitionException();
                            }
                            else
                            {
                                var function = default(JST.FunctionExpression);
                                if (gensym != null)
                                {
                                    var parameters = new Seq<JST.Identifier>();
                                    var body = new Seq<JST.Statement>();

                                    for (var i = 0; i < methodArity; i++)
                                        parameters.Add(gensym());
                                    if (script == null && methodArity == 3 && !methodDefn.IsStatic)
                                        body.Add
                                            (JST.Statement.IndexAssignment
                                                 (parameters[0].ToE(),
                                                  parameters[1].ToE(),
                                                  parameters[2].ToE()));
                                    else
                                    {
                                        script = PrefixName
                                            (ctxt, methodDefn, RecasePropertyEvent(ctxt, methodDefn, script), false);
                                        if (methodDefn.IsStatic && methodArity == 1)
                                            body.Add
                                                (JST.Statement.Assignment(script, parameters[0].ToE()));
                                        else if (!methodDefn.IsStatic && methodArity == 2)
                                            body.Add
                                                (JST.Statement.Assignment
                                                     (JST.Expression.Dot
                                                          (parameters[0].ToE(),
                                                           JST.Expression.ExplodePath(script)),
                                                      parameters[1].ToE()));
                                        else
                                        {
                                            env.Log(new InvalidInteropMessage
                                                (RewriterMsgContext.Method(ctxt, methodDefn),
                                                 "additional setter parameters not supported for default setters"));
                                            throw new DefinitionException();
                                        }
                                    }
                                    function = new JST.FunctionExpression(parameters, new JST.Statements(body));
                                }
                                return new ImportMethodInfo { MethodDefn = methodDefn, Script = function };
                            }
                        }
                        else
                            throw new InvalidOperationException();
                    }
                    else
                    {
                        var evnt = methodDefn.DeclaringMember as CCI.Event;
                        if (evnt != null)
                        {
                            // XREF1201
                            if (methodDefn == evnt.HandlerAdder)
                            {
                                // Adder
                                if (isOnMethod)
                                {
                                    script = PrefixName
                                        (ctxt,
                                         methodDefn,
                                         GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "add", localScript), false);
                                    return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false);
                                }
                                else if (script != null && script is JST.FunctionExpression)
                                {
                                    env.Log(new InvalidInteropMessage
                                        (RewriterMsgContext.Method(ctxt, methodDefn),
                                         "event import script cannot be a function"));
                                    throw new DefinitionException();
                                }
                                else
                                {
                                    var function = default(JST.FunctionExpression);
                                    if (gensym != null)
                                    {
                                        var parameters = new Seq<JST.Identifier>();
                                        var body = new Seq<JST.Statement>();

                                        for (var i = 0; i < methodArity; i++)
                                            parameters.Add(gensym());
                                        script = PrefixName
                                            (ctxt, methodDefn, RecasePropertyEvent(ctxt, methodDefn, script), false);
                                        if (methodDefn.IsStatic)
                                            body.Add
                                                (JST.Statement.Assignment(script, parameters[0].ToE()));
                                        else
                                            body.Add
                                                (JST.Statement.Assignment
                                                     (JST.Expression.Dot
                                                          (parameters[0].ToE(),
                                                           JST.Expression.ExplodePath(script)),
                                                      parameters[1].ToE()));
                                        function = new JST.FunctionExpression(parameters, new JST.Statements(body));
                                    }
                                    return new ImportMethodInfo { MethodDefn = methodDefn, Script = function };
                                }
                            }
                            else if (methodDefn == evnt.HandlerRemover)
                            {
                                // Remover
                                if (isOnMethod)
                                {
                                    script = PrefixName
                                        (ctxt,
                                         methodDefn,
                                         GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "remove", localScript), false);
                                    return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false);
                                }
                                else if (script != null && script is JST.FunctionExpression)
                                {
                                    env.Log(new InvalidInteropMessage
                                        (RewriterMsgContext.Method(ctxt, methodDefn),
                                         "event import script cannot be a function"));
                                    throw new DefinitionException();
                                }
                                else
                                {
                                    var function = default(JST.FunctionExpression);
                                    if (gensym != null)
                                    {
                                        var parameters = new Seq<JST.Identifier>();
                                        var body = new Seq<JST.Statement>();

                                        for (var i = 0; i < methodArity; i++)
                                            parameters.Add(gensym());
                                        script = PrefixName
                                            (ctxt, methodDefn, RecasePropertyEvent(ctxt, methodDefn, script), false);
                                        if (methodDefn.IsStatic)
                                            body.Add
                                                (JST.Statement.Assignment(script, parameters[0].ToE()));
                                        else
                                            body.Add
                                                (JST.Statement.Assignment
                                                     (JST.Expression.Dot
                                                          (parameters[0].ToE(),
                                                           JST.Expression.ExplodePath(script)),
                                                      parameters[1].ToE()));

                                        function = new JST.FunctionExpression(parameters, new JST.Statements(body));
                                    }
                                    return new ImportMethodInfo { MethodDefn = methodDefn, Script = function };
                                }
                            }
                            else
                                throw new InvalidOperationException();
                        }
                        else
                            throw new InvalidOperationException();
                    }
                }
                else
                {
                    // XREF1153
                    // Normal method
                    script = PrefixName(ctxt, methodDefn, RecaseMember(ctxt, methodDefn, script), false);
                    return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false);
                }
            }
        }
Esempio n. 4
0
        // ----------------------------------------------------------------------
        // Entry point from TypeCompiler
        // ----------------------------------------------------------------------

        public void Emit(ISeq<JST.Statement> body, JST.Expression target)
        {
            if (env.BreakOnBreak &&
                env.AttributeHelper.MethodHasAttribute(methEnv.Assembly, methEnv.Type, methEnv.Method, env.AttributeHelper.BreakAttributeRef, false, false))
                System.Diagnostics.Debugger.Break();

            var methodName = CST.CSTWriter.WithAppend(env.Global, CST.WriterStyle.Debug, methEnv.MethodRef.Append);
            var methodSlot = env.GlobalMapping.ResolveMethodDefToSlot(methEnv.Assembly, methEnv.Type, methEnv.Method);
            var method = Method(methodName);

            switch (mode)
            {
                case MethodCompilationMode.SelfContained:
                {
                    if (target != null)
                        throw new InvalidOperationException("not expecting target in self-contained mode");
                    var assmName = CST.CSTWriter.WithAppend
                        (env.Global, CST.WriterStyle.Uniform, methEnv.Assembly.Name.Append);
                    var typeSlot = env.GlobalMapping.ResolveTypeDefToSlot(methEnv.Assembly, methEnv.Type);

                    var func = new JST.FunctionExpression
                        (new Seq<JST.Identifier> { rootId, assemblyId, typeDefinitionId },
                         new JST.Statements(new JST.ReturnStatement(method)));
                    var methodLoader = new Seq<JST.Statement>();
                    if (env.DebugMode)
                        methodLoader.Add(new JST.CommentStatement(methodName));
                    methodLoader.Add
                        (JST.Statement.DotCall
                             (new JST.Identifier(env.Root).ToE(),
                              Constants.RootBindMethod,
                              new JST.StringLiteral(assmName),
                              new JST.StringLiteral(typeSlot),
                              new JST.BooleanLiteral(env.InteropManager.IsStatic(methEnv.Assembly, methEnv.Type, methEnv.Method)),
                              new JST.StringLiteral(methodSlot),
                              func));
                    var methodProgram = new JST.Program(new JST.Statements(methodLoader));
                    var methodFileName = Path.Combine
                        (env.OutputDirectory,
                         Path.Combine
                             (JST.Lexemes.StringToFileName(assmName),
                              Path.Combine(typeSlot, Path.Combine(methodSlot, Constants.MethodFileName))));
                    methodProgram.ToFile(methodFileName, env.PrettyPrint);
                    env.Log(new GeneratedJavaScriptFile("method '" + methEnv.MethodRef + "'", methodFileName));
                    break;
                }
            case MethodCompilationMode.DirectBind:
                {
                    if (target == null)
                        throw new InvalidOperationException("expecting target in self-contained mode");
                    if (env.DebugMode)
                        body.Add(new JST.CommentStatement(methodName));
                    body.Add
                        (JST.Statement.Assignment(JST.Expression.Dot(target, new JST.Identifier(methodSlot)), method));
                    break;
                }
            default:
                throw new ArgumentOutOfRangeException();
            }
        }
Esempio n. 5
0
        private JST.FunctionExpression MethodImpl(CST.CSTWriter trace)
        {
            if (trace != null)
                trace.Trace
                    ("Original IL method",
                     w =>
                     {
                         methEnv.Method.AppendDefinition(w);
                         w.EndLine();
                     });

            var func = ImportedMethod(trace) ?? NormalMethod(trace);

            // Simplify
            var simpCtxt = new JST.SimplifierContext(false, env.DebugMode, simpNameSupply, IsValue);
            func = (JST.FunctionExpression)func.Simplify(simpCtxt, EvalTimes.Bottom);
            if (trace != null)
                trace.Trace
                    ("After JavaScript simplification",
                     w =>
                     {
                         func.Append(w);
                         w.EndLine();
                     });

            if (env.DebugMode)
            {
                // Add debugging assistance
                var l = 0;
                Func<int> nextLine = () => { return l++; };
                var lineCountIds = new Set<JST.Identifier>();
                var debugStmnts = WithLineCounts(func.Body, nextLine, 0, lineCountIds);
                lineCountIds.Add(Constants.DebugCurrentLine);
                var debugBody = new Seq<JST.Statement>();
                debugBody.Add
                    (new JST.VariableStatement(lineCountIds.Select(id => new JST.VariableDeclaration(id)).ToSeq()));
                foreach (var s in debugStmnts.Body)
                    debugBody.Add(s);
                var exId = simpNameSupply.GenSym();
                var funcBody = new Seq<JST.Statement>();
#if !JSCRIPT_IS_CORRECT
                funcBody.Add(JST.Statement.Var(exId));
#endif
                funcBody.Add
                    (new JST.TryStatement
                         (new JST.Statements(debugBody),
                          new JST.CatchClause
                              (exId,
                               new JST.Statements
                                   (JST.Statement.DotCall(rootId.ToE(), Constants.RootDebugger, exId.ToE()),
                                    new JST.ThrowStatement(exId.ToE())))));
                func = new JST.FunctionExpression(func.Name, func.Parameters, new JST.Statements(funcBody));
            }

            if (trace != null)
                trace.Trace
                    ("Final JavaScript method",
                     w =>
                     {
                         func.Append(w);
                         w.EndLine();
                     });

            return func;
        }
Esempio n. 6
0
        // ----------------------------------------------------------------------
        // SPECIAL CASE: Imported methods
        // ----------------------------------------------------------------------

        public JST.FunctionExpression ImportedMethod(CST.CSTWriter trace)
        {
            if (!env.InteropManager.IsImported(methEnv.Assembly, methEnv.Type, methEnv.Method))
                return null;

            var isFactory = env.InteropManager.IsFactory(methEnv.Assembly, methEnv.Type, methEnv.Method);
            var delta = isFactory ? 1 : 0;

            var methCompEnv = MethodCompilerEnvironment.EnterUntranslatedMethod
                (env, outerNameSupply, nameSupply, rootId, assemblyId, typeDefinitionId, methEnv, parent.TypeTrace);

            var parameters = new Seq<JST.Identifier>();
            var body = new Seq<JST.Statement>();
            foreach (var id in methCompEnv.TypeBoundTypeParameterIds)
                parameters.Add(id);
            foreach (var id in methCompEnv.MethodBoundTypeParameterIds)
                parameters.Add(id);
            var valueParameters = new Seq<JST.Identifier>();
            for (var i = delta; i < methCompEnv.Method.Arity; i++)
            {
                var id = methCompEnv.ValueParameterIds[i];
                if (i == 0 && !methCompEnv.Method.IsStatic && methCompEnv.Type.Arity == 0)
                    body.Add(JST.Statement.Var(id, new JST.ThisExpression()));
                else
                    parameters.Add(id);
                valueParameters.Add(id);
            }

            // Take account of imports and exports on args/result to improve type sharing
            var usage = new CST.Usage();
            for (var i = delta; i < methCompEnv.Method.Arity; i++)
            {
                if (!env.InteropManager.IsNoInteropParameter(methEnv.Assembly, methEnv.Type, methEnv.Method, i))
                    methCompEnv.SubstituteType(methCompEnv.Method.ValueParameters[i].Type).AccumUsage(usage, true);
            }
            if (isFactory)
            {
                if (!env.InteropManager.IsNoInteropParameter(methEnv.Assembly, methEnv.Type, methEnv.Method, 0))
                    methCompEnv.TypeRef.AccumUsage(usage, true);
            }
            else if (methCompEnv.Method.Result != null)
            {
                if (!env.InteropManager.IsNoInteropResult(methEnv.Assembly, methEnv.Type, methEnv.Method))
                    methCompEnv.SubstituteType(methCompEnv.Method.Result.Type).AccumUsage(usage, true);
            }
            methCompEnv.BindUsage(body, usage);


            if (methCompEnv.Method.IsConstructor && !methCompEnv.Method.IsStatic)
            {
                // Constructor or factory
                var isValType = methCompEnv.Type.Style is CST.ValueTypeStyle;
                var callArgs = new Seq<JST.Expression>();
                var managedObjId = default(JST.Identifier);
                for (var i = delta; i < methCompEnv.Method.Arity; i++)
                {
                    if (i == 0)
                        // First argument is always the managed object or a managed pointer to value
                        managedObjId = valueParameters[i];
                    else if (env.InteropManager.IsNoInteropParameter(methEnv.Assembly, methEnv.Type, methEnv.Method, i))
                        // Supress exports
                        callArgs.Add(valueParameters[i].ToE());
                    else
                        callArgs.Add
                            (env.JSTHelpers.ExportExpressionForType
                                 (methCompEnv,
                                  methCompEnv.Method.ValueParameters[i].Type,
                                  valueParameters[i - delta].ToE()));
                }

                var call = env.InteropManager.AppendImport
                    (nameSupply, rootId, methEnv.Assembly, methEnv.Type, methEnv.Method, body, callArgs);
                if (isValType)
                {
                    if (isFactory)
                        body.Add(new JST.ReturnStatement(call));
                    else
                        body.Add(JST.Statement.DotCall(managedObjId.ToE(), Constants.PointerWrite, call));
                }
                else
                {
                    var state = env.InteropManager.GetTypeRepresentation(methEnv.Assembly, methEnv.Type).State;
                    switch (state)
                    {
                    case InstanceState.ManagedOnly:
                        if (isFactory)
                            body.Add(new JST.ReturnStatement(call));
                        else
                            throw new InvalidOperationException
                                ("imported constructors of 'ManagedOnly' types must be factories");
                        break;
                    case InstanceState.Merged:
                        if (isFactory)
                        {
                            if (env.InteropManager.IsNoInteropParameter
                                (methEnv.Assembly, methEnv.Type, methEnv.Method, 0))
                                body.Add(new JST.ReturnStatement(call));
                            else
                                body.Add
                                    (new JST.ReturnStatement
                                         (env.JSTHelpers.ImportExpressionForType(methCompEnv, methCompEnv.TypeRef, call)));
                        }
                        else
                            throw new InvalidOperationException
                                ("imported constructors of 'ManagedOnly' types must be factories");
                        break;
                    case InstanceState.ManagedAndJavaScript:
                    case InstanceState.JavaScriptOnly:
                        {
                            var unmanagedObjId = nameSupply.GenSym();
                            body.Add(JST.Statement.Var(unmanagedObjId, call));
                            body.Add
                                (JST.Statement.DotAssignment
                                     (managedObjId.ToE(), Constants.ObjectUnmanaged, unmanagedObjId.ToE()));
                            body.Add
                                (JST.Statement.DotCall
                                     (rootId.ToE(),
                                      state == InstanceState.ManagedAndJavaScript
                                          ? Constants.RootSetupManagedAndJavaScript
                                          : Constants.RootSetupJavaScriptOnly,
                                      managedObjId.ToE()));
                            env.JSTHelpers.AppendInvokeImportingConstructor
                                (methCompEnv, nameSupply, valueParameters, body, unmanagedObjId);
                            break;
                        }
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
            }
            else
            {
                if (isFactory)
                    throw new InvalidOperationException("only constructors can be factories");

                var outer = methCompEnv.Type.OuterPropertyOrEvent(methCompEnv.Method.MethodSignature);
                if (outer != null && outer.Flavor == CST.MemberDefFlavor.Event)
                {
                    // Event adder/remover
                    var eventDef = (CST.EventDef)outer;
                    var simulateMulticast = env.InteropManager.IsSimulateMulticastEvents
                        (methEnv.Assembly, methEnv.Type, eventDef);
                    // Since event is in same type as this method, ok to use handler type directly
                    var handlerType = eventDef.HandlerType;
                    var slotName = new JST.StringLiteral
                        (Constants.ObjectEventSlot(env.GlobalMapping.ResolveEventDefToSlot(methCompEnv.Assembly, methCompEnv.Type, eventDef)));
                    var obj = default(JST.Expression);
                    var delegateArg = default(JST.Expression);
                    if (methCompEnv.Method.IsStatic)
                    {
                        obj = methCompEnv.ResolveType(methCompEnv.TypeRef);
                        delegateArg = valueParameters[0].ToE();
                    }
                    else
                    {
                        obj = valueParameters[0].ToE();
                        delegateArg = valueParameters[1].ToE();
                    }
                    var slotExp = new JST.IndexExpression(obj, slotName);

                    var callArgs = new Seq<JST.Expression>();
                    if (!methCompEnv.Method.IsStatic)
                    {
                        if (env.InteropManager.IsNoInteropParameter
                            (methEnv.Assembly, methEnv.Type, methEnv.Method, callArgs.Count))
                            callArgs.Add(obj);
                        else
                            callArgs.Add
                                (env.JSTHelpers.ExportExpressionForType
                                     (methCompEnv, methCompEnv.Method.ValueParameters[0].Type, obj));
                    }
                    if (methCompEnv.Method.Signature.Equals(eventDef.Add))
                    {
                        if (simulateMulticast)
                        {
                            body.Add
                                (JST.Statement.DotCall
                                     (rootId.ToE(), Constants.RootAddEventHandler, obj, slotName, delegateArg));
                            if (env.InteropManager.IsNoInteropParameter
                                (methEnv.Assembly, methEnv.Type, methEnv.Method, callArgs.Count))
                                callArgs.Add(slotExp);
                            else
                                callArgs.Add
                                    (env.JSTHelpers.ExportExpressionForType(methCompEnv, handlerType, slotExp));
                        }
                        else
                            callArgs.Add(delegateArg);
                        body.Add
                            (new JST.ExpressionStatement
                                 (env.InteropManager.AppendImport
                                      (nameSupply,
                                       rootId,
                                       methEnv.Assembly,
                                       methEnv.Type,
                                       methEnv.Method,
                                       body,
                                       callArgs)));
                    }
                    else if (methCompEnv.Method.Signature.Equals(eventDef.Remove))
                    {
                        if (simulateMulticast)
                        {
                            body.Add
                                (JST.Statement.DotCall
                                     (rootId.ToE(), Constants.RootRemoveEventHandler, obj, slotName, delegateArg));
                            if (env.InteropManager.IsNoInteropParameter
                                (methEnv.Assembly, methEnv.Type, methEnv.Method, callArgs.Count))
                                callArgs.Add(slotExp);
                            else
                                callArgs.Add
                                    (env.JSTHelpers.ExportExpressionForType(methCompEnv, handlerType, slotExp));
                        }
                        else
                            callArgs.Add(new JST.NullExpression());
                        body.Add
                            (new JST.ExpressionStatement
                                 (env.InteropManager.AppendImport
                                      (nameSupply,
                                       rootId,
                                       methEnv.Assembly,
                                       methEnv.Type,
                                       methEnv.Method,
                                       body,
                                       callArgs)));
                    }
                    else
                        throw new InvalidOperationException("method not adder or remover");
                }
                else
                {
                    // Property getter/setter and normal methods
                    var callArgs = new Seq<JST.Expression>();
                    for (var i = 0; i < methCompEnv.Method.Arity; i++)
                    {
                        if (env.InteropManager.IsNoInteropParameter(methEnv.Assembly, methEnv.Type, methEnv.Method, i))
                            callArgs.Add(valueParameters[i].ToE());
                        else
                            callArgs.Add
                                (env.JSTHelpers.ExportExpressionForType
                                     (methCompEnv, methEnv.Method.ValueParameters[i].Type, valueParameters[i].ToE()));
                    }
                    var call = env.InteropManager.AppendImport
                        (nameSupply, rootId, methEnv.Assembly, methEnv.Type, methEnv.Method, body, callArgs);
                    if (methCompEnv.Method.Result == null)
                        body.Add(new JST.ExpressionStatement(call));
                    else if (env.InteropManager.IsNoInteropResult(methEnv.Assembly, methEnv.Type, methEnv.Method))
                        body.Add(new JST.ReturnStatement(call));
                    else
                        body.Add
                            (new JST.ReturnStatement
                                 (env.JSTHelpers.ImportExpressionForType
                                      (methCompEnv, methCompEnv.Method.Result.Type, call)));
                }
            }

            var func = default(JST.FunctionExpression);
            if (env.CLRInteropExceptions)
            {
                var exId = nameSupply.GenSym();
                var funcBody = new Seq<JST.Statement>();
#if !JSCRIPT_IS_CORRECT
                funcBody.Add(JST.Statement.Var(exId));
#endif
                funcBody.Add
                    (new JST.TryStatement
                         (new JST.Statements(body),
                          new JST.CatchClause
                              (exId,
                               new JST.Statements
                                   (new JST.ThrowStatement
                                        (JST.Expression.DotCall
                                             (rootId.ToE(), Constants.RootImportException, exId.ToE()))))));
                func = new JST.FunctionExpression(methCompEnv.MethodId, parameters, new JST.Statements(funcBody));
            }
            else
                func = new JST.FunctionExpression(methCompEnv.MethodId, parameters, new JST.Statements(body));

            if (trace != null)
                trace.Trace
                    ("Imported JavaScript function",
                     w =>
                         {
                             func.Append(w);
                             w.EndLine();
                         });

            return func;
        }
Esempio n. 7
0
        private JST.FunctionExpression NormalMethod(CST.CSTWriter trace)
        {
            var cstmethod = CST.CSTMethod.Translate(methEnv, nameSupply, trace);
            var methCompEnv = MethodCompilerEnvironment.EnterMethod
                (env, outerNameSupply, nameSupply, rootId, assemblyId, typeDefinitionId, cstmethod.CompEnv, parent.TypeTrace);

            var simpCtxt = new CST.SimplifierContext(methCompEnv, nameSupply, this, trace);
            cstmethod = cstmethod.Simplify(simpCtxt);

            if (trace != null)
                trace.Trace("After simplification of intermediate representation", w2 => cstmethod.Append(w2));

            var usage = cstmethod.Body.Usage(methCompEnv);

            // Bind all type and value parameters
            var parameters = new Seq<JST.Identifier>();
            var body = new Seq<JST.Statement>();

            foreach (var id in methCompEnv.TypeBoundTypeParameterIds)
                parameters.Add(id);
            foreach (var id in methCompEnv.MethodBoundTypeParameterIds)
                parameters.Add(id);

            var delta = env.InteropManager.IsFactory(methCompEnv.Assembly, methCompEnv.Type, methCompEnv.Method) ? 1 : 0;
            for (var i = delta; i < methCompEnv.Method.Arity; i++)
            {
                var id = methCompEnv.ValueParameterIds[i];
                if (i == 0 && !methCompEnv.Method.IsStatic && methCompEnv.Type.Arity == 0)
                {
                    // Only instance methods of first-kinded types use 'this' for their first argument
                    if (usage.Variables.ContainsKey(id))
                        body.Add(JST.Statement.Var(id, new JST.ThisExpression()));
                }
                else
                    parameters.Add(id);
            }

            // Introduce the top level bindings based on usage
            methCompEnv.BindUsage(body, usage);

            // Introduce shared assembly/type/pointer bindings based on usage
            if (env.DebugMode)
                body.Add(new JST.CommentStatement("Locals"));
            var uninit = new Seq<JST.Identifier>();
            foreach (var kv in usage.Variables)
            {
                var v = methCompEnv.Variable(kv.Key);
                if (v.ArgLocal == CST.ArgLocal.Local)
                {
                    if (methCompEnv.Method.IsInitLocals && v.IsInit)
                        body.Add
                            (JST.Statement.Var(v.Id, env.JSTHelpers.DefaultExpressionForType(methCompEnv, v.Type)));
                    else
                        uninit.Add(v.Id);
                }
            }
            if (uninit.Count > 0)
                body.Add(new JST.VariableStatement(uninit.Select(id => new JST.VariableDeclaration(id)).ToSeq()));

            // Translate body to JavaScript statements/expressions
            foreach (var s in cstmethod.Body.Body)
                TranslateStatement(methCompEnv, body, s);

            var func = new JST.FunctionExpression(methCompEnv.MethodId, parameters, new JST.Statements(body));

            if (trace != null)
                trace.Trace
                    ("After translation to JavaScript",
                     w =>
                         {
                             func.Append(w);
                             w.EndLine();
                         });

            return func;
        }
Esempio n. 8
0
 private JST.Expression HandlerLiteral(MethodCompilerEnvironment methCompEnv, CST.TryPseudoStatementHandler handler)
 {
     switch (handler.Flavor)
     {
         case CST.HandlerFlavor.Catch:
         {
             var catchh = (CST.CatchTryPseudoStatementHandler)handler;
             var exid = nameSupply.GenSym();
             var type = methCompEnv.ResolveType(catchh.ExceptionType);
             var match = JST.Expression.IsNotNull
                 (JST.Expression.DotCall(rootId.ToE(), Constants.RootIsInst, exid.ToE(), type));
             var pred = new JST.FunctionExpression
                 (new Seq<JST.Identifier> { exid },
                  new JST.Statements
                      (new JST.IfStatement
                           (match,
                            new JST.Statements
                                (JST.Statement.Assignment(catchh.ExceptionId.ToE(), exid.ToE()),
                                 new JST.ReturnStatement(new JST.BooleanLiteral(true))),
                            new JST.Statements(new JST.ReturnStatement(new JST.BooleanLiteral(false))))));
             return new JST.ObjectLiteral
                 (new OrdMap<JST.Identifier, JST.Expression>
                  {
                      { Constants.HandlerStyle, new JST.NumericLiteral(0) },
                      { Constants.HandlerTarget, new JST.NumericLiteral(catchh.HandlerId) },
                      { Constants.HandlerPred, pred }
                  });
         }
         case CST.HandlerFlavor.Fault:
             return new JST.ObjectLiteral
                 (new OrdMap<JST.Identifier, JST.Expression>
                  {
                      { Constants.HandlerStyle, new JST.NumericLiteral(1) },
                      { Constants.HandlerTarget, new JST.NumericLiteral(handler.HandlerId) }
                  });
         case CST.HandlerFlavor.Finally:
             return new JST.ObjectLiteral
                 (new OrdMap<JST.Identifier, JST.Expression>
                  {
                      { Constants.HandlerStyle, new JST.NumericLiteral(2) },
                      { Constants.HandlerTarget, new JST.NumericLiteral(handler.HandlerId) }
                  });
         case CST.HandlerFlavor.Filter:
             throw new InvalidOperationException("filter blocks not supported");
         default:
             throw new ArgumentOutOfRangeException();
     }
 }