PageRenderTime 49ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/bundles/plugins-trunk/XML/sidekick/ecmascript/parser/GlobalDeclCollector.java

#
Java | 298 lines | 195 code | 54 blank | 49 comment | 49 complexity | b364c863f5e46f7429a187328f42e7da MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. Copyright (c) 2004-2005, The Dojo Foundation
  3. All Rights Reserved.
  4. Licensed under the Academic Free License version 2.1 or above OR the
  5. modified BSD license. For more information on Dojo licensing, see:
  6. http://dojotoolkit.org/community/licensing.shtml <http://dojotoolkit.org/community/licensing.shtml>
  7. Code donated to the Dojo Foundation by AOL LLC under the terms of
  8. the Dojo CCLA (http://dojotoolkit.org/ccla.txt).
  9. */
  10. package sidekick.ecmascript.parser;
  11. import java.util.*;
  12. import sidekick.ecmascript.parser.ASTAssignmentExpression;
  13. import sidekick.ecmascript.parser.ASTExpressionStatement;
  14. import sidekick.ecmascript.parser.ASTForVarInStatement;
  15. import sidekick.ecmascript.parser.ASTForVarStatement;
  16. import sidekick.ecmascript.parser.ASTFormalParameterList;
  17. import sidekick.ecmascript.parser.ASTVariableDeclaration;
  18. import sidekick.ecmascript.parser.EcmaScriptVisitor;
  19. /**
  20. * Visitor that collects the global identifiers and string literals in the code
  21. * base and also decorates the function declaration nodes with symbol table
  22. * information of local variables
  23. *
  24. *
  25. * @since JDK 1.4
  26. */
  27. public class GlobalDeclCollector extends EcmaScriptVisitorAdapter implements
  28. EcmaScriptVisitor {
  29. // globals
  30. private Set declarations;
  31. private LinkedList declarationNodes;
  32. private boolean collectForvarDeclarations;
  33. // stacks of local variables
  34. private LinkedList localDeclarations;
  35. private LinkedList loopDeclarations;
  36. public GlobalDeclCollector(Set declarations, LinkedList declarationNodes,
  37. EcmaScriptVisitorDelegate visitorDelegate) {
  38. super(visitorDelegate);
  39. this.declarations = declarations;
  40. this.declarationNodes = declarationNodes;
  41. localDeclarations = new LinkedList();
  42. loopDeclarations = new LinkedList();
  43. }
  44. public GlobalDeclCollector(Set declarations, LinkedList declarationNodes) {
  45. this(declarations, declarationNodes, null);
  46. }
  47. public GlobalDeclCollector(Set declarations) {
  48. this(declarations, null);
  49. }
  50. private boolean isLocal(String identifierName) {
  51. ListIterator iter = loopDeclarations.listIterator(loopDeclarations
  52. .size());
  53. while (iter.hasPrevious()) {
  54. Map decls = (Map) iter.previous();
  55. if (decls.containsKey(identifierName)) {
  56. return true;
  57. }
  58. }
  59. iter = localDeclarations.listIterator(localDeclarations.size());
  60. while (iter.hasPrevious()) {
  61. Map decls = (Map) iter.previous();
  62. if (decls.containsKey(identifierName)) {
  63. return true;
  64. }
  65. }
  66. return false;
  67. }
  68. @Override
  69. public Object visit(ASTVariableDeclaration node, Object data) {
  70. String name = ((ASTIdentifier) node.jjtGetChild(0)).getName();
  71. if (collectForvarDeclarations) {
  72. Map forvarDeclarations = (Map) loopDeclarations.getLast();
  73. if (!forvarDeclarations.containsKey(name)) {
  74. forvarDeclarations.put(name, name);
  75. }
  76. } else if (localDeclarations.size() > 0) {
  77. Map functionDecls = (Map) localDeclarations.getLast();
  78. if (!functionDecls.containsKey(name)) {
  79. functionDecls.put(name, name);
  80. }
  81. } else {
  82. declarations.add(name);
  83. if (declarationNodes != null) {
  84. declarationNodes.add(node);
  85. }
  86. }
  87. return super.visit(node, data);
  88. }
  89. @Override
  90. public Object visit(ASTExpressionStatement node, Object data) {
  91. // see if we have an assignment expression with a composite reference on
  92. // the lhs
  93. if (node.jjtGetNumChildren() > 0) {
  94. SimpleNode exprNode = (SimpleNode) node.jjtGetChild(0);
  95. if ((exprNode instanceof ASTAssignmentExpression)
  96. && (exprNode.jjtGetNumChildren() > 0)) {
  97. SimpleNode lhsNode = (SimpleNode) exprNode.jjtGetChild(0);
  98. if (lhsNode instanceof ASTCompositeReference) {
  99. // determine if it is a global declaration
  100. String firstRefPart = null;
  101. SimpleNode cNode = (SimpleNode) lhsNode.jjtGetChild(0);
  102. if (cNode instanceof ASTIdentifier) {
  103. firstRefPart = ((ASTIdentifier) cNode).getName();
  104. }
  105. if ((firstRefPart != null) && (!isLocal(firstRefPart))) {
  106. String compositeName = ((ASTCompositeReference) lhsNode)
  107. .getCompositeName();
  108. if (compositeName != null) {
  109. declarations.add(compositeName);
  110. if (declarationNodes != null) {
  111. declarationNodes.add(exprNode);
  112. }
  113. }
  114. }
  115. } else if (lhsNode instanceof ASTIdentifier) {
  116. String lhsName = ((ASTIdentifier) lhsNode).getName();
  117. if ((lhsName != null) && (!isLocal(lhsName))) {
  118. // PENDING(uwe): I cannot really have this as a global
  119. // declaration
  120. // because I cannot distinguish between an actual
  121. // declaration
  122. // and an assignment
  123. // i.e. location = foo;
  124. // in this case it's window.location which would be bad
  125. // if I consider it
  126. // a declaration (that is something we own and is a
  127. // potential target for janitor/jabber)
  128. // so I look for the @constructor tag in comment
  129. // associated with this assignment
  130. // if it exists it's one of ours
  131. Comment comment = node.getComment();
  132. if ((comment != null)
  133. && comment.containsTag("constructor")) {
  134. declarations.add(lhsName);
  135. if (declarationNodes != null) {
  136. declarationNodes.add(exprNode);
  137. }
  138. }
  139. }
  140. }
  141. }
  142. }
  143. return super.visit(node, data);
  144. }
  145. @Override
  146. public Object visit(ASTForVarStatement node, Object data) {
  147. HashMap forvarDeclarations = new HashMap();
  148. loopDeclarations.add(forvarDeclarations);
  149. pre(node, data);
  150. collectForvarDeclarations = true;
  151. data = node.jjtGetChild(0).jjtAccept(this, data);
  152. collectForvarDeclarations = false;
  153. // it's weird but in javascript loop variables are visible afterwards
  154. // outside the loop
  155. // so we dump them into the last local variables map
  156. if (localDeclarations.size() > 0) {
  157. Map functionDecls = (Map) localDeclarations.getLast();
  158. Iterator keyIter = forvarDeclarations.keySet().iterator();
  159. while (keyIter.hasNext()) {
  160. String name = (String) keyIter.next();
  161. if (!functionDecls.containsKey(name)) {
  162. functionDecls.put(name, name);
  163. }
  164. }
  165. }
  166. int n = node.jjtGetNumChildren();
  167. for (int i = 1; i < n; i++) {
  168. data = node.jjtGetChild(i).jjtAccept(this, data);
  169. }
  170. loopDeclarations.removeLast();
  171. post(node, data);
  172. return data;
  173. }
  174. @Override
  175. public Object visit(ASTForVarInStatement node, Object data) {
  176. HashMap forvarInDecls = new HashMap();
  177. String forVarInName = ((ASTIdentifier) node.jjtGetChild(0)).getName();
  178. forvarInDecls.put(forVarInName, forVarInName);
  179. // it's weird but in javascript loop variables are visible afterwards
  180. // outside the loop
  181. // so we dump them into the last local variables map
  182. if (localDeclarations.size() > 0) {
  183. Map functionDecls = (Map) localDeclarations.getLast();
  184. if (!functionDecls.containsKey(forVarInName)) {
  185. functionDecls.put(forVarInName, forVarInName);
  186. }
  187. }
  188. loopDeclarations.add(forvarInDecls);
  189. data = super.visit(node, data);
  190. loopDeclarations.removeLast();
  191. return data;
  192. }
  193. @Override
  194. public Object visit(ASTFunctionDeclaration node, Object data) {
  195. int index = 0;
  196. pre(node, data);
  197. if (node.jjtGetNumChildren() == 3) {
  198. SimpleNode firstChild = (SimpleNode) node.jjtGetChild(0);
  199. String name = null;
  200. if (firstChild instanceof ASTIdentifier) {
  201. name = ((ASTIdentifier) firstChild).getName();
  202. } else {
  203. name = ((ASTIdentifier) firstChild.jjtGetChild(1)).getName();
  204. }
  205. // if scope is global record it as a global declaration
  206. if (getScope() instanceof ASTProgram) {
  207. declarations.add(name);
  208. if (declarationNodes != null) {
  209. declarationNodes.add(node);
  210. }
  211. }
  212. // visit function name identifier
  213. data = node.jjtGetChild(0).jjtAccept(this, data);
  214. index = 1;
  215. }
  216. ASTFormalParameterList paramList = (ASTFormalParameterList) node
  217. .jjtGetChild(index);
  218. ASTBlock body = (ASTBlock) node.jjtGetChild(index + 1);
  219. HashMap functionVars = new HashMap();
  220. if (paramList.jjtGetNumChildren() > 0) {
  221. int n = paramList.jjtGetNumChildren();
  222. for (int i = 0; i < n; i++) {
  223. ASTIdentifier param = (ASTIdentifier) paramList.jjtGetChild(i);
  224. String paramName = param.getName();
  225. functionVars.put(paramName, paramName);
  226. }
  227. }
  228. localDeclarations.add(functionVars);
  229. data = body.jjtAccept(this, data);
  230. // here we decorate the function declaration node
  231. // with all the local variables visible to it
  232. node.setLocals(localDeclarations);
  233. localDeclarations.removeLast();
  234. post(node, data);
  235. return data;
  236. }
  237. public Object visit(ASTRequireStatement node, Object data) {
  238. return data;
  239. }
  240. }