From 38afbfe56010a1d6af9f4ef9c6a17b1ee2ea7885 Mon Sep 17 00:00:00 2001 From: Jordan Kiesel Date: Sun, 5 Nov 2023 18:03:34 -0700 Subject: [PATCH] perf: leverage Chevrotain Allstar to reduce backtracking --- packages/java-parser/api.d.ts | 256 ----------------- packages/java-parser/package.json | 1 + packages/java-parser/src/parser.js | 5 +- .../src/productions/blocks-and-statements.js | 155 +++------- .../java-parser/src/productions/classes.js | 257 ++--------------- .../src/productions/expressions.js | 228 +++------------ .../java-parser/src/productions/interfaces.js | 265 +----------------- .../src/productions/packages-and-modules.js | 87 +----- .../productions/types-values-and-variables.js | 17 +- .../src/productions/utils/class-body-types.js | 11 - packages/prettier-plugin-java/src/options.js | 15 - .../src/printers/blocks-and-statements.ts | 12 - .../src/printers/classes.ts | 12 - .../src/printers/expressions.ts | 20 -- .../src/printers/interfaces.ts | 12 - .../src/printers/packages-and-modules.ts | 4 - yarn.lock | 9 +- 17 files changed, 132 insertions(+), 1234 deletions(-) delete mode 100644 packages/java-parser/src/productions/utils/class-body-types.js diff --git a/packages/java-parser/api.d.ts b/packages/java-parser/api.d.ts index 3ac93af0..1db05aea 100644 --- a/packages/java-parser/api.d.ts +++ b/packages/java-parser/api.d.ts @@ -170,16 +170,7 @@ export abstract class JavaCstVisitor implements ICstVisitor { ctx: CompactConstructorDeclarationCtx, param?: IN ): OUT; - isClassDeclaration(ctx: IsClassDeclarationCtx, param?: IN): OUT; - identifyClassBodyDeclarationType( - ctx: IdentifyClassBodyDeclarationTypeCtx, - param?: IN - ): OUT; isDims(ctx: IsDimsCtx, param?: IN): OUT; - isCompactConstructorDeclaration( - ctx: IsCompactConstructorDeclarationCtx, - param?: IN - ): OUT; compilationUnit(ctx: CompilationUnitCtx, param?: IN): OUT; ordinaryCompilationUnit(ctx: OrdinaryCompilationUnitCtx, param?: IN): OUT; modularCompilationUnit(ctx: ModularCompilationUnitCtx, param?: IN): OUT; @@ -195,7 +186,6 @@ export abstract class JavaCstVisitor implements ICstVisitor { usesModuleDirective(ctx: UsesModuleDirectiveCtx, param?: IN): OUT; providesModuleDirective(ctx: ProvidesModuleDirectiveCtx, param?: IN): OUT; requiresModifier(ctx: RequiresModifierCtx, param?: IN): OUT; - isModuleCompilationUnit(ctx: IsModuleCompilationUnitCtx, param?: IN): OUT; interfaceDeclaration(ctx: InterfaceDeclarationCtx, param?: IN): OUT; normalInterfaceDeclaration( ctx: NormalInterfaceDeclarationCtx, @@ -240,18 +230,6 @@ export abstract class JavaCstVisitor implements ICstVisitor { param?: IN ): OUT; elementValueList(ctx: ElementValueListCtx, param?: IN): OUT; - identifyInterfaceBodyDeclarationType( - ctx: IdentifyInterfaceBodyDeclarationTypeCtx, - param?: IN - ): OUT; - identifyAnnotationBodyDeclarationType( - ctx: IdentifyAnnotationBodyDeclarationTypeCtx, - param?: IN - ): OUT; - isSimpleElementValueAnnotation( - ctx: IsSimpleElementValueAnnotationCtx, - param?: IN - ): OUT; arrayInitializer(ctx: ArrayInitializerCtx, param?: IN): OUT; variableInitializerList(ctx: VariableInitializerListCtx, param?: IN): OUT; block(ctx: BlockCtx, param?: IN): OUT; @@ -305,12 +283,6 @@ export abstract class JavaCstVisitor implements ICstVisitor { resource(ctx: ResourceCtx, param?: IN): OUT; yieldStatement(ctx: YieldStatementCtx, param?: IN): OUT; variableAccess(ctx: VariableAccessCtx, param?: IN): OUT; - isBasicForStatement(ctx: IsBasicForStatementCtx, param?: IN): OUT; - isLocalVariableDeclaration( - ctx: IsLocalVariableDeclarationCtx, - param?: IN - ): OUT; - isClassicSwitchLabel(ctx: IsClassicSwitchLabelCtx, param?: IN): OUT; expression(ctx: ExpressionCtx, param?: IN): OUT; lambdaExpression(ctx: LambdaExpressionCtx, param?: IN): OUT; lambdaParameters(ctx: LambdaParametersCtx, param?: IN): OUT; @@ -386,14 +358,6 @@ export abstract class JavaCstVisitor implements ICstVisitor { 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; - isCastExpression(ctx: IsCastExpressionCtx, param?: IN): OUT; - isPrimitiveCastExpression(ctx: IsPrimitiveCastExpressionCtx, param?: IN): OUT; - isReferenceTypeCastExpression( - ctx: IsReferenceTypeCastExpressionCtx, - param?: IN - ): OUT; isRefTypeInMethodRef(ctx: IsRefTypeInMethodRefCtx, param?: IN): OUT; } @@ -527,16 +491,7 @@ export abstract class JavaCstVisitorWithDefaults ctx: CompactConstructorDeclarationCtx, param?: IN ): OUT; - isClassDeclaration(ctx: IsClassDeclarationCtx, param?: IN): OUT; - identifyClassBodyDeclarationType( - ctx: IdentifyClassBodyDeclarationTypeCtx, - param?: IN - ): OUT; isDims(ctx: IsDimsCtx, param?: IN): OUT; - isCompactConstructorDeclaration( - ctx: IsCompactConstructorDeclarationCtx, - param?: IN - ): OUT; compilationUnit(ctx: CompilationUnitCtx, param?: IN): OUT; ordinaryCompilationUnit(ctx: OrdinaryCompilationUnitCtx, param?: IN): OUT; modularCompilationUnit(ctx: ModularCompilationUnitCtx, param?: IN): OUT; @@ -552,7 +507,6 @@ export abstract class JavaCstVisitorWithDefaults usesModuleDirective(ctx: UsesModuleDirectiveCtx, param?: IN): OUT; providesModuleDirective(ctx: ProvidesModuleDirectiveCtx, param?: IN): OUT; requiresModifier(ctx: RequiresModifierCtx, param?: IN): OUT; - isModuleCompilationUnit(ctx: IsModuleCompilationUnitCtx, param?: IN): OUT; interfaceDeclaration(ctx: InterfaceDeclarationCtx, param?: IN): OUT; normalInterfaceDeclaration( ctx: NormalInterfaceDeclarationCtx, @@ -597,18 +551,6 @@ export abstract class JavaCstVisitorWithDefaults param?: IN ): OUT; elementValueList(ctx: ElementValueListCtx, param?: IN): OUT; - identifyInterfaceBodyDeclarationType( - ctx: IdentifyInterfaceBodyDeclarationTypeCtx, - param?: IN - ): OUT; - identifyAnnotationBodyDeclarationType( - ctx: IdentifyAnnotationBodyDeclarationTypeCtx, - param?: IN - ): OUT; - isSimpleElementValueAnnotation( - ctx: IsSimpleElementValueAnnotationCtx, - param?: IN - ): OUT; arrayInitializer(ctx: ArrayInitializerCtx, param?: IN): OUT; variableInitializerList(ctx: VariableInitializerListCtx, param?: IN): OUT; block(ctx: BlockCtx, param?: IN): OUT; @@ -662,12 +604,6 @@ export abstract class JavaCstVisitorWithDefaults resource(ctx: ResourceCtx, param?: IN): OUT; yieldStatement(ctx: YieldStatementCtx, param?: IN): OUT; variableAccess(ctx: VariableAccessCtx, param?: IN): OUT; - isBasicForStatement(ctx: IsBasicForStatementCtx, param?: IN): OUT; - isLocalVariableDeclaration( - ctx: IsLocalVariableDeclarationCtx, - param?: IN - ): OUT; - isClassicSwitchLabel(ctx: IsClassicSwitchLabelCtx, param?: IN): OUT; expression(ctx: ExpressionCtx, param?: IN): OUT; lambdaExpression(ctx: LambdaExpressionCtx, param?: IN): OUT; lambdaParameters(ctx: LambdaParametersCtx, param?: IN): OUT; @@ -743,14 +679,6 @@ export abstract class JavaCstVisitorWithDefaults 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; - isCastExpression(ctx: IsCastExpressionCtx, param?: IN): OUT; - isPrimitiveCastExpression(ctx: IsPrimitiveCastExpressionCtx, param?: IN): OUT; - isReferenceTypeCastExpression( - ctx: IsReferenceTypeCastExpressionCtx, - param?: IN - ): OUT; isRefTypeInMethodRef(ctx: IsRefTypeInMethodRefCtx, param?: IN): OUT; } @@ -1836,39 +1764,6 @@ export type CompactConstructorDeclarationCtx = { constructorBody: ConstructorBodyCstNode[]; }; -export interface IsClassDeclarationCstNode extends CstNode { - name: "isClassDeclaration"; - children: IsClassDeclarationCtx; -} - -export type IsClassDeclarationCtx = { - Semicolon?: IToken[]; - classModifier?: ClassModifierCstNode[]; -}; - -export interface IdentifyClassBodyDeclarationTypeCstNode extends CstNode { - name: "identifyClassBodyDeclarationType"; - children: IdentifyClassBodyDeclarationTypeCtx; -} - -export type IdentifyClassBodyDeclarationTypeCtx = { - annotation?: AnnotationCstNode[]; - Public?: IToken[]; - Protected?: IToken[]; - Private?: IToken[]; - Abstract?: IToken[]; - Static?: IToken[]; - Final?: IToken[]; - Transient?: IToken[]; - Volatile?: IToken[]; - Synchronized?: IToken[]; - Native?: IToken[]; - Sealed?: IToken[]; - NonSealed?: IToken[]; - Strictfp?: IToken[]; - unannType: UnannTypeCstNode[]; -}; - export interface IsDimsCstNode extends CstNode { name: "isDims"; children: IsDimsCtx; @@ -1883,20 +1778,6 @@ export type IsDimsCtx = { RBrace?: IToken[]; }; -export interface IsCompactConstructorDeclarationCstNode extends CstNode { - name: "isCompactConstructorDeclaration"; - children: IsCompactConstructorDeclarationCtx; -} - -export type IsCompactConstructorDeclarationCtx = { - annotation?: AnnotationCstNode[]; - Public?: IToken[]; - Protected?: IToken[]; - Private?: IToken[]; - simpleTypeName: SimpleTypeNameCstNode[]; - LCurly: IToken[]; -}; - export interface CompilationUnitCstNode extends CstNode { name: "compilationUnit"; children: CompilationUnitCtx; @@ -2090,17 +1971,6 @@ export type RequiresModifierCtx = { Static?: IToken[]; }; -export interface IsModuleCompilationUnitCstNode extends CstNode { - name: "isModuleCompilationUnit"; - children: IsModuleCompilationUnitCtx; -} - -export type IsModuleCompilationUnitCtx = { - packageDeclaration?: PackageDeclarationCstNode[]; - importDeclaration?: ImportDeclarationCstNode[]; - annotation?: AnnotationCstNode[]; -}; - export interface InterfaceDeclarationCstNode extends CstNode { name: "interfaceDeclaration"; children: InterfaceDeclarationCtx; @@ -2379,52 +2249,6 @@ export type ElementValueListCtx = { Comma?: IToken[]; }; -export interface IdentifyInterfaceBodyDeclarationTypeCstNode extends CstNode { - name: "identifyInterfaceBodyDeclarationType"; - children: IdentifyInterfaceBodyDeclarationTypeCtx; -} - -export type IdentifyInterfaceBodyDeclarationTypeCtx = { - annotation?: AnnotationCstNode[]; - Public?: IToken[]; - Protected?: IToken[]; - Private?: IToken[]; - Abstract?: IToken[]; - Static?: IToken[]; - Sealed?: IToken[]; - NonSealed?: IToken[]; - Strictfp?: IToken[]; - Final?: IToken[]; - Default?: IToken[]; - unannType: UnannTypeCstNode[]; -}; - -export interface IdentifyAnnotationBodyDeclarationTypeCstNode extends CstNode { - name: "identifyAnnotationBodyDeclarationType"; - children: IdentifyAnnotationBodyDeclarationTypeCtx; -} - -export type IdentifyAnnotationBodyDeclarationTypeCtx = { - annotation?: AnnotationCstNode[]; - Public?: IToken[]; - Protected?: IToken[]; - Private?: IToken[]; - Abstract?: IToken[]; - Static?: IToken[]; - Final?: IToken[]; - Strictfp?: IToken[]; - unannType: UnannTypeCstNode[]; -}; - -export interface IsSimpleElementValueAnnotationCstNode extends CstNode { - name: "isSimpleElementValueAnnotation"; - children: IsSimpleElementValueAnnotationCtx; -} - -export type IsSimpleElementValueAnnotationCtx = { - annotation: AnnotationCstNode[]; -}; - export interface ArrayInitializerCstNode extends CstNode { name: "arrayInitializer"; children: ArrayInitializerCtx; @@ -2972,39 +2796,6 @@ export type VariableAccessCtx = { primary: PrimaryCstNode[]; }; -export interface IsBasicForStatementCstNode extends CstNode { - name: "isBasicForStatement"; - children: IsBasicForStatementCtx; -} - -export type IsBasicForStatementCtx = { - For: IToken[]; - LBrace: IToken[]; - forInit?: ForInitCstNode[]; - Semicolon: IToken[]; -}; - -export interface IsLocalVariableDeclarationCstNode extends CstNode { - name: "isLocalVariableDeclaration"; - children: IsLocalVariableDeclarationCtx; -} - -export type IsLocalVariableDeclarationCtx = { - variableModifier?: VariableModifierCstNode[]; - localVariableType: LocalVariableTypeCstNode[]; - variableDeclaratorId: VariableDeclaratorIdCstNode[]; -}; - -export interface IsClassicSwitchLabelCstNode extends CstNode { - name: "isClassicSwitchLabel"; - children: IsClassicSwitchLabelCtx; -} - -export type IsClassicSwitchLabelCtx = { - switchLabel: SwitchLabelCstNode[]; - Colon: IToken[]; -}; - export interface ExpressionCstNode extends CstNode { name: "expression"; children: ExpressionCtx; @@ -3543,53 +3334,6 @@ export type GuardCtx = { expression: ExpressionCstNode[]; }; -export interface IdentifyNewExpressionTypeCstNode extends CstNode { - name: "identifyNewExpressionType"; - children: IdentifyNewExpressionTypeCtx; -} - -export type IdentifyNewExpressionTypeCtx = { - New: IToken[]; - classOrInterfaceTypeToInstantiate: ClassOrInterfaceTypeToInstantiateCstNode[]; -}; - -export interface IsLambdaExpressionCstNode extends CstNode { - name: "isLambdaExpression"; - children: IsLambdaExpressionCtx; -} - -export type IsLambdaExpressionCtx = {}; - -export interface IsCastExpressionCstNode extends CstNode { - name: "isCastExpression"; - children: IsCastExpressionCtx; -} - -export type IsCastExpressionCtx = {}; - -export interface IsPrimitiveCastExpressionCstNode extends CstNode { - name: "isPrimitiveCastExpression"; - children: IsPrimitiveCastExpressionCtx; -} - -export type IsPrimitiveCastExpressionCtx = { - LBrace: IToken[]; - primitiveType: PrimitiveTypeCstNode[]; - RBrace: IToken[]; -}; - -export interface IsReferenceTypeCastExpressionCstNode extends CstNode { - name: "isReferenceTypeCastExpression"; - children: IsReferenceTypeCastExpressionCtx; -} - -export type IsReferenceTypeCastExpressionCtx = { - LBrace: IToken[]; - referenceType: ReferenceTypeCstNode[]; - additionalBound?: AdditionalBoundCstNode[]; - RBrace: IToken[]; -}; - export interface IsRefTypeInMethodRefCstNode extends CstNode { name: "isRefTypeInMethodRef"; children: IsRefTypeInMethodRefCtx; diff --git a/packages/java-parser/package.json b/packages/java-parser/package.json index 4b323148..01336137 100644 --- a/packages/java-parser/package.json +++ b/packages/java-parser/package.json @@ -9,6 +9,7 @@ "types": "./api.d.ts", "dependencies": { "chevrotain": "11.0.3", + "chevrotain-allstar": "0.3.1", "lodash": "4.17.21" }, "scripts": { diff --git a/packages/java-parser/src/parser.js b/packages/java-parser/src/parser.js index 04a1a729..f2157776 100644 --- a/packages/java-parser/src/parser.js +++ b/packages/java-parser/src/parser.js @@ -1,4 +1,5 @@ import { CstParser, isRecognitionException } from "chevrotain"; +import { LLStarLookaheadStrategy } from "chevrotain-allstar"; import { allTokens, tokens as t } from "./tokens.js"; import * as lexicalStructure from "./productions/lexical-structure.js"; import * as typesValuesVariables from "./productions/types-values-and-variables.js"; @@ -38,7 +39,9 @@ import { shouldNotFormat } from "./comments.js"; export default class JavaParser extends CstParser { constructor() { super(allTokens, { - maxLookahead: 1, + lookaheadStrategy: new LLStarLookaheadStrategy({ + logging: getSkipValidations() ? () => {} : undefined + }), nodeLocationTracking: "full", // traceInitPerf: 2, skipValidations: getSkipValidations() diff --git a/packages/java-parser/src/productions/blocks-and-statements.js b/packages/java-parser/src/productions/blocks-and-statements.js index 80b9b27b..814cb266 100644 --- a/packages/java-parser/src/productions/blocks-and-statements.js +++ b/packages/java-parser/src/productions/blocks-and-statements.js @@ -23,25 +23,11 @@ export function defineRules($, t) { // https://docs.oracle.com/javase/specs/jls/se16/html/jls-14.html#jls-BlockStatement $.RULE("blockStatement", () => { - const isLocalVariableDeclaration = this.BACKTRACK_LOOKAHEAD( - $.isLocalVariableDeclaration - ); - - const isClassDeclaration = this.BACKTRACK_LOOKAHEAD($.isClassDeclaration); - $.OR({ DEF: [ - { - GATE: () => isLocalVariableDeclaration, - ALT: () => $.SUBRULE($.localVariableDeclarationStatement) - }, - { - GATE: () => isClassDeclaration, - ALT: () => $.SUBRULE($.classDeclaration) - }, - { - ALT: () => $.SUBRULE($.interfaceDeclaration) - }, + { ALT: () => $.SUBRULE($.localVariableDeclarationStatement) }, + { ALT: () => $.SUBRULE($.classDeclaration) }, + { ALT: () => $.SUBRULE($.interfaceDeclaration) }, { ALT: () => $.SUBRULE($.statement) } ], IGNORE_AMBIGUITIES: true @@ -76,19 +62,14 @@ export function defineRules($, t) { // https://docs.oracle.com/javase/specs/jls/se16/html/jls-14.html#jls-Statement $.RULE("statement", () => { - $.OR({ - DEF: [ - { - ALT: () => $.SUBRULE($.statementWithoutTrailingSubstatement) - }, - { ALT: () => $.SUBRULE($.labeledStatement) }, - // Spec deviation: combined "IfThenStatement" and "IfThenElseStatement" - { ALT: () => $.SUBRULE($.ifStatement) }, - { ALT: () => $.SUBRULE($.whileStatement) }, - { ALT: () => $.SUBRULE($.forStatement) } - ], - MAX_LOOKAHEAD: 2 - }); + $.OR([ + { ALT: () => $.SUBRULE($.statementWithoutTrailingSubstatement) }, + { ALT: () => $.SUBRULE($.labeledStatement) }, + // Spec deviation: combined "IfThenStatement" and "IfThenElseStatement" + { ALT: () => $.SUBRULE($.ifStatement) }, + { ALT: () => $.SUBRULE($.whileStatement) }, + { ALT: () => $.SUBRULE($.forStatement) } + ]); }); // https://docs.oracle.com/javase/specs/jls/se16/html/jls-14.html#jls-StatementWithoutTrailingSubstatement @@ -96,10 +77,7 @@ export function defineRules($, t) { $.OR({ DEF: [ { ALT: () => $.SUBRULE($.block) }, - { - GATE: () => this.BACKTRACK_LOOKAHEAD($.yieldStatement), - ALT: () => $.SUBRULE($.yieldStatement) - }, + { ALT: () => $.SUBRULE($.yieldStatement) }, { ALT: () => $.SUBRULE($.emptyStatement) }, { GATE: () => !tokenMatcher(this.LA(1).tokenType, t.Switch), @@ -186,13 +164,8 @@ export function defineRules($, t) { $.RULE("switchBlock", () => { $.CONSUME(t.LCurly); $.OR([ - { - GATE: () => this.BACKTRACK_LOOKAHEAD($.isClassicSwitchLabel), - ALT: () => $.MANY(() => $.SUBRULE($.switchBlockStatementGroup)) - }, - { - ALT: () => $.MANY2(() => $.SUBRULE($.switchRule)) - } + { ALT: () => $.MANY(() => $.SUBRULE($.switchBlockStatementGroup)) }, + { ALT: () => $.MANY2(() => $.SUBRULE($.switchRule)) } ]); $.CONSUME(t.RCurly); }); @@ -222,7 +195,6 @@ export function defineRules($, t) { } }, { - GATE: () => this.BACKTRACK_LOOKAHEAD($.pattern), ALT: () => { $.SUBRULE($.pattern); $.MANY(() => { @@ -294,10 +266,7 @@ export function defineRules($, t) { // https://docs.oracle.com/javase/specs/jls/se16/html/jls-14.html#jls-ForStatement $.RULE("forStatement", () => { $.OR([ - { - GATE: () => this.BACKTRACK_LOOKAHEAD($.isBasicForStatement), - ALT: () => $.SUBRULE($.basicForStatement) - }, + { ALT: () => $.SUBRULE($.basicForStatement) }, { ALT: () => $.SUBRULE($.enhancedForStatement) } ]); }); @@ -324,10 +293,7 @@ export function defineRules($, t) { // https://docs.oracle.com/javase/specs/jls/se16/html/jls-14.html#jls-ForInit $.RULE("forInit", () => { $.OR([ - { - GATE: () => $.BACKTRACK_LOOKAHEAD($.isLocalVariableDeclaration), - ALT: () => $.SUBRULE($.localVariableDeclaration) - }, + { ALT: () => $.SUBRULE($.localVariableDeclaration) }, { ALT: () => $.SUBRULE($.statementExpressionList) } ]); }); @@ -406,29 +372,26 @@ export function defineRules($, t) { // https://docs.oracle.com/javase/specs/jls/se16/html/jls-14.html#jls-TryStatement $.RULE("tryStatement", () => { - $.OR({ - DEF: [ - { - ALT: () => { - $.CONSUME(t.Try); - $.SUBRULE($.block); - $.OR2([ - { - ALT: () => { - $.SUBRULE($.catches); - $.OPTION(() => { - $.SUBRULE($.finally); - }); - } - }, - { ALT: () => $.SUBRULE2($.finally) } - ]); - } - }, - { ALT: () => $.SUBRULE($.tryWithResourcesStatement) } - ], - MAX_LOOKAHEAD: 2 - }); + $.OR([ + { + ALT: () => { + $.CONSUME(t.Try); + $.SUBRULE($.block); + $.OR2([ + { + ALT: () => { + $.SUBRULE($.catches); + $.OPTION(() => { + $.SUBRULE($.finally); + }); + } + }, + { ALT: () => $.SUBRULE2($.finally) } + ]); + } + }, + { ALT: () => $.SUBRULE($.tryWithResourcesStatement) } + ]); }); // https://docs.oracle.com/javase/specs/jls/se16/html/jls-14.html#jls-Catches @@ -510,10 +473,7 @@ export function defineRules($, t) { // https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-Resource $.RULE("resource", () => { $.OR([ - { - GATE: () => $.BACKTRACK_LOOKAHEAD($.isLocalVariableDeclaration), - ALT: () => $.SUBRULE($.localVariableDeclaration) - }, + { ALT: () => $.SUBRULE($.localVariableDeclaration) }, { ALT: () => $.SUBRULE($.variableAccess) } ]); }); @@ -532,45 +492,4 @@ export function defineRules($, t) { // TODO: verify that the primary is a fieldAccess or an expressionName. $.SUBRULE($.primary); }); - - // ------------------------------------ - // Special optimized backtracking rules. - // ------------------------------------ - $.RULE("isBasicForStatement", () => { - $.CONSUME(t.For); - $.CONSUME(t.LBrace); - $.OPTION(() => { - $.SUBRULE($.forInit); - }); - $.CONSUME(t.Semicolon); - // consuming the first semiColon distinguishes between - // "basic" and "enhanced" for statements - return true; - }); - - $.RULE("isLocalVariableDeclaration", () => { - $.MANY(() => { - $.SUBRULE($.variableModifier); - }); - $.SUBRULE($.localVariableType); - $.SUBRULE($.variableDeclaratorId); - - const nextTokenType = this.LA(1).tokenType; - switch (nextTokenType) { - // Int x; - case t.Semicolon: - // Int x, y, z; - case t.Comma: - // Int x = 5; - case t.Equals: - return true; - default: - return false; - } - }); - - $.RULE("isClassicSwitchLabel", () => { - $.SUBRULE($.switchLabel); - $.CONSUME(t.Colon); - }); } diff --git a/packages/java-parser/src/productions/classes.js b/packages/java-parser/src/productions/classes.js index df22b11e..bdd012ed 100644 --- a/packages/java-parser/src/productions/classes.js +++ b/packages/java-parser/src/productions/classes.js @@ -1,5 +1,4 @@ -import { isRecognitionException, tokenMatcher } from "chevrotain"; -import { classBodyTypes } from "./utils/class-body-types.js"; +import { tokenMatcher } from "chevrotain"; export function defineRules($, t) { // https://docs.oracle.com/javase/specs/jls/se16/html/jls-8.html#jls-ClassDeclaration @@ -111,54 +110,22 @@ export function defineRules($, t) { // https://docs.oracle.com/javase/specs/jls/se16/html/jls-8.html#jls-ClassBodyDeclaration $.RULE("classBodyDeclaration", () => { - const nextRuleType = $.BACKTRACK_LOOKAHEAD( - $.identifyClassBodyDeclarationType - ); - $.OR([ - { - GATE: () => - nextRuleType >= classBodyTypes.fieldDeclaration && - nextRuleType <= classBodyTypes.semiColon, - ALT: () => - $.SUBRULE($.classMemberDeclaration, { - ARGS: [nextRuleType] - }) - }, - // no gate needed for the initializers because these are LL(1) rules. + { ALT: () => $.SUBRULE($.classMemberDeclaration) }, { ALT: () => $.SUBRULE($.instanceInitializer) }, { ALT: () => $.SUBRULE($.staticInitializer) }, - { - GATE: () => - tokenMatcher(nextRuleType, classBodyTypes.constructorDeclaration), - ALT: () => $.SUBRULE($.constructorDeclaration) - } + { ALT: () => $.SUBRULE($.constructorDeclaration) } ]); }); // https://docs.oracle.com/javase/specs/jls/se16/html/jls-8.html#jls-ClassMemberDeclaration - $.RULE("classMemberDeclaration", nextRuleType => { + $.RULE("classMemberDeclaration", () => { $.OR([ - { - GATE: () => nextRuleType === classBodyTypes.fieldDeclaration, - ALT: () => $.SUBRULE($.fieldDeclaration) - }, - { - GATE: () => nextRuleType === classBodyTypes.methodDeclaration, - ALT: () => $.SUBRULE($.methodDeclaration) - }, - { - GATE: () => nextRuleType === classBodyTypes.classDeclaration, - ALT: () => $.SUBRULE($.classDeclaration) - }, - { - GATE: () => nextRuleType === classBodyTypes.interfaceDeclaration, - ALT: () => $.SUBRULE($.interfaceDeclaration) - }, - { - // No GATE is needed as this is LL(1) - ALT: () => $.CONSUME(t.Semicolon) - } + { ALT: () => $.SUBRULE($.fieldDeclaration) }, + { ALT: () => $.SUBRULE($.methodDeclaration) }, + { ALT: () => $.SUBRULE($.classDeclaration) }, + { ALT: () => $.SUBRULE($.interfaceDeclaration) }, + { ALT: () => $.CONSUME(t.Semicolon) } ]); }); @@ -392,10 +359,7 @@ export function defineRules($, t) { $.RULE("formalParameter", () => { $.OR([ // Spec Deviation: extracted to "variableParaRegularParameter" - { - GATE: $.BACKTRACK($.variableParaRegularParameter), - ALT: () => $.SUBRULE($.variableParaRegularParameter) - }, + { ALT: () => $.SUBRULE($.variableParaRegularParameter) }, { ALT: () => $.SUBRULE($.variableArityParameter) } ]); }); @@ -500,14 +464,9 @@ export function defineRules($, t) { }); $.SUBRULE($.simpleTypeName); $.CONSUME(t.LBrace); - $.OPTION2({ - // a "formalParameterList" and a "receiverParameter" - // cannot be distinguished using fixed lookahead. - GATE: $.BACKTRACK($.receiverParameter), - DEF: () => { - $.SUBRULE($.receiverParameter); - $.CONSUME(t.Comma); - } + $.OPTION2(() => { + $.SUBRULE($.receiverParameter); + $.CONSUME(t.Comma); }); $.OPTION3(() => { $.SUBRULE($.formalParameterList); @@ -524,11 +483,8 @@ export function defineRules($, t) { // https://docs.oracle.com/javase/specs/jls/se16/html/jls-8.html#jls-ConstructorBody $.RULE("constructorBody", () => { $.CONSUME(t.LCurly); - $.OPTION({ - GATE: $.BACKTRACK($.explicitConstructorInvocation), - DEF: () => { - $.SUBRULE($.explicitConstructorInvocation); - } + $.OPTION(() => { + $.SUBRULE($.explicitConstructorInvocation); }); $.OPTION2(() => { $.SUBRULE($.blockStatements); @@ -739,10 +695,7 @@ export function defineRules($, t) { // https://docs.oracle.com/javase/specs/jls/se16/html/jls-8.html#jls-RecordBodyDeclaration $.RULE("recordBodyDeclaration", () => { $.OR([ - { - GATE: () => this.BACKTRACK_LOOKAHEAD($.isCompactConstructorDeclaration), - ALT: () => $.SUBRULE($.compactConstructorDeclaration) - }, + { ALT: () => $.SUBRULE($.compactConstructorDeclaration) }, { ALT: () => $.SUBRULE($.classBodyDeclaration) } ]); }); @@ -756,178 +709,6 @@ export function defineRules($, t) { $.SUBRULE($.constructorBody); }); - $.RULE("isClassDeclaration", () => { - let isEmptyTypeDeclaration = false; - - if ( - $.OPTION(() => { - $.CONSUME(t.Semicolon); - }) - ) { - // an empty "TypeDeclaration" - isEmptyTypeDeclaration = true; - } - - try { - // The {classModifier} is a super grammar of the "interfaceModifier" - // So we must parse all the "{classModifier}" before we can distinguish - // between the alternatives. - $.MANY({ - GATE: () => - (tokenMatcher($.LA(1).tokenType, t.At) && - tokenMatcher($.LA(2).tokenType, t.Interface)) === false, - DEF: () => { - $.SUBRULE($.classModifier); - } - }); - } catch (e) { - if (isRecognitionException(e)) { - // TODO: add original syntax error? - throw "Cannot Identify if the is a or an "; - } else { - throw e; - } - } - - if (isEmptyTypeDeclaration) { - return false; - } - - const nextTokenType = this.LA(1).tokenType; - return ( - tokenMatcher(nextTokenType, t.Class) || - tokenMatcher(nextTokenType, t.Enum) || - (tokenMatcher(nextTokenType, t.Record) && - tokenMatcher(this.LA(2).tokenType, t.Identifier)) - ); - }); - - $.RULE("identifyClassBodyDeclarationType", () => { - try { - let nextTokenType = this.LA(1).tokenType; - let nextNextTokenType = this.LA(2).tokenType; - - switch (nextTokenType) { - case t.Semicolon: - return classBodyTypes.semiColon; - case t.LCurly: - return classBodyTypes.instanceInitializer; - case t.Static: - switch (nextNextTokenType) { - case t.LCurly: - return classBodyTypes.staticInitializer; - } - } - - // We have to look beyond the modifiers to distinguish between the declaration types. - $.MANY({ - GATE: () => - (tokenMatcher($.LA(1).tokenType, t.At) && - tokenMatcher($.LA(2).tokenType, t.Interface)) === false, - DEF: () => { - // This alternation includes all possible modifiers for all types of "ClassBodyDeclaration" - // Certain combinations are syntactically invalid, this is **not** checked here, - // Invalid combinations will cause a descriptive parsing error message to be - // Created inside the relevant parsing rules **after** this lookahead - // analysis. - $.OR([ - { - GATE: () => - (tokenMatcher($.LA(1).tokenType, t.At) && - tokenMatcher($.LA(2).tokenType, t.Interface)) === false, - ALT: () => $.SUBRULE($.annotation) - }, - { ALT: () => $.CONSUME(t.Public) }, - { ALT: () => $.CONSUME(t.Protected) }, - { ALT: () => $.CONSUME(t.Private) }, - { ALT: () => $.CONSUME(t.Abstract) }, - { ALT: () => $.CONSUME(t.Static) }, - { ALT: () => $.CONSUME(t.Final) }, - { ALT: () => $.CONSUME(t.Transient) }, - { ALT: () => $.CONSUME(t.Volatile) }, - { ALT: () => $.CONSUME(t.Synchronized) }, - { ALT: () => $.CONSUME(t.Native) }, - { ALT: () => $.CONSUME(t.Sealed) }, - { ALT: () => $.CONSUME(t.NonSealed) }, - { ALT: () => $.CONSUME(t.Strictfp) } - ]); - } - }); - - nextTokenType = this.LA(1).tokenType; - nextNextTokenType = this.LA(2).tokenType; - if ( - tokenMatcher(nextTokenType, t.Identifier) && - tokenMatcher(nextNextTokenType, t.LBrace) - ) { - return classBodyTypes.constructorDeclaration; - } - - if ( - tokenMatcher(nextTokenType, t.Class) || - tokenMatcher(nextTokenType, t.Enum) || - tokenMatcher(nextTokenType, t.Record) - ) { - return classBodyTypes.classDeclaration; - } - - if ( - tokenMatcher(nextTokenType, t.Interface) || - tokenMatcher(nextTokenType, t.At) - ) { - return classBodyTypes.interfaceDeclaration; - } - - if (tokenMatcher(nextTokenType, t.Void)) { - // method with result type "void" - return classBodyTypes.methodDeclaration; - } - - // Type Arguments common prefix - if (tokenMatcher(nextTokenType, t.Less)) { - this.SUBRULE($.typeParameters); - const nextTokenType = this.LA(1).tokenType; - const nextNextTokenType = this.LA(2).tokenType; - // " foo(" -> constructor - if ( - tokenMatcher(nextTokenType, t.Identifier) && - tokenMatcher(nextNextTokenType, t.LBrace) - ) { - return classBodyTypes.constructorDeclaration; - } - // typeParameters can only appear in method or constructor - // declarations, so if it is not a constructor it must be a method - return classBodyTypes.methodDeclaration; - } - - // Only field or method declarations may be valid at this point. - // All other alternatives should have been attempted. - // **both** start with "unannType" - this.SUBRULE($.unannType); - - const nextToken = this.LA(1); - nextNextTokenType = this.LA(2).tokenType; - // "foo(..." --> look like method start - if ( - tokenMatcher(nextToken, t.Identifier) && - tokenMatcher(nextNextTokenType, t.LBrace) - ) { - return classBodyTypes.methodDeclaration; - } - - // a valid field - // TODO: because we use token categories we should use tokenMatcher everywhere. - if (tokenMatcher(nextToken, t.Identifier)) { - return classBodyTypes.fieldDeclaration; - } - - return classBodyTypes.unknown; - } catch (e) { - // TODO: add info from the original error - throw Error("Cannot Identify the type of a "); - } - }); - $.RULE("isDims", () => { $.MANY($.annotation); return ( @@ -935,10 +716,4 @@ export function defineRules($, t) { tokenMatcher(this.LA(2).tokenType, t.RSquare) ); }); - - $.RULE("isCompactConstructorDeclaration", () => { - $.MANY($.constructorModifier); - $.SUBRULE($.simpleTypeName); - $.CONSUME(t.LCurly); - }); } diff --git a/packages/java-parser/src/productions/expressions.js b/packages/java-parser/src/productions/expressions.js index 087226ca..71b72c7b 100644 --- a/packages/java-parser/src/productions/expressions.js +++ b/packages/java-parser/src/productions/expressions.js @@ -2,10 +2,7 @@ import { tokenMatcher } from "chevrotain"; export function defineRules($, t) { $.RULE("expression", () => { $.OR([ - { - GATE: () => this.BACKTRACK_LOOKAHEAD($.isLambdaExpression), - ALT: () => $.SUBRULE($.lambdaExpression) - }, + { ALT: () => $.SUBRULE($.lambdaExpression) }, { ALT: () => $.SUBRULE($.ternaryExpression) } ]); }); @@ -68,13 +65,8 @@ export function defineRules($, t) { }); $.RULE("lambdaParameter", () => { - // TODO: performance, investigate the performance boost that could - // be gained by refactoring out the backtracking. $.OR([ - { - GATE: $.BACKTRACK($.regularLambdaParameter), - ALT: () => $.SUBRULE($.regularLambdaParameter) - }, + { ALT: () => $.SUBRULE($.regularLambdaParameter) }, { ALT: () => $.SUBRULE($.variableArityParameter) } ]); }); @@ -124,13 +116,8 @@ export function defineRules($, t) { ALT: () => { $.CONSUME(t.Instanceof); $.OR1([ - { - GATE: () => this.BACKTRACK_LOOKAHEAD($.pattern), - ALT: () => $.SUBRULE($.pattern) - }, - { - ALT: () => $.SUBRULE($.referenceType) - } + { ALT: () => $.SUBRULE($.pattern) }, + { ALT: () => $.SUBRULE($.referenceType) } ]); } }, @@ -214,21 +201,13 @@ export function defineRules($, t) { }); $.RULE("primaryPrefix", () => { - let isCastExpression = false; - if (tokenMatcher($.LA(1).tokenType, t.LBrace)) { - isCastExpression = this.BACKTRACK_LOOKAHEAD($.isCastExpression); - } - $.OR([ { ALT: () => $.SUBRULE($.literal) }, { ALT: () => $.CONSUME(t.This) }, { ALT: () => $.CONSUME(t.Void) }, { ALT: () => $.SUBRULE($.unannPrimitiveTypeWithOptionalDimsSuffix) }, { ALT: () => $.SUBRULE($.fqnOrRefType) }, - { - GATE: () => isCastExpression, - ALT: () => $.SUBRULE($.castExpression) - }, + { ALT: () => $.SUBRULE($.castExpression) }, { ALT: () => $.SUBRULE($.parenthesisExpression) }, { ALT: () => $.SUBRULE($.newExpression) }, { ALT: () => $.SUBRULE($.switchStatement) } @@ -236,35 +215,31 @@ export function defineRules($, t) { }); $.RULE("primarySuffix", () => { - $.OR({ - DEF: [ - { - ALT: () => { - $.CONSUME(t.Dot); - $.OR2([ - { ALT: () => $.CONSUME(t.This) }, - { - ALT: () => - $.SUBRULE($.unqualifiedClassInstanceCreationExpression) - }, - { - ALT: () => { - $.OPTION(() => { - $.SUBRULE($.typeArguments); - }); - $.CONSUME(t.Identifier); - } + $.OR([ + { + ALT: () => { + $.CONSUME(t.Dot); + $.OR2([ + { ALT: () => $.CONSUME(t.This) }, + { + ALT: () => $.SUBRULE($.unqualifiedClassInstanceCreationExpression) + }, + { + ALT: () => { + $.OPTION(() => { + $.SUBRULE($.typeArguments); + }); + $.CONSUME(t.Identifier); } - ]); - } - }, - { ALT: () => $.SUBRULE($.methodInvocationSuffix) }, - { ALT: () => $.SUBRULE($.classLiteralSuffix) }, - { ALT: () => $.SUBRULE($.arrayAccessSuffix) }, - { ALT: () => $.SUBRULE($.methodReferenceSuffix) } - ], - MAX_LOOKAHEAD: 2 - }); + } + ]); + } + }, + { ALT: () => $.SUBRULE($.methodInvocationSuffix) }, + { ALT: () => $.SUBRULE($.classLiteralSuffix) }, + { ALT: () => $.SUBRULE($.arrayAccessSuffix) }, + { ALT: () => $.SUBRULE($.methodReferenceSuffix) } + ]); }); // See https://github.com/jhipster/prettier-java/pull/154 to understand @@ -357,12 +332,7 @@ export function defineRules($, t) { $.RULE("castExpression", () => { $.OR([ - { - // TODO: performance: can avoid backtracking again here, parent rule could have this information - // when it checks isCastExpression (refactor needed) - GATE: () => this.BACKTRACK_LOOKAHEAD($.isPrimitiveCastExpression), - ALT: () => $.SUBRULE($.primitiveCastExpression) - }, + { ALT: () => $.SUBRULE($.primitiveCastExpression) }, { ALT: () => $.SUBRULE($.referenceTypeCastExpression) } ]); }); @@ -382,32 +352,15 @@ export function defineRules($, t) { }); $.CONSUME(t.RBrace); $.OR([ - { - GATE: () => this.BACKTRACK_LOOKAHEAD($.isLambdaExpression), - ALT: () => $.SUBRULE($.lambdaExpression) - }, + { ALT: () => $.SUBRULE($.lambdaExpression) }, { ALT: () => $.SUBRULE($.unaryExpressionNotPlusMinus) } ]); }); - const newExpressionTypes = { - arrayCreationExpression: 1, - unqualifiedClassInstanceCreationExpression: 2 - }; $.RULE("newExpression", () => { - const type = this.BACKTRACK_LOOKAHEAD($.identifyNewExpressionType); - $.OR([ - { - GATE: () => type === newExpressionTypes.arrayCreationExpression, - ALT: () => $.SUBRULE($.arrayCreationExpression) - }, - { - GATE: () => - type === - newExpressionTypes.unqualifiedClassInstanceCreationExpression, - ALT: () => $.SUBRULE($.unqualifiedClassInstanceCreationExpression) - } + { ALT: () => $.SUBRULE($.arrayCreationExpression) }, + { ALT: () => $.SUBRULE($.unqualifiedClassInstanceCreationExpression) } ]); }); @@ -446,13 +399,10 @@ export function defineRules($, t) { }); $.RULE("typeArgumentsOrDiamond", () => { - $.OR({ - DEF: [ - { ALT: () => $.SUBRULE($.diamond) }, - { ALT: () => $.SUBRULE($.typeArguments) } - ], - MAX_LOOKAHEAD: 2 - }); + $.OR([ + { ALT: () => $.SUBRULE($.diamond) }, + { ALT: () => $.SUBRULE($.typeArguments) } + ]); }); $.RULE("diamond", () => { @@ -480,18 +430,12 @@ export function defineRules($, t) { $.RULE("arrayCreationExpression", () => { $.CONSUME(t.New); $.OR([ - { - GATE: $.BACKTRACK($.primitiveType), - ALT: () => $.SUBRULE($.primitiveType) - }, + { ALT: () => $.SUBRULE($.primitiveType) }, { ALT: () => $.SUBRULE($.classOrInterfaceType) } ]); $.OR2([ - { - GATE: $.BACKTRACK($.arrayCreationDefaultInitSuffix), - ALT: () => $.SUBRULE($.arrayCreationDefaultInitSuffix) - }, + { ALT: () => $.SUBRULE($.arrayCreationDefaultInitSuffix) }, { ALT: () => $.SUBRULE($.arrayCreationExplicitInitSuffix) } ]); }); @@ -564,13 +508,8 @@ export function defineRules($, t) { // https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-Pattern $.RULE("pattern", () => { $.OR([ - { - GATE: () => this.BACKTRACK_LOOKAHEAD($.typePattern), - ALT: () => $.SUBRULE($.typePattern) - }, - { - ALT: () => $.SUBRULE($.recordPattern) - } + { ALT: () => $.SUBRULE($.typePattern) }, + { ALT: () => $.SUBRULE($.recordPattern) } ]); }); @@ -615,91 +554,6 @@ export function defineRules($, t) { $.SUBRULE($.expression); }); - // backtracking lookahead logic - $.RULE("identifyNewExpressionType", () => { - $.CONSUME(t.New); - const firstTokenAfterNew = this.LA(1).tokenType; - - // not an array initialization due to the prefix "TypeArguments" - if (tokenMatcher(firstTokenAfterNew, t.Less)) { - return newExpressionTypes.unqualifiedClassInstanceCreationExpression; - } - - try { - $.SUBRULE($.classOrInterfaceTypeToInstantiate); - } catch (e) { - // if it is not a "classOrInterfaceTypeToInstantiate" then - // (assuming a valid input) we are looking at an "arrayCreationExpression" - return newExpressionTypes.arrayCreationExpression; - } - - const firstTokenAfterClassType = this.LA(1).tokenType; - if (tokenMatcher(firstTokenAfterClassType, t.LBrace)) { - return newExpressionTypes.unqualifiedClassInstanceCreationExpression; - } - - // The LBrace above is mandatory in "classInstanceCreation..." so - // it must be an "arrayCreationExp" (if the input is valid) - // TODO: upgrade the logic to return "unknown" type if at this - // point it does not match "arrayCreation" either. - // - This will provide a better error message to the user - // in case of invalid inputs - return newExpressionTypes.arrayCreationExpression; - }); - - // Optimized backtracking, only scan ahead until the arrow("->"). - $.RULE("isLambdaExpression", () => { - // TODO: this check of next two tokens is probably redundant as the normal lookahead should take care of this. - const firstTokenType = this.LA(1).tokenType; - const secondTokenType = this.LA(2).tokenType; - // no parent lambda "x -> x * 2" - if ( - (tokenMatcher(firstTokenType, t.Identifier) || - tokenMatcher(firstTokenType, t.Underscore)) && - tokenMatcher(secondTokenType, t.Arrow) - ) { - return true; - } - // Performance optimizations, fail fast if it is not a LBrace. - else if (tokenMatcher(firstTokenType, t.LBrace)) { - $.SUBRULE($.lambdaParametersWithBraces); - const followedByArrow = tokenMatcher(this.LA(1).tokenType, t.Arrow); - return followedByArrow; - } - return false; - }); - - $.RULE("isCastExpression", () => { - if (this.BACKTRACK_LOOKAHEAD($.isPrimitiveCastExpression)) { - return true; - } - return this.BACKTRACK_LOOKAHEAD($.isReferenceTypeCastExpression); - }); - - $.RULE("isPrimitiveCastExpression", () => { - $.CONSUME(t.LBrace); - $.SUBRULE($.primitiveType); - // No dims so this is not a reference Type - $.CONSUME(t.RBrace); - return true; - }); - - $.RULE("isReferenceTypeCastExpression", () => { - $.CONSUME(t.LBrace); - $.SUBRULE($.referenceType); - $.MANY(() => { - $.SUBRULE($.additionalBound); - }); - $.CONSUME(t.RBrace); - const firstTokTypeAfterRBrace = this.LA(1).tokenType; - - return ( - this.firstForUnaryExpressionNotPlusMinus.find(tokType => - tokenMatcher(firstTokTypeAfterRBrace, tokType) - ) !== undefined - ); - }); - $.RULE("isRefTypeInMethodRef", () => { let result = undefined; $.SUBRULE($.typeArguments); diff --git a/packages/java-parser/src/productions/interfaces.js b/packages/java-parser/src/productions/interfaces.js index 65f09dbc..1362d368 100644 --- a/packages/java-parser/src/productions/interfaces.js +++ b/packages/java-parser/src/productions/interfaces.js @@ -4,11 +4,8 @@ export function defineRules($, t) { // https://docs.oracle.com/javase/specs/jls/se16/html/jls-9.html#jls-InterfaceDeclaration $.RULE("interfaceDeclaration", () => { // Spec Deviation: extracted the common "interfaceModifier" prefix to avoid backtracking. - $.MANY({ - DEF: () => { - $.SUBRULE($.interfaceModifier); - }, - MAX_LOOKAHEAD: 2 + $.MANY(() => { + $.SUBRULE($.interfaceModifier); }); $.OR([ @@ -74,43 +71,14 @@ export function defineRules($, t) { $.CONSUME(t.RCurly); }); - const InterfaceBodyTypes = { - unknown: 0, - constantDeclaration: 1, - interfaceMethodDeclaration: 2, - classDeclaration: 3, - interfaceDeclaration: 4, - semiColon: 5 - }; - // https://docs.oracle.com/javase/specs/jls/se16/html/jls-9.html#jls-InterfaceMemberDeclaration $.RULE("interfaceMemberDeclaration", () => { - const detectedType = this.BACKTRACK_LOOKAHEAD( - $.identifyInterfaceBodyDeclarationType - ); - $.OR([ - { - GATE: () => detectedType === InterfaceBodyTypes.constantDeclaration, - ALT: () => $.SUBRULE($.constantDeclaration) - }, - { - GATE: () => - detectedType === InterfaceBodyTypes.interfaceMethodDeclaration, - ALT: () => $.SUBRULE($.interfaceMethodDeclaration) - }, - { - GATE: () => detectedType === InterfaceBodyTypes.classDeclaration, - ALT: () => $.SUBRULE($.classDeclaration) - }, - { - GATE: () => detectedType === InterfaceBodyTypes.interfaceDeclaration, - ALT: () => $.SUBRULE($.interfaceDeclaration) - }, - { - // No GATE is needed as this is LL(1) - ALT: () => $.CONSUME(t.Semicolon) - } + { ALT: () => $.SUBRULE($.constantDeclaration) }, + { ALT: () => $.SUBRULE($.interfaceMethodDeclaration) }, + { ALT: () => $.SUBRULE($.classDeclaration) }, + { ALT: () => $.SUBRULE($.interfaceDeclaration) }, + { ALT: () => $.CONSUME(t.Semicolon) } ]); }); @@ -174,43 +142,14 @@ export function defineRules($, t) { $.CONSUME(t.RCurly); }); - const AnnotationBodyTypes = { - unknown: 0, - annotationTypeElementDeclaration: 2, - constantDeclaration: 1, - classDeclaration: 3, - interfaceDeclaration: 4, - semiColon: 5 - }; - // https://docs.oracle.com/javase/specs/jls/se16/html/jls-9.html#jls-InterfaceMemberDeclaration $.RULE("annotationTypeMemberDeclaration", () => { - const detectedType = this.BACKTRACK_LOOKAHEAD( - $.identifyAnnotationBodyDeclarationType - ); - $.OR([ - { - GATE: () => - detectedType === AnnotationBodyTypes.annotationTypeElementDeclaration, - ALT: () => $.SUBRULE($.annotationTypeElementDeclaration) - }, - { - GATE: () => detectedType === AnnotationBodyTypes.constantDeclaration, - ALT: () => $.SUBRULE($.constantDeclaration) - }, - { - GATE: () => detectedType === AnnotationBodyTypes.classDeclaration, - ALT: () => $.SUBRULE($.classDeclaration) - }, - { - GATE: () => detectedType === AnnotationBodyTypes.interfaceDeclaration, - ALT: () => $.SUBRULE($.interfaceDeclaration) - }, - { - // No GATE is needed as this is LL(1) - ALT: () => $.CONSUME(t.Semicolon) - } + { ALT: () => $.SUBRULE($.annotationTypeElementDeclaration) }, + { ALT: () => $.SUBRULE($.constantDeclaration) }, + { ALT: () => $.SUBRULE($.classDeclaration) }, + { ALT: () => $.SUBRULE($.interfaceDeclaration) }, + { ALT: () => $.CONSUME(t.Semicolon) } ]); }); @@ -272,8 +211,7 @@ export function defineRules($, t) { } } ], - IGNORE_AMBIGUITIES: true, - MAX_LOOKAHEAD: 2 + IGNORE_AMBIGUITIES: true }); $.CONSUME(t.RBrace); }); @@ -296,22 +234,12 @@ export function defineRules($, t) { // https://docs.oracle.com/javase/specs/jls/se16/html/jls-9.html#jls-ElementValue $.RULE("elementValue", () => { - const isSimpleElementValueAnnotation = this.BACKTRACK_LOOKAHEAD( - $.isSimpleElementValueAnnotation - ); - $.OR([ // Spec Deviation: "conditionalExpression" replaced with "expression" // Because we cannot differentiate between the two using fixed lookahead. - { - GATE: () => isSimpleElementValueAnnotation === false, - ALT: () => $.SUBRULE($.expression) - }, + { ALT: () => $.SUBRULE($.expression) }, { ALT: () => $.SUBRULE($.elementValueArrayInitializer) }, - { - GATE: () => isSimpleElementValueAnnotation === true, - ALT: () => $.SUBRULE($.annotation) - } + { ALT: () => $.SUBRULE($.annotation) } ]); }); @@ -338,167 +266,4 @@ export function defineRules($, t) { } }); }); - - // ------------------------------------ - // Special optimized backtracking rules. - // ------------------------------------ - $.RULE("identifyInterfaceBodyDeclarationType", () => { - let nextTokenType = this.LA(1).tokenType; - if (tokenMatcher(nextTokenType, t.Semicolon)) { - return InterfaceBodyTypes.semiColon; - } - - // We have to look beyond the modifiers to distinguish between the declaration types. - $.MANY({ - // To avoid ambiguity with @interface ("AnnotationTypeDeclaration" vs "Annotaion") - GATE: () => - (tokenMatcher($.LA(1).tokenType, t.At) && - tokenMatcher($.LA(2).tokenType, t.Interface)) === false, - DEF: () => { - // This alternation includes all possible modifiers for all types of "interfaceMemberDeclaration" - // Certain combinations are syntactically invalid, this is **not** checked here, - // Invalid combinations will cause a descriptive parsing error message to be - // Created inside the relevant parsing rules **after** this lookahead - // analysis. - $.OR([ - { ALT: () => $.SUBRULE($.annotation) }, - { ALT: () => $.CONSUME(t.Public) }, - { ALT: () => $.CONSUME(t.Protected) }, - { ALT: () => $.CONSUME(t.Private) }, - { ALT: () => $.CONSUME(t.Abstract) }, - { ALT: () => $.CONSUME(t.Static) }, - { ALT: () => $.CONSUME(t.Sealed) }, - { ALT: () => $.CONSUME(t.NonSealed) }, - { ALT: () => $.CONSUME(t.Strictfp) }, - { ALT: () => $.CONSUME(t.Final) }, - { ALT: () => $.CONSUME(t.Default) } - ]); - } - }); - - nextTokenType = this.LA(1).tokenType; - if ( - tokenMatcher(nextTokenType, t.Class) || - tokenMatcher(nextTokenType, t.Enum) || - tokenMatcher(nextTokenType, t.Record) - ) { - return InterfaceBodyTypes.classDeclaration; - } - if ( - tokenMatcher(nextTokenType, t.Interface) || - tokenMatcher(nextTokenType, t.At) - ) { - return InterfaceBodyTypes.interfaceDeclaration; - } - if ( - tokenMatcher(nextTokenType, t.Void) || - tokenMatcher(nextTokenType, t.Less) - ) { - // method with result type "void" - return InterfaceBodyTypes.interfaceMethodDeclaration; - } - - // Only constant or interfaceMethod declarations may be valid at this point. - // All other alternatives should have been attempted. - // **both** start with "unannType" - this.SUBRULE($.unannType); - - const nextToken = this.LA(1); - const nextNextTokenType = this.LA(2).tokenType; - // "foo(..." --> look like method start - if ( - tokenMatcher(nextToken, t.Identifier) && - tokenMatcher(nextNextTokenType, t.LBrace) - ) { - return InterfaceBodyTypes.interfaceMethodDeclaration; - } - // a valid constant - if (tokenMatcher(nextToken, t.Identifier)) { - return InterfaceBodyTypes.constantDeclaration; - } - return InterfaceBodyTypes.unknown; - }); - - $.RULE("identifyAnnotationBodyDeclarationType", () => { - let nextTokenType = this.LA(1).tokenType; - if (tokenMatcher(nextTokenType, t.Semicolon)) { - return AnnotationBodyTypes.semiColon; - } - - // We have to look beyond the modifiers to distinguish between the declaration types. - $.MANY({ - // To avoid ambiguity with @interface ("AnnotationTypeDeclaration" vs "Annotaion") - GATE: () => - (tokenMatcher($.LA(1).tokenType, t.At) && - tokenMatcher($.LA(2).tokenType, t.Interface)) === false, - DEF: () => { - // This alternation includes all possible modifiers for all types of "annotationTypeMemberDeclaration" - // Certain combinations are syntactically invalid, this is **not** checked here, - // Invalid combinations will cause a descriptive parsing error message to be - // Created inside the relevant parsing rules **after** this lookahead - // analysis. - $.OR([ - { ALT: () => $.SUBRULE($.annotation) }, - { ALT: () => $.CONSUME(t.Public) }, - { ALT: () => $.CONSUME(t.Protected) }, - { ALT: () => $.CONSUME(t.Private) }, - { ALT: () => $.CONSUME(t.Abstract) }, - { ALT: () => $.CONSUME(t.Static) }, - { ALT: () => $.CONSUME(t.Final) }, - { ALT: () => $.CONSUME(t.Strictfp) } - ]); - } - }); - - nextTokenType = this.LA(1).tokenType; - if ( - tokenMatcher(nextTokenType, t.Class) || - tokenMatcher(nextTokenType, t.Enum) - ) { - return AnnotationBodyTypes.classDeclaration; - } - if ( - tokenMatcher(nextTokenType, t.Interface) || - tokenMatcher(nextTokenType, t.At) - ) { - return AnnotationBodyTypes.interfaceDeclaration; - } - - // Only constant or annotationTypeElement declarations may be valid at this point. - // All other alternatives should have been attempted. - // **both** start with "unannType" - this.SUBRULE($.unannType); - - nextTokenType = this.LA(1).tokenType; - const nextNextTokenType = this.LA(2).tokenType; - // "foo(..." --> look like annotationTypeElement start - if ( - tokenMatcher(nextTokenType, t.Identifier) && - tokenMatcher(nextNextTokenType, t.LBrace) - ) { - return AnnotationBodyTypes.annotationTypeElementDeclaration; - } - // a valid constant - if (tokenMatcher(nextTokenType, t.Identifier)) { - return AnnotationBodyTypes.constantDeclaration; - } - return AnnotationBodyTypes.unknown; - }); - - $.RULE("isSimpleElementValueAnnotation", () => { - $.SUBRULE($.annotation); - const nextTokenType = this.LA(1).tokenType; - switch (nextTokenType) { - // annotation in "ElementValue" would be followed by one of those - // any other TokenType would indicate it is an annotation in a "referenceType" - // as part of a "methodReference" in "primary" - case t.Comma: - case t.Semicolon: - case t.RCurly: - case t.RBrace: - return true; - default: - return false; - } - }); } diff --git a/packages/java-parser/src/productions/packages-and-modules.js b/packages/java-parser/src/productions/packages-and-modules.js index 536c65fd..0d31df26 100644 --- a/packages/java-parser/src/productions/packages-and-modules.js +++ b/packages/java-parser/src/productions/packages-and-modules.js @@ -1,5 +1,4 @@ -import { isRecognitionException, tokenMatcher, EOF } from "chevrotain"; -import { classBodyTypes } from "./utils/class-body-types.js"; +import { tokenMatcher, EOF } from "chevrotain"; export function defineRules($, t) { /** @@ -11,17 +10,9 @@ export function defineRules($, t) { * 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); - $.OR([ - { - GATE: () => isModule === false, - ALT: () => $.SUBRULE($.ordinaryCompilationUnit) - }, - { - ALT: () => $.SUBRULE($.modularCompilationUnit) - } + { ALT: () => $.SUBRULE($.ordinaryCompilationUnit) }, + { ALT: () => $.SUBRULE($.modularCompilationUnit) } ]); // https://github.com/jhipster/prettier-java/pull/217 $.CONSUME(EOF); @@ -29,12 +20,7 @@ export function defineRules($, t) { // https://docs.oracle.com/javase/specs/jls/se16/html/jls-7.html#jls-OrdinaryCompilationUnit $.RULE("ordinaryCompilationUnit", () => { - $.OPTION({ - GATE: $.BACKTRACK($.packageDeclaration), - DEF: () => { - $.SUBRULE($.packageDeclaration); - } - }); + $.OPTION(() => $.SUBRULE($.packageDeclaration)); $.MANY(() => { $.SUBRULE3($.importDeclaration); }); @@ -114,28 +100,12 @@ export function defineRules($, t) { * 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 nextRuleType = $.BACKTRACK_LOOKAHEAD( - $.identifyClassBodyDeclarationType - ); - $.OR([ { ALT: () => $.CONSUME(t.Semicolon) }, - { - GATE: () => nextRuleType === classBodyTypes.classDeclaration, - ALT: () => $.SUBRULE($.classDeclaration) - }, - { - GATE: () => nextRuleType === classBodyTypes.interfaceDeclaration, - ALT: () => $.SUBRULE($.interfaceDeclaration) - }, - { - GATE: () => nextRuleType === classBodyTypes.fieldDeclaration, - ALT: () => $.SUBRULE($.fieldDeclaration) - }, - { - ALT: () => $.SUBRULE($.methodDeclaration) - } + { ALT: () => $.SUBRULE($.classDeclaration) }, + { ALT: () => $.SUBRULE($.interfaceDeclaration) }, + { ALT: () => $.SUBRULE($.fieldDeclaration) }, + { ALT: () => $.SUBRULE($.methodDeclaration) } ]); }); @@ -254,45 +224,4 @@ export function defineRules($, t) { { ALT: () => $.CONSUME(t.Static) } ]); }); - - $.RULE("isModuleCompilationUnit", () => { - $.OPTION(() => { - $.SUBRULE($.packageDeclaration); - // TODO: this return must be outside the OPTION at the top level rule - // a Java Module source code may not contain a package declaration. - return false; - }); - - try { - // the "{importDeclaration}" is a common prefix - $.MANY(() => { - $.SUBRULE2($.importDeclaration); - }); - - $.MANY2({ - // To avoid ambiguity with @interface ("AnnotationTypeDeclaration" vs "Annotaion") - GATE: () => - (tokenMatcher($.LA(1).tokenType, t.At) && - tokenMatcher($.LA(2).tokenType, t.Interface)) === false, - DEF: () => { - $.SUBRULE($.annotation); - } - }); - } catch (e) { - // This means we had a syntax error in the imports or annotations - // So we can't keep parsing deep enough to make the decision - if (isRecognitionException(e)) { - // TODO: add original syntax error? - throw "Cannot Identify if the source code is an OrdinaryCompilationUnit or ModularCompilationUnit"; - } else { - throw e; - } - } - - const nextTokenType = this.LA(1).tokenType; - return ( - tokenMatcher(nextTokenType, t.Open) || - tokenMatcher(nextTokenType, t.Module) - ); - }); } diff --git a/packages/java-parser/src/productions/types-values-and-variables.js b/packages/java-parser/src/productions/types-values-and-variables.js index 9e43128b..12589041 100644 --- a/packages/java-parser/src/productions/types-values-and-variables.js +++ b/packages/java-parser/src/productions/types-values-and-variables.js @@ -1,5 +1,3 @@ -import { tokenMatcher } from "chevrotain"; - export function defineRules($, t) { // --------------------- // Productions from ยง4 (Types, Values, and Variables) @@ -102,15 +100,7 @@ export function defineRules($, t) { }); // TODO: Semantic Check: This Identifier cannot be "var" $.CONSUME2(t.Identifier); - $.OPTION2({ - // To avoid confusion with "TypeArgumentsOrDiamond" rule - // as we use the "classType" rule in the "identifyNewExpressionType" - // optimized lookahead rule. - GATE: () => tokenMatcher($.LA(2).tokenType, t.Greater) === false, - DEF: () => { - $.SUBRULE2($.typeArguments); - } - }); + $.OPTION2(() => $.SUBRULE2($.typeArguments)); }); }); @@ -199,10 +189,7 @@ export function defineRules($, t) { $.RULE("typeArgument", () => { // TODO: performance: evaluate flipping the order of alternatives $.OR([ - { - GATE: $.BACKTRACK($.referenceType), - ALT: () => $.SUBRULE($.referenceType) - }, + { ALT: () => $.SUBRULE($.referenceType) }, { ALT: () => $.SUBRULE($.wildcard) } ]); }); diff --git a/packages/java-parser/src/productions/utils/class-body-types.js b/packages/java-parser/src/productions/utils/class-body-types.js deleted file mode 100644 index d92404b6..00000000 --- a/packages/java-parser/src/productions/utils/class-body-types.js +++ /dev/null @@ -1,11 +0,0 @@ -export const classBodyTypes = { - unknown: 0, - fieldDeclaration: 1, - methodDeclaration: 2, - classDeclaration: 3, - interfaceDeclaration: 4, - semiColon: 5, - instanceInitializer: 6, - staticInitializer: 7, - constructorDeclaration: 8 -}; diff --git a/packages/prettier-plugin-java/src/options.js b/packages/prettier-plugin-java/src/options.js index 2eea5086..0822dd65 100644 --- a/packages/prettier-plugin-java/src/options.js +++ b/packages/prettier-plugin-java/src/options.js @@ -52,9 +52,6 @@ export default { { value: "resource" }, { value: "yieldStatement" }, { value: "variableAccess" }, - { value: "isBasicForStatement" }, - { value: "isLocalVariableDeclaration" }, - { value: "isClassicSwitchLabel" }, { value: "classDeclaration" }, { value: "normalClassDeclaration" }, { value: "classModifier" }, @@ -121,10 +118,7 @@ export default { { value: "recordBody" }, { value: "recordBodyDeclaration" }, { value: "compactConstructorDeclaration" }, - { value: "isClassDeclaration" }, - { value: "identifyClassBodyDeclarationType" }, { value: "isDims" }, - { value: "isCompactConstructorDeclaration" }, { value: "expression" }, { value: "lambdaExpression" }, { value: "lambdaParameters" }, @@ -173,11 +167,6 @@ export default { { value: "componentPattern" }, { value: "unnamedPattern" }, { value: "guard" }, - { value: "identifyNewExpressionType" }, - { value: "isLambdaExpression" }, - { value: "isCastExpression" }, - { value: "isPrimitiveCastExpression" }, - { value: "isReferenceTypeCastExpression" }, { value: "isRefTypeInMethodRef" }, { value: "interfaceDeclaration" }, { value: "normalInterfaceDeclaration" }, @@ -202,9 +191,6 @@ export default { { value: "elementValue" }, { value: "elementValueArrayInitializer" }, { value: "elementValueList" }, - { value: "identifyInterfaceBodyDeclarationType" }, - { value: "identifyAnnotationBodyDeclarationType" }, - { value: "isSimpleElementValueAnnotation" }, { value: "literal" }, { value: "integerLiteral" }, { value: "floatingPointLiteral" }, @@ -231,7 +217,6 @@ export default { { value: "usesModuleDirective" }, { value: "providesModuleDirective" }, { value: "requiresModifier" }, - { value: "isModuleCompilationUnit" }, { value: "primitiveType" }, { value: "numericType" }, { value: "integralType" }, diff --git a/packages/prettier-plugin-java/src/printers/blocks-and-statements.ts b/packages/prettier-plugin-java/src/printers/blocks-and-statements.ts index 6da0538d..0432964a 100644 --- a/packages/prettier-plugin-java/src/printers/blocks-and-statements.ts +++ b/packages/prettier-plugin-java/src/printers/blocks-and-statements.ts @@ -607,16 +607,4 @@ export class BlocksAndStatementPrettierVisitor extends BaseCstPrettierPrinter { variableAccess(ctx: VariableAccessCtx) { return this.visitSingle(ctx); } - - isBasicForStatement() { - return "isBasicForStatement"; - } - - isLocalVariableDeclaration() { - return "isLocalVariableDeclaration"; - } - - isClassicSwitchLabel() { - return "isClassicSwitchLabel"; - } } diff --git a/packages/prettier-plugin-java/src/printers/classes.ts b/packages/prettier-plugin-java/src/printers/classes.ts index 180a3c27..8e19acb8 100644 --- a/packages/prettier-plugin-java/src/printers/classes.ts +++ b/packages/prettier-plugin-java/src/printers/classes.ts @@ -1052,19 +1052,7 @@ export class ClassesPrettierVisitor extends BaseCstPrettierPrinter { ]); } - isClassDeclaration() { - return "isClassDeclaration"; - } - - identifyClassBodyDeclarationType() { - return "identifyClassBodyDeclarationType"; - } - isDims() { return "isDims"; } - - isCompactConstructorDeclaration() { - return "isCompactConstructorDeclaration"; - } } diff --git a/packages/prettier-plugin-java/src/printers/expressions.ts b/packages/prettier-plugin-java/src/printers/expressions.ts index 72a15bb8..25ded33b 100644 --- a/packages/prettier-plugin-java/src/printers/expressions.ts +++ b/packages/prettier-plugin-java/src/printers/expressions.ts @@ -760,26 +760,6 @@ export class ExpressionsPrettierVisitor extends BaseCstPrettierPrinter { return concat([ctx.When[0], " ", expression]); } - identifyNewExpressionType() { - return "identifyNewExpressionType"; - } - - isLambdaExpression() { - return "isLambdaExpression"; - } - - isCastExpression() { - return "isCastExpression"; - } - - isPrimitiveCastExpression() { - return "isPrimitiveCastExpression"; - } - - isReferenceTypeCastExpression() { - return "isReferenceTypeCastExpression"; - } - isRefTypeInMethodRef() { return "isRefTypeInMethodRef"; } diff --git a/packages/prettier-plugin-java/src/printers/interfaces.ts b/packages/prettier-plugin-java/src/printers/interfaces.ts index eb5950bb..1daf4737 100644 --- a/packages/prettier-plugin-java/src/printers/interfaces.ts +++ b/packages/prettier-plugin-java/src/printers/interfaces.ts @@ -334,16 +334,4 @@ export class InterfacesPrettierVisitor extends BaseCstPrettierPrinter { return group(rejectAndConcat([rejectAndJoinSeps(commas, elementValues)])); } - - identifyInterfaceBodyDeclarationType() { - return "identifyInterfaceBodyDeclarationType"; - } - - identifyAnnotationBodyDeclarationType() { - return "identifyAnnotationBodyDeclarationType"; - } - - isSimpleElementValueAnnotation() { - return "isSimpleElementValueAnnotation"; - } } diff --git a/packages/prettier-plugin-java/src/printers/packages-and-modules.ts b/packages/prettier-plugin-java/src/printers/packages-and-modules.ts index 1121e85a..8698627f 100644 --- a/packages/prettier-plugin-java/src/printers/packages-and-modules.ts +++ b/packages/prettier-plugin-java/src/printers/packages-and-modules.ts @@ -256,8 +256,4 @@ export class PackagesAndModulesPrettierVisitor extends BaseCstPrettierPrinter { requiresModifier(ctx: RequiresModifierCtx) { return printTokenWithComments(this.getSingle(ctx) as IToken); } - - isModuleCompilationUnit() { - return "isModuleCompilationUnit"; - } } diff --git a/yarn.lock b/yarn.lock index 7177688a..582196ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2044,6 +2044,13 @@ check-error@^1.0.3: dependencies: get-func-name "^2.0.2" +chevrotain-allstar@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz#b7412755f5d83cc139ab65810cdb00d8db40e6ca" + integrity sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw== + dependencies: + lodash-es "^4.17.21" + chevrotain@11.0.3: version "11.0.3" resolved "https://registry.yarnpkg.com/chevrotain/-/chevrotain-11.0.3.tgz#88ffc1fb4b5739c715807eaeedbbf200e202fc1b" @@ -4062,7 +4069,7 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash-es@4.17.21: +lodash-es@4.17.21, lodash-es@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==