java-parser
Advanced tools
Comparing version
{ | ||
"name": "java-parser", | ||
"version": "2.2.0", | ||
"version": "2.3.0", | ||
"description": "Java Parser in JavaScript", | ||
"main": "src/index.js", | ||
"type": "module", | ||
"exports": "./src/index.js", | ||
"repository": "https://github.com/jhipster/prettier-java/tree/main/packages/java-parser", | ||
@@ -10,3 +11,4 @@ "license": "Apache-2.0", | ||
"dependencies": { | ||
"chevrotain": "6.5.0", | ||
"chevrotain": "11.0.3", | ||
"chevrotain-allstar": "0.3.1", | ||
"lodash": "4.17.21" | ||
@@ -19,3 +21,3 @@ }, | ||
}, | ||
"gitHead": "00a8585d20c56d933ce4c89dcb532d9e98d1a4cf" | ||
"gitHead": "30e1cad12e8936df43c25eeb9dad5aef20d9af6c" | ||
} |
@@ -1,5 +0,3 @@ | ||
"use strict"; | ||
import findLast from "lodash/findLast.js"; | ||
const findLast = require("lodash/findLast"); | ||
/** | ||
@@ -168,3 +166,3 @@ * Search where is the position of the comment in the token array by | ||
*/ | ||
function attachComments( | ||
export function attachComments( | ||
tokens, | ||
@@ -260,3 +258,3 @@ comments, | ||
*/ | ||
function matchFormatterOffOnPairs(comments) { | ||
export function matchFormatterOffOnPairs(comments) { | ||
const onOffComments = comments.filter(comment => | ||
@@ -300,3 +298,3 @@ isFormatterOffOnComment(comment) | ||
*/ | ||
function shouldNotFormat(node, commentPairs) { | ||
export function shouldNotFormat(node, commentPairs) { | ||
const matchingPair = findLast( | ||
@@ -314,7 +312,1 @@ commentPairs, | ||
} | ||
module.exports = { | ||
matchFormatterOffOnPairs, | ||
shouldNotFormat, | ||
attachComments | ||
}; |
@@ -1,13 +0,12 @@ | ||
"use strict"; | ||
const JavaLexer = require("./lexer"); | ||
const JavaParser = require("./parser"); | ||
const { attachComments, matchFormatterOffOnPairs } = require("./comments"); | ||
import JavaLexer from "./lexer.js"; | ||
import JavaParser from "./parser.js"; | ||
import { attachComments, matchFormatterOffOnPairs } from "./comments.js"; | ||
const parser = new JavaParser(); | ||
const BaseJavaCstVisitor = parser.getBaseCstVisitorConstructor(); | ||
const BaseJavaCstVisitorWithDefaults = | ||
export const BaseJavaCstVisitor = parser.getBaseCstVisitorConstructor(); | ||
export const BaseJavaCstVisitorWithDefaults = | ||
parser.getBaseCstVisitorConstructorWithDefaults(); | ||
function lexAndParse(inputText, entryPoint = "compilationUnit") { | ||
export function lexAndParse(inputText, entryPoint = "compilationUnit") { | ||
// Lex | ||
@@ -64,7 +63,7 @@ const lexResult = JavaLexer.tokenize(inputText); | ||
function parse(inputText, entryPoint = "compilationUnit") { | ||
export function parse(inputText, entryPoint = "compilationUnit") { | ||
return lexAndParse(inputText, entryPoint).cst; | ||
} | ||
module.exports = { | ||
export default { | ||
lexAndParse, | ||
@@ -71,0 +70,0 @@ parse, |
@@ -1,12 +0,8 @@ | ||
"use strict"; | ||
const chevrotain = require("chevrotain"); | ||
const { allTokens } = require("./tokens"); | ||
const { getSkipValidations } = require("./utils"); | ||
import { Lexer } from "chevrotain"; | ||
import { allTokens } from "./tokens.js"; | ||
import { getSkipValidations } from "./utils.js"; | ||
const Lexer = chevrotain.Lexer; | ||
const JavaLexer = new Lexer(allTokens, { | ||
export default new Lexer(allTokens, { | ||
ensureOptimizations: true, | ||
skipValidations: getSkipValidations() | ||
}); | ||
module.exports = JavaLexer; |
@@ -1,15 +0,15 @@ | ||
"use strict"; | ||
const { Parser, isRecognitionException } = require("chevrotain"); | ||
const { allTokens, tokens: t } = require("./tokens"); | ||
const lexicalStructure = require("./productions/lexical-structure"); | ||
const typesValuesVariables = require("./productions/types-values-and-variables"); | ||
const names = require("./productions/names"); | ||
const packagesModules = require("./productions/packages-and-modules"); | ||
const classes = require("./productions/classes"); | ||
const interfaces = require("./productions/interfaces"); | ||
const arrays = require("./productions/arrays"); | ||
const blocksStatements = require("./productions/blocks-and-statements"); | ||
const expressions = require("./productions/expressions"); | ||
const { getSkipValidations } = require("./utils"); | ||
const { shouldNotFormat } = require("./comments"); | ||
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"; | ||
import * as names from "./productions/names.js"; | ||
import * as packagesModules from "./productions/packages-and-modules.js"; | ||
import * as classes from "./productions/classes.js"; | ||
import * as interfaces from "./productions/interfaces.js"; | ||
import * as arrays from "./productions/arrays.js"; | ||
import * as blocksStatements from "./productions/blocks-and-statements.js"; | ||
import * as expressions from "./productions/expressions.js"; | ||
import { getSkipValidations } from "./utils.js"; | ||
import { shouldNotFormat } from "./comments.js"; | ||
@@ -39,6 +39,8 @@ /** | ||
*/ | ||
class JavaParser extends Parser { | ||
export default class JavaParser extends CstParser { | ||
constructor() { | ||
super(allTokens, { | ||
maxLookahead: 1, | ||
lookaheadStrategy: new LLStarLookaheadStrategy({ | ||
logging: getSkipValidations() ? () => {} : undefined | ||
}), | ||
nodeLocationTracking: "full", | ||
@@ -81,12 +83,12 @@ // traceInitPerf: 2, | ||
cstPostNonTerminal(ruleCstResult, ruleName) { | ||
if (this.isBackTracking()) { | ||
return; | ||
} | ||
super.cstPostNonTerminal(ruleCstResult, ruleName); | ||
if (this.isBackTracking() === false) { | ||
this.mostEnclosiveCstNodeByStartOffset[ | ||
ruleCstResult.location.startOffset | ||
] = ruleCstResult; | ||
this.mostEnclosiveCstNodeByEndOffset[ruleCstResult.location.endOffset] = | ||
ruleCstResult; | ||
this.mostEnclosiveCstNodeByStartOffset[ruleCstResult.location.startOffset] = | ||
ruleCstResult; | ||
this.mostEnclosiveCstNodeByEndOffset[ruleCstResult.location.endOffset] = | ||
ruleCstResult; | ||
shouldNotFormat(ruleCstResult, this.onOffCommentPairs); | ||
} | ||
shouldNotFormat(ruleCstResult, this.onOffCommentPairs); | ||
} | ||
@@ -100,5 +102,16 @@ | ||
try { | ||
// hack to enable outputting none CST values from grammar rules. | ||
this.outputCst = false; | ||
return production.call(this); | ||
// hack to enable outputting non-CST values from grammar rules. | ||
const { ruleName, originalGrammarAction } = production; | ||
try { | ||
this.ruleInvocationStateUpdate( | ||
this.fullRuleNameToShort[ruleName], | ||
ruleName, | ||
this.subruleIdx | ||
); | ||
return originalGrammarAction.call(this); | ||
} catch (e) { | ||
return this.invokeRuleCatch(e, true, () => undefined); | ||
} finally { | ||
this.ruleFinallyStateUpdate(); | ||
} | ||
} catch (e) { | ||
@@ -110,3 +123,2 @@ if (isRecognitionException(e)) { | ||
} finally { | ||
this.outputCst = true; | ||
this.reloadRecogState(orgState); | ||
@@ -122,3 +134,1 @@ this.isBackTrackingStack.pop(); | ||
} | ||
module.exports = JavaParser; |
@@ -1,6 +0,4 @@ | ||
"use strict"; | ||
import { tokenMatcher } from "chevrotain"; | ||
const { tokenMatcher } = require("chevrotain"); | ||
function defineRules($, t) { | ||
export function defineRules($, t) { | ||
// https://docs.oracle.com/javase/specs/jls/se16/html/jls-10.html#jls-ArrayInitializer | ||
@@ -31,5 +29,1 @@ $.RULE("arrayInitializer", () => { | ||
} | ||
module.exports = { | ||
defineRules | ||
}; |
@@ -1,9 +0,7 @@ | ||
"use strict"; | ||
import { tokenMatcher } from "chevrotain"; | ||
const { tokenMatcher } = require("chevrotain"); | ||
// Spec Deviation: The "*NoShortIf" variations were removed as the ambiguity of | ||
// the dangling else is resolved by attaching an "else" block | ||
// to the nearest "if" | ||
function defineRules($, t) { | ||
export function defineRules($, t) { | ||
// https://docs.oracle.com/javase/specs/jls/se16/html/jls-14.html#jls-Block | ||
@@ -28,21 +26,7 @@ $.RULE("block", () => { | ||
$.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) } | ||
@@ -82,15 +66,10 @@ ], | ||
$.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) } | ||
]); | ||
}); | ||
@@ -103,6 +82,3 @@ | ||
{ ALT: () => $.SUBRULE($.block) }, | ||
{ | ||
GATE: () => this.BACKTRACK_LOOKAHEAD($.yieldStatement), | ||
ALT: () => $.SUBRULE($.yieldStatement) | ||
}, | ||
{ ALT: () => $.SUBRULE($.yieldStatement) }, | ||
{ ALT: () => $.SUBRULE($.emptyStatement) }, | ||
@@ -194,9 +170,4 @@ { | ||
$.OR([ | ||
{ | ||
GATE: () => this.BACKTRACK_LOOKAHEAD($.isClassicSwitchLabel), | ||
ALT: () => $.MANY(() => $.SUBRULE($.switchBlockStatementGroup)) | ||
}, | ||
{ | ||
ALT: () => $.MANY2(() => $.SUBRULE($.switchRule)) | ||
} | ||
{ ALT: () => $.MANY(() => $.SUBRULE($.switchBlockStatementGroup)) }, | ||
{ ALT: () => $.MANY2(() => $.SUBRULE($.switchRule)) } | ||
]); | ||
@@ -231,3 +202,2 @@ $.CONSUME(t.RCurly); | ||
{ | ||
GATE: () => this.BACKTRACK_LOOKAHEAD($.pattern), | ||
ALT: () => { | ||
@@ -304,6 +274,3 @@ $.SUBRULE($.pattern); | ||
$.OR([ | ||
{ | ||
GATE: () => this.BACKTRACK_LOOKAHEAD($.isBasicForStatement), | ||
ALT: () => $.SUBRULE($.basicForStatement) | ||
}, | ||
{ ALT: () => $.SUBRULE($.basicForStatement) }, | ||
{ ALT: () => $.SUBRULE($.enhancedForStatement) } | ||
@@ -335,6 +302,3 @@ ]); | ||
$.OR([ | ||
{ | ||
GATE: () => $.BACKTRACK_LOOKAHEAD($.isLocalVariableDeclaration), | ||
ALT: () => $.SUBRULE($.localVariableDeclaration) | ||
}, | ||
{ ALT: () => $.SUBRULE($.localVariableDeclaration) }, | ||
{ ALT: () => $.SUBRULE($.statementExpressionList) } | ||
@@ -418,25 +382,22 @@ ]); | ||
$.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) } | ||
]); | ||
}); | ||
@@ -523,6 +484,3 @@ | ||
$.OR([ | ||
{ | ||
GATE: () => $.BACKTRACK_LOOKAHEAD($.isLocalVariableDeclaration), | ||
ALT: () => $.SUBRULE($.localVariableDeclaration) | ||
}, | ||
{ ALT: () => $.SUBRULE($.localVariableDeclaration) }, | ||
{ ALT: () => $.SUBRULE($.variableAccess) } | ||
@@ -546,47 +504,2 @@ ]); | ||
}); | ||
// ------------------------------------ | ||
// 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); | ||
}); | ||
} | ||
module.exports = { | ||
defineRules | ||
}; |
@@ -1,7 +0,4 @@ | ||
"use strict"; | ||
import { tokenMatcher } from "chevrotain"; | ||
const { isRecognitionException, tokenMatcher } = require("chevrotain"); | ||
const { classBodyTypes } = require("./utils/class-body-types"); | ||
function defineRules($, t) { | ||
export function defineRules($, t) { | ||
// https://docs.oracle.com/javase/specs/jls/se16/html/jls-8.html#jls-ClassDeclaration | ||
@@ -116,24 +113,7 @@ $.RULE("classDeclaration", () => { | ||
$.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) } | ||
]); | ||
@@ -143,24 +123,9 @@ }); | ||
// 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) } | ||
]); | ||
@@ -360,9 +325,18 @@ }); | ||
// https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-MethodDeclarator | ||
// https://docs.oracle.com/javase/specs/jls/se21/html/jls-8.html#jls-MethodDeclarator | ||
$.RULE("methodDeclarator", () => { | ||
$.CONSUME(t.Identifier); | ||
$.CONSUME(t.LBrace); | ||
$.OPTION(() => { | ||
$.SUBRULE($.formalParameterList); | ||
}); | ||
$.OR([ | ||
{ | ||
ALT: () => { | ||
$.SUBRULE($.receiverParameter); | ||
$.OPTION(() => { | ||
$.CONSUME(t.Comma); | ||
$.SUBRULE($.formalParameterList); | ||
}); | ||
} | ||
}, | ||
{ ALT: () => $.OPTION1(() => $.SUBRULE1($.formalParameterList)) } | ||
]); | ||
$.CONSUME(t.RBrace); | ||
@@ -400,6 +374,3 @@ $.OPTION2(() => { | ||
// Spec Deviation: extracted to "variableParaRegularParameter" | ||
{ | ||
GATE: $.BACKTRACK($.variableParaRegularParameter), | ||
ALT: () => $.SUBRULE($.variableParaRegularParameter) | ||
}, | ||
{ ALT: () => $.SUBRULE($.variableParaRegularParameter) }, | ||
{ ALT: () => $.SUBRULE($.variableArityParameter) } | ||
@@ -509,14 +480,14 @@ ]); | ||
$.CONSUME(t.LBrace); | ||
$.OPTION2({ | ||
// a "formalParameterList" and a "receiverParameter" | ||
// cannot be distinguished using fixed lookahead. | ||
GATE: $.BACKTRACK($.receiverParameter), | ||
DEF: () => { | ||
$.SUBRULE($.receiverParameter); | ||
$.CONSUME(t.Comma); | ||
} | ||
}); | ||
$.OPTION3(() => { | ||
$.SUBRULE($.formalParameterList); | ||
}); | ||
$.OR([ | ||
{ | ||
ALT: () => { | ||
$.SUBRULE($.receiverParameter); | ||
$.OPTION1(() => { | ||
$.CONSUME(t.Comma); | ||
$.SUBRULE($.formalParameterList); | ||
}); | ||
} | ||
}, | ||
{ ALT: () => $.OPTION2(() => $.SUBRULE1($.formalParameterList)) } | ||
]); | ||
$.CONSUME(t.RBrace); | ||
@@ -534,7 +505,4 @@ }); | ||
$.CONSUME(t.LCurly); | ||
$.OPTION({ | ||
GATE: $.BACKTRACK($.explicitConstructorInvocation), | ||
DEF: () => { | ||
$.SUBRULE($.explicitConstructorInvocation); | ||
} | ||
$.OPTION(() => { | ||
$.SUBRULE($.explicitConstructorInvocation); | ||
}); | ||
@@ -750,6 +718,3 @@ $.OPTION2(() => { | ||
$.OR([ | ||
{ | ||
GATE: () => this.BACKTRACK_LOOKAHEAD($.isCompactConstructorDeclaration), | ||
ALT: () => $.SUBRULE($.compactConstructorDeclaration) | ||
}, | ||
{ ALT: () => $.SUBRULE($.compactConstructorDeclaration) }, | ||
{ ALT: () => $.SUBRULE($.classBodyDeclaration) } | ||
@@ -768,174 +733,2 @@ ]); | ||
$.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 <TypeDeclaration> is a <ClassDeclaration> or an <InterfaceDeclaration>"; | ||
} 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; | ||
// "<T> 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 <classBodyDeclaration>"); | ||
} | ||
}); | ||
$.RULE("isDims", () => { | ||
@@ -948,12 +741,2 @@ $.MANY($.annotation); | ||
}); | ||
$.RULE("isCompactConstructorDeclaration", () => { | ||
$.MANY($.constructorModifier); | ||
$.SUBRULE($.simpleTypeName); | ||
$.CONSUME(t.LCurly); | ||
}); | ||
} | ||
module.exports = { | ||
defineRules | ||
}; |
@@ -1,10 +0,6 @@ | ||
"use strict"; | ||
const { tokenMatcher } = require("chevrotain"); | ||
function defineRules($, t) { | ||
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) } | ||
@@ -72,9 +68,4 @@ ]); | ||
$.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) } | ||
@@ -129,9 +120,4 @@ ]); | ||
$.OR1([ | ||
{ | ||
GATE: () => this.BACKTRACK_LOOKAHEAD($.pattern), | ||
ALT: () => $.SUBRULE($.pattern) | ||
}, | ||
{ | ||
ALT: () => $.SUBRULE($.referenceType) | ||
} | ||
{ ALT: () => $.SUBRULE($.pattern) }, | ||
{ ALT: () => $.SUBRULE($.referenceType) } | ||
]); | ||
@@ -220,7 +206,2 @@ } | ||
$.RULE("primaryPrefix", () => { | ||
let isCastExpression = false; | ||
if (tokenMatcher($.LA(1).tokenType, t.LBrace)) { | ||
isCastExpression = this.BACKTRACK_LOOKAHEAD($.isCastExpression); | ||
} | ||
$.OR([ | ||
@@ -232,6 +213,3 @@ { ALT: () => $.SUBRULE($.literal) }, | ||
{ ALT: () => $.SUBRULE($.fqnOrRefType) }, | ||
{ | ||
GATE: () => isCastExpression, | ||
ALT: () => $.SUBRULE($.castExpression) | ||
}, | ||
{ ALT: () => $.SUBRULE($.castExpression) }, | ||
{ ALT: () => $.SUBRULE($.parenthesisExpression) }, | ||
@@ -244,31 +222,28 @@ { ALT: () => $.SUBRULE($.newExpression) }, | ||
$.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($.templateArgument) } | ||
]); | ||
} | ||
}, | ||
{ ALT: () => $.SUBRULE($.methodInvocationSuffix) }, | ||
{ ALT: () => $.SUBRULE($.classLiteralSuffix) }, | ||
{ ALT: () => $.SUBRULE($.arrayAccessSuffix) }, | ||
{ ALT: () => $.SUBRULE($.methodReferenceSuffix) } | ||
]); | ||
}); | ||
@@ -281,9 +256,16 @@ | ||
$.MANY2({ | ||
// ".class" is a classLiteralSuffix | ||
GATE: () => | ||
// avoids ambiguity with ".this" and ".new" which are parsed as a primary suffix. | ||
tokenMatcher(this.LA(2).tokenType, t.Class) === false && | ||
tokenMatcher(this.LA(2).tokenType, t.This) === false && | ||
tokenMatcher(this.LA(2).tokenType, t.New) === false, | ||
$.MANY({ | ||
// avoids ambiguity with primary suffixes | ||
GATE: () => { | ||
const nextNextToken = $.LA(2); | ||
return !( | ||
tokenMatcher(nextNextToken, t.Class) || | ||
tokenMatcher(nextNextToken, t.This) || | ||
tokenMatcher(nextNextToken, t.New) || | ||
tokenMatcher(nextNextToken, t.StringLiteral) || | ||
tokenMatcher(nextNextToken, t.TextBlock) || | ||
tokenMatcher(nextNextToken, t.StringTemplateBegin) || | ||
tokenMatcher(nextNextToken, t.TextBlockTemplateBegin) | ||
); | ||
}, | ||
DEF: () => { | ||
@@ -367,8 +349,3 @@ $.CONSUME(t.Dot); | ||
$.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) } | ||
@@ -393,6 +370,3 @@ ]); | ||
$.OR([ | ||
{ | ||
GATE: () => this.BACKTRACK_LOOKAHEAD($.isLambdaExpression), | ||
ALT: () => $.SUBRULE($.lambdaExpression) | ||
}, | ||
{ ALT: () => $.SUBRULE($.lambdaExpression) }, | ||
{ ALT: () => $.SUBRULE($.unaryExpressionNotPlusMinus) } | ||
@@ -402,20 +376,6 @@ ]); | ||
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) } | ||
]); | ||
@@ -459,9 +419,6 @@ }); | ||
$.RULE("typeArgumentsOrDiamond", () => { | ||
$.OR({ | ||
DEF: [ | ||
{ ALT: () => $.SUBRULE($.diamond) }, | ||
{ ALT: () => $.SUBRULE($.typeArguments) } | ||
], | ||
MAX_LOOKAHEAD: 2 | ||
}); | ||
$.OR([ | ||
{ ALT: () => $.SUBRULE($.diamond) }, | ||
{ ALT: () => $.SUBRULE($.typeArguments) } | ||
]); | ||
}); | ||
@@ -494,6 +451,3 @@ | ||
$.OR([ | ||
{ | ||
GATE: $.BACKTRACK($.primitiveType), | ||
ALT: () => $.SUBRULE($.primitiveType) | ||
}, | ||
{ ALT: () => $.SUBRULE($.primitiveType) }, | ||
{ ALT: () => $.SUBRULE($.classOrInterfaceType) } | ||
@@ -503,6 +457,3 @@ ]); | ||
$.OR2([ | ||
{ | ||
GATE: $.BACKTRACK($.arrayCreationDefaultInitSuffix), | ||
ALT: () => $.SUBRULE($.arrayCreationDefaultInitSuffix) | ||
}, | ||
{ ALT: () => $.SUBRULE($.arrayCreationDefaultInitSuffix) }, | ||
{ ALT: () => $.SUBRULE($.arrayCreationExplicitInitSuffix) } | ||
@@ -577,12 +528,48 @@ ]); | ||
$.RULE("templateArgument", () => { | ||
$.OR([ | ||
{ ALT: () => $.SUBRULE($.template) }, | ||
{ ALT: () => $.CONSUME(t.StringLiteral) }, | ||
{ ALT: () => $.CONSUME(t.TextBlock) } | ||
]); | ||
}); | ||
$.RULE("template", () => { | ||
$.OR([ | ||
{ ALT: () => $.SUBRULE($.stringTemplate) }, | ||
{ ALT: () => $.SUBRULE($.textBlockTemplate) } | ||
]); | ||
}); | ||
$.RULE("stringTemplate", () => { | ||
$.CONSUME(t.StringTemplateBegin); | ||
$.SUBRULE($.embeddedExpression); | ||
$.MANY(() => { | ||
$.CONSUME(t.StringTemplateMid); | ||
$.SUBRULE1($.embeddedExpression); | ||
}); | ||
$.CONSUME(t.StringTemplateEnd); | ||
}); | ||
$.RULE("textBlockTemplate", () => { | ||
$.CONSUME(t.TextBlockTemplateBegin); | ||
$.SUBRULE($.embeddedExpression); | ||
$.MANY(() => { | ||
$.CONSUME(t.TextBlockTemplateMid); | ||
$.SUBRULE1($.embeddedExpression); | ||
}); | ||
$.CONSUME(t.TextBlockTemplateEnd); | ||
}); | ||
$.RULE("embeddedExpression", () => { | ||
$.OPTION(() => { | ||
$.SUBRULE($.expression); | ||
}); | ||
}); | ||
// 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) } | ||
]); | ||
@@ -632,87 +619,2 @@ }); | ||
// 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", () => { | ||
@@ -752,3 +654,3 @@ let result = undefined; | ||
function computeFirstForUnaryExpressionNotPlusMinus() { | ||
export function computeFirstForUnaryExpressionNotPlusMinus() { | ||
const firstUnaryExpressionNotPlusMinus = this.computeContentAssist( | ||
@@ -764,6 +666,1 @@ "unaryExpressionNotPlusMinus", | ||
} | ||
module.exports = { | ||
defineRules, | ||
computeFirstForUnaryExpressionNotPlusMinus | ||
}; |
@@ -1,13 +0,9 @@ | ||
"use strict"; | ||
const { tokenMatcher } = require("chevrotain"); | ||
import { tokenMatcher } from "chevrotain"; | ||
function defineRules($, t) { | ||
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); | ||
}); | ||
@@ -78,39 +74,10 @@ | ||
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) } | ||
]); | ||
@@ -179,39 +146,10 @@ }); | ||
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) } | ||
]); | ||
@@ -278,4 +216,3 @@ }); | ||
], | ||
IGNORE_AMBIGUITIES: true, | ||
MAX_LOOKAHEAD: 2 | ||
IGNORE_AMBIGUITIES: true | ||
}); | ||
@@ -303,18 +240,8 @@ $.CONSUME(t.RBrace); | ||
$.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) } | ||
]); | ||
@@ -346,169 +273,2 @@ }); | ||
}); | ||
// ------------------------------------ | ||
// 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; | ||
} | ||
}); | ||
} | ||
module.exports = { | ||
defineRules | ||
}; |
@@ -1,3 +0,2 @@ | ||
"use strict"; | ||
function defineRules($, t) { | ||
export function defineRules($, t) { | ||
// https://docs.oracle.com/javase/specs/jls/se16/html/jls-3.html#jls-Literal | ||
@@ -39,5 +38,1 @@ $.RULE("literal", () => { | ||
} | ||
module.exports = { | ||
defineRules | ||
}; |
@@ -1,4 +0,3 @@ | ||
"use strict"; | ||
const { tokenMatcher } = require("chevrotain"); | ||
function defineRules($, t) { | ||
import { tokenMatcher } from "chevrotain"; | ||
export function defineRules($, t) { | ||
// https://docs.oracle.com/javase/specs/jls/se16/html/jls-6.html#jls-ModuleName | ||
@@ -83,5 +82,1 @@ $.RULE("moduleName", () => { | ||
} | ||
module.exports = { | ||
defineRules | ||
}; |
@@ -1,6 +0,4 @@ | ||
"use strict"; | ||
const { isRecognitionException, tokenMatcher, EOF } = require("chevrotain"); | ||
const { classBodyTypes } = require("./utils/class-body-types"); | ||
import { tokenMatcher, EOF } from "chevrotain"; | ||
function defineRules($, t) { | ||
export function defineRules($, t) { | ||
/** | ||
@@ -15,13 +13,5 @@ * Spec Deviation: As OrdinaryCompilationUnit and UnnamedClassCompilationUnit | ||
$.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) } | ||
]); | ||
@@ -34,8 +24,3 @@ // https://github.com/jhipster/prettier-java/pull/217 | ||
$.RULE("ordinaryCompilationUnit", () => { | ||
$.OPTION({ | ||
GATE: $.BACKTRACK($.packageDeclaration), | ||
DEF: () => { | ||
$.SUBRULE($.packageDeclaration); | ||
} | ||
}); | ||
$.OPTION(() => $.SUBRULE($.packageDeclaration)); | ||
$.MANY(() => { | ||
@@ -120,24 +105,8 @@ $.SUBRULE3($.importDeclaration); | ||
$.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) } | ||
]); | ||
@@ -261,47 +230,2 @@ }); | ||
}); | ||
$.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) | ||
); | ||
}); | ||
} | ||
module.exports = { | ||
defineRules | ||
}; |
@@ -1,6 +0,2 @@ | ||
"use strict"; | ||
const { tokenMatcher } = require("chevrotain"); | ||
function defineRules($, t) { | ||
export function defineRules($, t) { | ||
// --------------------- | ||
@@ -107,11 +103,3 @@ // Productions from §4 (Types, Values, and Variables) | ||
$.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)); | ||
}); | ||
@@ -205,6 +193,3 @@ }); | ||
$.OR([ | ||
{ | ||
GATE: $.BACKTRACK($.referenceType), | ||
ALT: () => $.SUBRULE($.referenceType) | ||
}, | ||
{ ALT: () => $.SUBRULE($.referenceType) }, | ||
{ ALT: () => $.SUBRULE($.wildcard) } | ||
@@ -235,5 +220,1 @@ ]); | ||
} | ||
module.exports = { | ||
defineRules | ||
}; |
@@ -1,15 +0,7 @@ | ||
"use strict"; | ||
const { createToken: createTokenOrg, Lexer } = require("chevrotain"); | ||
const camelCase = require("lodash/camelCase"); | ||
import { createToken as createTokenOrg, Lexer } from "chevrotain"; | ||
import camelCase from "lodash/camelCase.js"; | ||
import * as chars from "./unicodesets.js"; | ||
let chars; | ||
// A little mini DSL for easier lexer definition. | ||
const fragments = {}; | ||
try { | ||
chars = require("./unicodesets"); | ||
} catch (e) { | ||
throw Error( | ||
"unicodesets.js file could not be found. Did you try to run the command: yarn run build ?" | ||
); | ||
} | ||
@@ -56,4 +48,8 @@ function inlineFragments(def) { | ||
"StringCharacter", | ||
"(?:(?:{{EscapeSequence}})|{{UnicodeInputCharacter}})" | ||
'(?:(?:{{EscapeSequence}})|{{UnicodeEscape}}|(?!["\\\\]).)' | ||
); | ||
FRAGMENT( | ||
"TextBlockCharacter", | ||
"(?:(?:{{EscapeSequence}})|{{UnicodeEscape}}|(?!\\\\).|\\\\?{{LineTerminator}})" | ||
); | ||
@@ -105,6 +101,14 @@ function matchJavaIdentifier(text, startOffset) { | ||
const allTokens = []; | ||
const allTokens = { | ||
modes: { | ||
global: [], | ||
stringTemplate: [], | ||
textBlockTemplate: [] | ||
}, | ||
defaultMode: "global" | ||
}; | ||
const allModes = Object.keys(allTokens.modes); | ||
const tokenDictionary = {}; | ||
function createToken(options) { | ||
function createToken(options, modes = allModes) { | ||
// TODO create a test to check all the tokenbs have a label defined | ||
@@ -123,3 +127,3 @@ if (!options.label) { | ||
const newTokenType = createTokenOrg(options); | ||
allTokens.push(newTokenType); | ||
modes.forEach(mode => allTokens.modes[mode].push(newTokenType)); | ||
tokenDictionary[options.name] = newTokenType; | ||
@@ -235,10 +239,58 @@ return newTokenType; | ||
name: "TextBlock", | ||
pattern: /"""\s*\n(\\"|\s|.)*?"""/ | ||
pattern: MAKE_PATTERN( | ||
'"""[\\x09\\x20\\x0C]*{{LineTerminator}}{{TextBlockCharacter}}*?"""' | ||
) | ||
}); | ||
createToken({ | ||
name: "TextBlockTemplateBegin", | ||
pattern: MAKE_PATTERN('"""{{LineTerminator}}{{TextBlockCharacter}}*?\\\\\\{'), | ||
push_mode: "textBlockTemplate" | ||
}); | ||
createToken( | ||
{ | ||
name: "TextBlockTemplateEnd", | ||
pattern: MAKE_PATTERN('\\}{{TextBlockCharacter}}*?"""'), | ||
pop_mode: true | ||
}, | ||
["textBlockTemplate"] | ||
); | ||
createToken({ | ||
name: "StringLiteral", | ||
pattern: MAKE_PATTERN('"(?:[^\\\\"]|{{StringCharacter}})*"') | ||
pattern: MAKE_PATTERN('"{{StringCharacter}}*?"') | ||
}); | ||
createToken({ | ||
name: "StringTemplateBegin", | ||
pattern: MAKE_PATTERN('"{{StringCharacter}}*?\\\\\\{'), | ||
push_mode: "stringTemplate" | ||
}); | ||
createToken( | ||
{ | ||
name: "StringTemplateEnd", | ||
pattern: MAKE_PATTERN('\\}{{StringCharacter}}*?"'), | ||
pop_mode: true | ||
}, | ||
["stringTemplate"] | ||
); | ||
createToken( | ||
{ | ||
name: "StringTemplateMid", | ||
pattern: MAKE_PATTERN("\\}{{StringCharacter}}*?\\\\\\{") | ||
}, | ||
["stringTemplate"] | ||
); | ||
createToken( | ||
{ | ||
name: "TextBlockTemplateMid", | ||
pattern: MAKE_PATTERN("\\}{{TextBlockCharacter}}*?\\\\\\{") | ||
}, | ||
["textBlockTemplate"] | ||
); | ||
// https://docs.oracle.com/javase/specs/jls/se21/html/jls-3.html#jls-3.9 | ||
@@ -391,4 +443,12 @@ // TODO: how to handle the special rule (see spec above) for "requires" and "transitive" | ||
createToken({ name: "RBrace", pattern: ")", categories: [Separators] }); | ||
createToken({ name: "LCurly", pattern: "{", categories: [Separators] }); | ||
createToken({ name: "RCurly", pattern: "}", categories: [Separators] }); | ||
createToken({ | ||
name: "LCurly", | ||
pattern: "{", | ||
categories: [Separators], | ||
push_mode: allTokens.defaultMode | ||
}); | ||
createToken( | ||
{ name: "RCurly", pattern: "}", categories: [Separators], pop_mode: true }, | ||
[allTokens.defaultMode] | ||
); | ||
createToken({ name: "LSquare", pattern: "[", categories: [Separators] }); | ||
@@ -530,3 +590,3 @@ createToken({ name: "RSquare", pattern: "]", categories: [Separators] }); | ||
// See: https://github.com/SAP/chevrotain/blob/master/examples/lexer/keywords_vs_identifiers/keywords_vs_identifiers.js | ||
allTokens.push(Identifier); | ||
allModes.forEach(mode => allTokens.modes[mode].push(Identifier)); | ||
tokenDictionary["Identifier"] = Identifier; | ||
@@ -540,5 +600,3 @@ | ||
} | ||
module.exports = { | ||
allTokens, | ||
tokens: tokenDictionary | ||
}; | ||
export { allTokens, tokenDictionary as tokens }; |
@@ -11,3 +11,2 @@ /*File generated with ../scripts/unicode.js using ../resources/Unicode/UnicodeData.txt. | ||
*/ | ||
"use strict"; | ||
const addRanges = (set, rangesArr) => { | ||
@@ -1003,5 +1002,2 @@ for (let i = 0; i < rangesArr.length; i++) { | ||
); | ||
module.exports = { | ||
firstIdentChar: fic, | ||
restIdentChar: ric | ||
}; | ||
export { fic as firstIdentChar, ric as restIdentChar }; |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
/** | ||
@@ -11,3 +9,3 @@ * Should Parser / Lexer Validations be skipped? | ||
*/ | ||
function getSkipValidations() { | ||
export function getSkipValidations() { | ||
return ( | ||
@@ -19,5 +17,1 @@ (typeof process !== "undefined" && // (not every runtime has a global `process` object | ||
} | ||
module.exports = { | ||
getSkipValidations | ||
}; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Yes
NaN255827
-9.69%3
50%20
-4.76%7438
-10.04%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
Updated