lucidaflow 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.
Potentially problematic release.
This version of lucidaflow might be problematic. Click here for more details.
- lucidaflow/__init__.py +0 -0
- lucidaflow/lucida_analyzer.py +1043 -0
- lucidaflow/lucida_ast.py +321 -0
- lucidaflow/lucida_errors.py +26 -0
- lucidaflow/lucida_interpreter.py +821 -0
- lucidaflow/lucida_lexer.py +248 -0
- lucidaflow/lucida_parser.py +584 -0
- lucidaflow/lucida_stdlib.py +249 -0
- lucidaflow/lucida_symbols.py +176 -0
- lucidaflow-1.0.0.dist-info/METADATA +1567 -0
- lucidaflow-1.0.0.dist-info/RECORD +14 -0
- lucidaflow-1.0.0.dist-info/WHEEL +5 -0
- lucidaflow-1.0.0.dist-info/licenses/LICENSE +21 -0
- lucidaflow-1.0.0.dist-info/top_level.txt +1 -0
lucidaflow/lucida_ast.py
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
# Copie e cole TODO este conteúdo em seu arquivo lucida_ast.py
|
|
2
|
+
|
|
3
|
+
class ASTNode:
|
|
4
|
+
"""
|
|
5
|
+
Nó base para todos os outros nós da AST.
|
|
6
|
+
Agora, cada nó armazena sua localização (linha e coluna)
|
|
7
|
+
a partir de um token de referência.
|
|
8
|
+
"""
|
|
9
|
+
def __init__(self, token=None):
|
|
10
|
+
self.token = token
|
|
11
|
+
if token:
|
|
12
|
+
self.line = token.line
|
|
13
|
+
self.col = token.col
|
|
14
|
+
else:
|
|
15
|
+
self.line = 0
|
|
16
|
+
self.col = 0
|
|
17
|
+
|
|
18
|
+
# --- Nós de Expressão (representam valores) ---
|
|
19
|
+
|
|
20
|
+
class SuperNode(ASTNode):
|
|
21
|
+
"""Representa a palavra-chave 'super'."""
|
|
22
|
+
def __init__(self, token):
|
|
23
|
+
super().__init__(token)
|
|
24
|
+
self.token = token
|
|
25
|
+
|
|
26
|
+
def __repr__(self):
|
|
27
|
+
return f"SuperNode"
|
|
28
|
+
|
|
29
|
+
class NumberNode(ASTNode):
|
|
30
|
+
def __init__(self, token):
|
|
31
|
+
super().__init__(token)
|
|
32
|
+
self.token = token
|
|
33
|
+
self.value = token.value
|
|
34
|
+
def __repr__(self):
|
|
35
|
+
return f"NumberNode({self.value})"
|
|
36
|
+
|
|
37
|
+
class StringNode(ASTNode):
|
|
38
|
+
def __init__(self, token):
|
|
39
|
+
super().__init__(token)
|
|
40
|
+
self.token = token
|
|
41
|
+
self.value = token.value
|
|
42
|
+
def __repr__(self):
|
|
43
|
+
return f"StringNode({repr(self.value)})"
|
|
44
|
+
|
|
45
|
+
class BoolNode(ASTNode):
|
|
46
|
+
def __init__(self, token):
|
|
47
|
+
super().__init__(token)
|
|
48
|
+
self.token = token
|
|
49
|
+
self.value = True if token.value == 'true' else False
|
|
50
|
+
def __repr__(self):
|
|
51
|
+
return f"BoolNode({self.value})"
|
|
52
|
+
|
|
53
|
+
class NullNode(ASTNode):
|
|
54
|
+
def __init__(self, token):
|
|
55
|
+
super().__init__(token)
|
|
56
|
+
self.token = token
|
|
57
|
+
self.value = None
|
|
58
|
+
def __repr__(self):
|
|
59
|
+
return "NullNode"
|
|
60
|
+
|
|
61
|
+
class UnaryOpNode(ASTNode):
|
|
62
|
+
def __init__(self, op_token, node):
|
|
63
|
+
super().__init__(op_token)
|
|
64
|
+
self.op_token = op_token
|
|
65
|
+
self.node = node
|
|
66
|
+
def __repr__(self):
|
|
67
|
+
return f"UnaryOpNode(op={self.op_token.value}, expr={self.node})"
|
|
68
|
+
|
|
69
|
+
class BinOpNode(ASTNode):
|
|
70
|
+
def __init__(self, left_node, op_token, right_node):
|
|
71
|
+
super().__init__(op_token)
|
|
72
|
+
self.left_node = left_node
|
|
73
|
+
self.op_token = op_token
|
|
74
|
+
self.right_node = right_node
|
|
75
|
+
def __repr__(self):
|
|
76
|
+
return f"BinOpNode({self.left_node}, {self.op_token.value}, {self.right_node})"
|
|
77
|
+
|
|
78
|
+
class TernaryOpNode(ASTNode):
|
|
79
|
+
# ATUALIZADO para a nova sintaxe
|
|
80
|
+
def __init__(self, condition_node, question_token, true_expr, false_expr):
|
|
81
|
+
super().__init__(question_token) # A posição é a do '?'
|
|
82
|
+
self.condition_node = condition_node
|
|
83
|
+
self.true_expr = true_expr
|
|
84
|
+
self.false_expr = false_expr
|
|
85
|
+
def __repr__(self):
|
|
86
|
+
return f"TernaryOpNode({self.condition_node} ? {self.true_expr} : {self.false_expr})"
|
|
87
|
+
|
|
88
|
+
class ListNode(ASTNode):
|
|
89
|
+
# NOTA: O Parser precisa passar o token de abertura '['
|
|
90
|
+
def __init__(self, start_token, element_nodes):
|
|
91
|
+
super().__init__(start_token)
|
|
92
|
+
self.element_nodes = element_nodes
|
|
93
|
+
def __repr__(self):
|
|
94
|
+
return f"ListNode(elements={self.element_nodes})"
|
|
95
|
+
|
|
96
|
+
class TupleNode(ASTNode):
|
|
97
|
+
# NOTA: O Parser precisa passar o token de abertura '('
|
|
98
|
+
def __init__(self, start_token, element_nodes):
|
|
99
|
+
super().__init__(start_token)
|
|
100
|
+
self.element_nodes = element_nodes
|
|
101
|
+
def __repr__(self):
|
|
102
|
+
return f"TupleNode(elements={self.element_nodes})"
|
|
103
|
+
|
|
104
|
+
class DictNode(ASTNode):
|
|
105
|
+
# NOTA: O Parser precisa passar o token de abertura '{'
|
|
106
|
+
def __init__(self, start_token, pairs):
|
|
107
|
+
super().__init__(start_token)
|
|
108
|
+
self.pairs = pairs
|
|
109
|
+
def __repr__(self):
|
|
110
|
+
return f"DictNode(pairs={self.pairs})"
|
|
111
|
+
|
|
112
|
+
class VarAccessNode(ASTNode):
|
|
113
|
+
def __init__(self, token):
|
|
114
|
+
super().__init__(token)
|
|
115
|
+
self.token = token
|
|
116
|
+
self.var_name = token.value
|
|
117
|
+
def __repr__(self):
|
|
118
|
+
return f"VarAccessNode(name='{self.var_name}')"
|
|
119
|
+
|
|
120
|
+
class IndexAccessNode(ASTNode):
|
|
121
|
+
# O token de referência é o '[' que inicia o acesso
|
|
122
|
+
def __init__(self, object_node, index_node, start_bracket_token):
|
|
123
|
+
super().__init__(start_bracket_token)
|
|
124
|
+
self.object_node = object_node
|
|
125
|
+
self.index_node = index_node
|
|
126
|
+
def __repr__(self):
|
|
127
|
+
return f"IndexAccessNode(object={self.object_node}, index={self.index_node})"
|
|
128
|
+
|
|
129
|
+
class ProcessCallNode(ASTNode):
|
|
130
|
+
# A posição da chamada é a do nome do processo/função
|
|
131
|
+
def __init__(self, node_to_call, arg_nodes):
|
|
132
|
+
super().__init__(node_to_call.token)
|
|
133
|
+
self.node_to_call = node_to_call
|
|
134
|
+
self.arg_nodes = arg_nodes
|
|
135
|
+
def __repr__(self):
|
|
136
|
+
return f"ProcessCallNode(name='{self.node_to_call.var_name}', args={self.arg_nodes})"
|
|
137
|
+
|
|
138
|
+
class AttributeAccessNode(ASTNode):
|
|
139
|
+
# A posição é a do atributo sendo acessado
|
|
140
|
+
def __init__(self, object_node, attribute_token):
|
|
141
|
+
super().__init__(attribute_token)
|
|
142
|
+
self.object_node = object_node
|
|
143
|
+
self.attribute_token = attribute_token
|
|
144
|
+
def __repr__(self):
|
|
145
|
+
return f"AttributeAccessNode(object={self.object_node}, attribute='{self.attribute_token.value}')"
|
|
146
|
+
|
|
147
|
+
class MethodCallNode(ASTNode):
|
|
148
|
+
# A posição é a do nome do método
|
|
149
|
+
def __init__(self, object_node, method_token, arg_nodes):
|
|
150
|
+
super().__init__(method_token)
|
|
151
|
+
self.object_node = object_node
|
|
152
|
+
self.method_token = method_token
|
|
153
|
+
self.arg_nodes = arg_nodes
|
|
154
|
+
def __repr__(self):
|
|
155
|
+
return f"MethodCallNode(object={self.object_node}, method='{self.method_token.value}', args={self.arg_nodes})"
|
|
156
|
+
|
|
157
|
+
class LambdaNode(ASTNode):
|
|
158
|
+
# NOTA: O Parser precisa passar o token 'process'
|
|
159
|
+
def __init__(self, process_token, params_node, body_node):
|
|
160
|
+
super().__init__(process_token)
|
|
161
|
+
self.params_node = params_node
|
|
162
|
+
self.body_node = body_node
|
|
163
|
+
def __repr__(self):
|
|
164
|
+
return f"LambdaNode(params={self.params_node}, body={self.body_node})"
|
|
165
|
+
|
|
166
|
+
# --- Nós de Statement (representam ações ou estruturas) ---
|
|
167
|
+
|
|
168
|
+
class ProgramNode(ASTNode):
|
|
169
|
+
def __init__(self, statements):
|
|
170
|
+
super().__init__() # O programa como um todo não tem um token único
|
|
171
|
+
self.statements = statements
|
|
172
|
+
def __repr__(self):
|
|
173
|
+
return f"ProgramNode({self.statements})"
|
|
174
|
+
|
|
175
|
+
class BlockNode(ASTNode):
|
|
176
|
+
# NOTA: O Parser precisa passar o token de abertura '{'
|
|
177
|
+
def __init__(self, start_brace_token, statements):
|
|
178
|
+
super().__init__(start_brace_token)
|
|
179
|
+
self.statements = statements
|
|
180
|
+
def __repr__(self):
|
|
181
|
+
return f"BlockNode({self.statements})"
|
|
182
|
+
|
|
183
|
+
class VarDeclNode(ASTNode):
|
|
184
|
+
def __init__(self, var_name_token, value_node, is_const, type_hint_node=None):
|
|
185
|
+
super().__init__(var_name_token)
|
|
186
|
+
self.var_name_token = var_name_token
|
|
187
|
+
self.value_node = value_node
|
|
188
|
+
self.is_const = is_const
|
|
189
|
+
self.type_hint_node = type_hint_node
|
|
190
|
+
|
|
191
|
+
class AssignNode(ASTNode):
|
|
192
|
+
# NOTA: O Parser precisa passar o token de atribuição (ex: '=')
|
|
193
|
+
def __init__(self, left_node, op_token, value_node):
|
|
194
|
+
super().__init__(op_token)
|
|
195
|
+
self.left_node = left_node
|
|
196
|
+
self.value_node = value_node
|
|
197
|
+
def __repr__(self):
|
|
198
|
+
return f"AssignNode({self.left_node} = {self.value_node})"
|
|
199
|
+
|
|
200
|
+
class WhenNode(ASTNode):
|
|
201
|
+
# NOTA: O Parser precisa passar o token 'when'
|
|
202
|
+
def __init__(self, when_token, condition_node, then_block, else_block):
|
|
203
|
+
super().__init__(when_token)
|
|
204
|
+
self.condition_node = condition_node
|
|
205
|
+
self.then_block = then_block
|
|
206
|
+
self.else_block = else_block
|
|
207
|
+
|
|
208
|
+
class WhileNode(ASTNode):
|
|
209
|
+
# NOTA: O Parser precisa passar o token 'while'
|
|
210
|
+
def __init__(self, while_token, condition_node, body_node):
|
|
211
|
+
super().__init__(while_token)
|
|
212
|
+
self.condition_node = condition_node
|
|
213
|
+
self.body_node = body_node
|
|
214
|
+
|
|
215
|
+
class ForEachNode(ASTNode):
|
|
216
|
+
# NOTA: O Parser precisa passar o token 'for'
|
|
217
|
+
def __init__(self, for_token, var_name_token, iterable_node, body_node):
|
|
218
|
+
super().__init__(for_token)
|
|
219
|
+
self.var_name_token = var_name_token
|
|
220
|
+
self.iterable_node = iterable_node
|
|
221
|
+
self.body_node = body_node
|
|
222
|
+
|
|
223
|
+
class BreakNode(ASTNode):
|
|
224
|
+
def __init__(self, token):
|
|
225
|
+
super().__init__(token)
|
|
226
|
+
self.token = token
|
|
227
|
+
|
|
228
|
+
class ContinueNode(ASTNode):
|
|
229
|
+
def __init__(self, token):
|
|
230
|
+
super().__init__(token)
|
|
231
|
+
self.token = token
|
|
232
|
+
|
|
233
|
+
class ReturnNode(ASTNode):
|
|
234
|
+
# NOTA: O Parser precisa passar o token 'return'
|
|
235
|
+
def __init__(self, return_token, node_to_return):
|
|
236
|
+
super().__init__(return_token)
|
|
237
|
+
self.node_to_return = node_to_return
|
|
238
|
+
|
|
239
|
+
class ProcessDeclNode(ASTNode):
|
|
240
|
+
def __init__(self, proc_name_token, params, return_type_node, body_node):
|
|
241
|
+
super().__init__(proc_name_token)
|
|
242
|
+
self.proc_name_token = proc_name_token
|
|
243
|
+
self.name = proc_name_token.value
|
|
244
|
+
self.params = params
|
|
245
|
+
self.return_type_node = return_type_node
|
|
246
|
+
self.body_node = body_node
|
|
247
|
+
|
|
248
|
+
class ParamNode(ASTNode):
|
|
249
|
+
def __init__(self, var_name_token, type_node):
|
|
250
|
+
super().__init__(var_name_token)
|
|
251
|
+
self.var_name_token = var_name_token
|
|
252
|
+
self.type_node = type_node
|
|
253
|
+
|
|
254
|
+
class TypeNode(ASTNode):
|
|
255
|
+
def __init__(self, token):
|
|
256
|
+
super().__init__(token)
|
|
257
|
+
self.token = token
|
|
258
|
+
self.name = token.value
|
|
259
|
+
|
|
260
|
+
class TypeDeclNode(ASTNode):
|
|
261
|
+
# Modificamos o __init__ para aceitar um 'parent_name_node'
|
|
262
|
+
def __init__(self, name_token, parent_name_node, fields, methods):
|
|
263
|
+
super().__init__(name_token)
|
|
264
|
+
self.name_token = name_token
|
|
265
|
+
self.parent_name_node = parent_name_node # <--- A NOVA LINHA
|
|
266
|
+
self.fields = fields
|
|
267
|
+
self.methods = methods
|
|
268
|
+
|
|
269
|
+
class ImportNode(ASTNode):
|
|
270
|
+
# NOTA: O Parser precisa passar o token 'import'
|
|
271
|
+
def __init__(self, import_token, filepath_node, namespace_token):
|
|
272
|
+
super().__init__(import_token)
|
|
273
|
+
self.filepath_node = filepath_node
|
|
274
|
+
self.namespace_token = namespace_token
|
|
275
|
+
|
|
276
|
+
class EnumNode(ASTNode):
|
|
277
|
+
"""
|
|
278
|
+
Representa uma declaração de enum completa. Ex: 'define enum Status { ... }'
|
|
279
|
+
"""
|
|
280
|
+
def __init__(self, enum_token, name_token, member_tokens):
|
|
281
|
+
super().__init__(enum_token)
|
|
282
|
+
self.name_token = name_token # O token com o nome do enum
|
|
283
|
+
self.member_tokens = member_tokens # Uma lista de tokens com os nomes dos membros
|
|
284
|
+
|
|
285
|
+
def __repr__(self):
|
|
286
|
+
member_names = [t.value for t in self.member_tokens]
|
|
287
|
+
return f"EnumNode(name='{self.name_token.value}', members={member_names})"
|
|
288
|
+
|
|
289
|
+
class TryCatchNode(ASTNode):
|
|
290
|
+
"""Representa a estrutura completa 'try-catch-finally'."""
|
|
291
|
+
def __init__(self, try_token, try_block, catch_clauses, finally_block):
|
|
292
|
+
super().__init__(try_token)
|
|
293
|
+
self.try_block = try_block
|
|
294
|
+
self.catch_clauses = catch_clauses # Uma lista de CatchNode
|
|
295
|
+
self.finally_block = finally_block # Pode ser None
|
|
296
|
+
|
|
297
|
+
class CatchNode(ASTNode):
|
|
298
|
+
"""Representa uma única cláusula 'catch (e: TipoErro) { ... }'."""
|
|
299
|
+
def __init__(self, catch_token, var_token, type_node, body_block):
|
|
300
|
+
super().__init__(catch_token)
|
|
301
|
+
self.var_token = var_token # O token da variável (ex: 'e')
|
|
302
|
+
self.type_node = type_node # O nó do tipo do erro (ex: 'FileNotFoundError')
|
|
303
|
+
self.body_block = body_block # O bloco de código a ser executado
|
|
304
|
+
|
|
305
|
+
class InterpolatedStringNode(ASTNode):
|
|
306
|
+
"""Representa uma f-string, contendo uma lista de partes."""
|
|
307
|
+
def __init__(self, start_token, parts):
|
|
308
|
+
super().__init__(start_token)
|
|
309
|
+
# 'parts' é uma lista de nós, que podem ser StringNode ou qualquer outro nó de expressão.
|
|
310
|
+
self.parts = parts
|
|
311
|
+
|
|
312
|
+
def __repr__(self):
|
|
313
|
+
return f"InterpolatedStringNode(parts={self.parts})"
|
|
314
|
+
|
|
315
|
+
class ListComprehensionNode(ASTNode):
|
|
316
|
+
"""Representa uma compreensão de lista: [expr for each var in iterable]"""
|
|
317
|
+
def __init__(self, start_token, expression_node, var_name_token, iterable_node):
|
|
318
|
+
super().__init__(start_token)
|
|
319
|
+
self.expression_node = expression_node # A expressão a ser avaliada (ex: n * n)
|
|
320
|
+
self.var_name_token = var_name_token # A variável do loop (ex: n)
|
|
321
|
+
self.iterable_node = iterable_node # A lista a ser percorrida (ex: numeros)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Arquivo: lucida_errors.py
|
|
2
|
+
|
|
3
|
+
class LucidaError(Exception):
|
|
4
|
+
"""Classe base para todos os erros da linguagem Lucida-Flow."""
|
|
5
|
+
def __init__(self, message="", line=0, col=0):
|
|
6
|
+
super().__init__(message)
|
|
7
|
+
self.line = line
|
|
8
|
+
self.col = col
|
|
9
|
+
self.message = message
|
|
10
|
+
|
|
11
|
+
def __str__(self):
|
|
12
|
+
if self.line:
|
|
13
|
+
return f"[Linha {self.line}:C{self.col}] {type(self).__name__}: {self.message}"
|
|
14
|
+
return f"{type(self).__name__}: {self.message}"
|
|
15
|
+
|
|
16
|
+
class LucidaSemanticError(LucidaError):
|
|
17
|
+
"""Erro detectado durante a análise semântica."""
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
class LucidaRuntimeError(LucidaError):
|
|
21
|
+
"""Erro detectado durante a execução (interpretação)."""
|
|
22
|
+
# Adicione 'error_type' ao construtor
|
|
23
|
+
def __init__(self, message="", line=0, col=0, error_type="RuntimeException"):
|
|
24
|
+
super().__init__(message, line, col)
|
|
25
|
+
# O nome do tipo de erro para o 'catch' da linguagem Lucida
|
|
26
|
+
self.error_type = error_type
|