| Index: frog/await/normalizer.dart
|
| diff --git a/frog/await/normalizer.dart b/frog/await/normalizer.dart
|
| deleted file mode 100644
|
| index 9c557d5a2e61d932f35e1fde4790f5afbe05832c..0000000000000000000000000000000000000000
|
| --- a/frog/await/normalizer.dart
|
| +++ /dev/null
|
| @@ -1,451 +0,0 @@
|
| -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -/**
|
| - * Normalizes the AST to make the translation in [AwaitProcessor] simpler. This
|
| - * normalization provides the following guarantees:
|
| - * - await only occurs in top-level assignments. For example:
|
| - * if (await t) return;
|
| - * after normalization should become:
|
| - * final $t = await t;
|
| - * if ($t) return;
|
| - *
|
| - * - await in declarations are split in multiple declarations:
|
| - * int x = 1, y = await t, z = 3, w = y;
|
| - * becomes:
|
| - * int x = 1;
|
| - * int y = await t;
|
| - * int z = 3, w = y;
|
| - *
|
| - * - await cannot occur on complex assignments:
|
| - * x += await t
|
| - * becomes:
|
| - * $t = await t
|
| - * x += $t
|
| - *
|
| - * - await cannot occur outside statement blocks:
|
| - * if (...) x = await t
|
| - * becomes:
|
| - * if (...) { x = await t }
|
| - */
|
| -class AwaitNormalizer implements TreeVisitor {
|
| - // TODO(sigmund): fix frog to make it possible to switch to '_a:tmp'. The
|
| - // mangling code currently breaks across closure-boundaries.
|
| - static final _PREFIX = '_a_tmp';
|
| - int _tmpVarCounter = 0;
|
| -
|
| - /** AST nodes that contain await expressions. */
|
| - NodeSet haveAwait;
|
| -
|
| - AwaitNormalizer(this.haveAwait);
|
| -
|
| - NormalizerResult visitVariableDefinition(VariableDefinition node) {
|
| - // split variable declarations in chuncks:
|
| - List<Statement> res = [];
|
| - List<Identifier> names = [];
|
| - List<Expression> values = [];
|
| - for (int i = 0; i < node.names.length; i++) {
|
| - final val = node.values[i];
|
| - if (val == null || !haveAwait.contains(val)) {
|
| - names.add(node.names[i]);
|
| - values.add(val);
|
| - } else {
|
| - // an await was found, declare previous vars first:
|
| - if (names.length > 0) {
|
| - res.add(new VariableDefinition(
|
| - node.modifiers, node.type, names, values, node.span));
|
| - names = [];
|
| - values = [];
|
| - }
|
| - final valRes = _visit(val);
|
| - res.addAll(valRes.stmts);
|
| - // add the declaration directly, since all following vars should
|
| - // be in a separate declaration
|
| - final newDecl = new VariableDefinition(node.modifiers, node.type,
|
| - [node.names[i]], [valRes.exp], node.span);
|
| - res.add(newDecl);
|
| - }
|
| - }
|
| - if (names.length > 0) {
|
| - res.add(new VariableDefinition(
|
| - node.modifiers, node.type, names, values, node.span));
|
| - }
|
| - return new NormalizerResult(res, null, null);
|
| - }
|
| -
|
| - NormalizerResult visitFunctionDefinition(FunctionDefinition node) {
|
| - if (!haveAwait.contains(node)) return null;
|
| - node.body = _visit(node.body).asStatement(); // normalize and replace body.
|
| - }
|
| -
|
| - NormalizerResult visitReturnStatement(ReturnStatement node) {
|
| - final expRes = _visit(node.value);
|
| - final res = new NormalizerResult([], null, null);
|
| - res.stmts.addAll(expRes.stmts);
|
| - res.stmts.add(new ReturnStatement(expRes.exp, node.span));
|
| - return res;
|
| - }
|
| -
|
| - NormalizerResult visitThrowStatement(ThrowStatement node) {
|
| - final expRes = _visit(node.value);
|
| - final res = new NormalizerResult([], null, null);
|
| - res.stmts.addAll(expRes.stmts);
|
| - res.stmts.add(new ThrowStatement(expRes.exp, node.span));
|
| - return res;
|
| - }
|
| -
|
| - NormalizerResult visitIfStatement(IfStatement node) {
|
| - final testRes = _visit(node.test);
|
| - final trueRes = _visit(node.trueBranch).asStatement();
|
| - final falseRes = _visit(node.falseBranch).asStatement();
|
| - final res = new NormalizerResult([], null, null);
|
| - res.stmts.addAll(testRes.stmts);
|
| - final exp = _liftExp(testRes, res.stmts);
|
| - res.stmts.add(new IfStatement(exp, trueRes, falseRes, node.span));
|
| - return res;
|
| - }
|
| -
|
| - NormalizerResult visitWhileStatement(WhileStatement node) {
|
| - final testRes = _visit(node.test);
|
| - final bodyRes = _visit(node.body).asStatement();
|
| - final res = new NormalizerResult([], null, null);
|
| - res.stmts.addAll(testRes.stmts);
|
| - final exp = _liftExp(testRes, res.stmts);
|
| - res.stmts.add(new WhileStatement(exp, bodyRes, node.span));
|
| - return res;
|
| - }
|
| -
|
| - NormalizerResult visitDoStatement(DoStatement node) {
|
| - final bodyRes = _visit(node.body);
|
| - final testRes = _visit(node.test);
|
| - final bodyList = [bodyRes.asStatement()];
|
| - bodyList.addAll(testRes.stmts);
|
| - final exp = _liftExp(testRes, bodyList);
|
| - final body = new BlockStatement(bodyList, node.span);
|
| - return new NormalizerResult.fromNode(
|
| - new DoStatement(body, exp, node.span));
|
| - }
|
| -
|
| - NormalizerResult visitForStatement(ForStatement node) {
|
| - // TODO(sigmund): implement
|
| - _notSupported("for loops", node);
|
| - return null;
|
| - }
|
| -
|
| - NormalizerResult visitForInStatement(ForInStatement node) {
|
| - _notSupported("for-in loops", node);
|
| - return null;
|
| - }
|
| -
|
| - NormalizerResult visitTryStatement(TryStatement node) {
|
| - final bodyRes = _visit(node.body);
|
| - List<CatchNode> catchesRes = [];
|
| - for (NormalizerResult r in _visitList(node.catches)) {
|
| - assert (r.node != null && r.node is CatchNode);
|
| - catchesRes.add(r.node);
|
| - }
|
| - final finallyRes = _visit(node.finallyBlock);
|
| -
|
| - return new NormalizerResult.fromNode(
|
| - new TryStatement(bodyRes.asStatement(),
|
| - catchesRes, finallyRes.asStatement(), node.span));
|
| - }
|
| -
|
| - NormalizerResult visitSwitchStatement(SwitchStatement node) {
|
| - _notSupported("switch statements", node);
|
| - return null;
|
| - }
|
| -
|
| - NormalizerResult visitBlockStatement(BlockStatement node) {
|
| - final bodyRes = _visitList(node.body);
|
| - final newBlock = [];
|
| - for (NormalizerResult b in bodyRes) {
|
| - newBlock.addAll(b.stmts);
|
| - if (b.exp != null) {
|
| - world.fatal(
|
| - "unexpected: expression result from normalizing block", node.span);
|
| -
|
| - }
|
| - }
|
| - return new NormalizerResult.fromNode(
|
| - new BlockStatement(newBlock, node.span));
|
| - }
|
| -
|
| - NormalizerResult visitLabeledStatement(LabeledStatement node) {
|
| - return new NormalizerResult.fromNode(new LabeledStatement(
|
| - node.name, _visit(node.body).asStatement(), node.span));
|
| - }
|
| -
|
| - visitAssertStatement(AssertStatement node) {
|
| - // We can normalize
|
| - // assert await M;
|
| - // as:
|
| - // var x = false;
|
| - // assert (x = true); // ensure await is only evaluated when assertions
|
| - // // are enabled
|
| - // if (x) {
|
| - // var t = await M;
|
| - // assert t;
|
| - // }
|
| - _notSupported("assert statements", node);
|
| - return null;
|
| - }
|
| -
|
| - NormalizerResult visitExpressionStatement(ExpressionStatement node) {
|
| - final bodyRes = _visit(node.body);
|
| - final res = new NormalizerResult([], null, null);
|
| - res.stmts.addAll(bodyRes.stmts);
|
| - res.stmts.add(new ExpressionStatement(bodyRes.exp, node.span));
|
| - return res;
|
| - }
|
| -
|
| - NormalizerResult visitCallExpression(CallExpression node) {
|
| - final targetRes = _visit(node.target);
|
| - final argsRes = _visitList(node.arguments);
|
| - final extraStmts = [];
|
| - final newArgs = [];
|
| - extraStmts.addAll(targetRes.stmts);
|
| - final target = _liftExp(targetRes, extraStmts);
|
| - for (final arg in argsRes) {
|
| - extraStmts.addAll(arg.stmts);
|
| - newArgs.add(arg.node);
|
| - }
|
| - return new NormalizerResult(extraStmts,
|
| - new CallExpression(target, newArgs, node.span), null);
|
| - }
|
| -
|
| - NormalizerResult visitIndexExpression(IndexExpression node) {
|
| - final targetRes = _visit(node.target);
|
| - final indexRes = _visit(node.index);
|
| - final extraStmts = [];
|
| - extraStmts.addAll(targetRes.stmts);
|
| - final target = _liftExp(targetRes, extraStmts);
|
| - extraStmts.addAll(indexRes.stmts);
|
| - final index = _liftExp(indexRes, extraStmts);
|
| - return new NormalizerResult(extraStmts,
|
| - new IndexExpression(target, index, node.span), null);
|
| - }
|
| -
|
| - NormalizerResult visitBinaryExpression(BinaryExpression node) {
|
| - final xRes = _visit(node.x);
|
| - final yRes = _visit(node.y);
|
| - final extraStmts = [];
|
| - extraStmts.addAll(xRes.stmts);
|
| - final x = _liftExp(xRes, extraStmts);
|
| - if (node.op.kind == TokenKind.OR || node.op.kind == TokenKind.AND) {
|
| - // AND and OR require short-circuiting code:
|
| - final otherStmts = [];
|
| - otherStmts.addAll(yRes.stmts);
|
| - final y = _liftExp(yRes, otherStmts);
|
| - final tmpId = _newTmp(node.span);
|
| - extraStmts.add(_declareVar(tmpId, x, false));
|
| - final tmpVar = new VarExpression(tmpId, node.span);
|
| - Expression test = tmpVar;
|
| - if (node.op.kind == TokenKind.OR) {
|
| - // (a && b) becomes t = a; if (t) t = b; (t)
|
| - // (a || b) becomes t = a; if (!t) t = b; (t)
|
| - test = new UnaryExpression(
|
| - new Token.fake(TokenKind.NOT, node.op.span), test, node.op.span);
|
| - }
|
| - otherStmts.add(new ExpressionStatement(
|
| - new BinaryExpression(new Token.fake(TokenKind.ASSIGN, node.span),
|
| - tmpVar, y, y.span), y.span));
|
| - extraStmts.add(new IfStatement(test,
|
| - new BlockStatement(otherStmts, node.y.span), null, node.y.span));
|
| - return new NormalizerResult(extraStmts, tmpVar, null);
|
| - } else {
|
| - extraStmts.addAll(yRes.stmts);
|
| - // Other operators require a var-lifting the rhs if they contain an await:
|
| - final y = _liftExp(yRes, extraStmts);
|
| - return new NormalizerResult(extraStmts,
|
| - new BinaryExpression(node.op, x, y, node.span), null);
|
| - }
|
| - }
|
| -
|
| - NormalizerResult visitUnaryExpression(UnaryExpression node) {
|
| - // TODO(sigmund): implement
|
| - _notSupported("unary expressions", node);
|
| - return null;
|
| - }
|
| -
|
| - NormalizerResult visitPostfixExpression(PostfixExpression node) {
|
| - // TODO(sigmund): implement
|
| - _notSupported("postfix expressions", node);
|
| - return null;
|
| - }
|
| -
|
| - NormalizerResult visitNewExpression(NewExpression node) {
|
| - // TODO(sigmund): implement
|
| - _notSupported("new expressions", node);
|
| - return null;
|
| - }
|
| -
|
| - NormalizerResult visitListExpression(ListExpression node) {
|
| - // TODO(sigmund): implement
|
| - _notSupported("list literals", node);
|
| - return null;
|
| - }
|
| -
|
| - NormalizerResult visitMapExpression(MapExpression node) {
|
| - // TODO(sigmund): implement
|
| - _notSupported("map literals", node);
|
| - return null;
|
| - }
|
| -
|
| - NormalizerResult visitConditionalExpression(ConditionalExpression node) {
|
| - // TODO(sigmund): implement
|
| - _notSupported("ternary expressions", node);
|
| - return null;
|
| - }
|
| -
|
| - NormalizerResult visitIsExpression(IsExpression node) {
|
| - // TODO(sigmund): implement
|
| - _notSupported("is expressions", node);
|
| - return null;
|
| - }
|
| -
|
| - NormalizerResult visitParenExpression(ParenExpression node) {
|
| - final res = _visit(node.body);
|
| - final extraStmts = [];
|
| - extraStmts.addAll(res.stmts);
|
| - final exp = _liftExp(res, extraStmts);
|
| - return new NormalizerResult(extraStmts,
|
| - new ParenExpression(exp, node.span), res.node);
|
| - }
|
| -
|
| - NormalizerResult visitAwaitExpression(AwaitExpression node) {
|
| - final stmts = [];
|
| - final bodyRes = _visit(node.body);
|
| - stmts.addAll(bodyRes.stmts);
|
| - final val = _asVariable(bodyRes, stmts);
|
| - return new NormalizerResult(stmts,
|
| - val != node.body ? new AwaitExpression(val, node.span) : node, null);
|
| - }
|
| -
|
| - NormalizerResult visitDotExpression(DotExpression node) {
|
| - final selfRes = _visit(node.self);
|
| - final extraStmts = [];
|
| - extraStmts.addAll(selfRes.stmts);
|
| - final self = _liftExp(selfRes, extraStmts);
|
| - return new NormalizerResult(extraStmts,
|
| - new DotExpression(self, node.name, node.span), null);
|
| - }
|
| -
|
| - NormalizerResult visitArgumentNode(ArgumentNode node) {
|
| - final valueRes = _visit(node.value);
|
| - final extraStmts = [];
|
| - extraStmts.addAll(valueRes.stmts);
|
| - final value = _liftExp(valueRes, extraStmts);
|
| - return new NormalizerResult(extraStmts, null,
|
| - new ArgumentNode(node.label, value, node.span));
|
| - }
|
| -
|
| - CatchNode visitCatchNode(CatchNode node) {
|
| - // TODO(sigmund): implement
|
| - _notSupported("catch node", node);
|
| - return node;
|
| - }
|
| -
|
| - NormalizerResult visitCaseNode(CaseNode node) {
|
| - // TODO(sigmund): implement
|
| - _notSupported("case node", node);
|
| - return null;
|
| - }
|
| -
|
| - List _visitList(List nodes) {
|
| - if (nodes == null) return null;
|
| - List res = [];
|
| - for (final n in nodes) {
|
| - res.add(_visit(n));
|
| - }
|
| - return res;
|
| - }
|
| -
|
| - _visit(node) {
|
| - if (node == null || !haveAwait.contains(node)) {
|
| - return new NormalizerResult.fromNode(node);
|
| - }
|
| - return node.visit(this);
|
| - }
|
| -
|
| - Identifier _newTmp(SourceSpan span) {
|
| - return new Identifier(_PREFIX + _tmpVarCounter++, span);
|
| - }
|
| -
|
| - VariableDefinition _declareVar(name, value, bool isFinal) {
|
| - return new VariableDefinition(
|
| - isFinal ? [new Token.fake(TokenKind.FINAL, value.span)] : null,
|
| - null, [name], [value], value.span);
|
| - }
|
| -
|
| - Expression _liftExp(NormalizerResult r, List<Statement> extraStmts) {
|
| - if (r.exp is! AwaitExpression) return r.exp;
|
| - Identifier name = _newTmp(r.exp.span);
|
| - extraStmts.add(_declareVar(name, r.exp, true));
|
| - return new VarExpression(name, r.exp.span);
|
| - }
|
| -
|
| - Expression _asVariable(NormalizerResult r, List<Statement> extraStmts) {
|
| - if (r.exp is VarExpression) return r.exp;
|
| - Identifier name = _newTmp(r.exp.span);
|
| - extraStmts.add(_declareVar(name, r.exp, true));
|
| - return new VarExpression(name, r.exp.span);
|
| - }
|
| -
|
| - _notSupported(what, node) {
|
| - world.error("Normalization of $what is not supported yet.", node.span);
|
| - }
|
| -}
|
| -
|
| -/** A temporary result of the normalization process. */
|
| -class NormalizerResult {
|
| - /** A list of statements, in order. */
|
| - List<Statement> stmts;
|
| -
|
| - /** Normalized expression (null for normalized statements). */
|
| - Expression exp;
|
| -
|
| - /** Resulting node for AST nodes that are not stmts or expressions. */
|
| - Node node;
|
| -
|
| - NormalizerResult(this.stmts, this.exp, this.node);
|
| -
|
| - factory NormalizerResult.fromNode(node) {
|
| - if (node == null) {
|
| - return new NormalizerResult(null, null, null);
|
| - } else if (node is Expression) {
|
| - return new NormalizerResult(const [], node, null);
|
| - } else if (node is Statement) {
|
| - return new NormalizerResult([node], null, null);
|
| - } else {
|
| - return new NormalizerResult(const [], null, node);
|
| - }
|
| - }
|
| -
|
| - Statement asStatement() {
|
| - if (exp != null) {
|
| - world.fatal("asStatement only supported on statement results.", exp.span);
|
| - }
|
| - if (stmts == null) {
|
| - return null;
|
| - }
|
| - if (stmts.length == 1) {
|
| - // Return the underlying statement without wrapping it in a block, unless
|
| - // the statement contains an await.
|
| - Statement stmt = stmts.last();
|
| -
|
| - if (stmt is! ExpressionStatement) return stmt;
|
| - ExpressionStatement expStmt = stmt;
|
| - Expression body = expStmt.body;
|
| -
|
| - if (body is! AwaitExpression || body is! BinaryExpression) return stmt;
|
| -
|
| - if (body is BinaryExpression) {
|
| - BinaryExpression binExp = body;
|
| - if (binExp.y is! AwaitExpression) return stmt;
|
| - }
|
| - }
|
| - return new BlockStatement(stmts, stmts.last().span);
|
| - }
|
| -}
|
|
|