Skip to content

Commit

Permalink
feat: JDK 22 unnamed variables & patterns
Browse files Browse the repository at this point in the history
closes #612
  • Loading branch information
jtkiesel authored and clementdessoude committed Nov 26, 2023
1 parent e53f3a4 commit 904ce59
Show file tree
Hide file tree
Showing 16 changed files with 535 additions and 191 deletions.
84 changes: 35 additions & 49 deletions packages/java-parser/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,6 @@ export abstract class JavaCstVisitor<IN, OUT> implements ICstVisitor<IN, OUT> {
switchBlock(ctx: SwitchBlockCtx, param?: IN): OUT;
switchBlockStatementGroup(ctx: SwitchBlockStatementGroupCtx, param?: IN): OUT;
switchLabel(ctx: SwitchLabelCtx, param?: IN): OUT;
caseOrDefaultLabel(ctx: CaseOrDefaultLabelCtx, param?: IN): OUT;
caseLabelElement(ctx: CaseLabelElementCtx, param?: IN): OUT;
switchRule(ctx: SwitchRuleCtx, param?: IN): OUT;
caseConstant(ctx: CaseConstantCtx, param?: IN): OUT;
whileStatement(ctx: WhileStatementCtx, param?: IN): OUT;
Expand All @@ -305,7 +303,6 @@ export abstract class JavaCstVisitor<IN, OUT> implements ICstVisitor<IN, OUT> {
resourceSpecification(ctx: ResourceSpecificationCtx, param?: IN): OUT;
resourceList(ctx: ResourceListCtx, param?: IN): OUT;
resource(ctx: ResourceCtx, param?: IN): OUT;
resourceInit(ctx: ResourceInitCtx, param?: IN): OUT;
yieldStatement(ctx: YieldStatementCtx, param?: IN): OUT;
variableAccess(ctx: VariableAccessCtx, param?: IN): OUT;
isBasicForStatement(ctx: IsBasicForStatementCtx, param?: IN): OUT;
Expand Down Expand Up @@ -385,7 +382,9 @@ export abstract class JavaCstVisitor<IN, OUT> implements ICstVisitor<IN, OUT> {
pattern(ctx: PatternCtx, param?: IN): OUT;
typePattern(ctx: TypePatternCtx, param?: IN): OUT;
recordPattern(ctx: RecordPatternCtx, param?: IN): OUT;
patternList(ctx: PatternListCtx, param?: IN): OUT;
componentPatternList(ctx: ComponentPatternListCtx, param?: IN): OUT;
componentPattern(ctx: ComponentPatternCtx, param?: IN): OUT;
unnamedPattern(ctx: UnnamedPatternCtx, param?: IN): OUT;
guard(ctx: GuardCtx, param?: IN): OUT;
identifyNewExpressionType(ctx: IdentifyNewExpressionTypeCtx, param?: IN): OUT;
isLambdaExpression(ctx: IsLambdaExpressionCtx, param?: IN): OUT;
Expand Down Expand Up @@ -636,8 +635,6 @@ export abstract class JavaCstVisitorWithDefaults<IN, OUT>
switchBlock(ctx: SwitchBlockCtx, param?: IN): OUT;
switchBlockStatementGroup(ctx: SwitchBlockStatementGroupCtx, param?: IN): OUT;
switchLabel(ctx: SwitchLabelCtx, param?: IN): OUT;
caseOrDefaultLabel(ctx: CaseOrDefaultLabelCtx, param?: IN): OUT;
caseLabelElement(ctx: CaseLabelElementCtx, param?: IN): OUT;
switchRule(ctx: SwitchRuleCtx, param?: IN): OUT;
caseConstant(ctx: CaseConstantCtx, param?: IN): OUT;
whileStatement(ctx: WhileStatementCtx, param?: IN): OUT;
Expand All @@ -663,7 +660,6 @@ export abstract class JavaCstVisitorWithDefaults<IN, OUT>
resourceSpecification(ctx: ResourceSpecificationCtx, param?: IN): OUT;
resourceList(ctx: ResourceListCtx, param?: IN): OUT;
resource(ctx: ResourceCtx, param?: IN): OUT;
resourceInit(ctx: ResourceInitCtx, param?: IN): OUT;
yieldStatement(ctx: YieldStatementCtx, param?: IN): OUT;
variableAccess(ctx: VariableAccessCtx, param?: IN): OUT;
isBasicForStatement(ctx: IsBasicForStatementCtx, param?: IN): OUT;
Expand Down Expand Up @@ -743,7 +739,9 @@ export abstract class JavaCstVisitorWithDefaults<IN, OUT>
pattern(ctx: PatternCtx, param?: IN): OUT;
typePattern(ctx: TypePatternCtx, param?: IN): OUT;
recordPattern(ctx: RecordPatternCtx, param?: IN): OUT;
patternList(ctx: PatternListCtx, param?: IN): OUT;
componentPatternList(ctx: ComponentPatternListCtx, param?: IN): OUT;
componentPattern(ctx: ComponentPatternCtx, param?: IN): OUT;
unnamedPattern(ctx: UnnamedPatternCtx, param?: IN): OUT;
guard(ctx: GuardCtx, param?: IN): OUT;
identifyNewExpressionType(ctx: IdentifyNewExpressionTypeCtx, param?: IN): OUT;
isLambdaExpression(ctx: IsLambdaExpressionCtx, param?: IN): OUT;
Expand Down Expand Up @@ -1283,8 +1281,9 @@ export interface VariableDeclaratorIdCstNode extends CstNode {
}

export type VariableDeclaratorIdCtx = {
Identifier: IToken[];
Identifier?: IToken[];
dims?: DimsCstNode[];
Underscore?: IToken[];
};

export interface VariableInitializerCstNode extends CstNode {
Expand Down Expand Up @@ -2652,28 +2651,8 @@ export interface SwitchLabelCstNode extends CstNode {
}

export type SwitchLabelCtx = {
caseOrDefaultLabel: CaseOrDefaultLabelCstNode[];
Colon?: IToken[];
};

export interface CaseOrDefaultLabelCstNode extends CstNode {
name: "caseOrDefaultLabel";
children: CaseOrDefaultLabelCtx;
}

export type CaseOrDefaultLabelCtx = {
Case?: IToken[];
caseLabelElement?: CaseLabelElementCstNode[];
Comma?: IToken[];
Default?: IToken[];
};

export interface CaseLabelElementCstNode extends CstNode {
name: "caseLabelElement";
children: CaseLabelElementCtx;
}

export type CaseLabelElementCtx = {
Null?: IToken[];
Default?: IToken[];
pattern?: PatternCstNode[];
Expand Down Expand Up @@ -2969,23 +2948,10 @@ export interface ResourceCstNode extends CstNode {
}

export type ResourceCtx = {
resourceInit?: ResourceInitCstNode[];
localVariableDeclaration?: LocalVariableDeclarationCstNode[];
variableAccess?: VariableAccessCstNode[];
};

export interface ResourceInitCstNode extends CstNode {
name: "resourceInit";
children: ResourceInitCtx;
}

export type ResourceInitCtx = {
variableModifier?: VariableModifierCstNode[];
localVariableType: LocalVariableTypeCstNode[];
Identifier: IToken[];
Equals: IToken[];
expression: ExpressionCstNode[];
};

export interface YieldStatementCstNode extends CstNode {
name: "yieldStatement";
children: YieldStatementCtx;
Expand Down Expand Up @@ -3068,6 +3034,7 @@ export interface LambdaParametersCstNode extends CstNode {
export type LambdaParametersCtx = {
lambdaParametersWithBraces?: LambdaParametersWithBracesCstNode[];
Identifier?: IToken[];
Underscore?: IToken[];
};

export interface LambdaParametersWithBracesCstNode extends CstNode {
Expand Down Expand Up @@ -3533,20 +3500,39 @@ export interface RecordPatternCstNode extends CstNode {
export type RecordPatternCtx = {
referenceType: ReferenceTypeCstNode[];
LBrace: IToken[];
patternList?: PatternListCstNode[];
componentPatternList?: ComponentPatternListCstNode[];
RBrace: IToken[];
};

export interface PatternListCstNode extends CstNode {
name: "patternList";
children: PatternListCtx;
export interface ComponentPatternListCstNode extends CstNode {
name: "componentPatternList";
children: ComponentPatternListCtx;
}

export type PatternListCtx = {
pattern: PatternCstNode[];
export type ComponentPatternListCtx = {
componentPattern: ComponentPatternCstNode[];
Comma?: IToken[];
};

export interface ComponentPatternCstNode extends CstNode {
name: "componentPattern";
children: ComponentPatternCtx;
}

export type ComponentPatternCtx = {
pattern?: PatternCstNode[];
unnamedPattern?: UnnamedPatternCstNode[];
};

export interface UnnamedPatternCstNode extends CstNode {
name: "unnamedPattern";
children: UnnamedPatternCtx;
}

export type UnnamedPatternCtx = {
Underscore: IToken[];
};

export interface GuardCstNode extends CstNode {
name: "guard";
children: GuardCtx;
Expand Down
98 changes: 39 additions & 59 deletions packages/java-parser/src/productions/blocks-and-statements.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,56 +207,49 @@ function defineRules($, t) {
});
});

// https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-SwitchLabel
$.RULE("switchLabel", () => {
$.SUBRULE($.caseOrDefaultLabel);
$.MANY({
GATE: () =>
tokenMatcher($.LA(1).tokenType, t.Colon) &&
(tokenMatcher($.LA(2).tokenType, t.Case) ||
tokenMatcher($.LA(2).tokenType, t.Default)),
DEF: () => {
$.CONSUME(t.Colon);
$.SUBRULE2($.caseOrDefaultLabel);
}
});
});

// https://docs.oracle.com/javase/specs/jls/se16/html/jls-14.html#jls-SwitchLabel
$.RULE("caseOrDefaultLabel", () => {
$.OR([
{
ALT: () => {
$.CONSUME(t.Case);
$.SUBRULE($.caseLabelElement);
$.MANY(() => {
$.CONSUME(t.Comma);
$.SUBRULE2($.caseLabelElement);
});
}
},
{
ALT: () => $.CONSUME(t.Default)
}
]);
});

$.RULE("caseLabelElement", () => {
$.OR([
{ ALT: () => $.CONSUME(t.Null) },
{ ALT: () => $.CONSUME(t.Default) },
{
GATE: () => this.BACKTRACK_LOOKAHEAD($.pattern),
ALT: () => {
$.SUBRULE($.pattern);
$.OPTION(() => {
$.SUBRULE($.guard);
});
$.OR2([
{
ALT: () => {
$.CONSUME(t.Null);
$.OPTION2(() => {
$.CONSUME3(t.Comma);
$.CONSUME(t.Default);
});
}
},
{
GATE: () => this.BACKTRACK_LOOKAHEAD($.pattern),
ALT: () => {
$.SUBRULE($.pattern);
$.MANY(() => {
$.CONSUME(t.Comma);
$.SUBRULE2($.pattern);
});
$.OPTION(() => {
$.SUBRULE($.guard);
});
}
},
{
GATE: () => !tokenMatcher($.LA(1).tokenType, t.Null),
ALT: () => {
$.SUBRULE($.caseConstant);
$.MANY2(() => {
$.CONSUME2(t.Comma);
$.SUBRULE2($.caseConstant);
});
}
}
]);
}
},
{
GATE: () => tokenMatcher($.LA(1).tokenType, t.Null) === false,
ALT: () => $.SUBRULE($.caseConstant)
}
{ ALT: () => $.CONSUME2(t.Default) }
]);
});

Expand Down Expand Up @@ -516,30 +509,17 @@ function defineRules($, t) {
});
});

// https://docs.oracle.com/javase/specs/jls/se16/html/jls-14.html#jls-Resource
// https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-Resource
$.RULE("resource", () => {
$.OR([
{
GATE: $.BACKTRACK($.resourceInit),
// Spec Deviation: extracted this alternative to "resourceInit"
// to enable backtracking.
ALT: () => $.SUBRULE($.resourceInit)
GATE: () => $.BACKTRACK_LOOKAHEAD($.isLocalVariableDeclaration),
ALT: () => $.SUBRULE($.localVariableDeclaration)
},
{ ALT: () => $.SUBRULE($.variableAccess) }
]);
});

// Spec Deviation: extracted from "resource"
$.RULE("resourceInit", () => {
$.MANY(() => {
$.SUBRULE($.variableModifier);
});
$.SUBRULE($.localVariableType);
$.CONSUME(t.Identifier);
$.CONSUME(t.Equals);
$.SUBRULE($.expression);
});

// https://docs.oracle.com/javase/specs/jls/se16/html/jls-14.html#jls-YieldStatement
$.RULE("yieldStatement", () => {
$.CONSUME(t.Yield);
Expand Down
17 changes: 12 additions & 5 deletions packages/java-parser/src/productions/classes.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,12 +210,19 @@ function defineRules($, t) {
});
});

// https://docs.oracle.com/javase/specs/jls/se16/html/jls-8.html#jls-VariableDeclaratorId
// https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-VariableDeclaratorId
$.RULE("variableDeclaratorId", () => {
$.CONSUME(t.Identifier);
$.OPTION(() => {
$.SUBRULE($.dims);
});
$.OR([
{
ALT: () => {
$.CONSUME(t.Identifier);
$.OPTION(() => {
$.SUBRULE($.dims);
});
}
},
{ ALT: () => $.CONSUME(t.Underscore) }
]);
});

// https://docs.oracle.com/javase/specs/jls/se16/html/jls-8.html#jls-VariableInitializer
Expand Down
25 changes: 19 additions & 6 deletions packages/java-parser/src/productions/expressions.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ function defineRules($, t) {
$.RULE("lambdaParameters", () => {
$.OR([
{ ALT: () => $.SUBRULE($.lambdaParametersWithBraces) },
{ ALT: () => $.CONSUME(t.Identifier) }
{ ALT: () => $.CONSUME(t.Identifier) },
{ ALT: () => $.CONSUME(t.Underscore) }
]);
});

Expand Down Expand Up @@ -584,20 +585,31 @@ function defineRules($, t) {
$.SUBRULE($.referenceType);
$.CONSUME(t.LBrace);
$.OPTION(() => {
$.SUBRULE($.patternList);
$.SUBRULE($.componentPatternList);
});
$.CONSUME(t.RBrace);
});

// https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-PatternList
$.RULE("patternList", () => {
$.SUBRULE($.pattern);
$.RULE("componentPatternList", () => {
$.SUBRULE($.componentPattern);
$.MANY(() => {
$.CONSUME(t.Comma);
$.SUBRULE2($.pattern);
$.SUBRULE2($.componentPattern);
});
});

$.RULE("componentPattern", () => {
$.OR([
{ ALT: () => $.SUBRULE($.pattern) },
{ ALT: () => $.SUBRULE($.unnamedPattern) }
]);
});

$.RULE("unnamedPattern", () => {
$.CONSUME(t.Underscore);
});

// https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-Guard
$.RULE("guard", () => {
$.CONSUME(t.When);
Expand Down Expand Up @@ -643,7 +655,8 @@ function defineRules($, t) {
const secondTokenType = this.LA(2).tokenType;
// no parent lambda "x -> x * 2"
if (
tokenMatcher(firstTokenType, t.Identifier) &&
(tokenMatcher(firstTokenType, t.Identifier) ||
tokenMatcher(firstTokenType, t.Underscore)) &&
tokenMatcher(secondTokenType, t.Arrow)
) {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ describe("Switch cases", () => {
case String s -> String.format("String %s", s);
case TOTO -> String.format("TOTO %s", o);
case null -> String.format("Null !");
case default -> String.format("Default !");
case null, default -> String.format("Default !");
default -> o.toString();
}`;
expect(() => javaParser.parse(input, "switchStatement")).to.not.throw();
Expand Down
Loading

0 comments on commit 904ce59

Please sign in to comment.