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

Side by Side Diff: lib/src/js/printer.dart

Issue 1030063004: more care around generated names, fixes #60 #82 and #97 (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 9 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
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 part of js_ast; 5 part of js_ast;
6 6
7 7
8 class JavaScriptPrintingOptions { 8 class JavaScriptPrintingOptions {
9 final bool shouldCompressOutput; 9 final bool shouldCompressOutput;
10 final bool minifyLocalVariables; 10 final bool minifyLocalVariables;
11 final bool preferSemicolonToNewlineInMinifiedOutput; 11 final bool preferSemicolonToNewlineInMinifiedOutput;
12 final bool avoidKeywordsInIdentifiers; 12
13
14 /// True to allow keywords in properties, such as `obj.var` or `obj.function`
15 /// Modern JS engines support this.
16 final bool allowKeywordsInProperties;
13 17
14 JavaScriptPrintingOptions( 18 JavaScriptPrintingOptions(
15 {this.shouldCompressOutput: false, 19 {this.shouldCompressOutput: false,
16 this.minifyLocalVariables: false, 20 this.minifyLocalVariables: false,
17 this.preferSemicolonToNewlineInMinifiedOutput: false, 21 this.preferSemicolonToNewlineInMinifiedOutput: false,
18 this.avoidKeywordsInIdentifiers: false}); 22 this.allowKeywordsInProperties: false});
19 } 23 }
20 24
21 25
22 /// An environment in which JavaScript printing is done. Provides emitting of 26 /// An environment in which JavaScript printing is done. Provides emitting of
23 /// text and pre- and post-visit callbacks. 27 /// text and pre- and post-visit callbacks.
24 abstract class JavaScriptPrintingContext { 28 abstract class JavaScriptPrintingContext {
25 /// Signals an error. This should happen only for serious internal errors. 29 /// Signals an error. This should happen only for serious internal errors.
26 void error(String message) { throw message; } 30 void error(String message) { throw message; }
27 31
28 /// Adds [string] to the output. 32 /// Adds [string] to the output.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 65
62 // The current indentation level. 66 // The current indentation level.
63 int _indentLevel = 0; 67 int _indentLevel = 0;
64 // A cache of all indentation strings used so far. 68 // A cache of all indentation strings used so far.
65 List<String> _indentList = <String>[""]; 69 List<String> _indentList = <String>[""];
66 70
67 static final identifierCharacterRegExp = new RegExp(r'^[a-zA-Z_0-9$]'); 71 static final identifierCharacterRegExp = new RegExp(r'^[a-zA-Z_0-9$]');
68 static final expressionContinuationRegExp = new RegExp(r'^[-+([]'); 72 static final expressionContinuationRegExp = new RegExp(r'^[-+([]');
69 73
70 Printer(JavaScriptPrintingOptions options, 74 Printer(JavaScriptPrintingOptions options,
71 JavaScriptPrintingContext context) 75 JavaScriptPrintingContext context,
76 {LocalNamer localNamer})
72 : options = options, 77 : options = options,
73 context = context, 78 context = context,
74 shouldCompressOutput = options.shouldCompressOutput, 79 shouldCompressOutput = options.shouldCompressOutput,
75 danglingElseVisitor = new DanglingElseVisitor(context), 80 danglingElseVisitor = new DanglingElseVisitor(context),
76 localNamer = determineRenamer(options.shouldCompressOutput, 81 localNamer = determineRenamer(localNamer, options);
77 options.minifyLocalVariables);
78 82
79 static LocalNamer determineRenamer(bool shouldCompressOutput, 83 static LocalNamer determineRenamer(LocalNamer localNamer,
80 bool allowVariableMinification) { 84 JavaScriptPrintingOptions options) {
81 return (shouldCompressOutput && allowVariableMinification) 85 if (localNamer != null) return localNamer;
86 return (options.shouldCompressOutput && options.minifyLocalVariables)
82 ? new MinifyRenamer() : new IdentityNamer(); 87 ? new MinifyRenamer() : new IdentityNamer();
83 } 88 }
84 89
85 90
86 // The current indentation string. 91 // The current indentation string.
87 String get indentation { 92 String get indentation {
88 // Lazily add new indentation strings as required. 93 // Lazily add new indentation strings as required.
89 while (_indentList.length <= _indentLevel) { 94 while (_indentList.length <= _indentLevel) {
90 _indentList.add(_indentList.last + " "); 95 _indentList.add(_indentList.last + " ");
91 } 96 }
(...skipping 679 matching lines...) Expand 10 before | Expand all | Expand 10 after
771 } 776 }
772 777
773 visitThis(This node) { 778 visitThis(This node) {
774 out("this"); 779 out("this");
775 } 780 }
776 781
777 visitSuper(Super node) { 782 visitSuper(Super node) {
778 out("super"); 783 out("super");
779 } 784 }
780 785
781 visitIdentifier(Identifier param) { 786 visitIdentifier(Identifier node) {
782 out(localNamer.getName(param.name)); 787 out(localNamer.getName(node));
783 } 788 }
784 789
785 bool isDigit(int charCode) { 790 bool isDigit(int charCode) {
786 return charCodes.$0 <= charCode && charCode <= charCodes.$9; 791 return charCodes.$0 <= charCode && charCode <= charCodes.$9;
787 } 792 }
788 793
789 bool isValidJavaScriptId(String field) { 794 bool isValidJavaScriptId(String field) {
790 if (field.length < 3) return false; 795 if (field.length < 3) return false;
791 // Ignore the leading and trailing string-delimiter. 796 // Ignore the leading and trailing string-delimiter.
792 for (int i = 1; i < field.length - 1; i++) { 797 for (int i = 1; i < field.length - 1; i++) {
793 // TODO(floitsch): allow more characters. 798 // TODO(floitsch): allow more characters.
794 int charCode = field.codeUnitAt(i); 799 int charCode = field.codeUnitAt(i);
795 if (!(charCodes.$a <= charCode && charCode <= charCodes.$z || 800 if (!(charCodes.$a <= charCode && charCode <= charCodes.$z ||
796 charCodes.$A <= charCode && charCode <= charCodes.$Z || 801 charCodes.$A <= charCode && charCode <= charCodes.$Z ||
797 charCode == charCodes.$$ || 802 charCode == charCodes.$$ ||
798 charCode == charCodes.$_ || 803 charCode == charCodes.$_ ||
799 i != 1 && isDigit(charCode))) { 804 i != 1 && isDigit(charCode))) {
800 return false; 805 return false;
801 } 806 }
802 } 807 }
803 808
804 if (options.avoidKeywordsInIdentifiers) { 809 // TODO(floitsch): normally we should also check that the field is not a
805 return !isJsKeyword(field.substring(1, field.length - 1)); 810 // reserved word. We don't generate fields with reserved word names except
806 } else { 811 // for 'super'.
807 // TODO(floitsch): normally we should also check that the field is not a 812 return options.allowKeywordsInProperties || field != '"super"';
808 // reserved word. We don't generate fields with reserved word names excep t
809 // for 'super'.
810 return field != '"super"';
811 }
812 } 813 }
813 814
814 visitAccess(PropertyAccess access) { 815 visitAccess(PropertyAccess access) {
815 visitNestedExpression(access.receiver, CALL, 816 visitNestedExpression(access.receiver, CALL,
816 newInForInit: inForInit, 817 newInForInit: inForInit,
817 newAtStatementBegin: atStatementBegin); 818 newAtStatementBegin: atStatementBegin);
818 propertyNameOut(access.selector, inAccess: true); 819 propertyNameOut(access.selector, inAccess: true);
819 } 820 }
820 821
821 visitNamedFunction(NamedFunction namedFunction) { 822 visitNamedFunction(NamedFunction namedFunction) {
(...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after
1234 bool visitLabeledStatement(LabeledStatement node) 1235 bool visitLabeledStatement(LabeledStatement node)
1235 => node.body.accept(this); 1236 => node.body.accept(this);
1236 bool visitLiteralStatement(LiteralStatement node) => true; 1237 bool visitLiteralStatement(LiteralStatement node) => true;
1237 bool visitClassDeclaration(ClassDeclaration) => false; 1238 bool visitClassDeclaration(ClassDeclaration) => false;
1238 1239
1239 bool visitExpression(Expression node) => false; 1240 bool visitExpression(Expression node) => false;
1240 } 1241 }
1241 1242
1242 1243
1243 abstract class LocalNamer { 1244 abstract class LocalNamer {
1244 String getName(String oldName); 1245 String getName(Identifier node);
1245 void enterScope(Node node); 1246 void enterScope(Node node);
1246 void leaveScope(); 1247 void leaveScope();
1247 } 1248 }
1248 1249
1249 1250
1250 class IdentityNamer implements LocalNamer { 1251 class IdentityNamer implements LocalNamer {
1251 String getName(String oldName) => oldName; 1252 String getName(Identifier node) => node.name;
1252 void enterScope(Node node) {} 1253 void enterScope(Node node) {}
1253 void leaveScope() {} 1254 void leaveScope() {}
1254 } 1255 }
1255 1256
1256 1257
1257 class MinifyRenamer implements LocalNamer { 1258 class MinifyRenamer implements LocalNamer {
1258 final List<Map<String, String>> maps = []; 1259 final List<Map<String, String>> maps = [];
1259 final List<int> parameterNumberStack = []; 1260 final List<int> parameterNumberStack = [];
1260 final List<int> variableNumberStack = []; 1261 final List<int> variableNumberStack = [];
1261 int parameterNumber = 0; 1262 int parameterNumber = 0;
1262 int variableNumber = 0; 1263 int variableNumber = 0;
1263 1264
1264 void enterScope(Node node) { 1265 void enterScope(Node node) {
1265 var vars = new VarCollector(); 1266 var vars = new VarCollector();
1266 node.accept(vars); 1267 node.accept(vars);
1267 maps.add(new Map<String, String>()); 1268 maps.add(new Map<String, String>());
1268 variableNumberStack.add(variableNumber); 1269 variableNumberStack.add(variableNumber);
1269 parameterNumberStack.add(parameterNumber); 1270 parameterNumberStack.add(parameterNumber);
1270 vars.forEachVar(declareVariable); 1271 vars.forEachVar(declareVariable);
1271 vars.forEachParam(declareParameter); 1272 vars.forEachParam(declareParameter);
1272 } 1273 }
1273 1274
1274 void leaveScope() { 1275 void leaveScope() {
1275 maps.removeLast(); 1276 maps.removeLast();
1276 variableNumber = variableNumberStack.removeLast(); 1277 variableNumber = variableNumberStack.removeLast();
1277 parameterNumber = parameterNumberStack.removeLast(); 1278 parameterNumber = parameterNumberStack.removeLast();
1278 } 1279 }
1279 1280
1280 String getName(String oldName) { 1281 String getName(Identifier node) {
1282 String oldName = node.name;
1281 // Go from inner scope to outer looking for mapping of name. 1283 // Go from inner scope to outer looking for mapping of name.
1282 for (int i = maps.length - 1; i >= 0; i--) { 1284 for (int i = maps.length - 1; i >= 0; i--) {
1283 var map = maps[i]; 1285 var map = maps[i];
1284 var replacement = map[oldName]; 1286 var replacement = map[oldName];
1285 if (replacement != null) return replacement; 1287 if (replacement != null) return replacement;
1286 } 1288 }
1287 return oldName; 1289 return oldName;
1288 } 1290 }
1289 1291
1290 static const LOWER_CASE_LETTERS = 26; 1292 static const LOWER_CASE_LETTERS = 26;
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
1367 codes.add(nthLetter((n ~/ nameSpaceSize) % LETTERS)); 1369 codes.add(nthLetter((n ~/ nameSpaceSize) % LETTERS));
1368 } 1370 }
1369 codes.add(charCodes.$0 + digit); 1371 codes.add(charCodes.$0 + digit);
1370 newName = new String.fromCharCodes(codes); 1372 newName = new String.fromCharCodes(codes);
1371 } 1373 }
1372 assert(new RegExp(r'[a-zA-Z][a-zA-Z0-9]*').hasMatch(newName)); 1374 assert(new RegExp(r'[a-zA-Z][a-zA-Z0-9]*').hasMatch(newName));
1373 maps.last[oldName] = newName; 1375 maps.last[oldName] = newName;
1374 return newName; 1376 return newName;
1375 } 1377 }
1376 } 1378 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698