blob: ca7aa6651d55c8968d14a54c4901767b2b9fe434 [file] [log] [blame]
ggalvizoab83c3b2021-12-22 14:15:50 -08001//
2// Licensed to the Apache Software Foundation (ASF) under one
3// or more contributor license agreements. See the NOTICE file
4// distributed with this work for additional information
5// regarding copyright ownership. The ASF licenses this file
6// to you under the Apache License, Version 2.0 (the
7// "License"); you may not use this file except in compliance
8// with the License. You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing,
13// software distributed under the License is distributed on an
14// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15// KIND, either express or implied. See the License for the
16// specific language governing permissions and limitations
17// under the License.
18//
19
ggalvizo08eab6f2022-04-15 15:22:00 -070020import java.util.HashSet;
ggalvizoacd4b5b2022-09-25 14:29:42 -070021import java.util.Objects;
ggalvizo08eab6f2022-04-15 15:22:00 -070022import java.util.Set;
23
ggalvizoacd4b5b2022-09-25 14:29:42 -070024import org.apache.asterix.graphix.common.metadata.IElementIdentifier;
25import org.apache.asterix.graphix.lang.annotation.ElementEvaluationAnnotation;
ggalvizo08eab6f2022-04-15 15:22:00 -070026import org.apache.asterix.graphix.lang.clause.FromGraphClause;
ggalvizo08eab6f2022-04-15 15:22:00 -070027import org.apache.asterix.graphix.lang.clause.MatchClause;
28import org.apache.asterix.graphix.lang.expression.EdgePatternExpr;
ggalvizoab83c3b2021-12-22 14:15:50 -080029import org.apache.asterix.graphix.lang.expression.GraphConstructor;
ggalvizo08eab6f2022-04-15 15:22:00 -070030import org.apache.asterix.graphix.lang.expression.PathPatternExpr;
31import org.apache.asterix.graphix.lang.expression.VertexPatternExpr;
32import org.apache.asterix.graphix.lang.optype.MatchType;
ggalvizoacd4b5b2022-09-25 14:29:42 -070033import org.apache.asterix.graphix.lang.parser.GraphixParserHint;
ggalvizoab83c3b2021-12-22 14:15:50 -080034import org.apache.asterix.graphix.lang.statement.CreateGraphStatement;
ggalvizo02256452022-06-14 19:18:50 -070035import org.apache.asterix.graphix.lang.statement.DeclareGraphStatement;
ggalvizoab83c3b2021-12-22 14:15:50 -080036import org.apache.asterix.graphix.lang.statement.GraphDropStatement;
ggalvizo02256452022-06-14 19:18:50 -070037import org.apache.asterix.graphix.lang.statement.GraphElementDeclaration;
ggalvizo08eab6f2022-04-15 15:22:00 -070038import org.apache.asterix.graphix.lang.struct.EdgeDescriptor;
39import org.apache.asterix.graphix.lang.struct.ElementLabel;
ggalvizoab83c3b2021-12-22 14:15:50 -080040import org.apache.asterix.lang.sqlpp.parser.ParseException;
41import org.apache.asterix.lang.sqlpp.parser.SqlppParseException;
42import org.apache.asterix.lang.sqlpp.parser.Token;
43
44@new_at_the_class_def
ggalvizoacd4b5b2022-09-25 14:29:42 -070045public GraphElementDeclaration parseGraphElementBody(IElementIdentifier identifier) throws CompilationException {
ggalvizo02256452022-06-14 19:18:50 -070046 return parseImpl(new ParseFunction<GraphElementDeclaration>() {
ggalvizoab83c3b2021-12-22 14:15:50 -080047 @Override
ggalvizo02256452022-06-14 19:18:50 -070048 public GraphElementDeclaration parse() throws ParseException {
ggalvizoab83c3b2021-12-22 14:15:50 -080049 DataverseName dataverse = defaultDataverse;
50 defaultDataverse = identifier.getGraphIdentifier().getDataverseName();
51
52 // We borrow the ViewBody production, where we have a SelectExpression or a VariableRef.
53 createNewScope();
54 Expression elementBodyExpr = GraphixParser.this.ViewBody();
55 removeCurrentScope();
56
57 defaultDataverse = dataverse;
ggalvizo02256452022-06-14 19:18:50 -070058 return new GraphElementDeclaration(identifier, elementBodyExpr);
ggalvizoab83c3b2021-12-22 14:15:50 -080059 }
60 });
61}
62
ggalvizoacd4b5b2022-09-25 14:29:42 -070063@new_at_the_class_def
64public GraphixParserHint fetchGraphixHint(Token token, GraphixParserHint[] expectedHints) {
65 if (token == null) {
66 return null;
67 }
68 Token hintToken = token.specialToken;
69
70 // We have a hint. Pull this from our collector.
71 if (hintToken == null) {
72 return null;
73 }
74 SourceLocation sourceLoc = getSourceLocation(hintToken);
75 hintCollector.remove(sourceLoc);
76
77 // Check for Graphix hints.
78 if (hintToken.hint != null) {
79 // A Graphix hint is not a SQLPP hint, so we shouldn't get anything in the "hint" field.
80 warnUnexpectedHint(hintToken.hint.getIdentifier(), sourceLoc, StringUtil.join(expectedHints, ", ", "\""));
81
82 } else if (hintToken.hintParams != null) {
83 for (GraphixParserHint graphixHint : expectedHints) {
84 if (graphixHint.getId().equals(hintToken.hintParams)) {
85 return graphixHint;
86 }
87 }
88 }
89 return null;
90}
91
ggalvizo08eab6f2022-04-15 15:22:00 -070092@override
93SelectBlock SelectBlock() throws ParseException:
94{
95 SelectClause selectClause = null;
96 FromClause fromClause = null;
97 FromGraphClause fromGraphClause = null;
98 List<LetClause> fromLetClauses = null;
99 WhereClause whereClause = null;
100 GroupbyClause groupbyClause = null;
101 List<LetClause> gbyLetClauses = null;
102 HavingClause havingClause = null;
103 SourceLocation startSrcLoc = null;
104
105 List<AbstractClause> fromLetWhereClauses = new ArrayList<AbstractClause>();
106 List<AbstractClause> gbyLetHavingClauses = new ArrayList<AbstractClause>();
107}
108{
109 (
110 (
111 selectClause = SelectClause() { startSrcLoc = selectClause.getSourceLocation(); }
112 (
113 (
114 ( LOOKAHEAD(2)
115 fromGraphClause = FromGraphClause()
116 | fromClause = FromClause()
117 )
118 ( fromLetClauses = LetClause() )?
119 ( whereClause = WhereClause() )?
120 ( groupbyClause = GroupbyClause()
121 ( gbyLetClauses = LetClause() )?
122 ( havingClause = HavingClause() )? )?
123 )
124 |
125 ( fromLetClauses = LetClause()
126 {
127 // LET without FROM -> create dummy FROM clause: FROM {{missing}} AS #0
128 SourceLocation sourceLoc = getSourceLocation(token);
129 LiteralExpr missingExpr = new LiteralExpr(MissingLiteral.INSTANCE);
130 missingExpr.setSourceLocation(sourceLoc);
131 List<Expression> list = new ArrayList<Expression>(1);
132 list.add(missingExpr);
133 ListConstructor listExpr = new ListConstructor(ListConstructor.Type.ORDERED_LIST_CONSTRUCTOR, list);
134 listExpr.setSourceLocation(sourceLoc);
135 List<FromTerm> fromTerms = new ArrayList<FromTerm>(1);
136 VariableExpr fromVar = new VariableExpr(new VarIdentifier("#0"));
137 fromVar.setSourceLocation(sourceLoc);
138 fromTerms.add(new FromTerm(listExpr, fromVar, null, new ArrayList<AbstractBinaryCorrelateClause>()));
139 fromClause = new FromClause(fromTerms);
140 }
141 ( whereClause = WhereClause() )?
142 )
143 )?
144 )
145 |
146 (
147 ( LOOKAHEAD(2)
148 fromGraphClause = FromGraphClause() { startSrcLoc = fromGraphClause.getSourceLocation(); }
149 | fromClause = FromClause() { startSrcLoc = fromClause.getSourceLocation(); }
150 )
151 ( fromLetClauses = LetClause() )?
152 ( whereClause = WhereClause() )?
153 ( groupbyClause = GroupbyClause()
154 ( gbyLetClauses = LetClause() )?
155 ( havingClause = HavingClause() )? )?
156 selectClause = SelectClause()
157 )
158 )
159 {
160 if (fromLetClauses != null) {
161 fromLetWhereClauses.addAll(fromLetClauses);
162 }
163 if (whereClause != null) {
164 fromLetWhereClauses.add(whereClause);
165 }
166 if (gbyLetClauses != null) {
167 gbyLetHavingClauses.addAll(gbyLetClauses);
168 }
169 if (havingClause != null) {
170 gbyLetHavingClauses.add(havingClause);
171 }
172
173 if (fromClause != null) {
174 SelectBlock selectBlock = new SelectBlock(selectClause, fromClause, fromLetWhereClauses,
175 groupbyClause, gbyLetHavingClauses);
176 selectBlock.setSourceLocation(startSrcLoc);
177 return selectBlock;
178
179 } else {
ggalvizoacd4b5b2022-09-25 14:29:42 -0700180 SelectBlock selectBlock = new SelectBlock(selectClause, fromGraphClause, fromLetWhereClauses,
181 groupbyClause, gbyLetHavingClauses);
ggalvizo08eab6f2022-04-15 15:22:00 -0700182 selectBlock.setSourceLocation(startSrcLoc);
183 return selectBlock;
184 }
185 }
186}
187
ggalvizo02256452022-06-14 19:18:50 -0700188@override
189Statement SingleStatement() throws ParseException:
ggalvizoab83c3b2021-12-22 14:15:50 -0800190{
ggalvizo02256452022-06-14 19:18:50 -0700191 Statement stmt = null;
ggalvizoab83c3b2021-12-22 14:15:50 -0800192}
193{
194 (
ggalvizo02256452022-06-14 19:18:50 -0700195 stmt = DataverseDeclaration()
196 | stmt = DeclareStatement()
197 | stmt = CreateStatement()
198 | stmt = LoadStatement()
199 | stmt = DropStatement()
200 | stmt = WriteStatement()
201 | stmt = SetStatement()
202 | stmt = InsertStatement()
203 | stmt = DeleteStatement()
204 | stmt = UpdateStatement()
205 | stmt = UpsertStatement()
206 | stmt = ConnectionStatement()
207 | stmt = CompactStatement()
208 | stmt = Query()
209 | stmt = RefreshExternalDatasetStatement()
210 )
211 {
212 return stmt;
213 }
214}
215
216@new
217Statement DeclareStatement() throws ParseException:
218{
219 Token startToken = null;
220 Statement stmt = null;
221}
222{
223 <DECLARE> { startToken = token; }
224 (
225 stmt = FunctionDecl(startToken)
226 | stmt = GraphDecl(startToken)
227 )
228 {
229 return stmt;
230 }
231}
232
233// Note: this is the same as FunctionDeclaration in the main grammar with the <DECLARE> token removed.
234@new
235FunctionDecl FunctionDecl(Token startToken) throws ParseException:
236{
237 String functionName;
238 Pair<Integer, List<Pair<VarIdentifier,TypeExpression>>> paramsWithArity = null;
239 Expression funcBody;
240 createNewScope();
241}
242{
243 <FUNCTION>
244 functionName = Identifier()
245 paramsWithArity = FunctionParameters()
246 <LEFTBRACE>
247 funcBody = FunctionBody()
248 <RIGHTBRACE>
249 {
250 int arity = paramsWithArity.first;
251 List<Pair<VarIdentifier,TypeExpression>> paramList = paramsWithArity.second;
252 FunctionSignature signature = new FunctionSignature(defaultDataverse, functionName, arity);
253 getCurrentScope().addFunctionDescriptor(signature, false);
254 ensureNoTypeDeclsInFunction(functionName, paramList, null, startToken);
255 List<VarIdentifier> params = new ArrayList<VarIdentifier>(paramList.size());
256 for (Pair<VarIdentifier,TypeExpression> p: paramList) {
257 params.add(p.getFirst());
258 }
259 FunctionDecl stmt = new FunctionDecl(signature, params, funcBody, false);
260 removeCurrentScope();
261 return addSourceLocation(stmt, startToken);
262 }
263}
264
265@merge
266Statement CreateStatement() throws ParseException:
267{
268}
269{
270 (
ggalvizoab83c3b2021-12-22 14:15:50 -0800271 before:
272 after: | stmt = CreateGraphStatement(startToken, false)
273 )
274 {
ggalvizoab83c3b2021-12-22 14:15:50 -0800275 }
276}
277
278@merge
279Statement CreateOrReplaceStatement(Token startStmtToken) throws ParseException:
280{
ggalvizoab83c3b2021-12-22 14:15:50 -0800281}
282{
283 (
ggalvizoab83c3b2021-12-22 14:15:50 -0800284 before:
285 after: | stmt = CreateGraphStatement(startStmtToken, true)
286 )
287 {
ggalvizoab83c3b2021-12-22 14:15:50 -0800288 }
289}
290
291@merge
292Statement DropStatement() throws ParseException:
293{
ggalvizoab83c3b2021-12-22 14:15:50 -0800294}
295{
296 (
ggalvizoab83c3b2021-12-22 14:15:50 -0800297 before:
298 after: | stmt = DropGraphStatement(startToken)
299 )
300 {
ggalvizo02256452022-06-14 19:18:50 -0700301 }
302}
303
304@new
305DeclareGraphStatement GraphDecl(Token startStmtToken) throws ParseException:
306{
307 GraphConstructor graphConstructor = null;
308 String graphName = null;
309}
310{
311 <GRAPH>
312 graphName = Identifier()
313 <AS> graphConstructor = GraphConstructor(token)
314 {
315 DeclareGraphStatement stmt = new DeclareGraphStatement(graphName, graphConstructor);
316 return addSourceLocation(stmt, startStmtToken);
ggalvizoab83c3b2021-12-22 14:15:50 -0800317 }
318}
319
320@new
321CreateGraphStatement CreateGraphStatement(Token startStmtToken, boolean orReplace) throws ParseException:
322{
323 CreateGraphStatement stmt = null;
324}
325{
326 <GRAPH> stmt = CreateGraphSpecification(startStmtToken, orReplace)
327 {
328 return stmt;
329 }
330}
331
332@new
333CreateGraphStatement CreateGraphSpecification(Token startStmtToken, boolean orReplace) throws ParseException:
334{
335 Pair<DataverseName, Identifier> nameComponents = null;
336 GraphConstructor graphConstructor = null;
337 boolean ifNotExists = false;
338}
339{
340 nameComponents = QualifiedName()
341 ifNotExists = IfNotExists()
342 {
343 if (orReplace && ifNotExists) {
344 throw new SqlppParseException(getSourceLocation(startStmtToken), "Unexpected IF NOT EXISTS");
345 }
346 }
347 <AS> graphConstructor = GraphConstructor(token)
348 {
349 CreateGraphStatement stmt = new CreateGraphStatement(nameComponents.first, nameComponents.second.getValue(),
350 orReplace, ifNotExists, graphConstructor);
351 return addSourceLocation(stmt, startStmtToken);
352 }
353}
354
355@new
356GraphDropStatement DropGraphStatement(Token startStmtToken) throws ParseException:
357{
358 GraphDropStatement stmt = null;
359}
360{
361 <GRAPH> stmt = DropGraphSpecification(startStmtToken)
362 {
363 return stmt;
364 }
365}
366
367@new
368GraphDropStatement DropGraphSpecification(Token startStmtToken) throws ParseException:
369{
370 Pair<DataverseName, Identifier> pairId = null;
371 boolean ifExists = false;
372}
373{
374 pairId = QualifiedName() ifExists = IfExists()
375 {
376 GraphDropStatement stmt = new GraphDropStatement(pairId.first, pairId.second.getValue(), ifExists);
377 return addSourceLocation(stmt, startStmtToken);
378 }
379}
380
381@new
382Pair<List<Integer>, List<List<String>>> KeyFields() throws ParseException:
383{
384 Pair<List<Integer>, List<List<String>>> keyFields = null;
385}
386{
387 // This is essentially an alias for the production PrimaryKeyFields.
388 keyFields = PrimaryKeyFields()
389 {
390 return keyFields;
391 }
392}
393
394@new
395GraphConstructor GraphConstructor(Token startStmtToken) throws ParseException:
396{
ggalvizo08eab6f2022-04-15 15:22:00 -0700397 List<GraphConstructor.VertexConstructor> vertexConstructors = new ArrayList<GraphConstructor.VertexConstructor>();
398 List<GraphConstructor.EdgeConstructor> edgeConstructors = new ArrayList<GraphConstructor.EdgeConstructor>();
399 GraphConstructor.VertexConstructor vertexConstructor = null;
400 GraphConstructor.EdgeConstructor edgeConstructor = null;
ggalvizoab83c3b2021-12-22 14:15:50 -0800401}
402{
ggalvizo08eab6f2022-04-15 15:22:00 -0700403 vertexConstructor = GraphVertexSpecification(startStmtToken) { vertexConstructors.add(vertexConstructor); }
ggalvizoab83c3b2021-12-22 14:15:50 -0800404 ( <COMMA>
405 (
ggalvizo08eab6f2022-04-15 15:22:00 -0700406 ( vertexConstructor = GraphVertexSpecification(token) { vertexConstructors.add(vertexConstructor); } )
407 | ( edgeConstructor = GraphEdgeSpecification(token) { edgeConstructors.add(edgeConstructor); } )
ggalvizoab83c3b2021-12-22 14:15:50 -0800408 )
409 )*
410 {
ggalvizo08eab6f2022-04-15 15:22:00 -0700411 GraphConstructor graphConstructor = new GraphConstructor(vertexConstructors, edgeConstructors);
ggalvizoab83c3b2021-12-22 14:15:50 -0800412 return addSourceLocation(graphConstructor, startStmtToken);
413 }
414}
415
416@new
ggalvizo08eab6f2022-04-15 15:22:00 -0700417GraphConstructor.VertexConstructor GraphVertexSpecification(Token startStmtToken) throws ParseException:
ggalvizoab83c3b2021-12-22 14:15:50 -0800418{
419 Pair<List<Integer>, List<List<String>>> primaryKeyFields;
420 Token beginPos = null, endPos = null;
ggalvizo696e5fd2022-06-21 18:12:07 -0700421 int positionOffset = 0;
ggalvizoab83c3b2021-12-22 14:15:50 -0800422 Expression vertexDefinitionExpr;
ggalvizoacd4b5b2022-09-25 14:29:42 -0700423 ElementLabel elementLabel;
ggalvizoab83c3b2021-12-22 14:15:50 -0800424}
425{
426 <VERTEX>
ggalvizoacd4b5b2022-09-25 14:29:42 -0700427 elementLabel = GraphVertexDefinitionPattern()
ggalvizoab83c3b2021-12-22 14:15:50 -0800428 <PRIMARY> <KEY> <LEFTPAREN> primaryKeyFields = KeyFields() <RIGHTPAREN>
429 <AS>
430 {
431 beginPos = token;
432 createNewScope();
433 }
434 (
ggalvizo696e5fd2022-06-21 18:12:07 -0700435 vertexDefinitionExpr = ViewBody() { endPos = token; positionOffset++; }
ggalvizo08eab6f2022-04-15 15:22:00 -0700436 | <LEFTPAREN> { beginPos = token; } vertexDefinitionExpr = ViewBody() { endPos = token; } <RIGHTPAREN>
ggalvizoab83c3b2021-12-22 14:15:50 -0800437 )
438 {
ggalvizo696e5fd2022-06-21 18:12:07 -0700439 String vDef = extractFragment(beginPos.beginLine, beginPos.beginColumn + positionOffset, endPos.endLine,
440 endPos.endColumn + 1);
ggalvizoab83c3b2021-12-22 14:15:50 -0800441 removeCurrentScope();
ggalvizoacd4b5b2022-09-25 14:29:42 -0700442 GraphConstructor.VertexConstructor vertexConstructor = new GraphConstructor.VertexConstructor(elementLabel,
ggalvizoab83c3b2021-12-22 14:15:50 -0800443 primaryKeyFields.second, primaryKeyFields.first, vertexDefinitionExpr, vDef);
ggalvizo08eab6f2022-04-15 15:22:00 -0700444 return addSourceLocation(vertexConstructor, startStmtToken);
ggalvizoab83c3b2021-12-22 14:15:50 -0800445 }
446}
447
448@new
ggalvizo08eab6f2022-04-15 15:22:00 -0700449ElementLabel GraphVertexDefinitionPattern() throws ParseException:
ggalvizoab83c3b2021-12-22 14:15:50 -0800450{
451 String vertexName;
452}
453{
454 <LEFTPAREN> <COLON> vertexName = Identifier() <RIGHTPAREN>
455 {
ggalvizoacd4b5b2022-09-25 14:29:42 -0700456 return new ElementLabel(vertexName, false);
ggalvizoab83c3b2021-12-22 14:15:50 -0800457 }
458}
459
460@new
ggalvizo08eab6f2022-04-15 15:22:00 -0700461GraphConstructor.EdgeConstructor GraphEdgeSpecification(Token startStmtToken) throws ParseException:
ggalvizoab83c3b2021-12-22 14:15:50 -0800462{
ggalvizo08eab6f2022-04-15 15:22:00 -0700463 Pair<Triple<ElementLabel, ElementLabel, ElementLabel>, Boolean> edgeDefinitionPattern;
ggalvizoab83c3b2021-12-22 14:15:50 -0800464 Pair<List<Integer>, List<List<String>>> keyFields;
465 Token beginPos = null, endPos = null;
466 Expression edgeDefinitionExpr = null;
ggalvizo696e5fd2022-06-21 18:12:07 -0700467 int positionOffset = 0;
ggalvizoab83c3b2021-12-22 14:15:50 -0800468
469 List<Integer> destinationKeySourceIndicators = null;
470 List<Integer> sourceKeySourceIndicators = null;
ggalvizoab83c3b2021-12-22 14:15:50 -0800471 List<List<String>> destinationKeyFields = null;
472 List<List<String>> sourceKeyFields = null;
ggalvizoab83c3b2021-12-22 14:15:50 -0800473}
474{
475 <EDGE>
476 edgeDefinitionPattern = GraphEdgeDefinitionPattern()
477 (
ggalvizo08eab6f2022-04-15 15:22:00 -0700478 <SOURCE> <KEY> <LEFTPAREN> keyFields = KeyFields() <RIGHTPAREN>
479 {
480 sourceKeyFields = keyFields.second;
481 sourceKeySourceIndicators = keyFields.first;
482 }
483 <DESTINATION> <KEY> <LEFTPAREN> keyFields = KeyFields() <RIGHTPAREN>
484 {
485 destinationKeyFields = keyFields.second;
486 destinationKeySourceIndicators = keyFields.first;
487 }
488 <AS>
489 {
490 beginPos = token;
491 createNewScope();
492 }
ggalvizoab83c3b2021-12-22 14:15:50 -0800493 (
ggalvizo696e5fd2022-06-21 18:12:07 -0700494 edgeDefinitionExpr = SelectExpression(true) { endPos = token; positionOffset++; }
ggalvizo08eab6f2022-04-15 15:22:00 -0700495 | <LEFTPAREN> { beginPos = token; } edgeDefinitionExpr = SelectExpression(true) { endPos = token; } <RIGHTPAREN>
ggalvizoab83c3b2021-12-22 14:15:50 -0800496 )
497 )
498 {
ggalvizo08eab6f2022-04-15 15:22:00 -0700499 ElementLabel destinationLabel, edgeLabel, sourceLabel;
ggalvizoab83c3b2021-12-22 14:15:50 -0800500 if (edgeDefinitionPattern.second) { // isDirectedLeft
501 sourceLabel = edgeDefinitionPattern.first.third;
502 edgeLabel = edgeDefinitionPattern.first.second;
503 destinationLabel = edgeDefinitionPattern.first.first;
ggalvizo08eab6f2022-04-15 15:22:00 -0700504
ggalvizoab83c3b2021-12-22 14:15:50 -0800505 } else {
506 sourceLabel = edgeDefinitionPattern.first.first;
507 edgeLabel = edgeDefinitionPattern.first.second;
508 destinationLabel = edgeDefinitionPattern.first.third;
509 }
510
511 String eDef = null;
512 if (edgeDefinitionExpr != null) {
ggalvizo696e5fd2022-06-21 18:12:07 -0700513 eDef = extractFragment(beginPos.beginLine, beginPos.beginColumn + positionOffset, endPos.endLine,
514 endPos.endColumn + 1);
ggalvizoab83c3b2021-12-22 14:15:50 -0800515 removeCurrentScope();
516 }
517
ggalvizo08eab6f2022-04-15 15:22:00 -0700518 GraphConstructor.EdgeConstructor edgeConstructor = new GraphConstructor.EdgeConstructor(edgeLabel, destinationLabel,
519 sourceLabel, destinationKeyFields, destinationKeySourceIndicators, sourceKeyFields, sourceKeySourceIndicators,
520 edgeDefinitionExpr, eDef);
521 return addSourceLocation(edgeConstructor, startStmtToken);
ggalvizoab83c3b2021-12-22 14:15:50 -0800522 }
523}
524
525@new
ggalvizo08eab6f2022-04-15 15:22:00 -0700526Pair<Triple<ElementLabel, ElementLabel, ElementLabel>, Boolean> GraphEdgeDefinitionPattern() throws ParseException:
ggalvizoab83c3b2021-12-22 14:15:50 -0800527{
ggalvizoacd4b5b2022-09-25 14:29:42 -0700528 ElementLabel leftElementLabel, rightElementLabel;
ggalvizoab83c3b2021-12-22 14:15:50 -0800529 boolean isDirectedLeft;
ggalvizo08eab6f2022-04-15 15:22:00 -0700530 String edgeName;
ggalvizoab83c3b2021-12-22 14:15:50 -0800531}
532{
ggalvizoacd4b5b2022-09-25 14:29:42 -0700533 leftElementLabel = GraphVertexDefinitionPattern()
ggalvizoab83c3b2021-12-22 14:15:50 -0800534 ( <MINUS> <LEFTBRACKET> <COLON> edgeName = Identifier() <RIGHTBRACKET> <MINUS> <GT> { isDirectedLeft = false; }
535 | <LT> <MINUS> <LEFTBRACKET> <COLON> edgeName = Identifier() <RIGHTBRACKET> <MINUS> { isDirectedLeft = true; } )
ggalvizoacd4b5b2022-09-25 14:29:42 -0700536 rightElementLabel = GraphVertexDefinitionPattern()
ggalvizoab83c3b2021-12-22 14:15:50 -0800537 {
ggalvizo08eab6f2022-04-15 15:22:00 -0700538 Triple<ElementLabel, ElementLabel, ElementLabel> t = new Triple<ElementLabel, ElementLabel, ElementLabel>(
ggalvizoacd4b5b2022-09-25 14:29:42 -0700539 leftElementLabel, new ElementLabel(edgeName, false), rightElementLabel);
ggalvizo08eab6f2022-04-15 15:22:00 -0700540 return new Pair<Triple<ElementLabel, ElementLabel, ElementLabel>, Boolean>(t, isDirectedLeft);
541 }
542}
543
544@new
545FromGraphClause FromGraphClause() throws ParseException:
546{
547 Token startToken = null;
548 GraphConstructor graphConstructor = null;
549 Pair<DataverseName, Identifier> nameComponents = null;
550 AbstractBinaryCorrelateClause correlateClause = null;
551
552 List<MatchClause> matchClauses = new ArrayList<MatchClause>();
553 List<PathPatternExpr> pathPatternExpressions = null;
554 List<AbstractBinaryCorrelateClause> correlateClauses = new ArrayList<AbstractBinaryCorrelateClause>();
555}
556{
557 <FROM> <GRAPH> { startToken = token; }
558 (
559 graphConstructor = GraphConstructor(token)
560 | nameComponents = QualifiedName()
561 )
562 <MATCH> pathPatternExpressions = PathPatternExpressions()
563 { matchClauses.add(new MatchClause(pathPatternExpressions, MatchType.LEADING)); }
564 ( LOOKAHEAD(3) // We want to avoid getting confused with the correlated clauses below.
565 (
566 <LEFT> ( <OUTER> )? <MATCH> pathPatternExpressions = PathPatternExpressions()
567 { matchClauses.add(new MatchClause(pathPatternExpressions, MatchType.LEFTOUTER)); }
568 |
569 ( <INNER> )? <MATCH> pathPatternExpressions = PathPatternExpressions()
570 { matchClauses.add(new MatchClause(pathPatternExpressions, MatchType.INNER)); }
571 )
572 )*
573 (
574 (
575 correlateClause = JoinOrUnnestClause(JoinType.INNER, UnnestType.INNER)
576 | ( <INNER> correlateClause = JoinOrUnnestClause(JoinType.INNER, UnnestType.INNER) )
577 | ( <LEFT> ( <OUTER> )? correlateClause = JoinOrUnnestClause(JoinType.LEFTOUTER, UnnestType.LEFTOUTER) )
578 | ( <RIGHT> ( <OUTER> )? correlateClause = JoinClause(JoinType.RIGHTOUTER) )
579 | ( <CROSS> correlateClause = CrossJoinClause() )
580 )
581 {
582 correlateClauses.add(correlateClause);
583 }
584 )*
585 {
586 FromGraphClause fromGraphClause;
587 if (graphConstructor == null) {
588 fromGraphClause = new FromGraphClause(nameComponents.first, nameComponents.second,
589 matchClauses, correlateClauses);
590
591 } else {
592 fromGraphClause = new FromGraphClause(graphConstructor, matchClauses, correlateClauses);
593 }
594 return addSourceLocation(fromGraphClause, startToken);
595 }
596}
597
598@new
599List<PathPatternExpr> PathPatternExpressions() throws ParseException:
600{
601 List<PathPatternExpr> pathPatternExpressions = new ArrayList<PathPatternExpr>();
602 PathPatternExpr pathPattern = null;
603 VariableExpr variableExpr = null;
604}
605{
606 pathPattern = PathPatternExpression() { pathPatternExpressions.add(pathPattern); }
607 (
608 ( <AS> )? variableExpr = Variable()
609 {
610 int index = pathPatternExpressions.size() - 1;
611 pathPatternExpressions.get(index).setVariableExpr(variableExpr);
612 }
613 )?
614 ( LOOKAHEAD(2)
615 <COMMA> pathPattern = PathPatternExpression() { pathPatternExpressions.add(pathPattern); }
616 (
617 ( <AS> )? variableExpr = Variable()
618 {
619 int index = pathPatternExpressions.size() - 1;
620 pathPatternExpressions.get(index).setVariableExpr(variableExpr);
621 }
622 )?
623 )*
624 {
625 return pathPatternExpressions;
626 }
627}
628
629@new
630PathPatternExpr PathPatternExpression() throws ParseException:
631{
632 List<VertexPatternExpr> orderedVertexExpressions = new ArrayList<VertexPatternExpr>();
633 List<EdgePatternExpr> orderedEdgeExpressions = new ArrayList<EdgePatternExpr>();
634
635 Token startToken = null, edgeStartToken = null;
636 VertexPatternExpr vertexExpr = null;
ggalvizoacd4b5b2022-09-25 14:29:42 -0700637 Pair<EdgeDescriptor, List<IExpressionAnnotation>> edgeDescriptorPair = null;
ggalvizo08eab6f2022-04-15 15:22:00 -0700638}
639{
640 vertexExpr = VertexPatternExpression()
641 {
642 startToken = token;
643 orderedVertexExpressions.add(vertexExpr);
644 }
645 (
ggalvizoacd4b5b2022-09-25 14:29:42 -0700646 edgeDescriptorPair = EdgeDescriptorPair() { edgeStartToken = token; }
ggalvizo08eab6f2022-04-15 15:22:00 -0700647 vertexExpr = VertexPatternExpression()
648 {
649 VertexPatternExpr leftVertex = orderedVertexExpressions.get(orderedVertexExpressions.size() - 1);
ggalvizoacd4b5b2022-09-25 14:29:42 -0700650 EdgePatternExpr edgePattern = new EdgePatternExpr(leftVertex, vertexExpr, edgeDescriptorPair.first);
651 if (!edgeDescriptorPair.second.isEmpty()) {
652 for (IExpressionAnnotation annotation : edgeDescriptorPair.second) {
653 edgePattern.addHint(annotation);
654 }
655 }
ggalvizo08eab6f2022-04-15 15:22:00 -0700656 orderedEdgeExpressions.add(addSourceLocation(edgePattern, edgeStartToken));
657 orderedVertexExpressions.add(vertexExpr);
658 }
659 )*
660 {
661 PathPatternExpr pathPattern = new PathPatternExpr(orderedVertexExpressions, orderedEdgeExpressions, null);
662 return addSourceLocation(pathPattern, startToken);
663 }
664}
665
666@new
667VertexPatternExpr VertexPatternExpression() throws ParseException:
668{
ggalvizoacd4b5b2022-09-25 14:29:42 -0700669 Set<String> vertexLabels = new HashSet<String>();
ggalvizo08eab6f2022-04-15 15:22:00 -0700670 VariableExpr variableExpr = null;
ggalvizoacd4b5b2022-09-25 14:29:42 -0700671 Expression filterExpr = null;
672 boolean isNegatedLabelSet = false;
ggalvizo08eab6f2022-04-15 15:22:00 -0700673 Token startToken = null;
674 String vertexLabelName;
675}
676{
677 <LEFTPAREN> { startToken = token; }
ggalvizoacd4b5b2022-09-25 14:29:42 -0700678 ( variableExpr = Variable() )?
ggalvizo08eab6f2022-04-15 15:22:00 -0700679 (
ggalvizoacd4b5b2022-09-25 14:29:42 -0700680 <COLON>
681 ( <CARET> { isNegatedLabelSet = true; } )?
682 vertexLabels = ParenthesizedLabelValueSet()
ggalvizo08eab6f2022-04-15 15:22:00 -0700683 )?
ggalvizoacd4b5b2022-09-25 14:29:42 -0700684 ( <WHERE> filterExpr = Expression() )?
ggalvizo08eab6f2022-04-15 15:22:00 -0700685 <RIGHTPAREN>
686 {
ggalvizoacd4b5b2022-09-25 14:29:42 -0700687 // Construct our label set.
688 Set<ElementLabel> labels = new HashSet<ElementLabel>();
689 for (String vertexLabelValue : vertexLabels) {
690 labels.add(new ElementLabel(vertexLabelValue, isNegatedLabelSet));
691 }
692 VertexPatternExpr vertexExpression = new VertexPatternExpr(variableExpr, filterExpr, labels);
ggalvizo08eab6f2022-04-15 15:22:00 -0700693 return addSourceLocation(vertexExpression, startToken);
694 }
695}
696
697@new
ggalvizoacd4b5b2022-09-25 14:29:42 -0700698Pair<EdgeDescriptor, List<IExpressionAnnotation>> EdgeDescriptorPair() throws ParseException:
ggalvizo08eab6f2022-04-15 15:22:00 -0700699{
ggalvizoacd4b5b2022-09-25 14:29:42 -0700700 GraphixParserHint[] expectedHints = { GraphixParserHint.EXPAND_AND_UNION_HINT,
701 GraphixParserHint.SWITCH_AND_CYCLE_HINT };
702 List<IExpressionAnnotation> hintList = new ArrayList<IExpressionAnnotation>();
703 Triple<Set<ElementLabel>, Pair<Integer, Integer>, Expression> edgeDetail = null;
704 Token startToken = null, hintToken = null;
ggalvizo08eab6f2022-04-15 15:22:00 -0700705 VariableExpr edgeVariable = null;
ggalvizoacd4b5b2022-09-25 14:29:42 -0700706 Expression filterExpr = null;
ggalvizo08eab6f2022-04-15 15:22:00 -0700707
708 // We default to undirected edges.
ggalvizo01f41f42022-04-26 18:42:38 -0700709 EdgeDescriptor.EdgeDirection edgeDirection = EdgeDescriptor.EdgeDirection.UNDIRECTED;
ggalvizo08eab6f2022-04-15 15:22:00 -0700710}
711{
712 (
713 <MINUS> { startToken = token; }
714 (
715 <LEFTBRACKET>
ggalvizoacd4b5b2022-09-25 14:29:42 -0700716 ( edgeVariable = Variable() )?
717 ( edgeDetail = EdgeDetail() )?
718 <RIGHTBRACKET> { hintToken = token; } <MINUS>
ggalvizo08eab6f2022-04-15 15:22:00 -0700719 )?
ggalvizo01f41f42022-04-26 18:42:38 -0700720 ( <GT> { edgeDirection = EdgeDescriptor.EdgeDirection.LEFT_TO_RIGHT; } )?
ggalvizo08eab6f2022-04-15 15:22:00 -0700721 |
722 <LT> {
723 startToken = token;
ggalvizo01f41f42022-04-26 18:42:38 -0700724 edgeDirection = EdgeDescriptor.EdgeDirection.RIGHT_TO_LEFT;
ggalvizo08eab6f2022-04-15 15:22:00 -0700725 }
726 <MINUS>
727 (
728 <LEFTBRACKET>
ggalvizoacd4b5b2022-09-25 14:29:42 -0700729 ( edgeVariable = Variable() )?
730 ( edgeDetail = EdgeDetail() )?
731 <RIGHTBRACKET> { hintToken = token; } <MINUS>
ggalvizo08eab6f2022-04-15 15:22:00 -0700732 )?
733 )
734 {
ggalvizoacd4b5b2022-09-25 14:29:42 -0700735 // See if we have an evaluation hint.
736 GraphixParserHint evalHint = fetchGraphixHint(hintToken, expectedHints);
737 if (Objects.equals(evalHint, GraphixParserHint.EXPAND_AND_UNION_HINT)) {
738 hintList.add(new ElementEvaluationAnnotation(ElementEvaluationAnnotation.Kind.EXPAND_AND_UNION));
739
740 } else if (Objects.equals(evalHint, GraphixParserHint.SWITCH_AND_CYCLE_HINT)) {
741 hintList.add(new ElementEvaluationAnnotation(ElementEvaluationAnnotation.Kind.SWITCH_AND_CYCLE));
742 }
743
ggalvizo01f41f42022-04-26 18:42:38 -0700744 // Edges (by default) are of pattern type EDGE and are not sub-paths.
745 EdgeDescriptor.PatternType patternType = EdgeDescriptor.PatternType.EDGE;
ggalvizo08eab6f2022-04-15 15:22:00 -0700746 Integer hopCountMin = 1;
747 Integer hopCountMax = 1;
748
749 Set<ElementLabel> labels = new HashSet<ElementLabel>();
750 if (edgeDetail != null) {
751 labels = edgeDetail.first;
ggalvizoacd4b5b2022-09-25 14:29:42 -0700752 filterExpr = edgeDetail.third;
ggalvizo08eab6f2022-04-15 15:22:00 -0700753
754 // We have explicitly specified "{" and "}". Use sub-path semantics.
755 if (edgeDetail.second != null) {
ggalvizo01f41f42022-04-26 18:42:38 -0700756 patternType = EdgeDescriptor.PatternType.PATH;
ggalvizo08eab6f2022-04-15 15:22:00 -0700757 hopCountMin = edgeDetail.second.first;
758 hopCountMax = edgeDetail.second.second;
759 }
760 }
ggalvizoacd4b5b2022-09-25 14:29:42 -0700761 EdgeDescriptor edgeDescriptor =
762 new EdgeDescriptor(edgeDirection, patternType, labels, filterExpr, edgeVariable, hopCountMin, hopCountMax);
763 return new Pair<EdgeDescriptor, List<IExpressionAnnotation>>(edgeDescriptor, hintList);
ggalvizo08eab6f2022-04-15 15:22:00 -0700764 }
765}
766
767@new
ggalvizoacd4b5b2022-09-25 14:29:42 -0700768Triple<Set<ElementLabel>, Pair<Integer, Integer>, Expression> EdgeDetail() throws ParseException:
ggalvizo08eab6f2022-04-15 15:22:00 -0700769{
ggalvizoacd4b5b2022-09-25 14:29:42 -0700770 Set<String> edgeLabels = new HashSet<String>();
ggalvizo08eab6f2022-04-15 15:22:00 -0700771 Pair<Integer, Integer> repetitionQuantifier = null;
ggalvizoacd4b5b2022-09-25 14:29:42 -0700772 Expression filterExpr = null;
773 boolean isNegatedLabelSet = false;
ggalvizo08eab6f2022-04-15 15:22:00 -0700774 String labelName = null;
775}
776{
777 (
ggalvizo08eab6f2022-04-15 15:22:00 -0700778 ( repetitionQuantifier = EdgeRepetitionQuantifier() )
ggalvizoacd4b5b2022-09-25 14:29:42 -0700779 |
780 (
781 <COLON>
782 ( <CARET> { isNegatedLabelSet = true; } )?
783 edgeLabels = ParenthesizedLabelValueSet()
784 ( LOOKAHEAD(2)
785 ( <WHERE> filterExpr = Expression() )
786 |
787 ( repetitionQuantifier = EdgeRepetitionQuantifier() )
788 )?
789 )
790 |
791 ( <WHERE> filterExpr = Expression() )
ggalvizo08eab6f2022-04-15 15:22:00 -0700792 )
793 {
ggalvizoacd4b5b2022-09-25 14:29:42 -0700794 // Construct our label set.
795 Set<ElementLabel> labels = new HashSet<ElementLabel>();
796 for (String edgeLabelValue : edgeLabels) {
797 labels.add(new ElementLabel(edgeLabelValue, isNegatedLabelSet));
798 }
799 return new Triple<Set<ElementLabel>, Pair<Integer, Integer>, Expression> (labels, repetitionQuantifier, filterExpr);
800 }
801}
802
803@new
804Set<String> ParenthesizedLabelValueSet() throws ParseException:
805{
806 Set<String> labelSet = new HashSet<String>();
807 Set<String> innerLabelSet = null;
808 String labelName = null;
809}
810{
811 (
812 ( labelName = Identifier() { labelSet.add(labelName); } )
813 |
814 (
815 <LEFTPAREN>
816 innerLabelSet = ParenthesizedLabelValueSet() { labelSet.addAll(innerLabelSet); }
817 (
818 <BAR>
819 innerLabelSet = ParenthesizedLabelValueSet() { labelSet.addAll(innerLabelSet); }
820 )*
821 <RIGHTPAREN>
822 )
823 )
824 {
825 return labelSet;
ggalvizo08eab6f2022-04-15 15:22:00 -0700826 }
827}
828
829@new
830Pair<Integer, Integer> EdgeRepetitionQuantifier() throws ParseException:
831{
832 Integer hopCountMin = null;
833 Integer hopCountMax = null;
834}
835{
ggalvizoacd4b5b2022-09-25 14:29:42 -0700836 (
837 <PLUS>
838 |
839 (
840 <LEFTBRACE>
841 ( <INTEGER_LITERAL> { hopCountMin = Integer.valueOf(token.image); } )?
842 <COMMA>
843 ( <INTEGER_LITERAL> { hopCountMax = Integer.valueOf(token.image); } )?
844 <RIGHTBRACE>
845 )
ggalvizo08eab6f2022-04-15 15:22:00 -0700846 )
ggalvizo08eab6f2022-04-15 15:22:00 -0700847 {
848 return new Pair<Integer, Integer>(hopCountMin, hopCountMax);
ggalvizoab83c3b2021-12-22 14:15:50 -0800849 }
850}
851
852@new
853<DEFAULT,IN_DBL_BRACE>
854TOKEN [IGNORE_CASE]:
855{
856 <DESTINATION: "destination">
857 | <EDGE: "edge">
858 | <GRAPH: "graph">
859 | <SOURCE: "source">
860 | <VERTEX: "vertex">
ggalvizo08eab6f2022-04-15 15:22:00 -0700861 | <MATCH: "match">
ggalvizoab83c3b2021-12-22 14:15:50 -0800862}
863
864@new_at_the_end
865<DEFAULT,IN_DBL_BRACE>
866TOKEN :
867{
868 <BAR: "|">
869}