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.
- pbi_parsers/__init__.py +9 -0
- pbi_parsers/base/__init__.py +7 -0
- pbi_parsers/base/lexer.py +127 -0
- pbi_parsers/base/tokens.py +61 -0
- pbi_parsers/dax/__init__.py +22 -0
- pbi_parsers/dax/exprs/__init__.py +107 -0
- pbi_parsers/dax/exprs/_base.py +46 -0
- pbi_parsers/dax/exprs/_utils.py +45 -0
- pbi_parsers/dax/exprs/add_sub.py +73 -0
- pbi_parsers/dax/exprs/add_sub_unary.py +72 -0
- pbi_parsers/dax/exprs/array.py +75 -0
- pbi_parsers/dax/exprs/column.py +56 -0
- pbi_parsers/dax/exprs/comparison.py +76 -0
- pbi_parsers/dax/exprs/concatenation.py +73 -0
- pbi_parsers/dax/exprs/div_mul.py +75 -0
- pbi_parsers/dax/exprs/exponent.py +67 -0
- pbi_parsers/dax/exprs/function.py +102 -0
- pbi_parsers/dax/exprs/hierarchy.py +68 -0
- pbi_parsers/dax/exprs/identifier.py +46 -0
- pbi_parsers/dax/exprs/ins.py +67 -0
- pbi_parsers/dax/exprs/keyword.py +60 -0
- pbi_parsers/dax/exprs/literal_number.py +46 -0
- pbi_parsers/dax/exprs/literal_string.py +45 -0
- pbi_parsers/dax/exprs/logical.py +76 -0
- pbi_parsers/dax/exprs/measure.py +44 -0
- pbi_parsers/dax/exprs/none.py +30 -0
- pbi_parsers/dax/exprs/parens.py +61 -0
- pbi_parsers/dax/exprs/returns.py +76 -0
- pbi_parsers/dax/exprs/table.py +51 -0
- pbi_parsers/dax/exprs/variable.py +68 -0
- pbi_parsers/dax/formatter.py +215 -0
- pbi_parsers/dax/lexer.py +222 -0
- pbi_parsers/dax/main.py +63 -0
- pbi_parsers/dax/parser.py +66 -0
- pbi_parsers/dax/tokens.py +54 -0
- pbi_parsers/dax/utils.py +120 -0
- pbi_parsers/pq/__init__.py +17 -0
- pbi_parsers/pq/exprs/__init__.py +98 -0
- pbi_parsers/pq/exprs/_base.py +33 -0
- pbi_parsers/pq/exprs/_utils.py +31 -0
- pbi_parsers/pq/exprs/add_sub.py +59 -0
- pbi_parsers/pq/exprs/add_sub_unary.py +57 -0
- pbi_parsers/pq/exprs/and_or_expr.py +60 -0
- pbi_parsers/pq/exprs/array.py +53 -0
- pbi_parsers/pq/exprs/arrow.py +50 -0
- pbi_parsers/pq/exprs/column.py +42 -0
- pbi_parsers/pq/exprs/comparison.py +62 -0
- pbi_parsers/pq/exprs/concatenation.py +61 -0
- pbi_parsers/pq/exprs/div_mul.py +59 -0
- pbi_parsers/pq/exprs/each.py +41 -0
- pbi_parsers/pq/exprs/ellipsis_expr.py +28 -0
- pbi_parsers/pq/exprs/function.py +63 -0
- pbi_parsers/pq/exprs/identifier.py +77 -0
- pbi_parsers/pq/exprs/if_expr.py +70 -0
- pbi_parsers/pq/exprs/is_expr.py +54 -0
- pbi_parsers/pq/exprs/keyword.py +40 -0
- pbi_parsers/pq/exprs/literal_number.py +31 -0
- pbi_parsers/pq/exprs/literal_string.py +31 -0
- pbi_parsers/pq/exprs/meta.py +54 -0
- pbi_parsers/pq/exprs/negation.py +52 -0
- pbi_parsers/pq/exprs/none.py +22 -0
- pbi_parsers/pq/exprs/not_expr.py +39 -0
- pbi_parsers/pq/exprs/parens.py +43 -0
- pbi_parsers/pq/exprs/record.py +58 -0
- pbi_parsers/pq/exprs/row.py +54 -0
- pbi_parsers/pq/exprs/row_index.py +57 -0
- pbi_parsers/pq/exprs/statement.py +67 -0
- pbi_parsers/pq/exprs/try_expr.py +55 -0
- pbi_parsers/pq/exprs/type_expr.py +78 -0
- pbi_parsers/pq/exprs/variable.py +52 -0
- pbi_parsers/pq/formatter.py +13 -0
- pbi_parsers/pq/lexer.py +219 -0
- pbi_parsers/pq/main.py +63 -0
- pbi_parsers/pq/parser.py +65 -0
- pbi_parsers/pq/tokens.py +81 -0
- pbi_parsers-0.7.8.dist-info/METADATA +66 -0
- pbi_parsers-0.7.8.dist-info/RECORD +78 -0
- pbi_parsers-0.7.8.dist-info/WHEEL +4 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
from pbi_parsers.dax.tokens import Token, TokenType
|
4
|
+
|
5
|
+
from ._base import Expression
|
6
|
+
from ._utils import lexer_reset
|
7
|
+
|
8
|
+
if TYPE_CHECKING:
|
9
|
+
from pbi_parsers.dax.parser import Parser
|
10
|
+
|
11
|
+
|
12
|
+
class LiteralNumberExpression(Expression):
|
13
|
+
"""Represents a literal number in DAX.
|
14
|
+
|
15
|
+
Examples:
|
16
|
+
42
|
17
|
+
3.14
|
18
|
+
-1000
|
19
|
+
|
20
|
+
"""
|
21
|
+
|
22
|
+
value: Token
|
23
|
+
|
24
|
+
def __init__(self, value: Token) -> None:
|
25
|
+
self.value = value
|
26
|
+
|
27
|
+
def pprint(self) -> str:
|
28
|
+
return f"Number ({self.value.text})"
|
29
|
+
|
30
|
+
@classmethod
|
31
|
+
@lexer_reset
|
32
|
+
def match(cls, parser: "Parser") -> "LiteralNumberExpression | None":
|
33
|
+
if cls.match_tokens(parser, [TokenType.NUMBER_LITERAL]):
|
34
|
+
value = parser.consume()
|
35
|
+
return LiteralNumberExpression(value=value)
|
36
|
+
return None
|
37
|
+
|
38
|
+
def children(self) -> list[Expression]: # noqa: PLR6301
|
39
|
+
"""Returns a list of child expressions."""
|
40
|
+
return []
|
41
|
+
|
42
|
+
def position(self) -> tuple[int, int]:
|
43
|
+
return self.value.text_slice.start, self.value.text_slice.end
|
44
|
+
|
45
|
+
def full_text(self) -> str:
|
46
|
+
return self.value.text_slice.full_text
|
@@ -0,0 +1,45 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
from pbi_parsers.dax.tokens import Token, TokenType
|
4
|
+
|
5
|
+
from ._base import Expression
|
6
|
+
from ._utils import lexer_reset
|
7
|
+
|
8
|
+
if TYPE_CHECKING:
|
9
|
+
from pbi_parsers.dax.parser import Parser
|
10
|
+
|
11
|
+
|
12
|
+
class LiteralStringExpression(Expression):
|
13
|
+
"""A literal string in DAX.
|
14
|
+
|
15
|
+
Examples:
|
16
|
+
"Hello, World!"
|
17
|
+
"Another String"
|
18
|
+
|
19
|
+
"""
|
20
|
+
|
21
|
+
value: Token
|
22
|
+
|
23
|
+
def __init__(self, value: Token) -> None:
|
24
|
+
self.value = value
|
25
|
+
|
26
|
+
def pprint(self) -> str:
|
27
|
+
return f"String ({self.value.text})"
|
28
|
+
|
29
|
+
@classmethod
|
30
|
+
@lexer_reset
|
31
|
+
def match(cls, parser: "Parser") -> "LiteralStringExpression | None":
|
32
|
+
if cls.match_tokens(parser, [TokenType.STRING_LITERAL]):
|
33
|
+
value = parser.consume()
|
34
|
+
return LiteralStringExpression(value=value)
|
35
|
+
return None
|
36
|
+
|
37
|
+
def children(self) -> list[Expression]: # noqa: PLR6301
|
38
|
+
"""Returns a list of child expressions."""
|
39
|
+
return []
|
40
|
+
|
41
|
+
def position(self) -> tuple[int, int]:
|
42
|
+
return self.value.text_slice.start, self.value.text_slice.end
|
43
|
+
|
44
|
+
def full_text(self) -> str:
|
45
|
+
return self.value.text_slice.full_text
|
@@ -0,0 +1,76 @@
|
|
1
|
+
import textwrap
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
from pbi_parsers.dax.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.dax.parser import Parser
|
11
|
+
|
12
|
+
|
13
|
+
class LogicalExpression(Expression):
|
14
|
+
"""AND/OR boolean expression in DAX.
|
15
|
+
|
16
|
+
Examples:
|
17
|
+
1 || 2
|
18
|
+
func() && 3
|
19
|
+
|
20
|
+
"""
|
21
|
+
|
22
|
+
operator: Token
|
23
|
+
left: Expression
|
24
|
+
right: Expression
|
25
|
+
|
26
|
+
def __init__(self, operator: Token, left: Expression, right: Expression) -> None:
|
27
|
+
self.operator = operator
|
28
|
+
self.left = left
|
29
|
+
self.right = right
|
30
|
+
|
31
|
+
@classmethod
|
32
|
+
@lexer_reset
|
33
|
+
def match(cls, parser: "Parser") -> "LogicalExpression | None":
|
34
|
+
from . import EXPRESSION_HIERARCHY, any_expression_match # noqa: PLC0415
|
35
|
+
|
36
|
+
skip_index = EXPRESSION_HIERARCHY.index(LogicalExpression)
|
37
|
+
|
38
|
+
left_term = any_expression_match(parser=parser, skip_first=skip_index + 1)
|
39
|
+
operator = parser.consume()
|
40
|
+
|
41
|
+
if not left_term:
|
42
|
+
return None
|
43
|
+
if operator.tok_type not in {
|
44
|
+
TokenType.DOUBLE_PIPE_OPERATOR,
|
45
|
+
TokenType.DOUBLE_AMPERSAND_OPERATOR,
|
46
|
+
}:
|
47
|
+
return None
|
48
|
+
|
49
|
+
right_term: Expression | None = any_expression_match(
|
50
|
+
parser=parser,
|
51
|
+
skip_first=skip_index,
|
52
|
+
)
|
53
|
+
if right_term is None:
|
54
|
+
msg = f"Expected a right term after operator {operator.text}, found: {parser.peek()}"
|
55
|
+
raise ValueError(msg)
|
56
|
+
return LogicalExpression(operator=operator, left=left_term, right=right_term)
|
57
|
+
|
58
|
+
def pprint(self) -> str:
|
59
|
+
left_str = textwrap.indent(self.left.pprint(), " " * 10).lstrip()
|
60
|
+
right_str = textwrap.indent(self.right.pprint(), " " * 10).lstrip()
|
61
|
+
return f"""
|
62
|
+
Logical (
|
63
|
+
operator: {self.operator.text},
|
64
|
+
left: {left_str},
|
65
|
+
right: {right_str}
|
66
|
+
)""".strip()
|
67
|
+
|
68
|
+
def children(self) -> list[Expression]:
|
69
|
+
"""Returns a list of child expressions."""
|
70
|
+
return [self.left, self.right]
|
71
|
+
|
72
|
+
def position(self) -> tuple[int, int]:
|
73
|
+
return self.left.position()[0], self.right.position()[1]
|
74
|
+
|
75
|
+
def full_text(self) -> str:
|
76
|
+
return self.left.full_text()
|
@@ -0,0 +1,44 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
from pbi_parsers.dax.tokens import Token, TokenType
|
4
|
+
|
5
|
+
from ._base import Expression
|
6
|
+
from ._utils import lexer_reset
|
7
|
+
|
8
|
+
if TYPE_CHECKING:
|
9
|
+
from pbi_parsers.dax.parser import Parser
|
10
|
+
|
11
|
+
|
12
|
+
class MeasureExpression(Expression):
|
13
|
+
"""Represents a measure in DAX.
|
14
|
+
|
15
|
+
Examples:
|
16
|
+
[Measure Name]
|
17
|
+
|
18
|
+
"""
|
19
|
+
|
20
|
+
name: Token
|
21
|
+
|
22
|
+
def __init__(self, name: Token) -> None:
|
23
|
+
self.name = name
|
24
|
+
|
25
|
+
def pprint(self) -> str:
|
26
|
+
return f"Measure ({self.name.text})"
|
27
|
+
|
28
|
+
@classmethod
|
29
|
+
@lexer_reset
|
30
|
+
def match(cls, parser: "Parser") -> "MeasureExpression | None":
|
31
|
+
if cls.match_tokens(parser, [TokenType.BRACKETED_IDENTIFIER]):
|
32
|
+
name = parser.consume()
|
33
|
+
return MeasureExpression(name=name)
|
34
|
+
return None
|
35
|
+
|
36
|
+
def children(self) -> list[Expression]: # noqa: PLR6301
|
37
|
+
"""Returns a list of child expressions."""
|
38
|
+
return []
|
39
|
+
|
40
|
+
def position(self) -> tuple[int, int]:
|
41
|
+
return self.name.text_slice.start, self.name.text_slice.end
|
42
|
+
|
43
|
+
def full_text(self) -> str:
|
44
|
+
return self.name.text_slice.full_text
|
@@ -0,0 +1,30 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
from ._base import Expression
|
4
|
+
|
5
|
+
if TYPE_CHECKING:
|
6
|
+
from pbi_parsers.dax.parser import Parser
|
7
|
+
|
8
|
+
|
9
|
+
class NoneExpression(Expression):
|
10
|
+
"""Used to represent the absence of a value, so far only occurring when a argument is skipped in a function."""
|
11
|
+
|
12
|
+
def pprint(self) -> str: # noqa: PLR6301 # kept this way to match the interface
|
13
|
+
return "None"
|
14
|
+
|
15
|
+
@classmethod
|
16
|
+
def match(cls, parser: "Parser") -> "NoneExpression | None":
|
17
|
+
msg = "NoneExpression.match should not be called, this is a placeholder for the absence of an expression."
|
18
|
+
raise NotImplementedError(msg)
|
19
|
+
|
20
|
+
def children(self) -> list[Expression]: # noqa: PLR6301
|
21
|
+
"""Returns a list of child expressions."""
|
22
|
+
return []
|
23
|
+
|
24
|
+
def position(self) -> tuple[int, int]: # noqa: PLR6301
|
25
|
+
"""Returns the position of the expression."""
|
26
|
+
return -1, -1
|
27
|
+
|
28
|
+
def full_text(self) -> str: # noqa: PLR6301
|
29
|
+
"""Returns the full text of the expression."""
|
30
|
+
return ""
|
@@ -0,0 +1,61 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
from pbi_parsers.dax.tokens import Token, TokenType
|
4
|
+
|
5
|
+
from ._base import Expression
|
6
|
+
from ._utils import lexer_reset
|
7
|
+
|
8
|
+
if TYPE_CHECKING:
|
9
|
+
from pbi_parsers.dax.parser import Parser
|
10
|
+
|
11
|
+
|
12
|
+
class ParenthesesExpression(Expression):
|
13
|
+
"""Represents a parenthesized expression in DAX.
|
14
|
+
|
15
|
+
Examples:
|
16
|
+
(1 + 2)
|
17
|
+
(func())
|
18
|
+
|
19
|
+
"""
|
20
|
+
|
21
|
+
inner_statement: Expression
|
22
|
+
parens: tuple[Token, Token]
|
23
|
+
|
24
|
+
def __init__(self, inner_statement: Expression, parens: tuple[Token, Token]) -> None:
|
25
|
+
self.inner_statement = inner_statement
|
26
|
+
self.parens = parens
|
27
|
+
|
28
|
+
def pprint(self) -> str:
|
29
|
+
return f"""
|
30
|
+
Parentheses (
|
31
|
+
{self.inner_statement}
|
32
|
+
)""".strip()
|
33
|
+
|
34
|
+
@classmethod
|
35
|
+
@lexer_reset
|
36
|
+
def match(cls, parser: "Parser") -> "ParenthesesExpression | None":
|
37
|
+
from . import any_expression_match # noqa: PLC0415
|
38
|
+
|
39
|
+
if not cls.match_tokens(parser, [TokenType.LEFT_PAREN]):
|
40
|
+
return None
|
41
|
+
|
42
|
+
left_paren = parser.consume()
|
43
|
+
value = any_expression_match(parser)
|
44
|
+
if value is None:
|
45
|
+
msg = "ParenthesesExpression.match called without valid inner expression"
|
46
|
+
raise ValueError(msg)
|
47
|
+
right_paren = parser.consume()
|
48
|
+
assert right_paren.tok_type == TokenType.RIGHT_PAREN # Consume the right parenthesis
|
49
|
+
return ParenthesesExpression(inner_statement=value, parens=(left_paren, right_paren))
|
50
|
+
|
51
|
+
def children(self) -> list[Expression]:
|
52
|
+
"""Returns a list of child expressions."""
|
53
|
+
return [self.inner_statement]
|
54
|
+
|
55
|
+
def position(self) -> tuple[int, int]:
|
56
|
+
"""Returns the position of the expression."""
|
57
|
+
return self.parens[0].text_slice.start, self.parens[1].text_slice.end
|
58
|
+
|
59
|
+
def full_text(self) -> str:
|
60
|
+
"""Returns the full text of the expression."""
|
61
|
+
return self.parens[0].text_slice.full_text
|
@@ -0,0 +1,76 @@
|
|
1
|
+
import textwrap
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
from pbi_parsers.dax.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.dax.parser import Parser
|
12
|
+
|
13
|
+
|
14
|
+
class ReturnExpression(Expression):
|
15
|
+
"""Represents a RETURN statement in DAX.
|
16
|
+
|
17
|
+
Examples:
|
18
|
+
VAR x = 1
|
19
|
+
RETURN x + 2
|
20
|
+
|
21
|
+
VAR x = 1
|
22
|
+
RETURN x
|
23
|
+
|
24
|
+
"""
|
25
|
+
|
26
|
+
ret: Expression
|
27
|
+
variable_statements: list[VariableExpression]
|
28
|
+
|
29
|
+
def __init__(self, ret: Expression, variable_statements: list[VariableExpression]) -> None:
|
30
|
+
self.ret = ret
|
31
|
+
self.variable_statements = variable_statements
|
32
|
+
|
33
|
+
def pprint(self) -> str:
|
34
|
+
return_val = textwrap.indent(self.ret.pprint(), " " * 12).lstrip()
|
35
|
+
statements = textwrap.indent(
|
36
|
+
",\n".join(stmt.pprint() for stmt in self.variable_statements),
|
37
|
+
" " * 16,
|
38
|
+
).lstrip()
|
39
|
+
return f"""
|
40
|
+
Return (
|
41
|
+
Return: {return_val},
|
42
|
+
Statements: {statements}
|
43
|
+
)""".strip()
|
44
|
+
|
45
|
+
@classmethod
|
46
|
+
@lexer_reset
|
47
|
+
def match(cls, parser: "Parser") -> "ReturnExpression | None":
|
48
|
+
from . import any_expression_match # noqa: PLC0415
|
49
|
+
|
50
|
+
if not cls.match_tokens(parser, [TokenType.VARIABLE]):
|
51
|
+
return None
|
52
|
+
|
53
|
+
statements: list[VariableExpression] = []
|
54
|
+
while not cls.match_tokens(parser, [TokenType.RETURN]):
|
55
|
+
statement = VariableExpression.match(parser)
|
56
|
+
if statement is None:
|
57
|
+
msg = "ReturnExpression.match called without valid inner expression"
|
58
|
+
raise ValueError(msg)
|
59
|
+
statements.append(statement)
|
60
|
+
|
61
|
+
assert parser.consume().tok_type == TokenType.RETURN # Consume the return token
|
62
|
+
ret = any_expression_match(parser)
|
63
|
+
if ret is None:
|
64
|
+
msg = "ReturnExpression.match called without valid return expression"
|
65
|
+
raise ValueError(msg)
|
66
|
+
return ReturnExpression(ret=ret, variable_statements=statements)
|
67
|
+
|
68
|
+
def children(self) -> list[Expression]:
|
69
|
+
"""Returns a list of child expressions."""
|
70
|
+
return [self.ret, *self.variable_statements]
|
71
|
+
|
72
|
+
def position(self) -> tuple[int, int]:
|
73
|
+
return self.variable_statements[0].position()[0], self.ret.position()[1]
|
74
|
+
|
75
|
+
def full_text(self) -> str:
|
76
|
+
return self.ret.full_text()
|
@@ -0,0 +1,51 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
from pbi_parsers.dax.tokens import Token, TokenType
|
4
|
+
|
5
|
+
from ._base import Expression
|
6
|
+
from ._utils import lexer_reset
|
7
|
+
|
8
|
+
if TYPE_CHECKING:
|
9
|
+
from pbi_parsers.dax.parser import Parser
|
10
|
+
|
11
|
+
|
12
|
+
class TableExpression(Expression):
|
13
|
+
"""Represents a table in DAX.
|
14
|
+
|
15
|
+
Examples:
|
16
|
+
TableName
|
17
|
+
'Table Name'
|
18
|
+
|
19
|
+
"""
|
20
|
+
|
21
|
+
name: Token
|
22
|
+
|
23
|
+
def __init__(self, name: Token) -> None:
|
24
|
+
self.name = name
|
25
|
+
|
26
|
+
def pprint(self) -> str:
|
27
|
+
return f"""
|
28
|
+
Table (
|
29
|
+
{self.name.text}
|
30
|
+
)""".strip()
|
31
|
+
|
32
|
+
@classmethod
|
33
|
+
@lexer_reset
|
34
|
+
def match(cls, parser: "Parser") -> "TableExpression | None":
|
35
|
+
name = parser.consume()
|
36
|
+
if name.tok_type not in {
|
37
|
+
TokenType.SINGLE_QUOTED_IDENTIFIER,
|
38
|
+
TokenType.UNQUOTED_IDENTIFIER,
|
39
|
+
}:
|
40
|
+
return None
|
41
|
+
return TableExpression(name=name)
|
42
|
+
|
43
|
+
def children(self) -> list[Expression]: # noqa: PLR6301
|
44
|
+
"""Returns a list of child expressions."""
|
45
|
+
return []
|
46
|
+
|
47
|
+
def position(self) -> tuple[int, int]:
|
48
|
+
return self.name.text_slice.start, self.name.text_slice.end
|
49
|
+
|
50
|
+
def full_text(self) -> str:
|
51
|
+
return self.name.text_slice.full_text
|
@@ -0,0 +1,68 @@
|
|
1
|
+
import textwrap
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
from pbi_parsers.dax.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.dax.parser import Parser
|
11
|
+
|
12
|
+
|
13
|
+
class VariableExpression(Expression):
|
14
|
+
"""Represents a variable assignment in DAX.
|
15
|
+
|
16
|
+
Examples:
|
17
|
+
VAR x = 1
|
18
|
+
VAR y = x + 2
|
19
|
+
|
20
|
+
VAR z = func()
|
21
|
+
|
22
|
+
"""
|
23
|
+
|
24
|
+
var_name: Token
|
25
|
+
statement: Expression
|
26
|
+
|
27
|
+
def __init__(self, var_name: Token, statement: Expression) -> None:
|
28
|
+
self.var_name = var_name
|
29
|
+
self.statement = statement
|
30
|
+
|
31
|
+
def pprint(self) -> str:
|
32
|
+
statement = textwrap.indent(self.statement.pprint(), " " * 15).lstrip()
|
33
|
+
return f"""
|
34
|
+
Variable (
|
35
|
+
name: {self.var_name.text},
|
36
|
+
statement: {statement}
|
37
|
+
)
|
38
|
+
""".strip()
|
39
|
+
|
40
|
+
@classmethod
|
41
|
+
@lexer_reset
|
42
|
+
def match(cls, parser: "Parser") -> "VariableExpression | None":
|
43
|
+
from . import any_expression_match # noqa: PLC0415
|
44
|
+
|
45
|
+
if not cls.match_tokens(
|
46
|
+
parser,
|
47
|
+
[TokenType.VARIABLE, TokenType.UNQUOTED_IDENTIFIER, TokenType.EQUAL_SIGN],
|
48
|
+
):
|
49
|
+
return None
|
50
|
+
|
51
|
+
parser.consume()
|
52
|
+
var_name = parser.consume()
|
53
|
+
parser.consume()
|
54
|
+
statement = any_expression_match(parser)
|
55
|
+
if statement is None:
|
56
|
+
msg = "VariableExpression.match called without valid inner expression"
|
57
|
+
raise ValueError(msg)
|
58
|
+
return VariableExpression(var_name=var_name, statement=statement)
|
59
|
+
|
60
|
+
def children(self) -> list[Expression]:
|
61
|
+
"""Returns a list of child expressions."""
|
62
|
+
return [self.statement]
|
63
|
+
|
64
|
+
def position(self) -> tuple[int, int]:
|
65
|
+
return self.var_name.text_slice.start, self.statement.position()[1]
|
66
|
+
|
67
|
+
def full_text(self) -> str:
|
68
|
+
return self.var_name.text_slice.full_text
|