| 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 TemporaryId(String name) : super(name); | 17 TemporaryId(String name) : super(name); |
| 18 } | 18 } |
| 19 | 19 |
| 20 /// Creates a qualified identifier, without determining for sure if it needs to |
| 21 /// be qualified until [setQualified] is called. |
| 22 /// |
| 23 /// This expression is transparent to visiting after [setQualified]. |
| 24 class MaybeQualifiedId extends Expression { |
| 25 Expression _expr; |
| 26 |
| 27 final Identifier qualifier; |
| 28 final Expression name; |
| 29 |
| 30 MaybeQualifiedId(this.qualifier, this.name) { |
| 31 _expr = new PropertyAccess(qualifier, name); |
| 32 } |
| 33 |
| 34 /// Helper to create an [Identifier] from something that starts as a property. |
| 35 static identifier(LiteralString propertyName) => |
| 36 new Identifier(propertyName.valueWithoutQuotes); |
| 37 |
| 38 void setQualified(bool qualified) { |
| 39 if (!qualified && name is LiteralString) { |
| 40 _expr = identifier(name); |
| 41 } |
| 42 } |
| 43 |
| 44 int get precedenceLevel => _expr.precedenceLevel; |
| 45 |
| 46 accept(NodeVisitor visitor) => _expr.accept(visitor); |
| 47 |
| 48 void visitChildren(NodeVisitor visitor) => _expr.visitChildren(visitor); |
| 49 } |
| 50 |
| 20 /// This class has two purposes: | 51 /// This class has two purposes: |
| 21 /// | 52 /// |
| 22 /// * rename JS identifiers to avoid keywords. | 53 /// * rename JS identifiers to avoid keywords. |
| 23 /// * rename temporary variables to avoid colliding with user-specified names, | 54 /// * rename temporary variables to avoid colliding with user-specified names, |
| 24 /// or other temporaries | 55 /// or other temporaries |
| 25 /// | 56 /// |
| 26 /// Each instance of [JSTemporary] is treated as a unique variable, with its | 57 /// 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 | 58 /// `name` field simply the suggestion of what name to use. By contrast |
| 28 /// [Identifiers] are never renamed unless they are an invalid identifier, like | 59 /// [Identifiers] are never renamed unless they are an invalid identifier, like |
| 29 /// `function` or `instanceof`, and their `name` field controls whether they | 60 /// `function` or `instanceof`, and their `name` field controls whether they |
| 30 /// refer to the same variable. | 61 /// refer to the same variable. |
| 31 class TemporaryNamer extends LocalNamer { | 62 class TemporaryNamer extends LocalNamer { |
| 32 final Map<Object, String> renames; | 63 final Map<Object, String> renames; |
| 33 | 64 |
| 34 TemporaryNamer(Node node) : renames = new _RenameVisitor.build(node).renames; | 65 TemporaryNamer(Node node) : renames = new _RenameVisitor.build(node).renames; |
| 35 | 66 |
| 36 String getName(Identifier node) { | 67 String getName(Identifier node) { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 108 _markUsed(node, id, declScope); | 139 _markUsed(node, id, declScope); |
| 109 } | 140 } |
| 110 | 141 |
| 111 _markUsed(Identifier node, Object id, _FunctionScope declScope) { | 142 _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 | 143 // 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. | 144 // will record all scopes it is visible in. |
| 114 Set<_FunctionScope> usedIn = null; | 145 Set<_FunctionScope> usedIn = null; |
| 115 if (needsRename(node)) { | 146 if (needsRename(node)) { |
| 116 usedIn = pendingRenames.putIfAbsent(id, () => new HashSet()); | 147 usedIn = pendingRenames.putIfAbsent(id, () => new HashSet()); |
| 117 } | 148 } |
| 118 | |
| 119 for (var s = scope, end = declScope.parent; s != end; s = s.parent) { | 149 for (var s = scope, end = declScope.parent; s != end; s = s.parent) { |
| 120 if (usedIn != null) { | 150 if (usedIn != null) { |
| 121 usedIn.add(s); | 151 usedIn.add(s); |
| 122 } else { | 152 } else { |
| 123 s.used.add(node.name); | 153 s.used.add(node.name); |
| 124 } | 154 } |
| 125 } | 155 } |
| 126 } | 156 } |
| 127 | 157 |
| 128 visitFunctionExpression(FunctionExpression node) { | 158 visitFunctionExpression(FunctionExpression node) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 177 candidate = '${name}\$$i'; | 207 candidate = '${name}\$$i'; |
| 178 } | 208 } |
| 179 } | 209 } |
| 180 return candidate; | 210 return candidate; |
| 181 } | 211 } |
| 182 } | 212 } |
| 183 | 213 |
| 184 bool needsRename(Identifier node) => | 214 bool needsRename(Identifier node) => |
| 185 node is TemporaryId || node.allowRename && invalidVariableName(node.name); | 215 node is TemporaryId || node.allowRename && invalidVariableName(node.name); |
| 186 | 216 |
| 187 Object /*String|JSTemporary*/ identifierKey(Identifier node) => | 217 Object /*String|TemporaryId*/ identifierKey(Identifier node) => |
| 188 node is TemporaryId ? node : node.name; | 218 node is TemporaryId ? node : node.name; |
| 189 | 219 |
| 190 /// Returns true for invalid JS variable names, such as keywords. | 220 /// Returns true for invalid JS variable names, such as keywords. |
| 191 /// Also handles invalid variable names in strict mode, like "arguments". | 221 /// Also handles invalid variable names in strict mode, like "arguments". |
| 192 bool invalidVariableName(String keyword, {bool strictMode: true}) { | 222 bool invalidVariableName(String keyword, {bool strictMode: true}) { |
| 193 switch (keyword) { | 223 switch (keyword) { |
| 194 case "break": | 224 case "break": |
| 195 case "case": | 225 case "case": |
| 196 case "catch": | 226 case "catch": |
| 197 case "class": | 227 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. | 268 /// In particular, "caller" "callee" and "arguments" cannot be used. |
| 239 bool invalidStaticFieldName(String name) { | 269 bool invalidStaticFieldName(String name) { |
| 240 switch (name) { | 270 switch (name) { |
| 241 case "arguments": | 271 case "arguments": |
| 242 case "caller": | 272 case "caller": |
| 243 case "callee": | 273 case "callee": |
| 244 return true; | 274 return true; |
| 245 } | 275 } |
| 246 return false; | 276 return false; |
| 247 } | 277 } |
| OLD | NEW |