UNPKG

java-parser

Version:

Java Parser in JavaScript

492 lines (450 loc) 16.1 kB
"use strict"; const { tokenMatcher } = require("chevrotain"); function defineRules($, t) { // https://docs.oracle.com/javase/specs/jls/se11/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 }); $.OR([ { ALT: () => $.SUBRULE($.normalInterfaceDeclaration) }, { ALT: () => $.SUBRULE($.annotationTypeDeclaration) } ]); }); // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-NormalInterfaceDeclaration $.RULE("normalInterfaceDeclaration", () => { // Spec Deviation: The "interfaceModifier" prefix was extracted to the "interfaceDeclaration" $.CONSUME(t.Interface); $.SUBRULE($.typeIdentifier); $.OPTION(() => { $.SUBRULE($.typeParameters); }); $.OPTION2(() => { $.SUBRULE($.extendsInterfaces); }); $.SUBRULE($.interfaceBody); }); // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-InterfaceModifier $.RULE("interfaceModifier", () => { $.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.Strictfp) } ]); }); // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-ExtendsInterfaces $.RULE("extendsInterfaces", () => { $.CONSUME(t.Extends); $.SUBRULE($.interfaceTypeList); }); // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-InterfaceBody $.RULE("interfaceBody", () => { $.CONSUME(t.LCurly); $.MANY(() => { $.SUBRULE($.interfaceMemberDeclaration); }); $.CONSUME(t.RCurly); }); const InterfaceBodyTypes = { unknown: 0, constantDeclaration: 1, interfaceMethodDeclaration: 2, classDeclaration: 3, interfaceDeclaration: 4, semiColon: 5 }; // https://docs.oracle.com/javase/specs/jls/se11/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) } ]); }); // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-ConstantDeclaration $.RULE("constantDeclaration", () => { $.MANY(() => { $.SUBRULE($.constantModifier); }); $.SUBRULE($.unannType); $.SUBRULE($.variableDeclaratorList); $.CONSUME(t.Semicolon); }); // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-ConstantModifier $.RULE("constantModifier", () => { $.OR([ { ALT: () => $.SUBRULE($.annotation) }, { ALT: () => $.CONSUME(t.Public) }, { ALT: () => $.CONSUME(t.Static) }, { ALT: () => $.CONSUME(t.Final) } ]); }); // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-InterfaceMethodDeclaration $.RULE("interfaceMethodDeclaration", () => { $.MANY(() => { $.SUBRULE($.interfaceMethodModifier); }); $.SUBRULE($.methodHeader); $.SUBRULE($.methodBody); }); // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-InterfaceMethodModifier $.RULE("interfaceMethodModifier", () => { $.OR([ { ALT: () => $.SUBRULE($.annotation) }, { ALT: () => $.CONSUME(t.Public) }, { ALT: () => $.CONSUME(t.Private) }, { ALT: () => $.CONSUME(t.Abstract) }, { ALT: () => $.CONSUME(t.Default) }, { ALT: () => $.CONSUME(t.Static) }, { ALT: () => $.CONSUME(t.Strictfp) } ]); }); // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-AnnotationTypeDeclaration $.RULE("annotationTypeDeclaration", () => { // Spec Deviation: The "interfaceModifier" prefix was extracted to the "interfaceDeclaration" $.CONSUME(t.At); $.CONSUME(t.Interface); $.SUBRULE($.typeIdentifier); $.SUBRULE($.annotationTypeBody); }); // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-AnnotationTypeBody $.RULE("annotationTypeBody", () => { $.CONSUME(t.LCurly); $.MANY(() => { $.SUBRULE($.annotationTypeMemberDeclaration); }); $.CONSUME(t.RCurly); }); const AnnotationBodyTypes = { unknown: 0, annotationTypeElementDeclaration: 2, constantDeclaration: 1, classDeclaration: 3, interfaceDeclaration: 4, semiColon: 5 }; // https://docs.oracle.com/javase/specs/jls/se11/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) } ]); }); // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-AnnotationTypeElementDeclaration $.RULE("annotationTypeElementDeclaration", () => { $.MANY(() => { $.SUBRULE($.annotationTypeElementModifier); }); $.SUBRULE($.unannType); $.CONSUME(t.Identifier); $.CONSUME(t.LBrace); $.CONSUME(t.RBrace); $.OPTION(() => { $.SUBRULE($.dims); }); $.OPTION2(() => { $.SUBRULE($.defaultValue); }); $.CONSUME(t.Semicolon); }); // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-AnnotationTypeElementModifier $.RULE("annotationTypeElementModifier", () => { $.OR([ { ALT: () => $.SUBRULE($.annotation) }, { ALT: () => $.CONSUME(t.Public) }, { ALT: () => $.CONSUME(t.Abstract) } ]); }); // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-DefaultValue $.RULE("defaultValue", () => { $.CONSUME(t.Default); $.SUBRULE($.elementValue); }); // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-Annotation $.RULE("annotation", () => { // Spec Deviation: The common prefix for all three annotation types was extracted to this rule. // This was done to avoid the use of backtracking for performance reasons. $.CONSUME(t.At); $.SUBRULE($.typeName); // If this optional grammar was not invoked we have a markerAnnotation // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-MarkerAnnotation $.OPTION(() => { $.CONSUME(t.LBrace); $.OR({ DEF: [ // normal annotation - https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-NormalAnnotation { ALT: () => $.SUBRULE($.elementValuePairList) }, // Single Element Annotation - https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-SingleElementAnnotation { ALT: () => $.SUBRULE($.elementValue) }, { ALT: () => { /* empty normal annotation contents */ } } ], IGNORE_AMBIGUITIES: true, MAX_LOOKAHEAD: 2 }); $.CONSUME(t.RBrace); }); }); // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-ElementValuePairList $.RULE("elementValuePairList", () => { $.SUBRULE($.elementValuePair); $.MANY(() => { $.CONSUME(t.Comma); $.SUBRULE2($.elementValuePair); }); }); $.RULE("elementValuePair", () => { $.CONSUME(t.Identifier); $.CONSUME(t.Equals); $.SUBRULE($.elementValue); }); // https://docs.oracle.com/javase/specs/jls/se11/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($.elementValueArrayInitializer) }, { GATE: () => isSimpleElementValueAnnotation === true, ALT: () => $.SUBRULE($.annotation) } ]); }); // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-ElementValueArrayInitializer $.RULE("elementValueArrayInitializer", () => { $.CONSUME(t.LCurly); $.OPTION(() => { $.SUBRULE($.elementValueList); }); $.OPTION2(() => { $.CONSUME(t.Comma); }); $.CONSUME(t.RCurly); }); // https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-ElementValueList $.RULE("elementValueList", () => { $.SUBRULE($.elementValue); $.MANY({ GATE: () => tokenMatcher($.LA(2).tokenType, t.RCurly) === false, DEF: () => { $.CONSUME(t.Comma); $.SUBRULE2($.elementValue); } }); }); // ------------------------------------ // 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.Static) }, { ALT: () => $.CONSUME(t.Final) }, { ALT: () => $.CONSUME(t.Abstract) }, { ALT: () => $.CONSUME(t.Default) }, { ALT: () => $.CONSUME(t.Strictfp) } ]); } }); nextTokenType = this.LA(1).tokenType; if ( tokenMatcher(nextTokenType, t.Class) || tokenMatcher(nextTokenType, t.Enum) ) { 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 };