Example #1
0
        public MethodCompiler(TypeDefinitionCompiler parent, JST.NameSupply outerNameSupply, CST.MethodDef methodDef, MethodCompilationMode mode)
        {
            env = parent.Env;
            this.parent = parent;
            methEnv = parent.TyconEnv.AddSelfTypeBoundArguments().AddMethod(methodDef).AddSelfMethodBoundArguments();
            messageCtxt = CST.MessageContextBuilders.Env(methEnv);
            this.mode = mode;
            this.outerNameSupply = outerNameSupply;

            var common = default(JST.NameSupply);
            switch (mode)
            {
            case MethodCompilationMode.SelfContained:
                common = outerNameSupply;
                // Will be bound by function passed to root's BindMethod
                rootId = common.GenSym();
                assemblyId = common.GenSym();
                typeDefinitionId = common.GenSym();
                break;
            case MethodCompilationMode.DirectBind:
                common = outerNameSupply.Fork();
                // Already bound
                rootId = parent.RootId;
                assemblyId = parent.AssemblyId;
                typeDefinitionId = parent.TypeDefinitionId;
                break;
            default:
                throw new ArgumentOutOfRangeException("mode");
            }

            nameSupply = common.Fork();
            simpNameSupply = common.Fork();
        }
Example #2
0
        public BBLoop(BasicBlock head, BasicBlock tail, IMSet<BasicBlock> body, JST.Identifier label)
        {
            Head = head;
            Tail = tail;
            Body = body;
            Label = label;

            var headEscapes = false;
            var headbranchbb = head as BranchBasicBlock;
            foreach (var t in head.Targets)
            {
                if (!body.Contains(t))
                    headEscapes = true;
            }

            var tailEscapes = false;
            var tailbranchbb = tail as BranchBasicBlock;
            foreach (var t in tail.Targets)
            {
                if (!body.Contains(t))
                    tailEscapes = true;
            }

            if (!headEscapes && tailEscapes && tailbranchbb != null)
            {
                if (tailbranchbb.Target.Equals(head))
                    Flavor = LoopFlavor.DoWhile;
                else if (tailbranchbb.Fallthrough.Equals(head))
                    Flavor = LoopFlavor.FlippedDoWhile;
                else
                    throw new InvalidOperationException("invalid loop");
            }
            else if (headEscapes && !tailEscapes && headbranchbb != null)
            {
                if (body.Contains(headbranchbb.Target))
                    Flavor = LoopFlavor.WhileDo;
                else if (body.Contains(headbranchbb.Fallthrough))
                    Flavor = LoopFlavor.FlippedWhileDo;
                else
                    throw new InvalidOperationException("invalid loop");
            }
            else if (!headEscapes && !tailEscapes)
                Flavor = LoopFlavor.Loop;
            else if (headEscapes && tailEscapes && headbranchbb != null && tailbranchbb != null)
            {
                // Could encode as do-while with a break at start, or while-do with a break at end.
                if (body.Contains(headbranchbb.Target))
                    Flavor = LoopFlavor.WhileDo;
                else if (body.Contains(headbranchbb.Fallthrough))
                    Flavor = LoopFlavor.FlippedWhileDo;
                else
                    throw new InvalidOperationException("invalid loop");
            }
            else
                Flavor = LoopFlavor.Unknown;
        }
Example #3
0
 public SimplifierContext
     (CompilationEnvironment compEnv,
      JST.NameSupply nameSupply,
      ISimplifierDatabase database,
      CSTWriter trace)
 {
     CompEnv = compEnv;
     NameSupply = nameSupply;
     subst = new Map<JST.Identifier, Expression>();
     statements = null;
     contextEffects = JST.Effects.Bottom;
     Database = database;
     Trace = trace;
 }
Example #4
0
 protected SimplifierContext
     (CompilationEnvironment compEnv,
      JST.NameSupply nameSupply,
      Map<JST.Identifier, Expression> subst,
      Seq<Statement> statements,
      JST.Effects contextEffects,
      ISimplifierDatabase database,
      CSTWriter trace)
 {
     CompEnv = compEnv;
     NameSupply = nameSupply;
     this.subst = subst;
     this.statements = statements;
     this.contextEffects = contextEffects;
     Database = database;
     Trace = trace;
 }
Example #5
0
        public static CSTMethod Translate(MethodEnvironment methEnv, JST.NameSupply nameSupply, CSTWriter trace)
        {
            // Infer machine states for each control point
            var machineStateInference = new MachineStateInference(methEnv, trace);
            machineStateInference.Infer();

            if (trace != null)
                trace.Trace
                    ("After machine state inference",
                     w =>
                         {
                             methEnv.Method.AppendDefinition(w);
                             w.EndLine();
                         });

            // Translate to basic-blocks which use structural control flow where possible
            var controlFlowRecovery = new ControlFlowRecovery(methEnv, nameSupply.GenSym, -1, trace);
            var root = controlFlowRecovery.Root();

            if (trace != null)
                trace.Trace
                    ("After control flow recovery",
                     w =>
                         {
                             root.AppendAll(w);
                             w.EndLine();
                         });

            var initState = root.Targets[0].Block.BeforeState;
            var compEnv = methEnv.AddVariables(nameSupply, i => initState.ArgLocalIsAlive(ArgLocal.Local, i));

            // Translate to intermediate statements/expressions/cells language
            var translator = new Translator
                (compEnv, nameSupply, controlFlowRecovery.NextInstructionId, trace);
            var body = translator.Translate(root);

            var res = new CSTMethod(compEnv, body);

            if (trace != null)
                trace.Trace("After translation to intermediate representation", res.Append);

            return res;
        }
Example #6
0
 public JST.Identifier FreshenArgument(JST.Identifier id, TypeRef type)
 {
     var newid = NameSupply.GenSym();
     var cell = new VariableCell(newid);
     Bind(id, cell.Read());
     CompEnv.AddVariable(newid, ArgLocal.Local, true, true, type);
     return newid;
 }
Example #7
0
        private JST.Statement WithLineCounts(JST.Statement statement, Func<int> nextLine, int currDepth, Set<JST.Identifier> lineCountIds)
        {
            if (statement.Flavor == JST.StatementFlavor.Try)
            {
                var trys = (JST.TryStatement)statement;
                if (trys.Catch != null)
                {
                    var tryBody = WithLineCounts(trys.Body, nextLine, currDepth + 1, lineCountIds);
                    var catchBody = new Seq<JST.Statement>();
                    var saveid = new JST.Identifier(Constants.DebugCurrentLine.Value + "_" + currDepth);
                    lineCountIds.Add(saveid);
                    catchBody.Add(JST.Statement.Assignment(saveid.ToE(), Constants.DebugCurrentLine.ToE())); 
                    foreach (var s in WithLineCounts(trys.Catch.Body, nextLine, currDepth + 1, lineCountIds).Body)
                        catchBody.Add(s);
                    var catchClause = new JST.CatchClause(trys.Catch.Loc, trys.Catch.Name, new JST.Statements(catchBody));
                    var finallyClause = default(JST.FinallyClause);
                    if (trys.Finally != null)
                        finallyClause = new JST.FinallyClause
                            (trys.Finally.Loc, WithLineCounts(trys.Finally.Body, nextLine, currDepth + 1, lineCountIds));
                    return new JST.TryStatement(trys.Loc, tryBody, catchClause, finallyClause);
                }
                // else: fall-through
            }
            // else: fall-through

            return statement.CloneWithSubStatementss
                (statement.SubStatementss.Select(ss => WithLineCounts(ss, nextLine, currDepth, lineCountIds)).ToSeq());
        }
Example #8
0
        private bool IsValue(JST.Expression expr)
        {
            var path = JST.Expression.ExplodePath(expr);
            if (path == null || path.Count == 0)
                return false;

            var id = path[0].ToIdentifier();
            if (id == null)
                return false;

            return id.Equals(rootId) || id.Equals(assemblyId);
        }
Example #9
0
 private void CheckScriptArity(MessageContext ctxt, CCI.Method methodDefn, JST.Expression script, int n)
 {
     var funcScript = script as JST.FunctionExpression;
     if (funcScript != null)
     {
         if (funcScript.Parameters.Count != n)
         {
             env.Log(new InvalidInteropMessage(RewriterMsgContext.Method(ctxt, methodDefn), "invalid function arity"));
             throw new DefinitionException();
         }
     }
 }
Example #10
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);
                }
            }
        }
Example #11
0
        private JST.Expression RecasePropertyEvent(MessageContext ctxt, CCI.Method method, JST.Expression script)
        {
            if (method.DeclaringMember == null)
                throw new ArgumentException("not a getter/setter/adder/remover method");

            if (script != null)
                return script;

            var name = Recase
                (method.DeclaringMember.Name.Name,
                 interopTypes.GetValue
                     (ctxt, method, env.NamingAttributeType, interopTypes.TheMemberNameCasingProperty));
            return new JST.Identifier(JST.Lexemes.StringToIdentifier(name)).ToE();
        }
Example #12
0
        // Return the exported name for a getter/setter/adder/remover method based on the property/event name
        private JST.Expression GetterSetterAdderRemoverNameFromPropertyEvent(MessageContext ctxt, CCI.Method method, string prefix, JST.Expression script)
        {
            if (method.DeclaringMember == null)
                throw new ArgumentException("not a getter/setter/adder/remover method");

            if (script != null && script is JST.FunctionExpression)
                throw new InvalidOperationException("not a path expression");

            var names = default(ISeq<JST.PropertyName>);
            if (script == null)
                // Take the actual property/event name as a starting point
                names = JST.Expression.ExplodePath(RecasePropertyEvent(ctxt, method, null));
            else
                // Take the user supplied property/event name as a starting point
                names = JST.Expression.ExplodePath(script);

            // Turn the property/event name into a getter/setter/adder/remover name
            var str = "";
            if (
                !interopTypes.GetValue
                     (ctxt, method, env.NamingAttributeType, interopTypes.TheRemoveAccessorPrefixProperty))
            {
                str += Recase
                    (prefix,
                     interopTypes.GetValue
                         (ctxt, method, env.NamingAttributeType, interopTypes.ThePrefixNameCasingProperty));
                if (
                    !interopTypes.GetValue
                         (ctxt,
                          method,
                          env.NamingAttributeType,
                          interopTypes.TheRemoveAccessorUnderscoreProperty))
                    str += "_";
            }
            str += names[names.Count - 1].Value;
            names[names.Count - 1] = new JST.PropertyName(str);

            return JST.Expression.Path(names);
        }
Example #13
0
        public ExportMethodInfo ExportInfo(MessageContext ctxt, Func<JST.Identifier> gensym, JST.Identifier rootId, CCI.Method methodDefn)
        {
            if (!IsExported(ctxt, methodDefn))
                return null;

            if (TypeArity(methodDefn) > 0)
            {
                env.Log(new InvalidInteropMessage(RewriterMsgContext.Member(ctxt, methodDefn), "polymorphic methods cannot be exported"));
                throw new DefinitionException();
            }
            if (TypeArity(methodDefn.DeclaringType) > 0 && (methodDefn is CCI.InstanceInitializer || methodDefn.IsStatic))
            {
                env.Log(new InvalidInteropMessage(RewriterMsgContext.Member(ctxt, methodDefn), "non-instance methods of higher-kinded types cannot be exported"));
                throw new DefinitionException();
            }

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

            var script = interopTypes.GetValue
                (ctxt, methodDefn, env.ExportAttributeType, interopTypes.TheScriptProperty);

            if (methodDefn is CCI.InstanceInitializer)
            {
                // XREF1181
                // Constructors
                if (TypeArity(methodDefn) > 0)
                    throw new InvalidOperationException("invalid constructor");
            }
            else if (methodDefn.DeclaringMember != null)
            {
                var isOnMethod = interopTypes.HasAttribute(methodDefn, env.ExportAttributeType, false);
                var localScript = isOnMethod ? interopTypes.GetValue(ctxt, methodDefn, env.ExportAttributeType, interopTypes.TheScriptProperty, false) : default(JST.Expression);

                var prop = methodDefn.DeclaringMember as CCI.Property;
                if (prop != null)
                {
                    // XREF1193
                    if (methodDefn == prop.Getter)
                        // Getter
                        script = isOnMethod
                                     ? GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "get", localScript)
                                     : GetterSetterAdderRemoverNameFromPropertyEvent(ctxt, methodDefn, "get", script);
                    else if (methodDefn == prop.Setter)
                        // Setter
                        script = isOnMethod
                                     ? GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "set", localScript)
                                     : GetterSetterAdderRemoverNameFromPropertyEvent(ctxt, methodDefn, "set", script);
                    else
                        throw new InvalidOperationException();
                }
                else
                {
                    var evnt = methodDefn.DeclaringMember as CCI.Event;
                    if (evnt != null)
                    {
                        // XREF1213
                        if (methodDefn == evnt.HandlerAdder)
                            // Adder
                            script = isOnMethod
                                         ? GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "add", localScript)
                                         : GetterSetterAdderRemoverNameFromPropertyEvent(ctxt, methodDefn, "add", script);
                        else if (methodDefn == evnt.HandlerRemover)
                            // Remover
                            script = isOnMethod
                                         ? GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "remove",
                                                                                  localScript)
                                         : GetterSetterAdderRemoverNameFromPropertyEvent(ctxt, methodDefn, "remove", script);
                        else
                            throw new InvalidOperationException();
                    }
                    else
                        throw new InvalidOperationException();
                }
            }
            else
            {
                // XREF1163
                // Normal methods
                script = RecaseMember(ctxt, methodDefn, script);
            }
            return FinalExportInfo(ctxt, gensym, rootId, methodDefn, PrefixName(ctxt, methodDefn, script, true));
        }
Example #14
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();
            }
        }
Example #15
0
 public void IncludeEffects(JST.Effects effects)
 {
     contextEffects = contextEffects.Lub(effects);
 }
Example #16
0
        private JST.Expression TranslateExpression(MethodCompilerEnvironment methCompEnv, ISeq<JST.Statement> optBody, JST.Expression optLvalue, bool ignoreResult, CST.Expression expr)
        {
            switch (expr.Flavor)
            {
            case CST.ExpressionFlavor.Null:
                return new JST.NullExpression();
            case CST.ExpressionFlavor.TypeHandle:
                {
                    // The type structure
                    var the = (CST.TypeHandleConstantExpression)expr;
                    return methCompEnv.ResolveType(the.RuntimeType);
                }
            case CST.ExpressionFlavor.FieldHandle:
                {
                    // A System.Reflection.FieldInfo instance, via exported constructor
                    var fhe = (CST.FieldHandleConstantExpression)expr;
                    var fieldEnv = fhe.RuntimeField.Enter(methCompEnv);
                    var slot = env.GlobalMapping.ResolveFieldDefToSlot
                        (fieldEnv.Assembly, fieldEnv.Type, fieldEnv.Field);
                    var fieldDefType = methCompEnv.ResolveType(fhe.RuntimeField.DefiningType);
                    var fieldType = methCompEnv.ResolveType(fieldEnv.SubstituteType(fieldEnv.Field.FieldType));
                    var init = default(JST.Expression);
                    var rawInit = fieldEnv.Field.Init as CST.RawFieldInit;
                    if (rawInit != null)
                        init = new JST.ArrayLiteral
                            (rawInit.Data.Select(b => (JST.Expression)new JST.NumericLiteral(b)).ToSeq());
                    else
                        init = new JST.NullExpression();
                    return JST.Expression.DotCall
                        (rootId.ToE(),
                         Constants.RootReflectionFieldInfo,
                         new JST.StringLiteral(slot),
                         fieldDefType,
                         new JST.BooleanLiteral(fieldEnv.Field.IsStatic),
                         new JST.BooleanLiteral(!fieldEnv.Field.IsStatic),
                         new JST.StringLiteral(fieldEnv.Field.Name),
                         new JST.NullExpression(),
                         fieldType,
                         init);
                }
            case CST.ExpressionFlavor.MethodHandle:
                {
                    // A System.Reflection.MethodInfo instance, via exported constructor
                    var mhe = (CST.MethodHandleConstantExpression)expr;
                    var runtimeMethEnv = mhe.RuntimeMethod.Enter(methCompEnv);
                    var slot = env.GlobalMapping.ResolveMethodDefToSlot
                        (runtimeMethEnv.Assembly, runtimeMethEnv.Type, runtimeMethEnv.Method);
                    var methodDef = runtimeMethEnv.Method;
                    var methodDefType = methCompEnv.ResolveType(mhe.RuntimeMethod.DefiningType);
                    var paramTypes =
                        methodDef.ValueParameters.Where((t, i) => i > 0 || methodDef.IsStatic).Select
                            (t => methCompEnv.ResolveType(runtimeMethEnv.SubstituteType(t.Type))).ToSeq();
                    var result = methodDef.Result == null
                                     ? null
                                     : methCompEnv.ResolveType(runtimeMethEnv.SubstituteType(methodDef.Result.Type));
                    var isStatic = env.InteropManager.IsStatic
                        (runtimeMethEnv.Assembly, runtimeMethEnv.Type, runtimeMethEnv.Method);
                    return JST.Expression.DotCall
                        (rootId.ToE(),
                         Constants.RootReflectionMethodInfo,
                         new JST.StringLiteral(slot),
                         methodDefType,
                         new JST.BooleanLiteral(isStatic),
                         new JST.BooleanLiteral(!isStatic),
                         new JST.StringLiteral(methodDef.Name),
                         new JST.NullExpression(),
                         new JST.BooleanLiteral(runtimeMethEnv.Method.IsVirtualOrAbstract),
                         new JST.ArrayLiteral(paramTypes),
                         new JST.BooleanLiteral(true),
                         result);
                }
            case CST.ExpressionFlavor.CodePointer:
                {
                    // Produces a <codePtr> structure, which is only 'observable' by delegate constructors.
                    // (We can't just produce the function itself because of issues with method slot updating
                    //  and delegate structural equality)
                    var cpe = (CST.CodePointerExpression)expr;
                    // If object is non-null then we assume the same object is passed to delegate constructor
                    var isVirtual = cpe.Object != null;
                    var bindings = new OrdMap<JST.Identifier, JST.Expression>();
                    if (cpe.Method.MethodTypeArguments.Count > 0)
                    {
                        var methodBoundTypeArgs =
                            cpe.Method.MethodTypeArguments.Select(t => methCompEnv.ResolveType(t)).ToSeq();
                        bindings.Add(Constants.CodePtrArguments, new JST.ArrayLiteral(methodBoundTypeArgs));
                    }
                    bindings.Add
                        (Constants.CodePtrType,
                         isVirtual ? new JST.NullExpression() : methCompEnv.ResolveType(cpe.Method.DefiningType));
                    bindings.Add
                        (Constants.CodePtrArity,
                         new JST.NumericLiteral(cpe.Method.ValueParameters.Count - (cpe.Method.IsStatic ? 0 : 1)));
                    bindings.Add
                        (Constants.CodePtrSlot, env.JSTHelpers.MethodSlotName(methCompEnv, cpe.Method, isVirtual));
                    return new JST.ObjectLiteral(bindings);
                }
            case CST.ExpressionFlavor.Int32:
                {
                    var ie = (CST.Int32ConstantExpression)expr;
                    return new JST.NumericLiteral(ie.Value);
                }
            case CST.ExpressionFlavor.Int64:
                {
                    var ie = (CST.Int64ConstantExpression)expr;
                    var n = (double)ie.Value;
                    var o = (long)n;
                    if (o != ie.Value)
                        env.Log
                            (new LossOfPrecisionMessage(CST.MessageContextBuilders.Expression(messageCtxt, expr), "int64 literal"));
                    return new JST.NumericLiteral(n);
                }
            case CST.ExpressionFlavor.Single:
                {
                    var se = (CST.SingleConstantExpression)expr;
                    return new JST.NumericLiteral(se.Value);
                }
            case CST.ExpressionFlavor.Double:
                {
                    var de = (CST.DoubleConstantExpression)expr;
                    return new JST.NumericLiteral(de.Value);
                }
            case CST.ExpressionFlavor.String:
                {
                    var se = (CST.StringConstantExpression)expr;
                    return methCompEnv.ResolveString(se.Value);
                }
            case CST.ExpressionFlavor.Unary:
                {
                    var ue = (CST.UnaryExpression)expr;
                    if (ue.WithOverflow)
                        env.Log
                            (new LossOfPrecisionMessage
                                 (CST.MessageContextBuilders.Expression(messageCtxt, expr), "overflow detection"));
                    if (ue.IsUnsigned)
                        env.Log
                            (new LossOfPrecisionMessage
                                 (CST.MessageContextBuilders.Expression(messageCtxt, expr), "unsigned arithmetic"));
                    switch (ue.Op)
                    {
                    case CST.UnaryOp.CheckFinite:
                        {
                            var ve = TranslateExpression(methCompEnv, optBody, null, false, ue.Value);
                            return JST.Expression.DotCall(rootId.ToE(), Constants.RootCheckFinite, ve);
                        }
                    case CST.UnaryOp.Length:
                        {
                            var ve = TranslateExpression(methCompEnv, optBody, null, false, ue.Value);
                            return JST.Expression.Dot(ve, Constants.length);
                        }
                    case CST.UnaryOp.Neg:
                        {
                            var ve = TranslateExpression(methCompEnv, optBody, null, false, ue.Value);
                            return new JST.UnaryExpression(JST.UnaryOp.UnaryMinus, ve);
                        }
                    case CST.UnaryOp.BitNot:
                        {
                            var ve = TranslateExpression(methCompEnv, optBody, null, false, ue.Value);
                            return new JST.UnaryExpression(JST.UnaryOp.BitwiseNot, ve);
                        }
                    case CST.UnaryOp.LogNot:
                        {
                            var ve = TranslateConditionalExpression(methCompEnv, optBody, ue.Value);
                            return new JST.UnaryExpression(JST.UnaryOp.LogicalNot, ve);
                        }
                    case CST.UnaryOp.IsZero:
                        {
                            var ve = TranslateConditionalExpression(methCompEnv, optBody, ue.Value);
                            return new JST.UnaryExpression(JST.UnaryOp.LogicalNot, ve);
                        }
                    case CST.UnaryOp.IsNonZero:
                        {
                            var ve = TranslateConditionalExpression(methCompEnv, optBody, ue.Value);
                            return ve;
                        }
                    case CST.UnaryOp.IsNull:
                        {
                            var ve = TranslateConditionalExpression(methCompEnv, optBody, ue.Value);
                            return new JST.UnaryExpression(JST.UnaryOp.LogicalNot, ve);
                        }
                    case CST.UnaryOp.IsNonNull:
                        {
                            var ve = TranslateConditionalExpression(methCompEnv, optBody, ue.Value);
                            // Must force result to be a boolean
                            return new JST.UnaryExpression(JST.UnaryOp.LogicalNot, new JST.UnaryExpression(JST.UnaryOp.LogicalNot, ve));
                        }
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
            case CST.ExpressionFlavor.Binary:
                {
                    var be = (CST.BinaryExpression)expr;
                    if (be.WithOverflow)
                        env.Log
                            (new LossOfPrecisionMessage
                                 (CST.MessageContextBuilders.Expression(messageCtxt, expr), "overflow detection"));
                    if (be.IsUnsigned && be.Op != CST.BinaryOp.Shr)
                        env.Log
                            (new LossOfPrecisionMessage
                                 (CST.MessageContextBuilders.Expression(messageCtxt, expr), "unsigned arithmetic"));
                    if (be.Op == CST.BinaryOp.LogAnd)
                    {
                        var le = TranslateConditionalExpression(methCompEnv, optBody, be.LeftValue);
                        // NOTE: Not safe to hoist side-effects into body since rhs may not be evaluated
                        var re = TranslateConditionalExpression(methCompEnv, null, be.RightValue);
                        return new JST.BinaryExpression(le, JST.BinaryOp.LogicalAND, re);

                    }
                    else if (be.Op == CST.BinaryOp.LogOr)
                    {
                        var le = TranslateConditionalExpression(methCompEnv, optBody, be.LeftValue);
                        // NOTE: Not safe to hoist side-effects into body since rhs may not be evaluated
                        var re = TranslateConditionalExpression(methCompEnv, null, be.RightValue);
                        return new JST.BinaryExpression(le, JST.BinaryOp.LogicalOR, re);
                    }
                    else
                    {
                        var le = TranslateExpression(methCompEnv, optBody, null, false, be.LeftValue);
                        var re = TranslateExpression(methCompEnv, optBody, null, false, be.RightValue);
                        switch (be.Op)
                        {
                        case CST.BinaryOp.Eq:
                            return new JST.BinaryExpression(le, JST.BinaryOp.Equals, re);
                        case CST.BinaryOp.Ne:
                            return new JST.BinaryExpression(le, JST.BinaryOp.NotEquals, re);
                        case CST.BinaryOp.Lt:
                            return new JST.BinaryExpression(le, JST.BinaryOp.LessThan, re);
                        case CST.BinaryOp.Le:
                            return new JST.BinaryExpression(le, JST.BinaryOp.LessThanOrEqual, re);
                        case CST.BinaryOp.Gt:
                            return new JST.BinaryExpression(le, JST.BinaryOp.GreaterThan, re);
                        case CST.BinaryOp.Ge:
                            return new JST.BinaryExpression(le, JST.BinaryOp.GreaterThanOrEqual, re);
                        case CST.BinaryOp.Add:
                            return new JST.BinaryExpression(le, JST.BinaryOp.Plus, re);
                        case CST.BinaryOp.Sub:
                            return new JST.BinaryExpression(le, JST.BinaryOp.Minus, re);
                        case CST.BinaryOp.Mul:
                            return new JST.BinaryExpression(le, JST.BinaryOp.Times, re);
                        case CST.BinaryOp.Div:
                            {
                                var de = new JST.BinaryExpression(le, JST.BinaryOp.Div, re);
                                if (be.Type(methCompEnv).Style(methCompEnv) is CST.IntegerTypeStyle)
                                    return new JST.BinaryExpression
                                        (de, JST.BinaryOp.LeftShift, new JST.NumericLiteral(0));
                                else
                                    return de;
                            }
                        case CST.BinaryOp.Rem:
                            return new JST.BinaryExpression(le, JST.BinaryOp.Mod, re);
                        case CST.BinaryOp.LogAnd:
                        case CST.BinaryOp.LogOr:
                            throw new InvalidOperationException();
                        case CST.BinaryOp.BitAnd:
                            return new JST.BinaryExpression(le, JST.BinaryOp.BitwiseAND, re);
                        case CST.BinaryOp.BitOr:
                            return new JST.BinaryExpression(le, JST.BinaryOp.BitwiseOR, re);
                        case CST.BinaryOp.BitXor:
                            return new JST.BinaryExpression(le, JST.BinaryOp.BitwiseXOR, re);
                        case CST.BinaryOp.Shl:
                            return new JST.BinaryExpression(le, JST.BinaryOp.LeftShift, re);
                        case CST.BinaryOp.Shr:
                            if (be.IsUnsigned)
                                return new JST.BinaryExpression(le, JST.BinaryOp.UnsignedRightShift, re);
                            else
                                return new JST.BinaryExpression(le, JST.BinaryOp.RightShift, re);
                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                    }
                }
            case CST.ExpressionFlavor.Convert:
                {
                    var ce = (CST.ConvertExpression)expr;
                    var ve = TranslateExpression(methCompEnv, optBody, null, false, ce.Value);
                    var sourceStyle = ce.Value.Type(methCompEnv).Style(methCompEnv);
                    var resultStyle = ce.ResultType.Style(methCompEnv);

                    env.Log(new LossOfPrecisionMessage(CST.MessageContextBuilders.Expression(messageCtxt, expr), "conversion"));

                    if (resultStyle is CST.Int32TypeStyle && sourceStyle is CST.FloatTypeStyle)
                        return new JST.BinaryExpression(ve, JST.BinaryOp.LeftShift, new JST.NumericLiteral(0));
                    else
                        return ve;
                }
            case CST.ExpressionFlavor.Read:
                {
                    var re = (CST.ReadExpression)expr;
                    if (re.Address.Flavor == CST.ExpressionFlavor.AddressOf)
                    {
                        var aoe = (CST.AddressOfExpression)re.Address;
                        return TranslateCellReadWrite(methCompEnv, optBody, false, aoe.Cell, null);
                    }
                    else
                    {
                        var ptre = TranslateExpression(methCompEnv, optBody, null, false, re.Address);
                        return JST.Expression.DotCall(ptre, Constants.PointerRead);
                    }
                }
            case CST.ExpressionFlavor.Write:
                {
                    var we = (CST.WriteExpression)expr;
                    if (we.Address.Flavor == CST.ExpressionFlavor.AddressOf)
                    {
                        var aoe = (CST.AddressOfExpression)we.Address;
                        return TranslateCellReadWrite
                            (methCompEnv,
                             optBody,
                             ignoreResult,
                             aoe.Cell,
                             lvalue => TranslateExpression(methCompEnv, optBody, lvalue, false, we.Value));
                    }
                    else
                    {
                        var ptre = TranslateExpression(methCompEnv, optBody, null, false, we.Address);
                        var ve = TranslateExpression(methCompEnv, optBody, null, false, we.Value);
                        return JST.Expression.DotCall(ptre, Constants.PointerWrite, ve);
                    }
                }
            case CST.ExpressionFlavor.AddressOf:
                {
                    var ao = (CST.AddressOfExpression)expr;
                    return TranslateCellAsPointer(methCompEnv, optBody, ao.Cell);
                }
            case CST.ExpressionFlavor.ConditionalDeref:
                {
                    var cde = (CST.ConditionalDerefExpression)expr;
                    var obj = TranslateExpression(methCompEnv, optBody, null, false, cde.Address);
                    return env.JSTHelpers.ConditionalDerefExpressionForType(methCompEnv, cde.ConstrainedType, obj);
                }
            case CST.ExpressionFlavor.Call:
                {
                    var ce = (CST.CallExpression)expr;
                    return TranslateCall(methCompEnv, optBody, ce.CallFlavor, ce.Method, ce.Arguments);
                }
            case CST.ExpressionFlavor.NewObject:
                {
                    var noe = (CST.NewObjectExpression)expr;
                    var args =
                        noe.Arguments.Select(e => TranslateExpression(methCompEnv, optBody, null, false, e)).ToSeq();
                    // Construction will try to build object directly into optLvalue, if any
                    return env.JSTHelpers.ConstructorExpression
                        (methCompEnv, nameSupply, optBody, optLvalue, noe.Method, args);
                }
            case CST.ExpressionFlavor.NewArray:
                {
                    var nae = (CST.NewArrayExpression)expr;
                    var len = TranslateExpression(methCompEnv, optBody, null, false, nae.Length);
                    var elemType = methCompEnv.ResolveType(nae.ElementType);
                    return JST.Expression.DotCall(rootId.ToE(), Constants.RootNewArray, elemType, len);
                }
            case CST.ExpressionFlavor.NewBox:
                {
                    var nbe = (CST.NewBoxExpression)expr;
                    var value = TranslateExpression(methCompEnv, optBody, null, false, nbe.Value);
                    return env.JSTHelpers.BoxExpressionForType(methCompEnv, nbe.ValueType, value);
                }
            case CST.ExpressionFlavor.Cast:
                {
                    var ce = (CST.CastExpression)expr;
                    var value = TranslateExpression(methCompEnv, optBody, null, false, ce.Value);
                    var resultType = methCompEnv.ResolveType(ce.ResultType);
                    return JST.Expression.DotCall(rootId.ToE(), Constants.RootCastClass, resultType, value);
                }
            case CST.ExpressionFlavor.Clone:
                {
                    var ce = (CST.CloneExpression)expr;
                    var ve = TranslateExpression(methCompEnv, optBody, null, false, ce.Value);
                    return env.JSTHelpers.CloneExpressionForType(methCompEnv, ce.ResultType, ve);
                }
            case CST.ExpressionFlavor.IsInst:
                {
                    var iie = (CST.IsInstExpression)expr;
                    var value = TranslateExpression(methCompEnv, optBody, null, false, iie.Value);
                    var testType = methCompEnv.ResolveType(iie.TestType);
                    return JST.Expression.DotCall(rootId.ToE(), Constants.RootIsInst, value, testType);
                }
            case CST.ExpressionFlavor.IfThenElse:
                {
                    var itee = (CST.IfThenElseExpression)expr;
                    var cond = TranslateConditionalExpression(methCompEnv, optBody, itee.Condition);
                    // NOTE: Not safe to hoist side-effects into body
                    var then = TranslateExpression(methCompEnv, null, null, false, itee.Then);
                    var els = TranslateExpression(methCompEnv, null, null, false, itee.Else);
                    return new JST.ConditionalExpression(cond, then, els);
                }
            case CST.ExpressionFlavor.ImportExport:
                {
                    var iee = (CST.ImportExportExpression)expr;
                    var ve = TranslateExpression(methCompEnv, optBody, null, false, iee.Value);
                    if (iee.IsImport)
                        return env.JSTHelpers.ImportExpressionForType(methCompEnv, iee.ManagedType, ve);
                    else
                        return env.JSTHelpers.ExportExpressionForType(methCompEnv, iee.ManagedType, ve);
                }
            case CST.ExpressionFlavor.CallImportedPseudo:
                {
                    var cie = (CST.CallImportedExpression)expr;
                    var calleeMemEnv = cie.Method.Enter(methCompEnv);
                    var localBody = optBody ?? new Seq<JST.Statement>();
                    var args =
                        cie.Arguments.Select(e => TranslateExpression(methCompEnv, optBody, null, false, e)).ToSeq();
                    var call = env.InteropManager.AppendImport
                        (nameSupply,
                         rootId,
                         calleeMemEnv.Assembly,
                         calleeMemEnv.Type,
                         calleeMemEnv.Method,
                         localBody,
                         args);
                    if (optBody == null && localBody.Count > 0)
                        return new JST.StatementsPseudoExpression(new JST.Statements(localBody), call);
                    else
                        return call;
                }
            case CST.ExpressionFlavor.StatementsPseudo:
                {
                    // Statements are in same scope as surrounding context
                    var se = (CST.StatementsPseudoExpression)expr;
                    var body = TranslateStatements(methCompEnv, se.Body);
                    var value = se.Value == null ? null : TranslateExpression(methCompEnv, body, null, false, se.Value);
                    return new JST.StatementsPseudoExpression(new JST.Statements(body), value);
                }
            case CST.ExpressionFlavor.InitialStatePseudo:
                return new JST.ObjectLiteral
                    (new OrdMap<JST.Identifier, JST.Expression>
                         {
                             { Constants.StatePC, new JST.NumericLiteral(0) },
                             { Constants.StateTryStack, new JST.ArrayLiteral() },
                             { Constants.StateContStack, new JST.ArrayLiteral() }
                         });
            default:
                throw new ArgumentOutOfRangeException();
            }
        }
Example #17
0
 //
 // Both the CLR and JavaScript allow almost any value or object to be tested for 'true'.
 // 
 //   CLR Object         JavaScript Object  CLR brtrue?        JavaScript true?
 //   -----------------  -----------------  -----------------  -----------------
 //   -                  undefined          -                  false
 //   null               null               false              false
 //   -                  false              -                  false
 //   -                  true               -                  true 
 //   0 (== false)       0                  false              false
 //   1 (== true)        1                  true               true
 //   []                 []                 true               true
 //   [1]                [1]                true               true
 //   ""                 ""                 true               false          <------- SPECIAL CASE
 //   "a"                "a"                true               true
 //   new Object()       new Object()       true               true
 //
 // Hence for anything which could be a string at runtime, we must implement 'is true' by
 //   (<exp> || <exp> === "")
 //
 private JST.Expression StringIsTrue(JST.Expression e)
 {
     return new JST.BinaryExpression(e, JST.BinaryOp.LogicalOR, new JST.BinaryExpression(e, JST.BinaryOp.StrictEquals, new JST.StringLiteral("")));
 }
Example #18
0
        private void EnsurePathExists(ISeq<JST.Statement> statements, JST.Expression script, bool isStatic)
        {
            var path = JST.Expression.ExplodePath(script);
            for (var i = isStatic ? 0 : 1; i < path.Count - 1; i++)
            {
                var prefixPath = new Seq<JST.PropertyName>();
                for (var j = 0; j <= i; j++)
                    prefixPath.Add(path[j]);
                var prefix = JST.Expression.Path(prefixPath);
                if (i == 0)
                {
                    var exId = new JST.Identifier("e");
#if !JSCRIPT_IS_CORRECT
                    statements.Add(JST.Statement.Var(exId));
#endif
                    statements.Add
                        (new JST.TryStatement
                             (new JST.Statements(new JST.ExpressionStatement(prefix)),
                              new JST.CatchClause(exId, new JST.Statements(JST.Statement.Assignment(prefix, new JST.ObjectLiteral())))));
                }
                else if (!path[i].Value.Equals(Constants.prototype.Value, StringComparison.Ordinal))
                    statements.Add
                        (new JST.IfStatement
                             (JST.Expression.IsNull(prefix),
                              new JST.Statements(JST.Statement.Assignment(prefix, new JST.ObjectLiteral()))));
            }
        }
Example #19
0
 public void BindArgument(JST.Identifier id, Expression argument)
 {
     Bind(id, argument);
 }
Example #20
0
 private JST.Expression RecaseMember(MessageContext ctxt, CCI.Member member, JST.Expression script)
 {
     if (script != null)
         return script;
     var name = Recase(member.Name.Name, interopTypes.GetValue(ctxt, member, env.NamingAttributeType, interopTypes.TheMemberNameCasingProperty));
     return new JST.Identifier(JST.Lexemes.StringToIdentifier(name)).ToE();
 }
Example #21
0
 protected void Bind(JST.Identifier id, Expression e)
 {
     if (subst.ContainsKey(id))
         subst[id] = e;
     else
         subst.Add(id, e);
 }
Example #22
0
        // Return the name for a getter/setter/adder/remover method based on the user-supplied method name or underlying method name
        private JST.Expression GetterSetterAdderRemoverNameFromMethod(MessageContext ctxt, CCI.Method method, string prefix, JST.Expression script)
        {
            if (method.DeclaringMember == null)
                throw new ArgumentException("not a getter/setter/adder/remover method");

            if (script != null)
                return script;

            var name = method.Name.Name;
            if (name.StartsWith(prefix + "_", StringComparison.OrdinalIgnoreCase))
                name = name.Substring(prefix.Length + 1);

            var str = "";
            if (!interopTypes.GetValue(ctxt, method, env.NamingAttributeType, interopTypes.TheRemoveAccessorPrefixProperty))
            {
                str += Recase(prefix, interopTypes.GetValue(ctxt, method, env.NamingAttributeType, interopTypes.ThePrefixNameCasingProperty));
                if (!interopTypes.GetValue(ctxt, method, env.NamingAttributeType, interopTypes.TheRemoveAccessorUnderscoreProperty))
                    str += "_";
            }
            str += Recase(name, interopTypes.GetValue(ctxt, method, env.NamingAttributeType, interopTypes.TheMemberNameCasingProperty));

            return new JST.Identifier(JST.Lexemes.StringToIdentifier(str)).ToE();
        }
Example #23
0
 public Expression ApplyReadFrom(JST.Identifier id)
 {
     var e = default(Expression);
     if (subst.TryGetValue(id, out e))
         return e;
     else
         return new VariableCell(id).Read();
 }
Example #24
0
        // Imports:
        //  - instance methods: no qualification
        //  - static methods & constructors: add qualification
        // Exports:
        //  - instance methods, not prototype bound: no qualification
        //  - instance methods, prototype bound: add qualification and 'prototype'
        //  - static methods & constructors: add qualification
        private JST.Expression PrefixName(MessageContext ctxt, CCI.Member member, JST.Expression script, bool isExport)
        {
            if (script != null && script is JST.FunctionExpression)
                return script;

            var isNonInstance = member.IsStatic || member is CCI.InstanceInitializer;
            var qual = interopTypes.GetValue
                (ctxt, member, env.NamingAttributeType, interopTypes.TheQualificationProperty);
            var isProto = isExport &&
                          interopTypes.GetValue
                              (ctxt,
                               member,
                               env.ExportAttributeType,
                               interopTypes.TheBindToPrototypeProperty);
            var path = new Seq<JST.PropertyName>();

            if (script == null && member is CCI.InstanceInitializer && qual == Qualification.None)
                qual = Qualification.Type;

            if (!isExport && !isNonInstance && qual != Qualification.None)
                qual = Qualification.None;

            if (isExport && !isNonInstance && !isProto && qual != Qualification.None)
                qual = Qualification.None;

            if (isExport && !isNonInstance && isProto && qual == Qualification.None)
                qual = Qualification.Type;

            if (isNonInstance)
            {
                var global = interopTypes.GetValue
                    (ctxt, member, env.NamingAttributeType, interopTypes.TheGlobalObjectProperty);
                if (global != null)
                {
                    if (global is JST.FunctionExpression)
                    {
                        env.Log(new InvalidInteropMessage
                            (RewriterMsgContext.Member(ctxt, member), "global object expression cannot be a function"));
                        throw new DefinitionException();
                    }
                    foreach (var p in JST.Expression.ExplodePath(global))
                        path.Add(p);
                }
            }

            if (qual == Qualification.Full)
            {
                var nsCasing = interopTypes.GetValue
                    (ctxt, member, env.NamingAttributeType, interopTypes.TheNamespaceCasingProperty);
                foreach (var name in member.DeclaringType.Namespace.Name.Split('.'))
                {
                    if (string.IsNullOrEmpty(name))
                    {
                        env.Log(new InvalidInteropMessage
                            (RewriterMsgContext.Member(ctxt, member),
                             "member's namespace cannot be represented in JavaScript"));
                        throw new DefinitionException();
                    }
                    path.Add(new JST.PropertyName(Recase(name, nsCasing)));
                }
            }

            if (qual == Qualification.Full || qual == Qualification.Type)
            {
                var type = member.DeclaringType;
                var i = path.Count;
                do
                {
                    var tnCasing = interopTypes.GetValue
                        (ctxt, type, env.NamingAttributeType, interopTypes.TheTypeNameCasingProperty);
                    path.Insert(i, new JST.PropertyName(Recase(type.Name.Name, tnCasing)));
                    type = type.DeclaringType;
                }
                while (type != null);
            }

            if (isProto)
                path.Add(new JST.PropertyName(Constants.prototype));

            if (script != null)
            {
                foreach (var p in JST.Expression.ExplodePath(script))
                    path.Add(p);
            }

            return JST.Expression.Path(path);
        }
Example #25
0
        public Cell ApplyCell(JST.Identifier id)
        {
            var e = default(Expression);
            if (subst.TryGetValue(id, out e))
            {
                var r = e as ReadExpression;
                if (r != null)
                {
                    var cell = r.Address.IsAddressOfCell;
                    if (cell != null)
                        return cell;
                    // else: fall-through
                }
                // else: fall-through
            }
            // else: fall-through

            return new VariableCell(id);
        }
Example #26
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 };
        }
Example #27
0
        public JST.Identifier ApplyId(JST.Identifier id)
        {
            var e = default(Expression);
            if (subst.TryGetValue(id, out e))
            {
                var r = e as ReadExpression;
                if (r != null)
                {
                    var cell = r.Address.IsAddressOfCell;
                    if (cell != null)
                    {
                        var id2 = cell.IsVariable;
                        if (id2 != null)
                            return id2;
                        // else: fall-through
                    }
                    // else: fall-through
                }
                // else: fall-through

            }
            // else: fall-through

            return id;
        }
Example #28
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 };
        }
Example #29
0
        // ----------------------------------------------------------------------
        // Driver
        // ----------------------------------------------------------------------

        private JST.Statements WithLineCounts(JST.Statements statements, Func<int> nextLine, int currDepth, Set<JST.Identifier> lineCountIds)
        {
            var res = new Seq<JST.Statement>();
            foreach (var s in statements.Body)
            {
                if (s.Flavor != JST.StatementFlavor.Comment)
                    res.Add
                        (JST.Statement.IdAssignment(Constants.DebugCurrentLine, new JST.NumericLiteral(nextLine())));
                res.Add(WithLineCounts(s, nextLine, currDepth, lineCountIds));
            }
            return new JST.Statements(res);
        }