Calc/.doc/refactoring/remover_corchetes.md

27 KiB

Refactorización: Sistema de Tokenización Algebraica

Resumen Ejecutivo

Reemplazar el sistema actual de corchetes por un tokenizador que convierte automáticamente patrones específicos en objetos tipados con capacidades algebraicas completas.

Problemas del Sistema Actual

Sistema de Corchetes

  • Complejidad innecesaria del BracketParser
  • Conflictos con eval() y SymPy
  • Sintaxis no estándar
  • Beneficios limitados (solo IPs realmente)
  • Dificulta la integración algebraica

Impacto

  • Código complejo para casos simples
  • Curva de aprendizaje innecesaria
  • Mantenimiento difícil
  • Extensibilidad limitada

Nuevo Sistema: Tokenización Algebraica

Filosofía Central

El usuario escribe código Python normal. El parser mejora automáticamente los tipos de datos.

Patrones de Tokenización

1. IntBase: base#valor

# Input usuario          # Post-tokenización
16#FF                 →   IntBase('FF', 16)
2#1010               →   IntBase('1010', 2) 
8#777                →   IntBase('777', 8)
16#x0                →   IntBase('x0', 16)      # ← ALGEBRAICO
2#101x               →   IntBase('101x', 2)     # ← ALGEBRAICO

2. FourBytes: x.x.x.x

# Input usuario          # Post-tokenización
192.168.1.1             FourBytes('192.168.1.1')
255.255.0.0             FourBytes('255.255.0.0')
10.1.x.2                FourBytes('10.1.x.2')      # ← ALGEBRAICO
a.b.c.d                 FourBytes('a.b.c.d')       # ← ALGEBRAICO

Precedencia de Tokenización

def preprocess_tokens(expression):
    # 1. MAYOR PRECEDENCIA: IntBase (patrón más específico)
    expression = re.sub(r'(\d+)#([0-9A-Fa-fx]+)', r'IntBase("\2", \1)', expression)
    
    # 2. MENOR PRECEDENCIA: FourBytes (patrón más general)
    expression = re.sub(r'\b([a-zA-Z0-9_]+\.[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+)\b', 
                       r'FourBytes("\1")', expression)
    
    return expression

Clases Base Universales

IntBase: Universal para Bases Numéricas

class IntBase(SympyClassBase):
    """
    Representación universal de números en cualquier base
    con soporte algebraico completo y operaciones aritméticas
    """
    
    def __init__(self, value_str, base=10):
        self.value_str = value_str
        self.base = base
        self.has_symbols = bool(re.search(r'[a-zA-Z_]', value_str))
        
        if self.has_symbols:
            # Modo algebraico: mantener como expresión simbólica
            self._symbolic_value = self._parse_symbolic_base()
            super().__init__(self._symbolic_value, f"{base}#{value_str}")
        else:
            # Modo numérico: convertir a entero
            self._numeric_value = int(value_str, base)
            super().__init__(self._numeric_value, f"{base}#{value_str}")
    
    def _parse_symbolic_base(self):
        """Convierte valor con símbolos a expresión SymPy"""
        # Ejemplo: "x0" base 16 → x*16^1 + 0*16^0
        # Ejemplo: "101x" base 2 → 1*2^3 + 0*2^2 + 1*2^1 + x*2^0
        symbols = []
        result = 0
        digits = list(self.value_str)
        
        for i, digit in enumerate(reversed(digits)):
            power = self.base ** i
            if digit.isdigit():
                coefficient = int(digit)
            elif digit in 'ABCDEF':
                coefficient = ord(digit) - ord('A') + 10
            elif digit in 'abcdef':
                coefficient = ord(digit) - ord('a') + 10
            else:
                # Es un símbolo
                coefficient = sympy.Symbol(digit)
                symbols.append(digit)
            
            result += coefficient * power
        
        return result
    
    def to_base(self, new_base):
        """Convierte a nueva base"""
        if self.has_symbols:
            # En modo algebraico, mantener expresión
            return IntBase(f"({self._symbolic_value})_base{new_base}", new_base)
        else:
            # En modo numérico, convertir directamente
            new_value_str = self._convert_to_base_string(self._numeric_value, new_base)
            return IntBase(new_value_str, new_base)
    
    @staticmethod
    def _convert_to_base_string(value, base):
        """Convierte entero a string en base específica"""
        if value == 0:
            return "0"
        digits = "0123456789ABCDEF"
        result = ""
        while value:
            result = digits[value % base] + result
            value //= base
        return result
    
    # ========== OPERADORES ARITMÉTICOS ==========
    
    def __add__(self, other):
        """Suma: mantiene la base del operando izquierdo"""
        if self.has_symbols:
            return super().__add__(other)  # Delegar a SymPy
        
        if isinstance(other, IntBase):
            if other.has_symbols:
                return super().__add__(other)
            result_value = self._numeric_value + other._numeric_value
        elif isinstance(other, int):
            result_value = self._numeric_value + other
        else:
            return super().__add__(other)
        
        result_str = self._convert_to_base_string(result_value, self.base)
        return IntBase(result_str, self.base)
    
    def __sub__(self, other):
        """Resta: mantiene la base del operando izquierdo"""
        if self.has_symbols:
            return super().__sub__(other)
        
        if isinstance(other, IntBase):
            if other.has_symbols:
                return super().__sub__(other)
            result_value = self._numeric_value - other._numeric_value
        elif isinstance(other, int):
            result_value = self._numeric_value - other
        else:
            return super().__sub__(other)
        
        result_str = self._convert_to_base_string(result_value, self.base)
        return IntBase(result_str, self.base)
    
    def __mul__(self, other):
        """Multiplicación: mantiene la base del operando izquierdo"""
        if self.has_symbols:
            return super().__mul__(other)
        
        if isinstance(other, IntBase):
            if other.has_symbols:
                return super().__mul__(other)
            result_value = self._numeric_value * other._numeric_value
        elif isinstance(other, int):
            result_value = self._numeric_value * other
        else:
            return super().__mul__(other)
        
        result_str = self._convert_to_base_string(result_value, self.base)
        return IntBase(result_str, self.base)
    
    def __truediv__(self, other):
        """División: mantiene la base del operando izquierdo"""
        if self.has_symbols:
            return super().__truediv__(other)
        
        if isinstance(other, IntBase):
            if other.has_symbols:
                return super().__truediv__(other)
            result_value = self._numeric_value // other._numeric_value  # División entera
        elif isinstance(other, int):
            result_value = self._numeric_value // other
        else:
            return super().__truediv__(other)
        
        result_str = self._convert_to_base_string(result_value, self.base)
        return IntBase(result_str, self.base)
    
    def __mod__(self, other):
        """Módulo: mantiene la base del operando izquierdo"""
        if self.has_symbols:
            return super().__mod__(other)
        
        if isinstance(other, IntBase):
            if other.has_symbols:
                return super().__mod__(other)
            result_value = self._numeric_value % other._numeric_value
        elif isinstance(other, int):
            result_value = self._numeric_value % other
        else:
            return super().__mod__(other)
        
        result_str = self._convert_to_base_string(result_value, self.base)
        return IntBase(result_str, self.base)
    
    # Operadores reversos para int + IntBase
    def __radd__(self, other):
        return self.__add__(other)
    
    def __rsub__(self, other):
        if isinstance(other, int):
            result_value = other - self._numeric_value
            result_str = self._convert_to_base_string(result_value, self.base)
            return IntBase(result_str, self.base)
        return super().__rsub__(other)
    
    def __rmul__(self, other):
        return self.__mul__(other)

FourBytes: Universal para Patrones x.x.x.x

class FourBytes(SympyClassBase):
    """
    Representación universal de patrones de 4 elementos
    con soporte algebraico completo y operaciones aritméticas
    """
    
    def __init__(self, dotted_string):
        self.original = dotted_string
        self.elements = dotted_string.split('.')
        
        if len(self.elements) != 4:
            raise ValueError(f"FourBytes requiere exactamente 4 elementos: {dotted_string}")
        
        self.has_symbols = any(not elem.isdigit() for elem in self.elements)
        
        if self.has_symbols:
            # Modo algebraico: crear expresión simbólica
            self._symbolic_elements = []
            for elem in self.elements:
                if elem.isdigit():
                    self._symbolic_elements.append(int(elem))
                else:
                    self._symbolic_elements.append(sympy.Symbol(elem))
            
            # Crear expresión como vector de 4 elementos
            self._symbolic_value = sympy.Matrix(self._symbolic_elements)
            super().__init__(self._symbolic_value, dotted_string)
        else:
            # Modo numérico: validar rangos y convertir
            self._numeric_elements = [int(elem) for elem in self.elements]
            # Crear valor como entero de 32 bits (para IPs)
            self._numeric_value = (self._numeric_elements[0] << 24 | 
                                 self._numeric_elements[1] << 16 | 
                                 self._numeric_elements[2] << 8 | 
                                 self._numeric_elements[3])
            super().__init__(self._numeric_value, dotted_string)
    
    def is_valid_ip_range(self):
        """Verifica si todos los elementos numéricos están en rango IP"""
        if self.has_symbols:
            return None  # No se puede validar con símbolos
        return all(0 <= x <= 255 for x in self._numeric_elements)
    
    def substitute(self, **kwargs):
        """Sustituye símbolos por valores"""
        if not self.has_symbols:
            return self
        
        new_elements = []
        for elem in self.elements:
            if elem in kwargs:
                new_elements.append(str(kwargs[elem]))
            else:
                new_elements.append(elem)
        
        return FourBytes('.'.join(new_elements))
    
    def __getitem__(self, index):
        """Acceso a elementos individuales"""
        if self.has_symbols:
            return self._symbolic_elements[index]
        else:
            return self._numeric_elements[index]
    
    def to_ip_int(self):
        """Convierte a entero de 32 bits (para IPs)"""
        if self.has_symbols:
            # Crear expresión algebraica
            return (self._symbolic_elements[0] * 2**24 + 
                   self._symbolic_elements[1] * 2**16 + 
                   self._symbolic_elements[2] * 2**8 + 
                   self._symbolic_elements[3])
        else:
            return self._numeric_value
    
    @staticmethod
    def _int_to_fourbytes(value):
        """Convierte entero de 32 bits a formato x.y.z.w"""
        w = value & 0xFF
        z = (value >> 8) & 0xFF
        y = (value >> 16) & 0xFF
        x = (value >> 24) & 0xFF
        return f"{x}.{y}.{z}.{w}"
    
    # ========== OPERADORES ARITMÉTICOS ==========
    
    def __add__(self, other):
        """Suma: convierte a int, opera, reconvierte a FourBytes"""
        if self.has_symbols:
            return super().__add__(other)  # Delegar a SymPy
        
        if isinstance(other, FourBytes):
            if other.has_symbols:
                return super().__add__(other)
            result_int = self._numeric_value + other._numeric_value
        elif isinstance(other, int):
            result_int = self._numeric_value + other
        else:
            return super().__add__(other)
        
        # Mantener en rango de 32 bits
        result_int = result_int & 0xFFFFFFFF
        result_str = self._int_to_fourbytes(result_int)
        return FourBytes(result_str)
    
    def __sub__(self, other):
        """Resta: convierte a int, opera, reconvierte a FourBytes"""
        if self.has_symbols:
            return super().__sub__(other)
        
        if isinstance(other, FourBytes):
            if other.has_symbols:
                return super().__sub__(other)
            result_int = self._numeric_value - other._numeric_value
        elif isinstance(other, int):
            result_int = self._numeric_value - other
        else:
            return super().__sub__(other)
        
        # Mantener en rango de 32 bits (underflow se convierte en valor alto)
        result_int = result_int & 0xFFFFFFFF
        result_str = self._int_to_fourbytes(result_int)
        return FourBytes(result_str)
    
    # ========== CONVERSIONES DE BASE ==========
    
    def ToBase(self, base):
        """
        Convierte cada elemento a la base especificada
        Retorna expresión con cada elemento convertido
        """
        if self.has_symbols:
            # Para elementos simbólicos, retornar expresión algebraica
            converted_elements = []
            for elem in self.elements:
                if elem.isdigit():
                    int_val = int(elem)
                    converted = IntBase._convert_to_base_string(int_val, base)
                    converted_elements.append(f"{base}#{converted}")
                else:
                    # Símbolo: expresar como conversión algebraica
                    converted_elements.append(f"{base}#{elem}")
            return '.'.join(converted_elements)
        else:
            # Para elementos numéricos, conversión directa
            converted_elements = []
            for elem_val in self._numeric_elements:
                converted = IntBase._convert_to_base_string(elem_val, base)
                converted_elements.append(f"{base}#{converted}")
            return '.'.join(converted_elements)
    
    def ToCIDR(self, prefix_length):
        """Convierte a notación CIDR"""
        return f"{self.original}/{prefix_length}"
    
    def ToHex(self):
        """Convierte cada elemento a hexadecimal"""
        return self.ToBase(16)
    
    def ToBinary(self):
        """Convierte cada elemento a binario"""
        return self.ToBase(2)
    
    def ToOctal(self):
        """Convierte cada elemento a octal"""
        return self.ToBase(8)

Integración con Clases Especializadas

Constructores Mejorados

class IP4(SympyClassBase):
    def __init__(self, address, mask=None):
        # address es FourBytes (ya tokenizado)
        if not isinstance(address, FourBytes):
            raise TypeError("address debe ser FourBytes")
        
        self.address = address
        
        if mask is not None:
            if isinstance(mask, int):
                self.mask = IP4Mask(mask)  # CIDR
            elif isinstance(mask, FourBytes):
                self.mask = IP4Mask(mask)  # Dotted decimal
            elif isinstance(mask, IntBase):
                # Conversión automática desde hex: 16#ffffff00 → máscara
                if not mask.has_symbols:
                    mask_int = mask._numeric_value
                    # Convertir a FourBytes primero
                    mask_fourbytes = FourBytes(FourBytes._int_to_fourbytes(mask_int))
                    self.mask = IP4Mask(mask_fourbytes)
                else:
                    self.mask = mask  # Mantener simbólico
            else:
                self.mask = mask

class Hex(SympyClassBase):
    def __init__(self, value):
        if isinstance(value, IntBase):
            # value es IntBase (ya tokenizado)
            self.int_base = value
            super().__init__(value.value, value.original)
        elif isinstance(value, FourBytes):
            # Conversión automática desde FourBytes
            if not value.has_symbols:
                # Convertir a valor hex único (32 bits)
                hex_value = hex(value._numeric_value)[2:].upper()
                self.int_base = IntBase(hex_value, 16)
                super().__init__(value._numeric_value, f"16#{hex_value}")
            else:
                # Mantener simbólico para análisis algebraico
                self.int_base = value
                super().__init__(value._symbolic_value, str(value))
        else:
            raise TypeError("value debe ser IntBase o FourBytes")

class Bin(SympyClassBase):
    def __init__(self, value):
        if isinstance(value, IntBase):
            # Conversión automática de cualquier base a binario
            if not value.has_symbols:
                bin_value = bin(value._numeric_value)[2:]  # Remover '0b'
                self.int_base = IntBase(bin_value, 2)
                super().__init__(value._numeric_value, f"2#{bin_value}")
            else:
                self.int_base = value
                super().__init__(value._symbolic_value, str(value))
        elif isinstance(value, FourBytes):
            # Convertir cada elemento a binario
            if not value.has_symbols:
                # Para FourBytes, crear representación elemento por elemento
                bin_elements = []
                for elem in value._numeric_elements:
                    bin_elements.append(bin(elem)[2:].zfill(8))  # 8 bits por elemento
                bin_representation = '.'.join(f"2#{elem}" for elem in bin_elements)
                
                # Crear IntBase con valor completo
                full_bin = ''.join(bin_elements)
                self.int_base = IntBase(full_bin, 2)
                super().__init__(value._numeric_value, bin_representation)
            else:
                self.int_base = value
                super().__init__(value._symbolic_value, str(value))
        else:
            raise TypeError("value debe ser IntBase o FourBytes")

class IP4Mask(ClassBase):
    def __init__(self, mask_input):
        if isinstance(mask_input, int):
            # CIDR notation
            self.prefix = mask_input
            self.mask_int = self._prefix_to_mask_int(mask_input)
        elif isinstance(mask_input, FourBytes):
            # Dotted decimal desde tokenización automática
            if not mask_input.has_symbols:
                self.mask_int = mask_input._numeric_value
                self.prefix = self._mask_int_to_prefix(self.mask_int)
            else:
                # Mantener simbólico
                self.prefix = None
                self.mask_int = mask_input._symbolic_value
        elif isinstance(mask_input, IntBase):
            # Desde hex u otra base
            if not mask_input.has_symbols:
                self.mask_int = mask_input._numeric_value
                self.prefix = self._mask_int_to_prefix(self.mask_int)
            else:
                # Mantener simbólico  
                self.prefix = None
                self.mask_int = mask_input._symbolic_value
        else:
            raise TypeError("mask_input debe ser int, FourBytes, o IntBase")
        
        super().__init__(self.mask_int, str(mask_input))

Conversiones Automáticas Bidireccionales

# Sistema de conversión fluido entre tipos:

class UniversalConverter:
    """Conversiones automáticas entre todos los tipos"""
    
    @staticmethod
    def auto_convert(source, target_type):
        """Convierte automáticamente entre tipos compatibles"""
        
        if target_type == Hex:
            if isinstance(source, FourBytes):
                return Hex(source)  # Usa constructor mejorado
            elif isinstance(source, IntBase):
                return Hex(source)
        
        elif target_type == IP4:
            if isinstance(source, FourBytes):
                return IP4(source)
            elif isinstance(source, str) and '.' in source:
                # Tokenización automática
                tokenized = preprocess_tokens(source)
                return eval(f"IP4({tokenized})")
        
        elif target_type == Bin:
            if isinstance(source, (IntBase, FourBytes)):
                return Bin(source)
        
        # Continuar para otros tipos...

# Ejemplos de uso fluido:

# 1. IP con máscara hexadecimal (automático):
ip1 = IP4(192.168.1.1, 16#ffffff00)  
# Tokeniza a: IP4(FourBytes('192.168.1.1'), IntBase('ffffff00', 16))
# Constructor IP4 convierte IntBase → IP4Mask automáticamente

# 2. Hex desde IP (automático):
ip_bytes = FourBytes('192.168.1.1')
hex_ip = Hex(ip_bytes)               
# Constructor Hex convierte FourBytes → representación hex

# 3. Análisis de máscara en múltiples bases:
mask = FourBytes('255.255.255.0')
mask_hex = Hex(mask)                 # → Hex basado en 32-bit value
mask_bin = Bin(mask)                 # → Bin con representación por elementos
mask_cidr = IP4Mask(mask)            # → /24

# 4. Operaciones mixtas automáticas:
base_ip = FourBytes('10.0.0.0')     
offset = 16#100                      # Tokeniza a IntBase('100', 16) = 256
next_ip = base_ip + offset           # → FourBytes('10.0.1.0')

Casos de Uso Algebraicos

1. Redes con Variables

# Usuario escribe:
network = IP4(192.168.x.0, 24)

# Tokenizado automáticamente a:
network = IP4(FourBytes('192.168.x.0'), 24)

# Operaciones algebraicas:
network.substitute(x=1)  # → IP4(192.168.1.0, 24)
network.address[2]       # → Symbol('x')

2. Aritmética de Bases

# Usuario escribe:
hex_val = Hex(16#x0)

# Tokenizado automáticamente a:
hex_val = Hex(IntBase('x0', 16))

# Operaciones algebraicas:
hex_val.substitute(x=15)  # → Hex(240)
hex_val + 1              # → 16*x + 1

3. Operaciones Aritméticas con IntBase

# Operaciones mantienen la base original:
a = 16#FF                # → IntBase('FF', 16)
b = 16#10                # → IntBase('10', 16) 
result = a + b           # → IntBase('10F', 16)  [255 + 16 = 271]

# Operaciones mixtas con enteros:
c = 16#A0 + 32           # → IntBase('C0', 16)   [160 + 32 = 192]
d = 2#1010 * 3           # → IntBase('11110', 2) [10 * 3 = 30]

# Operaciones entre bases diferentes:
e = 16#FF + 2#1010       # → IntBase('109', 16)  [255 + 10 = 265]

4. Operaciones Aritméticas con FourBytes

# Aritmética de direcciones:
ip1 = FourBytes('192.168.1.1')      # → ip_int = 3232235777
ip2 = FourBytes('0.0.0.5')          # → ip_int = 5
next_ip = ip1 + ip2                  # → FourBytes('192.168.1.6')

# Incremento simple:
base_ip = FourBytes('10.0.0.0')
next_net = base_ip + 256             # → FourBytes('10.0.1.0')
                                     
# Cálculos de rango:
start = FourBytes('192.168.1.0')
end = start + 255                    # → FourBytes('192.168.1.255')

5. Conversiones Automáticas Bidireccionales

# FourBytes → Otras bases:
ip = FourBytes('10.1.3.15')
ip.ToHex()                          # → "16#A.16#1.16#3.16#F"
ip.ToBinary()                       # → "2#1010.2#1.2#11.2#1111"
ip.ToBase(8)                        # → "8#12.8#1.8#3.8#17"

# Conversión directa en constructores:
hex_ip = Hex(FourBytes('10.1.3.15'))      # Automático via tokenización
ip_from_hex = IP4(FourBytes('10.1.3.16#ff'))  # 16#ff se tokeniza a IntBase

# Conversiones fluidas:
mask = FourBytes('255.255.255.0')
mask.ToBase(2)                      # → "2#11111111.2#11111111.2#11111111.2#0"

6. Análisis de Rangos con Constraints

# Red con parámetros:
net = IP4(10.a.b.0, c)

# Encontrar valores válidos:
constraints = [
    net.address[1] >= 0,    # a >= 0
    net.address[1] <= 255,  # a <= 255
    net.address[2] >= 0,    # b >= 0  
    net.address[2] <= 255,  # b <= 255
    c >= 8,                 # c >= 8
    c <= 30                 # c <= 30
]

solutions = solve(constraints, [a, b, c])

7. Ejemplos Prácticos de Conversión

# Ejemplo 1: IP con máscara hexadecimal
ip_hex_mask = IP4(192.168.1.1, 16#ffffff00)  # Tokeniza automáticamente
# Equivale a: IP4(FourBytes('192.168.1.1'), IntBase('ffffff00', 16))

# Ejemplo 2: Conversión de máscara
mask_fourbytes = FourBytes('255.255.255.0')
mask_hex = mask_fourbytes.ToHex()            # → "16#FF.16#FF.16#FF.16#0"
mask_cidr = mask_fourbytes.ToCIDR(24)        # → "255.255.255.0/24"

# Ejemplo 3: Aritmética mixta
base_net = FourBytes('192.168.0.0')
subnet_size = 2#100000000                    # 256 en binario
next_subnet = base_net + subnet_size         # → FourBytes('192.168.1.0')

# Ejemplo 4: Análisis de subredes
network = FourBytes('10.0.0.0')
for i in range(4):
    subnet = network + (i * 256)
    print(f"Subred {i}: {subnet}")
    # Subred 0: 10.0.0.0
    # Subred 1: 10.0.1.0  
    # Subred 2: 10.0.2.0
    # Subred 3: 10.0.3.0

Ventajas del Nuevo Sistema

1. Simplicidad

  • Sin parser complejo
  • Sintaxis estándar (Python puro)
  • Tokenización simple y rápida
  • Integración natural con eval()

2. Potencia Algebraica

  • Variables en cualquier posición
  • Sustituciones automáticas
  • Integración completa con SymPy
  • Análisis simbólico de redes/números

3. Extensibilidad

  • Fácil agregar nuevos patrones
  • Clases especializadas más simples
  • Reutilización de lógica base
  • Escalabilidad natural

4. Intuitividad

  • Usuario escribe código normal
  • Sin sintaxis especial que memorizar
  • Comportamiento predecible
  • Curva de aprendizaje mínima

Posibles Problemas y Soluciones

1. Ambigüedad x.y vs x.y.z.w

# PROBLEMA: ¿x.y es acceso a atributo o parte de FourBytes?
# SOLUCIÓN: Solo tokenizar si hay exactamente 4 elementos
pattern = r'\b([a-zA-Z0-9_]+\.[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+)\b'

2. Precedencia de Operadores

# PROBLEMA: 192.168.1.1 + 1 
# SOLUCIÓN: Tokenización antes de parsing de operadores
# Resultado: FourBytes('192.168.1.1') + 1

3. Validación con Símbolos

# PROBLEMA: ¿Cómo validar 10.x.1.2 como IP?
# SOLUCIÓN: Validación condicional y constraint solving
def is_valid_ip_symbolic(fourbytes):
    if not fourbytes.has_symbols:
        return fourbytes.is_valid_ip_range()
    
    # Crear constraints para símbolos
    constraints = []
    for i, elem in enumerate(fourbytes.elements):
        if not elem.isdigit():
            symbol = Symbol(elem)
            constraints.extend([symbol >= 0, symbol <= 255])
    
    return constraints

Plan de Implementación

Fase 1: Clases Base

  1. Implementar IntBase con soporte algebraico
  2. Implementar FourBytes con soporte algebraico
  3. Tests exhaustivos de ambas clases

Fase 2: Tokenizador

  1. Implementar preprocess_tokens()
  2. Integrar con HybridEvaluationEngine
  3. Tests de tokenización

Fase 3: Migración de Clases

  1. Migrar Hex, Bin, Dec a usar IntBase
  2. Migrar IP4, IP4Mask a usar FourBytes
  3. Eliminar sistema de corchetes

Fase 4: Nuevas Capacidades

  1. Operaciones algebraicas avanzadas
  2. Constraint solving para redes
  3. Análisis simbólico de rangos

Conclusión

Esta refactorización elimina complejidad innecesaria mientras añade capacidades algebraicas poderosas. El resultado será:

  • Más simple para casos básicos
  • Más poderoso para casos avanzados
  • Más intuitivo para el usuario
  • Más extensible para el futuro

El tokenizador automático hace que el usuario no tenga que aprender sintaxis especial, mientras que el soporte algebraico completo permite análisis sofisticados cuando se necesitan.