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

Side by Side Diff: lib/src/codegen/js_names.dart

Issue 1200243002: fixes #232, handling of arguments (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 6 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) 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
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 /// * rename JS identifiers to avoid keywords. 53 /// * rename JS identifiers to avoid keywords.
54 /// * rename temporary variables to avoid colliding with user-specified names, 54 /// * rename temporary variables to avoid colliding with user-specified names,
55 /// or other temporaries 55 /// or other temporaries
56 /// 56 ///
57 /// Each instance of [TemporaryId] is treated as a unique variable, with its 57 /// Each instance of [TemporaryId] is treated as a unique variable, with its
58 /// `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
59 /// [Identifiers] are never renamed unless they are an invalid identifier, like 59 /// [Identifiers] are never renamed unless they are an invalid identifier, like
60 /// `function` or `instanceof`, and their `name` field controls whether they 60 /// `function` or `instanceof`, and their `name` field controls whether they
61 /// refer to the same variable. 61 /// refer to the same variable.
62 class TemporaryNamer extends LocalNamer { 62 class TemporaryNamer extends LocalNamer {
63 final Map<Object, String> renames; 63 _FunctionScope scope;
64 64
65 TemporaryNamer(Node node) : renames = new _RenameVisitor.build(node).renames; 65 TemporaryNamer(Node node) : scope = new _RenameVisitor.build(node).rootScope;
66 66
67 String getName(Identifier node) { 67 String getName(Identifier node) {
68 var rename = renames[identifierKey(node)]; 68 var rename = scope.renames[identifierKey(node)];
69 if (rename != null) return rename; 69 if (rename != null) return rename;
70
71 assert(!needsRename(node));
72 return node.name; 70 return node.name;
73 } 71 }
74 72
75 void enterScope(FunctionExpression node) {} 73 void enterScope(FunctionExpression node) {
76 void leaveScope() {} 74 scope = scope.functions[node];
75 }
76 void leaveScope() {
77 scope = scope.parent;
78 }
77 } 79 }
78 80
79 /// Represents a complete function scope in JS. 81 /// Represents a complete function scope in JS.
80 /// 82 ///
81 /// We don't currently track ES6 block scopes, because we don't represent them 83 /// We don't currently track ES6 block scopes, because we don't represent them
82 /// in js_ast yet. 84 /// in js_ast yet.
83 class _FunctionScope { 85 class _FunctionScope {
84 /// The parent scope. 86 /// The parent scope.
85 final _FunctionScope parent; 87 final _FunctionScope parent;
86 88
87 /// All names declared in this scope. 89 /// All names declared in this scope.
88 final declared = new HashSet<Object>(); 90 final declared = new HashSet<Object>();
89 91
90 /// All names [declared] in this scope or its [parent]s, that is used in this 92 /// All names [declared] in this scope or its [parent]s, that is used in this
91 /// scope and/or children. This is exactly the set of variable names we must 93 /// scope and/or children. This is exactly the set of variable names we must
92 /// not collide with inside this scope. 94 /// not collide with inside this scope.
93 final used = new HashSet<String>(); 95 final used = new HashSet<String>();
94 96
95 /// Nested functions, these are visited after everything else so the names 97 /// Nested functions, these are visited after everything else so the names
96 /// they might need are in scope. 98 /// they might need are in scope.
97 final functions = new List<FunctionExpression>(); 99 final functions = new Map<FunctionExpression, _FunctionScope>();
100
101 /// New names assigned for temps and identifiers.
102 final renames = new HashMap<Object, String>();
98 103
99 _FunctionScope(this.parent); 104 _FunctionScope(this.parent);
100 } 105 }
101 106
102 /// Collects all names used in the visited tree. 107 /// Collects all names used in the visited tree.
103 class _RenameVisitor extends VariableDeclarationVisitor { 108 class _RenameVisitor extends VariableDeclarationVisitor {
104 final pendingRenames = new Map<Object, Set<_FunctionScope>>(); 109 final pendingRenames = new Map<Object, Set<_FunctionScope>>();
105 final renames = new HashMap<Object, String>();
106 110
107 final _FunctionScope rootScope = new _FunctionScope(null); 111 final _FunctionScope rootScope = new _FunctionScope(null);
108 _FunctionScope scope; 112 _FunctionScope scope;
109 113
110 _RenameVisitor.build(Node root) { 114 _RenameVisitor.build(Node root) {
111 scope = rootScope; 115 scope = rootScope;
112 root.accept(this); 116 root.accept(this);
113 _finishFunctions(); 117 _finishFunctions();
114 _finishNames(); 118 _finishNames();
115 } 119 }
(...skipping 20 matching lines...) Expand all
136 declScope = rootScope; 140 declScope = rootScope;
137 declScope.declared.add(id); 141 declScope.declared.add(id);
138 } 142 }
139 _markUsed(node, id, declScope); 143 _markUsed(node, id, declScope);
140 } 144 }
141 145
142 _markUsed(Identifier node, Object id, _FunctionScope declScope) { 146 _markUsed(Identifier node, Object id, _FunctionScope declScope) {
143 // If it needs rename, we can't add it to the used name set yet, instead we 147 // If it needs rename, we can't add it to the used name set yet, instead we
144 // will record all scopes it is visible in. 148 // will record all scopes it is visible in.
145 Set<_FunctionScope> usedIn = null; 149 Set<_FunctionScope> usedIn = null;
146 if (needsRename(node)) { 150 var rename = declScope != rootScope && needsRename(node);
151 if (rename) {
147 usedIn = pendingRenames.putIfAbsent(id, () => new HashSet()); 152 usedIn = pendingRenames.putIfAbsent(id, () => new HashSet());
148 } 153 }
149 for (var s = scope, end = declScope.parent; s != end; s = s.parent) { 154 for (var s = scope, end = declScope.parent; s != end; s = s.parent) {
150 if (usedIn != null) { 155 if (usedIn != null) {
151 usedIn.add(s); 156 usedIn.add(s);
152 } else { 157 } else {
153 s.used.add(node.name); 158 s.used.add(node.name);
154 } 159 }
155 } 160 }
156 } 161 }
157 162
158 visitFunctionExpression(FunctionExpression node) { 163 visitFunctionExpression(FunctionExpression node) {
159 // Visit nested functions after all identifiers are declared. 164 // Visit nested functions after all identifiers are declared.
160 scope.functions.add(node); 165 scope.functions[node] = new _FunctionScope(scope);
161 } 166 }
162 167
163 void _finishFunctions() { 168 void _finishFunctions() {
164 for (var f in scope.functions) { 169 scope.functions.forEach((FunctionExpression f, _FunctionScope s) {
165 scope = new _FunctionScope(scope); 170 scope = s;
166 super.visitFunctionExpression(f); 171 super.visitFunctionExpression(f);
167 _finishFunctions(); 172 _finishFunctions();
168 scope = scope.parent; 173 scope = scope.parent;
169 } 174 });
170 } 175 }
171 176
172 void _finishNames() { 177 void _finishNames() {
173 var allNames = new Set<String>(); 178 var allNames = new Set<String>();
174 pendingRenames.forEach((id, scopes) { 179 pendingRenames.forEach((id, scopes) {
175 allNames.clear(); 180 allNames.clear();
176 for (var s in scopes) allNames.addAll(s.used); 181 for (var s in scopes) allNames.addAll(s.used);
177 182
178 var name = _findName(id, allNames); 183 var name = _findName(id, allNames);
179 renames[id] = name; 184 for (var s in scopes) {
180 185 s.used.add(name);
181 for (var s in scopes) s.used.add(name); 186 s.renames[id] = name;
187 }
182 }); 188 });
183 } 189 }
184 190
185 static String _findName(Object id, Set<String> usedNames) { 191 static String _findName(Object id, Set<String> usedNames) {
186 String name; 192 String name;
187 bool valid; 193 bool valid;
188 if (id is TemporaryId) { 194 if (id is TemporaryId) {
189 name = id.name; 195 name = id.name;
190 valid = !invalidVariableName(name); 196 valid = !invalidVariableName(name);
191 } else { 197 } else {
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 /// In particular, "caller" "callee" and "arguments" cannot be used. 275 /// In particular, "caller" "callee" and "arguments" cannot be used.
270 bool invalidStaticFieldName(String name) { 276 bool invalidStaticFieldName(String name) {
271 switch (name) { 277 switch (name) {
272 case "arguments": 278 case "arguments":
273 case "caller": 279 case "caller":
274 case "callee": 280 case "callee":
275 return true; 281 return true;
276 } 282 }
277 return false; 283 return false;
278 } 284 }
OLDNEW
« lib/src/codegen/js_codegen.dart ('K') | « lib/src/codegen/js_codegen.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698