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

Side by Side Diff: utils/template/parser.dart

Issue 10010009: Calculator App for ChromeOS with fixes for templates/CSS to support this application. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Mininimal templates and more text node tests. Created 8 years, 8 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
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 3
4 class TagStack { 4 class TagStack {
5 List<ASTNode> _stack; 5 List<ASTNode> _stack;
6 6
7 TagStack(var elem) : _stack = [] { 7 TagStack(var elem) : _stack = [] {
8 _stack.add(elem); 8 _stack.add(elem);
9 } 9 }
10 10
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 _previousToken = _peekToken; 101 _previousToken = _peekToken;
102 _peekToken = tokenizer.next(inTag); 102 _peekToken = tokenizer.next(inTag);
103 return _previousToken; 103 return _previousToken;
104 } 104 }
105 105
106 bool _peekKind(int kind) { 106 bool _peekKind(int kind) {
107 return _peekToken.kind == kind; 107 return _peekToken.kind == kind;
108 } 108 }
109 109
110 /* Is the next token a legal identifier? This includes pseudo-keywords. */ 110 /* Is the next token a legal identifier? This includes pseudo-keywords. */
111 bool _peekIdentifier() { 111 bool _peekIdentifier([String name = null]) {
112 return TokenKind.isIdentifier(_peekToken.kind); 112 if (TokenKind.isIdentifier(_peekToken.kind)) {
113 return (name != null) ? _peekToken.text == name : true;
114 }
115
116 return false;
113 } 117 }
114 118
115 bool _maybeEat(int kind) { 119 bool _maybeEat(int kind) {
116 if (_peekToken.kind == kind) { 120 if (_peekToken.kind == kind) {
117 _previousToken = _peekToken; 121 _previousToken = _peekToken;
118 _peekToken = tokenizer.next(); 122 if (kind == TokenKind.GREATER_THAN) {
123 _peekToken = tokenizer.next(false);
124 } else {
125 _peekToken = tokenizer.next();
126 }
119 return true; 127 return true;
120 } else { 128 } else {
121 return false; 129 return false;
122 } 130 }
123 } 131 }
124 132
125 void _eat(int kind) { 133 void _eat(int kind) {
126 if (!_maybeEat(kind)) { 134 if (!_maybeEat(kind)) {
127 _errorExpected(TokenKind.kindToString(kind)); 135 _errorExpected(TokenKind.kindToString(kind));
128 } 136 }
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 // List<String> arg1, etc). 209 // List<String> arg1, etc).
202 var type = processAsIdentifier(); 210 var type = processAsIdentifier();
203 var paramName = processAsIdentifier(); 211 var paramName = processAsIdentifier();
204 if (type != null && paramName != null) { 212 if (type != null && paramName != null) {
205 params.add({'type': type, 'name' : paramName}); 213 params.add({'type': type, 'name' : paramName});
206 214
207 if (!_maybeEat(TokenKind.COMMA)) { 215 if (!_maybeEat(TokenKind.COMMA)) {
208 break; 216 break;
209 } 217 }
210 } else { 218 } else {
211 _error("Template paramter missing type and name", _makeSpan(start)); 219 // No parameters we're done.
212 break; 220 break;
213 } 221 }
214 } 222 }
215 223
216 _eat(TokenKind.RPAREN); 224 _eat(TokenKind.RPAREN);
217 225
218 TemplateSignature sig = 226 TemplateSignature sig =
219 new TemplateSignature(templateName.name, params, _makeSpan(start)); 227 new TemplateSignature(templateName.name, params, _makeSpan(start));
220 228
221 TemplateContent content = processTemplateContent(); 229 TemplateContent content = processTemplateContent();
(...skipping 14 matching lines...) Expand all
236 return identifier(); 244 return identifier();
237 } else if (TokenKind.validTagName(_peek())) { 245 } else if (TokenKind.validTagName(_peek())) {
238 var tok = _next(); 246 var tok = _next();
239 return new Identifier(TokenKind.tagNameFromTokenId(tok.kind), 247 return new Identifier(TokenKind.tagNameFromTokenId(tok.kind),
240 _makeSpan(start)); 248 _makeSpan(start));
241 } 249 }
242 } 250 }
243 251
244 css.Stylesheet processCSS() { 252 css.Stylesheet processCSS() {
245 // Is there a CSS block? 253 // Is there a CSS block?
246 if (_peekIdentifier()) { 254 if (_peekIdentifier('css')) {
255 _next();
256
247 int start = _peekToken.start; 257 int start = _peekToken.start;
248 if (identifier().name == 'css') { 258 _eat(TokenKind.LBRACE);
249 _eat(TokenKind.LBRACE);
250 259
251 css.Stylesheet cssCtx = processCSSContent(source, tokenizer.startIndex); 260 css.Stylesheet cssCtx = processCSSContent(source, tokenizer.startIndex);
252 261
253 // TODO(terry): Hack, restart template parser where CSS parser stopped. 262 // TODO(terry): Hack, restart template parser where CSS parser stopped.
254 tokenizer.index = lastCSSIndexParsed; 263 tokenizer.index = lastCSSIndexParsed;
255 _next(false); 264 _next(false);
256 265
257 _eat(TokenKind.RBRACE); // close } of css block 266 _eat(TokenKind.RBRACE); // close } of css block
258 267
259 return cssCtx; 268 return cssCtx;
269 }
270 }
271
272 // TODO(terry): get should be able to use all template control flow but return
273 // a string instead of a node. Maybe expose both html and get
274 // e.g.,
275 //
276 // A.)
277 // html {
278 // <div>...</div>
279 // }
280 //
281 // B.)
282 // html foo() {
283 // <div>..</div>
284 // }
285 //
286 // C.)
287 // get {
288 // <div>...</div>
289 // }
290 //
291 // D.)
292 // get foo() {
293 // <div>..</div>
294 // }
295 //
296 // Only one default allower either A or C the constructor will
297 // generate a string or a node.
298 // Examples B and D would generate getters that either return
299 // a node for B or a String for D.
300 //
301 List<TemplateGetter> processGetters() {
302 List<TemplateGetter> getters = [];
303
304 while (true) {
305 if (_peekIdentifier('get')) {
306 _next();
307
308 int start = _peekToken.start;
309 if (_peekIdentifier()) {
310 String getterName = identifier().name;
311
312 List<Map<Identifier, Identifier>> params =
313 new List<Map<Identifier, Identifier>>();
314
315 _eat(TokenKind.LPAREN);
316
317 start = _peekToken.start;
318 while (true) {
319 // TODO(terry): Need robust Dart argument parser (e.g.,
320 // List<String> arg1, etc).
321 var type = processAsIdentifier();
322 var paramName = processAsIdentifier();
323 if (paramName == null && type != null) {
324 paramName = type;
325 type = "";
326 }
327 if (type != null && paramName != null) {
328 params.add({'type': type, 'name' : paramName});
329
330 if (!_maybeEat(TokenKind.COMMA)) {
331 break;
332 }
333 } else {
334 // No parameters we're done.
335 break;
336 }
337 }
338
339 _eat(TokenKind.RPAREN);
340
341 _eat(TokenKind.LBRACE);
342
343 var elems = new TemplateElement.fragment(_makeSpan(_peekToken.start));
344 var templateDoc = processHTML(elems);
345
346 _eat(TokenKind.RBRACE); // close } of get block
347
348 getters.add(new TemplateGetter(getterName, params, templateDoc,
349 _makeSpan(_peekToken.start)));
350 }
351 } else {
352 break;
260 } 353 }
261 } 354 }
355
356 return getters;
357
358 /*
359 get newTotal(value) {
360 <div class="alignleft">${value}</div>
361 }
362
363 String get HTML_newTotal(value) {
364 return '<div class="alignleft">${value}</div>
365 }
366
367 */
262 } 368 }
369
263 TemplateContent processTemplateContent() { 370 TemplateContent processTemplateContent() {
264 css.Stylesheet stylesheet; 371 css.Stylesheet ss;
265 372
266 _eat(TokenKind.LBRACE); 373 _eat(TokenKind.LBRACE);
267 374
268 int start = _peekToken.start; 375 int start = _peekToken.start;
269 376
270 stylesheet = processCSS(); 377 ss = processCSS();
378
379 // TODO(terry): getters should be allowed anywhere not just after CSS.
380 List<TemplateGetter> getters = processGetters();
271 381
272 var elems = new TemplateElement.fragment(_makeSpan(_peekToken.start)); 382 var elems = new TemplateElement.fragment(_makeSpan(_peekToken.start));
273 var templateDoc = processHTML(elems); 383 var templateDoc = processHTML(elems);
274 384
275 // TODO(terry): Should allow css { } to be at beginning or end of the 385 // TODO(terry): Should allow css { } to be at beginning or end of the
276 // template's content. Today css only allow at beginning 386 // template's content. Today css only allow at beginning
277 // because the css {...} is sucked in as a text node. We'll 387 // because the css {...} is sucked in as a text node. We'll
278 // need a special escape for css maybe: 388 // need a special escape for css maybe:
279 // 389 //
280 // ${#css} 390 // ${#css}
281 // ${/css} 391 // ${/css}
282 // 392 //
283 // uggggly! 393 // uggggly!
284 394
395
285 _eat(TokenKind.RBRACE); 396 _eat(TokenKind.RBRACE);
286 397
287 return new TemplateContent(stylesheet, templateDoc, _makeSpan(start)); 398 return new TemplateContent(ss, templateDoc, getters, _makeSpan(start));
288 } 399 }
289 400
290 int lastCSSIndexParsed; // TODO(terry): Hack, last good CSS parsed. 401 int lastCSSIndexParsed; // TODO(terry): Hack, last good CSS parsed.
291 402
292 css.Stylesheet processCSSContent(var cssSource, int start) { 403 css.Stylesheet processCSSContent(var cssSource, int start) {
293 try { 404 try {
294 css.Parser parser = new css.Parser(new SourceFile( 405 css.Parser parser = new css.Parser(new SourceFile(
295 SourceFile.IN_MEMORY_FILE, cssSource.text), start); 406 SourceFile.IN_MEMORY_FILE, cssSource.text), start);
296 407
297 css.Stylesheet stylesheet = parser.parse(false, new ErrorMsgRedirector()); 408 css.Stylesheet stylesheet = parser.parse(false, new ErrorMsgRedirector());
(...skipping 30 matching lines...) Expand all
328 Map<String, TemplateAttribute> attrs = processAttributes(); 439 Map<String, TemplateAttribute> attrs = processAttributes();
329 440
330 String varName; 441 String varName;
331 if (attrs.containsKey('var')) { 442 if (attrs.containsKey('var')) {
332 varName = attrs['var'].value; 443 varName = attrs['var'].value;
333 attrs.remove('var'); 444 attrs.remove('var');
334 } 445 }
335 446
336 int scopeType; // 1 implies scoped, 2 implies non-scoped element. 447 int scopeType; // 1 implies scoped, 2 implies non-scoped element.
337 if (_maybeEat(TokenKind.GREATER_THAN)) { 448 if (_maybeEat(TokenKind.GREATER_THAN)) {
338 scopeType = 1; 449 // Scoped unless the tag is explicitly known as an unscoped tag
450 // e.g., <br>.
451 scopeType = TokenKind.unscopedTag(tagToken.kind) ? 2 : 1;
339 } else if (_maybeEat(TokenKind.END_NO_SCOPE_TAG)) { 452 } else if (_maybeEat(TokenKind.END_NO_SCOPE_TAG)) {
340 scopeType = 2; 453 scopeType = 2;
341 } 454 }
342 if (scopeType > 0) { 455 if (scopeType > 0) {
343 var elem = new TemplateElement.attributes(tagToken.kind, 456 var elem = new TemplateElement.attributes(tagToken.kind,
344 attrs.getValues(), varName, _makeSpan(start)); 457 attrs.getValues(), varName, _makeSpan(start));
345 stack.top().add(elem); 458 stack.top().add(elem);
346 459
347 if (scopeType == 1) { 460 if (scopeType == 1) {
348 // Maybe more nested tags/text? 461 // Maybe more nested tags/text?
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
497 610
498 /* Map is used so only last unique attribute name is remembered and to quickly 611 /* Map is used so only last unique attribute name is remembered and to quickly
499 * find the var attribute. 612 * find the var attribute.
500 */ 613 */
501 Map<String, TemplateAttribute> processAttributes() { 614 Map<String, TemplateAttribute> processAttributes() {
502 Map<String, TemplateAttribute> attrs = new Map(); 615 Map<String, TemplateAttribute> attrs = new Map();
503 616
504 int start = _peekToken.start; 617 int start = _peekToken.start;
505 String elemName; 618 String elemName;
506 while (_peekIdentifier() || 619 while (_peekIdentifier() ||
507 (elemName = TokenKind.elementsToName(_peek())) != null) { 620 (elemName = TokenKind.tagNameFromTokenId(_peek())) != null) {
508 var attrName; 621 var attrName;
509 if (elemName == null) { 622 if (elemName == null) {
510 attrName = identifier(); 623 attrName = identifier();
511 } else { 624 } else {
512 attrName = new Identifier(elemName, _makeSpan(start)); 625 attrName = new Identifier(elemName, _makeSpan(start));
513 _next(); 626 _next();
514 } 627 }
515 628
516 var attrValue; 629 var attrValue;
517 630
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
559 _next(false); 672 _next(false);
560 } else if (_peek() != TokenKind.RBRACE) { 673 } else if (_peek() != TokenKind.RBRACE) {
561 // Yes, grab the chars after the > 674 // Yes, grab the chars after the >
562 stringValue.add(_previousToken.source.text.substring( 675 stringValue.add(_previousToken.source.text.substring(
563 this._previousToken.end, this._peekToken.start)); 676 this._previousToken.end, this._peekToken.start));
564 } 677 }
565 } 678 }
566 679
567 // Gobble up everything until we hit < 680 // Gobble up everything until we hit <
568 while (_peek() != TokenKind.LESS_THAN && 681 while (_peek() != TokenKind.LESS_THAN &&
682 _peek() != TokenKind.START_COMMAND &&
683 _peek() != TokenKind.END_COMMAND &&
569 (_peek() != TokenKind.RBRACE || 684 (_peek() != TokenKind.RBRACE ||
570 (_peek() == TokenKind.RBRACE && inExpression)) && 685 (_peek() == TokenKind.RBRACE && inExpression)) &&
571 _peek() != TokenKind.END_OF_FILE) { 686 _peek() != TokenKind.END_OF_FILE) {
572 687
573 // Beginning of expression? 688 // Beginning of expression?
574 if (_peek() == TokenKind.START_EXPRESSION) { 689 if (_peek() == TokenKind.START_EXPRESSION) {
575 if (stringValue.length > 0) { 690 if (stringValue.length > 0) {
576 // We have a real text node create the text node. 691 // We have a real text node create the text node.
577 nodes.add(new TemplateText(stringValue.toString(), _makeSpan(start))); 692 nodes.add(new TemplateText(stringValue.toString(), _makeSpan(start)));
578 stringValue = new StringBuffer(); 693 stringValue = new StringBuffer();
(...skipping 17 matching lines...) Expand all
596 } 711 }
597 712
598 if (stringValue.length > 0) { 713 if (stringValue.length > 0) {
599 nodes.add(new TemplateText(stringValue.toString(), _makeSpan(start))); 714 nodes.add(new TemplateText(stringValue.toString(), _makeSpan(start)));
600 } 715 }
601 716
602 return nodes; 717 return nodes;
603 } 718 }
604 719
605 } 720 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698