vtlengine 1.0.1__py3-none-any.whl → 1.0.3__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.

Potentially problematic release.


This version of vtlengine might be problematic. Click here for more details.

Files changed (50) hide show
  1. vtlengine/API/_InternalApi.py +19 -8
  2. vtlengine/API/__init__.py +9 -9
  3. vtlengine/AST/ASTConstructor.py +23 -43
  4. vtlengine/AST/ASTConstructorModules/Expr.py +147 -71
  5. vtlengine/AST/ASTConstructorModules/ExprComponents.py +104 -40
  6. vtlengine/AST/ASTConstructorModules/Terminals.py +28 -39
  7. vtlengine/AST/ASTTemplate.py +16 -1
  8. vtlengine/AST/DAG/__init__.py +12 -15
  9. vtlengine/AST/Grammar/Vtl.g4 +49 -20
  10. vtlengine/AST/Grammar/VtlTokens.g4 +13 -1
  11. vtlengine/AST/Grammar/lexer.py +1293 -1183
  12. vtlengine/AST/Grammar/parser.py +5758 -3939
  13. vtlengine/AST/Grammar/tokens.py +12 -0
  14. vtlengine/AST/VtlVisitor.py +9 -2
  15. vtlengine/AST/__init__.py +21 -3
  16. vtlengine/DataTypes/TimeHandling.py +12 -7
  17. vtlengine/DataTypes/__init__.py +17 -24
  18. vtlengine/Exceptions/__init__.py +43 -1
  19. vtlengine/Exceptions/messages.py +82 -62
  20. vtlengine/Interpreter/__init__.py +125 -120
  21. vtlengine/Model/__init__.py +17 -12
  22. vtlengine/Operators/Aggregation.py +14 -14
  23. vtlengine/Operators/Analytic.py +56 -31
  24. vtlengine/Operators/Assignment.py +2 -3
  25. vtlengine/Operators/Boolean.py +5 -7
  26. vtlengine/Operators/CastOperator.py +12 -13
  27. vtlengine/Operators/Clause.py +11 -13
  28. vtlengine/Operators/Comparison.py +31 -17
  29. vtlengine/Operators/Conditional.py +157 -17
  30. vtlengine/Operators/General.py +4 -4
  31. vtlengine/Operators/HROperators.py +41 -34
  32. vtlengine/Operators/Join.py +18 -22
  33. vtlengine/Operators/Numeric.py +76 -39
  34. vtlengine/Operators/RoleSetter.py +6 -8
  35. vtlengine/Operators/Set.py +7 -12
  36. vtlengine/Operators/String.py +19 -27
  37. vtlengine/Operators/Time.py +366 -43
  38. vtlengine/Operators/Validation.py +4 -7
  39. vtlengine/Operators/__init__.py +38 -41
  40. vtlengine/Utils/__init__.py +149 -94
  41. vtlengine/__init__.py +1 -1
  42. vtlengine/files/output/__init__.py +2 -2
  43. vtlengine/files/output/_time_period_representation.py +0 -1
  44. vtlengine/files/parser/__init__.py +18 -18
  45. vtlengine/files/parser/_time_checking.py +3 -2
  46. {vtlengine-1.0.1.dist-info → vtlengine-1.0.3.dist-info}/METADATA +17 -5
  47. vtlengine-1.0.3.dist-info/RECORD +58 -0
  48. vtlengine-1.0.1.dist-info/RECORD +0 -58
  49. {vtlengine-1.0.1.dist-info → vtlengine-1.0.3.dist-info}/LICENSE.md +0 -0
  50. {vtlengine-1.0.1.dist-info → vtlengine-1.0.3.dist-info}/WHEEL +0 -0
@@ -1,15 +1,24 @@
1
1
  import json
2
2
  import os
3
3
  from pathlib import Path
4
- from typing import Union, Optional, Dict, List, Any
4
+ from typing import Any, Dict, List, Optional, Union
5
5
 
6
6
  import pandas as pd
7
7
  from s3fs import S3FileSystem # type: ignore[import-untyped]
8
8
 
9
9
  from vtlengine.AST import PersistentAssignment, Start
10
10
  from vtlengine.DataTypes import SCALAR_TYPES
11
- from vtlengine.Model import ValueDomain, Dataset, Scalar, Component, Role, ExternalRoutine
12
- from vtlengine.files.parser import _validate_pandas, _fill_dataset_empty_data
11
+ from vtlengine.Exceptions import check_key
12
+ from vtlengine.files.parser import _fill_dataset_empty_data, _validate_pandas
13
+ from vtlengine.Model import (
14
+ Component,
15
+ Dataset,
16
+ ExternalRoutine,
17
+ Role,
18
+ Role_keys,
19
+ Scalar,
20
+ ValueDomain,
21
+ )
13
22
 
14
23
  base_path = Path(__file__).parent
15
24
  filepath_VTL = base_path / "data" / "vtl"
@@ -30,15 +39,17 @@ def _load_dataset_from_structure(structures: Dict[str, Any]) -> Dict[str, Any]:
30
39
  if "datasets" in structures:
31
40
  for dataset_json in structures["datasets"]:
32
41
  dataset_name = dataset_json["name"]
33
- components = {
34
- component["name"]: Component(
42
+ components = {}
43
+
44
+ for component in dataset_json["DataStructure"]:
45
+ check_key("data_type", SCALAR_TYPES.keys(), component["type"])
46
+ check_key("role", Role_keys, component["role"])
47
+ components[component["name"]] = Component(
35
48
  name=component["name"],
36
49
  data_type=SCALAR_TYPES[component["type"]],
37
50
  role=Role(component["role"]),
38
51
  nullable=component["nullable"],
39
52
  )
40
- for component in dataset_json["DataStructure"]
41
- }
42
53
 
43
54
  datasets[dataset_name] = Dataset(name=dataset_name, components=components, data=None)
44
55
  if "scalars" in structures:
@@ -208,7 +219,7 @@ def load_datasets_with_data(data_structures: Any, datapoints: Optional[Any] = No
208
219
  return datasets, None
209
220
  # Handling dictionary of paths
210
221
  dict_datapoints = _load_datapoints_path(datapoints)
211
- for dataset_name, file_path in dict_datapoints.items():
222
+ for dataset_name, _ in dict_datapoints.items():
212
223
  if dataset_name not in datasets:
213
224
  raise Exception(f"Not found dataset {dataset_name}")
214
225
 
vtlengine/API/__init__.py CHANGED
@@ -1,29 +1,29 @@
1
1
  from pathlib import Path
2
- from typing import Any, Union, List, Optional, Dict
2
+ from typing import Any, Dict, List, Optional, Union
3
3
 
4
4
  import pandas as pd
5
5
  from antlr4 import CommonTokenStream, InputStream # type: ignore[import-untyped]
6
6
  from antlr4.error.ErrorListener import ErrorListener # type: ignore[import-untyped]
7
7
 
8
8
  from vtlengine.API._InternalApi import (
9
- load_vtl,
9
+ _check_output_folder,
10
+ _return_only_persistent_datasets,
10
11
  load_datasets,
11
- load_value_domains,
12
- load_external_routines,
13
12
  load_datasets_with_data,
14
- _return_only_persistent_datasets,
15
- _check_output_folder,
13
+ load_external_routines,
14
+ load_value_domains,
15
+ load_vtl,
16
16
  )
17
17
  from vtlengine.AST import Start
18
18
  from vtlengine.AST.ASTConstructor import ASTVisitor
19
19
  from vtlengine.AST.DAG import DAGAnalyzer
20
20
  from vtlengine.AST.Grammar.lexer import Lexer
21
21
  from vtlengine.AST.Grammar.parser import Parser
22
- from vtlengine.Interpreter import InterpreterAnalyzer
23
22
  from vtlengine.files.output._time_period_representation import (
24
- format_time_period_external_representation,
25
23
  TimePeriodRepresentation,
24
+ format_time_period_external_representation,
26
25
  )
26
+ from vtlengine.Interpreter import InterpreterAnalyzer
27
27
 
28
28
  pd.options.mode.chained_assignment = None
29
29
 
@@ -78,7 +78,7 @@ def create_ast(text: str) -> Start:
78
78
  stream = _lexer(text)
79
79
  cst = _parser(stream)
80
80
  visitor = ASTVisitor()
81
- ast = visitor.visit(cst)
81
+ ast = visitor.visitStart(cst)
82
82
  DAGAnalyzer.createDAG(ast)
83
83
  return ast
84
84
 
@@ -10,18 +10,18 @@ Node Creator.
10
10
  from antlr4.tree.Tree import TerminalNodeImpl
11
11
 
12
12
  from vtlengine.AST import (
13
- Start,
14
- Assignment,
15
- PersistentAssignment,
16
- Operator,
17
13
  Argument,
14
+ Assignment,
15
+ DefIdentifier,
16
+ DPRule,
18
17
  DPRuleset,
19
18
  HRBinOp,
20
- DPRule,
21
- HRuleset,
22
- DefIdentifier,
23
19
  HRule,
20
+ HRuleset,
24
21
  HRUnOp,
22
+ Operator,
23
+ PersistentAssignment,
24
+ Start,
25
25
  )
26
26
  from vtlengine.AST.ASTConstructorModules.Expr import Expr
27
27
  from vtlengine.AST.ASTConstructorModules.ExprComponents import ExprComp
@@ -30,8 +30,7 @@ from vtlengine.AST.ASTDataExchange import de_ruleset_elements
30
30
  from vtlengine.AST.Grammar.parser import Parser
31
31
  from vtlengine.AST.VtlVisitor import VtlVisitor
32
32
  from vtlengine.Exceptions import SemanticError
33
- from vtlengine.Model import Scalar, Component, Dataset
34
-
33
+ from vtlengine.Model import Component, Dataset, Scalar
35
34
 
36
35
  # pylint: disable=unreachable,expression-not-assigned
37
36
  # pylint: disable=assignment-from-no-return
@@ -280,19 +279,13 @@ class ASTVisitor(VtlVisitor):
280
279
  for erCode_name in ctx_list
281
280
  if isinstance(erCode_name, Parser.ErCodeContext)
282
281
  ]
283
- if len(er_code) == 0:
284
- er_code = None
285
- else:
286
- er_code = er_code[0]
282
+ er_code = None if len(er_code) == 0 else er_code[0]
287
283
  er_level = [
288
284
  Terminals().visitErLevel(erLevel_name)
289
285
  for erLevel_name in ctx_list
290
286
  if isinstance(erLevel_name, Parser.ErLevelContext)
291
287
  ]
292
- if len(er_level) == 0:
293
- er_level = None
294
- else:
295
- er_level = er_level[0]
288
+ er_level = None if len(er_level) == 0 else er_level[0]
296
289
 
297
290
  return DPRule(name=rule_name, rule=rule_node, erCode=er_code, erLevel=er_level)
298
291
 
@@ -317,11 +310,7 @@ class ASTVisitor(VtlVisitor):
317
310
  for element in ctx_list
318
311
  if isinstance(element, Parser.ScalarItemContext)
319
312
  ]
320
-
321
- if len(argument_default) == 0:
322
- argument_default = None
323
- else:
324
- argument_default = argument_default[0]
313
+ argument_default = None if len(argument_default) == 0 else argument_default[0]
325
314
 
326
315
  if isinstance(argument_type, (Dataset, Component, Scalar)):
327
316
  argument_type.name = argument_name.value
@@ -375,10 +364,7 @@ class ASTVisitor(VtlVisitor):
375
364
  if isinstance(valueDomain, TerminalNodeImpl)
376
365
  and valueDomain.getSymbol().type == Parser.VALUE_DOMAIN
377
366
  ]
378
- if len(value_domain) != 0:
379
- kind = "ValuedomainID"
380
- else:
381
- kind = "DatasetID"
367
+ kind = "ValuedomainID" if len(value_domain) != 0 else "DatasetID"
382
368
 
383
369
  conditions = [
384
370
  self.visitValueDomainSignature(vtlsig)
@@ -408,8 +394,8 @@ class ASTVisitor(VtlVisitor):
408
394
  # TODO Support for valueDomainSignature.
409
395
  def visitValueDomainSignature(self, ctx: Parser.ValueDomainSignatureContext):
410
396
  """
411
- valueDomainSignature: CONDITION IDENTIFIER (AS IDENTIFIER)? (',' IDENTIFIER (AS IDENTIFIER)?)* ; # noqa E501
412
- """
397
+ valueDomainSignature: CONDITION IDENTIFIER (AS IDENTIFIER)? (',' IDENTIFIER (AS IDENTIFIER)?)* ;
398
+ """ # noqa E501
413
399
  # AST_ASTCONSTRUCTOR.7
414
400
  ctx_list = list(ctx.getChildren())
415
401
  component_nodes = [
@@ -458,28 +444,22 @@ class ASTVisitor(VtlVisitor):
458
444
  for erCode_name in ctx_list
459
445
  if isinstance(erCode_name, Parser.ErCodeContext)
460
446
  ]
461
- if len(er_code) == 0:
462
- er_code = None
463
- else:
464
- er_code = er_code[0]
447
+ er_code = None if len(er_code) == 0 else er_code[0]
465
448
  er_level = [
466
449
  Terminals().visitErLevel(erLevel_name)
467
450
  for erLevel_name in ctx_list
468
451
  if isinstance(erLevel_name, Parser.ErLevelContext)
469
452
  ]
470
- if len(er_level) == 0:
471
- er_level = None
472
- else:
473
- er_level = er_level[0]
453
+ er_level = None if len(er_level) == 0 else er_level[0]
474
454
 
475
455
  return HRule(name=rule_name, rule=rule_node, erCode=er_code, erLevel=er_level)
476
456
 
477
457
  def visitCodeItemRelation(self, ctx: Parser.CodeItemRelationContext):
478
458
  """
479
- codeItemRelation: ( WHEN expr THEN )? codeItemRef codeItemRelationClause (codeItemRelationClause)* ; # noqa E501
480
- ( WHEN exprComponent THEN )? codetemRef=valueDomainValue comparisonOperand? codeItemRelationClause (codeItemRelationClause)* # noqa E501
459
+ codeItemRelation: ( WHEN expr THEN )? codeItemRef codeItemRelationClause (codeItemRelationClause)* ;
460
+ ( WHEN exprComponent THEN )? codetemRef=valueDomainValue comparisonOperand? codeItemRelationClause (codeItemRelationClause)*
481
461
 
482
- """
462
+ """ # noqa E501
483
463
 
484
464
  ctx_list = list(ctx.getChildren())
485
465
 
@@ -531,8 +511,8 @@ class ASTVisitor(VtlVisitor):
531
511
 
532
512
  def visitCodeItemRelationClause(self, ctx: Parser.CodeItemRelationClauseContext):
533
513
  """
534
- (opAdd=( PLUS | MINUS ))? rightCodeItem=valueDomainValue ( QLPAREN rightCondition=exprComponent QRPAREN )? # noqa E501
535
- """
514
+ (opAdd=( PLUS | MINUS ))? rightCodeItem=valueDomainValue ( QLPAREN rightCondition=exprComponent QRPAREN )?
515
+ """ # noqa E501
536
516
  ctx_list = list(ctx.getChildren())
537
517
 
538
518
  expr = [expr for expr in ctx_list if isinstance(expr, Parser.ExprContext)]
@@ -552,13 +532,13 @@ class ASTVisitor(VtlVisitor):
552
532
 
553
533
  code_item = DefIdentifier(value=value, kind="CodeItemID")
554
534
  if right_condition:
555
- setattr(code_item, "_right_condition", right_condition[0])
535
+ code_item._right_condition = right_condition[0]
556
536
 
557
537
  return HRBinOp(left=None, op=op, right=code_item)
558
538
  else:
559
539
  value = Terminals().visitValueDomainValue(ctx_list[0])
560
540
  code_item = DefIdentifier(value=value, kind="CodeItemID")
561
541
  if right_condition:
562
- setattr(code_item, "_right_condition", right_condition[0])
542
+ code_item._right_condition = right_condition[0]
563
543
 
564
544
  return code_item
@@ -1,30 +1,33 @@
1
1
  import re
2
2
  from copy import copy
3
+ from typing import Any
3
4
 
4
5
  from antlr4.tree.Tree import TerminalNodeImpl
5
6
 
6
7
  from vtlengine.AST import (
7
- If,
8
+ ID,
9
+ Aggregation,
10
+ Analytic,
11
+ Assignment,
8
12
  BinOp,
9
- RenameNode,
10
- UDOCall,
11
- UnaryOp,
12
- JoinOp,
13
- Identifier,
14
- ParamOp,
13
+ Case,
14
+ CaseObj,
15
+ Constant,
15
16
  EvalOp,
16
- ParamConstant,
17
+ Identifier,
18
+ If,
19
+ JoinOp,
17
20
  MulOp,
21
+ ParamConstant,
22
+ ParamOp,
18
23
  RegularAggregation,
19
- Assignment,
20
- Aggregation,
21
- ID,
24
+ RenameNode,
22
25
  TimeAggregation,
23
- Constant,
26
+ UDOCall,
27
+ UnaryOp,
24
28
  Validation,
25
- Analytic,
26
- Windowing,
27
29
  VarID,
30
+ Windowing,
28
31
  )
29
32
  from vtlengine.AST.ASTConstructorModules.ExprComponents import ExprComp
30
33
  from vtlengine.AST.ASTConstructorModules.Terminals import Terminals
@@ -47,22 +50,23 @@ class Expr(VtlVisitor):
47
50
  def visitExpr(self, ctx: Parser.ExprContext):
48
51
  """
49
52
  expr:
50
- LPAREN expr RPAREN # parenthesisExpr # noqa E501
51
- | functions # functionsExpression # noqa E501
52
- | dataset=expr QLPAREN clause=datasetClause QRPAREN # clauseExpr # noqa E501
53
- | expr MEMBERSHIP simpleComponentId # membershipExpr # noqa E501
54
- | op=(PLUS|MINUS|NOT) right=expr # unaryExpr # noqa E501
55
- | left=expr op=(MUL|DIV) right=expr # arithmeticExpr # noqa E501
56
- | left=expr op=(PLUS|MINUS|CONCAT) right=expr # arithmeticExprOrConcat # noqa E501
57
- | left=expr op=comparisonOperand right=expr # comparisonExpr # noqa E501
58
- | left=expr op=(IN|NOT_IN)(lists|valueDomainID) # inNotInExpr # noqa E501
59
- | left=expr op=AND right=expr # booleanExpr # noqa E501
60
- | left=expr op=(OR|XOR) right=expr # booleanExpr # noqa E501
61
- | IF conditionalExpr=expr THEN thenExpr=expr ELSE elseExpr=expr # ifExpr # noqa E501
62
- | constant # constantExpr # noqa E501
63
- | varID # varIdExpr # noqa E501
53
+ LPAREN expr RPAREN # parenthesisExpr
54
+ | functions # functionsExpression
55
+ | dataset=expr QLPAREN clause=datasetClause QRPAREN # clauseExpr
56
+ | expr MEMBERSHIP simpleComponentId # membershipExpr
57
+ | op=(PLUS|MINUS|NOT) right=expr # unaryExpr
58
+ | left=expr op=(MUL|DIV) right=expr # arithmeticExpr
59
+ | left=expr op=(PLUS|MINUS|CONCAT) right=expr # arithmeticExprOrConcat
60
+ | left=expr op=comparisonOperand right=expr # comparisonExpr
61
+ | left=expr op=(IN|NOT_IN)(lists|valueDomainID) # inNotInExpr
62
+ | left=expr op=AND right=expr # booleanExpr
63
+ | left=expr op=(OR|XOR) right=expr # booleanExpr
64
+ | IF conditionalExpr=expr THEN thenExpr=expr ELSE elseExpr=expr # ifExpr
65
+ | CASE WHEN expr THEN expr ELSE expr END # caseExpr
66
+ | constant # constantExpr
67
+ | varID # varIdExpr
64
68
  ;
65
- """
69
+ """ # noqa E501
66
70
  ctx_list = list(ctx.getChildren())
67
71
  c = ctx_list[0]
68
72
 
@@ -115,6 +119,26 @@ class Expr(VtlVisitor):
115
119
 
116
120
  return if_node
117
121
 
122
+ # CASE WHEN expr THEN expr ELSE expr END # caseExpr
123
+ elif isinstance(c, TerminalNodeImpl) and (c.getSymbol().type == Parser.CASE):
124
+
125
+ if len(ctx_list) % 4 != 3:
126
+ raise ValueError("Syntax error.")
127
+
128
+ else_node = self.visitExpr(ctx_list[-1])
129
+ ctx_list = ctx_list[1:-2]
130
+ cases = []
131
+
132
+ for i in range(0, len(ctx_list), 4):
133
+ condition = self.visitExpr(ctx_list[i + 1])
134
+ thenOp = self.visitExpr(ctx_list[i + 3])
135
+ case_obj = CaseObj(condition, thenOp)
136
+ cases.append(case_obj)
137
+
138
+ case_node = Case(cases, else_node)
139
+
140
+ return case_node
141
+
118
142
  # constant
119
143
  elif isinstance(ctx, Parser.ConstantExprContext):
120
144
  return Terminals().visitConstant(c)
@@ -348,8 +372,8 @@ class Expr(VtlVisitor):
348
372
 
349
373
  def visitJoinClauseWithoutUsing(self, ctx: Parser.JoinClauseWithoutUsingContext):
350
374
  """
351
- joinClause: joinClauseItem (COMMA joinClauseItem)* (USING componentID (COMMA componentID)*)? ; # noqa E501
352
- """
375
+ joinClause: joinClauseItem (COMMA joinClauseItem)* (USING componentID (COMMA componentID)*)? ;
376
+ """ # noqa E501
353
377
  ctx_list = list(ctx.getChildren())
354
378
 
355
379
  clause_nodes = []
@@ -363,8 +387,8 @@ class Expr(VtlVisitor):
363
387
 
364
388
  def visitJoinBody(self, ctx: Parser.JoinBodyContext):
365
389
  """
366
- joinBody: filterClause? (calcClause|joinApplyClause|aggrClause)? (keepOrDropClause)? renameClause? # noqa E501
367
- """
390
+ joinBody: filterClause? (calcClause|joinApplyClause|aggrClause)? (keepOrDropClause)? renameClause?
391
+ """ # noqa E501
368
392
  ctx_list = list(ctx.getChildren())
369
393
 
370
394
  body_nodes = []
@@ -432,8 +456,8 @@ class Expr(VtlVisitor):
432
456
 
433
457
  def visitEvalAtom(self, ctx: Parser.EvalAtomContext):
434
458
  """
435
- | EVAL LPAREN routineName LPAREN (varID|scalarItem)? (COMMA (varID|scalarItem))* RPAREN (LANGUAGE STRING_CONSTANT)? (RETURNS evalDatasetType)? RPAREN # noqa E501 # evalAtom
436
- """
459
+ | EVAL LPAREN routineName LPAREN (varID|scalarItem)? (COMMA (varID|scalarItem))* RPAREN (LANGUAGE STRING_CONSTANT)? (RETURNS evalDatasetType)? RPAREN # evalAtom
460
+ """ # noqa E501
437
461
  ctx_list = list(ctx.getChildren())
438
462
 
439
463
  routine_name = Terminals().visitRoutineName(ctx_list[2])
@@ -480,8 +504,8 @@ class Expr(VtlVisitor):
480
504
 
481
505
  def visitCastExprDataset(self, ctx: Parser.CastExprDatasetContext):
482
506
  """
483
- | CAST LPAREN expr COMMA (basicScalarType|valueDomainName) (COMMA STRING_CONSTANT)? RPAREN # noqa E501 # castExprDataset
484
- """
507
+ | CAST LPAREN expr COMMA (basicScalarType|valueDomainName) (COMMA STRING_CONSTANT)? RPAREN # castExprDataset
508
+ """ # noqa E501
485
509
  ctx_list = list(ctx.getChildren())
486
510
  c = ctx_list[0]
487
511
 
@@ -755,7 +779,8 @@ class Expr(VtlVisitor):
755
779
 
756
780
  def visitTimeFunctions(self, ctx: Parser.TimeFunctionsContext):
757
781
  if isinstance(ctx, Parser.PeriodAtomContext):
758
- return self.visitPeriodAtom(ctx)
782
+ # return self.visitPeriodAtom(ctx)
783
+ return self.visitTimeUnaryAtom(ctx)
759
784
  elif isinstance(ctx, Parser.FillTimeAtomContext):
760
785
  return self.visitFillTimeAtom(ctx)
761
786
  elif isinstance(ctx, Parser.FlowAtomContext):
@@ -766,13 +791,24 @@ class Expr(VtlVisitor):
766
791
  return self.visitTimeAggAtom(ctx)
767
792
  elif isinstance(ctx, Parser.CurrentDateAtomContext):
768
793
  return self.visitCurrentDateAtom(ctx)
794
+ elif isinstance(ctx, Parser.DateDiffAtomContext):
795
+ return self.visitTimeDiffAtom(ctx)
796
+ elif isinstance(ctx, Parser.DateAddAtomContext):
797
+ return self.visitTimeAddAtom(ctx)
798
+ elif isinstance(ctx, (Parser.YearAtomContext,
799
+ Parser.MonthAtomContext,
800
+ Parser.DayOfMonthAtomContext,
801
+ Parser.DayOfYearAtomContext,
802
+ Parser.DayToYearAtomContext,
803
+ Parser.DayToMonthAtomContext,
804
+ Parser.YearTodayAtomContext,
805
+ Parser.MonthTodayAtomContext)):
806
+
807
+ return self.visitTimeUnaryAtom(ctx)
769
808
  else:
770
809
  raise NotImplementedError
771
810
 
772
- def visitPeriodAtom(self, ctx: Parser.PeriodAtomContext):
773
- """
774
- periodExpr: PERIOD_INDICATOR '(' expr? ')' ;
775
- """
811
+ def visitTimeUnaryAtom(self, ctx: Any):
776
812
  ctx_list = list(ctx.getChildren())
777
813
  c = ctx_list[0]
778
814
 
@@ -789,6 +825,26 @@ class Expr(VtlVisitor):
789
825
 
790
826
  return UnaryOp(op=op, operand=operand_node[0])
791
827
 
828
+ # def visitPeriodAtom(self, ctx: Parser.PeriodAtomContext):
829
+ # """
830
+ # periodExpr: PERIOD_INDICATOR '(' expr? ')' ;
831
+ # """
832
+ # ctx_list = list(ctx.getChildren())
833
+ # c = ctx_list[0]
834
+ #
835
+ # op = c.getSymbol().text
836
+ # operand_node = [
837
+ # self.visitExpr(operand)
838
+ # for operand in ctx_list
839
+ # if isinstance(operand, Parser.ExprContext)
840
+ # ]
841
+ #
842
+ # if len(operand_node) == 0:
843
+ # # AST_ASTCONSTRUCTOR.15
844
+ # raise NotImplementedError
845
+ #
846
+ # return UnaryOp(op=op, operand=operand_node[0])
847
+
792
848
  def visitTimeShiftAtom(self, ctx: Parser.TimeShiftAtomContext):
793
849
  """
794
850
  timeShiftExpr: TIMESHIFT '(' expr ',' INTEGER_CONSTANT ')' ;
@@ -821,8 +877,8 @@ class Expr(VtlVisitor):
821
877
 
822
878
  def visitTimeAggAtom(self, ctx: Parser.TimeAggAtomContext):
823
879
  """
824
- TIME_AGG LPAREN periodIndTo=STRING_CONSTANT (COMMA periodIndFrom=(STRING_CONSTANT| OPTIONAL ))? (COMMA op=optionalExpr)? (COMMA (FIRST|LAST))? RPAREN # timeAggAtom # noqa E501
825
- """
880
+ TIME_AGG LPAREN periodIndTo=STRING_CONSTANT (COMMA periodIndFrom=(STRING_CONSTANT| OPTIONAL ))? (COMMA op=optionalExpr)? (COMMA (FIRST|LAST))? RPAREN # timeAggAtom
881
+ """ # noqa E501
826
882
  ctx_list = list(ctx.getChildren())
827
883
  c = ctx_list[0]
828
884
 
@@ -840,10 +896,7 @@ class Expr(VtlVisitor):
840
896
  and str_.getSymbol().type in [Parser.FIRST, Parser.LAST]
841
897
  ]
842
898
 
843
- if len(conf) == 0:
844
- conf = None
845
- else:
846
- conf = conf[0]
899
+ conf = None if len(conf) == 0 else conf[0]
847
900
 
848
901
  if ctx.op is not None:
849
902
  operand_node = self.visitOptionalExpr(ctx.op)
@@ -872,6 +925,35 @@ class Expr(VtlVisitor):
872
925
  c = list(ctx.getChildren())[0]
873
926
  return MulOp(op=c.getSymbol().text, children=[])
874
927
 
928
+ def visitTimeDiffAtom(self, ctx: Parser.TimeShiftAtomContext):
929
+ """ """
930
+ ctx_list = list(ctx.getChildren())
931
+ c = ctx_list[0]
932
+
933
+ op = c.getSymbol().text
934
+ left_node = self.visitExpr(ctx_list[2])
935
+ right_node = self.visitExpr(ctx_list[4])
936
+
937
+ return BinOp(left=left_node, op=op, right=right_node)
938
+
939
+ def visitTimeAddAtom(self, ctx: Parser.TimeShiftAtomContext):
940
+ """ """
941
+
942
+ ctx_list = list(ctx.getChildren())
943
+ c = ctx_list[0]
944
+
945
+ op = c.getSymbol().text
946
+ children_node = [self.visitExpr(ctx_list[2])]
947
+
948
+ param_constant_node = []
949
+
950
+ if len(ctx_list) > 4:
951
+ param_constant_node = [self.visitExpr(ctx_list[4])]
952
+ if len(ctx_list) > 6:
953
+ param_constant_node.append(self.visitExpr(ctx_list[6]))
954
+
955
+ return ParamOp(op=op, children=children_node, params=param_constant_node)
956
+
875
957
  """
876
958
  -----------------------------------
877
959
  Conditional Functions
@@ -903,10 +985,10 @@ class Expr(VtlVisitor):
903
985
 
904
986
  def visitSetFunctions(self, ctx: Parser.SetFunctionsContext):
905
987
  """
906
- setExpr: UNION LPAREN left=expr (COMMA expr)+ RPAREN # unionAtom # noqa E501
907
- | INTERSECT LPAREN left=expr (COMMA expr)+ RPAREN # intersectAtom # noqa E501
908
- | op=(SETDIFF|SYMDIFF) LPAREN left=expr COMMA right=expr RPAREN # setOrSYmDiffAtom # noqa E501
909
- """
988
+ setExpr: UNION LPAREN left=expr (COMMA expr)+ RPAREN # unionAtom
989
+ | INTERSECT LPAREN left=expr (COMMA expr)+ RPAREN # intersectAtom
990
+ | op=(SETDIFF|SYMDIFF) LPAREN left=expr COMMA right=expr RPAREN # setOrSYmDiffAtom
991
+ """ # noqa E501
910
992
  if isinstance(ctx, Parser.UnionAtomContext):
911
993
  return self.visitUnionAtom(ctx)
912
994
  elif isinstance(ctx, Parser.IntersectAtomContext):
@@ -948,8 +1030,8 @@ class Expr(VtlVisitor):
948
1030
 
949
1031
  def visitHierarchyFunctions(self, ctx: Parser.HierarchyFunctionsContext):
950
1032
  """
951
- HIERARCHY LPAREN op=expr COMMA hrName=IDENTIFIER (conditionClause)? (RULE ruleComponent=componentID)? (validationMode)? (inputModeHierarchy)? outputModeHierarchy? RPAREN # noqa E501
952
- """
1033
+ HIERARCHY LPAREN op=expr COMMA hrName=IDENTIFIER (conditionClause)? (RULE ruleComponent=componentID)? (validationMode)? (inputModeHierarchy)? outputModeHierarchy? RPAREN
1034
+ """ # noqa E501
953
1035
  ctx_list = list(ctx.getChildren())
954
1036
  c = ctx_list[0]
955
1037
 
@@ -1019,8 +1101,8 @@ class Expr(VtlVisitor):
1019
1101
 
1020
1102
  def visitValidateDPruleset(self, ctx: Parser.ValidateDPrulesetContext):
1021
1103
  """
1022
- validationDatapoint: CHECK_DATAPOINT '(' expr ',' IDENTIFIER (COMPONENTS componentID (',' componentID)*)? (INVALID|ALL_MEASURES|ALL)? ')' ; # noqa E501
1023
- """
1104
+ validationDatapoint: CHECK_DATAPOINT '(' expr ',' IDENTIFIER (COMPONENTS componentID (',' componentID)*)? (INVALID|ALL_MEASURES|ALL)? ')' ;
1105
+ """ # noqa E501
1024
1106
  ctx_list = list(ctx.getChildren())
1025
1107
  c = ctx_list[0]
1026
1108
 
@@ -1054,8 +1136,8 @@ class Expr(VtlVisitor):
1054
1136
  # TODO Not fully implemented only basic usage available.
1055
1137
  def visitValidateHRruleset(self, ctx: Parser.ValidateHRrulesetContext):
1056
1138
  """
1057
- CHECK_HIERARCHY LPAREN op=expr COMMA hrName=IDENTIFIER conditionClause? (RULE componentID)? validationMode? inputMode? validationOutput? RPAREN # noqa E501 # validateHRruleset
1058
- """
1139
+ CHECK_HIERARCHY LPAREN op=expr COMMA hrName=IDENTIFIER conditionClause? (RULE componentID)? validationMode? inputMode? validationOutput? RPAREN # validateHRruleset
1140
+ """ # noqa E501
1059
1141
 
1060
1142
  ctx_list = list(ctx.getChildren())
1061
1143
  c = ctx_list[0]
@@ -1116,8 +1198,8 @@ class Expr(VtlVisitor):
1116
1198
 
1117
1199
  def visitValidationSimple(self, ctx: Parser.ValidationSimpleContext):
1118
1200
  """
1119
- | CHECK LPAREN op=expr (codeErr=erCode)? (levelCode=erLevel)? imbalanceExpr? output=(INVALID|ALL)? RPAREN # noqa E501 # validationSimple
1120
- """
1201
+ | CHECK LPAREN op=expr (codeErr=erCode)? (levelCode=erLevel)? imbalanceExpr? output=(INVALID|ALL)? RPAREN # validationSimple
1202
+ """ # noqa E501
1121
1203
  ctx_list = list(ctx.getChildren())
1122
1204
  c = ctx_list[0]
1123
1205
  token = c.getSymbol()
@@ -1136,11 +1218,7 @@ class Expr(VtlVisitor):
1136
1218
  inbalance_node = self.visitImbalanceExpr(param)
1137
1219
 
1138
1220
  invalid = ctx_list[-2] if isinstance(ctx_list[-2], TerminalNodeImpl) else None
1139
-
1140
- if invalid is None:
1141
- invalid_value = False
1142
- else:
1143
- invalid_value = True if invalid.getSymbol().text == "invalid" else False
1221
+ invalid_value = False if invalid is None else invalid.getSymbol().text == "invalid"
1144
1222
 
1145
1223
  return Validation(
1146
1224
  op=token.text,
@@ -1200,7 +1278,7 @@ class Expr(VtlVisitor):
1200
1278
  grouping_op, group_node = self.visitGroupingClause(groups[0])
1201
1279
  if len(haves) != 0:
1202
1280
  have_node, expr = self.visitHavingClause(haves[0])
1203
- setattr(have_node, "expr", expr)
1281
+ have_node.expr = expr
1204
1282
 
1205
1283
  return Aggregation(
1206
1284
  op=op_node,
@@ -1277,9 +1355,7 @@ class Expr(VtlVisitor):
1277
1355
  elif isinstance(c, Parser.OrderByClauseContext):
1278
1356
  order_by = Terminals().visitOrderByClause(c)
1279
1357
  continue
1280
- elif isinstance(c, Parser.SignedIntegerContext) or isinstance(
1281
- c, Parser.ScalarItemContext
1282
- ):
1358
+ elif isinstance(c, (Parser.SignedIntegerContext, Parser.ScalarItemContext)):
1283
1359
  if params is None:
1284
1360
  params = []
1285
1361
  if isinstance(c, Parser.SignedIntegerContext):
@@ -1445,7 +1521,7 @@ class Expr(VtlVisitor):
1445
1521
  right_node = ExprComp().visitAggregateFunctionsComponents(ctx_list[base_index + 2])
1446
1522
  # Encoding the role information inside the Assignment for easiness and simplicity.
1447
1523
  # Cannot find another way with less lines of code
1448
- setattr(left_node, "role", role)
1524
+ left_node.role = role
1449
1525
 
1450
1526
  return Assignment(left_node, op_node, right_node)
1451
1527
 
@@ -1472,7 +1548,7 @@ class Expr(VtlVisitor):
1472
1548
  grouping_op, group_node = self.visitGroupingClause(groups[0])
1473
1549
  if len(haves) > 0:
1474
1550
  have_node, expr = self.visitHavingClause(haves[0])
1475
- setattr(have_node, "expr", expr)
1551
+ have_node.expr = expr
1476
1552
  for element in aggregate_nodes:
1477
1553
  element.right = Aggregation(
1478
1554
  op=element.right.op,