1 19 20 package org.netbeans.modules.languages.javascript; 21 22 import java.util.HashMap ; 23 import java.util.LinkedList ; 24 import java.util.WeakHashMap ; 25 import javax.swing.text.Document ; 26 import org.netbeans.api.languages.ASTItem; 27 import org.netbeans.api.languages.ASTNode; 28 import org.netbeans.api.languages.SyntaxContext; 29 import org.netbeans.api.languages.ASTToken; 30 import java.util.ArrayList ; 31 import java.util.Iterator ; 32 import java.util.List ; 33 import java.util.Map ; 34 import org.netbeans.modules.editor.NbEditorUtilities; 35 import org.openide.filesystems.FileObject; 36 import org.openide.loaders.DataObject; 37 38 39 43 public class Semantic { 44 45 private static String [] BLOCK_NAMES = {"Block", "IfStatement", "SwitchStatement", "DoStatement", "WhileStatement", "ForStatement", "TryStatement"}; 49 private static Map docsToInfos = new WeakHashMap (); 51 public static synchronized void storeInfo(Document doc, Info info) { 52 docsToInfos.put(doc, info); 53 } 54 55 public static synchronized Info getInfo(Document doc) { 56 return (Info)docsToInfos.get(doc); 57 } 58 59 public static ASTNode process (SyntaxContext cookie) { 60 ASTNode node = (ASTNode) cookie.getASTPath ().getRoot (); 61 ASTContext context = new ASTContext(cookie.getDocument()); 62 Info info = new Info(); 63 64 preprocessTree(node, context, info); 65 processTree(node, context, info); 66 storeInfo(cookie.getDocument(), info); 67 68 return node; 69 } 70 71 private static void preprocessTree(ASTNode node, ASTContext context, Info info) { 72 for (Iterator iter = node.getChildren().iterator(); iter.hasNext();) { 73 Object obj = iter.next(); 74 if (!(obj instanceof ASTNode)) { 75 continue; 76 } 77 ASTNode n = (ASTNode)obj; 78 String nt = n.getNT(); 79 if ("FunctionDeclaration".equals(nt)) { ASTNode fnode = findNode(n, "FunctionName", 0); 81 if (fnode == null) { 82 continue; 83 } 84 ASTItem item = fnode.getChildren().get(0); 85 if (item instanceof ASTToken) { 86 String name = ((ASTToken)item).getIdentifier(); 87 Declaration decl = new Declaration(context.getFileObject(), context.getDocument(), item, 88 Declaration.METHOD); 89 context.addMethod(name, decl); 90 info.putItem(item, decl); 91 } 92 } else { 93 preprocessTree(n, context, info); 94 } 95 } } 97 98 private static void processTree(ASTNode node, ASTContext context, Info info) { 99 context.startBlock(); 100 for (Iterator iter = node.getChildren().iterator(); iter.hasNext();) { 101 Object obj = iter.next(); 102 if (!(obj instanceof ASTNode)) { 103 continue; 104 } 105 ASTNode n = (ASTNode)obj; 106 String nt = n.getNT(); 107 if ("FunctionDeclaration".equals(nt)) { processFunction(n, node, context, info); 109 } else { 110 processTree(n, context, info); 111 } 112 } context.endBlock(); 114 } 115 116 private static void processFunction(ASTNode node, ASTNode parent, ASTContext context, Info info) { 117 context.startBlock(); 118 ASTNode paramsNode = findNode(node, "FormalParameterList", 2); if (paramsNode != null) { 120 Iterator iter = paramsNode.getChildren().iterator(); 121 while (iter.hasNext()) { 122 ASTToken token = (ASTToken)iter.next(); 123 if ("js_identifier".equals(token.getType())) { 124 String paramName = token.getIdentifier(); 125 Declaration decl = new Declaration(context.getFileObject(), context.getDocument(), token, 126 Declaration.PARAMETER); 127 context.addParameter(paramName, decl); 128 info.putItem(token, decl); 129 } 130 } } 132 ASTNode body = findNode(node, "FunctionBody", 4); processStatements(body, node, context, info, false); 134 context.clearParameters(); 135 context.endBlock(); 136 } 137 138 private static void processStatements(ASTNode node, ASTNode parent, ASTContext context, Info info, boolean newBlock) { 139 if (newBlock) { 140 context.startBlock(); 141 } 142 for (Iterator iter = node.getChildren().iterator(); iter.hasNext();) { 143 Object obj = iter.next(); 144 if (obj instanceof ASTNode) { 145 ASTNode n = (ASTNode)obj; 146 String nt = n.getNT(); 147 if ("VariableDeclaration".equals(nt)) { Object child = n.getChildren().get(0); 149 if (child instanceof ASTToken) { 150 ASTToken id = (ASTToken)child; 151 Declaration localVarDecl = new Declaration(context.getFileObject(), context.getDocument(), id, 152 Declaration.LOCAL_VARIABLE); 153 info.putItem(id, localVarDecl); 154 context.putLocalVar(id.getIdentifier(), localVarDecl); 155 ASTNode initializer = findNode(n, "Initializer", 1); 156 if (initializer != null) { 157 processStatements(initializer, node, context, info, false); 158 } 159 } 160 } else { 161 boolean isBlock = false; 162 for (int x = 0; x < BLOCK_NAMES.length; x++) { 163 if (BLOCK_NAMES[x].equals(nt)) { 164 isBlock = true; 165 break; 166 } 167 } 168 processStatements(n, node, context, info, isBlock); 169 } 170 } else { 171 ASTToken token = (ASTToken)obj; 172 if ("js_identifier".equals(token.getType())) { if (!"MemberOperator".equals(parent.getNT())) { String id = token.getIdentifier(); 175 ASTItem brother = findBrother(parent, node); 176 Declaration decl = null; 177 if ((brother instanceof ASTNode) && "Arguments".equals(((ASTNode)brother).getNT())) { decl = context.getMethod(id); 179 } else { 180 decl = context.getDeclaration(id); 181 } 182 if (decl != null) { 183 Usage usage = new Usage(context.getFileObject(), context.getDocument(), token, decl); 184 decl.addUsage(usage); 185 info.putItem(token, decl); 186 } 187 } } } } if (newBlock) { 192 context.endBlock(); 193 } 194 } 195 196 private static ASTNode findNode(ASTNode node, String nt, int index) { 197 List children = node.getChildren(); 198 if (index > children.size()) { 199 return null; 200 } 201 for (Iterator iter = children.listIterator(index); iter.hasNext();) { 202 Object obj = iter.next(); 203 if ((obj instanceof ASTNode) && nt.equals(((ASTNode)obj).getNT())) { 204 return (ASTNode)obj; 205 } 206 } 207 return null; 208 } 209 210 private static ASTItem findBrother(ASTNode node, ASTItem item) { 211 List children = node.getChildren(); 212 for (Iterator iter = children.iterator(); iter.hasNext();) { 213 Object obj = iter.next(); 214 if (obj == item) { 215 return iter.hasNext() ? (ASTItem) iter.next() : null; 216 } 217 } 218 return null; 219 } 220 221 public static class Declaration { 222 223 public static final int PARAMETER = 0; 224 public static final int LOCAL_VARIABLE = 1; 225 public static final int METHOD = 2; 226 227 private ASTItem item; 228 private FileObject fileObject; 229 private Document doc; 230 private int kind; 231 private List usages = new ArrayList (); 232 233 Declaration(FileObject fileObj, Document doc, ASTItem item, int kind) { 234 this.fileObject = fileObj; 235 this.doc = doc; 236 this.item = item; 237 this.kind = kind; 238 } 239 240 public void addUsage(Usage usage) { 241 usages.add(usage); 242 } 243 244 public List getUsages() { 245 return usages; 246 } 247 248 public ASTItem getASTItem() { 249 return item; 250 } 251 252 public FileObject getFileObject() { 253 return fileObject; 254 } 255 256 public Document getDocument() { 257 return doc; 258 } 259 260 public int getKind() { 261 return kind; 262 } 263 264 } 265 266 public static class Usage { 267 private ASTItem item; 268 private FileObject fileObject; 269 private Document doc; 270 private Declaration declaration; 271 272 Usage(FileObject fileObj, Document doc, ASTItem item, Declaration decl) { 273 this.fileObject = fileObj; 274 this.item = item; 275 this.declaration = decl; 276 } 277 278 public Declaration getDeclaration() { 279 return declaration; 280 } 281 282 public ASTItem getASTItem() { 283 return item; 284 } 285 286 public FileObject getFileObject() { 287 return fileObject; 288 } 289 290 } 291 292 public static class Info { 293 private Map items = new HashMap (); 295 public void putItem(ASTItem item, Declaration decl) { 296 items.put(item, decl); 297 } 298 299 public Declaration getItem(ASTItem item) { 300 return (Declaration)items.get(item); 301 } 302 } 303 304 private static class ASTContext { 305 306 private FileObject fileObject; 307 private Document doc; 308 309 private Map parameters = new HashMap (); 310 private Map methods = new HashMap (); 311 private LinkedList localVarsStack = new LinkedList (); 312 private Map localVarsDecl; 313 314 public ASTContext(Document doc) { 315 this.doc = doc; 316 DataObject dobj = NbEditorUtilities.getDataObject(doc); 317 fileObject = dobj.getPrimaryFile(); 318 } 319 320 public void addParameter(String paramName, Declaration decl) { 321 parameters.put(paramName, decl); 322 } 323 324 public void addMethod(String methodName, Declaration decl) { 325 methods.put(methodName, decl); 326 } 327 328 332 public void clearParameters() { 333 parameters.clear(); 334 } 335 336 public void startBlock() { 337 localVarsDecl = new HashMap (); 338 localVarsStack.addFirst(localVarsDecl); 339 } 340 341 public void endBlock() { 342 localVarsStack.removeFirst(); 343 localVarsDecl = localVarsStack.isEmpty() ? null : (Map )localVarsStack.getFirst(); 344 } 345 346 public void putLocalVar(String varName, Declaration localVarDecl) { 347 localVarsDecl.put(varName, localVarDecl); 348 } 349 350 public Declaration getDeclaration(String name) { 351 for (Iterator iter = localVarsStack.iterator(); iter.hasNext(); ) { 352 Map map = (Map )iter.next(); 353 Declaration decl = (Declaration)map.get(name); 354 if (decl != null) { 355 return decl; 356 } 357 } 358 return (Declaration)parameters.get(name); 359 } 360 361 public Declaration getMethod(String name) { 362 return (Declaration)methods.get(name); 363 } 364 365 public FileObject getFileObject() { 366 return fileObject; 367 } 368 369 public Document getDocument() { 370 return doc; 371 } 372 } 373 374 } 375 | Popular Tags |