392 lines
10 KiB
Markdown
392 lines
10 KiB
Markdown
# Simple Debug API - Calculadora MAV CAS
|
|
|
|
## Descripción
|
|
|
|
API CLI simple que usa el motor de evaluación existente para generar debug traces sin modificar el código base. Permite debuggear "como si usaras la aplicación" mediante archivos JSON.
|
|
|
|
---
|
|
|
|
## Uso
|
|
|
|
```bash
|
|
# Ejecutar debug
|
|
python simple_debug.py debug_input.json
|
|
|
|
# Con archivo de salida específico
|
|
python simple_debug.py debug_input.json --output debug_results.json
|
|
|
|
# Modo verboso
|
|
python simple_debug.py debug_input.json --verbose
|
|
```
|
|
|
|
---
|
|
|
|
## Formato de Entrada
|
|
|
|
### Estructura Simple
|
|
|
|
```json
|
|
{
|
|
"queries": [
|
|
{"index": 0, "type": "input", "content": "10.1.1.1 + 1"},
|
|
{"index": 1, "type": "input", "content": "16#FF + 10"},
|
|
{"index": 2, "type": "exec", "content": "engine.symbol_table"},
|
|
{"index": 3, "type": "input", "content": "x = 5"},
|
|
{"index": 4, "type": "exec", "content": "len(engine.symbol_table)"}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Tipos de Query
|
|
|
|
#### Input Query
|
|
Evalúa expresiones como si las escribieras en la calculadora:
|
|
|
|
```json
|
|
{"index": 0, "type": "input", "content": "10.1.1.1 + 1"}
|
|
{"index": 1, "type": "input", "content": "mask = 255.255.0.0"}
|
|
{"index": 2, "type": "input", "content": "solve(x**2 + 1, x)"}
|
|
```
|
|
|
|
#### Exec Query
|
|
Ejecuta código Python para inspeccionar el estado interno:
|
|
|
|
```json
|
|
{"index": 3, "type": "exec", "content": "engine.symbol_table"}
|
|
{"index": 4, "type": "exec", "content": "engine.parser.get_tokenization_info()"}
|
|
{"index": 5, "type": "exec", "content": "list(engine.base_context.keys())[:10]"}
|
|
```
|
|
|
|
---
|
|
|
|
## Formato de Salida
|
|
|
|
### Estructura de Respuesta
|
|
|
|
```json
|
|
{
|
|
"execution_info": {
|
|
"timestamp": "2025-01-01T10:30:15Z",
|
|
"total_queries": 5,
|
|
"successful": 4,
|
|
"failed": 1
|
|
},
|
|
"results": [
|
|
{
|
|
"index": 0,
|
|
"input": "10.1.1.1 + 1",
|
|
"output": "10.1.1.2",
|
|
"result_type": "FourBytes",
|
|
"success": true
|
|
},
|
|
{
|
|
"index": 1,
|
|
"input": "16#FF + 10",
|
|
"output": "16#109",
|
|
"result_type": "IntBase",
|
|
"success": true
|
|
},
|
|
{
|
|
"index": 2,
|
|
"input": "engine.symbol_table",
|
|
"output": "{'x': Symbol('x'), 'mask': FourBytes('255.255.0.0')}",
|
|
"result_type": "dict",
|
|
"success": true
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Resultado Individual
|
|
|
|
```json
|
|
{
|
|
"index": 0,
|
|
"input": "10.1.1.1 + 1",
|
|
"output": "10.1.1.2",
|
|
"result_type": "FourBytes",
|
|
"success": true,
|
|
"error": null,
|
|
"display_class": "[FourBytes]"
|
|
}
|
|
```
|
|
|
|
### Resultado con Error
|
|
|
|
```json
|
|
{
|
|
"index": 3,
|
|
"input": "IP4Mask(255.240.0.3)",
|
|
"output": null,
|
|
"result_type": null,
|
|
"success": false,
|
|
"error": "ValueError: Máscara inválida: 255.240.0.3"
|
|
}
|
|
```
|
|
|
|
### Resultado de Exec
|
|
|
|
```json
|
|
{
|
|
"index": 4,
|
|
"input": "len(engine.symbol_table)",
|
|
"output": "3",
|
|
"result_type": "int",
|
|
"success": true,
|
|
"exec_result": 3
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Casos de Uso Comunes
|
|
|
|
### 1. Debug de Tokenización
|
|
|
|
```json
|
|
{
|
|
"queries": [
|
|
{"index": 0, "type": "input", "content": "192.168.1.1 + 16#FF"},
|
|
{"index": 1, "type": "exec", "content": "engine.parser.process_expression('192.168.1.1 + 16#FF')"},
|
|
{"index": 2, "type": "exec", "content": "engine.parser.get_tokenization_info()"}
|
|
]
|
|
}
|
|
```
|
|
|
|
### 2. Debug de Contexto
|
|
|
|
```json
|
|
{
|
|
"queries": [
|
|
{"index": 0, "type": "input", "content": "x = 5"},
|
|
{"index": 1, "type": "input", "content": "y = x + 10"},
|
|
{"index": 2, "type": "exec", "content": "engine.symbol_table"},
|
|
{"index": 3, "type": "exec", "content": "len(engine.equations)"}
|
|
]
|
|
}
|
|
```
|
|
|
|
### 3. Debug de Tipos
|
|
|
|
```json
|
|
{
|
|
"queries": [
|
|
{"index": 0, "type": "input", "content": "ip = 10.1.1.x"},
|
|
{"index": 1, "type": "exec", "content": "type(engine.symbol_table['ip'])"},
|
|
{"index": 2, "type": "exec", "content": "engine.symbol_table['ip'].has_symbols"},
|
|
{"index": 3, "type": "input", "content": "ip.substitute(x=5)"}
|
|
]
|
|
}
|
|
```
|
|
|
|
### 4. Debug de Errores
|
|
|
|
```json
|
|
{
|
|
"queries": [
|
|
{"index": 0, "type": "input", "content": "bad_mask = 255.240.0.3"},
|
|
{"index": 1, "type": "input", "content": "IP4Mask(bad_mask)"},
|
|
{"index": 2, "type": "exec", "content": "engine.last_result"}
|
|
]
|
|
}
|
|
```
|
|
|
|
### 5. Testing de Regresión
|
|
|
|
```json
|
|
{
|
|
"queries": [
|
|
{"index": 0, "type": "input", "content": "10.1.1.1 + 1"},
|
|
{"index": 1, "type": "exec", "content": "str(type(engine.last_result))"},
|
|
{"index": 2, "type": "exec", "content": "engine.last_result.original"},
|
|
{"index": 3, "type": "input", "content": "16#FF + 10"},
|
|
{"index": 4, "type": "exec", "content": "engine.last_result.base"}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Funciones Útiles para Exec
|
|
|
|
### Estado del Motor
|
|
|
|
```python
|
|
# Contexto y variables
|
|
"engine.symbol_table" # Variables actuales
|
|
"list(engine.base_context.keys())" # Funciones disponibles
|
|
"len(engine.equations)" # Ecuaciones en el sistema
|
|
"engine.last_result" # Último resultado
|
|
|
|
# Configuración del motor
|
|
"engine.symbolic_mode" # ¿Modo simbólico?
|
|
"engine.debug" # ¿Debug habilitado?
|
|
```
|
|
|
|
### Información de Tipos
|
|
|
|
```python
|
|
# Tipos registrados
|
|
"engine.get_available_types()" # Info completa de tipos
|
|
"list(engine.registered_types_info['registered_classes'].keys())" # Tipos disponibles
|
|
"engine.registered_types_info['class_count']" # Cantidad de tipos
|
|
|
|
# Análisis de objetos
|
|
"type(engine.last_result)" # Tipo del último resultado
|
|
"engine.last_result.__class__.__name__" # Nombre de la clase
|
|
"hasattr(engine.last_result, 'has_symbols')" # ¿Tiene símbolos?
|
|
```
|
|
|
|
### Tokenización y Parsing
|
|
|
|
```python
|
|
# Tokenización
|
|
"engine.parser.get_tokenization_info()" # Info de tokenización
|
|
"engine.parser.process_expression('test')" # Procesar expresión
|
|
"len(engine.parser.tokenizer.tokenization_rules)" # Cantidad de reglas
|
|
|
|
# Análisis de expresiones
|
|
"engine._classify_line('x = 5')" # Clasificar línea
|
|
"engine._extract_variable_names('x + y')" # Extraer variables
|
|
```
|
|
|
|
### Testing de Funciones Específicas
|
|
|
|
```python
|
|
# Testing de FourBytes
|
|
"engine.last_result._numeric_value" # Valor numérico interno
|
|
"engine.last_result.has_symbols" # ¿Tiene símbolos?
|
|
"engine.last_result.original" # String original
|
|
|
|
# Testing de IntBase
|
|
"engine.last_result.base" # Base numérica
|
|
"engine.last_result.value_str" # String del valor
|
|
"engine.last_result._symbols" # Símbolos detectados
|
|
```
|
|
|
|
---
|
|
|
|
## Implementación Simple
|
|
|
|
### Estructura Mínima
|
|
|
|
```
|
|
simple_debug.py # CLI principal (~100 líneas)
|
|
debug_templates/ # Templates de ejemplo
|
|
├── basic_test.json
|
|
├── tokenization_test.json
|
|
└── regression_test.json
|
|
```
|
|
|
|
### CLI Principal (Pseudocódigo)
|
|
|
|
```python
|
|
# simple_debug.py
|
|
import json
|
|
from main_evaluation import HybridEvaluationEngine
|
|
|
|
def run_debug(input_file, output_file=None):
|
|
# Cargar queries
|
|
with open(input_file) as f:
|
|
data = json.load(f)
|
|
|
|
# Crear motor
|
|
engine = HybridEvaluationEngine()
|
|
results = []
|
|
|
|
# Ejecutar cada query
|
|
for query in data['queries']:
|
|
if query['type'] == 'input':
|
|
result = engine.evaluate_line(query['content'])
|
|
output = {
|
|
'index': query['index'],
|
|
'input': query['content'],
|
|
'output': str(result.result),
|
|
'result_type': type(result.result).__name__,
|
|
'success': not result.is_error,
|
|
'error': result.error if result.is_error else None
|
|
}
|
|
elif query['type'] == 'exec':
|
|
try:
|
|
exec_result = eval(query['content'], {'engine': engine})
|
|
output = {
|
|
'index': query['index'],
|
|
'input': query['content'],
|
|
'output': str(exec_result),
|
|
'result_type': type(exec_result).__name__,
|
|
'success': True,
|
|
'exec_result': exec_result
|
|
}
|
|
except Exception as e:
|
|
output = {
|
|
'index': query['index'],
|
|
'input': query['content'],
|
|
'success': False,
|
|
'error': str(e)
|
|
}
|
|
|
|
results.append(output)
|
|
|
|
# Guardar resultados
|
|
final_output = {
|
|
'execution_info': {...},
|
|
'results': results
|
|
}
|
|
|
|
with open(output_file, 'w') as f:
|
|
json.dump(final_output, f, indent=2)
|
|
```
|
|
|
|
---
|
|
|
|
## Templates de Ejemplo
|
|
|
|
### basic_test.json
|
|
```json
|
|
{
|
|
"queries": [
|
|
{"index": 0, "type": "input", "content": "10.1.1.1 + 1"},
|
|
{"index": 1, "type": "exec", "content": "type(engine.last_result).__name__"},
|
|
{"index": 2, "type": "input", "content": "16#FF"},
|
|
{"index": 3, "type": "exec", "content": "engine.last_result.base"}
|
|
]
|
|
}
|
|
```
|
|
|
|
### tokenization_test.json
|
|
```json
|
|
{
|
|
"queries": [
|
|
{"index": 0, "type": "exec", "content": "engine.parser.process_expression('192.168.1.1 + 16#FF')"},
|
|
{"index": 1, "type": "input", "content": "192.168.1.1 + 16#FF"},
|
|
{"index": 2, "type": "exec", "content": "engine.parser.get_tokenization_info()['rules'][:3]"}
|
|
]
|
|
}
|
|
```
|
|
|
|
### regression_test.json
|
|
```json
|
|
{
|
|
"queries": [
|
|
{"index": 0, "type": "input", "content": "mask=255.240.0.0"},
|
|
{"index": 1, "type": "exec", "content": "type(engine.symbol_table['mask']).__name__"},
|
|
{"index": 2, "type": "input", "content": "10.1.1.1 + 1"},
|
|
{"index": 3, "type": "exec", "content": "type(engine.last_result).__name__"},
|
|
{"index": 4, "type": "input", "content": "IP4Mask(255.255.0.0)"},
|
|
{"index": 5, "type": "exec", "content": "engine.last_result.get_prefix_int()"}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Ventajas de este Diseño
|
|
|
|
✅ **Simplicidad**: ~100 líneas de código total
|
|
✅ **Sin modificaciones**: Usa el motor existente tal como está
|
|
✅ **Flexibilidad**: Cualquier función del engine es accesible via exec
|
|
✅ **Debugging real**: Exactamente como usar la aplicación
|
|
✅ **Fácil testing**: JSON simple para casos de prueba
|
|
✅ **Serialización automática**: Python maneja la conversión a string
|
|
|
|
Esta aproximación te permite debuggear efectivamente sin crear una infraestructura compleja, usando el poder del motor existente. |