Exemplo n.º 1
0
        // ----------------------------------------------------------------------
        // Translating CST cells/expressions/statements
        // ----------------------------------------------------------------------

        private JST.Expression TranslateCellReadWrite(MethodCompilerEnvironment methCompEnv, ISeq<JST.Statement> optBody, bool ignoreResult, CST.Cell cell, Func<JST.Expression, JST.Expression> mkRexp)
        {
            var lvalue = default(JST.Expression);
            switch (cell.Flavor)
            {
                case CST.CellFlavor.Variable:
                    {
                        var alc = (CST.VariableCell)cell;
                        lvalue = alc.Id.ToE();
                        break;
                    }
                case CST.CellFlavor.Field:
                    {
                        var fc = (CST.FieldCell)cell;
                        var fieldEnv = fc.Field.Enter(methCompEnv);
                        if (fieldEnv.Field.IsStatic)
                        {
                            if (fc.Object != null)
                                throw new InvalidOperationException("static field has object");
                            lvalue = env.JSTHelpers.ResolveStaticField(methCompEnv, fc.Field);
                        }
                        else
                        {
                            if (fc.Object == null)
                                throw new InvalidOperationException("instance field does not have object");
                            var oe = TranslateExpression(methCompEnv, optBody, null, false, fc.Object);
                            lvalue = env.JSTHelpers.ResolveInstanceField(methCompEnv, oe, fc.Field);
                        }
                        break;
                    }
                case CST.CellFlavor.Element:
                    {
                        var ee = (CST.ElementCell)cell;
                        var ae = TranslateExpression(methCompEnv, optBody, null, false, ee.Array);
                        var ie = TranslateExpression(methCompEnv, optBody, null, false, ee.Index);
                        if (env.CLRArraySemantics)
                        {
                            // Must go via runtime read/write methods
                            if (mkRexp == null)
                                return JST.Expression.DotCall(rootId.ToE(), Constants.RootGetArrayValue, ae, ie);
                            else
                                return JST.Expression.DotCall
                                    (rootId.ToE(), Constants.RootSetArrayValueInstruction, ae, ie, mkRexp(null));
                        }
                        else
                        {
                            lvalue = new JST.IndexExpression(ae, ie);
                            break;
                        }
                    }
                case CST.CellFlavor.Box:
                    {
                        var bc = (CST.BoxCell)cell;
                        var be = TranslateExpression(methCompEnv, optBody, null, false, bc.Box);
                        if (mkRexp == null)
                        {
                            var valueType = methCompEnv.ResolveType(bc.ValueType);
                            return JST.Expression.DotCall(valueType, Constants.TypeUnboxAny, be);
                        }
                        else
                            throw new InvalidOperationException("cannot mutate boxed objects");
                    }
                case CST.CellFlavor.StatePCPseudo:
                    {
                        var sc = (CST.StatePCPseudoCell)cell;
                        lvalue = JST.Expression.Dot(sc.StateId.ToE(), Constants.StatePC);
                    }
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }

            if (mkRexp == null)
                return lvalue;
            else if (lvalue.IsIdentifier != null)
            {
                // Try to build r.h.s. diretly into knows l.h.s. lvalue
                var rvalue = mkRexp(lvalue);
                if (rvalue == null)
                {
                    // Great! No need for assignmet.
                    return ignoreResult ? null : lvalue;
                }
                else
                    // No luck, must assign explicitly
                    return new JST.BinaryExpression(lvalue, JST.BinaryOp.Assignment, rvalue);
            }
            else
                return new JST.BinaryExpression(lvalue, JST.BinaryOp.Assignment, mkRexp(null));
        }
Exemplo n.º 2
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;
        }