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

Side by Side Diff: compiler/java/com/google/dart/compiler/backend/js/analysis/DependencyComputer.java

Issue 9479013: Remove backends. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
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.
4
5 package com.google.dart.compiler.backend.js.analysis;
6
7 import org.mozilla.javascript.Token;
8 import org.mozilla.javascript.ast.AstNode;
9 import org.mozilla.javascript.ast.FunctionNode;
10 import org.mozilla.javascript.ast.Name;
11 import org.mozilla.javascript.ast.NewExpression;
12 import org.mozilla.javascript.ast.NodeVisitor;
13 import org.mozilla.javascript.ast.PropertyGet;
14 import org.mozilla.javascript.ast.Scope;
15 import org.mozilla.javascript.ast.Symbol;
16
17 import java.util.ArrayList;
18 import java.util.HashSet;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22
23 /**
24 * Computes the set of dependencies that a given AstNode node has.
25 */
26 class DependencyComputer {
27 /**
28 * Visitor for determining what dependencies an AstNode has.
29 */
30 class DependencyComputingVisitor implements NodeVisitor {
31 /**
32 * Adds a dependency on the given identifier. If the identifier is virtual then then a
33 * dependency is only added if the enclosing "class" has been instantiated.
34 */
35 private void addDependency(String identifier, boolean isVirtual) {
36 List<JavascriptElement> members = namesToElements.get(identifier);
37 if (members != null) {
38 for (JavascriptElement member : members) {
39 if (isVirtual && member.isVirtual()) {
40 JavascriptElement enclosingElement = member.getEnclosingElement();
41 if (enclosingElement != null && enclosingElement.isInstantiated()) {
42 dependencies.add(member);
43 }
44 } else {
45 if (!member.isVirtual()) {
46 if (member.getEnclosingElement() != null) {
47 dependencies.add(member.getEnclosingElement());
48 }
49 }
50 dependencies.add(member);
51 }
52 }
53 }
54 }
55
56 /**
57 * Record that we saw a new of a given identifier.
58 */
59 private void addInstantiation(String identifier) {
60 List<JavascriptElement> instantiatedClasses = namesToElements.get(identifi er);
61 if (instantiatedClasses != null) {
62 for (JavascriptElement instantiatedClass : instantiatedClasses) {
63 instantiatedClass.setInstantiated(true);
64
65 /*
66 * Whenever we see an instantiation we must check it and any super typ e for members that
67 * match the virtual names seen to date and we must ensure that the co rresponding inherits
68 * get emitted.
69 */
70 while (instantiatedClass != null) {
71 JavascriptElement inheritsInvocation = instantiatedClass.getInherits Invocation();
72 if (inheritsInvocation != null) {
73 dependencies.add(inheritsInvocation);
74 }
75
76 for (JavascriptElement member : instantiatedClass.getMembers()) {
77 if (virtualNames.contains(member.getName())) {
78 dependencies.add(member);
79 }
80 }
81
82 instantiatedClass = instantiatedClass.getInheritsElement();
83 }
84 }
85 }
86 }
87
88 private void addStaticDependency(String identifier) {
89 addDependency(identifier, false);
90 }
91
92 private void addVirtualDependency(String identifier) {
93 virtualNames.add(identifier);
94 addDependency(identifier, true);
95 }
96
97 Symbol findSymbol(Scope scope, String name) {
98 if (scope == null) {
99 return null;
100 }
101
102 Symbol symbol = scope.getSymbol(name);
103 if (symbol == null) {
104 Scope parentScope = scope.getParentScope();
105 if (parentScope == null && (scope != scope.getAstRoot())) {
106 return findSymbol(scope.getAstRoot(), name);
107 } else {
108 return findSymbol(parentScope, name);
109 }
110 }
111
112 return symbol;
113 }
114
115 /**
116 * Returns true if the name is a local or parameter name. However, if the n ame is on the
117 * right hand side of a property get then we don't consider this name to be a local variable.
118 */
119 boolean isLocalVariableOrParameter(Name name) {
120 Scope definingScope = name.getDefiningScope();
121 Scope enclosingScope = name.getEnclosingScope();
122 if (definingScope != null) {
123 Symbol symbol = definingScope.getSymbol(name.getIdentifier());
124 if (definingScope.getType() == Token.FUNCTION) {
125 if (symbol != null && (symbol.getDeclType() == Token.VAR)
126 || (symbol.getDeclType() == Token.LP)) {
127
128 if (name.getParent().getType() == Token.GETPROP) {
129 PropertyGet propertyGet = (PropertyGet) name.getParent();
130 return propertyGet.getRight() != name;
131 }
132
133 return true;
134 }
135 }
136 }
137
138 return false;
139 }
140
141 /**
142 * Returns <code>true</code> if the name is associated with a native
143 * function or a top level function.
144 */
145 private boolean isNativeOrTopLevelFunction(Scope enclosingScope, String name ) {
146 List<JavascriptElement> list = namesToElements.get(name);
147 if (list == null || list.isEmpty()) {
148 return false;
149 }
150
151 Symbol symbol = findSymbol(enclosingScope, name);
152 if (symbol != null
153 && (symbol.getDeclType() == Token.FUNCTION || symbol.getDeclType() == Token.VAR)) {
154 return true;
155 }
156
157 JavascriptElement javascriptElement = list.get(0);
158 return javascriptElement.isNative();
159 }
160
161 /**
162 * Return a static name if the {@link PropertyGet} matches the pattern x.y o r
163 * x.prototype.y or <code>null</code> if it does not.
164 */
165 String maybeGetStaticName(PropertyGet propertyGet) {
166 AstNode right = propertyGet.getRight();
167 int rightType = right.getType();
168 if (rightType != Token.NAME) {
169 return null;
170 }
171
172 AstNode left = propertyGet.getLeft();
173 int leftType = left.getType();
174 if (leftType == Token.NAME) {
175 String qualifier = ((Name) left).getIdentifier();
176
177 if (isNativeOrTopLevelFunction(left.getEnclosingScope(), qualifier)) {
178 String targetName = ((Name) right).getIdentifier();
179 String qualifiedName = qualifier + "." + targetName;
180 if ("prototype".equals(targetName)) {
181 return qualifiedName;
182 } else if (namesToElements.containsKey(qualifiedName)) {
183 return qualifiedName;
184 }
185 }
186 } else if (leftType == Token.GETPROP) {
187 PropertyGet leftPropGet = (PropertyGet) left;
188 String handleSpecialCase = maybeGetStaticName(leftPropGet);
189 if (handleSpecialCase != null && handleSpecialCase.endsWith("prototype") ) {
190 handleSpecialCase = handleSpecialCase + "." + ((Name) right).getIdenti fier();
191 if (namesToElements.containsKey(handleSpecialCase)) {
192 return handleSpecialCase;
193 }
194 }
195 }
196
197 return null;
198 }
199
200 @Override
201 public boolean visit(AstNode node) {
202 switch (node.getType()) {
203 case Token.GETPROP:
204 PropertyGet propertyGet = (PropertyGet) node;
205 String staticName = maybeGetStaticName(propertyGet);
206 if (staticName != null) {
207 addStaticDependency(staticName);
208 return false;
209 }
210 break;
211
212 case Token.FUNCTION:
213 FunctionNode functionNode = (FunctionNode) node;
214 functionNode.getBody().visit(this);
215 // Don't process the parameters
216 return false;
217
218 case Token.NAME:
219 Name name = (Name) node;
220 if (!isLocalVariableOrParameter(name)) {
221 String identifier = name.getIdentifier();
222 addVirtualDependency(identifier);
223 }
224 break;
225
226 case Token.NEW:
227 NewExpression newExpression = (NewExpression) node;
228 Name target = (Name) newExpression.getTarget();
229 if (target != null) {
230 addInstantiation(target.getIdentifier());
231 }
232 break;
233
234 default:
235 break;
236 }
237
238 return true;
239 }
240
241 }
242
243 private final List<JavascriptElement> dependencies = new ArrayList<JavascriptE lement>();
244 private final Map<String, List<JavascriptElement>> namesToElements;
245
246 /**
247 * Names that have been referenced using virtual syntax, i.e. not using A.prot otype.foo, but
248 * as foo or this.foo, etc.
249 */
250 private final Set<String> virtualNames = new HashSet<String>();
251
252 public DependencyComputer(Map<String, List<JavascriptElement>> namesToElements ) {
253 this.namesToElements = namesToElements;
254 }
255
256 public List<JavascriptElement> computeDependencies(AstNode node) {
257 // Clear the dependencies so this object can be reused.
258 dependencies.clear();
259 node.visit(new DependencyComputingVisitor());
260 return dependencies;
261 }
262 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698