use :node; var Node = module.require('../Node').Node; fn SwitchStatement(discriminant, cases) extends Node { this.type = 'SwitchStatement'; this.discriminant = discriminant; this.discriminant.parent = this; this.cases = cases; for caseClause in this.cases { caseClause.parent = this; } } SwitchStatement.prototype.codegen = () -> { if !super.codegen() { return; } var context = this.getContext(); var firstCase, currentCase, defaultCase; var fallthroughPosition = 1; this.discriminant = this.discriminant.codegen(); if this.discriminant.hasCallExpression() { var id = { "type": "Identifier", "name": SwitchStatement.getNextVariableName() }; context.node.body.splice(context.position, 0, { "type": "VariableDeclaration", "codeGenerated": true, "declarations": [{ "type": "VariableDeclarator", "id": id, "init": this.discriminant }], "kind": "let" }); this.discriminant = id; } var hasFallthrough = false; for caseClause in this.cases { if (!caseClause.tests) { defaultCase = caseClause; break; } if !firstCase? { firstCase = caseClause.codegen(); currentCase = firstCase; } else { if currentCase.fallthrough { hasFallthrough = true; currentCase = caseClause.codegen(this.branchFallthrough); context.node.body.splice(context.position + fallthroughPosition++, 0, currentCase); } else { currentCase.alternate = caseClause.codegen(this.fallthroughId?); currentCase = currentCase.alternate; } } } if hasFallthrough { for caseClause in this.cases { if !caseClause.fallthrough and caseClause != defaultCase { caseClause.body.body = [{ "type": "ExpressionStatement", "codeGenerated": true, "expression": { "type": "AssignmentExpression", "operator": "=", "left": this.fallthroughId, "right": { "type": "Literal", "value": 2 } } }].concat(caseClause.body.body); } } } if defaultCase? { if !firstCase? { Node.getErrorManager().error({ type: "SingleDefaultClause", message: "default clause without other case clauses is disallowed.", loc: defaultCase.loc }); } else { if currentCase.fallthrough { defaultCase = defaultCase.codegen(this.fallthroughId?); defaultCase.codeGenerated = true; if this.fallthroughId? { context.node.body.splice(context.position + fallthroughPosition++, 0, defaultCase); } else { for statement in defaultCase.body { context.node.body.splice(context.position + fallthroughPosition++, 0, statement); } } } else { currentCase.alternate = defaultCase.codegen(this.fallthroughId?); } } } if this.fallthroughId? { context.node.body.splice(context.position, 0, { "type": "VariableDeclaration", "codeGenerated": true, "declarations": [ { "type": "VariableDeclarator", "id": this.fallthroughId, "init": { "type": "Literal", "value": 0 } } ], "kind": "let" }); } if !firstCase? { this.type = "ExpressionStatement"; this.expression = this.discriminant; } else { this.type = firstCase.type; this.test = firstCase.test; this.consequent = firstCase.consequent; this.alternate = firstCase.alternate; } return this; }; SwitchStatement.getNextVariableName = () -> { if !this.switchStatementIndex? { this.switchStatementIndex = 0; } return "switchStatement" + this.switchStatementIndex++; }; SwitchStatement.resetVariableNames = () -> { this.switchStatementIndex = 0; }; exports.SwitchStatement = SwitchStatement;