OLD | NEW |
---|---|
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 dart_tree; | 5 library dart_tree; |
6 | 6 |
7 import '../dart2jslib.dart' as dart2js; | 7 import '../dart2jslib.dart' as dart2js; |
8 import '../dart_types.dart'; | 8 import '../dart_types.dart'; |
9 import '../util/util.dart'; | 9 import '../util/util.dart'; |
10 import '../elements/elements.dart' show FunctionElement, FunctionSignature; | 10 import '../elements/elements.dart' show FunctionElement, FunctionSignature; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
58 identifier = Emitter.makeIdentifier(name); | 58 identifier = Emitter.makeIdentifier(name); |
59 return identifier; | 59 return identifier; |
60 } | 60 } |
61 | 61 |
62 final bool isPure = true; | 62 final bool isPure = true; |
63 | 63 |
64 accept(Visitor visitor) => visitor.visitVariable(this); | 64 accept(Visitor visitor) => visitor.visitVariable(this); |
65 } | 65 } |
66 | 66 |
67 /** | 67 /** |
68 * A sequence of expressions. | |
69 */ | |
70 class Sequence extends Expression { | |
71 final List<Expression> expressions; | |
72 | |
73 Sequence(this.expressions); | |
74 | |
75 bool get isPure => expressions.every((e) => e.isPure); | |
76 | |
77 accept(Visitor visitor) => visitor.visitSequence(this); | |
78 } | |
79 | |
80 /** | |
68 * A local binding of a [Variable] to an [Expression]. | 81 * A local binding of a [Variable] to an [Expression]. |
69 * | 82 * |
70 * In contrast to the CPS-based IR, non-primitive expressions can be named | 83 * In contrast to the CPS-based IR, non-primitive expressions can be named |
71 * with let. | 84 * with let. |
72 */ | 85 */ |
73 class LetVal extends Expression { | 86 class LetVal extends Expression { |
74 final Variable variable; | 87 final Variable variable; |
75 final Expression definition; | 88 final Expression definition; |
76 final Expression body; | 89 final Expression body; |
77 | 90 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
127 accept(Visitor visitor) => visitor.visitConstant(this); | 140 accept(Visitor visitor) => visitor.visitConstant(this); |
128 } | 141 } |
129 | 142 |
130 abstract class Visitor<T> { | 143 abstract class Visitor<T> { |
131 // Abstract classes. | 144 // Abstract classes. |
132 T visitNode(Node node) => node.accept(this); | 145 T visitNode(Node node) => node.accept(this); |
133 T visitExpression(Expression node) => visitNode(node); | 146 T visitExpression(Expression node) => visitNode(node); |
134 | 147 |
135 // Concrete classes. | 148 // Concrete classes. |
136 T visitVariable(Variable node) => visitExpression(node); | 149 T visitVariable(Variable node) => visitExpression(node); |
150 T visitSequence(Sequence node) => visitExpression(node); | |
137 T visitLetVal(LetVal node) => visitExpression(node); | 151 T visitLetVal(LetVal node) => visitExpression(node); |
138 T visitInvokeStatic(InvokeStatic node) => visitExpression(node); | 152 T visitInvokeStatic(InvokeStatic node) => visitExpression(node); |
139 T visitReturn(Return node) => visitExpression(node); | 153 T visitReturn(Return node) => visitExpression(node); |
140 T visitConstant(Constant node) => visitExpression(node); | 154 T visitConstant(Constant node) => visitExpression(node); |
141 } | 155 } |
142 | 156 |
143 /** | 157 /** |
144 * Builder translates from CPS-based IR to direct-style Tree. | 158 * Builder translates from CPS-based IR to direct-style Tree. |
145 * | 159 * |
146 * A call `Invoke(fun, cont, args)`, where cont is a singly-referenced | 160 * A call `Invoke(fun, cont, args)`, where cont is a singly-referenced |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
190 | 204 |
191 Expression visitFunction(ir.Function node) { | 205 Expression visitFunction(ir.Function node) { |
192 // Functions are simplistically translated to their bodies. For now this | 206 // Functions are simplistically translated to their bodies. For now this |
193 // is good enough. | 207 // is good enough. |
194 returnContinuation = node.returnContinuation; | 208 returnContinuation = node.returnContinuation; |
195 return node.body.accept(this); | 209 return node.body.accept(this); |
196 } | 210 } |
197 | 211 |
198 Expression visitLetPrim(ir.LetPrim node) { | 212 Expression visitLetPrim(ir.LetPrim node) { |
199 // LetPrim is translated to LetVal. | 213 // LetPrim is translated to LetVal. |
200 Variable variable = new Variable(); | |
201 Expression definition = node.primitive.accept(this); | 214 Expression definition = node.primitive.accept(this); |
202 variables[node.primitive] = variable; | 215 if (node.primitive.hasAtLeastOneUse) { |
203 return new LetVal(variable, definition, node.body.accept(this)); | 216 Variable variable = new Variable(); |
217 variables[node.primitive] = variable; | |
218 return new LetVal(variable, definition, node.body.accept(this)); | |
219 } else { | |
220 return new Sequence([definition, node.body.accept(this)]); | |
221 } | |
204 } | 222 } |
205 | 223 |
206 Expression visitLetCont(ir.LetCont node) { | 224 Expression visitLetCont(ir.LetCont node) { |
207 // TODO(kmillikin): Allow continuations to have multiple uses. This could | 225 // TODO(kmillikin): Allow continuations to have multiple uses. This could |
208 // arise due to the representation of local control flow or due to | 226 // arise due to the representation of local control flow or due to |
209 // optimization. | 227 // optimization. |
210 assert(node.continuation.hasAtMostOneUse); | 228 assert(node.continuation.hasAtMostOneUse); |
211 return node.body.accept(this); | 229 return node.body.accept(this); |
212 } | 230 } |
213 | 231 |
214 Expression visitInvokeStatic(ir.InvokeStatic node) { | 232 Expression visitInvokeStatic(ir.InvokeStatic node) { |
215 // Calls are translated to direct style. | 233 // Calls are translated to direct style. |
216 List<Expression> arguments = translateArguments(node.arguments); | 234 List<Expression> arguments = translateArguments(node.arguments); |
217 Expression invoke = new InvokeStatic(node.target, arguments); | 235 Expression invoke = new InvokeStatic(node.target, arguments); |
218 ir.Continuation cont = node.continuation.definition; | 236 ir.Continuation cont = node.continuation.definition; |
219 if (cont == returnContinuation) { | 237 if (cont == returnContinuation) { |
220 return new Return(invoke); | 238 return new Return(invoke); |
221 } else { | 239 } else { |
222 assert(cont.hasExactlyOneUse); | 240 assert(cont.hasExactlyOneUse); |
223 Variable variable = new Variable(); | 241 if (cont.parameter.hasAtLeastOneUse) { |
224 variables[cont.parameter] = variable; | 242 Variable variable = new Variable(); |
225 return new LetVal(variable, invoke, cont.body.accept(this)); | 243 variables[cont.parameter] = variable; |
244 return new LetVal(variable, invoke, cont.body.accept(this)); | |
245 } else { | |
246 return new Sequence([invoke, cont.body.accept(this)]); | |
247 } | |
226 } | 248 } |
227 } | 249 } |
228 | 250 |
229 Expression visitInvokeContinuation(ir.InvokeContinuation node) { | 251 Expression visitInvokeContinuation(ir.InvokeContinuation node) { |
230 // TODO(kmillikin): Support non-return continuations. These could arise | 252 // TODO(kmillikin): Support non-return continuations. These could arise |
231 // due to local control flow or due to inlining or other optimization. | 253 // due to local control flow or due to inlining or other optimization. |
232 assert(node.continuation.definition == returnContinuation); | 254 assert(node.continuation.definition == returnContinuation); |
233 return new Return(variables[node.argument.definition]); | 255 return new Return(variables[node.argument.definition]); |
234 } | 256 } |
235 | 257 |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
313 } else if (!environment[i].definition.isPure) { | 335 } else if (!environment[i].definition.isPure) { |
314 // Once the first impure definition is seen, impure definitions should | 336 // Once the first impure definition is seen, impure definitions should |
315 // no longer be propagated. Continue searching for a pure definition. | 337 // no longer be propagated. Continue searching for a pure definition. |
316 seenImpure = true; | 338 seenImpure = true; |
317 } | 339 } |
318 } | 340 } |
319 // If the definition could not be propagated, leave the variable use. | 341 // If the definition could not be propagated, leave the variable use. |
320 return node; | 342 return node; |
321 } | 343 } |
322 | 344 |
345 Expression visitSequence(Sequence node) { | |
346 for (int i = 0; i < node.expressions.length; ++i) { | |
347 node.expressions[i] = node.expressions[i].accept(this); | |
348 } | |
349 return node; | |
350 } | |
351 | |
323 Expression visitLetVal(LetVal node) { | 352 Expression visitLetVal(LetVal node) { |
324 environment.add(node); | 353 environment.add(node); |
325 Expression body = node.body.accept(this); | 354 Expression body = node.body.accept(this); |
326 | 355 |
327 // TODO(kmillikin): Allow definitions that are not propagated. Currently, | 356 // TODO(kmillikin): Allow definitions that are not propagated. Currently, |
328 // the only bindings are anonymous intermediate values (which only have one | 357 // the only bindings are anonymous intermediate values (which only have one |
329 // use in the absence of optimizations) and they are not reordered. | 358 // use in the absence of optimizations) and they are not reordered. |
330 assert(!environment.contains(node)); | 359 assert(!environment.contains(node)); |
331 return body; | 360 return body; |
332 } | 361 } |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
472 ast.Expression value = (body as ast.Return).expression; | 501 ast.Expression value = (body as ast.Return).expression; |
473 if (value is ast.LiteralNull) { | 502 if (value is ast.LiteralNull) { |
474 // '{ return null; }' is '{}'. | 503 // '{ return null; }' is '{}'. |
475 body = makeBlock([]); | 504 body = makeBlock([]); |
476 } else { | 505 } else { |
477 // '{ return e; }' is '=> e;'. | 506 // '{ return e; }' is '=> e;'. |
478 body = new ast.Return(new SymbolToken(FUNCTION_INFO, -1), | 507 body = new ast.Return(new SymbolToken(FUNCTION_INFO, -1), |
479 semicolon, | 508 semicolon, |
480 value); | 509 value); |
481 } | 510 } |
511 } else if (body is ast.Block) { | |
512 // Remove a final 'return null' that ends the body block. | |
513 Link<ast.Node> nodes = (body as ast.Block).statements.nodes; | |
514 ast.Node last; | |
515 for (var n in nodes) { | |
floitsch
2014/04/04 11:14:27
Why not ast.Node last = nodes.last; or even
if (no
| |
516 last = n; | |
517 } | |
518 if (last is ast.Return) { | |
519 List<ast.Node> statements = | |
520 (body as ast.Block).statements.nodes.toList(); | |
521 statements.removeLast(); | |
522 body = makeBlock(statements); | |
523 } | |
482 } | 524 } |
483 | 525 |
484 return new ast.FunctionExpression(name, parameters, body, returnType, | 526 return new ast.FunctionExpression(name, parameters, body, returnType, |
485 ast.Modifiers.EMPTY, null, null); | 527 ast.Modifiers.EMPTY, null, null); |
486 } | 528 } |
487 | 529 |
488 /** | 530 /** |
489 * Translate a list of arguments to an AST NodeList. | 531 * Translate a list of arguments to an AST NodeList. |
490 */ | 532 */ |
491 ast.NodeList translateArguments(List<Expression> args) { | 533 ast.NodeList translateArguments(List<Expression> args) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
527 new ast.NodeList(openBrace, statements.toLink(), closeBrace)); | 569 new ast.NodeList(openBrace, statements.toLink(), closeBrace)); |
528 } | 570 } |
529 | 571 |
530 ast.Node visitVariable(Variable node) { | 572 ast.Node visitVariable(Variable node) { |
531 // The scope of variables is the body of their binding, so a name has | 573 // The scope of variables is the body of their binding, so a name has |
532 // already been generated when we visit a variable. | 574 // already been generated when we visit a variable. |
533 assert(node.identifier != null); | 575 assert(node.identifier != null); |
534 return new ast.Send(null, node.identifier); | 576 return new ast.Send(null, node.identifier); |
535 } | 577 } |
536 | 578 |
579 ast.Node visitSequence(Sequence node) { | |
580 return node.expressions.map((e) => e.accept(this)).reduce(concatenate); | |
581 } | |
582 | |
537 ast.Node visitLetVal(LetVal node) { | 583 ast.Node visitLetVal(LetVal node) { |
538 // Let bindings translate into assignments. | 584 // Let bindings translate into assignments. |
539 ast.Identifier identifier = node.variable.assignIdentifier(); | 585 ast.Identifier identifier = node.variable.assignIdentifier(); |
540 variables.add(identifier); | 586 variables.add(identifier); |
541 | 587 |
542 ast.Expression expression = node.definition.accept(this); | 588 ast.Expression expression = node.definition.accept(this); |
543 ast.Expression assignment = makeAssignment(identifier, expression); | 589 ast.Expression assignment = makeAssignment(identifier, expression); |
544 | 590 |
545 ast.Node rest = node.body.accept(this); | 591 ast.Node rest = node.body.accept(this); |
546 return concatenate(assignment, rest); | 592 return concatenate(assignment, rest); |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
669 } | 715 } |
670 | 716 |
671 ast.Expression visitInterceptor(dart2js.InterceptorConstant constant) { | 717 ast.Expression visitInterceptor(dart2js.InterceptorConstant constant) { |
672 return unimplemented(); | 718 return unimplemented(); |
673 } | 719 } |
674 | 720 |
675 ast.Expression visitDummy(dart2js.DummyConstant constant) { | 721 ast.Expression visitDummy(dart2js.DummyConstant constant) { |
676 return unimplemented(); | 722 return unimplemented(); |
677 } | 723 } |
678 } | 724 } |
OLD | NEW |