1 21 22 package org.armedbear.j; 23 24 import java.util.Stack ; 25 import java.util.ArrayList ; 26 27 public class JavaTagger extends Tagger implements Constants 28 { 29 private static final int NEUTRAL = 0; 31 private static final int INTERFACE_NAME = 1; 32 private static final int CLASS_NAME = 2; 33 private static final int CLASS_PROLOG = 3; private static final int EXTENDS = 4; 35 private static final int IMPLEMENTS = 5; 36 private static final int METHOD_NAME = 6; 37 private static final int METHOD_PROLOG = 7; 38 private static final int STATIC_INITIALIZER = 8; 39 private static final int NEW = 9; 40 private static final int FIELD_INITIALIZER = 10; 42 protected Position pos; 43 protected String token; 44 protected Position tokenStart; 45 46 private ArrayList tags; 47 private JavaClass currentClass; 48 private int visibility; 50 public JavaTagger(SystemBuffer buffer) 51 { 52 super(buffer); 53 } 54 55 public synchronized void run() 56 { 57 pos = new Position(buffer.getFirstLine(), 0); 58 token = null; 59 tokenStart = null; 60 tags = new ArrayList (); 61 currentClass = null; 62 visibility = 0; 63 final boolean beanShell = buffer.getModeId() == BEANSHELL_MODE; 64 final boolean javaScript = buffer.getModeId() == JAVASCRIPT_MODE; 65 final Stack stack = new Stack (); 66 int state = NEUTRAL; 67 while (!pos.atEnd()) { 68 char c = pos.getChar(); 69 if (Character.isWhitespace(c)) { 70 pos.skipWhitespace(); 71 continue; 72 } 73 if (c == '\'' || c == '"') { 74 pos.skipQuote(); 75 continue; 76 } 77 if (pos.lookingAt("/*")) { 78 skipComment(pos); 79 continue; 80 } 81 if (pos.lookingAt("//")) { 82 skipSingleLineComment(pos); 83 continue; 84 } 85 if (state == STATIC_INITIALIZER) { 86 if (c == '{') { 87 skipBrace(); 88 state = NEUTRAL; 89 continue; 90 } 91 state = NEUTRAL; 93 } 95 if (state == METHOD_NAME) { 96 if (c == '{') { 97 addTag(TAG_METHOD); 98 visibility = 0; 99 skipBrace(); 100 state = NEUTRAL; 101 continue; 102 } 103 if (c == ';') { 104 if (beanShell) { 105 ; } else { 107 addTag(TAG_METHOD); 109 visibility = 0; 110 } 111 state = NEUTRAL; 112 pos.next(); 113 continue; 114 } 115 if (pos.lookingAt("throws")) { 116 addTag(TAG_METHOD); 117 token = null; 119 visibility = 0; 120 state = METHOD_PROLOG; 121 pos.skip(6); continue; 123 } 124 state = NEUTRAL; 125 } 127 if (state == CLASS_PROLOG) { 128 if (pos.lookingAt("extends")) { 129 state = EXTENDS; 130 pos.skip(7); continue; 132 } 133 if (pos.lookingAt("implements")) { 134 state = IMPLEMENTS; 135 pos.skip(10); 136 continue; 137 } 138 if (c == '{') 139 state = NEUTRAL; 140 pos.next(); 141 continue; 142 } 143 if (state == IMPLEMENTS) { 144 if (c == '{') { 145 state = NEUTRAL; 146 pos.next(); 147 continue; 148 } 149 } 151 if (state == METHOD_PROLOG) { 152 if (c == '{') { 154 skipBrace(); 155 state = NEUTRAL; 156 } else if (c == ';') { 157 if (token != null) { 160 addTag(TAG_METHOD); 161 visibility = 0; 162 } 163 state = NEUTRAL; 164 pos.next(); 165 } else 166 pos.next(); 167 continue; 168 } 169 if (state == NEW) { 170 if (c == '(') { 171 skipParen(); 172 continue; 173 } else if (c == '{') { 174 skipBrace(); 175 continue; 176 } else if (c == ';') 177 state = NEUTRAL; 178 pos.next(); 179 continue; 180 } 181 if (state == FIELD_INITIALIZER) { 182 if (c == '(') { 183 skipParen(); 184 continue; 185 } 186 if (c == '{') { 187 skipBrace(); 188 if (javaScript) 189 state = NEUTRAL; 190 continue; 191 } 192 if (c == ',') 193 state = NEUTRAL; 194 else if (c == ';') { 195 state = NEUTRAL; 196 visibility = 0; 197 } 198 pos.next(); 199 continue; 200 } 201 if (state == IMPLEMENTS) { 202 if (c == ',') { 203 pos.next(); 204 continue; 205 } 206 } 207 if (c == '}') { 208 if (!stack.empty()) 209 currentClass = (JavaClass) stack.pop(); 210 else 211 currentClass = null; 212 pos.next(); 213 continue; 214 } 215 if (Character.isJavaIdentifierStart(c)) { 216 gatherToken(state == EXTENDS || state == IMPLEMENTS); 220 if (state == INTERFACE_NAME) { 221 if (currentClass != null) 222 stack.push(currentClass); 223 final JavaClass parentClass = currentClass; 224 currentClass = new JavaClass(token, TAG_INTERFACE); 225 state = CLASS_PROLOG; 226 tags.add(new JavaTag("interface ".concat(token), 228 tokenStart,TAG_INTERFACE, visibility, parentClass)); 229 visibility = 0; 230 } else if (state == CLASS_NAME) { 231 if (currentClass != null) 232 stack.push(currentClass); 233 final JavaClass parentClass = currentClass; 234 currentClass = new JavaClass(token, TAG_CLASS); 235 state = CLASS_PROLOG; 236 tags.add(new JavaTag("class ".concat(token), tokenStart, 238 TAG_CLASS, visibility, parentClass)); 239 visibility = 0; 240 } else if (state == EXTENDS) { 241 tags.add(new JavaTag(token, tokenStart, TAG_EXTENDS, 242 visibility, currentClass)); 243 state = CLASS_PROLOG; 244 } else if (state == IMPLEMENTS) 245 tags.add(new JavaTag(token, tokenStart, TAG_IMPLEMENTS, 246 visibility, currentClass)); 247 else if (token.equals("package") || token.equals("import")) 248 skipSemi(); 249 else if (token.equals("interface")) 250 state = INTERFACE_NAME; 251 else if (token.equals("class")) 252 state = CLASS_NAME; 253 else if (token.equals("static")) 254 state = STATIC_INITIALIZER; 255 else if (token.equals("new")) 256 state = NEW; 258 else if (token.equals("public")) 259 visibility |= TAG_PUBLIC; 260 else if (token.equals("protected")) 261 visibility |= TAG_PROTECTED; 262 else if (token.equals("private")) 263 visibility |= TAG_PRIVATE; 264 continue; 265 } 266 if (c == '(') { 267 skipParen(); 268 state = METHOD_NAME; 269 continue; 270 } 271 if (c == '=') { 272 addTag(TAG_FIELD); 273 state = FIELD_INITIALIZER; 274 pos.next(); 275 continue; 276 } 277 if (c == ';' || c == ',') { 279 if (token != null) 280 addTag(TAG_FIELD); 281 if (c == ';') 283 visibility = 0; 284 } 285 pos.next(); 286 } 287 buffer.setTags(tags); 288 } 289 290 private void addTag(int type) 291 { 292 if (currentClass != null) { 293 FastStringBuffer sb = new FastStringBuffer(currentClass.getName()); 294 sb.append('.'); 295 sb.append(token); 296 tags.add(new JavaTag(sb.toString(), tokenStart, type, visibility, currentClass)); 297 } else 298 tags.add(new JavaTag(token, tokenStart, type, visibility)); 299 } 300 301 protected static final void skipComment(Position pos) 302 { 303 while (true) { 304 if (pos.lookingAt("*/")) { 305 pos.skip(2); 306 return; 307 } 308 if (!pos.next()) 309 return; 310 } 311 } 312 313 protected final void skipSingleLineComment(Position pos) 314 { 315 checkForExplicitTag(pos); 316 Line next = pos.getNextLine(); 317 if (next != null) 318 pos.moveTo(next, 0); 319 else 320 pos.setOffset(pos.getLineLength()); 321 } 322 323 private final void checkForExplicitTag(Position pos) 324 { 325 if (tags == null) 326 return; final String explicitTag = 328 Editor.preferences().getStringProperty(Property.EXPLICIT_TAG); 329 if (explicitTag != null && explicitTag.length() > 0) { 330 pos = pos.copy(); 331 String s = pos.getString(); int index = s.indexOf(explicitTag); 333 if (index >= 0) { 334 pos.skip(index + explicitTag.length()); 335 pos.skipWhitespace(); 336 FastStringBuffer sb = new FastStringBuffer(); 338 char c = pos.getChar(); 339 if (c == '"') { 340 while (pos.next()) { 341 c = pos.getChar(); 342 if (c == '"') 343 break; 344 sb.append(c); 345 } 346 } else { 347 sb.append(c); 351 while (pos.next()) { 352 c = pos.getChar(); 353 if (Character.isWhitespace(c)) 354 break; 355 sb.append(c); 356 } 357 } 358 final String tag = sb.toString(); 359 pos.setOffset(0); 362 pos.skipWhitespace(); 363 tags.add(new JavaTag(tag, pos, TAG_EXPLICIT, 0, currentClass)); 364 } 365 } 366 } 367 368 private void gatherToken(boolean canonical) 371 { 372 tokenStart = new Position(pos); 373 FastStringBuffer sb = new FastStringBuffer(); 374 char c; 375 if (canonical) { 376 while (Character.isJavaIdentifierPart(c = pos.getChar()) || c == '.') { 377 sb.append(c); 378 if (!pos.next()) 379 break; 380 } 381 } else { 382 while (Character.isJavaIdentifierPart(c = pos.getChar())) { 383 sb.append(c); 384 if (!pos.next()) 385 break; 386 } 387 } 388 token = sb.toString(); 389 } 390 391 protected void skipParen() 392 { 393 if (pos.next()) { 394 int count = 1; 395 while (true) { 396 if (pos.lookingAt("/*")) { 397 skipComment(pos); 398 continue; 399 } 400 if (pos.lookingAt("//")) { 401 skipSingleLineComment(pos); 402 continue; 403 } 404 char c = pos.getChar(); 405 if (c == '"' || c == '\'') { 406 pos.skipQuote(); 407 continue; 408 } 409 if (c == '(') 410 ++count; 411 else if (c == ')') 412 --count; 413 if (!pos.next()) 414 break; 415 if (count == 0) 416 break; 417 } 418 } 419 } 420 421 protected void skipBrace() 422 { 423 if (pos.next()) { 424 int count = 1; 425 while (true) { 426 if (pos.lookingAt("/*")) { 427 skipComment(pos); 428 continue; 429 } 430 if (pos.lookingAt("//")) { 431 skipSingleLineComment(pos); 432 continue; 433 } 434 char c = pos.getChar(); 435 if (c == '"' || c == '\'') { 436 pos.skipQuote(); 437 continue; 438 } 439 if (c == '\\') { 440 if (!pos.next()) 442 break; 443 if (!pos.next()) 444 break; 445 continue; 446 } 447 if (c == '{') 448 ++count; 449 else if (c == '}') 450 --count; 451 if (!pos.next()) 452 break; 453 if (count == 0) 454 break; 455 } 456 } 457 } 458 459 private void skipSemi() 460 { 461 while (!pos.atEnd()) { 462 if (pos.lookingAt("/*")) { 463 skipComment(pos); 464 continue; 465 } 466 if (pos.lookingAt("//")) { 467 skipSingleLineComment(pos); 468 continue; 469 } 470 char c = pos.getChar(); 471 if (c == '"' || c == '\'') { 472 pos.skipQuote(); 473 continue; 474 } else if (c == ';') { 475 pos.next(); 476 break; 477 } else 478 pos.next(); 479 } 480 } 481 482 protected static final void skipPreprocessor(Position pos) 484 { 485 while (true) { 486 Line line = pos.getLine(); 487 Line nextLine = line.next(); 488 if (nextLine == null) { 489 pos.setOffset(line.length()); 490 return; 491 } 492 pos.moveTo(nextLine, 0); 493 if (line.length() == 0 || line.charAt(line.length()-1) != '\\') 494 return; 495 } 496 } 497 } 498 | Popular Tags |