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

Side by Side Diff: utils/template/codegen.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 // 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 class CGBlock { 5 class CGBlock {
6 int _blockType; // Code type of this block 6 int _blockType; // Code type of this block
7 int _indent; // Number of spaces to prefix for each statement 7 int _indent; // Number of spaces to prefix for each statement
8 bool _inEach; // This block or any currently active blocks is a 8 bool _inEach; // This block or any currently active blocks is a
9 // #each. If so then any element marked with a 9 // #each. If so then any element marked with a
10 // var attribute is repeated therefore the var 10 // var attribute is repeated therefore the var
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 CGStatement stmt = new CGStatement(elem, _indent, parentName, varName, 44 CGStatement stmt = new CGStatement(elem, _indent, parentName, varName,
45 exact, _inEach); 45 exact, _inEach);
46 _stmts.add(stmt); 46 _stmts.add(stmt);
47 47
48 return stmt; 48 return stmt;
49 } 49 }
50 50
51 void pop() { 51 void pop() {
52 _stmts.removeLast(); 52 _stmts.removeLast();
53 } 53 }
54 54
Jacob 2012/04/05 18:06:01 unreleated to this change but perhaps emit final i
55 void add(String value) { 55 void add(String value) {
56 if (_stmts.last() != null) { 56 if (_stmts.last() != null) {
57 _stmts.last().add(value); 57 _stmts.last().add(value);
58 } 58 }
59 } 59 }
60 60
61 CGStatement get last() => _stmts.last(); 61 CGStatement get last() => _stmts.length > 0 ? _stmts.last() : null;
62 62
63 /** 63 /**
64 * Returns mixed list of elements marked with the var attribute. If the 64 * Returns mixed list of elements marked with the var attribute. If the
65 * element is inside of a #each the name exposed is: 65 * element is inside of a #each the name exposed is:
66 * 66 *
67 * List varName; 67 * List varName;
68 * 68 *
69 * otherwise it's: 69 * otherwise it's:
70 * 70 *
71 * var varName; 71 * var varName;
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 return ""; 161 return "";
162 } 162 }
163 163
164 void add(String value) { 164 void add(String value) {
165 _buff.add(value); 165 _buff.add(value);
166 } 166 }
167 167
168 bool get isClosed() => _closed; 168 bool get isClosed() => _closed;
169 169
170 void close() { 170 void close() {
171 if (_elem is TemplateElement) { 171 if (_elem is TemplateElement && _elem.scoped) {
172 add("</${_elem.tagName}>"); 172 add("</${_elem.tagName}>");
173 } 173 }
174 _closed = true; 174 _closed = true;
175 } 175 }
176 176
177 String emitDartStatement() { 177 String emitDartStatement() {
178 StringBuffer statement = new StringBuffer(); 178 StringBuffer statement = new StringBuffer();
179 179
180 String spaces = Codegen.spaces(_indent); 180 String spaces = Codegen.spaces(_indent);
181 181
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 List<String> fileParts = filename.split('.'); 265 List<String> fileParts = filename.split('.');
266 assert(fileParts.length == 2); 266 assert(fileParts.length == 2);
267 filename = fileParts[0]; 267 filename = fileParts[0];
268 268
269 StringBuffer buff = new StringBuffer(); 269 StringBuffer buff = new StringBuffer();
270 int injectId = 0; // Inject function id 270 int injectId = 0; // Inject function id
271 271
272 buff.add("// Generated Dart class from HTML template.\n"); 272 buff.add("// Generated Dart class from HTML template.\n");
273 buff.add("// DO NOT EDIT.\n\n"); 273 buff.add("// DO NOT EDIT.\n\n");
274 274
275 buff.add("String safeHTML(String html) {\n");
276 buff.add(" // TODO(terry): Escaping for XSS vulnerabilities TBD.\n");
277 buff.add(" return html;\n");
278 buff.add("}\n\n");
279
280 String addStylesheetFuncName = "add_${filename}_templatesStyles"; 275 String addStylesheetFuncName = "add_${filename}_templatesStyles";
281 276
282 for (final template in templates) { 277 for (final template in templates) {
283 // Emit the template class. 278 // Emit the template class.
284 TemplateSignature sig = template.signature; 279 TemplateSignature sig = template.signature;
285 buff.add(_emitClass(sig.name, sig.params, template.content, 280 buff.add(_emitClass(sig.name, sig.params, template.content,
286 addStylesheetFuncName)); 281 addStylesheetFuncName));
287 } 282 }
288 283
289 // TODO(terry): Stylesheet aggregator should not be global needs to be 284 // TODO(terry): Stylesheet aggregator should not be global needs to be
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
379 anyParams = true; 374 anyParams = true;
380 } 375 }
381 if (anyParams) buff.add("\n"); 376 if (anyParams) buff.add("\n");
382 377
383 ElemCG ecg = new ElemCG(); 378 ElemCG ecg = new ElemCG();
384 379
385 if (!ecg.pushBlock()) { 380 if (!ecg.pushBlock()) {
386 world.error("Error at ${content}"); 381 world.error("Error at ${content}");
387 } 382 }
388 383
389 var root = content.html.children[0]; 384 var root = content.html.children.length > 0 ? content.html.children[0] :
385 content.html;
390 bool firstTime = true; 386 bool firstTime = true;
391 for (var child in root.children) { 387 for (var child in root.children) {
392 if (child is TemplateText) { 388 if (child is TemplateText) {
393 if (!firstTime) { 389 if (!firstTime) {
394 ecg.closeStatement(); 390 ecg.closeStatement();
395 } 391 }
396 CGStatement stmt = ecg.pushStatement(child, "_fragment"); 392
393 String textNodeValue = child.value.trim();
394 if (textNodeValue.length > 0) {
395 CGStatement stmt = ecg.pushStatement(child, "_fragment");
396 }
397 } 397 }
398 ecg.emitConstructHtml(child, "", "_fragment"); 398 ecg.emitConstructHtml(child, "", "_fragment");
399 firstTime = false; 399 firstTime = false;
400 } 400 }
401 401
402 // Create all element names marked with var. 402 // Create all element names marked with var.
403 String decls = ecg.globalDeclarations; 403 String decls = ecg.globalDeclarations;
404 if (decls.length > 0) { 404 if (decls.length > 0) {
405 buff.add("\n // Elements bound to a variable:\n"); 405 buff.add("\n // Elements bound to a variable:\n");
406 buff.add("${decls}\n"); 406 buff.add("${decls}\n");
(...skipping 19 matching lines...) Expand all
426 426
427 buff.add(" // Insure stylesheet for template exist in the document.\n"); 427 buff.add(" // Insure stylesheet for template exist in the document.\n");
428 buff.add(" ${addStylesheetFuncName}();\n\n"); 428 buff.add(" ${addStylesheetFuncName}();\n\n");
429 429
430 buff.add(" _fragment = new DocumentFragment();\n"); 430 buff.add(" _fragment = new DocumentFragment();\n");
431 431
432 buff.add(ecg.codeBody); // HTML for constructor to build. 432 buff.add(ecg.codeBody); // HTML for constructor to build.
433 433
434 buff.add(" }\n\n"); // End constructor 434 buff.add(" }\n\n"); // End constructor
435 435
436 buff.add(emitGetters(content.getters));
437
436 buff.add(" Element get root() => _fragment;\n"); 438 buff.add(" Element get root() => _fragment;\n");
437 439
438 // Emit all CSS class selectors: 440 // Emit all CSS class selectors:
439 buff.add(_emitCSSSelectors(content.css)); 441 buff.add(_emitCSSSelectors(content.css));
440 442
441 // Emit the injection functions. 443 // Emit the injection functions.
442 buff.add("\n // Injection functions:"); 444 buff.add("\n // Injection functions:");
443 for (final expr in ecg.expressions) { 445 for (final expr in ecg.expressions) {
444 buff.add("${expr}"); 446 buff.add("${expr}");
445 } 447 }
(...skipping 14 matching lines...) Expand all
460 if (content.css != null) { 462 if (content.css != null) {
461 buff.add("\'\'\'\n ${content.css.toString()}\n"); 463 buff.add("\'\'\'\n ${content.css.toString()}\n");
462 buff.add(" \'\'\';\n\n"); 464 buff.add(" \'\'\';\n\n");
463 465
464 // TODO(terry): Emit all known selectors for this template. 466 // TODO(terry): Emit all known selectors for this template.
465 buff.add(" // Stylesheet class selectors:\n"); 467 buff.add(" // Stylesheet class selectors:\n");
466 } else { 468 } else {
467 buff.add("\"\";\n"); 469 buff.add("\"\";\n");
468 } 470 }
469 471
472 buff.add(" String safeHTML(String html) {\n");
Jacob 2012/04/05 18:06:01 use multiline strings to make this cleaner
473 buff.add(" // TODO(terry): Escaping for XSS vulnerabilities TBD.\n");
474 buff.add(" return html;\n");
475 buff.add(" }\n");
476
470 buff.add("}\n"); // End class 477 buff.add("}\n"); // End class
471 478
472 return buff.toString(); 479 return buff.toString();
473 } 480 }
481
482 // TODO(terry): Need to generate function to inject any TemplateExpressions
483 // to call SafeHTML wrapper.
484 static String emitGetters(List<TemplateGetter> getters) {
485 StringBuffer buff = new StringBuffer();
486 for (final TemplateGetter getter in getters) {
487 buff.add(' String ${getter.getterSignatureAsString()} {\n');
488 buff.add(' return \'\'\'');
489 var docFrag = getter.docFrag.children[0];
490 for (final child in docFrag.children) {
491 buff.add(child.toString().trim());
492 }
493 buff.add('\'\'\';\n');
494 buff.add(' }\n\n');
495 }
496
497 return buff.toString();
498 }
474 } 499 }
475 500
476 class ElemCG { 501 class ElemCG {
477 // List of identifiers and quoted strings (single and double quoted). 502 // List of identifiers and quoted strings (single and double quoted).
478 var identRe = const RegExp( 503 var identRe = const RegExp(
479 "\s*('\"\\'\\\"[^'\"\\'\\\"]+'\"\\'\\\"|[_A-Za-z][_A-Za-z0-9]*)"); 504 "\s*('\"\\'\\\"[^'\"\\'\\\"]+'\"\\'\\\"|[_A-Za-z][_A-Za-z0-9]*)");
480 505
481 List<CGBlock> _cgBlocks; 506 List<CGBlock> _cgBlocks;
482 StringBuffer _globalDecls; // Global var declarations for all blocks. 507 StringBuffer _globalDecls; // Global var declarations for all blocks.
483 StringBuffer _globalInits; // Global List var initializtion for all 508 StringBuffer _globalInits; // Global List var initializtion for all
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
593 } 618 }
594 619
595 CGStatement pushStatement(var elem, var parentName) { 620 CGStatement pushStatement(var elem, var parentName) {
596 return lastBlock.push(elem, parentName, false); 621 return lastBlock.push(elem, parentName, false);
597 } 622 }
598 623
599 CGStatement pushExactStatement(var elem, var parentName) { 624 CGStatement pushExactStatement(var elem, var parentName) {
600 return lastBlock.push(elem, parentName, true); 625 return lastBlock.push(elem, parentName, true);
601 } 626 }
602 627
603 bool get isClosedStatement() => lastBlock.last.isClosed; 628 bool get isClosedStatement() {
629 return (lastBlock != null && lastBlock.last != null) ?
630 lastBlock.last.isClosed : false;
631 }
604 632
605 void closeStatement() { 633 void closeStatement() {
606 if (lastBlock != null && lastBlock.last != null && 634 if (lastBlock != null && lastBlock.last != null &&
607 !lastBlock.last.isClosed) { 635 !lastBlock.last.isClosed) {
608 lastBlock.last.close(); 636 lastBlock.last.close();
609 } 637 }
610 } 638 }
611 639
612 String get lastVariableName() { 640 String get lastVariableName() {
613 if (lastBlock != null && lastBlock.last != null) { 641 if (lastBlock != null && lastBlock.last != null) {
614 return lastBlock.last.variableName; 642 return lastBlock.last.variableName;
615 } 643 }
616 } 644 }
617 645
646 String get lastParentName() {
647 if (lastBlock != null && lastBlock.last != null) {
648 return lastBlock.last.parentName;
649 }
650 }
651
618 CGBlock get lastBlock() => _cgBlocks.length > 0 ? _cgBlocks.last() : null; 652 CGBlock get lastBlock() => _cgBlocks.length > 0 ? _cgBlocks.last() : null;
619 653
620 void add(String str) { 654 void add(String str) {
621 _cgBlocks.last().add(str); 655 _cgBlocks.last().add(str);
622 } 656 }
623 657
624 String get globalDeclarations() { 658 String get globalDeclarations() {
625 assert(_cgBlocks.length == 1); // Only constructor body should be left. 659 assert(_cgBlocks.length == 1); // Only constructor body should be left.
626 _globalDecls.add(lastBlock.globalDeclarations); 660 _globalDecls.add(lastBlock.globalDeclarations);
627 return _globalDecls.toString(); 661 return _globalDecls.toString();
(...skipping 19 matching lines...) Expand all
647 [String scopeName = "", 681 [String scopeName = "",
648 var parentVarOrIdx = 0, 682 var parentVarOrIdx = 0,
649 bool immediateNestedEach = false]) { 683 bool immediateNestedEach = false]) {
650 if (elem is TemplateElement) { 684 if (elem is TemplateElement) {
651 if (!elem.isFragment) { 685 if (!elem.isFragment) {
652 add("<${elem.tagName}${elem.attributesToString()}>"); 686 add("<${elem.tagName}${elem.attributesToString()}>");
653 } 687 }
654 String prevParent = lastVariableName; 688 String prevParent = lastVariableName;
655 for (var childElem in elem.children) { 689 for (var childElem in elem.children) {
656 if (childElem is TemplateElement) { 690 if (childElem is TemplateElement) {
691 closeStatement();
657 if (childElem.hasVar) { 692 if (childElem.hasVar) {
658 closeStatement();
659 emitConstructHtml(childElem, scopeName, prevParent, 693 emitConstructHtml(childElem, scopeName, prevParent,
660 childElem.varName); 694 childElem.varName);
661 closeStatement();
662 } else { 695 } else {
663 closeStatement();
664 emitConstructHtml(childElem, scopeName, prevParent); 696 emitConstructHtml(childElem, scopeName, prevParent);
665 closeStatement();
666 } 697 }
698 closeStatement();
667 } else { 699 } else {
668 emitElement(childElem, scopeName, parentVarOrIdx); 700 emitElement(childElem, scopeName, parentVarOrIdx);
669 } 701 }
670 } 702 }
671 703
672 // Close this tag. 704 // Close this tag.
673 closeStatement(); 705 closeStatement();
674 } else if (elem is TemplateText) { 706 } else if (elem is TemplateText) {
675 add("${elem.value}"); 707 String outputValue = elem.value.trim();
708 if (outputValue.length > 0) {
709 bool emitTextNode = false;
710 if (isClosedStatement) {
711 String prevParent = lastParentName;
712 CGStatement stmt = pushStatement(elem, prevParent);
713 emitTextNode = true;
714 }
715
716 // TODO(terry): Need to interpolate following:
717 // {sp} → space
718 // {nil} → empty string
719 // {\r} → carriage return
720 // {\n} → new line (line feed)
721 // {\t} → tab
722 // {lb} → left brace
723 // {rb} → right brace
724
725 add("${outputValue}"); // remove leading/trailing whitespace.
726
727 if (emitTextNode) {
728 closeStatement();
729 }
730 }
676 } else if (elem is TemplateExpression) { 731 } else if (elem is TemplateExpression) {
677 emitExpressions(elem, scopeName); 732 emitExpressions(elem, scopeName);
678 } else if (elem is TemplateEachCommand) { 733 } else if (elem is TemplateEachCommand) {
679 // Signal to caller new block coming in, returns "each_" prefix 734 // Signal to caller new block coming in, returns "each_" prefix
680 emitEach(elem, "List", elem.listName.name, "parent", immediateNestedEach, 735 emitEach(elem, "List", elem.listName.name, "parent", immediateNestedEach,
681 elem.hasLoopItem ? elem.loopItem.name : null); 736 elem.hasLoopItem ? elem.loopItem.name : null);
682 } else if (elem is TemplateWithCommand) { 737 } else if (elem is TemplateWithCommand) {
683 // Signal to caller new block coming in, returns "each_" prefix 738 // Signal to caller new block coming in, returns "each_" prefix
684 emitWith(elem, "var", elem.objectName.name, "parent", 739 emitWith(elem, "var", elem.objectName.name, "parent",
685 elem.hasBlockItem ? elem.blockItem.name : null); 740 elem.hasBlockItem ? elem.blockItem.name : null);
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after
937 for (String name in names) { 992 for (String name in names) {
938 buff.add(" var ${name} = _scopes[\"${name}\"];\n"); 993 buff.add(" var ${name} = _scopes[\"${name}\"];\n");
939 } 994 }
940 buff.add("\n"); 995 buff.add("\n");
941 } 996 }
942 997
943 return buff.toString(); 998 return buff.toString();
944 } 999 }
945 1000
946 } 1001 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698