--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java Thu Sep 01 21:25:33 2016 +0200
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java Thu Sep 01 13:21:52 2016 -0700
@@ -46,6 +46,8 @@
import static jdk.jshell.CompletenessAnalyzer.TK.*;
import jdk.jshell.TaskFactory.ParseTask;
import java.util.List;
+import java.util.function.Function;
+import java.util.function.Supplier;
/**
* Low level scanner to determine completeness of input.
@@ -81,13 +83,13 @@
CaInfo scan(String s) {
try {
- Scanner scanner = scannerFactory.newScanner(s, false);
- Matched in = new Matched(scanner);
- Parser parser = new Parser(in, proc, s);
+ Parser parser = new Parser(
+ () -> new Matched(scannerFactory.newScanner(s, false)),
+ () -> proc.taskFactory.new ParseTask(s));
Completeness stat = parser.parseUnit();
int endPos = stat == Completeness.UNKNOWN
? s.length()
- : in.prevCT.endPos;
+ : parser.endPos();
return new CaInfo(stat, endPos);
} catch (SyntaxException ex) {
return new CaInfo(error(), s.length());
@@ -188,7 +190,7 @@
ERROR(TokenKind.ERROR, XERRO), //
IDENTIFIER(TokenKind.IDENTIFIER, XEXPR1|XDECL1|XTERM), //
UNDERSCORE(TokenKind.UNDERSCORE, XERRO), // _
- CLASS(TokenKind.CLASS, XEXPR|XDECL1|XTERM), // class decl and .class
+ CLASS(TokenKind.CLASS, XEXPR|XDECL1), // class decl (MAPPED: DOTCLASS)
MONKEYS_AT(TokenKind.MONKEYS_AT, XEXPR|XDECL1), // @
IMPORT(TokenKind.IMPORT, XDECL1|XSTART), // import -- consider declaration
SEMI(TokenKind.SEMI, XSTMT1|XTERM|XSTART), // ;
@@ -206,15 +208,15 @@
THROWS(TokenKind.THROWS, XDECL), // throws
// Primarive type names
- BOOLEAN(TokenKind.BOOLEAN, XEXPR|XDECL1), // boolean
- BYTE(TokenKind.BYTE, XEXPR|XDECL1), // byte
- CHAR(TokenKind.CHAR, XEXPR|XDECL1), // char
- DOUBLE(TokenKind.DOUBLE, XEXPR|XDECL1), // double
- FLOAT(TokenKind.FLOAT, XEXPR|XDECL1), // float
- INT(TokenKind.INT, XEXPR|XDECL1), // int
- LONG(TokenKind.LONG, XEXPR|XDECL1), // long
- SHORT(TokenKind.SHORT, XEXPR|XDECL1), // short
- VOID(TokenKind.VOID, XEXPR|XDECL1), // void
+ BOOLEAN(TokenKind.BOOLEAN, XEXPR1|XDECL1), // boolean
+ BYTE(TokenKind.BYTE, XEXPR1|XDECL1), // byte
+ CHAR(TokenKind.CHAR, XEXPR1|XDECL1), // char
+ DOUBLE(TokenKind.DOUBLE, XEXPR1|XDECL1), // double
+ FLOAT(TokenKind.FLOAT, XEXPR1|XDECL1), // float
+ INT(TokenKind.INT, XEXPR1|XDECL1), // int
+ LONG(TokenKind.LONG, XEXPR1|XDECL1), // long
+ SHORT(TokenKind.SHORT, XEXPR1|XDECL1), // short
+ VOID(TokenKind.VOID, XEXPR1|XDECL1), // void
// Modifiers keywords
ABSTRACT(TokenKind.ABSTRACT, XDECL1), // abstract
@@ -230,7 +232,7 @@
// Declarations and type parameters (thus expressions)
EXTENDS(TokenKind.EXTENDS, XEXPR|XDECL), // extends
- COMMA(TokenKind.COMMA, XEXPR|XDECL), // ,
+ COMMA(TokenKind.COMMA, XEXPR|XDECL|XTERM), // ,
AMP(TokenKind.AMP, XEXPR|XDECL), // &
GT(TokenKind.GT, XEXPR|XDECL), // >
LT(TokenKind.LT, XEXPR|XDECL1), // <
@@ -239,7 +241,7 @@
GTGTGT(TokenKind.GTGTGT, XEXPR|XDECL), // >>>
QUES(TokenKind.QUES, XEXPR|XDECL), // ?
DOT(TokenKind.DOT, XEXPR|XDECL), // .
- STAR(TokenKind.STAR, XEXPR|XDECL|XTERM), // * -- import foo.* //TODO handle these case separately, XTERM
+ STAR(TokenKind.STAR, XEXPR), // * (MAPPED: DOTSTAR)
// Statement keywords
ASSERT(TokenKind.ASSERT, XSTMT1|XSTART), // assert
@@ -280,7 +282,7 @@
// Expressions cannot terminate
INSTANCEOF(TokenKind.INSTANCEOF, XEXPR), // instanceof
- NEW(TokenKind.NEW, XEXPR1), // new
+ NEW(TokenKind.NEW, XEXPR1), // new (MAPPED: COLCOLNEW)
SUPER(TokenKind.SUPER, XEXPR1|XDECL), // super -- shouldn't see as rec. But in type parameters
ARROW(TokenKind.ARROW, XEXPR), // ->
COLCOL(TokenKind.COLCOL, XEXPR), // ::
@@ -323,24 +325,29 @@
UNMATCHED(XERRO),
PARENS(XEXPR1|XDECL|XSTMT|XTERM),
BRACKETS(XEXPR|XDECL|XTERM),
- BRACES(XSTMT1|XEXPR|XTERM);
+ BRACES(XSTMT1|XEXPR|XTERM),
+ DOTSTAR(XDECL|XTERM), // import foo.*
+ COLCOLNEW(XEXPR|XTERM), // :: new
+ DOTCLASS(XEXPR|XTERM), // class decl and .class
+ ;
static final EnumMap<TokenKind,TK> tokenKindToTKMap = new EnumMap<>(TokenKind.class);
final TokenKind tokenKind;
final int belongs;
+ Function<TK,TK> mapping;
TK(int b) {
- this.tokenKind = null;
- this.belongs = b;
+ this(null, b);
}
TK(TokenKind tokenKind, int b) {
this.tokenKind = tokenKind;
this.belongs = b;
+ this.mapping = null;
}
- private static TK tokenKindToTK(TokenKind kind) {
+ private static TK tokenKindToTK(TK prev, TokenKind kind) {
TK tk = tokenKindToTKMap.get(kind);
if (tk == null) {
System.err.printf("No corresponding %s for %s: %s\n",
@@ -349,7 +356,9 @@
kind);
throw new InternalError("No corresponding TK for TokenKind: " + kind);
}
- return tk;
+ return tk.mapping != null
+ ? tk.mapping.apply(prev)
+ : tk;
}
boolean isOkToTerminate() {
@@ -383,8 +392,12 @@
}
}
for (TokenKind kind : TokenKind.values()) {
- tokenKindToTK(kind); // assure they can be retrieved without error
+ tokenKindToTK(null, kind); // assure they can be retrieved without error
}
+ // Mappings of disambiguated contexts
+ STAR.mapping = prev -> prev == DOT ? DOTSTAR : STAR;
+ NEW.mapping = prev -> prev == COLCOL ? COLCOLNEW : NEW;
+ CLASS.mapping = prev -> prev == DOT ? DOTCLASS : CLASS;
}
}
@@ -520,7 +533,7 @@
ct = match(BRACKETS, TokenKind.LBRACKET);
break;
default:
- ct = new CT(TK.tokenKindToTK(current.kind), advance());
+ ct = new CT(TK.tokenKindToTK(prevTK, current.kind), advance());
break;
}
if (ct.kind.isStart() && !prevTK.isOkToTerminate()) {
@@ -539,21 +552,21 @@
*/
private static class Parser {
- final Matched in;
- CT token;
- Completeness checkResult;
-
- final JShell proc;
- final String scannedInput;
-
+ private final Supplier<Matched> matchedFactory;
+ private final Supplier<ParseTask> parseFactory;
+ private Matched in;
+ private CT token;
+ private Completeness checkResult;
+ Parser(Supplier<Matched> matchedFactory, Supplier<ParseTask> parseFactory) {
+ this.matchedFactory = matchedFactory;
+ this.parseFactory = parseFactory;
+ resetInput();
+ }
- Parser(Matched in, JShell proc, String scannedInput) {
- this.in = in;
+ final void resetInput() {
+ this.in = matchedFactory.get();
nextToken();
-
- this.proc = proc;
- this.scannedInput = scannedInput;
}
final void nextToken() {
@@ -598,6 +611,10 @@
return flags != Completeness.COMPLETE;
}
+ public int endPos() {
+ return in.prevCT.endPos;
+ }
+
public Completeness parseUnit() {
//System.err.printf("%s: belongs %o XANY1 %o\n", token.kind, token.kind.belongs, token.kind.belongs & XANY1);
switch (token.kind.belongs & XANY1) {
@@ -651,11 +668,11 @@
case IDENTIFIER:
case BRACKETS:
return Completeness.COMPLETE_WITH_SEMI;
- case STAR:
+ case DOTSTAR:
if (isImport) {
return Completeness.COMPLETE_WITH_SEMI;
} else {
- return Completeness.DEFINITELY_INCOMPLETE;
+ return Completeness.UNKNOWN;
}
default:
return Completeness.DEFINITELY_INCOMPLETE;
@@ -667,7 +684,7 @@
public Completeness disambiguateDeclarationVsExpression() {
// String folding messes up position information.
- ParseTask pt = proc.taskFactory.new ParseTask(scannedInput);
+ ParseTask pt = parseFactory.get();
List<? extends Tree> units = pt.units();
if (units.isEmpty()) {
return error();
@@ -679,7 +696,7 @@
case LABELED_STATEMENT:
if (shouldAbort(IDENTIFIER)) return checkResult;
if (shouldAbort(COLON)) return checkResult;
- return parseStatement();
+ return parseStatement();
case VARIABLE:
case IMPORT:
case CLASS:
@@ -693,51 +710,6 @@
}
}
-// public Status parseExpressionOrDeclaration() {
-// if (token.kind == IDENTIFIER) {
-// nextToken();
-// switch (token.kind) {
-// case IDENTIFIER:
-// return parseDeclaration();
-// }
-// }
-// while (token.kind.isExpressionOrDeclaration()) {
-// if (!token.kind.isExpression()) {
-// return parseDeclaration();
-// }
-// if (!token.kind.isDeclaration()) {
-// // Expression not declaration
-// if (token.kind == EQ) {
-// // Check for array initializer
-// nextToken();
-// if (token.kind == BRACES) {
-// nextToken();
-// return lastly(SEMI);
-// }
-// }
-// return parseExpressionStatement();
-// }
-// nextToken();
-// }
-// switch (token.kind) {
-// case BRACES:
-// case SEMI:
-// nextToken();
-// return Status.COMPLETE;
-// case UNMATCHED:
-// nextToken();
-// return Status.DEFINITELY_INCOMPLETE;
-// case EOF:
-// if (in.prevCT.kind.isOkToTerminate()) {
-// return Status.COMPLETE_WITH_SEMI;
-// } else {
-// return Status.DEFINITELY_INCOMPLETE;
-// }
-// default:
-// return error();
-// }
-// }
-
public Completeness parseExpressionStatement() {
if (shouldAbort(parseExpression())) return checkResult;
return lastly(SEMI);
--- a/langtools/test/jdk/jshell/CompletenessTest.java Thu Sep 01 21:25:33 2016 +0200
+++ b/langtools/test/jdk/jshell/CompletenessTest.java Thu Sep 01 13:21:52 2016 -0700
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8149524 8131024
+ * @bug 8149524 8131024 8165211 8080071 8130454
* @summary Test SourceCodeAnalysis
* @build KullaTesting TestingInputStream
* @run testng CompletenessTest
@@ -63,6 +63,7 @@
"foo: while (true) { printf(\"Innn\"); break foo; }",
"class Case<E1 extends Enum<E1>, E2 extends Enum<E2>, E3 extends Enum<E3>> {}",
";",
+ "enum Tt { FOO, BAR, BAZ,; }"
};
static final String[] expression = new String[] {
@@ -77,6 +78,8 @@
"new int[] {1, 2,3}",
"new Foo() {}",
"i >= 0 && Character.isWhitespace(s.charAt(i))",
+ "int.class",
+ "String.class",
};
static final String[] complete_with_semi = new String[] {
@@ -113,6 +116,7 @@
"BufferedReader br = new BufferedReader(new FileReader(path))",
"bar: g()",
"baz: while (true) if (t()) printf('-'); else break baz",
+ "java.util.function.IntFunction<int[]> ggg = int[]::new",
};
static final String[] considered_incomplete = new String[] {
@@ -141,6 +145,8 @@
"if (match.kind == BRACES && (prevCT.kind == ARROW || prevCT.kind == NEW_MIDDLE)) {",
"if (match.kind == BRACES && (prevCT.kind == ARROW || prevCT.kind == NEW_MIDDLE)) { new CT(UNMATCHED, current, \"Unmatched \" + unmatched);",
"x +",
+ "x *",
+ "3 *",
"int",
"for (int i = 0; i < lines.length(); ++i) {",
"new",
@@ -156,6 +162,7 @@
"enum TK { EOF(TokenKind.EOF, 0),",
"enum TK { EOF(TokenKind.EOF, 0), NEW_MIDDLE(XEXPR1|XTERM)",
"enum TK { EOF(TokenKind.EOF, 0), NEW_MIDDLE(XEXPR1|XTERM); ",
+ "enum Tt { FOO, BAR, BAZ,;"
};
static final String[] unknown = new String[] {