UNPKG

3.23 kBJavaScriptView Raw
1var assert = require('assert');
2var helpers = require('../helpers');
3var traverse = require('../traverse');
4var BlockStatement = require('./BlockStatement');
5var CallExpression = require('./CallExpression');
6var ExpressionStatement = require('./ExpressionStatement');
7var Identifier = require('./Identifier');
8var ReturnStatement = require('./ReturnStatement');
9var IfStatement = require('./IfStatement');
10var FunctionDeclaration = require('./FunctionDeclaration');
11var FunctionExpression = require('./FunctionExpression');
12var VariableDeclaration = require('./VariableDeclaration');
13var SequenceExpression = require('./SequenceExpression');
14
15var WhileStatement = module.exports = function(test, body) {
16 this.type = 'WhileStatement';
17 this.test = test;
18 this.body = body;
19 this.async = false;
20};
21
22WhileStatement.prototype.normalize = function (place) {
23 if (this.body === null) {
24 this.body = new BlockStatement([]);
25 } else if (this.body.type !== 'BlockStatement') {
26 this.body = new BlockStatement([this.body]);
27 }
28
29 this.body.normalize();
30 place.push(this);
31};
32
33WhileStatement.prototype.transform = function (place) {
34 assert(this.body.type === 'BlockStatement');
35 var blockPlace = this.body.transform();
36
37 if (!this.body.async) {
38 place.push(this);
39 return place;
40 }
41
42 //At least one statement within body transformed
43 this.async = true;
44
45 var loopFunctionName = helpers.getLoopFunctionName();
46 var continuationName = loopFunctionName + '_' + helpers.continuationIdentifier;
47
48 //nextStatement is equivalant to continue statement, i.e. loop_0(loop_0_cont)
49 var nextStatement = new ExpressionStatement(new CallExpression(new Identifier(loopFunctionName), [new Identifier(continuationName)]));
50 //Add explicit continuation statement on the back of inner block
51 blockPlace.push(nextStatement);
52
53 //continuationStatement is like break statement, i.e. loop_0_cont()
54 var continuationStatement = new ExpressionStatement(new CallExpression(new Identifier(continuationName), []));
55
56 var body = new BlockStatement([new IfStatement(
57 this.test,
58 this.body,
59 new BlockStatement([continuationStatement])
60 )]);
61
62 var updateExpression = this.update;
63
64 //Transform break and continue statements
65 traverse(this.body, function (statement) {
66 if (statement.type === 'BreakStatement') {
67 statement = new ReturnStatement(continuationStatement.expression);
68 } else if (statement.type === 'ContinueStatement') {
69 if (updateExpression) {
70 var seqExpression = new SequenceExpression([updateExpression, nextStatement.expression]);
71 statement = new ReturnStatement(seqExpression);
72 } else {
73 statement = new ReturnStatement(nextStatement.expression);
74 }
75 }
76 return statement;
77 });
78
79 //Generate loop function
80 place.push(new FunctionDeclaration(
81 new Identifier(loopFunctionName),
82 [new Identifier(continuationName)],
83 body
84 ));
85
86 //Generate loop function invocation statement and continuation part
87 var nextPlace = [];
88 place.push(new ExpressionStatement(new CallExpression(
89 new Identifier(loopFunctionName),
90 [new FunctionExpression(null, [], new BlockStatement(nextPlace))]
91 )));
92 return nextPlace;
93};