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

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

Issue 671513013: dart2js: Accept named holes in js-templates. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebase, and move finishedClasses to buildFinishClass. 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
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 part of js; 5 part of js;
6 6
7 class TemplateManager { 7 class TemplateManager {
8 Map<String, Template> expressionTemplates = new Map<String, Template>(); 8 Map<String, Template> expressionTemplates = new Map<String, Template>();
9 Map<String, Template> statementTemplates = new Map<String, Template>(); 9 Map<String, Template> statementTemplates = new Map<String, Template>();
10 10
(...skipping 29 matching lines...) Expand all
40 * the original with the placeholders replaced by the arguments to 40 * the original with the placeholders replaced by the arguments to
41 * [instantiate]. 41 * [instantiate].
42 */ 42 */
43 class Template { 43 class Template {
44 final String source; 44 final String source;
45 final bool isExpression; 45 final bool isExpression;
46 final bool forceCopy; 46 final bool forceCopy;
47 final Node ast; 47 final Node ast;
48 48
49 Instantiator instantiator; 49 Instantiator instantiator;
50
50 int positionalArgumentCount = -1; 51 int positionalArgumentCount = -1;
51 // TODO(sra): Named arguments. 52
53 // Null, unless there are named holes.
54 List<String> holeNames;
55 bool get isPositional => holeNames == null;
52 56
53 Template(this.source, this.ast, 57 Template(this.source, this.ast,
54 {this.isExpression: true, this.forceCopy: false}) { 58 {this.isExpression: true, this.forceCopy: false}) {
55 _compile(); 59 _compile();
56 } 60 }
57 61
58 Template.withExpressionResult(this.ast) 62 Template.withExpressionResult(this.ast)
59 : source = null, isExpression = true, forceCopy = false { 63 : source = null, isExpression = true, forceCopy = false {
60 assert(ast is Expression); 64 assert(ast is Expression);
61 assert(_checkNoPlaceholders()); 65 assert(_checkNoPlaceholders());
(...skipping 14 matching lines...) Expand all
76 new InstantiatorGeneratorVisitor(false); 80 new InstantiatorGeneratorVisitor(false);
77 generator.compile(ast); 81 generator.compile(ast);
78 return generator.analysis.count == 0; 82 return generator.analysis.count == 0;
79 } 83 }
80 84
81 void _compile() { 85 void _compile() {
82 InstantiatorGeneratorVisitor generator = 86 InstantiatorGeneratorVisitor generator =
83 new InstantiatorGeneratorVisitor(forceCopy); 87 new InstantiatorGeneratorVisitor(forceCopy);
84 instantiator = generator.compile(ast); 88 instantiator = generator.compile(ast);
85 positionalArgumentCount = generator.analysis.count; 89 positionalArgumentCount = generator.analysis.count;
90 Set<String> names = generator.analysis.holeNames;
91 holeNames = names.isEmpty ? null : names.toList(growable:false);
86 } 92 }
87 93
88 Node instantiate(List arguments) { 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) {
89 if (arguments is List) { 99 if (arguments is List) {
90 if (arguments.length != positionalArgumentCount) { 100 if (arguments.length != positionalArgumentCount) {
91 throw 'Wrong number of template arguments, given ${arguments.length}, ' 101 throw 'Wrong number of template arguments, given ${arguments.length}, '
92 'expected $positionalArgumentCount'; 102 'expected $positionalArgumentCount';
93 } 103 }
94 return instantiator(arguments); 104 return instantiator(arguments);
95 } 105 }
96 // TODO(sra): Add named placeholders and a Map of arguments. 106 assert(arguments is Map);
97 throw new UnimplementedError('Template arguments must be a list'); 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);
98 } 120 }
99 } 121 }
100 122
101 /** 123 /**
102 * An Instantiator is a Function that generates a JS AST tree or List of 124 * 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 125 * trees. [arguments] is a List for positional templates, or Map for
104 * named templates. 126 * named templates.
105 */ 127 */
106 typedef Node Instantiator(var arguments); 128 typedef Node Instantiator(var arguments);
107 129
108 130
109 /** 131 /**
110 * InstantiatorGeneratorVisitor compiles a template. This class compiles a tree 132 * InstantiatorGeneratorVisitor compiles a template. This class compiles a tree
111 * containing [InterpolatedNode]s into a function that will create a copy of the 133 * containing [InterpolatedNode]s into a function that will create a copy of the
112 * tree with the interpolated nodes substituted with provided values. 134 * tree with the interpolated nodes substituted with provided values.
113 */ 135 */
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 } 179 }
158 180
159 static RegExp identiferRE = new RegExp(r'^[A-Za-z_$][A-Za-z_$0-9]*$'); 181 static RegExp identiferRE = new RegExp(r'^[A-Za-z_$][A-Za-z_$0-9]*$');
160 182
161 static Expression convertStringToVariableUse(String value) { 183 static Expression convertStringToVariableUse(String value) {
162 assert(identiferRE.hasMatch(value)); 184 assert(identiferRE.hasMatch(value));
163 return new VariableUse(value); 185 return new VariableUse(value);
164 } 186 }
165 187
166 Instantiator visitInterpolatedExpression(InterpolatedExpression node) { 188 Instantiator visitInterpolatedExpression(InterpolatedExpression node) {
167 int position = node.name; 189 var nameOrPosition = node.nameOrPosition;
168 return (arguments) { 190 return (arguments) {
169 var value = arguments[position]; 191 var value = arguments[nameOrPosition];
170 if (value is Expression) return value; 192 if (value is Expression) return value;
171 if (value is String) return convertStringToVariableUse(value);; 193 if (value is String) return convertStringToVariableUse(value);
172 error('Interpolated value #$position is not an Expression: $value'); 194 error('Interpolated value #$nameOrPosition is not an Expression: $value');
173 }; 195 };
174 } 196 }
175 197
176 Instantiator visitSplayableExpression(Node node) { 198 Instantiator visitSplayableExpression(Node node) {
177 if (node is InterpolatedExpression) { 199 if (node is InterpolatedExpression) {
178 int position = node.name; 200 var nameOrPosition = node.nameOrPosition;
179 return (arguments) { 201 return (arguments) {
180 var value = arguments[position]; 202 var value = arguments[nameOrPosition];
181 Expression toExpression(item) { 203 Expression toExpression(item) {
182 if (item is Expression) return item; 204 if (item is Expression) return item;
183 if (item is String) return convertStringToVariableUse(item); 205 if (item is String) return convertStringToVariableUse(item);
184 return error('Interpolated value #$position is not ' 206 return error('Interpolated value #$nameOrPosition is not '
185 'an Expression or List of Expressions: $value'); 207 'an Expression or List of Expressions: $value');
186 } 208 }
187 if (value is Iterable) return value.map(toExpression); 209 if (value is Iterable) return value.map(toExpression);
188 return toExpression(value); 210 return toExpression(value);
189 }; 211 };
190 } 212 }
191 return visit(node); 213 return visit(node);
192 } 214 }
193 215
194 Instantiator visitInterpolatedLiteral(InterpolatedLiteral node) { 216 Instantiator visitInterpolatedLiteral(InterpolatedLiteral node) {
195 int position = node.name; 217 var nameOrPosition = node.nameOrPosition;
196 return (arguments) { 218 return (arguments) {
197 var value = arguments[position]; 219 var value = arguments[nameOrPosition];
198 if (value is Literal) return value; 220 if (value is Literal) return value;
199 error('Interpolated value #$position is not a Literal: $value'); 221 error('Interpolated value #$nameOrPosition is not a Literal: $value');
200 }; 222 };
201 } 223 }
202 224
203 Instantiator visitInterpolatedParameter(InterpolatedParameter node) { 225 Instantiator visitInterpolatedParameter(InterpolatedParameter node) {
204 int position = node.name; 226 var nameOrPosition = node.nameOrPosition;
205 return (arguments) { 227 return (arguments) {
206 var value = arguments[position]; 228 var value = arguments[nameOrPosition];
207 229
208 Parameter toParameter(item) { 230 Parameter toParameter(item) {
209 if (item is Parameter) return item; 231 if (item is Parameter) return item;
210 if (item is String) return new Parameter(item); 232 if (item is String) return new Parameter(item);
211 return error('Interpolated value #$position is not a Parameter or ' 233 return error('Interpolated value #$nameOrPosition is not a Parameter or'
212 'List of Parameters: $value'); 234 ' List of Parameters: $value');
213 } 235 }
214 if (value is Iterable) return value.map(toParameter); 236 if (value is Iterable) return value.map(toParameter);
215 return toParameter(value); 237 return toParameter(value);
216 }; 238 };
217 } 239 }
218 240
219 Instantiator visitInterpolatedSelector(InterpolatedSelector node) { 241 Instantiator visitInterpolatedSelector(InterpolatedSelector node) {
220 // A selector is an expression, as in `a[selector]`. 242 // A selector is an expression, as in `a[selector]`.
221 // A String argument converted into a LiteralString, so `a.#` with argument 243 // A String argument converted into a LiteralString, so `a.#` with argument
222 // 'foo' generates `a["foo"]` which prints as `a.foo`. 244 // 'foo' generates `a["foo"]` which prints as `a.foo`.
223 int position = node.name; 245 var nameOrPosition = node.nameOrPosition;
224 return (arguments) { 246 return (arguments) {
225 var value = arguments[position]; 247 var value = arguments[nameOrPosition];
226 if (value is Expression) return value; 248 if (value is Expression) return value;
227 if (value is String) return new LiteralString('"$value"'); 249 if (value is String) return new LiteralString('"$value"');
228 error('Interpolated value #$position is not a selector: $value'); 250 error('Interpolated value #$nameOrPosition is not a selector: $value');
229 }; 251 };
230 } 252 }
231 253
232 Instantiator visitInterpolatedStatement(InterpolatedStatement node) { 254 Instantiator visitInterpolatedStatement(InterpolatedStatement node) {
233 int position = node.name; 255 var nameOrPosition = node.nameOrPosition;
234 return (arguments) { 256 return (arguments) {
235 var value = arguments[position]; 257 var value = arguments[nameOrPosition];
236 if (value is Node) return value.toStatement(); 258 if (value is Node) return value.toStatement();
237 error('Interpolated value #$position is not a Statement: $value'); 259 error('Interpolated value #$nameOrPosition is not a Statement: $value');
238 }; 260 };
239 } 261 }
240 262
241 Instantiator visitSplayableStatement(Node node) { 263 Instantiator visitSplayableStatement(Node node) {
242 if (node is InterpolatedStatement) { 264 if (node is InterpolatedStatement) {
243 int position = node.name; 265 var nameOrPosition = node.nameOrPosition;
244 return (arguments) { 266 return (arguments) {
245 var value = arguments[position]; 267 var value = arguments[nameOrPosition];
246 Statement toStatement(item) { 268 Statement toStatement(item) {
247 if (item is Statement) return item; 269 if (item is Statement) return item;
248 if (item is Expression) return item.toStatement();; 270 if (item is Expression) return item.toStatement();;
249 return error('Interpolated value #$position is not ' 271 return error('Interpolated value #$nameOrPosition is not '
250 'a Statement or List of Statements: $value'); 272 'a Statement or List of Statements: $value');
251 } 273 }
252 if (value is Iterable) return value.map(toStatement); 274 if (value is Iterable) return value.map(toStatement);
253 return toStatement(value); 275 return toStatement(value);
254 }; 276 };
255 } 277 }
256 return visit(node); 278 return visit(node);
257 } 279 }
258 280
259 Instantiator visitProgram(Program node) { 281 Instantiator visitProgram(Program node) {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 if (node.condition is InterpolatedExpression) { 332 if (node.condition is InterpolatedExpression) {
311 return visitIfConditionalCompilation(node); 333 return visitIfConditionalCompilation(node);
312 } else { 334 } else {
313 return visitIfNormal(node); 335 return visitIfNormal(node);
314 } 336 }
315 } 337 }
316 338
317 Instantiator visitIfConditionalCompilation(If node) { 339 Instantiator visitIfConditionalCompilation(If node) {
318 // Special version of visitInterpolatedExpression that permits bools. 340 // Special version of visitInterpolatedExpression that permits bools.
319 compileCondition(InterpolatedExpression node) { 341 compileCondition(InterpolatedExpression node) {
320 int position = node.name; 342 var nameOrPosition = node.nameOrPosition;
321 return (arguments) { 343 return (arguments) {
322 var value = arguments[position]; 344 var value = arguments[nameOrPosition];
323 if (value is bool) return value; 345 if (value is bool) return value;
324 if (value is Expression) return value; 346 if (value is Expression) return value;
325 if (value is String) return convertStringToVariableUse(value);; 347 if (value is String) return convertStringToVariableUse(value);;
326 error('Interpolated value #$position is not an Expression: $value'); 348 error('Interpolated value #$nameOrPosition '
349 'is not an Expression: $value');
327 }; 350 };
328 } 351 }
329 var makeCondition = compileCondition(node.condition); 352 var makeCondition = compileCondition(node.condition);
330 Instantiator makeThen = visit(node.then); 353 Instantiator makeThen = visit(node.then);
331 Instantiator makeOtherwise = visit(node.otherwise); 354 Instantiator makeOtherwise = visit(node.otherwise);
332 return (arguments) { 355 return (arguments) {
333 var condition = makeCondition(arguments); 356 var condition = makeCondition(arguments);
334 if (condition is bool) { 357 if (condition is bool) {
335 if (condition == true) { 358 if (condition == true) {
336 return makeThen(arguments); 359 return makeThen(arguments);
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after
640 Instantiator visitRegExpLiteral(RegExpLiteral node) => 663 Instantiator visitRegExpLiteral(RegExpLiteral node) =>
641 (arguments) => new RegExpLiteral(node.pattern); 664 (arguments) => new RegExpLiteral(node.pattern);
642 665
643 Instantiator visitComment(Comment node) => TODO('visitComment'); 666 Instantiator visitComment(Comment node) => TODO('visitComment');
644 } 667 }
645 668
646 /** 669 /**
647 * InterpolatedNodeAnalysis extract [InterpolatedNode]s from AST. 670 * InterpolatedNodeAnalysis extract [InterpolatedNode]s from AST.
648 */ 671 */
649 class InterpolatedNodeAnalysis extends BaseVisitor { 672 class InterpolatedNodeAnalysis extends BaseVisitor {
650 final Set<Node> containsInterpolatedNode = new Set<Node>(); 673 final Setlet<Node> containsInterpolatedNode = new Setlet<Node>();
651 final List<InterpolatedNode> interpolatedNodes = <InterpolatedNode>[]; 674 final List<InterpolatedNode> interpolatedNodes = <InterpolatedNode>[];
675 final Setlet<String> holeNames = new Setlet<String>();
652 int count = 0; 676 int count = 0;
653 677
654 InterpolatedNodeAnalysis(); 678 InterpolatedNodeAnalysis();
655 679
656 bool containsInterpolatedNodes(Node node) => 680 bool containsInterpolatedNodes(Node node) =>
657 containsInterpolatedNode.contains(node); 681 containsInterpolatedNode.contains(node);
658 682
659 void visit(Node node) { 683 void visit(Node node) {
660 node.accept(this); 684 node.accept(this);
661 } 685 }
662 686
663 void visitNode(Node node) { 687 void visitNode(Node node) {
664 int before = count; 688 int before = count;
665 node.visitChildren(this); 689 node.visitChildren(this);
666 if (count != before) containsInterpolatedNode.add(node); 690 if (count != before) containsInterpolatedNode.add(node);
667 return null; 691 return null;
668 } 692 }
669 693
670 visitInterpolatedNode(InterpolatedNode node) { 694 visitInterpolatedNode(InterpolatedNode node) {
671 interpolatedNodes.add(node); 695 interpolatedNodes.add(node);
672 containsInterpolatedNode.add(node); 696 containsInterpolatedNode.add(node);
697 if (node.isNamed) holeNames.add(node.nameOrPosition);
673 ++count; 698 ++count;
674 } 699 }
675 } 700 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js/printer.dart ('k') | pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698