blob: 5338219285abaf40116830ed7a425e0dad7396e7 [file] [log] [blame]
//
// 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.Set;
import org.apache.asterix.graphix.common.metadata.GraphElementIdentifier;
import org.apache.asterix.graphix.lang.clause.FromGraphClause;
import org.apache.asterix.graphix.lang.clause.GraphSelectBlock;
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.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(GraphElementIdentifier 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);
}
});
}
@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 {
GraphSelectBlock selectBlock = new GraphSelectBlock(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;
Expression vertexDefinitionExpr;
ElementLabel vertexLabel;
}
{
<VERTEX>
vertexLabel = GraphVertexDefinitionPattern()
<PRIMARY> <KEY> <LEFTPAREN> primaryKeyFields = KeyFields() <RIGHTPAREN>
<AS>
{
beginPos = token;
createNewScope();
}
(
vertexDefinitionExpr = ViewBody() { endPos = token; }
| <LEFTPAREN> { beginPos = token; } vertexDefinitionExpr = ViewBody() { endPos = token; } <RIGHTPAREN>
)
{
String vDef = extractFragment(beginPos.beginLine, beginPos.beginColumn + 1, endPos.endLine, endPos.endColumn + 1);
removeCurrentScope();
GraphConstructor.VertexConstructor vertexConstructor = new GraphConstructor.VertexConstructor(vertexLabel,
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);
}
}
@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;
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; }
| <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 + 1, 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 leftVertexLabel, rightVertexLabel;
boolean isDirectedLeft;
String edgeName;
}
{
leftVertexLabel = GraphVertexDefinitionPattern()
( <MINUS> <LEFTBRACKET> <COLON> edgeName = Identifier() <RIGHTBRACKET> <MINUS> <GT> { isDirectedLeft = false; }
| <LT> <MINUS> <LEFTBRACKET> <COLON> edgeName = Identifier() <RIGHTBRACKET> <MINUS> { isDirectedLeft = true; } )
rightVertexLabel = GraphVertexDefinitionPattern()
{
Triple<ElementLabel, ElementLabel, ElementLabel> t = new Triple<ElementLabel, ElementLabel, ElementLabel>(
leftVertexLabel, new ElementLabel(edgeName), rightVertexLabel);
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;
EdgeDescriptor edgeDescriptor = null;
}
{
vertexExpr = VertexPatternExpression()
{
startToken = token;
orderedVertexExpressions.add(vertexExpr);
}
(
edgeDescriptor = EdgeDescriptor() { edgeStartToken = token; }
vertexExpr = VertexPatternExpression()
{
VertexPatternExpr leftVertex = orderedVertexExpressions.get(orderedVertexExpressions.size() - 1);
EdgePatternExpr edgePattern = new EdgePatternExpr(leftVertex, vertexExpr, edgeDescriptor);
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<ElementLabel> vertexLabels = new HashSet<ElementLabel>();
VariableExpr variableExpr = null;
Token startToken = null;
String vertexLabelName;
}
{
<LEFTPAREN> { startToken = token; }
(
variableExpr = Variable()
)?
(
<COLON> vertexLabelName = Identifier() { vertexLabels.add(new ElementLabel(vertexLabelName)); }
( <BAR> vertexLabelName = Identifier() { vertexLabels.add(new ElementLabel(vertexLabelName)); } )*
)?
<RIGHTPAREN>
{
VertexPatternExpr vertexExpression = new VertexPatternExpr(variableExpr, vertexLabels);
return addSourceLocation(vertexExpression, startToken);
}
}
@new
EdgeDescriptor EdgeDescriptor() throws ParseException:
{
Pair<Set<ElementLabel>, Pair<Integer, Integer>> edgeDetail = null;
Token startToken = null;
VariableExpr edgeVariable = null;
// We default to undirected edges.
EdgeDescriptor.EdgeDirection edgeDirection = EdgeDescriptor.EdgeDirection.UNDIRECTED;
}
{
(
<MINUS> { startToken = token; }
(
<LEFTBRACKET>
(
edgeVariable = Variable()
)?
( <COLON> edgeDetail = EdgeDetail() )?
<RIGHTBRACKET> <MINUS>
)?
( <GT> { edgeDirection = EdgeDescriptor.EdgeDirection.LEFT_TO_RIGHT; } )?
|
<LT> {
startToken = token;
edgeDirection = EdgeDescriptor.EdgeDirection.RIGHT_TO_LEFT;
}
<MINUS>
(
<LEFTBRACKET>
(
edgeVariable = Variable()
)?
( <COLON> edgeDetail = EdgeDetail() )?
<RIGHTBRACKET> <MINUS>
)?
)
{
// 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;
// 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;
}
}
return new EdgeDescriptor(edgeDirection, patternType, labels, edgeVariable, hopCountMin, hopCountMax);
}
}
@new
Pair<Set<ElementLabel>, Pair<Integer, Integer>> EdgeDetail() throws ParseException:
{
Set<ElementLabel> edgeLabels = new HashSet<ElementLabel>();
Pair<Integer, Integer> repetitionQuantifier = null;
String labelName = null;
}
{
(
// Note: we want to forbid LABEL_1|LABEL_2{...}.
LOOKAHEAD(2, <BAR>)
(
labelName = Identifier() { edgeLabels.add(new ElementLabel(labelName)); }
<BAR> labelName = Identifier() { edgeLabels.add(new ElementLabel(labelName)); }
( <BAR> labelName = Identifier() { edgeLabels.add(new ElementLabel(labelName)); } )*
)
|
(
labelName = Identifier() { edgeLabels.add(new ElementLabel(labelName)); }
|
<LEFTPAREN>
labelName = Identifier() { edgeLabels.add(new ElementLabel(labelName)); }
( <BAR> labelName = Identifier() { edgeLabels.add(new ElementLabel(labelName)); } )*
<RIGHTPAREN>
)
( repetitionQuantifier = EdgeRepetitionQuantifier() )?
|
( repetitionQuantifier = EdgeRepetitionQuantifier() )
)
{
return new Pair<Set<ElementLabel>, Pair<Integer, Integer>> (edgeLabels, repetitionQuantifier);
}
}
@new
Pair<Integer, Integer> EdgeRepetitionQuantifier() throws ParseException:
{
Integer hopCountMin = null;
Integer hopCountMax = null;
}
{
<LEFTBRACE>
( // Note: we forbid unbounded edge repetition.
( <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: "|">
}