mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-23 12:34:32 +02:00
8210923: JShell: support for switch expressions
Reviewed-by: jlahoda
This commit is contained in:
parent
b3c1e4f663
commit
749916b897
4 changed files with 119 additions and 35 deletions
|
@ -228,15 +228,15 @@ class CompletenessAnalyzer {
|
||||||
// Declarations and type parameters (thus expressions)
|
// Declarations and type parameters (thus expressions)
|
||||||
EXTENDS(TokenKind.EXTENDS, XEXPR|XDECL), // extends
|
EXTENDS(TokenKind.EXTENDS, XEXPR|XDECL), // extends
|
||||||
COMMA(TokenKind.COMMA, XEXPR|XDECL), // ,
|
COMMA(TokenKind.COMMA, XEXPR|XDECL), // ,
|
||||||
AMP(TokenKind.AMP, XEXPR|XDECL), // &
|
AMP(TokenKind.AMP, XEXPR|XDECL, true), // &
|
||||||
GT(TokenKind.GT, XEXPR|XDECL), // >
|
GT(TokenKind.GT, XEXPR|XDECL, true), // >
|
||||||
LT(TokenKind.LT, XEXPR|XDECL1), // <
|
LT(TokenKind.LT, XEXPR|XDECL1, true), // <
|
||||||
LTLT(TokenKind.LTLT, XEXPR|XDECL1), // <<
|
LTLT(TokenKind.LTLT, XEXPR|XDECL1, true), // <<
|
||||||
GTGT(TokenKind.GTGT, XEXPR|XDECL), // >>
|
GTGT(TokenKind.GTGT, XEXPR|XDECL, true), // >>
|
||||||
GTGTGT(TokenKind.GTGTGT, XEXPR|XDECL), // >>>
|
GTGTGT(TokenKind.GTGTGT, XEXPR|XDECL, true), // >>>
|
||||||
QUES(TokenKind.QUES, XEXPR|XDECL), // ?
|
QUES(TokenKind.QUES, XEXPR|XDECL, true), // ?
|
||||||
DOT(TokenKind.DOT, XEXPR|XDECL), // .
|
DOT(TokenKind.DOT, XEXPR|XDECL), // .
|
||||||
STAR(TokenKind.STAR, XEXPR), // * (MAPPED: DOTSTAR)
|
STAR(TokenKind.STAR, XEXPR, true), // * (MAPPED: DOTSTAR)
|
||||||
|
|
||||||
// Statement keywords
|
// Statement keywords
|
||||||
ASSERT(TokenKind.ASSERT, XSTMT1|XSTART), // assert
|
ASSERT(TokenKind.ASSERT, XSTMT1|XSTART), // assert
|
||||||
|
@ -249,7 +249,7 @@ class CompletenessAnalyzer {
|
||||||
FOR(TokenKind.FOR, XSTMT1|XSTART), // for
|
FOR(TokenKind.FOR, XSTMT1|XSTART), // for
|
||||||
IF(TokenKind.IF, XSTMT1|XSTART), // if
|
IF(TokenKind.IF, XSTMT1|XSTART), // if
|
||||||
RETURN(TokenKind.RETURN, XSTMT1|XTERM|XSTART), // return
|
RETURN(TokenKind.RETURN, XSTMT1|XTERM|XSTART), // return
|
||||||
SWITCH(TokenKind.SWITCH, XSTMT1|XEXPR), // switch
|
SWITCH(TokenKind.SWITCH, XSTMT1|XEXPR1), // switch
|
||||||
SYNCHRONIZED(TokenKind.SYNCHRONIZED, XSTMT1|XDECL), // synchronized
|
SYNCHRONIZED(TokenKind.SYNCHRONIZED, XSTMT1|XDECL), // synchronized
|
||||||
THROW(TokenKind.THROW, XSTMT1|XSTART), // throw
|
THROW(TokenKind.THROW, XSTMT1|XSTART), // throw
|
||||||
TRY(TokenKind.TRY, XSTMT1|XSTART), // try
|
TRY(TokenKind.TRY, XSTMT1|XSTART), // try
|
||||||
|
@ -276,7 +276,7 @@ class CompletenessAnalyzer {
|
||||||
SUBSUB(TokenKind.SUBSUB, XEXPR1|XTERM), // --
|
SUBSUB(TokenKind.SUBSUB, XEXPR1|XTERM), // --
|
||||||
|
|
||||||
// Expressions cannot terminate
|
// Expressions cannot terminate
|
||||||
INSTANCEOF(TokenKind.INSTANCEOF, XEXPR), // instanceof
|
INSTANCEOF(TokenKind.INSTANCEOF, XEXPR, true), // instanceof
|
||||||
NEW(TokenKind.NEW, XEXPR1), // new (MAPPED: COLCOLNEW)
|
NEW(TokenKind.NEW, XEXPR1), // new (MAPPED: COLCOLNEW)
|
||||||
SUPER(TokenKind.SUPER, XEXPR1|XDECL), // super -- shouldn't see as rec. But in type parameters
|
SUPER(TokenKind.SUPER, XEXPR1|XDECL), // super -- shouldn't see as rec. But in type parameters
|
||||||
ARROW(TokenKind.ARROW, XEXPR), // ->
|
ARROW(TokenKind.ARROW, XEXPR), // ->
|
||||||
|
@ -292,18 +292,18 @@ class CompletenessAnalyzer {
|
||||||
BANG(TokenKind.BANG, XEXPR1), // !
|
BANG(TokenKind.BANG, XEXPR1), // !
|
||||||
TILDE(TokenKind.TILDE, XEXPR1), // ~
|
TILDE(TokenKind.TILDE, XEXPR1), // ~
|
||||||
COLON(TokenKind.COLON, XEXPR|XTERM), // :
|
COLON(TokenKind.COLON, XEXPR|XTERM), // :
|
||||||
EQEQ(TokenKind.EQEQ, XEXPR), // ==
|
EQEQ(TokenKind.EQEQ, XEXPR, true), // ==
|
||||||
LTEQ(TokenKind.LTEQ, XEXPR), // <=
|
LTEQ(TokenKind.LTEQ, XEXPR, true), // <=
|
||||||
GTEQ(TokenKind.GTEQ, XEXPR), // >=
|
GTEQ(TokenKind.GTEQ, XEXPR, true), // >=
|
||||||
BANGEQ(TokenKind.BANGEQ, XEXPR), // !=
|
BANGEQ(TokenKind.BANGEQ, XEXPR, true), // !=
|
||||||
AMPAMP(TokenKind.AMPAMP, XEXPR), // &&
|
AMPAMP(TokenKind.AMPAMP, XEXPR, true), // &&
|
||||||
BARBAR(TokenKind.BARBAR, XEXPR), // ||
|
BARBAR(TokenKind.BARBAR, XEXPR, true), // ||
|
||||||
PLUS(TokenKind.PLUS, XEXPR1), // +
|
PLUS(TokenKind.PLUS, XEXPR1, true), // +
|
||||||
SUB(TokenKind.SUB, XEXPR1), // -
|
SUB(TokenKind.SUB, XEXPR1, true), // -
|
||||||
SLASH(TokenKind.SLASH, XEXPR), // /
|
SLASH(TokenKind.SLASH, XEXPR, true), // /
|
||||||
BAR(TokenKind.BAR, XEXPR), // |
|
BAR(TokenKind.BAR, XEXPR, true), // |
|
||||||
CARET(TokenKind.CARET, XEXPR), // ^
|
CARET(TokenKind.CARET, XEXPR, true), // ^
|
||||||
PERCENT(TokenKind.PERCENT, XEXPR), // %
|
PERCENT(TokenKind.PERCENT, XEXPR, true), // %
|
||||||
PLUSEQ(TokenKind.PLUSEQ, XEXPR), // +=
|
PLUSEQ(TokenKind.PLUSEQ, XEXPR), // +=
|
||||||
SUBEQ(TokenKind.SUBEQ, XEXPR), // -=
|
SUBEQ(TokenKind.SUBEQ, XEXPR), // -=
|
||||||
STAREQ(TokenKind.STAREQ, XEXPR), // *=
|
STAREQ(TokenKind.STAREQ, XEXPR), // *=
|
||||||
|
@ -330,6 +330,7 @@ class CompletenessAnalyzer {
|
||||||
|
|
||||||
final TokenKind tokenKind;
|
final TokenKind tokenKind;
|
||||||
final int belongs;
|
final int belongs;
|
||||||
|
final boolean valueOp;
|
||||||
Function<TK,TK> mapping;
|
Function<TK,TK> mapping;
|
||||||
|
|
||||||
TK(int b) {
|
TK(int b) {
|
||||||
|
@ -337,8 +338,13 @@ class CompletenessAnalyzer {
|
||||||
}
|
}
|
||||||
|
|
||||||
TK(TokenKind tokenKind, int b) {
|
TK(TokenKind tokenKind, int b) {
|
||||||
|
this(tokenKind, b, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TK(TokenKind tokenKind, int b, boolean valueOp) {
|
||||||
this.tokenKind = tokenKind;
|
this.tokenKind = tokenKind;
|
||||||
this.belongs = b;
|
this.belongs = b;
|
||||||
|
this.valueOp = valueOp;
|
||||||
this.mapping = null;
|
this.mapping = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,6 +643,8 @@ class CompletenessAnalyzer {
|
||||||
return parseExpressionStatement(); // Let this gen the status
|
return parseExpressionStatement(); // Let this gen the status
|
||||||
}
|
}
|
||||||
return error();
|
return error();
|
||||||
|
case XSTMT1o | XEXPR1o:
|
||||||
|
return disambiguateStatementVsExpression();
|
||||||
default:
|
default:
|
||||||
throw new InternalError("Case not covered " + token.kind.belongs + " in " + token.kind);
|
throw new InternalError("Case not covered " + token.kind.belongs + " in " + token.kind);
|
||||||
}
|
}
|
||||||
|
@ -685,6 +693,44 @@ class CompletenessAnalyzer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Completeness disambiguateStatementVsExpression() {
|
||||||
|
if (token.kind == SWITCH) {
|
||||||
|
nextToken();
|
||||||
|
switch (token.kind) {
|
||||||
|
case PARENS:
|
||||||
|
nextToken();
|
||||||
|
break;
|
||||||
|
case UNMATCHED:
|
||||||
|
nextToken();
|
||||||
|
return Completeness.DEFINITELY_INCOMPLETE;
|
||||||
|
case EOF:
|
||||||
|
return Completeness.DEFINITELY_INCOMPLETE;
|
||||||
|
default:
|
||||||
|
return error();
|
||||||
|
}
|
||||||
|
switch (token.kind) {
|
||||||
|
case BRACES:
|
||||||
|
nextToken();
|
||||||
|
break;
|
||||||
|
case UNMATCHED:
|
||||||
|
nextToken();
|
||||||
|
return Completeness.DEFINITELY_INCOMPLETE;
|
||||||
|
case EOF:
|
||||||
|
return Completeness.DEFINITELY_INCOMPLETE;
|
||||||
|
default:
|
||||||
|
return error();
|
||||||
|
}
|
||||||
|
if (token.kind.valueOp) {
|
||||||
|
return parseExpressionOptionalSemi();
|
||||||
|
} else {
|
||||||
|
return Completeness.COMPLETE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new InternalError("Unexpected statement/expression not covered " + token.kind.belongs + " in " + token.kind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public Completeness disambiguateDeclarationVsExpression() {
|
public Completeness disambiguateDeclarationVsExpression() {
|
||||||
// String folding messes up position information.
|
// String folding messes up position information.
|
||||||
return parseFactory.apply(pt -> {
|
return parseFactory.apply(pt -> {
|
||||||
|
|
|
@ -160,7 +160,6 @@ class ReplParser extends JavacParser {
|
||||||
case WHILE:
|
case WHILE:
|
||||||
case DO:
|
case DO:
|
||||||
case TRY:
|
case TRY:
|
||||||
case SWITCH:
|
|
||||||
case RETURN:
|
case RETURN:
|
||||||
case THROW:
|
case THROW:
|
||||||
case BREAK:
|
case BREAK:
|
||||||
|
|
|
@ -90,4 +90,14 @@ public class ToolLocalSimpleTest extends ToolSimpleTest {
|
||||||
// can't set --enable-preview for local, ignore
|
// can't set --enable-preview for local, ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSwitchExpression() {
|
||||||
|
// can't set --enable-preview for local, ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSwitchExpressionCompletion() {
|
||||||
|
// can't set --enable-preview for local, ignore
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,6 +90,35 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSwitchExpression() {
|
||||||
|
test(false, new String[]{"--enable-preview", "--no-startup"},
|
||||||
|
(a) -> assertCommand(a, "enum Day {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }", "| created enum Day"),
|
||||||
|
(a) -> assertCommand(a, "Day day = Day.FRIDAY;", "day ==> FRIDAY"),
|
||||||
|
(a) -> assertCommand(a, "switch (day) {", ""),
|
||||||
|
(a) -> assertCommand(a, "case MONDAY, FRIDAY, SUNDAY -> 6;", ""),
|
||||||
|
(a) -> assertCommand(a, "case TUESDAY -> 7;", ""),
|
||||||
|
(a) -> assertCommand(a, "case THURSDAY, SATURDAY -> 8;", ""),
|
||||||
|
(a) -> assertCommand(a, "case WEDNESDAY -> 9;", ""),
|
||||||
|
(a) -> assertCommandOutputContains(a, "}", " ==> 6")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSwitchExpressionCompletion() {
|
||||||
|
test(false, new String[]{"--enable-preview", "--no-startup"},
|
||||||
|
(a) -> assertCommand(a, "enum Day {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }", "| created enum Day"),
|
||||||
|
(a) -> assertCommand(a, "Day day = Day.FRIDAY;", "day ==> FRIDAY"),
|
||||||
|
(a) -> assertCommand(a, "switch (day) {", ""),
|
||||||
|
(a) -> assertCommand(a, "case MONDAY, FRIDAY, SUNDAY -> 6;", ""),
|
||||||
|
(a) -> assertCommand(a, "case TUESDAY -> 7;", ""),
|
||||||
|
(a) -> assertCommand(a, "case THURSDAY, SATURDAY -> 8;", ""),
|
||||||
|
(a) -> assertCommand(a, "case WEDNESDAY -> 9;", ""),
|
||||||
|
(a) -> assertCommand(a, "} +", ""),
|
||||||
|
(a) -> assertCommandOutputContains(a, "1000", " ==> 1006")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLessThan() {
|
public void testLessThan() {
|
||||||
test(
|
test(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue