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

Side by Side Diff: pkg/compiler/lib/src/js/template.dart

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

Powered by Google App Engine
This is Rietveld 408576698