vtlengine 1.4.0rc2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. vtlengine/API/_InternalApi.py +791 -0
  2. vtlengine/API/__init__.py +612 -0
  3. vtlengine/API/data/schema/external_routines_schema.json +34 -0
  4. vtlengine/API/data/schema/json_schema_2.1.json +116 -0
  5. vtlengine/API/data/schema/value_domain_schema.json +97 -0
  6. vtlengine/AST/ASTComment.py +57 -0
  7. vtlengine/AST/ASTConstructor.py +598 -0
  8. vtlengine/AST/ASTConstructorModules/Expr.py +1928 -0
  9. vtlengine/AST/ASTConstructorModules/ExprComponents.py +995 -0
  10. vtlengine/AST/ASTConstructorModules/Terminals.py +790 -0
  11. vtlengine/AST/ASTConstructorModules/__init__.py +50 -0
  12. vtlengine/AST/ASTDataExchange.py +10 -0
  13. vtlengine/AST/ASTEncoders.py +32 -0
  14. vtlengine/AST/ASTString.py +675 -0
  15. vtlengine/AST/ASTTemplate.py +558 -0
  16. vtlengine/AST/ASTVisitor.py +25 -0
  17. vtlengine/AST/DAG/__init__.py +479 -0
  18. vtlengine/AST/DAG/_words.py +10 -0
  19. vtlengine/AST/Grammar/Vtl.g4 +705 -0
  20. vtlengine/AST/Grammar/VtlTokens.g4 +409 -0
  21. vtlengine/AST/Grammar/__init__.py +0 -0
  22. vtlengine/AST/Grammar/lexer.py +2139 -0
  23. vtlengine/AST/Grammar/parser.py +16597 -0
  24. vtlengine/AST/Grammar/tokens.py +169 -0
  25. vtlengine/AST/VtlVisitor.py +824 -0
  26. vtlengine/AST/__init__.py +674 -0
  27. vtlengine/DataTypes/TimeHandling.py +562 -0
  28. vtlengine/DataTypes/__init__.py +863 -0
  29. vtlengine/DataTypes/_time_checking.py +135 -0
  30. vtlengine/Exceptions/__exception_file_generator.py +96 -0
  31. vtlengine/Exceptions/__init__.py +159 -0
  32. vtlengine/Exceptions/messages.py +1004 -0
  33. vtlengine/Interpreter/__init__.py +2048 -0
  34. vtlengine/Model/__init__.py +501 -0
  35. vtlengine/Operators/Aggregation.py +357 -0
  36. vtlengine/Operators/Analytic.py +455 -0
  37. vtlengine/Operators/Assignment.py +23 -0
  38. vtlengine/Operators/Boolean.py +106 -0
  39. vtlengine/Operators/CastOperator.py +451 -0
  40. vtlengine/Operators/Clause.py +366 -0
  41. vtlengine/Operators/Comparison.py +488 -0
  42. vtlengine/Operators/Conditional.py +495 -0
  43. vtlengine/Operators/General.py +191 -0
  44. vtlengine/Operators/HROperators.py +254 -0
  45. vtlengine/Operators/Join.py +447 -0
  46. vtlengine/Operators/Numeric.py +422 -0
  47. vtlengine/Operators/RoleSetter.py +77 -0
  48. vtlengine/Operators/Set.py +176 -0
  49. vtlengine/Operators/String.py +578 -0
  50. vtlengine/Operators/Time.py +1144 -0
  51. vtlengine/Operators/Validation.py +275 -0
  52. vtlengine/Operators/__init__.py +900 -0
  53. vtlengine/Utils/__Virtual_Assets.py +34 -0
  54. vtlengine/Utils/__init__.py +479 -0
  55. vtlengine/__extras_check.py +17 -0
  56. vtlengine/__init__.py +27 -0
  57. vtlengine/files/__init__.py +0 -0
  58. vtlengine/files/output/__init__.py +35 -0
  59. vtlengine/files/output/_time_period_representation.py +55 -0
  60. vtlengine/files/parser/__init__.py +240 -0
  61. vtlengine/files/parser/_rfc_dialect.py +22 -0
  62. vtlengine/py.typed +0 -0
  63. vtlengine-1.4.0rc2.dist-info/METADATA +89 -0
  64. vtlengine-1.4.0rc2.dist-info/RECORD +66 -0
  65. vtlengine-1.4.0rc2.dist-info/WHEEL +4 -0
  66. vtlengine-1.4.0rc2.dist-info/licenses/LICENSE.md +661 -0
@@ -0,0 +1,1928 @@
1
+ import re
2
+ from copy import copy
3
+ from typing import Any
4
+
5
+ from antlr4.tree.Tree import TerminalNodeImpl
6
+
7
+ from vtlengine.AST import (
8
+ ID,
9
+ Aggregation,
10
+ Analytic,
11
+ Assignment,
12
+ BinOp,
13
+ Case,
14
+ CaseObj,
15
+ Constant,
16
+ EvalOp,
17
+ Identifier,
18
+ If,
19
+ JoinOp,
20
+ MulOp,
21
+ ParamConstant,
22
+ ParamOp,
23
+ ParFunction,
24
+ RegularAggregation,
25
+ RenameNode,
26
+ TimeAggregation,
27
+ UDOCall,
28
+ UnaryOp,
29
+ Validation,
30
+ VarID,
31
+ Windowing,
32
+ )
33
+ from vtlengine.AST.ASTConstructorModules import extract_token_info
34
+ from vtlengine.AST.ASTConstructorModules.ExprComponents import ExprComp
35
+ from vtlengine.AST.ASTConstructorModules.Terminals import Terminals
36
+ from vtlengine.AST.ASTDataExchange import de_ruleset_elements
37
+ from vtlengine.AST.Grammar.parser import Parser
38
+ from vtlengine.AST.Grammar.tokens import DATASET_PRIORITY
39
+ from vtlengine.AST.VtlVisitor import VtlVisitor
40
+ from vtlengine.Exceptions import SemanticError
41
+ from vtlengine.Model import Role
42
+
43
+
44
+ class Expr(VtlVisitor):
45
+ """______________________________________________________________________________________
46
+
47
+
48
+ Expr Definition.
49
+
50
+ _______________________________________________________________________________________
51
+ """
52
+
53
+ def visitExpr(self, ctx: Parser.ExprContext):
54
+ """
55
+ expr:
56
+ LPAREN expr RPAREN # parenthesisExpr
57
+ | functions # functionsExpression
58
+ | dataset=expr QLPAREN clause=datasetClause QRPAREN # clauseExpr
59
+ | expr MEMBERSHIP simpleComponentId # membershipExpr
60
+ | op=(PLUS|MINUS|NOT) right=expr # unaryExpr
61
+ | left=expr op=(MUL|DIV) right=expr # arithmeticExpr
62
+ | left=expr op=(PLUS|MINUS|CONCAT) right=expr # arithmeticExprOrConcat
63
+ | left=expr op=comparisonOperand right=expr # comparisonExpr
64
+ | left=expr op=(IN|NOT_IN)(lists|valueDomainID) # inNotInExpr
65
+ | left=expr op=AND right=expr # booleanExpr
66
+ | left=expr op=(OR|XOR) right=expr # booleanExpr
67
+ | IF conditionalExpr=expr THEN thenExpr=expr ELSE elseExpr=expr # ifExpr
68
+ | CASE WHEN expr THEN expr ELSE expr END # caseExpr
69
+ | constant # constantExpr
70
+ | varID # varIdExpr
71
+ ;
72
+ """ # noqa E501
73
+ ctx_list = list(ctx.getChildren())
74
+ c = ctx_list[0]
75
+
76
+ if isinstance(ctx, Parser.ParenthesisExprContext):
77
+ return self.visitParenthesisExpr(ctx)
78
+
79
+ elif isinstance(ctx, Parser.MembershipExprContext):
80
+ return self.visitMembershipExpr(ctx)
81
+
82
+ # dataset=expr QLPAREN clause=datasetClause QRPAREN # clauseExpr
83
+ elif isinstance(ctx, Parser.ClauseExprContext):
84
+ return self.visitClauseExpr(ctx)
85
+
86
+ # functions
87
+ elif isinstance(ctx, Parser.FunctionsExpressionContext):
88
+ return self.visitFunctionsExpression(c)
89
+
90
+ # op=(PLUS|MINUS|NOT) right=expr # unary expression
91
+ elif isinstance(ctx, Parser.UnaryExprContext):
92
+ return self.visitUnaryExpr(ctx)
93
+
94
+ # | left=expr op=(MUL|DIV) right=expr # arithmeticExpr
95
+ elif isinstance(ctx, Parser.ArithmeticExprContext):
96
+ return self.visitArithmeticExpr(ctx)
97
+
98
+ # | left=expr op=(PLUS|MINUS|CONCAT) right=expr # arithmeticExprOrConcat
99
+ elif isinstance(ctx, Parser.ArithmeticExprOrConcatContext):
100
+ return self.visitArithmeticExprOrConcat(ctx)
101
+
102
+ # | left=expr op=comparisonOperand right=expr # comparisonExpr
103
+ elif isinstance(ctx, Parser.ComparisonExprContext):
104
+ return self.visitComparisonExpr(ctx)
105
+
106
+ # | left=expr op=(IN|NOT_IN)(lists|valueDomainID) # inNotInExpr
107
+ elif isinstance(ctx, Parser.InNotInExprContext):
108
+ return self.visitInNotInExpr(ctx)
109
+
110
+ # | left=expr op=AND right=expr # booleanExpr
111
+ # | left=expr op=(OR|XOR) right=expr
112
+ elif isinstance(ctx, Parser.BooleanExprContext):
113
+ return self.visitBooleanExpr(ctx)
114
+
115
+ # IF conditionalExpr=expr THEN thenExpr=expr ELSE elseExpr=expr # ifExpr
116
+ elif isinstance(c, TerminalNodeImpl) and (c.getSymbol().type == Parser.IF):
117
+ condition_node = self.visitExpr(ctx_list[1])
118
+ then_op_node = self.visitExpr(ctx_list[3])
119
+ else_op_node = self.visitExpr(ctx_list[5])
120
+
121
+ if_node = If(
122
+ condition=condition_node,
123
+ thenOp=then_op_node,
124
+ elseOp=else_op_node,
125
+ **extract_token_info(ctx),
126
+ )
127
+
128
+ return if_node
129
+
130
+ # CASE WHEN expr THEN expr ELSE expr END # caseExpr
131
+ elif isinstance(c, TerminalNodeImpl) and (c.getSymbol().type == Parser.CASE):
132
+ if len(ctx_list) % 4 != 3:
133
+ raise ValueError("Syntax error.")
134
+
135
+ else_node = self.visitExpr(ctx_list[-1])
136
+ ctx_list = ctx_list[1:-2]
137
+ cases = []
138
+
139
+ for i in range(0, len(ctx_list), 4):
140
+ condition = self.visitExpr(ctx_list[i + 1])
141
+ thenOp = self.visitExpr(ctx_list[i + 3])
142
+ case_obj = CaseObj(
143
+ condition=condition, thenOp=thenOp, **extract_token_info(ctx_list[i + 1])
144
+ )
145
+ cases.append(case_obj)
146
+
147
+ case_node = Case(cases=cases, elseOp=else_node, **extract_token_info(ctx))
148
+
149
+ return case_node
150
+
151
+ # constant
152
+ elif isinstance(ctx, Parser.ConstantExprContext):
153
+ return Terminals().visitConstant(c)
154
+
155
+ # varID
156
+ elif isinstance(ctx, Parser.VarIdExprContext):
157
+ return Terminals().visitVarIdExpr(c)
158
+
159
+ else:
160
+ # AST_ASTCONSTRUCTOR.3
161
+ raise NotImplementedError
162
+
163
+ def bin_op_creator(self, ctx: Parser.ExprContext):
164
+ ctx_list = list(ctx.getChildren())
165
+ left_node = self.visitExpr(ctx_list[0])
166
+ if isinstance(ctx_list[1], Parser.ComparisonOperandContext):
167
+ op = list(ctx_list[1].getChildren())[0].getSymbol().text
168
+ else:
169
+ op = ctx_list[1].getSymbol().text
170
+ right_node = self.visitExpr(ctx_list[2])
171
+ token_info = extract_token_info(ctx)
172
+ bin_op_node = BinOp(left=left_node, op=op, right=right_node, **token_info)
173
+
174
+ return bin_op_node
175
+
176
+ def visitArithmeticExpr(self, ctx: Parser.ArithmeticExprContext):
177
+ return self.bin_op_creator(ctx)
178
+
179
+ def visitArithmeticExprOrConcat(self, ctx: Parser.ArithmeticExprOrConcatContext):
180
+ return self.bin_op_creator(ctx)
181
+
182
+ def visitComparisonExpr(self, ctx: Parser.ComparisonExprContext):
183
+ return self.bin_op_creator(ctx)
184
+
185
+ def visitInNotInExpr(self, ctx: Parser.InNotInExprContext):
186
+ ctx_list = list(ctx.getChildren())
187
+ left_node = self.visitExpr(ctx_list[0])
188
+ op = ctx_list[1].symbol.text
189
+
190
+ if isinstance(ctx_list[2], Parser.ListsContext):
191
+ right_node = Terminals().visitLists(ctx_list[2])
192
+ elif isinstance(ctx_list[2], Parser.ValueDomainIDContext):
193
+ right_node = Terminals().visitValueDomainID(ctx_list[2])
194
+ else:
195
+ raise NotImplementedError
196
+ bin_op_node = BinOp(left=left_node, op=op, right=right_node, **extract_token_info(ctx))
197
+
198
+ return bin_op_node
199
+
200
+ def visitBooleanExpr(self, ctx: Parser.BooleanExprContext):
201
+ return self.bin_op_creator(ctx)
202
+
203
+ def visitParenthesisExpr(self, ctx: Parser.ParenthesisExprContext):
204
+ operand = self.visitExpr(list(ctx.getChildren())[1])
205
+ return ParFunction(operand=operand, **extract_token_info(ctx))
206
+
207
+ def visitUnaryExpr(self, ctx: Parser.UnaryExprContext):
208
+ c_list = list(ctx.getChildren())
209
+ op = c_list[0].getSymbol().text
210
+ right = self.visitExpr(c_list[1])
211
+
212
+ return UnaryOp(op=op, operand=right, **extract_token_info(ctx))
213
+
214
+ def visitMembershipExpr(self, ctx: Parser.MembershipExprContext):
215
+ ctx_list = list(ctx.getChildren())
216
+ c = ctx_list[0]
217
+ membership = [
218
+ componentID
219
+ for componentID in ctx_list
220
+ if isinstance(componentID, Parser.SimpleComponentIdContext)
221
+ ]
222
+
223
+ previous_node = self.visitExpr(c)
224
+
225
+ # It is only possible to put a membership at the end so go the last one.
226
+ if len(membership) != 0:
227
+ previous_node = BinOp(
228
+ left=previous_node,
229
+ op="#",
230
+ right=Terminals().visitSimpleComponentId(membership[0]),
231
+ **extract_token_info(ctx),
232
+ )
233
+
234
+ return previous_node
235
+
236
+ def visitClauseExpr(self, ctx: Parser.ClauseExprContext):
237
+ ctx_list = list(ctx.getChildren())
238
+
239
+ dataset = self.visitExpr(ctx_list[0])
240
+
241
+ dataset_clause = self.visitDatasetClause(ctx_list[2])
242
+
243
+ dataset_clause.dataset = dataset
244
+
245
+ return dataset_clause
246
+
247
+ """______________________________________________________________________________________
248
+
249
+
250
+ Functions Definition.
251
+
252
+ _______________________________________________________________________________________"""
253
+
254
+ def visitFunctionsExpression(self, ctx: Parser.FunctionsExpressionContext):
255
+ """
256
+ functions:
257
+ joinOperators # joinFunctions
258
+ | genericOperators # genericFunctions
259
+ | stringOperators # stringFunctions
260
+ | numericOperators # numericFunctions
261
+ | comparisonOperators # comparisonFunctions
262
+ | timeOperators # timeFunctions
263
+ | setOperators # setFunctions
264
+ | hierarchyOperators # hierarchyFunctions
265
+ | validationOperators # validationFunctions
266
+ | conditionalOperators # conditionalFunctions
267
+ | aggrOperatorsGrouping # aggregateFunctions
268
+ | anFunction # analyticFunctions
269
+ ;
270
+ """
271
+ c = ctx.children[0]
272
+
273
+ if isinstance(ctx, Parser.JoinFunctionsContext):
274
+ return self.visitJoinFunctions(c)
275
+
276
+ elif isinstance(ctx, Parser.GenericFunctionsContext):
277
+ return self.visitGenericFunctions(c)
278
+
279
+ elif isinstance(ctx, Parser.StringFunctionsContext):
280
+ return self.visitStringFunctions(c)
281
+
282
+ elif isinstance(ctx, Parser.NumericFunctionsContext):
283
+ return self.visitNumericFunctions(c)
284
+
285
+ elif isinstance(ctx, Parser.ComparisonFunctionsContext):
286
+ return self.visitComparisonFunctions(c)
287
+
288
+ elif isinstance(ctx, Parser.TimeFunctionsContext):
289
+ return self.visitTimeFunctions(c)
290
+
291
+ elif isinstance(ctx, Parser.SetFunctionsContext):
292
+ return self.visitSetFunctions(c)
293
+
294
+ elif isinstance(ctx, Parser.HierarchyFunctionsContext):
295
+ return self.visitHierarchyFunctions(c)
296
+
297
+ elif isinstance(ctx, Parser.ValidationFunctionsContext):
298
+ return self.visitValidationFunctions(c)
299
+
300
+ elif isinstance(ctx, Parser.ConditionalFunctionsContext):
301
+ return self.visitConditionalFunctions(c)
302
+
303
+ elif isinstance(ctx, Parser.AggregateFunctionsContext):
304
+ return self.visitAggregateFunctions(c)
305
+
306
+ elif isinstance(ctx, Parser.AnalyticFunctionsContext):
307
+ return self.visitAnalyticFunctions(c)
308
+
309
+ else:
310
+ raise NotImplementedError
311
+
312
+ """
313
+ -----------------------------------
314
+ Join Functions
315
+ -----------------------------------
316
+ """
317
+
318
+ def visitJoinFunctions(self, ctx: Parser.JoinFunctionsContext):
319
+ ctx_list = list(ctx.getChildren())
320
+
321
+ using_node = None
322
+
323
+ op_node = ctx_list[0].getSymbol().text
324
+
325
+ if op_node in ["inner_join", "left_join"]:
326
+ clause_node, using_node = self.visitJoinClause(ctx_list[2])
327
+ else:
328
+ clause_node = self.visitJoinClauseWithoutUsing(ctx_list[2])
329
+
330
+ body_node = self.visitJoinBody(ctx_list[3])
331
+
332
+ token_info = extract_token_info(ctx)
333
+
334
+ if len(body_node) != 0:
335
+ previous_node = JoinOp(op=op_node, clauses=clause_node, using=using_node, **token_info)
336
+ regular_aggregation = None
337
+ for body in body_node:
338
+ regular_aggregation = body
339
+ regular_aggregation.dataset = previous_node
340
+ previous_node = regular_aggregation
341
+
342
+ # set the last of the body clauses (ie dataclauses).
343
+ previous_node.isLast = True
344
+
345
+ return regular_aggregation
346
+
347
+ else:
348
+ join_node = JoinOp(op=op_node, clauses=clause_node, using=using_node, **token_info)
349
+ join_node.isLast = True
350
+ return join_node
351
+
352
+ def visitJoinClauseItem(self, ctx: Parser.JoinClauseItemContext):
353
+ ctx_list = list(ctx.getChildren())
354
+ left_node = self.visitExpr(ctx_list[0])
355
+ if len(ctx_list) == 1:
356
+ return left_node
357
+
358
+ token_info = extract_token_info(ctx)
359
+ intop_node = ctx_list[1].getSymbol().text
360
+ right_node = Identifier(
361
+ value=Terminals().visitAlias(ctx_list[2]),
362
+ kind="DatasetID",
363
+ **extract_token_info(ctx_list[1].getSymbol()),
364
+ )
365
+ return BinOp(left=left_node, op=intop_node, right=right_node, **token_info)
366
+
367
+ def visitJoinClause(self, ctx: Parser.JoinClauseContext):
368
+ """
369
+ JoinClauseItem (COMMA joinClauseItem)* (USING componentID (COMMA componentID)*)?
370
+ """
371
+ ctx_list = list(ctx.getChildren())
372
+
373
+ clause_nodes = []
374
+ component_nodes = []
375
+ using = None
376
+
377
+ items = [item for item in ctx_list if isinstance(item, Parser.JoinClauseItemContext)]
378
+ components = [
379
+ component for component in ctx_list if isinstance(component, Parser.ComponentIDContext)
380
+ ]
381
+
382
+ for item in items:
383
+ clause_nodes.append(self.visitJoinClauseItem(item))
384
+
385
+ if len(components) != 0:
386
+ for component in components:
387
+ component_nodes.append(Terminals().visitComponentID(component).value)
388
+ using = component_nodes
389
+
390
+ return clause_nodes, using
391
+
392
+ def visitJoinClauseWithoutUsing(self, ctx: Parser.JoinClauseWithoutUsingContext):
393
+ """
394
+ joinClause: joinClauseItem (COMMA joinClauseItem)* (USING componentID (COMMA componentID)*)? ;
395
+ """ # noqa E501
396
+ ctx_list = list(ctx.getChildren())
397
+
398
+ clause_nodes = []
399
+
400
+ items = [item for item in ctx_list if isinstance(item, Parser.JoinClauseItemContext)]
401
+
402
+ for item in items:
403
+ clause_nodes.append(self.visitJoinClauseItem(item))
404
+
405
+ return clause_nodes
406
+
407
+ def visitJoinBody(self, ctx: Parser.JoinBodyContext):
408
+ """
409
+ joinBody: filterClause? (calcClause|joinApplyClause|aggrClause)? (keepOrDropClause)? renameClause?
410
+ """ # noqa E501
411
+ ctx_list = list(ctx.getChildren())
412
+
413
+ body_nodes = []
414
+
415
+ for c in ctx_list:
416
+ if isinstance(c, Parser.FilterClauseContext):
417
+ body_nodes.append(self.visitFilterClause(c))
418
+ elif isinstance(c, Parser.CalcClauseContext):
419
+ body_nodes.append(self.visitCalcClause(c))
420
+ elif isinstance(c, Parser.JoinApplyClauseContext):
421
+ body_nodes.append(self.visitJoinApplyClause(c))
422
+ elif isinstance(c, Parser.AggrClauseContext):
423
+ body_nodes.append(self.visitAggrClause(c))
424
+ elif isinstance(c, Parser.KeepOrDropClauseContext):
425
+ body_nodes.append(self.visitKeepOrDropClause(c))
426
+ elif isinstance(c, Parser.RenameClauseContext):
427
+ body_nodes.append(self.visitRenameClause(c))
428
+ else:
429
+ raise NotImplementedError
430
+
431
+ return body_nodes
432
+
433
+ # TODO Unary Op here?
434
+ def visitJoinApplyClause(self, ctx: Parser.JoinApplyClauseContext):
435
+ """
436
+ joinApplyClause: APPLY expr ;
437
+ """
438
+ ctx_list = list(ctx.getChildren())
439
+ op_node = ctx_list[0].getSymbol().text
440
+ operand_nodes = [self.visitExpr(ctx_list[1])]
441
+
442
+ return RegularAggregation(op=op_node, children=operand_nodes, **extract_token_info(ctx))
443
+
444
+ """
445
+ -----------------------------------
446
+ Generic Functions
447
+ -----------------------------------
448
+ """
449
+
450
+ def visitGenericFunctions(self, ctx: Parser.GenericFunctionsContext):
451
+ if isinstance(ctx, Parser.CallDatasetContext):
452
+ return self.visitCallDataset(ctx)
453
+ elif isinstance(ctx, Parser.EvalAtomContext):
454
+ return self.visitEvalAtom(ctx)
455
+ elif isinstance(ctx, Parser.CastExprDatasetContext):
456
+ return self.visitCastExprDataset(ctx)
457
+ else:
458
+ raise NotImplementedError
459
+
460
+ def visitCallDataset(self, ctx: Parser.CallDatasetContext):
461
+ """
462
+ callFunction: operatorID LPAREN (parameter (COMMA parameter)*)? RPAREN ;
463
+ """
464
+ ctx_list = list(ctx.getChildren())
465
+ c = ctx_list[0]
466
+
467
+ op = Terminals().visitOperatorID(c)
468
+ param_nodes = [
469
+ self.visitParameter(element)
470
+ for element in ctx_list
471
+ if isinstance(element, Parser.ParameterContext)
472
+ ]
473
+
474
+ return UDOCall(op=op, params=param_nodes, **extract_token_info(ctx))
475
+
476
+ def visitEvalAtom(self, ctx: Parser.EvalAtomContext):
477
+ """
478
+ | EVAL LPAREN routineName LPAREN (varID|scalarItem)? (COMMA (varID|scalarItem))* RPAREN (LANGUAGE STRING_CONSTANT)? (RETURNS evalDatasetType)? RPAREN # evalAtom
479
+ """ # noqa E501
480
+ ctx_list = list(ctx.getChildren())
481
+
482
+ routine_name = Terminals().visitRoutineName(ctx_list[2])
483
+
484
+ # Think of a way to maintain the order, for now its not necessary.
485
+ var_ids_nodes = [
486
+ Terminals().visitVarID(varID)
487
+ for varID in ctx_list
488
+ if isinstance(varID, Parser.VarIDContext)
489
+ ]
490
+ constant_nodes = [
491
+ Terminals().visitScalarItem(scalar)
492
+ for scalar in ctx_list
493
+ if isinstance(scalar, Parser.ScalarItemContext)
494
+ ]
495
+ children_nodes = var_ids_nodes + constant_nodes
496
+
497
+ # Reference manual says it is mandatory.
498
+ language_name = [
499
+ language
500
+ for language in ctx_list
501
+ if isinstance(language, TerminalNodeImpl)
502
+ and language.getSymbol().type == Parser.STRING_CONSTANT
503
+ ]
504
+ if len(language_name) == 0:
505
+ # AST_ASTCONSTRUCTOR.12
506
+ raise SemanticError("1-3-2-1", option="language")
507
+ # Reference manual says it is mandatory.
508
+ output_node = [
509
+ Terminals().visitEvalDatasetType(output)
510
+ for output in ctx_list
511
+ if isinstance(output, Parser.EvalDatasetTypeContext)
512
+ ]
513
+ if len(output_node) == 0:
514
+ # AST_ASTCONSTRUCTOR.13
515
+ raise SemanticError("1-3-2-1", option="output")
516
+
517
+ return EvalOp(
518
+ name=routine_name,
519
+ operands=children_nodes,
520
+ output=output_node[0],
521
+ language=language_name[0].getSymbol().text,
522
+ **extract_token_info(ctx),
523
+ )
524
+
525
+ def visitCastExprDataset(self, ctx: Parser.CastExprDatasetContext):
526
+ """
527
+ | CAST LPAREN expr COMMA (basicScalarType|valueDomainName) (COMMA STRING_CONSTANT)? RPAREN # castExprDataset
528
+ """ # noqa E501
529
+ ctx_list = list(ctx.getChildren())
530
+ c = ctx_list[0]
531
+
532
+ token = c.getSymbol()
533
+
534
+ op = token.text
535
+ expr_node = [
536
+ self.visitExpr(expr) for expr in ctx_list if isinstance(expr, Parser.ExprContext)
537
+ ]
538
+ basic_scalar_type = [
539
+ Terminals().visitBasicScalarType(type_)
540
+ for type_ in ctx_list
541
+ if isinstance(type_, Parser.BasicScalarTypeContext)
542
+ ]
543
+
544
+ [
545
+ Terminals().visitValueDomainName(valueD)
546
+ for valueD in ctx_list
547
+ if isinstance(valueD, Parser.ValueDomainNameContext)
548
+ ]
549
+
550
+ if len(ctx_list) > 6:
551
+ param_node = [
552
+ ParamConstant(
553
+ type_="PARAM_CAST",
554
+ value=str_.symbol.text.strip('"'),
555
+ **extract_token_info(str_.getSymbol()),
556
+ )
557
+ for str_ in ctx_list
558
+ if isinstance(str_, TerminalNodeImpl)
559
+ and str_.getSymbol().type == Parser.STRING_CONSTANT
560
+ ]
561
+ else:
562
+ param_node = []
563
+
564
+ if len(basic_scalar_type) == 1:
565
+ children_nodes = expr_node + basic_scalar_type
566
+
567
+ return ParamOp(
568
+ op=op, children=children_nodes, params=param_node, **extract_token_info(ctx)
569
+ )
570
+
571
+ else:
572
+ # AST_ASTCONSTRUCTOR.14
573
+ raise NotImplementedError
574
+
575
+ def visitParameter(self, ctx: Parser.ParameterContext):
576
+ ctx_list = list(ctx.getChildren())
577
+ c = ctx_list[0]
578
+
579
+ if isinstance(c, Parser.ExprContext):
580
+ return self.visitExpr(c)
581
+ elif isinstance(c, TerminalNodeImpl):
582
+ return ID(
583
+ type_="OPTIONAL", value=c.getSymbol().text, **extract_token_info(c.getSymbol())
584
+ )
585
+ else:
586
+ raise NotImplementedError
587
+
588
+ """
589
+ -----------------------------------
590
+ String Functions
591
+ -----------------------------------
592
+ """
593
+
594
+ def visitStringFunctions(self, ctx: Parser.StringFunctionsContext):
595
+ if isinstance(ctx, Parser.UnaryStringFunctionContext):
596
+ return self.visitUnaryStringFunction(ctx)
597
+ elif isinstance(ctx, Parser.SubstrAtomContext):
598
+ return self.visitSubstrAtom(ctx)
599
+ elif isinstance(ctx, Parser.ReplaceAtomContext):
600
+ return self.visitReplaceAtom(ctx)
601
+ elif isinstance(ctx, Parser.InstrAtomContext):
602
+ return self.visitInstrAtom(ctx)
603
+ else:
604
+ raise NotImplementedError
605
+
606
+ def visitUnaryStringFunction(self, ctx: Parser.UnaryStringFunctionContext):
607
+ ctx_list = list(ctx.getChildren())
608
+ c = ctx_list[0]
609
+
610
+ token = c.getSymbol()
611
+ op_node = token.text
612
+ operand_node = self.visitExpr(ctx_list[2])
613
+ return UnaryOp(op=op_node, operand=operand_node, **extract_token_info(ctx))
614
+
615
+ def visitSubstrAtom(self, ctx: Parser.SubstrAtomContext):
616
+ ctx_list = list(ctx.getChildren())
617
+ c = ctx_list[0]
618
+
619
+ params_nodes = []
620
+ children_nodes = []
621
+
622
+ token = c.getSymbol()
623
+ childrens = [expr for expr in ctx_list if isinstance(expr, Parser.ExprContext)]
624
+ params = [param for param in ctx_list if isinstance(param, Parser.OptionalExprContext)]
625
+
626
+ op_node = token.text
627
+ for children in childrens:
628
+ children_nodes.append(self.visitExpr(children))
629
+
630
+ if len(params) != 0:
631
+ for param in params:
632
+ params_nodes.append(self.visitOptionalExpr(param))
633
+
634
+ return ParamOp(
635
+ op=op_node, children=children_nodes, params=params_nodes, **extract_token_info(ctx)
636
+ )
637
+
638
+ def visitReplaceAtom(self, ctx: Parser.ReplaceAtomContext):
639
+ ctx_list = list(ctx.getChildren())
640
+ c = ctx_list[0]
641
+
642
+ token = c.getSymbol()
643
+ expressions = [
644
+ self.visitExpr(expr) for expr in ctx_list if isinstance(expr, Parser.ExprContext)
645
+ ]
646
+ params = [
647
+ self.visitOptionalExpr(param)
648
+ for param in ctx_list
649
+ if isinstance(param, Parser.OptionalExprContext)
650
+ ]
651
+
652
+ op_node = token.text
653
+
654
+ children_nodes = [expressions[0]]
655
+ params_nodes = [expressions[1]] + params
656
+
657
+ return ParamOp(
658
+ op=op_node, children=children_nodes, params=params_nodes, **extract_token_info(ctx)
659
+ )
660
+
661
+ def visitInstrAtom(self, ctx: Parser.InstrAtomContext):
662
+ ctx_list = list(ctx.getChildren())
663
+ c = ctx_list[0]
664
+
665
+ token = c.getSymbol()
666
+ expressions = [
667
+ self.visitExpr(expr) for expr in ctx_list if isinstance(expr, Parser.ExprContext)
668
+ ]
669
+ params = [
670
+ self.visitOptionalExpr(param)
671
+ for param in ctx_list
672
+ if isinstance(param, Parser.OptionalExprContext)
673
+ ]
674
+
675
+ op_node = token.text
676
+
677
+ children_nodes = [expressions[0]]
678
+ params_nodes = [expressions[1]] + params
679
+
680
+ return ParamOp(
681
+ op=op_node, children=children_nodes, params=params_nodes, **extract_token_info(ctx)
682
+ )
683
+
684
+ """
685
+ -----------------------------------
686
+ Numeric Functions
687
+ -----------------------------------
688
+ """
689
+
690
+ def visitNumericFunctions(self, ctx: Parser.NumericFunctionsContext):
691
+ if isinstance(ctx, Parser.UnaryNumericContext):
692
+ return self.visitUnaryNumeric(ctx)
693
+ elif isinstance(ctx, Parser.UnaryWithOptionalNumericContext):
694
+ return self.visitUnaryWithOptionalNumeric(ctx)
695
+ elif isinstance(ctx, Parser.BinaryNumericContext):
696
+ return self.visitBinaryNumeric(ctx)
697
+ else:
698
+ raise NotImplementedError
699
+
700
+ def visitUnaryNumeric(self, ctx: Parser.UnaryNumericContext):
701
+ ctx_list = list(ctx.getChildren())
702
+ c = ctx_list[0]
703
+
704
+ token = c.getSymbol()
705
+ op_node = token.text
706
+ operand_node = self.visitExpr(ctx_list[2])
707
+ return UnaryOp(op=op_node, operand=operand_node, **extract_token_info(ctx))
708
+
709
+ def visitUnaryWithOptionalNumeric(self, ctx: Parser.UnaryWithOptionalNumericContext):
710
+ ctx_list = list(ctx.getChildren())
711
+ c = ctx_list[0]
712
+
713
+ params_nodes = []
714
+ children_nodes = []
715
+
716
+ token = c.getSymbol()
717
+ childrens = [expr for expr in ctx_list if isinstance(expr, Parser.ExprContext)]
718
+ params = [param for param in ctx_list if isinstance(param, Parser.OptionalExprContext)]
719
+
720
+ op_node = token.text
721
+ for children in childrens:
722
+ children_nodes.append(self.visitExpr(children))
723
+
724
+ if len(params) != 0:
725
+ for param in params:
726
+ params_nodes.append(self.visitOptionalExpr(param))
727
+
728
+ return ParamOp(
729
+ op=op_node, children=children_nodes, params=params_nodes, **extract_token_info(ctx)
730
+ )
731
+
732
+ def visitBinaryNumeric(self, ctx: Parser.BinaryNumericContext):
733
+ ctx_list = list(ctx.getChildren())
734
+ c = ctx_list[0]
735
+
736
+ token = c.getSymbol()
737
+
738
+ left_node = self.visitExpr(ctx_list[2])
739
+ op_node = token.text
740
+ right_node = self.visitExpr(ctx_list[4])
741
+ return BinOp(left=left_node, op=op_node, right=right_node, **extract_token_info(ctx))
742
+
743
+ """
744
+ -----------------------------------
745
+ Comparison Functions
746
+ -----------------------------------
747
+ """
748
+
749
+ def visitComparisonFunctions(self, ctx: Parser.ComparisonFunctionsContext):
750
+ if isinstance(ctx, Parser.BetweenAtomContext):
751
+ return self.visitBetweenAtom(ctx)
752
+ elif isinstance(ctx, Parser.CharsetMatchAtomContext):
753
+ return self.visitCharsetMatchAtom(ctx)
754
+ elif isinstance(ctx, Parser.IsNullAtomContext):
755
+ return self.visitIsNullAtom(ctx)
756
+ elif isinstance(ctx, Parser.ExistInAtomContext):
757
+ return self.visitExistInAtom(ctx)
758
+ else:
759
+ raise NotImplementedError
760
+
761
+ def visitBetweenAtom(self, ctx: Parser.BetweenAtomContext):
762
+ ctx_list = list(ctx.getChildren())
763
+ c = ctx_list[0]
764
+
765
+ children_nodes = []
766
+
767
+ token = c.getSymbol()
768
+ childrens = [expr for expr in ctx_list if isinstance(expr, Parser.ExprContext)]
769
+
770
+ op_node = token.text
771
+ for children in childrens:
772
+ children_nodes.append(self.visitExpr(children))
773
+
774
+ return MulOp(op=op_node, children=children_nodes, **extract_token_info(ctx))
775
+
776
+ def visitCharsetMatchAtom(self, ctx: Parser.CharsetMatchAtomContext):
777
+ ctx_list = list(ctx.getChildren())
778
+ c = ctx_list[0]
779
+ token = c.getSymbol()
780
+
781
+ left_node = self.visitExpr(ctx_list[2])
782
+ op_node = token.text
783
+ right_node = self.visitExpr(ctx_list[4])
784
+ return BinOp(left=left_node, op=op_node, right=right_node, **extract_token_info(ctx))
785
+
786
+ def visitIsNullAtom(self, ctx: Parser.IsNullAtomContext):
787
+ ctx_list = list(ctx.getChildren())
788
+ c = ctx_list[0]
789
+ token = c.getSymbol()
790
+ op_node = token.text
791
+ operand_node = self.visitExpr(ctx_list[2])
792
+ return UnaryOp(op=op_node, operand=operand_node, **extract_token_info(ctx))
793
+
794
+ def visitExistInAtom(self, ctx: Parser.ExistInAtomContext):
795
+ ctx_list = list(ctx.getChildren())
796
+ token = ctx_list[0].getSymbol()
797
+ op = token.text
798
+
799
+ operand_nodes = [
800
+ self.visitExpr(expr) for expr in ctx_list if isinstance(expr, Parser.ExprContext)
801
+ ]
802
+ retain_nodes = [
803
+ Terminals().visitRetainType(retain)
804
+ for retain in ctx_list
805
+ if isinstance(retain, Parser.RetainTypeContext)
806
+ ]
807
+
808
+ return MulOp(op=op, children=operand_nodes + retain_nodes, **extract_token_info(ctx))
809
+
810
+ """
811
+ -----------------------------------
812
+ Time Functions
813
+ -----------------------------------
814
+ """
815
+
816
+ def visitTimeFunctions(self, ctx: Parser.TimeFunctionsContext):
817
+ if isinstance(ctx, Parser.PeriodAtomContext):
818
+ # return self.visitPeriodAtom(ctx)
819
+ return self.visitTimeUnaryAtom(ctx)
820
+ elif isinstance(ctx, Parser.FillTimeAtomContext):
821
+ return self.visitFillTimeAtom(ctx)
822
+ elif isinstance(ctx, Parser.FlowAtomContext):
823
+ return self.visitFlowAtom(ctx)
824
+ elif isinstance(ctx, Parser.TimeShiftAtomContext):
825
+ return self.visitTimeShiftAtom(ctx)
826
+ elif isinstance(ctx, Parser.TimeAggAtomContext):
827
+ return self.visitTimeAggAtom(ctx)
828
+ elif isinstance(ctx, Parser.CurrentDateAtomContext):
829
+ return self.visitCurrentDateAtom(ctx)
830
+ elif isinstance(ctx, Parser.DateDiffAtomContext):
831
+ return self.visitTimeDiffAtom(ctx)
832
+ elif isinstance(ctx, Parser.DateAddAtomContext):
833
+ return self.visitTimeAddAtom(ctx)
834
+ elif isinstance(
835
+ ctx,
836
+ (
837
+ Parser.YearAtomContext,
838
+ Parser.MonthAtomContext,
839
+ Parser.DayOfMonthAtomContext,
840
+ Parser.DayOfYearAtomContext,
841
+ Parser.DayToYearAtomContext,
842
+ Parser.DayToMonthAtomContext,
843
+ Parser.YearToDayAtomContext,
844
+ Parser.MonthToDayAtomContext,
845
+ ),
846
+ ):
847
+ return self.visitTimeUnaryAtom(ctx)
848
+ else:
849
+ raise NotImplementedError
850
+
851
+ def visitTimeUnaryAtom(self, ctx: Any):
852
+ ctx_list = list(ctx.getChildren())
853
+ c = ctx_list[0]
854
+
855
+ op = c.getSymbol().text
856
+ operand_node = [
857
+ self.visitExpr(operand)
858
+ for operand in ctx_list
859
+ if isinstance(operand, Parser.ExprContext)
860
+ ]
861
+
862
+ if len(operand_node) == 0:
863
+ # AST_ASTCONSTRUCTOR.15
864
+ raise NotImplementedError
865
+
866
+ return UnaryOp(op=op, operand=operand_node[0], **extract_token_info(ctx))
867
+
868
+ def visitTimeShiftAtom(self, ctx: Parser.TimeShiftAtomContext):
869
+ """
870
+ timeShiftExpr: TIMESHIFT '(' expr ',' INTEGER_CONSTANT ')' ;
871
+ """
872
+ ctx_list = list(ctx.getChildren())
873
+ c = ctx_list[0]
874
+
875
+ op = c.getSymbol().text
876
+ left_node = self.visitExpr(ctx_list[2])
877
+ right_node = Constant(
878
+ type_="INTEGER_CONSTANT",
879
+ value=Terminals().visitSignedInteger(ctx_list[4]),
880
+ **extract_token_info(ctx_list[4]),
881
+ )
882
+
883
+ return BinOp(left=left_node, op=op, right=right_node, **extract_token_info(ctx))
884
+
885
+ def visitFillTimeAtom(self, ctx: Parser.FillTimeAtomContext):
886
+ """
887
+ timeSeriesExpr: FILL_TIME_SERIES '(' expr (',' (SINGLE|ALL))? ')' ;
888
+ """
889
+ ctx_list = list(ctx.getChildren())
890
+ c = ctx_list[0]
891
+
892
+ op = c.getSymbol().text
893
+ children_node = [self.visitExpr(ctx_list[2])]
894
+
895
+ if len(ctx_list) > 4:
896
+ param_constant_node = [
897
+ ParamConstant(
898
+ type_="PARAM_TIMESERIES",
899
+ value=ctx_list[4].getSymbol().text,
900
+ **extract_token_info(ctx_list[4].getSymbol()),
901
+ )
902
+ ]
903
+ else:
904
+ param_constant_node = []
905
+
906
+ return ParamOp(
907
+ op=op, children=children_node, params=param_constant_node, **extract_token_info(ctx)
908
+ )
909
+
910
+ def visitTimeAggAtom(self, ctx: Parser.TimeAggAtomContext):
911
+ """
912
+ TIME_AGG LPAREN periodIndTo=STRING_CONSTANT (COMMA periodIndFrom=(STRING_CONSTANT| OPTIONAL ))? (COMMA op=optionalExpr)? (COMMA (FIRST|LAST))? RPAREN # timeAggAtom
913
+ """ # noqa E501
914
+ ctx_list = list(ctx.getChildren())
915
+ c = ctx_list[0]
916
+
917
+ op = c.getSymbol().text
918
+ period_to = str(ctx.periodIndTo.text)[1:-1]
919
+ period_from = None
920
+
921
+ if ctx.periodIndFrom is not None and ctx.periodIndFrom.type != Parser.OPTIONAL:
922
+ period_from = str(ctx.periodIndFrom.text)[1:-1]
923
+
924
+ conf = [
925
+ str_.getSymbol().text
926
+ for str_ in ctx_list
927
+ if isinstance(str_, TerminalNodeImpl)
928
+ and str_.getSymbol().type in [Parser.FIRST, Parser.LAST]
929
+ ]
930
+
931
+ conf = None if len(conf) == 0 else conf[0]
932
+
933
+ if ctx.op is not None:
934
+ operand_node = self.visitOptionalExpr(ctx.op)
935
+ if isinstance(operand_node, ID):
936
+ operand_node = None
937
+ elif isinstance(operand_node, Identifier):
938
+ operand_node = VarID(value=operand_node.value, **extract_token_info(ctx))
939
+ else:
940
+ operand_node = None
941
+
942
+ if operand_node is None:
943
+ # AST_ASTCONSTRUCTOR.17
944
+ raise Exception("Optional as expression node is not allowed in Time Aggregation")
945
+ return TimeAggregation(
946
+ op=op,
947
+ operand=operand_node,
948
+ period_to=period_to,
949
+ period_from=period_from,
950
+ conf=conf,
951
+ **extract_token_info(ctx),
952
+ )
953
+
954
+ def visitFlowAtom(self, ctx: Parser.FlowAtomContext):
955
+ ctx_list = list(ctx.getChildren())
956
+
957
+ op_node = ctx_list[0].getSymbol().text
958
+ operand_node = self.visitExpr(ctx_list[2])
959
+ return UnaryOp(op=op_node, operand=operand_node, **extract_token_info(ctx))
960
+
961
+ def visitCurrentDateAtom(self, ctx: Parser.CurrentDateAtomContext):
962
+ c = list(ctx.getChildren())[0]
963
+ return MulOp(op=c.getSymbol().text, children=[], **extract_token_info(ctx))
964
+
965
+ def visitTimeDiffAtom(self, ctx: Parser.TimeShiftAtomContext):
966
+ """ """
967
+ ctx_list = list(ctx.getChildren())
968
+ c = ctx_list[0]
969
+
970
+ op = c.getSymbol().text
971
+ left_node = self.visitExpr(ctx_list[2])
972
+ right_node = self.visitExpr(ctx_list[4])
973
+
974
+ return BinOp(left=left_node, op=op, right=right_node, **extract_token_info(ctx))
975
+
976
+ def visitTimeAddAtom(self, ctx: Parser.TimeShiftAtomContext):
977
+ """ """
978
+
979
+ ctx_list = list(ctx.getChildren())
980
+ c = ctx_list[0]
981
+
982
+ op = c.getSymbol().text
983
+ children_node = [self.visitExpr(ctx_list[2])]
984
+
985
+ param_constant_node = []
986
+
987
+ if len(ctx_list) > 4:
988
+ param_constant_node = [self.visitExpr(ctx_list[4])]
989
+ if len(ctx_list) > 6:
990
+ param_constant_node.append(self.visitExpr(ctx_list[6]))
991
+
992
+ return ParamOp(
993
+ op=op, children=children_node, params=param_constant_node, **extract_token_info(ctx)
994
+ )
995
+
996
+ """
997
+ -----------------------------------
998
+ Conditional Functions
999
+ -----------------------------------
1000
+ """
1001
+
1002
+ def visitConditionalFunctions(self, ctx: Parser.ConditionalFunctionsContext):
1003
+ if isinstance(ctx, Parser.NvlAtomContext):
1004
+ return self.visitNvlAtom(ctx)
1005
+ else:
1006
+ raise NotImplementedError
1007
+
1008
+ def visitNvlAtom(self, ctx: Parser.NvlAtomContext):
1009
+ ctx_list = list(ctx.getChildren())
1010
+ c = ctx_list[0]
1011
+
1012
+ token = c.getSymbol()
1013
+
1014
+ left_node = self.visitExpr(ctx_list[2])
1015
+ op_node = token.text
1016
+ right_node = self.visitExpr(ctx_list[4])
1017
+ return BinOp(left=left_node, op=op_node, right=right_node, **extract_token_info(ctx))
1018
+
1019
+ """
1020
+ -----------------------------------
1021
+ Set Functions
1022
+ -----------------------------------
1023
+ """
1024
+
1025
+ def visitSetFunctions(self, ctx: Parser.SetFunctionsContext):
1026
+ """
1027
+ setExpr: UNION LPAREN left=expr (COMMA expr)+ RPAREN # unionAtom
1028
+ | INTERSECT LPAREN left=expr (COMMA expr)+ RPAREN # intersectAtom
1029
+ | op=(SETDIFF|SYMDIFF) LPAREN left=expr COMMA right=expr RPAREN # setOrSYmDiffAtom
1030
+ """ # noqa E501
1031
+ if isinstance(ctx, Parser.UnionAtomContext):
1032
+ return self.visitUnionAtom(ctx)
1033
+ elif isinstance(ctx, Parser.IntersectAtomContext):
1034
+ return self.visitIntersectAtom(ctx)
1035
+ elif isinstance(ctx, Parser.SetOrSYmDiffAtomContext):
1036
+ return self.visitSetOrSYmDiffAtom(ctx)
1037
+ else:
1038
+ raise NotImplementedError
1039
+
1040
+ def visitUnionAtom(self, ctx: Parser.UnionAtomContext):
1041
+ ctx_list = list(ctx.getChildren())
1042
+ exprs_nodes = [
1043
+ self.visitExpr(expr) for expr in ctx_list if isinstance(expr, Parser.ExprContext)
1044
+ ]
1045
+
1046
+ return MulOp(
1047
+ op=ctx_list[0].getSymbol().text, children=exprs_nodes, **extract_token_info(ctx)
1048
+ )
1049
+
1050
+ def visitIntersectAtom(self, ctx: Parser.IntersectAtomContext):
1051
+ ctx_list = list(ctx.getChildren())
1052
+ exprs_nodes = [
1053
+ self.visitExpr(expr) for expr in ctx_list if isinstance(expr, Parser.ExprContext)
1054
+ ]
1055
+
1056
+ return MulOp(
1057
+ op=ctx_list[0].getSymbol().text, children=exprs_nodes, **extract_token_info(ctx)
1058
+ )
1059
+
1060
+ def visitSetOrSYmDiffAtom(self, ctx: Parser.SetOrSYmDiffAtomContext):
1061
+ ctx_list = list(ctx.getChildren())
1062
+ exprs_nodes = [
1063
+ self.visitExpr(expr) for expr in ctx_list if isinstance(expr, Parser.ExprContext)
1064
+ ]
1065
+
1066
+ return MulOp(
1067
+ op=ctx_list[0].getSymbol().text, children=exprs_nodes, **extract_token_info(ctx)
1068
+ )
1069
+
1070
+ """
1071
+ -----------------------------------
1072
+ Hierarchy Functions
1073
+ -----------------------------------
1074
+ """
1075
+
1076
+ def visitHierarchyFunctions(self, ctx: Parser.HierarchyFunctionsContext):
1077
+ """
1078
+ HIERARCHY LPAREN op=expr COMMA hrName=IDENTIFIER (conditionClause)? (RULE ruleComponent=componentID)? (validationMode)? (inputModeHierarchy)? outputModeHierarchy? RPAREN
1079
+ """ # noqa E501
1080
+ ctx_list = list(ctx.getChildren())
1081
+ c = ctx_list[0]
1082
+
1083
+ op = c.getSymbol().text
1084
+ dataset_node = self.visitExpr(ctx_list[2])
1085
+ rule_name_node = Identifier(
1086
+ value=ctx_list[4].getSymbol().text,
1087
+ kind="RuleID",
1088
+ **extract_token_info(ctx_list[4].getSymbol()),
1089
+ )
1090
+
1091
+ conditions = []
1092
+ modes = "non_null"
1093
+ inputs = "rule"
1094
+ retains = "computed"
1095
+ rule_comp = None
1096
+
1097
+ for c in ctx_list:
1098
+ if isinstance(c, Parser.ConditionClauseContext):
1099
+ conditions.append(Terminals().visitConditionClause(c))
1100
+ elif isinstance(c, Parser.ComponentIDContext):
1101
+ rule_comp = Terminals().visitComponentID(c)
1102
+ elif isinstance(c, Parser.ValidationModeContext):
1103
+ modes = Terminals().visitValidationMode(c)
1104
+ elif isinstance(c, Parser.InputModeHierarchyContext):
1105
+ inputs = Terminals().visitInputModeHierarchy(c)
1106
+ elif isinstance(c, Parser.OutputModeHierarchyContext):
1107
+ retains = Terminals().visitOutputModeHierarchy(c)
1108
+
1109
+ if len(conditions) != 0:
1110
+ # AST_ASTCONSTRUCTOR.22
1111
+ conditions = conditions[0]
1112
+
1113
+ if inputs == DATASET_PRIORITY:
1114
+ raise NotImplementedError("Dataset Priority input mode on HR is not implemented")
1115
+ param_constant_node = []
1116
+
1117
+ param_constant_node.append(
1118
+ ParamConstant(type_="PARAM_MODE", value=modes, **extract_token_info(ctx))
1119
+ )
1120
+ param_constant_node.append(
1121
+ ParamConstant(type_="PARAM_INPUT", value=inputs, **extract_token_info(ctx))
1122
+ )
1123
+ param_constant_node.append(
1124
+ ParamConstant(type_="PARAM_OUTPUT", value=retains, **extract_token_info(ctx))
1125
+ )
1126
+
1127
+ if not rule_comp and rule_name_node.value in de_ruleset_elements:
1128
+ if isinstance(de_ruleset_elements[rule_name_node.value], list):
1129
+ rule_element = de_ruleset_elements[rule_name_node.value][-1]
1130
+ else:
1131
+ rule_element = de_ruleset_elements[rule_name_node.value]
1132
+ if rule_element.kind == "DatasetID":
1133
+ check_hierarchy_rule = rule_element.value
1134
+ rule_comp = Identifier(
1135
+ value=check_hierarchy_rule, kind="ComponentID", **extract_token_info(ctx)
1136
+ )
1137
+ else: # ValuedomainID
1138
+ raise SemanticError("1-1-10-4", op=op)
1139
+ children = [dataset_node, rule_comp, rule_name_node, *conditions]
1140
+ children = [node for node in children if node is not None]
1141
+ return ParamOp(
1142
+ op=op,
1143
+ children=children,
1144
+ params=param_constant_node,
1145
+ **extract_token_info(ctx),
1146
+ )
1147
+
1148
+ """
1149
+ -----------------------------------
1150
+ Validation Functions
1151
+ -----------------------------------
1152
+ """
1153
+
1154
+ def visitValidationFunctions(self, ctx: Parser.ValidationFunctionsContext):
1155
+ if isinstance(ctx, Parser.ValidateDPrulesetContext):
1156
+ return self.visitValidateDPruleset(ctx)
1157
+ elif isinstance(ctx, Parser.ValidateHRrulesetContext):
1158
+ return self.visitValidateHRruleset(ctx)
1159
+ elif isinstance(ctx, Parser.ValidationSimpleContext):
1160
+ return self.visitValidationSimple(ctx)
1161
+
1162
+ def visitValidateDPruleset(self, ctx: Parser.ValidateDPrulesetContext):
1163
+ """
1164
+ validationDatapoint: CHECK_DATAPOINT '(' expr ',' IDENTIFIER (COMPONENTS componentID (',' componentID)*)? (INVALID|ALL_MEASURES|ALL)? ')' ;
1165
+ """ # noqa E501
1166
+ ctx_list = list(ctx.getChildren())
1167
+ c = ctx_list[0]
1168
+
1169
+ op = c.getSymbol().text
1170
+
1171
+ operand_node = self.visitExpr(ctx_list[2])
1172
+ rule_name = ctx_list[4].getSymbol().text
1173
+
1174
+ components = [
1175
+ Terminals().visitComponentID(comp)
1176
+ for comp in ctx_list
1177
+ if isinstance(comp, Parser.ComponentIDContext)
1178
+ ]
1179
+ aux_components = []
1180
+ for x in components:
1181
+ if isinstance(x, BinOp):
1182
+ aux_components.append(x.right.value)
1183
+ else:
1184
+ aux_components.append(x.value)
1185
+
1186
+ components = aux_components
1187
+
1188
+ # Default value for output is invalid.
1189
+ output = "invalid"
1190
+
1191
+ if isinstance(ctx_list[-2], Parser.ValidationOutputContext):
1192
+ output = Terminals().visitValidationOutput(ctx_list[-2])
1193
+
1194
+ return ParamOp(
1195
+ op=op,
1196
+ children=[operand_node, rule_name, *components],
1197
+ params=[output],
1198
+ **extract_token_info(ctx),
1199
+ )
1200
+
1201
+ # TODO Not fully implemented only basic usage available.
1202
+ def visitValidateHRruleset(self, ctx: Parser.ValidateHRrulesetContext):
1203
+ """
1204
+ CHECK_HIERARCHY LPAREN op=expr COMMA hrName=IDENTIFIER conditionClause? (RULE componentID)? validationMode? inputMode? validationOutput? RPAREN # validateHRruleset
1205
+ """ # noqa E501
1206
+
1207
+ ctx_list = list(ctx.getChildren())
1208
+ c = ctx_list[0]
1209
+
1210
+ op = c.getSymbol().text
1211
+
1212
+ dataset_node = self.visitExpr(ctx_list[2])
1213
+ rule_name_node = Identifier(
1214
+ value=ctx_list[4].getSymbol().text,
1215
+ kind="RuleID",
1216
+ **extract_token_info(ctx_list[4].getSymbol()),
1217
+ )
1218
+
1219
+ conditions = []
1220
+ # Default values
1221
+ modes = "non_null"
1222
+ inputs = "dataset"
1223
+ retains = "invalid"
1224
+ rule_comp = None
1225
+
1226
+ for c in ctx_list:
1227
+ if isinstance(c, Parser.ConditionClauseContext):
1228
+ conditions.append(Terminals().visitConditionClause(c))
1229
+ elif isinstance(c, Parser.ComponentIDContext):
1230
+ rule_comp = Terminals().visitComponentID(c)
1231
+ elif isinstance(c, Parser.ValidationModeContext):
1232
+ modes = Terminals().visitValidationMode(c)
1233
+ elif isinstance(c, Parser.InputModeContext):
1234
+ inputs = Terminals().visitInputMode(c)
1235
+ elif isinstance(c, Parser.ValidationOutputContext):
1236
+ retains = Terminals().visitValidationOutput(c)
1237
+
1238
+ if len(conditions) != 0:
1239
+ # AST_ASTCONSTRUCTOR.22
1240
+ conditions = conditions[0]
1241
+
1242
+ param_constant_node = []
1243
+
1244
+ if inputs == DATASET_PRIORITY:
1245
+ raise NotImplementedError("Dataset Priority input mode on HR is not implemented")
1246
+
1247
+ param_constant_node.append(
1248
+ ParamConstant(type_="PARAM_MODE", value=modes, **extract_token_info(ctx))
1249
+ )
1250
+ param_constant_node.append(
1251
+ ParamConstant(type_="PARAM_INPUT", value=inputs, **extract_token_info(ctx))
1252
+ )
1253
+ param_constant_node.append(
1254
+ ParamConstant(type_="PARAM_OUTPUT", value=retains, **extract_token_info(ctx))
1255
+ )
1256
+
1257
+ if not rule_comp:
1258
+ rule_name = rule_name_node.value
1259
+ if rule_name in de_ruleset_elements:
1260
+ if isinstance(de_ruleset_elements[rule_name], list):
1261
+ rule_element = de_ruleset_elements[rule_name][-1]
1262
+ else:
1263
+ rule_element = de_ruleset_elements[rule_name]
1264
+
1265
+ if rule_element.kind == "DatasetID":
1266
+ check_hierarchy_rule = rule_element.value
1267
+ rule_comp = Identifier(
1268
+ value=check_hierarchy_rule,
1269
+ kind="ComponentID",
1270
+ **extract_token_info(ctx),
1271
+ )
1272
+ else: # ValuedomainID
1273
+ raise SemanticError("1-1-10-4", op=op)
1274
+ children = [dataset_node, rule_comp, rule_name_node, *conditions]
1275
+ children = [node for node in children if node is not None]
1276
+ return ParamOp(
1277
+ op=op,
1278
+ children=children,
1279
+ params=param_constant_node,
1280
+ **extract_token_info(ctx),
1281
+ )
1282
+
1283
+ def visitValidationSimple(self, ctx: Parser.ValidationSimpleContext):
1284
+ """
1285
+ | CHECK LPAREN op=expr (codeErr=erCode)? (levelCode=erLevel)? imbalanceExpr? output=(INVALID|ALL)? RPAREN # validationSimple
1286
+ """ # noqa E501
1287
+ ctx_list = list(ctx.getChildren())
1288
+ c = ctx_list[0]
1289
+ token = c.getSymbol()
1290
+
1291
+ validation_node = self.visitExpr(ctx_list[2])
1292
+
1293
+ inbalance_node = None
1294
+ error_code = None
1295
+ error_level = None
1296
+ for param in ctx_list:
1297
+ if isinstance(param, Parser.ErCodeContext):
1298
+ error_code = Terminals().visitErCode(param)
1299
+ elif isinstance(param, Parser.ErLevelContext):
1300
+ error_level = Terminals().visitErLevel(param)
1301
+ elif isinstance(param, Parser.ImbalanceExprContext):
1302
+ inbalance_node = self.visitImbalanceExpr(param)
1303
+
1304
+ invalid = ctx_list[-2] if isinstance(ctx_list[-2], TerminalNodeImpl) else None
1305
+ invalid_value = False if invalid is None else invalid.getSymbol().text == "invalid"
1306
+
1307
+ return Validation(
1308
+ op=token.text,
1309
+ validation=validation_node,
1310
+ error_code=error_code,
1311
+ error_level=error_level,
1312
+ imbalance=inbalance_node,
1313
+ invalid=invalid_value,
1314
+ **extract_token_info(ctx),
1315
+ )
1316
+
1317
+ def visitImbalanceExpr(self, ctx: Parser.ImbalanceExprContext):
1318
+ ctx_list = list(ctx.getChildren())
1319
+ return self.visitExpr(ctx_list[1])
1320
+
1321
+ """
1322
+ -----------------------------------
1323
+ Aggregate Functions
1324
+ -----------------------------------
1325
+ """
1326
+
1327
+ # TODO Count function count() without parameters. Used at least in aggregations at having.
1328
+ def visitAggregateFunctions(self, ctx: Parser.AggregateFunctionsContext):
1329
+ """
1330
+ aggrFunction: SUM '(' expr ')'
1331
+ | AVG '(' expr ')'
1332
+ | COUNT '(' expr? ')'
1333
+ | MEDIAN '(' expr ')'
1334
+ | MIN '(' expr ')'
1335
+ | MAX '(' expr ')'
1336
+ | RANK '(' expr ')'
1337
+ | STDDEV_POP '(' expr ')'
1338
+ | STDDEV_SAMP '(' expr ')'
1339
+ | VAR_POP '(' expr ')'
1340
+ | VAR_SAMP '(' expr ')'
1341
+ ;
1342
+ """
1343
+ if isinstance(ctx, Parser.AggrDatasetContext):
1344
+ return self.visitAggrDataset(ctx)
1345
+ else:
1346
+ raise NotImplementedError
1347
+
1348
+ def visitAggrDataset(self, ctx: Parser.AggrDatasetContext):
1349
+ ctx_list = list(ctx.getChildren())
1350
+ # c = ctx_list[0]
1351
+
1352
+ grouping_op = None
1353
+ group_node = None
1354
+ have_node = None
1355
+
1356
+ groups = [group for group in ctx_list if isinstance(group, Parser.GroupingClauseContext)]
1357
+ haves = [have for have in ctx_list if isinstance(have, Parser.HavingClauseContext)]
1358
+
1359
+ op_node = ctx_list[0].getSymbol().text
1360
+ operand = self.visitExpr(ctx_list[2])
1361
+
1362
+ if len(groups) != 0:
1363
+ grouping_op, group_node = self.visitGroupingClause(groups[0])
1364
+ if len(haves) != 0:
1365
+ have_node, expr = self.visitHavingClause(haves[0])
1366
+ have_node.expr = expr
1367
+
1368
+ return Aggregation(
1369
+ op=op_node,
1370
+ operand=operand,
1371
+ grouping_op=grouping_op,
1372
+ grouping=group_node,
1373
+ having_clause=have_node,
1374
+ **extract_token_info(ctx),
1375
+ )
1376
+
1377
+ """
1378
+ -----------------------------------
1379
+ Analytic Functions
1380
+ -----------------------------------
1381
+ """
1382
+
1383
+ def visitAnalyticFunctions(self, ctx: Parser.AnalyticFunctionsContext):
1384
+ # ctx_list = list(ctx.getChildren())
1385
+
1386
+ if isinstance(ctx, Parser.AnSimpleFunctionContext):
1387
+ return self.visitAnSimpleFunction(ctx)
1388
+ elif isinstance(ctx, Parser.LagOrLeadAnContext):
1389
+ return self.visitLagOrLeadAn(ctx)
1390
+ elif isinstance(ctx, Parser.RatioToReportAnContext):
1391
+ return self.visitRatioToReportAn(ctx)
1392
+ else:
1393
+ raise NotImplementedError
1394
+
1395
+ def visitAnSimpleFunction(self, ctx: Parser.AnSimpleFunctionContext):
1396
+ ctx_list = list(ctx.getChildren())
1397
+
1398
+ window = None
1399
+ partition_by = None
1400
+ order_by = None
1401
+
1402
+ op_node = ctx_list[0].getSymbol().text
1403
+ operand = self.visitExpr(ctx_list[2])
1404
+
1405
+ for c in ctx_list[5:-2]:
1406
+ if isinstance(c, Parser.PartitionByClauseContext):
1407
+ partition_by = Terminals().visitPartitionByClause(c)
1408
+ continue
1409
+ elif isinstance(c, Parser.OrderByClauseContext):
1410
+ order_by = Terminals().visitOrderByClause(c)
1411
+ continue
1412
+ elif isinstance(c, Parser.WindowingClauseContext):
1413
+ window = Terminals().visitWindowingClause(c)
1414
+ continue
1415
+ else:
1416
+ raise NotImplementedError
1417
+
1418
+ if window is None:
1419
+ window = Windowing(
1420
+ type_="data",
1421
+ start=-1,
1422
+ stop=0,
1423
+ start_mode="preceding",
1424
+ stop_mode="current",
1425
+ **extract_token_info(ctx),
1426
+ )
1427
+
1428
+ return Analytic(
1429
+ op=op_node,
1430
+ operand=operand,
1431
+ partition_by=partition_by,
1432
+ order_by=order_by,
1433
+ window=window,
1434
+ **extract_token_info(ctx),
1435
+ )
1436
+
1437
+ def visitLagOrLeadAn(self, ctx: Parser.LagOrLeadAnContext):
1438
+ ctx_list = list(ctx.getChildren())
1439
+
1440
+ params = None
1441
+ partition_by = None
1442
+ order_by = None
1443
+
1444
+ op_node = ctx_list[0].getSymbol().text
1445
+ operand = self.visitExpr(ctx_list[2])
1446
+
1447
+ for c in ctx_list[4:-2]:
1448
+ if isinstance(c, Parser.PartitionByClauseContext):
1449
+ partition_by = Terminals().visitPartitionByClause(c)
1450
+ continue
1451
+ elif isinstance(c, Parser.OrderByClauseContext):
1452
+ order_by = Terminals().visitOrderByClause(c)
1453
+ continue
1454
+ elif isinstance(c, (Parser.SignedIntegerContext, Parser.ScalarItemContext)):
1455
+ if params is None:
1456
+ params = []
1457
+ if isinstance(c, Parser.SignedIntegerContext):
1458
+ params.append(Terminals().visitSignedInteger(c))
1459
+ else:
1460
+ params.append(Terminals().visitScalarItem(c))
1461
+ continue
1462
+
1463
+ if len(params) == 0:
1464
+ # AST_ASTCONSTRUCTOR.16
1465
+ raise Exception(f"{op_node} requires an offset parameter.")
1466
+
1467
+ return Analytic(
1468
+ op=op_node,
1469
+ operand=operand,
1470
+ partition_by=partition_by,
1471
+ order_by=order_by,
1472
+ params=params,
1473
+ **extract_token_info(ctx),
1474
+ )
1475
+
1476
+ def visitRatioToReportAn(self, ctx: Parser.RatioToReportAnContext):
1477
+ ctx_list = list(ctx.getChildren())
1478
+
1479
+ # params = None
1480
+ order_by = None
1481
+
1482
+ op_node = ctx_list[0].getSymbol().text
1483
+ operand = self.visitExpr(ctx_list[2])
1484
+
1485
+ partition_by = Terminals().visitPartitionByClause(ctx_list[5])
1486
+
1487
+ return Analytic(
1488
+ op=op_node,
1489
+ operand=operand,
1490
+ partition_by=partition_by,
1491
+ order_by=order_by,
1492
+ **extract_token_info(ctx),
1493
+ )
1494
+
1495
+ """______________________________________________________________________________________
1496
+
1497
+
1498
+ Clause Definition.
1499
+
1500
+ _______________________________________________________________________________________"""
1501
+
1502
+ def visitDatasetClause(self, ctx: Parser.DatasetClauseContext):
1503
+ """
1504
+ datasetClause:
1505
+ renameClause
1506
+ | aggrClause
1507
+ | filterClause
1508
+ | calcClause
1509
+ | keepClause
1510
+ | dropClause
1511
+ | pivotExpr
1512
+ | unpivotExpr
1513
+ | subspaceExpr
1514
+ ;
1515
+ """
1516
+ ctx_list = list(ctx.getChildren())
1517
+ c = ctx_list[0]
1518
+
1519
+ # RENAME renameClause
1520
+ if isinstance(c, Parser.RenameClauseContext):
1521
+ return self.visitRenameClause(c)
1522
+
1523
+ # aggrClause
1524
+ elif isinstance(c, Parser.AggrClauseContext):
1525
+ return self.visitAggrClause(c)
1526
+
1527
+ # filterClause
1528
+ elif isinstance(c, Parser.FilterClauseContext):
1529
+ return self.visitFilterClause(c)
1530
+
1531
+ # calcClause
1532
+ elif isinstance(c, Parser.CalcClauseContext):
1533
+ return self.visitCalcClause(c)
1534
+
1535
+ # keepClause
1536
+ elif isinstance(c, Parser.KeepOrDropClauseContext):
1537
+ return self.visitKeepOrDropClause(c)
1538
+
1539
+ # pivotExpr
1540
+ elif isinstance(c, Parser.PivotOrUnpivotClauseContext):
1541
+ return self.visitPivotOrUnpivotClause(c)
1542
+
1543
+ # subspaceExpr
1544
+ elif isinstance(c, Parser.SubspaceClauseContext):
1545
+ return self.visitSubspaceClause(c)
1546
+
1547
+ """
1548
+ -----------------------------------
1549
+ Rename Clause
1550
+ -----------------------------------
1551
+ """
1552
+
1553
+ def visitRenameClause(self, ctx: Parser.RenameClauseContext):
1554
+ """
1555
+ renameClause: RENAME renameClauseItem (COMMA renameClauseItem)*;
1556
+ """
1557
+ ctx_list = list(ctx.getChildren())
1558
+
1559
+ renames = [
1560
+ ctx_child
1561
+ for ctx_child in ctx_list
1562
+ if isinstance(ctx_child, Parser.RenameClauseItemContext)
1563
+ ]
1564
+ rename_nodes = []
1565
+
1566
+ for ctx_rename in renames:
1567
+ rename_nodes.append(self.visitRenameClauseItem(ctx_rename))
1568
+
1569
+ return RegularAggregation(
1570
+ op=ctx_list[0].getSymbol().text, children=rename_nodes, **extract_token_info(ctx)
1571
+ )
1572
+
1573
+ def visitRenameClauseItem(self, ctx: Parser.RenameClauseItemContext):
1574
+ """
1575
+ renameClauseItem: fromName=componentID TO toName=componentID;
1576
+ """
1577
+ ctx_list = list(ctx.getChildren())
1578
+
1579
+ left_node = Terminals().visitComponentID(ctx_list[0])
1580
+ if isinstance(left_node, BinOp):
1581
+ left_node = f"{left_node.left.value}{left_node.op}{left_node.right.value}"
1582
+ else:
1583
+ left_node = left_node.value
1584
+
1585
+ right_node = Terminals().visitVarID(ctx_list[2]).value
1586
+
1587
+ return RenameNode(old_name=left_node, new_name=right_node, **extract_token_info(ctx))
1588
+
1589
+ """
1590
+ -----------------------------------
1591
+ Aggregate Clause
1592
+ -----------------------------------
1593
+ """
1594
+
1595
+ def visitAggregateClause(self, ctx: Parser.AggregateClauseContext):
1596
+ """
1597
+ aggregateClause: aggrFunctionClause (',' aggrFunctionClause)* ;
1598
+ """
1599
+ ctx_list = list(ctx.getChildren())
1600
+
1601
+ aggregates_nodes = []
1602
+
1603
+ aggregates = [
1604
+ aggregate
1605
+ for aggregate in ctx_list
1606
+ if isinstance(aggregate, Parser.AggrFunctionClauseContext)
1607
+ ]
1608
+
1609
+ for agg in aggregates:
1610
+ aggregates_nodes.append(self.visitAggrFunctionClause(agg))
1611
+
1612
+ return aggregates_nodes
1613
+
1614
+ def visitAggrFunctionClause(self, ctx: Parser.AggrFunctionClauseContext):
1615
+ """
1616
+ aggrFunctionClause: (componentRole)? componentID ':=' aggrFunction ;
1617
+ """
1618
+ ctx_list = list(ctx.getChildren())
1619
+ c = ctx_list[0]
1620
+
1621
+ if isinstance(c, Parser.ComponentRoleContext):
1622
+ role = Terminals().visitComponentRole(c)
1623
+ base_index = 1
1624
+ else:
1625
+ base_index = 0
1626
+ role = Role.MEASURE
1627
+
1628
+ left_node = Terminals().visitSimpleComponentId(ctx_list[base_index])
1629
+ op_node = ":="
1630
+ right_node = ExprComp().visitAggregateFunctionsComponents(ctx_list[base_index + 2])
1631
+ # Encoding the role information inside the Assignment for easiness and simplicity.
1632
+ # Cannot find another way with less lines of code
1633
+ left_node.role = role
1634
+
1635
+ return Assignment(left=left_node, op=op_node, right=right_node, **extract_token_info(ctx))
1636
+
1637
+ def visitAggrClause(self, ctx: Parser.AggrClauseContext):
1638
+ """
1639
+ aggrClause: AGGREGATE aggregateClause (groupingClause havingClause?)? ;
1640
+ """
1641
+ ctx_list = list(ctx.getChildren())
1642
+ c = ctx_list[0]
1643
+
1644
+ op_node = c.getSymbol().text
1645
+ group_node = None
1646
+ grouping_op = None
1647
+ have_node = None
1648
+
1649
+ groups = [group for group in ctx_list if isinstance(group, Parser.GroupingClauseContext)]
1650
+ haves = [have for have in ctx_list if isinstance(have, Parser.HavingClauseContext)]
1651
+
1652
+ aggregate_nodes = self.visitAggregateClause(ctx_list[1])
1653
+
1654
+ children = []
1655
+
1656
+ if len(groups) != 0:
1657
+ grouping_op, group_node = self.visitGroupingClause(groups[0])
1658
+ if len(haves) > 0:
1659
+ have_node, expr = self.visitHavingClause(haves[0])
1660
+ have_node.expr = expr
1661
+ for element in aggregate_nodes:
1662
+ element.right = Aggregation(
1663
+ op=element.right.op,
1664
+ operand=element.right.operand,
1665
+ grouping_op=grouping_op,
1666
+ grouping=group_node,
1667
+ having_clause=have_node,
1668
+ **extract_token_info(ctx_list[1]),
1669
+ )
1670
+ children.append(copy(element))
1671
+
1672
+ return RegularAggregation(op=op_node, children=children, **extract_token_info(ctx))
1673
+
1674
+ def visitGroupingClause(self, ctx: Parser.GroupingClauseContext):
1675
+ """
1676
+ groupingClause:
1677
+ GROUP op=(BY | EXCEPT) componentID (COMMA componentID)* # groupByOrExcept
1678
+ | GROUP ALL exprComponent # groupAll
1679
+ ;
1680
+ """
1681
+ if isinstance(ctx, Parser.GroupByOrExceptContext):
1682
+ return self.visitGroupByOrExcept(ctx)
1683
+ elif isinstance(ctx, Parser.GroupAllContext):
1684
+ return self.visitGroupAll(ctx)
1685
+ else:
1686
+ raise NotImplementedError
1687
+
1688
+ def visitHavingClause(self, ctx: Parser.HavingClauseContext):
1689
+ """
1690
+ havingClause: HAVING exprComponent ;
1691
+ """
1692
+ ctx_list = list(ctx.getChildren())
1693
+ op_node = ctx_list[0].getSymbol().text
1694
+
1695
+ text = ctx_list[1].start.source[1].strdata
1696
+ expr = re.split("having", text)[1]
1697
+ expr = "having " + expr[:-2].strip()
1698
+
1699
+ if "]" in expr:
1700
+ index = expr.index("]")
1701
+ expr = expr[:index]
1702
+ if "end" in expr:
1703
+ index = expr.index("end")
1704
+ expr = expr[:index]
1705
+ if expr.count(")") > expr.count("("):
1706
+ index = expr.rindex(")")
1707
+ expr = expr[:index]
1708
+
1709
+ if "{" in expr or "}" in expr:
1710
+ expr = expr.replace("{", "(")
1711
+ expr = expr.replace("}", ")")
1712
+ if "not_in" in expr:
1713
+ expr = expr.replace("not_in", "not in")
1714
+ if '"' in expr:
1715
+ expr = expr.replace('"', "'")
1716
+
1717
+ if isinstance(ctx_list[1], Parser.ComparisonExprCompContext):
1718
+ param_nodes = ExprComp().visitComparisonExprComp(ctx_list[1])
1719
+ elif isinstance(ctx_list[1], Parser.InNotInExprCompContext):
1720
+ param_nodes = ExprComp().visitInNotInExprComp(ctx_list[1])
1721
+ elif isinstance(ctx_list[1], Parser.BooleanExprCompContext):
1722
+ param_nodes = ExprComp().visitBooleanExprComp(ctx_list[1])
1723
+ else:
1724
+ raise NotImplementedError
1725
+
1726
+ return ParamOp(
1727
+ op=op_node, children=None, params=param_nodes, **extract_token_info(ctx)
1728
+ ), expr
1729
+
1730
+ def visitGroupByOrExcept(self, ctx: Parser.GroupByOrExceptContext):
1731
+ ctx_list = list(ctx.getChildren())
1732
+
1733
+ token_left = ctx_list[0].getSymbol().text
1734
+ token_right = ctx_list[1].getSymbol().text
1735
+
1736
+ op_node = token_left + " " + token_right
1737
+
1738
+ children_nodes = [
1739
+ Terminals().visitComponentID(identifier)
1740
+ for identifier in ctx_list
1741
+ if isinstance(identifier, Parser.ComponentIDContext)
1742
+ ]
1743
+
1744
+ return op_node, children_nodes
1745
+
1746
+ def visitGroupAll(self, ctx: Parser.GroupAllContext):
1747
+ ctx_list = list(ctx.getChildren())
1748
+
1749
+ token_left = ctx_list[0].getSymbol().text
1750
+ token_right = ctx_list[1].getSymbol().text
1751
+
1752
+ op_node = token_left + " " + token_right
1753
+
1754
+ children_nodes = [ExprComp().visitExprComponent(ctx_list[2])]
1755
+
1756
+ return op_node, children_nodes
1757
+
1758
+ """
1759
+ -----------------------------------
1760
+ Filter Clause
1761
+ -----------------------------------
1762
+ """
1763
+
1764
+ def visitFilterClause(self, ctx: Parser.FilterClauseContext):
1765
+ """
1766
+ filterClause: FILTER expr;
1767
+ """
1768
+ ctx_list = list(ctx.getChildren())
1769
+ c = ctx_list[0]
1770
+ token = c.getSymbol()
1771
+
1772
+ op_node = token.text
1773
+ operand_nodes = []
1774
+ operand_nodes.append(ExprComp().visitExprComponent(ctx_list[1]))
1775
+
1776
+ return RegularAggregation(op=op_node, children=operand_nodes, **extract_token_info(ctx))
1777
+
1778
+ """
1779
+ -----------------------------------
1780
+ Calc Clause
1781
+ -----------------------------------
1782
+ """
1783
+
1784
+ def visitCalcClause(self, ctx: Parser.CalcClauseContext):
1785
+ """
1786
+ calcClause: CALC calcClauseItem (',' calcClauseItem)*;
1787
+ """
1788
+ ctx_list = list(ctx.getChildren())
1789
+ c = ctx_list[0]
1790
+
1791
+ calcClauseItems = [
1792
+ calcClauseItem
1793
+ for calcClauseItem in ctx_list
1794
+ if isinstance(calcClauseItem, Parser.CalcClauseItemContext)
1795
+ ]
1796
+ calcClauseItems_nodes = []
1797
+
1798
+ op_node = c.getSymbol().text
1799
+ for calcClauseItem in calcClauseItems:
1800
+ result = self.visitCalcClauseItem(calcClauseItem)
1801
+ calcClauseItems_nodes.append(result)
1802
+
1803
+ return RegularAggregation(
1804
+ op=op_node, children=calcClauseItems_nodes, **extract_token_info(ctx)
1805
+ )
1806
+
1807
+ def visitCalcClauseItem(self, ctx: Parser.CalcClauseItemContext):
1808
+ """
1809
+ calcClauseItem: (componentRole)? componentID ASSIGN exprComponent;
1810
+ """
1811
+ ctx_list = list(ctx.getChildren())
1812
+ c = ctx_list[0]
1813
+
1814
+ if isinstance(c, Parser.ComponentRoleContext):
1815
+ role = Terminals().visitComponentRole(c)
1816
+
1817
+ left_node = Terminals().visitComponentID(ctx_list[1])
1818
+ op_node = ":="
1819
+ right_node = ExprComp().visitExprComponent(ctx_list[3])
1820
+ operand_node = Assignment(
1821
+ left=left_node, op=op_node, right=right_node, **extract_token_info(ctx)
1822
+ )
1823
+ if role is None:
1824
+ return UnaryOp(
1825
+ op=Role.MEASURE.value.lower(), operand=operand_node, **extract_token_info(c)
1826
+ )
1827
+ return UnaryOp(op=role.value.lower(), operand=operand_node, **extract_token_info(c))
1828
+ else:
1829
+ left_node = Terminals().visitSimpleComponentId(c)
1830
+ op_node = ":="
1831
+ right_node = ExprComp().visitExprComponent(ctx_list[2])
1832
+
1833
+ operand_node = Assignment(
1834
+ left=left_node, op=op_node, right=right_node, **extract_token_info(ctx)
1835
+ )
1836
+ return UnaryOp(
1837
+ op=Role.MEASURE.value.lower(), operand=operand_node, **extract_token_info(ctx)
1838
+ )
1839
+
1840
+ def visitKeepOrDropClause(self, ctx: Parser.KeepOrDropClauseContext):
1841
+ """
1842
+ keepOrDropClause: op = (KEEP | DROP) componentID (COMMA componentID)* ;
1843
+ """
1844
+
1845
+ ctx_list = list(ctx.getChildren())
1846
+ c = ctx_list[0]
1847
+
1848
+ items = [item for item in ctx_list if isinstance(item, Parser.ComponentIDContext)]
1849
+ nodes = []
1850
+
1851
+ op_node = c.getSymbol().text
1852
+ for item in items:
1853
+ nodes.append(Terminals().visitComponentID(item))
1854
+
1855
+ return RegularAggregation(op=op_node, children=nodes, **extract_token_info(ctx))
1856
+
1857
+ """
1858
+ -----------------------------------
1859
+ Pivot/Unpivot Clause
1860
+ -----------------------------------
1861
+ """
1862
+
1863
+ def visitPivotOrUnpivotClause(self, ctx: Parser.PivotOrUnpivotClauseContext):
1864
+ """
1865
+ pivotOrUnpivotClause: op=(PIVOT|UNPIVOT) id_=componentID COMMA mea=componentID ;
1866
+ """
1867
+ ctx_list = list(ctx.getChildren())
1868
+ c = ctx_list[0]
1869
+ token = c.getSymbol()
1870
+
1871
+ op_node = token.text
1872
+ children_nodes = []
1873
+ children_nodes.append(Terminals().visitComponentID(ctx_list[1]))
1874
+ children_nodes.append(Terminals().visitComponentID(ctx_list[3]))
1875
+
1876
+ return RegularAggregation(op=op_node, children=children_nodes, **extract_token_info(ctx))
1877
+
1878
+ """
1879
+ -----------------------------------
1880
+ Subspace Clause
1881
+ -----------------------------------
1882
+ """
1883
+
1884
+ def visitSubspaceClause(self, ctx: Parser.SubspaceClauseContext):
1885
+ """
1886
+ subspaceClause: SUBSPACE subspaceClauseItem (COMMA subspaceClauseItem)*;"""
1887
+ ctx_list = list(ctx.getChildren())
1888
+ c = ctx_list[0]
1889
+
1890
+ subspace_nodes = []
1891
+ subspaces = [
1892
+ subspace
1893
+ for subspace in ctx_list
1894
+ if isinstance(subspace, Parser.SubspaceClauseItemContext)
1895
+ ]
1896
+
1897
+ for subspace in subspaces:
1898
+ subspace_nodes.append(self.visitSubspaceClauseItem(subspace))
1899
+
1900
+ op_node = c.getSymbol().text
1901
+ return RegularAggregation(op=op_node, children=subspace_nodes, **extract_token_info(ctx))
1902
+
1903
+ def visitSubspaceClauseItem(self, ctx: Parser.SubspaceClauseItemContext):
1904
+ ctx_list = list(ctx.getChildren())
1905
+
1906
+ left_node = Terminals().visitVarID(ctx_list[0])
1907
+ op_node = ctx_list[1].getSymbol().text
1908
+ if isinstance(ctx_list[2], Parser.ScalarItemContext):
1909
+ right_node = Terminals().visitScalarItem(ctx_list[2])
1910
+ else:
1911
+ right_node = Terminals().visitVarID(ctx_list[2])
1912
+ return BinOp(left=left_node, op=op_node, right=right_node, **extract_token_info(ctx))
1913
+
1914
+ def visitOptionalExpr(self, ctx: Parser.OptionalExprContext):
1915
+ """
1916
+ optionalExpr: expr
1917
+ | OPTIONAL ;
1918
+ """
1919
+ ctx_list = list(ctx.getChildren())
1920
+ c = ctx_list[0]
1921
+
1922
+ if isinstance(c, Parser.ExprContext):
1923
+ return self.visitExpr(c)
1924
+
1925
+ elif isinstance(c, TerminalNodeImpl):
1926
+ token = c.getSymbol()
1927
+ opt = token.text
1928
+ return ID(type_="OPTIONAL", value=opt, **extract_token_info(ctx))