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:
Will Anderson
2026-05-05 19:15:49 -05:00
parent 7f295bffe9
commit eb52be4ade
2 changed files with 48 additions and 0 deletions
+39
View File
@@ -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("");