Skip to content

Commit 2fd7695

Browse files
committed
Correcciones dentro del main.py para el detector de errores de sintaxis
1 parent f8bb9bf commit 2fd7695

1 file changed

Lines changed: 79 additions & 59 deletions

File tree

main.py

Lines changed: 79 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -230,33 +230,47 @@ def add_definition(name, node_id):
230230
if name and isinstance(name, str) and name.strip():
231231
defined_names[name.strip()] = node_id
232232

233-
for block in blocks:
234-
if not isinstance(block, dict):
235-
continue
236-
b_type = block.get('type', '')
237-
if b_type == 'py_var':
238-
add_definition(block.get('var_name'), block.get('id'))
239-
elif b_type == 'py_math':
240-
add_definition(block.get('target'), block.get('id'))
241-
elif b_type in ['py_int', 'py_float', 'py_input']:
242-
add_definition(block.get('target'), block.get('id'))
243-
elif b_type == 'py_loop':
244-
add_definition(block.get('iterator'), block.get('id'))
245-
elif b_type == 'py_func':
246-
add_definition(block.get('func_name'), block.get('id'))
247-
elif b_type == 'py_class':
248-
add_definition(block.get('name'), block.get('id'))
233+
# PRIMERA PASADA (RECURSIVA): Registrar todas las variables en todos los niveles
234+
def gather_definitions(block_list):
235+
for block in block_list:
236+
if not isinstance(block, dict):
237+
continue
238+
b_type = block.get('type', '')
239+
if b_type == 'py_var':
240+
add_definition(block.get('var_name'), block.get('id'))
241+
elif b_type == 'py_math':
242+
add_definition(block.get('target'), block.get('id'))
243+
elif b_type in ['py_int', 'py_float', 'py_input']:
244+
add_definition(block.get('target'), block.get('id'))
245+
elif b_type == 'py_loop':
246+
add_definition(block.get('iterator'), block.get('id'))
247+
elif b_type == 'py_func':
248+
add_definition(block.get('func_name'), block.get('id'))
249+
elif b_type == 'py_class':
250+
add_definition(block.get('name'), block.get('id'))
251+
252+
# Si el nodo tiene hijos (If, For, etc), entramos a revisarlos
253+
body = block.get('body', [])
254+
if isinstance(body, list):
255+
gather_definitions(body)
256+
257+
gather_definitions(blocks)
249258

250259
def suggest(name):
251260
candidates = difflib.get_close_matches(name, defined_names.keys(), n=1, cutoff=0.6)
252261
return candidates[0] if candidates else None
253262

254263
def check_expression(expr, block_id, description):
255-
names, parse_error = _extract_names(expr)
264+
if expr is None:
265+
return
266+
267+
# str() protege contra números puros que puedan crashear el AST
268+
names, parse_error = _extract_names(str(expr))
269+
256270
if parse_error:
257271
errors.append({
258272
'node_id': block_id,
259-
'message': f"Error de sintaxis en {description}: {parse_error}",
273+
'message': f"Sintaxis inválida en {description}",
260274
'suggestion': None
261275
})
262276
return
@@ -268,55 +282,61 @@ def check_expression(expr, block_id, description):
268282
if suggestion:
269283
errors.append({
270284
'node_id': block_id,
271-
'message': f"Nombre no definido '{name}' en {description}. Quizás quiso decir '{suggestion}'?",
285+
'message': f"'{name}' no existe. ¿Quisiste decir '{suggestion}'?",
272286
'suggestion': suggestion
273287
})
274288
else:
275289
errors.append({
276290
'node_id': block_id,
277-
'message': f"Nombre no definido '{name}' en {description}.",
291+
'message': f"La variable '{name}' no ha sido creada.",
278292
'suggestion': None
279293
})
280294

281-
for block in blocks:
282-
if not isinstance(block, dict):
283-
continue
284-
b_type = block.get('type', '')
285-
block_id = block.get('id')
286-
if b_type == 'py_var':
287-
check_expression(block.get('value', ''), block_id, 'valor de variable')
288-
elif b_type == 'py_math':
289-
check_expression(block.get('left', ''), block_id, 'lado izquierdo de la operación')
290-
check_expression(block.get('right', ''), block_id, 'lado derecho de la operación')
291-
elif b_type == 'py_print':
292-
check_expression(block.get('content', ''), block_id, 'contenido de print')
293-
elif b_type == 'py_input':
294-
# target is definition, prompt can be ignored
295-
pass
296-
elif b_type == 'py_int' or b_type == 'py_float':
297-
check_expression(block.get('value', ''), block_id, 'valor de conversión')
298-
elif b_type == 'py_compare':
299-
check_expression(block.get('left', ''), block_id, 'lado izquierdo de la comparación')
300-
check_expression(block.get('right', ''), block_id, 'lado derecho de la comparación')
301-
elif b_type == 'py_if':
302-
check_expression(block.get('condition', ''), block_id, 'condición if')
303-
elif b_type == 'py_elif':
304-
check_expression(block.get('condition', ''), block_id, 'condición elif')
305-
elif b_type == 'py_loop':
306-
check_expression(block.get('iterable', ''), block_id, 'iterable del for')
307-
elif b_type == 'py_while':
308-
check_expression(block.get('condition', ''), block_id, 'condición while')
309-
elif b_type == 'py_call':
310-
func_expr = block.get('func', '')
311-
args_expr = block.get('args', '')
312-
check_expression(func_expr, block_id, 'función llamada')
313-
if args_expr:
314-
# parse as tuple-like args
315-
check_expression(f"({args_expr})", block_id, 'argumentos de la llamada')
316-
elif b_type == 'py_return':
317-
check_expression(block.get('value', ''), block_id, 'valor de retorno')
318-
319-
# Remove duplicates by node_id + message
295+
# SEGUNDA PASADA (RECURSIVA): Buscar errores en cualquier profundidad
296+
def check_blocks(block_list):
297+
for block in block_list:
298+
if not isinstance(block, dict):
299+
continue
300+
b_type = block.get('type', '')
301+
block_id = block.get('id')
302+
303+
if b_type == 'py_var':
304+
check_expression(block.get('value', ''), block_id, 'el valor')
305+
elif b_type == 'py_math':
306+
check_expression(block.get('left', ''), block_id, 'el lado izquierdo')
307+
check_expression(block.get('right', ''), block_id, 'el lado derecho')
308+
elif b_type == 'py_print':
309+
check_expression(block.get('content', ''), block_id, 'lo que se va a imprimir')
310+
elif b_type in ['py_int', 'py_float']:
311+
check_expression(block.get('value', ''), block_id, 'la conversión')
312+
elif b_type == 'py_compare':
313+
check_expression(block.get('left', ''), block_id, 'la comparación (izq)')
314+
check_expression(block.get('right', ''), block_id, 'la comparación (der)')
315+
elif b_type == 'py_if':
316+
check_expression(block.get('condition', ''), block_id, 'la condición del If')
317+
elif b_type == 'py_elif':
318+
check_expression(block.get('condition', ''), block_id, 'la condición del Elif')
319+
elif b_type == 'py_loop':
320+
check_expression(block.get('iterable', ''), block_id, 'el rango del For')
321+
elif b_type == 'py_while':
322+
check_expression(block.get('condition', ''), block_id, 'la condición del While')
323+
elif b_type == 'py_call':
324+
func_expr = block.get('func', '')
325+
args_expr = block.get('args', '')
326+
check_expression(func_expr, block_id, 'la llamada a función')
327+
if args_expr:
328+
check_expression(f"({args_expr})", block_id, 'los parámetros')
329+
elif b_type == 'py_return':
330+
check_expression(block.get('value', ''), block_id, 'el valor a retornar')
331+
332+
# Volvemos a bajar en cascada para revisar el interior de los contenedores
333+
body = block.get('body', [])
334+
if isinstance(body, list):
335+
check_blocks(body)
336+
337+
check_blocks(blocks)
338+
339+
# Filtrar duplicados
320340
unique = {}
321341
for err in errors:
322342
key = (err['node_id'], err['message'])

0 commit comments

Comments
 (0)