blob: fd186b9645f16cf7f9ecab16059ec123748b5434 [file] [log] [blame]
Grammar GroovyRecognizer
ANTLR-generated HTML file from /Users/j6wbs/projects/groovy/groovy.head/groovy/trunk/groovy/jsr/ideas/parsers/antlr/src/org/codehaus/groovy/antlr/groovy.g
Terence Parr, MageLang Institute
ANTLR Version 2.7.5 (20050128); 1989-2005
/** JSR-241 Groovy Recognizer
*
* Run 'java Main [-showtree] directory-full-of-groovy-files'
*
* [The -showtree option pops up a Swing frame that shows
* the AST constructed from the parser.]
*
* Contributing authors:
* John Mitchell johnm@non.net
* Terence Parr parrt@magelang.com
* John Lilley jlilley@empathy.com
* Scott Stanchfield thetick@magelang.com
* Markus Mohnen mohnen@informatik.rwth-aachen.de
* Peter Williams pete.williams@sun.com
* Allan Jacobs Allan.Jacobs@eng.sun.com
* Steve Messick messick@redhills.com
* James Strachan jstrachan@protique.com
* John Pybus john@pybus.org
* John Rose rose00@mac.com
* Jeremy Rayner groovy@ross-rayner.com
*
* Version 1.00 December 9, 1997 -- initial release
* Version 1.01 December 10, 1997
* fixed bug in octal def (0..7 not 0..8)
* Version 1.10 August 1998 (parrt)
* added tree construction
* fixed definition of WS,comments for mac,pc,unix newlines
* added unary plus
* Version 1.11 (Nov 20, 1998)
* Added "shutup" option to turn off last ambig warning.
* Fixed inner class def to allow named class defs as statements
* synchronized requires compound not simple statement
* add [] after builtInType DOT class in primaryExpression
* "const" is reserved but not valid..removed from modifiers
* Version 1.12 (Feb 2, 1999)
* Changed LITERAL_xxx to xxx in tree grammar.
* Updated java.g to use tokens {...} now for 2.6.0 (new feature).
*
* Version 1.13 (Apr 23, 1999)
* Didn't have (stat)? for else clause in tree parser.
* Didn't gen ASTs for interface extends. Updated tree parser too.
* Updated to 2.6.0.
* Version 1.14 (Jun 20, 1999)
* Allowed final/abstract on local classes.
* Removed local interfaces from methods
* Put instanceof precedence where it belongs...in relationalExpr
* It also had expr not type as arg; fixed it.
* Missing ! on SEMI in classBlock
* fixed: (expr) + "string" was parsed incorrectly (+ as unary plus).
* fixed: didn't like Object[].class in parser or tree parser
* Version 1.15 (Jun 26, 1999)
* Screwed up rule with instanceof in it. :( Fixed.
* Tree parser didn't like (expr).something; fixed.
* Allowed multiple inheritance in tree grammar. oops.
* Version 1.16 (August 22, 1999)
* Extending an interface built a wacky tree: had extra EXTENDS.
* Tree grammar didn't allow multiple superinterfaces.
* Tree grammar didn't allow empty var initializer: {}
* Version 1.17 (October 12, 1999)
* ESC lexer rule allowed 399 max not 377 max.
* java.tree.g didn't handle the expression of synchronized
* statements.
* Version 1.18 (August 12, 2001)
* Terence updated to Java 2 Version 1.3 by
* observing/combining work of Allan Jacobs and Steve
* Messick. Handles 1.3 src. Summary:
* o primary didn't include boolean.class kind of thing
* o constructor calls parsed explicitly now:
* see explicitConstructorInvocation
* o add strictfp modifier
* o missing objBlock after new expression in tree grammar
* o merged local class definition alternatives, moved after declaration
* o fixed problem with ClassName.super.field
* o reordered some alternatives to make things more efficient
* o long and double constants were not differentiated from int/float
* o whitespace rule was inefficient: matched only one char
* o add an examples directory with some nasty 1.3 cases
* o made Main.java use buffered IO and a Reader for Unicode support
* o supports UNICODE?
* Using Unicode charVocabulay makes code file big, but only
* in the bitsets at the end. I need to make ANTLR generate
* unicode bitsets more efficiently.
* Version 1.19 (April 25, 2002)
* Terence added in nice fixes by John Pybus concerning floating
* constants and problems with super() calls. John did a nice
* reorg of the primary/postfix expression stuff to read better
* and makes f.g.super() parse properly (it was METHOD_CALL not
* a SUPER_CTOR_CALL). Also:
*
* o "finally" clause was a root...made it a child of "try"
* o Added stuff for asserts too for Java 1.4, but *commented out*
* as it is not backward compatible.
*
* Version 1.20 (October 27, 2002)
*
* Terence ended up reorging John Pybus' stuff to
* remove some nondeterminisms and some syntactic predicates.
* Note that the grammar is stricter now; e.g., this(...) must
* be the first statement.
*
* Trinary ?: operator wasn't working as array name:
* (isBig ? bigDigits : digits)[i];
*
* Checked parser/tree parser on source for
* Resin-2.0.5, jive-2.1.1, jdk 1.3.1, Lucene, antlr 2.7.2a4,
* and the 110k-line jGuru server source.
*
* Version 1.21 (October 17, 2003)
* Fixed lots of problems including:
* Ray Waldin: add typeDefinition to interfaceBlock in java.tree.g
* He found a problem/fix with floating point that start with 0
* Ray also fixed problem that (int.class) was not recognized.
* Thorsten van Ellen noticed that \n are allowed incorrectly in strings.
* TJP fixed CHAR_LITERAL analogously.
*
* Version 1.21.2 (March, 2003)
* Changes by Matt Quail to support generics (as per JDK1.5/JSR14)
* Notes:
* o We only allow the "extends" keyword and not the "implements"
* keyword, since thats what JSR14 seems to imply.
* o Thanks to Monty Zukowski for his help on the antlr-interest
* mail list.
* o Thanks to Alan Eliasen for testing the grammar over his
* Fink source base
*
* Version 1.22 (July, 2004)
* Changes by Michael Studman to support Java 1.5 language extensions
* Notes:
* o Added support for annotations types
* o Finished off Matt Quail's generics enhancements to support bound type arguments
* o Added support for new for statement syntax
* o Added support for static import syntax
* o Added support for enum types
* o Tested against JDK 1.5 source base and source base of jdigraph project
* o Thanks to Matt Quail for doing the hard part by doing most of the generics work
*
* Version 1.22.1 (July 28, 2004)
* Bug/omission fixes for Java 1.5 language support
* o Fixed tree structure bug with classOrInterface - thanks to Pieter Vangorpto for
* spotting this
* o Fixed bug where incorrect handling of SR and BSR tokens would cause type
* parameters to be recognised as type arguments.
* o Enabled type parameters on constructors, annotations on enum constants
* and package definitions
* o Fixed problems when parsing if ((char.class.equals(c))) {} - solution by Matt Quail at Cenqua
*
* Version 1.22.2 (July 28, 2004)
* Slight refactoring of Java 1.5 language support
* o Refactored for/"foreach" productions so that original literal "for" literal
* is still used but the for sub-clauses vary by token type
* o Fixed bug where type parameter was not included in generic constructor's branch of AST
*
* Version 1.22.3 (August 26, 2004)
* Bug fixes as identified by Michael Stahl; clean up of tabs/spaces
* and other refactorings
* o Fixed typeParameters omission in identPrimary and newStatement
* o Replaced GT reconcilliation code with simple semantic predicate
* o Adapted enum/assert keyword checking support from Michael Stahl's java15 grammar
* o Refactored typeDefinition production and field productions to reduce duplication
*
* Version 1.22.4 (October 21, 2004)
* Small bux fixes
* o Added typeArguments to explicitConstructorInvocation, e.g. new <String>MyParameterised()
* o Added typeArguments to postfixExpression productions for anonymous inner class super
* constructor invocation, e.g. new Outer().<String>super()
* o Fixed bug in array declarations identified by Geoff Roy
*
* Version 1.22.4.g.1
* o I have taken java.g for Java1.5 from Michael Studman (1.22.4)
* and have applied the groovy.diff from java.g (1.22) by John Rose
* back onto the new root (1.22.4) - Jeremy Rayner (Jan 2005)
* o for a map of the task see...
* http://groovy.javanicus.com/java-g.png
*
* This grammar is in the PUBLIC DOMAIN
*/
Definition of parser GroovyRecognizer, which is a subclass of LLkParser.
compilationUnit
: ( SH_COMMENT
|
)
nls
( packageDefinition
| ( statement
|
)
)
( sep
( statement
|
) )* EOF
;
/** Zero or more insignificant newlines, all gobbled up and thrown away. */
nls
: ( NLS
|
)
;
annotationsOpt
: ( annotation nls )*
;
packageDefinition
: annotationsOpt "package" identifier
;
/** A statement is an element of a block.
* Typical statements are declarations (which are scoped to the block)
* and expressions.
*/
statement
: declaration
| statementLabelPrefix
( openOrClosableBlock
| statement
)
| expressionStatement
| modifiersOpt typeDefinitionInternal
| "if" LPAREN assignmentLessExpression RPAREN nlsWarn compatibleBodyStatement
( ( sep
|
)
"else" nlsWarn compatibleBodyStatement
|
)
| forStatement
| "while" LPAREN strictContextExpression RPAREN nlsWarn compatibleBodyStatement
| "with" LPAREN strictContextExpression RPAREN nlsWarn compoundStatement
| STAR nls expressionStatement
| importStatement
| "switch" LPAREN strictContextExpression RPAREN nlsWarn LCURLY nls ( casesGroup )* RCURLY
| tryBlock
| "synchronized" LPAREN strictContextExpression RPAREN nlsWarn compoundStatement
| branchStatement
;
/** A statement separator is either a semicolon or a significant newline.
* Any number of additional (insignificant) newlines may accompany it.
*/
sep
: SEMI ( NLS )*
| NLS ( SEMI ( NLS )* )*
;
/** A Groovy script or simple expression. Can be anything legal inside {...}. */
snippetUnit
: nls blockBody
;
/** A block body is a parade of zero or more statements or expressions. */
blockBody
: ( statement
|
)
( sep
( statement
|
) )*
;
identifier
: IDENT ( DOT nls IDENT )*
;
importStatement
: "import"
( "static"
|
)
identifierStar
;
identifierStar
: IDENT ( DOT nls IDENT )*
( DOT nls STAR
| "as" nls IDENT
|
)
;
protected typeDefinitionInternal
: classDefinition
| interfaceDefinition
| enumDefinition
| annotationDefinition
;
classDefinition
: "class" IDENT nls
( typeParameters
|
)
superClassClause implementsClause classBlock
;
interfaceDefinition
: "interface" IDENT nls
( typeParameters
|
)
interfaceExtends interfaceBlock
;
enumDefinition
: "enum" IDENT implementsClause enumBlock
;
annotationDefinition
: AT "interface" IDENT annotationBlock
;
/** 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
: modifiers
( typeSpec
|
)
variableDefinitions
| typeSpec variableDefinitions
;
/** A list of one or more modifier, annotation, or "def". */
modifiers
: modifiersInternal
;
typeSpec
: classTypeSpec
| builtInTypeSpec
;
/** The tail of a declaration.
* Either v1, v2, ... (with possible initializers) or else m(args){body}.
* The two arguments are the modifier list (if any) and the declaration head (if any).
* The declaration head is the variable type, or (for a method) the return type.
* If it is missing, then the variable type is taken from its initializer (if there is one).
* Otherwise, the variable type defaults to 'any'.
* DECIDE: Method return types default to the type of the method body, as an expression.
*/
variableDefinitions
: variableDeclarator ( COMMA nls variableDeclarator )*
| ( IDENT
| STRING_LITERAL
)
LPAREN parameterDeclarationList RPAREN
( throwsClause
|
)
( ( nlsWarn openBlock )
|
)
;
/** 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
: modifiers
( typeSpec
|
)
singleVariable
| typeSpec singleVariable
;
/** Used in cases where a declaration cannot have commas, or ends with the "in" operator instead of '='. */
singleVariable
: variableName
;
/** 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
: singleDeclarationNoInit
( varInitializer
|
)
;
/** An assignment operator '=' followed by an expression. (Never empty.) */
varInitializer
: ASSIGN nls expression
;
/** 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
| ( upperCaseIdent
| builtInType
| qualifiedTypeName
)
( LBRACK balancedTokens RBRACK )* IDENT
;
modifier
: "private"
| "public"
| "protected"
| "static"
| "transient"
| "final"
| "abstract"
| "native"
| "threadsafe"
| "synchronized"
| "volatile"
| "strictfp"
;
/** 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
: IDENT
;
builtInType
: "void"
| "boolean"
| "byte"
| "char"
| "short"
| "int"
| "float"
| "long"
| "double"
| "any"
;
/** Not yet used - but we could use something like this to look for fully qualified type names
*/
qualifiedTypeName
: IDENT ( DOT IDENT )* DOT upperCaseIdent
;
balancedTokens
: ( balancedBrackets
| ( LPAREN
| LBRACK
| LCURLY
| STRING_CTOR_START
| RPAREN
| RBRACK
| RCURLY
| STRING_CTOR_END
)
)*
;
/** Used to look ahead for a constructor
*/
constructorStart
: modifiersOpt IDENT nls LPAREN
;
/** A list of zero or more modifiers, annotations, or "def". */
modifiersOpt
: ( modifiersInternal
|
)
;
/** Used only as a lookahead predicate for nested type declarations. */
typeDeclarationStart
: modifiersOpt
( "class"
| "interface"
| "enum"
| AT "interface"
)
;
classTypeSpec
: classOrInterfaceType declaratorBrackets
;
builtInTypeSpec
: builtInType declaratorBrackets
;
classOrInterfaceType
: IDENT
( typeArguments
|
)
( DOT IDENT
( typeArguments
|
) )*
;
/** After some type names, where zero or more empty bracket pairs are allowed.
* We use ARRAY_DECLARATOR to represent this.
* TODO: Is there some more Groovy way to view this in terms of the indexed property syntax?
*/
declaratorBrackets
: ( LBRACK RBRACK )*
;
typeArguments
: LT nls typeArgument ( COMMA nls typeArgument )* nls
( typeArgumentsOrParametersEnd
|
)
;
typeArgumentSpec
: classTypeSpec
| builtInTypeArraySpec
;
builtInTypeArraySpec
: builtInType
( declaratorBrackets
|
)
;
typeArgument
: ( typeArgumentSpec
| wildcardType
)
;
wildcardType
: QUESTION
( typeArgumentBounds
|
)
;
typeArgumentBounds
: ( "extends"
| "super"
)
nls classOrInterfaceType nls
;
protected typeArgumentsOrParametersEnd
: GT nls
| SR nls
| BSR nls
;
type
: classOrInterfaceType
| builtInType
;
modifiersInternal
: ( "def" nls
| modifier nls
| annotation nls
)+
;
annotation
: AT identifier
( LPAREN
( annotationArguments
|
)
RPAREN
|
)
;
annotationArguments
: annotationMemberValueInitializer
| anntotationMemberValuePairs
;
annotationMemberValueInitializer
: conditionalExpression
| annotation
;
anntotationMemberValuePairs
: annotationMemberValuePair ( COMMA nls annotationMemberValuePair )*
;
annotationMemberValuePair
: IDENT ASSIGN nls annotationMemberValueInitializer
;
conditionalExpression
: logicalOrExpression
( QUESTION nls assignmentExpression COLON nls conditionalExpression
|
)
;
annotationMemberArrayValueInitializer
: conditionalExpression
| annotation nls
;
superClassClause
: ( "extends" nls classOrInterfaceType nls
|
)
;
typeParameters
: LT nls typeParameter ( COMMA nls typeParameter )* nls
( typeArgumentsOrParametersEnd
|
)
;
implementsClause
: ( "implements" nls classOrInterfaceType ( COMMA nls classOrInterfaceType )* nls
|
)
;
classBlock
: LCURLY
( classField
|
)
( sep
( classField
|
) )* RCURLY
;
interfaceExtends
: ( "extends" nls classOrInterfaceType ( COMMA nls classOrInterfaceType )* nls
|
)
;
interfaceBlock
: LCURLY
( interfaceField
|
)
( sep
( interfaceField
|
) )* RCURLY
;
enumBlock
: LCURLY
( enumConstants
| ( classField
|
)
)
( sep
( classField
|
) )* RCURLY
;
annotationBlock
: LCURLY
( annotationField
|
)
( sep
( annotationField
|
) )* RCURLY
;
typeParameter
: ( IDENT )
( typeParameterBounds
|
)
;
typeParameterBounds
: "extends" nls classOrInterfaceType ( BAND nls classOrInterfaceType )*
;
classField
: modifiersOpt constructorDefinition
| declaration
| modifiersOpt ( typeDefinitionInternal )
| "static" compoundStatement
| compoundStatement
;
interfaceField
: declaration
| modifiersOpt ( typeDefinitionInternal )
;
annotationField
: modifiersOpt
( typeDefinitionInternal
| typeSpec
( IDENT LPAREN RPAREN
( "default" nls annotationMemberValueInitializer
|
)
| variableDefinitions
)
)
;
/** Guard for enumConstants. */
enumConstantsStart
: enumConstant
( COMMA
| SEMI
| NLS
| RCURLY
)
;
/** Comma-separated list of one or more enum constant definitions. */
enumConstants
: enumConstant ( COMMA nls enumConstant )*
( COMMA nls
|
)
;
enumConstant
: annotationsOpt IDENT
( LPAREN argList RPAREN
|
)
( enumConstantBlock
|
)
;
argList
: ( argument ( COMMA argument )*
|
)
( COMMA
|
)
;
enumConstantBlock
: LCURLY
( enumConstantField
|
)
( sep
( enumConstantField
|
) )* RCURLY
;
enumConstantField
: modifiersOpt
( typeDefinitionInternal
| ( typeParameters
|
)
typeSpec
( IDENT LPAREN parameterDeclarationList RPAREN
( throwsClause
|
)
( compoundStatement
|
)
| variableDefinitions
)
)
| compoundStatement
;
/** A list of zero or more formal parameters.
* If a parameter is variable length (e.g. String... myArg) it should be
* to the right of any other parameters of the same kind.
* General form: (req, ..., opt, ..., [rest], key, ..., [restKeys], [block]
* This must be sorted out after parsing, since the various declaration forms
* are impossible to tell apart without backtracking.
*/
parameterDeclarationList
: ( parameterDeclaration ( COMMA nls parameterDeclaration )*
|
)
;
throwsClause
: nls "throws" nls identifier ( COMMA nls identifier )*
;
compoundStatement
: openBlock
;
/** I've split out constructors separately; we could maybe integrate back into variableDefinitions
* later on if we maybe simplified 'def' to be a type declaration?
*/
constructorDefinition
: IDENT LPAREN parameterDeclarationList RPAREN
( throwsClause
|
)
nlsWarn constructorBody
;
constructorBody
: LCURLY nls
( explicitConstructorInvocation
( sep blockBody
|
)
| blockBody
)
RCURLY
;
/** Catch obvious constructor calls, but not the expr.super(...) calls */
explicitConstructorInvocation
: ( typeArguments
|
)
( "this" LPAREN argList RPAREN
| "super" LPAREN argList RPAREN
)
;
/** Declaration of a variable. This can be a class/instance variable,
* or a local variable in a method
* It can also include possible initialization.
*/
variableDeclarator
: variableName
( varInitializer
|
)
;
/** Zero or more insignificant newlines, all gobbled up and thrown away,
* but a warning message is left for the user, if there was a newline.
*/
nlsWarn
: (
|
)
nls
;
/** An open block is not allowed to have closure arguments. */
openBlock
: LCURLY nls blockBody RCURLY
;
variableName
: IDENT
;
expression
: assignmentExpression
;
/** A formal parameter for a method or closure. */
parameterDeclaration
: parameterModifiersOpt
( typeSpec
|
)
( TRIPLE_DOT
|
)
IDENT
( varInitializer
|
)
;
parameterModifiersOpt
: ( "def" nls
| "final" nls
| annotation nls
)*
;
/** Closure parameters are exactly like method parameters,
* except that they are not enclosed in parentheses, but rather
* are prepended to the front of a block, just after the brace.
* They are separated from the closure body by a CLOSABLE_BLOCK_OP token '->'.
*/
closableBlockParamsOpt
: parameterDeclarationList nls CLOSABLE_BLOCK_OP nls
| implicitParameters
|
;
/** A block known to be a closure, but which omits its arguments, is given this placeholder.
* A subsequent pass is responsible for deciding if there is an implicit 'it' parameter,
* or if the parameter list should be empty.
*/
implicitParameters
:
;
/** Lookahead to check whether a block begins with explicit closure arguments. */
closableBlockParamsStart
: parameterDeclarationList nls CLOSABLE_BLOCK_OP
;
/** Simple names, as in {x|...}, are completely equivalent to {(def x)|...}. Build the right AST. */
closableBlockParam
: IDENT
;
/** A block which is known to be a closure, even if it has no apparent arguments.
* A block inside an expression or after a method call is always assumed to be a closure.
* Only labeled, unparameterized blocks which occur directly as substatements are kept open.
*/
closableBlock
: LCURLY nls closableBlockParamsOpt blockBody RCURLY
;
/** A sub-block of a block can be either open or closable.
* It is closable if and only if there are explicit closure arguments.
* Compare this to a block which is appended to a method call,
* which is given closure arguments, even if they are not explicit in the code.
*/
openOrClosableBlock
: LCURLY nls closableBlockParamsOpt blockBody RCURLY
;
/** A labeled statement, consisting of a vanilla identifier followed by a colon. */
statementLabelPrefix
: IDENT COLON nls
;
/** An expression statement can be any general expression.
* <p>
* An expression statement can also be a <em>command</em>,
* which is a simple method call in which the outermost parentheses are omitted.
* <p>
* Certain "suspicious" looking forms are flagged for the user to disambiguate.
*/
expressionStatement
: ( checkSuspiciousExpressionStatement
|
)
expression
( commandArguments
|
)
;
assignmentLessExpression
: ( conditionalExpression )
;
/** In Java, "if", "while", and "for" statements can take random, non-braced statements as their bodies.
* Support this practice, even though it isn't very Groovy.
*/
compatibleBodyStatement
: compoundStatement
| statement
;
forStatement
: "for" LPAREN
( traditionalForClause
| forInClause
)
RPAREN nlsWarn compatibleBodyStatement
;
/** Things that can show up as expressions, but only in strict
* contexts like inside parentheses, argument lists, and list constructors.
*/
strictContextExpression
: ( singleDeclaration
| expression
| branchStatement
| annotation
)
;
casesGroup
: ( aCase )+ caseSList
;
tryBlock
: "try" nlsWarn compoundStatement ( nls handler )*
( nls finallyClause
|
)
;
/** In Groovy, return, break, continue, throw, and assert can be used in a parenthesized expression context.
* Example: println (x || (return)); println assert x, "won't print a false value!"
* If an optional expression is missing, its value is void (this coerces to null when a value is required).
*/
branchStatement
: "return"
( expression
|
)
| ( "break"
| "continue"
)
( statementLabelPrefix
|
)
( expression
|
)
| "throw" expression
| "assert" assignmentLessExpression
( ( COMMA
| COLON
)
expression
|
)
;
forInit
: declaration
| ( controlExpressionList
|
)
;
traditionalForClause
: forInit SEMI forCond SEMI forIter
;
forInClause
: ( singleDeclarationNoInit
| IDENT
)
( "in" shiftExpression
| COLON expression
)
;
forCond
: ( strictContextExpression
|
)
;
forIter
: ( controlExpressionList
|
)
;
shiftExpression
: additiveExpression ( ( ( SL
| SR
| BSR
)
| RANGE_INCLUSIVE
| RANGE_EXCLUSIVE
)
nls additiveExpression )*
;
/** Lookahead for suspicious statement warnings and errors. */
suspiciousExpressionStatementStart
: ( ( PLUS
| MINUS
)
| ( LBRACK
| LPAREN
| LCURLY
)
)
;
/**
* If two statements are separated by newline (not SEMI), the second had
* better not look like the latter half of an expression. If it does, issue a warning.
* <p>
* Also, if the expression starts with a closure, it needs to
* have an explicit parameter list, in order to avoid the appearance of a
* compound statement. This is a hard error.
* <p>
* These rules are different from Java's "dumb expression" restriction.
* Unlike Java, Groovy blocks can end with arbitrary (even dumb) expressions,
* as a consequence of optional 'return' and 'continue' tokens.
* <p>
* To make the programmer's intention clear, a leading closure must have an
* explicit parameter list, and must not follow a previous statement separated
* only by newlines.
*/
checkSuspiciousExpressionStatement
: (
|
)
|
|
;
/** A member name (x.y) or element name (x[y]) can serve as a command name,
* which may be followed by a list of arguments.
* Unlike parenthesized arguments, these must be plain expressions,
* without labels or spread operators.
*/
commandArguments
: expression ( COMMA nls expression )*
;
aCase
: ( "case" expression
| "default"
)
COLON nls
;
caseSList
: statement ( sep
( statement
|
) )*
;
controlExpressionList
: strictContextExpression ( COMMA nls strictContextExpression )*
;
handler
: "catch" LPAREN parameterDeclaration RPAREN nlsWarn compoundStatement
;
finallyClause
: "finally" nlsWarn compoundStatement
;
assignmentExpression
: conditionalExpression
( ( ASSIGN
| PLUS_ASSIGN
| MINUS_ASSIGN
| STAR_ASSIGN
| DIV_ASSIGN
| MOD_ASSIGN
| SR_ASSIGN
| BSR_ASSIGN
| SL_ASSIGN
| BAND_ASSIGN
| BXOR_ASSIGN
| BOR_ASSIGN
| STAR_STAR_ASSIGN
)
nls assignmentExpression
|
)
;
/** A "path expression" is a name or other primary, possibly qualified by various
* forms of dot, and/or followed by various kinds of brackets.
* It can be used for value or assigned to, or else further qualified, indexed, or called.
* It is called a "path" because it looks like a linear path through a data structure.
* Examples: x.y, x?.y, x*.y, x.@y; x[], x[y], x[y,z]; x(), x(y), x(y,z); x{s}; a.b[n].c(x).d{s}
* (Compare to a C lvalue, or LeftHandSide in the JLS section 15.26.)
* General expressions are built up from path expressions, using operators like '+' and '='.
*/
pathExpression
: primaryExpression
( nls pathElement
| nlsWarn appendedBlock
)*
;
primaryExpression
: IDENT
| constant
| newExpression
| "this"
| "super"
| parenthesizedExpression
| closableBlockConstructorExpression
| listOrMapConstructorExpression
| stringConstructorExpression
| scopeEscapeExpression
| builtInType
;
pathElementStart
: ( nls DOT )
| SPREAD_DOT
| OPTIONAL_DOT
| MEMBER_POINTER
| LBRACK
| LPAREN
| LCURLY
;
pathElement
:
( SPREAD_DOT
| OPTIONAL_DOT
| MEMBER_POINTER
| ( nls DOT )
)
nls
( typeArguments
|
)
namePart
| methodCallArgs
| appendedBlock
| indexPropertyArgs
;
/** An appended block follows any expression.
* If the expression is not a method call, it is given an empty argument list.
*/
appendedBlock
: closableBlock
;
/** This is the grammar for what can follow a dot: x.a, x.@a, x.&a, x.'a', etc.
* Note: <code>typeArguments</code> is handled by the caller of <code>namePart</code>.
*/
namePart
: ( AT
|
)
( IDENT
| STRING_LITERAL
| dynamicMemberName
| openBlock
| keywordPropertyNames
)
;
/** An expression may be followed by one or both of (...) and {...}.
* Note: If either is (...) or {...} present, it is a method call.
* The {...} is appended to the argument list, and matches a formal of type Closure.
* If there is no method member, a property (or field) is used instead, and must itself be callable.
* <p>
* If the methodCallArgs are absent, it is a property reference.
* If there is no property, it is treated as a field reference, but never a method reference.
* <p>
* Arguments in the (...) can be labeled, and the appended block can be labeled also.
* If there is a mix of unlabeled and labeled arguments,
* all the labeled arguments must follow the unlabeled arguments,
* except that the closure (labeled or not) is always a separate final argument.
* Labeled arguments are collected up and passed as a single argument to a formal of type Map.
* <p>
* Therefore, f(x,y, a:p, b:q) {s} is equivalent in all ways to f(x,y, [a:p,b:q], {s}).
* Spread arguments of sequence type count as unlabeled arguments,
* while spread arguments of map type count as labeled arguments.
* (This distinction must sometimes be checked dynamically.)
*
* A plain unlabeled argument is allowed to match a trailing Map or Closure argument:
* f(x, a:p) {s} === f(*[ x, [a:p], {s} ])
*/
methodCallArgs
: LPAREN argList RPAREN
;
/** An expression may be followed by [...].
* Unlike Java, these brackets may contain a general argument list,
* which is passed to the array element operator, which can make of it what it wants.
* The brackets may also be empty, as in T[]. This is how Groovy names array types.
* <p>Returned AST is [INDEX_OP, indexee, ELIST].
*/
indexPropertyArgs
: LBRACK argList RBRACK
;
/** If a dot is followed by a parenthesized or quoted expression, the member is computed dynamically,
* and the member selection is done only at runtime. This forces a statically unchecked member access.
*/
dynamicMemberName
: ( parenthesizedExpression
| stringConstructorExpression
)
;
/** Allowed keywords after dot (as a member name) and before colon (as a label).
* TODO: What's the rationale for these?
*/
keywordPropertyNames
: ( "class"
| "in"
| "as"
| "def"
| "if"
| "else"
| "for"
| "while"
| "do"
| "switch"
| "try"
| "catch"
| "finally"
| builtInType
)
;
parenthesizedExpression
: LPAREN strictContextExpression RPAREN
;
stringConstructorExpression
: STRING_CTOR_START stringConstructorValuePart ( STRING_CTOR_MIDDLE stringConstructorValuePart )* STRING_CTOR_END
;
logicalOrExpression
: logicalAndExpression ( LOR nls logicalAndExpression )*
;
logicalAndExpression
: inclusiveOrExpression ( LAND nls inclusiveOrExpression )*
;
inclusiveOrExpression
: exclusiveOrExpression ( BOR nls exclusiveOrExpression )*
;
exclusiveOrExpression
: andExpression ( BXOR nls andExpression )*
;
andExpression
: regexExpression ( BAND nls regexExpression )*
;
regexExpression
: equalityExpression ( ( REGEX_FIND
| REGEX_MATCH
)
nls equalityExpression )*
;
equalityExpression
: relationalExpression ( ( NOT_EQUAL
| EQUAL
| COMPARE_TO
)
nls relationalExpression )*
;
relationalExpression
: shiftExpression
( ( ( LT
| GT
| LE
| GE
| "in"
)
nls shiftExpression
|
)
| "instanceof" nls typeSpec
| "as" nls typeSpec
)
;
additiveExpression
: multiplicativeExpression ( ( PLUS
| MINUS
)
nls multiplicativeExpression )*
;
multiplicativeExpression
: ( INC nls powerExpressionNotPlusMinus ( ( STAR
| DIV
| MOD
)
nls powerExpression )* )
| ( DEC nls powerExpressionNotPlusMinus ( ( STAR
| DIV
| MOD
)
nls powerExpression )* )
| ( MINUS nls powerExpressionNotPlusMinus ( ( STAR
| DIV
| MOD
)
nls powerExpression )* )
| ( PLUS nls powerExpressionNotPlusMinus ( ( STAR
| DIV
| MOD
)
nls powerExpression )* )
| ( powerExpressionNotPlusMinus ( ( STAR
| DIV
| MOD
)
nls powerExpression )* )
;
powerExpressionNotPlusMinus
: unaryExpressionNotPlusMinus ( STAR_STAR nls unaryExpression )*
;
powerExpression
: unaryExpression ( STAR_STAR nls unaryExpression )*
;
unaryExpression
: INC nls unaryExpression
| DEC nls unaryExpression
| MINUS nls unaryExpression
| PLUS nls unaryExpression
| unaryExpressionNotPlusMinus
;
unaryExpressionNotPlusMinus
: BNOT nls unaryExpression
| LNOT nls unaryExpression
| ( LPAREN builtInTypeSpec RPAREN unaryExpression
| LPAREN classTypeSpec RPAREN unaryExpressionNotPlusMinus
| postfixExpression
)
;
postfixExpression
: pathExpression
( INC
| DEC
|
)
;
/** Numeric, string, regexp, boolean, or null constant. */
constant
: constantNumber
| STRING_LITERAL
| "true"
| "false"
| "null"
;
/** object instantiation.
* Trees are built as illustrated by the following input/tree pairs:
*
* new T()
*
* new
* |
* T -- ELIST
* |
* arg1 -- arg2 -- .. -- argn
*
* new int[]
*
* new
* |
* int -- ARRAY_DECLARATOR
*
* new int[] {1,2}
*
* new
* |
* int -- ARRAY_DECLARATOR -- ARRAY_INIT
* |
* EXPR -- EXPR
* | |
* 1 2
*
* new int[3]
* new
* |
* int -- ARRAY_DECLARATOR
* |
* EXPR
* |
* 3
*
* new int[1][2]
*
* new
* |
* int -- ARRAY_DECLARATOR
* |
* ARRAY_DECLARATOR -- EXPR
* | |
* EXPR 1
* |
* 2
*
*/
newExpression
: "new" nls
( typeArguments
|
)
type
( nls methodCallArgs
( appendedBlock
|
)
| newArrayDeclarator
)
;
closableBlockConstructorExpression
: closableBlock
;
/**
* A list constructor is a argument list enclosed in square brackets, without labels.
* Any argument can be decorated with a spread operator (*x), but not a label (a:x).
* Examples: [], [1], [1,2], [1,*l1,2], [*l1,*l2].
* (The l1, l2 must be a sequence or null.)
* <p>
* A map constructor is an argument list enclosed in square brackets, with labels everywhere,
* except on spread arguments, which stand for whole maps spliced in.
* A colon alone between the brackets also forces the expression to be an empty map constructor.
* Examples: [:], [a:1], [a:1,b:2], [a:1,*:m1,b:2], [*:m1,*:m2]
* (The m1, m2 must be a map or null.)
* Values associated with identical keys overwrite from left to right:
* [a:1,a:2] === [a:2]
* <p>
* Some malformed constructor expressions are not detected in the parser, but in a post-pass.
* Bad examples: [1,b:2], [a:1,2], [:1].
* (Note that method call arguments, by contrast, can be a mix of keyworded and non-keyworded arguments.)
*/
listOrMapConstructorExpression
: LBRACK argList RBRACK
| LBRACK COLON RBRACK
;
scopeEscapeExpression
: DOLLAR
( IDENT
| scopeEscapeExpression
)
;
stringConstructorValuePart
: ( STAR
|
)
( identifier
| openOrClosableBlock
)
;
newArrayDeclarator
: ( LBRACK
( expression
|
)
RBRACK )+
;
/** A single argument in (...) or [...]. Corresponds to to a method or closure parameter.
* May be labeled. May be modified by the spread operator '*' ('*:' for keywords).
*/
argument
: ( argumentLabel COLON
| STAR
( COLON
|
)
|
)
strictContextExpression
;
/** For lookahead only. Fast approximate parse of an argumentLabel followed by a colon. */
argumentLabelStart
: ( IDENT
| keywordPropertyNames
| constantNumber
| STRING_LITERAL
| balancedBrackets
)
COLON
;
/** A label for an argument is of the form a:b, 'a':b, "a":b, (a):b, etc..
* The labels in (a:b), ('a':b), and ("a":b) are in all ways equivalent,
* except that the quotes allow more spellings.
* Equivalent dynamically computed labels are (('a'):b) and ("${'a'}":b)
* but not ((a):b) or "$a":b, since the latter cases evaluate (a) as a normal identifier.
* Bottom line: If you want a truly variable label, use parens and say ((a):b).
*/
argumentLabel
: IDENT
| keywordPropertyNames
| primaryExpression
;
/** Numeric constant. */
constantNumber
: NUM_INT
| NUM_FLOAT
| NUM_LONG
| NUM_DOUBLE
| NUM_BIG_INT
| NUM_BIG_DECIMAL
;
/** Fast lookahead across balanced brackets of all sorts. */
balancedBrackets
: LPAREN balancedTokens RPAREN
| LBRACK balancedTokens RBRACK
| LCURLY balancedTokens RCURLY
| STRING_CTOR_START balancedTokens STRING_CTOR_END
;