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

3372 lines
89 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
*====================================================================
2019-05-30 15:06:50 +02:00
* Fix #1848 Local classes should preserve their modifiers
* Clément Fournier 05/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
*====================================================================
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);
}
2019-05-30 15:48:55 +02:00
private boolean shouldStartStatementInSwitch() {
switch (getToken(1).kind) {
case _DEFAULT:
case CASE:
case RBRACE:
return false;
default:
return true;
}
}
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);
}
}
2019-05-24 16:33:48 +02:00
// make the top node a child of the second node on the stack
private void injectTop() {
AbstractJavaNode top = (AbstractJavaNode) jjtree.popNode();
AbstractJavaNode prev = (AbstractJavaNode) jjtree.peekNode();
prev.jjtAddChild(top, prev.jjtGetNumChildren());
prev.jjtSetLastToken(top.jjtGetLastToken());
}
2019-05-24 17:29:36 +02:00
/**
* Keeps track during tree construction, whether we are currently building an
* explicit constructor invocation. Then the PrimaryExpression that may prefix
* a qualified super constructor call may not consume "super" tokens.
*/
private boolean inExplicitConstructorInvoc = false;
}
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() )* )*
2019-05-25 07:24:55 +02:00
// the module decl lookahead needs to be before the type declaration branch,
// looking for annotations + "open" | "module" will fail faster if it's *not*
// a module (most common case)
[ LOOKAHEAD(ModuleDeclLahead()) ModuleDeclaration() ( EmptyStatement() )* ]
( TypeDeclaration() ( EmptyStatement() )* )*
( < "\u001a" > )?
2019-05-25 07:24:55 +02:00
( < "~[]" > )? // what's this for? Do you mean ( < ~[] > )*, i.e. "any character"?
<EOF>
2019-05-25 07:24:55 +02:00
{
jjtThis.setComments(token_source.comments);
return jjtThis;
}
}
2019-05-25 07:24:55 +02:00
private void ModuleDeclLahead() #void:
{}
{
(Annotation())* LOOKAHEAD({isKeyword("open") || isKeyword("module")}) <IDENTIFIER>
}
2019-05-25 07:24:55 +02:00
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;
}
{
(
2019-05-24 19:08:06 +02:00
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(); }
2019-05-24 19:08:06 +02:00
| 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;
}
{
( "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-05-24 17:29:36 +02:00
{inExplicitConstructorInvoc = true;}
{
// We may only lookahead one token here, because:
// * "this" or "super" can't appear in the primary expression in case of
// qualified super call (last branch), or else compile error, so if we
// see one of them, then the rest is necessarily the arguments
2019-05-25 03:21:42 +02:00
// But: "this" may appear if it's qualified!
// * No primary expression may start with "<", meaning we can use it to
// know we're looking forward to type arguments
( LOOKAHEAD("<") TypeArguments() ( "this" | "super" {jjtThis.setIsSuper();} )
| LOOKAHEAD("this") "this"
| LOOKAHEAD("super") "super" {jjtThis.setIsSuper();}
| PrimaryExpression() "." [ TypeArguments() ] "super" {jjtThis.setIsSuper();}
)
2019-05-24 19:47:29 +02:00
// reset this before parsing the arguments list
2019-05-24 17:29:36 +02:00
{inExplicitConstructorInvoc = false;}
2019-05-24 19:47:29 +02:00
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())+
}
2019-02-16 11:44:34 +01:00
void ArrayTypeDim():
{}
{
2019-02-16 11:44:34 +01:00
(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
{}
{
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.
*/
2019-05-24 16:33:48 +02:00
AmbiguousName()
[ TypeArguments() #ClassOrInterfaceType(2) ]
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.
*/
2019-05-24 16:33:48 +02:00
( LOOKAHEAD(2) "." ClassTypeSegment() )*
2019-04-03 14:48:48 +02:00
{ forceTypeContext(); }
}
2019-05-24 16:33:48 +02:00
private void ClassTypeSegment() #ClassOrInterfaceType:
{}
{
TypeAnnotationList()
<IDENTIFIER>
// We'll enclose the previous segment
{ setLastTokenImage(jjtThis); jjtree.extendLeft();}
[ TypeArguments() ]
}
2018-11-06 04:22:31 +01:00
void TypeArguments():
{}
{
LOOKAHEAD(2)
"<" {checkForBadGenericsUsage();} TypeArgument() ( "," TypeArgument() )* ">"
|
"<" {checkForBadDiamondUsage();} ">"
}
2019-03-31 06:59:49 +02:00
void TypeArgument() #void:
{}
{
TypeAnnotationList() (ReferenceType() | WildcardType())
}
2019-03-21 13:58:03 +01:00
void WildcardType():
{}
{
2019-03-21 13:58:03 +01:00
"?" [ ("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()
}
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.
*/
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());}
}
void ConditionalExpression() #ConditionalExpression(>1) :
{}
{
2019-05-26 16:47:22 +02:00
ConditionalOrExpression() [ "?" 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()
}
2019-03-29 18:50:43 +01:00
// 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:
{}
{
2019-03-28 07:53:08 +01:00
( "+" | "-" )
{
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()
}
2019-05-28 16:33:59 +02:00
void UnaryExpression() #void:
{}
{
2019-05-28 16:33:59 +02:00
(("+" {jjtThis.setImage("+");} | "-" {jjtThis.setImage("-");}) UnaryExpression()) #UnaryExpression
| PreIncrementExpression()
| PreDecrementExpression()
| UnaryExpressionNotPlusMinus()
}
void PreIncrementExpression() :
{}
{
"++" PrimaryExpression()
}
void PreDecrementExpression() :
{}
{
"--" PrimaryExpression()
}
2019-05-28 16:33:59 +02:00
void UnaryExpressionNotPlusMinus() #void:
{}
{
2019-05-28 16:33:59 +02:00
(( "~" {jjtThis.setImage("~");} | "!" {jjtThis.setImage("!");}) UnaryExpression()) #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
2019-04-28 20:03:15 +02:00
// Those lookaheads are quite expensive, they're run to disambiguate between
// ParenthesizedExpression and CastExpression.
2019-03-30 18:39:11 +01:00
| LOOKAHEAD("(" TypeAnnotationList() PrimitiveType() ")")
("(" AnnotatedType() ")" UnaryExpression()) #CastExpression
2019-04-28 20:03:15 +02:00
// here we avoid looking ahead for a whole unary expression, instead just testing the token after ")"
| LOOKAHEAD("(" TypeAnnotationList() IntersectionType(true) ")" UnaryExprNotPmStart() )
2019-05-26 16:47:22 +02:00
("(" TypeAnnotationList() IntersectionType(true) ")" UnaryExpressionNotPlusMinus()) #CastExpression
| PostfixExpression()
2019-03-15 15:29:16 +01:00
| SwitchExpression()
}
private void UnaryExprNotPmStart() #void:
{}
{
// Condensed FIRST set of UnaryExpressionNotPlusMinus
// Avoid looking ahead for a whole UnaryExpressionNotPlusMinus, but just for a token
"~" | "!" | "(" | "switch" | "new" | "this" | "super" | Literal()
| <IDENTIFIER>
| "void" | PrimitiveType()
}
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.
2019-05-25 02:32:23 +02:00
* Iteration stops after the first method reference, or we can't continue.
2019-02-17 14:25:07 +01:00
*
* The resulting subtree looks left-recursive, but the parsing is iterative.
*/
void PrimaryExpression() #void :
{}
{
2019-05-25 02:32:23 +02:00
// the lookahead here stops iteration after the first method reference,
// because nothing can be chained after a method reference.
PrimaryPrefix() ( LOOKAHEAD(SuffixLAhead(), {!(jjtree.peekNode() instanceof ASTMethodReference)}) PrimarySuffix() )* {forceExprContext();}
}
2019-02-18 16:59:23 +01:00
/*
Expressions that may be present at the start of a primary expression.
*/
void PrimaryPrefix() #void :
{Token t;}
{
Literal()
2019-02-18 16:59:23 +01:00
| "this" #ThisExpression
2019-05-25 01:53:13 +02:00
| "super" #SuperExpression(true)
("." MemberSelector() | MethodReference())
2019-05-24 16:33:48 +02:00
| UnqualifiedAllocationExpr()
| ("void" "." "class") #ClassLiteral
| (PrimitiveType() [ Dims() ] ) #ArrayType(>1)
(
MethodReference()
| "." "class" #ClassLiteral(1)
)
2019-05-26 16:47:22 +02:00
| LOOKAHEAD(LambdaLahead()) LambdaExpression()
2019-03-24 19:27:59 +01:00
| ("(" Expression() ")") #ParenthesizedExpression
2019-05-25 02:05:42 +02:00
// If it is an ambiguous name, then we may go on
// into the next step, which is less restricted
// than PrimarySuffix
2019-05-24 17:29:36 +02:00
| AmbiguousName() [ LOOKAHEAD(Step2Lahead()) PrimaryStep2() ]
}
2019-05-25 02:05:42 +02:00
// This describes the cases where the PrimaryPrefix may fall
2019-05-28 16:33:59 +02:00
// into PrimaryStep2, after seeing an AmbiguousName. Notice
// that type arguments is still possible, as well as annotations
// ("@") before an annotated array type, or qualified "this".
// If we are in an explicit constructor invocation, then super is disallowed.
2019-05-24 17:29:36 +02:00
private void Step2Lahead() #void:
{}
{
2019-05-25 03:21:42 +02:00
"::" | "(" | "@" | "["
// the type arguments must be followed by what may complete a class type + method ref
// otherwise we choke on eg `i < w >> 1`, because `< w >` matches type arguments
| TypeArguments() ("[" | "." | "@" | "::")
2019-05-24 17:29:36 +02:00
| LOOKAHEAD({!inExplicitConstructorInvoc}) "."
| LOOKAHEAD({inExplicitConstructorInvoc}) "." ("class" | <IDENTIFIER> | TypeArguments() <IDENTIFIER> | "new" | "this") // not super in this case
2019-05-24 17:29:36 +02:00
}
private void SuffixLAhead() #void:
{}
{
2019-05-25 02:15:35 +02:00
// this is simpler than the step 2 lookahead
2019-05-24 17:29:36 +02:00
"::" | "["
| LOOKAHEAD({!inExplicitConstructorInvoc}) "."
| LOOKAHEAD({inExplicitConstructorInvoc}) "." (<IDENTIFIER> | TypeArguments() <IDENTIFIER> | "new") // not super or this in this case
2019-05-24 16:33:48 +02:00
}
2019-05-24 17:29:36 +02:00
2019-05-24 19:47:42 +02:00
// Step right after the *first* ambiguous name if any.
// Then we have more options than a primary suffix,
// we can still expect to have some class type and a
// class literal, or some type arguments and a method reference
2019-05-24 16:33:48 +02:00
void PrimaryStep2() #void:
{}
{
2019-05-25 03:21:42 +02:00
// If we find type parameters, then we can only expect a method reference
// class literals or qualifiers to static member access/call may not be parameterised
{forceTypeContext();} TypeArguments() {injectTop();} ( "." ClassTypeSegment() )* [ Dims() #ArrayType(2) ] MethodReference()
2019-05-24 16:33:48 +02:00
| MethodReference()
| ArgumentList() #MethodCall(2)
| "." (
{forceTypeContext();} "class" #ClassLiteral(1)
2019-05-25 02:05:42 +02:00
// qualified this or super
| {forceTypeContext();} "this" #ThisExpression(1)
| {forceTypeContext();} "super" #SuperExpression(1)
// here we force the super to be followed by something,
// "super" alone is not a valid expression
("." MemberSelector() | MethodReference())
2019-05-24 16:33:48 +02:00
| MemberSelector()
)
2019-05-28 16:33:59 +02:00
// catches the case where the ambig name is the start of an array type
2019-05-24 16:33:48 +02:00
| LOOKAHEAD("@" | "[" "]") {forceTypeContext();} Dims() #ArrayType(2) (MethodReference() | "." "class" #ClassLiteral(1))
2019-05-28 16:33:59 +02:00
// and here, the array expr in an array access
2019-05-25 02:15:35 +02:00
| {forceExprContext();} "[" Expression() "]" #ArrayAccess(2)
}
/**
2019-05-28 16:33:59 +02:00
* Productions that may be present after a PrimaryPrefix. Basically
* allows for call chains. We loop on this production in PrimaryExpression.
2019-02-18 16:59:23 +01:00
*/
2019-02-17 10:28:12 +01:00
void PrimarySuffix() #void :
{}
{
2019-03-24 19:27:59 +01:00
MethodReference()
2019-05-25 02:15:35 +02:00
| {forceExprContext();} "[" Expression() "]" #ArrayAccess(2)
2019-05-24 16:33:48 +02:00
| "." MemberSelector()
}
2019-05-24 19:47:42 +02:00
/**
2019-05-25 02:32:23 +02:00
* Part of a primary suffix that immediately follows a dot. Also
* part of step 2.
2019-05-24 19:47:42 +02:00
*/
2019-03-24 19:27:59 +01:00
void MemberSelector() #void :
{}
{
/* JLS §6.5.1:
* A name is syntactically classified as an ExpressionName [...] as the
* qualifying expression in a qualified class instance creation expression (§15.9)*
*/
2019-05-25 02:15:35 +02:00
{forceExprContext();} QualifiedAllocationExpr()
2019-03-24 19:27:59 +01:00
// if there are type arguments, this is a method call
2019-05-25 02:15:35 +02:00
| (TypeArguments() <IDENTIFIER> {setLastTokenImage(jjtThis);} ArgumentList()) #MethodCall(3)
| LOOKAHEAD(2) (<IDENTIFIER> {setLastTokenImage(jjtThis);} ArgumentList()) #MethodCall(2)
| (<IDENTIFIER> {setLastTokenImage(jjtThis);}) #FieldAccess(1)
}
2019-03-24 19:27:59 +01:00
void MethodReference(): // LHS is injected
{checkForBadMethodReferenceUsage();}
{
2019-03-24 19:27:59 +01:00
"::" {jjtree.extendLeft();}
2019-05-24 16:33:48 +02:00
[TypeArguments()]
( "new" | <IDENTIFIER> ) {setLastTokenImage(jjtThis);}
2019-05-25 01:49:38 +02:00
{/* empty, to set the image before jjtClose */}
}
2019-05-24 19:47:42 +02:00
// This factorises the lookahead for a lambda expression
// It's necessary because in all contexts a lambda may appear in,
// the arguments could be interpreted as a variable reference,
// or the start of a parenthesized expression
private void LambdaLahead() #void :
{}
{
LOOKAHEAD({!inSwitchLabel})
(
<IDENTIFIER>
| "(" <IDENTIFIER> ( "," <IDENTIFIER> )* ")"
| LambdaParameterList()
)
"->"
}
// 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 call argument, cast operand, the RHS of assignments,
// and the tail of a ternary expression
// 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.
void LambdaExpression():
{ checkForBadLambdaUsage(); }
2018-07-19 22:00:34 +02:00
{
LambdaParameterList() "->" ( Expression() | Block() )
2018-07-19 22:00:34 +02:00
}
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);
}
}
2019-02-17 05:41:33 +01:00
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()
}
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
{
(
(
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-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(); }
}
2019-02-17 14:25:07 +01:00
/*
* 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)
}
/*
* Statement syntax follows.
*/
void Statement() :
{}
{
2019-05-25 06:53:25 +02:00
Block()
| EmptyStatement()
| SwitchStatement()
| IfStatement()
| WhileStatement()
| DoStatement()
| ForStatement()
| BreakStatement()
| ContinueStatement()
| ReturnStatement()
| ThrowStatement()
| SynchronizedStatement()
| TryStatement()
2019-05-25 06:53:25 +02:00
// testing the hard cases last optimises the code gen
// all the previous cases are trivial for the parser
// because they start with a different token
| LOOKAHEAD( { isNextTokenAnAssert() } ) AssertStatement()
| LOOKAHEAD(2) LabeledStatement()
| StatementExpression() ";"
}
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()
|
// we don't need to lookahead further here
// the ambiguity between start of local class and local variable decl
// is already handled in the lookahead guarding LocalVariableDeclaration above.
LocalClassDecl()
}
void LocalClassDecl() #void:
{int mods = 0;}
{
// this preserves the modifiers of the local class.
// it allows for modifiers that are forbidden for local classes,
// but anyway we are *not* checking modifiers for incompatibilities
// anywhere else in this grammar (and indeed the production Modifiers
// accepts any modifier explicitly for the purpose of forgiving modifier errors,
// and reporting them later if needed --see its documentation).
2019-05-30 15:48:55 +02:00
// In particular, it unfortunately allows local class declarations to start
// with a "default" modifier, which introduces an ambiguity with default
// switch labels. This is guarded by a custom lookahead around SwitchLabel
mods=Modifiers() ClassOrInterfaceDeclaration(mods)
}
/*
* 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())*
|
2019-05-30 15:48:55 +02:00
":" (LOOKAHEAD(2) SwitchLabel() ":")*
// the lookahead is to prevent choosing BlockStatement when the token is "default",
// which could happen as local class declarations accept the "default" modifier.
(LOOKAHEAD({shouldStartStatementInSwitch()}) 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:
{}
{
2019-05-30 15:48:55 +02:00
(LOOKAHEAD(2) SwitchLabel() ":")+
// the lookahead is to prevent choosing BlockStatement when the token is "default",
// which could happen as local class declarations accept the "default" modifier.
(LOOKAHEAD({shouldStartStatementInSwitch()}) 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
}