| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dev_compiler.src.codegen.js_metalet; | 5 library dev_compiler.src.codegen.js_metalet; |
| 6 | 6 |
| 7 // TODO(jmesserly): import from its own package | 7 // TODO(jmesserly): import from its own package |
| 8 import 'package:dev_compiler/src/js/js_ast.dart'; | 8 import 'package:dev_compiler/src/js/js_ast.dart'; |
| 9 import 'package:dev_compiler/src/js/precedence.dart'; | 9 import 'package:dev_compiler/src/js/precedence.dart'; |
| 10 | 10 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 /// Returns an expression that ignores the result. This is a cross between | 57 /// Returns an expression that ignores the result. This is a cross between |
| 58 /// [toExpression] and [toStatement]. Used for C-style for-loop updaters, | 58 /// [toExpression] and [toStatement]. Used for C-style for-loop updaters, |
| 59 /// which is an expression syntactically, but functions more like a statement. | 59 /// which is an expression syntactically, but functions more like a statement. |
| 60 Expression toVoidExpression() { | 60 Expression toVoidExpression() { |
| 61 var block = toStatement(); | 61 var block = toStatement(); |
| 62 var s = block.statements; | 62 var s = block.statements; |
| 63 if (s.length == 1 && s.first is ExpressionStatement) { | 63 if (s.length == 1 && s.first is ExpressionStatement) { |
| 64 ExpressionStatement es = s.first; | 64 ExpressionStatement es = s.first; |
| 65 return es.expression; | 65 return es.expression; |
| 66 } | 66 } |
| 67 return new Call(new ArrowFun([], block), []); | 67 |
| 68 return _toInvokedFunction(block); |
| 68 } | 69 } |
| 69 | 70 |
| 70 Expression toAssignExpression(Expression left) { | 71 Expression toAssignExpression(Expression left) { |
| 71 if (left is Identifier) { | 72 if (left is Identifier) { |
| 72 var simple = _simplifyAssignment(left); | 73 var simple = _simplifyAssignment(left); |
| 73 if (simple != null) return simple; | 74 if (simple != null) return simple; |
| 74 | 75 |
| 75 var exprs = body.toList(); | 76 var exprs = body.toList(); |
| 76 exprs.add(exprs.removeLast().toAssignExpression(left)); | 77 exprs.add(exprs.removeLast().toAssignExpression(left)); |
| 77 return new MetaLet(variables, exprs); | 78 return new MetaLet(variables, exprs); |
| 78 } | 79 } |
| 79 return super.toAssignExpression(left); | 80 return super.toAssignExpression(left); |
| 80 } | 81 } |
| 81 | 82 |
| 82 Statement toVariableDeclaration(Identifier name) { | 83 Statement toVariableDeclaration(Identifier name) { |
| 83 var simple = _simplifyAssignment(name, isDeclaration: true); | 84 var simple = _simplifyAssignment(name, isDeclaration: true); |
| 84 if (simple != null) return simple.toStatement(); | 85 if (simple != null) return simple.toStatement(); |
| 85 return super.toVariableDeclaration(name); | 86 return super.toVariableDeclaration(name); |
| 86 } | 87 } |
| 87 | 88 |
| 88 Expression toExpression() { | 89 Expression toExpression() { |
| 89 if (_expression != null) return _expression; | 90 if (_expression != null) return _expression; |
| 90 var block = toReturn(); | 91 var block = toReturn(); |
| 91 var s = block.statements; | 92 var s = block.statements; |
| 92 if (s.length == 1 && s.first is Return) { | 93 if (s.length == 1 && s.first is Return) { |
| 93 Return es = s.first; | 94 Return es = s.first; |
| 94 return _expression = es.value; | 95 return _expression = es.value; |
| 95 } | 96 } |
| 96 // Wrap it in an immediately called function to get in expression context. | 97 // Wrap it in an immediately called function to get in expression context. |
| 97 // TODO(jmesserly): | 98 return _expression = _toInvokedFunction(block); |
| 98 return _expression = new Call(new ArrowFun([], block), []); | |
| 99 } | 99 } |
| 100 | 100 |
| 101 Block toStatement() { | 101 Block toStatement() { |
| 102 // Skip return value if not used. | 102 // Skip return value if not used. |
| 103 var statements = body.map((e) => e.toStatement()).toList(); | 103 var statements = body.map((e) => e.toStatement()).toList(); |
| 104 if (statelessResult) statements.removeLast(); | 104 if (statelessResult) statements.removeLast(); |
| 105 return _finishStatement(statements); | 105 return _finishStatement(statements); |
| 106 } | 106 } |
| 107 | 107 |
| 108 Block toReturn() { | 108 Block toReturn() { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 122 | 122 |
| 123 accept(NodeVisitor visitor) => toExpression().accept(visitor); | 123 accept(NodeVisitor visitor) => toExpression().accept(visitor); |
| 124 | 124 |
| 125 void visitChildren(NodeVisitor visitor) { | 125 void visitChildren(NodeVisitor visitor) { |
| 126 toExpression().visitChildren(visitor); | 126 toExpression().visitChildren(visitor); |
| 127 } | 127 } |
| 128 | 128 |
| 129 /// This generates as either a comma expression or a call. | 129 /// This generates as either a comma expression or a call. |
| 130 int get precedenceLevel => variables.isEmpty ? EXPRESSION : CALL; | 130 int get precedenceLevel => variables.isEmpty ? EXPRESSION : CALL; |
| 131 | 131 |
| 132 Expression _toInvokedFunction(Statement block) { |
| 133 var finder = new _YieldFinder(); |
| 134 block.accept(finder); |
| 135 if (!finder.hasYield) { |
| 136 return new Call(new ArrowFun([], block), []); |
| 137 } |
| 138 // If we have a yield, it's more tricky. We'll create a `function*`, which |
| 139 // we `yield*` to immediately invoke. We also may need to bind this: |
| 140 Expression fn = new Fun([], block, isGenerator: true); |
| 141 if (finder.hasThis) fn = js.call('#.bind(this)', fn); |
| 142 return new Yield(new Call(fn, []), star: true); |
| 143 } |
| 144 |
| 132 Block _finishStatement(List<Statement> statements) { | 145 Block _finishStatement(List<Statement> statements) { |
| 133 var params = <TemporaryId>[]; | 146 var params = <TemporaryId>[]; |
| 134 var values = <Expression>[]; | 147 var values = <Expression>[]; |
| 135 var block = _build(params, values, new Block(statements)); | 148 var block = _build(params, values, new Block(statements)); |
| 136 if (params.isEmpty) return block; | 149 if (params.isEmpty) return block; |
| 137 | 150 |
| 138 var vars = []; | 151 var vars = []; |
| 139 for (int i = 0; i < params.length; i++) { | 152 for (int i = 0; i < params.length; i++) { |
| 140 vars.add(new VariableInitialization(params[i], values[i])); | 153 vars.add(new VariableInitialization(params[i], values[i])); |
| 141 } | 154 } |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 223 | 236 |
| 224 var newBody = new Expression.binary([assign]..addAll(body), ','); | 237 var newBody = new Expression.binary([assign]..addAll(body), ','); |
| 225 Binary comma = new Template(null, newBody).safeCreate({name: left}); | 238 Binary comma = new Template(null, newBody).safeCreate({name: left}); |
| 226 return new MetaLet(vars, comma.commaToExpressionList(), | 239 return new MetaLet(vars, comma.commaToExpressionList(), |
| 227 statelessResult: statelessResult); | 240 statelessResult: statelessResult); |
| 228 } | 241 } |
| 229 } | 242 } |
| 230 | 243 |
| 231 class _VariableUseCounter extends BaseVisitor { | 244 class _VariableUseCounter extends BaseVisitor { |
| 232 final counts = <String, int>{}; | 245 final counts = <String, int>{}; |
| 233 visitInterpolatedExpression(InterpolatedExpression node) { | 246 @override visitInterpolatedExpression(InterpolatedExpression node) { |
| 234 int n = counts[node.nameOrPosition]; | 247 int n = counts[node.nameOrPosition]; |
| 235 counts[node.nameOrPosition] = n == null ? 1 : n + 1; | 248 counts[node.nameOrPosition] = n == null ? 1 : n + 1; |
| 236 } | 249 } |
| 237 } | 250 } |
| 238 | 251 |
| 239 class _IdentFinder extends BaseVisitor { | 252 class _IdentFinder extends BaseVisitor { |
| 240 final String name; | 253 final String name; |
| 241 bool found = false; | 254 bool found = false; |
| 242 _IdentFinder(this.name); | 255 _IdentFinder(this.name); |
| 243 | 256 |
| 244 visitIdentifier(Identifier node) { | 257 @override visitIdentifier(Identifier node) { |
| 245 if (node.name == name) found = true; | 258 if (node.name == name) found = true; |
| 246 } | 259 } |
| 247 visitNode(Node node) { | 260 @override visitNode(Node node) { |
| 248 if (!found) super.visitNode(node); | 261 if (!found) super.visitNode(node); |
| 249 } | 262 } |
| 250 } | 263 } |
| 264 |
| 265 class _YieldFinder extends BaseVisitor { |
| 266 bool hasYield = false; |
| 267 bool hasThis = false; |
| 268 bool _nestedFunction = false; |
| 269 @override visitThis(This node) { |
| 270 hasThis = true; |
| 271 } |
| 272 @override visitFunctionExpression(FunctionExpression node) { |
| 273 var savedNested = _nestedFunction; |
| 274 _nestedFunction = true; |
| 275 super.visitFunctionExpression(node); |
| 276 _nestedFunction = savedNested; |
| 277 } |
| 278 @override visitYield(Yield node) { |
| 279 if (!_nestedFunction) hasYield = true; |
| 280 } |
| 281 @override visitNode(Node node) { |
| 282 if (!hasYield) super.visitNode(node); |
| 283 } |
| 284 } |
| OLD | NEW |