Simatic_XML_Parser_to_SCL/create_processor_files.py

150 lines
5.7 KiB
Python

# -*- coding: utf-8 -*-
import os
import sys
import re
import argparse
# Directorio donde se crearán los archivos de procesador
PROCESSORS_DIR = "processors"
# Cabecera estándar para añadir a cada nuevo archivo
FILE_HEADER = """# -*- coding: utf-8 -*-
# TODO: Import necessary functions from processor_utils
# from .processor_utils import get_scl_representation, format_variable_name, ...
# Or: import processors.processor_utils as utils
# TODO: Define constants if needed (e.g., SCL_SUFFIX) or import them
SCL_SUFFIX = "_scl"
# --- Function code starts ---
"""
# Pie de página estándar con la función get_processor_info de plantilla
def get_file_footer(func_name):
# Intenta adivinar el type_name quitando 'process_'
# Necesitará ajustes manuales para casos como 'call', 'edge_detector', 'comparison', 'math'
type_name_guess = func_name.replace('process_', '')
return f"""
# --- Function code ends ---
# --- Processor Information Function ---
def get_processor_info():
\"\"\"Returns the type name and processing function for this module.\"\"\"
# TODO: Adjust the type_name if needed (e.g., for call, edge_detector, comparison, math)
# TODO: Return a list if this module handles multiple types (e.g., PBox/NBox, FC/FB)
type_name = "{type_name_guess}" # Basic guess
return {{'type_name': type_name, 'processor_func': {func_name}}}
"""
def extract_and_create_processors(source_py_file):
"""
Extracts top-level functions starting with 'process_' from the source file
and creates individual processor files in the PROCESSORS_DIR.
"""
if not os.path.exists(source_py_file):
print(f"Error: Source file not found: '{source_py_file}'")
return
print(f"Reading source file: '{source_py_file}'")
try:
with open(source_py_file, 'r', encoding='utf-8') as f:
lines = f.readlines()
except Exception as e:
print(f"Error reading source file: {e}")
return
# Crear directorio de procesadores si no existe
os.makedirs(PROCESSORS_DIR, exist_ok=True)
print(f"Ensuring '{PROCESSORS_DIR}' directory exists.")
current_func_name = None
current_func_lines = []
processor_count = 0
print("Searching for processor functions (def process_...):")
# Usamos una expresión regular para encontrar definiciones de función de nivel superior
# que empiecen por 'process_'
func_def_pattern = re.compile(r"^def\s+(process_\w+)\s*\(")
for i, line in enumerate(lines):
match = func_def_pattern.match(line)
if match: # Encontrada una nueva definición de función 'process_'
new_func_name = match.group(1)
# Si estábamos procesando una función anterior, guardarla ahora
if current_func_name:
create_processor_file(current_func_name, current_func_lines)
processor_count += 1
# Empezar a recolectar para la nueva función
print(f" - Found: {new_func_name}")
current_func_name = new_func_name
current_func_lines = [line] # Empezar con la línea 'def'
elif line.strip() == "" and not current_func_lines:
# Ignorar líneas en blanco antes de la primera función
continue
elif current_func_name and not line.startswith(' '):
# Si estamos dentro de una función y encontramos una línea
# que NO empieza con espacio (y no es un 'def process_'),
# podría ser el fin de la función (o una definición de otra cosa).
# Por simplicidad, asumimos que marca el fin. Guardamos la actual.
# (Esto funciona si las 'def process_' están una tras otra o separadas
# por comentarios o definiciones de funciones NO 'process_')
create_processor_file(current_func_name, current_func_lines)
processor_count += 1
current_func_name = None
current_func_lines = []
elif current_func_name:
# Si estamos recolectando líneas para una función, añadir la línea actual
current_func_lines.append(line)
# Guardar la última función encontrada después de salir del bucle
if current_func_name:
create_processor_file(current_func_name, current_func_lines)
processor_count += 1
if processor_count == 0:
print("\nWarning: No functions starting with 'process_' found at the top level.")
else:
print(f"\nFinished processing. Attempted to create/check {processor_count} processor files in '{PROCESSORS_DIR}'.")
def create_processor_file(func_name, func_lines):
"""Creates the individual processor file if it doesn't exist."""
target_filename = f"{func_name}.py"
target_filepath = os.path.join(PROCESSORS_DIR, target_filename)
if os.path.exists(target_filepath):
print(f" * Skipping: '{target_filename}' already exists.")
return
print(f" * Creating: '{target_filename}'...")
try:
with open(target_filepath, 'w', encoding='utf-8') as f:
f.write(FILE_HEADER)
f.writelines(func_lines) # Escribir las líneas de la función
f.write(get_file_footer(func_name))
except Exception as e:
print(f" Error writing file '{target_filename}': {e}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Extracts 'process_*' functions from a source Python file "
"and creates individual processor files."
)
parser.add_argument(
"source_file",
default="x2_process.py", # Valor por defecto
nargs='?', # Hacerlo opcional para que use el default
help="Path to the source Python file (default: x2_process.py)"
)
args = parser.parse_args()
extract_and_create_processors(args.source_file)