Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(152)

Side by Side Diff: frog/await/normalizer.dart

Issue 10548047: Remove frog from the repository. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Move test and update apidoc.gyp. Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « frog/await/nodeset.dart ('k') | frog/await/samples/dartcombat/README » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 /**
6 * Normalizes the AST to make the translation in [AwaitProcessor] simpler. This
7 * normalization provides the following guarantees:
8 * - await only occurs in top-level assignments. For example:
9 * if (await t) return;
10 * after normalization should become:
11 * final $t = await t;
12 * if ($t) return;
13 *
14 * - await in declarations are split in multiple declarations:
15 * int x = 1, y = await t, z = 3, w = y;
16 * becomes:
17 * int x = 1;
18 * int y = await t;
19 * int z = 3, w = y;
20 *
21 * - await cannot occur on complex assignments:
22 * x += await t
23 * becomes:
24 * $t = await t
25 * x += $t
26 *
27 * - await cannot occur outside statement blocks:
28 * if (...) x = await t
29 * becomes:
30 * if (...) { x = await t }
31 */
32 class AwaitNormalizer implements TreeVisitor {
33 // TODO(sigmund): fix frog to make it possible to switch to '_a:tmp'. The
34 // mangling code currently breaks across closure-boundaries.
35 static final _PREFIX = '_a_tmp';
36 int _tmpVarCounter = 0;
37
38 /** AST nodes that contain await expressions. */
39 NodeSet haveAwait;
40
41 AwaitNormalizer(this.haveAwait);
42
43 NormalizerResult visitVariableDefinition(VariableDefinition node) {
44 // split variable declarations in chuncks:
45 List<Statement> res = [];
46 List<Identifier> names = [];
47 List<Expression> values = [];
48 for (int i = 0; i < node.names.length; i++) {
49 final val = node.values[i];
50 if (val == null || !haveAwait.contains(val)) {
51 names.add(node.names[i]);
52 values.add(val);
53 } else {
54 // an await was found, declare previous vars first:
55 if (names.length > 0) {
56 res.add(new VariableDefinition(
57 node.modifiers, node.type, names, values, node.span));
58 names = [];
59 values = [];
60 }
61 final valRes = _visit(val);
62 res.addAll(valRes.stmts);
63 // add the declaration directly, since all following vars should
64 // be in a separate declaration
65 final newDecl = new VariableDefinition(node.modifiers, node.type,
66 [node.names[i]], [valRes.exp], node.span);
67 res.add(newDecl);
68 }
69 }
70 if (names.length > 0) {
71 res.add(new VariableDefinition(
72 node.modifiers, node.type, names, values, node.span));
73 }
74 return new NormalizerResult(res, null, null);
75 }
76
77 NormalizerResult visitFunctionDefinition(FunctionDefinition node) {
78 if (!haveAwait.contains(node)) return null;
79 node.body = _visit(node.body).asStatement(); // normalize and replace body.
80 }
81
82 NormalizerResult visitReturnStatement(ReturnStatement node) {
83 final expRes = _visit(node.value);
84 final res = new NormalizerResult([], null, null);
85 res.stmts.addAll(expRes.stmts);
86 res.stmts.add(new ReturnStatement(expRes.exp, node.span));
87 return res;
88 }
89
90 NormalizerResult visitThrowStatement(ThrowStatement node) {
91 final expRes = _visit(node.value);
92 final res = new NormalizerResult([], null, null);
93 res.stmts.addAll(expRes.stmts);
94 res.stmts.add(new ThrowStatement(expRes.exp, node.span));
95 return res;
96 }
97
98 NormalizerResult visitIfStatement(IfStatement node) {
99 final testRes = _visit(node.test);
100 final trueRes = _visit(node.trueBranch).asStatement();
101 final falseRes = _visit(node.falseBranch).asStatement();
102 final res = new NormalizerResult([], null, null);
103 res.stmts.addAll(testRes.stmts);
104 final exp = _liftExp(testRes, res.stmts);
105 res.stmts.add(new IfStatement(exp, trueRes, falseRes, node.span));
106 return res;
107 }
108
109 NormalizerResult visitWhileStatement(WhileStatement node) {
110 final testRes = _visit(node.test);
111 final bodyRes = _visit(node.body).asStatement();
112 final res = new NormalizerResult([], null, null);
113 res.stmts.addAll(testRes.stmts);
114 final exp = _liftExp(testRes, res.stmts);
115 res.stmts.add(new WhileStatement(exp, bodyRes, node.span));
116 return res;
117 }
118
119 NormalizerResult visitDoStatement(DoStatement node) {
120 final bodyRes = _visit(node.body);
121 final testRes = _visit(node.test);
122 final bodyList = [bodyRes.asStatement()];
123 bodyList.addAll(testRes.stmts);
124 final exp = _liftExp(testRes, bodyList);
125 final body = new BlockStatement(bodyList, node.span);
126 return new NormalizerResult.fromNode(
127 new DoStatement(body, exp, node.span));
128 }
129
130 NormalizerResult visitForStatement(ForStatement node) {
131 // TODO(sigmund): implement
132 _notSupported("for loops", node);
133 return null;
134 }
135
136 NormalizerResult visitForInStatement(ForInStatement node) {
137 _notSupported("for-in loops", node);
138 return null;
139 }
140
141 NormalizerResult visitTryStatement(TryStatement node) {
142 final bodyRes = _visit(node.body);
143 List<CatchNode> catchesRes = [];
144 for (NormalizerResult r in _visitList(node.catches)) {
145 assert (r.node != null && r.node is CatchNode);
146 catchesRes.add(r.node);
147 }
148 final finallyRes = _visit(node.finallyBlock);
149
150 return new NormalizerResult.fromNode(
151 new TryStatement(bodyRes.asStatement(),
152 catchesRes, finallyRes.asStatement(), node.span));
153 }
154
155 NormalizerResult visitSwitchStatement(SwitchStatement node) {
156 _notSupported("switch statements", node);
157 return null;
158 }
159
160 NormalizerResult visitBlockStatement(BlockStatement node) {
161 final bodyRes = _visitList(node.body);
162 final newBlock = [];
163 for (NormalizerResult b in bodyRes) {
164 newBlock.addAll(b.stmts);
165 if (b.exp != null) {
166 world.fatal(
167 "unexpected: expression result from normalizing block", node.span);
168
169 }
170 }
171 return new NormalizerResult.fromNode(
172 new BlockStatement(newBlock, node.span));
173 }
174
175 NormalizerResult visitLabeledStatement(LabeledStatement node) {
176 return new NormalizerResult.fromNode(new LabeledStatement(
177 node.name, _visit(node.body).asStatement(), node.span));
178 }
179
180 visitAssertStatement(AssertStatement node) {
181 // We can normalize
182 // assert await M;
183 // as:
184 // var x = false;
185 // assert (x = true); // ensure await is only evaluated when assertions
186 // // are enabled
187 // if (x) {
188 // var t = await M;
189 // assert t;
190 // }
191 _notSupported("assert statements", node);
192 return null;
193 }
194
195 NormalizerResult visitExpressionStatement(ExpressionStatement node) {
196 final bodyRes = _visit(node.body);
197 final res = new NormalizerResult([], null, null);
198 res.stmts.addAll(bodyRes.stmts);
199 res.stmts.add(new ExpressionStatement(bodyRes.exp, node.span));
200 return res;
201 }
202
203 NormalizerResult visitCallExpression(CallExpression node) {
204 final targetRes = _visit(node.target);
205 final argsRes = _visitList(node.arguments);
206 final extraStmts = [];
207 final newArgs = [];
208 extraStmts.addAll(targetRes.stmts);
209 final target = _liftExp(targetRes, extraStmts);
210 for (final arg in argsRes) {
211 extraStmts.addAll(arg.stmts);
212 newArgs.add(arg.node);
213 }
214 return new NormalizerResult(extraStmts,
215 new CallExpression(target, newArgs, node.span), null);
216 }
217
218 NormalizerResult visitIndexExpression(IndexExpression node) {
219 final targetRes = _visit(node.target);
220 final indexRes = _visit(node.index);
221 final extraStmts = [];
222 extraStmts.addAll(targetRes.stmts);
223 final target = _liftExp(targetRes, extraStmts);
224 extraStmts.addAll(indexRes.stmts);
225 final index = _liftExp(indexRes, extraStmts);
226 return new NormalizerResult(extraStmts,
227 new IndexExpression(target, index, node.span), null);
228 }
229
230 NormalizerResult visitBinaryExpression(BinaryExpression node) {
231 final xRes = _visit(node.x);
232 final yRes = _visit(node.y);
233 final extraStmts = [];
234 extraStmts.addAll(xRes.stmts);
235 final x = _liftExp(xRes, extraStmts);
236 if (node.op.kind == TokenKind.OR || node.op.kind == TokenKind.AND) {
237 // AND and OR require short-circuiting code:
238 final otherStmts = [];
239 otherStmts.addAll(yRes.stmts);
240 final y = _liftExp(yRes, otherStmts);
241 final tmpId = _newTmp(node.span);
242 extraStmts.add(_declareVar(tmpId, x, false));
243 final tmpVar = new VarExpression(tmpId, node.span);
244 Expression test = tmpVar;
245 if (node.op.kind == TokenKind.OR) {
246 // (a && b) becomes t = a; if (t) t = b; (t)
247 // (a || b) becomes t = a; if (!t) t = b; (t)
248 test = new UnaryExpression(
249 new Token.fake(TokenKind.NOT, node.op.span), test, node.op.span);
250 }
251 otherStmts.add(new ExpressionStatement(
252 new BinaryExpression(new Token.fake(TokenKind.ASSIGN, node.span),
253 tmpVar, y, y.span), y.span));
254 extraStmts.add(new IfStatement(test,
255 new BlockStatement(otherStmts, node.y.span), null, node.y.span));
256 return new NormalizerResult(extraStmts, tmpVar, null);
257 } else {
258 extraStmts.addAll(yRes.stmts);
259 // Other operators require a var-lifting the rhs if they contain an await:
260 final y = _liftExp(yRes, extraStmts);
261 return new NormalizerResult(extraStmts,
262 new BinaryExpression(node.op, x, y, node.span), null);
263 }
264 }
265
266 NormalizerResult visitUnaryExpression(UnaryExpression node) {
267 // TODO(sigmund): implement
268 _notSupported("unary expressions", node);
269 return null;
270 }
271
272 NormalizerResult visitPostfixExpression(PostfixExpression node) {
273 // TODO(sigmund): implement
274 _notSupported("postfix expressions", node);
275 return null;
276 }
277
278 NormalizerResult visitNewExpression(NewExpression node) {
279 // TODO(sigmund): implement
280 _notSupported("new expressions", node);
281 return null;
282 }
283
284 NormalizerResult visitListExpression(ListExpression node) {
285 // TODO(sigmund): implement
286 _notSupported("list literals", node);
287 return null;
288 }
289
290 NormalizerResult visitMapExpression(MapExpression node) {
291 // TODO(sigmund): implement
292 _notSupported("map literals", node);
293 return null;
294 }
295
296 NormalizerResult visitConditionalExpression(ConditionalExpression node) {
297 // TODO(sigmund): implement
298 _notSupported("ternary expressions", node);
299 return null;
300 }
301
302 NormalizerResult visitIsExpression(IsExpression node) {
303 // TODO(sigmund): implement
304 _notSupported("is expressions", node);
305 return null;
306 }
307
308 NormalizerResult visitParenExpression(ParenExpression node) {
309 final res = _visit(node.body);
310 final extraStmts = [];
311 extraStmts.addAll(res.stmts);
312 final exp = _liftExp(res, extraStmts);
313 return new NormalizerResult(extraStmts,
314 new ParenExpression(exp, node.span), res.node);
315 }
316
317 NormalizerResult visitAwaitExpression(AwaitExpression node) {
318 final stmts = [];
319 final bodyRes = _visit(node.body);
320 stmts.addAll(bodyRes.stmts);
321 final val = _asVariable(bodyRes, stmts);
322 return new NormalizerResult(stmts,
323 val != node.body ? new AwaitExpression(val, node.span) : node, null);
324 }
325
326 NormalizerResult visitDotExpression(DotExpression node) {
327 final selfRes = _visit(node.self);
328 final extraStmts = [];
329 extraStmts.addAll(selfRes.stmts);
330 final self = _liftExp(selfRes, extraStmts);
331 return new NormalizerResult(extraStmts,
332 new DotExpression(self, node.name, node.span), null);
333 }
334
335 NormalizerResult visitArgumentNode(ArgumentNode node) {
336 final valueRes = _visit(node.value);
337 final extraStmts = [];
338 extraStmts.addAll(valueRes.stmts);
339 final value = _liftExp(valueRes, extraStmts);
340 return new NormalizerResult(extraStmts, null,
341 new ArgumentNode(node.label, value, node.span));
342 }
343
344 CatchNode visitCatchNode(CatchNode node) {
345 // TODO(sigmund): implement
346 _notSupported("catch node", node);
347 return node;
348 }
349
350 NormalizerResult visitCaseNode(CaseNode node) {
351 // TODO(sigmund): implement
352 _notSupported("case node", node);
353 return null;
354 }
355
356 List _visitList(List nodes) {
357 if (nodes == null) return null;
358 List res = [];
359 for (final n in nodes) {
360 res.add(_visit(n));
361 }
362 return res;
363 }
364
365 _visit(node) {
366 if (node == null || !haveAwait.contains(node)) {
367 return new NormalizerResult.fromNode(node);
368 }
369 return node.visit(this);
370 }
371
372 Identifier _newTmp(SourceSpan span) {
373 return new Identifier(_PREFIX + _tmpVarCounter++, span);
374 }
375
376 VariableDefinition _declareVar(name, value, bool isFinal) {
377 return new VariableDefinition(
378 isFinal ? [new Token.fake(TokenKind.FINAL, value.span)] : null,
379 null, [name], [value], value.span);
380 }
381
382 Expression _liftExp(NormalizerResult r, List<Statement> extraStmts) {
383 if (r.exp is! AwaitExpression) return r.exp;
384 Identifier name = _newTmp(r.exp.span);
385 extraStmts.add(_declareVar(name, r.exp, true));
386 return new VarExpression(name, r.exp.span);
387 }
388
389 Expression _asVariable(NormalizerResult r, List<Statement> extraStmts) {
390 if (r.exp is VarExpression) return r.exp;
391 Identifier name = _newTmp(r.exp.span);
392 extraStmts.add(_declareVar(name, r.exp, true));
393 return new VarExpression(name, r.exp.span);
394 }
395
396 _notSupported(what, node) {
397 world.error("Normalization of $what is not supported yet.", node.span);
398 }
399 }
400
401 /** A temporary result of the normalization process. */
402 class NormalizerResult {
403 /** A list of statements, in order. */
404 List<Statement> stmts;
405
406 /** Normalized expression (null for normalized statements). */
407 Expression exp;
408
409 /** Resulting node for AST nodes that are not stmts or expressions. */
410 Node node;
411
412 NormalizerResult(this.stmts, this.exp, this.node);
413
414 factory NormalizerResult.fromNode(node) {
415 if (node == null) {
416 return new NormalizerResult(null, null, null);
417 } else if (node is Expression) {
418 return new NormalizerResult(const [], node, null);
419 } else if (node is Statement) {
420 return new NormalizerResult([node], null, null);
421 } else {
422 return new NormalizerResult(const [], null, node);
423 }
424 }
425
426 Statement asStatement() {
427 if (exp != null) {
428 world.fatal("asStatement only supported on statement results.", exp.span);
429 }
430 if (stmts == null) {
431 return null;
432 }
433 if (stmts.length == 1) {
434 // Return the underlying statement without wrapping it in a block, unless
435 // the statement contains an await.
436 Statement stmt = stmts.last();
437
438 if (stmt is! ExpressionStatement) return stmt;
439 ExpressionStatement expStmt = stmt;
440 Expression body = expStmt.body;
441
442 if (body is! AwaitExpression || body is! BinaryExpression) return stmt;
443
444 if (body is BinaryExpression) {
445 BinaryExpression binExp = body;
446 if (binExp.y is! AwaitExpression) return stmt;
447 }
448 }
449 return new BlockStatement(stmts, stmts.last().span);
450 }
451 }
OLDNEW
« no previous file with comments | « frog/await/nodeset.dart ('k') | frog/await/samples/dartcombat/README » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698