-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnodes.py
231 lines (176 loc) · 6.07 KB
/
nodes.py
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
from abc import ABC, abstractmethod
from ..lexer import BaseToken
from ..exceptions import *
from ..filesystem import FileSystem as Fs
class BaseNode(ABC):
"""Node interface"""
@abstractmethod
def __init__(self, *args, **kwargs): ...
@property
@abstractmethod
def line(self) -> int:
"""
:return: line number from which the node was extracted
"""
class NodeWithBody(BaseNode, ABC):
body = []
def push_node_to_body(self, node: BaseNode):
self.body.append(node)
class BasicNode(BaseNode, ABC):
pass
class NamedNode(BaseNode, ABC):
identifier = None
class NodeWithScope(NodeWithBody, NamedNode, ABC):
identifier = None
class PrintableNode(BaseNode, ABC):
def __repr__(self):
text = '<'
for attr_name, attr_value in vars(self).items():
text += f'{attr_name}:{attr_value.text if isinstance(attr_value, BaseToken) else attr_value}, '
text += '>'
return self.__class__.__name__ + text
class VariableNode(BasicNode, PrintableNode, NamedNode):
def __init__(self, identifier: BaseToken):
self.identifier = identifier
@property
def line(self) -> int:
return self.identifier.line
class ValueNode(BasicNode, PrintableNode):
def __init__(self, value: BaseToken):
self.value = value
@property
def line(self) -> int:
return self.value.line
class AssignNode(BasicNode, PrintableNode, NamedNode):
def __init__(self,
identifier: BaseToken,
value_type: BaseNode = None,
value: BaseNode = None):
self.identifier = identifier
self.value_type = value_type
self.value = value
self.definition = True
@property
def line(self) -> int:
return self.identifier.line
class FuncNode(NodeWithScope, PrintableNode, NamedNode):
def __init__(self,
identifier: BaseToken,
arguments: list[AssignNode] = None,
body: list[BaseNode] = None,
return_type: VariableNode = None,
template: bool = False):
self.identifier = identifier
self.arguments = arguments or []
self.body = body or []
self.return_type = return_type
self.template = template
@property
def line(self) -> int:
return self.identifier.line
class CallNode(BasicNode, PrintableNode):
def __init__(self,
identifier: BaseToken,
arguments: list[BaseNode] = None):
self.identifier = identifier
self.arguments = arguments or []
@property
def line(self) -> int:
return self.identifier.line
class LogicOpNode(BasicNode, PrintableNode):
def __init__(self,
left_operand: BaseNode = None,
right_operand: BaseNode = None,
operator: BaseToken = None):
self.left_operand = left_operand
self.right_operand = right_operand
self.operator = operator
self.in_brackets = False
@property
def line(self) -> int:
if not self.left_operand:
return -1
return self.left_operand.line
class ElseNode(NodeWithBody, PrintableNode):
def __init__(self, body: list[BaseNode] = None, ):
self.body = body or []
@property
def line(self) -> int:
if len(self.body) > 0:
return self.body[0].line
return -1
class BinOpNode(BasicNode, PrintableNode):
def __init__(self,
left_operand: BaseNode = None,
right_operand: BaseNode = None,
operator: BaseToken = None,
priority: int = None):
self.left_operand = left_operand
self.right_operand = right_operand
self.operator = operator
self.priority = priority
self.in_brackets = False
@staticmethod
def _get_operand_len(operand: BaseNode):
if isinstance(operand, (VariableNode, ValueNode)):
return 1
elif isinstance(operand, BinOpNode):
return len(operand)
return 0
def __len__(self):
tokens_number = 1
tokens_number += self._get_operand_len(self.left_operand)
tokens_number += self._get_operand_len(self.right_operand)
return tokens_number
def __repr__(self):
op_text = f'{self.left_operand} {self.operator.text} {self.right_operand}'
if self.in_brackets:
op_text = '( ' + op_text + ' )'
return self.__class__.__name__ + f'<{op_text}>'
@property
def line(self) -> int:
if self.left_operand:
return self.left_operand.line
return -1
class IfNode(NodeWithBody, PrintableNode):
def __init__(self,
condition: LogicOpNode | BinOpNode = None,
body: list[BaseNode] = None,
elif_cases: list = None,
else_case: ElseNode = None,
is_elif: bool = False):
self.condition = condition
self.body = body or []
self.elif_cases: list[IfNode.__init__] = elif_cases
self.else_case = else_case
self.is_elif = is_elif
@property
def line(self) -> int:
return self.condition.line
# class ForNode(BellyNode, PrintableNode):
# def __init__(self,
# body: list[BaseNode] = None,
# else_body: list[BaseNode] = None
# ):
# pass
class WhileNode(NodeWithBody, PrintableNode):
def __init__(self,
condition: LogicOpNode | BinOpNode = None,
body: list[BaseNode] = None,
else_body: list[BaseNode] = None):
self.condition = condition
self.else_body = else_body or []
self.body = body or []
@property
def line(self) -> int:
if not self.condition:
return -1
return self.condition.line
class ReturnNode(BasicNode, PrintableNode):
def __init__(self, node: BaseNode):
self.node = node
@property
def line(self) -> int:
if not self.node:
return -1
return self.node.line