Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: JDK 22 unnamed variables & patterns #620

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 35 additions & 49 deletions packages/java-parser/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,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 @@ -297,7 +295,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 @@ -377,7 +374,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 @@ -628,8 +627,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 @@ -655,7 +652,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 @@ -735,7 +731,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 @@ -1275,8 +1273,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 @@ -2644,28 +2643,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 @@ -2961,23 +2940,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 @@ -3060,6 +3026,7 @@ export interface LambdaParametersCstNode extends CstNode {
export type LambdaParametersCtx = {
lambdaParametersWithBraces?: LambdaParametersWithBracesCstNode[];
Identifier?: IToken[];
Underscore?: IToken[];
};

export interface LambdaParametersWithBracesCstNode extends CstNode {
Expand Down Expand Up @@ -3525,20 +3492,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);
});
Comment on lines -519 to -541
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update ! If I may, it would have been even better if you split the commit in two, one for handling the new JDK 22 unnamed variables & patterns feature, and one other for updating this: it is easier to review as it does not mix up two different things :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I probably should have made this change as the first commit, proving that no changes occurred after making this change, and then have my JDK 22 unnamed variables & patterns feature be the second commit, which would effectively leverage the change from the first. I'll keep this kind of thing in mind for future contributions!


// 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