OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 library dev_compiler.src.codegen.js_names; | 5 library dev_compiler.src.codegen.js_names; |
6 | 6 |
7 import 'dart:collection'; | 7 import 'dart:collection'; |
8 import 'package:dev_compiler/src/js/js_ast.dart'; | 8 import 'package:dev_compiler/src/js/js_ast.dart'; |
9 | 9 |
10 /// Unique instance for temporary variables. Will be renamed consistently | 10 /// Unique instance for temporary variables. Will be renamed consistently |
11 /// across the entire file. Different instances will be named differently | 11 /// across the entire file. Different instances will be named differently |
12 /// even if they have the same name, this makes it safe to use in code | 12 /// even if they have the same name, this makes it safe to use in code |
13 /// generation without needing global knowledge. See [JSNamer]. | 13 /// generation without needing global knowledge. See [JSNamer]. |
14 /// | 14 /// |
15 // TODO(jmesserly): move into js_ast? add a boolean to Identifier? | 15 // TODO(jmesserly): move into js_ast? add a boolean to Identifier? |
16 class TemporaryId extends Identifier { | 16 class TemporaryId extends Identifier { |
17 static int __id = 0; | |
Jennifer Messerly
2015/05/12 16:23:46
this helped for debugging, I could remove it thoug
| |
18 final int _id = ++__id; | |
17 TemporaryId(String name) : super(name); | 19 TemporaryId(String name) : super(name); |
20 toString() => super.toString() + ' $_id'; | |
21 } | |
22 | |
23 /// Creates a qualified identifier, without determining for sure if it needs to | |
24 /// be qualified until [setQualified] is called. | |
25 /// | |
26 /// This expression is transparent to visiting after [setQualified]. | |
27 class MaybeQualifiedId extends Expression { | |
28 Expression _expr; | |
29 | |
30 final Identifier qualifier; | |
31 final Expression name; | |
32 | |
33 MaybeQualifiedId(this.qualifier, this.name) { | |
34 _expr = new PropertyAccess(qualifier, name); | |
35 } | |
36 | |
37 /// Helper to create an [Identifier] from something that starts as a property. | |
38 static identifier(LiteralString propertyName) => | |
39 new Identifier(propertyName.valueWithoutQuotes); | |
40 | |
41 void setQualified(bool qualified) { | |
42 if (!qualified && name is LiteralString) { | |
43 _expr = identifier(name); | |
44 } | |
45 } | |
46 | |
47 int get precedenceLevel => _expr.precedenceLevel; | |
48 | |
49 accept(NodeVisitor visitor) => _expr.accept(visitor); | |
50 | |
51 void visitChildren(NodeVisitor visitor) => _expr.visitChildren(visitor); | |
18 } | 52 } |
19 | 53 |
20 /// This class has two purposes: | 54 /// This class has two purposes: |
21 /// | 55 /// |
22 /// * rename JS identifiers to avoid keywords. | 56 /// * rename JS identifiers to avoid keywords. |
23 /// * rename temporary variables to avoid colliding with user-specified names, | 57 /// * rename temporary variables to avoid colliding with user-specified names, |
24 /// or other temporaries | 58 /// or other temporaries |
25 /// | 59 /// |
26 /// Each instance of [JSTemporary] is treated as a unique variable, with its | 60 /// Each instance of [TemporaryId] is treated as a unique variable, with its |
27 /// `name` field simply the suggestion of what name to use. By contrast | 61 /// `name` field simply the suggestion of what name to use. By contrast |
28 /// [Identifiers] are never renamed unless they are an invalid identifier, like | 62 /// [Identifiers] are never renamed unless they are an invalid identifier, like |
29 /// `function` or `instanceof`, and their `name` field controls whether they | 63 /// `function` or `instanceof`, and their `name` field controls whether they |
30 /// refer to the same variable. | 64 /// refer to the same variable. |
31 class TemporaryNamer extends LocalNamer { | 65 class TemporaryNamer extends LocalNamer { |
32 final Map<Object, String> renames; | 66 final Map<Object, String> renames; |
33 | 67 |
34 TemporaryNamer(Node node) : renames = new _RenameVisitor.build(node).renames; | 68 TemporaryNamer(Node node) : renames = new _RenameVisitor.build(node).renames; |
35 | 69 |
36 String getName(Identifier node) { | 70 String getName(Identifier node) { |
(...skipping 26 matching lines...) Expand all Loading... | |
63 | 97 |
64 /// Nested functions, these are visited after everything else so the names | 98 /// Nested functions, these are visited after everything else so the names |
65 /// they might need are in scope. | 99 /// they might need are in scope. |
66 final functions = new List<FunctionExpression>(); | 100 final functions = new List<FunctionExpression>(); |
67 | 101 |
68 _FunctionScope(this.parent); | 102 _FunctionScope(this.parent); |
69 } | 103 } |
70 | 104 |
71 /// Collects all names used in the visited tree. | 105 /// Collects all names used in the visited tree. |
72 class _RenameVisitor extends VariableDeclarationVisitor { | 106 class _RenameVisitor extends VariableDeclarationVisitor { |
73 final pendingRenames = new Map<Object, Set<_FunctionScope>>(); | 107 final pendingRenames = new Map<Object, Set<_FunctionScope>>.identity(); |
74 final renames = new HashMap<Object, String>(); | 108 final renames = new HashMap<Object, String>.identity(); |
75 | 109 |
76 final _FunctionScope rootScope = new _FunctionScope(null); | 110 final _FunctionScope rootScope = new _FunctionScope(null); |
77 _FunctionScope scope; | 111 _FunctionScope scope; |
78 | 112 |
79 _RenameVisitor.build(Node root) { | 113 _RenameVisitor.build(Node root) { |
80 scope = rootScope; | 114 scope = rootScope; |
81 root.accept(this); | 115 root.accept(this); |
82 _finishFunctions(); | 116 _finishFunctions(); |
83 _finishNames(); | 117 _finishNames(); |
84 } | 118 } |
(...skipping 23 matching lines...) Expand all Loading... | |
108 _markUsed(node, id, declScope); | 142 _markUsed(node, id, declScope); |
109 } | 143 } |
110 | 144 |
111 _markUsed(Identifier node, Object id, _FunctionScope declScope) { | 145 _markUsed(Identifier node, Object id, _FunctionScope declScope) { |
112 // If it needs rename, we can't add it to the used name set yet, instead we | 146 // If it needs rename, we can't add it to the used name set yet, instead we |
113 // will record all scopes it is visible in. | 147 // will record all scopes it is visible in. |
114 Set<_FunctionScope> usedIn = null; | 148 Set<_FunctionScope> usedIn = null; |
115 if (needsRename(node)) { | 149 if (needsRename(node)) { |
116 usedIn = pendingRenames.putIfAbsent(id, () => new HashSet()); | 150 usedIn = pendingRenames.putIfAbsent(id, () => new HashSet()); |
117 } | 151 } |
118 | |
119 for (var s = scope, end = declScope.parent; s != end; s = s.parent) { | 152 for (var s = scope, end = declScope.parent; s != end; s = s.parent) { |
120 if (usedIn != null) { | 153 if (usedIn != null) { |
121 usedIn.add(s); | 154 usedIn.add(s); |
122 } else { | 155 } else { |
123 s.used.add(node.name); | 156 s.used.add(node.name); |
124 } | 157 } |
125 } | 158 } |
126 } | 159 } |
127 | 160 |
128 visitFunctionExpression(FunctionExpression node) { | 161 visitFunctionExpression(FunctionExpression node) { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
177 candidate = '${name}\$$i'; | 210 candidate = '${name}\$$i'; |
178 } | 211 } |
179 } | 212 } |
180 return candidate; | 213 return candidate; |
181 } | 214 } |
182 } | 215 } |
183 | 216 |
184 bool needsRename(Identifier node) => | 217 bool needsRename(Identifier node) => |
185 node is TemporaryId || node.allowRename && invalidVariableName(node.name); | 218 node is TemporaryId || node.allowRename && invalidVariableName(node.name); |
186 | 219 |
187 Object /*String|JSTemporary*/ identifierKey(Identifier node) => | 220 Object /*String|TemporaryId*/ identifierKey(Identifier node) => |
188 node is TemporaryId ? node : node.name; | 221 node is TemporaryId ? node : node.name; |
189 | 222 |
190 /// Returns true for invalid JS variable names, such as keywords. | 223 /// Returns true for invalid JS variable names, such as keywords. |
191 /// Also handles invalid variable names in strict mode, like "arguments". | 224 /// Also handles invalid variable names in strict mode, like "arguments". |
192 bool invalidVariableName(String keyword, {bool strictMode: true}) { | 225 bool invalidVariableName(String keyword, {bool strictMode: true}) { |
193 switch (keyword) { | 226 switch (keyword) { |
194 case "break": | 227 case "break": |
195 case "case": | 228 case "case": |
196 case "catch": | 229 case "catch": |
197 case "class": | 230 case "class": |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
238 /// In particular, "caller" "callee" and "arguments" cannot be used. | 271 /// In particular, "caller" "callee" and "arguments" cannot be used. |
239 bool invalidStaticFieldName(String name) { | 272 bool invalidStaticFieldName(String name) { |
240 switch (name) { | 273 switch (name) { |
241 case "arguments": | 274 case "arguments": |
242 case "caller": | 275 case "caller": |
243 case "callee": | 276 case "callee": |
244 return true; | 277 return true; |
245 } | 278 } |
246 return false; | 279 return false; |
247 } | 280 } |
OLD | NEW |