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

Side by Side Diff: lib/compiler/implementation/js/printer.dart

Issue 11146013: Fix JS minifier to lift var declarations within functions. Still disabled. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 2 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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 Printer implements NodeVisitor { 5 class Printer implements NodeVisitor {
6 final bool shouldCompressOutput; 6 final bool shouldCompressOutput;
7 leg.Compiler compiler; 7 leg.Compiler compiler;
8 leg.CodeBuffer outBuffer; 8 leg.CodeBuffer outBuffer;
9 int indentLevel = 0; 9 int indentLevel = 0;
10 bool inForInit = false; 10 bool inForInit = false;
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 blockOutWithoutBraces(node.body); 344 blockOutWithoutBraces(node.body);
345 indentLevel--; 345 indentLevel--;
346 } 346 }
347 } 347 }
348 348
349 visitLabeledStatement(LabeledStatement node) { 349 visitLabeledStatement(LabeledStatement node) {
350 outIndent("${node.label}:"); 350 outIndent("${node.label}:");
351 blockBody(node.body, needsSeparation: false, needsNewline: true); 351 blockBody(node.body, needsSeparation: false, needsNewline: true);
352 } 352 }
353 353
354 void functionOut(Fun fun, Node name) { 354 void functionOut(Fun fun, Node name, VarCollector vars) {
355 out("function"); 355 out("function");
356 if (name != null) { 356 if (name != null) {
357 out(" "); 357 out(" ");
358 // Name must be a [Decl]. Therefore only test for primary expressions. 358 // Name must be a [Decl]. Therefore only test for primary expressions.
359 visitNestedExpression(name, PRIMARY, 359 visitNestedExpression(name, PRIMARY,
360 newInForInit: false, newAtStatementBegin: false); 360 newInForInit: false, newAtStatementBegin: false);
361 } 361 }
362 namer.enterScope(); 362 namer.enterScope(vars);
363 out("("); 363 out("(");
364 if (fun.params != null) { 364 if (fun.params != null) {
365 visitCommaSeparated(fun.params, PRIMARY, 365 visitCommaSeparated(fun.params, PRIMARY,
366 newInForInit: false, newAtStatementBegin: false); 366 newInForInit: false, newAtStatementBegin: false);
367 } 367 }
368 out(")"); 368 out(")");
369 blockBody(fun.body, needsSeparation: false, needsNewline: false); 369 blockBody(fun.body, needsSeparation: false, needsNewline: false);
370 namer.leaveScope(); 370 namer.leaveScope();
371 } 371 }
372 372
373 visitFunctionDeclaration(FunctionDeclaration declaration) { 373 visitFunctionDeclaration(FunctionDeclaration declaration) {
374 VarCollector vars = new VarCollector();
375 vars.visitFunctionDeclaration(declaration);
374 indent(); 376 indent();
375 functionOut(declaration.function, declaration.name); 377 functionOut(declaration.function, declaration.name, vars);
376 lineOut(); 378 lineOut();
377 } 379 }
378 380
379 visitNestedExpression(Expression node, int requiredPrecedence, 381 visitNestedExpression(Expression node, int requiredPrecedence,
380 [bool newInForInit, bool newAtStatementBegin]) { 382 [bool newInForInit, bool newAtStatementBegin]) {
381 bool needsParentheses = 383 bool needsParentheses =
382 // a - (b + c). 384 // a - (b + c).
383 (requiredPrecedence != EXPRESSION && 385 (requiredPrecedence != EXPRESSION &&
384 node.precedenceLevel < requiredPrecedence) || 386 node.precedenceLevel < requiredPrecedence) ||
385 // for (a = (x in o); ... ; ... ) { ... } 387 // for (a = (x in o); ... ; ... ) { ... }
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
606 608
607 visitVariableUse(VariableUse ref) { 609 visitVariableUse(VariableUse ref) {
608 out(namer.getName(ref.name)); 610 out(namer.getName(ref.name));
609 } 611 }
610 612
611 visitThis(This node) { 613 visitThis(This node) {
612 out("this"); 614 out("this");
613 } 615 }
614 616
615 visitVariableDeclaration(VariableDeclaration decl) { 617 visitVariableDeclaration(VariableDeclaration decl) {
616 out(namer.declareName(decl.name)); 618 out(namer.getName(decl.name));
617 } 619 }
618 620
619 visitParameter(Parameter param) { 621 visitParameter(Parameter param) {
620 out(namer.declareName(param.name)); 622 out(namer.getName(param.name));
621 } 623 }
622 624
623 bool isDigit(int charCode) { 625 bool isDigit(int charCode) {
624 return charCodes.$0 <= charCode && charCode <= charCodes.$9; 626 return charCodes.$0 <= charCode && charCode <= charCodes.$9;
625 } 627 }
626 628
627 bool isValidJavaScriptId(String field) { 629 bool isValidJavaScriptId(String field) {
628 if (field.length < 3) return false; 630 if (field.length < 3) return false;
629 // Ignore the leading and trailing string-delimiter. 631 // Ignore the leading and trailing string-delimiter.
630 for (int i = 1; i < field.length - 1; i++) { 632 for (int i = 1; i < field.length - 1; i++) {
(...skipping 27 matching lines...) Expand all
658 return; 660 return;
659 } 661 }
660 } 662 }
661 out("["); 663 out("[");
662 visitNestedExpression(selector, EXPRESSION, 664 visitNestedExpression(selector, EXPRESSION,
663 newInForInit: false, newAtStatementBegin: false); 665 newInForInit: false, newAtStatementBegin: false);
664 out("]"); 666 out("]");
665 } 667 }
666 668
667 visitNamedFunction(NamedFunction namedFunction) { 669 visitNamedFunction(NamedFunction namedFunction) {
668 functionOut(namedFunction.function, namedFunction.name); 670 VarCollector vars = new VarCollector();
671 vars.visitNamedFunction(namedFunction);
672 functionOut(namedFunction.function, namedFunction.name, vars);
669 } 673 }
670 674
671 visitFun(Fun fun) { 675 visitFun(Fun fun) {
672 functionOut(fun, null); 676 VarCollector vars = new VarCollector();
677 vars.visitFun(fun);
678 functionOut(fun, null, vars);
673 } 679 }
674 680
675 visitLiteralBool(LiteralBool node) { 681 visitLiteralBool(LiteralBool node) {
676 out(node.value ? "true" : "false"); 682 out(node.value ? "true" : "false");
677 } 683 }
678 684
679 visitLiteralString(LiteralString node) { 685 visitLiteralString(LiteralString node) {
680 out(node.value); 686 out(node.value);
681 } 687 }
682 688
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
771 visit(inputs[i]); 777 visit(inputs[i]);
772 out(parts[i + 1]); 778 out(parts[i + 1]);
773 } 779 }
774 } 780 }
775 781
776 visitLiteralStatement(LiteralStatement node) { 782 visitLiteralStatement(LiteralStatement node) {
777 outLn(node.code); 783 outLn(node.code);
778 } 784 }
779 } 785 }
780 786
787
788 // Collects all the var declarations in the function. We need to do this in a
789 // separate pass because JS vars are lifted to the top of the function.
790 class VarCollector extends BaseVisitor {
791 bool nested;
792 final Set<String> vars;
793 final List<String> ordered_vars;
794
795 VarCollector() : nested = false, vars = new Set<String>(), ordered_vars = [];
796
797 void forEach(void fn(String)) => ordered_vars.forEach(fn);
798
799 void functionOut(Fun fun) {
floitsch 2012/10/15 11:17:18 "out" doesn't seem to fit. Maybe "collectVarsInFun
800 if (!nested) {
801 nested = true;
802 if (fun.params != null) {
803 for (int i = 0; i < fun.params.length; i++) {
804 add(fun.params[i].name);
805 }
806 }
807 visitBlock(fun.body);
808 nested = false;
809 }
810 }
811
812 void add(String name) {
813 if (!vars.contains(name)) {
814 vars.add(name);
815 ordered_vars.add(name);
816 }
817 }
818
819 void visitFunctionDeclaration(FunctionDeclaration declaration) {
820 functionOut(declaration.function);
floitsch 2012/10/15 11:17:18 Add comment that we are skipping the function-decl
821 }
822
823 void visitNamedFunction(NamedFunction namedFunction) {
floitsch 2012/10/15 11:17:18 Add comment that we are skipping the named-functio
824 functionOut(namedFunction.function);
825 }
826
827 void visitFun(Fun fun) {
828 functionOut(fun);
829 }
830
831 void visitVariableDeclaration(VariableDeclaration decl) {
832 add(decl.name);
833 }
834 }
835
836
781 /** 837 /**
782 * Returns true, if the given node must be wrapped into braces when used 838 * Returns true, if the given node must be wrapped into braces when used
783 * as then-statement in an [If] that has an else branch. 839 * as then-statement in an [If] that has an else branch.
784 */ 840 */
785 class DanglingElseVisitor extends BaseVisitor<bool> { 841 class DanglingElseVisitor extends BaseVisitor<bool> {
786 leg.Compiler compiler; 842 leg.Compiler compiler;
787 843
788 DanglingElseVisitor(this.compiler); 844 DanglingElseVisitor(this.compiler);
789 845
790 bool visitProgram(Program node) => false; 846 bool visitProgram(Program node) => false;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
832 leg.Compiler compiler) { 888 leg.Compiler compiler) {
833 Printer printer = new Printer(compiler); 889 Printer printer = new Printer(compiler);
834 printer.visit(node); 890 printer.visit(node);
835 return printer.outBuffer; 891 return printer.outBuffer;
836 } 892 }
837 893
838 894
839 abstract class Namer { 895 abstract class Namer {
840 String getName(String oldName); 896 String getName(String oldName);
841 String declareName(String oldName); 897 String declareName(String oldName);
842 void enterScope(); 898 void enterScope(VarCollector vars);
843 void leaveScope(); 899 void leaveScope();
844 } 900 }
845 901
846 902
847 class IdentityNamer implements Namer { 903 class IdentityNamer implements Namer {
848 String getName(String oldName) => oldName; 904 String getName(String oldName) => oldName;
849 String declareName(String oldName) => oldName; 905 String declareName(String oldName) => oldName;
850 void enterScope() {} 906 void enterScope(VarCollector vars) {}
851 void leaveScope() {} 907 void leaveScope() {}
852 } 908 }
853 909
854 910
855 class MinifyRenamer implements Namer { 911 class MinifyRenamer implements Namer {
856 final List<Map<String, String>> maps = []; 912 final List<Map<String, String>> maps = [];
857 final List<int> nameNumberStack = []; 913 final List<int> nameNumberStack = [];
858 int nameNumber = 0; 914 int nameNumber = 0;
859 915
860 MinifyRenamer(); 916 MinifyRenamer();
861 917
862 void enterScope() { 918 void enterScope(VarCollector vars) {
863 maps.add(new Map<String, String>()); 919 maps.add(new Map<String, String>());
864 nameNumberStack.add(nameNumber); 920 nameNumberStack.add(nameNumber);
921 vars.forEach(declareName);
865 } 922 }
866 923
867 void leaveScope() { 924 void leaveScope() {
868 maps.removeLast(); 925 maps.removeLast();
869 nameNumber = nameNumberStack.removeLast(); 926 nameNumber = nameNumberStack.removeLast();
870 } 927 }
871 928
872 String getName(String oldName) { 929 String getName(String oldName) {
873 for (int i = maps.length - 1; i >= 0; i--) { 930 for (int i = maps.length - 1; i >= 0; i--) {
874 var map = maps[i]; 931 var map = maps[i];
875 var replacement = map[oldName]; 932 var replacement = map[oldName];
876 if (replacement != null) return replacement; 933 if (replacement != null) return replacement;
877 } 934 }
878 return oldName; 935 return oldName;
879 } 936 }
880 937
881 static int nthLetter(int n) { 938 static int nthLetter(int n) {
882 return (n < 26) ? charCodes.$a + n : charCodes.$A + n - 26; 939 return (n < 26) ? charCodes.$a + n : charCodes.$A + n - 26;
883 } 940 }
884 941
885 String declareName(String oldName) { 942 String declareName(String oldName) {
886 const LETTERS = 52; 943 const LETTERS = 52;
887 const DIGITS = 10; 944 const DIGITS = 10;
888 if (maps.isEmpty()) return oldName; 945 if (maps.isEmpty()) return oldName;
946
889 String newName; 947 String newName;
890 int n = nameNumber; 948 int n = nameNumber;
891 if (n < LETTERS) { 949 if (n < LETTERS) {
892 // Start naming variables a, b, c, ..., z, A, B, C, ..., Z. 950 // Start naming variables a, b, c, ..., z, A, B, C, ..., Z.
893 newName = new String.fromCharCodes([nthLetter(n)]); 951 newName = new String.fromCharCodes([nthLetter(n)]);
894 } else { 952 } else {
895 // Then name variables a0, a1, a2, ..., a9, b0, b1, ..., Z9, aa0, aa1, ... 953 // Then name variables a0, a1, a2, ..., a9, b0, b1, ..., Z9, aa0, aa1, ...
896 // For all functions with fewer than 500 locals this is just as compact 954 // For all functions with fewer than 500 locals this is just as compact
897 // as using aa, ab, etc. but avoids clashes with keywords. 955 // as using aa, ab, etc. but avoids clashes with keywords.
898 n -= LETTERS; 956 n -= LETTERS;
(...skipping 15 matching lines...) Expand all
914 } 972 }
915 codes.add(charCodes.$0 + digit); 973 codes.add(charCodes.$0 + digit);
916 newName = new String.fromCharCodes(codes); 974 newName = new String.fromCharCodes(codes);
917 } 975 }
918 assert(const RegExp(r'[a-zA-Z][a-zA-Z0-9]*').hasMatch(newName)); 976 assert(const RegExp(r'[a-zA-Z][a-zA-Z0-9]*').hasMatch(newName));
919 nameNumber++; 977 nameNumber++;
920 maps.last()[oldName] = newName; 978 maps.last()[oldName] = newName;
921 return newName; 979 return newName;
922 } 980 }
923 } 981 }
OLDNEW
« no previous file with comments | « no previous file | tests/compiler/dart2js/class_codegen_test.dart » ('j') | tests/compiler/dart2js/class_codegen_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698