1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
from typing import Any
from .modifier import Modifier
class ExpressionParser:
__data: dict[str, Any]
__modifiers: list[type[Modifier]]
def __init__(self, data: dict[str, Any], modifiers: list[type[Modifier]]) -> None:
self.__data = data
self.__modifiers = modifiers
def parse(self, expression: str) -> Any:
# no curly brackets means that the whole thing is an interpolation
if expression.count("{") == 0 and expression.count("}") == 0:
parsed_interpolation = self.__parse_interpolation(expression)
return parsed_interpolation
# uneven curly brackets means invalid syntax
if expression.count("{") != expression.count("}"):
return expression
# otherwise only parts of it are
parsed_expression = ""
interp_start = None
interp_end = None
for idx, char in enumerate(expression):
parsed_expression += char
if char == "{":
interp_start = idx
if char == "}":
interp_end = idx + 1
if interp_start is not None and interp_end is not None:
interp = expression[interp_start:interp_end]
parsed_interp = self.__parse_interpolation(interp[1:-1])
parsed_expression = parsed_expression.replace(interp, parsed_interp)
interp_start = None
interp_end = None
return parsed_expression
def __parse_interpolation(self, interpolation: str) -> Any:
parts = interpolation.split("|")
value = self.__var_to_val(parts[0].strip())
modifiers = [x.strip() for x in parts[1:]] if len(parts) > 1 else []
for modifier in modifiers:
modifier_name = ""
args_start = None
args_end = None
modifier_opts = []
for idx, char in enumerate(modifier):
if char == "(":
args_start = idx + 1
if char == ")":
args_end = idx
if args_start is None and args_end is None:
modifier_name += char
if args_start and args_end:
args_str = modifier[args_start:args_end]
modifier_opts = self.__parse_args_str_to_args(args_str)
value = self.__modify_value(value, modifier_name, modifier_opts)
return value
@staticmethod
def __parse_args_str_to_args(args_str) -> list[str | int | float | bool]:
args = []
for idx, char in enumerate(args_str):
if len(args) == 0:
args.append("")
if char == "," and args[-1].count('"') % 2 == 0:
args.append("")
else:
args[-1] += char
parsed_args = []
for arg in args:
if arg.startswith("'") and arg.endswith("'"):
parsed_args.append(arg[1:-1])
continue
if arg.startswith('"') and arg.endswith('"'):
parsed_args.append(arg[1:-1])
continue
if all([x in "1234567890" for x in arg.lstrip("-")]):
parsed_args.append(int(arg))
continue
if all([x in "1234567890." for x in arg.lstrip("-")]):
parsed_args.append(float(arg))
continue
if arg == "true" or arg == "false":
parsed_args.append(True if arg == "true" else False)
return parsed_args
def __modify_value(self, value: Any, modifier_name: str, modifier_opts: list[Any]) -> Any:
for modifier in self.__modifiers:
if modifier.__name__ == modifier_name:
return modifier().modify(value, modifier_opts)
return value
def __var_to_val(self, var: str) -> Any:
"""
Turns a expression var into the value it maps to
in the data dictionary.
"""
parts = var.split(".")
value = self.__data
for part in parts:
if part in value:
value = value[part]
else:
return None
return value
|