//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
//

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

import org.apache.asterix.graphix.common.metadata.IElementIdentifier;
import org.apache.asterix.graphix.lang.annotation.ElementEvaluationAnnotation;
import org.apache.asterix.graphix.lang.clause.FromGraphClause;
import org.apache.asterix.graphix.lang.clause.MatchClause;
import org.apache.asterix.graphix.lang.expression.EdgePatternExpr;
import org.apache.asterix.graphix.lang.expression.GraphConstructor;
import org.apache.asterix.graphix.lang.expression.PathPatternExpr;
import org.apache.asterix.graphix.lang.expression.VertexPatternExpr;
import org.apache.asterix.graphix.lang.optype.MatchType;
import org.apache.asterix.graphix.lang.parser.GraphixParserHint;
import org.apache.asterix.graphix.lang.statement.CreateGraphStatement;
import org.apache.asterix.graphix.lang.statement.DeclareGraphStatement;
import org.apache.asterix.graphix.lang.statement.GraphDropStatement;
import org.apache.asterix.graphix.lang.statement.GraphElementDeclaration;
import org.apache.asterix.graphix.lang.struct.EdgeDescriptor;
import org.apache.asterix.graphix.lang.struct.ElementLabel;
import org.apache.asterix.lang.sqlpp.parser.ParseException;
import org.apache.asterix.lang.sqlpp.parser.SqlppParseException;
import org.apache.asterix.lang.sqlpp.parser.Token;

@new_at_the_class_def
public GraphElementDeclaration parseGraphElementBody(IElementIdentifier identifier) throws CompilationException {
    return parseImpl(new ParseFunction<GraphElementDeclaration>() {
        @Override
        public GraphElementDeclaration parse() throws ParseException {
            DataverseName dataverse = defaultDataverse;
            defaultDataverse = identifier.getGraphIdentifier().getDataverseName();

            // We borrow the ViewBody production, where we have a SelectExpression or a VariableRef.
            createNewScope();
            Expression elementBodyExpr = GraphixParser.this.ViewBody();
            removeCurrentScope();

            defaultDataverse = dataverse;
            return new GraphElementDeclaration(identifier, elementBodyExpr);
        }
    });
}

@new_at_the_class_def
public GraphixParserHint fetchGraphixHint(Token token, GraphixParserHint[] expectedHints) {
    if (token == null) {
      return null;
    }
    Token hintToken = token.specialToken;

    // We have a hint. Pull this from our collector.
    if (hintToken == null) {
      return null;
    }
    SourceLocation sourceLoc = getSourceLocation(hintToken);
    hintCollector.remove(sourceLoc);

    // Check for Graphix hints.
    if (hintToken.hint != null) {
        // A Graphix hint is not a SQLPP hint, so we shouldn't get anything in the "hint" field.
        warnUnexpectedHint(hintToken.hint.getIdentifier(), sourceLoc, StringUtil.join(expectedHints, ", ", "\""));

    } else if (hintToken.hintParams != null) {
        for (GraphixParserHint graphixHint : expectedHints) {
            if (graphixHint.getId().equals(hintToken.hintParams)) {
                return graphixHint;
            }
        }
    }
    return null;
}

@override
SelectBlock SelectBlock() throws ParseException:
{
  SelectClause selectClause = null;
  FromClause fromClause = null;
  FromGraphClause fromGraphClause = null;
  List<LetClause> fromLetClauses = null;
  WhereClause whereClause = null;
  GroupbyClause groupbyClause = null;
  List<LetClause> gbyLetClauses = null;
  HavingClause havingClause = null;
  SourceLocation startSrcLoc = null;

  List<AbstractClause> fromLetWhereClauses = new ArrayList<AbstractClause>();
  List<AbstractClause> gbyLetHavingClauses = new ArrayList<AbstractClause>();
}
{
  (
    (
      selectClause = SelectClause() { startSrcLoc = selectClause.getSourceLocation(); }
      (
        (
          ( LOOKAHEAD(2)
            fromGraphClause = FromGraphClause()
            | fromClause = FromClause()
          )
          ( fromLetClauses = LetClause() )?
          ( whereClause = WhereClause() )?
          ( groupbyClause = GroupbyClause()
            ( gbyLetClauses = LetClause() )?
            ( havingClause = HavingClause() )? )?
        )
        |
        ( fromLetClauses = LetClause()
          {
            // LET without FROM -> create dummy FROM clause: FROM {{missing}} AS #0
            SourceLocation sourceLoc = getSourceLocation(token);
            LiteralExpr missingExpr = new LiteralExpr(MissingLiteral.INSTANCE);
            missingExpr.setSourceLocation(sourceLoc);
            List<Expression> list = new ArrayList<Expression>(1);
            list.add(missingExpr);
            ListConstructor listExpr = new ListConstructor(ListConstructor.Type.ORDERED_LIST_CONSTRUCTOR, list);
            listExpr.setSourceLocation(sourceLoc);
            List<FromTerm> fromTerms = new ArrayList<FromTerm>(1);
            VariableExpr fromVar = new VariableExpr(new VarIdentifier("#0"));
            fromVar.setSourceLocation(sourceLoc);
            fromTerms.add(new FromTerm(listExpr, fromVar, null, new ArrayList<AbstractBinaryCorrelateClause>()));
            fromClause = new FromClause(fromTerms);
          }
          ( whereClause = WhereClause() )?
        )
      )?
    )
    |
    (
      ( LOOKAHEAD(2)
        fromGraphClause = FromGraphClause() { startSrcLoc = fromGraphClause.getSourceLocation(); }
        | fromClause = FromClause() { startSrcLoc = fromClause.getSourceLocation(); }
     )
     ( fromLetClauses = LetClause() )?
     ( whereClause = WhereClause() )?
     ( groupbyClause = GroupbyClause()
       ( gbyLetClauses = LetClause() )?
       ( havingClause = HavingClause() )? )?
     selectClause = SelectClause()
    )
  )
  {
    if (fromLetClauses != null) {
      fromLetWhereClauses.addAll(fromLetClauses);
    }
    if (whereClause != null) {
      fromLetWhereClauses.add(whereClause);
    }
    if (gbyLetClauses != null) {
      gbyLetHavingClauses.addAll(gbyLetClauses);
    }
    if (havingClause != null) {
      gbyLetHavingClauses.add(havingClause);
    }

    if (fromClause != null) {
      SelectBlock selectBlock = new SelectBlock(selectClause, fromClause, fromLetWhereClauses,
        groupbyClause, gbyLetHavingClauses);
      selectBlock.setSourceLocation(startSrcLoc);
      return selectBlock;

    } else {
      SelectBlock selectBlock = new SelectBlock(selectClause, fromGraphClause, fromLetWhereClauses,
        groupbyClause, gbyLetHavingClauses);
      selectBlock.setSourceLocation(startSrcLoc);
      return selectBlock;
    }
  }
}

@override
Statement SingleStatement() throws ParseException:
{
  Statement stmt = null;
}
{
  (
    stmt = DataverseDeclaration()
    | stmt = DeclareStatement()
    | stmt = CreateStatement()
    | stmt = LoadStatement()
    | stmt = DropStatement()
    | stmt = WriteStatement()
    | stmt = SetStatement()
    | stmt = InsertStatement()
    | stmt = DeleteStatement()
    | stmt = UpdateStatement()
    | stmt = UpsertStatement()
    | stmt = ConnectionStatement()
    | stmt = CompactStatement()
    | stmt = Query()
    | stmt = RefreshExternalDatasetStatement()
  )
  {
    return stmt;
  }
}

@new
Statement DeclareStatement() throws ParseException:
{
  Token startToken = null;
  Statement stmt = null;
}
{
  <DECLARE> { startToken = token; }
  (
    stmt = FunctionDecl(startToken)
    | stmt = GraphDecl(startToken)
  )
  {
    return stmt;
  }
}

// Note: this is the same as FunctionDeclaration in the main grammar with the <DECLARE> token removed.
@new
FunctionDecl FunctionDecl(Token startToken) throws ParseException:
{
  String functionName;
  Pair<Integer, List<Pair<VarIdentifier,TypeExpression>>> paramsWithArity = null;
  Expression funcBody;
  createNewScope();
}
{
  <FUNCTION>
  functionName = Identifier()
  paramsWithArity = FunctionParameters()
  <LEFTBRACE>
  funcBody = FunctionBody()
  <RIGHTBRACE>
  {
    int arity = paramsWithArity.first;
    List<Pair<VarIdentifier,TypeExpression>> paramList = paramsWithArity.second;
    FunctionSignature signature = new FunctionSignature(defaultDataverse, functionName, arity);
    getCurrentScope().addFunctionDescriptor(signature, false);
    ensureNoTypeDeclsInFunction(functionName, paramList, null, startToken);
    List<VarIdentifier> params = new ArrayList<VarIdentifier>(paramList.size());
    for (Pair<VarIdentifier,TypeExpression> p: paramList) {
        params.add(p.getFirst());
    }
    FunctionDecl stmt = new FunctionDecl(signature, params, funcBody, false);
    removeCurrentScope();
    return addSourceLocation(stmt, startToken);
  }
}

@merge
Statement CreateStatement() throws ParseException:
{
}
{
  (
    before:
    after:    | stmt = CreateGraphStatement(startToken, false)
  )
  {
  }
}

@merge
Statement CreateOrReplaceStatement(Token startStmtToken) throws ParseException:
{
}
{
  (
    before:
    after:    | stmt = CreateGraphStatement(startStmtToken, true)
  )
  {
  }
}

@merge
Statement DropStatement() throws ParseException:
{
}
{
  (
    before:
    after:    | stmt = DropGraphStatement(startToken)
  )
  {
  }
}

@new
DeclareGraphStatement GraphDecl(Token startStmtToken) throws ParseException:
{
  GraphConstructor graphConstructor = null;
  String graphName = null;
}
{
  <GRAPH>
  graphName = Identifier()
  <AS> graphConstructor = GraphConstructor(token)
  {
    DeclareGraphStatement stmt = new DeclareGraphStatement(graphName, graphConstructor);
    return addSourceLocation(stmt, startStmtToken);
  }
}

@new
CreateGraphStatement CreateGraphStatement(Token startStmtToken, boolean orReplace) throws ParseException:
{
  CreateGraphStatement stmt = null;
}
{
  <GRAPH> stmt = CreateGraphSpecification(startStmtToken, orReplace)
  {
    return stmt;
  }
}

@new
CreateGraphStatement CreateGraphSpecification(Token startStmtToken, boolean orReplace) throws ParseException:
{
  Pair<DataverseName, Identifier> nameComponents = null;
  GraphConstructor graphConstructor = null;
  boolean ifNotExists = false;
}
{
  nameComponents = QualifiedName()
  ifNotExists = IfNotExists()
  {
    if (orReplace && ifNotExists) {
      throw new SqlppParseException(getSourceLocation(startStmtToken), "Unexpected IF NOT EXISTS");
    }
  }
  <AS> graphConstructor = GraphConstructor(token)
  {
    CreateGraphStatement stmt = new CreateGraphStatement(nameComponents.first, nameComponents.second.getValue(),
        orReplace, ifNotExists, graphConstructor);
    return addSourceLocation(stmt, startStmtToken);
  }
}

@new
GraphDropStatement DropGraphStatement(Token startStmtToken) throws ParseException:
{
   GraphDropStatement stmt = null;
}
{
  <GRAPH> stmt = DropGraphSpecification(startStmtToken)
  {
    return stmt;
  }
}

@new
GraphDropStatement DropGraphSpecification(Token startStmtToken) throws ParseException:
{
  Pair<DataverseName, Identifier> pairId = null;
  boolean ifExists = false;
}
{
  pairId = QualifiedName() ifExists = IfExists()
  {
    GraphDropStatement stmt = new GraphDropStatement(pairId.first, pairId.second.getValue(), ifExists);
    return addSourceLocation(stmt, startStmtToken);
  }
}

@new
Pair<List<Integer>, List<List<String>>> KeyFields() throws ParseException:
{
  Pair<List<Integer>, List<List<String>>> keyFields = null;
}
{
  // This is essentially an alias for the production PrimaryKeyFields.
  keyFields = PrimaryKeyFields()
  {
    return keyFields;
  }
}

@new
GraphConstructor GraphConstructor(Token startStmtToken) throws ParseException:
{
  List<GraphConstructor.VertexConstructor> vertexConstructors = new ArrayList<GraphConstructor.VertexConstructor>();
  List<GraphConstructor.EdgeConstructor> edgeConstructors = new ArrayList<GraphConstructor.EdgeConstructor>();
  GraphConstructor.VertexConstructor vertexConstructor = null;
  GraphConstructor.EdgeConstructor edgeConstructor = null;
}
{
  vertexConstructor = GraphVertexSpecification(startStmtToken) { vertexConstructors.add(vertexConstructor); }
  ( <COMMA>
    (
      ( vertexConstructor = GraphVertexSpecification(token) { vertexConstructors.add(vertexConstructor); } )
      | ( edgeConstructor = GraphEdgeSpecification(token) { edgeConstructors.add(edgeConstructor); } )
    )
  )*
  {
    GraphConstructor graphConstructor = new GraphConstructor(vertexConstructors, edgeConstructors);
    return addSourceLocation(graphConstructor, startStmtToken);
  }
}

@new
GraphConstructor.VertexConstructor GraphVertexSpecification(Token startStmtToken) throws ParseException:
{
  Pair<List<Integer>, List<List<String>>> primaryKeyFields;
  Token beginPos = null, endPos = null;
  int positionOffset = 0;
  Expression vertexDefinitionExpr;
  ElementLabel elementLabel;
}
{
  <VERTEX>
  elementLabel = GraphVertexDefinitionPattern()
  <PRIMARY> <KEY> <LEFTPAREN> primaryKeyFields = KeyFields() <RIGHTPAREN>
  <AS>
  {
    beginPos = token;
    createNewScope();
  }
  (
    vertexDefinitionExpr = ViewBody() { endPos = token; positionOffset++; }
    | <LEFTPAREN> { beginPos = token; } vertexDefinitionExpr = ViewBody() { endPos = token; } <RIGHTPAREN>
  )
  {
    String vDef = extractFragment(beginPos.beginLine, beginPos.beginColumn + positionOffset, endPos.endLine,
      endPos.endColumn + 1);
    removeCurrentScope();
    GraphConstructor.VertexConstructor vertexConstructor = new GraphConstructor.VertexConstructor(elementLabel,
      primaryKeyFields.second, primaryKeyFields.first, vertexDefinitionExpr, vDef);
    return addSourceLocation(vertexConstructor, startStmtToken);
  }
}

@new
ElementLabel GraphVertexDefinitionPattern() throws ParseException:
{
  String vertexName;
}
{
  <LEFTPAREN> <COLON> vertexName = Identifier() <RIGHTPAREN>
  {
    return new ElementLabel(vertexName, false);
  }
}

@new
GraphConstructor.EdgeConstructor GraphEdgeSpecification(Token startStmtToken) throws ParseException:
{
  Pair<Triple<ElementLabel, ElementLabel, ElementLabel>, Boolean> edgeDefinitionPattern;
  Pair<List<Integer>, List<List<String>>> keyFields;
  Token beginPos = null, endPos = null;
  Expression edgeDefinitionExpr = null;
  int positionOffset = 0;

  List<Integer> destinationKeySourceIndicators = null;
  List<Integer> sourceKeySourceIndicators = null;
  List<List<String>> destinationKeyFields = null;
  List<List<String>> sourceKeyFields = null;
}
{
  <EDGE>
  edgeDefinitionPattern = GraphEdgeDefinitionPattern()
  (
    <SOURCE> <KEY> <LEFTPAREN> keyFields = KeyFields() <RIGHTPAREN>
    {
      sourceKeyFields = keyFields.second;
      sourceKeySourceIndicators = keyFields.first;
    }
    <DESTINATION> <KEY> <LEFTPAREN> keyFields = KeyFields() <RIGHTPAREN>
    {
      destinationKeyFields = keyFields.second;
      destinationKeySourceIndicators = keyFields.first;
    }
    <AS>
    {
      beginPos = token;
      createNewScope();
    }
    (
      edgeDefinitionExpr = SelectExpression(true) { endPos = token; positionOffset++;  }
      | <LEFTPAREN> { beginPos = token; } edgeDefinitionExpr = SelectExpression(true) { endPos = token; } <RIGHTPAREN>
    )
  )
  {
    ElementLabel destinationLabel, edgeLabel, sourceLabel;
    if (edgeDefinitionPattern.second) { // isDirectedLeft
      sourceLabel = edgeDefinitionPattern.first.third;
      edgeLabel = edgeDefinitionPattern.first.second;
      destinationLabel = edgeDefinitionPattern.first.first;

    } else {
      sourceLabel = edgeDefinitionPattern.first.first;
      edgeLabel = edgeDefinitionPattern.first.second;
      destinationLabel = edgeDefinitionPattern.first.third;
    }

    String eDef = null;
    if (edgeDefinitionExpr != null) {
      eDef = extractFragment(beginPos.beginLine, beginPos.beginColumn + positionOffset, endPos.endLine,
        endPos.endColumn + 1);
      removeCurrentScope();
    }

    GraphConstructor.EdgeConstructor edgeConstructor = new GraphConstructor.EdgeConstructor(edgeLabel, destinationLabel,
        sourceLabel, destinationKeyFields, destinationKeySourceIndicators, sourceKeyFields, sourceKeySourceIndicators,
        edgeDefinitionExpr, eDef);
    return addSourceLocation(edgeConstructor, startStmtToken);
  }
}

@new
Pair<Triple<ElementLabel, ElementLabel, ElementLabel>, Boolean> GraphEdgeDefinitionPattern() throws ParseException:
{
  ElementLabel leftElementLabel, rightElementLabel;
  boolean isDirectedLeft;
  String edgeName;
}
{
  leftElementLabel = GraphVertexDefinitionPattern()
  ( <MINUS> <LEFTBRACKET> <COLON> edgeName = Identifier() <RIGHTBRACKET> <MINUS> <GT> { isDirectedLeft = false; }
  | <LT> <MINUS> <LEFTBRACKET> <COLON> edgeName = Identifier() <RIGHTBRACKET> <MINUS> { isDirectedLeft = true; } )
  rightElementLabel = GraphVertexDefinitionPattern()
  {
    Triple<ElementLabel, ElementLabel, ElementLabel> t = new Triple<ElementLabel, ElementLabel, ElementLabel>(
      leftElementLabel, new ElementLabel(edgeName, false), rightElementLabel);
    return new Pair<Triple<ElementLabel, ElementLabel, ElementLabel>, Boolean>(t, isDirectedLeft);
  }
}

@new
FromGraphClause FromGraphClause() throws ParseException:
{
  Token startToken = null;
  GraphConstructor graphConstructor = null;
  Pair<DataverseName, Identifier> nameComponents = null;
  AbstractBinaryCorrelateClause correlateClause = null;

  List<MatchClause> matchClauses = new ArrayList<MatchClause>();
  List<PathPatternExpr> pathPatternExpressions = null;
  List<AbstractBinaryCorrelateClause> correlateClauses = new ArrayList<AbstractBinaryCorrelateClause>();
}
{
  <FROM> <GRAPH> { startToken = token; }
  (
    graphConstructor = GraphConstructor(token)
    | nameComponents = QualifiedName()
  )
  <MATCH> pathPatternExpressions = PathPatternExpressions()
  { matchClauses.add(new MatchClause(pathPatternExpressions, MatchType.LEADING)); }
  ( LOOKAHEAD(3) // We want to avoid getting confused with the correlated clauses below.
    (
      <LEFT> ( <OUTER> )? <MATCH> pathPatternExpressions = PathPatternExpressions()
      { matchClauses.add(new MatchClause(pathPatternExpressions, MatchType.LEFTOUTER)); }
      |
      ( <INNER> )? <MATCH> pathPatternExpressions = PathPatternExpressions()
      { matchClauses.add(new MatchClause(pathPatternExpressions, MatchType.INNER)); }
    )
  )*
  (
    (
      correlateClause = JoinOrUnnestClause(JoinType.INNER, UnnestType.INNER)
      | ( <INNER> correlateClause = JoinOrUnnestClause(JoinType.INNER, UnnestType.INNER) )
      | ( <LEFT> ( <OUTER> )? correlateClause = JoinOrUnnestClause(JoinType.LEFTOUTER, UnnestType.LEFTOUTER) )
      | ( <RIGHT> ( <OUTER> )? correlateClause = JoinClause(JoinType.RIGHTOUTER) )
      | ( <CROSS> correlateClause = CrossJoinClause() )
    )
    {
      correlateClauses.add(correlateClause);
    }
  )*
  {
    FromGraphClause fromGraphClause;
    if (graphConstructor == null) {
      fromGraphClause = new FromGraphClause(nameComponents.first, nameComponents.second,
        matchClauses, correlateClauses);

    } else {
      fromGraphClause = new FromGraphClause(graphConstructor, matchClauses, correlateClauses);
    }
    return addSourceLocation(fromGraphClause, startToken);
  }
}

@new
List<PathPatternExpr> PathPatternExpressions() throws ParseException:
{
  List<PathPatternExpr> pathPatternExpressions = new ArrayList<PathPatternExpr>();
  PathPatternExpr pathPattern = null;
  VariableExpr variableExpr = null;
}
{
  pathPattern = PathPatternExpression() { pathPatternExpressions.add(pathPattern); }
  (
    ( <AS> )? variableExpr = Variable()
    {
      int index = pathPatternExpressions.size() - 1;
      pathPatternExpressions.get(index).setVariableExpr(variableExpr);
    }
  )?
  ( LOOKAHEAD(2)
    <COMMA> pathPattern = PathPatternExpression() { pathPatternExpressions.add(pathPattern); }
    (
      ( <AS> )? variableExpr = Variable()
      {
        int index = pathPatternExpressions.size() - 1;
        pathPatternExpressions.get(index).setVariableExpr(variableExpr);
      }
    )?
  )*
  {
    return pathPatternExpressions;
  }
}

@new
PathPatternExpr PathPatternExpression() throws ParseException:
{
  List<VertexPatternExpr> orderedVertexExpressions = new ArrayList<VertexPatternExpr>();
  List<EdgePatternExpr> orderedEdgeExpressions = new ArrayList<EdgePatternExpr>();

  Token startToken = null, edgeStartToken = null;
  VertexPatternExpr vertexExpr = null;
  Pair<EdgeDescriptor, List<IExpressionAnnotation>> edgeDescriptorPair = null;
}
{
  vertexExpr = VertexPatternExpression()
  {
    startToken = token;
    orderedVertexExpressions.add(vertexExpr);
  }
  (
    edgeDescriptorPair = EdgeDescriptorPair() { edgeStartToken = token; }
    vertexExpr = VertexPatternExpression()
    {
      VertexPatternExpr leftVertex = orderedVertexExpressions.get(orderedVertexExpressions.size() - 1);
      EdgePatternExpr edgePattern = new EdgePatternExpr(leftVertex, vertexExpr, edgeDescriptorPair.first);
      if (!edgeDescriptorPair.second.isEmpty()) {
        for (IExpressionAnnotation annotation : edgeDescriptorPair.second) {
          edgePattern.addHint(annotation);
        }
      }
      orderedEdgeExpressions.add(addSourceLocation(edgePattern, edgeStartToken));
      orderedVertexExpressions.add(vertexExpr);
    }
  )*
  {
    PathPatternExpr pathPattern = new PathPatternExpr(orderedVertexExpressions, orderedEdgeExpressions, null);
    return addSourceLocation(pathPattern, startToken);
  }
}

@new
VertexPatternExpr VertexPatternExpression() throws ParseException:
{
  Set<String> vertexLabels = new HashSet<String>();
  VariableExpr variableExpr = null;
  Expression filterExpr = null;
  boolean isNegatedLabelSet = false;
  Token startToken = null;
  String vertexLabelName;
}
{
  <LEFTPAREN> { startToken = token; }
  ( variableExpr = Variable() )?
  (
    <COLON>
    ( <CARET> { isNegatedLabelSet = true; } )?
    vertexLabels = ParenthesizedLabelValueSet()
  )?
  ( <WHERE> filterExpr = Expression() )?
  <RIGHTPAREN>
  {
    // Construct our label set.
    Set<ElementLabel> labels = new HashSet<ElementLabel>();
    for (String vertexLabelValue : vertexLabels) {
      labels.add(new ElementLabel(vertexLabelValue, isNegatedLabelSet));
    }
    VertexPatternExpr vertexExpression = new VertexPatternExpr(variableExpr, filterExpr, labels);
    return addSourceLocation(vertexExpression, startToken);
  }
}

@new
Pair<EdgeDescriptor, List<IExpressionAnnotation>> EdgeDescriptorPair() throws ParseException:
{
  GraphixParserHint[] expectedHints = { GraphixParserHint.EXPAND_AND_UNION_HINT,
                                        GraphixParserHint.SWITCH_AND_CYCLE_HINT };
  List<IExpressionAnnotation> hintList = new ArrayList<IExpressionAnnotation>();
  Triple<Set<ElementLabel>, Pair<Integer, Integer>, Expression> edgeDetail = null;
  Token startToken = null, hintToken = null;
  VariableExpr edgeVariable = null;
  Expression filterExpr = null;

  // We default to undirected edges.
  EdgeDescriptor.EdgeDirection edgeDirection = EdgeDescriptor.EdgeDirection.UNDIRECTED;
}
{
  (
    <MINUS> { startToken = token; }
    (
      <LEFTBRACKET>
      ( edgeVariable = Variable() )?
      ( edgeDetail = EdgeDetail() )?
      <RIGHTBRACKET> { hintToken = token; } <MINUS>
    )?
    ( <GT> { edgeDirection = EdgeDescriptor.EdgeDirection.LEFT_TO_RIGHT; } )?
    |
    <LT> {
      startToken = token;
      edgeDirection = EdgeDescriptor.EdgeDirection.RIGHT_TO_LEFT;
    }
    <MINUS>
    (
      <LEFTBRACKET>
      ( edgeVariable = Variable() )?
      ( edgeDetail = EdgeDetail() )?
      <RIGHTBRACKET> { hintToken = token; } <MINUS>
    )?
  )
  {
    // See if we have an evaluation hint.
    GraphixParserHint evalHint = fetchGraphixHint(hintToken, expectedHints);
    if (Objects.equals(evalHint, GraphixParserHint.EXPAND_AND_UNION_HINT)) {
      hintList.add(new ElementEvaluationAnnotation(ElementEvaluationAnnotation.Kind.EXPAND_AND_UNION));

    } else if (Objects.equals(evalHint, GraphixParserHint.SWITCH_AND_CYCLE_HINT)) {
      hintList.add(new ElementEvaluationAnnotation(ElementEvaluationAnnotation.Kind.SWITCH_AND_CYCLE));
    }

    // Edges (by default) are of pattern type EDGE and are not sub-paths.
    EdgeDescriptor.PatternType patternType = EdgeDescriptor.PatternType.EDGE;
    Integer hopCountMin = 1;
    Integer hopCountMax = 1;

    Set<ElementLabel> labels = new HashSet<ElementLabel>();
    if (edgeDetail != null) {
      labels = edgeDetail.first;
      filterExpr = edgeDetail.third;

      // We have explicitly specified "{" and "}". Use sub-path semantics.
      if (edgeDetail.second != null) {
        patternType = EdgeDescriptor.PatternType.PATH;
        hopCountMin = edgeDetail.second.first;
        hopCountMax = edgeDetail.second.second;
      }
    }
    EdgeDescriptor edgeDescriptor =
      new EdgeDescriptor(edgeDirection, patternType, labels, filterExpr, edgeVariable, hopCountMin, hopCountMax);
    return new Pair<EdgeDescriptor, List<IExpressionAnnotation>>(edgeDescriptor, hintList);
  }
}

@new
Triple<Set<ElementLabel>, Pair<Integer, Integer>, Expression> EdgeDetail() throws ParseException:
{
  Set<String> edgeLabels = new HashSet<String>();
  Pair<Integer, Integer> repetitionQuantifier = null;
  Expression filterExpr = null;
  boolean isNegatedLabelSet = false;
  String labelName = null;
}
{
  (
    ( repetitionQuantifier = EdgeRepetitionQuantifier() )
    |
    (
      <COLON>
      ( <CARET> { isNegatedLabelSet = true; } )?
      edgeLabels = ParenthesizedLabelValueSet()
      ( LOOKAHEAD(2)
        ( <WHERE> filterExpr = Expression() )
        |
        ( repetitionQuantifier = EdgeRepetitionQuantifier() )
      )?
    )
    |
    ( <WHERE> filterExpr = Expression() )
  )
  {
    // Construct our label set.
    Set<ElementLabel> labels = new HashSet<ElementLabel>();
    for (String edgeLabelValue : edgeLabels) {
      labels.add(new ElementLabel(edgeLabelValue, isNegatedLabelSet));
    }
    return new Triple<Set<ElementLabel>, Pair<Integer, Integer>, Expression> (labels, repetitionQuantifier, filterExpr);
  }
}

@new
Set<String> ParenthesizedLabelValueSet() throws ParseException:
{
  Set<String> labelSet = new HashSet<String>();
  Set<String> innerLabelSet = null;
  String labelName = null;
}
{
  (
    ( labelName = Identifier() { labelSet.add(labelName); } )
    |
    (
      <LEFTPAREN>
      innerLabelSet = ParenthesizedLabelValueSet() { labelSet.addAll(innerLabelSet); }
      (
        <BAR>
        innerLabelSet = ParenthesizedLabelValueSet() { labelSet.addAll(innerLabelSet); }
      )*
      <RIGHTPAREN>
    )
  )
  {
    return labelSet;
  }
}

@new
Pair<Integer, Integer> EdgeRepetitionQuantifier() throws ParseException:
{
  Integer hopCountMin = null;
  Integer hopCountMax = null;
}
{
  (
    <PLUS>
    |
    (
      <LEFTBRACE>
      ( <INTEGER_LITERAL> { hopCountMin = Integer.valueOf(token.image); } )?
      <COMMA>
      ( <INTEGER_LITERAL> { hopCountMax = Integer.valueOf(token.image); } )?
      <RIGHTBRACE>
    )
  )
  {
    return new Pair<Integer, Integer>(hopCountMin, hopCountMax);
  }
}

@new
<DEFAULT,IN_DBL_BRACE>
TOKEN [IGNORE_CASE]:
{
  <DESTINATION: "destination">
  | <EDGE: "edge">
  | <GRAPH: "graph">
  | <SOURCE: "source">
  | <VERTEX: "vertex">
  | <MATCH: "match">
}

@new_at_the_end
<DEFAULT,IN_DBL_BRACE>
TOKEN :
{
  <BAR: "|">
}