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