Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |