1/* 2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package jdk.jshell; 27 28import com.sun.tools.javac.code.Source; 29import com.sun.tools.javac.parser.Scanner; 30import com.sun.tools.javac.parser.ScannerFactory; 31import com.sun.tools.javac.parser.Tokens.Token; 32import com.sun.tools.javac.parser.Tokens.TokenKind; 33import com.sun.tools.javac.util.Context; 34import com.sun.tools.javac.util.JCDiagnostic; 35import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; 36import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 37import com.sun.tools.javac.util.Log; 38import java.io.PrintWriter; 39import java.io.StringWriter; 40import java.util.ArrayDeque; 41import java.util.Deque; 42import java.util.EnumMap; 43import java.util.Iterator; 44import jdk.jshell.SourceCodeAnalysis.Completeness; 45import com.sun.source.tree.Tree; 46import static jdk.jshell.CompletenessAnalyzer.TK.*; 47import jdk.jshell.TaskFactory.ParseTask; 48import java.util.List; 49import java.util.function.Function; 50import java.util.function.Supplier; 51 52/** 53 * Low level scanner to determine completeness of input. 54 * @author Robert Field 55 */ 56class CompletenessAnalyzer { 57 58 private final ScannerFactory scannerFactory; 59 private final JShell proc; 60 61 private static Completeness error() { 62 return Completeness.UNKNOWN; // For breakpointing 63 } 64 65 static class CaInfo { 66 67 CaInfo(Completeness status, int unitEndPos) { 68 this.status = status; 69 this.unitEndPos = unitEndPos; 70 } 71 final int unitEndPos; 72 final Completeness status; 73 } 74 75 CompletenessAnalyzer(JShell proc) { 76 this.proc = proc; 77 Context context = new Context(); 78 Log log = CaLog.createLog(context); 79 context.put(Log.class, log); 80 context.put(Source.class, Source.JDK1_9); 81 scannerFactory = ScannerFactory.instance(context); 82 } 83 84 CaInfo scan(String s) { 85 try { 86 Parser parser = new Parser( 87 () -> new Matched(scannerFactory.newScanner(s, false)), 88 () -> proc.taskFactory.parse(s)); 89 Completeness stat = parser.parseUnit(); 90 int endPos = stat == Completeness.UNKNOWN 91 ? s.length() 92 : parser.endPos(); 93 return new CaInfo(stat, endPos); 94 } catch (SyntaxException ex) { 95 return new CaInfo(error(), s.length()); 96 } 97 } 98 99 @SuppressWarnings("serial") // serialVersionUID intentionally omitted 100 private static class SyntaxException extends RuntimeException { 101 } 102 103 private static void die() { 104 throw new SyntaxException(); 105 } 106 107 /** 108 * Subclass of Log used by compiler API to die on error and ignore 109 * other messages 110 */ 111 private static class CaLog extends Log { 112 113 private static CaLog createLog(Context context) { 114 PrintWriter pw = new PrintWriter(new StringWriter()); 115 CaLog log = new CaLog(context, pw); 116 context.put(logKey, log); 117 return log; 118 } 119 120 private CaLog(Context context, PrintWriter pw) { 121 super(context, pw); 122 } 123 124 @Override 125 public void error(String key, Object... args) { 126 die(); 127 } 128 129 @Override 130 public void error(DiagnosticPosition pos, String key, Object... args) { 131 die(); 132 } 133 134 @Override 135 public void error(DiagnosticFlag flag, DiagnosticPosition pos, String key, Object... args) { 136 die(); 137 } 138 139 @Override 140 public void error(int pos, String key, Object... args) { 141 die(); 142 } 143 144 @Override 145 public void error(DiagnosticFlag flag, int pos, String key, Object... args) { 146 die(); 147 } 148 149 @Override 150 public void report(JCDiagnostic diagnostic) { 151 // Ignore 152 } 153 } 154 155 // Location position kinds -- a token is ... 156 private static final int XEXPR = 0b1; // OK in expression (not first) 157 private static final int XDECL = 0b10; // OK in declaration (not first) 158 private static final int XSTMT = 0b100; // OK in statement framework (not first) 159 private static final int XEXPR1o = 0b1000; // OK first in expression 160 private static final int XDECL1o = 0b10000; // OK first in declaration 161 private static final int XSTMT1o = 0b100000; // OK first or only in statement framework 162 private static final int XEXPR1 = XEXPR1o | XEXPR; // OK in expression (anywhere) 163 private static final int XDECL1 = XDECL1o | XDECL; // OK in declaration (anywhere) 164 private static final int XSTMT1 = XSTMT1o | XSTMT; // OK in statement framework (anywhere) 165 private static final int XANY1 = XEXPR1o | XDECL1o | XSTMT1o; // Mask: first in statement, declaration, or expression 166 private static final int XTERM = 0b100000000; // Can terminate (last before EOF) 167 private static final int XSTART = 0b1000000000; // Boundary, must be XTERM before 168 private static final int XERRO = 0b10000000000; // Is an error 169 private static final int XBRACESNEEDED = 0b100000000000; // Expect {ANY} LBRACE 170 171 /** 172 * An extension of the compiler's TokenKind which adds our combined/processed 173 * kinds. Also associates each TK with a union of acceptable kinds of code 174 * position it can occupy. For example: IDENTIFER is XEXPR1|XDECL1|XTERM, 175 * meaning it can occur in expressions or declarations (but not in the 176 * framework of a statement and that can be the final (terminating) token 177 * in a snippet. 178 * <P> 179 * There must be a TK defined for each compiler TokenKind, an exception 180 * will 181 * be thrown if a TokenKind is defined and a corresponding TK is not. Add a 182 * new TK in the appropriate category. If it is like an existing category 183 * (e.g. a new modifier or type this may be all that is needed. If it 184 * is bracketing or modifies the acceptable positions of other tokens, 185 * please closely examine the needed changes to this scanner. 186 */ 187 static enum TK { 188 189 // Special 190 EOF(TokenKind.EOF, 0), // 191 ERROR(TokenKind.ERROR, XERRO), // 192 IDENTIFIER(TokenKind.IDENTIFIER, XEXPR1|XDECL1|XTERM), // 193 UNDERSCORE(TokenKind.UNDERSCORE, XERRO), // _ 194 CLASS(TokenKind.CLASS, XEXPR|XDECL1|XBRACESNEEDED), // class decl (MAPPED: DOTCLASS) 195 MONKEYS_AT(TokenKind.MONKEYS_AT, XEXPR|XDECL1), // @ 196 IMPORT(TokenKind.IMPORT, XDECL1|XSTART), // import -- consider declaration 197 SEMI(TokenKind.SEMI, XSTMT1|XTERM|XSTART), // ; 198 199 // Shouldn't see -- error 200 PACKAGE(TokenKind.PACKAGE, XERRO), // package 201 CONST(TokenKind.CONST, XERRO), // reserved keyword -- const 202 GOTO(TokenKind.GOTO, XERRO), // reserved keyword -- goto 203 CUSTOM(TokenKind.CUSTOM, XERRO), // No uses 204 205 // Declarations 206 ENUM(TokenKind.ENUM, XDECL1|XBRACESNEEDED), // enum 207 IMPLEMENTS(TokenKind.IMPLEMENTS, XDECL), // implements 208 INTERFACE(TokenKind.INTERFACE, XDECL1|XBRACESNEEDED), // interface 209 THROWS(TokenKind.THROWS, XDECL|XBRACESNEEDED), // throws 210 211 // Primarive type names 212 BOOLEAN(TokenKind.BOOLEAN, XEXPR1|XDECL1), // boolean 213 BYTE(TokenKind.BYTE, XEXPR1|XDECL1), // byte 214 CHAR(TokenKind.CHAR, XEXPR1|XDECL1), // char 215 DOUBLE(TokenKind.DOUBLE, XEXPR1|XDECL1), // double 216 FLOAT(TokenKind.FLOAT, XEXPR1|XDECL1), // float 217 INT(TokenKind.INT, XEXPR1|XDECL1), // int 218 LONG(TokenKind.LONG, XEXPR1|XDECL1), // long 219 SHORT(TokenKind.SHORT, XEXPR1|XDECL1), // short 220 VOID(TokenKind.VOID, XEXPR1|XDECL1), // void 221 222 // Modifiers keywords 223 ABSTRACT(TokenKind.ABSTRACT, XDECL1), // abstract 224 FINAL(TokenKind.FINAL, XDECL1), // final 225 NATIVE(TokenKind.NATIVE, XDECL1), // native 226 STATIC(TokenKind.STATIC, XDECL1), // static 227 STRICTFP(TokenKind.STRICTFP, XDECL1), // strictfp 228 PRIVATE(TokenKind.PRIVATE, XDECL1), // private 229 PROTECTED(TokenKind.PROTECTED, XDECL1), // protected 230 PUBLIC(TokenKind.PUBLIC, XDECL1), // public 231 TRANSIENT(TokenKind.TRANSIENT, XDECL1), // transient 232 VOLATILE(TokenKind.VOLATILE, XDECL1), // volatile 233 234 // Declarations and type parameters (thus expressions) 235 EXTENDS(TokenKind.EXTENDS, XEXPR|XDECL), // extends 236 COMMA(TokenKind.COMMA, XEXPR|XDECL), // , 237 AMP(TokenKind.AMP, XEXPR|XDECL), // & 238 GT(TokenKind.GT, XEXPR|XDECL), // > 239 LT(TokenKind.LT, XEXPR|XDECL1), // < 240 LTLT(TokenKind.LTLT, XEXPR|XDECL1), // << 241 GTGT(TokenKind.GTGT, XEXPR|XDECL), // >> 242 GTGTGT(TokenKind.GTGTGT, XEXPR|XDECL), // >>> 243 QUES(TokenKind.QUES, XEXPR|XDECL), // ? 244 DOT(TokenKind.DOT, XEXPR|XDECL), // . 245 STAR(TokenKind.STAR, XEXPR), // * (MAPPED: DOTSTAR) 246 247 // Statement keywords 248 ASSERT(TokenKind.ASSERT, XSTMT1|XSTART), // assert 249 BREAK(TokenKind.BREAK, XSTMT1|XTERM|XSTART), // break 250 CATCH(TokenKind.CATCH, XSTMT1|XSTART), // catch 251 CONTINUE(TokenKind.CONTINUE, XSTMT1|XTERM|XSTART), // continue 252 DO(TokenKind.DO, XSTMT1|XSTART), // do 253 ELSE(TokenKind.ELSE, XSTMT1|XTERM|XSTART), // else 254 FINALLY(TokenKind.FINALLY, XSTMT1|XSTART), // finally 255 FOR(TokenKind.FOR, XSTMT1|XSTART), // for 256 IF(TokenKind.IF, XSTMT1|XSTART), // if 257 RETURN(TokenKind.RETURN, XSTMT1|XTERM|XSTART), // return 258 SWITCH(TokenKind.SWITCH, XSTMT1|XSTART), // switch 259 SYNCHRONIZED(TokenKind.SYNCHRONIZED, XSTMT1|XDECL), // synchronized 260 THROW(TokenKind.THROW, XSTMT1|XSTART), // throw 261 TRY(TokenKind.TRY, XSTMT1|XSTART), // try 262 WHILE(TokenKind.WHILE, XSTMT1|XSTART), // while 263 264 // Statement keywords that we shouldn't see -- inside braces 265 CASE(TokenKind.CASE, XSTMT|XSTART), // case 266 DEFAULT(TokenKind.DEFAULT, XSTMT|XSTART), // default method, default case -- neither we should see 267 268 // Expressions (can terminate) 269 INTLITERAL(TokenKind.INTLITERAL, XEXPR1|XTERM), // 270 LONGLITERAL(TokenKind.LONGLITERAL, XEXPR1|XTERM), // 271 FLOATLITERAL(TokenKind.FLOATLITERAL, XEXPR1|XTERM), // 272 DOUBLELITERAL(TokenKind.DOUBLELITERAL, XEXPR1|XTERM), // 273 CHARLITERAL(TokenKind.CHARLITERAL, XEXPR1|XTERM), // 274 STRINGLITERAL(TokenKind.STRINGLITERAL, XEXPR1|XTERM), // 275 TRUE(TokenKind.TRUE, XEXPR1|XTERM), // true 276 FALSE(TokenKind.FALSE, XEXPR1|XTERM), // false 277 NULL(TokenKind.NULL, XEXPR1|XTERM), // null 278 THIS(TokenKind.THIS, XEXPR1|XTERM), // this -- shouldn't see 279 280 // Expressions maybe terminate //TODO handle these case separately 281 PLUSPLUS(TokenKind.PLUSPLUS, XEXPR1|XTERM), // ++ 282 SUBSUB(TokenKind.SUBSUB, XEXPR1|XTERM), // -- 283 284 // Expressions cannot terminate 285 INSTANCEOF(TokenKind.INSTANCEOF, XEXPR), // instanceof 286 NEW(TokenKind.NEW, XEXPR1), // new (MAPPED: COLCOLNEW) 287 SUPER(TokenKind.SUPER, XEXPR1|XDECL), // super -- shouldn't see as rec. But in type parameters 288 ARROW(TokenKind.ARROW, XEXPR), // -> 289 COLCOL(TokenKind.COLCOL, XEXPR), // :: 290 LPAREN(TokenKind.LPAREN, XEXPR), // ( 291 RPAREN(TokenKind.RPAREN, XEXPR), // ) 292 LBRACE(TokenKind.LBRACE, XEXPR), // { 293 RBRACE(TokenKind.RBRACE, XEXPR), // } 294 LBRACKET(TokenKind.LBRACKET, XEXPR), // [ 295 RBRACKET(TokenKind.RBRACKET, XEXPR), // ] 296 ELLIPSIS(TokenKind.ELLIPSIS, XEXPR), // ... 297 EQ(TokenKind.EQ, XEXPR), // = 298 BANG(TokenKind.BANG, XEXPR1), // ! 299 TILDE(TokenKind.TILDE, XEXPR1), // ~ 300 COLON(TokenKind.COLON, XEXPR|XTERM), // : 301 EQEQ(TokenKind.EQEQ, XEXPR), // == 302 LTEQ(TokenKind.LTEQ, XEXPR), // <= 303 GTEQ(TokenKind.GTEQ, XEXPR), // >= 304 BANGEQ(TokenKind.BANGEQ, XEXPR), // != 305 AMPAMP(TokenKind.AMPAMP, XEXPR), // && 306 BARBAR(TokenKind.BARBAR, XEXPR), // || 307 PLUS(TokenKind.PLUS, XEXPR1), // + 308 SUB(TokenKind.SUB, XEXPR1), // - 309 SLASH(TokenKind.SLASH, XEXPR), // / 310 BAR(TokenKind.BAR, XEXPR), // | 311 CARET(TokenKind.CARET, XEXPR), // ^ 312 PERCENT(TokenKind.PERCENT, XEXPR), // % 313 PLUSEQ(TokenKind.PLUSEQ, XEXPR), // += 314 SUBEQ(TokenKind.SUBEQ, XEXPR), // -= 315 STAREQ(TokenKind.STAREQ, XEXPR), // *= 316 SLASHEQ(TokenKind.SLASHEQ, XEXPR), // /= 317 AMPEQ(TokenKind.AMPEQ, XEXPR), // &= 318 BAREQ(TokenKind.BAREQ, XEXPR), // |= 319 CARETEQ(TokenKind.CARETEQ, XEXPR), // ^= 320 PERCENTEQ(TokenKind.PERCENTEQ, XEXPR), // %= 321 LTLTEQ(TokenKind.LTLTEQ, XEXPR), // <<= 322 GTGTEQ(TokenKind.GTGTEQ, XEXPR), // >>= 323 GTGTGTEQ(TokenKind.GTGTGTEQ, XEXPR), // >>>= 324 325 // combined/processed kinds 326 UNMATCHED(XERRO), 327 PARENS(XEXPR1|XDECL|XSTMT|XTERM), 328 BRACKETS(XEXPR|XDECL|XTERM), 329 BRACES(XSTMT1|XEXPR|XTERM), 330 DOTSTAR(XDECL|XTERM), // import foo.* 331 COLCOLNEW(XEXPR|XTERM), // :: new 332 DOTCLASS(XEXPR|XTERM), // class decl and .class 333 ; 334 335 static final EnumMap<TokenKind,TK> tokenKindToTKMap = new EnumMap<>(TokenKind.class); 336 337 final TokenKind tokenKind; 338 final int belongs; 339 Function<TK,TK> mapping; 340 341 TK(int b) { 342 this(null, b); 343 } 344 345 TK(TokenKind tokenKind, int b) { 346 this.tokenKind = tokenKind; 347 this.belongs = b; 348 this.mapping = null; 349 } 350 351 private static TK tokenKindToTK(TK prev, TokenKind kind) { 352 TK tk = tokenKindToTKMap.get(kind); 353 if (tk == null) { 354 System.err.printf("No corresponding %s for %s: %s\n", 355 TK.class.getCanonicalName(), 356 TokenKind.class.getCanonicalName(), 357 kind); 358 throw new InternalError("No corresponding TK for TokenKind: " + kind); 359 } 360 return tk.mapping != null 361 ? tk.mapping.apply(prev) 362 : tk; 363 } 364 365 boolean isOkToTerminate() { 366 return (belongs & XTERM) != 0; 367 } 368 369 boolean isExpression() { 370 return (belongs & XEXPR) != 0; 371 } 372 373 boolean isDeclaration() { 374 return (belongs & XDECL) != 0; 375 } 376 377 boolean isError() { 378 return (belongs & XERRO) != 0; 379 } 380 381 boolean isStart() { 382 return (belongs & XSTART) != 0; 383 } 384 385 boolean isBracesNeeded() { 386 return (belongs & XBRACESNEEDED) != 0; 387 } 388 389 /** 390 * After construction, check that all compiler TokenKind values have 391 * corresponding TK values. 392 */ 393 static { 394 for (TK tk : TK.values()) { 395 if (tk.tokenKind != null) { 396 tokenKindToTKMap.put(tk.tokenKind, tk); 397 } 398 } 399 for (TokenKind kind : TokenKind.values()) { 400 tokenKindToTK(null, kind); // assure they can be retrieved without error 401 } 402 // Mappings of disambiguated contexts 403 STAR.mapping = prev -> prev == DOT ? DOTSTAR : STAR; 404 NEW.mapping = prev -> prev == COLCOL ? COLCOLNEW : NEW; 405 CLASS.mapping = prev -> prev == DOT ? DOTCLASS : CLASS; 406 } 407 } 408 409 /** 410 * A completeness scanner token. 411 */ 412 private static class CT { 413 414 /** The token kind */ 415 public final TK kind; 416 417 /** The end position of this token */ 418 public final int endPos; 419 420 /** The error message **/ 421 public final String message; 422 423 private CT(TK tk, Token tok, String msg) { 424 this.kind = tk; 425 this.endPos = tok.endPos; 426 this.message = msg; 427 //throw new InternalError(msg); /* for debugging */ 428 } 429 430 private CT(TK tk, Token tok) { 431 this.kind = tk; 432 this.endPos = tok.endPos; 433 this.message = null; 434 } 435 436 private CT(TK tk, int endPos) { 437 this.kind = tk; 438 this.endPos = endPos; 439 this.message = null; 440 } 441 } 442 443 /** 444 * Look for matching tokens (like parens) and other special cases, like "new" 445 */ 446 private static class Matched implements Iterator<CT> { 447 448 private final Scanner scanner; 449 private Token current; 450 private CT prevCT; 451 private CT currentCT; 452 private final Deque<Token> stack = new ArrayDeque<>(); 453 454 Matched(Scanner scanner) { 455 this.scanner = scanner; 456 advance(); 457 prevCT = currentCT = new CT(SEMI, 0); // So is valid for testing 458 } 459 460 @Override 461 public boolean hasNext() { 462 return currentCT.kind != EOF; 463 } 464 465 private Token advance() { 466 Token prev = current; 467 scanner.nextToken(); 468 current = scanner.token(); 469 return prev; 470 } 471 472 @Override 473 public CT next() { 474 prevCT = currentCT; 475 currentCT = nextCT(); 476 return currentCT; 477 } 478 479 private CT match(TK tk, TokenKind open) { 480 Token tok = advance(); 481 db("match desired-tk=%s, open=%s, seen-tok=%s", tk, open, tok.kind); 482 if (stack.isEmpty()) { 483 return new CT(ERROR, tok, "Encountered '" + tok + "' with no opening '" + open + "'"); 484 } 485 Token p = stack.pop(); 486 if (p.kind != open) { 487 return new CT(ERROR, tok, "No match for '" + p + "' instead encountered '" + tok + "'"); 488 } 489 return new CT(tk, tok); 490 } 491 492 private void db(String format, Object ... args) { 493// System.err.printf(format, args); 494// System.err.printf(" -- stack("); 495// if (stack.isEmpty()) { 496// 497// } else { 498// for (Token tok : stack) { 499// System.err.printf("%s ", tok.kind); 500// } 501// } 502// System.err.printf(") current=%s / currentCT=%s\n", current.kind, currentCT.kind); 503 } 504 505 /** 506 * @return the next scanner token 507 */ 508 private CT nextCT() { 509 // TODO Annotations? 510 TK prevTK = currentCT.kind; 511 while (true) { 512 db("nextCT"); 513 CT ct; 514 switch (current.kind) { 515 case EOF: 516 db("eof"); 517 if (stack.isEmpty()) { 518 ct = new CT(EOF, current); 519 } else { 520 TokenKind unmatched = stack.pop().kind; 521 stack.clear(); // So we will get EOF next time 522 ct = new CT(UNMATCHED, current, "Unmatched " + unmatched); 523 } 524 break; 525 case LPAREN: 526 case LBRACE: 527 case LBRACKET: 528 stack.push(advance()); 529 prevTK = SEMI; // new start 530 continue; 531 case RPAREN: 532 ct = match(PARENS, TokenKind.LPAREN); 533 break; 534 case RBRACE: 535 ct = match(BRACES, TokenKind.LBRACE); 536 break; 537 case RBRACKET: 538 ct = match(BRACKETS, TokenKind.LBRACKET); 539 break; 540 default: 541 ct = new CT(TK.tokenKindToTK(prevTK, current.kind), advance()); 542 break; 543 } 544 // Detect an error if we are at starting position and the last 545 // token wasn't a terminating one. Special case: within braces, 546 // comma can proceed semicolon, e.g. the values list in enum 547 if (ct.kind.isStart() && !prevTK.isOkToTerminate() && prevTK != COMMA) { 548 return new CT(ERROR, current, "No '" + prevTK + "' before '" + ct.kind + "'"); 549 } 550 if (stack.isEmpty() || ct.kind.isError()) { 551 return ct; 552 } 553 prevTK = ct.kind; 554 } 555 } 556 } 557 558 /** 559 * Fuzzy parser based on token kinds 560 */ 561 private static class Parser { 562 563 private final Supplier<Matched> matchedFactory; 564 private final Supplier<ParseTask> parseFactory; 565 private Matched in; 566 private CT token; 567 private Completeness checkResult; 568 569 Parser(Supplier<Matched> matchedFactory, Supplier<ParseTask> parseFactory) { 570 this.matchedFactory = matchedFactory; 571 this.parseFactory = parseFactory; 572 resetInput(); 573 } 574 575 final void resetInput() { 576 this.in = matchedFactory.get(); 577 nextToken(); 578 } 579 580 final void nextToken() { 581 in.next(); 582 token = in.currentCT; 583 } 584 585 boolean shouldAbort(TK tk) { 586 if (token.kind == tk) { 587 nextToken(); 588 return false; 589 } 590 switch (token.kind) { 591 case EOF: 592 checkResult = ((tk == SEMI) && in.prevCT.kind.isOkToTerminate()) 593 ? Completeness.COMPLETE_WITH_SEMI 594 : Completeness.DEFINITELY_INCOMPLETE; 595 return true; 596 case UNMATCHED: 597 checkResult = Completeness.DEFINITELY_INCOMPLETE; 598 return true; 599 default: 600 checkResult = error(); 601 return true; 602 603 } 604 } 605 606 Completeness lastly(TK tk) { 607 if (shouldAbort(tk)) return checkResult; 608 return Completeness.COMPLETE; 609 } 610 611 Completeness optionalFinalSemi() { 612 if (!shouldAbort(SEMI)) return Completeness.COMPLETE; 613 if (checkResult == Completeness.COMPLETE_WITH_SEMI) return Completeness.COMPLETE; 614 return checkResult; 615 } 616 617 boolean shouldAbort(Completeness flags) { 618 checkResult = flags; 619 return flags != Completeness.COMPLETE; 620 } 621 622 public int endPos() { 623 return in.prevCT.endPos; 624 } 625 626 public Completeness parseUnit() { 627 //System.err.printf("%s: belongs %o XANY1 %o\n", token.kind, token.kind.belongs, token.kind.belongs & XANY1); 628 switch (token.kind.belongs & XANY1) { 629 case XEXPR1o: 630 return parseExpressionOptionalSemi(); 631 case XSTMT1o: { 632 Completeness stat = parseSimpleStatement(); 633 return stat==null? error() : stat; 634 } 635 case XDECL1o: 636 return parseDeclaration(); 637 case XSTMT1o | XDECL1o: 638 case XEXPR1o | XDECL1o: 639 return disambiguateDeclarationVsExpression(); 640 case 0: 641 if ((token.kind.belongs & XERRO) != 0) { 642 return parseExpressionStatement(); // Let this gen the status 643 } 644 return error(); 645 default: 646 throw new InternalError("Case not covered " + token.kind.belongs + " in " + token.kind); 647 } 648 } 649 650 public Completeness parseDeclaration() { 651 boolean isImport = token.kind == IMPORT; 652 boolean isBracesNeeded = false; 653 while (token.kind.isDeclaration()) { 654 isBracesNeeded |= token.kind.isBracesNeeded(); 655 nextToken(); 656 } 657 switch (token.kind) { 658 case EQ: 659 nextToken(); 660 return parseExpressionStatement(); 661 case BRACES: 662 case SEMI: 663 nextToken(); 664 return Completeness.COMPLETE; 665 case UNMATCHED: 666 nextToken(); 667 return Completeness.DEFINITELY_INCOMPLETE; 668 case EOF: 669 switch (in.prevCT.kind) { 670 case BRACES: 671 case SEMI: 672 return Completeness.COMPLETE; 673 case IDENTIFIER: 674 return isBracesNeeded 675 ? Completeness.DEFINITELY_INCOMPLETE 676 : Completeness.COMPLETE_WITH_SEMI; 677 case BRACKETS: 678 return Completeness.COMPLETE_WITH_SEMI; 679 case DOTSTAR: 680 if (isImport) { 681 return Completeness.COMPLETE_WITH_SEMI; 682 } else { 683 return Completeness.UNKNOWN; 684 } 685 default: 686 return Completeness.DEFINITELY_INCOMPLETE; 687 } 688 default: 689 return error(); 690 } 691 } 692 693 public Completeness disambiguateDeclarationVsExpression() { 694 // String folding messes up position information. 695 ParseTask pt = parseFactory.get(); 696 List<? extends Tree> units = pt.units(); 697 if (units.isEmpty()) { 698 return error(); 699 } 700 Tree unitTree = units.get(0); 701 switch (unitTree.getKind()) { 702 case EXPRESSION_STATEMENT: 703 return parseExpressionOptionalSemi(); 704 case LABELED_STATEMENT: 705 if (shouldAbort(IDENTIFIER)) return checkResult; 706 if (shouldAbort(COLON)) return checkResult; 707 return parseStatement(); 708 case VARIABLE: 709 case IMPORT: 710 case CLASS: 711 case ENUM: 712 case ANNOTATION_TYPE: 713 case INTERFACE: 714 case METHOD: 715 return parseDeclaration(); 716 default: 717 return error(); 718 } 719 } 720 721 public Completeness parseExpressionStatement() { 722 if (shouldAbort(parseExpression())) return checkResult; 723 return lastly(SEMI); 724 } 725 726 public Completeness parseExpressionOptionalSemi() { 727 if (shouldAbort(parseExpression())) return checkResult; 728 return optionalFinalSemi(); 729 } 730 731 public Completeness parseExpression() { 732 while (token.kind.isExpression()) 733 nextToken(); 734 return Completeness.COMPLETE; 735 } 736 737 public Completeness parseStatement() { 738 Completeness stat = parseSimpleStatement(); 739 if (stat == null) { 740 return parseExpressionStatement(); 741 } 742 return stat; 743 } 744 745 /** 746 * Statement = Block | IF ParExpression Statement [ELSE Statement] | FOR 747 * "(" ForInitOpt ";" [Expression] ";" ForUpdateOpt ")" Statement | FOR 748 * "(" FormalParameter : Expression ")" Statement | WHILE ParExpression 749 * Statement | DO Statement WHILE ParExpression ";" | TRY Block ( 750 * Catches | [Catches] FinallyPart ) | TRY "(" ResourceSpecification 751 * ";"opt ")" Block [Catches] [FinallyPart] | SWITCH ParExpression "{" 752 * SwitchBlockStatementGroups "}" | SYNCHRONIZED ParExpression Block | 753 * RETURN [Expression] ";" | THROW Expression ";" | BREAK [Ident] ";" | 754 * CONTINUE [Ident] ";" | ASSERT Expression [ ":" Expression ] ";" | ";" 755 */ 756 public Completeness parseSimpleStatement() { 757 switch (token.kind) { 758 case BRACES: 759 return lastly(BRACES); 760 case IF: { 761 nextToken(); 762 if (shouldAbort(PARENS)) return checkResult; 763 Completeness thenpart = parseStatement(); 764 if (shouldAbort(thenpart)) return thenpart; 765 if (token.kind == ELSE) { 766 nextToken(); 767 return parseStatement(); 768 } 769 return thenpart; 770 771 } 772 case FOR: { 773 nextToken(); 774 if (shouldAbort(PARENS)) return checkResult; 775 if (shouldAbort(parseStatement())) return checkResult; 776 return Completeness.COMPLETE; 777 } 778 case WHILE: { 779 nextToken(); 780 if (shouldAbort(PARENS)) return error(); 781 return parseStatement(); 782 } 783 case DO: { 784 nextToken(); 785 switch (parseStatement()) { 786 case DEFINITELY_INCOMPLETE: 787 case CONSIDERED_INCOMPLETE: 788 case COMPLETE_WITH_SEMI: 789 return Completeness.DEFINITELY_INCOMPLETE; 790 case UNKNOWN: 791 return error(); 792 case COMPLETE: 793 break; 794 } 795 if (shouldAbort(WHILE)) return checkResult; 796 if (shouldAbort(PARENS)) return checkResult; 797 return lastly(SEMI); 798 } 799 case TRY: { 800 boolean hasResources = false; 801 nextToken(); 802 if (token.kind == PARENS) { 803 nextToken(); 804 hasResources = true; 805 } 806 if (shouldAbort(BRACES)) return checkResult; 807 if (token.kind == CATCH || token.kind == FINALLY) { 808 while (token.kind == CATCH) { 809 if (shouldAbort(CATCH)) return checkResult; 810 if (shouldAbort(PARENS)) return checkResult; 811 if (shouldAbort(BRACES)) return checkResult; 812 } 813 if (token.kind == FINALLY) { 814 if (shouldAbort(FINALLY)) return checkResult; 815 if (shouldAbort(BRACES)) return checkResult; 816 } 817 } else if (!hasResources) { 818 if (token.kind == EOF) { 819 return Completeness.DEFINITELY_INCOMPLETE; 820 } else { 821 return error(); 822 } 823 } 824 return Completeness.COMPLETE; 825 } 826 case SWITCH: { 827 nextToken(); 828 if (shouldAbort(PARENS)) return checkResult; 829 return lastly(BRACES); 830 } 831 case SYNCHRONIZED: { 832 nextToken(); 833 if (shouldAbort(PARENS)) return checkResult; 834 return lastly(BRACES); 835 } 836 case THROW: { 837 nextToken(); 838 if (shouldAbort(parseExpression())) return checkResult; 839 return lastly(SEMI); 840 } 841 case SEMI: 842 return lastly(SEMI); 843 case ASSERT: 844 nextToken(); 845 // Crude expression parsing just happily eats the optional colon 846 return parseExpressionStatement(); 847 case RETURN: 848 case BREAK: 849 case CONTINUE: 850 nextToken(); 851 return parseExpressionStatement(); 852 // What are these doing here? 853 case ELSE: 854 case FINALLY: 855 case CATCH: 856 return error(); 857 case EOF: 858 return Completeness.CONSIDERED_INCOMPLETE; 859 default: 860 return null; 861 } 862 } 863 } 864} 865