Example #1
0
 private Expression PrimaryExpression()
 {
     switch (Current.Tag)
     {
     case InputElementTag.This:
         {
             var loc = Current.Loc;
             Consume();
             return new ThisExpression(loc);
         }
     case InputElementTag.Debugger:
         {
             var loc = Current.Loc;
             Consume();
             return new DebuggerExpression(loc);
         }
     case InputElementTag.Identifier:
         {
             var id = new Identifier(Current.Loc, Current.Value);
             Consume();
             return new IdentifierExpression(id.Loc, id);
         }
     case InputElementTag.Number:
         {
             var nl = NumericLiteral.FromJavaScript(Current.Loc, Current.Value);
             Consume();
             return nl;
         }
     case InputElementTag.String:
         {
             var sl = new StringLiteral(Current.Loc, Current.Value);
             // lexer has already converted to underlying value
             Consume();
             return sl;
         }
     case InputElementTag.Null:
         {
             var loc = Current.Loc;
             Consume();
             return new NullExpression(Current.Loc);
         }
     case InputElementTag.True:
     case InputElementTag.False:
         {
             var bl = BooleanLiteral.FromJavaScript(Current.Loc, Current.Value);
             Consume();
             return bl;
         }
     case InputElementTag.Regexp:
         {
             // lexer has NOT already converted to underlying value
             var rl = RegularExpressionLiteral.FromJavaScript(Current.Loc, Current.Value);
             Consume();
             return rl;
         }
     case InputElementTag.LSquare:
         {
             var loc = Current.Loc;
             var elems = new Seq<Expression>();
             Consume();
             while (Current.Tag != InputElementTag.RSquare)
             {
                 if (Current.Tag == InputElementTag.Comma)
                 {
                     var elem = new IdentifierExpression
                         (Current.Loc, new Identifier(Current.Loc, Identifier.Undefined.Value));
                     elems.Add(elem);
                     Consume();
                 }
                 else
                 {
                     var elem = AssignmentExpression(false);
                     elems.Add(elem);
                     if (Current.Tag == InputElementTag.Comma)
                         Consume();
                     else if (Current.Tag != InputElementTag.RSquare)
                         throw IEError("array literal", "',' or ']'");
                 }
             }
             loc = loc.Union(Current.Loc);
             Consume();
             return new ArrayLiteral(loc, elems);
         }
     case InputElementTag.LBrace:
         {
             var bindings = new OrdMap<PropertyName, Expression>();
             var loc = DelimitedList
                 ("object literal",
                  "',' or '}'",
                  InputElementTag.Comma,
                  InputElementTag.RBrace,
                  () =>
                      {
                          var propName = default(PropertyName);
                          switch (Current.Tag)
                          {
                          case InputElementTag.Identifier:
                              propName = new PropertyName(Current.Loc, Current.Value);
                              break;
                          case InputElementTag.String:
                              propName = new PropertyName(Current.Loc, Current.Value);
                              break;
                          case InputElementTag.Number:
                              propName = PropertyName.FromJavaScriptNumber(Current.Loc, Current.Value);
                              break;
                          default:
                              throw IEError("object literal", "identifier, string or number");
                          }
                          Consume();
                          Only("object literal", "':'", InputElementTag.Colon);
                          var value = AssignmentExpression(false);
                          // This will silently ignore repeat bindings
                          bindings.Add(propName, value);
                      });
             LastWasInExpressionContext();
             return new ObjectLiteral(loc, bindings);
         }
     case InputElementTag.LParen:
         {
             Consume();
             var e = Expression(false);
             Only("expression", "')'", InputElementTag.RParen);
             LastWasInExpressionContext();
             return e;
         }
     case InputElementTag.Function:
         {
             var loc = Current.Loc;
             Consume();
             var name = default(Identifier);
             if (Current.Tag == InputElementTag.Identifier)
             {
                 name = new Identifier(Current.Loc, Current.Value);
                 Consume();
             }
             if (Current.Tag != InputElementTag.LParen)
                 throw IEError("function expression", "'('");
             var parameters = new Seq<Identifier>();
             DelimitedList
                 ("function expression parameters",
                  "',' or ')'",
                  InputElementTag.Comma,
                  InputElementTag.RParen,
                  () =>
                      {
                          if (Current.Tag != InputElementTag.Identifier)
                              throw IEError("function expression parameters", "identifier");
                          parameters.Add(new Identifier(Current.Loc, Current.Value));
                          Consume();
                      });
             var body = new Seq<Statement>();
             loc = loc.Union(BlockStatements("function expression", true, body));
             return new FunctionExpression(loc, name, parameters, new Statements(body));
         }
     default:
         throw IEError("expression", "primary expression");
     }
 }
Example #2
0
        public void Emit()
        {
            var assm = typeof (RuntimeCompiler).Assembly;
            var res = "Microsoft.LiveLabs.JavaScript.IL2JS." + Constants.RuntimeFileName;
            var runtime = default(JST.Program);
            using (var runtimeStream = assm.GetManifestResourceStream(res))
            {
                if (runtimeStream == null)
                    throw new InvalidOperationException("unable to find runtime resource");
                runtime = JST.Program.FromStream(Constants.RuntimeFileName, runtimeStream, true);
            }

            var mode = default(string);
            switch (env.CompilationMode)
            {
            case CompilationMode.Plain:
                mode = "plain";
                break;
            case CompilationMode.Collecting:
                mode = "collecting";
                break;
            case CompilationMode.Traced:
                mode = "traced";
                break;
            default:
                throw new ArgumentOutOfRangeException();
            }

            var body = default(ISeq<JST.Statement>);
            if (env.DebugMode)
            {
                body = new Seq<JST.Statement>();
                body.Add
                    (JST.Statement.Var(Constants.DebugLevel, new JST.NumericLiteral(env.DebugLevel)));
                body.Add(JST.Statement.Var(Constants.DebugId, new JST.BooleanLiteral(true)));
                body.Add(JST.Statement.Var(Constants.ModeId, new JST.StringLiteral(mode)));
                body.Add(JST.Statement.Var(Constants.SafeId, new JST.BooleanLiteral(env.SafeInterop)));
                foreach (var s in runtime.Body.Body)
                    body.Add(s);
            }
            else
            {
                // Simplify
                var simpCtxt =
                    new JST.SimplifierContext(true, env.DebugMode, new JST.NameSupply(Constants.Globals), null).
                        InFreshStatements();
                simpCtxt.Bind(Constants.DebugId, new JST.BooleanLiteral(false));
                simpCtxt.Bind(Constants.ModeId, new JST.StringLiteral(mode));
                simpCtxt.Bind(Constants.SafeId, new JST.BooleanLiteral(env.SafeInterop));
                simpCtxt.Add(JST.Statement.Var(Constants.DebugLevel, new JST.NumericLiteral(env.DebugLevel)));
                runtime.Body.Simplify(simpCtxt, EvalTimes.Bottom, false);
                body = simpCtxt.Statements;
            }

            var opts = new OrdMap<JST.Identifier, JST.Expression>();
            var mscorlibName = new JST.StringLiteral
                (CST.CSTWriter.WithAppend(env.Global, CST.WriterStyle.Uniform, env.Global.MsCorLibName.Append));
            opts.Add(Constants.SetupMscorlib, mscorlibName);
            var target = default(string);
            switch (env.Target)
            {
            case Target.Browser:
                target = "browser";
                break;
            case Target.CScript:
                target = "cscript";
                break;
            default:
                throw new ArgumentOutOfRangeException();
            }
            opts.Add(Constants.SetupTarget, new JST.StringLiteral(target));
            var loadPaths = env.LoadPaths.Select<string, JST.Expression>(FixupPath).ToSeq();
            if (loadPaths.Count == 0)
                loadPaths.Add(new JST.StringLiteral(""));
            opts.Add(Constants.SetupSearchPaths, new JST.ArrayLiteral(loadPaths));

            if (env.DebugMode)
                body.Add(new JST.CommentStatement("Setup runtime"));
            var rootId = new JST.Identifier(env.Root);
            body.Add(JST.Statement.Var(rootId, new JST.ObjectLiteral()));
            body.Add(JST.Statement.Call(Constants.NewRuntime.ToE(), rootId.ToE(), new JST.ObjectLiteral(opts)));

            var program = new JST.Program(new JST.Statements(body));
            var runtimeFileName = Path.Combine(env.OutputDirectory, Constants.RuntimeFileName);
            program.ToFile(runtimeFileName, env.PrettyPrint);
            env.Log(new GeneratedJavaScriptFile("runtime", runtimeFileName));
        }
Example #3
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 #4
0
        // For speed we inline rather than chain to base-type default values
        // (Though, actually, that's not necessary since value types are sealed and have not inherited fields...)
        private void EmitDefaultValue(Seq<JST.Statement> body, JST.Expression lhs)
        {
            var s = TypeCompEnv.Type.Style;
            var innerBody = new Seq<JST.Statement>();

            if (s is CST.VoidTypeStyle || s is CST.ManagedPointerTypeStyle)
                innerBody.Add
                    (new JST.ThrowStatement
                         (JST.Expression.DotCall(RootId.ToE(), Constants.RootInvalidOperationException)));
            else if (s is CST.NumberTypeStyle || s is CST.EnumTypeStyle || TypeCompEnv.TypeRef.Equals(Env.Global.DecimalRef))
                innerBody.Add(new JST.ReturnStatement(new JST.NumericLiteral(0)));
            else if (s is CST.StructTypeStyle)
            {
                var allFieldRefs = new Seq<CST.FieldRef>();
                AccumInstanceFields(TypeCompEnv, allFieldRefs);

                var innerTypeCompEnv = TypeCompEnv.EnterFunction();

                var usage = new CST.Usage();
                foreach (var fieldRef in allFieldRefs)
                {
                    if (Env.JSTHelpers.DefaultFieldValueIsNonNull(innerTypeCompEnv, fieldRef))
                        fieldRef.ExternalFieldType.AccumUsage(usage, true);
                }
                innerTypeCompEnv.BindUsage(innerBody, usage, TypePhase.Constructed);

                var bindings = new OrdMap<JST.Identifier, JST.Expression>();
                foreach (var fieldRef in allFieldRefs)
                    bindings.Add
                        (Env.JSTHelpers.ResolveFieldToIdentifier(innerTypeCompEnv, fieldRef, false),
                         Env.JSTHelpers.DefaultFieldValue(innerTypeCompEnv, fieldRef));

                innerBody.Add(new JST.ReturnStatement(new JST.ObjectLiteral(bindings)));
            }
            // else: default default value of null is ok

            if (innerBody.Count > 0)
                body.Add
                    (JST.Statement.DotAssignment
                         (lhs, Constants.TypeDefaultValue, new JST.FunctionExpression(null, new JST.Statements(innerBody))));
        }
Example #5
0
        public void Emit()
        {
            var assm    = typeof(RuntimeCompiler).Assembly;
            var res     = "Microsoft.LiveLabs.JavaScript.IL2JS." + Constants.RuntimeFileName;
            var runtime = default(JST.Program);

            using (var runtimeStream = assm.GetManifestResourceStream(res))
            {
                if (runtimeStream == null)
                {
                    throw new InvalidOperationException("unable to find runtime resource");
                }
                runtime = JST.Program.FromStream(Constants.RuntimeFileName, runtimeStream, true);
            }

            var mode = default(string);

            switch (env.CompilationMode)
            {
            case CompilationMode.Plain:
                mode = "plain";
                break;

            case CompilationMode.Collecting:
                mode = "collecting";
                break;

            case CompilationMode.Traced:
                mode = "traced";
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            var body = default(ISeq <JST.Statement>);

            if (env.DebugMode)
            {
                body = new Seq <JST.Statement>();
                body.Add
                    (JST.Statement.Var(Constants.DebugLevel, new JST.NumericLiteral(env.DebugLevel)));
                body.Add(JST.Statement.Var(Constants.DebugId, new JST.BooleanLiteral(true)));
                body.Add(JST.Statement.Var(Constants.ModeId, new JST.StringLiteral(mode)));
                body.Add(JST.Statement.Var(Constants.SafeId, new JST.BooleanLiteral(env.SafeInterop)));
                foreach (var s in runtime.Body.Body)
                {
                    body.Add(s);
                }
            }
            else
            {
                // Simplify
                var simpCtxt =
                    new JST.SimplifierContext(true, env.DebugMode, new JST.NameSupply(Constants.Globals), null).
                    InFreshStatements();
                simpCtxt.Bind(Constants.DebugId, new JST.BooleanLiteral(false));
                simpCtxt.Bind(Constants.ModeId, new JST.StringLiteral(mode));
                simpCtxt.Bind(Constants.SafeId, new JST.BooleanLiteral(env.SafeInterop));
                simpCtxt.Add(JST.Statement.Var(Constants.DebugLevel, new JST.NumericLiteral(env.DebugLevel)));
                runtime.Body.Simplify(simpCtxt, EvalTimes.Bottom, false);
                body = simpCtxt.Statements;
            }

            var opts         = new OrdMap <JST.Identifier, JST.Expression>();
            var mscorlibName = new JST.StringLiteral
                                   (CST.CSTWriter.WithAppend(env.Global, CST.WriterStyle.Uniform, env.Global.MsCorLibName.Append));

            opts.Add(Constants.SetupMscorlib, mscorlibName);
            var target = default(string);

            switch (env.Target)
            {
            case Target.Browser:
                target = "browser";
                break;

            case Target.CScript:
                target = "cscript";
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
            opts.Add(Constants.SetupTarget, new JST.StringLiteral(target));
            var loadPaths = env.LoadPaths.Select <string, JST.Expression>(FixupPath).ToSeq();

            if (loadPaths.Count == 0)
            {
                loadPaths.Add(new JST.StringLiteral(""));
            }
            opts.Add(Constants.SetupSearchPaths, new JST.ArrayLiteral(loadPaths));

            if (env.DebugMode)
            {
                body.Add(new JST.CommentStatement("Setup runtime"));
            }
            var rootId = new JST.Identifier(env.Root);

            body.Add(JST.Statement.Var(rootId, new JST.ObjectLiteral()));
            body.Add(JST.Statement.Call(Constants.NewRuntime.ToE(), rootId.ToE(), new JST.ObjectLiteral(opts)));

            var program         = new JST.Program(new JST.Statements(body));
            var runtimeFileName = Path.Combine(env.OutputDirectory, Constants.RuntimeFileName);

            program.ToFile(runtimeFileName, env.PrettyPrint);
            env.Log(new GeneratedJavaScriptFile("runtime", runtimeFileName));
        }