Simatic_XML_Parser_to_SCL/create_processor_files.py

144 lines
5.6 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
# Example: 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):
"""Generates the standard footer with a placeholder get_processor_info."""
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., 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, copying
the entire function body until the next top-level definition.
"""
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
os.makedirs(PROCESSORS_DIR, exist_ok=True)
print(f"Ensuring '{PROCESSORS_DIR}' directory exists.")
print("Searching for processor functions (def process_...):")
processor_functions = [] # Store tuples of (name, start_line_index, end_line_index)
current_func_start = -1
current_func_name = None
# Pattern to find ANY top-level function definition
any_func_def_pattern = re.compile(r"^def\s+(\w+)\s*\(")
# Pattern specific to processor functions
process_func_def_pattern = re.compile(r"^def\s+(process_\w+)\s*\(")
# First pass: Identify start and end lines of all top-level functions
for i, line in enumerate(lines):
match = any_func_def_pattern.match(line)
if match:
# Found a new top-level function definition
if current_func_name is not None:
# Mark the end of the *previous* function
# Only add if it was a 'process_' function
if current_func_name.startswith("process_"):
processor_functions.append((current_func_name, current_func_start, i))
# Start tracking the new function
current_func_name = match.group(1)
current_func_start = i
# Add the last function found in the file (if it was a process_ function)
if current_func_name is not None and current_func_name.startswith("process_"):
processor_functions.append((current_func_name, current_func_start, len(lines)))
# Second pass: Create files using the identified line ranges
processor_count = 0
if not processor_functions:
print("\nWarning: No functions starting with 'process_' found at the top level.")
return
print(f"Found {len(processor_functions)} potential processor functions.")
for func_name, start_idx, end_idx in processor_functions:
print(f" - Processing: {func_name} (lines {start_idx+1}-{end_idx})")
func_lines = lines[start_idx:end_idx] # Extract lines for this function
# Remove trailing blank lines from the extracted block, often happens before next def
while func_lines and func_lines[-1].strip() == "":
func_lines.pop()
create_processor_file(func_name, func_lines)
processor_count += 1
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)
# Write the function lines, ensuring consistent newline endings
for line in func_lines:
f.write(line.rstrip() + '\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)