UNPKG

3.15 kBJavaScriptView Raw
1var BlockStatement = require('./BlockStatement');
2var CallExpression = require('./CallExpression');
3var ExpressionStatement = require('./ExpressionStatement');
4var FunctionDeclaration = require('./FunctionDeclaration');
5var Identifier = require('./Identifier');
6var ReturnStatement = require('./ReturnStatement');
7var helpers = require('../helpers');
8var traverse = require('../traverse');
9
10var SwitchStatement = module.exports = function(discriminant, cases) {
11 this.type = 'SwitchStatement';
12 this.discriminant = discriminant;
13 this.cases = cases;
14};
15
16SwitchStatement.prototype.normalize = function (body) {
17 if (this.cases) {
18 this.cases.forEach(function (sCase) {
19 var block = new BlockStatement(sCase.consequent);
20 block.normalize();
21 sCase.consequent = block.body;
22 });
23 }
24 body.push(this);
25};
26
27SwitchStatement.prototype.transform = function (place) {
28 var innerPlace = [];
29 var caseFunctions = [];
30 var casePlaces = [];
31 var async = false;
32 //Make case function form cases
33 if (this.cases) {
34 this.cases.forEach(function (sCase, index) {
35 var name = 'case_' + index;
36 var func = new FunctionDeclaration(
37 new Identifier(name),
38 [new Identifier(helpers.continuationIdentifier)],
39 new BlockStatement(sCase.consequent)
40 );
41
42 var place = func.body.transform();
43 async = async || func.body.async;
44 casePlaces.push(place);
45 caseFunctions.push(func);
46 innerPlace.push(func);
47 });
48 }
49
50 if (!async) {
51 //No need to transform
52 place.push(this);
53 return place;
54 }
55 this.async = true;
56
57 //Replace thiss in cases with case function calls
58 this.cases.forEach(function (sCase, index) {
59 var name = 'case_' + index;
60 var continuationExpression = new CallExpression(new Identifier(name), [new Identifier(helpers.continuationIdentifier)]);
61 sCase.consequent = [
62 new ReturnStatement(continuationExpression),
63 ];
64 });
65
66 caseFunctions.forEach(function (func, index) {
67 var nextFunc = null;
68 if (index !== caseFunctions.length - 1) {
69 nextFunc = caseFunctions[index + 1];
70 }
71 var place = casePlaces[index];
72 place.forEach(function (statement, i) {
73 //Transform break this into cont()
74 if (statement.type === 'BreakStatement') {
75 place[i] = helpers.continuationStatement;
76 }
77 });
78 if (place.length === 0 || !helpers.isContinuationStatement(place[place.length - 1])) {
79 //No break in the end, fall through into next case function
80 if (nextFunc !== null) {
81 place.push(new ExpressionStatement(new CallExpression(nextFunc.id, [new Identifier(helpers.continuationIdentifier)])));
82 } else {
83 place.push(helpers.continuationStatement);
84 }
85 }
86
87 traverse(func.body, function (statement) {
88 if (statement.type === 'BreakStatement') {
89 statement = new ReturnStatement(helpers.continuationStatement.expression);
90 }
91 return statement;
92 });
93 });
94
95 //Add switch this into inner place
96 innerPlace.push(this);
97
98 var nextPlace = [];
99 place.push(helpers.makeCPS(innerPlace, nextPlace));
100
101 return nextPlace;
102};