| 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 part of js; | 5 part of js; |
| 6 | 6 |
| 7 class Printer implements NodeVisitor { | 7 class Printer implements NodeVisitor { |
| 8 final bool shouldCompressOutput; | 8 final bool shouldCompressOutput; |
| 9 leg.Compiler compiler; | 9 leg.Compiler compiler; |
| 10 leg.CodeBuffer outBuffer; | 10 leg.CodeBuffer outBuffer; |
| 11 int indentLevel = 0; | 11 int indentLevel = 0; |
| 12 bool inForInit = false; | 12 bool inForInit = false; |
| 13 bool atStatementBegin = false; | 13 bool atStatementBegin = false; |
| 14 final DanglingElseVisitor danglingElseVisitor; | 14 final DanglingElseVisitor danglingElseVisitor; |
| 15 final LocalNamer localNamer; | 15 final Namer namer; |
| 16 | 16 |
| 17 Printer(leg.Compiler compiler) | 17 Printer(leg.Compiler compiler) |
| 18 : shouldCompressOutput = compiler.enableMinification, | 18 : shouldCompressOutput = compiler.enableMinification, |
| 19 this.compiler = compiler, | 19 this.compiler = compiler, |
| 20 outBuffer = new leg.CodeBuffer(), | 20 outBuffer = new leg.CodeBuffer(), |
| 21 danglingElseVisitor = new DanglingElseVisitor(compiler), | 21 danglingElseVisitor = new DanglingElseVisitor(compiler), |
| 22 localNamer = determineRenamer(compiler.enableMinification); | 22 namer = determineRenamer(compiler.enableMinification); |
| 23 | 23 |
| 24 static LocalNamer determineRenamer(bool shouldCompressOutput) { | 24 static Namer determineRenamer(bool shouldCompressOutput) { |
| 25 // TODO(erikcorry): Re-enable the MinifyRenamer after M1. | 25 // TODO(erikcorry): Re-enable the MinifyRenamer after M1. |
| 26 return new IdentityNamer(); | 26 return new IdentityNamer(); |
| 27 } | 27 } |
| 28 | 28 |
| 29 void spaceOut() { | 29 void spaceOut() { |
| 30 if (!shouldCompressOutput) out(" "); | 30 if (!shouldCompressOutput) out(" "); |
| 31 } | 31 } |
| 32 void lineOut() { | 32 void lineOut() { |
| 33 if (!shouldCompressOutput) out("\n"); | 33 if (!shouldCompressOutput) out("\n"); |
| 34 } | 34 } |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 355 } | 355 } |
| 356 | 356 |
| 357 void functionOut(Fun fun, Node name, VarCollector vars) { | 357 void functionOut(Fun fun, Node name, VarCollector vars) { |
| 358 out("function"); | 358 out("function"); |
| 359 if (name != null) { | 359 if (name != null) { |
| 360 out(" "); | 360 out(" "); |
| 361 // Name must be a [Decl]. Therefore only test for primary expressions. | 361 // Name must be a [Decl]. Therefore only test for primary expressions. |
| 362 visitNestedExpression(name, PRIMARY, | 362 visitNestedExpression(name, PRIMARY, |
| 363 newInForInit: false, newAtStatementBegin: false); | 363 newInForInit: false, newAtStatementBegin: false); |
| 364 } | 364 } |
| 365 localNamer.enterScope(vars); | 365 namer.enterScope(vars); |
| 366 out("("); | 366 out("("); |
| 367 if (fun.params != null) { | 367 if (fun.params != null) { |
| 368 visitCommaSeparated(fun.params, PRIMARY, | 368 visitCommaSeparated(fun.params, PRIMARY, |
| 369 newInForInit: false, newAtStatementBegin: false); | 369 newInForInit: false, newAtStatementBegin: false); |
| 370 } | 370 } |
| 371 out(")"); | 371 out(")"); |
| 372 blockBody(fun.body, needsSeparation: false, needsNewline: false); | 372 blockBody(fun.body, needsSeparation: false, needsNewline: false); |
| 373 localNamer.leaveScope(); | 373 namer.leaveScope(); |
| 374 } | 374 } |
| 375 | 375 |
| 376 visitFunctionDeclaration(FunctionDeclaration declaration) { | 376 visitFunctionDeclaration(FunctionDeclaration declaration) { |
| 377 VarCollector vars = new VarCollector(); | 377 VarCollector vars = new VarCollector(); |
| 378 vars.visitFunctionDeclaration(declaration); | 378 vars.visitFunctionDeclaration(declaration); |
| 379 indent(); | 379 indent(); |
| 380 functionOut(declaration.function, declaration.name, vars); | 380 functionOut(declaration.function, declaration.name, vars); |
| 381 lineOut(); | 381 lineOut(); |
| 382 } | 382 } |
| 383 | 383 |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 603 } | 603 } |
| 604 | 604 |
| 605 visitPostfix(Postfix postfix) { | 605 visitPostfix(Postfix postfix) { |
| 606 visitNestedExpression(postfix.argument, LEFT_HAND_SIDE, | 606 visitNestedExpression(postfix.argument, LEFT_HAND_SIDE, |
| 607 newInForInit: inForInit, | 607 newInForInit: inForInit, |
| 608 newAtStatementBegin: atStatementBegin); | 608 newAtStatementBegin: atStatementBegin); |
| 609 out(postfix.op); | 609 out(postfix.op); |
| 610 } | 610 } |
| 611 | 611 |
| 612 visitVariableUse(VariableUse ref) { | 612 visitVariableUse(VariableUse ref) { |
| 613 out(localNamer.getName(ref.name)); | 613 out(namer.getName(ref.name)); |
| 614 } | 614 } |
| 615 | 615 |
| 616 visitThis(This node) { | 616 visitThis(This node) { |
| 617 out("this"); | 617 out("this"); |
| 618 } | 618 } |
| 619 | 619 |
| 620 visitVariableDeclaration(VariableDeclaration decl) { | 620 visitVariableDeclaration(VariableDeclaration decl) { |
| 621 out(localNamer.getName(decl.name)); | 621 out(namer.getName(decl.name)); |
| 622 } | 622 } |
| 623 | 623 |
| 624 visitParameter(Parameter param) { | 624 visitParameter(Parameter param) { |
| 625 out(localNamer.getName(param.name)); | 625 out(namer.getName(param.name)); |
| 626 } | 626 } |
| 627 | 627 |
| 628 bool isDigit(int charCode) { | 628 bool isDigit(int charCode) { |
| 629 return charCodes.$0 <= charCode && charCode <= charCodes.$9; | 629 return charCodes.$0 <= charCode && charCode <= charCodes.$9; |
| 630 } | 630 } |
| 631 | 631 |
| 632 bool isValidJavaScriptId(String field) { | 632 bool isValidJavaScriptId(String field) { |
| 633 if (field.length < 3) return false; | 633 if (field.length < 3) return false; |
| 634 // Ignore the leading and trailing string-delimiter. | 634 // Ignore the leading and trailing string-delimiter. |
| 635 for (int i = 1; i < field.length - 1; i++) { | 635 for (int i = 1; i < field.length - 1; i++) { |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 890 | 890 |
| 891 | 891 |
| 892 leg.CodeBuffer prettyPrint(Node node, | 892 leg.CodeBuffer prettyPrint(Node node, |
| 893 leg.Compiler compiler) { | 893 leg.Compiler compiler) { |
| 894 Printer printer = new Printer(compiler); | 894 Printer printer = new Printer(compiler); |
| 895 printer.visit(node); | 895 printer.visit(node); |
| 896 return printer.outBuffer; | 896 return printer.outBuffer; |
| 897 } | 897 } |
| 898 | 898 |
| 899 | 899 |
| 900 abstract class LocalNamer { | 900 abstract class Namer { |
| 901 String getName(String oldName); | 901 String getName(String oldName); |
| 902 String declareName(String oldName); | 902 String declareName(String oldName); |
| 903 void enterScope(VarCollector vars); | 903 void enterScope(VarCollector vars); |
| 904 void leaveScope(); | 904 void leaveScope(); |
| 905 } | 905 } |
| 906 | 906 |
| 907 | 907 |
| 908 class IdentityNamer implements LocalNamer { | 908 class IdentityNamer implements Namer { |
| 909 String getName(String oldName) => oldName; | 909 String getName(String oldName) => oldName; |
| 910 String declareName(String oldName) => oldName; | 910 String declareName(String oldName) => oldName; |
| 911 void enterScope(VarCollector vars) {} | 911 void enterScope(VarCollector vars) {} |
| 912 void leaveScope() {} | 912 void leaveScope() {} |
| 913 } | 913 } |
| 914 | 914 |
| 915 | 915 |
| 916 class MinifyRenamer implements LocalNamer { | 916 class MinifyRenamer implements Namer { |
| 917 final List<Map<String, String>> maps = []; | 917 final List<Map<String, String>> maps = []; |
| 918 final List<int> nameNumberStack = []; | 918 final List<int> nameNumberStack = []; |
| 919 int nameNumber = 0; | 919 int nameNumber = 0; |
| 920 | 920 |
| 921 MinifyRenamer(); | 921 MinifyRenamer(); |
| 922 | 922 |
| 923 void enterScope(VarCollector vars) { | 923 void enterScope(VarCollector vars) { |
| 924 maps.add(new Map<String, String>()); | 924 maps.add(new Map<String, String>()); |
| 925 nameNumberStack.add(nameNumber); | 925 nameNumberStack.add(nameNumber); |
| 926 vars.forEach(declareName); | 926 vars.forEach(declareName); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 943 static int nthLetter(int n) { | 943 static int nthLetter(int n) { |
| 944 return (n < 26) ? charCodes.$a + n : charCodes.$A + n - 26; | 944 return (n < 26) ? charCodes.$a + n : charCodes.$A + n - 26; |
| 945 } | 945 } |
| 946 | 946 |
| 947 String declareName(String oldName) { | 947 String declareName(String oldName) { |
| 948 const LETTERS = 52; | 948 const LETTERS = 52; |
| 949 const DIGITS = 10; | 949 const DIGITS = 10; |
| 950 if (maps.isEmpty) return oldName; | 950 if (maps.isEmpty) return oldName; |
| 951 | 951 |
| 952 String newName; | 952 String newName; |
| 953 do { | 953 int n = nameNumber; |
| 954 int n = nameNumber; | 954 if (n < LETTERS) { |
| 955 if (n < LETTERS) { | 955 // Start naming variables a, b, c, ..., z, A, B, C, ..., Z. |
| 956 // Start naming variables a, b, c, ..., z, A, B, C, ..., Z. | 956 newName = new String.fromCharCodes([nthLetter(n)]); |
| 957 newName = new String.fromCharCodes([nthLetter(n)]); | 957 } else { |
| 958 } else { | 958 // Then name variables a0, a1, a2, ..., a9, b0, b1, ..., Z9, aa0, aa1, ... |
| 959 // Then name variables a0, a1, ..., a9, b0, b1, ..., Z9, aa0, aa1, ... | 959 // For all functions with fewer than 500 locals this is just as compact |
| 960 // For all functions with fewer than 500 locals this is just as compact | 960 // as using aa, ab, etc. but avoids clashes with keywords. |
| 961 // as using aa, ab, etc. but avoids clashes with keywords. | 961 n -= LETTERS; |
| 962 n -= LETTERS; | 962 int digit = n % DIGITS; |
| 963 int digit = n % DIGITS; | 963 n ~/= DIGITS; |
| 964 n ~/= DIGITS; | 964 int alphaChars = 1; |
| 965 int alphaChars = 1; | 965 int nameSpaceSize = LETTERS; |
| 966 int nameSpaceSize = LETTERS; | 966 // Find out whether we should use the 1-character namespace (size 52), the |
| 967 // Find out whether we should use the 1-character namespace (size 52), | 967 // 2-character namespace (size 52*52), etc. |
| 968 // the 2-character namespace (size 52*52), etc. | 968 while (n >= nameSpaceSize) { |
| 969 while (n >= nameSpaceSize) { | 969 n -= nameSpaceSize; |
| 970 n -= nameSpaceSize; | 970 alphaChars++; |
| 971 alphaChars++; | 971 nameSpaceSize *= LETTERS; |
| 972 nameSpaceSize *= LETTERS; | |
| 973 } | |
| 974 var codes = <int>[]; | |
| 975 for (var i = 0; i < alphaChars; i++) { | |
| 976 nameSpaceSize ~/= LETTERS; | |
| 977 codes.add(nthLetter((n ~/ nameSpaceSize) % LETTERS)); | |
| 978 } | |
| 979 codes.add(charCodes.$0 + digit); | |
| 980 newName = new String.fromCharCodes(codes); | |
| 981 } | 972 } |
| 982 assert(const RegExp(r'[a-zA-Z][a-zA-Z0-9]*').hasMatch(newName)); | 973 var codes = <int>[]; |
| 983 nameNumber++; | 974 for (var i = 0; i < alphaChars; i++) { |
| 984 } while (isReserved(newName)); | 975 nameSpaceSize ~/= LETTERS; |
| 985 maps.last()[oldName] = newName; | 976 codes.add(nthLetter((n ~/ nameSpaceSize) % LETTERS)); |
| 977 } |
| 978 codes.add(charCodes.$0 + digit); |
| 979 newName = new String.fromCharCodes(codes); |
| 980 } |
| 981 assert(const RegExp(r'[a-zA-Z][a-zA-Z0-9]*').hasMatch(newName)); |
| 982 nameNumber++; |
| 983 maps.last[oldName] = newName; |
| 986 return newName; | 984 return newName; |
| 987 } | 985 } |
| 988 | |
| 989 // We only have names here that are single-letter or end with a digit, | |
| 990 // since those are the ones we can generate. | |
| 991 bool isReserved(String name) { | |
| 992 assert(name.length == 1 || const RegExp(r'[0-9]$').hasMatch(name)); | |
| 993 // No names reserved yet. All JS keywords are more than one character and | |
| 994 // do not end with a digit. | |
| 995 return false; | |
| 996 } | |
| 997 } | 986 } |
| OLD | NEW |