---
name: lua_engine
kind: function
lang: cpp
domain: core
version: "1.0.0"
purity: impure
signature: "lua_engine::Engine* lua_engine::get(); void lua_engine::shutdown(); int lua_engine::compile(Engine*, const std::string& body, std::string* err_out); void lua_engine::release(Engine*, int id); std::string lua_engine::eval(Engine*, int id, const RowCtx& ctx, std::string* err_out); std::string lua_engine::preprocess(const std::string& body)"
description: "Motor Lua 5.4 sandbox para evaluar formulas de columnas. Sandbox quita io/require/dofile/loadfile/load/package/debug; os reducido a date/time/difftime/clock. Builtins fn.* (~20 funciones de string/tipo/fecha). Preprocesa [col_name] -> row[\"col_name\"]. Auto-return si la formula es expresion. Type-aware push segun ColumnType declarado."
tags: [tables, lua, sandbox, formula, tql, cpp-tables]
uses_functions: []
uses_types: ["data_table_types_cpp_core"]
returns: []
returns_optional: true
error_type: "error_go_core"
imports: [lua.h, lualib.h, lauxlib.h]
tested: true
tests:
  - "eval expr simple"
  - "eval con vars via RowCtx"
  - "error en expr invalida"
  - "sandbox bloquea io.open"
  - "preprocess convierte [col] a row[\"col\"]"
  - "fn.* builtins disponibles"
  - "shutdown y reinicio"
test_file_path: "cpp/tests/test_lua_engine.cpp"
file_path: "cpp/functions/core/lua_engine.cpp"
params:
  - name: body
    desc: "Cuerpo de la formula Lua. Expresiones sueltas reciben auto-return. Usa [col_name] para referenciar columnas del RowCtx."
  - name: ctx
    desc: "RowCtx con puntero al array cells row-major, cabeceras, mapa nombre->columna, tipos declarados y columnas derivadas. nullptr en campos opcionales activa heuristica Auto."
output: "std::string con el resultado de la formula convertido a string via luaL_tolstring. Vacio + err_out poblado si hay error de compilacion o runtime."
notes: "Extraido del playground tables (issue 0081-D). Enlaza contra lua54 (vendored en cpp/vendor/lua). Linker: target_link_libraries(tu_target PRIVATE lua54). Origen: cpp/apps/primitives_gallery/playground/tables/lua_engine.{h,cpp}."
---

# lua_engine

Motor Lua 5.4 sandbox para evaluar formulas de columnas en el stack TQL. Diseñado para que `data_table` (y en el futuro `data_table_cpp_viz`) compile y evalúe expresiones definidas por el usuario sin acceso al filesystem ni a la red.

## API

```cpp
#include "core/lua_engine.h"

// Ciclo de vida (singleton por proceso/hilo)
lua_engine::Engine* e = lua_engine::get();
lua_engine::shutdown();  // libera el lua_State; get() crea uno nuevo si se llama de nuevo

// Compilar una formula (una vez por formula, N evals)
std::string err;
int id = lua_engine::compile(e, "[price] * [qty]", &err);  // id >= 0 si ok
if (id < 0) { /* err tiene el mensaje */ }

// Evaluar sobre una fila
lua_engine::RowCtx ctx = { cells, ncols, row_index, &headers, &name_to_col };
std::string result = lua_engine::eval(e, id, ctx, &err);

// Liberar cuando ya no se necesite la formula
lua_engine::release(e, id);
```

## Ejemplo

```cpp
#include "core/lua_engine.h"

// Formula: multiplica price por qty
lua_engine::Engine* e = lua_engine::get();
std::string err;
int id = lua_engine::compile(e, "[price] * [qty]", &err);

// Tabla: 1 fila, cols = {price="10.5", qty="3"}
const char* cells[] = { "10.5", "3" };
std::vector<std::string> headers = { "price", "qty" };
std::unordered_map<std::string,int> name_to_col = { {"price",0}, {"qty",1} };
data_table::ColumnType types[] = { data_table::ColumnType::Float, data_table::ColumnType::Float };

lua_engine::RowCtx ctx;
ctx.cells = cells; ctx.orig_cols = 2; ctx.row = 0;
ctx.header_names = &headers; ctx.name_to_col = &name_to_col;
ctx.types_orig = types; ctx.n_types_orig = 2;

std::string result = lua_engine::eval(e, id, ctx, &err);
// result == "31.5"
lua_engine::release(e, id);
```

## Cuando usarla

Cuando necesites evaluar expresiones de usuario sobre filas de datos tabulares con acceso a columnas por nombre. Antes de invocar `compute_stage` con `DerivedColumn.formula` poblado. Si necesitas un pipeline TQL con formulas, `tql.cpp` usa esta funcion internamente.

## Gotchas

- **Estado interno `lua_State`**: el motor es un singleton con estado mutable. Compile/eval/release modifican el estado del `lua_State`. No es re-entrante por diseño.
- **Sandbox**: `io`, `require`, `loadfile`, `dofile`, `load`, `package`, `debug` son `nil` en el ambiente. `os` solo expone `date`, `time`, `difftime`, `clock`. Intentar `io.open(...)` produce un runtime error (nil index).
- **Thread-safety**: NO thread-safe. Una instancia (`Engine`) por hilo. Si necesitas evaluar formulas en paralelo, crea un motor independiente con `luaL_newstate` por hilo — actualmente la API no expone constructores multiples; extender si hace falta.
- **Linker**: requiere `lua54` (target CMake definido por `cpp/vendor/lua/CMakeLists.txt`). Añadir `target_link_libraries(tu_target PRIVATE lua54)` al CMakeLists de la app/test.
- **Ciclos en derived cols**: detectados con un stack `visiting_derived`; el ciclo retorna `nil` en vez de recursion infinita.
- **Auto-return**: si la formula no comienza con `return`, `if`, `for`, `while`, `do`, `local`, `repeat` o `function`, se antepone `return` automaticamente. Permite escribir `[price] * 1.21` sin `return`.
