storm-cli 1.0.0__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.
- main.py +753 -0
- src/__init__.py +2 -0
- src/ast.py +100 -0
- src/column.py +56 -0
- src/enum.py +21 -0
- src/error_handler.py +35 -0
- src/generic_controller_csharp.py +106 -0
- src/generic_mapper_csharp.py +35 -0
- src/generic_pagination_csharp.py +44 -0
- src/generic_query_chsarp.py +18 -0
- src/generic_service_csharp.py +112 -0
- src/interpreter.py +2300 -0
- src/keyword.py +18 -0
- src/parser.py +397 -0
- src/pos.py +11 -0
- src/table.py +37 -0
- src/template.py +14 -0
- src/tok.py +12 -0
- src/tok_type.py +13 -0
- src/tokenizer.py +238 -0
- storm_cli-1.0.0.dist-info/METADATA +350 -0
- storm_cli-1.0.0.dist-info/RECORD +26 -0
- storm_cli-1.0.0.dist-info/WHEEL +5 -0
- storm_cli-1.0.0.dist-info/entry_points.txt +2 -0
- storm_cli-1.0.0.dist-info/licenses/LICENSE +21 -0
- storm_cli-1.0.0.dist-info/top_level.txt +2 -0
src/keyword.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Keyword(Enum):
|
|
5
|
+
ENUM = 'enum'
|
|
6
|
+
TABLE = 'table'
|
|
7
|
+
UUID = 'uuid'
|
|
8
|
+
INT = 'int'
|
|
9
|
+
LONG = 'long'
|
|
10
|
+
FLOAT = 'float'
|
|
11
|
+
DOUBLE = 'double'
|
|
12
|
+
DATETIME = 'datetime'
|
|
13
|
+
STRING = 'string'
|
|
14
|
+
BOOL = 'bool'
|
|
15
|
+
PK = 'pk'
|
|
16
|
+
UNIQUE = 'unique'
|
|
17
|
+
TRUE = 'true'
|
|
18
|
+
FALSE = 'false'
|
src/parser.py
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
from src.ast import AstType, ASTNode
|
|
2
|
+
from src.tokenizer import Tokenizer
|
|
3
|
+
from src.tok_type import TokenType
|
|
4
|
+
from src.keyword import Keyword
|
|
5
|
+
from src.error_handler import raise_error
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Parser(Tokenizer):
|
|
9
|
+
def __init__(self, fpath):
|
|
10
|
+
with open(fpath) as f:
|
|
11
|
+
fdata = f.read()
|
|
12
|
+
super().__init__(fpath, fdata)
|
|
13
|
+
self.current_token = None
|
|
14
|
+
|
|
15
|
+
def next_token(self):
|
|
16
|
+
self.current_token = self.nextToken()
|
|
17
|
+
|
|
18
|
+
def __check_type(self, expected_type):
|
|
19
|
+
if self.current_token is None:
|
|
20
|
+
raise_error(self.file_path, self.file_data, f"Expected token of type {expected_type.value}, but got None", self._pos())
|
|
21
|
+
return self.current_token.tok_type == expected_type
|
|
22
|
+
|
|
23
|
+
def __check_value(self, expected_value):
|
|
24
|
+
if self.current_token is None:
|
|
25
|
+
raise_error(self.file_path, self.file_data, f"Expected token with value '{expected_value}', but got None", self._pos())
|
|
26
|
+
return self.current_token.value == expected_value and (
|
|
27
|
+
self.__check_type(TokenType.KEYWORD) or self.__check_type(TokenType.SYMBOL)
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def __consume_type(self, expected_type):
|
|
31
|
+
if self.current_token is None:
|
|
32
|
+
raise_error(self.file_path, self.file_data, f"Expected token of type {expected_type.value}, but got None", self._pos())
|
|
33
|
+
if self.current_token.tok_type != expected_type:
|
|
34
|
+
raise_error(self.file_path, self.file_data, f"Expected token of type {expected_type.value}, but got {self.current_token.tok_type.value}", self.current_token.position)
|
|
35
|
+
self.next_token()
|
|
36
|
+
|
|
37
|
+
def __consume_value(self, expected_value):
|
|
38
|
+
if self.current_token is None:
|
|
39
|
+
raise_error(self.file_path, self.file_data, f"Expected token with value '{expected_value}', but got None", self._pos())
|
|
40
|
+
if self.current_token.value != expected_value:
|
|
41
|
+
raise_error(self.file_path, self.file_data, f"Expected token with value '{expected_value}', but got '{self.current_token.value}'", self.current_token.position)
|
|
42
|
+
self.next_token()
|
|
43
|
+
|
|
44
|
+
def _parse_primary(self):
|
|
45
|
+
if self.__check_type(TokenType.STRING):
|
|
46
|
+
node = ASTNode.create_terminal_node(AstType.STR_LITERAL, self.current_token.value, self.current_token.position)
|
|
47
|
+
self.__consume_type(TokenType.STRING)
|
|
48
|
+
return node
|
|
49
|
+
if self.current_token.tok_type in (TokenType.INT, TokenType.HEX, TokenType.OCT, TokenType.BIN):
|
|
50
|
+
node = ASTNode.create_terminal_node(AstType.INT_LITERAL, self.current_token.value, self.current_token.position)
|
|
51
|
+
self.next_token()
|
|
52
|
+
return node
|
|
53
|
+
if self.__check_type(TokenType.KEYWORD) and self.current_token.value in (Keyword.TRUE.value, Keyword.FALSE.value):
|
|
54
|
+
node = ASTNode.create_terminal_node(AstType.BOOL_LITERAL, self.current_token.value, self.current_token.position)
|
|
55
|
+
self.__consume_type(TokenType.KEYWORD)
|
|
56
|
+
return node
|
|
57
|
+
if self.__check_type(TokenType.IDENTIFIER):
|
|
58
|
+
node = ASTNode.create_terminal_node(AstType.IDENTIFIER, self.current_token.value, self.current_token.position)
|
|
59
|
+
self.__consume_type(TokenType.IDENTIFIER)
|
|
60
|
+
return node
|
|
61
|
+
if self.__check_value('('):
|
|
62
|
+
self.__consume_value('(')
|
|
63
|
+
node = self._parse_expression()
|
|
64
|
+
self.__consume_value(')')
|
|
65
|
+
return node
|
|
66
|
+
raise_error(self.file_path, self.file_data, f"unexpected token in expression", self.current_token.position)
|
|
67
|
+
|
|
68
|
+
def _parse_unary(self):
|
|
69
|
+
if self.current_token and self.__check_type(TokenType.SYMBOL) and self.current_token.value in ('+', '-', '!', '~'):
|
|
70
|
+
pos = self.current_token.position
|
|
71
|
+
op = self.current_token.value
|
|
72
|
+
self.__consume_value(op)
|
|
73
|
+
operand = self._parse_unary()
|
|
74
|
+
if operand is None:
|
|
75
|
+
raise_error(self.file_path, self.file_data, "expected expression after unary operator", pos)
|
|
76
|
+
ast_type = {
|
|
77
|
+
'+': AstType.UNARY_PLUS,
|
|
78
|
+
'-': AstType.UNARY_MINUS,
|
|
79
|
+
'!': AstType.UNARY_NOT,
|
|
80
|
+
'~': AstType.UNARY_BITWISE_NOT,
|
|
81
|
+
}[op]
|
|
82
|
+
return ASTNode.create_unary(ast_type, operand, pos)
|
|
83
|
+
return self._parse_primary()
|
|
84
|
+
|
|
85
|
+
def _parse_multiplicative(self):
|
|
86
|
+
left = self._parse_unary()
|
|
87
|
+
while self.current_token and self.__check_type(TokenType.SYMBOL) and self.current_token.value in ('*', '/', '%'):
|
|
88
|
+
pos = self.current_token.position
|
|
89
|
+
op = self.current_token.value
|
|
90
|
+
self.__consume_value(op)
|
|
91
|
+
right = self._parse_unary()
|
|
92
|
+
if right is None:
|
|
93
|
+
raise_error(self.file_path, self.file_data, "expected expression", pos)
|
|
94
|
+
ast_type = {
|
|
95
|
+
'*': AstType.BINARY_MUL,
|
|
96
|
+
'/': AstType.BINARY_DIV,
|
|
97
|
+
'%': AstType.BINARY_MOD,
|
|
98
|
+
}[op]
|
|
99
|
+
left = ASTNode.create_binary(ast_type, left, right, pos)
|
|
100
|
+
return left
|
|
101
|
+
|
|
102
|
+
def _parse_additive(self):
|
|
103
|
+
left = self._parse_multiplicative()
|
|
104
|
+
while self.current_token and self.__check_type(TokenType.SYMBOL) and self.current_token.value in ('+', '-'):
|
|
105
|
+
pos = self.current_token.position
|
|
106
|
+
op = self.current_token.value
|
|
107
|
+
self.__consume_value(op)
|
|
108
|
+
right = self._parse_multiplicative()
|
|
109
|
+
if right is None:
|
|
110
|
+
raise_error(self.file_path, self.file_data, "expected expression", pos)
|
|
111
|
+
ast_type = AstType.BINARY_ADD if op == '+' else AstType.BINARY_SUB
|
|
112
|
+
left = ASTNode.create_binary(ast_type, left, right, pos)
|
|
113
|
+
return left
|
|
114
|
+
|
|
115
|
+
def _parse_shift(self):
|
|
116
|
+
left = self._parse_additive()
|
|
117
|
+
while self.current_token and self.__check_type(TokenType.SYMBOL) and self.current_token.value in ('<<', '>>'):
|
|
118
|
+
pos = self.current_token.position
|
|
119
|
+
op = self.current_token.value
|
|
120
|
+
self.__consume_value(op)
|
|
121
|
+
right = self._parse_additive()
|
|
122
|
+
if right is None:
|
|
123
|
+
raise_error(self.file_path, self.file_data, "expected expression", pos)
|
|
124
|
+
ast_type = AstType.BINARY_SHL if op == '<<' else AstType.BINARY_SHR
|
|
125
|
+
left = ASTNode.create_binary(ast_type, left, right, pos)
|
|
126
|
+
return left
|
|
127
|
+
|
|
128
|
+
def _parse_relational(self):
|
|
129
|
+
left = self._parse_shift()
|
|
130
|
+
while self.current_token and self.__check_type(TokenType.SYMBOL) and self.current_token.value in ('<', '<=', '>', '>='):
|
|
131
|
+
pos = self.current_token.position
|
|
132
|
+
op = self.current_token.value
|
|
133
|
+
self.__consume_value(op)
|
|
134
|
+
right = self._parse_shift()
|
|
135
|
+
if right is None:
|
|
136
|
+
raise_error(self.file_path, self.file_data, "expected expression", pos)
|
|
137
|
+
ast_type = {
|
|
138
|
+
'<': AstType.BINARY_LT,
|
|
139
|
+
'<=': AstType.BINARY_LTE,
|
|
140
|
+
'>': AstType.BINARY_GT,
|
|
141
|
+
'>=': AstType.BINARY_GTE,
|
|
142
|
+
}[op]
|
|
143
|
+
left = ASTNode.create_binary(ast_type, left, right, pos)
|
|
144
|
+
return left
|
|
145
|
+
|
|
146
|
+
def _parse_equality(self):
|
|
147
|
+
left = self._parse_relational()
|
|
148
|
+
while self.current_token and self.__check_type(TokenType.SYMBOL) and self.current_token.value in ('==', '!='):
|
|
149
|
+
pos = self.current_token.position
|
|
150
|
+
op = self.current_token.value
|
|
151
|
+
self.__consume_value(op)
|
|
152
|
+
right = self._parse_relational()
|
|
153
|
+
if right is None:
|
|
154
|
+
raise_error(self.file_path, self.file_data, "expected expression", pos)
|
|
155
|
+
ast_type = AstType.BINARY_EQ if op == '==' else AstType.BINARY_NE
|
|
156
|
+
left = ASTNode.create_binary(ast_type, left, right, pos)
|
|
157
|
+
return left
|
|
158
|
+
|
|
159
|
+
def _parse_bitwise_and(self):
|
|
160
|
+
left = self._parse_equality()
|
|
161
|
+
while self.current_token and self.__check_type(TokenType.SYMBOL) and self.current_token.value == '&':
|
|
162
|
+
pos = self.current_token.position
|
|
163
|
+
self.__consume_value('&')
|
|
164
|
+
right = self._parse_equality()
|
|
165
|
+
if right is None:
|
|
166
|
+
raise_error(self.file_path, self.file_data, "expected expression", pos)
|
|
167
|
+
left = ASTNode.create_binary(AstType.BINARY_BITWISE_AND, left, right, pos)
|
|
168
|
+
return left
|
|
169
|
+
|
|
170
|
+
def _parse_bitwise_xor(self):
|
|
171
|
+
left = self._parse_bitwise_and()
|
|
172
|
+
while self.current_token and self.__check_type(TokenType.SYMBOL) and self.current_token.value == '^':
|
|
173
|
+
pos = self.current_token.position
|
|
174
|
+
self.__consume_value('^')
|
|
175
|
+
right = self._parse_bitwise_and()
|
|
176
|
+
if right is None:
|
|
177
|
+
raise_error(self.file_path, self.file_data, "expected expression", pos)
|
|
178
|
+
left = ASTNode.create_binary(AstType.BINARY_BITWISE_XOR, left, right, pos)
|
|
179
|
+
return left
|
|
180
|
+
|
|
181
|
+
def _parse_bitwise_or(self):
|
|
182
|
+
left = self._parse_bitwise_xor()
|
|
183
|
+
while self.current_token and self.__check_type(TokenType.SYMBOL) and self.current_token.value == '|':
|
|
184
|
+
pos = self.current_token.position
|
|
185
|
+
self.__consume_value('|')
|
|
186
|
+
right = self._parse_bitwise_xor()
|
|
187
|
+
if right is None:
|
|
188
|
+
raise_error(self.file_path, self.file_data, "expected expression", pos)
|
|
189
|
+
left = ASTNode.create_binary(AstType.BINARY_BITWISE_OR, left, right, pos)
|
|
190
|
+
return left
|
|
191
|
+
|
|
192
|
+
def _parse_logical_and(self):
|
|
193
|
+
left = self._parse_bitwise_or()
|
|
194
|
+
while self.current_token and self.__check_type(TokenType.SYMBOL) and self.current_token.value == '&&':
|
|
195
|
+
pos = self.current_token.position
|
|
196
|
+
self.__consume_value('&&')
|
|
197
|
+
right = self._parse_bitwise_or()
|
|
198
|
+
if right is None:
|
|
199
|
+
raise_error(self.file_path, self.file_data, "expected expression", pos)
|
|
200
|
+
left = ASTNode.create_binary(AstType.BINARY_LOGICAL_AND, left, right, pos)
|
|
201
|
+
return left
|
|
202
|
+
|
|
203
|
+
def _parse_logical_or(self):
|
|
204
|
+
left = self._parse_logical_and()
|
|
205
|
+
while self.current_token and self.__check_type(TokenType.SYMBOL) and self.current_token.value == '||':
|
|
206
|
+
pos = self.current_token.position
|
|
207
|
+
self.__consume_value('||')
|
|
208
|
+
right = self._parse_logical_and()
|
|
209
|
+
if right is None:
|
|
210
|
+
raise_error(self.file_path, self.file_data, "expected expression", pos)
|
|
211
|
+
left = ASTNode.create_binary(AstType.BINARY_LOGICAL_OR, left, right, pos)
|
|
212
|
+
return left
|
|
213
|
+
|
|
214
|
+
def _parse_expression(self):
|
|
215
|
+
return self._parse_logical_or()
|
|
216
|
+
|
|
217
|
+
def _parse_value(self):
|
|
218
|
+
if self.current_token.tok_type == TokenType.STRING:
|
|
219
|
+
node = ASTNode.create_terminal_node(AstType.STR_LITERAL, self.current_token.value, self.current_token.position)
|
|
220
|
+
self.__consume_type(TokenType.STRING)
|
|
221
|
+
elif self.current_token.tok_type in (TokenType.INT, TokenType.HEX, TokenType.OCT, TokenType.BIN):
|
|
222
|
+
node = ASTNode.create_terminal_node(AstType.INT_LITERAL, self.current_token.value, self.current_token.position)
|
|
223
|
+
self.next_token()
|
|
224
|
+
elif self.current_token.tok_type == TokenType.KEYWORD and self.current_token.value in (Keyword.TRUE.value, Keyword.FALSE.value):
|
|
225
|
+
node = ASTNode.create_terminal_node(AstType.BOOL_LITERAL, self.current_token.value, self.current_token.position)
|
|
226
|
+
self.__consume_type(TokenType.KEYWORD)
|
|
227
|
+
elif self.current_token.tok_type == TokenType.IDENTIFIER:
|
|
228
|
+
node = ASTNode.create_terminal_node(AstType.IDENTIFIER, self.current_token.value, self.current_token.position)
|
|
229
|
+
self.__consume_type(TokenType.IDENTIFIER)
|
|
230
|
+
else:
|
|
231
|
+
raise_error(self.file_path, self.file_data, f"unexpected token in value", self.current_token.position)
|
|
232
|
+
return node
|
|
233
|
+
|
|
234
|
+
def _parse_enum_item(self):
|
|
235
|
+
pos = self.current_token.position
|
|
236
|
+
name_node = ASTNode.create_terminal_node(AstType.IDENTIFIER, self.current_token.value, self.current_token.position)
|
|
237
|
+
self.__consume_type(TokenType.IDENTIFIER)
|
|
238
|
+
|
|
239
|
+
node = ASTNode.create_enum_item(pos)
|
|
240
|
+
node.a = name_node
|
|
241
|
+
|
|
242
|
+
if self.__check_value('='):
|
|
243
|
+
self.__consume_value('=')
|
|
244
|
+
node.b = self._parse_expression()
|
|
245
|
+
|
|
246
|
+
return node
|
|
247
|
+
|
|
248
|
+
def _parse_enum(self):
|
|
249
|
+
pos = self.current_token.position
|
|
250
|
+
self.__consume_value(Keyword.ENUM.value)
|
|
251
|
+
name_node = ASTNode.create_terminal_node(AstType.IDENTIFIER, self.current_token.value, self.current_token.position)
|
|
252
|
+
self.__consume_type(TokenType.IDENTIFIER)
|
|
253
|
+
self.__consume_value('{')
|
|
254
|
+
|
|
255
|
+
node = ASTNode.create_enum_decl(pos)
|
|
256
|
+
node.a = name_node
|
|
257
|
+
|
|
258
|
+
prev = None
|
|
259
|
+
while not self.__check_value('}'):
|
|
260
|
+
item = self._parse_enum_item()
|
|
261
|
+
if prev:
|
|
262
|
+
prev.next = item
|
|
263
|
+
else:
|
|
264
|
+
node.b = item
|
|
265
|
+
prev = item
|
|
266
|
+
if self.__check_value(','):
|
|
267
|
+
self.__consume_value(',')
|
|
268
|
+
|
|
269
|
+
self.__consume_value('}')
|
|
270
|
+
return node
|
|
271
|
+
|
|
272
|
+
def _parse_attr(self):
|
|
273
|
+
pos = self.current_token.position
|
|
274
|
+
name_node = ASTNode.create_terminal_node(AstType.IDENTIFIER, self.current_token.value, self.current_token.position)
|
|
275
|
+
self.__consume_type(TokenType.IDENTIFIER)
|
|
276
|
+
self.__consume_value('=')
|
|
277
|
+
|
|
278
|
+
node = ASTNode.create_field_attr(pos)
|
|
279
|
+
node.a = name_node
|
|
280
|
+
|
|
281
|
+
if self.current_token.tok_type == TokenType.STRING:
|
|
282
|
+
val_node = ASTNode.create_terminal_node(AstType.STR_LITERAL, self.current_token.value, self.current_token.position)
|
|
283
|
+
self.__consume_type(TokenType.STRING)
|
|
284
|
+
elif self.current_token.tok_type in (TokenType.INT, TokenType.HEX, TokenType.OCT, TokenType.BIN):
|
|
285
|
+
val_node = ASTNode.create_terminal_node(AstType.INT_LITERAL, self.current_token.value, self.current_token.position)
|
|
286
|
+
self.next_token()
|
|
287
|
+
else:
|
|
288
|
+
raise_error(self.file_path, self.file_data, f"expected value in attribute", self.current_token.position)
|
|
289
|
+
|
|
290
|
+
node.b = val_node
|
|
291
|
+
return node
|
|
292
|
+
|
|
293
|
+
def _parse_attrs(self):
|
|
294
|
+
pos = self.current_token.position
|
|
295
|
+
self.__consume_value('(')
|
|
296
|
+
node = ASTNode.create_field_attrs(pos)
|
|
297
|
+
|
|
298
|
+
prev = None
|
|
299
|
+
while not self.__check_value(')'):
|
|
300
|
+
attr = self._parse_attr()
|
|
301
|
+
if prev:
|
|
302
|
+
prev.next = attr
|
|
303
|
+
else:
|
|
304
|
+
node.a = attr
|
|
305
|
+
prev = attr
|
|
306
|
+
if self.__check_value(','):
|
|
307
|
+
self.__consume_value(',')
|
|
308
|
+
|
|
309
|
+
self.__consume_value(')')
|
|
310
|
+
return node
|
|
311
|
+
|
|
312
|
+
def _parse_type(self):
|
|
313
|
+
pos = self.current_token.position
|
|
314
|
+
if not (self.__check_type(TokenType.IDENTIFIER) or self.__check_type(TokenType.KEYWORD)):
|
|
315
|
+
raise_error(self.file_path, self.file_data, f"expected type name, got '{self.current_token.value}'", self.current_token.position)
|
|
316
|
+
type_name = self.current_token.value
|
|
317
|
+
self.next_token()
|
|
318
|
+
|
|
319
|
+
if self.__check_value('?'):
|
|
320
|
+
self.__consume_value('?')
|
|
321
|
+
type_name += '?'
|
|
322
|
+
|
|
323
|
+
node = ASTNode.create_terminal_node(AstType.TYPE, type_name, pos)
|
|
324
|
+
|
|
325
|
+
if self.__check_value('('):
|
|
326
|
+
node.a = self._parse_attrs()
|
|
327
|
+
|
|
328
|
+
return node
|
|
329
|
+
|
|
330
|
+
def _parse_field(self):
|
|
331
|
+
pos = self.current_token.position
|
|
332
|
+
name_node = ASTNode.create_terminal_node(AstType.IDENTIFIER, self.current_token.value, self.current_token.position)
|
|
333
|
+
self.__consume_type(TokenType.IDENTIFIER)
|
|
334
|
+
self.__consume_value(':')
|
|
335
|
+
|
|
336
|
+
type_node = self._parse_type()
|
|
337
|
+
|
|
338
|
+
node = ASTNode.create_field_decl(pos)
|
|
339
|
+
node.a = name_node
|
|
340
|
+
node.b = type_node
|
|
341
|
+
|
|
342
|
+
if self.__check_value('='):
|
|
343
|
+
self.__consume_value('=')
|
|
344
|
+
val_node = self._parse_expression()
|
|
345
|
+
node.d = val_node
|
|
346
|
+
|
|
347
|
+
if self.__check_type(TokenType.KEYWORD) and self.current_token.value in (Keyword.PK.value, Keyword.UNIQUE.value):
|
|
348
|
+
node.value = self.current_token.value
|
|
349
|
+
self.__consume_type(TokenType.KEYWORD)
|
|
350
|
+
|
|
351
|
+
if self.__check_value(';'):
|
|
352
|
+
self.__consume_value(';')
|
|
353
|
+
|
|
354
|
+
return node
|
|
355
|
+
|
|
356
|
+
def _parse_table(self):
|
|
357
|
+
pos = self.current_token.position
|
|
358
|
+
self.__consume_value(Keyword.TABLE.value)
|
|
359
|
+
name_node = ASTNode.create_terminal_node(AstType.IDENTIFIER, self.current_token.value, self.current_token.position)
|
|
360
|
+
self.__consume_type(TokenType.IDENTIFIER)
|
|
361
|
+
self.__consume_value('{')
|
|
362
|
+
|
|
363
|
+
node = ASTNode.create_table_decl(pos)
|
|
364
|
+
node.a = name_node
|
|
365
|
+
|
|
366
|
+
prev = None
|
|
367
|
+
while not self.__check_value('}'):
|
|
368
|
+
field = self._parse_field()
|
|
369
|
+
if prev:
|
|
370
|
+
prev.next = field
|
|
371
|
+
else:
|
|
372
|
+
node.b = field
|
|
373
|
+
prev = field
|
|
374
|
+
|
|
375
|
+
self.__consume_value('}')
|
|
376
|
+
return node
|
|
377
|
+
|
|
378
|
+
def _parse_decl(self):
|
|
379
|
+
if self.__check_type(TokenType.KEYWORD):
|
|
380
|
+
if self.current_token.value == Keyword.ENUM.value:
|
|
381
|
+
return self._parse_enum()
|
|
382
|
+
if self.current_token.value == Keyword.TABLE.value:
|
|
383
|
+
return self._parse_table()
|
|
384
|
+
raise_error(self.file_path, self.file_data, f"unexpected token '{self.current_token.value}'", self.current_token.position)
|
|
385
|
+
|
|
386
|
+
def _parse_program(self):
|
|
387
|
+
node = ASTNode.create_program(self.current_token.position)
|
|
388
|
+
last = node
|
|
389
|
+
while self.current_token.tok_type != TokenType.EOF:
|
|
390
|
+
decl = self._parse_decl()
|
|
391
|
+
last.next = decl
|
|
392
|
+
last = decl
|
|
393
|
+
return node
|
|
394
|
+
|
|
395
|
+
def parse(self):
|
|
396
|
+
self.next_token()
|
|
397
|
+
return self._parse_program()
|
src/pos.py
ADDED
src/table.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
from src.column import ColumnType
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
PRIMITIVE_TYPES = {'int', 'long', 'float', 'double', 'string', 'bool', 'uuid', 'datetime'}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Table:
|
|
12
|
+
def __init__(self, name, columns=[]):
|
|
13
|
+
self.name = name
|
|
14
|
+
self.columns: list[tuple[str, ColumnType]] = columns
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
def from_ast(cls, node, table_names=None):
|
|
18
|
+
table_names = table_names or set()
|
|
19
|
+
name = node.a.value
|
|
20
|
+
columns = []
|
|
21
|
+
cur = node.b
|
|
22
|
+
while cur:
|
|
23
|
+
col_name = cur.a.value
|
|
24
|
+
type_node = cur.b
|
|
25
|
+
col_type = ColumnType.from_ast(type_node, table_names)
|
|
26
|
+
if cur.d is not None:
|
|
27
|
+
col_type.default_value_node = cur.d
|
|
28
|
+
columns.append((col_name, col_type))
|
|
29
|
+
cur = cur.next
|
|
30
|
+
return cls(name, columns)
|
|
31
|
+
|
|
32
|
+
def dependencies(self):
|
|
33
|
+
deps = set()
|
|
34
|
+
for _, col_type in self.columns:
|
|
35
|
+
if col_type.is_fk and col_type.ref_table:
|
|
36
|
+
deps.add(col_type.ref_table)
|
|
37
|
+
return deps
|
src/template.py
ADDED
src/tok.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from src.pos import Pos
|
|
2
|
+
from src.tok_type import TokenType
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Tok:
|
|
6
|
+
def __init__(self, tok_type: TokenType, value, position: Pos):
|
|
7
|
+
self.tok_type = tok_type
|
|
8
|
+
self.value = value
|
|
9
|
+
self.position = position
|
|
10
|
+
|
|
11
|
+
def __repr__(self):
|
|
12
|
+
return f"Tok({self.tok_type.value}, {self.value}, {self.position})"
|