runtime: add EL_TRUE/EL_FALSE macros and scoped arena for CLI
Adds EL_TRUE/EL_FALSE convenience macros to el_runtime.h alongside the existing EL_NULL, making boolean-returning builtins readable without raw (el_val_t) casts. Documents all value macros in the header comment. Also lands el_arena_push/el_arena_pop — a scoped string arena for CLI programs that never call el_request_start/end. The compiler can push a mark before a compilation unit and pop it after to free intermediate strings, reducing peak RSS during long compile runs.
This commit is contained in:
@@ -102,6 +102,45 @@ void el_request_end(void) {
|
||||
_tl_arena.count = 0;
|
||||
}
|
||||
|
||||
/* ── Scoped arena for CLI use ─────────────────────────────────────────────── *
|
||||
* CLI programs never call el_request_start/end, so all strdup allocations are
|
||||
* permanent. el_arena_push/pop let the compiler free intermediate strings
|
||||
* after each compilation unit.
|
||||
*
|
||||
* el_arena_push() — activates the arena if not already active, saves the
|
||||
* current arena count as a mark, and returns it as an el_val_t Int.
|
||||
* el_arena_pop(mark) — frees all strings allocated since the push mark and
|
||||
* resets the count. If count reaches 0, deactivates the arena.
|
||||
*/
|
||||
#define EL_ARENA_SCOPE_DEPTH 32
|
||||
static _Thread_local size_t _tl_arena_scope[EL_ARENA_SCOPE_DEPTH];
|
||||
static _Thread_local int _tl_arena_scope_depth = 0;
|
||||
|
||||
el_val_t el_arena_push(void) {
|
||||
if (!_tl_arena_active) {
|
||||
_tl_arena_active = 1;
|
||||
}
|
||||
if (_tl_arena_scope_depth < EL_ARENA_SCOPE_DEPTH) {
|
||||
_tl_arena_scope[_tl_arena_scope_depth++] = _tl_arena.count;
|
||||
}
|
||||
return (el_val_t)(int64_t)_tl_arena.count;
|
||||
}
|
||||
|
||||
el_val_t el_arena_pop(el_val_t mark) {
|
||||
size_t save = (size_t)(int64_t)mark;
|
||||
if (save > _tl_arena.count) save = 0;
|
||||
for (size_t i = save; i < _tl_arena.count; i++) {
|
||||
if (_tl_arena.ptrs[i]) {
|
||||
free(_tl_arena.ptrs[i]);
|
||||
_tl_arena.ptrs[i] = NULL;
|
||||
}
|
||||
}
|
||||
_tl_arena.count = save;
|
||||
if (_tl_arena_scope_depth > 0) _tl_arena_scope_depth--;
|
||||
if (save == 0) _tl_arena_active = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Persistent allocation — bypasses the arena (state_set, engram internals). */
|
||||
static char* el_strdup_persist(const char* s) {
|
||||
if (!s) return strdup("");
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
* EL_STR(s) cast string literal to el_val_t
|
||||
* EL_CSTR(v) cast el_val_t back to const char*
|
||||
* EL_INT(v) identity — el_val_t is already int64_t
|
||||
* EL_NULL null / zero value
|
||||
* EL_FALSE boolean false (0)
|
||||
* EL_TRUE boolean true (1)
|
||||
*
|
||||
* Link requirements:
|
||||
* -lcurl — required for the HTTP client (http_get, http_post, llm_*).
|
||||
@@ -53,6 +56,8 @@ typedef int64_t el_val_t;
|
||||
#define EL_CSTR(v) ((const char*)(uintptr_t)(v))
|
||||
#define EL_INT(v) (v)
|
||||
#define EL_NULL ((el_val_t)0)
|
||||
#define EL_FALSE ((el_val_t)0)
|
||||
#define EL_TRUE ((el_val_t)1)
|
||||
|
||||
/* Float values share the el_val_t (int64) slot via a bit-cast.
|
||||
* The codegen emits Float literals as `el_from_float(<dbl>)` so the
|
||||
@@ -117,6 +122,10 @@ el_val_t el_min(el_val_t a, el_val_t b);
|
||||
void el_retain(el_val_t v);
|
||||
void el_release(el_val_t v);
|
||||
|
||||
/* ── Scoped arena (CLI use) ───────────────────────────────────────────────── */
|
||||
el_val_t el_arena_push(void);
|
||||
el_val_t el_arena_pop(el_val_t mark);
|
||||
|
||||
/* ── List ────────────────────────────────────────────────────────────────── */
|
||||
|
||||
el_val_t el_list_new(el_val_t count, ...);
|
||||
|
||||
Reference in New Issue
Block a user