1 | var assert = require('assert');
|
2 | var helpers = require('../helpers');
|
3 | var traverse = require('../traverse');
|
4 | var BlockStatement = require('./BlockStatement');
|
5 | var CallExpression = require('./CallExpression');
|
6 | var ExpressionStatement = require('./ExpressionStatement');
|
7 | var Identifier = require('./Identifier');
|
8 | var ReturnStatement = require('./ReturnStatement');
|
9 | var IfStatement = require('./IfStatement');
|
10 | var FunctionDeclaration = require('./FunctionDeclaration');
|
11 | var FunctionExpression = require('./FunctionExpression');
|
12 | var VariableDeclaration = require('./VariableDeclaration');
|
13 | var SequenceExpression = require('./SequenceExpression');
|
14 |
|
15 | var WhileStatement = module.exports = function(test, body) {
|
16 | this.type = 'WhileStatement';
|
17 | this.test = test;
|
18 | this.body = body;
|
19 | this.async = false;
|
20 | };
|
21 |
|
22 | WhileStatement.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 |
|
33 | WhileStatement.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 |
|
43 | this.async = true;
|
44 |
|
45 | var loopFunctionName = helpers.getLoopFunctionName();
|
46 | var continuationName = loopFunctionName + '_' + helpers.continuationIdentifier;
|
47 |
|
48 |
|
49 | var nextStatement = new ExpressionStatement(new CallExpression(new Identifier(loopFunctionName), [new Identifier(continuationName)]));
|
50 |
|
51 | blockPlace.push(nextStatement);
|
52 |
|
53 |
|
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 |
|
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 |
|
80 | place.push(new FunctionDeclaration(
|
81 | new Identifier(loopFunctionName),
|
82 | [new Identifier(continuationName)],
|
83 | body
|
84 | ));
|
85 |
|
86 |
|
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 | };
|