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"); } }
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)); }
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(); } }
// 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)))); }
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)); }