Skip to content

Commit

Permalink
feat: support unnamed class compilation unit (with spec deviation)
Browse files Browse the repository at this point in the history
  • Loading branch information
clementdessoude committed Oct 29, 2023
1 parent 7ea8ece commit 2b42563
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 53 deletions.
83 changes: 37 additions & 46 deletions packages/java-parser/src/productions/packages-and-modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,15 @@ const { isRecognitionException, tokenMatcher, EOF } = require("chevrotain");
const { classBodyTypes } = require("./utils/class-body-types");

function defineRules($, t) {
// https://docs.oracle.com/javase/specs/jls/se16/html/jls-7.html#CompilationUnit

/**
* Spec Deviation: As OrdinaryCompilationUnit and UnnamedClassCompilationUnit
* both can have multiple class or interface declarations, both were combined
* in the ordinaryCompilationUnit rule
*
* https://docs.oracle.com/javase/specs/jls/se21/html/jls-7.html#jls-7.3
* https://docs.oracle.com/javase/specs/jls/se21/preview/specs/unnamed-classes-instance-main-methods-jls.html
*/
$.RULE("compilationUnit", () => {
// custom optimized backtracking lookahead logic
const isModule = $.BACKTRACK_LOOKAHEAD($.isModuleCompilationUnit);
Expand Down Expand Up @@ -96,18 +104,41 @@ function defineRules($, t) {
]);
});

// https://docs.oracle.com/javase/specs/jls/se16/html/jls-7.html#jls-TypeDeclaration

/**
* Spec Deviation: As OrdinaryCompilationUnit and UnnamedClassCompilationUnit
* both can have multiple class or interface declarations, both were combined
* in the ordinaryCompilationUnit rule
*
* As a result, the typeDeclaration combine TopLevelClassOrInterfaceDeclaration and includes fields and method declarations as well
* to handle unnamed class compilation unit
*
* https://docs.oracle.com/javase/specs/jls/se21/html/jls-7.html#jls-TopLevelClassOrInterfaceDeclaration
* https://docs.oracle.com/javase/specs/jls/se21/preview/specs/unnamed-classes-instance-main-methods-jls.html
*/
$.RULE("typeDeclaration", () => {
// TODO: consider extracting the prefix modifiers here to avoid backtracking
const isClassDeclaration = this.BACKTRACK_LOOKAHEAD($.isClassDeclaration);
const nextRuleType = $.BACKTRACK_LOOKAHEAD(
$.identifyClassBodyDeclarationType
);

$.OR([
{ ALT: () => $.CONSUME(t.Semicolon) },
{
GATE: () => isClassDeclaration,
GATE: () => nextRuleType === classBodyTypes.classDeclaration,
ALT: () => $.SUBRULE($.classDeclaration)
},
{ ALT: () => $.SUBRULE($.interfaceDeclaration) },
{ ALT: () => $.CONSUME(t.Semicolon) }
{
GATE: () => nextRuleType === classBodyTypes.interfaceDeclaration,
ALT: () => $.SUBRULE($.interfaceDeclaration)
},
{
GATE: () => nextRuleType === classBodyTypes.fieldDeclaration,
ALT: () => $.SUBRULE($.fieldDeclaration)
},
{
ALT: () => $.SUBRULE($.methodDeclaration)
}
]);
});

Expand Down Expand Up @@ -227,46 +258,6 @@ function defineRules($, t) {
]);
});

$.RULE("unnamedClassCompilationUnit", () => {
$.MANY(() => $.SUBRULE($.importDeclaration));

const nextRuleType = $.BACKTRACK_LOOKAHEAD(
$.identifyClassBodyDeclarationType
);
$.MANY1({
GATE: () => nextRuleType !== classBodyTypes.methodDeclaration,
DEF: () => $.SUBRULE($.classMemberDeclarationNoMethod, {
ARGS: [nextRuleType]
})
});
$.SUBRULE($.methodDeclaration);
$.MANY2(() => {
const nextRuleType = $.BACKTRACK_LOOKAHEAD($.identifyClassBodyDeclarationType);
$.SUBRULE($.classMemberDeclaration, {
ARGS: [nextRuleType]
});
});
});

$.RULE("classMemberDeclarationNoMethod", nextRuleType => {
$.OR([
{
GATE: () => nextRuleType === classBodyTypes.fieldDeclaration,
ALT: () => $.SUBRULE($.fieldDeclaration)
},
{
GATE: () => nextRuleType === classBodyTypes.classDeclaration,
ALT: () => $.SUBRULE($.classDeclaration)
},
{ ALT: () => $.CONSUME(t.Semicolon) },
{
GATE: () => nextRuleType === classBodyTypes.interfaceDeclaration,
ALT: () => $.SUBRULE($.interfaceDeclaration)
}
]);

});

$.RULE("isModuleCompilationUnit", () => {
$.OPTION(() => {
$.SUBRULE($.packageDeclaration);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ describe("Unnamed Class Compilation Unit", () => {
System.out.println("Hello, World!");
}
`;
javaParser.parse(input, "compilationUnit");
expect(() => javaParser.parse(input, "compilationUnit")).to.not.throw();
});

Expand All @@ -19,7 +20,7 @@ describe("Unnamed Class Compilation Unit", () => {
System.out.println("Hello, World!");
}
`;
expect(() => javaParser.parse(input, "unnamedClassCompilationUnit")).to.not.throw();
expect(() => javaParser.parse(input, "compilationUnit")).to.not.throw();
});

it("should handle UnnamedClassCompilationUnit with fields", () => {
Expand All @@ -32,7 +33,7 @@ describe("Unnamed Class Compilation Unit", () => {
System.out.println(hourra);
}
`;
expect(() => javaParser.parse(input, "unnamedClassCompilationUnit")).to.not.throw();
expect(() => javaParser.parse(input, "compilationUnit")).to.not.throw();
});

it("should handle UnnamedClassCompilationUnit with class declaration", () => {
Expand All @@ -43,7 +44,7 @@ describe("Unnamed Class Compilation Unit", () => {
System.out.println(Test.greetings());
}
`;
expect(() => javaParser.parse(input, "unnamedClassCompilationUnit")).to.not.throw();
expect(() => javaParser.parse(input, "compilationUnit")).to.not.throw();
});

it("should handle UnnamedClassCompilationUnit with interface declaration", () => {
Expand All @@ -54,7 +55,7 @@ describe("Unnamed Class Compilation Unit", () => {
System.out.println(Test.greetings());
}
`;
expect(() => javaParser.parse(input, "unnamedClassCompilationUnit")).to.not.throw();
expect(() => javaParser.parse(input, "compilationUnit")).to.not.throw();
});

it("should handle UnnamedClassCompilationUnit with semicolons", () => {
Expand All @@ -65,7 +66,7 @@ describe("Unnamed Class Compilation Unit", () => {
System.out.println("Hello World!");
}
`;
expect(() => javaParser.parse(input, "unnamedClassCompilationUnit")).to.not.throw();
expect(() => javaParser.parse(input, "compilationUnit")).to.not.throw();
});

it("should handle UnnamedClassCompilationUnit with class member declarations", () => {
Expand All @@ -77,7 +78,7 @@ describe("Unnamed Class Compilation Unit", () => {
}
`;

expect(() => javaParser.parse(input, "unnamedClassCompilationUnit")).to.not.throw();
expect(() => javaParser.parse(input, "compilationUnit")).to.not.throw();
});

it("should handle UnnamedClassCompilationUnit with imports", () => {
Expand All @@ -90,6 +91,6 @@ describe("Unnamed Class Compilation Unit", () => {
}
`;

expect(() => javaParser.parse(input, "unnamedClassCompilationUnit")).to.not.throw();
expect(() => javaParser.parse(input, "compilationUnit")).to.not.throw();
});
});

0 comments on commit 2b42563

Please sign in to comment.