pmd/pmd-java/etc/grammar/Java.jjt

3252 lines
84 KiB
Plaintext
Raw Normal View History

/**
2019-04-04 18:51:57 +02:00
* Change expression, type and annotation grammar to remove unnecessary nodes,
* eliminate some inconsistencies, and most importantly have an expressive tree
* for primary expressions. Expressions and types now appear to be left-recursive.
* This also introduces AmbiguousName, which are pushed only in syntactically
* ambiguous contexts: https://docs.oracle.com/javase/specs/jls/se9/html/jls-6.html#jls-6.5.1
*
* Those are the first grammar changes for 7.0.0.
* Refs:
* #1661 [java] About operator nodes
* #1367 [java] Parsing error on annotated subclass
* #1150 [java] ClassOrInterfaceType AST improvements
* #1019 [java] Breaking Java Grammar changes for PMD 7.0.0
* #997 [java] Java8 parsing corner case with annotated array types
* #910 [java] AST inconsistency between primitive and reference type arrays
* #497 [java] RFC: new layer of abstraction atop PrimaryExpressions
* Clément Fournier 04/2019
2019-02-16 16:47:42 +01:00
*====================================================================
* 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
*====================================================================
2017-06-01 11:56:48 -03:00
* 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;
2018-11-06 04:22:31 +01:00
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) {
2019-02-17 14:25:07 +01:00
Node node = jjtree.peekNode();
2019-02-17 15:45:00 +01:00
if (node instanceof ASTConstructorCall) {
ASTConstructorCall expr = (ASTConstructorCall) node;
2019-03-09 19:10:49 +01:00
ASTTypeArguments types = expr.getTypeNode().getTypeArguments();
2019-02-17 14:25:07 +01:00
if (expr.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() {
2019-03-21 20:47:23 +01:00
Node top = jjtree.peekNode();
if (!(top instanceof ASTFieldAccess || top instanceof ASTVariableReference)) {
throwParseException("Expected a variable access, but was a " + top.getXPathNodeName());
}
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!");
}
}
2019-03-15 15:29:16 +01:00
private void checkForMultipleCaseLabels() {
if (jdkVersion < 12) {
throwParseException("Multiple case labels in switch statements are only supported with Java 12");
}
}
2019-03-15 20:51:53 +01:00
/**
* 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;
2019-03-15 15:29:16 +01:00
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");
}
}
2019-03-16 10:47:12 +01:00
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<Integer, String> getSuppressMap() {
return token_source.getSuppressMap();
}
public void setSuppressMarker(String marker) {
token_source.setSuppressMarker(marker);
}
2019-02-17 11:36:18 +01:00
private void setLastTokenImage(JavaNode node) {
node.setImage(getToken(0).getImage());
}
2019-03-21 20:47:23 +01:00
private void forceExprContext() {
Node top = jjtree.peekNode();
if (top instanceof ASTAmbiguousName) {
// see doc on the method
Node replacement = ((ASTAmbiguousName) top).forceExprContext();
jjtree.popNode();
jjtree.pushNode(replacement);
}
}
2019-04-03 14:48:48 +02:00
private void forceTypeContext() {
Node top = jjtree.peekNode();
if (top instanceof ASTAmbiguousName) {
// see doc on the method
Node replacement = ((ASTAmbiguousName) top).forceTypeContext();
jjtree.popNode();
jjtree.pushNode(replacement);
}
}
}
PARSER_END(JavaParser)
TOKEN_MGR_DECLS :
{
protected List<Comment> comments = new ArrayList<Comment>();
}
/* 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
}
<IN_FORMAL_COMMENT>
SPECIAL_TOKEN :
{
<FORMAL_COMMENT: "*/" > { comments.add(new FormalComment(matchedToken)); } : DEFAULT
}
<IN_MULTI_LINE_COMMENT>
SPECIAL_TOKEN :
{
<MULTI_LINE_COMMENT: "*/" > { comments.add(new MultiLineComment(matchedToken)); } : DEFAULT
}
<IN_FORMAL_COMMENT,IN_MULTI_LINE_COMMENT>
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:
<DECIMAL_LITERAL> (["l","L"])?
| <HEX_LITERAL> (["l","L"])?
| <BINARY_LITERAL> (["l","L"])?
| <OCTAL_LITERAL> (["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"])?)? (<EXPONENT>)? (["f","F","d","D"])?
| "." (["0"-"9"]((["0"-"9","_"])*["0"-"9"])?) (<EXPONENT>)? (["f","F","d","D"])?
| (["0"-"9"]((["0"-"9","_"])*["0"-"9"])?) <EXPONENT> (["f","F","d","D"])?
| (["0"-"9"]((["0"-"9","_"])*["0"-"9"])?) (<EXPONENT>)? ["f","F","d","D"]
>
|
< HEX_FLOATING_POINT_LITERAL:
(<HEX_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> (<PART_LETTER>)* >
|
< #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: "<<" >
2018-06-25 12:42:34 +02:00
// 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" > )?
( < "~[]" > )?
<EOF>
{
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):
{
2017-09-22 13:33:08 +02:00
Token t = null;
jjtThis.setModifiers(modifiers);
boolean inInterfaceOld = inInterface;
2017-09-22 13:33:08 +02:00
inInterface = false;
}
{
( /* See note about this optional final modifier in BlockStatement */
["final"|"abstract"] "class" | "interface" { jjtThis.setInterface(); inInterface = true; } )
t=<IDENTIFIER> { 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;
}
{
2019-03-21 13:58:03 +01:00
"extends" AnnotatedClassOrInterfaceType()
( "," AnnotatedClassOrInterfaceType() { extendsMoreThanOne = true; } )*
}
void ImplementsList():
{}
{
2019-03-21 13:58:03 +01:00
"implements" AnnotatedClassOrInterfaceType()
( "," AnnotatedClassOrInterfaceType() )*
}
void EnumDeclaration(int modifiers):
{
Token t;
jjtThis.setModifiers(modifiers);
}
{
t = <IDENTIFIER> {
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=<IDENTIFIER> {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():
{}
{
2019-04-26 00:27:23 +02:00
VariableDeclaratorId() [ ArgumentList() ] [ ClassOrInterfaceBody() #AnonymousClassDeclaration ]
}
void TypeParameters():
{}
{
"<" {checkForBadGenericsUsage();} TypeParameter() ( "," TypeParameter() )* ">"
}
void TypeParameter():
{Token t;}
{
AnnotationList()
t=<IDENTIFIER> {jjtThis.setImage(t.image);} [ TypeBound() ]
}
void TypeBound():
{}
{
2019-03-31 07:49:25 +02:00
"extends" TypeAnnotationList() IntersectionType(false)
}
void ClassOrInterfaceBody():
{}
{
"{" ( ClassOrInterfaceBodyDeclaration() )* "}"
}
void ClassOrInterfaceBodyDeclaration():
{
int modifiers;
}
{ LOOKAHEAD(["static"] "{" ) Initializer()
| modifiers = Modifiers()
( LOOKAHEAD(3) ClassOrInterfaceDeclaration(modifiers)
| LOOKAHEAD({isKeyword("enum")}) EnumDeclaration(modifiers)
| LOOKAHEAD( [ TypeParameters() ] <IDENTIFIER> "(" ) ConstructorDeclaration(modifiers)
| LOOKAHEAD( Type() <IDENTIFIER> ( "[" "]" )* ( "," | "=" | ";" ) ) FieldDeclaration(modifiers)
| LOOKAHEAD(2) MethodDeclaration(modifiers)
| LOOKAHEAD(2) AnnotationTypeDeclaration(modifiers)
)
|
";"
}
void FieldDeclaration(int modifiers) :
{jjtThis.setModifiers(modifiers);}
{
Type() VariableDeclarator() ( "," VariableDeclarator() )* ";"
}
void VariableDeclarator() :
{}
{
VariableDeclaratorId() [ "=" VariableInitializer() ]
}
2019-02-17 04:58:32 +01:00
// TODO use ArrayTypeDims
void VariableDeclaratorId() :
{
Token t;
String image;
}
{
(LOOKAHEAD(2) t=<IDENTIFIER> "." <THIS> { checkforBadExplicitReceiverParameter(); jjtThis.setExplicitReceiverParameter(); image=t.image + ".this"; }
| t=<THIS> { checkforBadExplicitReceiverParameter(); jjtThis.setExplicitReceiverParameter(); image = t.image;}
| t=<IDENTIFIER> { image = t.image; } ( "[" "]" { jjtThis.bumpArrayDepth(); })*
)
{
checkForBadAssertUsage(image, "a variable name");
checkForBadEnumUsage(image, "a variable name");
checkForBadIdentifier(image);
jjtThis.setImage( image );
}
}
2019-02-18 23:39:10 +01:00
void VariableInitializer() #void:
{}
{
ArrayInitializer()
| Expression()
}
void ArrayInitializer() :
{}
{
"{" [ VariableInitializer() ( LOOKAHEAD(2) "," VariableInitializer() )* ] [ "," ] "}"
}
void MethodDeclaration(int modifiers) :
{
jjtThis.setModifiers(modifiers);
{ checkForBadPrivateInterfaceMethod(jjtThis); }
}
{
[ TypeParameters() ]
2019-03-21 13:58:03 +01:00
ResultType() MethodDeclarator() [ "throws" NameList() ]
( Block() | ";" )
}
void MethodDeclarator() :
{Token t;}
{
t=<IDENTIFIER>
{
checkForBadAssertUsage(t.image, "a method name");
checkForBadEnumUsage(t.image, "a method name");
jjtThis.setImage( t.image );
}
2019-02-17 04:58:32 +01:00
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() ]
<IDENTIFIER> {jjtThis.setImage(getToken(0).getImage());} FormalParameters() [ "throws" NameList() ]
"{"
[ LOOKAHEAD(ExplicitConstructorInvocation()) ExplicitConstructorInvocation() ]
( BlockStatement() )*
t = "}" { if (isPrecededByComment(t)) { jjtThis.setContainsComment(); } }
}
void ExplicitConstructorInvocation() :
{}
{
2019-04-26 00:27:23 +02:00
LOOKAHEAD("this" ArgumentList() ";") "this" ArgumentList() ";"
|
2019-04-26 00:27:23 +02:00
LOOKAHEAD(TypeArguments() "this" ArgumentList() ";") TypeArguments() "this" ArgumentList() ";"
|
[LOOKAHEAD(PrimaryExpression() "." SuperInvocationTail()) PrimaryExpression() "." ] SuperInvocationTail() {jjtThis.setIsSuper();}
2019-04-25 19:46:06 +02:00
}
void SuperInvocationTail() #void:
2019-04-25 19:46:06 +02:00
{}
{
2019-04-26 00:27:23 +02:00
[ TypeArguments() ] "super" ArgumentList() ";"
}
void Initializer() :
{}
{
[ "static" {jjtThis.setStatic();} ] Block()
}
2018-11-05 21:20:43 +01:00
/* 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} [ ]}
*/
void IntersectionType(boolean inCast) #IntersectionType(isIntersection):
{boolean isIntersection=false;}
2019-03-21 13:58:03 +01:00
{
2019-03-30 18:39:11 +01:00
// The first type may be annotated, but the annotations are handled outside
Type() ( "&" {if (inCast) checkForBadIntersectionTypesInCasts();isIntersection=true;} ClassOrInterfaceType() )*
2019-03-21 13:58:03 +01:00
}
void AnnotationList() #void:
{}
2019-03-21 13:58:03 +01:00
{
(Annotation())*
2019-03-21 13:58:03 +01:00
}
void TypeAnnotationList() #void:
{}
2019-03-21 13:58:03 +01:00
{
(TypeAnnotation())*
2019-03-21 13:58:03 +01:00
}
void AnnotatedType() #void:
{}
2019-03-21 13:58:03 +01:00
{
TypeAnnotationList() Type()
2019-03-21 13:58:03 +01:00
}
void AnnotatedRefType() #void:
{}
2019-03-21 13:58:03 +01:00
{
TypeAnnotationList() ReferenceType()
2019-03-21 13:58:03 +01:00
}
void AnnotatedClassOrInterfaceType() #void:
{}
2019-03-21 13:58:03 +01:00
{
TypeAnnotationList() ClassOrInterfaceType()
2019-03-21 13:58:03 +01:00
}
/*
* 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
*/
2018-11-05 21:20:43 +01:00
void Type() #void:
{
Token t;
}
{
2019-02-16 11:44:34 +01:00
// lookahead to catch arrays of primitive types.
// we can't lookahead for just PrimitiveType() "["
// because the "[" may be preceded by annotations
LOOKAHEAD(PrimitiveType() ArrayTypeDim() | <IDENTIFIER>) ReferenceType()
| PrimitiveType()
}
2018-11-05 21:20:43 +01:00
void Dims() #ArrayTypeDims:
{}
{
2019-02-16 16:47:42 +01:00
// the list of dimensions is flat, but annotations are
// preserved within each specific dim.
2019-02-16 11:44:34 +01:00
(ArrayTypeDim())+
}
2018-11-05 21:20:43 +01:00
2019-02-16 11:44:34 +01:00
void ArrayTypeDim():
{}
{
(TypeAnnotation())* "[" "]"
2018-11-05 21:20:43 +01:00
}
2018-11-05 21:20:43 +01:00
void ReferenceType() #void:
{}
{
2018-11-06 04:22:31 +01:00
( PrimitiveType() Dims() ) #ArrayType
2018-11-05 21:20:43 +01:00
| ( ClassOrInterfaceType() [ LOOKAHEAD(2) Dims() ] ) #ArrayType(>1)
}
2018-11-07 08:52:19 +01:00
/**
2019-02-16 11:15:52 +01:00
* Parses a ClassOrInterfaceType. The production itself is #void,
2019-02-16 11:44:34 +01:00
* but the node exists (declared inline within the production).
2018-11-07 08:52:19 +01:00
*/
2018-11-06 04:22:31 +01:00
void ClassOrInterfaceType() #void:
2019-02-18 17:55:41 +01:00
{}
{
/*
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.
*/
2019-02-18 17:55:41 +01:00
/*
First, gobble up all identifiers until the first type arguments
or annotation is found. The name is ambiguous between package or
type name unless type arguments are present, in which case we can
be sure that the last segment is a type name.
*/
( AmbiguousName() [ TypeArguments() ]) #ClassOrInterfaceType(>1)
2018-11-06 04:22:31 +01:00
{
2019-02-18 17:55:41 +01:00
// At this point the first ClassOrInterfaceType may be on top of the stack,
2019-02-18 18:19:38 +01:00
// but its image is not set. If it is on the stack we need to shrink the bounds
// of the ambiguous name, or delete it.
2019-02-18 17:55:41 +01:00
Node first = jjtree.peekNode();
if (!(first instanceof ASTAmbiguousName)) {
// then we saw type arguments, so the last segment is definitely a type name
ASTAmbiguousName name = (ASTAmbiguousName) first.jjtGetChild(0);
name.shrinkOrDeleteInParentSetImage();
}
2018-11-06 04:22:31 +01:00
}
2019-02-16 11:44:34 +01:00
/*
2019-03-24 19:27:59 +01:00
Now if there are other segments, either the previous segment specified type
2019-04-03 14:48:48 +02:00
arguments, or the next has an annotation. Either way we know that all the
following segments is a type name. Each segment is parsed as its own ClassOrInterfaceType
which encloses the previous one. The resulting structure appears left-recursive, but the parser just
2019-02-16 12:02:21 +01:00
executes a loop. That scheme preserves the position of type arguments and annotations.
2019-02-16 11:44:34 +01:00
See #1150.
*/
2018-11-06 04:22:31 +01:00
( LOOKAHEAD(2)
(
"."
(TypeAnnotation())*
2019-02-18 17:55:41 +01:00
<IDENTIFIER> { jjtThis.setImage(getToken(0).getImage()); }
{jjtree.extendLeft();} // We'll enclose the previous segment
2018-11-06 04:22:31 +01:00
[ LOOKAHEAD( "<" ) TypeArguments() ]
2019-02-17 04:37:48 +01:00
) #ClassOrInterfaceType
2018-11-06 04:22:31 +01:00
)*
2019-04-03 14:48:48 +02:00
{ forceTypeContext(); }
}
2018-11-06 04:22:31 +01:00
void TypeArguments():
{}
{
LOOKAHEAD(2)
2019-03-31 06:59:49 +02:00
"<" {checkForBadGenericsUsage();} TypeArgument() ( "," TypeArgument() )* ">"
|
"<" {checkForBadDiamondUsage();} ">"
}
2019-03-31 06:59:49 +02:00
void TypeArgument() #void:
{}
2019-03-21 13:58:03 +01:00
{
TypeAnnotationList() (ReferenceType() | WildcardType())
2019-03-21 13:58:03 +01:00
}
void WildcardType():
{}
{
"?" [ ("extends" {jjtThis.setUpperBound(true);}| "super") AnnotatedRefType() ]
}
2018-11-05 21:20:43 +01:00
/* 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() :
{}
{
2019-02-16 16:47:42 +01:00
( "boolean"
| "char"
| "byte"
| "short"
| "int"
| "long"
| "float"
| "double"
)
{jjtThis.setImage(getToken(0).getImage());}
}
void ResultType() :
{}
{
2019-03-21 13:58:03 +01:00
"void" | AnnotatedType()
}
void TypeOrVoid() #void:
{}
{
"void" | Type()
}
2019-02-17 08:55:37 +01:00
2019-03-21 13:58:03 +01:00
// TODO rename to ThrowsClause
void NameList() :
{}
{
(TypeAnnotation())* Name()
( "," (TypeAnnotation())* Name()
)*
}
/*
* Expression syntax follows.
*/
2019-02-18 10:53:17 +01:00
void Expression() #AssignmentExpression(>1):
/*
* 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.
*/
2018-06-25 12:42:34 +02:00
// 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
2019-03-15 20:51:53 +01:00
//
// To prevent LambdaExpressions in switch labels, the field #inSwitchLabel is used
// as a workaround.
2019-02-19 00:15:26 +01:00
{AssignmentOp op = null;}
{
ConditionalExpression()
[
2019-02-18 10:53:17 +01:00
LOOKAHEAD(2) op=AssignmentOperator() {jjtThis.setOp(op);} Expression()
]
}
2019-02-19 02:30:43 +01:00
AssignmentOp AssignmentOperator() #void:
{}
{
2019-04-03 14:48:48 +02:00
( "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | ">>>=" | "&=" | "^=" | "|=" )
2019-02-19 00:15:26 +01:00
{return AssignmentOp.fromImage(getToken(0).getImage());}
}
2018-06-25 12:42:34 +02:00
// 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() )*
}
// same as ShiftExpression
void EqualityExpression() #void:
{}
{
2019-04-04 14:32:54 +02:00
InstanceOfExpression() (EqualityExprTail())*
}
void EqualityExprTail() #EqualityExpression:
{}
{
( "==" | "!=" )
{
jjtThis.setImage(getToken(0).getImage());
jjtree.extendLeft();
}
InstanceOfExpression()
}
void InstanceOfExpression() #InstanceOfExpression(>1):
{}
{
RelationalExpression() [ LOOKAHEAD(2) "instanceof" Type() ]
}
void RelationalExpression() #RelationalExpression(>1):
{}
{
ShiftExpression()
2019-03-29 19:03:03 +01:00
(
( "<" | ">" | "<=" | ">=" )
{ jjtThis.setImage(getToken(0).getImage()); }
ShiftExpression()
)?
// There cannot be more than one, because it wouldn't compile
// From the JLS:
// For example, a<b<c parses as (a<b)<c, which is always a compile-time
// error, because the type of a<b is always boolean and < is not an operator
// on boolean values.
}
2019-03-28 08:50:55 +01:00
/**
* The structure parsed by this production is entirely left-recursive,
2019-03-29 18:50:43 +01:00
* but the jjtClose of AbstractLrBinaryExpr flattens the first child
2019-03-28 08:50:55 +01:00
* if the operator is the same. This is the best compromise I've found,
* it keeps the grammar readable and simple to parse in lookaheads.
*/
2019-03-29 18:50:43 +01:00
void ShiftExpression() #void:
{}
{
AdditiveExpression() (ShiftExprTail())*
}
void ShiftExprTail() #ShiftExpression:
{}
{
( "<<" { jjtThis.setImage("<<");}
| RSIGNEDSHIFT() { jjtThis.setImage(">>"); }
| RUNSIGNEDSHIFT() { jjtThis.setImage(">>>"); }
)
{
jjtree.extendLeft();
}
AdditiveExpression()
}
// this is exactly similar to ShiftExpression
2019-03-28 07:53:08 +01:00
void AdditiveExpression() #void:
{}
{
2019-03-28 09:01:55 +01:00
MultiplicativeExpression() (AdditiveExprTail())*
2019-03-28 07:53:08 +01:00
}
void AdditiveExprTail() #AdditiveExpression:
{}
{
( "+" | "-" )
{
jjtThis.setImage(getToken(0).getImage());
jjtree.extendLeft();
}
MultiplicativeExpression()
}
2019-03-29 18:50:43 +01:00
// this is exactly similar to ShiftExpression
2019-03-28 09:01:55 +01:00
void MultiplicativeExpression() #void:
{}
{
2019-03-28 09:01:55 +01:00
UnaryExpression() (MultiplicativeExprTail())*
}
2019-03-28 09:01:55 +01:00
void MultiplicativeExprTail() #MultiplicativeExpression:
{}
{
( "*" | "/" | "%" )
{
jjtThis.setImage(getToken(0).getImage());
jjtree.extendLeft();
}
UnaryExpression()
}
void UnaryExpression() #UnaryExpression((jjtn000.getImage() != null)):
{}
{
("+" {jjtThis.setImage("+");} | "-" {jjtThis.setImage("-");}) UnaryExpression()
| PreIncrementExpression()
| PreDecrementExpression()
| UnaryExpressionNotPlusMinus()
}
void PreIncrementExpression() :
{}
{
"++" PrimaryExpression()
}
void PreDecrementExpression() :
{}
{
"--" PrimaryExpression()
}
2019-02-19 00:15:26 +01:00
void UnaryExpressionNotPlusMinus() #UnaryExpression((jjtn000.getImage() != null)):
{}
{
( "~" {jjtThis.setImage("~");} | "!" {jjtThis.setImage("!");} ) UnaryExpression()
2019-03-30 18:39:11 +01:00
// There's no separate production for CastExpression, because that would force
// us to repeat the lookahead
// Those lookaheads are very expensive, they're run to disambiguate between
// ParenthesizedExpression and CastExpression.
2019-03-30 18:39:11 +01:00
| LOOKAHEAD("(" TypeAnnotationList() PrimitiveType() ")")
("(" AnnotatedType() ")" UnaryExpression()) #CastExpression
| LOOKAHEAD("(" TypeAnnotationList() IntersectionType(true) ")" UnaryExpressionNotPlusMinus() )
("(" TypeAnnotationList() IntersectionType(true) ")" UnaryExpressionNotPlusMinus()) #CastExpression
| PostfixExpression()
2019-03-15 15:29:16 +01:00
| SwitchExpression()
}
void PostfixExpression() #PostfixExpression((jjtn000.getImage() != null)):
{}
{
PrimaryExpression() [ "++" {jjtThis.setImage("++");} | "--" {jjtThis.setImage("--");} ]
}
2019-03-15 15:29:16 +01:00
void SwitchExpression() :
{}
{
{checkForSwitchExpression();}
2019-03-15 20:51:53 +01:00
"switch" "(" Expression() ")" SwitchBlock()
2019-03-15 15:29:16 +01:00
}
2019-02-17 14:25:07 +01:00
/**
* A primary expression. This includes call chains, etc.
*
* A PrimaryPrefix corresponds to an unqualified primary expression,
* e.g "new Foo()". Then, if any, suffixes of the form e.g. ".method()",
* ".field" or "::ref" are added, each time enclosing the previous node.
*
* The resulting subtree looks left-recursive, but the parsing is iterative.
*/
void PrimaryExpression() #void :
{}
{
2019-04-25 19:46:06 +02:00
PrimaryPrefix() ( LOOKAHEAD(SuffixLAhead()) PrimarySuffix() )* {forceExprContext();}
}
2019-02-18 16:59:23 +01:00
/*
Expressions that may be present at the start of a primary expression.
2019-02-18 22:45:20 +01:00
TODO some lookaheads can be simplified if we're ok with loosing some strictness
2019-02-18 16:59:23 +01:00
*/
void PrimaryPrefix() #void :
{Token t;}
{
Literal()
2019-02-18 16:59:23 +01:00
| "this" #ThisExpression
| "super" #SuperExpression
2019-02-18 16:59:23 +01:00
// todo we can probably simplify the lambda lookaheads
2019-03-15 20:51:53 +01:00
| LOOKAHEAD( <IDENTIFIER> "->", {!inSwitchLabel} ) LambdaExpression()
2019-04-03 14:13:16 +02:00
| LOOKAHEAD( "(" <IDENTIFIER> ( "," <IDENTIFIER> )* ")" "->" , {!inSwitchLabel} ) LambdaExpression()
| LOOKAHEAD( LambdaParameterList() "->", {!inSwitchLabel} ) LambdaExpression()
2019-03-24 19:27:59 +01:00
| ("(" Expression() ")") #ParenthesizedExpression
2019-02-17 14:25:07 +01:00
| UnqualifiedAllocationExpr()
2019-02-18 18:48:31 +01:00
| LOOKAHEAD( TypeOrVoid() "." "class" )
(TypeOrVoid() "." "class") #ClassLiteral
| LOOKAHEAD( ReferenceType() "::" [TypeArguments()] "new" )
ReferenceType() MethodReference()
2019-02-18 16:59:23 +01:00
// not a constructor reference, and is just a sequence of identifiers: could be an expression or a type
2019-02-18 18:48:31 +01:00
| LOOKAHEAD( Name() "::" )
AmbiguousName() MethodReference()
2019-02-18 22:45:20 +01:00
// we know it's not just a sequence of identifiers, so if
// ReferenceType matches, there are type parameters or annots,
// which means we shouldn't parse as an ambiguous name otherwise
// we choke on the type parameters
2019-02-18 18:48:31 +01:00
| LOOKAHEAD( ReferenceType() "::" )
ReferenceType() MethodReference()
| AmbiguousName() [ LOOKAHEAD("." "super" ".")
2019-04-25 19:46:06 +02:00
// The LHS of this or super is necessarily a type name, ie ambiguous
// Having this here instead of in PrimarySuffix makes the grammar more
// restrictive and also allows ExplicitConstructorInvocation to be parsed
"." "super" #SuperExpression(1) MemberSelector()
2019-04-25 19:46:06 +02:00
]
}
/**
2019-02-18 16:59:23 +01:00
* Productions that may be present after a PrimaryPrefix. The way this is written makes for a nice tree,
* but also allows many invalid things to be written (which is fine because we parse compilable code).
* E.g. this allows `foo().this::bar[0].this`
2019-02-18 16:59:23 +01:00
*
* Not all PrimaryPrefix expressions are here, eg
*/
2019-02-17 10:28:12 +01:00
void PrimarySuffix() #void :
{}
{
2019-03-24 19:27:59 +01:00
MethodReference()
2019-04-26 00:27:23 +02:00
| ArgumentList() #MethodCall(2)
2019-03-24 19:27:59 +01:00
| ("[" Expression() "]") #ArrayAccess(2)
2019-02-18 22:45:20 +01:00
// all the following start with a "."
| LOOKAHEAD(2) "." "this" #ThisExpression(1)
2019-02-18 16:59:23 +01:00
// lookahead("." "new")
2019-03-24 19:27:59 +01:00
| LOOKAHEAD(2) QualifiedAllocationExpr()
2019-04-25 19:46:06 +02:00
| LOOKAHEAD("." [TypeArguments()] <IDENTIFIER>) MemberSelector() // more complex method call patterns
2019-03-24 19:27:59 +01:00
}
2019-04-25 19:46:06 +02:00
void SuffixLAhead() #void:
{}
{
// not "super", otherwise runs into conflicts with ExplicitConstructorInvocation
"." ("new" | "this" | [ TypeArguments() ] <IDENTIFIER>)
2019-04-25 19:46:06 +02:00
| "::"
| "["
| "("
}
2019-03-24 19:27:59 +01:00
void MemberSelector() #void :
{}
{
// if there are type arguments, this is a method call
2019-04-26 00:27:23 +02:00
LOOKAHEAD(2) ("." {jjtree.extendLeft();} TypeArguments() <IDENTIFIER> {setLastTokenImage (jjtThis) ;} ArgumentList()) #MethodCall
| LOOKAHEAD(3) ("." {jjtree.extendLeft();} <IDENTIFIER> {setLastTokenImage(jjtThis);} ArgumentList()) #MethodCall
2019-03-24 19:27:59 +01:00
| ("." {jjtree.extendLeft();} <IDENTIFIER> {setLastTokenImage(jjtThis);}) #FieldAccess
}
void MethodReference(): // LHS is injected
{checkForBadMethodReferenceUsage();}
{
"::" {jjtree.extendLeft();}
[TypeArguments()] ( "new" | <IDENTIFIER>) {setLastTokenImage(jjtThis);}
2019-02-17 10:28:12 +01:00
}
void LambdaExpression():
{ checkForBadLambdaUsage(); }
{
LambdaParameterList() "->" ( Expression() | Block() )
}
void LambdaParameterList():
2018-07-19 22:00:34 +02:00
{}
{
VariableDeclaratorId() #LambdaParameter
| LOOKAHEAD("(" <IDENTIFIER> ("," | ")"))
"(" [ VariableDeclaratorId() #LambdaParameter(true) ( "," VariableDeclaratorId() #LambdaParameter )* ] ")"
| "(" [ LambdaParameter() ( "," LambdaParameter() )* ] ")"
2018-07-19 22:00:34 +02:00
}
void LambdaParameter():
{boolean isVarType = false;}
2018-07-19 22:00:34 +02:00
{
[
( "final" {jjtThis.setFinal(true);} | Annotation() )*
isVarType=LambdaParameterType() { jjtThis.setVarType(); }
[ "..." {checkForBadVariableArgumentsUsage();} {jjtThis.setVarargs();} ]
]
2018-07-19 22:00:34 +02:00
VariableDeclaratorId()
}
/** Returns true if this is "var". */
boolean LambdaParameterType() #void :
2018-07-19 22:00:34 +02:00
{}
{
LOOKAHEAD( { jdkVersion >= 11 && isKeyword("var") } )
<IDENTIFIER> { return true; }
| Type() { return false; }
2018-07-19 22:00:34 +02:00
}
2019-02-17 05:41:33 +01:00
void Literal() #void :
{ Token t;}
{
2019-02-17 05:41:33 +01:00
NumericLiteral()
| StringLiteral()
| CharLiteral()
| ("true" { jjtThis.setTrue(); } | "false") #BooleanLiteral
| "null" #NullLiteral
}
2019-02-17 05:41:33 +01:00
void NumericLiteral():
{
Token t;
}
{
2019-03-24 19:27:59 +01:00
( t=<INTEGER_LITERAL> { jjtThis.setIntLiteral();}
| t=<FLOATING_POINT_LITERAL> { jjtThis.setFloatLiteral();}
| t=<HEX_FLOATING_POINT_LITERAL> { checkForBadHexFloatingPointLiteral(); jjtThis.setFloatLiteral();}
2019-02-17 05:41:33 +01:00
)
{
checkForBadNumericalLiteralslUsage(t);
jjtThis.setImage(t.image);
}
}
void CharLiteral():
{}
{
2019-02-17 05:41:33 +01:00
<CHARACTER_LITERAL> {jjtThis.setImage(getToken(0).getImage());}
}
2019-02-17 05:41:33 +01:00
void StringLiteral():
{}
2019-02-17 05:41:33 +01:00
{
<STRING_LITERAL> { jjtThis.setImage(getToken(0).getImage()); }
}
2019-02-17 08:55:37 +01:00
void Arguments() : // TODO remove
{}
{
2019-04-26 00:27:23 +02:00
ArgumentList()
}
2019-04-26 00:27:23 +02:00
void ArgumentList() :
{}
{
"(" [ Expression() ( "," Expression() )* ] ")"
}
2019-02-17 14:25:07 +01:00
// more straightforward because can't be an array creation expr
2019-02-17 15:45:00 +01:00
void QualifiedAllocationExpr() #ConstructorCall:
2019-02-17 14:25:07 +01:00
{}
{
"."
"new"
{jjtree.extendLeft();}
2019-02-17 14:25:07 +01:00
[ TypeArguments() ]
2019-03-24 13:29:05 +01:00
TypeAnnotationList()
ClassOrInterfaceType()
2019-04-26 00:27:23 +02:00
ArgumentList()
2019-02-17 14:25:07 +01:00
[
{ boolean inInterfaceOld = inInterface; inInterface = false; /* a anonymous class is not a interface */ }
ClassOrInterfaceBody() #AnonymousClassDeclaration
{ inInterface = inInterfaceOld; } // always restore the flag after leaving the node
]
{ checkForBadAnonymousDiamondUsage(); }
}
// this is much weaker than the JLS but since we parse compilable code
// the actual terms we get respect the JLS.
// only used in PrimaryPrefix
void UnqualifiedAllocationExpr() #void :
2019-03-26 18:09:47 +01:00
{
boolean isArrayInit=false;
}
2019-02-17 14:25:07 +01:00
{
(
(
"new" [ TypeArguments() ] (TypeAnnotation())*
(
2019-03-26 18:09:47 +01:00
PrimitiveType() ArrayDimsAndInits(){isArrayInit=true;}
2019-02-17 14:25:07 +01:00
|
ClassOrInterfaceType()
(
2019-03-26 18:09:47 +01:00
ArrayDimsAndInits() {isArrayInit=true;}
2019-02-17 14:25:07 +01:00
|
2019-04-26 00:27:23 +02:00
ArgumentList()
2019-02-17 14:25:07 +01:00
[
{ boolean inInterfaceOld = inInterface; inInterface = false; /* a anonymous class is not a interface */ }
ClassOrInterfaceBody() #AnonymousClassDeclaration
{ inInterface = inInterfaceOld; } // always restore the flag after leaving the node
]
)
)
2019-03-26 18:09:47 +01:00
{/*Empty unit, important*/}
2019-02-17 14:25:07 +01:00
)
2019-03-26 18:09:47 +01:00
#ArrayAllocation(isArrayInit)
2019-02-17 14:25:07 +01:00
)
2019-03-26 18:09:47 +01:00
#ConstructorCall(!isArrayInit)
2019-02-17 14:25:07 +01:00
{ checkForBadAnonymousDiamondUsage(); }
}
/*
* The second LOOKAHEAD specification below is to parse to PrimarySuffix
* if there is an expression between the "[...]".
*/
2019-03-26 18:09:47 +01:00
void ArrayDimsAndInits() #void:
{}
{
2019-03-26 18:09:47 +01:00
LOOKAHEAD(TypeAnnotationList() "[" "]" ) ((ArrayTypeDim())+) #ArrayAllocationDims [ ArrayInitializer() ]
| (ArrayDimExpr())+ #ArrayAllocationDims
}
2019-03-26 18:09:47 +01:00
void ArrayDimExpr() #void:
{boolean hasExpr=false;}
{
((TypeAnnotationList() "[" [ Expression() {hasExpr=true;} ] "]") #ArrayDimExpr(hasExpr) ) #ArrayTypeDim(!hasExpr)
}
2019-03-26 18:09:47 +01:00
/*
* 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=<IDENTIFIER> {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() <IDENTIFIER>)
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") } ) <IDENTIFIER>
| Type()
}
void EmptyStatement() :
{}
{
";"
}
void StatementExpression() :
2019-02-19 00:15:26 +01:00
{AssignmentOp op = null;}
{
PreIncrementExpression()
|
PreDecrementExpression()
|
// using PostfixExpression here allows us to skip the part of the production tree
2019-02-18 10:53:17 +01:00
// between Expression() and PostfixExpression()
(PostfixExpression() [ op=AssignmentOperator() {jjtThis.setOp(op);} Expression() ]) #AssignmentExpression(>1)
}
2019-03-15 15:29:16 +01:00
void SwitchStatement():
{}
{
2019-03-15 20:51:53 +01:00
"switch" "(" Expression() ")" SwitchBlock()
}
2019-03-15 15:29:16 +01:00
void SwitchBlock() #void :
{}
{
2019-03-15 20:51:53 +01:00
"{"
(
SwitchLabel()
(
"->" SwitchLabeledRulePart() (SwitchLabeledRule())*
|
":" (LOOKAHEAD(2) SwitchLabel() ":")* (BlockStatement())* (SwitchLabeledStatementGroup())*
)
)?
2019-03-16 07:53:02 +01:00
"}"
2019-03-15 15:29:16 +01:00
}
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() :
{}
{
2019-03-15 20:51:53 +01:00
{ inSwitchLabel = true; }
(
2019-04-03 14:13:16 +02:00
"case" (ConditionalExpression()) ({checkForMultipleCaseLabels();} "," (ConditionalExpression()) )*
|
2019-03-15 15:29:16 +01:00
"default" {jjtThis.setDefault();}
2019-03-15 20:51:53 +01:00
)
{ inSwitchLabel = false; }
2019-03-15 15:29:16 +01:00
}
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;}
{
2019-03-17 10:14:00 +01:00
"break" [ LOOKAHEAD(<IDENTIFIER> ";") t=<IDENTIFIER> {jjtThis.setImage(t.image);} | Expression() {checkForBreakExpression();} ] ";"
}
void ContinueStatement() :
{Token t;}
{
"continue" [ t=<IDENTIFIER> {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() :
{}
{
2019-03-21 20:47:23 +01:00
LOOKAHEAD(("final" | Annotation())* LocalVariableType() VariableDeclaratorId() "=" )
( ( "final" {jjtThis.setFinal(true);} | Annotation() )* LocalVariableType() VariableDeclaratorId() "=" Expression() )
|
2019-03-21 20:47:23 +01:00
PrimaryExpression() {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!");
}
}
{
<IDENTIFIER> Expression() [ ":" Expression() ] ";"
}
/* We use productions to match >>>, >> and > so that we can keep the
* type declaration syntax with generics clean
*/
2019-03-26 20:43:31 +01:00
void RUNSIGNEDSHIFT() #void:
{}
{
( LOOKAHEAD({ getToken(1).kind == GT &&
((Token.GTToken)getToken(1)).realKind == RUNSIGNEDSHIFT} )
">" ">" ">"
)
}
2019-03-26 20:43:31 +01:00
void RSIGNEDSHIFT() #void:
{}
{
( LOOKAHEAD({ getToken(1).kind == GT &&
((Token.GTToken)getToken(1)).realKind == RSIGNEDSHIFT} )
">" ">"
)
}
/* Annotation syntax follows. */
2019-03-21 15:07:55 +01:00
void Annotation() #void:
{}
{
2019-03-21 15:07:55 +01:00
(
LOOKAHEAD( "@" Name() "(" ( <IDENTIFIER> "=" | ")" ))
NormalAnnotation()
|
LOOKAHEAD( "@" Name() "(" )
SingleMemberAnnotation()
|
MarkerAnnotation()
2019-03-21 15:07:55 +01:00
)
{checkForBadAnnotationUsage();}
}
void AnnotationBase(Node n) #void:
{String name = null;}
{
"@" name=VoidName() {n.setImage(name);}
}
void NormalAnnotation():
{}
{
2019-03-21 15:07:55 +01:00
AnnotationBase(jjtThis) "(" [ MemberValuePairs() ] ")"
}
void MarkerAnnotation():
{}
{
2019-03-21 15:07:55 +01:00
AnnotationBase(jjtThis)
}
void SingleMemberAnnotation():
{}
{
2019-03-21 15:07:55 +01:00
AnnotationBase(jjtThis) "(" MemberValue() ")"
}
2019-03-21 15:34:40 +01:00
void MemberValuePairs() #void:
{}
{
MemberValuePair() ( "," MemberValuePair() )*
}
void MemberValuePair():
{Token t;}
{
t=<IDENTIFIER> { jjtThis.setImage(t.image); } "=" MemberValue()
}
2019-03-21 15:07:55 +01:00
void MemberValue() #void:
{}
{
Annotation()
|
MemberValueArrayInitializer()
|
2019-03-21 15:07:55 +01:00
// Constant expression
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=<IDENTIFIER>
{
checkForBadAnnotationUsage();
checkForBadTypeIdentifierUsage(t.image);
jjtThis.setImage(t.image);
}
AnnotationTypeBody()
}
void AnnotationTypeBody():
{}
{
"{" ( AnnotationTypeMemberDeclaration() )* "}"
}
void AnnotationTypeMemberDeclaration():
{
int modifiers;
}
{
modifiers = Modifiers()
(
LOOKAHEAD(Type() <IDENTIFIER> "(") AnnotationMethodDeclaration(modifiers)
|
ClassOrInterfaceDeclaration(modifiers)
|
LOOKAHEAD(3) EnumDeclaration(modifiers)
|
AnnotationTypeDeclaration(modifiers)
|
FieldDeclaration(modifiers)
)
|
( ";" )
}
void AnnotationMethodDeclaration(int modifiers):
{
Token t;
jjtThis.setModifiers(modifiers);
}
{
Type() t=<IDENTIFIER> "(" ")" [ DefaultValue() ] ";"
{
jjtThis.setImage(t.image);
}
}
void DefaultValue():
{}
{
"default" MemberValue()
}
void ModuleDeclaration():
{
StringBuilder s = new StringBuilder();
Token t;
checkForBadModuleUsage();
}
{
( Annotation() )* [LOOKAHEAD({isKeyword("open")}) <IDENTIFIER> {jjtThis.setOpen(true);}] LOOKAHEAD({isKeyword("module")}) <IDENTIFIER>
t=<IDENTIFIER> { s.append(t.image); }
( "." t=<IDENTIFIER> { s.append('.').append(t.image); } )* { jjtThis.setImage(s.toString()); }
"{" (ModuleDirective())* "}"
}
void ModuleDirective():
{}
{
( LOOKAHEAD({isKeyword("requires")}) <IDENTIFIER> { jjtThis.setType(ASTModuleDirective.DirectiveType.REQUIRES); }
(LOOKAHEAD({isKeyword("transitive")}) <IDENTIFIER> { jjtThis.setRequiresModifier(ASTModuleDirective.RequiresModifier.TRANSITIVE); } |
"static" { jjtThis.setRequiresModifier(ASTModuleDirective.RequiresModifier.STATIC); } )?
ModuleName() ";" )
| ( LOOKAHEAD({isKeyword("exports")}) <IDENTIFIER> { jjtThis.setType(ASTModuleDirective.DirectiveType.EXPORTS); } Name() [ LOOKAHEAD({isKeyword("to")}) <IDENTIFIER> ModuleName() ("," ModuleName())*] ";" )
| ( LOOKAHEAD({isKeyword("opens")}) <IDENTIFIER> { jjtThis.setType(ASTModuleDirective.DirectiveType.OPENS); } Name() [ LOOKAHEAD({isKeyword("to")}) <IDENTIFIER> ModuleName() ("," ModuleName())*] ";" )
| ( LOOKAHEAD({isKeyword("uses")}) <IDENTIFIER> { jjtThis.setType(ASTModuleDirective.DirectiveType.USES); } Name() ";" )
| ( LOOKAHEAD({isKeyword("provides")}) <IDENTIFIER> { jjtThis.setType(ASTModuleDirective.DirectiveType.PROVIDES); } Name() LOOKAHEAD({isKeyword("with")}) <IDENTIFIER> Name() ("," Name() )* ";" )
}
// Similar to Name()
void ModuleName():
{
StringBuilder s = new StringBuilder();
Token t;
}
{
t=<IDENTIFIER> { s.append(t.image); }
( "." t=<IDENTIFIER> {s.append('.').append(t.image);} )*
{jjtThis.setImage(s.toString());}
}
2019-02-17 10:28:12 +01:00
void Name():
{String image;}
{
image=VoidName()
{jjtThis.setImage(image); }
}
2019-02-18 17:55:41 +01:00
void AmbiguousName():
{String image;}
{
image=VoidName()
{jjtThis.setImage(image); }
}
2019-02-17 10:28:12 +01:00
String VoidName() #void:
/*
* 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=<IDENTIFIER>
{
s.append(t.image);
}
( LOOKAHEAD(2) "." t=<IDENTIFIER>
{s.append('.').append(t.image);}
)*
{return s.toString();}
}
2019-02-18 16:59:23 +01:00
// This is used to get JJTree to generate a node.
2019-04-03 14:48:48 +02:00
// Variable references are always ambiguous
// when they're parsed, so they're not created
// normally by jjtree, but rather by the disambiguation
// hooks spread across the parser
2019-02-18 16:59:23 +01:00
//noinspection JavaCCJccUnusedProduction
void VariableReference():
{}
{
<IDENTIFIER>
2019-03-24 19:27:59 +01:00
}