io.deephaven.lang.generated.Chunker.jj Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of deephaven-open-api-lang-parser Show documentation
Show all versions of deephaven-open-api-lang-parser Show documentation
The 'open-api-lang-parser' project
/*@bgen(jjtree) Generated By:JJTree: Do not edit this line. Chunker.jj */
/*@egen*/options {
STATIC = false;
DEBUG_PARSER=false;
DEBUG_LOOKAHEAD=false;
DEBUG_TOKEN_MANAGER=false;
SUPPORT_CLASS_VISIBILITY_PUBLIC=true;
JAVA_TEMPLATE_TYPE = "modern";
TOKEN_EXTENDS ="BaseToken";
COMMON_TOKEN_ACTION=true;
}
PARSER_BEGIN(Chunker)
package io.deephaven.lang.generated;
import static io.deephaven.lang.shared.lsp.DiagnosticCode.*;
import static java.util.Collections.singletonList;
import io.deephaven.lang.api.ChunkerInvokable;
import io.deephaven.lang.api.IsScope;
import io.deephaven.lang.api.ParseState;
import io.deephaven.lang.api.ParseCancelled;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.IdentityHashMap;
import java.io.IOException;
public class Chunker implements/*@bgen(jjtree)*/ ChunkerTreeConstants, /*@egen*/ ChunkerMixin {/*@bgen(jjtree)*/
protected JJTChunkerState jjtree = new JJTChunkerState();
/*@egen*/
private final ParseState root = new ParseState(null);
private volatile ParseState current = root;
private final Stack stack = new Stack();
private final IdentityHashMap states = new IdentityHashMap();
private ChunkerInvokable invoker;
public static void main(String[] args) throws Exception {
final Chunker ast;
if (args.length == 0) {
ast = new Chunker(new StreamProvider(System.in));
} else {
ast = new Chunker(new StreamProvider(new java.io.StringReader(args[0])));
}
ast.Document();
}
void report(int code) {
// no-op
}
void jjtreeOpenNodeScope(Node n){
ParseState state = new ParseState(n);
ParseState was = states.put(n, state);
assert was == null : "State map is screwy; " + was + " and " + state + " both added for " + n;
current.addChild(state);
current = state;
}
void jjtreeCloseNodeScope(Node n){
ParseState is = states.get(n);
assert is != null : "State map is screwy; no entry for " + n + " found in " + states;
current = is.finish();
}
public boolean isLookingAhead() {
return jj_lookingAhead;
}
public Token curToken() {
return jj_lookingAhead ? jj_scanpos : token;
}
@Override
public char next() throws IOException {
// next() is much nicer to type....
return jj_input_stream.readChar();
}
@Override
public void back(int backup, int tokenBegin) {
jj_input_stream.backup(backup);
if (tokenBegin != -1) {
jj_input_stream.tokenBegin = tokenBegin;
}
}
void putBackTokens(boolean clearCurrent) {
// instead of trying to mess with the insanity of the jjt runtime state,
// lets instead make our peeking-methods look at existing token images;
// if there are cases where a peek method matches and an existing token is of the wrong type,
// then we may need to fix on a case-by-case basis (adding extra "recovery productions")
// This should at least be simplified by exposing a simple character stream,
// which first reads the existing tokens, and then looks at the underlying input stream.
// We may also want to behave differently when jj_lookingAhead is true. i.e. only actually
// put tokens back when we aren't looking ahead, so we don't attempt to mutate the stack
// until the moment we are actually creating the tokens protected by a peeker method.
jj_ntk = -1; // erase knowledge of any existing tokens.
jj_lastpos = jj_scanpos;
jj_la = 1;
if (token == null) {
return;
}
final Token toPutBack = clearCurrent ? token : token.next;
int begin;
if (toPutBack != null) {
begin = toPutBack.tokenBegin;
} else {
begin = -1;
}
int backup = putBack(clearCurrent ? token : token.next);
if (clearCurrent) {
token.next = null;
}
back(backup, begin);
}
int putBack(Token token) {
if (token == null) {
return 0;
}
// Only put back tokens we haven't already put back.
// We want to leave the tokens attached, because
// we may accidentally detach a legitimate token if a lookahead fails.
if (token.detached) {
return 0;
}
token.detached = true;
int backup = putBack(token.specialToken);
backup += token.image.length();
Token putBack = token.next;
token.next = null;
return backup + putBack(putBack);
}
void fixState(Token token) {
ParseState p = current;
while (p.getSrc() != null) {
if (p.getSrc().jjtGetLastToken() == null) {
p.getSrc().addJunk(token);
}
p = p.getParent();
}
}
public Token token() {
return token;
}
public void checkInterrupts() {
if (Thread.interrupted()) {
throw new ParseCancelled();
}
}
}
PARSER_END(Chunker)
TOKEN_MGR_DECLS : {
Stack stateStack = new Stack();
boolean first;
void backup(int n) { input_stream.backup(n); }
void putBack(Token token, StringBuilder image, int amt) {
input_stream.backup(amt);
assert image.length() - amt >= 0;
image.setLength(image.length()-amt);
token.image = image.toString();
token.endColumn -= amt;
}
public void CommonTokenAction(Token t) {
// hm... perhaps we should also -- the specialToken length from startIndex here?
// we handle it manually already, but will need to do more testing on comments
// (i.e. our only SpecialTokens) later...
t.startIndex = getCurrentTokenAbsolutePosition();
t.endIndex = t.startIndex + t.image.length();
t.tokenBegin = input_stream.tokenBegin;
}
public int getCurrentTokenAbsolutePosition() {
final SimpleCharStream in = input_stream;
return jjmatchedKind == EOF && in.getTotalCharsRead() + 1 == in.getMaxNextCharInd()
? in.getMaxNextCharInd()
: in.getAbsoluteTokenBegin();
}
public SimpleCharStream stream() {
return input_stream;
}
}
// we ignore slash newlines (for python's benefit)
// however, we will match actual newlines,
// since those are semantically significant in python and groovy
SKIP:
{
"\\\n"
| "\\\r"
| "\\\r\n"
}
TOKEN:
{
// An internal token for any newline character
< #NL: "\n"|"\r"|"\r\n" >
}
TOKEN :
{
<#ESCAPED_NL: "\\" [ "\n", "\r" ] > // for python, allow `\` to end a line; we will want to filter these out when appropriate...
}
TOKEN :
{
<#ESCAPED_APOS: "\\'" >
| | | ~["'", "\n", "\r"] )+ >
| > : DEFAULT
}
TOKEN :
{
<#ESCAPED_QUOTE: "\\\"" >
| | | ~["\"", "\n", "\r" ] )+ >
| > : DEFAULT
}
// Whitespace tokens; only considered in DEFAULT mode (collecting up assignment / statements).
TOKEN:
{
// We leave whitespace and newline tokens in the parsed ast;
// places where whitespace can be ignored, we will simply discard the tokens.
// This is done in preparation to properly understand python structures (where leading whitespace is significant)
< WHITESPACE: (" " | "\t")+ >
}
// Newline must be checked for inside of strings as well...
TOKEN:
{
// Eat whitespace before a newline, but not after (thx python)
< NEWLINE: ( " " | "\t" )* ( )+ >
}
// Handle comments; for now, we'll just totally ignore them,
// however, in the future, we may want to offer some kind of intelligent completion there as well.
< DEFAULT >
SPECIAL_TOKEN :
{
// Ugh... need to pick "//" or "#" based on groovy or python.
// double slashes IS a valid operator in python (floor division)
// so... not really sure how to handle this at the tokenizer level...
// probably makes the most sense to bifurcate DEFAULT into GROOVY and PYTHON states.
// This is fairly straight forward for the special tokens, but we'll need to ensure
// other token semantics are updated / possibly duplicated as well...
)? >
}
< DEFAULT >
SPECIAL_TOKEN :
{
< "/**" ~["/"] > { input_stream.backup(1); } : IN_JAVA_DOC_COMMENT
|
< "/*" > : IN_MULTI_LINE_COMMENT
}
// Once in a multi-line comment, gobble up everything that isn't */
MORE :
{
< ~["*"] | ( "*" ~["/"] ) >
}
// Exiting from multi-line comments
SPECIAL_TOKEN :
{
: DEFAULT
}
SPECIAL_TOKEN :
{
: DEFAULT
}
// Alright, done with whitespace and comments; now for strings:
< DEFAULT >
TOKEN:
{
< QUOTE: "\"" > : STR_QUOTE
| < APOS: "'" > : STR_APOS
}
< DEFAULT > // TODO(later) python-only....
TOKEN:
{
< FROM_LOCAL: "from" ( )+ (".")+ ( )* >
}
// Define some whitespace and universally recognized punctuation tokens
< DEFAULT >
TOKEN:
{
// Tokens suitable for identifiers
< NEW: "new" >
| < EXTENDS: "extends" >
| < IMPLEMENTS: "implements" >
| < CLASS: ("class" | "interface" | "enum" | "@interface") >
| < SUPER: "super" >
| < ID:
["A"-"Z","a"-"z", "_", "$" ]
(["A"-"Z","a"-"z","0"-"9", "_", "$" ])*
>
| < #DIGIT: [ "0"-"9" ] ( [ "0"-"9", "_" ] )* >
| < #SCIENTIFIC: [ "e", "E" ] ( "-" )? >
| < NUM:
// see https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
// we'll allow for all valid java formats; will consider python/groovy later
( "-" | "+" )?
(
// hex
"0x" [ "0"-"9", "a"-"f", "A"-"F" ] ( [ "0"-"9", "a"-"f", "A"-"F", "_" ] )*
)
|
(
// binary
"0b" ( [ "0"-"1" ] )+
)
|
(
// regular digits
// optional suffixes
(
"l" | "L" |
( "."
( )?
( ["f", "F", "d", "D" ] | )?
)?
|
)?
) >
| < #NUM_OP: "+" | "-" | "*" | "**" | "/" | "%" | "@" | "&" | "|" | "^" | ">>" | "<<" > // Consider //=
| < DOUBLE_EQ: "=" ( "=" | "~" | "=~" ) >
| < ASSIGN: ( )? "=" ( ~[ "=", "~" ] )? > {
// We gobble up an (optional) "extra char" to check for and avoid == and =~.
// Here, we will put that extra char back, since we don't want it in our token
if (image.charAt(image.length()-1) != '=') {
putBack(matchedToken, image, 1);
}
}
| < INVOKE: ( ( | )* )? "(" >
| < CLOSURE_START: "{" >
| < COLON: ":" >
| < CLOSURE_END: "}" >
| < AT: "@" >
| < ARRAY_START: "[" >
| < ARRAY_END: "]" >
| < ARROW: "->" >
| < LT: "<" >
| < GT: ">" >
| < QUEST: "?" >
| < AMP: "&" >
| < STARS: "*" ( "*" )? >
| < LOGIC:
// we aren't concerned with correct structural use of any operators;
// we just want to be able to gobble them up without producing syntax errors
"!="
| "!"
// we may consider ternaries properly ...later.
| ( "?" ) // allow elvis operator (plain ? handled by , which we grab from productions manually)
// explicitly not adding as it gets special handling (b/c python and groovy use it differently)
| ( ( "in" | "as" | "is" | "instanceof" ) ( | ) ) // groovy uses some words as operators
| "*:" // groovy spread map
| ( ".." ( "<" )? ) // groovy ranges
| "<=>" // groovy spaceship operator
| ( ">" ( "=" | ">" | ">>" ) )
| ( "<" ( "=" | "<" ) )
| ( "+" ( "+" )? )
| ( "-" ( "-" )? )
// | ( "*" ( "*" )? )
| "/"
| "%"
| "&&"
| ( "|" ( "|" )? )
| "^"
| "~"
>
| < ACCESS:
(
( | "*" ) // groovy
"."
) |
(
"."
( | "@" )? // more groovy
)
>
| < TRIPLE_QUOTES:
"\"\"\""
(
( "\\\"" )
|
(
~["\""]
| ( "\"" ~["\""] )
| ("\"\"" ~["\""] )
)
)*
( "\"\"\"" )?
>
| < TRIPLE_APOS:
"'''"
(
( "\\'" )
|
(
~["'"]
| ( "'" ~["'"] )
| ("''" ~["'"] )
)
)*
( "'''" )?
>
| < COMMA: "," >
| < SEMI: ";" >
| < CLOSE_PAREN: ")" >
}
// Do not define new token regex here, unless they are for junk nodes!
// The actual AST nodes defined below
ChunkerDocument Document() :
{/*@bgen(jjtree) Document */
ChunkerDocument jjtn000 = new ChunkerDocument(this, JJTDOCUMENT);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/
Node n = jjtn000;
}
{/*@bgen(jjtree) Document */
try {
/*@egen*/
// Grab as many statements as we can.
EatStatements(true)/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{
// document is done. Fill in backlinks.
jjtn000.jjtGetFirstToken().addBackLinks();
return jjtn000;
}/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
throw (RuntimeException)jjte000;
}
if (jjte000 instanceof ParseException) {
throw (ParseException)jjte000;
}
throw (Error)jjte000;
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
Node EatStatements(boolean persistent) :
{Node n = null;}
{
(
try {
(
n = Newline() |
// TODO: pass leading whitespace into Statement.
// We do not let Statement() gather leading Whitespace(),
// as that could result in it being matched eagerly,
// and we don't want to pay for LL(2+).
// for now, we can easily search to the left of Statement()'s first token,
// so we'll avoid any leading whitespace in any production.
n = Whitespace() |
n = Statement()
)
} catch (ParseException e) {
// Whenever there is an unhandled parse exception,
// gobble up the rest of the line and attach to previous node.
if (n != null) {
token = n.addJunk(eatJunk());
}
fixState(token);
if (!persistent) {
return n;
}
}
)*
{ return n; }
}
ChunkerStatement Statement() :
{/*@bgen(jjtree) Statement */
ChunkerStatement jjtn000 = new ChunkerStatement(this, JJTSTATEMENT);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/
Node expr = null; ChunkerAssign assignment = null;
Token ignore = null;
List annotations = Collections.emptyList();
checkInterrupts();
}
{/*@bgen(jjtree) Statement */
try {
/*@egen*/
try {
[ annotations = Annotations() { expr = annotations.get(annotations.size() - 1); } [ Whitespace() ] ]
(
LOOKAHEAD( { isTypedAssign() } )
(
assignment = TypedAssign() { expr = assignment; }
[ expr = Values() {
assignment.setValue(expr);
}]
)
|
LOOKAHEAD( { isAssign() } )
(
assignment = Assign() { expr = assignment; }
[ expr = Values() {
assignment.setValue(expr);
}] // optional to allow for `var =` as an "invalid, but likely thing we want to handle"
)
| LOOKAHEAD( { isClassDecl() } )
(
expr = JavaClassDecl()
)
| (
// special handling for python `from .name` imports
[]
expr = Values()
[
[ Whitespace() ]
assignment = Assign() {
// set the current expression as the scope to assign.
assignment.addScope(singletonList((IsScope)expr));
}
[ Whitespace() ]
[ expr = Values() ]
]
)
)
[ Whitespace() {
expr.adopt(jjtree.popNode());
} ]
( {
expr.addToken(token);
} | {
// TODO: mark this node as something that should give type information, if any, to it's sibling.
// when we are ready for it, finding a comma token at the end of a statement should suffice to figure it out.
// This will be useful for groovy closure and python set detection.
expr.addToken(token);
} | {
// we'll want something better than this for python ... later.
expr.addToken(token);
} | {
ignore = token;
back(1, token.tokenBegin);
} | {
ignore = token;
back(1, token.tokenBegin);
} | Newline()
| Eof() {
// let's keep eof's for now, since "end of the script" is a very common and important cursor position,
// deserving of special treatment / enhanced guesses.
// jjtree.popNode();
} ) // optional semi-colon delimiter
} catch (ParseException e) {
// Whenever there is an unhandled parse exception,
// gobble up the rest of the line and attach to previous node.
if (expr != null) {
token = expr.addJunk(eatJunk());
fixState(token);
}
}/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{
Token removed = jjtn000.removeToken(ignore);
if (removed != null) {
token = removed;
}
jjtn000.setAnnotations(annotations);
return jjtn000;
}/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
throw (RuntimeException)jjte000;
}
if (jjte000 instanceof ParseException) {
throw (ParseException)jjte000;
}
throw (Error)jjte000;
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
ChunkerJavaClassDecl JavaClassDecl() :
{/*@bgen(jjtree) JavaClassDecl */
ChunkerJavaClassDecl jjtn000 = new ChunkerJavaClassDecl(this, JJTJAVACLASSDECL);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/
boolean wellFormed = false;
}
{/*@bgen(jjtree) JavaClassDecl */
try {
/*@egen*/
// This is brutish, but we don't inspect these ast nodes at all right now...
// and likely not for quite a while... we'd be much better off to defer to native parsers here.
[
[
// TODO: handle well-formed-ness and associated warnings / suggestions when that fails.
TypeDecl()
[ ]
[
[
TypeDecl()
(
[ ]
[ ]
[ TypeDecl() ]
)*
]
[ ]
]
[
[
TypeDecl()
(
[ ]
[ ]
[ TypeDecl() ]
)*
]
[ ]
]
]
]
[ ]
[
(
// TODO something which actually eats member declarations... and arbitrary `{ statementBlocks() }`
EatStatements(false)
[ {
wellFormed = true;
} ]
)
| Eof()
]/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{
jjtn000.setWellFormed(wellFormed);
return jjtn000;
}/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
throw (RuntimeException)jjte000;
}
if (jjte000 instanceof ParseException) {
throw (ParseException)jjte000;
}
throw (Error)jjte000;
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
ChunkerAssign Assign() :
{/*@bgen(jjtree) Assign */
ChunkerAssign jjtn000 = new ChunkerAssign(this, JJTASSIGN);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/}
{/*@bgen(jjtree) Assign */
try {
/*@egen*/
Ident()
[ ]
[ ]/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{ return jjtn000; }/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
throw (RuntimeException)jjte000;
}
if (jjte000 instanceof ParseException) {
throw (ParseException)jjte000;
}
throw (Error)jjte000;
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
ChunkerTypedAssign TypedAssign() :
{/*@bgen(jjtree) TypedAssign */
ChunkerTypedAssign jjtn000 = new ChunkerTypedAssign(this, JJTTYPEDASSIGN);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/}
{/*@bgen(jjtree) TypedAssign */
try {
/*@egen*/
TypeDecl()
[ ]
Ident()
[ ]
[ ]/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{ return jjtn000; }/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
throw (RuntimeException)jjte000;
}
if (jjte000 instanceof ParseException) {
throw (ParseException)jjte000;
}
throw (Error)jjte000;
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
ChunkerTypeDecl TypeDecl():
{/*@bgen(jjtree) TypeDecl */
ChunkerTypeDecl jjtn000 = new ChunkerTypeDecl(this, JJTTYPEDECL);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/}
{/*@bgen(jjtree) TypeDecl */
try {
/*@egen*/
[ ]
[ TypeParams() ]/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{ return jjtn000; }/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
throw (RuntimeException)jjte000;
}
if (jjte000 instanceof ParseException) {
throw (ParseException)jjte000;
}
throw (Error)jjte000;
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
ChunkerTypeParams TypeParams() :
{/*@bgen(jjtree) TypeParams */
ChunkerTypeParams jjtn000 = new ChunkerTypeParams(this, JJTTYPEPARAMS);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/ boolean wellFormed=false; }
{/*@bgen(jjtree) TypeParams */
try {
/*@egen*/
(
( | )*
TypeParam(true)
( ( | )* ( | )* TypeParam(true) )*
)?
[ ]
[ { wellFormed = true; } ]/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{
jjtn000.setWellFormed(wellFormed);
return jjtn000;
}/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
throw (RuntimeException)jjte000;
}
if (jjte000 instanceof ParseException) {
throw (ParseException)jjte000;
}
throw (Error)jjte000;
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
ChunkerTypeParam TypeParam(boolean canWildcard) :
{/*@bgen(jjtree) TypeParam */
ChunkerTypeParam jjtn000 = new ChunkerTypeParam(this, JJTTYPEPARAM);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/ boolean wellFormed=false; }
{/*@bgen(jjtree) TypeParam */
try {
/*@egen*/
(
(
( | )*
(
( | )*
[ ]
( | )*
)*
)
|
{
if (!canWildcard) {
report(MALFORMED_TYPE_ARGUMENT);
}
}
)
( | )?
(
( | )
[ | ]
( ( [ ] )* )
[ TypeParams() ]
(
[ [ TypeParams() ] ]
)*
)?/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{
jjtn000.setWellFormed(wellFormed);
return jjtn000;
}/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
throw (RuntimeException)jjte000;
}
if (jjte000 instanceof ParseException) {
throw (ParseException)jjte000;
}
throw (Error)jjte000;
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
ChunkerIdent Ident() :
{/*@bgen(jjtree) Ident */
ChunkerIdent jjtn000 = new ChunkerIdent(this, JJTIDENT);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/}
{/*@bgen(jjtree) Ident */
try {
/*@egen*/
/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{ return jjtn000; }/*@bgen(jjtree)*/
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
ChunkerNum Num() :
{/*@bgen(jjtree) Num */
ChunkerNum jjtn000 = new ChunkerNum(this, JJTNUM);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/}
{/*@bgen(jjtree) Num */
try {
/*@egen*/
/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{ return jjtn000; }/*@bgen(jjtree)*/
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
ChunkerWhitespace Whitespace() :
{/*@bgen(jjtree) Whitespace */
ChunkerWhitespace jjtn000 = new ChunkerWhitespace(this, JJTWHITESPACE);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/}
{/*@bgen(jjtree) Whitespace */
try {
/*@egen*/
/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{ return jjtn000; }/*@bgen(jjtree)*/
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
ChunkerMethodName MethodName() :
{/*@bgen(jjtree) MethodName */
ChunkerMethodName jjtn000 = new ChunkerMethodName(this, JJTMETHODNAME);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/}
{/*@bgen(jjtree) MethodName */
try {
/*@egen*/
/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{ return jjtn000; }/*@bgen(jjtree)*/
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
ChunkerNewline Newline() :
{/*@bgen(jjtree) Newline */
ChunkerNewline jjtn000 = new ChunkerNewline(this, JJTNEWLINE);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/}
{/*@bgen(jjtree) Newline */
try {
/*@egen*/
/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{ return jjtn000; }/*@bgen(jjtree)*/
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
ChunkerNew New() :
{/*@bgen(jjtree) New */
ChunkerNew jjtn000 = new ChunkerNew(this, JJTNEW);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/
boolean wellFormed = false;
String name = null;
ChunkerInvokable parent = invoker;
List scope = null;
}
{/*@bgen(jjtree) New */
try {
/*@egen*/
[ TypeParams() ] [ scope = Scope() { jjtn000.addScope(scope); } ] [ ] [
(
LOOKAHEAD( { isTypedInvoke(true) } )
(
{ name = token.image; }
[ ]
TypeParams()
[ ]
MethodName() {
name += "." + token.image.substring(0, token.image.length()-1);
}
)
|
MethodName() {
// shave off the opening (
name = token.image.substring(0, token.image.length()-1);
}
)
[ Whitespace() ]
{ invoker = jjtn000; }
[ MethodArguments(jjtn000) ]
{ invoker = parent; }
try {
(
{ wellFormed = true; }
| Newline() {
// we want to let newline end the final statement of source,
// but we don't actually want to keep the token; that will be needed
// to finish a not-the-last statement in a block of source.
jjtn000.setWellFormed(false);
putBackTokens(true);
token.next = null;
jjtree.popNode();
}
| Eof() {
wellFormed = false;
}
)
} catch (ParseException e) {
// This invocation is malformed; recover here so we can continue
Node node = jjtree.nodeArity() > 0 ? jjtree.peekNode() : jjtn000;
Token junk = eatJunk();
node.addToken(junk);
}
]/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{
if (name == null) { wellFormed = false; }
jjtn000.setName(name);
jjtn000.setWellFormed(wellFormed);
return jjtn000;
}/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
throw (RuntimeException)jjte000;
}
if (jjte000 instanceof ParseException) {
throw (ParseException)jjte000;
}
throw (Error)jjte000;
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
Node maybeBin(Node src) :
{
ChunkerBinaryExpression result;
assert src == jjtree.peekNode();
jjtree.popNode();
}
{
result = BinaryExpression(src)
{
if (result.getJoiner() == null && result.getRight() == null) {
jjtree.pushNode(src);
return src;
}
return result.rescope(null);
}
}
// Forms a chain of whitespace-separated values;
// anything that actually matches in here is likely either
// malformed, or deserving of it's own production
// (but, for now, we're being extremely lax, so
// the parser can at least survive valid source that it
// simply does not understand well enough yet).
Node Values() :
{
Node value;
ChunkerWhitespace ws = null;
}
{
(
value = Expression()
[ ws = Whitespace() {
jjtree.popNode();
}]
( value = maybeBin(value) {
if (ws != null) {
value.insertChild(ws, 1);
ws = null;
}
}
[ ws = Whitespace() {
jjtree.popNode();
}]
)*
)
{
if (ws != null) {
jjtree.pushNode(ws);
}
return value;
}
}
Node MethodArg() :
{ Node value; }
{
(
LOOKAHEAD( { isPythonAnnotated() } )
( value = Ident() {
value.addToken(token);
} )
|
value = Values()
)
{
return value;
}
}
void MethodArguments(ChunkerInvokable invokable) :
{ Node value; ChunkerAssign assign; }
{
// handle argument lists
[
[ Whitespace() ]
]
value = MethodArg() {
invokable.addArgument(value);
}
// once there is an unmatched open paren, eat both newlines and whitespace
( Whitespace() | Newline() )*
(
LOOKAHEAD( { isAssign() } )
assign = Assign() [ value = Values() {
assign.setValue(value);
}]
)?
( Whitespace() | Newline() )*
(
( Whitespace() | Newline() )*
[ ]
( Whitespace() | Newline() )*
[
value = MethodArg() {
invokable.addArgument(value);
}
( Whitespace() | Newline() )*
]
)*
}
List Scope() :
{
ChunkerIdent addTo;
ChunkerTypeParams typeParams;
List sub, result = new ArrayList();
}
{
LOOKAHEAD( { isScope() } )
(
addTo = Ident() {
// hm, should probably pop this node, and force callers to always stash the actual nodes on something.
result.add(addTo);
jjtree.popNode();
}
// handle type argument lists
[ typeParams = TypeParams() {
addTo.setTypeParams(typeParams);
// we are eating these TypeParams, so remove them from the stack.
jjtree.popNode();
} ]
{
// add this to the Ident that we'll be returning.
// We should maybe have a different subtype for this...
addTo.addToken(token);
}
[ sub = Scope() {
result.addAll(sub);
}]
)
{
return result;
}
}
List Annotations() :
{
ChunkerAnnotation anno;
List result = new ArrayList();
}
{
(
( anno = Annotation() {
result.add(anno);
} )+
)
{
return result;
}
}
ChunkerAnnotation Annotation():
{/*@bgen(jjtree) Annotation */
ChunkerAnnotation jjtn000 = new ChunkerAnnotation(this, JJTANNOTATION);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/
boolean wellFormed = false;
}
{/*@bgen(jjtree) Annotation */
try {
/*@egen*/
(
[ Ident() {
wellFormed = true;
} ]
[ Whitespace() ]
[ Invoke() ]
// TODO: if python, _require_ a newline for each decorator
( Whitespace() | Newline() )*
)/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{ return jjtn000; }/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
throw (RuntimeException)jjte000;
}
if (jjte000 instanceof ParseException) {
throw (ParseException)jjte000;
}
throw (Error)jjte000;
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
ChunkerInvoke Invoke():
{/*@bgen(jjtree) Invoke */
ChunkerInvoke jjtn000 = new ChunkerInvoke(this, JJTINVOKE);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/
boolean wellFormed = false;
String name;
ChunkerInvokable parent = invoker;
}
{/*@bgen(jjtree) Invoke */
try {
/*@egen*/
(
LOOKAHEAD( { isTypedInvoke(false) } )
(
TypeParams()
[ ]
MethodName() { name = token.image.substring(0, token.image.length()-1); }
)
|
MethodName() {
// shave off the opening (
name = token.image.substring(0, token.image.length()-1);
}
)
( Whitespace() | Newline() )*
{ invoker = jjtn000; }
[ MethodArguments(jjtn000) ]
{
if (parent != null) {
// jjtThis.addScope(parent);
}
invoker = parent;
}
try {
(
(
{
wellFormed = true;
}
// technically, this should be reserved only for method declarations, not invocations,
// but we currently are not differentiating, and are generally allowing all malformed syntax,
// so, here it goes...
[ ]
[
[ Values() ]
{
wellFormed = false;
}
[ {
wellFormed = true;
} ]
]
)
| Newline() {
// we want to let newline end the final statement of source,
// but we don't actually want to keep the token; that will be needed
// to finish a not-the-last statement in a block of source.
jjtn000.setWellFormed(false);
}
| Eof() {
wellFormed = false;
}
)
} catch (ParseException e) {
// This invocation is malformed; recover here so we can continue
Node node = jjtree.nodeArity() > 0 ? jjtree.peekNode() : jjtn000;
Token junk = eatJunk();
node.addToken(junk);
}/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{
jjtn000.setWellFormed(wellFormed);
jjtn000.setName(name);
return jjtn000;
}/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
throw (RuntimeException)jjte000;
}
if (jjte000 instanceof ParseException) {
throw (ParseException)jjte000;
}
throw (Error)jjte000;
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
ChunkerParam Param():
{/*@bgen(jjtree) Param */
ChunkerParam jjtn000 = new ChunkerParam(this, JJTPARAM);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/
List scope;
Node value; ChunkerAssign assign;
}
{/*@bgen(jjtree) Param */
try {
/*@egen*/
(
[
LOOKAHEAD( { isScope() } )
scope = Scope() {
for (IsScope ident : scope) {
jjtn000.addChild(ident);
}
}
]
Ident()
[ ]
[ // python support
Values()
]
[ TypeParams() ]
[ ]
[ Array() ]
[
[
(
LOOKAHEAD( { isAssign() } )
// try to gobble up assigns first...
assign = Assign()
( | )*
[ value = Expression() {
assign.setValue(value);
}]
)
// settle for a plain identifier
| Ident()
]
]
[ ]
)/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{return jjtn000;}/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
throw (RuntimeException)jjte000;
}
if (jjte000 instanceof ParseException) {
throw (ParseException)jjte000;
}
throw (Error)jjte000;
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
ChunkerClosure Closure():
{/*@bgen(jjtree) Closure */
ChunkerClosure jjtn000 = new ChunkerClosure(this, JJTCLOSURE);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/
boolean wellFormed = false, hasType = false, hadComma = false;
Node n = null;
List scope;
List params;
}
{/*@bgen(jjtree) Closure */
try {
/*@egen*/
// TODO: consider python dictionaries before getting here (i.e. make a method that peeks for dictionary syntax)
( Whitespace() | Newline() )*
[
LOOKAHEAD({ isParamList() })
n = ClosureParams() [ ]
]
( Whitespace() | Newline() )*
EatStatements(false)
( Whitespace() | Newline() )*
try {
(
(
{ wellFormed = true; }
[ Whitespace() {
jjtree.popNode();
}]
[ Invoke() ]
)
| Eof() {
jjtn000.setWellFormed(false);
}
)
} catch (ParseException e) {
// This invocation is malformed; recover here so we can continue
Node node = jjtree.nodeArity() > 0 ? jjtree.peekNode() : jjtn000;
Token junk = eatJunk();
node.addToken(junk);
}/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{
jjtn000.setWellFormed(wellFormed);
return jjtn000;
}/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
throw (RuntimeException)jjte000;
}
if (jjte000 instanceof ParseException) {
throw (ParseException)jjte000;
}
throw (Error)jjte000;
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
Node ClosureParams() :
{Node n = null;}
{
try {
n = Param()
(
( | )*
n = Param()
)*
} catch (ParseException ignored) {
// any matched tokens should be put back for us...
}
{ return n; }
}
ChunkerArray Array():
{/*@bgen(jjtree) Array */
ChunkerArray jjtn000 = new ChunkerArray(this, JJTARRAY);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/
boolean wellFormed = false;
Node n = null;
}
{/*@bgen(jjtree) Array */
try {
/*@egen*/
// TODO: consider python list comprehension here
( Whitespace() | Newline() )*
[ MethodArguments(jjtn000) ]
( Whitespace() | Newline() )*
try {
(
{ wellFormed = true; }
| Eof() {
wellFormed = false;
}
)
} catch (ParseException e) {
// This invocation is malformed; recover here so we can continue
Node node = jjtree.nodeArity() > 0 ? jjtree.peekNode() : jjtn000;
Token junk = eatJunk();
node.addToken(junk);
}/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{
jjtn000.setWellFormed(wellFormed);
return jjtn000;
}/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
throw (RuntimeException)jjte000;
}
if (jjte000 instanceof ParseException) {
throw (ParseException)jjte000;
}
throw (Error)jjte000;
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
Node Expression() :
{
Node expr = null, expr2 = null, anchor = null;
String name;
ChunkerBinaryExpression bin = null;
ChunkerWhitespace ws = null;
ChunkerAssign assign = null;
boolean wellFormed = false;
}
{
(
(
// | expr = ClassDef()
// | expr = FuncDef() // more python-y stuff...
(
expr = Closure()
) | (
expr = Array()
) | (
expr = Invoke()
) | (
expr = String()
) | (
expr = Num()
) | (
expr = New()
) | (
expr = Ident()
[
ws = Whitespace() {
jjtree.popNode();
}
// Space-delimited expressions; this is how we ignore "keywords" like return or println
// We should do something special when these might actually be groovy "shorthand": method calls w/out ()
[ expr2 = Expression() {
ChunkerBinaryExpression b = new ChunkerBinaryExpression(this, JJTBINARYEXPRESSION);
jjtree.popNode();
jjtree.popNode();
b.setLeft(expr);
b.insertChild(ws, 1);
b.setJoiner(ws.jjtGetFirstToken());
b.setRight(expr2);
expr = b.rescope(null);
jjtree.pushNode(expr);
}]
]
)
)
[ ws = Whitespace() {
jjtree.popNode();
} ]
// after a valid expression, there may be some things to chain into a more complex expression...
[
{
jjtree.popNode();
}
bin = BinaryExpression(expr) {
if (bin.getRight() == null && bin.getJoiner() == null) {
if (ws != null) {
jjtree.pushNode(ws);
}
bin = null;
} else {
if (ws != null) {
bin.insertChild(ws, 1);
}
expr = bin.rescope(null);
if (bin != expr) {
jjtree.popNode();
jjtree.pushNode(expr);
bin = null;
}
}
}
]
[
(
{
// If we saw an assign statement, then we need to make the current expression the scope of an Assign().
assign = new ChunkerAssign(this, JJTASSIGN);
jjtree.popNode();
assign.addChild(bin == null ? expr : bin);
bin = null;
if (ws != null) {
assign.addChild(ws);
}
assign.addToken(token);
jjtree.pushNode(assign);
expr = assign;
}
)
[ {
assign.addToken(token);
}]
[ expr2 = Values() {
assign.setValue(expr2);
jjtree.popNode();
assign.addChild(expr2);
}]
]
)
{
if (assign != null) {
// TODO: make addChild fix tokens so we can delete this workaround
assign.jjtSetLastToken(token);
}
return bin == null ? expr : bin;
}
}
void EatBinaryWhitespace() :
{}
{
LOOKAHEAD( { isBinExprAcrossNewline() } )
( | )+
{}
}
ChunkerBinaryExpression BinaryExpression(Node left) :
{/*@bgen(jjtree) BinaryExpression */
ChunkerBinaryExpression jjtn000 = new ChunkerBinaryExpression(this, JJTBINARYEXPRESSION);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/
boolean wellFormed = left.isWellFormed();
Node right = null;
Token joiner;
jjtn000.setLeft(left);
// jjtree.popNode();
}
{/*@bgen(jjtree) BinaryExpression */
try {
/*@egen*/
(
// TODO: handle newline followed by ACCESS or LOGIC
[ EatBinaryWhitespace() ]
(
{
if (!(token.image.equals("++") || token.image.equals("--"))) {
wellFormed = false; // if there is an expression, it will be reset to true...
}
joiner = token;
jjtn000.setJoiner(joiner);
}
| {
wellFormed = false; // not legal to have this w/out a followup expression
joiner = token;
jjtn000.setJoiner(joiner);
}
| {
wellFormed = false; // not legal to have this w/out a followup expression
joiner = token;
jjtn000.setJoiner(joiner);
}
| {
wellFormed = false; // not legal to have this w/out a followup expression
joiner = token;
jjtn000.setJoiner(joiner);
}
| {
wellFormed = false; // not legal to have this w/out a followup expression
joiner = token;
jjtn000.setJoiner(joiner);
}
| {
wellFormed = false; // not legal to have this w/out a followup expression
joiner = token;
jjtn000.setJoiner(joiner);
}
| {
wellFormed = false; // not legal to have this w/out a followup expression
joiner = token;
jjtn000.setJoiner(joiner);
}
| {
joiner = token;
jjtn000.setJoiner(joiner);
}
| {
joiner = token;
jjtn000.setJoiner(joiner);
}
| right = Array() {
ChunkerBinaryExpression b = new ChunkerBinaryExpression(this, JJTBINARYEXPRESSION);
jjtree.popNode();
b.setLeft(left);
// no joiner when we're mashing a trailing [] onto an expression (optional parens are troublesome)
b.setRight(right);
left = b;
right = null;
jjtn000.setLeft(b);
wellFormed = left.isWellFormed();
}
)
[ ]
// recurse into the "any valid value" production.
[ right = Expression() {
wellFormed = left.isWellFormed();
jjtn000.setRight(right);
Node maybeWs = jjtree.popNode();
if (maybeWs instanceof ChunkerWhitespace) {
Node next = jjtree.popNode();
assert next == right;
jjtree.pushNode(maybeWs);
}
}]
[ ]
)/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{
// TODO: transform types to scopes...
jjtn000.setWellFormed(wellFormed);
return jjtn000;
}/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
throw (RuntimeException)jjte000;
}
if (jjte000 instanceof ParseException) {
throw (ParseException)jjte000;
}
throw (Error)jjte000;
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
ChunkerString String() :
{/*@bgen(jjtree) String */
ChunkerString jjtn000 = new ChunkerString(this, JJTSTRING);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/
boolean wellFormed = false;
StringBuilder b = new StringBuilder();
String quoteType;
}
{/*@bgen(jjtree) String */
try {
/*@egen*/
(
(
{
quoteType = token.image;
wellFormed = false;
}
[
[ { b.append(token.image); } ]
(
Newline() {
// TODO: take a parameter to this production that controls
// whether we simply absorb the newlines, or form a malformed ast node.
jjtn000.setWellFormed(false);
jjtree.popNode();
putBackTokens(true);
token.next = null;
}
| Eof() {
wellFormed = false;
jjtree.popNode();
}
| {
wellFormed = "\"".equals(token.image);
if (!wellFormed) {
back(token.image.length(), -1);
}
}
)
]
)
|
(
{ quoteType = token.image; }
{
wellFormed = false;
}
[
( {
b.append(token.image);
} )*
(
Newline() {
// TODO: take a parameter to this production that controls
// whether we simply absorb the newlines, or form a malformed ast node.
jjtn000.setWellFormed(false);
jjtree.popNode();
putBackTokens(true);
token.next = null;
}
| Eof() {
wellFormed = false;
jjtree.popNode();
}
| {
wellFormed = "'".equals(token.image);
if (!wellFormed) {
back(token.image.length(), -1);
}
}
)
]
)
)/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{
jjtn000.initialize(quoteType, b.toString(), wellFormed);
return jjtn000;
}/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
if (jjtc000) {
jjtree.clearNodeScope(jjtn000);
jjtc000 = false;
} else {
jjtree.popNode();
}
if (jjte000 instanceof RuntimeException) {
throw (RuntimeException)jjte000;
}
if (jjte000 instanceof ParseException) {
throw (ParseException)jjte000;
}
throw (Error)jjte000;
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}
// This is here so we can easily Eof() { jjtree.popNode(); } to discard eof tokens
ChunkerEof Eof():
{/*@bgen(jjtree) Eof */
ChunkerEof jjtn000 = new ChunkerEof(this, JJTEOF);
boolean jjtc000 = true;
jjtree.openNodeScope(jjtn000);
jjtreeOpenNodeScope(jjtn000);
jjtn000.jjtSetFirstToken(getToken(1));
/*@egen*/}
{/*@bgen(jjtree) Eof */
try {
/*@egen*/
/*@bgen(jjtree)*/
{
jjtree.closeNodeScope(jjtn000, true);
jjtc000 = false;
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
/*@egen*/
{ return jjtn000; }/*@bgen(jjtree)*/
} finally {
if (jjtc000) {
jjtree.closeNodeScope(jjtn000, true);
if (jjtree.nodeCreated()) {
jjtreeCloseNodeScope(jjtn000);
}
jjtn000.jjtSetLastToken(getToken(0));
}
}
/*@egen*/
}