📄 groovy.g
字号:
// Query a name token to see if it is identical with the current class name.
// This is used to distinguish constructors from other methods.
private boolean isConstructorIdent(Token x) {
if (currentClass == null) return false;
if (currentClass.getType() != IDENT) return false; // cannot happen?
String cname = currentClass.getText();
if (x == null || x.getType() != IDENT) return false; // cannot happen?
return cname.equals(x.getText());
}
// Scratch variable for last 'sep' token.
// Written by the 'sep' rule, read only by immediate callers of 'sep'.
// (Not entirely clean, but better than a million xx=sep occurrences.)
private int sepToken = EOF;
// Scratch variable for last argument list; tells whether there was a label.
// Written by 'argList' rule, read only by immediate callers of 'argList'.
private boolean argListHasLabels = false;
// Scratch variable, holds most recently completed pathExpression.
// Read only by immediate callers of 'pathExpression' and 'expression'.
private AST lastPathExpression = null;
// Inherited attribute pushed into most expression rules.
// If not zero, it means that the left context of the expression
// being parsed is a statement boundary or an initializer sign '='.
// Only such expressions are allowed to reach across newlines
// to pull in an LCURLY and appended block.
private final int LC_STMT = 1, LC_INIT = 2;
/**
* Counts the number of LT seen in the typeArguments production.
* It is used in semantic predicates to ensure we have seen
* enough closing '>' characters; which actually may have been
* either GT, SR or BSR tokens.
*/
private int ltCounter = 0;
/* This symbol is used to work around a known ANTLR limitation.
* In a loop with syntactic predicate, ANTLR needs help knowing
* that the loop exit is a second alternative.
* Example usage: ( (LCURLY)=> block | {ANTLR_LOOP_EXIT}? )*
* Probably should be an ANTLR RFE.
*/
////// Original comment in Java grammar:
// Unfortunately a syntactic predicate can only select one of
// multiple alternatives on the same level, not break out of
// an enclosing loop, which is why this ugly hack (a fake
// empty alternative with always-false semantic predicate)
// is necessary.
private static final boolean ANTLR_LOOP_EXIT = false;
}
// Compilation Unit: In Groovy, this is a single file or script. This is the start
// rule for this parser
compilationUnit
:
// The very first characters of the file may be "#!". If so, ignore the first line.
(SH_COMMENT!)?
// we can have comments at the top of a file
nls!
// A compilation unit starts with an optional package definition
( (annotationsOpt "package")=> packageDefinition
| (statement[EOF])?
)
// The main part of the script is a sequence of any number of statements.
// Semicolons and/or significant newlines serve as separators.
( sep! (statement[sepToken])? )*
EOF!
;
/** A Groovy script or simple expression. Can be anything legal inside {...}. */
snippetUnit
: nls! blockBody[EOF]
;
// Package statement: optional annotations followed by "package" then the package identifier.
packageDefinition
//TODO? options {defaultErrorHandler = true;} // let ANTLR handle errors
: annotationsOpt p:"package"^ {#p.setType(PACKAGE_DEF);} identifier
;
// Import statement: import followed by a package or class name
importStatement
//TODO? options {defaultErrorHandler = true;}
{ boolean isStatic = false; }
: i:"import"^ {#i.setType(IMPORT);} ( "static"! {#i.setType(STATIC_IMPORT);} )? identifierStar
;
// TODO REMOVE
// A type definition is either a class, interface, enum or annotation with possible additional semis.
//typeDefinition
// options {defaultErrorHandler = true;}
// : m:modifiers!
// typeDefinitionInternal[#m]
// | SEMI!
// ;
// Added this production, even though 'typeDefinition' seems to be obsolete,
// as this is referenced by many other parts of the grammar.
// Protected type definitions production for reuse in other productions
protected typeDefinitionInternal[AST mods]
: cd:classDefinition[#mods] // inner class
{#typeDefinitionInternal = #cd;}
| id:interfaceDefinition[#mods] // inner interface
{#typeDefinitionInternal = #id;}
| ed:enumDefinition[#mods] // inner enum
{#typeDefinitionInternal = #ed;}
| ad:annotationDefinition[#mods] // inner annotation
{#typeDefinitionInternal = #ad;}
;
/** A declaration is the creation of a reference or primitive-type variable,
* or (if arguments are present) of a method.
* Generically, this is called a 'variable' definition, even in the case of a class field or method.
* It may start with the modifiers and/or a declaration keyword "def".
* It may also start with the modifiers and a capitalized type name.
* <p>
* AST effect: Create a separate Type/Var tree for each var in the var list.
* Must be guarded, as in (declarationStart) => declaration.
*/
declaration!
:
// method/variable using a 'def' or a modifier; type is optional
m:modifiers
(t:typeSpec[false])?
v:variableDefinitions[#m, #t]
{#declaration = #v;}
|
// method/variable using a type only
t2:typeSpec[false]
v2:variableDefinitions[null,#t2]
{#declaration = #v2;}
;
// *TODO* We must also audit the various occurrences of warning
// suppressions like "options { greedy = true; }".
/** A declaration with one declarator and no initialization, like a parameterDeclaration.
* Used to parse loops like <code>for (int x in y)</code> (up to the <code>in</code> keyword).
*/
singleDeclarationNoInit!
:
// method/variable using a 'def' or a modifier; type is optional
m:modifiers
(t:typeSpec[false])?
v:singleVariable[#m, #t]
{#singleDeclarationNoInit = #v;}
|
// method/variable using a type only
t2:typeSpec[false]
v2:singleVariable[null,#t2]
{#singleDeclarationNoInit = #v2;}
;
/** A declaration with one declarator and optional initialization, like a parameterDeclaration.
* Used to parse declarations used for both binding and effect, in places like argument
* lists and <code>while</code> statements.
*/
singleDeclaration
: sd:singleDeclarationNoInit!
{ #singleDeclaration = #sd; }
(varInitializer)?
;
/** Used only as a lookahead predicate, before diving in and parsing a declaration.
* A declaration can be unambiguously introduced with "def", an annotation or a modifier token like "final".
* It may also be introduced by a simple identifier whose first character is an uppercase letter,
* as in {String x}. A declaration can also be introduced with a built in type like 'int' or 'void'.
* Brackets (array and generic) are allowed, as in {List[] x} or {int[][] y}.
* Anything else is parsed as a statement of some sort (expression or command).
* <p>
* (In the absence of explicit method-call parens, we assume a capitalized name is a type name.
* Yes, this is a little hacky. Alternatives are to complicate the declaration or command
* syntaxes, or to have the parser query the symbol table. Parse-time queries are evil.
* And we want both {String x} and {println x}. So we need a syntactic razor-edge to slip
* between 'println' and 'String'.)
*
* *TODO* The declarationStart production needs to be strengthened to recognize
* things like {List<String> foo}.
* Right now it only knows how to skip square brackets after the type, not
* angle brackets.
* This probably turns out to be tricky because of >> vs. > >. If so,
* just put a TODO comment in.
*/
declarationStart!
: "def"
| modifier
| AT IDENT // IDENT != "interface"
| ( upperCaseIdent
| builtInType
| qualifiedTypeName
) (LBRACK balancedTokens RBRACK)* IDENT
;
/** Not yet used - but we could use something like this to look for fully qualified type names
*/
qualifiedTypeName!
:
IDENT (DOT IDENT)* DOT upperCaseIdent
;
/** Used to look ahead for a constructor
*/
constructorStart!
:
modifiersOpt! id:IDENT! {isConstructorIdent(id)}? nls! LPAREN! //...
;
/** Used only as a lookahead predicate for nested type declarations. */
/*TODO* The lookahead in typeDeclarationStart needs to skip annotations, not
just stop at '@', because variable and method declarations can also be
annotated.
> typeDeclarationStart!
> : (modifier!)* ("class" | "interface" | "enum" | AT )
S.B. something like
> : (modifier! | annotationTokens!)* ("class" | "interface" |
> "enum" )
(And maybe @interface, if Java 5 allows nested annotation types? Don't
know offhand.)
Where annotationTokens can be a quick paren-skipper, as in other
places: '@' ident '(' balancedTokens ')'.
*/
typeDeclarationStart!
: modifiersOpt! ("class" | "interface" | "enum" | AT "interface")
;
/** An IDENT token whose spelling is required to start with an uppercase letter.
* In the case of a simple statement {UpperID name} the identifier is taken to be a type name, not a command name.
*/
upperCaseIdent
: {isUpperCase(LT(1))}?
IDENT
;
// A type specification is a type name with possible brackets afterwards
// (which would make it an array type).
// Set addImagNode true for types inside expressions, not declarations.
typeSpec[boolean addImagNode]
: classTypeSpec[addImagNode]
| builtInTypeSpec[addImagNode]
;
// also check that 'classOrInterfaceType[false]' is a suitable substitution for 'identifier'
// A class type specification is a class type with either:
// - possible brackets afterwards
// (which would make it an array type).
// - generic type arguments after
classTypeSpec[boolean addImagNode] {Token first = LT(1);}
: ct:classOrInterfaceType[false]!
declaratorBrackets[#ct]
{
if ( addImagNode ) {
#classTypeSpec = #(create(TYPE,"TYPE",first,LT(1)), #classTypeSpec);
}
}
;
// A non-built in type name, with possible type parameters
classOrInterfaceType[boolean addImagNode] {Token first = LT(1);}
: IDENT^ (typeArguments)?
( options{greedy=true;}: // match as many as possible
DOT^
IDENT (typeArguments)?
)*
{
if ( addImagNode ) {
#classOrInterfaceType = #(create(TYPE,"TYPE",first,LT(1)), #classOrInterfaceType);
}
}
;
// A specialised form of typeSpec where built in types must be arrays
typeArgumentSpec
: classTypeSpec[true]
| builtInTypeArraySpec[true]
;
// A generic type argument is a class type, a possibly bounded wildcard type or a built-in type array
typeArgument {Token first = LT(1);}
: ( typeArgumentSpec
| wildcardType
)
{#typeArgument = #(create(TYPE_ARGUMENT,"TYPE_ARGUMENT",first,LT(1)), #typeArgument);}
;
// Wildcard type indicating all types (with possible constraint)
wildcardType
: q:QUESTION^ {#q.setType(WILDCARD_TYPE);}
(("extends" | "super")=> typeArgumentBounds)?
;
// Type arguments to a class or interface type
typeArguments
{Token first = LT(1);
int currentLtLevel = 0;}
:
{currentLtLevel = ltCounter;}
LT! {ltCounter++;} nls!
typeArgument
( options{greedy=true;}: // match as many as possible
{inputState.guessing !=0 || ltCounter == currentLtLevel + 1}?
COMMA! nls! typeArgument
)*
nls!
( // turn warning off since Antlr generates the right code,
// plus we have our semantic predicate below
options{generateAmbigWarnings=false;}:
typeArgumentsOrParametersEnd
)?
// make sure we have gobbled up enough '>' characters
// if we are at the "top level" of nested typeArgument productions
{(currentLtLevel != 0) || ltCounter == currentLtLevel}?
{#typeArguments = #(create(TYPE_ARGUMENTS, "TYPE_ARGUMENTS",first,LT(1)), #typeArguments);}
;
// this gobbles up *some* amount of '>' characters, and counts how many
// it gobbled.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -