From 3787411cf5f4ba501f51c92856b14a2e0a84e527 Mon Sep 17 00:00:00 2001 From: Miguel Date: Fri, 18 Apr 2025 16:33:36 +0200 Subject: [PATCH] Intento de mejora para multiples ramas --- x2_process.py | 216 ++++++++++++++++++++++++-------------------------- 1 file changed, 103 insertions(+), 113 deletions(-) diff --git a/x2_process.py b/x2_process.py index 2a3e855..8a925b7 100644 --- a/x2_process.py +++ b/x2_process.py @@ -3,10 +3,14 @@ import json import os import copy import traceback +import re # Import regex for PBox SCL parsing if needed later # --- Constantes y Configuración --- SCL_SUFFIX = "_scl" +# Global data variable to be accessible by processors needing network context +data = {} + # --- Helper Functions --- def get_scl_representation(source_info, network_id, scl_map, access_map): @@ -126,19 +130,18 @@ def process_contact(instruction, network_id, scl_map, access_map): instr_type = instruction['type'] if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False - is_negated = False # TODO: Determinar si es negado + is_negated = False # TODO: Determinar si es negado (ej. por 'Name') # print(f"DEBUG: Intentando procesar CONTACT{' (N)' if is_negated else ''} - UID: {instr_uid} en Red: {network_id}") - # --- INICIO CORRECCIÓN --- + # --- CORRECCIÓN: Manejar 'in' implícito --- in_input = instruction['inputs'].get('in') in_rlo_scl = None if in_input is None: - # Si no hay pin 'in' conectado explícitamente, asumir TRUE (conectado a powerrail/riel vertical) + # Si no hay pin 'in' conectado explícitamente, asumir TRUE # print(f"DEBUG: Asumiendo IN=TRUE para CONTACT UID {instr_uid} (pin 'in' no conectado)") in_rlo_scl = "TRUE" else: - # Si hay pin 'in', intentar resolverlo in_rlo_scl = get_scl_representation(in_input, network_id, scl_map, access_map) # --- FIN CORRECCIÓN --- @@ -148,17 +151,18 @@ def process_contact(instruction, network_id, scl_map, access_map): # print(f"DEBUG: Dependencia no resuelta para CONTACT UID: {instr_uid} (in={in_rlo_scl}, op={operand_scl})") return False - # ... (resto de process_contact sin cambios: construir RLO, actualizar scl_map y JSON, retornar True) ... term = f"NOT {operand_scl}" if is_negated else operand_scl + # Envolver término en paréntesis si es necesario if not (term.startswith('"') and term.endswith('"')): - if not (term.startswith('(') and term.endswith(')')): + if ' ' in term and not (term.startswith('(') and term.endswith(')')): term = f"({term})" new_rlo_scl = "" if in_rlo_scl == "TRUE": new_rlo_scl = term else: - if not (in_rlo_scl.startswith('(') and in_rlo_scl.endswith(')')) and 'AND' in in_rlo_scl or 'OR' in in_rlo_scl: + # Envolver RLO anterior en paréntesis si es necesario + if ('AND' in in_rlo_scl or 'OR' in in_rlo_scl) and not (in_rlo_scl.startswith('(') and in_rlo_scl.endswith(')')): in_rlo_processed = f"({in_rlo_scl})" else: in_rlo_processed = in_rlo_scl @@ -186,23 +190,25 @@ def process_eq(instruction, network_id, scl_map, access_map): # print(f"DEBUG: Dependencia no resuelta para EQ UID: {instr_uid} (in1={in1_scl}, in2={in2_scl})") return False - # Poner operandos entre paréntesis si son complejos op1 = f"({in1_scl})" if ' ' in in1_scl else in1_scl op2 = f"({in2_scl})" if ' ' in in2_scl else in2_scl - comparison_scl = f"{op1} = {op2}" # SCL usa '=' para comparación + comparison_scl = f"{op1} = {op2}" map_key_out = (network_id, instr_uid, 'out') scl_map[map_key_out] = comparison_scl - # --- Manejo de ENO --- - # El 'pre' en LAD para comparación a menudo actúa como el EN. - pre_scl = get_scl_representation(instruction['inputs'].get('pre'), network_id, scl_map, access_map) - # Si 'pre' no está conectado, asumimos TRUE. - effective_en_scl = "TRUE" if pre_scl is None else pre_scl - # El estado ENO de una comparación es TRUE si se ejecuta (EN=TRUE) y FALSE si no. + # --- Manejo de ENO (CORREGIDO) --- + pre_input = instruction['inputs'].get('pre') + # Asumir TRUE si 'pre' no está conectado explícitamente + pre_scl = "TRUE" if pre_input is None else get_scl_representation(pre_input, network_id, scl_map, access_map) + + if pre_scl is None: # Si está conectado pero no resuelto + # print(f"DEBUG: Dependencia PRE no resuelta para EQ UID {instr_uid}") + return False # No se puede determinar ENO si PRE no está listo + + # El estado ENO de una comparación es TRUE si se ejecuta (EN/PRE=TRUE) y FALSE si no. map_key_eno = (network_id, instr_uid, 'eno') - scl_map[map_key_eno] = effective_en_scl - # print(f"DEBUG: EQ UID: {instr_uid} - Estado ENO en scl_map[{map_key_eno}] = {effective_en_scl}") + scl_map[map_key_eno] = pre_scl # ENO sigue a la habilitación PRE # --- Fin Manejo de ENO --- instruction['scl'] = f"// Comparison Eq {instr_uid}: {comparison_scl}" @@ -218,19 +224,24 @@ def process_coil(instruction, network_id, scl_map, access_map): # print(f"DEBUG: Intentando procesar COIL - UID: {instr_uid} en Red: {network_id}") in_rlo_scl = get_scl_representation(instruction['inputs'].get('in'), network_id, scl_map, access_map) - operand_scl = get_scl_representation(instruction['inputs'].get('operand'), network_id, scl_map, access_map) + operand_info = instruction['inputs'].get('operand') # Obtener info completa del operando + operand_scl = get_scl_representation(operand_info, network_id, scl_map, access_map) + if in_rlo_scl is None or operand_scl is None: # print(f"DEBUG: Dependencia no resuelta para COIL UID: {instr_uid} (in={in_rlo_scl}, op={operand_scl})") return False - operand_info = instruction['inputs'].get('operand') if not (operand_info and operand_info.get('type') == 'variable'): print(f"Error: Operando de COIL UID {instr_uid} no es una variable: {operand_info}") instruction['scl'] = f"// ERROR: Coil {instr_uid} operando no es variable" instruction['type'] = instr_type + "_error" return True + # Simplificar RLO si es posible antes de asignar + if in_rlo_scl == "(TRUE)": in_rlo_scl = "TRUE" + elif in_rlo_scl == "(FALSE)": in_rlo_scl = "FALSE" + scl_final = f"{operand_scl} := {in_rlo_scl};" instruction['scl'] = scl_final @@ -247,7 +258,7 @@ def process_convert(instruction, network_id, scl_map, access_map): # print(f"DEBUG: Intentando procesar CONVERT - UID: {instr_uid} en Red: {network_id}") - # --- Manejo de EN --- + # --- CORRECCIÓN: Manejo de EN --- en_input = instruction['inputs'].get('en') en_scl = None if en_input is None: @@ -255,12 +266,16 @@ def process_convert(instruction, network_id, scl_map, access_map): en_scl = "TRUE" else: en_scl = get_scl_representation(en_input, network_id, scl_map, access_map) - # --- Fin Manejo de EN --- + + if en_scl is None: # Bloquear si EN está conectado pero no resuelto + # print(f"DEBUG: Dependencia EN no resuelta para CONVERT UID: {instr_uid}") + return False + # --- FIN CORRECCIÓN --- in_scl = get_scl_representation(instruction['inputs'].get('in'), network_id, scl_map, access_map) - if en_scl is None or in_scl is None: - # print(f"DEBUG: Dependencia no resuelta para CONVERT UID: {instr_uid} (en={en_scl}, in={in_scl})") + if in_scl is None: + # print(f"DEBUG: Dependencia IN no resuelta para CONVERT UID: {instr_uid}") return False target_scl = get_target_scl_name(instruction, 'out', network_id, default_to_temp=True) @@ -271,14 +286,14 @@ def process_convert(instruction, network_id, scl_map, access_map): return True conversion_expr = in_scl # Asume conversión implícita por ahora - # TODO: Añadir lógica de conversión explícita si se extraen tipos de TemplateValue scl_core = f"{target_scl} := {conversion_expr};" + # --- CORRECCIÓN: Generación de IF --- if en_scl != "TRUE": scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" else: - # Si en_scl ES "TRUE", no se necesita IF scl_final = scl_core + # --- FIN CORRECCIÓN --- instruction['scl'] = scl_final instruction['type'] = instr_type + SCL_SUFFIX @@ -286,9 +301,10 @@ def process_convert(instruction, network_id, scl_map, access_map): map_key_out = (network_id, instr_uid, 'out') scl_map[map_key_out] = target_scl + # --- CORRECCIÓN: Añadir ENO a scl_map --- map_key_eno = (network_id, instr_uid, 'eno') scl_map[map_key_eno] = en_scl # ENO sigue a EN - # print(f"DEBUG: CONVERT UID: {instr_uid} - Estado ENO en scl_map[{map_key_eno}] = {en_scl}") + # --- FIN CORRECCIÓN --- # print(f"INFO: CONVERT UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...") return True @@ -301,7 +317,7 @@ def process_mod(instruction, network_id, scl_map, access_map): # print(f"DEBUG: Intentando procesar MOD - UID: {instr_uid} en Red: {network_id}") - # --- Manejo de EN --- + # --- CORRECCIÓN: Manejo de EN --- en_input = instruction['inputs'].get('en') en_scl = None if en_input is None: @@ -309,13 +325,17 @@ def process_mod(instruction, network_id, scl_map, access_map): en_scl = "TRUE" else: en_scl = get_scl_representation(en_input, network_id, scl_map, access_map) - # --- Fin Manejo de EN --- + + if en_scl is None: # Bloquear si EN está conectado pero no resuelto + # print(f"DEBUG: Dependencia EN no resuelta para MOD UID: {instr_uid}") + return False + # --- FIN CORRECCIÓN --- in1_scl = get_scl_representation(instruction['inputs'].get('in1'), network_id, scl_map, access_map) in2_scl = get_scl_representation(instruction['inputs'].get('in2'), network_id, scl_map, access_map) - if en_scl is None or in1_scl is None or in2_scl is None: - # print(f"DEBUG: Dependencia no resuelta para MOD UID: {instr_uid} (en={en_scl}, in1={in1_scl}, in2={in2_scl})") + if in1_scl is None or in2_scl is None: + # print(f"DEBUG: Dependencia no resuelta para MOD UID: {instr_uid} (in1={in1_scl}, in2={in2_scl})") return False target_scl = get_target_scl_name(instruction, 'out', network_id, default_to_temp=True) @@ -328,11 +348,12 @@ def process_mod(instruction, network_id, scl_map, access_map): op1 = f"({in1_scl})" if ' ' in in1_scl else in1_scl op2 = f"({in2_scl})" if ' ' in in2_scl else in2_scl scl_core = f"{target_scl} := {op1} MOD {op2};" + # --- CORRECCIÓN: Generación de IF --- if en_scl != "TRUE": scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" else: - # Si en_scl ES "TRUE", no se necesita IF scl_final = scl_core + # --- FIN CORRECCIÓN --- instruction['scl'] = scl_final instruction['type'] = instr_type + SCL_SUFFIX @@ -340,9 +361,10 @@ def process_mod(instruction, network_id, scl_map, access_map): map_key_out = (network_id, instr_uid, 'out') scl_map[map_key_out] = target_scl + # --- CORRECCIÓN: Añadir ENO a scl_map --- map_key_eno = (network_id, instr_uid, 'eno') scl_map[map_key_eno] = en_scl # ENO sigue a EN - # print(f"DEBUG: MOD UID: {instr_uid} - Estado ENO en scl_map[{map_key_eno}] = {en_scl}") + # --- FIN CORRECCIÓN --- # print(f"INFO: MOD UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...") return True @@ -354,7 +376,7 @@ def process_add(instruction, network_id, scl_map, access_map): # print(f"DEBUG: Intentando procesar ADD - UID: {instr_uid} en Red: {network_id}") - # --- Manejo de EN --- + # --- CORRECCIÓN: Manejo de EN --- en_input = instruction['inputs'].get('en') en_scl = None if en_input is None: @@ -362,13 +384,17 @@ def process_add(instruction, network_id, scl_map, access_map): en_scl = "TRUE" else: en_scl = get_scl_representation(en_input, network_id, scl_map, access_map) - # --- Fin Manejo de EN --- + + if en_scl is None: # Bloquear si EN está conectado pero no resuelto + # print(f"DEBUG: Dependencia EN no resuelta para ADD UID: {instr_uid}") + return False + # --- FIN CORRECCIÓN --- in1_scl = get_scl_representation(instruction['inputs'].get('in1'), network_id, scl_map, access_map) in2_scl = get_scl_representation(instruction['inputs'].get('in2'), network_id, scl_map, access_map) - if en_scl is None or in1_scl is None or in2_scl is None: - # print(f"DEBUG: Dependencia no resuelta para ADD UID: {instr_uid} (en={en_scl}, in1={in1_scl}, in2={in2_scl})") + if in1_scl is None or in2_scl is None: + # print(f"DEBUG: Dependencia no resuelta para ADD UID: {instr_uid} (in1={in1_scl}, in2={in2_scl})") return False target_scl = get_target_scl_name(instruction, 'out', network_id, default_to_temp=True) @@ -381,11 +407,12 @@ def process_add(instruction, network_id, scl_map, access_map): op1 = f"({in1_scl})" if ' ' in in1_scl else in1_scl op2 = f"({in2_scl})" if ' ' in in2_scl else in2_scl scl_core = f"{target_scl} := {op1} + {op2};" + # --- CORRECCIÓN: Generación de IF --- if en_scl != "TRUE": scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" else: - # Si en_scl ES "TRUE", no se necesita IF scl_final = scl_core + # --- FIN CORRECCIÓN --- instruction['scl'] = scl_final instruction['type'] = instr_type + SCL_SUFFIX @@ -393,9 +420,10 @@ def process_add(instruction, network_id, scl_map, access_map): map_key_out = (network_id, instr_uid, 'out') scl_map[map_key_out] = target_scl + # --- CORRECCIÓN: Añadir ENO a scl_map --- map_key_eno = (network_id, instr_uid, 'eno') scl_map[map_key_eno] = en_scl # ENO sigue a EN - # print(f"DEBUG: ADD UID: {instr_uid} - Estado ENO en scl_map[{map_key_eno}] = {en_scl}") + # --- FIN CORRECCIÓN --- # print(f"INFO: ADD UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...") return True @@ -407,7 +435,7 @@ def process_move(instruction, network_id, scl_map, access_map): # print(f"DEBUG: Intentando procesar MOVE - UID: {instr_uid} en Red: {network_id}") - # --- Manejo de EN --- + # --- CORRECCIÓN: Manejo de EN --- en_input = instruction['inputs'].get('en') en_scl = None if en_input is None: @@ -415,12 +443,16 @@ def process_move(instruction, network_id, scl_map, access_map): en_scl = "TRUE" else: en_scl = get_scl_representation(en_input, network_id, scl_map, access_map) - # --- Fin Manejo de EN --- + + if en_scl is None: # Bloquear si EN está conectado pero no resuelto + # print(f"DEBUG: Dependencia EN no resuelta para MOVE UID: {instr_uid}") + return False + # --- FIN CORRECCIÓN --- in_scl = get_scl_representation(instruction['inputs'].get('in'), network_id, scl_map, access_map) - if en_scl is None or in_scl is None: - # print(f"DEBUG: Dependencia no resuelta para MOVE UID: {instr_uid} (en={en_scl}, in={in_scl})") + if in_scl is None: + # print(f"DEBUG: Dependencia IN no resuelta para MOVE UID: {instr_uid}") return False target_scl = get_target_scl_name(instruction, 'out1', network_id, default_to_temp=False) # No usar temp por defecto @@ -430,16 +462,19 @@ def process_move(instruction, network_id, scl_map, access_map): return False scl_core = f"{target_scl} := {in_scl};" + # --- CORRECCIÓN: Generación de IF --- if en_scl != "TRUE": scl_final = f"IF {en_scl} THEN\n {scl_core}\nEND_IF;" else: - # Si en_scl ES "TRUE", no se necesita IF scl_final = scl_core + # --- FIN CORRECCIÓN --- instruction['scl'] = scl_final instruction['type'] = instr_type + SCL_SUFFIX # print(f"INFO: MOVE UID: {instr_uid} procesado. SCL: {scl_final.splitlines()[0]}...") + # Move no tiene ENO explícito en la mayoría de implementaciones LAD/SCL, + # por lo que no añadimos map_key_eno aquí normalmente. return True def process_pbox(instruction, network_id, scl_map, access_map, network_logic_list): @@ -451,44 +486,34 @@ def process_pbox(instruction, network_id, scl_map, access_map, network_logic_lis instr_type = instruction['type'] if instr_type.endswith(SCL_SUFFIX) or "_error" in instr_type: return False - print(f"DEBUG: Intentando procesar PBOX - UID: {instr_uid} en Red: {network_id}") + # print(f"DEBUG: Intentando procesar PBOX - UID: {instr_uid} en Red: {network_id}") - # 1. Obtener el bit de memoria (siempre presente en PBox para flancos) mem_bit_input = instruction['inputs'].get('bit') mem_bit_scl = get_scl_representation(mem_bit_input, network_id, scl_map, access_map) if mem_bit_scl is None: - print(f"DEBUG: Dependencia no resuelta para PBOX UID: {instr_uid} (bit={mem_bit_scl})") + # print(f"DEBUG: Dependencia no resuelta para PBOX UID: {instr_uid} (bit={mem_bit_scl})") return False - # Validar que el bit de memoria sea una variable if not (mem_bit_input and mem_bit_input.get('type') == 'variable'): print(f"Error: Entrada 'bit' de PBOX UID {instr_uid} no es una variable: {mem_bit_input}") instruction['scl'] = f"// ERROR: PBox {instr_uid} entrada 'bit' no es variable" instruction['type'] += "_error" return True - # 2. Determinar si es un flanco P_TRIG (heurística basada en patrón común) - # Patrón: La salida del PBox va a un Coil y el PBox está precedido por lógica booleana. is_likely_p_trig = False - consuming_coil_info = None - # Buscar Coil que consume la salida 'out' de este PBox consuming_coil_uid = None for potential_consumer in network_logic_list: consumer_inputs = potential_consumer.get('inputs', {}) - coil_input_signal = consumer_inputs.get('in') # Bobinas usan 'in' + coil_input_signal = consumer_inputs.get('in') if isinstance(coil_input_signal, dict) and \ coil_input_signal.get('type') == 'connection' and \ coil_input_signal.get('source_instruction_uid') == instr_uid and \ coil_input_signal.get('source_pin') == 'out': - if potential_consumer.get('type', '').startswith('Coil'): + consumer_type = potential_consumer.get('type', '').replace('_scl','').replace('_error','') + if consumer_type == 'Coil': consuming_coil_uid = potential_consumer['instruction_uid'] - # print(f"DEBUG: PBox {instr_uid} alimenta Coil {consuming_coil_uid}") - is_likely_p_trig = True # Fuerte indicio de P_TRIG + is_likely_p_trig = True break - # else: # Podría alimentar otra cosa, ¿quizás no es P_TRIG? - # print(f"DEBUG: Salida de PBox {instr_uid} no alimenta un Coil directamente.") - # pass - # 3. Encontrar la señal CLK implícita (Heurística: buscar RLO hacia atrás) rlo_scl = None if is_likely_p_trig: clk_source_found = False @@ -499,66 +524,49 @@ def process_pbox(instruction, network_id, scl_map, access_map, network_logic_lis break if current_instr_index != -1: - # Buscar hacia atrás desde ANTES del PBox for i in range(current_instr_index - 1, -1, -1): prev_instr = network_logic_list[i] prev_instr_uid = prev_instr['instruction_uid'] - # Usar tipo original para la búsqueda prev_instr_type = prev_instr.get('type', '').replace(SCL_SUFFIX, '').replace('_error', '') - # Instrucciones que generan el RLO relevante if prev_instr_type in ['Contact', 'Eq', 'O', 'PBox', 'And', 'Xor', 'Ne', 'Gt', 'Lt', 'Ge', 'Le']: map_key_prev_out = (network_id, prev_instr_uid, 'out') potential_clk_scl = scl_map.get(map_key_prev_out) if potential_clk_scl is not None: rlo_scl = potential_clk_scl clk_source_found = True - # print(f"DEBUG: Fuente CLK para PBox {instr_uid} inferida de: {prev_instr_type} UID {prev_instr_uid} -> {rlo_scl}") break elif prev_instr_type in ['Move', 'Add', 'Convert', 'Mod']: - # Si encontramos un bloque funcional, el RLO podría venir de su ENO map_key_prev_eno = (network_id, prev_instr_uid, 'eno') potential_clk_scl = scl_map.get(map_key_prev_eno) if potential_clk_scl is not None: rlo_scl = potential_clk_scl clk_source_found = True - # print(f"DEBUG: Fuente CLK para PBox {instr_uid} inferida de ENO de: {prev_instr_type} UID {prev_instr_uid} -> {rlo_scl}") break - # Si no tiene ENO resuelto, seguimos buscando atrás if not clk_source_found: - # Podría estar conectado directamente a powerrail si es el inicio de la lógica - # O la heurística falló. Devolver error o asumir TRUE? Devolver error es más seguro. print(f"Error: No se pudo inferir la fuente CLK para PBOX UID {instr_uid} (probable P_TRIG).") instruction['scl'] = f"// ERROR: PBox {instr_uid} sin fuente CLK implícita clara" instruction['type'] += "_error" - return True # Marcado como error + return True - # Verificar si el RLO inferido se resolvió if rlo_scl is None: - print(f"DEBUG: Dependencia CLK (inferida) no resuelta para PBOX UID: {instr_uid}") + # print(f"DEBUG: Dependencia CLK (inferida) no resuelta para PBOX UID: {instr_uid}") return False - # 4. Generar SCL scl_comment = "" if is_likely_p_trig: - # Usar función hipotética P_TRIG_FUNC clk_signal_formatted = f"({rlo_scl})" if ' ' in rlo_scl else rlo_scl result_scl = f"P_TRIG_FUNC(CLK := {clk_signal_formatted}, M := {mem_bit_scl})" scl_comment = f"// Edge detection PBox {instr_uid} -> {result_scl} (CLK source inferred)" else: - # Si no parece P_TRIG, simplemente pasar el valor del bit de memoria? - # O podría ser un N_TRIG (flanco negativo)? O sólo lectura de M? - # Por seguridad, si no es el patrón P_TRIG->Coil, pasamos el bit. print(f"Advertencia: PBox UID {instr_uid} no coincide con patrón P_TRIG->Coil. Pasando valor de {mem_bit_scl} directamente.") result_scl = mem_bit_scl scl_comment = f"// PBox {instr_uid} - Passing value from bit: {result_scl}" - # 5. Poner el resultado en scl_map para la salida 'out' map_key_out = (network_id, instr_uid, 'out') scl_map[map_key_out] = result_scl - # 6. Actualizar JSON instruction['scl'] = scl_comment instruction['type'] = instr_type + SCL_SUFFIX return True @@ -586,7 +594,6 @@ def process_o(instruction, network_id, scl_map, access_map): all_resolved = False # print(f"DEBUG: Dependencia no resuelta para O UID: {instr_uid} (pin {pin})") break - # Poner entre paréntesis si es complejo para seguridad en OR term = f"({in_scl})" if (' ' in in_scl or 'AND' in in_scl) and not (in_scl.startswith('(') and in_scl.endswith(')')) else in_scl scl_parts.append(term) @@ -615,8 +622,7 @@ def process_json_to_scl(json_filepath): print(f"Cargando JSON desde: {json_filepath}") try: with open(json_filepath, 'r', encoding='utf-8') as f: - # Guardar data globalmente o pasarla a process_pbox si es necesario - global data # Hacer data accesible globalmente (o pasar como argumento) + global data data = json.load(f) except Exception as e: print(f"Error al cargar o parsear JSON: {e}") @@ -629,14 +635,11 @@ def process_json_to_scl(json_filepath): net_id = network['id'] current_access_map = {} for instr in network.get('logic', []): - # (Código para reconstruir access_map - sin cambios) - # Chequear inputs for pin, source in instr.get('inputs', {}).items(): sources_to_check = source if isinstance(source, list) else ([source] if isinstance(source, dict) else []) for src in sources_to_check: if isinstance(src, dict) and src.get('uid') and src.get('scope') and src.get('type') in ['variable', 'constant']: current_access_map[src['uid']] = src - # Chequear outputs for pin, dest_list in instr.get('outputs', {}).items(): if isinstance(dest_list, list): for dest in dest_list: @@ -645,7 +648,7 @@ def process_json_to_scl(json_filepath): network_access_maps[net_id] = current_access_map scl_map = {} - max_passes = 20 + max_passes = 25 # Aumentado ligeramente por si acaso passes = 0 # Lista de procesadores con orden corregido @@ -659,11 +662,10 @@ def process_json_to_scl(json_filepath): process_add, process_move, process_coil, + # process_group_ifs, # Aplazado por ahora para simplificar ] - # Crear el mapa para búsqueda rápida - processor_map = {func.__name__.split('_')[1].capitalize(): func for func in processors} - # !!! POTENCIAL PROBLEMA 1: La clave aquí sigue siendo sensible a mayúsculas !!! - # Ejemplo: "Pbox" vs "PBox" + # Mapa de procesadores usando lower case para la clave + processor_map = {func.__name__.split('_')[1].lower(): func for func in processors} print("\n--- Iniciando Bucle de Procesamiento Iterativo ---") while passes < max_passes: @@ -671,57 +673,45 @@ def process_json_to_scl(json_filepath): made_change_in_pass = False print(f"\n--- Pase {passes} ---") - # Iterar sobre las redes for network in data.get('networks', []): network_id = network['id'] access_map = network_access_maps.get(network_id, {}) network_logic = network.get('logic', []) - # Iterar sobre las instrucciones en la red for instruction in network_logic: instr_type_original = instruction['type'] - # Saltar si ya está procesado o es error if instr_type_original.endswith(SCL_SUFFIX) or "_error" in instr_type_original: continue - # --- Búsqueda del procesador (CORREGIR ESTA PARTE) --- - processor_func = None - instr_type_lookup = instr_type_original.capitalize() # Capitalizar para buscar en el mapa - # !!! POTENCIAL PROBLEMA 2: Si el tipo es 'O', capitalize() da 'O', pero la clave es 'O'? - # Vamos a usar minúsculas para la búsqueda en el mapa también + # Búsqueda de procesador (case-insensitive) instr_type_lower_lookup = instr_type_original.lower() - func_to_call = None - for func_key_cap, func_obj in processor_map.items(): - if func_key_cap.lower() == instr_type_lower_lookup: - func_to_call = func_obj - break - # --- Fin Corrección Búsqueda --- + func_to_call = processor_map.get(instr_type_lower_lookup) - # Si encontramos un procesador para este tipo if func_to_call: - # print(f"DEBUG: Encontrado procesador {func_to_call.__name__} para tipo {instr_type_original}") # Añadir para depurar + # print(f"DEBUG: Intentando {func_to_call.__name__} para {instr_type_original} UID {instruction['instruction_uid']}") try: - # Pasar lista lógica si es necesario + # Pasar lista lógica si es PBox if func_to_call == process_pbox: changed = func_to_call(instruction, network_id, scl_map, access_map, network_logic) else: changed = func_to_call(instruction, network_id, scl_map, access_map) if changed: + # print(f"DEBUG: Cambio realizado por {func_to_call.__name__} en UID {instruction['instruction_uid']}") made_change_in_pass = True - # No hacer break aquí, seguir intentando otros procesadores - # en la misma instrucción podría tener sentido en algunos casos? - # Por ahora, SÍ hacemos break para procesar una vez por pase. - # break # <--- Quitar este break si queremos reintentar en el mismo pase? No, mantenerlo. + # No hacer break, permite que el procesador de grupo actúe si se añade después except Exception as e: - # ... (manejo de errores) ... print(f"ERROR al ejecutar {func_to_call.__name__} en UID {instruction.get('instruction_uid')} Red {network_id}: {e}") traceback.print_exc() instruction['scl'] = f"// ERROR during processing: {e}" instruction['type'] += "_error" made_change_in_pass = True - # else: # Reducir ruido - # print(f"DEBUG: No se encontró procesador para el tipo: {instr_type_original}") + + # --- Llamada Opcional al Procesador de Agrupación (APLAZADO) --- + # if made_change_in_pass: # Solo intentar agrupar si hubo otros cambios? + # for network in data.get('networks', []): + # # ... (código para llamar a process_group_ifs) ... + # pass if not made_change_in_pass: