All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.neo4j.cypher.internal.parser.javacc.cypher.jj Maven / Gradle / Ivy

There is a newer version: 5.23.0
Show newest version

options {
  LOOKAHEAD = 1;
  CHOICE_AMBIGUITY_CHECK = 2;
  OTHER_AMBIGUITY_CHECK = 1;
  DEBUG_PARSER = false;
  DEBUG_LOOKAHEAD = false;
  DEBUG_TOKEN_MANAGER = false;
  ERROR_REPORTING = true;
  JAVA_UNICODE_ESCAPE = true;
  UNICODE_INPUT = false;
  IGNORE_CASE = false;
  USER_TOKEN_MANAGER = false;
  USER_CHAR_STREAM = true;
  BUILD_PARSER = true;
  BUILD_TOKEN_MANAGER = true;
  SANITY_CHECK = true;
  FORCE_LA_CHECK = false;
  TOKEN_EXTENDS = "WithOffset";
  COMMON_TOKEN_ACTION = true;
}

PARSER_BEGIN(Cypher)

/*
 * Copyright (c) 2002-2019 "Neo4j,"
 * Neo4j Sweden AB [http://neo4j.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.cypher.internal.parser.javacc;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.neo4j.cypher.internal.ast.factory.AccessType;
import org.neo4j.cypher.internal.ast.factory.ASTExceptionFactory;
import org.neo4j.cypher.internal.ast.factory.ASTFactory;
import org.neo4j.cypher.internal.ast.factory.ASTFactory.StringPos;
import org.neo4j.cypher.internal.ast.factory.ActionType;
import org.neo4j.cypher.internal.ast.factory.ConstraintType;
import org.neo4j.cypher.internal.ast.factory.ConstraintVersion;
import org.neo4j.cypher.internal.ast.factory.CreateIndexTypes;
import org.neo4j.cypher.internal.ast.factory.HintIndexType;
import org.neo4j.cypher.internal.ast.factory.ParameterType;
import org.neo4j.cypher.internal.ast.factory.ScopeType;
import org.neo4j.cypher.internal.ast.factory.ShowCommandFilterTypes;
import org.neo4j.cypher.internal.ast.factory.SimpleEither;

/** Simple brace matcher. */
public class Cypher {

    ASTExceptionFactory exceptionFactory;
    ASTFactory astFactory;

    public Cypher(ASTFactory astFactory,
                  ASTExceptionFactory exceptionFactory,
                  CharStream stream) {
        this(stream);
        this.astFactory = astFactory;
        this.exceptionFactory = exceptionFactory;
    }

    private POS pos( Token t )
    {
        return t != null ? astFactory.inputPosition( t.beginOffset, t.beginLine, t.beginColumn ) : null;
    }

    private void assertValidType( Token t, String expected, String actual ) throws Exception
    {
        if ( expected != null && !expected.equals(actual) )
        {
            throw exceptionFactory.syntaxException( new ParseException(
                String.format("Invalid input '%s': expected \"%s\"", t.image, expected ) ), t.beginOffset, t.beginLine, t.beginColumn );
        }
    }

    private void assertNotAlreadySet( Object object, Token token, String errorMessage ) throws Exception
    {
        if ( object != null )
        {
            throw exceptionFactory.syntaxException( new ParseException( errorMessage ), token.beginOffset, token.beginLine, token.beginColumn );
        }
    }
}

PARSER_END(Cypher)

TOKEN_MGR_DECLS :
{
    public void CommonTokenAction( Token t )
    {
        CypherCharStream ccStream = (CypherCharStream) input_stream;
        t.beginOffset = ccStream.getBeginOffset();
        t.endOffset = ccStream.getEndOffset();
    }
}

SKIP :
{
    " "
    | "\t"
    | "\n"
    | "\r"
}

/* COMMENTS */

SPECIAL_TOKEN :
{
    < SINGLE_LINE_COMMENT: "//"(~["\n","\r"])* ("\n"|"\r"|"\r\n")? >
}

MORE :
{
    < "/**" ~["/"] > { input_stream.backup( 1 ); } : IN_FORMAL_COMMENT
    | "/*" : IN_MULTI_LINE_COMMENT
}


SPECIAL_TOKEN :
{
    < FORMAL_COMMENT: "*/" > : DEFAULT
}


SPECIAL_TOKEN :
{
    < MULTI_LINE_COMMENT: "*/" > : DEFAULT
}


MORE :
{
    < ~[] >
}

/* LITERALS */

TOKEN :
{
    < DECIMAL_DOUBLE: ( ["0"-"9"] )+ "." ( ["0"-"9"] )+ (  )? (  )?
                      | "." ( ["0"-"9"] )+ (  )? (  )?
                      | ( ["0"-"9"] )+  (  )? >
    | < UNSIGNED_DECIMAL_INTEGER: ( ( ["1"-"9"] ( ["0"-"9"] )* (  )* ) | "0" ) > //0 with part letter -> Octal integer?
    | < #DECIMAL_EXPONENT: ["e","E"] ( ["+","-"] )? ( ["0"-"9"] )+ (  )* >
    | < UNSIGNED_HEX_INTEGER: "0" ["x","X"] (  )* >
    | < UNSIGNED_OCTAL_INTEGER: "0" ( "o" )? (  )* >
}

MORE : { < STRING1_OPEN: "'" > : STRING1 }
 MORE: { "\\\\" { image.delete( image.length() - 2, image.length() ); image.append( "\\" ); } }
 MORE: { "\\\'" { image.delete( image.length() - 2, image.length() ); image.append( "'" ); } }
 MORE: { "\\\"" { image.delete( image.length() - 2, image.length() ); image.append( "\"" ); } }
 MORE: { "\\b" { image.delete( image.length() - 2, image.length() ); image.append( "\b" ); } }
 MORE: { "\\f" { image.delete( image.length() - 2, image.length() ); image.append( "\f" ); } }
 MORE: { "\\n" { image.delete( image.length() - 2, image.length() ); image.append( "\n" ); } }
 MORE: { "\\r" { image.delete( image.length() - 2, image.length() ); image.append( "\r" ); } }
 MORE: { "\\t" { image.delete( image.length() - 2, image.length() ); image.append( "\t" ); } }
 MORE: { "\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]" }
 MORE: { < ~["'"] > }
 TOKEN: {  { matchedToken.image = image.substring( 1, image.length() - 1 ); } : DEFAULT }

MORE : { < STRING2_OPEN: "\"" > : STRING2 }
 MORE: { "\\\\" { image.delete( image.length() - 2, image.length() ); image.append( "\\" ); } }
 MORE: { "\\\'" { image.delete( image.length() - 2, image.length() ); image.append( "'" ); } }
 MORE: { "\\\"" { image.delete( image.length() - 2, image.length() ); image.append( "\"" ); } }
 MORE: { "\\b" { image.delete( image.length() - 2, image.length() ); image.append( "\b" ); } }
 MORE: { "\\f" { image.delete( image.length() - 2, image.length() ); image.append( "\f" ); } }
 MORE: { "\\n" { image.delete( image.length() - 2, image.length() ); image.append( "\n" ); } }
 MORE: { "\\r" { image.delete( image.length() - 2, image.length() ); image.append( "\r" ); } }
 MORE: { "\\t" { image.delete( image.length() - 2, image.length() ); image.append( "\t" ); } }
 MORE: { "\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]" }
 MORE: { < ~["\""] > }
 TOKEN: {  { matchedToken.image = image.substring( 1, image.length() - 1 ); } : DEFAULT }

MORE : { < ESCAPED_SYMBOLIC_NAME_OPEN: "`" > : ESC_SYMB_NAME }
 MORE: { < ~["`"] > }
 MORE: { "``" { image.delete( image.length() - 2, image.length() ); image.append( "`" ); } }
 TOKEN: {  { matchedToken.image = image.substring( 1, image.length() - 1 ); } : DEFAULT }

/**
* add new tokens to SymbolicNameString() if they should be accepted as an identifier as well
* add new tokens to IdentifierTokens.tokens for correct filtering of identifier tokens
*/
TOKEN [IGNORE_CASE] :
{
    < ACCESS: "ACCESS" >
    | < ACTIVE: "ACTIVE" >
    | < ALIAS: "ALIAS" >
    | < ALIASES: "ALIASES" >
    | < ALL_SHORTEST_PATH: "allShortestPaths" >
    | < ALL: "ALL" >
    | < ALTER: "ALTER" >
    | < AND: "AND" >
    | < ANY: "ANY" >
    | < AS: "AS" >
    | < ASC: "ASC" ("ENDING")? >
    | < ASSERT: "ASSERT" >
    | < ASSIGN: "ASSIGN" >
    | < AT: "AT" >
    | < BAR: "|" >
    | < BRIEF: "BRIEF" >
    | < BTREE: "BTREE" >
    | < BUILT: "BUILT" >
    | < BY: "BY" >
    | < CALL: "CALL" >
    | < CASE: "CASE" >
    | < CATALOG: "CATALOG">
    | < CHANGE: "CHANGE">
    | < COMMIT: "COMMIT" >
    | < CONSTRAINT: "CONSTRAINT" >
    | < CONSTRAINTS: "CONSTRAINTS" >
    | < CONTAINS: "CONTAINS" >
    | < COPY: "COPY" >
    | < COUNT: "count" >
    | < CREATE: "CREATE" >
    | < CSV: "CSV" >
    | < CURRENT: "CURRENT" >
    | < DATA: "DATA">
    | < DATABASE: "DATABASE">
    | < DATABASES: "DATABASES">
    | < DBMS: "DBMS">
    | < DEFAULT_TOKEN: "DEFAULT">
    | < DEFINED: "DEFINED">
    | < DELETE: "DELETE" >
    | < DENY: "DENY" >
    | < DESC: "DESC" ("ENDING")? >
    | < DESTROY: "DESTROY">
    | < DETACH: "DETACH" >
    | < DOLLAR: "$">
    | < DISTINCT: "DISTINCT" >
    | < DIVIDE: "/" >
    | < DOT: "." >
    | < DOTDOT: ".." >
    | < DRIVER: "DRIVER" >
    | < DROP: "DROP" >
    | < DUMP: "DUMP" >
    | < EACH: "EACH" >
    | < ELEMENT: "ELEMENT" >
    | < ELEMENTS: "ELEMENTS" >
    | < ELSE: "ELSE" >
    | < ENCRYPTED: "ENCRYPTED" >
    | < END: "END" >
    | < ENDS: "ENDS" >
    | < EQ: "=" >
    | < EXECUTABLE: "EXECUTABLE" >
    | < EXIST: "EXIST" >
    | < EXISTENCE: "EXISTENCE" >
    | < EXISTS: "EXISTS" >
    | < EXTRACT: "EXTRACT" >
    | < FALSE: "false" >
    | < FIELDTERMINATOR: "FIELDTERMINATOR" >
    | < FILTER: "FILTER" >
    | < FOR: "FOR" >
    | < FOREACH: "FOREACH" >
    | < FROM: "FROM" >
    | < FULLTEXT: "FULLTEXT" >
    | < FUNCTION: "FUNCTION" >
    | < FUNCTIONS: "FUNCTIONS" >
    | < GE: ">=" >
    | < GRANT: "GRANT">
    | < GRAPH: "GRAPH" >
    | < GRAPHS: "GRAPHS" >
    | < GT: ">" >
    | < HEADERS: "HEADERS" >
    | < HOME: "HOME">
    | < IF: "IF" >
    | < IMPERSONATE: "IMPERSONATE" >
    | < IN: "IN" >
    | < INDEX: "INDEX" >
    | < INDEXES: "INDEXES" >
    | < IS: "IS" >
    | < JOIN: "JOIN" >
    | < KEY: "KEY" >
    | < LABEL: "LABEL" >
    | < LABELS: "LABELS" >
    | < LBRACKET: "[" >
    | < LCURLY: "{" >
    | < LE: "<=" >
    | < LIMITROWS: "LIMIT" >
    | < LOAD: "LOAD" >
    | < LOOKUP: "LOOKUP" >
    | < LPAREN: "(" >
    | < LT: "<" >
    | < MANAGEMENT: "MANAGEMENT" >
    | < MATCH: "MATCH" >
    | < MERGE: "MERGE" >
    | < MINUS: "-" >
    | < MODULO: "%" >
    | < NEQ: "!=" >
    | < NEQ2: "<>" >
    | < NAME: "NAME" >
    | < NAMES: "NAMES" >
    | < NEW: "NEW" >
    | < NODE: "NODE" >
    | < NODES: "NODES" >
    | < NONE: "NONE" >
    | < NOT: "NOT" >
    | < NOWAIT: "NOWAIT">
    | < NULL: "null">
    | < OF: "OF" >
    | < ON: "ON" >
    | < ONLY: "ONLY" >
    | < OPTIONAL: "OPTIONAL" >
    | < OPTIONS: "OPTIONS" >
    | < OR: "OR" >
    | < ORDER: "ORDER" >
    | < OUTPUT: "OUTPUT" >
    | < PASSWORD: "PASSWORD" >
    | < PASSWORDS: "PASSWORDS" >
    | < PERIODIC: "PERIODIC" >
    | < PLAINTEXT: "PLAINTEXT" >
    | < PLUS: "+" >
    | < POINT: "POINT">
    | < POPULATED: "POPULATED">
    | < POW: "^" >
    | < PRIVILEGE: "PRIVILEGE" >
    | < PRIVILEGES: "PRIVILEGES" >
    | < PROCEDURE: "PROCEDURE" >
    | < PROCEDURES: "PROCEDURES" >
    | < PROPERTY: "PROPERTY" >
    | < RANGE: "RANGE" >
    | < RBRACKET: "]" >
    | < RCURLY: "}" >
    | < READ: "READ" >
    | < REDUCE: "REDUCE" >
    | < RENAME: "RENAME" >
    | < REGEQ: "=~" >
    | < REL: "REL" >
    | < RELATIONSHIP: "RELATIONSHIP" >
    | < RELATIONSHIPS: "RELATIONSHIPS" >
    | < REMOVE: "REMOVE" >
    | < REPLACE: "REPLACE" >
    | < REQUIRE: "REQUIRE" >
    | < REQUIRED: "REQUIRED" >
    | < RETURN: "RETURN" >
    | < REVOKE: "REVOKE">
    | < ROLE: "ROLE">
    | < ROLES: "ROLES">
    | < ROW: "ROW">
    | < ROWS: "ROWS">
    | < RPAREN: ")" >
    | < SCAN: "SCAN" >
    | < SEC: "SEC">
    | < SECOND: "SECOND">
    | < SECONDS: "SECONDS">
    | < SEEK: "SEEK" >
    | < SET: "SET" >
    | < SHORTEST_PATH: "shortestPath" >
    | < SHOW: "SHOW">
    | < SINGLE: "SINGLE" >
    | < SKIPROWS: "SKIP" >
    | < START: "START">
    | < STARTS: "STARTS" >
    | < STATUS: "STATUS" >
    | < STOP: "STOP">
    | < SUSPENDED: "SUSPENDED">
    | < TARGET: "TARGET" >
    | < TERMINATE: "TERMINATE">
    | < TEXT: "TEXT">
    | < THEN: "THEN" >
    | < TIMES: "*" >
    | < TO: "TO" >
    | < TRANSACTION: "TRANSACTION" >
    | < TRANSACTIONS: "TRANSACTIONS" >
    | < TRAVERSE: "TRAVERSE" >
    | < TRUE: "true">
    | < TYPE: "TYPE">
    | < TYPES: "TYPES">
    | < UNION: "UNION" >
    | < UNIQUE: "UNIQUE" >
    | < UNWIND: "UNWIND" >
    | < USE: "USE" >
    | < USER: "USER">
    | < USERS: "USERS">
    | < USING: "USING" >
    | < VERBOSE: "VERBOSE" >
    | < WAIT: "WAIT">
    | < WHEN: "WHEN" >
    | < WHERE: "WHERE" >
    | < WITH: "WITH" >
    | < WRITE: "WRITE" >
    | < XOR: "XOR" >
    | < YIELD: "YIELD" >
}

/* IDENTIFIERS */

TOKEN :
{
    < IDENTIFIER:  ()* >
    | < #LETTER:
        [  // all chars for which Character.isIdentifierStart is true except `$`
            "\u0041"-"\u005a",
            "\u005f",
            "\u0061"-"\u007a",
            "\u00a2"-"\u00a5",
            "\u00aa",
            "\u00b5",
            "\u00ba",
            "\u00c0"-"\u00d6",
            "\u00d8"-"\u00f6",
            "\u00f8"-"\u02c1",
            "\u02c6"-"\u02d1",
            "\u02e0"-"\u02e4",
            "\u02ec",
            "\u02ee",
            "\u0370"-"\u0374",
            "\u0376"-"\u0377",
            "\u037a"-"\u037d",
            "\u037f",
            "\u0386",
            "\u0388"-"\u038a",
            "\u038c",
            "\u038e"-"\u03a1",
            "\u03a3"-"\u03f5",
            "\u03f7"-"\u0481",
            "\u048a"-"\u052f",
            "\u0531"-"\u0556",
            "\u0559",
            "\u0560"-"\u0588",
            "\u058f",
            "\u05d0"-"\u05ea",
            "\u05ef"-"\u05f2",
            "\u060b",
            "\u0620"-"\u064a",
            "\u066e"-"\u066f",
            "\u0671"-"\u06d3",
            "\u06d5",
            "\u06e5"-"\u06e6",
            "\u06ee"-"\u06ef",
            "\u06fa"-"\u06fc",
            "\u06ff",
            "\u0710",
            "\u0712"-"\u072f",
            "\u074d"-"\u07a5",
            "\u07b1",
            "\u07ca"-"\u07ea",
            "\u07f4"-"\u07f5",
            "\u07fa",
            "\u07fe"-"\u0815",
            "\u081a",
            "\u0824",
            "\u0828",
            "\u0840"-"\u0858",
            "\u0860"-"\u086a",
            "\u08a0"-"\u08b4",
            "\u08b6"-"\u08c7",
            "\u0904"-"\u0939",
            "\u093d",
            "\u0950",
            "\u0958"-"\u0961",
            "\u0971"-"\u0980",
            "\u0985"-"\u098c",
            "\u098f"-"\u0990",
            "\u0993"-"\u09a8",
            "\u09aa"-"\u09b0",
            "\u09b2",
            "\u09b6"-"\u09b9",
            "\u09bd",
            "\u09ce",
            "\u09dc"-"\u09dd",
            "\u09df"-"\u09e1",
            "\u09f0"-"\u09f3",
            "\u09fb"-"\u09fc",
            "\u0a05"-"\u0a0a",
            "\u0a0f"-"\u0a10",
            "\u0a13"-"\u0a28",
            "\u0a2a"-"\u0a30",
            "\u0a32"-"\u0a33",
            "\u0a35"-"\u0a36",
            "\u0a38"-"\u0a39",
            "\u0a59"-"\u0a5c",
            "\u0a5e",
            "\u0a72"-"\u0a74",
            "\u0a85"-"\u0a8d",
            "\u0a8f"-"\u0a91",
            "\u0a93"-"\u0aa8",
            "\u0aaa"-"\u0ab0",
            "\u0ab2"-"\u0ab3",
            "\u0ab5"-"\u0ab9",
            "\u0abd",
            "\u0ad0",
            "\u0ae0"-"\u0ae1",
            "\u0af1",
            "\u0af9",
            "\u0b05"-"\u0b0c",
            "\u0b0f"-"\u0b10",
            "\u0b13"-"\u0b28",
            "\u0b2a"-"\u0b30",
            "\u0b32"-"\u0b33",
            "\u0b35"-"\u0b39",
            "\u0b3d",
            "\u0b5c"-"\u0b5d",
            "\u0b5f"-"\u0b61",
            "\u0b71",
            "\u0b83",
            "\u0b85"-"\u0b8a",
            "\u0b8e"-"\u0b90",
            "\u0b92"-"\u0b95",
            "\u0b99"-"\u0b9a",
            "\u0b9c",
            "\u0b9e"-"\u0b9f",
            "\u0ba3"-"\u0ba4",
            "\u0ba8"-"\u0baa",
            "\u0bae"-"\u0bb9",
            "\u0bd0",
            "\u0bf9",
            "\u0c05"-"\u0c0c",
            "\u0c0e"-"\u0c10",
            "\u0c12"-"\u0c28",
            "\u0c2a"-"\u0c39",
            "\u0c3d",
            "\u0c58"-"\u0c5a",
            "\u0c60"-"\u0c61",
            "\u0c80",
            "\u0c85"-"\u0c8c",
            "\u0c8e"-"\u0c90",
            "\u0c92"-"\u0ca8",
            "\u0caa"-"\u0cb3",
            "\u0cb5"-"\u0cb9",
            "\u0cbd",
            "\u0cde",
            "\u0ce0"-"\u0ce1",
            "\u0cf1"-"\u0cf2",
            "\u0d04"-"\u0d0c",
            "\u0d0e"-"\u0d10",
            "\u0d12"-"\u0d3a",
            "\u0d3d",
            "\u0d4e",
            "\u0d54"-"\u0d56",
            "\u0d5f"-"\u0d61",
            "\u0d7a"-"\u0d7f",
            "\u0d85"-"\u0d96",
            "\u0d9a"-"\u0db1",
            "\u0db3"-"\u0dbb",
            "\u0dbd",
            "\u0dc0"-"\u0dc6",
            "\u0e01"-"\u0e30",
            "\u0e32"-"\u0e33",
            "\u0e3f"-"\u0e46",
            "\u0e81"-"\u0e82",
            "\u0e84",
            "\u0e86"-"\u0e8a",
            "\u0e8c"-"\u0ea3",
            "\u0ea5",
            "\u0ea7"-"\u0eb0",
            "\u0eb2"-"\u0eb3",
            "\u0ebd",
            "\u0ec0"-"\u0ec4",
            "\u0ec6",
            "\u0edc"-"\u0edf",
            "\u0f00",
            "\u0f40"-"\u0f47",
            "\u0f49"-"\u0f6c",
            "\u0f88"-"\u0f8c",
            "\u1000"-"\u102a",
            "\u103f",
            "\u1050"-"\u1055",
            "\u105a"-"\u105d",
            "\u1061",
            "\u1065"-"\u1066",
            "\u106e"-"\u1070",
            "\u1075"-"\u1081",
            "\u108e",
            "\u10a0"-"\u10c5",
            "\u10c7",
            "\u10cd",
            "\u10d0"-"\u10fa",
            "\u10fc"-"\u1248",
            "\u124a"-"\u124d",
            "\u1250"-"\u1256",
            "\u1258",
            "\u125a"-"\u125d",
            "\u1260"-"\u1288",
            "\u128a"-"\u128d",
            "\u1290"-"\u12b0",
            "\u12b2"-"\u12b5",
            "\u12b8"-"\u12be",
            "\u12c0",
            "\u12c2"-"\u12c5",
            "\u12c8"-"\u12d6",
            "\u12d8"-"\u1310",
            "\u1312"-"\u1315",
            "\u1318"-"\u135a",
            "\u1380"-"\u138f",
            "\u13a0"-"\u13f5",
            "\u13f8"-"\u13fd",
            "\u1401"-"\u166c",
            "\u166f"-"\u167f",
            "\u1681"-"\u169a",
            "\u16a0"-"\u16ea",
            "\u16ee"-"\u16f8",
            "\u1700"-"\u170c",
            "\u170e"-"\u1711",
            "\u1720"-"\u1731",
            "\u1740"-"\u1751",
            "\u1760"-"\u176c",
            "\u176e"-"\u1770",
            "\u1780"-"\u17b3",
            "\u17d7",
            "\u17db"-"\u17dc",
            "\u1820"-"\u1878",
            "\u1880"-"\u1884",
            "\u1887"-"\u18a8",
            "\u18aa",
            "\u18b0"-"\u18f5",
            "\u1900"-"\u191e",
            "\u1950"-"\u196d",
            "\u1970"-"\u1974",
            "\u1980"-"\u19ab",
            "\u19b0"-"\u19c9",
            "\u1a00"-"\u1a16",
            "\u1a20"-"\u1a54",
            "\u1aa7",
            "\u1b05"-"\u1b33",
            "\u1b45"-"\u1b4b",
            "\u1b83"-"\u1ba0",
            "\u1bae"-"\u1baf",
            "\u1bba"-"\u1be5",
            "\u1c00"-"\u1c23",
            "\u1c4d"-"\u1c4f",
            "\u1c5a"-"\u1c7d",
            "\u1c80"-"\u1c88",
            "\u1c90"-"\u1cba",
            "\u1cbd"-"\u1cbf",
            "\u1ce9"-"\u1cec",
            "\u1cee"-"\u1cf3",
            "\u1cf5"-"\u1cf6",
            "\u1cfa",
            "\u1d00"-"\u1dbf",
            "\u1e00"-"\u1f15",
            "\u1f18"-"\u1f1d",
            "\u1f20"-"\u1f45",
            "\u1f48"-"\u1f4d",
            "\u1f50"-"\u1f57",
            "\u1f59",
            "\u1f5b",
            "\u1f5d",
            "\u1f5f"-"\u1f7d",
            "\u1f80"-"\u1fb4",
            "\u1fb6"-"\u1fbc",
            "\u1fbe",
            "\u1fc2"-"\u1fc4",
            "\u1fc6"-"\u1fcc",
            "\u1fd0"-"\u1fd3",
            "\u1fd6"-"\u1fdb",
            "\u1fe0"-"\u1fec",
            "\u1ff2"-"\u1ff4",
            "\u1ff6"-"\u1ffc",
            "\u203f"-"\u2040",
            "\u2054",
            "\u2071",
            "\u207f",
            "\u2090"-"\u209c",
            "\u20a0"-"\u20bf",
            "\u2102",
            "\u2107",
            "\u210a"-"\u2113",
            "\u2115",
            "\u2119"-"\u211d",
            "\u2124",
            "\u2126",
            "\u2128",
            "\u212a"-"\u212d",
            "\u212f"-"\u2139",
            "\u213c"-"\u213f",
            "\u2145"-"\u2149",
            "\u214e",
            "\u2160"-"\u2188",
            "\u2c00"-"\u2c2e",
            "\u2c30"-"\u2c5e",
            "\u2c60"-"\u2ce4",
            "\u2ceb"-"\u2cee",
            "\u2cf2"-"\u2cf3",
            "\u2d00"-"\u2d25",
            "\u2d27",
            "\u2d2d",
            "\u2d30"-"\u2d67",
            "\u2d6f",
            "\u2d80"-"\u2d96",
            "\u2da0"-"\u2da6",
            "\u2da8"-"\u2dae",
            "\u2db0"-"\u2db6",
            "\u2db8"-"\u2dbe",
            "\u2dc0"-"\u2dc6",
            "\u2dc8"-"\u2dce",
            "\u2dd0"-"\u2dd6",
            "\u2dd8"-"\u2dde",
            "\u2e2f",
            "\u3005"-"\u3007",
            "\u3021"-"\u3029",
            "\u3031"-"\u3035",
            "\u3038"-"\u303c",
            "\u3041"-"\u3096",
            "\u309d"-"\u309f",
            "\u30a1"-"\u30fa",
            "\u30fc"-"\u30ff",
            "\u3105"-"\u312f",
            "\u3131"-"\u318e",
            "\u31a0"-"\u31bf",
            "\u31f0"-"\u31ff",
            "\u3400"-"\u4dbf",
            "\u4e00"-"\u9ffc",
            "\ua000"-"\ua48c",
            "\ua4d0"-"\ua4fd",
            "\ua500"-"\ua60c",
            "\ua610"-"\ua61f",
            "\ua62a"-"\ua62b",
            "\ua640"-"\ua66e",
            "\ua67f"-"\ua69d",
            "\ua6a0"-"\ua6ef",
            "\ua717"-"\ua71f",
            "\ua722"-"\ua788",
            "\ua78b"-"\ua7bf",
            "\ua7c2"-"\ua7ca",
            "\ua7f5"-"\ua801",
            "\ua803"-"\ua805",
            "\ua807"-"\ua80a",
            "\ua80c"-"\ua822",
            "\ua838",
            "\ua840"-"\ua873",
            "\ua882"-"\ua8b3",
            "\ua8f2"-"\ua8f7",
            "\ua8fb",
            "\ua8fd"-"\ua8fe",
            "\ua90a"-"\ua925",
            "\ua930"-"\ua946",
            "\ua960"-"\ua97c",
            "\ua984"-"\ua9b2",
            "\ua9cf",
            "\ua9e0"-"\ua9e4",
            "\ua9e6"-"\ua9ef",
            "\ua9fa"-"\ua9fe",
            "\uaa00"-"\uaa28",
            "\uaa40"-"\uaa42",
            "\uaa44"-"\uaa4b",
            "\uaa60"-"\uaa76",
            "\uaa7a",
            "\uaa7e"-"\uaaaf",
            "\uaab1",
            "\uaab5"-"\uaab6",
            "\uaab9"-"\uaabd",
            "\uaac0",
            "\uaac2",
            "\uaadb"-"\uaadd",
            "\uaae0"-"\uaaea",
            "\uaaf2"-"\uaaf4",
            "\uab01"-"\uab06",
            "\uab09"-"\uab0e",
            "\uab11"-"\uab16",
            "\uab20"-"\uab26",
            "\uab28"-"\uab2e",
            "\uab30"-"\uab5a",
            "\uab5c"-"\uab69",
            "\uab70"-"\uabe2",
            "\uac00"-"\ud7a3",
            "\ud7b0"-"\ud7c6",
            "\ud7cb"-"\ud7fb",
            "\uf900"-"\ufa6d",
            "\ufa70"-"\ufad9",
            "\ufb00"-"\ufb06",
            "\ufb13"-"\ufb17",
            "\ufb1d",
            "\ufb1f"-"\ufb28",
            "\ufb2a"-"\ufb36",
            "\ufb38"-"\ufb3c",
            "\ufb3e",
            "\ufb40"-"\ufb41",
            "\ufb43"-"\ufb44",
            "\ufb46"-"\ufbb1",
            "\ufbd3"-"\ufd3d",
            "\ufd50"-"\ufd8f",
            "\ufd92"-"\ufdc7",
            "\ufdf0"-"\ufdfc",
            "\ufe33"-"\ufe34",
            "\ufe4d"-"\ufe4f",
            "\ufe69",
            "\ufe70"-"\ufe74",
            "\ufe76"-"\ufefc",
            "\uff04",
            "\uff21"-"\uff3a",
            "\uff3f",
            "\uff41"-"\uff5a",
            "\uff66"-"\uffbe",
            "\uffc2"-"\uffc7",
            "\uffca"-"\uffcf",
            "\uffd2"-"\uffd7",
            "\uffda"-"\uffdc",
            "\uffe0"-"\uffe1",
            "\uffe5"-"\uffe6"
        ] >
    | < #PART_LETTER:
        [  // all chars for which Character.isIdentifierPart is true
            "\u0000"-"\u0008",
            "\u000e"-"\u001b",
            "\u0024",
            "\u0030"-"\u0039",
            "\u0041"-"\u005a",
            "\u005f",
            "\u0061"-"\u007a",
            "\u007f"-"\u009f",
            "\u00a2"-"\u00a5",
            "\u00aa",
            "\u00ad",
            "\u00b5",
            "\u00ba",
            "\u00c0"-"\u00d6",
            "\u00d8"-"\u00f6",
            "\u00f8"-"\u02c1",
            "\u02c6"-"\u02d1",
            "\u02e0"-"\u02e4",
            "\u02ec",
            "\u02ee",
            "\u0300"-"\u0374",
            "\u0376"-"\u0377",
            "\u037a"-"\u037d",
            "\u037f",
            "\u0386",
            "\u0388"-"\u038a",
            "\u038c",
            "\u038e"-"\u03a1",
            "\u03a3"-"\u03f5",
            "\u03f7"-"\u0481",
            "\u0483"-"\u0487",
            "\u048a"-"\u052f",
            "\u0531"-"\u0556",
            "\u0559",
            "\u0560"-"\u0588",
            "\u058f",
            "\u0591"-"\u05bd",
            "\u05bf",
            "\u05c1"-"\u05c2",
            "\u05c4"-"\u05c5",
            "\u05c7",
            "\u05d0"-"\u05ea",
            "\u05ef"-"\u05f2",
            "\u0600"-"\u0605",
            "\u060b",
            "\u0610"-"\u061a",
            "\u061c",
            "\u0620"-"\u0669",
            "\u066e"-"\u06d3",
            "\u06d5"-"\u06dd",
            "\u06df"-"\u06e8",
            "\u06ea"-"\u06fc",
            "\u06ff",
            "\u070f"-"\u074a",
            "\u074d"-"\u07b1",
            "\u07c0"-"\u07f5",
            "\u07fa",
            "\u07fd"-"\u082d",
            "\u0840"-"\u085b",
            "\u0860"-"\u086a",
            "\u08a0"-"\u08b4",
            "\u08b6"-"\u08c7",
            "\u08d3"-"\u0963",
            "\u0966"-"\u096f",
            "\u0971"-"\u0983",
            "\u0985"-"\u098c",
            "\u098f"-"\u0990",
            "\u0993"-"\u09a8",
            "\u09aa"-"\u09b0",
            "\u09b2",
            "\u09b6"-"\u09b9",
            "\u09bc"-"\u09c4",
            "\u09c7"-"\u09c8",
            "\u09cb"-"\u09ce",
            "\u09d7",
            "\u09dc"-"\u09dd",
            "\u09df"-"\u09e3",
            "\u09e6"-"\u09f3",
            "\u09fb"-"\u09fc",
            "\u09fe",
            "\u0a01"-"\u0a03",
            "\u0a05"-"\u0a0a",
            "\u0a0f"-"\u0a10",
            "\u0a13"-"\u0a28",
            "\u0a2a"-"\u0a30",
            "\u0a32"-"\u0a33",
            "\u0a35"-"\u0a36",
            "\u0a38"-"\u0a39",
            "\u0a3c",
            "\u0a3e"-"\u0a42",
            "\u0a47"-"\u0a48",
            "\u0a4b"-"\u0a4d",
            "\u0a51",
            "\u0a59"-"\u0a5c",
            "\u0a5e",
            "\u0a66"-"\u0a75",
            "\u0a81"-"\u0a83",
            "\u0a85"-"\u0a8d",
            "\u0a8f"-"\u0a91",
            "\u0a93"-"\u0aa8",
            "\u0aaa"-"\u0ab0",
            "\u0ab2"-"\u0ab3",
            "\u0ab5"-"\u0ab9",
            "\u0abc"-"\u0ac5",
            "\u0ac7"-"\u0ac9",
            "\u0acb"-"\u0acd",
            "\u0ad0",
            "\u0ae0"-"\u0ae3",
            "\u0ae6"-"\u0aef",
            "\u0af1",
            "\u0af9"-"\u0aff",
            "\u0b01"-"\u0b03",
            "\u0b05"-"\u0b0c",
            "\u0b0f"-"\u0b10",
            "\u0b13"-"\u0b28",
            "\u0b2a"-"\u0b30",
            "\u0b32"-"\u0b33",
            "\u0b35"-"\u0b39",
            "\u0b3c"-"\u0b44",
            "\u0b47"-"\u0b48",
            "\u0b4b"-"\u0b4d",
            "\u0b55"-"\u0b57",
            "\u0b5c"-"\u0b5d",
            "\u0b5f"-"\u0b63",
            "\u0b66"-"\u0b6f",
            "\u0b71",
            "\u0b82"-"\u0b83",
            "\u0b85"-"\u0b8a",
            "\u0b8e"-"\u0b90",
            "\u0b92"-"\u0b95",
            "\u0b99"-"\u0b9a",
            "\u0b9c",
            "\u0b9e"-"\u0b9f",
            "\u0ba3"-"\u0ba4",
            "\u0ba8"-"\u0baa",
            "\u0bae"-"\u0bb9",
            "\u0bbe"-"\u0bc2",
            "\u0bc6"-"\u0bc8",
            "\u0bca"-"\u0bcd",
            "\u0bd0",
            "\u0bd7",
            "\u0be6"-"\u0bef",
            "\u0bf9",
            "\u0c00"-"\u0c0c",
            "\u0c0e"-"\u0c10",
            "\u0c12"-"\u0c28",
            "\u0c2a"-"\u0c39",
            "\u0c3d"-"\u0c44",
            "\u0c46"-"\u0c48",
            "\u0c4a"-"\u0c4d",
            "\u0c55"-"\u0c56",
            "\u0c58"-"\u0c5a",
            "\u0c60"-"\u0c63",
            "\u0c66"-"\u0c6f",
            "\u0c80"-"\u0c83",
            "\u0c85"-"\u0c8c",
            "\u0c8e"-"\u0c90",
            "\u0c92"-"\u0ca8",
            "\u0caa"-"\u0cb3",
            "\u0cb5"-"\u0cb9",
            "\u0cbc"-"\u0cc4",
            "\u0cc6"-"\u0cc8",
            "\u0cca"-"\u0ccd",
            "\u0cd5"-"\u0cd6",
            "\u0cde",
            "\u0ce0"-"\u0ce3",
            "\u0ce6"-"\u0cef",
            "\u0cf1"-"\u0cf2",
            "\u0d00"-"\u0d0c",
            "\u0d0e"-"\u0d10",
            "\u0d12"-"\u0d44",
            "\u0d46"-"\u0d48",
            "\u0d4a"-"\u0d4e",
            "\u0d54"-"\u0d57",
            "\u0d5f"-"\u0d63",
            "\u0d66"-"\u0d6f",
            "\u0d7a"-"\u0d7f",
            "\u0d81"-"\u0d83",
            "\u0d85"-"\u0d96",
            "\u0d9a"-"\u0db1",
            "\u0db3"-"\u0dbb",
            "\u0dbd",
            "\u0dc0"-"\u0dc6",
            "\u0dca",
            "\u0dcf"-"\u0dd4",
            "\u0dd6",
            "\u0dd8"-"\u0ddf",
            "\u0de6"-"\u0def",
            "\u0df2"-"\u0df3",
            "\u0e01"-"\u0e3a",
            "\u0e3f"-"\u0e4e",
            "\u0e50"-"\u0e59",
            "\u0e81"-"\u0e82",
            "\u0e84",
            "\u0e86"-"\u0e8a",
            "\u0e8c"-"\u0ea3",
            "\u0ea5",
            "\u0ea7"-"\u0ebd",
            "\u0ec0"-"\u0ec4",
            "\u0ec6",
            "\u0ec8"-"\u0ecd",
            "\u0ed0"-"\u0ed9",
            "\u0edc"-"\u0edf",
            "\u0f00",
            "\u0f18"-"\u0f19",
            "\u0f20"-"\u0f29",
            "\u0f35",
            "\u0f37",
            "\u0f39",
            "\u0f3e"-"\u0f47",
            "\u0f49"-"\u0f6c",
            "\u0f71"-"\u0f84",
            "\u0f86"-"\u0f97",
            "\u0f99"-"\u0fbc",
            "\u0fc6",
            "\u1000"-"\u1049",
            "\u1050"-"\u109d",
            "\u10a0"-"\u10c5",
            "\u10c7",
            "\u10cd",
            "\u10d0"-"\u10fa",
            "\u10fc"-"\u1248",
            "\u124a"-"\u124d",
            "\u1250"-"\u1256",
            "\u1258",
            "\u125a"-"\u125d",
            "\u1260"-"\u1288",
            "\u128a"-"\u128d",
            "\u1290"-"\u12b0",
            "\u12b2"-"\u12b5",
            "\u12b8"-"\u12be",
            "\u12c0",
            "\u12c2"-"\u12c5",
            "\u12c8"-"\u12d6",
            "\u12d8"-"\u1310",
            "\u1312"-"\u1315",
            "\u1318"-"\u135a",
            "\u135d"-"\u135f",
            "\u1380"-"\u138f",
            "\u13a0"-"\u13f5",
            "\u13f8"-"\u13fd",
            "\u1401"-"\u166c",
            "\u166f"-"\u167f",
            "\u1681"-"\u169a",
            "\u16a0"-"\u16ea",
            "\u16ee"-"\u16f8",
            "\u1700"-"\u170c",
            "\u170e"-"\u1714",
            "\u1720"-"\u1734",
            "\u1740"-"\u1753",
            "\u1760"-"\u176c",
            "\u176e"-"\u1770",
            "\u1772"-"\u1773",
            "\u1780"-"\u17d3",
            "\u17d7",
            "\u17db"-"\u17dd",
            "\u17e0"-"\u17e9",
            "\u180b"-"\u180e",
            "\u1810"-"\u1819",
            "\u1820"-"\u1878",
            "\u1880"-"\u18aa",
            "\u18b0"-"\u18f5",
            "\u1900"-"\u191e",
            "\u1920"-"\u192b",
            "\u1930"-"\u193b",
            "\u1946"-"\u196d",
            "\u1970"-"\u1974",
            "\u1980"-"\u19ab",
            "\u19b0"-"\u19c9",
            "\u19d0"-"\u19d9",
            "\u1a00"-"\u1a1b",
            "\u1a20"-"\u1a5e",
            "\u1a60"-"\u1a7c",
            "\u1a7f"-"\u1a89",
            "\u1a90"-"\u1a99",
            "\u1aa7",
            "\u1ab0"-"\u1abd",
            "\u1abf"-"\u1ac0",
            "\u1b00"-"\u1b4b",
            "\u1b50"-"\u1b59",
            "\u1b6b"-"\u1b73",
            "\u1b80"-"\u1bf3",
            "\u1c00"-"\u1c37",
            "\u1c40"-"\u1c49",
            "\u1c4d"-"\u1c7d",
            "\u1c80"-"\u1c88",
            "\u1c90"-"\u1cba",
            "\u1cbd"-"\u1cbf",
            "\u1cd0"-"\u1cd2",
            "\u1cd4"-"\u1cfa",
            "\u1d00"-"\u1df9",
            "\u1dfb"-"\u1f15",
            "\u1f18"-"\u1f1d",
            "\u1f20"-"\u1f45",
            "\u1f48"-"\u1f4d",
            "\u1f50"-"\u1f57",
            "\u1f59",
            "\u1f5b",
            "\u1f5d",
            "\u1f5f"-"\u1f7d",
            "\u1f80"-"\u1fb4",
            "\u1fb6"-"\u1fbc",
            "\u1fbe",
            "\u1fc2"-"\u1fc4",
            "\u1fc6"-"\u1fcc",
            "\u1fd0"-"\u1fd3",
            "\u1fd6"-"\u1fdb",
            "\u1fe0"-"\u1fec",
            "\u1ff2"-"\u1ff4",
            "\u1ff6"-"\u1ffc",
            "\u200b"-"\u200f",
            "\u202a"-"\u202e",
            "\u203f"-"\u2040",
            "\u2054",
            "\u2060"-"\u2064",
            "\u2066"-"\u206f",
            "\u2071",
            "\u207f",
            "\u2090"-"\u209c",
            "\u20a0"-"\u20bf",
            "\u20d0"-"\u20dc",
            "\u20e1",
            "\u20e5"-"\u20f0",
            "\u2102",
            "\u2107",
            "\u210a"-"\u2113",
            "\u2115",
            "\u2119"-"\u211d",
            "\u2124",
            "\u2126",
            "\u2128",
            "\u212a"-"\u212d",
            "\u212f"-"\u2139",
            "\u213c"-"\u213f",
            "\u2145"-"\u2149",
            "\u214e",
            "\u2160"-"\u2188",
            "\u2c00"-"\u2c2e",
            "\u2c30"-"\u2c5e",
            "\u2c60"-"\u2ce4",
            "\u2ceb"-"\u2cf3",
            "\u2d00"-"\u2d25",
            "\u2d27",
            "\u2d2d",
            "\u2d30"-"\u2d67",
            "\u2d6f",
            "\u2d7f"-"\u2d96",
            "\u2da0"-"\u2da6",
            "\u2da8"-"\u2dae",
            "\u2db0"-"\u2db6",
            "\u2db8"-"\u2dbe",
            "\u2dc0"-"\u2dc6",
            "\u2dc8"-"\u2dce",
            "\u2dd0"-"\u2dd6",
            "\u2dd8"-"\u2dde",
            "\u2de0"-"\u2dff",
            "\u2e2f",
            "\u3005"-"\u3007",
            "\u3021"-"\u302f",
            "\u3031"-"\u3035",
            "\u3038"-"\u303c",
            "\u3041"-"\u3096",
            "\u3099"-"\u309a",
            "\u309d"-"\u309f",
            "\u30a1"-"\u30fa",
            "\u30fc"-"\u30ff",
            "\u3105"-"\u312f",
            "\u3131"-"\u318e",
            "\u31a0"-"\u31bf",
            "\u31f0"-"\u31ff",
            "\u3400"-"\u4dbf",
            "\u4e00"-"\u9ffc",
            "\ua000"-"\ua48c",
            "\ua4d0"-"\ua4fd",
            "\ua500"-"\ua60c",
            "\ua610"-"\ua62b",
            "\ua640"-"\ua66f",
            "\ua674"-"\ua67d",
            "\ua67f"-"\ua6f1",
            "\ua717"-"\ua71f",
            "\ua722"-"\ua788",
            "\ua78b"-"\ua7bf",
            "\ua7c2"-"\ua7ca",
            "\ua7f5"-"\ua827",
            "\ua82c",
            "\ua838",
            "\ua840"-"\ua873",
            "\ua880"-"\ua8c5",
            "\ua8d0"-"\ua8d9",
            "\ua8e0"-"\ua8f7",
            "\ua8fb",
            "\ua8fd"-"\ua92d",
            "\ua930"-"\ua953",
            "\ua960"-"\ua97c",
            "\ua980"-"\ua9c0",
            "\ua9cf"-"\ua9d9",
            "\ua9e0"-"\ua9fe",
            "\uaa00"-"\uaa36",
            "\uaa40"-"\uaa4d",
            "\uaa50"-"\uaa59",
            "\uaa60"-"\uaa76",
            "\uaa7a"-"\uaac2",
            "\uaadb"-"\uaadd",
            "\uaae0"-"\uaaef",
            "\uaaf2"-"\uaaf6",
            "\uab01"-"\uab06",
            "\uab09"-"\uab0e",
            "\uab11"-"\uab16",
            "\uab20"-"\uab26",
            "\uab28"-"\uab2e",
            "\uab30"-"\uab5a",
            "\uab5c"-"\uab69",
            "\uab70"-"\uabea",
            "\uabec"-"\uabed",
            "\uabf0"-"\uabf9",
            "\uac00"-"\ud7a3",
            "\ud7b0"-"\ud7c6",
            "\ud7cb"-"\ud7fb",
            "\uf900"-"\ufa6d",
            "\ufa70"-"\ufad9",
            "\ufb00"-"\ufb06",
            "\ufb13"-"\ufb17",
            "\ufb1d"-"\ufb28",
            "\ufb2a"-"\ufb36",
            "\ufb38"-"\ufb3c",
            "\ufb3e",
            "\ufb40"-"\ufb41",
            "\ufb43"-"\ufb44",
            "\ufb46"-"\ufbb1",
            "\ufbd3"-"\ufd3d",
            "\ufd50"-"\ufd8f",
            "\ufd92"-"\ufdc7",
            "\ufdf0"-"\ufdfc",
            "\ufe00"-"\ufe0f",
            "\ufe20"-"\ufe2f",
            "\ufe33"-"\ufe34",
            "\ufe4d"-"\ufe4f",
            "\ufe69",
            "\ufe70"-"\ufe74",
            "\ufe76"-"\ufefc",
            "\ufeff",
            "\uff04",
            "\uff10"-"\uff19",
            "\uff21"-"\uff3a",
            "\uff3f",
            "\uff41"-"\uff5a",
            "\uff66"-"\uffbe",
            "\uffc2"-"\uffc7",
            "\uffca"-"\uffcf",
            "\uffd2"-"\uffd7",
            "\uffda"-"\uffdc",
            "\uffe0"-"\uffe1",
            "\uffe5"-"\uffe6",
            "\ufff9"-"\ufffb"
        ] >
}

TOKEN :
{
    < ARROW_LINE: ["\u002d", "\u00ad", "\u2010", "\u2011", "\u2012", "\u2013", "\u2014", "\u2015", "\ufe58", "\ufe63", "\uff0d"] >
    | < ARROW_LEFT_HEAD: ["\u27e8", "\u3008", "\ufe64", "\uff1c"] >
    | < ARROW_RIGHT_HEAD: ["\u27e9", "\u3009", "\ufe65", "\uff1e"] >
}

<*> TOKEN :
{
    < UNKNOWN: ~[",", ":", ";", " ", "\t", "\n", "\r"] >
}

/** Root production. */
List Statements() throws Exception :
{
    STATEMENT x;
    List stmts = new ArrayList<>();
}
{
    try {
        x=Statement() { stmts.add( x ); }
        ( LOOKAHEAD(2) ";" x=Statement() { stmts.add( x ); } )* ( LOOKAHEAD(2) ";" )? 
        {
            return stmts;
        }
    } catch ( ParseException e ) {
        Token t = e.currentToken.next;
        if ( e.getMessage().contains( "Encountered \"\"" ) )
        {
            throw exceptionFactory.syntaxException( t.image, ParseExceptions.expected( e.expectedTokenSequences, e.tokenImage ), e,
                                                   t.endOffset + 1, t.endLine, t.endColumn + 1 );
        }
        else
        {
            throw exceptionFactory.syntaxException( t.image, ParseExceptions.expected( e.expectedTokenSequences, e.tokenImage ), e,
                                                   t.beginOffset, t.beginLine, t.beginColumn );
        }
    } catch ( InvalidUnicodeLiteral e ) {
        throw exceptionFactory.syntaxException( e, e.offset, e.line, e.column );
    }
}

STATEMENT Statement() throws Exception:
{
    STATEMENT statement;
    USE_CLAUSE useClause = null;
}
{
    (
        statement=PeriodicCommitQuery()
        | useClause=UseClause() statement=SingleQueryOrCommandWithUseClause(useClause)
        | statement=SingleQueryOrCommand()
    )
    {
        return statement;
    }
}

STATEMENT SingleQueryOrCommand() throws Exception:
{
    STATEMENT statement = null;
    QUERY query = null;
    boolean hasCatalog = false;
}
{
    (
        LOOKAHEAD(2) ( { hasCatalog = true; })? statement=CreateCommand( null ) // CREATE admin thing vs CREATE graph thing
        | ( { hasCatalog = true; })? statement=Command( null )
        | query=SingleQuery() ( query=Union(query) )*
    )
    {
        if ( query != null )
        {
            return query;
        }
        return hasCatalog ? astFactory.hasCatalog( statement ) : statement;
    }
}

STATEMENT SingleQueryOrCommandWithUseClause( USE_CLAUSE useClause ) throws Exception:
{
    STATEMENT statement = null;
    QUERY query = null;
    boolean hasCatalog = false;
}
{
    (
        LOOKAHEAD(2) ( { hasCatalog = true; })? statement=CreateCommand( useClause ) // CREATE admin thing vs CREATE graph thing
        | ( { hasCatalog = true; })? statement=Command( useClause )
        | query=SingleQueryWithUseClause( useClause ) ( query=Union(query) )*
    )
    {
        if ( query != null )
        {
            return query;
        }
        return hasCatalog ? astFactory.hasCatalog( statement ) : statement;
    }
}

QUERY PeriodicCommitQuery() :
{
    Token t;
    Token tPeriodicCommit;
    Token batchSize = null;
    CLAUSE loadCsv;
    List queryBody;
}
{
    t= tPeriodicCommit=  ( batchSize= )?
    loadCsv=LoadCSVClause()
    queryBody=PeriodicCommitQueryBody()
    {
        return astFactory.periodicCommitQuery( pos( t ), pos( tPeriodicCommit ), batchSize == null ? null : batchSize.image, loadCsv, queryBody );
    }
}

List PeriodicCommitQueryBody() :
{
    CLAUSE x;
    List clauses = new ArrayList<>();
}
{
    ( x=Clause() { clauses.add( x ); } )*
    {
        return clauses;
    }
}

QUERY RegularQuery() :
{
    QUERY x;
}
{
    x=SingleQuery() ( x=Union(x) )*
    {
        return x;
    }
}

QUERY Union( QUERY lhs ) :
{
    Token t;
    QUERY rhs;
    boolean all = false;
}
{
    t= (  { all = true; } )? rhs=SingleQuery()
    {
        return astFactory.newUnion( pos( t ), lhs, rhs, all );
    }
}

QUERY SingleQuery() :
{
    CLAUSE x;
    List clauses = new ArrayList<>();
}
{
    ( x=Clause() { clauses.add( x ); } )+
    {
        return astFactory.newSingleQuery( clauses );
    }
}

QUERY SingleQueryWithUseClause( CLAUSE useClause ) :
{
    CLAUSE x;
    List clauses = new ArrayList<>();
    if ( useClause != null )
    {
      clauses.add( useClause );
    }
}
{
    ( x=Clause() { clauses.add( x ); } )*
    {
        return astFactory.newSingleQuery( clauses );
    }
}

CLAUSE Clause() :
{
    CLAUSE x = null;
}
{
    (
        x=UseClause()
        | x=ReturnClause()
        | x=CreateClause() // because create index/constraint
        | x=DeleteClause()
        | x=SetClause()
        | x=RemoveClause()
        | x=MatchClause()
        | x=MergeClause()
        | x=WithClause()
        | x=UnwindClause()
        | LOOKAHEAD(2) x=CallClause() // because subqueries also start with CALL
        | x=SubqueryClause()
        | x=LoadCSVClause()
        | x=ForeachClause()
    )
    {
        return x;
    }
}

// USE

USE_CLAUSE UseClause() :
{
    Token t;
    EXPRESSION e;
}
{
    t= ( LOOKAHEAD( 2 )  )? e=Expression()
    {
        return astFactory.useClause(  pos( t ), e );
    }
}

// RETURN

RETURN_CLAUSE ReturnClause() :
{
    Token t;
    RETURN_CLAUSE clause = null;
}
{
    t=
    clause=ReturnBody( t )
    {
        return clause;
    }
}

RETURN_CLAUSE ReturnBody( Token t ) :
{
    Token skipPosition = null;
    Token limitPosition = null;
    boolean distinct = false;
    List order = new ArrayList<>();
    Token orderPos = null;
    EXPRESSION skip = null;
    EXPRESSION limit = null;
    ORDER_ITEM o = null;
    RETURN_ITEM x;
    RETURN_ITEMS returnItems;
}
{
    ( LOOKAHEAD( 2 )  { distinct = true; } )?
    ( returnItems=ReturnItems() )
    ( orderPos=  o=OrderItem() { order.add( o ); } ( "," o=OrderItem() {order.add( o ); } )* )? ( { skipPosition=token.next; } skip=Skip() )? ( { limitPosition=token.next; } limit=Limit() )?
    {
        return astFactory.newReturnClause(  pos( t ), distinct, returnItems, order, pos( orderPos ), skip, pos( skipPosition ), limit, pos( limitPosition ) );
    }
}

RETURN_ITEM ReturnItem() :
{
    EXPRESSION e;
    VARIABLE v = null;
    Token eStart;
    Token eEnd;
}
{
    { eStart = token; }
    e=Expression() { eEnd = token; } (  v=Variable() )?
    {
        if ( v != null )
        {
            return astFactory.newReturnItem( pos( eStart.next ), e, v );
        }
        else
        {
            return astFactory.newReturnItem( pos( eStart.next ), e, eStart.next.beginOffset, eEnd.endOffset );
        }
    }
}

RETURN_ITEMS ReturnItems() :
{
    Token returnItemsPosition;
    RETURN_ITEM x;
    List returnItems = new ArrayList<>();
    boolean returnAll = false;
}
{
    { returnItemsPosition = token; }
    (
         { returnAll = true; } ( "," x=ReturnItem() { returnItems.add( x ); } )*
        | x=ReturnItem() { returnItems.add( x ); } ( "," x=ReturnItem() { returnItems.add( x ); } )*
    ) {
        return astFactory.newReturnItems( pos( returnItemsPosition.next ), returnAll, returnItems );
    }
}

ORDER_ITEM OrderItem() :
{
    Token t;
    EXPRESSION e;
}
{
    {t = token;}
    e=Expression()
    (
         { return astFactory.orderDesc( pos( t.next ), e ); }
        | (  )? { return astFactory.orderAsc( pos( t.next ), e ); }
    )
}

EXPRESSION Skip() :
{
    EXPRESSION e;
}
{
     e=Expression()
    {
        return e;
    }
}

EXPRESSION Limit() :
{
    EXPRESSION e; }
{
     e=Expression()
    {
        return e;
    }
}

// WHERE

WHERE WhereClause() :
{
    Token t;
    EXPRESSION e;
}
{
    t= e=Expression()
    {
        return astFactory.whereClause( pos( t ), e );
    }
}

// WITH

CLAUSE WithClause() :
{
    Token t;
    RETURN_CLAUSE returnClause;
    WHERE where = null;
}
{
    t= returnClause=ReturnBody( t ) ( where=WhereClause() )?
    {
        return astFactory.withClause( pos( t ), returnClause, where );
    }
}

// CREATE

CLAUSE CreateClause() :
{
    Token t;
    List patterns;
}
{
    t= patterns=PatternList()
    {
        return astFactory.createClause( pos( t ), patterns );
    }
}

// SET

SET_CLAUSE SetClause() :
{
    Token t;
    SET_ITEM item;
    List items = new ArrayList<>();
}
{
    t= item=SetItem() { items.add( item ); } ( "," item=SetItem() { items.add( item ); } )*
    {
        return astFactory.setClause( pos( t ), items );
    }
}

SET_ITEM SetItem() :
{
    EXPRESSION e;
    PROPERTY p;
    VARIABLE v;
    List> labels;
}
{
    LOOKAHEAD( 2 ) p=PropertyExpression()  e=Expression() { return astFactory.setProperty( p, e ); }
    | LOOKAHEAD( 2 ) v=Variable()  e=Expression() { return astFactory.setVariable( v, e ); }
    | LOOKAHEAD( 2 ) v = Variable() "+=" e=Expression() { return astFactory.addAndSetVariable( v, e ); }
    | v = Variable() labels = NodeLabels() { return astFactory.setLabels( v, labels ); }
}

// REMOVE

CLAUSE RemoveClause() :
{
    Token t;
    REMOVE_ITEM item;
    List items = new ArrayList<>();
}
{
    t= item=RemoveItem() { items.add( item ); } ( "," item=RemoveItem() { items.add( item ); })*
    {
        return astFactory.removeClause( pos( t ), items );
    }
}

REMOVE_ITEM RemoveItem() :
{
    EXPRESSION e;
    PROPERTY p;
    VARIABLE v;
    List> labels;
}
{
    LOOKAHEAD(2) p=PropertyExpression() { return astFactory.removeProperty( p ); }
    | v=Variable() labels=NodeLabels() { return astFactory.removeLabels( v, labels ); }
}

// DELETE

CLAUSE DeleteClause() :
{
    Token detachT = null;
    Token t;
    boolean detach = false;
    EXPRESSION e;
    List list = new ArrayList<>();
}
{
    ( detachT= { detach = true; } )? t= e=Expression() {list.add( e );} ( "," e=Expression() { list.add( e ); } )*
    {
        return astFactory.deleteClause( pos( detachT != null ? detachT : t ), detach, list );
    }
}

// MATCH

CLAUSE MatchClause() :
{
    Token optionalT = null;
    Token t;
    Token whereToken = null;
    boolean optional = false;
    List patterns;
    List hints;
    WHERE where = null;
}
{
    ( optionalT= { optional = true; } )? t= patterns=PatternList() hints=Hints() ( where=WhereClause() )?
    {
        return astFactory.matchClause( pos( optionalT != null ? optionalT : t ), optional, patterns, pos( t.next ), hints, where );
    }
}

List Hints() :
{
    Token t;
    boolean seek;
    VARIABLE v;
    Token labelOrRelType;
    List joinVariables;
    HINT hint;
    List hints = null;
}
{
    ( t=
        (
               hint = IndexHintBody( HintIndexType.ANY, pos( t ) )
            |   hint = IndexHintBody( HintIndexType.BTREE, pos( t ) )
            |   hint = IndexHintBody( HintIndexType.TEXT, pos( t ) )
            |   joinVariables=VariableList1() { hint = astFactory.usingJoin( pos( t ), joinVariables ); }
            |  v=Variable() labelOrRelType=LabelOrRelType() { hint = astFactory.usingScan( pos( t ), v, labelOrRelType.image ); }
        )
        {
            if ( hints == null )
            {
                hints = new ArrayList<>();
            }
            hints.add( hint );
        }
    )*
    {
        return hints;
    }
}

HINT IndexHintBody( HintIndexType indexType, POS p ) :
{
    boolean seek = false;
    VARIABLE v;
    Token labelOrRelType;
    List propNames;
}
{
    ( LOOKAHEAD( 2 )  { seek = true; } )? v=Variable() labelOrRelType=LabelOrRelType()  propNames=SymbolicNameList1() 
    {
        return astFactory.usingIndexHint( p, v, labelOrRelType.image, propNames, seek, indexType);
    }
}

// MERGE

CLAUSE MergeClause() :
{
    Token t;
    Token onToken;
    PATTERN p;
    SET_CLAUSE c;
    ArrayList clauses = new ArrayList<>();
    ArrayList positions = new ArrayList<>();
    ArrayList actionTypes = new ArrayList<>();
}
{
    t= p=Pattern()
    (
        onToken =  (
             c=SetClause() { clauses.add( c ); actionTypes.add( ASTFactory.MergeActionType.OnMatch ); positions.add( pos( onToken ) ); }
            |  c=SetClause() { clauses.add( c ); actionTypes.add( ASTFactory.MergeActionType.OnCreate ); positions.add( pos( onToken ) ); }
        )
    )*
    {
        return astFactory.mergeClause( pos( t ), p, clauses, actionTypes, positions );
    }
}

// UNWIND

CLAUSE UnwindClause() :
{
    Token t;
    EXPRESSION e;
    VARIABLE v;}
{
    t= e=Expression()  v=Variable()
    {
        return astFactory.unwindClause( pos( t ), e, v );
    }
}

// CALL

CLAUSE CallClause() :
{
    Token t;
    Token procedureNamePosition;
    Token procedureResultPosition = null;
    List namespace;
    String name;
    EXPRESSION e;
    List arguments = null;
    boolean yieldAll = false;
    CALL_RESULT_ITEM x;
    List items = null;
    WHERE where = null;
}
{
    t= namespace=Namespace() {procedureNamePosition = token;} name=ProcedureName()
    (  { arguments = new ArrayList<>(); }
        ( LOOKAHEAD( 2 ) e=Expression() { arguments.add( e ); })? ( "," e=Expression() { arguments.add( e ); })*
        
    )?
    ( procedureResultPosition= (
         { yieldAll = true; }
        | { items = new ArrayList<>(); }
            x=ProcedureResultItem() { items.add( x ); }
            ( "," x=ProcedureResultItem() { items.add( x ); })*
            ( where=WhereClause() )?
        )
    )?
    {
        return astFactory.callClause( pos( t ),
                                     pos( t.next ),
                                     pos( procedureNamePosition.next ),
                                     pos( procedureResultPosition ),
                                     namespace,
                                     name,
                                     arguments,
                                     yieldAll,
                                     items,
                                     where );
    }
}

String ProcedureName() :
{
    Token t;
}
{
    t=SymbolicNameString()
    {
        return t.image;
    }
}

CALL_RESULT_ITEM ProcedureResultItem() :
{
    Token t;
    VARIABLE v = null;
}
{
    t=SymbolicNameString() (  v=Variable() )?
    {
        return astFactory.callResultItem( pos( t ), t.image,  v );
    }
}

// LOAD CSV

CLAUSE LoadCSVClause() :
{
    Token t;
    boolean headers = false;
    EXPRESSION source;
    VARIABLE v;
    Token sep = null;
}
{
    t= 
    (   { headers = true; } )?
     source=Expression()  v=Variable()
    (  ( sep=StringToken() ) )?
    {
        return astFactory.loadCsvClause( pos( t ), headers, source, v, sep == null ? null : sep.image );
    }
}

// FOREACH

CLAUSE ForeachClause() :
{
    Token t;
    VARIABLE v;
    EXPRESSION list;
    CLAUSE c;
    List clauses = new ArrayList<>();
}
{
    t=  v=Variable()  list=Expression() 
    ( c=Clause() { clauses.add( c ); } )+
    
    {
        return astFactory.foreachClause( pos( t ), v, list, clauses );
    }
}

CLAUSE SubqueryClause() :
{
    Token t;
    QUERY q;
    SUBQUERY_IN_TRANSACTIONS_PARAMETERS inTransactionsParams = null;
}
{
    t=
    
    ( q=PeriodicCommitQuery() | q=RegularQuery() )
    
    ( inTransactionsParams = SubqueryInTransactionsParameters() )?
    {
        return astFactory.subqueryClause( pos( t ), q, inTransactionsParams );
    }
}

SUBQUERY_IN_TRANSACTIONS_PARAMETERS SubqueryInTransactionsParameters() :
{
    Token t;
    EXPRESSION batchSize = null;
}
{
    t= 
    ( batchSize=Expression() ( | ))?
    {
        return astFactory.subqueryInTransactionsParams( pos( t ), batchSize );
    }
}

// PATTERN

List PatternList() :
{
    PATTERN p;
    List patterns = new ArrayList<>();
}
{
    p=Pattern() { patterns.add( p ); } ( "," p=Pattern() { patterns.add( p ); } )*
    {
        return patterns;
    }
}

PATTERN Pattern() :
{
    VARIABLE v;
    PATTERN p;
}
{
    LOOKAHEAD( 2 ) v=Variable()  p=AnonymousPattern() { return astFactory.namedPattern( v, p ); }
    | p=AnonymousPattern() { return p; }
}

PATTERN AnonymousPattern() :
{
    PATTERN p;
}
{
    (
        p=ShortestPathPattern()
        | LOOKAHEAD( 3 ) p=EveryPathPattern()
        |  p=AnonymousPattern() 
    )
    {
        return p;
    }
}

PATTERN ShortestPathPattern() :
{
    Token t;
    PATTERN p;
}
{
    t=  p=EveryPathPattern()  { return astFactory.shortestPathPattern( pos( t ), p ); }
    | t=  p=EveryPathPattern()  { return astFactory.allShortestPathsPattern( pos( t ), p ); }
}

PATTERN EveryPathPattern() :
{
    NODE_PATTERN n;
    REL_PATTERN r;
    List relationships = new ArrayList<>();
    List nodes = new ArrayList<>();
}
{
    n=NodePattern() { nodes.add( n ); }
    (
        LOOKAHEAD( 2 ) r=RelationshipPattern() { relationships.add( r ); }
        n=NodePattern() { nodes.add( n ); }
    )*
    {
        return astFactory.everyPathPattern( nodes, relationships );
    }
}

PATTERN EveryPathPatternNonEmpty() :
{
    NODE_PATTERN n;
    REL_PATTERN r;
    List relationships = new ArrayList<>();
    List nodes = new ArrayList<>();
}
{
    n=NodePattern() { nodes.add( n ); }
    (
        LOOKAHEAD( 2 ) r=RelationshipPattern() {relationships.add( r );}
        n=NodePattern() { nodes.add( n ); }
    )+
    {
        return astFactory.everyPathPattern( nodes, relationships );
    }
}

NODE_PATTERN NodePattern() :
{
    Token t;
    VARIABLE v = null;
    List> labels = new ArrayList<>();
    EXPRESSION properties = null;
    EXPRESSION predicate = null;
}
{
    t=
    (
        v=Variable() [labels=NodeLabels()] [properties=Properties()] [ predicate=Expression()]
        | [labels=NodeLabels()] [properties=Properties()]
    )
    
    {
        return astFactory.nodePattern( pos( t ), v, labels, properties, predicate );
    }
}

List> NodeLabels() :
{
    Token label;
    List> labels = new ArrayList<>();
}
{
    ( LOOKAHEAD( 2 ) label=LabelOrRelType() { labels.add( new StringPos<>( label.image, pos( label ) ) ); } )+
    {
        return labels;
    }
}

EXPRESSION HasLabels(EXPRESSION subject) :
{
    List> labels;
}
{
    labels=NodeLabels()
    {
        return astFactory.hasLabelsOrTypes( subject, labels );
    }
}

Token LabelOrRelType() :
{
    Token t;
}
{
    ":" t=SymbolicNameString()
    {
        return t;
    }
}

List> LabelOrRelTypes() :
{
    List> labels = new ArrayList<>();
    StringPos label;
}
{
    ":" SymbolicNameString() { labels.add( new StringPos( token.image, pos(token) ) ); }
    (  SymbolicNameString() { labels.add( new StringPos( token.image, pos(token) ) ); } )*
    {
        return labels;
    }
}

EXPRESSION Properties() :
{
    EXPRESSION e;
}
{
    (
        LOOKAHEAD( 3 ) e=MapLiteral()
        | e=Parameter( ParameterType.ANY )
        | e=OldParameter()
    )
    {
        return e;
    }
}

REL_PATTERN RelationshipPattern() :
{
    Token firstToken = token.next;
    Token t;
    boolean left = false;
    boolean right = false;
    VARIABLE v = null;
    List> relTypes = new ArrayList<>();
    boolean legacyTypeSeparator = false;
    PATH_LENGTH pathLength = null;
    EXPRESSION properties = null;
}
{
    ( LeftArrow() { left = true; })? ArrowLine()
    (  ( v=Variable() )?
        ( ":" t=SymbolicNameString()
            {
                relTypes = new ArrayList<>();
                relTypes.add(new StringPos<>( t.image,  pos( t ) ) );
            }
            (  ( ":" {legacyTypeSeparator = true; })? t=SymbolicNameString() { relTypes.add( new StringPos<>( t.image,  pos( t ) ) ); })*
        )?
        ( pathLength=PathLength() )?
        ( properties=Properties() )?
        
    )?
    ArrowLine() ( RightArrow() { right = true; } )?
    {
        return astFactory.relationshipPattern( pos( firstToken ), left, right, v, relTypes, pathLength, properties, legacyTypeSeparator );
    }
}

void LeftArrow() :
{}
{
   | 
}

void ArrowLine() :
{}
{
   | 
}

void RightArrow() :
{}
{
   | 
}

PATH_LENGTH PathLength() :
{
    Token t;
    PATH_LENGTH p = null;
}
{
    t= ( p=PathLengthLiteral( t ) )?
    {
        return p == null ? astFactory.pathLength( pos( t ), null, null, null, null ) : p;
    }
}

PATH_LENGTH PathLengthLiteral( Token t ) :
{
    Token v1 = null;
    Token v2 = null;
}
{
    LOOKAHEAD( 2 ) ( v1= )? t= ( v2= )?
        {
            return astFactory.pathLength( pos( t ), v1 == null ? null : pos ( v1 ), v2 == null ? null : pos ( v2 ),  v1 == null ? "" : v1.image, v2 == null ? "" : v2.image );
        }
    | v1=
        {
            String v = v1 == null ? "" : v1.image;
            return astFactory.pathLength( pos( t ), v1 == null ? null : pos ( v1 ), v1 == null ? null : pos ( v1 ), v, v);
        }
}

// EXPRESSIONS

EXPRESSION Expression() :
{
    EXPRESSION e;
}
{
    e=Expression12()
    {
        return e;
    }
}

EXPRESSION Expression12() :
{
    Token t;
    EXPRESSION e;
    EXPRESSION temp;
}
{
    e=Expression11() ( t= temp=Expression11() { e = astFactory.or( pos( t ), e, temp ); } )*
    {
        return e;
    }
}

EXPRESSION Expression11() :
{
    Token t;
    EXPRESSION e;
    EXPRESSION temp;
}
{
    e=Expression10() ( t= temp=Expression10() { e = astFactory.xor( pos( t ), e, temp ); } )*
    {
        return e;
    }
}

EXPRESSION Expression10() :
{
    Token t;
    EXPRESSION e;
    EXPRESSION temp;
}
{
    e=Expression9() (t= temp=Expression9() { e = astFactory.and( pos( t ), e, temp ); } )*
    {
        return e;
    }
}

EXPRESSION Expression9() :
{
    Token t;
    EXPRESSION e;
}
{
    (
        LOOKAHEAD( 3 ) t= e=Expression9() { e = astFactory.not( pos( t ), e ); }
        | e=Expression8()
    )
    {
        return e;
    }
}

EXPRESSION Expression8() :
{
    Token t;
    EXPRESSION e;
    EXPRESSION lhs;
    EXPRESSION rhs;
    List expressions = new ArrayList();
}
{
    e=Expression7() { lhs = e; } (
        LOOKAHEAD( 2 ) t=  rhs=Expression7() { expressions.add( astFactory.eq( pos( t ), lhs, rhs)); lhs = rhs; }
        | t= rhs=Expression7() { expressions.add( astFactory.neq( pos( t ), lhs, rhs ) ); lhs = rhs; }
        | t= rhs=Expression7() { expressions.add( astFactory.neq2( pos( t ), lhs, rhs ) ); lhs = rhs; }
        | t= rhs=Expression7() { expressions.add( astFactory.lte( pos( t ), lhs, rhs ) ); lhs = rhs; }
        | t= rhs=Expression7() { expressions.add( astFactory.gte( pos( t ), lhs, rhs ) ); lhs = rhs; }
        | t= rhs=Expression7() { expressions.add( astFactory.lt( pos( t ), lhs, rhs ) ); lhs = rhs; }
        | t= rhs=Expression7() { expressions.add( astFactory.gt( pos( t ), lhs, rhs ) ); lhs = rhs; }
    )*
    {
        if ( expressions.isEmpty() )
        {
            return e;
        }
        else if ( expressions.size() == 1 )
        {
            return expressions.get( 0 );
        }
        else
        {
            return astFactory.ands( expressions );
        }
    }
}

EXPRESSION Expression7() :
{
    EXPRESSION e;
}
{
    e=Expression6() ( e=ComparisonExpression6( e ) )?
    {
        return e;
    }
}

EXPRESSION ComparisonExpression6( EXPRESSION lhs ) :
{
    Token t;
    EXPRESSION rhs;
}
{
    LOOKAHEAD( 2 ) t= rhs=Expression6() { return astFactory.regeq( pos( t ), lhs, rhs ); }
    | t=  rhs=Expression6() { return astFactory.startsWith( pos( t ), lhs, rhs ); }
    | t=  rhs=Expression6() { return astFactory.endsWith( pos( t ), lhs, rhs ); }
    | t= rhs=Expression6() { return astFactory.contains( pos( t ), lhs, rhs ); }
    | t= rhs=Expression6() { return astFactory.in( pos( t ), lhs, rhs ); }
    | t= (
         { return astFactory.isNull( pos( t ), lhs ); }
        |   { return astFactory.isNotNull( pos( t ), lhs ); }
    )
}

EXPRESSION Expression6() :
{
    Token t;
    EXPRESSION lhs;
    EXPRESSION rhs;
}
{
    lhs=Expression5() (
        t= rhs=Expression5() { lhs = astFactory.plus( pos( t ), lhs, rhs); }
        | t= rhs=Expression5() { lhs = astFactory.minus( pos( t ), lhs, rhs); }
    )*
    {
        return lhs;
    }
}

EXPRESSION Expression5() :
{
    Token t;
    EXPRESSION lhs;
    EXPRESSION rhs;
}
{
    lhs=Expression4() (
        t= rhs=Expression4() { lhs = astFactory.multiply( pos( t ), lhs, rhs ); }
        | t= rhs=Expression4() { lhs = astFactory.divide( pos( t ), lhs, rhs ); }
        | t= rhs=Expression4() { lhs = astFactory.modulo( pos( t ), lhs, rhs ); }
    )*
    {
        return lhs;
    }
}

EXPRESSION Expression4() :
{
    Token t;
    EXPRESSION lhs;
    EXPRESSION rhs;
}
{
    lhs=Expression3() ( t= rhs=Expression3() { lhs = astFactory.pow( pos( t ), lhs, rhs ); } )*
    {
        return lhs;
    }
}

EXPRESSION Expression3() :
{
    Token t;
    EXPRESSION e;
}
{
    (
        LOOKAHEAD(3) e=Expression2()
        | t =  e=Expression2() { e = astFactory.unaryPlus( pos( t ), e ); }
        | t =  e=Expression2() { e = astFactory.unaryMinus( pos( t ), e ); }
    )
    {
        return e;
    }
}

EXPRESSION Expression2() :
{
    EXPRESSION e;
}
{
    e=Expression1() ( e=PostFix1( e ) )*
    {
        return e;
    }
}

EXPRESSION PostFix1( EXPRESSION subject ) :
{
    Token t;
    EXPRESSION e1 = null;
    EXPRESSION e2 = null;
    EXPRESSION ret;
}
{
    (
        ret=Property( subject )
        | ret=HasLabels( subject )
        | LOOKAHEAD( Expression() )  e1=Expression()  { ret=astFactory.listLookup( subject, e1 ); }
        | t= ( e1=Expression() )?  ( e2=Expression() )?  { ret=astFactory.listSlice( pos( t ), subject, e1, e2 ); }
    )
    {
        return ret;
    }
}

PROPERTY Property( EXPRESSION subject ) :
{
    EXPRESSION e;
    StringPos propKeyName;
}
{
     propKeyName=PropertyKeyName()
    {
        return astFactory.property( subject, propKeyName );
    }
}

PROPERTY PropertyExpression() :
{
    EXPRESSION subject;
    PROPERTY p;
}
{
    subject=Expression1() ( p=Property( subject ) { subject = p; } )+
    {
        return p;
    }
}

EXPRESSION Expression1() :
{
    EXPRESSION e = null;
    Token t;
}
{
    (
        e=NumberLiteral()
        | e=StringLiteral()
        | e=Parameter( ParameterType.ANY )
        | t= { e = astFactory.newTrueLiteral( pos( t ) ); }
        | t= { e = astFactory.newFalseLiteral( pos( t ) ); }
        | LOOKAHEAD( 2 ) t= { e = astFactory.newNullLiteral( pos( t ) ); }
        | LOOKAHEAD( 3 ) e=CaseExpression()
        | LOOKAHEAD( 3 ) t=    { e = astFactory.newCountStar( pos( t ) ); }
        | LOOKAHEAD( 3 ) e=MapLiteral()
        | LOOKAHEAD( 3 ) e=ExistsSubQuery() // `exists { match` should not be a map-projection
        | LOOKAHEAD( 2 ) e=MapProjection()
        | e=OldParameter()
        | LOOKAHEAD(  v=Variable()  e=Expression() (  |  |  )) e=ListComprehension() // before literal because it takes precedence. Lookahead due to potential confusion with ListLiteral
        | LOOKAHEAD( PatternComprehensionPrefix() ) e=PatternComprehension() // Only after matching up to "WHERE" or "|" can we be sure it is a PatternComprehension and not a ListLiteral.
        | LOOKAHEAD( 3 ) e=ListLiteral()
        | LOOKAHEAD( 3 ) e=FilterExpression()
        | LOOKAHEAD( 3 ) e=ExtractExpression()
        | LOOKAHEAD( 3 ) e=ReduceExpression()
        | LOOKAHEAD( 3 ) e=AllExpression()
        | LOOKAHEAD( 3 ) e=AnyExpression()
        | LOOKAHEAD( 3 ) e=NoneExpression()
        | LOOKAHEAD( 3 ) e=SingleExpression()
        | LOOKAHEAD( NodePattern() RelationshipPattern() ) e=PatternExpression()
        | LOOKAHEAD( 2 ) e=ShortestPathExpression()
        |  e=Expression() 
        | LOOKAHEAD( (SymbolicNameString()  )* SymbolicNameString()  ) e=FunctionInvocation()
        | e=Variable()
    )
    {
        return e;
    }
}

EXPRESSION CaseExpression() :
{
    Token t;
    EXPRESSION caseExpr = null;
    EXPRESSION e;
    List when = new ArrayList<>();
    List then = new ArrayList<>();
    EXPRESSION elseCase = null;
}
{
    t=
    (
        LOOKAHEAD( Expression()  ) caseExpr=Expression() 
        | 
    ) e=Expression() { when.add( e ); }
     e=Expression() { then.add( e ); }
    (
         e=Expression() { when.add( e ); }
         e=Expression() {then.add( e );}
    )*
    (  elseCase=Expression() )?
    
    {
        return astFactory.caseExpression( pos( t ), caseExpr, when, then, elseCase);
    }
}

EXPRESSION ListComprehension() :
{
    Token t;
    VARIABLE v;
    EXPRESSION e;
    EXPRESSION where = null;
    EXPRESSION projection = null;
}
{
    t= v=Variable()  e=Expression() (  where=Expression() )? (  projection=Expression() )? 
    {
        return astFactory.listComprehension( pos( t ), v, e, where, projection );
    }
}

EXPRESSION PatternComprehension() :
{
    Token t;
    Token relationshipPatternPosition;
    VARIABLE v = null;
    PATTERN p;
    EXPRESSION where = null;
    EXPRESSION projection = null;
}
{
    t= ( v=Variable()  )? {relationshipPatternPosition = token;} p=EveryPathPatternNonEmpty() (  where=Expression() )?  projection=Expression() 
    {
        return astFactory.patternComprehension( pos( t ), pos( relationshipPatternPosition.next ), v, p, where, projection );
    }
}

void PatternComprehensionPrefix() :
{}
{
     ( Variable()  )? EveryPathPattern() (  |  )
}

EXPRESSION FilterExpression() :
{
    Token t;
    VARIABLE v;
    EXPRESSION e;
    EXPRESSION where = null;
}
{
    t=  v=Variable()  e=Expression() (  where=Expression() )? 
    {
        return astFactory.filterExpression( pos( t ), v, e, where );
    }
}

EXPRESSION ExtractExpression() :
{
    Token t;
    VARIABLE v;
    EXPRESSION e;
    EXPRESSION where = null;
    EXPRESSION projection = null;
}
{
    t=  v=Variable()  e=Expression() (  where=Expression() )? (  projection=Expression() )? 
    {
        return astFactory.extractExpression( pos( t ), v, e, where, projection );
    }
}

EXPRESSION ReduceExpression() :
{
    Token t;
    VARIABLE acc;
    EXPRESSION accExpr;
    VARIABLE v;
    EXPRESSION vExpr;
    EXPRESSION innerExpr;
}
{
    t=
    
        acc=Variable()  accExpr=Expression()
        "," v=Variable()  vExpr=Expression()
         innerExpr=Expression()
    
    {
        return astFactory.reduceExpression( pos( t ), acc, accExpr, v, vExpr, innerExpr );
    }
}

EXPRESSION AllExpression() :
{
    Token t;
    VARIABLE v;
    EXPRESSION e;
    EXPRESSION where = null;
}
{
    t=  v=Variable()  e=Expression() (  where=Expression() )? 
    {
        return astFactory.allExpression( pos( t ), v, e, where );
    }
}

EXPRESSION AnyExpression() :
{
    Token t;
    VARIABLE v;
    EXPRESSION e;
    EXPRESSION where = null;
}
{
    t=  v=Variable()  e=Expression() (  where=Expression() )? 
    {
        return astFactory.anyExpression( pos( t ), v, e, where );
    }
}

EXPRESSION NoneExpression() :
{
    Token t;
    VARIABLE v;
    EXPRESSION e;
    EXPRESSION where = null;
}
{
    t=  v=Variable()  e=Expression() (  where=Expression() )? 
    {
        return astFactory.noneExpression( pos( t ), v, e, where );
    }
}

EXPRESSION SingleExpression() :
{
    Token t;
    VARIABLE v;
    EXPRESSION e;
    EXPRESSION where = null;
}
{
    t=  v=Variable()  e=Expression() (  where=Expression() )? 
    {
        return astFactory.singleExpression( pos( t ), v, e, where );
    }
}

EXPRESSION PatternExpression() :
{
    PATTERN p;
    Token t;
}
{
    { t = token; }
    p=EveryPathPatternNonEmpty()
    {
        return astFactory.patternExpression( pos( t.next ), p );
    }
}

EXPRESSION ShortestPathExpression() :
{
    PATTERN p;
    Token t;
}
{
    { t = token; }
    p=ShortestPathPattern()
    {
        return astFactory.patternExpression( pos( t.next ), p );
    }
}

EXPRESSION MapProjection() :
{
    Token t;
    VARIABLE v;
    MAP_PROJECTION_ITEM x;
    List items = new ArrayList<>();
}
{
    v=Variable() t= ( x=MapProjectionItem() { items.add( x ); } )? ( "," x=MapProjectionItem() { items.add( x ); } )* 
    {
        return astFactory.mapProjection( pos( t ), v, items );
    }
}

MAP_PROJECTION_ITEM MapProjectionItem() :
{
    Token t;
    StringPos p;
    EXPRESSION e;
    VARIABLE v;
}
{
    LOOKAHEAD( 2 ) p=PropertyKeyName() ":" e=Expression() { return astFactory.mapProjectionLiteralEntry( p, e ); }
    | LOOKAHEAD( 2 )  p=PropertyKeyName() { return astFactory.mapProjectionProperty( p ); }
    | v=Variable() { return astFactory.mapProjectionVariable( v ); }
    |  t= { return astFactory.mapProjectionAll( pos( t ) ); }
}

EXPRESSION ExistsSubQuery() :
{
    Token t;
    List patterns;
    EXPRESSION where = null;
}
{
    t=  ( LOOKAHEAD( 2 )  )? patterns=PatternList() (  where=Expression() )? 
    {
        return astFactory.existsSubQuery( pos( t ), patterns, where );
    }
}

EXPRESSION Literal() :
{
    Token t;
    EXPRESSION e;
}
{
    (
        e=NumberLiteral()
        | e=StringLiteral()
        | e=Parameter( ParameterType.ANY )
        | t= { e = astFactory.newTrueLiteral( pos( t ) ); }
        | t= { e = astFactory.newFalseLiteral( pos( t ) ); }
        | LOOKAHEAD( 2 ) t= { e = astFactory.newNullLiteral( pos( t ) ); }
        | e=ListLiteralOfLiterals()
        | e=MapLiteralOfLiterals()
        | e=FunctionInvocation() // for spatial and temporal constructors
    )
    {
        return e;
    }
}

EXPRESSION ListLiteralOfLiterals() :
{
    Token t;
    EXPRESSION e;
    List list = new ArrayList<>();
}
{
    t= ( e=Literal() { list.add(e); } )? ( "," e=Literal() {list.add( e ); } )* 
    {
        return astFactory.listLiteral( pos( t ), list );
    }
}

EXPRESSION MapLiteralOfLiterals() :
{
    Token t;
    StringPos key;
    EXPRESSION value;
    List> keys = new ArrayList<>();
    List values = new ArrayList<>();
}
{
    t= ( key=PropertyKeyName() ":" value=Literal() {keys.add( key ); values.add( value ); } )?
           ( "," key=PropertyKeyName() ":" value=Literal() {keys.add( key ); values.add( value ); } )* 
    {
        return astFactory.mapLiteral( pos( t ), keys, values );
    }
}

EXPRESSION StringLiteral() :
{
    Token t;
}
{
    t=StringToken() { return astFactory.newString( pos( t ), token.image ); }
}

EXPRESSION NumberLiteral() :
{
    Token sign = null;
    Token t;
    boolean negated = false;
}
{
    ( sign= { negated = true; } )?
    (
        t= { return astFactory.newDouble(  pos( sign != null ? sign : t ) , sign != null ? sign.image + token.image : token.image ); }
        | t= { return astFactory.newDecimalInteger( pos( sign != null ? sign : t ), token.image, negated ); }
        | t= { return astFactory.newHexInteger( pos( sign != null ? sign : t ), token.image, negated ); }
        | t= { return astFactory.newOctalInteger( pos( sign != null ? sign : t ), token.image, negated ); }
    )
}

EXPRESSION SignedIntegerLiteral():
{
    Token sign = null;
    Token number;
    boolean negated = false;
}
{
    ( sign= { negated = true; })?
    number=
    {
        return astFactory.newDecimalInteger( pos( sign != null ? sign : number ), token.image, negated );
    }
}

EXPRESSION ListLiteral() :
{
    Token t;
    EXPRESSION e;
    List list = new ArrayList<>();
}
{
    t= ( e=Expression() { list.add( e ); } )? ( "," e=Expression() { list.add( e ); } )* 
    {
        return astFactory.listLiteral( pos( t ), list );
    }
}

EXPRESSION MapLiteral() :
{
    Token t;
    StringPos key;
    EXPRESSION value;
    List> keys = new ArrayList<>();
    List values = new ArrayList<>();
}
{
    t= ( key=PropertyKeyName() ":" value=Expression() { keys.add( key ); values.add( value ); } )?
           ( "," key=PropertyKeyName() ":" value=Expression() { keys.add( key ); values.add( value ); } )* 
    {
        return astFactory.mapLiteral( pos( t ), keys, values);
    }
}

StringPos PropertyKeyName() :
{
    Token t;
}
{
    t=SymbolicNameString()
    {
        return new StringPos( t.image,  pos( t ) );
    }
}

PARAMETER Parameter( ParameterType type ) :
{
    Token t;
    VARIABLE v;
}
{
    t= (
        v=Variable() { return astFactory.newParameter( pos( t ), v, type ); }
        |  { return astFactory.newParameter( pos( t ), token.image, type ); }
    )
}

EXPRESSION OldParameter() :
{
    Token t;
    VARIABLE v;
}
{
    t= v=Variable() 
    {
        return astFactory.oldParameter( pos( t ), v );
    }
}

EXPRESSION FunctionInvocation() :
{
    Token before = token;
    Token nameSpaceToken;
    Token nameToken;
    List namespace;
    boolean distinct = false;
    EXPRESSION e;
    List arguments = new ArrayList<>();
}
{
    namespace=Namespace() nameToken=SymbolicNameString()
    
        ( LOOKAHEAD( 2 )  { distinct=true; })?
        ( e=Expression() { arguments.add( e ); } )? ( "," e=Expression() { arguments.add( e ); } )*
    
    {
        return astFactory.functionInvocation( pos( before.next ), pos( nameToken ), namespace, nameToken.image, distinct, arguments );
    }
}

List Namespace() :
{
    Token t;
    List parts = new ArrayList<>();
}
{
    ( LOOKAHEAD( 2 ) t=SymbolicNameString() { parts.add( t.image ); }  )*
    {
        return parts;
    }
}

String FunctionName() :
{
    Token t;
}
{
    t=SymbolicNameString()
    {
        return t.image;
    }
}

List VariableList1() :
{
    Token t;
    List list = new ArrayList<>();
}
{
    t=SymbolicNameString() { list.add( astFactory.newVariable( pos( t ), t.image ) ); }
    ( "," t=SymbolicNameString() { list.add( astFactory.newVariable( pos( t ), t.image) ); })*
    {
        return list;
    }
}

VARIABLE Variable() :
{
    Token t;
}
{
    t=SymbolicNameString()
    {
        return astFactory.newVariable( pos( t ), t.image );
    }
}

List SymbolicNameList1() :
{
    Token n;
    List list = new ArrayList<>();
}
{
    n=SymbolicNameString() { list.add(n.image); } ( "," n=SymbolicNameString() { list.add( n.image ); } )*
    {
        return list;
    }
}

// Command Section

STATEMENT_WITH_GRAPH CreateCommand( USE_CLAUSE useClause ) throws Exception:
{
    Token start;
    boolean replace = false;
    STATEMENT_WITH_GRAPH statement;
}
{
    start= (  { replace = true; })? (
        statement=CreateRole( start, replace )
        | statement=CreateUser( start, replace )
        | statement=CreateDatabase( start, replace )
        | statement=CreateConstraint( start, replace )
        | statement=CreateIndex( start, replace )
        | statement=CreateAlias( start, replace )
    )
    {
        return astFactory.useGraph( statement, useClause );
    }
}

STATEMENT Command( USE_CLAUSE useClause ) throws Exception:
{
    STATEMENT statement = null;
}
{
    (

        statement=CommandWithUseGraph( useClause )
        | statement=ShowCommand( useClause )
        | statement=TerminateCommand( useClause )
    )
    {
        return statement;
    }
}

STATEMENT_WITH_GRAPH CommandWithUseGraph( USE_CLAUSE useClause ) throws Exception:
{
    STATEMENT_WITH_GRAPH s;
}
{
    (
        s=DropCommand()
        | s=AlterCommand()
        | s=RenameCommand()
        | s=DenyPrivilege()
        | s=RevokeCommand()
        | s=GrantCommand()
        | s=StartDatabase()
        | s=StopDatabase()
    )
    {
        return astFactory.useGraph( s, useClause );
    }
}

STATEMENT_WITH_GRAPH DropCommand() throws Exception:
{
    Token start;
    STATEMENT_WITH_GRAPH s;
}
{
    start=
    (
        s=DropRole( start )
        | s=DropUser( start )
        | s=DropDatabase( start )
        | s=DropConstraint( start )
        | s=DropIndex( start )
        | s=DropAlias( start )
    )
    {
        return s;
    }
}

STATEMENT_WITH_GRAPH AlterCommand() throws Exception:
{
    Token start = null;
    STATEMENT_WITH_GRAPH s;
}
{
    start=
    (
        s=AlterDatabase( start )
        | s=AlterAlias( start )
        | s=AlterCurrentUser( start )
        | s=AlterUser( start )
    )
    {
        return s;
    }
}

// SHOW commands

STATEMENT ShowCommand( USE_CLAUSE useClause ) :
{
    Token start = null;
    Token showCommandType = null;
    STATEMENT statement = null;
}
{
    start=
    (
        showCommandType= statement=ShowAllCommand( start, useClause )
        |  statement=ShowRoles( start, useClause, false )
        | showCommandType= statement=ShowIndexesAllowBrief( start, useClause, ShowCommandFilterTypes.BTREE )
        | showCommandType= statement=ShowIndexesNoBrief( start, useClause, ShowCommandFilterTypes.RANGE )
        | showCommandType= statement=ShowIndexesNoBrief( start, useClause, ShowCommandFilterTypes.FULLTEXT )
        | showCommandType= statement=ShowIndexesNoBrief( start, useClause, ShowCommandFilterTypes.TEXT )
        | showCommandType= statement=ShowIndexesNoBrief( start, useClause, ShowCommandFilterTypes.POINT )
        | showCommandType= statement=ShowIndexesNoBrief( start, useClause, ShowCommandFilterTypes.LOOKUP )
        | showCommandType= statement=ShowConstraintsAllowBriefAndYield( start, useClause, ShowCommandFilterTypes.UNIQUE )
        | showCommandType= statement=ShowNodeCommand( start, useClause )
        | showCommandType= statement=ShowPropertyCommand( start, useClause, ShowCommandFilterTypes.EXIST )
        | showCommandType= statement=ShowConstraintsAllowYield( start, useClause, ShowCommandFilterTypes.EXIST )
        | showCommandType= statement=ShowConstraintsAllowBrief( start, useClause, ShowCommandFilterTypes.OLD_EXISTS )
        | showCommandType= statement=ShowConstraintsAllowBriefAndYield( start, useClause, ShowCommandFilterTypes.OLD_EXIST )
        | showCommandType= statement=ShowRelationshipCommand( start, useClause )
        | showCommandType= statement=ShowRelCommand( start, useClause )
        | showCommandType=  statement=ShowFunctions( start, useClause, ShowCommandFilterTypes.BUILT_IN )
        | showCommandType=  statement=ShowFunctions( start, useClause, ShowCommandFilterTypes.USER_DEFINED )
        | statement=ShowRoles( start, useClause, true )
        | statement=ShowIndexesAllowBrief( start, useClause, ShowCommandFilterTypes.ALL )
        | statement=ShowDatabase( start, useClause )
        | statement=ShowUsers( start, useClause )
        | statement=ShowCurrentUser( start, useClause )
        | statement=ShowConstraintsAllowBriefAndYield( start, useClause, ShowCommandFilterTypes.ALL )
        | statement=ShowProcedures( start, useClause )
        | statement=ShowFunctions( start, useClause, ShowCommandFilterTypes.ALL )
        | statement=ShowTransactions( start, useClause )
        | statement=ShowAliases( start, useClause )
    )
    {
        return statement;
    }
}

STATEMENT TerminateCommand( USE_CLAUSE useClause ) :
{
    Token start = null;
    STATEMENT statement = null;
}
{
    start=
    (
        statement=TerminateTransactions( start, useClause )
    )
    {
        return statement;
    }
}

STATEMENT ShowAllCommand( Token start, USE_CLAUSE useClause ) :
{
    STATEMENT statement = null;
}
{
    (
        statement=ShowRoles( start, useClause, true )
        | statement=ShowIndexesAllowBrief( start, useClause, ShowCommandFilterTypes.ALL )
        | statement=ShowConstraintsAllowBriefAndYield( start, useClause, ShowCommandFilterTypes.ALL )
        | statement=ShowFunctions( start, useClause, ShowCommandFilterTypes.ALL )
    )
    {
        return statement;
    }
}

STATEMENT ShowNodeCommand( Token start, USE_CLAUSE useClause ) :
{
    Token constraintType = null;
    STATEMENT statement = null;
}
{
    // Needs to add  to the type
    (
        constraintType= statement=ShowConstraintsAllowBriefAndYield( start, useClause, ShowCommandFilterTypes.NODE_KEY )
        | constraintType= statement=ShowPropertyCommand( start, useClause, ShowCommandFilterTypes.NODE_EXIST )
        | constraintType= statement=ShowConstraintsAllowYield( start, useClause, ShowCommandFilterTypes.NODE_EXIST )
        | constraintType= statement=ShowConstraintsAllowBrief( start, useClause, ShowCommandFilterTypes.NODE_OLD_EXISTS )
        | constraintType= statement=ShowConstraintsAllowBriefAndYield( start, useClause, ShowCommandFilterTypes.NODE_OLD_EXIST )
    )
    {
        return statement;
    }
}

STATEMENT ShowRelationshipCommand( Token start, USE_CLAUSE useClause ) :
{
    Token constraintType = null;
    STATEMENT statement = null;
}
{
    (
        constraintType= statement=ShowPropertyCommand( start, useClause, ShowCommandFilterTypes.RELATIONSHIP_EXIST )
        | constraintType= statement=ShowConstraintsAllowYield( start, useClause, ShowCommandFilterTypes.RELATIONSHIP_EXIST )
        | constraintType= statement=ShowConstraintsAllowBrief( start, useClause, ShowCommandFilterTypes.RELATIONSHIP_OLD_EXISTS )
        | constraintType= statement=ShowConstraintsAllowBriefAndYield( start, useClause, ShowCommandFilterTypes.RELATIONSHIP_OLD_EXIST )
    )
    {
        return statement;
    }
}

STATEMENT ShowRelCommand( Token start, USE_CLAUSE useClause ) :
{
    STATEMENT statement = null;
}
{
    (
         statement=ShowPropertyCommand( start, useClause, ShowCommandFilterTypes.RELATIONSHIP_EXIST )
        |  statement=ShowConstraintsAllowYield( start, useClause, ShowCommandFilterTypes.RELATIONSHIP_EXIST )
        |  statement=ShowConstraintsAllowYield( start, useClause, ShowCommandFilterTypes.RELATIONSHIP_EXIST )
    )
    {
        return statement;
    }
}

STATEMENT ShowPropertyCommand( Token start, USE_CLAUSE useClause, ShowCommandFilterTypes constraintType ) :
{
    STATEMENT statement = null;
}
{
    (  statement=ShowConstraintsAllowYield( start, useClause, constraintType )
    |  statement=ShowConstraintsAllowYield( start, useClause, constraintType )
    ) { return statement; }
}

RETURN_ITEM YieldItem() :
{
    VARIABLE e;
    VARIABLE v = null;
    Token eStart;
    Token eEnd;
}
{
    { eStart = token; }
    e=Variable() { eEnd = token; } (  v=Variable() )?
    {
        if ( v != null )
        {
            return astFactory.newReturnItem( pos( eStart.next ), e, v );
        }
        else
        {
            return astFactory.newReturnItem( pos( eStart.next ), e, eStart.next.beginOffset, eEnd.endOffset );
        }
    }
}

YIELD YieldClause():
{
    Token start;
    Token skipPosition = null;
    Token limitPosition = null;
    Token orderToken = null;
    boolean returnAll = false;
    RETURN_ITEM item;
    ORDER_ITEM o;
    List returnItems = new ArrayList<>();
    List orders = new ArrayList<>();
    EXPRESSION skip = null;
    EXPRESSION limit = null;
    WHERE where = null;
}
{
    start=
    (  { returnAll = true; }  |
    ( item=YieldItem() { returnItems.add( item ); } ("," item=YieldItem() { returnItems.add( item ); } )*))
    ( orderToken=  o=OrderItem() { orders.add( o ); } ( "," o=OrderItem() {orders.add( o ); } )*)?
    ( skipPosition= skip=SignedIntegerLiteral() )?
    ( limitPosition= limit=SignedIntegerLiteral() )?
    ( where=WhereClause() ) ?
    {
        return astFactory.yieldClause( pos( start ), returnAll, returnItems, pos( start.next ), orders, pos( orderToken ), skip, pos( skipPosition ), limit, pos( limitPosition ), where );
    }
}

STATEMENT ShowIndexesAllowBrief( Token start, USE_CLAUSE useClause, ShowCommandFilterTypes indexType ):
{
    // all and btree indexes
    List clauses = new ArrayList<>();
    if ( useClause != null )
    {
      clauses.add( useClause );
    }
    boolean brief = false;
    boolean verbose = false;
    WHERE where = null;
    YIELD yieldClause = null;
    RETURN_CLAUSE returnClause = null;
}
{
    (  |  )
    (
        ( (  { brief = true; } |  { verbose = true; } ) (  )? )
        | ( yieldClause=YieldClause() ( returnClause=ReturnClause() )? )
        | where=WhereClause()
    )?
    {
        if ( yieldClause != null )
        {
            clauses.add( astFactory.showIndexClause( pos( start ), indexType, brief, verbose, where, true ) );
            clauses.add( yieldClause );
            if ( returnClause != null )
            {
                clauses.add( returnClause );
            }
        }
        else
        {
            clauses.add( astFactory.showIndexClause( pos( start ), indexType, brief, verbose, where, false ) );
        }
        return astFactory.newSingleQuery( pos( start ), clauses );
    }
}

STATEMENT ShowIndexesNoBrief(Token start, USE_CLAUSE useClause, ShowCommandFilterTypes indexType):
{
  // fulltext, text and lookup indexes
  List clauses = new ArrayList<>();
  if (useClause != null) {
      clauses.add( useClause );
  }
  WHERE where = null;
  YIELD yieldClause = null;
  RETURN_CLAUSE returnClause = null;
}
{
    (  |  )
    ( (yieldClause=YieldClause() ( returnClause=ReturnClause() )?) | where=WhereClause() )?
    {
        if ( yieldClause != null )
        {
            clauses.add( astFactory.showIndexClause( pos( start ), indexType, false, false, where, true ) );
            clauses.add( yieldClause );
            if ( returnClause != null )
            {
                clauses.add( returnClause );
            }
        }
        else
        {
            clauses.add( astFactory.showIndexClause( pos( start ), indexType, false, false, where, false ) );
        }
        return astFactory.newSingleQuery( pos( start ), clauses );
    }
}

STATEMENT ShowConstraintsAllowBriefAndYield( Token start, USE_CLAUSE useClause, ShowCommandFilterTypes constraintType ):
{
    // all, node key, uniqueness and old valid existence constraints
    List clauses = new ArrayList<>();
    if ( useClause != null )
    {
        clauses.add( useClause );
    }
    boolean brief = false;
    boolean verbose = false;
    WHERE where = null;
    YIELD yieldClause = null;
    RETURN_CLAUSE returnClause = null;
}
{
    (  |  )
    (
        ( (  { brief = true; } |  { verbose = true; }) ()? )
        | ( yieldClause=YieldClause() ( returnClause=ReturnClause() )?)
        | where=WhereClause()
    )?
    {
        if ( yieldClause != null )
        {
            clauses.add( astFactory.showConstraintClause( pos( start ), constraintType, brief, verbose, where, true ) );
            clauses.add( yieldClause );
            if ( returnClause != null )
            {
                clauses.add( returnClause );
            }
        }
        else
        {
            clauses.add( astFactory.showConstraintClause( pos( start ), constraintType, brief, verbose, where, false ) );
        }
        return astFactory.newSingleQuery( pos( start ), clauses );
    }
}

STATEMENT ShowConstraintsAllowBrief( Token start, USE_CLAUSE useClause, ShowCommandFilterTypes constraintType ):
{
    // old deprecated existence constraints
    List clauses = new ArrayList<>();
    if ( useClause != null )
    {
        clauses.add( useClause );
    }
    boolean brief = false;
    boolean verbose = false;
}
{
    (  |  )
    ( (  { brief = true; } |  { verbose = true; }) ()? )?
    {
        clauses.add( astFactory.showConstraintClause( pos( start ), constraintType, brief, verbose, null, false ) );
        return astFactory.newSingleQuery( pos( start ), clauses );
    }
}

STATEMENT ShowConstraintsAllowYield( Token start, USE_CLAUSE useClause, ShowCommandFilterTypes constraintType ):
{
    // new existence constraints
    List clauses = new ArrayList<>();
    if (useClause != null)
    {
        clauses.add( useClause );
    }
    WHERE where = null;
    YIELD yieldClause = null;
    RETURN_CLAUSE returnClause = null;
}
{
    (  |  )
    (
        ( yieldClause=YieldClause() ( returnClause=ReturnClause() ) ? )
        | where=WhereClause()
    )?
    {
        if ( yieldClause != null )
        {
            clauses.add( astFactory.showConstraintClause( pos( start ), constraintType, false, false, where, true ) );
            clauses.add( yieldClause );
            if ( returnClause != null )
            {
                clauses.add( returnClause );
            }
        }
        else
        {
            clauses.add( astFactory.showConstraintClause( pos( start ), constraintType, false, false, where, false ) );
        }
        return astFactory.newSingleQuery( pos( start ), clauses );
    }
}

STATEMENT ShowProcedures( Token start, USE_CLAUSE useClause ):
{
    List clauses = new ArrayList<>();
    if (useClause != null)
    {
        clauses.add( useClause );
    }

    boolean currentUser = false;
    Token userToken = null;
    String user = null;

    WHERE where = null;
    YIELD yieldClause = null;
    RETURN_CLAUSE returnClause = null;
}
{
    (  |  )
    (
         { currentUser = true; } ( 
        ( LOOKAHEAD( )   { currentUser = true; }
        | userToken=SymbolicNameString() { user = userToken.image; currentUser = false; } ) )?
    )?
    (
        ( yieldClause=YieldClause() ( returnClause=ReturnClause() ) ? )
        | where=WhereClause()
    )?
    {
        if ( yieldClause != null )
        {
            clauses.add( astFactory.showProcedureClause( pos( start ), currentUser, user, where, true ) );
            clauses.add( yieldClause );
            if ( returnClause != null )
            {
                clauses.add( returnClause );
            }
        }
        else
        {
            clauses.add( astFactory.showProcedureClause( pos( start ), currentUser, user, where, false ) );
        }
        return astFactory.newSingleQuery( pos( start ), clauses );
    }
}

STATEMENT ShowFunctions( Token start, USE_CLAUSE useClause, ShowCommandFilterTypes functionType ):
{
    List clauses = new ArrayList<>();
    if (useClause != null)
    {
        clauses.add( useClause );
    }

    boolean currentUser = false;
    Token userToken = null;
    String user = null;

    WHERE where = null;
    YIELD yieldClause = null;
    RETURN_CLAUSE returnClause = null;
}
{
    (  |  )
    (
         { currentUser = true; } ( 
        ( LOOKAHEAD( )   { currentUser = true; }
        | userToken=SymbolicNameString() { user = userToken.image; currentUser = false; } ) )?
    )?
    (
        ( yieldClause=YieldClause() ( returnClause=ReturnClause() ) ? )
        | where=WhereClause()
    )?
    {
        if ( yieldClause != null )
        {
            clauses.add( astFactory.showFunctionClause( pos( start ), functionType, currentUser, user, where, true ) );
            clauses.add( yieldClause );
            if ( returnClause != null )
            {
                clauses.add( returnClause );
            }
        }
        else
        {
            clauses.add( astFactory.showFunctionClause( pos( start ), functionType, currentUser, user, where, false ) );
        }
        return astFactory.newSingleQuery( pos( start ), clauses );
    }
}

STATEMENT ShowTransactions( Token start, USE_CLAUSE useClause ):
{
    List clauses = new ArrayList<>();
    if (useClause != null)
    {
        clauses.add( useClause );
    }

    List ids = new ArrayList<>();
    PARAMETER param = null;
    SimpleEither, PARAMETER> idEither = SimpleEither.left(ids);

    WHERE where = null;
    YIELD yieldClause = null;
    RETURN_CLAUSE returnClause = null;
}
{
    (  |  )
    (
        //lookaheads for potential symbolicNames "yield", "where"
        LOOKAHEAD() yieldClause=YieldClause() ( returnClause=ReturnClause() ) ?
        | LOOKAHEAD() where=WhereClause()
        | ( (ids=TransactionIdStringList() { idEither=SimpleEither.left(ids); }) | (param=Parameter( ParameterType.ANY ) { idEither=SimpleEither.right(param); }) ) (
            ( yieldClause=YieldClause() ( returnClause=ReturnClause() ) ? )
            | where=WhereClause()
        )?
    )?
    {
        if ( yieldClause != null )
        {
            clauses.add( astFactory.showTransactionsClause( pos( start ), idEither,  where, true ) );
            clauses.add( yieldClause );
            if ( returnClause != null )
            {
                clauses.add( returnClause );
            }
        }
        else
        {
            clauses.add( astFactory.showTransactionsClause( pos( start ), idEither, where, false ) );
        }
        return astFactory.newSingleQuery( pos( start ), clauses );
    }
}

STATEMENT TerminateTransactions( Token start, USE_CLAUSE useClause ):
{
    List clauses = new ArrayList<>();
    if (useClause != null)
    {
        clauses.add( useClause );
    }

    List ids = new ArrayList<>();
    PARAMETER param = null;
    SimpleEither, PARAMETER> idEither = SimpleEither.left(ids);
}
{
    (  |  )
    (
        (ids=TransactionIdStringList() { idEither=SimpleEither.left(ids); }) |
        (param=Parameter( ParameterType.ANY ) { idEither=SimpleEither.right(param); })
    )?
    {
        clauses.add( astFactory.terminateTransactionsClause( pos( start ), idEither ) );
        return astFactory.newSingleQuery( pos( start ), clauses );
    }
}

// Schema commands
// Constraint commands

SCHEMA_COMMAND CreateConstraint( Token start, boolean replace ) throws Exception:
{
    String name = null;
    boolean ifNotExists = false;
    Token label;
    VARIABLE variable = null;
    List properties= new ArrayList<>();
    SimpleEither, PARAMETER> options = null;
    ConstraintType constraintType = ConstraintType.NODE_EXISTS;
    boolean isNode = false;
    Token errorStart;
    boolean containsOn = true;
    ConstraintVersion constraintVersion = ConstraintVersion.CONSTRAINT_VERSION_0;
}
{
    
    (
        //special construct for allowing lookahead since on could also be an identifier
        LOOKAHEAD ( )  
        | LOOKAHEAD ( )   { containsOn = false; }
        | LOOKAHEAD ( )    { ifNotExists = true; } ( |  { containsOn = false; }) 
        | ( LOOKAHEAD(2) SymbolicNameString() { name = token.image; } )? (    { ifNotExists = true; } )? ( |  { containsOn = false; }) 
    )
    (
        //(variable:LABEL)
        variable=Variable() label=LabelOrRelType()  { isNode = true; }
    |   //()-[variable:LABEL]-()
         ( LeftArrow() )? ArrowLine()
         variable=Variable() label=LabelOrRelType() 
        ArrowLine() ( RightArrow() )?  
    )
    (
         // CREATE CONSTRAINT ON (variable:LABEL) ASSERT EXISTS variable.prop
        LOOKAHEAD( )
         { constraintVersion = ConstraintVersion.CONSTRAINT_VERSION_0; }
        errorStart= { constraintType = isNode ? ConstraintType.NODE_EXISTS : ConstraintType.REL_EXISTS; }
        properties=PropertyList()
    |
        (
             { constraintVersion = ConstraintVersion.CONSTRAINT_VERSION_2; }
            |  { constraintVersion = ConstraintVersion.CONSTRAINT_VERSION_0; }
        )
        properties=PropertyList()
        (
            errorStart=
            (
                 {
                        // CREATE CONSTRAINT ON (variable:LABEL) ASSERT variable.prop IS UNIQUE
                        // CREATE CONSTRAINT FOR (variable:LABEL) REQUIRE variable.prop IS UNIQUE
                        constraintType = ConstraintType.UNIQUE ;
                        if ( !isNode )
                        {
                            throw exceptionFactory.syntaxException(
                                new ParseException( ASTExceptionFactory.relationshipPattternNotAllowed( constraintType ) ),
                                errorStart.beginOffset, errorStart.beginLine, errorStart.beginColumn );
                        }
                     }
                |  
                    {
                        // CREATE CONSTRAINT ON (variable:LABEL) ASSERT variable.prop IS NODE KEY
                        // CREATE CONSTRAINT FOR (variable:LABEL) REQUIRE variable.prop IS NODE KEY
                        constraintType = ConstraintType.NODE_KEY;
                        if ( !isNode )
                        {
                            throw exceptionFactory.syntaxException(
                                new ParseException( ASTExceptionFactory.relationshipPattternNotAllowed( constraintType ) ),
                                errorStart.beginOffset, errorStart.beginLine, errorStart.beginColumn );
                        }
                    }
                |   {
                    // CREATE CONSTRAINT ON (variable:LABEL) ASSERT variable.prop IS NOT NULL
                    // CREATE CONSTRAINT FOR (variable:LABEL) REQUIRE variable.prop IS NOT NULL
                    constraintType = isNode ? ConstraintType.NODE_IS_NOT_NULL : ConstraintType.REL_IS_NOT_NULL;
                    if (constraintVersion == ConstraintVersion.CONSTRAINT_VERSION_0)
                    {
                        constraintVersion = ConstraintVersion.CONSTRAINT_VERSION_1;
                    }
                }
            )
        )
    )
    (  options=MapOrParameter() )?
    {
        return astFactory.createConstraint( pos( start ), constraintType, replace, ifNotExists, name, variable,
        new StringPos( label.image, pos( label ) ), properties, options, containsOn, constraintVersion );
    }
}

SCHEMA_COMMAND DropConstraint( Token start ) throws Exception:
{
        Token name = null;
        boolean ifExists = false;
        VARIABLE variable = null;
        Token label = null;
        List properties= new ArrayList<>();
        ConstraintType constraintType = ConstraintType.NODE_EXISTS;
        boolean isNode = false;
        Token errorStart;
}
{
    
    ( LOOKAHEAD ( )  
        (
            //(n:LABEL)
            variable=Variable() label=LabelOrRelType()  { isNode = true; }
        |   //()-[r:RELTYPE]-()
             ( LeftArrow() )? ArrowLine()
             variable=Variable() label=LabelOrRelType() 
            ArrowLine() ( RightArrow() )?  
        )
        
        (
            LOOKAHEAD() errorStart= { constraintType = isNode ? ConstraintType.NODE_EXISTS : ConstraintType.REL_EXISTS; }
            properties=PropertyList()
       |
            properties=PropertyList()
            errorStart=
              (
                  //DROP CONSTRAINT ON (node:Label) ASSERT (node.prop) IS UNIQUE
                   {
                          constraintType = ConstraintType.UNIQUE;
                          if ( !isNode )
                          {
                              throw exceptionFactory.syntaxException(
                                  new ParseException( ASTExceptionFactory.relationshipPattternNotAllowed( constraintType ) ),
                                  errorStart.beginOffset, errorStart.beginLine, errorStart.beginColumn );
                          }
                      }
                  | //DROP CONSTRAINT ON (node:Label) ASSERT (node.prop) IS NODE KEY
                       
                      {
                          constraintType = ConstraintType.NODE_KEY ;
                          if ( !isNode )
                          {
                              throw exceptionFactory.syntaxException(
                                  new ParseException( ASTExceptionFactory.relationshipPattternNotAllowed( constraintType ) ),
                                  errorStart.beginOffset, errorStart.beginLine, errorStart.beginColumn );
                          }
                      }
                  |   {
                      constraintType = isNode ? ConstraintType.NODE_IS_NOT_NULL : ConstraintType.REL_IS_NOT_NULL;
                  }
              )
        )
        {
            return astFactory.dropConstraint( pos( start ), constraintType, variable, new StringPos( label.image, pos( label ) ),
                properties );
        }
    |   //DROP CONSTRAINT name IF EXISTS
        name=SymbolicNameString() (   { ifExists = true; } )?
        {
            return astFactory.dropConstraint( pos( start ), name.image, ifExists );
        }
    )
}

// Index commands

SCHEMA_COMMAND CreateIndex( Token start, boolean replace ) throws Exception:
{
    SCHEMA_COMMAND command = null;
}
{
    (
          command=createIndex( start, replace, CreateIndexTypes.BTREE )
        |   command=createIndex( start, replace, CreateIndexTypes.RANGE )
        |   command=createFulltextIndex( start, replace )
        |   command=createIndex( start, replace, CreateIndexTypes.TEXT )
        |   command=createIndex( start, replace, CreateIndexTypes.POINT )
        |   command=createLookupIndex( start, replace )
        |  (
            LOOKAHEAD( ":")  command=oldCreateIndex( start, replace ) // old syntax: CREATE INDEX ON :nodeLabel(prop1, prop2)
            | command=createIndex( start, replace, CreateIndexTypes.DEFAULT )
        )
    )
    {
        return command;
    }
}

SCHEMA_COMMAND oldCreateIndex(Token start, boolean replace ) throws Exception:
{
    Token nodeLabel;
    List> properties;
}
{
    //CREATE INDEX ON :nodeLabel(prop1, prop2)
    nodeLabel=LabelOrRelType()
     properties = SymbolicNamePositions() 
    {
        if (replace) {
            throw exceptionFactory.syntaxException( new ParseException("'REPLACE' is not allowed for this index syntax"), start.beginOffset, start.beginLine, start.beginColumn );
        }
        return astFactory.createIndexWithOldSyntax( pos(start), new StringPos<>(nodeLabel.image, pos(nodeLabel) ), properties );
    }
}

SCHEMA_COMMAND createIndex( Token start, boolean replace, CreateIndexTypes indexType ) throws Exception:
{
    boolean ifNotExists = false;
    boolean isNode = false;
    String indexName = null;
    VARIABLE variable = null;
    Token label = null;
    List properties= new ArrayList<>();
    SimpleEither, PARAMETER> options = null;
}
{
    //CREATE [RANGE | BTREE | TEXT | POINT] INDEX FOR (n:label) ON (n.prop)
    (
        //lookaheads for potential symbolicNames "for", "if"
        LOOKAHEAD( )  
        | LOOKAHEAD( )    { ifNotExists = true; }   
        | (SymbolicNameString() { indexName = token.image; } ) (    { ifNotExists = true; } )?  
    )
    (
        //(n:LABEL)
        variable=Variable() label=LabelOrRelType()  { isNode = true; }
    |   //()-[r:RELTYPE]-()
         ( LeftArrow() )? ArrowLine()
         variable=Variable() label=LabelOrRelType() 
        ArrowLine() ( RightArrow() )?  
    )
    
    properties=PropertyList()
    (  options=MapOrParameter() )?
    {
        return astFactory.createIndex( pos(start), replace, ifNotExists, isNode, indexName, variable, new StringPos<>(label.image, pos(label)), properties, options, indexType );
    }
}

SCHEMA_COMMAND createFulltextIndex( Token start, boolean replace):
{
    boolean ifNotExists = false;
    boolean isNode = false;
    String indexName = null;
    VARIABLE variable = null;
    VARIABLE propName = null;
    PROPERTY p = null;
    List> labels = new ArrayList<>();
    List properties= new ArrayList<>();
    SimpleEither, PARAMETER> options = null;
}
{
    //CREATE FULLTEXT INDEX FOR (n:T1 | T2) ON (v.prop)
    (
        //lookaheads for potential symbolicNames "for", "if"
        LOOKAHEAD( )  
        | LOOKAHEAD( ) (    { ifNotExists = true; } )  
        | (SymbolicNameString() { indexName = token.image; } ) (    { ifNotExists = true; } )?  
    )
        (   //(v:L1 | ... | Ln)
            variable=Variable() labels=LabelOrRelTypes()  { isNode = true; }
        |
            //()-[r:R1 | ... | Rn]-()
             ( LeftArrow() )? ArrowLine()
             variable=Variable() labels=LabelOrRelTypes() 
            ArrowLine() ( RightArrow() )?  
        )
         
        
            propName=Variable() p=Property( propName ) { properties.add( p ); }
            ( "," propName=Variable() p=Property( propName ) { properties.add( p ); } )*
        
        (  options=MapOrParameter() )?
        {
            return astFactory.createFulltextIndex( pos(start), replace, ifNotExists, isNode, indexName, variable, labels, properties, options );
        }
}

SCHEMA_COMMAND createLookupIndex( Token start, boolean replace ):
{
    boolean ifNotExists = false;
    boolean isNode = false;
    String indexName = null;
    VARIABLE variable = null;
    StringPos funcName = null;
    VARIABLE funcParam = variable;
    SimpleEither, PARAMETER> options = null;
}
{
    //CREATE LOOKUP INDEX FOR (n) ON EACH funcName(funcParam)
    (
            //lookaheads for potential symbolicNames "for", "if"
            LOOKAHEAD( )  
            | LOOKAHEAD( )(    { ifNotExists = true; } )  
            | (SymbolicNameString() { indexName = token.image; } ) (    { ifNotExists = true; } )?  
    )
    (   //(v)
        variable=Variable()    { isNode = true; }
    |
        //()-[r]-()
         ( LeftArrow() )? ArrowLine()
         variable=Variable() 
        ArrowLine() ( RightArrow() )?    (LOOKAHEAD() )?
    )
    SymbolicNameString() { funcName = new StringPos( token.image, pos(token) ); }  funcParam=Variable() 
    (  options=MapOrParameter() )?
    {
        return astFactory.createLookupIndex( pos(start), replace, ifNotExists, isNode, indexName, variable, funcName, funcParam, options );
    }
}

SCHEMA_COMMAND DropIndex( Token start ):
{
    Token nodeLabel;
    List> properties;
    Token name;
    boolean ifExists = false;
}
{
    
    ( LOOKAHEAD(2)  nodeLabel=LabelOrRelType()  properties=SymbolicNamePositions() 
        { return astFactory.dropIndex( pos(start), new StringPos<>(nodeLabel.image, pos(nodeLabel) ), properties ); }
    | name=SymbolicNameString() (   { ifExists = true; } )?
        { return astFactory.dropIndex( pos(start), name.image, ifExists ); }
    )
}

List PropertyList():
{
    VARIABLE variable;
    PROPERTY p;
    List properties= new ArrayList<>();
}
{
        (
            variable=Variable() p=Property( variable ) { properties.add( p ); }
            | 
                variable=Variable() p=Property( variable ) { properties.add( p ); }
                ( "," variable=Variable() p=Property( variable ) { properties.add( p ); } )*
            
        )
        {
            return properties;
        }
}

// Administration Commands

ADMINISTRATION_COMMAND RenameCommand():
{
    Token start;
    ADMINISTRATION_COMMAND command;
}
{
    start=
    (
        command=RenameRole( start )
        | command=RenameUser( start )
    )
    {
        return command;
    }
}

ADMINISTRATION_COMMAND GrantCommand() throws Exception:
{
    Token start;
    ADMINISTRATION_COMMAND c;
}
{
    start=
    (
      c=grantPrivilege(start)
      |  (
            LOOKAHEAD( ) c=grantRoleManagement(start)
            | c=GrantRole(start)
        )
      |  c=GrantRole(start)
    )
    {
        return c;
    }
}

ADMINISTRATION_COMMAND RevokeCommand() throws Exception:
{
    Token start;
    ADMINISTRATION_COMMAND c;
}
{
    start=
    (
       ( c=RevokePrivilege(start, false, true) |  c=revokeRoleManagement(start, false, true) )
      |  ( c=RevokePrivilege(start, true, false) |  c=revokeRoleManagement(start, true, false) )
      | c=RevokePrivilege(start, true, true)
      |  (
            LOOKAHEAD( ) c=revokeRoleManagement(start, true, true)
            | c=RevokeRole(start)
      )
      |  c=RevokeRole(start)
    )
    {
        return c;
    }
}

// Role commands

ADMINISTRATION_COMMAND CreateRole( Token start, boolean replace ):
{
    SimpleEither roleName = null;
    SimpleEither sourceRoleName = null;
    boolean ifNotExists = false;
}
{
    
    roleName=SymbolicNameOrStringParameter()
    (    { ifNotExists = true; } )?
    (    sourceRoleName=SymbolicNameOrStringParameter() )?
    {
        return astFactory.createRole( pos( start ), replace, roleName, sourceRoleName, ifNotExists );
    }
}

ADMINISTRATION_COMMAND DropRole( Token start ):
{
    SimpleEither roleName = null;
    boolean ifExists = false;
}
{
    
    roleName=SymbolicNameOrStringParameter()
    (   { ifExists = true; } )?
    {
        return astFactory.dropRole( pos( start ), roleName, ifExists );
    }
}

ADMINISTRATION_COMMAND RenameRole( Token start ):
{
    SimpleEither fromRoleName = null;
    SimpleEither toRoleName = null;
    boolean ifExists = false;
}
{
    
    fromRoleName=SymbolicNameOrStringParameter()
    (   { ifExists = true; } )?
    
    toRoleName=SymbolicNameOrStringParameter()
    {
        return astFactory.renameRole( pos( start ), fromRoleName, toRoleName, ifExists );
    }
}

STATEMENT_WITH_GRAPH ShowRoles( Token start, USE_CLAUSE useClause, boolean showAll ):
{
    boolean withUsers = false;
    YIELD yield = null;
    RETURN_CLAUSE returnClause = null;
    WHERE where = null;
}
{
    
    (   { withUsers = true; } )?
    (
        ( yield = YieldClause() ( returnClause = ReturnClause() )? )
        | ( where=WhereClause() )
    )?
    {
        return astFactory.useGraph( astFactory.showRoles( pos( start ), withUsers, showAll, yield, returnClause, where ), useClause );
    }
}

ADMINISTRATION_COMMAND GrantRole( Token start ):
{
    List> roles;
    List> users;
}
{
    roles=SymbolicNameOrStringParameterList()  users=SymbolicNameOrStringParameterList()
    {
        return astFactory.grantRoles( pos( start ), roles, users );
    }
}

ADMINISTRATION_COMMAND RevokeRole(Token start):
{
    List> roles;
    List> users;
}
{
    roles=SymbolicNameOrStringParameterList()  users=SymbolicNameOrStringParameterList()
    {
        return astFactory.revokeRoles( pos( start ), roles, users );
    }
}

// User commands

ADMINISTRATION_COMMAND CreateUser( Token start, boolean replace ) throws Exception:
{
    Token set = null;
    SimpleEither username = null;
    EXPRESSION password = null;
    boolean ifNotExists = false;
    boolean encrypted = false;
    Optional changeRequired = Optional.empty();
    Optional suspended = Optional.empty();
    Optional> homeDatabase = Optional.empty();
}
{
    
    username=SymbolicNameOrStringParameter()
    (    { ifNotExists = true; } )?
     (
        (  { encrypted = false; })
        | ( <ENCRYPTED> { encrypted = true; })
        )?
        <PASSWORD> password=passwordExpression() ( changeRequired=PasswordChangeRequired( start, changeRequired ) )?
    (
        set=<SET> (
            <PASSWORD> changeRequired=PasswordChangeRequired( set, changeRequired )
            | suspended=UserStatus( set, suspended )
            | homeDatabase=HomeDatabase( set, homeDatabase )
        )
    )*
    {
        return astFactory.createUser( pos( start ), replace, ifNotExists, username, password, encrypted,
                                      changeRequired.orElse( true ), suspended.orElse( null ), homeDatabase.orElse( null ) );
    }
}

ADMINISTRATION_COMMAND DropUser( Token start ) :
{
    SimpleEither<String, PARAMETER> username = null;
    boolean ifExists = false;
}
{
    <USER>
    username=SymbolicNameOrStringParameter()
    ( <IF> <EXISTS> { ifExists = true; } )?
    {
        return astFactory.dropUser( pos( start ), ifExists, username );
    }
}

ADMINISTRATION_COMMAND RenameUser(Token start):
{
    SimpleEither<String, PARAMETER> fromUserName = null;
    SimpleEither<String, PARAMETER> toUserName = null;
    boolean ifExists = false;
}
{
    <USER>
    fromUserName=SymbolicNameOrStringParameter()
    (<IF> <EXISTS> { ifExists = true; } )?
    <TO>
    toUserName=SymbolicNameOrStringParameter()
    {
        return astFactory.renameUser( pos( start ), fromUserName, toUserName, ifExists );
    }
}

ADMINISTRATION_COMMAND AlterCurrentUser( Token start ) throws Exception:
{
    EXPRESSION currentPassword = null;
    EXPRESSION newPassword = null;
}
{
    <CURRENT> <USER> <SET> <PASSWORD> <FROM> currentPassword=passwordExpression() <TO> newPassword=passwordExpression()
    {
        return astFactory.setOwnPassword( pos( start ), currentPassword, newPassword);
    }
}

ADMINISTRATION_COMMAND AlterUser( Token start ) throws Exception:
{
    Token set = null;
    SimpleEither<String, PARAMETER> username = null;
    EXPRESSION password = null;
    boolean ifExists = false;
    boolean encrypted = false;
    Optional<Boolean> changeRequired = Optional.empty();
    Optional<Boolean> suspended = Optional.empty();
    Optional<SimpleEither<String, PARAMETER>> homeDatabase = Optional.empty();
    boolean removeHome = false;
    String passwordSetError = "Duplicate SET PASSWORD clause";
}
{
    <USER>
    username=SymbolicNameOrStringParameter()
    ( <IF> <EXISTS> { ifExists = true; } )?
    (
        (
            set=<SET> (
                <PLAINTEXT> { assertNotAlreadySet( password, set, passwordSetError ); }
                    <PASSWORD> password=SetPassword( set, password ) ( changeRequired=PasswordChangeRequired( set, changeRequired ) )?
                | <ENCRYPTED> { assertNotAlreadySet( password, set, passwordSetError ); encrypted = true; }
                    <PASSWORD> password=SetPassword( set, password ) ( changeRequired=PasswordChangeRequired( set, changeRequired ) )?
                | <PASSWORD> (
                    changeRequired=PasswordChangeRequired( set, changeRequired )
                    | password=SetPassword( set, password ) ( changeRequired=PasswordChangeRequired( set, changeRequired ) )?
                )
                | suspended=UserStatus( set, suspended )
                | homeDatabase=HomeDatabase( set, homeDatabase )
            )
        )+
        | <REMOVE> <HOME> <DATABASE> { removeHome = true; }
    )
    {
        return astFactory.alterUser( pos( start ), ifExists, username, password, encrypted,
            changeRequired.orElse( null ), suspended.orElse( null ), homeDatabase.orElse( null ), removeHome );
    }
}

EXPRESSION SetPassword( Token start, EXPRESSION password ) throws Exception:
{
    String errorMessage = "Duplicate SET PASSWORD clause";
    EXPRESSION newPassword = null;
}
{
    newPassword=passwordExpression()
    {
        if ( password != null ) {
            throw exceptionFactory.syntaxException( new ParseException( errorMessage ), start.beginOffset, start.beginLine, start.beginColumn );
        }
        return newPassword;
    }
}

EXPRESSION passwordExpression():
{
   Token name = null;
   PARAMETER parameter = null;
}
{
    (
        name=StringToken()
        | parameter=Parameter( ParameterType.STRING )
    )
    {
        if ( name != null )
        {
            return astFactory.passwordExpression( pos(name), name.image );
        }
        else
        {
            return astFactory.passwordExpression( parameter );
        }
    }
}

Token StringToken():
{
   Token stringLiteral = null;
}
{
    (
        stringLiteral=<STRING_LITERAL1>
        | stringLiteral=<STRING_LITERAL2>
    )
    {
        return stringLiteral;
    }
}

SimpleEither<String, PARAMETER> StringOrParameter():
{
    Token token = null;
    PARAMETER parameter = null;
}
{
    token=StringToken() { return SimpleEither.<String, PARAMETER>left( token.image ); }
    | parameter=Parameter( ParameterType.STRING ) { return SimpleEither.<String, PARAMETER>right( parameter ); }
}

Optional<Boolean> PasswordChangeRequired( Token start, Optional<Boolean> changeRequired ) throws Exception:
{
    String errorMessage = "Duplicate SET PASSWORD CHANGE [NOT] REQUIRED clause";
    boolean required = true;
}
{
    <CHANGE> ( <NOT> { required = false; } )? <REQUIRED>
    {
        assertNotAlreadySet( changeRequired.orElse(null), start, errorMessage );
        return Optional.of( required );
    }
}

Optional<Boolean> UserStatus( Token start, Optional<Boolean> suspended ) throws Exception:
{
    String errorMessage = "Duplicate SET STATUS {SUSPENDED|ACTIVE} clause";
    boolean suspend = false;
}
{
    <STATUS> (
        <SUSPENDED> { suspend = true; }
        | <ACTIVE> { suspend = false; }
    )
    {
        assertNotAlreadySet( suspended.orElse(null), start, errorMessage );
        return Optional.of( suspend );
    }
}

Optional<SimpleEither<String, PARAMETER>> HomeDatabase( Token start, Optional<SimpleEither<String, PARAMETER>> homeDatabase ) throws Exception:
{
    String errorMessage = "Duplicate SET HOME DATABASE clause";
    SimpleEither<String, PARAMETER> home = null;
}
{
    <HOME> <DATABASE> home=SymbolicDatabaseNameStringOrParameter()
    {
        assertNotAlreadySet( homeDatabase.orElse(null), start, errorMessage );
        return Optional.of( home );
    }
}

STATEMENT_WITH_GRAPH ShowUsers( Token start, USE_CLAUSE useClause ):
{
    YIELD yield = null;
    RETURN_CLAUSE returnClause = null;
    WHERE where = null;
}
{
    <USERS> (
        ( yield = YieldClause() ( returnClause = ReturnClause() )? )
        | where=WhereClause()
    )?
    {
        return astFactory.useGraph( astFactory.showUsers( pos( start ), yield, returnClause, where ), useClause );
    }
}

STATEMENT_WITH_GRAPH ShowCurrentUser( Token start, USE_CLAUSE useClause ):
{
    YIELD yield = null;
    RETURN_CLAUSE returnClause = null;
    WHERE where = null;
}
{
    <CURRENT> <USER> (
        ( yield = YieldClause() ( returnClause = ReturnClause() )? )
        | where=WhereClause() )?
    {
        return astFactory.useGraph( astFactory.showCurrentUser( pos( start ), yield, returnClause, where ), useClause );
    }
}

// Privilege commands

ADMINISTRATION_COMMAND grantRoleManagement(Token start):
{
    PRIVILEGE_TYPE privilege = null;
    List<SimpleEither<String, PARAMETER>> roles = null;
}
{
    privilege=roleManagementPrivilege(start) <TO> roles=SymbolicNameOrStringParameterList()
    {
        return astFactory.grantPrivilege( pos(start), roles, privilege );
    }
}

ADMINISTRATION_COMMAND revokeRoleManagement(Token start, boolean revokeGrant, boolean revokeDeny):
{
    PRIVILEGE_TYPE privilege = null;
    List<SimpleEither<String, PARAMETER>> roles = null;
}
{
    privilege=roleManagementPrivilege(start) <FROM> roles=SymbolicNameOrStringParameterList()
    {
        return astFactory.revokePrivilege( pos(start), roles, privilege, revokeGrant, revokeDeny );
    }
}

PRIVILEGE_TYPE roleManagementPrivilege(Token start):
{
    List<SimpleEither<String, PARAMETER>> roles = null;
}
{
    <MANAGEMENT> <ON> <DBMS>
    {
        return astFactory.dbmsPrivilege( pos(start), astFactory.privilegeAction( ActionType.ROLE_ALL ), astFactory.allQualifier() );
    }
}

ADMINISTRATION_COMMAND grantPrivilege(Token start) throws Exception:
{
    List<SimpleEither<String, PARAMETER>> roles = null;
    PRIVILEGE_TYPE privilege = null;
}
{
    privilege=privilege(start) <TO> roles=SymbolicNameOrStringParameterList()
    {
        return astFactory.grantPrivilege( pos(start), roles, privilege );
    }
}

ADMINISTRATION_COMMAND DenyPrivilege() throws Exception:
{
    Token start;
    List<SimpleEither<String, PARAMETER>> roles = null;
    PRIVILEGE_TYPE privilege = null;
}
{
    start=<DENY>
    (
       privilege=privilege(start)
       // DENY doesn't have a choice conflict for ROLE MANAGEMENT
       | <ROLE> privilege=roleManagementPrivilege(start)
    )
    <TO> roles=SymbolicNameOrStringParameterList()
    {
        return astFactory.denyPrivilege( pos(start), roles, privilege );
    }
}

ADMINISTRATION_COMMAND RevokePrivilege(Token start, boolean revokeGrant, boolean revokeDeny) throws Exception:
{
    List<SimpleEither<String, PARAMETER>> roles = null;
    PRIVILEGE_TYPE privilege = null;
}
{
    privilege=privilege(start) <FROM> roles=SymbolicNameOrStringParameterList()
    {
        return astFactory.revokePrivilege( pos(start), roles, privilege, revokeGrant, revokeDeny );
    }
}

PRIVILEGE_TYPE privilege(Token start) throws Exception:
{
    PRIVILEGE_TYPE privilege = null;
}
{
    (
        privilege=allPrivilege(start)
        | privilege=createPrivilege(start)
        | privilege=dropPrivilege(start)
        | privilege=showPrivilege(start)
        | privilege=setPrivilege(start)
        | privilege=removePrivilege(start)
        | privilege=databasePrivilege(start)
        | privilege=dbmsPrivilege(start)
        | privilege=writePrivilege(start)
        | privilege=qualifiedGraphPrivileges(start)
        | privilege=qualifiedGraphPrivilegesWithProperty(start)
    )
    {
        return privilege;
    }
}

PRIVILEGE_TYPE allPrivilege(Token start) throws Exception:
{
    ADMINISTRATION_ACTION action = null;
    List<SimpleEither<String, PARAMETER>> names = null;
    boolean isAll = false;
    String type = null;
    Token t = null;
    ScopeType scopeType = ScopeType.NAMED;
}
{
    <ALL> ((<DBMS> { type = "DBMS"; } | <GRAPH> { type = "GRAPH"; } | <DATABASE> { type = "DATABASE"; } )? <PRIVILEGES>)? <ON> (
        t=<DEFAULT_TOKEN> (
             <GRAPH> {
                 assertValidType( t, type, "GRAPH" );
                 return astFactory.graphPrivilege( pos(start), astFactory.privilegeAction( ActionType.GRAPH_ALL ), astFactory.graphScopes( pos( t ), null, ScopeType.DEFAULT ), null, astFactory.allQualifier() );
             }
             | <DATABASE> {
                assertValidType( t, type, "DATABASE" );
                return astFactory.databasePrivilege( pos(start), astFactory.privilegeAction( ActionType.DATABASE_ALL ), astFactory.databaseScopes( pos( t ), null, ScopeType.DEFAULT ), astFactory.allDatabasesQualifier() );
             }
        )
        | t=<HOME> (
            <GRAPH> {
                assertValidType( t, type, "GRAPH" );
                return astFactory.graphPrivilege( pos(start), astFactory.privilegeAction( ActionType.GRAPH_ALL ), astFactory.graphScopes( pos( t ), null, ScopeType.HOME ), null, astFactory.allQualifier() );
            }
            | <DATABASE> {
                assertValidType( t, type, "DATABASE" );
                return astFactory.databasePrivilege( pos(start), astFactory.privilegeAction( ActionType.DATABASE_ALL ), astFactory.databaseScopes( pos( t ), null, ScopeType.HOME ), astFactory.allDatabasesQualifier() );
            }
        )
        | t=<DBMS> {
            assertValidType( t, type, "DBMS" );
            return astFactory.dbmsPrivilege( pos(start), astFactory.privilegeAction( ActionType.DBMS_ALL ), astFactory.allQualifier() );
        }
        | (t=<GRAPH> | t=<GRAPHS>) (<TIMES> { scopeType = ScopeType.ALL; } | names=SymbolicDatabaseNameStringOrParameterList()) {
            assertValidType( t, type, "GRAPH" );
            return astFactory.graphPrivilege( pos(start), astFactory.privilegeAction( ActionType.GRAPH_ALL ), astFactory.graphScopes( pos( t ), names, scopeType ), null, astFactory.allQualifier() );
        }
        | (t=<DATABASE> | t=<DATABASES>) (<TIMES> { scopeType = ScopeType.ALL; } | names=SymbolicDatabaseNameStringOrParameterList()) {
            assertValidType( t, type, "DATABASE" );
            return astFactory.databasePrivilege( pos(start), astFactory.privilegeAction( ActionType.DATABASE_ALL ), astFactory.databaseScopes( pos( t ), names, scopeType ), astFactory.allDatabasesQualifier() );
        }
    )
}

PRIVILEGE_TYPE createPrivilege(Token start):
{
    PRIVILEGE_TYPE privilege = null;
    ADMINISTRATION_ACTION action = null;
    List<DATABASE_SCOPE> databases = null;
    List<GRAPH_SCOPE> graphs = null;
    List<PRIVILEGE_QUALIFIER> qualifier = new ArrayList<>();
}
{
    <CREATE>
    (
       (
           (
               (<INDEX> | <INDEXES>) { action = astFactory.privilegeAction( ActionType.INDEX_CREATE ); }
               | (<CONSTRAINT> | <CONSTRAINTS>) { action = astFactory.privilegeAction( ActionType.CONSTRAINT_CREATE ); }
               | <NEW> (
                   (<NODE>)? (<LABEL> | <LABELS>) { action = astFactory.privilegeAction( ActionType.CREATE_LABEL ); }
                   | (<RELATIONSHIP>)? (<TYPE> | <TYPES>) { action = astFactory.privilegeAction( ActionType.CREATE_RELTYPE ); }
                   | (<PROPERTY>)? (<NAME> | <NAMES>) { action = astFactory.privilegeAction( ActionType.CREATE_PROPERTYKEY ); }
               )
           ) <ON> databases=DatabaseScopeList() { privilege = astFactory.databasePrivilege( pos(start), action, databases, astFactory.allDatabasesQualifier() ); }
       ) | (
           (
               <DATABASE> { action = astFactory.privilegeAction( ActionType.DATABASE_CREATE ); }
               | <ALIAS> { action = astFactory.privilegeAction( ActionType.ALIAS_CREATE ); }
               | <ROLE> { action = astFactory.privilegeAction( ActionType.ROLE_CREATE ); }
               | <USER> { action = astFactory.privilegeAction( ActionType.USER_CREATE ); }
           ) <ON> <DBMS> { privilege = astFactory.dbmsPrivilege( pos(start), action,  astFactory.allQualifier() ); }
       ) | ( <ON> graphs=graphScopeList() qualifier=graphQualifier() { privilege = astFactory.graphPrivilege( pos(start), astFactory.privilegeAction( ActionType.GRAPH_CREATE ), graphs, null, qualifier ); } )
    ) { return privilege; }
}

PRIVILEGE_TYPE dropPrivilege(Token start):
{
    PRIVILEGE_TYPE privilege = null;
    ADMINISTRATION_ACTION action = null;
    List<DATABASE_SCOPE> databases = null;
}
{
    <DROP>
    (
       (
           (
               (<INDEX> | <INDEXES>) { action = astFactory.privilegeAction( ActionType.INDEX_DROP ); }
               | (<CONSTRAINT> | <CONSTRAINTS>) { action = astFactory.privilegeAction( ActionType.CONSTRAINT_DROP ); }
           ) <ON> databases=DatabaseScopeList() { privilege = astFactory.databasePrivilege( pos(start), action, databases, astFactory.allDatabasesQualifier() ); }
       ) | (
           (
               <DATABASE> { action = astFactory.privilegeAction( ActionType.DATABASE_DROP ); }
               | <ALIAS> { action = astFactory.privilegeAction( ActionType.ALIAS_DROP ); }
               | <ROLE> { action = astFactory.privilegeAction( ActionType.ROLE_DROP ); }
               | <USER> { action = astFactory.privilegeAction( ActionType.USER_DROP ); }
           ) <ON> <DBMS> { privilege = astFactory.dbmsPrivilege( pos(start), action, astFactory.allQualifier() ); }
       )
    ) { return privilege; }
}

PRIVILEGE_TYPE showPrivilege(Token start):
{
    PRIVILEGE_TYPE privilege = null;
    ADMINISTRATION_ACTION action = null;
    List<DATABASE_SCOPE> databases = null;
    List<PRIVILEGE_QUALIFIER> qualifier = astFactory.allDatabasesQualifier();
    List<SimpleEither<String, PARAMETER>>qualifiers = null;
}
{
    <SHOW>
    (
        (
            (
                (<INDEX> | <INDEXES>) { action = astFactory.privilegeAction( ActionType.INDEX_SHOW ); }
                | (<CONSTRAINT> | <CONSTRAINTS>) { action = astFactory.privilegeAction( ActionType.CONSTRAINT_SHOW ); }
                | (<TRANSACTION> | <TRANSACTIONS>) { action = astFactory.privilegeAction( ActionType.TRANSACTION_SHOW ); qualifier = astFactory.allUsersQualifier(); }
                    ( <LPAREN> (<TIMES> | qualifiers=SymbolicNameOrStringParameterList() { qualifier = astFactory.userQualifier(qualifiers); } ) <RPAREN> )?
            ) <ON> databases=DatabaseScopeList() { privilege = astFactory.databasePrivilege( pos(start), action, databases, qualifier ); }
        ) | (
            (
                <ALIAS> { action = astFactory.privilegeAction( ActionType.ALIAS_SHOW ); }
                | <PRIVILEGE> { action = astFactory.privilegeAction( ActionType.PRIVILEGE_SHOW ); }
                | <ROLE> { action = astFactory.privilegeAction( ActionType.ROLE_SHOW ); }
                | <USER> { action = astFactory.privilegeAction( ActionType.USER_SHOW ); }
            ) <ON> <DBMS> { privilege = astFactory.dbmsPrivilege( pos(start), action, astFactory.allQualifier() ); }
        )
    ) { return privilege; }
}

PRIVILEGE_TYPE setPrivilege(Token start):
{
    PRIVILEGE_TYPE privilege = null;
    ADMINISTRATION_ACTION action = null;
    List<GRAPH_SCOPE> graphs = null;
    PRIVILEGE_RESOURCE resource = null;
    List<PRIVILEGE_QUALIFIER> qualifier = null;
}
{
    <SET>
    (
        (
            (
                ( <PASSWORD> | <PASSWORDS> ) { action = astFactory.privilegeAction( ActionType.USER_PASSWORD ); }
                | <USER> (
                    <STATUS> { action = astFactory.privilegeAction( ActionType.USER_STATUS ); }
                    | <HOME> <DATABASE> { action = astFactory.privilegeAction( ActionType.USER_HOME ); }
                )
                | <DATABASE> <ACCESS> { action = astFactory.privilegeAction( ActionType.SET_DATABASE_ACCESS); }
            ) <ON> <DBMS> { privilege = astFactory.dbmsPrivilege( pos(start), action, astFactory.allQualifier() ); }
        ) | (
            ( <LABEL> resource=labelResource() <ON> graphs=graphScopeList() { privilege = astFactory.graphPrivilege( pos(start), astFactory.privilegeAction( ActionType.GRAPH_LABEL_SET ), graphs, resource, List.of( astFactory.allLabelsQualifier( pos(start) ) ) ); } )
            | ( <PROPERTY> resource=propertyResource() <ON> graphs=graphScopeList() qualifier=graphQualifier() { privilege = astFactory.graphPrivilege( pos(start), astFactory.privilegeAction( ActionType.GRAPH_PROPERTY_SET ), graphs, resource, qualifier ); } )
        )
    ) { return privilege; }
}

PRIVILEGE_TYPE removePrivilege(Token start):
{
    PRIVILEGE_TYPE privilege = null;
    List<GRAPH_SCOPE> graphs = null;
    PRIVILEGE_RESOURCE resource = null;
    ADMINISTRATION_ACTION action = null;
}
{
    <REMOVE>
    (
        (
            (
                <PRIVILEGE> { action = astFactory.privilegeAction( ActionType.PRIVILEGE_REMOVE ); }
                | <ROLE> { action = astFactory.privilegeAction( ActionType.ROLE_REMOVE ); }
            ) <ON> <DBMS> { privilege = astFactory.dbmsPrivilege( pos(start), action, astFactory.allQualifier() ); }
        ) | ( <LABEL> resource=labelResource() <ON> graphs=graphScopeList() { privilege = astFactory.graphPrivilege( pos(start), astFactory.privilegeAction( ActionType.GRAPH_LABEL_REMOVE ), graphs, resource, List.of( astFactory.allLabelsQualifier( pos(start) ) ) ); } )
    ) { return privilege; }
}

PRIVILEGE_TYPE writePrivilege(Token start):
{
    List<GRAPH_SCOPE> graphs = null;
    List<SimpleEither<String, PARAMETER>> qualifiers = null;
}
{
    <WRITE> <ON> graphs=graphScopeList()
    {
        return astFactory.graphPrivilege( pos(start), astFactory.privilegeAction( ActionType.GRAPH_WRITE ), graphs, null, List.of( astFactory.allElementsQualifier( pos(start) ) ) );
    }
}

PRIVILEGE_TYPE databasePrivilege(Token start):
{
    ADMINISTRATION_ACTION action = null;
    List<DATABASE_SCOPE> databases = null;
    List<PRIVILEGE_QUALIFIER> qualifier = astFactory.allDatabasesQualifier();
    List<SimpleEither<String, PARAMETER>>qualifiers = null;
}
{
    (
        <ACCESS> { action = astFactory.privilegeAction( ActionType.ACCESS ); }
        | <START> { action = astFactory.privilegeAction( ActionType.DATABASE_START ); }
        | <STOP> { action = astFactory.privilegeAction( ActionType.DATABASE_STOP ); }
        | (<INDEX> | <INDEXES>) (<MANAGEMENT>)? { action = astFactory.privilegeAction( ActionType.INDEX_ALL ); }
        | (<CONSTRAINT> | <CONSTRAINTS>) (<MANAGEMENT>)? { action = astFactory.privilegeAction( ActionType.CONSTRAINT_ALL ); }
        | <TRANSACTION> (<MANAGEMENT>)? { qualifier = astFactory.allUsersQualifier(); } (<LPAREN> (<TIMES> | qualifiers=SymbolicNameOrStringParameterList() { qualifier = astFactory.userQualifier(qualifiers); } ) <RPAREN>)? { action = astFactory.privilegeAction( ActionType.TRANSACTION_ALL ); }
        | <TERMINATE> (<TRANSACTION> | <TRANSACTIONS>) { qualifier = astFactory.allUsersQualifier(); } (<LPAREN> (<TIMES> | qualifiers=SymbolicNameOrStringParameterList() { qualifier = astFactory.userQualifier(qualifiers); } ) <RPAREN>)? { action = astFactory.privilegeAction( ActionType.TRANSACTION_TERMINATE ); }
        | <NAME> (<MANAGEMENT>)? { action = astFactory.privilegeAction( ActionType.CREATE_TOKEN ); }
    )
    <ON> databases=DatabaseScopeList()
    {
        return astFactory.databasePrivilege( pos(start), action, databases, qualifier );
    }
}

// all dbms privileges apart from EXECUTE PROCEDURE/FUNCTION since we have to solve globbing for that first
PRIVILEGE_TYPE dbmsPrivilege(Token start):
{
    ADMINISTRATION_ACTION action = null;
    List<PRIVILEGE_QUALIFIER> qualifier = astFactory.allQualifier();
    List<SimpleEither<String, PARAMETER>> qualifiers = null;
}
{
    (
        <ALTER> (
            <USER> { action = astFactory.privilegeAction( ActionType.USER_ALTER ); }
            | <DATABASE> { action = astFactory.privilegeAction( ActionType.DATABASE_ALTER ); }
            | <ALIAS> { action = astFactory.privilegeAction( ActionType.ALIAS_ALTER ); }
        )
        | <ASSIGN> (
            <PRIVILEGE> { action = astFactory.privilegeAction( ActionType.PRIVILEGE_ASSIGN ); }
            | <ROLE> { action = astFactory.privilegeAction( ActionType.ROLE_ASSIGN ); }
        )
        | <DATABASE> <MANAGEMENT> { action = astFactory.privilegeAction( ActionType.DATABASE_MANAGEMENT ); }
        | <ALIAS> <MANAGEMENT> { action = astFactory.privilegeAction( ActionType.ALIAS_MANAGEMENT ); }
        | <PRIVILEGE> <MANAGEMENT> { action = astFactory.privilegeAction( ActionType.PRIVILEGE_ALL ); }
        | <RENAME> (
            <ROLE> { action = astFactory.privilegeAction( ActionType.ROLE_RENAME ); }
            | <USER> { action = astFactory.privilegeAction( ActionType.USER_RENAME ); }
        )
        | <USER> <MANAGEMENT> { action = astFactory.privilegeAction( ActionType.USER_ALL ); }
        | <IMPERSONATE> { qualifier = astFactory.allUsersQualifier(); }
            ( <LPAREN> (<TIMES> | qualifiers=SymbolicNameOrStringParameterList() { qualifier = astFactory.userQualifier(qualifiers); } ) <RPAREN> )?
            { action = astFactory.privilegeAction( ActionType.USER_IMPERSONATE ); }
    )
    <ON> <DBMS>
    {
        return astFactory.dbmsPrivilege( pos(start), action, qualifier );
    }
}

PRIVILEGE_TYPE qualifiedGraphPrivilegesWithProperty(Token start):
{
    ADMINISTRATION_ACTION action = null;
    List<GRAPH_SCOPE> graphs = null;
    List<PRIVILEGE_QUALIFIER> qualifier = null;
    PRIVILEGE_RESOURCE resource = null;
}
{
    (
        <TRAVERSE> { action = astFactory.privilegeAction( ActionType.GRAPH_TRAVERSE ); }
        | ( <READ> { action = astFactory.privilegeAction( ActionType.GRAPH_READ ); } resource=propertyResource() )
        | ( <MATCH> { action = astFactory.privilegeAction( ActionType.GRAPH_MATCH ); } resource=propertyResource() )
    )
    <ON> graphs=graphScopeList() qualifier=graphQualifier() (<LPAREN> <TIMES> <RPAREN>)?
    {
        return astFactory.graphPrivilege( pos(start), action, graphs, resource, qualifier );
    }
}

PRIVILEGE_TYPE qualifiedGraphPrivileges(Token start):
{
    ADMINISTRATION_ACTION action = null;
    List<GRAPH_SCOPE> graphs = null;
    List<PRIVILEGE_QUALIFIER> qualifier = null;
    PRIVILEGE_RESOURCE resource = null;
}
{
    (
        <DELETE> { action = astFactory.privilegeAction( ActionType.GRAPH_DELETE ); }
        | <MERGE> resource=propertyResource() { action = astFactory.privilegeAction( ActionType.GRAPH_MERGE ); }
    )
    <ON> graphs=graphScopeList() qualifier=graphQualifier()
    {
        return astFactory.graphPrivilege( pos(start), action, graphs, resource, qualifier );
    }
}

PRIVILEGE_RESOURCE labelResource():
{
    List<String> names = null;
    Token t;
}
{
    <TIMES> { return astFactory.allLabelsResource( pos(token) ); }
    | names=SymbolicNameList1() { return astFactory.labelsResource( pos(token), names ); }
}

PRIVILEGE_RESOURCE propertyResource():
{
    List<String> names = null;
    PRIVILEGE_RESOURCE resource = null;
    Token t;
}
{
    <LCURLY> (
        <TIMES> { resource = astFactory.allPropertiesResource( pos(token) ); }
        | names=SymbolicNameList1() { resource = astFactory.propertiesResource( pos(token), names ); }
    ) <RCURLY>
    {
        return resource;
    }
}

List<PRIVILEGE_QUALIFIER> graphQualifier():
{
    List<PRIVILEGE_QUALIFIER> qualifier = new ArrayList<>();
    List<String> names = null;
    Token n = null;
}
{
    (
        (<RELATIONSHIP> | <RELATIONSHIPS>) (
            <TIMES> { qualifier.add( astFactory.allRelationshipsQualifier( pos(token) ) ); }
            | ( n=SymbolicNameString() { qualifier.add( astFactory.relationshipQualifier( pos(n), n.image ) ); } ( "," n=SymbolicNameString() { qualifier.add( astFactory.relationshipQualifier( pos(n), n.image ) ); } )* )
        )
        | (<NODE> | <NODES>) (
            <TIMES> { qualifier.add( astFactory.allLabelsQualifier( pos(token) ) ); }
            | ( n=SymbolicNameString() { qualifier.add( astFactory.labelQualifier( pos(n), n.image ) ); } ( "," n=SymbolicNameString() { qualifier.add( astFactory.labelQualifier( pos(n), n.image ) ); } )* )
        )
        | (<ELEMENT> | <ELEMENTS>) (
            <TIMES> { qualifier.add( astFactory.allElementsQualifier( pos(token) ) ); }
            | ( n=SymbolicNameString() { qualifier.add( astFactory.elementQualifier( pos(n), n.image ) ); } ( "," n=SymbolicNameString() { qualifier.add( astFactory.elementQualifier( pos(n), n.image ) ); } )* )
        )
    )?
    {
        if ( qualifier.isEmpty() ) {
            qualifier.add( astFactory.allElementsQualifier( pos(token) ) );
        }
        return qualifier;
    }
}

// Database commands

ADMINISTRATION_COMMAND CreateDatabase( Token start, boolean replace ):
{
    SimpleEither<String, PARAMETER> databaseName = null;
    boolean ifNotExists = false;
    WAIT_CLAUSE wait = astFactory.wait( false, -1 );
    SimpleEither<Map<String, EXPRESSION>, PARAMETER> options = null;
}
{
    <DATABASE> databaseName=SymbolicDatabaseNameStringOrParameter()
    ( <IF> <NOT> <EXISTS> { ifNotExists = true; } )?
    ( options=Options() )?
    ( wait = WaitClause() )?
    {
       return astFactory.createDatabase( pos( start ), replace, databaseName, ifNotExists, wait, options );
    }
}

SimpleEither<Map<String, EXPRESSION>, PARAMETER> Options() :
{
     SimpleEither<Map<String, EXPRESSION>, PARAMETER> options = null;
}
{
    <OPTIONS> options=MapOrParameter()
    {
        return options;
    }
}

ADMINISTRATION_COMMAND DropDatabase( Token start ):
{
    SimpleEither<String, PARAMETER> databaseName = null;
    boolean ifExists = false;
    WAIT_CLAUSE wait = astFactory.wait( false, -1 );
    boolean dumpData = false;
}
{
    <DATABASE> databaseName=SymbolicDatabaseNameStringOrParameter()
    ( <IF> <EXISTS> { ifExists = true; } )?
    ( ( <DUMP> { dumpData = true; } | <DESTROY> ) <DATA> )?
    ( wait = WaitClause() )?
    {
        return astFactory.dropDatabase( pos( start ), databaseName, ifExists, dumpData, wait );
    }
}

ADMINISTRATION_COMMAND AlterDatabase( Token start ):
{
    SimpleEither<String, PARAMETER> databaseName = null;
    boolean ifExists = false;
    AccessType accessType = AccessType.READ_WRITE;
}
{
    <DATABASE>
    databaseName=SymbolicDatabaseNameStringOrParameter()
    ( <IF> <EXISTS> { ifExists = true; } )?
    <SET> <ACCESS> <READ> ( <ONLY> { accessType = AccessType.READ_ONLY; } | <WRITE> )
    {
        return astFactory.alterDatabase( pos( start ), databaseName, ifExists, accessType );
    }
}

ADMINISTRATION_COMMAND StartDatabase():
{
    Token start;
    SimpleEither<String, PARAMETER> databaseName;
    WAIT_CLAUSE wait = astFactory.wait( false, -1 );
}
{
    start=<START> <DATABASE> databaseName=SymbolicDatabaseNameStringOrParameter() ( wait=WaitClause() )?
    {
      return astFactory.startDatabase( pos( start ), databaseName, wait );
    }
}

ADMINISTRATION_COMMAND StopDatabase():
{
    Token start;
    SimpleEither<String, PARAMETER> databaseName;
    WAIT_CLAUSE wait = astFactory.wait( false, -1 );
}
{
    start=<STOP> <DATABASE> databaseName=SymbolicDatabaseNameStringOrParameter() ( wait=WaitClause() )?
    {
      return astFactory.stopDatabase( pos( start ), databaseName, wait );
    }
}

WAIT_CLAUSE WaitClause():
{
    Token number = null;
    boolean wait = false;
}
{
    (
        <WAIT> { wait = true; } ( number=<UNSIGNED_DECIMAL_INTEGER> ( <SEC> | <SECOND> | <SECONDS> )? )?
        | <NOWAIT>
    )
    {
        if ( number != null )
        {
            return astFactory.wait( wait, Long.parseLong( number.image) );
        }
        return astFactory.wait( wait, -1 ) ;
    }
}

STATEMENT_WITH_GRAPH ShowDatabase( Token start, USE_CLAUSE useClause ):
{
    DATABASE_SCOPE scope;
    YIELD yield = null;
    RETURN_CLAUSE returnClause = null;
    WHERE where = null;
}
{
   scope = DatabaseScope()
        (
            ( yield = YieldClause() ( returnClause = ReturnClause() )? )
            | ( where=WhereClause() )
        )?
   {
        return astFactory.useGraph( astFactory.showDatabase( pos( start ), scope, yield, returnClause, where), useClause );
   }
}

DATABASE_SCOPE DatabaseScope():
{
    Token start = null;
    SimpleEither<String, PARAMETER> name = null;
    boolean isDefault = false;
    boolean isHome = false;
}
{
    (
        start=<DATABASE> name=SymbolicDatabaseNameStringOrParameter()
        | start=<DATABASES>
        | start=<DEFAULT_TOKEN> <DATABASE> { isDefault = true; }
        | start=<HOME> <DATABASE> { isHome = true; }
    )
  {
    return astFactory.databaseScope( pos( start ), name, isDefault, isHome );
  }
}

List<DATABASE_SCOPE> DatabaseScopeList():
{
    Token start = null;
    List<SimpleEither<String, PARAMETER>> names = null;
    ScopeType type = ScopeType.NAMED;
}
{
    (
        (start=<DATABASE> | start=<DATABASES>) (<TIMES> { type = ScopeType.ALL; } | names=SymbolicDatabaseNameStringOrParameterList())
        | start=<DEFAULT_TOKEN> <DATABASE> { type = ScopeType.DEFAULT; }
        | start=<HOME> <DATABASE> { type = ScopeType.HOME; }
    )
  {
    return astFactory.databaseScopes( pos( start ), names, type );
  }
}

List<GRAPH_SCOPE> graphScopeList():
{
    Token start = null;
    List<SimpleEither<String, PARAMETER>> names = null;
    ScopeType type = ScopeType.NAMED;
}
{
    (
        (start=<GRAPH> | start=<GRAPHS>) (<TIMES> { type = ScopeType.ALL; } | names=SymbolicDatabaseNameStringOrParameterList())
        | start=<DEFAULT_TOKEN> <GRAPH> { type = ScopeType.DEFAULT; }
        | start=<HOME> <GRAPH> { type = ScopeType.HOME; }
    )
    {
        return astFactory.graphScopes( pos( start ), names, type );
    }
}

ADMINISTRATION_COMMAND CreateAlias( Token start, boolean replace ) throws Exception:
{
    AliasName<PARAMETER> aliasName = null;
    SimpleEither<String, PARAMETER> targetName = null;
    boolean ifNotExists = false;
    SimpleEither<String, PARAMETER> url = null;
    SimpleEither<String, PARAMETER> username = null;
    EXPRESSION password = null;
    SimpleEither<Map<String, EXPRESSION>, PARAMETER> driverSettings = null;
}
{
    <ALIAS>
    aliasName=SymbolicAliasName()
    ( <IF> <NOT> <EXISTS> { ifNotExists = true; } )?
    <FOR> <DATABASE> targetName=SymbolicDatabaseNameStringOrParameter()
    (
        <AT> url=StringOrParameter()
        <USER> username=SymbolicNameOrStringParameter()
        <PASSWORD> password=passwordExpression()
        ( <DRIVER> driverSettings=MapOrParameter() )?
    )?
    {
       if ( url == null )
       {
           return astFactory.createLocalDatabaseAlias( pos( start ), replace, aliasName.getLocalAliasName(), targetName, ifNotExists );
       }
       else
       {
           return astFactory.createRemoteDatabaseAlias( pos( start ), replace, aliasName.getRemoteAliasName(), targetName, ifNotExists, url, username, password, driverSettings );
       }
    }
}

ADMINISTRATION_COMMAND DropAlias( Token start ):
{
    SimpleEither<String, PARAMETER> aliasName = null;
    boolean ifExists = false;
}
{
    <ALIAS> aliasName=SymbolicDatabaseNameStringOrParameter()
    (<IF> <EXISTS> { ifExists = true; })?
    <FOR> <DATABASE>
    {
        return astFactory.dropAlias( pos( start ), aliasName, ifExists );
    }
}


ADMINISTRATION_COMMAND AlterAlias( Token start ) throws Exception:
{
    AliasName<PARAMETER> aliasName = null;
    SimpleEither<String, PARAMETER> targetName = null;
    boolean ifExists = false;
    SimpleEither<String, PARAMETER> url = null;
    SimpleEither<String, PARAMETER> username = null;
    EXPRESSION password = null;
    SimpleEither<Map<String, EXPRESSION>, PARAMETER> driverSettings = null;
    Token errorStart = null;
    String alreadySet = "Duplicate SET DATABASE %s clause";
}
{
    <ALIAS> aliasName=SymbolicAliasName()
    (<IF> <EXISTS> { ifExists = true; })?
    <SET> <DATABASE>
    (
        errorStart=<TARGET> { assertNotAlreadySet( targetName, errorStart, String.format(alreadySet, errorStart.image) ); } targetName=SymbolicDatabaseNameStringOrParameter()  ( <AT> url=StringOrParameter() )?
        | errorStart=<USER> { assertNotAlreadySet( username, errorStart, String.format(alreadySet, errorStart.image) ); } username=SymbolicNameOrStringParameter()
        | errorStart=<PASSWORD> { assertNotAlreadySet( password, errorStart, String.format(alreadySet, errorStart.image) ); } password=passwordExpression()
        | errorStart=<DRIVER> { assertNotAlreadySet( driverSettings, errorStart, String.format(alreadySet, errorStart.image) ); } driverSettings=MapOrParameter()
    )+
    {
        if ( url == null && username == null && password == null && driverSettings == null )
        {
            return astFactory.alterLocalDatabaseAlias( pos( start ), aliasName.getLocalAliasName(), targetName, ifExists );
        }
        else
        {
            return astFactory.alterRemoteDatabaseAlias( pos( start ), aliasName.getRemoteAliasName(), targetName, ifExists, url, username, password, driverSettings );
        }
    }
}

STATEMENT ShowAliases( Token start, USE_CLAUSE useClause ):
{
    WHERE where = null;
    YIELD yieldClause = null;
    RETURN_CLAUSE returnClause = null;
}
{
    ( <ALIAS> | <ALIASES> )
    ( <FOR> ( <DATABASE> | <DATABASES> ))
    (
        ( yieldClause=YieldClause() ( returnClause=ReturnClause() )? )
        | where=WhereClause()
    )?
    {
        return astFactory.useGraph( astFactory.showAliases( pos( start ), yieldClause, returnClause, where), useClause );
    }
}

List<SimpleEither<String, PARAMETER>> SymbolicDatabaseNameStringOrParameterList():
{
    SimpleEither<String, PARAMETER> dbSymbol = null;
    List<SimpleEither<String, PARAMETER>> databases = new ArrayList<>();
}
{
    dbSymbol=SymbolicDatabaseNameStringOrParameter() { databases.add(dbSymbol); }
    ("," dbSymbol=SymbolicDatabaseNameStringOrParameter() { databases.add(dbSymbol); } )*
    {
        return databases;
    }
}

SimpleEither<String, PARAMETER> SymbolicDatabaseNameStringOrParameter():
{
    Token nameToken;
    StringBuilder nameBuilder;
    PARAMETER parameter;
}
{
    nameToken=SymbolicNameString() { nameBuilder =new StringBuilder( nameToken.image ); }
        ( <DOT> nameToken=SymbolicNameString() { nameBuilder.append( "." ); nameBuilder.append( nameToken.image ); } )*
        {
            return SimpleEither.<String, PARAMETER>left( nameBuilder.toString() );
        }
    | parameter=Parameter(ParameterType.STRING) { return SimpleEither.<String, PARAMETER>right( parameter ); }
}

AliasName<PARAMETER> SymbolicAliasName() throws Exception:
{
    Token token;
    AliasName<PARAMETER> name = null;
    PARAMETER parameter;
}
{
    token=SymbolicNameString() { name = new AliasName<PARAMETER>( exceptionFactory, token ); }
        ( <DOT> token=SymbolicNameString() { name.add( token ); } )*
        {
            return name;
        }
    | parameter=Parameter(ParameterType.STRING) { return new AliasName<PARAMETER>( exceptionFactory, parameter ); }
}

List<SimpleEither<String, PARAMETER>> SymbolicNameOrStringParameterList() :
{
    SimpleEither<String, PARAMETER> entry;
    List<SimpleEither<String, PARAMETER>> list = new ArrayList<>();
}
{
    entry=SymbolicNameOrStringParameter() { list.add( entry ); }
    ( "," entry=SymbolicNameOrStringParameter() { list.add( entry ); } )*
    {
        return list;
    }
}

SimpleEither<String, PARAMETER> SymbolicNameOrStringParameter():
{
    Token name;
    PARAMETER parameter;
}
{
    name=SymbolicNameString() { return SimpleEither.<String, PARAMETER>left( name.image ); }
    | parameter=Parameter(ParameterType.STRING) { return SimpleEither.<String, PARAMETER>right( parameter ); }
}

String TransactionIdString():
{
    Token t;
}
{
    t=StringToken() { return token.image; }
}

List<String> TransactionIdStringList():
{
    String entry;
    List<String> list = new ArrayList<>();
}
{
    entry=TransactionIdString() { list.add( entry ); }
    ( "," entry=TransactionIdString() { list.add( entry ); } )*
    {
        return list;
    }
}

SimpleEither<Map<String, EXPRESSION>, PARAMETER> MapOrParameter():
{
    Map<String, EXPRESSION> map = null;
    PARAMETER parameter;
}
{
    map=Map() { return SimpleEither.<Map<String,EXPRESSION>,PARAMETER>left ( map ); }
    | parameter=Parameter( ParameterType.MAP ) { return SimpleEither.<Map<String,EXPRESSION>,PARAMETER>right( parameter ); }
}

Map<String, EXPRESSION> Map():
{
    Token key;
    EXPRESSION expr;
    LinkedHashMap<String, EXPRESSION> map = new LinkedHashMap<>();
}
{
    <LCURLY>
    (
        key=SymbolicNameString()  ":" expr=Expression() { map.put( key.image, expr ); }
        ( "," key=SymbolicNameString()  ":" expr=Expression() { map.put( key.image, expr ); } )*
    )?
    <RCURLY>
    {
        return map;
    }
}

List<StringPos<POS>> SymbolicNamePositions():
{
    List<StringPos<POS>> names = new ArrayList<>();
}
{
    SymbolicNameString() { names.add( new StringPos<>( token.image, pos( token ) ) ); }
    ( "," SymbolicNameString() { names.add( new StringPos<>( token.image, pos( token ) ) ); } )*
    {
        return names;
    }
}

Token SymbolicNameString() :
{
    Token t;
}
{
    (
        t=<IDENTIFIER>
        | t=<ESCAPED_SYMBOLIC_NAME>

        //list of allowed keywords
        | t=<ACCESS>
        | t=<ACTIVE>
        | t=<ALIAS>
        | t=<ALIASES>
        | t=<ALL_SHORTEST_PATH>
        | t=<ALL>
        | t=<ALTER>
        | t=<AND>
        | t=<ANY>
        | t=<AS>
        | t=<ASC>
        | t=<ASSERT>
        | t=<ASSIGN>
        | t=<AT>
        | t=<BRIEF>
        | t=<BTREE>
        | t=<BUILT>
        | t=<BY>
        | t=<CALL>
        | t=<CASE>
        | t=<CATALOG>
        | t=<CHANGE>
        | t=<COMMIT>
        | t=<CONSTRAINT>
        | t=<CONSTRAINTS>
        | t=<CONTAINS>
        | t=<COPY>
        | t=<COUNT>
        | t=<CREATE>
        | t=<CSV>
        | t=<CURRENT>
        | t=<DATA>
        | t=<DATABASE>
        | t=<DATABASES>
        | t=<DBMS>
        | t=<DEFAULT_TOKEN>
        | t=<DEFINED>
        | t=<DELETE>
        | t=<DENY>
        | t=<DESC>
        | t=<DESTROY>
        | t=<DETACH>
        | t=<DISTINCT>
        | t=<DRIVER>
        | t=<DROP>
        | t=<DUMP>
        | t=<EACH>
        | t=<ELEMENT>
        | t=<ELEMENTS>
        | t=<ELSE>
        | t=<ENCRYPTED>
        | t=<END>
        | t=<ENDS>
        | t=<EXECUTABLE>
        | t=<EXIST>
        | t=<EXISTENCE>
        | t=<EXISTS>
        | t=<EXTRACT>
        | t=<FALSE>
        | t=<FIELDTERMINATOR>
        | t=<FILTER>
        | t=<FOREACH>
        | t=<FOR>
        | t=<FROM>
        | t=<FULLTEXT>
        | t=<FUNCTION>
        | t=<FUNCTIONS>
        | t=<GRANT>
        | t=<GRAPH>
        | t=<GRAPHS>
        | t=<HEADERS>
        | t=<HOME>
        | t=<IF>
        | t=<IN>
        | t=<INDEX>
        | t=<INDEXES>
        | t=<IS>
        | t=<JOIN>
        | t=<KEY>
        | t=<LABEL>
        | t=<LABELS>
        | t=<LIMITROWS>
        | t=<LOAD>
        | t=<LOOKUP>
        | t=<MATCH>
        | t=<MANAGEMENT>
        | t=<MERGE>
        | t=<NAME>
        | t=<NAMES>
        | t=<NEW>
        | t=<NODE>
        | t=<NODES>
        | t=<NONE>
        | t=<NOT>
        | t=<NOWAIT>
        | t=<NULL>
        | t=<OF>
        | t=<ON>
        | t=<ONLY>
        | t=<OPTIONAL>
        | t=<OPTIONS>
        | t=<OR>
        | t=<ORDER>
        | t=<OUTPUT>
        | t=<PASSWORD>
        | t=<PASSWORDS>
        | t=<PERIODIC>
        | t=<PLAINTEXT>
        | t=<POINT>
        | t=<POPULATED>
        | t=<PRIVILEGE>
        | t=<PRIVILEGES>
        | t=<PROCEDURE>
        | t=<PROCEDURES>
        | t=<PROPERTY>
        | t=<RANGE>
        | t=<READ>
        | t=<REDUCE>
        | t=<REL>
        | t=<RELATIONSHIP>
        | t=<RELATIONSHIPS>
        | t=<REMOVE>
        | t=<RENAME>
        | t=<REPLACE>
        | t=<REQUIRE>
        | t=<REQUIRED>
        | t=<RETURN>
        | t=<REVOKE>
        | t=<ROLE>
        | t=<ROLES>
        | t=<ROW>
        | t=<ROWS>
        | t=<SCAN>
        | t=<SEC>
        | t=<SECOND>
        | t=<SECONDS>
        | t=<SEEK>
        | t=<SET>
        | t=<SHORTEST_PATH>
        | t=<SHOW>
        | t=<SINGLE>
        | t=<SKIPROWS>
        | t=<START>
        | t=<STARTS>
        | t=<STATUS>
        | t=<STOP>
        | t=<SUSPENDED>
        | t=<TARGET>
        | t=<TERMINATE>
        | t=<TEXT>
        | t=<THEN>
        | t=<TO>
        | t=<TRANSACTION>
        | t=<TRANSACTIONS>
        | t=<TRAVERSE>
        | t=<TRUE>
        | t=<TYPE>
        | t=<TYPES>
        | t=<UNION>
        | t=<UNIQUE>
        | t=<UNWIND>
        | t=<USE>
        | t=<USER>
        | t=<USERS>
        | t=<USING>
        | t=<VERBOSE>
        | t=<WAIT>
        | t=<WHEN>
        | t=<WHERE>
        | t=<WITH>
        | t=<WRITE>
        | t=<XOR>
        | t=<YIELD>
    )
    {
        return t;
    }
}
</code></pre>    <br/>
    <br/>
    <div id="right-banner">
            </div>
    <div id="left-banner">
            </div>
<div class='clear'></div>
    <aside class="related-items">
        <section>
            <div class="panel panel-primary">
                <div class="panel-heading margin-bottom">Related Artifacts</div>
                <div class="">
                    <a title='This artifact is from the group mysql' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/mysql/mysql-connector-java' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> mysql-connector-java <small class='group-info' >mysql</small></a><br/><a title='This artifact is from the group com.github.codedrinker' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/com.github.codedrinker/facebook-messenger' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> facebook-messenger <small class='group-info' >com.github.codedrinker</small></a><br/><a title='This artifact is from the group org.seleniumhq.selenium' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.seleniumhq.selenium/selenium-java' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> selenium-java <small class='group-info' >org.seleniumhq.selenium</small></a><br/><a title='This artifact is from the group com.github.sola92' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/com.github.sola92/instagram-java' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> instagram-java <small class='group-info' >com.github.sola92</small></a><br/><a title='This artifact is from the group com.google.code.gson' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/com.google.code.gson/gson' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> gson <small class='group-info' >com.google.code.gson</small></a><br/><a title='This artifact is from the group org.apache.poi' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.apache.poi/poi' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> poi <small class='group-info' >org.apache.poi</small></a><br/><a title='This artifact is from the group org.apache.httpcomponents' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.apache.httpcomponents/httpclient' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> httpclient <small class='group-info' >org.apache.httpcomponents</small></a><br/><a title='This artifact is from the group org.json' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.json/json' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> json <small class='group-info' >org.json</small></a><br/><a title='This artifact is from the group com.google.code.facebook-java-api' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/com.google.code.facebook-java-api/facebook-java-api' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> facebook-java-api <small class='group-info' >com.google.code.facebook-java-api</small></a><br/><a title='This artifact is from the group org.apache.poi' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.apache.poi/poi-ooxml' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> poi-ooxml <small class='group-info' >org.apache.poi</small></a><br/><a title='This artifact is from the group com.fasterxml.jackson.core' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/com.fasterxml.jackson.core/jackson-databind' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> jackson-databind <small class='group-info' >com.fasterxml.jackson.core</small></a><br/><a title='This artifact is from the group junit' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/junit/junit' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> junit <small class='group-info' >junit</small></a><br/><a title='This artifact is from the group org.primefaces' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.primefaces/primefaces' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> primefaces <small class='group-info' >org.primefaces</small></a><br/><a title='This artifact is from the group com.github.noraui' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/com.github.noraui/ojdbc7' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> ojdbc7 <small class='group-info' >com.github.noraui</small></a><br/><a title='This artifact is from the group com.jfoenix' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/com.jfoenix/jfoenix' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> jfoenix <small class='group-info' >com.jfoenix</small></a><br/><a title='This artifact is from the group org.testng' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.testng/testng' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> testng <small class='group-info' >org.testng</small></a><br/><a title='This artifact is from the group com.googlecode.json-simple' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/com.googlecode.json-simple/json-simple' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> json-simple <small class='group-info' >com.googlecode.json-simple</small></a><br/><a title='This artifact is from the group org.seleniumhq.selenium' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.seleniumhq.selenium/selenium-server' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> selenium-server <small class='group-info' >org.seleniumhq.selenium</small></a><br/><a title='This artifact is from the group com.itextpdf' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/com.itextpdf/itextpdf' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> itextpdf <small class='group-info' >com.itextpdf</small></a><br/><a title='This artifact is from the group org.springframework' class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.springframework/spring-core' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> spring-core <small class='group-info' >org.springframework</small></a><br/>                </div>
            </div>
        </section>
        <section>
            <div class="panel panel-primary">
                <div class="panel-heading margin-bottom">Related Groups</div>
                <div class="">
                    <a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.springframework' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> org.springframework</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.apache.poi' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> org.apache.poi</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.hibernate' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> org.hibernate</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.springframework.boot' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> org.springframework.boot</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/com.fasterxml.jackson.core' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> com.fasterxml.jackson.core</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/com.itextpdf' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> com.itextpdf</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.seleniumhq.selenium' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> org.seleniumhq.selenium</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/mysql' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> mysql</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.finos.legend.engine' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> org.finos.legend.engine</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.apache.httpcomponents' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> org.apache.httpcomponents</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.apache.logging.log4j' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> org.apache.logging.log4j</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.openjfx' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> org.openjfx</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.apache.commons' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> org.apache.commons</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/org.json' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> org.json</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/com.google.guava' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> com.google.guava</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/com.google.zxing' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> com.google.zxing</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/net.sf.jasperreports' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> net.sf.jasperreports</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/javax.xml.bind' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> javax.xml.bind</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/ojdbc' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> ojdbc</a><br/><a class='btn btn-default btn-xs small-margin-bottom ellipsis sidebar-btn' href='/artifacts/com.google.code.facebook-java-api' ><i class="fa fa-arrow-circle-right" aria-hidden="true"></i> com.google.code.facebook-java-api</a><br/>                </div>
            </div>
        </section>
    </aside>
    <div class='clear'></div>
</main>
</div>
<br/><br/>
    <div class="align-center">&copy; 2015 - 2024 <a href="/legal-notice.php">Weber Informatics LLC</a>&nbsp;|&nbsp;<a href="/data-protection.php">Privacy Policy</a></div>
<br/><br/><br/><br/><br/><br/>
</body>
</html>