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