pbi-parsers 0.7.8__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 (78) hide show
  1. pbi_parsers/__init__.py +9 -0
  2. pbi_parsers/base/__init__.py +7 -0
  3. pbi_parsers/base/lexer.py +127 -0
  4. pbi_parsers/base/tokens.py +61 -0
  5. pbi_parsers/dax/__init__.py +22 -0
  6. pbi_parsers/dax/exprs/__init__.py +107 -0
  7. pbi_parsers/dax/exprs/_base.py +46 -0
  8. pbi_parsers/dax/exprs/_utils.py +45 -0
  9. pbi_parsers/dax/exprs/add_sub.py +73 -0
  10. pbi_parsers/dax/exprs/add_sub_unary.py +72 -0
  11. pbi_parsers/dax/exprs/array.py +75 -0
  12. pbi_parsers/dax/exprs/column.py +56 -0
  13. pbi_parsers/dax/exprs/comparison.py +76 -0
  14. pbi_parsers/dax/exprs/concatenation.py +73 -0
  15. pbi_parsers/dax/exprs/div_mul.py +75 -0
  16. pbi_parsers/dax/exprs/exponent.py +67 -0
  17. pbi_parsers/dax/exprs/function.py +102 -0
  18. pbi_parsers/dax/exprs/hierarchy.py +68 -0
  19. pbi_parsers/dax/exprs/identifier.py +46 -0
  20. pbi_parsers/dax/exprs/ins.py +67 -0
  21. pbi_parsers/dax/exprs/keyword.py +60 -0
  22. pbi_parsers/dax/exprs/literal_number.py +46 -0
  23. pbi_parsers/dax/exprs/literal_string.py +45 -0
  24. pbi_parsers/dax/exprs/logical.py +76 -0
  25. pbi_parsers/dax/exprs/measure.py +44 -0
  26. pbi_parsers/dax/exprs/none.py +30 -0
  27. pbi_parsers/dax/exprs/parens.py +61 -0
  28. pbi_parsers/dax/exprs/returns.py +76 -0
  29. pbi_parsers/dax/exprs/table.py +51 -0
  30. pbi_parsers/dax/exprs/variable.py +68 -0
  31. pbi_parsers/dax/formatter.py +215 -0
  32. pbi_parsers/dax/lexer.py +222 -0
  33. pbi_parsers/dax/main.py +63 -0
  34. pbi_parsers/dax/parser.py +66 -0
  35. pbi_parsers/dax/tokens.py +54 -0
  36. pbi_parsers/dax/utils.py +120 -0
  37. pbi_parsers/pq/__init__.py +17 -0
  38. pbi_parsers/pq/exprs/__init__.py +98 -0
  39. pbi_parsers/pq/exprs/_base.py +33 -0
  40. pbi_parsers/pq/exprs/_utils.py +31 -0
  41. pbi_parsers/pq/exprs/add_sub.py +59 -0
  42. pbi_parsers/pq/exprs/add_sub_unary.py +57 -0
  43. pbi_parsers/pq/exprs/and_or_expr.py +60 -0
  44. pbi_parsers/pq/exprs/array.py +53 -0
  45. pbi_parsers/pq/exprs/arrow.py +50 -0
  46. pbi_parsers/pq/exprs/column.py +42 -0
  47. pbi_parsers/pq/exprs/comparison.py +62 -0
  48. pbi_parsers/pq/exprs/concatenation.py +61 -0
  49. pbi_parsers/pq/exprs/div_mul.py +59 -0
  50. pbi_parsers/pq/exprs/each.py +41 -0
  51. pbi_parsers/pq/exprs/ellipsis_expr.py +28 -0
  52. pbi_parsers/pq/exprs/function.py +63 -0
  53. pbi_parsers/pq/exprs/identifier.py +77 -0
  54. pbi_parsers/pq/exprs/if_expr.py +70 -0
  55. pbi_parsers/pq/exprs/is_expr.py +54 -0
  56. pbi_parsers/pq/exprs/keyword.py +40 -0
  57. pbi_parsers/pq/exprs/literal_number.py +31 -0
  58. pbi_parsers/pq/exprs/literal_string.py +31 -0
  59. pbi_parsers/pq/exprs/meta.py +54 -0
  60. pbi_parsers/pq/exprs/negation.py +52 -0
  61. pbi_parsers/pq/exprs/none.py +22 -0
  62. pbi_parsers/pq/exprs/not_expr.py +39 -0
  63. pbi_parsers/pq/exprs/parens.py +43 -0
  64. pbi_parsers/pq/exprs/record.py +58 -0
  65. pbi_parsers/pq/exprs/row.py +54 -0
  66. pbi_parsers/pq/exprs/row_index.py +57 -0
  67. pbi_parsers/pq/exprs/statement.py +67 -0
  68. pbi_parsers/pq/exprs/try_expr.py +55 -0
  69. pbi_parsers/pq/exprs/type_expr.py +78 -0
  70. pbi_parsers/pq/exprs/variable.py +52 -0
  71. pbi_parsers/pq/formatter.py +13 -0
  72. pbi_parsers/pq/lexer.py +219 -0
  73. pbi_parsers/pq/main.py +63 -0
  74. pbi_parsers/pq/parser.py +65 -0
  75. pbi_parsers/pq/tokens.py +81 -0
  76. pbi_parsers-0.7.8.dist-info/METADATA +66 -0
  77. pbi_parsers-0.7.8.dist-info/RECORD +78 -0
  78. pbi_parsers-0.7.8.dist-info/WHEEL +4 -0
@@ -0,0 +1,39 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from pbi_parsers.pq.tokens import TokenType
4
+
5
+ from ._base import Expression
6
+ from ._utils import lexer_reset
7
+
8
+ if TYPE_CHECKING:
9
+ from pbi_parsers.pq.parser import Parser
10
+
11
+
12
+ class NotExpression(Expression):
13
+ expr: Expression
14
+
15
+ def __init__(
16
+ self,
17
+ expr: Expression,
18
+ ) -> None:
19
+ self.expr = expr
20
+
21
+ def pprint(self) -> str:
22
+ return f"Not ({self.expr.pprint()})"
23
+
24
+ @classmethod
25
+ @lexer_reset
26
+ def match(cls, parser: "Parser") -> "NotExpression | None":
27
+ from . import any_expression_match # noqa: PLC0415
28
+
29
+ if parser.consume().tok_type != TokenType.NOT:
30
+ return None
31
+
32
+ expr = any_expression_match(parser)
33
+ if expr is None:
34
+ return None
35
+ return NotExpression(expr=expr)
36
+
37
+ def children(self) -> list[Expression]:
38
+ """Returns a list of child expressions."""
39
+ return [self.expr]
@@ -0,0 +1,43 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from pbi_parsers.pq.tokens import TokenType
4
+
5
+ from ._base import Expression
6
+ from ._utils import lexer_reset
7
+
8
+ if TYPE_CHECKING:
9
+ from pbi_parsers.pq.parser import Parser
10
+
11
+
12
+ class ParenthesesExpression(Expression):
13
+ inner_statement: Expression | None
14
+
15
+ def __init__(self, inner_statement: Expression | None) -> None:
16
+ self.inner_statement = inner_statement
17
+
18
+ def pprint(self) -> str:
19
+ return f"""
20
+ Parentheses (
21
+ {self.inner_statement}
22
+ )""".strip()
23
+
24
+ @classmethod
25
+ @lexer_reset
26
+ def match(cls, parser: "Parser") -> "ParenthesesExpression | None":
27
+ from . import any_expression_match # noqa: PLC0415
28
+
29
+ if not cls.match_tokens(parser, [TokenType.LEFT_PAREN]):
30
+ return None
31
+
32
+ parser.consume()
33
+ # when paired with an arrow expression, the value may not exist
34
+ value = any_expression_match(parser)
35
+
36
+ if parser.consume().tok_type != TokenType.RIGHT_PAREN:
37
+ return None
38
+
39
+ return ParenthesesExpression(inner_statement=value)
40
+
41
+ def children(self) -> list[Expression]:
42
+ """Returns a list of child expressions."""
43
+ return [self.inner_statement] if self.inner_statement else []
@@ -0,0 +1,58 @@
1
+ import textwrap
2
+ from typing import TYPE_CHECKING
3
+
4
+ from pbi_parsers.pq.tokens import TokenType
5
+
6
+ from ._base import Expression
7
+ from ._utils import lexer_reset
8
+ from .identifier import IdentifierExpression
9
+
10
+ if TYPE_CHECKING:
11
+ from pbi_parsers.pq.parser import Parser
12
+
13
+
14
+ class RecordExpression(Expression):
15
+ args: list[tuple[IdentifierExpression, Expression]]
16
+
17
+ def __init__(self, args: list[tuple[IdentifierExpression, Expression]]) -> None:
18
+ self.args = args
19
+
20
+ def pprint(self) -> str:
21
+ args = ",\n".join(f"{arg[0].pprint()}: {arg[1].pprint()}" for arg in self.args)
22
+ args = textwrap.indent(args, " " * 4)[4:]
23
+ return f"""
24
+ Record (
25
+ {args}
26
+ ) """.strip()
27
+
28
+ @classmethod
29
+ @lexer_reset
30
+ def match(cls, parser: "Parser") -> "RecordExpression | None":
31
+ from . import any_expression_match # noqa: PLC0415
32
+
33
+ args: list[tuple[IdentifierExpression, Expression]] = []
34
+ if parser.consume().tok_type != TokenType.LEFT_BRACKET:
35
+ return None
36
+
37
+ while parser.peek().tok_type != TokenType.RIGHT_BRACKET:
38
+ name = IdentifierExpression.match(parser)
39
+ if name is None:
40
+ return None
41
+ if parser.consume().tok_type != TokenType.EQUAL_SIGN:
42
+ return None
43
+
44
+ value = any_expression_match(parser)
45
+ if value is None:
46
+ return None
47
+
48
+ args.append((name, value))
49
+
50
+ if parser.peek().tok_type == TokenType.COMMA:
51
+ parser.consume()
52
+
53
+ parser.consume() # consume the right bracket
54
+ return RecordExpression(args=args)
55
+
56
+ def children(self) -> list[Expression]:
57
+ """Returns a list of child expressions."""
58
+ return [val for arg in self.args for val in arg]
@@ -0,0 +1,54 @@
1
+ import textwrap
2
+ from typing import TYPE_CHECKING
3
+
4
+ from pbi_parsers.pq.tokens import TokenType
5
+
6
+ from ._base import Expression
7
+ from ._utils import lexer_reset
8
+ from .identifier import IdentifierExpression
9
+
10
+ if TYPE_CHECKING:
11
+ from pbi_parsers.pq.parser import Parser
12
+
13
+
14
+ class RowExpression(Expression):
15
+ table: IdentifierExpression
16
+ indexer: Expression
17
+
18
+ def __init__(
19
+ self,
20
+ table: IdentifierExpression,
21
+ indexer: Expression,
22
+ ) -> None:
23
+ self.table = table
24
+ self.indexer = indexer
25
+
26
+ def pprint(self) -> str:
27
+ indexer = textwrap.indent(self.indexer.pprint(), " " * 4)[4:]
28
+ return f"""
29
+ Table (
30
+ name: {self.table.pprint()},
31
+ indexer: {indexer}
32
+ ) """.strip()
33
+
34
+ @classmethod
35
+ @lexer_reset
36
+ def match(cls, parser: "Parser") -> "RowExpression | None":
37
+ from . import any_expression_match # noqa: PLC0415
38
+
39
+ table = IdentifierExpression.match(parser)
40
+ if table is None:
41
+ return None
42
+ if parser.consume().tok_type != TokenType.LEFT_CURLY_BRACE:
43
+ return None
44
+ indexer = any_expression_match(parser)
45
+ if indexer is None:
46
+ return None
47
+ if parser.consume().tok_type != TokenType.RIGHT_CURLY_BRACE:
48
+ return None
49
+
50
+ return RowExpression(table=table, indexer=indexer)
51
+
52
+ def children(self) -> list[Expression]:
53
+ """Returns a list of child expressions."""
54
+ return [self.table, self.indexer]
@@ -0,0 +1,57 @@
1
+ import textwrap
2
+ from typing import TYPE_CHECKING
3
+
4
+ from pbi_parsers.pq.tokens import TokenType
5
+
6
+ from ._base import Expression
7
+ from ._utils import lexer_reset
8
+
9
+ if TYPE_CHECKING:
10
+ from pbi_parsers.pq.parser import Parser
11
+
12
+
13
+ class RowIndexExpression(Expression):
14
+ table: Expression
15
+ indexer: Expression
16
+
17
+ def __init__(self, table: Expression, indexer: Expression) -> None:
18
+ self.table = table
19
+ self.indexer = indexer
20
+
21
+ def pprint(self) -> str:
22
+ table = textwrap.indent(self.table.pprint(), " " * 4)[4:]
23
+ indexer = textwrap.indent(self.indexer.pprint(), " " * 4)[4:]
24
+ return f"""
25
+ Indexer (
26
+ table: {table},
27
+ indexer: {indexer}
28
+ ) """.strip()
29
+
30
+ @classmethod
31
+ @lexer_reset
32
+ def match(cls, parser: "Parser") -> "RowIndexExpression | None":
33
+ from . import EXPRESSION_HIERARCHY, any_expression_match # noqa: PLC0415
34
+
35
+ skip_index = EXPRESSION_HIERARCHY.index(
36
+ RowIndexExpression,
37
+ ) # intentionally inclusive of self to allow +-++- chains
38
+
39
+ table = any_expression_match(parser, skip_first=skip_index + 1)
40
+ if table is None:
41
+ return None
42
+
43
+ if parser.consume().tok_type != TokenType.LEFT_BRACKET:
44
+ return None
45
+
46
+ indexer = any_expression_match(parser)
47
+ if indexer is None:
48
+ return None
49
+
50
+ if parser.consume().tok_type != TokenType.RIGHT_BRACKET:
51
+ return None
52
+
53
+ return RowIndexExpression(table=table, indexer=indexer)
54
+
55
+ def children(self) -> list[Expression]:
56
+ """Returns a list of child expressions."""
57
+ return [self.table, self.indexer]
@@ -0,0 +1,67 @@
1
+ import textwrap
2
+ from typing import TYPE_CHECKING
3
+
4
+ from pbi_parsers.pq.tokens import TokenType
5
+
6
+ from ._base import Expression
7
+ from ._utils import lexer_reset
8
+ from .variable import VariableExpression
9
+
10
+ if TYPE_CHECKING:
11
+ from pbi_parsers.pq.parser import Parser
12
+
13
+
14
+ class StatementExpression(Expression):
15
+ statements: list[VariableExpression]
16
+ let_expr: Expression
17
+
18
+ def __init__(self, let_expr: Expression, statements: list[VariableExpression]) -> None:
19
+ self.let_expr = let_expr
20
+ self.statements = statements
21
+
22
+ def pprint(self) -> str:
23
+ let_expr = textwrap.indent(self.let_expr.pprint(), " " * 14)[14:]
24
+ statements = textwrap.indent(
25
+ ",\n".join(statement.pprint() for statement in self.statements),
26
+ " " * 17,
27
+ )[17:]
28
+ return f"""
29
+ Statement (
30
+ statements: {statements}
31
+ let_expr: {let_expr}
32
+ )
33
+ """.strip()
34
+
35
+ @classmethod
36
+ @lexer_reset
37
+ def match(cls, parser: "Parser") -> "StatementExpression | None":
38
+ from . import any_expression_match # noqa: PLC0415
39
+
40
+ if parser.consume().tok_type != TokenType.LET:
41
+ return None
42
+
43
+ statements = []
44
+ while parser.peek().tok_type != TokenType.IN:
45
+ statements.append(VariableExpression.match(parser))
46
+
47
+ if parser.peek().tok_type == TokenType.COMMA:
48
+ parser.consume()
49
+ elif parser.peek().tok_type != TokenType.IN:
50
+ msg = f"Expected a comma or 'in' token, got {parser.peek().tok_type}"
51
+ raise ValueError(msg)
52
+ if not statements:
53
+ return None
54
+
55
+ if parser.consume().tok_type != TokenType.IN:
56
+ msg = "Expected 'in' token after let statements"
57
+ raise ValueError(msg)
58
+
59
+ in_expr = any_expression_match(parser)
60
+ if in_expr is None:
61
+ msg = "Expected an expression after 'in' token"
62
+ raise ValueError(msg)
63
+ return StatementExpression(statements=statements, let_expr=in_expr)
64
+
65
+ def children(self) -> list[Expression]:
66
+ """Returns a list of child expressions."""
67
+ return [self.let_expr, *self.statements]
@@ -0,0 +1,55 @@
1
+ import textwrap
2
+ from typing import TYPE_CHECKING
3
+
4
+ from pbi_parsers.pq.tokens import TokenType
5
+
6
+ from ._base import Expression
7
+ from ._utils import lexer_reset
8
+
9
+ if TYPE_CHECKING:
10
+ from pbi_parsers.pq.parser import Parser
11
+
12
+
13
+ class TryExpression(Expression):
14
+ try_expr: Expression
15
+ otherwise_expr: Expression
16
+
17
+ def __init__(self, try_expr: Expression, otherwise_expr: Expression) -> None:
18
+ self.try_expr = try_expr
19
+ self.otherwise_expr = otherwise_expr
20
+
21
+ def pprint(self) -> str:
22
+ try_expr = textwrap.indent(self.try_expr.pprint(), " " * 10)[10:]
23
+ otherwise_expr = textwrap.indent(self.otherwise_expr.pprint(), " " * 10)[10:]
24
+ return f"""
25
+ Try (
26
+ try: {try_expr},
27
+ otherwise: {otherwise_expr}
28
+ )""".strip()
29
+
30
+ @classmethod
31
+ @lexer_reset
32
+ def match(cls, parser: "Parser") -> "TryExpression | None":
33
+ from . import any_expression_match # noqa: PLC0415
34
+
35
+ try_ = parser.consume()
36
+ if try_.tok_type != TokenType.TRY:
37
+ return None
38
+ try_expr: Expression | None = any_expression_match(
39
+ parser,
40
+ ) # this expression can recurse
41
+ if not try_expr:
42
+ return None
43
+
44
+ otherwise = parser.consume()
45
+ if otherwise.tok_type != TokenType.OTHERWISE:
46
+ return None
47
+ otherwise_expr = any_expression_match(parser)
48
+ if not otherwise_expr:
49
+ return None
50
+
51
+ return TryExpression(try_expr=try_expr, otherwise_expr=otherwise_expr)
52
+
53
+ def children(self) -> list[Expression]:
54
+ """Returns a list of child expressions."""
55
+ return [self.try_expr, self.otherwise_expr]
@@ -0,0 +1,78 @@
1
+ import textwrap
2
+ from typing import TYPE_CHECKING
3
+
4
+ from pbi_parsers.pq.tokens import Token, TokenType
5
+
6
+ from ._base import Expression
7
+ from ._utils import lexer_reset
8
+
9
+ if TYPE_CHECKING:
10
+ from pbi_parsers.pq.parser import Parser
11
+
12
+
13
+ class TypingExpression(Expression):
14
+ type_name: list[Token]
15
+ nullable: Token | None = None
16
+ column_mapping: Expression | None = None
17
+
18
+ def __init__(
19
+ self,
20
+ type_name: list[Token],
21
+ nullable: Token | None = None,
22
+ column_mapping: Expression | None = None,
23
+ ) -> None:
24
+ self.tok_type_name = type_name
25
+ self.nullable = nullable
26
+ self.column_mapping = column_mapping
27
+
28
+ def pprint(self) -> str:
29
+ type_name = ".".join(t.text for t in self.tok_type_name)
30
+ if self.column_mapping is None:
31
+ base = f"Type ({type_name})"
32
+ else:
33
+ column_mapping = textwrap.indent(self.column_mapping.pprint(), " " * 10)[10:]
34
+ base = f"""
35
+ Type (
36
+ type: {type_name},
37
+ column: {column_mapping}
38
+ )
39
+ """
40
+ return base
41
+
42
+ @classmethod
43
+ @lexer_reset
44
+ def match(cls, parser: "Parser") -> "TypingExpression | None":
45
+ from . import any_expression_match # noqa: PLC0415
46
+
47
+ type_keyword = parser.consume()
48
+ if type_keyword.tok_type == TokenType.TYPE_LITERAL:
49
+ return TypingExpression(type_name=[type_keyword])
50
+ if type_keyword.tok_type != TokenType.TYPE:
51
+ return None
52
+
53
+ nullable = None
54
+ if parser.peek().tok_type == TokenType.NULLABLE:
55
+ nullable = parser.consume()
56
+
57
+ name_parts = [parser.consume()]
58
+ # single part name (i.e. no period)
59
+ while parser.peek().tok_type == TokenType.PERIOD:
60
+ period, name = parser.consume(), parser.consume()
61
+ if name.tok_type not in {TokenType.UNQUOTED_IDENTIFIER, TokenType.TYPE}:
62
+ return None
63
+ if period.tok_type != TokenType.PERIOD:
64
+ return None
65
+ name_parts.append(name)
66
+ if len(name_parts) == 1 and name_parts[0].text == "table":
67
+ column_mapping = any_expression_match(parser)
68
+ else:
69
+ column_mapping = None
70
+ return TypingExpression(
71
+ type_name=name_parts,
72
+ nullable=nullable,
73
+ column_mapping=column_mapping,
74
+ )
75
+
76
+ def children(self) -> list[Expression]:
77
+ """Returns a list of child expressions."""
78
+ return [self.column_mapping] if self.column_mapping else []
@@ -0,0 +1,52 @@
1
+ import textwrap
2
+ from typing import TYPE_CHECKING
3
+
4
+ from pbi_parsers.pq.tokens import Token, TokenType
5
+
6
+ from ._base import Expression
7
+ from ._utils import lexer_reset
8
+
9
+ if TYPE_CHECKING:
10
+ from pbi_parsers.pq.parser import Parser
11
+
12
+
13
+ class VariableExpression(Expression):
14
+ var_name: Token
15
+ statement: Expression
16
+
17
+ def __init__(self, var_name: Token, statement: Expression) -> None:
18
+ self.var_name = var_name
19
+ self.statement = statement
20
+
21
+ def pprint(self) -> str:
22
+ statement = textwrap.indent(self.statement.pprint(), " " * 17).lstrip()
23
+ return f"""
24
+ Variable (
25
+ name: {self.var_name.text},
26
+ statement: {statement}
27
+ )
28
+ """.strip()
29
+
30
+ @classmethod
31
+ @lexer_reset
32
+ def match(cls, parser: "Parser") -> "VariableExpression | None":
33
+ from . import any_expression_match # noqa: PLC0415
34
+
35
+ var_name = parser.consume()
36
+ equal_sign = parser.consume()
37
+ if (
38
+ var_name.tok_type
39
+ not in {TokenType.QUOTED_IDENTIFER, TokenType.UNQUOTED_IDENTIFIER, TokenType.HASH_IDENTIFIER}
40
+ or equal_sign.tok_type != TokenType.EQUAL_SIGN
41
+ ):
42
+ return None
43
+
44
+ statement = any_expression_match(parser)
45
+ if statement is None:
46
+ msg = "VariableExpression.match called without valid inner expression"
47
+ raise ValueError(msg)
48
+ return VariableExpression(var_name=var_name, statement=statement)
49
+
50
+ def children(self) -> list[Expression]:
51
+ """Returns a list of child expressions."""
52
+ return [self.statement]
@@ -0,0 +1,13 @@
1
+ from .exprs import Expression
2
+
3
+
4
+ class Formatter:
5
+ expression: Expression
6
+
7
+ def __init__(self, expression: Expression) -> None:
8
+ self.expression = expression
9
+
10
+ def format(self) -> str:
11
+ # Implement the formatting logic here
12
+ msg = "Formatter.format method is not implemented."
13
+ raise NotImplementedError(msg)