/** * Change parsing of types to flatten their AST and preserve their structure. * Refs #1150 [java] ClassOrInterfaceType AST improvements * Clément Fournier 02/2019 *==================================================================== * Add support for Java 12 switch expressions and switch rules. * Andreas Dangel, Clément Fournier 03/2019 *==================================================================== * Add support for Java 10 Local Variable Type Inference * See #743. In Java 10 mode, "var" as local variable type is handled special. * Andreas Dangel 04/2018 *==================================================================== * Fixes #888 [java] ParseException occurs with valid '<>' in Java 1.8 mode * Juan Martin Sotuyo Dodero 01/2018 *==================================================================== * Fixes #793 [java] Parser error with private method in nested classes in interfaces * Andreas Dangel 12/2017 *==================================================================== * Add support for Java 9 changes: * Private interface methods are only allowed with java9. * A single underscore "_" is an invalid identifier in java9. * Diamond operator for anonymous classes is only allowed with java9. * Add support for module-info.java. * Allow more concise try-with-resources statements with java9. * Andreas Dangel 09/2017 *==================================================================== * Add support for new Java 8 annotation locations. * Bugs #414, #415, #417 * @Snap252 06/2017 *==================================================================== * Allow empty statements (";") between package, import * and type declarations. * Bug #378 * Andreas Dangel 05/2017 *==================================================================== * Allow method references to specify generics also for * constructor references ("new"). * Bug #309 * Andreas Dangel 03/2017 *==================================================================== * Provide a better fix for CastExpression, getting rid of most hacks. * Bug #257 * * Juan Martin Sotuyo Dodero 02/2017 *==================================================================== * Allow local classes to carry more than one annotation. * Bug #208 * * Juan Martin Sotuyo Dodero 01/2017 *==================================================================== * Change lookahead for AnnotationMethodDeclaration in AnnotationTypeMemberDeclaration. * Bug #206 * * Juan Martin Sotuyo Dodero 01/2017 *==================================================================== * Allow method references to specify generics. * Bug #207 * * Juan Martin Sotuyo Dodero 01/2017 *==================================================================== * Simplify VariableDeclaratorId, forbidding illegal sequences such as * this[] and MyClass.this[] * * Juan Martin Sotuyo Dodero 10/2016 *==================================================================== * Improve lambda detection in PrimaryPrefix to improve parsing performance. * * Juan Martin Sotuyo Dodero 10/2016 *==================================================================== * Fix for regression introduced in previous changeset. * The syntactic lookahead was not properly handled by javacc, * so it was converted to a semantic one * Bug #1530 * * Juan Martin Sotuyo Dodero 10/2016 *==================================================================== * Fix for an expression within an additive expression that was * wrongly taken as a cast expression. * Bug #1484 * * Andreas Dangel 05/2016 *==================================================================== * Fix for Lambda expression with one variable * Bug #1470 * * Andreas Dangel 04/2016 *==================================================================== * Added support for explicit receiver parameters. * Bug #1455 * * Andreas Dangel 01/2016 *==================================================================== * Added capability for Tracking Tokens. * * Amit Kumar Prasad 10/2015 *==================================================================== * Fix for Cast Expression not detected properly in Return statements * Bug #1429 * * Andreas Dangel 10/2015 *==================================================================== * Fix for Lambda expressions without variables. * * Andreas Dangel 11/2014 *==================================================================== * Fix for Lambda expressions with two or three variables. * * Andreas Dangel 07/2014 *==================================================================== * Added support for Java 8 language constructs. * * Andreas Dangel 01/2014 * =================================================================== * Fix ForStatement to allow Annotations within the initializer. * * Andreas Dangel 01/2013 * =================================================================== * Fix wrong consumption of modifiers (e.g. "final") in a for-each loop. * Check for wrong java usage when catching multiple exceptions. * * Andreas Dangel 12/2012 * =================================================================== * Enhance grammar to use LocalVariableDeclaration in a for-each loop. * This enhances the symbol table to recognize variables declared in such * a for-each loop. * * Andreas Dangel 10/2012 * =================================================================== * Fix parser problem #3530124 with generics * * Modified the grammar, so that the different usages of generics work. * Adjusted the rules, that use "super", as super is no longer a PrimarySuffix. * It's now either a ExplicitConstructorInvocation or a PrimaryPrefix. * See also test case ParserCornersTest/testParsersCases * * Andreas Dangel 05/2012 * =================================================================== * Added support for Java 7 language constructs * * Dinesh Bolkensteyn (SonarSource), 10/2011 * =================================================================== * Changed the CastLookahead production to use 3 lookaheads for primitive types as suggested by Andreas Dangel * * Brian Remedios 07/2011 * =================================================================== * Added in support for assert as a name using lookaheads * * Tom Copeland, 09/03 * =================================================================== * Copied over the changes made by Andrea Gini and Marco Savard to * support JDK 1.4 language constructs, i.e., asserts. * See the java1_4c.jj distributed in the javacc2.1/examples/JavaGrammers directory. * Made numerous other modifications to support PMD. * * Tom Copeland, 6/02 * =================================================================== * This file is a modified version of one originally found in the * VTransformer Examples directory of JavaCC1_1. It has been * modified to accept Java source code for Java 1.2. Basically, * this means a new key word was added, 'strictfp', and that keyword * added to the appropriate productions and LOOKAHEADs (where other, * similar keywords are listed as possible choices). This involved * changing 11 lines. * * Some other minor changes were made, which can be found by doing * a search on 'DW, 7/99'. * * The goal of this effort was for the grammar to be able to parse * any legal Java 1.2 source code. It does not reject all illegal * cases, but neither did the original. Plus, when it comes to * the new 'strictfp' keyword, the Java Compiler from Sun (JDK1.2.1) * also does not reject all illegal cases, as defined by the * "Updates" document found at * http://java.sun.com/docs/books/jls/strictfp-changes.pdf * (see the testcases.txt file for details). * * David Williams, 7/99 * =================================================================== * * * Copyright (C) 1996, 1997 Sun Microsystems Inc. * * Use of this file and the system it is part of is constrained by the * file COPYRIGHT in the root directory of this system. You may, however, * make any modifications you wish to this file. * * Java files generated by running JavaCC on this file (or modified versions * of this file) may be used in exactly the same manner as Java files * generated from any grammar developed by you. * * Author: Sriram Sankar * Date: 3/5/97 * * This file contains a Java grammar and actions that implement a front-end. */ options { JAVA_UNICODE_ESCAPE = true; CACHE_TOKENS = true; STATIC = false; USER_CHAR_STREAM = true; JDK_VERSION = "1.5"; MULTI = true; VISITOR = true; NODE_USES_PARSER = true; TRACK_TOKENS = true; NODE_PACKAGE="net.sourceforge.pmd.lang.java.ast"; //DEBUG_PARSER = true; //DEBUG_LOOKAHEAD = true; } PARSER_BEGIN(JavaParser) package net.sourceforge.pmd.lang.java.ast; import java.util.ArrayList; import java.util.List; import java.util.Map; import net.sourceforge.pmd.lang.ast.CharStream; import net.sourceforge.pmd.lang.ast.TokenMgrError; import net.sourceforge.pmd.lang.ast.Node; public class JavaParser { private int jdkVersion = 0; public void setJdkVersion(int jdkVersion) { this.jdkVersion = jdkVersion; } private void throwParseException(String message) { int line = -1; int col = -1; if (jj_lastpos != null) { line = jj_lastpos.beginLine; col = jj_lastpos.beginColumn; } throw new ParseException("Line " + line + ", Column " + col + ": " + message); } private void checkForBadAssertUsage(String in, String usage) { if (jdkVersion > 3 && in.equals("assert")) { throwParseException("Can't use 'assert' as " + usage + " when running in JDK 1.4 mode!"); } } private void checkForBadStaticImportUsage() { if (jdkVersion < 5) { throwParseException("Can't use static imports when running in JDK 1.4 mode!"); } } private void checkForBadAnnotationUsage() { if (jdkVersion < 5) { throwParseException("Can't use annotations when running in JDK 1.4 mode!"); } } private void checkForBadGenericsUsage() { if (jdkVersion < 5) { throwParseException("Can't use generics unless running in JDK 1.5 mode!"); } } private void checkForBadVariableArgumentsUsage() { if (jdkVersion < 5) { throwParseException("Can't use variable arguments (varargs) when running in JDK 1.4 mode!"); } } private void checkForBadJDK15ForLoopSyntaxArgumentsUsage() { if (jdkVersion < 5) { throwParseException("Can't use JDK 1.5 for loop syntax when running in JDK 1.4 mode!"); } } private void checkForBadEnumUsage(String in, String usage) { if (jdkVersion >= 5 && in.equals("enum")) { throwParseException("Can't use 'enum' as " + usage + " when running in JDK 1.5 mode!"); } } private void checkForBadHexFloatingPointLiteral() { if (jdkVersion < 5) { throwParseException("Can't use hexadecimal floating point literals in pre-JDK 1.5 target"); } } private void checkForBadNumericalLiteralslUsage(Token token) { if (jdkVersion < 7) { if (token.image.contains("_")) { throwParseException("Can't use underscores in numerical literals when running in JDK inferior to 1.7 mode!"); } if (token.image.startsWith("0b") || token.image.startsWith("0B")) { throwParseException("Can't use binary numerical literals when running in JDK inferior to 1.7 mode!"); } } } private void checkForBadDiamondUsage() { if (jdkVersion < 7) { throwParseException("Cannot use the diamond generic notation when running in JDK inferior to 1.7 mode!"); } } private void checkForBadTryWithResourcesUsage() { if (jdkVersion < 7) { throwParseException("Cannot use the try-with-resources notation when running in JDK inferior to 1.7 mode!"); } } private void checkForBadMultipleExceptionsCatching() { if (jdkVersion < 7) { throwParseException("Cannot catch multiple exceptions when running in JDK inferior to 1.7 mode!"); } } private void checkForBadLambdaUsage() { if (jdkVersion < 8) { throwParseException("Cannot use lambda expressions when running in JDK inferior to 1.8 mode!"); } } private void checkForBadMethodReferenceUsage() { if (jdkVersion < 8) { throwParseException("Cannot use method references when running in JDK inferior to 1.8 mode!"); } } private void checkForBadDefaultImplementationUsage() { if (jdkVersion < 8) { throwParseException("Cannot use default implementations in interfaces when running in JDK inferior to 1.8 mode!"); } } private void checkForBadIntersectionTypesInCasts() { if (jdkVersion < 8) { throwParseException("Cannot use intersection types in casts when running in JDK inferior to 1.8 mode!"); } } private void checkForBadTypeAnnotations() { if (jdkVersion < 8) { throwParseException("Cannot use type annotations when running in JDK inferior to 1.8 mode!"); } } private void checkforBadExplicitReceiverParameter() { if (jdkVersion < 8) { throwParseException("Cannot use explicit receiver parameters when running in JDK inferior to 1.8 mode!"); } } private void checkForBadAnonymousDiamondUsage() { if (jdkVersion < 9) { ASTAllocationExpression node = (ASTAllocationExpression)jjtree.peekNode(); ASTTypeArguments types = node.getFirstChildOfType(ASTClassOrInterfaceType.class).getFirstChildOfType(ASTTypeArguments.class); if (node.isAnonymousClass() && types != null && types.isDiamond()) { throwParseException("Cannot use '<>' with anonymous inner classes when running in JDK inferior to 9 mode!"); } } } /** * Keeps track whether we are dealing with an interface or not. Needed since the tree is * is not fully constructed yet, when we check for private interface methods. * The flag is updated, if entering ClassOrInterfaceDeclaration and reset when leaving. * The flag is also reset, if entering a anonymous inner class or enums. */ private boolean inInterface = false; private void checkForBadPrivateInterfaceMethod(ASTMethodDeclaration node) { if (jdkVersion < 9 && inInterface && node.isPrivate()) { throwParseException("Cannot use private interface methods when running in JDK inferior to 9 mode!"); } } private void checkForBadIdentifier(String image) { if (jdkVersion >= 9 && "_".equals(image)) { throwParseException("With JDK 9, '_' is a keyword, and may not be used as an identifier!"); } } private void checkForBadModuleUsage() { if (jdkVersion < 9) { throwParseException("Cannot use module declaration when running in JDK inferior to 9 mode!"); } } private void checkForBadConciseTryWithResourcesUsage() { if (jdkVersion < 9) { throwParseException("Cannot use concise try-with-resources when running in JDK inferior to 9 mode!"); } } private void checkForBadTypeIdentifierUsage(String image) { if (jdkVersion >= 10 && "var".equals(image)) { throwParseException("With JDK 10, 'var' is a restricted local variable type and cannot be used for type declarations!"); } } private void checkForMultipleCaseLabels() { if (jdkVersion < 12) { throwParseException("Multiple case labels in switch statements are only supported with Java 12"); } } /** * Keeps track during tree construction, whether we are currently building a switch label. * A switch label must not contain a LambdaExpression. * Unfortunately, we have added LambdaExpression as part of PrimaryPrefix, which is wrong. * To keep compatibility, this flag is used, whether a LambdaExpression should be parsed * in PrimaryPrefix. * See also comment at #Expression(). */ private boolean inSwitchLabel = false; private void checkForSwitchRules() { if (jdkVersion < 12) { throwParseException("Switch rules in switch statements are only supported with Java 12"); } } private void checkForSwitchExpression() { if (jdkVersion < 12) { throwParseException("Switch expressions are only supported with Java 12"); } } private void checkForBreakExpression() { if (jdkVersion < 12) { throwParseException("Expressions in break statements are only supported with Java 12"); } } // This is a semantic LOOKAHEAD to determine if we're dealing with an assert // Note that this can't be replaced with a syntactic lookahead // since "assert" isn't a string literal token private boolean isNextTokenAnAssert() { if (jdkVersion <= 3) { return false; } return getToken(1).image.equals("assert"); } private boolean isPrecededByComment(Token tok) { boolean res = false; while (!res && tok.specialToken != null) { tok = tok.specialToken; res = tok.kind == SINGLE_LINE_COMMENT || tok.kind == FORMAL_COMMENT || tok.kind == MULTI_LINE_COMMENT; } return res; } /** * Semantic lookahead to check if the next identifier is a * specific restricted keyword. */ private boolean isKeyword(String keyword) { return getToken(1).kind == IDENTIFIER && getToken(1).image.equals(keyword); } public Map getSuppressMap() { return token_source.getSuppressMap(); } public void setSuppressMarker(String marker) { token_source.setSuppressMarker(marker); } /** * Takes the two nodes at the top of the stack and inject the next-to-last as the first * child of the last. Basically it transforms eg [A][B] into [[A]B]. Can be used to e.g. * build a left-recursive expression or type subtree from an iterative parsing. */ private void wrapLeft() { AbstractJavaNode lastSegment = (AbstractJavaNode) jjtree.popNode(); Node previousSegment = jjtree.popNode(); lastSegment.insertChild((JavaNode) previousSegment, 0, true); jjtree.pushNode(lastSegment); } } PARSER_END(JavaParser) TOKEN_MGR_DECLS : { protected List comments = new ArrayList(); } /* WHITE SPACE */ SPECIAL_TOKEN : { " " | "\t" | "\n" | "\r" | "\f" } SPECIAL_TOKEN : { < SINGLE_LINE_COMMENT: "//"(~["\n","\r"])* ("\n"|"\r"|"\r\n")? > { int startOfNOPMD = matchedToken.image.indexOf(suppressMarker); if (startOfNOPMD != -1) { suppressMap.put(matchedToken.beginLine, matchedToken.image.substring(startOfNOPMD + suppressMarker.length())); } comments.add(new SingleLineComment(matchedToken)); } } /* COMMENTS */ MORE : { <"/**" ~["/"]> { input_stream.backup(1); } : IN_FORMAL_COMMENT | "/*" : IN_MULTI_LINE_COMMENT } SPECIAL_TOKEN : { { comments.add(new FormalComment(matchedToken)); } : DEFAULT } SPECIAL_TOKEN : { { comments.add(new MultiLineComment(matchedToken)); } : DEFAULT } MORE : { < ~[] > } /* RESERVED WORDS AND LITERALS */ TOKEN : { < ABSTRACT: "abstract" > | < BOOLEAN: "boolean" > | < BREAK: "break" > | < BYTE: "byte" > | < CASE: "case" > | < CATCH: "catch" > | < CHAR: "char" > | < CLASS: "class" > | < CONST: "const" > | < CONTINUE: "continue" > | < _DEFAULT: "default" > | < DO: "do" > | < DOUBLE: "double" > | < ELSE: "else" > | < EXTENDS: "extends" > | < FALSE: "false" > | < FINAL: "final" > | < FINALLY: "finally" > | < FLOAT: "float" > | < FOR: "for" > | < GOTO: "goto" > | < IF: "if" > | < IMPLEMENTS: "implements" > | < IMPORT: "import" > | < INSTANCEOF: "instanceof" > | < INT: "int" > | < INTERFACE: "interface" > | < LONG: "long" > | < NATIVE: "native" > | < NEW: "new" > | < NULL: "null" > | < PACKAGE: "package"> | < PRIVATE: "private" > | < PROTECTED: "protected" > | < PUBLIC: "public" > | < RETURN: "return" > | < SHORT: "short" > | < STATIC: "static" > | < SUPER: "super" > | < SWITCH: "switch" > | < SYNCHRONIZED: "synchronized" > | < THIS: "this" > | < THROW: "throw" > | < THROWS: "throws" > | < TRANSIENT: "transient" > | < TRUE: "true" > | < TRY: "try" > | < VOID: "void" > | < VOLATILE: "volatile" > | < WHILE: "while" > | < STRICTFP: "strictfp" > } /* Restricted Keywords */ // Note: These are commented out, since these keywords // can still be used as identifiers. // see isKeyword() semantic lookup /* TOKEN : { < OPEN: "open" > | < MODULE: "module" > | < REQUIRES: "requires" > | < TRANSITIVE: "transitive" > | < EXPORTS: "exports" > | < OPENS: "opens" > | < TO: "to" > | < USES: "uses" > | < PROVIDES: "provides" > | < WITH: "with" > } */ /* LITERALS */ TOKEN : { < INTEGER_LITERAL: (["l","L"])? | (["l","L"])? | (["l","L"])? | (["l","L"])? > | < #DECIMAL_LITERAL: (["0"-"9"]((["0"-"9","_"])*["0"-"9"])?) > | < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"]((["0"-"9","a"-"f","A"-"F","_"])*["0"-"9","a"-"f","A"-"F"])?) > | < #BINARY_LITERAL: "0" ["b","B"] (["0","1"]((["0","1","_"])*["0","1"])?) > | < #OCTAL_LITERAL: "0" (["0"-"7"]((["0"-"7","_"])*["0"-"7"])?) > | < FLOATING_POINT_LITERAL: (["0"-"9"]((["0"-"9","_"])*["0"-"9"])?) "." (["0"-"9"]((["0"-"9","_"])*["0"-"9"])?)? ()? (["f","F","d","D"])? | "." (["0"-"9"]((["0"-"9","_"])*["0"-"9"])?) ()? (["f","F","d","D"])? | (["0"-"9"]((["0"-"9","_"])*["0"-"9"])?) (["f","F","d","D"])? | (["0"-"9"]((["0"-"9","_"])*["0"-"9"])?) ()? ["f","F","d","D"] > | < HEX_FLOATING_POINT_LITERAL: ( (".")? | "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"]((["0"-"9","a"-"f","A"-"F","_"])*["0"-"9","a"-"f","A"-"F"])?)? "." (["0"-"9","a"-"f","A"-"F"]((["0"-"9","a"-"f","A"-"F","_"])*["0"-"9","a"-"f","A"-"F"])?)) ["p","P"] (["+","-"])? (["0"-"9"]((["0"-"9","_"])*["0"-"9"])?) (["f","F","d","D"])? > | < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"]((["0"-"9","_"])*["0"-"9"])?) > | < CHARACTER_LITERAL: "'" ( (~["'","\\","\n","\r"]) | ("\\" ( ["n","t","b","r","f","\\","'","\""] | ["0"-"7"] ( ["0"-"7"] )? | ["0"-"3"] ["0"-"7"] ["0"-"7"] ) ) ) "'" > | < STRING_LITERAL: "\"" ( (~["\"","\\","\n","\r"]) | ("\\" ( ["n","t","b","r","f","\\","'","\""] | ["0"-"7"] ( ["0"-"7"] )? | ["0"-"3"] ["0"-"7"] ["0"-"7"] ) ) )* "\"" > } /* IDENTIFIERS */ TOKEN : { < IDENTIFIER: ()* > | < #LETTER: [ // all chars for which Character.isJavaIdentifierStart is true "$", "A"-"Z", "_", "a"-"z", "\u00a2"-"\u00a5", "\u00aa", "\u00b5", "\u00ba", "\u00c0"-"\u00d6", "\u00d8"-"\u00f6", "\u00f8"-"\u02c1", "\u02c6"-"\u02d1", "\u02e0"-"\u02e4", "\u02ec", "\u02ee", "\u0370"-"\u0374", "\u0376"-"\u0377", "\u037a"-"\u037d", "\u037f", "\u0386", "\u0388"-"\u038a", "\u038c", "\u038e"-"\u03a1", "\u03a3"-"\u03f5", "\u03f7"-"\u0481", "\u048a"-"\u052f", "\u0531"-"\u0556", "\u0559", "\u0561"-"\u0587", "\u058f", "\u05d0"-"\u05ea", "\u05f0"-"\u05f2", "\u060b", "\u0620"-"\u064a", "\u066e"-"\u066f", "\u0671"-"\u06d3", "\u06d5", "\u06e5"-"\u06e6", "\u06ee"-"\u06ef", "\u06fa"-"\u06fc", "\u06ff", "\u0710", "\u0712"-"\u072f", "\u074d"-"\u07a5", "\u07b1", "\u07ca"-"\u07ea", "\u07f4"-"\u07f5", "\u07fa", "\u0800"-"\u0815", "\u081a", "\u0824", "\u0828", "\u0840"-"\u0858", "\u08a0"-"\u08b4", "\u0904"-"\u0939", "\u093d", "\u0950", "\u0958"-"\u0961", "\u0971"-"\u0980", "\u0985"-"\u098c", "\u098f"-"\u0990", "\u0993"-"\u09a8", "\u09aa"-"\u09b0", "\u09b2", "\u09b6"-"\u09b9", "\u09bd", "\u09ce", "\u09dc"-"\u09dd", "\u09df"-"\u09e1", "\u09f0"-"\u09f3", "\u09fb", "\u0a05"-"\u0a0a", "\u0a0f"-"\u0a10", "\u0a13"-"\u0a28", "\u0a2a"-"\u0a30", "\u0a32"-"\u0a33", "\u0a35"-"\u0a36", "\u0a38"-"\u0a39", "\u0a59"-"\u0a5c", "\u0a5e", "\u0a72"-"\u0a74", "\u0a85"-"\u0a8d", "\u0a8f"-"\u0a91", "\u0a93"-"\u0aa8", "\u0aaa"-"\u0ab0", "\u0ab2"-"\u0ab3", "\u0ab5"-"\u0ab9", "\u0abd", "\u0ad0", "\u0ae0"-"\u0ae1", "\u0af1", "\u0af9", "\u0b05"-"\u0b0c", "\u0b0f"-"\u0b10", "\u0b13"-"\u0b28", "\u0b2a"-"\u0b30", "\u0b32"-"\u0b33", "\u0b35"-"\u0b39", "\u0b3d", "\u0b5c"-"\u0b5d", "\u0b5f"-"\u0b61", "\u0b71", "\u0b83", "\u0b85"-"\u0b8a", "\u0b8e"-"\u0b90", "\u0b92"-"\u0b95", "\u0b99"-"\u0b9a", "\u0b9c", "\u0b9e"-"\u0b9f", "\u0ba3"-"\u0ba4", "\u0ba8"-"\u0baa", "\u0bae"-"\u0bb9", "\u0bd0", "\u0bf9", "\u0c05"-"\u0c0c", "\u0c0e"-"\u0c10", "\u0c12"-"\u0c28", "\u0c2a"-"\u0c39", "\u0c3d", "\u0c58"-"\u0c5a", "\u0c60"-"\u0c61", "\u0c85"-"\u0c8c", "\u0c8e"-"\u0c90", "\u0c92"-"\u0ca8", "\u0caa"-"\u0cb3", "\u0cb5"-"\u0cb9", "\u0cbd", "\u0cde", "\u0ce0"-"\u0ce1", "\u0cf1"-"\u0cf2", "\u0d05"-"\u0d0c", "\u0d0e"-"\u0d10", "\u0d12"-"\u0d3a", "\u0d3d", "\u0d4e", "\u0d5f"-"\u0d61", "\u0d7a"-"\u0d7f", "\u0d85"-"\u0d96", "\u0d9a"-"\u0db1", "\u0db3"-"\u0dbb", "\u0dbd", "\u0dc0"-"\u0dc6", "\u0e01"-"\u0e30", "\u0e32"-"\u0e33", "\u0e3f"-"\u0e46", "\u0e81"-"\u0e82", "\u0e84", "\u0e87"-"\u0e88", "\u0e8a", "\u0e8d", "\u0e94"-"\u0e97", "\u0e99"-"\u0e9f", "\u0ea1"-"\u0ea3", "\u0ea5", "\u0ea7", "\u0eaa"-"\u0eab", "\u0ead"-"\u0eb0", "\u0eb2"-"\u0eb3", "\u0ebd", "\u0ec0"-"\u0ec4", "\u0ec6", "\u0edc"-"\u0edf", "\u0f00", "\u0f40"-"\u0f47", "\u0f49"-"\u0f6c", "\u0f88"-"\u0f8c", "\u1000"-"\u102a", "\u103f", "\u1050"-"\u1055", "\u105a"-"\u105d", "\u1061", "\u1065"-"\u1066", "\u106e"-"\u1070", "\u1075"-"\u1081", "\u108e", "\u10a0"-"\u10c5", "\u10c7", "\u10cd", "\u10d0"-"\u10fa", "\u10fc"-"\u1248", "\u124a"-"\u124d", "\u1250"-"\u1256", "\u1258", "\u125a"-"\u125d", "\u1260"-"\u1288", "\u128a"-"\u128d", "\u1290"-"\u12b0", "\u12b2"-"\u12b5", "\u12b8"-"\u12be", "\u12c0", "\u12c2"-"\u12c5", "\u12c8"-"\u12d6", "\u12d8"-"\u1310", "\u1312"-"\u1315", "\u1318"-"\u135a", "\u1380"-"\u138f", "\u13a0"-"\u13f5", "\u13f8"-"\u13fd", "\u1401"-"\u166c", "\u166f"-"\u167f", "\u1681"-"\u169a", "\u16a0"-"\u16ea", "\u16ee"-"\u16f8", "\u1700"-"\u170c", "\u170e"-"\u1711", "\u1720"-"\u1731", "\u1740"-"\u1751", "\u1760"-"\u176c", "\u176e"-"\u1770", "\u1780"-"\u17b3", "\u17d7", "\u17db"-"\u17dc", "\u1820"-"\u1877", "\u1880"-"\u18a8", "\u18aa", "\u18b0"-"\u18f5", "\u1900"-"\u191e", "\u1950"-"\u196d", "\u1970"-"\u1974", "\u1980"-"\u19ab", "\u19b0"-"\u19c9", "\u1a00"-"\u1a16", "\u1a20"-"\u1a54", "\u1aa7", "\u1b05"-"\u1b33", "\u1b45"-"\u1b4b", "\u1b83"-"\u1ba0", "\u1bae"-"\u1baf", "\u1bba"-"\u1be5", "\u1c00"-"\u1c23", "\u1c4d"-"\u1c4f", "\u1c5a"-"\u1c7d", "\u1ce9"-"\u1cec", "\u1cee"-"\u1cf1", "\u1cf5"-"\u1cf6", "\u1d00"-"\u1dbf", "\u1e00"-"\u1f15", "\u1f18"-"\u1f1d", "\u1f20"-"\u1f45", "\u1f48"-"\u1f4d", "\u1f50"-"\u1f57", "\u1f59", "\u1f5b", "\u1f5d", "\u1f5f"-"\u1f7d", "\u1f80"-"\u1fb4", "\u1fb6"-"\u1fbc", "\u1fbe", "\u1fc2"-"\u1fc4", "\u1fc6"-"\u1fcc", "\u1fd0"-"\u1fd3", "\u1fd6"-"\u1fdb", "\u1fe0"-"\u1fec", "\u1ff2"-"\u1ff4", "\u1ff6"-"\u1ffc", "\u203f"-"\u2040", "\u2054", "\u2071", "\u207f", "\u2090"-"\u209c", "\u20a0"-"\u20be", "\u2102", "\u2107", "\u210a"-"\u2113", "\u2115", "\u2119"-"\u211d", "\u2124", "\u2126", "\u2128", "\u212a"-"\u212d", "\u212f"-"\u2139", "\u213c"-"\u213f", "\u2145"-"\u2149", "\u214e", "\u2160"-"\u2188", "\u2c00"-"\u2c2e", "\u2c30"-"\u2c5e", "\u2c60"-"\u2ce4", "\u2ceb"-"\u2cee", "\u2cf2"-"\u2cf3", "\u2d00"-"\u2d25", "\u2d27", "\u2d2d", "\u2d30"-"\u2d67", "\u2d6f", "\u2d80"-"\u2d96", "\u2da0"-"\u2da6", "\u2da8"-"\u2dae", "\u2db0"-"\u2db6", "\u2db8"-"\u2dbe", "\u2dc0"-"\u2dc6", "\u2dc8"-"\u2dce", "\u2dd0"-"\u2dd6", "\u2dd8"-"\u2dde", "\u2e2f", "\u3005"-"\u3007", "\u3021"-"\u3029", "\u3031"-"\u3035", "\u3038"-"\u303c", "\u3041"-"\u3096", "\u309d"-"\u309f", "\u30a1"-"\u30fa", "\u30fc"-"\u30ff", "\u3105"-"\u312d", "\u3131"-"\u318e", "\u31a0"-"\u31ba", "\u31f0"-"\u31ff", "\u3400"-"\u4db5", "\u4e00"-"\u9fd5", "\ua000"-"\ua48c", "\ua4d0"-"\ua4fd", "\ua500"-"\ua60c", "\ua610"-"\ua61f", "\ua62a"-"\ua62b", "\ua640"-"\ua66e", "\ua67f"-"\ua69d", "\ua6a0"-"\ua6ef", "\ua717"-"\ua71f", "\ua722"-"\ua788", "\ua78b"-"\ua7ad", "\ua7b0"-"\ua7b7", "\ua7f7"-"\ua801", "\ua803"-"\ua805", "\ua807"-"\ua80a", "\ua80c"-"\ua822", "\ua838", "\ua840"-"\ua873", "\ua882"-"\ua8b3", "\ua8f2"-"\ua8f7", "\ua8fb", "\ua8fd", "\ua90a"-"\ua925", "\ua930"-"\ua946", "\ua960"-"\ua97c", "\ua984"-"\ua9b2", "\ua9cf", "\ua9e0"-"\ua9e4", "\ua9e6"-"\ua9ef", "\ua9fa"-"\ua9fe", "\uaa00"-"\uaa28", "\uaa40"-"\uaa42", "\uaa44"-"\uaa4b", "\uaa60"-"\uaa76", "\uaa7a", "\uaa7e"-"\uaaaf", "\uaab1", "\uaab5"-"\uaab6", "\uaab9"-"\uaabd", "\uaac0", "\uaac2", "\uaadb"-"\uaadd", "\uaae0"-"\uaaea", "\uaaf2"-"\uaaf4", "\uab01"-"\uab06", "\uab09"-"\uab0e", "\uab11"-"\uab16", "\uab20"-"\uab26", "\uab28"-"\uab2e", "\uab30"-"\uab5a", "\uab5c"-"\uab65", "\uab70"-"\uabe2", "\uac00"-"\ud7a3", "\ud7b0"-"\ud7c6", "\ud7cb"-"\ud7fb", "\uf900"-"\ufa6d", "\ufa70"-"\ufad9", "\ufb00"-"\ufb06", "\ufb13"-"\ufb17", "\ufb1d", "\ufb1f"-"\ufb28", "\ufb2a"-"\ufb36", "\ufb38"-"\ufb3c", "\ufb3e", "\ufb40"-"\ufb41", "\ufb43"-"\ufb44", "\ufb46"-"\ufbb1", "\ufbd3"-"\ufd3d", "\ufd50"-"\ufd8f", "\ufd92"-"\ufdc7", "\ufdf0"-"\ufdfc", "\ufe33"-"\ufe34", "\ufe4d"-"\ufe4f", "\ufe69", "\ufe70"-"\ufe74", "\ufe76"-"\ufefc", "\uff04", "\uff21"-"\uff3a", "\uff3f", "\uff41"-"\uff5a", "\uff66"-"\uffbe", "\uffc2"-"\uffc7", "\uffca"-"\uffcf", "\uffd2"-"\uffd7", "\uffda"-"\uffdc", "\uffe0"-"\uffe1", "\uffe5"-"\uffe6" ] > | < #PART_LETTER: [ // all chars for which Character.isJavaIdentifierPart is true "\u0000"-"\u0008", "\u000e"-"\u001b", "$", "0"-"9", "A"-"Z", "_", "a"-"z", "\u007f"-"\u009f", "\u00a2"-"\u00a5", "\u00aa", "\u00ad", "\u00b5", "\u00ba", "\u00c0"-"\u00d6", "\u00d8"-"\u00f6", "\u00f8"-"\u02c1", "\u02c6"-"\u02d1", "\u02e0"-"\u02e4", "\u02ec", "\u02ee", "\u0300"-"\u0374", "\u0376"-"\u0377", "\u037a"-"\u037d", "\u037f", "\u0386", "\u0388"-"\u038a", "\u038c", "\u038e"-"\u03a1", "\u03a3"-"\u03f5", "\u03f7"-"\u0481", "\u0483"-"\u0487", "\u048a"-"\u052f", "\u0531"-"\u0556", "\u0559", "\u0561"-"\u0587", "\u058f", "\u0591"-"\u05bd", "\u05bf", "\u05c1"-"\u05c2", "\u05c4"-"\u05c5", "\u05c7", "\u05d0"-"\u05ea", "\u05f0"-"\u05f2", "\u0600"-"\u0605", "\u060b", "\u0610"-"\u061a", "\u061c", "\u0620"-"\u0669", "\u066e"-"\u06d3", "\u06d5"-"\u06dd", "\u06df"-"\u06e8", "\u06ea"-"\u06fc", "\u06ff", "\u070f"-"\u074a", "\u074d"-"\u07b1", "\u07c0"-"\u07f5", "\u07fa", "\u0800"-"\u082d", "\u0840"-"\u085b", "\u08a0"-"\u08b4", "\u08e3"-"\u0963", "\u0966"-"\u096f", "\u0971"-"\u0983", "\u0985"-"\u098c", "\u098f"-"\u0990", "\u0993"-"\u09a8", "\u09aa"-"\u09b0", "\u09b2", "\u09b6"-"\u09b9", "\u09bc"-"\u09c4", "\u09c7"-"\u09c8", "\u09cb"-"\u09ce", "\u09d7", "\u09dc"-"\u09dd", "\u09df"-"\u09e3", "\u09e6"-"\u09f3", "\u09fb", "\u0a01"-"\u0a03", "\u0a05"-"\u0a0a", "\u0a0f"-"\u0a10", "\u0a13"-"\u0a28", "\u0a2a"-"\u0a30", "\u0a32"-"\u0a33", "\u0a35"-"\u0a36", "\u0a38"-"\u0a39", "\u0a3c", "\u0a3e"-"\u0a42", "\u0a47"-"\u0a48", "\u0a4b"-"\u0a4d", "\u0a51", "\u0a59"-"\u0a5c", "\u0a5e", "\u0a66"-"\u0a75", "\u0a81"-"\u0a83", "\u0a85"-"\u0a8d", "\u0a8f"-"\u0a91", "\u0a93"-"\u0aa8", "\u0aaa"-"\u0ab0", "\u0ab2"-"\u0ab3", "\u0ab5"-"\u0ab9", "\u0abc"-"\u0ac5", "\u0ac7"-"\u0ac9", "\u0acb"-"\u0acd", "\u0ad0", "\u0ae0"-"\u0ae3", "\u0ae6"-"\u0aef", "\u0af1", "\u0af9", "\u0b01"-"\u0b03", "\u0b05"-"\u0b0c", "\u0b0f"-"\u0b10", "\u0b13"-"\u0b28", "\u0b2a"-"\u0b30", "\u0b32"-"\u0b33", "\u0b35"-"\u0b39", "\u0b3c"-"\u0b44", "\u0b47"-"\u0b48", "\u0b4b"-"\u0b4d", "\u0b56"-"\u0b57", "\u0b5c"-"\u0b5d", "\u0b5f"-"\u0b63", "\u0b66"-"\u0b6f", "\u0b71", "\u0b82"-"\u0b83", "\u0b85"-"\u0b8a", "\u0b8e"-"\u0b90", "\u0b92"-"\u0b95", "\u0b99"-"\u0b9a", "\u0b9c", "\u0b9e"-"\u0b9f", "\u0ba3"-"\u0ba4", "\u0ba8"-"\u0baa", "\u0bae"-"\u0bb9", "\u0bbe"-"\u0bc2", "\u0bc6"-"\u0bc8", "\u0bca"-"\u0bcd", "\u0bd0", "\u0bd7", "\u0be6"-"\u0bef", "\u0bf9", "\u0c00"-"\u0c03", "\u0c05"-"\u0c0c", "\u0c0e"-"\u0c10", "\u0c12"-"\u0c28", "\u0c2a"-"\u0c39", "\u0c3d"-"\u0c44", "\u0c46"-"\u0c48", "\u0c4a"-"\u0c4d", "\u0c55"-"\u0c56", "\u0c58"-"\u0c5a", "\u0c60"-"\u0c63", "\u0c66"-"\u0c6f", "\u0c81"-"\u0c83", "\u0c85"-"\u0c8c", "\u0c8e"-"\u0c90", "\u0c92"-"\u0ca8", "\u0caa"-"\u0cb3", "\u0cb5"-"\u0cb9", "\u0cbc"-"\u0cc4", "\u0cc6"-"\u0cc8", "\u0cca"-"\u0ccd", "\u0cd5"-"\u0cd6", "\u0cde", "\u0ce0"-"\u0ce3", "\u0ce6"-"\u0cef", "\u0cf1"-"\u0cf2", "\u0d01"-"\u0d03", "\u0d05"-"\u0d0c", "\u0d0e"-"\u0d10", "\u0d12"-"\u0d3a", "\u0d3d"-"\u0d44", "\u0d46"-"\u0d48", "\u0d4a"-"\u0d4e", "\u0d57", "\u0d5f"-"\u0d63", "\u0d66"-"\u0d6f", "\u0d7a"-"\u0d7f", "\u0d82"-"\u0d83", "\u0d85"-"\u0d96", "\u0d9a"-"\u0db1", "\u0db3"-"\u0dbb", "\u0dbd", "\u0dc0"-"\u0dc6", "\u0dca", "\u0dcf"-"\u0dd4", "\u0dd6", "\u0dd8"-"\u0ddf", "\u0de6"-"\u0def", "\u0df2"-"\u0df3", "\u0e01"-"\u0e3a", "\u0e3f"-"\u0e4e", "\u0e50"-"\u0e59", "\u0e81"-"\u0e82", "\u0e84", "\u0e87"-"\u0e88", "\u0e8a", "\u0e8d", "\u0e94"-"\u0e97", "\u0e99"-"\u0e9f", "\u0ea1"-"\u0ea3", "\u0ea5", "\u0ea7", "\u0eaa"-"\u0eab", "\u0ead"-"\u0eb9", "\u0ebb"-"\u0ebd", "\u0ec0"-"\u0ec4", "\u0ec6", "\u0ec8"-"\u0ecd", "\u0ed0"-"\u0ed9", "\u0edc"-"\u0edf", "\u0f00", "\u0f18"-"\u0f19", "\u0f20"-"\u0f29", "\u0f35", "\u0f37", "\u0f39", "\u0f3e"-"\u0f47", "\u0f49"-"\u0f6c", "\u0f71"-"\u0f84", "\u0f86"-"\u0f97", "\u0f99"-"\u0fbc", "\u0fc6", "\u1000"-"\u1049", "\u1050"-"\u109d", "\u10a0"-"\u10c5", "\u10c7", "\u10cd", "\u10d0"-"\u10fa", "\u10fc"-"\u1248", "\u124a"-"\u124d", "\u1250"-"\u1256", "\u1258", "\u125a"-"\u125d", "\u1260"-"\u1288", "\u128a"-"\u128d", "\u1290"-"\u12b0", "\u12b2"-"\u12b5", "\u12b8"-"\u12be", "\u12c0", "\u12c2"-"\u12c5", "\u12c8"-"\u12d6", "\u12d8"-"\u1310", "\u1312"-"\u1315", "\u1318"-"\u135a", "\u135d"-"\u135f", "\u1380"-"\u138f", "\u13a0"-"\u13f5", "\u13f8"-"\u13fd", "\u1401"-"\u166c", "\u166f"-"\u167f", "\u1681"-"\u169a", "\u16a0"-"\u16ea", "\u16ee"-"\u16f8", "\u1700"-"\u170c", "\u170e"-"\u1714", "\u1720"-"\u1734", "\u1740"-"\u1753", "\u1760"-"\u176c", "\u176e"-"\u1770", "\u1772"-"\u1773", "\u1780"-"\u17d3", "\u17d7", "\u17db"-"\u17dd", "\u17e0"-"\u17e9", "\u180b"-"\u180e", "\u1810"-"\u1819", "\u1820"-"\u1877", "\u1880"-"\u18aa", "\u18b0"-"\u18f5", "\u1900"-"\u191e", "\u1920"-"\u192b", "\u1930"-"\u193b", "\u1946"-"\u196d", "\u1970"-"\u1974", "\u1980"-"\u19ab", "\u19b0"-"\u19c9", "\u19d0"-"\u19d9", "\u1a00"-"\u1a1b", "\u1a20"-"\u1a5e", "\u1a60"-"\u1a7c", "\u1a7f"-"\u1a89", "\u1a90"-"\u1a99", "\u1aa7", "\u1ab0"-"\u1abd", "\u1b00"-"\u1b4b", "\u1b50"-"\u1b59", "\u1b6b"-"\u1b73", "\u1b80"-"\u1bf3", "\u1c00"-"\u1c37", "\u1c40"-"\u1c49", "\u1c4d"-"\u1c7d", "\u1cd0"-"\u1cd2", "\u1cd4"-"\u1cf6", "\u1cf8"-"\u1cf9", "\u1d00"-"\u1df5", "\u1dfc"-"\u1f15", "\u1f18"-"\u1f1d", "\u1f20"-"\u1f45", "\u1f48"-"\u1f4d", "\u1f50"-"\u1f57", "\u1f59", "\u1f5b", "\u1f5d", "\u1f5f"-"\u1f7d", "\u1f80"-"\u1fb4", "\u1fb6"-"\u1fbc", "\u1fbe", "\u1fc2"-"\u1fc4", "\u1fc6"-"\u1fcc", "\u1fd0"-"\u1fd3", "\u1fd6"-"\u1fdb", "\u1fe0"-"\u1fec", "\u1ff2"-"\u1ff4", "\u1ff6"-"\u1ffc", "\u200b"-"\u200f", "\u202a"-"\u202e", "\u203f"-"\u2040", "\u2054", "\u2060"-"\u2064", "\u2066"-"\u206f", "\u2071", "\u207f", "\u2090"-"\u209c", "\u20a0"-"\u20be", "\u20d0"-"\u20dc", "\u20e1", "\u20e5"-"\u20f0", "\u2102", "\u2107", "\u210a"-"\u2113", "\u2115", "\u2119"-"\u211d", "\u2124", "\u2126", "\u2128", "\u212a"-"\u212d", "\u212f"-"\u2139", "\u213c"-"\u213f", "\u2145"-"\u2149", "\u214e", "\u2160"-"\u2188", "\u2c00"-"\u2c2e", "\u2c30"-"\u2c5e", "\u2c60"-"\u2ce4", "\u2ceb"-"\u2cf3", "\u2d00"-"\u2d25", "\u2d27", "\u2d2d", "\u2d30"-"\u2d67", "\u2d6f", "\u2d7f"-"\u2d96", "\u2da0"-"\u2da6", "\u2da8"-"\u2dae", "\u2db0"-"\u2db6", "\u2db8"-"\u2dbe", "\u2dc0"-"\u2dc6", "\u2dc8"-"\u2dce", "\u2dd0"-"\u2dd6", "\u2dd8"-"\u2dde", "\u2de0"-"\u2dff", "\u2e2f", "\u3005"-"\u3007", "\u3021"-"\u302f", "\u3031"-"\u3035", "\u3038"-"\u303c", "\u3041"-"\u3096", "\u3099"-"\u309a", "\u309d"-"\u309f", "\u30a1"-"\u30fa", "\u30fc"-"\u30ff", "\u3105"-"\u312d", "\u3131"-"\u318e", "\u31a0"-"\u31ba", "\u31f0"-"\u31ff", "\u3400"-"\u4db5", "\u4e00"-"\u9fd5", "\ua000"-"\ua48c", "\ua4d0"-"\ua4fd", "\ua500"-"\ua60c", "\ua610"-"\ua62b", "\ua640"-"\ua66f", "\ua674"-"\ua67d", "\ua67f"-"\ua6f1", "\ua717"-"\ua71f", "\ua722"-"\ua788", "\ua78b"-"\ua7ad", "\ua7b0"-"\ua7b7", "\ua7f7"-"\ua827", "\ua838", "\ua840"-"\ua873", "\ua880"-"\ua8c4", "\ua8d0"-"\ua8d9", "\ua8e0"-"\ua8f7", "\ua8fb", "\ua8fd", "\ua900"-"\ua92d", "\ua930"-"\ua953", "\ua960"-"\ua97c", "\ua980"-"\ua9c0", "\ua9cf"-"\ua9d9", "\ua9e0"-"\ua9fe", "\uaa00"-"\uaa36", "\uaa40"-"\uaa4d", "\uaa50"-"\uaa59", "\uaa60"-"\uaa76", "\uaa7a"-"\uaac2", "\uaadb"-"\uaadd", "\uaae0"-"\uaaef", "\uaaf2"-"\uaaf6", "\uab01"-"\uab06", "\uab09"-"\uab0e", "\uab11"-"\uab16", "\uab20"-"\uab26", "\uab28"-"\uab2e", "\uab30"-"\uab5a", "\uab5c"-"\uab65", "\uab70"-"\uabea", "\uabec"-"\uabed", "\uabf0"-"\uabf9", "\uac00"-"\ud7a3", "\ud7b0"-"\ud7c6", "\ud7cb"-"\ud7fb", "\uf900"-"\ufa6d", "\ufa70"-"\ufad9", "\ufb00"-"\ufb06", "\ufb13"-"\ufb17", "\ufb1d"-"\ufb28", "\ufb2a"-"\ufb36", "\ufb38"-"\ufb3c", "\ufb3e", "\ufb40"-"\ufb41", "\ufb43"-"\ufb44", "\ufb46"-"\ufbb1", "\ufbd3"-"\ufd3d", "\ufd50"-"\ufd8f", "\ufd92"-"\ufdc7", "\ufdf0"-"\ufdfc", "\ufe00"-"\ufe0f", "\ufe20"-"\ufe2f", "\ufe33"-"\ufe34", "\ufe4d"-"\ufe4f", "\ufe69", "\ufe70"-"\ufe74", "\ufe76"-"\ufefc", "\ufeff", "\uff04", "\uff10"-"\uff19", "\uff21"-"\uff3a", "\uff3f", "\uff41"-"\uff5a", "\uff66"-"\uffbe", "\uffc2"-"\uffc7", "\uffca"-"\uffcf", "\uffd2"-"\uffd7", "\uffda"-"\uffdc", "\uffe0"-"\uffe1", "\uffe5"-"\uffe6", "\ufff9"-"\ufffb" ] > } /* SEPARATORS */ TOKEN : { < LPAREN: "(" > | < RPAREN: ")" > | < LBRACE: "{" > | < RBRACE: "}" > | < LBRACKET: "[" > | < RBRACKET: "]" > | < SEMICOLON: ";" > | < COMMA: "," > | < DOT: "." > | < AT: "@" > } /* OPERATORS */ TOKEN : { < ASSIGN: "=" > | < LT: "<" > | < BANG: "!" > | < TILDE: "~" > | < HOOK: "?" > | < COLON: ":" > | < EQ: "==" > | < LE: "<=" > | < GE: ">=" > | < NE: "!=" > | < SC_OR: "||" > | < SC_AND: "&&" > | < INCR: "++" > | < DECR: "--" > | < PLUS: "+" > | < MINUS: "-" > | < STAR: "*" > | < SLASH: "/" > | < BIT_AND: "&" > | < BIT_OR: "|" > | < XOR: "^" > | < REM: "%" > | < LSHIFT: "<<" > // Notice the absence of >> or >>>, to not conflict with generics | < PLUSASSIGN: "+=" > | < MINUSASSIGN: "-=" > | < STARASSIGN: "*=" > | < SLASHASSIGN: "/=" > | < ANDASSIGN: "&=" > | < ORASSIGN: "|=" > | < XORASSIGN: "^=" > | < REMASSIGN: "%=" > | < LSHIFTASSIGN: "<<=" > | < RSIGNEDSHIFTASSIGN: ">>=" > | < RUNSIGNEDSHIFTASSIGN: ">>>=" > | < ELLIPSIS: "..." > | < LAMBDA: "->" > | < METHOD_REF: "::" > } /* >'s need special attention due to generics syntax. */ TOKEN : { < RUNSIGNEDSHIFT: ">>>" > { matchedToken.kind = GT; ((Token.GTToken)matchedToken).realKind = RUNSIGNEDSHIFT; input_stream.backup(2); matchedToken.image = ">"; } | < RSIGNEDSHIFT: ">>" > { matchedToken.kind = GT; ((Token.GTToken)matchedToken).realKind = RSIGNEDSHIFT; input_stream.backup(1); matchedToken.image = ">"; } | < GT: ">" > } /***************************************** * THE JAVA LANGUAGE GRAMMAR STARTS HERE * *****************************************/ /* * Program structuring syntax follows. */ ASTCompilationUnit CompilationUnit() : {} { [ LOOKAHEAD( ( Annotation() )* "package" ) PackageDeclaration() ( EmptyStatement() )* ] ( ImportDeclaration() ( EmptyStatement() )* )* ( LOOKAHEAD(2) TypeDeclaration() ( EmptyStatement() )* )* [ LOOKAHEAD({isKeyword("open") || isKeyword("module") || getToken(1).kind == AT}) ModuleDeclaration() ( EmptyStatement() )* ] ( < "\u001a" > )? ( < "~[]" > )? { jjtThis.setComments(token_source.comments); return jjtThis; } } void PackageDeclaration() : {} { ( Annotation() )* "package" Name() ";" } void ImportDeclaration() : {} { "import" [ "static" {checkForBadStaticImportUsage();jjtThis.setStatic();} ] Name() [ "." "*" {jjtThis.setImportOnDemand();} ] ";" } /* * Modifiers. We match all modifiers in a single rule to reduce the chances of * syntax errors for simple modifier mistakes. It will also enable us to give * better error messages. */ int Modifiers() #void: { int modifiers = 0; } { ( LOOKAHEAD(2) ( "public" { modifiers |= AccessNode.PUBLIC; } | "static" { modifiers |= AccessNode.STATIC; } | "protected" { modifiers |= AccessNode.PROTECTED; } | "private" { modifiers |= AccessNode.PRIVATE; } | "final" { modifiers |= AccessNode.FINAL; } | "abstract" { modifiers |= AccessNode.ABSTRACT; } | "synchronized" { modifiers |= AccessNode.SYNCHRONIZED; } | "native" { modifiers |= AccessNode.NATIVE; } | "transient" { modifiers |= AccessNode.TRANSIENT; } | "volatile" { modifiers |= AccessNode.VOLATILE; } | "strictfp" { modifiers |= AccessNode.STRICTFP; } | "default" { modifiers |= AccessNode.DEFAULT; checkForBadDefaultImplementationUsage(); } | Annotation() ) )* { return modifiers; } } /* * Declaration syntax follows. */ void TypeDeclaration(): { int modifiers; } { modifiers = Modifiers() ( ClassOrInterfaceDeclaration(modifiers) | LOOKAHEAD({isKeyword("enum")}) EnumDeclaration(modifiers) | AnnotationTypeDeclaration(modifiers) ) } void ClassOrInterfaceDeclaration(int modifiers): { Token t = null; jjtThis.setModifiers(modifiers); boolean inInterfaceOld = inInterface; inInterface = false; } { ( /* See note about this optional final modifier in BlockStatement */ ["final"|"abstract"] "class" | "interface" { jjtThis.setInterface(); inInterface = true; } ) t= { checkForBadTypeIdentifierUsage(t.image); jjtThis.setImage(t.image); } [ TypeParameters() ] [ ExtendsList() ] [ ImplementsList() ] ClassOrInterfaceBody() { inInterface = inInterfaceOld; } // always restore the flag after leaving the node } void ExtendsList(): { boolean extendsMoreThanOne = false; } { "extends" (TypeAnnotation())* ClassOrInterfaceType() ( "," (TypeAnnotation())* ClassOrInterfaceType() { extendsMoreThanOne = true; } )* } void ImplementsList(): {} { "implements" (TypeAnnotation())* ClassOrInterfaceType() ( "," (TypeAnnotation())* ClassOrInterfaceType() )* } void EnumDeclaration(int modifiers): { Token t; jjtThis.setModifiers(modifiers); } { t = { if (!"enum".equals(t.image)) { throw new ParseException("ERROR: expecting enum"); } if (jdkVersion < 5) { throw new ParseException("ERROR: Can't use enum as a keyword in pre-JDK 1.5 target"); } } t= {checkForBadTypeIdentifierUsage(t.image); jjtThis.setImage(t.image);} [ ImplementsList() ] EnumBody() } void EnumBody(): { boolean inInterfaceOld = inInterface; inInterface = false; } { "{" [( Annotation() )* EnumConstant() ( LOOKAHEAD(2) "," ( Annotation() )* EnumConstant() )* ] [ "," ] [ ";" ( ClassOrInterfaceBodyDeclaration() )* ] "}" { inInterface = inInterfaceOld; } // always restore the flag after leaving the node } void EnumConstant(): {Token t;} { t= {jjtThis.setImage(t.image);} [ Arguments() ] [ ClassOrInterfaceBody() ] } void TypeParameters(): {} { "<" {checkForBadGenericsUsage();} TypeParameter() ( "," TypeParameter() )* ">" } void TypeParameter(): {Token t;} { (TypeAnnotation())* t= {jjtThis.setImage(t.image);} [ TypeBound() ] } void TypeBound(): {} { "extends" (TypeAnnotation())* ClassOrInterfaceType() ( "&" (TypeAnnotation())* ClassOrInterfaceType() )* } void ClassOrInterfaceBody(): {} { "{" ( ClassOrInterfaceBodyDeclaration() )* "}" } void ClassOrInterfaceBodyDeclaration(): { int modifiers; } { LOOKAHEAD(["static"] "{" ) Initializer() | modifiers = Modifiers() ( LOOKAHEAD(3) ClassOrInterfaceDeclaration(modifiers) | LOOKAHEAD({isKeyword("enum")}) EnumDeclaration(modifiers) | LOOKAHEAD( [ TypeParameters() ] "(" ) ConstructorDeclaration(modifiers) | LOOKAHEAD( Type() ( "[" "]" )* ( "," | "=" | ";" ) ) FieldDeclaration(modifiers) | LOOKAHEAD(2) MethodDeclaration(modifiers) | LOOKAHEAD(2) AnnotationTypeDeclaration(modifiers) ) | ";" } void FieldDeclaration(int modifiers) : {jjtThis.setModifiers(modifiers);} { Type() VariableDeclarator() ( "," VariableDeclarator() )* ";" } void VariableDeclarator() : {} { VariableDeclaratorId() [ "=" VariableInitializer() ] } // TODO use ArrayTypeDims void VariableDeclaratorId() : { Token t; String image; } { (LOOKAHEAD(2) t= "." { checkforBadExplicitReceiverParameter(); jjtThis.setExplicitReceiverParameter(); image=t.image + ".this"; } | t= { checkforBadExplicitReceiverParameter(); jjtThis.setExplicitReceiverParameter(); image = t.image;} | t= { image = t.image; } ( "[" "]" { jjtThis.bumpArrayDepth(); })* ) { checkForBadAssertUsage(image, "a variable name"); checkForBadEnumUsage(image, "a variable name"); checkForBadIdentifier(image); jjtThis.setImage( image ); } } void VariableInitializer() : {} { ArrayInitializer() | Expression() } void ArrayInitializer() : {} { "{" [ VariableInitializer() ( LOOKAHEAD(2) "," VariableInitializer() )* ] [ "," ] "}" } void MethodDeclaration(int modifiers) : { jjtThis.setModifiers(modifiers); { checkForBadPrivateInterfaceMethod(jjtThis); } } { [ TypeParameters() ] (TypeAnnotation())* ResultType() MethodDeclarator() [ "throws" NameList() ] ( Block() | ";" ) } void MethodDeclarator() : {Token t;} { t= { checkForBadAssertUsage(t.image, "a method name"); checkForBadEnumUsage(t.image, "a method name"); jjtThis.setImage( t.image ); } FormalParameters() ( "[" "]" )* // TODO use ArrayTypeDims } void FormalParameters() : {} { "(" [ FormalParameter() ( "," FormalParameter() )* ] ")" } void FormalParameter() : { } { ( "final" {jjtThis.setFinal(true);} | Annotation() )* Type() ("|" {checkForBadMultipleExceptionsCatching();} Type())* [ "..." {checkForBadVariableArgumentsUsage();} {jjtThis.setVarargs();} ] VariableDeclaratorId() } void ConstructorDeclaration(int modifiers) : {jjtThis.setModifiers(modifiers); Token t;} { [ TypeParameters() ] {jjtThis.setImage(getToken(0).getImage());} FormalParameters() [ "throws" NameList() ] "{" [ LOOKAHEAD(ExplicitConstructorInvocation()) ExplicitConstructorInvocation() ] ( BlockStatement() )* t = "}" { if (isPrecededByComment(t)) { jjtThis.setContainsComment(); } } } void ExplicitConstructorInvocation() : {} { LOOKAHEAD("this" Arguments() ";") "this" {jjtThis.setIsThis();} Arguments() ";" | LOOKAHEAD(TypeArguments() "this" Arguments() ";") TypeArguments() "this" {jjtThis.setIsThis();} Arguments() ";" | [ LOOKAHEAD(PrimaryExpression() ".") PrimaryExpression() "." ] [ TypeArguments() ] "super" {jjtThis.setIsSuper();} Arguments() ";" } void Initializer() : {} { [ "static" {jjtThis.setStatic();} ] Block() } /* JLS: https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.3 ReferenceType: ClassOrInterfaceType TypeVariable ArrayType ClassOrInterfaceType: ClassType InterfaceType ClassType: {Annotation} Identifier [TypeArguments] ClassOrInterfaceType . {Annotation} Identifier [TypeArguments] InterfaceType: ClassType TypeVariable: {Annotation} Identifier ArrayType: PrimitiveType Dims ClassOrInterfaceType Dims TypeVariable Dims Dims: {Annotation} [ ] {{Annotation} [ ]} */ /* * Type, name and expression syntax follows. * Type is the same as "UnannType" in JLS * * See https://docs.oracle.com/javase/specs/jls/se10/html/jls-8.html#jls-UnannType */ void Type() #void: { Token t; } { // lookahead to catch arrays of primitive types. // we can't lookahead for just PrimitiveType() "[" // because the "[" may be preceded by annotations LOOKAHEAD(PrimitiveType() ArrayTypeDim() | ) ReferenceType() | PrimitiveType() } void Dims() #ArrayTypeDims: {} { // the list of dimensions is flat, but annotations are // preserved within each specific dim. (ArrayTypeDim())+ } void ArrayTypeDim(): {} { (TypeAnnotation())* "[" "]" } void ReferenceType() #void: {} { // TODO TypeVariable is ambiguous with ClassOrInterfaceType // but I think it would be good to have a node for it nevertheless // to help typeres, since TypeVariables have special types (intersection types) // This could be handled in a rewrite phase, which is necessary for // disambiguation. Since type parameters shadow anything, their disambiguation // is stable regardless of classpath config. ( PrimitiveType() Dims() ) #ArrayType | ( ClassOrInterfaceType() [ LOOKAHEAD(2) Dims() ] ) #ArrayType(>1) } /** * Parses a ClassOrInterfaceType. The production itself is #void, * but the node exists (declared inline within the production). */ void ClassOrInterfaceType() #void: { StringBuilder imageBuilder = new StringBuilder(); Token t; } { /* First, gobble up all identifiers until the first type arguments or annotation is found. This builds a single ClassOrInterfaceType with the given image and the type arguments if any. */ ( t= { imageBuilder.append(t.getImage()); } /* FIXME We gobble up all identifiers until we find either type arguments or annotations, because it may be a FQCN, e.g. java.util.List is a single node. But java.util.Map.Entry should be two nodes ((java.util.Map).Entry) I would have said this doesn't matter but the other fixme comment just below shows we need a rewrite phase anyway */ ( LOOKAHEAD("." ) "." t= { imageBuilder.append('.').append(t.getImage()); } )* [ LOOKAHEAD( "<" ) TypeArguments() ] ) #ClassOrInterfaceType { // At this point the first ClassOrInterfaceType is on top of the stack jjtree.peekNode().setImage(imageBuilder.toString()); } /* Now if there are other segments, either the previous type specified type arguments, or the next has an annotation. Each of the following segments is its own ClassOrInterfaceType which encloses the previous one. The resulting structure appears left-recursive, but the parser just executes a loop. That scheme preserves the position of type arguments and annotations. See #1150. FIXME this doesn't account for annotated AND qualified types e.g. java.util.@Annot List, in which java.util should not be a ClassOrInterfaceType We can only fix that through rewrite, later on, with knowledge of the classpath. */ ( LOOKAHEAD(2) ( "." (TypeAnnotation())* t= { jjtThis.setImage(t.getImage()); } [ LOOKAHEAD( "<" ) TypeArguments() ] ) #ClassOrInterfaceType // inject the previous segment into the last one { wrapLeft(); } )* } void TypeArguments(): {} { LOOKAHEAD(2) "<" {checkForBadGenericsUsage();} TypeArgument() ( "," TypeArgument() )* ">" | "<" {checkForBadDiamondUsage();} ">" } /** * TODO We could make this #void and instead have a node WildcardType extending ReferenceType. * This would remove this level of nesting, which is unnecessary. */ void TypeArgument(): {} { (TypeAnnotation())* (ReferenceType() | "?" [ WildcardBounds() ]) } void WildcardBounds(): {} { ("extends" | "super") (TypeAnnotation())* ReferenceType() } /* JLS https://docs.oracle.com/javase/specs/jls/se10/html/jls-4.html#jls-PrimitiveType PrimitiveType: {Annotation} NumericType {Annotation} boolean NumericType: IntegralType FloatingPointType IntegralType: (one of) byte short int long char FloatingPointType: (one of) float double */ void PrimitiveType() : {} { ( "boolean" | "char" | "byte" | "short" | "int" | "long" | "float" | "double" ) {jjtThis.setImage(getToken(0).getImage());} } void ResultType() : {} { "void" | Type() } void Name() : /* * A lookahead of 2 is required below since "Name" can be followed * by a ".*" when used in the context of an "ImportDeclaration". */ { StringBuilder s = new StringBuilder(); Token t; } { t= { s.append(t.image); } ( LOOKAHEAD(2) "." t= {s.append('.').append(t.image);} )* {jjtThis.setImage(s.toString());} } void NameList() : {} { (TypeAnnotation())* Name() ( "," (TypeAnnotation())* Name() )* } /* * Expression syntax follows. */ void Expression() : /* * This expansion has been written this way instead of: * Assignment() | ConditionalExpression() * for performance reasons. * However, it is a weakening of the grammar for it allows the LHS of * assignments to be any conditional expression whereas it can only be * a primary expression. Consider adding a semantic predicate to work * around this. */ // It also allows lambda expressions in many more contexts as allowed by the JLS. // Lambda expressions are not a PrimaryExpression in the JLS, instead they're // separated from the AssignmentExpression production. Their use is restricted // to method and constructor argument, cast operand, and the RHS of assignments. // https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.27 // // To prevent LambdaExpressions in switch labels, the field #inSwitchLabel is used // as a workaround. {} { ConditionalExpression() [ LOOKAHEAD(2) AssignmentOperator() Expression() ] } void AssignmentOperator() : {} { "=" {jjtThis.setImage("=");} | "*=" {jjtThis.setImage("*="); jjtThis.setCompound();} | "/=" {jjtThis.setImage("/="); jjtThis.setCompound();} | "%=" {jjtThis.setImage("%="); jjtThis.setCompound();} | "+=" {jjtThis.setImage("+="); jjtThis.setCompound();} | "-=" {jjtThis.setImage("-="); jjtThis.setCompound();} | "<<=" {jjtThis.setImage("<<="); jjtThis.setCompound();} | ">>=" {jjtThis.setImage(">>="); jjtThis.setCompound();} | ">>>=" {jjtThis.setImage(">>>="); jjtThis.setCompound();} | "&=" {jjtThis.setImage("&="); jjtThis.setCompound();} | "^=" {jjtThis.setImage("^="); jjtThis.setCompound();} | "|=" {jjtThis.setImage("|="); jjtThis.setCompound();} } // TODO Setting isTernary is unnecessary, since the node is only pushed on the stack if there is at least one child, // ie if it's a ternary void ConditionalExpression() #ConditionalExpression(>1) : {} { ConditionalOrExpression() [ LOOKAHEAD(2) "?" Expression() ":" ConditionalExpression() ] } void ConditionalOrExpression() #ConditionalOrExpression(>1): {} { ConditionalAndExpression() ( LOOKAHEAD(2) "||" ConditionalAndExpression() )* } void ConditionalAndExpression() #ConditionalAndExpression(>1): {} { InclusiveOrExpression() ( LOOKAHEAD(2) "&&" InclusiveOrExpression() )* } void InclusiveOrExpression() #InclusiveOrExpression(>1) : {} { ExclusiveOrExpression() ( LOOKAHEAD(2) "|" ExclusiveOrExpression() )* } void ExclusiveOrExpression() #ExclusiveOrExpression(>1) : {} { AndExpression() ( LOOKAHEAD(2) "^" AndExpression() )* } void AndExpression() #AndExpression(>1): {} { EqualityExpression() ( LOOKAHEAD(2) "&" EqualityExpression() )* } void EqualityExpression() #EqualityExpression(>1): {} { InstanceOfExpression() ( LOOKAHEAD(2) ( "==" {jjtThis.setImage("==");} | "!=" {jjtThis.setImage("!=");} ) InstanceOfExpression() )* } void InstanceOfExpression() #InstanceOfExpression(>1): {} { RelationalExpression() [ LOOKAHEAD(2) "instanceof" Type() ] } void RelationalExpression() #RelationalExpression(>1): {} { ShiftExpression() ( LOOKAHEAD(2) ( "<" {jjtThis.setImage("<");} | ">" {jjtThis.setImage(">");} | "<=" {jjtThis.setImage("<=");} | ">=" {jjtThis.setImage(">=");} ) ShiftExpression() )* } void ShiftExpression() #ShiftExpression(>1): {} { AdditiveExpression() ( LOOKAHEAD(2) ( "<<" { jjtThis.setImage("<<");} | RSIGNEDSHIFT() { jjtThis.setImage(">>"); } | RUNSIGNEDSHIFT() { jjtThis.setImage(">>>"); } ) AdditiveExpression() )* } void AdditiveExpression() #AdditiveExpression(>1): {} { MultiplicativeExpression() ( LOOKAHEAD(2) ( "+" {jjtThis.setImage("+");} | "-" {jjtThis.setImage("-");} ) MultiplicativeExpression() )* } void MultiplicativeExpression() #MultiplicativeExpression(>1): {} { UnaryExpression() ( LOOKAHEAD(2) ( "*" {jjtThis.setImage("*");} | "/" {jjtThis.setImage("/");} | "%" {jjtThis.setImage("%");}) UnaryExpression() )* } void UnaryExpression() #UnaryExpression((jjtn000.getImage() != null)): {} { ("+" {jjtThis.setImage("+");} | "-" {jjtThis.setImage("-");}) UnaryExpression() | PreIncrementExpression() | PreDecrementExpression() | UnaryExpressionNotPlusMinus() } void PreIncrementExpression() : {} { "++" PrimaryExpression() } void PreDecrementExpression() : {} { "--" PrimaryExpression() } void UnaryExpressionNotPlusMinus() #UnaryExpressionNotPlusMinus((jjtn000.getImage() != null)): {} { ( "~" {jjtThis.setImage("~");} | "!" {jjtThis.setImage("!");} ) UnaryExpression() /* * This is really ugly... we are repeating the CastExpression lookahead and full expression... * If we don't the lookahead within CastExpression is ignored, and it simply looks for the expression, * meaning we can't be explicit as to what can be casted depending on the cast type (primitive or otherwhise) */ | LOOKAHEAD("(" (Annotation())* PrimitiveType() ")") CastExpression() | LOOKAHEAD("(" (Annotation())* Type() ( "&" ReferenceType() )* ")" UnaryExpressionNotPlusMinus()) CastExpression() | PostfixExpression() | SwitchExpression() } void PostfixExpression() #PostfixExpression((jjtn000.getImage() != null)): {} { PrimaryExpression() [ "++" {jjtThis.setImage("++");} | "--" {jjtThis.setImage("--");} ] } void CastExpression() : {} { LOOKAHEAD( "(" (Annotation())* PrimitiveType() ")" ) "(" (TypeAnnotation())* Type() ")" UnaryExpression() | "(" (TypeAnnotation())* Type() ( "&" {checkForBadIntersectionTypesInCasts(); jjtThis.setIntersectionTypes(true);} ReferenceType() )* ")" UnaryExpressionNotPlusMinus() } void SwitchExpression() : {} { {checkForSwitchExpression();} "switch" "(" Expression() ")" SwitchBlock() } void PrimaryExpression() : {} { PrimaryPrefix() ( LOOKAHEAD(2) PrimarySuffix() )* } void MemberSelector(): { Token t; } { "." TypeArguments() t= {jjtThis.setImage(t.image);} | MethodReference() } void MethodReference() : {Token t; checkForBadMethodReferenceUsage();} { "::" [TypeArguments()] ( "new" {jjtThis.setImage("new");} | t= {jjtThis.setImage(t.image);} ) } void PrimaryPrefix() : {Token t;} { Literal() | LOOKAHEAD(2) "this" {jjtThis.setUsesThisModifier();} | "super" {jjtThis.setUsesSuperModifier();} | LOOKAHEAD( "->", {!inSwitchLabel} ) LambdaExpression() | LOOKAHEAD( "(" VariableDeclaratorId() ( "," VariableDeclaratorId() )* ")" "->", {!inSwitchLabel} ) LambdaExpression() | LOOKAHEAD( FormalParameters() "->", {!inSwitchLabel} ) LambdaExpression() | LOOKAHEAD(3) "(" Expression() ")" | AllocationExpression() | LOOKAHEAD( ResultType() "." "class" ) (ResultType() #void "." "class") #ClassLiteral | LOOKAHEAD( Name() "::" ) Name() | LOOKAHEAD( ReferenceType() MethodReference() ) ReferenceType() MethodReference() | Name() } void LambdaExpression() : { checkForBadLambdaUsage(); } { VariableDeclaratorId() "->" ( Expression() | Block() ) | LOOKAHEAD(3) LambdaParameters() "->" ( Expression() | Block() ) | LOOKAHEAD(3) "(" VariableDeclaratorId() ( "," VariableDeclaratorId() )* ")" "->" ( Expression() | Block() ) } void LambdaParameters() #FormalParameters : {} { "(" [ LambdaParameterList() ] ")" } void LambdaParameterList() #void : {} { LambdaParameter() ( "," LambdaParameter() )* } void LambdaParameter() #FormalParameter : {} { ( "final" {jjtThis.setFinal(true);} | Annotation() )* LambdaParameterType() [ "..." {checkForBadVariableArgumentsUsage();} {jjtThis.setVarargs();} ] VariableDeclaratorId() } void LambdaParameterType() #void : {} { LOOKAHEAD( { jdkVersion >= 11 && isKeyword("var") } ) | Type() } void PrimarySuffix() : {Token t;} { LOOKAHEAD(2) "." "this" | LOOKAHEAD(2) "." "super" | LOOKAHEAD(2) "." AllocationExpression() | LOOKAHEAD(3) MemberSelector() | "[" Expression() "]" {jjtThis.setIsArrayDereference();} | "." t= {jjtThis.setImage(t.image);} | Arguments() {jjtThis.setIsArguments();} } void Literal() #void : { Token t;} { NumericLiteral() | StringLiteral() | CharLiteral() | ("true" { jjtThis.setTrue(); } | "false") #BooleanLiteral | "null" #NullLiteral } void NumericLiteral(): { Token t; } { ( t= { jjtThis.setIntLiteral();} | t= { jjtThis.setFloatLiteral();} | t= { checkForBadHexFloatingPointLiteral(); jjtThis.setFloatLiteral();} ) { checkForBadNumericalLiteralslUsage(t); jjtThis.setImage(t.image); } } void CharLiteral(): {} { {jjtThis.setImage(getToken(0).getImage());} } void StringLiteral(): {} { { jjtThis.setImage(getToken(0).getImage()); } } void Arguments() : {} { "(" [ ArgumentList() ] ")" } void ArgumentList() : {} { Expression() ( "," Expression() )* } void AllocationExpression(): {} { "new" (TypeAnnotation())* (LOOKAHEAD(2) PrimitiveType() ArrayDimsAndInits() | ClassOrInterfaceType() ( ArrayDimsAndInits() | Arguments() [ { boolean inInterfaceOld = inInterface; inInterface = false; /* a anonymous class is not a interface */ } ClassOrInterfaceBody() { inInterface = inInterfaceOld; } // always restore the flag after leaving the node ] ) { checkForBadAnonymousDiamondUsage(); } ) } /* * The second LOOKAHEAD specification below is to parse to PrimarySuffix * if there is an expression between the "[...]". * TODO use ArrayTypeDims */ void ArrayDimsAndInits() : {} { LOOKAHEAD(2) ( LOOKAHEAD(2) (TypeAnnotation())* "[" Expression() "]" {jjtThis.bumpArrayDepth();})+ ( LOOKAHEAD(2) "[" "]" {jjtThis.bumpArrayDepth();} )* | ( "[" "]" {jjtThis.bumpArrayDepth();})+ ArrayInitializer() } /* * Statement syntax follows. */ void Statement() : {} { LOOKAHEAD( { isNextTokenAnAssert() } ) AssertStatement() | LOOKAHEAD(2) LabeledStatement() | Block() | EmptyStatement() | StatementExpression() ";" | SwitchStatement() | IfStatement() | WhileStatement() | DoStatement() | ForStatement() | BreakStatement() | ContinueStatement() | ReturnStatement() | ThrowStatement() | SynchronizedStatement() | TryStatement() } void LabeledStatement() : {Token t;} { t= {jjtThis.setImage(t.image);} ":" Statement() } void Block() : {Token t;} { "{" ( BlockStatement() )* t = "}" { if (isPrecededByComment(t)) { jjtThis.setContainsComment(); } } } void BlockStatement(): {} { LOOKAHEAD( { isNextTokenAnAssert() } ) AssertStatement() | LOOKAHEAD(( "final" | Annotation() )* Type() ) LocalVariableDeclaration() ";" | Statement() | /* TODO: Seems like we should be discarding the "final" after using it in the lookahead; I added a ["final|abstract"] inside ClassOrInterfaceDeclaration, but that seems like a hack that could break other things... */ LOOKAHEAD( (Annotation())* ["final"|"abstract"] "class") (Annotation())* ClassOrInterfaceDeclaration(0) } /* * See https://docs.oracle.com/javase/specs/jls/se10/html/jls-14.html#jls-14.4 */ void LocalVariableDeclaration() : {} { ( "final" {jjtThis.setFinal(true);} | Annotation() )* LocalVariableType() VariableDeclarator() ( "," VariableDeclarator() )* } void LocalVariableType() #void : {} { LOOKAHEAD( { jdkVersion >= 10 && isKeyword("var") } ) | Type() } void EmptyStatement() : {} { ";" } void StatementExpression() : {} { PreIncrementExpression() | PreDecrementExpression() | LOOKAHEAD( PrimaryExpression() AssignmentOperator() ) PrimaryExpression() AssignmentOperator() Expression() | PostfixExpression() } void SwitchStatement(): {} { "switch" "(" Expression() ")" SwitchBlock() } void SwitchBlock() #void : {} { "{" ( SwitchLabel() ( "->" SwitchLabeledRulePart() (SwitchLabeledRule())* | ":" (LOOKAHEAD(2) SwitchLabel() ":")* (BlockStatement())* (SwitchLabeledStatementGroup())* ) )? "}" } void SwitchLabeledRule() #void : {checkForSwitchRules();} { SwitchLabel() "->" SwitchLabeledRulePart() } void SwitchLabeledRulePart() #void: {checkForSwitchRules();} { ( ( Expression() ";" ) #SwitchLabeledExpression(2) | ( Block() ) #SwitchLabeledBlock(2) | ( ThrowStatement() ) #SwitchLabeledThrowStatement(2) ) } // For PMD 7, make this a real node to group the labels + statements void SwitchLabeledStatementGroup() #void: {} { (LOOKAHEAD(2) SwitchLabel() ":")+ ( BlockStatement() )* } void SwitchLabel() : {} { { inSwitchLabel = true; } ( "case" ( ConditionalExpression() #Expression ) ({checkForMultipleCaseLabels();} "," ( ConditionalExpression() #Expression ) )* | "default" {jjtThis.setDefault();} ) { inSwitchLabel = false; } } void IfStatement() : /* * The disambiguating algorithm of JavaCC automatically binds dangling * else's to the innermost if statement. The LOOKAHEAD specification * is to tell JavaCC that we know what we are doing. */ {} { "if" "(" Expression() ")" Statement() [ LOOKAHEAD(1) "else" {jjtThis.setHasElse();} Statement() ] } void WhileStatement() : {} { "while" "(" Expression() ")" Statement() } void DoStatement() : {} { "do" Statement() "while" "(" Expression() ")" ";" } void ForStatement() : {} { "for" "(" ( LOOKAHEAD(LocalVariableDeclaration() ":") {checkForBadJDK15ForLoopSyntaxArgumentsUsage();} LocalVariableDeclaration() ":" Expression() | [ ForInit() ] ";" [ Expression() ] ";" [ ForUpdate() ] ) ")" Statement() } void ForInit() : {} { LOOKAHEAD( LocalVariableDeclaration() ) LocalVariableDeclaration() | StatementExpressionList() } void StatementExpressionList() : {} { StatementExpression() ( "," StatementExpression() )* } void ForUpdate() : {} { StatementExpressionList() } void BreakStatement() : {Token t;} { "break" [ LOOKAHEAD( ";") t= {jjtThis.setImage(t.image);} | Expression() {checkForBreakExpression();} ] ";" } void ContinueStatement() : {Token t;} { "continue" [ t= {jjtThis.setImage(t.image);} ] ";" } void ReturnStatement() : {} { "return" [ Expression() ] ";" } void ThrowStatement() : {} { "throw" Expression() ";" } void SynchronizedStatement() : {} { "synchronized" "(" Expression() ")" Block() } void TryStatement() : /* * Semantic check required here to make sure that at least one * resource/finally/catch is present. */ {} { "try" (ResourceSpecification())? Block() ( CatchStatement() )* [ FinallyStatement() ] } void ResourceSpecification() : {} { {checkForBadTryWithResourcesUsage();} "(" Resources() (LOOKAHEAD(2) ";")? ")" } void Resources() : {} { Resource() (LOOKAHEAD(2) ";" Resource())* } void Resource() : {} { LOOKAHEAD(2) ( ( "final" {jjtThis.setFinal(true);} | Annotation() )* LocalVariableType() VariableDeclaratorId() "=" Expression() ) | Name() {checkForBadConciseTryWithResourcesUsage();} } void CatchStatement() : {} { "catch" "(" FormalParameter() ")" Block() } void FinallyStatement() : {} { "finally" Block() } void AssertStatement() : { if (jdkVersion <= 3) { throw new ParseException("Can't use 'assert' as a keyword when running in JDK 1.3 mode!"); } } { Expression() [ ":" Expression() ] ";" } /* We use productions to match >>>, >> and > so that we can keep the * type declaration syntax with generics clean */ void RUNSIGNEDSHIFT(): // TODO 7.0.0 make #void {} { ( LOOKAHEAD({ getToken(1).kind == GT && ((Token.GTToken)getToken(1)).realKind == RUNSIGNEDSHIFT} ) ">" ">" ">" ) } void RSIGNEDSHIFT(): // TODO 7.0.0 make #void {} { ( LOOKAHEAD({ getToken(1).kind == GT && ((Token.GTToken)getToken(1)).realKind == RSIGNEDSHIFT} ) ">" ">" ) } /* Annotation syntax follows. */ void Annotation(): {} { LOOKAHEAD( "@" Name() "(" ( "=" | ")" )) NormalAnnotation() | LOOKAHEAD( "@" Name() "(" ) SingleMemberAnnotation() | MarkerAnnotation() } void NormalAnnotation(): {} { "@" Name() "(" [ MemberValuePairs() ] ")" {checkForBadAnnotationUsage();} } void MarkerAnnotation(): {} { "@" Name() {checkForBadAnnotationUsage();} } void SingleMemberAnnotation(): {} { "@" Name() "(" MemberValue() ")" {checkForBadAnnotationUsage();} } void MemberValuePairs(): {} { MemberValuePair() ( "," MemberValuePair() )* } void MemberValuePair(): {Token t;} { t= { jjtThis.setImage(t.image); } "=" MemberValue() } void MemberValue(): {} { Annotation() | MemberValueArrayInitializer() | ConditionalExpression() } void MemberValueArrayInitializer(): {} { "{" (MemberValue() ( LOOKAHEAD(2) "," MemberValue() )* [ "," ])? "}" } /* * We use that ghost production to factorise the check for JDK >= 1.8. */ void TypeAnnotation() #void: {} { Annotation() {checkForBadTypeAnnotations();} } /* Annotation Types. */ void AnnotationTypeDeclaration(int modifiers): { Token t; jjtThis.setModifiers(modifiers); } { "@" "interface" t= { checkForBadAnnotationUsage(); checkForBadTypeIdentifierUsage(t.image); jjtThis.setImage(t.image); } AnnotationTypeBody() } void AnnotationTypeBody(): {} { "{" ( AnnotationTypeMemberDeclaration() )* "}" } void AnnotationTypeMemberDeclaration(): { int modifiers; } { modifiers = Modifiers() ( LOOKAHEAD(Type() "(") AnnotationMethodDeclaration(modifiers) | ClassOrInterfaceDeclaration(modifiers) | LOOKAHEAD(3) EnumDeclaration(modifiers) | AnnotationTypeDeclaration(modifiers) | FieldDeclaration(modifiers) ) | ( ";" ) } void AnnotationMethodDeclaration(int modifiers): { Token t; jjtThis.setModifiers(modifiers); } { Type() t= "(" ")" [ DefaultValue() ] ";" { jjtThis.setImage(t.image); } } void DefaultValue(): {} { "default" MemberValue() } void ModuleDeclaration(): { StringBuilder s = new StringBuilder(); Token t; checkForBadModuleUsage(); } { ( Annotation() )* [LOOKAHEAD({isKeyword("open")}) {jjtThis.setOpen(true);}] LOOKAHEAD({isKeyword("module")}) t= { s.append(t.image); } ( "." t= { s.append('.').append(t.image); } )* { jjtThis.setImage(s.toString()); } "{" (ModuleDirective())* "}" } void ModuleDirective(): {} { ( LOOKAHEAD({isKeyword("requires")}) { jjtThis.setType(ASTModuleDirective.DirectiveType.REQUIRES); } (LOOKAHEAD({isKeyword("transitive")}) { jjtThis.setRequiresModifier(ASTModuleDirective.RequiresModifier.TRANSITIVE); } | "static" { jjtThis.setRequiresModifier(ASTModuleDirective.RequiresModifier.STATIC); } )? ModuleName() ";" ) | ( LOOKAHEAD({isKeyword("exports")}) { jjtThis.setType(ASTModuleDirective.DirectiveType.EXPORTS); } Name() [ LOOKAHEAD({isKeyword("to")}) ModuleName() ("," ModuleName())*] ";" ) | ( LOOKAHEAD({isKeyword("opens")}) { jjtThis.setType(ASTModuleDirective.DirectiveType.OPENS); } Name() [ LOOKAHEAD({isKeyword("to")}) ModuleName() ("," ModuleName())*] ";" ) | ( LOOKAHEAD({isKeyword("uses")}) { jjtThis.setType(ASTModuleDirective.DirectiveType.USES); } Name() ";" ) | ( LOOKAHEAD({isKeyword("provides")}) { jjtThis.setType(ASTModuleDirective.DirectiveType.PROVIDES); } Name() LOOKAHEAD({isKeyword("with")}) Name() ("," Name() )* ";" ) } // Similar to Name() void ModuleName(): { StringBuilder s = new StringBuilder(); Token t; } { t= { s.append(t.image); } ( "." t= {s.append('.').append(t.image);} )* {jjtThis.setImage(s.toString());} }