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()); }
private void TranslateStatement(MethodCompilerEnvironment methCompEnv, Seq<JST.Statement> body, CST.Statement stmnt) { switch (stmnt.Flavor) { case CST.StatementFlavor.Expression: { var es = (CST.ExpressionStatement)stmnt; if (env.DebugMode) body.Add(new JST.CommentStatement(es.ToString())); var exp = TranslateExpression(methCompEnv, body, null, true, es.Value); if (exp != null) body.Add(new JST.ExpressionStatement(exp)); break; } case CST.StatementFlavor.Break: { var bs = (CST.BreakStatement)stmnt; body.Add(new JST.BreakStatement(bs.Label)); break; } case CST.StatementFlavor.Continue: { var cs = (CST.ContinueStatement)stmnt; body.Add(new JST.ContinueStatement(cs.Label)); break; } case CST.StatementFlavor.Throw: { var ts = (CST.ThrowStatement)stmnt; if (env.DebugMode) body.Add(new JST.CommentStatement(ts.ToString())); var e = TranslateExpression(methCompEnv, body, null, false, ts.Exception); body.Add(new JST.ThrowStatement(e)); break; } case CST.StatementFlavor.Rethrow: { var rs = (CST.RethrowStatement)stmnt; if (env.DebugMode) body.Add(new JST.CommentStatement(rs.ToString())); var e = TranslateExpression(methCompEnv, body, null, false, rs.Exception); body.Add(new JST.ThrowStatement(e)); break; } case CST.StatementFlavor.Return: { var rs = (CST.ReturnStatement)stmnt; if (env.DebugMode) body.Add(new JST.CommentStatement(rs.ToString())); var e = rs.Value == null ? null : TranslateExpression(methCompEnv, body, null, false, rs.Value); body.Add(new JST.ReturnStatement(e)); break; } case CST.StatementFlavor.IfThenElse: { var ites = (CST.IfThenElseStatement)stmnt; if (env.DebugMode) body.Add(new JST.CommentStatement("condition: " + ites.Condition.ToString())); var cond = TranslateConditionalExpression(methCompEnv, body, ites.Condition); var then = new JST.Statements(TranslateStatements(methCompEnv, ites.Then)); var els = ites.Else == null ? default(JST.Statements) : new JST.Statements(TranslateStatements(methCompEnv, ites.Else)); body.Add(new JST.IfStatement(cond, then, els)); break; } case CST.StatementFlavor.Switch: { var ss = (CST.SwitchStatement)stmnt; if (env.DebugMode) body.Add(new JST.CommentStatement("switch: " + ss.Value.ToString())); var v = TranslateExpression(methCompEnv, body, null, false, ss.Value); var cases = new Seq<JST.CaseClause>(); var def = default(JST.DefaultClause); foreach (var ssc in ss.Cases) { var actValues = ssc.Values.Where(i => i >= 0).ToList(); if (actValues.Count < ssc.Values.Count) { if (def != null) throw new InvalidOperationException("duplicate default cases"); var caseBody = TranslateStatements(methCompEnv, ssc.Body); def = new JST.DefaultClause(new JST.Statements(caseBody), -1); } if (actValues.Count > 0) { for (var i = 0; i < actValues.Count - 1; i++) cases.Add (new JST.CaseClause (new JST.NumericLiteral(ssc.Values[i]), new JST.Statements())); var caseBody = TranslateStatements(methCompEnv, ssc.Body); cases.Add (new JST.CaseClause (new JST.NumericLiteral(ssc.Values[ssc.Values.Count - 1]), new JST.Statements(caseBody))); } } body.Add(new JST.SwitchStatement(v, cases, def)); break; } case CST.StatementFlavor.DoWhile: { var dws = (CST.DoWhileStatement)stmnt; var whileBody = TranslateStatements(methCompEnv, dws.Body); // NOTE: Not safe to hoist side-effects to body var cond = TranslateConditionalExpression(methCompEnv, null, dws.Condition); body.Add(new JST.DoStatement(new JST.Statements(whileBody), cond)); if (env.DebugMode) body.Add(new JST.CommentStatement("condition: " + dws.Condition.ToString())); break; } case CST.StatementFlavor.WhileDo: { var wds = (CST.WhileDoStatement)stmnt; if (env.DebugMode) body.Add(new JST.CommentStatement("condition: " + wds.Condition.ToString())); // NOTE: Not safe to hoist side-effects into body var cond = TranslateConditionalExpression(methCompEnv, null, wds.Condition); var doBody = TranslateStatements(methCompEnv, wds.Body); body.Add(new JST.WhileStatement(cond, new JST.Statements(doBody))); break; } case CST.StatementFlavor.InitializeObject: { var ios = (CST.InitializeObjectStatement)stmnt; if (env.DebugMode) body.Add(new JST.CommentStatement(ios.ToString())); var ptrType = ios.Address.Type(methCompEnv); if (ios.Address.Flavor == CST.ExpressionFlavor.AddressOf) { var aoe = (CST.AddressOfExpression)ios.Address; var exp = TranslateCellReadWrite (methCompEnv, body, true, aoe.Cell, lvalue => env.JSTHelpers.DefaultExpressionForType(methCompEnv, ptrType.Arguments[0])); if (exp != null) body.Add(new JST.ExpressionStatement(exp)); } else { var ptr = TranslateExpression(methCompEnv, body, null, false, ios.Address); var defval = env.JSTHelpers.DefaultExpressionForType(methCompEnv, ptrType.Arguments[0]); body.Add (new JST.ExpressionStatement(JST.Expression.DotCall(ptr, Constants.PointerWrite, defval))); } break; } case CST.StatementFlavor.Try: { var ts = (CST.TryStatement)stmnt; var tryBody = TranslateStatements(methCompEnv, ts.Body); var finallyClause = default(JST.FinallyClause); var exceptionId = default(JST.Identifier); var catchTests = default(Seq<JST.Expression>); var catchBodies = default(Seq<Seq<JST.Statement>>); var nCatches = ts.Handlers.Where(h => h.Flavor == CST.HandlerFlavor.Catch).Count(); foreach (var h in ts.Handlers) { switch (h.Flavor) { case CST.HandlerFlavor.Catch: { var ch = (CST.TryStatementCatchHandler)h; var thisBody = TranslateStatements(methCompEnv, ch.Body); if (exceptionId == null) exceptionId = ch.ExceptionId; var type = methCompEnv.ResolveType(ch.Type); var thisTest = JST.Expression.IsNotNull (JST.Expression.DotCall (rootId.ToE(), Constants.RootIsInst, exceptionId.ToE(), type)); if (catchTests == null) { catchTests = new Seq<JST.Expression>(); catchBodies = new Seq<Seq<JST.Statement>>(); } catchTests.Add(thisTest); if (!ch.ExceptionId.Equals(exceptionId)) { var newBody = new Seq<JST.Statement>(); newBody.Add(JST.Statement.Var(ch.ExceptionId, exceptionId.ToE())); foreach (var s in thisBody) newBody.Add(s); catchBodies.Add(newBody); } else catchBodies.Add(thisBody); break; } case CST.HandlerFlavor.Finally: { var finallyBody = TranslateStatements(methCompEnv, h.Body); if (finallyClause != null) throw new InvalidOperationException("more than one finally clause"); finallyClause = new JST.FinallyClause(new JST.Statements(finallyBody)); break; } case CST.HandlerFlavor.Filter: throw new InvalidOperationException("filter handler not supported"); case CST.HandlerFlavor.Fault: throw new InvalidOperationException("fault handler not supported"); default: throw new ArgumentOutOfRangeException(); } } var catchClause = default(JST.CatchClause); if (exceptionId != null) { var catchIf = default(JST.Statement); for (var i = catchTests.Count - 1; i >= 0; i--) { if (catchIf == null) catchIf = new JST.IfStatement (catchTests[i], new JST.Statements(catchBodies[i]), new JST.Statements(new JST.ThrowStatement(exceptionId.ToE()))); else catchIf = new JST.IfStatement(catchTests[i], new JST.Statements(catchBodies[i]), new JST.Statements(catchIf)); } catchClause = new JST.CatchClause(exceptionId, new JST.Statements(catchIf)); } body.Add(new JST.TryStatement(new JST.Statements(tryBody), catchClause, finallyClause)); break; } case CST.StatementFlavor.HandlePseudo: { var hs = (CST.HandlePseudoStatement)stmnt; body.Add (JST.Statement.DotCall (rootId.ToE(), Constants.RootHandle, hs.StateId.ToE(), hs.ExceptionId.ToE())); break; } case CST.StatementFlavor.PushTryPseudo: { var pts = (CST.PushTryPseudoStatement)stmnt; body.Add (JST.Statement.Call (JST.Expression.Dot(pts.StateId.ToE(), Constants.StateTryStack, Constants.push), new JST.ObjectLiteral(new OrdMap<JST.Identifier, JST.Expression> { { Constants.TryHandlers, new JST.ArrayLiteral(pts.Handlers.Select(h => HandlerLiteral(methCompEnv, h)).ToSeq()) } }))); break; } case CST.StatementFlavor.LeavePseudo: { var ls = (CST.LeavePseudoStatement)stmnt; body.Add (JST.Statement.DotCall (rootId.ToE(), Constants.RootLeaveTryCatch, ls.StateId.ToE(), new JST.NumericLiteral(ls.PopCount), new JST.NumericLiteral(ls.TargetId))); break; } case CST.StatementFlavor.EndPseudo: { var es = (CST.EndPseudoStatement)stmnt; body.Add (JST.Statement.DotCall(rootId.ToE(), Constants.RootEndFaultFinally, es.StateId.ToE())); break; } case CST.StatementFlavor.GotoPseudo: { var gs = (CST.GotoPseudoStatement)stmnt; body.Add (JST.Statement.DotAssignment(gs.StateId.ToE(), Constants.StatePC, new JST.NumericLiteral(gs.TargetId))); break; } default: throw new ArgumentOutOfRangeException(); } }