⚙️ Compile subsystem — HIX_Compile*¶
HIX expone un subsistema unificado para compilar y ejecutar código Harbour
dinámico desde dentro de tu aplicación. Es la vía que utiliza internamente
el dispatcher (.prg cargados dinámicamente), los loaders, los middlewares
y el motor de vistas. Lo tienes disponible también para tus propios
controllers cuando necesites compilar o ejecutar un .prg o un HRB
precompilado en tiempo de respuesta.
🧭 Introducido en v2.3.12, consolidado en v2.4.0 como única vía de compilación de la lib. La antigua
HIX_CompileFilefue eliminada en v2.4.0.
Por qué un subsistema¶
Antes de v2.3.12 había dos caminos distintos: uno para compile puro
(HIX_CompileFile + hb_CompileFromBuf) y otro para compile+run, con
contratos de error diferentes y stack walkers específicos de cada caller.
Resultado: código duplicado, errores difíciles de propagar y boot logs
asimétricos entre loaders y dispatcher.
v2.4.0 consolida todos esos caminos (dispatcher, loaders, middleware loader, motor de vistas) sobre un único contrato hash:
ok— booleano,.T.si la fase final no produjo error.phase— en qué fase quedó la ejecución:"compile","load","run".hrb— bytes del HRB resultante del compile (si la fase compile pasó).err— hash normalizado del error (ver más abajo).NILsiok=.T..diagnostics— array de diagnósticos secundarios (warnings, lines,...).preambleLines— nº de líneas de preamble inyectadas (ajustalinedelerr).where— info de localización del compile (filename, etc).
API pública¶
Todas las funciones nunca propagan Break: devuelven el hash con
ok=.F. y err poblado si algo falla. Nunca hay que envolverlas en
TRY/CATCH.
HIX_CompileCode( cSource [, hOpts] [, cFilename] )¶
Compila una fuente .prg en memoria. Opciones típicas en hOpts:
{ "virtualName" => "my_module", "runtime" => .F. }. cFilename
etiqueta el error cuando el compile falla.
LOCAL hRes := HIX_CompileCode( "FUNCTION Foo() ; RETURN 42" )
IF ! hRes["ok"]
le( "Compile failed: " + hRes["err"]["description"] )
RETURN NIL
ENDIF
// hRes["hrb"] contiene el HRB listo para ejecutar
HIX_CompileCodeFromFile( cPath )¶
Wrapper compile-only desde disco. Devuelve el mismo hash. Es la vía que
usan el dispatcher y los loaders para compilar .prg persistidos.
LOCAL hRes := HIX_CompileCodeFromFile( "www/controllers/my_action.prg" )
IF ! hRes["ok"]
USendError( 500, "Compile: " + hRes["err"]["description"] )
RETURN NIL
ENDIF
HIX_CompileRunPrg( cPath [, ...args] )¶
Compile + ejecuta en un paso. Captura también el error runtime, no solo
el de compile. Devuelve el mismo contrato hash — phase será "compile"
si cayó compilando y "run" si cayó ejecutando.
LOCAL hRes := HIX_CompileRunPrg( "scripts/report.prg", nUserId, cPeriod )
IF ! hRes["ok"]
// Da igual si fue compile error o runtime error — es el mismo shape
USendError( 500, hRes["err"]["description"] )
RETURN NIL
ENDIF
HIX_CompileRunHrb( cHrbBytes [, cVirtualName [, ...args]] )¶
Ejecuta un HRB ya compilado (bytes). Útil cuando ya tienes el .hrb en
caché o lo generaste con HIX_CompileCode y lo guardaste en disco.
Internamente usa HB_HRB_BIND_FORCELOCAL para evitar colisiones con
otros HRBs cargados.
LOCAL cHrb := hb_MemoRead( "cache/report.hrb" )
LOCAL hRes := HIX_CompileRunHrb( cHrb, "report", nUserId )
HIX_CompileLastError()¶
Devuelve un snapshot del último error runtime capturado por el
subsistema. THREAD STATIC — un hilo solo ve sus propios errores.
Útil cuando has llamado a HIX_CompileRunPrg y necesitas la stack
completa aparte del err que ya trae el hash.
LOCAL hLast := HIX_CompileLastError()
IF hLast != NIL
ld( "aStack: " + hb_ValToExp( hLast["aStack"] ) )
ENDIF
Shape de err normalizado¶
El hash de error dentro de hRes["err"] tiene siempre las mismas claves,
sea de compile o runtime. Compile produce el subset:
| Clave | Significado |
|---|---|
kind |
"compile" o "runtime" |
severity |
"error", "warning" |
code |
Código numérico (preprocesador, parser) |
description |
Mensaje principal — listo para mostrar al usuario |
file |
Fichero fuente donde se detectó el error |
line |
Línea (ya ajustada por preambleLines) |
lineCode |
Snippet exacto de la línea culpable |
Runtime añade todo el contexto Harbour:
| Clave adicional | Significado |
|---|---|
operation |
Función/operación que falló |
args |
Argumentos pasados cuando petó |
subsystem |
oError:subSystem |
genCode |
oError:genCode (código genérico Harbour) |
subCode |
oError:subCode |
osCode |
Código de OS si aplica |
filename |
Fichero del error runtime |
stack |
Stack trace en formato texto |
aStack |
Stack trace como array estructurado |
Ejemplo — controller que ejecuta un script dinámico¶
FUNCTION _RunUserScript()
LOCAL cPath := "www/scripts/" + UParam( "name" ) + ".prg"
LOCAL hRes
IF ! hb_FileExists( cPath )
RETURN USendError( 404, "Script no encontrado" )
ENDIF
hRes := HIX_CompileRunPrg( cPath, USession( "user_id" ) )
IF ! hRes["ok"]
le( "Script failed [" + hRes["phase"] + "]: " + hRes["err"]["description"] )
RETURN USendJson( { ;
"ok" => .F., ;
"phase" => hRes["phase"], ;
"error" => hRes["err"]["description"],;
"line" => hRes["err"]["line"] ;
}, 500 )
ENDIF
USendJson( { "ok" => .T. } )
RETURN NIL
Boot log enriquecido¶
A partir de v2.4.0, cuando un loader o un middleware falla al
compilar durante el arranque, el boot log vuelca línea, código y snippet
en lugar de solo el mensaje. Esto no requiere configuración — es
automático porque el loader usa HIX_CompileCodeFromFile y traduce su
hash directamente al logger.
Formato típico:
[loader] fail: www/loaders/stats.prg
line: 42 (code: 2007)
>> LOCAL x = y + z // = en lugar de :=
description: Error de sintaxis
Dónde no usarlo¶
- No llames a
HIX_CompileRunPrgen tu hot path para scripts que no cambian — compila cada vez. Guarda el HRB conHIX_CompileCode+ un.md5como caché y usaHIX_CompileRunHrbdespués. Es exactamente lo que hace el motor de vistas internamente. - No uses este subsistema para evaluar expresiones simples. Para eso
Harbour ya tiene
&(cExpr)(macro-eval). Compile está pensado para bloques.prgenteros conFUNCTION/PROCEDURE. - No confíes en que
errtraigaaStackcuandokind=="compile". La stack solo tiene sentido para errores runtime.
Cambios respecto a versiones anteriores¶
| Antes de v2.3.12 | A partir de v2.4.0 |
|---|---|
HIX_CompileFile( cPath ) |
Eliminada. Usar HIX_CompileCodeFromFile( cPath ) para compile-only o HIX_CompileRunPrg( cPath ) para compile+run. |
hb_CompileFromBuf directo |
Encapsulado en HIX_CompileFromBuf (low-level, uso interno de HIX_CompileCode) |
oError:operation == "line:N" |
oError:operation == "line N". La fuente oficial es oErr:cargo["line"] |
src/hix_prepro.prg |
Eliminado. Las directivas TRY/CATCH/FINALLY viven ya en src/include/hix_const.ch. |
Ver changes/2.4.0.md para la lista completa de breaking changes y el audit trail de la migración.