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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js/template.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of js;
6
7 class TemplateManager {
8 Map<String, Template> expressionTemplates = new Map<String, Template>();
9 Map<String, Template> statementTemplates = new Map<String, Template>();
10
11 TemplateManager();
12
13
14 Template lookupExpressionTemplate(String source) {
15 return expressionTemplates[source];
16 }
17
18 Template defineExpressionTemplate(String source, Node ast) {
19 Template template =
20 new Template(source, ast, isExpression: true, forceCopy: false);
21 expressionTemplates[source] = template;
22 return template;
23 }
24
25 Template lookupStatementTemplate(String source) {
26 return statementTemplates[source];
27 }
28
29 Template defineStatementTemplate(String source, Node ast) {
30 Template template =
31 new Template(source, ast, isExpression: false, forceCopy: false);
32 statementTemplates[source] = template;
33 return template;
34 }
35 }
36
37 /**
38 * A Template is created with JavaScript AST containing placeholders (interface
39 * InterpolatedNode). The [instantiate] method creates an AST that looks like
40 * the original with the placeholders replaced by the arguments to
41 * [instantiate].
42 */
43 class Template {
44 final String source;
45 final bool isExpression;
46 final bool forceCopy;
47 final Node ast;
48
49 Instantiator instantiator;
50 int positionalArgumentCount = -1;
51 // TODO(sra): Named arguments.
52
53 Template(this.source, this.ast,
54 {this.isExpression: true, this.forceCopy: false}) {
55 _compile();
56 }
57
58 Template.withExpressionResult(this.ast)
59 : source = null, isExpression = true, forceCopy = false {
60 assert(ast is Expression);
61 assert(_checkNoPlaceholders());
62 positionalArgumentCount = 0;
63 instantiator = (arguments) => ast;
64 }
65
66 Template.withStatementResult(this.ast)
67 : source = null, isExpression = false, forceCopy = false {
68 assert(ast is Statement);
69 assert(_checkNoPlaceholders());
70 positionalArgumentCount = 0;
71 instantiator = (arguments) => ast;
72 }
73
74 bool _checkNoPlaceholders() {
75 InstantiatorGeneratorVisitor generator =
76 new InstantiatorGeneratorVisitor(false);
77 generator.compile(ast);
78 return generator.analysis.count == 0;
79 }
80
81 void _compile() {
82 InstantiatorGeneratorVisitor generator =
83 new InstantiatorGeneratorVisitor(forceCopy);
84 instantiator = generator.compile(ast);
85 positionalArgumentCount = generator.analysis.count;
86 }
87
88 Node instantiate(List arguments) {
89 if (arguments is List) {
90 if (arguments.length != positionalArgumentCount) {
91 throw 'Wrong number of template arguments, given ${arguments.length}, '
92 'expected $positionalArgumentCount';
93 }
94 return instantiator(arguments);
95 }
96 // TODO(sra): Add named placeholders and a Map of arguments.
97 throw new UnimplementedError('Template arguments must be a list');
98 }
99 }
100
101 /**
102 * An Instantiator is a Function that generates a JS AST tree or List of
103 * trees. [arguments] is a List for positional templates, or (TODO) Map for
104 * named templates.
105 */
106 typedef Node Instantiator(var arguments);
107
108
109 /**
110 * InstantiatorGeneratorVisitor compiles a template. This class compiles a tree
111 * containing [InterpolatedNode]s into a function that will create a copy of the
112 * tree with the interpolated nodes substituted with provided values.
113 */
114 class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
115
116 final bool forceCopy;
117
118 InterpolatedNodeAnalysis analysis = new InterpolatedNodeAnalysis();
119
120 /**
121 * The entire tree is cloned if [forceCopy] is true.
122 */
123 InstantiatorGeneratorVisitor(this.forceCopy);
124
125 Instantiator compile(Node node) {
126 analysis.visit(node);
127 Instantiator result = visit(node);
128 return result;
129 }
130
131 static error(String message) {
132 throw message;
133 }
134
135 static Instantiator same(Node node) => (arguments) => node;
136 static Node makeNull(arguments) => null;
137
138 Instantiator visit(Node node) {
139 if (forceCopy || analysis.containsInterpolatedNodes(node)) {
140 return node.accept(this);
141 }
142 return same(node);
143 }
144
145 Instantiator visitNullable(Node node) {
146 if (node == null) return makeNull;
147 return visit(node);
148 }
149
150 Instantiator visitSplayable(Node node) {
151 // TODO(sra): Process immediate [InterpolatedNode]s, permitting splaying.
152 return visit(node);
153 }
154
155 Instantiator visitNode(Node node) {
156 throw 'Unimplemented InstantiatorGeneratorVisitor for $node';
157 }
158
159 static RegExp identiferRE = new RegExp(r'^[A-Za-z_$][A-Za-z_$0-9]*$');
160
161 static Expression convertStringToVariableUse(String value) {
162 assert(identiferRE.hasMatch(value));
163 return new VariableUse(value);
164 }
165
166 Instantiator visitInterpolatedExpression(InterpolatedExpression node) {
167 int position = node.name;
168 return (arguments) {
169 var value = arguments[position];
170 if (value is Expression) return value;
171 if (value is String) return convertStringToVariableUse(value);;
172 error('Interpolated value #$position is not an Expression: $value');
173 };
174 }
175
176 Instantiator visitSplayableExpression(Node node) {
177 if (node is InterpolatedExpression) {
178 int position = node.name;
179 return (arguments) {
180 var value = arguments[position];
181 Expression toExpression(item) {
182 if (item is Expression) return item;
183 if (item is String) return convertStringToVariableUse(item);
184 return error('Interpolated value #$position is not '
185 'an Expression or List of Expressions: $value');
186 }
187 if (value is Iterable) return value.map(toExpression);
188 return toExpression(value);
189 };
190 }
191 return visit(node);
192 }
193
194 Instantiator visitInterpolatedLiteral(InterpolatedLiteral node) {
195 int position = node.name;
196 return (arguments) {
197 var value = arguments[position];
198 if (value is Literal) return value;
199 error('Interpolated value #$position is not a Literal: $value');
200 };
201 }
202
203 Instantiator visitInterpolatedParameter(InterpolatedParameter node) {
204 int position = node.name;
205 return (arguments) {
206 var value = arguments[position];
207
208 Parameter toParameter(item) {
209 if (item is Parameter) return item;
210 if (item is String) return new Parameter(item);
211 return error('Interpolated value #$position is not a Parameter or '
212 'List of Parameters: $value');
213 }
214 if (value is Iterable) return value.map(toParameter);
215 return toParameter(value);
216 };
217 }
218
219 Instantiator visitInterpolatedSelector(InterpolatedSelector node) {
220 // A selector is an expression, as in `a[selector]`.
221 // A String argument converted into a LiteralString, so `a.#` with argument
222 // 'foo' generates `a["foo"]` which prints as `a.foo`.
223 int position = node.name;
224 return (arguments) {
225 var value = arguments[position];
226 if (value is Expression) return value;
227 if (value is String) return new LiteralString('"$value"');
228 error('Interpolated value #$position is not a selector: $value');
229 };
230 }
231
232 Instantiator visitInterpolatedStatement(InterpolatedStatement node) {
233 int position = node.name;
234 return (arguments) {
235 var value = arguments[position];
236 if (value is Node) return value.toStatement();
237 error('Interpolated value #$position is not a Statement: $value');
238 };
239 }
240
241 Instantiator visitSplayableStatement(Node node) {
242 if (node is InterpolatedStatement) {
243 int position = node.name;
244 return (arguments) {
245 var value = arguments[position];
246 Statement toStatement(item) {
247 if (item is Statement) return item;
248 if (item is Expression) return item.toStatement();;
249 return error('Interpolated value #$position is not '
250 'a Statement or List of Statements: $value');
251 }
252 if (value is Iterable) return value.map(toStatement);
253 return toStatement(value);
254 };
255 }
256 return visit(node);
257 }
258
259 Instantiator visitProgram(Program node) {
260 List instantiators = node.body.map(visitSplayableStatement).toList();
261 return (arguments) {
262 List<Statement> statements = <Statement>[];
263 void add(node) {
264 if (node is EmptyStatement) return;
265 if (node is Iterable) {
266 statements.addAll(node);
267 } else {
268 statements.add(node.toStatement());
269 }
270 }
271 for (Instantiator instantiator in instantiators) {
272 add(instantiator(arguments));
273 }
274 return new Program(statements);
275 };
276 }
277
278 Instantiator visitBlock(Block node) {
279 List instantiators = node.statements.map(visitSplayableStatement).toList();
280 return (arguments) {
281 List<Statement> statements = <Statement>[];
282 void add(node) {
283 if (node is EmptyStatement) return;
284 if (node is Iterable) {
285 statements.addAll(node);
286 } else if (node is Block) {
287 statements.addAll(node.statements);
288 } else {
289 statements.add(node.toStatement());
290 }
291 }
292 for (Instantiator instantiator in instantiators) {
293 add(instantiator(arguments));
294 }
295 return new Block(statements);
296 };
297 }
298
299 Instantiator visitExpressionStatement(ExpressionStatement node) {
300 Instantiator buildExpression = visit(node.expression);
301 return (arguments) {
302 return buildExpression(arguments).toStatement();
303 };
304 }
305
306 Instantiator visitEmptyStatement(EmptyStatement node) =>
307 (arguments) => new EmptyStatement();
308
309 Instantiator visitIf(If node) {
310 if (node.condition is InterpolatedExpression) {
311 return visitIfConditionalCompilation(node);
312 } else {
313 return visitIfNormal(node);
314 }
315 }
316
317 Instantiator visitIfConditionalCompilation(If node) {
318 // Special version of visitInterpolatedExpression that permits bools.
319 compileCondition(InterpolatedExpression node) {
320 int position = node.name;
321 return (arguments) {
322 var value = arguments[position];
323 if (value is bool) return value;
324 if (value is Expression) return value;
325 if (value is String) return convertStringToVariableUse(value);;
326 error('Interpolated value #$position is not an Expression: $value');
327 };
328 }
329 var makeCondition = compileCondition(node.condition);
330 Instantiator makeThen = visit(node.then);
331 Instantiator makeOtherwise = visit(node.otherwise);
332 return (arguments) {
333 var condition = makeCondition(arguments);
334 if (condition is bool) {
335 if (condition == true) {
336 return makeThen(arguments);
337 } else {
338 return makeOtherwise(arguments);
339 }
340 }
341 return new If(
342 condition,
343 makeThen(arguments),
344 makeOtherwise(arguments));
345 };
346 }
347
348 Instantiator visitIfNormal(If node) {
349 Instantiator makeCondition = visit(node.condition);
350 Instantiator makeThen = visit(node.then);
351 Instantiator makeOtherwise = visit(node.otherwise);
352 return (arguments) {
353 return new If(
354 makeCondition(arguments),
355 makeThen(arguments),
356 makeOtherwise(arguments));
357 };
358 }
359
360 Instantiator visitFor(For node) {
361 Instantiator makeInit = visitNullable(node.init);
362 Instantiator makeCondition = visitNullable(node.condition);
363 Instantiator makeUpdate = visitNullable(node.update);
364 Instantiator makeBody = visit(node.body);
365 return (arguments) {
366 return new For(
367 makeInit(arguments), makeCondition(arguments), makeUpdate(arguments),
368 makeBody(arguments));
369 };
370 }
371
372 Instantiator visitForIn(ForIn node) {
373 Instantiator makeLeftHandSide = visit(node.leftHandSide);
374 Instantiator makeObject = visit(node.object);
375 Instantiator makeBody = visit(node.body);
376 return (arguments) {
377 return new ForIn(
378 makeLeftHandSide(arguments),
379 makeObject(arguments),
380 makeBody(arguments));
381 };
382 }
383
384 TODO(String name) {
385 throw new UnimplementedError('$this.$name');
386 }
387
388 Instantiator visitWhile(While node) => TODO('visitWhile');
389 Instantiator visitDo(Do node) => TODO('visitDo');
390
391 Instantiator visitContinue(Continue node) =>
392 (arguments) => new Continue(node.targetLabel);
393
394 Instantiator visitBreak(Break node) =>
395 (arguments) => new Break(node.targetLabel);
396
397 Instantiator visitReturn(Return node) {
398 Instantiator makeExpression = visitNullable(node.value);
399 return (arguments) => new Return(makeExpression(arguments));
400 }
401
402 Instantiator visitThrow(Throw node) {
403 Instantiator makeExpression = visit(node.expression);
404 return (arguments) => new Throw(makeExpression(arguments));
405 }
406
407
408 Instantiator visitTry(Try node) {
409 Instantiator makeBody = visit(node.body);
410 Instantiator makeCatch = visitNullable(node.catchPart);
411 Instantiator makeFinally = visitNullable(node.finallyPart);
412 return (arguments) => new Try(
413 makeBody(arguments), makeCatch(arguments), makeFinally(arguments));
414 }
415
416 Instantiator visitCatch(Catch node) {
417 Instantiator makeDeclaration = visit(node.declaration);
418 Instantiator makeBody = visit(node.body);
419 return (arguments) => new Catch(
420 makeDeclaration(arguments), makeBody(arguments));
421 }
422
423 Instantiator visitSwitch(Switch node) => TODO('visitSwitch');
424 Instantiator visitCase(Case node) => TODO('visitCase');
425 Instantiator visitDefault(Default node) => TODO('visitDefault');
426
427 Instantiator visitFunctionDeclaration(FunctionDeclaration node) {
428 Instantiator makeName = visit(node.name);
429 Instantiator makeFunction = visit(node.function);
430 return (arguments) =>
431 new FunctionDeclaration(makeName(arguments), makeFunction(arguments));
432 }
433
434 Instantiator visitLabeledStatement(LabeledStatement node) =>
435 TODO('visitLabeledStatement');
436 Instantiator visitLiteralStatement(LiteralStatement node) =>
437 TODO('visitLiteralStatement');
438 Instantiator visitBlob(Blob node) =>
439 TODO('visitBlob');
440 Instantiator visitLiteralExpression(LiteralExpression node) =>
441 TODO('visitLiteralExpression');
442
443 Instantiator visitVariableDeclarationList(VariableDeclarationList node) {
444 List<Instantiator> declarationMakers =
445 node.declarations.map(visit).toList();
446 return (arguments) {
447 List<VariableInitialization> declarations = <VariableInitialization>[];
448 for (Instantiator instantiator in declarationMakers) {
449 var result = instantiator(arguments);
450 declarations.add(result);
451 }
452 return new VariableDeclarationList(declarations);
453 };
454 }
455
456 Instantiator visitAssignment(Assignment node) {
457 Instantiator makeLeftHandSide = visit(node.leftHandSide);
458 String op = node.op;
459 Instantiator makeValue = visitNullable(node.value);
460 return (arguments) {
461 return new Assignment.compound(
462 makeLeftHandSide(arguments),
463 op,
464 makeValue(arguments));
465 };
466 }
467
468 Instantiator visitVariableInitialization(VariableInitialization node) {
469 Instantiator makeDeclaration = visit(node.declaration);
470 Instantiator makeValue = visitNullable(node.value);
471 return (arguments) {
472 return new VariableInitialization(
473 makeDeclaration(arguments), makeValue(arguments));
474 };
475 }
476
477 Instantiator visitConditional(Conditional cond) {
478 Instantiator makeCondition = visit(cond.condition);
479 Instantiator makeThen = visit(cond.then);
480 Instantiator makeOtherwise = visit(cond.otherwise);
481 return (arguments) => new Conditional(
482 makeCondition(arguments),
483 makeThen(arguments),
484 makeOtherwise(arguments));
485 }
486
487 Instantiator visitNew(New node) =>
488 handleCallOrNew(node, (target, arguments) => new New(target, arguments));
489
490 Instantiator visitCall(Call node) =>
491 handleCallOrNew(node, (target, arguments) => new Call(target, arguments));
492
493 Instantiator handleCallOrNew(Call node, finish(target, arguments)) {
494 Instantiator makeTarget = visit(node.target);
495 Iterable<Instantiator> argumentMakers =
496 node.arguments.map(visitSplayableExpression).toList();
497
498 // TODO(sra): Avoid copying call arguments if no interpolation or forced
499 // copying.
500 return (arguments) {
501 Node target = makeTarget(arguments);
502 List<Expression> callArguments = <Expression>[];
503 for (Instantiator instantiator in argumentMakers) {
504 var result = instantiator(arguments);
505 if (result is Iterable) {
506 callArguments.addAll(result);
507 } else {
508 callArguments.add(result);
509 }
510 }
511 return finish(target, callArguments.toList(growable: false));
512 };
513 }
514
515 Instantiator visitBinary(Binary node) {
516 Instantiator makeLeft = visit(node.left);
517 Instantiator makeRight = visit(node.right);
518 String op = node.op;
519 return (arguments) =>
520 new Binary(op, makeLeft(arguments), makeRight(arguments));
521 }
522
523 Instantiator visitPrefix(Prefix node) {
524 Instantiator makeOperand = visit(node.argument);
525 String op = node.op;
526 return (arguments) => new Prefix(op, makeOperand(arguments));
527 }
528
529 Instantiator visitPostfix(Postfix node) {
530 Instantiator makeOperand = visit(node.argument);
531 String op = node.op;
532 return (arguments) => new Postfix(op, makeOperand(arguments));
533 }
534
535 Instantiator visitVariableUse(VariableUse node) =>
536 (arguments) => new VariableUse(node.name);
537
538 Instantiator visitThis(This node) => (arguments) => new This();
539
540 Instantiator visitVariableDeclaration(VariableDeclaration node) =>
541 (arguments) => new VariableDeclaration(node.name);
542
543 Instantiator visitParameter(Parameter node) =>
544 (arguments) => new Parameter(node.name);
545
546 Instantiator visitAccess(PropertyAccess node) {
547 Instantiator makeReceiver = visit(node.receiver);
548 Instantiator makeSelector = visit(node.selector);
549 return (arguments) =>
550 new PropertyAccess(makeReceiver(arguments), makeSelector(arguments));
551 }
552
553 Instantiator visitNamedFunction(NamedFunction node) {
554 Instantiator makeDeclaration = visit(node.name);
555 Instantiator makeFunction = visit(node.function);
556 return (arguments) =>
557 new NamedFunction(makeDeclaration(arguments), makeFunction(arguments));
558 }
559
560 Instantiator visitFun(Fun node) {
561 List<Instantiator> paramMakers = node.params.map(visitSplayable).toList();
562 Instantiator makeBody = visit(node.body);
563 // TODO(sra): Avoid copying params if no interpolation or forced copying.
564 return (arguments) {
565 List<Parameter> params = <Parameter>[];
566 for (Instantiator instantiator in paramMakers) {
567 var result = instantiator(arguments);
568 if (result is Iterable) {
569 params.addAll(result);
570 } else {
571 params.add(result);
572 }
573 }
574 Statement body = makeBody(arguments);
575 return new Fun(params, body);
576 };
577 }
578
579 Instantiator visitLiteralBool(LiteralBool node) =>
580 (arguments) => new LiteralBool(node.value);
581
582 Instantiator visitLiteralString(LiteralString node) =>
583 (arguments) => new LiteralString(node.value);
584
585 Instantiator visitLiteralNumber(LiteralNumber node) =>
586 (arguments) => new LiteralNumber(node.value);
587
588 Instantiator visitLiteralNull(LiteralNull node) =>
589 (arguments) => new LiteralNull();
590
591 Instantiator visitArrayInitializer(ArrayInitializer node) {
592 // Assume array has no missing elements.
593 // TODO(sra): Implement splicing?
594 List<Instantiator> elementMakers = node.elements
595 .map((ArrayElement element) => visit(element.value))
596 .toList();
597 return (arguments) {
598 List<ArrayElement> elements = <ArrayElement>[];
599 void add(Expression value) {
600 elements.add(new ArrayElement(elements.length, value));
601 }
602 for (Instantiator instantiator in elementMakers) {
603 var result = instantiator(arguments);
604 add(result);
605 }
606 return new ArrayInitializer(elements.length, elements);
607 };
608 }
609
610 Instantiator visitArrayElement(ArrayElement node) {
611 throw 'Should not get here'; // Handled in visitArrayInitializer.
612 }
613
614 Instantiator visitObjectInitializer(ObjectInitializer node) {
615 List<Instantiator> propertyMakers =
616 node.properties.map(visitSplayable).toList();
617 bool isOneLiner = node.isOneLiner;
618 return (arguments) {
619 List<Property> properties = <Property>[];
620 for (Instantiator instantiator in propertyMakers) {
621 var result = instantiator(arguments);
622 if (result is Iterable) {
623 properties.addAll(result);
624 } else {
625 properties.add(result);
626 }
627 }
628 return new ObjectInitializer(properties, isOneLiner: isOneLiner);
629 };
630 }
631
632 Instantiator visitProperty(Property node) {
633 Instantiator makeName = visit(node.name);
634 Instantiator makeValue = visit(node.value);
635 return (arguments) {
636 return new Property(makeName(arguments), makeValue(arguments));
637 };
638 }
639
640 Instantiator visitRegExpLiteral(RegExpLiteral node) =>
641 (arguments) => new RegExpLiteral(node.pattern);
642
643 Instantiator visitComment(Comment node) => TODO('visitComment');
644 }
645
646 /**
647 * InterpolatedNodeAnalysis extract [InterpolatedNode]s from AST.
648 */
649 class InterpolatedNodeAnalysis extends BaseVisitor {
650 final Set<Node> containsInterpolatedNode = new Set<Node>();
651 final List<InterpolatedNode> interpolatedNodes = <InterpolatedNode>[];
652 int count = 0;
653
654 InterpolatedNodeAnalysis();
655
656 bool containsInterpolatedNodes(Node node) =>
657 containsInterpolatedNode.contains(node);
658
659 void visit(Node node) {
660 node.accept(this);
661 }
662
663 void visitNode(Node node) {
664 int before = count;
665 node.visitChildren(this);
666 if (count != before) containsInterpolatedNode.add(node);
667 return null;
668 }
669
670 visitInterpolatedNode(InterpolatedNode node) {
671 interpolatedNodes.add(node);
672 containsInterpolatedNode.add(node);
673 ++count;
674 }
675 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698