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

3079 lines
93 KiB
Plaintext
Raw Normal View History

/**
* Support "JEP 455: Primitive Types in Patterns, instanceof, and switch (Preview)" (Java 23)
* Changes in InstanceOfExpression
* Support "JEP 476: Module Import Declarations (Preview)" (Java 23)
* Changes in ImportDeclaration
* Support "JEP 477: Implicitly Declared Classes and Instance Main Methods (Third Preview)" (Java 23)
* Changes in CompilationUnit, added new node ImplicitClassDeclaration
* Andreas Dangel 07/2024
*====================================================================
* Support "JEP 447: Statements before super(...) (Preview)" (Java 22)
* Changes in ConstructorBlock
* Support "JEP 456: Unnamed Variables & Patterns" (Java 22)
* This is now a regular language feature. Otherwise no changes.
* Support "JEP 463: Implicitly Declared Classes and Instance Main Methods (Second Preview)" (Java 22)
* No changes.
* Support "JEP 459: String Templates (Second Preview)" (Java 22)
* Use ASTTemplate.setContent instead of setImage.
* Remove support for Record pattern in enhanced for statements. This was only a Java 20 Preview feature.
* Remove support for ParenthesizedPatterns. This was only a Java 20 Preview feature.
* Andreas Dangel 02/2024
*====================================================================
2023-12-13 10:51:47 +01:00
* Renamed various nodes:
* ClassOrInterfaceType -> ClassType
* ClassOrInterfaceDeclaration -> ClassDeclaration
* ClassOrInterfaceBody -> ClassBody
* AnyTypeDeclaration -> TypeDeclaration
* MethodOrConstructorDeclaration -> ExecutableDeclaration
* VariableDeclaratorId -> VariableId
* Andreas Dangel 12/2023
*====================================================================
* Support "JEP 443: Unnamed Patterns and Variables" for Java 21 Preview.
* New AST nodes: ASTUnnamedPattern
* Support "JEP 430: String Templates" for Java 21 Preview.
* New AST nodes: ASTTemplateExpression, ASTTemplate, ASTTemplateFragment
* Promote "JEP 441: Pattern Matching for switch" as permanent language feature for Java 21.
* Renamed SwitchGuard to Guard.
* Promote "JEP 440: Record Patterns" as permanent language feature for Java 21.
* Renamed ComponentPatternList to PatternList
* Andreas Dangel 08/2023
*====================================================================
* Support "JEP 433: Pattern Matching for switch (Fourth Preview)" for Java 20 Preview
* SwitchLabel simplified
* Support "JEP 432: Record Patterns (Second Preview)" for Java 20 Preview
* ForStatement allows record patterns
* Removed named record patterns (optional VariableDeclaratorId following the pattern)
* Remove support for Java 18 preview language features
* GuardedPattern is removed
* Andreas Dangel 02/2023
*====================================================================
* Support "JEP 427: Pattern Matching for switch (Third Preview)" for Java 19 Preview
* Note: GuardedPattern is deprecated and only valid for 17-preview and 18-preview
2022-07-10 14:29:03 +02:00
* New AST node: ASTSwitchGuard (production "Guard") - used within switch case labels for refining a pattern
* Support "JEP 405: Record Patterns (Preview)" for Java 19 Preview
2022-07-10 14:29:03 +02:00
* New AST node: ASTRecordPattern and ASTComponentPatternList (production "RecordStructurePattern")
* Remove support for Java 17 preview language features
* Andreas Dangel 07/2022
*====================================================================
* Improve module grammar.
* Type names in "provides" directives are disambiguated like any other type name.
* ASTName is made redundant and removed for good.
* Clément Fournier 03/2022
*====================================================================
* Support "JEP 420: Pattern Matching for switch (Second Preview)" for Java 18 Preview
* There were no grammar changes between 18-preview and 17-preview
* Remove support for Java 16 preview language features
* Andreas Dangel 03/2022
*====================================================================
* Promote "JEP 409: Sealed Classes" as permanent language feature with Java 17.
* Support "JEP 406: Pattern Matching for switch (Preview)" for Java 17 Preview.
* Remove support for Java 15 preview language features
* Andreas Dangel 07/2021
*====================================================================
2021-03-05 11:48:05 +01:00
* Fix #3117 - infinite loop when parsing invalid code nested in lambdas
* Andreas Dangel 03/2021
*====================================================================
* Fix #3145 - parse exception with local records
* Clément Fournier 03/2021
*====================================================================
* Remove support for Java 14 preview language features
* JEP 397: Sealed Classes (Second Preview) for Java16 Preview
* JEP 395: Records for Java16
* JEP 394: Pattern Matching for instanceof for Java16
* Andreas Dangel 02/2021
*====================================================================
* Remove support for Java 13 preview language features.
* Promote text blocks as a permanent language features with Java 15.
* Support Pattern Matching for instanceof with Java 15 Preview.
* Support Records with Java 15 Preview.
* Support Local Records with Java 15 Preview.
* Support Sealed Classes with Java 15 Preview.
* Andreas Dangel 08/2020
*====================================================================
* Add support for record types introduced as a preview language
* feature with Java 14. See JEP 359.
* Andreas Dangel 02/2020
2019-07-01 12:36:29 +02:00
*====================================================================
* Add support for pattern matching for instance of introduced
2020-02-28 10:51:38 +01:00
* as a preview language feature with Java 14. See JEP 305.
* Clément Fournier 02/2020
2019-06-18 17:44:40 +02:00
*====================================================================
* Switch Expressions are now a standard feature of Java 14.
* Andreas Dangel 02/2020
2019-02-16 16:47:42 +01:00
*====================================================================
* Add support for the yield statement introduced as a preview language
* feature with Java 13. See JEP 354.
* Add support for text block literals introduces as a preview language
* feature with Java 13. See JEP 355.
* Andreas Dangel 08/2019
*====================================================================
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
* ===================================================================
2019-01-08 23:30:51 +01:00
* 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 {
2020-01-11 05:22:29 +01:00
UNICODE_INPUT=true;
CACHE_TOKENS = true;
STATIC = false;
MULTI = true;
VISITOR = true;
NODE_PACKAGE="net.sourceforge.pmd.lang.java.ast";
// disable the calculation of expected tokens when a parse error occurs
// depending on the possible allowed next tokens, this
// could be expensive (see https://github.com/pmd/pmd/issues/3117)
//ERROR_REPORTING = false;
//DEBUG_PARSER = true;
//DEBUG_LOOKAHEAD = true;
//DEBUG_TOKEN_MANAGER = true;
}
2020-01-11 05:22:29 +01:00
PARSER_BEGIN(JavaParserImpl)
package net.sourceforge.pmd.lang.java.ast;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.Map;
2019-12-16 07:36:47 +01:00
import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken;
import net.sourceforge.pmd.lang.ast.Node;
New typeres framework Ceci est la combinaison de 338+ commits. Make set of classes to mirror types Implement capture conversion Document Doc Implement contains for targs Implement toString Fully implement subtyping Check for reifiability Implement unchecked, fix array subtyping Test rec typevar building Test primitive subtyping Test array subtyping Test wildcards subtyping Doc Rename primitiveType Reify conversions Test boxing Make constants for common types Test type param mutual recursion More defensive validation Implement numeric promotion Checkstyle Implement supertype set Implement lub Fix infinite recursion Fix lub bugs Use linkedhashset for stable ordering Add primitives to common types Move common types into type factory Try a lazy class resolver, needs a symbol table Improve lazy resolver Implement conditional expr typing remove poly impl Represent primitive wrappers differently Better compromise for primitive wrappers Extract wildcard interface Extract array type interface Refactor to extract interfaces Don't depend on initialization of jprimitiveType Finish pretty printer Remove dependency on reflection Fix class initialization trouble Move to type constants Use regular impl for OBJECT Encapsulate ops into TypeOps Add inference var to model Impl some ops Add some type inference algos Invocation context compatibility Add incorporation Generify bound set with ExprOps Add applicability tests Fix compil Add incorporation actions Implement incorporation Add inference steps Implement brute force walk strategy Remove some type params Wire in everything Implement methodtype Access methods from JClassType Represent enclosing types Work on overriding Implement expr ops Catch easy cases Diamond inference Fix pretty printer Fix concurrent mod Test Add reflect info to JModifier Add symbolic type declaration Most specific check Test with nested invocation Test lub Add constraints for lambdas and all subexpressions Resolve full call chain with lambdas Set partial results on nodes Test chain Doc Generalise expr mirrors Fix context Add invocation mirror Add support for method references make infer static Cleanup interface Fix constructor access Test method reference Cleanup method ref types Test constructor reference Test overload resolution, fix TODO Fix ctdecl of mref on non-ground target type Add graph walk strategy Document Use toposort Make enum constant implement ctor invoc mirror Work on context Test conditional expr type Handle switch exprs uniformly Fix bugs Add type inference performance test case Add overload resolution tests Cache result of overload selection, only recompute invocation Optimise common case in graph building Optimise propagation by merging variables Fix some tests, cleanup Preserve applicability phase Improve jsinglechildnode Add way to get a field's type Make more complex stress test Cache bound check results Type projection for inference Simplify lazy type inference of var ids Improve memory usage - reuse constant enum sets (by far the biggest leak, given the number of PropagateBounds created) - implement substitution without a visitor Optimise imports Cache hash of classes Cleanup Add overloads test Fix context fetching Fix lub bug Test switch expr Fix rebase Remove useless type Factorise poly check Remove base poly expr Fix array initializer Remove duplicated numeric literal typing Fix inferred iterable type Move method resolution phase to upper level Delete useless var Commit pr plan Remove useless method Fix enclosing type comb rule REVERT ME Remove partial enclosing type support Add package info Put task list in branch description Fix old rebases Fix rebase Simplify for left recursive ops Fix comments Fix rebase Revert "REVERT ME Remove partial enclosing type support" This reverts commit 8080ff1585b3a760fafc957282771baf716f3c7f. WIP base type mirrors on symbols Make JMethodType not a JTypeMirror Figure out getSymbol & type vars make type factory non-static Add a parameter to visitors Fix compilation Use symbol table in lazy type resolver Move package Fix most tests Move internal api around Specify some stuff Split reflect impl from API Make AST impl Equality routines Fix tests Move internal symtable doc Improve symtableResolver ergonomics Poly res tests Make AST type factory Update Make lambda expressions not a MethodlikeNode Build local var sym Update for switches Make Infer not static, fix logging Don't expose visitor nature of SymbolResolver Cleanup Improve type error handling Don't throw away CTdecls for an arg mismatch Fix more tests Local symbol tables Symbol table looks in interfaces Incompatible changes that should stay on this branch and not be squashed ResolveResult Explicitly typed lambdas Fix some static bugs Fix a lot of bugs Use FQCN symtable Move parsing contexts to upper level Cleanup DSL to test types test subst Dont create an exception for each failure Stack trace creation takes a significant amount of time Remove laziness for fetching method streams Streams obfuscate performance analysis by delaying the computation until the last moment. Fix some bugs with unresolved classes Also measure performance: full typeres is around same time as parsing. This is great. At this point 80% of all types are resolved (though some type inference results are probably incorrect). Mostly this comes from the fact that there are still AmbiguousNames in the tree. Fix problem with varargs Handle enclosing types Enclosing types Fix compil Add another stress test Refactor primitive subtyping Fix rebase Fix rebase: tests Figure out type factories WIP Move type ops into TypeOps Move AsSuper Figure out type factories WIP Make TypeSystem object wip WIP WIP Make typeops static Fix grounding routine Fix bug with return type Start fixing tests Cleanup primitive types Fix some tests Add todo Remove JDK test dependency Test cases lubbing String and StringBuilder produce different outputs on JDK [8, 11[ and 11+, because StringBuilder was made a Comparable<StringBuilder> in JDK 11 Implement most specific method selection Drop JVariableSig from symbol table Use asOuterSuper instead Fix local var type inference with foreach. Fix a lot of stuff based on jdk 12 run Make type system own symbol factories Fix intersection with bound Fix standalone ternary types Capture field access type Eg class Foo<T> { T[] field; } Foo<? extends T>.field : capture(T)[] Add tests Delete lexical substs Fix reflected owner type Add graph viz Fix bug with graph reduction Optimise ivar dependency reduction by a lot. The previous 60s stress test now takes 600ms. Btw at this point type res for the whole JDK 12 codebase takes 25 secs, down from 175 on 6.20.0 (7x speedup). Implement inherited field/class lookup Fix scoping inside switch statements Fix a few bugs Handle inherited methods Interfaces should inherit Object methods Move lub into TypeSystem Handle class types induced by intersections Fix lambda congruence Test lambda with intersection type Fix inference Fix same type check using equals Simplify intersection type induction Remove type sys extension Simplify sym factories Finish symbol factory streamlining Document Cache non-erased symbols separately Doc Revert, erased types are only raw Get rid of generic constants in TypeSystem Remove some dead code Fix exact method reference Improve unchecked conversion handling Fix dependency of delegated ivars Improve logging, fix a few bugs Test enclosing types Improve loggin Print file location Fix subtyping for wildcards Fix standalone method types Fix boxing conversion Fix promotion on unary exprs Implement special treatment of getClass() Add tests for anon classes Make symbol tables use lists for methods Fix method reference with void target type Move graphUtils Make unresolved types bottom (instead of top) It's more likely to be useful. Eg. Unresolved var = ...; knownMethod(var); Here, var must conform to the parameter, if it is unresolved, we assume that's the case. Otherwise we would fail resolution of knownMethod for this call site. The reverse situation is rarer. Fix conversions in loose phase Make JInferenceVar a class Hide TypePair Remove special string type Fix toString of anon classes Implement overload specificity for generic methdos Fix anon class ctors Fix Object methods not in scope in interfaces Fixing anon class ctors WIP Fix rebase Cleanup Print type var bounds Fix tests, improve pretty printing Hide ast sym factory Fix array method erasure Fix superclass, uncover bug with substitution Substitute type param bounds Make Array have Object methods Fix duplicated logging categories Make root symbolFactory thread safe Fix overload ambiguity with hiding Fix exact method when they shadow each other Make PMultimap type Make shadowGroup Make a few utilities to replace import tables Replace other tables Cleanup Compat with old impl Fix rebase Port to using sigs Make base class for shadow groups Fix method group Test shadowing of inherited members Fix bugs with tparams Specialize to StringMultimap Big optimizations Simplify a lot of things, remove caching of getAllMethods Factorize group implementations Add resolveFirst Fix bug with ctor invocation Fix type parsing for union types Generify multimap Implement nextShadowGroup Remove unused API of pmultimap Use interface where possible Fix tests Use singleton resolvers more frequently Remove commons collections dependency Tries don't make a significant difference in execution time. Mostly because tries used in symbol tables are very small. Remove some api of jtypemirror Fix shadow barriers Fix accessibility check for protected member Qualified ctor invocations have access to inner class name Make strict stream for profiling LOOK AT ME strict streams Strict streams are actually *much* more efficient for our use case Extract some stuff into CollectionUtil Make methods shadow each other doc Simplify OptionalBool Improve strict stream Eventually I'll remove it Doc newer symtable Make PMultimap type Make shadowGroup Make a few utilities to replace import tables Cleanup Checkout newer sym table from typeres branch Port Checkout tests Port tests, remove old impl Extract augment function Move classes back into internal package Abstract stuff away for pmd-core Optimise singular map case even more Fix nextShadowGroup WIP Make ShadowIterator to replace getNextGroup Use chain iterator Add tests Finish impl Add tests for supertype enumerator Add tests for method shadowing in imports Port to using types etc Fix tests Fix outdated tests Fix anon class ctors Fix more outdated tests Object methods should be in scope in interfaces Fix compil Make simple signature parser Make stubs Figure out loading logic Progress on type param parsing Do away with nested classes Class signatures It works! Parse tvar bounds lazily Fix a lot of stuff No errors on pmd-core JDK 13 under 80s Implement toString everywhere Try to make the whole thing thread safe Still a spurious NPE, access flags are weird. For j.l.invoke.DelegatingMethodHandle (declared as `final class Holder {}`) the access flags from the class file are 0x32, and the enclosing type is null, while when accessed through reflection, the access flags are correctly 0x10. The class is engineered through VM magic so idk what happens Remove shared caching of TypeSystem The sub caches are not useful anymore and creating them all the time is wasteful Add some tests Fix improper locking Reorganise typeSystem initialization Change the name Doc Opts Optimise away some expensive lookaheads in the parser Doc Fix modifiers Optimise big switches in parser Placing token decls that are frequently used together closer increases the chance that the compiler generate a TABLESWITCH instruction instead of a LOOKUPSWITCH. Table switches take constant lookup time, while lookupswitch is linear. Selection of table switch is now done for the biggest switches of the parser: the one in types, in modifiers, in statements, and at the start of expressions. Other lookup switches are unimportant because they have very few labels (typically 2). Optimise variable initializer lookahead make test rule noop PARSER Optimise common branches in expressions PARSER opt blocks & statements doc Don't accept void by default Split signature parsers Simplify type param parsing Simplify type params parsing Some optimisations Tests Simplify synchronization Factorize synchronization logic Move ConsList into pmd-core Prune more empty nodes Use single map for asm resolver Remove changes to parser Add option to suppress type inference log entry creation Use soft references to allow class stubs to be GCed Fix rebase
2020-02-11 04:43:54 +01:00
import net.sourceforge.pmd.lang.java.types.JPrimitiveType.PrimitiveTypeKind;
2018-11-06 04:22:31 +01:00
2020-01-11 05:22:29 +01:00
class JavaParserImpl {
private int jdkVersion = 0;
private boolean preview = false;
public void setJdkVersion(int jdkVersion) {
this.jdkVersion = jdkVersion;
}
public void setPreview(boolean preview) {
this.preview = preview;
}
private void throwParseException(String message) {
2023-03-19 22:49:45 +01:00
throw new ParseException(message).withLocation(token);
}
2020-08-22 20:48:21 +02:00
private boolean isRecordTypeSupported() {
return jdkVersion >= 16;
2020-08-22 20:48:21 +02:00
}
private boolean localTypesSupported() {
return isRecordTypeSupported();
}
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-16 10:47:12 +01:00
// 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 isAssertStart() {
if (jdkVersion <= 3) {
return false;
}
2019-09-27 06:21:08 +02:00
2020-02-07 23:43:26 +01:00
return getToken(1).getImage().equals("assert");
}
private boolean isRecordStart() {
2021-03-05 11:54:58 +01:00
return isRecordTypeSupported() && isKeyword("record") && isToken(2, IDENTIFIER);
}
private boolean isEnumStart() {
return jdkVersion >= 5 && isKeyword("enum");
}
/**
* Semantic lookahead to check if the next identifier is a
* specific restricted keyword.
*
* <p>Restricted keywords are:
* var, yield, record, sealed, permits, "non" + "-" + "sealed"
*
* <p>enum and assert is used like restricted keywords, as they were not keywords
* in the early java versions.
*/
private boolean isKeyword(String image) {
return isKeyword(1, image);
}
private boolean isKeyword(int index, String image) {
Token token = getToken(index);
return token.kind == IDENTIFIER && token.image.equals(image);
}
private boolean isToken(int index, int kind) {
return getToken(index).kind == kind;
}
/**
* Semantic lookahead which matches "non-sealed".
*
* <p>"non-sealed" cannot be a token, for several reasons:
* It is only a keyword with java15 preview+, it consists actually
* of several separate tokens, which are valid on their own.
*/
private boolean isNonSealedModifier() {
if (isKeyword(1, "non") && isToken(2, MINUS) && isKeyword(3, "sealed")) {
2020-08-22 20:48:21 +02:00
JavaccToken nonToken = getToken(1);
JavaccToken minusToken = getToken(2);
JavaccToken sealedToken = getToken(3);
return nonToken.getReportLocation().getEndColumn() == minusToken.getReportLocation().getStartColumn()
&& minusToken.getReportLocation().getEndColumn() == sealedToken.getReportLocation().getStartColumn();
}
return false;
}
private boolean classModifierForLocalTypesLookahead() {
Token next = getToken(1);
return next.kind == AT
|| next.kind == PUBLIC
|| next.kind == PROTECTED
|| next.kind == PRIVATE
|| next.kind == ABSTRACT
|| next.kind == STATIC
|| next.kind == FINAL
|| next.kind == STRICTFP;
}
private boolean localTypeDeclAfterModifiers() {
Token next = getToken(1);
return next.kind == CLASS
|| localTypesSupported() && (
next.kind == INTERFACE
|| next.kind == AT && isToken(2, INTERFACE)
|| next.kind == IDENTIFIER && next.getImage().equals("enum")
2021-03-05 11:54:58 +01:00
|| next.kind == IDENTIFIER && next.getImage().equals("record") && isToken(2, IDENTIFIER)
);
}
private boolean localTypeDeclGivenNextIsIdent() {
return localTypesSupported() && (isRecordStart() || isEnumStart());
}
2020-03-17 20:27:14 +01:00
/**
* True if we're in a switch block, one precondition for parsing a yield
* statement.
*/
2020-03-17 21:36:15 +01:00
private boolean inSwitchExprBlock = false;
2020-03-17 20:27:14 +01:00
private boolean isYieldStart() {
2020-04-04 18:54:49 +02:00
return inSwitchExprBlock
2020-03-17 20:27:14 +01:00
&& isKeyword("yield")
&& mayStartExprAfterYield(2);
}
private boolean mayStartExprAfterYield(final int offset) {
// based off of https://hg.openjdk.java.net/jdk/jdk/file/bc3da0226ffa/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java#l2580
// please don't sue me
2020-04-08 21:06:19 +02:00
JavaccToken token = getToken(offset);
2020-03-17 20:27:14 +01:00
if (token == null) return false; // eof
switch (token.kind) {
case PLUS: case MINUS: case STRING_LITERAL: case CHARACTER_LITERAL:
case INTEGER_LITERAL: case FLOATING_POINT_LITERAL: case HEX_FLOATING_POINT_LITERAL:
case NULL: case IDENTIFIER: case TRUE: case FALSE:
case NEW: case SWITCH: case THIS: case SUPER:
return true;
case INCR: case DECR:
return getToken(offset + 1).kind != SEMICOLON; // eg yield++;
case LPAREN:
int lookahead = offset + 1;
int balance = 1;
2020-04-08 21:06:19 +02:00
JavaccToken t;
2020-03-17 20:27:14 +01:00
while ((t = getToken(lookahead)) != null && balance > 0) {
switch (t.kind) {
case LPAREN: balance++; break;
case RPAREN: balance--; break;
case COMMA: if (balance == 1) return false; // a method call, eg yield(1, 2);
}
lookahead++;
}
// lambda: yield () -> {};
// method call: yield ();
2020-03-17 21:36:15 +01:00
return t != null
&& (lookahead != offset + 2 // ie ()
|| t.kind == LAMBDA);
2020-03-17 20:27:14 +01:00
default:
return false;
}
}
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);
}
2020-05-02 20:54:41 +02:00
private void setLastTokenImage(AbstractJavaNode node) {
2019-02-17 11:36:18 +01:00
node.setImage(getToken(0).getImage());
}
private void fixLastToken() {
AbstractJavaNode top = (AbstractJavaNode) jjtree.peekNode();
top.setLastToken(getToken(0));
}
2019-03-21 20:47:23 +01:00
private void forceExprContext() {
2020-01-28 14:01:40 +01:00
AbstractJavaNode top = jjtree.peekNode();
2019-03-21 20:47:23 +01:00
if (top instanceof ASTAmbiguousName) {
// see doc on the method
2020-01-28 14:01:40 +01:00
AbstractJavaNode replacement = (AbstractJavaNode) ((ASTAmbiguousName) top).forceExprContext();
2019-03-21 20:47:23 +01:00
jjtree.popNode();
jjtree.pushNode(replacement);
}
}
private void pushEmptyModifierList() {
ASTModifierList emptyMods = new ASTModifierList(JJTMODIFIERLIST);
emptyMods.setDeclaredModifiers(Collections.emptySet());
JavaccToken tok = JavaccToken.implicitBefore(getToken(1));
2020-05-02 20:54:41 +02:00
emptyMods.setFirstToken(tok);
emptyMods.setLastToken(tok);
jjtree.pushNode(emptyMods);
}
2021-02-18 12:58:13 +01:00
private void insertEmptyModifierListWithAnnotations(AbstractJavaNode node, AbstractJavaNode nodeWithAnnotations) {
ASTModifierList emptyMods = new ASTModifierList(JJTMODIFIERLIST);
emptyMods.setDeclaredModifiers(Collections.emptySet());
JavaccToken tok = JavaccToken.implicitBefore(node.getFirstToken());
emptyMods.setFirstToken(tok);
emptyMods.setLastToken(tok);
List<ASTAnnotation> annotations = new ArrayList<ASTAnnotation>();
while (nodeWithAnnotations.getNumChildren() > 0 && nodeWithAnnotations.getChild(0) instanceof ASTAnnotation) {
ASTAnnotation annotation = (ASTAnnotation) nodeWithAnnotations.getChild(0);
nodeWithAnnotations.removeChildAtIndex(0);
annotations.add(annotation);
}
for (int i = 0; i < annotations.size(); i++) {
emptyMods.addChild(annotations.get(i), i);
}
if (!annotations.isEmpty()) {
emptyMods.setFirstToken(annotations.get(0).getFirstToken());
emptyMods.setLastToken(annotations.get(annotations.size() - 1).getLastToken());
}
node.insertChild(emptyMods, 0);
}
2019-04-03 14:48:48 +02:00
private void forceTypeContext() {
2020-01-28 14:01:40 +01:00
AbstractJavaNode top = jjtree.peekNode();
2019-04-03 14:48:48 +02:00
2019-05-28 19:16:04 +02:00
if (top instanceof ASTAmbiguousName) {
// see doc on the method
2020-01-28 14:01:40 +01:00
AbstractJavaNode replacement = ((ASTAmbiguousName) top).forceTypeContext();
2019-05-28 19:16:04 +02:00
jjtree.popNode();
jjtree.pushNode(replacement);
}
2019-04-03 14:48:48 +02:00
}
2019-05-28 19:16:04 +02:00
2019-05-29 13:12:43 +02:00
// make the top node the last child of the second node on the stack
// If the stack ends with ..[A][B], then it becomes ..[A[B]]
2019-05-24 16:33:48 +02:00
private void injectTop() {
AbstractJavaNode top = (AbstractJavaNode) jjtree.popNode();
AbstractJavaNode prev = (AbstractJavaNode) jjtree.peekNode();
2020-05-02 20:54:41 +02:00
prev.addChild(top, prev.getNumChildren());
prev.setLastToken(top.getLastToken());
2019-05-24 16:33:48 +02:00
}
/**
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;
}
2020-01-11 05:22:29 +01:00
PARSER_END(JavaParserImpl)
TOKEN_MGR_DECLS :
{
2022-03-07 22:00:14 +01:00
protected List<JavaComment> comments = new ArrayList<JavaComment>();
private Deque<Boolean> savedTemplateKind = new ArrayDeque<Boolean>();
private Deque<Integer> braceDepthInTemplate = new ArrayDeque<Integer>();
private int braceDepthCurrentTemplate;
private boolean templateKind;
private static final java.util.regex.Pattern TEXT_BLOCK_TEMPLATE_END_PATTERN =
java.util.regex.Pattern.compile("^}[^\"]*\"\"\"");
private static final java.util.regex.Pattern STRING_TEMPLATE_MID_OR_END_PATTERN =
java.util.regex.Pattern.compile("^}(?:[^\"\\\\\n\r]|\\\\(?:[ntbrfs\\\\'\"]|[0-7][0-7]?|[0-3][0-7][0-7]))*(\\{|\")");
private void pushBrace() {
braceDepthCurrentTemplate++;
}
private void pushTemplate(boolean isTextBlockTemplate) {
braceDepthInTemplate.push(braceDepthCurrentTemplate);
savedTemplateKind.push(templateKind);
templateKind = isTextBlockTemplate;
braceDepthCurrentTemplate = 1;
}
private boolean isInTemplate() {
return braceDepthCurrentTemplate > 0;
}
private void popBrace() {
if (!isInTemplate())
return;
if (--braceDepthCurrentTemplate == 0) {
// this brace ends the template
popTemplate();
}
}
private void popTemplate() {
boolean isInTextBlockTemplate = templateKind;
if (!braceDepthInTemplate.isEmpty()) {
braceDepthCurrentTemplate = braceDepthInTemplate.pop();
templateKind = savedTemplateKind.pop();
if (isInTextBlockTemplate) {
SwitchTo(JavaTokenKinds.IN_TEXT_BLOCK_LITERAL);
} else {
SwitchTo(JavaTokenKinds.IN_STRING_TEMPLATE);
}
} else {
SwitchTo(JavaTokenKinds.DEFAULT);
}
}
private net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken rereadTokenAs(int kind, int length) {
input_stream.backup(lengthOfMatch);
try {
for (int i = 0; i < length; i++) {
input_stream.readChar();
}
} catch (java.io.EOFException eofException) {
throw new IllegalStateException(eofException);
}
jjmatchedKind = kind;
return jjFillToken();
}
private net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken handleBlock() {
net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken matchedToken = rereadTokenAs(JavaTokenKinds.RBRACE, 1);
if (!"}".equals(input_stream.getTokenImage())) {
throw new IllegalStateException("Expected '}'");
}
return matchedToken;
}
}
/* WHITE SPACE */
SPECIAL_TOKEN :
{
// those are private, just for code organisation
< #HORIZONTAL_WHITESPACE: [" ", "\t", "\f"] >
| < #LINE_TERMINATOR: "\n" | "\r" | "\r\n" >
// this one is pushed, notice the (..)+ construct, to avoid
// creating one token per character
| < WHITESPACE: ([" ", "\t", "\f", "\n", "\r"])+ >
}
/* COMMENTS */
SPECIAL_TOKEN :
{
< SINGLE_LINE_COMMENT: "//"(~["\n","\r"])* ("\n"|"\r"|"\r\n")? >
{
int startOfNOPMD = matchedToken.getImage().indexOf(suppressMarker);
if (startOfNOPMD != -1) {
suppressMap.put(matchedToken.getReportLocation().getStartLine(), matchedToken.getImage().substring(startOfNOPMD + suppressMarker.length()));
}
2022-03-07 22:00:14 +01:00
comments.add(new JavaComment(matchedToken));
}
}
MORE :
{
<"/**" ~["/"]> { input_stream.backup(1); } : IN_FORMAL_COMMENT
|
"/*" : IN_MULTI_LINE_COMMENT
}
<IN_FORMAL_COMMENT>
SPECIAL_TOKEN :
{
<FORMAL_COMMENT: "*/" > { comments.add(new JavadocComment(matchedToken)); } : DEFAULT
}
<IN_MULTI_LINE_COMMENT>
SPECIAL_TOKEN :
{
2022-03-07 22:00:14 +01:00
<MULTI_LINE_COMMENT: "*/" > { comments.add(new JavaComment(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_NUMERAL> (["l","L"])?
| <HEX_NUMERAL> (["l","L"])?
| <BINARY_NUMERAL> (["l","L"])?
| <OCTAL_NUMERAL> (["l","L"])?
>
| < #DECIMAL_NUMERAL: ["1"-"9"] (("_")* ["0"-"9"])* >
| < #HEX_NUMERAL: "0" ["x","X"] <HEX_DIGIT_SEQ> >
| < #BINARY_NUMERAL: "0" ["b","B"] ["0","1"] (("_")* ["0","1"])* >
| < #OCTAL_NUMERAL: "0" (("_")* ["0"-"7"])* >
|
< FLOATING_POINT_LITERAL:
<DECIMAL_FLOATING_POINT_LITERAL>
| <HEX_FLOATING_POINT_LITERAL>
>
| < #DECIMAL_FLOATING_POINT_LITERAL:
<DIGIT_SEQ> "." (<DIGIT_SEQ>)? (<EXPONENT>)? (["f","F", "d","D"])?
| "." <DIGIT_SEQ> (<EXPONENT>)? (["f","F", "d","D"])?
| <DIGIT_SEQ> <EXPONENT> (["f","F", "d","D"])?
| <DIGIT_SEQ> (<EXPONENT>)? ["f","F", "d","D"]
>
| < #HEX_FLOATING_POINT_LITERAL:
"0" ["x","X"] <HEX_DIGIT_SEQ> (".")? <HEX_EXPONENT> (["f","F", "d","D"])?
| "0" ["x","X"] (<HEX_DIGIT_SEQ>)? "." <HEX_DIGIT_SEQ> <HEX_EXPONENT> (["f","F", "d","D"])?
>
| < #DIGIT_SEQ: ["0"-"9"] (("_")* ["0"-"9"])* >
| < #HEX_DIGIT_SEQ: ["0"-"9","a"-"f","A"-"F"] (("_")* ["0"-"9","a"-"f","A"-"F"])* >
| < #EXPONENT: ["e","E"] <EXPONENT_TAIL> >
| < #HEX_EXPONENT: ["p","P"] <EXPONENT_TAIL> >
| < #EXPONENT_TAIL: (["+","-"])? <DIGIT_SEQ> >
| < CHARACTER_LITERAL: "'" ( ~["'", "\\","\n","\r"] | <STRING_ESCAPE> ) "'" >
| < STRING_LITERAL: "\"" (<STRING_CHARACTER>)* "\"" >
| < #STRING_CHARACTER: ~["\"","\\","\n","\r"] | <STRING_ESCAPE> >
| < #STRING_ESCAPE:
"\\"
2020-03-02 21:05:21 +01:00
( ["n","t","b","r","f","s","\\","'","\""]
// octal escapes
| ["0"-"7"] ( ["0"-"7"] )?
| ["0"-"3"] ["0"-"7"] ["0"-"7"]
)
>
| < #TEXT_BLOCK_CHARACTER: ~["\\"] | <STRING_ESCAPE> | ("\\")? <LINE_TERMINATOR> >
| < #STRING_FRAGMENT: (<STRING_CHARACTER>)* >
| < STRING_TEMPLATE_BEGIN: "\"" <STRING_FRAGMENT> "\\{" > { pushTemplate(false); }
}
2023-01-26 18:59:55 -03:00
/* TEXT BLOCKS */
// note: Text Blocks need an own lexical state, so that we can reliably determine
// the end of the text block (""") which is 3 characters long.
2023-01-26 18:59:55 -03:00
MORE :
{
< "\"\"\"" (<HORIZONTAL_WHITESPACE>)* <LINE_TERMINATOR> > : IN_TEXT_BLOCK_LITERAL
}
<IN_TEXT_BLOCK_LITERAL>
TOKEN : {
2023-01-26 18:59:55 -03:00
<TEXT_BLOCK_LITERAL: "\"\"\"" > : DEFAULT
| <TEXT_BLOCK_TEMPLATE_MID: "\\{"> { pushTemplate(true); }: DEFAULT
2023-01-26 18:59:55 -03:00
}
<IN_TEXT_BLOCK_LITERAL>
MORE :
{
< <TEXT_BLOCK_CHARACTER> >
}
<IN_STRING_TEMPLATE>
TOKEN:
{
< STRING_TEMPLATE_END: <STRING_FRAGMENT> "\"" > : DEFAULT
| < STRING_TEMPLATE_MID: <STRING_FRAGMENT> "\\{" > { pushTemplate(false); } : DEFAULT
}
/* IDENTIFIERS */
TOKEN :
{
2020-01-25 09:52:36 +01:00
< IDENTIFIER : <LETTER> ( <PART_LETTER> )* >
// all chars for which Character.isJavaIdentifierStart is true
| < #LETTER : ["$","A"-"Z","_","a"-"z","\u00a2"-"\u00a5","\u00aa","\u00b5","\u00ba",
"\u00c0"-"\u00d6","\u00d8"-"\u00f6","\u00f8"-"\u021f","\u0222"-"\u0233","\u0250"-"\u02ad",
"\u02b0"-"\u02b8","\u02bb"-"\u02c1","\u02d0"-"\u02d1","\u02e0"-"\u02e4","\u02ee","\u037a",
"\u0386","\u0388"-"\u038a","\u038c","\u038e"-"\u03a1","\u03a3"-"\u03ce","\u03d0"-"\u03d7",
"\u03da"-"\u03f3","\u0400"-"\u0481","\u048c"-"\u04c4","\u04c7"-"\u04c8","\u04cb"-"\u04cc",
"\u04d0"-"\u04f5","\u04f8"-"\u04f9","\u0531"-"\u0556","\u0559","\u0561"-"\u0587",
"\u05d0"-"\u05ea","\u05f0"-"\u05f2","\u0621"-"\u063a","\u0640"-"\u064a","\u0671"-"\u06d3",
"\u06d5","\u06e5"-"\u06e6","\u06fa"-"\u06fc","\u0710","\u0712"-"\u072c","\u0780"-"\u07a5",
"\u0905"-"\u0939","\u093d","\u0950","\u0958"-"\u0961","\u0985"-"\u098c","\u098f"-"\u0990",
"\u0993"-"\u09a8","\u09aa"-"\u09b0","\u09b2","\u09b6"-"\u09b9","\u09dc"-"\u09dd",
"\u09df"-"\u09e1","\u09f0"-"\u09f3","\u0a05"-"\u0a0a","\u0a0f"-"\u0a10","\u0a13"-"\u0a28",
"\u0a2a"-"\u0a30","\u0a32"-"\u0a33","\u0a35"-"\u0a36","\u0a38"-"\u0a39","\u0a59"-"\u0a5c",
"\u0a5e","\u0a72"-"\u0a74","\u0a85"-"\u0a8b","\u0a8d","\u0a8f"-"\u0a91","\u0a93"-"\u0aa8",
"\u0aaa"-"\u0ab0","\u0ab2"-"\u0ab3","\u0ab5"-"\u0ab9","\u0abd","\u0ad0","\u0ae0",
"\u0b05"-"\u0b0c","\u0b0f"-"\u0b10","\u0b13"-"\u0b28","\u0b2a"-"\u0b30","\u0b32"-"\u0b33",
"\u0b36"-"\u0b39","\u0b3d","\u0b5c"-"\u0b5d","\u0b5f"-"\u0b61","\u0b85"-"\u0b8a",
"\u0b8e"-"\u0b90","\u0b92"-"\u0b95","\u0b99"-"\u0b9a","\u0b9c","\u0b9e"-"\u0b9f",
"\u0ba3"-"\u0ba4","\u0ba8"-"\u0baa","\u0bae"-"\u0bb5","\u0bb7"-"\u0bb9","\u0c05"-"\u0c0c",
"\u0c0e"-"\u0c10","\u0c12"-"\u0c28","\u0c2a"-"\u0c33","\u0c35"-"\u0c39","\u0c60"-"\u0c61",
"\u0c85"-"\u0c8c","\u0c8e"-"\u0c90","\u0c92"-"\u0ca8","\u0caa"-"\u0cb3","\u0cb5"-"\u0cb9",
"\u0cde","\u0ce0"-"\u0ce1","\u0d05"-"\u0d0c","\u0d0e"-"\u0d10","\u0d12"-"\u0d28",
"\u0d2a"-"\u0d39","\u0d60"-"\u0d61","\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"-"\u0edd","\u0f00",
"\u0f40"-"\u0f47","\u0f49"-"\u0f6a","\u0f88"-"\u0f8b","\u1000"-"\u1021","\u1023"-"\u1027",
"\u1029"-"\u102a","\u1050"-"\u1055","\u10a0"-"\u10c5","\u10d0"-"\u10f6","\u1100"-"\u1159",
"\u115f"-"\u11a2","\u11a8"-"\u11f9","\u1200"-"\u1206","\u1208"-"\u1246","\u1248",
"\u124a"-"\u124d","\u1250"-"\u1256","\u1258","\u125a"-"\u125d","\u1260"-"\u1286","\u1288",
"\u128a"-"\u128d","\u1290"-"\u12ae","\u12b0","\u12b2"-"\u12b5","\u12b8"-"\u12be","\u12c0",
"\u12c2"-"\u12c5","\u12c8"-"\u12ce","\u12d0"-"\u12d6","\u12d8"-"\u12ee","\u12f0"-"\u130e",
"\u1310","\u1312"-"\u1315","\u1318"-"\u131e","\u1320"-"\u1346","\u1348"-"\u135a",
"\u13a0"-"\u13f4","\u1401"-"\u166c","\u166f"-"\u1676","\u1681"-"\u169a","\u16a0"-"\u16ea",
"\u1780"-"\u17b3","\u17db","\u1820"-"\u1877","\u1880"-"\u18a8","\u1e00"-"\u1e9b",
2022-05-01 18:16:39 +02:00
"\u1ea0"-"\u1ef9","\u1d00"-"\u1eef","\u1f00"-"\u1f15","\u1f18"-"\u1f1d","\u1f20"-"\u1f45","\u1f48"-"\u1f4d",
2020-01-25 09:52:36 +01:00
"\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",
"\u207f","\u20a0"-"\u20af","\u2102","\u2107","\u210a"-"\u2113","\u2115","\u2119"-"\u211d",
"\u2124","\u2126","\u2128","\u212a"-"\u212d","\u212f"-"\u2131","\u2133"-"\u2139",
"\u2160"-"\u2183","\u3005"-"\u3007","\u3021"-"\u3029","\u3031"-"\u3035","\u3038"-"\u303a",
"\u3041"-"\u3094","\u309d"-"\u309e","\u30a1"-"\u30fe","\u3105"-"\u312c","\u3131"-"\u318e",
"\u31a0"-"\u31b7","\u3400"-"\u4db5","\u4e00"-"\u9fa5","\ua000"-"\ua48c","\ua490"-"\uabff","\uac00"-"\ud7a3",
2020-01-25 09:52:36 +01:00
"\uf900"-"\ufa2d","\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"-"\ufdfb",
"\ufe33"-"\ufe34","\ufe4d"-"\ufe4f","\ufe69","\ufe70"-"\ufe72","\ufe74","\ufe76"-"\ufefc",
"\uff04","\uff21"-"\uff3a","\uff3f","\uff41"-"\uff5a","\uff65"-"\uffbe","\uffc2"-"\uffc7",
"\uffca"-"\uffcf","\uffd2"-"\uffd7","\uffda"-"\uffdc","\uffe0"-"\uffe1","\uffe5"-"\uffe6"]>
// all chars for which Character.isJavaIdentifierPart is true
| < #PART_LETTER: ["\u0000"-"\b","\u000e"-"\u001b","$","0"-"9","A"-"Z","_","a"-"z",
"\u007f"-"\u009f","\u00a2"-"\u00a5","\u00aa","\u00b5","\u00ba","\u00c0"-"\u00d6",
"\u00d8"-"\u00f6","\u00f8"-"\u021f","\u0222"-"\u0233","\u0250"-"\u02ad","\u02b0"-"\u02b8",
"\u02bb"-"\u02c1","\u02d0"-"\u02d1","\u02e0"-"\u02e4","\u02ee","\u0300"-"\u034e",
"\u0360"-"\u0362","\u037a","\u0386","\u0388"-"\u038a","\u038c","\u038e"-"\u03a1",
"\u03a3"-"\u03ce","\u03d0"-"\u03d7","\u03da"-"\u03f3","\u0400"-"\u0481","\u0483"-"\u0486",
"\u048c"-"\u04c4","\u04c7"-"\u04c8","\u04cb"-"\u04cc","\u04d0"-"\u04f5","\u04f8"-"\u04f9",
"\u0531"-"\u0556","\u0559","\u0561"-"\u0587","\u0591"-"\u05a1","\u05a3"-"\u05b9",
"\u05bb"-"\u05bd","\u05bf","\u05c1"-"\u05c2","\u05c4","\u05d0"-"\u05ea","\u05f0"-"\u05f2",
"\u0621"-"\u063a","\u0640"-"\u0655","\u0660"-"\u0669","\u0670"-"\u06d3","\u06d5"-"\u06dc",
"\u06df"-"\u06e8","\u06ea"-"\u06ed","\u06f0"-"\u06fc","\u070f"-"\u072c","\u0730"-"\u074a",
"\u0780"-"\u07b0","\u0901"-"\u0903","\u0905"-"\u0939","\u093c"-"\u094d","\u0950"-"\u0954",
"\u0958"-"\u0963","\u0966"-"\u096f","\u0981"-"\u0983","\u0985"-"\u098c","\u098f"-"\u0990",
"\u0993"-"\u09a8","\u09aa"-"\u09b0","\u09b2","\u09b6"-"\u09b9","\u09bc","\u09be"-"\u09c4",
"\u09c7"-"\u09c8","\u09cb"-"\u09cd","\u09d7","\u09dc"-"\u09dd","\u09df"-"\u09e3",
"\u09e6"-"\u09f3","\u0a02","\u0a05"-"\u0a0a","\u0a0f"-"\u0a10","\u0a13"-"\u0a28",
"\u0a2a"-"\u0a30","\u0a32"-"\u0a33","\u0a35"-"\u0a36","\u0a38"-"\u0a39","\u0a3c",
"\u0a3e"-"\u0a42","\u0a47"-"\u0a48","\u0a4b"-"\u0a4d","\u0a59"-"\u0a5c","\u0a5e",
"\u0a66"-"\u0a74","\u0a81"-"\u0a83","\u0a85"-"\u0a8b","\u0a8d","\u0a8f"-"\u0a91",
"\u0a93"-"\u0aa8","\u0aaa"-"\u0ab0","\u0ab2"-"\u0ab3","\u0ab5"-"\u0ab9","\u0abc"-"\u0ac5",
"\u0ac7"-"\u0ac9","\u0acb"-"\u0acd","\u0ad0","\u0ae0","\u0ae6"-"\u0aef","\u0b01"-"\u0b03",
"\u0b05"-"\u0b0c","\u0b0f"-"\u0b10","\u0b13"-"\u0b28","\u0b2a"-"\u0b30","\u0b32"-"\u0b33",
"\u0b36"-"\u0b39","\u0b3c"-"\u0b43","\u0b47"-"\u0b48","\u0b4b"-"\u0b4d","\u0b56"-"\u0b57",
"\u0b5c"-"\u0b5d","\u0b5f"-"\u0b61","\u0b66"-"\u0b6f","\u0b82"-"\u0b83","\u0b85"-"\u0b8a",
"\u0b8e"-"\u0b90","\u0b92"-"\u0b95","\u0b99"-"\u0b9a","\u0b9c","\u0b9e"-"\u0b9f",
"\u0ba3"-"\u0ba4","\u0ba8"-"\u0baa","\u0bae"-"\u0bb5","\u0bb7"-"\u0bb9","\u0bbe"-"\u0bc2",
"\u0bc6"-"\u0bc8","\u0bca"-"\u0bcd","\u0bd7","\u0be7"-"\u0bef","\u0c01"-"\u0c03",
"\u0c05"-"\u0c0c","\u0c0e"-"\u0c10","\u0c12"-"\u0c28","\u0c2a"-"\u0c33","\u0c35"-"\u0c39",
"\u0c3e"-"\u0c44","\u0c46"-"\u0c48","\u0c4a"-"\u0c4d","\u0c55"-"\u0c56","\u0c60"-"\u0c61",
"\u0c66"-"\u0c6f","\u0c82"-"\u0c83","\u0c85"-"\u0c8c","\u0c8e"-"\u0c90","\u0c92"-"\u0ca8",
"\u0caa"-"\u0cb3","\u0cb5"-"\u0cb9","\u0cbe"-"\u0cc4","\u0cc6"-"\u0cc8","\u0cca"-"\u0ccd",
"\u0cd5"-"\u0cd6","\u0cde","\u0ce0"-"\u0ce1","\u0ce6"-"\u0cef","\u0d02"-"\u0d03",
"\u0d05"-"\u0d0c","\u0d0e"-"\u0d10","\u0d12"-"\u0d28","\u0d2a"-"\u0d39","\u0d3e"-"\u0d43",
"\u0d46"-"\u0d48","\u0d4a"-"\u0d4d","\u0d57","\u0d60"-"\u0d61","\u0d66"-"\u0d6f",
"\u0d82"-"\u0d83","\u0d85"-"\u0d96","\u0d9a"-"\u0db1","\u0db3"-"\u0dbb","\u0dbd",
"\u0dc0"-"\u0dc6","\u0dca","\u0dcf"-"\u0dd4","\u0dd6","\u0dd8"-"\u0ddf","\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"-"\u0edd","\u0f00","\u0f18"-"\u0f19",
"\u0f20"-"\u0f29","\u0f35","\u0f37","\u0f39","\u0f3e"-"\u0f47","\u0f49"-"\u0f6a",
"\u0f71"-"\u0f84","\u0f86"-"\u0f8b","\u0f90"-"\u0f97","\u0f99"-"\u0fbc","\u0fc6",
"\u1000"-"\u1021","\u1023"-"\u1027","\u1029"-"\u102a","\u102c"-"\u1032","\u1036"-"\u1039",
"\u1040"-"\u1049","\u1050"-"\u1059","\u10a0"-"\u10c5","\u10d0"-"\u10f6","\u1100"-"\u1159",
"\u115f"-"\u11a2","\u11a8"-"\u11f9","\u1200"-"\u1206","\u1208"-"\u1246","\u1248",
"\u124a"-"\u124d","\u1250"-"\u1256","\u1258","\u125a"-"\u125d","\u1260"-"\u1286",
"\u1288","\u128a"-"\u128d","\u1290"-"\u12ae","\u12b0","\u12b2"-"\u12b5","\u12b8"-"\u12be",
"\u12c0","\u12c2"-"\u12c5","\u12c8"-"\u12ce","\u12d0"-"\u12d6","\u12d8"-"\u12ee",
"\u12f0"-"\u130e","\u1310","\u1312"-"\u1315","\u1318"-"\u131e","\u1320"-"\u1346",
"\u1348"-"\u135a","\u1369"-"\u1371","\u13a0"-"\u13f4","\u1401"-"\u166c","\u166f"-"\u1676",
"\u1681"-"\u169a","\u16a0"-"\u16ea","\u1780"-"\u17d3","\u17db","\u17e0"-"\u17e9",
"\u180b"-"\u180e","\u1810"-"\u1819","\u1820"-"\u1877","\u1880"-"\u18a9","\u1d00"-"\u1d7f","\u1e00"-"\u1e9b",
2020-01-25 09:52:36 +01:00
"\u1ea0"-"\u1ef9","\u1f00"-"\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","\u200c"-"\u200f",
"\u202a"-"\u202e","\u203f"-"\u2040","\u206a"-"\u206f","\u207f","\u20a0"-"\u20af",
"\u20d0"-"\u20dc","\u20e1","\u2102","\u2107","\u210a"-"\u2113","\u2115","\u2119"-"\u211d",
"\u2124","\u2126","\u2128","\u212a"-"\u212d","\u212f"-"\u2131","\u2133"-"\u2139",
"\u2160"-"\u2183","\u3005"-"\u3007","\u3021"-"\u302f","\u3031"-"\u3035","\u3038"-"\u303a",
"\u3041"-"\u3094","\u3099"-"\u309a","\u309d"-"\u309e","\u30a1"-"\u30fe","\u3105"-"\u312c",
"\u3131"-"\u318e","\u31a0"-"\u31b7","\u3400"-"\u4db5","\u4e00"-"\u9fa5","\ua000"-"\ua48c",
"\ua490"-"\uabff",
2020-01-25 09:52:36 +01:00
"\uac00"-"\ud7a3","\uf900"-"\ufa2d","\ufb00"-"\ufb06","\ufb13"-"\ufb17","\ufb1d"-"\ufb28",
"\ufb2a"-"\ufb36","\ufb38"-"\ufb3c","\ufb3e","\ufb40"-"\ufb41","\ufb43"-"\ufb44",
"\ufb46"-"\ufbb1","\ufbd3"-"\ufd3d","\ufd50"-"\ufd8f","\ufd92"-"\ufdc7","\ufdf0"-"\ufdfb",
"\ufe20"-"\ufe23","\ufe33"-"\ufe34","\ufe4d"-"\ufe4f","\ufe69","\ufe70"-"\ufe72","\ufe74",
"\ufe76"-"\ufefc","\ufeff","\uff04","\uff10"-"\uff19","\uff21"-"\uff3a","\uff3f",
"\uff41"-"\uff5a","\uff65"-"\uffbe","\uffc2"-"\uffc7","\uffca"-"\uffcf","\uffd2"-"\uffd7",
"\uffda"-"\uffdc","\uffe0"-"\uffe1","\uffe5"-"\uffe6","\ufff9"-"\ufffb"]>
}
/* SEPARATORS */
TOKEN :
{
< LPAREN: "(" >
| < RPAREN: ")" >
| < LBRACE: "{" > { pushBrace(); }
| < RBRACE: "}" > { popBrace(); }
| < 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: ">>>" > { input_stream.backup(2); }
| < RSIGNEDSHIFT: ">>" > { input_stream.backup(1); }
| < GT: ">" >
}
/*****************************************
* THE JAVA LANGUAGE GRAMMAR STARTS HERE *
*****************************************/
/*
* Program structuring syntax follows.
*/
ASTCompilationUnit CompilationUnit() :
{}
{
[ LOOKAHEAD( ( Annotation() )* "package" ) PackageDeclaration() ( EmptyDeclaration() )* ]
( ImportDeclaration() ( EmptyDeclaration() )* )*
// ModularCompilationUnit:
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() ( EmptyDeclaration() )* ]
// OrdinaryCompilationUnit: -> TopLevelClassOrInterfaceDeclaration
( TypeDeclaration() ( EmptyDeclaration() )* )*
// SimpleCompilationUnit:
[
(
{ pushEmptyModifierList(); }
(
( LOOKAHEAD(3) ClassMemberDeclarationNoMethod() )*
ModifierList() MethodDeclaration()
( ClassOrInterfaceBodyDeclaration() )*
) #ClassBody
) #ImplicitClassDeclaration
]
<EOF>
2019-05-25 07:24:55 +02:00
{
jjtThis.setComments(token_source.comments);
return jjtThis;
}
}
2019-05-25 07:24:55 +02:00
// see ClassOrInterfaceBodyDeclaration()
void ClassMemberDeclarationNoMethod() #void:
{}
{
ModifierList()
( LOOKAHEAD(3) ClassOrInterfaceDeclaration()
| LOOKAHEAD({isKeyword("enum")}) EnumDeclaration()
| LOOKAHEAD({isKeyword("record")}) RecordDeclaration()
| LOOKAHEAD( [ TypeParameters() ] <IDENTIFIER> "(" ) ConstructorDeclaration()
| LOOKAHEAD( Type() <IDENTIFIER> (AnnotationList() "[" "]")* ( "," | "=" | ";" ) ) FieldDeclaration()
| LOOKAHEAD(2) AnnotationTypeDeclaration()
)
}
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() :
{String image;}
{
ModAnnotationList() "package" image=VoidName() { jjtThis.setImage(image); } ";"
}
void ImportDeclaration() :
{String image;}
{
"import"
(
"static" {jjtThis.setStatic();}
| LOOKAHEAD({isKeyword("module")}) <IDENTIFIER> {jjtThis.setModuleImport();}
)?
image=VoidName() { jjtThis.setImage(image); }
[ "." "*" {jjtThis.setImportOnDemand();} ] ";"
}
/*
2019-01-08 23:30:51 +01:00
* 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.
*/
void ModifierList():
{
EnumSet<JModifier> modifiers = EnumSet.noneOf(JModifier.class);
}
{
(
2019-05-24 19:08:06 +02:00
LOOKAHEAD(2)
(
"public" { modifiers.add(JModifier.PUBLIC); }
| "static" { modifiers.add(JModifier.STATIC); }
| "protected" { modifiers.add(JModifier.PROTECTED); }
| "private" { modifiers.add(JModifier.PRIVATE); }
| "final" { modifiers.add(JModifier.FINAL); }
| "abstract" { modifiers.add(JModifier.ABSTRACT); }
| "synchronized" { modifiers.add(JModifier.SYNCHRONIZED); }
| "native" { modifiers.add(JModifier.NATIVE); }
| "transient" { modifiers.add(JModifier.TRANSIENT); }
| "volatile" { modifiers.add(JModifier.VOLATILE); }
| "strictfp" { modifiers.add(JModifier.STRICTFP); }
| "default" { modifiers.add(JModifier.DEFAULT); }
2020-08-22 21:39:14 +02:00
| LOOKAHEAD({isKeyword("sealed")}) <IDENTIFIER> { modifiers.add(JModifier.SEALED); }
| LOOKAHEAD({isNonSealedModifier()}) <IDENTIFIER> <MINUS> <IDENTIFIER> { modifiers.add(JModifier.NON_SEALED); }
| Annotation()
)
)*
{ jjtThis.setDeclaredModifiers(modifiers); }
{ jjtree.injectRight(1); } // inject the modifier node in the follower
}
/*
* Declaration syntax follows.
*/
2020-02-14 04:14:15 +01:00
void TypeDeclaration() #void:
{}
{
ModifierList()
(
ClassOrInterfaceDeclaration()
2020-03-02 21:05:21 +01:00
| AnnotationTypeDeclaration()
| LOOKAHEAD({isKeyword("enum")}) EnumDeclaration()
| LOOKAHEAD({isKeyword("record")}) RecordDeclaration()
)
}
void ClassOrInterfaceDeclaration() #ClassDeclaration:
{}
{
2019-09-25 06:30:17 +02:00
( "class" | "interface" { jjtThis.setInterface(); } )
<IDENTIFIER> { jjtThis.setSimpleName(getToken(0).getImage()); }
[ TypeParameters() ]
[ ExtendsList() ]
[ ImplementsList() ]
[ LOOKAHEAD({isKeyword("permits")}) PermittedSubclasses() ]
ClassOrInterfaceBody()
}
void ExtendsList():
{}
{
2019-03-21 13:58:03 +01:00
"extends" AnnotatedClassOrInterfaceType()
( "," AnnotatedClassOrInterfaceType() )*
}
void ImplementsList():
{}
{
2019-03-21 13:58:03 +01:00
"implements" AnnotatedClassOrInterfaceType()
( "," AnnotatedClassOrInterfaceType() )*
}
void PermittedSubclasses() #PermitsList:
2023-03-19 22:49:45 +01:00
{}
{
2023-03-19 22:49:45 +01:00
softKeyword("permits")
ClassOrInterfaceType()
( "," ClassOrInterfaceType() )*
}
void EnumDeclaration():
2023-03-19 22:49:45 +01:00
{}
{
2023-03-19 22:49:45 +01:00
softKeyword("enum")
<IDENTIFIER> { jjtThis.setSimpleName(getToken(0).getImage()); }
[ ImplementsList() ]
EnumBody()
}
void EnumBody():
2019-09-25 06:30:17 +02:00
{}
{
"{"
[ EnumConstant() ( LOOKAHEAD(2) "," EnumConstant() )* ]
[ "," { jjtThis.setTrailingComma(); } ]
[ ";" { jjtThis.setSeparatorSemi(); } ( ClassOrInterfaceBodyDeclaration() )* ]
"}"
}
void EnumConstant():
{}
{
ModAnnotationList() VariableDeclaratorId() [ ArgumentList() ] [ AnonymousClassDeclaration() ]
}
2020-03-02 21:05:21 +01:00
void RecordDeclaration():
2023-03-19 22:49:45 +01:00
{}
{
2023-03-19 22:49:45 +01:00
softKeyword("record")
<IDENTIFIER> { jjtThis.setSimpleName(getToken(0).getImage()); }
[ TypeParameters() ]
RecordHeader()
[ ImplementsList() ]
RecordBody()
}
void RecordHeader() #void:
{}
{
"(" RecordComponentList() ")"
}
void RecordComponentList() :
{}
{
[ RecordComponent() ("," RecordComponent())* ]
}
void RecordComponent():
{}
{
2020-03-02 21:05:21 +01:00
ModAnnotationList()
FormalParamType()
VariableDeclaratorId()
}
void RecordBody():
{}
{
"{"
( RecordBodyDeclaration() )*
"}"
}
void RecordBodyDeclaration() #void :
{}
{
LOOKAHEAD(CompactConstructorDeclarationLookahead()) ModifierList() CompactConstructorDeclaration()
|
2020-03-02 19:00:59 +01:00
ClassOrInterfaceBodyDeclaration()
}
private void CompactConstructorDeclarationLookahead() #void:
2020-03-02 19:00:59 +01:00
{}
{
2020-03-28 15:28:34 +01:00
ModifierList() <IDENTIFIER> "{"
}
void CompactConstructorDeclaration():
2020-03-02 21:05:21 +01:00
{}
{
<IDENTIFIER> { jjtThis.setImage(token.image); }
2020-03-02 21:05:21 +01:00
Block()
}
void TypeParameters():
{}
{
2019-09-25 06:30:17 +02:00
"<" TypeParameter() ( "," TypeParameter() )* ">"
}
void TypeParameter():
2020-02-07 23:43:26 +01:00
{}
{
AnnotationList()
2020-02-07 23:43:26 +01:00
<IDENTIFIER> {setLastTokenImage(jjtThis);} [ "extends" IntersectionType() ]
}
void ClassOrInterfaceBody() #ClassBody:
{}
{
"{"
( ClassOrInterfaceBodyDeclaration() )*
"}"
}
void ClassOrInterfaceBodyDeclaration() #void:
{}
{ LOOKAHEAD(["static"] "{" ) Initializer()
| ModifierList()
( LOOKAHEAD(3) ClassOrInterfaceDeclaration()
| LOOKAHEAD({isKeyword("enum")}) EnumDeclaration()
2020-03-02 21:05:21 +01:00
| LOOKAHEAD({isKeyword("record")}) RecordDeclaration()
| LOOKAHEAD( [ TypeParameters() ] <IDENTIFIER> "(" ) ConstructorDeclaration()
| LOOKAHEAD( Type() <IDENTIFIER> (AnnotationList() "[" "]")* ( "," | "=" | ";" ) ) FieldDeclaration()
| LOOKAHEAD(2) MethodDeclaration()
| LOOKAHEAD(2) AnnotationTypeDeclaration()
)
|
2019-05-28 19:16:04 +02:00
";" #EmptyDeclaration
}
void FieldDeclaration() :
{}
{
Type() VariableDeclarator() ( "," VariableDeclarator() )* ";"
}
void VariableDeclarator() :
{}
{
VariableIdWithDims() [ "=" VariableInitializer() ]
}
void VariableDeclaratorId() #VariableId:
2019-10-07 19:35:20 +02:00
{}
{
<IDENTIFIER> { jjtThis.setName(getToken(0).getImage()); }
}
void VariableIdWithDims() #VariableId :
{}
{
<IDENTIFIER> { jjtThis.setName(getToken(0).getImage()); }
[ Dims() ]
}
void ReceiverParameter():
{}
{
AnnotatedClassOrInterfaceType() [ <IDENTIFIER> "." ] "this"
}
2019-02-18 23:39:10 +01:00
void VariableInitializer() #void:
{}
{
ArrayInitializer()
| Expression()
}
void ArrayInitializer() :
{}
{
"{"
[ VariableInitializer() ( LOOKAHEAD(2) "," VariableInitializer() )* ] [ "," ]
"}"
}
void MethodDeclaration() :
{}
{
[ TypeParameters() ]
ResultType()
<IDENTIFIER> { jjtThis.setName(getToken(0).getImage()); }
FormalParameters()
[ Dims() ]
2019-09-27 06:21:08 +02:00
[ ThrowsList() ]
( Block() | ";" )
}
void FormalParameters() :
{}
{
"(" [ ( LOOKAHEAD(ReceiverParameter()) ReceiverParameter() | FormalParameter() ) ( "," FormalParameter() )* ] ")"
}
void FormalParameter() :
{}
{
LocalVarModifierList()
2020-01-07 22:05:28 +01:00
FormalParamType() ("|" FormalParamType())* // remove this stuff when #2202 is merged
VariableIdWithDims()
}
void FormalParamType() #void:
{}
{
PrimitiveType() [ LOOKAHEAD(2) VarargsDimensions() #ArrayType(2) ]
| ClassOrInterfaceType() [ LOOKAHEAD(2) VarargsDimensions() #ArrayType(2) ]
}
void VarargsDimensions() #ArrayDimensions:
{}
{
// like ArrayDimensions but allows for a varargs ellipsis at the end ("...")
LOOKAHEAD(AnnotationList() "[") (LOOKAHEAD(AnnotationList() "[") ArrayTypeDim())+ [ VarargsDim() ]
| VarargsDim()
}
void VarargsDim() #ArrayTypeDim:
{}
{
TypeAnnotListNoInject() "..." {jjtThis.setVarargs();}
}
void ConstructorDeclaration() :
{}
{
[ TypeParameters() ]
<IDENTIFIER> {setLastTokenImage(jjtThis);}
FormalParameters()
[ ThrowsList() ]
ConstructorBlock()
}
private void ConstructorBlock() #Block:
{}
{
"{"
(
LOOKAHEAD(ExplicitConstructorInvocation()) ExplicitConstructorInvocation()
|
( LOOKAHEAD(2) BlockStatement() )*
[ LOOKAHEAD(ExplicitConstructorInvocation()) ExplicitConstructorInvocation() ]
)
( BlockStatement() )*
"}"
}
void ExplicitConstructorInvocation() :
2022-11-16 13:56:01 +01:00
{boolean prev = inExplicitConstructorInvoc; 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
2022-11-16 13:56:01 +01:00
{inExplicitConstructorInvoc = prev;}
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} [ ]}
*/
2019-09-25 06:30:17 +02:00
void IntersectionType() #IntersectionType(isIntersection):
{boolean isIntersection=false;}
2019-03-21 13:58:03 +01:00
{
2019-09-25 06:30:17 +02:00
AnnotatedType() ( "&" {isIntersection=true;} AnnotatedClassOrInterfaceType() )*
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
}
2019-05-29 12:56:34 +02:00
void ModAnnotationList() #ModifierList:
{jjtThis.setDeclaredModifiers(Collections.emptySet());}
{
(Annotation())*
}
int TypeAnnotListNoInject() #void:
{int num = 0;}
2019-05-29 12:56:34 +02:00
{
( TypeAnnotation() {num++;} )*
{
return num;
}
2019-05-29 12:56:34 +02:00
}
// Type annotation lists are by default injected in the
// next node to be opened (most likely a type).
// Sometimes (array dims), this need not be and TypeAnnotListNoInject
// should be used.
void TypeAnnotationList() #void:
{int size=0;}
2019-03-21 13:58:03 +01:00
{
size=TypeAnnotListNoInject() { jjtree.injectRight(size); }
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:
2020-01-07 22:24:32 +01:00
{}
{
2020-01-07 22:24:32 +01:00
PrimitiveType() [ LOOKAHEAD(2) Dims() #ArrayType(2) ]
| ClassOrInterfaceType() [ LOOKAHEAD(2) Dims() #ArrayType(2) ]
}
2019-08-15 17:39:44 +02:00
void Dims() #ArrayDimensions:
{}
{
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-05-29 12:56:34 +02:00
TypeAnnotListNoInject() "[" "]"
}
2018-11-05 21:20:43 +01:00
2018-11-05 21:20:43 +01:00
void ReferenceType() #void:
{}
{
2019-05-28 19:16:04 +02:00
// We parse it that way because the right injection considers node openings,
// which means if we want the annotations to belong to the element type, then
// the ArrayType node needs to be opened after eg the PrimitiveType
PrimitiveType() Dims() #ArrayType(2)
| ClassOrInterfaceType() [ LOOKAHEAD(2) Dims() #ArrayType(2) ]
}
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
2019-05-28 19:16:04 +02:00
(LOOKAHEAD({jjtree.isInjectionPending()})
// Perhaps surprisingly a type annotation binds to the closest segment
// So in "@B Map.Entry", "@B" binds to "Map", and Map is required to be a type name.
// If the annotation is not applicable to TYPE_USE then it doesn't compile
// So if there are annotations pending injection here, then they're necessarily
// type annotations, since otherwise they would have been consumed in the
// annotation list of a declaration.
// Eg in "public abstract @F int foo();", "@F" is part of the modifier list of the method.
// but in "public abstract <T> @F T foo();", "@F" is necessarily a type annotation, and indeed
// is in a separate AnnotationList (it follows the type parameters so is not a modifier).
// To sum it up, if we have annotations pending, then the first segment is necessarily
// a type name, otherwise it wouldn't have compiled. So it's not ambiguous and we can
// start fresh: "@B Map.Entry" will be unambiguously [[@B Map].Entry]
2019-05-28 19:16:04 +02:00
(<IDENTIFIER> { jjtThis.setSimpleName(getToken(0).getImage()); } [ TypeArguments() ]) #ClassType
2019-05-28 19:16:04 +02:00
|
2018-11-06 04:22:31 +01:00
// Otherwise, for now we have no clue 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-28 19:16:04 +02:00
AmbiguousName()
[ TypeArguments() #ClassType(2) ]
2019-05-28 19:16:04 +02:00
{
// At this point the first ClassType may be on top of the stack,
2019-05-28 19:16:04 +02: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.
Node first = jjtree.peekNode();
if (first instanceof ASTClassType) {
2019-05-28 19:16:04 +02:00
// then we saw type arguments, so the last segment is definitely a type name
ASTAmbiguousName name = first.firstChild(ASTAmbiguousName.class);
2019-05-28 19:16:04 +02:00
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.
*/
( LOOKAHEAD(2) "." ClassTypeSegment() )*
2019-04-03 14:48:48 +02:00
{ forceTypeContext(); }
}
private void ClassTypeSegment() #ClassType(jjtree.nodeArity() + 1):
2019-05-24 16:33:48 +02:00
{}
{
2019-05-29 12:56:34 +02:00
TypeAnnotListNoInject()
2019-05-24 16:33:48 +02:00
<IDENTIFIER>
// We'll enclose the previous segment
{ jjtThis.setSimpleName(getToken(0).getImage()); }
2019-05-24 16:33:48 +02:00
[ TypeArguments() ]
}
2018-11-06 04:22:31 +01:00
void TypeArguments():
{}
{
LOOKAHEAD(2)
2019-09-25 06:30:17 +02:00
"<" TypeArgument() ( "," TypeArgument() )* ">"
|
2019-09-25 06:30:17 +02:00
"<" ">"
}
2019-03-31 06:59:49 +02:00
void TypeArgument() #void:
{}
{
TypeAnnotationList() (ReferenceType() | WildcardType())
}
2019-03-21 13:58:03 +01:00
void WildcardType():
{}
{
"?" [ ("extends" | "super" {jjtThis.setLowerBound(true);}) 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() :
{}
{
2020-07-26 17:48:42 +02:00
"boolean" {jjtThis.setKind(PrimitiveTypeKind.BOOLEAN);}
New typeres framework Ceci est la combinaison de 338+ commits. Make set of classes to mirror types Implement capture conversion Document Doc Implement contains for targs Implement toString Fully implement subtyping Check for reifiability Implement unchecked, fix array subtyping Test rec typevar building Test primitive subtyping Test array subtyping Test wildcards subtyping Doc Rename primitiveType Reify conversions Test boxing Make constants for common types Test type param mutual recursion More defensive validation Implement numeric promotion Checkstyle Implement supertype set Implement lub Fix infinite recursion Fix lub bugs Use linkedhashset for stable ordering Add primitives to common types Move common types into type factory Try a lazy class resolver, needs a symbol table Improve lazy resolver Implement conditional expr typing remove poly impl Represent primitive wrappers differently Better compromise for primitive wrappers Extract wildcard interface Extract array type interface Refactor to extract interfaces Don't depend on initialization of jprimitiveType Finish pretty printer Remove dependency on reflection Fix class initialization trouble Move to type constants Use regular impl for OBJECT Encapsulate ops into TypeOps Add inference var to model Impl some ops Add some type inference algos Invocation context compatibility Add incorporation Generify bound set with ExprOps Add applicability tests Fix compil Add incorporation actions Implement incorporation Add inference steps Implement brute force walk strategy Remove some type params Wire in everything Implement methodtype Access methods from JClassType Represent enclosing types Work on overriding Implement expr ops Catch easy cases Diamond inference Fix pretty printer Fix concurrent mod Test Add reflect info to JModifier Add symbolic type declaration Most specific check Test with nested invocation Test lub Add constraints for lambdas and all subexpressions Resolve full call chain with lambdas Set partial results on nodes Test chain Doc Generalise expr mirrors Fix context Add invocation mirror Add support for method references make infer static Cleanup interface Fix constructor access Test method reference Cleanup method ref types Test constructor reference Test overload resolution, fix TODO Fix ctdecl of mref on non-ground target type Add graph walk strategy Document Use toposort Make enum constant implement ctor invoc mirror Work on context Test conditional expr type Handle switch exprs uniformly Fix bugs Add type inference performance test case Add overload resolution tests Cache result of overload selection, only recompute invocation Optimise common case in graph building Optimise propagation by merging variables Fix some tests, cleanup Preserve applicability phase Improve jsinglechildnode Add way to get a field's type Make more complex stress test Cache bound check results Type projection for inference Simplify lazy type inference of var ids Improve memory usage - reuse constant enum sets (by far the biggest leak, given the number of PropagateBounds created) - implement substitution without a visitor Optimise imports Cache hash of classes Cleanup Add overloads test Fix context fetching Fix lub bug Test switch expr Fix rebase Remove useless type Factorise poly check Remove base poly expr Fix array initializer Remove duplicated numeric literal typing Fix inferred iterable type Move method resolution phase to upper level Delete useless var Commit pr plan Remove useless method Fix enclosing type comb rule REVERT ME Remove partial enclosing type support Add package info Put task list in branch description Fix old rebases Fix rebase Simplify for left recursive ops Fix comments Fix rebase Revert "REVERT ME Remove partial enclosing type support" This reverts commit 8080ff1585b3a760fafc957282771baf716f3c7f. WIP base type mirrors on symbols Make JMethodType not a JTypeMirror Figure out getSymbol & type vars make type factory non-static Add a parameter to visitors Fix compilation Use symbol table in lazy type resolver Move package Fix most tests Move internal api around Specify some stuff Split reflect impl from API Make AST impl Equality routines Fix tests Move internal symtable doc Improve symtableResolver ergonomics Poly res tests Make AST type factory Update Make lambda expressions not a MethodlikeNode Build local var sym Update for switches Make Infer not static, fix logging Don't expose visitor nature of SymbolResolver Cleanup Improve type error handling Don't throw away CTdecls for an arg mismatch Fix more tests Local symbol tables Symbol table looks in interfaces Incompatible changes that should stay on this branch and not be squashed ResolveResult Explicitly typed lambdas Fix some static bugs Fix a lot of bugs Use FQCN symtable Move parsing contexts to upper level Cleanup DSL to test types test subst Dont create an exception for each failure Stack trace creation takes a significant amount of time Remove laziness for fetching method streams Streams obfuscate performance analysis by delaying the computation until the last moment. Fix some bugs with unresolved classes Also measure performance: full typeres is around same time as parsing. This is great. At this point 80% of all types are resolved (though some type inference results are probably incorrect). Mostly this comes from the fact that there are still AmbiguousNames in the tree. Fix problem with varargs Handle enclosing types Enclosing types Fix compil Add another stress test Refactor primitive subtyping Fix rebase Fix rebase: tests Figure out type factories WIP Move type ops into TypeOps Move AsSuper Figure out type factories WIP Make TypeSystem object wip WIP WIP Make typeops static Fix grounding routine Fix bug with return type Start fixing tests Cleanup primitive types Fix some tests Add todo Remove JDK test dependency Test cases lubbing String and StringBuilder produce different outputs on JDK [8, 11[ and 11+, because StringBuilder was made a Comparable<StringBuilder> in JDK 11 Implement most specific method selection Drop JVariableSig from symbol table Use asOuterSuper instead Fix local var type inference with foreach. Fix a lot of stuff based on jdk 12 run Make type system own symbol factories Fix intersection with bound Fix standalone ternary types Capture field access type Eg class Foo<T> { T[] field; } Foo<? extends T>.field : capture(T)[] Add tests Delete lexical substs Fix reflected owner type Add graph viz Fix bug with graph reduction Optimise ivar dependency reduction by a lot. The previous 60s stress test now takes 600ms. Btw at this point type res for the whole JDK 12 codebase takes 25 secs, down from 175 on 6.20.0 (7x speedup). Implement inherited field/class lookup Fix scoping inside switch statements Fix a few bugs Handle inherited methods Interfaces should inherit Object methods Move lub into TypeSystem Handle class types induced by intersections Fix lambda congruence Test lambda with intersection type Fix inference Fix same type check using equals Simplify intersection type induction Remove type sys extension Simplify sym factories Finish symbol factory streamlining Document Cache non-erased symbols separately Doc Revert, erased types are only raw Get rid of generic constants in TypeSystem Remove some dead code Fix exact method reference Improve unchecked conversion handling Fix dependency of delegated ivars Improve logging, fix a few bugs Test enclosing types Improve loggin Print file location Fix subtyping for wildcards Fix standalone method types Fix boxing conversion Fix promotion on unary exprs Implement special treatment of getClass() Add tests for anon classes Make symbol tables use lists for methods Fix method reference with void target type Move graphUtils Make unresolved types bottom (instead of top) It's more likely to be useful. Eg. Unresolved var = ...; knownMethod(var); Here, var must conform to the parameter, if it is unresolved, we assume that's the case. Otherwise we would fail resolution of knownMethod for this call site. The reverse situation is rarer. Fix conversions in loose phase Make JInferenceVar a class Hide TypePair Remove special string type Fix toString of anon classes Implement overload specificity for generic methdos Fix anon class ctors Fix Object methods not in scope in interfaces Fixing anon class ctors WIP Fix rebase Cleanup Print type var bounds Fix tests, improve pretty printing Hide ast sym factory Fix array method erasure Fix superclass, uncover bug with substitution Substitute type param bounds Make Array have Object methods Fix duplicated logging categories Make root symbolFactory thread safe Fix overload ambiguity with hiding Fix exact method when they shadow each other Make PMultimap type Make shadowGroup Make a few utilities to replace import tables Replace other tables Cleanup Compat with old impl Fix rebase Port to using sigs Make base class for shadow groups Fix method group Test shadowing of inherited members Fix bugs with tparams Specialize to StringMultimap Big optimizations Simplify a lot of things, remove caching of getAllMethods Factorize group implementations Add resolveFirst Fix bug with ctor invocation Fix type parsing for union types Generify multimap Implement nextShadowGroup Remove unused API of pmultimap Use interface where possible Fix tests Use singleton resolvers more frequently Remove commons collections dependency Tries don't make a significant difference in execution time. Mostly because tries used in symbol tables are very small. Remove some api of jtypemirror Fix shadow barriers Fix accessibility check for protected member Qualified ctor invocations have access to inner class name Make strict stream for profiling LOOK AT ME strict streams Strict streams are actually *much* more efficient for our use case Extract some stuff into CollectionUtil Make methods shadow each other doc Simplify OptionalBool Improve strict stream Eventually I'll remove it Doc newer symtable Make PMultimap type Make shadowGroup Make a few utilities to replace import tables Cleanup Checkout newer sym table from typeres branch Port Checkout tests Port tests, remove old impl Extract augment function Move classes back into internal package Abstract stuff away for pmd-core Optimise singular map case even more Fix nextShadowGroup WIP Make ShadowIterator to replace getNextGroup Use chain iterator Add tests Finish impl Add tests for supertype enumerator Add tests for method shadowing in imports Port to using types etc Fix tests Fix outdated tests Fix anon class ctors Fix more outdated tests Object methods should be in scope in interfaces Fix compil Make simple signature parser Make stubs Figure out loading logic Progress on type param parsing Do away with nested classes Class signatures It works! Parse tvar bounds lazily Fix a lot of stuff No errors on pmd-core JDK 13 under 80s Implement toString everywhere Try to make the whole thing thread safe Still a spurious NPE, access flags are weird. For j.l.invoke.DelegatingMethodHandle (declared as `final class Holder {}`) the access flags from the class file are 0x32, and the enclosing type is null, while when accessed through reflection, the access flags are correctly 0x10. The class is engineered through VM magic so idk what happens Remove shared caching of TypeSystem The sub caches are not useful anymore and creating them all the time is wasteful Add some tests Fix improper locking Reorganise typeSystem initialization Change the name Doc Opts Optimise away some expensive lookaheads in the parser Doc Fix modifiers Optimise big switches in parser Placing token decls that are frequently used together closer increases the chance that the compiler generate a TABLESWITCH instruction instead of a LOOKUPSWITCH. Table switches take constant lookup time, while lookupswitch is linear. Selection of table switch is now done for the biggest switches of the parser: the one in types, in modifiers, in statements, and at the start of expressions. Other lookup switches are unimportant because they have very few labels (typically 2). Optimise variable initializer lookahead make test rule noop PARSER Optimise common branches in expressions PARSER opt blocks & statements doc Don't accept void by default Split signature parsers Simplify type param parsing Simplify type params parsing Some optimisations Tests Simplify synchronization Factorize synchronization logic Move ConsList into pmd-core Prune more empty nodes Use single map for asm resolver Remove changes to parser Add option to suppress type inference log entry creation Use soft references to allow class stubs to be GCed Fix rebase
2020-02-11 04:43:54 +01:00
| "char" {jjtThis.setKind(PrimitiveTypeKind.CHAR);}
| "byte" {jjtThis.setKind(PrimitiveTypeKind.BYTE);}
| "short" {jjtThis.setKind(PrimitiveTypeKind.SHORT);}
| "int" {jjtThis.setKind(PrimitiveTypeKind.INT);}
| "long" {jjtThis.setKind(PrimitiveTypeKind.LONG);}
| "float" {jjtThis.setKind(PrimitiveTypeKind.FLOAT);}
| "double" {jjtThis.setKind(PrimitiveTypeKind.DOUBLE);}
}
void ResultType() #void:
{}
{
"void" #VoidType
| AnnotatedType()
}
2019-09-27 06:21:08 +02:00
void ThrowsList() :
{}
{
2019-09-27 06:21:08 +02:00
"throws" AnnotatedClassOrInterfaceType() ( "," AnnotatedClassOrInterfaceType())*
}
/*
* 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-08-15 13:54:52 +02:00
LOOKAHEAD(1) op=AssignmentOperator() {jjtThis.setOp(op);} Expression()
]
}
2019-02-19 02:30:43 +01:00
AssignmentOp AssignmentOperator() #void:
{}
{
"=" { return AssignmentOp.ASSIGN; }
| "*=" { return AssignmentOp.MUL_ASSIGN; }
| "/=" { return AssignmentOp.DIV_ASSIGN; }
| "%=" { return AssignmentOp.MOD_ASSIGN; }
| "+=" { return AssignmentOp.ADD_ASSIGN; }
| "-=" { return AssignmentOp.SUB_ASSIGN; }
| "<<=" { return AssignmentOp.LEFT_SHIFT_ASSIGN; }
| ">>=" { return AssignmentOp.RIGHT_SHIFT_ASSIGN; }
| ">>>=" { return AssignmentOp.UNSIGNED_RIGHT_SHIFT_ASSIGN; }
| "&=" { return AssignmentOp.AND_ASSIGN; }
| "^=" { return AssignmentOp.XOR_ASSIGN; }
| "|=" { return AssignmentOp.OR_ASSIGN; }
}
void ConditionalExpression() #ConditionalExpression(>1) :
{}
{
2019-08-15 13:54:52 +02:00
ConditionalOrExpression() [LOOKAHEAD(1) "?" Expression() ":" ConditionalExpression() ]
}
void ConditionalOrExpression() #void:
{}
{
2019-08-15 13:54:52 +02:00
ConditionalAndExpression() (LOOKAHEAD(1) ("||" {jjtThis.setOp(BinaryOp.CONDITIONAL_OR);} ConditionalAndExpression()) #InfixExpression(2))*
}
void ConditionalAndExpression() #void:
{}
{
2019-08-15 13:54:52 +02:00
InclusiveOrExpression() (LOOKAHEAD(1) ("&&" {jjtThis.setOp(BinaryOp.CONDITIONAL_AND);} InclusiveOrExpression()) #InfixExpression(2))*
}
void InclusiveOrExpression() #void:
{}
{
2019-08-15 13:54:52 +02:00
ExclusiveOrExpression() (LOOKAHEAD(1) ("|" {jjtThis.setOp(BinaryOp.OR);} ExclusiveOrExpression()) #InfixExpression(2))*
}
void ExclusiveOrExpression() #void:
{}
{
2019-08-15 13:54:52 +02:00
AndExpression() (LOOKAHEAD(1) ("^" {jjtThis.setOp(BinaryOp.XOR);} AndExpression()) #InfixExpression(2))*
}
void AndExpression() #void:
{}
{
2019-08-15 13:54:52 +02:00
EqualityExpression() (LOOKAHEAD(1) ("&" {jjtThis.setOp(BinaryOp.AND);} EqualityExpression()) #InfixExpression(2))*
}
void EqualityExpression() #void:
{}
{
InstanceOfExpression()
2019-08-15 13:54:52 +02:00
(LOOKAHEAD(1)
(
( "==" {jjtThis.setOp(BinaryOp.EQ);}
| "!=" {jjtThis.setOp(BinaryOp.NE);}
)
InstanceOfExpression()
) #InfixExpression(2)
)*
}
void Pattern() #void:
{}
{
LOOKAHEAD((Annotation())* ReferenceType() "(") RecordPattern()
| TypePattern()
}
void TypePattern():
{}
{
LocalVarModifierList() LocalVariableType() VariableDeclaratorId()
}
void RecordPattern():
2022-07-10 15:31:29 +02:00
{}
{
(Annotation())* ReferenceType() RecordStructurePattern()
}
2024-10-07 16:40:37 +02:00
void RecordStructurePattern() #PatternList:
{}
{
"(" [ ComponentPatternList() ] ")"
}
2024-10-07 16:40:37 +02:00
void ComponentPatternList() #void :
{}
{
ComponentPattern() ( "," ComponentPattern() )*
}
void ComponentPattern() #void:
{}
{
LOOKAHEAD({isKeyword("_")}) UnnamedPattern()
| Pattern()
}
void UnnamedPattern():
{}
{
softKeyword("_")
}
void InstanceOfExpression() #void:
{}
{
RelationalExpression() [
("instanceof"
(
LOOKAHEAD(ReferenceType() "(") RecordPattern()
| AnnotatedType() [
2022-11-16 13:56:01 +01:00
VariableDeclaratorId() #TypePattern(2)
| RecordStructurePattern() #RecordPattern(2)
]
| Pattern()
)
2020-03-02 21:05:21 +01:00
{
jjtThis.setOp(BinaryOp.INSTANCEOF);
AbstractJavaNode top = jjtree.popNode();
if (top instanceof ASTPattern) {
2022-01-29 19:04:32 +01:00
if (top instanceof ASTTypePattern && !(top.getChild(0) instanceof ASTModifierList)) {
2021-02-18 12:58:13 +01:00
insertEmptyModifierListWithAnnotations(top, (AbstractJavaNode) top.getChild(0));
}
2020-03-02 21:05:21 +01:00
top = new ASTPatternExpression((ASTPattern) top);
} else {
top = new ASTTypeExpression((ASTType) top);
}
jjtree.pushNode(top);
}
2022-11-16 13:56:01 +01:00
{} // manipulate node before it is closed.
2018-12-22 09:01:20 +01:00
) #InfixExpression(2)
]
}
2019-07-28 15:19:52 +02:00
void RelationalExpression() #void:
{}
{
2019-07-28 15:19:52 +02:00
// There technically cannot be more than one, because it wouldn't compile
// But we give it some leeway to not make the parser too knowledgeable
// 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.
ShiftExpression()
2019-08-15 13:54:52 +02:00
(LOOKAHEAD(1)
(
(
"<" {jjtThis.setOp(BinaryOp.LT);}
| ">" {jjtThis.setOp(BinaryOp.GT);}
| "<=" {jjtThis.setOp(BinaryOp.LE);}
| ">=" {jjtThis.setOp(BinaryOp.GE);}
)
ShiftExpression()
) #InfixExpression(2)
)*
}
2019-03-29 18:50:43 +01:00
void ShiftExpression() #void:
{}
{
AdditiveExpression()
2019-08-15 13:54:52 +02:00
(LOOKAHEAD(1)
(
( "<<" {jjtThis.setOp(BinaryOp.LEFT_SHIFT);}
| RSIGNEDSHIFT() {jjtThis.setOp(BinaryOp.RIGHT_SHIFT);}
| RUNSIGNEDSHIFT() {jjtThis.setOp(BinaryOp.UNSIGNED_RIGHT_SHIFT);}
)
AdditiveExpression()
) #InfixExpression(2)
)*
}
2019-03-28 07:53:08 +01:00
void AdditiveExpression() #void:
{}
{
MultiplicativeExpression()
2019-08-15 13:54:52 +02:00
(LOOKAHEAD(1)
(
( "+" {jjtThis.setOp(BinaryOp.ADD);}
| "-" {jjtThis.setOp(BinaryOp.SUB);}
)
MultiplicativeExpression()
) #InfixExpression(2)
)*
}
2019-03-28 09:01:55 +01:00
void MultiplicativeExpression() #void:
{}
{
2019-03-28 09:01:55 +01:00
UnaryExpression()
2019-08-15 13:54:52 +02:00
(LOOKAHEAD(1)
(
( "*" {jjtThis.setOp(BinaryOp.MUL);}
| "/" {jjtThis.setOp(BinaryOp.DIV);}
| "%" {jjtThis.setOp(BinaryOp.MOD);}
)
UnaryExpression()
) #InfixExpression(2)
)*
2019-03-28 09:01:55 +01:00
}
2019-07-28 15:19:52 +02:00
// TODO update operator setting for those expressions
2019-05-28 16:33:59 +02:00
void UnaryExpression() #void:
{}
{
2019-12-09 14:54:05 +01:00
(("+" {jjtThis.setOp(UnaryOp.UNARY_PLUS);} | "-" {jjtThis.setOp(UnaryOp.UNARY_MINUS);}) UnaryExpression()) #UnaryExpression
| PrefixIncrementExpression()
| UnaryExpressionNotPlusMinus()
}
2019-12-09 14:54:05 +01:00
void PrefixIncrementExpression() #UnaryExpression:
{}
{
2019-12-09 14:54:05 +01:00
("++" {jjtThis.setOp(UnaryOp.PRE_INCREMENT);}
| "--" {jjtThis.setOp(UnaryOp.PRE_DECREMENT);}
)
PrimaryExpression()
}
2019-05-28 16:33:59 +02:00
void UnaryExpressionNotPlusMinus() #void:
{}
{
2019-12-09 14:54:05 +01:00
(( "~" {jjtThis.setOp(UnaryOp.COMPLEMENT);} | "!" {jjtThis.setOp(UnaryOp.NEGATION);}) 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 ")"
2019-09-25 06:30:17 +02:00
| LOOKAHEAD("(" IntersectionType() ")" UnaryExprNotPmStart() )
("(" IntersectionType() ")" 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() #void:
{}
{
PrimaryExpression()
[
LOOKAHEAD(1)
2019-12-09 14:54:05 +01:00
("++" {jjtThis.setOp(UnaryOp.POST_INCREMENT);}
| "--" {jjtThis.setOp(UnaryOp.POST_DECREMENT);}
) #UnaryExpression(1)
]
}
2019-03-15 15:29:16 +01:00
void SwitchExpression() :
2020-03-17 21:36:15 +01:00
{boolean prevInSwitchBlock = inSwitchExprBlock;}
2019-03-15 15:29:16 +01:00
{
2020-03-17 21:36:15 +01:00
"switch" "(" Expression() ")"
{inSwitchExprBlock = true;}
SwitchBlock()
{inSwitchExprBlock = prevInSwitchBlock;}
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 :
{JavaccToken savedStart;}
{
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" #VoidType "." "class") #ClassLiteral
2020-01-25 02:40:35 +01:00
| LOOKAHEAD(1) // suppress the warning here.
(PrimitiveType() [ Dims() ] ) #ArrayType(>1)
2019-05-24 16:33:48 +02:00
(
MethodReference()
| "." "class" #ClassLiteral(1)
)
// If annotations start the expression, it's necessarily a method or ctor reference
// This is because types in class literals or in qualified super/this may not be annotated
2020-01-25 02:40:35 +01:00
| LOOKAHEAD("@") AnnotatedRefType() MethodReference()
2019-05-26 16:47:22 +02:00
| LOOKAHEAD(LambdaLahead()) LambdaExpression()
// Parenthesized expr, we need to adjust start/end tokens
| "(" {savedStart = getToken(0);} Expression() ")"
{
AstImplUtil.bumpParenDepth((ASTExpression) jjtree.peekNode());
AbstractJavaNode top = (AbstractJavaNode) jjtree.peekNode();
2020-05-02 20:54:41 +02:00
top.setFirstToken(savedStart);
top.setLastToken(getToken(0));
}
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()
| {forceExprContext();} Template() #TemplateExpression(2)
2019-05-24 16:33:48 +02:00
)
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)
}
2020-01-25 02:40:35 +01:00
void MethodReference() #MethodReference(jjtree.nodeArity() + 1): // LHS is injected
2019-09-25 06:30:17 +02:00
{}
{
2020-01-25 02:40:35 +01:00
"::"
2019-05-24 16:33:48 +02:00
[TypeArguments()]
( "new" | <IDENTIFIER> ) { jjtThis.setMethodName(getToken(0).getImage()); }
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}) LambdaParameterList() "->"
2019-05-24 19:47:42 +02:00
}
// 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():
2019-09-25 06:30:17 +02:00
{ }
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
{}
{
SimpleLambdaParam()
| LOOKAHEAD("(" <IDENTIFIER> ("," | ")"))
"(" [ SimpleLambdaParam() ( "," SimpleLambdaParam())* ] ")"
| "(" [ LambdaParameter() ( "," LambdaParameter() )* ] ")"
2018-07-19 22:00:34 +02:00
}
void SimpleLambdaParam() #LambdaParameter:
{pushEmptyModifierList();}
2019-05-28 19:16:04 +02:00
{
VariableDeclaratorId()
2019-05-28 19:16:04 +02:00
}
void LambdaParameter():
{}
2018-07-19 22:00:34 +02:00
{
LocalVarModifierList() // this weakens the grammar a bit
[
LambdaParameterType()
]
VariableIdWithDims()
2018-07-19 22:00:34 +02:00
}
/** 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; }
| FormalParamType() { return false; }
2018-07-19 22:00:34 +02:00
}
void Template() :
{}
{
StringTemplate()
| TextBlockTemplate()
| <STRING_LITERAL> #TemplateFragment
| <TEXT_BLOCK_LITERAL> #TemplateFragment
}
void StringTemplate() #void :
{}
{
<STRING_TEMPLATE_BEGIN> #TemplateFragment
EmbeddedExpression()
(LOOKAHEAD(2) (<RBRACE> <STRING_TEMPLATE_MID> ) #TemplateFragment EmbeddedExpression() )*
(<RBRACE> <STRING_TEMPLATE_END>) #TemplateFragment
}
void TextBlockTemplate() #void :
{}
{
<TEXT_BLOCK_TEMPLATE_MID> #TemplateFragment
EmbeddedExpression()
(LOOKAHEAD(2) ( <RBRACE> <TEXT_BLOCK_TEMPLATE_MID> ) #TemplateFragment EmbeddedExpression() )*
(<RBRACE> <TEXT_BLOCK_LITERAL>) #TemplateFragment
}
void EmbeddedExpression() #void :
{}
{
[ Expression() ]
}
2019-02-17 05:41:33 +01:00
void Literal() #void :
2020-04-08 21:06:19 +02:00
{}
{
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():
2020-02-07 23:43:26 +01:00
{}
{
2020-02-07 23:43:26 +01:00
( <INTEGER_LITERAL> { jjtThis.setIntLiteral(); }
| <FLOATING_POINT_LITERAL> { jjtThis.setFloatLiteral(); }
2019-02-17 05:41:33 +01:00
)
2020-02-07 23:43:26 +01:00
{ setLastTokenImage(jjtThis); }
}
2019-02-17 05:41:33 +01:00
void CharLiteral():
{}
{
2020-02-07 23:43:26 +01:00
<CHARACTER_LITERAL> { setLastTokenImage(jjtThis); }
}
2019-02-17 05:41:33 +01:00
void StringLiteral():
{}
2019-02-17 05:41:33 +01:00
{
( <STRING_LITERAL>
2020-02-07 23:43:26 +01:00
| <TEXT_BLOCK_LITERAL> { jjtThis.setTextBlock(); }
)
{ setLastTokenImage(jjtThis); }
2019-02-17 05:41:33 +01:00
}
void ArgumentList() :
{}
{
"(" [ Expression() ( "," Expression() )* ] ")"
}
2019-02-17 14:25:07 +01:00
// more straightforward because can't be an array creation expr
2020-01-25 02:40:35 +01:00
void QualifiedAllocationExpr() #ConstructorCall(jjtree.nodeArity() + 1):
{}
{
2019-02-17 14:25:07 +01:00
"new"
[ TypeArguments() ]
2019-05-28 19:16:04 +02:00
AnnotatedClassOrInterfaceType()
2019-04-26 00:27:23 +02:00
ArgumentList()
[ AnonymousClassDeclaration() ]
2019-02-17 14:25:07 +01:00
}
void AnonymousClassDeclaration():
{
pushEmptyModifierList();
}
{
ClassOrInterfaceBody()
}
2019-02-17 14:25:07 +01:00
// 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-05-29 12:56:34 +02:00
"new" [ TypeArguments() ] TypeAnnotationList()
2019-02-17 14:25:07 +01:00
(
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
|
ArgumentList() [ AnonymousClassDeclaration() ]
2019-02-17 14:25:07 +01:00
)
)
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
}
2019-02-17 14:25:07 +01:00
/*
* The array dimensions are appended to the array type and they're both
* enclosed into an ArrayType node.
*/
2019-03-26 18:09:47 +01:00
void ArrayDimsAndInits() #void:
{}
{
2019-08-15 17:39:44 +02:00
LOOKAHEAD(TypeAnnotationList() "[" "]" ) (((ArrayTypeDim())+) #ArrayDimensions) #ArrayType(2) [ ArrayInitializer() ]
| ( (ArrayDimExpr())+ #ArrayDimensions ) #ArrayType(2)
2019-03-26 18:09:47 +01:00
}
// may push either an ArrayDimExpr or ArrayTypeDim
2019-03-26 18:09:47 +01:00
void ArrayDimExpr() #void:
{boolean hasExpr=false;}
{
2019-05-29 12:56:34 +02:00
((TypeAnnotListNoInject() "[" [ Expression() {hasExpr=true;} ] "]") #ArrayDimExpr(hasExpr) ) #ArrayTypeDim(!hasExpr)
}
/*
* Statement syntax follows.
*/
void Statement() #void:
{}
{
StatementNoIdent()
// 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
2020-03-17 21:36:15 +01:00
| LOOKAHEAD( { isYieldStart() } ) YieldStatement()
| LOOKAHEAD( { isAssertStart() } ) AssertStatement()
| LOOKAHEAD(2) LabeledStatement()
| ( StatementExpression() ";" ) #ExpressionStatement
}
void StatementNoIdent() #void:
{}
{
Block()
| EmptyStatement()
| SwitchStatement()
| IfStatement()
| WhileStatement()
| DoStatement()
| ForStatement()
| BreakStatement()
| ContinueStatement()
| ReturnStatement()
| ThrowStatement()
| SynchronizedStatement()
| TryStatement()
}
void LabeledStatement() :
2020-02-07 23:43:26 +01:00
{}
{
2020-02-07 23:43:26 +01:00
<IDENTIFIER> { setLastTokenImage(jjtThis); } ":" Statement()
}
void Block() :
{}
{
"{"
( BlockStatement() )*
"}"
}
void BlockStatement() #void:
{} // Note: this has been written this way to minimize lookaheads
// This generates a table switch with very few lookaheads
{
LOOKAHEAD(1, "@" | "final" )
// this eagerly parses all modifiers and annotations. After that, either a local type declaration
// or a local variable declaration follows.
// This allows more modifiers for local variables than actually allowed
2020-08-23 22:00:09 +02:00
// The ModifierList is adopted by the next node to open
ModifierList() (
LOOKAHEAD({localTypeDeclAfterModifiers()}) LocalTypeDecl()
2020-08-23 22:00:09 +02:00
| LOOKAHEAD({true}) LocalVariableDeclarationPendingModifiers() ";" { fixLastToken(); }
)
| LOOKAHEAD(1, <IDENTIFIER>)
(
LOOKAHEAD({ localTypeDeclGivenNextIsIdent() }) ModifierList() LocalTypeDecl()
| LOOKAHEAD({ isAssertStart() }) AssertStatement()
| LOOKAHEAD({ isYieldStart() }) YieldStatement()
| LOOKAHEAD({ getToken(2).kind == COLON }) LabeledStatement()
2020-08-23 15:53:58 +02:00
| LOOKAHEAD(ReferenceType() <IDENTIFIER>) LocalVariableDeclaration() ";" { fixLastToken(); }
| LOOKAHEAD({true}) ExpressionStatement()
)
| LOOKAHEAD(1, LocalTypeStartNoIdent()) ModifierList() LocalTypeDecl()
| LOOKAHEAD(1) StatementNoIdent()
| LOOKAHEAD(Type() <IDENTIFIER>) LocalVariableDeclaration() ";" { fixLastToken(); }
| LOOKAHEAD({true}) ExpressionStatement()
}
private void LocalTypeStartNoIdent() #void: // A lookahead
{}
2020-08-23 21:31:32 +02:00
{ // notice: not default, not synchronized, not final
"public" | "static" | "protected" | "private"
| "abstract" | "native" | "transient"
| "volatile" | "strictfp"
| "class" | "interface"
}
void LocalTypeDecl() #void:
{} // At the point this is called, a ModifierList is on the top of the stack,
{ // waiting for the next node to open. We want that node to be the type declaration,
// not the wrapper statement node.
( ClassOrInterfaceDeclaration()
2020-08-22 21:39:14 +02:00
| LOOKAHEAD({isKeyword("record")}) RecordDeclaration()
| LOOKAHEAD({isKeyword("enum")}) EnumDeclaration()
) {
// Wrap the type decl into a statement
// This can't be done with regular jjtree constructs, as the ModifierList
// is adopted by the first node to be opened.
ASTTypeDeclaration type = (ASTTypeDeclaration) jjtree.popNode();
ASTLocalClassStatement stmt = new ASTLocalClassStatement(type);
jjtree.pushNode(stmt);
}
}
/*
* See https://docs.oracle.com/javase/specs/jls/se10/html/jls-14.html#jls-14.4
*/
void LocalVariableDeclaration() :
{}
{
LocalVarModifierList()
LocalVariableType()
VariableDeclarator()
( "," VariableDeclarator() )*
}
2020-08-23 22:00:09 +02:00
void LocalVariableDeclarationPendingModifiers() #LocalVariableDeclaration:
{}
{
// no ModifierList, it's pending at this time
LocalVariableType()
VariableDeclarator()
( "," VariableDeclarator() )*
}
private void LocalVarModifierList() #ModifierList:
{Set<JModifier> set = Collections.emptySet(); }
2019-05-28 19:16:04 +02:00
{
( "final" { set = ASTModifierList.JUST_FINAL; } | Annotation() )*
{jjtThis.setDeclaredModifiers(set);}
2019-05-28 19:16:04 +02:00
}
void LocalVariableType() #void:
{}
{
LOOKAHEAD( { jdkVersion >= 10 && isKeyword("var") } ) <IDENTIFIER>
| Type()
}
void EmptyStatement() :
{}
{
";"
}
void EmptyDeclaration() :
{}
{
";"
}
void ExpressionStatement():
{}
{
StatementExpression() ";"
}
void StatementExpression() #void:
2019-02-19 00:15:26 +01:00
{AssignmentOp op = null;}
{
PrefixIncrementExpression()
|
// 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-12-14 18:02:49 +01:00
void SwitchBlock() #void:
2019-03-15 15:29:16 +01:00
{}
{
"{"
(
2019-12-14 18:02:49 +01:00
LOOKAHEAD(SwitchLabel() ":") (SwitchFallthroughBranch())+
| (SwitchArrowBranch())*
)
"}"
2019-03-15 15:29:16 +01:00
}
2019-12-14 18:02:49 +01:00
void SwitchArrowBranch():
2019-09-25 06:30:17 +02:00
{}
{
2019-12-14 18:02:49 +01:00
SwitchLabel() "->" (Expression() ";" | Block() | ThrowStatement())
}
2019-12-14 18:02:49 +01:00
void SwitchFallthroughBranch():
{}
{
2019-12-14 18:02:49 +01:00
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; }
(
"case" CaseLabelElement(jjtThis) ( "," CaseLabelElement(jjtThis) )*
|
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 CaseLabelElement(ASTSwitchLabel label) #void:
{}
{
"null" #NullLiteral [ "," "default" {label.setDefault();} ]
|
LOOKAHEAD(Pattern()) CasePattern() [ LOOKAHEAD({isKeyword("when")}) Guard() ]
|
CaseConstant()
}
void CaseConstant() #void:
{}
{
2021-07-22 19:31:45 +02:00
ConditionalExpression()
}
void CasePattern() #void:
{}
{
Pattern()
}
void Guard() :
2023-03-19 22:49:45 +01:00
{}
{
2023-03-19 22:49:45 +01:00
softKeyword("when")
Expression()
}
void YieldStatement() :
2019-09-25 06:30:17 +02:00
{ }
{
<IDENTIFIER> Expression() ";"
}
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() #void:
2020-04-08 21:06:19 +02:00
{JavaccToken t;}
{
t="for" "("
(
LOOKAHEAD(EnhancedForDeclaration() ":")
2023-02-04 19:10:37 +01:00
(EnhancedForDeclaration() ":" Expression() ")" Statement() { jjtThis.setFirstToken(t); }) #ForeachStatement
| (
[ ForInit() ] ";"
[ Expression() ] ";"
[ ForUpdate() ]
")" Statement()
2020-05-02 20:54:41 +02:00
{ jjtThis.setFirstToken(t); }
) #ForStatement
)
}
void EnhancedForDeclaration() #void:
2023-02-04 19:10:37 +01:00
{}
{
LocalVariableDeclaration()
}
void ForInit() :
{}
{
LOOKAHEAD( LocalVariableDeclaration() )
LocalVariableDeclaration()
|
StatementExpressionList()
}
void StatementExpressionList() :
{}
{
StatementExpression() ( "," StatementExpression() )*
}
void ForUpdate() :
{}
{
StatementExpressionList()
}
void BreakStatement() :
2020-02-07 23:43:26 +01:00
{}
{
2020-03-02 21:05:21 +01:00
"break" [ <IDENTIFIER> { setLastTokenImage(jjtThis); } ] ";"
}
void ContinueStatement() :
2020-02-07 23:43:26 +01:00
{}
{
2020-03-02 21:05:21 +01:00
"continue" [ <IDENTIFIER> { setLastTokenImage(jjtThis); } ] ";"
}
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" (ResourceList())?
Block()
( CatchClause() )*
[ FinallyClause() ]
}
void ResourceList():
{}
{
"("
Resource() (LOOKAHEAD(2) ";" Resource())*
(";" {jjtThis.setTrailingSemi();})?
")"
}
void Resource() :
{}
{
2019-03-21 20:47:23 +01:00
LOOKAHEAD(("final" | Annotation())* LocalVariableType() VariableDeclaratorId() "=" )
(
LocalVarModifierList()
LocalVariableType() VariableDeclarator()
) #LocalVariableDeclaration
|
2019-09-25 06:30:17 +02:00
PrimaryExpression()
2019-09-25 07:37:31 +02:00
{
Node top = jjtree.peekNode();
if (!(top instanceof ASTVariableAccess || top instanceof ASTFieldAccess || top instanceof ASTThisExpression))
throwParseException("Expected a variable or field access, but was a " + top.getXPathNodeName());
2019-09-25 07:37:31 +02:00
}
{}
}
void CatchClause() :
{}
{
"catch"
"(" CatchParameter() ")"
Block()
}
2020-01-07 22:24:32 +01:00
void CatchParameter():
{boolean multi=false;}
{
LocalVarModifierList()
2020-01-07 22:24:32 +01:00
( AnnotatedClassOrInterfaceType() ( "|" AnnotatedClassOrInterfaceType() {multi=true;} )* ) #UnionType(multi)
VariableDeclaratorId()
}
void FinallyClause() :
{}
{
"finally" Block()
}
void AssertStatement() :
2019-09-25 06:57:09 +02:00
{}
{
<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:
{}
{
2022-03-07 22:00:14 +01:00
LOOKAHEAD({ JavaTokenDocumentBehavior.getRealKind(getToken(1)) == RUNSIGNEDSHIFT})
">" ">" ">"
}
2019-03-26 20:43:31 +01:00
void RSIGNEDSHIFT() #void:
{}
{
2022-03-07 22:00:14 +01:00
LOOKAHEAD({ JavaTokenDocumentBehavior.getRealKind(getToken(1)) == RSIGNEDSHIFT})
">" ">"
}
/* Annotation syntax follows. */
2020-01-25 01:30:26 +01:00
void Annotation():
{}
{
2020-07-24 22:23:33 +02:00
"@" ClassName() [ AnnotationMemberList() ]
}
2020-01-25 01:30:26 +01:00
void AnnotationMemberList():
{}
{
2020-01-25 01:30:26 +01:00
"("
( LOOKAHEAD(<IDENTIFIER> "=")
MemberValuePair() ( "," MemberValuePair() )*
| [ ShorthandAnnotationValue() ]
)
")"
}
2020-01-25 01:30:26 +01:00
void ShorthandAnnotationValue() #MemberValuePair:
{
2020-01-25 01:30:26 +01:00
jjtThis.setImage("value");
jjtThis.setShorthand();
}
{
2020-01-25 01:30:26 +01:00
MemberValue()
}
void MemberValuePair():
2020-02-07 23:43:26 +01:00
{}
{
2020-02-07 23:43:26 +01:00
<IDENTIFIER> { setLastTokenImage(jjtThis); } "=" MemberValue()
}
2019-03-21 15:07:55 +01:00
void MemberValue() #void:
{}
{
Annotation()
2020-01-25 01:30:26 +01:00
| MemberValueArrayInitializer()
| ConditionalExpression() // Constant expression
}
void MemberValueArrayInitializer():
{}
{
"{"
(MemberValue() ( LOOKAHEAD(2) "," MemberValue() )*)? [ "," ]
"}"
}
/*
* We use that ghost production to factorise the check for JDK >= 1.8.
*/
void TypeAnnotation() #void:
{}
{
2019-09-25 06:30:17 +02:00
Annotation()
}
/* Annotation Types. */
void AnnotationTypeDeclaration():
{}
{
"@" "interface" <IDENTIFIER> { jjtThis.setSimpleName(getToken(0).getImage()); }
AnnotationTypeBody()
}
void AnnotationTypeBody():
{}
{
"{"
( AnnotationTypeMemberDeclaration() )*
"}"
}
void AnnotationTypeMemberDeclaration() #void:
{}
{
ModifierList()
(
LOOKAHEAD(Type() <IDENTIFIER> "(") AnnotationMethodDeclaration()
|
ClassOrInterfaceDeclaration()
|
LOOKAHEAD(3) EnumDeclaration()
|
AnnotationTypeDeclaration()
|
FieldDeclaration()
)
|
2019-05-28 19:16:04 +02:00
";" #EmptyDeclaration
}
void AnnotationMethodDeclaration() #MethodDeclaration:
{}
{
Type()
<IDENTIFIER> { jjtThis.setName(getToken(0).getImage()); }
2020-04-08 21:06:19 +02:00
("(" ")") #FormalParameters
2020-01-16 03:21:09 +01:00
[ Dims() ]
[ DefaultValue() ] ";"
}
void DefaultValue():
{}
{
"default" MemberValue()
}
void ModuleDeclaration():
{}
{
AnnotationList()
[LOOKAHEAD({isKeyword("open")}) <IDENTIFIER> {jjtThis.setOpen(true);}]
LOOKAHEAD({isKeyword("module")}) <IDENTIFIER>
ModuleName()
"{"
(ModuleDirective())*
"}"
}
void ModuleDirective() #void:
{String packageName;}
{
( LOOKAHEAD({isKeyword("requires")}) <IDENTIFIER>
[
LOOKAHEAD({isKeyword("transitive")}) <IDENTIFIER> { jjtThis.setTransitive(); }
| "static" { jjtThis.setStatic(); }
]
ModuleName() ";" ) #ModuleRequiresDirective
| ( LOOKAHEAD({isKeyword("exports")}) <IDENTIFIER> packageName=VoidNameNoLookahead() {jjtThis.setPackageName(packageName);} [ LOOKAHEAD({isKeyword("to")}) <IDENTIFIER> ModuleName() ("," ModuleName())* ] ";" ) #ModuleExportsDirective
| ( LOOKAHEAD({isKeyword("opens")}) <IDENTIFIER> packageName=VoidNameNoLookahead() {jjtThis.setPackageName(packageName);} [ LOOKAHEAD({isKeyword("to")}) <IDENTIFIER> ModuleName() ("," ModuleName())* ] ";" ) #ModuleOpensDirective
| ( LOOKAHEAD({isKeyword("uses")}) <IDENTIFIER> ClassName() ";" ) #ModuleUsesDirective
| ( LOOKAHEAD({isKeyword("provides")}) <IDENTIFIER> ClassName() LOOKAHEAD({isKeyword("with")}) <IDENTIFIER> ClassName() ("," ClassName() )* ";" ) #ModuleProvidesDirective
}
void ModuleName():
2020-04-08 21:06:19 +02:00
{ String name; }
{
name=VoidNameNoLookahead() { jjtThis.setName(name); }
2019-02-17 10:28:12 +01:00
}
2019-02-18 17:55:41 +01:00
void AmbiguousName():
2020-04-08 21:06:19 +02:00
{ String name; }
2019-02-18 17:55:41 +01:00
{
2020-04-08 21:06:19 +02:00
name=VoidName() { jjtThis.setImage(name); }
2019-02-18 17:55:41 +01:00
}
2019-02-17 10:28:12 +01:00
String VoidName() #void:
/*
* A lookahead of 2 is required below since "Name" can be followed
2019-06-26 18:28:58 +02:00
* by a ".*" when used in the context of an "ImportDeclaration",
2020-04-08 21:06:19 +02:00
* or with "this" or "super" in PrimaryPrefix (AmbiguousName).
2019-02-17 10:28:12 +01:00
*/
{
StringBuilder s = new StringBuilder();
JavaccToken t;
2019-02-17 10:28:12 +01:00
}
{
2020-01-25 01:30:26 +01:00
t=<IDENTIFIER> { s.append(t.getImage()); }
2020-04-08 21:06:19 +02:00
( LOOKAHEAD(2) "." t=<IDENTIFIER> { s.append('.').append(t.getImage()); }
2019-02-17 10:28:12 +01:00
)*
{return s.toString();}
}
2019-02-18 16:59:23 +01:00
String VoidNameNoLookahead() #void:
{
StringBuilder s = new StringBuilder();
JavaccToken t;
}
{
t=<IDENTIFIER> { s.append(t.getImage()); }
( "." t=<IDENTIFIER> { s.append('.').append(t.getImage()); } )*
{return s.toString();}
}
2020-07-24 22:23:33 +02:00
// Produces a ClassOrInterfaceType, possibly with an ambiguous LHS
void ClassName() #void:
{}
{
AmbiguousName() { forceTypeContext(); }
}
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
//noinspection UnusedProduction
2020-03-02 21:05:21 +01:00
void VariableAccess(): {} { <IDENTIFIER> }
// those are created manually
void TypeExpression(): {} { <IDENTIFIER> }
void PatternExpression(): {} { <IDENTIFIER> }
void LocalClassStatement(): {} { TypeDeclaration() }
2023-03-19 22:49:45 +01:00
void softKeyword(String name) #void: {} {
<IDENTIFIER> {
if (!getToken(0).getImageCs().contentEquals(name))
throwParseException("Expecting keyword '" + name + "'");
}
}