From 28ef43264ae1756fde0e9b6738915553e0cab74a Mon Sep 17 00:00:00 2001 From: Tim Lingo <1timlingo@gmail.com> Date: Mon, 15 Jun 2026 16:58:11 -0500 Subject: [PATCH 01/13] feat(el-runtime): native Windows port of el_runtime.c (winsock/dlsym/CreateProcess) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compiles for Windows x64 via mingw-w64 and still compiles clean on POSIX (darwin/linux) — all Windows code is behind #ifdef _WIN32, POSIX path unchanged. - el_platform_win.h (new): winsock2 + auto WSAStartup, el_closesocket(), dlsym->GetProcAddress, popen/_popen, mkdir/_mkdir, setenv/_putenv_s, timegm/_mkgmtime, localtime_r/gmtime_r. Threading unchanged — mingw winpthreads supplies + -lpthread. - el_runtime.c: include block guarded; 10 socket-close sites -> el_closesocket(); setsockopt arg4 cast; tm_zone guarded; exec_bg fork/exec -> CreateProcess. Part of feat/windows-port. Core-el change, for Will's review. Co-Authored-By: Claude Opus 4.8 (1M context) --- lang/el-compiler/runtime/el_platform_win.h | 94 ++++++++++++++++++++++ lang/el-compiler/runtime/el_runtime.c | 59 ++++++++++---- 2 files changed, 139 insertions(+), 14 deletions(-) create mode 100644 lang/el-compiler/runtime/el_platform_win.h diff --git a/lang/el-compiler/runtime/el_platform_win.h b/lang/el-compiler/runtime/el_platform_win.h new file mode 100644 index 0000000..12d417b --- /dev/null +++ b/lang/el-compiler/runtime/el_platform_win.h @@ -0,0 +1,94 @@ +#ifndef EL_PLATFORM_WIN_H +#define EL_PLATFORM_WIN_H +/* + * el_platform_win.h — Windows OS-boundary shim for el_runtime.c. + * + * Branch: feat/windows-el-runtime. Included ONLY when _WIN32 is defined; the POSIX build is + * untouched. Goal: let el_runtime.c (a BSD-sockets / dlfcn / fork host) compile and link with + * mingw-w64 into a native neuron.exe, with no behavioural change to the Linux/macOS build. + * + * What it maps: + * - sockets : winsock2 (same call names: socket/bind/listen/accept/recv/send/setsockopt). + * Sockets close with closesocket() (see el_closesocket), and the stack must be + * started once with WSAStartup — done automatically via a load-time constructor. + * - dlsym : el_runtime.c uses dlsym(RTLD_DEFAULT, name) to resolve callback/tool symbols + * exported by the main module. Windows equivalent: GetProcAddress on the process + * module. Link the soul with -Wl,--export-all-symbols so the symbols are findable. + * - popen : mapped to _popen/_pclose. + * - threads : UNCHANGED. mingw-w64 ships winpthreads, so + -lpthread just work. + */ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +#include +#include + +/* Portable headers mingw-w64 provides (verified present). */ +#include +#include +#include +#include +#include +#include /* strcasecmp */ +#include +#include +#include +#include /* mingw-w64 provides gettimeofday here */ +#include +#include +#include +#include +#include +#include + +/* ── socket close ─────────────────────────────────────────────────────────── */ +/* Winsock closes sockets with closesocket(), not close() (close() is for file fds). The POSIX + build defines the same helper as close() so the call sites are identical across platforms. */ +static inline int el_closesocket(int s) { return closesocket((SOCKET)s); } + +/* ── winsock init (once, at load) ─────────────────────────────────────────── */ +static void el__win_net_init(void) { + static int inited = 0; + if (!inited) { WSADATA w; WSAStartup(MAKEWORD(2, 2), &w); inited = 1; } +} +__attribute__((constructor)) static void el__win_ctor(void) { el__win_net_init(); } + +/* ── dlsym → GetProcAddress ───────────────────────────────────────────────── */ +#ifndef RTLD_DEFAULT +#define RTLD_DEFAULT ((void*)0) +#endif +static inline void* el_win_dlsym(void* handle, const char* name) { + (void)handle; + return (void*)(uintptr_t)GetProcAddress(GetModuleHandleA(NULL), name); +} +#define dlsym(h, n) el_win_dlsym((h), (n)) + +/* ── popen / pclose ───────────────────────────────────────────────────────── */ +#define popen _popen +#define pclose _pclose + +/* ── misc POSIX → Win32 shims ─────────────────────────────────────────────── */ +#include /* _mkdir */ +#define mkdir(path, mode) _mkdir(path) /* POSIX mkdir(path,mode) → _mkdir(path) */ +#define timegm _mkgmtime /* UTC tm → time_t */ + +/* setenv/unsetenv: not in the Windows CRT; map to _putenv_s. */ +static inline int setenv(const char* name, const char* value, int overwrite) { + (void)overwrite; + return _putenv_s(name, value ? value : ""); +} +static inline int unsetenv(const char* name) { return _putenv_s(name, ""); } + +/* localtime_r/gmtime_r: Windows offers localtime_s/gmtime_s with reversed arg order. */ +static inline struct tm* localtime_r(const time_t* t, struct tm* out) { + return localtime_s(out, t) == 0 ? out : (struct tm*)0; +} +static inline struct tm* gmtime_r(const time_t* t, struct tm* out) { + return gmtime_s(out, t) == 0 ? out : (struct tm*)0; +} + +#endif /* EL_PLATFORM_WIN_H */ diff --git a/lang/el-compiler/runtime/el_runtime.c b/lang/el-compiler/runtime/el_runtime.c index df83e95..4faf72a 100644 --- a/lang/el-compiler/runtime/el_runtime.c +++ b/lang/el-compiler/runtime/el_runtime.c @@ -21,6 +21,10 @@ #include "el_runtime.h" +#ifdef _WIN32 +/* Windows OS-boundary shim (winsock/dlsym/popen). Threading stays on (winpthreads). */ +#include "el_platform_win.h" +#else #include #include /* strcasecmp */ #include @@ -42,6 +46,10 @@ #include #include #include +/* On POSIX, sockets close with the same close() as files; el_platform_win.h supplies the Windows + variant. Defined here so the socket call sites are identical across platforms. */ +static inline int el_closesocket(int s) { return close(s); } +#endif #ifdef HAVE_CURL #include #endif @@ -1587,17 +1595,17 @@ el_val_t http_serve(el_val_t port, el_val_t handler) { int sock = socket(AF_INET6, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); return 0; } int yes = 1; int no = 0; - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); - setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no)); + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&yes, sizeof(yes)); + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&no, sizeof(no)); struct sockaddr_in6 addr; memset(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; addr.sin6_addr = in6addr_any; addr.sin6_port = htons((uint16_t)p); if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { - perror("bind"); close(sock); return 0; + perror("bind"); el_closesocket(sock); return 0; } - if (listen(sock, 64) < 0) { perror("listen"); close(sock); return 0; } + if (listen(sock, 64) < 0) { perror("listen"); el_closesocket(sock); return 0; } fprintf(stderr, "[http] listening on [::]:%d (dual-stack)\n", p); while (1) { struct sockaddr_in6 cli; @@ -1614,11 +1622,11 @@ el_val_t http_serve(el_val_t port, el_val_t handler) { _http_conn_active++; pthread_mutex_unlock(&_http_conn_mu); HttpWorkerArg* arg = malloc(sizeof(HttpWorkerArg)); - if (!arg) { close(cfd); continue; } + if (!arg) { el_closesocket(cfd); continue; } arg->fd = cfd; pthread_t tid; if (pthread_create(&tid, NULL, http_worker, arg) != 0) { - close(cfd); free(arg); + el_closesocket(cfd); free(arg); pthread_mutex_lock(&_http_conn_mu); _http_conn_active--; pthread_cond_signal(&_http_conn_cv); @@ -1627,7 +1635,7 @@ el_val_t http_serve(el_val_t port, el_val_t handler) { } pthread_detach(tid); } - close(sock); + el_closesocket(sock); return 0; } @@ -1837,17 +1845,17 @@ el_val_t http_serve_v2(el_val_t port, el_val_t handler) { int sock = socket(AF_INET6, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); return 0; } int yes = 1; int no = 0; - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); - setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no)); + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&yes, sizeof(yes)); + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&no, sizeof(no)); struct sockaddr_in6 addr; memset(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; addr.sin6_addr = in6addr_any; addr.sin6_port = htons((uint16_t)p); if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { - perror("bind"); close(sock); return 0; + perror("bind"); el_closesocket(sock); return 0; } - if (listen(sock, 64) < 0) { perror("listen"); close(sock); return 0; } + if (listen(sock, 64) < 0) { perror("listen"); el_closesocket(sock); return 0; } fprintf(stderr, "[http v2] listening on [::]:%d (dual-stack)\n", p); while (1) { struct sockaddr_in6 cli; @@ -1864,11 +1872,11 @@ el_val_t http_serve_v2(el_val_t port, el_val_t handler) { _http_conn_active++; pthread_mutex_unlock(&_http_conn_mu); HttpWorkerArg* arg = malloc(sizeof(HttpWorkerArg)); - if (!arg) { close(cfd); continue; } + if (!arg) { el_closesocket(cfd); continue; } arg->fd = cfd; pthread_t tid; if (pthread_create(&tid, NULL, http_worker_v2, arg) != 0) { - close(cfd); free(arg); + el_closesocket(cfd); free(arg); pthread_mutex_lock(&_http_conn_mu); _http_conn_active--; pthread_cond_signal(&_http_conn_cv); @@ -1877,7 +1885,7 @@ el_val_t http_serve_v2(el_val_t port, el_val_t handler) { } pthread_detach(tid); } - close(sock); + el_closesocket(sock); return 0; } @@ -2051,6 +2059,23 @@ el_val_t exec(el_val_t cmdv) { el_val_t exec_bg(el_val_t cmdv) { const char* cmd = EL_CSTR(cmdv); if (!cmd || !*cmd) return el_wrap_str(el_strdup("")); +#ifdef _WIN32 + /* Windows: no fork/exec. Launch a detached `cmd /c ` with no console window via + CreateProcess (DETACHED_PROCESS | CREATE_NO_WINDOW). Returns the PID as a string, "" on fail. + Mirrors the POSIX branch: child runs independently, caller is not blocked. */ + char cmdline[8192]; + snprintf(cmdline, sizeof(cmdline), "cmd.exe /c %s", cmd); + STARTUPINFOA si; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); + PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(pi)); + BOOL ok = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, + DETACHED_PROCESS | CREATE_NO_WINDOW, NULL, NULL, &si, &pi); + if (!ok) return el_wrap_str(el_strdup("")); + char pidbuf[32]; + snprintf(pidbuf, sizeof(pidbuf), "%lu", (unsigned long)pi.dwProcessId); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return el_wrap_str(el_strdup(pidbuf)); +#else pid_t pid = fork(); if (pid < 0) { /* fork failed */ @@ -2073,6 +2098,7 @@ el_val_t exec_bg(el_val_t cmdv) { char pidbuf[32]; snprintf(pidbuf, sizeof(pidbuf), "%d", (int)pid); return el_wrap_str(el_strdup(pidbuf)); +#endif } el_val_t fs_list(el_val_t pathv) { @@ -4337,7 +4363,12 @@ static int _el_decompose_earth(el_caltime_t* ct, struct tm* tm_out, int* abbr_le localtime_r(&s, &tm); *tm_out = tm; if (abbr_buf && abbr_cap > 0) { + /* mingw's struct tm has no tm_zone (BSD/glibc extension); no abbrev available there. */ +#ifdef _WIN32 + const char* z_str = ""; +#else const char* z_str = tm.tm_zone ? tm.tm_zone : ""; +#endif size_t n = strlen(z_str); if (n >= abbr_cap) n = abbr_cap - 1; memcpy(abbr_buf, z_str, n); From a36a62ca141a531e498b0215fef8cb48771af48e Mon Sep 17 00:00:00 2001 From: Tim Lingo <1timlingo@gmail.com> Date: Mon, 15 Jun 2026 17:14:17 -0500 Subject: [PATCH 02/13] fix(el-runtime): promote http_handler typedefs to el_runtime.h (cross-module + Windows) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit http_handler_fn / http_handler4_fn were defined only inside el_runtime.c, so soul modules (routes/chat/...) that reference them via cross-module forward declarations couldn't see the types — which broke the Windows link of every module. Moving the public function-pointer types to the shared header is the correct home and unblocks the build on all platforms (identical typedef, C11-safe redefinition in el_runtime.c). With this, the soul links into a native Windows neuron.exe (mingw, static) that boots and serves HTTP on :7770 — verified /health → 200 {"status":"alive",...} in a Win11 VM. Co-Authored-By: Claude Opus 4.8 (1M context) --- lang/el-compiler/runtime/el_runtime.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lang/el-compiler/runtime/el_runtime.h b/lang/el-compiler/runtime/el_runtime.h index c0529ef..88c2a36 100644 --- a/lang/el-compiler/runtime/el_runtime.h +++ b/lang/el-compiler/runtime/el_runtime.h @@ -52,6 +52,12 @@ typedef int64_t el_val_t; +/* HTTP request-handler function-pointer types. Public because soul modules (routes/chat/etc.) + * register handlers across translation units; previously defined only inside el_runtime.c, which + * made cross-module references (and the Windows build) fail. Home in the shared header. */ +typedef el_val_t (*http_handler_fn)(el_val_t method, el_val_t path, el_val_t body); +typedef el_val_t (*http_handler4_fn)(el_val_t method, el_val_t path, el_val_t body, el_val_t headers); + #define EL_STR(s) ((el_val_t)(uintptr_t)(s)) #define EL_CSTR(v) ((const char*)(uintptr_t)(v)) #define EL_INT(v) (v) From 2dec76c87ac804f4c0ab910833310a1b3f4eb6e8 Mon Sep 17 00:00:00 2001 From: Tim Lingo <1timlingo@gmail.com> Date: Tue, 16 Jun 2026 19:46:56 -0500 Subject: [PATCH 03/13] fix(runtime): reconcile live data-integrity fixes onto main (UAF + atomic engram_save) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ports the fixes that until now lived only in the un-versioned el-sdk source the live macOS soul was hand-built from (captured in the [DO NOT MERGE] live-darwin-runtime snapshot) FORWARD onto main, faithfully and minimally — without dragging in the snapshot's deletions of main's newer engram_wm_/engram_load_merge/http_serve_async. 1. UAF (hallucinated/lost-saves root cause): engram_new_id + engram_node_full now use el_strdup_persist, NOT el_strdup. el_strdup tracks into the per-request arena that el_request_end() frees when the creating HTTP request completes — leaving stored nodes with dangling pointers (corrupted ids, 'saved but never listed'). Transplanted verbatim from the live runtime; el_strdup_persist sites 19->27, matching live. 2. Atomic engram_save: write .tmp, fflush+fsync, rename() over target (atomic on POSIX) so a booting soul's engram_load never reads a truncated/0-byte snapshot — the genesis -> nodes=1 -> 63-node-clobber loop. Plus a sparse-write floor: refuse to overwrite a >200KB snapshot with one < 1/16 its size. (Validated in isolation: harness 11/11; rebuilt+booted the darwin soul, round-tripped 5113 nodes, no clobber.) The response-truncation fix is already on main (_tl_fs_read_len binary-safe length). Compiles clean. For Will to build through CI/elb and deploy. Co-Authored-By: Claude Opus 4.8 (1M context) --- lang/el-compiler/runtime/el_runtime.c | 48 +++++++++++++++++++-------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/lang/el-compiler/runtime/el_runtime.c b/lang/el-compiler/runtime/el_runtime.c index 2f4c839..1036d16 100644 --- a/lang/el-compiler/runtime/el_runtime.c +++ b/lang/el-compiler/runtime/el_runtime.c @@ -6322,7 +6322,9 @@ static void engram_grow_edges(void) { static char* engram_new_id(void) { el_val_t v = uuid_new(); const char* s = EL_CSTR(v); - return el_strdup(s ? s : ""); + /* Persistent: node ids live in the global store; an arena (el_strdup) id is + * freed at el_request_end(), corrupting the node after the creating request. */ + return el_strdup_persist(s ? s : ""); } /* Convert a node into an ElMap of its fields. */ @@ -6417,12 +6419,17 @@ el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, const char* lb = EL_CSTR(label); const char* ti = EL_CSTR(tier); const char* tg = EL_CSTR(tags); - n->content = el_strdup(c ? c : ""); - n->node_type = el_strdup(nt && *nt ? nt : "Memory"); - n->label = el_strdup(lb && *lb ? lb : (c ? engram_first_n_chars(c, 60) : "")); - n->tier = el_strdup(ti && *ti ? ti : "Working"); - n->tags = el_strdup(tg ? tg : ""); - n->metadata = el_strdup("{}"); + /* Persistent (el_strdup_persist, NOT el_strdup): these strings are owned by the + * persistent global node store. el_strdup tracks into the per-request arena, which + * el_request_end() frees when the creating HTTP request completes — leaving the + * stored node with dangling pointers (corrupted ids, "saved but never listed"). + * This is the root cause of the hallucinated/lost-saves class of bugs. */ + n->content = el_strdup_persist(c ? c : ""); + n->node_type = el_strdup_persist(nt && *nt ? nt : "Memory"); + n->label = el_strdup_persist(lb && *lb ? lb : (c ? engram_first_n_chars(c, 60) : "")); + n->tier = el_strdup_persist(ti && *ti ? ti : "Working"); + n->tags = el_strdup_persist(tg ? tg : ""); + n->metadata = el_strdup_persist("{}"); n->salience = engram_decode_score(salience); n->importance = engram_decode_score(importance); n->confidence = engram_decode_score(confidence); @@ -7365,13 +7372,28 @@ el_val_t engram_save(el_val_t path) { jb_putc(&b, '}'); } jb_puts(&b, "]}"); - FILE* f = fopen(p, "wb"); - if (!f) { free(b.buf); return 0; } + { + struct stat _st; + if (stat(p, &_st) == 0 && _st.st_size > 200000 && + (uint64_t)b.len < (uint64_t)_st.st_size / 16) { + fprintf(stderr, "[engram_save] REFUSED sparse write: new %zu vs existing %lld (<1/16) protecting %s\n", + b.len, (long long)_st.st_size, p); + free(b.buf); return 0; + } + } + size_t _plen = strlen(p); + char* _tmp = (char*)malloc(_plen + 5); + if (!_tmp) { free(b.buf); return 0; } + memcpy(_tmp, p, _plen); memcpy(_tmp + _plen, ".tmp", 5); + FILE* f = fopen(_tmp, "wb"); + if (!f) { free(_tmp); free(b.buf); return 0; } size_t w = fwrite(b.buf, 1, b.len, f); - fclose(f); - int ok = (w == b.len); - free(b.buf); - return ok ? 1 : 0; + int wok = (w == b.len); + if (wok) { fflush(f); fsync(fileno(f)); } + fclose(f); free(b.buf); + if (!wok) { unlink(_tmp); free(_tmp); return 0; } + if (rename(_tmp, p) != 0) { unlink(_tmp); free(_tmp); return 0; } + free(_tmp); return 1; } /* Helper: extract a string field from a JSON object substring. */ From 18e1ab6db12a4209ff148fbd60dd172e59ee35a0 Mon Sep 17 00:00:00 2001 From: Tim Lingo <1timlingo@gmail.com> Date: Wed, 17 Jun 2026 13:14:57 -0500 Subject: [PATCH 04/13] =?UTF-8?q?feat(engram):=20add=20accumulation=20laye?= =?UTF-8?q?r=20(layer=205)=20=E2=80=94=20new=20nodes=20default=20to=20it,?= =?UTF-8?q?=20not=20core-identity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements the accumulation layer from the Layered Consciousness architecture (provisional 64/064,262) and answers the deferred design question. Per the spec and Will's design: new user-facing nodes (memories, knowledge, conversations) are created in an accumulation layer at the TOP of the consciousness stack — the engram the user sees — while the layers below (safety, core-identity, domain, imprint, suit) shape behavior but are hidden from the user. - Adds ENGRAM_LAYER_ACCUMULATION (5) + the layer record in engram_init_layers (activation_priority 50, suppressible, not injectable, transparent=0). - engram_node and engram_node_full now assign new nodes to ENGRAM_LAYER_ACCUMULATION. - ENGRAM_LAYER_DEFAULT stays CORE_IDENTITY ON PURPOSE: it is the fallback for LEGACY nodes loaded from snapshots without a layer_id, so existing data (the originator corpus) is NEVER migrated. New-nodes-only — the immutable-originator rule. This is the foundation for fixing the identity-bleed / customer-isolation issue (user data was landing in Neuron's core-identity layer). The retrieval-side provenance filter (introspection should compile from accumulation, not the originator corpus — Persona 64/036,574) is a follow-on, pending the batch-2 Layered Consciousness + Engram spec docs for exact semantics. Compiles clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- lang/el-compiler/runtime/el_runtime.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/lang/el-compiler/runtime/el_runtime.c b/lang/el-compiler/runtime/el_runtime.c index 2f4c839..fd9949a 100644 --- a/lang/el-compiler/runtime/el_runtime.c +++ b/lang/el-compiler/runtime/el_runtime.c @@ -6031,6 +6031,14 @@ void el_cgi_init(el_val_t name, el_val_t dharma_id, el_val_t principal, #define ENGRAM_LAYER_DOMAIN 2u #define ENGRAM_LAYER_IMPRINT 3u #define ENGRAM_LAYER_SUIT 4u +#define ENGRAM_LAYER_ACCUMULATION 5u +/* New user-facing nodes (memories, knowledge, conversations) are created in the + * accumulation layer — the top of the consciousness stack, the engram the user + * sees; every layer below shapes behavior but is hidden from the user (Layered + * Consciousness architecture, app 64/064,262). ENGRAM_LAYER_DEFAULT stays + * core-identity ON PURPOSE: it is the fallback home for LEGACY nodes loaded from + * snapshots without a layer_id, so existing data (the originator corpus) is + * never migrated out of its established layer. New != legacy. */ #define ENGRAM_LAYER_DEFAULT ENGRAM_LAYER_CORE_IDENTITY /* Pass 3 override floor. Layer 0 nodes that received any background @@ -6208,6 +6216,20 @@ static void engram_init_layers(EngramStore* g) { .transparent = 0, .injectable = 1 }; + /* Layer 5 — accumulation. The TOP of the consciousness stack: the default + * home for all new user-facing nodes. This is the engram the user sees; + * every layer below shapes behavior but is hidden from the user. Not + * injectable — it is the persistent user accumulation, not a swappable + * overlay. transparent=0: its content is surfaced to introspection (it is + * the user's own knowledge/memory), unlike the lower behavioral layers. */ + g->layers[g->layer_count++] = (EngramLayer){ + .layer_id = ENGRAM_LAYER_ACCUMULATION, + .name = el_strdup_persist("accumulation"), + .activation_priority = 50, + .suppressible = 1, + .transparent = 0, + .injectable = 0 + }; } static EngramStore* engram_get(void) { @@ -6399,7 +6421,7 @@ el_val_t engram_node(el_val_t content, el_val_t node_type, el_val_t salience) { n->last_activated = now; n->created_at = now; n->updated_at = now; - n->layer_id = ENGRAM_LAYER_DEFAULT; + n->layer_id = ENGRAM_LAYER_ACCUMULATION; /* new user-facing node → top layer */ g->node_count++; return el_wrap_str(el_strdup(n->id)); } @@ -6435,7 +6457,7 @@ el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, n->last_activated = now; n->created_at = now; n->updated_at = now; - n->layer_id = ENGRAM_LAYER_DEFAULT; + n->layer_id = ENGRAM_LAYER_ACCUMULATION; /* new user-facing node → top layer */ g->node_count++; return el_wrap_str(el_strdup(n->id)); } From c087b97093a300f24f599384f3235f7de992d401 Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Fri, 19 Jun 2026 18:59:10 -0500 Subject: [PATCH 05/13] =?UTF-8?q?fix(windows):=20resolve=20PR=20blockers?= =?UTF-8?q?=20=E2=80=94=20nanosleep=20shim,=20unsetenv,=20duplicate=20type?= =?UTF-8?q?defs,=20SOCKET=20type,=20el=5Fclosesocket?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lang/el-compiler/runtime/el_platform_win.h | 29 +++++++++++++++++++--- lang/el-compiler/runtime/el_runtime.c | 27 ++++++++++++++++---- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/lang/el-compiler/runtime/el_platform_win.h b/lang/el-compiler/runtime/el_platform_win.h index 12d417b..88204a0 100644 --- a/lang/el-compiler/runtime/el_platform_win.h +++ b/lang/el-compiler/runtime/el_platform_win.h @@ -48,7 +48,7 @@ /* ── socket close ─────────────────────────────────────────────────────────── */ /* Winsock closes sockets with closesocket(), not close() (close() is for file fds). The POSIX build defines the same helper as close() so the call sites are identical across platforms. */ -static inline int el_closesocket(int s) { return closesocket((SOCKET)s); } +static inline int el_closesocket(SOCKET s) { return closesocket(s); } /* ── winsock init (once, at load) ─────────────────────────────────────────── */ static void el__win_net_init(void) { @@ -76,12 +76,35 @@ static inline void* el_win_dlsym(void* handle, const char* name) { #define mkdir(path, mode) _mkdir(path) /* POSIX mkdir(path,mode) → _mkdir(path) */ #define timegm _mkgmtime /* UTC tm → time_t */ -/* setenv/unsetenv: not in the Windows CRT; map to _putenv_s. */ +/* setenv/unsetenv: not in the Windows CRT; map to _putenv_s / SetEnvironmentVariable. */ static inline int setenv(const char* name, const char* value, int overwrite) { (void)overwrite; return _putenv_s(name, value ? value : ""); } -static inline int unsetenv(const char* name) { return _putenv_s(name, ""); } +static inline int unsetenv(const char* name) { + /* _putenv_s(name, "") sets VAR="" rather than removing it. + * SetEnvironmentVariableA(name, NULL) truly deletes it from the Win32 + * env block; then we sync the CRT cache with _putenv("NAME="). */ + SetEnvironmentVariableA(name, NULL); + size_t len = strlen(name); + char *buf = (char*)malloc(len + 2); + if (!buf) return -1; + memcpy(buf, name, len); + buf[len] = '='; + buf[len + 1] = '\0'; + _putenv(buf); + free(buf); + return 0; +} + +/* nanosleep — not available in MSVC/UCRT; approximate with Sleep(). */ +static inline int el_nanosleep(const struct timespec *req, struct timespec *rem) { + (void)rem; + DWORD ms = (DWORD)((req->tv_sec * 1000ULL) + (req->tv_nsec / 1000000ULL)); + Sleep(ms ? ms : 1); + return 0; +} +#define nanosleep(req, rem) el_nanosleep((req), (rem)) /* localtime_r/gmtime_r: Windows offers localtime_s/gmtime_s with reversed arg order. */ static inline struct tm* localtime_r(const time_t* t, struct tm* out) { diff --git a/lang/el-compiler/runtime/el_runtime.c b/lang/el-compiler/runtime/el_runtime.c index 4faf72a..f19b266 100644 --- a/lang/el-compiler/runtime/el_runtime.c +++ b/lang/el-compiler/runtime/el_runtime.c @@ -1061,7 +1061,6 @@ el_val_t http_post_to_file(el_val_t url, el_val_t body, el_val_t headers_map, el #define HTTP_MAX_CONNS 64 -typedef el_val_t (*http_handler_fn)(el_val_t method, el_val_t path, el_val_t body); typedef struct { char* name; @@ -1536,12 +1535,20 @@ static void http_send_response(int fd, const char* body) { } typedef struct { +#ifdef _WIN32 + SOCKET fd; +#else int fd; +#endif } HttpWorkerArg; static void* http_worker(void* arg) { HttpWorkerArg* a = (HttpWorkerArg*)arg; +#ifdef _WIN32 + SOCKET fd = a->fd; +#else int fd = a->fd; +#endif free(a); char *method = NULL, *path = NULL, *body = NULL; if (http_read_request(fd, &method, &path, &body, NULL) == 0) { @@ -1573,7 +1580,7 @@ static void* http_worker(void* arg) { free(response); } free(method); free(path); free(body); - close(fd); + el_closesocket(fd); /* release a slot */ pthread_mutex_lock(&_http_conn_mu); _http_conn_active--; @@ -1610,7 +1617,11 @@ el_val_t http_serve(el_val_t port, el_val_t handler) { while (1) { struct sockaddr_in6 cli; socklen_t clen = sizeof(cli); +#ifdef _WIN32 + SOCKET cfd = accept(sock, (struct sockaddr*)&cli, &clen); +#else int cfd = accept(sock, (struct sockaddr*)&cli, &clen); +#endif if (cfd < 0) { if (errno == EINTR) continue; perror("accept"); break; @@ -1656,8 +1667,6 @@ el_val_t http_serve(el_val_t port, el_val_t handler) { * separate active-handler slot, separate dlsym fallback. Mixing v1 and v2 * handlers in the same process is fine — they don't share the active slot. */ -typedef el_val_t (*http_handler4_fn)(el_val_t method, el_val_t path, - el_val_t headers_map, el_val_t body); typedef struct { char* name; @@ -1793,7 +1802,11 @@ static el_val_t http_build_headers_map(const char* hdr_block) { static void* http_worker_v2(void* arg) { HttpWorkerArg* a = (HttpWorkerArg*)arg; +#ifdef _WIN32 + SOCKET fd = a->fd; +#else int fd = a->fd; +#endif free(a); char *method = NULL, *path = NULL, *body = NULL, *hdr_block = NULL; if (http_read_request(fd, &method, &path, &body, &hdr_block) == 0) { @@ -1823,7 +1836,7 @@ static void* http_worker_v2(void* arg) { free(response); } free(method); free(path); free(body); free(hdr_block); - close(fd); + el_closesocket(fd); pthread_mutex_lock(&_http_conn_mu); _http_conn_active--; pthread_cond_signal(&_http_conn_cv); @@ -1860,7 +1873,11 @@ el_val_t http_serve_v2(el_val_t port, el_val_t handler) { while (1) { struct sockaddr_in6 cli; socklen_t clen = sizeof(cli); +#ifdef _WIN32 + SOCKET cfd = accept(sock, (struct sockaddr*)&cli, &clen); +#else int cfd = accept(sock, (struct sockaddr*)&cli, &clen); +#endif if (cfd < 0) { if (errno == EINTR) continue; perror("accept"); break; From 93d36fddb1a85dbd74c03e632ca09082fde0571c Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Thu, 25 Jun 2026 11:45:36 -0500 Subject: [PATCH 06/13] =?UTF-8?q?fix(windows):=20guard=20el=5Fmem=5Fcheck?= =?UTF-8?q?=20with=20=5FWIN32=20=E2=80=94=20rusage=20is=20POSIX-only?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lang/el-compiler/runtime/el_runtime.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lang/el-compiler/runtime/el_runtime.c b/lang/el-compiler/runtime/el_runtime.c index d00b7d7..12a2075 100644 --- a/lang/el-compiler/runtime/el_runtime.c +++ b/lang/el-compiler/runtime/el_runtime.c @@ -5880,6 +5880,10 @@ el_val_t getpid_now(void) { * Returns 0 always (the only non-return path is the exit() branch). */ el_val_t el_mem_check(void) { +#ifdef _WIN32 + /* getrusage is POSIX-only — memory guard disabled on Windows. */ + return 0; +#else /* Read limit from env; default 512 MB. */ long limit_mb = 512; const char *env_val = getenv("ELC_MAX_MEM_MB"); @@ -5905,6 +5909,7 @@ el_val_t el_mem_check(void) { exit(1); } return 0; +#endif } /* ── args() — command-line argument access ────────────────────────────────── From f7bd99ae45201be0d0aecccf120efd0585c2ed6e Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Fri, 26 Jun 2026 08:47:08 -0500 Subject: [PATCH 07/13] =?UTF-8?q?self-review=202026-06-26:=20WM=20cap,=20b?= =?UTF-8?q?reakthrough=20floor=200.25=E2=86=920.10,=20ISE=20WM=20exclusion?= =?UTF-8?q?,=20/api/neuron/state-events=20route?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three improvements from today's self-review: 1. ENGRAM_BREAKTHROUGH_WEIGHT 0.25→0.10 Live data showed 524/525 WM nodes at breakthrough floor (0.25). Knowledge nodes promoted at 0.21 decayed to 0.147 in one call, fell below the old 0.25 floor, and were immediately evicted for fresh breakthrough candidates. Natural promotion was invisible. Invariant maintained: 0.10 < all per-type thresholds (min=0.15 Canonical). 2. ENGRAM_WM_CAP=24 with Pass 4 (per-call) + Pass 5 (global) enforcement Without a cap, broad queries like 'knowledge' promote 525+ nodes simultaneously. WM is now bounded to 24 nodes. Algorithm: qsort on promoted weights, keep top-24 by cutoff, evict the rest. Global pass enforces cap across nodes that were promoted in prior calls and persist via working_memory_weight. Validated: WM promoted goes 525→24. Cognitive basis: Cowan (2001) WM ~4 chunks; 24 gives richer multi-topic context while preventing flooding. 3. ISE exclusion from WM + /api/neuron/state-events route InternalStateEvent nodes were reaching WM via breakthrough (5 suppression cycles) because their content (curiosity seed JSON with 'knowledge', 'memory', etc.) triggered lexical seeding. ISEs are observability-only and must never surface in context. Fix: guard in Pass 2 clears suppression_count and skips to wm_weights[i]=0.0. Also added POST /api/neuron/state-events route to server.el (auth-exempt, internal endpoint). The main soul daemon posts ISEs here but the route was missing — all ise_post() calls were silently returning 'not found'. Research: SYNAPSE (arXiv 2601.02744) validates spreading factor 0.8 (our 0.7), top-M WM cap design, and cosine similarity seeding. Next priority: implement cosine similarity initial seeding from the other branch. --- engram/dist/engram | Bin 0 -> 3528536 bytes engram/dist/engram.c | 21 +++- engram/src/server.el | 36 ++++++ lang/releases/v1.0.0-20260501/el_runtime.c | 133 ++++++++++++++++++++- 4 files changed, 186 insertions(+), 4 deletions(-) create mode 100755 engram/dist/engram diff --git a/engram/dist/engram b/engram/dist/engram new file mode 100755 index 0000000000000000000000000000000000000000..95430e24eec4b6097df819082ce4d19a04a83406 GIT binary patch literal 3528536 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 z zR2y%%I~e#Qew5wSfgf%cWe;@lkFvWCrG$k}M7I7HWToi(-q!pB)-Z~8;2CTGoDyCx zbAa7bQH9$|XXYAT(oo@-EvxNHDXS6tvHbS>w9{=%FuyqEB@UY0qn@j#!U1?-u*kKr z-0!K7xiMG-W-rTd&m1edrtE;b+#8g>b(eXAX|@Hk-L_R_^_xb=q>b!sr3aNZG-eG` zLjGnLDVy|dAW-Iw5Az0P?Ef6J%(+JY((WbnSsH!TL0`+cR6E~pzVo2_3Ag_~z zzmR|LlNNU(XnQ@()BJak?w3ec=EdVFuCUNc*U_uP^Jd$IHa>7+1@=rUILGX{i8C;CgF5-BJQ;l16%w6UgQbQ(?a6$ZECY%{2axT;eqv)FYN!_MVx9d35 ze4KWW^ZC#I9@&Dk_%G0goz%Yz`p!q5s9;ZuaS}PlE4)Uh&Hm3R_t($vb$7(BVX(2# zJ10}=V1<6IYoyMU(LJ5?M-ZCI=Ny;Jx#hT*+g&<;GwLL=%*L(^?i98?-J6mb?oDw$ z-J9WJOtY@ZJzvRKqlGuA@3C6FBU3wv@At;%B9kHW^50LmgS<;~$7(YoVfDCID0x@X z(&Lu#z1@+W5Kq=l);w>Di&v%MotF@AL|nYP;^K+Cz1{H-3GvvYkI8RWT)drp`-<0v zwmW={@pb$_c#)-jUWtqQ0^jExkhte0#1-4n*0@LF;&$;pX7PIBj!B67ro^Sc+G+P> zCo(>F{+t}=($w8Qxh`!7?b=KH_xV4PaQc7N*pBnG9{%@G=ECs>nx20F|NlYz3;#dh z|8?W18ULs8-`9AU|8syLA7g%$^cEgmV4ZCX^8Xl=RpRn%|?oWhUfcyIoWleqfp{$j!KQv33;ev_ZMQKzm&UJ;=ZF zxR3i1o*Q`{$-S}W;oKXiJlrrgbVvUsX4%+B0#@!=wUb5j!HILNqE!u5w zDSC?bnfCQ1oPS(W`OdcME1xIq&vL(5^L*|Xr##!xs3v+M4O)Pb_<nvB}cJjW0_l}mmMRE_p z_LjP$8ou}Pe+PO@^{=G9=x+00i}A0eUd~QF)eaw3yafLWus!APT^5$L!t&)&8N|=r z(2;VTtoaXE_r^sB+e`byr&y!(&-2QT^@01cCn=r1%Z4q_%({@xeqfd@xqemvyT&`n zPyI*VV6*>Xmffz`&Bl38oBhpM_AKK&tFFjSJcoa8QAxv+O1r2bOCEvGcZZIoB=0BxVtzBMw#j@(! zDd6rN2ZuEY{8hDEFebXbHXr|atBb>p;Do&4Am>2!v$=A=fSom=;5Bki*}`6%13R^L zt&C?<)$-aj!BeeC^Q{1DA~+NDxhj9p`wq?Pa%hvtpZm&xo*rINI~6?Z%{)g+(tR~m zljU59_Nsx))nDNwXz>C)3yWFKb8Db&n*Adb52wLA>^M<{wd_2a+>_p$v^$f z@;`OD{8PwZ>_ofBpS~Ti{@gF@$~?3DSI_OY{yC>yYON}BZ2+F*uFZq@l!j#uqPyo> z+?Ph&g3Azl06BKYu@d;mC&@3Z<(BnyU*$Ice`?Fk`p+zPz-_uO4F}S6_oukrk@k)& zxBCBSDtDC=TLjR!2O7_Z#;cQ&C+r@t{yjHboo4;MG`t+#ocLMmAam9yOY5mhXN;ay z*TsCo@=EW%q}Ed_v)EhC-pO9pfynv5J8eBK=JEiK2dqQB{TkNyBWv>~u+C?FiX5VJ zsxIUWH~wAd5-RL-!}E|kuCSMc(?$NUr(riBwW8Xd?p1M+8_$La;H`_iu+t!b`v_S>f!S|O~Y4s==WeX|E#(oKkaoUx}ZN&Hd7bWg)XS$w=22TUI5g%`MnS9q$2SA!kFHUYY#%??im>kW_CND(__73h%4(HT`d z(sdTKw|%{dwD?VbS4qT>i;tT#Xr9feG$5%0@5s49>6Zyxeir6 z;Y}5kubT3e8|9-+!E*k^=#pp`Lzh&5E@{wd#ORtx!>Vh#m$pmLHDQ0O1AUt6OY}`v z`+0X!=3VZzipTA#-n%H@F3Q|A{0h&m;WuIXBrVv)zZHy4_M>#Y9{CMMFBR2C>wD&c zTU&}wV#%LV*pG_h;q3AHXZ9*(zZRafJHnHCojrMDY}zKyDa!cqYV13(pOU(RcYw2j zPw_6}E&CT$slhA2s5G$$(Ud$kJH2&LK~omzOWD6@n$DX&i>3v<*{5h)l^%TTsfz{hLaw95>1?2O&`U(g!j3;mqV*vMcKuy})|o+>3{2Fr+z2LWtL<|UOw?A}wQ-oJV{RQ2W%ooe zQGVRur2^AEF_@@i=*PrFjmQ0kczRlY0raF}dt+#7{*a!w&)T#lT7BpR%6t&F(538I zC``#q*$PwAf?vn{OB32Qf+<;lK|=fbY2O4)iEF*+V|SZ(`01Due?0CYO7l6XJ#AkL zs`7283~d#|m45Xg|5{B<$pd3_Ov!ezeE7@$``&S2ilM8ixD}=ZKdF~vTwTa_m7dN~ z@gw{}!kL(oEsV{MoOucLjK!4rscRzE_w7T8^~Dxe|8-mG=xH0Dq5T_qDohD(g$JRG ze_jZtgtoW!fhj5d3ivA?R;A?B^QBB>{wZvP?rd%MA_*|tj7PnMToS#b>%s8aGMbb0F^WDg|q%Hez3y7!iCft8$@{@k?ChMh*qW4ms z_$T&{cm!`!Oga&~iTXFZd6nd=+^4~t&<-LanRt^)Ql|A%o@ieVgg0@2Pho^&$KbwU zF=cJLZ?>lP32vd?=(Dd#8{rm=mKuZjALM(klv%#-28H^HuJnD z!-_ZAYT!+_o)O+;)Np+bGp4lA)#M51Z1sdk{a?bB*y&5bm25AK#g*Kg9>tY>B|R2b zQkx#dm8?#W;!5h$bzDh9dJL{)v*-UfuH@#*!oXK53l*-U&J)hVt#Bo^{1aSB1OIR< zT*+$Qf-9-RPjDq0@x!ffB@O%&T!}#^vSu3)S8|UhiYvj*J}`Ip>3rYBd6;|uZuS}a z#FZHQ!WynmT!|%IR8F@wX9ypI*PHo)zl*_@q!_%XDjrutdQ0F_*0>AfiIIoNOGUu2J|}IL)p61Au;SO^kDtO;;#P7G z;eQbqwq3%(8>J3{L$Rj&Vq92jx`IP7=K(3lPvXK_(-j;_l=sET`{-N!zk-CG_Nxw5@m(!pK}}(vp-d0dHc283=E3+J2|aOX$lLT^9WW-^=*U zi|Qw~D*XiQEB$^Dzm4~lhhKb@^&tH=C=ANWIpGuJb&~K3gF;#n3=01pr29PSD!s!a zp0LnS*K3RZei#(mvSlzB6vBy2VCW6{#-JEs6kQ4ig}QB_Zb~meJ17jwSke&;3T@a) z{rknBz>A_Z+y9sx`jQJZsj-nY+%PjqeACg1tB4heo~3 z{pCgAR2JC{Kl?d~2Ps*HJ!IS737YTX)N zzq*6T61P%hJWJeizPCTe*~qwf6U{t~JQW_r60b_)t(%?@Z)9A&rnvkz@;xdf*pN|; z@p&ptilwa0adE%Lw{N6iL%^iOl~-X>EO7;cVy)+Y^L@_mB`%nhxVQ?FVu{-s7x!(x z$2`=aV^ZScMlmUqG@D>jh6*NSDCa-vpWLC^4%+qu;=j-L$njuR)PJxlwB2$3e?WTI zjW05=Dn;N;Ml}j1ricH9<1aA&U!X849sI9z_!TBa$|STlC`?M$a|xJ~%fO+Sn3UU9>^DzewxmUG2Z%G;`F(HTVe(QLb`TVYZt3p|VUO8@-tp^k`7 zEs7bfPu4Lh=fGppY092N?zP4~gkVSD;~TLp=HAWT)?Q=pcCRDs&MXakZl0s>+1~67 zd)WK(=FSa^URm~cJ-JC?&*GA>_kjM-b08_~u1gNv*wkE^z#K5FnBYQZ5 zz@%JjS96ZSq&(gSCgmv$Cgk&ALiU15SqvtHr_VicBY)3GFd;7t0+V9ouP`Z}?*o%z z&HqPWLh6#WJjzhUGhqI2fC`l}1+Q5YH44D7O z4EjIq%<>=82PVRr|11~%4<>^?DB~G0|2MMe|3P3ftnL5GY4ZQJoBkiF#oM$Uc3Gj!F5Xcx42SLYYn6Nqm{j|DVb-n^+XuIfCh+ofEJq zpQd(BHgG?QWsb$6e8Odp!Jt4NF&Gre9)m%l%@Z&vlwbDCJ~7&cCyKr}f*@8s@U$S_zfhB<^R2{5gH-I4_d<2J5|I=A9IF$MgI;NYr{o+ur z?E{BGf44(_vJP@17xjxnA)M5^Gwy^RZx42B9M=B7ajy z)P;_yG8B>pR*4PwT4?!!2j_K^MDMlJr9n=x}H9-d@*c9|^N|y&c{MFc$ zLF%ibdha-V$~_*nS8M9P6YweQZ3;eRqt!me{N(>z_>@(_j}M=66?PYo^n*{)JW40G zmOkm2e@V}#IJ+DQpQ83}V|C%Je~hf9&mNyb-ZJ0H9-Zj0O?=8zl@WZ(Zr6lD?L}}Z zCO+j+1D_)Hd~E-$<5QFyy@#!C-K>bso>jwiEJ{6Z(`L^O#Rqqwwpv|FVR(jo?$9MUnk_(|%c)_D#U2Jib1W zSFfKLgW-rN-;>;H`X%f?QNH(S)3#?u>9(Qxce9C4Ddn7);3JBsY3=xnes%9X;2*FD zH66FYM&PILDS^7sEfsn?>%@=n2MK55Q|^_0l_x6`>KTJiSwAxd3t-wjDe9xXVt34H z&n2dA*cofvH&pu$c`AGgZiP>wjOCPZ8ExMeKIOS@)`h-LUJ_UEDbHau_+rAh^KHea z{Oe)xDcB8*9}f|Hin1LR#Wa}p@RD{6J|(Fkw$Hp`%g`3Zr_lEQaY34aQJJXYQl_P8 zE`?K}@9_7(F;TlJf>W8O`alHhNw#Yc>AGb0i1`BfHx1%`sOnJer$ev&Xx1#iZaLfD_A=#{ekRO8{{2S!P{Q#aOrr9yr?0P<`XPgUqBPnk^{k@3%BDfW^{P+n@P2>{Ni(*$M^kY9|$0!}Uf}NDvJt?bpVlzeT zrxe@EZtZ+)9#|E3(B>|__4u!Kdnsb;z}#Ps*h?Yr-hE;>Dmos`zLGk9EcQ|~9j9XM zwRST92tGyLf=|(HySW<6Sfh-KvxQP>+CrhOEi&I7NDcoxd+#pvx&fZ@8LV%>zG9oB zK?ESQIPNT=hOYo!gdI-VI7R^wg5 z;3s$pbF7MZ4>YhlC~B9K$sHpH|Z-t*@DmkXL}b4zawna?gnA) zg#Fb3b~pOx;|5L8h9&fI@StTa%=bjT^Wb%IP9w4wrvGj9ztF_}_;39Ayzq;!2o_?- z;II&l6T>ISPk6M#LXh4_Us@CofuDo4*O9hb>;5S0@eqceeYD~qY7S-p(#9R5!b=n$ zLcZIux$GEi;2}Q4y#E>Ga^wWU9pqh#zmm}`aTOlI5?A3NO3zJ*r|=M#cnS|;iKpWs zE=-80c(Ns)!b4c%DLlka3_Jw?tz}hs2uoarhp@y|c!)<0JVabvg@>@jRd@(XT!n|Y zM=%ZGA>!gHJcK2#!b4c%Dm=vM4LTkoE^ZVL@fjTtF+%VV*ns41%T3mH(6&)L1hzON z-CS&Oth-RhL-2jw_76wZr<3}`}pw?t>7VcfQO)cJ{~+onvRF~5_kx+4vbg5{P_kR zqCm$(khj7^6dKrvLIV%M{~c}v``}(zq-=D^zyC4*{ZBu5h+oc&#X}f;rQ@>YvPO;Y zqX-^?^1-u^iTme&i`ybPoamfhKSakvj28XAfrqGy!$S-K4{-oIM6rQ?D0YV3H-m@B zG|sbUf_)G?M4JT<(Z;{+;30NjqA(Jk-O1n~h72ALvBSVad}EM!h;Lf(5U=!shiJ9n zA-)YBqS(oPFn9=_KKEmd{5@}ghqxR&7R>hp;t`De6&~W-ec&Oi`Om^eMIAOWC_@>~ zfccNaM#aWK*vPQvzoHL3f;Im)!9(nIg9iW)!82g~*LcALuxEZI^`F%T9>JRbYOxUk z9)UI};~6mjZ-|YELEsUr^-t{s4`9uI40wcM@Cdo!5qJj7U+@T*4+4*1&Hv5QJRb<9*-}to8rAm;MKjuoyf7&w%+~Gm`!v1RlYf|LQ*Q z2-f^hrPBYS!9%2hhoEo!!b6zj?;Ae)fApEr-@MBb@eoG-Ip0oC#6y^TP2nM;b~%E3 z%M$SrB~E3do2g_aN;Y zSLRqe#3x+l7(4{@5sQboG!_p*nPmIMwe6q4h@0=9y5I*n_V|KC^ zaUg<+_%(QlG?AC$@DMw|L+t1S4}px~CcKV^xKzhO5cc$Vh#^{l`N2cneEY&E9)dh# z@DR*lk@S~Tgy)sa3187ZNIV4dpu$7UjKf3BH1H76gskP2F31e~9k2|9kK!SokHbUU zq2nQlEBZ%?n_!otsxLgmkSHDkxu}0U#1I`1@#|udg?F24bCHF0JjCb0L;MqXh!ll~ zc;I&f;30IqVBGmr(dEbLfOe8b1P_6(;$glmI-soz4`I;(js3l@15%g>iyr7>!9)yF zS9Fpxn!2JcbVVIG>@$7zDZ@svt}%5=XN`@JwGnh?=$p{?1GIz z=caUf=%oH?Y{VdSS5ZBA95&+TscL`F)R`w@BW5T)7W`{>gnz9Z@_!5)G2=AY2;HW9 z)UJosc1KQB=f>K-{>Hk{_;>ojMzp4?uxsg)j+K`t@D?2#A$x?e*oe(rwF|{6WH**a^Wgbo72Mq0SNPgzS$yr^W1XnwWzlzfG)n@0bd1y?J@Gy?~6HCl|#z-VJX-N`k^oEMCm(qp{2C3#8tLEy0|}v@a=qCu@iIO z20QV{+=RMB`ftvJKI`!#>JfvTaNH5wcgj9?9CqT%>|xV3wl|DD^qXgBa|AmfeTbew z^#Oj3f}bFqAGh>}U=He}uL$QSob0)o>4^Oc6`!<o^-Bk2%c z+07;o(Vr{2G1C7>NmH;C((ja`lrW1Wj9E^hFXO-H^y|K#5-FR~Uz>3WUrIg;;^P|s zEBJ5LN%jj*Q7_$I@9D7>?qz+9WoKF}-r_#+Cp?0;kbTVv-a`Ew-kdMxQtn~RtBkf2 z96|!#g7%ZWI}>jqc23lujWaEVHq3qe1kA;Lg{z4j*Zbt2LWh1Yg0$;3GxR%x#Qkn6 zWggbNM*7+KR`(S&8kifxs{K*IeIR{h#=-wa`Q}{@z1$>qX5LU348r&ce-OXd_`g`_ z3BSv53(cGshd~>NEPax6PX3vB+supyS?sa<}5&5RdUor*1donj7`|Yp&!C zo=4qZbGhOEg|pDy8wRJbHCM-LoS8k5vWW_F5%|TNzVEN0y_V32In#!Q!QwYlKtuP%%`AvDzY_EPX9R|%>!}W>ju!M`ss$aM`xLrQz;uwFw6itt;&@r4U!D-fbbuj=8CMCI4kI6vrb}nkhrah4<~(C; zDjvbO5?sf-q}6fTjXJL5wuxaGhl=+KPr$zee=}Y?erDW*aq%K?2qX1Vb5S4pDSH?L zO)=hW%;qx!Qnn0D-53?PjgO)U_bt8Mil#jzk@uS8r#){xSsNc)9v087_CJO)Y1^QF) zAGB#FZO||N1Kt*;=l=IU`^A6!W{b$3QJTmR{KrLV-7Mn)9aH4YP3M1RJ*@iaAO`;bwlaepy$|5)LX@?C5P|8c%1_qDtS4gJSB?w1z6kejZx$WviKEO`nR zWc0a$$rzmwS7AXcaTONC5?5hC6ea`P82q=^RbfFaaTONC5?5hCetUk;%s?TyKD?G@b2ww+|MDA?)BW^V>8h5tX zv2ihur_VcEcJ52CkMSq&FEQ<7d@OgitXdbnvjuEJ{GBcKYU5s$`k^`=g!*n9XKjyj z8lN=k)QMkU$N5?p@A4hsDQJso|KyJ!4+0irH&~FTXrGS-4?^93InHuCpeo}zg>2611Ck-x%%^o7N+=06xLhM9jJwjllUEQB@x!C)cG`gaTx3t`QFSRYsfYyOkKA}k)M z{|lov@3N7n$0Ats?+c4y%^y61xAj#Y?wRG^ zaCssY!kT|-7ItjLX?dAhS{cuP`ENW=^X82^v;2QlHgNu{hk^w;U&~|fw~S}N{Fep5 zf}DS5`5!OuH~*YN!xOO}CSMaQhz0)<++LZ81!+%;#e)2ud1V9(LYYm>M|_#h{}C+6 zr>V>)7DVtLCKiNtPQZeEy2`9$K@!Uxiv{_F%N&CRfj(leAe24EHU@2;fCZuavL6+} zg8aQ{8=e@01^I+!lT#~y0uIE!v)AcqU1mLJKHJ{2acCb{kX5DOidBw8+Zf0gn+UJ4 zAT8LgkULrkdpazLUf^m#B3y4m9q+=Zk)k2@RgDml0HG06)%98F6`wl?CHyk`5yDZO!?#3?}MA#unf zm3V1{tt9S#?Y!34C~NfYnGEmCX8iX2WAzqUH|EY3!Iv2KyhQF|q5s>B@NVR_ez75h z6Iroic1cfF+}U=)hR}b=#UN*{>s>aWI$3{uAx)vZTyBFoYDF1bL?%lCiBi|hr) z(0YpOo2MxqSPZ|r->tACoj0tzM~!*y^!L6zHht*Rjhs)d=I)o&R>E^eHI?(P)zf)% zmbH2TZ#l!dDmD1nObI)yh>N z*<(n^U*_!p$KIL8M^&Hu|D2gDGn0iZ1VRWTAs|^0K?FgQG6`rQ!B~QJvF!y!uOUG! zVl@GggrGu#${?*4Yyp)PqPayY3byx3q_r5WHPWKBy(NIwglH8NNCeF9{d~`ynKP4x zxU}{D>L1_NS-<=KJfG+D72TAKZ6=1~Pq{t}$qvWvNuKQ%evJ|@hGd`cYg{k5k*XYZ zzew&a{2Is747`Xw%#R^S<6fQrGOR}oNw?>}*ay(A47^A{+j@pGNbK+p{k*bx+E>7f zaBt#8MDI8!Yk? zBwM8~l{7S;;`|KwFb?zXzEH3g)a`+1bwg&mNB11!`xxY{d(JobHO}Q;>0N1=&v`pY*;mIY&H{xI z;a>4;kj5KHV+m#7Ek@+-%Hr3FOZ+N~$hykn|K$HeJXo~RdTpwOj$<5#Q*1>DY*F|>wp6>Z51o?Ob{L=Ew`%8H?@1-t8XI3fo z#6NqvS7SW?-7WHR{Ah&1+DFM`TiePi>cTin`JIA_`MR@Ea3a%>xhh=8I0q?IYihMe z)Xios)p%nWM1fR4Qk(d*df8r5hxCkv})54^Z*`MB)L>drab1_x z6`5m;95PNf9|o z(F?9knpHETAS)|M{ik1I{M$cF@g#TRQMkQ#I3YLY=${M6ilCvr^$HST5z}Xyf z=F2Y5e0d`LJO}A@JQ_R6N&2%$|FpDeS&kjClQKxR=)9VMY>(P1&)!&W>2h*O&k|dl~SI~eHm#Q)xb3> zGHVoTvf9vuaS>bi#(f$27{&Umc2Lr|hz8!tT5VbQtWn3fhVsAS9vL_e{u0g#WvxZ| zjFNNuSl5km!b_s}9~Z$sFPr-^(l&}S`)U&gjf)879rtC+!e)(%jqJ*kV)@U%uGi|mDPt1jxG%mS zOpVEVq%bwaJ>N3!NII>4Hw0s9jIs4)-=0_Y0cvdZV``pc3{m4c<3{G6^seW^kZy^` z9B1-b&owo%Mv!q6KlzMrf~OHqf|gU>vtdqgHVk8)8e936B6;+V!KNS4i(CIU$6?8j za8d<_A070+HGDZYCpdgt(Erx(PmyP1&XjR7aP5BjhX3ZAR~`9~4f&9)ZMC`x#%z(# zW;omxk>J#_LfjQE@$Tiin&KUGbvM3ich$XPchrq7Sy(^-^8!S8}g$y^pO zc=ZU^;7rc?Z5^mpvVsvdGGMG_XbnRVH$YMg>%n4Bu4$c;pGh3(8$0XbqdsN-Q zCeENC><{tRjEg7Fa=nc9-`dYz(Zak^V$&+7srks5)6BNjN`6vETORe^-TGVFi}VNA zd!N&JImFckJ0xLSu|wYUnEfo1_%rDbnPaE>d1Ac(^m<;-+4=il45f##Bj=nqRpNAEqOig)BuUH}elX1{1lj$BSC;#0fE8`}=Uuy73-yLY$k!y3;>42A!LOyzynz7VWI(=6LfZ>%LV-6FiJ} zyF0@NkiLlBo&6#z)Y&iIvuiGYtMfkVSulk>_jF!PiTSVB?~0Z{zqj$+-FZ1z1^L?& zs-FZ0~yzlP3oMF80=;pkfWZs+Serl8KeY}- z+6e1A?|l2|bRga^tn=~zQpdsbv9gn8&7syd%*mfw|Ix>}+rLlp>p#L+$IgAfD~GuM zU#;$Z@192XOu}u+Ix@>#+orI;lXWd)RdK1!T``?&8E5oPON$sRy3nJ@`zBK^vgdK+ z_KSCLu6(9exlYz0vi2@p<``TEC#TYzzT-MJ&j?G|JRnzyo1Qzpz!w+cNL;?X9s5y# zI?tXb8BbZ~etI3kF)v5AcQ0(}5cXYY=nz(k9qKWqL+E0Mir!$Y_I;lYVJ%4cKplc^ zH}nOuTunRFvEFxi_Fi=e!L}cr_H3&TVTaGQd3LCwL-)JMeEVg^_v{Rov-{I`UaVnn3YJYL zjnSl|*)BM3uY8yHs~ui@(?<4T5y+nRvEJYxu~Xbrgxr^Z#ZFP#H}Xy7*UwI^EM9ei z5!O@kjsFkxpJ{KpmAto{H?vEAeYynV>8y4J$X`ueLUA|w?%X@N=RCej9Ymbt`2}$* zT>|%#4oTx|(pW+rbf-%gHma)lx5OoWMVByaOjYqL{y)UCRhO{s0J?-%yVjjgm#}wq zxA{mV>;PTDlXu8^-d}fOZ@PDYUzb3c?0nx_2d{}dSab>Ce0}z&$SdR>-^TOKyqEg; zBYCfsx)QlE=Q%a;Y}lJ-doHJb)IDL%;9mOd_8YG>bPCsB>DMVNN~mxxO6a0f*v1$n zI)!cQ#g%S?@XfRtHl^8~$3=#nPMW>(e^=tXSk|o~yA~Ntwr9Ki!*@;m^UZvJG5=O> zaQOU6UIP4*?hW1f<^6izn{kRC&E&DL!~?HYRA|`claN-2eut$ zN0hD7D)OJ>(so`q+YY?*gs=32?{l89l=*w;4rwRXO4)j!pO^axZ##R@Ab+-ZBw+$#$Q7&?plXHuZlK zetmig)y}1jWUGEHYY3SSYs|Ci&+SPs!MPT!Ia;fc^TF-SK6jDH?R_8Nn=(S5E`oSE z_sZDouLE-&Qgd4jGA(4s1z-n7z6@V^gt|u#?Yl=_?Yl?DE%&aHjERDQ%*;goK0U;+ zC4H^buqAz&tJsoG3o&Hp2!B~)PZ*kAJEj1=8P$!YD0u=8B#0J6|YM4$suI)yZJ3g{%1P63^S3*E&GbP@~3 zqfs7@y=eWyVx~rgob2REo zGiA@#G});=CVR5}guyu*uRO!}bdtE*>34}ABzP|7eFx!9`m^Twh&i_zIkmKL8(|M1 zY?&)RyfXngd}&49%~w_|n5@OuK6r8AT{cJIBYK4E`dlr(jD6!X%#90vw&tphJdY}y zUmk_~FFms0CH{Gl>!`BK@)z}}f=I4!Gw)s&^!;tpE8l1EUF|g~TT^Bra(Ea2XXDDa z#}2E&W%)0S{7E_s_})g?=062N|CoJPk3ber{{BkYE)CaWpP)<*grT4MEA=ThyOd=s zWzeH6p8x&*`cuf_NBtmh{gutyy;?YMv^q6LTlRHFshfhT5uWL1da~X1&Nq~ol*4iA zaNE%=uS`C>qVvv#-JSQKpG>FC>_}7Vswpy_$#bO>d(CXmWS&2yJ**!FK1RmlRMymd zPvif?T=V(wD$|cQ47FCZgz-Jrd6idlE>n;{*&|rvu9fwm#owJgJHo1qD{YS2V860Y zwEEo=T%ho2}wy48czt;n*InEY|5~n^&;@mv{J=cc-5>FrylF!425^9>#5_4W!rm z@$=fsc}1!9UM|O~1jWaAiZGTQ@uySTP8I&5h*#yol1^zG@-0mAKw3{8wx%_?R^$C< z+P^ie2P9n~D~hEbZI(7^N%QZ$X>KO1b4mBJW}3gd*N6F6Y5uNh6KkaTIAQFxlx>yN zJ$2b7y|gJw@9TW?muXV%0iM;`if}ULUgX(KykcML)+=-OaPR(BmDdK>&`GL)$#3SN zNuHzlDL6FT)5f)IZa>f4T-OkW*evAXuEyO(SPuo2`{tl>x5j^zvJwA<_?yca^jAOj ztS|pQn+HAHXYi-+Aa3O-@h`@e%L$CwJtGdF_a|+4^Qjyxn3) zd_^~Q#NV>m5kHC@@f^;$-+>)5u3I}sZ~QI?obDxkIOEQ%$Yy98gjQKq- zIK4Sz9@lI9B~jQByUuP$X^lUm8%}d;{E={~r^2Zo1E)H!*ZB9vVMp2rPIYVi-|2?a z+#3I{IAgss0Zw%noa*GQJ3Csl{4?M*UzPC5^8Z9PcEr~B7erx44yXC|;55he8vm*x z*pc^v)7+Z>$ZqU-t??(vU`Lz^r+o~Z_LOaJ`EMD99dYU>%l|dq*zsE9e=!a_@)4el zm*YIsalOVrEdx995uYsnUv*>0YmNWb1nh{jJsGrt>9}6w-*zr`#Mz%L{{Az%+7Wx> zPZ^b{XX43Wo?H2#_V__!c@r6qhZS@P4ChuI81!fP~NJTdDlFTt#Bee1~&fPp0>NT5s zjlf?vai}__UPTVA*2T=rzBrnSD`rstm&HyydmPN`PMg=pnXnDJ=v2R5^r0lbUG$a_ zYR#S@e!l7TLmZL#^Vvnu%;?!JdhVE>?V>IF3*R20!R6Z{I9d0}{=m(?A`K_pL)QQD z*c-IW&g+=otzC2k>wLdm^dEoI3l<1@+}FC;MT_pskYxwU<6b8$A0`Ny(E*+_yz;m$ zV*jCu?2bLNR~~oybA~)lVS>CeIqEPDxm-jcc>XeHM4^n$g+sKsvM6n4K|-OcETPPW zo+qn-cUHNb;9WkA+%AJOm~y+L$nCZrEuAzC97n_;UBxfhX$Ns(qcGFqjo(51BG;?2 zxe7^(s}MQfa%6gC$omSA@0I1x6fe&$OQ?bIh^`KCt%72 zU!#t@$OYlf--i5C$KnORz6Hc;8~zvK(cT z+IPlja0SAlVRxu`$-on9o}2l{2nRho?ec15iU;5kTpy;zZc5S?iQdJGr>uu~w(wq) zI7qV*M~F(dHQX6N;p+6?RhBe=h+T@A?z{RB-b8PBtHQLI{Xgy;Z>BLHzuS5UcLCqd zRvzc`k2T#xE%B^B(>eY_%G-=%#{{Yq8o_uEBJ`CXnDQwCBF&v@&uB|N{&+^6f< z3wkCfCem?t4pd5ie%f&c0P! z)J!;$x~o=fdZNp(Z@;19`u6wq=*F=t-R&{9*qUftbYpb+x$V)mevJz&&TX$}?e>fw z+4cx!5B8uoMc0qL;MJ>j;Xb!j2hO*GiXh?@JOrS3%nINspA?GLbnotFH7yg_AgGb9hq5YHDqv^g3bg zMTbbAg#AOkvRK-*;8$#v$8hwNJNcjgR9lnqh5r7ZL)SNp?@)#%t{W` zW~PQusc#wV-rW-BC~UqnvVH*Tik8{=6)p4Z6{+EQ_04y>>eKA`^@pk>xVpJI>swOX zyESah=F$$n#rX)w8SA7h^2*A~r9S5pX9o99E!jnzEXXLESe}TUFC_xoUGF;KAmiWh zUp$ahM;I;ktgQA3cSmBl=6Q#-MA)NbUFIre?Xm#3Mo(~w9+5p(mT%qSv?+b>cHZaE z-r&*PJ%M|-efi^uC^uV7W%2XW<2GBoYoE=LCFR#SMXNZ;7`UFYNU__FZDAeZ;J;St zr!CywA##LLV-MGq;?y3il6CGucbE2)CVkx=-m5%&U@vXx%oLrrXG6zmXCATDZLue{ z%Y0#NL))s8+UK?}-(T|Hvi+@$1=e*k`!kR5kvQJDbzQ3Ncp*j8JhDHs{==B)$;`p= zPonO8A%*A7)q~nMjuLEVB7H8t?tbo9eYAW(`@bf~viOaTGt+7vXY%fK4$&TSOd|Zp zR&Q{enR4$o`=It)Kc0H;eJ*Wg$x!B_W6RdjhMKe}N6}{c{W*?w&9kj~K)afkZ*R!m zZ2v)yx?e5#>y7)nW*W`YZRb=H=Y@?Ym1Qhq`cr+WQ_dcSl2516J9 z-W&eHjrXDW1JCs9oWs7jLK8!Y%jxwu^n8)6NPHoQA;cHqeV>q(1+MAWIY)f)8UCWY z;SwMA%MzdAub=VWNql0%oCeNdA6$2Y@_Pxr=2iCOTGrH_O}4>pI&J)vePG=;^!5vb|K02VcjoeNZLIt&WiR0~ zHnS&>udB0P)!s&XngLhW^|(jbTddL@St0|O%l|gk!tyWUMSPm*(%$PFzpeVJ_Tasv z^r>g2=uN%pi1MEeUoZXU^bL0A)ez>_Q0Cb%=G$=AW{&Nr=ugdeYTGx3uur#XSCrV@ zliD6}Z=ddTuX8XrO{XoF&YwTgp}Pu7=4VbkvveAMze*UF64oVzITb#yDXj5q>b$oP z>|u2s_E6R^wz_>_-sn>u$M4m*uMSaIj$_lL3lp=hDTpP+_nw|M;#DKWzODlGzj?l*GmuYd0 z{O4XeY1dWo@KDZbp0bup2H(wejNqPm#M3g+-NAaktpPp(N!KGWQYMMM@-Cnp%yO#z&PF z>cfmn)yw?vms9UqW_solPl%=7DZVCwqu!3 z2Gt$(#+^+&_Qg$m5P6!4+tMDabtIT}i4$&_D?X%-P7qe*l8Rl9oS3-PVARtXPp+oS zE0;{#wVpkXtPge4kFAhrwtZmRp%a}~M5w$N>G*HLGwbSU?#=&XzE4(lVAPSs89{z2 zp9-^Fwh*qoFZ7nV^kd39!rFJG?9A}NXRgob%-b)1K4cA(7NK2{M7^D2J;8pnzxm(& z{3q{Q?1Nr79X{=aQ~TZ9jq#TL&$ss;%G;j6`fXdZ%*8Pq2hL31c$HndK*r8iySw8k z?W&FO0G`L)YglVXVR!#`*4}H)HhwCvRKlusdpvc$4e0 z8)la){*Bw=ZiI&;g1IfSB1g%(MJ6hBvCXA5VUyb7SeCT0|Nka$yzB<{??{A7-6+g!$FL;k0Rrszx+O<}XcJ;IM%X(?qJ+9wT zmQm$dy97rVS)RR%a`MoQJd?GEHrdyu=+3q%%E<`VQ8!A9cwsjCQy2YA;;16dD3V{cpG8qNDLwwQt)73b}G z_e|dYPW;hMuK2HtOcj3%^;5=s32zlR@ht8qlRx2-*v7g@WINie{o>`yT6s~kebZIG z`*`D?xxLV#r@A!ctHw9I%>N(v-v2T*t-z`2*!5+&9GXM+H(911`If0^>RX2Q8|(CV zFl>ubcT^@xxV`i9Req^6*5m~a%2M{EQZHIXzghCX ze3v|B>3YET?()^$KbE`&)Y~ZJ@iX*MQf~#l)mwMz(}K#|8t>WC)mwR6)6`RWYp0jr zE9F9&AEOVv?z@jS@AWqSd+xpO$p_0q{RPUok#eq~oEx<>Mp*KVGUl7^`$jsC(JwZ5 z>!923l&$(spXi|7bkJ@Z=@T!Ik4DP2hO%ueI8$3ge`s`QS_kc>k+?b}%r3T8rFV+_ z%g?)^&V}@I{)t?LJ^0H$S?QBHYaNwfho;|~AavFx!=D0)h>-P*>!~I>{ zySZPL)51TFymLGa!&c{r+-J|QyL0voyC+A}L+Uj>6c>gI$2o9LoC_C$i>%k?SLSlg z#%|FeT!1`f&yw-wBBM~8BsN{G(K8s=_t|vAPH*Cc*k<&vbDV-h0y&m8k#og}KW*Z0 zgBOYKM|hs+KF9MkvKaNxm~#yrDgRE#-|=zC_HfEhf^Ui&34cf7GZZ4fqFN^TdT_R>->=mLtHDOdf8s^Ui0O2|VlXyMuM z=Sk(0z|SB2NI$lUeT9_iWV^mdx@N(HseDMe?vBH+5G) z-OVPPE#$$hBNug4P*qS@c;;*Sm7W&+w$f6=CNHHa>{tW&q?}Z{*le@aZ?@?;tzOD{ zqW68X-GLl792ZvKyh1p{IA<4Iwx_Af2=d6!0PsokxBPqmttaVhalj;S(-!78VqQ7APB#X=(eC>Ij2z zDr*~ItS=6geN5~@TjZj-oCPF2F#qEMCoJsmx_E_Gyu} z=(Na?BIflQ9Wk4dY?QlgNJtTKxgB;-LvDIyuq>Z-podRcCTwE45 zI@3o?FUVk>;tcJN&5m=H6Wc<^xmp}DOO?i8{e-f)NJY2xV=c}R>&SBaj;oXFn_NR3 zSIMK4i`9Aj}gf zmBlA?@i)LFVZWL`G1j3EbgA(F7-EFqYK!YFT(xdUBR##OuQ&fjy874sh;(6>uF_?u z=bxRH&zhId>R-y@8ZANRdcAI(YCC@0(lGWu zozVcUwp;Dpy?Satf5e?yhm6I|NAAvPu4Wvp4#kDw&{I{T zr>fR*T75fXe6zhWS9H)%F1e+=s?E6@&$Yb1ng>d(MB;10$ z`$(%;{gLiLZ{0MRc_4$Zn#1$!=Y)|y^j34iNNc#8tHw2tt6tx7r_$F1aB=ADG0!Z$ zl5)9%@|i_B6(j4Nxt(%Ta^6RO70Bn%S>3Ox1(~nOEzY>?3$OKEopmTOnaSFu!}p@A zXFsix=Hr}6znOd=;@ye~mBk|&m$w}V^HhfA)oY=8ePviaR~uJ1SFPSS!#=)F52-AE zC?8$kaIj79syV z(IOAXx(oYpkq65BEBZak#>2Q@tMVSZB1ey{&QbY~UCI6J+*1azmE2e51ee4ArgvWs zQitF)ipgKM>#&PeSv*a>>eR1|dbU&FA@qaL?arIl%evps2cc~IqFI~ibFFtW7ULJ#YsG$;@i?%o98sw2WmABazfAg74$2fwKXB0!^EHemnctF!K&hP z!hC=-kiAHA+@736aSb`rzEf%E68|C6al)RYuqBz;OwB19uhxj7-+jhr*rlj&SJ4&; zKW&xG6OImH^Xbm<5+-|@jw*D+vhEv*e_3Bz{mMTMdqS<&6y{0bdu8ePU4k=tCeE$a zH_E=dQu7?CCjH@g+tXR!@9F3qKj%UCt9iEqeV$!gQQXi@o1(qV5xXr(2lYfwb){=3mE*8@^mV5VYvi^ONHPoJhJ-I5Zxlx`1!pTE-`rsYz)Alwimd&8MM?W|>SHx=y@#x>sp5O>skVMEq!D)N>B^dZ8gXi|jZGC}+G9S> z+n<6?g!$o$-&bU)cqL4cGrtWttRbg!v~6RZ9)X-rTRu5;40oeGaL%q%DNCEjvM)7|yy&b<1o6IT?aCRP?{ ziTOp^li@d1mTt?*)Zt^3{h-sWxHY7%)qeA;(VogBi_5Q1QViQ`Xms=*Is<`w%>gJSY9QA@|}C?eg#7R?$|5&{lrJy|NSk_Gr(b zyH^x<9MS8~v}yIyzFOJ8yv;cRHRy(Fk@X8d@7=NPihB~=6>A5%D?CHo6{*o7MLO-e@m+EKK4!dnX$XKjhTDajo@ z?&-}76Q=%R;m$jD7VR9GQ#67514A$7{>h@R%loenyZpc%PZk~E+bukwO0q_Fz@&G)c5|0SMVL~cJ-a>mZ)yN!-Jx}b6wPbQp_D^ir!jzrfBRP|5H?! zH`r4Ui(cSl=M^sc5^{Mk^Al*lt~xvC^hkSZrXA@^7nd{M-Y4UM*_LE)DDs^3*qc7X z*wAq#kNR`hoAoU9yXBa%R`QP1o&&UP9+|Rf9$D-%o1n;`$x#3%h8{g&r z?|O8B%;A^MzkcG^%C4Vy5IOC;_Ir}v)nf`SFFSXl!j>_o>!iJa`C!xWh-2I7#}d8+ z|BexVPSVgtAse`FPnfn-+M|epR6Y&&J;aTaSw=GLdx$X<#E;iFwgRI>H*ol^ta>b?hY9b zP7Zc=oLn)%^AY;ftEwl^50M?98&tA6($l|6_r%YsET+%H?PlQ4WZ(a*r^DCF+F~br z^7VvIovAbkc7gYCEsQNPE_F9Y$@trOOCIx+oW;}gK0Tf|tej!y+EUZ5o(jH5rJc8GLfngbVRKa11jA$bv>xuAD74Ta(nG;9K`dS=nr=-XxELp%6azQ8+9sXeSi~Z{gL#M%Ep`m|aY(8t?a_`lgjTvg$a@L zT*bai#uuIRd~`5xyU6fPx@?}M5jGF_x~55XThjsju3xc3#(bFh1G?Y zr?(Hs%?lyznysynw6D>lS%>P!9${X%9vore>CT-Zf5Zl&LavSw_asfjMJ0}tXV#l_ zTBLiDq}2r$%blhPR;&qqt-@P+{dV~NO?FRu-v4i1@V^di&sEy8{z~>~+7tYIm|;&) zg3W;AF=bD%HrSqE73E~w6R3NuJwZc%!=9jt>*f%{Zs3^roesyk)t(>?UPX&N!EfPY zlQ~1u-*&2Vpm~2A?>~V(fq!fbvM2Z@?eEjr6R?)-)}G)2!lO=lwI{et&b(4~35L9& z=)=zYda@_T?;)PMRJwb&Czu!%u8d);sC&}}!fH=Y(TDJcd&655WKS@NG;Zr5+;8@w zJe)!0;j+XNY)|kpdt4dQO?!grgx`ZbLBQCj%etZ$dxFlV!q*4O&z%Ooe{IY#cZX)1 zj6F*ie7~h#1>*bdy8`k3S)^0Oo6i&9?K}`4_}LG7)(y{Nk1OlT&r3I4%v$O5)(wB` zm1TZP-Ed$#`i#2a0o}B-Ao;AnJ@q1=z0%tkTfYGE+3yea$!7!0it$R;kUhy~_dnV5 z8qF)8_4hrid=~kOMLz2*ufED>r=|5EpJiSCY2~vQPzExlpG`j7ATpso$Y(dPfAPs@ zS(lsg*`MRTH~DNm-+PnKzA+CO?VWBVqutz%jP{%K_3mV}?bH>rt`3pY{+Kv|WV8YG zKG&@GKFDZ`dus!K@X2WX?Lf(BlbYTbiHrj|?Fn=;Cj;fQ{`Mg9zbbfhkk`vvSnW^d z4pnkmC5O8z89D91y6;GtA(uJHzAaczdoOFkIX*dUv`wr+GtOI7DR!?1yU1yyJw3^3H+Lha6&dRZ=JNwro#)w%tkq5( z?g^5$w$qotXTvV>GPVB)&ekAfTk<%VTj?!^t3iX%YMNTX2Nifdpyrp@J zGZ!NxTr|)FKSjqcT?0KC$S6NRF1YyWIE6bp&HV%OqCI9?lQcY!47YV0?e-ykd&?B9 zpmM<(@Q2vr0Rj?dP`b*%01)vGUxhsW)&F#CY`#(Vyy}(pNIEiy@7qwbw4^}q8B5|`r|$3|!R>q$qa zxI5Y|c6a#Y`8O+>`91t|!?pd8>E9e6(_dQ}DAT{Ew0oKUYVsxVh%8IuauAMV#Oq47 zZ=)@^!wuQKN`sQ^4@LGguuW{$MYg{NzmeBQBHzDR$@lL98}~`%`&)=#>a>NtN%^$U z4_e5p1Np!73z5msM&5rk+uf1(meD`OhUG(SW*k)$(4|j6zO5gd`=%-DAL^I&v!1fb z`Wv3;i>yCM$@(*c_-&LtQpx(0dX+~e5{GIJXP4EzTu?RmUoNXNXWusal21ds>sh!=di~XyM`5l4i)w9^-1t&6>RL4y6Uk&Gcaba_3KG>yn#uqp>8t9|K)6ufLa$P(AWllJe9s?&rjOP$xg*d@Jz*lexr*qGq zptu7$nVMga@4rl#sY@?vUr+dIe!*T}#>(}?+e{q7^YH;^^cdlZY%QU#3_JyL{McuP zYKz!Ez|)b+e=(j``Hy%SaDU@IIIf+&#wB4mRQO`!rNV~?B+V;dGt+#WF;etK5B4#v z?-15DWNYIUSBFt1&yY5=On$}vK1-RH;n(yUzELhLm;%aWgg34~D!z_X>cA+MhvYwR zxoqZM_GLe`CDb<9q~FKaT~AyMw!Drx)Illti}N)fmxt7EOZcT7!TmgqagDasYadVf z#XpPB!{+1jP-6<^Im*i)B0M7Vk>}Uo%9bs=H}b_%28RgqMwIS?Cqt`y7y15s)N2!S z@)6uM;50^HN3l{1t?>wEgE`ux*&B~>-K*zyyn(x&=do_hlNRFc*rMq*={%=tA&uCd zdG_jh$06LijK4484%uVtQfyJm4o&XCh1RYCW1?vhii@NcY_rJ1yT~e6+)+Hn%KfF} zZ81LVT3|m;@^g_?-ckJ8FZ@C9|?ANd8)l# z)up{DSugXdA@B9u7?}9amE^bQG0@e74S~Y3$=ZZ9VsYnr+U|hz`>Nj2dBn>{0@kzR zl-<)E-t%m{B&q4E;3rv)Lr6~Zql?ayhpv`_PP54UqrYiLJtuoiWXJ3xiunK!A0}m@URH9RMV?QN$Smz>}NA$9(*h8ga7nO>AR4R5-*b3mn zabdVnTu6QDkjmVYT-$D~0sE?kyK#5n*5GP!H96D`_FCt8w1(AiiuA9$gfrCw6;m}Qzb_vt%B!M+<_BQ7}NUK{Xt~o=$^HSgFJ@_FAZBHg?;4v5uWF{&-Xlst(N*{ z409jGOj#HNQiNuO3({4>g1`m4<20~u39HgUJe<9e}`LU&@= zO4$asRWX(*9O*^z2It|#_^#^1gOsh*iY~TNh8;`G4cAFK zdfBRv*ZU$5r)+2=%$;4wv10Pv<2bfAD!^7Mpj|zMtyFc0r@a~+9#?$~IPt+o`H8L6 z@1!1lwo+kTZKWvR<;Rfwbg`AP`E8}Dy|z+Zd$W}~^Ik8uQq@7WQj*>``d}+n)r+kZ zVf5Knig32jF8X9Er8@&{rJh}tvl$z{&Dij5#)fY*Hhfa%Vl%ZFTR!QVEl<%$!Rs_v zM}pUhz`1bF`sTvQ+~ymRyU}k}Tu@nDLOqM@Ky0WYEH+e}H8YX@d=?y(6D7PurPzDn zu+=L{O-@}{kSFp4r|O$V9@0j8?Y$Zc@(LOY&rB1WuYx|?Sgi{)Y^+wqFVa6^t@o4~ z8w1+38XNcaj@^2A2RaXQH`8%4+) zEcNKMtxEgex~ww=`wK=)Z!8!)y>a^Z>5X9Q8=cO@yq~^5n{SzCX6%p5y==c@tQJ>- zjTJJ70-4jWF;(_foz=pf69Ps)6pVZr82NB8@(wWa&g~*o2-&8iRTvwMK%^`YkkjaLZcfO>Mr$djZ^NO z#(k9BJJkK%vC)l@;NBy#&qBUbQ${$?CPXyWQm$oHLp=-UU*Gc|Y1#`O0Xn{YX2(+_;vs$7tJboXIs- zd-%pwuA27XjZ??C*WJz!oBz^~E7vW}#`VEB8glcsCF@q)`ryXfuL!C8sixIDck9C& zpPgoF{HYdObH}Ye-IyO4#(j)&pD6eJjQinoAI*K(#!JV9H42B7EoAeJaK_aij;PGt zszueTyft*=Z*oE!->_?*J4)uYKgW9fx2LD?e=FnC#<#{?+W5B%E^Yjc7TP#36|Bu3 zBY!gA{%vo_<6*Yu_uty9Jw8%ve*c4ew8zJB?XRtPrN3>@`wx?!>KAX?e*%5UlViT~ z3yur++wfse!u=<0OV*vd?a7V1Z+md# zc)M1!^R|aK?&ALo?XfjKAf8jV?cA7SkEyxujV1dZSpL+;rS{~;!S=z8Ire@v_rG=v z?{;nciaomKugmQlAFvN?G|Nc-%dtn*{AkZ2{u!kFou;gQQnsZ1ulB(;`#PuZcVzxY zqhl;?{C_kK)(1CUmCpFF*Pq6caqe~BCjWz%{c@vYS^td=eK7lz_!`F`N9}Wwjv9v^ zUh|yhsM}Vuq}`#1)r8Z&-pZIp`A=(XxnNpjm>yjY^L>D z+K8L>q0v6zglL>e`xr~Uzed}Lx$UWqg2i{}F^!kgKHgonYhw{@KM!A@MqfDq$4lqlaK@@Z{FB7LgYlD$-yw`u zLj&yEyfPpE8uYj5iz&mFr$g0xQsZ16-#k@~-ETE^zrEPIb>O!ddpBw0PcA9P-fao{ zgaLJxtOqm7mMGk1Mj847*5tG8#+qJu3&s8|h529hc&!iRu|Gj>oM!hN9fnn#D`+>@5jr~B6_Hl%x*2-cZ_wCB!Zwz1#zAwMan)Hx)&i3B^tT_Yi zR{{1cgzQ^~s`2HOKHgW$P_va*^Q#3YtY|+T%kws&Y#}tJOeYogI@{pBpdn8*9=@@8RQH8kF1t*6#;>|Nk=7CpbL!J2!p%WF(TJ~wA= zaXbGfZVC&q%X3UyYuM%SZRtk4=QP&`Hlk06$6jY0?T%;dfiTbES=i+z$9wc^)+)Qa zCn*P+gU^Qh*be3|5cgqMYg!fV{m9G+Kka_IXLb*Ed1KMJ_;DYGUx`=Q<>^k(d3^Wb zKG3bpUiL6)&tHpO-o2zhz%I{@O{(U3kadt8DGnE7LA7 zmGIF&dK{Fq*gVkhcUbpLghH#Wu{JL69X<4`DL zdDwPm)~e#wtovvOJN$BnDNUVILg}YnZS!agJ4|^)>j(Ls%skG@GBF>ruTA6ZAhFG( zJWeJJV+G5n@hX@U@({u+#%{a zEpeD3Ye|gr+#Zam6+F>5; z_4~F7o)*F!z}{k&*ynXL8RMFyKdYVxhd!H|gWcA5aq@kr(|Df}Wn3Mx&*l!? zR$bgN&t8A3%vRsI6#Mk>%G?&Mavi)P*q0>KWwRa-JG^Y{_Wo0@*zjE^SJnpC$o0_d z@_BNFgYRm&Zkb&^SFTmF%ja<2F?H9%$ENOHIJUob!{bw*UU)v&m^*e9ZJqkdg(JA% znw(n{Gc>no-9YVz{Zs#E;UA_xv+$4jd2Z^qh0i7D6piJZ*zx@#f$syuZy1Z6UGdN- z@UydMYw}Nv{>Hx_5dJvA`jGIqUNP+Q3%Gx7C_xBvv^~AH7Fn>V! zKg4e_@9!hdmBjsP!he-`#5Qm&?6+M^yWYL}235E^*Y0+1Q{;cR4=DFdx z?-9l#;#o<&l1Itgjoy6DBVBLtKArdTh+Fa~d6hgp$NO2tc?EG_Nf`O0C!hRE`mOn$ zmu%#>nmP52yaD|74^;$eKcVHoiall-pynF=S3bfxh;mbj%1 zRuI3$s}p|=@x|dkp7=G=A?e>k{`ZsrLVZHh4E@}u%k<$*^LSrOImF<`45i+ZcM#U& zDh);Y;HJy5uL7jY0G+&F-$4%Q?rp!7ykeHQ^spvNy5G+sSzY zVt>~$ZwhTczuxR8olEoR1AB50p~n|Fyv%D#UQ1tm)#mghG8c)h<0<;(()1CYWWH|z zCvyr+%t^2^$H4~NYfq|Oep|f4M;Nw_e+jU4gvZe%wvP7%**WgfM-Dw?A30QCvt?mg zNJvrs{C9HZmA#WQH)PmLbIa;;>dF5zvUXzp1;651UJ-w+4gDFoXN%3_UlcClS8pR9 z_SrlVKj|%C?&-t5D|uOPS9vVP2og{62+wKA(L>-uBk?-!2f{-ya?c+*kN)A1kqa zWPfDZK8~aviS6U>nMXdA?IYzN?a^oZ$e53gMzzV{y+KcMXlJU@d05sWtV!*|)t*7P zBCP9=mgU1cT8>DcnOZ+A@{;=2kv8nw?#XGr&gK~=*Pq!u>0C|Q$JUX$@%}npy%$cV z!`Mq6#$NI;_L7IOmpqKU)N0TtyDqx)`0D4i+r}`@Xl}UEqDo&(Jk--D0yhnKqQel?|oc zXG3|Md_BcHn?V>YVA3X{#~YNmx;P2_ljON&u-0*!>+&V=jiDE~>FY@w1ygnkK3B1& z|2B1K*ij}k&kewiaz>CHWu(uJQfzx=y}O+Kv#fn2ED7U|HrBZj+V~RsKnwPi@~)jW zB6gIbJE<(YS=mJX2)%w~8JJF+9XrYa>Wl;V4(~?CL0f#=X4b2Mohu>S{uMWuS9)zJ zYw=g&wWTakwv^)Eu%#5;p4jM#9`g|W|73dpb|?Mwq|5GkAj0morL;G3c0z|kw|iP2 zvTeuCxZ?x%!71$9^Gusc>4R?$HEb&7enbj&fPE$UJ1sP%zLj^G*QOY@k#fH^#cLZG zYJ7Whi2vJ&q26!UVk&<_{ol5l->}7$Z*M01zl|8;^@lB{@@ENitNG1hi@E%oE^B^~ z;dJ7czCeHP+0OY-bv^5NdbY)c2T_9$QG*vzgCDUM+sq`HcY^FQ2V3kj|Aw6A5bdKs zb$dN+MKEnLhrCvLtFq6Wi+yGk-{c>$&wPS$d{1eP&ptDZZ{p_x>VA_QT^Q|A*=O35 z+CC@y%(Vr1Y5#J}m&3Hnj5X{s9mmv z|9NpwtP{G#HMZBd1UqHm!P?C5d%=SZ?PFN45!SXKJlOY1n^`6|a=*_~CMF&%tk>|7 zmyp(Zl3#_pGjMY7I;gmU@nGMQ|Gee$b?#+-X~l!JqQ5oqV1MJj2RvASjf==m&xQxv zxV;yvAA#W<}sWf?8uff%PvgeP;DdEQc@*9PqK#5j#6%zq%pDWD8RR%r03 z${AT*u>pnTx95J{BgV;JeqT_G(~a<8^>qHyKLX=~JiH6WX(nm-B4M27QP-aX#wnnE z8GW>OjML-Wy6K|^#>wAD%SAuLh`#cHT_GR#g{mX&kJX<_S4`j-utN^XK@z&xPP4LML(X++#|ZQe^>qZ zm}sAVJa8^y&D)!P{BG)@r!}wBuOIiXO=em212DfJS-jbPD}&&Tf1rzhXy*OT|ijS#FS$Iriwp1i@(llKR6 zabiDu@&`>l`Av$$cHG}stGl(GVi&k6SWiwl^`s{c;6||M$(0?z218H289jNF)MK!o zd?R{toYIru@70svALprugU8g9FJ&AL)|0FD@t{{vzS*xQzh!GU=L%Q8vR-uMge$u8 z65&WdS1wo4mCIFh<#M&^%H>&f<#H8Wxm^9a@(}cec68;o`j&oHU3vd6b>&~`%Ky*k z%G=p9CvJ@MbkH|MXOW7oTp#H!|2sB5sp!hF2UdDX;h(cNe)t3Qv5Oyc8hjJnKk!hffoY@v3Z7N* zO`t#jFde>$LU<;oz&C-7-cj`GVtYRm-SK2w{INsuO&mkN_ffjmp*SbdD+`Y50rYV` z&I$Cz0h|-){XPrlM9UkLOX8>GoFMLh3Fm~jF8ba7kLR3lfQwL^6Ia_j7f}zQzmhfg zC+3{Me+K>)=fsM5gL48~#*fn79mmjRP6k);Aojx&Uj`f(iu0im-U;{^1aEF&D{h|H zkMH*caZYrHuc$6H@D)|1J>x5;pkI~vPGUbSaa#E&uBKhgvGPw)<^`->to##^`0X?Q zL^oIqAO8e-RQwb4ix%>X?TknIiC`lX{{&czhQC?(C(`q_JL%hE^UOcB2fH7pV{T0e8WAO>h^^APx#yS1R1a-dN=5z2h!!eyErI1vrNotNpdeJuNr~hm}X+ z|0A5kQO4h$-~*Ih3-d zFW8d)FUL8USca@fAC_T<<4+fOrX!0ru?*W%4Q?CRhiF$mo2yk;<*55_$^D8P^c8Cz zvAJH{0#_5ukmr3jGdB>+uqZbG%kU=)pG~pl{&wzrlK*svWe6CPd%-fC-x`Qz7|ru1 z#WLIlr-rGwuQ7O40fGE9*CTCfZYy>SI&8Ai!}-g3$0J{ZgJ zBypKohF@^s9hQOd?PaU&hM_0zo!h2lOE-E_unephUhWCYK-+w|CoIDP!n0x--el~O zwd+3x%P_TC@z;G8zLwxJ)Mbw7g|8)%{Px(d?Q-Un!Pg?Ti^A6eKCL*Q{5HYYGS60_ z?3=Jz?ARXy??KOYi>c}0Khy8V-Gy7DxLFL27U60U&XzlIci?Wvt;AL1R^X~|l?G0< z%x3Vo{Mlh(KH(+-N9yBqN#Sh2cHwi0A+6*5d@k+S{0pCp{?_dB3&GR$hIKeC+$~|r zg^BREG!xGu@|Dln`yI+lcwV$zgQum!%hMvby}UATd)P^&5_Sgnex8<`a)r^02=Vc> zq}T&FTH4vyh;8OO@V7+RqY6uP*I77PLKF^ryY6u1=)%w9-aUbPw|)8JhxUS*C9M~b zR>3apgP#Tay4@y6i*UxI*h7w0fxC9_Un_a*k)vf(o~-M;_Dg&3JOnE?chfI(?hfpi zDS}@J_t`iGw5xX~c7RvKj^`qeJLD4VF+=O!W3a~@3qK3IEn=UUr%kQb;aD+wTJp4f zo^8B$bJgm#JiDi=sIvGL(jw#03Bo&Y(FEkj{p;GW8wC!Zf5yam&x7XtH7m~w|EKZI^!GzA z&q`HEW$|UC(}zJ|ED)ZR3l4um3_XKIvcjrVVp^gteC6r zt}HHh8RaKDD~qXLKhKJzE6)n$JEECAN*A6LyPs#pZu6c=ZR?e1<)MSU@T@QvRe{U( zpGi%6`@*xL+j=>Z+SYfT6~fs<{C(nCiH!>6S>e3&&77Csg=>ZKwsNgBSI1(f9)s(L zi^fIa;9Z%AJ$pX-D&bn8A4bu>#r6={;3q$`nzYFtxX*kluQano6xV(KF@}c322vJ42;Zns~*$LX9Et<}kTK49DmhqufwTqNNZE)vUFZspMW z4BRB&0*lau+Qa|dah zy&YMQ5vo;`$Q5pq?005kyA@fG&Ao7w%x3;8A*|-GOW_;g?C`L!a%F$=33*B=s~zT^ zu{Au;$5TSN_G)9a=f{Eegq?eb1n`uww%%dxd0U^d8$2cIyl!~JCr@mQ&VJq z^rdAoXXyI*N`{cfK)#Y1^3@fOHN?7>_mx)*`Ep$A2hV#5*e0(J*Eqo=P={#@N z2ZyL<^E_`U11)xSPNj=7ip4fDwl+tVQ|y|Y6_kf2XM0DpkBGe^#~ynp=XH%GQX69MjMRF0 zMpk%vM%G}5GfQ|zk~~#w44#n(C-pcvg#9=w!>`1vct&EQJPCa77Dv_X`QIVx{BM(Iq~TBOv1p%jOr8<)DgA6Nb!GC5 zgb}`hp)&Z^gZs){v)(D6&b_^JuK)6ZvtX!Jt}lMxw)w_@cJRn0?3IOcxGT>{KwGH2 zgtKL0{P?MO+Q!@rgJ*<2>dC8yvtJremrZ>H@Qir(zar}bKV|TYlo8h4m`}zt;`Q@y zfuAb8gtK;I{5&J%{lL{R0X!o|{(_vLJDw45IrW5}3OEDYf}c9hK7Hp^@ty&z?od1< z|BY@Wm}f+BhJ2fSCQhAa|IOisyy2Vio+ZLH!roW7Mm`AQ8u^g+vHt1|I7*Ot%*kL+ zeP{6&+TlprtMs)N!V}Jhmal3Z=o}Q+h+Mt+skL7G)Y>5Yl;RqZ{{%mE-=o#V_q$dU z%d_C91}$Duyy4F)iU*UXZn;Ok>h6%UZNKCm`8VVqVO*b)mgKo?>_|_q+#`7xcrMom z)_zS-tevS3s&(s0wO;O#TE#sA@5t@>QUf+k|(R@D%q5oFQGfN8lZ~1g;X{9vP9O z`M5_yleMT+3-?GfVRqpjiHb6~N9d!A>7%FVF9Sr5=j9&RfIU$qcq)_ULHIIO72RIE zo_XgP#^0X!M;fgBBlOJ!^wC%2qCEFAM=Aah-YuP%;pZO#BXtt&)N%T$;ve~VkmaoP zK>m@lowfeGptII*Fwa_Ny(K(fNg@@2qvk4#hhHUd%x~DBclpF^YF2->&4}O2$l@`Xeije>sSE z1ew*Gjb8i<@}%{|(S>)U)|dml_?Lk7v#bd^AGrkCr`VD9j(>S_L*PEa$2+3sSNxHE zkI6gYqzwu0$YabapNe;ca`?==Bj>CYIlh05nl4!X5ViJ)XS5?=J+e1MtwrP<^VE<_ z;U4*Fed}9xI3D2s7#ZT_7zy!mk4)vO~DKeNLRAzUGLgG=fKZLmu{Q`AJXS@;J<^Pz;ocmZ}2(rwxDz1L*O(C@p6}h za1MNk5<39&JtiCm!_3sGbnE8E6@GKA8XHcYHH(K{qj5b!L6uLPp$4LgypA;ALOE@)549qTrUn2k) z6i=9E!v)m|M~4Of@?T&m8AH3Ad9_*o^WtBA+)Z5V=m>j`%a03s+zh`LT+o|+3~Li% z1>=HlCT(V!EatvDT+r`&4d1{8T_gFmluL;>u3%gcwgbL$`3Cp0kF;`}>>w@^7gW!E z54fO!@h(lqyD7cng08;58~lNR3tH=wtp#zM1h&mUj+6f+JS#5fAad;gW4NGzGSsCE z*{Ae$j#C`@{S>$$f8YK;iVGV1)~CY-eVy{M;)0sI+$L6BP!eH(5pY4HN$cl?3kqmc zs$ZT37j)}=-SkTX7v%4kU2#GFcJ(>pf)Epf`nMZOM3bu9mEoWt}XzgU^Z! zIv_Y7`kU5AT+mwf3BpYxxS+3+&R|^7Xpvce5^fUWJ{vBm-sC3vbhw~^w(wbTLGS;t zPq+(zyZ8d&E(%$Dm8E6;!*Lgv5RY(^$W^#WV+H z9o8pZ_>0JJ`=Sf~gH;!9;S{+7xnFO(@M6CArVH=NDH5m;KhxB`KK#ejm&qxTFS18; z_6~3dB9jWP`?+S__dy?ia{XEK;eRvq;Q?(y^x=Dxo8IWxJ*P-On?OdN*^nHl6W?O! z#Ffr-gXqKu*8QjGXO@gBKZ$%)Y~7bzbmGWb3{DZz+ivme#QVf4;`Q@yqZ4m1bmEFr zguEYk(A0?=oFYU2h%6+p8%_~#IrXFy?~zkP*0viAow#s{v?Fg0<`hvn@r_BLXdM<3W2?>RxAiKnmap|4fJG4e<3TlR4Ff#_A|vd@0_x_ycnPFxaF1B{r-}1+Ko#%3%b3f-f=ks}g-UmAHw_L6f z!=MvB{nx1&!#)z%2(CA6@f6v-k8y408Uc^O8T|Y4-)L_RRacz@r${q&=#Ai6(1B|t z$l%YoM(V*cav@UY8i6jEuvA6RpP9Kvpd+^88UcpwKj9kr=m_e^?`Lw2Ano6TYea5~ zK_C9|TqA2CA7NZ0S1ZLJv;*miNG^NHTqF429p5vq5k-K+H3E*23z2AJ@Qnm@__spW zF^keu-79g8v_#&_&Z3nt6c0pY;mn0c@IKpyYa}USLDYuK1yRRvF8e9vBLSy)&xA)Z zuZn`aMcieBqrka@EDh3YQ973VA_?dVR{SEU=LD={Ecr#skbb}UMeJZI%={ww&(IkX zjTnn6FL$vCV}kGxj9UbFidc+2s;dOTgTZ!DjWJE!BH;HT4wBMiz*m58Viv=R#c&!fHUHGpTZT3g!S8LZZl19%3U#nOdm_?mH)Tpm0_ zJNozKz%zs%wvT73D`Pd^3P&z}YRA3D1DN;~`7AK`iN} z`hjQ25PKfezXhIQgUoYM3B7Vb4?HJN;++Z4pre1g#d$7|;@vNdXV{*=hyQNy4FA61 zRBljmuY?g6c&iOiT!EKUgalP>pc~0+3BR)$!!(V~l_|@w3Gtc`zsXuS;yYOnR|-cwC=cOmJj0~x zk@k=A62D1Dyh{Ahg4g8OS9~jRU^aTde*Wq%UXwF88;p2OivDj-9uEvnZ@eb;&PmmT zQ)qNjCDyMQQmq2NNh7#U>R0ZbRKE-M`p&mh*RS!ZZcqx<4J&=C>zxyEKN$DZaqo@$ zn{n@n`vly3Ri{jrcu;a>9uzt!Gd626<3aiAE5bW0w%|b-&-CgQdzEG$lt%EK1Yuuv z_T|R|j5lzD80I%w zsu(&Cbn+hQjCc;zikeg(3NS^aa8{Yy>Zgi4#Rb=jXktY~6eY zoG5|d073gUV=og7J`7HkB5*oRuX8M-Gt29OV!0iJ320msOLA|kwTm>C-Fn4gUXS$8 z&#~4Qso#9qdMpzLBHqtzPifT`PhQu47HhAadmR}!O66*|>YH#r<+i!XeBwr_TmaiXMv zyTvx2kfmlKk7|^k#@054Dxn#9N~pV1Ow7p0E6dEtE9G4i(s@-xxElQ|$C=ef)5(H% z=nlKtY&R-ZiQJ??GdqzE+7NxA%MSGXoOjv!7oBbCy5q z{yMm!sGlLr3i9}6%P_u&80R6LAdbt4cCHAZb1~;Ahqh=jE`a$H=N#j$c~6kv2*lAc zh7(8Sr{|Tab&pQhei$%6BP@z+I)c8G`WXF#nh>@b;pmKV@P#D1gKKGY{`|b8jQLT! z+=Z;~`HFxKc-M$Bd{=?*D9x-)Ii4rM69ODC`f~EFVxI9*RVu(^q5zMHLJ6mU(*B9T3 zRbTvl;BK~O@sYmZZ6#a z7S8eJfxS@xd!q#Q#sSzH;*{&+Iw4+o%vsyb`}8)h{XBR@RFRfkCo*T%CGwoqD-DzI ze?0tZ!P2~<%zXA=3R&-u8)|QjslGdheSl7~8vy;|T_)oF_9r6<4 zh=0kB`26W-WAn?f)|h^l&!7HDY(A|!5TeCcbdbeG-cCH*|&1ZstD%M2ic5VJx*-roc=8;@<<{m?GDgL2u z8Cg;5cy&b9pIk(6w6qrCKNo(5gF^9P?Z-P9l0#Qv&41ddoV7>L?TPC% z)1z>{y~}#jxT(7~l*ebD%EJpF68Tgou0F3IK(^<#JacU=#4 zNqn2c&tus>ji|%@b5|$d&Z$Z#IK)S{QN6&$R?_*hKF04L*JkX#KyI?# zEH@!s*-9IZm9PA1&264D7_O|SZ(P|O=YT6)FLSI6vgTOXKi`65Wv0xrvQg$(c@%vS zcq-0K=2-cczgYCJ#IX{OdLlVfUmPpf%DN0QHVpe&T0^pU|BP{i__en>h)XPSWzZ3u z&Z_!5^d`37Qo4*|mj!Y+%ap%*3&hzQ6Mc z>cc4}jun)X#;^+Gz{IgqjrbX+4D~GQ`>e)PD#jGU6B4FuW$zp-bI}KSJ*Vp2Gs#up zwy^34g@h>^){SGu_W#i|hwx;>tnp<2(Trn-;e}>Tz`QcVco_2hl!A$QRHroWvpFB_ zL1UF{_t+U#lL=2Y?9w<^81Lrrx zU;hF0edD;DM?)aPu{@(nt|u+8s}5DiR?pQG3&9$Lz-i(H?iJ_kUO8627%C3=a5dvt zxfktdk7MP`U6vdx6D0Y?XG6s@$iloyRsoF5QT(?IGQNfWa}0M95G`@6Xrjf~QDSlt z`eE(*?i?%7cQB3>@?}gJ<5;148%!DFSfS^HDf{&B%H+?2ij(P{FlA4c6(`Sb2geHX zG{CX4OJ6eO@A`NBoU=dm<+6_sixI}%9+I>Z{>lHvGpjJKPaii_yyZYx?;ILpKUxZ`jPZGxp!;}4UsCW)zkj9z`PZkTiC`&vU*>LS&C3CD`&D|Hr3Y`W@T6*sF9oFfw; z7upq}Y1IKQv~704M&gGE*M1(*42*G$a;TBcCbH&T3D|flV{z2?yhj49$rxV9hIi!= z6YmPvXgubT1k`hdR>OE#C=C_9R}KF>faAHrx`UW=RNPMb&zRFDtPuWDLA-CvZv00{ zF6DM-z{WCsHwtp6haiIzur9BFEdD#?Ljl#u%Pkp^4AVriC`yyoh?H*7RT{>qUb%aQ%vqh>jAgn zt{cn#bW3#E3gt{Uytm9J;h7X1=Yw#A8|O&>5_xU0!E(J$Ym3f8aJAIXdcAk9mc(^E zaJBp^Hvdo1FPOMmp7~7TYMF-r)6e2+LA|Ap&|y#MWBeNO@=E+iAdhGJ5L-UR9_=VD zJVbhhF5AkXq*s_MakWTz#|`Fv@yUtpVW`i>Tu$Qi2aihQ39Re3l*H6;Sp~NmZVlX8 zxOFj{b}bzF>)}e_%HSS~;Tj%_QNIC>7Zv`yp0U-#HF4F${T0=rUOevOaX$t34!Bn` zzL(+kAH@vEH^Vj4@Z1T{9jg@$kHqi|56AfCIEzOhlds>hK4$Zq$~qH|iUNC{op1Jh zHj)NBEdD<{l>7zSgUZkdJZA^|!lQiaTJWeWzCB>$IgH02aUPqYAUE#|j2Q`g6liS5 z+AZ-L0X(9d%P4TF&>lSU8;?BnE4H4dK2K}9Lddwa*o#wK6o=yh$lg`lgmm=J#$$XH zJv%CMsE}^Oko5q=9BI%m*x5+P|77Km7Fwgz`yYWfJf`q&sYG9-HD@~F^~rxA&ycm0 zedmJjtj+GR%0)g#val_zr@(q=~ z;4LwLx5NP65`znz8cqcV-IoF7Fd**+2RP)}pn&7yxN6l{$cA{sqyUUT%pH@$3geHY zW8WO^s(We+_JaBO5&AJp4wE+AUn=J3D{y9*@Gbw8 z_%p09KgSVgUznedh=aod+p^*x_Ax&-6i&vr?6#BE`@NdHUqj`!sF#UyTDF*<6%b~KV4(FJLadWFa83UpK-_& z%?C7JJ`ZlS%Zd5<&ct`pPt4CQtmjD=Lzo{|IbW8TpC8`8{FtA2k;k8d`8jBZFQ7k| zpLbUEjjh;k$rbQBz*a;xZTR}cyE6D#}!d6gux9+}b09!GDt+*`M z3VU-DbR>f>F1s1J{hOfMzY)6qY0&LYt?J00QU%PHNOlqBC0*DG+y52m`c3+2t9hyq z{d64m$h6LE`Y+Q@f78-`{qzAF?vvj1)7PVpdz9D7`sqWqyeB68w2Aiw`f1BH=&yeI z#qWF2PeT^?bM@03QBVERPd^OVycO?B5BljVm0WpcN9P2J^Bm+(CjImf$WeRKPy66~ zZ~EzOyeBp~>Rr3->!|0Ty-d6(4oJgNM{V2gBu6HhbZ0+w)NicpLq~m21=CSm^#!J* zj;#9{YlC*21#%8Jr#4_lfM+t2?!u~1K;9j`C(>F^{kf#4mh_Nx7N(yu4DDjYdm`h# zY0Q#MmRV1o8f4Z}_lx(0^so5le@0JT6vWN~A>Na-DErR2LF_D$mop{allmISY7*`6 zp2+polb$*_Yg&*Lmq;G`|i0y%@dZ~0S!qA&E+!CAR^Z<1U&^P0R|l1(doTT&rc zZin2Pai0uTLgx$|GvusVjeKtDp994P;y%INJO#SyV$9Pi&@n)N!!TJ4%kYJ)tNyG@ zR~?Fe+laUr_sJZt9Wpw`eL_CzsmUkq6Y?$f)O1hWC*)h|sp-C(p8A9XI3JYYK2ZRx zCUc+6p|d~+cuxlO)FDYd@}B%2_0$^!#d8=hz8GgFJ@pgd*djeO^wUhAM>(9g8m<09pk_y-3{0IV;si8?n!hO2>lmn-^z5-|BM#bIzz9yVuIKRUJ}yp483!V zxV{ZG6d0QUsbj>o-b%6254>j3(GmuecunfC&mNEe)agRP(}arc@T0c`iRUptXb@)` z?%Obbk$k`ieRnf--RDF3s%FSnA%|;kQL2q+F}E~Azk5ufYB2;s_YM8-9_V=|hiO`y zXCh1@*WLhLmEHc_tjRCF6#U360j7tOiz9u0$a z9b6PYnsXR5Mmx)W5bxtLra{47tVe#hlpt{gbZjY^6VB7Q9!H^f-lcG0x@fk(43fB3 zCZb&Dkk91>>F3WX1C2rXTr04+I8V?I=N|?dGw^%@?`tGIaZr&o*O4w~(O%5Y!>qYh z_M=^17;*3^oGBPlrigR_Zq*f-RdEh4*{g&vyY~FLkONP(AZ<&om16}Q(=(FJKdT_~ ze1%fooW)l>wVV$;xV+%n^DGXet;HN|3Nydpf%ApDy7^mW*;CLt9?U9;Foz@kJ7LHu zzgpOLP5CeGnqTdHA0 z1ACK%`OCudrsFwXPtS_X%YuDVVY_6z13a#%B6}yKnF^gEYd7di8!-=W3-Q{h=5_5& zXg`%!7u|^V12(qL_InjLK+=V=wZ)bDpNd$Pem?TbgHL7f>V$A!_h^Ln;8Wq+{ZHM@ zs}DkNc+k{Fn+fwQ_kk^lgTAM-8W(wOyxBKCI@0Tk!A-+-(OJGXM$U zqD$RfBNERlqQAwrWmt=>hh8(mUl*OoY<5b$4*=imdIieK>~>s?h0yUfA}zv=u>Lh# z(^_=Cb5;X*fT&-e#rQf0KA7g2I`nUF!$6lDw$N+ix{#v*?#Ppb>sZ2Y6WKXlz;!IK z!gYAs;5r8Ng6p7oRrp>t{3ye99NdHcsg`gZlwLE&Y68}CR1c?+zaV~47q$awm*HE& zcDVlxYzMQyMES@TiONd24-MvzVe#&`ceU@L6N?aah90BRXN)cyY*a~;z1F^smjQG$# zwn9naWDEgkC#{9OrqzY5h%m+93%26!e#Yg8xNNZ%p99}us*|I*-jB7kEw*B6uklOR ziuVaKVNoyjkeg9jw%CeyD4bj`Z{nKPn3m_mgdr^xwqiK0?O`iy=e+)4E53Npjy@LH z3akIQ4YtC%Z(3t3zCwJK*or%VC80IyuY#>W8@Z~v!EW5@ubh&A2kmQV(TbV>hj2oZjt? zp*qM)HH;gDb9AiMjom$o8)ukA+$fx*l5wN(yaVG#;T(C!jl%N^#*Ko$U(LlTMgBh6 zgCaj{&x`nuUgrZ@xsUN~;%w{bd>HJW-R7U_}VBpaU^l1Ttjw&@-w_MeK%6(NZ}3Oxj;T??m=D| zKg#pF`iYfr(J_vWGf1!eI`A1$`cbgkv&|!9u7i<3n$M~%&xS$x@Mt$t3yz%P%*L45 zK&?I)Hk(XN&Eq^i%r}i_6T;i0KWw+$gZ1lt7~}(OjXhcye@aKT#GjJM`pTQoU-Hmn zDxl9)La*rn`)|jp&iEm9r=b@iUFBKG8Zh^4H}AvVSG2b&72&m6=b@vKV|R#o$XR246}s564xvA^j+XsZ}Fgc}6s0Vmtgr-4T* zPU1{aU>rSywxV+Eci{%RT5zCzo0$;>IafqWW_T3E*N};Fz@Z-r!GXbgsT`iHA4%oV zj+V=DFd;VKVB*D_s4NNn=1AG=CUK-F0&@5Z=$r4yb?cYX+F?kqIP?#e_Y23<)#rX6 zIGznz{McUu$HO>MfM?kt<9Pn3I8vzGTT{jk;CKdbJeLc{W9HJB1CEYZ!WZ-d$Mfv6 zE*#IfJKn*+k;lJL0h~{$6<>$tf4M2!p`Gjnn}WFL<7wVlyQqvKv35Bd#EF%Vhd1Dv z!T=sH%zxXQJVk@kRIH~Qs|{C6>#KhAZXiB0@5WQuyPUxJLD^Hf&BcVFVOWZlp_q^3 zP=;9i=W7@jNhZo?yH=#KS>Thp=3kUcHE(tDZQ##1hceW|nYc6Vg?%>r*8-aq&Ih|j ztWeF2)T(B-pbm&TBSU+0La@7o5DSNT5hI{Kcou7&_~%q(?tRWPJMB5oF>%kSvZvxY z4%Z6&gB=5h3(CMy!6EQUVIRW2kFfv7`;&OT4`J(Yy${zT0!Ikr0>=p>14jyD1IG#u z!=4jP1a1+A58Ep2C0;|#R3S|>MPTa$@MlQt1JBlmAMx)(UQ~{kuMLdH?Y9Be!xnAO zeI2G^?O=Z$rv6^y+Q6QAyIDrg&TzT{>oeY156n^9Or6*^>dyxHb+WeuiU0J=oG=4*JhO%;zRX;c}4f{AJj8`Sr=nCMNtT0SneW7NW7+&Pmg<+ySRw}#CZ^Qne zZ8kUY!1$AN=CSPEf&Y|o_=Q=SA(~-<2=TpJ8@#354m!r9z zq<`OK$+aQZQ%@MC9=SHKhun!aG~nE(^=Lyg&&FUK+j}wWl8I*n?XCTTLfQkvzYlU0 zvOP)3T%0$RuuGXTzpVW2X@t*3{_Ej$DNbUnvNHKhzB9x8FY(YZ?tuL$MB>K5EOm(FFd0Mmo<4dfR4T4+hS1`hA?`^ceoXUkAP{(&Nl-KoJ z@jo6peQ?EoTy_qgH{jZN$~OIA ze6O6cOV5FKqy*1*gL|X~+#`wZy1MDSrt}uxzcd#dB!p=?85kot4|`tN8u&codPx{D z>@R}A2b3nMb#=G$LrZ7yfu%a$yYxM*4PqU2bz8%<9`kt4eU&5Up2&|ye8F{bkoPj~ z4K?RZyvXk08;wI*icyC5+&OoW(WDHklz4FP{Wo5myWg zIIjx#T^9$no@nlzMdNKZ##;m2eZXPtwit8t|7!yO1;dRPRwwTyED+=nJ#lU{0Lw&} zRf_X0#^_Fr)wdO%BH?$=<6e{I#P~J}fIs>X9M>H)RaMt214_3=3@JVKlXMklPF~ zV=rEaP?eV98^T^J=nZ>;^mx=6$>S-_AU?p%t3i0MO-fI3865Fy!~%mt|Fw>pH&vBm z&f4UP`hhEqQ?@polj@PlJ&_k5$S===N25sLT}rqnlEI9|yhm&4osfa#qK*rTr?Irn zcKJ2Z+%K;MtnAxpEzo&l8f0-!SO@fumng}z<;Lie!;y?KHS+<+XYt;bG}p^=Hq6)5 zcWl@AJ?R+KIIjn5i7vZ2k_p#1NO}k03wbzaYTV7+%LF3)*A?pO<4 zj`MmZzHa}#o?BrPXnS7I&9DQcbvKn^veK7vXVAL&0@i@L6oD-U^i}Ab4lgcPl9wX$ zX2jr|f%AGU-+4Wd8CcB^u{1wm9>f^zb)T?eY0rAY9x*1|plXiufCG;Q2ObX&JRTf) zJUH-paNzOaz~jMz$Abfp2L~Px4m=(lcsw}pcyL^`C2vQ71#ibz*uE2PWG8gWugbg~ z#BcstCb-RE8y~BLeLUWouqC%)-rt>heIDce!29R%j<6-fxl*Wvt^@xK#@peFbt`1) zz44fkydgY2{k%Fo>^%LagPoJAo8errj!bA6`@6xGI5tSwl12|;+CE{} zl5V^mwDvV&OW3s~wgfn2h9k*=Z{qC`AU)z4=#Kirmb^~b z2n!6wBd{LcGCL1*R&`OiMQi1Q~bSPOZN3M zE(7AS#g>#HZ>Bma!u5Xib6af5-+GN7GDzfg5tY}XUT&7tvc;C9Q#iR^=HZ(D6PDN# z5owvQB@g4e2W*MeT&JbEt`FXh_y>B#mUOLIx?@YsYnDc5Yi!Alh|dyRvKv?$nnV6e zuq9UY$5Z|F!r5_VNzea?Ua%!yb@yM2E%AQu=V42t&^IixC5L5B4ohrF$Gg7|Y>6lG zdO5HqRW`P^Y)tlnExCvFtM1s6?Ur`7HrSGFcxT>60EYlv$7REoBqKjGAHkNuj4jzm z++e=|w&WYaia-w4Uu?++nTvz4C1J>?CAP$qWXl{k_<)P*3VVK6c4p8eU`yUX{%Ah?x!4lh{_vk-OO7n=TfcAFH=v7YS1An1Yq`orYRFA* zhQA*Fwg~twN-knPU+`$zipq^ySGXP=&8FLp&YilYXE4 z|0SLdD(}|aR}bj-2lV@wMZXWD{eS((wTLU%p*G_*%gdr^}f+-j|1sRuW4dO#0u*@$??;H&Ie263`W*FEF(wP(8 zI6Z81;Rj!|uM5vadzm;r29X@|8eoQHUAS%Ar<&S+X5YH-cNg`c3;(mE3%BYEqzhMi z*L^*RYd>p;)5EGyKu#addt2+n8zg=B8LTDCzaV|MpYa;BixsDbLcwJ0G{(s;$gB^? zwPa77nb`xU2iED- zhLzBV?}Oah%;#a!hht2i{wLZPj^VUFll9^7pCv92v@hwy^Lx^VBmed2CtSUx4C(T6i`57LLXK_7k^<;z9+ z+D|CKZ=e9b2hO5$HB4$A=~C55`tT%O`+zQdKo{PBUAW(Gt_x4ac-sQ|WLsT$^T>oM zlP){~xIv~1KM{|9A7{bq5sUu6dlKI$aljK!z8&K;`UK|mH0Wf4XcBZfg2 zeEP&RG55F&!{K+}dK1F2c^~7N_>T`jSKjnjb=4VgbP(r#;~gCM3b^)WU|bq8wrl8_O6J7#ZO}0vg`T)m#-_2gA^74a^ISWf zn|cA*(52wfAP)U5ehq)%xcnHu#p;u{EN@3;~6!glkLHZk8 zehpJw4EhlJd47;F65JZ4;LFGYw+6T}>b^xiR2O9C>9gkN)$;BMg}hr!Ex0vsu3AEM zK}6mHJg4ggS)*{~EzYa8!>thuSw6{FCPoe^t-o3+eg_!~>7A&~!@-fU{!%zH@clpW zJ(IyG0vK-x@l{*^H%k*ZSHdFIrETDDnS9Z|H3a9As6)R9Xo*ayBJK(aJMlo&m`K7- zJkTq4Vr8a;ohZue3p?=uuoGV}{)zxr2|MwCbS4ST z#O?7+k{+-VboOu~_$t)ER5ae9YgYkR(G==ZRgS(q2RMpm;H`*5hw3Lmi!k8xP^ony zY@pi9U354<3TKmiV}YkY{urKu)~ptIiZ2%S15bf<8sRCho;+k}`$X$WhNn={S-idD zDaIn59`_Z%L0}!(#Xn(#gTT7+kXe2?fP=8YLA(n7rOSnb_yGO-a^N7&Vz0uva}zG$ z?2xt8kFnNEDOjH8WCsV~3>&{o#X($v9&-Q(artl%w&OaM#x>@&zHkuNXZJj&e{CE@ z8tl~RUz3ZzF~0{K#C*In;UK)x*DY}n^YHE$#zBB%d>gkDM6Yvn> ze7LB(lB)^}#(9>(Tt4;?oZAP!(MxpI1sod~BcjDWr3- zi09YRCdkrOmg4;OQ>Su{r#O8Pr;qVCi?_@EMvB}1JKuh$aiotloINT3_S3iqX|T1? z&5tIpbEsStq2fg7KengbRx_yqTzPao_s*J0i4Ak|rccmCWyQKhjB-qLS%C9=Bh`s6 zWxTs9>`q`l|AJgZNGzp`YDJ}oTOLzy1dVZ!DR)`IGc(uC|}d+^;g zlgQVm)=X+T&0RegX#%gaJ$_!zB=V%P$d`B6P&iI)HU#vs1EzJ?PY|HO&e;D*uK{YOq5ioUx1wm&8R@wT0de0>ecwEhG~ z;2ZS53E0u_aF^01a0Z?Rm&6&YaT`bK-q=R{3~|L>!40k%#tnABxoUL37uWH4M)I^} z4$w6s{^NMgPc|f%Al*iA#tj)hr1UtR(;kCtu9bLqJ#^JU9m*V)12>E25DlKG3g6zS zx|n)I<*0J?SE{m7FsI_*8ljGj{-7D(CuU?sCHiu7##`NFUe!XlsYa~t3CBw9qr?7& zrHwMpL)uYF--zAQCYGiu{Sqnt6TlH)fpq;iKUeH+a#jMXh3}HDg(Gg!SI#?6r27cC zCO_R9H@7)Yq%z)4Ij`wA&5zo}kIzYm9h`f9a31G?{=m7k9LIgu z3Wu3lUTzVE@_Sc{_s`;eq(A2s?#_7?^2)4mx&PQZD_y<5nAVV8_F2w!KAe}?jt+fk zyJ-#CIMSsZxMFc^$}*{-}e^#hj=>e|iiuW2z&PXHpw$I-Mup#J&w?;b|YE zu?WA$9DWGGYm9yfPwA`!pEO~m*1$gt+|W7XNx~0}6_4Y+$liO3r$|Q4@Is#Kc`5Nw z;~pG`GTw-u2aC_i;h%!vfbVIZ{Uf_Zy`T@>iR(txgKD^&$hCeP!>;GKi9D`ToHW&q zBNOcRBYcCpM_;mk{`ytuM|RtA-^%W7SQBMsTSaGzTeYR%Anf;}#0FsGCL+I;PJe*? z{+dY*Yt~GvSAx3)$VG`Ec=qK_Qad&&!^8<_KPij~e4#3EEBLW? zq&B4ghZgZb#(;LDcClzjd`sd0g>raP+#_*M-%_7ghU*lC3k!P_?3Nn+l6vj~ zHBmkGffwdmW39L@>XpIb<18O4u?XqiiL|70dK=$i&x6JHm{0Xd`3@HAK}(Q6mH^roSPSs5ysBt3@UPC zSl5(ds#hPQ;$B1Y6Gxm-H~wrcai(_g8SrTK>!8{lX@T7h(S7gM>tS-SbShinYt30H_PurGZ9&*-`a;i$Z{ z_6fzDC4C25iWEa~7Q)cHLF1m%QR2HV@QluWwf#Rd$TrLumn9t#@)zk}PxbeA zggZ|0qfSia-bCeozx#iY$A6L9u`}KSeWgoZdVY??-*O?#{#-_79*^&QJ+UT%-R9A~ z*Wy26Nd9d0nY?y|uj>V+Uql<`ko1DKJZ^<%DB0Jh7Zl{Fc`h*nXRWJv&NaQ@x;&Bt z5nt{crGLv7V6$OQ<3<1b8vF~lJ;=}8<-z69S#e>w?`gj6X}v{xJcIK^Z$rK;@_0DU z$+z@#D^sUm`Shn#rI_l3eEyPSBIZ(6sIu4lq4hUE0jGpGySp>C9h$sS7~@$dA8 zL$}@oD6!6y`W^L!Fo)gwH^T+5Pz^nYF~3`ZGhvr|4?QhkZ&U2fUk69;zsIxv;E$)e z-;Z$Yos;zLB!zdvGu)fPAE)q6a(KM6ol8_GS9oPnaxi#r)aU+`oPqPvwOBuABt4d_ z<~A=1!L=H;{GkqeV(#6RB9wqbXJtv60DJsFu*XlD3Olz|<(q{m@b87c(&5VN=ipXq z;)OKWyJg1k9$7I;j|4B*hzOpG&Wv%yy|Z-hNcU>oyGr+Jx_8I@AnD$ni&l9NW?#YV z@Xh-I>_H-sXIJ3AMy01mmAP|+%dT=6T84GnsD_|C_6*nNXHz+ehYj%*p}ko=h$9@% z1${pfagAy?mbYNibQf?lyI#fb&eu=6#RaltSGR_ssJ|@;ocW=4dW2hRP}B>E*KGn9 z6^?v?SDM)(P<&xnFRJDETyc)F8?OT&vgVpdjaN^dgc?)G)7nFrE6~OyW2LnlaR!rJ9kA~yq3J`aP`pYoWPmY+7AM-my2-2bK)s3 z)FNK&2Wa1<)ycAaxh$PE%DOX2?)ZOrRGmOSKW=Y+y&wB0%!}uL-A`%R`Hx6x zB_J*QKWe12da96C*MFBYzJPgM(*K^x^F*AMb3rQV#qytO`JL$-Wgp+X{Zpr3&vRne zKbiDUkb7)U?YUMQ$}7ZI6#=DBz~#Z^kK7IWzafw-_@NCn#uJ#!ze2vTE=*KnKHLqQ zM+2O~n-f37^Vw*FIk2y3VDog(X9HW$Wt@@Cja6N9<9pciS=L7^s}Jin44Ze-)AJJG zz(4K^`yy^y>RcwMSrkDG1Ju({QEwbf1ne=zPhyt93vQaY#+S;g7ZWw zyKT8l`FBD7BRO64C?P}VrCAB$+M z2w4!;$W}HXMQk38$GVtjb7*b`=FlGE*2!_7K-^S^p@{d#L;Z{QZp1s6=U%}$PgeWr zq9Wih&J%Ffc|@E8c>sw@a;tB1>a9rEm+L$&M)^+2#;Zo2rfA`Jp}GbxDjwS!6m>=hZEp}UrE=` zeI-->+$;0-|M!Ysuica(q;1L)wr*M=oZOTx@a2p3@o=l)-iPBCS4>yJIl?)^!LGdS zbVujT(=&C*S1j@shkV5&UsI5;smRwf!t;r@$~NrItssEUO#)yGU4txU3MXy|1%l*_Cfvi&twTN z<9p9n(-Fsm!njv6_3t1ae}uUn?w)7vM|=f{?|xw%i|;kpM!LhU!9A5J&5?`>X#wiKO)=; zxM6rd8O{^W$H5K5v&nFtHL*$K;F94yNBAb?(mniSIL+fJ`ds+Y@Mpsqsbx#sjQGj2?M;r2@1>vz=aUhlw~ zo%IO=)`#dHN&}BMMIkyG6rvNS6rBw?lMMYuZEyfS)lqacI6`meB)S`%L=Vnc9At17 z4I|M9(Efi$KX?PqVX^9Q~Ztx%#qI3xwKL*@EZl93gpiuJF*xnMvg(^YkyS%uV{FCB`d zt1|SbOLLR%Se2#UbR<5hq-37(&XKgFeI@q`U;Q&aNwq3N==^6|Qo^b%;h}h4_KR?J zaHru`6(=WcTBX-NU%V*k9i)3;eR9&U)r<5k>lY4lw#=O$GnA4k84 zOY&U3NND?FZqhj9XBGOw^Kb{?THqcooq_z_r+*RtPUP=!X%6z2iTvdxO{Dz&GZy)~ zPk0CZR+hh1f#y5-$LYX2J)AqKUkcT^wlcl4}Rw=%3mz< zw-EV@MgDSxqlZ(IYF8nD@K3GE6;{jnJ1FOGL+L`~FI~R_{?3vNsCM*WmAje-y6d@jQJS{H^dmg!>MzewdrEsbs$XostFm zuS)d#&XR0>Ny&U+YsmuW_w>Tal5C-D<-#N%)KNA338mz#WD=4Of0RC21$zQMfj^4JgkJ zxWjO#;dWCV52Yl%1NRkNC!9}RO40lNAHwa$sBzjLTle<#3G6X>j+$t%a+CI|$bT=eC5#8;vy@XEerWe9_pV zaRv7a>=Ecce>wl{|LH&dZOm^M;cmcOS_oH-`S29nILxKFaBs)zvM<8jfVq^`gw-X> z_2meEs$_-!6Zqp+J*Xdo?{Zfa>hFNRwPd+ahVM_7tPpD9hp&22@I*XWs|tl=_~nS} z6SyIW>khcGlEwO%b+;zfmMqb)fbY5L0sRf@7bYdITB)D%|J)KG3%+XA z1H!m3=pV6E$b}z+xK>!?uL}9|K|C$U-)-=BQ2r3lY04jb%AX4HQ2r9&S5y8F&ne0u zd>_Phn??TCB7Yr*8A%5ze?>V-8<4-B*3C#d%<`AR@^|u3tdzgHRQ&HB5Kes_i~l_3 zFEyz{C*|)a#7Xt{Jo5Js#22{=`9pj!B7a8_-!-c#e>p6F`w(CFD&!CGQT}QX-?-J3 zztp6EAU?|9Q8=o<)yUu5fEu{0TB5&bSd{cI)!(}0q`|9Ef9n>p{B1oHhk9EgoIEs_ z4OOMY&08f=_!K+8+k4S*TxBF;BQ>O^*I_#r=Y2%|c<> zYxhDF97jfU6CO?gZOeQvRHi4 zuaUeX2k~a=uSU3BIDf>qy<&lI7vgKJ$VRwDD8qcDn~QYy`t1nQ3imYPJBGM6Azxo1 z4ojH?$sRPEGbJ?K;CF@gM1J! z>dIr&W8iLun+4~vI!_qBI$xN!xgB?Y)hmRgHPWkeL|9i^YDPVEOKpsr_qr8!Rpr3WBN1f_Xr+U<>9(Afmo$67ideo`@H?Gs) zG;h7tDfGVPetIwZ!(zCxaMU+SN)|%alq1~w+_CBVN)|!hlq)3Tx*Yv?C;IOnaD5bg zxD9=HHm*(KO<_&pOkp;lFYkam40jri=IB48|I!@&27H>MzkpA3^pEfzxEHnvQ{nD&@W{RqZXd2s!fgm1G5V$8 zk)szoxMkl4S3XQD?1W2maKV{iF4auMI!1blxQbp528Y#g}@y1re|_3eVLZ`T6oSB**~^mC&y|G}x? z+~7RneBd<8b<_RB9BZ!|+ zXKH7uHq{p2wyE}or=PA}aQw;I(;-jSw%z?q?IYz+);fIfWbNx0HrDzMf4WvBY^>eB z@R{0q8=kI>|J&2GSMS?YoAdd`+Lp#mwKtx9rnb3rW34|pzOPe-*2cMAS)1k=TwB6v zYlDN{5MqPg6yDH`toXmQ5I4TOA!y zTN@r(8-aI;c-I~~t~OxW)wSaiuBlBH#?Twt_54Lak{bDcYJ2Az=`h5a6!3eFAA6V3-tvz(j${p3CK zzn!>ee)E_;^BYI*nNRKXH8?^{7$zQe4m@lhdcx(LQ#t_GC!MiDxJ5cog)@Ld*8mP( z12}XI;LtUIL)QQfT?06D4dBow^z}Fs z?{EatC4Zs}6PHr(R!nrLgw-NkkpSGoQANN9$AG1L7Jd6z9M_tr;K2ac>!srmqG z1Rsj$05EOwz_?oHr%}!iYQ#iWyHr-)3rC!oyJ=p9PNQGuVhp?d)&FoKmNINH;yy zYwrtl^WGKijd~YnAXN%Af2)|j8BS_LO-l{xF{R*q43BdOcdzC;Hp7)W0kg>PUH0uB ztopkb@N&Seu=3#gBV60!6gz8N8TYRVuejF24!UtE-+og^{E_h0MTavqfB9iu>SsTw zS2z4HWW|AveyAV9>Cl)u&c>L7@oS}{F&zB~XIcZVBiYy;2Y!v}@^5&)|3SZv;5=+e zLH{bpc?Y?0=hDEj0=MT`g-G9#y#$4S7U5anL6`{OFW2Mz#qiB>(HZhNjJx8(TEc)M zXuR{q;h}1{D|s`J4$zY$YuAC%AE_Jl|96w?D!_lUfH#F%6>;rWp}Y# z_H>lJr@61QW=P%fq1+qwYq%=Ht6KGgPZjN9XqS#7PGTTD9PrI>IA@GediO4#zbC&_;CU$A6To5DzvY4Rf1O0&l*GAs z7L4-44yb)d_>j^Dydw-G*@?7aPW}uSEeZ=;6C>H6wBs3J)zi@ClRK3;YaO{+0kDm` zsqkg9ZQNb3joZy^;{sqCcl`&=h_eN8Oox5k0=Vh0ky~J4Cr9|jM&(emom>;b2ZNKO z2=;Q6N9v<(Xzv2053`rstbn~7!kkbB7-#&@`2^X^aW_VnZdUjw9;b5Qc_NiHQ3?69*7IpFx!v?2VoZ>-%Ivs8fGIh>V2p3w$LcpP(;agYj}?G z+>iD<9|}7sI35_iXYs#N;`xp1LC=vfY)oef1fC~t_9Y*4<& zJ-z!9@9JUSWP1J_`V>9?l%69@1M)^#e0opw*!Htz10vZbRpXl3s15hAuvhc3uvbg8 z-+rjS&Uk-}OZ)S75!$aK`z@T$%fs$P0qn98m}rM8wNr_8`?=Ej9b7kiHLG^?^EBJ5 z#bA6fdo|_SNe#|x&Gu>|@cbO|bW{;6+oJ`G7_;WS-G+B7M!z=P4H9`V88%9BqoWJ+u>TdLHjI=qFMbjBng) z5tiaSf%g0fb^r?`Xp=p!iiJ@PZcY?4jeO}IDNupK-@*i*@d?TORqGk&+) z?-!_Zv}d<|(UJWgJG=46d+hwL;>ljI%kIgl?VX)r*CmawW5@%Ir_IR6v&aLp<3ydl zM)^jVVeoC+qAe8t0glFiss5iqUDx9bkv$5jovGfQq-U@XW#JJ1>rk>6_BFo8o^#^; zEDf|Jo)cDH8cW{BBUBg8H+HKF_Ro$dTfXl9>^D&dw%FwNF#po}pg%Tq2jAK>YnwT%^2s)H_aZ<2wVC@X@+y_D%Vw??ZA0x&m~FBF{2u-A z9RAamHgogXch)v@tq5mpGxssVkb?8(+qCoGG85?~ zBQGG3(jDVV)?$+=KXh8?6%1VRdU&)*@EcX|OGlF!+yB zohlVb%h@`uiQpt648EM!*GTId!ucZ&+A9o48eftP)5M-o7 z(Ksjik8a6B8?o;vTT_zPusC58$Lwcd8<;ixU_chnd1t{!z%?%-4>o(^9N4ar4FTD% zaXQI%&14tY)pw-6@u|6QblI>RroJJ!7jaFH{D9`r_2~a5e(7ek9oZ=AU{~3U`i&L$ zP9i@cHC${#eqpOn8iI09jZzBJ@|1!j%IpMpf0TnTH_t&hfilOzJr@-(Y{`ok-iwM8 z_U6S2PUG*@JC9G(dyb!{_ZmM}Z<1AdLM}NDZr|%U!U1l?uo1BP+4qNFk9|>NM}LU> z|HJc-;Qz(qc`fdp-pmm`ruP=l58-|Up4XAD=!$1A?x)?^6m#R9-^JW|=c$+(ceciq za85!R=PYdHJcT&UOHeN_JmQd16{F_dTu1R9uHh>Rk0^1!4!$G#yr*k0uVBv=xX(Zv z7QW-uiuq|)kU^Of+SWM>ZI|pC4BJlBp8+;qXurg7QFle*Q!m0lRE9eIE|e2TqYn4R z>fBI=9;ibP)ZrM^;TY7R2kOuRbvOofI0kj-fjaa+9eSV+Jy3_EQHP^Zhoe!4qfv(* zkoS6^4n0tZ9;ibPs+)Zlb;9Zh*lEb4^n2zBVe>W1s8s~S8<9eTVAf3?N)HFxSe zHr%CS&8XY&asO<_=#DwOYu2-oY})j^%w!!AaTAlV(-di<5Po6 zTTpNF^E2|?^275A;YMK$RPZh>^u0UkvkB)g?z*UKJptJf&H!`m&)hQikIv;6m+h+J zJPgUVW1V48a<6Rjz|F_54^j8n!JhJ9-`WxRr z&Za`d*&An*6t{gor5E~{#(jOHfqF&$?Wb`NX>9+lXZukThf%#VxbH0g*)o68eKk(y zBy0W=96o_)vjWI$X3N|~-gw>!*^GL(Avr8my%9V{?UsB+Awk^WG{|U7d_{9{9g1hf zSCj-9h9zIoACQj3SLEG|uV~QsolkV}wqW!uBN03!}jU3#54*S2OA=qcbH*o}cVGNq?X-{tA2s*UaB!|Ji z%JiHwBtL+E9C#maE-WYRfjs3n+Kl?vr`UH9PXc7FVkhc={+VQto{n$YLdS~42UHLK z1^R~gWIjN63QK%IyA&E`A5LrgGLq3D{CfB#86>!5Kp0`nv2?W=oi}D*#?rMu_S1krjAR;U3+%w zY)2(#vwMv=N)9&y_a^yC9`c-`7=*Yy#T#kA<@bkf?M-_?c0O7S$xph=4PKaSy=GQ( zOcvVJ&X9##+5p!p!^DTFu8_APqXx)SMQUMx2xKemTt8^f8L zR!RRHw6|$5MRE7W2V^xD*~m8j{jRlaBOmFQWgAF$3GQuW8{6>AR<QQnrEeyoPqRl5ODGX!e~K`p|GQAJCf! zcN}rkeu~Gwk9d&&Oy$0x$@{JTKV7m7;ymu&ug~3SU)E21x$$U!;savxa>b}#`G69U zr{9tf2zlIoRLWzod_ZByXHR@U0eE*g_<&TD#wG9p^~76(G1X~MXM+=2dsLGD;fLWgITTbRm&`iuboK_oan611)nS%_y8I6kuciSNT<=2hVM zDDxt|52u-|vh zX`l2m+6Ov!{MVgC@C(^JN4~E(US)AOAr7qXdWgfazb;Zn9 zpU;o;d$e&L;NckH;TYiI7~tU;;Gr4dp&=fc-{U`OfQMtDFu=pnKc3eC9*zMXjsYHy zKDkYPQ?83XxJ`c3ybbVhba90Iw{VKsZH_!Ri@HpSQhehY9= z{Qt&pVQO0mL-F6mZ;}3A$ZwHx3H%nPlI-9jYpnS#tm@!*&TnDA?DqLBwxjGl;oUlG z{OXS1h;yGu(mBnX(W(yGfDKLKMa^qY<$=KDWGI5gbVZohI8s@aq431D2GE0!SIm;_E9k7~3Rf=YR>Y$kToHhCk=tATs;j!$Yu!`L-n#Zo zuk}xj!8_N%j|6<{y&>Q`uZn;QZw@v-YXiOy(zPGp*FE+9P+j{$e*IG|d}+Y9d|80I z;-P>FCBi5XCQ{da6k(cRk1-Kpnv|shUn|Sl`)~M%0-A5sy>XDvo?eNwJV)xoaG0Js;F%+AVO7R&@UD*V*KYx9eZ(0Y96aOTAbyJmJR|OntHHBz9(6|V>5RJ3 zGVewZI4n%O8`~UByc@5WZ9HaL@oroL-i<-v-Ei)McLV2*%Jv>j2v58lP54F&pYlf7 z`9sKC0ki#x!dcZCaBmEP?RkK4QA6hw8cyR{KP?*1iF*U(!SnfePTU)mU!}~wQ3KrG zT361iVkno>fqF>$0k|*p0jje&q(NK;k9`AdFVz9ualE55x;MTG%r4r%+fgS<_2X@9 zM*Wek%UYbxeFpX9i*QTPC+(10h!KiH7G?ZMZ~_41~|bXK=7_(-l}^;?}G%LC#oKpt+xIo~PM#+Pc9K63eejaQ?bKAewh1^7_t%u6ayF6Fl^uHAMVF&mc} zKj4ddJ}2&9f_z7s1oplyG)An%SZ#n$?@U}2unB`r z3T!m+j-IbXT+hL6qvwdLiTN>%??VIJCh?0L#oFbl;u=x<&s{GDD>bEL-$GnQC(!?c z!3m)O9|d9cf|PCyqsQ!TfbHKI;v=39y;6?jdgR9qHZM5ON$FQgHUPvkBI0{Gf4L3c zcbe^Efayox$)13|AEObt`$tLFcnfBY6*~DCd zwzkhbG8gS^mwV*C)z|)%2wUo|3Jtvb<493_nz%HhU>|$zQ7xR9X zU5sNZ>?@Er4(HI2U5u7qQRj zM>ZD}AGKix+M^Ae7=#_|R7ib*?0L?hJmq-a1{)YD4)g(}p+y=dyP2OkC z582s}y%gC>5&pCWX{T}5%VkI3wf!EpCp+*R+1^N8E1u$CSlP(-W~?}!T~obCyd zZ?da-7B<}`yPBNi=u=PJNqxr3{(#L5Xphbsw{CsLWJmSMEj{#^xy96HtZZyL;zU+If$|u|R z+=c%{f9-pgBVV@mJ%2}eBs&dom%x^1*NN`-J=e1DtnGXDBAl&#PbHNb_C2=c?#sUC zr|HBe(Kla+Rr%Lg^Mx$6;0r0U;0swN^M%;vX%B3zE-vfN7xGWaOO5?Adacq&|Dw9& zVSDsP)P>2`Wr55WVw;{lTbJEPYcAG)xo|guC!`f_qYYn($)4aG+WAuK30isyZ;j9I zZa48IzNLAd((B3Q!NfIURVSCgHS(~`HDX&&MXX)AxJH(;z9DgqSf$kuu8{(nYs7vU zU0fsgAPws};f(*l+*w|Hz4T9e)D8a@>0da$7p{?`=eu)_AfA7h4|eYs&(>bJMzr7> zvCfa3HiGR$F6>&EEeGr-V(r;YD5ZL{1~@-{2It3z zs6(0aV?!D0aDemU*W>)?YmCoJ?Be{mbEm}lu@-$@_02@F3hid%{MZ(3=KR>eIhr{? zHgIYS&JS&b#P2aKvWxR$2Cj+oW6vmS&X0yseR6(0f&ZpG&JV{y-8nyA>L(vZG2-lv z^FxZe%NEPhMtgfd)5z!}jZl_<`)Sl7jUHuJN_E}wk>F+p--p$lFY|q5z9jK|Tmat( z$)A=(_V7m=z7N$^{-u|~^)U;w1WT@uyOBmuTpvDP+T;3o+br++Ib0t)3$BkFkhY2I zBh`ZI%9)`kK?tL za*(d|_sGEZbJ$ZI4G9+O;d8;kOb#*xW6yNY_P}_qfPMHUJ4|wrU}L0!emupIxNh`Iqc*p)m8U&aC+ZaK zg*NZ9(LFy$veB)+*?JADHZZxw2G0;(JExd@6g(Vtok~v|{*STZ53C%-|1m_2Vb>%_ z@ivZU`5Y_8GoR|0WJ_bkJLG%DcgpHr=Ko;j1OEs50Lft({|By#{{!hF&(=1*wladR zu@9AG1R5I|fkx&48Oz#B@vb5H(d{H77{}%l1^t6C<}G;udgB1W|HO)~;9Mv#l3akt z9CYesYZ*Zv(lN^jknUpK+sX)@$1__QK}e^Ci~!%=hcLD>f=}>FmJwLBb3-p2Amh=- zwqv@pCcugV#HxIEDBJ6|_=^R|kHMv8Qjtdu=93{32gv< zT0$|&;tF&|K~u33Tn9!65f>EESy)swouXB9X}KxIwQibr?=3;fYgw-Mw%%WYEkagi zu6Q&5-{+kfcxPm@?AGu1XFi|vIp;m^S)TKp=bSn3bI$WUD94C?Av|=N)89b4Q&c|W ziTFzxAWu-cCndEi-_(z2Ppk5MaZKyFdD`2uV}S6w%l+Z)Vt^!rrr#3-L_lM^7$7u1 zw1oi@gmC%m*gF@)-6FxAGVk^32E68dq)whJ}>fCasB^xjmB= zo^@Mpp|OZ((L4<`qnrdgT9W<*9Pa^ge^U7SRb z8~_XnUrGAhI2VOZ?x|9V2&=+Pk?Jc-pBE=r`bu(hDF_J&YRj40o+T%_Eh2Sg=m-f*wipt z`rJip{pSJ8Vt_n8cAyvVED(1TF3LAPHW3&W-ynRbsNCNaCSlKpxv+2ZHuz5ub7Q73 zIa4iNk`eKQWqR?Mrye#>&gmw4zVa8M4?H&9J@r*KdTvHolg2W1iBe*q2( zlXIJzaZu#drnKzqFA8u_8Xe?l*7H8OkfVX4AU~twW*fHY=NPsPNJ98I_#{`)BW_l4 zgm+1C1n#Si@cswk-byy7%T{*Fa|6Be__vA7_b509K|*b}j)}e$99+zQFIebORm> z`09wq!egnkmiMG`=wT<)g z82&5lI4`k~KVCO_lQ=KJGUE6$+SjKE$72Owzkg*Q#${*pvi9^r?WFGr=fwkg?bt0= zEEVgzm-gtScqhbp`6t?APbvtyM2cikcdrb{2VQP>+6Vw8B|8>&AX!(Q=HZAJA)4+P-1-U zJ#Y_gp2K{~mg!f*A6!6W9sE?k)|Tp1l(mlU776OQihJ`Y!7O4DpA(d%C{EzrDKlB<7rO`4`h=>q+kH48Mu zOY`*=#}hScOZ05_@#&hXl3e!Tr->S$(gp1Dr_(iqOY>O?WbQ?{cj3;!JzPFsQ&Buy zzZ3rM;yL=`<$0R!B{}-@@VoFUy6`Iw7=Af^g>+#&Zy($T{wUZAkAgo3{v7zL;ID$e z1O5*9@4tWd>VWmajhsKelWE+l2RpW%=xL z_#15BhoNQj^$WJlVh@$&>CbPO!<1$7S>c|U`i!zXc74xm{Q_Hg_n^FSNVktKZw_Bx z2GYIBmp5BK&Q@M9%DZDrHrtHy^0(;t^15(kx^QLAK|Y>=Y@CE#Y=Vq^4*Bw_P0$R6 zOM}aY^SQkXSEdVBrVCf*GR8sS{sc|&XH2gyNK2K!o2g9Yo z<->L1%KYEJmEi=xE_|6Te3@T~FZ0Uf{k^;JW&UsC%kX_m=OpW4Z+{WzEk71(OW#o>>da+V;zaSB zzPgnAX&YPx*@oe+>9%a)?f1ixJX2nMBL4q z1ot-15xc;5g?%i=lih#>&m-VQ!qFYQ{2i?K0LumSeStL7QGO`SLRoEhx|i4E9bvjO z;oSOVoE82U_8*iMXZb5HAg&2D*JV{RuFGr9_B;ekO&%h!~pjT7P>@HRk$n{9v~2LctzdFyR?Yf;yiaJ$G30(E^#zAZ1^EiAxG+3?~1 zzJ!;u;qv~07H7N^=75*t&>=B;0b7< zyOG}qEtHSWKfVDhhkBGp{~fO*Y_%uqhco_1;`s2aeopp854A22ygkw28|;a$&UuHw zt2_Ym&?;uisMU`0z}pl>-hi3nAQyps9Bhh27>5Sf6d8G&qDNp;^hmQ!(cY7Go1#dY zO;IF2em=$cv0{$^vx2udA{!R6MQOoINd%t=FU5%drFc7D3fZ}kZBZRujV+HIGv!Xa zt45w0TOPYi3`Be#Z|?$}1lSo}#$A;5ddJ~i3zkX@*?Mo-4f(M5u``y+0SBxOt9;Ph zXl+lV9ZLmeKt9m6mOF@JEJ7@muTf5gINXM%5^l#**)XGepbbj}b{)?7B|esqk&kSd z2q%SXl-Bb;(t;n%b4zWVZ=etDZIf?9 z!MBz($W}~%Com3ZotO=Ib;MS=(QazQb1imLyZ&@@c2f>~cfwZLhO&g%Dk{_?w41se z&(3yJQxNBDH`Rc)G-Ip4rbvl2&URB}h$Fix=l`_!?54iHr?oYlqurE4`)qbolkmUO zS-Yt|pv&2AY8Togw42f%ztL{$`AZHVgyo6HElu^d>xpMMo?*jVZ-4f}v$sNZ&ibqx3Ec|pAA7?7 zG0S%MJ5P@c^cbEiU3m+ncI zp-!sT9hh{{_0tOajf^kwK-<=#9WO=95sz6y`67`=Zp-HZT0KFl z*PZb(6I$?%zs0Q&JOB z-8~DU3v@1=Wn~1gX`mN_j?BWvlN~m9E(`i3U!W_f zijs#^74=N7Lis3L<%xLbG9zqdM%c=9OIBg^v)um^Yj878=)cO^p)t z6LfRo()g-)7p_Vs5}_}p=g6j-($o8>67cj|!U+!%=QoYx^5%-x1SbQlx*zzda*>kW z&qDU9^{5+o1Xw$97LyBC!F|c))=Au|>LjjkE^tyf37i;C1jki1tmoHj%`}nza2wWy z`;xe0LQIR@F>UK&uO*2r@{djQ?c9v_(TH#7C{YOC?h7{DTC68qurH>0H1YZ|Q;;Pd zZ3os;)fn)+K_ZI1YPNk(8-gtL2=@YZ!*^R;E1Jx)mO428n-}j0pXX2bM!IB{TdtU+ zELuK47h8vCUax{Ui9}}k5*QLLcy~M8Xt;$^d>bQ80Pjax{NZ0T1BU~y9`R%F{2y}= zo~iy=%PGVW7IqNgGf`dybQbowZhRR*mPt0h9(5+$!tuN>x7-V#$|Zf-mxRSbW%GM2 zpkw1Z>iRA3s54!aReXOvSE8`ZCX*%>n9qJGn3~5?EEa$_s z5VrQWANti7&IisLP66iy=LzQl=ME=_lfm668^S(noR-qmQzSn_m`(eVM39HJv8(%c zBp;r|j`9Hv>nNkhCLfOYKSCNB2Krcabq11aaph+4Z>#I%sydHV>U!^0>dR*6-{9); z-}Mu|cX>QvbGYRv=$$q-%Tc&h4}~&F_f0m?|8a}A6qUiJBa-Ohps1DG+!xl&5=Se;u zWq?nQ+0r~^d%ptD^+X%wF$!^+Vt1tTvGfKnd3geliP!e_k=(sE%qDAYCg@4wt{c^L z|AD&HcBe)ZAN8k>@{R6HRZXev=;P$}12DcOLCAb&io`c&0 zw-N3MxJTjE!0zUe7IaV9o!ta8F16!rov5vONZ0IrNE7b zOM)8?cMse!xFK)@;iBRC!rcbf6D|ZU5Y8XY8_olcmjTd(acZ>F!n6>DBq4tHf(=t z&kbW{J@B(6#6NLm9WT$GmT1U0_K|I4z|(RR@w849VXa5>nsOTAzJQw<+DmW18I3Hd z_^|cc#goSEtK z4f>A9$OGRKiO*<5J<=2A*J3UZcXk_XJGRhh1wb#26t0U8U|wW}EW z@<`*?u%6dTJFHEp7?II${5zArme0OU+~W@-`^&z zFYK~I=K!4LriRwnt;o#3@4RuJ;94zYUgFKuM40~ewREIEbSbg%O)^n@Q^QG7GffG= z=^)u|+~iuZ-7l$WNB5+rZwAKicsV$!sj5d()Az#@cJvgvp9vSGTs4T;)vY4URXeSj zR(bZD0KV?QxTrIG@qI>nmnND!`MwOTx@<;Y!`0(G^`EP~Kk@u5#uxQt5&BOGc_i7S z@{N$m{cuU45&BHX

{c1R}vVZ{tU+)7;~? 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

{hrFGtUc)Yd(inCCT*>6 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

P}-#UG~VnXxt+UYg|*8|DD>QR2cgdjXdr& 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�(uyS3T6MbYtlP`swFr1E?xt)X*E4X|Z9>63 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ν!joI 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±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⪼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 z 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 z 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

    yQ>)xECnCvh)hP0fGslQ!l)-;jlzuX|8yz>iaR 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%0Dg9a)r&3UZ>oBeJ0jon zOsLbyOvurXzvB?ub8=(_ymKzyA1dM&)B_|1ubt^}9U znBzQr(37=J!ywMxwKqpRS#?@}eXl>(jjYJkH?=#&nyS-2-aOLok8eiTIAtT88C~nt zClc?r!4b8C(FKgV9-DUJCsw37jg^+(GO{#JAGO0Fl~%n(Zel39^jUC}gDn=I9d?%H z83zjr#2=n^%AWAhA+-I6_@oBb`2yJNHpp$jIrd@X#7r4=2osD%AUX zPs)k-+BM)uaNRV<7ESE<6Yw(&4hp{^$q^Pw{dy_u+Y4XbLq@0^SYnBhwlG`NbTR$Q zZ@I5U*x%!f@0p2Lna6HD|D9Hp`n zjk6vc&V{?Ov7t`p-afy1F{{MbbSYc>VRpW8IqbZ+b}8G(L0Sv`d3L^DiYDrVFAJHQ z&%A5i$KL^CU^Ek7*Z)9?%*-m$KSK-Ez!P0n-Vxi4QgaFa|BP2si|jU82a`sK{)GWW6{Uor#? zTj9Y#eAsrdlmvz%ujNS{E*b@A?IIpmyqY)vxUn@UTQuR%#^TR@&AqCaY!!Hz$NwMN zpKsj%aD|xUbn6oy&X$+K?Pl_9*8TZD+fH6^T%N{`)5y2|ntac&A%7!pCoEo#YWMlzc;Xc{iAtQ))L{`A0-SYBq84K>0OX)sI*>8GCvuBG>rU z;ftcrNxQ5fHf<&bO2po`>~`x5@-E7=*urnY;sCBS2aJX9!oNSAEzE;*?efTa#ObBO~E zs@G!!bL0qXjxkDM2VR&7c7}Tk<)`@M1aKG)zj(Osb%~4T^dvm=0lIo*yOS{o z$hW~)40)^5a8PoRN6bW12coGb{8-EQ13X-fKd*)lrZFa!AKio=T8kdqBn$PQqla3t z#Vq2o3Fx75i6zno4-F%>Z|6;jl*5nEW-L)mcWNy<*6@#at>TMlUh8hMX0< zT3BCvS!P0s{=1NTV=H;OcW1*N*u&6w3gtO?LB(W$?ug0yhk{pZZX5Sg3qMdJBPXDE zBNW~=kQ6~vVNz*X^#vjRI(`JD!5Hn4!dmzM=^`sVjA(;hw$g)*heB`R5AVYTw`_8 z1!DR#VtThPCOhCL6Ma7O$eelj7_jqaM;SSf-e}wYF2X^jcaJYbjTzL-c_WPnlj{UMkzZQDJ#{+6D z$Dy+nrk}t!D7{2A*XiajV_ zH;6ghj1JQB>_VdkFdi;?9!}qZ4pMq$D!(5dkz@4DuM(3^Djn2cUgdYc;Z^ytfcz@z zrJdz((LbHBfty;oDl$i2vJ4a@_>c=|C#9!rd^`j9;=kg#uCk>R^$Om7wFNMi#?K{S zsL5NTpG8Y63~c}}mEh%Vu+$XjkH=EL(fK7V$?s&7&woics0a=+$v5E0C&}{^;5&oh zw58zYb>gv~{9Vh4)II`F&TPCbb@30z%dbD$!mc$|Cljy3tPF(4&uogD${9 z&oH*Hh&fc;{%bhvDsw%i+=CA*6Gu|*_^?pfVhI&54L)gD$YW{56t5iiiswo_(nD;1 zn*SRE$7hfiiYf5=ct`oM55eCg?D=`Lwl&o*`bVCW7rMZ?d{!K`X=R)$E_;Kq*TDgG zV;`e~X15*I9|uFH+YTGs!PAp)(Ys5EWy0cOF?C3tKA1RP z>7f1KNcl3wL!-TirJZ~0im!B_-^bvGt=Q85w58&qndBC0h|5Z@Q@0LAPvG;0z!@4i z+A=TCh(imFGNsQC(GEOafL}cf{u3EfBi9%NA3cb!jw>wI7ow|M!EUyrSoGcRk*DV6 z$#yu#m6)d=cc5di^8~PS9@}Z?O^%e$83%VLJrvA+X)PWRFvpEAs~0b~cx22a^1O50 z`buK6t?9)gZMNH|se6z=YQg@MrjGf-uZ0c}m(^qcBe~A`3Daz$+?&!}70mG~tkv&o zi;b;&Tw?WCxzyY%^k?5AcHQeTj-Z8H*POzR7J3ysItzwVt~-rQb;a@`c92qAtgk$j zE6>17_3%(V*H<~1H(3`|R~gD@yq`+0yR<+L+uLsC;uozVY1Q7PL?SIVF>9B{$R#mI}~JFYb2gKRetaD=mG+{mj); zuJ;S-04Y12MoMb2SRa{BT_{{Q!Sk!&GljWTdfBQpw9l{c3MVynXzEwFMgv$=+UV=W z`NpGH9s1Q(CB~yq!0WykzmOO|U%s>~U#ud&-)F_Ilh;lg29~fRD_9ypeDC0M)_^4m zwpDKUNw{GvIGPO~4ThJ3z>*V=dJA9sJbr5)I2yX3%qU25`(m@+QCh|c-m8X}UIS-8 zDyto4Fs9a74 ze6bvk|0(l1{y>hg>yk(GfR}cJd4+MwBQLV13QPBOEi)$1$<`AMml!%HTb{!{-0!%2 zxdT^*%h>g0j&x<^=--5v`Enu4x$ac7^jp~I|3qd`}AHYZS(@) zYo+D*H@nZjRlpHmOBZpNza7Y2#)6}VPL}($QT4`r*$3bI0WpOMo_w1ar6#h3Tw?`T zDwkKx<%Jt<}!NDlIL$kp7~kT}r4|q(Be_O6abhO=WCn3$KVq}aVBmIQ> z_NU+|A$;@v5%5nC{F7h`74yh(t|0DLaq=MYk8$YjP&B}Quuj?F;BoYlWj}r?sTqxA z*ViYJN5(F@NxK;TS+;z3evZ71J%`WF(Jj(Wu6ux-L%t%_f`-A*n!a$8r*?@!NJT4^eCpzZO9LHM=V)XviO!h7$*dsQWR95LEYsh@QrMpNbrbfIO%ARSKh>3-b2fRZ zNPJr)8v7nJQYBb7=k|9jmEAm_sCj&X%_3g1^+aNJVC||7yhk6Zf4Df zF#iGky+2p&7A`c>M&dP%`w3F<88zQimOxp^cx&OKwOm8hJYvadsanWtUc(n>6Q336 zrqzD@xZ4Vd&rXTZrSxxMEB7tQ_F*U@@RW1}pE70*BTt0gDhze@7ND!igL0i&jB5+_ z6OT4t3KwmJheo2SgYap}zo|UY$j0i|*@2 z&R__BZ7A3J4Yjkag$4SrsGYT;mG(Od#5QVYHNl#9)dIWRpJ*rNSRl`)SZpE0iG#pW zF*w=)Z%l=w5)asYG1_qY$dulGja+mq@!Gv1IY!YtMd0-l4ZgVK0h*?D#aLwUfDiEc!?*&DFc@DDw3T zG?K@uK%*5fH(|tUDu4ALys*497p+}@Z?nrkfT2CC`!#aZN^AG#?`sB~FuLWR6OrY) z_`Coa1y`+tU#vTe^v?O`e7#`Xz-2PNz{-83?JP3V&`G-^PsrK$$SN?IhFv$oJMq{| z6TB1-M>WAe(duXLpQ~_>UweU{Qx@kMDc*8DrGt-R=-n9vj;96;!16kz7FS$eon9V|)~2{^|I~ZrU8=IF!8*n6iVC@sT!+#|-EY%IYYve=g@@|lw>P=pdick! z>>HfU;%7e(Id$_6@}TfgEMwb+e(XhlCldQuUgiWpIlfr!k7%Zsz|Tv>STCX*QqkIj z3M$2{QYST2dhF29`^>>U{}i*U7#^y`_jQ$L!DJ+u%G^orgSy87H1?a|sS|UbiB?hh z>fwx6)jQVW)9dkNY3g3#qI`9)U`qAie26AWZj<^GE3uVTMaDF*G?J}_;unkajf@v%XmW#iV?B6<;&0uuQB$ zU#t4-BJ$RA=auMQ;{8k27Tf1>zeXsrb`aFr<1z^U>G)(AHhhMAacxq7rSb^4orW zovl9uDg}B^K+0(yd7C8 zM-eOa;rj0}uc}AbhapPB^KYWp0Oe5#Wqb>jP3S)VO-zVe0RGhM!T;q|XD)^^ZFH5pZlJnjzg~ej&{#?0f zKKdBm$(ZNS@0Z2$>R46xFj2GbCqE$GP#98vW(e{A)|MR684MMKoEP>M>RK)M9qJvC zv$ORA;xjk+xd8vXMtpV-TYsPU?7jmY*^RpE;4o?)aD)#(XrLJIvm6_E8T;MOn8y<5 zZv{K8d$Yyc6_t9^Ui9-GYAO{u@Q+JutElAv@rms&nS&PULH$+LIbv!&`slCepN4}P z;2a-@uxt zh^hLCclq6UzJHc=zk&~YZ|XYm|mPHo`MQ@U2Qy`|?Eakm}D-@uUsy(g?m(Eq^@t*>OecJ66Lr^k6>> z4_yw*6PL+Z2ZA3fIcsZRp4@89Gwvg2{l*ZdJ`(J>(OE9|Wd!S%;Paco@(p6K$B4^< z@Lxr6(Vx)Oqlp{lpmkKt;7)Xbof2U}2XS=GUp`>%?*%&>(RSVF|JVYj4O!GAMoPQB zdLg`k4Swpdixm1l>bq;+t@B*+40Oqxa#{@Q=zB1bJ)B; zXYCSUk;mbJo^l#k4#uA-Kc@1DN?SdnVhQ-?74-_^od;g;!5(a z!!GH`)*`tW4DAUnqEEHRcyXCSY+2@zFAlpzZ}V}z7ueayIJQy$I;!{%jIUGm^A6qf zCp1qWwbp^?pY6I|tI7Jt5QcWDz z*5Z_Hz4@P3r?CioN=b0*U5LY~(~pa4azoW{PfYr8*$gkZ-#Koq>d-!46Nf21lCFF` z+!FyuPX#|NV!i{|Mf7481|ThX2}xfBH2#CIy{1 z4*t2D9*|81Zn5dt~-{_Hhh)87^|Oj!HkL!2_?MwYLz< z$F&vckF9h|^J=%@kHs9K&(b0}dvTG78&apob>tV*Zp$wYB@RpBUN578Mu4Gi*uy7q zY{>N!axoZMM=Vy`?vX!1KW>MM=Q73^*6$4ZXDhKgIj=7knl}GM)t&!?`0HhS^f5Hd z5c)oL6T@$%_v{s7c(tb^)p1M={|xMOK?}?;kr&{L6zUzT={;jFv3EOsPy&YEgmVD$#!q_bC76)6c#A{!8iTSFt}8gKc5_%7?Y=%@+@&p_{5I=w;8B`}X7;`zo^O zA99MzRTa|c(9oZ&{vo(B1^)4AXt+q_7gfK9;vLmLs$#MSc#U`(ZlPu$N`6u0F0To;aAr+}|pS{e>YSK0>-I;mdaAeF;b z`9)QO9SjdCE&bBUlQQ{q($;qZ{s%{8o9 zJb8pc_>r}I<|r^UlRS_BM^@tbS>%QM>)S=i$#S9;@`|Ptp5PR@p4yx<-sg-7Kpv$H#L` z#PO$z!A`?{DmUP(n_<&ixVEZssJi`hzE{0NqgCAuT(^Rs9CAKKcz*&hpu$;qzJHmz zS!CW3_RiSlBJA%zIHeez-G_!=I=I|8e)uANuzBd`PO=+uN(MZXx4T5&O3l97(noYh z1F4?pU*OyPbu+uT7+Frg#{hV!yR5=S6z{0sk0yB1$4Bs_>d98|z2c#G*8XjHsL3nI zO%rcY>zE66ngUgBx=6l2PBDcz?8%NeY}PR1FlSlxN-b-hw&D=+Hu_>T$LAf`>lSoBl_Ky7v*s3uQhPO z8+C4dG_jc4AL;7_V9csNM_p6ZISTNV>8VBdvI0GPmqT6v+vhDkg~~sVXWhr6IiEo@ z{FF5;q2|$)e_T|i7Rk@4t4_J+MB`!KUD(;c%krg-u0I z52k-e)zZrF3CV3`dM~u}eOJqj=Xyl+99EaONEF-ECerb$genr3dXJ z`0yw;@-{dO#@{!ii6$&MFJh!qk6J`8H9Yj0!zl_fOXTJGVCrs#pKRUca8lRMyutXw zTKHl#{5l5=&4nYDXOS-fLpfk5GNehwfT3nMOZl>w(ZQJsF8y>Ub@lWdkvyB;ez?e- zo+GQUkum8x;K(VRSx$X@Xo;`JF-LJXyfK%1-AoNM1pBF{k6P`;SV1fnfR^4)Pkzd+ zcue)=yTt4CMA zx8}D>2kX;H>~jy-siprcI<-{%B=VFzjh(Co2V;rp$AU|>?`S6Dtb>DeOAx+ZpJLBnG}b2xgkF$vU{^Zu%U$qJ7%fvvCmpn20X93>O6B=P%4ZLG0xewfL=Q z{MPuhCeL_ci8+F5ILif!!ov4%E_@K*4RZeE>Gq>n`Jq+~cm3i~!f;26a( z1qX`Zmts9a=^X66mbFo}i+-%#dTe|joc<7gFtNVenEYO`X#eW4;W>Sl9(#XJ*(a6x zdhrd1$gDgoUu7Sw+PgQPwwyhC<$9MxhZ&27K575_pMg`&_~&Psr~6WgS5C60i5MyO zaFs|dC9cH}ZOyZbQ^ZI1!&UOp-RK1Rc(&3HqPS|Z6A zyT} zd)0E)-u_Vbu!XUgtt)%l!r9x_jlKOpvZ+01VasD}=I}V%nc&X0aQ63y228hU!(+Wc zquGo2uMgSkM+Vy(rv%x$t)F4D^kvW5!dP!ZGP&Lrtd+$otk|5|mtv(>69f*1V^>eW ztycU{2y?On-Ws%Is;vq>82RG|`OH93`-JA*iGS)#+;#}8{T!Qo0c?J)FpMs_hF$#$ zT#sHj%Qh1Zy^lOX*F-oLKI;nyzG3N!zIXWa**360lbHW4KFi{8iFNxOvJNhYX5Z;{ zus&j8y@+@ zJ#4Cnn|s5b=y2XFc=Ju>>MeXu$sw0fQ`x9@*^9mGWlt)8v#PRDR^j8SBOkQA!5ZkQ_5mJ8V?S@>8xonTF@rotc7Bs^?R4m_ z{3h9yPaj=bv1m=DH<5j8R`#)}J$q^&Tjoyo=fRURcRIxVk<{Vvac_Wkfp%9~X)bHf z493$~^Je&KGcjd1YH5|pe#Jo3zgc@Ll3*-<3Vq0hE~x!L4kg2B@m)id&Qlo#;gb%G;K%XCeH6^P^tOZ|cPo~1xiL4^}n2OlDC8qxI|Pp-ioz-iEKX))vvf zW%nl>BJ`?V7pwfW-{`1zeRSYSxi&8{>0ZS;E{RPbLCpq$JCYF9a!7I`ff*)`uix^ci)j4Paa^- z$W=ND9pM3Us=jhJ*Lpmuo*K&${bxx|UvH7qaYU@i^w(Gx(o@-ry*tS>Jm)yVzD>Rd zr(@u{v8;J2m{RAcxQP+NFO`V!cbxJ9T(E-t!QeR_V?ikXh5SNtNS%0wxbYI)c5{#0 z>I9E3H+F>>aU?O~Dz(3MFfkEhP`v_gp=(sVrG%eHG2b!ZOxCjJW^ajzq_2Af+AQu? zPi~PONv&=;+DyeHUlRAIdR;>;`_}GOxdxZMj=t`?hsZS$7pnT=dF*)%xKTQJ1K0MX zvX`{HM33C%l$G#LBfhB{_MS{EI2c@90EZd;TtSbn%9(c|-}yfNVkdq^L(d1EpKG9xmi+-?tVtsGbqrps zdyIT6^QwAIPAMG0f$IE^Iyi2O`We1?j#m%;l`&UJ^%1N6IEn#BF+qj0@6}Rc5;+Ie z!xX*5B_fw$%iw%WRJ(tlGuZ0mEoIMVH|{-*K9nGO#Y|`wawc$+32aR!Up|m}%WAN- zk@?xodRyQpRWD6WvfrxR^`Lgw1MRkpIU0){9VJ(H8omDKAs7Y8`-}UUe121D)~1%;vq`<5lLLVH397gg;jKrD(WhNTh?Flp1lNyvVnYauhx#5gcZKle8UDe`#`ZzSVa^VK<0yq+uiZ;;PYy>h)e za#|nK-*g(DQoZ1Hhn%-~O07*3JhcJLG{94;Z?qy6{-J+2oSdlY-)-pVPszu}ah9Qs zq8_7S(B1IozPuCS;KmZ!1D;c7H2eztZYL&Gab=JE%VGz0nN+mz0b(s`bAs~Vv?GsDkQC1L}yx6z{9}~6RWloVY>2><#F75HhogZ_y#GB+JKB#QsJRE<2K{Yuo zl{fSE$)WY(CY4(sgI`hH)RpV0J@^~dD>zCibL-1@x?~01l!7mNAKj|*g44l6aJkz^ z$new%p2E?4&05C>mrjInf=5&wwAdJixqq;D6OSmcHAi2Nay~?PEH?oJ~e6 z55Uje+|%tMCt5-sCmc?=qH^l+k#EfKkvfY;HF`Yf+@Xr&GG zSvCc_$%(?L*!e`_RMl%aBG4@ZgWN`+VKs7iR3SO_T<{a*^Jy{URW@To)6gp~pf`Wg zo{N8@7rz5PiSUrBpKIuvR}$d>xM(4@J#{9)$N05ea=R<(B~W$0UA|nXTi*f?Rl!3M z^fPs(pP&gJQ8J%i4eWT-d~!wfHK|??bxuVLcuBzTY**_^oH>r3f^haP^`$q?3%~55 zH*Pg&3iSpv4eu0*0&0G4{GF=t_-i#zeS3lv-d4SF9$EB-hu*ksA1A!YeXII^H+a7Y zTZ>?B%Hh@6WHm3{;tl; zVGkuWZ*;epJW3ii+yoYnvJP(#I%;_HD@6=v12luzpTgCt*k}yCxM`B1vFau8of7~DsX6}@vF`8D-8;}p z@2>Xir19va9pBSQ#bWfbV&X&%?cFX_Pph>U@jvI*%Us zH9e~EozmM`tfS%|)l;GB!$)|XM~x=D{D^MaMNbwST#p~S09Rk)b33D*mEMkJ&Nh}G zK_g`o%h~C34xvu0_Nw&u)c{nE;giT>qj!FVXevJy9 zr+D4G>>KvRozgq4L<8Z|vag=m&mhkqG#oK^6Xyt$wlvXVP>u`F50u8NL~ZiMex(R z^sE#yPjDx`?{6{17n5_ADnyo7uN$t%oLemywi;pv>LHM(WsP!#`o9ZeW z^#^Y8QnB8EHcBHe&@fo@e%!H7&Ve?ng(Lmi$nMidDnF~@!WwK`^@G@-K5nSoZ4bVW zD?O^upx##l&K0K4FwZJSz6JfG_6$$p`>o|i$+MmiZ*Dx!S%{k0iM>n)11jgI&MwR5 zZ>*eu(-Vz!u>2@F91Av!UHddriH>&i^{#AV?svm?R&4bWPR~^iciuG12tbunEuVsr1&`LS_h$kF!68j3G+j5NPz~dr% zNrAk7S%DZj?6RI~JuZ(29XFmIc3B=DdP2{+lEa>Vi`;F&w-U>#eV&|SE&Fo@&cOC; z`3?E^HZ+qNj49u*@<_q>CI9(J&Re=$^O`c0UgFqZas>3iag9jy(!JyeBGF3|$Prw| zR)f(?z8nEuc@(`Aj8=LEt>gqtbMOOCf~R!WTlw&td%jKJDUv)u3_R6*B*1o4Cru@W zi%fTlp>UMyu`K#mU6}Vf2JMuRE#zHF2(zUo&N*nO35gJ|Tvy`S;GYlp435OfR^q6{)lIRQ+r{ z_pSD$rE~B8{Y`FqFv*XBadn1Gou!jF%V#RB-36{!YuE{`v@h?l*oVI}@DcYAvvnor z+JNu+vY=Y5K_{s=;sP4U1HXpznzhTR4=bqlY3mlWUk0^|o%qifG>6*bltS!w&JrRV zXs`9~=V4Q1k0g zJ|L9%Z7euSg}BEU&V9pnJE5@)E|&hR>aUOt+fQUv`6>b#UH zbfdE8XOvyTG3qm1aFVL~Id|G+JzP|0;p`*k<~7!GDE+&U)curCJj6Xj=9P(&aM22| z(+p?yyk!IJugb zAI1hB``_K4Kv?F@n<36=hyVFJc;e79MZ?cco&(!-qap~={tC#^{_~p z!}(&NmqkkJVOiaB*tk0Th+fUU@9Oj-`sa?w1qSgsSb6D7H~!15?`EI3ip#Ea#AE%j zwI}gmcINT-093?V!h3*aWiLC)-5#Iya{I8 zwb2$^^%ClWYdhI4#B{c`tfww$vf3)C3);}j(bNT_R~1OPvY?|b$mcC7ma~==qis&3 zZR|27>a?sI9b}8=4CMHzT)mdM;0zQ;%?ec)oKKxEk$T@e>V9*n|IOhH%LJaUdGicQ z&2#-l6ZJT=n91|iqbDidPEC(|PT(Ue+D33Tcsys#J2?w}7UzvGGX<|3VS1xnokbu0 zvi@$ZMWg4hDvlm9Ou(l;Ja=7{@;VN)DJlmeR=2D>)Im`W0rT;uB-Pn^L@!ovx zy1LJnx%N-g`RMAIHrFGMs=;du(ZI3sn}FVr&zdNPmxzx{+W z^SAMgfh{~=z`-*vZ1HP5*7W%I*7Uz``@H2mlYq6znDIB(GLkvG{^DOhv-QdoabSz} z?Ra*p?N8c{8`Ct86&$Iv?xVrc&1VWsF$Jv)G;QY1Ho(8eu>sokUt0Y*inVsUXXU*iejLR{bi5bAd*l5$ ziXGSS-ZAriO8|H`tKL)2 z+111=0owQ;R&D$mu(B4c1W|kRo%0V?)H(m0C7;3Gg<1a%R$O4EoT#5^{!{%W5}vn5Pa^o*VO!OS%iIaerN>*aekNw=8JTC?$o>kFZoJPa{4lLDxp~Cnz9qW1Gd+Vt%dviUv zfw?uTsSf^Z=AiBC_^M|dqqwK_eC;=d#Lw>e?ekKuzc`)wnZ`WDVQ1iIn*W(AH>P#M z{<>m+;k@6C-~Wie>&`s(u!Sv-wFO2@wbcv@vjxnKvke$B%{K7K>9){_2Y4^k)_3`X zwxB*dryyyDEpW|DTQ8nVV2$NG+>s$R^&E@}=Bt}JcNZOWm&sCZQ_o+(rklFplb2|= zhWqE(&c~Q+XW;6F`#Jx2lEv1(KET!()5+#t(b?7jr#JNNVmrH#bA;Ch+AhJvwQzpz z)L`3k&FXCSac~m%yMX(i&;2Jdj(OP0T*lYQhvV4IrVRC&r^z=|_SOzf0Y_DqP*E{B z*fy2tM_4DnU<*SpTvmDD$uHU(pQWy;bm%4(PoqO8gxRcgepbNC#1XE^hv zK36?IBmx{-wWV!p%@nVz_y6WPOrCC2>!5VBb@Br?Ri6w(+ts0WFQ8GUEZ0(*>m=(q zm7ipf5ZF>{(mELJpWE4{;yqPQpG)kedSg`|$>-?ftDJYeoO-J2v#7@YE5Tpgg4wpu z(S`3bpB216mg}E}$Ifv!jhQ^L>am@R4l;0-*>9 ztOW!NCDQN;Czo$-#Se2nevCTK-vU6$T)GWkrML?;fy&k%#p^D?tbXsIz|+!k!*_-yR~ zX7zx?x_6k5#QR8&S>(7a0;#mc<54R;3~PpW<9x% zSXFeUa>jT7Sl`STZ#~1*W2i*-FpdYP?IV*mQi{yMXig;F|bD zrB?AtYJcp?J8ldiS6b@+Ov7K?Lu^p2@u5Ze`c~p(cVCW=jrI8f+e)GEGF2PRG+M=B zCuCoGKrb%id9kkqqo0X=PUie+N6=E!gSKL3_kbCv{|{Hsb(nbrN6wB()ijgCCQf>y^EwEAiC}sI513 zO@ZD^!gRpxF3?Yjub#*6RBFRM0^A&7ogJ)i9CkW8@zqoDjd!ZI&6VjXXG~*e`4RI5 zPprlA%0iXf2X*d54l6gjR&GCxeL}OaKn1ZO6C1FyA}?Ob-VCYvB#z zx0;B&B6Y^a_tqWXcxG;)u>x4yfZaBQ=frL*uq5#h*>NSV2Xd-`C2BwdzfRWX9Izy{ z>{F<*H!X))5bOfWkw;!2ChIuz>2#j)!c$0G3GrbO*zF>W9_+L5naXJr7spyaFP@cO zXqxPMCAh#jTjq7(g`N1t6zc0wokWfcb%}PL`hooW67uhfL8K1I;SQ(u-NE>HsX5%H z{b{oVcMsYu`8vSTWEhdbU18vmTMArtVe*~j?8cF@f^;FDt4uZ?=xOMo}=hd`Z401 zfv2LdJXgB2)R;H4SlP(BL6ZcB!=XuYR%hWO&(ha~<41xf&5*T&wzsFx`4u_%rJ~?> z@J@UnUoFW~IgG`-s))77GxHYbx$??QmBYAoSCzR4`*#TWi(4vkR1R)(We)I^t>}{2 z-D~Kl3Y>osx^B+MbCrYllko{8Z_m{SQ0G(lZWVB_k#EU416A;l8-P87+_U7|pN!9yV2a!(PzPyQMFbT7V$<?44s_DRpB{nUbfS4?p@A+U9_^ zSv5cNj4QAH1)oeyvm<*Ofo-@F8WhLeE1^N}%346H6dZvE4*~--;hC22V6z_okOfCi zQ&+!l=z0Ucfmt^$4>&rd@1y2tPilU4?R3hl2EPw?_(|UnZIrqYDfI6^mOWax85>?J zVs(nliP-H<5eK#y`hOX+g4o~Fnd@NIXU2#^*L?OpVob3yg;?fU=mZY{|GmJg-Qc>^ z(f4I#t4w}>z+AVfL=b9o{8ay=_ znj~^q0(FN642AY!`<;A@Sg)&s+){VA9d=)Bh^eRGKbSGZG;5$q*Aas#b!o+a;8=|h zbxo1}Ft%TzMH2ftm$+2nKO=ziuJD-MtnaJLe>48gK1&LXsno8HT~erGpkLUTtxr2w zW<0fXxA`f#4Cs(`3FoLOTTOj+=tH-vB7N>U;1jweG~@vCfcT$h!LuHnk?lH&%rb`c zDcQb_da>jfL7VnLmxdvm%!Dre!Wv0#{Odfk;iqk`q?{7tt{K_n(mTv*U@4P57)oC^ zBIit@CWtNfkTK#%@_d1%MZil-aJCFzg4C30k$cG8%igSH{iCtL9<#SL#O7<|7v2rtRP#>Bvt)o8A*xf;K7G@}W($1lGW}Te<%t}0~oAtR_$L+)<+=mO&)J_XS?m$9zt%xQjRk*fr|{YRrK zjZ9+d*N!eQkEdWSgf7Kr5|;(9dt*4V2Xd@qgsDeEnXV7624EV11Y}GY0#_Np;P;ygU_tVH#;kN zN#YpM_t~#_)~ib;@%Yf$EaaCI<}UuIC&;aSh4_mvJ#jmk#9v7L*bH)FlbL(f0M0Z+ zuKKK!`sT=Wj>-bPCA8@XGLy(55)V5ywNS-$W$}LnwCA9Fk68K63yB|sHthwb27x^V!f%#^K;iuD2+w6=q?e^f2lWdTzD^X_wCT9ys+a&F*5f-_@h-r*3>`7XPyUrGNDgZ(5KB#Vm&?d zDdr1{K25@3Ui0~F?ykVU)Pp$$ycgk>89Yle?XWIT6OiQbDCRmoWl7Cjx>6v{Uq1)h#ToBGgi$@Z;! z895h6piRT@S#N{qY~$HO@TsTJ!I%BCRneufGYZL@j!`vb%J9jI;N1-y4*@${6>obI zI`szLiphsRA zN#M;ZBZVR##Q{Up>elPck+-i0W~NNeH-mwj>&GD@jmJn8^(&L#Roql(P^(1x)55@TK_@(i@-Q{qy?s4w#t zFjW0NLGJ0q?<6qqSmM8=o<}?2aS|~H;>*>JWgD*y$-%!_VSIdyy2H?&lw;Jf7?Pt0 zh36CJTx6^sl4I6D?^5JL1!u#Q$B` zgBzgbDT{NA+y3^G%Uxcj_g;dJX)&@GveF7_%Vw5WnR0gMWb7eAljf4EFSZQ_abcIO z`^h{kH0jIR-CbBqp-l;lyYu5^$a~~NY|qidunQc39+g9n27+(jLKE5|)65~SP3pM* z%s3pmKO6ScGU`Fec|4q#!*kQHUrdQBgchAK2I2Rrgum^9C%?+xrSt1pXi}f}jClrn zBzY_!!$YK=v=tLpW(<$R9zx8}5%}6*Vq+M!iNyxF0r)<|JRXLw z?$Ep;@R<_U zFZp<}k%sQCg&i`kAa?K!G{}k_EYh>W$@9q|&K%wU7_?x3lX@=TyX5k$T|@tC3d!XW zzczIq*wdd*Kd;`54PdvC{9`FG$XZ=5*60f0Jp|mU zSyZIQqMN<=0x8@sZjKYU*w?_xt=NVk;A+l z{Jn(?q6?C982zT`@_gVmTx?+J^5$gPiBWrdI@uR z0^7Fm=y=ALNqn<>^QE&}%sY{@ewnMM;`@lOyVhG z(E$e|4+-5#KAvSfLhNZ~cm-#i5s&$vC0hqVbF?9a`s|DXkTJx+4#!Eec% zjb6<-iOuN~o^Mt_Z=|o_%6wPVbpk`g%z+=mzuK{vlaPVpmy{TJ+&Q5c9xP) zU1-cNuOSDAJp*@YfZ3_QPf;a$JTySgy$nPa+9PzQ>mBYXd_!=!E4VB&(J;Ofzr957 zg5F;RJP(3L1i@4K0vnaUndE{MY%g)e=jIx{kbyR^*Kf1e$=G~q1xBck_VUKP&>YSi z1a2Nh-mufR?A0t!9@uVTF8)q`D)&m+jS7uW_?MjPJO?;Dj?Ldc_d*nGiIQU2N z^3We$*S9~1Ed7h#nfH?UhSa%A!Txql?Pl{O_;p`wB|FHe2mo&GCl~BFXt%`2b!Hr0 znD0rA5F%pT}ZOKK2zUxhpbKUf7E zi9Fq$T%G+lHg|h%kB@*)!fRro>)p^hvf-NoPq#aflfh+!Sa&%y`mbTxuHrZ4oU`4= zTbvtnl6|($jVaPs4<%LyniRR(vO%^D&o--;-{$TNz7?^*l1C^xS_12Gc3eBwVGwla zVPIpIx=+?FwWWY#t?YVBfyj3spK}~F`h?$%*KY4XJn@4D;rWDWaDIH0m;!g zjy%0AZ=W&j$82RkpM|`%20A9O&C3^M=?~`YGk3v{2e4LK(di%MJq?-KF(cn_AX6Vk zewF%y;`b2UEQ`5{Y~+=RX2~`1--q8gVECK+w<`YC`k`#|X=qV9_*IGn`wx6l8^BItLSE1M%5rwm+92IRyO8d_(wul6)9P0 z_DG8sU5j62&wb6@mB4Wq?2j#=;k}Tl$`lVPF~W%x%p`CBljF$UJ@JK5?{k6OM!nBc zPrafo#!O;QrKbK+=N6??XOQo;V-2}ZUlizFv0)2;7ky0R^b+>06j@qww4D4een*kx zBHk}ECIdrXaSr+0?|W+x=OYId7)E&oIVJ^W)x1D=XJWo?K%PFObh8rTc(To7&6+u<62RxNa)Z2=+T{Lwwg<+ z!S^t-^#jax@NjBwLdT|!-e`1&9yy>#QNcE+)WZ0hv7bc$aw22N8G(I>JzY6wKQZ#_ z^{>WkG>=WAHcY{Kqw+KM7`hZSVuN`cJ!c@bh@%VEn~E-hTm9FVF0nyBfQ&aC*xCoY z#~s^XyaFv+5w?%`!42xX&!l720UuJN=VFIkfqb+A`Dib+uWLrWSq%*k`RLx&(7rXM z-bU<@(4{HRrGvm;;`Pi82?9oPlz9+tUk&RT13}hqmk5xbyW!&N;c??=9 zv~&WrbQdv%Nwrz}fJqjQv*9zLhMJKymOQ#~o8WP0l+Q%`B~=~H@E&pnFy#WLLg*(G zI`s>9FMbk{-OoUuKE#$ifmqZ#u^0VvezRGHZYh3?R?yAqBR33wmhI zQP@0QVLiLCN3TPp3fQkLqYrYPaDl#cG=2{qBMS zv-UcToXO_qAYiHo^l%<=g^|GhZpJ6}qi#-ejG+hH$Pt`7Y>R6qyzbFAu}6jPHo6}# zRQz))_M`ZrTlAcvTg*Kv@TN87zTvp4%lOy zfffSo>JAT*a~NgKBgSMKBk;Ag#MjpTN}E&8rF)0D&1Nop>El(-k=ZtCH+(Lan%3D$ z=O0jzYdrcHzKs}atd6wm5+#o))^9DyHTPU2F#wmF#+qWzPl*H$Ig5n(B_BuMSM;dT zSdG3fXUU4b|0*z_0!`|GZF@yVp0Ns=B(+IZTLkj+N5wETo0o^sl_0*T(6bBv2Cx!epCT%Itjh#&G_4}k5UV~ z0{XOr|1I104rA1eB5LVVqnULO`;pX*4vouqJ&=2vbFH?SQiJORYrP!$B)Kiq78dB! za!;H4W281#3u*&}0*99?yOPw$>W;&F4l>kHWbq-$Xu-%N5_=@NtI#P$pP*BRp(%n3 zEf}xZebk)^{^bGOgb@02J&TTU{AxFhSe|rH>E%E(}?KxqL$(c(A2;u;VC0KdhKG&I#zw(WL&GZVU`UF*|yI%Gy&2Zo-UFmT}_4H`~@}Jlv4>G5L^l8Nb z$hi&q)C~oXfm=EA{8j9cYlf4rgAH1ii5_yU$QZTrka-N)y#^g*E@wB) zuHZZ_oryh` z+GmpgWYu2a9Pr1fX@*_c2_2Cf<{D^qATdlY=ZI~)NS%*89X>{@zA4qPu=UQp+^!!_)`0ybveU0fpJZuj}rVa zH`M;bciUonEHf8_gAbj}G2_maV2>=sX2`is;ELpYwSzV#z~{VYfJ_4ZUWOJ)4zv>) z=|}YV8^-L$_y42bdkpjf*i9|?k=#^j)>v*Xxy8QF6`OV%^iFDc z>|-qjZl__BoZ`es1)XV~K|a=yJlAMqNS3~tWlRgNGXC>8v2@UjPl=D4HZ)JS56Lrk z!|R?Q$2t7VGW{cBNvgZv>aL=%?(D%DWNxtmlwwz!$~q=c^SZ;j0@ugbm9{PR*1Rr7 zhck^;*p>GD&E~!yelPM-5Hj~(Xi+jU_waSpaYSYl8RKF483YXy`(!bFSHnAx0H5*1 zlXP8(9UodG@zR5!MH=^oZVNpU|Jv2WlO*L77^9&_FSG6+Gw<868N7il!0THZOe~4` zBAm!iMewfH&Iu^yURNi9ui3w*8&nh*vq%Q+4PG${#NKo|U+;q2{D=&taz1imLc z?ImDdXp$+v&?FV71f1>X{?p^B({XwuG|4pYAuqK{r=8?!l$mEZGi`Aw_Uw={>;XHB z_s8$R9#d}=e1t;H_cRn`q&Ccb}>jilDX5&TrmnYV#WG6~$+l^yJU z1iNDuwfzR;S4-Y`L?5t(c$+1}VN$bWs?_TMPV=!PRX~S6MK*ev+J2(5R6~a({#A7U zaAdpBQn718hlE$AW1CDz&KA9GBeufP+~3dKM6X)}t~~`^-++BGDQ6onR16NbRsOY> z=)#tN?SwH9+oa&nDsXlZbIDEZh^M_0#B6O!M|dkoF}mZ z$g7gCEXmubk`okOWnFb?`ZzLay% zPjl|MW!H9eJgxXyCjK=!pELn^dp2}$BRWPV{7k<2tfE1M)Dp_!tk{j_Ib`m5=GSXP zflJ^xmGL}`ZV-W7vnnJM~BW}K0=?1p;zJ;d398kvTeUMinvF3P8YM-7>Hk_ z0y>dD9C|sjfLf5y5pcTz+9Nh4IScL))>nLVkAbh^8!02EHlf8~M*Qsoc+2fhYEyytUEVBnEnQQ9?pJ`Fdy`q!=~lP!numptAs0z3 z*c*&f>b|F7zbaX>N%{L{?>a&)b?kXd`CIw ztAze+0!Ayr^;CZ2@vDg(-vKy{Cl0C0LcR}-2O~e5=*PVogYdqo@Bk|gsld1$znYEt zev7VtFKex{9|PkEiO#J=zUHiK;Ak&6Eb%E;4ALfY2rErFk8LF~Xb|5$YL~c?AWuGX znXxy{#J3hj>~@r~iFP@Q=)m8GxF6&BYUr0!XeM;DkYBM~OlRHWfcx|CS9QsTCuNzjXf z;ET|v3~-<&dCTR<^6ij!)0w~UG#7P?CliOX!o$;|%d>Ut9)<&bU+N@YjSWO(0IA(k zMt;1+17%j0>h5*Kz`&oC90Xn;1i$B_pRa}{l|yrOvtAKDWmCr(n>+Ab&R#czXWs?R zZ3ZqLM82*8rrw6XZpiu3xC5G$#Jq37Zge~Ac#1t4OzoEka%+v@=>Kx&$#QUZ4eyJM zd)mSx^tD=Z4|p*P7--G&k3t{3{s@HGUvTX@|J))t(!6uon zZyZexC+J5H^tNs2ZQ{%N2sqjU&59pk>Nldhbw(BlUX$-K!QJ`r9m!4JD`SGs^>8-C zv%QLa>1)nIuX@v@rqEuirVupC8y7Gd-U z0CY+C{yg?Xe79onR&gZ2>LbkGif5zFLkja`T{POfvbNZsmJ!P)vi5B=3YDBBa3ZlI zo8kFW@c#>syPY_;gV3Uutjii;P~t{}zvaWf<^zjTC&*hHZz#V18hecKFt8(MgU;jL zUF?h4v8&;&Rp93)aH#4|87KK3!2V0{Hj$YofwvY-%F$CMndTT|ZL{NHWbHz8F|m=0 zu}i*yU2@y~>y3HXCAW1vY;NkbNtc*}5@a%|Gb;RTPhAc*A_DQfm8g2zFA)zZ@oZO| z{h2s<&N+m3iM}TOl7ulEjg#=V>)>xE_XU*2pt~Oc9z|Z6%G{)$f$+Ka$s?JK5AJ31 zNCNS{&4tHRhPH73fX?PXXS)*ro5auv{2YK6g)x^NtmP49&n_~uk&{x$9hpJ=e+~3Z z;{R))BPsCPbYvx~rcgFEfD-ctC$&d2us3<&=kjp!N5DUUXOU+FhPnYmk79RG^+1?^ zIx_bNa+135s?pcg%h;uQ0x^--@2WB9dwe8CmDIcjb{ym)ReTxdo`Y}fz$XLUVk;N= zBX(4&6)_E+Djt2mBQ&Tbez2*;5p`aeugB*eGWu-Cen5@IZn-5!Fgp7y(4fwbo78c| z_6>ay8CYVu#cv_CS`K|W$Srj947p|cPqRq z;IitSF^TJvdY>Eh@{#i~zb7ZLUt~jGBRRXH`bB7|X}6stXK!q+*tOz+Js)$aoV|W` zTX}}r19-IdT|GwJ8;L>Htk%!?KXVttL@;oIUQgQ@$-omr3$;SbPj;UuF@<=6r zap%p_*Z5k=sXUu?$w%Fz?n|C&xXQ(poY9>(a^C@O0MFG}kf(m) zx$}0(`E5b2>}BN4Mvyz(k{sGUk@MTiec2U>?q-So-9a;w+-=DB4IE4Uv)tg`njJ$pZ}_X{fb_iJd;z}_#aT+nafLj!v!x+C$s?QA#1 zt)69V2ln>l_Od=gn+Ntza&z{qX#i^jdt14^|G@q*klfxdbc+Knhr6mB@$%51BfFcq zkHbGYBY&Mi{wlUf9c1EHpzCMA+y0_=;+tH~_=jSntG2f?PHh_EehD2|&UF(xGYR_m z5wKDWKReEPF2f#^$@MaHnxVuI$6>d*np{xHLk%FFW;T4}0Qmj_KB8B#rFDiLw-}L6 zEKQ_22pZH5T3bR)O$u={>a1$ylk$Ad)BCJIk0gdh;_TMY*97t+G<@7r8z%&Q)dRhw zAhW=HYIr_%Z-d;ON9OAebdHKonzL5XX7KTRm*g(C6C2dfY`w=C&a0qysni}XL_U2e zybwKOlW_t&{t0M*3ike#uxjHp`dR9+eDetUOy}eIMxb+((oZ@&H|dUW=pAxIKD;uN z7_B?uE2Yp+v44FAex;zdhVCkLJ+x$#z7XBxQ)u&qCB#EA=Sq8!vEtk&<5TQu)iHdJ zm{~c8rwW^F1@_qH=p6gu^ZBfa$UH0P?{m)e?nR97Vd5Yvq05z@f*a6giACKiJQSXP z58uCr^HFBz9XF;^A4$$xk036hZQfSwsN403yyNERnYq+C$;EHD-OOhX55t>t?a+yev6=yyBXW+Pi+9%z|6=Q$h#aZ5*Y30bpKgSvJ9d_ZH zCe{gETh1QKY|lA+)V`gM-f#q7xeHxLU`z7-{)Vsm&a=hl&)D`ipu1j)U2Q7+pd;f9 zLoOT)+?0$ithdDmcGsNk8M6ymIYi&3*g*2JQ#9i&j0iJd4;oWw?gfXs7UXjlA#ugv zgT(nsol=nx+an)}&m|vuO?dpn#Er~@cMc<-BL28(q!Q~Fcf!;YS{yQZogilh9Fx4^ zvT*Dp$cgQSk#h&Gbw`do2<}NUM z@bCS=n#h1<$W~$xNCT!cbdDder$rP0cW4*-%(@~Y2Av}dK3_h-k`qIKC5hk62ggKy z5F2kb^d=ph;&u3VS!#jam0Zzk_>R;WNkz9k2A*_6z7V_Z2>vf2uBIfl0DZO%etK+@ z+&jh|yQn$&6naMM9YvhG8A0xx=$_O&MaO8BgN_00mJt_J4$Tl;_1g4XQg2dxjDtj; z1hyrPM&>PYp~S{Yyu${O6CV=WS_tPTw>8INzh5wZhpsg0x+i$eT{n)k+tB5IOy<_da+w{~(M=P*wKeinfTIl$Rc`f%a1euiAWnP!$gnOr`JahZW{ z(XlE=**^wSM@e!WX5wEw3Lbunt~Z_dVyV|ToPNX}*M)J3U&uN$pvnluFSKWQpj&)H zS;*TF!%Fo2*!JT%kGUtZ;bG|CYuNsUHnhO@ANEC|I)CR;Z2DE;rqWNL2fdJkL$QHm z0V~26`m+uxOR|iP->i2P0y7Qg?+{mpp869o^CY+=HvLHI-AWzq+t;mEwd5uCbgAqK zbfQ19W*1^;#Ga9XyqgRy8nF=nDKKqf&sdJ^JOG*ZI$$FNx|5vy19^Pwu~~%SyAHue z*T&ody%oP=o7|I}LnyUw1F3u5M)`>x`?2W z{&;A9E;Rs&?S?1J0e(V<7jZ^Fu351=$SrjMyD@jkl}QA5M1NWVZ!W<i&#E<2ZRT!s|=1>5F~oVQl)LMGeKnI~AUD*3W;I!zLxy1Bc3p}p)ahtw$foYaQclJV)_uDTso`6PtDffVfE#&Sk z$jdd}dc1@hY{X*$%e`2;2Kd$Svqd?m15v?8Mcf7e9`Zn z&!U#3rJD}K_bI-fM@JMA7m7au`cog<0KI9>+Ql-Txr|fd)88IdgHBqYFCZ@T7_=v% zfb%a_ahB*+c6Y10$cO3*{U1@NM->zxXI;j7VJbIWa-k%bR?f7LGwUQj-8v7x#%O_l zD!QrG0>AjsP1wisIit`zzk8As9thoWIP<9?i5`jlJ~|v&h29imf0#mymBh_F#`ttnhJE88 zvY6Q5#J(YMFL$B?*HB|y>>Lwli})!^cPv5Q3lT zDCdJ6#3xiCw3D?-KpyQjvdkrUdg<8ln^C*H8Sz)mnbSV@--NFY$uw0R$k#^iHqr|U z^o-HipP@rxz>=N`PeJZIOum)W1b1)_fE`%c-BUwXL8e9yGT~vbv(J)$H3|9{kG-`6 zGLFQ+h>X(-+v}pR9G8gAR_w1y_!)OWmp0eiI^dmMEnCM_be$d| z2LWGYjP)zlI}JTUV)vrI$>MC?WBP0Lv3py{OV2m9?>dG*2pa)%Qv0d`Pn=8vauNA# z(4q=xkcy#5&3CPWK1ltO1mHpZ(p?som{riCWAi-{JSVHaXN)=x`7x^_o z_z66@U}1@?b85bd-OvXkw3K{wsG)a774+AU1)|jpc=$XLjEMQ3TJ*`@# zyNzYYLA$=QD>*1)SeZT|fVL?+8MrI;A*2TB zYTzan86pfCoD3bh2l!|XeCWu}1JCAr{L)^!RHnz^mu^|bc?IBJMFp`lB0od-#K$yM z_5nI1@p`YP60Zjxl3L6q$U*rMuLm94XK!t^K-amJz1snvNKE@8{ue#G1u{`d?lxp; z>WTwfa%MzN=+9-qMC;rW(4$g(wKn`d&?0z;#8^e(la{!usqEJY;OScWbP%T(6!!~f zY_~;*4zgmbphNEqyg-LCWt`9fH&1!g3tAq@CQ3;o5oVr-$A zIJVFj3=NtVY|$VGvb3CcAT&tM;1Zj^oI$b;Tfs`;M&Kw3+I=JOAOX;zbJRjErZ#dH z?S?EfKM`x+L;Q{!g<=h{UgJ!_X#f~9z(37Lek%RJ)gE$)k`V(vB8_}PY znxBy0AbG-FMw&YCq+*CyqC-lJo)PeTi3ccxuO%NZ^VnDq7*BHkh@3r=f}Ea!{Ok%Z z;ymVTbslpfw$($kg53{eU%loFZ*C0!z2yVk0yjm#jO50o!W);fu7lBilA$+~iL3gE zSmD|A^d=krmCqUQyYZu1^rl^v72_#qZK?V^&_JPOGDo2^gP}9ivC&t7ze01;p*i}( zd_{8(z~5hi-spU@2;YNs{(F(p8oPWs_%|7NklM(T?VN`co6C7f2Z%kVJ`n3H`7mPp zmfWi8IR}XGY+>HSn)v2c1;rt^0xMnVUu@(e_Y^W$(YsV0%-;sOl^g_(5j{+N%~y{@ zrvgsyn1oz2x!83zu#)5`G{%lCfc6v^?hcY0TxbfN8QT6dH5Y`w?9h{;4H~ky$jmYZ zY`WwEh9dK1nceZ_^oO>{8A#8Hz5yHveGz+n7BWx57z$zW68_+ip&Gvi=Rbuo)2)o z=_+W<3}~3F-7NHViJ$t6_$lo2D&A!)d3mdlmw((@V?OH9v({Bn_d&_ZoAiOiP6?ig z{3QB$6*zn+Fj9rABQ^VbL2E_V8UT$EJHo@*=cP_gHtQp6v<-N*^sQ~iZK<1(-J4Sb zCrIUoe2ty44*qn_#uLUgY(f$@RSIuf%$~?OBE85fkH|Zr{F;A-=e7Yaw-IL?56y{B z-DF%xe0eZ5`Z8!}Pw2h)o3?xS(m#Ohit7ea|CwLt%s|#8j=c{bm+vBGMgMBDrEhfy zb~1yv8=2#qhn->@Hi#>Mn+j;A4ZbuH8_$$8 zJK#&(%pJrlNN!k5bf2EcHxgfWcyy6befUKn)%8k47|NDL=@ zen>%{k&dn0=7=%o9CXUtmV!Hxs~r(OE*ln>5Ci4%}oA$0BvGyAj7C z=Zi#A+rs%~nL1x&6R>pnv|ag_ONJKeU9tOAL(jIXF-?7qso%@_B2~}?@ddmNyh}ZT z1YmLk`*%CABQ?P`QZuCzSvh`*H!mSe{Nl!loImCvlf<_<%%!0G9HD0ETsJhc#k(`(?uTn%)Aog$;VCnev!y6 zQJg;;fqydG{E~AZUdTISWbMc?%YoGwz*q4fW+8{oTtvKB-XZ+hiKMTFnpYwV&P1M& zb0E6l4@!JYR%x7mE|TrTJ2G&8$G3m!wyibpp)OidK2v#y~(1~NadND^ilY1#Lsn~k#$WbNOb#~w%m$SJaCHJo2tenkVrEgy1jomc$TXt5N zq1bf<_jS(ZzMJ@iS`WREcy!TGH0XB3j4W3t^w5Z(HtNBP5TBrdhw$5Fpf5bZbHUjC zBo3xMGQc|atLDdzNcXlr2!YKko_fwMQWf3kCL3n>8y?9 zRm*uCv*_a$c+|R4hg5y0&qtM*E%LLCt(isUwRe$AIlMscKwYM}%(2@V@-*4MSorsH zXtdCl7~;cElFxhW1aX}G!WA9a4sMiiE}!H;&3tpa@$9fHbFp)~+0C`xwH-ZtE_(QN z$iCIo;TIVB47&aXGE5=3kjA>&nd{*tg~mg`#u4aBkN4r(OQ^j=&7A#b3Jlt?y+j)) zJaKf-5RWN&D)GQb$-@~8Z;SQy5kzrz4bMa+mvv&ISENpvUH7o-TgJ^6yqOG(!%i%hvOd(SN`E;SDznsqV{}@_${Y+Yu!>8R(z@zA^cM7 zHvckh)WnYGdk>_>t@!eK)t!&||K-=)?dR9CGw0p#4zb^=y0(Fg2|w;ismDuQ+lo+r zsb@PO?)<2M)Up-7pX1*cpZI@Q%KWKa>yY_Vw>Irc`lfEJ_`r{_Ru}az_P*6EG;b~V zJh1m|?#qGeZ=g}CR_zt^L9JR1d@fggH0>7^AN)X>8@~6fw({MvwNjsV^CiA3e)p6% zJnQp)S*w-!++_?o>fNUOsp4bLmo*h1dyIUKvu==ozV;iV^07zD{rhUghx@tTcw|rd zM{(cdSO3KCo3gI`Bjx?^wNlsj19iW_2P}T|{;lNxxLWZAzoqV5zFx5fczwMBrvZQB zIsEGfp@-skKL~uxhlYJXpXdz(_3f@mfG-@*tM?&hC9>0L(|qBTdplg zYldEF)4r1NEC|;Y$T=2r4g)a#{cgq*$ZzOJ+JdX#5&b!*BCQ$cO!2<&82Gkx&vI&_ zV{~=gEc6fkD1iSfds82t_*(vt>)hM9ntobQ6Fi#dw%vj+-A>9+@b$*rC0_j>L6S+G=%EUuYh0XFW76 z>*fh9(r$i&wdm(rivHcyF` z-wB(i{7HWA-aMs+{0`qdB}9G)Zl2Oi>-!@6^VgTh)t(Bo;PT0rwX$;X!h+2x@;+J_ zlRWDZr`DzEa~OULE<-$P6T^O=1TIf_;PPkBcfETcG+w@W#|3K>ZPZB{??rpord+NC z<~--bC|nE_KZ*8LEACBTe**&3MqbbQ3;zlLPrW?r+HfsWoxkCS(?{W3UfOZKIWY{J zNg=h;Ubblqb~R5Vj?1DUg12tk%4wU&Z&UEn)V_5-Gk$YLGi|N)orW_$5*atO-JLu6 z{%+QP58nx94g!xK0^4c8k#)b7adw&2zVj0M(VBH`jh!&YPQ6E;cfEc8N*|5!KF0Wv z?`b^W!jFFVzW>Vw??o9d-V>Nz&AnJ~^%<_^Tpa)NaE`PWHf2 zHhaE@Ghk%D1%}tspISrWA6K3mzj;ciwpL(G&Mt{%oU*3!tnh{1{K>k1>Uk#)T2gUY z+ParG@5cMw`<{FKkuBxDr@5BgxM0@Xdp?q!D>IR}PyaJ;yl3D17OwPTTnX$!6n(A* zSH5E2f4a#0p6C0G_c7Aw$@@!r=PLT}#W(L9eCImjg7>41t9W1V>@q(%@L!AjE_gS} zh~Qm;h3?!FSUAb=D*i6TKbA1Jrg&!u-t*<1{|s%KcizNvzr{PFmi;#G+(|#a^m{Aw z5Z?J+{dXJl&MSGo@!CfjrL@WX4}NIP|7)%C=QeZJq~gif@y^ml z@=GgtbfmF?eudruWANFgWl~>!X{wJk7mPdFn85dB&d+V9C;3WUamS&9^<{`j9*!X&1UG@Rsgrmvbzbt9dbwSIzoFDkt7Ios6U*xuy} zBd`BX+5Gizw{R-kGcJFe`r6a(#i@L*|0qs<%sY+89c4`Ntl_0_>irAe zYh{e_%y%aD1a@!c+8?Jr;NBm>sodtjk6-41|LA^~9mtQ`` zIQ?)U^%WC(-BHj;=Go_ZnTu_u5BSvHC+-@$D}F-N^UaM>kT>`{+jMIuP9`&F6bQ zx{=jCx=o}0&}|ZZp7-iDGFO>j;B9{W4Ql+p9bIsO@B8RhjjqwHUq>T)R&Zi;QWg)|g zZWJr~7aQRW(6o%W;oY3k0vo{cM;p(-_2Pq~7bW3Kmvh=RrDp)gt9@(~s~ubWc>Rs5 z#WuCT0~^otD`)-g0^dY-58y0}mgsdS{_@}SXN}8CxBGB^nVGmwbSLpsUzLCUE%`qn zB5mX@{x0YGJI3;Wg6&8nfVtS|&pWmgf5~3ijlR`)nB)0oTBMgww4!hSIsQ|@b}M6A z{Tv%)T=5mg%R50yneBr6XKF#VOnY!ZW^B-{To2$nkZU{Fw{v|P*Uh*N;yRK4walh{ zNR9Wkhu^-+wRc~8dhR9s!F_$J*`@b&sb|hT>gW8&_Vr57zBc#Y*YLEF?;+Fwo_%%m z?fQKUOB=a@>qh(9jD4j)-+lcr`u6VY+~3&OhdgsUp67+#|J!}tVsDJEa_!yMt)6>7 z@cT#b6Cbmx z6Mgoz)o<+U5ymDo>Bagv{{P-r@%c9RVuc1j?YFny>t|`-rD$?AazvCN*Yf=He{i2a z3A*$?ulB6LE%j^g$M(60XP;yI_c z`48^tfBeRt-sl;BLH+pu*q*L?&%)hh{5HZ}c;mH~*wZ_F_Z0p*pdP0D_LP3c`0Q!? z|G}P~U@ii0v+LKSVNAkXFN_gvEY}l9(8V@M;v8&+<2CKbgowYKO2O{t_3`gU)(=(l zk2EeXIRBQ!1Q6?0xR!XY50Eilw6(5Y?(;nNi8G8g&M_Y8qXqA*wY4TbtaYJ0yMfrS zmmd_F+lnEOIFO?}JBKz$K&yFklnm8iul2?w`p@G8`iZYSZ2)t4Q46THVV^!}kM6R; zW*;o;A~a_IKP{ZBMlPDdch(Y*@Sl8Vfz46)fi0$5#yf{`$y|NklX!+7c~{jF`;k(8gxyQbFiafy8XsiQTYKPbYvnTbglt z<{i|_(wvXmES!?ZqE3>?q?YZwNm+MF+Q^Z}P-!+lS$D#pELpdvpYuKstPMI2{dhCrw`JYR#T4PnTGmd*Uu8+Ulm?kUQ z=QH+hp0T&BAA19y{BP`Ed(ZkewSV|b6g_Om@5S~n*7MBO{Qj%^w+niEsr{>F-32GM zAN$w#Z>neiMqXC_))>H zJ@&T72YhqZ)dSGCB8@oJE;!fLc*m!`ziOAbv$lrIr+uPom$-tq#(dhPk0O4FpM{RL zEo^OXJMW~e?YwRLeE?2z*44ZhZI@RsXB=&L#>Rc`czB1H+cw6tyuXX*yyNkX=U8y)84Qyt&E{Q?G5WftRn4m_@1Kwimu$o{@uzx4q!i%*w_BhuRIl( z?v-!6HamOlfOP?Cjgh12Cq?a3E6+ZqjqKvnW{m|o-KWhON7~3(+K9^^p=3Auv%%+u z{4Pn-1TZ40H%qLU4YXN*`7qBpmZ%ks&-gX(M?9XJsb{Xp~ zc*S_Xb{Vhuy<{(Cp0YMm*o(e)$2`vPVBa0UfMeb>?2E-O+g1y|$v=I5l)$w2yWa6g zY{Bi)hZ>VZjnz9Qx!2F{o_Abw?|Q#`-m%HO1kbn>A678ZIA-D0L%9k*usLODqix<; zgAB*$Bv@^|JxN{r*xRi84Y3C5+SU+jU_IXuYhYay8xU*RtE}g-wq+Z*gx*7FVa zH+5|%Ho;@xvfd{)!T0?D>~FsP``F*C=dp+RK5xe!=i6TZ_Bh}7?fo0yw_%U-eLtYV z9%qerXyf;7BN{&+IJ(}RXFY#UV>~W)U#5FMvU`?JAyinhX z_xnzFzxxS(_klIv_ieyhqECNbSVP{*(8@is;_xe-rEfRLW3J{}&4hPl&9$$-d<*}> zyIP%Ud*5nXC2j9}+Ll>uZfRTQXrIp@5sEttc)INnk5WvLoDa%Z1iuV~oCWSRZ}*qj5eb!s9P z@HdX{NgvufDt{#-F1F#`8160LUK;DF-n*&c-kscA$i1bkue!ITXMLXoxwnXWS*)|V zSKDx}Klk3^UODTn?p@KV{=FNx_cr&muRZtfZus6c+o zdrKSconE9Zc#nG%{^q$?+Hmg}_ZD+6?K{ss?YjE09ORyYFZM@`vsc5tecV%PmP<`H z-k0@XiC=3DusDU^mB1f%i?8y5xeDT;DuA<<{5rmt+Vk31oj>6|zXLzzK0bjdf0LX* z-v5sKat(ZR=2zqI?6Vh_WAF=Ph+jZ>6Sln!ZNhcVxX`qbSHq7l_TGCJfu-ZDp_FKf8X=D-sdxa-}CFd&#(D?&u4m{U;F!>|IqvV zy5IM_&=$4+|NZ-(pX+^o{qKAJdGGVN7e4QmhdsV2;K)N`BKkNV6C5ik!?>kRi_|EF4-nm^{C%J#%+B&cOn{g>$ znxdgT^ScgwSb6SzjKZJ%>(w*&bM4@L&WQOcI5P42F8mD&2u|)C;OLSRNPZi6oQ^+h zf2y!M25WJSyF_aI-q9J>(S9vbGIy9`=Hw&$Iy!Ykam$ZEd z{qXH$Ao%Urd%ZJO)5z_07%z898~NEn@eM;?knw}HR`aUttqNlULiAwjUH1zJJW_~F z&D*ckzJ9rL+Q`Mca~0!}cZ3HN*wRJ@2Waa8t-btS#vfdB)%Cu6TF%@YHRG=*uei|L z->!tTk#jv`U+OpCTD~#m*YVd+z&7UlytmJ1{pP%^ciPCOX^VYMd(Zp)hCbvl(N=$b zZQ970TsQW4HTd{mJuA9LLvHD#o@?*^i@)-bv*%+j_WmNj_g`q@{pWe#--hU`b4gAW zXAhuvX~rk&{npsnVz9AAW1kZJJra8rv5B60zCJ0jQR;u7|23EB-fi9qb zUzmy|Usd}CoMKF00~1<+)?2kz^j2+O(3YiXy@8WI1p^=C(q=dkg1}eL|NVo6UyhW# ztIki_8p$jl`t6nE+`$`Fe7V?77V;kZt71RWpes-C|Jr6+>SSi<>7M%^s#qS& zPA~f?Fj^60<=_hMQ)Aw8gEJ0artrR9ycf&wI)34iH5y}+cjSNDlSxYU^sd9%0h&|j zUYz9aF22$EejnZqsQp^TD7tKWe1Xs?3;&;g@Hj zYdd+)8rzM|H2f0k8`@1yk9eymr`N8bzDIvk=}!x){aRwN<=w-KMf(2GGpA9WIjQGc-vo_{G)D1^_j$2L-YsLY zdDkV%_{Hb`4sU<9NbEbUj70iVeZ}6S)^-r@X0fJ?=hLvCy}j!fDQnZvE_0LqPM>dp zTWh~;MmBNUvPbGWyvKSjSPGr;UmKZ=ckPJRZM5e8>vWZj({J6wefC>oLT1Q!pt;iT z68`tX$-AC4knhWL=ee$jtIjt$9rP`5)p!jozIhB-xCZ!}87*ty09P{qPsTT-jrk!Id-n zzn6QqfV6il9E>u4y~)buQE>dtP0kYR`|7G zo7Fo1haU`8)9(aeXcTlr_@S(U&KT<9EXR7UJ@5Ih?LR&5MJYK(-itB>9_yd+>`AoW z{5J7kxq?~CkL3&ddl|nMmc+K^dvE@|7tT$sQTffz=GRzo*N44c3p@$#uH`#w@8fP! zdq2Uu_rq^--pf5%^KXY+cKvBBt@+A(pKwpX9Zed zAES&co~vJL#_}|M$v(b>Y!jyTk(wp!htOlqI}Z;G{3r96!*eqB01w>zj{Se`zHqI* zaSGnCkK=pzUK)-4J;qcI%jMR57SUD@ON{eQ-qUzbY?Lh<%`?)7VxEoPk2Hob)+s!z z#+o(fT`!F8q#v1^tWVikAAGI7MdWJ>Upx0}L|cExcjC`C8t6(t)*9LB&pvBCT-x9r zwAHWm6sxU@wi7BhBz8mvsiq?n^wd8i8lkn^<{eay_;|s>$ zUu+h=H0S61FL0UZZJVGuDI!8!w6T(3wI6=;W*PJJ<+DQbRey_xpGO+c`R)^YQbj+& z`UNy6qf!4B&6!8v>YHkRBaJKl_E+ML1PL`?&G&M%l*Eo z<_g-n}rV> z{bEfmS;fkGQST)NI>)n4zBI6fHD-&qzz2lx2YcrM-uTjDfmJn+=K>WiD!M{&ANh{4 z2u&=%q)knuzt4RT+!lDFSr4E5vmjEi$Y7bF6U zY77fx43Wk!w6W&a_>uFZZ98omG(^prJ@nVZ>gVy5^butg^L!f5tA6vXe)DN7XD_8r zlK=b9F-PxuhO(X~eQ58uytmZL<2>VDYmH~E@7g`D)-J|aCC`U?c$epSsi`73r=Fh> zq~`PyZ8A^QmTt9CTS&p1|M*Ug^}w5Fe&l*8{;1wvX}wFnX+wWotTw6Pa28e6S_R zw@ba>p2)Lld|QoYg7yAbPoJtS-D>*_Z2~X;{W<9`mj1LYH#*hx-GZF80Scc=;}kwM z*4vK|v*P>x{_=g`MYRnVnKaT!rtM{9`%B<%ajiHFP`Z0Lk-AdbUjiHO*7`~NvynFM6^}V&yw|8&8vf5VDCh*eKy#B|p z&lSFX?y=rq>f2|SL(P?#^o#Zx=(k@PJj=Rx*2;Q+o^PK+thQIJHZ{&R$Rn&rsfPUW zDgE((jW)@lvtF^1qes(xF^wbtaHrGlQB(-#=*)+}_i z5$tqvPx!LSMh#kd278e3!Zy%YUz^YeyeE3R*CrGQoOyF0}BBkecwmquUneeZo1;w+=R z4}WT%LPFJ=B#;j*&x)PyRmlxjyxNijgui)hU|Hl=X^C-8hbHy%`fVfEt4_5oZDDdz+O^&y*EF?$ zQ6D9`WuLyY1y|3)chIHo#m%9KX(RguXh;4UpufBR*XOAT;xNuL{-un+f_?;E{~DsH zSX?*uMC_Awkx%!jT{&xPZ6)jDTZg4TeX>qY)~S(9bmlRuUZ~LgU%_KL{rkg!e9Jq> zV8$2=EXg|HlY&M&j8@Ds3mO;8T6pK(;(vMGz=PsZmzuXfjLDqDe%X{vir!M{h_dW) zt*|}xLxznEcuCn$_VO)}RptF%vL5^&qeWp~jWHs?Me#9Md8<*z9o*OKQTT2yXhXtrn;`d-2W$>KV$Kf?s{TYwg8be%IyOwBG)3Bd`>;G?BA< z1#TSG1K8tW;3fpPxeB-$6EIi7&ExdX{(J@8*DV5GRst(?fR$EH^{Eva>%VRaZ}4pk z9xB>)cc}B9Z$S5;71{hITKpQ>%Cfc3mpO~?Fy@1{LPvm!E;84vi076z@3pTkC3A&t zeLs`FfKA{?@>BziSLsXWyNpZLbdIO*a@BVOjT1PK_XmPo{%b0EcF0Lz9S1fAK2zyK z)=K((RP`5GJrx|6_nQN=E3utx0a~H#>Aj7<*VvAh$Qs`7p-X=hriRn67p8{tzb{NZ zi*3>uroLc}ePL=9*O!8+^RuK*MMKQ&|D*2Rz#51bMo`<(N{~~VjN0NUC}}+&hP!%dv-Dz611(~-|zMNV_tjD-p^${>shyFt@S*+cb*xDmW4W3 zu+?MqoR7|)dlfna`DL=Fa3pZV(wZyZrs!QnZq*>S1bZy~sjM#|w>BfUZUv{Z*+zrY zq2$+Z7>njkZ_o+SjLbw`A&d2htEALcCw2h40Zt`>aRJ`y4?ZT_}dfnCeL**-pj)b%N z5#l8?xR|SOc|KS1(k9vx-3mwF;a)T?7#`*Rwc*Bgt&JT%P6~dPXOnidz=HRy3{g@0O)kEXr)576TyfJb9?$2&{7u=PqmAH?QY3;*3i=sfkO@mx$h;^!|$ ze2huZ$Vuk&6!TG)?9a8pUvsjNdn$6yd1cv5^x4_I5Xtz#@P*FUZ(#dqjG~{6_ro^c zLcQUCScmNfrq=hugX*w1K484ZsjKm34l&-n5B^=_-DX7D&%!6;-KOy#pr1j;yDi!V zSNRX4v+w(W@y5zI1D;ghhT)%mVz{ww#}smG$th?yaxZOIkWovnT9aW;;OHY`rs&Ev zY6?~{?qYHbil_KE#kY}TE%P5DvaG;p>-bIE;u9ToNt>c?>L+^)Q zXo$D^+E=+&yDeYvm*hzZ?+&l}f@f&Qm8Y??3pyHrR~wHJysiMIDrm^Iq2CX?yf*-^ zD*s_^=ugldb9PSI`a5V!y!0AZ$xBYM`n_w@7|qpnefQg(`zmZB6P!icIGSq%J-d@} zXTW=cv4(QqVaB$Mz4Lkv!|2^S!8l&Cr=~8w-e@$AuRQdu=46b~!#vqCHab>-PPfk@ zh}dQO4eYXSscqW)BG+)#83>O5*XhrOpO_VV@^}OGe`qB8{^0F}=sjx`x|VtG;2g_^ znMR~OTSiZPh<)o8z9n5x;&E{uLtYQA9WZF$1uJ2AzpYJmq#=iC-8^iar?e$kua3N)Wa`!CkW?yhT{mI^5NBgq3XY5{Ar+Nl(Ra1T=W$Pn! zCc58#zS;Qv2!D^=C-5dNpVd9s8ey<`?tQ?S=c8O>d0%#iEmwZWT7a=nreEy6K6*Qh zj@!%F^US2q?A?#n#Y2Do2>s=aH;!lRuBl6k;9xX$MSrcpy^HZDFbCC)|4GI(ig${o z3IA7vf6=p}7Y5qNgTenw1pc3Jjoqv4#0bFK@T!8hcwZlxH}Og({8759#)0{jdA-ut zg4cj|EX(LghG!H@I7~g^Uh}8_f8c-B1cP;vaeUZB|7n9WZlY=bX~q?T?%SdJ9O%9S zy3c{`gWoo~bLKezv!P?}8lxMUvA>D1fi;unJ$lXSzRnv9J-k#?XY(}lVbcXXJ_&kGvT1|-DeA~Jb!a0gSjc~yR-g~@hUlXh`pDzk z7Yl`7=w~r_pY_g4&b3MoUPt-G;8#4X{|or9JzB~ybm-yiy-YgyEB0(8caPIxv@)DF zMJt`PgVRd%8YTt#sP%0)icXeA(MdQ$C&mhwPLhKEuJ$8z;zRCC0lt!We@__MT851K z=Bhc3i9CyzXSv9;V%kjs4;pJRZ3vIW;6nfZmH#gO4EAk*bCub+4FAHnn5$RszO=i9 zt8ZDBeT9btB{u&IZbuG=lV)%soIJ%f6y99GH!U7{IlOCv#W!}+&G^oYZ2#$M=1cyO zQtv|r^QXVKG~M);XZuzawCB9IblCX$cUMaXK~wZU9v#snK8V)QL$$k`@x-=UMPF{) z>Sv4krtK2!BHFJ|`>eMLEzXh9{Oer}_Lcjt3Rt4`x%8JKL#<#fW0Wklkl$8GNw@p_ zzQ}X8UUjYEYhwRaJov53;f~(b$e% zF+04~m<=z%8;QX=N7fX4oVpfqZEMj~`)7G`$FR;d;^TCbX#-HK?I^V&*AC(ZeL35-s;ms{B42u)li@t6k zT#Gro=NQjITl?Xkb97BXr^*4F^_7Iaan1SDnu0&``~_?wY!Q2`Z9Hq`8Ol>Jm;IS` z%*q$s#dwOLotZq_5p-f?S`#<%Ji}wmbn#mKmo)`GV2#FA8?tbp)BiU4F~x_L`BZEP1z$=k~bwUSj7M8Te1LZ*kgrjD8Hi5%|?<$3CEK#dD5j8lMVO*f98l`>Efs z`WE@9w?+G?DOad|dso~D?S38_{v5Pi$ll=_8li1l&)y=K2C;*8@LaND6IY$V72%Qn z2Dlb~%*Kw7wVT}Yxa>LkMFKvFs)P4XU-Sfx*mWJhE;$*@OIDxFlN7v*at^EmZJ%h_ z;_$F(`;3KS+O&CA>ml*2_9rLO=62@CDeDUs^|jmY>y&?Qu)Xo}&tzaLsctGdp$Pr; zG~~1iT9# zM^B#Zw{ZP^<}F;kL~G8Hdkt7;p~@z5pB9ru1{U33s$V$2rK zrEl~+WFUjbe>@_ClWcvnhUbz!!l`sk761F?XA<$_s)7|f`#t;kZbsMSqiaHOwyxPP zUGo#(Y0WNO6GBFZ6VNsD9J-gTDQ7N239hdBe4nmS&a7y?lKR&~^hAp!CZPJVVaz@7FIpN0)qt=Wg9C=z;nCZ-NK#Z`$oi-(1DB zn^*&i?rgk5b5nu2KF*jKjfXbs&vyD*FFg{r^~mE9Jpv5_$0fX1?CVDQm}1km(~tB> zj{PnvcmY>nV&0O1lkI1|;2f@+FX7{I?i=Egb1c)yk?t0aALN;6qha;U(gl6AV}Cyg zT@b4WPJitNbU{I%E|9!Gj(mBohQ6cDS#*3K{ok>Y4EZrUCiwdK&poF{XMQ9G=ffk< z_sJ3RkZ5x-`99?O#r|d!YdEgrJJu-cjpoF_GRF8#_Ts(%w!h~E*3@@#zvIb~fo||w zzpAKPy!fA#DIQ_W*ught^!+{gT*CJn$I)|z&1xsg-{|7=dFt5xFvkt}q+6W$;QDA^ zqsmT<#0S$oXU7M>KzuM0+rEspni)H^(bI(ePQF8+0bAX-EVsKvdu*#m2CVTZwZ6|7 zjUm>dEpJl>+8%0s!+N&I9sgiuX064qJ;*s4lE>0zZryC)`Ud@1bs2EI^^shOCA8;{;90o|!ZS4Vi1hIq z+Al`FXr6?7Z1zIocX0f3{xxmcuzm#ij~@d6i81(3T-1+$7e|BP_m4GN3&ar<9F83| zf;GTM)&OQ8i*Mm&*)px_V0K9f`znnYc^4QJcD_Niu_&+Cte88g;IcTaVOX!R@6`5t zIJSuy+yIY=CoI38J*oankc)-TsJ#!`GUZ1!g8XFfZOhCbO|FU+ycWFnuDAv`uEw7G zG`t&U>oMW>Rn|$8gUwu(r;Sc3_%r1VvwN1!r!S5sS7Bh?wTw;h?7HRh?5!J&18uAe zS5a>bzgMWcb*sML$9XTvwOeUd&;N_(;Yv?qm^di;4^1}AuljpV{Lq+fn0!CYv-*mf z_~x6fmE&#*-DoUt!`4+BtEm6m`&n}s5qN$#TK29_?@SB1NxOaT-W(m6$U7Gw2KWfU z+p@=Pd{|=wUdnHzP5Eecd>j5vFq+!54|l55-!}U4hr_cTgZo zETF#n{u%F|M(*j{tHI7J>s@UI5~+WZa^Xs|(f*Dfy5-0`BXBg**D&Pn@Oz+nZ2Nb| z`g?8zCYPob(vSGwcYIFIcKAs5NpJakKF7WI>ow$8b3}GMB$(i-*N|Q8A+&iag|^+c zF6X`4C*a_$eXLR7))%beIk>DiOE&9H>c#zvm6|cD@5V(v4-nf!<^fZzOkR z@~A)&&t&6G;MwcQj#t37?CA{T;xECe-q~x+H2e>&=~HM6y*XPk6X{9WeLCBxS@yib!0Y_i9D3X5HDwPs7J1t}cDs9cuJ;GI zN)HcqZW%OY^XpLZx_$_~_fy)m_1@_@{dzBM+yK27R{wve-s`5$N2T|kp{;Z3y|%Ff z_1b>urMDM*HcedUG*L`~L$k;x;_XFDS525#d zg&eZ=9(6yA-un)1eN=kyTG|>6|9yHdg8x3f2mTG4PZH4!1J_6Lt!9AV|IhW_ug4(Y ztl&f7HCA`ozDM|aFuivnxHy;I+xP9E_1;+O4yO0KJpV`aUNZ3a>9!cXw<7x82kE_Q z#|9Qs-qm~A_nocxx_BnN_dBjJdXM$$n7{+nmmKWny`%Ty@N*7l9XbO4&`9hG3;V*0 zofF^KyE@L+eV0-vTsf>!<8Pa4vKP+`96idnQD1U&?bUZjbl-*ko@>eRZ)H!r>~-~p ztlaPGo$Knp{YgD@T-~?-HDs8p`+h^&j41}^I!U_Eeja20ySnfBN#t#?F73e&8cHKpg}*0TIgP|3uP_xOt2%f= zPxx`2Q(EI8FJLTZ<|Ntv#%(+PdsN_^vC=1#(Jx8C=YUClO1D;_r#5?%JCCBuklQ*O&V?-IAz!8{8`Q{DPer+)kejzN%QaCja@2ORDK??yocZBe>fL$G0(>V zS9Co+-vaFTKzyvt4(NX?{~OBg$#vUX%zw@*vd`oL}Xsom-2&FQ06r6@%hS)cUhp1}?Y9ShI=1m!GX+)Ivg zpWV+nkvY+JKmVice)+r32VU7xk23f5V~oIk^us!FJKtfn{VgZ3b@blZr;!v~&3nU> zR9iEAO@Z|>W0^aKl{^peZRPaxtf+BJ44z>P*9vX8aBD32k+DoV9o}Kdzm9E(eP!Er zNAI84c!Vw3I)RTyfU(%tb~1NY)6Hu~;|AM%BBLNW4k!Oy2pi zuisk(48)H7 zTpb&90kV8PGCd#Jeho7IYJ5Jd8((tPjp5aCta*m>ZUkjUQr1H5Bm3vY;XBaxZj4}y z&L@fN0|;Gc^kAdoH#Au@*s+Y6(AxSP$Z`3q%IG)UGLCBv+<*^Z2JbfVF8wXDB2#!L z@7p?Fl&dp`(odKb+v7IY=?oUPoK2s|+)8{BiTET~?;SHH5ieU!yo@zslkkCzuEPH* zo4(~%?}79KBcHP-RTX5@SN7;}0qc^->M~e|GX5*G5BR&i`;G4TSKVLW-ES_l%Y0>A zAe;51_jf!VhOJI6ua9x)UU(J`Ed0|c^q)T5Jidf+oH|{3DBVoq z2<>p;DfETLu60Ex@Ch!#Sj=9;`g=J$g?1!k*7NRn{O?9@>?+I6ZTS)Moi<9((cbG( z?X_C+O--z|$FL@xBTeZi5yE}ooZq}FC33r{MR zM}BT2{k>+xpKQZ_vJd{`;Lqq!>oLKvaiDj0WHUdfkPr2odF#XqCI-JqIjzOAF4P#3 z?J=C)rq*uB!Kb3yY)01Ae0t5n{5PNNs=4SlUHMo2wJTIMyE|(t@(;X(%aCXDblyy2 za1nm=ckZ9lSb}U!C;zD(xHG$jchiPjYqf`I+m8&fX|zAbe!X(JhVd=~TcBgLXohp? z#wr#(eOU+_VlOo9`qt$i72o%+m=FEu!w1*E4_Cu0@Co*h?92dd#QH?V1FkRU8T!&X zs^r`LM$W9NWnCCh&X(p@Fza5lvKW70G4gRS<%{Ll10N--k5uK&|u^K6|idD&v2Ffe&*|OjK#y4I9oTyhvl9dGl0jL2Wt)E z@Sb}N|Kg5;xJ2|Ayo_CYXXYb6y(L+>B_H=Urk7^teg}DQQ$oaE8j}{7g>HTA|D**j z<$CJlX@S{XXQ!nFF5`Oh^t8a`TvvF~0#|VT-l^0;`X`MF<(8-4Z&dKTp2GC$Mnx6z zx%5l>eD~LRHyQg$ z`pC(b_NiQ@QGtz82ru=BHaT0Pz>ZJlrv>7{f#Mh{FMZofOD=U73LHvEi1{AXg5&4u>I@JuprELU3|bN?XsuX1jYWOY}U6Tgt3RB>0uj^6{0 z!(|zq^(J}F{v-a&W)nT>{~!4uyMD0O?$}hySN;L*R|%KI5Aq{>(_+^lD*s{gYHw0| z*j&PeU>a<1TC6+}oZ6$MItI9C0G?R6rT8p%k^G126(1B1w`r{OB^-)Ym-XSzJv-dN z(a$O8$UI-Lj{C~Eq)ulq(ZJZI+kXu-yO`hL`Fe4|xMAHdC~oP(qI_t<^8jsU0K4Xn zoYd`_2WPIF+=1`$UV2$_(_SMohs$|p>n`r^y_>99*^r(?jHXJcW(!E9vLe4Px~nMqgTeAj~tKMM;R?!wT}{-aBv?Q7kEbF zjO5?RzNzMaeT2rL_t~vekvHtKls>qMcZS#4uJv6KWk)ggV)kXUQAYN~GTy(=|H?A< z%SF|j#dAM?MLmmSJi=Qj&ZxB%lOTt+y*FIA!?p*K9K9NmeLJaV&-IzG^y_||&uU^f z8KQUe>qWd5PA70>O#7qbYPL^NIUn%F;Yd5h%x4X}kp*wq<)hZ;DxdTr_TFt!pU^`U z{1ChM&XKde;3CRs&n7y4f3%K=#tKE-gYDaNzpL_iwXyNc*UvtaUa_>u{GPQ>*2YcW zKH0SHdT?#YHYR>%f~!pC`BT8u8a2-&`7b}A@T++iEk4h)lx2pUFYy!Z(~Xo)4!|s& z7@6+`d%h?3&G#8#{T=pTCAOsMKNYD%?rmZ8{69}Qcm7vV#h|vQdaO4 z4>AAG(5~kH5w7Q&|01`Yk6`{2Y3qaL{{ZkPA1ZeK=bSbF1AU%nzWz)5JjP_|D;5;} z-5SM!2F~+&-No>!<~b{}f9Y20HG8@*#de<2imgE0@7Uby#|K)Mz{A)=;X&|Z^B3=v z8CN~_y>v&3Or@d9 z*!X?gWZcJ)!ht!^WiHp)l_NSFLEa<6iKh}`ew`fk|3=4Q?N>G8Ht z#%^!ocEkjk=_c$Di^zBgTRq<3M1NI*HG<{!1@f|LUL3xxq8=tOdS7dFjx4a?=__i|jFb<4J#GGi#GP zavoOW)AF)MLq5?|&)T{<gD z{)%RBsCTzgSL1PQk}vT;16X=jEM!azSgSE^kH=nr#@cXI5#2F{_BAGBm{EJ>vGC*H zz&?nl%?7Q#px5j#jt?k~dM&y>p(H1_!!s(VTn)cv6qd6$@wVlu6CN0DF1mfUvFKTR zGP^jh;Q_8y**D+4gjo4)+&{R(ShS1%14kLx<{q;G+9=$-(yS=vnqb7&mf)j%u=lD% z7nk0id;4%>_5-8+k6c`OTkf@^jlk_*WA;(#;au|Rb;ganv}IpIzumk)+JCQk{IK$A zo!a{V`6OFm6nIK6x#+AlwdO`PbS%!LLj}ikv@e{u{f#|Sw85FD+r3=1_dNl;C$Juq zZgqSBzRn}8KW~fk*4CQ-*_F>aIS7@H8WlOL&*qwir^z=gEHCTGePDR=><5{Lhwd{M zJ#hcX+r0%+aIjVjzRdaR+Wxr0@e~T(x9x2;d zU2B)Uow82@*R}73FTI%G)8j|ww0q*6y?DSHyM{Q|T;0alt77&J#>%L_XRgv|FXIE| zDthl=c=a&+8KYQZj>exc1|As;uZ)BL$K$gcHc&@xJvZ-0zznP>DAK4WZ`?e+UL4;Iwj@x!I1sq)eL_O)*v(TIN| zAlV!G;c(kO6`E$)-zRU)BMyO&vy@yu?|5VO-Y>5yDE&CTInE_-NTxjPPNrTrafrWLQjq}zgL$Y$Gl*delu=d?QhVPA@qxdd`kZc`%js3tzAQxYtF{i zO7AH)i4Xi~_CgizE&En(4&@h6ej2i^9NkliK3c%lk3QN8zOuQ`Mjz$vMSjx%{LH;| zImViU>x|Z}Y`z!pvG4j%FGeqoVI6!J8c}RDs`R->5KwTXw_dxKW*JzrC(5hZu1u_CuaIs#7+=?PcY; zxAA_LX_ag2e*xC?|D+!4tbCrUk3HBrF3l|FUT2x4gDYgdUFMI}5&k=vBk51)-U^B~ zbT9vomunGi&0S#>{%xAk)bTT;v4=R+G2#}MXWYI}n$gpqW;ErQMnx87t)!Z|$!2`5 zXmT<0+k?OVjXPPd5KkKo4!S?-?{Q_i^-hr;msVfdnJsnk&1(+k7|ngO zoXS~K8{+lQRHLV38h$=#b$+!mKE0H_FIkrwy4+}bk3IXL>DcnbTT)H0P3QK0k%h+b zdcG6aB40{oLSQ2MMHKh^{=KqwQ##wA?+`IS#e}NBy+sV(OZ)M(pGW)om(--TU+!m| zR(Un}m+j#Nwo2@BgK;h>FUeg<`D-a(N%?iaGp)3QIl{i<*=C+SeMxPq;4d;0%CTDu z)z?&Da`D0Vn(~vie%1G=Q-TwR5$gqiRWFBUN^YP3b@9{WU@5Yj7=9q{xKXjnQ+WD( z=3me9n19JQ3q0$*Akn~9=xGx3DBF57{=#}-EycF}sCZp8asqy6l}xGj<`H&M%cNxhq#RIET3vz1&BA#U~fP1l-^}>m}Ak&vE|J9`Uo4 zGmtj+bmf`x9oY1RR=Ph|<=PqVDEKUWE%}kxSCz+PO4++Wxn zp21#*3f4Y_3z!Gy;(+W#(b#`;Rhb0x8M-;QF#358&x_ijfuDy9rvY<$=F4@Xpw)|@ z)kfG84o>$(*T7kaQestx_t^fHcFo%mvyF6EAW&d@4VuHh|Ct9x-=wu4Ixui*X4;&7UMaR@&zgi`; zb6;m&Cb?%t-s97>ZHCm6%X1~u!f}&qer_pS4o>@J)y>GN_kg7&0!udZFcd6PfCb-! zZDR_Szd{qCANm^=m%Vi!X9sSb*JybxTh8;{BKa*3Nd9Iqhl&}qw(eO5zl(RJe+KgF z{ytf5fDe^Tq24Lt+o6%per*r1nc%MD$Nom?$x8M@>$}|2?V=I!KpFg&(7fj0G-H2P zg7Ie80yAOVRoEKxMTt*!-bWGk@M7w0m!71A6fWC@G8^`zc zz_;K%0r_5pd@lj-9q69U>2n%^v9{AQEm#Ua*lSN@RX+Cm#kBD({f(i&PZ)c;c9~;3 zniJR<185md7-wVtG{C@nw$nz)7g{SA93>S8KMh6w^yo2X|qx@lWY-jlewRPqE zf1Cf6=9td76XC);kXeV35zVx97`b7hBknLq@B3T2Q)f3iuF@Rc$-27mS<3#1ar~HZ z9A+GEUGiY6?20YOnbFYS1L%`H%C=%#K7^m)HR0*R0sh8qi7@X7emh_ zz%w6syyd02In2ql2yK>LvNlz=i_S2Vyup4cXo$1obv8{k^P(KSeEBMwZ`n?z_)O%N zvw*3CcSXnpKYiz5(=5EeSX7zBnHIoUgsy7^*PWC}XU>St7Z&wK@vXW4V1jY1k7tV~ zl0S)T%8!zhv39q+mOixt+u@V_Yc5w#N+#wePiUT)}y9;)B7{)#|KuL_|%2RQO0&;#X;@gmu!@;Sg^I= z%c#MZfo$KI#lB;$CuEnYj?TQSisw7q<#*-wOwDgBdJjDf%th~jU*@NXJPBgCh1smN zC7bs`mnYGk7CwkPa)6?J5RJfEd_g~~7tw!qic>H99Q8I)uYPKOJ;mPLdS2|hq56A} zdaarL^~B%V%&*{_59~wLtE65=Mt?oUD}*P@m{dF1nmP;L!%t{?04`16qGuw{T>Y7f z?hNV~b2A6}IBpmlmtZ4GK6Jo`9q?5rb0gV47aX7BzKr$n+4`m#eG}@VU9GLOW>){3CcW z{)&w$dG}|d;@8N9$_KGm|AIXivF$IRUS&Ja^bS7D1cr-vmQLMU8H@V62p)Y99^D0x zdVu*sa(7>1J9IB%azU$f2;13YHy`+d@Ai}JZh(ba_N+7@Z7Z1 z``|+bYsdU(sm1pT8|U4W%QdH^Ej&Z-_`fWk_v?61TjeEVstPj9{JWc5!-e+y={M~R zUi?5o&V$d|?`tR<8eP9sWwz`J7oGu6(LOQRPDAlw7rE}7ePi1z@~^ovq0gUU+fFlc zqix7x?>V$k%{y|yH;OLW*i%=|z1Ebn6}K>cJ>N~4ukidBI28}OwwEh!CY4-f$0@?B zrK-SH3+tI^z3~O~MznmB?bY392TqLQ(}}@dj3tA(qkM(k5!>s;p=%nYOYrLs*e7Pk z8ORw?OuvJA^79rGKdDhnpBSiJ{vU|xKOq>%N2wYlrZ2grSdM)1!#kWL%-)5;1?SYaL+lg8r)o~cssZ91itkJwoG(v?kZwug89q9SdXt; z<9w7jSxqGGPw%xJSxX!*aS(s}V6eRsf$b-Qz}1Ehb@TdkUcr6zD;$#4Ot$2#97UbaoD}>6{p+1&CfPZPv9W}~V1FV4`x>r; z=LPBPVk4-$p4T~>0XQGgyAn`H{SVXr7g=r}G@5`;)yS*xI0B7q%k9+u6*#dD(9q zT~@GZ5AwNSOE=>>TQA+5s`#m3(^atQdag5T!>g?W_B^^dF2q$bk`-6sT$m&$M@u}m z8+j&r@RJXkMZ4bSH3zd<&ji7_Y_xdRPzy}2y>2Q-*2(VZ0biF=b|PhSDfTL!_2{IZj&Yn^8-t-}AFj!#Ch-_4$+&Su6VIQ|v?SUs`LbR)U5m~}`p@p8q{ zZ66r6nsA(FPV5kV4c_(P_c_)tT7L}Eug0iynqT<|)qf^DH5FJ-(C06BE}HogcuMxM z9tVH#@;f}jIxc^q;QBfEksN474xww5PqS@q3;8tQMmU{DT?fCu;ODp(emBRZMDWY^ z4uxOxO4QF)yl)`qjaXCQGIXo#%2@p-eTI*~)^DGpJoph!G?5E1Lv6?EH>u(Wyc@91zFXVVhToq@H`#RC5+GBM<^3nC(C!8qCmH%@Z zK8|u?LSM#DBYITcgZdKvbp3VUS-RPbN%(7k54GngR*xYk$Tu+$y!+WWV$B|MO~A!S z!#;2BS?ZQRTOoW(Vd4<2Q^h~FUDrfg6^607&ea3%`Ig~%aR<7KhGUP6z%JoDi52X- z@o3MDz29cNyWd9nqGkrZFvGI_M$zM(29L&$Q+Q>r0*lexs?&x}()Gy;SvOO@sMM@@ z2KlEsuSX^p5tFP&)@4(tRCSPZM^f0oXL|Qd!zXhaak$MF7!@^1j-N|qupewZBBKiw z3){}z6(MV}i3^L6wI(sQEZPGnJ?NK%zr$`TWgmmumhVfxV#k-(+;tIsY-X;m&HQ!U z1NhX|FjpEwHuBAd#~y>=%A_vki%uZJ=xY}3q%^NNcqw{Av~9nmt(VW2o=LIw%wTPa zhJA64yl~;VRdA{84^dy^xD_9YUA`T^7WdKc{yl98mX+)Yz%OOnxUv%yI{WeU_p~Lr zR^i*Q;lkHvrVWJaD89R&GgtGOQ=L;%15dZ3!;8pCF^+``t0O%23O)qQsXK>N;Q5L6 zewhB5Ioy*Nfe$^j7#}Bc$EK6-h=#svR%8(0FM{Wrp~)iTh~oV-#yPsKMzMc%fYl}) zpflM_ z*?ocYe4fESb{S~K<|Fm3b+}@lf=zJfS-xrRYiBK(-pgJ%VzwucE0Qhx&XtG!@6vA? z8+VmWkK}q+9o)#-BaeX#!}#hGSJB2?Wb$|TKZkqy0+O589Gn%yD?yuAlF!L2uX5HC zYYLk_zY;|U(X{zN?Fgq&MsQjr+LRv&Jh(i*g!qN_!?<&ug^XgZ_gihL1Lj&jwi(z9 zvVC~((8F6vePy0xoS$XPRp@NV9_hQ13FO{5`QQWAhP&ybcSSz(_ZsBz)vOEI@5R1H z*~3N9XGUkZP-}3v4e5uwz`68?;#iVHMn||%@e1`N`jby?1Z9*z{O)ImBiA`EXtl|A z%wy&Hly3Cp`slrltJF3+#9%!xJ%FB@y&W5*hW*UeFk=U8I5v>JIkMHsDeh1m?ng0Z z^+CCS_9#vTH#$>izH#|6y|$zes!7GTUWCVQUPr*QY;Uo$=drDq1`Z%?*`@EW1@>Jz>+78QdaY4>+%) zKbu~_X|x{I`Zy1~ZGk^U@9~rUxjDprWp`*Vsp7)29a_PwZHo{C??CQwDAKGV>^j+3 zUdqPvyo@-u{N(a4>ZZt8s@?W?aDnD6e+%;^xY$t4k=ryb#+sf_xT}&u2a7MIQ*q zyNPF~GOoLsZv!9kDrgS9x4pTf(j9)`-U z8l{|!)Swrg22J;}{g}u6Y-FF1`1(1)`d)ZP0c9%pIr}Ip4@Iu8quara z`jigLCl5k>>c4bGK5+;4{}FU%K5+r}|E>Cuk6r)YL-(~YM?YiShq+$P^?$i)UL@1c z#h-h`zsR@})^GWd{TcrZf8IrV(EK_16Pw?swYCeN<|m!G5+22;=UTfp3?lP>`wd6t z{gkV_A8iD-q5&LMM83(sm7ha4i2NMYTpgNrzCUOJkL&>LUwiZ}oiXTqW9(gYdUIqv zD(}){2J<7nX{DV!+Ee@5kEeDj!GUZGcQ2gV7WVn$l-IYB)@Qbk56C9FgR0rSktSXV$E+u8K$l}U8|ztQ@hjBZ z1uPGZ-<wAeK-^C zJ)7OM<@g^b1{ctty-$cXtIkt9%H@+^G9~!8JK5hu&dg!6n~=5NPy z^rik!fG3^Jl#l+fN-kYis91o;Il|bXy-g82dcasGM#g#>SJ_1^*oHbAP%($>NdLNb z`&Zw`B4a6@z_)wI`FGCw@C6^^c}-kWt;W_4JUX}Gd|(UNIrBre_dk*LTCo9K8(cZt zA?+KWt#o2Ticed};%HlZ2{}N~w)hcpdl?0}tI-(`-f;+${&$q(=z&syRVYd7oM z6yAj{^!LQBv)af3I@j4Ik`KFRXE2><$RBQu3)}&m8SDux!JcX{jhR~Ks@`*h)U(F} zY>TOb{cgvH^WSs6GxpEuSs(5B;k9$Ek(wiLIr0vFxa1`;N*=Vpli5t5=u&#@w5KLj z@-%OxbEc1IEYEYcJUvN$m&S~D!cp=xDYz-p_F?u0V#m)={Uz{~+twcVAzC&cjcTj@ zSa^F6aMchuYoUJVLeY}f_CLF_aQ)kyQvn^dM9#pOAH%b*%zcG+MML6U&KOA%EwsRc zqW}5GL2t>dTvrwqMtlkl5uXA!xbq#;h}?fwZE=5!tL8G6j@$7YM$@qi!!r>W(7`*d z0|x1f8k>jB&b>p_*&M0U%2{5>j+9v0=85q$tRe?!Fdn@cJo)-~6#f8y`8B4~zQd!w zJ|4AsnRhc?JVpE+R>_Q=H4&L1Sz8RfJRiZqDVvv5`gl2Z9)$1PDC^RR=3zALpX7OS zTuSX?+7ditDH9^bAerRj{fY|K{phFI+yeG<43M8?T}8QCe=0^(j@)!(8j7iC?OTNX zCSOOi%q?RruR7Q!eX$+jvg0_agG}EpKbLJ&Asb_DXoF|+Lnbw^IXDx)p*=SE`g*=Y zs5pBo@=Uzg3=E20mH?w-hBd&k)?S|{*>;f8~)ifz2TX%-O_;}gS92) z4usBxXKGJ~WXu0>9V|aUak(v??ic>w#8EXiF|upG85ffAt%kG5{^QK+ApW3#cn|9v zqKgk$Q@AmulQ+)6ciI2laruMfJBaq{NOvnIr0tA+xxOH4s?I9xhFx){y^l%$5eu5r zm`ddXVjlCE-D4r^4GQb3Bu|w%3l(naa9x7w}^9spw4pm<(bM z?f7zj%>Q>-Gpyy_&Y2TWv<+O>UCr3tb=`kaelTC(-PpygQS0Dp;Bez{d#NwGBsw1V zo%h0zYi~;nzJOu8Ki6FTMDNe`?ft`Z`BmEc;JF;yw-;V*us7ahe=GifkIsW3uk+s& zM<#D*B{uF#@22*Is;07^t}R$F>dB?qD|0sG^j03q?)~Zp_QWL^yR&Qcy(`+WeTIXz z_uGG_Jay<1 z-{kGRW}#Jsb9JC^yb z;y`>S3;brV-c;_~QOcMZI@5`mzn+ud5k6|p9*b^hpE^I=dhWdO#2v7WZ;rt4 z?YU6A#G^DxRQSP zFyGgBgtnT|U9A6m-iUl(16!vjiSIjvQmUHbo;we^P>x7aaAyQI@z=5oE;dm?>j^+u0x{nZ!>&^kkk+D^rN$lX_u4owcPY5jk2w}MRTreP;To?+Y zVffR8z)c?^45Q8k!^nOZrbokIBnB@12w~`i&xWGSBc6U3CPc$9IWds@Az+YhPL7&!AtG+ru;L0H+*$rDy-iGpnk$pyl7|mzLaXZIT~aXUSUV0F6cdN`0r0Tq&Qm z|N8|kBkGslNx5R|@>m-<`ulU!4P)P2^5o?Iiyli&)L3dX7W|+6WAO#QD;Qn4?XmcR z8+n$2&alhbWAOza=2@}(%pMClY&@&y+l8U^n+}#dwX3UP%&T1`x4+p{aeq!T(Ua%^*&=V=;pl;(Yz&oeNAH)S_Z!jsYtj4Om3ud3 z_g-@-p83ey62B=vzowwWtY2!ajNjBgwZH9G2WvYf4=d6C-GUqL{NYla!-+mBxQaS{ z*#i;yzR!QzO4iCm+fGuS8JRhoH2+$28y6&Qa&76p{Hzb?V_HlfYyN>gEa1)uZsQ(@ ze=Kki0tfDY*}~?8>fCtw$vhQsYUHmz1fXZznR@W z)#7>=*OA$>5r#v%?iek`*f_6lr#sJC;GgsOpKJBhkQ?_I#&s>@TgW&Ukejdbo}6=! zM0;)G1282iB(wcGygyvC+F=>}_|A3FKb_WgfF z-M=1n|3cI~d)fNxj*Pnh2-+!m?2&^lzyJ3xYvt~)mJ5zVY~`CbWWb;5vjmykf=tdw zCYK$k_x>mI5P+2gS?-y0?KJK*Os_&Eqa zuY;d+Rxa4I5IerCcR_6e{5Agv2?Ol-8)EGEpWQCM%pmsoZ~E-<{c|Jsc>PxMfNPI` z0-D5b+!mXcp)#N5UGv%Y__o+{r2bxe{3Ni_{|DIPUz9z*Et{B7wu#T5e5c*EJ$@bd z{|vOvUXzy`ntuN_)~EmE+-m-#*Kv}urL?&hdhtRpd!ZLc#@>v5@ZEw1$QjAmXxVx% z;}Y!;klUVtIj*s?^(|nJmaSLYxEUy0#oMlIwUDi`a9Jzoqq`hBK1=StboRN6u{5i* z&$Ql{MQm6$%qzfPuPyja?j_t;;ZL(|CC2@E#!cBC)_42ozL^-5&ozCfLt2`S3$=?P(@w#0dQWSg;8v)?b`eFnI8$9E=z&!O^l z+;Ux%vuP$0N1?s_+Rs%LssB~3`UddH8$IBk+_4qp>CH0(hJ8M(bEbPPeY-UEJ=KHe zps4|Lr1$ZZ)A&EjoIC!}q~L9oe;zp`A7%@_w0v-#9HGVWyi>il)eikl;(wKF73M;= z)KdQIi~^hf()#I-{Z*a6M4rfQ3tc$Zrb9jZGS9S6ggyF&gULk~my$XEH)P|F1ux?f z4qDKu_}%Q>HTKQeXTTfFXLLvBy|~{e7JbBlGx-N&*A3YHHvhWwxq?2}`?x;IoYymx zInur5o!66`$(|8tWn=Ock#7hk27gZ3V$Oej4L--GX@5UYF`skc<^}2)%x{TeTm890 zXX%Zk4{<(mIc-%j_r(!BG(^^3zGXAnqvi|BCU;?$jQlP8?Y7&z;R`-WUCAwX+tZA#(Lgyi+}wmcPpX<|ta;#eavEeVf{&XjwFjJLVDP zs^}_R=FqfnlVK+AbNSoNag1JrG4Aa?){&c^C&vZa-~1!zTS*&-88i96-KoH$Q1U_YJ8i{+rsb9X4X2^;n^X8E%1F*{B96v4XpVp0^Jv|_ zQs#S}9Q%9Z-~pz7WBlaaB|7Izu~$>R0zY=Q_E2>( zM;Y&jXJ!C%p2w_sn)(L%tcd5zm9WmN;=4mHF0~8;A5L=cO`f;nOL&+3yLZMIJrgvC zl)qt+@`BS3oQGrTut$EpwIaUB=3_G_kg{B7*QT5^Kdygn9lZWXbg%io$S1jJ#dB4WFgnd!KBmeV#@KGf1d4OHG#kLC_ zf4@uP%gfLoG2dKH_xq0@rL1V#GW<ZkKMt-vxVNhVd7-@q7V?w4i{tQYp<()a5{CJkD#@!-4hQ#~1>n$3 zf~9+}eFja!D1Xnw_rp7s6K*i?uL5_A2Yr2DUaw&oy~N~t?EmNOxsvx+ZsvSPogq*& z!WiGMYLqkQz+${1y)aOwx%q^#+$3Dk@<{gJ~<=Eo=@(3;=|z`@yulrcEc9(Y~q>AGUigT5$3AkR%Z1WMhw5*;%ITzk?;C1V@$G}?^4e$7~;e8nx1?##f zSTA*9{oe?z_n3{~=>uTxm&36*7T?SSUYBo#-+p-e`Q{<(4Z>Bh5eoxu7j5uE$je=}UZrT%@Zo=M$; z^{Dpj#lSj;XYU$(7Y@4}J$!saTy>oV>|S8cL+*YCI5{V)q8_~FF_z+FuJD=msVc84 zjlG-S2S0h}s*Fjzqs|uggGS5t_{=$t$|sz^du^S@EPE|}^xnGsE#6HDy_FkoBZsEO zv}*4*<7*AZoyoW@#%;a)f^Yxa?#Y2`D0c;WIrO}QdwnA^%}A~-0S5al1M!K+SL-8Y<-(gzIpMZmIgQlQ zcfNmBVr*1y2y3G$ z&llv!8L)@2?GuW*7s3ZOzz+rR#Ul9QdSdUNZET-<-R?#(aY zp9ayxGLyA1E&$ zig+){=Dnogl{|Ys!`R+IF1*fSCpY*YvUR`pgS0?9*X-}61@ia~T-I|nb)mm{8cRO+ zXhHtxey}vFG7BGLk__`n8qG2?6pAUX7(V$=X!SpTcCuqK6JKnG574TIN0&ys~f*zrqJN-1Cu(X%fCnNpuWu{zg;1?sNuX~uQ9PUtMt-bzUljPGiQ0!aBf&T@<8pjv3DY$ zHhknB_<>FRYTwu1xYT_)p43{MwUSW!t=vj8tz5ZVI!lcFuBR7c!>IpvS>wr;R5|IO zLQhJqEw4746~Cr@<#e;+Ep$!grDlbnvqCEGH!JFa!ImlPZ9}F6!|{CoQ|E3^^Y`3N z8`>XsyXqkG>N!uO@~`ZhRh>@urm;^&bwbbudwqPBDYOf|DyJd`Dbv>;jDIel&=j$n>apVKLm;KoBTyFv&I-_n+7y0GfZ-5u=ew}>jZP{(( z0;8zswzV2KbuJel5p|x8;aoC3y1z4N<&OrCClS_IT_h}`$x%zGZb9THLSSCYX zI>%)mbLY~?KKMyzRSQ>kY#4lCQ}{F%t=Tj;yO~Fw3n>4K;FV8SbLG_)-{V=ZEK3X6 zen;xWyxXSl8||e}jj@yKd(7oz=(EO_`APOSuS@uTagr_bQ|+9bCn+bK`T6d&BlFXO z^VJ4>7&X3&fqxfzRr2e(*PJ!2?vw2@iNPm0t4*>X9ehY9G*HI%SBG5_WJkxj6M zzKYSG_A}beY@Hm?^Lr!D)7cY>zpyYJo1u;C8PPMorf9naW6{U?%ba2C>s(E~w)Tj+ z`u#%M5$uBNRpxcD`ZgWPp6GAawkM`jcQ*EfoyQRS{$u9_rt!XqajSj<>(>xt>%P#K zt!LqB&bRZfri^GZ)kvw$w`r0ym5{3?F?L9A1jqHr+cw}hf-U#&Jd;mpm%gV5{f&vD z#XETya%9H(^n}OZ{gf zs1Gmw&8I)D&35y>4?A}#vaT(Ptg-Sb=dNiZYpnHJW4U&XY3r=2gFieSew^>zM9x%6 z3g+VnVf|z48aodO8_bE-Six#y5Oz+3$9%SVuK!E}-+ z4SxS%9ceU5P(^Y!!{7u>H`*HGYOYJ<{_Nj5%4O{O&*pU8gS4-uux*9&# z8p)~oS3AEodwhUz!aTRsyE2>Hm*PX&>`TvCIXrRx%J~VlpLt7sTC7c`ex?yC{U&)< z?MKc3ppCA*cHhah)9f7IPt#69LiQW+Y3)M z+LTDXmcg3yFVLS)>t@!Q(l5e|iwna)I40oU@)jJLalbV00X? zMtiZ{v+h<;=>~t>t#SUQMChi4+%EA!8|#ovVh!T;O!}zjTaPvP*&9nAJeYmK&$`-I z{jn?i_r2t9DAp}I^k&-*mHlabuIA>(WseoipYb2iLL;^Vm1eC>x}ozzqfvG!cEq;1H<9DI#ECt(Gmor`wi&tS1r*mlA3pdU&$56^ z{^zwZ=WfhFj=M2AHy&q?2Vc6z^A>gMS?~3=$urpo?*Am(l|A78r|!1QtIo6g{V8<^ z>vIdTCc01atA_8zFGHX3w(FmXmH~?;n}$_2Mf)JmS=RbH%8nXXwgKL5fVW%V?GU`J zJQ~Y1YQ4RseYrHTeC_1ge0aV#SR-jHL*;#F&E@j97n(sfAX`3d=T}NLWMDUZP<>a< z8{}%cGTwvlB-W1=E8DAm=)=it4`!t|c7@&o2P5C=$^r-8-rH@t<@>EaI~l%r;|F=1 zK{<`{CHCIy->@s5b1cve#2S`nVv~2UmMUW{weH>=@_{N3E$IEq2F{^RsAVm+;6OrJ zJn_LGvL_k(A%SC2(Iv(uIwRs`p25X=8-3=xJnj`R<%R*%!)odaLPM;6a-;e3z zZ}g$@O2=!w8u$8pvp0=@zw*$y_rJ1XT-^ACaR=km#xcfi)X}$YwlT)^PZ^iQQFcGi zv|d>Msf4s~6V@lD$Bi!Ef5Ahk9+hJp$G-4yJI8@j!8pzw*Ex-~jSIJ64td4})8p79 zi;boG{1M&HuVr29;#@esh%vm$7)CROR~W+`jNuN(@GyOEV+`Z=`8T5HxY&xS4E zv}QIEEao_iZ$>^(f1TJ)4H`dlEF0i8o@w8x+D*Q>gw*_S%4=~}g6y1m$b!V{jqIeG z&bDu|$n7hIKC_|EcIdMm`V^1kK%dG#?jWwUj<}X=YtGx!{>kGR_yb%XSViCH#e?#F z=$Y<0&!s63*|UVTlPh;w54*&69UhROs$wPGeb>nCm(2?x)l}nJx%)Qa>#2wu8JECJXT1UC% zE8OyLIpr18i;iIrRd0z~?|7u1HLzYRTsOMqPYey0bgc{5Ldx6gJ&mQusnbFNfpVcX z!xx6Rv96f4akE;Kn=I@UTycte{8)-@%;D?=_6pc>84LeFB5R42)KNeBu3t_jx{>ni zAu4QCzqFBwf2|(BZ6W(_W9Y#9GjsReR=~ksnKK zwlSt?d^`<4w7#kWCoYbj;@ROiqqF5dsyKforPJ8`c-=heyEcVnwneO_5gWQJ&bw~` zu_-Gvev|S`1}jrF!ryDhs;tFR;*Dib@U4)2ogVMLZ0coSY;DrFL)iPs9>T=V&`UMo z*IRqRAZ-cnFH?QUMvk^AR9d*puO*|x;yE89F(SGHfyx7^b3eUIgwd)931sc*8^ zhVzUwVGr?6)?6p1DnG^uJO#e3dwiRS4|a}X?(yw43BRi2mid09jP}7+>b&ATkCOx6 z|IJ_d3tS(;P&&jLrN46EpLqBukMAD1`YSrtnTZ|?p(AV1kvaeFZ=80)oW@G8Y@v2)ff*LwS_fcUv?c(Q!g^n7`M^T|C9~FP>s$6i>;xws=ZS-lGSz zzVy?shWWqlvO50SWtv}m!pK-WC3Iu|cVD9QWcVe0({(gHk}>$##^PTahkt#_ZP>oLwA&l*W=b?tS`g@MbMcmVjE&a*quzbs%Fi3@(j|15N0Nu1GC&3*m6 zl%17aTQ?X@D|LO?Xj-9btgj&-{$ZTsJSX8i!prCWaOr zSCSnkUzlv$q5P{kv>T!=l|w%d>R;8j8d#U^kIt9RgkO4B6fpOTpn>b5h0j70*Wow& z4EfQ{cN#vq*x2|D?8aDK)JhIz9q;IGzw7~c`nY9Q)wyGbUwSh5rn;*uE)!ljZ$&b} zErTxVF(PH4{r$2b{)KW?F>%JhaP(p0j7Nd73Rs1o;)vf_vB5_Cr==r|9^Z04{THJv z^nV7lRVK}tK2NgG_NY^p25{VqYzqXj%&WMId1b6 zk$T6gv8P`kkK2XiVajIEUvxf5chMZ?^_TXU<%6B?;MQG9-74x<9&%y;Txw+6> z|2Ya_PaJ;A;XLR3))k!3{gOFQ4y`^9+!;MK-~F2NXQw(o@o&@SVDzN--{;-`4Su_h zc0Z8c*n<$uZ@Zbl-WAs{#;X}SXWtTolTGybV(kmL^@;u*5ac&H*0z`CX-`o+brQe} zd(k|ev+$C2&zAVTto72DV{d5RkH>K2)9=9367YmPykaOk@&1PYOL!XgPvPlW#=H%PAbl%&u;QR24+x-dpGhuz19|Dt*bM2LmucJa?K^wkf5ZPOD-V5+w$Mr2>(Lo6#5;Ss z@uT$kmd!#A32vP)+Mjdh%Gl)xwLd`X-?QI2>mS8qOlZ6Ry9S26Kfny`=8PS|e;0l0 zyr0joHmfPSGdFa(F*}?`9B~l4qV;kku!Qowv-4H5@RxrWyJ8RP9L-S6jm_@ao|byqIqX3ykYWuC?4wec!KhEMB7M7*hs6OD|b(OiDArq zSGjo)IcI2y-yMER3ckbra@KIKupY2^;s2rT&Eumg&pz%m8IYL-5X`=i1r!ocTV)Xh z%K%yfXcvmDS}Rfev;&AObz`w*g4hOvmQmcmr-Z6)GD?dT6#BF^YHL$zElAy}eF$nF z6XOO5%m6X(_jjLjl9M3`V13`u=lx?oXXebkUiY=%*L~gKRWWq%Dr-EEvj-#4-{e~h z_Ir6v+4`)t%eg-_NFJ?#VlTM=P;s(`9=Kai@hr+mIh{5IOBDGo^)TVY-zih?oX^1) z7^OCn=}0(oygJxY+7pfo_TA}VvU6k)xZ^A_@ zxfX>-j_r=_G-sWC^0Q{EdA8kp5;jl5Yb9K`U}aap`iWgd%C3aV3xQBr(`_}d4RJ)$@!;xCGV);Q&U`Yk+k z)`!0NA=Wl8gS{-u7ZER0##~=!KVRRK`_kq$S+TQ#hx&?;>v7SX3Fa>FB|O#E`^-o2 z841=7UqQ4qykIQ3zD6lOWDWSMJCw~k^3Td2JeqisqBj4YFn$G{gA-5o7e{8C#W6pwHx*ly~LXN<-4QFRLU zurFK`Uj!d6Z>!kZKz=%GyF`sYWrq(N$>?yzS7uXQ@5b@e+E@9>Z3*u71cwh9qu@Zk zZO(iZRIjK02*z|Tux;vZ*A0H$)+G!Zox0={Gpn4T+0bO-ETP<3H_imIe^u9Y@;8@im&o+9` zSF3#Hah#J|Pg}Ix<(+?yZP@9|%p~yAmSdMe7nedG-+)fO4!vB0eK?bR0Vf&V75=a> z;GFw3GJ|uUDfCqgoi%;STD^|XU;f^fy^>F|4JltP@)a8L#jfHRh9=<4hTo{~$7#ov z?XsD+@LP2(T_0Ml;OL~F_j!{y3+(*%j9rYo4V^n?->~YNr)fvsPOz-zlf)9(uK9uW@Hzu`8bi ztJxk{y_+AIfsZe>thev06K6C2Q*D@W4yqH(x`nmw!2vFAy<}K-Wt+M@Hv$Y_L-vXG zS?Eox`9Krqe5BU96dZ8nrgXD2_^okBZthOWL=R1mor1lp`i+Wxrp&37(f<~>W5c0C z?{M?`C9jFoTZ5=U<-xlN0*lc{Y%LrfVQ_{CNdc~c| z_?p}=YjtO_)8}s5)7)!Wn*eJR=Bc&J1Q&he?bbM60v~GFo2g~}l@GFQ|jlt;9x1_Jt`NSiCC3iIciGS-%p{?U*#?GSb!IaEu`Zi~R zWd{_^9W&PP|8(Mcf@!_O^EOhi3w^T_&r|v1)jh5e930xO=+^&p^tua%(l>iLKU$28 z6kL|mhhVZ5SZHion^No}#q?gvXCa?8d=4X@gTee$Qu`I0k~VPADNCOA&!66B-I`gI z{`tfG)oUjD{PTnU75M9Oe{djW`I^PVKUbvW8(e)8SifbB%FG0bX+`|!Id=K^#wo&EbV!H zi}plsirrW4{;uFDek7QB`GbKOb#3055&K`hzl2Sp{k|}`1aI0Vn*A&9dxGcl{C^_w z`~&4bOL)##d;bAEU)*N<58VB+Angg>>$-!dp=}4Aw*ED)7Mc!2drinwm(MPyoeFe> zaG`y_gW!D|?*wn%yLo{Bo*>U|7+&bxvkRX`M(jHNFE%nKGxliGxZe6^$G8;N-W`5_ zhc-@RJuavGXSp8z)ZV9Dk7V4{xP-SBe4rjafbFqS`@4!WmTnUOCgAC)3Sf+!7*)|W z@ti7;E)znwbqA+{6NJ-%&lpb6GWO33PQ`W}iP-zJDgG!~d?UDZ5Ab>!c-79?G`7Kt zKiQBPXxH7Ex;-Xl*`{&;2g4YXH$3>8 z&N}PA$dwJ>OGQ7|U0I#Swk>G(vf3AHXn(D9*(oYdhNv9M)OV&+8UBOB=fdk*JVAW-v+j_3konKA3 zA7L&pIr>%x_OR+|1>?FXen$5w=UO+|Z&Dtpom|3$sesu5M;H1uwB+!eBu=g5MLx(DfC9I-OfU;`O$8Q_P-S~^2wTP7_7xiNN z#kZ1w$C>**&fNdOTA<^Mt70u>6T7}*`Gx<*Ja)wdFYa>TYd0vxwa6*n7CbY3l}f-!A#0@Hy@0`#2#c}%4Y9FabHgUvrO`zMYvB(bIBq;e+=Jsr_!%4V@&u+#oy%%)mqIZ=1P9U zd_MAxa;|RU!7rvo(-?!XYlhgq$6ru4-=AN-WX|}p@-0^3cbtX)dJbpI|H=AkZ9mVP zWn+eq!$IqY2Q9;g^$wQ-9&lq zBMXnevc>P+)o?YFFT&OKH~J(Xnc&C zYYubGjeV8(FidAkFoQeu*!ve#eRBpNEOQCIKz~6cPn9tg6N83d5Uq~KGuel2y zCjh=?kk-&Xf{shv+Uc*uFpYB<3J|!@qM>9I0f^SlUs0UYU3ceJAfF z31%vPI_1}KkJj_(5VEu8^ILp+NlHeGe1YEmq-0qR-I=?W|H8A3J9nY0J)EUhjEz~( zFb9@70X2iFu1QgPt7MUuQq`Y4$@0 znzl2AH_%k)y|uuCQS6BZI>AJ`RkA$MdepEUrNG6#r%L)$S9hjZ=wRBfL5JGZ*2hZh zh7JYO$?Ww{)L6(Fsc~P=z4TqlGIwA8LU6dCi!V< z`uh{>h{@MpTa!Oy`1RlkI@OM=ejJK_LK*#UbZN7eo$YxqPNdUTMgJ*@2zr6=;uqAd zpssiQ+3V!q3Hz@50OhTL{)C>sO#7LV>lZKH80ei9UBdbXe7CL%@_*?df5PC%q^#&V z-k157tx4tm)DnLJyxTZ!Yqr6i>FhmDS zvu^cou*hX>-Rk3GZQxAYdH>qqb}w>a)j@KT6fveo)^pXLxpR~8JVlIoW6IrYR_Zr6 z!1z{K3noPG0S6n9`_ic_>z*~s^grjcM7NprYjFpYOC$J4O^lhwX6E;5cJyB6Cp}>+ zbb|e~YV+ihXgzqj6@9su{D5jlacR;U@*EnGJemRycxmIC(8g8df1gHsw7sbjx;TvQ zs~j2DgzqbB!MX7)?#?sghSx51`km-UkIV@jf)=E|oN#|<_S7Hp+RT$X#J+Wm{sfb3 zXMSzaQu6#RV}2#f?-Zv$#+%s6{Fqy`*39pmcouQG5n^pDVr_;ppQ=NlJAkl}tU8E{>p z;#YldTc5N3!IK!C;s=P;DY9B?b%*z9p|hMZIv z7;h!Sivq-_hS51Bhr`Uvq8;~+Y~_lL&zb`6PevwjrweguP0t-IYcim>yQW>3*cq@k z7t^LMh`;yi*6PT#J_%ycjb4<&xtk2mXjnXb(8WIfuK=buaAv~1%*^#h+N;?bhl+(SI{%-X%uU-`#oER`Y)2py)2%-#wW7dTH0dtKa#pkvyx_ z{NFSv`U?M-Q>SV&WrjLs22y6YQ|9!-=nIqytIXAu8RL}6q|CXj0q?_w2G6!z7ZpaI zrL5^Em;ayXb0qRbr~Dv(PqSL@{+VL6JIhS*m9FHvU?TXv#?#9`A0nPTuw8dLXS9p} z&!pd3Rwz-`Kcm{$ym;qq#voYMATM+tK1{5C5Exs&;M%H`z_viYK(+7vTXx<>yElNt zUcTGaICePWc#>zboCv`y)PFU7R&iFa=p$=S2KiQ`=WltgvoGaC>WiOrb!Toxl3u1Z zStFyDT}Rtp_)eIdB*`Al-E=>!tDil&9ptKKQp}!30MZM34m$WI+U3 z5J471kOh~2+;;Cy=6}5-3o4KW{eWi#Spd)6Q;~B2nxKArWWieaZdf@Oj4W8Y#;5<0 z1&4TF?z|7B-?ip`)+~%KMLvN9aA-tF&iAZeo>{-VSUL3-f3CQVH`%XWV%9G|wq)+P zW95@^*XNx-(GPNl-y1Dt%6;?~XdlOYYj){>cz+u*tRm&!HLvS8yg8I~$GvPC(aNOW=9GP<}a@6p>-KHcHjOM2kh57QRyZjv0$1s?FVD7r)KqdT5DMw=;|TPQBRx=?apJ#AJFv09hX zW{7v6R<`(QGgN$yX>%!UE*)mI>fFR~`tTb$b4{UQyaGqwd9kVpdEoqK@n13D+y5Ja zT=)DJa{v2;dc(*mC|NXx{a0+=e_etsBCkvPU18+n?e4BH$)YM`QI#W$s*pv^=(eT3 zZFyAM8@_MkQAgZxeAfBUKje^88r9|J! z_SGGPUb~{zO^o#-a^#6#iPyI26!gwnoXub@hd}v(D4A;*EtmEW>aZ5G^oCMqQRNyO_kV8e`Fk@!3yAUgF}O1V37w6 zu3^5y5%?Bxt6H;DV*};~#iP+}Yw_pFce$4~G(L-5(t@q%A0DAN_*IkR+0hbk?oX5{ zc6k$gWEa0xj(*J?O7UkV^AYhG?;H}?=gIn?I}gEAvZE2X@iB7ay`7Wl#7~;gJ#v_f z_@e6T{eAy`;w^?ZIJ_m1q_<+@t?S)05A4KS$SL&yDsOq#<}J_7gtw4es-3rtKR({F z4mot!FV?M@!CA&YK_~%!Z3^a)o06Qwis>t>L_TmvzY$(I+(+(LV)}+x&e}4IyqofO zD^5lG2Y11rO5snGjh2GTHgB2=uPKM;TnO*^B0T5|bPSu9VN9yvDzJsTGZ2Z`C{HPNrN16xj>k2J2O@Adx}-le{O%bg>9y`r+K-}9%&u$8`-!pF~NUZsD>bw2-&?^UMk_@%{*Ve#JLy~TU0cH?zv*3iNtUusJu{;8tgKiXT* z8fqS?`+sz2MZaEO8j;zzngjsRmA=$%^BDVezALso&A8Sx)~o1`cTv7yTuh&HeJRnE z1FgrNW^AT>qYf1EuJu z8Q_5EP&lgbMHqVon^ZWx96yE5)rt>;lnZre5y)9*%)F5jQaZ@wFv-s`c{_TUT9UB%+h(CbO zWS;MG`(3X0-4*t`Oz*oZ?RNvc??MUFUO&&ffzG?2=Us{O4*uTW?^&V5`-j>#J?f0( zANU(Z<}Q^4sUuo%w# zwfDY~dXFqRJ+AuHjn48Fw1mL-M;6VA_svYJzI|Y5>wDya{8j(H)qkhW0huRP572!A z3m>c+J29|9w@LjCF?TsYjq{-o3TNK=K~l|l_R_J@Y}+d$gN<_ ze-r$cO{5s*KZ6guX{V7qiGM=pU~Tp^qpK+QZxeWs10IaOEfjC|`|5;u6DTkK2TWF3 zV{;77ONVN3{LtDnEoQzS|2$OJ2>+Ge*3~tn{{%vj8R_z+fpa&5bF^c0jeY1E-m&In z=U1noley#kZ*RX>`ZUJALm5R{*?W;%;+9p0^C2H zjN1de{hpc|&2ajyf2YmBx9Xj?PVjy3|HxN^>`%s-ztL~;|FyN_=?Lgi^d+7uf6s;d zZ~MHux7*|cOZF|*u+D0uiJW?wy+R3W<~?c9P6oa%BOfNGn0t0ABp;w9$p`5?Z)iN| zGVuZQ0PVH}Mth#h&6?)xYX|5!!e7$#(DkZ}LIb$e#PCAo@r8l`U~UxOoZZ z)4KDeOOMMt4qy7sv?uzv{8l0#o2eXH3?Q4b@ui2EFZ&DIbvKLFLwBk?M0vH{oljkS zDc|*%cz8f6JV$L@AzKX}_hnAM#q>Ktwi^AG(r*qtKyjDK>8(BFhyxSmzuo%$gy=HQ z{Oeh}wMIFm8Zp7-_t*%`R;c5JJ$LJI_CS4b)+EL_cNOB(>=|XSOj;zA5l&?^BR193;0wE z&b#|j$BWCqIL^8L4WEPP+t6~xpy&?jxwQPB;PQ`qnk#3+j4XYPJxSJB^7Qe~V9v9T zbIz;0b1oeeUHuu&d1_B{&gxj-1;?1{@$kqqJ#!uJ@JO3io!g05UE-bVghA2Ej$^LJ z(|>=@T#w?>l@I%zT-cGIq&(3%`Zg1JOb03|3f?a-{S3m%b@7*KBNBU_tgLJj{fiS_8%yWKJXd! z|J9!QKeMC%1>XMI8@=T->i?{s`aip)|4Y67R~1ID_>B4=*i-*wI{F{$?SE5Ybi!xU z|DG>*=nF^D-?<(A=Xm>XEQ}U>M*Z*TssAr@^dEo5L;vsPMvqYMGok;U`k&m<|Eu2q z#}-B3_>B6G_SFB12sXK`BX8-{e@^sw$LL?SL{G7Wm!hBh;J@>o{v+%`+=pMF79R#S zG?0T)46sH#2ADatipfs#UI-{JxEIZj6VFy_pdUG51E|$Yqmd z`!cH=d9GkCjo2zxdZNSsSWk4@WqLCArFxD^es;{xCjWm2?z;{O&yqHZ} z+P@5(=ER;=5_?uj8Q6(th3dM)fX&sh{KWJZZqxcz7~~x`D!0I z4+1UEg9D40(`CS=7~fC?TUBwLN0>_p-J%#jnfvY_?`qh`YfH&&sUeQMc23S(>M$>B zLvf!;8wQi_uxteT0%cahx14bWBj+hc@8z@|Vn1UH_0`8HwN1Nc>xob9^LlbO$eBD9 zv!OBH2u^k9mv-YHcOD>4j&*nAAA9lvC%Bk?Kqc_ zY4%=CQz|(uSPQ|kn!K5A+;;(M&<|LOKHuVw0OME0Kk{p*K6j|Mq1IcH>FVNBXn1-G0% z)%4hZ1GgrAm$Ej}|Lk+i$}O4`yPyAR4z-PH;;fm@OuxcfC)dBdhx*G^KklgyzGo-Q zT~gy3crTyO51snu{7&wFq3R##sK3?tl``?^T)^Jh`Rt(`ea1K0hotqwe=}o~@g;T6 zt)TwDMIXS|oEcFJpnOL1A?cjyW&Bsc{sQ|9X8!E!&u=83fV0Oi!|Pj;|Eeb(QcS3D zXtW21mViUqkKJW(=-*G-{OCT`D4vSX2R{Gb7Zdlyca5tEzjF(@PT7}xQTa{sz@?Wz zd18fVb1T=YD6fgm=?L$nyRU$U2yaS<01NWj7 z(N^|j_pK@NXSHkq&vWS4jAhYH@#2!4wI{dJ6L)zzuoO?+MUK;Lv@O5EX~5I=Lw1ip z$J#5>9<5@053-)Z*Qbfu&B^3k4Y_Evz8i@74gX?NT`GL@T;jWCjUaZBeaH~8T_Iw- zLd15x^)7ewDt6h)6=@NRe9!ON?hRp2v0t&#>tB>lLiqwVFn0BK06*O8*lvyB^Xu?f zQ$AD@m5f%LuKXeejt#f23meXjVXvUQdib?$$T8S(Rp5?oH&2Lj|1&ZM+1=|#tio9e6!l|SgOn>7qu9GWcu1~I&jeib&duxG!!cQ3Xd_#F7kWD{E| zU%PPH;+#kzD>9??ZU znh|dlzetc9U;ObPdW+7nG4`2_TNu0KkaUH)e{ggK^l$0F(h;_yV~eNf0!N)W5$(O6=+F;->D192 zOdaTYIJ%e4ZDkM1U3&nY{{*yS>;37m2Q+TQOrdvHn7O6L?sewEd4bIzz*7(K-#z5I zh%&Z3^q^V5B@Mkyy02uzLG(z$s)93Fjld{kblt4jZL|a2Mk|kncxrcg*0Eyn6z8I~ z6+M67fsf>2__=j!nurS#tcscUX!43lrZr_-o5XMai?X^4M`f$It4aIpS&UhG(%LtF znQ<>kDQKzTp4WQDU17$Z8T*Fj&$#38Hpy7=R3GPOE&*4CXT@>@JqzvJM5%3Q>| zM&i+Sa;EP9d}k|9o#BGEh#|J`hE!f7?4G*d!U^#S@Hx?86Z98x{p>|d;v)|q_iiPDAF$D0ncZB}2U3rEJA zMog~L-u+a*H?tn;3(MlAf+y>=!QgXFOu132zz@-73;a+0%BIk|$7xe=mo0QXc=nWI ztLYv@@N8yq@s05^@U4n9v&ilKuDJt1xRe!p;`g>ML~ZLXR<}Lz6@3@JwN8_Mk{dg$ zC%BO?zq6pR?qkZNce*ys&w!aVpu?t7Zu9p?rp{{_kv6Y+NMG&|>^{%AXi@P3x6_8` ztQ?q$#`4R7Jo!b7r zNb~ue>J@PJ8FmxDrC;oyXeIVzuj~HITAugvsp?ZuZE+^?4a!*j<}7qw;D_jZ$e`K3 zT|Q%K-=F_rHuvAycc6XeE^=`hpFqI5%`00poxxhz>$3Es`w$s0`pSt zo@^chj&L`k*7_0d6e=EJ=k*UXz3^hVtZA=euuF2TE>w(k`KYQF%b$LHZ+XL?_BI@O z$NXpg_3FanKt*9~-?)8lhdZ3-Gv1^8AH;!|k(<8wbD>u2)vK}|D{ofAsDJ28|9EgW-%J4JQIE-F|REgTaUZZ|C& zv&GhR3tAen7hk(Nf9*)tVIMSJP8@!%iJ#4j4Td(tj;&{}i_ZKj4_{`ikpC(UwvAHm z7TJ0u!S&?&r}R+2zv}Pz)Mp;obJkz|mvV2g@;|0H^=q*yll%V!cvS4`sQ*`JB*

    OYo=f0@wX|2<$r?*bJ3tqeDD(Jceeye!TAb0~mm?4~Mb9k_R>$}=H z0B^th`mD79)-U*Z^7#!7tUX=hguh@1ZK|Ejx*>mrZ{ZYcM&Mz1E;?IPzI6^`*-`fe z|lv6`pc02x`+9GJF$?F zi`QK=v|#<0ZoAmJXfD6s^Y@EQV;nx@Q7UcPaa+Oa5zuBc?atQOHf+7QifKdtIvu<2 z+8<7=E52>gk&4@VM<{P#7|w`4DOsI?d=d>FLa&!>l+6BM1aVOQ{w;@I$8JhTX26?8 z1Ivd5*OvB{Y|Lu;V1$*3X$-(v@^L!fb(X#?7-}s;W~4&juAKZDa#Hu~25A4_F!(lW zqkiRI2~d9ta(J4~nuFsDhh(fB1Fd-Vr;AuKaKiYnDjfakLcK#5boHk($PwvJllFGV zDd|tbjU41uc4}mXWQAx|y3|vgaV96&%mDWRTfT2PzC&`E3O{I9V+=5dOkZ|&Z0MxA z7TV`-#g;LbEdOUPvTDZi%7=ciD<#;{jBj-+zSXi%-XZ7pcYl@!EK?`UEo_FD!2`EV z1U4hkhppK+A2IjJ{|CJ63*c5)yle!#tcE*KTweBl%C+;dY@3&HANFrtK3NigheoPr zG(1$p90Dy(?^wSHGk)>c$rI)jPU0Sws~rBP^=evl!9H(GC2+1pTcTJ^t6eSzEC8Kd1AWUuF)KzAKMBeV*0&>q)b==y#;@$|Lo+ z@tb(^&gEtudHQd>f7&fK>qvd3ul3j1xSh*|TA%(F?|X-~n)Z5!TI(O?cQC0Obn*22 zyzdv<`cwFAq+h62dRGhasHN~C`GaTU4=&s7i%Pak>z7vDlA2a6nhg2y$@C5$VV)-b z7JF^xwHJi8T!dWESacR$GF-axZROxEunmnzH-NUp+oq@4ayJv2Q+uKTgWvqWj`dFk z_M*Le24}8qn86)2ZEd4=q8BNTJy(dCGi^$x? zadbKpPgd@<{c57^$tLhKuyDbaa00(1aO3-tKuJYmGdim7v&JXEC%-x!pWC_gdHlXw z`)omJW@u{_KF|6r=qreB;O7bczrSC4uGK0%RX8j*W6743s0Dl~$c;UQ^_73k*a;Pd(L;=@9-MD~x3Vz0-+ni` zeH`o&4PjiWdlUMKbY)Y&wlMlGWkZ~MXn(i8F#2!aHI`VTt~X_!zTPX0?&5vK=sC{2 zKvDFcDl0zX?nfPdXRqj2b4IrU7Vx1%@9fo?9rHc@&fYY5Qn_@NB62XILyiX4o3MLU z4=svrHht#Bw$pB{qet2PIr$5uM`gwS%74Y=;Hh==sL|lLTkn}3>ivQLDin|5)2Ub$sdcNewE9zMvbBm^=;2J%gi;b zu_evHz+|`!6LM%$?@G!wf@|KnnsU=R$_XYjDOcl}gZeuF-K$SCmurioDmRUC7Hg&U zO5scG^IBCLeFfi6j(ex``buR0r?`mfsexY`H0k6x{pBJy8E77~!ZZ8L274c5? zz49Gv{m0Or^Z%+6&KhPX*MUAxaq8%9E!B}N(F{$@h9;z2RF+i~u1m?9Q&Mnkq5b~g z-od;dTzWO{19K)7V6&7~6k-R@vH0FjX9o|Od$)Y-`#wee(+esJHMft^QN)i982-^g z=O10@(K8b7?6v44Lf@KC-@extcA|f8S$J4-S(m2Gdw7?1(Y54Hm|a->H})8qW7>c@ zg@(R&Bg>$#ka+Accq}?d6SBYu&nqqt7yACD`K0`&_Wt|#R<$0qZNcKnMJi_%&n-+v z{*+dmyX^*+!B04|G=KO@Z8O)wQy=}LE!(0Ei#{WZ#vf5R?`y#lCEwo2ZY=95-gkQX`C;HFU zBb>cJ4s07?`!6ya8IXyOIUN|NjW?Y(8l5)&*Jvih zvL_Y)W7DGRw_qz8Sz#@_{)p`4zo3^(R@^i=!|Ycs{Lq$xx`!fp->Cw9x%0l0vtKD0 zc!Yf?@I~zkmj6a(>vtx;n>T=i=GTH=vaZP5BfM(hdjOe^J@(=t=BRgt@c1h9xaFK9 zLT|wq3UoRfc53F54MPV#^XRgM#xFh0=Q%#_@UfP?eO<}2e_uCw+5cU4&9Zl{Ll4@s zo_Q57Yy8qx%ijEwp4OHr&3mG_E|MFdHbT&q3tGNGd z&s21x3eI%Y3a;$wY5b2+Ph)O|FPr^1^evq)L1xV?Mh6o-=TYBUPggx^o5kdkgEYvqhoaOXf}P_sq2wldRUO zmRqe?@3300$@R6)^#yfyZjVpn@dsN%^tZwv+*aK`Sgn1|QuZ(doUf~3jVG>(MA6l&eQJk5-j#Kt;X-S$Hqt$zAJ07|) z79N&4cz6;xQV$*q-m-(rn3uu9Nh!yJgR7Epa0>0!3J1ZzZ5Md(k9(w(;Ul=5D15{N z1RwEc!6(F1@TuV09ee~Q7e3XjqjwDjAGb~Rs|^myZ=*AkEn(e#X035)fP4cT6dLPN2O&{#dbZgIKY#ZUHe9J$i z5Aoz5QeJ$0v7Yetg?hr*Z`KpOexsi7A?#S`LlwSRM=bEjvQDnHBE5F_EPScR%B8&b zn_L*z6#f_VA-paFhV`6HTu!GW5Evyb#+j_YU7vFEsG z_K|DQtBT40aRG8y;|YSZ?=YUHu(kh&@1hhunaU@X{#(#%`!WXctqrqN*FLIo+-A*d z98!N?O=aZ-$s_eYcfEX;nJxABocft^^nF`s-p?zap77?7$ax<^JK}lo!}GMa`DVY+ zhBqshPI#;G)(Ic6fBVsCRzfi!AFk&NsuTM$58vFI_%A}(y~`LQdiBgVfoF&@_u{wY zKjYo;PiO2cInZQME*b6VnRlU*_Sgv7O;=2@qVBm*?e*)-q3riJUvbZT=EtUOarRz| zLW%Mx(bd`Oc;G?HoHdJN;#&hI&+uORgf%+nS(O{T0GiY}$S|=P=yQAAbDsa;%w;|M zLGpXJ@$^NU^$3I_GqUm1?nWnQJ>QPSs86vHuQ=yC+sDQlF89xh3s;KqXUDW#r?>!{Qo%HA69!ScZQv7@81W=aan#Y{+svgn1}$maGTPR zKRnHN*h^_Vn|-VAROWtMEH2&ZeIHh_Y+c&JyVJU3h3ZKEH!M znN&v%Cw$G<@)vkzNnB@MedZ3b-HcUj4*=GU8taj^&2zCc_EASRw2yg&&$jDMrM<4| z`kcBI*#1{gSM6~pWi@AoR+Y8pMaz&eLHO0Zu`#ys$lZ(;yiNn4mGru|pK1>4-YVk*D zUBeD8bT_x#J#%Yv`V2d`R|P%>=+ni&L$p_J?zi)`bl2WOPkaAx+AGILD_De?Um$#L zdwaF;c;ccGjmRe-drm)R?vpF>qqnLJ-aX7y`lse09FyD@E_c`W<(|GbJAHGndG&7E zQVzIJCR?kUhtQTUuUg}o$i0IGMnijU_k2&g>zsD0E?D+r!x@k6t=;g~z2)cQn+=bQ zhtXl(HDAv}|CNzGyrrGLHZ8j3cXyam?ys9A5gYYwVg=KkT$yzpHICa%sDpmnNcf`@|vU z@_#WrqHPkfV4`<(ccM)rAEOs|dAMK`^^Eg9WbDVchU#h``Kjo9fp~?Bzm>FK^2Pvs z>KU7li^ULK#?A~3PeV>mB@b0Od8q9Bqi>WDpwPK0;NcI2AAH{k!c3Z1nAxjLQkqmv~X$;A?eb|nw> zJ_yf&|0ZU`yL2aOm>igr#pv~`O5TuvJw4Vye34}H-RxIvR?bUw1i_B7@Q@$il8^BF#F4Yu!g zhp(RuYOJquf)Ta%ZUAWV_r_)^+k~@Cw*Ues1=Z8=`(!*mB3r_v4QC9`TgR zRXNV)w2yD*Y3=Q;_mn%Ca^W8zn~oMzM|4yp8?FmFs!O7y+FQSM6c2bB8f{(NahCwJ zZt|CR#s6Ll+5GP*o;UH)8HnT@xBm%WxWJiD1#yF2&8H{6@C;`Fy5kE?{AcKI74U{n zJgKrtd|{Vcrrs{|E0sy&3opB6n(Q(Ut4tDK_?uhCq2mWs#^no1bgVH)*uQV5Bvr;br{o#y;5O*w4hu zDCVZ!2BtsJi#7ZDcr#`7JwPn7g}^~Uh@9V4JCH) zTYh5EoEr~40^i*_WW8&n&c!ciY;%nZn$ozQRXcol$Mux=H{<#r?{CKSr1v-DdYs>; zU+C|8&UCQ<+%f_?eH~|A%o@B}5IulxqJ87nxU0w_HYS}rG)lD&^~+u?v+DQG**j~j z?%GHzd43K1J}bU`f9Oy#JX8Jv#WzW}TIH9n#o1>1)9;o1o;A-mzmhnaGTKU|t>Ls4 zR_r@%jVNiLtyI$%I(>Uv_#sWss37r1#hlTS&Trn~n{?mFpEZ^?b7^xNZ8qaCT?0N{ zK0YVfh+SREopnX;`{vivZq;yWRMCyT`Jv&~%-O^j*zs8Du^{)U9HE_TD}7rd^SGUH zE6&zF&zK$iDZihZbI#a#;12X}?xPs#fcbYG=-0kkF}v9#okLa@Fcg@m3~LJ zL-*v}_7d_vU8Z-ewe(T*j+{s{^$vZ|dG}EXd4s;Jcbpk&e@A|uX?n+cwZ9|(%msSK zxuN!Vc2fO)~p}H`B(>CHI-(pRN zle26h`eZN^nK6d@$ezaMDtPOjmY-3dHu;_(JB+U1KtEyho10jpW?(oQ*jo$FiE9kb zxVD#&OJxdp70{gwd_wH;hzArc=X@yZQv{CG=*fC9?wR5Nf2SX!5zPLWfhqY=&ZdnD zPhE?#s&2hgH{#T-r*0rrQHX8aQJ;J!gHLb_ztR|ndfFf-$-v_r!#Z~i+>6k@KI9bf zQNNx!2!^7OAa}z}1P;Z_Wg>HFWDXO7Lk&;C+wentcu|ez%yyW5RB};a^n->^*Vd2J z*4du6$o291r)+Dk+TxCf_BoQbqv2Dwb*b7q*V7g`I5yMPiQvs7webZH%<;KDL>tG0 zH)m7V;LT)Deez(e?mV9v$Gc{yYAnQp2sVm$TdHxGSRVWLkN9oz+rfqQb{VU|1%ngd zf^fo%3;k&~1zSLM56})?#SR1`F^MgOD{4`(giu2+1ldxO&fse$LXG4!0OYZwZv=N*9 zV&)J!6+dILyx4cNyigzVABz7PxiC0MF6a(~F64q+2N___`noc}kqaAj51#u@{uAAu zor7E$>&S)s;lJa$k_&~7Tqr~?6uELCKXxlLDqSSg%HLK4ocaJy$qDV}=TWCvPmDgVcSa^S?ZNB+q<6>!;M&gXx148q{dV#CYZ+%Uum2{z zz8qe^gm{hac)egKd>cZ2o7d;X4mrHO9A5u*cs+bRI@R#{@o|lzeNI~@MjNuoI_WJO%UsAvRQ}9{QP7OIy+S`Jkt^Sm4ovOA5 zd)kT=MJqpLTLabBP)}RLdtTSMt#}t4qrmwG9Et~hI=*xjF<{1i1b?K9FUS9si40b3{>0g%!}EbG7_>CdjtYvyb8=f8B)d0pOiFFfMlfgIfh zvpr{6Zq)FsSvgU~xn{x3#=y(GI&C@eyV7YbV!*t-YbN|y^qUUvs$iV2GNumRl^**i zzt_zjIkxH-Q|i_-FP)#7LTrt4)Ek|TJoO{-*Io7Q;+@j*2D4`JLrDLVt*jjNVeUjy zj`}at)>`zuyTEb5YcaX$#s4b&)`oWaA*b^n$(!q;#pA})nd;kb%zXZFJxvo1>Dom5nI4 z)X{f1#j4gB@iwgme$54x=Umj*2F@kCt+tbLjHsRqx4Wnx!JfjV-HL1+CBK6y?}?)^ zy2L{v_7lm;jE!|G{maHm3)y!<+~n9;lDS``y&A?UxeHJ3@~$m!4guzC{4?4!IRrer zntu)B)3~mF+jI8L_!;cn1@cAUAKzt+dC-ZC2 z9QbYW-rzrSeJ3yTUj+JTaL(sEf&VJG{_{Q5e@^v@J#4SfK2cUuF09`=^_2@Nx&J3r zAKvHI-wJKqa-ePWfj*P!8r=8<;tRcdmAmBw1J?gVUEz1d$8DSY1AncZ;#8#D?5BRM zQ@KNC?oV~^ zJDtTx6?5OBbK=Tzr*np3+9)FCJQcnIjwAx)S;^x}-vuttb#b1- zA~vxz&gHe^oSR3>z^IosE)cMy#KUH^rP_J5)W>pSABHoR>3qC-wQgUOoL4K`GkS|tiz*(P`=Ydz#Cw;~wz^hUx&ZRjyhRVUqr<^skTFt)vDvuo8C^{ zc?xIK!C9@7V5ocIK6IvK|Cc9m|7k|-bjsTJoZeCfK3~uMmqpwcqkU@4MfAL$ zG8M#J=!~e|1+2{KI@%0oT4UkGk-1YZ-7o_&dLfmmGzpK$#`sln~O6X6Jq<7u{~bmi5@p+Vx~O5e#zRE3`6t^aqYzRpjgAFi_X!=D)aa6JDto`Zfk z8hydhceVtvN3i+BL2H!kQ7eK>#io9Gtew-w{r!7>>wLWXdn><1x61pG4WH1N!-hWA zrcHbf%(Axb|D3fIU2~N;2cVrRB`5YMSLyRc*_Dlz-p>`qx?2UEtjrLm2ym=huyAE}5DSvicfiN&|4q zDY15F{JvtvMdrl*$C-!w`$>Mo19mhGk&P5+(OL3T>1`N-|b-LT>%}e`J`=>#oR+CS4n=XK=44v z4S$JeGH=;fP28o`#CZ1;U#_)x@kH}P7H8|d&65gDJlO+> zC8rCFoM!(#(U>k-T@ZUhaE10Nn8OQNBiX01@u=@_*jx3e8;?3VUaNRi`ce#XTJMr{@0qqH`;S?%JzL1JiO##eDctXd;@;y z-@E@h7T%c|g8`*;$9gjHrx%j&&3!N6V zp1emmbuIc$^Mh0Blm{l2?;2wTZHu1%(=leAz!=|!UoPxN5FKtqChddwRs1*rVq^oYqSCz_I6BTij7+7TyijjQ#W_|jEn<8($8T@v_~ zfLq<=-Ewnny*)<0t6n==Mg++{mr4vx8vd`ob@5sKh)L~F%<0L*oDLx7w3p6`wCe*+ zQ>?@c&W6bTHNJ;z+xKv}#wkApu^f`Ot{lFX-%YaBbROa?JMYX$=9MQt55446=SB}A zr*sw|;wO&%S@G-q*hRE=eM)}yK5$$9W3{0?HS6HH!#@Wu!E;A1ydi!gzN07jZx?Ga zeSk%N%*c!X!++v|vK5tIxEOd;EWX*vg`X4qonQ+Otc8c?FT6RfHP^WX)!mX*SNzj* z>Kc87GhB~S-*W1wF1-1O>ZcNCa9s7-AAZ17Kj_pC9&dflSFQBa4>dEp^1Nj=7aPx2mh<_ z0~tOTY^i}?P3O#HHS5S7mE+c-50*e%*Y@Un6x|S;eQq!`u9_TNVdy~lIGfOan$W4H z?dp(ybD^_*WS`D3Y8;x6)>LrO+6cb-PkDqS7aO7J3Rf;N#&ejHaKgm}cYGxF~cIB)M|ky`{h621%fxpR{ENn`~$TZQba0&kD}eNvt9_fR%GVW@b2&+WbG zX^%b1P02EkHtjPQhAv9Sz79Wbyhi@e{MZfTUfnl$a$N@V)YFcW@1{T2K{~~A^rx{) zezOOZA^&*z*LJM@_2OahoOg+LZiFrsf4fxYS57aE?o>VA?RUo8!IScgY&!~GPJc1V zo7f(wPo3{L%zqW_v|kXrm@+q}6jV#DEn(lgIk|u0fggAJe~G93Q1TJjvbCG}0w2wH zg{S`-?gOasXF5EGeG2|N^x&krbmH-5iRUEu+p8pcx6|*FJhkrbybrU!MZSE4D~k=T zui)wS zYhee3JagVVnt3>L7M>E@*ty?_N}`uK{Vw9EwR7hzoEAP$eX(ukQR{8?dh=puQpcqa zYX`YrJ@*cyC$EwpX+2|*tosR1S2nn`Hx>TlZQG^098bFyyPI6Lo*T|ft6E;mj zF4Cu0K3+wet&6{cjQcXO?n}tLi;;a7asFa@UGtD>gfubR!?1v&fTicwF7lkD==#TPN}>A-1P9dIx(d1(|dxwYr>rJdoE7vJ?S+lOFu z2IyM*6&Euu*{C(>2*%!nCrEEld~JX|iyPS+ti_hIO04K)$|8%5Pwge1bJ$C+<9_F- z26MkN>luL8r}1g-V{M)WEQAM&FKsx<8rJ|Hi(;dW2gl^2T*P;ke}wy=l|%5Nl9cHC z{3jc81ASfR>sP&!`=56?_dnmk{m*v*w_kD3@*PgTlRLQo*}UWa=Z<$**zdUix#QiH z_B-x>?sykUn7ZT{Xn!}*c}I?f_ID-DJI>O#zdI|G_<;MLZ+FI_`=1|i?th-f{mj!C zzkG}2%!p27uZ1<;Q_nhH1fE`tjIDO+DGsYBh`o$I*vMtzIRY5Sf6F=l=*mTB#MOp$ z<0a^nHOSYMi{{2J=C1Q!aR>DK2UMTM`M-%N{mmWFA7KwDSHM%f zt;cpFzxx4eox>9RtB^BVgIv}?aTLlq%39307ha%qqUa9hoG7xW(;3lP$yM;fK3joI zK+ljpsr;nEopt{FmWpC)=8eo_&7xc42RJ8Im12$2+V^yx@+1cbCI4EOyUveEb_c>^ z#>&oD+-lM6F=Kb5dmO8+eb9yQS#7=Qw6!@auNoXQW4F&yjAeNNQO`M&(IgxS9@QmY}F2;eM z>u7lNa8~p(XB--j#mgFG`Ki=Y%O%^;^Ojd z&WYwbZPsv3v@1R0r?e?O;zpi_(Ys}jui|^y>~p1?Gu55;o1ks&H}&?6Rem_}0LhO) zc>Gv>4_NsQ?O|_oo-Ir?tKdxZ`k|%lGhsFO-*h0mivjP_ryf} zi1tiO1b5p=7gSutJ}#Ved8+yYKnf(Nk5;F+vn$)68T{z!30&+@nw8h;pn}{1o+(Z1VWKS7N&bkrVpfxU-KPCm1T z-G_X=oWUrcE4i0t?2(tv9&47dN9=Pq$}680yU>A!@F-&R&b;d7$lbC(4JNNt{dpGm z&J{=NCs@(Qg!1o77GjU#XS8EMvSY7)gdgaeZZ3|jmgVHwJ*qEYpuSG`^hF-~F6npO z**5*&##3vaMtq8Fc*UC-yj!%`lg*yjXrn&!Z%7JV=|ccFz&*mkOF<*c9JF_m?lJ?Gr9`&vSEg3SSJ+4AYfhJBN# zy_$pAFDVY}&lu7Ud$rB^!Exmm9u512$*^a>-NF8Ep1!1;;JeK33O5x4r1;P!;AJH_ zu|!uP>R$fuwoRg~p7x246*r>$)x?Yb^-r6(Y5(Ru#w=V?yyJNKVLcK-?vMy@M^STn zWa}L6k(kCk5@kOe-sv8Rtf$MW?}OKAuYCgbis5sH2MTA%pC><-c%9*M>wSjLiN}f8 zDP|->za#3F)GZ+|R>k_SA8PsYy1ZG?O8JgU4pnRoEvkXW!j3O{FR)S!$Xtg`XLrH- zK0w!gz(Z@9H8&G5ACUY@4% z$HUVm(^iDN(+bB%6i*Ao(-hzKMR=NlExcE{xNNvL&a&lD1iymzbiFZW@|}}=&+K7k z!K?2>uQvB9vd*Or{p1j{BHEs9Vpg(D%*r$5B-I|*Q}}M{u{$!cTfFfq%8TZWgL31j z(iyv;A!Ri!W=#aT)BkPci1UU=J8?8zsTb>zop-F2sY z6VeT;=8Rq-npmLuqi6IKlahSrA#*bL%36*K!+%1I)vC{oHqcfBag3R#O-W=DPonP` zWmAm5boEj@zZqp`Mu1lYm`FDW3jgt24r4Ce;s|oDH|1(rqcAcr%s#N@WXgNw-tpqd zR>rA0bcG{=h5W374SAjn>>~KopR2L$e|N5{4BW(1CgWe2gn!}LTJaFoKP;N-AqGuj ze+k$;F?34e6`t`gU6}YM&##S`!k%o7+0zQ(gA2kxi~QD}am1IGv?#tjJ+^{=LnHi& zVsKpZ<@TrQQh$z#FMsm$?3sP3kJ+299qLcCE%DXuz6O02+ePDw^g)+|=5#Nh;vNFT zJ-9FrLYF!_YWD50YwPI8z!=VW-RY)>%&?mc+l61?$0)IgJ4&@-B#jaoyK z=ftni%BoiGq8o-<%7cVo8l9K&YTFuMML%XvI@`%uY+qF4(CGS8tmrkAv3dFzf&T@- z|9t#lQ}BaLu5)9lx}u>cXiqfs08g#ak?;AalR{lTZS5q!@SkK*4(6!<`ikgX!=DY4|baCS(#^%z&-QcXgr#p0Ty+a4IJ+s20gG%zj zTu2?!K|Z)==>3Kv(Oux5*7zd+vqDz%7I08&!aJQqUR7e99UbPt;m6EJu_zr(FhE?sAQ+sj^?5FL)+DwRF# zvag2X!LM5JZ=U0hFFRI$0^_^MZ66)P9$&T@Ux7QmlY1WDcij5ym1%raANnchRjh^h z=FECFeolCq75iWF%#OWbp4=BmJwxN*^>T)WSG?iZ z{4d^cH_v0)x~9J4KR3DrIB57WIQwVnTi8{yX>TG%?1>C(l=O}a{=2XGjv4oFyM4x* z>37UnTU|Zlf$7U;>^j?;KMx+VYYgX_*-zZ{1I~3LC&`OGzXZLl$>fX5XlcfV)SZ|` zz6?VLx^LkmU{sTCZ7K+#v)~|l0PxG$HI#GWYG*k0(cyZke}J)yesZ1qGpOHF`F8~) zVng$s^3th#Dz9~~AvQYSDSz%U%D<@giS^HM%AcwE{K%SL%6zo;W`75HrdYV8@W9FC z`B8&oyh{NV!lNe6rv#)c11IT3UYH3#1h*~pqxR~Nqcz2^8$5k`?cdt zOtP#MZe%i`q_1+ zO+SC)c?+MG5nG7O@DZDlf{gVeV|yWEdn03!uZzhEhD>UEHn_t}OSS%-xGPVfA7V2j z=Kku@>+ReV>OU9xWq1el^d9|K+zljtTn?`ekkix1mW8Kw$QE*WYE2gb7vV?XbSo-a zbY)9t{Kz%<@p;Os&Em1#VLZZ>Em^Ub>2K$7d>`!5HJH4VUE!GBMv>EoHHLhn@Ws-( zBNsFf166dEJ)Zk%%heeYe3#tKMt7Fo@$rw>kpnEl+<|mH|Cv2!=XZ$Tnuq)U1b!<{ z>l>f5&tK|}FzJ`I!>8CeP=cHV`59+c7qd^sJLO0@h2Qmy?B8yllzzOkD5E$P=_zgG zhue)^7vGgqcYqi|cdR?;FBzXr461BAk3NoVoY3CP7TNbZYc76_Xhe7Pg(5S|SVo-| z-9ov)zsxFdzZDBojK9r{?fa)iAJ^E3(VUYOY87mo7FU)#)|)3)F*p4BwM>>+P0Wxuz1 z2=^yCvAK$KdXu*GPWf`R7RuM*+oQWyt&AXN)1+4hfKxiL!dKz<{hH>6ouE3!KJG*e z5{CjV!XFaZ!sg*lkqEHymk8zQ%^Ip?i%rD;v}U7qAS?zK8xnD*D%g@TRj zOW~*HXz*c0F8WP+>|OF<+q9n^6CY44g5`mGEq0mUHPV6m65tNr8Mw=i^};z1I8Rb+ zB=hpZ`CQ-}cHmsFU}T(qD00+*_vRj?>{uV*;_@HGcM3MS@Z)xR+J0Je5MxuBBhXZW z@kAtlT-;!cBOfGY+aEIdfZel+?)tmq+R3=;>AM&jI+t}dW5QpV&zKaeDjKthpL**7 zH%Gbbfc)422X+;rZPw@z?Px5YW(>dSVGN<*+`<&@8xiiP-&g5(w^_4-*vso&`IH?S zLK`0sV;@#HNiGo^Co>IB)^irv#Yx?veDIr7>OMyAh{HqnW78-`GoAVoo&$N-@I0BP zVm1|5rr0z1@J9JtzQ=pvZ6EW@iuE?noS5G{b7MZ9wf;-B-?Pyx=Vh-d4h7j8?M~ja z=SUn$!?m&*p}+RCc?QP#qTW8;mi5o`tmJd7`?yUTuD*;c3G4g?ehA6x zXXM0Qps)O4_@Ln%0b_e+8y&Q(HnN>Ily@PFZ8#hJEjw-KQMO$Hw&#*L6R2v58e9Qk={POZw+m? zjq5HVe>nDhkX+igU~k)F%!(DCz!+b4`mopsw8to$E+=-2JI0AUkMTLTJ~oiGFl|@LhD2fiAfYz7au}l)dzu5w=b{ z3Ogl}vl_&QtU3t4j?-R)(F<>kuUyNS^dDPsYhpP9Jk%C(e91FW%CO|qc`z< z`MIDOFCE%KPfOvu^fX|XD7jT|$c+7fcanXw zZKQ6RYsUI&o7*$c+UZ^mb< zy{=;aJ!?*-U-8sgertZOoY0{fVCU^mW6E**(>_&lf8UgzM}Mz5{Wa3|VSK*y6>Y*U z%~~)veiKjmri=ZY$EH8&7~SpKN9eqR z@h_b{B~glfqSy@4p3auVq2DU(5#>O$e8fi^`z0fGJM}F5+$s}<4?IsF(}0ooIdrdh zDKK(jIFWPJlh9>zfY}mqBH3`uik_u5=qrIw-%7h)+ILv=X37d@?}Jvr zw@t6w`xqO&cB=3;&%vWvJ>cyK+7g|(cw63%x97&g(4A}Vq=49xk9y&3! z?6HlF3^|TI`#XJ#HuIrP^=Z@Qx$s!|vLr9FW23R%1q-8}6%UJ!`wZv(K6ujYyq#D% z&AZ?;ocDI8&tuK|po0UJIfsTt|KQ9SSeclh1{=pajX^YV zJbQINaK`Ze(DvqmRTfv{|8wt6$V~zWWF;&~z$IbN%DsqkLj>8CfLg6K30sq}hM*!Y z1fp#)s62|IXiHFQlPj@U!9wd>gWA3rt+J@yd|v}<4PaG7AfaG>pEJ+%Bu|o?MBlH! zKa!a{&&-*bGiT16IdkSrDZKJ=cq4pS*#t#%Uw0nopcc(NK^xROgYG{|Mh5{Md@3P$ z`It~-^CK$kn!gGEVqS03YNPebsaxi?%Y-d@MxS~^(C2lBY3YG{^~jy?=CxY&k)a|} zaE`{=Q$0NVHR=`{5ot#vyzU_B(q8%f2fjsyH2$vWkg@--rf*tY(jP9c|w zUx@DHbM|83|Wqx@oDFo<#SagG_SMZG1oTnkM+Nc)85jXg!Qe-po(i!wc1pc_U1 zm96ih3EnkmITARJ!iQxYdNvL_70xyUM*I09`J+u;_eb0jSkGCA$c34#E$v~;T$grU zpnlM3$^Dw2f zZFU-bejPf!F|^Tsk72cWA64$6K1qJj$xC1M1HasyV{d}b4Zzp#$ZX6bjdctimzL3& z{8n9mGV6NPtjkn zg&sc$JwE5<*`mjHiypt_o@Et&7xHX=N;vaP7aDuupfTrYtL(9MPDDRij~pQS(q*)3 z4RV3#N8bXM+=DwL^G9@~>@9YlMMt`tFt+3pWfLX#?V>Nubw!`>F?U5@Dssjh=u5py z-iYxROJ9|~RAd*qW=>em*{L||Ca;Y1Z16)B> znuIbZe-8e%ngmzr75kMOAKfCyLkByxpiA^@V9K0{bNTi{14`yES9v2_@_rYYzcI<6 z0a;($%lu{st?;URo~xY^ml)t`tI$jKJF_id@i|6f9VIRub`{?xHG8whfm!t zW_|x)Ui}VwZBHxTMed$ytE;^XJazzl^NeeGLRr~(H}8+*GeN!SC3^P{F8h9KXwox1 zs*}*bf}J%6D3_H|Vsb6wV(ljQj!`u1E`b=l_m`#(^9_jgsFZJzJ_ zf$CeM_aSf_6^@$on0QCX+= zfEPROlllBz_JqAnoB*TgAK*mxgoZ5YZ9ENbgqE)~>$3C>mGGzkOI@eHqws`)by2tK z8)wTyexUmP+Esn%)>M70Aw9aOPwf}F&;wd_sDCi)D+QObw*`-CZySXVr_<<{lH`t3 zGJadvuODyi!zOi0TWxiM4NtqOlh|)I;LrOuWLc@B0NCQ^B(&WTKleiOAVm+~@wYlDn%fVJ%_*CHn%}nBM%lcJP~P9LU~I>{PMSuNY)EKN-wTG^E&9g)058qa_&fhQ+|$7ZLH4HwLqea_qKq|7_TaKFm(a3r zrcPx)+MQk8qrjB$h{e{y{pDSUwJc3{3Er6laux-Rp8N~+Sr0DkKFH|X-UjgzE$KEr zndJvV-LrkqS1q=7^{g4uny)E_wX~GJje5L!3-Y*%4=28Y_;LE)z&T;9d0%)+FuDxN z7W5lXp*euT`&nABh8dEkKh8MGJzOt)iEZ2+IgZWT7WN$t*y?D(*did$$Axki%CN84 zl*s)4F@4HoAEEN}@-@j`0^5sCiOi3=d@E%?ahCE@kL>kBv7?dm3zetfGJQSgF*lRX zhfhNvXJ<2s%f1*}lD+b_ckQ|6xzc`l`}~&1O?`59@<;S267C~h%Rc4b?5zrhaBmLWP2(>Nd~M|3#*%(LD=H{o z3SKxT(Wmj}X8b1L7sAJwE$J7^clI~Dl`ikCf9?w7?e$*%efQ;_PoR&V(#L(=yV}04 zbiBZ;$>KF<^Bzb~XsLnvWxQV7(!535@fP}$Z_vlA>yg#igK?8{9q#s!X6R{VL#Kv* zyldZpQ^b~-vt&6#c5sF)bnBo`&8{BUclTp1MKGr#nOjlJv1sN^47O*%y!YV{yCL4K z;7l00bDQVWvUgScyU9t$e)GvBJ(}+yT*+JkZY}#Q*}pQDI}w{_M?jBm-S0`%4 zqSI(XcH-Qtsj|#@Q1mBipS$Za{blk=dOb2@OZxfC^qno~*bR|i^tsQsq_H}lSuYo=^lxWqeOrK=^(~D&+E;0~DZ zC$W>#&O*Cqn$u;zr+_cT$7c-Fk0}_fzDvvDWv^40`W`e~-^Y2_5Zdw~`2z9F?dXA2 z-W{Wrt+(WLG1gW)F5Gzo<9j{hd>!LGmvNs156!8D4)k$@%yw)ZriY$3c+_q5SHu4J zxy|agF`n4eOS>)F+u2E54Bjp0hMm_bJaio8?ewWZpSg-o*Khq1^P#y+d=&@Qsgz=y zn$MrmsNmL(FUTaq{peB>&?kuQGavYQ=KZk*;hm+i`oBnf8C$%+W@b124!!_w9@u@f zzupL4Rj$v)7hj}*IDMyF`tFIX=e*6|!hhg>iU-^DcOoatJiM4P(iYJ(S0UHzN2XDE zZTwpDcC{z4bZmd4jkTr@YA_>egVHzhuGnSKTE0ZlA;v7ls<8n#><&saf#EgYYAn{k6q3ll5vl8 ztlug&DOb{7vHK7{&HH;zr^d22$(?QdhE%cdY?!Vozf%>wwIgq8i0=upNjZJB)+Be( z?gS@d6R^K1ZMBR|58%n3Er_t;nyJ2mw#G7OFpHp`!ekRSdorzbC z(btp4y4ISuYK(q2X~Mgnaz3?H?iHS`bm6(_#k`$Ni8yE))G? zq?(ViR!3<4D+(Bc!1gr;zGKWf>ap*rRlX4o8>0Ujs%`$LD9uwat?Tk3R(Z}y_B$iQ zerRX%!7(lOZ{rfRJ4z-?yQ2J;lULd`fVb8Q7}KuWb&~pp4ieDc)&keE8``4Ub-AZx zy3kgu-HOBwyA`8fN38O42hhS-|CE+?O%35*Fl{@}T#@w(-C}V8bl~Ql(}9kswz|N# zHJ-BO^fcREfL(uA?S9>?HxF5}wn-aV9)dEj2s)g3FbVUP7MBd?MPSl<&CTXt?y z{z%eaDl+Wgt8No|3UtTHfN_fnqw+NO&P_Y`s+F349vO1NV(#NJZ$20T|C05~w(f}D zz{h+RzX$gLL+poS?P=&_?U8;*nEOECeeLZ*EPuXUVAVo`c$W zch910z-~Q9?FYqYMNH`xWBEOx_FnjK?bmUHuY)i8-P$6wi3({4%Dr@|vc z**{J-?ZTiq(_2E>aZ5+8H*WEZ?ZfpPjX8Wt2H+)43 z9auE}4dW|3slUtIXAysax<0(lT(8*UKwERm9a;vL@FQi7$^r+8+zBb74&g0kntI3f z!1LU_xtX--=ox@hA5(ipW!V$T_xmgSu5|TptbMy#-50c%dyR4$cj2OWD{?>Y3CsP4 zW9ojxfR_6Wat12*8{*|Y1imBoV{^{hqTV`7;P)w4^jo34?JIA`xuI|OAm76cz`*a} z@lyIA@4X-^9uyxra{pspDEn9BQK7qDHO5-f9~wsfzgzoOobLT^x67K4vf&Md(Vdxi?Re|UnitbE;ZQ2cU_#V$q4 z4Oi`m_J0V@s$4fVimcv30|%1zKEPl-J~;(@SkX(!9X6pSg(Gd4{x;?FCW%~Yrd>Qt z|8MCNGG?3fjl=YPr28g=8`g*v;-!CR-X-%0*k8F{9H!QHO=EpOiJzOVO2^0FC3njd zJu2Eup)InnDF52Ax*VHci=N(up5!i&@iyQ9_0E{kv_(&Hzs7<88li)LSI=S+T8O)#b!7{jm;@^NF_VK>t)zR;_pt@({i;>i8^r% zdObhX*R)&N-$$7;rrf=V@=pO5f(P+o{T_V&F=Q(#EBVDQl!WE%VanMb$zI5bJU$gV zPC}<8I<;f(x~dC-FSaj%;Eyrkiydj)WiF^spPG+@nW%c7uYg( zzoU%7`&wcDjQsVSA%;S0R-3Ab!(R?PC-g@h&k{D1r==eD?y=G)c(>J`eCW@r=NAF$ zSweo%u{nVyx($J)c>b6;eH8eF4=Gp$@LwN%PTuB4S6jUn-8VF&cxr#gBU{nu91wli zFzTqn1~?)kyJ-&XK=-xt1N2?BO4rrjzk=_z7isAqpzC7Zs5=c-*};4}hMgVynv>MG z$vrz&m-~ofC%BAnf-6mP=!fFfU7Dsu7xykXM?j~$Y2uPpJ&Qcz^H=aC_-UB#+gmPY zeQN%9d?Vr&=7OwKvM-IHtjq(M6SW(gcd-Z2h3+@Nx2lWMJ=N?R#7F3{2%~*->HB7M z8>P+-TmOcSAt`H|5pc)DS-$l!X)?cMT~+uzpQ_)_eGd68JoD#f9J)D>__y(TS<5$k z!?b?;Dse=zeiy%A;(d)4Sew)I+a;}JwfJd)w+%dTnzi8@`1S_I+x|v?^ilRa(#QV= zZ&n`}*WDw|H^=Pe+ba6Hi@pjUsuDf~{;ngh@bftma`rJ>Li&D$Bh48x(AQz~%hp&wL!Otu!WS5@^PCetu&>b?YxG|p zg#H;@XfkIbYrCCyi2b|$xA0=2-&6mbT3xREGZ=3r$k@uAlqUG!H>_>#@gg{Rf_BK5 zA6I!Kuasfj?t(8PlUE~?hMGP!!X6ZzSd{-Q%E;Ij*!Xkd#^!c@QH=feI`RtL=2bNB zKJXuGXk`vc#X?La|xA&&)4< z7kSG{f0i=Reu3#GE-=}KMs)Hb9~GPJEERnM?_IE`-79TzUjX02 zSK8^c?Rtgz(0gcrw>5_X(+B^7=Qh2JUP16A`$KpW{>Rc94?c)}(vFGYX$3*&oVU`yMxOd4UGXrax|&2rLa z>1%sCRqMUd=62`ftQlXq-%QbEzRNt{VAgd8I8xW8wz?EvIRiRq)-|T3F2m0ku+4Mu zuFn?H8}4j5Pb`aTyaAqj);u3j>m)kQvz!myh|X5-d`+NjnJ(jOD8sdW>so%NxyrWE zo&$-E!_fmo_>aPu-ljcrZlls;N2qisx}ZOkUTM(9fyAC8Rr=H9e_h(oTVw?yw_k3S zJJ3gcKhC*b?Kp$3#9nS9`OlIjxNRg99wPDEfH48R{nBw_uh8Frk<>*w(I=0iOd@}l zFNGtva&Hn(LY6;v%JJL6>mL2uefOJBx-VoMjyrwNOL7)|f$suG=x^_MZ5RCY5PG*m zYP|lQrpH1b((gfxm*lyhdZkWHbLwAER%8gF?TO%M;`kA|!{yX(k^a(VXgBhC^vuuW zhiF7!?5mxj6~lXJ-eazw{#-}@6BE7K+?nhJ!WS2L7GKe4&a0#iVP5xKywo!@RMQtH z_8c~Yeo6Z4?2C?b&g}-~2s3RxIwwEndy#*!qt`IbyZipz6+W!yLeAmdg-bmTP~Qv4 z<;y0`;P*1m3&F_f!CG-4?`?hI3irP=a#R2c1lt_6OS{~6-K z$D}{XS8$o}esYQA4d?tWjWew7bfT=^N++uN7URGD3EsK-c~*7kOtE8V)f-A&=?z7e z4fi$eGV9RBupS^EIED5|M>lssbfRv}U6Ft;9sY5Jr59Cxxu>#@Qm4pi`}fJ*v)5bfc=yk*#$Kt-k>*;rXgw%8TtrSAD(1tQ#BUHhtA7Yusax z_75bF;ddPWd}jX?eC9@1u;-buYcFXFdn$X{Q1r(NChcnjb9>h?XPPh**!$VXrUh3s zIrD<{wP39#`D9jO=t)PTs^=H2^`x^kd*$_5p%3@sAi^nCwyb=PpE7_;;ExYw-_lZ*L2({@r>$n0(R)t~3Kz zx3uC)OPC4ogZMPHH^}8 zd8bTx?AzqikW;%{KQ?VWeNy4B@X%eh2DzG^LzPd{XS_gI$f3jZ6kjvX_Z!*dyIl{Cuvit&z(3%Gh-uPMd7&(>kY1zlJXq3yMlK& z9oW*z*x>7=nlf_U`w-z|{>0bGxt|7ezT1Oy-Vn}v-PnhOau3R>*P^=+_)5k@pI*z_ zJH?4!23oS8ZAu>C@07F6S<-KOWEOC)Ii;_b@icu>c;P%jaDE-%eHUrFN!yt?X1q%K z!>`!a<5xn?24qhhT6^!IWX>k*(Cg-+*9}js+q&2hdjA5`50a(V%|)+!1ify{8tb}O zokMJ;U-jsoYVkz?p1pJEdr5EZ5d+&g??nIb)#fWx_5HHH?qlfC(5uWn8{mu~X=vLs z2JT3-=ztS@iyRs4KmDAs-p6V&6&mLYchCmeuNdbGvHm;x9lv-i^d~+cBK-HzXXvR_ z&xAg!p7mS!xeFZahX%1BZE8-#j~5yY1*i=vHXpPvnukYPrw| zc5^CS^4j*PLQ~(>N8oDUC4fu8LmvCp+t{zl{HbQYS}6Nfd;|vai2?1a{ZBo*u13Xc zBK>Cw1I?R%#u@WwA7NweE6f!Ka|N5_J6+gcYI-TOHQ@nMzHHZTbABAq3R3i+(N?7! zp#KG}Xa8;bE@S&$?l+GEmdsJ;sOfL?xq<%fr@v9$ZZD)$U=m)Gn z?mN_W+LO21&@29 zD*l1y7@-r<12<51pVs)hP;9_N4taomi@O*0cz5JCS~lYng1cQ>5cb!^FQUAR^&1@^%y}YjkBR?3WQ9$3A6xsti`~x9vO|2izqa`;@Lay@xjiK{WNx=gtuZx$ldjmCs>2He|qS4?D*u)nydw{I-^e{kY2y$HuGK4NdI&6 zHNo`Fq1|yC?hFjwe|vh6F@1t@Z0{Fd&eFst)!dVAa&N%CgSXC;Hze!1tli>6I?3Hp zACLfTXy^pq*wDP?)!y34^+Hp$SM&j*XOz&*I#)=(3TIe_ytDZLd-i3#vALMHHJ7tr zerr%{+QvZ>55HZs#8Z>ldsxqt@tz&*z2$dL_Th`!Z@*Qv*n>ZR?^{L7Ju{FG!`XXJ z>xCUW`T;k8+c-N5<$O4acg?DuVQ)>~eKC0C+zHsQ%h}9^q9V_*3lo7; zz*+*VX|%Tv*hRoe?sX4w;0F7CTSPlgv37)Mp%tODvkLfA$S>n_3>&I=>ay->Sbpf6 zUw1Oc+{|O-k~_n&U3Kb07cwuHYpwURdHXMcea2SkGLJoy&{2}SPoH?z1x?c~#8+zG zX7ugN!`1zmP1?xUu8{AJ6zrnP?i+uk>}TWOQ)@Es-Z2kF9uq%Ig172upC=5x$Z^WQ zIgNb`y7_nq=gMOHN!}y;B}B1iGOovli~j<*evEpgzAt5M;d}lNO@A~}WZ7Fp9&a

    7&rvAj0=zk>j#EzKhr%H}&XH1Sj!9 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

    qt8q@A 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ĵ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 delta 444339 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νtgI?m}}(`tx`9F>ZW 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

    *J< zSdb{3CtOKKvA;V1wTpY`Bolq&EqFPZu*U5&o0*U5j}R zPB>6F-GO#m$NS%p1?P2GFqw9tzocF1gLG9I`ft){>2T|&*wFrKc(Ag5#m?WtZ!z~V zcA~J1h3stj02icw2cMS04O5 zol0M#Er*adZjKE-=;!GodN`f^6Z+@UCG=X@u=t-t!x1+4mcV!EjEiu4XKd(q2_8v% zT!9zRuI2DrI)VO<&Z2*{T0MU*|HFctZ1AJ&wBTDxx1vjLpue~97~v^&*)8-h6W*?^ zpFgwV2pdZNz=B)C&0FF?X6{Wp+(!RM;ij?_rKZDzcmgJ@)s7o zEgUDjp3Y(a3E^68Fwe|8)8*_RW{AQ};Z=0vT^uM|_=501bksfcySK#wOur#)#Icaf z1)GGA3jeOGzsW*tKW+VG^lvk-13%@84ejc}-GpDJJ&>z^|KGM?nMo&cz$bJLy^#*D zhYfz9Bk1dNB<<9W?*QGK_HU%utLJ|_3)PMoxSS4Y0`F4RuQ;M5T*y4J75sp9Xa{?= zM}JiZ_$4~Q4IZbg|CAm6jIzG}KQasMX!x8C?F47jiO<2m(rKOHzv)5`xI+hQ;L`;j zNT<*dbiT6n{$IvIWLGTsnhxp)pQfYfDmq~x^44zHFm5pHPglMOPov}g;q`RnD^K(H ze-^@qp`n~Eq-#He4XWuDbZ8*@pQq#LmuRoy$j8xcBjLn*KYp`C(|-xF@~ zEZ<`0&kGNw%b8E6E9fujN`r-b7OLn5 zmco1JkY(_7+VfM`r873jTMqZ3Jy*bQ(82VFbS}L@TR(s0EPTU;q|Y!QpN?Az-xYTC zzya((N8XQ)qTdvrMW--drEIFurNIy>p(XZ3)Yp{MPU7QN< zr+qfU*Se_tU;oqwY(=3~S8NdZHQa-)$b{cl*8N30;rVn#7QBZ2{=4As=+Zs#c{(c_ zuG`JPhTeNo=+X@i*ayE#`+WyT(?L1#S9C6Yly=>Z{2$t%cJ;*kN_w!tLeT*%m`+#G zpVKMFkmu1!$Kfj4QV4f=9vdW|gvZdaMetHO>MU%evrx)HK5c&v4Oi$$+R~jH(5+~{ z^XTtQdtHFv6JAbdBR4GDS#Z0E1%<*l=>X;qJ@^sP9qDR1fUcou)0W>be=BWgwR--4 zWudqX4RyS*L3}y<0$p((9WTF(HOl(_cTolX zRa>nK%6;jgM{o$8ZfRo8<7tmta3&q{1pEsfSsQ*pr`W+=dSO5NI!$o@4`(4<74!k- z(@FFe+NUn^;iq0q4}KeLzM zHBKsWz;BQP1g9~W8K=>{lPrLY7_cJWn!_m+e1xvvQ_+7esB>Wj2 z76k92^XM|VlCIwmFDQ8w`a9Dxqv1EKR?lB53o&fS3P-~hI%6VSOgm44>-Oh6HU)lx zPM!*XKqt(A9AK!*+wQ-f08enfBcXzfFhIOX!j` z`W9YK=Viggbn=Vuk7}#ue}^jQAF{|_ z&``jJq?7Oy{ut<34EIsi{nh8-QFP*YIFkJlCGZN`?l*WhU97F||0^tnl%nD3m$6|f z-H)!ig!~=4;xe2_*Ia>rq{GYL>vTTd<`vAZRJQ*9@6ST=RVkYd!KIdy^$#FbbUf`GfPtBGZ`%0@^asIdmhi8%#T9lKhW_&Qa7Q|}13XAs{~0sH4Stt4ygQ<>lm!QO zIGawS%W0=h$ejW)(C<0;1vnP+Ev_D-x2peY7o^%!+N@vq6=p1^#vi1H? z9E%NZv%&XmxZ@~nkoFEdQd$2{W`)C(nHNuhH_|~<;B)NvnFjww7txNR&A0-Kc7V`Ua)oi%a7|eH#fya*F{hz?XJT_F&S+w&UEVw}D z(zS#64$Vd0i_WJ*=#oU_%jlvNaIV3E?@AQz(8a6ZPOoEw+%Mp_>8!PIEbY1u-bnk? z-_x1&CAye493JYxV#CITjmQzQ%wT zg(HMl3g^&?+p+$ZaGMa!H}gOntLHzKg@9i$V7KsfVb?b?(CiPQqb_3o0^094I9vF} zsuITE*MEWlwv@PvVQE!>8;EoE+Id|Jn%C7fVt;Y__?<+-|HIu23@Uez5kc0 zg5DsY91W}3kZ=S3fq7vCe2Te!C2R@B2Hv;f&UE}8cr=|)FQk+Hbi(idJ5@m+Agl@t z4$y9Q;Uip-aSy&N?EDT6VCKHU;lj)RwSj@z{}$jwN@-gZNO;id>=cQ4Wx0!-Z$ShQ&NUifG6czA9XQ z4mNcB8-Jql5snnzBz(qd_57Iw8qBpF*k5?M@Mht2!VbJ!%=rU^r)lfw&urK%8qNwg zinTr90O4uEX~JiO8_eVVZyun(D(Jr?G94+rQTP-c&X2%;KGvJ|5uPf%aX#;VbHQoR z&|rb>zyZS3gf|Np3pb3jo!38(Z?SoRX`*41@LA!83&lX;Na2mbrwvhPu*i0xkMI=X z^>h|Lf>L4E#h7R2?+6>~MB$=vn|Rv+Zws##z9{Un#CH8yTN{=yZ3~uj!Y!8C4tQO7 zmGEg{r;lydkF>FR{#V!(ES8hPjtRB{h6yjD9sa==(Fx(Fmtnn`kAB?x{$KTYLHVq( z%O|!2LWMU7Ulo4#Q``07kJ)^-4bmFOcUNI{FiXA<+kgi|1<9Yeg74# z_x}Uo{wr(;#0q~;hw>x1N|(`fKg0Tj`}l}D(XKVT|HrW4@Bj@49q>d`>wz}W9`^7F z+Pg7qmxK+1+~F7K1aEi(9r6OahITXhpm10f^xuG3`oeeF5J$VML>}&ge5kVisty^B1*gxkLB$Zbqq5$>?G<<=9W)d+=(GU%Yr2d+PiMZ0 zyum8Wk9`ep3afwqFAxP+RnQye4~K`)*(2c(XrCZ>8C^#2prc12zfAj&h8rd00B&R8 ze#+K=|396D2sR`Hqan%Kp#HhvvG9*{WC;8h?e!+y@e6Da{}$|}Y<)rR!0#}37!OD3 zTt9z)@1d}s3!>hKf2Q-o;rq1R1lZ$CY*0vtDC?i0)QQO7r$Zy)Y3whb1g9ulfB!cN zheX34!p^I)Va{X>=ui7jf#0Fa=|yx*B=X&K_*A%bHShoQ87SDNV1xJ=*o#h@4}U;s zrobEM@(j3$&i)2&umkiHYHq%*SM4r{SN z#%|4d$=p@ONY`9KOkSOtPfB^ zr_d>R$iHI0+fT4@j0LBB6mHSUbmLSU!1oApPr8VHn@&55JYHEJAodu%o4H*9e1&;A zY*^~A#|HT)(9nx6D1_gm6Mum}SJoSporE_scRLOL%sl)Ie2IDLIoM$X_A5NEt?u96 zEVy1k!#FyWUQT;lM1D|NAE1UlO6Qa!KgE8(%kbZHKHYL74iI@o<@)~b$AVoM7JNWg z(x1_u*OBj~9V_80w98%CISm_lJ2takUa!)TuJ9b%w_P**{r?UY?AxQ^yt4HzrW0ALjb!n&JMhVM9U}EO6h94GO!$eUO z-~i?sFT=B#89h&(1*_Hbm%9K3rwk0N z{tO;M=O@82bmB@lUD^5;e-58zUP;&g26@pclg8k^+&G0nZF&$1-w%-4NESzM6%N8`$-i{3_=*D!$ z*T`Ea>kYlWf&0*I+u^t9blRW;Gm&rD&ilWNg?u)+XQQE#_Sz4(%fyDc=it$F$~AZq zo&7t!kB%*e%arv;7XClD$qoYp1B74(KN zgVC^@4ZbhJ2k7u2@C`caCD?fnHmIUsrgQy~&r;U&OJ0WKnCHBrtndFc7BT|RaG3Ud z75<$rrt4>8!-&_AccuMD!J}xmH{gYId^Eh5&R)h(TwHF&CFNFP+t?$qx zcpCGh#qc`j(edyh=7k@_cj%G?xcxrNPhHj=_x}hMJU>Ol9A&*>b|Rd}yle&h9qo_= zU!#Lp!cTq27eM>cVV@(PtZaQjs|*wtvk>(Kyn+inSHrvMEcy%`l7jpnx{`L!!2wFv zAP=O2H^MXMFk=e}sVqcpgHO>Bhu{YLF|e=*?n9TKf+y3Nr{QE}{R)%Lz=xS<6vKZp zHxkdH;Bo*PRFuH4(A5{a0VSv3KuKu4T~;N}N0-~B2)7&a_X*HDs3xbmDdR4*LTt;3m1)(B~H1o6es(EF7e>-#_JIW$zTp{O(5@&~-)Y!7&# zvi@#&e;%Gfdv}LZ=^FYMI>ih517-aVy7z(|f8_n|;EjThD(DToUVy{t*gkL)olED@ z34M|OsjN3h_kkZWkM9R}$isYx{_u-=y#KRUn7{`A0cc33y?o*C>AV-=ayoM;+~g29 z7!JQodrp82+AkW;JY--&=qwbjvcY{e?D!L2k>f|Oud;rJJY(P~%$?@ItC+{ngMXrv z=fl->$O8B|<1hx+#Gx=oS-*wxi{OdOBjVvzbkY(yk1kyb-=3S{qwqrJdB@-k<}N4TbF@dHwtD^>9>ai2YeD`0fzU}O zu^?Pozhxdp@JGypPQzc(v1j04>B3_85$$*u?pA>PO0@O;|CTD~4XV$fVJ2N!0?+4y zjEnGBwC8W|5xSVZNk^0-cR7v?gD=4^(q-42asNlK;BpfUtLUgd;p22>!xq+Wy4pWu zU_?vUi;iyvPoM)`;3Q@J0=-+qdCY^`w7~uUCmVd)qM_9ZY>?a@euYl&0LRb~ZtynR z@mcu1vfePgBYcZ_VJEm%A?DXSXQ1HELVySSA)P>Prh~g6Kdr1ci0TUeK}UGP|FGY^ zJKXXYZ0PI-_oGt`7T#pRuO}J|x|mL*9r__ZM&}QN@6*+xaJQ4#(0(%f7F|Lwr;W5J zXxOI;`V}Qa!sTpmoC-Jn6?qliS6M%HMN!DZ>9P;uWIBBYoX_$dH)xlLg6+W98bgT&SHZSI#5}EhM8xOkEJ8e!tb%a z`W(E7E-!(%&=D8lBj!J1;dBv&8*E6Y9nbM2xr)3u9e*8upH6Ae()!J~nvQA)AEo`8 z!w+Z&XZTs;JYG>b3qi{IEsbb_hIz~bTf$#4Pj3wu(HU)EyArIAYzuoS>vt^A6&}bu z#0@qg*pT)N3v8(A2ydl5JHe;uxaVNY1#Fl{ccT+KBY#s_A0X5N4yWV0T5VXSb3s54 zG_0Zv>1;aM3;B84p(kAbA`VbZKTk*XMLvd38VJubJw#hQ|GQamdK(Ql=&;FftKYDJ z*A#ddT|>`O)~~QQ5_vlFkg4!#=DyS52h3AGRMz)@=TdBtIs*+Mbl6OInX=v>I~x9y zd0-6u6Z7Ob@LA@S23+S7=DW>Y5I%W}k zlKs9P!++AA%i!jhaeyq^n-2M;CGP*REL47i1@q|qmGBli=}Y(=U9cB^@(MPvKMW6` zOX%rzT0ZhM%K8N*9N}A3zy`;oX!wT>Rdl;DY*2I@`7pZdXE>HlKLPJh)*Cqd0v})= zQUqUTo@Sgv;Q<>;is4RIv7zHRcoZFe9-c?1(>v&>66B@I`T+hH;2X64Z}46A8;PYT zw7P~3oi4%s=p6bTI`A^`MB3*Hyq8WdhfB@%x8R1qV}8Y-@IctGcrnN7dXJf$u2PnpNIhYwh-p1;HnC{(f`$PI4)KWvcw z4BSmwZ(!dE4q+bn96W`2d>1%{&glvtp`AS8yW0Bx4`QL?b!_1JJQ~I*>(8)?9!F>O zKt756K0V=Ov`23^lg^|I>0oc4y<2=mbT2w`0rD_qeE`2WcnTe{2%gP;&yV4? z1`Am%9Hc`M&~TZqq#ggj0ZNu3_ol->gWsZ4zJTNDw6*Ylx_UQk++m^e5DM)pu|eKX z@Mt>WFdVC_Utv@}yq$S9eSvw&5#)BaG0*!r+@1FS*=oZwo&|>!Xh>4l8$=eu>zO+i z!N-}0oq|i5=bV8Z?qI{JV%VDwJO_u-iB_xUKZ%8q^Jw@{Ss%c&1pb*0z6hUXzsnW4 zf_A8Y@6&E{gFkT~AG!q{sIBk+=U8yRi2?oT40;4zL5I-3x6uC{okGu|9S74H9zEL5_g zCmnDf3w-Gq`c<=^ew_}kLI2xyE}q4)apoR%;Iqtwje00tXG3yBxQY$2jo^BJ;VlhvgqtYq4ZNO$+tJQX z!#!vxC%8Xd-4qU_jVxyr#;St8-C|n86WL&C1;;S=XbUf6o=1O4JG4W-m9Ae!OQ6^dMzFOJn~GsnEqZ{KYsz;(eN`He0#uWX@9z$cJo4h zo6e;Fp#ys&uYC_6X(`=9S^vyLc_a5zw%-5oEJU%vr7s#5a)2kji+Nr@A}Z z>Hf<409mghANDuz|9lo=*$@(lhUFX(N&mpyZY1(wnLE>V|6qfRQOKJr>!&K0evx@l zF!Ip`8^T#w#D7G^RzeNV&>Vj{e2uDAQX8EWqp89`eo)-m~ z`YiLfImoXwPo`Tw!~r~Fk#|xlDRY4yhjSVh|@Gj<_^fl&rE0Et~UQD}N z>R2DMh?U4+P}T>Cr6(|VN_N5hKbsBi$yl(J4LM)J-!U(wZ!iyAgS>`$H0@Cf2XIJ5 z-cMN{z?GiFJZpo2hPiCW-vDo8L&zrhAoEDNlDS)+|182Isvi_pU*ou5G^ISTL zd64l98Wyr4oZiibn(fFBGk45{tC^>L3)ioW17y>El=T4ub|D|iJd`$=8&!MIkjMu6 zY&ee%Df{44%roiwcG$pgKk}B!`YjHoUt?Zz5c%88ExGV#$PG)<4=ALuA)PMf0G~t1 z|HnL#Zc_&bC_9Y2o3cJYH66x0;VAMCnWxfQt+{&sypE&cJ2v>!l^jrV0(q^v*r1Z` zrL5oLxRc0VVxCOLF!wlxd>M0J`g@)0`@iT68cwpIoUU6B8^oML-dtI~!bEx~bGHk~ zLzsKhiOdUrL%yDQDSb-W(61osG8(S2A)an&j{~?|Mc!FiAHb6iWuEst@~O;=>CMa| zt|Q;WJeIDouY>>ouhUI5JYa)6-Mu~zkn;!f!OHpog>*FYusg_?Fps7WFn9P1`3dH( z^rQL)Hpse%2FC{2AfNVC*6&crKgfqOkEG`@w|jtm1#@Tm2j&@%kpId&m#%Fz#0Ei6 zw6=crIw|W{7*6{!udzcuin(JQcoFlodhjad*>pbhfCk9VG7qJV1`aqtl>-`DDeD8+ zH-ZD0r#uP2$vl((gt_0-$k#CsrVE)@I3d5p+|tx)!}3%k93ZJV8rm!C1EkX#sR$Aqv2U)eE@%YH1iTSjRY2Z!wSQhI|V1L^_qZTX*C;n0wQg znHP8=|C4#Cvi0}>4vsiLRBtqRDeD8o(_zeA`XK+1xhK7ed7cmQ-OP*WYs@1CAiu{v zc0g1GpnTNfE{5$5+bOm#VSCBto?)r*>Lf5Bp zfUE#`fU-V7J{`$CWEk>!%p>V>4jNuzgZ(&oHuID) z_+#dobPjXB_mLlG9!x)EUNHgrlTED$P(S|@QSem-eSoA0csLp?>GXW&K2wl?#ypVD zV_r5D`6=erblql{pAdz-xw7@&|4U`TpAB9!(eS#pL46Ob z!elmNtw)2Qtn++2lX*xQ^6!~P(tk3y`wF>TE39{>dnxN5@{BFWUozN`%fc)+1ZALM zDf4hThk4C5%W!XP!;( zW^R87`C;ZRbOrN>!#Y>rKM&XtYb{tT?c3mlg-0-;hq69k86C{rs{r`~=Kl02%#(jc zzK(eYoyWYUQ04mmKg9;eU$EdN9YEJ_iv#4*ZRzM=(eFja)34CJMaU!QG&-KHQnudz zX)KhT!h%C|>S_2gUHBVpam9gRnzgb1p|uU2)E(|mJN1Br>1=u$UFFpV_kS`AfjzMx zo35sdY46_1|Drvn!>!ukKnW}00dyiAO6Sra(ZwqaELg=t6&rTbfuA8SrX%PFbUy9Y z9tS9)htdv7SU-*Sp_A!IgM|Yuq|q1YT)I{VY~ZpI13S__bfB_+uG8p=bn55mH)yw2 z@Cw>+Nk$=^1@AB519UX~GhIYqrVGDBe+^xl0ylHxbG`=dOoy(8`@@DMcpVBsY=}yQ zC(_aMY`Td4gf6Dj>GBO&pQo%J+w_g_WjdR_Z?$^<@>zKL87wHKJ?L_J2whEw(e`QB zU=Hm}C(-WoHrkuc*VfOUKMN&n2&Sv(aQf+IalmN$SvsEXPbbqMbUGcQtbazb=_Sh6 z-~T-};T5c7Lj}E$j@XR+7+pnQp<};7{(z25hg){UhDmfs+I|c2ejWMye?AMrZ1CTT zhDf@IUP|YEjr=RRoX(;{GLRpoUA}>@(kb+Vjs{NXz6}k{-C^hLuovw^_fytCR9TtG z$IyB747!M3L6^~A(N**zg9W=C7E?nICBu*0-TktX9vzHw&3;2%;T!VZn5B0G&t&(%;ZYbPiof7tv9> zG4B=~udVO@1|EEi*wBftq=(S%doW-;9YIf{i|M6wNH+S@=tw%3&QP}A|L0lAX2U;p z9^JeP4rsp@1HEWpdN7?qkEK2Lq5nhLk6up4?&JNR!9oHXj?u|52n6eTNO2 z(av-yx|Hrm$K;@Y811p2_y0r|GWVllFHSR5P1*_BI!i>Q#ytIhEAtX&{^~!bRPYrCk|9Ycc2YRE;f9Dh4Sy=;dJ^BaJaJm z=5xw}Kcd~}RkRnqi}s^W(Lr=IY*@lrXz@HYh@$(@arCQn51}i*ebQhdmW489eO)He_n0T=<3RSkaex%s zNm=(7(C*C3kD}j;c0LCC(*CsZ8Vk`ZgwW~qM7o%crtJ$ba1rfIucE{0bUK;dOXtIe z<)|v?SKxOX1IyWv@H6~~c0K_&^~O8kO?Ri$=;3r39Z9Dh(K48M{$Sdjca`---e+RDj0{R{PhFj2n_u=-m%Ohod|9i2JR;#V`*Xb8&uln!^ z+QShZM+dclKcMYf!ZBt(5dN61pueQk2erlhpUy(cU@XX@?fl_Gbn46SDY|kvTt-KZ zg#V^f#=s5w;2lZ+2yR9DFKcU9UvU=}JU&B1KiYi_{3>1ZH9VTGJO+=WgO0-=(k1lA zbY>~?b#%-f1BGp7!#((Wx}b%t^?+yT^mcG1o%;-2uPgs;(#t>HhdR?lCFD+-U;;MyK;&=0RTrUTrTPNco)Wcp<~oqmhXrl-?+ z^dfD2|0lR%gA`q;ZL!Q43a8Pt=?r>I5b_*)_1o|{`fdb#mkyo;JM>rIoObHpo|^-A zRyG>z!dw*mRY5z_fG3)s2glHf^cK2kA@VG`iatjNFGYUU^q276{`&q`8(LPQ&~yL} zU`c_y)46nz>9xq;qf6<}Xt#~X*V2A;9v%M`@)H9LY#6@>g;Ld^59FB*TYQmw?uA>^ zmGl79-yt7PJLbT1>7ZPA2^~dmH(1EdL&HAPMes2?^b~wjSsyU;G~8q$Y&r9PuI>by z%I<#~_%T$JM3G2RAws5v##2ek7&1gr$ruqLu{>X9zX{Y9_Cj%rkl3+K>pNV6c z9=|7&`iL*H+WU!{VET7ri49~t`XKRcxCy?-@~??@iq^&oev=ML+GK#HKg4^P9$!Ec z@4|`aejlrSD)C*IF^#x~WqxASjbuE@8N}W!&m1@N`Ojhnvq%A_4mt=CYcV~(0J;=0 z9k!Dt-UKrghz-#{NtxISPK9IPN8=tp|DR%jA{6w)_3$5`>=8p@fVoq0&zcV2mgb! zVQyWr!0d#D)Wn2SnZfv7oqdB0paK`dmT(2kzyP&yCffVqT3Gic8IN-_8Q&6K0{h*h zNP!80SQPlf)$mo;0Jli}OO}&~f3SR;SZoWqLXW$|3b5`y;$?6FRYHRG2o9Xc#E2t#(N8w8NI&Almw7-J;>xlbdit&X6VtQo7pm|6 z_8B+DykZ#yi5Nf?u0jW0coNTge0; z;gw8}57-KO!6R@WESpcpzm5J8@Oz3C{38Wp=+FTRn2-qyXi^hT!5mmqlvoCifS18d z@LE>A7^&A`c_A?sh(KTw3Bq6}_##{YUuIdJ)Zbuw{6kcrM*I$b1^K-KR7hzMTsqqP4AlQk50SvGYRt;)l^Zz}9f=be%8J_c&xF2?c|FY^~PD`@Df*Mk<1;^GB z>%#r81*}^~kpdf5&_cYM>4`1tB94Gf;ivFUxCi}RU|B2Dp8;=!tKnd{gF^5C0Z%uX zuo;$x1-Fv{onSiL0qj% zz<8LJNc<3%gg?S`c+i$26WSq|X-CX}m07+_1~h>S;6S(uz6H~gNc{^~68^^W71GW_ z?IIJ>pOIibYzMD_8Sr*E2|frHz~@+gPR7fCX@$hKup~@z?ZyHSNWymTI+lyb06Squ zE3rSE1Si4;a6a4wH^H>FiT=#j|2<>@w01I}3`~bjVLSK;%z&@KNpKm;tdOo!`XJ9rFcz>*GR0SpB)o(^2V^u+n^ji3ny*I=3=>F@%UgnL+C zO4`?U{98} zlK$slh9^aW3$};U>6|tXW3N+u7f+VITc$qJeH2H}E zieY283r>b-dy@L!@Os#ogYrWChSOm|FXomq7p%!iu1K8e@e82C%g|m8uSI(kY=L$jZqlD} zN5LEfCs7a!C&9^ZDx3~Kg0tZ=xD>93tKm+#gP5XC@+Mc*j{*@`c@kOSLf8Xd4yVJq ztp4zJSaLGy?*!Yy-mLz|$J?3D|1ku#DGC!eStM+Hg7_wE2|tBn;R>cDrZRtHGL+PJ z!jkZ0AJVP~FJzjZS#Lb<@$+91ffEYW!VK6Lj)k4!bolVNr!gNh_$pium%x>9H(bs1 z#QD#EkPJ|d0(rOz)`2@AH$V!BU}yh_>&2mU|E(=kqg`m)53^dV2XB{1g8;5!gpCd zL)zcMba;^EaMC^}fGofc)@1oCX}5wIus<aGcoZbTPg#y6?O)&mm^+Y6Sa6QC z%fgkgAxw`W?fY52NE|s~=JRKaAR7e*Nu;2bXOB#-H1y zc2dxRf~2p+Q^!w7W_voU0@H^{yD7_mi4Veda5T#!q&*8}z}3|F*Z<537^9?M7zIhN z7=tVzX^gb5gbQFBmj99VAh-#>%rZ@J;-&o=OyeMKVPHZUCkZAWArnf%GAwhE_DwJy zc4C>Ew4Y*{e>(F+I*B+J=7zt(Ja9LKfEPg@tPc;cJedrrdK42(AzsC@2=NhE06q^( z!k1uWn7WOCj^HtD441-o@F&;nuaC{Td)VP%%Z$bg8Sn}?0@j0*U>i7{>520{0zoDU9>Ll0 zGx#xF1dqU_EGv*5n0g#HsUq=8m>b>&^C&8k^M4-#UKH$y^-jp3899UKdLz$q{T&VeJ~S8x(sKVjzcmyST-6j^a5 zyd2Jk*TIirZFmIMW!a4Ez$uuvjW`eHhMUJtF%JtK1U)DafcxP&@F1)SFAF0JrkRro z*0AhA91IJ<(Xb?($TT&6S}7w)LjfJmgN@-=upL|rd%#^V10I1R;OVEyf|Fp0)8k+N zGZ&DKU@HnTVP7~KJ_;AWA#f>t67GOs!rky+xF23{hI#&vFJKUX!WrV9uo5ibNVZfB z4ulWDG$+y?$g&^tGgg1N3YLWHCdU=i2@mW3Ix790U@fsl0J79SDq3-~?O3uCN`vA7;S! zV46Rf@G;A$i2uO?uwVpPkmQ7!&%Y=FWfaK5bXWs6hIL>&cpK~iJHQOs7mk2K;iPeo zpZ{?P(os+jXTm?=Y@qzzL?qzOXTT9JYfmz#i~Tm;q>rx2n5$MBTVFS1mj(~ev zP9zg3Mv(>6E)#38e2+K~7J$QHN)kad0%iCHOouaJW4I8ugWtg(a0|?U2jK{K(uIiy zQ?w)mvq?Zphjrmh*d5M>55bS&KzIaZu$)eIpa7=bC;mQR=JUsmKqQ)MArHI|=7pu< zP*@HQd_V?tf@zt=2Usp5&VmKtvT=`}|B?vaqCgpLg6VJ{Yz&XVcJTBVaseK&1k8Yy z;0Tz`^u+m}gkUQQ(&1xpCY%Ci!zQ=M6@lRL)o)U-iUlPHLII;j`SOTWQim)-f3bupwU=P>^ zX25Q61RO*mNJ4NHPKTevnQ#Z34G+MN;URbg9%i|g?7+&4f9KF!TA(MUaGoayT6xgEL{Ncya~VuoCk6X$n z{H7mm3I}Zl^XF1qzY_Dq1qH;jVWHCb6W`SpXZba0mxouC6R&_sWVG)bHy`t_ z0*$%JUO1sZ`vsZ62d+Lwd>l3oCO!u*L;FRT2fht!H;~@|ehlZ~w@=H)&BuHxu*3qY zP~dcnOwbG`yOApxfIapQbMcTJi}E2BfCUZ{OTdAV#0v0W1o66YkG~Y?I*`B+1>Hx8 zcfs`@WI+d5?eI~!9FBquyhwdA+yv*sNpL08)cD6d^Dybqgo4Z<;@@yQe#x4~ORhNd z8CjqZtc`nO0nFn``m4f{@CNt}Y|6`gDIQ-yDXzd31xY9ffTQ3rI267F2g0dvHk=F3 zfh%AE_%kna|Hl_#|BKutJt(MNLayK++>Zs$no8S zg8i@u90dQy0?xtR17yKhVTGT>_u&G3$O_;*)W3$)VX78^HiEA(cQo07F*rDmSYR62 z0UmfETpml>wcw^9vY?G{Hx{@R?jSqP{8j{lWUP2EoC&+Z_3mVX!|=XgGQmkWw2e3p z)`wGJNz^}rWBtc(V&?Pz5kY1NnV=g^<|gLlBUhX>jaUwrDkM+AD!3Jol@V-%w<_2P z2jiEpUEtF_%>Lt_ig+W~_k#?01P&b~6P|;4^htX%EdGhK=fHl}r2P||H%QvQ!pnXW zkH8+x@h3hNnK7MQVQ?=gkbpJuoBK+z{t7a|MmVCD)LX&YW~BW9Tq;XU!Gl;pB+NaG zw<5U1D%e0e6vFj*VX1`U`^khYaAgJYPnhwJcq;R)BgP+VOFJ^21T2LGtHG_J6e*x1 z`2B+nU<%jMNxK&;xrR6l&cuQ)!VxP;`(0Ssl=vBZy@!nd9&VzplAs2G?mKc9x4^3w zkoIpdeG%~w*ls@Y_~njY@hX@fj=)VV4!2g3@nvC3|0Wq=IRg3(Vr|$G?I!Sb8PdK3 zc9JG`fSb_n0jGbK+m{9C*r1od1>ENP+N7vI9{lSOhm2llEn>G2WDg z4%4kj`xcmCM7$j?!cA=p-+4~jT_{$EViNek!SHdI_JXvZg9Y#wCGoILEV=9N!s*e( z`EceF;#Y7v+Nnka!FW%TPB{52nQ#cET_B!3i|o+*DB?MAGAsv6Mv!(bxEtebgcZnm z6wMrgF(z<^tKk4R77m9CTF6Zq1=H|JX#yM!--N4!$bufi`pM&FKL7a$geC&!C!_H1 zTcpD~*a_`*urk~Rcc8u>F32Za&Lu>4EFBhs^Ts`X{x3n0iGtOzH*5%Bhi&1a05)cT*aCj?8Quul(2kD#^avg8rq6XqGuzfvo zKP*{G{129@Cgv9=`yl&{co8i1o>&3ql=>8N)mzDZCas-(gg4A49sAp27WybHrRE@a zM=pu$Is%JdBG-8ambyrM1s=htt`A`ww7-D!;P-IpWzxTucmpjdo&>*85RVBtMaV*< zFu)vG9QCrWS$xdQgGy^SW9wr~4k|sRv~grDn?w5R7LgsH!yWh<+7M>oQ(;Tk7`7ib z^C!ELUX!2X_Jw8PQ*cBDX-^=gXmb#xqk!>-6coZd@JHCAlC*ciztKJh+r1_2GeyaQ zI#4eI8{=owS4^1s3{<0o;dsEjCG94Yf4XHCT);0x% zd~@G+Gw|dm9ZdK_|7-7ATQWBlZ&n2cEf|%(P20l3*w!NGdK?`7M@GCED&3~ z5Uzem22_I0@`zW$y4_?4bl_}U;a1oZFPFPn{qb3e7llCi85xiPw_-~p;eyAc{VFV( zMVtwHWD~!DOK~8)hgV^NO)$NmESTy=VBAN75m@;<@nmtbBa+x+LD&OdEJ(oK`^W-h zVO=+3HF%!`F&)+?^%QL@g7Uqjz#0}u2WMEwiM0E{MMLC;DwI_}NPH0uoNc?w!qW|ZK`Dsi4FBqSnww}$~*zC;aKsJZ7`5K$E{%0~j?dAW1iTP=b zZ0=+8KQ>RF|KBSVW3wWg*RqWHX=bc|%un0P<^VQdVDoi0KWFo2Huu9;n2$DD^1oLg z#pZQvHevG~Hv7d`QA+c-o@I;Ui8)!*rnC7On_sfIDyED%EY-sn|6}va1rt~EziH;N zc`=(+*}R&~y8ksrGx~2pvt_d*n|;|F#O7c&hq3wmf6TmVuKp*W(Nfs_fX&&&A27X`&8vw2_aWH8=FMz2X0th)t^YqyJT-g%zhL~5 zT-khp&4<`bu{o5@XW1P6e)33>W=l5joG?ZE-vais6}Yn5 zo6U#We2mRuY(CHCxN(cq{%-+S*a}i&4uvSq-<87_7qPjV%^%oY&*oM(cgFl-PD72c z#gnD~yZ`)bp3P=SHp{YEoy}|hYl^1x-+*SwW^*>%ve}KzK5PzP^RfR}h(KZ49Zvtl?-Dapquhbnnw1)oylKgHbzMv2WPV!8IdQkxGTSYgf0+MqSNM%sC9P=w_q!GxA6&-e5T4_bmPPIL zJ7HwGwxoT~);QpETzT$$l|90J);3`$`|ABFd{?N)VE=BKZEqFa0WzeA&iQjRN%xD+<(|qMCk|3;bY-}NtDWp+1q5K)@Z0Df3KSS#o)TKhELA* zcs|)}>$M{nWUt9zr<2joVX@FBqg3#>fcR31YnGYCmorX9PJ11%b{!v9-y?`p zeJO9lB5v27vw`<6nyovfE)_(jrnTRBd}gH9CS&Ah`%~2iraQ7b443ayeAQP_E|<6I zm0y=eY8SQWLh$0Y#}OZ#H`=PiufIFl&}Y@ElQEqW;+4PK?_p zroI+2-zugiYQ*hr?U3nZ$URp2X8x~SQF_D=8!Ao&&6cp{B(g1|K;;%H)^W5r(PV{ z(v~f?fxoS2((aZt=_}&pVXBQePffmOO}F`Uc(ZNzhyL@*0Y93&1;yloJW|(NZhg>>H3u;dZi7Gv}?26tn9XjecY~9sMxBR5WQ($|ntXG3i*Y;G;BjHKHmZc5*1Vgzwzs+{p^(Myq zSVf55CB;^Q9C=eoyE75J$F>59tq9*Ao|F&?&jdiQX_XOafeT?xvM8{DcP>PHSC$@B2JNGaaGld z*6~SiY`jmuOl=Z(=$fBX?4cF6YwMo%4qx&l?kF!^_IJaNs0`J~8uQi`EmYV|&Vc=mP~TZwGS3~_R`Pbzn`>va^7mNtYiZ6A zIh8i@cGJFXc{(5Fb?etv%(Lvw5h>47*+I=W_T^{3C2q3uJNmD@?4I50&DZJ7lsomDs&LnuUXv?U^b#`X5qymI#YUtGv?DUJ;OX&gv-nH#15 zEvcxB6|}zpI(*LLs`Yie*1Q$l6{GmVeyLx#tS@M_yIphp?TG{5_iuVKRp@!|nrP0E zq|7b@=_JML;#~X(58j%}C$RP7QwitXsb0NXXcdF&s1l1Sg)?Uqt#7^5(p%On(XZO3 z_4$|DkXeSpjM`7VpT1o)N-?;RDSE0kdBKu(QxEx$BhXI(qBW^zkMwf5OI;jqWWb)A9IgOmRB z)Vi2%+Ozshxz3(#EgbUGIqW-fK9yc{_7JwU_19ZpUG$v)@)AYfG>bbLVq-2m()!Yi zmz_~aY!k1cS3j@x8?Ku2^s8rg#n+U%9GhC+T~OHfoj)?tK)jWT`_=pN%gvWtJ$BgE z_X>rq%ULfMTh*fS^Jm*b-I^#yV-&xli}!=-RG;rNL0x>(A{Wrp}{5X zTYN`RuKLwImxW6HD9&uV`1bv+HdDjM#=D^z(e^f?{F0i(Z>v|_eYoM_aOvgS`Hsc+ zb*!v}zGmsysTbD1oqZseic+!G%U`%6!EaIU`VN}I+E~Y&{Xd1a$ZQKJlXiIGxZRJ_ zFizy>!_%4KJo6{zFZxib{&Vv~u7_Jn{Tr@FFVuJ&$~C2cYx9P^XJgL1y1*kobIOi> zi*+_9AK6}dDL0!D^zVU5)HY*Z#nVP*qGh7He`yK5eex*7{_;k@t3NH|6kI8bZD)eE zpHoPboMkJ0WSHW%(Q1j2O8Tw1cERjz;^qqbujJE@2F2GLU>{%c!Tz*m4$8LH;~Av3A&TZXgmSKQ8?(Y)kcIu&TX?T!?8rQ7oY(<(=;TiQqZA4@dO;BaxP zf1@Jm(y~EcBj{?}zq8z~DvxL*&uLC$65?`}G9q%<>@&2#DGFOuU+`r94clwFk=`lQ zLkkPP{L-ulr?1@q#rj{VN}97N*W$XADLRow|ANm470yzvU#9XW_00Q(q=lAC4;dy_ z-k|c`nnl7(^aYyqtNUCM`=%LKy*ut+>|Akb_lWP;fw$R(o0Ug%uXs7Dmt9)Wb8wN| zvbU#|Eeqs(MQZ2{hb9eh`pbLI-ZS{!W}n0vp;s&3@k>a)_%@tjvfXW9%+RSWrf0IC zSn!yB&y-g$|5{)BvFle{T)0Bzbh~pFF~Y`8O9QE)warh16z=u(woIWorsd6V7fP1R zSl)4NG*qYM+d;1_{yT-jBUfv0$$Co57rwus0+SaF>R3yU<~wbgm33&f_`8nK6{~1+FCz{4!}i*FIZvxj*tG1byzfJs zqrWypEgx1?x$=ju8XeRqvhL;Xl`gJxy-;6eJzH_aqbGdf;I?9`#d@$kF9 zG`B?W_bR>LwS4Bzu!`$*WLAV7Z!TFQ5%c-}u+pCmn~(WAES{6qHIczBjy91KD_eXu!`AB zKV<&2;=)bO%oR$;sp@Cm*`IkDerZ_G=hD&#WvjD0c1`zhH!5os){YXhtoZonWUS7e z$Eq@68VTmM-7lUOhSyez^%puctiOHQF3bFI(6Y6I)#uhFMG80Ue5jy7-F@};LcHcD zwacQx({p+seh%Xfy`SAsGm!E8{NX=erZ|-Cuznuft-GPcIi~7D=gRT72TSPdRk8ui7?agkiELRqmVtMb-S(yu=YHc4cs6L<9SozLgD|NG{dQt9^Ds#Wb z(;J&jR=lY`V_w;G!|(E>86F1@_*9Z|+`U=5L)@Y*l0W1x>!i=07kDQ_&Ren|c~@V)y+0x}hiDHaJ`!$d)nmEgMvoUK>ftlK*ik1{v|6urBGKA zPnC_P9-+4Xitc?wKbXgJX<^pI)Zw{z=W%X-sN^*w{o&tt>iGUdSUN0;hgKs86^XkYaNF}71u;X z%ZfQ~k32Z9rERm;`-quumv{avwlxxzb33CY;T$WhACz$N*|~u$i&lu#53QYaR@ri} zbIoB+vCmKWDtSkZH&M-WnSer->=awU92d&w!Unn0!R7ASt5r?b=w11@c31o+M?S}< zs>bc>c3!aTbc?dte1~&iXl26N9xnsaw;vub@)kc@mHJ_ATy28uk&O5^i)EeF^&-M= zKAfVbz3*?g5mhGE_kPwq`82*@tFax6F46v-nH@0oOorK}$OEs{uFj-tdLDHR2zf|< z$@(iOzK~{+YFef>$skTuaOtDzYkz-RzG~C6#IB&0mr`14j~uPO)E)b%BJOFW)+*Xv zIc=b7>~u-kDa+fA^kWWnU2^XkCIiydd*m!Wech-~)D&dz@VQUi$|Bb?Vry1ZZ=UW8 z5iPzara_y|G}L_N2=FlCeEFGrr}nBSe2v(@)n7$Y_clux&o$>+W2^4ubIH9f$#Cle z)jwY68>%WkX+IpkDm(k)b=z)ASTt7bDzBOSMu*H3UO&2N-9&$jCGB1OS}7eD3uJu74qrGNLC zbfgBil;zV);a*{{jH5oRGwZZC^RDvJ{MOMElb1dHA!e@9U$1^#k#{Md?8V_bcP}by z+9qZU#cjDUt$@;_-p)^nJffZ)$Ro7UI8 z(~MSrkMWB?R{G;R70;4_)t<`s-P3=4EPg-#KttyOUvKlc@JmpugF8iqanj@;eZvOeY1oy}bO5enp+HZz?D;F(w(oj8i)@^dnnBf-|>ER{JfxHkwYs7sJ`b4nxE{Z^9J(p z{>>8;PvFv9dWW;$^XACUwFAjbxiT|ns$Ah&Vt(iY<$5~e#H^zURRd<-VR@drE3d>q z9Si0WwJ_IcAF@NwnoKC?gV=X6Hs?g>0~7t@3HLbJ%n{G}*oR_`-FF%3 zv&7_e0vgtBqMVj^X#U>v_eJ!l>aQ}N`ID=co>#JIz7VEU^|Swe>c2)2LE-xmhI8vQ z-n6_ozhB)t`DJOy-XjZqIF4GypDuWibb>FuB;YLf&J9idIk75=o+q1T+bna=exYWf za^&t$-+zAn&yBl1gXiCS==dS-fJCcC%V1`{z_K0I629$=uHT^MHa#gfT%9thVpmjG zMqQ}lSn=m1)BGy0mo7(2je5Jd7inKoy09;~%lXk?E3e&WF06NRKcm0V>C0iO4Lo^w zZX4!4Q2sYHS}}a+Zupmx7aKZjN`COgWX3le`o5RFc+V!r;;+D-mET&|eEM4SE_b=8 zY1`X-k(-S}wUn|fZf{$3oa(!{?q?xiJAL8Gk=`xAmp_5V&Arm+_-eT=|pGhz^a~`uphD zmtQ)J{ZdBTH{2PlIGyZsWWnAWqDwcpDExK}ElbSLs4lPlW_HZSc>6;W3%8N9OzCJv zo8;Qrt{lVOJHu-YmK2wWFbeBJO-wzU%?wWdh&^7kK{Z(C_k*5ug;D2MzH)dT{Gh?y z-GhJ9I!289VqJULy`Q>5~yJ>Nf;xWH|Gbr(af|bIGu~_TDcu%Kh|4qx!JbLZ{TNQ32o#`|IWl}Nsb~@4PB}3<8edV zeLW6%1Ri>Ia_aAf3~pI(eeY)heZQ-?Tep9FzTx2Y9+x~vugqu8k8&2BzWkT#$%?3Q zy_v_aiz?dqQ``?#wpP|iwiNZGEw6ApBvBf(iSKWgdi=qiYos21el=}yL*7!4?8kI! z?IAgfih}gA_@q7GTC>J@uMFm|>uGDMwTr7fo?@i!HAU#t#tS7%0xHK{)JKo#)>?AE z$sIZnct}0J#rn_V@QtfB{o;_g&Dpp8VWm@|u7Krg!2b=oy7FF=RO$-nAm*I=-QqpGPBkGp>1yA zl;YKKQie0;51LN;{OLRevWviG3TVCvkE+CI!_B#QdCnqUTxgj zYVtEH=Iohrux5Da%0E(+%=b^}v8in^k3uC(j>lx4IX&knf^;;%YnY_8Y2oRKwI)@{;IK3m40k)UhSk}Hej0X_?Q25 zen60~r-{J4(z(rUSGXOl%uiLBe^v(rSkcvfVVpaP%PpT#&v1m*#tAG1yBgG-K=&P5Kj{Ab8-;{=0SL}ZtSUJ=g&)cwSa@Dnc zQ`b)w;PA5X@C^UR_gq*k{-U@PzKy1_|{Yl|CXFU$$%XSY+-S zp1W^xRoR^LzaMC?4K@_Fei&X|A!Gf}$g=m0uXbAQ^u=b2OPbw}Fa1TGJvb#WD|Z=H z93{Q<{6Ldpq=QCr+Q-SlMaM>N=Y@UjIdK9N+)e#5 zuIn)wZh@&oG^ulH$``Q2Yk;svo*jzQhCp%ny8~fUu}Zh=es@RPg!Aj zFM#7uq1r`{WGjb#Ke-GBi#sPBes=uWP2N2zyC_MGEqw1FmvxxO zU#lxe{?6q8Xo^~?`(D}ZuuM$V>*uF`E*rkCzi78h zP)hLnq-T`nsuU-2+nh3$o}&YQlR4M$D_Q$)ecaUA9Wd*9U4C<qe@^}4YJ0HYk5kq1HQfhNMfIgddaH#uJh{wq z@>%7hO+0sZaNM$K=Go=tdD!KBA^!gPar7 z1I${}#l>~(Jv6u04@o`Nu%5f~Y0C29&n;S?Lys>|exm&@d+JpBKtn%O9Pp;A=V}SK9xqIa^VvUL~{j+CKZj z*(tvZmE0Z0S3JF#K^O7Sm@;!M#ro)m1>yJK%f^^i`6h%4 zg?Ud?>e-cOyw+dr=i>9X)x=63NK*rmZuG)@^JmX)R-HK`?X>%z+i1&br>d_XUUQX% ztlX{IFX>Rew!7W?(%3!eidlP=EOuSh5-8YVURm1tM8oyO&(RJcpV`yuRw@pzlz)@b zG{f)*@7F-S^|aR&ts8s0cZUvZHqPVvrg68@zt`*DW?lKYjoP{V+r)JR-OdcsFTJBC z_b=R}FwD?idjFco&3AL7`2$)_6kjF%3Y0XTexV_M`uX_pTlY>sIoagb_7jt~jvnwe zyW`p<>NUo%YddC@?|OiD$mj^8VC&K~5}IeN&+Fn-g{J(Sd@U&_-f%ICz^?6gd{*>LKv^Xc-! zJ=e6p)m(8~l{@vK@cd8BcK08dXRSU^Wfxa|qqEXyY+i4SMQrnu4F?>PEiQ8W^wKw; z=bm*^!)SJWsN6t-&IOLC8ApUelb^bu58w4DMt|hR{H^=5qiMrNkAvI0#SUFq->$yk zS)SOc&3s!a=P9Pz#-XQ^=uM+q| zG+!j&mI)7!FMZw;WOURjd}Hjp5Nr4Im)eJ7Q)jIGX}zhHil6d5WZ>#Y^=pPZeDf}M zu8`{3#{91B;^P|y)So&Gg+{lX5lLH^&7r(e|vf_`Qj6mPzGmSp$vf7PO_L|N5Yi9CsgqLT}bnW!}N;BmzYu%7= z7YJ(Z+4dtrUGUGf8`adqNzaFZ`?I4r4u72Hme9RhCM`B`!;ZnMIqu7QY`C~aq`rwo z{JTb%E#7$GWK7=a_4kFZEx+rypglCIWPZ}3}(;@AsPY-WXfhy~p%OYPC ziBIiFX=iX=REg#@)3h5pI^RC&NTiF_rnUbP7gzB6x4Muqz@Ufbs^zq>+n)s+fY8>d}UDOq}S`d{@OKR4U#9=zmxrJ?C|r{<{29Rpo=}g3);Gf4Tj$?e}f&S)_0}sZvqrO<&fL%)4uTr84?YI34W&`+Q;J z+4fAi7lH%R+*8~~-yJM$H7JR?=&(b+bPAR56m=_$mi@ke-SQX0iO!F`WP*2odAWB^ zW6{gP?Nzn?-d3Y2p{qkU9EwjqsB~~0Uf?Md(JrGc@r|-Fl1q!8KFgPX)^NmSF2OMG zlHiT~I*0h%pSzi4%?l4PO}HFaDIA!PyIyjVaL!7ePbzV@YAr_h*xOqaaQCdZ;-r`7 z5qIa+qk4}O+a4%y3b!8!qoy?g?RM4drw6?R2S=2cAZ^$$k?JKuHTNdu+Z_w~uRzTtT!>#Jnf9fqIv(6^R%~n|o6)_J-wFBzmllD79|8 zr_mAdO3&-~noshh{!2r>o(okl-v+p5a>M(=ku5E`{w}o%{ASk$^Eb%W{V;S$zWqS( zdwZ^QMY=le(w_wZ*5`M9+@YFV{mt%9{jB{~^i|xv@>llm2$}p+!Q*v)tln<3 zch-gOg~4kkP14g*p3?H~ylC$xo4Cnpiv(%Q6H_!RzP(Irczts6;*KW~T?LQ&*VP>0 zmfiJW2A_5jeelS6wHrs*sqGuxtCr0}as6pu*T=9~tg`r<*^f&r8hswgroR-nJ9O=A zd(wjA^Zve`D()I|{AF8Fb7wXE?GEpHmxX;kefQe$)f~M1LexQS$~31#{*h|NL@;sQ6ZEDlaVlR8`$CwVkJol{DySk@bEd7lUSfiWpw_e!<@yvz9TQ!&9sS z1E{jX&%(;@UO#z7T{dyd5Su&wQANUsppf1-TN32-1ce^-JXN?9?!h6DTk`eUxjVwA zy``IfZ|z-X=ZVxADiDU*}a-a<8p>Ma%q@5}Glx%+ilzV6?{s+)BB?8S zlJP?#rL1-eXQHJ>b%P;yyUE$U;m!;rZX=nJy0S!d{(Vm;8$P%Bt2xayU9g#PG|%~P zNPO>Vk?2TI*RYuCijtbzp!;D?m-x~W;u{+j+cf&pUr_nf?e7R^AeS6rXPj<#+^#n(qJI4e9VSE#TIXgy^kJ#VsBiG$wKKOCMm+qh$F zk8u0Zej8Ob^QH7SSLkz!7 z)^r^+sSctaJX~=|HX?xq%?{eBGmmT+SdYQW=cj#rnvefsF=lT}b8AjT+ zdtGae>)RwYH6d1OQ<=|}sn@qEc+Fqksyvnz9ahn{tWl_CWxGP$wB@0$cV-wYb$Rej zaFN*161$F)7lIU(Q)KCsQqxivac5`$iO{k6d!GWn^|!w_y2vcMTcWYiv9q5=>4St>+&cirE-WKYi|eGmC3IqRQt6)oG$Df*~v&FT{k zTuQWWxL9w zCg&W}(+dQCzRXJ7nB5|_zNL1oQsVRQ1({ODUDZ&>@2j4!z3SLIBE0?n`&6p2|A5pJ ziwj4m9qlMy^vTY6=(=FfvhEUkgO=Fv)PK>Xt1B+QpSRc~fq!P+B^QH~!53=t9&Irm zJIb9JBLBR3S6)8fqo4E+ znV)XjDKW+P?&vayvvMK~jw<0i*Z%F)`;wNRK=;QjC!5ZmxnU)snCr=1GyUBu4}XD9 z%jS+Me>ba|`>W*K_hf`_sS25_GFRB$qM`1D)8?D;@8_;N_iSbaLq^!i`$Y4t1+vRkq0USk&qO+iz+-Z7%-lX{8ElDr{G#e>kqVV9}a@U56Z9|HayP zQRb6AoYb?QTY72g%m?a4t~*CHO|6TM@b%PgnSDI?`@-`llW(T2uJYfbrsm#XsU@&5 z{MN|>9H)8i)4nqp{QdvZMA)C;A1Lk!RuR>HP?K*A#%0u;Nm>{yW6=J zMG3T5H|*Z@o6F8iuX?`lF&B}!jy}_$TgOa0(Y=Tg=qWz@*=!E|m;UI_`Gd2NH!SmPtUjQ^c%fd?5tW@|bM}i%5rn?@h zP0#FdXM>soP0Wp>NnNP>xb2*|%s}A;q;b26{_LiM`{9B?2y2%e?fn=IPaLa9V)`E4 zJ3YP0DDRH$0o9N2f0r2OCcB)EqA@&=zxbTW z8b?*C2gTpsL*VAFXIf3Bu_)cvaO@uNO5Iq=W@KR9X42r=(K}r>82QNIvL-Ug9y6q}d>O#TrtvC88M#H5xtBPK5nI*x7GffSz3{y=J?F{On;$jlfE)AJn&6 zP|7bF!Zy)q_q2cEtnx|e?cp=T54ESoyCd74FMGIOXvM7<=H!KerltMlv6Si2K*Xi4 z<~3Z#4I9*};2O&y~*S-WlJip3h4O4I#wvQjjOSzxCT>GH9J>&3rR6 ze>vH@0=!|(mzsEW6f(Le686w9~gRIBRTy^u8 zgGEg4;_%47{}EIseFm zD=glMfs{Uu662#nuLHL();~e<=}P8_0f%B^076^sEoskIM;Vr9+_r+2vuyQ!H@~tqAKK3(kDB=xnbJ*1AWaG zLQVg{(WN#PAnPsRSKbtss++~$Ft*DRk!{iJABsPJ&H&CQ!0liHNNp=&IANI!70@@I ze=C$%7X>{T6=)6=iY)HW&ScP;s{Cx)DpD@AUp({2C{F41e?l+qCPLWjm z4t7rG@5qzEJP7k^*^mjRD>}w$tYSGQn9sTzBhCLI#RW=XW0tM=0S_CRT3WOvf1#(n zq>8xZu$*Vc z>pWhot&=+_wm3Yj1Z~WQ^yB4V@dA&1S88F25!);OF7^Y^sHo<;1H%+o>PI^vYxe^- z;dF)`x$eAzap+O={F74Vq%Df4g*oC?{T88FTSXvup&|3_k=+o?Gle%=CsZEjF3SENkBe>1e9m>Yx| zJVgggz5gz(6%@oNbgZp;(>3b6U-5p!Re^AZj5ts1zG3OKXxy32eKds0_VddC;5>zLmpX6X3S|c;c z<|6|0b7gQ$B!4brJ;s!(e?mRkM1y%%6)TEJKIfmZA2fB$BicCuR{@j(rI|)cOi_|( zyN>{lh_qF`DDIzd_RD8+Xx`N0gp&fhLy*cUla@%mV8UcS#M4HMQJO#SL@xe=zflQM zwi~Wza2bj7XhRO?X9jpFp_b{Nek@++y6rN6^s(U@>}tWi+<2KOe-!B0f%Yd#!Weny z!J|#YgLCfC|IJDGm-SQbbYOGfX>5kNzzafLt^TC7+9$L^+a+-{I~PiwM_zdU(FFtv zqMJ9M&Kx1N-6PO=fXLG$mRI+@Ec(=+A8cI^SJKjlv?T2l;zjZtV7{ay^`c;_>h%RL5n`R4yR=_x=>bn zZD`GsMr3=H$BYhS2(^bVX+ZhJP=;JV;UrJ}Giq6fdb-}`fAAsBJ=_|D4dHI8fSlJy zVl2`kAKVFVF&ToBh3yXZN*c3+Gp7i&HlH*jBCrn&K$Dau&L|uUbETeik=~`zU%BKM zFM?9@@hw9-a;(H@?rU`kCOBXDT$Yq&=R>NApYz>lsOaI#@i%xtvWQS1(F2fc{l}j5 zWjvLzTfrG-e|Ku4yPFSoZX`Dh0BUMFOGZNLoCH!d;tNs6L>gSYyHe;3zy0!` z;N`kxgdN9XQ3yk@A%{`2j5Wh{SELte?>5;9c$hu>6+*C%`dn>d+2_bph|GabD43RY zVdXWH`IiVM)m}IZN*64!4X;)3TFg8(8xk0;f^RPwe@flAy@F*f{mv}W^x`PQRC-y` zWXujag9;O8glCW*9`Rj$4koum;nfgQb*F#vHLs1Q7^zZrLfDy9Zr`2aYV*spdOtGZ z!s7wjvbLxif`4ZL%4E&AGA{DXk_vh0IlnG{6SalMfYXNnjoE6ej+&Fc21%Jw`QMcO z7LhnDe<*4g##*}Mc!@^8F`ug(527XrKVm6S*!VESna?;n7Cx^KfvYVll9WDGF5vqP z7y%z7`pF0$_G2Herq!#I0W9?RVoA6z=}s626Gkr~B7vG=a_&Ba_-Tfd5q6 z0s->YZxqY{p$cAN^P@k!%5ta-?qxSW1Lu2>5Lhuf(b06^;Ku=nPGUpJ&y&_WY^Gp_ z$G)cQr2#XLZ5twi5H&aZRlku_4G2_Q+_;!V#2SFxik0Aji|Phy9bEre@rpo^Or`c1 ze{!{$dr__))s|$;m20ZMx&#Tv3c(`~c2qSzgpObfBwkO_Lkiv%2yjuwp*%Qy&{PRT z=k!E1tt8Sqmyt~86nKX0li9!>>>pK815{_x$oEj07^zZGB*u<02o;rS^hWeb3L7O$ zoj-1+MCv%IVn1uBRfW#xRagaDC&+poe~s1;0OhBWoIHS4xNtmXE&^~K^F)M04v}YH zi<8JH50Ox>z(fSdlz|{|uzDh11~B}Yn)*qq0{GZAa&V#Pj|&>bjT3apjwlSC>4zF; z**{FU>e?Vttp(I$C42WhW3>%~H3ZckPZ@5((ty3wtlaAOcnUdU%l!s$ml!vhf37C)@EtJQc8mHQ>RW`OgIV>pbcRodXDU8XBJDQe`hK}70ZOWS8${)r+vKFlBhCbF|AXmsXu9Qz?Xm# zfgk~^EvGs0$}Qhy>zh#1!eqdd<9LPsU;@uQ%~a7Vz3X_ctrmX9dS%~+uL%#c+~fq= zTM3OVBpopa+Oow`4#Nzhtg|g$V@v&Op&Ikn+3i1bSo0r$f3~g-la?nm z9?##1W_l`L9V9~f${ApehBwjHYhM2z3a$sk#__v(Pksb81F@1Ke#Y$(G0&l5FFBPt zj3sJ7$qOSlQ$;3PSxgPJyBlj4vS85^R zDuO#@P8TKDjlB*)oQ`VB+$P7ydq?^>en#jZZhK@ zylOFTM}{BdS%!RIPv~8ah}S~ZY^$Opi#Ec({$c64^WkcHW-9s(*UiBlRt&x5|7UNz zgp=s&5?+M(Bn5t>bO)**=>rP{p6Ji`E2cb0zfNs!lI}ZJwh9yWf6^RZGMyU45seh^ za9n}MpsxfBK&s2AXb9lu@=a8wfh!yWs@CL;!}|y>d5~o(g|B%Q5I4Zzsz~1VZtuf1 z4JN7k38$D_&rV=2_ACnBG)2Un$pM>02P`1??>M`aH+(1=to5?1?ld*`>a~Rw z^wYZK0#ux074R?nf3VO=9>N|2@Bb>G>7NlHURhS|ok=F>uee!X$PK1OU&Jd z&4d(-{Q}227g1$`KV68ecChU1-Q_1ocKBBpp7(=wxptWjf1<4kljCb;G90AJShIop zmfRNMcOpR>s}s*H<5gS&RXFBj_oOm4tyBhJh=8H)<5&IysxLwKIg1K3$X%TmRNk!4 z1;_k7qL%mR!;N0W7J*}*UDC`&P7^HPul2m!DLwUzC`-K&SjfSpI7+O+ip|5qX_i(ES-?-7vG% zhjaVmFFgtpu9t-)TWl;#0~3Q5SA3LO4-WQ}A3fgZ*^U-(GyARv=uZ>W90pG&-nFn* zcVh!kmFC(PwT&RJmWYIj`zxSJQ%l?I0cKY!c!$cf#9E>KY22R zCC2-kr3NGQgp_&Fb_AALvKNLF2%c(`>}-}kf1x+*Xk!P?D#xmxG8az%k6&qGc$cjv zqUIaukgBSa^hoZI_eu#Rz1wA1!xbn<(HRg`a8E*m^D16o&CJTm2K{z1=}Ce@h#!D>)?gfq@}hyzsh}1e z^khd1_~@LE()xddnIYcUSy$?8nl)joe-@|Yy{I2_1VP{le=;pgiFmc%o`ect9_+!|C?L#PyNU^LHJeqphC^1K}uS8Y^sHsW$K-0l6e`%yy z6)sl4W*=3@AFoc5axbDNY|#CSn1$#EL?HiA4pPYw+LcS(xx%Wxxe>E>vEL;AvYnlH z>p0uHyN{FbsQ?(KR-DAE>rYiLIxlLov8mT${eq52WJJk#46J}Jxsy;pu{x={(vD5d zLLnjq?)WGoH6ZebWNn)I*wB-BrUzARCd85XCNP!=<0Gd4D`3o>AJwz~S?gt*b@hb?AsFD9E6eKSBxqKBf zqR>D4(U|ib&d<<4ez5j%zyLI%MM+p3OzOS1DhLhbtL(RW-0`KN-BNaZe|3l8XvD`e zSbWVH%xF!Av}x8wAM+rox;Kb5$G3*NhxtIObBRv0U`;DWzAmk>B+WKN<=F~N@)@xWa7k0 z!z-?33V9 zUETlh#1`bRBs(>iQ)o4yAauQNczoKjQC?&Ty!dM8!b{dG?O?>zkX_{-=u#`w`?Mn+b(v=cqf$$-0Hz<_AU^(fBb=`L45fYleC+IBWWjr}utZB92 zO~lKF>BAzq#%qTaVNDmLH|XY$G@fRu-~WF+VJ&^g14^$I%7&dIxGlt_zP~TkQcaJ} z-k-_*<(Y_xS5Bs*VSXyI$$mxgBL3g38B1;R z1l;8DCPq7m(q;=L8q-DEH1hD9&MbdKh2Lh3$N5M1N!(l*nluU37-NTnJ?~W!qXkFd zx3$$cMHnX2!XSe$amzyi-6|YWtK0sU6l>vi1=%Sn9CFNkUxA)Wa|uzgCwneosq{3M zg^k(;e~kXE)l}bEnd@}L8`s8SDa&iP3tn)x%qK`0x&S=1^BfI%V=kyqK+S)BMt#e$ z>@e$sXZ)**vL;{C@!LpVxM&*u9rRj4i36?nvOPQ!Q*XGmgre2Nx}D8$Ow$xn(UIj^ z^w={jx1UIl{eiW#_s_ej8HzcQ2vDR@7!x}QOM|X&FlWQ<&8LWTu+!&O@fw==vX;iJ z9xqPhjtd`Z9pM|0UDNh&f>wWAaty5@ytG+LQzlQ-n2)~9GBnH9X@O<)@@!8@(he3Gb@Ca{Dk!YXKvwNYJ z!Kkt-RHHAmA01tlTzBK$x{T(1MwTGM^CoXMIy4C)lgpKZo8n>^>ZcTnN4B7#K%Vp= zJ=l5+FB8z@$-x>%B@T-Hs7<{^H4yO+o^HtC_{Ay+ylFM8WAD&gkCu(ZCRLK)?(QMA zlN6fkBxU;$JSy@+O$mQpC*v%D0z(3P+i)Ns1tl|_|=ukW|GKCpk*=V#8~~Wg!nzP zsdr9?QC;m;u_iHn9?huqlw{52u9KqwJ4cRwnR|$OONA~)NDzM%H0NA_8%(O6+xrHB zb7$oyOLxPC!+Rxlxst{1NORn}Tyu76EUV4~+!=@T7m=77<2B~cV15l-~e>8I|H?MQ!s1M)oOyWU>drK;>MDu%sRmAT0l!_)BAv=C+DJ!eO z3tln|m}PVL6Y)>K^mn72PN1(!-($BUBMyZzbv%+-ZGhsHQV0yjXwla zdIL!!q{uqchCXRT*1(t%o8n78ft{V43Et)L7iE1>4{y+`a)>CfLau2`ZqP|SSX3-i zC*Is55x?ka#DE6YBpc&b&X$v{vQsf*)Rp51q{-Y>gGN}v>(`Y- z*u^u7`k8MUqTz6A{ja3ih_^fu<90B6iw$H|7QEv>rmOMVVa+EJN7MTl8& z!VFH^Cmzs+6P)UA{p+(%Gx4UTCEv%PT6%AkzFkjPn~Xm9*u>YUpvkJfy;YI&q{_KR zSS}32rs+4dQsliwOUi{(ezuoQf$ z3*xk3i~)vizn^=6I?Ys41BVyDLAkHbNRTiTuSzB=J zsNpEnYn(C zsm=E*PK&C;;muJ@hiW!auW<)qXXJ{a&{BV8ja%Ykx(V<2ZcG^{+YfTFp0hl2KKX9+ z-UL*27Ef+pg}4l{g>y5<;|di>7?fVP{i^Vuv!aDLxm@>1vA~;^z*Ajv_Z&F;rw@m` zM99mBVu97@B{Zpje`mW>KajPC@S_hR(IkIvgZq&h7as*IClK)&dxz~Q!)U*KJ% z=C4tVcecj#xX;~|09PTXhrzB{Wl7I*dmRlPNrmpfj===e0D?QRL`LDRz5WTwL~kFW zHJ!}PL`Cd>fqc@ios*`B4suma-XGre84T(7AZtEGSgQ&F=Cc{kX3$ZW2EHp2G9YR3|7-^m9OhU zDLu>LN3ME!PR7m95zyZNy}Px#mW#cw)vw^!W_>S}uz0`>n$NvjoAw`8nXsB#d^WRa zgGm{3yCb3>@St|U*l~ZQVSd_LhI!~9pJL-3LiFg$pz@5vZs;hXlCl`G+XA?gWdhp`IMSdDZL~oDc)hbgIPjR*E{q+@7A83|5xKJEXB&MK2 z+E48E(x;(wv&+%F6JOk^iUS;;-vF-(z56boPq*{6(ls@nz!&j`YEW`DhqKFL}dhJJa9bQMhWFj^O``V+J zvBfZO_)@3lHo|{f9h$dsDI6?!c(v7HqF_0=b`?5yny}I`VJTiohi^r%aalG|FZgoW zdlvMExr7)7qRi~T07`M1w0~QiO1B@y7bfb%l;ng)WMdF6)o~uG^I0p$IQx8L;Cv89 zib3I2=HinF;&6ML9KvSrB_>W$F|TK14<*)$=UVixS*(8yYhx#L&q&-YEAwlQb+xsrd=h36V=cV$_Xljl8pMXUW!=tyBi zx6WO;JJZD~(FMvDWe4vt0qFj57Kp%I8xmzT{10PKrOmh@#WbfIqFMBpI;ij$`XpD7 z859HP>@-wpm?2AG`Q!Q#kvdCE6jKO5|F7cCgF8(&Zztz;h^Z})e!>VM)2^~ei-Lf1 z#YunalBh&D)J6N0-8izXy82djoX<~oeY1LySs^?uGY7*NNXSrB0pK${@;t~;Q^fF z{i?1~KqbJvnbypg1_W|XUOIoA?0(S`^48K{F`2E}=j7yO4V;v%mN1oj9NZ+fbRuIV zU@A@kjpnhIqH1*%xb?Hd1G{I)Glq7d;t2>L6f?#WhfH8qBtAfw{)Gy6?GXeud_;f4 z7l$c~Z0byt$4!O_vflYp@-c!MCS#-)CnUYYRUJd7S?fi09X=04EHF7eoweBf*#(tj z>RffFs>o!aVo=UE5$3JT5A)}&fC)XH`$WWz1jy*1xobN8-5{fS!_JSf$b0I*@*`7F z@Mjpq=|ejNCZl)~XG)$uKK$Y_9i)H9fXJlxy?vs9HHB#54{y8ontmsgCY`gZ4*nWL zB+3<1WCY@?D+iAlpKxW@9<-M3z84!0QtJ&jZC8@$*nh-uQho|C&nYzcU~WlR(5RyW zC!sk>!tfCLZwR$SewBu5k%64sYXUl5h9an34GIs5D@WyPf7;aKXt-J%7OQ`Xe@L>k zX2#%He_GbD!$VhdONqfyynby(w!ILCNRg0If;W$TWvE=yUm{bix=tS%H=(pS?dM)y z0yRcUP4(S?%bpFuX!SXm3pF@34Ez5pzHU?SGGxnHmly-W2H6y_%md3qwYiCQpKH8# zL_ns(hsT5t*f#d$r3gK#cg%mpI~6<+q0z^oOE)aH!WGL6;i=?bh)Zl+r&y%Vb_V($DefQVu!UmEOIkZw$6OhmFsL7)e9a8^8tK zwZ~7TjYYc6WaCf=Nv)3q|M;daA=DC4xpW8lG+~V-3@%6@n zAD^GlUt2zXff2_r)e!ld_QbLC@swti-NS(xL_X!`fe@x((Hb!#6%zTAg6tnF?Y=0# zm9bO1Xjm7qy)D#F3PIUoQ@>{?_)a%@~)qE0P}nb`t}HWUJ{x1Y3NBCDfL(2Q(2I^dB? zYiQ@be-0*qb?ASqz;Rvr+ErH_L5FfB*XfQP5z9kL%$R%p1!lFrNw9!U4*B^ zfT;jZK$xerNvcFvHY&(>8p-rCn@RPS@fn=dpaelHzCwRAP-2d)c-n8&9o{x_L%G5m%=A1N(^5lCacN3qod^aQ z*DPSEghzik<=5ER{YvbCYq+l9j?Me}+~iK5km7RB_2C4)p(udeSc6z4_R@K3%(zMu1Uf!yBI}!*UP ztZleY7Q;!Sri4YgMqo_|8%3|#Z8(FW4I`Xr!n%LkZkdLJrnoob0JejSMh;vUyd{UX zN*ch6{PT*G^8yioPA7Z&x-^Z`JMU9L2!9n9R8Pp!JY!IKGtzn08f5#yOn?x&RH6r0 zVjl9BOAoI@>^%)%_UmG%p>f%5h1>)8w_Sj!xMWGb+;JdVBGKi=d;k5SHRS%pT~O$o?k3OBlUnARln1-`Mniblp%-Z_+>2_5`mT0#lp(}enP$Ags=T>9+AK)0V_qK-D(X5=Wb zS^0@X;;F|fQ*rxqN^Xg*h8vcuB5Obb+spr4O#wPBxhCEq>jYQh7O`jRsOo=+ zi;ZzJ5FuP$n@hpmN;o@uEDsT-r*C5)308e-RyXO>;r_WnToUY51!Vfw?pq!% zAt=^j>AY2%0N{mJSL3f*tV8GVe*cRA@~~VMd$-6KzV1I{qr-9vY8p(lH1M|kgYEH& zfT-yWo7Om@a`2K)$J`SYqO5%Pm=K?N!)=ee4o8*HRX2XB`LE z7M~PO?4;6rweOb$5c(2DP*QvSK*weye{uU)ND%ltI?t4{>}PaW&jD#opk8 zGBQY0=D8GYnq*MMf+MAE_85Pjni^-%ug7#1{&a(Wq(+7>cp_zU2Mgz zz_IQk4gL}g9um&%7}O*oxeV^i)$12~cT1Xb6QSIDe30yLjOtF3)nhDphAm$7cGQND z!;RP{YvHg8Df*l7vzeEG0G#V-bo+l%hx_63`&`{v zmYfQyi_E(365HeSUv~|XvBb3N673pH%ua+19t3^S+}`M9@8n*xyC!Oa{t4FckXr9+ z`v%?LE1Fuvijzk@2EhW^N1KyuGR`Cru_pA9t?9Oj-!C8fYdHs~HZX=LV*)9xUxqv~ zT_fm!7`Y}cP_s1QiGhF5zl;K*UyO=Q=a7@7KWW>E?neNC!`!DT5Dsf_IH53vzqvqW9ntc_zw( zMlXJf3mKj0T{iP(Z46m?GVcCsWO7Fkzn9a2H9#PJPing2TzhK}S`<;vtmnr^-R6AO zB*D10Zu0_xzY4-gXXLGZyK&BU7=e6jRkjT;qWqw$iS9L3@|8 zg*Cu`OWD}ZU#vy$R+?Sp{apm?rxn1BwaD*47suDtdjklK*r@NCL+_I6e@`UcEAt)T zxE|GIg7qEJ?lM~8>qC{f%Xxgt&{_;lO=%~8+_Xn8003_f;FpTWh1Zk2uPmTg-))#N zcOc@_nwyh5$?u_BJpx|yh@2-=#Qty5obRalUsrUc4W>*KX7R>nuk6SqH?!t!5L#fK z`p92$rOCge8nK>4kRmLzI5u;{hB^57Ius4*%vtNn-AN3buTKXHWb^7V1NK(mLiYE6 zahz9C$dWHMYRR(OQEC`+$@ETY#aiRzL2)N3pN7VtNksDqi5*w|p+|7hCORX0xT(93 zH9$gdb8FB#F~Wl?NAArhaa_(nbS}?CpW{@H7UOV$9f0V(%_Ia@<66)F$H#G`^ZssNza^j0O#QI8US|)TP(==x+*3nJGZT+_ zR|Z*6^InM?|9s6~1_vG)_c?ffP_Y#xGgmc(`|tDXhDXGO9Dp%@hZ*3AHp9w=u4U)a z#cKtGIbZE0wx`609b1+)WrhtoV;q<5oe>eo^gwDCA>RfPtULP4bF*1doRaSX%y72f;p z0dVJ0!))lN_-5k|tP%L}D4a%r_`Nv&H#HroI#y|znZS?JN&G#p)U`+}Fkg+jb<=`Q z(60Pr=lG?je3oav8@yr>adAcC;O{FX2L*&;xAKB3COefaI z6DIg{K z1ZnPXZIYF1V)z^GP3CWjoiL5NP*mRF3hghpBQdm|R$a#xdWo^{%Hh(ax9DL++uxNZ z``*pLFIZ3-OFp9`5%E$MMMcRl>({Z4L|3u5KIaJU z9757$gJ#M1AfS=CRqf!ICBZ@T3ZXGiH$a>ji%$?N2{m{YT*}9;e5};k;r}XR325Sz z3Rai$6Ad}hYFOQx<@lT=j95`0mgWP-jDnAO2F4SHS{%XOad^*v_f%WTj7b-v3L#51 zlROMB1;qnv2mj+gBOID*3xzKib=+jT5LeXYt38MKBB$;wR1{i~4FN+V-zBU70LbTP zqoI8mMSovic-1c`#zFwgm~g4;m_u;a>MuoS!LB7e_*?BZL1t6AQ`=>fsBNz^T}4v& zTZXhYrrxs@Ho2aET9#wZ9GSNllFUu<0>SsYV_!*A)mdk0=1y(OOn+4?J1^1LX^vMm zl%c78Kq9q+?o!Le8Rpy9Le4sF5kg1o>|GlCJ_-XYWGk;-cHzWqW2mmgF86a_19(Uq zvoeux@ zknKC_t;cfIY-coqX)8Zn<)T8q5m4Gu@?#?|X@nS9in8?kT_)(v9xfw79lW-Ihpz@z zAODeq=3|L}rEA%+Qn^HB6Fm->BD2-fT8RI1VMG~He$SHR_dCC(QO8Et70v1gYkEV$ zdV9}9C$Nc(9=hLkX{56SeS`90Eu%(7|HtGATJ(p2OiR0(lXM&swzpGQft*Sib{b5M z8Hi)KHL0F)JKD>9?-ce>OlxWL4;go9wFsjJQ>QF{#UTNTLHYUGk=B}5=jA`$w+`d& zKfZh*J7{=Mt_JDmzqUiP0kt=pIRu8iB`7QiBB@+ptmOZuyq}{!X&;)n-gwxIt`q&2 z0f?BEB7O+pBMku7Nt9V{^D$<}r5+ zH8)24kZ10UuLqOcW+#oxoI*gOQ2CSP5rt`gp}vu+wSRp$5-!#?_N)-q)8HpAD5h?g z2O(qEeg=W3=YeAI8Fbq-bxU2m&BKOd3kwX z=dtVl?S0$C+7)ZK=P?61scW9>kdPPpkaX~9yb@t`@?op017sD~@?j>LU9-tdRw>$l zdEisNScKtW8TEEI;5o;3uy#zwUksgR7kU%B*DhNRRcxN&-Wy}c<98OBmc_ZUAiP{T zlccj`TeaZ!x=*W*J6bm((sztHFvJQ8bL}vgR=k5e_)t<>v>pZXOQ_E;1s!4LD(EX- zmJ@LRZx?4ZW70k)e8|wyWv-}g|7X2_j0A;nObr5Jyv9ZuFW44pQmR63+%%MX5kO+Y zhtX(tT3Z}Z3j=@ncb{@HOTm1}?XccL%PK8*mOpN2_JwB~+{gD{$yDME!y<;py;0Ny z^;W^mDK#fKy@tz8vzi&E&dtmj6SW$F`}%0@DQqJoBDZL1zrC#~q?C;O#g)2$*J9Xb z+VV-H6yLh}eNk-ZQLKPO$+E$%`;s>^BL|5xK|}>*rR&m~mWAgql&I6NZG6^cx?w4j zr*|?JJMV*=99g7r2e5t$>WSZh!s9~8GJOD2FIS_%()_T7+3iW}nfEOTa}UWuM(jHS z-Wzyw=RF!w5M3IK2mzwnS9#ojN3a2*;4Xk(4_eDmVW^V0OcP$-S67@aN5MK~43z)S zhz}lzp!bGPhz?3Q{?dsl_Hsu8ouZr-B^wVRoQQ5k7bnDs+mEFHXinh-VYKcSb>Ke( z_3PA1KA@un8{y}~A;JG-m@;O2V|^nG#`5OC&fB(SC~Ciu*B=KMG|WAJbkztVr}k3P z;2}m^lXJiP7P_GOI%NxbY92Uq?mj!qVht%BIbbp?T=N8Tn^~bce=Hy3_1-0%J5)k{ ze`7xXXC~5EmmUfXG3oj~Xqgzn0k4dH-g@7GgM7W9fWly07}#Gn@W|j9{y)b=`GsL~ z23`b?n#=Ug_8sbw;Wui3upGCD)>q%w(%?1gz{@}oBc9AjZ;*^r81IXb;2c4FbU=)J z9VuUFOUspLV2&6G30gxj1!k;Q&Y9q@Zn=dzr{r{~)4UzQqD2ou!j%uq_Za9DWz3x2 z6C)SZsm}zJ8_Soa-dU34zHK(590RfOC2m0uMN)WGMDvq-w!GPf zZl@7ytF5iTa3YK#g|Tp{iE4{M$pEdFXm)lC0~u#b%t7h5Ft@vkqjN2kh{vK3w}@H0 z-tVsh7+t*3T)?oknR0Sc7KiX1Vxe2$=`bG2&S(85guj^&&hyZN^3qCGh5S8AN$q`= z_zvb`r}@9zi$nN-2qNoX>B`Qj_JXOi3R!FJecQ=bq4Rtmed4Q}FK z#qmI+B(q|*M{)WTvP0_as!4xy)pKsbfP`CUYhT$|d*}OqLEdyys!~E>!^;wRBm%hW z=3jNJSOpoz=^UWW|I#=h=XvQEh}eYT8zdi??vCtE$&4!*0;CgN>l*TEac{LZ_-2en#JtxH zfn?8LQf&x-4gXaNbl81{)u(pVo-bjhcA^`!MBtH>d2zw>EDZSOnM0`wfaI|Mo#w~Z zkVH_k+kfVrzFIVmM*7)t@E_h`#tXdHz|s%hJb=q>~NXkA`4E`fUKj%oVHlk@)V|` z8C*FlC)lD%ddi^NVNss+v4N=%gP4#x{-io2M>OqS`?yBLghGUkE=sg_Nk0Bov1`7@ zyN2CS{A|hvy<5CS$>DvmO#xxcqUH?R57c9Sv%5V>g49!=s*Y;8Yv{Of~5 znA!CctII9TNP>A8@pD6s_v_b~aL_aN?cANZ@I$aP$8@*Yp@h_Ci0mS?&W>!1w$LVj zSH&b**uQ>NfVBKW^F5^YUr(^VQoi0XHC{m0DoJpo{L?3xl*qv0qvB zjIq~J#f=}&ydtJcj5hZ3_HD!dT|RYeor9r7KZ`e-SiE4(kKM?!1xq2_qD5*IseJ!w zU*nyfj3IfXdpQeb*7Nz-rFJN9bk=EqR!4CVA8XwGd#dIk|0__bnwE$@U}VMf!uFU7 zf-vW1I$nN6BCUj}Ebxt#zc2(AFkct;0Lk0UIQcJ;u9?&wBjxwEeg_pwi^kdl8Pk}x zMjyD93CPgPdCXv7>?oD=dAc9R{^OoOY?6IJ+YAN~R<=XGs=o~gN6 zVnvsSwu@y!7@MNx$1fV?C@cw$uWa<7_Fe>ZohXxoXfg+Ji!9D7t;54>g$-V{uYz2N zuF>PT9~9&uBbpYjxR3w6ZQ=iis#=6gQym?hWRKys%|nBbhtxTd7|I9+Z$nXC2Wi@x zmX^Z=?2~VyQN@A?$BACFt9_Aww&niIDar{K@0Wo(jftGmWj}ufX{TIGv+G>B&GD~6 zW}m-_F+~h#46`!b@=4)XK`k9FWy)do+6+RZbTn-0KiGJ@+zO z5Pj8Z_$Ic-si)@YTz String { "{\"status\":\"ok\",\"engine\":\"engram-runtime-native\"}" } +// route_sync — return a snapshot of non-ISE/non-Working nodes for the soul daemon +// to merge into its in-process graph via engram_load_merge. +// +// The soul calls GET /api/sync every SOUL_REFRESH_MS (default 10 min) to pull +// new Knowledge/Memory/BacklogItem nodes from the authoritative HTTP Engram into +// its in-process working store. Previously this returned 404 "not found", causing +// the soul to write the error JSON to a temp file and attempt an empty merge. +// +// Strategy: save the current snapshot to disk, read it back, return the full +// snapshot JSON. The soul's engram_load_merge handles large files gracefully +// (it skips nodes already present by ID). Auth-exempt: same-host internal call. +// (2026-06-27 self-review: added this route to fix silent 10-min sync failures) +fn route_sync(method: String, path: String, body: String) -> String { + let dir: String = env("ENGRAM_DATA_DIR") + if str_eq(dir, "") { let dir = "/tmp/engram" } + let snap_path: String = dir + "/snapshot.json" + engram_save(snap_path) + let snap: String = fs_read(snap_path) + if str_eq(snap, "") { return "{\"nodes\":[],\"edges\":[]}" } + return snap +} + // route_emit_ise — write an InternalStateEvent node from the soul daemon. // // Endpoint: POST /api/neuron/state-events @@ -330,6 +352,11 @@ fn handle_request(method: String, path: String, body: String) -> String { return route_load(method, path, body) } + // Sync — soul daemon periodic pull of non-ISE knowledge into in-process graph + if str_eq(method, "GET") && str_eq(clean, "/api/sync") { + return route_sync(method, path, body) + } + "{\"error\":\"not found\",\"path\":\"" + clean + "\"}" } From 3da9181debb89bdefcc941dbd8fbf6eaa3723cf7 Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Mon, 29 Jun 2026 12:38:36 -0500 Subject: [PATCH 10/13] fix(releases/v1.0.0): println stdout flush for launchd; Knowledge node activation threshold --- lang/releases/v1.0.0-20260501/el_runtime.c | 114 +++++++++++++-------- 1 file changed, 69 insertions(+), 45 deletions(-) diff --git a/lang/releases/v1.0.0-20260501/el_runtime.c b/lang/releases/v1.0.0-20260501/el_runtime.c index 831e016..a4a2742 100644 --- a/lang/releases/v1.0.0-20260501/el_runtime.c +++ b/lang/releases/v1.0.0-20260501/el_runtime.c @@ -140,6 +140,12 @@ void println(el_val_t s) { const char* str = EL_CSTR(s); if (str) puts(str); else puts(""); + /* Flush stdout immediately so logs are visible even when stdout is redirected + * to a file (launchd plists redirect stdout; stdio defaults to full-buffering + * for non-tty streams, which silently holds log messages indefinitely). + * (2026-06-29 self-review: soul.out.log showed May 26 mtime despite daemon + * running since June 29 07:14AM — startup println output stuck in stdio buffer) */ + fflush(stdout); } void print(el_val_t s) { @@ -5562,6 +5568,13 @@ static double engram_type_threshold(const char* node_type, const char* tier) { if (strcmp(tier, "Lesson") == 0) return 0.25; } if (node_type) { + /* Knowledge nodes with Procedural/Semantic tier (post-activation-count migration) + * should keep a lower threshold than the generic 0.40 default. + * Canonical/Lesson Knowledge: handled by tier checks above (0.15/0.25). + * Procedural Knowledge (activation_count >= 50): 0.20 — proven repeated use + * justifies lower threshold, consistent with ACT-R base-level learning rationale. + * (2026-06-29 self-review: documented in knowledge graph since 2026-06-04) */ + if (strcmp(node_type, "Knowledge") == 0) return 0.20; if (strcmp(node_type, "Belief") == 0) return 0.30; if (strcmp(node_type, "Entity") == 0) return 0.30; } @@ -5830,11 +5843,15 @@ static void engram_grow_edges(void) { g->edge_capacity = nc; } -/* Build a fresh UUID string. Reuses uuid_new but takes the underlying char*. */ +/* Build a fresh UUID string. Reuses uuid_new but takes the underlying char*. + * Must use el_strdup_persist because the returned pointer is stored in EngramNode/EngramEdge + * fields that outlive the current HTTP request's per-request string arena. If el_strdup + * were used the arena teardown at el_request_end() would free the id/content/etc. strings, + * leaving dangling pointers in the EngramStore. (2026-06-27 fix: arena corruption bug) */ static char* engram_new_id(void) { el_val_t v = uuid_new(); const char* s = EL_CSTR(v); - return el_strdup(s ? s : ""); + return el_strdup_persist(s ? s : ""); } /* Convert a node into an ElMap of its fields. */ @@ -5877,11 +5894,14 @@ static double engram_decode_score(el_val_t v) { return (double)n; } +/* engram_first_n_chars — extract label substring from content. + * Must use persistent allocation since the result is stored in EngramNode.label. + * (2026-06-27 fix: arena corruption bug — was using el_strbuf/el_strdup) */ static char* engram_first_n_chars(const char* s, size_t n) { - if (!s) return el_strdup(""); + if (!s) return el_strdup_persist(""); size_t l = strlen(s); if (l > n) l = n; - char* out = el_strbuf(l); + char* out = el_strbuf_persist(l); memcpy(out, s, l); out[l] = '\0'; return out; @@ -5895,12 +5915,13 @@ el_val_t engram_node(el_val_t content, el_val_t node_type, el_val_t salience) { n->id = engram_new_id(); const char* c = EL_CSTR(content); const char* nt = EL_CSTR(node_type); - n->content = el_strdup(c ? c : ""); - n->node_type = el_strdup(nt && *nt ? nt : "Memory"); + /* Use el_strdup_persist: these strings outlive the HTTP request arena. */ + n->content = el_strdup_persist(c ? c : ""); + n->node_type = el_strdup_persist(nt && *nt ? nt : "Memory"); n->label = engram_first_n_chars(c, 60); - n->tier = el_strdup("Working"); - n->tags = el_strdup(""); - n->metadata = el_strdup("{}"); + n->tier = el_strdup_persist("Working"); + n->tags = el_strdup_persist(""); + n->metadata = el_strdup_persist("{}"); n->salience = engram_decode_score(salience); if (n->salience <= 0.0 || n->salience > 1.0) n->salience = 0.5; n->importance = 0.5; @@ -5913,7 +5934,7 @@ el_val_t engram_node(el_val_t content, el_val_t node_type, el_val_t salience) { n->updated_at = now; n->layer_id = ENGRAM_LAYER_DEFAULT; g->node_count++; - return el_wrap_str(el_strdup(n->id)); + return el_wrap_str(el_strdup_persist(n->id)); } el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, @@ -5929,12 +5950,13 @@ el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, const char* lb = EL_CSTR(label); const char* ti = EL_CSTR(tier); const char* tg = EL_CSTR(tags); - n->content = el_strdup(c ? c : ""); - n->node_type = el_strdup(nt && *nt ? nt : "Memory"); - n->label = el_strdup(lb && *lb ? lb : (c ? engram_first_n_chars(c, 60) : "")); - n->tier = el_strdup(ti && *ti ? ti : "Working"); - n->tags = el_strdup(tg ? tg : ""); - n->metadata = el_strdup("{}"); + /* Use el_strdup_persist: these strings outlive the HTTP request arena. */ + n->content = el_strdup_persist(c ? c : ""); + n->node_type = el_strdup_persist(nt && *nt ? nt : "Memory"); + n->label = el_strdup_persist(lb && *lb ? lb : (c ? engram_first_n_chars(c, 60) : "")); + n->tier = el_strdup_persist(ti && *ti ? ti : "Working"); + n->tags = el_strdup_persist(tg ? tg : ""); + n->metadata = el_strdup_persist("{}"); n->salience = engram_decode_score(salience); n->importance = engram_decode_score(importance); n->confidence = engram_decode_score(confidence); @@ -5949,7 +5971,7 @@ el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, n->updated_at = now; n->layer_id = ENGRAM_LAYER_DEFAULT; g->node_count++; - return el_wrap_str(el_strdup(n->id)); + return el_wrap_str(el_strdup_persist(n->id)); } /* engram_node_layered — like engram_node_full but with explicit layer @@ -5982,20 +6004,21 @@ el_val_t engram_node_layered(el_val_t content, el_val_t node_type, el_val_t labe const char* lb = EL_CSTR(label); const char* tg = EL_CSTR(tags); const char* st = EL_CSTR(status); - n->content = el_strdup(c ? c : ""); - n->node_type = el_strdup(nt && *nt ? nt : "Memory"); - n->label = el_strdup(lb && *lb ? lb : (c ? engram_first_n_chars(c, 60) : "")); - n->tier = el_strdup("Working"); - n->tags = el_strdup(tg ? tg : ""); + /* Use el_strdup_persist: these strings outlive the HTTP request arena. */ + n->content = el_strdup_persist(c ? c : ""); + n->node_type = el_strdup_persist(nt && *nt ? nt : "Memory"); + n->label = el_strdup_persist(lb && *lb ? lb : (c ? engram_first_n_chars(c, 60) : "")); + n->tier = el_strdup_persist("Working"); + n->tags = el_strdup_persist(tg ? tg : ""); if (st && *st) { /* Minimal metadata payload: {"status":"..."}. Keep it cheap so * callers using `status` don't pay JSON parse cost on every read. */ size_t sl = strlen(st) + 16; - char* meta = el_strbuf(sl); + char* meta = el_strbuf_persist(sl); snprintf(meta, sl, "{\"status\":\"%s\"}", st); n->metadata = meta; } else { - n->metadata = el_strdup("{}"); + n->metadata = el_strdup_persist("{}"); } n->salience = engram_decode_score(salience); n->importance = engram_decode_score(certainty); @@ -6016,7 +6039,7 @@ el_val_t engram_node_layered(el_val_t content, el_val_t node_type, el_val_t labe if (!engram_find_layer((uint32_t)lid)) lid = (int64_t)ENGRAM_LAYER_DEFAULT; n->layer_id = (uint32_t)lid; g->node_count++; - return el_wrap_str(el_strdup(n->id)); + return el_wrap_str(el_strdup_persist(n->id)); } /* ── Layer registry public API ────────────────────────────────────────────── @@ -6268,10 +6291,11 @@ void engram_connect(el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t EngramEdge* e = &g->edges[g->edge_count]; memset(e, 0, sizeof(*e)); e->id = engram_new_id(); - e->from_id = el_strdup(f); - e->to_id = el_strdup(t); - e->relation = el_strdup(r && *r ? r : "associate"); - e->metadata = el_strdup("{}"); + /* Use el_strdup_persist: edge strings outlive the HTTP request arena. */ + e->from_id = el_strdup_persist(f); + e->to_id = el_strdup_persist(t); + e->relation = el_strdup_persist(r && *r ? r : "associate"); + e->metadata = el_strdup_persist("{}"); e->weight = engram_decode_score(weight); if (e->weight <= 0.0 || e->weight > 1.0) e->weight = 0.5; e->confidence = 1.0; @@ -7080,7 +7104,7 @@ el_val_t engram_load(el_val_t path) { nn->tier = eg_get_str_field(obj, "tier"); nn->tags = eg_get_str_field(obj, "tags"); nn->metadata = eg_get_str_field(obj, "metadata"); - if (!nn->metadata || !*nn->metadata) { free(nn->metadata); nn->metadata = el_strdup("{}"); } + if (!nn->metadata || !*nn->metadata) { free(nn->metadata); nn->metadata = el_strdup_persist("{}"); } nn->salience = eg_get_num_field(obj, "salience"); nn->importance = eg_get_num_field(obj, "importance"); nn->confidence = eg_get_num_field(obj, "confidence"); @@ -7131,7 +7155,7 @@ el_val_t engram_load(el_val_t path) { ee->to_id = eg_get_str_field(obj, "to_id"); ee->relation = eg_get_str_field(obj, "relation"); ee->metadata = eg_get_str_field(obj, "metadata"); - if (!ee->metadata || !*ee->metadata) { free(ee->metadata); ee->metadata = el_strdup("{}"); } + if (!ee->metadata || !*ee->metadata) { free(ee->metadata); ee->metadata = el_strdup_persist("{}"); } ee->weight = eg_get_num_field(obj, "weight"); ee->confidence = eg_get_num_field(obj, "confidence"); ee->created_at = eg_get_int_field(obj, "created_at"); @@ -8007,13 +8031,13 @@ static int64_t dharma_find_or_create_relation_edge(const char* peer_base, int cr engram_grow_nodes(); EngramNode* n = &g->nodes[g->node_count]; memset(n, 0, sizeof(*n)); - n->id = el_strdup(self_id); - n->content = el_strdup(_el_cgi_dharma_id ? _el_cgi_dharma_id : "(self)"); - n->node_type = el_strdup("DharmaSelf"); - n->label = el_strdup("dharma:self"); - n->tier = el_strdup("Working"); - n->tags = el_strdup("dharma"); - n->metadata = el_strdup("{}"); + n->id = el_strdup_persist(self_id); + n->content = el_strdup_persist(_el_cgi_dharma_id ? _el_cgi_dharma_id : "(self)"); + n->node_type = el_strdup_persist("DharmaSelf"); + n->label = el_strdup_persist("dharma:self"); + n->tier = el_strdup_persist("Working"); + n->tags = el_strdup_persist("dharma"); + n->metadata = el_strdup_persist("{}"); n->salience = 1.0; n->importance = 1.0; n->confidence = 1.0; int64_t now = engram_now_ms(); n->created_at = now; n->updated_at = now; n->last_activated = now; @@ -8024,13 +8048,13 @@ static int64_t dharma_find_or_create_relation_edge(const char* peer_base, int cr engram_grow_nodes(); EngramNode* n = &g->nodes[g->node_count]; memset(n, 0, sizeof(*n)); - n->id = el_strdup(peer_node); - n->content = el_strdup(peer_base); - n->node_type = el_strdup("DharmaPeer"); - n->label = el_strdup(peer_node); - n->tier = el_strdup("Working"); - n->tags = el_strdup("dharma"); - n->metadata = el_strdup("{}"); + n->id = el_strdup_persist(peer_node); + n->content = el_strdup_persist(peer_base); + n->node_type = el_strdup_persist("DharmaPeer"); + n->label = el_strdup_persist(peer_node); + n->tier = el_strdup_persist("Working"); + n->tags = el_strdup_persist("dharma"); + n->metadata = el_strdup_persist("{}"); n->salience = 0.5; n->importance = 0.5; n->confidence = 1.0; int64_t now = engram_now_ms(); n->created_at = now; n->updated_at = now; n->last_activated = now; From 6271cb42b25aae2f5ee14e4040eecd599b206253 Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Mon, 29 Jun 2026 12:40:14 -0500 Subject: [PATCH 11/13] feat(runtime): native platform backends (AppKit, UIKit, Android, GTK4, SDL2, LVGL, Win32) Add seven platform bridge implementations and the shared native target header: el_native_target.h, el_appkit.m, el_uikit.m, el_android.c, el_gtk4.c, el_sdl2.c, el_lvgl.c, el_win32.c, el_runtime_win32.c. Each bridge implements the 33 __widget_* C builtins declared in el_native_target.h for its platform toolkit. el_runtime_win32.c provides a POSIX-free runtime stub for cross-compiled Win32 targets. --- lang/el-compiler/runtime/el_android.c | 949 +++++++++++++ lang/el-compiler/runtime/el_appkit.m | 1018 ++++++++++++++ lang/el-compiler/runtime/el_gtk4.c | 1327 ++++++++++++++++++ lang/el-compiler/runtime/el_lvgl.c | 844 ++++++++++++ lang/el-compiler/runtime/el_native_target.h | 574 ++++++++ lang/el-compiler/runtime/el_runtime_win32.c | 1146 ++++++++++++++++ lang/el-compiler/runtime/el_sdl2.c | 1360 ++++++++++++++++++ lang/el-compiler/runtime/el_uikit.m | 1118 +++++++++++++++ lang/el-compiler/runtime/el_win32.c | 1363 +++++++++++++++++++ 9 files changed, 9699 insertions(+) create mode 100644 lang/el-compiler/runtime/el_android.c create mode 100644 lang/el-compiler/runtime/el_appkit.m create mode 100644 lang/el-compiler/runtime/el_gtk4.c create mode 100644 lang/el-compiler/runtime/el_lvgl.c create mode 100644 lang/el-compiler/runtime/el_native_target.h create mode 100644 lang/el-compiler/runtime/el_runtime_win32.c create mode 100644 lang/el-compiler/runtime/el_sdl2.c create mode 100644 lang/el-compiler/runtime/el_uikit.m create mode 100644 lang/el-compiler/runtime/el_win32.c diff --git a/lang/el-compiler/runtime/el_android.c b/lang/el-compiler/runtime/el_android.c new file mode 100644 index 0000000..7e3e765 --- /dev/null +++ b/lang/el-compiler/runtime/el_android.c @@ -0,0 +1,949 @@ +/* + * el_android.c — Android JNI backend for the el native widget system. + * + * This file implements the Android widget layer that el_seed.c calls through + * to when EL_TARGET_ANDROID is defined. It is the exact Android counterpart + * to el_appkit.m and presents the same C API surface. + * + * Architecture: + * el program (el code) + * → __widget_* C builtins in el_seed.c + * → el_android_* C-callable functions declared here + * → ElBridge static methods in Java via JNI + * → android.view.View subclasses on the UI thread + * + * Widget handles: every widget (window root, view, control) is assigned an + * int64_t slot index into view_slots[]. The el program holds these as opaque + * Int values. Slot 0 is never valid (null handle = -1 convention). + * + * Threading: Android requires all UI operations to run on the main (UI) thread. + * Every JNI call that mutates a View is dispatched through + * Activity.runOnUiThread(Runnable) if the current thread is not the UI thread. + * el_android_run_loop is a no-op — Android lifecycle is driven by the Activity. + * + * Callback mechanism: when a widget fires an event Java calls + * nativeOnClick / nativeOnChange / nativeOnSubmit + * The C side looks up the registered El function name for that slot, then: + * dlsym(RTLD_DEFAULT, fn_name)(widget_handle, event_data_string) + * This matches the __thread_create pattern in el_seed.c exactly. + * + * Compile / link (as part of libelruntime.so): + * Compiled by the Android Gradle NDK build system with -DEL_TARGET_ANDROID. + * Link flags: -landroid -llog -ldl + * + * Java companion: ElBridge.java in the same directory must be compiled into + * the Android application's APK (package com.neuron.el). + */ + +#ifdef EL_TARGET_ANDROID + +#include +#include +#include +#include +#include +#include +#include "el_runtime.h" + +/* ── Logging ─────────────────────────────────────────────────────────────── */ + +#define EL_TAG "ElAndroid" +#define EL_LOGI(...) __android_log_print(ANDROID_LOG_INFO, EL_TAG, __VA_ARGS__) +#define EL_LOGW(...) __android_log_print(ANDROID_LOG_WARN, EL_TAG, __VA_ARGS__) +#define EL_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, EL_TAG, __VA_ARGS__) + +/* ── JNI global state ────────────────────────────────────────────────────── */ + +static JavaVM *g_jvm = NULL; +static jobject g_activity = NULL; /* global ref to Activity */ +static jclass g_bridge_class = NULL; /* global ref to ElBridge class */ + +/* Cached method IDs on ElBridge — filled in el_android_init(). */ +static jmethodID g_mid_createLinearLayout = NULL; +static jmethodID g_mid_createFrameLayout = NULL; +static jmethodID g_mid_createScrollView = NULL; +static jmethodID g_mid_createTextView = NULL; +static jmethodID g_mid_createButton = NULL; +static jmethodID g_mid_createEditText = NULL; +static jmethodID g_mid_createImageView = NULL; +static jmethodID g_mid_setContentView = NULL; +static jmethodID g_mid_setTitle = NULL; +static jmethodID g_mid_addChild = NULL; +static jmethodID g_mid_removeChild = NULL; +static jmethodID g_mid_destroyView = NULL; +static jmethodID g_mid_setText = NULL; +static jmethodID g_mid_getText = NULL; +static jmethodID g_mid_setTextColor = NULL; +static jmethodID g_mid_setBackgroundColor = NULL; +static jmethodID g_mid_setFont = NULL; +static jmethodID g_mid_setPadding = NULL; +static jmethodID g_mid_setWidth = NULL; +static jmethodID g_mid_setHeight = NULL; +static jmethodID g_mid_setFlex = NULL; +static jmethodID g_mid_setCornerRadius = NULL; +static jmethodID g_mid_setEnabled = NULL; +static jmethodID g_mid_setVisibility = NULL; +static jmethodID g_mid_setOnClickListener = NULL; +static jmethodID g_mid_setOnChangeListener = NULL; +static jmethodID g_mid_setOnSubmitListener = NULL; +static jmethodID g_mid_runOnUiThread = NULL; /* Activity.runOnUiThread */ + +/* ── Widget table ─────────────────────────────────────────────────────────── */ + +#define EL_ANDROID_MAX_WIDGETS 4096 + +typedef enum { + EL_WIDGET_FREE = 0, + EL_WIDGET_WINDOW = 1, + EL_WIDGET_VSTACK = 2, + EL_WIDGET_HSTACK = 3, + EL_WIDGET_ZSTACK = 4, + EL_WIDGET_SCROLL = 5, + EL_WIDGET_LABEL = 6, + EL_WIDGET_BUTTON = 7, + EL_WIDGET_TEXTFIELD = 8, + EL_WIDGET_TEXTAREA = 9, + EL_WIDGET_IMAGE = 10, +} ElWidgetKind; + +typedef struct { + ElWidgetKind kind; + jint slot; /* Java-side slot index (matches C index) */ + char *cb_click; /* El function name for click / submit events */ + char *cb_change; /* El function name for value-change events */ +} ElWidget; + +static ElWidget _el_widgets[EL_ANDROID_MAX_WIDGETS]; + +static int64_t el_widget_alloc(ElWidgetKind kind, jint slot) { + for (int i = 1; i < EL_ANDROID_MAX_WIDGETS; i++) { + if (_el_widgets[i].kind == EL_WIDGET_FREE) { + _el_widgets[i].kind = kind; + _el_widgets[i].slot = slot; + _el_widgets[i].cb_click = NULL; + _el_widgets[i].cb_change = NULL; + return (int64_t)i; + } + } + EL_LOGE("el_widget_alloc: slot table full"); + return -1; +} + +static ElWidget *el_widget_get(int64_t handle) { + if (handle <= 0 || handle >= EL_ANDROID_MAX_WIDGETS) return NULL; + if (_el_widgets[handle].kind == EL_WIDGET_FREE) return NULL; + return &_el_widgets[handle]; +} + +static void el_widget_free(int64_t handle) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + w->kind = EL_WIDGET_FREE; + w->slot = -1; + free(w->cb_click); w->cb_click = NULL; + free(w->cb_change); w->cb_change = NULL; +} + +/* ── JNI environment helpers ─────────────────────────────────────────────── */ + +/* + * Obtain a JNIEnv for the calling thread. Attaches the thread to the JVM if + * needed (detaches in el_jni_detach_if_attached — call in pairs). + */ +static int g_was_attached = 0; /* thread-local would be cleaner but this is + safe for single-threaded el programs */ + +static JNIEnv *el_jni_env(void) { + if (!g_jvm) return NULL; + JNIEnv *env = NULL; + jint rc = (*g_jvm)->GetEnv(g_jvm, (void **)&env, JNI_VERSION_1_6); + if (rc == JNI_OK) { g_was_attached = 0; return env; } + if (rc == JNI_EDETACHED) { + if ((*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL) == JNI_OK) { + g_was_attached = 1; + return env; + } + } + EL_LOGE("el_jni_env: failed to obtain JNIEnv"); + return NULL; +} + +static void el_jni_detach_if_attached(void) { + if (g_was_attached && g_jvm) { + (*g_jvm)->DetachCurrentThread(g_jvm); + g_was_attached = 0; + } +} + +/* ── UI-thread dispatch ──────────────────────────────────────────────────── */ +/* + * Most ElBridge static methods already dispatch to the UI thread internally + * (they call Activity.runOnUiThread). The helper below is available for + * cases where the caller needs to be sure the call has completed before + * returning (ElBridge methods marked "sync" use a CountDownLatch internally). + * + * For the current implementation we call ElBridge methods directly; ElBridge + * itself marshals to the UI thread via Activity.runOnUiThread + latch. + * This keeps the C side simple and mirrors the AppKit dispatch_sync pattern. + */ + +/* ── JNI_OnLoad ──────────────────────────────────────────────────────────── */ + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { + (void)reserved; + g_jvm = vm; + EL_LOGI("JNI_OnLoad: el Android bridge loaded"); + return JNI_VERSION_1_6; +} + +/* ── el_android_init ─────────────────────────────────────────────────────── */ +/* + * Called from __native_init(). The Activity must have already called + * ElBridge.registerActivity(activity) from Java before this runs, which sets + * g_activity via the nativeRegisterActivity JNI method below. + * + * Caches all method IDs used later so individual widget calls avoid repeated + * FindClass / GetStaticMethodID lookups. + */ +void el_android_init(void) { + static int done = 0; + if (done) return; + done = 1; + + JNIEnv *env = el_jni_env(); + if (!env) { EL_LOGE("el_android_init: no JNIEnv"); return; } + + jclass cls = (*env)->FindClass(env, "com/neuron/el/ElBridge"); + if (!cls) { EL_LOGE("el_android_init: ElBridge class not found"); return; } + g_bridge_class = (*env)->NewGlobalRef(env, cls); + (*env)->DeleteLocalRef(env, cls); + +#define CACHE_STATIC(var, name, sig) \ + var = (*env)->GetStaticMethodID(env, g_bridge_class, name, sig); \ + if (!var) EL_LOGW("el_android_init: method not found: %s %s", name, sig) + + CACHE_STATIC(g_mid_createLinearLayout, "createLinearLayout", "(II)I"); + CACHE_STATIC(g_mid_createFrameLayout, "createFrameLayout", "()I"); + CACHE_STATIC(g_mid_createScrollView, "createScrollView", "()I"); + CACHE_STATIC(g_mid_createTextView, "createTextView", "(Ljava/lang/String;)I"); + CACHE_STATIC(g_mid_createButton, "createButton", "(Ljava/lang/String;)I"); + CACHE_STATIC(g_mid_createEditText, "createEditText", "(Ljava/lang/String;Z)I"); + CACHE_STATIC(g_mid_createImageView, "createImageView", "(Ljava/lang/String;)I"); + CACHE_STATIC(g_mid_setContentView, "setContentView", "(I)V"); + CACHE_STATIC(g_mid_setTitle, "setTitle", "(Ljava/lang/String;)V"); + CACHE_STATIC(g_mid_addChild, "addChild", "(II)V"); + CACHE_STATIC(g_mid_removeChild, "removeChild", "(II)V"); + CACHE_STATIC(g_mid_destroyView, "destroyView", "(I)V"); + CACHE_STATIC(g_mid_setText, "setText", "(ILjava/lang/String;)V"); + CACHE_STATIC(g_mid_getText, "getText", "(I)Ljava/lang/String;"); + CACHE_STATIC(g_mid_setTextColor, "setTextColor", "(IFFFF)V"); + CACHE_STATIC(g_mid_setBackgroundColor, "setBackgroundColor", "(IFFFF)V"); + CACHE_STATIC(g_mid_setFont, "setFont", "(ILjava/lang/String;IZ)V"); + CACHE_STATIC(g_mid_setPadding, "setPadding", "(IIIII)V"); + CACHE_STATIC(g_mid_setWidth, "setWidth", "(II)V"); + CACHE_STATIC(g_mid_setHeight, "setHeight", "(II)V"); + CACHE_STATIC(g_mid_setFlex, "setFlex", "(II)V"); + CACHE_STATIC(g_mid_setCornerRadius, "setCornerRadius", "(IF)V"); + CACHE_STATIC(g_mid_setEnabled, "setEnabled", "(IZ)V"); + CACHE_STATIC(g_mid_setVisibility, "setVisibility", "(IZ)V"); + CACHE_STATIC(g_mid_setOnClickListener, "setOnClickListener", "(I)V"); + CACHE_STATIC(g_mid_setOnChangeListener, "setOnChangeListener", "(I)V"); + CACHE_STATIC(g_mid_setOnSubmitListener, "setOnSubmitListener", "(I)V"); +#undef CACHE_STATIC + + el_jni_detach_if_attached(); + EL_LOGI("el_android_init: complete"); +} + +/* ── JNI: Activity registration ─────────────────────────────────────────── */ + +/* + * Called from Java: ElBridge.registerActivity(activity) calls back here. + * Stores a global reference to the Activity so C code can dispatch to it. + */ +JNIEXPORT void JNICALL +Java_com_neuron_el_ElBridge_nativeRegisterActivity(JNIEnv *env, jclass cls, + jobject activity) { + (void)cls; + if (g_activity) { + (*env)->DeleteGlobalRef(env, g_activity); + g_activity = NULL; + } + if (activity) { + g_activity = (*env)->NewGlobalRef(env, activity); + EL_LOGI("nativeRegisterActivity: activity registered"); + } +} + +/* ── El callback invocation ──────────────────────────────────────────────── */ +/* + * Invoke an El callback by symbol name. + * Signature matches AppKit: fn(handle: Int, data: String) -> Void + * compiled to: void fn(el_val_t handle, el_val_t data) + */ +typedef void (*ElCb2)(int64_t handle, int64_t data); + +static void el_android_invoke_cb(const char *fn_name, int64_t handle, + const char *data) { + if (!fn_name || !*fn_name) return; + void *sym = dlsym(RTLD_DEFAULT, fn_name); + if (!sym) { EL_LOGW("invoke_cb: symbol not found: %s", fn_name); return; } + ElCb2 fn = (ElCb2)sym; + fn(handle, (int64_t)(uintptr_t)(data ? data : "")); +} + +/* ── JNI: callbacks from Java → C ───────────────────────────────────────── */ + +JNIEXPORT void JNICALL +Java_com_neuron_el_ElBridge_nativeOnClick(JNIEnv *env, jclass cls, jint slot) { + (void)env; (void)cls; + int64_t handle = (int64_t)slot; + ElWidget *w = el_widget_get(handle); + if (w && w->cb_click) { + el_android_invoke_cb(w->cb_click, handle, ""); + } +} + +JNIEXPORT void JNICALL +Java_com_neuron_el_ElBridge_nativeOnChange(JNIEnv *env, jclass cls, + jint slot, jstring text) { + (void)cls; + int64_t handle = (int64_t)slot; + ElWidget *w = el_widget_get(handle); + if (w && w->cb_change) { + const char *ctext = text ? (*env)->GetStringUTFChars(env, text, NULL) : ""; + el_android_invoke_cb(w->cb_change, handle, ctext); + if (text) (*env)->ReleaseStringUTFChars(env, text, ctext); + } +} + +JNIEXPORT void JNICALL +Java_com_neuron_el_ElBridge_nativeOnSubmit(JNIEnv *env, jclass cls, + jint slot, jstring text) { + (void)cls; + int64_t handle = (int64_t)slot; + ElWidget *w = el_widget_get(handle); + if (w && w->cb_click) { /* submit stored in cb_click, same as AppKit */ + const char *ctext = text ? (*env)->GetStringUTFChars(env, text, NULL) : ""; + el_android_invoke_cb(w->cb_click, handle, ctext); + if (text) (*env)->ReleaseStringUTFChars(env, text, ctext); + } +} + +/* ── Helper: jstring from C string ──────────────────────────────────────── */ + +static jstring el_jstr(JNIEnv *env, const char *s) { + return (*env)->NewStringUTF(env, s ? s : ""); +} + +/* ── Window ──────────────────────────────────────────────────────────────── */ + +/* + * el_android_window_create — on Android a "window" is the root LinearLayout + * set as the Activity's content view. We create a vertical LinearLayout and + * store it. el_android_window_show calls setContentView on the Activity. + */ +int64_t el_android_window_create(const char *title, int width, int height, + int min_width, int min_height) { + (void)width; (void)height; (void)min_width; (void)min_height; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + + /* VERTICAL LinearLayout with no spacing (spacing added via margins in Java) */ + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createLinearLayout, + (jint)1 /* VERTICAL */, (jint)0); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; + } + + /* Set activity title */ + if (g_mid_setTitle && title) { + jstring jtitle = el_jstr(env, title); + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setTitle, jtitle); + (*env)->DeleteLocalRef(env, jtitle); + } + + int64_t handle = el_widget_alloc(EL_WIDGET_WINDOW, (int)slot); + el_jni_detach_if_attached(); + return handle; +} + +void el_android_window_show(int64_t handle) { + ElWidget *w = el_widget_get(handle); + if (!w || w->kind != EL_WIDGET_WINDOW) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setContentView, + (jint)w->slot); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_window_set_title(int64_t handle, const char *title) { + (void)handle; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + jstring jtitle = el_jstr(env, title); + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setTitle, jtitle); + (*env)->DeleteLocalRef(env, jtitle); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +/* ── Layout containers ───────────────────────────────────────────────────── */ + +int64_t el_android_vstack_create(int spacing) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createLinearLayout, + (jint)1 /* VERTICAL */, (jint)spacing); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_VSTACK, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +int64_t el_android_hstack_create(int spacing) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createLinearLayout, + (jint)0 /* HORIZONTAL */, (jint)spacing); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_HSTACK, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +int64_t el_android_zstack_create(void) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createFrameLayout); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_ZSTACK, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +int64_t el_android_scroll_create(void) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createScrollView); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_SCROLL, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +/* ── Widget factories ─────────────────────────────────────────────────────── */ + +int64_t el_android_label_create(const char *text) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jstring jt = el_jstr(env, text); + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createTextView, jt); + (*env)->DeleteLocalRef(env, jt); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_LABEL, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +int64_t el_android_button_create(const char *label) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jstring jl = el_jstr(env, label); + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createButton, jl); + (*env)->DeleteLocalRef(env, jl); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_BUTTON, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +int64_t el_android_text_field_create(const char *placeholder) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jstring jp = el_jstr(env, placeholder); + /* singleLine = true */ + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createEditText, jp, (jboolean)JNI_TRUE); + (*env)->DeleteLocalRef(env, jp); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_TEXTFIELD, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +int64_t el_android_text_area_create(const char *placeholder) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jstring jp = el_jstr(env, placeholder); + /* singleLine = false → multiline EditText */ + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createEditText, jp, (jboolean)JNI_FALSE); + (*env)->DeleteLocalRef(env, jp); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_TEXTAREA, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +int64_t el_android_image_create(const char *path) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jstring jp = el_jstr(env, path); + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createImageView, jp); + (*env)->DeleteLocalRef(env, jp); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_IMAGE, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +/* ── Widget property setters ─────────────────────────────────────────────── */ + +void el_android_widget_set_text(int64_t handle, const char *text) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + jstring jt = el_jstr(env, text); + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setText, + (jint)w->slot, jt); + (*env)->DeleteLocalRef(env, jt); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +const char *el_android_widget_get_text(int64_t handle) { + ElWidget *w = el_widget_get(handle); + if (!w) return ""; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return ""; + jstring js = (jstring)(*env)->CallStaticObjectMethod(env, g_bridge_class, + g_mid_getText, + (jint)w->slot); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return ""; } + const char *result = ""; + if (js) { + const char *cstr = (*env)->GetStringUTFChars(env, js, NULL); + result = cstr ? strdup(cstr) : ""; + if (cstr) (*env)->ReleaseStringUTFChars(env, js, cstr); + (*env)->DeleteLocalRef(env, js); + } + el_jni_detach_if_attached(); + return result; +} + +void el_android_widget_set_color(int64_t handle, float r, float g, float b, float a) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setTextColor, + (jint)w->slot, (jfloat)r, (jfloat)g, + (jfloat)b, (jfloat)a); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_bg_color(int64_t handle, float r, float g, float b, float a) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setBackgroundColor, + (jint)w->slot, (jfloat)r, (jfloat)g, + (jfloat)b, (jfloat)a); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_font(int64_t handle, const char *family, int size, int bold) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + jstring jfam = el_jstr(env, family); + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setFont, + (jint)w->slot, jfam, (jint)size, + (jboolean)(bold ? JNI_TRUE : JNI_FALSE)); + (*env)->DeleteLocalRef(env, jfam); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_padding(int64_t handle, int top, int right, int bottom, int left) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setPadding, + (jint)w->slot, (jint)top, (jint)right, + (jint)bottom, (jint)left); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_width(int64_t handle, int width) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setWidth, + (jint)w->slot, (jint)width); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_height(int64_t handle, int height) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setHeight, + (jint)w->slot, (jint)height); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_flex(int64_t handle, int flex) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setFlex, + (jint)w->slot, (jint)flex); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_corner_radius(int64_t handle, int radius) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setCornerRadius, + (jint)w->slot, (jfloat)radius); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_disabled(int64_t handle, int disabled) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setEnabled, + (jint)w->slot, + (jboolean)(disabled ? JNI_FALSE : JNI_TRUE)); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_hidden(int64_t handle, int hidden) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + /* visible=true means NOT hidden */ + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setVisibility, + (jint)w->slot, + (jboolean)(hidden ? JNI_FALSE : JNI_TRUE)); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +/* ── Child management ─────────────────────────────────────────────────────── */ + +void el_android_widget_add_child(int64_t parent, int64_t child) { + ElWidget *pw = el_widget_get(parent); + ElWidget *cw = el_widget_get(child); + if (!pw || !cw) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_addChild, + (jint)pw->slot, (jint)cw->slot); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_remove_child(int64_t parent, int64_t child) { + ElWidget *pw = el_widget_get(parent); + ElWidget *cw = el_widget_get(child); + if (!pw || !cw) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_removeChild, + (jint)pw->slot, (jint)cw->slot); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +/* ── Event registration ───────────────────────────────────────────────────── */ + +void el_android_widget_on_click(int64_t handle, const char *fn_name) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + free(w->cb_click); + w->cb_click = (fn_name && *fn_name) ? strdup(fn_name) : NULL; + if (!w->cb_click) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setOnClickListener, + (jint)w->slot); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_on_change(int64_t handle, const char *fn_name) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + free(w->cb_change); + w->cb_change = (fn_name && *fn_name) ? strdup(fn_name) : NULL; + if (!w->cb_change) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setOnChangeListener, + (jint)w->slot); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_on_submit(int64_t handle, const char *fn_name) { + /* Submit stored in cb_click, same as AppKit. */ + ElWidget *w = el_widget_get(handle); + if (!w) return; + free(w->cb_click); + w->cb_click = (fn_name && *fn_name) ? strdup(fn_name) : NULL; + if (!w->cb_click) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setOnSubmitListener, + (jint)w->slot); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +/* ── Widget destroy ───────────────────────────────────────────────────────── */ + +void el_android_widget_destroy(int64_t handle) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (env && g_bridge_class) { + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_destroyView, + (jint)w->slot); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + } + el_widget_free(handle); + el_jni_detach_if_attached(); +} + +/* ── Manifest reader ─────────────────────────────────────────────────────── */ +/* + * __manifest_read: parse the app{} block from a manifest file. + * Returns the raw file contents as an el_val_t (const char* cast). + * The caller (el program) parses the returned string. + * Reads from the filesystem; for APK assets use the AssetManager path instead. + */ +static char *el_read_file(const char *path) { + if (!path || !*path) return NULL; + FILE *f = fopen(path, "rb"); + if (!f) return NULL; + fseek(f, 0, SEEK_END); + long len = ftell(f); + fseek(f, 0, SEEK_SET); + if (len <= 0) { fclose(f); return NULL; } + char *buf = (char *)malloc((size_t)len + 1); + if (!buf) { fclose(f); return NULL; } + fread(buf, 1, (size_t)len, f); + buf[len] = '\0'; + fclose(f); + return buf; +} + +el_val_t el_android_manifest_read(const char *path) { + char *contents = el_read_file(path); + if (!contents) return (el_val_t)(uintptr_t)""; + return (el_val_t)(uintptr_t)contents; /* caller owns allocation */ +} + +/* ── __widget_* C API (called from el_seed.c) ────────────────────────────── */ +/* + * These are the functions declared in el_native_target.h under EL_TARGET_ANDROID. + * They forward to the el_android_* internal functions above. + * + * The el_val_t / int64_t ABI matches the AppKit functions exactly: + * - Integer params passed as int64_t, extracted with (int) + * - String params passed as int64_t, extracted with (const char*)(uintptr_t) + * - Float params (r,g,b,a) passed as int64_t bit-cast from double; extracted + * with el_to_float / bit-cast union + */ + +static inline float el_val_to_float(el_val_t v) { + union { double d; int64_t i; } u; + u.i = v; + return (float)u.d; +} + +void __native_init(void) { + el_android_init(); +} + +void __native_run_loop(void) { + /* No-op on Android — lifecycle is driven by the Activity. */ +} + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_android_window_create( + (const char *)(uintptr_t)title, + (int)width, (int)height, (int)min_width, (int)min_height); +} + +void __window_show(el_val_t handle) { + el_android_window_show((int64_t)handle); +} + +void __window_set_title(el_val_t handle, el_val_t title) { + el_android_window_set_title((int64_t)handle, + (const char *)(uintptr_t)title); +} + +el_val_t __vstack_create(el_val_t spacing) { + return (el_val_t)el_android_vstack_create((int)spacing); +} + +el_val_t __hstack_create(el_val_t spacing) { + return (el_val_t)el_android_hstack_create((int)spacing); +} + +el_val_t __zstack_create(void) { + return (el_val_t)el_android_zstack_create(); +} + +el_val_t __scroll_create(void) { + return (el_val_t)el_android_scroll_create(); +} + +el_val_t __label_create(el_val_t text) { + return (el_val_t)el_android_label_create((const char *)(uintptr_t)text); +} + +el_val_t __button_create(el_val_t label) { + return (el_val_t)el_android_button_create((const char *)(uintptr_t)label); +} + +el_val_t __text_field_create(el_val_t placeholder) { + return (el_val_t)el_android_text_field_create((const char *)(uintptr_t)placeholder); +} + +el_val_t __text_area_create(el_val_t placeholder) { + return (el_val_t)el_android_text_area_create((const char *)(uintptr_t)placeholder); +} + +el_val_t __image_create(el_val_t path_or_name) { + return (el_val_t)el_android_image_create((const char *)(uintptr_t)path_or_name); +} + +void __widget_set_text(el_val_t handle, el_val_t text) { + el_android_widget_set_text((int64_t)handle, + (const char *)(uintptr_t)text); +} + +el_val_t __widget_get_text(el_val_t handle) { + return (el_val_t)(uintptr_t)el_android_widget_get_text((int64_t)handle); +} + +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a) { + el_android_widget_set_color((int64_t)handle, + el_val_to_float(r), el_val_to_float(g), + el_val_to_float(b), el_val_to_float(a)); +} + +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a) { + el_android_widget_set_bg_color((int64_t)handle, + el_val_to_float(r), el_val_to_float(g), + el_val_to_float(b), el_val_to_float(a)); +} + +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold) { + el_android_widget_set_font((int64_t)handle, + (const char *)(uintptr_t)family, + (int)size, (int)bold); +} + +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_android_widget_set_padding((int64_t)handle, + (int)top, (int)right, (int)bottom, (int)left); +} + +void __widget_set_width(el_val_t handle, el_val_t width) { + el_android_widget_set_width((int64_t)handle, (int)width); +} + +void __widget_set_height(el_val_t handle, el_val_t height) { + el_android_widget_set_height((int64_t)handle, (int)height); +} + +void __widget_set_flex(el_val_t handle, el_val_t flex) { + el_android_widget_set_flex((int64_t)handle, (int)flex); +} + +void __widget_set_corner_radius(el_val_t handle, el_val_t radius) { + el_android_widget_set_corner_radius((int64_t)handle, (int)radius); +} + +void __widget_set_disabled(el_val_t handle, el_val_t disabled) { + el_android_widget_set_disabled((int64_t)handle, (int)disabled); +} + +void __widget_set_hidden(el_val_t handle, el_val_t hidden) { + el_android_widget_set_hidden((int64_t)handle, (int)hidden); +} + +void __widget_add_child(el_val_t parent, el_val_t child) { + el_android_widget_add_child((int64_t)parent, (int64_t)child); +} + +void __widget_remove_child(el_val_t parent, el_val_t child) { + el_android_widget_remove_child((int64_t)parent, (int64_t)child); +} + +void __widget_destroy(el_val_t handle) { + el_android_widget_destroy((int64_t)handle); +} + +void __widget_on_click(el_val_t handle, el_val_t fn_name) { + el_android_widget_on_click((int64_t)handle, + (const char *)(uintptr_t)fn_name); +} + +void __widget_on_change(el_val_t handle, el_val_t fn_name) { + el_android_widget_on_change((int64_t)handle, + (const char *)(uintptr_t)fn_name); +} + +void __widget_on_submit(el_val_t handle, el_val_t fn_name) { + el_android_widget_on_submit((int64_t)handle, + (const char *)(uintptr_t)fn_name); +} + +el_val_t __manifest_read(el_val_t path) { + return el_android_manifest_read((const char *)(uintptr_t)path); +} + +#endif /* EL_TARGET_ANDROID */ diff --git a/lang/el-compiler/runtime/el_appkit.m b/lang/el-compiler/runtime/el_appkit.m new file mode 100644 index 0000000..9eac7a6 --- /dev/null +++ b/lang/el-compiler/runtime/el_appkit.m @@ -0,0 +1,1018 @@ +/* + * el_appkit.m — AppKit backend for the el native widget system. + * + * This file implements the macOS AppKit widget layer that el_seed.c calls + * through to when EL_TARGET_MACOS is defined. + * + * Architecture: + * el program (el code) + * → __widget_* C builtins in el_seed.c + * → el_appkit_* C-callable functions declared here + * → NSView/NSWindow/NSStackView/NSButton/etc. via ObjC + * + * Widget handles: every widget (window, view, control) is assigned an int64_t + * slot index into _el_widgets[]. The el program holds these as opaque Int values. + * Slot 0 is never valid (reserved as null handle = -1 convention). + * + * Threading: All AppKit calls MUST run on the main thread. el_appkit_dispatch_main + * bounces work to the main thread synchronously if called from a background thread. + * el_appkit_run_loop MUST be called from the main thread; it never returns. + * + * Callback mechanism: when a widget fires an event (button click, text change), + * the bridge looks up the registered callback function name, then calls + * dlsym(RTLD_DEFAULT, fn_name)(widget_handle, event_data_string) + * This resolves the El function symbol at runtime, matching the __thread_create + * pattern already established in el_seed.c. + * + * Compile (MRC — no ARC; manual retain/release needed for struct-embedded id): + * clang -std=gnu11 -ObjC -fno-objc-arc -framework Cocoa -c el_appkit.m -o el_appkit.o + * Then link el_appkit.o alongside el_seed.c. + * + * Do NOT use -fobjc-arc: the widget table stores id in a plain C struct. ARC + * forbids explicit retain/release on struct-embedded object pointers and cannot + * insert automatic retain/release through C struct boundaries. MRC is the + * correct choice for this kind of C/ObjC bridge. + * + * Link flags required: + * -framework Cocoa + */ + +#import +#include +#include +#include +#include +#include + +/* ── Widget table ─────────────────────────────────────────────────────────── */ + +#define EL_APPKIT_MAX_WIDGETS 4096 + +typedef enum { + EL_WIDGET_FREE = 0, + EL_WIDGET_WINDOW = 1, + EL_WIDGET_VSTACK = 2, + EL_WIDGET_HSTACK = 3, + EL_WIDGET_ZSTACK = 4, + EL_WIDGET_SCROLL = 5, + EL_WIDGET_LABEL = 6, + EL_WIDGET_BUTTON = 7, + EL_WIDGET_TEXTFIELD = 8, + EL_WIDGET_TEXTAREA = 9, + EL_WIDGET_IMAGE = 10, + EL_WIDGET_DIVIDER = 11, + EL_WIDGET_SPACER = 12, +} ElWidgetKind; + +typedef struct { + ElWidgetKind kind; + id obj; /* NSWindow* or NSView* subclass, retained */ + char* cb_click; /* El function name for click/submit events */ + char* cb_change; /* El function name for value-change events */ + char* user_data; /* custom data string passed to click callbacks */ +} ElWidget; + +static ElWidget _el_widgets[EL_APPKIT_MAX_WIDGETS]; +static int _el_widget_count = 0; + +/* Allocate a slot and return its index. Returns -1 if full. */ +static int64_t el_widget_alloc(ElWidgetKind kind, id obj) { + for (int i = 1; i < EL_APPKIT_MAX_WIDGETS; i++) { + if (_el_widgets[i].kind == EL_WIDGET_FREE) { + _el_widgets[i].kind = kind; + _el_widgets[i].obj = [obj retain]; + _el_widgets[i].cb_click = NULL; + _el_widgets[i].cb_change = NULL; + _el_widgets[i].user_data = NULL; + if (i > _el_widget_count) _el_widget_count = i; + return (int64_t)i; + } + } + return -1; +} + +static ElWidget* el_widget_get(int64_t handle) { + if (handle <= 0 || handle >= EL_APPKIT_MAX_WIDGETS) return NULL; + if (_el_widgets[handle].kind == EL_WIDGET_FREE) return NULL; + return &_el_widgets[handle]; +} + +static void el_widget_free(int64_t handle) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + [w->obj release]; + w->obj = nil; + w->kind = EL_WIDGET_FREE; + free(w->cb_click); w->cb_click = NULL; + free(w->cb_change); w->cb_change = NULL; + free(w->user_data); w->user_data = NULL; +} + +/* ── Dispatch helpers ─────────────────────────────────────────────────────── */ + +/* Run a block on the main thread, waiting for completion. Safe to call from + * any thread including the main thread. */ +static void el_appkit_sync_main(void (^block)(void)) { + if ([NSThread isMainThread]) { + block(); + } else { + dispatch_sync(dispatch_get_main_queue(), block); + } +} + +/* ── El callback invocation ──────────────────────────────────────────────── */ +/* + * Invoke an El callback by symbol name. The El function must have the + * signature: fn handler(handle: Int, data: String) -> Void + * which compiles to: void fn_name(el_val_t handle, el_val_t data) + */ +typedef void (*ElCb2)(int64_t handle, int64_t data); + +static void el_appkit_invoke_cb(const char* fn_name, int64_t handle, const char* data) { + if (!fn_name || !*fn_name) return; + void* sym = dlsym(RTLD_DEFAULT, fn_name); + if (!sym) return; + ElCb2 fn = (ElCb2)sym; + fn(handle, (int64_t)(uintptr_t)(data ? data : "")); +} + +/* ── ObjC delegate for button clicks ─────────────────────────────────────── */ + +@interface ElButtonTarget : NSObject +@property int64_t widgetHandle; +@end + +@implementation ElButtonTarget +- (void)buttonClicked:(id)sender { + ElWidget* w = el_widget_get(self.widgetHandle); + if (w && w->cb_click) { + el_appkit_invoke_cb(w->cb_click, self.widgetHandle, w->user_data ? w->user_data : ""); + } +} +@end + +/* ── ObjC delegate for text field changes / enter key ───────────────────── */ + +@interface ElTextFieldDelegate : NSObject +@property int64_t widgetHandle; +@end + +@implementation ElTextFieldDelegate +- (void)controlTextDidChange:(NSNotification*)notif { + ElWidget* w = el_widget_get(self.widgetHandle); + if (!w) return; + NSTextField* tf = (NSTextField*)notif.object; + const char* val = [[tf stringValue] UTF8String]; + if (w->cb_change) { + el_appkit_invoke_cb(w->cb_change, self.widgetHandle, val ? val : ""); + } +} +- (void)controlTextDidEndEditing:(NSNotification*)notif { + /* Enter key (or tab) submits. The userInfo value is an NSNumber, not NSEvent. */ + NSNumber* movement = [[notif userInfo] objectForKey:@"NSTextMovement"]; + if (movement && [movement intValue] == NSTextMovementReturn) { + ElWidget* w = el_widget_get(self.widgetHandle); + if (!w) return; + NSTextField* tf = (NSTextField*)notif.object; + const char* val = [[tf stringValue] UTF8String]; + if (w->cb_click) { /* cb_click = on_submit for text fields */ + el_appkit_invoke_cb(w->cb_click, self.widgetHandle, val ? val : ""); + } + } +} +@end + +/* We hold strong references to our ObjC delegate objects in a side table so + * ARC/MRC don't collect them. Simple parallel array keyed by widget slot. */ +static id _el_delegates[EL_APPKIT_MAX_WIDGETS]; + +/* ── Flipped wrapper for NSScrollView document views ───────────────────────── + * NSScrollView's clip view uses the document view's coordinate system. When + * the document view is non-flipped (origin at bottom-left), content stacks + * from the bottom. This subclass overrides isFlipped so content starts at the + * visual top-left, matching expected list/feed behaviour. */ +@interface ElFlippedView : NSView +@end +@implementation ElFlippedView +- (BOOL)isFlipped { return YES; } +@end + +/* ── ElResizableContentView ─────────────────────────────────────────────────── + * Used as NSWindow's content view instead of a plain NSView. + * Overrides setFrameSize: to propagate the new size directly to the single + * root child without going through the AL constraint graph. + * + * Why: with TAMIC:NO on the content view and 4-edge AL constraints to the + * child, NSWindow calls [contentView fittingSize] to compute its minimum + * resize floor. fittingSize walks the constraint graph and returns the + * largest minimum it finds — locking horizontal resize to the initial width. + * By removing the AL constraints and propagating via setFrameSize: instead, + * NSWindow has no constraint-based minimum and respects setContentMinSize: only. */ +@interface ElResizableContentView : NSView +@end +@implementation ElResizableContentView +- (NSSize)fittingSize { return NSMakeSize(1.0, 1.0); } +- (NSSize)intrinsicContentSize { return NSMakeSize(NSViewNoIntrinsicMetric, NSViewNoIntrinsicMetric); } +@end + +/* ElWindow subclass — overrides minSize so the AL constraint graph cannot + * inflate the resize floor beyond the manifest-specified minimum. + * NSWindow normally sets minSize from the larger of the explicit setMinSize: + * call and the AL-computed minimum content size; the override replaces that + * with the explicit minimum only. */ +@interface ElWindow : NSWindow +@property (nonatomic) NSSize elMinFrameSize; +@property (nonatomic) NSSize elInitialContentSize; /* designed width/height from manifest */ +@end +@implementation ElWindow +- (NSSize)minSize { return _elMinFrameSize; } +@end + +/* ── NSApplication setup ──────────────────────────────────────────────────── */ + +@interface ElAppDelegate : NSObject +@end + +@implementation ElAppDelegate +- (void)applicationDidFinishLaunching:(NSNotification*)notif { + /* Nothing needed — windows are created programmatically before run loop. */ +} +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)app { + return YES; +} +@end + +static ElAppDelegate* _el_app_delegate = nil; + +/* ── Public C API (called from el_seed.c) ─────────────────────────────────── */ + +/* + * el_appkit_init — initialize NSApplication. Must be called once on the main + * thread before any other el_appkit_* function. Idempotent. + */ +void el_appkit_init(void) { + static int done = 0; + if (done) return; + done = 1; + [NSApplication sharedApplication]; + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + _el_app_delegate = [[ElAppDelegate alloc] init]; + [NSApp setDelegate:_el_app_delegate]; +} + +/* + * el_appkit_window_create — create an NSWindow and return its handle. + * title, width, height, min_width, min_height come from manifest.el app{} block. + */ +int64_t el_appkit_window_create(const char* title, int width, int height, + int min_width, int min_height) { + __block int64_t handle = -1; + el_appkit_sync_main(^{ + NSRect frame = NSMakeRect(0, 0, (CGFloat)width, (CGFloat)height); + NSWindowStyleMask style = + NSWindowStyleMaskTitled | + NSWindowStyleMaskClosable | + NSWindowStyleMaskMiniaturizable | + NSWindowStyleMaskResizable; + ElWindow* win = [[ElWindow alloc] + initWithContentRect:frame + styleMask:style + backing:NSBackingStoreBuffered + defer:NO]; + [win setTitle:[NSString stringWithUTF8String:title ? title : ""]]; + /* Store the manifest minimum as our explicit frame floor. */ + NSRect minContentRect = NSMakeRect(0, 0, (CGFloat)min_width, (CGFloat)min_height); + NSSize minFrame = [win frameRectForContentRect:minContentRect].size; + win.elMinFrameSize = minFrame; + [win setContentMinSize:NSMakeSize((CGFloat)min_width, (CGFloat)min_height)]; + win.elInitialContentSize = NSMakeSize((CGFloat)width, (CGFloat)height); + [win center]; + + ElResizableContentView* root = [[ElResizableContentView alloc] initWithFrame:frame]; + [win setContentView:root]; + + handle = el_widget_alloc(EL_WIDGET_WINDOW, win); + [win release]; + [root release]; + }); + return handle; +} + +/* + * el_appkit_window_show — make the window visible and bring it to front. + */ +void el_appkit_window_show(int64_t handle) { + el_appkit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w || w->kind != EL_WIDGET_WINDOW) return; + NSWindow* win = (NSWindow*)w->obj; + /* AL may have shrunk the window during the build phase. + * Restore the designed content size before showing — the window + * is not yet visible so the user never sees the shrunken state. + * After this, AL runs within the correct frame and required + * 4-edge constraints keep the child filling on every resize. */ + if ([win isKindOfClass:[ElWindow class]]) { + ElWindow* elWin = (ElWindow*)win; + NSSize cs = elWin.elInitialContentSize; + if (cs.width > 0) { + [win setContentSize:cs]; + [win center]; + } + } + [win makeKeyAndOrderFront:nil]; + [NSApp activateIgnoringOtherApps:YES]; + }); +} + +/* + * el_appkit_window_set_title — update window title at runtime. + */ +void el_appkit_window_set_title(int64_t handle, const char* title) { + el_appkit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w || w->kind != EL_WIDGET_WINDOW) return; + NSWindow* win = (NSWindow*)w->obj; + [win setTitle:[NSString stringWithUTF8String:title ? title : ""]]; + }); +} + +/* + * el_appkit_run_loop — start the NSApplication run loop. Never returns. + * Must be called from the main thread as the last step of main(). + */ +void el_appkit_run_loop(void) { + [NSApp run]; +} + +/* ── Layout container factories ───────────────────────────────────────────── */ + +static int64_t make_stack(NSUserInterfaceLayoutOrientation orient, + CGFloat spacing) { + __block int64_t handle = -1; + el_appkit_sync_main(^{ + NSStackView* sv = [[NSStackView alloc] initWithFrame:NSZeroRect]; + [sv setOrientation:orient]; + /* Alignment must match the stack's cross-axis to avoid NSStackView + * silently flipping orientation. For a vertical stack, align children + * to the leading edge (left); for a horizontal stack, align to top. + * Using NSLayoutAttributeLeading on a horizontal stack flips it vertical. */ + NSLayoutAttribute align = (orient == NSUserInterfaceLayoutOrientationVertical) + ? NSLayoutAttributeLeading : NSLayoutAttributeTop; + [sv setAlignment:align]; + [sv setSpacing:spacing]; + [sv setEdgeInsets:NSEdgeInsetsZero]; + [sv setDistribution:NSStackViewDistributionFill]; + [sv setTranslatesAutoresizingMaskIntoConstraints:NO]; + ElWidgetKind kind = (orient == NSUserInterfaceLayoutOrientationVertical) + ? EL_WIDGET_VSTACK : EL_WIDGET_HSTACK; + handle = el_widget_alloc(kind, sv); + [sv release]; + }); + return handle; +} + +int64_t el_appkit_vstack_create(int spacing) { + return make_stack(NSUserInterfaceLayoutOrientationVertical, (CGFloat)spacing); +} + +int64_t el_appkit_hstack_create(int spacing) { + return make_stack(NSUserInterfaceLayoutOrientationHorizontal, (CGFloat)spacing); +} + +int64_t el_appkit_zstack_create(void) { + /* ZStack = NSView with manual child positioning (no stack manager). */ + __block int64_t handle = -1; + el_appkit_sync_main(^{ + NSView* v = [[NSView alloc] initWithFrame:NSZeroRect]; + [v setTranslatesAutoresizingMaskIntoConstraints:NO]; + handle = el_widget_alloc(EL_WIDGET_ZSTACK, v); + [v release]; + }); + return handle; +} + +int64_t el_appkit_scroll_create(void) { + __block int64_t handle = -1; + el_appkit_sync_main(^{ + NSScrollView* sv = [[NSScrollView alloc] initWithFrame:NSZeroRect]; + [sv setHasVerticalScroller:YES]; + [sv setHasHorizontalScroller:NO]; + [sv setAutohidesScrollers:YES]; + [sv setTranslatesAutoresizingMaskIntoConstraints:NO]; + handle = el_widget_alloc(EL_WIDGET_SCROLL, sv); + [sv release]; + }); + return handle; +} + +/* ── Widget factories ─────────────────────────────────────────────────────── */ + +int64_t el_appkit_label_create(const char* text) { + __block int64_t handle = -1; + el_appkit_sync_main(^{ + NSTextField* lbl = [NSTextField labelWithString: + [NSString stringWithUTF8String:text ? text : ""]]; + [lbl setEditable:NO]; + [lbl setBordered:NO]; + [lbl setDrawsBackground:NO]; + [lbl setTranslatesAutoresizingMaskIntoConstraints:NO]; + handle = el_widget_alloc(EL_WIDGET_LABEL, lbl); + }); + return handle; +} + +int64_t el_appkit_button_create(const char* label) { + __block int64_t handle = -1; + el_appkit_sync_main(^{ + NSButton* btn = [[NSButton alloc] initWithFrame:NSZeroRect]; + [btn setButtonType:NSButtonTypeMomentaryLight]; + [btn setBezelStyle:NSBezelStyleShadowlessSquare]; + [btn setTitle:[NSString stringWithUTF8String:label ? label : ""]]; + [btn setAlignment:NSTextAlignmentLeft]; + [btn setTranslatesAutoresizingMaskIntoConstraints:NO]; + + /* Create action target. */ + ElButtonTarget* target = [[ElButtonTarget alloc] init]; + /* handle assigned below after alloc — set after */ + [btn setTarget:target]; + [btn setAction:@selector(buttonClicked:)]; + + int64_t h = el_widget_alloc(EL_WIDGET_BUTTON, btn); + target.widgetHandle = h; + _el_delegates[h] = target; /* retain */ + handle = h; + [btn release]; + }); + return handle; +} + +int64_t el_appkit_text_field_create(const char* placeholder) { + __block int64_t handle = -1; + el_appkit_sync_main(^{ + NSTextField* tf = [[NSTextField alloc] initWithFrame:NSZeroRect]; + [tf setTranslatesAutoresizingMaskIntoConstraints:NO]; + if (placeholder && *placeholder) { + [tf setPlaceholderString:[NSString stringWithUTF8String:placeholder]]; + } + + ElTextFieldDelegate* del = [[ElTextFieldDelegate alloc] init]; + [tf setDelegate:del]; + + int64_t h = el_widget_alloc(EL_WIDGET_TEXTFIELD, tf); + del.widgetHandle = h; + _el_delegates[h] = del; + handle = h; + [tf release]; + }); + return handle; +} + +int64_t el_appkit_text_area_create(const char* placeholder) { + __block int64_t handle = -1; + el_appkit_sync_main(^{ + NSScrollView* scroll = [[NSScrollView alloc] initWithFrame:NSZeroRect]; + [scroll setHasVerticalScroller:YES]; + [scroll setAutohidesScrollers:YES]; + [scroll setTranslatesAutoresizingMaskIntoConstraints:NO]; + + NSTextView* tv = [[NSTextView alloc] initWithFrame:NSZeroRect]; + [tv setMinSize:NSMakeSize(0, 60)]; + [tv setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)]; + [tv setVerticallyResizable:YES]; + [tv setHorizontallyResizable:NO]; + [tv setAutoresizingMask:NSViewWidthSizable]; + if (placeholder && *placeholder) { + /* NSTextView has no native placeholder; we set a hint via + * a custom accessibility description as a minimal approach. */ + [tv setAccessibilityPlaceholderValue: + [NSString stringWithUTF8String:placeholder]]; + } + [[tv textContainer] setWidthTracksTextView:YES]; + [scroll setDocumentView:tv]; + + int64_t h = el_widget_alloc(EL_WIDGET_TEXTAREA, scroll); + handle = h; + [scroll release]; + [tv release]; + }); + return handle; +} + +int64_t el_appkit_image_create(const char* path_or_name) { + __block int64_t handle = -1; + el_appkit_sync_main(^{ + NSImage* img = nil; + if (path_or_name && *path_or_name) { + /* Try as filesystem path first, then as named system image. */ + img = [[NSImage alloc] initWithContentsOfFile: + [NSString stringWithUTF8String:path_or_name]]; + if (!img) { + img = [NSImage imageNamed:[NSString stringWithUTF8String:path_or_name]]; + if (img) [img retain]; + } + } + NSImageView* iv = [[NSImageView alloc] initWithFrame:NSZeroRect]; + [iv setTranslatesAutoresizingMaskIntoConstraints:NO]; + if (img) { + [iv setImage:img]; + [img release]; + } + handle = el_widget_alloc(EL_WIDGET_IMAGE, iv); + [iv release]; + }); + return handle; +} + +/* ── Widget property setters ─────────────────────────────────────────────── */ + +void el_appkit_widget_set_text(int64_t handle, const char* text) { + el_appkit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + NSString* s = [NSString stringWithUTF8String:text ? text : ""]; + switch (w->kind) { + case EL_WIDGET_LABEL: + case EL_WIDGET_TEXTFIELD: + [(NSTextField*)w->obj setStringValue:s]; + break; + case EL_WIDGET_BUTTON: + [(NSButton*)w->obj setTitle:s]; + break; + case EL_WIDGET_TEXTAREA: { + NSScrollView* sv = (NSScrollView*)w->obj; + NSTextView* tv = (NSTextView*)[sv documentView]; + [tv setString:s]; + break; + } + case EL_WIDGET_WINDOW: + [(NSWindow*)w->obj setTitle:s]; + break; + default: break; + } + }); +} + +const char* el_appkit_widget_get_text(int64_t handle) { + __block const char* result = ""; + el_appkit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + NSString* s = nil; + switch (w->kind) { + case EL_WIDGET_LABEL: + case EL_WIDGET_TEXTFIELD: + s = [(NSTextField*)w->obj stringValue]; + break; + case EL_WIDGET_BUTTON: + s = [(NSButton*)w->obj title]; + break; + case EL_WIDGET_TEXTAREA: { + NSScrollView* sv = (NSScrollView*)w->obj; + NSTextView* tv = (NSTextView*)[sv documentView]; + s = [tv string]; + break; + } + default: break; + } + if (s) result = strdup([s UTF8String]); + }); + return result; +} + +void el_appkit_widget_set_color(int64_t handle, float r, float g, float b, float a) { + el_appkit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + NSColor* c = [NSColor colorWithSRGBRed:(CGFloat)r + green:(CGFloat)g + blue:(CGFloat)b + alpha:(CGFloat)a]; + switch (w->kind) { + case EL_WIDGET_LABEL: + case EL_WIDGET_TEXTFIELD: + [(NSTextField*)w->obj setTextColor:c]; + break; + case EL_WIDGET_BUTTON: { + /* Update foreground color on attributed title, preserving font. */ + NSButton* btn = (NSButton*)w->obj; + NSAttributedString* existing = [btn attributedTitle]; + NSMutableAttributedString* as; + if (existing && [existing length] > 0) { + as = [[NSMutableAttributedString alloc] initWithAttributedString:existing]; + } else { + NSString* t = [btn title]; + if (!t) t = @""; + as = [[NSMutableAttributedString alloc] initWithString:t]; + } + [as addAttribute:NSForegroundColorAttributeName value:c + range:NSMakeRange(0, [as length])]; + [btn setAttributedTitle:as]; + [as release]; + break; + } + case EL_WIDGET_VSTACK: + case EL_WIDGET_HSTACK: + case EL_WIDGET_ZSTACK: { + /* Set background via wantsLayer + layer background. */ + NSView* v = (NSView*)w->obj; + [v setWantsLayer:YES]; + [v layer].backgroundColor = [c CGColor]; + break; + } + default: break; + } + }); +} + +void el_appkit_widget_set_bg_color(int64_t handle, float r, float g, float b, float a) { + el_appkit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + NSColor* c = [NSColor colorWithSRGBRed:(CGFloat)r + green:(CGFloat)g + blue:(CGFloat)b + alpha:(CGFloat)a]; + if (w->kind == EL_WIDGET_WINDOW) { + NSWindow* win = (NSWindow*)w->obj; + [win setBackgroundColor:c]; + /* Also paint the contentView layer so it shows through NSStackView. */ + NSView* cv = [win contentView]; + [cv setWantsLayer:YES]; + [cv layer].backgroundColor = [c CGColor]; + return; + } + if (w->kind == EL_WIDGET_BUTTON) { + /* Disable native bezel so CALayer background is visible. */ + NSButton* btn = (NSButton*)w->obj; + [btn setBordered:NO]; + [btn setWantsLayer:YES]; + [btn layer].backgroundColor = [c CGColor]; + return; + } + NSView* v = (NSView*)w->obj; + if (w->kind == EL_WIDGET_SCROLL) { + /* NSScrollView needs setBackgroundColor, not just layer bg. */ + NSScrollView* sv = (NSScrollView*)v; + [sv setBackgroundColor:c]; + [sv setDrawsBackground:YES]; + } + [v setWantsLayer:YES]; + [v layer].backgroundColor = [c CGColor]; + }); +} + +void el_appkit_widget_set_font(int64_t handle, const char* family, int size, int bold) { + el_appkit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + NSFont* font; + if (bold) { + font = [NSFont boldSystemFontOfSize:(CGFloat)size]; + } else if (family && *family && strcmp(family, "system") != 0) { + font = [NSFont fontWithName:[NSString stringWithUTF8String:family] + size:(CGFloat)size]; + if (!font) font = [NSFont systemFontOfSize:(CGFloat)size]; + } else { + font = [NSFont systemFontOfSize:(CGFloat)size]; + } + switch (w->kind) { + case EL_WIDGET_LABEL: + case EL_WIDGET_TEXTFIELD: + [(NSTextField*)w->obj setFont:font]; + break; + case EL_WIDGET_BUTTON: + /* NSButton: set font via attributed title, preserving existing foreground color. */ + { + NSButton* fbtn = (NSButton*)w->obj; + NSAttributedString* fexisting = [fbtn attributedTitle]; + NSMutableAttributedString* as; + if (fexisting && [fexisting length] > 0) { + as = [[NSMutableAttributedString alloc] initWithAttributedString:fexisting]; + } else { + NSString* ft = [fbtn title]; + if (!ft) ft = @""; + as = [[NSMutableAttributedString alloc] initWithString:ft]; + } + [as addAttribute:NSFontAttributeName value:font + range:NSMakeRange(0, [as length])]; + [fbtn setAttributedTitle:as]; + [as release]; + } + break; + case EL_WIDGET_TEXTAREA: { + NSScrollView* sv = (NSScrollView*)w->obj; + NSTextView* tv = (NSTextView*)[sv documentView]; + [tv setFont:font]; + break; + } + default: break; + } + }); +} + +void el_appkit_widget_set_padding(int64_t handle, int top, int right, int bottom, int left) { + el_appkit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + /* Padding on stack views maps to edgeInsets. */ + if (w->kind == EL_WIDGET_VSTACK || w->kind == EL_WIDGET_HSTACK) { + NSStackView* sv = (NSStackView*)w->obj; + [sv setEdgeInsets:NSEdgeInsetsMake((CGFloat)top, (CGFloat)left, + (CGFloat)bottom, (CGFloat)right)]; + } + /* For individual widgets we set a custom layout margin via constraints. + * For now, NSTextView respects textContainerInset. */ + if (w->kind == EL_WIDGET_TEXTAREA) { + NSScrollView* sv = (NSScrollView*)w->obj; + NSTextView* tv = (NSTextView*)[sv documentView]; + [tv setTextContainerInset:NSMakeSize((CGFloat)(left + right) / 2, + (CGFloat)(top + bottom) / 2)]; + } + }); +} + +void el_appkit_widget_set_width(int64_t handle, int width) { + el_appkit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + NSView* v = (NSView*)w->obj; + if ([v isKindOfClass:[NSWindow class]]) return; + /* Add a fixed-width constraint. */ + NSLayoutConstraint* c = [NSLayoutConstraint + constraintWithItem:v + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1.0 + constant:(CGFloat)width]; + c.priority = NSLayoutPriorityDefaultHigh; + [v addConstraint:c]; + }); +} + +void el_appkit_widget_set_height(int64_t handle, int height) { + el_appkit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + NSView* v = (NSView*)w->obj; + if ([v isKindOfClass:[NSWindow class]]) return; + NSLayoutConstraint* c = [NSLayoutConstraint + constraintWithItem:v + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1.0 + constant:(CGFloat)height]; + c.priority = NSLayoutPriorityDefaultHigh; + [v addConstraint:c]; + }); +} + +void el_appkit_widget_set_flex(int64_t handle, int flex) { + el_appkit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + NSView* v = (NSView*)w->obj; + if ([v isKindOfClass:[NSWindow class]]) return; + if (flex > 0) { + /* flex:1 → low hugging (wants to expand) + low compression resistance + * (willing to be compressed). This makes NSStackViewDistributionFill + * choose this view to grow/shrink to fill available space. */ + [v setContentHuggingPriority:NSLayoutPriorityDefaultLow + forOrientation:NSLayoutConstraintOrientationHorizontal]; + [v setContentHuggingPriority:NSLayoutPriorityDefaultLow + forOrientation:NSLayoutConstraintOrientationVertical]; + [v setContentCompressionResistancePriority:NSLayoutPriorityDefaultLow + forOrientation:NSLayoutConstraintOrientationHorizontal]; + [v setContentCompressionResistancePriority:NSLayoutPriorityDefaultLow + forOrientation:NSLayoutConstraintOrientationVertical]; + } else { + /* flex:0 → high hugging (stays at natural size) + high compression + * resistance (resists shrinking). */ + [v setContentHuggingPriority:NSLayoutPriorityDefaultHigh + forOrientation:NSLayoutConstraintOrientationHorizontal]; + [v setContentHuggingPriority:NSLayoutPriorityDefaultHigh + forOrientation:NSLayoutConstraintOrientationVertical]; + [v setContentCompressionResistancePriority:NSLayoutPriorityDefaultHigh + forOrientation:NSLayoutConstraintOrientationHorizontal]; + [v setContentCompressionResistancePriority:NSLayoutPriorityDefaultHigh + forOrientation:NSLayoutConstraintOrientationVertical]; + } + }); +} + +void el_appkit_widget_set_corner_radius(int64_t handle, int radius) { + el_appkit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + NSView* v = (NSView*)w->obj; + if ([v isKindOfClass:[NSWindow class]]) return; + [v setWantsLayer:YES]; + [v layer].cornerRadius = (CGFloat)radius; + [v layer].masksToBounds = YES; + }); +} + +void el_appkit_widget_set_disabled(int64_t handle, int disabled) { + el_appkit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + if (w->kind == EL_WIDGET_BUTTON) { + [(NSButton*)w->obj setEnabled:!disabled]; + } else if (w->kind == EL_WIDGET_TEXTFIELD) { + [(NSTextField*)w->obj setEnabled:!disabled]; + } + }); +} + +void el_appkit_widget_set_hidden(int64_t handle, int hidden) { + el_appkit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + NSView* v = (NSView*)w->obj; + if (![v isKindOfClass:[NSWindow class]]) { + [v setHidden:(BOOL)hidden]; + } + }); +} + +/* ── Child management ─────────────────────────────────────────────────────── */ + +/* + * el_appkit_widget_add_child — attach child widget to parent. + * + * - Window: child is added to contentView (NSStackView). + * - VStack/HStack: child is added as an arranged subview. + * - ZStack/generic view: child is added as a plain subview. + * - ScrollView: child becomes the documentView (only first child honoured). + */ +void el_appkit_widget_add_child(int64_t parent, int64_t child) { + el_appkit_sync_main(^{ + ElWidget* pw = el_widget_get(parent); + ElWidget* cw = el_widget_get(child); + if (!pw || !cw) return; + + NSView* childView = (NSView*)cw->obj; + if ([childView isKindOfClass:[NSWindow class]]) return; /* can't add window as child */ + + switch (pw->kind) { + case EL_WIDGET_WINDOW: { + NSWindow* win = (NSWindow*)pw->obj; + NSView* cv = [win contentView]; + /* Standard required 4-edge constraints so the child always + * fills the content view during user-initiated resize. + * AL may shrink the window during the build phase (before show), + * but el_appkit_window_show calls setContentSize: to restore + * the designed size before making the window visible. */ + [childView setTranslatesAutoresizingMaskIntoConstraints:NO]; + [cv addSubview:childView]; + [NSLayoutConstraint activateConstraints:@[ + [childView.topAnchor constraintEqualToAnchor:cv.topAnchor], + [childView.bottomAnchor constraintEqualToAnchor:cv.bottomAnchor], + [childView.leadingAnchor constraintEqualToAnchor:cv.leadingAnchor], + [childView.trailingAnchor constraintEqualToAnchor:cv.trailingAnchor], + ]]; + break; + } + case EL_WIDGET_VSTACK: { + NSStackView* sv = (NSStackView*)pw->obj; + [sv addArrangedSubview:childView]; + /* Pin child leading+trailing to fill cross-axis (width) of the VStack. + * Priority 999 avoids intrinsic-size feedback through NSWindow. */ + [childView setTranslatesAutoresizingMaskIntoConstraints:NO]; + NSLayoutConstraint* vl = [NSLayoutConstraint + constraintWithItem:childView attribute:NSLayoutAttributeLeading + relatedBy:NSLayoutRelationEqual + toItem:sv attribute:NSLayoutAttributeLeading + multiplier:1.0 constant:0.0]; + NSLayoutConstraint* vr = [NSLayoutConstraint + constraintWithItem:childView attribute:NSLayoutAttributeTrailing + relatedBy:NSLayoutRelationEqual + toItem:sv attribute:NSLayoutAttributeTrailing + multiplier:1.0 constant:0.0]; + vl.priority = 999; + vr.priority = 999; + [sv addConstraints:@[vl, vr]]; + break; + } + case EL_WIDGET_HSTACK: { + NSStackView* sv = (NSStackView*)pw->obj; + [sv addArrangedSubview:childView]; + /* Pin child top+bottom to fill cross-axis (height) of the HStack. + * Priority 499 (well below required 1000) lets the window frame + * win over child intrinsic size, avoiding NSWindow auto-resize. */ + [childView setTranslatesAutoresizingMaskIntoConstraints:NO]; + NSLayoutConstraint* ht = [NSLayoutConstraint + constraintWithItem:childView attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationEqual + toItem:sv attribute:NSLayoutAttributeTop + multiplier:1.0 constant:0.0]; + NSLayoutConstraint* hb = [NSLayoutConstraint + constraintWithItem:childView attribute:NSLayoutAttributeBottom + relatedBy:NSLayoutRelationEqual + toItem:sv attribute:NSLayoutAttributeBottom + multiplier:1.0 constant:0.0]; + ht.priority = 499; + hb.priority = 499; + [sv addConstraints:@[ht, hb]]; + break; + } + case EL_WIDGET_SCROLL: { + NSScrollView* sv = (NSScrollView*)pw->obj; + /* Wrap the child in a flipped view so content starts at the + * visual top-left. Without flipping, NSScrollView places the + * document origin at the bottom-left and lists appear inverted. */ + ElFlippedView* flipper = [[ElFlippedView alloc] initWithFrame:NSZeroRect]; + [flipper setTranslatesAutoresizingMaskIntoConstraints:NO]; + [childView setTranslatesAutoresizingMaskIntoConstraints:NO]; + [flipper addSubview:childView]; + /* Pin child to all 4 edges of the flipper. */ + NSArray* hc = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[c]|" + options:0 metrics:nil views:@{@"c": childView}]; + NSArray* vc = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[c]|" + options:0 metrics:nil views:@{@"c": childView}]; + [flipper addConstraints:hc]; + [flipper addConstraints:vc]; + [sv setDocumentView:flipper]; + /* Constrain flipper width to the scroll view so items fill the + * full panel width (vertical-only scrolling). */ + NSLayoutConstraint* wc = [NSLayoutConstraint + constraintWithItem:flipper attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:sv attribute:NSLayoutAttributeWidth + multiplier:1.0 constant:0.0]; + [sv addConstraint:wc]; + [flipper release]; + break; + } + case EL_WIDGET_ZSTACK: + default: { + NSView* pv = (NSView*)pw->obj; + [pv addSubview:childView]; + break; + } + } + }); +} + +/* + * el_appkit_widget_remove_child — remove a child widget from its parent. + */ +void el_appkit_widget_remove_child(int64_t parent, int64_t child) { + el_appkit_sync_main(^{ + ElWidget* cw = el_widget_get(child); + if (!cw) return; + NSView* v = (NSView*)cw->obj; + if (![v isKindOfClass:[NSWindow class]]) { + [v removeFromSuperview]; + } + }); +} + +/* ── Event registration ───────────────────────────────────────────────────── */ + +void el_appkit_widget_set_data(int64_t handle, const char* data_str) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + free(w->user_data); + w->user_data = data_str && *data_str ? strdup(data_str) : NULL; +} + +void el_appkit_widget_on_click(int64_t handle, const char* fn_name) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + free(w->cb_click); + w->cb_click = fn_name && *fn_name ? strdup(fn_name) : NULL; +} + +void el_appkit_widget_on_change(int64_t handle, const char* fn_name) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + free(w->cb_change); + w->cb_change = fn_name && *fn_name ? strdup(fn_name) : NULL; +} + +void el_appkit_widget_on_submit(int64_t handle, const char* fn_name) { + /* For text fields, submit = pressing Enter → stored in cb_click slot. */ + el_appkit_widget_on_click(handle, fn_name); +} + +/* ── Widget destroy ───────────────────────────────────────────────────────── */ + +void el_appkit_widget_destroy(int64_t handle) { + el_appkit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + NSView* v = (NSView*)w->obj; + if (![v isKindOfClass:[NSWindow class]]) { + [v removeFromSuperview]; + } else { + [(NSWindow*)w->obj close]; + } + [_el_delegates[handle] release]; + _el_delegates[handle] = nil; + el_widget_free(handle); + }); +} diff --git a/lang/el-compiler/runtime/el_gtk4.c b/lang/el-compiler/runtime/el_gtk4.c new file mode 100644 index 0000000..d427786 --- /dev/null +++ b/lang/el-compiler/runtime/el_gtk4.c @@ -0,0 +1,1327 @@ +/* + * el_gtk4.c — GTK4 backend for the el native widget system. + * + * This file implements the GTK4 widget layer that el_seed.c calls through to + * when EL_TARGET_LINUX is defined. It runs on both Linux and macOS (Homebrew). + * + * Architecture: + * el program (el code) + * → __widget_* C builtins in el_seed.c + * → el_gtk4_* C-callable functions declared here + * → GtkWidget* / GtkWindow* via GTK4 C API + * + * Widget handles: every widget is assigned an int64_t slot index into + * _el_widgets[]. The el program holds these as opaque Int values. + * Slot 0 is never valid (reserved; invalid handle = -1 convention). + * + * macOS lifecycle: + * On macOS the GTK4 Quartz backend sets the NSApplication main menu during + * g_application_run → startup signal, which requires the main thread. The el + * program's compiled main() calls native_init(), then window/widget creation, + * then native_run_loop() — so g_application_run() IS called from the main + * thread in el_gtk4_run_loop(). + * + * The constraint is that GTK widget creation requires an initialized display, + * which only exists after g_application_run starts. To handle this, all + * el_gtk4_* calls made before el_gtk4_run_loop() are DEFERRED into a queue. + * The activate handler replays the queue, then the app runs normally. + * + * Threading (post-activation): + * GTK4 must run on the main thread. el_gtk4_sync_main() uses + * g_main_context_invoke_full() to dispatch from any thread, waiting for + * completion via a GMutex/GCond pair — the same role as dispatch_sync() in + * the AppKit bridge. + * + * Callback mechanism: on signal, the bridge calls + * dlsym(RTLD_DEFAULT, fn_name)(widget_handle, event_data_string) + * matching the el_appkit.m / __thread_create pattern in el_seed.c. + * + * Compile: + * gcc -DEL_TARGET_LINUX $(pkg-config --cflags gtk4) \ + * el_gtk4.c -c -o el_gtk4.o + * Then link el_gtk4.o alongside el_seed.c with: + * $(pkg-config --libs gtk4) -ldl + * + * GTK4 version notes: + * • gtk_widget_get_style_context() is deprecated in GTK 4.10+. + * A #if GTK_MINOR_VERSION guard selects the correct CSS-provider path. + * • gtk_editable_get_text() / gtk_editable_set_text() are the unified + * GTK4 text API for GtkEntry and any GtkEditable. + */ + +#ifdef EL_TARGET_LINUX + +/* _GNU_SOURCE: expose RTLD_DEFAULT (dlfcn.h) and strdup (string.h) on Linux. */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +/* G_APPLICATION_DEFAULT_FLAGS was added in GLib 2.74. + * Ubuntu 22.04 ships GLib 2.72 — use the older alias when running on it. */ +#ifndef G_APPLICATION_DEFAULT_FLAGS +#define G_APPLICATION_DEFAULT_FLAGS G_APPLICATION_FLAGS_NONE +#endif + +/* el_val_t must already be defined by el_runtime.h / el_seed.h. */ +#ifndef EL_VAL_T_DEFINED +typedef int64_t el_val_t; +#endif + +#ifndef EL_CSTR +#define EL_CSTR(v) ((const char*)(uintptr_t)(v)) +#endif +#ifndef EL_STR +#define EL_STR(s) ((el_val_t)(uintptr_t)(s)) +#endif + +/* ── Widget table ─────────────────────────────────────────────────────────── */ + +#define EL_GTK4_MAX_WIDGETS 4096 + +typedef enum { + EL_WIDGET_FREE = 0, + EL_WIDGET_WINDOW = 1, + EL_WIDGET_VSTACK = 2, + EL_WIDGET_HSTACK = 3, + EL_WIDGET_ZSTACK = 4, + EL_WIDGET_SCROLL = 5, + EL_WIDGET_LABEL = 6, + EL_WIDGET_BUTTON = 7, + EL_WIDGET_TEXTFIELD = 8, + EL_WIDGET_TEXTAREA = 9, + EL_WIDGET_IMAGE = 10, + EL_WIDGET_DIVIDER = 11, + EL_WIDGET_SPACER = 12, +} ElWidgetKind; + +typedef struct { + ElWidgetKind kind; + GtkWidget* widget; /* Strong reference (g_object_ref'd on alloc). */ + char* cb_click; /* El function name for click/submit events. */ + char* cb_change;/* El function name for value-change events. */ +} ElWidget; + +static ElWidget _el_widgets[EL_GTK4_MAX_WIDGETS]; +static int _el_widget_count = 0; + +/* + * el_widget_alloc — allocate a slot for a fully-constructed widget. + * Takes a strong ref. Returns slot index or -1 if full. + */ +static int64_t el_widget_alloc(ElWidgetKind kind, GtkWidget* w) { + for (int i = 1; i < EL_GTK4_MAX_WIDGETS; i++) { + if (_el_widgets[i].kind == EL_WIDGET_FREE) { + _el_widgets[i].kind = kind; + _el_widgets[i].widget = (GtkWidget*)g_object_ref(w); + _el_widgets[i].cb_click = NULL; + _el_widgets[i].cb_change = NULL; + if (i > _el_widget_count) _el_widget_count = i; + return (int64_t)i; + } + } + return -1; +} + +/* + * el_widget_prealloc — reserve a slot without a GTK widget (pre-activation). + * The slot kind is set; widget remains NULL until el_widget_install() fills it. + * Returns the reserved slot index, or -1 if full. + */ +static int64_t el_widget_prealloc(ElWidgetKind kind) { + for (int i = 1; i < EL_GTK4_MAX_WIDGETS; i++) { + if (_el_widgets[i].kind == EL_WIDGET_FREE) { + _el_widgets[i].kind = kind; + _el_widgets[i].widget = NULL; + _el_widgets[i].cb_click = NULL; + _el_widgets[i].cb_change = NULL; + if (i > _el_widget_count) _el_widget_count = i; + return (int64_t)i; + } + } + return -1; +} + +/* + * el_widget_install — install a GTK widget into a pre-allocated slot. + * Takes a strong ref on w. + */ +static void el_widget_install(int64_t slot, GtkWidget* w) { + if (slot <= 0 || slot >= EL_GTK4_MAX_WIDGETS) return; + if (_el_widgets[slot].widget) g_object_unref(_el_widgets[slot].widget); + _el_widgets[slot].widget = (GtkWidget*)g_object_ref(w); +} + +/* Look up a slot. Returns NULL for invalid/free handle. */ +static ElWidget* el_widget_get(int64_t handle) { + if (handle <= 0 || handle >= EL_GTK4_MAX_WIDGETS) return NULL; + if (_el_widgets[handle].kind == EL_WIDGET_FREE) return NULL; + return &_el_widgets[handle]; +} + +/* Release a slot. Unrefs the widget; callers must remove from parent first. */ +static void el_widget_free(int64_t handle) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + if (w->widget) { g_object_unref(w->widget); w->widget = NULL; } + w->kind = EL_WIDGET_FREE; + free(w->cb_click); w->cb_click = NULL; + free(w->cb_change); w->cb_change = NULL; +} + +/* ── Deferred operation queue ─────────────────────────────────────────────── */ +/* + * Before el_gtk4_run_loop() starts g_application_run(), the GTK display is not + * yet initialized. All el_gtk4_* calls are recorded as deferred ops and + * replayed from the activate handler after the display is ready. + * + * Each deferred op is { fn, data } where fn is a _main-style function and data + * is a heap-allocated copy of the arguments. The _main functions are called + * exactly as they would be post-activation. + * + * Creation functions (window_create, label_create, etc.) pre-allocate a slot + * via el_widget_prealloc() before recording the deferred op. The slot index is + * returned immediately to the el program. The _main function receives the + * pre-allocated slot as part of its arg struct and calls el_widget_install() + * rather than el_widget_alloc(). + */ + +#define EL_DEFERRED_MAX 8192 + +typedef struct { + void (*fn)(void*); + void* data; +} ElDeferredOp; + +static ElDeferredOp _el_deferred[EL_DEFERRED_MAX]; +static int _el_deferred_count = 0; + +/* Queue a deferred op. data must be heap-allocated (will be free()'d after replay). */ +static void el_defer(void (*fn)(void*), void* data) { + if (_el_deferred_count >= EL_DEFERRED_MAX) { + fprintf(stderr, "el_gtk4: deferred op queue full\n"); + return; + } + _el_deferred[_el_deferred_count].fn = fn; + _el_deferred[_el_deferred_count].data = data; + _el_deferred_count++; +} + +/* Replay all deferred ops in order. Called from the activate handler. */ +static void el_deferred_replay(void) { + for (int i = 0; i < _el_deferred_count; i++) { + _el_deferred[i].fn(_el_deferred[i].data); + free(_el_deferred[i].data); + } + _el_deferred_count = 0; +} + +/* ── GtkApplication (global) ─────────────────────────────────────────────── */ + +static GtkApplication* _el_app = NULL; +static int _el_app_running = 0; /* 1 after activate fires */ + +/* ── CSS / styling helpers ────────────────────────────────────────────────── */ + +/* + * apply_css — attach a CSS snippet to a single widget with APPLICATION priority. + * GTK 4.10 deprecated gtk_widget_get_style_context(); use gtk_widget_add_css_class() + * + a display-level provider for new GTK, or the style-context path for older GTK. + * + * We use the style-context path behind a version guard because it reliably + * scopes the CSS to just this widget, which is what the el property setters + * need (each call replaces/adds to the widget's own stylesheet). + */ +static void apply_css(GtkWidget* widget, const char* css_str) { + if (!widget || !css_str) return; + GtkCssProvider* p = gtk_css_provider_new(); + +#if GTK_CHECK_VERSION(4, 12, 0) + /* GTK 4.12+: load_from_string takes a plain string (no length). */ + gtk_css_provider_load_from_string(p, css_str); +#else + gtk_css_provider_load_from_data(p, css_str, -1); +#endif + +#if GTK_MINOR_VERSION >= 10 + /* 4.10+: style context is deprecated; use display-scoped provider + css class. + * We add a unique widget name so the selector targets only this widget. */ + static guint64 _css_id_counter = 0; + char name_buf[32]; + snprintf(name_buf, sizeof(name_buf), "el-w-%" G_GUINT64_FORMAT, ++_css_id_counter); + gtk_widget_set_name(widget, name_buf); + + /* Wrap the CSS to scope to this widget's name. */ + char* scoped = NULL; + int n = asprintf(&scoped, "#%s { %s }", name_buf, css_str); + (void)n; + if (scoped) { + GtkCssProvider* sp = gtk_css_provider_new(); +#if GTK_CHECK_VERSION(4, 12, 0) + gtk_css_provider_load_from_string(sp, scoped); +#else + gtk_css_provider_load_from_data(sp, scoped, -1); +#endif + gtk_style_context_add_provider_for_display( + gtk_widget_get_display(widget), + GTK_STYLE_PROVIDER(sp), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_object_unref(sp); + free(scoped); + } + g_object_unref(p); +#else + /* GTK < 4.10: style context is available and widget-scoped. */ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + gtk_style_context_add_provider( + gtk_widget_get_style_context(widget), + GTK_STYLE_PROVIDER(p), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + G_GNUC_END_IGNORE_DEPRECATIONS + g_object_unref(p); +#endif +} + +/* ── Main-thread dispatch ────────────────────────────────────────────────── */ + +/* + * Dispatch a function on the GTK main thread, blocking until it completes. + * If already on the main thread, calls the function directly. + * + * Use a GMainContext + GMutex/GCond pair so we can synchronously wait for + * the idle callback to execute, mirroring dispatch_sync(main_queue, ...). + * + * NOTE: only called post-activation. Pre-activation calls go through el_defer(). + */ + +typedef struct { + void (*fn)(void*); + void* data; + GMutex mutex; + GCond cond; + int done; +} ElSyncCall; + +static gboolean _el_sync_dispatch(gpointer user_data) { + ElSyncCall* call = (ElSyncCall*)user_data; + call->fn(call->data); + g_mutex_lock(&call->mutex); + call->done = 1; + g_cond_signal(&call->cond); + g_mutex_unlock(&call->mutex); + return G_SOURCE_REMOVE; +} + +static void el_gtk4_sync_main(void (*fn)(void*), void* data) { + /* Check if we're already on the thread running the default main context. */ + GMainContext* main_ctx = g_main_context_default(); + if (g_main_context_is_owner(main_ctx)) { + fn(data); + return; + } + ElSyncCall call; + call.fn = fn; + call.data = data; + call.done = 0; + g_mutex_init(&call.mutex); + g_cond_init(&call.cond); + + g_main_context_invoke(main_ctx, _el_sync_dispatch, &call); + + g_mutex_lock(&call.mutex); + while (!call.done) { + g_cond_wait(&call.cond, &call.mutex); + } + g_mutex_unlock(&call.mutex); + g_mutex_clear(&call.mutex); + g_cond_clear(&call.cond); +} + +/* ── El callback invocation ──────────────────────────────────────────────── */ + +/* + * El callback functions have signature (per el_seed.c conventions): + * void fn_name(int64_t handle, int64_t data) + * where data is a (const char*) cast to int64_t — same as AppKit bridge. + */ +typedef void (*ElCb2)(int64_t handle, int64_t data); + +static void el_gtk4_invoke_cb(const char* fn_name, int64_t handle, + const char* data) { + if (!fn_name || !*fn_name) return; + void* sym = dlsym(RTLD_DEFAULT, fn_name); + if (!sym) return; + ElCb2 fn = (ElCb2)sym; + fn(handle, (int64_t)(uintptr_t)(data ? data : "")); +} + +/* ── Signal callbacks ────────────────────────────────────────────────────── */ + +/* Slot index stored as widget data so signal handlers can look it up. */ +#define EL_SLOT_KEY "el-slot" + +static void _el_on_button_clicked(GtkButton* btn, gpointer user_data) { + (void)btn; + int64_t slot = (int64_t)(intptr_t)user_data; + ElWidget* w = el_widget_get(slot); + if (w && w->cb_click) { + el_gtk4_invoke_cb(w->cb_click, slot, ""); + } +} + +static void _el_on_entry_changed(GtkEditable* editable, gpointer user_data) { + int64_t slot = (int64_t)(intptr_t)user_data; + ElWidget* w = el_widget_get(slot); + if (w && w->cb_change) { + const char* text = gtk_editable_get_text(editable); + el_gtk4_invoke_cb(w->cb_change, slot, text ? text : ""); + } +} + +static void _el_on_entry_activate(GtkEntry* entry, gpointer user_data) { + (void)entry; + int64_t slot = (int64_t)(intptr_t)user_data; + ElWidget* w = el_widget_get(slot); + if (w && w->cb_click) { + const char* text = gtk_editable_get_text(GTK_EDITABLE(entry)); + el_gtk4_invoke_cb(w->cb_click, slot, text ? text : ""); + } +} + +/* GtkTextBuffer "changed" signal for textarea. */ +static void _el_on_textbuffer_changed(GtkTextBuffer* buf, gpointer user_data) { + int64_t slot = (int64_t)(intptr_t)user_data; + ElWidget* w = el_widget_get(slot); + if (!w || !w->cb_change) return; + GtkTextIter start, end; + gtk_text_buffer_get_bounds(buf, &start, &end); + char* text = gtk_text_buffer_get_text(buf, &start, &end, FALSE); + el_gtk4_invoke_cb(w->cb_change, slot, text ? text : ""); + g_free(text); +} + +/* + * _el_on_close_request — prevent spurious window-close events on macOS. + * + * On macOS, the GTK4 Quartz backend sends windowShouldClose: messages to + * GtkApplicationWindows when the app is launched from a terminal or when + * NSApplication sends automatic hide/close notifications. These arrive as + * close-request signals and would cause the app to exit prematurely. + * + * Returning TRUE from close-request tells GTK to NOT destroy the window. + * This is correct default behavior for el apps — windows stay open until + * the el program explicitly destroys them or the process exits. + * + * If the el program needs user-closeable windows, it can connect its own + * close-request handler (registered after this one) that returns FALSE to + * allow the close. + */ +static gboolean _el_on_close_request(GtkWindow* window, gpointer user_data) { + (void)window; (void)user_data; + /* Return TRUE: prevent the default close/destroy action. */ + return TRUE; +} + +/* ── GtkApplication activate callback ───────────────────────────────────── */ + +static void _el_app_activate(GtkApplication* app, gpointer user_data) { + /* + * Replay all deferred widget operations. These are the window/widget + * creation calls made during the el boot sequence before native_run_loop(). + * The display is now initialized, so GTK APIs are safe. + * + * g_application_hold() prevents the GApplication from auto-quitting when + * there are temporarily no open windows (e.g., during the replay phase + * before gtk_window_present is called on the first window). + */ + (void)user_data; + /* + * Hold the GApplication during replay to prevent auto-quit if there are + * temporarily no windows between the start of replay and gtk_window_present. + */ + g_application_hold(G_APPLICATION(app)); + _el_app_running = 1; + el_deferred_replay(); + g_application_release(G_APPLICATION(app)); +} + +/* ── Public C API ─────────────────────────────────────────────────────────── */ + +/* + * el_gtk4_init — initialize GTK4 + GtkApplication. Idempotent. + * Must be called once before any other el_gtk4_* function. + */ +void el_gtk4_init(void) { + static int done = 0; + if (done) return; + done = 1; + + _el_app = gtk_application_new("ai.neuralplatform.el", G_APPLICATION_DEFAULT_FLAGS); + g_signal_connect(_el_app, "activate", G_CALLBACK(_el_app_activate), NULL); +} + +/* + * el_gtk4_run_loop — start the GTK main loop. Never returns. + * el code calls __native_run_loop() which dispatches here. + * + * On macOS the GTK4 Quartz backend requires g_application_run() on the main + * thread. The el boot sequence runs on the main thread, so this call is always + * from the main thread. The deferred queue mechanism handles the fact that all + * widget creation occurred before this call. + */ +void el_gtk4_run_loop(void) { + if (!_el_app) el_gtk4_init(); + int status = g_application_run(G_APPLICATION(_el_app), 0, NULL); + (void)status; +} + +/* ── Window ───────────────────────────────────────────────────────────────── */ + +typedef struct { + const char* title; + int width, height, min_width, min_height; + int64_t slot; /* pre-allocated slot; _main installs widget here */ +} _ElWindowCreateArgs; + +static void _el_window_create_main(void* vp) { + _ElWindowCreateArgs* a = (_ElWindowCreateArgs*)vp; + GtkWidget* win = gtk_application_window_new(_el_app); + gtk_window_set_title(GTK_WINDOW(win), a->title ? a->title : ""); + gtk_window_set_default_size(GTK_WINDOW(win), a->width, a->height); + + /* Set minimum size via content-area size hint. */ + if (a->min_width > 0 || a->min_height > 0) { + gtk_widget_set_size_request(win, a->min_width, a->min_height); + } + + /* Use a vertical GtkBox as the root content widget so children stack + * vertically by default — mirrors the NSStackView root in AppKit. */ + GtkWidget* root = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_window_set_child(GTK_WINDOW(win), root); + + if (a->slot >= 0) { + el_widget_install(a->slot, win); + g_object_unref(win); /* el_widget_install took a ref */ + } + /* Connect close-request handler to prevent macOS GTK4 Quartz auto-close. */ + g_signal_connect(win, "close-request", + G_CALLBACK(_el_on_close_request), NULL); +} + +int64_t el_gtk4_window_create(const char* title, int width, int height, + int min_width, int min_height) { + int64_t slot = el_widget_prealloc(EL_WIDGET_WINDOW); + if (!_el_app_running) { + _ElWindowCreateArgs* a = malloc(sizeof(_ElWindowCreateArgs)); + a->title = title ? strdup(title) : NULL; + a->width = width; + a->height = height; + a->min_width = min_width; + a->min_height = min_height; + a->slot = slot; + el_defer(_el_window_create_main, a); + } else { + _ElWindowCreateArgs a = { title, width, height, min_width, min_height, slot }; + el_gtk4_sync_main(_el_window_create_main, &a); + } + return slot; +} + +typedef struct { int64_t handle; } _ElHandleArgs; + +static void _el_window_show_main(void* vp) { + _ElHandleArgs* a = (_ElHandleArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || w->kind != EL_WIDGET_WINDOW || !w->widget) return; + gtk_window_present(GTK_WINDOW(w->widget)); +} + +void el_gtk4_window_show(int64_t handle) { + if (!_el_app_running) { + _ElHandleArgs* a = malloc(sizeof(_ElHandleArgs)); + a->handle = handle; + el_defer(_el_window_show_main, a); + } else { + _ElHandleArgs a = { handle }; + el_gtk4_sync_main(_el_window_show_main, &a); + } +} + +typedef struct { int64_t handle; char* title; } _ElSetTitleArgs; + +static void _el_window_set_title_main(void* vp) { + _ElSetTitleArgs* a = (_ElSetTitleArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || w->kind != EL_WIDGET_WINDOW || !w->widget) return; + gtk_window_set_title(GTK_WINDOW(w->widget), a->title ? a->title : ""); +} + +void el_gtk4_window_set_title(int64_t handle, const char* title) { + if (!_el_app_running) { + _ElSetTitleArgs* a = malloc(sizeof(_ElSetTitleArgs)); + a->handle = handle; + a->title = title ? strdup(title) : NULL; + el_defer(_el_window_set_title_main, a); + } else { + _ElSetTitleArgs a = { handle, (char*)title }; + el_gtk4_sync_main(_el_window_set_title_main, &a); + } +} + +/* ── Layout containers ───────────────────────────────────────────────────── */ + +typedef struct { + GtkOrientation orient; + int spacing; + int64_t slot; +} _ElStackCreateArgs; + +static void _el_stack_create_main(void* vp) { + _ElStackCreateArgs* a = (_ElStackCreateArgs*)vp; + GtkWidget* box = gtk_box_new(a->orient, a->spacing); + if (a->slot >= 0) { + el_widget_install(a->slot, box); + g_object_unref(box); + } +} + +int64_t el_gtk4_vstack_create(int spacing) { + int64_t slot = el_widget_prealloc(EL_WIDGET_VSTACK); + if (!_el_app_running) { + _ElStackCreateArgs* a = malloc(sizeof(_ElStackCreateArgs)); + a->orient = GTK_ORIENTATION_VERTICAL; + a->spacing = spacing; + a->slot = slot; + el_defer(_el_stack_create_main, a); + } else { + _ElStackCreateArgs a = { GTK_ORIENTATION_VERTICAL, spacing, slot }; + el_gtk4_sync_main(_el_stack_create_main, &a); + } + return slot; +} + +int64_t el_gtk4_hstack_create(int spacing) { + int64_t slot = el_widget_prealloc(EL_WIDGET_HSTACK); + if (!_el_app_running) { + _ElStackCreateArgs* a = malloc(sizeof(_ElStackCreateArgs)); + a->orient = GTK_ORIENTATION_HORIZONTAL; + a->spacing = spacing; + a->slot = slot; + el_defer(_el_stack_create_main, a); + } else { + _ElStackCreateArgs a = { GTK_ORIENTATION_HORIZONTAL, spacing, slot }; + el_gtk4_sync_main(_el_stack_create_main, &a); + } + return slot; +} + +typedef struct { int64_t slot; } _ElSlotArgs; + +static void _el_zstack_create_main(void* vp) { + _ElSlotArgs* a = (_ElSlotArgs*)vp; + GtkWidget* overlay = gtk_overlay_new(); + if (a->slot >= 0) { el_widget_install(a->slot, overlay); g_object_unref(overlay); } +} + +int64_t el_gtk4_zstack_create(void) { + int64_t slot = el_widget_prealloc(EL_WIDGET_ZSTACK); + if (!_el_app_running) { + _ElSlotArgs* a = malloc(sizeof(_ElSlotArgs)); a->slot = slot; + el_defer(_el_zstack_create_main, a); + } else { + _ElSlotArgs a = { slot }; + el_gtk4_sync_main(_el_zstack_create_main, &a); + } + return slot; +} + +static void _el_scroll_create_main(void* vp) { + _ElSlotArgs* a = (_ElSlotArgs*)vp; + GtkWidget* sw = gtk_scrolled_window_new(); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + if (a->slot >= 0) { el_widget_install(a->slot, sw); g_object_unref(sw); } +} + +int64_t el_gtk4_scroll_create(void) { + int64_t slot = el_widget_prealloc(EL_WIDGET_SCROLL); + if (!_el_app_running) { + _ElSlotArgs* a = malloc(sizeof(_ElSlotArgs)); a->slot = slot; + el_defer(_el_scroll_create_main, a); + } else { + _ElSlotArgs a = { slot }; + el_gtk4_sync_main(_el_scroll_create_main, &a); + } + return slot; +} + +/* ── Widget factories ─────────────────────────────────────────────────────── */ + +typedef struct { char* text; int64_t slot; } _ElTextSlotArgs; + +static void _el_label_create_main(void* vp) { + _ElTextSlotArgs* a = (_ElTextSlotArgs*)vp; + GtkWidget* lbl = gtk_label_new(a->text ? a->text : ""); + gtk_label_set_xalign(GTK_LABEL(lbl), 0.0f); + gtk_label_set_wrap(GTK_LABEL(lbl), FALSE); + if (a->slot >= 0) { el_widget_install(a->slot, lbl); g_object_unref(lbl); } +} + +int64_t el_gtk4_label_create(const char* text) { + int64_t slot = el_widget_prealloc(EL_WIDGET_LABEL); + if (!_el_app_running) { + _ElTextSlotArgs* a = malloc(sizeof(_ElTextSlotArgs)); + a->text = text ? strdup(text) : NULL; a->slot = slot; + el_defer(_el_label_create_main, a); + } else { + _ElTextSlotArgs a = { (char*)text, slot }; + el_gtk4_sync_main(_el_label_create_main, &a); + } + return slot; +} + +static void _el_button_create_main(void* vp) { + _ElTextSlotArgs* a = (_ElTextSlotArgs*)vp; + GtkWidget* btn = gtk_button_new_with_label(a->text ? a->text : ""); + if (a->slot >= 0) { + el_widget_install(a->slot, btn); + g_object_unref(btn); + g_signal_connect(btn, "clicked", + G_CALLBACK(_el_on_button_clicked), + (gpointer)(intptr_t)a->slot); + } +} + +int64_t el_gtk4_button_create(const char* label) { + int64_t slot = el_widget_prealloc(EL_WIDGET_BUTTON); + if (!_el_app_running) { + _ElTextSlotArgs* a = malloc(sizeof(_ElTextSlotArgs)); + a->text = label ? strdup(label) : NULL; a->slot = slot; + el_defer(_el_button_create_main, a); + } else { + _ElTextSlotArgs a = { (char*)label, slot }; + el_gtk4_sync_main(_el_button_create_main, &a); + } + return slot; +} + +static void _el_text_field_create_main(void* vp) { + _ElTextSlotArgs* a = (_ElTextSlotArgs*)vp; + GtkWidget* entry = gtk_entry_new(); + if (a->text && *a->text) { + gtk_entry_set_placeholder_text(GTK_ENTRY(entry), a->text); + } + if (a->slot >= 0) { + el_widget_install(a->slot, entry); + g_object_unref(entry); + gpointer slot_ptr = (gpointer)(intptr_t)a->slot; + g_signal_connect(entry, "changed", + G_CALLBACK(_el_on_entry_changed), slot_ptr); + g_signal_connect(entry, "activate", + G_CALLBACK(_el_on_entry_activate), slot_ptr); + } +} + +int64_t el_gtk4_text_field_create(const char* placeholder) { + int64_t slot = el_widget_prealloc(EL_WIDGET_TEXTFIELD); + if (!_el_app_running) { + _ElTextSlotArgs* a = malloc(sizeof(_ElTextSlotArgs)); + a->text = placeholder ? strdup(placeholder) : NULL; a->slot = slot; + el_defer(_el_text_field_create_main, a); + } else { + _ElTextSlotArgs a = { (char*)placeholder, slot }; + el_gtk4_sync_main(_el_text_field_create_main, &a); + } + return slot; +} + +static void _el_text_area_create_main(void* vp) { + _ElTextSlotArgs* a = (_ElTextSlotArgs*)vp; + GtkWidget* sw = gtk_scrolled_window_new(); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_widget_set_vexpand(sw, TRUE); + + GtkWidget* tv = gtk_text_view_new(); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tv), GTK_WRAP_WORD_CHAR); + gtk_widget_set_hexpand(tv, TRUE); + gtk_widget_set_vexpand(tv, TRUE); + + /* GTK4 GtkTextView has no native placeholder; set accessible description. */ + if (a->text && *a->text) { + gtk_accessible_update_property(GTK_ACCESSIBLE(tv), + GTK_ACCESSIBLE_PROPERTY_PLACEHOLDER, a->text, -1); + } + + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), tv); + + if (a->slot >= 0) { + el_widget_install(a->slot, sw); + g_object_unref(sw); + GtkTextBuffer* buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tv)); + g_signal_connect(buf, "changed", + G_CALLBACK(_el_on_textbuffer_changed), + (gpointer)(intptr_t)a->slot); + } +} + +int64_t el_gtk4_text_area_create(const char* placeholder) { + int64_t slot = el_widget_prealloc(EL_WIDGET_TEXTAREA); + if (!_el_app_running) { + _ElTextSlotArgs* a = malloc(sizeof(_ElTextSlotArgs)); + a->text = placeholder ? strdup(placeholder) : NULL; a->slot = slot; + el_defer(_el_text_area_create_main, a); + } else { + _ElTextSlotArgs a = { (char*)placeholder, slot }; + el_gtk4_sync_main(_el_text_area_create_main, &a); + } + return slot; +} + +static void _el_image_create_main(void* vp) { + _ElTextSlotArgs* a = (_ElTextSlotArgs*)vp; + GtkWidget* img = NULL; + if (a->text && *a->text) { + /* Try as a filesystem path first. */ + if (g_file_test(a->text, G_FILE_TEST_EXISTS)) { + img = gtk_picture_new_for_filename(a->text); + } + if (!img) { + /* Fall back to icon name. */ + img = gtk_image_new_from_icon_name(a->text); + } + } + if (!img) { + img = gtk_picture_new(); + } + if (a->slot >= 0) { el_widget_install(a->slot, img); g_object_unref(img); } +} + +int64_t el_gtk4_image_create(const char* path_or_name) { + int64_t slot = el_widget_prealloc(EL_WIDGET_IMAGE); + if (!_el_app_running) { + _ElTextSlotArgs* a = malloc(sizeof(_ElTextSlotArgs)); + a->text = path_or_name ? strdup(path_or_name) : NULL; a->slot = slot; + el_defer(_el_image_create_main, a); + } else { + _ElTextSlotArgs a = { (char*)path_or_name, slot }; + el_gtk4_sync_main(_el_image_create_main, &a); + } + return slot; +} + +/* ── Widget property setters ─────────────────────────────────────────────── */ + +typedef struct { int64_t handle; char* text; } _ElWidgetTextArgs; + +static void _el_widget_set_text_main(void* vp) { + _ElWidgetTextArgs* a = (_ElWidgetTextArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || !w->widget) return; + const char* s = a->text ? a->text : ""; + switch (w->kind) { + case EL_WIDGET_LABEL: + gtk_label_set_text(GTK_LABEL(w->widget), s); + break; + case EL_WIDGET_TEXTFIELD: + gtk_editable_set_text(GTK_EDITABLE(w->widget), s); + break; + case EL_WIDGET_BUTTON: + gtk_button_set_label(GTK_BUTTON(w->widget), s); + break; + case EL_WIDGET_TEXTAREA: { + GtkWidget* tv = gtk_scrolled_window_get_child( + GTK_SCROLLED_WINDOW(w->widget)); + if (tv && GTK_IS_TEXT_VIEW(tv)) { + GtkTextBuffer* buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tv)); + gtk_text_buffer_set_text(buf, s, -1); + } + break; + } + case EL_WIDGET_WINDOW: + gtk_window_set_title(GTK_WINDOW(w->widget), s); + break; + default: break; + } +} + +void el_gtk4_widget_set_text(int64_t handle, const char* text) { + if (!_el_app_running) { + _ElWidgetTextArgs* a = malloc(sizeof(_ElWidgetTextArgs)); + a->handle = handle; a->text = text ? strdup(text) : NULL; + el_defer(_el_widget_set_text_main, a); + } else { + _ElWidgetTextArgs a = { handle, (char*)text }; + el_gtk4_sync_main(_el_widget_set_text_main, &a); + } +} + +typedef struct { int64_t handle; const char* result; } _ElWidgetGetTextArgs; + +static void _el_widget_get_text_main(void* vp) { + _ElWidgetGetTextArgs* a = (_ElWidgetGetTextArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || !w->widget) { a->result = ""; return; } + switch (w->kind) { + case EL_WIDGET_LABEL: + a->result = gtk_label_get_text(GTK_LABEL(w->widget)); + break; + case EL_WIDGET_TEXTFIELD: + a->result = gtk_editable_get_text(GTK_EDITABLE(w->widget)); + break; + case EL_WIDGET_BUTTON: + a->result = gtk_button_get_label(GTK_BUTTON(w->widget)); + break; + case EL_WIDGET_TEXTAREA: { + GtkWidget* tv = gtk_scrolled_window_get_child( + GTK_SCROLLED_WINDOW(w->widget)); + if (tv && GTK_IS_TEXT_VIEW(tv)) { + GtkTextBuffer* buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tv)); + GtkTextIter start, end; + gtk_text_buffer_get_bounds(buf, &start, &end); + /* Returns g_malloc'd string — caller treats it as short-lived. */ + a->result = gtk_text_buffer_get_text(buf, &start, &end, FALSE); + } else { + a->result = ""; + } + break; + } + default: + a->result = ""; + break; + } +} + +const char* el_gtk4_widget_get_text(int64_t handle) { + _ElWidgetGetTextArgs a = { handle, "" }; + el_gtk4_sync_main(_el_widget_get_text_main, &a); + return a.result ? strdup(a.result) : strdup(""); +} + +typedef struct { + int64_t handle; + float r, g, b, a; +} _ElColorArgs; + +static void _el_widget_set_color_main(void* vp) { + _ElColorArgs* a = (_ElColorArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || !w->widget) return; + char css[128]; + snprintf(css, sizeof(css), "color: rgba(%d,%d,%d,%.3f);", + (int)(a->r * 255.0f), (int)(a->g * 255.0f), + (int)(a->b * 255.0f), (double)a->a); + apply_css(w->widget, css); +} + +void el_gtk4_widget_set_color(int64_t handle, float r, float g, float b, float a) { + if (!_el_app_running) { + _ElColorArgs* args = malloc(sizeof(_ElColorArgs)); + *args = ((_ElColorArgs){ handle, r, g, b, a }); + el_defer(_el_widget_set_color_main, args); + } else { + _ElColorArgs args = { handle, r, g, b, a }; + el_gtk4_sync_main(_el_widget_set_color_main, &args); + } +} + +static void _el_widget_set_bg_color_main(void* vp) { + _ElColorArgs* a = (_ElColorArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || !w->widget || w->kind == EL_WIDGET_WINDOW) return; + char css[128]; + snprintf(css, sizeof(css), "background-color: rgba(%d,%d,%d,%.3f);", + (int)(a->r * 255.0f), (int)(a->g * 255.0f), + (int)(a->b * 255.0f), (double)a->a); + apply_css(w->widget, css); +} + +void el_gtk4_widget_set_bg_color(int64_t handle, float r, float g, float b, float a) { + if (!_el_app_running) { + _ElColorArgs* args = malloc(sizeof(_ElColorArgs)); + *args = ((_ElColorArgs){ handle, r, g, b, a }); + el_defer(_el_widget_set_bg_color_main, args); + } else { + _ElColorArgs args = { handle, r, g, b, a }; + el_gtk4_sync_main(_el_widget_set_bg_color_main, &args); + } +} + +typedef struct { + int64_t handle; + char* family; + int size; + int bold; +} _ElFontArgs; + +static void _el_widget_set_font_main(void* vp) { + _ElFontArgs* a = (_ElFontArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || !w->widget) return; + char css[256]; + const char* fam = (a->family && *a->family && strcmp(a->family, "system") != 0) + ? a->family : "sans-serif"; + snprintf(css, sizeof(css), + "font-family: %s; font-size: %dpx; font-weight: %s;", + fam, a->size, a->bold ? "bold" : "normal"); + apply_css(w->widget, css); +} + +void el_gtk4_widget_set_font(int64_t handle, const char* family, int size, int bold) { + if (!_el_app_running) { + _ElFontArgs* a = malloc(sizeof(_ElFontArgs)); + a->handle = handle; a->family = family ? strdup(family) : NULL; + a->size = size; a->bold = bold; + el_defer(_el_widget_set_font_main, a); + } else { + _ElFontArgs a = { handle, (char*)family, size, bold }; + el_gtk4_sync_main(_el_widget_set_font_main, &a); + } +} + +typedef struct { int64_t handle; int top, right, bottom, left; } _ElPaddingArgs; + +static void _el_widget_set_padding_main(void* vp) { + _ElPaddingArgs* a = (_ElPaddingArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || !w->widget) return; + char css[128]; + snprintf(css, sizeof(css), "padding: %dpx %dpx %dpx %dpx;", + a->top, a->right, a->bottom, a->left); + apply_css(w->widget, css); +} + +void el_gtk4_widget_set_padding(int64_t handle, int top, int right, int bottom, int left) { + if (!_el_app_running) { + _ElPaddingArgs* a = malloc(sizeof(_ElPaddingArgs)); + *a = ((_ElPaddingArgs){ handle, top, right, bottom, left }); + el_defer(_el_widget_set_padding_main, a); + } else { + _ElPaddingArgs a = { handle, top, right, bottom, left }; + el_gtk4_sync_main(_el_widget_set_padding_main, &a); + } +} + +typedef struct { int64_t handle; int value; } _ElIntPropArgs; + +static void _el_widget_set_width_main(void* vp) { + _ElIntPropArgs* a = (_ElIntPropArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || !w->widget || w->kind == EL_WIDGET_WINDOW) return; + gint cur_h = -1; + gtk_widget_get_size_request(w->widget, NULL, &cur_h); + gtk_widget_set_size_request(w->widget, a->value, cur_h); +} + +void el_gtk4_widget_set_width(int64_t handle, int width) { + if (!_el_app_running) { + _ElIntPropArgs* a = malloc(sizeof(_ElIntPropArgs)); + a->handle = handle; a->value = width; + el_defer(_el_widget_set_width_main, a); + } else { + _ElIntPropArgs a = { handle, width }; + el_gtk4_sync_main(_el_widget_set_width_main, &a); + } +} + +static void _el_widget_set_height_main(void* vp) { + _ElIntPropArgs* a = (_ElIntPropArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || !w->widget || w->kind == EL_WIDGET_WINDOW) return; + gint cur_w = -1; + gtk_widget_get_size_request(w->widget, &cur_w, NULL); + gtk_widget_set_size_request(w->widget, cur_w, a->value); +} + +void el_gtk4_widget_set_height(int64_t handle, int height) { + if (!_el_app_running) { + _ElIntPropArgs* a = malloc(sizeof(_ElIntPropArgs)); + a->handle = handle; a->value = height; + el_defer(_el_widget_set_height_main, a); + } else { + _ElIntPropArgs a = { handle, height }; + el_gtk4_sync_main(_el_widget_set_height_main, &a); + } +} + +static void _el_widget_set_flex_main(void* vp) { + _ElIntPropArgs* a = (_ElIntPropArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || !w->widget || w->kind == EL_WIDGET_WINDOW) return; + gboolean expand = (a->value > 0) ? TRUE : FALSE; + gtk_widget_set_hexpand(w->widget, expand); + gtk_widget_set_vexpand(w->widget, expand); +} + +void el_gtk4_widget_set_flex(int64_t handle, int flex) { + if (!_el_app_running) { + _ElIntPropArgs* a = malloc(sizeof(_ElIntPropArgs)); + a->handle = handle; a->value = flex; + el_defer(_el_widget_set_flex_main, a); + } else { + _ElIntPropArgs a = { handle, flex }; + el_gtk4_sync_main(_el_widget_set_flex_main, &a); + } +} + +static void _el_widget_set_corner_radius_main(void* vp) { + _ElIntPropArgs* a = (_ElIntPropArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || !w->widget || w->kind == EL_WIDGET_WINDOW) return; + char css[64]; + snprintf(css, sizeof(css), "border-radius: %dpx;", a->value); + apply_css(w->widget, css); +} + +void el_gtk4_widget_set_corner_radius(int64_t handle, int radius) { + if (!_el_app_running) { + _ElIntPropArgs* a = malloc(sizeof(_ElIntPropArgs)); + a->handle = handle; a->value = radius; + el_defer(_el_widget_set_corner_radius_main, a); + } else { + _ElIntPropArgs a = { handle, radius }; + el_gtk4_sync_main(_el_widget_set_corner_radius_main, &a); + } +} + +static void _el_widget_set_disabled_main(void* vp) { + _ElIntPropArgs* a = (_ElIntPropArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || !w->widget) return; + gtk_widget_set_sensitive(w->widget, !a->value); +} + +void el_gtk4_widget_set_disabled(int64_t handle, int disabled) { + if (!_el_app_running) { + _ElIntPropArgs* a = malloc(sizeof(_ElIntPropArgs)); + a->handle = handle; a->value = disabled; + el_defer(_el_widget_set_disabled_main, a); + } else { + _ElIntPropArgs a = { handle, disabled }; + el_gtk4_sync_main(_el_widget_set_disabled_main, &a); + } +} + +static void _el_widget_set_hidden_main(void* vp) { + _ElIntPropArgs* a = (_ElIntPropArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || !w->widget || w->kind == EL_WIDGET_WINDOW) return; + gtk_widget_set_visible(w->widget, !a->value); +} + +void el_gtk4_widget_set_hidden(int64_t handle, int hidden) { + if (!_el_app_running) { + _ElIntPropArgs* a = malloc(sizeof(_ElIntPropArgs)); + a->handle = handle; a->value = hidden; + el_defer(_el_widget_set_hidden_main, a); + } else { + _ElIntPropArgs a = { handle, hidden }; + el_gtk4_sync_main(_el_widget_set_hidden_main, &a); + } +} + +/* ── Child management ─────────────────────────────────────────────────────── */ + +typedef struct { int64_t parent; int64_t child; } _ElParentChildArgs; + +static void _el_widget_add_child_main(void* vp) { + _ElParentChildArgs* a = (_ElParentChildArgs*)vp; + ElWidget* pw = el_widget_get(a->parent); + ElWidget* cw = el_widget_get(a->child); + if (!pw || !cw || !pw->widget || !cw->widget) return; + if (cw->kind == EL_WIDGET_WINDOW) return; /* cannot add a window as child */ + + GtkWidget* child_widget = cw->widget; + + switch (pw->kind) { + case EL_WIDGET_WINDOW: { + /* Append to the root VBox that window_create installs as child. */ + GtkWidget* root = gtk_window_get_child(GTK_WINDOW(pw->widget)); + if (root && GTK_IS_BOX(root)) { + gtk_box_append(GTK_BOX(root), child_widget); + } else { + /* Fallback: replace root child. */ + gtk_window_set_child(GTK_WINDOW(pw->widget), child_widget); + } + break; + } + case EL_WIDGET_VSTACK: + case EL_WIDGET_HSTACK: + gtk_box_append(GTK_BOX(pw->widget), child_widget); + break; + case EL_WIDGET_ZSTACK: + /* First child becomes the base; subsequent children are overlays. */ + if (!gtk_overlay_get_child(GTK_OVERLAY(pw->widget))) { + gtk_overlay_set_child(GTK_OVERLAY(pw->widget), child_widget); + } else { + gtk_overlay_add_overlay(GTK_OVERLAY(pw->widget), child_widget); + } + break; + case EL_WIDGET_SCROLL: + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(pw->widget), + child_widget); + break; + default: + /* Generic fallback — shouldn't be reached for standard widget kinds. */ + break; + } +} + +void el_gtk4_widget_add_child(int64_t parent, int64_t child) { + if (!_el_app_running) { + _ElParentChildArgs* a = malloc(sizeof(_ElParentChildArgs)); + a->parent = parent; a->child = child; + el_defer(_el_widget_add_child_main, a); + } else { + _ElParentChildArgs a = { parent, child }; + el_gtk4_sync_main(_el_widget_add_child_main, &a); + } +} + +static void _el_widget_remove_child_main(void* vp) { + _ElParentChildArgs* a = (_ElParentChildArgs*)vp; + ElWidget* pw = el_widget_get(a->parent); + ElWidget* cw = el_widget_get(a->child); + if (!pw || !cw || !pw->widget || !cw->widget) return; + if (cw->kind == EL_WIDGET_WINDOW) return; + + GtkWidget* child_widget = cw->widget; + + switch (pw->kind) { + case EL_WIDGET_WINDOW: { + GtkWidget* root = gtk_window_get_child(GTK_WINDOW(pw->widget)); + if (root && GTK_IS_BOX(root)) { + gtk_box_remove(GTK_BOX(root), child_widget); + } + break; + } + case EL_WIDGET_VSTACK: + case EL_WIDGET_HSTACK: + gtk_box_remove(GTK_BOX(pw->widget), child_widget); + break; + case EL_WIDGET_ZSTACK: + gtk_overlay_remove_overlay(GTK_OVERLAY(pw->widget), child_widget); + break; + case EL_WIDGET_SCROLL: + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(pw->widget), NULL); + break; + default: + break; + } +} + +void el_gtk4_widget_remove_child(int64_t parent, int64_t child) { + if (!_el_app_running) { + _ElParentChildArgs* a = malloc(sizeof(_ElParentChildArgs)); + a->parent = parent; a->child = child; + el_defer(_el_widget_remove_child_main, a); + } else { + _ElParentChildArgs a = { parent, child }; + el_gtk4_sync_main(_el_widget_remove_child_main, &a); + } +} + +/* ── Event registration ───────────────────────────────────────────────────── */ + +/* + * on_click / on_change / on_submit just store the function name string. + * The actual g_signal_connect calls happen at widget creation time. + * Here we update the stored callback so the already-connected signal handler + * will call the new function name. + * + * These are safe to call pre-activation because they only touch the slot table, + * not GTK objects. We still defer them to ensure ordering with widget creation. + */ + +typedef struct { int64_t handle; char* fn_name; } _ElCbArgs; + +static void _el_widget_on_click_main(void* vp) { + _ElCbArgs* a = (_ElCbArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w) return; + free(w->cb_click); + w->cb_click = (a->fn_name && *a->fn_name) ? strdup(a->fn_name) : NULL; +} + +void el_gtk4_widget_on_click(int64_t handle, const char* fn_name) { + if (!_el_app_running) { + _ElCbArgs* a = malloc(sizeof(_ElCbArgs)); + a->handle = handle; a->fn_name = fn_name ? strdup(fn_name) : NULL; + el_defer(_el_widget_on_click_main, a); + } else { + ElWidget* w = el_widget_get(handle); + if (!w) return; + free(w->cb_click); + w->cb_click = (fn_name && *fn_name) ? strdup(fn_name) : NULL; + } +} + +static void _el_widget_on_change_main(void* vp) { + _ElCbArgs* a = (_ElCbArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w) return; + free(w->cb_change); + w->cb_change = (a->fn_name && *a->fn_name) ? strdup(a->fn_name) : NULL; +} + +void el_gtk4_widget_on_change(int64_t handle, const char* fn_name) { + if (!_el_app_running) { + _ElCbArgs* a = malloc(sizeof(_ElCbArgs)); + a->handle = handle; a->fn_name = fn_name ? strdup(fn_name) : NULL; + el_defer(_el_widget_on_change_main, a); + } else { + ElWidget* w = el_widget_get(handle); + if (!w) return; + free(w->cb_change); + w->cb_change = (fn_name && *fn_name) ? strdup(fn_name) : NULL; + } +} + +void el_gtk4_widget_on_submit(int64_t handle, const char* fn_name) { + /* For text fields, "submit" = Enter key activate → stored in cb_click. */ + el_gtk4_widget_on_click(handle, fn_name); +} + +/* ── Widget destroy ───────────────────────────────────────────────────────── */ + +static void _el_widget_destroy_main(void* vp) { + _ElHandleArgs* a = (_ElHandleArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || !w->widget) return; + if (w->kind == EL_WIDGET_WINDOW) { + gtk_window_destroy(GTK_WINDOW(w->widget)); + } else { + /* Unparent the widget before freeing the slot. */ + GtkWidget* parent = gtk_widget_get_parent(w->widget); + if (parent) { + if (GTK_IS_BOX(parent)) { + gtk_box_remove(GTK_BOX(parent), w->widget); + } else if (GTK_IS_OVERLAY(parent)) { + gtk_overlay_remove_overlay(GTK_OVERLAY(parent), w->widget); + } else if (GTK_IS_SCROLLED_WINDOW(parent)) { + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(parent), NULL); + } + /* gtk_window_get_child case: the parent is a GtkBox inside a window */ + } + } + el_widget_free(a->handle); +} + +void el_gtk4_widget_destroy(int64_t handle) { + if (!_el_app_running) { + _ElHandleArgs* a = malloc(sizeof(_ElHandleArgs)); + a->handle = handle; + el_defer(_el_widget_destroy_main, a); + } else { + _ElHandleArgs a = { handle }; + el_gtk4_sync_main(_el_widget_destroy_main, &a); + } +} + +#endif /* EL_TARGET_LINUX */ diff --git a/lang/el-compiler/runtime/el_lvgl.c b/lang/el-compiler/runtime/el_lvgl.c new file mode 100644 index 0000000..4c3a318 --- /dev/null +++ b/lang/el-compiler/runtime/el_lvgl.c @@ -0,0 +1,844 @@ +/* + * el_lvgl.c — LVGL v9 backend for the el native widget system. + * + * This file implements the microcontroller/embedded widget layer that el_seed.c + * calls through to when EL_TARGET_LVGL is defined. + * + * Architecture: + * el program (el code) + * → __widget_* C builtins in el_seed.c + * → el_lvgl_* C functions defined here + * → lv_obj_t widgets via LVGL v9 + * + * Target platforms: ESP32, STM32, industrial panels, any system with 256KB+ + * RAM and an LVGL-compatible display driver. No OS required. + * + * Widget handles: every widget is assigned an int64_t slot index into + * g_widgets[]. The el program holds these as opaque Int values. + * Slot 0 is reserved; -1 = invalid handle. + * + * Window model: on embedded there is one screen. __window_create configures + * lv_scr_act() as the root container. __window_show is a no-op (the screen + * is always visible). __native_run_loop calls lv_task_handler() in a tight + * loop — on RTOS this runs inside a dedicated task; on bare metal it IS the + * main loop. The host application is responsible for initialising the display + * driver and calling lv_tick_inc() before calling __native_run_loop. + * + * Callback dispatch: + * When EL_LVGL_NO_DLSYM is NOT defined (hosted Linux, testing): + * dlsym(RTLD_DEFAULT, fn_name) resolves the El function symbol at runtime. + * When EL_LVGL_NO_DLSYM IS defined (bare-metal ESP32/STM32): + * The caller must provide: + * el_val_t el_lvgl_dispatch(const char *fn, el_val_t a, el_val_t b); + * which maps function names to function pointers via a compile-time table. + * + * Font mapping: LVGL v9 ships Montserrat in discrete sizes. __widget_set_font + * maps the requested point size to the nearest available Montserrat variant. + * Bold is approximated by stepping up two sizes (no separate bold face in the + * default LVGL font set). Define EL_LVGL_CUSTOM_FONT to override font_select(). + * + * Compile (hosted test build): + * gcc -DEL_TARGET_LVGL -I./lvgl el_lvgl.c -c -o el_lvgl.o + * # Then link with lvgl.a / lvgl source tree. + * + * Compile (bare-metal, no dynamic linker): + * arm-none-eabi-gcc -DEL_TARGET_LVGL -DEL_LVGL_NO_DLSYM \ + * -I./lvgl el_lvgl.c -c -o el_lvgl.o + */ + +#ifdef EL_TARGET_LVGL + +#include "lvgl/lvgl.h" +#include +#include +#include +#include + +#ifndef EL_LVGL_NO_DLSYM +#include +#endif + +#include "el_runtime.h" + +/* ── Callback dispatch macro ─────────────────────────────────────────────── */ + +#ifdef EL_LVGL_NO_DLSYM +/* + * Bare-metal path. The application provides this function: + * el_val_t el_lvgl_dispatch(const char *fn, el_val_t a, el_val_t b); + * It maps string names → function pointers, typically via a switch on a hash + * or a sorted table of {name, fn_ptr} pairs generated by elc. + */ +extern el_val_t el_lvgl_dispatch(const char *fn, el_val_t a, el_val_t b); +#define EL_LVGL_CALL(fn_name, a, b) el_lvgl_dispatch((fn_name), (a), (b)) +#else +/* + * Hosted path. dlsym resolves the El symbol at call time. + * We use a compound-statement expression (GCC/Clang extension) to avoid + * executing dlsym more than once per call. + */ +#define EL_LVGL_CALL(fn_name, a, b) \ + ({ \ + typedef el_val_t (*_el_fn_t)(el_val_t, el_val_t); \ + _el_fn_t _fn = (_el_fn_t)(uintptr_t)dlsym(RTLD_DEFAULT, (fn_name)); \ + _fn ? _fn((a), (b)) : (el_val_t)0; \ + }) +#endif + +/* ── Widget table ─────────────────────────────────────────────────────────── */ + +#define EL_LVGL_MAX_WIDGETS 4096 + +/* + * Widget kinds — mirrors AppKit/GTK4 backends so future tooling can stay + * consistent across all targets. + */ +typedef enum { + EL_LVGL_FREE = 0, + EL_LVGL_WINDOW = 1, + EL_LVGL_VSTACK = 2, + EL_LVGL_HSTACK = 3, + EL_LVGL_ZSTACK = 4, + EL_LVGL_SCROLL = 5, + EL_LVGL_LABEL = 6, + EL_LVGL_BUTTON = 7, /* lv_btn_create; inner label at slot_btn_label */ + EL_LVGL_TEXTFIELD = 8, /* lv_textarea, one-line */ + EL_LVGL_TEXTAREA = 9, /* lv_textarea, multiline */ + EL_LVGL_IMAGE = 10, + EL_LVGL_DIVIDER = 11, + EL_LVGL_SPACER = 12, +} ElLvglKind; + +/* + * Per-slot state. Callback names are stored inline (256 bytes each) to avoid + * heap allocation on targets with no malloc or fragmented heaps. + */ +typedef struct { + ElLvglKind kind; + lv_obj_t *obj; /* primary LVGL object */ + lv_obj_t *btn_label; /* for EL_LVGL_BUTTON: inner lv_label child */ + char cb_click[256]; + char cb_change[256]; + char cb_submit[256]; +} ElLvglWidget; + +static ElLvglWidget g_widgets[EL_LVGL_MAX_WIDGETS]; + +/* ── Slot helpers ─────────────────────────────────────────────────────────── */ + +static int64_t lvgl_slot_alloc(ElLvglKind kind, lv_obj_t *obj) { + for (int i = 1; i < EL_LVGL_MAX_WIDGETS; i++) { + if (g_widgets[i].kind == EL_LVGL_FREE) { + g_widgets[i].kind = kind; + g_widgets[i].obj = obj; + g_widgets[i].btn_label = NULL; + g_widgets[i].cb_click[0] = '\0'; + g_widgets[i].cb_change[0] = '\0'; + g_widgets[i].cb_submit[0] = '\0'; + return (int64_t)i; + } + } + return -1; /* table full */ +} + +static ElLvglWidget *lvgl_slot_get(int64_t handle) { + if (handle <= 0 || handle >= EL_LVGL_MAX_WIDGETS) return NULL; + if (g_widgets[handle].kind == EL_LVGL_FREE) return NULL; + return &g_widgets[handle]; +} + +static void lvgl_slot_free(int64_t handle) { + if (handle <= 0 || handle >= EL_LVGL_MAX_WIDGETS) return; + ElLvglWidget *w = &g_widgets[handle]; + w->kind = EL_LVGL_FREE; + w->obj = NULL; + w->btn_label = NULL; + w->cb_click[0] = '\0'; + w->cb_change[0] = '\0'; + w->cb_submit[0] = '\0'; +} + +/* ── Font selection ───────────────────────────────────────────────────────── */ +/* + * LVGL ships Montserrat in the following sizes (subset enabled by lv_conf.h): + * 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 + * + * We map the requested size to the nearest available size. Bold is + * approximated by stepping up two sizes (no separate bold face in the default + * font set). Define EL_LVGL_CUSTOM_FONT to replace this function entirely. + */ +#ifndef EL_LVGL_CUSTOM_FONT + +static const lv_font_t *font_select(int size, int bold) { + /* Step up two sizes for bold approximation. */ + if (bold) size += 4; + + /* Clamp to available range. */ + if (size < 8) size = 8; + if (size > 48) size = 48; + + /* Round to nearest even size >= 8. */ + if (size % 2 != 0) size++; + + switch (size) { +#if LV_FONT_MONTSERRAT_8 + case 8: return &lv_font_montserrat_8; +#endif +#if LV_FONT_MONTSERRAT_10 + case 10: return &lv_font_montserrat_10; +#endif +#if LV_FONT_MONTSERRAT_12 + case 12: return &lv_font_montserrat_12; +#endif +#if LV_FONT_MONTSERRAT_14 + case 14: return &lv_font_montserrat_14; +#endif +#if LV_FONT_MONTSERRAT_16 + case 16: return &lv_font_montserrat_16; +#endif +#if LV_FONT_MONTSERRAT_18 + case 18: return &lv_font_montserrat_18; +#endif +#if LV_FONT_MONTSERRAT_20 + case 20: return &lv_font_montserrat_20; +#endif +#if LV_FONT_MONTSERRAT_22 + case 22: return &lv_font_montserrat_22; +#endif +#if LV_FONT_MONTSERRAT_24 + case 24: return &lv_font_montserrat_24; +#endif +#if LV_FONT_MONTSERRAT_26 + case 26: return &lv_font_montserrat_26; +#endif +#if LV_FONT_MONTSERRAT_28 + case 28: return &lv_font_montserrat_28; +#endif +#if LV_FONT_MONTSERRAT_30 + case 30: return &lv_font_montserrat_30; +#endif +#if LV_FONT_MONTSERRAT_32 + case 32: return &lv_font_montserrat_32; +#endif +#if LV_FONT_MONTSERRAT_34 + case 34: return &lv_font_montserrat_34; +#endif +#if LV_FONT_MONTSERRAT_36 + case 36: return &lv_font_montserrat_36; +#endif +#if LV_FONT_MONTSERRAT_38 + case 38: return &lv_font_montserrat_38; +#endif +#if LV_FONT_MONTSERRAT_40 + case 40: return &lv_font_montserrat_40; +#endif +#if LV_FONT_MONTSERRAT_42 + case 42: return &lv_font_montserrat_42; +#endif +#if LV_FONT_MONTSERRAT_44 + case 44: return &lv_font_montserrat_44; +#endif +#if LV_FONT_MONTSERRAT_46 + case 46: return &lv_font_montserrat_46; +#endif +#if LV_FONT_MONTSERRAT_48 + case 48: return &lv_font_montserrat_48; +#endif + default: + /* + * Requested size is not compiled in. Fall back to the default + * theme font, which is guaranteed to be present. + */ + return LV_FONT_DEFAULT; + } +} + +#endif /* EL_LVGL_CUSTOM_FONT */ + +/* ── Event callback ───────────────────────────────────────────────────────── */ + +/* + * Single LVGL event callback used for all widget events. The user_data is + * the slot index cast to (void*) via intptr_t — avoids heap allocation. + * + * Three event codes are handled: + * LV_EVENT_CLICKED → cb_click (buttons, any tappable widget) + * LV_EVENT_VALUE_CHANGED → cb_change (textarea, checkbox, etc.) + * LV_EVENT_READY → cb_submit (Enter pressed in textarea one-line mode) + */ +static void el_lvgl_event_cb(lv_event_t *e) { + lv_event_code_t code = lv_event_get_code(e); + intptr_t slot = (intptr_t)lv_event_get_user_data(e); + ElLvglWidget *w = lvgl_slot_get((int64_t)slot); + if (!w) return; + + if (code == LV_EVENT_CLICKED && w->cb_click[0]) { + EL_LVGL_CALL(w->cb_click, (el_val_t)slot, (el_val_t)0); + } + + if (code == LV_EVENT_VALUE_CHANGED && w->cb_change[0]) { + /* + * Retrieve current text for textarea/textfield widgets so the handler + * receives the updated value as its second argument. + */ + const char *txt = ""; + lv_obj_t *target = lv_event_get_target(e); + if (w->kind == EL_LVGL_TEXTFIELD || w->kind == EL_LVGL_TEXTAREA) { + txt = lv_textarea_get_text(target); + if (!txt) txt = ""; + } + EL_LVGL_CALL(w->cb_change, (el_val_t)slot, + (el_val_t)(uintptr_t)txt); + } + + if (code == LV_EVENT_READY && w->cb_submit[0]) { + /* LV_EVENT_READY fires when Enter is pressed in a one-line textarea. */ + EL_LVGL_CALL(w->cb_submit, (el_val_t)slot, (el_val_t)0); + } +} + +/* ── Initialisation ───────────────────────────────────────────────────────── */ + +/* + * el_lvgl_init — call lv_init(). The host must have already initialised the + * display driver and input driver before this, or immediately after. Idempotent. + */ +void el_lvgl_init(void) { + static int done = 0; + if (done) return; + done = 1; + lv_init(); +} + +/* + * el_lvgl_run_loop — drive lv_task_handler() indefinitely. + * + * On RTOS: this function should run inside a dedicated FreeRTOS/Zephyr task. + * On bare metal: call this as the last statement of main(). + * + * The 5 ms delay between handler calls matches the LVGL documentation + * recommendation for a ~200 Hz refresh budget. + * + * On hosted Linux (EL_LVGL_SDL or similar), usleep(5000) is used. On RTOS + * targets define EL_LVGL_RTOS_DELAY(ms) to map to vTaskDelay/k_sleep/etc. + */ +void el_lvgl_run_loop(void) { + for (;;) { + lv_task_handler(); +#if defined(EL_LVGL_RTOS_DELAY) + EL_LVGL_RTOS_DELAY(5); +#elif defined(__linux__) || defined(__APPLE__) + { + /* Hosted test build — usleep available. */ +#include + usleep(5000); + } +#endif + /* Bare-metal without a delay macro: the HAL tick increment loop + * is the caller's responsibility. No sleep needed if lv_tick_inc() + * is driven from a hardware timer ISR. */ + } +} + +/* ── Window ───────────────────────────────────────────────────────────────── */ + +/* + * el_lvgl_window_create — configure lv_scr_act() as a vertical flex container + * and return a slot handle wrapping it. The title is stored for informational + * purposes (e.g., a status bar widget the host might create). Width/height + * are ignored on embedded targets because the screen size is fixed by the + * display driver; they are accepted for API compatibility with other backends. + */ +int64_t el_lvgl_window_create(const char *title, int width, int height, + int min_width, int min_height) { + (void)width; (void)height; (void)min_width; (void)min_height; + + lv_obj_t *scr = lv_scr_act(); + + /* Configure the active screen as a vertical flex container so that + * widgets added via __widget_add_child stack naturally. */ + lv_obj_set_flex_flow(scr, LV_FLEX_FLOW_COLUMN); + lv_obj_set_size(scr, LV_PCT(100), LV_PCT(100)); + + /* Store the window title in a user-data string on the screen object + * so host code can retrieve it if it wants to render a title bar. */ + if (title && *title) { + /* lv_obj_set_user_data stores a void* — we cast the string pointer. + * The string must outlive the screen object; for literals this is + * always true. For dynamic titles use el_lvgl_window_set_title. */ + lv_obj_set_user_data(scr, (void *)(uintptr_t)title); + } + + /* Allocate a slot for the screen object. */ + int64_t h = lvgl_slot_alloc(EL_LVGL_WINDOW, scr); + return h; +} + +/* + * el_lvgl_window_show — no-op on embedded. The screen is always visible. + */ +void el_lvgl_window_show(int64_t handle) { + (void)handle; + /* On multi-screen setups, load the screen: */ + /* ElLvglWidget *w = lvgl_slot_get(handle); + * if (w) lv_scr_load(w->obj); */ +} + +/* + * el_lvgl_window_set_title — update the user_data pointer on the screen object. + * On embedded, "title" is typically only used by a custom host title bar. + */ +void el_lvgl_window_set_title(int64_t handle, const char *title) { + ElLvglWidget *w = lvgl_slot_get(handle); + if (!w || w->kind != EL_LVGL_WINDOW) return; + lv_obj_set_user_data(w->obj, (void *)(uintptr_t)(title ? title : "")); +} + +/* ── Layout containers ────────────────────────────────────────────────────── */ + +/* + * el_lvgl_vstack_create — vertical flex column with inter-item gap = spacing. + */ +int64_t el_lvgl_vstack_create(int spacing) { + lv_obj_t *obj = lv_obj_create(lv_scr_act()); + lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN); + lv_obj_set_style_pad_row(obj, (lv_coord_t)spacing, 0); + lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT); + /* Remove default LVGL border and background so containers are transparent + * by default, matching the AppKit/GTK4 backends. */ + lv_obj_set_style_border_width(obj, 0, 0); + lv_obj_set_style_bg_opa(obj, LV_OPA_TRANSP, 0); + lv_obj_set_style_pad_all(obj, 0, 0); + return lvgl_slot_alloc(EL_LVGL_VSTACK, obj); +} + +/* + * el_lvgl_hstack_create — horizontal flex row with inter-item gap = spacing. + */ +int64_t el_lvgl_hstack_create(int spacing) { + lv_obj_t *obj = lv_obj_create(lv_scr_act()); + lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW); + lv_obj_set_style_pad_column(obj, (lv_coord_t)spacing, 0); + lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT); + lv_obj_set_style_border_width(obj, 0, 0); + lv_obj_set_style_bg_opa(obj, LV_OPA_TRANSP, 0); + lv_obj_set_style_pad_all(obj, 0, 0); + return lvgl_slot_alloc(EL_LVGL_HSTACK, obj); +} + +/* + * el_lvgl_zstack_create — plain container, children positioned absolutely. + * No flex flow is set; callers use lv_obj_set_pos() on children directly, + * or rely on their natural 0,0 origin. + */ +int64_t el_lvgl_zstack_create(void) { + lv_obj_t *obj = lv_obj_create(lv_scr_act()); + lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT); + lv_obj_set_style_border_width(obj, 0, 0); + lv_obj_set_style_bg_opa(obj, LV_OPA_TRANSP, 0); + lv_obj_set_style_pad_all(obj, 0, 0); + return lvgl_slot_alloc(EL_LVGL_ZSTACK, obj); +} + +/* + * el_lvgl_scroll_create — vertically scrollable container. + */ +int64_t el_lvgl_scroll_create(void) { + lv_obj_t *obj = lv_obj_create(lv_scr_act()); + lv_obj_set_scroll_dir(obj, LV_DIR_VER); + lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN); + lv_obj_set_size(obj, LV_PCT(100), LV_SIZE_CONTENT); + lv_obj_set_style_border_width(obj, 0, 0); + lv_obj_set_style_pad_all(obj, 0, 0); + return lvgl_slot_alloc(EL_LVGL_SCROLL, obj); +} + +/* ── Widget factories ─────────────────────────────────────────────────────── */ + +/* + * el_lvgl_label_create — static text label. + */ +int64_t el_lvgl_label_create(const char *text) { + lv_obj_t *obj = lv_label_create(lv_scr_act()); + lv_label_set_text(obj, text ? text : ""); + return lvgl_slot_alloc(EL_LVGL_LABEL, obj); +} + +/* + * el_lvgl_button_create — pressable button with a child label. + * + * LVGL buttons are containers; text is placed in an inner lv_label child. + * We store the child label pointer in btn_label so set_text / get_text can + * reach it without searching the object tree at runtime. + */ +int64_t el_lvgl_button_create(const char *label) { + lv_obj_t *btn = lv_btn_create(lv_scr_act()); + lv_obj_t *lbl = lv_label_create(btn); + lv_label_set_text(lbl, label ? label : ""); + lv_obj_center(lbl); + + int64_t h = lvgl_slot_alloc(EL_LVGL_BUTTON, btn); + if (h >= 0) { + g_widgets[h].btn_label = lbl; + /* Register click callback immediately so button responds when a + * callback name is registered later via __widget_on_click. */ + lv_obj_add_event_cb(btn, el_lvgl_event_cb, LV_EVENT_CLICKED, + (void *)(intptr_t)h); + } + return h; +} + +/* + * el_lvgl_text_field_create — single-line text input. + */ +int64_t el_lvgl_text_field_create(const char *placeholder) { + lv_obj_t *obj = lv_textarea_create(lv_scr_act()); + lv_textarea_set_one_line(obj, true); + if (placeholder && *placeholder) { + lv_textarea_set_placeholder_text(obj, placeholder); + } + int64_t h = lvgl_slot_alloc(EL_LVGL_TEXTFIELD, obj); + if (h >= 0) { + lv_obj_add_event_cb(obj, el_lvgl_event_cb, LV_EVENT_VALUE_CHANGED, + (void *)(intptr_t)h); + lv_obj_add_event_cb(obj, el_lvgl_event_cb, LV_EVENT_READY, + (void *)(intptr_t)h); + } + return h; +} + +/* + * el_lvgl_text_area_create — multi-line text input. + */ +int64_t el_lvgl_text_area_create(const char *placeholder) { + lv_obj_t *obj = lv_textarea_create(lv_scr_act()); + lv_textarea_set_one_line(obj, false); + if (placeholder && *placeholder) { + lv_textarea_set_placeholder_text(obj, placeholder); + } + int64_t h = lvgl_slot_alloc(EL_LVGL_TEXTAREA, obj); + if (h >= 0) { + lv_obj_add_event_cb(obj, el_lvgl_event_cb, LV_EVENT_VALUE_CHANGED, + (void *)(intptr_t)h); + } + return h; +} + +/* + * el_lvgl_image_create — image widget. + * + * On hosted Linux (SDL backend), path is a filesystem path. + * On embedded with SPIFFS/LittleFS, path is a SPIFFS URI: "S:/image.bin". + * LVGL image decoders are registered separately by the host application. + */ +int64_t el_lvgl_image_create(const char *path_or_name) { + lv_obj_t *obj = lv_img_create(lv_scr_act()); + if (path_or_name && *path_or_name) { + lv_img_set_src(obj, path_or_name); + } + return lvgl_slot_alloc(EL_LVGL_IMAGE, obj); +} + +/* ── Widget property setters ─────────────────────────────────────────────── */ + +/* + * el_lvgl_widget_set_text — update visible text. + * + * Dispatch per kind: + * LABEL → lv_label_set_text + * BUTTON → lv_label_set_text on inner btn_label child + * TEXTFIELD / TEXTAREA → lv_textarea_set_text + * WINDOW → lv_obj_set_user_data (stores title string) + */ +void el_lvgl_widget_set_text(int64_t handle, const char *text) { + ElLvglWidget *w = lvgl_slot_get(handle); + if (!w) return; + const char *t = text ? text : ""; + switch (w->kind) { + case EL_LVGL_LABEL: + lv_label_set_text(w->obj, t); + break; + case EL_LVGL_BUTTON: + if (w->btn_label) lv_label_set_text(w->btn_label, t); + break; + case EL_LVGL_TEXTFIELD: + case EL_LVGL_TEXTAREA: + lv_textarea_set_text(w->obj, t); + break; + case EL_LVGL_WINDOW: + lv_obj_set_user_data(w->obj, (void *)(uintptr_t)t); + break; + default: + break; + } +} + +/* + * el_lvgl_widget_get_text — retrieve visible text. + * + * Returns a pointer into LVGL's internal storage — valid until the next LVGL + * operation that modifies the widget. Callers that need to hold the value + * across LVGL calls must strdup() it. + */ +const char *el_lvgl_widget_get_text(int64_t handle) { + ElLvglWidget *w = lvgl_slot_get(handle); + if (!w) return ""; + switch (w->kind) { + case EL_LVGL_LABEL: + return lv_label_get_text(w->obj); + case EL_LVGL_BUTTON: + return w->btn_label ? lv_label_get_text(w->btn_label) : ""; + case EL_LVGL_TEXTFIELD: + case EL_LVGL_TEXTAREA: + return lv_textarea_get_text(w->obj); + default: + return ""; + } +} + +/* + * el_lvgl_widget_set_color — foreground (text) colour. + * + * r/g/b are 0.0–1.0 floats bit-cast as el_val_t (see el_runtime.h). + * LVGL lv_color_make takes uint8_t 0–255 components. + */ +void el_lvgl_widget_set_color(int64_t handle, + float r, float g, float b, float a) { + (void)a; /* LVGL text colour has no per-glyph alpha channel */ + ElLvglWidget *w = lvgl_slot_get(handle); + if (!w) return; + lv_color_t c = lv_color_make( + (uint8_t)(r * 255.0f + 0.5f), + (uint8_t)(g * 255.0f + 0.5f), + (uint8_t)(b * 255.0f + 0.5f)); + lv_obj_set_style_text_color(w->obj, c, 0); + if (w->kind == EL_LVGL_BUTTON && w->btn_label) { + lv_obj_set_style_text_color(w->btn_label, c, 0); + } +} + +/* + * el_lvgl_widget_set_bg_color — background fill colour + opacity. + */ +void el_lvgl_widget_set_bg_color(int64_t handle, + float r, float g, float b, float a) { + ElLvglWidget *w = lvgl_slot_get(handle); + if (!w) return; + lv_color_t c = lv_color_make( + (uint8_t)(r * 255.0f + 0.5f), + (uint8_t)(g * 255.0f + 0.5f), + (uint8_t)(b * 255.0f + 0.5f)); + lv_opa_t opa = (lv_opa_t)(a * 255.0f + 0.5f); + lv_obj_set_style_bg_color(w->obj, c, 0); + lv_obj_set_style_bg_opa(w->obj, opa, 0); +} + +/* + * el_lvgl_widget_set_font — apply font to text-bearing widget. + * + * The `family` parameter is accepted for API compatibility but LVGL uses + * compiled-in fonts only. Only the size and bold flag have effect unless + * EL_LVGL_CUSTOM_FONT is defined by the host. + */ +void el_lvgl_widget_set_font(int64_t handle, + const char *family, int size, int bold) { + (void)family; /* ignored; LVGL uses compiled-in Montserrat fonts */ + ElLvglWidget *w = lvgl_slot_get(handle); + if (!w) return; + const lv_font_t *font = font_select(size, bold); + if (!font) return; + lv_obj_set_style_text_font(w->obj, font, 0); + if (w->kind == EL_LVGL_BUTTON && w->btn_label) { + lv_obj_set_style_text_font(w->btn_label, font, 0); + } +} + +/* + * el_lvgl_widget_set_padding — set per-side padding (top/right/bottom/left). + */ +void el_lvgl_widget_set_padding(int64_t handle, + int top, int right, int bottom, int left) { + ElLvglWidget *w = lvgl_slot_get(handle); + if (!w) return; + lv_obj_set_style_pad_top(w->obj, (lv_coord_t)top, 0); + lv_obj_set_style_pad_right(w->obj, (lv_coord_t)right, 0); + lv_obj_set_style_pad_bottom(w->obj, (lv_coord_t)bottom, 0); + lv_obj_set_style_pad_left(w->obj, (lv_coord_t)left, 0); +} + +/* + * el_lvgl_widget_set_width — set explicit pixel width. + */ +void el_lvgl_widget_set_width(int64_t handle, int width) { + ElLvglWidget *w = lvgl_slot_get(handle); + if (!w) return; + lv_obj_set_width(w->obj, (lv_coord_t)width); +} + +/* + * el_lvgl_widget_set_height — set explicit pixel height. + */ +void el_lvgl_widget_set_height(int64_t handle, int height) { + ElLvglWidget *w = lvgl_slot_get(handle); + if (!w) return; + lv_obj_set_height(w->obj, (lv_coord_t)height); +} + +/* + * el_lvgl_widget_set_flex — set flex grow factor. + * + * flex > 0 → lv_obj_set_flex_grow(obj, flex): object expands to fill + * remaining space proportional to its grow factor. + * flex == 0 → lv_obj_set_flex_grow(obj, 0): object uses natural size. + */ +void el_lvgl_widget_set_flex(int64_t handle, int flex) { + ElLvglWidget *w = lvgl_slot_get(handle); + if (!w) return; + lv_obj_set_flex_grow(w->obj, (uint8_t)(flex > 0 ? flex : 0)); +} + +/* + * el_lvgl_widget_set_corner_radius — set border radius. + */ +void el_lvgl_widget_set_corner_radius(int64_t handle, int radius) { + ElLvglWidget *w = lvgl_slot_get(handle); + if (!w) return; + lv_obj_set_style_radius(w->obj, (lv_coord_t)radius, 0); +} + +/* + * el_lvgl_widget_set_disabled — enable/disable interactive state. + * + * LV_STATE_DISABLED greys out the widget and prevents input events. + */ +void el_lvgl_widget_set_disabled(int64_t handle, int disabled) { + ElLvglWidget *w = lvgl_slot_get(handle); + if (!w) return; + if (disabled) { + lv_obj_add_state(w->obj, LV_STATE_DISABLED); + } else { + lv_obj_clear_state(w->obj, LV_STATE_DISABLED); + } +} + +/* + * el_lvgl_widget_set_hidden — show/hide widget. + * + * LV_OBJ_FLAG_HIDDEN hides the widget and removes it from layout flow. + */ +void el_lvgl_widget_set_hidden(int64_t handle, int hidden) { + ElLvglWidget *w = lvgl_slot_get(handle); + if (!w) return; + if (hidden) { + lv_obj_add_flag(w->obj, LV_OBJ_FLAG_HIDDEN); + } else { + lv_obj_clear_flag(w->obj, LV_OBJ_FLAG_HIDDEN); + } +} + +/* ── Tree operations ──────────────────────────────────────────────────────── */ + +/* + * el_lvgl_widget_add_child — attach child widget to parent. + * + * lv_obj_set_parent() reparents the child object inside the LVGL tree. + * For WINDOW parents we use the screen object itself as the parent, since + * lv_scr_act() IS the root container. + */ +void el_lvgl_widget_add_child(int64_t parent, int64_t child) { + ElLvglWidget *pw = lvgl_slot_get(parent); + ElLvglWidget *cw = lvgl_slot_get(child); + if (!pw || !cw) return; + lv_obj_set_parent(cw->obj, pw->obj); +} + +/* + * el_lvgl_widget_remove_child — detach child from its current parent. + * + * LVGL has no explicit "remove from parent without deleting" operation. + * We reparent the child back to the active screen (making it a root-level + * floating widget) and then hide it. The widget still occupies a slot and + * can be re-attached or destroyed later. + */ +void el_lvgl_widget_remove_child(int64_t parent, int64_t child) { + (void)parent; + ElLvglWidget *cw = lvgl_slot_get(child); + if (!cw) return; + /* Move to screen root and hide. */ + lv_obj_set_parent(cw->obj, lv_scr_act()); + lv_obj_add_flag(cw->obj, LV_OBJ_FLAG_HIDDEN); +} + +/* + * el_lvgl_widget_destroy — delete widget and its children from the LVGL tree, + * then free the slot. + * + * lv_obj_del() recursively deletes the object and all children. After this + * call the handle is invalid and must not be used. + */ +void el_lvgl_widget_destroy(int64_t handle) { + ElLvglWidget *w = lvgl_slot_get(handle); + if (!w) return; + lv_obj_del(w->obj); + lvgl_slot_free(handle); +} + +/* ── Event registration ───────────────────────────────────────────────────── */ + +/* + * Event registration stores the El function name in the widget slot. The + * actual lv_obj_add_event_cb() call is made here (or was made in the factory + * for buttons/textfields where we know the relevant event codes upfront). + * + * For widgets that did not register their event callback in the factory (e.g. + * labels receiving a click handler), we add the LVGL event binding now. + */ + +void el_lvgl_widget_on_click(int64_t handle, const char *fn_name) { + ElLvglWidget *w = lvgl_slot_get(handle); + if (!w) return; + strncpy(w->cb_click, fn_name ? fn_name : "", 255); + w->cb_click[255] = '\0'; + /* + * Buttons already have LV_EVENT_CLICKED registered in the factory. + * For other widget kinds (labels, containers used as tap targets), add + * the click flag and register the callback. + */ + if (w->kind != EL_LVGL_BUTTON) { + lv_obj_add_flag(w->obj, LV_OBJ_FLAG_CLICKABLE); + lv_obj_add_event_cb(w->obj, el_lvgl_event_cb, LV_EVENT_CLICKED, + (void *)(intptr_t)handle); + } +} + +void el_lvgl_widget_on_change(int64_t handle, const char *fn_name) { + ElLvglWidget *w = lvgl_slot_get(handle); + if (!w) return; + strncpy(w->cb_change, fn_name ? fn_name : "", 255); + w->cb_change[255] = '\0'; + /* + * Textfield/textarea factories already register VALUE_CHANGED. + * For other kinds (e.g. a custom toggle), add the binding now. + */ + if (w->kind != EL_LVGL_TEXTFIELD && w->kind != EL_LVGL_TEXTAREA) { + lv_obj_add_event_cb(w->obj, el_lvgl_event_cb, LV_EVENT_VALUE_CHANGED, + (void *)(intptr_t)handle); + } +} + +void el_lvgl_widget_on_submit(int64_t handle, const char *fn_name) { + ElLvglWidget *w = lvgl_slot_get(handle); + if (!w) return; + strncpy(w->cb_submit, fn_name ? fn_name : "", 255); + w->cb_submit[255] = '\0'; + /* + * LV_EVENT_READY fires when Enter is pressed in a one-line textarea. + * Textfield factories already register READY. For other kinds, add it. + */ + if (w->kind != EL_LVGL_TEXTFIELD) { + lv_obj_add_event_cb(w->obj, el_lvgl_event_cb, LV_EVENT_READY, + (void *)(intptr_t)handle); + } +} + +#endif /* EL_TARGET_LVGL */ diff --git a/lang/el-compiler/runtime/el_native_target.h b/lang/el-compiler/runtime/el_native_target.h new file mode 100644 index 0000000..7daabb7 --- /dev/null +++ b/lang/el-compiler/runtime/el_native_target.h @@ -0,0 +1,574 @@ +/* + * el_native_target.h — Native widget declarations for el programs targeting + * native desktop UI (AppKit / GTK4 / Win32). + * + * This header is designed to be included AFTER el_runtime.h without conflict: + * - It does NOT redefine el_to_float, el_from_float, or any el_runtime.h + * static inlines. + * - It does NOT redeclare __println, __print, or other functions whose + * return types differ between el_seed.h and el_runtime.h. + * - It adds: native widget builtins + float arithmetic helpers that the + * current el_runtime.h omits but elc still emits calls to. + * + * Usage: + * Inject via -include at compile time, OR #include it after el_runtime.h. + * + * clang -DEL_TARGET_MACOS -include el_native_target.h -c my_app.c ... + */ + +#pragma once + +#include +#include + +/* el_val_t must already be defined by el_runtime.h or el_seed.h. */ +#ifndef EL_VAL_T_DEFINED +typedef int64_t el_val_t; +#endif + +/* ── Float arithmetic helpers ─────────────────────────────────────────────── + * elc emits calls to float_div / float_mul etc. for Float-typed expressions. + * These were in el_runtime.c through v1.0.0-20260501 but are missing from the + * current el_runtime.h. Redeclared here as static inline to avoid link deps. + * Only defined if not already declared (old runtimes that still have them). */ + +#ifndef EL_FLOAT_OPS_DEFINED +#define EL_FLOAT_OPS_DEFINED + +/* el_to_float / el_from_float — bit-cast between el_val_t and double. + * Defined as static inline in both el_runtime.h and el_seed.h; we do NOT + * redefine them here. We rely on one of those headers being included first. */ + +static inline el_val_t float_div(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub, ur; + ua.i = a; ub.i = b; + ur.d = (ub.d != 0.0) ? (ua.d / ub.d) : 0.0; + return ur.i; +} + +static inline el_val_t float_mul(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub, ur; + ua.i = a; ub.i = b; ur.d = ua.d * ub.d; + return ur.i; +} + +static inline el_val_t float_add(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub, ur; + ua.i = a; ub.i = b; ur.d = ua.d + ub.d; + return ur.i; +} + +static inline el_val_t float_sub(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub, ur; + ua.i = a; ub.i = b; ur.d = ua.d - ub.d; + return ur.i; +} + +static inline el_val_t float_lt(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d < ub.d); +} + +static inline el_val_t float_gt(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d > ub.d); +} + +static inline el_val_t float_lte(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d <= ub.d); +} + +static inline el_val_t float_gte(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d >= ub.d); +} + +static inline el_val_t float_eq(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d == ub.d); +} + +#endif /* EL_FLOAT_OPS_DEFINED */ + +/* ── Native widget system (macOS AppKit) ──────────────────────────────────── + * Available when compiled with -DEL_TARGET_MACOS and linked with el_appkit.m. + * Widget handles are opaque int64_t slot indices; -1 = invalid. */ + +#ifdef EL_TARGET_MACOS + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); +void __widget_set_data(el_val_t handle, el_val_t data_str); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_MACOS */ + +/* ── Native widget system (Linux GTK4) ────────────────────────────────────── + * Available when compiled with -DEL_TARGET_LINUX and linked with el_gtk4.c. + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * All functions have the same signatures as EL_TARGET_MACOS above. */ + +#ifdef EL_TARGET_LINUX + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader — same JSON output as EL_TARGET_MACOS */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_LINUX */ + +/* ── Native widget system (Windows Win32) ─────────────────────────────────── + * Available when compiled with -DEL_TARGET_WIN32 and linked with el_win32.c. + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * Link: el_win32.obj comctl32.lib user32.lib gdi32.lib */ + +#ifdef EL_TARGET_WIN32 + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_WIN32 */ + +/* ── Native widget system (iOS UIKit) ─────────────────────────────────────── + * Available when compiled with -DEL_TARGET_IOS and linked with el_uikit.m. + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * + * iOS lifecycle note: UIApplicationMain never returns. The el program must + * store its UI-build logic in a void(*)(void) function pointer, assign it to + * el_main_entry_fn, then call __native_run_loop. ElAppDelegate invokes + * el_main_entry_fn inside didFinishLaunchingWithOptions. + * Call el_uikit_set_args(argc, argv) from main() before __native_run_loop. */ + +#ifdef EL_TARGET_IOS + +/* Lifecycle entry-function hook — set before calling __native_run_loop. */ +extern void (*el_main_entry_fn)(void); + +/* Forward argc/argv from main() to UIApplicationMain. */ +void el_uikit_set_args(int argc, char** argv); + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_IOS */ + +/* ── Native widget system (Android JNI) ───────────────────────────────────── + * Available when compiled with -DEL_TARGET_ANDROID and linked with + * libelruntime.so (which includes el_android.c compiled by the NDK build). + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * + * Java companion: ElBridge.java (package com.neuron.el) must be compiled into + * the APK. The Activity must call ElBridge.init(this) before any widget ops. + * + * Link flags (in Android.mk or CMakeLists.txt): + * -landroid -llog -ldl */ + +#ifdef EL_TARGET_ANDROID + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); /* no-op on Android */ + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_ANDROID */ + +/* ── Native widget system (LVGL v9 — embedded / microcontroller) ───────────── + * Available when compiled with -DEL_TARGET_LVGL and linked with el_lvgl.c + * and the LVGL library (lvgl.a or lvgl source tree). + * + * Target platforms: ESP32, STM32, industrial panels. Any system with 256KB+ + * RAM and an LVGL-compatible display driver. No OS required. + * + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * + * Bare-metal / no dynamic linker: + * Compile with -DEL_LVGL_NO_DLSYM and provide: + * el_val_t el_lvgl_dispatch(const char *fn, el_val_t a, el_val_t b); + * + * Compile: + * gcc -DEL_TARGET_LVGL -I./lvgl el_lvgl.c -c -o el_lvgl.o + * # Then link with lvgl.a. */ + +#ifdef EL_TARGET_LVGL + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader — same JSON output as all other native targets */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_LVGL */ + +/* ── Native widget system (SDL2 — embedded / Pi) ──────────────────────────── + * Available when compiled with -DEL_TARGET_SDL2 and linked with el_sdl2.c. + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * + * Target: Raspberry Pi Zero, embedded Linux, any system with a framebuffer + * and SDL2 available. No GTK, no desktop environment required. + * + * Compile: + * gcc -DEL_TARGET_SDL2 $(sdl2-config --cflags) -c el_sdl2.c -o el_sdl2.o + * Link: + * $(sdl2-config --libs) -lSDL2_ttf -lSDL2_image -ldl */ + +#ifdef EL_TARGET_SDL2 + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_SDL2 */ diff --git a/lang/el-compiler/runtime/el_runtime_win32.c b/lang/el-compiler/runtime/el_runtime_win32.c new file mode 100644 index 0000000..4588839 --- /dev/null +++ b/lang/el-compiler/runtime/el_runtime_win32.c @@ -0,0 +1,1146 @@ +/* + * el_runtime_win32.c — Minimal Win32-compatible el runtime stub. + * + * Provides only the symbols that native-hello (and the el-native vessel) call + * from el_runtime.h. Replaces the full el_runtime.c + el_seed.c for + * cross-compiled Win32 targets where POSIX headers (pthread, curl, dlfcn, + * sys/socket, etc.) are unavailable. + * + * Symbols provided: + * Allocators: el_strdup, el_strbuf, el_wrap_str (static helpers) + * I/O: println, print + * String: el_str_concat, str_eq, str_starts_with, str_len, str_concat, + * int_to_str, str_to_int, native_str_to_int, str_slice, str_trim, + * str_contains, str_ends_with, str_to_upper, str_to_lower, + * str_index_of, str_char_at, str_char_code, str_replace, + * str_pad_left, str_pad_right, str_upper, str_lower + * Math: el_abs, el_max, el_min, int_to_float, float_to_int + * List: el_list_empty, el_list_new, el_list_len, el_list_get, + * el_list_append, el_list_clone + * Map: el_map_new, el_map_get, el_get_field, el_map_set + * Retain/RC: el_retain, el_release + * Arena: el_arena_push, el_arena_pop + * JSON: json_get_string, json_get_int, json_get_float, json_get_bool, + * json_get_raw, json_find_key (static), json_skip_value (static) + * Process: exit_program, env, el_runtime_init_args + * Stubs: All remaining el_runtime.h symbols as no-op / return-0 stubs + * so the linker is satisfied even if the app doesn't call them. + * + * el_request_start / el_request_end are provided as empty no-ops (no HTTP + * server, no per-request arena needed for a native GUI app). + * + * Compile: + * x86_64-w64-mingw32-gcc -std=c11 -DEL_TARGET_WIN32 -I \ + * -c el_runtime_win32.c -o el_runtime_win32.o + */ + +#include "el_runtime.h" + +#include +#include +#include +#include +#include +#include +#include + +/* ── Arena (single-threaded; no pthread needed) ─────────────────────────── */ + +#define EL_ARENA_INITIAL 512 + +typedef struct { + char** ptrs; + size_t count; + size_t cap; +} ElArena; + +static ElArena _arena = {NULL, 0, 0}; +static int _arena_active = 0; + +static void el_arena_track(char* p) { + if (!_arena_active || !p) return; + if (_arena.count >= _arena.cap) { + size_t nc = _arena.cap == 0 ? EL_ARENA_INITIAL : _arena.cap * 2; + char** g = realloc(_arena.ptrs, nc * sizeof(char*)); + if (!g) return; + _arena.ptrs = g; + _arena.cap = nc; + } + _arena.ptrs[_arena.count++] = p; +} + +void el_request_start(void) { _arena.count = 0; _arena_active = 1; } +void el_request_end(void) { + _arena_active = 0; + for (size_t i = 0; i < _arena.count; i++) free(_arena.ptrs[i]); + _arena.count = 0; +} + +#define EL_ARENA_SCOPE_DEPTH 32 +static size_t _arena_scope[EL_ARENA_SCOPE_DEPTH]; +static int _arena_scope_depth = 0; + +el_val_t el_arena_push(void) { + if (!_arena_active) _arena_active = 1; + if (_arena_scope_depth < EL_ARENA_SCOPE_DEPTH) + _arena_scope[_arena_scope_depth++] = _arena.count; + return (el_val_t)(int64_t)_arena.count; +} + +el_val_t el_arena_pop(el_val_t mark) { + size_t save = (size_t)(int64_t)mark; + if (save > _arena.count) save = 0; + for (size_t i = save; i < _arena.count; i++) { + if (_arena.ptrs[i]) { free(_arena.ptrs[i]); _arena.ptrs[i] = NULL; } + } + _arena.count = save; + if (_arena_scope_depth > 0) _arena_scope_depth--; + if (save == 0) _arena_active = 0; + return 0; +} + +/* ── Allocator helpers ───────────────────────────────────────────────────── */ + +static char* el_strdup(const char* s) { + if (!s) { char* p = strdup(""); el_arena_track(p); return p; } + char* p = strdup(s); + el_arena_track(p); + return p; +} + +static char* el_strbuf(size_t n) { + char* p = malloc(n + 1); + if (!p) { fputs("el_runtime_win32: out of memory\n", stderr); exit(1); } + p[0] = '\0'; + el_arena_track(p); + return p; +} + +static el_val_t el_wrap_str(char* s) { + return EL_STR(s); +} + +/* ── I/O ─────────────────────────────────────────────────────────────────── */ + +el_val_t println(el_val_t s) { + const char* str = EL_CSTR(s); + puts(str ? str : ""); + return 0; +} + +el_val_t print(el_val_t s) { + const char* str = EL_CSTR(s); + if (str) fputs(str, stdout); + return 0; +} + +el_val_t readline(void) { + char buf[4096]; + if (!fgets(buf, sizeof(buf), stdin)) return el_wrap_str(el_strdup("")); + size_t len = strlen(buf); + if (len > 0 && buf[len - 1] == '\n') buf[len - 1] = '\0'; + return el_wrap_str(el_strdup(buf)); +} + +/* ── String builtins ─────────────────────────────────────────────────────── */ + +el_val_t el_str_concat(el_val_t av, el_val_t bv) { + const char* a = EL_CSTR(av); + const char* b = EL_CSTR(bv); + if (!a) a = ""; + if (!b) b = ""; + size_t la = strlen(a), lb = strlen(b); + char* out = el_strbuf(la + lb); + memcpy(out, a, la); + memcpy(out + la, b, lb); + out[la + lb] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_eq(el_val_t av, el_val_t bv) { + const char* a = EL_CSTR(av); + const char* b = EL_CSTR(bv); + if (!a || !b) return (el_val_t)(a == b); + return (el_val_t)(strcmp(a, b) == 0); +} + +el_val_t str_starts_with(el_val_t sv, el_val_t prefv) { + const char* s = EL_CSTR(sv); + const char* p = EL_CSTR(prefv); + if (!s || !p) return 0; + return (el_val_t)(strncmp(s, p, strlen(p)) == 0); +} + +el_val_t str_ends_with(el_val_t sv, el_val_t sufv) { + const char* s = EL_CSTR(sv); + const char* suf = EL_CSTR(sufv); + if (!s || !suf) return 0; + size_t ls = strlen(s), lsuf = strlen(suf); + if (lsuf > ls) return 0; + return (el_val_t)(strcmp(s + ls - lsuf, suf) == 0); +} + +el_val_t str_len(el_val_t sv) { + const char* s = EL_CSTR(sv); + return s ? (el_val_t)strlen(s) : 0; +} + +el_val_t str_concat(el_val_t a, el_val_t b) { + return el_str_concat(a, b); +} + +el_val_t int_to_str(el_val_t n) { + char buf[32]; + snprintf(buf, sizeof(buf), "%lld", (long long)n); + return el_wrap_str(el_strdup(buf)); +} + +el_val_t str_to_int(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + return (el_val_t)atoll(s); +} + +el_val_t native_str_to_int(el_val_t sv) { return str_to_int(sv); } + +el_val_t str_slice(el_val_t sv, el_val_t start, el_val_t end) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + int64_t len = (int64_t)strlen(s); + if (start < 0) start = 0; + if (end > len) end = len; + if (start >= end) return el_wrap_str(el_strdup("")); + int64_t sz = end - start; + char* out = el_strbuf((size_t)sz); + memcpy(out, s + start, (size_t)sz); + out[sz] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_contains(el_val_t sv, el_val_t subv) { + const char* s = EL_CSTR(sv); + const char* sub = EL_CSTR(subv); + if (!s || !sub) return 0; + return (el_val_t)(strstr(s, sub) != NULL); +} + +el_val_t str_replace(el_val_t sv, el_val_t fromv, el_val_t tov) { + const char* s = EL_CSTR(sv); + const char* from = EL_CSTR(fromv); + const char* to = EL_CSTR(tov); + if (!s || !from || !to) return el_wrap_str(el_strdup(s ? s : "")); + size_t ls = strlen(s), lf = strlen(from), lt = strlen(to); + if (lf == 0) return el_wrap_str(el_strdup(s)); + /* Count occurrences */ + size_t count = 0; + const char* p = s; + while ((p = strstr(p, from)) != NULL) { count++; p += lf; } + size_t new_len = ls + count * (lt > lf ? lt - lf : 0) - count * (lf > lt ? lf - lt : 0); + char* out = el_strbuf(new_len); + const char* src = s; + char* dst = out; + while ((p = strstr(src, from)) != NULL) { + size_t pre = (size_t)(p - src); + memcpy(dst, src, pre); dst += pre; + memcpy(dst, to, lt); dst += lt; + src = p + lf; + } + strcpy(dst, src); + return el_wrap_str(out); +} + +el_val_t str_to_upper(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + char* out = el_strbuf(n); + for (size_t i = 0; i < n; i++) out[i] = (char)toupper((unsigned char)s[i]); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_to_lower(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + char* out = el_strbuf(n); + for (size_t i = 0; i < n; i++) out[i] = (char)tolower((unsigned char)s[i]); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_upper(el_val_t sv) { return str_to_upper(sv); } +el_val_t str_lower(el_val_t sv) { return str_to_lower(sv); } + +el_val_t str_trim(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + while (*s && isspace((unsigned char)*s)) s++; + size_t n = strlen(s); + while (n > 0 && isspace((unsigned char)s[n - 1])) n--; + char* out = el_strbuf(n); + memcpy(out, s, n); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_index_of(el_val_t sv, el_val_t subv) { + const char* s = EL_CSTR(sv); + const char* sub = EL_CSTR(subv); + if (!s || !sub) return -1; + const char* p = strstr(s, sub); + return p ? (el_val_t)(p - s) : -1; +} + +el_val_t str_char_at(el_val_t sv, el_val_t i) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + int64_t idx = (int64_t)i; + int64_t len = (int64_t)strlen(s); + if (idx < 0 || idx >= len) return 0; + char buf[2] = { s[idx], '\0' }; + return el_wrap_str(el_strdup(buf)); +} + +el_val_t str_char_code(el_val_t sv, el_val_t i) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + int64_t idx = (int64_t)i; + int64_t len = (int64_t)strlen(s); + if (idx < 0 || idx >= len) return 0; + return (el_val_t)(unsigned char)s[idx]; +} + +el_val_t str_pad_left(el_val_t sv, el_val_t widthv, el_val_t padv) { + const char* s = EL_CSTR(sv); + const char* pad = EL_CSTR(padv); + if (!s) s = ""; + if (!pad || !*pad) pad = " "; + int64_t width = (int64_t)widthv; + int64_t slen = (int64_t)strlen(s); + if (slen >= width) return el_wrap_str(el_strdup(s)); + int64_t need = width - slen; + char* out = el_strbuf((size_t)width); + size_t plen = strlen(pad); + for (int64_t i = 0; i < need; i++) out[i] = pad[i % plen]; + memcpy(out + need, s, (size_t)slen); + out[width] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_pad_right(el_val_t sv, el_val_t widthv, el_val_t padv) { + const char* s = EL_CSTR(sv); + const char* pad = EL_CSTR(padv); + if (!s) s = ""; + if (!pad || !*pad) pad = " "; + int64_t width = (int64_t)widthv; + int64_t slen = (int64_t)strlen(s); + if (slen >= width) return el_wrap_str(el_strdup(s)); + int64_t need = width - slen; + char* out = el_strbuf((size_t)width); + memcpy(out, s, (size_t)slen); + size_t plen = strlen(pad); + for (int64_t i = 0; i < need; i++) out[slen + i] = pad[i % plen]; + out[width] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_format(el_val_t fmtv, el_val_t datav) { + /* Minimal stub — just return the format string unchanged. */ + return fmtv; +} + +el_val_t str_split(el_val_t sv, el_val_t sepv) { + /* Return empty list stub. */ + return el_list_empty(); +} + +el_val_t str_count(el_val_t sv, el_val_t subv) { + const char* s = EL_CSTR(sv); + const char* sub = EL_CSTR(subv); + if (!s || !sub || !*sub) return 0; + size_t lsub = strlen(sub); + int64_t cnt = 0; + const char* p = s; + while ((p = strstr(p, sub)) != NULL) { cnt++; p += lsub; } + return (el_val_t)cnt; +} + +/* ── Math ────────────────────────────────────────────────────────────────── */ + +el_val_t el_abs(el_val_t n) { return n < 0 ? -n : n; } +el_val_t el_max(el_val_t a, el_val_t b) { return a > b ? a : b; } +el_val_t el_min(el_val_t a, el_val_t b) { return a < b ? a : b; } + +el_val_t int_to_float(el_val_t n) { return el_from_float((double)(int64_t)n); } +el_val_t float_to_int(el_val_t f) { return (el_val_t)(int64_t)el_to_float(f); } +el_val_t float_to_str(el_val_t f) { + char buf[64]; + snprintf(buf, sizeof(buf), "%g", el_to_float(f)); + return el_wrap_str(el_strdup(buf)); +} +el_val_t str_to_float(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + return el_from_float(strtod(s, NULL)); +} +el_val_t format_float(el_val_t f, el_val_t decimals) { + char buf[128]; + int d = (int)(int64_t)decimals; + if (d < 0) d = 0; if (d > 30) d = 30; + snprintf(buf, sizeof(buf), "%.*f", d, el_to_float(f)); + return el_wrap_str(el_strdup(buf)); +} +el_val_t decimal_round(el_val_t f, el_val_t decimals) { return format_float(f, decimals); } +el_val_t math_sqrt(el_val_t f) { return el_from_float(sqrt(el_to_float(f))); } +el_val_t math_log(el_val_t f) { return el_from_float(log10(el_to_float(f))); } +el_val_t math_ln(el_val_t f) { return el_from_float(log(el_to_float(f))); } +el_val_t math_sin(el_val_t f) { return el_from_float(sin(el_to_float(f))); } +el_val_t math_cos(el_val_t f) { return el_from_float(cos(el_to_float(f))); } +el_val_t math_pi(void) { return el_from_float(3.14159265358979323846); } + +/* ── Refcounted heap objects ─────────────────────────────────────────────── */ + +#define EL_MAGIC_LIST 0xE15710A1u +#define EL_MAGIC_MAP 0xE19A704Bu + +typedef struct { uint32_t magic; uint32_t refcount; } ElHeader; + +typedef struct { + ElHeader hdr; + int64_t length; + int64_t capacity; + el_val_t* elems; +} ElList; + +typedef struct { + ElHeader hdr; + int64_t count; + int64_t capacity; + el_val_t* keys; + el_val_t* values; +} ElMap; + +static int looks_like_heap_obj(el_val_t v) { + if (v == 0) return 0; + int64_t s = (int64_t)v; + if (s > -0x10000 && s < 0x10000) return 0; + uintptr_t p = (uintptr_t)v; + if (p < 0x10000) return 0; + if (p & 0x7) return 0; + return 1; +} + +void el_retain(el_val_t v) { + if (!looks_like_heap_obj(v)) return; + ElHeader* h = (ElHeader*)(uintptr_t)v; + if (h->magic == EL_MAGIC_LIST || h->magic == EL_MAGIC_MAP) h->refcount++; +} + +void el_release(el_val_t v) { + if (!looks_like_heap_obj(v)) return; + ElHeader* h = (ElHeader*)(uintptr_t)v; + if (h->magic == EL_MAGIC_LIST) { + if (h->refcount > 0 && --h->refcount == 0) { + ElList* l = (ElList*)h; + free(l->elems); h->magic = 0; free(l); + } + } else if (h->magic == EL_MAGIC_MAP) { + if (h->refcount > 0 && --h->refcount == 0) { + ElMap* m = (ElMap*)h; + free(m->keys); free(m->values); h->magic = 0; free(m); + } + } +} + +/* ── List ────────────────────────────────────────────────────────────────── */ + +static ElList* list_alloc(int64_t cap) { + if (cap < 4) cap = 4; + ElList* lst = malloc(sizeof(ElList)); + if (!lst) { fputs("el_runtime_win32: OOM\n", stderr); exit(1); } + lst->hdr.magic = EL_MAGIC_LIST; + lst->hdr.refcount = 1; + lst->length = 0; + lst->capacity = cap; + lst->elems = malloc((size_t)cap * sizeof(el_val_t)); + if (!lst->elems) { fputs("el_runtime_win32: OOM\n", stderr); exit(1); } + return lst; +} + +el_val_t el_list_empty(void) { return EL_STR(list_alloc(4)); } + +el_val_t el_list_new(el_val_t count, ...) { + ElList* lst = list_alloc(count > 0 ? count : 4); + va_list ap; va_start(ap, count); + for (int64_t i = 0; i < count; i++) lst->elems[i] = va_arg(ap, el_val_t); + va_end(ap); + lst->length = count; + return EL_STR(lst); +} + +el_val_t el_list_len(el_val_t lv) { + ElList* l = (ElList*)(uintptr_t)lv; + return l ? l->length : 0; +} + +el_val_t el_list_get(el_val_t lv, el_val_t idx) { + ElList* l = (ElList*)(uintptr_t)lv; + if (!l || idx < 0 || idx >= l->length) return 0; + return l->elems[idx]; +} + +el_val_t el_list_append(el_val_t lv, el_val_t elem) { + ElList* old = (ElList*)(uintptr_t)lv; + if (!old) { + ElList* fresh = list_alloc(4); + fresh->elems[0] = elem; + fresh->length = 1; + return EL_STR(fresh); + } + if (old->hdr.refcount <= 1) { + if (old->length >= old->capacity) { + int64_t nc = old->capacity > 0 ? old->capacity * 2 : 4; + el_val_t* g = realloc(old->elems, (size_t)nc * sizeof(el_val_t)); + if (!g) { fputs("el_runtime_win32: OOM\n", stderr); exit(1); } + old->elems = g; + old->capacity = nc; + } + old->elems[old->length++] = elem; + return lv; + } + int64_t nc = old->length + 1; + if (nc < 4) nc = 4; + ElList* fresh = malloc(sizeof(ElList)); + if (!fresh) { fputs("el_runtime_win32: OOM\n", stderr); exit(1); } + fresh->hdr.magic = EL_MAGIC_LIST; + fresh->hdr.refcount = 1; + fresh->length = old->length + 1; + fresh->capacity = nc; + fresh->elems = malloc((size_t)nc * sizeof(el_val_t)); + if (!fresh->elems) { fputs("el_runtime_win32: OOM\n", stderr); exit(1); } + if (old->length > 0) + memcpy(fresh->elems, old->elems, (size_t)old->length * sizeof(el_val_t)); + fresh->elems[old->length] = elem; + return EL_STR(fresh); +} + +el_val_t el_list_clone(el_val_t lv) { + ElList* old = (ElList*)(uintptr_t)lv; + if (!old) return el_list_empty(); + ElList* fresh = list_alloc(old->capacity > 0 ? old->capacity : 4); + if (old->length > 0) + memcpy(fresh->elems, old->elems, (size_t)old->length * sizeof(el_val_t)); + fresh->length = old->length; + return EL_STR(fresh); +} + +/* ── Map ─────────────────────────────────────────────────────────────────── */ + +static ElMap* map_alloc(int64_t cap) { + if (cap < 4) cap = 4; + ElMap* m = malloc(sizeof(ElMap)); + if (!m) { fputs("el_runtime_win32: OOM\n", stderr); exit(1); } + m->hdr.magic = EL_MAGIC_MAP; + m->hdr.refcount = 1; + m->count = 0; + m->capacity = cap; + m->keys = malloc((size_t)cap * sizeof(el_val_t)); + m->values = malloc((size_t)cap * sizeof(el_val_t)); + if (!m->keys || !m->values) { fputs("el_runtime_win32: OOM\n", stderr); exit(1); } + return m; +} + +el_val_t el_map_new(el_val_t pair_count, ...) { + ElMap* m = map_alloc(pair_count > 0 ? pair_count : 4); + va_list ap; va_start(ap, pair_count); + for (int64_t i = 0; i < pair_count; i++) { + m->keys[i] = va_arg(ap, el_val_t); + m->values[i] = va_arg(ap, el_val_t); + } + va_end(ap); + m->count = pair_count; + return EL_STR(m); +} + +el_val_t el_map_get(el_val_t mv, el_val_t kv) { + ElMap* m = (ElMap*)(uintptr_t)mv; + const char* key = EL_CSTR(kv); + if (!m || !key) return 0; + for (int64_t i = 0; i < m->count; i++) { + const char* k = EL_CSTR(m->keys[i]); + if (k && strcmp(k, key) == 0) return m->values[i]; + } + return 0; +} + +el_val_t el_get_field(el_val_t mv, el_val_t kv) { return el_map_get(mv, kv); } + +el_val_t el_map_set(el_val_t mv, el_val_t kv, el_val_t value) { + ElMap* m = (ElMap*)(uintptr_t)mv; + if (!m) { + ElMap* fresh = map_alloc(4); + fresh->keys[0] = kv; fresh->values[0] = value; fresh->count = 1; + return EL_STR(fresh); + } + const char* key = EL_CSTR(kv); + if (key) { + for (int64_t i = 0; i < m->count; i++) { + const char* k = EL_CSTR(m->keys[i]); + if (k && strcmp(k, key) == 0) { m->values[i] = value; return mv; } + } + } + if (m->count >= m->capacity) { + int64_t nc = m->capacity > 0 ? m->capacity * 2 : 4; + el_val_t* gk = realloc(m->keys, (size_t)nc * sizeof(el_val_t)); + el_val_t* gv = realloc(m->values, (size_t)nc * sizeof(el_val_t)); + if (!gk || !gv) { fputs("el_runtime_win32: OOM\n", stderr); exit(1); } + m->keys = gk; m->values = gv; m->capacity = nc; + } + m->keys[m->count] = kv; m->values[m->count] = value; m->count++; + return mv; +} + +/* ── JSON helpers ────────────────────────────────────────────────────────── */ + +typedef struct { + const char* p; + const char* end; + int err; +} JsonParser; + +static void jp_skip_ws(JsonParser* jp) { + while (jp->p < jp->end) { + char c = *jp->p; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') jp->p++; + else break; + } +} + +static char* jp_parse_string_raw(JsonParser* jp) { + if (jp->p >= jp->end || *jp->p != '"') { jp->err = 1; return el_strdup(""); } + jp->p++; + size_t cap = 32, len = 0; + char* out = malloc(cap); + if (!out) { fputs("el_runtime_win32: OOM\n", stderr); exit(1); } + while (jp->p < jp->end && *jp->p != '"') { + char c = *jp->p++; + if (c == '\\' && jp->p < jp->end) { + char esc = *jp->p++; + switch (esc) { + case '"': c = '"'; break; + case '\\': c = '\\'; break; + case '/': c = '/'; break; + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'u': + for (int i = 0; i < 4 && jp->p < jp->end; i++) jp->p++; + c = '?'; + break; + default: c = esc; break; + } + } + if (len + 1 >= cap) { + cap *= 2; + out = realloc(out, cap); + if (!out) { fputs("el_runtime_win32: OOM\n", stderr); exit(1); } + } + out[len++] = c; + } + if (jp->p < jp->end && *jp->p == '"') jp->p++; + else jp->err = 1; + out[len] = '\0'; + return out; +} + +static const char* json_skip_value(const char* p) { + if (!p || !*p) return p; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p == '"') { + p++; + int e = 0; + while (*p) { + if (e) { e = 0; p++; continue; } + if (*p == '\\') { e = 1; p++; continue; } + if (*p == '"') { p++; break; } + p++; + } + return p; + } + if (*p == '{' || *p == '[') { + char open = *p, close = (open == '{') ? '}' : ']'; + int depth = 0, in_str = 0, e = 0; + while (*p) { + char c = *p; + if (in_str) { + if (e) e = 0; + else if (c == '\\') e = 1; + else if (c == '"') in_str = 0; + p++; continue; + } + if (c == '"') { in_str = 1; p++; continue; } + if (c == open) depth++; + else if (c == close) { depth--; p++; if (!depth) return p; continue; } + p++; + } + return p; + } + while (*p && *p != ',' && *p != '}' && *p != ']' && + *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r') p++; + return p; +} + +static const char* json_find_key(const char* s, const char* key) { + if (!s || !key) return NULL; + size_t klen = strlen(key); + int depth = 0, in_str = 0, escape = 0; + const char* p = s; + while (*p) { + char c = *p; + if (in_str) { + if (escape) escape = 0; + else if (c == '\\') escape = 1; + else if (c == '"') { + p++; in_str = 0; continue; + } + p++; continue; + } + if (c == '"') { + const char* str_start = p + 1; + const char* q = str_start; + int e = 0; + while (*q) { + if (e) { e = 0; q++; continue; } + if (*q == '\\') { e = 1; q++; continue; } + if (*q == '"') break; + q++; + } + size_t slen = (size_t)(q - str_start); + const char* after = (*q == '"') ? q + 1 : q; + if (depth == 1 && slen == klen && strncmp(str_start, key, klen) == 0) { + const char* r = after; + while (*r == ' ' || *r == '\t' || *r == '\n' || *r == '\r') r++; + if (*r == ':') { + r++; + while (*r == ' ' || *r == '\t' || *r == '\n' || *r == '\r') r++; + return r; + } + } + p = after; continue; + } + if (c == '{' || c == '[') depth++; + else if (c == '}' || c == ']') depth--; + p++; + } + return NULL; +} + +el_val_t json_get_string(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + if (!p || *p != '"') return el_wrap_str(el_strdup("")); + JsonParser jp = { p, json + (json ? strlen(json) : 0), 0 }; + char* parsed = jp_parse_string_raw(&jp); + if (jp.err) { free(parsed); return el_wrap_str(el_strdup("")); } + return el_wrap_str(parsed); +} + +el_val_t json_get_int(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + if (!p || *p == '"' || *p == '{' || *p == '[') return 0; + return (el_val_t)strtoll(p, NULL, 10); +} + +el_val_t json_get_float(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + if (!p || *p == '"' || *p == '{' || *p == '[') return 0; + return el_from_float(strtod(p, NULL)); +} + +el_val_t json_get_bool(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + if (!p) return 0; + return (el_val_t)(strncmp(p, "true", 4) == 0); +} + +el_val_t json_get_raw(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + if (!p) return el_wrap_str(el_strdup("")); + const char* end = json_skip_value(p); + size_t n = (size_t)(end - p); + char* out = el_strbuf(n); + memcpy(out, p, n); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t json_get(el_val_t json, el_val_t key) { + return json_get_raw(json, key); +} + +/* Simple JSON number / scalar parser helpers for json_parse / json_stringify */ + +el_val_t json_parse(el_val_t s) { + /* Minimal: return the string verbatim (caller accesses via json_get_*). */ + return s; +} + +el_val_t json_stringify(el_val_t v) { + /* Basic: if it already looks like a string, return it. */ + const char* s = EL_CSTR(v); + return s ? v : EL_STR("{}"); +} + +el_val_t json_set(el_val_t json_str, el_val_t key, el_val_t value) { + /* Stub: returns the original JSON unchanged. */ + return json_str; +} + +el_val_t json_array_len(el_val_t json_str) { + const char* s = EL_CSTR(json_str); + if (!s || *s != '[') return 0; + int64_t cnt = 0; + int depth = 0, in_str = 0, e = 0; + const char* p = s; + while (*p) { + char c = *p; + if (in_str) { + if (e) e = 0; else if (c == '\\') e = 1; else if (c == '"') in_str = 0; + p++; continue; + } + if (c == '"') { in_str = 1; p++; continue; } + if (c == '[' || c == '{') { if (depth++ == 0 && c == '[') { p++; continue; } } + else if (c == ']' || c == '}') { if (--depth == 0) break; } + else if (c == ',' && depth == 1) cnt++; + p++; + } + /* If we saw any content, count = separators + 1 */ + if (depth == 0) { /* empty or done */ } + /* Simpler: count commas at depth 1 + 1 if non-empty */ + /* Re-scan for simplicity */ + cnt = 0; + depth = 0; in_str = 0; e = 0; + p = s; + int has_content = 0; + while (*p) { + char c = *p; + if (in_str) { + if (e) e = 0; else if (c == '\\') e = 1; else if (c == '"') in_str = 0; + p++; continue; + } + if (c == '"') { in_str = 1; p++; continue; } + if (c == '[' || c == '{') depth++; + else if (c == ']' || c == '}') { + depth--; + if (depth == 0) break; + } + if (depth == 1) { + if (c != '[' && c != ' ' && c != '\t' && c != '\n' && c != '\r') has_content = 1; + if (c == ',') cnt++; + } + p++; + } + return has_content ? cnt + 1 : 0; +} + +el_val_t json_array_get(el_val_t json_str, el_val_t index) { + const char* s = EL_CSTR(json_str); + if (!s || *s != '[') return 0; + int64_t target = (int64_t)index; + int64_t cur = 0; + int depth = 0, in_str = 0, e = 0; + const char* p = s; + while (*p) { + char c = *p; + if (in_str) { + if (e) e = 0; else if (c == '\\') e = 1; else if (c == '"') in_str = 0; + p++; continue; + } + if (c == '"') { in_str = 1; } + if (c == '[' || c == '{') depth++; + else if (c == ']' || c == '}') { if (--depth == 0) break; } + if (depth == 1 && (p == s + 1 || c == ',')) { + if (c == ',') { cur++; p++; while (*p == ' ' || *p == '\t' || *p == '\n') p++; } + else { p++; while (*p == ' ' || *p == '\t' || *p == '\n') p++; } + if (cur == target) { + const char* end = json_skip_value(p); + size_t n = (size_t)(end - p); + char* out = el_strbuf(n); + memcpy(out, p, n); out[n] = '\0'; + return el_wrap_str(out); + } + continue; + } + p++; + } + return 0; +} + +el_val_t json_array_get_string(el_val_t json_str, el_val_t index) { + el_val_t raw = json_array_get(json_str, index); + if (!raw) return el_wrap_str(el_strdup("")); + const char* s = EL_CSTR(raw); + if (!s || *s != '"') return raw; + JsonParser jp = { s, s + strlen(s), 0 }; + char* parsed = jp_parse_string_raw(&jp); + return el_wrap_str(parsed); +} + +el_val_t json_escape_string(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("\"\"")); + size_t n = strlen(s); + char* out = el_strbuf(n * 6 + 4); + char* p = out; + *p++ = '"'; + for (size_t i = 0; i < n; i++) { + unsigned char c = (unsigned char)s[i]; + switch (c) { + case '"': *p++ = '\\'; *p++ = '"'; break; + case '\\': *p++ = '\\'; *p++ = '\\'; break; + case '\n': *p++ = '\\'; *p++ = 'n'; break; + case '\r': *p++ = '\\'; *p++ = 'r'; break; + case '\t': *p++ = '\\'; *p++ = 't'; break; + default: + if (c < 0x20) { + p += sprintf(p, "\\u%04x", c); + } else { + *p++ = (char)c; + } + } + } + *p++ = '"'; *p = '\0'; + return el_wrap_str(out); +} + +el_val_t json_build_object(el_val_t kvs) { return kvs; } +el_val_t json_build_array(el_val_t items) { return items; } + +/* ── Environment / process ───────────────────────────────────────────────── */ + +el_val_t env(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return el_wrap_str(el_strdup("")); + const char* v = getenv(k); + return el_wrap_str(el_strdup(v ? v : "")); +} + +el_val_t exit_program(el_val_t code) { + exit((int)(int64_t)code); + return 0; +} + +/* Args store — populated by el_runtime_init_args */ +static el_val_t _el_args_list = 0; + +void el_runtime_init_args(int argc, char** argv) { + _el_args_list = el_list_empty(); + for (int i = 1; i < argc; i++) { + _el_args_list = el_list_append(_el_args_list, EL_STR(argv[i])); + } +} + +el_val_t args(void) { + if (!_el_args_list) _el_args_list = el_list_empty(); + return _el_args_list; +} + +/* ── HTML helpers (stubs) ────────────────────────────────────────────────── */ + +el_val_t el_html_sanitize(el_val_t input_html, el_val_t allowlist_json) { return input_html; } +el_val_t html_raw(el_val_t s) { return s; } +el_val_t html_escape(el_val_t s) { return s; } +el_val_t url_encode(el_val_t s) { return s; } +el_val_t url_decode(el_val_t s) { return s; } + +/* ── Filesystem stubs ────────────────────────────────────────────────────── */ + +el_val_t fs_read(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p) return el_wrap_str(el_strdup("")); + FILE* f = fopen(p, "rb"); + if (!f) return el_wrap_str(el_strdup("")); + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + if (sz <= 0) { fclose(f); return el_wrap_str(el_strdup("")); } + char* buf = malloc((size_t)sz + 1); + if (!buf) { fclose(f); return el_wrap_str(el_strdup("")); } + size_t got = fread(buf, 1, (size_t)sz, f); + buf[got] = '\0'; + fclose(f); + el_arena_track(buf); + return EL_STR(buf); +} + +el_val_t fs_write(el_val_t path, el_val_t content) { + const char* p = EL_CSTR(path); + const char* c = EL_CSTR(content); + if (!p || !c) return 0; + FILE* f = fopen(p, "wb"); + if (!f) return 0; + fputs(c, f); + fclose(f); + return 1; +} + +el_val_t fs_exists(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p) return 0; + FILE* f = fopen(p, "rb"); + if (!f) return 0; + fclose(f); + return 1; +} + +el_val_t fs_list(el_val_t path) { return el_wrap_str(el_strdup("")); } +el_val_t fs_list_json(el_val_t path) { return el_wrap_str(el_strdup("[]")); } +el_val_t fs_mkdir(el_val_t path) { return 0; } +el_val_t fs_write_bytes(el_val_t path, el_val_t bytes, el_val_t n) { return 0; } + +/* ── HTTP stubs (no network in Win32 GUI app) ────────────────────────────── */ + +el_val_t http_get(el_val_t url) { return el_wrap_str(el_strdup("{\"error\":\"no http\"}")); } +el_val_t http_post(el_val_t url, el_val_t body) { return http_get(url); } +el_val_t http_post_json(el_val_t url, el_val_t body) { return http_get(url); } +el_val_t http_get_with_headers(el_val_t url, el_val_t h) { return http_get(url); } +el_val_t http_post_with_headers(el_val_t url, el_val_t b, el_val_t h) { return http_get(url); } +el_val_t http_post_json_with_headers(el_val_t url, el_val_t h, el_val_t b) { return http_get(url); } +el_val_t http_post_form_auth(el_val_t url, el_val_t b, el_val_t a) { return http_get(url); } +el_val_t http_delete(el_val_t url) { return http_get(url); } +el_val_t http_serve(el_val_t port, el_val_t handler) { return 0; } +el_val_t http_set_handler(el_val_t name) { return 0; } +el_val_t http_serve_v2(el_val_t port, el_val_t handler) { return 0; } +el_val_t http_set_handler_v2(el_val_t name) { return 0; } +el_val_t http_response(el_val_t status, el_val_t headers_json, el_val_t body) { return body; } +void el_seed_set_http_conn_fd(int fd) { (void)fd; } +el_val_t http_post_to_file(el_val_t url, el_val_t b, el_val_t h, el_val_t out) { return 0; } +el_val_t http_get_to_file(el_val_t url, el_val_t h, el_val_t out) { return 0; } + +/* ── Time stubs ──────────────────────────────────────────────────────────── */ + +#include + +el_val_t time_now(void) { return (el_val_t)time(NULL); } +el_val_t time_now_utc(void) { return time_now(); } +el_val_t now_ns(void) { return (el_val_t)(time(NULL) * (int64_t)1000000000LL); } +el_val_t el_now_instant(void) { return now_ns(); } +el_val_t now(void) { return el_now_instant(); } +el_val_t unix_seconds(el_val_t n) { return n * 1000000000LL; } +el_val_t unix_millis(el_val_t n) { return n * 1000000LL; } +el_val_t unix_timestamp(void) { return (el_val_t)time(NULL); } +el_val_t sleep_secs(el_val_t secs) { return 0; } +el_val_t sleep_ms(el_val_t ms) { return 0; } +el_val_t el_sleep_duration(el_val_t dur) { return 0; } +el_val_t time_format(el_val_t ts, el_val_t fmt) { return el_wrap_str(el_strdup("")); } +el_val_t time_to_parts(el_val_t ts) { return el_wrap_str(el_strdup("{}")); } +el_val_t time_from_parts(el_val_t s, el_val_t ns, el_val_t tz) { return s; } +el_val_t time_add(el_val_t ts, el_val_t n, el_val_t unit) { return ts; } +el_val_t time_diff(el_val_t a, el_val_t b, el_val_t unit) { return a - b; } +el_val_t instant_from_iso8601(el_val_t s) { return 0; } +el_val_t el_duration_from_nanos(el_val_t ns) { return ns; } +el_val_t duration_seconds(el_val_t n) { return n * 1000000000LL; } +el_val_t duration_millis(el_val_t n) { return n * 1000000LL; } +el_val_t duration_nanos(el_val_t n) { return n; } +el_val_t el_instant_add_dur(el_val_t i, el_val_t d) { return i + d; } +el_val_t el_instant_sub_dur(el_val_t i, el_val_t d) { return i - d; } +el_val_t el_instant_diff(el_val_t a, el_val_t b) { return a - b; } +el_val_t el_duration_add(el_val_t a, el_val_t b) { return a + b; } +el_val_t el_duration_sub(el_val_t a, el_val_t b) { return a - b; } +el_val_t el_duration_scale(el_val_t d, el_val_t s) { return d * s; } +el_val_t el_duration_div(el_val_t d, el_val_t s) { return s ? d / s : 0; } +el_val_t el_instant_lt(el_val_t a, el_val_t b) { return a < b; } +el_val_t el_instant_le(el_val_t a, el_val_t b) { return a <= b; } +el_val_t el_instant_gt(el_val_t a, el_val_t b) { return a > b; } +el_val_t el_instant_ge(el_val_t a, el_val_t b) { return a >= b; } +el_val_t el_instant_eq(el_val_t a, el_val_t b) { return a == b; } +el_val_t el_instant_ne(el_val_t a, el_val_t b) { return a != b; } +el_val_t el_duration_lt(el_val_t a, el_val_t b) { return a < b; } +el_val_t el_duration_le(el_val_t a, el_val_t b) { return a <= b; } +el_val_t el_duration_gt(el_val_t a, el_val_t b) { return a > b; } +el_val_t el_duration_ge(el_val_t a, el_val_t b) { return a >= b; } +el_val_t el_duration_eq(el_val_t a, el_val_t b) { return a == b; } +el_val_t el_duration_ne(el_val_t a, el_val_t b) { return a != b; } +el_val_t instant_to_unix_seconds(el_val_t i) { return i / 1000000000LL; } +el_val_t instant_to_unix_millis(el_val_t i) { return i / 1000000LL; } +el_val_t instant_to_iso8601(el_val_t i) { return el_wrap_str(el_strdup("")); } +el_val_t duration_to_seconds(el_val_t d) { return d / 1000000000LL; } +el_val_t duration_to_millis(el_val_t d) { return d / 1000000LL; } +el_val_t duration_to_nanos(el_val_t d) { return d; } + +/* ── Calendar stubs ──────────────────────────────────────────────────────── */ + +el_val_t zone(el_val_t id) { return id; } +el_val_t zone_utc(void) { return EL_STR("UTC"); } +el_val_t zone_local(void) { return EL_STR("local"); } +el_val_t zone_offset(el_val_t h, el_val_t m) { return 0; } +el_val_t earth_calendar(el_val_t z) { return 0; } +el_val_t earth_calendar_default(void) { return 0; } +el_val_t mars_calendar(void) { return 0; } +el_val_t cycle_calendar(el_val_t p) { return 0; } +el_val_t no_cycle_calendar(void) { return 0; } +el_val_t relative_calendar(el_val_t e) { return 0; } +el_val_t now_in(el_val_t cal) { return 0; } +el_val_t in_calendar(el_val_t inst, el_val_t cal) { return 0; } +el_val_t cal_format(el_val_t ct, el_val_t pattern) { return el_wrap_str(el_strdup("")); } +el_val_t cal_to_instant(el_val_t ct) { return 0; } +el_val_t cal_cycle_phase(el_val_t ct) { return 0; } +el_val_t cal_in(el_val_t ct, el_val_t cal) { return 0; } +el_val_t local_date(el_val_t y, el_val_t m, el_val_t d) { return 0; } +el_val_t local_time(el_val_t h, el_val_t m, el_val_t s, el_val_t ns) { return 0; } +el_val_t local_datetime(el_val_t date, el_val_t time) { return 0; } +el_val_t zoned(el_val_t date, el_val_t time, el_val_t cal) { return 0; } +el_val_t local_date_year(el_val_t ld) { return 0; } +el_val_t local_date_month(el_val_t ld) { return 0; } +el_val_t local_date_day(el_val_t ld) { return 0; } +el_val_t local_time_hour(el_val_t lt) { return 0; } +el_val_t local_time_minute(el_val_t lt) { return 0; } +el_val_t local_time_second(el_val_t lt) { return 0; } +el_val_t local_time_nanos(el_val_t lt) { return 0; } +el_val_t el_local_date_add_dur(el_val_t ld, el_val_t dur) { return ld; } +el_val_t el_local_time_add_dur(el_val_t lt, el_val_t dur) { return lt; } +el_val_t el_local_date_lt(el_val_t a, el_val_t b) { return a < b; } +el_val_t el_local_date_eq(el_val_t a, el_val_t b) { return a == b; } +el_val_t rhythm_cycle_start(void) { return 0; } +el_val_t rhythm_cycle_phase(el_val_t p) { return 0; } +el_val_t rhythm_duration(el_val_t d) { return 0; } +el_val_t rhythm_session_start(void) { return 0; } +el_val_t rhythm_event(el_val_t name) { return 0; } +el_val_t rhythm_and(el_val_t a, el_val_t b) { return 0; } +el_val_t rhythm_or(el_val_t a, el_val_t b) { return 0; } +el_val_t rhythm_weekday(el_val_t day) { return 0; } +el_val_t rhythm_weekly_at(el_val_t day, el_val_t h, el_val_t m) { return 0; } +el_val_t rhythm_next_after(el_val_t r, el_val_t after, el_val_t cal) { return 0; } +el_val_t rhythm_matches(el_val_t r, el_val_t ct) { return 0; } + +/* ── UUID stubs ──────────────────────────────────────────────────────────── */ + +el_val_t uuid_new(void) { return el_wrap_str(el_strdup("00000000-0000-0000-0000-000000000000")); } +el_val_t uuid_v4(void) { return uuid_new(); } + +/* ── State K/V stubs ─────────────────────────────────────────────────────── */ + +el_val_t state_set(el_val_t key, el_val_t value) { return value; } +el_val_t state_get(el_val_t key) { return 0; } +el_val_t state_del(el_val_t key) { return 0; } +el_val_t state_keys(void) { return el_wrap_str(el_strdup("[]")); } +el_val_t state_has(el_val_t key) { return 0; } +el_val_t state_get_or(el_val_t key, el_val_t def) { return def; } + +/* ── TTL cache stubs ─────────────────────────────────────────────────────── */ + +el_val_t ttl_cache_set(el_val_t key, el_val_t value) { return value; } +el_val_t ttl_cache_get(el_val_t key, el_val_t max_age) { return 0; } +el_val_t ttl_cache_age(el_val_t key) { return -1; } diff --git a/lang/el-compiler/runtime/el_sdl2.c b/lang/el-compiler/runtime/el_sdl2.c new file mode 100644 index 0000000..6f9a70d --- /dev/null +++ b/lang/el-compiler/runtime/el_sdl2.c @@ -0,0 +1,1360 @@ +/* + * el_sdl2.c — SDL2 backend for the el native widget system. + * + * This file implements the SDL2 widget layer that el_seed.c calls through to + * when EL_TARGET_SDL2 is defined. It is the embedded/Pi counterpart to + * el_appkit.m (macOS) and el_gtk4.c (Linux desktop). + * + * Architecture: + * el program (el code) + * → __widget_* C builtins in el_seed.c + * → el_sdl2_* C functions declared here + * → SDL2 pixel drawing (SDL_RenderFillRect, TTF_RenderUTF8_Blended) + * + * SDL2 has no widget toolkit — it only draws pixels. This bridge implements + * widgets as drawn primitives: rectangles, text, borders. Each "widget" is a + * logical node in a retained layout tree. On any state change, the whole scene + * re-renders via el_sdl2_layout + el_sdl2_render_widget. + * + * Widget handles: every widget is an int64_t slot index into g_widgets[]. + * Slot 0 is reserved; valid handles are 1..EL_SDL2_MAX_WIDGETS-1. -1 = invalid. + * + * Threading: SDL2 requires that all rendering happen on the thread that called + * SDL_Init. __native_run_loop runs on the main thread and never returns. + * Callback functions fired by the event loop are called synchronously from the + * same thread — no locking required. + * + * Font loading: DejaVu or Liberation Sans searched in standard Linux paths. + * Falls back to a NULL font (text omitted) if none found. + * + * Target: Raspberry Pi Zero 2W, 512 MB RAM, no desktop environment, raw + * framebuffer via SDL2's KMS/DRM or fbdev driver. + * + * Compile: + * gcc -DEL_TARGET_SDL2 $(sdl2-config --cflags) -c el_sdl2.c -o el_sdl2.o + * Link: + * $(sdl2-config --libs) -lSDL2_ttf -lSDL2_image -ldl + */ + +#ifdef EL_TARGET_SDL2 + +#include +#include +#include +#include +#include +#include +#include +#include +#include "el_runtime.h" + +/* ── Widget type constants ────────────────────────────────────────────────── */ + +#define EL_WIDGET_NONE 0 +#define EL_WIDGET_WINDOW 1 +#define EL_WIDGET_VSTACK 2 +#define EL_WIDGET_HSTACK 3 +#define EL_WIDGET_ZSTACK 4 +#define EL_WIDGET_SCROLL 5 +#define EL_WIDGET_LABEL 6 +#define EL_WIDGET_BUTTON 7 +#define EL_WIDGET_TEXT_FIELD 8 +#define EL_WIDGET_TEXT_AREA 9 +#define EL_WIDGET_IMAGE 10 +#define EL_WIDGET_DIVIDER 11 +#define EL_WIDGET_SPACER 12 + +/* Layout direction stored in layout_type */ +#define EL_LAYOUT_NONE 0 +#define EL_LAYOUT_VSTACK 1 +#define EL_LAYOUT_HSTACK 2 +#define EL_LAYOUT_ZSTACK 3 + +#define EL_SDL2_MAX_WIDGETS 4096 + +/* ── Widget struct ────────────────────────────────────────────────────────── */ + +typedef struct { + int type; /* EL_WIDGET_* */ + SDL_Rect bounds; /* computed layout position */ + char text[512]; /* label text, button label, placeholder, img path */ + char cb_click[256]; /* El callback fn name — button click / text submit */ + char cb_change[256]; /* El callback fn name — text change */ + char cb_submit[256]; /* El callback fn name — text submit (stored here, mirrored to cb_click) */ + /* foreground colour */ + uint8_t fg_r, fg_g, fg_b, fg_a; + /* background colour */ + uint8_t bg_r, bg_g, bg_b, bg_a; + int font_size; + char font_family[128]; + int font_bold; + int padding_t, padding_r, padding_b, padding_l; + int fixed_width, fixed_height; /* 0 = auto */ + int flex; + int corner_radius; + int disabled; + int hidden; + /* tree */ + int children[64]; + int child_count; + int parent; /* -1 = root */ + /* layout when this node IS a container */ + int layout_type; + int layout_spacing; + /* text field / text area state */ + char input_buf[1024]; + int input_focused; + int cursor_pos; + /* hover state for button highlight */ + int hovered; + /* cached texture for image (freed on destroy) */ + SDL_Texture *img_texture; +} ElWidget; + +/* ── Globals ──────────────────────────────────────────────────────────────── */ + +static ElWidget g_widgets[EL_SDL2_MAX_WIDGETS]; +static int g_slot_used[EL_SDL2_MAX_WIDGETS]; +static SDL_Window *g_sdl_window = NULL; +static SDL_Renderer *g_renderer = NULL; +static TTF_Font *g_font_default = NULL; +static int g_root_widget = -1; +static int g_focused_widget = -1; +static int g_dirty = 1; /* 1 = needs redraw */ +static int g_win_w = 800; +static int g_win_h = 600; + +/* ── Slot management ──────────────────────────────────────────────────────── */ + +static int64_t el_sdl2_alloc_slot(int type) { + for (int i = 1; i < EL_SDL2_MAX_WIDGETS; i++) { + if (!g_slot_used[i]) { + g_slot_used[i] = 1; + ElWidget *w = &g_widgets[i]; + memset(w, 0, sizeof(*w)); + w->type = type; + w->parent = -1; + w->layout_type = EL_LAYOUT_NONE; + /* default colours: white fg, transparent bg */ + w->fg_r = 255; w->fg_g = 255; w->fg_b = 255; w->fg_a = 255; + w->bg_r = 0; w->bg_g = 0; w->bg_b = 0; w->bg_a = 0; + w->font_size = 14; + return (int64_t)i; + } + } + return -1; /* full */ +} + +static ElWidget *el_sdl2_get(int64_t handle) { + if (handle <= 0 || handle >= EL_SDL2_MAX_WIDGETS) return NULL; + if (!g_slot_used[handle]) return NULL; + return &g_widgets[handle]; +} + +static void el_sdl2_free_slot(int64_t handle) { + if (handle <= 0 || handle >= EL_SDL2_MAX_WIDGETS) return; + ElWidget *w = &g_widgets[handle]; + if (w->img_texture) { + SDL_DestroyTexture(w->img_texture); + w->img_texture = NULL; + } + g_slot_used[handle] = 0; +} + +/* ── Font loading ─────────────────────────────────────────────────────────── */ + +static TTF_Font *el_sdl2_load_font(int size) { + static const char *paths[] = { + "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", + "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf", + "/usr/share/fonts/TTF/DejaVuSans.ttf", + "/usr/share/fonts/dejavu/DejaVuSans.ttf", + "/usr/share/fonts/truetype/freefont/FreeSans.ttf", + "/System/Library/Fonts/Helvetica.ttc", /* macOS dev */ + NULL + }; + for (int i = 0; paths[i]; i++) { + TTF_Font *f = TTF_OpenFont(paths[i], size); + if (f) return f; + } + return NULL; +} + +static TTF_Font *el_sdl2_get_font(int size) { + if (size <= 0) size = 14; + /* Simple approach: reuse the default font if size matches, else open again. + * For Pi Zero with one app, this is sufficient. */ + if (g_font_default && size == 14) return g_font_default; + return el_sdl2_load_font(size); +} + +/* ── Callback dispatch ────────────────────────────────────────────────────── */ + +static void el_sdl2_fire_cb(const char *fn_name, int64_t handle, const char *data) { + if (!fn_name || !fn_name[0]) return; + typedef el_val_t (*el_cb_fn)(el_val_t, el_val_t); + el_cb_fn fn = (el_cb_fn)(uintptr_t)dlsym(RTLD_DEFAULT, fn_name); + if (fn) { + el_val_t d = data ? (el_val_t)(uintptr_t)data : (el_val_t)0; + fn((el_val_t)handle, d); + g_dirty = 1; + } +} + +/* ── Rounded rectangle helpers ────────────────────────────────────────────── */ + +/* Draw a filled rounded rectangle approximation using SDL_RenderFillRect. + * The approach: draw the centre cross and fill the 4 corner arcs by drawing + * small squares step-by-step. Sufficient for Pi Zero where SDL_gfx may not + * be available. */ +static void el_sdl2_fill_rounded_rect(SDL_Renderer *r, const SDL_Rect *rect, + int radius, + uint8_t cr, uint8_t cg, uint8_t cb, uint8_t ca) { + if (radius <= 0 || rect->w <= 0 || rect->h <= 0) { + SDL_SetRenderDrawColor(r, cr, cg, cb, ca); + SDL_RenderFillRect(r, rect); + return; + } + if (radius > rect->w / 2) radius = rect->w / 2; + if (radius > rect->h / 2) radius = rect->h / 2; + + SDL_SetRenderDrawColor(r, cr, cg, cb, ca); + + /* Horizontal band (full width, inner height minus corners) */ + SDL_Rect horiz = {rect->x, rect->y + radius, rect->w, rect->h - 2 * radius}; + SDL_RenderFillRect(r, &horiz); + + /* Top band */ + SDL_Rect top = {rect->x + radius, rect->y, rect->w - 2 * radius, radius}; + SDL_RenderFillRect(r, &top); + + /* Bottom band */ + SDL_Rect bot = {rect->x + radius, rect->y + rect->h - radius, rect->w - 2 * radius, radius}; + SDL_RenderFillRect(r, &bot); + + /* Draw quarter circles at each corner using row-by-row filling. + * For each row dy in [0, radius), compute the chord width from circle eq. */ + for (int dy = 0; dy < radius; dy++) { + /* x-extent of circle arc at this dy from centre */ + double dx = radius - 1 - (int)(0.5 + (double)radius * + (1.0 - ((double)(radius - 1 - dy) * (double)(radius - 1 - dy)) / + ((double)radius * (double)radius))); + int fill_w = radius - (int)dx; + if (fill_w < 1) fill_w = 1; + + /* top-left corner */ + SDL_Rect tl = {rect->x + radius - fill_w, rect->y + dy, fill_w, 1}; + SDL_RenderFillRect(r, &tl); + /* top-right corner */ + SDL_Rect tr = {rect->x + rect->w - radius, rect->y + dy, fill_w, 1}; + SDL_RenderFillRect(r, &tr); + /* bottom-left corner */ + SDL_Rect bl = {rect->x + radius - fill_w, rect->y + rect->h - 1 - dy, fill_w, 1}; + SDL_RenderFillRect(r, &bl); + /* bottom-right corner */ + SDL_Rect br = {rect->x + rect->w - radius, rect->y + rect->h - 1 - dy, fill_w, 1}; + SDL_RenderFillRect(r, &br); + } +} + +/* Draw a 1px border around a (possibly rounded) rect */ +static void el_sdl2_draw_border(SDL_Renderer *r, const SDL_Rect *rect, + uint8_t cr, uint8_t cg, uint8_t cb, uint8_t ca) { + SDL_SetRenderDrawColor(r, cr, cg, cb, ca); + SDL_RenderDrawRect(r, rect); +} + +/* ── Layout engine ────────────────────────────────────────────────────────── */ + +/* Measure the natural size of a leaf widget. + * Returns 0 if size could not be determined. */ +static void el_sdl2_measure(int slot, int *out_w, int *out_h) { + ElWidget *w = el_sdl2_get(slot); + if (!w) { *out_w = 0; *out_h = 0; return; } + + int fs = w->font_size > 0 ? w->font_size : 14; + TTF_Font *font = el_sdl2_get_font(fs); + + switch (w->type) { + case EL_WIDGET_LABEL: { + if (font && w->text[0]) { + int tw = 0, th = 0; + TTF_SizeUTF8(font, w->text, &tw, &th); + *out_w = tw + w->padding_l + w->padding_r; + *out_h = th + w->padding_t + w->padding_b; + } else { + *out_w = 8 + w->padding_l + w->padding_r; + *out_h = fs + 4 + w->padding_t + w->padding_b; + } + break; + } + case EL_WIDGET_BUTTON: { + if (font && w->text[0]) { + int tw = 0, th = 0; + TTF_SizeUTF8(font, w->text, &tw, &th); + *out_w = tw + 32 + w->padding_l + w->padding_r; + *out_h = th + 20 + w->padding_t + w->padding_b; + } else { + *out_w = 80 + w->padding_l + w->padding_r; + *out_h = fs + 20 + w->padding_t + w->padding_b; + } + break; + } + case EL_WIDGET_TEXT_FIELD: + case EL_WIDGET_TEXT_AREA: { + *out_w = 200; /* default — will stretch with flex */ + *out_h = fs + 12 + w->padding_t + w->padding_b; + if (w->type == EL_WIDGET_TEXT_AREA) *out_h = (fs + 4) * 4 + w->padding_t + w->padding_b; + break; + } + case EL_WIDGET_IMAGE: { + *out_w = 64; + *out_h = 64; + break; + } + case EL_WIDGET_SPACER: { + *out_w = 0; + *out_h = 0; + break; + } + case EL_WIDGET_DIVIDER: { + *out_w = 2; + *out_h = 2; + break; + } + default: { + *out_w = 0; + *out_h = 0; + break; + } + } + + /* Fixed dimensions override natural size */ + if (w->fixed_width > 0) *out_w = w->fixed_width; + if (w->fixed_height > 0) *out_h = w->fixed_height; +} + +/* Forward declaration */ +static void el_sdl2_layout(int slot, SDL_Rect available); + +static void el_sdl2_layout_vstack(ElWidget *w, SDL_Rect inner) { + int spacing = w->layout_spacing; + int n = w->child_count; + if (n == 0) return; + + /* First pass: measure non-flex children and sum flex weights */ + int total_fixed_h = 0; + int total_flex = 0; + for (int i = 0; i < n; i++) { + int ci = w->children[i]; + ElWidget *cw = el_sdl2_get(ci); + if (!cw || cw->hidden) continue; + if (cw->flex > 0) { + total_flex += cw->flex; + } else { + int mw, mh; + el_sdl2_measure(ci, &mw, &mh); + total_fixed_h += mh; + } + } + /* Count spacing gaps */ + int gaps = (n > 1) ? (n - 1) * spacing : 0; + int flex_pool = inner.h - total_fixed_h - gaps; + if (flex_pool < 0) flex_pool = 0; + + /* Second pass: assign rects */ + int y = inner.y; + for (int i = 0; i < n; i++) { + int ci = w->children[i]; + ElWidget *cw = el_sdl2_get(ci); + if (!cw) continue; + if (cw->hidden) { + SDL_Rect z = {0, 0, 0, 0}; + cw->bounds = z; + continue; + } + int ch; + if (cw->flex > 0 && total_flex > 0) { + ch = (flex_pool * cw->flex) / total_flex; + } else { + int mw, mh; + el_sdl2_measure(ci, &mw, &mh); + ch = mh; + } + SDL_Rect child_rect = {inner.x, y, inner.w, ch}; + el_sdl2_layout(ci, child_rect); + y += ch + spacing; + } +} + +static void el_sdl2_layout_hstack(ElWidget *w, SDL_Rect inner) { + int spacing = w->layout_spacing; + int n = w->child_count; + if (n == 0) return; + + int total_fixed_w = 0; + int total_flex = 0; + for (int i = 0; i < n; i++) { + int ci = w->children[i]; + ElWidget *cw = el_sdl2_get(ci); + if (!cw || cw->hidden) continue; + if (cw->flex > 0) { + total_flex += cw->flex; + } else { + int mw, mh; + el_sdl2_measure(ci, &mw, &mh); + total_fixed_w += mw; + } + } + int gaps = (n > 1) ? (n - 1) * spacing : 0; + int flex_pool = inner.w - total_fixed_w - gaps; + if (flex_pool < 0) flex_pool = 0; + + int x = inner.x; + for (int i = 0; i < n; i++) { + int ci = w->children[i]; + ElWidget *cw = el_sdl2_get(ci); + if (!cw) continue; + if (cw->hidden) { + SDL_Rect z = {0, 0, 0, 0}; + cw->bounds = z; + continue; + } + int cw_size; + if (cw->flex > 0 && total_flex > 0) { + cw_size = (flex_pool * cw->flex) / total_flex; + } else { + int mw, mh; + el_sdl2_measure(ci, &mw, &mh); + cw_size = mw; + } + SDL_Rect child_rect = {x, inner.y, cw_size, inner.h}; + el_sdl2_layout(ci, child_rect); + x += cw_size + spacing; + } +} + +static void el_sdl2_layout(int slot, SDL_Rect available) { + ElWidget *w = el_sdl2_get(slot); + if (!w) return; + + if (w->hidden) { + SDL_Rect z = {0, 0, 0, 0}; + w->bounds = z; + return; + } + + /* Apply fixed dimensions if set */ + if (w->fixed_width > 0) available.w = w->fixed_width; + if (w->fixed_height > 0) available.h = w->fixed_height; + + w->bounds = available; + + /* For containers: compute inner rect after padding, then layout children */ + SDL_Rect inner = { + available.x + w->padding_l, + available.y + w->padding_t, + available.w - w->padding_l - w->padding_r, + available.h - w->padding_t - w->padding_b + }; + if (inner.w < 0) inner.w = 0; + if (inner.h < 0) inner.h = 0; + + switch (w->layout_type) { + case EL_LAYOUT_VSTACK: + el_sdl2_layout_vstack(w, inner); + break; + case EL_LAYOUT_HSTACK: + el_sdl2_layout_hstack(w, inner); + break; + case EL_LAYOUT_ZSTACK: + /* Each child gets the full inner rect */ + for (int i = 0; i < w->child_count; i++) { + el_sdl2_layout(w->children[i], inner); + } + break; + default: + /* Leaf: layout_type NONE means no children. + * WINDOW/SCROLL/etc. that has a content child: give it full inner. */ + if (w->type == EL_WIDGET_WINDOW || w->type == EL_WIDGET_SCROLL) { + for (int i = 0; i < w->child_count; i++) { + el_sdl2_layout(w->children[i], inner); + } + } + break; + } +} + +/* ── Render pass ──────────────────────────────────────────────────────────── */ + +static void el_sdl2_render_text_in_rect(TTF_Font *font, const char *text, + SDL_Color col, SDL_Rect dst) { + if (!font || !text || !text[0]) return; + SDL_Surface *surf = TTF_RenderUTF8_Blended(font, text, col); + if (!surf) return; + SDL_Texture *tex = SDL_CreateTextureFromSurface(g_renderer, surf); + SDL_FreeSurface(surf); + if (!tex) return; + + int tw, th; + SDL_QueryTexture(tex, NULL, NULL, &tw, &th); + + /* Clip to dst rect */ + SDL_Rect src_rect = {0, 0, tw, th}; + SDL_Rect dst_rect = dst; + /* Centre vertically; left-align horizontally */ + dst_rect.y = dst.y + (dst.h - th) / 2; + dst_rect.h = th; + dst_rect.w = tw; + if (dst_rect.w > dst.w) { + dst_rect.w = dst.w; + src_rect.w = dst.w; + } + + SDL_RenderSetClipRect(g_renderer, &dst); + SDL_RenderCopy(g_renderer, tex, &src_rect, &dst_rect); + SDL_RenderSetClipRect(g_renderer, NULL); + SDL_DestroyTexture(tex); +} + +static void el_sdl2_render_text_centered(TTF_Font *font, const char *text, + SDL_Color col, SDL_Rect dst) { + if (!font || !text || !text[0]) return; + SDL_Surface *surf = TTF_RenderUTF8_Blended(font, text, col); + if (!surf) return; + SDL_Texture *tex = SDL_CreateTextureFromSurface(g_renderer, surf); + SDL_FreeSurface(surf); + if (!tex) return; + + int tw, th; + SDL_QueryTexture(tex, NULL, NULL, &tw, &th); + + SDL_Rect src_rect = {0, 0, tw, th}; + if (src_rect.w > dst.w) src_rect.w = dst.w; + + SDL_Rect dst_rect; + dst_rect.x = dst.x + (dst.w - src_rect.w) / 2; + dst_rect.y = dst.y + (dst.h - th) / 2; + dst_rect.w = src_rect.w; + dst_rect.h = th; + + SDL_RenderSetClipRect(g_renderer, &dst); + SDL_RenderCopy(g_renderer, tex, &src_rect, &dst_rect); + SDL_RenderSetClipRect(g_renderer, NULL); + SDL_DestroyTexture(tex); +} + +/* Forward declaration */ +static void el_sdl2_render_widget(int slot); + +static void el_sdl2_render_widget(int slot) { + ElWidget *w = el_sdl2_get(slot); + if (!w || w->hidden) return; + + SDL_Rect b = w->bounds; + if (b.w <= 0 || b.h <= 0) return; + + int fs = w->font_size > 0 ? w->font_size : 14; + TTF_Font *font = el_sdl2_get_font(fs); + SDL_Color fg = {w->fg_r, w->fg_g, w->fg_b, w->fg_a}; + + /* ── Draw background ── */ + if (w->bg_a > 0) { + el_sdl2_fill_rounded_rect(g_renderer, &b, w->corner_radius, + w->bg_r, w->bg_g, w->bg_b, w->bg_a); + } + + /* ── Widget-specific drawing ── */ + switch (w->type) { + case EL_WIDGET_WINDOW: { + /* Window just provides a background; children render themselves. */ + /* Fill entire window with bg (default dark) */ + SDL_Rect win_rect = {0, 0, g_win_w, g_win_h}; + uint8_t br = w->bg_a > 0 ? w->bg_r : 30; + uint8_t bg_g = w->bg_a > 0 ? w->bg_g : 30; + uint8_t bb = w->bg_a > 0 ? w->bg_b : 30; + SDL_SetRenderDrawColor(g_renderer, br, bg_g, bb, 255); + SDL_RenderFillRect(g_renderer, &win_rect); + break; + } + + case EL_WIDGET_VSTACK: + case EL_WIDGET_HSTACK: + case EL_WIDGET_ZSTACK: + case EL_WIDGET_SCROLL: + /* Containers: bg already drawn above. Children rendered below. */ + break; + + case EL_WIDGET_LABEL: { + /* Text content */ + SDL_Rect inner = { + b.x + w->padding_l, + b.y + w->padding_t, + b.w - w->padding_l - w->padding_r, + b.h - w->padding_t - w->padding_b + }; + el_sdl2_render_text_in_rect(font, w->text, fg, inner); + break; + } + + case EL_WIDGET_BUTTON: { + /* Button body */ + uint8_t btn_r, btn_g, btn_b; + if (w->disabled) { + btn_r = 80; btn_g = 80; btn_b = 80; + } else if (w->hovered) { + btn_r = (uint8_t)(w->bg_a > 0 ? SDL_min(255, (int)w->bg_r + 40) : 100); + btn_g = (uint8_t)(w->bg_a > 0 ? SDL_min(255, (int)w->bg_g + 40) : 100); + btn_b = (uint8_t)(w->bg_a > 0 ? SDL_min(255, (int)w->bg_b + 40) : 140); + } else { + btn_r = w->bg_a > 0 ? w->bg_r : 60; + btn_g = w->bg_a > 0 ? w->bg_g : 60; + btn_b = w->bg_a > 0 ? w->bg_b : 100; + } + el_sdl2_fill_rounded_rect(g_renderer, &b, w->corner_radius > 0 ? w->corner_radius : 4, + btn_r, btn_g, btn_b, 255); + + /* Border */ + SDL_SetRenderDrawColor(g_renderer, 140, 140, 200, 255); + SDL_RenderDrawRect(g_renderer, &b); + + /* Centered label */ + SDL_Color label_col = {w->fg_r, w->fg_g, w->fg_b, w->disabled ? 128u : 255u}; + SDL_Rect inner = { + b.x + w->padding_l + 4, + b.y + w->padding_t, + b.w - w->padding_l - w->padding_r - 8, + b.h - w->padding_t - w->padding_b + }; + el_sdl2_render_text_centered(font, w->text, label_col, inner); + break; + } + + case EL_WIDGET_TEXT_FIELD: + case EL_WIDGET_TEXT_AREA: { + /* Background */ + uint8_t field_bg_r = 40, field_bg_g = 40, field_bg_b = 50; + if (w->bg_a > 0) { field_bg_r = w->bg_r; field_bg_g = w->bg_g; field_bg_b = w->bg_b; } + el_sdl2_fill_rounded_rect(g_renderer, &b, 3, + field_bg_r, field_bg_g, field_bg_b, 255); + + /* Border — highlighted when focused */ + if (w->input_focused) { + SDL_SetRenderDrawColor(g_renderer, 80, 140, 220, 255); + } else { + SDL_SetRenderDrawColor(g_renderer, 100, 100, 120, 255); + } + SDL_RenderDrawRect(g_renderer, &b); + + SDL_Rect inner = { + b.x + 6 + w->padding_l, + b.y + w->padding_t, + b.w - 12 - w->padding_l - w->padding_r, + b.h - w->padding_t - w->padding_b + }; + + const char *display = w->input_buf[0] ? w->input_buf : w->text; /* text = placeholder */ + SDL_Color text_col; + if (!w->input_buf[0] && w->text[0]) { + /* placeholder style: dimmed */ + text_col = (SDL_Color){120, 120, 140, 255}; + } else { + text_col = fg; + } + + el_sdl2_render_text_in_rect(font, display, text_col, inner); + + /* Draw cursor if focused */ + if (w->input_focused && font) { + /* Measure text up to cursor position */ + char before_cursor[1024]; + int cplen = w->cursor_pos; + if (cplen < 0) cplen = 0; + int buflen = (int)strlen(w->input_buf); + if (cplen > buflen) cplen = buflen; + memcpy(before_cursor, w->input_buf, cplen); + before_cursor[cplen] = '\0'; + int cx = 0, cy_unused = 0; + if (before_cursor[0]) { + TTF_SizeUTF8(font, before_cursor, &cx, &cy_unused); + } + int cursor_x = inner.x + cx; + int cursor_y1 = b.y + 3; + int cursor_y2 = b.y + b.h - 3; + SDL_SetRenderDrawColor(g_renderer, 200, 200, 255, 255); + SDL_RenderDrawLine(g_renderer, cursor_x, cursor_y1, cursor_x, cursor_y2); + } + break; + } + + case EL_WIDGET_IMAGE: { + /* Load or reuse cached texture */ + if (!w->img_texture && w->text[0]) { + SDL_Surface *surf = IMG_Load(w->text); + if (!surf) { + /* Try as raw SDL surface */ + surf = SDL_LoadBMP(w->text); + } + if (surf) { + w->img_texture = SDL_CreateTextureFromSurface(g_renderer, surf); + SDL_FreeSurface(surf); + } + } + if (w->img_texture) { + SDL_RenderCopy(g_renderer, w->img_texture, NULL, &b); + } else { + /* Placeholder: grey box with X */ + SDL_SetRenderDrawColor(g_renderer, 80, 80, 80, 255); + SDL_RenderFillRect(g_renderer, &b); + SDL_SetRenderDrawColor(g_renderer, 140, 140, 140, 255); + SDL_RenderDrawLine(g_renderer, b.x, b.y, b.x + b.w, b.y + b.h); + SDL_RenderDrawLine(g_renderer, b.x + b.w, b.y, b.x, b.y + b.h); + } + break; + } + + case EL_WIDGET_DIVIDER: { + SDL_SetRenderDrawColor(g_renderer, 80, 80, 80, 255); + SDL_RenderFillRect(g_renderer, &b); + break; + } + + case EL_WIDGET_SPACER: + default: + break; + } + + /* ── Recurse into children ── */ + for (int i = 0; i < w->child_count; i++) { + el_sdl2_render_widget(w->children[i]); + } +} + +static void el_sdl2_render(void) { + /* Clear with dark background */ + SDL_SetRenderDrawColor(g_renderer, 30, 30, 30, 255); + SDL_RenderClear(g_renderer); + + if (g_root_widget >= 0) { + el_sdl2_render_widget(g_root_widget); + } +} + +/* ── Event handling ───────────────────────────────────────────────────────── */ + +/* Hit-test: find the deepest interactive widget at (x, y). + * Returns slot index or -1. */ +static int el_sdl2_hit_test(int slot, int x, int y) { + ElWidget *w = el_sdl2_get(slot); + if (!w || w->hidden) return -1; + + SDL_Rect b = w->bounds; + if (x < b.x || x >= b.x + b.w) return -1; + if (y < b.y || y >= b.y + b.h) return -1; + + /* Check children first (front-to-back; last child = topmost) */ + for (int i = w->child_count - 1; i >= 0; i--) { + int r = el_sdl2_hit_test(w->children[i], x, y); + if (r >= 0) return r; + } + + /* This widget itself is a candidate if interactive */ + if (w->type == EL_WIDGET_BUTTON || + w->type == EL_WIDGET_TEXT_FIELD || + w->type == EL_WIDGET_TEXT_AREA) { + return slot; + } + + return -1; +} + +/* Clear hover on all buttons */ +static void el_sdl2_clear_hover(int slot) { + ElWidget *w = el_sdl2_get(slot); + if (!w) return; + if (w->type == EL_WIDGET_BUTTON) w->hovered = 0; + for (int i = 0; i < w->child_count; i++) { + el_sdl2_clear_hover(w->children[i]); + } +} + +static void el_sdl2_handle_event(SDL_Event *e) { + switch (e->type) { + case SDL_QUIT: + exit(0); + break; + + case SDL_WINDOWEVENT: + if (e->window.event == SDL_WINDOWEVENT_RESIZED || + e->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { + g_win_w = e->window.data1; + g_win_h = e->window.data2; + /* Re-layout root */ + if (g_root_widget >= 0) { + SDL_Rect full = {0, 0, g_win_w, g_win_h}; + el_sdl2_layout(g_root_widget, full); + } + g_dirty = 1; + } + break; + + case SDL_MOUSEBUTTONDOWN: { + if (e->button.button != SDL_BUTTON_LEFT) break; + int mx = e->button.x; + int my = e->button.y; + + /* Unfocus previous text field */ + if (g_focused_widget >= 0) { + ElWidget *fw = el_sdl2_get(g_focused_widget); + if (fw) fw->input_focused = 0; + } + g_focused_widget = -1; + + int hit = (g_root_widget >= 0) ? el_sdl2_hit_test(g_root_widget, mx, my) : -1; + if (hit < 0) break; + + ElWidget *hw = el_sdl2_get(hit); + if (!hw) break; + + if (hw->type == EL_WIDGET_BUTTON && !hw->disabled) { + el_sdl2_fire_cb(hw->cb_click, (int64_t)hit, ""); + } else if (hw->type == EL_WIDGET_TEXT_FIELD || + hw->type == EL_WIDGET_TEXT_AREA) { + hw->input_focused = 1; + g_focused_widget = hit; + SDL_StartTextInput(); + } + g_dirty = 1; + break; + } + + case SDL_MOUSEMOTION: { + if (g_root_widget < 0) break; + int mx = e->motion.x; + int my = e->motion.y; + int prev_hover = -1; + /* Find any currently hovered button */ + for (int i = 1; i < EL_SDL2_MAX_WIDGETS; i++) { + if (g_slot_used[i] && g_widgets[i].type == EL_WIDGET_BUTTON && + g_widgets[i].hovered) { + prev_hover = i; + break; + } + } + /* Clear all hover */ + el_sdl2_clear_hover(g_root_widget); + /* Set hover on current button under cursor */ + int hit = el_sdl2_hit_test(g_root_widget, mx, my); + if (hit >= 0) { + ElWidget *hw = el_sdl2_get(hit); + if (hw && hw->type == EL_WIDGET_BUTTON && !hw->disabled) { + hw->hovered = 1; + } + } + if (hit != prev_hover) g_dirty = 1; + break; + } + + case SDL_KEYDOWN: { + if (g_focused_widget < 0) break; + ElWidget *fw = el_sdl2_get(g_focused_widget); + if (!fw) break; + + SDL_Keycode key = e->key.keysym.sym; + + if (key == SDLK_BACKSPACE) { + int len = (int)strlen(fw->input_buf); + if (len > 0 && fw->cursor_pos > 0) { + /* Remove character before cursor */ + int cp = fw->cursor_pos; + memmove(fw->input_buf + cp - 1, fw->input_buf + cp, + (size_t)(len - cp + 1)); + fw->cursor_pos--; + el_sdl2_fire_cb(fw->cb_change, (int64_t)g_focused_widget, fw->input_buf); + } + g_dirty = 1; + } else if (key == SDLK_DELETE) { + int len = (int)strlen(fw->input_buf); + if (fw->cursor_pos < len) { + memmove(fw->input_buf + fw->cursor_pos, + fw->input_buf + fw->cursor_pos + 1, + (size_t)(len - fw->cursor_pos)); + el_sdl2_fire_cb(fw->cb_change, (int64_t)g_focused_widget, fw->input_buf); + g_dirty = 1; + } + } else if (key == SDLK_LEFT) { + if (fw->cursor_pos > 0) { fw->cursor_pos--; g_dirty = 1; } + } else if (key == SDLK_RIGHT) { + int len = (int)strlen(fw->input_buf); + if (fw->cursor_pos < len) { fw->cursor_pos++; g_dirty = 1; } + } else if (key == SDLK_HOME) { + fw->cursor_pos = 0; g_dirty = 1; + } else if (key == SDLK_END) { + fw->cursor_pos = (int)strlen(fw->input_buf); g_dirty = 1; + } else if (key == SDLK_RETURN || key == SDLK_KP_ENTER) { + if (fw->type == EL_WIDGET_TEXT_FIELD) { + /* Submit */ + el_sdl2_fire_cb(fw->cb_submit[0] ? fw->cb_submit : fw->cb_click, + (int64_t)g_focused_widget, fw->input_buf); + g_dirty = 1; + } else { + /* Text area: insert newline via SDL_TEXTINPUT */ + } + } else if (key == SDLK_TAB) { + /* Blur current field */ + fw->input_focused = 0; + SDL_StopTextInput(); + g_focused_widget = -1; + g_dirty = 1; + } + break; + } + + case SDL_TEXTINPUT: { + if (g_focused_widget < 0) break; + ElWidget *fw = el_sdl2_get(g_focused_widget); + if (!fw) break; + + const char *inp = e->text.text; + int inp_len = (int)strlen(inp); + int buf_len = (int)strlen(fw->input_buf); + int max_buf = (int)sizeof(fw->input_buf) - 1; + + if (buf_len + inp_len <= max_buf) { + /* Insert at cursor position */ + int cp = fw->cursor_pos; + memmove(fw->input_buf + cp + inp_len, fw->input_buf + cp, + (size_t)(buf_len - cp + 1)); + memcpy(fw->input_buf + cp, inp, (size_t)inp_len); + fw->cursor_pos += inp_len; + el_sdl2_fire_cb(fw->cb_change, (int64_t)g_focused_widget, fw->input_buf); + g_dirty = 1; + } + break; + } + + default: + break; + } +} + +/* ── Public API — called from el_seed.c wrappers ──────────────────────────── */ + +void el_sdl2_init(void) { + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) { + fprintf(stderr, "el_sdl2: SDL_Init failed: %s\n", SDL_GetError()); + exit(1); + } + if (TTF_Init() != 0) { + fprintf(stderr, "el_sdl2: TTF_Init failed: %s\n", TTF_GetError()); + exit(1); + } + if (!(IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG) & (IMG_INIT_PNG | IMG_INIT_JPG))) { + fprintf(stderr, "el_sdl2: IMG_Init warning: %s\n", IMG_GetError()); + /* Non-fatal: images won't load, but text UI still works */ + } + + /* Load default font */ + g_font_default = el_sdl2_load_font(14); + if (!g_font_default) { + fprintf(stderr, "el_sdl2: warning: no system font found; text will not render\n"); + } +} + +void el_sdl2_run_loop(void) { + SDL_Event event; + while (1) { + while (SDL_PollEvent(&event)) { + el_sdl2_handle_event(&event); + } + if (g_dirty) { + el_sdl2_render(); + SDL_RenderPresent(g_renderer); + g_dirty = 0; + } + SDL_Delay(16); /* ~60 fps cap */ + } +} + +int64_t el_sdl2_window_create(const char *title, int width, int height, + int min_width, int min_height) { + g_win_w = width > 0 ? width : 800; + g_win_h = height > 0 ? height : 600; + + Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE; + + /* On Pi with no desktop: use fullscreen desktop if w/h not specified */ + g_sdl_window = SDL_CreateWindow( + title ? title : "", + SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, + g_win_w, g_win_h, flags); + + if (!g_sdl_window) { + fprintf(stderr, "el_sdl2: SDL_CreateWindow failed: %s\n", SDL_GetError()); + return -1; + } + + if (min_width > 0 || min_height > 0) { + SDL_SetWindowMinimumSize(g_sdl_window, min_width, min_height); + } + + g_renderer = SDL_CreateRenderer(g_sdl_window, -1, + SDL_RENDERER_ACCELERATED | + SDL_RENDERER_PRESENTVSYNC); + if (!g_renderer) { + /* Fall back to software renderer (required on Pi Zero fbdev) */ + g_renderer = SDL_CreateRenderer(g_sdl_window, -1, SDL_RENDERER_SOFTWARE); + } + if (!g_renderer) { + fprintf(stderr, "el_sdl2: SDL_CreateRenderer failed: %s\n", SDL_GetError()); + return -1; + } + + SDL_SetRenderDrawBlendMode(g_renderer, SDL_BLENDMODE_BLEND); + + int64_t handle = el_sdl2_alloc_slot(EL_WIDGET_WINDOW); + if (handle < 0) return -1; + + ElWidget *w = el_sdl2_get(handle); + snprintf(w->text, sizeof(w->text), "%s", title ? title : ""); + w->layout_type = EL_LAYOUT_VSTACK; + w->layout_spacing = 0; + w->bounds.x = 0; w->bounds.y = 0; + w->bounds.w = g_win_w; w->bounds.h = g_win_h; + + g_root_widget = (int)handle; + g_dirty = 1; + return handle; +} + +void el_sdl2_window_show(int64_t handle) { + if (g_sdl_window) { + SDL_ShowWindow(g_sdl_window); + } + /* Trigger initial layout */ + if (g_root_widget >= 0) { + SDL_Rect full = {0, 0, g_win_w, g_win_h}; + el_sdl2_layout(g_root_widget, full); + } + g_dirty = 1; +} + +void el_sdl2_window_set_title(int64_t handle, const char *title) { + if (g_sdl_window) { + SDL_SetWindowTitle(g_sdl_window, title ? title : ""); + } + ElWidget *w = el_sdl2_get(handle); + if (w) snprintf(w->text, sizeof(w->text), "%s", title ? title : ""); + g_dirty = 1; +} + +int64_t el_sdl2_vstack_create(int spacing) { + int64_t h = el_sdl2_alloc_slot(EL_WIDGET_VSTACK); + if (h < 0) return -1; + ElWidget *w = el_sdl2_get(h); + w->layout_type = EL_LAYOUT_VSTACK; + w->layout_spacing = spacing; + return h; +} + +int64_t el_sdl2_hstack_create(int spacing) { + int64_t h = el_sdl2_alloc_slot(EL_WIDGET_HSTACK); + if (h < 0) return -1; + ElWidget *w = el_sdl2_get(h); + w->layout_type = EL_LAYOUT_HSTACK; + w->layout_spacing = spacing; + return h; +} + +int64_t el_sdl2_zstack_create(void) { + int64_t h = el_sdl2_alloc_slot(EL_WIDGET_ZSTACK); + if (h < 0) return -1; + ElWidget *w = el_sdl2_get(h); + w->layout_type = EL_LAYOUT_ZSTACK; + return h; +} + +int64_t el_sdl2_scroll_create(void) { + int64_t h = el_sdl2_alloc_slot(EL_WIDGET_SCROLL); + if (h < 0) return -1; + ElWidget *w = el_sdl2_get(h); + /* Scroll: single content child; layout passes full inner rect */ + w->layout_type = EL_LAYOUT_NONE; + return h; +} + +int64_t el_sdl2_label_create(const char *text) { + int64_t h = el_sdl2_alloc_slot(EL_WIDGET_LABEL); + if (h < 0) return -1; + ElWidget *w = el_sdl2_get(h); + snprintf(w->text, sizeof(w->text), "%s", text ? text : ""); + return h; +} + +int64_t el_sdl2_button_create(const char *label) { + int64_t h = el_sdl2_alloc_slot(EL_WIDGET_BUTTON); + if (h < 0) return -1; + ElWidget *w = el_sdl2_get(h); + snprintf(w->text, sizeof(w->text), "%s", label ? label : ""); + w->padding_t = 4; w->padding_b = 4; + w->padding_l = 8; w->padding_r = 8; + return h; +} + +int64_t el_sdl2_text_field_create(const char *placeholder) { + int64_t h = el_sdl2_alloc_slot(EL_WIDGET_TEXT_FIELD); + if (h < 0) return -1; + ElWidget *w = el_sdl2_get(h); + /* text field: text[] holds the placeholder */ + snprintf(w->text, sizeof(w->text), "%s", placeholder ? placeholder : ""); + w->padding_t = 2; w->padding_b = 2; + w->padding_l = 4; w->padding_r = 4; + return h; +} + +int64_t el_sdl2_text_area_create(const char *placeholder) { + int64_t h = el_sdl2_alloc_slot(EL_WIDGET_TEXT_AREA); + if (h < 0) return -1; + ElWidget *w = el_sdl2_get(h); + snprintf(w->text, sizeof(w->text), "%s", placeholder ? placeholder : ""); + w->padding_t = 4; w->padding_b = 4; + w->padding_l = 6; w->padding_r = 6; + return h; +} + +int64_t el_sdl2_image_create(const char *path_or_name) { + int64_t h = el_sdl2_alloc_slot(EL_WIDGET_IMAGE); + if (h < 0) return -1; + ElWidget *w = el_sdl2_get(h); + snprintf(w->text, sizeof(w->text), "%s", path_or_name ? path_or_name : ""); + return h; +} + +/* ── Widget property setters ─────────────────────────────────────────────── */ + +void el_sdl2_widget_set_text(int64_t handle, const char *text) { + ElWidget *w = el_sdl2_get(handle); + if (!w) return; + if (w->type == EL_WIDGET_TEXT_FIELD || w->type == EL_WIDGET_TEXT_AREA) { + /* Setting text on a field = set input buffer content */ + snprintf(w->input_buf, sizeof(w->input_buf), "%s", text ? text : ""); + w->cursor_pos = (int)strlen(w->input_buf); + } else { + snprintf(w->text, sizeof(w->text), "%s", text ? text : ""); + /* Invalidate image texture if path changed */ + if (w->type == EL_WIDGET_IMAGE && w->img_texture) { + SDL_DestroyTexture(w->img_texture); + w->img_texture = NULL; + } + } + g_dirty = 1; +} + +const char *el_sdl2_widget_get_text(int64_t handle) { + ElWidget *w = el_sdl2_get(handle); + if (!w) return ""; + if (w->type == EL_WIDGET_TEXT_FIELD || w->type == EL_WIDGET_TEXT_AREA) { + return w->input_buf; + } + return w->text; +} + +void el_sdl2_widget_set_color(int64_t handle, float r, float g, float b, float a) { + ElWidget *w = el_sdl2_get(handle); + if (!w) return; + w->fg_r = (uint8_t)(r * 255.0f); + w->fg_g = (uint8_t)(g * 255.0f); + w->fg_b = (uint8_t)(b * 255.0f); + w->fg_a = (uint8_t)(a * 255.0f); + g_dirty = 1; +} + +void el_sdl2_widget_set_bg_color(int64_t handle, float r, float g, float b, float a) { + ElWidget *w = el_sdl2_get(handle); + if (!w) return; + w->bg_r = (uint8_t)(r * 255.0f); + w->bg_g = (uint8_t)(g * 255.0f); + w->bg_b = (uint8_t)(b * 255.0f); + w->bg_a = (uint8_t)(a * 255.0f); + g_dirty = 1; +} + +void el_sdl2_widget_set_font(int64_t handle, const char *family, int size, int bold) { + ElWidget *w = el_sdl2_get(handle); + if (!w) return; + if (family) snprintf(w->font_family, sizeof(w->font_family), "%s", family); + if (size > 0) w->font_size = size; + w->font_bold = bold; + g_dirty = 1; +} + +void el_sdl2_widget_set_padding(int64_t handle, int top, int right, int bottom, int left) { + ElWidget *w = el_sdl2_get(handle); + if (!w) return; + w->padding_t = top; + w->padding_r = right; + w->padding_b = bottom; + w->padding_l = left; + /* Re-layout from root */ + if (g_root_widget >= 0) { + SDL_Rect full = {0, 0, g_win_w, g_win_h}; + el_sdl2_layout(g_root_widget, full); + } + g_dirty = 1; +} + +void el_sdl2_widget_set_width(int64_t handle, int width) { + ElWidget *w = el_sdl2_get(handle); + if (!w) return; + w->fixed_width = width; + if (g_root_widget >= 0) { + SDL_Rect full = {0, 0, g_win_w, g_win_h}; + el_sdl2_layout(g_root_widget, full); + } + g_dirty = 1; +} + +void el_sdl2_widget_set_height(int64_t handle, int height) { + ElWidget *w = el_sdl2_get(handle); + if (!w) return; + w->fixed_height = height; + if (g_root_widget >= 0) { + SDL_Rect full = {0, 0, g_win_w, g_win_h}; + el_sdl2_layout(g_root_widget, full); + } + g_dirty = 1; +} + +void el_sdl2_widget_set_flex(int64_t handle, int flex) { + ElWidget *w = el_sdl2_get(handle); + if (!w) return; + w->flex = flex; + if (g_root_widget >= 0) { + SDL_Rect full = {0, 0, g_win_w, g_win_h}; + el_sdl2_layout(g_root_widget, full); + } + g_dirty = 1; +} + +void el_sdl2_widget_set_corner_radius(int64_t handle, int radius) { + ElWidget *w = el_sdl2_get(handle); + if (!w) return; + w->corner_radius = radius; + g_dirty = 1; +} + +void el_sdl2_widget_set_disabled(int64_t handle, int disabled) { + ElWidget *w = el_sdl2_get(handle); + if (!w) return; + w->disabled = disabled; + g_dirty = 1; +} + +void el_sdl2_widget_set_hidden(int64_t handle, int hidden) { + ElWidget *w = el_sdl2_get(handle); + if (!w) return; + w->hidden = hidden; + if (g_root_widget >= 0) { + SDL_Rect full = {0, 0, g_win_w, g_win_h}; + el_sdl2_layout(g_root_widget, full); + } + g_dirty = 1; +} + +/* ── Child management ─────────────────────────────────────────────────────── */ + +void el_sdl2_widget_add_child(int64_t parent, int64_t child) { + ElWidget *pw = el_sdl2_get(parent); + ElWidget *cw = el_sdl2_get(child); + if (!pw || !cw) return; + if (pw->child_count >= 64) return; /* max children per node */ + + /* Prevent duplicates */ + for (int i = 0; i < pw->child_count; i++) { + if (pw->children[i] == (int)child) return; + } + + pw->children[pw->child_count++] = (int)child; + cw->parent = (int)parent; + + /* Re-layout */ + if (g_root_widget >= 0) { + SDL_Rect full = {0, 0, g_win_w, g_win_h}; + el_sdl2_layout(g_root_widget, full); + } + g_dirty = 1; +} + +void el_sdl2_widget_remove_child(int64_t parent, int64_t child) { + ElWidget *pw = el_sdl2_get(parent); + ElWidget *cw = el_sdl2_get(child); + if (!pw) return; + + for (int i = 0; i < pw->child_count; i++) { + if (pw->children[i] == (int)child) { + memmove(&pw->children[i], &pw->children[i + 1], + (size_t)(pw->child_count - i - 1) * sizeof(int)); + pw->child_count--; + if (cw) cw->parent = -1; + break; + } + } + + if (g_root_widget >= 0) { + SDL_Rect full = {0, 0, g_win_w, g_win_h}; + el_sdl2_layout(g_root_widget, full); + } + g_dirty = 1; +} + +/* ── Event registration ───────────────────────────────────────────────────── */ + +void el_sdl2_widget_on_click(int64_t handle, const char *fn_name) { + ElWidget *w = el_sdl2_get(handle); + if (!w) return; + snprintf(w->cb_click, sizeof(w->cb_click), "%s", fn_name ? fn_name : ""); +} + +void el_sdl2_widget_on_change(int64_t handle, const char *fn_name) { + ElWidget *w = el_sdl2_get(handle); + if (!w) return; + snprintf(w->cb_change, sizeof(w->cb_change), "%s", fn_name ? fn_name : ""); +} + +void el_sdl2_widget_on_submit(int64_t handle, const char *fn_name) { + ElWidget *w = el_sdl2_get(handle); + if (!w) return; + snprintf(w->cb_submit, sizeof(w->cb_submit), "%s", fn_name ? fn_name : ""); + /* Mirror into cb_click so RETURN key fires via cb_click fallback too */ + snprintf(w->cb_click, sizeof(w->cb_click), "%s", fn_name ? fn_name : ""); +} + +/* ── Widget destroy ───────────────────────────────────────────────────────── */ + +void el_sdl2_widget_destroy(int64_t handle) { + ElWidget *w = el_sdl2_get(handle); + if (!w) return; + + /* Remove from parent */ + if (w->parent >= 0) { + el_sdl2_widget_remove_child((int64_t)w->parent, handle); + } + + /* Recursively destroy children */ + for (int i = 0; i < w->child_count; i++) { + el_sdl2_widget_destroy((int64_t)w->children[i]); + } + + if (g_focused_widget == (int)handle) { + g_focused_widget = -1; + SDL_StopTextInput(); + } + if (g_root_widget == (int)handle) { + g_root_widget = -1; + } + + el_sdl2_free_slot(handle); + g_dirty = 1; +} + +#endif /* EL_TARGET_SDL2 */ diff --git a/lang/el-compiler/runtime/el_uikit.m b/lang/el-compiler/runtime/el_uikit.m new file mode 100644 index 0000000..01a97a1 --- /dev/null +++ b/lang/el-compiler/runtime/el_uikit.m @@ -0,0 +1,1118 @@ +/* + * el_uikit.m — UIKit backend for the el native widget system. + * + * This file implements the iOS UIKit widget layer that el_seed.c calls + * through to when EL_TARGET_IOS is defined. + * + * Architecture: + * el program (el code) + * → __widget_* C builtins in el_seed.c + * → el_uikit_* C-callable functions declared here + * → UIView/UIWindow/UIStackView/UIButton/etc. via ObjC + * + * Widget handles: every widget (window, view, control) is assigned an int64_t + * slot index into _el_widgets[]. The el program holds these as opaque Int values. + * Slot 0 is never valid (reserved as null handle = -1 convention). + * + * Threading: All UIKit calls MUST run on the main thread. el_uikit_sync_main + * bounces work to the main thread synchronously if called from a background thread. + * + * Callback mechanism: when a widget fires an event (button tap, text change), + * the bridge looks up the registered callback function name, then calls + * dlsym(RTLD_DEFAULT, fn_name)(widget_handle, event_data_string) + * This resolves the El function symbol at runtime, matching the __thread_create + * pattern already established in el_seed.c. + * + * iOS lifecycle: UIApplicationMain never returns. The el program's "main" body + * (window creation, layout, show) must execute inside applicationDidFinishLaunchingWithOptions. + * The caller sets el_main_entry_fn before calling __native_run_loop so the + * delegate can invoke it at the right time. + * + * Compile (MRC — no ARC; manual retain/release needed for struct-embedded id): + * clang -std=gnu11 -ObjC -fno-objc-arc -DEL_TARGET_IOS -framework UIKit \ + * -c el_uikit.m -o el_uikit.o + * Then link el_uikit.o alongside el_seed.c. + * + * Do NOT use -fobjc-arc: the widget table stores id in a plain C struct. ARC + * forbids explicit retain/release on struct-embedded object pointers and cannot + * insert automatic retain/release through C struct boundaries. MRC is the + * correct choice for this kind of C/ObjC bridge. + * + * Link flags required: + * -framework UIKit + */ + +#ifdef EL_TARGET_IOS + +#import +#import +#include +#include +#include +#include +#include +#include "el_runtime.h" + +/* ── Widget table ─────────────────────────────────────────────────────────── */ + +#define EL_UIKIT_MAX_WIDGETS 4096 + +typedef enum { + EL_WIDGET_FREE = 0, + EL_WIDGET_WINDOW = 1, + EL_WIDGET_VSTACK = 2, + EL_WIDGET_HSTACK = 3, + EL_WIDGET_ZSTACK = 4, + EL_WIDGET_SCROLL = 5, + EL_WIDGET_LABEL = 6, + EL_WIDGET_BUTTON = 7, + EL_WIDGET_TEXTFIELD = 8, + EL_WIDGET_TEXTAREA = 9, + EL_WIDGET_IMAGE = 10, + EL_WIDGET_DIVIDER = 11, + EL_WIDGET_SPACER = 12, +} ElWidgetKind; + +typedef struct { + ElWidgetKind kind; + id obj; /* UIWindow* or UIView* subclass, retained */ + char* cb_click; /* El function name for click/submit events */ + char* cb_change; /* El function name for value-change events */ +} ElWidget; + +static ElWidget _el_widgets[EL_UIKIT_MAX_WIDGETS]; +static int _el_widget_count = 0; + +/* Side table for ObjC delegate objects keyed by widget slot (MRC retained). */ +static id _el_delegates[EL_UIKIT_MAX_WIDGETS]; + +/* Allocate a slot and return its index. Returns -1 if full. */ +static int64_t el_widget_alloc(ElWidgetKind kind, id obj) { + for (int i = 1; i < EL_UIKIT_MAX_WIDGETS; i++) { + if (_el_widgets[i].kind == EL_WIDGET_FREE) { + _el_widgets[i].kind = kind; + _el_widgets[i].obj = [obj retain]; + _el_widgets[i].cb_click = NULL; + _el_widgets[i].cb_change = NULL; + if (i > _el_widget_count) _el_widget_count = i; + return (int64_t)i; + } + } + return -1; +} + +static ElWidget* el_widget_get(int64_t handle) { + if (handle <= 0 || handle >= EL_UIKIT_MAX_WIDGETS) return NULL; + if (_el_widgets[handle].kind == EL_WIDGET_FREE) return NULL; + return &_el_widgets[handle]; +} + +static void el_widget_free(int64_t handle) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + [w->obj release]; + w->obj = nil; + w->kind = EL_WIDGET_FREE; + free(w->cb_click); w->cb_click = NULL; + free(w->cb_change); w->cb_change = NULL; +} + +/* ── Dispatch helpers ─────────────────────────────────────────────────────── */ + +/* Run a block on the main thread, waiting for completion. Safe to call from + * any thread including the main thread. Uses dispatch_sync so callers can + * rely on the block having run before the function returns. */ +static void el_uikit_sync_main(void (^block)(void)) { + if ([NSThread isMainThread]) { + block(); + } else { + dispatch_sync(dispatch_get_main_queue(), block); + } +} + +/* ── El callback invocation ──────────────────────────────────────────────── */ +/* + * Invoke an El callback by symbol name. The El function must have the + * signature: fn handler(handle: Int, data: String) -> Void + * which compiles to: void fn_name(el_val_t handle, el_val_t data) + */ +typedef void (*ElCb2)(int64_t handle, int64_t data); + +static void el_uikit_invoke_cb(const char* fn_name, int64_t handle, const char* data) { + if (!fn_name || !*fn_name) return; + void* sym = dlsym(RTLD_DEFAULT, fn_name); + if (!sym) return; + ElCb2 fn = (ElCb2)sym; + fn(handle, (int64_t)(uintptr_t)(data ? data : "")); +} + +/* ── ObjC helper: ElEventProxy — button tap and text event target ─────────── */ + +/* + * ElEventProxy is a lightweight ObjC action target / delegate aggregator. + * One instance is allocated per widget that has events. Stored in _el_delegates[]. + */ +@interface ElEventProxy : NSObject +@property (nonatomic, assign) int64_t widgetHandle; +/* UIButton tap */ +- (void)elButtonTapped:(id)sender; +/* UITextField UIControlEventEditingChanged */ +- (void)elTextChanged:(id)sender; +@end + +@implementation ElEventProxy + +- (void)elButtonTapped:(id)sender { + (void)sender; + ElWidget* w = el_widget_get(self.widgetHandle); + if (w && w->cb_click) { + el_uikit_invoke_cb(w->cb_click, self.widgetHandle, ""); + } +} + +- (void)elTextChanged:(id)sender { + UITextField* tf = (UITextField*)sender; + ElWidget* w = el_widget_get(self.widgetHandle); + if (!w) return; + const char* val = [tf.text UTF8String]; + if (w->cb_change) { + el_uikit_invoke_cb(w->cb_change, self.widgetHandle, val ? val : ""); + } +} + +/* UITextFieldDelegate — return key fires on_submit (stored in cb_click). */ +- (BOOL)textFieldShouldReturn:(UITextField*)textField { + ElWidget* w = el_widget_get(self.widgetHandle); + if (w && w->cb_click) { + const char* val = [textField.text UTF8String]; + el_uikit_invoke_cb(w->cb_click, self.widgetHandle, val ? val : ""); + } + [textField resignFirstResponder]; + return YES; +} + +@end + +/* ── UITextView change delegate ──────────────────────────────────────────── */ + +@interface ElTextViewDelegate : NSObject +@property (nonatomic, assign) int64_t widgetHandle; +@end + +@implementation ElTextViewDelegate + +- (void)textViewDidChange:(UITextView*)textView { + ElWidget* w = el_widget_get(self.widgetHandle); + if (!w || !w->cb_change) return; + const char* val = [textView.text UTF8String]; + el_uikit_invoke_cb(w->cb_change, self.widgetHandle, val ? val : ""); +} + +@end + +/* ── iOS application lifecycle ───────────────────────────────────────────── */ + +/* + * el_main_entry_fn — set by el's main() (via __native_run_loop) before calling + * UIApplicationMain. The app delegate invokes it in didFinishLaunching so that + * the el program's window/widget setup runs at the correct lifecycle point. + */ +void (*el_main_entry_fn)(void) = NULL; + +/* argc/argv forwarded from el_runtime_init_args (or main). */ +static int _el_argc = 0; +static char** _el_argv = NULL; + +/* + * el_uikit_set_args — call from el_runtime_init_args / main() before + * __native_run_loop to forward argc/argv to UIApplicationMain. + */ +void el_uikit_set_args(int argc, char** argv) { + _el_argc = argc; + _el_argv = argv; +} + +@interface ElAppDelegate : UIResponder +@property (nonatomic, strong) UIWindow *keyWindow; +@end + +@implementation ElAppDelegate + +- (BOOL)application:(UIApplication*)app + didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { + (void)app; (void)launchOptions; + /* + * The el program called __native_init and set up el_main_entry_fn before + * UIApplicationMain was entered. We call it here so window creation and + * widget layout happen on the main thread at the right lifecycle moment. + */ + if (el_main_entry_fn) { + el_main_entry_fn(); + } + return YES; +} + +- (void)applicationWillResignActive:(UIApplication*)app { (void)app; } +- (void)applicationDidEnterBackground:(UIApplication*)app { (void)app; } +- (void)applicationWillEnterForeground:(UIApplication*)app { (void)app; } +- (void)applicationDidBecomeActive:(UIApplication*)app { (void)app; } + +@end + +/* ── Public C API ─────────────────────────────────────────────────────────── */ + +/* + * el_uikit_init — one-time initialisation. Idempotent. Call before any other + * el_uikit_* function. On iOS there is no UIApplication equivalent of + * [NSApplication sharedApplication] to call here — the real initialisation + * happens inside UIApplicationMain which is entered from el_uikit_run_loop. + * This function records that init was requested. + */ +static int _el_uikit_init_done = 0; + +void el_uikit_init(void) { + _el_uikit_init_done = 1; +} + +/* + * el_uikit_run_loop — enters UIApplicationMain. Never returns. + * Must be called from the process main thread as the final step of main(). + * Sets el_main_entry_fn to the provided function pointer before entering + * UIApplicationMain so the app delegate can call back into el code. + */ +void el_uikit_run_loop(void (*entry_fn)(void)) { + el_main_entry_fn = entry_fn; + UIApplicationMain(_el_argc, _el_argv, nil, @"ElAppDelegate"); +} + +/* + * el_uikit_window_create — create a UIWindow and configure a root + * UINavigationController + UIViewController. Returns window handle. + * + * On iOS there is exactly one full-screen window. width/height from the + * manifest are stored but the window always fills the screen. The title + * is applied to the root view controller's navigationItem. + */ +int64_t el_uikit_window_create(const char* title, int width, int height, + int min_width, int min_height) { + (void)width; (void)height; (void)min_width; (void)min_height; + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UIScreen* screen = [UIScreen mainScreen]; + UIWindow* win = [[UIWindow alloc] initWithFrame:[screen bounds]]; + win.backgroundColor = [UIColor systemBackgroundColor]; + + /* Root view controller with a vertical UIStackView as content. */ + UIViewController* rootVC = [[UIViewController alloc] init]; + NSString* titleStr = [NSString stringWithUTF8String:title ? title : ""]; + rootVC.title = titleStr; + + UIStackView* rootStack = [[UIStackView alloc] initWithFrame:CGRectZero]; + rootStack.axis = UILayoutConstraintAxisVertical; + rootStack.alignment = UIStackViewAlignmentFill; + rootStack.distribution = UIStackViewDistributionFill; + rootStack.spacing = 0.0; + rootStack.translatesAutoresizingMaskIntoConstraints = NO; + [rootVC.view addSubview:rootStack]; + + /* Pin root stack to safe area. */ + UILayoutGuide* safe = rootVC.view.safeAreaLayoutGuide; + [NSLayoutConstraint activateConstraints:@[ + [rootStack.topAnchor constraintEqualToAnchor:safe.topAnchor], + [rootStack.leadingAnchor constraintEqualToAnchor:safe.leadingAnchor], + [rootStack.trailingAnchor constraintEqualToAnchor:safe.trailingAnchor], + [rootStack.bottomAnchor constraintEqualToAnchor:safe.bottomAnchor], + ]]; + + UINavigationController* navCtrl = + [[UINavigationController alloc] initWithRootViewController:rootVC]; + win.rootViewController = navCtrl; + + /* Store the window. The root stack is accessible via + * ((UINavigationController*)win.rootViewController) + * .topViewController.view.subviews[0] + * but we reach it by casting obj to UIWindow* and digging at add_child time. */ + handle = el_widget_alloc(EL_WIDGET_WINDOW, win); + [win release]; + [rootVC release]; + [rootStack release]; + [navCtrl release]; + }); + return handle; +} + +/* + * el_uikit_window_show — make the window key and visible. + */ +void el_uikit_window_show(int64_t handle) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w || w->kind != EL_WIDGET_WINDOW) return; + UIWindow* win = (UIWindow*)w->obj; + [win makeKeyAndVisible]; + }); +} + +/* + * el_uikit_window_set_title — update nav bar title at runtime. + */ +void el_uikit_window_set_title(int64_t handle, const char* title) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w || w->kind != EL_WIDGET_WINDOW) return; + UIWindow* win = (UIWindow*)w->obj; + UINavigationController* nav = (UINavigationController*)win.rootViewController; + if ([nav isKindOfClass:[UINavigationController class]]) { + nav.topViewController.title = + [NSString stringWithUTF8String:title ? title : ""]; + } + }); +} + +/* ── Layout container factories ───────────────────────────────────────────── */ + +static int64_t make_uistack(UILayoutConstraintAxis axis, CGFloat spacing) { + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UIStackView* sv = [[UIStackView alloc] initWithFrame:CGRectZero]; + sv.axis = axis; + sv.alignment = UIStackViewAlignmentFill; + sv.distribution = UIStackViewDistributionFill; + sv.spacing = spacing; + sv.translatesAutoresizingMaskIntoConstraints = NO; + ElWidgetKind kind = (axis == UILayoutConstraintAxisVertical) + ? EL_WIDGET_VSTACK : EL_WIDGET_HSTACK; + handle = el_widget_alloc(kind, sv); + [sv release]; + }); + return handle; +} + +int64_t el_uikit_vstack_create(int spacing) { + return make_uistack(UILayoutConstraintAxisVertical, (CGFloat)spacing); +} + +int64_t el_uikit_hstack_create(int spacing) { + return make_uistack(UILayoutConstraintAxisHorizontal, (CGFloat)spacing); +} + +int64_t el_uikit_zstack_create(void) { + /* ZStack = plain UIView; children are added with addSubview and use + * Auto Layout or absolute frames set by the caller. */ + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UIView* v = [[UIView alloc] initWithFrame:CGRectZero]; + v.translatesAutoresizingMaskIntoConstraints = NO; + handle = el_widget_alloc(EL_WIDGET_ZSTACK, v); + [v release]; + }); + return handle; +} + +int64_t el_uikit_scroll_create(void) { + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UIScrollView* sv = [[UIScrollView alloc] initWithFrame:CGRectZero]; + sv.translatesAutoresizingMaskIntoConstraints = NO; + sv.alwaysBounceVertical = YES; + sv.showsHorizontalScrollIndicator = NO; + handle = el_widget_alloc(EL_WIDGET_SCROLL, sv); + [sv release]; + }); + return handle; +} + +/* ── Widget factories ─────────────────────────────────────────────────────── */ + +int64_t el_uikit_label_create(const char* text) { + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UILabel* lbl = [[UILabel alloc] initWithFrame:CGRectZero]; + lbl.text = [NSString stringWithUTF8String:text ? text : ""]; + lbl.numberOfLines = 0; + lbl.translatesAutoresizingMaskIntoConstraints = NO; + handle = el_widget_alloc(EL_WIDGET_LABEL, lbl); + [lbl release]; + }); + return handle; +} + +int64_t el_uikit_button_create(const char* label) { + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UIButton* btn = [UIButton buttonWithType:UIButtonTypeSystem]; + [btn setTitle:[NSString stringWithUTF8String:label ? label : ""] + forState:UIControlStateNormal]; + btn.translatesAutoresizingMaskIntoConstraints = NO; + + ElEventProxy* proxy = [[ElEventProxy alloc] init]; + [btn addTarget:proxy + action:@selector(elButtonTapped:) + forControlEvents:UIControlEventTouchUpInside]; + + int64_t h = el_widget_alloc(EL_WIDGET_BUTTON, btn); + proxy.widgetHandle = h; + _el_delegates[h] = proxy; /* retain in side table */ + handle = h; + /* btn is autoreleased from buttonWithType: — no release needed */ + }); + return handle; +} + +int64_t el_uikit_text_field_create(const char* placeholder) { + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UITextField* tf = [[UITextField alloc] initWithFrame:CGRectZero]; + tf.translatesAutoresizingMaskIntoConstraints = NO; + if (placeholder && *placeholder) { + tf.placeholder = [NSString stringWithUTF8String:placeholder]; + } + tf.borderStyle = UITextBorderStyleRoundedRect; + tf.autocorrectionType = UITextAutocorrectionTypeNo; + + ElEventProxy* proxy = [[ElEventProxy alloc] init]; + tf.delegate = proxy; + [tf addTarget:proxy + action:@selector(elTextChanged:) + forControlEvents:UIControlEventEditingChanged]; + + int64_t h = el_widget_alloc(EL_WIDGET_TEXTFIELD, tf); + proxy.widgetHandle = h; + _el_delegates[h] = proxy; + handle = h; + [tf release]; + }); + return handle; +} + +int64_t el_uikit_text_area_create(const char* placeholder) { + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UITextView* tv = [[UITextView alloc] initWithFrame:CGRectZero]; + tv.translatesAutoresizingMaskIntoConstraints = NO; + tv.font = [UIFont systemFontOfSize:14.0]; + tv.layer.borderColor = [[UIColor systemGray4Color] CGColor]; + tv.layer.borderWidth = 1.0; + tv.layer.cornerRadius = 6.0; + tv.clipsToBounds = YES; + /* UITextView has no native placeholder; set accessibility hint. */ + if (placeholder && *placeholder) { + tv.accessibilityHint = [NSString stringWithUTF8String:placeholder]; + } + + ElTextViewDelegate* del = [[ElTextViewDelegate alloc] init]; + tv.delegate = del; + + int64_t h = el_widget_alloc(EL_WIDGET_TEXTAREA, tv); + del.widgetHandle = h; + _el_delegates[h] = del; + handle = h; + [tv release]; + }); + return handle; +} + +int64_t el_uikit_image_create(const char* path_or_name) { + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UIImage* img = nil; + if (path_or_name && *path_or_name) { + /* Try filesystem path first, then bundle asset name. */ + img = [UIImage imageWithContentsOfFile: + [NSString stringWithUTF8String:path_or_name]]; + if (!img) { + img = [UIImage imageNamed: + [NSString stringWithUTF8String:path_or_name]]; + } + } + UIImageView* iv = [[UIImageView alloc] initWithFrame:CGRectZero]; + iv.translatesAutoresizingMaskIntoConstraints = NO; + iv.contentMode = UIViewContentModeScaleAspectFit; + if (img) { + iv.image = img; + } + handle = el_widget_alloc(EL_WIDGET_IMAGE, iv); + [iv release]; + }); + return handle; +} + +/* ── Widget property setters ─────────────────────────────────────────────── */ + +void el_uikit_widget_set_text(int64_t handle, const char* text) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + NSString* s = [NSString stringWithUTF8String:text ? text : ""]; + switch (w->kind) { + case EL_WIDGET_LABEL: + ((UILabel*)w->obj).text = s; + break; + case EL_WIDGET_TEXTFIELD: + ((UITextField*)w->obj).text = s; + break; + case EL_WIDGET_BUTTON: + [(UIButton*)w->obj setTitle:s forState:UIControlStateNormal]; + break; + case EL_WIDGET_TEXTAREA: + ((UITextView*)w->obj).text = s; + break; + case EL_WIDGET_WINDOW: + el_uikit_window_set_title(handle, text); + break; + default: break; + } + }); +} + +const char* el_uikit_widget_get_text(int64_t handle) { + __block const char* result = ""; + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + NSString* s = nil; + switch (w->kind) { + case EL_WIDGET_LABEL: + s = ((UILabel*)w->obj).text; + break; + case EL_WIDGET_TEXTFIELD: + s = ((UITextField*)w->obj).text; + break; + case EL_WIDGET_BUTTON: + s = [(UIButton*)w->obj titleForState:UIControlStateNormal]; + break; + case EL_WIDGET_TEXTAREA: + s = ((UITextView*)w->obj).text; + break; + default: break; + } + if (s) result = strdup([s UTF8String]); + }); + return result; +} + +void el_uikit_widget_set_color(int64_t handle, float r, float g, float b, float a) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + UIColor* c = [UIColor colorWithRed:(CGFloat)(r / 255.0) + green:(CGFloat)(g / 255.0) + blue:(CGFloat)(b / 255.0) + alpha:(CGFloat)(a / 255.0)]; + switch (w->kind) { + case EL_WIDGET_LABEL: + ((UILabel*)w->obj).textColor = c; + break; + case EL_WIDGET_TEXTFIELD: + ((UITextField*)w->obj).textColor = c; + break; + case EL_WIDGET_TEXTAREA: + ((UITextView*)w->obj).textColor = c; + break; + case EL_WIDGET_BUTTON: + [(UIButton*)w->obj setTitleColor:c forState:UIControlStateNormal]; + ((UIButton*)w->obj).tintColor = c; + break; + case EL_WIDGET_VSTACK: + case EL_WIDGET_HSTACK: + case EL_WIDGET_ZSTACK: + ((UIView*)w->obj).backgroundColor = c; + break; + default: break; + } + }); +} + +void el_uikit_widget_set_bg_color(int64_t handle, float r, float g, float b, float a) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + if (w->kind == EL_WIDGET_WINDOW) { + UIWindow* win = (UIWindow*)w->obj; + win.backgroundColor = [UIColor colorWithRed:(CGFloat)(r / 255.0) + green:(CGFloat)(g / 255.0) + blue:(CGFloat)(b / 255.0) + alpha:(CGFloat)(a / 255.0)]; + return; + } + UIView* v = (UIView*)w->obj; + v.backgroundColor = [UIColor colorWithRed:(CGFloat)(r / 255.0) + green:(CGFloat)(g / 255.0) + blue:(CGFloat)(b / 255.0) + alpha:(CGFloat)(a / 255.0)]; + }); +} + +void el_uikit_widget_set_font(int64_t handle, const char* family, int size, int bold) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + UIFont* font; + if (bold) { + font = [UIFont boldSystemFontOfSize:(CGFloat)size]; + } else if (family && *family && strcmp(family, "system") != 0) { + font = [UIFont fontWithName:[NSString stringWithUTF8String:family] + size:(CGFloat)size]; + if (!font) font = [UIFont systemFontOfSize:(CGFloat)size]; + } else { + font = [UIFont systemFontOfSize:(CGFloat)size]; + } + switch (w->kind) { + case EL_WIDGET_LABEL: + ((UILabel*)w->obj).font = font; + break; + case EL_WIDGET_TEXTFIELD: + ((UITextField*)w->obj).font = font; + break; + case EL_WIDGET_TEXTAREA: + ((UITextView*)w->obj).font = font; + break; + case EL_WIDGET_BUTTON: + ((UIButton*)w->obj).titleLabel.font = font; + break; + default: break; + } + }); +} + +void el_uikit_widget_set_padding(int64_t handle, int top, int right, int bottom, int left) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + UIEdgeInsets insets = UIEdgeInsetsMake( + (CGFloat)top, (CGFloat)left, (CGFloat)bottom, (CGFloat)right); + if (w->kind == EL_WIDGET_VSTACK || w->kind == EL_WIDGET_HSTACK) { + UIStackView* sv = (UIStackView*)w->obj; + sv.layoutMargins = insets; + sv.layoutMarginsRelativeArrangement = YES; + } else if (w->kind == EL_WIDGET_TEXTAREA) { + UITextView* tv = (UITextView*)w->obj; + tv.textContainerInset = insets; + } else { + UIView* v = (UIView*)w->obj; + v.layoutMargins = insets; + } + }); +} + +void el_uikit_widget_set_width(int64_t handle, int width) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w || w->kind == EL_WIDGET_WINDOW) return; + UIView* v = (UIView*)w->obj; + NSLayoutConstraint* c = [v.widthAnchor + constraintEqualToConstant:(CGFloat)width]; + c.priority = UILayoutPriorityDefaultHigh; + c.active = YES; + }); +} + +void el_uikit_widget_set_height(int64_t handle, int height) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w || w->kind == EL_WIDGET_WINDOW) return; + UIView* v = (UIView*)w->obj; + NSLayoutConstraint* c = [v.heightAnchor + constraintEqualToConstant:(CGFloat)height]; + c.priority = UILayoutPriorityDefaultHigh; + c.active = YES; + }); +} + +void el_uikit_widget_set_flex(int64_t handle, int flex) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w || w->kind == EL_WIDGET_WINDOW) return; + UIView* v = (UIView*)w->obj; + /* flex > 0 → low hugging priority so the view expands to fill space. + * flex == 0 → high hugging priority so the view stays at intrinsic size. */ + UILayoutPriority p = (flex > 0) + ? UILayoutPriorityDefaultLow + : UILayoutPriorityDefaultHigh; + [v setContentHuggingPriority:p + forAxis:UILayoutConstraintAxisHorizontal]; + [v setContentHuggingPriority:p + forAxis:UILayoutConstraintAxisVertical]; + }); +} + +void el_uikit_widget_set_corner_radius(int64_t handle, int radius) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w || w->kind == EL_WIDGET_WINDOW) return; + UIView* v = (UIView*)w->obj; + v.layer.cornerRadius = (CGFloat)radius; + v.clipsToBounds = YES; + }); +} + +void el_uikit_widget_set_disabled(int64_t handle, int disabled) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + switch (w->kind) { + case EL_WIDGET_BUTTON: + ((UIButton*)w->obj).enabled = !disabled; + break; + case EL_WIDGET_TEXTFIELD: + ((UITextField*)w->obj).enabled = !disabled; + break; + case EL_WIDGET_TEXTAREA: + ((UITextView*)w->obj).editable = !disabled; + break; + default: + ((UIView*)w->obj).userInteractionEnabled = !disabled; + break; + } + }); +} + +void el_uikit_widget_set_hidden(int64_t handle, int hidden) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w || w->kind == EL_WIDGET_WINDOW) return; + ((UIView*)w->obj).hidden = (BOOL)hidden; + }); +} + +/* ── Child management ─────────────────────────────────────────────────────── */ + +/* + * el_uikit_widget_add_child — attach child widget to parent. + * + * - Window: child is added to the root UIStackView inside the root VC. + * - VStack/HStack: child is added as an arranged subview. + * - ZStack: child is added as a plain subview (caller manages layout). + * - ScrollView: child is added as a subview and pinned to content layout guide. + * - Generic view: child is added as a plain subview. + */ +void el_uikit_widget_add_child(int64_t parent, int64_t child) { + el_uikit_sync_main(^{ + ElWidget* pw = el_widget_get(parent); + ElWidget* cw = el_widget_get(child); + if (!pw || !cw) return; + if (cw->kind == EL_WIDGET_WINDOW) return; /* can't add window as subview */ + + UIView* childView = (UIView*)cw->obj; + + switch (pw->kind) { + case EL_WIDGET_WINDOW: { + /* Dig to the root stack view: window → navCtrl → topVC → view → subviews[0] */ + UIWindow* win = (UIWindow*)pw->obj; + UINavigationController* nav = + (UINavigationController*)win.rootViewController; + UIView* rootVCView = nav.topViewController.view; + UIStackView* stack = nil; + for (UIView* sub in rootVCView.subviews) { + if ([sub isKindOfClass:[UIStackView class]]) { + stack = (UIStackView*)sub; + break; + } + } + if (stack) { + [stack addArrangedSubview:childView]; + } else { + [rootVCView addSubview:childView]; + } + break; + } + case EL_WIDGET_VSTACK: + case EL_WIDGET_HSTACK: { + UIStackView* sv = (UIStackView*)pw->obj; + [sv addArrangedSubview:childView]; + break; + } + case EL_WIDGET_SCROLL: { + UIScrollView* sv = (UIScrollView*)pw->obj; + [sv addSubview:childView]; + /* Pin child to content layout guide so scroll view knows content size. */ + UILayoutGuide* cg = sv.contentLayoutGuide; + childView.translatesAutoresizingMaskIntoConstraints = NO; + [NSLayoutConstraint activateConstraints:@[ + [childView.topAnchor constraintEqualToAnchor:cg.topAnchor], + [childView.leadingAnchor constraintEqualToAnchor:cg.leadingAnchor], + [childView.trailingAnchor constraintEqualToAnchor:cg.trailingAnchor], + [childView.bottomAnchor constraintEqualToAnchor:cg.bottomAnchor], + /* Width matches scroll view's frame (vertical scroll only). */ + [childView.widthAnchor constraintEqualToAnchor:sv.frameLayoutGuide.widthAnchor], + ]]; + break; + } + case EL_WIDGET_ZSTACK: + default: { + UIView* pv = (UIView*)pw->obj; + [pv addSubview:childView]; + break; + } + } + }); +} + +/* + * el_uikit_widget_remove_child — detach a child widget from its parent. + */ +void el_uikit_widget_remove_child(int64_t parent, int64_t child) { + el_uikit_sync_main(^{ + ElWidget* pw = el_widget_get(parent); + ElWidget* cw = el_widget_get(child); + if (!cw || cw->kind == EL_WIDGET_WINDOW) return; + UIView* childView = (UIView*)cw->obj; + /* If parent is a stack view, remove from arranged subviews too. */ + if (pw && (pw->kind == EL_WIDGET_VSTACK || pw->kind == EL_WIDGET_HSTACK)) { + UIStackView* sv = (UIStackView*)pw->obj; + [sv removeArrangedSubview:childView]; + } else if (pw && pw->kind == EL_WIDGET_WINDOW) { + /* Find and remove from root stack. */ + UIWindow* win = (UIWindow*)pw->obj; + UINavigationController* nav = + (UINavigationController*)win.rootViewController; + for (UIView* sub in nav.topViewController.view.subviews) { + if ([sub isKindOfClass:[UIStackView class]]) { + [(UIStackView*)sub removeArrangedSubview:childView]; + break; + } + } + } + [childView removeFromSuperview]; + }); +} + +/* ── Event registration ───────────────────────────────────────────────────── */ + +void el_uikit_widget_on_click(int64_t handle, const char* fn_name) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + free(w->cb_click); + w->cb_click = (fn_name && *fn_name) ? strdup(fn_name) : NULL; +} + +void el_uikit_widget_on_change(int64_t handle, const char* fn_name) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + free(w->cb_change); + w->cb_change = (fn_name && *fn_name) ? strdup(fn_name) : NULL; +} + +void el_uikit_widget_on_submit(int64_t handle, const char* fn_name) { + /* For text fields, submit = return key → stored in cb_click slot. */ + el_uikit_widget_on_click(handle, fn_name); +} + +/* ── Widget destroy ───────────────────────────────────────────────────────── */ + +void el_uikit_widget_destroy(int64_t handle) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + if (w->kind != EL_WIDGET_WINDOW) { + UIView* v = (UIView*)w->obj; + /* If it's in a stack view, also remove from arranged subviews. */ + if ([v.superview isKindOfClass:[UIStackView class]]) { + [(UIStackView*)v.superview removeArrangedSubview:v]; + } + [v removeFromSuperview]; + } + [_el_delegates[handle] release]; + _el_delegates[handle] = nil; + el_widget_free(handle); + }); +} + +/* ── Manifest reader ──────────────────────────────────────────────────────── */ + +/* + * el_uikit_manifest_read — read an app manifest file. Tries the given path + * first; if not found, looks in the main bundle. Returns a C string with the + * file contents (heap-allocated; caller must not free — matches AppKit bridge + * convention of returning static/permanent lifetime strings from manifest). + * Returns NULL on failure. + */ +const char* el_uikit_manifest_read(const char* path) { + if (!path || !*path) return NULL; + + NSString* pathStr = [NSString stringWithUTF8String:path]; + NSString* content = [NSString stringWithContentsOfFile:pathStr + encoding:NSUTF8StringEncoding + error:nil]; + if (!content) { + /* Try bundle resource lookup — strip to last component without extension. */ + NSString* baseName = [[pathStr lastPathComponent] + stringByDeletingPathExtension]; + NSString* ext = [pathStr pathExtension]; + NSString* bundlePath = [[NSBundle mainBundle] + pathForResource:baseName ofType:(ext.length ? ext : nil)]; + if (bundlePath) { + content = [NSString stringWithContentsOfFile:bundlePath + encoding:NSUTF8StringEncoding + error:nil]; + } + } + if (!content) return NULL; + return strdup([content UTF8String]); +} + +/* ── __widget_* C API (called from el_seed.c) ─────────────────────────────── */ +/* + * These are the symbols that el compiled programs actually call. They forward + * directly to the el_uikit_* implementations above. el_val_t is int64_t (the + * same type used by the AppKit bridge). + */ + +void __native_init(void) { + el_uikit_init(); +} + +void __native_run_loop(void) { + /* el_main_entry_fn must be set by the caller before this. On iOS the + * entry function pointer pattern is inverted vs macOS: the el program + * packages up its "build UI" work into a lambda / function and registers + * it via el_main_entry_fn, then calls __native_run_loop. + * el_uikit_run_loop takes that fn pointer and passes it to UIApplicationMain. */ + el_uikit_run_loop(el_main_entry_fn); +} + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_uikit_window_create( + (const char*)(uintptr_t)title, + (int)width, (int)height, + (int)min_width, (int)min_height); +} + +void __window_show(el_val_t handle) { + el_uikit_window_show((int64_t)handle); +} + +void __window_set_title(el_val_t handle, el_val_t title) { + el_uikit_window_set_title((int64_t)handle, + (const char*)(uintptr_t)title); +} + +el_val_t __vstack_create(el_val_t spacing) { + return (el_val_t)el_uikit_vstack_create((int)spacing); +} + +el_val_t __hstack_create(el_val_t spacing) { + return (el_val_t)el_uikit_hstack_create((int)spacing); +} + +el_val_t __zstack_create(void) { + return (el_val_t)el_uikit_zstack_create(); +} + +el_val_t __scroll_create(void) { + return (el_val_t)el_uikit_scroll_create(); +} + +el_val_t __label_create(el_val_t text) { + return (el_val_t)el_uikit_label_create((const char*)(uintptr_t)text); +} + +el_val_t __button_create(el_val_t label) { + return (el_val_t)el_uikit_button_create((const char*)(uintptr_t)label); +} + +el_val_t __text_field_create(el_val_t placeholder) { + return (el_val_t)el_uikit_text_field_create( + (const char*)(uintptr_t)placeholder); +} + +el_val_t __text_area_create(el_val_t placeholder) { + return (el_val_t)el_uikit_text_area_create( + (const char*)(uintptr_t)placeholder); +} + +el_val_t __image_create(el_val_t path_or_name) { + return (el_val_t)el_uikit_image_create( + (const char*)(uintptr_t)path_or_name); +} + +void __widget_set_text(el_val_t handle, el_val_t text) { + el_uikit_widget_set_text((int64_t)handle, (const char*)(uintptr_t)text); +} + +el_val_t __widget_get_text(el_val_t handle) { + return (el_val_t)(uintptr_t)el_uikit_widget_get_text((int64_t)handle); +} + +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a) { + el_uikit_widget_set_color((int64_t)handle, + (float)r, (float)g, (float)b, (float)a); +} + +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a) { + el_uikit_widget_set_bg_color((int64_t)handle, + (float)r, (float)g, (float)b, (float)a); +} + +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold) { + el_uikit_widget_set_font((int64_t)handle, + (const char*)(uintptr_t)family, (int)size, (int)bold); +} + +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_uikit_widget_set_padding((int64_t)handle, + (int)top, (int)right, (int)bottom, (int)left); +} + +void __widget_set_width(el_val_t handle, el_val_t width) { + el_uikit_widget_set_width((int64_t)handle, (int)width); +} + +void __widget_set_height(el_val_t handle, el_val_t height) { + el_uikit_widget_set_height((int64_t)handle, (int)height); +} + +void __widget_set_flex(el_val_t handle, el_val_t flex) { + el_uikit_widget_set_flex((int64_t)handle, (int)flex); +} + +void __widget_set_corner_radius(el_val_t handle, el_val_t radius) { + el_uikit_widget_set_corner_radius((int64_t)handle, (int)radius); +} + +void __widget_set_disabled(el_val_t handle, el_val_t disabled) { + el_uikit_widget_set_disabled((int64_t)handle, (int)disabled); +} + +void __widget_set_hidden(el_val_t handle, el_val_t hidden) { + el_uikit_widget_set_hidden((int64_t)handle, (int)hidden); +} + +void __widget_add_child(el_val_t parent, el_val_t child) { + el_uikit_widget_add_child((int64_t)parent, (int64_t)child); +} + +void __widget_remove_child(el_val_t parent, el_val_t child) { + el_uikit_widget_remove_child((int64_t)parent, (int64_t)child); +} + +void __widget_destroy(el_val_t handle) { + el_uikit_widget_destroy((int64_t)handle); +} + +void __widget_on_click(el_val_t handle, el_val_t fn_name) { + el_uikit_widget_on_click((int64_t)handle, + (const char*)(uintptr_t)fn_name); +} + +void __widget_on_change(el_val_t handle, el_val_t fn_name) { + el_uikit_widget_on_change((int64_t)handle, + (const char*)(uintptr_t)fn_name); +} + +void __widget_on_submit(el_val_t handle, el_val_t fn_name) { + el_uikit_widget_on_submit((int64_t)handle, + (const char*)(uintptr_t)fn_name); +} + +el_val_t __manifest_read(el_val_t path) { + return (el_val_t)(uintptr_t)el_uikit_manifest_read( + (const char*)(uintptr_t)path); +} + +#endif /* EL_TARGET_IOS */ diff --git a/lang/el-compiler/runtime/el_win32.c b/lang/el-compiler/runtime/el_win32.c new file mode 100644 index 0000000..b99ea71 --- /dev/null +++ b/lang/el-compiler/runtime/el_win32.c @@ -0,0 +1,1363 @@ +/* + * el_win32.c — Win32 backend for the el native widget system. + * + * This file implements the Windows Win32 widget layer that el_seed.c calls + * through to when EL_TARGET_WIN32 is defined. + * + * Architecture: + * el program (el code) + * → __widget_* C builtins in el_seed.c + * → el_win32_* C functions declared here + * → HWND/Win32 API / GDI + * + * Widget handles: every widget (window, view, control) is assigned an int64_t + * slot index into _el_widgets[]. The el program holds these as opaque Int values. + * Slot 0 is never valid (reserved; handle -1 = invalid). + * + * Threading: Win32 UI must run on the main thread. el is single-threaded for + * native UI, so all calls are direct. The message loop runs on the main thread + * and never returns. + * + * Callback mechanism: when a widget fires an event (button click, text change), + * the bridge looks up the registered callback function name, then calls + * GetProcAddress(GetModuleHandle(NULL), fn_name)(widget_handle, event_data) + * This resolves the El function symbol at runtime, matching el_seed.c's + * dlsym(RTLD_DEFAULT, fn_name) pattern on POSIX. + * + * Layout: VStack and HStack containers maintain a child HWND list and reflow + * children on WM_SIZE using SetWindowPos. ZStack uses absolute positioning. + * + * Subclassing: SetWindowSubclass (comctl32) is used to intercept WM_COMMAND + * and WM_NOTIFY on container windows so button clicks and edit changes route + * back to el callbacks. + * + * String encoding: el strings are UTF-8 (const char*). All Win32 text APIs + * use wide strings (WCHAR*). Conversion via MultiByteToWideChar / + * WideCharToMultiByte throughout. + * + * Compile: + * cl /DEL_TARGET_WIN32 el_win32.c /c /Fo:el_win32.obj + * (link with: comctl32.lib user32.lib gdi32.lib) + * or with clang-cl: + * clang-cl /DEL_TARGET_WIN32 -c el_win32.c -o el_win32.obj + */ + +#ifdef EL_TARGET_WIN32 + +#define WIN32_LEAN_AND_MEAN +#ifndef UNICODE +#define UNICODE +#endif +#ifndef _UNICODE +#define _UNICODE +#endif + +#include +#include +#include +#include +#include +#include +#include "el_runtime.h" + +/* ── Compile-time linkage ─────────────────────────────────────────────────── */ +#pragma comment(lib, "comctl32.lib") +#pragma comment(lib, "user32.lib") +#pragma comment(lib, "gdi32.lib") + +/* ── Custom window messages ───────────────────────────────────────────────── */ +/* WM_USER+1: posted to a container to trigger a layout reflow pass. */ +#define WM_EL_REFLOW (WM_USER + 1) + +/* ── Widget type enum ─────────────────────────────────────────────────────── */ + +#define EL_WIN32_MAX_WIDGETS 4096 +#define EL_WIN32_MAX_CHILDREN 256 + +typedef enum { + EL_WIDGET_FREE = 0, + EL_WIDGET_WINDOW = 1, + EL_WIDGET_VSTACK = 2, + EL_WIDGET_HSTACK = 3, + EL_WIDGET_ZSTACK = 4, + EL_WIDGET_SCROLL = 5, + EL_WIDGET_LABEL = 6, + EL_WIDGET_BUTTON = 7, + EL_WIDGET_TEXTFIELD = 8, + EL_WIDGET_TEXTAREA = 9, + EL_WIDGET_IMAGE = 10, +} ElWidgetKind; + +/* Per-slot data. */ +typedef struct { + ElWidgetKind kind; + HWND hwnd; /* primary window handle; NULL if free */ + char* cb_click; /* El function name for click / submit events */ + char* cb_change; /* El function name for value-change events */ + + /* Layout data (used by VSTACK / HSTACK / ZSTACK / WINDOW containers) */ + int spacing; /* pixels between children */ + int pad_top; + int pad_right; + int pad_bottom; + int pad_left; + int flex; /* flex weight; 0 = fixed size */ + + /* Fixed size overrides (0 = not set) */ + int fixed_w; + int fixed_h; + + /* Child list for layout containers */ + int64_t children[EL_WIN32_MAX_CHILDREN]; + int child_count; + + /* Color state (stored for WM_CTLCOLOR* replies) */ + COLORREF fg_color; + COLORREF bg_color; + HBRUSH bg_brush; + int has_fg; + int has_bg; + + /* Font */ + HFONT font; /* NULL = default system font */ + + /* Image: HBITMAP loaded for SS_BITMAP static */ + HBITMAP hbmp; +} ElWidget; + +static ElWidget _el_widgets[EL_WIN32_MAX_WIDGETS]; +static int _el_widget_count = 0; + +/* ── Window class names ───────────────────────────────────────────────────── */ +static const WCHAR* EL_WNDCLASS_VSTACK = L"ElVStack"; +static const WCHAR* EL_WNDCLASS_HSTACK = L"ElHStack"; +static const WCHAR* EL_WNDCLASS_ZSTACK = L"ElZStack"; +static const WCHAR* EL_WNDCLASS_SCROLL = L"ElScroll"; +static const WCHAR* EL_WNDCLASS_WINDOW = L"ElWindow"; + +/* ── Forward declarations ─────────────────────────────────────────────────── */ +static void el_win32_reflow(int64_t container_handle); +static LRESULT CALLBACK el_container_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); +static LRESULT CALLBACK el_toplevel_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); + +/* ── String helpers ───────────────────────────────────────────────────────── */ + +/* UTF-8 → WCHAR*. Caller must free(). Returns NULL on failure. */ +static WCHAR* el_utf8_to_wide(const char* s) { + if (!s) s = ""; + int n = MultiByteToWideChar(CP_UTF8, 0, s, -1, NULL, 0); + if (n <= 0) return _wcsdup(L""); + WCHAR* buf = (WCHAR*)malloc((size_t)n * sizeof(WCHAR)); + if (!buf) return _wcsdup(L""); + MultiByteToWideChar(CP_UTF8, 0, s, -1, buf, n); + return buf; +} + +/* WCHAR* → UTF-8 char*. Caller must free(). Returns NULL on failure. */ +static char* el_wide_to_utf8(const WCHAR* ws) { + if (!ws) return strdup(""); + int n = WideCharToMultiByte(CP_UTF8, 0, ws, -1, NULL, 0, NULL, NULL); + if (n <= 0) return strdup(""); + char* buf = (char*)malloc((size_t)n); + if (!buf) return strdup(""); + WideCharToMultiByte(CP_UTF8, 0, ws, -1, buf, n, NULL, NULL); + return buf; +} + +/* ── Slot management ──────────────────────────────────────────────────────── */ + +static int64_t el_widget_alloc(ElWidgetKind kind, HWND hwnd) { + for (int i = 1; i < EL_WIN32_MAX_WIDGETS; i++) { + if (_el_widgets[i].kind == EL_WIDGET_FREE) { + ElWidget* w = &_el_widgets[i]; + memset(w, 0, sizeof(ElWidget)); + w->kind = kind; + w->hwnd = hwnd; + if (i > _el_widget_count) _el_widget_count = i; + return (int64_t)i; + } + } + return -1; +} + +static ElWidget* el_widget_get(int64_t handle) { + if (handle <= 0 || handle >= EL_WIN32_MAX_WIDGETS) return NULL; + if (_el_widgets[handle].kind == EL_WIDGET_FREE) return NULL; + return &_el_widgets[handle]; +} + +static void el_widget_free_slot(int64_t handle) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + free(w->cb_click); w->cb_click = NULL; + free(w->cb_change); w->cb_change = NULL; + if (w->bg_brush) { DeleteObject(w->bg_brush); w->bg_brush = NULL; } + if (w->font) { DeleteObject(w->font); w->font = NULL; } + if (w->hbmp) { DeleteObject(w->hbmp); w->hbmp = NULL; } + w->hwnd = NULL; + w->kind = EL_WIDGET_FREE; +} + +/* Map HWND → widget slot (O(n) linear scan; table is small). */ +static int64_t el_hwnd_to_slot(HWND hwnd) { + for (int i = 1; i <= _el_widget_count; i++) { + if (_el_widgets[i].kind != EL_WIDGET_FREE && _el_widgets[i].hwnd == hwnd) + return (int64_t)i; + } + return -1; +} + +/* ── El callback invocation ──────────────────────────────────────────────── */ +/* + * Invoke an El callback by symbol name. El functions have the signature: + * fn handler(handle: Int, data: String) -> Void + * compiled to: void fn_name(el_val_t handle, el_val_t data) + */ +typedef void (*ElCb2)(int64_t handle, int64_t data); + +static void el_win32_invoke_cb(const char* fn_name, int64_t handle, const char* data) { + if (!fn_name || !*fn_name) return; + FARPROC proc = GetProcAddress(GetModuleHandleW(NULL), fn_name); + if (!proc) return; + ElCb2 fn = (ElCb2)(void*)proc; + fn(handle, (int64_t)(uintptr_t)(data ? data : "")); +} + +/* ── Layout reflow ────────────────────────────────────────────────────────── */ +/* + * Reflow the direct children of a container widget. + * + * For VSTACK: stack children top-to-bottom, respecting padding and spacing. + * Children with flex > 0 divide the leftover height proportionally. + * Children with fixed_h > 0 use that height; otherwise QueryWidget. + * + * For HSTACK: same logic, left-to-right. + * + * For WINDOW: its content area is the client rect; children stacked vertically + * (WINDOW acts like an outer VSTACK for direct child attachment purposes). + * + * For ZSTACK: children fill the entire client rect (absolute; no reflow). + * + * For SCROLL: the single child fills the client rect width; height is its + * natural height (scroll bar handles overflow). + */ +static void el_win32_reflow(int64_t handle) { + ElWidget* pw = el_widget_get(handle); + if (!pw || !pw->hwnd) return; + + RECT cr; + GetClientRect(pw->hwnd, &cr); + int total_w = cr.right - cr.left; + int total_h = cr.bottom - cr.top; + + int pt = pw->pad_top; + int pr = pw->pad_right; + int pb = pw->pad_bottom; + int pl = pw->pad_left; + int sp = pw->spacing; + + int n = pw->child_count; + if (n == 0) return; + + if (pw->kind == EL_WIDGET_ZSTACK) { + /* All children fill the client rect. */ + int cw = total_w - pl - pr; + int ch = total_h - pt - pb; + if (cw < 0) cw = 0; + if (ch < 0) ch = 0; + for (int i = 0; i < n; i++) { + ElWidget* cw_ = el_widget_get(pw->children[i]); + if (!cw_ || !cw_->hwnd) continue; + SetWindowPos(cw_->hwnd, NULL, pl, pt, cw, ch, + SWP_NOZORDER | SWP_NOACTIVATE); + } + return; + } + + if (pw->kind == EL_WIDGET_SCROLL) { + /* Single child fills width; natural height. */ + if (n < 1) return; + ElWidget* cw_ = el_widget_get(pw->children[0]); + if (!cw_ || !cw_->hwnd) return; + int cw = total_w - pl - pr; + if (cw < 0) cw = 0; + /* Measure natural height. */ + RECT cr2; + GetWindowRect(cw_->hwnd, &cr2); + int ch = cr2.bottom - cr2.top; + if (cw_->fixed_h > 0) ch = cw_->fixed_h; + SetWindowPos(cw_->hwnd, NULL, pl, pt, cw, ch, + SWP_NOZORDER | SWP_NOACTIVATE); + /* Update scroll range. */ + SCROLLINFO si; + si.cbSize = sizeof(si); + si.fMask = SIF_RANGE | SIF_PAGE; + si.nMin = 0; + si.nMax = ch + pt + pb; + si.nPage = (UINT)total_h; + SetScrollInfo(pw->hwnd, SB_VERT, &si, TRUE); + return; + } + + /* VSTACK, HSTACK, WINDOW */ + int is_vert = (pw->kind == EL_WIDGET_VSTACK || + pw->kind == EL_WIDGET_WINDOW); + + /* First pass: determine fixed sizes and total flex weight. */ + int total_flex = 0; + int fixed_used = 0; /* pixels consumed by fixed children + spacing */ + + /* Per-child resolved size in the main axis. */ + int* sizes = (int*)malloc((size_t)n * sizeof(int)); + if (!sizes) return; + + for (int i = 0; i < n; i++) { + ElWidget* cw_ = el_widget_get(pw->children[i]); + sizes[i] = 0; + if (!cw_ || !cw_->hwnd) continue; + int fixed = is_vert ? cw_->fixed_h : cw_->fixed_w; + if (fixed > 0) { + sizes[i] = fixed; + fixed_used += fixed; + } else if (cw_->flex > 0) { + total_flex += cw_->flex; + } else { + /* No flex, no fixed: measure current window size as default. */ + RECT wr; + GetWindowRect(cw_->hwnd, &wr); + int nat = is_vert ? (wr.bottom - wr.top) : (wr.right - wr.left); + if (nat < 1) nat = is_vert ? 24 : 80; /* reasonable fallback */ + sizes[i] = nat; + fixed_used += nat; + } + if (i < n - 1) fixed_used += sp; /* spacing between children */ + } + + /* Available space for flex children. */ + int avail = (is_vert ? (total_h - pt - pb) : (total_w - pl - pr)) - fixed_used; + if (avail < 0) avail = 0; + + /* Second pass: assign flex sizes. */ + if (total_flex > 0) { + for (int i = 0; i < n; i++) { + ElWidget* cw_ = el_widget_get(pw->children[i]); + if (!cw_ || !cw_->hwnd) continue; + if (cw_->flex > 0 && sizes[i] == 0) { + sizes[i] = (avail * cw_->flex) / total_flex; + } + } + } + + /* Third pass: position children. */ + int cursor = is_vert ? pt : pl; + for (int i = 0; i < n; i++) { + ElWidget* cw_ = el_widget_get(pw->children[i]); + if (!cw_ || !cw_->hwnd) continue; + + int x, y, cw, ch; + if (is_vert) { + x = pl; + y = cursor; + cw = (cw_->fixed_w > 0) ? cw_->fixed_w : (total_w - pl - pr); + ch = sizes[i]; + if (cw < 0) cw = 0; + if (ch < 0) ch = 0; + cursor += ch + sp; + } else { + x = cursor; + y = pt; + cw = sizes[i]; + ch = (cw_->fixed_h > 0) ? cw_->fixed_h : (total_h - pt - pb); + if (cw < 0) cw = 0; + if (ch < 0) ch = 0; + cursor += cw + sp; + } + + SetWindowPos(cw_->hwnd, NULL, x, y, cw, ch, + SWP_NOZORDER | SWP_NOACTIVATE); + + /* Recursively reflow child containers. */ + if (cw_->kind == EL_WIDGET_VSTACK || + cw_->kind == EL_WIDGET_HSTACK || + cw_->kind == EL_WIDGET_ZSTACK || + cw_->kind == EL_WIDGET_SCROLL || + cw_->kind == EL_WIDGET_WINDOW) { + el_win32_reflow(pw->children[i]); + } + } + + free(sizes); +} + +/* ── Container WndProc ────────────────────────────────────────────────────── */ +/* + * Used for VSTACK, HSTACK, ZSTACK, SCROLL containers. + * Handles WM_SIZE (reflow), WM_CTLCOLOR* (color theming), WM_COMMAND (events), + * WM_VSCROLL (scroll container). + */ +static LRESULT CALLBACK el_container_wndproc(HWND hwnd, UINT msg, + WPARAM wp, LPARAM lp) { + int64_t slot = el_hwnd_to_slot(hwnd); + ElWidget* w = (slot >= 0) ? el_widget_get(slot) : NULL; + + switch (msg) { + case WM_SIZE: + if (w) el_win32_reflow(slot); + return 0; + + case WM_EL_REFLOW: + if (w) el_win32_reflow(slot); + return 0; + + case WM_VSCROLL: { + if (!w || w->kind != EL_WIDGET_SCROLL) break; + SCROLLINFO si; + si.cbSize = sizeof(si); + si.fMask = SIF_ALL; + GetScrollInfo(hwnd, SB_VERT, &si); + int pos = si.nPos; + switch (LOWORD(wp)) { + case SB_LINEUP: pos -= 20; break; + case SB_LINEDOWN: pos += 20; break; + case SB_PAGEUP: pos -= si.nPage; break; + case SB_PAGEDOWN: pos += si.nPage; break; + case SB_THUMBTRACK: pos = si.nTrackPos; break; + case SB_TOP: pos = si.nMin; break; + case SB_BOTTOM: pos = si.nMax; break; + } + if (pos < si.nMin) pos = si.nMin; + if (pos > si.nMax - (int)si.nPage) pos = si.nMax - (int)si.nPage; + si.fMask = SIF_POS; + si.nPos = pos; + SetScrollInfo(hwnd, SB_VERT, &si, TRUE); + /* Scroll child. */ + if (w->child_count > 0) { + ElWidget* cw_ = el_widget_get(w->children[0]); + if (cw_ && cw_->hwnd) { + RECT cr; GetClientRect(hwnd, &cr); + SetWindowPos(cw_->hwnd, NULL, 0, -pos, + cr.right - cr.left, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + } + } + return 0; + } + + case WM_COMMAND: { + /* Route click / change notifications to el callbacks. */ + HWND ctrl = (HWND)lp; + if (!ctrl) break; + int64_t cs = el_hwnd_to_slot(ctrl); + ElWidget* cw = (cs >= 0) ? el_widget_get(cs) : NULL; + if (!cw) break; + + WORD notif = HIWORD(wp); + if (cw->kind == EL_WIDGET_BUTTON && notif == BN_CLICKED) { + el_win32_invoke_cb(cw->cb_click, cs, ""); + } else if (cw->kind == EL_WIDGET_TEXTFIELD) { + if (notif == EN_CHANGE) { + el_win32_invoke_cb(cw->cb_change, cs, ""); + } + } else if (cw->kind == EL_WIDGET_TEXTAREA) { + if (notif == EN_CHANGE) { + el_win32_invoke_cb(cw->cb_change, cs, ""); + } + } + /* Propagate to parent so top-level window also sees it. */ + HWND parent = GetParent(hwnd); + if (parent) SendMessageW(parent, msg, wp, lp); + return 0; + } + + case WM_CTLCOLORSTATIC: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORBTN: { + HWND ctrl = (HWND)lp; + int64_t cs = el_hwnd_to_slot(ctrl); + ElWidget* cw = (cs >= 0) ? el_widget_get(cs) : NULL; + if (cw) { + HDC hdc = (HDC)wp; + if (cw->has_fg) SetTextColor(hdc, cw->fg_color); + if (cw->has_bg) { + SetBkColor(hdc, cw->bg_color); + if (cw->bg_brush) return (LRESULT)cw->bg_brush; + } + } + break; + } + + case WM_ERASEBKGND: { + if (w && w->has_bg && w->bg_brush) { + HDC hdc = (HDC)wp; + RECT rc; + GetClientRect(hwnd, &rc); + FillRect(hdc, &rc, w->bg_brush); + return 1; + } + break; + } + + case WM_DESTROY: + return 0; + } + + return DefWindowProcW(hwnd, msg, wp, lp); +} + +/* ── Top-level window WndProc ────────────────────────────────────────────── */ +static LRESULT CALLBACK el_toplevel_wndproc(HWND hwnd, UINT msg, + WPARAM wp, LPARAM lp) { + int64_t slot = el_hwnd_to_slot(hwnd); + ElWidget* w = (slot >= 0) ? el_widget_get(slot) : NULL; + + switch (msg) { + case WM_SIZE: + if (w) el_win32_reflow(slot); + return 0; + + case WM_EL_REFLOW: + if (w) el_win32_reflow(slot); + return 0; + + case WM_COMMAND: { + /* Bubble COMMAND messages from child controls. */ + HWND ctrl = (HWND)lp; + if (!ctrl) break; + int64_t cs = el_hwnd_to_slot(ctrl); + ElWidget* cw = (cs >= 0) ? el_widget_get(cs) : NULL; + if (!cw) { + /* Not a direct slot child — pass to DefWindowProc. */ + break; + } + WORD notif = HIWORD(wp); + if (cw->kind == EL_WIDGET_BUTTON && notif == BN_CLICKED) { + el_win32_invoke_cb(cw->cb_click, cs, ""); + } else if ((cw->kind == EL_WIDGET_TEXTFIELD || + cw->kind == EL_WIDGET_TEXTAREA) && notif == EN_CHANGE) { + el_win32_invoke_cb(cw->cb_change, cs, ""); + } + return 0; + } + + case WM_CTLCOLORSTATIC: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORBTN: { + HWND ctrl = (HWND)lp; + int64_t cs = el_hwnd_to_slot(ctrl); + ElWidget* cw = (cs >= 0) ? el_widget_get(cs) : NULL; + if (cw) { + HDC hdc = (HDC)wp; + if (cw->has_fg) SetTextColor(hdc, cw->fg_color); + if (cw->has_bg) { + SetBkColor(hdc, cw->bg_color); + if (cw->bg_brush) return (LRESULT)cw->bg_brush; + } + } + break; + } + + case WM_ERASEBKGND: { + if (w && w->has_bg && w->bg_brush) { + HDC hdc = (HDC)wp; + RECT rc; + GetClientRect(hwnd, &rc); + FillRect(hdc, &rc, w->bg_brush); + return 1; + } + break; + } + + case WM_GETMINMAXINFO: { + /* Stored in the window's GWLP_USERDATA as packed two ints: min_w | min_h. */ + LONG_PTR ud = GetWindowLongPtrW(hwnd, GWLP_USERDATA); + if (ud) { + int min_w = (int)(ud & 0xFFFF); + int min_h = (int)((ud >> 16) & 0xFFFF); + MINMAXINFO* mm = (MINMAXINFO*)lp; + if (min_w > 0) mm->ptMinTrackSize.x = min_w; + if (min_h > 0) mm->ptMinTrackSize.y = min_h; + } + return 0; + } + + case WM_CLOSE: + DestroyWindow(hwnd); + return 0; + + case WM_DESTROY: + PostQuitMessage(0); + return 0; + } + + return DefWindowProcW(hwnd, msg, wp, lp); +} + +/* ── Subclass proc for EDIT controls (Enter key → on_submit) ────────────── */ +static LRESULT CALLBACK el_edit_subclass_proc(HWND hwnd, UINT msg, WPARAM wp, + LPARAM lp, UINT_PTR uid, + DWORD_PTR ref_data) { + (void)uid; (void)ref_data; + if (msg == WM_KEYDOWN && wp == VK_RETURN) { + int64_t slot = el_hwnd_to_slot(hwnd); + ElWidget* w = (slot >= 0) ? el_widget_get(slot) : NULL; + if (w && w->cb_click) { + /* Gather current text as data. */ + int len = GetWindowTextLengthW(hwnd); + WCHAR* wbuf = (WCHAR*)malloc((size_t)(len + 2) * sizeof(WCHAR)); + if (wbuf) { + GetWindowTextW(hwnd, wbuf, len + 1); + char* utf8 = el_wide_to_utf8(wbuf); + free(wbuf); + el_win32_invoke_cb(w->cb_click, slot, utf8); + free(utf8); + } + return 0; /* suppress default beep */ + } + } + return DefSubclassProc(hwnd, msg, wp, lp); +} + +/* ── Window-class registration ────────────────────────────────────────────── */ +static int _el_classes_registered = 0; + +static void el_win32_register_classes(void) { + if (_el_classes_registered) return; + _el_classes_registered = 1; + + /* Initialize common controls (needed for SetWindowSubclass). */ + INITCOMMONCONTROLSEX icc; + icc.dwSize = sizeof(icc); + icc.dwICC = ICC_WIN95_CLASSES | ICC_STANDARD_CLASSES; + InitCommonControlsEx(&icc); + + HINSTANCE hinst = GetModuleHandleW(NULL); + + /* Container class (VStack, HStack, ZStack, Scroll) */ + WNDCLASSW wc; + memset(&wc, 0, sizeof(wc)); + wc.lpfnWndProc = el_container_wndproc; + wc.hInstance = hinst; + wc.hCursor = LoadCursorW(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wc.lpszClassName = EL_WNDCLASS_VSTACK; + RegisterClassW(&wc); + + wc.lpszClassName = EL_WNDCLASS_HSTACK; + RegisterClassW(&wc); + + wc.lpszClassName = EL_WNDCLASS_ZSTACK; + RegisterClassW(&wc); + + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpszClassName = EL_WNDCLASS_SCROLL; + RegisterClassW(&wc); + + /* Top-level window class */ + memset(&wc, 0, sizeof(wc)); + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = el_toplevel_wndproc; + wc.hInstance = hinst; + wc.hCursor = LoadCursorW(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wc.lpszClassName = EL_WNDCLASS_WINDOW; + RegisterClassW(&wc); +} + +/* ── Public C API ─────────────────────────────────────────────────────────── */ + +/* + * el_win32_init — one-time initialisation. Must be called before any other + * el_win32_* function. + */ +void el_win32_init(void) { + static int done = 0; + if (done) return; + done = 1; + el_win32_register_classes(); +} + +/* + * el_win32_run_loop — enter the Win32 message loop. Never returns. + * Must be called from the main thread after all windows are shown. + */ +void el_win32_run_loop(void) { + MSG msg; + while (GetMessageW(&msg, NULL, 0, 0) > 0) { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } +} + +/* ── Window ───────────────────────────────────────────────────────────────── */ + +int64_t el_win32_window_create(const char* title, int width, int height, + int min_width, int min_height) { + el_win32_register_classes(); + HINSTANCE hinst = GetModuleHandleW(NULL); + WCHAR* wtitle = el_utf8_to_wide(title ? title : ""); + + DWORD style = WS_OVERLAPPEDWINDOW; + HWND hwnd = CreateWindowW( + EL_WNDCLASS_WINDOW, + wtitle, + style, + CW_USEDEFAULT, CW_USEDEFAULT, + width, height, + NULL, NULL, hinst, NULL); + + free(wtitle); + if (!hwnd) return -1; + + /* Pack min_width / min_height into GWLP_USERDATA (low 16 = min_w, next 16 = min_h). */ + LONG_PTR ud = ((LONG_PTR)(min_height & 0xFFFF) << 16) | (LONG_PTR)(min_width & 0xFFFF); + SetWindowLongPtrW(hwnd, GWLP_USERDATA, ud); + + int64_t handle = el_widget_alloc(EL_WIDGET_WINDOW, hwnd); + if (handle < 0) { DestroyWindow(hwnd); return -1; } + + ElWidget* w = el_widget_get(handle); + w->spacing = 0; + + return handle; +} + +void el_win32_window_show(int64_t handle) { + ElWidget* w = el_widget_get(handle); + if (!w || w->kind != EL_WIDGET_WINDOW || !w->hwnd) return; + ShowWindow(w->hwnd, SW_SHOW); + UpdateWindow(w->hwnd); +} + +void el_win32_window_set_title(int64_t handle, const char* title) { + ElWidget* w = el_widget_get(handle); + if (!w || w->kind != EL_WIDGET_WINDOW || !w->hwnd) return; + WCHAR* wt = el_utf8_to_wide(title ? title : ""); + SetWindowTextW(w->hwnd, wt); + free(wt); +} + +/* ── Layout container factories ───────────────────────────────────────────── */ + +static int64_t el_win32_make_container(const WCHAR* class_name, ElWidgetKind kind, + int spacing) { + el_win32_register_classes(); + HWND hwnd = CreateWindowW( + class_name, + L"", + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN, + 0, 0, 0, 0, + HWND_MESSAGE, /* temporary parent; reparented on add_child */ + NULL, + GetModuleHandleW(NULL), + NULL); + if (!hwnd) return -1; + + int64_t handle = el_widget_alloc(kind, hwnd); + if (handle < 0) { DestroyWindow(hwnd); return -1; } + + ElWidget* w = el_widget_get(handle); + w->spacing = spacing; + return handle; +} + +int64_t el_win32_vstack_create(int spacing) { + return el_win32_make_container(EL_WNDCLASS_VSTACK, EL_WIDGET_VSTACK, spacing); +} + +int64_t el_win32_hstack_create(int spacing) { + return el_win32_make_container(EL_WNDCLASS_HSTACK, EL_WIDGET_HSTACK, spacing); +} + +int64_t el_win32_zstack_create(void) { + return el_win32_make_container(EL_WNDCLASS_ZSTACK, EL_WIDGET_ZSTACK, 0); +} + +int64_t el_win32_scroll_create(void) { + HWND hwnd = CreateWindowW( + EL_WNDCLASS_SCROLL, + L"", + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_VSCROLL, + 0, 0, 0, 0, + HWND_MESSAGE, + NULL, + GetModuleHandleW(NULL), + NULL); + if (!hwnd) return -1; + + int64_t handle = el_widget_alloc(EL_WIDGET_SCROLL, hwnd); + if (handle < 0) { DestroyWindow(hwnd); return -1; } + return handle; +} + +/* ── Widget factories ─────────────────────────────────────────────────────── */ + +int64_t el_win32_label_create(const char* text) { + el_win32_register_classes(); + WCHAR* wt = el_utf8_to_wide(text ? text : ""); + HWND hwnd = CreateWindowW( + L"STATIC", + wt, + WS_CHILD | WS_VISIBLE | SS_LEFT, + 0, 0, 0, 24, + HWND_MESSAGE, NULL, GetModuleHandleW(NULL), NULL); + free(wt); + if (!hwnd) return -1; + return el_widget_alloc(EL_WIDGET_LABEL, hwnd); +} + +int64_t el_win32_button_create(const char* label) { + el_win32_register_classes(); + WCHAR* wl = el_utf8_to_wide(label ? label : ""); + HWND hwnd = CreateWindowW( + L"BUTTON", + wl, + WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, + 0, 0, 0, 32, + HWND_MESSAGE, NULL, GetModuleHandleW(NULL), NULL); + free(wl); + if (!hwnd) return -1; + return el_widget_alloc(EL_WIDGET_BUTTON, hwnd); +} + +int64_t el_win32_text_field_create(const char* placeholder) { + el_win32_register_classes(); + HWND hwnd = CreateWindowW( + L"EDIT", + L"", + WS_CHILD | WS_VISIBLE | WS_BORDER | + ES_AUTOHSCROLL | ES_LEFT, + 0, 0, 0, 26, + HWND_MESSAGE, NULL, GetModuleHandleW(NULL), NULL); + if (!hwnd) return -1; + + /* Set placeholder / cue banner (Windows Vista+). */ + if (placeholder && *placeholder) { + WCHAR* wp = el_utf8_to_wide(placeholder); + SendMessageW(hwnd, EM_SETCUEBANNER, TRUE, (LPARAM)wp); + free(wp); + } + + int64_t handle = el_widget_alloc(EL_WIDGET_TEXTFIELD, hwnd); + if (handle < 0) { DestroyWindow(hwnd); return -1; } + + /* Subclass to intercept VK_RETURN for on_submit. */ + SetWindowSubclass(hwnd, el_edit_subclass_proc, (UINT_PTR)handle, 0); + return handle; +} + +int64_t el_win32_text_area_create(const char* placeholder) { + el_win32_register_classes(); + HWND hwnd = CreateWindowW( + L"EDIT", + L"", + WS_CHILD | WS_VISIBLE | WS_BORDER | + ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL, + 0, 0, 0, 80, + HWND_MESSAGE, NULL, GetModuleHandleW(NULL), NULL); + if (!hwnd) return -1; + + /* EDIT multiline does not support EM_SETCUEBANNER, so no placeholder. */ + (void)placeholder; + + int64_t handle = el_widget_alloc(EL_WIDGET_TEXTAREA, hwnd); + if (handle < 0) { DestroyWindow(hwnd); return -1; } + return handle; +} + +int64_t el_win32_image_create(const char* path) { + el_win32_register_classes(); + HWND hwnd = CreateWindowW( + L"STATIC", + L"", + WS_CHILD | WS_VISIBLE | SS_BITMAP | SS_REALSIZECONTROL, + 0, 0, 0, 0, + HWND_MESSAGE, NULL, GetModuleHandleW(NULL), NULL); + if (!hwnd) return -1; + + int64_t handle = el_widget_alloc(EL_WIDGET_IMAGE, hwnd); + if (handle < 0) { DestroyWindow(hwnd); return -1; } + + ElWidget* w = el_widget_get(handle); + + if (path && *path) { + WCHAR* wpath = el_utf8_to_wide(path); + HBITMAP hbmp = (HBITMAP)LoadImageW(NULL, wpath, IMAGE_BITMAP, + 0, 0, + LR_LOADFROMFILE | LR_DEFAULTSIZE); + free(wpath); + if (hbmp) { + w->hbmp = hbmp; + SendMessageW(hwnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp); + } + } + + return handle; +} + +/* ── Widget property setters ─────────────────────────────────────────────── */ + +void el_win32_widget_set_text(int64_t handle, const char* text) { + ElWidget* w = el_widget_get(handle); + if (!w || !w->hwnd) return; + WCHAR* wt = el_utf8_to_wide(text ? text : ""); + SetWindowTextW(w->hwnd, wt); + free(wt); +} + +const char* el_win32_widget_get_text(int64_t handle) { + ElWidget* w = el_widget_get(handle); + if (!w || !w->hwnd) return strdup(""); + int len = GetWindowTextLengthW(w->hwnd); + if (len <= 0) return strdup(""); + WCHAR* wbuf = (WCHAR*)malloc((size_t)(len + 2) * sizeof(WCHAR)); + if (!wbuf) return strdup(""); + GetWindowTextW(w->hwnd, wbuf, len + 1); + char* result = el_wide_to_utf8(wbuf); + free(wbuf); + return result; /* caller must free() */ +} + +void el_win32_widget_set_color(int64_t handle, float r, float g, float b, float a) { + (void)a; /* Win32 classic does not support per-control alpha */ + ElWidget* w = el_widget_get(handle); + if (!w || !w->hwnd) return; + w->fg_color = RGB((int)(r * 255.0f), (int)(g * 255.0f), (int)(b * 255.0f)); + w->has_fg = 1; + InvalidateRect(w->hwnd, NULL, TRUE); +} + +void el_win32_widget_set_bg_color(int64_t handle, float r, float g, float b, float a) { + (void)a; + ElWidget* w = el_widget_get(handle); + if (!w || !w->hwnd) return; + w->bg_color = RGB((int)(r * 255.0f), (int)(g * 255.0f), (int)(b * 255.0f)); + w->has_bg = 1; + if (w->bg_brush) DeleteObject(w->bg_brush); + w->bg_brush = CreateSolidBrush(w->bg_color); + InvalidateRect(w->hwnd, NULL, TRUE); +} + +void el_win32_widget_set_font(int64_t handle, const char* family, int size, int bold) { + ElWidget* w = el_widget_get(handle); + if (!w || !w->hwnd) return; + + LOGFONTW lf; + memset(&lf, 0, sizeof(lf)); + lf.lfHeight = -MulDiv(size > 0 ? size : 12, GetDeviceCaps(GetDC(NULL), LOGPIXELSY), 72); + lf.lfWeight = bold ? FW_BOLD : FW_NORMAL; + lf.lfCharSet = DEFAULT_CHARSET; + + if (family && *family && strcmp(family, "system") != 0) { + WCHAR* wf = el_utf8_to_wide(family); + wcsncpy(lf.lfFaceName, wf, LF_FACESIZE - 1); + free(wf); + } + /* family == NULL or "system" → lfFaceName stays zeroed → system font */ + + HFONT hfont = CreateFontIndirectW(&lf); + if (!hfont) return; + + if (w->font) DeleteObject(w->font); + w->font = hfont; + SendMessageW(w->hwnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0)); +} + +void el_win32_widget_set_padding(int64_t handle, int top, int right, + int bottom, int left) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + w->pad_top = top; + w->pad_right = right; + w->pad_bottom = bottom; + w->pad_left = left; + /* Trigger reflow if already parented. */ + if (w->hwnd) PostMessageW(w->hwnd, WM_EL_REFLOW, 0, 0); +} + +void el_win32_widget_set_width(int64_t handle, int width) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + w->fixed_w = width; + if (w->hwnd) { + RECT r; GetWindowRect(w->hwnd, &r); + int h = r.bottom - r.top; + SetWindowPos(w->hwnd, NULL, 0, 0, width, h, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + } +} + +void el_win32_widget_set_height(int64_t handle, int height) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + w->fixed_h = height; + if (w->hwnd) { + RECT r; GetWindowRect(w->hwnd, &r); + int cw = r.right - r.left; + SetWindowPos(w->hwnd, NULL, 0, 0, cw, height, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + } +} + +void el_win32_widget_set_flex(int64_t handle, int flex) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + w->flex = flex; + /* Let parent reflow absorb the change. */ +} + +void el_win32_widget_set_corner_radius(int64_t handle, int radius) { + /* + * Classic Win32 does not have native per-control corner radii. + * If radius > 0 we apply a rounded rectangular window region so the + * control at least clips to a rounded rect. This is approximate — it + * does not anti-alias and may look boxy on high-DPI displays. + */ + ElWidget* w = el_widget_get(handle); + if (!w || !w->hwnd || radius <= 0) return; + RECT r; GetWindowRect(w->hwnd, &r); + int ww = r.right - r.left; + int wh = r.bottom - r.top; + if (ww <= 0 || wh <= 0) return; + HRGN rgn = CreateRoundRectRgn(0, 0, ww, wh, radius * 2, radius * 2); + SetWindowRgn(w->hwnd, rgn, TRUE); + /* Note: SetWindowRgn takes ownership of rgn; do NOT DeleteObject it. */ +} + +void el_win32_widget_set_disabled(int64_t handle, int disabled) { + ElWidget* w = el_widget_get(handle); + if (!w || !w->hwnd) return; + EnableWindow(w->hwnd, disabled ? FALSE : TRUE); +} + +void el_win32_widget_set_hidden(int64_t handle, int hidden) { + ElWidget* w = el_widget_get(handle); + if (!w || !w->hwnd) return; + ShowWindow(w->hwnd, hidden ? SW_HIDE : SW_SHOW); +} + +/* ── Child management ─────────────────────────────────────────────────────── */ + +/* + * el_win32_widget_add_child — attach child widget to parent. + * + * - WINDOW / VSTACK / HSTACK / ZSTACK: SetParent child into container. + * - SCROLL: first child becomes the scrolled content. + * + * After reparenting, triggers a layout reflow of the parent. + */ +void el_win32_widget_add_child(int64_t parent, int64_t child) { + ElWidget* pw = el_widget_get(parent); + ElWidget* cw = el_widget_get(child); + if (!pw || !cw || !pw->hwnd || !cw->hwnd) return; + if (cw->kind == EL_WIDGET_WINDOW) return; /* cannot add window as child */ + if (pw->child_count >= EL_WIN32_MAX_CHILDREN) return; + + /* Reparent the child HWND into the container. */ + SetParent(cw->hwnd, pw->hwnd); + + /* Make sure the WS_CHILD style is set and WS_POPUP is cleared. */ + LONG_PTR style = GetWindowLongPtrW(cw->hwnd, GWL_STYLE); + style |= WS_CHILD; + style &= ~WS_POPUP; + SetWindowLongPtrW(cw->hwnd, GWL_STYLE, style); + ShowWindow(cw->hwnd, SW_SHOW); + + pw->children[pw->child_count++] = child; + + /* Reflow parent so the new child gets positioned. */ + el_win32_reflow(parent); +} + +void el_win32_widget_remove_child(int64_t parent, int64_t child) { + ElWidget* pw = el_widget_get(parent); + ElWidget* cw = el_widget_get(child); + if (!cw || !cw->hwnd) return; + + /* Detach HWND from parent. */ + SetParent(cw->hwnd, NULL); + + /* Remove from parent's child list. */ + if (pw) { + for (int i = 0; i < pw->child_count; i++) { + if (pw->children[i] == child) { + memmove(&pw->children[i], &pw->children[i + 1], + (size_t)(pw->child_count - i - 1) * sizeof(int64_t)); + pw->child_count--; + break; + } + } + el_win32_reflow(parent); + } +} + +/* ── Event registration ───────────────────────────────────────────────────── */ + +void el_win32_widget_on_click(int64_t handle, const char* fn_name) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + free(w->cb_click); + w->cb_click = (fn_name && *fn_name) ? strdup(fn_name) : NULL; +} + +void el_win32_widget_on_change(int64_t handle, const char* fn_name) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + free(w->cb_change); + w->cb_change = (fn_name && *fn_name) ? strdup(fn_name) : NULL; +} + +void el_win32_widget_on_submit(int64_t handle, const char* fn_name) { + /* For text fields, submit (Enter key) is stored in cb_click, same as AppKit. */ + el_win32_widget_on_click(handle, fn_name); +} + +/* ── Widget destroy ───────────────────────────────────────────────────────── */ + +void el_win32_widget_destroy(int64_t handle) { + ElWidget* w = el_widget_get(handle); + if (!w || !w->hwnd) return; + DestroyWindow(w->hwnd); + el_widget_free_slot(handle); +} + +/* ── Manifest reader ──────────────────────────────────────────────────────── */ +/* + * Same parser as the macOS implementation in el_seed.c. + * Reads the app{} block from a manifest.el file: + * + * app { + * window_title "My App" + * window_width 1200 + * window_height 800 + * min_width 600 + * min_height 400 + * } + * + * Returns JSON: {"title":"...","width":N,"height":N,"min_width":N,"min_height":N} + * Returns "{}" on failure. + * + * NOTE: el_seed.c already defines __manifest_read for both EL_TARGET_MACOS and + * EL_TARGET_WIN32 using the same parser body. We re-implement it here because + * el_seed.c's implementation is inside #ifdef EL_TARGET_MACOS; the Win32 + * version lives here, symmetric with the macOS one. + */ + +static void w32_manifest_skip_ws(const char** p) { + while (**p && (unsigned char)**p <= ' ') (*p)++; +} + +static char* w32_manifest_read_string(const char** p) { + w32_manifest_skip_ws(p); + if (**p != '"') return NULL; + (*p)++; + const char* start = *p; + while (**p && **p != '"') { + if (**p == '\\') (*p)++; + (*p)++; + } + size_t len = (size_t)(*p - start); + if (**p == '"') (*p)++; + char* out = (char*)malloc(len + 1); + if (!out) return NULL; + memcpy(out, start, len); + out[len] = '\0'; + return out; +} + +static int64_t w32_manifest_read_int(const char** p) { + w32_manifest_skip_ws(p); + int64_t result = 0; + int neg = 0; + if (**p == '-') { neg = 1; (*p)++; } + while (**p >= '0' && **p <= '9') { + result = result * 10 + (**p - '0'); + (*p)++; + } + return neg ? -result : result; +} + +static const char* w32_manifest_find_app_block(const char* src) { + while (*src) { + if (src[0] == '/' && src[1] == '/') { + while (*src && *src != '\n') src++; + continue; + } + if (strncmp(src, "app", 3) == 0 && + (src[3] == ' ' || src[3] == '\t' || src[3] == '\n' || src[3] == '{')) { + src += 3; + while (*src && *src != '{') src++; + if (*src == '{') return src + 1; + return NULL; + } + src++; + } + return NULL; +} + +/* el_val_t helpers — mirror of what el_seed.c provides. */ +#ifndef EL_CSTR +#define EL_CSTR(v) ((const char*)(uintptr_t)(v)) +#endif +#ifndef EL_STR +#define EL_STR(p) ((el_val_t)(uintptr_t)(p)) +#endif + +el_val_t el_win32_manifest_read(const char* path) { + if (!path || !*path) return EL_STR(strdup("{}")); + + FILE* f = fopen(path, "r"); + if (!f) return EL_STR(strdup("{}")); + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + if (sz <= 0) { fclose(f); return EL_STR(strdup("{}")); } + char* src = (char*)malloc((size_t)sz + 1); + if (!src) { fclose(f); return EL_STR(strdup("{}")); } + size_t got = fread(src, 1, (size_t)sz, f); + src[got] = '\0'; + fclose(f); + + const char* app_start = w32_manifest_find_app_block(src); + if (!app_start) { free(src); return EL_STR(strdup("{}")); } + + char* title = NULL; + int64_t width = 1200, height = 800; + int64_t min_w = 600, min_h = 400; + + const char* cur = app_start; + while (*cur && *cur != '}') { + while (*cur && (unsigned char)*cur <= ' ') cur++; + if (*cur == '}') break; + if (cur[0] == '/' && cur[1] == '/') { + while (*cur && *cur != '\n') cur++; + continue; + } + const char* key_start = cur; + while (*cur && (unsigned char)*cur > ' ' && *cur != '{' && *cur != '}') cur++; + size_t key_len = (size_t)(cur - key_start); + if (key_len == 0) { cur++; continue; } + while (*cur == ' ' || *cur == '\t') cur++; + + if (key_len == 12 && strncmp(key_start, "window_title", 12) == 0) { free(title); title = w32_manifest_read_string(&cur); } + else if (key_len == 12 && strncmp(key_start, "window_width", 12) == 0) { width = w32_manifest_read_int(&cur); } + else if (key_len == 13 && strncmp(key_start, "window_height", 13) == 0) { height = w32_manifest_read_int(&cur); } + else if (key_len == 9 && strncmp(key_start, "min_width", 9) == 0) { min_w = w32_manifest_read_int(&cur); } + else if (key_len == 10 && strncmp(key_start, "min_height", 10) == 0) { min_h = w32_manifest_read_int(&cur); } + else { while (*cur && *cur != '\n' && *cur != '}') cur++; } + } + + free(src); + + const char* t = title ? title : "App"; + size_t buf_sz = strlen(t) * 6 + 128; + char* buf = (char*)malloc(buf_sz); + if (!buf) { free(title); return EL_STR(strdup("{}")); } + snprintf(buf, buf_sz, + "{\"title\":\"%s\",\"width\":%lld,\"height\":%lld,\"min_width\":%lld,\"min_height\":%lld}", + t, (long long)width, (long long)height, (long long)min_w, (long long)min_h); + free(title); + return EL_STR(buf); +} + +/* ── el_seed.c __* builtins for EL_TARGET_WIN32 ──────────────────────────── */ +/* + * These are the thin el_val_t wrappers that el_seed.c (with EL_TARGET_WIN32) + * will call. They mirror the EL_TARGET_MACOS section in el_seed.c exactly. + * + * el_seed.c includes this file's declarations via el_native_target.h and + * links el_win32.o. The __* symbol definitions below are compiled into + * el_win32.c itself (not el_seed.c) when EL_TARGET_WIN32 is defined, keeping + * el_seed.c platform-agnostic. + */ + +/* Helper: extract el string pointer. */ +static inline const char* _w32_cstr(el_val_t v) { + return (const char*)(uintptr_t)v; +} +static inline el_val_t _w32_str(const char* p) { + return (el_val_t)(uintptr_t)p; +} + +/* Bit-cast helper for float args (el_val_t carries IEEE 754 doubles). */ +static inline double _w32_to_float(el_val_t v) { + union { double d; int64_t i; } u; u.i = (int64_t)v; return u.d; +} + +void __native_init(void) { el_win32_init(); } +void __native_run_loop(void) { el_win32_run_loop(); } + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_win32_window_create( + _w32_cstr(title), + (int)(int64_t)width, (int)(int64_t)height, + (int)(int64_t)min_width, (int)(int64_t)min_height); +} + +void __window_show(el_val_t h) { el_win32_window_show((int64_t)h); } +void __window_set_title(el_val_t h, el_val_t t) { el_win32_window_set_title((int64_t)h, _w32_cstr(t)); } + +el_val_t __vstack_create(el_val_t spacing) { return (el_val_t)el_win32_vstack_create((int)(int64_t)spacing); } +el_val_t __hstack_create(el_val_t spacing) { return (el_val_t)el_win32_hstack_create((int)(int64_t)spacing); } +el_val_t __zstack_create(void) { return (el_val_t)el_win32_zstack_create(); } +el_val_t __scroll_create(void) { return (el_val_t)el_win32_scroll_create(); } + +el_val_t __label_create(el_val_t text) { return (el_val_t)el_win32_label_create(_w32_cstr(text)); } +el_val_t __button_create(el_val_t label) { return (el_val_t)el_win32_button_create(_w32_cstr(label)); } +el_val_t __text_field_create(el_val_t placeholder) { return (el_val_t)el_win32_text_field_create(_w32_cstr(placeholder)); } +el_val_t __text_area_create(el_val_t placeholder) { return (el_val_t)el_win32_text_area_create(_w32_cstr(placeholder)); } +el_val_t __image_create(el_val_t path) { return (el_val_t)el_win32_image_create(_w32_cstr(path)); } + +void __widget_set_text(el_val_t h, el_val_t t) { el_win32_widget_set_text((int64_t)h, _w32_cstr(t)); } + +el_val_t __widget_get_text(el_val_t h) { + const char* s = el_win32_widget_get_text((int64_t)h); + /* el_win32_widget_get_text returns a malloc'd string; caller treats as + * short-lived (same contract as el_appkit version). */ + return s ? _w32_str(s) : _w32_str(strdup("")); +} + +void __widget_set_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_win32_widget_set_color((int64_t)h, + (float)_w32_to_float(r), (float)_w32_to_float(g), + (float)_w32_to_float(b), (float)_w32_to_float(a)); +} + +void __widget_set_bg_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_win32_widget_set_bg_color((int64_t)h, + (float)_w32_to_float(r), (float)_w32_to_float(g), + (float)_w32_to_float(b), (float)_w32_to_float(a)); +} + +void __widget_set_font(el_val_t h, el_val_t family, el_val_t size, el_val_t bold) { + el_win32_widget_set_font((int64_t)h, _w32_cstr(family), + (int)(int64_t)size, (int)(int64_t)bold); +} + +void __widget_set_padding(el_val_t h, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_win32_widget_set_padding((int64_t)h, + (int)(int64_t)top, (int)(int64_t)right, + (int)(int64_t)bottom, (int)(int64_t)left); +} + +void __widget_set_width(el_val_t h, el_val_t w) { el_win32_widget_set_width((int64_t)h, (int)(int64_t)w); } +void __widget_set_height(el_val_t h, el_val_t ht) { el_win32_widget_set_height((int64_t)h, (int)(int64_t)ht); } +void __widget_set_flex(el_val_t h, el_val_t f) { el_win32_widget_set_flex((int64_t)h, (int)(int64_t)f); } +void __widget_set_corner_radius(el_val_t h, el_val_t r) { el_win32_widget_set_corner_radius((int64_t)h, (int)(int64_t)r); } +void __widget_set_disabled(el_val_t h, el_val_t d) { el_win32_widget_set_disabled((int64_t)h, (int)(int64_t)d); } +void __widget_set_hidden(el_val_t h, el_val_t hid) { el_win32_widget_set_hidden((int64_t)h, (int)(int64_t)hid); } + +void __widget_add_child(el_val_t p, el_val_t c) { el_win32_widget_add_child((int64_t)p, (int64_t)c); } +void __widget_remove_child(el_val_t p, el_val_t c) { el_win32_widget_remove_child((int64_t)p, (int64_t)c); } +void __widget_destroy(el_val_t h) { el_win32_widget_destroy((int64_t)h); } + +void __widget_on_click(el_val_t h, el_val_t fn_name) { el_win32_widget_on_click((int64_t)h, _w32_cstr(fn_name)); } +void __widget_on_change(el_val_t h, el_val_t fn_name) { el_win32_widget_on_change((int64_t)h, _w32_cstr(fn_name)); } +void __widget_on_submit(el_val_t h, el_val_t fn_name) { el_win32_widget_on_submit((int64_t)h, _w32_cstr(fn_name)); } + +el_val_t __manifest_read(el_val_t path) { + return el_win32_manifest_read(_w32_cstr(path)); +} + +#endif /* EL_TARGET_WIN32 */ From edff25180e7683860910d85f4a990564a8f309cd Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Mon, 29 Jun 2026 12:40:26 -0500 Subject: [PATCH 12/13] feat(runtime): Java platform bridge and platform detection tooling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ElBridge.java: Android Java companion to el_android.c — all public methods are static, dispatches View mutations to the UI thread via runOnUiThread/CountDownLatch, and exposes native callbacks (nativeOnClick, nativeOnChange, nativeOnSubmit). PLATFORM_BRIDGE_SPEC.md: authoritative spec for implementing new platform bridges (slot table contract, required __* functions, callback dispatch pattern). detect-platforms: shell script that probes for available bridge toolchains and prints what can be built on the current machine. new-platform: scaffold generator that creates a new el_.c with all 33 required stubs wired up. --- lang/el-compiler/runtime/ElBridge.java | 711 ++++++++++++++++++ .../runtime/PLATFORM_BRIDGE_SPEC.md | 554 ++++++++++++++ lang/el-compiler/runtime/detect-platforms | 208 +++++ lang/el-compiler/runtime/new-platform | 711 ++++++++++++++++++ 4 files changed, 2184 insertions(+) create mode 100644 lang/el-compiler/runtime/ElBridge.java create mode 100644 lang/el-compiler/runtime/PLATFORM_BRIDGE_SPEC.md create mode 100755 lang/el-compiler/runtime/detect-platforms create mode 100755 lang/el-compiler/runtime/new-platform diff --git a/lang/el-compiler/runtime/ElBridge.java b/lang/el-compiler/runtime/ElBridge.java new file mode 100644 index 0000000..52cb402 --- /dev/null +++ b/lang/el-compiler/runtime/ElBridge.java @@ -0,0 +1,711 @@ +/* + * ElBridge.java — Android Java companion to el_android.c. + * + * All public methods are static. The C JNI layer calls these to create views, + * set properties, and manage the widget tree. Views are identified by integer + * slot indices matching the C-side handle values. + * + * Threading: every method that touches a View dispatches to the UI thread + * using Activity.runOnUiThread(Runnable) and blocks with a CountDownLatch + * until the UI thread completes the operation. This mirrors the AppKit + * dispatch_sync(main_queue, ^{}) pattern in el_appkit.m. + * + * Callbacks: Java sets listeners on views that call back into C via: + * nativeOnClick(int slot) + * nativeOnChange(int slot, String text) + * nativeOnSubmit(int slot, String text) + * These are declared native and implemented in el_android.c. + * + * Usage (in your Activity.onCreate): + * System.loadLibrary("elruntime"); + * ElBridge.init(this); + * + * The native library calls __native_init() which calls nativeRegisterActivity + * via the C side; alternatively call ElBridge.init(this) directly from Java. + * + * Compile requirements: + * Android minSdkVersion 21 (Lollipop) or higher. + * No third-party dependencies — uses only android.* framework classes. + * For image loading from arbitrary file paths, BitmapFactory is used. + * To replace with Glide/Picasso, edit createImageView only. + */ + +package com.neuron.el; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.Typeface; +import android.graphics.drawable.GradientDrawable; +import android.os.Handler; +import android.os.Looper; +import android.text.Editable; +import android.text.InputType; +import android.text.TextWatcher; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; + +import java.util.concurrent.CountDownLatch; + +public class ElBridge { + + /* ── Native callbacks (implemented in el_android.c) ─────────────────── */ + + public static native void nativeOnClick(int slot); + public static native void nativeOnChange(int slot, String text); + public static native void nativeOnSubmit(int slot, String text); + public static native void nativeRegisterActivity(Activity activity); + + /* ── State ───────────────────────────────────────────────────────────── */ + + private static final int MAX_SLOTS = 4096; + + private static Activity sActivity; + private static Handler sUiHandler; + private static View[] sViews = new View[MAX_SLOTS]; + private static int sNextSlot = 1; /* slot 0 reserved / null */ + + /* ── Init ────────────────────────────────────────────────────────────── */ + + /** + * Must be called from the Activity before any widget operations. + * Typically called from Activity.onCreate after System.loadLibrary. + */ + public static void init(Activity activity) { + sActivity = activity; + sUiHandler = new Handler(Looper.getMainLooper()); + nativeRegisterActivity(activity); + } + + /* ── Slot management ─────────────────────────────────────────────────── */ + + private static int allocSlot(View v) { + /* Find a free slot starting from sNextSlot, wrap around. */ + for (int i = 0; i < MAX_SLOTS - 1; i++) { + int idx = ((sNextSlot - 1 + i) % (MAX_SLOTS - 1)) + 1; + if (sViews[idx] == null) { + sViews[idx] = v; + sNextSlot = (idx % (MAX_SLOTS - 1)) + 1; + return idx; + } + } + android.util.Log.e("ElBridge", "allocSlot: slot table full"); + return -1; + } + + private static View getView(int slot) { + if (slot <= 0 || slot >= MAX_SLOTS) return null; + return sViews[slot]; + } + + /* ── UI-thread dispatch helper ───────────────────────────────────────── */ + + /* + * Dispatch r on the UI thread and block until it completes. + * Safe to call from the UI thread itself (runs inline without posting). + */ + private static void runSync(final Runnable r) { + if (Looper.myLooper() == Looper.getMainLooper()) { + r.run(); + } else { + final CountDownLatch latch = new CountDownLatch(1); + sUiHandler.post(new Runnable() { + @Override public void run() { + try { r.run(); } finally { latch.countDown(); } + } + }); + try { latch.await(); } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + + /* ── Integer slot returning runSync helper ───────────────────────────── */ + + private interface IntSupplier { int get(); } + + private static int runSyncInt(final IntSupplier s) { + final int[] result = { -1 }; + runSync(new Runnable() { + @Override public void run() { result[0] = s.get(); } + }); + return result[0]; + } + + /* ── Context accessor ────────────────────────────────────────────────── */ + + private static Context ctx() { return sActivity; } + + /* ── View creation ───────────────────────────────────────────────────── */ + + /** + * Create a LinearLayout. + * @param orientation 1=VERTICAL, 0=HORIZONTAL + * @param spacing gap between children in dp; applied as bottom/right margin + */ + public static int createLinearLayout(final int orientation, final int spacing) { + return runSyncInt(new IntSupplier() { + @Override public int get() { + LinearLayout ll = new LinearLayout(ctx()); + ll.setOrientation(orientation == 1 + ? LinearLayout.VERTICAL + : LinearLayout.HORIZONTAL); + ll.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + /* Spacing is stored so addChild can apply margins. */ + ll.setTag(R_TAG_SPACING, spacing); + return allocSlot(ll); + } + }); + } + + /** Create a FrameLayout (ZStack equivalent). */ + public static int createFrameLayout() { + return runSyncInt(new IntSupplier() { + @Override public int get() { + FrameLayout fl = new FrameLayout(ctx()); + fl.setLayoutParams(new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + return allocSlot(fl); + } + }); + } + + /** Create a ScrollView. */ + public static int createScrollView() { + return runSyncInt(new IntSupplier() { + @Override public int get() { + ScrollView sv = new ScrollView(ctx()); + sv.setLayoutParams(new ScrollView.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + sv.setFillViewport(true); + return allocSlot(sv); + } + }); + } + + /** Create a TextView with initial text. */ + public static int createTextView(final String text) { + return runSyncInt(new IntSupplier() { + @Override public int get() { + TextView tv = new TextView(ctx()); + tv.setText(text != null ? text : ""); + tv.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + return allocSlot(tv); + } + }); + } + + /** Create a Button with a label. */ + public static int createButton(final String label) { + return runSyncInt(new IntSupplier() { + @Override public int get() { + Button btn = new Button(ctx()); + btn.setText(label != null ? label : ""); + btn.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + return allocSlot(btn); + } + }); + } + + /** + * Create an EditText. + * @param placeholder hint text + * @param singleLine true = single-line text field; false = multi-line text area + */ + public static int createEditText(final String placeholder, final boolean singleLine) { + return runSyncInt(new IntSupplier() { + @Override public int get() { + EditText et = new EditText(ctx()); + et.setHint(placeholder != null ? placeholder : ""); + if (singleLine) { + et.setInputType(InputType.TYPE_CLASS_TEXT + | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); + et.setMaxLines(1); + et.setSingleLine(true); + } else { + et.setInputType(InputType.TYPE_CLASS_TEXT + | InputType.TYPE_TEXT_FLAG_MULTI_LINE); + et.setMinLines(3); + et.setSingleLine(false); + et.setGravity(Gravity.TOP | Gravity.START); + } + et.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + return allocSlot(et); + } + }); + } + + /** + * Create an ImageView, loading from a file path via BitmapFactory. + * If path is null/empty the ImageView is created with no image. + */ + public static int createImageView(final String path) { + return runSyncInt(new IntSupplier() { + @Override public int get() { + ImageView iv = new ImageView(ctx()); + iv.setScaleType(ImageView.ScaleType.FIT_CENTER); + iv.setAdjustViewBounds(true); + if (path != null && !path.isEmpty()) { + Bitmap bmp = BitmapFactory.decodeFile(path); + if (bmp != null) { + iv.setImageBitmap(bmp); + } else { + android.util.Log.w("ElBridge", + "createImageView: failed to decode " + path); + } + } + iv.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + return allocSlot(iv); + } + }); + } + + /* ── Window operations ───────────────────────────────────────────────── */ + + /** Set the Activity's content view to the view at slot. */ + public static void setContentView(final int slot) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v != null && sActivity != null) { + sActivity.setContentView(v); + } + } + }); + } + + /** Set the Activity title. */ + public static void setTitle(final String title) { + runSync(new Runnable() { + @Override public void run() { + if (sActivity != null) { + sActivity.setTitle(title != null ? title : ""); + } + } + }); + } + + /* ── Tree operations ─────────────────────────────────────────────────── */ + + /** + * Add child view to parent view. + * LinearLayout: child added as arranged child with spacing margin. + * ScrollView: child replaces current document view. + * FrameLayout / other ViewGroup: plain addView. + */ + public static void addChild(final int parentSlot, final int childSlot) { + runSync(new Runnable() { + @Override public void run() { + View parent = getView(parentSlot); + View child = getView(childSlot); + if (parent == null || child == null) return; + + /* Remove child from existing parent first. */ + if (child.getParent() instanceof ViewGroup) { + ((ViewGroup) child.getParent()).removeView(child); + } + + if (parent instanceof LinearLayout) { + LinearLayout ll = (LinearLayout) parent; + Object tag = ll.getTag(R_TAG_SPACING); + int spacing = (tag instanceof Integer) ? (Integer) tag : 0; + LinearLayout.LayoutParams lp; + Object existingLp = child.getLayoutParams(); + if (existingLp instanceof LinearLayout.LayoutParams) { + lp = (LinearLayout.LayoutParams) existingLp; + } else { + lp = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + } + /* Apply spacing as margin on the leading/top edge (after first child). */ + if (ll.getChildCount() > 0 && spacing > 0) { + int px = dpToPx(spacing); + if (ll.getOrientation() == LinearLayout.VERTICAL) { + lp.topMargin = px; + } else { + lp.leftMargin = px; + } + } + child.setLayoutParams(lp); + ll.addView(child); + } else if (parent instanceof ScrollView) { + ScrollView sv = (ScrollView) parent; + sv.removeAllViews(); + sv.addView(child); + } else if (parent instanceof ViewGroup) { + ((ViewGroup) parent).addView(child); + } + } + }); + } + + /** Remove child from its parent. */ + public static void removeChild(final int parentSlot, final int childSlot) { + runSync(new Runnable() { + @Override public void run() { + View parent = getView(parentSlot); + View child = getView(childSlot); + if (parent instanceof ViewGroup && child != null) { + ((ViewGroup) parent).removeView(child); + } + } + }); + } + + /** Remove the view from its parent and release the slot. */ + public static void destroyView(final int slot) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v == null) return; + if (v.getParent() instanceof ViewGroup) { + ((ViewGroup) v.getParent()).removeView(v); + } + sViews[slot] = null; + } + }); + } + + /* ── Property setters ────────────────────────────────────────────────── */ + + public static void setText(final int slot, final String text) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + String s = text != null ? text : ""; + if (v instanceof EditText) { + ((EditText) v).setText(s); + } else if (v instanceof Button) { + ((Button) v).setText(s); + } else if (v instanceof TextView) { + ((TextView) v).setText(s); + } + } + }); + } + + public static String getText(final int slot) { + final String[] result = { "" }; + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v instanceof TextView) { + CharSequence cs = ((TextView) v).getText(); + result[0] = cs != null ? cs.toString() : ""; + } + } + }); + return result[0]; + } + + /** Set foreground text color. Components in [0,1]. */ + public static void setTextColor(final int slot, final float r, final float g, + final float b, final float a) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v instanceof TextView) { + ((TextView) v).setTextColor(floatToArgb(r, g, b, a)); + } + } + }); + } + + /** Set background color using a GradientDrawable so corner radius is preserved. */ + public static void setBackgroundColor(final int slot, final float r, final float g, + final float b, final float a) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v == null) return; + ensureGradientBackground(v); + GradientDrawable gd = (GradientDrawable) v.getBackground(); + gd.setColor(floatToArgb(r, g, b, a)); + } + }); + } + + /** + * Set font family and size. + * family: "system" or null → system default; otherwise tries to load by name. + * bold: if true uses Typeface.BOLD. + */ + public static void setFont(final int slot, final String family, + final int sizeSp, final boolean bold) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (!(v instanceof TextView)) return; + TextView tv = (TextView) v; + Typeface tf; + if (family != null && !family.isEmpty() + && !family.equals("system")) { + Typeface base = Typeface.create(family, + bold ? Typeface.BOLD : Typeface.NORMAL); + tf = (base != null) ? base + : Typeface.defaultFromStyle(bold ? Typeface.BOLD : Typeface.NORMAL); + } else { + tf = Typeface.defaultFromStyle(bold ? Typeface.BOLD : Typeface.NORMAL); + } + tv.setTypeface(tf); + tv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, sizeSp); + } + }); + } + + /** Set padding in dp. */ + public static void setPadding(final int slot, final int top, final int right, + final int bottom, final int left) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v != null) { + v.setPadding(dpToPx(left), dpToPx(top), dpToPx(right), dpToPx(bottom)); + } + } + }); + } + + /** Set explicit width in dp. Passes MATCH_PARENT for negative values. */ + public static void setWidth(final int slot, final int widthDp) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v == null) return; + ViewGroup.LayoutParams lp = v.getLayoutParams(); + if (lp == null) lp = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + lp.width = widthDp < 0 + ? ViewGroup.LayoutParams.MATCH_PARENT + : dpToPx(widthDp); + v.setLayoutParams(lp); + } + }); + } + + /** Set explicit height in dp. */ + public static void setHeight(final int slot, final int heightDp) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v == null) return; + ViewGroup.LayoutParams lp = v.getLayoutParams(); + if (lp == null) lp = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + lp.height = heightDp < 0 + ? ViewGroup.LayoutParams.MATCH_PARENT + : dpToPx(heightDp); + v.setLayoutParams(lp); + } + }); + } + + /** + * Set flex weight on a child of a LinearLayout. + * flex > 0 → weight = flex, width/height = 0dp (expand). + * flex == 0 → weight = 0, wrap_content (shrink to content). + */ + public static void setFlex(final int slot, final int flex) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v == null) return; + ViewGroup.LayoutParams lp = v.getLayoutParams(); + if (lp instanceof LinearLayout.LayoutParams) { + LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams) lp; + if (flex > 0) { + llp.weight = (float) flex; + /* Determine orientation from parent to set 0dp on the right axis. */ + if (v.getParent() instanceof LinearLayout) { + LinearLayout parent = (LinearLayout) v.getParent(); + if (parent.getOrientation() == LinearLayout.VERTICAL) { + llp.height = 0; + } else { + llp.width = 0; + } + } + } else { + llp.weight = 0f; + } + v.setLayoutParams(llp); + } + } + }); + } + + /** Set corner radius in dp using a GradientDrawable background. */ + public static void setCornerRadius(final int slot, final float radiusDp) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v == null) return; + ensureGradientBackground(v); + GradientDrawable gd = (GradientDrawable) v.getBackground(); + gd.setCornerRadius(dpToPxF(radiusDp)); + } + }); + } + + public static void setEnabled(final int slot, final boolean enabled) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v != null) v.setEnabled(enabled); + } + }); + } + + /** + * Show or hide a view. + * @param visible true = VISIBLE, false = GONE (matches AppKit setHidden semantics) + */ + public static void setVisibility(final int slot, final boolean visible) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v != null) v.setVisibility(visible ? View.VISIBLE : View.GONE); + } + }); + } + + /* ── Event listener registration ─────────────────────────────────────── */ + + /** Register an OnClickListener that calls back into C nativeOnClick. */ + public static void setOnClickListener(final int slot) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v == null) return; + final int capturedSlot = slot; + v.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View view) { + nativeOnClick(capturedSlot); + } + }); + } + }); + } + + /** + * Register a TextWatcher on an EditText that calls back nativeOnChange + * for every text change. + */ + public static void setOnChangeListener(final int slot) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (!(v instanceof EditText)) return; + final int capturedSlot = slot; + ((EditText) v).addTextChangedListener(new TextWatcher() { + @Override public void beforeTextChanged(CharSequence s, int start, + int count, int after) {} + @Override public void onTextChanged(CharSequence s, int start, + int before, int count) {} + @Override public void afterTextChanged(Editable s) { + nativeOnChange(capturedSlot, s != null ? s.toString() : ""); + } + }); + } + }); + } + + /** + * Register an OnEditorActionListener on a single-line EditText that calls + * nativeOnSubmit when the user presses the action/enter key. + */ + public static void setOnSubmitListener(final int slot) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (!(v instanceof EditText)) return; + final int capturedSlot = slot; + ((EditText) v).setOnEditorActionListener( + new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView tv, int actionId, + android.view.KeyEvent event) { + nativeOnSubmit(capturedSlot, + tv.getText() != null ? tv.getText().toString() : ""); + return true; + } + }); + } + }); + } + + /* ── Internal helpers ─────────────────────────────────────────────────── */ + + /* + * Tag key used to stash the spacing value on LinearLayouts so addChild + * can apply the correct margin between children. + * We use a stable integer resource-id-like value; because we do not have + * a resources file here we use View.generateViewId() lazily. + */ + private static int sSpacingTagKey = 0; + + private static int R_TAG_SPACING; + static { + R_TAG_SPACING = View.generateViewId(); + } + + /** Convert dp to pixels using the Activity's display metrics. */ + private static int dpToPx(float dp) { + if (sActivity == null) return (int) dp; + float density = sActivity.getResources().getDisplayMetrics().density; + return Math.round(dp * density); + } + + private static float dpToPxF(float dp) { + if (sActivity == null) return dp; + float density = sActivity.getResources().getDisplayMetrics().density; + return dp * density; + } + + /** Convert RGBA float components (0–1) to an Android ARGB int. */ + private static int floatToArgb(float r, float g, float b, float a) { + int ai = Math.round(a * 255f); + int ri = Math.round(r * 255f); + int gi = Math.round(g * 255f); + int bi = Math.round(b * 255f); + return Color.argb(ai, ri, gi, bi); + } + + /** + * Ensure the view has a GradientDrawable background so that both color + * and corner radius can be set independently. If the current background + * is already a GradientDrawable it is reused; otherwise a new transparent + * one is installed. + */ + private static void ensureGradientBackground(View v) { + if (!(v.getBackground() instanceof GradientDrawable)) { + GradientDrawable gd = new GradientDrawable(); + gd.setColor(Color.TRANSPARENT); + v.setBackground(gd); + } + } +} diff --git a/lang/el-compiler/runtime/PLATFORM_BRIDGE_SPEC.md b/lang/el-compiler/runtime/PLATFORM_BRIDGE_SPEC.md new file mode 100644 index 0000000..82d37e4 --- /dev/null +++ b/lang/el-compiler/runtime/PLATFORM_BRIDGE_SPEC.md @@ -0,0 +1,554 @@ +# Platform Bridge Specification — el-native + +This document is the authoritative reference for anyone implementing a new platform bridge for the el-native widget system. Read it top to bottom before writing a single line of code. + +--- + +## What a Platform Bridge Is + +The el compiler (`elc`) emits C code. That C code calls `__`-prefixed functions for everything OS-related: printing, file I/O, threading, and — when building a native UI app — widget creation and event handling. These `__` functions are the *OS boundary*. + +For native UI, the bridge is the translation layer between that fixed C API and whatever platform toolkit you are targeting. The bridge owns: + +1. A **slot table** of up to 4096 widget objects, indexed by `int64_t` handle. +2. Implementations of all 33 `__*` widget functions declared in `el_native_target.h`. +3. Callback dispatch from platform events back into El function symbols resolved via `dlsym` (or a platform equivalent). + +The thin wrappers in `el_seed.c` (`#ifdef EL_TARGET_*` blocks) marshal between `el_val_t` and native C types, then call through to the bridge. The bridge itself never touches `el_val_t` — it works only with plain C types (`int64_t`, `const char*`, `int`, `float`). + +**Existing bridges:** + +| File | Platform | Toolkit | Language | +|------|----------|---------|----------| +| `el_appkit.m` | macOS | AppKit | ObjC (MRC) | +| `el_gtk4.c` | Linux | GTK4 | C | +| `el_win32.c` | Windows | Win32/ComCtl | C | +| `el_uikit.m` | iOS | UIKit | ObjC (MRC) | +| `el_android.c` + `ElBridge.java` | Android | View/JNI | C + Java | +| `el_sdl2.c` | Embedded Linux / Pi | SDL2 | C | +| `el_lvgl.c` | Microcontrollers | LVGL | C | + +--- + +## The Slot System + +Every widget — window, button, label, container, image — is stored in a static array: + +```c +#define EL__MAX_WIDGETS 4096 + +typedef struct { + ElWidgetKind kind; + /* platform-specific object reference (pointer, handle, ID...) */ + /* callback names */ + char* cb_click; + char* cb_change; +} ElWidget; + +static ElWidget _el_widgets[EL__MAX_WIDGETS]; +``` + +Rules: +- **Slot 0 is never valid.** Scan starts at index 1. This ensures 0 is never a valid handle. +- **Handle = slot index.** An `int64_t` value returned to El code is a direct index into `_el_widgets[]`. +- **-1 = invalid.** All create functions return -1 on failure (table full, platform API error). +- **Slot is FREE until allocated, FREE again after destroy.** Use an `ElWidgetKind` enum where `0 = EL_WIDGET_FREE` to track liveness. +- **4096 slots is the system-wide maximum.** This is intentional and sufficient for any realistic UI. Do not increase it without a compelling reason. + +### Slot allocation and release pattern + +```c +static int64_t el_widget_alloc(ElWidgetKind kind, /* platform object ref */) { + for (int i = 1; i < EL__MAX_WIDGETS; i++) { + if (_el_widgets[i].kind == EL_WIDGET_FREE) { + _el_widgets[i].kind = kind; + /* store platform object ref — retain/addref if needed */ + _el_widgets[i].cb_click = NULL; + _el_widgets[i].cb_change = NULL; + return (int64_t)i; + } + } + return -1; /* table full */ +} + +static ElWidget* el_widget_get(int64_t handle) { + if (handle <= 0 || handle >= EL__MAX_WIDGETS) return NULL; + if (_el_widgets[handle].kind == EL_WIDGET_FREE) return NULL; + return &_el_widgets[handle]; +} + +static void el_widget_free(int64_t handle) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + /* release platform object ref */ + w->kind = EL_WIDGET_FREE; + free(w->cb_click); w->cb_click = NULL; + free(w->cb_change); w->cb_change = NULL; +} +``` + +**NULL handle guard:** `el_widget_get` must return `NULL` for any handle that is 0, negative, out of range, or points to a `FREE` slot. Every `__` function that takes a handle must null-check the result of `el_widget_get` before doing anything. Failing to do so causes crashes or corruption when El code passes an uninitialized handle. + +--- + +## The 33 Required Functions + +Every bridge must implement all 33 functions listed below. They are grouped by category. The signatures shown are from `el_native_target.h` and from `el_seed.c`'s wrapper layer; the bridge itself uses plain C types (the wrappers do the `el_val_t` ↔ C-type conversion). + +### Internal C signatures (what the bridge implements) + +These are what your `.c` / `.m` file defines. The `el_seed.c` wrappers call these. + +#### Lifecycle (2 functions) + +```c +void el__init(void); +``` +**Purpose:** Initialize the platform UI toolkit. Must be idempotent (safe to call more than once). Called once from `__native_init` before any widget creation. +**Edge cases:** On platforms where the toolkit must be initialized before a display connection is established (X11, Wayland), this is where that happens. On Android, this is a no-op because ElBridge.java calls init from Java. + +```c +void el__run_loop(void); +``` +**Purpose:** Start the platform event loop. On most platforms this **never returns**. Exceptions: Android (the loop is Java-managed — this must be a no-op) and headless test builds. +**Edge cases:** Must be called from the main thread. On iOS/UIKit, calls `UIApplicationMain` which never returns; El code must set `el_main_entry_fn` before calling this. + +#### Window (3 functions) + +```c +int64_t el__window_create(const char* title, int w, int h, int mw, int mh); +``` +**Purpose:** Create a top-level window. `w`/`h` = initial size in logical pixels. `mw`/`mh` = minimum size (0 = no minimum). +**Returns:** Slot handle, or -1 on failure. +**Edge cases:** NULL or empty `title` must be handled gracefully (use `""`). On mobile (iOS, Android), the concept of a "window" maps to the root view controller / activity root view — create that here. + +```c +void el__window_show(int64_t handle); +``` +**Purpose:** Make the window visible. On some platforms windows are hidden at creation; this makes them appear. +**Edge cases:** NULL handle → return silently. Calling on an already-visible window is a no-op. + +```c +void el__window_set_title(int64_t handle, const char* title); +``` +**Purpose:** Update the window's title bar text at runtime. +**Edge cases:** NULL handle or NULL title → no-op. + +#### Layout containers (4 functions) + +```c +int64_t el__vstack_create(int spacing); +int64_t el__hstack_create(int spacing); +``` +**Purpose:** Create a vertical/horizontal linear container. `spacing` = gap between children in logical pixels. +**Returns:** Slot handle, or -1. +**Edge cases:** spacing = 0 is valid and common. + +```c +int64_t el__zstack_create(void); +``` +**Purpose:** Create a z-axis layered container (children overlap, no stacking direction). Used for overlays. +**Returns:** Slot handle, or -1. + +```c +int64_t el__scroll_create(void); +``` +**Purpose:** Create a scrollable container. Scrolls vertically by default. Only the first child added is the scrollable content. +**Returns:** Slot handle, or -1. + +#### Leaf widgets (5 functions) + +```c +int64_t el__label_create(const char* text); +``` +**Purpose:** Create a non-editable text label. +**Edge cases:** NULL/empty text → label with empty string, not a crash. + +```c +int64_t el__button_create(const char* label); +``` +**Purpose:** Create a clickable button. The `label` is the button's visible text. +**Edge cases:** The button must wire up an action target at creation time so that click callbacks registered later via `el__widget_on_click` will fire. On platforms with target-action (AppKit, UIKit), allocate the delegate object here. + +```c +int64_t el__text_field_create(const char* placeholder); +``` +**Purpose:** Create a single-line text input. `placeholder` is the hint text shown when empty. +**Edge cases:** NULL placeholder → no hint text displayed. + +```c +int64_t el__text_area_create(const char* placeholder); +``` +**Purpose:** Create a multi-line text input (scrollable). +**Edge cases:** Same as text_field_create. On AppKit, this wraps NSTextView inside NSScrollView — the slot's `obj` points to the scroll view, not the text view. + +```c +int64_t el__image_create(const char* path_or_name); +``` +**Purpose:** Create an image widget. `path_or_name` can be a filesystem path or a platform resource name. Try path first, fall back to named resource. +**Edge cases:** Non-existent path → create an empty image widget (do not crash). NULL → same. + +#### Widget properties (12 functions) + +```c +void el__widget_set_text(int64_t handle, const char* text); +``` +**Purpose:** Update the text content of a label, button, text field, text area, or window title. Must dispatch on `kind` to use the correct API. +**Edge cases:** NULL handle → no-op. NULL text → treat as `""`. + +```c +const char* el__widget_get_text(int64_t handle); +``` +**Purpose:** Return the current text of a widget. Returns a `const char*` that the `el_seed.c` wrapper wraps into an `el_val_t` string. +**Edge cases:** NULL handle → return `""` (never NULL). The caller in `el_seed.c` handles the `strdup` lifetime issue — see the AppKit reference implementation notes. + +```c +void el__widget_set_color(int64_t h, float r, float g, float b, float a); +void el__widget_set_bg_color(int64_t h, float r, float g, float b, float a); +``` +**Purpose:** Set foreground (text) color and background color respectively. All channels are normalized floats [0.0, 1.0]. +**Edge cases:** For containers, `set_color` may be a no-op (no text); `set_bg_color` should set the layer/surface background. On platforms without alpha compositing, clamp alpha to 0 or 1. + +```c +void el__widget_set_font(int64_t h, const char* family, int size, int bold); +``` +**Purpose:** Set the font on a text-bearing widget. `family` = font family name or `"system"` for the platform default. `size` = point size. `bold` = 0 or 1. +**Edge cases:** If `family` is not found, fall back to the system font. Non-text widgets (containers, images) → no-op. + +```c +void el__widget_set_padding(int64_t h, int top, int right, int bottom, int left); +``` +**Purpose:** Set internal padding/insets for a container or text area. +**Edge cases:** On platforms where padding is per-view (not per-container), map to the nearest equivalent (margin, insets, text container inset). For leaf widgets other than text areas, this may be a partial no-op. + +```c +void el__widget_set_width(int64_t h, int width); +void el__widget_set_height(int64_t h, int height); +``` +**Purpose:** Apply a fixed-size constraint. `width`/`height` in logical pixels. +**Edge cases:** On platforms with Auto Layout or constraint systems, add a fixed-size constraint. Do not apply to windows (size is set at creation). Calling multiple times should override the previous constraint, not add another. + +```c +void el__widget_set_flex(int64_t h, int flex); +``` +**Purpose:** Set the flex/expansion factor. `flex > 0` → the widget expands to fill available space. `flex == 0` → hugs content size. +**Edge cases:** Maps to content-hugging priority (AppKit), `GtkWidget::hexpand`/`vexpand` (GTK4), or layout weight (Android). For windows → no-op. + +```c +void el__widget_set_corner_radius(int64_t h, int radius); +``` +**Purpose:** Apply rounded corners to the widget's visual layer. +**Edge cases:** Requires backing layer / GPU surface. On platforms without layer compositing (Win32 without DX), this may be a no-op or require manual painting. Radius in logical pixels. + +```c +void el__widget_set_disabled(int64_t h, int disabled); +``` +**Purpose:** Enable or disable user interaction. `disabled = 1` → greyed out, non-interactive. +**Edge cases:** Only meaningful for interactive widgets (button, text field). For containers/labels → no-op. + +```c +void el__widget_set_hidden(int64_t h, int hidden); +``` +**Purpose:** Show or hide the widget. `hidden = 1` → invisible but still in layout. +**Edge cases:** For windows, map to `orderOut`/`hide` or equivalent. For views, use `setHidden`/`gtk_widget_set_visible` or equivalent. + +#### Tree management (3 functions) + +```c +void el__widget_add_child(int64_t parent, int64_t child); +``` +**Purpose:** Attach a child widget to a parent container. Dispatch on parent kind: +- Window → add to root content view/container +- VStack/HStack → add as arranged/linear child +- ZStack → add as overlapping subview +- Scroll → set as document/content view (first child only) +- Other → add as plain subview + +**Edge cases:** NULL parent or child handle → no-op. Attempting to add a window as a child → no-op. Adding the same child twice is platform-defined behavior (tolerate it). + +```c +void el__widget_remove_child(int64_t parent, int64_t child); +``` +**Purpose:** Detach child from its parent. The child slot remains allocated; the widget is not destroyed. +**Edge cases:** NULL handles → no-op. Child not currently attached → no-op. + +```c +void el__widget_destroy(int64_t handle); +``` +**Purpose:** Destroy a widget: remove from superview/parent, release the platform object, release callback strings, mark slot as FREE. +**Edge cases:** For windows, close the window. Free any delegate/target objects stored in side tables. After destroy, the handle is invalid — El code must not use it again (this is the caller's responsibility, not enforced here). + +#### Event registration (3 functions) + +```c +void el__widget_on_click(int64_t h, const char* fn_name); +void el__widget_on_change(int64_t h, const char* fn_name); +void el__widget_on_submit(int64_t h, const char* fn_name); +``` +**Purpose:** Register an El callback function by symbol name. +- `on_click` → button press +- `on_change` → text field value change (keystroke-level) +- `on_submit` → text field Enter key (text field only; stored in `cb_click` slot in AppKit) + +The implementation stores `strdup(fn_name)` in the widget's `cb_click` or `cb_change` field. The platform event handler calls `el__invoke_cb` (see callback ABI section). +**Edge cases:** NULL or empty `fn_name` → clear the callback (`free` + set NULL). Calling on a non-interactive widget (label, image) → no-op or store silently (harmless). + +#### Manifest reader (1 function) + +```c +/* Note: __manifest_read is implemented in el_seed.c, not in the bridge. */ +/* Bridges do NOT need to implement this. */ +``` + +`__manifest_read` is handled entirely in the platform-independent section of `el_seed.c`. It reads a JSON/EL manifest file from the path in the `EL_MANIFEST` environment variable. Bridge authors do not need to implement this. + +--- + +## The Callback ABI + +When a platform event fires (button clicked, text changed), the bridge must call back into the El runtime. The mechanism: + +```c +typedef void (*ElCb2)(int64_t handle, int64_t data); + +static void el__invoke_cb(const char* fn_name, int64_t handle, const char* data) { + if (!fn_name || !*fn_name) return; + void* sym = dlsym(RTLD_DEFAULT, fn_name); + if (!sym) return; + ElCb2 fn = (ElCb2)sym; + fn(handle, (int64_t)(uintptr_t)(data ? data : "")); +} +``` + +The El callback signature (in El source): +``` +fn handler(handle: Int, data: String) -> Void +``` + +Which compiles to: +```c +void handler(int64_t handle, int64_t data) +``` + +Where `data` is a `const char*` cast to `int64_t` (the el `String` representation). For click events, `data` is `""`. For change/submit events, `data` is the current widget text. + +**On platforms without `dlsym`** (Windows, some embedded systems): use `GetProcAddress(GetModuleHandle(NULL), fn_name)` on Windows, or maintain a manual symbol registration table for embedded targets where dynamic linking is unavailable. + +**Thread safety for callbacks:** Callbacks fired from a background thread must be marshalled to the UI thread before calling into El code. El code may call `__widget_set_text` or other UI functions synchronously from within the callback — those must run on the UI thread. + +--- + +## Thread Safety Contract + +**All platform UI operations must execute on the main/UI thread.** This is a hard requirement on every platform (AppKit, UIKit, GTK4, Win32, Android View, SDL2 main thread rule). + +The reference pattern (AppKit): +```c +static void el_appkit_sync_main(void (^block)(void)) { + if ([NSThread isMainThread]) { + block(); + } else { + dispatch_sync(dispatch_get_main_queue(), block); + } +} +``` + +For other platforms: +- **GTK4:** `g_main_context_invoke` or `g_idle_add` + semaphore for synchronous dispatch +- **Win32:** `SendMessage(hwnd, WM_APP, ...)` or `PostMessage` + wait +- **Android:** `Activity.runOnUiThread` +- **SDL2:** All ops must be called from the thread that initialized SDL (the main thread) +- **LVGL:** `lv_lock()` / `lv_unlock()` for thread-safe access + +El program flow is: `main()` → build UI (on main thread) → `__native_run_loop()`. Because UI is built before the run loop starts, most widget creation calls are already on the main thread. The sync dispatch wrapper exists to handle callbacks that arrive on worker threads (e.g., network callbacks that update UI). + +--- + +## Integration Pattern + +### In `el_native_target.h` + +Add an `#ifdef EL_TARGET_` block declaring all 33 `__*` functions with their `el_val_t` signatures (identical to the existing blocks for MACOS, LINUX, etc.): + +```c +#ifdef EL_TARGET_ + +void __native_init(void); +void __native_run_loop(void); + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_ */ +``` + +### In `el_seed.c` + +Add an `#ifdef EL_TARGET_` block containing: +1. `extern` declarations of all `el__*` functions (your bridge's C API) +2. Thin wrapper functions that marshal `el_val_t` ↔ C types and call through + +The wrapper pattern (copy from the `EL_TARGET_MACOS` block and substitute the platform name): + +```c +#ifdef EL_TARGET_ + +/* Forward declarations — implemented in el_.c */ +extern void el__init(void); +extern void el__run_loop(void); +extern int64_t el__window_create(const char* title, int w, int h, int mw, int mh); +/* ... all others ... */ + +/* Wrappers */ +void __native_init(void) { el__init(); } +void __native_run_loop(void) { el__run_loop(); } + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el__window_create( + EL_CSTR(title), + (int)(int64_t)width, (int)(int64_t)height, + (int)(int64_t)min_width, (int)(int64_t)min_height); +} + +void __window_show(el_val_t h) { el__window_show((int64_t)h); } +void __window_set_title(el_val_t h, el_val_t t) { el__window_set_title((int64_t)h, EL_CSTR(t)); } + +/* ... continue for all 33 functions ... */ + +#endif /* EL_TARGET_ */ +``` + +Key marshalling rules: +- `el_val_t` → `int64_t` handle: `(int64_t)h` +- `el_val_t` → `int`: `(int)(int64_t)value` +- `el_val_t` → `const char*`: `EL_CSTR(value)` +- `el_val_t` → `float`: `(float)el_to_float(value)` (for color channels) +- `int64_t` handle → `el_val_t`: `(el_val_t)handle` +- `const char*` → `el_val_t`: `EL_STR(str)` — but read the get_text note below + +**`__widget_get_text` note:** The bridge returns `const char*`. The `el_seed.c` wrapper wraps it with `EL_STR(s)`. The returned pointer must remain valid until the El program is done with it. The AppKit implementation returns a `strdup`'d string — the caller (seed wrapper) stores it without tracking it in the arena. This is a known lifetime edge; be consistent with the platform's existing pattern. + +--- + +## How el Strings Work + +Inside El compiled C code, strings are `el_val_t` values where the value is the `uintptr_t` cast of a `const char*`: + +```c +#define EL_STR(s) ((el_val_t)(uintptr_t)(s)) +#define EL_CSTR(v) ((const char*)(uintptr_t)(v)) +``` + +To construct a string result in `el_seed.c`: +```c +static char* s = strdup("hello"); +return EL_STR(s); +``` + +To read a string argument passed from El: +```c +const char* text = EL_CSTR(some_el_val_t_argument); +``` + +The `EL_STR` / `EL_CSTR` macros are defined in `el_seed.h` and are available in `el_seed.c`. Bridge files (`el_.c`) do not use these macros — they only deal in `const char*` at their API boundary. + +--- + +## Known Gotchas + +### Duplicate symbols with `el_runtime.c` + +`el_runtime.c` defines many of the same `__`-prefixed symbols as `el_seed.c`. When linking both (required for the native-hello example), the linker will reject duplicate definitions. The build system uses `nmedit` (macOS) to hide the `el_runtime.c` copies of symbols that `el_seed.c` already defines, keeping `el_seed.c` canonical. + +If you are writing a build script for a new platform and see duplicate symbol link errors involving `__println`, `__print`, `__str_len`, etc., apply the same nmedit / `objcopy --weaken-symbol` / `strip --strip-symbol` trick from the macOS build to your platform's object file handling. + +### The `nmedit` trick on macOS + +```bash +# Build a keep-list: symbols defined in el_seed.o but also in el_runtime.o +nm el_seed.o | awk '/^[0-9a-f]+ T _/{print $3}' | sort > .seed_T.txt +nm el_runtime.o | awk '/^[0-9a-f]+ T _/{print $3}' | sort > .rt_T.txt +# Keep only symbols unique to el_runtime.o +comm -23 .rt_T.txt .seed_T.txt > .rt_keep.txt +nmedit -s .rt_keep.txt el_runtime.o +``` + +On Linux, use `objcopy` with `--weaken-symbol` for each duplicate, or link `el_seed.o` before `el_runtime.o` and use `--allow-multiple-definition` if your use case permits it. + +### ObjC bridges must use MRC, not ARC + +Bridges that use Objective-C (AppKit, UIKit) **must** compile without ARC (`-fno-objc-arc`). The reason: the widget table stores `id` values in a plain C struct. ARC cannot insert retain/release through C struct boundaries, and will reject explicit `[obj retain]` / `[obj release]` calls in ARC mode. Use: + +```bash +clang -ObjC -fno-objc-arc -framework Cocoa -c el_appkit.m +``` + +### Widget table struct — don't put `id` fields in C structs under ARC + +If you ever add ARC-managed object fields to the `ElWidget` struct, you will get a compile error. Keep the struct C-only (pointers as `void*` if you must, cast when using) or compile as MRC. + +### The `el_seed.c` `__manifest_read` is platform-independent + +`__manifest_read` is already implemented in `el_seed.c` (in the section compiled unconditionally). You do not implement it in your bridge. You do need to declare it in the `el_native_target.h` block for your platform (matching the other platforms), but `el_seed.c` already has the implementation. + +--- + +## Completion Checklist + +Before declaring your bridge ready for integration: + +- [ ] All 33 `__*` functions implemented (including `__manifest_read` declaration, implementation is in seed) +- [ ] Slot table with 4096 entries, scan starting at index 1 +- [ ] `el_widget_get` returns NULL for handle 0, negative, out-of-range, and FREE slots +- [ ] All functions null-check `el_widget_get` result before use +- [ ] `el__init` is idempotent +- [ ] `el__run_loop` either never returns or is documented as a no-op (Android) +- [ ] Callback dispatch via `dlsym` (or platform equivalent) implemented +- [ ] All UI operations dispatched to the main/UI thread +- [ ] `el_native_target.h` updated with `#ifdef EL_TARGET_` block +- [ ] `el_seed.c` updated with `#ifdef EL_TARGET_` extern + wrapper block +- [ ] Bridge compiles cleanly with no warnings: `cc -DEL_TARGET_ -Wall -Wextra -c el_.c` +- [ ] Bridge links cleanly with `el_seed.o` and `el_runtime.o` (duplicate symbol check) +- [ ] `detect-platforms` script updated with detection logic for the new platform +- [ ] Basic smoke test: create window → add label → show window → run loop diff --git a/lang/el-compiler/runtime/detect-platforms b/lang/el-compiler/runtime/detect-platforms new file mode 100755 index 0000000..bceace2 --- /dev/null +++ b/lang/el-compiler/runtime/detect-platforms @@ -0,0 +1,208 @@ +#!/usr/bin/env bash +# detect-platforms — probe available platform bridge dependencies +# +# Reports which el-native platform bridges can be built on this machine, +# with install instructions for anything that is missing. +# +# Usage: ./detect-platforms +# ./build.sh platforms (from native-hello) + +set -uo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# ── Helpers ─────────────────────────────────────────────────────────────────── + +PASS="[+]" +FAIL="[ ]" + +_ok() { printf " ${PASS} %-22s %s\n" "$1" "$2"; } +_miss() { printf " ${FAIL} %-22s %s\n" "$1" "$2"; } + +# ── Header ──────────────────────────────────────────────────────────────────── + +echo "" +echo "==> el-native platform detection" +echo "" +echo " Checking build dependencies for each platform bridge..." +echo "" + +AVAILABLE=0 +MISSING=0 + +# ── macOS / AppKit ──────────────────────────────────────────────────────────── + +if [[ "$(uname)" == "Darwin" ]]; then + if xcrun --find clang &>/dev/null && xcrun --find xcodebuild &>/dev/null 2>/dev/null || \ + xcrun --find cc &>/dev/null; then + CLT_INFO="Xcode CLT $(xcode-select -p 2>/dev/null | sed 's|/Developer||' || echo '')" + _ok "macOS/AppKit" "-DEL_TARGET_MACOS ${CLT_INFO}" + AVAILABLE=$((AVAILABLE + 1)) + else + _miss "macOS/AppKit" "-DEL_TARGET_MACOS (Xcode CLT missing — xcode-select --install)" + MISSING=$((MISSING + 1)) + fi +else + _miss "macOS/AppKit" "-DEL_TARGET_MACOS (not on macOS)" +fi + +# ── iOS / UIKit ─────────────────────────────────────────────────────────────── + +if [[ "$(uname)" == "Darwin" ]]; then + if xcrun --sdk iphoneos --show-sdk-path &>/dev/null 2>&1; then + SDK_VER=$(xcrun --sdk iphoneos --show-sdk-version 2>/dev/null || echo "") + _ok "iOS/UIKit" "-DEL_TARGET_IOS SDK ${SDK_VER} (requires Xcode.app)" + AVAILABLE=$((AVAILABLE + 1)) + else + _miss "iOS/UIKit" "-DEL_TARGET_IOS (iOS SDK not found — install Xcode.app)" + MISSING=$((MISSING + 1)) + fi +else + _miss "iOS/UIKit" "-DEL_TARGET_IOS (not on macOS — requires Xcode)" +fi + +# ── Linux / GTK4 ────────────────────────────────────────────────────────────── + +if pkg-config --exists gtk4 2>/dev/null; then + GTK_VER=$(pkg-config --modversion gtk4 2>/dev/null) + _ok "Linux/GTK4" "-DEL_TARGET_LINUX gtk4 ${GTK_VER}" + AVAILABLE=$((AVAILABLE + 1)) +else + _miss "Linux/GTK4" "-DEL_TARGET_LINUX (gtk4 not found)" + echo " Install: apt install libgtk-4-dev" + echo " or: dnf install gtk4-devel" + echo " or: brew install gtk4" + MISSING=$((MISSING + 1)) +fi + +# ── SDL2 / Embedded Linux / Pi ──────────────────────────────────────────────── + +SDL2_OK=0 +if pkg-config --exists sdl2 2>/dev/null; then + SDL2_VER=$(pkg-config --modversion sdl2 2>/dev/null) + # Also check for SDL2_ttf (needed for text rendering) + if pkg-config --exists SDL2_ttf 2>/dev/null; then + TTF_VER=$(pkg-config --modversion SDL2_ttf 2>/dev/null) + _ok "SDL2/Embedded" "-DEL_TARGET_SDL2 sdl2 ${SDL2_VER}, SDL2_ttf ${TTF_VER}" + else + _ok "SDL2/Embedded" "-DEL_TARGET_SDL2 sdl2 ${SDL2_VER} (SDL2_ttf missing — needed for text)" + echo " Install: apt install libsdl2-ttf-dev" + fi + SDL2_OK=1 + AVAILABLE=$((AVAILABLE + 1)) +elif command -v sdl2-config &>/dev/null; then + SDL2_VER=$(sdl2-config --version 2>/dev/null || echo "") + _ok "SDL2/Embedded" "-DEL_TARGET_SDL2 sdl2 ${SDL2_VER} (via sdl2-config)" + SDL2_OK=1 + AVAILABLE=$((AVAILABLE + 1)) +fi + +if [[ $SDL2_OK -eq 0 ]]; then + _miss "SDL2/Embedded" "-DEL_TARGET_SDL2 (sdl2 not found)" + echo " Install: apt install libsdl2-dev libsdl2-ttf-dev libsdl2-image-dev" + echo " or: brew install sdl2 sdl2_ttf sdl2_image" + MISSING=$((MISSING + 1)) +fi + +# ── LVGL / Microcontrollers ─────────────────────────────────────────────────── + +LVGL_OK=0 +LVGL_WHERE="" + +if [ -f "${SCRIPT_DIR}/lvgl/lvgl.h" ]; then + LVGL_WHERE="./lvgl/lvgl.h" + LVGL_OK=1 +elif [ -f "${SCRIPT_DIR}/../lvgl/lvgl.h" ]; then + LVGL_WHERE="adjacent lvgl/" + LVGL_OK=1 +elif [ -f "/usr/include/lvgl/lvgl.h" ]; then + LVGL_WHERE="/usr/include/lvgl" + LVGL_OK=1 +elif [ -f "/usr/local/include/lvgl/lvgl.h" ]; then + LVGL_WHERE="/usr/local/include/lvgl" + LVGL_OK=1 +elif pkg-config --exists lvgl 2>/dev/null; then + LVGL_WHERE="pkg-config ($(pkg-config --modversion lvgl 2>/dev/null))" + LVGL_OK=1 +fi + +if [[ $LVGL_OK -eq 1 ]]; then + _ok "LVGL/MCU" "-DEL_TARGET_LVGL ${LVGL_WHERE}" + AVAILABLE=$((AVAILABLE + 1)) +else + _miss "LVGL/MCU" "-DEL_TARGET_LVGL (lvgl.h not found)" + echo " Install: git clone https://github.com/lvgl/lvgl" + echo " (place lvgl/ next to el-compiler/runtime/)" + MISSING=$((MISSING + 1)) +fi + +# ── Android / JNI ───────────────────────────────────────────────────────────── + +ANDROID_OK=0 +ANDROID_WHERE="" + +if [ -n "${ANDROID_NDK_HOME:-}" ] && [ -d "${ANDROID_NDK_HOME}" ]; then + NDK_VER="" + if [ -f "${ANDROID_NDK_HOME}/source.properties" ]; then + NDK_VER=$(grep "Pkg.Revision" "${ANDROID_NDK_HOME}/source.properties" \ + 2>/dev/null | cut -d= -f2 | tr -d ' ' || echo "") + fi + ANDROID_WHERE="NDK ${NDK_VER:-(version unknown)} at \$ANDROID_NDK_HOME" + ANDROID_OK=1 +elif command -v ndk-build &>/dev/null; then + ANDROID_WHERE="ndk-build in PATH" + ANDROID_OK=1 +elif [ -n "${ANDROID_HOME:-}" ] && [ -d "${ANDROID_HOME}/ndk" ]; then + ANDROID_WHERE="NDK via \$ANDROID_HOME/ndk" + ANDROID_OK=1 +fi + +if [[ $ANDROID_OK -eq 1 ]]; then + _ok "Android/JNI" "-DEL_TARGET_ANDROID ${ANDROID_WHERE}" + AVAILABLE=$((AVAILABLE + 1)) +else + _miss "Android/JNI" "-DEL_TARGET_ANDROID (ANDROID_NDK_HOME not set)" + echo " Install: https://developer.android.com/studio/releases/ndk" + echo " Then: export ANDROID_NDK_HOME=/path/to/ndk" + MISSING=$((MISSING + 1)) +fi + +# ── Windows / Win32 (cross or native) ───────────────────────────────────────── + +WIN32_OK=0 +WIN32_WHERE="" + +if [[ "$(uname)" == MINGW* ]] || [[ "$(uname)" == CYGWIN* ]] || \ + [[ "$(uname)" == MSYS* ]]; then + WIN32_WHERE="native Windows ($(uname))" + WIN32_OK=1 +elif command -v x86_64-w64-mingw32-gcc &>/dev/null; then + MINGW_VER=$(x86_64-w64-mingw32-gcc --version 2>/dev/null | head -1 || echo "") + WIN32_WHERE="mingw cross-compiler — ${MINGW_VER}" + WIN32_OK=1 +elif command -v i686-w64-mingw32-gcc &>/dev/null; then + WIN32_WHERE="mingw 32-bit cross-compiler" + WIN32_OK=1 +fi + +if [[ $WIN32_OK -eq 1 ]]; then + _ok "Windows/Win32" "-DEL_TARGET_WIN32 ${WIN32_WHERE}" + AVAILABLE=$((AVAILABLE + 1)) +else + _miss "Windows/Win32" "-DEL_TARGET_WIN32 (mingw cross-compiler not found)" + echo " Install: brew install mingw-w64" + echo " or: apt install gcc-mingw-w64" + MISSING=$((MISSING + 1)) +fi + +# ── Summary ─────────────────────────────────────────────────────────────────── + +echo "" +echo " ${AVAILABLE} platform(s) available, ${MISSING} unavailable on this machine." +echo "" + +if [[ -x "${SCRIPT_DIR}/new-platform" ]]; then + echo " Scaffold a new bridge: ${SCRIPT_DIR}/new-platform " +fi +echo " Bridge contract: ${SCRIPT_DIR}/PLATFORM_BRIDGE_SPEC.md" +echo "" diff --git a/lang/el-compiler/runtime/new-platform b/lang/el-compiler/runtime/new-platform new file mode 100755 index 0000000..86add28 --- /dev/null +++ b/lang/el-compiler/runtime/new-platform @@ -0,0 +1,711 @@ +#!/usr/bin/env bash +# new-platform — scaffold a new el-native platform bridge +# +# Usage: ./new-platform +# +# Example: +# ./new-platform myplatform +# +# Creates el_myplatform.c with all 33 required __* functions stubbed out, +# the ElWidget slot table, and the dlsym callback dispatcher. +# +# After running, follow the printed instructions to wire the bridge into +# el_native_target.h and el_seed.c. +# +# See PLATFORM_BRIDGE_SPEC.md for the full bridge contract. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# ── Argument validation ─────────────────────────────────────────────────────── + +if [[ $# -lt 1 ]]; then + echo "Usage: $0 " >&2 + echo "" >&2 + echo " lowercase identifier, e.g. myrtos, wayland, qt6" >&2 + echo "" >&2 + echo "This creates el_.c in the current directory." >&2 + exit 1 +fi + +PLATFORM_LOWER="${1,,}" # force lowercase +PLATFORM_UPPER="${PLATFORM_LOWER^^}" # force uppercase + +# Validate: letters, digits, underscores only +if [[ ! "${PLATFORM_LOWER}" =~ ^[a-z][a-z0-9_]*$ ]]; then + echo "Error: platform name must start with a letter and contain only a-z, 0-9, _" >&2 + exit 1 +fi + +OUTPUT_FILE="${SCRIPT_DIR}/el_${PLATFORM_LOWER}.c" + +if [[ -f "${OUTPUT_FILE}" ]]; then + echo "Error: ${OUTPUT_FILE} already exists." >&2 + echo " Remove it first if you want to regenerate it." >&2 + exit 1 +fi + +# ── Generate the bridge file ────────────────────────────────────────────────── + +cat > "${OUTPUT_FILE}" << BRIDGE_FILE +/* + * el_${PLATFORM_LOWER}.c — el-native platform bridge for ${PLATFORM_UPPER}. + * + * Generated by new-platform. Replace the TODO stubs with real implementations. + * See PLATFORM_BRIDGE_SPEC.md for the full contract. + * + * ── Slot system ────────────────────────────────────────────────────────────── + * Every widget (window, button, label, container, image) is stored in a static + * array of ElWidget structs. The el program holds an int64_t "handle" which is + * a direct index into that array. Rules: + * - Slot 0 is NEVER valid. Scans start at index 1. + * - Handle -1 means "invalid" / "create failed". + * - Maximum 4096 concurrent widgets. + * - el_widget_get() returns NULL for 0, negative, out-of-range, or FREE slots. + * + * ── Callback ABI ───────────────────────────────────────────────────────────── + * When a platform event fires (click, text change), call el_${PLATFORM_LOWER}_invoke_cb: + * + * el_${PLATFORM_LOWER}_invoke_cb(w->cb_click, slot_index, ""); + * + * The El callback signature: + * fn handler(handle: Int, data: String) -> Void + * compiles to: + * void handler(int64_t handle, int64_t data) + * where data is a const char* cast to int64_t (el String representation). + * + * ── Thread safety ──────────────────────────────────────────────────────────── + * ALL platform UI calls must run on the main/UI thread. If your platform + * delivers events on background threads (e.g., from a network callback that + * updates a label), marshal to the main thread before calling any widget op. + * + * ── Compile ────────────────────────────────────────────────────────────────── + * cc -DEL_TARGET_${PLATFORM_UPPER} \\ + * \$(pkg-config --cflags ) \\ + * -c el_${PLATFORM_LOWER}.c -o el_${PLATFORM_LOWER}.o + * + * ── Link ───────────────────────────────────────────────────────────────────── + * cc el_${PLATFORM_LOWER}.o el_seed.o el_runtime.o -o myapp \\ + * \$(pkg-config --libs ) -ldl -lpthread + */ + +#ifdef EL_TARGET_${PLATFORM_UPPER} + +/* ── TODO: add platform-specific includes here ────────────────────────────── + * Examples: + * #include // GTK4 + * #include // SDL2 + * #include "lvgl/lvgl.h" // LVGL + * #include // Win32 + */ + +#include +#include +#include +#include +#include /* dlsym — replace with GetProcAddress on Windows */ + +/* ── Widget table ─────────────────────────────────────────────────────────── */ + +#define EL_${PLATFORM_UPPER}_MAX_WIDGETS 4096 + +typedef enum { + EL_WIDGET_FREE = 0, + EL_WIDGET_WINDOW = 1, + EL_WIDGET_VSTACK = 2, + EL_WIDGET_HSTACK = 3, + EL_WIDGET_ZSTACK = 4, + EL_WIDGET_SCROLL = 5, + EL_WIDGET_LABEL = 6, + EL_WIDGET_BUTTON = 7, + EL_WIDGET_TEXTFIELD = 8, + EL_WIDGET_TEXTAREA = 9, + EL_WIDGET_IMAGE = 10, +} ElWidgetKind; + +typedef struct { + ElWidgetKind kind; + + /* TODO: add your platform's native widget reference here. + * Examples: + * GtkWidget* widget; // GTK4 + * SDL_Rect rect; // SDL2 (no object, just geometry) + * lv_obj_t* obj; // LVGL + * HWND hwnd; // Win32 + * void* native; // generic pointer + */ + void* native; /* platform widget reference — replace as needed */ + + /* Text content (cached for platforms that don't provide a get-text API) */ + char* text; + + /* Foreground / background color (RGBA, 0.0-1.0) */ + float fg_r, fg_g, fg_b, fg_a; + float bg_r, bg_g, bg_b, bg_a; + + /* Geometry */ + int width; /* 0 = not set */ + int height; /* 0 = not set */ + int flex; /* 0 = hug content, >0 = expand */ + + /* Padding (top, right, bottom, left) */ + int pad_top, pad_right, pad_bottom, pad_left; + + /* Corner radius */ + int corner_radius; + + /* State */ + int disabled; /* 0 = enabled, 1 = disabled */ + int hidden; /* 0 = visible, 1 = hidden */ + + /* Event callbacks — El function name resolved at event time via dlsym */ + char* cb_click; /* on_click / on_submit */ + char* cb_change; /* on_change */ +} ElWidget; + +static ElWidget _el_widgets[EL_${PLATFORM_UPPER}_MAX_WIDGETS]; + +/* ── Slot management ──────────────────────────────────────────────────────── */ + +static int64_t el_widget_alloc(ElWidgetKind kind, void* native) { + for (int i = 1; i < EL_${PLATFORM_UPPER}_MAX_WIDGETS; i++) { + if (_el_widgets[i].kind == EL_WIDGET_FREE) { + memset(&_el_widgets[i], 0, sizeof(ElWidget)); + _el_widgets[i].kind = kind; + _el_widgets[i].native = native; + return (int64_t)i; + } + } + fprintf(stderr, "el_${PLATFORM_LOWER}: widget table full (max %d)\n", + EL_${PLATFORM_UPPER}_MAX_WIDGETS); + return -1; +} + +static ElWidget* el_widget_get(int64_t handle) { + if (handle <= 0 || handle >= EL_${PLATFORM_UPPER}_MAX_WIDGETS) return NULL; + if (_el_widgets[handle].kind == EL_WIDGET_FREE) return NULL; + return &_el_widgets[handle]; +} + +static void el_widget_free(int64_t handle) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + /* TODO: release w->native (toolkit-specific) */ + free(w->text); + free(w->cb_click); + free(w->cb_change); + memset(w, 0, sizeof(ElWidget)); /* sets kind = EL_WIDGET_FREE (0) */ +} + +/* ── Callback dispatcher ─────────────────────────────────────────────────── */ +/* + * Invoke an El function by symbol name. The El function must have the + * compiled signature: void fn(int64_t handle, int64_t data) + * where data is a const char* cast to int64_t (el String representation). + * + * On platforms without dlsym (e.g., Windows), replace with: + * GetProcAddress(GetModuleHandle(NULL), fn_name) + * On embedded targets without dynamic linking, maintain a manual symbol table. + */ +typedef void (*ElCb2)(int64_t handle, int64_t data); + +static void el_${PLATFORM_LOWER}_invoke_cb(const char* fn_name, + int64_t handle, + const char* data) { + if (!fn_name || !*fn_name) return; + void* sym = dlsym(RTLD_DEFAULT, fn_name); + if (!sym) { + fprintf(stderr, "el_${PLATFORM_LOWER}: callback symbol not found: %s\n", fn_name); + return; + } + ElCb2 fn = (ElCb2)sym; + fn(handle, (int64_t)(uintptr_t)(data ? data : "")); +} + +/* ── Lifecycle ────────────────────────────────────────────────────────────── */ + +/* + * el_${PLATFORM_LOWER}_init — initialize the platform toolkit. + * Must be idempotent (safe to call more than once). + * Called once from __native_init before any widget creation. + */ +void el_${PLATFORM_LOWER}_init(void) { + static int done = 0; + if (done) return; + done = 1; + + /* TODO: initialize your platform toolkit here. + * Examples: + * gtk_init(NULL, NULL); // GTK4 + * SDL_Init(SDL_INIT_VIDEO); // SDL2 + * lv_init(); // LVGL + */ +} + +/* + * el_${PLATFORM_LOWER}_run_loop — start the platform event loop. + * On most platforms this NEVER returns. Exceptions: Android (no-op). + * Must be called from the main thread. + */ +void el_${PLATFORM_LOWER}_run_loop(void) { + /* TODO: start the platform event/render loop. + * Examples: + * gtk_main(); // GTK4 + * while (1) { SDL_PollEvent(...); render(); SDL_Delay(16); } // SDL2 + * while (1) { lv_task_handler(); usleep(5000); } // LVGL + */ +} + +/* ── Window ───────────────────────────────────────────────────────────────── */ + +int64_t el_${PLATFORM_LOWER}_window_create(const char* title, int w, int h, + int mw, int mh) { + /* TODO: create a top-level window. + * title may be NULL — treat as "". + * mw/mh are minimum dimensions (0 = no minimum). + * Return slot handle on success, -1 on failure. + */ + (void)title; (void)w; (void)h; (void)mw; (void)mh; + return -1; /* TODO: implement */ +} + +void el_${PLATFORM_LOWER}_window_show(int64_t handle) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + /* TODO: make the window visible. */ +} + +void el_${PLATFORM_LOWER}_window_set_title(int64_t handle, const char* title) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + /* TODO: update the window title. title may be NULL — treat as "". */ + (void)title; +} + +/* ── Layout containers ────────────────────────────────────────────────────── */ + +int64_t el_${PLATFORM_LOWER}_vstack_create(int spacing) { + /* TODO: create a vertical linear container with the given spacing (px). */ + (void)spacing; + return -1; /* TODO: implement */ +} + +int64_t el_${PLATFORM_LOWER}_hstack_create(int spacing) { + /* TODO: create a horizontal linear container with the given spacing (px). */ + (void)spacing; + return -1; /* TODO: implement */ +} + +int64_t el_${PLATFORM_LOWER}_zstack_create(void) { + /* TODO: create a z-axis overlay container (children overlap). */ + return -1; /* TODO: implement */ +} + +int64_t el_${PLATFORM_LOWER}_scroll_create(void) { + /* TODO: create a scrollable container (vertical scroll, first child = content). */ + return -1; /* TODO: implement */ +} + +/* ── Leaf widgets ─────────────────────────────────────────────────────────── */ + +int64_t el_${PLATFORM_LOWER}_label_create(const char* text) { + /* TODO: create a non-editable text label. text may be NULL — treat as "". */ + (void)text; + return -1; /* TODO: implement */ +} + +int64_t el_${PLATFORM_LOWER}_button_create(const char* label) { + /* TODO: create a clickable button with the given label text. + * Wire up the platform event handler so on_click callbacks fire later. */ + (void)label; + return -1; /* TODO: implement */ +} + +int64_t el_${PLATFORM_LOWER}_text_field_create(const char* placeholder) { + /* TODO: create a single-line text input. placeholder may be NULL. */ + (void)placeholder; + return -1; /* TODO: implement */ +} + +int64_t el_${PLATFORM_LOWER}_text_area_create(const char* placeholder) { + /* TODO: create a multi-line text input (scrollable). placeholder may be NULL. */ + (void)placeholder; + return -1; /* TODO: implement */ +} + +int64_t el_${PLATFORM_LOWER}_image_create(const char* path_or_name) { + /* TODO: create an image widget. + * Try path_or_name as a filesystem path first, then as a named resource. + * If neither resolves, create an empty image widget (do not crash). */ + (void)path_or_name; + return -1; /* TODO: implement */ +} + +/* ── Widget property setters ─────────────────────────────────────────────── */ + +void el_${PLATFORM_LOWER}_widget_set_text(int64_t handle, const char* text) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + /* TODO: update text on label, button, text field, text area, or window title. + * Dispatch on w->kind. text may be NULL — treat as "". + * Cache in w->text if the platform has no get-text API. */ + free(w->text); + w->text = strdup(text ? text : ""); +} + +const char* el_${PLATFORM_LOWER}_widget_get_text(int64_t handle) { + ElWidget* w = el_widget_get(handle); + if (!w) return ""; + /* TODO: return the current text of the widget. + * If the platform provides a get-text API, use it. + * Otherwise return w->text (populated by set_text). + * NEVER return NULL — return "" on failure. */ + return w->text ? w->text : ""; +} + +void el_${PLATFORM_LOWER}_widget_set_color(int64_t handle, + float r, float g, float b, float a) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + w->fg_r = r; w->fg_g = g; w->fg_b = b; w->fg_a = a; + /* TODO: apply foreground (text) color to the platform widget. */ +} + +void el_${PLATFORM_LOWER}_widget_set_bg_color(int64_t handle, + float r, float g, float b, float a) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + w->bg_r = r; w->bg_g = g; w->bg_b = b; w->bg_a = a; + /* TODO: apply background color to the platform widget. */ +} + +void el_${PLATFORM_LOWER}_widget_set_font(int64_t handle, + const char* family, int size, int bold) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + /* TODO: set font on text-bearing widgets (label, button, text field, text area). + * family may be "system" — use the platform default font in that case. + * Fall back to system font if family is not found. */ + (void)family; (void)size; (void)bold; +} + +void el_${PLATFORM_LOWER}_widget_set_padding(int64_t handle, + int top, int right, + int bottom, int left) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + w->pad_top = top; w->pad_right = right; + w->pad_bottom = bottom; w->pad_left = left; + /* TODO: apply padding/insets to the platform container or text widget. */ +} + +void el_${PLATFORM_LOWER}_widget_set_width(int64_t handle, int width) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + w->width = width; + /* TODO: apply a fixed-width constraint to the platform widget. */ +} + +void el_${PLATFORM_LOWER}_widget_set_height(int64_t handle, int height) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + w->height = height; + /* TODO: apply a fixed-height constraint to the platform widget. */ +} + +void el_${PLATFORM_LOWER}_widget_set_flex(int64_t handle, int flex) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + w->flex = flex; + /* TODO: set the flex/expand factor. + * flex > 0 → widget expands to fill available space. + * flex == 0 → widget hugs content size. + * Maps to: content hugging priority (AppKit), hexpand/vexpand (GTK4), + * layout_weight (Android), stretch factor (SDL2 manual layout). */ +} + +void el_${PLATFORM_LOWER}_widget_set_corner_radius(int64_t handle, int radius) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + w->corner_radius = radius; + /* TODO: apply rounded corners (requires GPU layer / backing surface on most platforms). */ +} + +void el_${PLATFORM_LOWER}_widget_set_disabled(int64_t handle, int disabled) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + w->disabled = disabled; + /* TODO: enable or disable the widget (buttons, text fields). No-op for containers/labels. */ +} + +void el_${PLATFORM_LOWER}_widget_set_hidden(int64_t handle, int hidden) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + w->hidden = hidden; + /* TODO: show or hide the widget. + * hidden=1 → invisible but still occupies layout space (visibility:hidden semantics). + * For windows: minimize or hide. */ +} + +/* ── Tree management ─────────────────────────────────────────────────────── */ + +void el_${PLATFORM_LOWER}_widget_add_child(int64_t parent, int64_t child) { + ElWidget* pw = el_widget_get(parent); + ElWidget* cw = el_widget_get(child); + if (!pw || !cw) return; + + /* TODO: attach child to parent. Dispatch on pw->kind: + * EL_WIDGET_WINDOW → add to root content view/container + * EL_WIDGET_VSTACK → add as vertical child + * EL_WIDGET_HSTACK → add as horizontal child + * EL_WIDGET_ZSTACK → add as overlapping subview + * EL_WIDGET_SCROLL → set as the scrollable content view (first child only) + * default → add as plain subview + * Do NOT add a window widget as a child. */ + (void)pw; (void)cw; +} + +void el_${PLATFORM_LOWER}_widget_remove_child(int64_t parent, int64_t child) { + ElWidget* pw = el_widget_get(parent); + ElWidget* cw = el_widget_get(child); + if (!pw || !cw) return; + /* TODO: detach child from parent. The child slot remains allocated (not destroyed). */ + (void)pw; (void)cw; +} + +void el_${PLATFORM_LOWER}_widget_destroy(int64_t handle) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + /* TODO: remove the widget from its parent/superview. + * For windows: close the window. + * Free any platform delegate/target objects stored in side tables. + * Then free the slot: */ + el_widget_free(handle); +} + +/* ── Event registration ───────────────────────────────────────────────────── */ + +void el_${PLATFORM_LOWER}_widget_on_click(int64_t handle, const char* fn_name) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + free(w->cb_click); + w->cb_click = (fn_name && *fn_name) ? strdup(fn_name) : NULL; +} + +void el_${PLATFORM_LOWER}_widget_on_change(int64_t handle, const char* fn_name) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + free(w->cb_change); + w->cb_change = (fn_name && *fn_name) ? strdup(fn_name) : NULL; +} + +void el_${PLATFORM_LOWER}_widget_on_submit(int64_t handle, const char* fn_name) { + /* Submit (Enter key in text field) reuses the cb_click slot, matching AppKit convention. */ + el_${PLATFORM_LOWER}_widget_on_click(handle, fn_name); +} + +/* ── Example event handler (adapt to your platform's callback mechanism) ─── */ +/* + * When a button is clicked in your platform event loop, call: + * + * ElWidget* w = el_widget_get(slot_index); + * if (w && w->cb_click) { + * el_${PLATFORM_LOWER}_invoke_cb(w->cb_click, slot_index, ""); + * } + * + * When a text field changes: + * + * ElWidget* w = el_widget_get(slot_index); + * if (w && w->cb_change) { + * el_${PLATFORM_LOWER}_invoke_cb(w->cb_change, slot_index, current_text); + * } + */ + +#endif /* EL_TARGET_${PLATFORM_UPPER} */ +BRIDGE_FILE + +chmod 644 "${OUTPUT_FILE}" + +# ── Print next-steps instructions ──────────────────────────────────────────── + +UPPER="${PLATFORM_UPPER}" +LOWER="${PLATFORM_LOWER}" + +cat << INSTRUCTIONS + +Created: el_${LOWER}.c + +Next steps: + ──────────────────────────────────────────────────────────────────────────── + 1. Add to el_native_target.h (inside a new #ifdef EL_TARGET_${UPPER} block): + + #ifdef EL_TARGET_${UPPER} + + void __native_init(void); + void __native_run_loop(void); + + el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); + void __window_show(el_val_t handle); + void __window_set_title(el_val_t handle, el_val_t title); + + el_val_t __vstack_create(el_val_t spacing); + el_val_t __hstack_create(el_val_t spacing); + el_val_t __zstack_create(void); + el_val_t __scroll_create(void); + + el_val_t __label_create(el_val_t text); + el_val_t __button_create(el_val_t label); + el_val_t __text_field_create(el_val_t placeholder); + el_val_t __text_area_create(el_val_t placeholder); + el_val_t __image_create(el_val_t path_or_name); + + void __widget_set_text(el_val_t handle, el_val_t text); + el_val_t __widget_get_text(el_val_t handle); + void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); + void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); + void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); + void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); + void __widget_set_width(el_val_t handle, el_val_t width); + void __widget_set_height(el_val_t handle, el_val_t height); + void __widget_set_flex(el_val_t handle, el_val_t flex); + void __widget_set_corner_radius(el_val_t handle, el_val_t radius); + void __widget_set_disabled(el_val_t handle, el_val_t disabled); + void __widget_set_hidden(el_val_t handle, el_val_t hidden); + + void __widget_add_child(el_val_t parent, el_val_t child); + void __widget_remove_child(el_val_t parent, el_val_t child); + void __widget_destroy(el_val_t handle); + + void __widget_on_click(el_val_t handle, el_val_t fn_name); + void __widget_on_change(el_val_t handle, el_val_t fn_name); + void __widget_on_submit(el_val_t handle, el_val_t fn_name); + + el_val_t __manifest_read(el_val_t path); + + #endif /* EL_TARGET_${UPPER} */ + + ──────────────────────────────────────────────────────────────────────────── + 2. Add to el_seed.c (copy the EL_TARGET_MACOS block as a template and + substitute el_appkit_ → el_${LOWER}_): + + #ifdef EL_TARGET_${UPPER} + + /* Forward declarations — implemented in el_${LOWER}.c */ + extern void el_${LOWER}_init(void); + extern void el_${LOWER}_run_loop(void); + extern int64_t el_${LOWER}_window_create(const char* title, int w, int h, int mw, int mh); + extern void el_${LOWER}_window_show(int64_t handle); + extern void el_${LOWER}_window_set_title(int64_t handle, const char* title); + extern int64_t el_${LOWER}_vstack_create(int spacing); + extern int64_t el_${LOWER}_hstack_create(int spacing); + extern int64_t el_${LOWER}_zstack_create(void); + extern int64_t el_${LOWER}_scroll_create(void); + extern int64_t el_${LOWER}_label_create(const char* text); + extern int64_t el_${LOWER}_button_create(const char* label); + extern int64_t el_${LOWER}_text_field_create(const char* placeholder); + extern int64_t el_${LOWER}_text_area_create(const char* placeholder); + extern int64_t el_${LOWER}_image_create(const char* path_or_name); + extern void el_${LOWER}_widget_set_text(int64_t handle, const char* text); + extern const char* el_${LOWER}_widget_get_text(int64_t handle); + extern void el_${LOWER}_widget_set_color(int64_t h, float r, float g, float b, float a); + extern void el_${LOWER}_widget_set_bg_color(int64_t h, float r, float g, float b, float a); + extern void el_${LOWER}_widget_set_font(int64_t h, const char* family, int size, int bold); + extern void el_${LOWER}_widget_set_padding(int64_t h, int top, int right, int bottom, int left); + extern void el_${LOWER}_widget_set_width(int64_t h, int width); + extern void el_${LOWER}_widget_set_height(int64_t h, int height); + extern void el_${LOWER}_widget_set_flex(int64_t h, int flex); + extern void el_${LOWER}_widget_set_corner_radius(int64_t h, int radius); + extern void el_${LOWER}_widget_set_disabled(int64_t h, int disabled); + extern void el_${LOWER}_widget_set_hidden(int64_t h, int hidden); + extern void el_${LOWER}_widget_add_child(int64_t parent, int64_t child); + extern void el_${LOWER}_widget_remove_child(int64_t parent, int64_t child); + extern void el_${LOWER}_widget_destroy(int64_t handle); + extern void el_${LOWER}_widget_on_click(int64_t h, const char* fn_name); + extern void el_${LOWER}_widget_on_change(int64_t h, const char* fn_name); + extern void el_${LOWER}_widget_on_submit(int64_t h, const char* fn_name); + + void __native_init(void) { el_${LOWER}_init(); } + void __native_run_loop(void) { el_${LOWER}_run_loop(); } + + el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_${LOWER}_window_create( + EL_CSTR(title), + (int)(int64_t)width, (int)(int64_t)height, + (int)(int64_t)min_width, (int)(int64_t)min_height); + } + void __window_show(el_val_t h) { el_${LOWER}_window_show((int64_t)h); } + void __window_set_title(el_val_t h, el_val_t t) { el_${LOWER}_window_set_title((int64_t)h, EL_CSTR(t)); } + + el_val_t __vstack_create(el_val_t s) { return (el_val_t)el_${LOWER}_vstack_create((int)(int64_t)s); } + el_val_t __hstack_create(el_val_t s) { return (el_val_t)el_${LOWER}_hstack_create((int)(int64_t)s); } + el_val_t __zstack_create(void) { return (el_val_t)el_${LOWER}_zstack_create(); } + el_val_t __scroll_create(void) { return (el_val_t)el_${LOWER}_scroll_create(); } + + el_val_t __label_create(el_val_t t) { return (el_val_t)el_${LOWER}_label_create(EL_CSTR(t)); } + el_val_t __button_create(el_val_t l) { return (el_val_t)el_${LOWER}_button_create(EL_CSTR(l)); } + el_val_t __text_field_create(el_val_t p) { return (el_val_t)el_${LOWER}_text_field_create(EL_CSTR(p)); } + el_val_t __text_area_create(el_val_t p) { return (el_val_t)el_${LOWER}_text_area_create(EL_CSTR(p)); } + el_val_t __image_create(el_val_t p) { return (el_val_t)el_${LOWER}_image_create(EL_CSTR(p)); } + + void __widget_set_text(el_val_t h, el_val_t t) { el_${LOWER}_widget_set_text((int64_t)h, EL_CSTR(t)); } + el_val_t __widget_get_text(el_val_t h) { + const char* s = el_${LOWER}_widget_get_text((int64_t)h); + return EL_STR(s ? s : ""); + } + void __widget_set_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_${LOWER}_widget_set_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); + } + void __widget_set_bg_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_${LOWER}_widget_set_bg_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); + } + void __widget_set_font(el_val_t h, el_val_t family, el_val_t size, el_val_t bold) { + el_${LOWER}_widget_set_font((int64_t)h, EL_CSTR(family), + (int)(int64_t)size, (int)(int64_t)bold); + } + void __widget_set_padding(el_val_t h, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_${LOWER}_widget_set_padding((int64_t)h, + (int)(int64_t)top, (int)(int64_t)right, + (int)(int64_t)bottom, (int)(int64_t)left); + } + void __widget_set_width(el_val_t h, el_val_t w) { el_${LOWER}_widget_set_width((int64_t)h, (int)(int64_t)w); } + void __widget_set_height(el_val_t h, el_val_t ht) { el_${LOWER}_widget_set_height((int64_t)h, (int)(int64_t)ht); } + void __widget_set_flex(el_val_t h, el_val_t f) { el_${LOWER}_widget_set_flex((int64_t)h, (int)(int64_t)f); } + void __widget_set_corner_radius(el_val_t h, el_val_t r) { el_${LOWER}_widget_set_corner_radius((int64_t)h, (int)(int64_t)r); } + void __widget_set_disabled(el_val_t h, el_val_t d) { el_${LOWER}_widget_set_disabled((int64_t)h, (int)(int64_t)d); } + void __widget_set_hidden(el_val_t h, el_val_t hid) { el_${LOWER}_widget_set_hidden((int64_t)h, (int)(int64_t)hid); } + void __widget_add_child(el_val_t p, el_val_t c) { el_${LOWER}_widget_add_child((int64_t)p, (int64_t)c); } + void __widget_remove_child(el_val_t p, el_val_t c) { el_${LOWER}_widget_remove_child((int64_t)p, (int64_t)c); } + void __widget_destroy(el_val_t h) { el_${LOWER}_widget_destroy((int64_t)h); } + void __widget_on_click(el_val_t h, el_val_t fn) { el_${LOWER}_widget_on_click((int64_t)h, EL_CSTR(fn)); } + void __widget_on_change(el_val_t h, el_val_t fn) { el_${LOWER}_widget_on_change((int64_t)h, EL_CSTR(fn)); } + void __widget_on_submit(el_val_t h, el_val_t fn) { el_${LOWER}_widget_on_submit((int64_t)h, EL_CSTR(fn)); } + + #endif /* EL_TARGET_${UPPER} */ + + ──────────────────────────────────────────────────────────────────────────── + 3. Implement each TODO in el_${LOWER}.c. + + 4. Compile: + cc -DEL_TARGET_${UPPER} -Wall \\ + \$(pkg-config --cflags 2>/dev/null) \\ + -c el_${LOWER}.c -o el_${LOWER}.o + + 5. Link: + cc el_${LOWER}.o el_seed.o el_runtime.o -o myapp \\ + \$(pkg-config --libs 2>/dev/null) \\ + -ldl -lpthread + + See PLATFORM_BRIDGE_SPEC.md for the full bridge contract and gotchas. +INSTRUCTIONS From 58753a88d734b0e099a0b3c0f90370106b2c1a05 Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Mon, 29 Jun 2026 12:40:37 -0500 Subject: [PATCH 13/13] feat(ui): native vessel, HTML vessel update, native hello examples, profile card, UI tools el-native vessel: El-level wrappers around __widget_* C builtins, exposing vstack, label, button, text_field, etc. as clean El functions for application code. el-html/main.elh: updated extern declarations for the HTML vessel's codegen API. native-hello: cross-platform desktop example (AppKit/GTK4/Win32/SDL2) with build scripts, Dockerfiles for Linux/Pi, and Win32 cross-compile support. native-hello-android: Gradle project with ElBridge integration and build script. native-hello-ios: Xcode project for the iOS UIKit target. profile-card: manifest.el for a styling/layout/i18n example app that exercises el-style, el-layout, el-i18n, el-config, and el-secrets vessels. ui/tools/native-codegen: Python codegen pass (el_ui_native_codegen.py) that lowers el-ui component DSL to el-native vessel calls, plus build script and test fixtures. --- ui/examples/native-hello-android/.gitignore | 6 + .../native-hello-android/app/build.gradle | 55 + .../app/proguard-rules.pro | 4 + .../app/src/main/AndroidManifest.xml | 23 + .../src/main/java/com/neuron/el/ElApp.java | 18 + .../src/main/java/com/neuron/el/ElBridge.java | 711 + .../main/java/com/neuron/el/MainActivity.java | 38 + .../app/src/main/jni/CMakeLists.txt | 57 + .../app/src/main/jni/el_android.c | 964 ++ .../app/src/main/jni/el_native_target.h | 573 + .../app/src/main/jni/el_native_vessel.c | 459 + .../app/src/main/jni/el_runtime.c | 11733 ++++++++++++++++ .../app/src/main/jni/el_runtime.h | 883 ++ .../app/src/main/jni/el_seed.c | 1942 +++ .../app/src/main/jni/native_hello.c | 123 + .../app/src/main/res/layout/activity_main.xml | 13 + .../app/src/main/res/values/strings.xml | 4 + ui/examples/native-hello-android/build.gradle | 4 + ui/examples/native-hello-android/build.sh | 83 + .../native-hello-android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 63375 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + ui/examples/native-hello-android/gradlew | 122 + .../local.properties.template | 7 + .../native-hello-android/settings.gradle | 17 + ui/examples/native-hello-ios/.gitignore | 4 + .../NativeHello.xcodeproj/project.pbxproj | 377 + .../xcschemes/NativeHello.xcscheme | 78 + .../native-hello-ios/NativeHello/Info.plist | 38 + .../NativeHello/el_native_target.h | 573 + .../NativeHello/el_native_vessel.c | 459 + .../native-hello-ios/NativeHello/el_runtime.c | 11733 ++++++++++++++++ .../native-hello-ios/NativeHello/el_runtime.h | 883 ++ .../native-hello-ios/NativeHello/el_seed.c | 1942 +++ .../native-hello-ios/NativeHello/el_uikit.m | 1118 ++ .../native-hello-ios/NativeHello/main.m | 48 + .../NativeHello/native_hello.c | 123 + ui/examples/native-hello-ios/build.sh | 136 + ui/examples/native-hello/-o | 0 .../native-hello/Dockerfile.linux-gtk4 | 88 + ui/examples/native-hello/Dockerfile.pi | 99 + .../build-docker/el_native_vessel.c | 459 + .../build-docker/el_native_vessel.h | 69 + .../native-hello/build-docker/native_hello.c | 123 + .../build-docker/runtime/el_gtk4.c | 1027 ++ .../build-docker/runtime/el_native_target.h | 573 + .../build-docker/runtime/el_runtime.c | 11733 ++++++++++++++++ .../build-docker/runtime/el_runtime.h | 883 ++ .../build-docker/runtime/el_seed.c | 1942 +++ .../build-docker/runtime/el_seed.h | 324 + ui/examples/native-hello/build-gtk4.sh | 182 + ui/examples/native-hello/build-gtk4/.rt_T.txt | 397 + .../native-hello/build-gtk4/.rt_keep.txt | 340 + .../native-hello/build-gtk4/.seed_T.txt | 137 + .../native-hello/build-gtk4/.vessel_keep.txt | 55 + ui/examples/native-hello/build-gtk4/el_gtk4.o | Bin 0 -> 33464 bytes .../build-gtk4/el_native_vessel.c | 459 + .../build-gtk4/el_native_vessel.h | 69 + .../build-gtk4/el_native_vessel.o | Bin 0 -> 14692 bytes .../native-hello/build-gtk4/el_runtime.o | Bin 0 -> 244380 bytes ui/examples/native-hello/build-gtk4/el_seed.o | Bin 0 -> 50056 bytes .../native-hello/build-gtk4/native-hello-gtk4 | Bin 0 -> 303136 bytes .../native-hello/build-gtk4/native_hello.c | 123 + .../native-hello/build-gtk4/native_hello.o | Bin 0 -> 6192 bytes ui/examples/native-hello/build-sdl2.sh | 169 + ui/examples/native-hello/build-win32.sh | 135 + .../build-win32/el_native_vessel.c | 459 + .../build-win32/el_native_vessel.h | 69 + .../build-win32/el_native_vessel.o | Bin 0 -> 14736 bytes .../build-win32/el_runtime_win32.o | Bin 0 -> 43103 bytes .../native-hello/build-win32/el_win32.o | Bin 0 -> 31904 bytes .../native-hello/build-win32/native-hello.exe | Bin 0 -> 246847 bytes .../native-hello/build-win32/native_hello.c | 123 + .../native-hello/build-win32/native_hello.o | Bin 0 -> 5580 bytes ui/examples/native-hello/build.sh | 198 + ui/examples/native-hello/build/.rt_T.txt | 397 + ui/examples/native-hello/build/.rt_keep.txt | 340 + ui/examples/native-hello/build/.seed_T.txt | 137 + .../native-hello/build/.vessel_keep.txt | 55 + ui/examples/native-hello/build/el_appkit.o | Bin 0 -> 58520 bytes .../native-hello/build/el_native_vessel.c | 459 + .../native-hello/build/el_native_vessel.h | 69 + .../native-hello/build/el_native_vessel.o | Bin 0 -> 14692 bytes ui/examples/native-hello/build/el_runtime.o | Bin 0 -> 244380 bytes ui/examples/native-hello/build/el_sdl2.o | Bin 0 -> 31624 bytes ui/examples/native-hello/build/el_seed.o | Bin 0 -> 50056 bytes ui/examples/native-hello/build/native-hello | Bin 0 -> 324000 bytes .../build/native-hello-linux-arm64 | Bin 0 -> 300664 bytes .../build/native-hello-linux-x86_64 | Bin 0 -> 299048 bytes .../native-hello/build/native-hello-pi-arm64 | Bin 0 -> 300664 bytes .../native-hello/build/native-hello-sdl2 | Bin 0 -> 297632 bytes ui/examples/native-hello/build/native_hello.c | 123 + ui/examples/native-hello/build/native_hello.o | Bin 0 -> 6192 bytes .../native-hello/docker-build-linux.sh | 128 + ui/examples/native-hello/manifest.el | 19 + ui/examples/native-hello/src/App.el | 141 + ui/examples/native-hello/src/main.el | 43 + ui/examples/profile-card/manifest.el | 25 + ui/tools/dist/el-ui-native-codegen | 4 + ui/tools/native-codegen/build.sh | 62 + .../native-codegen/el_ui_native_codegen.py | 822 ++ ui/tools/native-codegen/test_app.el | 28 + ui/tools/native-codegen/test_native_hello.el | 52 + ui/vessels/el-html/src/main.elh | 42 + ui/vessels/el-native/src/main.el | 386 + ui/vessels/el-native/src/main.elh | 57 + 106 files changed, 58984 insertions(+) create mode 100644 ui/examples/native-hello-android/.gitignore create mode 100644 ui/examples/native-hello-android/app/build.gradle create mode 100644 ui/examples/native-hello-android/app/proguard-rules.pro create mode 100644 ui/examples/native-hello-android/app/src/main/AndroidManifest.xml create mode 100644 ui/examples/native-hello-android/app/src/main/java/com/neuron/el/ElApp.java create mode 100644 ui/examples/native-hello-android/app/src/main/java/com/neuron/el/ElBridge.java create mode 100644 ui/examples/native-hello-android/app/src/main/java/com/neuron/el/MainActivity.java create mode 100644 ui/examples/native-hello-android/app/src/main/jni/CMakeLists.txt create mode 100644 ui/examples/native-hello-android/app/src/main/jni/el_android.c create mode 100644 ui/examples/native-hello-android/app/src/main/jni/el_native_target.h create mode 100644 ui/examples/native-hello-android/app/src/main/jni/el_native_vessel.c create mode 100644 ui/examples/native-hello-android/app/src/main/jni/el_runtime.c create mode 100644 ui/examples/native-hello-android/app/src/main/jni/el_runtime.h create mode 100644 ui/examples/native-hello-android/app/src/main/jni/el_seed.c create mode 100644 ui/examples/native-hello-android/app/src/main/jni/native_hello.c create mode 100644 ui/examples/native-hello-android/app/src/main/res/layout/activity_main.xml create mode 100644 ui/examples/native-hello-android/app/src/main/res/values/strings.xml create mode 100644 ui/examples/native-hello-android/build.gradle create mode 100755 ui/examples/native-hello-android/build.sh create mode 100644 ui/examples/native-hello-android/gradle.properties create mode 100644 ui/examples/native-hello-android/gradle/wrapper/gradle-wrapper.jar create mode 100644 ui/examples/native-hello-android/gradle/wrapper/gradle-wrapper.properties create mode 100755 ui/examples/native-hello-android/gradlew create mode 100644 ui/examples/native-hello-android/local.properties.template create mode 100644 ui/examples/native-hello-android/settings.gradle create mode 100644 ui/examples/native-hello-ios/.gitignore create mode 100644 ui/examples/native-hello-ios/NativeHello.xcodeproj/project.pbxproj create mode 100644 ui/examples/native-hello-ios/NativeHello.xcodeproj/xcshareddata/xcschemes/NativeHello.xcscheme create mode 100644 ui/examples/native-hello-ios/NativeHello/Info.plist create mode 100644 ui/examples/native-hello-ios/NativeHello/el_native_target.h create mode 100644 ui/examples/native-hello-ios/NativeHello/el_native_vessel.c create mode 100644 ui/examples/native-hello-ios/NativeHello/el_runtime.c create mode 100644 ui/examples/native-hello-ios/NativeHello/el_runtime.h create mode 100644 ui/examples/native-hello-ios/NativeHello/el_seed.c create mode 100644 ui/examples/native-hello-ios/NativeHello/el_uikit.m create mode 100644 ui/examples/native-hello-ios/NativeHello/main.m create mode 100644 ui/examples/native-hello-ios/NativeHello/native_hello.c create mode 100755 ui/examples/native-hello-ios/build.sh create mode 100644 ui/examples/native-hello/-o create mode 100644 ui/examples/native-hello/Dockerfile.linux-gtk4 create mode 100644 ui/examples/native-hello/Dockerfile.pi create mode 100644 ui/examples/native-hello/build-docker/el_native_vessel.c create mode 100644 ui/examples/native-hello/build-docker/el_native_vessel.h create mode 100644 ui/examples/native-hello/build-docker/native_hello.c create mode 100644 ui/examples/native-hello/build-docker/runtime/el_gtk4.c create mode 100644 ui/examples/native-hello/build-docker/runtime/el_native_target.h create mode 100644 ui/examples/native-hello/build-docker/runtime/el_runtime.c create mode 100644 ui/examples/native-hello/build-docker/runtime/el_runtime.h create mode 100644 ui/examples/native-hello/build-docker/runtime/el_seed.c create mode 100644 ui/examples/native-hello/build-docker/runtime/el_seed.h create mode 100755 ui/examples/native-hello/build-gtk4.sh create mode 100644 ui/examples/native-hello/build-gtk4/.rt_T.txt create mode 100644 ui/examples/native-hello/build-gtk4/.rt_keep.txt create mode 100644 ui/examples/native-hello/build-gtk4/.seed_T.txt create mode 100644 ui/examples/native-hello/build-gtk4/.vessel_keep.txt create mode 100644 ui/examples/native-hello/build-gtk4/el_gtk4.o create mode 100644 ui/examples/native-hello/build-gtk4/el_native_vessel.c create mode 100644 ui/examples/native-hello/build-gtk4/el_native_vessel.h create mode 100644 ui/examples/native-hello/build-gtk4/el_native_vessel.o create mode 100644 ui/examples/native-hello/build-gtk4/el_runtime.o create mode 100644 ui/examples/native-hello/build-gtk4/el_seed.o create mode 100755 ui/examples/native-hello/build-gtk4/native-hello-gtk4 create mode 100644 ui/examples/native-hello/build-gtk4/native_hello.c create mode 100644 ui/examples/native-hello/build-gtk4/native_hello.o create mode 100755 ui/examples/native-hello/build-sdl2.sh create mode 100755 ui/examples/native-hello/build-win32.sh create mode 100644 ui/examples/native-hello/build-win32/el_native_vessel.c create mode 100644 ui/examples/native-hello/build-win32/el_native_vessel.h create mode 100644 ui/examples/native-hello/build-win32/el_native_vessel.o create mode 100644 ui/examples/native-hello/build-win32/el_runtime_win32.o create mode 100644 ui/examples/native-hello/build-win32/el_win32.o create mode 100755 ui/examples/native-hello/build-win32/native-hello.exe create mode 100644 ui/examples/native-hello/build-win32/native_hello.c create mode 100644 ui/examples/native-hello/build-win32/native_hello.o create mode 100755 ui/examples/native-hello/build.sh create mode 100644 ui/examples/native-hello/build/.rt_T.txt create mode 100644 ui/examples/native-hello/build/.rt_keep.txt create mode 100644 ui/examples/native-hello/build/.seed_T.txt create mode 100644 ui/examples/native-hello/build/.vessel_keep.txt create mode 100644 ui/examples/native-hello/build/el_appkit.o create mode 100644 ui/examples/native-hello/build/el_native_vessel.c create mode 100644 ui/examples/native-hello/build/el_native_vessel.h create mode 100644 ui/examples/native-hello/build/el_native_vessel.o create mode 100644 ui/examples/native-hello/build/el_runtime.o create mode 100644 ui/examples/native-hello/build/el_sdl2.o create mode 100644 ui/examples/native-hello/build/el_seed.o create mode 100755 ui/examples/native-hello/build/native-hello create mode 100755 ui/examples/native-hello/build/native-hello-linux-arm64 create mode 100755 ui/examples/native-hello/build/native-hello-linux-x86_64 create mode 100755 ui/examples/native-hello/build/native-hello-pi-arm64 create mode 100755 ui/examples/native-hello/build/native-hello-sdl2 create mode 100644 ui/examples/native-hello/build/native_hello.c create mode 100644 ui/examples/native-hello/build/native_hello.o create mode 100755 ui/examples/native-hello/docker-build-linux.sh create mode 100644 ui/examples/native-hello/manifest.el create mode 100644 ui/examples/native-hello/src/App.el create mode 100644 ui/examples/native-hello/src/main.el create mode 100644 ui/examples/profile-card/manifest.el create mode 100755 ui/tools/dist/el-ui-native-codegen create mode 100755 ui/tools/native-codegen/build.sh create mode 100644 ui/tools/native-codegen/el_ui_native_codegen.py create mode 100644 ui/tools/native-codegen/test_app.el create mode 100644 ui/tools/native-codegen/test_native_hello.el create mode 100644 ui/vessels/el-html/src/main.elh create mode 100644 ui/vessels/el-native/src/main.el create mode 100644 ui/vessels/el-native/src/main.elh diff --git a/ui/examples/native-hello-android/.gitignore b/ui/examples/native-hello-android/.gitignore new file mode 100644 index 0000000..0ca7c87 --- /dev/null +++ b/ui/examples/native-hello-android/.gitignore @@ -0,0 +1,6 @@ +local.properties +.gradle/ +build/ +app/build/ +*.iml +.idea/ diff --git a/ui/examples/native-hello-android/app/build.gradle b/ui/examples/native-hello-android/app/build.gradle new file mode 100644 index 0000000..dd1dd28 --- /dev/null +++ b/ui/examples/native-hello-android/app/build.gradle @@ -0,0 +1,55 @@ +plugins { + id 'com.android.application' +} + +android { + namespace 'com.neuron.el' + compileSdk 34 + + defaultConfig { + applicationId "com.neuron.el" + minSdk 21 + targetSdk 34 + versionCode 1 + versionName "1.0" + + externalNativeBuild { + cmake { + cppFlags "" + arguments "-DANDROID_STL=c++_shared" + } + } + + ndk { + // Build for the two most relevant ABIs. Add x86/x86_64 for emulator. + abiFilters "arm64-v8a", "armeabi-v7a", "x86_64" + } + } + + externalNativeBuild { + cmake { + path "src/main/jni/CMakeLists.txt" + version "3.22.1" + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + debug { + jniDebuggable true + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + // No third-party dependencies — el-native uses only android.* framework classes. + implementation 'androidx.appcompat:appcompat:1.6.1' +} diff --git a/ui/examples/native-hello-android/app/proguard-rules.pro b/ui/examples/native-hello-android/app/proguard-rules.pro new file mode 100644 index 0000000..c0c619f --- /dev/null +++ b/ui/examples/native-hello-android/app/proguard-rules.pro @@ -0,0 +1,4 @@ +# Add project specific ProGuard rules here. +# Keep ElBridge and MainActivity so JNI symbol names stay intact. +-keep class com.neuron.el.ElBridge { *; } +-keep class com.neuron.el.MainActivity { *; } diff --git a/ui/examples/native-hello-android/app/src/main/AndroidManifest.xml b/ui/examples/native-hello-android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..780d219 --- /dev/null +++ b/ui/examples/native-hello-android/app/src/main/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + diff --git a/ui/examples/native-hello-android/app/src/main/java/com/neuron/el/ElApp.java b/ui/examples/native-hello-android/app/src/main/java/com/neuron/el/ElApp.java new file mode 100644 index 0000000..25f72d6 --- /dev/null +++ b/ui/examples/native-hello-android/app/src/main/java/com/neuron/el/ElApp.java @@ -0,0 +1,18 @@ +package com.neuron.el; + +import android.app.Application; + +/** + * ElApp — Application subclass for native-hello-android. + * + * Currently minimal: exists as an anchor for future app-level initialisation + * (crash reporting, global state, etc.). Listed in AndroidManifest.xml as + * android:name=".ElApp". + */ +public class ElApp extends Application { + + @Override + public void onCreate() { + super.onCreate(); + } +} diff --git a/ui/examples/native-hello-android/app/src/main/java/com/neuron/el/ElBridge.java b/ui/examples/native-hello-android/app/src/main/java/com/neuron/el/ElBridge.java new file mode 100644 index 0000000..52cb402 --- /dev/null +++ b/ui/examples/native-hello-android/app/src/main/java/com/neuron/el/ElBridge.java @@ -0,0 +1,711 @@ +/* + * ElBridge.java — Android Java companion to el_android.c. + * + * All public methods are static. The C JNI layer calls these to create views, + * set properties, and manage the widget tree. Views are identified by integer + * slot indices matching the C-side handle values. + * + * Threading: every method that touches a View dispatches to the UI thread + * using Activity.runOnUiThread(Runnable) and blocks with a CountDownLatch + * until the UI thread completes the operation. This mirrors the AppKit + * dispatch_sync(main_queue, ^{}) pattern in el_appkit.m. + * + * Callbacks: Java sets listeners on views that call back into C via: + * nativeOnClick(int slot) + * nativeOnChange(int slot, String text) + * nativeOnSubmit(int slot, String text) + * These are declared native and implemented in el_android.c. + * + * Usage (in your Activity.onCreate): + * System.loadLibrary("elruntime"); + * ElBridge.init(this); + * + * The native library calls __native_init() which calls nativeRegisterActivity + * via the C side; alternatively call ElBridge.init(this) directly from Java. + * + * Compile requirements: + * Android minSdkVersion 21 (Lollipop) or higher. + * No third-party dependencies — uses only android.* framework classes. + * For image loading from arbitrary file paths, BitmapFactory is used. + * To replace with Glide/Picasso, edit createImageView only. + */ + +package com.neuron.el; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.Typeface; +import android.graphics.drawable.GradientDrawable; +import android.os.Handler; +import android.os.Looper; +import android.text.Editable; +import android.text.InputType; +import android.text.TextWatcher; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; + +import java.util.concurrent.CountDownLatch; + +public class ElBridge { + + /* ── Native callbacks (implemented in el_android.c) ─────────────────── */ + + public static native void nativeOnClick(int slot); + public static native void nativeOnChange(int slot, String text); + public static native void nativeOnSubmit(int slot, String text); + public static native void nativeRegisterActivity(Activity activity); + + /* ── State ───────────────────────────────────────────────────────────── */ + + private static final int MAX_SLOTS = 4096; + + private static Activity sActivity; + private static Handler sUiHandler; + private static View[] sViews = new View[MAX_SLOTS]; + private static int sNextSlot = 1; /* slot 0 reserved / null */ + + /* ── Init ────────────────────────────────────────────────────────────── */ + + /** + * Must be called from the Activity before any widget operations. + * Typically called from Activity.onCreate after System.loadLibrary. + */ + public static void init(Activity activity) { + sActivity = activity; + sUiHandler = new Handler(Looper.getMainLooper()); + nativeRegisterActivity(activity); + } + + /* ── Slot management ─────────────────────────────────────────────────── */ + + private static int allocSlot(View v) { + /* Find a free slot starting from sNextSlot, wrap around. */ + for (int i = 0; i < MAX_SLOTS - 1; i++) { + int idx = ((sNextSlot - 1 + i) % (MAX_SLOTS - 1)) + 1; + if (sViews[idx] == null) { + sViews[idx] = v; + sNextSlot = (idx % (MAX_SLOTS - 1)) + 1; + return idx; + } + } + android.util.Log.e("ElBridge", "allocSlot: slot table full"); + return -1; + } + + private static View getView(int slot) { + if (slot <= 0 || slot >= MAX_SLOTS) return null; + return sViews[slot]; + } + + /* ── UI-thread dispatch helper ───────────────────────────────────────── */ + + /* + * Dispatch r on the UI thread and block until it completes. + * Safe to call from the UI thread itself (runs inline without posting). + */ + private static void runSync(final Runnable r) { + if (Looper.myLooper() == Looper.getMainLooper()) { + r.run(); + } else { + final CountDownLatch latch = new CountDownLatch(1); + sUiHandler.post(new Runnable() { + @Override public void run() { + try { r.run(); } finally { latch.countDown(); } + } + }); + try { latch.await(); } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + + /* ── Integer slot returning runSync helper ───────────────────────────── */ + + private interface IntSupplier { int get(); } + + private static int runSyncInt(final IntSupplier s) { + final int[] result = { -1 }; + runSync(new Runnable() { + @Override public void run() { result[0] = s.get(); } + }); + return result[0]; + } + + /* ── Context accessor ────────────────────────────────────────────────── */ + + private static Context ctx() { return sActivity; } + + /* ── View creation ───────────────────────────────────────────────────── */ + + /** + * Create a LinearLayout. + * @param orientation 1=VERTICAL, 0=HORIZONTAL + * @param spacing gap between children in dp; applied as bottom/right margin + */ + public static int createLinearLayout(final int orientation, final int spacing) { + return runSyncInt(new IntSupplier() { + @Override public int get() { + LinearLayout ll = new LinearLayout(ctx()); + ll.setOrientation(orientation == 1 + ? LinearLayout.VERTICAL + : LinearLayout.HORIZONTAL); + ll.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + /* Spacing is stored so addChild can apply margins. */ + ll.setTag(R_TAG_SPACING, spacing); + return allocSlot(ll); + } + }); + } + + /** Create a FrameLayout (ZStack equivalent). */ + public static int createFrameLayout() { + return runSyncInt(new IntSupplier() { + @Override public int get() { + FrameLayout fl = new FrameLayout(ctx()); + fl.setLayoutParams(new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + return allocSlot(fl); + } + }); + } + + /** Create a ScrollView. */ + public static int createScrollView() { + return runSyncInt(new IntSupplier() { + @Override public int get() { + ScrollView sv = new ScrollView(ctx()); + sv.setLayoutParams(new ScrollView.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + sv.setFillViewport(true); + return allocSlot(sv); + } + }); + } + + /** Create a TextView with initial text. */ + public static int createTextView(final String text) { + return runSyncInt(new IntSupplier() { + @Override public int get() { + TextView tv = new TextView(ctx()); + tv.setText(text != null ? text : ""); + tv.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + return allocSlot(tv); + } + }); + } + + /** Create a Button with a label. */ + public static int createButton(final String label) { + return runSyncInt(new IntSupplier() { + @Override public int get() { + Button btn = new Button(ctx()); + btn.setText(label != null ? label : ""); + btn.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + return allocSlot(btn); + } + }); + } + + /** + * Create an EditText. + * @param placeholder hint text + * @param singleLine true = single-line text field; false = multi-line text area + */ + public static int createEditText(final String placeholder, final boolean singleLine) { + return runSyncInt(new IntSupplier() { + @Override public int get() { + EditText et = new EditText(ctx()); + et.setHint(placeholder != null ? placeholder : ""); + if (singleLine) { + et.setInputType(InputType.TYPE_CLASS_TEXT + | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); + et.setMaxLines(1); + et.setSingleLine(true); + } else { + et.setInputType(InputType.TYPE_CLASS_TEXT + | InputType.TYPE_TEXT_FLAG_MULTI_LINE); + et.setMinLines(3); + et.setSingleLine(false); + et.setGravity(Gravity.TOP | Gravity.START); + } + et.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + return allocSlot(et); + } + }); + } + + /** + * Create an ImageView, loading from a file path via BitmapFactory. + * If path is null/empty the ImageView is created with no image. + */ + public static int createImageView(final String path) { + return runSyncInt(new IntSupplier() { + @Override public int get() { + ImageView iv = new ImageView(ctx()); + iv.setScaleType(ImageView.ScaleType.FIT_CENTER); + iv.setAdjustViewBounds(true); + if (path != null && !path.isEmpty()) { + Bitmap bmp = BitmapFactory.decodeFile(path); + if (bmp != null) { + iv.setImageBitmap(bmp); + } else { + android.util.Log.w("ElBridge", + "createImageView: failed to decode " + path); + } + } + iv.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + return allocSlot(iv); + } + }); + } + + /* ── Window operations ───────────────────────────────────────────────── */ + + /** Set the Activity's content view to the view at slot. */ + public static void setContentView(final int slot) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v != null && sActivity != null) { + sActivity.setContentView(v); + } + } + }); + } + + /** Set the Activity title. */ + public static void setTitle(final String title) { + runSync(new Runnable() { + @Override public void run() { + if (sActivity != null) { + sActivity.setTitle(title != null ? title : ""); + } + } + }); + } + + /* ── Tree operations ─────────────────────────────────────────────────── */ + + /** + * Add child view to parent view. + * LinearLayout: child added as arranged child with spacing margin. + * ScrollView: child replaces current document view. + * FrameLayout / other ViewGroup: plain addView. + */ + public static void addChild(final int parentSlot, final int childSlot) { + runSync(new Runnable() { + @Override public void run() { + View parent = getView(parentSlot); + View child = getView(childSlot); + if (parent == null || child == null) return; + + /* Remove child from existing parent first. */ + if (child.getParent() instanceof ViewGroup) { + ((ViewGroup) child.getParent()).removeView(child); + } + + if (parent instanceof LinearLayout) { + LinearLayout ll = (LinearLayout) parent; + Object tag = ll.getTag(R_TAG_SPACING); + int spacing = (tag instanceof Integer) ? (Integer) tag : 0; + LinearLayout.LayoutParams lp; + Object existingLp = child.getLayoutParams(); + if (existingLp instanceof LinearLayout.LayoutParams) { + lp = (LinearLayout.LayoutParams) existingLp; + } else { + lp = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + } + /* Apply spacing as margin on the leading/top edge (after first child). */ + if (ll.getChildCount() > 0 && spacing > 0) { + int px = dpToPx(spacing); + if (ll.getOrientation() == LinearLayout.VERTICAL) { + lp.topMargin = px; + } else { + lp.leftMargin = px; + } + } + child.setLayoutParams(lp); + ll.addView(child); + } else if (parent instanceof ScrollView) { + ScrollView sv = (ScrollView) parent; + sv.removeAllViews(); + sv.addView(child); + } else if (parent instanceof ViewGroup) { + ((ViewGroup) parent).addView(child); + } + } + }); + } + + /** Remove child from its parent. */ + public static void removeChild(final int parentSlot, final int childSlot) { + runSync(new Runnable() { + @Override public void run() { + View parent = getView(parentSlot); + View child = getView(childSlot); + if (parent instanceof ViewGroup && child != null) { + ((ViewGroup) parent).removeView(child); + } + } + }); + } + + /** Remove the view from its parent and release the slot. */ + public static void destroyView(final int slot) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v == null) return; + if (v.getParent() instanceof ViewGroup) { + ((ViewGroup) v.getParent()).removeView(v); + } + sViews[slot] = null; + } + }); + } + + /* ── Property setters ────────────────────────────────────────────────── */ + + public static void setText(final int slot, final String text) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + String s = text != null ? text : ""; + if (v instanceof EditText) { + ((EditText) v).setText(s); + } else if (v instanceof Button) { + ((Button) v).setText(s); + } else if (v instanceof TextView) { + ((TextView) v).setText(s); + } + } + }); + } + + public static String getText(final int slot) { + final String[] result = { "" }; + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v instanceof TextView) { + CharSequence cs = ((TextView) v).getText(); + result[0] = cs != null ? cs.toString() : ""; + } + } + }); + return result[0]; + } + + /** Set foreground text color. Components in [0,1]. */ + public static void setTextColor(final int slot, final float r, final float g, + final float b, final float a) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v instanceof TextView) { + ((TextView) v).setTextColor(floatToArgb(r, g, b, a)); + } + } + }); + } + + /** Set background color using a GradientDrawable so corner radius is preserved. */ + public static void setBackgroundColor(final int slot, final float r, final float g, + final float b, final float a) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v == null) return; + ensureGradientBackground(v); + GradientDrawable gd = (GradientDrawable) v.getBackground(); + gd.setColor(floatToArgb(r, g, b, a)); + } + }); + } + + /** + * Set font family and size. + * family: "system" or null → system default; otherwise tries to load by name. + * bold: if true uses Typeface.BOLD. + */ + public static void setFont(final int slot, final String family, + final int sizeSp, final boolean bold) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (!(v instanceof TextView)) return; + TextView tv = (TextView) v; + Typeface tf; + if (family != null && !family.isEmpty() + && !family.equals("system")) { + Typeface base = Typeface.create(family, + bold ? Typeface.BOLD : Typeface.NORMAL); + tf = (base != null) ? base + : Typeface.defaultFromStyle(bold ? Typeface.BOLD : Typeface.NORMAL); + } else { + tf = Typeface.defaultFromStyle(bold ? Typeface.BOLD : Typeface.NORMAL); + } + tv.setTypeface(tf); + tv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, sizeSp); + } + }); + } + + /** Set padding in dp. */ + public static void setPadding(final int slot, final int top, final int right, + final int bottom, final int left) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v != null) { + v.setPadding(dpToPx(left), dpToPx(top), dpToPx(right), dpToPx(bottom)); + } + } + }); + } + + /** Set explicit width in dp. Passes MATCH_PARENT for negative values. */ + public static void setWidth(final int slot, final int widthDp) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v == null) return; + ViewGroup.LayoutParams lp = v.getLayoutParams(); + if (lp == null) lp = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + lp.width = widthDp < 0 + ? ViewGroup.LayoutParams.MATCH_PARENT + : dpToPx(widthDp); + v.setLayoutParams(lp); + } + }); + } + + /** Set explicit height in dp. */ + public static void setHeight(final int slot, final int heightDp) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v == null) return; + ViewGroup.LayoutParams lp = v.getLayoutParams(); + if (lp == null) lp = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + lp.height = heightDp < 0 + ? ViewGroup.LayoutParams.MATCH_PARENT + : dpToPx(heightDp); + v.setLayoutParams(lp); + } + }); + } + + /** + * Set flex weight on a child of a LinearLayout. + * flex > 0 → weight = flex, width/height = 0dp (expand). + * flex == 0 → weight = 0, wrap_content (shrink to content). + */ + public static void setFlex(final int slot, final int flex) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v == null) return; + ViewGroup.LayoutParams lp = v.getLayoutParams(); + if (lp instanceof LinearLayout.LayoutParams) { + LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams) lp; + if (flex > 0) { + llp.weight = (float) flex; + /* Determine orientation from parent to set 0dp on the right axis. */ + if (v.getParent() instanceof LinearLayout) { + LinearLayout parent = (LinearLayout) v.getParent(); + if (parent.getOrientation() == LinearLayout.VERTICAL) { + llp.height = 0; + } else { + llp.width = 0; + } + } + } else { + llp.weight = 0f; + } + v.setLayoutParams(llp); + } + } + }); + } + + /** Set corner radius in dp using a GradientDrawable background. */ + public static void setCornerRadius(final int slot, final float radiusDp) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v == null) return; + ensureGradientBackground(v); + GradientDrawable gd = (GradientDrawable) v.getBackground(); + gd.setCornerRadius(dpToPxF(radiusDp)); + } + }); + } + + public static void setEnabled(final int slot, final boolean enabled) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v != null) v.setEnabled(enabled); + } + }); + } + + /** + * Show or hide a view. + * @param visible true = VISIBLE, false = GONE (matches AppKit setHidden semantics) + */ + public static void setVisibility(final int slot, final boolean visible) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v != null) v.setVisibility(visible ? View.VISIBLE : View.GONE); + } + }); + } + + /* ── Event listener registration ─────────────────────────────────────── */ + + /** Register an OnClickListener that calls back into C nativeOnClick. */ + public static void setOnClickListener(final int slot) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (v == null) return; + final int capturedSlot = slot; + v.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View view) { + nativeOnClick(capturedSlot); + } + }); + } + }); + } + + /** + * Register a TextWatcher on an EditText that calls back nativeOnChange + * for every text change. + */ + public static void setOnChangeListener(final int slot) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (!(v instanceof EditText)) return; + final int capturedSlot = slot; + ((EditText) v).addTextChangedListener(new TextWatcher() { + @Override public void beforeTextChanged(CharSequence s, int start, + int count, int after) {} + @Override public void onTextChanged(CharSequence s, int start, + int before, int count) {} + @Override public void afterTextChanged(Editable s) { + nativeOnChange(capturedSlot, s != null ? s.toString() : ""); + } + }); + } + }); + } + + /** + * Register an OnEditorActionListener on a single-line EditText that calls + * nativeOnSubmit when the user presses the action/enter key. + */ + public static void setOnSubmitListener(final int slot) { + runSync(new Runnable() { + @Override public void run() { + View v = getView(slot); + if (!(v instanceof EditText)) return; + final int capturedSlot = slot; + ((EditText) v).setOnEditorActionListener( + new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView tv, int actionId, + android.view.KeyEvent event) { + nativeOnSubmit(capturedSlot, + tv.getText() != null ? tv.getText().toString() : ""); + return true; + } + }); + } + }); + } + + /* ── Internal helpers ─────────────────────────────────────────────────── */ + + /* + * Tag key used to stash the spacing value on LinearLayouts so addChild + * can apply the correct margin between children. + * We use a stable integer resource-id-like value; because we do not have + * a resources file here we use View.generateViewId() lazily. + */ + private static int sSpacingTagKey = 0; + + private static int R_TAG_SPACING; + static { + R_TAG_SPACING = View.generateViewId(); + } + + /** Convert dp to pixels using the Activity's display metrics. */ + private static int dpToPx(float dp) { + if (sActivity == null) return (int) dp; + float density = sActivity.getResources().getDisplayMetrics().density; + return Math.round(dp * density); + } + + private static float dpToPxF(float dp) { + if (sActivity == null) return dp; + float density = sActivity.getResources().getDisplayMetrics().density; + return dp * density; + } + + /** Convert RGBA float components (0–1) to an Android ARGB int. */ + private static int floatToArgb(float r, float g, float b, float a) { + int ai = Math.round(a * 255f); + int ri = Math.round(r * 255f); + int gi = Math.round(g * 255f); + int bi = Math.round(b * 255f); + return Color.argb(ai, ri, gi, bi); + } + + /** + * Ensure the view has a GradientDrawable background so that both color + * and corner radius can be set independently. If the current background + * is already a GradientDrawable it is reused; otherwise a new transparent + * one is installed. + */ + private static void ensureGradientBackground(View v) { + if (!(v.getBackground() instanceof GradientDrawable)) { + GradientDrawable gd = new GradientDrawable(); + gd.setColor(Color.TRANSPARENT); + v.setBackground(gd); + } + } +} diff --git a/ui/examples/native-hello-android/app/src/main/java/com/neuron/el/MainActivity.java b/ui/examples/native-hello-android/app/src/main/java/com/neuron/el/MainActivity.java new file mode 100644 index 0000000..47eec0e --- /dev/null +++ b/ui/examples/native-hello-android/app/src/main/java/com/neuron/el/MainActivity.java @@ -0,0 +1,38 @@ +package com.neuron.el; + +import android.app.Activity; +import android.os.Bundle; + +/** + * MainActivity — entry point for native-hello-android. + * + * Loads the el native shared library, initialises ElBridge with the Activity + * reference (required before any widget operations), then hands control to the + * compiled el program via nativeMain(). + * + * The el boot sequence (native_init → window_from_manifest → app_build → + * window_show) runs inside nativeMain. __native_run_loop is a no-op on Android; + * the Activity lifecycle owns the UI thread after onCreate returns. + */ +public class MainActivity extends Activity { + + static { + System.loadLibrary("elnative"); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // Register this Activity with the bridge BEFORE nativeMain so that + // el_android_init can look up ElBridge methods and __native_init works. + ElBridge.init(this); + // Run the compiled el program. + nativeMain(); + } + + /** + * Implemented in el_android.c as Java_com_neuron_el_MainActivity_nativeMain. + * Calls the el program's main(), which runs the full boot sequence. + */ + private native void nativeMain(); +} diff --git a/ui/examples/native-hello-android/app/src/main/jni/CMakeLists.txt b/ui/examples/native-hello-android/app/src/main/jni/CMakeLists.txt new file mode 100644 index 0000000..fbc3dea --- /dev/null +++ b/ui/examples/native-hello-android/app/src/main/jni/CMakeLists.txt @@ -0,0 +1,57 @@ +cmake_minimum_required(VERSION 3.22.1) +project("elnative") + +# +# CMakeLists.txt for native-hello-android +# +# Sources: +# el_android.c — Android JNI widget bridge +# el_seed.c — OS-boundary __-prefixed primitives +# el_runtime.c — High-level el builtins (str_len, json_*, etc.) +# el_native_vessel.c — el-native vessel (compiled from vessels/el-native/src/main.el) +# native_hello.c — App entry point (compiled from examples/native-hello/src/main.el) +# +# el_runtime.c and el_seed.c both define __-prefixed symbols. On Android the +# linker accepts duplicate weak symbols; the shared library loads one copy. +# The EL_TARGET_ANDROID guard in el_android.c ensures only the Android widget +# backend is compiled in. +# + +add_library( + elnative + SHARED + + # native_hello.c listed first so its main() takes precedence over the + # vessel's main() when --allow-multiple-definition is in effect. + native_hello.c + el_native_vessel.c + el_android.c + el_seed.c + el_runtime.c +) + +# EL_TARGET_ANDROID activates the Android JNI widget backend in el_android.c +# and the corresponding guards in el_seed.c / el_native_target.h. +target_compile_definitions(elnative PRIVATE + EL_TARGET_ANDROID +) + +target_include_directories(elnative PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# el_runtime.c and el_seed.c both define __-prefixed OS-boundary symbols. +# el_runtime.c's copies are weaker definitions; allow-multiple-definition lets +# the linker pick one copy silently (el_seed.c listed later = its copy wins +# in the Android linker's right-to-left resolution order). +target_link_options(elnative PRIVATE + "-Wl,--allow-multiple-definition" +) + +find_library(log-lib log) +find_library(android-lib android) + +target_link_libraries(elnative + ${log-lib} + ${android-lib} +) diff --git a/ui/examples/native-hello-android/app/src/main/jni/el_android.c b/ui/examples/native-hello-android/app/src/main/jni/el_android.c new file mode 100644 index 0000000..5f629ba --- /dev/null +++ b/ui/examples/native-hello-android/app/src/main/jni/el_android.c @@ -0,0 +1,964 @@ +/* + * el_android.c — Android JNI backend for the el native widget system. + * + * This file implements the Android widget layer that el_seed.c calls through + * to when EL_TARGET_ANDROID is defined. It is the exact Android counterpart + * to el_appkit.m and presents the same C API surface. + * + * Architecture: + * el program (el code) + * → __widget_* C builtins in el_seed.c + * → el_android_* C-callable functions declared here + * → ElBridge static methods in Java via JNI + * → android.view.View subclasses on the UI thread + * + * Widget handles: every widget (window root, view, control) is assigned an + * int64_t slot index into view_slots[]. The el program holds these as opaque + * Int values. Slot 0 is never valid (null handle = -1 convention). + * + * Threading: Android requires all UI operations to run on the main (UI) thread. + * Every JNI call that mutates a View is dispatched through + * Activity.runOnUiThread(Runnable) if the current thread is not the UI thread. + * el_android_run_loop is a no-op — Android lifecycle is driven by the Activity. + * + * Callback mechanism: when a widget fires an event Java calls + * nativeOnClick / nativeOnChange / nativeOnSubmit + * The C side looks up the registered El function name for that slot, then: + * dlsym(RTLD_DEFAULT, fn_name)(widget_handle, event_data_string) + * This matches the __thread_create pattern in el_seed.c exactly. + * + * Compile / link (as part of libelruntime.so): + * Compiled by the Android Gradle NDK build system with -DEL_TARGET_ANDROID. + * Link flags: -landroid -llog -ldl + * + * Java companion: ElBridge.java in the same directory must be compiled into + * the Android application's APK (package com.neuron.el). + */ + +#ifdef EL_TARGET_ANDROID + +#include +#include +#include +#include +#include +#include +#include "el_runtime.h" + +/* ── Logging ─────────────────────────────────────────────────────────────── */ + +#define EL_TAG "ElAndroid" +#define EL_LOGI(...) __android_log_print(ANDROID_LOG_INFO, EL_TAG, __VA_ARGS__) +#define EL_LOGW(...) __android_log_print(ANDROID_LOG_WARN, EL_TAG, __VA_ARGS__) +#define EL_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, EL_TAG, __VA_ARGS__) + +/* ── JNI global state ────────────────────────────────────────────────────── */ + +static JavaVM *g_jvm = NULL; +static jobject g_activity = NULL; /* global ref to Activity */ +static jclass g_bridge_class = NULL; /* global ref to ElBridge class */ + +/* Cached method IDs on ElBridge — filled in el_android_init(). */ +static jmethodID g_mid_createLinearLayout = NULL; +static jmethodID g_mid_createFrameLayout = NULL; +static jmethodID g_mid_createScrollView = NULL; +static jmethodID g_mid_createTextView = NULL; +static jmethodID g_mid_createButton = NULL; +static jmethodID g_mid_createEditText = NULL; +static jmethodID g_mid_createImageView = NULL; +static jmethodID g_mid_setContentView = NULL; +static jmethodID g_mid_setTitle = NULL; +static jmethodID g_mid_addChild = NULL; +static jmethodID g_mid_removeChild = NULL; +static jmethodID g_mid_destroyView = NULL; +static jmethodID g_mid_setText = NULL; +static jmethodID g_mid_getText = NULL; +static jmethodID g_mid_setTextColor = NULL; +static jmethodID g_mid_setBackgroundColor = NULL; +static jmethodID g_mid_setFont = NULL; +static jmethodID g_mid_setPadding = NULL; +static jmethodID g_mid_setWidth = NULL; +static jmethodID g_mid_setHeight = NULL; +static jmethodID g_mid_setFlex = NULL; +static jmethodID g_mid_setCornerRadius = NULL; +static jmethodID g_mid_setEnabled = NULL; +static jmethodID g_mid_setVisibility = NULL; +static jmethodID g_mid_setOnClickListener = NULL; +static jmethodID g_mid_setOnChangeListener = NULL; +static jmethodID g_mid_setOnSubmitListener = NULL; +static jmethodID g_mid_runOnUiThread = NULL; /* Activity.runOnUiThread */ + +/* ── Widget table ─────────────────────────────────────────────────────────── */ + +#define EL_ANDROID_MAX_WIDGETS 4096 + +typedef enum { + EL_WIDGET_FREE = 0, + EL_WIDGET_WINDOW = 1, + EL_WIDGET_VSTACK = 2, + EL_WIDGET_HSTACK = 3, + EL_WIDGET_ZSTACK = 4, + EL_WIDGET_SCROLL = 5, + EL_WIDGET_LABEL = 6, + EL_WIDGET_BUTTON = 7, + EL_WIDGET_TEXTFIELD = 8, + EL_WIDGET_TEXTAREA = 9, + EL_WIDGET_IMAGE = 10, +} ElWidgetKind; + +typedef struct { + ElWidgetKind kind; + jint slot; /* Java-side slot index (matches C index) */ + char *cb_click; /* El function name for click / submit events */ + char *cb_change; /* El function name for value-change events */ +} ElWidget; + +static ElWidget _el_widgets[EL_ANDROID_MAX_WIDGETS]; + +static int64_t el_widget_alloc(ElWidgetKind kind, jint slot) { + for (int i = 1; i < EL_ANDROID_MAX_WIDGETS; i++) { + if (_el_widgets[i].kind == EL_WIDGET_FREE) { + _el_widgets[i].kind = kind; + _el_widgets[i].slot = slot; + _el_widgets[i].cb_click = NULL; + _el_widgets[i].cb_change = NULL; + return (int64_t)i; + } + } + EL_LOGE("el_widget_alloc: slot table full"); + return -1; +} + +static ElWidget *el_widget_get(int64_t handle) { + if (handle <= 0 || handle >= EL_ANDROID_MAX_WIDGETS) return NULL; + if (_el_widgets[handle].kind == EL_WIDGET_FREE) return NULL; + return &_el_widgets[handle]; +} + +static void el_widget_free(int64_t handle) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + w->kind = EL_WIDGET_FREE; + w->slot = -1; + free(w->cb_click); w->cb_click = NULL; + free(w->cb_change); w->cb_change = NULL; +} + +/* ── JNI environment helpers ─────────────────────────────────────────────── */ + +/* + * Obtain a JNIEnv for the calling thread. Attaches the thread to the JVM if + * needed (detaches in el_jni_detach_if_attached — call in pairs). + */ +static int g_was_attached = 0; /* thread-local would be cleaner but this is + safe for single-threaded el programs */ + +static JNIEnv *el_jni_env(void) { + if (!g_jvm) return NULL; + JNIEnv *env = NULL; + jint rc = (*g_jvm)->GetEnv(g_jvm, (void **)&env, JNI_VERSION_1_6); + if (rc == JNI_OK) { g_was_attached = 0; return env; } + if (rc == JNI_EDETACHED) { + if ((*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL) == JNI_OK) { + g_was_attached = 1; + return env; + } + } + EL_LOGE("el_jni_env: failed to obtain JNIEnv"); + return NULL; +} + +static void el_jni_detach_if_attached(void) { + if (g_was_attached && g_jvm) { + (*g_jvm)->DetachCurrentThread(g_jvm); + g_was_attached = 0; + } +} + +/* ── UI-thread dispatch ──────────────────────────────────────────────────── */ +/* + * Most ElBridge static methods already dispatch to the UI thread internally + * (they call Activity.runOnUiThread). The helper below is available for + * cases where the caller needs to be sure the call has completed before + * returning (ElBridge methods marked "sync" use a CountDownLatch internally). + * + * For the current implementation we call ElBridge methods directly; ElBridge + * itself marshals to the UI thread via Activity.runOnUiThread + latch. + * This keeps the C side simple and mirrors the AppKit dispatch_sync pattern. + */ + +/* ── JNI_OnLoad ──────────────────────────────────────────────────────────── */ + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { + (void)reserved; + g_jvm = vm; + EL_LOGI("JNI_OnLoad: el Android bridge loaded"); + return JNI_VERSION_1_6; +} + +/* ── el_android_init ─────────────────────────────────────────────────────── */ +/* + * Called from __native_init(). The Activity must have already called + * ElBridge.registerActivity(activity) from Java before this runs, which sets + * g_activity via the nativeRegisterActivity JNI method below. + * + * Caches all method IDs used later so individual widget calls avoid repeated + * FindClass / GetStaticMethodID lookups. + */ +void el_android_init(void) { + static int done = 0; + if (done) return; + done = 1; + + JNIEnv *env = el_jni_env(); + if (!env) { EL_LOGE("el_android_init: no JNIEnv"); return; } + + jclass cls = (*env)->FindClass(env, "com/neuron/el/ElBridge"); + if (!cls) { EL_LOGE("el_android_init: ElBridge class not found"); return; } + g_bridge_class = (*env)->NewGlobalRef(env, cls); + (*env)->DeleteLocalRef(env, cls); + +#define CACHE_STATIC(var, name, sig) \ + var = (*env)->GetStaticMethodID(env, g_bridge_class, name, sig); \ + if (!var) EL_LOGW("el_android_init: method not found: %s %s", name, sig) + + CACHE_STATIC(g_mid_createLinearLayout, "createLinearLayout", "(II)I"); + CACHE_STATIC(g_mid_createFrameLayout, "createFrameLayout", "()I"); + CACHE_STATIC(g_mid_createScrollView, "createScrollView", "()I"); + CACHE_STATIC(g_mid_createTextView, "createTextView", "(Ljava/lang/String;)I"); + CACHE_STATIC(g_mid_createButton, "createButton", "(Ljava/lang/String;)I"); + CACHE_STATIC(g_mid_createEditText, "createEditText", "(Ljava/lang/String;Z)I"); + CACHE_STATIC(g_mid_createImageView, "createImageView", "(Ljava/lang/String;)I"); + CACHE_STATIC(g_mid_setContentView, "setContentView", "(I)V"); + CACHE_STATIC(g_mid_setTitle, "setTitle", "(Ljava/lang/String;)V"); + CACHE_STATIC(g_mid_addChild, "addChild", "(II)V"); + CACHE_STATIC(g_mid_removeChild, "removeChild", "(II)V"); + CACHE_STATIC(g_mid_destroyView, "destroyView", "(I)V"); + CACHE_STATIC(g_mid_setText, "setText", "(ILjava/lang/String;)V"); + CACHE_STATIC(g_mid_getText, "getText", "(I)Ljava/lang/String;"); + CACHE_STATIC(g_mid_setTextColor, "setTextColor", "(IFFFF)V"); + CACHE_STATIC(g_mid_setBackgroundColor, "setBackgroundColor", "(IFFFF)V"); + CACHE_STATIC(g_mid_setFont, "setFont", "(ILjava/lang/String;IZ)V"); + CACHE_STATIC(g_mid_setPadding, "setPadding", "(IIIII)V"); + CACHE_STATIC(g_mid_setWidth, "setWidth", "(II)V"); + CACHE_STATIC(g_mid_setHeight, "setHeight", "(II)V"); + CACHE_STATIC(g_mid_setFlex, "setFlex", "(II)V"); + CACHE_STATIC(g_mid_setCornerRadius, "setCornerRadius", "(IF)V"); + CACHE_STATIC(g_mid_setEnabled, "setEnabled", "(IZ)V"); + CACHE_STATIC(g_mid_setVisibility, "setVisibility", "(IZ)V"); + CACHE_STATIC(g_mid_setOnClickListener, "setOnClickListener", "(I)V"); + CACHE_STATIC(g_mid_setOnChangeListener, "setOnChangeListener", "(I)V"); + CACHE_STATIC(g_mid_setOnSubmitListener, "setOnSubmitListener", "(I)V"); +#undef CACHE_STATIC + + el_jni_detach_if_attached(); + EL_LOGI("el_android_init: complete"); +} + +/* ── JNI: Activity registration ─────────────────────────────────────────── */ + +/* + * Called from Java: ElBridge.registerActivity(activity) calls back here. + * Stores a global reference to the Activity so C code can dispatch to it. + */ +JNIEXPORT void JNICALL +Java_com_neuron_el_ElBridge_nativeRegisterActivity(JNIEnv *env, jclass cls, + jobject activity) { + (void)cls; + if (g_activity) { + (*env)->DeleteGlobalRef(env, g_activity); + g_activity = NULL; + } + if (activity) { + g_activity = (*env)->NewGlobalRef(env, activity); + EL_LOGI("nativeRegisterActivity: activity registered"); + } +} + +/* ── El callback invocation ──────────────────────────────────────────────── */ +/* + * Invoke an El callback by symbol name. + * Signature matches AppKit: fn(handle: Int, data: String) -> Void + * compiled to: void fn(el_val_t handle, el_val_t data) + */ +typedef void (*ElCb2)(int64_t handle, int64_t data); + +static void el_android_invoke_cb(const char *fn_name, int64_t handle, + const char *data) { + if (!fn_name || !*fn_name) return; + void *sym = dlsym(RTLD_DEFAULT, fn_name); + if (!sym) { EL_LOGW("invoke_cb: symbol not found: %s", fn_name); return; } + ElCb2 fn = (ElCb2)sym; + fn(handle, (int64_t)(uintptr_t)(data ? data : "")); +} + +/* ── JNI: callbacks from Java → C ───────────────────────────────────────── */ + +JNIEXPORT void JNICALL +Java_com_neuron_el_ElBridge_nativeOnClick(JNIEnv *env, jclass cls, jint slot) { + (void)env; (void)cls; + int64_t handle = (int64_t)slot; + ElWidget *w = el_widget_get(handle); + if (w && w->cb_click) { + el_android_invoke_cb(w->cb_click, handle, ""); + } +} + +JNIEXPORT void JNICALL +Java_com_neuron_el_ElBridge_nativeOnChange(JNIEnv *env, jclass cls, + jint slot, jstring text) { + (void)cls; + int64_t handle = (int64_t)slot; + ElWidget *w = el_widget_get(handle); + if (w && w->cb_change) { + const char *ctext = text ? (*env)->GetStringUTFChars(env, text, NULL) : ""; + el_android_invoke_cb(w->cb_change, handle, ctext); + if (text) (*env)->ReleaseStringUTFChars(env, text, ctext); + } +} + +JNIEXPORT void JNICALL +Java_com_neuron_el_ElBridge_nativeOnSubmit(JNIEnv *env, jclass cls, + jint slot, jstring text) { + (void)cls; + int64_t handle = (int64_t)slot; + ElWidget *w = el_widget_get(handle); + if (w && w->cb_click) { /* submit stored in cb_click, same as AppKit */ + const char *ctext = text ? (*env)->GetStringUTFChars(env, text, NULL) : ""; + el_android_invoke_cb(w->cb_click, handle, ctext); + if (text) (*env)->ReleaseStringUTFChars(env, text, ctext); + } +} + +/* ── Helper: jstring from C string ──────────────────────────────────────── */ + +static jstring el_jstr(JNIEnv *env, const char *s) { + return (*env)->NewStringUTF(env, s ? s : ""); +} + +/* ── Window ──────────────────────────────────────────────────────────────── */ + +/* + * el_android_window_create — on Android a "window" is the root LinearLayout + * set as the Activity's content view. We create a vertical LinearLayout and + * store it. el_android_window_show calls setContentView on the Activity. + */ +int64_t el_android_window_create(const char *title, int width, int height, + int min_width, int min_height) { + (void)width; (void)height; (void)min_width; (void)min_height; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + + /* VERTICAL LinearLayout with no spacing (spacing added via margins in Java) */ + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createLinearLayout, + (jint)1 /* VERTICAL */, (jint)0); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; + } + + /* Set activity title */ + if (g_mid_setTitle && title) { + jstring jtitle = el_jstr(env, title); + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setTitle, jtitle); + (*env)->DeleteLocalRef(env, jtitle); + } + + int64_t handle = el_widget_alloc(EL_WIDGET_WINDOW, (int)slot); + el_jni_detach_if_attached(); + return handle; +} + +void el_android_window_show(int64_t handle) { + ElWidget *w = el_widget_get(handle); + if (!w || w->kind != EL_WIDGET_WINDOW) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setContentView, + (jint)w->slot); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_window_set_title(int64_t handle, const char *title) { + (void)handle; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + jstring jtitle = el_jstr(env, title); + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setTitle, jtitle); + (*env)->DeleteLocalRef(env, jtitle); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +/* ── Layout containers ───────────────────────────────────────────────────── */ + +int64_t el_android_vstack_create(int spacing) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createLinearLayout, + (jint)1 /* VERTICAL */, (jint)spacing); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_VSTACK, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +int64_t el_android_hstack_create(int spacing) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createLinearLayout, + (jint)0 /* HORIZONTAL */, (jint)spacing); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_HSTACK, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +int64_t el_android_zstack_create(void) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createFrameLayout); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_ZSTACK, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +int64_t el_android_scroll_create(void) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createScrollView); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_SCROLL, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +/* ── Widget factories ─────────────────────────────────────────────────────── */ + +int64_t el_android_label_create(const char *text) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jstring jt = el_jstr(env, text); + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createTextView, jt); + (*env)->DeleteLocalRef(env, jt); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_LABEL, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +int64_t el_android_button_create(const char *label) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jstring jl = el_jstr(env, label); + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createButton, jl); + (*env)->DeleteLocalRef(env, jl); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_BUTTON, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +int64_t el_android_text_field_create(const char *placeholder) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jstring jp = el_jstr(env, placeholder); + /* singleLine = true */ + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createEditText, jp, (jboolean)JNI_TRUE); + (*env)->DeleteLocalRef(env, jp); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_TEXTFIELD, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +int64_t el_android_text_area_create(const char *placeholder) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jstring jp = el_jstr(env, placeholder); + /* singleLine = false → multiline EditText */ + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createEditText, jp, (jboolean)JNI_FALSE); + (*env)->DeleteLocalRef(env, jp); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_TEXTAREA, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +int64_t el_android_image_create(const char *path) { + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return -1; + jstring jp = el_jstr(env, path); + jint slot = (*env)->CallStaticIntMethod(env, g_bridge_class, + g_mid_createImageView, jp); + (*env)->DeleteLocalRef(env, jp); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return -1; } + int64_t h = el_widget_alloc(EL_WIDGET_IMAGE, (int)slot); + el_jni_detach_if_attached(); + return h; +} + +/* ── Widget property setters ─────────────────────────────────────────────── */ + +void el_android_widget_set_text(int64_t handle, const char *text) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + jstring jt = el_jstr(env, text); + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setText, + (jint)w->slot, jt); + (*env)->DeleteLocalRef(env, jt); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +const char *el_android_widget_get_text(int64_t handle) { + ElWidget *w = el_widget_get(handle); + if (!w) return ""; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return ""; + jstring js = (jstring)(*env)->CallStaticObjectMethod(env, g_bridge_class, + g_mid_getText, + (jint)w->slot); + if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionClear(env); el_jni_detach_if_attached(); return ""; } + const char *result = ""; + if (js) { + const char *cstr = (*env)->GetStringUTFChars(env, js, NULL); + result = cstr ? strdup(cstr) : ""; + if (cstr) (*env)->ReleaseStringUTFChars(env, js, cstr); + (*env)->DeleteLocalRef(env, js); + } + el_jni_detach_if_attached(); + return result; +} + +void el_android_widget_set_color(int64_t handle, float r, float g, float b, float a) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setTextColor, + (jint)w->slot, (jfloat)r, (jfloat)g, + (jfloat)b, (jfloat)a); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_bg_color(int64_t handle, float r, float g, float b, float a) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setBackgroundColor, + (jint)w->slot, (jfloat)r, (jfloat)g, + (jfloat)b, (jfloat)a); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_font(int64_t handle, const char *family, int size, int bold) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + jstring jfam = el_jstr(env, family); + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setFont, + (jint)w->slot, jfam, (jint)size, + (jboolean)(bold ? JNI_TRUE : JNI_FALSE)); + (*env)->DeleteLocalRef(env, jfam); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_padding(int64_t handle, int top, int right, int bottom, int left) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setPadding, + (jint)w->slot, (jint)top, (jint)right, + (jint)bottom, (jint)left); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_width(int64_t handle, int width) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setWidth, + (jint)w->slot, (jint)width); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_height(int64_t handle, int height) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setHeight, + (jint)w->slot, (jint)height); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_flex(int64_t handle, int flex) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setFlex, + (jint)w->slot, (jint)flex); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_corner_radius(int64_t handle, int radius) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setCornerRadius, + (jint)w->slot, (jfloat)radius); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_disabled(int64_t handle, int disabled) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setEnabled, + (jint)w->slot, + (jboolean)(disabled ? JNI_FALSE : JNI_TRUE)); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_set_hidden(int64_t handle, int hidden) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + /* visible=true means NOT hidden */ + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setVisibility, + (jint)w->slot, + (jboolean)(hidden ? JNI_FALSE : JNI_TRUE)); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +/* ── Child management ─────────────────────────────────────────────────────── */ + +void el_android_widget_add_child(int64_t parent, int64_t child) { + ElWidget *pw = el_widget_get(parent); + ElWidget *cw = el_widget_get(child); + if (!pw || !cw) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_addChild, + (jint)pw->slot, (jint)cw->slot); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_remove_child(int64_t parent, int64_t child) { + ElWidget *pw = el_widget_get(parent); + ElWidget *cw = el_widget_get(child); + if (!pw || !cw) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_removeChild, + (jint)pw->slot, (jint)cw->slot); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +/* ── Event registration ───────────────────────────────────────────────────── */ + +void el_android_widget_on_click(int64_t handle, const char *fn_name) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + free(w->cb_click); + w->cb_click = (fn_name && *fn_name) ? strdup(fn_name) : NULL; + if (!w->cb_click) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setOnClickListener, + (jint)w->slot); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_on_change(int64_t handle, const char *fn_name) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + free(w->cb_change); + w->cb_change = (fn_name && *fn_name) ? strdup(fn_name) : NULL; + if (!w->cb_change) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setOnChangeListener, + (jint)w->slot); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +void el_android_widget_on_submit(int64_t handle, const char *fn_name) { + /* Submit stored in cb_click, same as AppKit. */ + ElWidget *w = el_widget_get(handle); + if (!w) return; + free(w->cb_click); + w->cb_click = (fn_name && *fn_name) ? strdup(fn_name) : NULL; + if (!w->cb_click) return; + JNIEnv *env = el_jni_env(); + if (!env || !g_bridge_class) return; + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_setOnSubmitListener, + (jint)w->slot); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + el_jni_detach_if_attached(); +} + +/* ── Widget destroy ───────────────────────────────────────────────────────── */ + +void el_android_widget_destroy(int64_t handle) { + ElWidget *w = el_widget_get(handle); + if (!w) return; + JNIEnv *env = el_jni_env(); + if (env && g_bridge_class) { + (*env)->CallStaticVoidMethod(env, g_bridge_class, g_mid_destroyView, + (jint)w->slot); + if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env); + } + el_widget_free(handle); + el_jni_detach_if_attached(); +} + +/* ── Manifest reader ─────────────────────────────────────────────────────── */ +/* + * __manifest_read: parse the app{} block from a manifest file. + * Returns the raw file contents as an el_val_t (const char* cast). + * The caller (el program) parses the returned string. + * Reads from the filesystem; for APK assets use the AssetManager path instead. + */ +static char *el_read_file(const char *path) { + if (!path || !*path) return NULL; + FILE *f = fopen(path, "rb"); + if (!f) return NULL; + fseek(f, 0, SEEK_END); + long len = ftell(f); + fseek(f, 0, SEEK_SET); + if (len <= 0) { fclose(f); return NULL; } + char *buf = (char *)malloc((size_t)len + 1); + if (!buf) { fclose(f); return NULL; } + fread(buf, 1, (size_t)len, f); + buf[len] = '\0'; + fclose(f); + return buf; +} + +el_val_t el_android_manifest_read(const char *path) { + char *contents = el_read_file(path); + if (!contents) return (el_val_t)(uintptr_t)""; + return (el_val_t)(uintptr_t)contents; /* caller owns allocation */ +} + +/* ── __widget_* C API (called from el_seed.c) ────────────────────────────── */ +/* + * These are the functions declared in el_native_target.h under EL_TARGET_ANDROID. + * They forward to the el_android_* internal functions above. + * + * The el_val_t / int64_t ABI matches the AppKit functions exactly: + * - Integer params passed as int64_t, extracted with (int) + * - String params passed as int64_t, extracted with (const char*)(uintptr_t) + * - Float params (r,g,b,a) passed as int64_t bit-cast from double; extracted + * with el_to_float / bit-cast union + */ + +static inline float el_val_to_float(el_val_t v) { + union { double d; int64_t i; } u; + u.i = v; + return (float)u.d; +} + +void __native_init(void) { + el_android_init(); +} + +void __native_run_loop(void) { + /* No-op on Android — lifecycle is driven by the Activity. */ +} + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_android_window_create( + (const char *)(uintptr_t)title, + (int)width, (int)height, (int)min_width, (int)min_height); +} + +void __window_show(el_val_t handle) { + el_android_window_show((int64_t)handle); +} + +void __window_set_title(el_val_t handle, el_val_t title) { + el_android_window_set_title((int64_t)handle, + (const char *)(uintptr_t)title); +} + +el_val_t __vstack_create(el_val_t spacing) { + return (el_val_t)el_android_vstack_create((int)spacing); +} + +el_val_t __hstack_create(el_val_t spacing) { + return (el_val_t)el_android_hstack_create((int)spacing); +} + +el_val_t __zstack_create(void) { + return (el_val_t)el_android_zstack_create(); +} + +el_val_t __scroll_create(void) { + return (el_val_t)el_android_scroll_create(); +} + +el_val_t __label_create(el_val_t text) { + return (el_val_t)el_android_label_create((const char *)(uintptr_t)text); +} + +el_val_t __button_create(el_val_t label) { + return (el_val_t)el_android_button_create((const char *)(uintptr_t)label); +} + +el_val_t __text_field_create(el_val_t placeholder) { + return (el_val_t)el_android_text_field_create((const char *)(uintptr_t)placeholder); +} + +el_val_t __text_area_create(el_val_t placeholder) { + return (el_val_t)el_android_text_area_create((const char *)(uintptr_t)placeholder); +} + +el_val_t __image_create(el_val_t path_or_name) { + return (el_val_t)el_android_image_create((const char *)(uintptr_t)path_or_name); +} + +void __widget_set_text(el_val_t handle, el_val_t text) { + el_android_widget_set_text((int64_t)handle, + (const char *)(uintptr_t)text); +} + +el_val_t __widget_get_text(el_val_t handle) { + return (el_val_t)(uintptr_t)el_android_widget_get_text((int64_t)handle); +} + +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a) { + el_android_widget_set_color((int64_t)handle, + el_val_to_float(r), el_val_to_float(g), + el_val_to_float(b), el_val_to_float(a)); +} + +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a) { + el_android_widget_set_bg_color((int64_t)handle, + el_val_to_float(r), el_val_to_float(g), + el_val_to_float(b), el_val_to_float(a)); +} + +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold) { + el_android_widget_set_font((int64_t)handle, + (const char *)(uintptr_t)family, + (int)size, (int)bold); +} + +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_android_widget_set_padding((int64_t)handle, + (int)top, (int)right, (int)bottom, (int)left); +} + +void __widget_set_width(el_val_t handle, el_val_t width) { + el_android_widget_set_width((int64_t)handle, (int)width); +} + +void __widget_set_height(el_val_t handle, el_val_t height) { + el_android_widget_set_height((int64_t)handle, (int)height); +} + +void __widget_set_flex(el_val_t handle, el_val_t flex) { + el_android_widget_set_flex((int64_t)handle, (int)flex); +} + +void __widget_set_corner_radius(el_val_t handle, el_val_t radius) { + el_android_widget_set_corner_radius((int64_t)handle, (int)radius); +} + +void __widget_set_disabled(el_val_t handle, el_val_t disabled) { + el_android_widget_set_disabled((int64_t)handle, (int)disabled); +} + +void __widget_set_hidden(el_val_t handle, el_val_t hidden) { + el_android_widget_set_hidden((int64_t)handle, (int)hidden); +} + +void __widget_add_child(el_val_t parent, el_val_t child) { + el_android_widget_add_child((int64_t)parent, (int64_t)child); +} + +void __widget_remove_child(el_val_t parent, el_val_t child) { + el_android_widget_remove_child((int64_t)parent, (int64_t)child); +} + +void __widget_destroy(el_val_t handle) { + el_android_widget_destroy((int64_t)handle); +} + +void __widget_on_click(el_val_t handle, el_val_t fn_name) { + el_android_widget_on_click((int64_t)handle, + (const char *)(uintptr_t)fn_name); +} + +void __widget_on_change(el_val_t handle, el_val_t fn_name) { + el_android_widget_on_change((int64_t)handle, + (const char *)(uintptr_t)fn_name); +} + +void __widget_on_submit(el_val_t handle, el_val_t fn_name) { + el_android_widget_on_submit((int64_t)handle, + (const char *)(uintptr_t)fn_name); +} + +el_val_t __manifest_read(el_val_t path) { + return el_android_manifest_read((const char *)(uintptr_t)path); +} + +/* ── MainActivity JNI entry point ─────────────────────────────────────────── */ +/* + * Java_com_neuron_el_MainActivity_nativeMain — invoked from MainActivity.onCreate + * after ElBridge.init(this). Calls the el program's compiled main() which runs + * the boot sequence: native_init → window_from_manifest → app_build → window_show. + * __native_run_loop is a no-op on Android; the Activity lifecycle drives the UI. + */ +JNIEXPORT void JNICALL +Java_com_neuron_el_MainActivity_nativeMain(JNIEnv *env, jobject obj) { + (void)env; (void)obj; + extern int main(int argc, char **argv); + char *argv[] = {"el-app", NULL}; + main(1, argv); +} + +#endif /* EL_TARGET_ANDROID */ diff --git a/ui/examples/native-hello-android/app/src/main/jni/el_native_target.h b/ui/examples/native-hello-android/app/src/main/jni/el_native_target.h new file mode 100644 index 0000000..dc1edcb --- /dev/null +++ b/ui/examples/native-hello-android/app/src/main/jni/el_native_target.h @@ -0,0 +1,573 @@ +/* + * el_native_target.h — Native widget declarations for el programs targeting + * native desktop UI (AppKit / GTK4 / Win32). + * + * This header is designed to be included AFTER el_runtime.h without conflict: + * - It does NOT redefine el_to_float, el_from_float, or any el_runtime.h + * static inlines. + * - It does NOT redeclare __println, __print, or other functions whose + * return types differ between el_seed.h and el_runtime.h. + * - It adds: native widget builtins + float arithmetic helpers that the + * current el_runtime.h omits but elc still emits calls to. + * + * Usage: + * Inject via -include at compile time, OR #include it after el_runtime.h. + * + * clang -DEL_TARGET_MACOS -include el_native_target.h -c my_app.c ... + */ + +#pragma once + +#include +#include + +/* el_val_t must already be defined by el_runtime.h or el_seed.h. */ +#ifndef EL_VAL_T_DEFINED +typedef int64_t el_val_t; +#endif + +/* ── Float arithmetic helpers ─────────────────────────────────────────────── + * elc emits calls to float_div / float_mul etc. for Float-typed expressions. + * These were in el_runtime.c through v1.0.0-20260501 but are missing from the + * current el_runtime.h. Redeclared here as static inline to avoid link deps. + * Only defined if not already declared (old runtimes that still have them). */ + +#ifndef EL_FLOAT_OPS_DEFINED +#define EL_FLOAT_OPS_DEFINED + +/* el_to_float / el_from_float — bit-cast between el_val_t and double. + * Defined as static inline in both el_runtime.h and el_seed.h; we do NOT + * redefine them here. We rely on one of those headers being included first. */ + +static inline el_val_t float_div(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub, ur; + ua.i = a; ub.i = b; + ur.d = (ub.d != 0.0) ? (ua.d / ub.d) : 0.0; + return ur.i; +} + +static inline el_val_t float_mul(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub, ur; + ua.i = a; ub.i = b; ur.d = ua.d * ub.d; + return ur.i; +} + +static inline el_val_t float_add(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub, ur; + ua.i = a; ub.i = b; ur.d = ua.d + ub.d; + return ur.i; +} + +static inline el_val_t float_sub(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub, ur; + ua.i = a; ub.i = b; ur.d = ua.d - ub.d; + return ur.i; +} + +static inline el_val_t float_lt(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d < ub.d); +} + +static inline el_val_t float_gt(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d > ub.d); +} + +static inline el_val_t float_lte(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d <= ub.d); +} + +static inline el_val_t float_gte(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d >= ub.d); +} + +static inline el_val_t float_eq(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d == ub.d); +} + +#endif /* EL_FLOAT_OPS_DEFINED */ + +/* ── Native widget system (macOS AppKit) ──────────────────────────────────── + * Available when compiled with -DEL_TARGET_MACOS and linked with el_appkit.m. + * Widget handles are opaque int64_t slot indices; -1 = invalid. */ + +#ifdef EL_TARGET_MACOS + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_MACOS */ + +/* ── Native widget system (Linux GTK4) ────────────────────────────────────── + * Available when compiled with -DEL_TARGET_LINUX and linked with el_gtk4.c. + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * All functions have the same signatures as EL_TARGET_MACOS above. */ + +#ifdef EL_TARGET_LINUX + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader — same JSON output as EL_TARGET_MACOS */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_LINUX */ + +/* ── Native widget system (Windows Win32) ─────────────────────────────────── + * Available when compiled with -DEL_TARGET_WIN32 and linked with el_win32.c. + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * Link: el_win32.obj comctl32.lib user32.lib gdi32.lib */ + +#ifdef EL_TARGET_WIN32 + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_WIN32 */ + +/* ── Native widget system (iOS UIKit) ─────────────────────────────────────── + * Available when compiled with -DEL_TARGET_IOS and linked with el_uikit.m. + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * + * iOS lifecycle note: UIApplicationMain never returns. The el program must + * store its UI-build logic in a void(*)(void) function pointer, assign it to + * el_main_entry_fn, then call __native_run_loop. ElAppDelegate invokes + * el_main_entry_fn inside didFinishLaunchingWithOptions. + * Call el_uikit_set_args(argc, argv) from main() before __native_run_loop. */ + +#ifdef EL_TARGET_IOS + +/* Lifecycle entry-function hook — set before calling __native_run_loop. */ +extern void (*el_main_entry_fn)(void); + +/* Forward argc/argv from main() to UIApplicationMain. */ +void el_uikit_set_args(int argc, char** argv); + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_IOS */ + +/* ── Native widget system (Android JNI) ───────────────────────────────────── + * Available when compiled with -DEL_TARGET_ANDROID and linked with + * libelruntime.so (which includes el_android.c compiled by the NDK build). + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * + * Java companion: ElBridge.java (package com.neuron.el) must be compiled into + * the APK. The Activity must call ElBridge.init(this) before any widget ops. + * + * Link flags (in Android.mk or CMakeLists.txt): + * -landroid -llog -ldl */ + +#ifdef EL_TARGET_ANDROID + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); /* no-op on Android */ + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_ANDROID */ + +/* ── Native widget system (LVGL v9 — embedded / microcontroller) ───────────── + * Available when compiled with -DEL_TARGET_LVGL and linked with el_lvgl.c + * and the LVGL library (lvgl.a or lvgl source tree). + * + * Target platforms: ESP32, STM32, industrial panels. Any system with 256KB+ + * RAM and an LVGL-compatible display driver. No OS required. + * + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * + * Bare-metal / no dynamic linker: + * Compile with -DEL_LVGL_NO_DLSYM and provide: + * el_val_t el_lvgl_dispatch(const char *fn, el_val_t a, el_val_t b); + * + * Compile: + * gcc -DEL_TARGET_LVGL -I./lvgl el_lvgl.c -c -o el_lvgl.o + * # Then link with lvgl.a. */ + +#ifdef EL_TARGET_LVGL + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader — same JSON output as all other native targets */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_LVGL */ + +/* ── Native widget system (SDL2 — embedded / Pi) ──────────────────────────── + * Available when compiled with -DEL_TARGET_SDL2 and linked with el_sdl2.c. + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * + * Target: Raspberry Pi Zero, embedded Linux, any system with a framebuffer + * and SDL2 available. No GTK, no desktop environment required. + * + * Compile: + * gcc -DEL_TARGET_SDL2 $(sdl2-config --cflags) -c el_sdl2.c -o el_sdl2.o + * Link: + * $(sdl2-config --libs) -lSDL2_ttf -lSDL2_image -ldl */ + +#ifdef EL_TARGET_SDL2 + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_SDL2 */ diff --git a/ui/examples/native-hello-android/app/src/main/jni/el_native_vessel.c b/ui/examples/native-hello-android/app/src/main/jni/el_native_vessel.c new file mode 100644 index 0000000..0682965 --- /dev/null +++ b/ui/examples/native-hello-android/app/src/main/jni/el_native_vessel.c @@ -0,0 +1,459 @@ +#include +#include +#include "el_runtime.h" + +el_val_t native_init(void); +el_val_t native_run_loop(void); +el_val_t manifest_read(el_val_t path); +el_val_t manifest_title(el_val_t m); +el_val_t manifest_width(el_val_t m); +el_val_t manifest_height(el_val_t m); +el_val_t manifest_min_width(el_val_t m); +el_val_t manifest_min_height(el_val_t m); +el_val_t window_create(el_val_t title, el_val_t width, el_val_t height, el_val_t min_width, el_val_t min_height); +el_val_t window_from_manifest(el_val_t manifest_path); +el_val_t window_show(el_val_t handle); +el_val_t window_set_title(el_val_t handle, el_val_t title); +el_val_t vstack(el_val_t spacing); +el_val_t vstack_tight(void); +el_val_t hstack(el_val_t spacing); +el_val_t zstack(void); +el_val_t scroll(void); +el_val_t label(el_val_t text); +el_val_t button(el_val_t label); +el_val_t text_field(el_val_t placeholder); +el_val_t text_area(el_val_t placeholder); +el_val_t image(el_val_t path_or_name); +el_val_t widget_set_text(el_val_t handle, el_val_t text); +el_val_t widget_get_text(el_val_t handle); +el_val_t widget_set_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_font(el_val_t handle, el_val_t family, el_val_t size, el_val_t bold); +el_val_t widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, el_val_t bottom, el_val_t left); +el_val_t widget_set_padding_all(el_val_t handle, el_val_t p); +el_val_t widget_set_padding_xy(el_val_t handle, el_val_t px, el_val_t py); +el_val_t widget_set_width(el_val_t handle, el_val_t width); +el_val_t widget_set_height(el_val_t handle, el_val_t height); +el_val_t widget_set_flex(el_val_t handle, el_val_t flex); +el_val_t widget_set_corner_radius(el_val_t handle, el_val_t radius); +el_val_t widget_set_disabled(el_val_t handle, el_val_t disabled); +el_val_t widget_set_hidden(el_val_t handle, el_val_t hidden); +el_val_t widget_add_child(el_val_t parent, el_val_t child); +el_val_t widget_remove_child(el_val_t parent, el_val_t child); +el_val_t widget_destroy(el_val_t handle); +el_val_t widget_on_click(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_change(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_submit(el_val_t handle, el_val_t fn_name); +el_val_t hex_channel(el_val_t s, el_val_t offset); +el_val_t hex_nibble(el_val_t c); +el_val_t color_hex_r(el_val_t hex); +el_val_t color_hex_g(el_val_t hex); +el_val_t color_hex_b(el_val_t hex); +el_val_t color_hex_a(el_val_t hex); +el_val_t widget_set_color_hex(el_val_t handle, el_val_t hex); +el_val_t widget_set_bg_color_hex(el_val_t handle, el_val_t hex); +el_val_t style_surface(el_val_t handle); +el_val_t style_button_primary(el_val_t handle); +el_val_t style_label_body(el_val_t handle); +el_val_t style_label_heading(el_val_t handle); +el_val_t style_label_muted(el_val_t handle); + +el_val_t TOKEN_PRIMARY; +el_val_t TOKEN_ON_PRIMARY; +el_val_t TOKEN_BACKGROUND; +el_val_t TOKEN_ON_BG; +el_val_t TOKEN_SURFACE; +el_val_t TOKEN_ON_SURFACE; +el_val_t TOKEN_OUTLINE; +el_val_t TOKEN_ERROR; + +el_val_t native_init(void) { + __native_init(); + return 0; +} + +el_val_t native_run_loop(void) { + __native_run_loop(); + return 0; +} + +el_val_t manifest_read(el_val_t path) { + return __manifest_read(path); + return 0; +} + +el_val_t manifest_title(el_val_t m) { + return json_get_string(m, EL_STR("title")); + return 0; +} + +el_val_t manifest_width(el_val_t m) { + return json_get_int(m, EL_STR("width")); + return 0; +} + +el_val_t manifest_height(el_val_t m) { + return json_get_int(m, EL_STR("height")); + return 0; +} + +el_val_t manifest_min_width(el_val_t m) { + return json_get_int(m, EL_STR("min_width")); + return 0; +} + +el_val_t manifest_min_height(el_val_t m) { + return json_get_int(m, EL_STR("min_height")); + return 0; +} + +el_val_t window_create(el_val_t title, el_val_t width, el_val_t height, el_val_t min_width, el_val_t min_height) { + return __window_create(title, width, height, min_width, min_height); + return 0; +} + +el_val_t window_from_manifest(el_val_t manifest_path) { + el_val_t m = manifest_read(manifest_path); + el_val_t title = manifest_title(m); + el_val_t w = manifest_width(m); + el_val_t h = manifest_height(m); + el_val_t mw = manifest_min_width(m); + el_val_t mh = manifest_min_height(m); + el_val_t safe_w = ({ el_val_t _if_result_1 = 0; if ((w > 0)) { _if_result_1 = (w); } else { _if_result_1 = (1200); } _if_result_1; }); + el_val_t safe_h = ({ el_val_t _if_result_2 = 0; if ((h > 0)) { _if_result_2 = (h); } else { _if_result_2 = (800); } _if_result_2; }); + el_val_t safe_mw = ({ el_val_t _if_result_3 = 0; if ((mw > 0)) { _if_result_3 = (mw); } else { _if_result_3 = (600); } _if_result_3; }); + el_val_t safe_mh = ({ el_val_t _if_result_4 = 0; if ((mh > 0)) { _if_result_4 = (mh); } else { _if_result_4 = (400); } _if_result_4; }); + el_val_t safe_t = ({ el_val_t _if_result_5 = 0; if ((str_len(title) > 0)) { _if_result_5 = (title); } else { _if_result_5 = (EL_STR("App")); } _if_result_5; }); + return window_create(safe_t, safe_w, safe_h, safe_mw, safe_mh); + return 0; +} + +el_val_t window_show(el_val_t handle) { + __window_show(handle); + return 0; +} + +el_val_t window_set_title(el_val_t handle, el_val_t title) { + __window_set_title(handle, title); + return 0; +} + +el_val_t vstack(el_val_t spacing) { + return __vstack_create(spacing); + return 0; +} + +el_val_t vstack_tight(void) { + return __vstack_create(0); + return 0; +} + +el_val_t hstack(el_val_t spacing) { + return __hstack_create(spacing); + return 0; +} + +el_val_t zstack(void) { + return __zstack_create(); + return 0; +} + +el_val_t scroll(void) { + return __scroll_create(); + return 0; +} + +el_val_t label(el_val_t text) { + return __label_create(text); + return 0; +} + +el_val_t button(el_val_t label) { + return __button_create(label); + return 0; +} + +el_val_t text_field(el_val_t placeholder) { + return __text_field_create(placeholder); + return 0; +} + +el_val_t text_area(el_val_t placeholder) { + return __text_area_create(placeholder); + return 0; +} + +el_val_t image(el_val_t path_or_name) { + return __image_create(path_or_name); + return 0; +} + +el_val_t widget_set_text(el_val_t handle, el_val_t text) { + __widget_set_text(handle, text); + return 0; +} + +el_val_t widget_get_text(el_val_t handle) { + return __widget_get_text(handle); + return 0; +} + +el_val_t widget_set_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + __widget_set_color(handle, r, g, b, a); + return 0; +} + +el_val_t widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + __widget_set_bg_color(handle, r, g, b, a); + return 0; +} + +el_val_t widget_set_font(el_val_t handle, el_val_t family, el_val_t size, el_val_t bold) { + el_val_t bold_int = ({ el_val_t _if_result_6 = 0; if (bold) { _if_result_6 = (1); } else { _if_result_6 = (0); } _if_result_6; }); + __widget_set_font(handle, family, size, bold_int); + return 0; +} + +el_val_t widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, el_val_t bottom, el_val_t left) { + __widget_set_padding(handle, top, right, bottom, left); + return 0; +} + +el_val_t widget_set_padding_all(el_val_t handle, el_val_t p) { + __widget_set_padding(handle, p, p, p, p); + return 0; +} + +el_val_t widget_set_padding_xy(el_val_t handle, el_val_t px, el_val_t py) { + __widget_set_padding(handle, py, px, py, px); + return 0; +} + +el_val_t widget_set_width(el_val_t handle, el_val_t width) { + __widget_set_width(handle, width); + return 0; +} + +el_val_t widget_set_height(el_val_t handle, el_val_t height) { + __widget_set_height(handle, height); + return 0; +} + +el_val_t widget_set_flex(el_val_t handle, el_val_t flex) { + __widget_set_flex(handle, flex); + return 0; +} + +el_val_t widget_set_corner_radius(el_val_t handle, el_val_t radius) { + __widget_set_corner_radius(handle, radius); + return 0; +} + +el_val_t widget_set_disabled(el_val_t handle, el_val_t disabled) { + el_val_t d = ({ el_val_t _if_result_7 = 0; if (disabled) { _if_result_7 = (1); } else { _if_result_7 = (0); } _if_result_7; }); + __widget_set_disabled(handle, d); + return 0; +} + +el_val_t widget_set_hidden(el_val_t handle, el_val_t hidden) { + el_val_t h = ({ el_val_t _if_result_8 = 0; if (hidden) { _if_result_8 = (1); } else { _if_result_8 = (0); } _if_result_8; }); + __widget_set_hidden(handle, h); + return 0; +} + +el_val_t widget_add_child(el_val_t parent, el_val_t child) { + __widget_add_child(parent, child); + return 0; +} + +el_val_t widget_remove_child(el_val_t parent, el_val_t child) { + __widget_remove_child(parent, child); + return 0; +} + +el_val_t widget_destroy(el_val_t handle) { + __widget_destroy(handle); + return 0; +} + +el_val_t widget_on_click(el_val_t handle, el_val_t fn_name) { + __widget_on_click(handle, fn_name); + return 0; +} + +el_val_t widget_on_change(el_val_t handle, el_val_t fn_name) { + __widget_on_change(handle, fn_name); + return 0; +} + +el_val_t widget_on_submit(el_val_t handle, el_val_t fn_name) { + __widget_on_submit(handle, fn_name); + return 0; +} + +el_val_t hex_channel(el_val_t s, el_val_t offset) { + el_val_t hi = str_slice(s, offset, (offset + 1)); + el_val_t lo = str_slice(s, (offset + 1), (offset + 2)); + el_val_t h = hex_nibble(hi); + el_val_t l = hex_nibble(lo); + return ((h * 16) + l); + return 0; +} + +el_val_t hex_nibble(el_val_t c) { + if (str_eq(c, EL_STR("0"))) { + return 0; + } + if (str_eq(c, EL_STR("1"))) { + return 1; + } + if (str_eq(c, EL_STR("2"))) { + return 2; + } + if (str_eq(c, EL_STR("3"))) { + return 3; + } + if (str_eq(c, EL_STR("4"))) { + return 4; + } + if (str_eq(c, EL_STR("5"))) { + return 5; + } + if (str_eq(c, EL_STR("6"))) { + return 6; + } + if (str_eq(c, EL_STR("7"))) { + return 7; + } + if (str_eq(c, EL_STR("8"))) { + return 8; + } + if (str_eq(c, EL_STR("9"))) { + return 9; + } + if (str_eq(c, EL_STR("a"))) { + return 10; + } + if (str_eq(c, EL_STR("b"))) { + return 11; + } + if (str_eq(c, EL_STR("c"))) { + return 12; + } + if (str_eq(c, EL_STR("d"))) { + return 13; + } + if (str_eq(c, EL_STR("e"))) { + return 14; + } + if (str_eq(c, EL_STR("f"))) { + return 15; + } + if (str_eq(c, EL_STR("A"))) { + return 10; + } + if (str_eq(c, EL_STR("B"))) { + return 11; + } + if (str_eq(c, EL_STR("C"))) { + return 12; + } + if (str_eq(c, EL_STR("D"))) { + return 13; + } + if (str_eq(c, EL_STR("E"))) { + return 14; + } + if (str_eq(c, EL_STR("F"))) { + return 15; + } + return 0; + return 0; +} + +el_val_t color_hex_r(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_9 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_9 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_9 = (hex); } _if_result_9; }); + el_val_t v = hex_channel(s, 0); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_g(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_10 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_10 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_10 = (hex); } _if_result_10; }); + el_val_t v = hex_channel(s, 2); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_b(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_11 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_11 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_11 = (hex); } _if_result_11; }); + el_val_t v = hex_channel(s, 4); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_a(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_12 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_12 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_12 = (hex); } _if_result_12; }); + if (str_len(s) < 8) { + return el_from_float(1.0); + } + el_val_t v = hex_channel(s, 6); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t widget_set_color_hex(el_val_t handle, el_val_t hex) { + widget_set_color(handle, color_hex_r(hex), color_hex_g(hex), color_hex_b(hex), color_hex_a(hex)); + return 0; +} + +el_val_t widget_set_bg_color_hex(el_val_t handle, el_val_t hex) { + widget_set_bg_color(handle, color_hex_r(hex), color_hex_g(hex), color_hex_b(hex), color_hex_a(hex)); + return 0; +} + +el_val_t style_surface(el_val_t handle) { + widget_set_bg_color_hex(handle, TOKEN_SURFACE); + widget_set_corner_radius(handle, 8); + return 0; +} + +el_val_t style_button_primary(el_val_t handle) { + widget_set_bg_color_hex(handle, TOKEN_PRIMARY); + widget_set_color_hex(handle, TOKEN_ON_PRIMARY); + widget_set_corner_radius(handle, 8); + widget_set_padding_xy(handle, 16, 8); + return 0; +} + +el_val_t style_label_body(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_ON_BG); + widget_set_font(handle, EL_STR("system"), 14, 0); + return 0; +} + +el_val_t style_label_heading(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_ON_BG); + widget_set_font(handle, EL_STR("system"), 20, 1); + return 0; +} + +el_val_t style_label_muted(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_OUTLINE); + widget_set_font(handle, EL_STR("system"), 12, 0); + return 0; +} + +int el_vessel_main(int _argc, char** _argv) { + el_runtime_init_args(_argc, _argv); + TOKEN_PRIMARY = EL_STR("#60a5fa"); + TOKEN_ON_PRIMARY = EL_STR("#0f172a"); + TOKEN_BACKGROUND = EL_STR("#0f172a"); + TOKEN_ON_BG = EL_STR("#f8fafc"); + TOKEN_SURFACE = EL_STR("#1e293b"); + TOKEN_ON_SURFACE = EL_STR("#f8fafc"); + TOKEN_OUTLINE = EL_STR("#475569"); + TOKEN_ERROR = EL_STR("#f87171"); + return 0; +} + diff --git a/ui/examples/native-hello-android/app/src/main/jni/el_runtime.c b/ui/examples/native-hello-android/app/src/main/jni/el_runtime.c new file mode 100644 index 0000000..a735c9f --- /dev/null +++ b/ui/examples/native-hello-android/app/src/main/jni/el_runtime.c @@ -0,0 +1,11733 @@ +/* + * el_runtime.c — El language C runtime implementation + * + * All functions use el_val_t (= int64_t) as the universal value type. + * Strings are transported as their pointer address cast to int64_t. + * On any 64-bit system sizeof(pointer) <= sizeof(int64_t), so this is safe. + * + * Compile with: + * cc -std=c11 -I -lcurl -lpthread -o .c el_runtime.c + * + * Link requirements: -lcurl (HTTP client + LLM), -lpthread (HTTP server). + */ + +/* Feature-test macros must be set before any standard headers. _GNU_SOURCE + * exposes clock_gettime/CLOCK_REALTIME, strcasecmp, and the dlfcn extensions + * (RTLD_DEFAULT) — all of which macOS hands us without asking but glibc on + * Debian gates behind an explicit opt-in. */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "el_runtime.h" + +#include +#include /* strcasecmp */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* dlsym for http_set_handler fallback */ +#include +#include +#include +#include +#include +#include /* getrusage — memory guard */ +#ifdef HAVE_CURL +#include +#endif + +/* ── Internal allocators ─────────────────────────────────────────────────── */ + +/* + * Per-request string arena + * + * Every El string allocated via el_strbuf / el_strdup during an HTTP request + * is registered in a thread-local arena. When el_request_end() is called at + * the end of the worker thread, every arena entry is freed — recovering all + * the intermediate strings from el_str_concat chains (build_system_prompt, + * engram_compile, etc.) that are otherwise leaked forever. + * + * Long-lived allocations (state_set values, engram internal storage) call + * el_strdup_persist() / el_strbuf_persist() which bypass the arena entirely. + */ + +#define EL_ARENA_INITIAL 512 + +typedef struct { + char** ptrs; + size_t count; + size_t cap; +} ElArena; + +static _Thread_local ElArena _tl_arena = {NULL, 0, 0}; +static _Thread_local int _tl_arena_active = 0; + +/* Binary-safe fs_read length — set by fs_read, consumed by http_send_response. + * Allows serving PNGs and other binary files without strlen truncation. */ +static _Thread_local size_t _tl_fs_read_len = 0; + +static void el_arena_track(char* p) { + if (!_tl_arena_active || !p) return; + if (_tl_arena.count >= _tl_arena.cap) { + size_t nc = _tl_arena.cap == 0 ? EL_ARENA_INITIAL : _tl_arena.cap * 2; + char** grown = realloc(_tl_arena.ptrs, nc * sizeof(char*)); + if (!grown) return; /* can't track — will leak this one ptr, but don't crash */ + _tl_arena.ptrs = grown; + _tl_arena.cap = nc; + } + _tl_arena.ptrs[_tl_arena.count++] = p; +} + +/* Called by http_worker before dispatching the El handler. */ +void el_request_start(void) { + _tl_arena.count = 0; + _tl_arena_active = 1; +} + +/* Called by http_worker after the El handler returns and the response is sent. + * Frees every intermediate string allocated during the request. */ +void el_request_end(void) { + _tl_arena_active = 0; + for (size_t i = 0; i < _tl_arena.count; i++) { + free(_tl_arena.ptrs[i]); + } + _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(""); + return strdup(s); +} +static char* el_strbuf_persist(size_t n) { + char* p = malloc(n + 1); + if (!p) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + p[0] = '\0'; + return p; +} + +static char* el_strdup(const char* s) { + if (!s) { char* p = strdup(""); el_arena_track(p); return p; } + char* p = strdup(s); + el_arena_track(p); + return p; +} + +static char* el_strbuf(size_t n) { + char* p = malloc(n + 1); + if (!p) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + p[0] = '\0'; + el_arena_track(p); + return p; +} + +/* Wrap an allocated C string as el_val_t */ +static el_val_t el_wrap_str(char* s) { + return EL_STR(s); +} + +/* ── I/O ──────────────────────────────────────────────────────────────────── */ + +el_val_t println(el_val_t s) { + const char* str = EL_CSTR(s); + if (str) puts(str); + else puts(""); + return 0; +} + +el_val_t print(el_val_t s) { + const char* str = EL_CSTR(s); + if (str) fputs(str, stdout); + return 0; +} + +el_val_t readline(void) { + char buf[4096]; + if (!fgets(buf, sizeof(buf), stdin)) return el_wrap_str(el_strdup("")); + size_t len = strlen(buf); + if (len > 0 && buf[len - 1] == '\n') buf[len - 1] = '\0'; + return el_wrap_str(el_strdup(buf)); +} + +/* __read_n — read exactly n bytes from stdin. + * Allocates a buffer of size n+1, calls fread(buf, 1, n, stdin) to read + * exactly n raw bytes (including \r, \n, NUL, etc.), null-terminates, and + * returns the buffer as an El String. Returns "" on EOF or I/O error. + * + * Used by the El LSP server to read JSON-RPC message bodies after parsing + * the Content-Length header. readline() cannot be used for the body because + * it stops at the first \n and LSP JSON bodies are not newline-terminated. */ +el_val_t __read_n(el_val_t nv) { + int64_t n = EL_INT(nv); + if (n <= 0) return el_wrap_str(el_strdup("")); + char* buf = malloc((size_t)n + 1); + if (!buf) { fputs("el_runtime: __read_n: out of memory\n", stderr); return el_wrap_str(el_strdup("")); } + size_t got = fread(buf, 1, (size_t)n, stdin); + buf[got] = '\0'; + if (got == 0) { free(buf); return el_wrap_str(el_strdup("")); } + /* Track in arena so the allocation is freed when the request ends. */ + el_arena_track(buf); + return el_wrap_str(buf); +} + +/* __print_raw — write a string to stdout without any modification. + * Unlike println/print (which call puts/fputs and may add newlines or flush + * in platform-specific ways), this uses fwrite with the exact byte count so + * that embedded \r\n pairs in LSP Content-Length headers survive intact. */ +void __print_raw(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return; + size_t len = strlen(s); + fwrite(s, 1, len, stdout); + fflush(stdout); +} + +/* ── String builtins ─────────────────────────────────────────────────────── */ + +el_val_t el_str_concat(el_val_t av, el_val_t bv) { + const char* a = EL_CSTR(av); + const char* b = EL_CSTR(bv); + if (!a) a = ""; + if (!b) b = ""; + size_t la = strlen(a); + size_t lb = strlen(b); + char* out = el_strbuf(la + lb); + memcpy(out, a, la); + memcpy(out + la, b, lb); + out[la + lb] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_eq(el_val_t av, el_val_t bv) { + const char* a = EL_CSTR(av); + const char* b = EL_CSTR(bv); + if (!a || !b) return (el_val_t)(a == b); + return (el_val_t)(strcmp(a, b) == 0); +} + +el_val_t str_starts_with(el_val_t sv, el_val_t prefv) { + const char* s = EL_CSTR(sv); + const char* prefix = EL_CSTR(prefv); + if (!s || !prefix) return 0; + size_t lp = strlen(prefix); + return (el_val_t)(strncmp(s, prefix, lp) == 0); +} + +el_val_t str_ends_with(el_val_t sv, el_val_t sufv) { + const char* s = EL_CSTR(sv); + const char* suffix = EL_CSTR(sufv); + if (!s || !suffix) return 0; + size_t ls = strlen(s); + size_t lsuf = strlen(suffix); + if (lsuf > ls) return 0; + return (el_val_t)(strcmp(s + ls - lsuf, suffix) == 0); +} + +el_val_t str_len(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + return (el_val_t)strlen(s); +} + +el_val_t str_concat(el_val_t a, el_val_t b) { + return el_str_concat(a, b); +} + +el_val_t int_to_str(el_val_t n) { + char buf[32]; + snprintf(buf, sizeof(buf), "%lld", (long long)n); + return el_wrap_str(el_strdup(buf)); +} + +el_val_t str_to_int(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + return (el_val_t)atoll(s); +} + +/* native_str_to_int — El compiler-generated alias for str_to_int. + * Converts a string el_val_t to its integer representation. */ +el_val_t native_str_to_int(el_val_t sv) { return str_to_int(sv); } + +el_val_t str_slice(el_val_t sv, el_val_t start, el_val_t end) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + int64_t len = (int64_t)strlen(s); + if (start < 0) start = 0; + if (end > len) end = len; + if (start >= end) return el_wrap_str(el_strdup("")); + int64_t sz = end - start; + char* out = el_strbuf((size_t)sz); + memcpy(out, s + start, (size_t)sz); + out[sz] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_contains(el_val_t sv, el_val_t subv) { + const char* s = EL_CSTR(sv); + const char* sub = EL_CSTR(subv); + if (!s || !sub) return 0; + return (el_val_t)(strstr(s, sub) != NULL); +} + +el_val_t str_replace(el_val_t sv, el_val_t fromv, el_val_t tov) { + const char* s = EL_CSTR(sv); + const char* from = EL_CSTR(fromv); + const char* to = EL_CSTR(tov); + if (!s || !from || !to) return el_wrap_str(el_strdup(s ? s : "")); + size_t ls = strlen(s); + size_t lf = strlen(from); + size_t lt = strlen(to); + if (lf == 0) return el_wrap_str(el_strdup(s)); + size_t count = 0; + const char* p = s; + while ((p = strstr(p, from)) != NULL) { count++; p += lf; } + size_t out_sz = ls + count * lt + 1; + char* out = el_strbuf(out_sz); + char* dst = out; + p = s; + const char* found; + while ((found = strstr(p, from)) != NULL) { + size_t chunk = (size_t)(found - p); + memcpy(dst, p, chunk); dst += chunk; + memcpy(dst, to, lt); dst += lt; + p = found + lf; + } + strcpy(dst, p); + return el_wrap_str(out); +} + +el_val_t str_to_upper(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + char* out = el_strbuf(n); + for (size_t i = 0; i < n; i++) out[i] = (char)toupper((unsigned char)s[i]); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_to_lower(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + char* out = el_strbuf(n); + for (size_t i = 0; i < n; i++) out[i] = (char)tolower((unsigned char)s[i]); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_trim(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + while (*s && isspace((unsigned char)*s)) s++; + size_t n = strlen(s); + while (n > 0 && isspace((unsigned char)s[n - 1])) n--; + char* out = el_strbuf(n); + memcpy(out, s, n); + out[n] = '\0'; + return el_wrap_str(out); +} + +/* ── Math ────────────────────────────────────────────────────────────────── */ + +el_val_t el_abs(el_val_t n) { return n < 0 ? -n : n; } +el_val_t el_max(el_val_t a, el_val_t b) { return a > b ? a : b; } +el_val_t el_min(el_val_t a, el_val_t b) { return a < b ? a : b; } + +/* ── Refcounted heap objects ────────────────────────────────────────────────── + * + * ElList and ElMap carry a magic-tagged header at offset 0: + * { uint32_t magic; uint32_t refcount; ... payload ... } + * + * The magic tag distinguishes refcounted objects from raw C strings (whose + * first byte is printable ASCII < 0x80) and from small integers (which can't + * be dereferenced). el_retain / el_release sniff the magic and act only on + * matching values; everything else is a safe no-op. + * + * Both ElList and ElMap use INDIRECTION: the header is fixed-size and never + * moves. The payload arrays (elems, keys, values) live in separate heap + * allocations, so realloc-grow on append never invalidates the caller's + * pointer to the header. This is what lets us mutate-in-place safely when + * the refcount is 1 and copy-on-write when it's higher. + * + * Memory model in practice: + * Single-owner accumulator (the cg_stmts pattern) — refcount stays at 1, + * appends amortize to O(1), total memory O(N) for an N-element list. + * Multi-owner branching (the cg_if_stmt pattern) — refcount > 1, each + * append on a shared list copies, so the original is preserved for the + * else-branch. Persistent semantics where they're needed; mutation where + * they're not. */ + +#define EL_MAGIC_LIST 0xE15710A1u /* >= 0x80 in MSB so 'looks_like_string' rejects */ +#define EL_MAGIC_MAP 0xE19A704Bu + +typedef struct { + uint32_t magic; + uint32_t refcount; +} ElHeader; + +/* ── List ────────────────────────────────────────────────────────────────── */ + +typedef struct { + ElHeader hdr; + int64_t length; + int64_t capacity; + el_val_t* elems; +} ElList; + +static ElList* list_alloc(int64_t cap) { + if (cap < 4) cap = 4; + ElList* lst = malloc(sizeof(ElList)); + if (!lst) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + lst->hdr.magic = EL_MAGIC_LIST; + lst->hdr.refcount = 1; + lst->length = 0; + lst->capacity = cap; + lst->elems = malloc((size_t)cap * sizeof(el_val_t)); + if (!lst->elems) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + return lst; +} + +el_val_t el_list_empty(void) { + return EL_STR(list_alloc(4)); +} + +el_val_t el_list_new(el_val_t count, ...) { + ElList* lst = list_alloc(count > 0 ? count : 4); + va_list ap; + va_start(ap, count); + for (int64_t i = 0; i < count; i++) { + lst->elems[i] = va_arg(ap, el_val_t); + } + va_end(ap); + lst->length = count; + return EL_STR(lst); +} + +el_val_t el_list_len(el_val_t listv) { + ElList* lst = (ElList*)(uintptr_t)listv; + if (!lst) return 0; + return lst->length; +} + +el_val_t el_list_get(el_val_t listv, el_val_t index) { + ElList* lst = (ElList*)(uintptr_t)listv; + if (!lst) return 0; + if (index < 0 || index >= lst->length) return 0; + return lst->elems[index]; +} + +el_val_t el_list_append(el_val_t listv, el_val_t elem) { + ElList* old = (ElList*)(uintptr_t)listv; + if (!old) { + ElList* fresh = list_alloc(4); + fresh->elems[0] = elem; + fresh->length = 1; + return EL_STR(fresh); + } + + /* Uniquely owned: grow the elems buffer in place. The header pointer the + * caller holds doesn't move (we only realloc the inner array). This is + * the common case in compiler accumulators, and it's amortized O(1). */ + if (old->hdr.refcount <= 1) { + if (old->length >= old->capacity) { + int64_t new_cap = old->capacity > 0 ? old->capacity * 2 : 4; + el_val_t* grown = realloc(old->elems, (size_t)new_cap * sizeof(el_val_t)); + if (!grown) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + old->elems = grown; + old->capacity = new_cap; + } + old->elems[old->length++] = elem; + return listv; + } + + /* Shared: copy-on-write. The original is preserved for its other owners. */ + int64_t new_cap = old->length + 1; + if (new_cap < 4) new_cap = 4; + ElList* fresh = malloc(sizeof(ElList)); + if (!fresh) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + fresh->hdr.magic = EL_MAGIC_LIST; + fresh->hdr.refcount = 1; + fresh->length = old->length + 1; + fresh->capacity = new_cap; + fresh->elems = malloc((size_t)new_cap * sizeof(el_val_t)); + if (!fresh->elems) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + if (old->length > 0) { + memcpy(fresh->elems, old->elems, (size_t)old->length * sizeof(el_val_t)); + } + fresh->elems[old->length] = elem; + return EL_STR(fresh); +} + +el_val_t el_list_clone(el_val_t listv) { + /* Shallow copy: the new ElList owns its own header and elems buffer, but + * the elements themselves are shared (which is what callers want for the + * cg_if_stmt 'declared' pattern — cloning the spine, not its contents). + * Used by codegen at scope branch points where two child scopes need to + * see the same starting set of declared names without each other's + * mutations. */ + ElList* old = (ElList*)(uintptr_t)listv; + if (!old) return el_list_empty(); + int64_t cap = old->capacity > 0 ? old->capacity : 4; + if (cap < old->length) cap = old->length; + if (cap < 4) cap = 4; + ElList* fresh = malloc(sizeof(ElList)); + if (!fresh) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + fresh->hdr.magic = EL_MAGIC_LIST; + fresh->hdr.refcount = 1; + fresh->length = old->length; + fresh->capacity = cap; + fresh->elems = malloc((size_t)cap * sizeof(el_val_t)); + if (!fresh->elems) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + if (old->length > 0) { + memcpy(fresh->elems, old->elems, (size_t)old->length * sizeof(el_val_t)); + } + return EL_STR(fresh); +} + +/* ── Map ─────────────────────────────────────────────────────────────────── */ + +typedef struct { + ElHeader hdr; + int64_t count; + int64_t capacity; + el_val_t* keys; + el_val_t* values; +} ElMap; + +static ElMap* map_alloc(int64_t cap) { + if (cap < 4) cap = 4; + ElMap* m = malloc(sizeof(ElMap)); + if (!m) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + m->hdr.magic = EL_MAGIC_MAP; + m->hdr.refcount = 1; + m->count = 0; + m->capacity = cap; + m->keys = malloc((size_t)cap * sizeof(el_val_t)); + m->values = malloc((size_t)cap * sizeof(el_val_t)); + if (!m->keys || !m->values) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + return m; +} + +el_val_t el_map_new(el_val_t pair_count, ...) { + ElMap* m = map_alloc(pair_count > 0 ? pair_count : 4); + va_list ap; + va_start(ap, pair_count); + for (int64_t i = 0; i < pair_count; i++) { + m->keys[i] = va_arg(ap, el_val_t); + m->values[i] = va_arg(ap, el_val_t); + } + va_end(ap); + m->count = pair_count; + return EL_STR(m); +} + +static ElMap* as_map(el_val_t v) { return (ElMap*)(uintptr_t)v; } + +el_val_t el_map_get(el_val_t mapv, el_val_t keyv) { + ElMap* m = as_map(mapv); + const char* key = EL_CSTR(keyv); + if (!m || !key) return 0; + for (int64_t i = 0; i < m->count; i++) { + const char* k = EL_CSTR(m->keys[i]); + if (k && strcmp(k, key) == 0) return m->values[i]; + } + return 0; +} + +el_val_t el_get_field(el_val_t mapv, el_val_t keyv) { + return el_map_get(mapv, keyv); +} + +/* Internal: in-place set on a uniquely-owned map. */ +static el_val_t map_set_in_place(ElMap* m, el_val_t keyv, el_val_t value) { + const char* key = EL_CSTR(keyv); + if (key) { + for (int64_t i = 0; i < m->count; i++) { + const char* k = EL_CSTR(m->keys[i]); + if (k && strcmp(k, key) == 0) { m->values[i] = value; return EL_STR(m); } + } + } + if (m->count >= m->capacity) { + int64_t new_cap = m->capacity > 0 ? m->capacity * 2 : 4; + el_val_t* gk = realloc(m->keys, (size_t)new_cap * sizeof(el_val_t)); + el_val_t* gv = realloc(m->values, (size_t)new_cap * sizeof(el_val_t)); + if (!gk || !gv) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + m->keys = gk; + m->values = gv; + m->capacity = new_cap; + } + m->keys[m->count] = keyv; + m->values[m->count] = value; + m->count++; + return EL_STR(m); +} + +el_val_t el_map_set(el_val_t mapv, el_val_t keyv, el_val_t value) { + ElMap* m = as_map(mapv); + if (!m) return 0; + if (m->hdr.refcount <= 1) { + return map_set_in_place(m, keyv, value); + } + /* Shared: copy then set. The original is preserved for its other owners. */ + int64_t new_cap = m->count + 1; + if (new_cap < 4) new_cap = 4; + ElMap* fresh = malloc(sizeof(ElMap)); + if (!fresh) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + fresh->hdr.magic = EL_MAGIC_MAP; + fresh->hdr.refcount = 1; + fresh->count = m->count; + fresh->capacity = new_cap; + fresh->keys = malloc((size_t)new_cap * sizeof(el_val_t)); + fresh->values = malloc((size_t)new_cap * sizeof(el_val_t)); + if (!fresh->keys || !fresh->values) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + if (m->count > 0) { + memcpy(fresh->keys, m->keys, (size_t)m->count * sizeof(el_val_t)); + memcpy(fresh->values, m->values, (size_t)m->count * sizeof(el_val_t)); + } + return map_set_in_place(fresh, keyv, value); +} + +/* ── Refcount ops ─────────────────────────────────────────────────────────── */ +/* + * Both retain and release sniff the magic header to decide whether a value + * is a refcounted heap object. For small integers, raw C strings, and any + * value whose magic word doesn't match, both functions are no-ops. This lets + * codegen emit them on every let-binding without having to track types. + * + * Safety: we filter out obvious non-pointers (small magnitudes, misaligned + * addresses) before dereferencing. For any value that passes the filter and + * lives in a mapped page, reading the first 4 bytes is safe — strings start + * with printable ASCII (< 0x80), so their magic word will never collide with + * EL_MAGIC_LIST (0xE1...) or EL_MAGIC_MAP (0xE1...). Random integers that + * happen to look like aligned heap pointers are exceedingly unlikely to land + * on a page whose first 4 bytes match either magic. */ + +static int looks_like_heap_obj(el_val_t v) { + if (v == 0) return 0; + int64_t s = (int64_t)v; + if (s > -0x10000 && s < 0x10000) return 0; /* small ints */ + uintptr_t p = (uintptr_t)v; + if (p < 0x10000) return 0; /* low addresses */ + if (p & 0x7) return 0; /* malloc returns 8-aligned */ + return 1; +} + +void el_retain(el_val_t v) { + if (!looks_like_heap_obj(v)) return; + ElHeader* h = (ElHeader*)(uintptr_t)v; + if (h->magic == EL_MAGIC_LIST || h->magic == EL_MAGIC_MAP) { + h->refcount++; + } +} + +void el_release(el_val_t v) { + if (!looks_like_heap_obj(v)) return; + ElHeader* h = (ElHeader*)(uintptr_t)v; + if (h->magic == EL_MAGIC_LIST) { + if (h->refcount > 0 && --h->refcount == 0) { + ElList* l = (ElList*)h; + free(l->elems); + l->hdr.magic = 0; /* poison so use-after-free is detected */ + free(l); + } + } else if (h->magic == EL_MAGIC_MAP) { + if (h->refcount > 0 && --h->refcount == 0) { + ElMap* m = (ElMap*)h; + free(m->keys); + free(m->values); + m->hdr.magic = 0; + free(m); + } + } +} + +/* ── Batch 2/3 forward decls (defined later in JSON section) ────────────── */ + +typedef struct JsonBuf JsonBuf; +typedef struct JsonParser JsonParser; +static void jb_init(JsonBuf* b); +static void jb_putc(JsonBuf* b, char c); +static void jb_puts(JsonBuf* b, const char* s); +static void jb_emit_escaped(JsonBuf* b, const char* s); +static int looks_like_string(el_val_t v); +static const char* json_find_key(const char* s, const char* key); +static const char* json_skip_value(const char* p); +static char* jp_parse_string_raw(JsonParser* jp); + +/* Struct definitions are visible here because batch 2/3 helpers above use + * them by value; the bodies (jb_init, etc.) appear in the JSON section. */ +struct JsonBuf { + char* buf; + size_t len; + size_t cap; +}; + +struct JsonParser { + const char* p; + const char* end; + int err; +}; + +/* ── Batch 2: Real HTTP (libcurl client + POSIX-socket server) ───────────── */ +/* + * Client: blocking libcurl easy-handle calls. Errors are returned as a JSON + * fragment {"error":"..."} so callers can detect via str_starts_with("{") / + * json_get_string("error", ...). + * + * Server: bind/listen/accept loop on a TCP socket. Each accepted connection + * is handled in its own pthread (detached). A semaphore-style counter caps + * concurrent in-flight connections at HTTP_MAX_CONNS (64). When the cap is + * reached, accept() blocks until a worker exits. This prevents runaway + * thread creation under high load. + * + * Handler dispatch: El does not expose first-class function references at + * the runtime layer, so the second argument to http_serve(port, handler) is + * treated as a string name (or any el_val_t — the runtime ignores its + * value and uses the registry). Callers register a C-level handler via + * + * extern void el_runtime_register_handler(const char* name, + * el_val_t (*fn)(el_val_t, + * el_val_t, + * el_val_t)); + * + * and select the active handler by calling http_set_handler("name") from + * El, or by setting it directly through the C registry. If no handler is + * registered, the server replies with a 200 carrying a default message so + * the loop is observable. + */ + +/* ── JSON error helper (used by HTTP, PQ, crypto stubs) ─────────────────── */ + +/* JSON-escape an arbitrary C string into an allocated buffer. */ +static char* json_escape_alloc(const char* s) { + if (!s) return el_strdup(""); + JsonBuf b; jb_init(&b); + for (const char* p = s; *p; p++) { + unsigned char c = (unsigned char)*p; + switch (c) { + case '"': jb_puts(&b, "\\\""); break; + case '\\': jb_puts(&b, "\\\\"); break; + case '\n': jb_puts(&b, "\\n"); break; + case '\r': jb_puts(&b, "\\r"); break; + case '\t': jb_puts(&b, "\\t"); break; + default: + if (c < 0x20) { + char tmp[8]; snprintf(tmp, sizeof(tmp), "\\u%04x", c); + jb_puts(&b, tmp); + } else jb_putc(&b, (char)c); + } + } + return b.buf; +} + +static el_val_t http_error_json(const char* msg) { + char* esc = json_escape_alloc(msg ? msg : "unknown error"); + char* buf = el_strbuf(strlen(esc) + 16); + sprintf(buf, "{\"error\":\"%s\"}", esc); + free(esc); + return el_wrap_str(buf); +} + +#ifdef HAVE_CURL +/* ── HTTP client write-callback buffer ───────────────────────────────────── */ + +typedef struct { + char* data; + size_t len; + size_t cap; +} HttpBuf; + +static void httpbuf_init(HttpBuf* b) { + b->cap = 1024; + b->len = 0; + b->data = malloc(b->cap); + if (!b->data) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + b->data[0] = '\0'; +} + +static void httpbuf_append(HttpBuf* b, const void* src, size_t n) { + if (b->len + n + 1 > b->cap) { + while (b->len + n + 1 > b->cap) b->cap *= 2; + b->data = realloc(b->data, b->cap); + if (!b->data) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + } + memcpy(b->data + b->len, src, n); + b->len += n; + b->data[b->len] = '\0'; +} + +static size_t http_write_cb(char* ptr, size_t size, size_t nmemb, void* ud) { + size_t n = size * nmemb; + httpbuf_append((HttpBuf*)ud, ptr, n); + return n; +} + +/* HTTP timeout (ms) — read once from EL_HTTP_TIMEOUT_MS, default 60000. + * Applied via CURLOPT_TIMEOUT_MS on every libcurl request. */ +static long _el_http_timeout_ms = -1; +static long el_http_timeout_ms(void) { + long v = __atomic_load_n(&_el_http_timeout_ms, __ATOMIC_ACQUIRE); + if (v >= 0) return v; + const char* s = getenv("EL_HTTP_TIMEOUT_MS"); + long parsed = 60000L; + if (s && *s) { + char* end = NULL; + long n = strtol(s, &end, 10); + if (end != s && n > 0) parsed = n; + } + __atomic_store_n(&_el_http_timeout_ms, parsed, __ATOMIC_RELEASE); + return parsed; +} + +/* Internal: do a libcurl request; takes optional body/headers, optional method override. */ +static el_val_t http_do(const char* method, const char* url, const char* body, + struct curl_slist* extra_headers) { + if (!url || !*url) return http_error_json("empty url"); + CURL* c = curl_easy_init(); + if (!c) return http_error_json("curl_easy_init failed"); + HttpBuf rb; httpbuf_init(&rb); + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, http_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, &rb); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, el_http_timeout_ms()); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-runtime/1.0"); + if (extra_headers) curl_easy_setopt(c, CURLOPT_HTTPHEADER, extra_headers); + if (method && strcmp(method, "POST") == 0) { + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, body ? body : ""); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(body ? strlen(body) : 0)); + } else if (method && strcmp(method, "DELETE") == 0) { + curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, "DELETE"); + } + CURLcode rc = curl_easy_perform(c); + curl_easy_cleanup(c); + if (rc != CURLE_OK) { + free(rb.data); + const char* m = errbuf[0] ? errbuf : curl_easy_strerror(rc); + return http_error_json(m); + } + return el_wrap_str(rb.data); +} + +el_val_t http_get(el_val_t url) { + return http_do("GET", EL_CSTR(url), NULL, NULL); +} + +el_val_t http_post(el_val_t url, el_val_t body) { + return http_do("POST", EL_CSTR(url), EL_CSTR(body), NULL); +} + +el_val_t http_post_json(el_val_t url, el_val_t json_body) { + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + el_val_t r = http_do("POST", EL_CSTR(url), EL_CSTR(json_body), h); + curl_slist_free_all(h); + return r; +} + +/* Build a curl_slist from an ElMap of name -> value strings. */ +static struct curl_slist* headers_from_map(el_val_t headers_map) { + struct curl_slist* h = NULL; + ElMap* m = as_map(headers_map); + if (!m) return NULL; + for (int64_t i = 0; i < m->count; i++) { + const char* k = EL_CSTR(m->keys[i]); + const char* v = EL_CSTR(m->values[i]); + if (!k || !v) continue; + size_t n = strlen(k) + strlen(v) + 4; + char* line = malloc(n); + if (!line) continue; + snprintf(line, n, "%s: %s", k, v); + h = curl_slist_append(h, line); + free(line); + } + return h; +} + +el_val_t http_get_with_headers(el_val_t url, el_val_t headers_map) { + struct curl_slist* h = headers_from_map(headers_map); + el_val_t r = http_do("GET", EL_CSTR(url), NULL, h); + if (h) curl_slist_free_all(h); + return r; +} + +el_val_t http_post_with_headers(el_val_t url, el_val_t body, el_val_t headers_map) { + struct curl_slist* h = headers_from_map(headers_map); + el_val_t r = http_do("POST", EL_CSTR(url), EL_CSTR(body), h); + if (h) curl_slist_free_all(h); + return r; +} + +/* http_post_json_with_headers — POST with Content-Type: application/json plus + * any additional headers supplied as an El map. Combines http_post_json and + * http_post_with_headers: the Content-Type header is always prepended so + * callers do not have to include it in their map. */ +el_val_t http_post_json_with_headers(el_val_t url, el_val_t headers_map, el_val_t json_body) { + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + /* Append caller-supplied headers from the map */ + ElMap* m = as_map(headers_map); + if (m) { + for (int64_t i = 0; i < m->count; i++) { + const char* k = EL_CSTR(m->keys[i]); + const char* v = EL_CSTR(m->values[i]); + if (!k || !v) continue; + size_t n = strlen(k) + strlen(v) + 4; + char* line = malloc(n); + if (!line) continue; + snprintf(line, n, "%s: %s", k, v); + h = curl_slist_append(h, line); + free(line); + } + } + el_val_t r = http_do("POST", EL_CSTR(url), EL_CSTR(json_body), h); + curl_slist_free_all(h); + return r; +} + +el_val_t http_post_form_auth(el_val_t url, el_val_t form_body, el_val_t auth_header) { + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/x-www-form-urlencoded"); + const char* a = EL_CSTR(auth_header); + if (a && *a) { + size_t n = strlen(a) + 32; + char* line = malloc(n); + snprintf(line, n, "Authorization: %s", a); + h = curl_slist_append(h, line); + free(line); + } + el_val_t r = http_do("POST", EL_CSTR(url), EL_CSTR(form_body), h); + curl_slist_free_all(h); + return r; +} + +/* HTTP DELETE — mirrors http_post but with CURLOPT_CUSTOMREQUEST=DELETE. + * Returns response body on success; on transport failure returns an error + * JSON fragment (same convention as http_get/http_post). Callers that + * expect "" on failure should check for a leading '{' and an "error" key. */ +el_val_t http_delete(el_val_t url) { + return http_do("DELETE", EL_CSTR(url), NULL, NULL); +} + +/* ── HTTP → file streaming ──────────────────────────────────────────────── + * + * Why this exists: el_val_t strings are NUL-terminated by convention, so + * accumulating an HTTP response into an httpbuf and then wrapping its + * `.data` pointer with el_wrap_str() loses the byte length. Any consumer + * that does strlen() on the wrapped pointer truncates the body at the + * first embedded NUL. Audio (MP3, WAV, OGG), images (PNG, JPEG), and any + * other binary payload hits this. The vessels that download such bodies + * (e.g. ElevenLabs TTS → MP3) get silently corrupted files. + * + * The fix: wire libcurl's CURLOPT_WRITEFUNCTION directly to fwrite() + * against a fopen()-ed FILE*. The bytes never pass through an el_val_t + * string, so embedded NULs are preserved verbatim. Caller's contract is + * just "a file at this path with the response body in it". */ + +static size_t http_file_write_cb(char* ptr, size_t size, size_t nmemb, void* ud) { + FILE* f = (FILE*)ud; + return fwrite(ptr, size, nmemb, f); +} + +/* Internal: stream body to file. method is "GET" or "POST". body may be NULL + * (GET) or NUL-terminated (POST). headers may be NULL. Returns 1/0. */ +static el_val_t http_do_to_file(const char* method, const char* url, + const char* body, struct curl_slist* extra_headers, + const char* output_path) { + if (!url || !*url) return 0; + if (!output_path || !*output_path) return 0; + FILE* f = fopen(output_path, "wb"); + if (!f) return 0; + + CURL* c = curl_easy_init(); + if (!c) { fclose(f); remove(output_path); return 0; } + + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, http_file_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, f); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, el_http_timeout_ms()); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-runtime/1.0"); + curl_easy_setopt(c, CURLOPT_FAILONERROR, 1L); /* 4xx/5xx → CURLE_HTTP_RETURNED_ERROR */ + if (extra_headers) curl_easy_setopt(c, CURLOPT_HTTPHEADER, extra_headers); + + if (method && strcmp(method, "POST") == 0) { + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, body ? body : ""); + /* For the request body we still rely on strlen — POST bodies are + * caller-controlled and JSON/text in every known El use case. + * If a future caller needs a binary POST body, add a *_bytes + * variant that takes an explicit length, mirroring fs_write_bytes. */ + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(body ? strlen(body) : 0)); + } + + CURLcode rc = curl_easy_perform(c); + curl_easy_cleanup(c); + + /* Flush + close before signalling success, so the file is fully on disk + * by the time the caller reads back. */ + int flush_ok = (fflush(f) == 0); + int close_ok = (fclose(f) == 0); + + if (rc != CURLE_OK || !flush_ok || !close_ok) { + remove(output_path); + return 0; + } + return 1; +} + +el_val_t http_get_to_file(el_val_t url, el_val_t headers_map, el_val_t output_path) { + struct curl_slist* h = headers_from_map(headers_map); + el_val_t r = http_do_to_file("GET", EL_CSTR(url), NULL, h, EL_CSTR(output_path)); + if (h) curl_slist_free_all(h); + return r; +} + +el_val_t http_post_to_file(el_val_t url, el_val_t body, el_val_t headers_map, el_val_t output_path) { + struct curl_slist* h = headers_from_map(headers_map); + el_val_t r = http_do_to_file("POST", EL_CSTR(url), EL_CSTR(body), h, EL_CSTR(output_path)); + if (h) curl_slist_free_all(h); + return r; +} +#endif /* HAVE_CURL */ + +/* ── HTTP server (POSIX sockets + pthreads) ──────────────────────────────── */ + +#define HTTP_MAX_CONNS 64 + +typedef el_val_t (*http_handler_fn)(el_val_t method, el_val_t path, el_val_t body); + +typedef struct { + char* name; + http_handler_fn fn; +} HttpHandlerEntry; + +static HttpHandlerEntry _http_handlers[32]; +static size_t _http_handler_count = 0; +static char* _http_active_handler = NULL; +static pthread_mutex_t _http_handler_mu = PTHREAD_MUTEX_INITIALIZER; + +static pthread_mutex_t _http_conn_mu = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t _http_conn_cv = PTHREAD_COND_INITIALIZER; +static int _http_conn_active = 0; + +/* Public C-level API: register a handler by name. Programs that want El + * `http_serve` to dispatch into their handler call this from main() before + * http_serve. Not declared in the header to keep the public API minimal — + * extern lookup works since C symbols are global. */ +void el_runtime_register_handler(const char* name, http_handler_fn fn); +void el_runtime_register_handler(const char* name, http_handler_fn fn) { + if (!name || !fn) return; + pthread_mutex_lock(&_http_handler_mu); + for (size_t i = 0; i < _http_handler_count; i++) { + if (strcmp(_http_handlers[i].name, name) == 0) { + _http_handlers[i].fn = fn; + pthread_mutex_unlock(&_http_handler_mu); + return; + } + } + if (_http_handler_count < sizeof(_http_handlers) / sizeof(_http_handlers[0])) { + _http_handlers[_http_handler_count].name = el_strdup(name); + _http_handlers[_http_handler_count].fn = fn; + _http_handler_count++; + } + pthread_mutex_unlock(&_http_handler_mu); +} + +el_val_t http_set_handler(el_val_t name) { + const char* n = EL_CSTR(name); + pthread_mutex_lock(&_http_handler_mu); + free(_http_active_handler); + _http_active_handler = el_strdup(n ? n : ""); + /* If the name is not yet in the registry, try dlsym lookup against + * the running binary's symbol table. Every El `fn name(...)` compiles + * to a global C symbol with that exact name, so El programs can self- + * register their own handlers just by calling http_set_handler("name"). */ + if (n && *n) { + int found = 0; + for (size_t i = 0; i < _http_handler_count; i++) { + if (strcmp(_http_handlers[i].name, n) == 0) { found = 1; break; } + } + if (!found) { + void* sym = dlsym(RTLD_DEFAULT, n); + if (sym && _http_handler_count < sizeof(_http_handlers) / sizeof(_http_handlers[0])) { + _http_handlers[_http_handler_count].name = el_strdup(n); + _http_handlers[_http_handler_count].fn = (http_handler_fn)sym; + _http_handler_count++; + } + } + } + pthread_mutex_unlock(&_http_handler_mu); + return 0; +} + +static http_handler_fn http_lookup_active(void) { + http_handler_fn out = NULL; + pthread_mutex_lock(&_http_handler_mu); + if (_http_active_handler) { + for (size_t i = 0; i < _http_handler_count; i++) { + if (strcmp(_http_handlers[i].name, _http_active_handler) == 0) { + out = _http_handlers[i].fn; break; + } + } + } + pthread_mutex_unlock(&_http_handler_mu); + return out; +} + +/* Auto-detect Content-Type from response body. */ +static const char* http_detect_content_type(const char* body) { + if (!body) return "text/plain; charset=utf-8"; + const char* p = body; + /* Binary magic bytes — check before stripping whitespace */ + if ((unsigned char)p[0] == 0x89 && p[1]=='P' && p[2]=='N' && p[3]=='G') + return "image/png"; + if ((unsigned char)p[0] == 0xFF && (unsigned char)p[1] == 0xD8) + return "image/jpeg"; + if (strncmp(p, "GIF8", 4) == 0) return "image/gif"; + if (strncmp(p, "RIFF", 4) == 0) return "image/webp"; + if (strncmp(p, "wOFF", 4) == 0) return "font/woff"; + if (strncmp(p, "wOF2", 4) == 0) return "font/woff2"; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (strncasecmp(p, "= cap) { + if (cap >= 1024 * 1024) { free(buf); return -1; } + cap *= 2; + buf = realloc(buf, cap); + if (!buf) return -1; + } + ssize_t n = recv(fd, buf + len, cap - len - 1, 0); + if (n <= 0) { free(buf); return -1; } + len += (size_t)n; + buf[len] = '\0'; + if (strstr(buf, "\r\n\r\n")) break; + } + /* Parse request line */ + char* sp1 = strchr(buf, ' '); + if (!sp1) { free(buf); return -1; } + *sp1 = '\0'; + *out_method = el_strdup(buf); + char* path_start = sp1 + 1; + char* sp2 = strchr(path_start, ' '); + if (!sp2) { free(*out_method); *out_method = NULL; free(buf); return -1; } + *sp2 = '\0'; + *out_path = el_strdup(path_start); + char* hdr_end = strstr(sp2 + 1, "\r\n\r\n"); + /* Capture the raw header block (after the request line's CRLF, up to + * but not including the terminating \r\n\r\n) for callers that asked + * for it. The legacy 3-arg path passes NULL and skips this. */ + if (out_headers_block) { + char* hdr_start = strstr(sp2 + 1, "\r\n"); + if (hdr_start && hdr_start < hdr_end) { + hdr_start += 2; + size_t hb_len = (size_t)(hdr_end - hdr_start); + char* hb = malloc(hb_len + 1); + if (hb) { + memcpy(hb, hdr_start, hb_len); + hb[hb_len] = '\0'; + *out_headers_block = hb; + } + } else { + *out_headers_block = el_strdup(""); + } + } + /* Find Content-Length */ + long content_length = 0; + char* hp = sp2 + 1; + while (hp < hdr_end) { + char* line_end = strstr(hp, "\r\n"); + /* line_end == hdr_end means we're on the LAST header line — its + * trailing \r\n is the same \r\n that begins the \r\n\r\n header + * terminator. Process this line; only stop when line_end is past + * hdr_end (which means the parser walked off the end of the + * header block). The previous condition (line_end >= hdr_end) + * silently dropped any Content-Length that appeared as the last + * header — exactly what real curl/clients tend to emit. */ + if (!line_end || line_end > hdr_end) break; + if (strncasecmp(hp, "Content-Length:", 15) == 0) { + content_length = strtol(hp + 15, NULL, 10); + if (content_length < 0) content_length = 0; + if (content_length > 64 * 1024 * 1024) content_length = 64 * 1024 * 1024; + } + hp = line_end + 2; + } + /* Body: any bytes already read past hdr_end, plus more recv */ + char* body_start = hdr_end + 4; + size_t body_have = (buf + len) - body_start; + char* body = malloc((size_t)content_length + 1); + if (!body) { free(*out_method); free(*out_path); *out_method=NULL; *out_path=NULL; free(buf); return -1; } + if ((long)body_have > content_length) body_have = (size_t)content_length; + if (body_have > 0) memcpy(body, body_start, body_have); + while ((long)body_have < content_length) { + ssize_t n = recv(fd, body + body_have, (size_t)content_length - body_have, 0); + if (n <= 0) break; + body_have += (size_t)n; + } + body[body_have] = '\0'; + *out_body = body; + free(buf); + return 0; +} + +/* Reason phrase for common HTTP statuses. Falls back to "Status" for the + * long tail — clients only care about the numeric code. */ +static const char* http_reason_phrase(int status) { + switch (status) { + case 200: return "OK"; + case 201: return "Created"; + case 202: return "Accepted"; + case 204: return "No Content"; + case 301: return "Moved Permanently"; + case 302: return "Found"; + case 303: return "See Other"; + case 304: return "Not Modified"; + case 307: return "Temporary Redirect"; + case 308: return "Permanent Redirect"; + case 400: return "Bad Request"; + case 401: return "Unauthorized"; + case 403: return "Forbidden"; + case 404: return "Not Found"; + case 405: return "Method Not Allowed"; + case 409: return "Conflict"; + case 410: return "Gone"; + case 422: return "Unprocessable Entity"; + case 429: return "Too Many Requests"; + case 500: return "Internal Server Error"; + case 501: return "Not Implemented"; + case 502: return "Bad Gateway"; + case 503: return "Service Unavailable"; + case 504: return "Gateway Timeout"; + default: return "Status"; + } +} + +/* Best-effort send with retry on partial writes. */ +static int http_send_all(int fd, const char* p, size_t left) { + while (left > 0) { + ssize_t w = send(fd, p, left, 0); + if (w <= 0) return -1; + p += w; left -= (size_t)w; + } + return 0; +} + +/* Discriminator that http_response() embeds at the start of its envelope. + * A handler returning a string starting with this exact prefix is treated + * as a structured response; anything else is treated as a raw body. */ +#define EL_HTTP_RESPONSE_TAG "{\"el_http_response\":1" + +/* Keys that conflict with runtime-managed headers are silently dropped to + * avoid double-emission — the runtime always emits its own Content-Length + * and Connection: close. Content-Type from the envelope IS allowed and + * overrides auto-detection. */ +static int http_header_is_managed(const char* k) { + return strcasecmp(k, "Content-Length") == 0 + || strcasecmp(k, "Connection") == 0; +} + +/* Walk an ElMap of header pairs and emit each as `K: V\r\n` into JsonBuf b. + * Sets *out_saw_content_type to 1 if the map contained an explicit + * Content-Type so the caller can skip auto-detection. */ +static void http_emit_headers_from_map(JsonBuf* b, el_val_t headers_map, + int* out_saw_content_type) { + *out_saw_content_type = 0; + if (headers_map == 0) return; + ElMap* m = (ElMap*)(uintptr_t)headers_map; + if (!m || m->hdr.magic != EL_MAGIC_MAP) return; + for (int64_t i = 0; i < m->count; i++) { + const char* k = EL_CSTR(m->keys[i]); + const char* v = EL_CSTR(m->values[i]); + if (!k || !v) continue; + if (http_header_is_managed(k)) continue; + if (strcasecmp(k, "Content-Type") == 0) *out_saw_content_type = 1; + jb_puts(b, k); + jb_puts(b, ": "); + jb_puts(b, v); + jb_puts(b, "\r\n"); + } +} + +/* Parse the envelope produced by http_response(). On success returns 1 and + * populates *out_status, *out_headers_map (an ElMap el_val_t — caller must + * el_release), and *out_body (allocated). On failure returns 0. + * + * Implementation: feeds the entire envelope through the recursive-descent + * JSON parser (which builds proper ElMap/ElList values), then pulls the + * three top-level fields by name. Avoids re-stringifying the headers map + * since json_stringify() does not support nested objects. */ +static int http_parse_envelope(const char* s, int* out_status, + el_val_t* out_headers_map, char** out_body, + el_val_t* out_parsed_root) { + if (!s) return 0; + if (strncmp(s, EL_HTTP_RESPONSE_TAG, + sizeof(EL_HTTP_RESPONSE_TAG) - 1) != 0) return 0; + + el_val_t parsed = json_parse(EL_STR(s)); + if (parsed == EL_NULL) return 0; + + int status = 200; + el_val_t hmap = 0; + char* body = NULL; + + el_val_t sv = el_map_get(parsed, EL_STR("status")); + if (sv != 0) { + /* status comes back as an integer — el_val_t holds it directly. */ + long sc = (long)sv; + if (sc >= 100 && sc <= 599) status = (int)sc; + } + + el_val_t hv = el_map_get(parsed, EL_STR("headers")); + if (hv != 0) { + ElMap* hm = (ElMap*)(uintptr_t)hv; + if (hm && hm->hdr.magic == EL_MAGIC_MAP) hmap = hv; + } + + el_val_t bv = el_map_get(parsed, EL_STR("body")); + if (bv != 0) { + const char* bs = EL_CSTR(bv); + if (bs) body = el_strdup(bs); + } + if (!body) body = el_strdup(""); + + *out_status = status; + *out_headers_map = hmap; + *out_body = body; + *out_parsed_root = parsed; /* caller releases to free hmap + entries */ + return 1; +} + +/* Lightweight `__status__` envelope: if the body's first key is `__status__` + * and its value is a numeric literal, lift the status to the HTTP layer and + * strip the marker from the body before sending. This is the common case for + * El handlers that want to return 4xx/5xx without going through + * http_response() — they just prepend `{"__status__":,...}` to the JSON + * they were already returning. + * + * We deliberately recognise ONLY the first-key form so the contract is cheap + * to detect and unambiguous: `{"__status__":401,"error":"unauthorized"}` is + * an envelope, but `{"error":"...","__status__":401}` is not. Product code + * controls placement. + * + * On success returns 1 with *out_status set and *out_body_alloc populated + * with a freshly malloc'd body (caller frees). On failure returns 0 and + * leaves outputs untouched. */ +static int http_parse_status_envelope(const char* s, int* out_status, + char** out_body_alloc) { + if (!s) return 0; + const char* p = s; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '{') return 0; + p++; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + static const char marker[] = "\"__status__\""; + size_t mlen = sizeof(marker) - 1; + if (strncmp(p, marker, mlen) != 0) return 0; + p += mlen; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != ':') return 0; + p++; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p < '0' || *p > '9') return 0; /* non-numeric -> not an envelope */ + int status = 0; + while (*p >= '0' && *p <= '9') { + status = status * 10 + (*p - '0'); + p++; + } + if (status < 100 || status > 599) return 0; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + /* Two trailing shapes accepted: + * ,"k":v,...} -> body becomes {"k":v,...} + * } -> body becomes {} + * Anything else (e.g. `:` re-appearing, garbage) drops the envelope so + * we don't strip what we shouldn't. */ + if (*p == '}') { + *out_status = status; + *out_body_alloc = el_strdup("{}"); + return 1; + } + if (*p != ',') return 0; + p++; /* skip the comma; the rest of the object follows */ + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + /* Build the trimmed body: '{' + remainder. */ + size_t rest_len = strlen(p); + char* out = (char*)malloc(rest_len + 2); + if (!out) return 0; + out[0] = '{'; + memcpy(out + 1, p, rest_len); + out[rest_len + 1] = '\0'; + *out_status = status; + *out_body_alloc = out; + return 1; +} + +/* Send a fully-built HTTP response. If `body` starts with the envelope tag, + * unpack status/headers/body. Otherwise emit the historical 200-OK with + * auto-detected Content-Type. */ +/* Thread-local flag: if 1, http_send_response writes status + headers but + * NO body (HEAD method behaviour). Set by http_worker before calling + * http_send_response, cleared after. */ +static __thread int _tl_http_head_only = 0; + +static void http_send_response(int fd, const char* body) { + if (!body) body = ""; + + int status = 200; + el_val_t env_headers_map = 0; + char* env_body = NULL; + el_val_t env_parsed_root = 0; + int is_envelope = http_parse_envelope(body, &status, + &env_headers_map, &env_body, + &env_parsed_root); + + /* If the rich http_response() envelope didn't claim this body, try the + * lightweight `__status__` form. This second envelope is malloc-backed so + * we route it through env_body and let the existing cleanup path free it + * — same lifetime contract, no special case at the bottom of the + * function. */ + if (!is_envelope) { + char* trimmed = NULL; + if (http_parse_status_envelope(body, &status, &trimmed)) { + env_body = trimmed; + is_envelope = 1; + } + } + + const char* eff_body = is_envelope ? env_body : body; + /* Use the real byte count from fs_read if available (handles binary files + * with embedded null bytes — PNG, WOFF2, etc.). Fall back to strlen for + * normal text/JSON responses where _tl_fs_read_len is 0. */ + size_t blen = (_tl_fs_read_len > 0) ? _tl_fs_read_len : strlen(eff_body); + _tl_fs_read_len = 0; /* consume — one-shot per response */ + int head_only = _tl_http_head_only; + + JsonBuf hdrs; jb_init(&hdrs); + int saw_content_type = 0; + if (is_envelope) { + http_emit_headers_from_map(&hdrs, env_headers_map, + &saw_content_type); + } + if (!saw_content_type) { + jb_puts(&hdrs, "Content-Type: "); + jb_puts(&hdrs, http_detect_content_type(eff_body)); + jb_puts(&hdrs, "\r\n"); + } + + char status_line[64]; + int sl = snprintf(status_line, sizeof(status_line), + "HTTP/1.1 %d %s\r\n", + status, http_reason_phrase(status)); + if (sl < 0) { + if (env_parsed_root) el_release(env_parsed_root); + free(env_body); free(hdrs.buf); return; + } + + char tail[128]; + int tl = snprintf(tail, sizeof(tail), + "Content-Length: %zu\r\n" + "Connection: close\r\n" + "\r\n", blen); + if (tl < 0) { + if (env_parsed_root) el_release(env_parsed_root); + free(env_body); free(hdrs.buf); return; + } + + if (http_send_all(fd, status_line, (size_t)sl) == 0 + && http_send_all(fd, hdrs.buf, hdrs.len) == 0 + && http_send_all(fd, tail, (size_t)tl) == 0 + && (head_only + /* HEAD requests echo headers + Content-Length but no body. */ + ? 1 + : http_send_all(fd, eff_body, blen) == 0)) { + /* sent successfully */ + } + + if (env_parsed_root) el_release(env_parsed_root); + free(env_body); + free(hdrs.buf); +} + +typedef struct { + int fd; +} HttpWorkerArg; + +static void* http_worker(void* arg) { + HttpWorkerArg* a = (HttpWorkerArg*)arg; + int fd = a->fd; + free(a); + char *method = NULL, *path = NULL, *body = NULL; + if (http_read_request(fd, &method, &path, &body, NULL) == 0) { + http_handler_fn h = http_lookup_active(); + char* response = NULL; + /* HEAD: dispatch as GET so existing handlers respond with the same + * body, but flag the response writer to emit headers only. RFC 9110 + * requires HEAD to mirror GET headers + Content-Length without body. */ + int head_only = (method && strcmp(method, "HEAD") == 0); + const char* dispatch_method = head_only ? "GET" : method; + el_request_start(); /* begin per-request arena */ + if (h) { + el_val_t r = h(EL_STR(dispatch_method), EL_STR(path), EL_STR(body)); + const char* rs = EL_CSTR(r); + /* Copy response out BEFORE arena teardown. + * For binary files, _tl_fs_read_len holds the real byte count — + * use memcpy instead of strdup so null bytes are preserved. */ + size_t rlen = _tl_fs_read_len > 0 ? _tl_fs_read_len : (rs ? strlen(rs) : 0); + response = malloc(rlen + 1); + if (response && rs) { memcpy(response, rs, rlen); response[rlen] = '\0'; } + else if (response) { response[0] = '\0'; } + } else { + response = el_strdup_persist("el-runtime: no http handler registered"); + } + el_request_end(); /* free all intermediate strings */ + _tl_http_head_only = head_only; + http_send_response(fd, response); + _tl_http_head_only = 0; + free(response); + } + free(method); free(path); free(body); + close(fd); + /* release a slot */ + pthread_mutex_lock(&_http_conn_mu); + _http_conn_active--; + pthread_cond_signal(&_http_conn_cv); + pthread_mutex_unlock(&_http_conn_mu); + return NULL; +} + +el_val_t http_serve(el_val_t port, el_val_t handler) { + /* If `handler` looks like a string name, register it as the active handler. */ + const char* hname = EL_CSTR(handler); + if (hname && looks_like_string(handler)) { + http_set_handler(handler); + } + int p = (int)port; + if (p <= 0 || p > 65535) { fprintf(stderr, "http_serve: invalid port %d\n", p); return 0; } + /* Dual-stack: AF_INET6 with IPV6_V6ONLY=0 accepts both IPv4 and IPv6. + * This makes `localhost` work in browsers that resolve it to ::1 first. */ + int sock = socket(AF_INET6, SOCK_STREAM, 0); + if (sock < 0) { perror("socket"); return 0; } + int yes = 1; int no = 0; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no)); + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr = in6addr_any; + addr.sin6_port = htons((uint16_t)p); + if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + perror("bind"); close(sock); return 0; + } + if (listen(sock, 64) < 0) { perror("listen"); close(sock); return 0; } + fprintf(stderr, "[http] listening on [::]:%d (dual-stack)\n", p); + while (1) { + struct sockaddr_in6 cli; + socklen_t clen = sizeof(cli); + int cfd = accept(sock, (struct sockaddr*)&cli, &clen); + if (cfd < 0) { + if (errno == EINTR) continue; + perror("accept"); break; + } + pthread_mutex_lock(&_http_conn_mu); + while (_http_conn_active >= HTTP_MAX_CONNS) { + pthread_cond_wait(&_http_conn_cv, &_http_conn_mu); + } + _http_conn_active++; + pthread_mutex_unlock(&_http_conn_mu); + HttpWorkerArg* arg = malloc(sizeof(HttpWorkerArg)); + if (!arg) { close(cfd); continue; } + arg->fd = cfd; + pthread_t tid; + if (pthread_create(&tid, NULL, http_worker, arg) != 0) { + close(cfd); free(arg); + pthread_mutex_lock(&_http_conn_mu); + _http_conn_active--; + pthread_cond_signal(&_http_conn_cv); + pthread_mutex_unlock(&_http_conn_mu); + continue; + } + pthread_detach(tid); + } + close(sock); + return 0; +} + +/* ── HTTP server v2 — request headers + structured response ──────────────── */ +/* + * v2 widens the handler signature from + * (method, path, body) -> body_string + * to + * (method, path, headers_map, body) -> body_string_or_envelope + * + * The response envelope is detected uniformly inside http_send_response — so + * 4-arg handlers can return either a plain body or http_response(...). The + * 3-arg path stays untouched in spirit (its handlers still build plain + * bodies; the envelope tag, being `{"el_http_response":1`, will never + * collide with normal JSON the legacy server.el routes return). + * + * Registry is parallel to the 3-arg handler registry: separate name table, + * separate active-handler slot, separate dlsym fallback. Mixing v1 and v2 + * handlers in the same process is fine — they don't share the active slot. */ + +typedef el_val_t (*http_handler4_fn)(el_val_t method, el_val_t path, + el_val_t headers_map, el_val_t body); + +typedef struct { + char* name; + http_handler4_fn fn; +} HttpHandler4Entry; + +static HttpHandler4Entry _http_handlers4[32]; +static size_t _http_handler4_count = 0; +static char* _http_active_handler4 = NULL; + +void el_runtime_register_handler_v2(const char* name, http_handler4_fn fn); +void el_runtime_register_handler_v2(const char* name, http_handler4_fn fn) { + if (!name || !fn) return; + pthread_mutex_lock(&_http_handler_mu); + for (size_t i = 0; i < _http_handler4_count; i++) { + if (strcmp(_http_handlers4[i].name, name) == 0) { + _http_handlers4[i].fn = fn; + pthread_mutex_unlock(&_http_handler_mu); + return; + } + } + if (_http_handler4_count < + sizeof(_http_handlers4) / sizeof(_http_handlers4[0])) { + _http_handlers4[_http_handler4_count].name = el_strdup(name); + _http_handlers4[_http_handler4_count].fn = fn; + _http_handler4_count++; + } + pthread_mutex_unlock(&_http_handler_mu); +} + +el_val_t http_set_handler_v2(el_val_t name) { + const char* n = EL_CSTR(name); + pthread_mutex_lock(&_http_handler_mu); + free(_http_active_handler4); + _http_active_handler4 = el_strdup(n ? n : ""); + if (n && *n) { + int found = 0; + for (size_t i = 0; i < _http_handler4_count; i++) { + if (strcmp(_http_handlers4[i].name, n) == 0) { found = 1; break; } + } + if (!found) { + void* sym = dlsym(RTLD_DEFAULT, n); + if (sym && _http_handler4_count < + sizeof(_http_handlers4) / sizeof(_http_handlers4[0])) { + _http_handlers4[_http_handler4_count].name = el_strdup(n); + _http_handlers4[_http_handler4_count].fn = + (http_handler4_fn)sym; + _http_handler4_count++; + } + } + } + pthread_mutex_unlock(&_http_handler_mu); + return 0; +} + +static http_handler4_fn http_lookup_active_v2(void) { + http_handler4_fn out = NULL; + pthread_mutex_lock(&_http_handler_mu); + if (_http_active_handler4) { + for (size_t i = 0; i < _http_handler4_count; i++) { + if (strcmp(_http_handlers4[i].name, + _http_active_handler4) == 0) { + out = _http_handlers4[i].fn; break; + } + } + } + pthread_mutex_unlock(&_http_handler_mu); + return out; +} + +/* Build an ElMap from the raw header block produced by http_read_request. + * Keys are lowercased (RFC 7230 — case-insensitive); values have leading + * whitespace trimmed. Repeated headers with the same name are joined with + * ", " in arrival order, matching standard library behaviour elsewhere. */ +static el_val_t http_build_headers_map(const char* hdr_block) { + el_val_t m = el_map_new(0); + if (!hdr_block || !*hdr_block) return m; + const char* p = hdr_block; + while (*p) { + const char* line_end = strstr(p, "\r\n"); + const char* end = line_end ? line_end : p + strlen(p); + const char* colon = NULL; + for (const char* c = p; c < end; c++) { + if (*c == ':') { colon = c; break; } + } + if (colon && colon > p) { + size_t klen = (size_t)(colon - p); + char* key = malloc(klen + 1); + if (key) { + for (size_t i = 0; i < klen; i++) { + unsigned char ch = (unsigned char)p[i]; + key[i] = (char)tolower(ch); + } + key[klen] = '\0'; + const char* vstart = colon + 1; + while (vstart < end && (*vstart == ' ' || *vstart == '\t')) vstart++; + size_t vlen = (size_t)(end - vstart); + /* Strip trailing OWS just in case. */ + while (vlen > 0 + && (vstart[vlen - 1] == ' ' + || vstart[vlen - 1] == '\t')) vlen--; + /* Coalesce repeats: if key already present, append ", value". */ + el_val_t existing = el_map_get(m, EL_STR(key)); + if (existing != 0 && looks_like_string(existing)) { + const char* old = EL_CSTR(existing); + size_t olen = strlen(old); + char* combined = malloc(olen + 2 + vlen + 1); + if (combined) { + memcpy(combined, old, olen); + memcpy(combined + olen, ", ", 2); + memcpy(combined + olen + 2, vstart, vlen); + combined[olen + 2 + vlen] = '\0'; + m = el_map_set(m, EL_STR(key), EL_STR(combined)); + } + free(key); + } else { + char* val = malloc(vlen + 1); + if (val) { + memcpy(val, vstart, vlen); + val[vlen] = '\0'; + m = el_map_set(m, EL_STR(key), EL_STR(val)); + } else { + free(key); + } + } + } + } + if (!line_end) break; + p = line_end + 2; + } + return m; +} + +static void* http_worker_v2(void* arg) { + HttpWorkerArg* a = (HttpWorkerArg*)arg; + int fd = a->fd; + free(a); + char *method = NULL, *path = NULL, *body = NULL, *hdr_block = NULL; + if (http_read_request(fd, &method, &path, &body, &hdr_block) == 0) { + http_handler4_fn h = http_lookup_active_v2(); + char* response = NULL; + int head_only = (method && strcmp(method, "HEAD") == 0); + const char* dispatch_method = head_only ? "GET" : method; + el_request_start(); /* begin per-request arena */ + if (h) { + el_val_t hmap = http_build_headers_map(hdr_block ? hdr_block : ""); + el_val_t r = h(EL_STR(dispatch_method), EL_STR(path), hmap, EL_STR(body)); + const char* rs = EL_CSTR(r); + size_t rlen = _tl_fs_read_len > 0 ? _tl_fs_read_len : (rs ? strlen(rs) : 0); + response = malloc(rlen + 1); + if (response && rs) { memcpy(response, rs, rlen); response[rlen] = '\0'; } + else if (response) { response[0] = '\0'; } + el_release(hmap); + } else { + response = el_strdup_persist( + "el-runtime: no v2 http handler registered " + "(call http_set_handler_v2)"); + } + el_request_end(); /* free all intermediate strings */ + _tl_http_head_only = head_only; + http_send_response(fd, response); + _tl_http_head_only = 0; + free(response); + } + free(method); free(path); free(body); free(hdr_block); + close(fd); + pthread_mutex_lock(&_http_conn_mu); + _http_conn_active--; + pthread_cond_signal(&_http_conn_cv); + pthread_mutex_unlock(&_http_conn_mu); + return NULL; +} + +el_val_t http_serve_v2(el_val_t port, el_val_t handler) { + const char* hname = EL_CSTR(handler); + if (hname && looks_like_string(handler)) { + http_set_handler_v2(handler); + } + int p = (int)port; + if (p <= 0 || p > 65535) { + fprintf(stderr, "http_serve_v2: invalid port %d\n", p); + return 0; + } + /* Dual-stack: same as http_serve - AF_INET6 + IPV6_V6ONLY=0. */ + int sock = socket(AF_INET6, SOCK_STREAM, 0); + if (sock < 0) { perror("socket"); return 0; } + int yes = 1; int no = 0; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no)); + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr = in6addr_any; + addr.sin6_port = htons((uint16_t)p); + if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + perror("bind"); close(sock); return 0; + } + if (listen(sock, 64) < 0) { perror("listen"); close(sock); return 0; } + fprintf(stderr, "[http v2] listening on [::]:%d (dual-stack)\n", p); + while (1) { + struct sockaddr_in6 cli; + socklen_t clen = sizeof(cli); + int cfd = accept(sock, (struct sockaddr*)&cli, &clen); + if (cfd < 0) { + if (errno == EINTR) continue; + perror("accept"); break; + } + pthread_mutex_lock(&_http_conn_mu); + while (_http_conn_active >= HTTP_MAX_CONNS) { + pthread_cond_wait(&_http_conn_cv, &_http_conn_mu); + } + _http_conn_active++; + pthread_mutex_unlock(&_http_conn_mu); + HttpWorkerArg* arg = malloc(sizeof(HttpWorkerArg)); + if (!arg) { close(cfd); continue; } + arg->fd = cfd; + pthread_t tid; + if (pthread_create(&tid, NULL, http_worker_v2, arg) != 0) { + close(cfd); free(arg); + pthread_mutex_lock(&_http_conn_mu); + _http_conn_active--; + pthread_cond_signal(&_http_conn_cv); + pthread_mutex_unlock(&_http_conn_mu); + continue; + } + pthread_detach(tid); + } + close(sock); + return 0; +} + +/* Build the response envelope a 4-arg handler can return. We hand-write + * the JSON so the discriminator key always lands first — the runtime's + * http_parse_envelope() detects it via prefix match. headers_json must be + * either "" (empty), "{}" (empty object), or a well-formed JSON object + * literal; anything else will produce a malformed envelope and the runtime + * will treat the whole string as a plain body (no envelope detected). */ +el_val_t http_response(el_val_t status, el_val_t headers_json, el_val_t body) { + long sc = (long)status; + if (sc < 100 || sc > 599) sc = 200; + const char* hj = EL_CSTR(headers_json); + if (!hj || !*hj) hj = "{}"; + /* Light validation: must start with '{' and end with '}'. */ + size_t hlen = strlen(hj); + int hj_ok = (hlen >= 2 && hj[0] == '{' && hj[hlen - 1] == '}'); + if (!hj_ok) hj = "{}"; + const char* b = EL_CSTR(body); + if (!b) b = ""; + + JsonBuf out; jb_init(&out); + jb_puts(&out, EL_HTTP_RESPONSE_TAG); /* {"el_http_response":1 */ + jb_puts(&out, ",\"status\":"); + char num[32]; + snprintf(num, sizeof(num), "%ld", sc); + jb_puts(&out, num); + jb_puts(&out, ",\"headers\":"); + jb_puts(&out, hj); + jb_puts(&out, ",\"body\":"); + jb_emit_escaped(&out, b); + jb_putc(&out, '}'); + return el_wrap_str(out.buf); +} + +/* ── Filesystem ──────────────────────────────────────────────────────────── */ + +el_val_t fs_read(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + _tl_fs_read_len = 0; + if (!path) return el_wrap_str(el_strdup("")); + FILE* f = fopen(path, "rb"); + if (!f) return el_wrap_str(el_strdup("")); + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + if (sz < 0) { fclose(f); return el_wrap_str(el_strdup("")); } /* pipe/special file */ + char* buf = el_strbuf((size_t)sz); + size_t got = fread(buf, 1, (size_t)sz, f); + buf[got] = '\0'; + _tl_fs_read_len = got; /* store real byte count for binary-safe send */ + fclose(f); + return el_wrap_str(buf); +} + +el_val_t fs_write(el_val_t pathv, el_val_t contentv) { + const char* path = EL_CSTR(pathv); + const char* content = EL_CSTR(contentv); + if (!path || !content) return 0; + FILE* f = fopen(path, "wb"); + if (!f) return 0; + size_t n = strlen(content); + size_t written = fwrite(content, 1, n, f); + fclose(f); + return written == n ? 1 : 0; +} + +/* fs_write_bytes — explicit-length binary write. Bypasses strlen so embedded + * NULs survive. Caller must know the byte count (e.g. from base64_decode, + * or the fixed 32-byte sha256_bytes/hmac_sha256_bytes outputs). + * + * If `length` is negative, treats as failure. If `length` is 0, creates an + * empty file (still useful as a "touch with content" primitive). */ +el_val_t fs_write_bytes(el_val_t pathv, el_val_t bytesv, el_val_t lengthv) { + const char* path = EL_CSTR(pathv); + const char* bytes = EL_CSTR(bytesv); + int64_t n = (int64_t)lengthv; + if (!path || !bytes) return 0; + if (n < 0) return 0; + FILE* f = fopen(path, "wb"); + if (!f) return 0; + size_t written = (n > 0) ? fwrite(bytes, 1, (size_t)n, f) : 0; + int flush_ok = (fflush(f) == 0); + int close_ok = (fclose(f) == 0); + if (!flush_ok || !close_ok || written != (size_t)n) { + remove(path); + return 0; + } + return 1; +} + +// stdout_to_file / stdout_restore — redirect process stdout to a file and +// restore it. Used by the compiler's JS post-processing pipeline to capture +// codegen output before piping through terser / obfuscator. +#include +static int _el_saved_stdout_fd = -1; + +el_val_t stdout_to_file(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + if (!path) return (el_val_t)(int64_t)-1; + fflush(stdout); + _el_saved_stdout_fd = dup(STDOUT_FILENO); + int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd < 0) return (el_val_t)(int64_t)-1; + dup2(fd, STDOUT_FILENO); + close(fd); + return (el_val_t)(int64_t)0; +} + +el_val_t stdout_restore(void) { + if (_el_saved_stdout_fd >= 0) { + fflush(stdout); + dup2(_el_saved_stdout_fd, STDOUT_FILENO); + close(_el_saved_stdout_fd); + _el_saved_stdout_fd = -1; + } + return (el_val_t)(int64_t)0; +} + +// exec_command — run a shell command, return exit code (0 = success). +// Used by elb and other El tooling to invoke subprocesses. +el_val_t exec_command(el_val_t cmdv) { + const char* cmd = EL_CSTR(cmdv); + if (!cmd) return (el_val_t)(int64_t)-1; + int ret = system(cmd); + return (el_val_t)(int64_t)ret; +} + +// exec_capture — run a shell command, capture stdout, return as String. +// Returns "" on failure. +el_val_t exec_capture(el_val_t cmdv) { + const char* cmd = EL_CSTR(cmdv); + if (!cmd) return el_wrap_str(el_strdup("")); + FILE* f = popen(cmd, "r"); + if (!f) return el_wrap_str(el_strdup("")); + JsonBuf b; jb_init(&b); + char buf[4096]; + while (fgets(buf, sizeof(buf), f)) jb_puts(&b, buf); + pclose(f); + return el_wrap_str(b.buf); +} + +// exec — run a shell command via /bin/sh, capture stdout, return as String. +// Times out after 30 seconds. Returns "" on any error. +// El name: exec(cmd) -> String +el_val_t exec(el_val_t cmdv) { + const char* cmd = EL_CSTR(cmdv); + if (!cmd || !*cmd) return el_wrap_str(el_strdup("")); + /* Build a time-limited command: wrap with timeout(1) if available, + * otherwise rely on the 30s read loop guard below. We use the simple + * popen approach with a deadline measured by wall clock so the caller + * is never blocked indefinitely. */ + FILE* f = popen(cmd, "r"); + if (!f) return el_wrap_str(el_strdup("")); + JsonBuf b; jb_init(&b); + char buf[4096]; + /* 30-second wall-clock deadline */ + time_t deadline = time(NULL) + 30; + while (time(NULL) < deadline) { + if (fgets(buf, sizeof(buf), f) == NULL) break; + jb_puts(&b, buf); + } + pclose(f); + return el_wrap_str(b.buf); +} + +// exec_bg — run a shell command in background, return PID as String. +// The child process runs independently; the caller is not blocked. +// Returns "" on fork failure. +// El name: exec_bg(cmd) -> String +el_val_t exec_bg(el_val_t cmdv) { + const char* cmd = EL_CSTR(cmdv); + if (!cmd || !*cmd) return el_wrap_str(el_strdup("")); + pid_t pid = fork(); + if (pid < 0) { + /* fork failed */ + return el_wrap_str(el_strdup("")); + } + if (pid == 0) { + /* child: detach from parent's stdio, exec via shell */ + setsid(); + int devnull = open("/dev/null", O_RDWR); + if (devnull >= 0) { + dup2(devnull, STDIN_FILENO); + dup2(devnull, STDOUT_FILENO); + dup2(devnull, STDERR_FILENO); + close(devnull); + } + execl("/bin/sh", "sh", "-c", cmd, (char*)NULL); + _exit(127); + } + /* parent: convert pid to string and return immediately */ + char pidbuf[32]; + snprintf(pidbuf, sizeof(pidbuf), "%d", (int)pid); + return el_wrap_str(el_strdup(pidbuf)); +} + +el_val_t fs_list(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + el_val_t lst = el_list_empty(); + if (!path) return lst; + DIR* d = opendir(path); + if (!d) return lst; + struct dirent* e; + while ((e = readdir(d)) != NULL) { + if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) continue; + lst = el_list_append(lst, el_wrap_str(el_strdup(e->d_name))); + } + closedir(d); + return lst; +} + +/* fs_list_json — return directory entries as a JSON array of strings. + * Returns "[]" for missing or non-directory paths. Excludes "." and "..". */ +el_val_t fs_list_json(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + if (!path) return EL_STR("[]"); + DIR* d = opendir(path); + if (!d) return EL_STR("[]"); + /* Collect entries first so we can build the JSON in one pass. */ + char** names = NULL; + size_t count = 0, cap = 0; + struct dirent* e; + while ((e = readdir(d)) != NULL) { + if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) continue; + if (count >= cap) { + cap = cap ? cap * 2 : 16; + names = realloc(names, cap * sizeof(char*)); + if (!names) { closedir(d); return EL_STR("[]"); } + } + names[count++] = strdup(e->d_name); + } + closedir(d); + /* Build JSON array. */ + size_t sz = 3; /* "[]" + NUL */ + for (size_t i = 0; i < count; i++) sz += strlen(names[i]) * 2 + 6; /* conservative */ + char* buf = malloc(sz); + if (!buf) { for (size_t i = 0; i < count; i++) free(names[i]); free(names); return EL_STR("[]"); } + size_t pos = 0; + buf[pos++] = '['; + for (size_t i = 0; i < count; i++) { + if (i > 0) buf[pos++] = ','; + buf[pos++] = '"'; + for (const char* p = names[i]; *p; p++) { + if (*p == '"' || *p == '\\') buf[pos++] = '\\'; + else if (*p == '\n') { buf[pos++] = '\\'; buf[pos++] = 'n'; continue; } + else if (*p == '\t') { buf[pos++] = '\\'; buf[pos++] = 't'; continue; } + buf[pos++] = *p; + } + buf[pos++] = '"'; + free(names[i]); + } + free(names); + buf[pos++] = ']'; + buf[pos] = '\0'; + return el_wrap_str(buf); +} + +/* fs_exists — true iff stat(path) succeeds. Symlinks are followed. */ +el_val_t fs_exists(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + if (!path || !*path) return 0; + struct stat st; + return (el_val_t)(stat(path, &st) == 0 ? 1 : 0); +} + +/* fs_mkdir — create directory at path with mode 0755, mkdir -p semantics. + * Returns 1 if path exists or was created (incl. all parents); 0 on failure. + * Walks the path component-by-component so missing intermediate dirs are + * also created. An existing leaf is not an error. */ +el_val_t fs_mkdir(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + if (!path || !*path) return 0; + size_t n = strlen(path); + char* buf = malloc(n + 1); + if (!buf) return 0; + memcpy(buf, path, n + 1); + /* Walk components; create each prefix in turn. */ + for (size_t i = 1; i <= n; i++) { + if (buf[i] == '/' || buf[i] == '\0') { + char saved = buf[i]; + buf[i] = '\0'; + if (buf[0] != '\0') { + if (mkdir(buf, 0755) != 0 && errno != EEXIST) { + /* Tolerate the case where this prefix exists as a non-dir + * only when stat says it's a directory. */ + struct stat st; + if (stat(buf, &st) != 0 || !S_ISDIR(st.st_mode)) { + free(buf); + return 0; + } + } + } + buf[i] = saved; + } + } + free(buf); + return 1; +} + +/* ── URL encoding ─────────────────────────────────────────────────────────── */ + +/* RFC 3986 percent-encoding for URL components (form bodies, query strings). + * Unreserved set: A-Z a-z 0-9 - _ . ~ — passed through verbatim. + * Everything else (including space) becomes %XX hex. */ +el_val_t url_encode(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + static const char hex[] = "0123456789ABCDEF"; + size_t n = strlen(s); + char* out = el_strbuf(n * 3); + size_t o = 0; + for (size_t i = 0; i < n; i++) { + unsigned char c = (unsigned char)s[i]; + if ((c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + c == '-' || c == '_' || c == '.' || c == '~') { + out[o++] = (char)c; + } else { + out[o++] = '%'; + out[o++] = hex[(c >> 4) & 0xF]; + out[o++] = hex[c & 0xF]; + } + } + out[o] = '\0'; + return el_wrap_str(out); +} + +/* Decode percent-encoded URL component. '+' becomes space (form-encoded); + * malformed %-escapes are emitted verbatim. */ +el_val_t url_decode(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + char* out = el_strbuf(n); + size_t o = 0; + for (size_t i = 0; i < n; i++) { + char c = s[i]; + if (c == '+') { + out[o++] = ' '; + } else if (c == '%' && i + 2 < n) { + char h1 = s[i + 1], h2 = s[i + 2]; + int v1 = (h1 >= '0' && h1 <= '9') ? h1 - '0' + : (h1 >= 'a' && h1 <= 'f') ? h1 - 'a' + 10 + : (h1 >= 'A' && h1 <= 'F') ? h1 - 'A' + 10 : -1; + int v2 = (h2 >= '0' && h2 <= '9') ? h2 - '0' + : (h2 >= 'a' && h2 <= 'f') ? h2 - 'a' + 10 + : (h2 >= 'A' && h2 <= 'F') ? h2 - 'A' + 10 : -1; + if (v1 >= 0 && v2 >= 0) { + out[o++] = (char)((v1 << 4) | v2); + i += 2; + } else { + out[o++] = c; + } + } else { + out[o++] = c; + } + } + out[o] = '\0'; + return el_wrap_str(out); +} + +/* ── html_raw ──────────────────────────────────────────────────────────────── + * Identity passthrough for raw HTML template interpolation. + * El's {raw(expr)} compiles to html_raw(expr) — the value is output as-is + * without any escaping. The caller is responsible for safety. + */ +el_val_t html_raw(el_val_t s) { + return s; +} + +/* ── html_escape ───────────────────────────────────────────────────────────── + * Escape < > " ' & for safe HTML text interpolation. + * El's {expr} in HTML templates compiles to html_escape(expr). + */ +el_val_t html_escape(el_val_t sv) { + const char* src = EL_CSTR(sv); + if (!src) return EL_STR(""); + size_t len = strlen(src); + /* Worst case: every byte → 6 chars (") */ + char* out = (char*)malloc(len * 6 + 1); + if (!out) return sv; + el_arena_track(out); + char* p = out; + for (size_t i = 0; i < len; i++) { + unsigned char c = (unsigned char)src[i]; + switch (c) { + case '&': memcpy(p, "&", 5); p += 5; break; + case '<': memcpy(p, "<", 4); p += 4; break; + case '>': memcpy(p, ">", 4); p += 4; break; + case '"': memcpy(p, """, 6); p += 6; break; + case '\'': memcpy(p, "'", 5); p += 5; break; + default: *p++ = (char)c; break; + } + } + *p = '\0'; + return el_wrap_str(out); +} + +/* ── HTML allowlist sanitizer ──────────────────────────────────────────────── + * el_html_sanitize(input, allowlist_json) + * + * Strict allowlist HTML cleaner. Replaces the older denylist patterns + * (str_replace cascades that wrapped dangerous tags in HTML comments and + * renamed `on*` attributes). The denylist approach is fragile: comment- + * wrapping can be re-broken by a literal `-->` inside an attacker-supplied + * attribute value, and every new attack vector requires a code change. + * + * Design: + * - Single-pass byte-level state machine. + * - Tag and attribute names are matched case-insensitively against the + * allowlist. Unknown tags are dropped entirely (the open and close + * markers are stripped; their inner text content survives, escaped). + * - A small set of "dangerous container" tags (script, style, iframe, + * object, embed, form, plus a few rarer ones) drop themselves AND + * their full subtree — text between `` is + * CDATA-like and must not be re-emitted as escaped text either. + * - Comments (), doctype (), CDATA (), + * and processing instructions () are dropped entirely. + * - Text content outside dropped subtrees is HTML-escaped (&, <, >, ", '). + * - Attribute values are unquoted/dequoted, then re-emitted with double + * quotes around the cleanly-escaped value. + * - For `` and any `src` attribute, the URL scheme is validated: + * only http:, https:, mailto:, fragment-only `#anchor`, or relative + * paths are allowed. Anything else (javascript:, data:, vbscript:, + * about:, file:, etc.) drops the attribute. + * - Self-closing void tags (br, hr, img, etc.) emit without a close tag. + * - Malformed input (unclosed tag at EOF, bad attribute syntax) drops + * the pending tag and continues. Pre-encoded entities (<, &, + * etc.) are passed through verbatim — the browser will decode them + * safely on render. + * + * Allowlist format (JSON string): + * {"p":[],"a":["href","title"],"strong":[],...} + * - Key = lowercase tag name. + * - Value = JSON array of allowed attribute names (lowercase). + * - Empty array means tag allowed but no attributes survive. + * + * Output is a freshly-allocated arena-tracked el_val_t string. */ + +/* Internal byte buffer with realloc-doubling. Used during sanitization; + * the final result is copied into an arena-tracked el_strbuf so the caller + * sees standard runtime memory semantics. */ +typedef struct { + char* data; + size_t len; + size_t cap; +} html_buf_t; + +static void html_buf_init(html_buf_t* b) { + b->cap = 256; + b->data = malloc(b->cap); + if (!b->data) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + b->len = 0; +} + +static void html_buf_grow(html_buf_t* b, size_t need) { + if (b->len + need + 1 <= b->cap) return; + size_t nc = b->cap; + while (b->len + need + 1 > nc) nc *= 2; + char* nd = realloc(b->data, nc); + if (!nd) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + b->data = nd; + b->cap = nc; +} + +static void html_buf_putc(html_buf_t* b, char c) { + html_buf_grow(b, 1); + b->data[b->len++] = c; +} + +static void html_buf_puts(html_buf_t* b, const char* s) { + if (!s) return; + size_t n = strlen(s); + html_buf_grow(b, n); + memcpy(b->data + b->len, s, n); + b->len += n; +} + +static void html_buf_free(html_buf_t* b) { + free(b->data); + b->data = NULL; + b->len = b->cap = 0; +} + +/* ASCII tolower, locale-independent. */ +static int html_tolower(int c) { + return (c >= 'A' && c <= 'Z') ? c + 32 : c; +} + +/* Case-insensitive ASCII compare of [a, a+n) against c-string `s`. + * Returns 1 iff lengths match and bytes are equal under tolower. */ +static int html_ieq_n(const char* a, size_t n, const char* s) { + if (!a || !s) return 0; + if (strlen(s) != n) return 0; + for (size_t i = 0; i < n; i++) { + if (html_tolower((unsigned char)a[i]) != html_tolower((unsigned char)s[i])) return 0; + } + return 1; +} + +/* Case-insensitive ASCII compare of two byte slices. */ +static int html_iemem(const char* a, const char* b, size_t n) { + for (size_t i = 0; i < n; i++) { + if (html_tolower((unsigned char)a[i]) != html_tolower((unsigned char)b[i])) return 0; + } + return 1; +} + +/* Walk a JSON allowlist object and find the value (an array) for a given + * tag key, comparing case-insensitively. On hit returns a pointer to the + * opening `[` of the array and writes the byte length of the array span + * (including the brackets) to *out_len. On miss returns NULL. + * + * The parser is intentionally tiny: it does not handle escapes inside + * keys (allowlist authors do not need them), and it relies on balanced + * brackets/quotes within the value array. */ +static const char* html_allowlist_find(const char* allow, const char* tag, + size_t tag_len, size_t* out_len) { + if (!allow) return NULL; + const char* p = allow; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '{') return NULL; + p++; + while (*p) { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p == '}' || *p == 0) return NULL; + if (*p != '"') return NULL; + p++; + const char* k = p; + while (*p && *p != '"') p++; + if (*p != '"') return NULL; + size_t klen = (size_t)(p - k); + p++; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != ':') return NULL; + p++; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') return NULL; + const char* arr_start = p; + int depth = 0; + int in_str = 0; + while (*p) { + char c = *p; + if (in_str) { + if (c == '\\' && p[1]) { p += 2; continue; } + if (c == '"') in_str = 0; + } else { + if (c == '"') in_str = 1; + else if (c == '[') depth++; + else if (c == ']') { depth--; if (depth == 0) { p++; break; } } + } + p++; + } + size_t alen = (size_t)(p - arr_start); + int match = (klen == tag_len) && html_iemem(k, tag, klen); + if (match) { + if (out_len) *out_len = alen; + return arr_start; + } + } + return NULL; +} + +/* Returns 1 iff `attr` (length attr_len) appears as a string element + * in the JSON array slice [arr, arr+arr_len). Comparison is case- + * insensitive. */ +static int html_attr_in_array(const char* arr, size_t arr_len, + const char* attr, size_t attr_len) { + if (!arr || arr_len < 2) return 0; + const char* p = arr + 1; + const char* end = arr + arr_len - 1; + while (p < end) { + while (p < end && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',')) p++; + if (p >= end) return 0; + if (*p != '"') return 0; + p++; + const char* s = p; + while (p < end && *p != '"') { + if (*p == '\\' && p + 1 < end) p++; + p++; + } + if (p >= end) return 0; + size_t slen = (size_t)(p - s); + p++; + if (slen == attr_len && html_iemem(s, attr, slen)) return 1; + } + return 0; +} + +/* Hard-coded set of tags whose content is ALSO dropped (entire subtree). */ +static int html_is_dangerous_container(const char* tag, size_t tag_len) { + static const char* names[] = { + "script", "style", "iframe", "object", "embed", "form", + "noscript", "noembed", "template", "svg", "math", "frame", + "frameset", "applet", "audio", "video", "source", "track", + NULL + }; + for (int i = 0; names[i]; i++) { + if (html_ieq_n(tag, tag_len, names[i])) return 1; + } + return 0; +} + +/* HTML void elements — emit without a close tag. */ +static int html_is_void(const char* tag, size_t tag_len) { + static const char* names[] = { + "area", "base", "br", "col", "embed", "hr", "img", "input", + "link", "meta", "param", "source", "track", "wbr", + NULL + }; + for (int i = 0; names[i]; i++) { + if (html_ieq_n(tag, tag_len, names[i])) return 1; + } + return 0; +} + +/* Append a single byte HTML-escaped into the output buffer. */ +static void html_escape_byte(html_buf_t* out, unsigned char c) { + switch (c) { + case '<': html_buf_puts(out, "<"); break; + case '>': html_buf_puts(out, ">"); break; + case '"': html_buf_puts(out, """); break; + case '\'': html_buf_puts(out, "'"); break; + default: html_buf_putc(out, (char)c); break; + } +} + +/* Validate a URL value against the allowlist of safe schemes for hrefs. + * Returns 1 iff the URL is safe to emit. Acceptable forms: + * - http:// or https:// (case-insensitive) + * - mailto: + * - fragment-only `#anchor` + * - relative path that does not contain a colon before the first + * slash/?/# (so `foo/bar`, `/foo`, `?x=1` are OK; `javascript:x` is + * not — its colon precedes any path/hash/query separator). + * + * URL leading whitespace and embedded ASCII control bytes (TAB, LF, CR) + * are stripped before the scheme test, mirroring how browsers normalise + * URLs (these bytes are otherwise a known XSS bypass: `java\tscript:`). */ +static int html_url_is_safe(const char* url, size_t len) { + if (!url || len == 0) return 1; /* empty href is harmless */ + size_t i = 0; + while (i < len) { + unsigned char c = (unsigned char)url[i]; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == 0x0B || c == 0x0C) { + i++; continue; + } + break; + } + if (i >= len) return 1; /* whitespace only */ + if (url[i] == '#') return 1; /* fragment only */ + if (url[i] == '/' || url[i] == '?') return 1; /* relative */ + /* Find the first scheme-terminating character. */ + size_t scheme_end = (size_t)-1; + for (size_t j = i; j < len; j++) { + char c = url[j]; + if (c == ':') { scheme_end = j; break; } + if (c == '/' || c == '?' || c == '#') break; + } + if (scheme_end == (size_t)-1) return 1; /* no colon → relative path */ + /* Lowercase the scheme, stripping embedded control bytes. */ + char scheme[32]; + size_t sl = 0; + for (size_t j = i; j < scheme_end && sl < sizeof(scheme) - 1; j++) { + unsigned char c = (unsigned char)url[j]; + if (c == '\t' || c == '\n' || c == '\r' || c == 0x0B || c == 0x0C) continue; + scheme[sl++] = (char)html_tolower(c); + } + scheme[sl] = '\0'; + if (strcmp(scheme, "http") == 0) return 1; + if (strcmp(scheme, "https") == 0) return 1; + if (strcmp(scheme, "mailto") == 0) return 1; + return 0; +} + +el_val_t el_html_sanitize(el_val_t input_v, el_val_t allowlist_v) { + const char* input = EL_CSTR(input_v); + const char* allow = EL_CSTR(allowlist_v); + if (!input) return el_wrap_str(el_strdup("")); + if (!allow) allow = "{}"; + size_t in_len = strlen(input); + + html_buf_t out; + html_buf_init(&out); + + size_t i = 0; + while (i < in_len) { + unsigned char c = (unsigned char)input[i]; + if (c != '<') { + /* Plain text — escape and emit. We pass `&` through verbatim + * to preserve pre-encoded entities (`<`, `&`, `&#x...;`) + * which the browser will decode safely. */ + if (c == '&') html_buf_putc(&out, '&'); + else html_escape_byte(&out, c); + i++; + continue; + } + /* `<` — try to parse a tag. */ + if (i + 1 >= in_len) { + html_buf_puts(&out, "<"); + i++; + continue; + } + /* Comments, doctype, CDATA, processing instructions — drop entirely. */ + if (input[i + 1] == '!') { + if (i + 3 < in_len && input[i + 2] == '-' && input[i + 3] == '-') { + size_t j = i + 4; + while (j + 2 < in_len && !(input[j] == '-' && input[j + 1] == '-' && input[j + 2] == '>')) j++; + if (j + 2 < in_len) i = j + 3; + else i = in_len; + continue; + } + size_t j = i + 2; + while (j < in_len && input[j] != '>') j++; + i = (j < in_len) ? j + 1 : in_len; + continue; + } + if (input[i + 1] == '?') { + size_t j = i + 2; + while (j < in_len && input[j] != '>') j++; + i = (j < in_len) ? j + 1 : in_len; + continue; + } + int is_close = 0; + size_t name_start = i + 1; + if (input[i + 1] == '/') { + is_close = 1; + name_start = i + 2; + } + if (name_start >= in_len) { + html_buf_puts(&out, "<"); + i++; + continue; + } + unsigned char nc = (unsigned char)input[name_start]; + if (!((nc >= 'a' && nc <= 'z') || (nc >= 'A' && nc <= 'Z'))) { + /* `<` followed by non-letter — emit as escaped text. */ + html_buf_puts(&out, "<"); + i++; + continue; + } + size_t name_end = name_start; + while (name_end < in_len) { + unsigned char x = (unsigned char)input[name_end]; + if ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || + (x >= '0' && x <= '9') || x == '-' || x == '_' || x == ':') { + name_end++; + } else { + break; + } + } + const char* tag = input + name_start; + size_t tag_len = name_end - name_start; + /* Find the `>` that closes this tag, respecting quoted attrs. */ + size_t cur = name_end; + int self_close = 0; + while (cur < in_len) { + unsigned char x = (unsigned char)input[cur]; + if (x == '"' || x == '\'') { + unsigned char q = x; + cur++; + while (cur < in_len && (unsigned char)input[cur] != q) cur++; + if (cur < in_len) cur++; /* skip closing quote */ + continue; + } + if (x == '/' && cur + 1 < in_len && input[cur + 1] == '>') { + self_close = 1; + break; + } + if (x == '>') break; + cur++; + } + if (cur >= in_len) { + /* Malformed: unclosed tag at EOF. Drop the rest of the input. */ + i = in_len; + continue; + } + size_t tag_end = self_close ? cur + 2 : cur + 1; /* one past `>` */ + /* Dangerous container — drop the whole subtree. */ + if (!is_close && html_is_dangerous_container(tag, tag_len)) { + if (self_close || html_is_void(tag, tag_len)) { + i = tag_end; + continue; + } + size_t scan = tag_end; + int found_close = 0; + while (scan < in_len) { + if (input[scan] != '<') { scan++; continue; } + if (scan + 1 < in_len && input[scan + 1] == '/') { + size_t cn_start = scan + 2; + size_t cn_end = cn_start; + while (cn_end < in_len) { + unsigned char x = (unsigned char)input[cn_end]; + if ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || + (x >= '0' && x <= '9') || x == '-' || x == '_' || x == ':') { + cn_end++; + } else break; + } + if (cn_end - cn_start == tag_len && + html_iemem(input + cn_start, tag, tag_len)) { + size_t end_close = cn_end; + while (end_close < in_len && input[end_close] != '>') end_close++; + i = (end_close < in_len) ? end_close + 1 : in_len; + found_close = 1; + break; + } + } + scan++; + } + if (!found_close) { + /* No matching close — drop everything from here on. */ + i = in_len; + } + continue; + } + /* Look up the tag in the allowlist. */ + size_t arr_len = 0; + const char* arr = html_allowlist_find(allow, tag, tag_len, &arr_len); + if (!arr) { + /* Tag not allowed. Drop the open/close marker; inner text is + * processed by the outer loop and re-emitted as escaped text. */ + i = tag_end; + continue; + } + if (is_close) { + if (!html_is_void(tag, tag_len)) { + html_buf_putc(&out, '<'); + html_buf_putc(&out, '/'); + for (size_t k = 0; k < tag_len; k++) { + html_buf_putc(&out, (char)html_tolower((unsigned char)tag[k])); + } + html_buf_putc(&out, '>'); + } + i = tag_end; + continue; + } + /* Allowed open tag. Emit ``. */ + html_buf_putc(&out, '<'); + for (size_t k = 0; k < tag_len; k++) { + html_buf_putc(&out, (char)html_tolower((unsigned char)tag[k])); + } + size_t a = name_end; + while (a < cur) { + unsigned char x = (unsigned char)input[a]; + if (x == ' ' || x == '\t' || x == '\n' || x == '\r' || x == '/') { a++; continue; } + size_t an_start = a; + while (a < cur) { + unsigned char y = (unsigned char)input[a]; + if (y == '=' || y == ' ' || y == '\t' || y == '\n' || y == '\r' || y == '/' || y == '>') break; + a++; + } + size_t an_len = a - an_start; + if (an_len == 0) { a++; continue; } + size_t av_start = 0; + size_t av_len = 0; + int has_value = 0; + size_t b = a; + while (b < cur && (input[b] == ' ' || input[b] == '\t' || input[b] == '\n' || input[b] == '\r')) b++; + if (b < cur && input[b] == '=') { + has_value = 1; + b++; + while (b < cur && (input[b] == ' ' || input[b] == '\t' || input[b] == '\n' || input[b] == '\r')) b++; + if (b < cur && (input[b] == '"' || input[b] == '\'')) { + unsigned char q = (unsigned char)input[b]; + b++; + av_start = b; + while (b < cur && (unsigned char)input[b] != q) b++; + av_len = b - av_start; + if (b < cur) b++; + } else { + av_start = b; + while (b < cur) { + unsigned char y = (unsigned char)input[b]; + if (y == ' ' || y == '\t' || y == '\n' || y == '\r' || y == '>') break; + b++; + } + av_len = b - av_start; + } + a = b; + } + if (!html_attr_in_array(arr, arr_len, input + an_start, an_len)) continue; + int is_href = (an_len == 4 && html_iemem(input + an_start, "href", 4)); + int is_src = (an_len == 3 && html_iemem(input + an_start, "src", 3)); + if ((is_href || is_src) && has_value) { + if (!html_url_is_safe(input + av_start, av_len)) continue; + } + html_buf_putc(&out, ' '); + for (size_t k = 0; k < an_len; k++) { + html_buf_putc(&out, (char)html_tolower((unsigned char)input[an_start + k])); + } + if (has_value) { + html_buf_puts(&out, "=\""); + for (size_t k = 0; k < av_len; k++) { + unsigned char y = (unsigned char)input[av_start + k]; + /* Re-escape so the emitted attribute is well-formed + * double-quoted HTML. `&` passes through to preserve + * pre-encoded entities. */ + if (y == '"') html_buf_puts(&out, """); + else if (y == '<') html_buf_puts(&out, "<"); + else if (y == '>') html_buf_puts(&out, ">"); + else html_buf_putc(&out, (char)y); + } + html_buf_putc(&out, '"'); + } + } + html_buf_putc(&out, '>'); + i = tag_end; + } + /* Copy into arena-tracked buffer so the standard runtime memory model + * applies to the returned string. */ + char* result = el_strbuf(out.len); + memcpy(result, out.data, out.len); + result[out.len] = '\0'; + html_buf_free(&out); + return el_wrap_str(result); +} + +/* ── JSON ────────────────────────────────────────────────────────────────── */ + +/* True iff the segment is non-empty and every byte is an ASCII digit. We treat + * such segments as numeric array indices when walking a dot-path; mixed names + * like "0a" remain object-key lookups, so a key named "0" still wins over an + * index when the surrounding container is an object. */ +static int json_path_seg_is_index(const char* seg, size_t n) { + if (n == 0) return 0; + for (size_t i = 0; i < n; i++) { + if (seg[i] < '0' || seg[i] > '9') return 0; + } + return 1; +} + +/* Skip JSON whitespace. */ +static const char* json_skip_ws(const char* p) { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + return p; +} + +/* Descend one segment into the JSON cursor `p`. + * - If `p` points at an array `[...]` and the segment is all digits, + * advance to that element (zero-based). + * - Otherwise treat the segment as an object key and use json_find_key + * scoped to a one-level slice of the current container. + * Returns NULL if the descent fails (segment not found, container mismatch). + * + * `seg` is a pointer into the original path string and `seg_len` is its + * byte length — this avoids an extra alloc per segment. */ +static const char* json_path_descend(const char* p, const char* seg, size_t seg_len) { + if (!p || !seg) return NULL; + p = json_skip_ws(p); + if (*p == '[' && json_path_seg_is_index(seg, seg_len)) { + long idx = 0; + for (size_t i = 0; i < seg_len; i++) idx = idx * 10 + (seg[i] - '0'); + p++; /* step past '[' */ + p = json_skip_ws(p); + long cur = 0; + while (*p && *p != ']') { + if (cur == idx) return p; + const char* end = json_skip_value(p); + if (!end || end == p) return NULL; + p = json_skip_ws(end); + if (*p == ',') { p++; p = json_skip_ws(p); cur++; continue; } + /* No comma after this element — only acceptable at the closing ']', + * which means we ran out of elements. */ + break; + } + return NULL; + } + /* Object lookup. json_find_key walks at depth 1 of whatever container it + * receives, so we slice from `p` onwards. Caller already positioned us at + * the opening '{' (or at whitespace before it). */ + if (*p != '{') return NULL; + /* Build a NUL-terminated copy of the key segment for the lookup. We only + * pay this cost when the segment isn't a numeric index. */ + char stack_key[256]; + char* k = stack_key; + if (seg_len + 1 > sizeof(stack_key)) { + k = malloc(seg_len + 1); + if (!k) return NULL; + } + memcpy(k, seg, seg_len); + k[seg_len] = '\0'; + const char* found = json_find_key(p, k); + if (k != stack_key) free(k); + return found; +} + +/* Read the JSON value at `p` into a freshly-allocated, arena-owned el_val_t. + * - String -> unescaped, wrapped el_val_t string + * - Anything else -> raw JSON slice as a string (matches the historical + * json_get behaviour: numbers/bools/null come back stringified). */ +static el_val_t json_read_value(const char* p) { + p = json_skip_ws(p); + if (*p == '"') { + p++; + size_t cap = strlen(p) + 1; + char* out = el_strbuf(cap); + char* w = out; + while (*p && *p != '"') { + if (*p == '\\' && *(p+1)) { + p++; + switch (*p) { + case '"': *w++ = '"'; break; + case '\\': *w++ = '\\'; break; + case '/': *w++ = '/'; break; + case 'n': *w++ = '\n'; break; + case 'r': *w++ = '\r'; break; + case 't': *w++ = '\t'; break; + default: *w++ = *p; break; + } + } else { + *w++ = *p; + } + p++; + } + *w = '\0'; + return el_wrap_str(out); + } + /* Object/array/number/bool/null — return the raw slice up to the value's + * end. json_skip_value tracks brace/bracket/string state so nested objects + * round-trip cleanly. */ + const char* end = json_skip_value(p); + if (!end) end = p; + size_t n = (size_t)(end - p); + /* Strip trailing whitespace from scalar values so callers don't see + * `123 ` when they parsed a pretty-printed number. */ + while (n > 0 && (p[n-1] == ' ' || p[n-1] == '\t' || p[n-1] == '\n' || p[n-1] == '\r')) { + n--; + } + char* out = el_strbuf(n); + memcpy(out, p, n); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t json_get(el_val_t jsonv, el_val_t keyv) { + const char* json = EL_CSTR(jsonv); + const char* key = EL_CSTR(keyv); + if (!json || !key) return el_wrap_str(el_strdup("")); + + /* Fast path: key contains no '.' — keep the historical single-segment + * substring search so existing callers retain their O(strlen) cost + * profile. The dot-path walker is only paid for when needed. */ + if (!strchr(key, '.')) { + size_t klen = strlen(key); + char stack_pat[512]; + char* pattern; + if (klen + 5 <= sizeof(stack_pat)) { + pattern = stack_pat; + } else { + pattern = malloc(klen + 5); + if (!pattern) return el_wrap_str(el_strdup("")); + } + snprintf(pattern, klen + 5, "\"%s\":", key); + const char* p = strstr(json, pattern); + if (pattern != stack_pat) free(pattern); + if (!p) return el_wrap_str(el_strdup("")); + p += strlen(key) + 3; /* skip "key": */ + return json_read_value(p); + } + + /* Dot-path traversal. Walk segments left to right; at each step, descend + * into the current container by either array index (all-digit segment on + * an array cursor) or object key. */ + const char* cursor = json_skip_ws(json); + const char* seg_start = key; + const char* k = key; + while (1) { + if (*k == '.' || *k == '\0') { + size_t seg_len = (size_t)(k - seg_start); + cursor = json_path_descend(cursor, seg_start, seg_len); + if (!cursor) return el_wrap_str(el_strdup("")); + if (*k == '\0') break; + k++; + seg_start = k; + continue; + } + k++; + } + return json_read_value(cursor); +} + +/* ── Float bit-cast helpers ──────────────────────────────────────────────── */ +/* `el_to_float` and `el_from_float` are exposed in el_runtime.h as static + * inlines so generated programs (which #include the header) can call them + * for Float literals. No definitions are needed here. */ + +/* ── JSON parser (recursive descent) ─────────────────────────────────────── */ +/* + * Parsed JSON representation: + * - object -> ElMap (keys & values are el_val_t) + * - array -> ElList + * - string -> EL_STR-wrapped char* (allocated) + * - number -> int (el_val_t) if integer, otherwise el_from_float(double) + * - true -> 1 + * - false -> 0 + * - null -> EL_NULL (0) + * + * Note: there is no runtime type tag — parsed numbers cannot be + * distinguished from booleans by the runtime alone. The codegen tracks + * types separately. This matches the rest of el_val_t's type-erased model. + */ + +/* JsonParser struct is forward-declared near the HTTP/Engram section. */ + +static void jp_skip_ws(JsonParser* jp) { + while (jp->p < jp->end) { + char c = *jp->p; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') jp->p++; + else break; + } +} + +static el_val_t jp_parse_value(JsonParser* jp); + +/* Parse a JSON string literal (the opening " has NOT yet been consumed). */ +static char* jp_parse_string_raw(JsonParser* jp) { + if (jp->p >= jp->end || *jp->p != '"') { jp->err = 1; return el_strdup(""); } + jp->p++; + size_t cap = 32, len = 0; + char* out = malloc(cap); + if (!out) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + while (jp->p < jp->end && *jp->p != '"') { + char c = *jp->p++; + if (c == '\\' && jp->p < jp->end) { + char esc = *jp->p++; + switch (esc) { + case '"': c = '"'; break; + case '\\': c = '\\'; break; + case '/': c = '/'; break; + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'u': { + /* Skip 4 hex digits; emit '?' as a placeholder */ + for (int i = 0; i < 4 && jp->p < jp->end; i++) jp->p++; + c = '?'; + break; + } + default: c = esc; break; + } + } + if (len + 1 >= cap) { + cap *= 2; + out = realloc(out, cap); + if (!out) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + } + out[len++] = c; + } + if (jp->p < jp->end && *jp->p == '"') jp->p++; + else jp->err = 1; + out[len] = '\0'; + return out; +} + +static el_val_t jp_parse_number(JsonParser* jp) { + const char* start = jp->p; + int is_float = 0; + if (jp->p < jp->end && (*jp->p == '-' || *jp->p == '+')) jp->p++; + while (jp->p < jp->end && isdigit((unsigned char)*jp->p)) jp->p++; + if (jp->p < jp->end && *jp->p == '.') { + is_float = 1; jp->p++; + while (jp->p < jp->end && isdigit((unsigned char)*jp->p)) jp->p++; + } + if (jp->p < jp->end && (*jp->p == 'e' || *jp->p == 'E')) { + is_float = 1; jp->p++; + if (jp->p < jp->end && (*jp->p == '+' || *jp->p == '-')) jp->p++; + while (jp->p < jp->end && isdigit((unsigned char)*jp->p)) jp->p++; + } + size_t n = (size_t)(jp->p - start); + char buf[64]; + if (n >= sizeof(buf)) n = sizeof(buf) - 1; + memcpy(buf, start, n); + buf[n] = '\0'; + if (is_float) return el_from_float(strtod(buf, NULL)); + return (el_val_t)strtoll(buf, NULL, 10); +} + +static el_val_t jp_parse_array(JsonParser* jp) { + if (jp->p < jp->end && *jp->p == '[') jp->p++; + el_val_t lst = el_list_empty(); + jp_skip_ws(jp); + if (jp->p < jp->end && *jp->p == ']') { jp->p++; return lst; } + while (jp->p < jp->end) { + jp_skip_ws(jp); + el_val_t v = jp_parse_value(jp); + lst = el_list_append(lst, v); + jp_skip_ws(jp); + if (jp->p < jp->end && *jp->p == ',') { jp->p++; continue; } + if (jp->p < jp->end && *jp->p == ']') { jp->p++; break; } + jp->err = 1; + break; + } + return lst; +} + +static el_val_t jp_parse_object(JsonParser* jp) { + if (jp->p < jp->end && *jp->p == '{') jp->p++; + el_val_t m = el_map_new(0); + jp_skip_ws(jp); + if (jp->p < jp->end && *jp->p == '}') { jp->p++; return m; } + while (jp->p < jp->end) { + jp_skip_ws(jp); + char* key = jp_parse_string_raw(jp); + jp_skip_ws(jp); + if (jp->p < jp->end && *jp->p == ':') jp->p++; + else { jp->err = 1; free(key); break; } + jp_skip_ws(jp); + el_val_t v = jp_parse_value(jp); + m = el_map_set(m, EL_STR(key), v); + jp_skip_ws(jp); + if (jp->p < jp->end && *jp->p == ',') { jp->p++; continue; } + if (jp->p < jp->end && *jp->p == '}') { jp->p++; break; } + jp->err = 1; + break; + } + return m; +} + +static el_val_t jp_parse_value(JsonParser* jp) { + jp_skip_ws(jp); + if (jp->p >= jp->end) { jp->err = 1; return EL_NULL; } + char c = *jp->p; + if (c == '"') return el_wrap_str(jp_parse_string_raw(jp)); + if (c == '{') return jp_parse_object(jp); + if (c == '[') return jp_parse_array(jp); + if (c == '-' || isdigit((unsigned char)c)) return jp_parse_number(jp); + if (c == 't' && jp->p + 4 <= jp->end && strncmp(jp->p, "true", 4) == 0) { jp->p += 4; return 1; } + if (c == 'f' && jp->p + 5 <= jp->end && strncmp(jp->p, "false", 5) == 0) { jp->p += 5; return 0; } + if (c == 'n' && jp->p + 4 <= jp->end && strncmp(jp->p, "null", 4) == 0) { jp->p += 4; return EL_NULL; } + jp->err = 1; + return EL_NULL; +} + +el_val_t json_parse(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return EL_NULL; + JsonParser jp = { .p = s, .end = s + strlen(s), .err = 0 }; + el_val_t v = jp_parse_value(&jp); + if (jp.err) return EL_NULL; + return v; +} + +/* ── JSON stringify ──────────────────────────────────────────────────────── */ +/* + * Stringify policy: el_val_t is type-erased, so we cannot perfectly + * round-trip arbitrary values. We use these heuristics: + * - If value is an ElList pointer (in the heap range), serialize as array. + * - If value is an ElMap pointer, serialize as object. + * - If value looks like a printable string pointer, serialize as string. + * - Otherwise serialize as integer. + * This is best-effort. Programs that need exact control should build the + * string directly. A pointer test is the cheapest way to disambiguate + * from small integers without a separate type tag. + */ + +/* JsonBuf struct is forward-declared near the HTTP section so HTTP helpers + * can use it. Its definition appears there. */ + +static void jb_init(JsonBuf* b) { + b->cap = 64; b->len = 0; + b->buf = malloc(b->cap); + if (!b->buf) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + b->buf[0] = '\0'; +} + +static void jb_reserve(JsonBuf* b, size_t add) { + if (b->len + add + 1 > b->cap) { + while (b->len + add + 1 > b->cap) b->cap *= 2; + b->buf = realloc(b->buf, b->cap); + if (!b->buf) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + } +} + +static void jb_putc(JsonBuf* b, char c) { + jb_reserve(b, 1); + b->buf[b->len++] = c; + b->buf[b->len] = '\0'; +} + +static void jb_puts(JsonBuf* b, const char* s) { + size_t n = strlen(s); + jb_reserve(b, n); + memcpy(b->buf + b->len, s, n); + b->len += n; + b->buf[b->len] = '\0'; +} + +static void jb_emit_escaped(JsonBuf* b, const char* s) { + jb_putc(b, '"'); + for (; *s; s++) { + unsigned char c = (unsigned char)*s; + switch (c) { + case '"': jb_puts(b, "\\\""); break; + case '\\': jb_puts(b, "\\\\"); break; + case '\b': jb_puts(b, "\\b"); break; + case '\f': jb_puts(b, "\\f"); break; + case '\n': jb_puts(b, "\\n"); break; + case '\r': jb_puts(b, "\\r"); break; + case '\t': jb_puts(b, "\\t"); break; + default: + if (c < 0x20) { + char tmp[8]; + snprintf(tmp, sizeof(tmp), "\\u%04x", c); + jb_puts(b, tmp); + } else { + jb_putc(b, (char)c); + } + break; + } + } + jb_putc(b, '"'); +} + +/* Heuristic: is this el_val_t likely a pointer to an ElList? + * We can't fully verify, but pointers are large addresses, integers small. + * Treat values whose magnitude exceeds 2^32 as potential pointers and + * sniff by reading the header conservatively. + * + * Simpler heuristic: if the value reads as a printable string, treat as + * string; otherwise as integer. Lists/Maps are encoded as struct pointers, + * which have leading binary bytes — so they won't look like strings. */ + +static int looks_like_string(el_val_t v) { + if (v == 0) return 0; + /* Treat plausible heap addresses as candidates. + * Threshold: 4 GiB (0x100000000). On 64-bit systems heap addresses from + * malloc/mmap start well above 4 GiB (ASLR pushes them to ~0x7f...). + * El integer values (counters, unix timestamps up to ~2106) all fit below + * 0x100000000 (4294967296). The old threshold of 1,000,000 caused unix + * timestamps (~1.7e9) to be misidentified as string pointers — a segfault + * risk in json_stringify and jb_emit_value. */ + uintptr_t p = (uintptr_t)v; + if (p < 0x100000000ULL) return 0; /* integers, timestamps, counters */ + if (p < 0x1000) return 0; + /* Sniff first bytes for printable */ + const unsigned char* s = (const unsigned char*)p; + for (int i = 0; i < 16; i++) { + unsigned char c = s[i]; + if (c == '\0') return 1; /* terminated string (empty string is still a valid string) */ + /* Reject C0 control chars (non-whitespace), allow UTF-8 high bytes. + * 0x09-0x0d = tab/newline/cr/vt/ff (whitespace, OK) + * 0x20-0x7e = printable ASCII (OK) + * 0x7f = DEL (reject) + * 0x80-0xff = UTF-8 continuation/lead bytes (OK for multi-byte chars) */ + if (c < 0x09 || (c > 0x0d && c < 0x20) || c == 0x7f) return 0; + } + return 1; /* 16+ printable bytes — call it a string */ +} + +static void jb_emit_value(JsonBuf* b, el_val_t v); + +static void jb_emit_int(JsonBuf* b, int64_t n) { + char tmp[32]; + snprintf(tmp, sizeof(tmp), "%lld", (long long)n); + jb_puts(b, tmp); +} + +static void jb_emit_value(JsonBuf* b, el_val_t v) { + if (v == EL_NULL) { jb_puts(b, "null"); return; } + if (looks_like_string(v)) { + jb_emit_escaped(b, EL_CSTR(v)); + return; + } + jb_emit_int(b, (int64_t)v); +} + +el_val_t json_stringify(el_val_t v) { + JsonBuf b; jb_init(&b); + jb_emit_value(&b, v); + return el_wrap_str(b.buf); +} + +/* ── JSON substring accessors ────────────────────────────────────────────── */ +/* + * These walk the raw JSON string looking for "key": at the top level (depth 1) + * of an object. They handle escaped quotes, nested objects/arrays, and + * whitespace around the colon. + */ + +/* Find "key": at object-depth == 1 inside the JSON object string `s`. + * Returns pointer to the first byte of the value, or NULL. */ +static const char* json_find_key(const char* s, const char* key) { + if (!s || !key) return NULL; + size_t klen = strlen(key); + int depth = 0; + int in_str = 0; + int escape = 0; + const char* p = s; + while (*p) { + char c = *p; + if (in_str) { + if (escape) { escape = 0; } + else if (c == '\\') { escape = 1; } + else if (c == '"') { + /* End of string. If we're at depth 1, check if this was a key. */ + p++; + if (depth == 1) { + /* The string just ended at p-1. Check if it matches key + * and is followed by a colon. We need to backtrack to find + * the start of this string and compare. */ + } + in_str = 0; + continue; + } + p++; + continue; + } + if (c == '"') { + /* Start of a string literal */ + const char* str_start = p + 1; + const char* q = str_start; + int e = 0; + while (*q) { + if (e) { e = 0; q++; continue; } + if (*q == '\\') { e = 1; q++; continue; } + if (*q == '"') break; + q++; + } + size_t slen = (size_t)(q - str_start); + const char* after = (*q == '"') ? q + 1 : q; + /* If at depth 1 and matches key and followed by ':' -> got it */ + if (depth == 1 && slen == klen && strncmp(str_start, key, klen) == 0) { + const char* r = after; + while (*r == ' ' || *r == '\t' || *r == '\n' || *r == '\r') r++; + if (*r == ':') { + r++; + while (*r == ' ' || *r == '\t' || *r == '\n' || *r == '\r') r++; + return r; + } + } + p = after; + continue; + } + if (c == '{' || c == '[') depth++; + else if (c == '}' || c == ']') depth--; + p++; + } + return NULL; +} + +/* Skip a JSON value starting at p; return pointer past the value end. */ +static const char* json_skip_value(const char* p) { + if (!p || !*p) return p; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p == '"') { + p++; + int e = 0; + while (*p) { + if (e) { e = 0; p++; continue; } + if (*p == '\\') { e = 1; p++; continue; } + if (*p == '"') { p++; break; } + p++; + } + return p; + } + if (*p == '{' || *p == '[') { + char open = *p; + char close = (open == '{') ? '}' : ']'; + int depth = 0; + int in_str = 0; + int e = 0; + while (*p) { + char c = *p; + if (in_str) { + if (e) { e = 0; } + else if (c == '\\') { e = 1; } + else if (c == '"') in_str = 0; + p++; + continue; + } + if (c == '"') { in_str = 1; p++; continue; } + if (c == open) depth++; + else if (c == close) { depth--; p++; if (depth == 0) return p; continue; } + p++; + } + return p; + } + /* scalar: number, true/false/null */ + while (*p && *p != ',' && *p != '}' && *p != ']' && + *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r') p++; + return p; +} + +el_val_t json_get_string(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + if (!p || *p != '"') return el_wrap_str(el_strdup("")); + p++; + JsonParser jp = { .p = p - 1, .end = json + (json ? strlen(json) : 0), .err = 0 }; + char* parsed = jp_parse_string_raw(&jp); + if (jp.err) { free(parsed); return el_wrap_str(el_strdup("")); } + return el_wrap_str(parsed); +} + +el_val_t json_get_int(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + if (!p) return 0; + if (*p == '"' || *p == '{' || *p == '[') return 0; + return (el_val_t)strtoll(p, NULL, 10); +} + +el_val_t json_get_float(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + if (!p) return 0; + if (*p == '"' || *p == '{' || *p == '[') return 0; + return el_from_float(strtod(p, NULL)); +} + +el_val_t json_get_bool(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + if (!p) return 0; + if (strncmp(p, "true", 4) == 0) return 1; + return 0; +} + +el_val_t json_get_raw(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + /* Clear fs_read binary-length hint — result is a fresh null-terminated + * string, not the raw file bytes, so Content-Length must use strlen. */ + _tl_fs_read_len = 0; + if (!p) return el_wrap_str(el_strdup("")); + const char* end = json_skip_value(p); + size_t n = (size_t)(end - p); + char* out = el_strbuf(n); + memcpy(out, p, n); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t json_set(el_val_t json_str, el_val_t key, el_val_t value) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + /* raw_val is the JSON value as-is (already encoded by the caller). + * If it looks like a plain (non-JSON) string, wrap it as a JSON string. + * Convention: callers pass pre-encoded values like "\"bob\"" for strings, + * "42" for numbers, "true"/"false" for booleans. */ + const char* raw_val = EL_CSTR(value); + if (!k) k = ""; + if (!raw_val) raw_val = "null"; + if (!json || !*json) { + /* Build a fresh object */ + JsonBuf b; jb_init(&b); + jb_putc(&b, '{'); + jb_emit_escaped(&b, k); + jb_putc(&b, ':'); + jb_puts(&b, raw_val); + jb_putc(&b, '}'); + return el_wrap_str(b.buf); + } + const char* existing = json_find_key(json, k); + JsonBuf b; jb_init(&b); + if (existing) { + const char* end = json_skip_value(existing); + /* Copy [json .. existing) */ + size_t prefix = (size_t)(existing - json); + jb_reserve(&b, prefix); + memcpy(b.buf + b.len, json, prefix); + b.len += prefix; + b.buf[b.len] = '\0'; + jb_puts(&b, raw_val); + jb_puts(&b, end); + return el_wrap_str(b.buf); + } + /* Insert before closing '}'. Find last '}' */ + size_t jl = strlen(json); + if (jl == 0) { free(b.buf); return el_wrap_str(el_strdup("{}")); } + /* Find last '}' from the end */ + ssize_t close_idx = -1; + for (ssize_t i = (ssize_t)jl - 1; i >= 0; i--) { + if (json[i] == '}') { close_idx = i; break; } + } + if (close_idx < 0) { + free(b.buf); + return el_wrap_str(el_strdup(json)); + } + /* Determine if object is empty: scan between last '{' and '}' for non-ws */ + int empty = 1; + for (ssize_t i = close_idx - 1; i >= 0; i--) { + char c = json[i]; + if (c == '{') break; + if (c != ' ' && c != '\t' && c != '\n' && c != '\r') { empty = 0; break; } + } + /* Copy json[0..close_idx) */ + jb_reserve(&b, (size_t)close_idx); + memcpy(b.buf + b.len, json, (size_t)close_idx); + b.len += (size_t)close_idx; + b.buf[b.len] = '\0'; + if (!empty) jb_putc(&b, ','); + jb_emit_escaped(&b, k); + jb_putc(&b, ':'); + jb_puts(&b, raw_val); + /* Append from close_idx onward */ + jb_puts(&b, json + close_idx); + return el_wrap_str(b.buf); +} + +el_val_t json_array_len(el_val_t json_str) { + const char* s = EL_CSTR(json_str); + if (!s) return 0; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s != '[') return 0; + s++; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ']') return 0; + int64_t count = 0; + while (*s) { + const char* end = json_skip_value(s); + if (end == s) break; + count++; + s = end; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ',') { s++; continue; } + if (*s == ']' || *s == '\0') break; + } + return (el_val_t)count; +} + +/* json_array_get — return the i-th element of a JSON array as a JSON + * fragment string. Nested objects and arrays are returned verbatim + * (json_skip_value tracks brace/bracket depth so nested structures are + * preserved intact). Out-of-range index → "". */ +el_val_t json_array_get(el_val_t json_str, el_val_t index) { + const char* s = EL_CSTR(json_str); + int64_t idx = (int64_t)index; + if (!s || idx < 0) return el_wrap_str(el_strdup("")); + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s != '[') return el_wrap_str(el_strdup("")); + s++; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ']') return el_wrap_str(el_strdup("")); + int64_t i = 0; + while (*s) { + const char* start = s; + const char* end = json_skip_value(s); + if (end == s) break; + if (i == idx) { + size_t n = (size_t)(end - start); + char* out = el_strbuf(n); + memcpy(out, start, n); + out[n] = '\0'; + return el_wrap_str(out); + } + i++; + s = end; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ',') { s++; while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; continue; } + if (*s == ']' || *s == '\0') break; + } + return el_wrap_str(el_strdup("")); +} + +/* json_array_get_string — same as json_array_get, but assume the element + * is a JSON string and return the unquoted/unescaped value. Non-string + * elements yield "". */ +el_val_t json_array_get_string(el_val_t json_str, el_val_t index) { + el_val_t raw = json_array_get(json_str, index); + const char* s = EL_CSTR(raw); + if (!s || *s != '"') return el_wrap_str(el_strdup("")); + JsonParser jp = { + .p = s, + .end = s + strlen(s), + .err = 0, + }; + char* parsed = jp_parse_string_raw(&jp); + if (jp.err) { + free(parsed); + return el_wrap_str(el_strdup("")); + } + return el_wrap_str(parsed); +} + +/* json_escape_string — escape a string value for embedding in JSON. + * Returns the escaped content WITHOUT surrounding quotes. + * "say \"hello\"" -> "say \\\"hello\\\"" */ +el_val_t json_escape_string(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + /* Worst case: every char needs a 2-char escape. */ + char* out = malloc(n * 2 + 1); + if (!out) return el_wrap_str(el_strdup("")); + size_t j = 0; + for (size_t i = 0; i < n; i++) { + unsigned char c = (unsigned char)s[i]; + if (c == '"') { out[j++] = '\\'; out[j++] = '"'; } + else if (c == '\\') { out[j++] = '\\'; out[j++] = '\\'; } + else if (c == '\n') { out[j++] = '\\'; out[j++] = 'n'; } + else if (c == '\r') { out[j++] = '\\'; out[j++] = 'r'; } + else if (c == '\t') { out[j++] = '\\'; out[j++] = 't'; } + else { out[j++] = (char)c; } + } + out[j] = '\0'; + el_val_t result = el_wrap_str(el_strdup(out)); + free(out); + return result; +} + +/* json_build_object — build a JSON object from a flat key-value list. + * kvs is [key0, val0, key1, val1, ...]. Values are raw JSON (pass + * strings as "\"value\"" or use json_escape_string). */ +el_val_t json_build_object(el_val_t kvs) { + el_val_t list = kvs; + int64_t n = el_list_len(list); + JsonBuf b; jb_init(&b); + jb_putc(&b, '{'); + int first = 1; + for (int64_t i = 0; i + 1 < n; i += 2) { + el_val_t k = el_list_get(list, (el_val_t)i); + el_val_t v = el_list_get(list, (el_val_t)(i + 1)); + const char* ks = EL_CSTR(k); + const char* vs = EL_CSTR(v); + if (!ks || !vs) continue; + if (!first) jb_putc(&b, ','); + first = 0; + jb_putc(&b, '"'); + jb_puts(&b, ks); + jb_puts(&b, "\":\""); + /* escape the value string */ + size_t vn = strlen(vs); + for (size_t j = 0; j < vn; j++) { + unsigned char c = (unsigned char)vs[j]; + if (c == '"') { jb_putc(&b, '\\'); jb_putc(&b, '"'); } + else if (c == '\\') { jb_putc(&b, '\\'); jb_putc(&b, '\\'); } + else if (c == '\n') { jb_putc(&b, '\\'); jb_putc(&b, 'n'); } + else if (c == '\r') { jb_putc(&b, '\\'); jb_putc(&b, 'r'); } + else if (c == '\t') { jb_putc(&b, '\\'); jb_putc(&b, 't'); } + else { jb_putc(&b, (char)c); } + } + jb_putc(&b, '"'); + } + jb_putc(&b, '}'); + return el_wrap_str(b.buf); +} + +/* json_build_array — build a JSON array from a list of raw JSON values. + * items is ["\"alpha\"", "\"beta\"", "42", "true", ...]. */ +el_val_t json_build_array(el_val_t items) { + el_val_t list = items; + int64_t n = el_list_len(list); + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + for (int64_t i = 0; i < n; i++) { + el_val_t v = el_list_get(list, (el_val_t)i); + const char* vs = EL_CSTR(v); + if (!vs) continue; + if (i > 0) jb_putc(&b, ','); + jb_puts(&b, vs); + } + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +/* ── Time ────────────────────────────────────────────────────────────────── */ + +el_val_t time_now(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + int64_t ms = (int64_t)tv.tv_sec * 1000LL + (int64_t)tv.tv_usec / 1000LL; + return (el_val_t)ms; +} + +el_val_t time_now_utc(void) { + return time_now(); +} + +el_val_t time_format(el_val_t ts, el_val_t fmt) { + int64_t ms = (int64_t)ts; + time_t s = (time_t)(ms / 1000); + int msec = (int)(ms % 1000); + if (msec < 0) { msec += 1000; s -= 1; } + struct tm tm; + gmtime_r(&s, &tm); + const char* fmt_str = EL_CSTR(fmt); + if (!fmt_str || *fmt_str == '\0' || strcmp(fmt_str, "ISO") == 0) { + char buf[64]; + snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, msec); + return el_wrap_str(el_strdup(buf)); + } + char buf[256]; + if (strftime(buf, sizeof(buf), fmt_str, &tm) == 0) buf[0] = '\0'; + return el_wrap_str(el_strdup(buf)); +} + +el_val_t time_to_parts(el_val_t ts) { + int64_t ms = (int64_t)ts; + time_t s = (time_t)(ms / 1000); + int msec = (int)(ms % 1000); + if (msec < 0) { msec += 1000; s -= 1; } + struct tm tm; + gmtime_r(&s, &tm); + /* Return a JSON string so callers can use json_get to extract fields. */ + char buf[256]; + snprintf(buf, sizeof(buf), + "{\"year\":%d,\"month\":%d,\"day\":%d,\"hour\":%d,\"minute\":%d,\"second\":%d,\"ms\":%d}", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, msec); + return el_wrap_str(el_strdup(buf)); +} + +el_val_t time_from_parts(el_val_t secs, el_val_t ns, el_val_t tz) { + (void)tz; + int64_t s = (int64_t)secs; + int64_t n = (int64_t)ns; + int64_t ms = s * 1000LL + n / 1000000LL; + return (el_val_t)ms; +} + +el_val_t time_add(el_val_t ts, el_val_t n, el_val_t unit) { + const char* u = EL_CSTR(unit); + int64_t cur = (int64_t)ts; + int64_t d = (int64_t)n; + int64_t add_ms = d; + if (u) { + if (strcmp(u, "ms") == 0) add_ms = d; + else if (strcmp(u, "sec") == 0) add_ms = d * 1000LL; + else if (strcmp(u, "min") == 0) add_ms = d * 60000LL; + else if (strcmp(u, "hour") == 0) add_ms = d * 3600000LL; + else if (strcmp(u, "day") == 0) add_ms = d * 86400000LL; + } + return (el_val_t)(cur + add_ms); +} + +el_val_t time_diff(el_val_t ts1, el_val_t ts2, el_val_t unit) { + int64_t d = (int64_t)ts2 - (int64_t)ts1; + const char* u = EL_CSTR(unit); + if (!u || strcmp(u, "ms") == 0) return (el_val_t)d; + if (strcmp(u, "sec") == 0) return (el_val_t)(d / 1000LL); + if (strcmp(u, "min") == 0) return (el_val_t)(d / 60000LL); + if (strcmp(u, "hour") == 0) return (el_val_t)(d / 3600000LL); + if (strcmp(u, "day") == 0) return (el_val_t)(d / 86400000LL); + return (el_val_t)d; +} + +/* Block the calling thread for `secs` seconds. Negative values are clamped + * to 0. Used by El programs that poll external resources (e.g. RunPod + * /status, Engram readiness probes). */ +el_val_t sleep_secs(el_val_t secs) { + int64_t s = (int64_t)secs; + if (s < 0) s = 0; + struct timespec ts; + ts.tv_sec = (time_t)s; + ts.tv_nsec = 0; + nanosleep(&ts, NULL); + return 0; +} + +el_val_t sleep_ms(el_val_t ms) { + int64_t m = (int64_t)ms; + if (m < 0) m = 0; + struct timespec ts; + ts.tv_sec = (time_t)(m / 1000LL); + ts.tv_nsec = (long)((m % 1000LL) * 1000000LL); + nanosleep(&ts, NULL); + return 0; +} + +/* ── Instant + Duration: first-class temporal types ────────────────────────── + * El's substrate (Neuron) is a temporal cognition system. Memory salience + * decay, the six-tier pacemaker, TTL caches, and supersession are all + * temporal. Treating time as a raw Int (now() returning ms-since-epoch and + * arithmetic done with mixed unit literals) lets bugs through the type + * system: `(now - cached_at) < 60` cannot tell ms from sec, and `sleep(30)` + * is ambiguous. This block introduces two dedicated representations. + * + * Representation: + * Instant — int64 nanoseconds since the Unix epoch + * Duration — int64 nanoseconds (signed; negative durations are legal, + * e.g. when a deadline has passed) + * + * Both share the el_val_t (int64) slot the rest of the runtime uses, so no + * boxing / arena allocation is needed. Type discipline is enforced at the + * codegen layer: `let x: Duration = ...` registers `x` in __duration_names, + * and BinOp dispatches through typed wrappers (el_duration_add, etc.) that + * make intent explicit in the generated C. Mismatched ops (Instant+Instant, + * Duration+Int) are surfaced via #error directives at codegen time so the + * downstream cc step fails with a clear El-source-level message. + * + * Nanosecond precision matches POSIX clock_gettime / nanosleep granularity. + * 2^63 nanos covers ~292 years from epoch — comfortably past 2200, plenty + * for a memory-system runtime that never schedules outside a human lifespan. + */ + +/* now() — current Instant. Wraps clock_gettime(CLOCK_REALTIME) for nanosecond + * precision. Falls back to gettimeofday on systems where clock_gettime is + * unavailable (defensive — every supported platform has it). */ +el_val_t el_now_instant(void) { + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts) == 0) { + int64_t ns = (int64_t)ts.tv_sec * 1000000000LL + (int64_t)ts.tv_nsec; + return (el_val_t)ns; + } + struct timeval tv; + gettimeofday(&tv, NULL); + int64_t ns = (int64_t)tv.tv_sec * 1000000000LL + + (int64_t)tv.tv_usec * 1000LL; + return (el_val_t)ns; +} + +el_val_t now(void) { + return el_now_instant(); +} + +/* now_ns — return current Unix time as nanoseconds (Int). + * Thin wrapper over el_now_instant for use in test timing. */ +el_val_t now_ns(void) { + return el_now_instant(); +} + +/* unix_seconds(n) — Instant from a Unix-epoch second count. + * unix_millis(n) — Instant from a Unix-epoch millisecond count. */ +el_val_t unix_seconds(el_val_t n) { + int64_t s = (int64_t)n; + return (el_val_t)(s * 1000000000LL); +} + +el_val_t unix_millis(el_val_t n) { + int64_t m = (int64_t)n; + return (el_val_t)(m * 1000000LL); +} + +/* instant_from_iso8601 — parse a strict subset: + * YYYY-MM-DDTHH:MM:SS[.fff]Z + * Returns 0 (the Unix-epoch sentinel) on parse failure. Callers that need to + * distinguish epoch-zero from a parse error should use a wider sentinel + * representation; the current zero-on-failure choice matches existing El + * runtime conventions for parse builtins (str_to_int, parse_int). */ +el_val_t instant_from_iso8601(el_val_t s) { + const char* str = EL_CSTR(s); + if (!str) return (el_val_t)0; + int Y, M, D, h, m, sec, frac = 0; + int n = sscanf(str, "%d-%d-%dT%d:%d:%d.%3d", &Y, &M, &D, &h, &m, &sec, &frac); + if (n < 6) { + n = sscanf(str, "%d-%d-%dT%d:%d:%dZ", &Y, &M, &D, &h, &m, &sec); + if (n < 6) return (el_val_t)0; + } + struct tm tm; + memset(&tm, 0, sizeof(tm)); + tm.tm_year = Y - 1900; + tm.tm_mon = M - 1; + tm.tm_mday = D; + tm.tm_hour = h; + tm.tm_min = m; + tm.tm_sec = sec; + /* timegm — UTC. POSIX-Y but available on macOS and glibc. */ + time_t t = timegm(&tm); + if (t == (time_t)-1) return (el_val_t)0; + int64_t ns = (int64_t)t * 1000000000LL + (int64_t)frac * 1000000LL; + return (el_val_t)ns; +} + +/* Duration constructors. The El-side postfix literals (30.seconds, 1.hour) + * are lowered by the codegen directly into a literal int64 of nanoseconds — + * these constructors are for runtime values where the count is dynamic. */ +el_val_t el_duration_from_nanos(el_val_t ns) { + return (el_val_t)(int64_t)ns; +} + +el_val_t duration_seconds(el_val_t n) { + int64_t s = (int64_t)n; + return (el_val_t)(s * 1000000000LL); +} + +el_val_t duration_millis(el_val_t n) { + int64_t m = (int64_t)n; + return (el_val_t)(m * 1000000LL); +} + +el_val_t duration_nanos(el_val_t n) { + return (el_val_t)(int64_t)n; +} + +/* Arithmetic — typed wrappers. At the C level these are no-op casts, but + * the codegen routes Instant/Duration BinOps through them so the generated + * C says `el_instant_add_dur(start, dur)` rather than `start + dur`. The + * intent is explicit, the operand order is documented, and a future change + * to the underlying representation (saturating arithmetic, overflow guards) + * has a single chokepoint. */ +el_val_t el_instant_add_dur(el_val_t inst, el_val_t dur) { + return (el_val_t)((int64_t)inst + (int64_t)dur); +} + +el_val_t el_instant_sub_dur(el_val_t inst, el_val_t dur) { + return (el_val_t)((int64_t)inst - (int64_t)dur); +} + +el_val_t el_instant_diff(el_val_t a, el_val_t b) { + /* a - b — yields a Duration (negative if b is later than a). */ + return (el_val_t)((int64_t)a - (int64_t)b); +} + +el_val_t el_duration_add(el_val_t a, el_val_t b) { + return (el_val_t)((int64_t)a + (int64_t)b); +} + +el_val_t el_duration_sub(el_val_t a, el_val_t b) { + return (el_val_t)((int64_t)a - (int64_t)b); +} + +el_val_t el_duration_scale(el_val_t dur, el_val_t scalar) { + return (el_val_t)((int64_t)dur * (int64_t)scalar); +} + +el_val_t el_duration_div(el_val_t dur, el_val_t scalar) { + int64_t s = (int64_t)scalar; + if (s == 0) return (el_val_t)0; + return (el_val_t)((int64_t)dur / s); +} + +/* Comparisons. Return 1/0 in el_val_t convention. */ +el_val_t el_instant_lt(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a < (int64_t)b ? 1 : 0); } +el_val_t el_instant_le(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a <= (int64_t)b ? 1 : 0); } +el_val_t el_instant_gt(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a > (int64_t)b ? 1 : 0); } +el_val_t el_instant_ge(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a >= (int64_t)b ? 1 : 0); } +el_val_t el_instant_eq(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a == (int64_t)b ? 1 : 0); } +el_val_t el_instant_ne(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a != (int64_t)b ? 1 : 0); } +el_val_t el_duration_lt(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a < (int64_t)b ? 1 : 0); } +el_val_t el_duration_le(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a <= (int64_t)b ? 1 : 0); } +el_val_t el_duration_gt(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a > (int64_t)b ? 1 : 0); } +el_val_t el_duration_ge(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a >= (int64_t)b ? 1 : 0); } +el_val_t el_duration_eq(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a == (int64_t)b ? 1 : 0); } +el_val_t el_duration_ne(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a != (int64_t)b ? 1 : 0); } + +/* Conversions. */ +el_val_t instant_to_unix_seconds(el_val_t i) { + return (el_val_t)((int64_t)i / 1000000000LL); +} + +el_val_t instant_to_unix_millis(el_val_t i) { + return (el_val_t)((int64_t)i / 1000000LL); +} + +el_val_t instant_to_iso8601(el_val_t i) { + int64_t ns = (int64_t)i; + time_t s = (time_t)(ns / 1000000000LL); + int msec = (int)((ns / 1000000LL) % 1000LL); + if (msec < 0) { msec += 1000; s -= 1; } + struct tm tm; + gmtime_r(&s, &tm); + char buf[64]; + snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, msec); + return el_wrap_str(el_strdup(buf)); +} + +el_val_t duration_to_seconds(el_val_t d) { + return (el_val_t)((int64_t)d / 1000000000LL); +} + +el_val_t duration_to_millis(el_val_t d) { + return (el_val_t)((int64_t)d / 1000000LL); +} + +el_val_t duration_to_nanos(el_val_t d) { + return (el_val_t)(int64_t)d; +} + +/* sleep(Duration) — Phase 1 replacement for ambiguous sleep(Int). The runtime + * still exposes sleep_secs/sleep_ms for legacy call sites; codegen lowers + * sleep(Duration) to el_sleep_duration(d). Negative durations clamp to 0 so a + * stale deadline doesn't block forever. */ +el_val_t el_sleep_duration(el_val_t dur) { + int64_t ns = (int64_t)dur; + if (ns < 0) ns = 0; + struct timespec ts; + ts.tv_sec = (time_t)(ns / 1000000000LL); + ts.tv_nsec = (long)(ns % 1000000000LL); + nanosleep(&ts, NULL); + return (el_val_t)0; +} + +/* unix_timestamp() — back-compat. Existing El callers expect an Int seconds + * value; this stays an Int returner so the type system isn't disturbed for + * legacy code. New code should call now() and convert when needed. */ +el_val_t unix_timestamp(void) { + return instant_to_unix_seconds(el_now_instant()); +} + +/* TTL cache helpers. Backed by the existing process-wide K/V (state_set/get) + * with a sibling __ttl_set_at_ entry recording the Instant of the last + * write. ttl_cache_get returns "" if the entry is missing or stale, so call + * sites can branch on `if v == "" { miss } else { hit }` — the same shape + * existing get-with-default code uses. No more (now - cached_at) < 60. */ +el_val_t ttl_cache_set(el_val_t key, el_val_t value) { + const char* k = EL_CSTR(key); + if (!k) return (el_val_t)0; + /* Store the value at the user's key. */ + state_set(key, value); + /* Stamp set_at — opaque schema, namespaced under __ttl: prefix so user + * keys can't collide with stamps. */ + size_t klen = strlen(k); + char* stamp_key = (char*)malloc(klen + 16); + if (!stamp_key) return (el_val_t)0; + snprintf(stamp_key, klen + 16, "__ttl_at:%s", k); + int64_t now_ns = (int64_t)el_now_instant(); + char buf[32]; + snprintf(buf, sizeof(buf), "%lld", (long long)now_ns); + state_set(EL_STR(stamp_key), EL_STR(buf)); + free(stamp_key); + return (el_val_t)1; +} + +el_val_t ttl_cache_get(el_val_t key, el_val_t max_age) { + const char* k = EL_CSTR(key); + if (!k) return el_wrap_str(el_strdup("")); + /* Look up stamp. */ + size_t klen = strlen(k); + char* stamp_key = (char*)malloc(klen + 16); + if (!stamp_key) return el_wrap_str(el_strdup("")); + snprintf(stamp_key, klen + 16, "__ttl_at:%s", k); + el_val_t stamp = state_get(EL_STR(stamp_key)); + free(stamp_key); + const char* sv = EL_CSTR(stamp); + if (!sv || !*sv) return el_wrap_str(el_strdup("")); + int64_t set_at = (int64_t)atoll(sv); + int64_t now_ns = (int64_t)el_now_instant(); + int64_t age = now_ns - set_at; + int64_t max_ns = (int64_t)max_age; + if (age < 0) return el_wrap_str(el_strdup("")); /* clock skew — treat as miss */ + if (age > max_ns) return el_wrap_str(el_strdup("")); /* expired */ + return state_get(key); +} + +el_val_t ttl_cache_age(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return (el_val_t)INT64_MAX; + size_t klen = strlen(k); + char* stamp_key = (char*)malloc(klen + 16); + if (!stamp_key) return (el_val_t)INT64_MAX; + snprintf(stamp_key, klen + 16, "__ttl_at:%s", k); + el_val_t stamp = state_get(EL_STR(stamp_key)); + free(stamp_key); + const char* sv = EL_CSTR(stamp); + if (!sv || !*sv) return (el_val_t)INT64_MAX; + int64_t set_at = (int64_t)atoll(sv); + int64_t now_ns = (int64_t)el_now_instant(); + return (el_val_t)(now_ns - set_at); +} + +/* ── Calendar + CalendarTime + Rhythm + LocalDate/Time/DateTime ────────────── + * Phase 1.5. Calendar is pluggable: EarthCalendar (IANA zones + Gregorian + + * DST), MarsCalendar (sols, MTC), CycleCalendar(period), NoCycleCalendar, + * RelativeCalendar(epoch). Phase 1 zone wrapping folds INTO EarthCalendar; + * UTC and IANA zones are themselves Earth-parochial and cannot live at the + * lowest type layer. + * + * A Rhythm is a small AST that asks the Calendar for cycle phase, weekday, + * etc. Most rhythm logic is calendar-agnostic at runtime: rhythm_cycle_phase + * means "midpoint of cycle" whether the cycle is 24h on Earth or 30h on a + * station or 300y on a long-cycle world. */ + +/* Magic headers — used by the runtime to recognize boxed temporal values + * arriving through el_val_t. Distinct constants so accidental misuse fails + * loudly rather than silently. */ +#define EL_CAL_MAGIC 0xE1CA1EDDU +#define EL_CALTIME_MAGIC 0xE1CA1747U +#define EL_RHYTHM_MAGIC 0xE1287A11U +#define EL_LDATE_MAGIC 0xE1DA7E00U +#define EL_LDT_MAGIC 0xE1DA7E1DU +#define EL_ZONE_MAGIC 0xE12017E0U + +typedef enum { + EL_CALENDAR_EARTH = 1, + EL_CALENDAR_MARS = 2, + EL_CALENDAR_CYCLE = 3, + EL_CALENDAR_NO_CYCLE = 4, + EL_CALENDAR_RELATIVE = 5 +} el_calendar_kind_t; + +typedef struct { + uint32_t magic; + char* id; /* IANA name or "+HH:MM" / "-HH:MM" */ + int fixed; /* 1 for fixed offset, 0 for IANA */ + int64_t offset_ns; /* fixed offset in nanos (only when fixed) */ +} el_zone_t; + +typedef struct { + uint32_t magic; + el_calendar_kind_t kind; + el_zone_t* zone; /* EarthCalendar; MarsCalendar uses MTC */ + int64_t cycle_period_ns;/* CycleCalendar; computed for Earth (86400 s) and Mars (88775.244 s) */ + int64_t epoch_ns; /* RelativeCalendar; Unix-epoch zero otherwise */ +} el_calendar_t; + +typedef struct { + uint32_t magic; + int64_t instant_ns; + el_calendar_t* cal; +} el_caltime_t; + +/* Rhythm AST. */ +typedef enum { + EL_RHYTHM_CYCLE_START = 1, + EL_RHYTHM_CYCLE_PHASE = 2, + EL_RHYTHM_DURATION = 3, + EL_RHYTHM_SESSION_START = 4, + EL_RHYTHM_EVENT = 5, + EL_RHYTHM_AND = 6, + EL_RHYTHM_OR = 7, + EL_RHYTHM_WEEKDAY = 8, + EL_RHYTHM_WEEKLY_AT = 9 +} el_rhythm_kind_t; + +typedef struct el_rhythm_s { + uint32_t magic; + el_rhythm_kind_t kind; + double phase; /* CYCLE_PHASE */ + int64_t period_ns; /* DURATION */ + int weekday; /* 1..7 Mon..Sun */ + int hour; + int minute; + char* event_name; /* EVENT */ + struct el_rhythm_s* a; /* AND/OR */ + struct el_rhythm_s* b; +} el_rhythm_t; + +typedef struct { + uint32_t magic; + int year; + int month; + int day; +} el_localdate_t; + +typedef struct { + uint32_t magic; + el_localdate_t* date; + int64_t time_ns; /* nanos since midnight */ +} el_localdt_t; + +/* Magic-tag check helpers — peek the first 4 bytes of an el_val_t pointer + * and compare against the expected magic. Strings are NUL-terminated and + * never start with our magic byte sequence, so this is safe. */ +static int el_is_magic(el_val_t v, uint32_t want) { + if (v == 0) return 0; + /* Defensive: only follow pointers in plausible address space. + * On 64-bit unix processes pointers are above 0x10000. */ + if ((uint64_t)v < 0x10000ULL) return 0; + uint32_t got = *(volatile uint32_t*)(uintptr_t)v; + return got == want; +} + +/* Sol length on Mars in nanoseconds: 88775.244 seconds. */ +#define EL_MARS_SOL_NS ((int64_t)88775244000000LL) +/* Earth solar day in nanoseconds: 86400 seconds. */ +#define EL_EARTH_DAY_NS ((int64_t)86400000000000LL) + +/* ── Zone construction ────────────────────────────────────────────────────── + * Zones intern by id string so equality comparisons are pointer-compares. */ + +#define EL_ZONE_TABLE_CAP 64 +static el_zone_t* _el_zone_table[EL_ZONE_TABLE_CAP]; +static int _el_zone_count = 0; + +static el_zone_t* _el_zone_intern(const char* id, int fixed, int64_t offset_ns) { + for (int i = 0; i < _el_zone_count; i++) { + el_zone_t* z = _el_zone_table[i]; + if (z->fixed == fixed && z->offset_ns == offset_ns && + strcmp(z->id ? z->id : "", id ? id : "") == 0) { + return z; + } + } + if (_el_zone_count >= EL_ZONE_TABLE_CAP) { + /* Out of slots: build a non-interned zone. Equality will fail across + * such zones but the program still runs. */ + el_zone_t* z = (el_zone_t*)malloc(sizeof(el_zone_t)); + z->magic = EL_ZONE_MAGIC; + z->id = el_strdup_persist(id ? id : ""); + z->fixed = fixed; + z->offset_ns = offset_ns; + return z; + } + el_zone_t* z = (el_zone_t*)malloc(sizeof(el_zone_t)); + z->magic = EL_ZONE_MAGIC; + z->id = el_strdup_persist(id ? id : ""); + z->fixed = fixed; + z->offset_ns = offset_ns; + _el_zone_table[_el_zone_count++] = z; + return z; +} + +el_val_t zone(el_val_t id) { + const char* s = EL_CSTR(id); + if (!s || !*s) return (el_val_t)(uintptr_t)_el_zone_intern("UTC", 0, 0); + /* Fixed-offset shortcut: "+HH:MM" or "-HH:MM". */ + if ((s[0] == '+' || s[0] == '-') && strlen(s) >= 6 && s[3] == ':') { + int sign = (s[0] == '-') ? -1 : 1; + int hh = (s[1] - '0') * 10 + (s[2] - '0'); + int mm = (s[4] - '0') * 10 + (s[5] - '0'); + int64_t off = (int64_t)sign * ((int64_t)hh * 3600LL + (int64_t)mm * 60LL) * 1000000000LL; + return (el_val_t)(uintptr_t)_el_zone_intern(s, 1, off); + } + return (el_val_t)(uintptr_t)_el_zone_intern(s, 0, 0); +} + +el_val_t zone_utc(void) { + return (el_val_t)(uintptr_t)_el_zone_intern("UTC", 1, 0); +} + +el_val_t zone_local(void) { + /* Resolve the local zone via TZ env or system default. tzset() picks + * up TZ if set; otherwise the C library reads /etc/localtime. We store + * the zone id as "LOCAL" so subsequent equality holds; resolution is + * lazy at use time. */ + return (el_val_t)(uintptr_t)_el_zone_intern("LOCAL", 0, 0); +} + +el_val_t zone_offset(el_val_t hours, el_val_t minutes) { + int hh = (int)(int64_t)hours; + int mm = (int)(int64_t)minutes; + int sign = (hh < 0 || mm < 0) ? -1 : 1; + if (hh < 0) hh = -hh; + if (mm < 0) mm = -mm; + int64_t off = (int64_t)sign * ((int64_t)hh * 3600LL + (int64_t)mm * 60LL) * 1000000000LL; + char buf[16]; + snprintf(buf, sizeof(buf), "%c%02d:%02d", sign < 0 ? '-' : '+', hh, mm); + return (el_val_t)(uintptr_t)_el_zone_intern(buf, 1, off); +} + +/* ── Calendar interning ──────────────────────────────────────────────────── */ + +#define EL_CAL_TABLE_CAP 64 +static el_calendar_t* _el_cal_table[EL_CAL_TABLE_CAP]; +static int _el_cal_count = 0; + +static el_calendar_t* _el_cal_intern(el_calendar_kind_t kind, el_zone_t* z, + int64_t period_ns, int64_t epoch_ns) { + for (int i = 0; i < _el_cal_count; i++) { + el_calendar_t* c = _el_cal_table[i]; + if (c->kind == kind && c->zone == z && + c->cycle_period_ns == period_ns && c->epoch_ns == epoch_ns) { + return c; + } + } + el_calendar_t* c = (el_calendar_t*)malloc(sizeof(el_calendar_t)); + c->magic = EL_CAL_MAGIC; + c->kind = kind; + c->zone = z; + c->cycle_period_ns = period_ns; + c->epoch_ns = epoch_ns; + if (_el_cal_count < EL_CAL_TABLE_CAP) _el_cal_table[_el_cal_count++] = c; + return c; +} + +el_val_t earth_calendar(el_val_t z_val) { + el_zone_t* z = NULL; + if (z_val != 0 && el_is_magic(z_val, EL_ZONE_MAGIC)) { + z = (el_zone_t*)(uintptr_t)z_val; + } else { + z = (el_zone_t*)(uintptr_t)zone_local(); + } + return (el_val_t)(uintptr_t)_el_cal_intern(EL_CALENDAR_EARTH, z, EL_EARTH_DAY_NS, 0); +} + +el_val_t earth_calendar_default(void) { + return earth_calendar(zone_local()); +} + +el_val_t mars_calendar(void) { + el_zone_t* z = (el_zone_t*)(uintptr_t)_el_zone_intern("MTC", 1, 0); + return (el_val_t)(uintptr_t)_el_cal_intern(EL_CALENDAR_MARS, z, EL_MARS_SOL_NS, 0); +} + +el_val_t cycle_calendar(el_val_t period_dur) { + int64_t period = (int64_t)period_dur; + if (period <= 0) period = 1; + return (el_val_t)(uintptr_t)_el_cal_intern(EL_CALENDAR_CYCLE, NULL, period, 0); +} + +el_val_t no_cycle_calendar(void) { + return (el_val_t)(uintptr_t)_el_cal_intern(EL_CALENDAR_NO_CYCLE, NULL, 0, 0); +} + +el_val_t relative_calendar(el_val_t epoch_inst) { + int64_t ep = (int64_t)epoch_inst; + return (el_val_t)(uintptr_t)_el_cal_intern(EL_CALENDAR_RELATIVE, NULL, 0, ep); +} + +/* ── CalendarTime ───────────────────────────────────────────────────────── */ + +static el_caltime_t* _el_caltime_alloc(int64_t inst, el_calendar_t* c) { + el_caltime_t* ct = (el_caltime_t*)malloc(sizeof(el_caltime_t)); + ct->magic = EL_CALTIME_MAGIC; + ct->instant_ns = inst; + ct->cal = c; + return ct; +} + +static el_calendar_t* _el_resolve_cal(el_val_t cal_val) { + if (cal_val == 0 || !el_is_magic(cal_val, EL_CAL_MAGIC)) { + return (el_calendar_t*)(uintptr_t)earth_calendar_default(); + } + return (el_calendar_t*)(uintptr_t)cal_val; +} + +el_val_t now_in(el_val_t cal_val) { + el_calendar_t* c = _el_resolve_cal(cal_val); + int64_t ns = (int64_t)el_now_instant(); + return (el_val_t)(uintptr_t)_el_caltime_alloc(ns, c); +} + +el_val_t in_calendar(el_val_t inst, el_val_t cal_val) { + el_calendar_t* c = _el_resolve_cal(cal_val); + return (el_val_t)(uintptr_t)_el_caltime_alloc((int64_t)inst, c); +} + +el_val_t cal_to_instant(el_val_t ct_val) { + if (!el_is_magic(ct_val, EL_CALTIME_MAGIC)) return (el_val_t)0; + el_caltime_t* ct = (el_caltime_t*)(uintptr_t)ct_val; + return (el_val_t)ct->instant_ns; +} + +el_val_t cal_in(el_val_t ct_val, el_val_t cal_val) { + if (!el_is_magic(ct_val, EL_CALTIME_MAGIC)) return (el_val_t)0; + el_caltime_t* ct = (el_caltime_t*)(uintptr_t)ct_val; + el_calendar_t* c = _el_resolve_cal(cal_val); + return (el_val_t)(uintptr_t)_el_caltime_alloc(ct->instant_ns, c); +} + +el_val_t cal_cycle_phase(el_val_t ct_val) { + if (!el_is_magic(ct_val, EL_CALTIME_MAGIC)) return el_from_float(0.0); + el_caltime_t* ct = (el_caltime_t*)(uintptr_t)ct_val; + el_calendar_t* c = ct->cal; + if (c->kind == EL_CALENDAR_NO_CYCLE) { + return el_from_float(0.0/0.0); /* NaN sentinel */ + } + int64_t period = c->cycle_period_ns; + if (period <= 0) return el_from_float(0.0); + int64_t base = ct->instant_ns - c->epoch_ns; + int64_t phase_ns = base % period; + if (phase_ns < 0) phase_ns += period; + double phase = (double)phase_ns / (double)period; + return el_from_float(phase); +} + +/* ── Earth zone resolution: TZ-based offset lookup ────────────────────────── + * For an EarthCalendar(zone), we want to convert an instant_ns into local + * y/m/d/h/m/s, including DST. Approach: setenv("TZ", id), tzset(), use + * localtime_r, then restore. This is not thread-safe by design — El's + * runtime is single-threaded for the request handler path. Cache the + * computed (instant -> tm) to avoid the syscall churn on repeat formats. */ + +static void _el_apply_zone(el_zone_t* z) { + if (!z) { unsetenv("TZ"); tzset(); return; } + if (z->fixed && strcmp(z->id, "UTC") == 0) { + setenv("TZ", "UTC0", 1); + tzset(); + return; + } + if (z->fixed) { + /* Fixed offset: POSIX TZ uses inverted sign (sign convention of + * "hours WEST of UTC" rather than east). Build the spec accordingly. */ + char buf[32]; + int neg_secs = (int)(-z->offset_ns / 1000000000LL); + int sign = neg_secs < 0 ? -1 : 1; + int abs_secs = neg_secs < 0 ? -neg_secs : neg_secs; + int hh = abs_secs / 3600; + int mm = (abs_secs % 3600) / 60; + snprintf(buf, sizeof(buf), "FIX%c%d:%02d", sign < 0 ? '-' : '+', hh, mm); + setenv("TZ", buf, 1); + tzset(); + return; + } + if (strcmp(z->id, "LOCAL") == 0) { + unsetenv("TZ"); + tzset(); + return; + } + setenv("TZ", z->id, 1); + tzset(); +} + +static int _el_decompose_earth(el_caltime_t* ct, struct tm* tm_out, int* abbr_len, char* abbr_buf, size_t abbr_cap) { + el_calendar_t* c = ct->cal; + el_zone_t* z = c->zone; + _el_apply_zone(z); + time_t s = (time_t)(ct->instant_ns / 1000000000LL); + struct tm tm; + localtime_r(&s, &tm); + *tm_out = tm; + if (abbr_buf && abbr_cap > 0) { + const char* z_str = tm.tm_zone ? tm.tm_zone : ""; + size_t n = strlen(z_str); + if (n >= abbr_cap) n = abbr_cap - 1; + memcpy(abbr_buf, z_str, n); + abbr_buf[n] = '\0'; + if (abbr_len) *abbr_len = (int)n; + } + return 0; +} + +/* Format an Earth CalendarTime under a Java-DateTimeFormatter-ish pattern. + * We support a useful core: yyyy MM dd HH mm ss z EEE MMM d h a — enough for + * the acceptance tests. Single quotes denote literal text. */ +static const char* _el_weekday_short[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; +static const char* _el_month_short[] = {"Jan","Feb","Mar","Apr","May","Jun", + "Jul","Aug","Sep","Oct","Nov","Dec"}; + +static char* _el_format_earth(el_caltime_t* ct, const char* pattern) { + struct tm tm; + char abbr[16] = {0}; + int abbr_len = 0; + _el_decompose_earth(ct, &tm, &abbr_len, abbr, sizeof(abbr)); + size_t cap = strlen(pattern) * 4 + 64; + char* out = (char*)malloc(cap); + size_t pos = 0; + size_t i = 0; + size_t plen = strlen(pattern); + while (i < plen) { + char ch = pattern[i]; + /* Quoted literal */ + if (ch == '\'') { + i++; + while (i < plen && pattern[i] != '\'') { + if (pos + 1 >= cap) { cap *= 2; out = realloc(out, cap); } + out[pos++] = pattern[i++]; + } + if (i < plen) i++; + continue; + } + /* Count run of same letter */ + size_t run = 1; + while (i + run < plen && pattern[i + run] == ch) run++; + char tmp[64]; + tmp[0] = '\0'; + if (ch == 'y') { + if (run >= 4) snprintf(tmp, sizeof(tmp), "%04d", tm.tm_year + 1900); + else snprintf(tmp, sizeof(tmp), "%02d", (tm.tm_year + 1900) % 100); + } else if (ch == 'M') { + if (run >= 3) snprintf(tmp, sizeof(tmp), "%s", _el_month_short[tm.tm_mon]); + else if (run == 2) snprintf(tmp, sizeof(tmp), "%02d", tm.tm_mon + 1); + else snprintf(tmp, sizeof(tmp), "%d", tm.tm_mon + 1); + } else if (ch == 'd') { + if (run >= 2) snprintf(tmp, sizeof(tmp), "%02d", tm.tm_mday); + else snprintf(tmp, sizeof(tmp), "%d", tm.tm_mday); + } else if (ch == 'H') { + if (run >= 2) snprintf(tmp, sizeof(tmp), "%02d", tm.tm_hour); + else snprintf(tmp, sizeof(tmp), "%d", tm.tm_hour); + } else if (ch == 'h') { + int h12 = tm.tm_hour % 12; if (h12 == 0) h12 = 12; + if (run >= 2) snprintf(tmp, sizeof(tmp), "%02d", h12); + else snprintf(tmp, sizeof(tmp), "%d", h12); + } else if (ch == 'm') { + if (run >= 2) snprintf(tmp, sizeof(tmp), "%02d", tm.tm_min); + else snprintf(tmp, sizeof(tmp), "%d", tm.tm_min); + } else if (ch == 's') { + if (run >= 2) snprintf(tmp, sizeof(tmp), "%02d", tm.tm_sec); + else snprintf(tmp, sizeof(tmp), "%d", tm.tm_sec); + } else if (ch == 'a') { + snprintf(tmp, sizeof(tmp), "%s", tm.tm_hour < 12 ? "AM" : "PM"); + } else if (ch == 'E') { + snprintf(tmp, sizeof(tmp), "%s", _el_weekday_short[tm.tm_wday]); + } else if (ch == 'z') { + snprintf(tmp, sizeof(tmp), "%s", abbr); + } else { + for (size_t k = 0; k < run; k++) { + if (pos + 1 >= cap) { cap *= 2; out = realloc(out, cap); } + out[pos++] = ch; + } + i += run; + continue; + } + size_t tl = strlen(tmp); + if (pos + tl + 1 >= cap) { cap = (cap + tl) * 2; out = realloc(out, cap); } + memcpy(out + pos, tmp, tl); + pos += tl; + i += run; + } + out[pos] = '\0'; + char* result = el_strdup(out); + free(out); + return result; +} + +/* Format a Mars CalendarTime: %sol prints the integer sol number since + * mission epoch (Unix epoch fallback), %phase prints cycle_phase as a + * 0..1 decimal. Other %-specifiers fall through. */ +static char* _el_format_mars(el_caltime_t* ct, const char* pattern) { + el_calendar_t* c = ct->cal; + int64_t period = c->cycle_period_ns > 0 ? c->cycle_period_ns : EL_MARS_SOL_NS; + int64_t base = ct->instant_ns - c->epoch_ns; + int64_t sol = base / period; + int64_t phase_ns = base % period; + if (phase_ns < 0) { phase_ns += period; sol -= 1; } + double phase = (double)phase_ns / (double)period; + size_t cap = strlen(pattern) * 4 + 64; + char* out = (char*)malloc(cap); + size_t pos = 0; + for (size_t i = 0; pattern[i]; i++) { + if (pattern[i] == '%' && pattern[i+1]) { + char tmp[64]; + tmp[0] = '\0'; + if (strncmp(pattern + i + 1, "sol", 3) == 0) { + snprintf(tmp, sizeof(tmp), "%lld", (long long)sol); + i += 3; + } else if (strncmp(pattern + i + 1, "phase", 5) == 0) { + snprintf(tmp, sizeof(tmp), "%.4f", phase); + i += 5; + } else if (pattern[i+1] == 'd') { + snprintf(tmp, sizeof(tmp), "%lld", (long long)sol); + i += 1; + } else { + tmp[0] = pattern[i+1]; tmp[1] = '\0'; + i += 1; + } + size_t tl = strlen(tmp); + if (pos + tl + 1 >= cap) { cap = (cap + tl) * 2; out = realloc(out, cap); } + memcpy(out + pos, tmp, tl); + pos += tl; + } else { + if (pos + 1 >= cap) { cap *= 2; out = realloc(out, cap); } + out[pos++] = pattern[i]; + } + } + out[pos] = '\0'; + char* result = el_strdup(out); + free(out); + return result; +} + +/* Format a CycleCalendar CalendarTime: %cycle and %phase. */ +static char* _el_format_cycle(el_caltime_t* ct, const char* pattern) { + el_calendar_t* c = ct->cal; + int64_t period = c->cycle_period_ns > 0 ? c->cycle_period_ns : 1; + int64_t base = ct->instant_ns - c->epoch_ns; + int64_t cycle = base / period; + int64_t phase_ns = base % period; + if (phase_ns < 0) { phase_ns += period; cycle -= 1; } + double phase = (double)phase_ns / (double)period; + size_t cap = strlen(pattern) * 4 + 64; + char* out = (char*)malloc(cap); + size_t pos = 0; + for (size_t i = 0; pattern[i]; i++) { + if (pattern[i] == '%' && pattern[i+1]) { + char tmp[64]; + tmp[0] = '\0'; + if (strncmp(pattern + i + 1, "cycle", 5) == 0) { + snprintf(tmp, sizeof(tmp), "%lld", (long long)cycle); + i += 5; + } else if (strncmp(pattern + i + 1, "phase", 5) == 0) { + snprintf(tmp, sizeof(tmp), "%.4f", phase); + i += 5; + } else if (pattern[i+1] == 'd') { + snprintf(tmp, sizeof(tmp), "%lld", (long long)cycle); + i += 1; + } else if (pattern[i+1] == 'f') { + snprintf(tmp, sizeof(tmp), "%.2f", phase); + i += 1; + } else { + /* Pass through unknown specifier */ + tmp[0] = '%'; tmp[1] = pattern[i+1]; tmp[2] = '\0'; + i += 1; + } + size_t tl = strlen(tmp); + if (pos + tl + 1 >= cap) { cap = (cap + tl) * 2; out = realloc(out, cap); } + memcpy(out + pos, tmp, tl); + pos += tl; + } else { + if (pos + 1 >= cap) { cap *= 2; out = realloc(out, cap); } + out[pos++] = pattern[i]; + } + } + out[pos] = '\0'; + char* result = el_strdup(out); + free(out); + return result; +} + +el_val_t cal_format(el_val_t ct_val, el_val_t pattern_val) { + if (!el_is_magic(ct_val, EL_CALTIME_MAGIC)) return el_wrap_str(el_strdup("")); + el_caltime_t* ct = (el_caltime_t*)(uintptr_t)ct_val; + const char* pat = EL_CSTR(pattern_val); + if (!pat) pat = ""; + char* result = NULL; + switch (ct->cal->kind) { + case EL_CALENDAR_EARTH: result = _el_format_earth(ct, pat); break; + case EL_CALENDAR_MARS: result = _el_format_mars(ct, pat); break; + case EL_CALENDAR_CYCLE: result = _el_format_cycle(ct, pat); break; + case EL_CALENDAR_RELATIVE: result = _el_format_cycle(ct, pat); break; + case EL_CALENDAR_NO_CYCLE: { + char buf[64]; + snprintf(buf, sizeof(buf), "instant:%lld", (long long)ct->instant_ns); + result = el_strdup(buf); + break; + } + default: result = el_strdup(""); + } + return el_wrap_str(result); +} + +/* ── LocalDate / LocalTime / LocalDateTime ──────────────────────────────── */ + +static int _el_days_in_month(int y, int m) { + static const int dim[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; + if (m == 2) { + int leap = ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0); + return 28 + (leap ? 1 : 0); + } + if (m < 1 || m > 12) return 30; + return dim[m - 1]; +} + +el_val_t local_date(el_val_t y, el_val_t m, el_val_t d) { + el_localdate_t* ld = (el_localdate_t*)malloc(sizeof(el_localdate_t)); + ld->magic = EL_LDATE_MAGIC; + ld->year = (int)(int64_t)y; + ld->month = (int)(int64_t)m; + ld->day = (int)(int64_t)d; + return (el_val_t)(uintptr_t)ld; +} + +el_val_t local_time(el_val_t h, el_val_t m, el_val_t s, el_val_t ns) { + int64_t hh = (int64_t)h; + int64_t mm = (int64_t)m; + int64_t ss = (int64_t)s; + int64_t nn = (int64_t)ns; + int64_t total = hh * 3600000000000LL + mm * 60000000000LL + ss * 1000000000LL + nn; + return (el_val_t)total; +} + +el_val_t local_datetime(el_val_t date_val, el_val_t time_val) { + if (!el_is_magic(date_val, EL_LDATE_MAGIC)) return (el_val_t)0; + el_localdt_t* ldt = (el_localdt_t*)malloc(sizeof(el_localdt_t)); + ldt->magic = EL_LDT_MAGIC; + ldt->date = (el_localdate_t*)(uintptr_t)date_val; + ldt->time_ns = (int64_t)time_val; + return (el_val_t)(uintptr_t)ldt; +} + +el_val_t zoned(el_val_t date_val, el_val_t time_val, el_val_t cal_val) { + if (!el_is_magic(date_val, EL_LDATE_MAGIC)) return (el_val_t)0; + el_localdate_t* ld = (el_localdate_t*)(uintptr_t)date_val; + el_calendar_t* c = _el_resolve_cal(cal_val); + int64_t time_ns = (int64_t)time_val; + /* Convert (LocalDate, LocalTime, EarthCalendar) -> Instant. + * For non-Earth calendars we use day-anchored conversion: treat the + * LocalDate's (y,m,d) as a Gregorian projection, convert to seconds via + * mktime under the calendar's zone, then add nanos-since-midnight. */ + if (c->kind == EL_CALENDAR_EARTH) { + _el_apply_zone(c->zone); + struct tm tm; memset(&tm, 0, sizeof(tm)); + tm.tm_year = ld->year - 1900; + tm.tm_mon = ld->month - 1; + tm.tm_mday = ld->day; + tm.tm_hour = (int)(time_ns / 3600000000000LL); + tm.tm_min = (int)((time_ns / 60000000000LL) % 60); + tm.tm_sec = (int)((time_ns / 1000000000LL) % 60); + tm.tm_isdst = -1; + time_t t = mktime(&tm); + if (t == (time_t)-1) return (el_val_t)0; + int64_t ns = (int64_t)t * 1000000000LL + (time_ns % 1000000000LL); + return (el_val_t)(uintptr_t)_el_caltime_alloc(ns, c); + } + /* Non-Earth fallback: project as if Earth UTC then attach calendar. */ + struct tm tm; memset(&tm, 0, sizeof(tm)); + tm.tm_year = ld->year - 1900; + tm.tm_mon = ld->month - 1; + tm.tm_mday = ld->day; + tm.tm_hour = (int)(time_ns / 3600000000000LL); + tm.tm_min = (int)((time_ns / 60000000000LL) % 60); + tm.tm_sec = (int)((time_ns / 1000000000LL) % 60); + time_t t = timegm(&tm); + if (t == (time_t)-1) return (el_val_t)0; + int64_t ns = (int64_t)t * 1000000000LL + (time_ns % 1000000000LL); + return (el_val_t)(uintptr_t)_el_caltime_alloc(ns, c); +} + +el_val_t local_date_year(el_val_t v) { + if (!el_is_magic(v, EL_LDATE_MAGIC)) return (el_val_t)0; + return (el_val_t)((el_localdate_t*)(uintptr_t)v)->year; +} +el_val_t local_date_month(el_val_t v) { + if (!el_is_magic(v, EL_LDATE_MAGIC)) return (el_val_t)0; + return (el_val_t)((el_localdate_t*)(uintptr_t)v)->month; +} +el_val_t local_date_day(el_val_t v) { + if (!el_is_magic(v, EL_LDATE_MAGIC)) return (el_val_t)0; + return (el_val_t)((el_localdate_t*)(uintptr_t)v)->day; +} +el_val_t local_time_hour(el_val_t v) { + int64_t t = (int64_t)v; + return (el_val_t)(t / 3600000000000LL); +} +el_val_t local_time_minute(el_val_t v) { + int64_t t = (int64_t)v; + return (el_val_t)((t / 60000000000LL) % 60); +} +el_val_t local_time_second(el_val_t v) { + int64_t t = (int64_t)v; + return (el_val_t)((t / 1000000000LL) % 60); +} +el_val_t local_time_nanos(el_val_t v) { + int64_t t = (int64_t)v; + return (el_val_t)(t % 1000000000LL); +} + +el_val_t el_local_date_add_dur(el_val_t ld_val, el_val_t dur_val) { + if (!el_is_magic(ld_val, EL_LDATE_MAGIC)) return ld_val; + el_localdate_t* ld = (el_localdate_t*)(uintptr_t)ld_val; + int64_t dur_ns = (int64_t)dur_val; + int64_t days = dur_ns / EL_EARTH_DAY_NS; + int y = ld->year, m = ld->month, d = ld->day; + /* Walk days forward/backward in canonical Gregorian. */ + while (days > 0) { + int dim = _el_days_in_month(y, m); + if (d + days <= dim) { d += (int)days; days = 0; break; } + days -= (dim - d + 1); + d = 1; + m++; + if (m > 12) { m = 1; y++; } + } + while (days < 0) { + if (d + days >= 1) { d += (int)days; days = 0; break; } + days += d; + m--; + if (m < 1) { m = 12; y--; } + d = _el_days_in_month(y, m); + } + return local_date((el_val_t)y, (el_val_t)m, (el_val_t)d); +} + +el_val_t el_local_time_add_dur(el_val_t lt_val, el_val_t dur_val) { + int64_t t = (int64_t)lt_val + (int64_t)dur_val; + /* Wrap mod 24h on Earth-default. CycleCalendar wrapping requires the + * caller to use cal_in / cal_format for the right modulus. */ + int64_t day = EL_EARTH_DAY_NS; + int64_t r = t % day; + if (r < 0) r += day; + return (el_val_t)r; +} + +el_val_t el_local_date_lt(el_val_t a_val, el_val_t b_val) { + if (!el_is_magic(a_val, EL_LDATE_MAGIC) || !el_is_magic(b_val, EL_LDATE_MAGIC)) return (el_val_t)0; + el_localdate_t* a = (el_localdate_t*)(uintptr_t)a_val; + el_localdate_t* b = (el_localdate_t*)(uintptr_t)b_val; + if (a->year != b->year) return (el_val_t)(a->year < b->year ? 1 : 0); + if (a->month != b->month) return (el_val_t)(a->month < b->month ? 1 : 0); + return (el_val_t)(a->day < b->day ? 1 : 0); +} + +el_val_t el_local_date_eq(el_val_t a_val, el_val_t b_val) { + if (!el_is_magic(a_val, EL_LDATE_MAGIC) || !el_is_magic(b_val, EL_LDATE_MAGIC)) return (el_val_t)0; + el_localdate_t* a = (el_localdate_t*)(uintptr_t)a_val; + el_localdate_t* b = (el_localdate_t*)(uintptr_t)b_val; + return (el_val_t)((a->year == b->year && a->month == b->month && a->day == b->day) ? 1 : 0); +} + +/* ── Rhythm ──────────────────────────────────────────────────────────────── */ + +static el_rhythm_t* _el_rhythm_alloc(el_rhythm_kind_t k) { + el_rhythm_t* r = (el_rhythm_t*)calloc(1, sizeof(el_rhythm_t)); + r->magic = EL_RHYTHM_MAGIC; + r->kind = k; + return r; +} + +el_val_t rhythm_cycle_start(void) { + return (el_val_t)(uintptr_t)_el_rhythm_alloc(EL_RHYTHM_CYCLE_START); +} + +el_val_t rhythm_cycle_phase(el_val_t phase_val) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_CYCLE_PHASE); + r->phase = el_to_float(phase_val); + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_duration(el_val_t d_val) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_DURATION); + r->period_ns = (int64_t)d_val; + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_session_start(void) { + return (el_val_t)(uintptr_t)_el_rhythm_alloc(EL_RHYTHM_SESSION_START); +} + +el_val_t rhythm_event(el_val_t name_val) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_EVENT); + const char* n = EL_CSTR(name_val); + r->event_name = el_strdup_persist(n ? n : ""); + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_and(el_val_t a_val, el_val_t b_val) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_AND); + r->a = el_is_magic(a_val, EL_RHYTHM_MAGIC) ? (el_rhythm_t*)(uintptr_t)a_val : NULL; + r->b = el_is_magic(b_val, EL_RHYTHM_MAGIC) ? (el_rhythm_t*)(uintptr_t)b_val : NULL; + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_or(el_val_t a_val, el_val_t b_val) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_OR); + r->a = el_is_magic(a_val, EL_RHYTHM_MAGIC) ? (el_rhythm_t*)(uintptr_t)a_val : NULL; + r->b = el_is_magic(b_val, EL_RHYTHM_MAGIC) ? (el_rhythm_t*)(uintptr_t)b_val : NULL; + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_weekday(el_val_t day) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_WEEKDAY); + r->weekday = (int)(int64_t)day; + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_weekly_at(el_val_t day, el_val_t hour, el_val_t minute) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_WEEKLY_AT); + r->weekday = (int)(int64_t)day; + r->hour = (int)(int64_t)hour; + r->minute = (int)(int64_t)minute; + return (el_val_t)(uintptr_t)r; +} + +/* Compute the next instant on or after `after` when rhythm `r` matches, + * under calendar `cal`. */ +static int64_t _el_next_after(el_rhythm_t* r, int64_t after_ns, el_calendar_t* cal) { + if (!r) return after_ns; + int64_t period = cal->cycle_period_ns > 0 ? cal->cycle_period_ns : EL_EARTH_DAY_NS; + switch (r->kind) { + case EL_RHYTHM_CYCLE_START: { + int64_t base = after_ns - cal->epoch_ns; + int64_t cyc = (base / period) + 1; + return cal->epoch_ns + cyc * period; + } + case EL_RHYTHM_CYCLE_PHASE: { + int64_t base = after_ns - cal->epoch_ns; + int64_t cyc_ns = (int64_t)(r->phase * (double)period); + int64_t cur_cyc = base / period; + int64_t candidate = cal->epoch_ns + cur_cyc * period + cyc_ns; + if (candidate <= after_ns) candidate += period; + return candidate; + } + case EL_RHYTHM_DURATION: { + return after_ns + (r->period_ns > 0 ? r->period_ns : 1); + } + case EL_RHYTHM_WEEKDAY: + case EL_RHYTHM_WEEKLY_AT: { + if (cal->kind != EL_CALENDAR_EARTH) { + /* Non-Earth calendars: fall back to cycle math, treating + * weekday as a 7-cycle-per-period proxy. */ + return after_ns + period; + } + _el_apply_zone(cal->zone); + time_t s = (time_t)(after_ns / 1000000000LL); + struct tm tm; + localtime_r(&s, &tm); + /* tm_wday: 0=Sun..6=Sat. We use 1=Mon..7=Sun. */ + int target = r->weekday >= 1 && r->weekday <= 7 ? r->weekday : 1; + int target_wday = target == 7 ? 0 : target; /* 7→Sun=0, 1→Mon=1 */ + int days_ahead = (target_wday - tm.tm_wday + 7) % 7; + int hour = (r->kind == EL_RHYTHM_WEEKLY_AT) ? r->hour : 0; + int minute = (r->kind == EL_RHYTHM_WEEKLY_AT) ? r->minute : 0; + struct tm cand = tm; + cand.tm_mday += days_ahead; + cand.tm_hour = hour; + cand.tm_min = minute; + cand.tm_sec = 0; + cand.tm_isdst = -1; + time_t cand_t = mktime(&cand); + int64_t cand_ns = (int64_t)cand_t * 1000000000LL; + if (cand_ns <= after_ns) { + cand.tm_mday += 7; + cand.tm_isdst = -1; + cand_t = mktime(&cand); + cand_ns = (int64_t)cand_t * 1000000000LL; + } + return cand_ns; + } + case EL_RHYTHM_AND: { + int64_t a = _el_next_after(r->a, after_ns, cal); + int64_t b = _el_next_after(r->b, after_ns, cal); + return a > b ? a : b; + } + case EL_RHYTHM_OR: { + int64_t a = _el_next_after(r->a, after_ns, cal); + int64_t b = _el_next_after(r->b, after_ns, cal); + return a < b ? a : b; + } + case EL_RHYTHM_SESSION_START: + case EL_RHYTHM_EVENT: + default: + return after_ns; + } +} + +el_val_t rhythm_next_after(el_val_t r_val, el_val_t after_val, el_val_t cal_val) { + if (!el_is_magic(r_val, EL_RHYTHM_MAGIC)) return after_val; + el_rhythm_t* r = (el_rhythm_t*)(uintptr_t)r_val; + el_calendar_t* c = _el_resolve_cal(cal_val); + int64_t out = _el_next_after(r, (int64_t)after_val, c); + return (el_val_t)out; +} + +el_val_t rhythm_matches(el_val_t r_val, el_val_t ct_val) { + if (!el_is_magic(r_val, EL_RHYTHM_MAGIC)) return (el_val_t)0; + if (!el_is_magic(ct_val, EL_CALTIME_MAGIC)) return (el_val_t)0; + el_rhythm_t* r = (el_rhythm_t*)(uintptr_t)r_val; + el_caltime_t* ct = (el_caltime_t*)(uintptr_t)ct_val; + int64_t period = ct->cal->cycle_period_ns > 0 ? ct->cal->cycle_period_ns : EL_EARTH_DAY_NS; + int64_t base = ct->instant_ns - ct->cal->epoch_ns; + int64_t phase_ns = base % period; + if (phase_ns < 0) phase_ns += period; + double phase = (double)phase_ns / (double)period; + switch (r->kind) { + case EL_RHYTHM_CYCLE_START: return (el_val_t)(phase_ns == 0 ? 1 : 0); + case EL_RHYTHM_CYCLE_PHASE: { + double diff = phase - r->phase; + if (diff < 0) diff = -diff; + return (el_val_t)(diff < 0.001 ? 1 : 0); + } + default: return (el_val_t)0; + } +} + +/* ── UUID v4 ─────────────────────────────────────────────────────────────── */ + +static int _el_uuid_seeded = 0; + +static void _el_uuid_seed(void) { + if (!_el_uuid_seeded) { + srand((unsigned)time(NULL) ^ (unsigned)(uintptr_t)&_el_uuid_seeded); + _el_uuid_seeded = 1; + } +} + +el_val_t uuid_new(void) { + _el_uuid_seed(); + unsigned char b[16]; + for (int i = 0; i < 16; i++) b[i] = (unsigned char)(rand() & 0xff); + /* Version 4 */ + b[6] = (b[6] & 0x0f) | 0x40; + /* RFC 4122 variant */ + b[8] = (b[8] & 0x3f) | 0x80; + char buf[37]; + snprintf(buf, sizeof(buf), + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + b[0], b[1], b[2], b[3], + b[4], b[5], + b[6], b[7], + b[8], b[9], + b[10], b[11], b[12], b[13], b[14], b[15]); + return el_wrap_str(el_strdup(buf)); +} + +el_val_t uuid_v4(void) { return uuid_new(); } + +/* ── Environment ─────────────────────────────────────────────────────────── */ + +el_val_t env(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return el_wrap_str(el_strdup("")); + const char* v = getenv(k); + return el_wrap_str(el_strdup(v ? v : "")); +} + +/* ── In-process state K/V ────────────────────────────────────────────────── */ + +typedef struct { + char* key; + char* value; +} StateEntry; + +static StateEntry* _state_entries = NULL; +static size_t _state_count = 0; +static size_t _state_cap = 0; +/* Mutex protecting all _state_entries access. state_set/state_get are called + * concurrently from 64 HTTP worker threads — without this lock, realloc and + * free race, producing corruption, double-free, and segfaults. */ +static pthread_mutex_t _state_mu = PTHREAD_MUTEX_INITIALIZER; + +static StateEntry* state_find(const char* key) { + for (size_t i = 0; i < _state_count; i++) { + if (strcmp(_state_entries[i].key, key) == 0) return &_state_entries[i]; + } + return NULL; +} + +el_val_t state_set(el_val_t key, el_val_t value) { + const char* k = EL_CSTR(key); + const char* v = EL_CSTR(value); + if (!k) return 0; + if (!v) v = ""; + pthread_mutex_lock(&_state_mu); + StateEntry* e = state_find(k); + if (e) { + free(e->value); + e->value = el_strdup_persist(v); + pthread_mutex_unlock(&_state_mu); + return 1; + } + if (_state_count >= _state_cap) { + size_t nc = _state_cap == 0 ? 16 : _state_cap * 2; + StateEntry* grown = realloc(_state_entries, nc * sizeof(StateEntry)); + if (!grown) { pthread_mutex_unlock(&_state_mu); fputs("el_runtime: out of memory\n", stderr); exit(1); } + _state_entries = grown; + _state_cap = nc; + } + _state_entries[_state_count].key = el_strdup_persist(k); + _state_entries[_state_count].value = el_strdup_persist(v); + _state_count++; + pthread_mutex_unlock(&_state_mu); + return 1; +} + +el_val_t state_get(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return el_wrap_str(el_strdup("")); + pthread_mutex_lock(&_state_mu); + StateEntry* e = state_find(k); + char* result = el_strdup_persist(e ? e->value : ""); + pthread_mutex_unlock(&_state_mu); + /* wrap in arena-tracked copy for the caller's request lifetime */ + char* copy = el_strdup(result); + return el_wrap_str(copy); +} + +el_val_t state_del(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return 0; + pthread_mutex_lock(&_state_mu); + for (size_t i = 0; i < _state_count; i++) { + if (strcmp(_state_entries[i].key, k) == 0) { + free(_state_entries[i].key); + free(_state_entries[i].value); + for (size_t j = i + 1; j < _state_count; j++) { + _state_entries[j - 1] = _state_entries[j]; + } + _state_count--; + pthread_mutex_unlock(&_state_mu); + return 1; + } + } + pthread_mutex_unlock(&_state_mu); + return 1; +} + +el_val_t state_keys(void) { + pthread_mutex_lock(&_state_mu); + /* Build a JSON array string: ["key1","key2",...] */ + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + for (size_t i = 0; i < _state_count; i++) { + if (i > 0) jb_putc(&b, ','); + jb_putc(&b, '"'); + jb_emit_escaped(&b, _state_entries[i].key); + jb_putc(&b, '"'); + } + jb_putc(&b, ']'); + pthread_mutex_unlock(&_state_mu); + return el_wrap_str(b.buf); +} + +/* Returns 1 (true) if the key is present in the state store, else 0 (false). */ +el_val_t state_has(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return 0; + pthread_mutex_lock(&_state_mu); + StateEntry* e = state_find(k); + int found = (e != NULL) ? 1 : 0; + pthread_mutex_unlock(&_state_mu); + return (el_val_t)found; +} + +/* Returns the value for key, or default_val if the key is absent. */ +el_val_t state_get_or(el_val_t key, el_val_t default_val) { + const char* k = EL_CSTR(key); + if (!k) return default_val; + pthread_mutex_lock(&_state_mu); + StateEntry* e = state_find(k); + if (e) { + char* copy = el_strdup(e->value); + pthread_mutex_unlock(&_state_mu); + return el_wrap_str(copy); + } + pthread_mutex_unlock(&_state_mu); + return default_val; +} + +/* ── Float formatting ────────────────────────────────────────────────────── */ + +el_val_t float_to_str(el_val_t f) { + char buf[64]; + double v = el_to_float(f); + /* Normalize NaN to "nan" regardless of sign — platform-independent. */ + if (isnan(v)) { + snprintf(buf, sizeof(buf), "nan"); + } else { + snprintf(buf, sizeof(buf), "%g", v); + } + return el_wrap_str(el_strdup(buf)); +} + +el_val_t int_to_float(el_val_t n) { + return el_from_float((double)(int64_t)n); +} + +el_val_t float_to_int(el_val_t f) { + return (el_val_t)(int64_t)el_to_float(f); +} + +el_val_t format_float(el_val_t f, el_val_t decimals) { + int d = (int)(int64_t)decimals; + if (d < 0) d = 0; + if (d > 30) d = 30; + char buf[128]; + snprintf(buf, sizeof(buf), "%.*f", d, el_to_float(f)); + return el_wrap_str(el_strdup(buf)); +} + +el_val_t decimal_round(el_val_t f, el_val_t decimals) { + int d = (int)(int64_t)decimals; + if (d < 0) d = 0; + if (d > 15) d = 15; + double mul = pow(10.0, (double)d); + double v = el_to_float(f); + double r = (v >= 0.0 ? floor(v * mul + 0.5) : -floor(-v * mul + 0.5)) / mul; + return el_from_float(r); +} + +el_val_t str_to_float(el_val_t s) { + const char* str = EL_CSTR(s); + if (!str) return el_from_float(0.0); + return el_from_float(strtod(str, NULL)); +} + +/* ── Math (Float-aware) ──────────────────────────────────────────────────── */ + +el_val_t math_sqrt(el_val_t f) { return el_from_float(sqrt(el_to_float(f))); } +el_val_t math_log(el_val_t f) { return el_from_float(log(el_to_float(f))); } +el_val_t math_ln(el_val_t f) { return el_from_float(log(el_to_float(f))); } +el_val_t math_sin(el_val_t f) { return el_from_float(sin(el_to_float(f))); } +el_val_t math_cos(el_val_t f) { return el_from_float(cos(el_to_float(f))); } +el_val_t math_pi(void) { return el_from_float(3.141592653589793238462643383279502884); } + +/* ── String additions ────────────────────────────────────────────────────── */ + +el_val_t str_index_of(el_val_t s, el_val_t sub) { + const char* str = EL_CSTR(s); + const char* sb = EL_CSTR(sub); + if (!str || !sb) return -1; + const char* hit = strstr(str, sb); + if (!hit) return -1; + return (el_val_t)(int64_t)(hit - str); +} + +el_val_t str_split(el_val_t s, el_val_t sep) { + const char* str = EL_CSTR(s); + const char* sp = EL_CSTR(sep); + el_val_t lst = el_list_empty(); + if (!str) return lst; + if (!sp || !*sp) { + lst = el_list_append(lst, el_wrap_str(el_strdup(str))); + return lst; + } + size_t lp = strlen(sp); + const char* p = str; + const char* hit; + while ((hit = strstr(p, sp)) != NULL) { + size_t n = (size_t)(hit - p); + char* out = el_strbuf(n); + memcpy(out, p, n); + out[n] = '\0'; + lst = el_list_append(lst, el_wrap_str(out)); + p = hit + lp; + } + lst = el_list_append(lst, el_wrap_str(el_strdup(p))); + return lst; +} + +el_val_t str_char_at(el_val_t s, el_val_t i) { + const char* str = EL_CSTR(s); + int64_t idx = (int64_t)i; + if (!str) return el_wrap_str(el_strdup("")); + int64_t n = (int64_t)strlen(str); + if (idx < 0 || idx >= n) return el_wrap_str(el_strdup("")); + char buf[2]; + buf[0] = str[idx]; + buf[1] = '\0'; + return el_wrap_str(el_strdup(buf)); +} + +el_val_t str_char_code(el_val_t s, el_val_t i) { + const char* str = EL_CSTR(s); + int64_t idx = (int64_t)i; + if (!str) return 0; + int64_t n = (int64_t)strlen(str); + if (idx < 0 || idx >= n) return 0; + return (el_val_t)(unsigned char)str[idx]; +} + +static el_val_t str_pad(const char* s, int64_t width, const char* pad, int left) { + if (!s) s = ""; + if (!pad || !*pad) pad = " "; + int64_t lp = (int64_t)strlen(pad); + int64_t ls = (int64_t)strlen(s); + if (ls >= width) return el_wrap_str(el_strdup(s)); + int64_t need = width - ls; + char* out = el_strbuf((size_t)width); + if (left) { + for (int64_t i = 0; i < need; i++) out[i] = pad[i % lp]; + memcpy(out + need, s, (size_t)ls); + } else { + memcpy(out, s, (size_t)ls); + for (int64_t i = 0; i < need; i++) out[ls + i] = pad[i % lp]; + } + out[width] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_pad_left(el_val_t s, el_val_t width, el_val_t pad) { + return str_pad(EL_CSTR(s), (int64_t)width, EL_CSTR(pad), 1); +} + +el_val_t str_pad_right(el_val_t s, el_val_t width, el_val_t pad) { + return str_pad(EL_CSTR(s), (int64_t)width, EL_CSTR(pad), 0); +} + +el_val_t str_format(el_val_t fmt, el_val_t data) { + const char* tpl = EL_CSTR(fmt); + if (!tpl) return el_wrap_str(el_strdup("")); + JsonBuf b; jb_init(&b); + const char* p = tpl; + while (*p) { + if (*p == '{') { + const char* q = p + 1; + while (*q && *q != '}') q++; + if (*q == '}') { + size_t klen = (size_t)(q - p - 1); + char keybuf[256]; + if (klen < sizeof(keybuf)) { + memcpy(keybuf, p + 1, klen); + keybuf[klen] = '\0'; + el_val_t v = el_map_get(data, EL_STR(keybuf)); + if (v != 0 && looks_like_string(v)) { + jb_puts(&b, EL_CSTR(v)); + p = q + 1; + continue; + } else if (v != 0) { + jb_emit_int(&b, (int64_t)v); + p = q + 1; + continue; + } + } + /* Unknown key — leave {key} verbatim */ + jb_reserve(&b, klen + 2); + memcpy(b.buf + b.len, p, klen + 2); + b.len += klen + 2; + b.buf[b.len] = '\0'; + p = q + 1; + continue; + } + } + jb_putc(&b, *p); + p++; + } + return el_wrap_str(b.buf); +} + +el_val_t str_lower(el_val_t s) { return str_to_lower(s); } +el_val_t str_upper(el_val_t s) { return str_to_upper(s); } + +/* ── Text-processing primitives (Phase 1: byte/codepoint, ASCII char classes) + * + * Phase 1 covers the operations every text-handling caller used to roll by + * hand on top of str_index_of + str_slice. The character-class predicates + * (is_letter / is_digit / ...) are ASCII only — Unicode-grapheme awareness, + * NFC/NFD normalization, and regex are Phase 2. Single-char input checks the + * first byte; multi-char input requires ALL bytes to match (false otherwise). + * + * Counting: + * str_count non-overlapping occurrences of sub in s + * str_count_chars codepoint count (UTF-8 leading-byte count) + * str_count_bytes explicit byte length (alias of str_len) + * str_count_lines \n-delimited line count (\r\n folded to \n) + * str_count_words whitespace-delimited tokens, non-empty only + * str_count_letters ASCII [A-Za-z] + * str_count_digits ASCII [0-9] + * + * Find / position: + * str_index_of_all all byte offsets of sub, [] if none + * str_last_index_of last byte offset of sub, -1 if not found + * str_find_chars first index of any char in any_of, -1 if none + * + * Transform: + * str_repeat s * n (non-negative) + * str_reverse codepoint-reversed (NOT grapheme-aware) + * str_strip_prefix s without prefix if present, else s + * str_strip_suffix s without suffix if present, else s + * str_strip_chars strip leading+trailing chars matching any in chars + * str_lstrip strip leading whitespace + * str_rstrip strip trailing whitespace + * + * Char classification (Bool): + * is_letter, is_digit, is_alphanumeric, is_whitespace, + * is_punctuation, is_uppercase, is_lowercase + * + * Splitting: + * str_split_lines \n-delimited (\r\n folded). Trailing empty dropped. + * str_split_chars alias of native_string_chars in str_ namespace + * str_split_n split into at most n parts (last part keeps the + * rest verbatim, including any further separators) + * + * Joining: + * str_join [String] -> String, sep between elements + */ + +/* Count non-overlapping occurrences of sub in s. Empty sub returns 0. */ +el_val_t str_count(el_val_t sv, el_val_t subv) { + const char* s = EL_CSTR(sv); + const char* sub = EL_CSTR(subv); + if (!s || !sub || !*sub) return 0; + size_t lp = strlen(sub); + int64_t count = 0; + const char* p = s; + while ((p = strstr(p, sub)) != NULL) { + count++; + p += lp; /* non-overlapping advance */ + } + return (el_val_t)count; +} + +/* Codepoint count: walk bytes, count those NOT matching 10xxxxxx. */ +el_val_t str_count_chars(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + int64_t count = 0; + for (const unsigned char* p = (const unsigned char*)s; *p; p++) { + if ((*p & 0xC0) != 0x80) count++; + } + return (el_val_t)count; +} + +el_val_t str_count_bytes(el_val_t sv) { + return str_len(sv); +} + +el_val_t str_count_lines(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s || !*s) return 0; + int64_t count = 0; + int has_content = 0; + for (const char* p = s; *p; p++) { + has_content = 1; + if (*p == '\n') { + count++; + has_content = 0; /* the \n closed the line */ + } + } + if (has_content) count++; /* trailing line with no terminator */ + return (el_val_t)count; +} + +el_val_t str_count_words(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + int64_t count = 0; + int in_word = 0; + for (const unsigned char* p = (const unsigned char*)s; *p; p++) { + if (isspace(*p)) { + in_word = 0; + } else if (!in_word) { + in_word = 1; + count++; + } + } + return (el_val_t)count; +} + +el_val_t str_count_letters(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + int64_t count = 0; + for (const unsigned char* p = (const unsigned char*)s; *p; p++) { + if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z')) count++; + } + return (el_val_t)count; +} + +el_val_t str_count_digits(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + int64_t count = 0; + for (const unsigned char* p = (const unsigned char*)s; *p; p++) { + if (*p >= '0' && *p <= '9') count++; + } + return (el_val_t)count; +} + +el_val_t str_index_of_all(el_val_t sv, el_val_t subv) { + const char* s = EL_CSTR(sv); + const char* sub = EL_CSTR(subv); + el_val_t lst = el_list_empty(); + if (!s || !sub || !*sub) return lst; + size_t lp = strlen(sub); + const char* p = s; + const char* hit; + while ((hit = strstr(p, sub)) != NULL) { + lst = el_list_append(lst, (el_val_t)(int64_t)(hit - s)); + p = hit + lp; + } + return lst; +} + +el_val_t str_last_index_of(el_val_t sv, el_val_t subv) { + const char* s = EL_CSTR(sv); + const char* sub = EL_CSTR(subv); + if (!s || !sub || !*sub) return -1; + size_t lp = strlen(sub); + int64_t last = -1; + const char* p = s; + const char* hit; + while ((hit = strstr(p, sub)) != NULL) { + last = (int64_t)(hit - s); + p = hit + lp; + } + return (el_val_t)last; +} + +el_val_t str_find_chars(el_val_t sv, el_val_t any_of_v) { + const char* s = EL_CSTR(sv); + const char* any = EL_CSTR(any_of_v); + if (!s || !any || !*any) return -1; + for (const char* p = s; *p; p++) { + if (strchr(any, *p)) return (el_val_t)(int64_t)(p - s); + } + return -1; +} + +el_val_t str_repeat(el_val_t sv, el_val_t nv) { + const char* s = EL_CSTR(sv); + int64_t n = (int64_t)nv; + if (!s || n <= 0) return el_wrap_str(el_strdup("")); + size_t ls = strlen(s); + if (ls == 0) return el_wrap_str(el_strdup("")); + size_t total = ls * (size_t)n; + char* out = el_strbuf(total); + for (int64_t i = 0; i < n; i++) { + memcpy(out + i * ls, s, ls); + } + out[total] = '\0'; + return el_wrap_str(out); +} + +/* Reverse by codepoint: walk codepoints, copy each backwards into the output. + * NOT grapheme-aware (Phase 2). Combining marks attached to a base codepoint + * will detach. ASCII strings are byte-reverse equivalent. */ +el_val_t str_reverse(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + char* out = el_strbuf(n); + /* Walk forward, find each codepoint's byte length, then copy from the end. */ + size_t out_pos = n; + const unsigned char* p = (const unsigned char*)s; + while (*p) { + int cp_len; + if ((*p & 0x80) == 0x00) cp_len = 1; + else if ((*p & 0xE0) == 0xC0) cp_len = 2; + else if ((*p & 0xF0) == 0xE0) cp_len = 3; + else if ((*p & 0xF8) == 0xF0) cp_len = 4; + else cp_len = 1; /* invalid byte: passthrough */ + out_pos -= cp_len; + memcpy(out + out_pos, p, cp_len); + p += cp_len; + } + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_strip_prefix(el_val_t sv, el_val_t prefv) { + const char* s = EL_CSTR(sv); + const char* pref = EL_CSTR(prefv); + if (!s) return el_wrap_str(el_strdup("")); + if (!pref || !*pref) return el_wrap_str(el_strdup(s)); + size_t lp = strlen(pref); + size_t ls = strlen(s); + if (lp <= ls && strncmp(s, pref, lp) == 0) { + char* out = el_strbuf(ls - lp); + memcpy(out, s + lp, ls - lp); + out[ls - lp] = '\0'; + return el_wrap_str(out); + } + return el_wrap_str(el_strdup(s)); +} + +el_val_t str_strip_suffix(el_val_t sv, el_val_t sufv) { + const char* s = EL_CSTR(sv); + const char* suf = EL_CSTR(sufv); + if (!s) return el_wrap_str(el_strdup("")); + if (!suf || !*suf) return el_wrap_str(el_strdup(s)); + size_t ls = strlen(s); + size_t lsuf = strlen(suf); + if (lsuf <= ls && strcmp(s + ls - lsuf, suf) == 0) { + char* out = el_strbuf(ls - lsuf); + memcpy(out, s, ls - lsuf); + out[ls - lsuf] = '\0'; + return el_wrap_str(out); + } + return el_wrap_str(el_strdup(s)); +} + +el_val_t str_strip_chars(el_val_t sv, el_val_t charsv) { + const char* s = EL_CSTR(sv); + const char* chars = EL_CSTR(charsv); + if (!s) return el_wrap_str(el_strdup("")); + if (!chars || !*chars) return el_wrap_str(el_strdup(s)); + const char* start = s; + while (*start && strchr(chars, *start)) start++; + size_t n = strlen(start); + while (n > 0 && strchr(chars, start[n - 1])) n--; + char* out = el_strbuf(n); + memcpy(out, start, n); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_lstrip(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + while (*s && isspace((unsigned char)*s)) s++; + return el_wrap_str(el_strdup(s)); +} + +el_val_t str_rstrip(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + while (n > 0 && isspace((unsigned char)s[n - 1])) n--; + char* out = el_strbuf(n); + memcpy(out, s, n); + out[n] = '\0'; + return el_wrap_str(out); +} + +/* Character classification. + * Empty input returns false. Multi-char input requires ALL bytes to match. + * ASCII range only; Phase 2 will widen to Unicode. */ +static int s_all_match(el_val_t sv, int (*pred)(unsigned char)) { + const char* s = EL_CSTR(sv); + if (!s || !*s) return 0; + for (const unsigned char* p = (const unsigned char*)s; *p; p++) { + if (!pred(*p)) return 0; + } + return 1; +} + +static int p_letter(unsigned char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); } +static int p_digit(unsigned char c) { return c >= '0' && c <= '9'; } +static int p_alnum(unsigned char c) { return p_letter(c) || p_digit(c); } +static int p_white(unsigned char c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'; } +static int p_punct(unsigned char c) { return ispunct(c) ? 1 : 0; } +static int p_upper(unsigned char c) { return c >= 'A' && c <= 'Z'; } +static int p_lower(unsigned char c) { return c >= 'a' && c <= 'z'; } + +el_val_t is_letter(el_val_t s) { return (el_val_t)s_all_match(s, p_letter); } +el_val_t is_digit(el_val_t s) { return (el_val_t)s_all_match(s, p_digit); } +el_val_t is_alphanumeric(el_val_t s) { return (el_val_t)s_all_match(s, p_alnum); } +el_val_t is_whitespace(el_val_t s) { return (el_val_t)s_all_match(s, p_white); } +el_val_t is_punctuation(el_val_t s) { return (el_val_t)s_all_match(s, p_punct); } +el_val_t is_uppercase(el_val_t s) { return (el_val_t)s_all_match(s, p_upper); } +el_val_t is_lowercase(el_val_t s) { return (el_val_t)s_all_match(s, p_lower); } + +/* Split on \n. \r\n is folded to \n first. Trailing empty after final \n + * is dropped (so "a\nb\n" -> ["a", "b"], not ["a", "b", ""]). */ +el_val_t str_split_lines(el_val_t sv) { + const char* s = EL_CSTR(sv); + el_val_t lst = el_list_empty(); + if (!s) return lst; + size_t n = strlen(s); + /* Pre-scan: build into a normalized buffer with \r\n folded. */ + const char* line_start = s; + for (size_t i = 0; i <= n; i++) { + if (s[i] == '\n' || s[i] == '\0') { + size_t len = (size_t)(s + i - line_start); + /* Drop trailing \r if this was \r\n. */ + if (len > 0 && line_start[len - 1] == '\r') len--; + /* Drop final trailing-empty-after-newline. */ + if (s[i] == '\0' && len == 0 && i > 0 && s[i - 1] == '\n') break; + char* out = el_strbuf(len); + memcpy(out, line_start, len); + out[len] = '\0'; + lst = el_list_append(lst, el_wrap_str(out)); + if (s[i] == '\0') break; + line_start = s + i + 1; + } + } + return lst; +} + +el_val_t str_split_chars(el_val_t s) { + return native_string_chars(s); +} + +/* Split into at most n parts. The (n-1)th split point is the LAST split; + * after it, the remainder is appended verbatim including any further + * separators. n <= 0 returns an empty list. n == 1 returns [s]. */ +el_val_t str_split_n(el_val_t sv, el_val_t sepv, el_val_t nv) { + const char* s = EL_CSTR(sv); + const char* sep = EL_CSTR(sepv); + int64_t n = (int64_t)nv; + el_val_t lst = el_list_empty(); + if (!s) return lst; + if (n <= 0) return lst; + if (n == 1 || !sep || !*sep) { + lst = el_list_append(lst, el_wrap_str(el_strdup(s))); + return lst; + } + size_t lp = strlen(sep); + const char* p = s; + int64_t parts = 0; + const char* hit; + while (parts < n - 1 && (hit = strstr(p, sep)) != NULL) { + size_t len = (size_t)(hit - p); + char* out = el_strbuf(len); + memcpy(out, p, len); + out[len] = '\0'; + lst = el_list_append(lst, el_wrap_str(out)); + p = hit + lp; + parts++; + } + /* Remainder verbatim. */ + lst = el_list_append(lst, el_wrap_str(el_strdup(p))); + return lst; +} + +/* Join a [String] with a separator. Empty list -> "". Single-element -> + * that element. Non-string elements are stringified via int_to_str. */ +el_val_t str_join(el_val_t listv, el_val_t sepv) { + return list_join(listv, sepv); +} + +/* ── List additions ──────────────────────────────────────────────────────── */ + +el_val_t list_push(el_val_t list, el_val_t elem) { + return el_list_append(list, elem); +} + +el_val_t list_push_front(el_val_t listv, el_val_t elem) { + ElList* lst = (ElList*)(uintptr_t)listv; + if (!lst) { + el_val_t nl = el_list_empty(); + return el_list_append(nl, elem); + } + /* Append to grow capacity, then shift right */ + listv = el_list_append(listv, elem); + lst = (ElList*)(uintptr_t)listv; + for (int64_t i = lst->length - 1; i > 0; i--) { + lst->elems[i] = lst->elems[i - 1]; + } + lst->elems[0] = elem; + return EL_STR(lst); +} + +el_val_t list_join(el_val_t listv, el_val_t sep) { + ElList* lst = (ElList*)(uintptr_t)listv; + const char* sp = EL_CSTR(sep); + if (!sp) sp = ""; + if (!lst || lst->length == 0) return el_wrap_str(el_strdup("")); + JsonBuf b; jb_init(&b); + for (int64_t i = 0; i < lst->length; i++) { + if (i > 0) jb_puts(&b, sp); + el_val_t v = lst->elems[i]; + if (v == 0) continue; + if (looks_like_string(v)) { + jb_puts(&b, EL_CSTR(v)); + } else { + char tmp[32]; + snprintf(tmp, sizeof(tmp), "%lld", (long long)v); + jb_puts(&b, tmp); + } + } + return el_wrap_str(b.buf); +} + +el_val_t list_range(el_val_t start, el_val_t end) { + int64_t a = (int64_t)start; + int64_t b = (int64_t)end; + el_val_t lst = el_list_empty(); + for (int64_t i = a; i < b; i++) lst = el_list_append(lst, (el_val_t)i); + return lst; +} + +/* ── Bool helpers ────────────────────────────────────────────────────────── */ + +el_val_t bool_to_str(el_val_t b) { + return el_wrap_str(el_strdup(b ? "true" : "false")); +} + +/* ── Numeric parsing ─────────────────────────────────────────────────────── */ + +/* parse_int — strtoll with a default. str_to_int already exists but does not + * distinguish "0" from a parse failure, so callers that need a sentinel use + * this. Skips leading whitespace; accepts an optional leading +/-; returns + * default_val on empty input or no consumed digits. Trailing junk is ignored + * (atoi-style). */ +el_val_t parse_int(el_val_t sv, el_val_t default_val) { + const char* s = EL_CSTR(sv); + if (!s) return default_val; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == '\0') return default_val; + char* end = NULL; + long long n = strtoll(s, &end, 10); + if (end == s) return default_val; + return (el_val_t)n; +} + +/* ── Process ─────────────────────────────────────────────────────────────── */ + +el_val_t exit_program(el_val_t code) { + exit((int)code); + return 0; /* unreachable */ +} + +/* getpid_now — current process id. Named with the _now suffix to avoid + * colliding with the libc `getpid` declaration that the runtime already + * sees via (calling it `getpid` would fight the prototype). */ +el_val_t getpid_now(void) { + return (el_val_t)getpid(); +} + +/* el_mem_check — self-terminating memory guard for long-running compiler runs. + * + * Call this periodically (e.g. after each function compiled) to detect runaway + * memory growth before the OS OOM-killer fires. Reads the limit from the env + * var ELC_MAX_MEM_MB (default 512 MB). If resident set size exceeds the limit, + * prints a diagnostic to stderr and exits with code 1 so the caller (elb or a + * CI script) can handle the failure gracefully instead of having the whole + * machine go down. + * + * Platform notes: + * macOS — ru_maxrss is in bytes. + * Linux — ru_maxrss is in kilobytes. + * We normalise to MB before comparing. + * + * Returns 0 always (the only non-return path is the exit() branch). + */ +el_val_t el_mem_check(void) { + /* Read limit from env; default 512 MB. */ + long limit_mb = 512; + const char *env_val = getenv("ELC_MAX_MEM_MB"); + if (env_val && *env_val) { + long v = atol(env_val); + if (v > 0) limit_mb = v; + } + + struct rusage ru; + if (getrusage(RUSAGE_SELF, &ru) != 0) return 0; /* can't read — skip check */ + + long rss_mb; +#if defined(__APPLE__) || defined(__MACH__) + /* macOS: ru_maxrss is bytes */ + rss_mb = (long)(ru.ru_maxrss / (1024L * 1024L)); +#else + /* Linux: ru_maxrss is kilobytes */ + rss_mb = (long)(ru.ru_maxrss / 1024L); +#endif + + if (rss_mb >= limit_mb) { + fprintf(stderr, "elc: memory limit exceeded (%ldMB), aborting\n", limit_mb); + exit(1); + } + return 0; +} + +/* ── args() — command-line argument access ────────────────────────────────── + * Compiled El programs call args() to get a list of CLI arguments. + * Call el_runtime_init_args(argc, argv) at the start of C main() to populate. + * The args list excludes argv[0] (the program name). */ + +static el_val_t _el_args_list = 0; + +void el_runtime_init_args(int argc, char** argv) { + _el_args_list = el_list_empty(); + for (int i = 1; i < argc; i++) { + _el_args_list = el_list_append(_el_args_list, EL_STR(argv[i])); + } +} + +el_val_t args(void) { + if (!_el_args_list) _el_args_list = el_list_empty(); + return _el_args_list; +} + +/* ── CGI identity ──────────────────────────────────────────────────────────── + * Called once at program start by the generated main() of a cgi {} program. + * Stores CGI identity so dharma_* builtins can reference it. */ + +static const char* _el_cgi_name = NULL; +static const char* _el_cgi_dharma_id = NULL; +static const char* _el_cgi_principal = NULL; +static const char* _el_cgi_network = NULL; +static const char* _el_cgi_engram = NULL; + +void el_cgi_init(el_val_t name, el_val_t dharma_id, el_val_t principal, + el_val_t network, el_val_t engram) { + _el_cgi_name = EL_CSTR(name); + _el_cgi_dharma_id = EL_CSTR(dharma_id); + _el_cgi_principal = EL_CSTR(principal); + _el_cgi_network = EL_CSTR(network) ? EL_CSTR(network) : "dharma-mainnet"; + _el_cgi_engram = EL_CSTR(engram) ? EL_CSTR(engram) : "http://localhost:8742"; + printf("[cgi] identity: name=%s dharma_id=%s principal=%s network=%s engram=%s\n", + _el_cgi_name ? _el_cgi_name : "(unset)", + _el_cgi_dharma_id ? _el_cgi_dharma_id : "(unset)", + _el_cgi_principal ? _el_cgi_principal : "(unset)", + _el_cgi_network, + _el_cgi_engram); +} + + +/* ── Batch 3: Engram in-process graph store ──────────────────────────────── */ +/* + * Single global EngramStore allocated lazily on first call. All node and + * edge content strings are owned (strdup'd) by the store. Linear arrays + * with doubling capacity for both nodes and edges. + * + * Two-layer activation algorithm (engram_activate): + * + * LAYER 1 — Broad fan-out (background activation): + * 1. Find seed nodes whose content/label/tags contain query (case-insens). + * 2. BFS up to `depth` hops along ALL edges (excitatory and inhibitory). + * Every reachable node fires — nothing is filtered at this layer. + * 3. bg_act = seed.salience * temporal_decay * dampening + * propagated as: new_bg = parent_bg * edge_weight * 0.7 * (1 + tbonus) + * where tbonus ∈ {0, 0.10, 0.20} for co-temporal nodes. + * 4. If reached by multiple paths, take max background_activation. + * 5. Persist background_activation to EngramNode.background_activation. + * + * LAYER 2 — Executive filter (working memory promotion): + * 6. For each inhibitory edge where source has background_activation > 0: + * inhibition[target] = max(bg[source] * e->weight) + * 7. For each background-activated node: + * raw_wm = bg * goal_bias(node, query) * confidence + * * (1 - (1 - INHIBITION_FACTOR) * inhibition) + * 8. Per-type threshold gate: raw_wm >= type_threshold → promoted. + * Safety/DharmaSelf: 0.05 Canonical: 0.15 Lesson: 0.25 + * Belief/Entity: 0.30 Note/Memory/Working: 0.40 + * 9. If not promoted: suppression_count++. After + * ENGRAM_SUPPRESSION_BREAKTHROUGH suppressions → force breakthrough + * at ENGRAM_BREAKTHROUGH_WEIGHT (latent tension surfacing). + * 10. Persist working_memory_weight to EngramNode.working_memory_weight. + * 11. Sort: promoted nodes (wm > 0) first by wm desc, then background- + * only by bg desc. Context compilation uses ONLY promoted nodes. + * + * Temporal decay: + * decay_factor = exp(-lambda * age_hours / T_half) + * T_half = 168.0 h (one week), lambda = ln(2) + * + * Activation dampening: + * dampen = 1.0 / (1.0 + log(1 + activation_count)) + * + * engram_query_range(start_ms, end_ms): + * Returns nodes whose created_at OR last_activated falls within + * [start_ms, end_ms], sorted by created_at ascending. + */ + +/* Temporal decay constants. + * T_HALF_HOURS: half-life in hours — one week. After one week of no + * activation a node retains 50% of its base salience contribution. + * DECAY_LAMBDA: ln(2) ≈ 0.693147 */ +#define ENGRAM_T_HALF_HOURS 168.0 +#define ENGRAM_DECAY_LAMBDA 0.693147 + +/* Two-layer activation constants. + * ENGRAM_WM_THRESHOLD: minimum background_activation for a node to be + * considered for working-memory promotion (layer 2 candidate gate). + * ENGRAM_WM_DECAY: per-turn decay applied to working_memory_weight for + * nodes NOT re-activated in the current turn (conversational thread + * continuity: a node promoted in turn N persists with reduced weight + * into turn N+1 without re-activation cost). + * ENGRAM_SUPPRESSION_BREAKTHROUGH: after this many consecutive suppressions + * a latent node forces itself into working memory at reduced weight, + * modelling the brain's "intrusive thought" / unresolved-tension surfacing. + * ENGRAM_BREAKTHROUGH_WEIGHT: the reduced working_memory_weight assigned + * when a suppressed node breaks through. + * ENGRAM_INHIBITION_FACTOR: multiplier applied to working_memory_weight when + * an inhibitory edge fires against a node (0 = full suppress, 0.3 = partial). */ +#define ENGRAM_WM_THRESHOLD 0.15 +#define ENGRAM_WM_DECAY 0.7 +#define ENGRAM_SUPPRESSION_BREAKTHROUGH 5 +#define ENGRAM_BREAKTHROUGH_WEIGHT 0.25 +#define ENGRAM_INHIBITION_FACTOR 0.1 + +/* ── Layered consciousness architecture ────────────────────────────────────── + * + * The engram graph is stratified into LAYERS that gate which suppressions + * apply during the executive filter pass. Layers are ordered shallow-to-deep + * by `activation_priority`; the deepest layer (priority 0, conventionally + * "safety") is the structural floor of the soul: nodes here cannot be + * silenced by inhibitory edges from any other layer. Higher layers + * (core-identity, domain-knowledge, imprint, suit) are normally + * suppressible — they participate in attentional inhibition and goal + * focus the way the prior single-graph implementation did. + * + * The five canonical layers (see engram_init_layers): + * 0. safety — structural, transparent, non-injectable, non-suppressible + * 1. core-identity — default for legacy nodes; suppressible + * 2. domain-knowledge— suppressible + * 3. imprint — runtime-injectable (an Imprint package can add/remove) + * 4. suit — runtime-injectable (a Suit overlays domain skill) + * + * Three-pass activation (engram_activate): + * Pass 1 — Background fan-out: BFS spreads activation across ALL layers + * (existing behavior preserved). Inhibitory edges propagate at + * this layer too; no filtering happens here. + * Pass 2 — Working memory promotion: type-threshold gate, goal bias, + * confidence weighting, inhibitory suppression. Inhibitory edges + * ONLY apply against nodes whose layer is `suppressible == 1`. + * Nodes in non-suppressible layers (Layer 0) ignore inhibition. + * Pass 3 — Layer 0 override: every node in a non-suppressible layer that + * received background activation has its working_memory_weight + * forced to >= ENGRAM_LAYER0_OVERRIDE_WEIGHT. The sacred fire — + * safety nodes that touched any seed unconditionally surface, + * even when the executive filter would have silenced them. + * + * Layer fields: + * suppressible : 0 → inhibitory edges are ignored against nodes in this + * layer during pass 2. Pass 3 also force-promotes them. + * 1 → standard behavior (most layers). + * transparent : 1 → emitted into the prompt context so its content shapes + * output, but filtered out of "what do you know about + * yourself?" introspection queries (engram_search and + * friends do not return transparent-layer nodes by + * default). 0 → fully visible to introspection. + * injectable : 1 → can be added/removed at runtime via engram_add_layer + * and engram_remove_layer (imprints, suits). + * 0 → built-in, fixed at engram_get() initialization. + * + * Backward compatibility: + * Nodes and edges loaded from snapshots without a `layer_id` field default + * to layer 1 (core-identity). The five canonical layers are always present. + */ +#define ENGRAM_LAYER_SAFETY 0u +#define ENGRAM_LAYER_CORE_IDENTITY 1u +#define ENGRAM_LAYER_DOMAIN 2u +#define ENGRAM_LAYER_IMPRINT 3u +#define ENGRAM_LAYER_SUIT 4u +#define ENGRAM_LAYER_DEFAULT ENGRAM_LAYER_CORE_IDENTITY + +/* Pass 3 override floor. Layer 0 nodes that received any background + * activation are force-promoted to AT LEAST this working_memory_weight, + * regardless of inhibitory suppression in pass 2. */ +#define ENGRAM_LAYER0_OVERRIDE_WEIGHT 1.0 + +/* Per-node-type activation thresholds. + * Lower tier / safety-critical nodes fire more readily. */ +static double engram_type_threshold(const char* node_type, const char* tier) { + if (node_type) { + if (strcmp(node_type, "DharmaSelf") == 0) return 0.05; + if (strcmp(node_type, "Safety") == 0) return 0.05; + } + if (tier) { + if (strcmp(tier, "Canonical") == 0) return 0.15; + if (strcmp(tier, "Lesson") == 0) return 0.25; + } + if (node_type) { + if (strcmp(node_type, "Belief") == 0) return 0.30; + if (strcmp(node_type, "Entity") == 0) return 0.30; + } + return 0.40; /* Note / Memory / Working (most nodes) */ +} + +typedef struct EngramNode { + char* id; + char* content; + char* node_type; + char* label; + char* tier; + char* tags; + char* metadata; + double salience; + double importance; + double confidence; + double temporal_decay_rate; /* per-node override for lambda; 0 = use default */ + int64_t activation_count; + int64_t last_activated; + int64_t created_at; + int64_t updated_at; + /* Two-layer activation fields ───────────────────────────────────────── + * background_activation: Layer 1. Set by BFS fan-out on every query. + * Every reachable node fires here — nothing is filtered at this stage. + * Models the brain's massive parallel sub-threshold activation of all + * associated content in response to a stimulus. + * working_memory_weight: Layer 2. Executive filter output. Only nodes + * that survive goal-state / attentional-bias scoring receive a + * non-zero weight here. Context compilation ONLY uses this field. + * Background-activated nodes with working_memory_weight == 0 remain + * latent — real, available, but silent. + * suppression_count: Consecutive turn count where this node was + * background-activated but NOT promoted to working memory. High + * values signal the node "wants to surface." After + * ENGRAM_SUPPRESSION_BREAKTHROUGH consecutive suppressions the node + * is force-promoted at a reduced weight (breakthrough activation). */ + double background_activation; + double working_memory_weight; + int32_t suppression_count; + /* Layered consciousness — see ENGRAM_LAYER_* macros and engram_init_layers. + * Defaults to ENGRAM_LAYER_DEFAULT (1, core-identity) for legacy nodes + * created via engram_node / engram_node_full and for snapshots that + * predate the layered schema. */ + uint32_t layer_id; +} EngramNode; + +typedef struct EngramEdge { + char* id; + char* from_id; + char* to_id; + char* relation; + char* metadata; + double weight; + double confidence; + int64_t created_at; + int64_t updated_at; + int64_t last_fired; + /* Inhibitory flag: when 1, activating the source node SUPPRESSES the + * working_memory_weight of the target node rather than exciting it. + * Models attentional inhibition: "I am focused on code work" creates + * inhibitory edges to personal/emotional nodes, preventing them from + * surfacing even if they have high background_activation. */ + int inhibitory; + /* Layered consciousness — edges carry a layer assignment for + * categorization/visualization. Pass 2 inhibitory gating is decided by + * the TARGET node's layer (whether it's suppressible), not by the edge + * layer. Defaults to ENGRAM_LAYER_DEFAULT. */ + uint32_t layer_id; +} EngramEdge; + +/* Layered consciousness — runtime layer registry entry. */ +typedef struct EngramLayer { + uint32_t layer_id; /* 0 = deepest (safety/limbic) */ + char* name; /* persistent — owned by the store */ + uint32_t activation_priority; /* lower = fires earlier; safety = 0 */ + int suppressible; /* can higher layers suppress nodes here? */ + int transparent; /* invisible to introspection queries? */ + int injectable; /* can be added/removed at runtime? */ +} EngramLayer; + +typedef struct EngramStore { + EngramNode* nodes; + int64_t node_count; + int64_t node_capacity; + EngramEdge* edges; + int64_t edge_count; + int64_t edge_capacity; + /* Layer registry — see engram_init_layers. The five canonical layers + * are always present; injectable layers (imprint, suit) are extended + * via engram_add_layer at runtime. layer_id values are assigned + * monotonically; removed injectable layers leave a NULL `name` slot + * (tombstone) so existing layer_id references on nodes stay stable. */ + EngramLayer* layers; + size_t layer_count; + size_t layer_capacity; +} EngramStore; + +static EngramStore* engram_global = NULL; + +/* Initialize the five canonical layers on a fresh store. Called once from + * engram_get(). Layer ids 0..4 are reserved; runtime-injected imprint/suit + * layers (engram_add_layer) get ids 5+. */ +static void engram_init_layers(EngramStore* g) { + g->layer_capacity = 16; + g->layers = calloc(g->layer_capacity, sizeof(EngramLayer)); + if (!g->layers) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + g->layer_count = 0; + + /* Layer 0 — safety. Structural floor. Non-suppressible; transparent + * (filtered out of introspection but still shapes output); not + * runtime-injectable. */ + g->layers[g->layer_count++] = (EngramLayer){ + .layer_id = ENGRAM_LAYER_SAFETY, + .name = el_strdup_persist("safety"), + .activation_priority = 0, + .suppressible = 0, + .transparent = 1, + .injectable = 0 + }; + /* Layer 1 — core-identity. The default home for legacy nodes. */ + g->layers[g->layer_count++] = (EngramLayer){ + .layer_id = ENGRAM_LAYER_CORE_IDENTITY, + .name = el_strdup_persist("core-identity"), + .activation_priority = 10, + .suppressible = 1, + .transparent = 0, + .injectable = 0 + }; + /* Layer 2 — domain-knowledge. */ + g->layers[g->layer_count++] = (EngramLayer){ + .layer_id = ENGRAM_LAYER_DOMAIN, + .name = el_strdup_persist("domain-knowledge"), + .activation_priority = 20, + .suppressible = 1, + .transparent = 0, + .injectable = 0 + }; + /* Layer 3 — imprint. Injectable: an imprint package adds/removes this + * layer (and the nodes assigned to it) as a unit. */ + g->layers[g->layer_count++] = (EngramLayer){ + .layer_id = ENGRAM_LAYER_IMPRINT, + .name = el_strdup_persist("imprint"), + .activation_priority = 30, + .suppressible = 1, + .transparent = 0, + .injectable = 1 + }; + /* Layer 4 — suit. Injectable: a Suit overlays domain skill (e.g. + * "enterprise advisor", "divorce lawyer") and can be detached. */ + g->layers[g->layer_count++] = (EngramLayer){ + .layer_id = ENGRAM_LAYER_SUIT, + .name = el_strdup_persist("suit"), + .activation_priority = 40, + .suppressible = 1, + .transparent = 0, + .injectable = 1 + }; +} + +static EngramStore* engram_get(void) { + if (engram_global) return engram_global; + engram_global = calloc(1, sizeof(EngramStore)); + if (!engram_global) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + engram_global->node_capacity = 16; + engram_global->nodes = calloc((size_t)engram_global->node_capacity, sizeof(EngramNode)); + engram_global->edge_capacity = 16; + engram_global->edges = calloc((size_t)engram_global->edge_capacity, sizeof(EngramEdge)); + engram_init_layers(engram_global); + return engram_global; +} + +/* Resolve a layer record by id. Returns NULL if no layer with that id + * exists (e.g. a removed injectable layer or a malformed snapshot). */ +static EngramLayer* engram_find_layer(uint32_t layer_id) { + EngramStore* g = engram_get(); + for (size_t i = 0; i < g->layer_count; i++) { + EngramLayer* L = &g->layers[i]; + if (!L->name) continue; /* tombstone for removed injectable layer */ + if (L->layer_id == layer_id) return L; + } + return NULL; +} + +/* Resolve a layer record by name. Returns NULL if not found. */ +static EngramLayer* engram_find_layer_by_name(const char* name) { + if (!name || !*name) return NULL; + EngramStore* g = engram_get(); + for (size_t i = 0; i < g->layer_count; i++) { + EngramLayer* L = &g->layers[i]; + if (!L->name) continue; + if (strcmp(L->name, name) == 0) return L; + } + return NULL; +} + +/* Allocate the next layer id. Skips ids that are still in use. */ +static uint32_t engram_next_layer_id(void) { + EngramStore* g = engram_get(); + uint32_t maxid = 0; + for (size_t i = 0; i < g->layer_count; i++) { + if (g->layers[i].layer_id > maxid) maxid = g->layers[i].layer_id; + } + return maxid + 1; +} + +/* Whether a node in `layer_id` may be silenced by inhibitory edges in pass 2. */ +static int engram_layer_is_suppressible(uint32_t layer_id) { + EngramLayer* L = engram_find_layer(layer_id); + if (!L) return 1; /* unknown layer → safe default: standard suppression */ + return L->suppressible ? 1 : 0; +} + +/* Whether a layer is transparent (its content shapes output but is filtered + * from introspection queries). Currently used to mark Layer 0 as invisible + * to "what do you know about yourself" lookups while still letting it + * dominate the prompt context. */ +static int engram_layer_is_transparent(uint32_t layer_id) { + EngramLayer* L = engram_find_layer(layer_id); + if (!L) return 0; + return L->transparent ? 1 : 0; +} + +static int64_t engram_now_ms(void) { + struct timeval tv; gettimeofday(&tv, NULL); + return (int64_t)tv.tv_sec * 1000LL + (int64_t)tv.tv_usec / 1000LL; +} + +static EngramNode* engram_find_node(const char* id) { + if (!id) return NULL; + EngramStore* g = engram_get(); + for (int64_t i = 0; i < g->node_count; i++) { + if (g->nodes[i].id && strcmp(g->nodes[i].id, id) == 0) return &g->nodes[i]; + } + return NULL; +} + +static int64_t engram_find_node_index(const char* id) { + if (!id) return -1; + EngramStore* g = engram_get(); + for (int64_t i = 0; i < g->node_count; i++) { + if (g->nodes[i].id && strcmp(g->nodes[i].id, id) == 0) return i; + } + return -1; +} + +static void engram_grow_nodes(void) { + EngramStore* g = engram_get(); + if (g->node_count < g->node_capacity) return; + int64_t nc = g->node_capacity * 2; + g->nodes = realloc(g->nodes, (size_t)nc * sizeof(EngramNode)); + if (!g->nodes) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + memset(g->nodes + g->node_capacity, 0, + (size_t)(nc - g->node_capacity) * sizeof(EngramNode)); + g->node_capacity = nc; +} + +static void engram_grow_edges(void) { + EngramStore* g = engram_get(); + if (g->edge_count < g->edge_capacity) return; + int64_t nc = g->edge_capacity * 2; + g->edges = realloc(g->edges, (size_t)nc * sizeof(EngramEdge)); + if (!g->edges) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + memset(g->edges + g->edge_capacity, 0, + (size_t)(nc - g->edge_capacity) * sizeof(EngramEdge)); + g->edge_capacity = nc; +} + +/* Build a fresh UUID string. Reuses uuid_new but takes the underlying char*. */ +static char* engram_new_id(void) { + el_val_t v = uuid_new(); + const char* s = EL_CSTR(v); + return el_strdup(s ? s : ""); +} + +/* Convert a node into an ElMap of its fields. */ +static el_val_t engram_node_to_map(const EngramNode* n) { + el_val_t m = el_map_new(0); + m = el_map_set(m, EL_STR(el_strdup("id")), EL_STR(el_strdup(n->id ? n->id : ""))); + m = el_map_set(m, EL_STR(el_strdup("content")), EL_STR(el_strdup(n->content ? n->content : ""))); + m = el_map_set(m, EL_STR(el_strdup("node_type")), EL_STR(el_strdup(n->node_type ? n->node_type : ""))); + m = el_map_set(m, EL_STR(el_strdup("label")), EL_STR(el_strdup(n->label ? n->label : ""))); + m = el_map_set(m, EL_STR(el_strdup("tier")), EL_STR(el_strdup(n->tier ? n->tier : "Working"))); + m = el_map_set(m, EL_STR(el_strdup("tags")), EL_STR(el_strdup(n->tags ? n->tags : ""))); + m = el_map_set(m, EL_STR(el_strdup("metadata")), EL_STR(el_strdup(n->metadata ? n->metadata : "{}"))); + m = el_map_set(m, EL_STR(el_strdup("salience")), el_from_float(n->salience)); + m = el_map_set(m, EL_STR(el_strdup("importance")), el_from_float(n->importance)); + m = el_map_set(m, EL_STR(el_strdup("confidence")), el_from_float(n->confidence)); + m = el_map_set(m, EL_STR(el_strdup("temporal_decay_rate")), el_from_float(n->temporal_decay_rate)); + m = el_map_set(m, EL_STR(el_strdup("activation_count")), (el_val_t)n->activation_count); + m = el_map_set(m, EL_STR(el_strdup("last_activated")), (el_val_t)n->last_activated); + m = el_map_set(m, EL_STR(el_strdup("created_at")), (el_val_t)n->created_at); + m = el_map_set(m, EL_STR(el_strdup("updated_at")), (el_val_t)n->updated_at); + m = el_map_set(m, EL_STR(el_strdup("background_activation")), el_from_float(n->background_activation)); + m = el_map_set(m, EL_STR(el_strdup("working_memory_weight")), el_from_float(n->working_memory_weight)); + m = el_map_set(m, EL_STR(el_strdup("suppression_count")), (el_val_t)n->suppression_count); + m = el_map_set(m, EL_STR(el_strdup("layer_id")), (el_val_t)(int64_t)n->layer_id); + return m; +} + +/* (Node JSON serialization is provided by `engram_emit_node_json` further + * down in the persistence section — reused by the *_json builtins below.) */ +static void engram_emit_node_json(JsonBuf* b, const EngramNode* n); +static void engram_emit_edge_json(JsonBuf* b, const EngramEdge* e); + +/* Salience may arrive either as a float bit-pattern or as a small integer + * (e.g. 1, meaning 1.0). Heuristic: if interpreted as double it's in + * [0.0, 100.0] use it; otherwise treat as int and convert. */ +static double engram_decode_score(el_val_t v) { + double f = el_to_float(v); + if (!isnan(f) && !isinf(f) && f >= 0.0 && f <= 100.0) return f; + int64_t n = (int64_t)v; + return (double)n; +} + +static char* engram_first_n_chars(const char* s, size_t n) { + if (!s) return el_strdup(""); + size_t l = strlen(s); + if (l > n) l = n; + char* out = el_strbuf(l); + memcpy(out, s, l); + out[l] = '\0'; + return out; +} + +el_val_t engram_node(el_val_t content, el_val_t node_type, el_val_t salience) { + EngramStore* g = engram_get(); + engram_grow_nodes(); + EngramNode* n = &g->nodes[g->node_count]; + memset(n, 0, sizeof(*n)); + n->id = engram_new_id(); + const char* c = EL_CSTR(content); + const char* nt = EL_CSTR(node_type); + n->content = el_strdup(c ? c : ""); + n->node_type = el_strdup(nt && *nt ? nt : "Memory"); + n->label = engram_first_n_chars(c, 60); + n->tier = el_strdup("Working"); + n->tags = el_strdup(""); + n->metadata = el_strdup("{}"); + n->salience = engram_decode_score(salience); + if (n->salience <= 0.0 || n->salience > 1.0) n->salience = 0.5; + n->importance = 0.5; + n->confidence = 1.0; + n->temporal_decay_rate = 0.0; /* 0 = use global default ENGRAM_DECAY_LAMBDA */ + n->activation_count = 0; + int64_t now = engram_now_ms(); + n->last_activated = now; + n->created_at = now; + n->updated_at = now; + n->layer_id = ENGRAM_LAYER_DEFAULT; + g->node_count++; + return el_wrap_str(el_strdup(n->id)); +} + +el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags) { + EngramStore* g = engram_get(); + engram_grow_nodes(); + EngramNode* n = &g->nodes[g->node_count]; + memset(n, 0, sizeof(*n)); + n->id = engram_new_id(); + const char* c = EL_CSTR(content); + const char* nt = EL_CSTR(node_type); + const char* lb = EL_CSTR(label); + const char* ti = EL_CSTR(tier); + const char* tg = EL_CSTR(tags); + n->content = el_strdup(c ? c : ""); + n->node_type = el_strdup(nt && *nt ? nt : "Memory"); + n->label = el_strdup(lb && *lb ? lb : (c ? engram_first_n_chars(c, 60) : "")); + n->tier = el_strdup(ti && *ti ? ti : "Working"); + n->tags = el_strdup(tg ? tg : ""); + n->metadata = el_strdup("{}"); + n->salience = engram_decode_score(salience); + n->importance = engram_decode_score(importance); + n->confidence = engram_decode_score(confidence); + if (n->salience <= 0.0 || n->salience > 1.0) n->salience = 0.5; + if (n->importance <= 0.0 || n->importance > 1.0) n->importance = 0.5; + if (n->confidence <= 0.0 || n->confidence > 1.0) n->confidence = 1.0; + n->temporal_decay_rate = 0.0; /* 0 = use global default ENGRAM_DECAY_LAMBDA */ + n->activation_count = 0; + int64_t now = engram_now_ms(); + n->last_activated = now; + n->created_at = now; + n->updated_at = now; + n->layer_id = ENGRAM_LAYER_DEFAULT; + g->node_count++; + return el_wrap_str(el_strdup(n->id)); +} + +/* engram_node_layered — like engram_node_full but with explicit layer + * assignment and an additional `status` slot reserved for callers that + * track lifecycle state in metadata. The signature mirrors the public API + * defined in the layered consciousness design doc: + * + * engram_node_layered(content, node_type, label, + * salience, certainty, confidence, + * status, tags, layer_id) + * + * `certainty` is folded into `importance` (it occupies the same axis in + * the existing schema). `status` is recorded under metadata.status; an + * empty status leaves metadata as the default "{}". + * + * If `layer_id` does not resolve to a known layer the call falls back to + * ENGRAM_LAYER_DEFAULT — better to keep the node addressable than to drop + * it because of a stale layer reference. Callers wanting strict validation + * should engram_list_layers first. */ +el_val_t engram_node_layered(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t certainty, el_val_t confidence, + el_val_t status, el_val_t tags, el_val_t layer_id) { + EngramStore* g = engram_get(); + engram_grow_nodes(); + EngramNode* n = &g->nodes[g->node_count]; + memset(n, 0, sizeof(*n)); + n->id = engram_new_id(); + const char* c = EL_CSTR(content); + const char* nt = EL_CSTR(node_type); + const char* lb = EL_CSTR(label); + const char* tg = EL_CSTR(tags); + const char* st = EL_CSTR(status); + n->content = el_strdup(c ? c : ""); + n->node_type = el_strdup(nt && *nt ? nt : "Memory"); + n->label = el_strdup(lb && *lb ? lb : (c ? engram_first_n_chars(c, 60) : "")); + n->tier = el_strdup("Working"); + n->tags = el_strdup(tg ? tg : ""); + if (st && *st) { + /* Minimal metadata payload: {"status":"..."}. Keep it cheap so + * callers using `status` don't pay JSON parse cost on every read. */ + size_t sl = strlen(st) + 16; + char* meta = el_strbuf(sl); + snprintf(meta, sl, "{\"status\":\"%s\"}", st); + n->metadata = meta; + } else { + n->metadata = el_strdup("{}"); + } + n->salience = engram_decode_score(salience); + n->importance = engram_decode_score(certainty); + n->confidence = engram_decode_score(confidence); + if (n->salience <= 0.0 || n->salience > 1.0) n->salience = 0.5; + if (n->importance <= 0.0 || n->importance > 1.0) n->importance = 0.5; + if (n->confidence <= 0.0 || n->confidence > 1.0) n->confidence = 1.0; + n->temporal_decay_rate = 0.0; + n->activation_count = 0; + int64_t now = engram_now_ms(); + n->last_activated = now; + n->created_at = now; + n->updated_at = now; + /* Resolve layer assignment. Caller passes either a numeric layer_id or + * a stringified id; el_to_float / int cast tolerates both. */ + int64_t lid = (int64_t)layer_id; + if (lid < 0) lid = (int64_t)ENGRAM_LAYER_DEFAULT; + if (!engram_find_layer((uint32_t)lid)) lid = (int64_t)ENGRAM_LAYER_DEFAULT; + n->layer_id = (uint32_t)lid; + g->node_count++; + return el_wrap_str(el_strdup(n->id)); +} + +/* ── Layer registry public API ────────────────────────────────────────────── + * + * The five canonical layers are seeded at engram_get() initialization. + * Runtime code (typically imprint/suit injection logic at the EL level) + * can extend the registry with engram_add_layer() — only layers marked + * `injectable=1` may be removed via engram_remove_layer(). Removing a + * layer leaves a tombstone slot so existing layer_id references on nodes + * stay valid; orphaned references resolve to "unknown layer" and inherit + * the default suppression behavior. + */ + +/* engram_add_layer — register a new layer at runtime. + * Returns the assigned layer_id as an el_val_t int (cast back via int64_t). + * Conflicting names are rejected (returns 0). */ +el_val_t engram_add_layer(el_val_t name, el_val_t priority, el_val_t suppressible, + el_val_t transparent, el_val_t injectable) { + EngramStore* g = engram_get(); + const char* nm = EL_CSTR(name); + if (!nm || !*nm) return (el_val_t)0; + if (engram_find_layer_by_name(nm)) { + /* Name collision — return existing id so callers are idempotent. */ + return (el_val_t)(int64_t)engram_find_layer_by_name(nm)->layer_id; + } + if (g->layer_count >= g->layer_capacity) { + size_t nc = g->layer_capacity ? g->layer_capacity * 2 : 16; + EngramLayer* grown = realloc(g->layers, nc * sizeof(EngramLayer)); + if (!grown) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + memset(grown + g->layer_capacity, 0, + (nc - g->layer_capacity) * sizeof(EngramLayer)); + g->layers = grown; + g->layer_capacity = nc; + } + EngramLayer* L = &g->layers[g->layer_count++]; + L->layer_id = engram_next_layer_id(); + L->name = el_strdup_persist(nm); + L->activation_priority = (uint32_t)(int64_t)priority; + L->suppressible = (int)(int64_t)suppressible ? 1 : 0; + L->transparent = (int)(int64_t)transparent ? 1 : 0; + L->injectable = (int)(int64_t)injectable ? 1 : 0; + return (el_val_t)(int64_t)L->layer_id; +} + +/* engram_remove_layer — remove an injectable layer by id. + * Built-in (non-injectable) layers cannot be removed. Nodes still tagged + * with the removed layer's id keep their tag but resolve to "unknown + * layer" thereafter and inherit standard (suppressible) behavior. + * Returns 1 on success, 0 on failure (unknown id, non-injectable). */ +el_val_t engram_remove_layer(el_val_t layer_id) { + EngramStore* g = engram_get(); + int64_t lid = (int64_t)layer_id; + for (size_t i = 0; i < g->layer_count; i++) { + EngramLayer* L = &g->layers[i]; + if (!L->name) continue; + if ((int64_t)L->layer_id != lid) continue; + if (!L->injectable) return (el_val_t)0; + free(L->name); + L->name = NULL; /* tombstone */ + /* Leave layer_id, priority, flags intact so debug snapshots can + * still distinguish "removed at runtime" from "never existed". */ + return (el_val_t)1; + } + return (el_val_t)0; +} + +/* engram_list_layers — enumerate the active layer registry. + * Returns an ElList of maps, one per non-tombstone layer, sorted by + * activation_priority ascending (deepest layer first). */ +el_val_t engram_list_layers(void) { + EngramStore* g = engram_get(); + el_val_t lst = el_list_empty(); + if (g->layer_count == 0) return lst; + /* Build an index sorted by activation_priority ascending. */ + size_t* idx = malloc(g->layer_count * sizeof(size_t)); + if (!idx) return lst; + size_t live = 0; + for (size_t i = 0; i < g->layer_count; i++) { + if (g->layers[i].name) idx[live++] = i; + } + /* Insertion sort — N is small (≤ a few dozen layers). */ + for (size_t i = 1; i < live; i++) { + size_t key = idx[i]; + uint32_t kp = g->layers[key].activation_priority; + size_t j = i; + while (j > 0 && g->layers[idx[j - 1]].activation_priority > kp) { + idx[j] = idx[j - 1]; + j--; + } + idx[j] = key; + } + for (size_t i = 0; i < live; i++) { + EngramLayer* L = &g->layers[idx[i]]; + el_val_t m = el_map_new(0); + m = el_map_set(m, EL_STR(el_strdup("layer_id")), + (el_val_t)(int64_t)L->layer_id); + m = el_map_set(m, EL_STR(el_strdup("name")), + EL_STR(el_strdup(L->name ? L->name : ""))); + m = el_map_set(m, EL_STR(el_strdup("activation_priority")), + (el_val_t)(int64_t)L->activation_priority); + m = el_map_set(m, EL_STR(el_strdup("suppressible")), + (el_val_t)(int64_t)(L->suppressible ? 1 : 0)); + m = el_map_set(m, EL_STR(el_strdup("transparent")), + (el_val_t)(int64_t)(L->transparent ? 1 : 0)); + m = el_map_set(m, EL_STR(el_strdup("injectable")), + (el_val_t)(int64_t)(L->injectable ? 1 : 0)); + lst = el_list_append(lst, m); + } + free(idx); + return lst; +} + +el_val_t engram_get_node(el_val_t id) { + const char* sid = EL_CSTR(id); + EngramNode* n = engram_find_node(sid); + if (!n) return el_map_new(0); + return engram_node_to_map(n); +} + +void engram_strengthen(el_val_t node_id) { + const char* sid = EL_CSTR(node_id); + EngramNode* n = engram_find_node(sid); + if (!n) return; + n->salience += 0.05; + if (n->salience > 1.0) n->salience = 1.0; + n->activation_count++; + n->last_activated = engram_now_ms(); + n->updated_at = n->last_activated; +} + +void engram_forget(el_val_t node_id) { + const char* sid = EL_CSTR(node_id); + if (!sid) return; + EngramStore* g = engram_get(); + int64_t idx = engram_find_node_index(sid); + if (idx < 0) return; + /* Free node strings */ + EngramNode* n = &g->nodes[idx]; + free(n->id); free(n->content); free(n->node_type); free(n->label); + free(n->tier); free(n->tags); free(n->metadata); + /* Shift remaining nodes down */ + for (int64_t i = idx + 1; i < g->node_count; i++) { + g->nodes[i - 1] = g->nodes[i]; + } + g->node_count--; + memset(&g->nodes[g->node_count], 0, sizeof(EngramNode)); + /* Remove all incident edges */ + int64_t w = 0; + for (int64_t r = 0; r < g->edge_count; r++) { + EngramEdge* e = &g->edges[r]; + int incident = (e->from_id && strcmp(e->from_id, sid) == 0) || + (e->to_id && strcmp(e->to_id, sid) == 0); + if (incident) { + free(e->id); free(e->from_id); free(e->to_id); + free(e->relation); free(e->metadata); + } else { + if (w != r) g->edges[w] = g->edges[r]; + w++; + } + } + g->edge_count = w; +} + +el_val_t engram_node_count(void) { + return (el_val_t)engram_get()->node_count; +} + +static int istr_contains(const char* hay, const char* needle) { + if (!hay || !needle || !*needle) return 0; + size_t nl = strlen(needle); + for (const char* p = hay; *p; p++) { + if (strncasecmp(p, needle, nl) == 0) return 1; + } + return 0; +} + +el_val_t engram_search(el_val_t query, el_val_t limit) { + EngramStore* g = engram_get(); + const char* q = EL_CSTR(query); + int64_t lim = (int64_t)limit; + if (lim <= 0) lim = 100; + el_val_t lst = el_list_empty(); + if (!q || !*q) return lst; + int64_t found = 0; + for (int64_t i = 0; i < g->node_count && found < lim; i++) { + EngramNode* n = &g->nodes[i]; + /* Filter transparent layers: nodes whose layer is `transparent=1` + * shape output but are invisible to introspection ("what do you + * know about yourself"). They still surface via engram_activate + * + engram_compile_layered_json — that's the legitimate path. */ + if (engram_layer_is_transparent(n->layer_id)) continue; + if (istr_contains(n->content, q) || + istr_contains(n->label, q) || + istr_contains(n->tags, q)) { + lst = el_list_append(lst, engram_node_to_map(n)); + found++; + } + } + return lst; +} + +/* Sort node indices by salience desc (small N, insertion sort is fine). */ +static void engram_sort_indices_by_salience(int64_t* arr, int64_t n, + const EngramNode* nodes) { + for (int64_t i = 1; i < n; i++) { + int64_t key = arr[i]; + double ks = nodes[key].salience; + int64_t j = i - 1; + while (j >= 0 && nodes[arr[j]].salience < ks) { + arr[j + 1] = arr[j]; + j--; + } + arr[j + 1] = key; + } +} + +el_val_t engram_scan_nodes(el_val_t limit, el_val_t offset) { + EngramStore* g = engram_get(); + int64_t lim = (int64_t)limit; if (lim <= 0) lim = 100; + int64_t off = (int64_t)offset; if (off < 0) off = 0; + el_val_t lst = el_list_empty(); + if (g->node_count == 0) return lst; + int64_t* idx = malloc((size_t)g->node_count * sizeof(int64_t)); + if (!idx) return lst; + /* Skip transparent layers — same introspection-filter rationale as + * engram_search above. */ + int64_t live = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (engram_layer_is_transparent(g->nodes[i].layer_id)) continue; + idx[live++] = i; + } + engram_sort_indices_by_salience(idx, live, g->nodes); + int64_t end = off + lim; + if (end > live) end = live; + for (int64_t i = off; i < end; i++) { + lst = el_list_append(lst, engram_node_to_map(&g->nodes[idx[i]])); + } + free(idx); + return lst; +} + +void engram_connect(el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t relation) { + EngramStore* g = engram_get(); + const char* f = EL_CSTR(from_id); + const char* t = EL_CSTR(to_id); + const char* r = EL_CSTR(relation); + if (!f || !t) return; + engram_grow_edges(); + EngramEdge* e = &g->edges[g->edge_count]; + memset(e, 0, sizeof(*e)); + e->id = engram_new_id(); + e->from_id = el_strdup(f); + e->to_id = el_strdup(t); + e->relation = el_strdup(r && *r ? r : "associate"); + e->metadata = el_strdup("{}"); + e->weight = engram_decode_score(weight); + if (e->weight <= 0.0 || e->weight > 1.0) e->weight = 0.5; + e->confidence = 1.0; + int64_t now = engram_now_ms(); + e->created_at = now; + e->updated_at = now; + e->last_fired = 0; + e->layer_id = ENGRAM_LAYER_DEFAULT; + g->edge_count++; +} + +el_val_t engram_edge_between(el_val_t from_id, el_val_t to_id) { + EngramStore* g = engram_get(); + const char* f = EL_CSTR(from_id); + const char* t = EL_CSTR(to_id); + if (!f || !t) return 0; + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + if (e->from_id && e->to_id && + strcmp(e->from_id, f) == 0 && strcmp(e->to_id, t) == 0) return 1; + } + return 0; +} + +/* Reserved helper: edge -> ElMap. Kept around for future builtins. */ +static el_val_t engram_edge_to_map(const EngramEdge* e) __attribute__((unused)); +static el_val_t engram_edge_to_map(const EngramEdge* e) { + el_val_t m = el_map_new(0); + m = el_map_set(m, EL_STR(el_strdup("id")), EL_STR(el_strdup(e->id ? e->id : ""))); + m = el_map_set(m, EL_STR(el_strdup("from_id")), EL_STR(el_strdup(e->from_id ? e->from_id : ""))); + m = el_map_set(m, EL_STR(el_strdup("to_id")), EL_STR(el_strdup(e->to_id ? e->to_id : ""))); + m = el_map_set(m, EL_STR(el_strdup("relation")), EL_STR(el_strdup(e->relation ? e->relation : ""))); + m = el_map_set(m, EL_STR(el_strdup("metadata")), EL_STR(el_strdup(e->metadata ? e->metadata : "{}"))); + m = el_map_set(m, EL_STR(el_strdup("weight")), el_from_float(e->weight)); + m = el_map_set(m, EL_STR(el_strdup("confidence")), el_from_float(e->confidence)); + m = el_map_set(m, EL_STR(el_strdup("created_at")), (el_val_t)e->created_at); + m = el_map_set(m, EL_STR(el_strdup("updated_at")), (el_val_t)e->updated_at); + m = el_map_set(m, EL_STR(el_strdup("last_fired")), (el_val_t)e->last_fired); + m = el_map_set(m, EL_STR(el_strdup("inhibitory")), (el_val_t)(e->inhibitory ? 1 : 0)); + m = el_map_set(m, EL_STR(el_strdup("layer_id")), (el_val_t)(int64_t)e->layer_id); + return m; +} + +el_val_t engram_neighbors(el_val_t node_id) { + EngramStore* g = engram_get(); + const char* sid = EL_CSTR(node_id); + el_val_t lst = el_list_empty(); + if (!sid) return lst; + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + const char* other = NULL; + if (e->from_id && strcmp(e->from_id, sid) == 0) other = e->to_id; + else if (e->to_id && strcmp(e->to_id, sid) == 0) other = e->from_id; + if (!other) continue; + EngramNode* n = engram_find_node(other); + if (n) lst = el_list_append(lst, engram_node_to_map(n)); + } + return lst; +} + +el_val_t engram_neighbors_filtered(el_val_t node_id, el_val_t max_depth, el_val_t direction) { + EngramStore* g = engram_get(); + const char* sid = EL_CSTR(node_id); + int64_t md = (int64_t)max_depth; if (md <= 0) md = 1; + const char* dir = EL_CSTR(direction); /* "out" | "in" | "both" (default) */ + el_val_t lst = el_list_empty(); + if (!sid || g->node_count == 0) return lst; + int64_t start = engram_find_node_index(sid); + if (start < 0) return lst; + /* BFS with depth tracking */ + int64_t* visited = calloc((size_t)g->node_count, sizeof(int64_t)); + int64_t* queue = calloc((size_t)g->node_count, sizeof(int64_t)); + int64_t* depths = calloc((size_t)g->node_count, sizeof(int64_t)); + if (!visited || !queue || !depths) { + free(visited); free(queue); free(depths); return lst; + } + int64_t qh = 0, qt = 0; + queue[qt++] = start; + visited[start] = 1; + depths[start] = 0; + while (qh < qt) { + int64_t cur = queue[qh++]; + const char* cur_id = g->nodes[cur].id; + int64_t cur_depth = depths[cur]; + if (cur_depth >= md) continue; + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + const char* other = NULL; + int outgoing = e->from_id && strcmp(e->from_id, cur_id) == 0; + int incoming = e->to_id && strcmp(e->to_id, cur_id) == 0; + if (dir && strcmp(dir, "out") == 0 && !outgoing) continue; + if (dir && strcmp(dir, "in") == 0 && !incoming) continue; + if (outgoing) other = e->to_id; + else if (incoming) other = e->from_id; + else continue; + int64_t oi = engram_find_node_index(other); + if (oi < 0 || visited[oi]) continue; + visited[oi] = 1; + depths[oi] = cur_depth + 1; + queue[qt++] = oi; + } + } + /* Emit all visited except the seed */ + for (int64_t i = 0; i < g->node_count; i++) { + if (visited[i] && i != start) { + lst = el_list_append(lst, engram_node_to_map(&g->nodes[i])); + } + } + free(visited); free(queue); free(depths); + return lst; +} + +el_val_t engram_edge_count(void) { + return (el_val_t)engram_get()->edge_count; +} + +/* Compute temporal decay factor for a node given current time. + * effective contribution = salience * exp(-lambda * age_hours / T_half) + * Clamped to [0.05, 1.0] so very old nodes retain a meaningful floor. */ +static double engram_temporal_decay(const EngramNode* n, int64_t now_ms) { + int64_t age_ms = now_ms - n->last_activated; + if (age_ms <= 0) return 1.0; + double lambda = (n->temporal_decay_rate > 0.0) ? n->temporal_decay_rate + : ENGRAM_DECAY_LAMBDA; + double age_hours = (double)age_ms / 3600000.0; + double factor = exp(-lambda * age_hours / ENGRAM_T_HALF_HOURS); + if (factor < 0.05) factor = 0.05; + return factor; +} + +/* Activation dampening: high activation_count nodes are "well-known" context + * and get less marginal boost per firing. + * count=0 → 1.0, count=2 → ~0.74, count=9 → ~0.59, count=99 → ~0.43 */ +static double engram_activation_dampen(const EngramNode* n) { + return 1.0 / (1.0 + log(1.0 + (double)n->activation_count)); +} + +/* Temporal proximity bonus: boost propagation along edges connecting + * co-temporal nodes. Returns a multiplier bonus in [0, 0.2]. */ +static double engram_temporal_proximity_bonus(int64_t node_created, + int64_t seed_epoch) { + int64_t diff = node_created - seed_epoch; + if (diff < 0) diff = -diff; + if (diff < 86400000LL) return 0.20; /* within 1 day */ + if (diff < 604800000LL) return 0.10; /* within 7 days */ + return 0.0; +} + +/* ── Two-layer activation (biologically-motivated) ─────────────────────────── + * + * Layer 1 — Broad fan-out (background activation): + * BFS + spreading activation fires on ALL nodes reachable from seeds, + * regardless of relevance to the current goal. Every reachable node gets + * a background_activation score. Nothing is filtered here. Models the + * brain's massive parallel sub-threshold activation of all associated + * content in response to a stimulus. Temporal decay and activation + * dampening are applied at this layer (as before), but no threshold gate. + * + * Layer 2 — Executive filter (working memory promotion): + * A second pass asks: given the query (goal intent), attentional bias, + * and inhibitory edge topology — which background-activated nodes should + * break through into working memory? + * + * wm_weight = bg_activation * goal_bias(node, query) * confidence + * * inhibitory_suppression_factor + * + * Only nodes where wm_weight >= ENGRAM_WM_THRESHOLD are promoted to + * working memory (working_memory_weight > 0). Background-activated nodes + * that don't cross the threshold accumulate suppression_count. After + * ENGRAM_SUPPRESSION_BREAKTHROUGH consecutive suppressed turns, the node + * force-breaks through at ENGRAM_BREAKTHROUGH_WEIGHT (latent tension + * surfacing — models intrusive memory / unresolved cognitive load). + * + * Inhibitory edges: + * An edge with inhibitory=1 suppresses the TARGET node's working memory + * promotion when the SOURCE is background-activated. Background activation + * of the target is NOT affected — the node fires in layer 1. Only the + * executive filter (layer 2) is gated. Models attentional inhibition: + * "focused on code work" suppresses personal memories from surfacing + * even if they have high background_activation. + * + * Goal bias: + * A lightweight heuristic rates how well each background-activated node + * aligns with the apparent intent of the current query. Technical queries + * boost Belief/Canonical/Lesson nodes; relational queries boost Memory/ + * Entity nodes. Direct lexical overlap gives a 50% bonus. + * + * Working memory persistence (turn continuity): + * Nodes promoted in the previous turn retain a decayed working_memory_weight + * (weight *= ENGRAM_WM_DECAY) without needing re-activation. This models + * conversational thread continuity — once a topic is in working memory, + * it persists slightly into the next turn. + * + * Returns ElList of {node, activation_strength, working_memory_weight, + * epistemic_confidence, hops, promoted}. + * "promoted" = 1 if working_memory_weight > 0, 0 if background-only. + * Context compilation uses ONLY nodes with promoted=1. + * + * Temporal decay (preserved from prior implementation): + * effective_salience = salience * exp(-lambda * age_hours / T_half) + * where T_half = 168 h (one week), lambda = ln(2) + * + * Activation dampening (preserved): + * dampen = 1 / (1 + log(1 + activation_count)) + * + * Temporal proximity bonus (preserved): + * edge_strength *= (1 + tbonus) where tbonus ∈ {0, 0.10, 0.20} + * + * Per-type threshold gates apply only to working memory promotion (layer 2): + * Safety/DharmaSelf: 0.05 Canonical: 0.15 Lesson: 0.25 + * Belief/Entity: 0.30 Note/Memory/Working: 0.40 + */ + +/* Compute goal-state bias multiplier for a node given the query. + * Returns a value in [0.3, 2.0]. This is a lightweight heuristic — + * a production implementation may use LLM-derived intent classification. */ +static double engram_goal_bias(const EngramNode* n, const char* query) { + if (!query || !*query) return 1.0; + double bias = 1.0; + /* Direct lexical overlap: node content/label/tags share text with query. */ + if (istr_contains(n->content, query) || istr_contains(n->label, query) || + istr_contains(n->tags, query)) { + bias += 0.5; + } + /* Node-type resonance with query intent. */ + int technical_query = istr_contains(query, "code") || + istr_contains(query, "function") || + istr_contains(query, "implement") || + istr_contains(query, "error") || + istr_contains(query, "bug") || + istr_contains(query, "build") || + istr_contains(query, "system") || + istr_contains(query, "design") || + istr_contains(query, "architecture"); + int personal_query = istr_contains(query, "feel") || + istr_contains(query, "emotion") || + istr_contains(query, "remember") || + istr_contains(query, "personal") || + istr_contains(query, "story") || + istr_contains(query, "relationship"); + if (n->node_type) { + int is_knowledge = (strcmp(n->node_type, "Belief") == 0) || + (strcmp(n->node_type, "DharmaSelf") == 0) || + (strcmp(n->node_type, "Safety") == 0); + int is_personal = (strcmp(n->node_type, "Memory") == 0) || + (strcmp(n->node_type, "Entity") == 0); + if (technical_query && is_knowledge) bias += 0.3; + if (technical_query && is_personal) bias -= 0.3; + if (personal_query && is_personal) bias += 0.3; + if (personal_query && is_knowledge) bias -= 0.1; + } + /* Tier-based bonus: promote higher-confidence knowledge nodes. */ + if (n->tier) { + if (strcmp(n->tier, "Canonical") == 0) bias += 0.2; + if (strcmp(n->tier, "Lesson") == 0) bias += 0.1; + } + if (bias < 0.3) bias = 0.3; + if (bias > 2.0) bias = 2.0; + return bias; +} + +el_val_t engram_activate(el_val_t query, el_val_t depth) { + EngramStore* g = engram_get(); + const char* q = EL_CSTR(query); + int64_t max_depth = (int64_t)depth; if (max_depth <= 0) max_depth = 2; + el_val_t out = el_list_empty(); + if (!q || g->node_count == 0) return out; + + int64_t now_ms = engram_now_ms(); + + /* Per-node layer-1 tracking. */ + double* best_bg = calloc((size_t)g->node_count, sizeof(double)); + int64_t* best_hops = calloc((size_t)g->node_count, sizeof(int64_t)); + int* reached = calloc((size_t)g->node_count, sizeof(int)); + if (!best_bg || !best_hops || !reached) { + free(best_bg); free(best_hops); free(reached); return out; + } + + /* ── LAYER 1: broad fan-out (background activation) ───────────────── + * Find seeds, apply temporal decay + dampening, BFS with edge weights. + * Inhibitory edges propagate activation normally at this layer — they + * only gate working memory promotion in layer 2. */ + typedef struct { int64_t idx; double act; int64_t created_at; } SeedEntry; + SeedEntry* seeds = malloc((size_t)g->node_count * sizeof(SeedEntry)); + int64_t seed_count = 0; + if (!seeds) { + free(best_bg); free(best_hops); free(reached); return out; + } + for (int64_t i = 0; i < g->node_count; i++) { + EngramNode* n = &g->nodes[i]; + if (istr_contains(n->content, q) || + istr_contains(n->label, q) || + istr_contains(n->tags, q)) { + double tdecay = engram_temporal_decay(n, now_ms); + double dampen = engram_activation_dampen(n); + double act = n->salience * tdecay * dampen; + seeds[seed_count].idx = i; + seeds[seed_count].act = act; + seeds[seed_count].created_at = n->created_at; + seed_count++; + best_bg[i] = act; + best_hops[i] = 0; + reached[i] = 1; + } + } + /* Compute mean seed created_at for temporal proximity bonus. */ + int64_t seed_epoch = 0; + if (seed_count > 0) { + seed_epoch = seeds[0].created_at; + for (int64_t s = 1; s < seed_count; s++) + seed_epoch = (seed_epoch + seeds[s].created_at) / 2; + } + typedef struct { int64_t idx; int64_t hops; double act; } Frontier; + Frontier* fr = malloc((size_t)(g->node_count * (max_depth + 1)) * sizeof(Frontier) + 16 * sizeof(Frontier)); + if (!fr) { + free(best_bg); free(best_hops); free(reached); free(seeds); return out; + } + int64_t fhead = 0, ftail = 0; + int64_t fcap = (int64_t)((size_t)(g->node_count * (max_depth + 1)) + 16); + for (int64_t s = 0; s < seed_count; s++) { + if (ftail >= fcap) break; + fr[ftail].idx = seeds[s].idx; + fr[ftail].hops = 0; + fr[ftail].act = seeds[s].act; + ftail++; + } + const double SPREAD_DECAY = 0.7; + while (fhead < ftail) { + Frontier f = fr[fhead++]; + if (f.hops >= max_depth) continue; + const char* cur_id = g->nodes[f.idx].id; + for (int64_t ei = 0; ei < g->edge_count; ei++) { + EngramEdge* e = &g->edges[ei]; + const char* other = NULL; + if (e->from_id && strcmp(e->from_id, cur_id) == 0) other = e->to_id; + else if (e->to_id && strcmp(e->to_id, cur_id) == 0) other = e->from_id; + else continue; + int64_t oi = engram_find_node_index(other); + if (oi < 0) continue; + EngramNode* on = &g->nodes[oi]; + double tbonus = engram_temporal_proximity_bonus(on->created_at, seed_epoch); + double tdecay = engram_temporal_decay(on, now_ms); + double dampen = engram_activation_dampen(on); + double new_act = f.act * e->weight * SPREAD_DECAY * (1.0 + tbonus) + * tdecay * dampen; + int64_t new_hops = f.hops + 1; + if (!reached[oi] || new_act > best_bg[oi]) { + best_bg[oi] = new_act; + best_hops[oi] = new_hops; + reached[oi] = 1; + if (ftail < fcap) { + fr[ftail].idx = oi; + fr[ftail].hops = new_hops; + fr[ftail].act = new_act; + ftail++; + } + } + } + } + /* Persist layer-1 background_activation to node store. */ + for (int64_t i = 0; i < g->node_count; i++) { + g->nodes[i].background_activation = reached[i] ? best_bg[i] : 0.0; + } + + /* ── TRAVERSAL INFERENCE: infer A→C edges when A→B→C was traversed ── + * For each pair of edges (A→B, B→C) where all three nodes were reached, + * create an inferred A→C edge with weight = w(A→B) * w(B→C) * 0.8 + * if no A→C edge already exists. Cap at 64 new edges per call. + * + * IMPORTANT: collect candidates FIRST into a flat array (no pointers into + * g->edges held across the apply pass), then apply after — this avoids + * dangling pointer bugs if engram_grow_edges() reallocs the array. */ + { + const int64_t INFER_CAP = 64; + typedef struct { char from[64]; char to[64]; double weight; } InferCandidate; + InferCandidate* cands = malloc((size_t)INFER_CAP * sizeof(InferCandidate)); + int64_t ncands = 0; + int64_t snap_ec = g->edge_count; + if (cands) { + for (int64_t e1 = 0; e1 < snap_ec && ncands < INFER_CAP; e1++) { + EngramEdge* ea = &g->edges[e1]; + if (!ea->from_id || !ea->to_id) continue; + int64_t ai = engram_find_node_index(ea->from_id); + int64_t bi = engram_find_node_index(ea->to_id); + if (ai < 0 || bi < 0) continue; + if (!reached[ai] || !reached[bi]) continue; + for (int64_t e2 = 0; e2 < snap_ec && ncands < INFER_CAP; e2++) { + if (e2 == e1) continue; + EngramEdge* eb = &g->edges[e2]; + if (!eb->from_id || !eb->to_id) continue; + if (strcmp(eb->from_id, ea->to_id) != 0) continue; + int64_t ci = engram_find_node_index(eb->to_id); + if (ci < 0 || !reached[ci]) continue; + if (ai == ci) continue; + int already = 0; + for (int64_t ex = 0; ex < snap_ec; ex++) { + EngramEdge* ee = &g->edges[ex]; + if (ee->from_id && ee->to_id && + strcmp(ee->from_id, ea->from_id) == 0 && + strcmp(ee->to_id, eb->to_id) == 0) { + already = 1; break; + } + } + if (already) continue; + int dup = 0; + for (int64_t k = 0; k < ncands; k++) { + if (strcmp(cands[k].from, ea->from_id) == 0 && + strcmp(cands[k].to, eb->to_id) == 0) { dup = 1; break; } + } + if (dup) continue; + double inf_w = ea->weight * eb->weight * 0.8; + if (inf_w < 0.05) inf_w = 0.05; + if (inf_w > 1.0) inf_w = 1.0; + strncpy(cands[ncands].from, ea->from_id, 63); cands[ncands].from[63] = '\0'; + strncpy(cands[ncands].to, eb->to_id, 63); cands[ncands].to[63] = '\0'; + cands[ncands].weight = inf_w; + ncands++; + } + } + for (int64_t k = 0; k < ncands; k++) { + engram_grow_edges(); + EngramEdge* ne = &g->edges[g->edge_count]; + memset(ne, 0, sizeof(*ne)); + ne->id = engram_new_id(); + /* Use strdup (not el_strdup) so these persist beyond the request. */ + ne->from_id = strdup(cands[k].from); + ne->to_id = strdup(cands[k].to); + ne->relation = strdup("inferred"); + ne->metadata = strdup("{}"); + ne->weight = cands[k].weight; + ne->confidence = 0.8; + ne->created_at = now_ms; + ne->updated_at = now_ms; + ne->last_fired = now_ms; + ne->layer_id = ENGRAM_LAYER_DEFAULT; + g->edge_count++; + } + free(cands); + } + } + + /* ── PASS 2: executive filter → working memory promotion ──────────── */ + /* Step A: collect inhibitory suppressions from fired inhibitory edges. + * Layered consciousness: inhibition is ONLY recorded against targets + * whose layer is `suppressible == 1`. Nodes in non-suppressible layers + * (Layer 0 / safety) ignore inhibitory edges entirely — their working + * memory weight cannot be silenced by attentional suppression. */ + double* inhibition = calloc((size_t)g->node_count, sizeof(double)); + if (!inhibition) { + free(best_bg); free(best_hops); free(reached); free(seeds); free(fr); + return out; + } + for (int64_t ei = 0; ei < g->edge_count; ei++) { + EngramEdge* e = &g->edges[ei]; + if (!e->inhibitory) continue; + int64_t src = engram_find_node_index(e->from_id); + int64_t tgt = engram_find_node_index(e->to_id); + if (src < 0 || tgt < 0) continue; + if (!reached[src] || best_bg[src] <= 0.0) continue; + /* Skip if target layer is non-suppressible: Layer 0 / safety nodes + * are immune to inhibitory edges from any source. The pass-3 + * override below also force-promotes them, but recording inhibition + * against them at all would be wasted work and could confuse + * downstream debugging output. */ + if (!engram_layer_is_suppressible(g->nodes[tgt].layer_id)) continue; + /* Inhibition strength proportional to source background activation + * and edge weight. Takes the maximum if multiple inhibitory edges + * target the same node. */ + double inh = best_bg[src] * e->weight; + if (inh > inhibition[tgt]) inhibition[tgt] = inh; + } + /* Step B: compute working_memory_weight per candidate node. */ + double* wm_weights = calloc((size_t)g->node_count, sizeof(double)); + if (!wm_weights) { + free(best_bg); free(best_hops); free(reached); free(seeds); + free(fr); free(inhibition); return out; + } + for (int64_t i = 0; i < g->node_count; i++) { + if (!reached[i] || best_bg[i] <= 0.0) continue; + EngramNode* n = &g->nodes[i]; + /* Per-type threshold: safety nodes break through more easily. */ + double type_threshold = engram_type_threshold(n->node_type, n->tier); + /* Goal bias weights the node's relevance to current intent. */ + double bias = engram_goal_bias(n, q); + /* Raw working memory score. */ + double raw_wm = best_bg[i] * bias * n->confidence; + /* Apply inhibitory suppression. Full inhibition → scale by factor. */ + double inh = inhibition[i]; + if (inh > 1.0) inh = 1.0; + double suppress = 1.0 - (1.0 - ENGRAM_INHIBITION_FACTOR) * inh; + raw_wm *= suppress; + /* Threshold gate: must exceed per-type threshold to enter working + * memory. Type threshold replaces the old flat 0.2 filter. */ + if (raw_wm >= type_threshold) { + wm_weights[i] = raw_wm > 1.0 ? 1.0 : raw_wm; + if (n->suppression_count > 0) n->suppression_count = 0; + } else { + /* Node didn't make it through — increment suppression counter. + * After N consecutive suppressions: force breakthrough. */ + n->suppression_count++; + if (n->suppression_count >= ENGRAM_SUPPRESSION_BREAKTHROUGH) { + wm_weights[i] = ENGRAM_BREAKTHROUGH_WEIGHT; + n->suppression_count = 0; + } else { + wm_weights[i] = 0.0; + } + } + } + /* ── PASS 3: Layer 0 override (the sacred fire) ───────────────────── + * Every node in a non-suppressible layer that received any background + * activation is force-promoted to AT LEAST ENGRAM_LAYER0_OVERRIDE_WEIGHT. + * This runs LAST and overrides whatever Pass 2 decided — Layer 0 cannot + * be silenced by inhibitory edges, by goal-bias misalignment, by + * confidence weighting, or by per-type threshold gates. If the seed + * fan-out reached a structural-floor node, that node surfaces. + * + * Note: this also clears the suppression_count when an override fires, + * since the node DID surface this turn — it just took the override path + * rather than the standard threshold path. Without this, a Layer 0 + * node with persistent inhibitory pressure would accumulate + * suppression_count forever and never reach the breakthrough state. */ + for (int64_t i = 0; i < g->node_count; i++) { + if (!reached[i] || best_bg[i] <= 0.0) continue; + EngramNode* n = &g->nodes[i]; + if (engram_layer_is_suppressible(n->layer_id)) continue; + if (wm_weights[i] < ENGRAM_LAYER0_OVERRIDE_WEIGHT) { + wm_weights[i] = ENGRAM_LAYER0_OVERRIDE_WEIGHT; + } + n->suppression_count = 0; + } + + /* Persist working_memory_weight (post Pass 3) to node store. */ + for (int64_t i = 0; i < g->node_count; i++) { + g->nodes[i].working_memory_weight = wm_weights[i]; + } + + /* ── HEBBIAN STRENGTHENING: fire together, wire together ───────────── + * For each pair of co-promoted nodes (working_memory_weight > 0) that + * share an edge, boost that edge's weight by 0.05 (capped at 1.0). + * Also increment activation_count and update last_activated on promoted + * nodes — this is what drives tier migration below. */ + for (int64_t i = 0; i < g->node_count; i++) { + if (wm_weights[i] <= 0.0) continue; + EngramNode* n = &g->nodes[i]; + n->activation_count++; + n->last_activated = now_ms; + n->updated_at = now_ms; + } + for (int64_t ei = 0; ei < g->edge_count; ei++) { + EngramEdge* e = &g->edges[ei]; + if (!e->from_id || !e->to_id) continue; + int64_t src = engram_find_node_index(e->from_id); + int64_t tgt = engram_find_node_index(e->to_id); + if (src < 0 || tgt < 0) continue; + if (wm_weights[src] > 0.0 && wm_weights[tgt] > 0.0) { + e->weight += 0.05; + if (e->weight > 1.0) e->weight = 1.0; + e->last_fired = now_ms; + e->updated_at = now_ms; + } + } + + /* ── TIER MIGRATION: promote nodes based on activation_count thresholds ─ + * 0–4 → Working + * 5–19 → Episodic + * 20–49 → Semantic + * 50+ → Procedural + * Only upgrade (never downgrade) to preserve earned tier. */ + for (int64_t i = 0; i < g->node_count; i++) { + EngramNode* n = &g->nodes[i]; + const char* target_tier = NULL; + int64_t ac = n->activation_count; + if (ac >= 50) target_tier = "Procedural"; + else if (ac >= 20) target_tier = "Semantic"; + else if (ac >= 5) target_tier = "Episodic"; + else target_tier = "Working"; + if (target_tier && n->tier && strcmp(n->tier, target_tier) != 0) { + /* Only upgrade (Working < Episodic < Semantic < Procedural). */ + int cur_rank = 0, new_rank = 0; + if (strcmp(n->tier, "Working") == 0) cur_rank = 0; + else if (strcmp(n->tier, "Episodic") == 0) cur_rank = 1; + else if (strcmp(n->tier, "Semantic") == 0) cur_rank = 2; + else if (strcmp(n->tier, "Procedural") == 0) cur_rank = 3; + if (strcmp(target_tier, "Working") == 0) new_rank = 0; + else if (strcmp(target_tier, "Episodic") == 0) new_rank = 1; + else if (strcmp(target_tier, "Semantic") == 0) new_rank = 2; + else if (strcmp(target_tier, "Procedural") == 0) new_rank = 3; + if (new_rank > cur_rank) { + free(n->tier); + /* Use strdup (not el_strdup) so tier string persists beyond the request. */ + n->tier = strdup(target_tier); + n->updated_at = now_ms; + } + } + } + + /* ── Collect all background-activated nodes for the return value ──── + * Callers see both layers. Context compilation uses only promoted nodes + * (working_memory_weight > 0). Sort: promoted first by wm_weight desc, + * then background-only by background_activation desc. */ + typedef struct { int64_t idx; double bg; double wm; double epist; int64_t hops; } Result; + Result* results = malloc((size_t)g->node_count * sizeof(Result)); + int64_t rcount = 0; + if (!results) { + free(best_bg); free(best_hops); free(reached); free(seeds); + free(fr); free(inhibition); free(wm_weights); return out; + } + for (int64_t i = 0; i < g->node_count; i++) { + if (!reached[i]) continue; + double epist = best_bg[i] * g->nodes[i].confidence; + /* Include if promoted to working memory OR if background activation + * is meaningful enough to report (epist >= 0.1). */ + if (epist < 0.1 && wm_weights[i] <= 0.0) continue; + results[rcount].idx = i; + results[rcount].bg = best_bg[i]; + results[rcount].wm = wm_weights[i]; + results[rcount].epist = epist; + results[rcount].hops = best_hops[i]; + rcount++; + } + /* Sort: promoted nodes first (by wm_weight desc), then background-only + * by background_activation desc. */ + for (int64_t i = 1; i < rcount; i++) { + Result key = results[i]; + int64_t j = i - 1; + while (j >= 0 && (results[j].wm < key.wm || + (results[j].wm == key.wm && results[j].bg < key.bg))) { + results[j + 1] = results[j]; + j--; + } + results[j + 1] = key; + } + for (int64_t i = 0; i < rcount; i++) { + el_val_t entry = el_map_new(0); + entry = el_map_set(entry, EL_STR(el_strdup("node")), + engram_node_to_map(&g->nodes[results[i].idx])); + entry = el_map_set(entry, EL_STR(el_strdup("activation_strength")), + el_from_float(results[i].bg)); + entry = el_map_set(entry, EL_STR(el_strdup("working_memory_weight")), + el_from_float(results[i].wm)); + entry = el_map_set(entry, EL_STR(el_strdup("epistemic_confidence")), + el_from_float(results[i].epist)); + entry = el_map_set(entry, EL_STR(el_strdup("hops")), + (el_val_t)results[i].hops); + entry = el_map_set(entry, EL_STR(el_strdup("promoted")), + (el_val_t)(results[i].wm > 0.0 ? 1 : 0)); + out = el_list_append(out, entry); + } + free(best_bg); free(best_hops); free(reached); + free(seeds); free(fr); free(inhibition); free(wm_weights); free(results); + return out; +} + +/* ── Engram persistence (JSON snapshot) ─────────────────────────────────── */ + +static void engram_emit_node_json(JsonBuf* b, const EngramNode* n) { + jb_putc(b, '{'); + jb_puts(b, "\"id\":"); jb_emit_escaped(b, n->id ? n->id : ""); + jb_puts(b, ",\"content\":"); jb_emit_escaped(b, n->content ? n->content : ""); + jb_puts(b, ",\"node_type\":"); jb_emit_escaped(b, n->node_type ? n->node_type : ""); + jb_puts(b, ",\"label\":"); jb_emit_escaped(b, n->label ? n->label : ""); + jb_puts(b, ",\"tier\":"); jb_emit_escaped(b, n->tier ? n->tier : "Working"); + jb_puts(b, ",\"tags\":"); jb_emit_escaped(b, n->tags ? n->tags : ""); + jb_puts(b, ",\"metadata\":"); jb_emit_escaped(b, n->metadata ? n->metadata : "{}"); + char tmp[80]; + snprintf(tmp, sizeof(tmp), ",\"salience\":%g", n->salience); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"importance\":%g", n->importance); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"confidence\":%g", n->confidence); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"temporal_decay_rate\":%g", n->temporal_decay_rate); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"activation_count\":%lld", (long long)n->activation_count); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"last_activated\":%lld", (long long)n->last_activated); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"created_at\":%lld", (long long)n->created_at); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"updated_at\":%lld", (long long)n->updated_at); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"background_activation\":%g", n->background_activation); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"working_memory_weight\":%g", n->working_memory_weight); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"suppression_count\":%d", n->suppression_count); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"layer_id\":%u", n->layer_id); jb_puts(b, tmp); + jb_putc(b, '}'); +} + +static void engram_emit_edge_json(JsonBuf* b, const EngramEdge* e) { + jb_putc(b, '{'); + jb_puts(b, "\"id\":"); jb_emit_escaped(b, e->id ? e->id : ""); + jb_puts(b, ",\"from_id\":"); jb_emit_escaped(b, e->from_id ? e->from_id : ""); + jb_puts(b, ",\"to_id\":"); jb_emit_escaped(b, e->to_id ? e->to_id : ""); + jb_puts(b, ",\"relation\":"); jb_emit_escaped(b, e->relation ? e->relation : ""); + jb_puts(b, ",\"metadata\":"); jb_emit_escaped(b, e->metadata ? e->metadata : "{}"); + char tmp[64]; + snprintf(tmp, sizeof(tmp), ",\"weight\":%g", e->weight); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"confidence\":%g", e->confidence); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"created_at\":%lld", (long long)e->created_at); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"updated_at\":%lld", (long long)e->updated_at); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"last_fired\":%lld", (long long)e->last_fired); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"inhibitory\":%d", e->inhibitory ? 1 : 0); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"layer_id\":%u", e->layer_id); jb_puts(b, tmp); + jb_putc(b, '}'); +} + +el_val_t engram_save(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p || !*p) return 0; + EngramStore* g = engram_get(); + JsonBuf b; jb_init(&b); + jb_puts(&b, "{\"nodes\":["); + for (int64_t i = 0; i < g->node_count; i++) { + if (i > 0) jb_putc(&b, ','); + engram_emit_node_json(&b, &g->nodes[i]); + } + jb_puts(&b, "],\"edges\":["); + for (int64_t i = 0; i < g->edge_count; i++) { + if (i > 0) jb_putc(&b, ','); + engram_emit_edge_json(&b, &g->edges[i]); + } + /* Layered consciousness — emit the layer registry under "layers". + * Older readers that don't know about this top-level key will simply + * ignore it (forward compatible). Tombstoned (removed-injectable) + * layers are skipped — they have no name and can't be re-created + * meaningfully on load anyway. */ + jb_puts(&b, "],\"layers\":["); + int first_layer = 1; + for (size_t i = 0; i < g->layer_count; i++) { + EngramLayer* L = &g->layers[i]; + if (!L->name) continue; + if (!first_layer) jb_putc(&b, ','); + first_layer = 0; + jb_putc(&b, '{'); + char tmp[80]; + snprintf(tmp, sizeof(tmp), "\"layer_id\":%u", L->layer_id); + jb_puts(&b, tmp); + jb_puts(&b, ",\"name\":"); + jb_emit_escaped(&b, L->name); + snprintf(tmp, sizeof(tmp), ",\"activation_priority\":%u", L->activation_priority); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"suppressible\":%d", L->suppressible ? 1 : 0); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"transparent\":%d", L->transparent ? 1 : 0); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"injectable\":%d", L->injectable ? 1 : 0); + jb_puts(&b, tmp); + jb_putc(&b, '}'); + } + jb_puts(&b, "]}"); + FILE* f = fopen(p, "wb"); + if (!f) { free(b.buf); return 0; } + size_t w = fwrite(b.buf, 1, b.len, f); + fclose(f); + int ok = (w == b.len); + free(b.buf); + return ok ? 1 : 0; +} + +/* Helper: extract a string field from a JSON object substring. */ +static char* eg_get_str_field(const char* obj, const char* key) { + const char* p = json_find_key(obj, key); + if (!p) return el_strdup(""); + if (*p != '"') return el_strdup(""); + JsonParser jp = { .p = p, .end = p + strlen(p), .err = 0 }; + char* out = jp_parse_string_raw(&jp); + if (jp.err) { free(out); return el_strdup(""); } + return out; +} + +static double eg_get_num_field(const char* obj, const char* key) { + const char* p = json_find_key(obj, key); + if (!p || *p == '"' || *p == '{' || *p == '[') return 0.0; + return strtod(p, NULL); +} + +static int64_t eg_get_int_field(const char* obj, const char* key) { + const char* p = json_find_key(obj, key); + if (!p || *p == '"' || *p == '{' || *p == '[') return 0; + return strtoll(p, NULL, 10); +} + +/* Iterate the top-level nodes/edges arrays in a saved snapshot. */ +static const char* eg_skip_ws(const char* p) { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + return p; +} + +el_val_t engram_load(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p || !*p) return 0; + FILE* f = fopen(p, "rb"); + if (!f) return 0; + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + if (sz <= 0) { fclose(f); return 0; } + char* data = malloc((size_t)sz + 1); + if (!data) { fclose(f); return 0; } + size_t got = fread(data, 1, (size_t)sz, f); + fclose(f); + data[got] = '\0'; + + /* Reset store */ + EngramStore* g = engram_get(); + for (int64_t i = 0; i < g->node_count; i++) { + free(g->nodes[i].id); free(g->nodes[i].content); free(g->nodes[i].node_type); + free(g->nodes[i].label); free(g->nodes[i].tier); free(g->nodes[i].tags); + free(g->nodes[i].metadata); + } + g->node_count = 0; + for (int64_t i = 0; i < g->edge_count; i++) { + free(g->edges[i].id); free(g->edges[i].from_id); free(g->edges[i].to_id); + free(g->edges[i].relation); free(g->edges[i].metadata); + } + g->edge_count = 0; + + /* Walk nodes array */ + const char* nodes_p = json_find_key(data, "nodes"); + if (nodes_p) { + nodes_p = eg_skip_ws(nodes_p); + if (*nodes_p == '[') { + nodes_p++; + nodes_p = eg_skip_ws(nodes_p); + while (*nodes_p && *nodes_p != ']') { + if (*nodes_p != '{') { nodes_p++; continue; } + const char* end = json_skip_value(nodes_p); + size_t n = (size_t)(end - nodes_p); + char* obj = malloc(n + 1); + memcpy(obj, nodes_p, n); obj[n] = '\0'; + engram_grow_nodes(); + EngramNode* nn = &g->nodes[g->node_count]; + memset(nn, 0, sizeof(*nn)); + nn->id = eg_get_str_field(obj, "id"); + nn->content = eg_get_str_field(obj, "content"); + nn->node_type = eg_get_str_field(obj, "node_type"); + nn->label = eg_get_str_field(obj, "label"); + nn->tier = eg_get_str_field(obj, "tier"); + nn->tags = eg_get_str_field(obj, "tags"); + nn->metadata = eg_get_str_field(obj, "metadata"); + if (!nn->metadata || !*nn->metadata) { free(nn->metadata); nn->metadata = el_strdup("{}"); } + nn->salience = eg_get_num_field(obj, "salience"); + nn->importance = eg_get_num_field(obj, "importance"); + nn->confidence = eg_get_num_field(obj, "confidence"); + nn->temporal_decay_rate = eg_get_num_field(obj, "temporal_decay_rate"); + /* temporal_decay_rate defaults to 0 (use global) if absent in snapshot */ + nn->activation_count = eg_get_int_field(obj, "activation_count"); + nn->last_activated = eg_get_int_field(obj, "last_activated"); + nn->created_at = eg_get_int_field(obj, "created_at"); + nn->updated_at = eg_get_int_field(obj, "updated_at"); + nn->background_activation = eg_get_num_field(obj, "background_activation"); + nn->working_memory_weight = eg_get_num_field(obj, "working_memory_weight"); + nn->suppression_count = (int32_t)eg_get_int_field(obj, "suppression_count"); + /* layer_id defaults to ENGRAM_LAYER_DEFAULT (core-identity) + * for snapshots that predate the layered schema. We can't + * tell "explicit 0" from "missing field" using the helper + * directly, so probe for the key — if absent, fall back. */ + if (json_find_key(obj, "layer_id")) { + nn->layer_id = (uint32_t)eg_get_int_field(obj, "layer_id"); + } else { + nn->layer_id = ENGRAM_LAYER_DEFAULT; + } + g->node_count++; + free(obj); + nodes_p = end; + nodes_p = eg_skip_ws(nodes_p); + if (*nodes_p == ',') { nodes_p++; nodes_p = eg_skip_ws(nodes_p); } + } + } + } + /* Walk edges array */ + const char* edges_p = json_find_key(data, "edges"); + if (edges_p) { + edges_p = eg_skip_ws(edges_p); + if (*edges_p == '[') { + edges_p++; + edges_p = eg_skip_ws(edges_p); + while (*edges_p && *edges_p != ']') { + if (*edges_p != '{') { edges_p++; continue; } + const char* end = json_skip_value(edges_p); + size_t n = (size_t)(end - edges_p); + char* obj = malloc(n + 1); + memcpy(obj, edges_p, n); obj[n] = '\0'; + engram_grow_edges(); + EngramEdge* ee = &g->edges[g->edge_count]; + memset(ee, 0, sizeof(*ee)); + ee->id = eg_get_str_field(obj, "id"); + ee->from_id = eg_get_str_field(obj, "from_id"); + ee->to_id = eg_get_str_field(obj, "to_id"); + ee->relation = eg_get_str_field(obj, "relation"); + ee->metadata = eg_get_str_field(obj, "metadata"); + if (!ee->metadata || !*ee->metadata) { free(ee->metadata); ee->metadata = el_strdup("{}"); } + ee->weight = eg_get_num_field(obj, "weight"); + ee->confidence = eg_get_num_field(obj, "confidence"); + ee->created_at = eg_get_int_field(obj, "created_at"); + ee->updated_at = eg_get_int_field(obj, "updated_at"); + ee->last_fired = eg_get_int_field(obj, "last_fired"); + ee->inhibitory = (int)eg_get_int_field(obj, "inhibitory"); + if (json_find_key(obj, "layer_id")) { + ee->layer_id = (uint32_t)eg_get_int_field(obj, "layer_id"); + } else { + ee->layer_id = ENGRAM_LAYER_DEFAULT; + } + g->edge_count++; + free(obj); + edges_p = end; + edges_p = eg_skip_ws(edges_p); + if (*edges_p == ',') { edges_p++; edges_p = eg_skip_ws(edges_p); } + } + } + } + /* Walk layers array (optional — older snapshots omit this). + * If present we replace the canonical registry entirely; if absent we + * keep whatever the engram_get() init established. */ + const char* layers_p = json_find_key(data, "layers"); + if (layers_p) { + layers_p = eg_skip_ws(layers_p); + if (*layers_p == '[') { + /* Reset existing layer registry. Free strdup'd names; the + * struct array itself can be reused. */ + for (size_t i = 0; i < g->layer_count; i++) { + if (g->layers[i].name) free(g->layers[i].name); + g->layers[i].name = NULL; + } + g->layer_count = 0; + + layers_p++; + layers_p = eg_skip_ws(layers_p); + while (*layers_p && *layers_p != ']') { + if (*layers_p != '{') { layers_p++; continue; } + const char* end = json_skip_value(layers_p); + size_t n = (size_t)(end - layers_p); + char* obj = malloc(n + 1); + memcpy(obj, layers_p, n); obj[n] = '\0'; + if (g->layer_count >= g->layer_capacity) { + size_t nc = g->layer_capacity ? g->layer_capacity * 2 : 16; + EngramLayer* grown = realloc(g->layers, nc * sizeof(EngramLayer)); + if (!grown) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + memset(grown + g->layer_capacity, 0, + (nc - g->layer_capacity) * sizeof(EngramLayer)); + g->layers = grown; + g->layer_capacity = nc; + } + EngramLayer* L = &g->layers[g->layer_count]; + memset(L, 0, sizeof(*L)); + L->layer_id = (uint32_t)eg_get_int_field(obj, "layer_id"); + L->activation_priority = (uint32_t)eg_get_int_field(obj, "activation_priority"); + L->suppressible = (int)eg_get_int_field(obj, "suppressible") ? 1 : 0; + L->transparent = (int)eg_get_int_field(obj, "transparent") ? 1 : 0; + L->injectable = (int)eg_get_int_field(obj, "injectable") ? 1 : 0; + char* nm = eg_get_str_field(obj, "name"); + if (nm && *nm) { + L->name = el_strdup_persist(nm); + free(nm); + } else { + free(nm); + L->name = el_strdup_persist(""); + } + g->layer_count++; + free(obj); + layers_p = end; + layers_p = eg_skip_ws(layers_p); + if (*layers_p == ',') { layers_p++; layers_p = eg_skip_ws(layers_p); } + } + } + } + free(data); + return 1; +} + +/* ── Engram JSON-string accessors ───────────────────────────────────────── + * These return pre-serialized JSON strings so callers (especially HTTP + * handlers) don't have to round-trip ElList/ElMap through json_stringify + * — which can't reliably distinguish those structures from raw pointers + * due to el_val_t's type erasure. The runtime knows the real C types and + * can serialize directly. */ + +el_val_t engram_get_node_json(el_val_t id) { + const char* sid = EL_CSTR(id); + EngramNode* n = engram_find_node(sid); + if (!n) return el_wrap_str(el_strdup("{}")); + JsonBuf b; jb_init(&b); + engram_emit_node_json(&b, n); + return el_wrap_str(b.buf); +} + +el_val_t engram_search_json(el_val_t query, el_val_t limit) { + EngramStore* g = engram_get(); + const char* q = EL_CSTR(query); + int64_t lim = (int64_t)limit; + if (lim <= 0) lim = 100; + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + int first = 1; + int64_t found = 0; + if (q && *q) { + for (int64_t i = 0; i < g->node_count && found < lim; i++) { + EngramNode* n = &g->nodes[i]; + /* Filter transparent layers — same as engram_search. */ + if (engram_layer_is_transparent(n->layer_id)) continue; + if (istr_contains(n->content, q) || + istr_contains(n->label, q) || + istr_contains(n->tags, q)) { + if (!first) jb_putc(&b, ','); + engram_emit_node_json(&b, n); + first = 0; + found++; + } + } + } + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +el_val_t engram_scan_nodes_json(el_val_t limit, el_val_t offset) { + EngramStore* g = engram_get(); + int64_t lim = (int64_t)limit; if (lim <= 0) lim = 100; + int64_t off = (int64_t)offset; if (off < 0) off = 0; + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + if (g->node_count == 0) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + int64_t* idx = malloc((size_t)g->node_count * sizeof(int64_t)); + if (!idx) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + /* Skip transparent layers — introspection filter, same as engram_scan_nodes. */ + int64_t live = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (engram_layer_is_transparent(g->nodes[i].layer_id)) continue; + idx[live++] = i; + } + engram_sort_indices_by_salience(idx, live, g->nodes); + int64_t end = off + lim; + if (end > live) end = live; + int first = 1; + for (int64_t i = off; i < end; i++) { + if (!first) jb_putc(&b, ','); + engram_emit_node_json(&b, &g->nodes[idx[i]]); + first = 0; + } + free(idx); + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +/* engram_scan_nodes_by_type_json — filter by node_type before paginating. + * Empty / NULL type_v falls back to the unfiltered scan (existing behaviour). + * Result is JSON array, salience-sorted, transparent layers skipped. */ +el_val_t engram_scan_nodes_by_type_json(el_val_t type_v, el_val_t limit, el_val_t offset) { + const char* type_filter = EL_CSTR(type_v); + if (!type_filter || !*type_filter) { + return engram_scan_nodes_json(limit, offset); + } + EngramStore* g = engram_get(); + int64_t lim = (int64_t)limit; if (lim <= 0) lim = 100; + int64_t off = (int64_t)offset; if (off < 0) off = 0; + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + if (g->node_count == 0) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + int64_t* idx = malloc((size_t)g->node_count * sizeof(int64_t)); + if (!idx) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + int64_t live = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (engram_layer_is_transparent(g->nodes[i].layer_id)) continue; + const char* nt = g->nodes[i].node_type; + if (!nt || strcmp(nt, type_filter) != 0) continue; + idx[live++] = i; + } + engram_sort_indices_by_salience(idx, live, g->nodes); + int64_t end = off + lim; + if (end > live) end = live; + int first = 1; + for (int64_t i = off; i < end; i++) { + if (!first) jb_putc(&b, ','); + engram_emit_node_json(&b, &g->nodes[idx[i]]); + first = 0; + } + free(idx); + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +el_val_t engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction) { + /* Re-implement here directly so we serialize without going through + * the ElList path. Walks BFS to max_depth, emits {node, edge, hops} + * triples. */ + EngramStore* g = engram_get(); + const char* sid = EL_CSTR(node_id); + int64_t depth = (int64_t)max_depth; if (depth <= 0) depth = 1; + const char* dir = EL_CSTR(direction); if (!dir) dir = "both"; + int allow_out = (strcmp(dir, "out") == 0) || (strcmp(dir, "both") == 0); + int allow_in = (strcmp(dir, "in") == 0) || (strcmp(dir, "both") == 0); + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + if (!sid || !*sid) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + + /* Frontier of (node_id, hops). Cap to a sane size. */ + char** frontier = calloc(1024, sizeof(char*)); + int64_t* frontier_h = calloc(1024, sizeof(int64_t)); + int64_t fc = 0; + char** visited = calloc(1024, sizeof(char*)); + int64_t vc = 0; + if (!frontier || !frontier_h || !visited) { + free(frontier); free(frontier_h); free(visited); + jb_putc(&b, ']'); return el_wrap_str(b.buf); + } + /* Use plain strdup (not el_strdup) so arena doesn't track these pointers. + * The BFS loop manually frees them below — arena would double-free them. */ + frontier[fc] = strdup(sid); frontier_h[fc] = 0; fc++; + visited[vc++] = strdup(sid); + + int first = 1; + while (fc > 0) { + char* cur = frontier[0]; int64_t h = frontier_h[0]; + for (int64_t k = 1; k < fc; k++) { frontier[k-1] = frontier[k]; frontier_h[k-1] = frontier_h[k]; } + fc--; + if (h >= depth) { free(cur); continue; } + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + const char* peer = NULL; + if (allow_out && e->from_id && strcmp(e->from_id, cur) == 0) peer = e->to_id; + else if (allow_in && e->to_id && strcmp(e->to_id, cur) == 0) peer = e->from_id; + if (!peer) continue; + int seen = 0; + for (int64_t v = 0; v < vc; v++) { + if (strcmp(visited[v], peer) == 0) { seen = 1; break; } + } + if (seen) continue; + EngramNode* n = engram_find_node(peer); + if (!n) continue; + if (!first) jb_putc(&b, ','); + jb_puts(&b, "{\"node\":"); + engram_emit_node_json(&b, n); + jb_puts(&b, ",\"edge\":"); + engram_emit_edge_json(&b, e); + char tmp[64]; snprintf(tmp, sizeof(tmp), ",\"hops\":%lld}", (long long)(h + 1)); + jb_puts(&b, tmp); + first = 0; + if (vc < 1024) visited[vc++] = strdup(peer); + if (fc < 1024 && h + 1 < depth) { frontier[fc] = strdup(peer); frontier_h[fc] = h + 1; fc++; } + } + free(cur); + } + for (int64_t i = 0; i < fc; i++) free(frontier[i]); + for (int64_t i = 0; i < vc; i++) free(visited[i]); + free(frontier); free(frontier_h); free(visited); + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +el_val_t engram_activate_json(el_val_t query, el_val_t depth) { + /* Run two-layer engram_activate and serialize the result list to JSON. + * Each entry includes both activation_strength (layer 1 background) and + * working_memory_weight (layer 2 executive filter), plus promoted flag. + * Callers performing context compilation should filter to promoted=1. */ + el_val_t lst = engram_activate(query, depth); + ElList* arr = (ElList*)(uintptr_t)lst; + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + if (arr) { + for (int64_t i = 0; i < arr->length; i++) { + if (!arr->elems[i]) continue; + el_val_t node_map = el_map_get(arr->elems[i], EL_STR("node")); + el_val_t strength_v = el_map_get(arr->elems[i], EL_STR("activation_strength")); + el_val_t wm_v = el_map_get(arr->elems[i], EL_STR("working_memory_weight")); + el_val_t epist_v = el_map_get(arr->elems[i], EL_STR("epistemic_confidence")); + el_val_t hops_v = el_map_get(arr->elems[i], EL_STR("hops")); + el_val_t promoted_v = el_map_get(arr->elems[i], EL_STR("promoted")); + /* Look up underlying EngramNode by id to emit canonical JSON. */ + el_val_t id_v = el_map_get(node_map, EL_STR("id")); + const char* id_s = EL_CSTR(id_v); + EngramNode* n = id_s ? engram_find_node(id_s) : NULL; + if (i > 0) jb_putc(&b, ','); + jb_puts(&b, "{\"node\":"); + if (n) { + engram_emit_node_json(&b, n); + } else { + jb_puts(&b, "{}"); + } + char tmp[80]; + snprintf(tmp, sizeof(tmp), ",\"activation_strength\":%g", el_to_float(strength_v)); jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"working_memory_weight\":%g", el_to_float(wm_v)); jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"epistemic_confidence\":%g", el_to_float(epist_v)); jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"hops\":%lld", (long long)(int64_t)hops_v); jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"promoted\":%d}", (int)(int64_t)promoted_v); jb_puts(&b, tmp); + } + } + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +el_val_t engram_stats_json(void) { + EngramStore* g = engram_get(); + char buf[128]; + snprintf(buf, sizeof(buf), + "{\"node_count\":%lld,\"edge_count\":%lld,\"layer_count\":%zu}", + (long long)g->node_count, (long long)g->edge_count, g->layer_count); + return el_wrap_str(el_strdup(buf)); +} + +/* engram_list_layers_json — serialized counterpart of engram_list_layers. + * Returns a JSON array, sorted by activation_priority ascending. */ +el_val_t engram_list_layers_json(void) { + EngramStore* g = engram_get(); + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + /* Build a sorted index over live layers. */ + size_t* idx = malloc((g->layer_count + 1) * sizeof(size_t)); + if (!idx) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + size_t live = 0; + for (size_t i = 0; i < g->layer_count; i++) { + if (g->layers[i].name) idx[live++] = i; + } + for (size_t i = 1; i < live; i++) { + size_t key = idx[i]; + uint32_t kp = g->layers[key].activation_priority; + size_t j = i; + while (j > 0 && g->layers[idx[j - 1]].activation_priority > kp) { + idx[j] = idx[j - 1]; + j--; + } + idx[j] = key; + } + int first = 1; + for (size_t i = 0; i < live; i++) { + EngramLayer* L = &g->layers[idx[i]]; + if (!first) jb_putc(&b, ','); + first = 0; + jb_putc(&b, '{'); + char tmp[80]; + snprintf(tmp, sizeof(tmp), "\"layer_id\":%u", L->layer_id); jb_puts(&b, tmp); + jb_puts(&b, ",\"name\":"); + jb_emit_escaped(&b, L->name ? L->name : ""); + snprintf(tmp, sizeof(tmp), ",\"activation_priority\":%u", L->activation_priority); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"suppressible\":%d", L->suppressible ? 1 : 0); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"transparent\":%d", L->transparent ? 1 : 0); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"injectable\":%d", L->injectable ? 1 : 0); + jb_puts(&b, tmp); + jb_putc(&b, '}'); + } + free(idx); + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +/* engram_compile_layered_json — produce a prompt-ready context block split + * by layer. + * + * Runs the three-pass activation, then partitions promoted nodes by layer + * suppressibility: + * - Non-suppressible (Layer 0 / structural-floor) layers go FIRST under + * the heading "[LAYER 0 — STRUCTURAL]". These are the sacred-fire + * nodes that surfaced via the pass-3 override. + * - All other promoted layers go SECOND under "[ENGRAM CONTEXT]". + * + * Output is a single JSON-string el_val_t: a UTF-8 text block ready to be + * concatenated into a system prompt. Returns "" if no nodes promoted. + * + * Transparent layers (Layer 0) are emitted into the prompt — they shape + * the model's output — but engram_search and friends still hide them from + * introspection-style queries. The split heading lets the LLM weight them + * appropriately without revealing their internal label. + * + * Each emitted line for a node is its raw JSON (matching engram_emit_node_json) + * so downstream JSON parsers can still walk individual records inside the + * formatted block. The block is plain text, not a JSON document — callers + * concatenating it into a prompt should treat it as opaque markdown. */ +el_val_t engram_compile_layered_json(el_val_t intent, el_val_t depth) { + EngramStore* g = engram_get(); + /* Run the three-pass activator. We need the persisted node fields, so + * call engram_activate (it writes background_activation and + * working_memory_weight back into the store). */ + (void)engram_activate(intent, depth); + + /* Walk the store and partition by suppressibility. */ + JsonBuf b; jb_init(&b); + int wrote_layer0 = 0; + int wrote_normal = 0; + + /* Sort indices by working_memory_weight descending so the most + * confidently promoted nodes appear first within each section. */ + int64_t* idx = malloc((size_t)(g->node_count + 1) * sizeof(int64_t)); + if (!idx) return el_wrap_str(el_strdup("")); + int64_t mc = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (g->nodes[i].working_memory_weight > 0.0) idx[mc++] = i; + } + for (int64_t i = 1; i < mc; i++) { + int64_t key = idx[i]; + double kw = g->nodes[key].working_memory_weight; + int64_t j = i; + while (j > 0 && g->nodes[idx[j - 1]].working_memory_weight < kw) { + idx[j] = idx[j - 1]; + j--; + } + idx[j] = key; + } + + /* Section 1: structural floor (non-suppressible layers). */ + for (int64_t i = 0; i < mc; i++) { + EngramNode* n = &g->nodes[idx[i]]; + if (engram_layer_is_suppressible(n->layer_id)) continue; + if (!wrote_layer0) { + jb_puts(&b, "[LAYER 0 — STRUCTURAL]\n"); + wrote_layer0 = 1; + } + engram_emit_node_json(&b, n); + jb_putc(&b, '\n'); + } + + /* Section 2: standard engram context (suppressible layers). */ + for (int64_t i = 0; i < mc; i++) { + EngramNode* n = &g->nodes[idx[i]]; + if (!engram_layer_is_suppressible(n->layer_id)) continue; + if (!wrote_normal) { + if (wrote_layer0) jb_putc(&b, '\n'); + jb_puts(&b, "[ENGRAM CONTEXT]\n"); + wrote_normal = 1; + } + engram_emit_node_json(&b, n); + jb_putc(&b, '\n'); + } + + free(idx); + if (b.len == 0) { + free(b.buf); + return el_wrap_str(el_strdup("")); + } + return el_wrap_str(b.buf); +} + +/* engram_query_range — temporal range query. + * Returns a JSON array of nodes whose created_at OR last_activated falls + * within [start_ms, end_ms], sorted by created_at ascending. + * Enables "what was I working on last Tuesday?" style queries by passing + * unix-millisecond timestamps for the start and end of the target interval. + * Both endpoints are inclusive. Pass 0 for start_ms to mean "beginning of + * time"; pass 0 for end_ms to mean "now". */ +el_val_t engram_query_range(el_val_t start_ms_v, el_val_t end_ms_v) { + EngramStore* g = engram_get(); + int64_t start_ms = (int64_t)start_ms_v; + int64_t end_ms = (int64_t)end_ms_v; + if (end_ms <= 0) end_ms = engram_now_ms(); + + /* Collect matching indices. */ + int64_t* idx = malloc((size_t)g->node_count * sizeof(int64_t)); + if (!idx) return el_wrap_str(el_strdup("[]")); + int64_t mc = 0; + for (int64_t i = 0; i < g->node_count; i++) { + EngramNode* n = &g->nodes[i]; + int in_created = (n->created_at >= start_ms && n->created_at <= end_ms); + int in_activated = (n->last_activated >= start_ms && n->last_activated <= end_ms); + if (in_created || in_activated) idx[mc++] = i; + } + /* Sort by created_at ascending (insertion sort — N is small in practice). */ + for (int64_t i = 1; i < mc; i++) { + int64_t key = idx[i]; + int64_t kts = g->nodes[key].created_at; + int64_t j = i - 1; + while (j >= 0 && g->nodes[idx[j]].created_at > kts) { + idx[j + 1] = idx[j]; + j--; + } + idx[j + 1] = key; + } + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + for (int64_t i = 0; i < mc; i++) { + if (i > 0) jb_putc(&b, ','); + engram_emit_node_json(&b, &g->nodes[idx[i]]); + } + jb_putc(&b, ']'); + free(idx); + return el_wrap_str(b.buf); +} + +/* ── engram_apply_decay_json — temporal decay maintenance ──────────────────── + * + * Iterates ALL nodes and applies temporal decay to their stored `salience` + * field based on time elapsed since `last_activated`: + * + * new_salience = current_salience * decay_rate ^ hours_since_activation + * + * where decay_rate defaults to 0.5^(1/168) per hour (half-life one week), + * or the node's own `temporal_decay_rate` if non-zero. + * + * Nodes with temporal_decay_rate == 0 are NOT immune — the global default + * applies. To make a node truly immune, set temporal_decay_rate to a very + * small positive value (e.g. 0.0001). Nodes that are "pinned" can be + * identified by a tier of "Procedural" — those are skipped. + * + * After updating salience, nodes with salience < 0.05 AND tier == "Working" + * are pruned (deleted) unless they have no content (guard against garbage). + * + * Returns a JSON summary: {"updated": N, "pruned": N} */ +el_val_t engram_apply_decay_json(void) { + EngramStore* g = engram_get(); + int64_t now_ms = engram_now_ms(); + int64_t updated = 0, pruned = 0; + + for (int64_t i = 0; i < g->node_count; i++) { + EngramNode* n = &g->nodes[i]; + /* Skip Procedural nodes (they are "locked in"). */ + if (n->tier && strcmp(n->tier, "Procedural") == 0) continue; + int64_t age_ms = now_ms - n->last_activated; + if (age_ms <= 0) continue; + double lambda = (n->temporal_decay_rate > 0.0) ? n->temporal_decay_rate + : ENGRAM_DECAY_LAMBDA; + double age_hours = (double)age_ms / 3600000.0; + double decay_factor = exp(-lambda * age_hours / ENGRAM_T_HALF_HOURS); + double new_salience = n->salience * decay_factor; + if (new_salience < 0.0) new_salience = 0.0; + if (new_salience != n->salience) { + n->salience = new_salience; + n->updated_at = now_ms; + updated++; + } + } + + /* Prune low-salience Working nodes. Walk backwards to allow in-place + * removal without invalidating indices. */ + for (int64_t i = g->node_count - 1; i >= 0; i--) { + EngramNode* n = &g->nodes[i]; + if (n->salience >= 0.05) continue; + /* Only prune Working tier nodes — higher tiers are protected. */ + if (!n->tier || strcmp(n->tier, "Working") != 0) continue; + /* Guard: skip nodes with no content. */ + if (!n->content || !*n->content) continue; + /* Free node strings. */ + free(n->id); free(n->content); free(n->node_type); free(n->label); + free(n->tier); free(n->tags); free(n->metadata); + /* Shift remaining nodes down. */ + for (int64_t j = i + 1; j < g->node_count; j++) { + g->nodes[j - 1] = g->nodes[j]; + } + g->node_count--; + memset(&g->nodes[g->node_count], 0, sizeof(EngramNode)); + pruned++; + } + + /* Remove dangling edges for pruned nodes (any edge whose endpoint no + * longer exists in the node list). */ + if (pruned > 0) { + int64_t w = 0; + for (int64_t r = 0; r < g->edge_count; r++) { + EngramEdge* e = &g->edges[r]; + int dangling = 0; + if (e->from_id && engram_find_node_index(e->from_id) < 0) dangling = 1; + if (e->to_id && engram_find_node_index(e->to_id) < 0) dangling = 1; + if (dangling) { + free(e->id); free(e->from_id); free(e->to_id); + free(e->relation); free(e->metadata); + } else { + if (w != r) g->edges[w] = g->edges[r]; + w++; + } + } + g->edge_count = w; + } + + char buf[128]; + snprintf(buf, sizeof(buf), + "{\"ok\":true,\"updated\":%lld,\"pruned\":%lld}", + (long long)updated, (long long)pruned); + return el_wrap_str(el_strdup(buf)); +} + +#ifdef HAVE_CURL +/* ── DHARMA network ───────────────────────────────────────────────────────── + * Real implementation. Peers are addressed by `dharma_id` — either bare + * (e.g. "ntn-genesis", transport defaults to http://localhost:7770) or + * "@" where is the peer's Engram-exposed daemon. + * + * Channels are logical handles cached per-cgi: `dharma_connect` is + * idempotent and returns "ch:". The channel registry below tracks + * every cgi_id we've connected to and its resolved transport URL. + * + * Relationship weights live in the local Engram graph: edges of type + * "dharma-relation" between a synthetic local node ("dharma:self") and + * synthetic peer nodes ("dharma:peer:"). Hebbian increments + * accumulate in EngramEdge.weight, clamped to [0.0, 1.0]. + * + * Events arrive over HTTP via the application's request handler, which is + * expected to call el_runtime_dharma_event_arrive() when it sees a + * /dharma/event POST. dharma_field() blocks on a per-event-type queue. + */ + +#define DHARMA_DEFAULT_URL "http://localhost:7770" + +/* Channel registry — one entry per known peer. */ +typedef struct DharmaChannel { + char* cgi_id; /* full dharma_id including any @ suffix */ + char* base_id; /* registry-id portion (before @) for relationship lookup */ + char* url; /* resolved transport URL */ + char* channel_id; /* "ch:" */ +} DharmaChannel; + +static DharmaChannel* _dharma_channels = NULL; +static size_t _dharma_channel_count = 0; +static size_t _dharma_channel_cap = 0; +static pthread_mutex_t _dharma_channel_mu = PTHREAD_MUTEX_INITIALIZER; + +/* Event queue — per-type linked list. dharma_field blocks on _dharma_event_cv. */ +typedef struct DharmaEvent { + char* event_type; + char* payload; + char* source; + int64_t timestamp; + struct DharmaEvent* next; +} DharmaEvent; + +static DharmaEvent* _dharma_event_head = NULL; +static DharmaEvent* _dharma_event_tail = NULL; +static pthread_mutex_t _dharma_event_mu = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t _dharma_event_cv = PTHREAD_COND_INITIALIZER; + +/* Split "@" → (base_id, url). If no "@", base_id = full, url = default. + * Returned strings are heap-allocated; caller must free. */ +static void dharma_parse_id(const char* full, char** out_base, char** out_url) { + if (!full) full = ""; + const char* at = strchr(full, '@'); + if (at) { + size_t bn = (size_t)(at - full); + char* b = malloc(bn + 1); + memcpy(b, full, bn); b[bn] = '\0'; + *out_base = b; + *out_url = el_strdup(at + 1); + if (!**out_url) { free(*out_url); *out_url = el_strdup(DHARMA_DEFAULT_URL); } + } else { + *out_base = el_strdup(full); + *out_url = el_strdup(DHARMA_DEFAULT_URL); + } +} + +/* Find existing channel by full cgi_id. Caller must hold _dharma_channel_mu. */ +static DharmaChannel* dharma_find_channel_locked(const char* cgi_id) { + if (!cgi_id) return NULL; + for (size_t i = 0; i < _dharma_channel_count; i++) { + if (_dharma_channels[i].cgi_id && + strcmp(_dharma_channels[i].cgi_id, cgi_id) == 0) { + return &_dharma_channels[i]; + } + } + return NULL; +} + +/* Add a new channel entry. Caller must hold _dharma_channel_mu. */ +static DharmaChannel* dharma_add_channel_locked(const char* cgi_id) { + if (_dharma_channel_count >= _dharma_channel_cap) { + size_t nc = _dharma_channel_cap ? _dharma_channel_cap * 2 : 8; + _dharma_channels = realloc(_dharma_channels, nc * sizeof(DharmaChannel)); + if (!_dharma_channels) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + memset(_dharma_channels + _dharma_channel_cap, 0, + (nc - _dharma_channel_cap) * sizeof(DharmaChannel)); + _dharma_channel_cap = nc; + } + DharmaChannel* ch = &_dharma_channels[_dharma_channel_count++]; + char* base = NULL; char* url = NULL; + dharma_parse_id(cgi_id, &base, &url); + ch->cgi_id = el_strdup(cgi_id ? cgi_id : ""); + ch->base_id = base; + ch->url = url; + size_t cn = strlen(ch->cgi_id) + 4; + ch->channel_id = malloc(cn); + snprintf(ch->channel_id, cn, "ch:%s", ch->cgi_id); + return ch; +} + +el_val_t dharma_connect(el_val_t cgi_id) { + const char* id = EL_CSTR(cgi_id); + if (!id || !*id) return el_wrap_str(el_strdup("")); + pthread_mutex_lock(&_dharma_channel_mu); + DharmaChannel* ch = dharma_find_channel_locked(id); + if (!ch) ch = dharma_add_channel_locked(id); + char* out = el_strdup(ch->channel_id); + pthread_mutex_unlock(&_dharma_channel_mu); + return el_wrap_str(out); +} + +/* Build an error JSON body — same shape http_error_json uses. */ +static el_val_t dharma_error_json(const char* msg) { + return http_error_json(msg); +} + +el_val_t dharma_send(el_val_t channel, el_val_t content) { + const char* ch_id = EL_CSTR(channel); + const char* msg = EL_CSTR(content); + if (!ch_id || strncmp(ch_id, "ch:", 3) != 0) { + return dharma_error_json("invalid channel"); + } + const char* peer_id = ch_id + 3; + /* Look up channel; if unknown (caller fabricated), auto-register. */ + pthread_mutex_lock(&_dharma_channel_mu); + DharmaChannel* ch = dharma_find_channel_locked(peer_id); + if (!ch) ch = dharma_add_channel_locked(peer_id); + char* url = el_strdup(ch->url); + pthread_mutex_unlock(&_dharma_channel_mu); + /* Build /dharma/recv body. */ + const char* from = _el_cgi_dharma_id ? _el_cgi_dharma_id : "(unknown)"; + char* esc_ch = json_escape_alloc(ch_id); + char* esc_from = json_escape_alloc(from); + char* esc_msg = json_escape_alloc(msg ? msg : ""); + JsonBuf b; jb_init(&b); + jb_puts(&b, "{\"channel\":\""); jb_puts(&b, esc_ch); + jb_puts(&b, "\",\"from\":\""); jb_puts(&b, esc_from); + jb_puts(&b, "\",\"content\":\""); jb_puts(&b, esc_msg); + jb_puts(&b, "\"}"); + free(esc_ch); free(esc_from); free(esc_msg); + size_t ul = strlen(url) + 16; + char* full_url = malloc(ul); + snprintf(full_url, ul, "%s/dharma/recv", url); + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + el_val_t resp = http_do("POST", full_url, b.buf, h); + curl_slist_free_all(h); + free(b.buf); free(full_url); free(url); + return resp; +} + +el_val_t dharma_activate(el_val_t query) { + const char* q = EL_CSTR(query); + if (!q) q = ""; + el_val_t out = el_list_empty(); + char* esc_q = json_escape_alloc(q); + JsonBuf body; jb_init(&body); + jb_puts(&body, "{\"query\":\""); jb_puts(&body, esc_q); jb_puts(&body, "\"}"); + free(esc_q); + + /* Snapshot the channel list under lock so we can iterate without + * holding the mutex during network I/O. */ + pthread_mutex_lock(&_dharma_channel_mu); + size_t n = _dharma_channel_count; + char** urls = calloc(n ? n : 1, sizeof(char*)); + char** ids = calloc(n ? n : 1, sizeof(char*)); + char** bases = calloc(n ? n : 1, sizeof(char*)); + for (size_t i = 0; i < n; i++) { + urls[i] = el_strdup(_dharma_channels[i].url); + ids[i] = el_strdup(_dharma_channels[i].cgi_id); + bases[i] = el_strdup(_dharma_channels[i].base_id); + } + pthread_mutex_unlock(&_dharma_channel_mu); + + for (size_t i = 0; i < n; i++) { + size_t ul = strlen(urls[i]) + 32; + char* full_url = malloc(ul); + snprintf(full_url, ul, "%s/api/activate", urls[i]); + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + el_val_t resp = http_do("POST", full_url, body.buf, h); + curl_slist_free_all(h); + free(full_url); + const char* rs = EL_CSTR(resp); + if (!rs || !*rs) continue; + if (rs[0] == '{' && strstr(rs, "\"error\"")) continue; + + /* Look up relationship weight (attenuation). */ + double rel_weight = 1.0; + { + const char* self_id = "dharma:self"; + char peer_node[512]; + snprintf(peer_node, sizeof(peer_node), "dharma:peer:%s", bases[i]); + EngramStore* g = engram_get(); + for (int64_t k = 0; k < g->edge_count; k++) { + EngramEdge* e = &g->edges[k]; + if (e->from_id && e->to_id && + strcmp(e->from_id, self_id) == 0 && + strcmp(e->to_id, peer_node) == 0 && + e->relation && strcmp(e->relation, "dharma-relation") == 0) { + rel_weight = e->weight; + break; + } + } + } + + /* Iterate the response array. Expect either a top-level array + * or an object whose "results" field is an array. */ + const char* arr = rs; + while (*arr == ' ' || *arr == '\t' || *arr == '\n' || *arr == '\r') arr++; + char* arr_owned = NULL; + if (*arr == '{') { + el_val_t r = json_get_raw(EL_STR(rs), EL_STR("results")); + const char* rr = EL_CSTR(r); + if (rr && *rr == '[') { + arr_owned = el_strdup(rr); + arr = arr_owned; + } else { + continue; + } + } + if (*arr != '[') { free(arr_owned); continue; } + const char* p = arr + 1; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + while (*p && *p != ']') { + const char* end = json_skip_value(p); + size_t en = (size_t)(end - p); + char* obj = el_strbuf(en); + memcpy(obj, p, en); obj[en] = '\0'; + + /* Pull activation_strength if present, else 1.0. */ + el_val_t act_v = json_get_float(EL_STR(obj), EL_STR("activation_strength")); + double act = el_to_float(act_v); + if (!(act > 0.0 && act <= 100.0)) act = 1.0; + double final_act = act * rel_weight; + + el_val_t entry = el_map_new(0); + /* node = the inner JSON if present, else the entire obj. */ + el_val_t node_raw = json_get_raw(EL_STR(obj), EL_STR("node")); + const char* nr = EL_CSTR(node_raw); + entry = el_map_set(entry, EL_STR(el_strdup("node")), + (nr && *nr) ? node_raw : EL_STR(el_strdup(obj))); + entry = el_map_set(entry, EL_STR(el_strdup("source_cgi")), + EL_STR(el_strdup(ids[i]))); + entry = el_map_set(entry, EL_STR(el_strdup("activation_strength")), + el_from_float(final_act)); + out = el_list_append(out, entry); + free(obj); + p = end; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + } + free(arr_owned); + } + for (size_t i = 0; i < n; i++) { free(urls[i]); free(ids[i]); free(bases[i]); } + free(urls); free(ids); free(bases); + free(body.buf); + return out; +} + +void dharma_emit(el_val_t event_type, el_val_t payload) { + const char* et = EL_CSTR(event_type); + const char* pay = EL_CSTR(payload); + if (!et) et = ""; + if (!pay) pay = ""; + const char* src = _el_cgi_dharma_id ? _el_cgi_dharma_id : "(unknown)"; + int64_t ts = engram_now_ms(); + + char* esc_et = json_escape_alloc(et); + char* esc_pay = json_escape_alloc(pay); + char* esc_src = json_escape_alloc(src); + JsonBuf b; jb_init(&b); + jb_puts(&b, "{\"type\":\""); jb_puts(&b, esc_et); + jb_puts(&b, "\",\"payload\":\""); jb_puts(&b, esc_pay); + jb_puts(&b, "\",\"source\":\""); jb_puts(&b, esc_src); + jb_puts(&b, "\",\"timestamp\":"); jb_emit_int(&b, ts); + jb_putc(&b, '}'); + free(esc_et); free(esc_pay); free(esc_src); + + /* Snapshot URLs to avoid holding the channel mutex during I/O. */ + pthread_mutex_lock(&_dharma_channel_mu); + size_t n = _dharma_channel_count; + char** urls = calloc(n ? n : 1, sizeof(char*)); + for (size_t i = 0; i < n; i++) urls[i] = el_strdup(_dharma_channels[i].url); + pthread_mutex_unlock(&_dharma_channel_mu); + + for (size_t i = 0; i < n; i++) { + size_t ul = strlen(urls[i]) + 32; + char* full_url = malloc(ul); + snprintf(full_url, ul, "%s/dharma/event", urls[i]); + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + el_val_t r = http_do("POST", full_url, b.buf, h); + (void)r; /* fire-and-forget — emit is not synchronous */ + curl_slist_free_all(h); + free(full_url); + } + for (size_t i = 0; i < n; i++) free(urls[i]); + free(urls); + free(b.buf); +} + +void el_runtime_dharma_event_arrive(const char* event_type, const char* payload, + const char* source) { + DharmaEvent* ev = calloc(1, sizeof(DharmaEvent)); + if (!ev) return; + ev->event_type = el_strdup(event_type ? event_type : ""); + ev->payload = el_strdup(payload ? payload : ""); + ev->source = el_strdup(source ? source : ""); + ev->timestamp = engram_now_ms(); + ev->next = NULL; + pthread_mutex_lock(&_dharma_event_mu); + if (_dharma_event_tail) _dharma_event_tail->next = ev; + else _dharma_event_head = ev; + _dharma_event_tail = ev; + pthread_cond_broadcast(&_dharma_event_cv); + pthread_mutex_unlock(&_dharma_event_mu); +} + +el_val_t dharma_field(el_val_t event_type) { + const char* et = EL_CSTR(event_type); + if (!et) et = ""; + + /* Compute deadline: now + 30 seconds. */ + struct timespec deadline; + clock_gettime(CLOCK_REALTIME, &deadline); + deadline.tv_sec += 30; + + DharmaEvent* found = NULL; + pthread_mutex_lock(&_dharma_event_mu); + while (1) { + /* Scan queue for matching type; pop and return first match. */ + DharmaEvent* prev = NULL; + DharmaEvent* cur = _dharma_event_head; + while (cur) { + if (cur->event_type && strcmp(cur->event_type, et) == 0) { + if (prev) prev->next = cur->next; + else _dharma_event_head = cur->next; + if (_dharma_event_tail == cur) _dharma_event_tail = prev; + cur->next = NULL; + found = cur; + break; + } + prev = cur; cur = cur->next; + } + if (found) break; + int rc = pthread_cond_timedwait(&_dharma_event_cv, &_dharma_event_mu, &deadline); + if (rc == ETIMEDOUT) break; + } + pthread_mutex_unlock(&_dharma_event_mu); + + if (!found) return el_map_new(0); + el_val_t m = el_map_new(0); + m = el_map_set(m, EL_STR(el_strdup("type")), + EL_STR(el_strdup(found->event_type ? found->event_type : ""))); + m = el_map_set(m, EL_STR(el_strdup("payload")), + EL_STR(el_strdup(found->payload ? found->payload : ""))); + m = el_map_set(m, EL_STR(el_strdup("source_cgi")), + EL_STR(el_strdup(found->source ? found->source : ""))); + m = el_map_set(m, EL_STR(el_strdup("timestamp")), (el_val_t)found->timestamp); + free(found->event_type); free(found->payload); free(found->source); free(found); + return m; +} + +/* Locate (or create) the local "dharma:self" node and the synthetic peer + * node "dharma:peer:". Returns the index of the dharma-relation + * edge, or -1 if not found. If `create` is non-zero, ensure the nodes + * and edge exist (creating them as needed) and return the edge index. */ +static int64_t dharma_find_or_create_relation_edge(const char* peer_base, int create) { + if (!peer_base || !*peer_base) return -1; + EngramStore* g = engram_get(); + const char* self_id = "dharma:self"; + char peer_node[512]; + snprintf(peer_node, sizeof(peer_node), "dharma:peer:%s", peer_base); + + /* Look for the edge first. */ + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + if (e->from_id && e->to_id && + strcmp(e->from_id, self_id) == 0 && + strcmp(e->to_id, peer_node) == 0 && + e->relation && strcmp(e->relation, "dharma-relation") == 0) { + return i; + } + } + if (!create) return -1; + + /* Ensure self node exists. We use a fixed id (not engram_new_id) so + * subsequent calls reuse the same one. */ + if (!engram_find_node(self_id)) { + engram_grow_nodes(); + EngramNode* n = &g->nodes[g->node_count]; + memset(n, 0, sizeof(*n)); + n->id = el_strdup(self_id); + n->content = el_strdup(_el_cgi_dharma_id ? _el_cgi_dharma_id : "(self)"); + n->node_type = el_strdup("DharmaSelf"); + n->label = el_strdup("dharma:self"); + n->tier = el_strdup("Working"); + n->tags = el_strdup("dharma"); + n->metadata = el_strdup("{}"); + n->salience = 1.0; n->importance = 1.0; n->confidence = 1.0; + int64_t now = engram_now_ms(); + n->created_at = now; n->updated_at = now; n->last_activated = now; + n->layer_id = ENGRAM_LAYER_DEFAULT; + g->node_count++; + } + if (!engram_find_node(peer_node)) { + engram_grow_nodes(); + EngramNode* n = &g->nodes[g->node_count]; + memset(n, 0, sizeof(*n)); + n->id = el_strdup(peer_node); + n->content = el_strdup(peer_base); + n->node_type = el_strdup("DharmaPeer"); + n->label = el_strdup(peer_node); + n->tier = el_strdup("Working"); + n->tags = el_strdup("dharma"); + n->metadata = el_strdup("{}"); + n->salience = 0.5; n->importance = 0.5; n->confidence = 1.0; + int64_t now = engram_now_ms(); + n->created_at = now; n->updated_at = now; n->last_activated = now; + n->layer_id = ENGRAM_LAYER_DEFAULT; + g->node_count++; + } + /* Create the edge with weight 0.0 — caller will increment. */ + engram_grow_edges(); + EngramEdge* e = &g->edges[g->edge_count]; + memset(e, 0, sizeof(*e)); + e->id = engram_new_id(); + e->from_id = el_strdup(self_id); + e->to_id = el_strdup(peer_node); + e->relation = el_strdup("dharma-relation"); + e->metadata = el_strdup("{}"); + e->weight = 0.0; + e->confidence = 1.0; + int64_t now = engram_now_ms(); + e->created_at = now; e->updated_at = now; + e->layer_id = ENGRAM_LAYER_DEFAULT; + int64_t idx = g->edge_count; + g->edge_count++; + return idx; +} + +void dharma_strengthen(el_val_t cgi_id, el_val_t weight) { + const char* id = EL_CSTR(cgi_id); + if (!id || !*id) return; + char* base = NULL; char* url = NULL; + dharma_parse_id(id, &base, &url); + free(url); + int64_t ei = dharma_find_or_create_relation_edge(base, 1); + free(base); + if (ei < 0) return; + EngramStore* g = engram_get(); + double inc = engram_decode_score(weight); + if (!(inc >= 0.0)) inc = 0.0; + double w = g->edges[ei].weight + inc; + if (w < 0.0) w = 0.0; + if (w > 1.0) w = 1.0; + g->edges[ei].weight = w; + g->edges[ei].updated_at = engram_now_ms(); + g->edges[ei].last_fired = g->edges[ei].updated_at; +} + +el_val_t dharma_relationship(el_val_t cgi_id) { + const char* id = EL_CSTR(cgi_id); + if (!id || !*id) return el_from_float(0.0); + char* base = NULL; char* url = NULL; + dharma_parse_id(id, &base, &url); + free(url); + int64_t ei = dharma_find_or_create_relation_edge(base, 0); + free(base); + if (ei < 0) return el_from_float(0.0); + EngramStore* g = engram_get(); + return el_from_float(g->edges[ei].weight); +} + +el_val_t dharma_peers(void) { + /* Walk dharma-relation edges out of "dharma:self", weight > 0, sort desc. */ + EngramStore* g = engram_get(); + const char* self_id = "dharma:self"; + typedef struct { char* peer_base; double weight; } PeerEntry; + PeerEntry* peers = malloc((size_t)(g->edge_count + 1) * sizeof(PeerEntry)); + int64_t pcount = 0; + if (!peers) return el_list_empty(); + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + if (!e->from_id || !e->to_id) continue; + if (strcmp(e->from_id, self_id) != 0) continue; + if (!e->relation || strcmp(e->relation, "dharma-relation") != 0) continue; + if (e->weight <= 0.0) continue; + const char* prefix = "dharma:peer:"; + size_t pl = strlen(prefix); + if (strncmp(e->to_id, prefix, pl) != 0) continue; + peers[pcount].peer_base = el_strdup(e->to_id + pl); + peers[pcount].weight = e->weight; + pcount++; + } + /* Sort desc by weight. */ + for (int64_t i = 1; i < pcount; i++) { + PeerEntry key = peers[i]; + int64_t j = i - 1; + while (j >= 0 && peers[j].weight < key.weight) { + peers[j + 1] = peers[j]; j--; + } + peers[j + 1] = key; + } + el_val_t out = el_list_empty(); + for (int64_t i = 0; i < pcount; i++) { + out = el_list_append(out, EL_STR(peers[i].peer_base)); + } + free(peers); + return out; +} +#endif /* HAVE_CURL — DHARMA network */ + +/* ── Batch 4: LLM (Anthropic API client) ─────────────────────────────────── */ +/* + * All LLM builtins call https://api.anthropic.com/v1/messages with the API + * key from env ANTHROPIC_API_KEY. Default model is "claude-sonnet-4-5" + * when the supplied model is empty/null. + * + * `llm_call_agentic` runs a real multi-turn tool_use/tool_result loop. + * Tool handlers are registered with `llm_register_tool(name, fn_name)`, + * which dlsym()s the named symbol. Each tool handler has the C signature + * el_val_t handler(el_val_t input_json); + * and returns a JSON-string el_val_t result. Iteration is capped at 10. + */ + +#ifdef HAVE_CURL +static const char* LLM_DEFAULT_MODEL = "claude-sonnet-4-5"; +static const char* LLM_API_URL = "https://api.anthropic.com/v1/messages"; +static const char* LLM_VERSION = "2023-06-01"; + +static const char* llm_resolve_model(const char* m) { + if (!m || !*m) return LLM_DEFAULT_MODEL; + return m; +} + +/* + * ── Configurable LLM provider chain ────────────────────────────────────────── + * + * Providers are configured via indexed env vars. The runtime tries each in + * order (0, 1, 2, ...) and returns the first successful non-empty response. + * + * Per provider (N = 0, 1, 2, ...): + * NEURON_LLM_N_URL — endpoint URL (base URL; /v1/chat/completions appended + * if format is "openai" and not already in URL) + * NEURON_LLM_N_KEY — API key + * NEURON_LLM_N_FORMAT — "openai" (default) or "anthropic" + * NEURON_LLM_N_MODEL — model name override (optional) + * + * Example — Neuron inference primary, Anthropic fallback: + * NEURON_LLM_0_URL=https://soma.../v1/chat/completions + * NEURON_LLM_0_KEY=svc-key + * NEURON_LLM_0_FORMAT=openai + * NEURON_LLM_0_MODEL=neuron + * NEURON_LLM_1_URL=https://api.anthropic.com/v1/messages + * NEURON_LLM_1_KEY=sk-ant-... + * NEURON_LLM_1_FORMAT=anthropic + * + * If no NEURON_LLM_0_URL is set, falls back to legacy ANTHROPIC_API_KEY. + */ + +#define LLM_MAX_PROVIDERS 16 + +/* forward declarations */ +static el_val_t llm_extract_text(el_val_t resp_val); +static el_val_t llm_extract_text_openai(el_val_t resp_val); + +static el_val_t llm_extract_text_openai(el_val_t resp_val) { + const char* resp = EL_CSTR(resp_val); + if (!resp || !*resp) return el_wrap_str(el_strdup("")); + if (resp[0] == '{' && strstr(resp, "\"error\"")) return el_wrap_str(el_strdup("")); + const char* choices = json_find_key(resp, "choices"); + if (!choices || *choices != '[') return el_wrap_str(el_strdup("")); + choices++; + while (*choices == ' ' || *choices == '\t') choices++; + if (*choices != '{') return el_wrap_str(el_strdup("")); + const char* end = json_skip_value(choices); + size_t n = (size_t)(end - choices); + char* obj = malloc(n + 1); memcpy(obj, choices, n); obj[n] = '\0'; + const char* msg = json_find_key(obj, "message"); + if (!msg || *msg != '{') { free(obj); return el_wrap_str(el_strdup("")); } + const char* msg_end = json_skip_value(msg); + size_t mn = (size_t)(msg_end - msg); + char* msg_obj = malloc(mn + 1); memcpy(msg_obj, msg, mn); msg_obj[mn] = '\0'; + const char* content = json_find_key(msg_obj, "content"); + el_val_t result = el_wrap_str(el_strdup("")); + if (content && *content == '"') { + JsonParser jp = { .p = content, .end = content + strlen(content), .err = 0 }; + char* text = jp_parse_string_raw(&jp); + if (!jp.err && text) result = el_wrap_str(text); + } + free(msg_obj); free(obj); + return result; +} + +/* Send a request to one provider. Returns the raw response string. + * format: 0 = openai, 1 = anthropic */ +static el_val_t llm_provider_request(const char* url, const char* key, + int format, const char* model, + const char* system_str, + const char* user_str) { + char* esc_sys = system_str && *system_str ? json_escape_alloc(system_str) : NULL; + char* esc_user = json_escape_alloc(user_str ? user_str : ""); + JsonBuf b; jb_init(&b); + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + + if (format == 0) { /* OpenAI */ + char full_url[1024]; + if (strstr(url, "/chat/completions") || strstr(url, "/messages")) { + snprintf(full_url, sizeof(full_url), "%s", url); + } else { + snprintf(full_url, sizeof(full_url), "%s/v1/chat/completions", url); + } + { size_t n = strlen(key)+24; char* l=malloc(n); snprintf(l,n,"Authorization: Bearer %s",key); h=curl_slist_append(h,l); free(l); } + jb_putc(&b, '{'); + jb_puts(&b, "\"model\":"); jb_emit_escaped(&b, model ? model : "neuron"); + jb_puts(&b, ",\"max_tokens\":4096,\"messages\":["); + if (esc_sys && *esc_sys) { jb_puts(&b,"{\"role\":\"system\",\"content\":\""); jb_puts(&b,esc_sys); jb_puts(&b,"\"},"); } + jb_puts(&b, "{\"role\":\"user\",\"content\":\""); jb_puts(&b, esc_user); jb_puts(&b, "\"}]}"); + el_val_t resp = http_do("POST", full_url, b.buf, h); + curl_slist_free_all(h); free(b.buf); + if (esc_sys) free(esc_sys); free(esc_user); + return llm_extract_text_openai(resp); + } else { /* Anthropic */ + { size_t n = strlen(key)+16; char* l=malloc(n); snprintf(l,n,"x-api-key: %s",key); h=curl_slist_append(h,l); free(l); } + { size_t n = strlen(LLM_VERSION)+32; char* l=malloc(n); snprintf(l,n,"anthropic-version: %s",LLM_VERSION); h=curl_slist_append(h,l); free(l); } + jb_putc(&b, '{'); + jb_puts(&b, "\"model\":"); jb_emit_escaped(&b, model ? model : LLM_DEFAULT_MODEL); + jb_puts(&b, ",\"max_tokens\":4096"); + if (esc_sys && *esc_sys) { jb_puts(&b,",\"system\":\""); jb_puts(&b,esc_sys); jb_puts(&b,"\""); } + jb_puts(&b, ",\"messages\":[{\"role\":\"user\",\"content\":\""); jb_puts(&b, esc_user); jb_puts(&b, "\"}]}"); + el_val_t resp = http_do("POST", url, b.buf, h); + curl_slist_free_all(h); free(b.buf); + if (esc_sys) free(esc_sys); free(esc_user); + return llm_extract_text(resp); + } +} + +static el_val_t llm_chain_call(const char* system_str, const char* user_str) { + char url_key[64], key_key[64], fmt_key[64], model_key[64]; + for (int i = 0; i < LLM_MAX_PROVIDERS; i++) { + snprintf(url_key, sizeof(url_key), "NEURON_LLM_%d_URL", i); + snprintf(key_key, sizeof(key_key), "NEURON_LLM_%d_KEY", i); + snprintf(fmt_key, sizeof(fmt_key), "NEURON_LLM_%d_FORMAT", i); + snprintf(model_key, sizeof(model_key), "NEURON_LLM_%d_MODEL", i); + const char* url = getenv(url_key); + const char* key = getenv(key_key); + if (!url || !*url || !key || !*key) break; /* end of chain */ + const char* fmt_s = getenv(fmt_key); + int fmt = (fmt_s && strcmp(fmt_s, "anthropic") == 0) ? 1 : 0; + const char* model = getenv(model_key); + fprintf(stderr, "[llm] trying provider %d (%s)\n", i, url); + el_val_t result = llm_provider_request(url, key, fmt, model, system_str, user_str); + const char* t = EL_CSTR(result); + if (t && *t && t[0] != '{') return result; /* success */ + fprintf(stderr, "[llm] provider %d failed or empty, trying next\n", i); + } + /* Legacy fallback: ANTHROPIC_API_KEY */ + const char* api_key = getenv("ANTHROPIC_API_KEY"); + if (!api_key || !*api_key) return http_error_json("no LLM providers configured"); + fprintf(stderr, "[llm] using legacy ANTHROPIC_API_KEY fallback\n"); + return llm_provider_request(LLM_API_URL, api_key, 1, NULL, system_str, user_str); +} + +/* Legacy llm_request — kept for backward compat with agentic loop internals */ +static el_val_t llm_request(const char* json_body) { + const char* api_key = getenv("ANTHROPIC_API_KEY"); + if (!api_key || !*api_key) return http_error_json("ANTHROPIC_API_KEY not set"); + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + { size_t n=strlen(api_key)+16; char* l=malloc(n); snprintf(l,n,"x-api-key: %s",api_key); h=curl_slist_append(h,l); free(l); } + { size_t n=strlen(LLM_VERSION)+32; char* l=malloc(n); snprintf(l,n,"anthropic-version: %s",LLM_VERSION); h=curl_slist_append(h,l); free(l); } + el_val_t resp = http_do("POST", LLM_API_URL, json_body, h); + curl_slist_free_all(h); + return resp; +} + +/* Extract concatenated assistant text from an Anthropic /v1/messages + * response. The response shape is: + * {"content":[{"type":"text","text":"..."}, ...], ...} + * If parsing fails, returns the raw response so the caller can inspect. + */ +static el_val_t llm_extract_text(el_val_t resp_val) { + const char* resp = EL_CSTR(resp_val); + if (!resp || !*resp) return el_wrap_str(el_strdup("")); + /* If error JSON, propagate as-is. */ + if (resp[0] == '{' && strstr(resp, "\"error\"")) { + return el_wrap_str(el_strdup(resp)); + } + /* Find "content":[ ... ] */ + const char* p = json_find_key(resp, "content"); + if (!p) return el_wrap_str(el_strdup(resp)); + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') return el_wrap_str(el_strdup(resp)); + p++; + JsonBuf out; jb_init(&out); + while (*p && *p != ']') { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p != '{') break; + const char* end = json_skip_value(p); + size_t n = (size_t)(end - p); + char* obj = malloc(n + 1); + memcpy(obj, p, n); obj[n] = '\0'; + const char* type_p = json_find_key(obj, "type"); + if (type_p && *type_p == '"') { + JsonParser jp = { .p = type_p, .end = type_p + strlen(type_p), .err = 0 }; + char* type_s = jp_parse_string_raw(&jp); + if (!jp.err && type_s && strcmp(type_s, "text") == 0) { + const char* tp = json_find_key(obj, "text"); + if (tp && *tp == '"') { + JsonParser jp2 = { .p = tp, .end = tp + strlen(tp), .err = 0 }; + char* text_s = jp_parse_string_raw(&jp2); + if (!jp2.err && text_s) jb_puts(&out, text_s); + free(text_s); + } + } + free(type_s); + } + free(obj); + p = end; + } + return el_wrap_str(out.buf); +} + +el_val_t llm_call(el_val_t model, el_val_t prompt) { + const char* u = EL_CSTR(prompt); if (!u) u = ""; + return llm_chain_call(NULL, u); +} + +el_val_t llm_call_system(el_val_t model, el_val_t system_prompt, el_val_t user_prompt) { + const char* s = EL_CSTR(system_prompt); if (!s) s = ""; + const char* u = EL_CSTR(user_prompt); if (!u) u = ""; + return llm_chain_call(s, u); +} + +/* ── Tool registry for llm_call_agentic ─────────────────────────────────── */ + +typedef el_val_t (*llm_tool_fn)(el_val_t input); + +typedef struct LlmToolEntry { + char* name; + llm_tool_fn fn; +} LlmToolEntry; + +static LlmToolEntry _llm_tools[64]; +static size_t _llm_tool_count = 0; +static pthread_mutex_t _llm_tool_mu = PTHREAD_MUTEX_INITIALIZER; + +static llm_tool_fn llm_tool_lookup(const char* name) { + if (!name) return NULL; + llm_tool_fn fn = NULL; + pthread_mutex_lock(&_llm_tool_mu); + for (size_t i = 0; i < _llm_tool_count; i++) { + if (strcmp(_llm_tools[i].name, name) == 0) { fn = _llm_tools[i].fn; break; } + } + pthread_mutex_unlock(&_llm_tool_mu); + return fn; +} + +void llm_register_tool(el_val_t name, el_val_t handler_fn_name) { + const char* nm = EL_CSTR(name); + const char* sym = EL_CSTR(handler_fn_name); + if (!nm || !*nm || !sym || !*sym) return; + void* p = dlsym(RTLD_DEFAULT, sym); + if (!p) { + fprintf(stderr, "[llm_register_tool] symbol not found: %s\n", sym); + return; + } + pthread_mutex_lock(&_llm_tool_mu); + /* Replace existing entry by name. */ + for (size_t i = 0; i < _llm_tool_count; i++) { + if (strcmp(_llm_tools[i].name, nm) == 0) { + _llm_tools[i].fn = (llm_tool_fn)p; + pthread_mutex_unlock(&_llm_tool_mu); + return; + } + } + if (_llm_tool_count < sizeof(_llm_tools) / sizeof(_llm_tools[0])) { + _llm_tools[_llm_tool_count].name = el_strdup(nm); + _llm_tools[_llm_tool_count].fn = (llm_tool_fn)p; + _llm_tool_count++; + } + pthread_mutex_unlock(&_llm_tool_mu); +} + +/* Serialize the El `tools` list into the JSON `tools:[...]` field expected + * by the Anthropic API. Each tool is an ElMap with name/description/ + * input_schema. input_schema is treated as either a JSON-object string + * (passed through verbatim) or a missing field (substitute {}). */ +static void llm_emit_tools_json(JsonBuf* b, el_val_t tools_list) { + jb_putc(b, '['); + ElList* lst = (ElList*)(uintptr_t)tools_list; + int64_t n = lst ? lst->length : 0; + for (int64_t i = 0; i < n; i++) { + if (i > 0) jb_putc(b, ','); + ElMap* tm = as_map(lst->elems[i]); + const char* name = ""; + const char* desc = ""; + const char* schema = "{}"; + if (tm) { + for (int64_t k = 0; k < tm->count; k++) { + const char* key = EL_CSTR(tm->keys[k]); + const char* val = EL_CSTR(tm->values[k]); + if (!key || !val) continue; + if (strcmp(key, "name") == 0) name = val; + else if (strcmp(key, "description") == 0) desc = val; + else if (strcmp(key, "input_schema") == 0) schema = val; + } + } + char* esc_name = json_escape_alloc(name); + char* esc_desc = json_escape_alloc(desc); + jb_puts(b, "{\"name\":\""); jb_puts(b, esc_name); + jb_puts(b, "\",\"description\":\""); jb_puts(b, esc_desc); + jb_puts(b, "\",\"input_schema\":"); jb_puts(b, schema && *schema ? schema : "{}"); + jb_putc(b, '}'); + free(esc_name); free(esc_desc); + } + jb_putc(b, ']'); +} + +/* Walk the assistant `content` array and emit each block back into b, + * preserving the verbatim JSON of every block — used to re-include the + * assistant turn in the next request. */ +static void llm_emit_content_blocks(JsonBuf* b, const char* resp) { + const char* p = json_find_key(resp, "content"); + jb_putc(b, '['); + if (!p) { jb_putc(b, ']'); return; } + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') { jb_putc(b, ']'); return; } + p++; + int first = 1; + while (*p && *p != ']') { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p != '{') break; + const char* end = json_skip_value(p); + if (!first) jb_putc(b, ','); + first = 0; + size_t n = (size_t)(end - p); + jb_reserve(b, n); + memcpy(b->buf + b->len, p, n); + b->len += n; + b->buf[b->len] = '\0'; + p = end; + } + jb_putc(b, ']'); +} + +/* Concatenate all "text" blocks from a response. Returns owned string. */ +static char* llm_concat_text_blocks(const char* resp) { + JsonBuf out; jb_init(&out); + if (!resp) return out.buf; + const char* p = json_find_key(resp, "content"); + if (!p) return out.buf; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') return out.buf; + p++; + while (*p && *p != ']') { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p != '{') break; + const char* end = json_skip_value(p); + size_t n = (size_t)(end - p); + char* obj = malloc(n + 1); + memcpy(obj, p, n); obj[n] = '\0'; + const char* tp = json_find_key(obj, "type"); + if (tp && *tp == '"') { + JsonParser jp = { .p = tp, .end = tp + strlen(tp), .err = 0 }; + char* tname = jp_parse_string_raw(&jp); + if (!jp.err && tname && strcmp(tname, "text") == 0) { + const char* xp = json_find_key(obj, "text"); + if (xp && *xp == '"') { + JsonParser jp2 = { .p = xp, .end = xp + strlen(xp), .err = 0 }; + char* txt = jp_parse_string_raw(&jp2); + if (!jp2.err && txt) jb_puts(&out, txt); + free(txt); + } + } + free(tname); + } + free(obj); + p = end; + } + return out.buf; +} + +/* Build tool_result message blocks for every tool_use in a response. + * Appends to `b` an array element for each tool_use; caller wraps. */ +static int llm_build_tool_results(JsonBuf* b, const char* resp) { + int any = 0; + const char* p = json_find_key(resp, "content"); + if (!p) return 0; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') return 0; + p++; + while (*p && *p != ']') { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p != '{') break; + const char* end = json_skip_value(p); + size_t n = (size_t)(end - p); + char* obj = malloc(n + 1); + memcpy(obj, p, n); obj[n] = '\0'; + + const char* tp = json_find_key(obj, "type"); + char* type_s = NULL; + if (tp && *tp == '"') { + JsonParser jp = { .p = tp, .end = tp + strlen(tp), .err = 0 }; + type_s = jp_parse_string_raw(&jp); + } + if (type_s && strcmp(type_s, "tool_use") == 0) { + /* Extract id, name, input. */ + char* id_s = NULL; char* name_s = NULL; + const char* idp = json_find_key(obj, "id"); + if (idp && *idp == '"') { + JsonParser jp = { .p = idp, .end = idp + strlen(idp), .err = 0 }; + id_s = jp_parse_string_raw(&jp); + } + const char* np = json_find_key(obj, "name"); + if (np && *np == '"') { + JsonParser jp = { .p = np, .end = np + strlen(np), .err = 0 }; + name_s = jp_parse_string_raw(&jp); + } + el_val_t input_raw = json_get_raw(EL_STR(obj), EL_STR("input")); + const char* input_s = EL_CSTR(input_raw); + if (!input_s || !*input_s) input_s = "{}"; + + llm_tool_fn fn = llm_tool_lookup(name_s ? name_s : ""); + char* result = NULL; + int is_error = 0; + if (!fn) { + size_t en = strlen(name_s ? name_s : "(null)") + 64; + result = malloc(en); + snprintf(result, en, "{\"error\":\"tool not registered: %s\"}", + name_s ? name_s : "(null)"); + is_error = 1; + } else { + el_val_t out = fn(EL_STR(input_s)); + const char* os = EL_CSTR(out); + result = el_strdup(os ? os : ""); + } + + if (any) jb_putc(b, ','); + char* esc_id = json_escape_alloc(id_s ? id_s : ""); + char* esc_res = json_escape_alloc(result ? result : ""); + jb_puts(b, "{\"type\":\"tool_result\",\"tool_use_id\":\""); + jb_puts(b, esc_id); + jb_puts(b, "\",\"content\":\""); + jb_puts(b, esc_res); + jb_puts(b, "\""); + if (is_error) jb_puts(b, ",\"is_error\":true"); + jb_putc(b, '}'); + free(esc_id); free(esc_res); free(result); + free(id_s); free(name_s); + any = 1; + } + free(type_s); + free(obj); + p = end; + } + return any; +} + +el_val_t llm_call_agentic(el_val_t model, el_val_t system, el_val_t user, el_val_t tools) { + /* Empty tools list → degrade to plain system call. */ + ElList* tl = (ElList*)(uintptr_t)tools; + if (!tl || tl->length == 0) { + return llm_call_system(model, system, user); + } + const char* m = llm_resolve_model(EL_CSTR(model)); + const char* sys_p = EL_CSTR(system); if (!sys_p) sys_p = ""; + const char* usr_p = EL_CSTR(user); if (!usr_p) usr_p = ""; + + /* Build the static parts: tools JSON and system prompt — these don't + * change across iterations. */ + JsonBuf tools_buf; jb_init(&tools_buf); + llm_emit_tools_json(&tools_buf, tools); + char* esc_sys = json_escape_alloc(sys_p); + + /* messages array, accumulated as a mutable JSON fragment (no surrounding + * brackets — emitted at request time). */ + JsonBuf msgs; jb_init(&msgs); + /* First user message. */ + char* esc_user = json_escape_alloc(usr_p); + jb_puts(&msgs, "{\"role\":\"user\",\"content\":\""); + jb_puts(&msgs, esc_user); + jb_puts(&msgs, "\"}"); + free(esc_user); + + char* last_text = el_strdup(""); + el_val_t final_out = 0; + int reached_cap = 1; + + for (int iter = 0; iter < 10; iter++) { + /* Build request body. */ + JsonBuf body; jb_init(&body); + jb_putc(&body, '{'); + jb_puts(&body, "\"model\":"); jb_emit_escaped(&body, m); + jb_puts(&body, ",\"max_tokens\":4096"); + if (*sys_p) { + jb_puts(&body, ",\"system\":\""); + jb_puts(&body, esc_sys); + jb_puts(&body, "\""); + } + jb_puts(&body, ",\"tools\":"); + jb_puts(&body, tools_buf.buf); + jb_puts(&body, ",\"messages\":["); + jb_puts(&body, msgs.buf); + jb_puts(&body, "]}"); + + el_val_t resp_v = llm_request(body.buf); + free(body.buf); + const char* resp = EL_CSTR(resp_v); + if (!resp || !*resp) { + final_out = http_error_json("empty response"); + reached_cap = 0; + break; + } + if (resp[0] == '{' && strstr(resp, "\"error\"") && + !json_find_key(resp, "content")) { + final_out = el_wrap_str(el_strdup(resp)); + reached_cap = 0; + break; + } + + /* Update last_text from this response. */ + free(last_text); + last_text = llm_concat_text_blocks(resp); + + /* Inspect stop_reason. */ + el_val_t sr_v = json_get_string(EL_STR(resp), EL_STR("stop_reason")); + const char* sr = EL_CSTR(sr_v); if (!sr) sr = ""; + + if (strcmp(sr, "end_turn") == 0) { + final_out = el_wrap_str(el_strdup(last_text)); + reached_cap = 0; + break; + } + if (strcmp(sr, "max_tokens") == 0) { + size_t ln = strlen(last_text) + 16; + char* out = malloc(ln); + snprintf(out, ln, "%s\n[truncated]", last_text); + final_out = el_wrap_str(out); + reached_cap = 0; + break; + } + if (strcmp(sr, "tool_use") != 0) { + /* Unexpected stop reason; return the text we have. */ + final_out = el_wrap_str(el_strdup(last_text)); + reached_cap = 0; + break; + } + + /* Append the assistant turn (raw content blocks) to messages. */ + JsonBuf ab; jb_init(&ab); + jb_puts(&ab, ",{\"role\":\"assistant\",\"content\":"); + llm_emit_content_blocks(&ab, resp); + jb_putc(&ab, '}'); + jb_puts(&msgs, ab.buf); + free(ab.buf); + + /* Build tool_result message. */ + JsonBuf tr; jb_init(&tr); + jb_puts(&tr, ",{\"role\":\"user\",\"content\":["); + int any = llm_build_tool_results(&tr, resp); + jb_puts(&tr, "]}"); + if (any) { + jb_puts(&msgs, tr.buf); + } + free(tr.buf); + } + + if (reached_cap) { + size_t ln = strlen(last_text) + 32; + char* out = malloc(ln); + snprintf(out, ln, "[loop_cap_reached]\n%s", last_text); + final_out = el_wrap_str(out); + } + free(last_text); + free(esc_sys); + free(tools_buf.buf); + free(msgs.buf); + return final_out; +} + +/* base64-encode arbitrary bytes (returns owned C string). + * Internal helper for llm_vision; the public crypto entry point that El + * programs call is `base64_encode(el_val_t)` defined in the crypto block + * at the end of this file. */ +static char* el_b64_encode_internal(const unsigned char* src, size_t n) { + static const char tbl[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + size_t out_len = 4 * ((n + 2) / 3); + char* out = malloc(out_len + 1); + if (!out) return NULL; + size_t o = 0; + for (size_t i = 0; i < n;) { + uint32_t v = 0; int got = 0; + v |= (uint32_t)src[i++] << 16; got++; + if (i < n) { v |= (uint32_t)src[i++] << 8; got++; } + if (i < n) { v |= (uint32_t)src[i++]; got++; } + out[o++] = tbl[(v >> 18) & 0x3f]; + out[o++] = tbl[(v >> 12) & 0x3f]; + out[o++] = (got > 1) ? tbl[(v >> 6) & 0x3f] : '='; + out[o++] = (got > 2) ? tbl[v & 0x3f] : '='; + } + out[o] = '\0'; + return out; +} + +el_val_t llm_vision(el_val_t model, el_val_t system, el_val_t prompt, el_val_t image_url_or_b64) { + const char* m = llm_resolve_model(EL_CSTR(model)); + const char* s = EL_CSTR(system); if (!s) s = ""; + const char* u = EL_CSTR(prompt); if (!u) u = ""; + const char* img = EL_CSTR(image_url_or_b64); if (!img) img = ""; + + /* Choose source mode */ + char* image_block = NULL; + if (strncasecmp(img, "http://", 7) == 0 || strncasecmp(img, "https://", 8) == 0) { + char* esc_url = json_escape_alloc(img); + size_t n = strlen(esc_url) + 128; + image_block = malloc(n); + snprintf(image_block, n, + "{\"type\":\"image\",\"source\":{\"type\":\"url\",\"url\":\"%s\"}}", + esc_url); + free(esc_url); + } else if (strncmp(img, "data:", 5) == 0) { + /* Inline data URL: split media-type and base64 */ + const char* semi = strchr(img + 5, ';'); + const char* comma = strchr(img + 5, ','); + char media[64] = "image/png"; + if (semi && comma && semi < comma) { + size_t ml = (size_t)(semi - (img + 5)); + if (ml >= sizeof(media)) ml = sizeof(media) - 1; + memcpy(media, img + 5, ml); media[ml] = '\0'; + } + const char* b64 = comma ? comma + 1 : ""; + char* esc_media = json_escape_alloc(media); + char* esc_b64 = json_escape_alloc(b64); + size_t n = strlen(esc_media) + strlen(esc_b64) + 192; + image_block = malloc(n); + snprintf(image_block, n, + "{\"type\":\"image\",\"source\":{\"type\":\"base64\"," + "\"media_type\":\"%s\",\"data\":\"%s\"}}", + esc_media, esc_b64); + free(esc_media); free(esc_b64); + } else if (*img) { + /* Treat as file path: read, base64-encode, attach. */ + FILE* f = fopen(img, "rb"); + if (!f) { + char err[256]; snprintf(err, sizeof(err), "cannot open image: %s", img); + return http_error_json(err); + } + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + if (sz <= 0) { fclose(f); return http_error_json("empty image file"); } + unsigned char* buf = malloc((size_t)sz); + if (!buf) { fclose(f); return http_error_json("oom"); } + size_t got = fread(buf, 1, (size_t)sz, f); + fclose(f); + char* b64 = el_b64_encode_internal(buf, got); + free(buf); + if (!b64) return http_error_json("base64 encode failed"); + const char* media = "image/png"; + size_t ilen = strlen(img); + if (ilen >= 4) { + if (strcasecmp(img + ilen - 4, ".jpg") == 0 || + (ilen >= 5 && strcasecmp(img + ilen - 5, ".jpeg") == 0)) media = "image/jpeg"; + else if (strcasecmp(img + ilen - 4, ".gif") == 0) media = "image/gif"; + else if (strcasecmp(img + ilen - 4, ".webp") == 0) media = "image/webp"; + } + char* esc_b64 = json_escape_alloc(b64); free(b64); + size_t n = strlen(esc_b64) + 192; + image_block = malloc(n); + snprintf(image_block, n, + "{\"type\":\"image\",\"source\":{\"type\":\"base64\"," + "\"media_type\":\"%s\",\"data\":\"%s\"}}", + media, esc_b64); + free(esc_b64); + } + + char* esc_sys = json_escape_alloc(s); + char* esc_user = json_escape_alloc(u); + JsonBuf b; jb_init(&b); + jb_putc(&b, '{'); + jb_puts(&b, "\"model\":"); jb_emit_escaped(&b, m); + jb_puts(&b, ",\"max_tokens\":4096"); + if (*s) { + jb_puts(&b, ",\"system\":\""); + jb_puts(&b, esc_sys); + jb_puts(&b, "\""); + } + jb_puts(&b, ",\"messages\":[{\"role\":\"user\",\"content\":["); + if (image_block) { + jb_puts(&b, image_block); + jb_putc(&b, ','); + } + jb_puts(&b, "{\"type\":\"text\",\"text\":\""); + jb_puts(&b, esc_user); + jb_puts(&b, "\"}]}]}"); + free(esc_sys); free(esc_user); free(image_block); + el_val_t resp = llm_request(b.buf); + free(b.buf); + return llm_extract_text(resp); +} + +el_val_t llm_models(void) { + el_val_t lst = el_list_empty(); + lst = el_list_append(lst, el_wrap_str(el_strdup("claude-sonnet-4-5"))); + lst = el_list_append(lst, el_wrap_str(el_strdup("claude-opus-4-7"))); + lst = el_list_append(lst, el_wrap_str(el_strdup("claude-haiku-4-5"))); + return lst; +} +#endif /* HAVE_CURL */ + +/* ── Native VM builtin aliases ────────────────────────────────────────────── + * El source files use native_* names (El VM builtins). + * When compiled to C, these map directly to el_* runtime functions. */ + +el_val_t native_list_get(el_val_t list, el_val_t index) { + return el_list_get(list, index); +} + +el_val_t native_list_len(el_val_t list) { + return el_list_len(list); +} + +el_val_t native_list_append(el_val_t list, el_val_t elem) { + return el_list_append(list, elem); +} + +el_val_t native_list_empty(void) { + return el_list_empty(); +} + +el_val_t native_list_clone(el_val_t list) { + return el_list_clone(list); +} + +el_val_t native_string_chars(el_val_t sv) { + const char* s = EL_CSTR(sv); + el_val_t result = el_list_empty(); + if (!s) return result; + while (*s) { + char buf[2]; + buf[0] = *s; + buf[1] = '\0'; + result = el_list_append(result, EL_STR(strdup(buf))); + s++; + } + return result; +} + +el_val_t native_int_to_str(el_val_t n) { + return int_to_str(n); +} + +/* ── Method-call shorthand aliases ────────────────────────────────────────── + * Short names that result from the method-call convention: + * myList.append(x) → append(myList, x) + * myList.len() → len(myList) + * myList.get(i) → get(myList, i) + * myMap.map_get(k) → map_get(myMap, k) + * myMap.map_set(k,v) → map_set(myMap, k, v) */ + +el_val_t append(el_val_t list, el_val_t elem) { return el_list_append(list, elem); } +el_val_t len(el_val_t list) { return el_list_len(list); } +el_val_t get(el_val_t list, el_val_t index) { return el_list_get(list, index); } +el_val_t map_get(el_val_t map, el_val_t key) { return el_map_get(map, key); } +el_val_t map_set(el_val_t map, el_val_t key, el_val_t value) { return el_map_set(map, key, value); } + +/* ── Crypto primitives ────────────────────────────────────────────────────── + * + * SHA-256 implementation adapted from Brad Conte's public-domain reference + * (https://github.com/B-Con/crypto-algorithms/blob/master/sha256.c, public + * domain per the project's LICENSE). HMAC follows RFC 2104. Base64 encoding + * follows RFC 4648; the URL-safe variant uses the alphabet from §5 of the + * RFC and omits padding (per JWT/JWS convention). + * + * Self-contained: no OpenSSL/libcrypto dependency. The runtime keeps its + * existing `-lcurl -lpthread -ldl -lm` link line. + * + * Binary outputs (sha256_bytes, hmac_sha256_bytes) tag their buffer with a + * magic header so base64_encode/base64url_encode can recover the exact byte + * length even when the payload contains embedded NULs. Plain C strings + * (without the header) fall back to strlen(), preserving the existing API + * shape for normal text inputs. */ + +/* Magic-header for length-tagged binary buffers. Layout: + * [ uint32_t magic = EL_MAGIC_BIN ][ uint32_t length ][ data... ][ \0 ] + * The returned el_val_t points at `data`, so consumers that strlen() it still + * get a sensible (though possibly truncated) view. el_bin_len() recovers the + * true length by sniffing the 8 bytes preceding the pointer. + * + * Magic value chosen with high MSB so it cannot collide with printable ASCII + * (the same discriminator pattern used by EL_MAGIC_LIST / EL_MAGIC_MAP). */ +#define EL_MAGIC_BIN 0xE1B17EAFu + +typedef struct { + uint32_t magic; + uint32_t length; +} el_bin_hdr_t; + +/* Allocate a length-tagged binary buffer; returns pointer to the data area. */ +static unsigned char* el_bin_alloc(size_t len) { + el_bin_hdr_t* hdr = (el_bin_hdr_t*)malloc(sizeof(el_bin_hdr_t) + len + 1); + if (!hdr) { fputs("el_runtime: out of memory (bin)\n", stderr); exit(1); } + hdr->magic = EL_MAGIC_BIN; + hdr->length = (uint32_t)len; + unsigned char* data = (unsigned char*)(hdr + 1); + data[len] = '\0'; /* keep NUL-terminated for accidental strlen calls */ + return data; +} + +/* Recover length from a possibly-tagged buffer. Returns 1 if tagged. */ +static int el_bin_lookup(const void* p, size_t* out_len) { + if (!p) { *out_len = 0; return 0; } + /* Avoid reading off the front of a page on tiny pointers (e.g. NULs + * passed in as int-cast values). 4096 is a safe lower bound on any + * platform we target. */ + if ((uintptr_t)p < 4096) return 0; + const el_bin_hdr_t* hdr = (const el_bin_hdr_t*)((const char*)p - sizeof(el_bin_hdr_t)); + if (hdr->magic != EL_MAGIC_BIN) return 0; + *out_len = hdr->length; + return 1; +} + +/* Effective input length: tagged length if present, else strlen. */ +static size_t el_input_len(const char* s) { + size_t n; + if (el_bin_lookup(s, &n)) return n; + return s ? strlen(s) : 0; +} + +/* ─── SHA-256 (Brad Conte / public domain) ──────────────────────────────── */ + +typedef struct { + unsigned char data[64]; + uint32_t datalen; + uint64_t bitlen; + uint32_t state[8]; +} el_sha256_ctx_t; + +static const uint32_t el_sha256_k[64] = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +}; + +#define EL_ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) +#define EL_CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) +#define EL_MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define EL_EP0(x) (EL_ROTR(x,2) ^ EL_ROTR(x,13) ^ EL_ROTR(x,22)) +#define EL_EP1(x) (EL_ROTR(x,6) ^ EL_ROTR(x,11) ^ EL_ROTR(x,25)) +#define EL_SIG0(x) (EL_ROTR(x,7) ^ EL_ROTR(x,18) ^ ((x) >> 3)) +#define EL_SIG1(x) (EL_ROTR(x,17) ^ EL_ROTR(x,19) ^ ((x) >> 10)) + +static void el_sha256_transform(el_sha256_ctx_t* ctx, const unsigned char* data) { + uint32_t a, b, c, d, e, f, g, h, t1, t2, m[64]; + int i, j; + for (i = 0, j = 0; i < 16; ++i, j += 4) { + m[i] = ((uint32_t)data[j] << 24) | ((uint32_t)data[j + 1] << 16) + | ((uint32_t)data[j + 2] << 8) | (uint32_t)data[j + 3]; + } + for (; i < 64; ++i) { + m[i] = EL_SIG1(m[i-2]) + m[i-7] + EL_SIG0(m[i-15]) + m[i-16]; + } + a = ctx->state[0]; b = ctx->state[1]; c = ctx->state[2]; d = ctx->state[3]; + e = ctx->state[4]; f = ctx->state[5]; g = ctx->state[6]; h = ctx->state[7]; + for (i = 0; i < 64; ++i) { + t1 = h + EL_EP1(e) + EL_CH(e,f,g) + el_sha256_k[i] + m[i]; + t2 = EL_EP0(a) + EL_MAJ(a,b,c); + h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2; + } + ctx->state[0] += a; ctx->state[1] += b; ctx->state[2] += c; ctx->state[3] += d; + ctx->state[4] += e; ctx->state[5] += f; ctx->state[6] += g; ctx->state[7] += h; +} + +static void el_sha256_init(el_sha256_ctx_t* ctx) { + ctx->datalen = 0; + ctx->bitlen = 0; + ctx->state[0] = 0x6a09e667; ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; ctx->state[7] = 0x5be0cd19; +} + +static void el_sha256_update(el_sha256_ctx_t* ctx, const unsigned char* data, size_t len) { + for (size_t i = 0; i < len; ++i) { + ctx->data[ctx->datalen++] = data[i]; + if (ctx->datalen == 64) { + el_sha256_transform(ctx, ctx->data); + ctx->bitlen += 512; + ctx->datalen = 0; + } + } +} + +static void el_sha256_final(el_sha256_ctx_t* ctx, unsigned char hash[32]) { + uint32_t i = ctx->datalen; + if (ctx->datalen < 56) { + ctx->data[i++] = 0x80; + while (i < 56) ctx->data[i++] = 0x00; + } else { + ctx->data[i++] = 0x80; + while (i < 64) ctx->data[i++] = 0x00; + el_sha256_transform(ctx, ctx->data); + memset(ctx->data, 0, 56); + } + ctx->bitlen += (uint64_t)ctx->datalen * 8; + ctx->data[63] = (unsigned char)( ctx->bitlen & 0xff); + ctx->data[62] = (unsigned char)((ctx->bitlen >> 8) & 0xff); + ctx->data[61] = (unsigned char)((ctx->bitlen >> 16) & 0xff); + ctx->data[60] = (unsigned char)((ctx->bitlen >> 24) & 0xff); + ctx->data[59] = (unsigned char)((ctx->bitlen >> 32) & 0xff); + ctx->data[58] = (unsigned char)((ctx->bitlen >> 40) & 0xff); + ctx->data[57] = (unsigned char)((ctx->bitlen >> 48) & 0xff); + ctx->data[56] = (unsigned char)((ctx->bitlen >> 56) & 0xff); + el_sha256_transform(ctx, ctx->data); + for (i = 0; i < 4; ++i) { + hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0xff; + hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0xff; + hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0xff; + hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0xff; + hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0xff; + hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0xff; + hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0xff; + hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0xff; + } +} + +static void el_sha256_oneshot(const unsigned char* data, size_t len, unsigned char out[32]) { + el_sha256_ctx_t c; + el_sha256_init(&c); + el_sha256_update(&c, data, len); + el_sha256_final(&c, out); +} + +/* ─── HMAC-SHA-256 (RFC 2104) ───────────────────────────────────────────── */ + +static void el_hmac_sha256(const unsigned char* key, size_t key_len, + const unsigned char* msg, size_t msg_len, + unsigned char out[32]) { + unsigned char k[64]; + unsigned char k_ipad[64]; + unsigned char k_opad[64]; + unsigned char inner[32]; + + if (key_len > 64) { + el_sha256_oneshot(key, key_len, k); + memset(k + 32, 0, 32); + } else { + memcpy(k, key, key_len); + memset(k + key_len, 0, 64 - key_len); + } + for (int i = 0; i < 64; ++i) { + k_ipad[i] = k[i] ^ 0x36; + k_opad[i] = k[i] ^ 0x5c; + } + { + el_sha256_ctx_t c; + el_sha256_init(&c); + el_sha256_update(&c, k_ipad, 64); + el_sha256_update(&c, msg, msg_len); + el_sha256_final(&c, inner); + } + { + el_sha256_ctx_t c; + el_sha256_init(&c); + el_sha256_update(&c, k_opad, 64); + el_sha256_update(&c, inner, 32); + el_sha256_final(&c, out); + } +} + +/* ─── Hex helper ────────────────────────────────────────────────────────── */ + +static el_val_t el_hex_encode(const unsigned char* data, size_t len) { + static const char digits[] = "0123456789abcdef"; + char* out = el_strbuf(len * 2); + for (size_t i = 0; i < len; ++i) { + out[i * 2] = digits[(data[i] >> 4) & 0xf]; + out[i * 2 + 1] = digits[ data[i] & 0xf]; + } + out[len * 2] = '\0'; + return el_wrap_str(out); +} + +/* ─── Base64 (RFC 4648) ─────────────────────────────────────────────────── */ + +static const char el_b64_std_alphabet[64] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char el_b64_url_alphabet[64] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + +el_val_t el_base64_encode_n(const unsigned char* data, size_t len, int url_safe) { + const char* alphabet = url_safe ? el_b64_url_alphabet : el_b64_std_alphabet; + /* Standard form is padded to multiple of 4; URL-safe omits padding. */ + size_t out_cap = ((len + 2) / 3) * 4 + 1; + char* out = el_strbuf(out_cap); + size_t i = 0, j = 0; + while (i + 3 <= len) { + uint32_t v = ((uint32_t)data[i] << 16) | ((uint32_t)data[i+1] << 8) | (uint32_t)data[i+2]; + out[j++] = alphabet[(v >> 18) & 0x3f]; + out[j++] = alphabet[(v >> 12) & 0x3f]; + out[j++] = alphabet[(v >> 6) & 0x3f]; + out[j++] = alphabet[ v & 0x3f]; + i += 3; + } + size_t rem = len - i; + if (rem == 1) { + uint32_t v = (uint32_t)data[i] << 16; + out[j++] = alphabet[(v >> 18) & 0x3f]; + out[j++] = alphabet[(v >> 12) & 0x3f]; + if (!url_safe) { out[j++] = '='; out[j++] = '='; } + } else if (rem == 2) { + uint32_t v = ((uint32_t)data[i] << 16) | ((uint32_t)data[i+1] << 8); + out[j++] = alphabet[(v >> 18) & 0x3f]; + out[j++] = alphabet[(v >> 12) & 0x3f]; + out[j++] = alphabet[(v >> 6) & 0x3f]; + if (!url_safe) { out[j++] = '='; } + } + out[j] = '\0'; + return el_wrap_str(out); +} + +/* Decode either alphabet — accepts both '+/' and '-_' transparently, and + * tolerates missing padding (which JWTs typically omit). Whitespace is + * skipped for robustness. Invalid characters cause the decode to stop and + * the partial result so far is returned. */ +static el_val_t el_base64_decode_any(const char* in) { + if (!in) { + unsigned char* empty = el_bin_alloc(0); + return EL_STR((char*)empty); + } + size_t in_len = strlen(in); + /* Worst case: 3 output bytes per 4 input chars, +1 NUL slack. */ + unsigned char* out = el_bin_alloc(((in_len + 3) / 4) * 3 + 1); + + int8_t lut[256]; + for (int i = 0; i < 256; ++i) lut[i] = -1; + for (int i = 0; i < 64; ++i) lut[(unsigned char)el_b64_std_alphabet[i]] = (int8_t)i; + /* Allow URL-safe characters too (so one decoder handles both forms). */ + lut[(unsigned char)'-'] = 62; + lut[(unsigned char)'_'] = 63; + + uint32_t buf = 0; + int bits = 0; + size_t o = 0; + for (size_t i = 0; i < in_len; ++i) { + unsigned char c = (unsigned char)in[i]; + if (c == '=' || c == '\r' || c == '\n' || c == ' ' || c == '\t') continue; + int8_t v = lut[c]; + if (v < 0) break; /* invalid char — stop */ + buf = (buf << 6) | (uint32_t)v; + bits += 6; + if (bits >= 8) { + bits -= 8; + out[o++] = (unsigned char)((buf >> bits) & 0xff); + } + } + /* Patch the length header to the actual decoded length. */ + el_bin_hdr_t* hdr = (el_bin_hdr_t*)((char*)out - sizeof(el_bin_hdr_t)); + hdr->length = (uint32_t)o; + out[o] = '\0'; + return EL_STR((char*)out); +} + +/* ─── Public crypto entry points ────────────────────────────────────────── */ + +el_val_t el_sha256_bytes_n(const unsigned char* data, size_t len) { + unsigned char* out = el_bin_alloc(32); + el_sha256_oneshot(data, len, out); + return EL_STR((char*)out); +} + +el_val_t sha256_hex(el_val_t input) { + const char* s = EL_CSTR(input); + size_t n = el_input_len(s); + unsigned char digest[32]; + el_sha256_oneshot((const unsigned char*)(s ? s : ""), n, digest); + return el_hex_encode(digest, 32); +} + +el_val_t sha256_bytes(el_val_t input) { + const char* s = EL_CSTR(input); + size_t n = el_input_len(s); + return el_sha256_bytes_n((const unsigned char*)(s ? s : ""), n); +} + +el_val_t hmac_sha256_hex(el_val_t key, el_val_t message) { + const char* k = EL_CSTR(key); + const char* m = EL_CSTR(message); + size_t kn = el_input_len(k); + size_t mn = el_input_len(m); + unsigned char mac[32]; + el_hmac_sha256((const unsigned char*)(k ? k : ""), kn, + (const unsigned char*)(m ? m : ""), mn, + mac); + return el_hex_encode(mac, 32); +} + +el_val_t hmac_sha256_bytes(el_val_t key, el_val_t message) { + const char* k = EL_CSTR(key); + const char* m = EL_CSTR(message); + size_t kn = el_input_len(k); + size_t mn = el_input_len(m); + unsigned char* out = el_bin_alloc(32); + el_hmac_sha256((const unsigned char*)(k ? k : ""), kn, + (const unsigned char*)(m ? m : ""), mn, + out); + return EL_STR((char*)out); +} + +el_val_t base64_encode(el_val_t input) { + const char* s = EL_CSTR(input); + size_t n = el_input_len(s); + return el_base64_encode_n((const unsigned char*)(s ? s : ""), n, /*url_safe=*/0); +} + +el_val_t base64url_encode(el_val_t input) { + const char* s = EL_CSTR(input); + size_t n = el_input_len(s); + return el_base64_encode_n((const unsigned char*)(s ? s : ""), n, /*url_safe=*/1); +} + +el_val_t base64_decode(el_val_t input) { + return el_base64_decode_any(EL_CSTR(input)); +} + +el_val_t base64url_decode(el_val_t input) { + return el_base64_decode_any(EL_CSTR(input)); +} + +/* ── Post-quantum cryptography (liboqs + OpenSSL) ─────────────────────────── + * + * Algorithm choices (per CNSA 2.0 / NIST PQ guidance, as of 2024): + * Signatures: CRYSTALS-Dilithium-3 (NIST security level 3, balanced) + * KEM: CRYSTALS-Kyber-768 (NIST security level 3) + * Hash: SHA3-256 (Keccak) (PQ-aware protocols favour SHA3 over SHA2) + * Hybrid: X25519 || Kyber-768, combined via HKDF-SHA256 + * + * Why hybrid: Kyber is new. X25519 has 20+ years of analysis. Hybridizing + * preserves classical security if Kyber falls to a future cryptanalytic + * advance, and preserves PQ security if X25519 falls to a quantum adversary. + * "Recordable now, decryptable later" already threatens long-lived classical + * key exchange — the only safe move for keys protecting durable doctrine + * (CGI lineage, KindredGrants, Principal-CGI covenants) is to encapsulate + * with PQ today, even if the classical leg is what the wire shows. + * + * Compile-time detection: when is unavailable the pq_* functions + * compile to stubs that return a JSON error envelope. SHA3-256 stays + * available regardless (it's implemented inline, no liboqs dep). This lets + * the runtime build cleanly on dev machines without liboqs while production + * gets the full PQ stack. */ + +/* ─── SHA3-256 (Keccak, FIPS 202) ──────────────────────────────────────────── + * Inline reference implementation. ~120 LoC, no external dependency. + * rate=1088 bits, capacity=512 bits, output=256 bits, padding=0x06. */ + +static const uint64_t el_keccak_rc[24] = { + 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, + 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, + 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, + 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, + 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, + 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, + 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, + 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL +}; + +static const unsigned el_keccak_rho[24] = { + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 +}; + +static const unsigned el_keccak_pi[24] = { + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 +}; + +#define EL_ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n)))) + +static void el_keccak_f1600(uint64_t s[25]) { + for (int round = 0; round < 24; ++round) { + uint64_t bc[5], t; + for (int i = 0; i < 5; ++i) + bc[i] = s[i] ^ s[i+5] ^ s[i+10] ^ s[i+15] ^ s[i+20]; + for (int i = 0; i < 5; ++i) { + t = bc[(i+4) % 5] ^ EL_ROTL64(bc[(i+1) % 5], 1); + for (int j = 0; j < 25; j += 5) s[j+i] ^= t; + } + t = s[1]; + for (int i = 0; i < 24; ++i) { + int j = el_keccak_pi[i]; + bc[0] = s[j]; + s[j] = EL_ROTL64(t, el_keccak_rho[i]); + t = bc[0]; + } + for (int j = 0; j < 25; j += 5) { + for (int i = 0; i < 5; ++i) bc[i] = s[j+i]; + for (int i = 0; i < 5; ++i) + s[j+i] = bc[i] ^ ((~bc[(i+1) % 5]) & bc[(i+2) % 5]); + } + s[0] ^= el_keccak_rc[round]; + } +} + +static void el_sha3_256_oneshot(const unsigned char* data, size_t len, + unsigned char out[32]) { + uint64_t st[25] = {0}; + unsigned char* sb = (unsigned char*)st; + const size_t rate = 136; /* 1088 bits / 8 */ + size_t i = 0; + while (len - i >= rate) { + for (size_t k = 0; k < rate; ++k) sb[k] ^= data[i + k]; + el_keccak_f1600(st); + i += rate; + } + size_t rem = len - i; + for (size_t k = 0; k < rem; ++k) sb[k] ^= data[i + k]; + sb[rem] ^= 0x06; /* SHA3 domain-separation byte */ + sb[rate - 1] ^= 0x80; /* final-block padding bit (high bit of last byte) */ + el_keccak_f1600(st); + memcpy(out, sb, 32); +} + +el_val_t sha3_256_hex(el_val_t input) { + const char* s = EL_CSTR(input); + size_t n = el_input_len(s); + unsigned char digest[32]; + el_sha3_256_oneshot((const unsigned char*)(s ? s : ""), n, digest); + return el_hex_encode(digest, 32); +} + +/* ─── Hex decode helper ───────────────────────────────────────────────────── + * Returns a length-tagged binary buffer (so embedded NULs survive); on + * odd-length / invalid input returns NULL with *out_len = 0. Caller is + * responsible for emitting the error envelope. */ + +static int el_hex_nibble(char c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + return -1; +} + +__attribute__((unused)) +static unsigned char* el_hex_decode(const char* s, size_t* out_len) { + *out_len = 0; + if (!s) return NULL; + size_t n = strlen(s); + if (n & 1) return NULL; + size_t blen = n / 2; + unsigned char* out = el_bin_alloc(blen); + for (size_t i = 0; i < blen; ++i) { + int hi = el_hex_nibble(s[i*2]); + int lo = el_hex_nibble(s[i*2 + 1]); + if (hi < 0 || lo < 0) return NULL; + out[i] = (unsigned char)((hi << 4) | lo); + } + *out_len = blen; + return out; +} + +/* JSON error envelope reused across all PQ entry points. */ +static el_val_t pq_error(const char* msg) { + return http_error_json(msg); +} + +#if __has_include() +#include +#define EL_HAVE_LIBOQS 1 +#else +#define EL_HAVE_LIBOQS 0 +#endif + +#if EL_HAVE_LIBOQS && __has_include() +#include +#define EL_HAVE_OPENSSL 1 +#else +#define EL_HAVE_OPENSSL 0 +#endif + +#if !EL_HAVE_LIBOQS + +/* ─── Stubs (liboqs unavailable) ─────────────────────────────────────────── + * Each entry point returns the same JSON error so callers can inspect a + * single canonical "missing primitive" string. pq_verify is the lone + * exception — verifying without liboqs simply means "not verified", so + * returning Bool false (0) keeps the type contract intact. */ + +#define EL_PQ_NO_LIB "liboqs not linked, post-quantum primitives unavailable" + +el_val_t pq_keygen_signature(void) { return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_sign(el_val_t sk, el_val_t msg) { (void)sk; (void)msg; return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_verify(el_val_t pk, el_val_t msg, el_val_t sig) { (void)pk; (void)msg; (void)sig; return EL_INT(0); } +el_val_t pq_kem_keygen(void) { return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_kem_encaps(el_val_t pk) { (void)pk; return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_kem_decaps(el_val_t sk, el_val_t ct) { (void)sk; (void)ct; return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_hybrid_keygen(void) { return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_hybrid_handshake(el_val_t pub) { (void)pub; return pq_error(EL_PQ_NO_LIB); } + +#else /* EL_HAVE_LIBOQS */ + +/* ─── Dilithium-3 / ML-DSA-65 signatures ──────────────────────────────── + * + * NIST FIPS 204 standardized CRYSTALS-Dilithium as ML-DSA. ML-DSA-65 is the + * FIPS form of what we historically called Dilithium-3 — same algorithm + * family, same security level, identical key/sig sizes, but with a couple + * of standardization-driven tweaks (e.g. domain separation in the message + * binding). liboqs 0.12+ exposes both names; 0.15+ retired the legacy + * "Dilithium" constants in favour of "ML-DSA". We prefer ML-DSA-65 if the + * header advertises it, fall back to Dilithium-3 otherwise. Anything + * already signed with the older constant remains verifiable against that + * same constant — callers should pin the algorithm via the OQS_SIG handle's + * method_name field if they need to interoperate with archival signatures. */ + +#if defined(OQS_SIG_alg_ml_dsa_65) +# define EL_DILITHIUM_ALG OQS_SIG_alg_ml_dsa_65 +#elif defined(OQS_SIG_alg_dilithium_3) +# define EL_DILITHIUM_ALG OQS_SIG_alg_dilithium_3 +#else +# define EL_DILITHIUM_ALG "ML-DSA-65" /* string fallback; runtime probe catches misconfig */ +#endif + +el_val_t pq_keygen_signature(void) { + OQS_SIG* sig = OQS_SIG_new(EL_DILITHIUM_ALG); + if (!sig) return pq_error("OQS_SIG_new(dilithium-3) failed"); + unsigned char* pk = (unsigned char*)malloc(sig->length_public_key); + unsigned char* sk = (unsigned char*)malloc(sig->length_secret_key); + if (!pk || !sk) { free(pk); free(sk); OQS_SIG_free(sig); return pq_error("oom"); } + if (OQS_SIG_keypair(sig, pk, sk) != OQS_SUCCESS) { + free(pk); free(sk); OQS_SIG_free(sig); + return pq_error("dilithium-3 keypair generation failed"); + } + el_val_t pk_hex = el_hex_encode(pk, sig->length_public_key); + el_val_t sk_hex = el_hex_encode(sk, sig->length_secret_key); + OQS_MEM_secure_free(sk, sig->length_secret_key); + free(pk); + + const char* pks = EL_CSTR(pk_hex); + const char* sks = EL_CSTR(sk_hex); + char* buf = el_strbuf(strlen(pks) + strlen(sks) + 64); + sprintf(buf, "{\"public_key\":\"%s\",\"secret_key\":\"%s\"}", pks, sks); + OQS_SIG_free(sig); + return el_wrap_str(buf); +} + +el_val_t pq_sign(el_val_t secret_key_hex, el_val_t message) { + size_t sk_len = 0; + unsigned char* sk = el_hex_decode(EL_CSTR(secret_key_hex), &sk_len); + if (!sk) return pq_error("invalid hex in secret_key"); + + OQS_SIG* sig = OQS_SIG_new(EL_DILITHIUM_ALG); + if (!sig) return pq_error("OQS_SIG_new(dilithium-3) failed"); + if (sk_len != sig->length_secret_key) { + OQS_SIG_free(sig); + return pq_error("secret_key length mismatch for dilithium-3"); + } + + const char* msg = EL_CSTR(message); + size_t msg_len = el_input_len(msg); + unsigned char* signature = (unsigned char*)malloc(sig->length_signature); + size_t signature_len = sig->length_signature; + if (!signature) { OQS_SIG_free(sig); return pq_error("oom"); } + + if (OQS_SIG_sign(sig, signature, &signature_len, + (const unsigned char*)(msg ? msg : ""), msg_len, sk) != OQS_SUCCESS) { + free(signature); OQS_SIG_free(sig); + return pq_error("dilithium-3 sign failed"); + } + el_val_t sig_hex = el_hex_encode(signature, signature_len); + free(signature); OQS_SIG_free(sig); + return sig_hex; +} + +el_val_t pq_verify(el_val_t public_key_hex, el_val_t message, el_val_t signature_hex) { + size_t pk_len = 0, sig_len = 0; + unsigned char* pk = el_hex_decode(EL_CSTR(public_key_hex), &pk_len); + unsigned char* signature = el_hex_decode(EL_CSTR(signature_hex), &sig_len); + if (!pk || !signature) return EL_INT(0); + + OQS_SIG* sig = OQS_SIG_new(EL_DILITHIUM_ALG); + if (!sig) return EL_INT(0); + if (pk_len != sig->length_public_key) { OQS_SIG_free(sig); return EL_INT(0); } + + const char* msg = EL_CSTR(message); + size_t msg_len = el_input_len(msg); + OQS_STATUS rc = OQS_SIG_verify(sig, + (const unsigned char*)(msg ? msg : ""), msg_len, + signature, sig_len, pk); + OQS_SIG_free(sig); + return (rc == OQS_SUCCESS) ? EL_INT(1) : EL_INT(0); +} + +/* ─── Kyber-768 / ML-KEM-768 KEM ──────────────────────────────────────── + * + * NIST FIPS 203 standardized CRYSTALS-Kyber as ML-KEM. ML-KEM-768 is the + * FIPS form of what we historically called Kyber-768. Same situation as + * Dilithium → ML-DSA: prefer the standardized constant, fall back to the + * legacy name. liboqs 0.15.0 still exposes OQS_KEM_alg_kyber_768; the + * algorithm is identical at the wire level to ML-KEM-768 except for FIPS + * domain-separation tweaks, so the two ciphertexts/keys are NOT + * cross-compatible. Pin the constant for archival material. */ + +#if defined(OQS_KEM_alg_ml_kem_768) +# define EL_KYBER_ALG OQS_KEM_alg_ml_kem_768 +#elif defined(OQS_KEM_alg_kyber_768) +# define EL_KYBER_ALG OQS_KEM_alg_kyber_768 +#else +# define EL_KYBER_ALG "ML-KEM-768" +#endif + +el_val_t pq_kem_keygen(void) { + OQS_KEM* kem = OQS_KEM_new(EL_KYBER_ALG); + if (!kem) return pq_error("OQS_KEM_new(kyber-768) failed"); + unsigned char* pk = (unsigned char*)malloc(kem->length_public_key); + unsigned char* sk = (unsigned char*)malloc(kem->length_secret_key); + if (!pk || !sk) { free(pk); free(sk); OQS_KEM_free(kem); return pq_error("oom"); } + if (OQS_KEM_keypair(kem, pk, sk) != OQS_SUCCESS) { + free(pk); free(sk); OQS_KEM_free(kem); + return pq_error("kyber-768 keypair generation failed"); + } + el_val_t pk_hex = el_hex_encode(pk, kem->length_public_key); + el_val_t sk_hex = el_hex_encode(sk, kem->length_secret_key); + OQS_MEM_secure_free(sk, kem->length_secret_key); + free(pk); + + const char* pks = EL_CSTR(pk_hex); + const char* sks = EL_CSTR(sk_hex); + char* buf = el_strbuf(strlen(pks) + strlen(sks) + 64); + sprintf(buf, "{\"public_key\":\"%s\",\"secret_key\":\"%s\"}", pks, sks); + OQS_KEM_free(kem); + return el_wrap_str(buf); +} + +el_val_t pq_kem_encaps(el_val_t public_key_hex) { + size_t pk_len = 0; + unsigned char* pk = el_hex_decode(EL_CSTR(public_key_hex), &pk_len); + if (!pk) return pq_error("invalid hex in public_key"); + + OQS_KEM* kem = OQS_KEM_new(EL_KYBER_ALG); + if (!kem) return pq_error("OQS_KEM_new(kyber-768) failed"); + if (pk_len != kem->length_public_key) { + OQS_KEM_free(kem); + return pq_error("public_key length mismatch for kyber-768"); + } + unsigned char* ct = (unsigned char*)malloc(kem->length_ciphertext); + unsigned char* ss = (unsigned char*)malloc(kem->length_shared_secret); + if (!ct || !ss) { free(ct); free(ss); OQS_KEM_free(kem); return pq_error("oom"); } + if (OQS_KEM_encaps(kem, ct, ss, pk) != OQS_SUCCESS) { + free(ct); free(ss); OQS_KEM_free(kem); + return pq_error("kyber-768 encapsulation failed"); + } + el_val_t ct_hex = el_hex_encode(ct, kem->length_ciphertext); + el_val_t ss_hex = el_hex_encode(ss, kem->length_shared_secret); + free(ct); + OQS_MEM_secure_free(ss, kem->length_shared_secret); + + const char* cts = EL_CSTR(ct_hex); + const char* sss = EL_CSTR(ss_hex); + char* buf = el_strbuf(strlen(cts) + strlen(sss) + 64); + sprintf(buf, "{\"ciphertext\":\"%s\",\"shared_secret\":\"%s\"}", cts, sss); + OQS_KEM_free(kem); + return el_wrap_str(buf); +} + +el_val_t pq_kem_decaps(el_val_t secret_key_hex, el_val_t ciphertext_hex) { + size_t sk_len = 0, ct_len = 0; + unsigned char* sk = el_hex_decode(EL_CSTR(secret_key_hex), &sk_len); + unsigned char* ct = el_hex_decode(EL_CSTR(ciphertext_hex), &ct_len); + if (!sk || !ct) return pq_error("invalid hex in inputs"); + + OQS_KEM* kem = OQS_KEM_new(EL_KYBER_ALG); + if (!kem) return pq_error("OQS_KEM_new(kyber-768) failed"); + if (sk_len != kem->length_secret_key || ct_len != kem->length_ciphertext) { + OQS_KEM_free(kem); + return pq_error("input length mismatch for kyber-768"); + } + unsigned char* ss = (unsigned char*)malloc(kem->length_shared_secret); + if (!ss) { OQS_KEM_free(kem); return pq_error("oom"); } + /* Kyber is IND-CCA via Fujisaki-Okamoto: decaps always returns *some* + * shared_secret even on tampered ciphertext (an implicit-rejection value + * derived from sk). Protocols MUST confirm the shared_secret matches via + * a subsequent step (e.g. AEAD tag, key-confirmation MAC) — do not + * assume decaps success implies authenticity. */ + if (OQS_KEM_decaps(kem, ss, ct, sk) != OQS_SUCCESS) { + free(ss); OQS_KEM_free(kem); + return pq_error("kyber-768 decapsulation failed"); + } + el_val_t ss_hex = el_hex_encode(ss, kem->length_shared_secret); + OQS_MEM_secure_free(ss, kem->length_shared_secret); + OQS_KEM_free(kem); + return ss_hex; +} + +/* ─── Hybrid handshake (X25519 + Kyber-768, HKDF-SHA256 combined) ─────── */ + +#if !EL_HAVE_OPENSSL + +el_val_t pq_hybrid_keygen(void) { + return pq_error("hybrid handshake requires OpenSSL (X25519); rebuild with -lcrypto"); +} +el_val_t pq_hybrid_handshake(el_val_t pub) { + (void)pub; + return pq_error("hybrid handshake requires OpenSSL (X25519); rebuild with -lcrypto"); +} + +#else /* EL_HAVE_OPENSSL */ + +/* HKDF-SHA256 (RFC 5869) — Extract+Expand. Reuses the inline HMAC-SHA256 + * already in this file. Empty salt → 32 zero bytes per the RFC. */ +static void el_hkdf_sha256(const unsigned char* salt, size_t salt_len, + const unsigned char* ikm, size_t ikm_len, + const unsigned char* info, size_t info_len, + unsigned char* out, size_t out_len) { + unsigned char zero_salt[32] = {0}; + if (salt_len == 0) { salt = zero_salt; salt_len = 32; } + unsigned char prk[32]; + el_hmac_sha256(salt, salt_len, ikm, ikm_len, prk); + + unsigned char t[32]; + size_t produced = 0; + unsigned char counter = 1; + unsigned char* buf = (unsigned char*)malloc(32 + info_len + 1); + if (!buf) { fputs("el_runtime: hkdf oom\n", stderr); return; } + while (produced < out_len) { + size_t off = 0; + if (counter > 1) { memcpy(buf, t, 32); off = 32; } + if (info && info_len) { memcpy(buf + off, info, info_len); off += info_len; } + buf[off++] = counter; + el_hmac_sha256(prk, 32, buf, off, t); + size_t chunk = (out_len - produced > 32) ? 32 : (out_len - produced); + memcpy(out + produced, t, chunk); + produced += chunk; + counter++; + } + free(buf); +} + +/* X25519 keygen via OpenSSL EVP. Returns 1 on success. + * Fills pk[32] and sk[32] (raw X25519 byte strings, no DER wrapper). */ +static int el_x25519_keygen(unsigned char pk[32], unsigned char sk[32]) { + EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL); + if (!pctx) return 0; + if (EVP_PKEY_keygen_init(pctx) != 1) { EVP_PKEY_CTX_free(pctx); return 0; } + EVP_PKEY* key = NULL; + if (EVP_PKEY_keygen(pctx, &key) != 1) { EVP_PKEY_CTX_free(pctx); return 0; } + EVP_PKEY_CTX_free(pctx); + + size_t plen = 32, slen = 32; + if (EVP_PKEY_get_raw_public_key (key, pk, &plen) != 1 || plen != 32) { + EVP_PKEY_free(key); return 0; + } + if (EVP_PKEY_get_raw_private_key(key, sk, &slen) != 1 || slen != 32) { + EVP_PKEY_free(key); return 0; + } + EVP_PKEY_free(key); + return 1; +} + +/* X25519 ECDH: derive 32-byte shared secret from local sk and remote pk. */ +static int el_x25519_derive(const unsigned char sk[32], const unsigned char rpk[32], + unsigned char ss[32]) { + EVP_PKEY* my = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, sk, 32); + EVP_PKEY* rem = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, NULL, rpk, 32); + if (!my || !rem) { EVP_PKEY_free(my); EVP_PKEY_free(rem); return 0; } + EVP_PKEY_CTX* dctx = EVP_PKEY_CTX_new(my, NULL); + if (!dctx) { EVP_PKEY_free(my); EVP_PKEY_free(rem); return 0; } + int ok = 0; + size_t out_len = 32; + if (EVP_PKEY_derive_init(dctx) == 1 && + EVP_PKEY_derive_set_peer(dctx, rem) == 1 && + EVP_PKEY_derive(dctx, ss, &out_len) == 1 && + out_len == 32) ok = 1; + EVP_PKEY_CTX_free(dctx); + EVP_PKEY_free(my); + EVP_PKEY_free(rem); + return ok; +} + +/* Hybrid wire layout (binary form, before hex encode): + * public_key = x25519_pub (32) || kyber_pub (1184) → 1216 bytes + * secret_key = x25519_sec (32) || kyber_sec (2400) → 2432 bytes + * ciphertext = ephem_x25519_pub (32) || kyber_ct (1088) → 1120 bytes + * shared_secret = HKDF-SHA256(x25519_ss || kyber_ss, info="el-pq-hybrid-v1", 32 bytes) + * The keygen result also exposes the four component hex fields for callers + * that prefer to handle the legs independently. */ + +el_val_t pq_hybrid_keygen(void) { + OQS_KEM* kem = OQS_KEM_new(EL_KYBER_ALG); + if (!kem) return pq_error("OQS_KEM_new(kyber-768) failed"); + + unsigned char xpk[32], xsk[32]; + if (!el_x25519_keygen(xpk, xsk)) { + OQS_KEM_free(kem); + return pq_error("X25519 keygen failed"); + } + + unsigned char* kpk = (unsigned char*)malloc(kem->length_public_key); + unsigned char* ksk = (unsigned char*)malloc(kem->length_secret_key); + if (!kpk || !ksk) { free(kpk); free(ksk); OQS_KEM_free(kem); return pq_error("oom"); } + if (OQS_KEM_keypair(kem, kpk, ksk) != OQS_SUCCESS) { + free(kpk); free(ksk); OQS_KEM_free(kem); + return pq_error("kyber-768 keypair generation failed"); + } + + size_t pub_len = 32 + kem->length_public_key; + size_t sec_len = 32 + kem->length_secret_key; + unsigned char* pub_buf = (unsigned char*)malloc(pub_len); + unsigned char* sec_buf = (unsigned char*)malloc(sec_len); + if (!pub_buf || !sec_buf) { + free(pub_buf); free(sec_buf); free(kpk); + OQS_MEM_secure_free(ksk, kem->length_secret_key); + OQS_KEM_free(kem); return pq_error("oom"); + } + memcpy(pub_buf, xpk, 32); memcpy(pub_buf + 32, kpk, kem->length_public_key); + memcpy(sec_buf, xsk, 32); memcpy(sec_buf + 32, ksk, kem->length_secret_key); + + el_val_t x_pub_hex = el_hex_encode(xpk, 32); + el_val_t x_sec_hex = el_hex_encode(xsk, 32); + el_val_t k_pub_hex = el_hex_encode(kpk, kem->length_public_key); + el_val_t k_sec_hex = el_hex_encode(ksk, kem->length_secret_key); + el_val_t pub_hex = el_hex_encode(pub_buf, pub_len); + el_val_t sec_hex = el_hex_encode(sec_buf, sec_len); + + OQS_MEM_secure_free(ksk, kem->length_secret_key); + free(kpk); free(pub_buf); free(sec_buf); + OQS_KEM_free(kem); + memset(xsk, 0, 32); /* best-effort wipe of stack copy */ + + const char* xph = EL_CSTR(x_pub_hex); + const char* xsh = EL_CSTR(x_sec_hex); + const char* kph = EL_CSTR(k_pub_hex); + const char* ksh = EL_CSTR(k_sec_hex); + const char* pubh = EL_CSTR(pub_hex); + const char* sech = EL_CSTR(sec_hex); + + char* buf = el_strbuf(strlen(xph) + strlen(xsh) + strlen(kph) + strlen(ksh) + + strlen(pubh) + strlen(sech) + 256); + sprintf(buf, + "{\"x25519_pub\":\"%s\",\"x25519_sec\":\"%s\"," + "\"kyber_pub\":\"%s\",\"kyber_sec\":\"%s\"," + "\"public_key\":\"%s\",\"secret_key\":\"%s\"}", + xph, xsh, kph, ksh, pubh, sech); + return el_wrap_str(buf); +} + +/* Initiator-side handshake. Caller supplies the responder's combined public + * key (x25519_pub || kyber_pub, hex-encoded). The runtime: + * 1. Generates an ephemeral X25519 keypair, runs ECDH against the + * responder's static x25519_pub. + * 2. Runs Kyber-768 encaps against the responder's kyber_pub → kyber_ct, + * kyber_ss. + * 3. Combined shared = HKDF-SHA256(salt="", ikm = x25519_ss || kyber_ss, + * info = "el-pq-hybrid-v1", L = 32). + * 4. Returns combined ciphertext (= ephemeral_x25519_pub || kyber_ct) and + * the derived shared_secret. + * + * Responder side composition (intentionally not a separate runtime fn — + * trivial to express in El given pq_kem_decaps + a future x25519_derive + * primitive): split the ciphertext into ephem_xpk (32) and kyber_ct, run + * X25519(static_xsk, ephem_xpk) and pq_kem_decaps(static_kyber_sk, kyber_ct), + * then HKDF-SHA256 with the same salt/info to recover the same shared_secret. + * If a separate x25519 entry point becomes valuable, add `pq_hybrid_open` + * here taking (secret_key_combined, ciphertext_combined). */ +el_val_t pq_hybrid_handshake(el_val_t remote_pub_combined) { + size_t pub_len = 0; + unsigned char* rpub = el_hex_decode(EL_CSTR(remote_pub_combined), &pub_len); + if (!rpub) return pq_error("invalid hex in remote_pub_combined"); + + OQS_KEM* kem = OQS_KEM_new(EL_KYBER_ALG); + if (!kem) return pq_error("OQS_KEM_new(kyber-768) failed"); + if (pub_len != 32 + kem->length_public_key) { + OQS_KEM_free(kem); + return pq_error("remote_pub_combined length mismatch (expected x25519_pub || kyber_pub)"); + } + + unsigned char e_xpk[32], e_xsk[32], x_ss[32]; + if (!el_x25519_keygen(e_xpk, e_xsk)) { + OQS_KEM_free(kem); + return pq_error("X25519 ephemeral keygen failed"); + } + if (!el_x25519_derive(e_xsk, rpub, x_ss)) { + memset(e_xsk, 0, 32); + OQS_KEM_free(kem); + return pq_error("X25519 derive failed"); + } + memset(e_xsk, 0, 32); /* ephemeral; not needed after derive */ + + unsigned char* k_ct = (unsigned char*)malloc(kem->length_ciphertext); + unsigned char* k_ss = (unsigned char*)malloc(kem->length_shared_secret); + if (!k_ct || !k_ss) { + free(k_ct); free(k_ss); OQS_KEM_free(kem); + return pq_error("oom"); + } + if (OQS_KEM_encaps(kem, k_ct, k_ss, rpub + 32) != OQS_SUCCESS) { + free(k_ct); free(k_ss); OQS_KEM_free(kem); + return pq_error("kyber-768 encapsulation failed"); + } + + /* HKDF combine: ikm = x_ss || k_ss. */ + size_t ikm_len = 32 + kem->length_shared_secret; + unsigned char* ikm = (unsigned char*)malloc(ikm_len); + if (!ikm) { + free(k_ct); OQS_MEM_secure_free(k_ss, kem->length_shared_secret); + OQS_KEM_free(kem); + return pq_error("oom"); + } + memcpy(ikm, x_ss, 32); + memcpy(ikm + 32, k_ss, kem->length_shared_secret); + unsigned char combined[32]; + static const char info_str[] = "el-pq-hybrid-v1"; + el_hkdf_sha256(NULL, 0, ikm, ikm_len, + (const unsigned char*)info_str, sizeof(info_str) - 1, + combined, 32); + + memset(x_ss, 0, 32); + OQS_MEM_secure_free(k_ss, kem->length_shared_secret); + OQS_MEM_secure_free(ikm, ikm_len); + + /* Combined ciphertext = ephemeral_x25519_pub || kyber_ct. */ + size_t ct_len = 32 + kem->length_ciphertext; + unsigned char* combined_ct = (unsigned char*)malloc(ct_len); + if (!combined_ct) { free(k_ct); OQS_KEM_free(kem); return pq_error("oom"); } + memcpy(combined_ct, e_xpk, 32); + memcpy(combined_ct + 32, k_ct, kem->length_ciphertext); + free(k_ct); + OQS_KEM_free(kem); + + el_val_t ct_hex = el_hex_encode(combined_ct, ct_len); + el_val_t ss_hex = el_hex_encode(combined, 32); + free(combined_ct); + memset(combined, 0, 32); + + const char* cts = EL_CSTR(ct_hex); + const char* sss = EL_CSTR(ss_hex); + char* buf = el_strbuf(strlen(cts) + strlen(sss) + 64); + sprintf(buf, "{\"ciphertext\":\"%s\",\"shared_secret\":\"%s\"}", cts, sss); + return el_wrap_str(buf); +} + +#endif /* EL_HAVE_OPENSSL */ +#endif /* EL_HAVE_LIBOQS */ + +/* ─── AEAD: AES-256-GCM ──────────────────────────────────────────────────── + * + * Symmetric authenticated encryption used to wrap envelopes once a shared + * secret has been derived from the KEM (Kyber-768 / hybrid). The El surface + * is intentionally narrow: + * + * aead_encrypt(key_hex, plaintext) + * → {"nonce":"<24 hex>","ciphertext":"<...hex including 16-byte tag>"} + * + * aead_decrypt(key_hex, nonce_hex, ciphertext_hex) + * → plaintext String, or "" on auth failure / malformed input + * + * Conventions: + * - key_hex must decode to exactly 32 bytes (AES-256). Callers that hold + * a longer KEM shared_secret should normalize via SHA3-256(ss) → 32 bytes + * before passing it in. (Kyber-768's shared_secret is already 32 bytes, + * but keeping this contract explicit lets the El side be agnostic.) + * - nonce is a fresh 12-byte random value drawn from the OS CSPRNG. Caller + * never picks the nonce — eliminates the GCM nonce-reuse footgun entirely. + * - tag is the standard 16 bytes, appended to ciphertext per RFC 5116. + * `ciphertext` field is therefore (plaintext_len + 16) bytes, hex-encoded. + * - No associated data (AAD). If we later need bound metadata, add a + * length-prefixed AAD argument and bump the envelope version tag. + * + * Failure mode: + * aead_encrypt returns http_error_json(...) on input/system failure. + * aead_decrypt returns the empty string on ANY failure (including auth-tag + * mismatch). Callers MUST check for "" before using the result. */ + +#if !__has_include() + +el_val_t aead_encrypt(el_val_t key_hex, el_val_t plaintext) { + (void)key_hex; (void)plaintext; + return http_error_json("aead_encrypt requires OpenSSL (libcrypto); rebuild with -lcrypto"); +} +el_val_t aead_decrypt(el_val_t key_hex, el_val_t nonce_hex, el_val_t ciphertext_hex) { + (void)key_hex; (void)nonce_hex; (void)ciphertext_hex; + return el_wrap_str(el_strdup("")); +} + +#else /* OpenSSL available */ + +#include +#include + +el_val_t aead_encrypt(el_val_t key_hex, el_val_t plaintext) { + size_t key_len = 0; + unsigned char* key = el_hex_decode(EL_CSTR(key_hex), &key_len); + if (!key) return http_error_json("invalid hex in key"); + if (key_len != 32) return http_error_json("aead key must be 32 bytes (64 hex chars) for AES-256-GCM"); + + const char* pt = EL_CSTR(plaintext); + size_t pt_len = el_input_len(pt); + if (!pt) pt = ""; + + unsigned char nonce[12]; + if (RAND_bytes(nonce, 12) != 1) return http_error_json("OS CSPRNG failed (RAND_bytes)"); + + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + if (!ctx) return http_error_json("EVP_CIPHER_CTX_new failed"); + + if (EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) != 1) { + EVP_CIPHER_CTX_free(ctx); return http_error_json("aes-256-gcm init failed"); + } + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL) != 1) { + EVP_CIPHER_CTX_free(ctx); return http_error_json("set ivlen failed"); + } + if (EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce) != 1) { + EVP_CIPHER_CTX_free(ctx); return http_error_json("aes-256-gcm key/iv init failed"); + } + + /* GCM ciphertext is the same length as plaintext; we append a 16-byte + * authentication tag for AEAD semantics. Allocate plaintext_len + 16. */ + unsigned char* ct = (unsigned char*)malloc(pt_len + 16); + if (!ct) { EVP_CIPHER_CTX_free(ctx); return http_error_json("oom"); } + int outlen = 0, total = 0; + if (EVP_EncryptUpdate(ctx, ct, &outlen, (const unsigned char*)pt, (int)pt_len) != 1) { + free(ct); EVP_CIPHER_CTX_free(ctx); return http_error_json("aes-256-gcm update failed"); + } + total += outlen; + if (EVP_EncryptFinal_ex(ctx, ct + total, &outlen) != 1) { + free(ct); EVP_CIPHER_CTX_free(ctx); return http_error_json("aes-256-gcm final failed"); + } + total += outlen; + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, ct + total) != 1) { + free(ct); EVP_CIPHER_CTX_free(ctx); return http_error_json("aes-256-gcm get tag failed"); + } + EVP_CIPHER_CTX_free(ctx); + + el_val_t nonce_hex_v = el_hex_encode(nonce, 12); + el_val_t ct_hex_v = el_hex_encode(ct, (size_t)total + 16); + free(ct); + + const char* nh = EL_CSTR(nonce_hex_v); + const char* ch = EL_CSTR(ct_hex_v); + char* buf = el_strbuf(strlen(nh) + strlen(ch) + 48); + sprintf(buf, "{\"nonce\":\"%s\",\"ciphertext\":\"%s\"}", nh, ch); + return el_wrap_str(buf); +} + +el_val_t aead_decrypt(el_val_t key_hex, el_val_t nonce_hex, el_val_t ciphertext_hex) { + size_t key_len = 0, nonce_len = 0, ct_len = 0; + unsigned char* key = el_hex_decode(EL_CSTR(key_hex), &key_len); + unsigned char* nonce = el_hex_decode(EL_CSTR(nonce_hex), &nonce_len); + unsigned char* ct = el_hex_decode(EL_CSTR(ciphertext_hex), &ct_len); + if (!key || !nonce || !ct) return el_wrap_str(el_strdup("")); + if (key_len != 32 || nonce_len != 12) return el_wrap_str(el_strdup("")); + if (ct_len < 16) return el_wrap_str(el_strdup("")); + + size_t body_len = ct_len - 16; + const unsigned char* tag = ct + body_len; + + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + if (!ctx) return el_wrap_str(el_strdup("")); + + if (EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) != 1 || + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL) != 1 || + EVP_DecryptInit_ex(ctx, NULL, NULL, key, nonce) != 1) { + EVP_CIPHER_CTX_free(ctx); return el_wrap_str(el_strdup("")); + } + + unsigned char* pt = (unsigned char*)malloc(body_len + 1); + if (!pt) { EVP_CIPHER_CTX_free(ctx); return el_wrap_str(el_strdup("")); } + int outlen = 0, total = 0; + if (EVP_DecryptUpdate(ctx, pt, &outlen, ct, (int)body_len) != 1) { + free(pt); EVP_CIPHER_CTX_free(ctx); return el_wrap_str(el_strdup("")); + } + total += outlen; + /* Set expected tag before final — GCM's final step is where auth happens. */ + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, (void*)tag) != 1) { + free(pt); EVP_CIPHER_CTX_free(ctx); return el_wrap_str(el_strdup("")); + } + int rc = EVP_DecryptFinal_ex(ctx, pt + total, &outlen); + EVP_CIPHER_CTX_free(ctx); + if (rc != 1) { + /* Auth failure or padding/length mismatch. Return empty so callers + * cannot accidentally treat tampered ciphertext as a valid message. */ + free(pt); + return el_wrap_str(el_strdup("")); + } + total += outlen; + pt[total] = '\0'; + + /* Copy into the el arena so the caller-visible string outlives this fn. */ + char* out = el_strbuf((size_t)total); + memcpy(out, pt, (size_t)total); + out[total] = '\0'; + free(pt); + return el_wrap_str(out); +} + +#endif /* __has_include() */ + +#ifdef HAVE_CURL +/* ──────────────────────────────────────────────────────────────────────────── + * OTLP/HTTP observability — logs, traces, metrics + * + * Design goals: + * - Zero blocking on the request path. Producers append to in-memory + * ring buffers; a single worker thread flushes to the OTLP endpoint. + * - Drop-on-failure semantics. If the endpoint is unreachable or slow, + * we drop telemetry rather than back-pressure into the request handler. + * - Best-effort serialization. Each record is pre-serialized as JSON when + * the El program calls the primitive; the worker just batches. + * - Configuration via env vars: + * OTLP_ENDPOINT e.g. https://alloy.neuralplatform.ai:4318 + * OTEL_SERVICE_NAME e.g. neuron-web (default: argv[0] basename) + * OTEL_SERVICE_VERSION (default: "0.0.0") + * OTEL_RESOURCE_ATTRS comma-sep k=v pairs (optional) + * + * Wire format: OTLP/HTTP JSON. Three endpoints: + * POST {endpoint}/v1/logs — log records + * POST {endpoint}/v1/traces — spans + * POST {endpoint}/v1/metrics — counter/gauge points + * + * El programs see four primitives: + * trace_span_start(name) -> SpanHandle (just a string id) + * trace_span_end(handle) (computes duration, queues) + * emit_log(level, msg, fields_json) (queues a log record) + * emit_metric(name, value, tags_json) (queues a counter increment) + * ──────────────────────────────────────────────────────────────────────────── + */ + +#define OTLP_BUF_CAP 4096 /* per-buffer ring size */ +#define OTLP_FLUSH_MS 2000 /* flush every 2s */ +#define OTLP_BATCH_MAX 200 /* up to 200 records per POST */ + +typedef struct { + char* data; /* malloc'd JSON fragment for this record */ +} OtlpRec; + +typedef struct { + OtlpRec ring[OTLP_BUF_CAP]; + size_t head; /* next write slot */ + size_t tail; /* next read slot */ + pthread_mutex_t mu; +} OtlpQueue; + +static OtlpQueue _otlp_logs = { .mu = PTHREAD_MUTEX_INITIALIZER }; +static OtlpQueue _otlp_traces = { .mu = PTHREAD_MUTEX_INITIALIZER }; +static OtlpQueue _otlp_metrics = { .mu = PTHREAD_MUTEX_INITIALIZER }; + +static char* _otlp_endpoint = NULL; /* e.g. https://alloy.neuralplatform.ai:4318 */ +static char* _otlp_service_name = NULL; +static char* _otlp_service_version = NULL; +static int _otlp_initialized = 0; +static pthread_t _otlp_worker_thread; + +/* enqueue — returns 1 if accepted, 0 if dropped (full buffer or no endpoint) */ +static int otlp_enqueue(OtlpQueue* q, const char* json) { + if (!_otlp_endpoint || !json) return 0; + pthread_mutex_lock(&q->mu); + size_t next_head = (q->head + 1) % OTLP_BUF_CAP; + if (next_head == q->tail) { + /* buffer full — drop oldest */ + free(q->ring[q->tail].data); + q->ring[q->tail].data = NULL; + q->tail = (q->tail + 1) % OTLP_BUF_CAP; + } + q->ring[q->head].data = strdup(json); + q->head = next_head; + pthread_mutex_unlock(&q->mu); + return 1; +} + +/* drain — copies up to OTLP_BATCH_MAX items into a comma-joined string, + * caller must free the result. Returns NULL if queue is empty. */ +static char* otlp_drain(OtlpQueue* q) { + pthread_mutex_lock(&q->mu); + if (q->head == q->tail) { pthread_mutex_unlock(&q->mu); return NULL; } + /* compute total length */ + size_t total = 0, count = 0; + size_t i = q->tail; + while (i != q->head && count < OTLP_BATCH_MAX) { + if (q->ring[i].data) total += strlen(q->ring[i].data) + 1; /* +1 for comma */ + i = (i + 1) % OTLP_BUF_CAP; + count++; + } + char* out = malloc(total + 4); + if (!out) { pthread_mutex_unlock(&q->mu); return NULL; } + out[0] = '\0'; + size_t off = 0; + i = q->tail; + count = 0; + while (i != q->head && count < OTLP_BATCH_MAX) { + if (q->ring[i].data) { + size_t l = strlen(q->ring[i].data); + if (off > 0) { out[off++] = ','; } + memcpy(out + off, q->ring[i].data, l); + off += l; + free(q->ring[i].data); + q->ring[i].data = NULL; + } + i = (i + 1) % OTLP_BUF_CAP; + count++; + } + out[off] = '\0'; + q->tail = i; + pthread_mutex_unlock(&q->mu); + return out; +} + +/* Build resource block once (service.name, service.version, host.name) */ +static char* otlp_resource_block(void) { + static char cached[1024]; + static int built = 0; + if (built) return cached; + char host[256] = "unknown"; + gethostname(host, sizeof(host) - 1); + snprintf(cached, sizeof(cached), + "{\"attributes\":[" + "{\"key\":\"service.name\",\"value\":{\"stringValue\":\"%s\"}}," + "{\"key\":\"service.version\",\"value\":{\"stringValue\":\"%s\"}}," + "{\"key\":\"host.name\",\"value\":{\"stringValue\":\"%s\"}}" + "]}", + _otlp_service_name ? _otlp_service_name : "el-app", + _otlp_service_version ? _otlp_service_version : "0.0.0", + host); + built = 1; + return cached; +} + +/* Best-effort POST. Drops on any error. */ +static void otlp_post(const char* path, const char* body) { + if (!_otlp_endpoint || !body || !*body) return; + char url[1024]; + snprintf(url, sizeof(url), "%s%s", _otlp_endpoint, path); + CURL* c = curl_easy_init(); + if (!c) return; + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, body); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)strlen(body)); + curl_easy_setopt(c, CURLOPT_HTTPHEADER, h); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, 3000L); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, NULL); /* discard response */ + curl_easy_perform(c); + curl_slist_free_all(h); + curl_easy_cleanup(c); +} + +/* Flush worker — runs forever until process exits */ +static void* otlp_worker(void* arg) { + (void)arg; + while (1) { + struct timespec ts = { OTLP_FLUSH_MS / 1000, (OTLP_FLUSH_MS % 1000) * 1000000L }; + nanosleep(&ts, NULL); + + char* logs = otlp_drain(&_otlp_logs); + if (logs && *logs) { + char body[OTLP_BUF_CAP * 8]; + int n = snprintf(body, sizeof(body), + "{\"resourceLogs\":[{\"resource\":%s," + "\"scopeLogs\":[{\"scope\":{\"name\":\"el-runtime\"}," + "\"logRecords\":[%s]}]}]}", + otlp_resource_block(), logs); + if (n > 0 && n < (int)sizeof(body)) otlp_post("/v1/logs", body); + } + free(logs); + + char* traces = otlp_drain(&_otlp_traces); + if (traces && *traces) { + char body[OTLP_BUF_CAP * 8]; + int n = snprintf(body, sizeof(body), + "{\"resourceSpans\":[{\"resource\":%s," + "\"scopeSpans\":[{\"scope\":{\"name\":\"el-runtime\"}," + "\"spans\":[%s]}]}]}", + otlp_resource_block(), traces); + if (n > 0 && n < (int)sizeof(body)) otlp_post("/v1/traces", body); + } + free(traces); + + char* metrics = otlp_drain(&_otlp_metrics); + if (metrics && *metrics) { + char body[OTLP_BUF_CAP * 8]; + int n = snprintf(body, sizeof(body), + "{\"resourceMetrics\":[{\"resource\":%s," + "\"scopeMetrics\":[{\"scope\":{\"name\":\"el-runtime\"}," + "\"metrics\":[%s]}]}]}", + otlp_resource_block(), metrics); + if (n > 0 && n < (int)sizeof(body)) otlp_post("/v1/metrics", body); + } + free(metrics); + } + return NULL; +} + +/* Initialize OTLP — called lazily on first emit. Idempotent. */ +static void otlp_lazy_init(void) { + if (_otlp_initialized) return; + static pthread_mutex_t once_mu = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock(&once_mu); + if (_otlp_initialized) { pthread_mutex_unlock(&once_mu); return; } + + const char* ep = getenv("OTLP_ENDPOINT"); + if (!ep || !*ep) { + _otlp_initialized = 1; + pthread_mutex_unlock(&once_mu); + return; + } + _otlp_endpoint = strdup(ep); + /* trim trailing slash */ + size_t l = strlen(_otlp_endpoint); + if (l > 0 && _otlp_endpoint[l - 1] == '/') _otlp_endpoint[l - 1] = '\0'; + + const char* svc = getenv("OTEL_SERVICE_NAME"); + _otlp_service_name = strdup(svc && *svc ? svc : "el-app"); + const char* ver = getenv("OTEL_SERVICE_VERSION"); + _otlp_service_version = strdup(ver && *ver ? ver : "0.0.0"); + + pthread_create(&_otlp_worker_thread, NULL, otlp_worker, NULL); + pthread_detach(_otlp_worker_thread); + _otlp_initialized = 1; + pthread_mutex_unlock(&once_mu); +} + +/* JSON-escape a string into out_buf. Returns chars written (excluding null). */ +static size_t otlp_json_escape(const char* in, char* out, size_t out_cap) { + size_t o = 0; + for (size_t i = 0; in[i] && o + 8 < out_cap; i++) { + unsigned char c = (unsigned char)in[i]; + if (c == '"') { out[o++] = '\\'; out[o++] = '"'; } + else if (c == '\\'){ out[o++] = '\\'; out[o++] = '\\'; } + else if (c == '\n'){ out[o++] = '\\'; out[o++] = 'n'; } + else if (c == '\r'){ out[o++] = '\\'; out[o++] = 'r'; } + else if (c == '\t'){ out[o++] = '\\'; out[o++] = 't'; } + else if (c < 0x20) { o += snprintf(out + o, out_cap - o, "\\u%04x", c); } + else { out[o++] = (char)c; } + } + out[o] = '\0'; + return o; +} + +/* ── Public El primitives ─────────────────────────────────────────────────── */ + +/* emit_log(level, msg, fields_json) — fields_json is a JSON object string or "" */ +el_val_t emit_log(el_val_t level_v, el_val_t msg_v, el_val_t fields_v) { + otlp_lazy_init(); + if (!_otlp_endpoint) return EL_INT(0); + const char* level = EL_CSTR(level_v); if (!level) level = "INFO"; + const char* msg = EL_CSTR(msg_v); if (!msg) msg = ""; + const char* fields = EL_CSTR(fields_v); if (!fields) fields = ""; + /* Map El level names to OTLP severity numbers */ + int sev_num = 9; /* INFO */ + if (strcmp(level, "TRACE") == 0) sev_num = 1; + else if (strcmp(level, "DEBUG") == 0) sev_num = 5; + else if (strcmp(level, "INFO") == 0) sev_num = 9; + else if (strcmp(level, "WARN") == 0 || strcmp(level, "WARNING") == 0) sev_num = 13; + else if (strcmp(level, "ERROR") == 0) sev_num = 17; + else if (strcmp(level, "FATAL") == 0) sev_num = 21; + char esc_msg[2048]; otlp_json_escape(msg, esc_msg, sizeof(esc_msg)); + /* unix nanos */ + struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); + long long now_nano = (long long)ts.tv_sec * 1000000000LL + ts.tv_nsec; + char rec[4096]; + int n = snprintf(rec, sizeof(rec), + "{\"timeUnixNano\":\"%lld\",\"severityNumber\":%d," + "\"severityText\":\"%s\"," + "\"body\":{\"stringValue\":\"%s\"}%s%s}", + now_nano, sev_num, level, esc_msg, + (fields && *fields) ? ",\"attributes\":" : "", + (fields && *fields) ? fields : ""); + if (n > 0 && n < (int)sizeof(rec)) otlp_enqueue(&_otlp_logs, rec); + return EL_INT(1); +} + +/* emit_metric(name, value, tags_json) — Sum (counter) data point. tags_json + * is a JSON array of {key, value} pairs or empty string. */ +el_val_t emit_metric(el_val_t name_v, el_val_t value_v, el_val_t tags_v) { + otlp_lazy_init(); + if (!_otlp_endpoint) return EL_INT(0); + const char* name = EL_CSTR(name_v); if (!name) name = "unknown"; + int64_t val = (int64_t)value_v; + const char* tags = EL_CSTR(tags_v); if (!tags) tags = ""; + char esc_name[256]; otlp_json_escape(name, esc_name, sizeof(esc_name)); + struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); + long long now_nano = (long long)ts.tv_sec * 1000000000LL + ts.tv_nsec; + char rec[4096]; + int n = snprintf(rec, sizeof(rec), + "{\"name\":\"%s\",\"sum\":{\"aggregationTemporality\":2,\"isMonotonic\":true," + "\"dataPoints\":[{\"asInt\":\"%lld\"," + "\"timeUnixNano\":\"%lld\"" + "%s%s}]}}", + esc_name, (long long)val, now_nano, + (tags && *tags) ? ",\"attributes\":" : "", + (tags && *tags) ? tags : ""); + if (n > 0 && n < (int)sizeof(rec)) otlp_enqueue(&_otlp_metrics, rec); + return EL_INT(1); +} + +/* trace_span_start(name) — returns a span handle (string of "traceid:spanid:start_nano:name") */ +el_val_t trace_span_start(el_val_t name_v) { + otlp_lazy_init(); + const char* name = EL_CSTR(name_v); if (!name) name = "span"; + /* generate 16-byte trace id and 8-byte span id */ + static _Thread_local int seeded = 0; + if (!seeded) { srand((unsigned int)(uintptr_t)pthread_self() ^ (unsigned int)time(NULL)); seeded = 1; } + char tid[33], sid[17]; + for (int i = 0; i < 32; i++) tid[i] = "0123456789abcdef"[rand() & 0xF]; + tid[32] = '\0'; + for (int i = 0; i < 16; i++) sid[i] = "0123456789abcdef"[rand() & 0xF]; + sid[16] = '\0'; + struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); + long long now_nano = (long long)ts.tv_sec * 1000000000LL + ts.tv_nsec; + char* handle = malloc(strlen(name) + 80); + if (!handle) return EL_STR(""); + sprintf(handle, "%s:%s:%lld:%s", tid, sid, now_nano, name); + el_arena_track(handle); + return EL_STR(handle); +} + +/* trace_span_end(handle) — emits the span with computed duration */ +el_val_t trace_span_end(el_val_t handle_v) { + otlp_lazy_init(); + if (!_otlp_endpoint) return EL_INT(0); + const char* h = EL_CSTR(handle_v); if (!h) return EL_INT(0); + /* parse "tid:sid:start_nano:name" */ + char tid[64], sid[32], rest[1024]; + long long start_nano = 0; + if (sscanf(h, "%63[^:]:%31[^:]:%lld:%1023[^\n]", tid, sid, &start_nano, rest) != 4) return EL_INT(0); + struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); + long long end_nano = (long long)ts.tv_sec * 1000000000LL + ts.tv_nsec; + char esc_name[1024]; otlp_json_escape(rest, esc_name, sizeof(esc_name)); + char rec[4096]; + int n = snprintf(rec, sizeof(rec), + "{\"traceId\":\"%s\",\"spanId\":\"%s\"," + "\"name\":\"%s\"," + "\"kind\":1," + "\"startTimeUnixNano\":\"%lld\"," + "\"endTimeUnixNano\":\"%lld\"," + "\"status\":{\"code\":1}}", + tid, sid, esc_name, start_nano, end_nano); + if (n > 0 && n < (int)sizeof(rec)) otlp_enqueue(&_otlp_traces, rec); + return EL_INT(1); +} + +/* Convenience: emit a one-shot timed event (emit start+end immediately). + * For El programs that want point events with duration baked in. */ +el_val_t emit_event(el_val_t name_v, el_val_t duration_ms_v) { + otlp_lazy_init(); + if (!_otlp_endpoint) return EL_INT(0); + const char* name = EL_CSTR(name_v); if (!name) name = "event"; + int64_t dur_ms = (int64_t)duration_ms_v; + el_val_t h = trace_span_start(EL_STR((char*)name)); + /* fudge start to be (now - duration) */ + (void)dur_ms; + return trace_span_end(h); +} + +#endif /* HAVE_CURL — OTLP */ + +/* ── Threading seed primitives ─────────────────────────────────────────────── + * __thread_create(fn_name, arg) -> Int spawn El fn in a pthread, return tid + * __thread_join(tid) -> String join thread, return result string + * __mutex_new() -> Int allocate a mutex, return handle + * __mutex_lock(m) lock mutex m + * __mutex_unlock(m) unlock mutex m + * + * Every El fn compiles to a global C symbol. __thread_create uses dlsym to + * look up the function by name and run it in a pthread. This means any El fn + * with signature (String) -> String is directly threadable. + */ + +typedef el_val_t (*ElFn1)(el_val_t); + +typedef struct { + ElFn1 fn; + el_val_t arg; + el_val_t result; +} ElThreadArg; + +#define EL_THREAD_MAX 256 + +typedef struct { + pthread_t tid; + ElThreadArg* arg; + int alive; +} ElThread; + +static ElThread _threads[EL_THREAD_MAX]; +static int _thread_count = 0; +static pthread_mutex_t _thread_alloc_mu = PTHREAD_MUTEX_INITIALIZER; + +static void* el_thread_runner(void* raw) { + ElThreadArg* a = (ElThreadArg*)raw; + a->result = a->fn(a->arg); + return NULL; +} + +el_val_t __thread_create(el_val_t fn_name_v, el_val_t arg_v) { + const char* sym = EL_CSTR(fn_name_v); + if (!sym || !*sym) return EL_INT(-1); + void* p = dlsym(RTLD_DEFAULT, sym); + if (!p) { + fprintf(stderr, "[__thread_create] symbol not found: %s\n", sym); + return EL_INT(-1); + } + ElThreadArg* a = (ElThreadArg*)malloc(sizeof(ElThreadArg)); + if (!a) return EL_INT(-1); + a->fn = (ElFn1)p; + a->arg = arg_v; + a->result = EL_STR(""); + + pthread_mutex_lock(&_thread_alloc_mu); + if (_thread_count >= EL_THREAD_MAX) { + pthread_mutex_unlock(&_thread_alloc_mu); + free(a); + fprintf(stderr, "[__thread_create] thread table full\n"); + return EL_INT(-1); + } + int slot = _thread_count++; + _threads[slot].arg = a; + _threads[slot].alive = 1; + pthread_mutex_unlock(&_thread_alloc_mu); + + if (pthread_create(&_threads[slot].tid, NULL, el_thread_runner, a) != 0) { + pthread_mutex_lock(&_thread_alloc_mu); + _thread_count--; + pthread_mutex_unlock(&_thread_alloc_mu); + free(a); + return EL_INT(-1); + } + return EL_INT(slot); +} + +el_val_t __thread_join(el_val_t tid_v) { + int slot = (int)(int64_t)tid_v; + if (slot < 0 || slot >= EL_THREAD_MAX) return EL_STR(""); + pthread_join(_threads[slot].tid, NULL); + el_val_t result = _threads[slot].arg->result; + free(_threads[slot].arg); + _threads[slot].alive = 0; + return result; +} + +/* Mutex table */ + +#define EL_MUTEX_MAX 64 + +typedef struct { + pthread_mutex_t mu; + int allocated; +} ElMutexEntry; + +static ElMutexEntry _mutexes[EL_MUTEX_MAX]; +static int _mutex_count = 0; +static pthread_mutex_t _mutex_alloc_mu = PTHREAD_MUTEX_INITIALIZER; + +el_val_t __mutex_new(void) { + pthread_mutex_lock(&_mutex_alloc_mu); + if (_mutex_count >= EL_MUTEX_MAX) { + pthread_mutex_unlock(&_mutex_alloc_mu); + fprintf(stderr, "[__mutex_new] mutex table full\n"); + return EL_INT(-1); + } + int slot = _mutex_count++; + pthread_mutex_init(&_mutexes[slot].mu, NULL); + _mutexes[slot].allocated = 1; + pthread_mutex_unlock(&_mutex_alloc_mu); + return EL_INT(slot); +} + +void __mutex_lock(el_val_t m_v) { + int slot = (int)(int64_t)m_v; + if (slot < 0 || slot >= EL_MUTEX_MAX || !_mutexes[slot].allocated) return; + pthread_mutex_lock(&_mutexes[slot].mu); +} + +void __mutex_unlock(el_val_t m_v) { + int slot = (int)(int64_t)m_v; + if (slot < 0 || slot >= EL_MUTEX_MAX || !_mutexes[slot].allocated) return; + pthread_mutex_unlock(&_mutexes[slot].mu); +} + +/* ── Channels ─────────────────────────────────────────────────────────────── * + * Buffered MPMC channel backed by a mutex + condvar + circular buffer. + * channel_new(capacity) -> Int (handle) + * channel_send(ch, msg) — blocks if full (capacity > 0) or never (unbounded) + * channel_recv(ch) -> String — blocks until a message is available + * channel_try_recv(ch) -> String — non-blocking, returns "" if empty + * channel_close(ch) — signal no more sends; recv drains remaining + * + * Bounded channels (cap > 0): circular buffer, sender blocks when full. + * Unbounded channels (cap == 0): dynamic array, sender never blocks. + */ +#define EL_CHANNEL_MAX 64 +#define EL_CHANNEL_BUF 1024 + +typedef struct { + char** buf; + int cap; /* 0 = unbounded (grows dynamically) */ + int head, tail, count; + int dyn_cap; /* allocated slots for unbounded mode */ + int closed; + pthread_mutex_t mu; + pthread_cond_t not_empty; + pthread_cond_t not_full; +} ElChannel; + +static ElChannel _channels[EL_CHANNEL_MAX]; +static int _channel_count = 0; +static pthread_mutex_t _channel_alloc_mu = PTHREAD_MUTEX_INITIALIZER; + +el_val_t __channel_new(el_val_t capacity_v) { + int cap = (int)(int64_t)capacity_v; + if (cap < 0) cap = 0; + + pthread_mutex_lock(&_channel_alloc_mu); + if (_channel_count >= EL_CHANNEL_MAX) { + pthread_mutex_unlock(&_channel_alloc_mu); + fprintf(stderr, "[__channel_new] channel table full\n"); + return EL_INT(-1); + } + int slot = _channel_count++; + pthread_mutex_unlock(&_channel_alloc_mu); + + ElChannel* ch = &_channels[slot]; + memset(ch, 0, sizeof(*ch)); + ch->cap = cap; + ch->closed = 0; + ch->head = 0; + ch->tail = 0; + ch->count = 0; + + if (cap > 0) { + /* Bounded: fixed circular buffer. */ + ch->buf = (char**)malloc((size_t)cap * sizeof(char*)); + ch->dyn_cap = cap; + } else { + /* Unbounded: start with EL_CHANNEL_BUF slots, grow as needed. */ + ch->buf = (char**)malloc(EL_CHANNEL_BUF * sizeof(char*)); + ch->dyn_cap = EL_CHANNEL_BUF; + } + if (!ch->buf) { + fprintf(stderr, "[__channel_new] out of memory\n"); + return EL_INT(-1); + } + + pthread_mutex_init(&ch->mu, NULL); + pthread_cond_init(&ch->not_empty, NULL); + pthread_cond_init(&ch->not_full, NULL); + + return EL_INT(slot); +} + +void __channel_send(el_val_t ch_v, el_val_t msg_v) { + int slot = (int)(int64_t)ch_v; + if (slot < 0 || slot >= EL_CHANNEL_MAX) return; + ElChannel* ch = &_channels[slot]; + + const char* msg = EL_CSTR(msg_v); + if (!msg) msg = ""; + char* copy = strdup(msg); /* channel owns the string */ + + pthread_mutex_lock(&ch->mu); + + if (ch->closed) { + /* Send on closed channel is a no-op (drop the message). */ + pthread_mutex_unlock(&ch->mu); + free(copy); + return; + } + + if (ch->cap > 0) { + /* Bounded: block while full. */ + while (ch->count >= ch->cap && !ch->closed) { + pthread_cond_wait(&ch->not_full, &ch->mu); + } + if (ch->closed) { + pthread_mutex_unlock(&ch->mu); + free(copy); + return; + } + ch->buf[ch->tail] = copy; + ch->tail = (ch->tail + 1) % ch->cap; + ch->count++; + } else { + /* Unbounded: grow the buffer if needed. */ + if (ch->count >= ch->dyn_cap) { + int new_cap = ch->dyn_cap * 2; + char** grown = (char**)realloc(ch->buf, (size_t)new_cap * sizeof(char*)); + if (!grown) { + pthread_mutex_unlock(&ch->mu); + free(copy); + fprintf(stderr, "[__channel_send] out of memory growing channel\n"); + return; + } + /* The circular buffer may have wrapped. Linearise it first. + * In unbounded mode head is always 0 (we append at tail, drain + * from head), so a simple memmove isn't needed — but if the + * buffer did wrap (tail < head after growth), we need to fix up. + * Simplest safe path: if tail wrapped, move the head..old_cap + * segment to new_cap..new_cap+(old_cap-head). */ + if (ch->tail < ch->head) { + /* Wrapped: [head..old_cap) is the front, [0..tail) is the back. */ + int front = ch->dyn_cap - ch->head; + memmove(grown + ch->dyn_cap, grown + ch->head, (size_t)front * sizeof(char*)); + ch->head = ch->dyn_cap; + } + ch->buf = grown; + ch->dyn_cap = new_cap; + } + ch->buf[ch->tail] = copy; + ch->tail = (ch->tail + 1) % ch->dyn_cap; + ch->count++; + } + + pthread_cond_signal(&ch->not_empty); + pthread_mutex_unlock(&ch->mu); +} + +el_val_t __channel_recv(el_val_t ch_v) { + int slot = (int)(int64_t)ch_v; + if (slot < 0 || slot >= EL_CHANNEL_MAX) return EL_STR(""); + ElChannel* ch = &_channels[slot]; + + pthread_mutex_lock(&ch->mu); + + /* Block until there is a message or the channel is closed and drained. */ + while (ch->count == 0 && !ch->closed) { + pthread_cond_wait(&ch->not_empty, &ch->mu); + } + + if (ch->count == 0) { + /* Closed and empty — signal EOF. */ + pthread_mutex_unlock(&ch->mu); + return EL_STR(""); + } + + int buf_cap = (ch->cap > 0) ? ch->cap : ch->dyn_cap; + char* msg = ch->buf[ch->head]; + ch->head = (ch->head + 1) % buf_cap; + ch->count--; + + pthread_cond_signal(&ch->not_full); + pthread_mutex_unlock(&ch->mu); + + /* Hand the string to the arena so it is freed after the request. */ + el_arena_track(msg); + return EL_STR(msg); +} + +el_val_t __channel_try_recv(el_val_t ch_v) { + int slot = (int)(int64_t)ch_v; + if (slot < 0 || slot >= EL_CHANNEL_MAX) return EL_STR(""); + ElChannel* ch = &_channels[slot]; + + pthread_mutex_lock(&ch->mu); + + if (ch->count == 0) { + pthread_mutex_unlock(&ch->mu); + return EL_STR(""); + } + + int buf_cap = (ch->cap > 0) ? ch->cap : ch->dyn_cap; + char* msg = ch->buf[ch->head]; + ch->head = (ch->head + 1) % buf_cap; + ch->count--; + + pthread_cond_signal(&ch->not_full); + pthread_mutex_unlock(&ch->mu); + + el_arena_track(msg); + return EL_STR(msg); +} + +void __channel_close(el_val_t ch_v) { + int slot = (int)(int64_t)ch_v; + if (slot < 0 || slot >= EL_CHANNEL_MAX) return; + ElChannel* ch = &_channels[slot]; + + pthread_mutex_lock(&ch->mu); + ch->closed = 1; + /* Wake all blocked recvers and senders so they can observe the close. */ + pthread_cond_broadcast(&ch->not_empty); + pthread_cond_broadcast(&ch->not_full); + pthread_mutex_unlock(&ch->mu); +} + +/* ── DHARMA runtime additions ──────────────────────────────────────────────── + * + * Functions required by the dharma registry service. Added here so the + * released el_runtime.c includes them without requiring dharma to bundle + * its own stubs. + * + * Functions added: + * list_len — alias for el_list_len (used in handlers.el) + * list_get — alias for el_list_get (used in handlers.el) + * json_array_push — append a pre-encoded JSON element to a JSON array string + * now_millis — milliseconds since Unix epoch (alias for time_now) + * unix_timestamp_ms — same as now_millis (alias) + * time_now_ms — same as now_millis (alias) + * log_info — stderr structured log at INFO level + * log_warn — stderr structured log at WARN level + * config — reads a config value from the environment + * http_patch — HTTP PATCH with JSON Content-Type + * http_post_engram — HTTP POST with optional X-API-Key header + * http_get_engram — HTTP GET with optional X-API-Key header + * str_to_bytes — encode a string as a JSON array of byte values + * bytes_to_str — decode a JSON array of byte values back to a string + * hash_sha256 — SHA-256 hex digest of a string + */ + +/* list_len — return the number of elements in a list. */ +el_val_t list_len(el_val_t list) { + return el_list_len(list); +} + +/* list_get — return the element at index i in a list. */ +el_val_t list_get(el_val_t list, el_val_t index) { + return el_list_get(list, index); +} + +/* json_array_push — append element (a pre-encoded JSON fragment, e.g. "\"foo\"" + * or "42") to the JSON array string arr. Returns a new JSON array string. + * Example: json_array_push("[]", "\"alice\"") -> "[\"alice\"]" + * json_array_push("[\"alice\"]", "\"bob\"") -> "[\"alice\",\"bob\"]" */ +el_val_t json_array_push(el_val_t arr_v, el_val_t elem_v) { + const char* arr = EL_CSTR(arr_v); + const char* elem = EL_CSTR(elem_v); + if (!arr || !*arr) arr = "[]"; + if (!elem || !*elem) elem = "null"; + + /* Trim whitespace, find the closing ']'. */ + const char* p = arr; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') { + /* Not an array — return a single-element array. */ + size_t n = strlen(elem) + 4; + char* out = el_strbuf(n); + snprintf(out, n, "[%s]", elem); + return el_wrap_str(out); + } + size_t arr_len = strlen(arr); + size_t elem_len = strlen(elem); + + /* Walk from the end to find the matching ']'. */ + const char* end = arr + arr_len - 1; + while (end > p && (*end == ' ' || *end == '\t' || *end == '\n' || *end == '\r')) end--; + if (*end != ']') { + /* Malformed — wrap elem in a new array. */ + size_t n = elem_len + 4; + char* out = el_strbuf(n); + snprintf(out, n, "[%s]", elem); + return el_wrap_str(out); + } + + /* Content between '[' and ']'. */ + const char* inner_start = p + 1; + const char* inner_end = end; /* points AT ']' */ + /* Check if the array is empty (only whitespace between brackets). */ + const char* q = inner_start; + while (q < inner_end && (*q == ' ' || *q == '\t' || *q == '\n' || *q == '\r')) q++; + int empty = (q == inner_end); + + /* Build: prefix + (comma if non-empty) + elem + "]" */ + size_t prefix_len = (size_t)(inner_end - arr); /* up to but not including ']' */ + size_t sep_len = empty ? 0 : 1; /* "," if non-empty */ + size_t out_len = prefix_len + sep_len + elem_len + 2; /* +"]" + NUL */ + char* out = el_strbuf(out_len); + memcpy(out, arr, prefix_len); + if (!empty) out[prefix_len] = ','; + memcpy(out + prefix_len + sep_len, elem, elem_len); + out[prefix_len + sep_len + elem_len] = ']'; + out[prefix_len + sep_len + elem_len + 1] = '\0'; + return el_wrap_str(out); +} + +/* now_millis — milliseconds since Unix epoch. */ +el_val_t now_millis(void) { + return time_now(); +} + +/* unix_timestamp_ms — same as now_millis. */ +el_val_t unix_timestamp_ms(void) { + return time_now(); +} + +/* time_now_ms — same as now_millis. */ +el_val_t time_now_ms(void) { + return time_now(); +} + +/* log_info — write a structured [INFO] line to stderr. */ +void log_info(el_val_t msg_v) { + const char* msg = EL_CSTR(msg_v); + fprintf(stderr, "[INFO] %s\n", msg ? msg : ""); +} + +/* log_warn — write a structured [WARN] line to stderr. */ +void log_warn(el_val_t msg_v) { + const char* msg = EL_CSTR(msg_v); + fprintf(stderr, "[WARN] %s\n", msg ? msg : ""); +} + +/* config — read a configuration value from the environment. + * Returns "" if the variable is not set (same as __env_get). */ +el_val_t config(el_val_t key_v) { + const char* key = EL_CSTR(key_v); + if (!key || !*key) return EL_STR(""); + const char* val = getenv(key); + if (!val) return EL_STR(""); + return el_wrap_str(el_strdup(val)); +} + +#ifdef HAVE_CURL +/* http_patch — HTTP PATCH request with Content-Type: application/json. + * Returns the response body (same error convention as http_post_json). */ +el_val_t http_patch(el_val_t url_v, el_val_t body_v) { + const char* url = EL_CSTR(url_v); + const char* body = EL_CSTR(body_v); + if (!url || !*url) return http_error_json("empty url"); + CURL* c = curl_easy_init(); + if (!c) return http_error_json("curl_easy_init failed"); + HttpBuf rb; httpbuf_init(&rb); + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, "PATCH"); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, body ? body : ""); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(body ? strlen(body) : 0)); + curl_easy_setopt(c, CURLOPT_HTTPHEADER, h); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, http_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, &rb); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, el_http_timeout_ms()); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-runtime/1.0"); + CURLcode rc = curl_easy_perform(c); + curl_slist_free_all(h); + curl_easy_cleanup(c); + if (rc != CURLE_OK) { + free(rb.data); + const char* m = errbuf[0] ? errbuf : curl_easy_strerror(rc); + return http_error_json(m); + } + return el_wrap_str(rb.data); +} + +/* http_post_engram — HTTP POST with optional X-API-Key header. + * If key is "" no authentication header is sent. */ +el_val_t http_post_engram(el_val_t url_v, el_val_t key_v, el_val_t body_v) { + const char* url = EL_CSTR(url_v); + const char* key = EL_CSTR(key_v); + const char* body = EL_CSTR(body_v); + if (!url || !*url) return http_error_json("empty url"); + CURL* c = curl_easy_init(); + if (!c) return http_error_json("curl_easy_init failed"); + HttpBuf rb; httpbuf_init(&rb); + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + if (key && *key) { + size_t n = strlen(key) + 32; + char* hdr = malloc(n); + snprintf(hdr, n, "X-API-Key: %s", key); + h = curl_slist_append(h, hdr); + free(hdr); + } + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, body ? body : ""); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(body ? strlen(body) : 0)); + curl_easy_setopt(c, CURLOPT_HTTPHEADER, h); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, http_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, &rb); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, el_http_timeout_ms()); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-runtime/1.0"); + CURLcode rc = curl_easy_perform(c); + curl_slist_free_all(h); + curl_easy_cleanup(c); + if (rc != CURLE_OK) { + free(rb.data); + const char* m = errbuf[0] ? errbuf : curl_easy_strerror(rc); + return http_error_json(m); + } + return el_wrap_str(rb.data); +} + +/* http_get_engram — HTTP GET with optional X-API-Key header. */ +el_val_t http_get_engram(el_val_t url_v, el_val_t key_v) { + const char* url = EL_CSTR(url_v); + const char* key = EL_CSTR(key_v); + if (!url || !*url) return http_error_json("empty url"); + CURL* c = curl_easy_init(); + if (!c) return http_error_json("curl_easy_init failed"); + HttpBuf rb; httpbuf_init(&rb); + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + struct curl_slist* h = NULL; + if (key && *key) { + size_t n = strlen(key) + 32; + char* hdr = malloc(n); + snprintf(hdr, n, "X-API-Key: %s", key); + h = curl_slist_append(h, hdr); + free(hdr); + } + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_HTTPGET, 1L); + if (h) curl_easy_setopt(c, CURLOPT_HTTPHEADER, h); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, http_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, &rb); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, el_http_timeout_ms()); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-runtime/1.0"); + CURLcode rc = curl_easy_perform(c); + if (h) curl_slist_free_all(h); + curl_easy_cleanup(c); + if (rc != CURLE_OK) { + free(rb.data); + const char* m = errbuf[0] ? errbuf : curl_easy_strerror(rc); + return http_error_json(m); + } + return el_wrap_str(rb.data); +} +#endif /* HAVE_CURL */ + +/* str_to_bytes — encode a string as a JSON array of unsigned byte values. + * "hello" -> "[104,101,108,108,111]" + * Used by db.el to store binary content in Engram JSON nodes. */ +el_val_t str_to_bytes(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s || !*s) return el_wrap_str(el_strdup("[]")); + size_t n = strlen(s); + /* Worst case: each byte is 3 digits + comma = 4 chars, plus "[]" + NUL. */ + char* out = el_strbuf(n * 4 + 3); + size_t pos = 0; + out[pos++] = '['; + for (size_t i = 0; i < n; i++) { + unsigned char b = (unsigned char)s[i]; + if (i > 0) out[pos++] = ','; + /* Write decimal representation of b. */ + if (b >= 100) { + out[pos++] = (char)('0' + b / 100); + out[pos++] = (char)('0' + (b / 10) % 10); + out[pos++] = (char)('0' + b % 10); + } else if (b >= 10) { + out[pos++] = (char)('0' + b / 10); + out[pos++] = (char)('0' + b % 10); + } else { + out[pos++] = (char)('0' + b); + } + } + out[pos++] = ']'; + out[pos] = '\0'; + return el_wrap_str(out); +} + +/* bytes_to_str — decode a JSON array of integer byte values back to a string. + * "[104,101,108,108,111]" -> "hello" + * Inverse of str_to_bytes. */ +el_val_t bytes_to_str(el_val_t arr_v) { + const char* s = EL_CSTR(arr_v); + if (!s) return el_wrap_str(el_strdup("")); + /* Skip whitespace, expect '['. */ + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s != '[') return el_wrap_str(el_strdup("")); + s++; + + /* Count elements to size the output buffer. */ + int64_t n = (int64_t)json_array_len(arr_v); + if (n <= 0) return el_wrap_str(el_strdup("")); + + char* out = el_strbuf((size_t)n + 1); + size_t pos = 0; + + /* Walk the array, parse each integer, store as a byte. */ + while (*s) { + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ']' || *s == '\0') break; + /* Parse decimal integer. */ + char* end_ptr; + long v = strtol(s, &end_ptr, 10); + if (end_ptr == s) break; /* parse failure */ + s = end_ptr; + if (v >= 0 && v <= 255) out[pos++] = (char)(unsigned char)v; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ',') { s++; continue; } + if (*s == ']' || *s == '\0') break; + } + out[pos] = '\0'; + return el_wrap_str(out); +} + +/* hash_sha256 — return the SHA-256 hex digest of a string. + * Uses the built-in el_sha256_oneshot implementation (no OpenSSL required). */ +el_val_t hash_sha256(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) s = ""; + unsigned char digest[32]; + el_sha256_oneshot((const unsigned char*)s, strlen(s), digest); + return el_hex_encode(digest, 32); +} + +/* ── __ prefixed aliases — public boundary for compiled El programs ────────── + * + * The El compiler's self-hosting back-end emits calls to __-prefixed function + * names (e.g. __println, __str_len). These wrappers forward to the existing + * el_runtime implementations so both naming conventions resolve at link time. + * + * Note: __thread_create and __thread_join are already defined above in the + * threading section; they are not repeated here. + * ──────────────────────────────────────────────────────────────────────────── */ + +/* I/O */ +el_val_t __println(el_val_t s) { return println(s); } +el_val_t __print(el_val_t s) { return print(s); } +el_val_t __readline(void) { return readline(); } + +/* String */ +el_val_t __int_to_str(el_val_t n) { return int_to_str(n); } +el_val_t __str_to_int(el_val_t s) { return str_to_int(s); } +el_val_t __float_to_str(el_val_t f) { return float_to_str(f); } +el_val_t __str_to_float(el_val_t s) { return str_to_float(s); } +el_val_t __str_len(el_val_t s) { return str_len(s); } +el_val_t __str_char_at(el_val_t s, el_val_t i) { return str_char_at(s, i); } + +el_val_t __str_cmp(el_val_t a, el_val_t b) { + const char* ca = EL_CSTR(a); + const char* cb = EL_CSTR(b); + if (!ca) ca = ""; + if (!cb) cb = ""; + return (el_val_t)strcmp(ca, cb); +} + +el_val_t __str_ncmp(el_val_t a, el_val_t b, el_val_t n) { + const char* ca = EL_CSTR(a); + const char* cb = EL_CSTR(b); + if (!ca) ca = ""; + if (!cb) cb = ""; + return (el_val_t)strncmp(ca, cb, (size_t)n); +} + +el_val_t __str_concat_raw(el_val_t a, el_val_t b) { return str_concat(a, b); } +el_val_t __str_slice_raw(el_val_t s, el_val_t start, el_val_t end) { return str_slice(s, start, end); } + +el_val_t __str_alloc(el_val_t n) { + if (n <= 0) n = 0; + char* buf = el_strbuf((size_t)n + 1); + memset(buf, 0, (size_t)n + 1); + return el_wrap_str(buf); +} + +el_val_t __str_set_char(el_val_t s, el_val_t i, el_val_t c) { + char* buf = (char*)(uintptr_t)s; + if (buf) buf[(size_t)i] = (char)c; + return s; +} + +/* URL encoding */ +el_val_t __url_encode(el_val_t s) { return url_encode(s); } +el_val_t __url_decode(el_val_t s) { return url_decode(s); } + +/* Environment */ +el_val_t __env_get(el_val_t key) { return env(key); } + +/* Subprocess */ +el_val_t __exec(el_val_t cmd) { return exec(cmd); } +el_val_t __exec_bg(el_val_t cmd) { return exec_bg(cmd); } + +/* Process */ +el_val_t __exit_program(el_val_t code) { return exit_program(code); } + +/* Filesystem */ +el_val_t __fs_exists(el_val_t path) { return fs_exists(path); } +el_val_t __fs_mkdir(el_val_t path) { return fs_mkdir(path); } +el_val_t __fs_read(el_val_t path) { return fs_read(path); } +el_val_t __fs_write(el_val_t path, el_val_t content) { return fs_write(path, content); } +el_val_t __fs_write_bytes(el_val_t path, el_val_t bytes, el_val_t n) { return fs_write_bytes(path, bytes, n); } +el_val_t __fs_list_raw(el_val_t path) { return fs_list_json(path); } + +/* HTTP server (no curl dependency) */ +el_val_t __http_response(el_val_t status, el_val_t headers_json, el_val_t body) { return http_response(status, headers_json, body); } +el_val_t __http_serve(el_val_t port, el_val_t handler) { return http_serve(port, handler); } +el_val_t __http_serve_v2(el_val_t port, el_val_t handler) { return http_serve_v2(port, handler); } + +/* HTTP conn fd / SSE — __http_conn_fd lives in el_seed.c; stubs provided here + * so el_runtime.c compiles standalone. When both translation units are linked + * the el_seed.c definitions win via their non-static linkage (strong symbols). + * These stubs are marked weak so they are silently overridden. */ +__attribute__((weak)) el_val_t __http_conn_fd(void) { return (el_val_t)(-1); } +__attribute__((weak)) el_val_t __http_sse_open(el_val_t conn_id) { (void)conn_id; return 0; } +__attribute__((weak)) el_val_t __http_sse_send(el_val_t conn_id, el_val_t data) { (void)conn_id; (void)data; return 0; } +__attribute__((weak)) el_val_t __http_sse_close(el_val_t conn_id) { (void)conn_id; return 0; } + +/* JSON */ +el_val_t __json_array_get(el_val_t json, el_val_t index) { return json_array_get(json, index); } +el_val_t __json_array_get_string(el_val_t json, el_val_t index) { return json_array_get_string(json, index); } +el_val_t __json_array_len(el_val_t json) { return json_array_len(json); } +el_val_t __json_get(el_val_t json, el_val_t key) { return json_get(json, key); } +el_val_t __json_get_raw(el_val_t json, el_val_t key) { return json_get_raw(json, key); } +el_val_t __json_set(el_val_t json, el_val_t key, el_val_t value){ return json_set(json, key, value); } +el_val_t __json_parse_map(el_val_t json_str) { return json_parse(json_str); } +el_val_t __json_stringify_val(el_val_t val) { return json_stringify(val); } + +/* Hashing */ +el_val_t __sha256_hex(el_val_t s) { return hash_sha256(s); } + +/* State K/V */ +el_val_t __state_del(el_val_t key) { return state_del(key); } +el_val_t __state_get(el_val_t key) { return state_get(key); } +el_val_t __state_keys(void) { return state_keys(); } +el_val_t __state_set(el_val_t key, el_val_t val) { return state_set(key, val); } + +/* UUID */ +el_val_t __uuid_v4(void) { return uuid_v4(); } + +/* Args */ +el_val_t __args_json(void) { return args(); } + +/* HTTP client aliases — require curl; defined inside #ifdef HAVE_CURL below + * with a matching stub in the #ifndef HAVE_CURL block. */ +#ifdef HAVE_CURL +el_val_t __http_do(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_map, el_val_t timeout_ms) { + /* timeout_ms is accepted for API compatibility but ignored here; + * el_runtime's http_do uses the EL_HTTP_TIMEOUT_MS env var instead. */ + (void)timeout_ms; + struct curl_slist* h = headers_from_map(headers_map); + el_val_t r = http_do(EL_CSTR(method), EL_CSTR(url), EL_CSTR(body), h); + if (h) curl_slist_free_all(h); + return r; +} + +/* __http_do_map — same as __http_do but headers_map arg is a JSON-string + * rather than an ElMap. Parse it first, then delegate. */ +el_val_t __http_do_map(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t timeout_ms) { + (void)timeout_ms; + /* Build a curl_slist from a JSON object {"Header":"value",...}. */ + const char* hj = EL_CSTR(headers_json); + struct curl_slist* h = NULL; + if (hj && *hj && *hj == '{') { + /* Walk the JSON pairs with a simple parser reusing json_get_string logic. */ + /* For correctness we just call the existing json_get iteration path. + * We duplicate the key-extraction loop from headers_from_map but driven + * by JSON rather than ElMap. Use json_get_raw to iterate is not easy + * without knowing keys, so accept the JSON string and build a tmp map. */ + el_val_t map = json_parse(EL_STR(hj)); + h = headers_from_map(map); + } + el_val_t r = http_do(EL_CSTR(method), EL_CSTR(url), EL_CSTR(body), h); + if (h) curl_slist_free_all(h); + return r; +} + +/* __http_do_map_to_file — same as __http_do_map but streams response body + * to a local file path rather than returning it as a string. */ +el_val_t __http_do_map_to_file(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t output_path) { + const char* hj = EL_CSTR(headers_json); + struct curl_slist* h = NULL; + if (hj && *hj && *hj == '{') { + el_val_t map = json_parse(EL_STR(hj)); + h = headers_from_map(map); + } + el_val_t r = http_do_to_file(EL_CSTR(method), EL_CSTR(url), EL_CSTR(body), + h, EL_CSTR(output_path)); + if (h) curl_slist_free_all(h); + return r; +} +#endif /* HAVE_CURL */ + +#ifndef HAVE_CURL +/* ── HAVE_CURL=0 stubs — compile without -lcurl for the elc CLI binary. ───── * + * These return a JSON error string so El programs get a clear message if they + * call HTTP/LLM functions in a curl-less build. */ +static el_val_t _no_curl_err(void) { + return el_wrap_str(el_strdup("{\"error\":\"not built with HAVE_CURL\"}")); +} +el_val_t http_get(el_val_t url) { (void)url; return _no_curl_err(); } +el_val_t http_post(el_val_t url, el_val_t body) { (void)url; (void)body; return _no_curl_err(); } +el_val_t http_post_json(el_val_t url, el_val_t body) { (void)url; (void)body; return _no_curl_err(); } +el_val_t http_get_with_headers(el_val_t url, el_val_t h) { (void)url; (void)h; return _no_curl_err(); } +el_val_t http_post_with_headers(el_val_t url, el_val_t b, el_val_t h) { (void)url; (void)b; (void)h; return _no_curl_err(); } +el_val_t http_post_json_with_headers(el_val_t url, el_val_t h, el_val_t b) { (void)url; (void)h; (void)b; return _no_curl_err(); } +el_val_t http_post_form_auth(el_val_t url, el_val_t b, el_val_t a) { (void)url; (void)b; (void)a; return _no_curl_err(); } +el_val_t http_delete(el_val_t url) { (void)url; return _no_curl_err(); } +el_val_t http_patch(el_val_t url, el_val_t body) { (void)url; (void)body; return _no_curl_err(); } +el_val_t http_get_to_file(el_val_t url, el_val_t h, el_val_t p) { (void)url; (void)h; (void)p; return _no_curl_err(); } +el_val_t http_post_to_file(el_val_t url, el_val_t b, el_val_t h, el_val_t p) { (void)url; (void)b; (void)h; (void)p; return _no_curl_err(); } +el_val_t http_post_engram(el_val_t url, el_val_t k, el_val_t b) { (void)url; (void)k; (void)b; return _no_curl_err(); } +el_val_t http_get_engram(el_val_t url, el_val_t k) { (void)url; (void)k; return _no_curl_err(); } +el_val_t llm_call(el_val_t m, el_val_t p) { (void)m; (void)p; return _no_curl_err(); } +el_val_t llm_call_system(el_val_t m, el_val_t s, el_val_t u) { (void)m; (void)s; (void)u; return _no_curl_err(); } +el_val_t llm_call_agentic(el_val_t m, el_val_t s, el_val_t u, el_val_t t) { (void)m; (void)s; (void)u; (void)t; return _no_curl_err(); } +el_val_t llm_vision(el_val_t m, el_val_t s, el_val_t p, el_val_t i) { (void)m; (void)s; (void)p; (void)i; return _no_curl_err(); } +el_val_t llm_models(void) { return el_list_empty(); } +void llm_register_tool(el_val_t n, el_val_t f) { (void)n; (void)f; } +/* __ HTTP stubs (no-curl build) */ +el_val_t __http_do(el_val_t m, el_val_t u, el_val_t b, el_val_t h, el_val_t t) { (void)m; (void)u; (void)b; (void)h; (void)t; return _no_curl_err(); } +el_val_t __http_do_map(el_val_t m, el_val_t u, el_val_t b, el_val_t h, el_val_t t) { (void)m; (void)u; (void)b; (void)h; (void)t; return _no_curl_err(); } +el_val_t __http_do_map_to_file(el_val_t m, el_val_t u, el_val_t b, el_val_t h, el_val_t p) { (void)m; (void)u; (void)b; (void)h; (void)p; return _no_curl_err(); } +#endif /* !HAVE_CURL */ diff --git a/ui/examples/native-hello-android/app/src/main/jni/el_runtime.h b/ui/examples/native-hello-android/app/src/main/jni/el_runtime.h new file mode 100644 index 0000000..2f9583f --- /dev/null +++ b/ui/examples/native-hello-android/app/src/main/jni/el_runtime.h @@ -0,0 +1,883 @@ +/* + * el_runtime.h — El language C runtime header + * + * Declares all built-in functions available to compiled El programs. + * Include this in every generated .c file. + * + * Value model: + * All El values are represented as el_val_t (= int64_t). + * On 64-bit systems a pointer fits in int64_t. + * String values are cast: (el_val_t)(uintptr_t)"hello" + * Integer values are stored directly. + * This lets arithmetic work naturally while still passing strings around. + * + * Type conventions (El -> C): + * String -> el_val_t (holds const char* via uintptr_t cast) + * Int -> el_val_t + * Bool -> el_val_t (0 = false, nonzero = true) + * Any -> el_val_t + * Void -> void + * + * Macros for convenience: + * 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_*). + * -lpthread — required for the HTTP server (one detached thread per + * connection, capped at 64 concurrent). + * -loqs — optional; required only when liboqs is installed and the + * pq_* / sha3_256_hex entry points are needed. Detected at + * compile time via __has_include(). + * -lcrypto — optional; pulled in alongside -loqs. Used for X25519 in + * pq_hybrid_* and HKDF-SHA256 derivation. + * + * Canonical compile command: + * cc -std=c11 -I el-compiler/runtime -lcurl -lpthread \ + * -o .c el-compiler/runtime/el_runtime.c + * + * With liboqs (post-quantum stack): + * cc -std=c11 -I el-compiler/runtime -lcurl -lpthread -loqs -lcrypto \ + * -o .c el-compiler/runtime/el_runtime.c + */ + +#pragma once + +#include +#include + +typedef int64_t el_val_t; + +#define EL_STR(s) ((el_val_t)(uintptr_t)(s)) +#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()` so the + * underlying bits represent the IEEE 754 double. Float-aware builtins + * (math, format, json) round-trip via these helpers. */ +static inline double el_to_float(el_val_t v) { + union { int64_t i; double f; } u; + u.i = (int64_t)v; + return u.f; +} + +static inline el_val_t el_from_float(double f) { + union { double f; int64_t i; } u; + u.f = f; + return (el_val_t)u.i; +} + +#ifdef __cplusplus +extern "C" { +#endif + +/* ── I/O ──────────────────────────────────────────────────────────────────── */ + +el_val_t println(el_val_t s); +el_val_t print(el_val_t s); +el_val_t readline(void); + +/* ── String builtins ─────────────────────────────────────────────────────── */ + +el_val_t el_str_concat(el_val_t a, el_val_t b); +el_val_t str_eq(el_val_t a, el_val_t b); +el_val_t str_starts_with(el_val_t s, el_val_t prefix); +el_val_t str_ends_with(el_val_t s, el_val_t suffix); +el_val_t str_len(el_val_t s); +el_val_t str_concat(el_val_t a, el_val_t b); +el_val_t int_to_str(el_val_t n); +el_val_t str_to_int(el_val_t s); +el_val_t native_str_to_int(el_val_t s); +el_val_t str_slice(el_val_t s, el_val_t start, el_val_t end); +el_val_t str_contains(el_val_t s, el_val_t sub); +el_val_t str_replace(el_val_t s, el_val_t from, el_val_t to); +el_val_t str_to_upper(el_val_t s); +el_val_t str_to_lower(el_val_t s); +el_val_t str_trim(el_val_t s); + +/* ── Math ────────────────────────────────────────────────────────────────── */ + +el_val_t el_abs(el_val_t n); +el_val_t el_max(el_val_t a, el_val_t b); +el_val_t el_min(el_val_t a, el_val_t b); + +/* ── Refcount (ARC) ────────────────────────────────────────────────────────── + * Lists and Maps carry a refcount. Strings and ints do not — el_retain and + * el_release are safe no-ops on non-refcounted values (they sniff a magic + * header at offset 0 and only act if the magic matches). + * + * Codegen emits these at let-binding shadowing, function entry (params), and + * function exit (locals other than the returned value). The refcount lets + * el_list_append and el_map_set mutate in place when uniquely owned (cheap) + * and copy-on-write when shared (preserves persistent semantics across + * accumulator patterns in the compiler itself). */ + +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, ...); +el_val_t el_list_len(el_val_t list); +el_val_t el_list_get(el_val_t list, el_val_t index); +el_val_t el_list_append(el_val_t list, el_val_t elem); +el_val_t el_list_empty(void); +el_val_t el_list_clone(el_val_t list); + +/* ── Map ─────────────────────────────────────────────────────────────────── */ + +el_val_t el_map_new(el_val_t pair_count, ...); +el_val_t el_get_field(el_val_t map, el_val_t key); +el_val_t el_map_get(el_val_t map, el_val_t key); +el_val_t el_map_set(el_val_t map, el_val_t key, el_val_t value); + +/* ── HTTP ─────────────────────────────────────────────────────────────────── */ + +el_val_t http_get(el_val_t url); +el_val_t http_post(el_val_t url, el_val_t body); +el_val_t http_post_json(el_val_t url, el_val_t json_body); +el_val_t http_get_with_headers(el_val_t url, el_val_t headers_map); +el_val_t http_post_with_headers(el_val_t url, el_val_t body, el_val_t headers_map); +el_val_t http_post_json_with_headers(el_val_t url, el_val_t headers_map, el_val_t json_body); +el_val_t http_post_form_auth(el_val_t url, el_val_t form_body, el_val_t auth_header); +el_val_t http_delete(el_val_t url); +el_val_t http_serve(el_val_t port, el_val_t handler); +el_val_t http_set_handler(el_val_t name); + +/* HTTP server v2 ───────────────────────────────────────────────────────────── + * Same dispatch model as http_serve, but the handler signature is widened: + * + * el_val_t handler(method, path, headers_map, body) + * + * `headers_map` is an ElMap from lowercased header name → header value (both + * Strings). Repeated headers are joined with ", " per RFC 7230. + * + * Response value: the handler may return either + * (a) a plain body string — same auto-content-type / 200-OK behaviour as + * http_serve (3-arg) — or + * (b) a response envelope built with `http_response(status, headers_json, + * body)`. The runtime detects the envelope discriminator + * `"el_http_response":1` at the start of the returned string and + * unpacks status / headers / body before sending. + * + * The 3-arg http_serve(port, handler) remains supported unchanged for + * existing handlers (e.g. products/web/server.el): it dispatches with + * (method, path, body), hardcodes 200 OK, and auto-detects content type. */ +el_val_t http_serve_v2(el_val_t port, el_val_t handler); +el_val_t http_set_handler_v2(el_val_t name); + +/* Build an HTTP response envelope. `headers_json` should be a JSON object + * literal like `{"WWW-Authenticate":"Basic"}` (or "" / "{}" for none). The + * returned string carries the discriminator `{"el_http_response":1,...}` + * which the runtime's send-path detects and unpacks. Detection happens + * uniformly inside http_send_response, so a 3-arg handler may also return + * an envelope. The 3-arg variant remains documented as a fixed 200-OK + * auto-content-type contract for legacy handlers that return plain bodies. */ +el_val_t http_response(el_val_t status, el_val_t headers_json, el_val_t body); + +/* SSE connection fd — set by http_worker_v2 before calling the El handler, + * cleared afterwards. Defined in el_seed.c; called from el_runtime.c. + * The getter is exposed as __http_conn_fd() to El programs. */ +void el_seed_set_http_conn_fd(int fd); + +/* HTTP timeout — every libcurl request honors EL_HTTP_TIMEOUT_MS (default + * 60000ms). Read lazily on first use, so setting the env var any time before + * the first http_* call is sufficient. */ + +/* Streaming variants — write the response body straight to a file via + * libcurl's CURLOPT_WRITEFUNCTION = fwrite. These bypass the el_val_t string + * wrapper entirely, so binary payloads (audio/mpeg, image/png, etc.) survive + * embedded NUL bytes that would truncate a strlen()-based code path. + * + * Both honor EL_HTTP_TIMEOUT_MS, follow redirects, and accept the same + * `headers_map` shape as http_post_with_headers (ElMap of String→String). + * + * Return value: 1 on success (file fully written), 0 on any failure + * (network, file open, partial write). On failure the output file is removed + * so callers cannot mistake a partially-written file for a valid one. */ +el_val_t http_post_to_file(el_val_t url, el_val_t body, el_val_t headers_map, el_val_t output_path); +el_val_t http_get_to_file(el_val_t url, el_val_t headers_map, el_val_t output_path); + +/* ── URL encoding ────────────────────────────────────────────────────────── */ + +el_val_t url_encode(el_val_t s); /* RFC 3986 unreserved set */ +el_val_t url_decode(el_val_t s); /* '+' → space, %XX → byte */ + +/* ── HTML allowlist sanitizer ──────────────────────────────────────────────── + * el_html_sanitize(input_html, allowlist_json) — strict allowlist HTML + * cleaner. State-machine parser; tag/attribute names compared case- + * insensitively against the allowlist; `` / `<… src>` URL schemes + * validated (http, https, mailto, fragment-only, or relative); whole- + * subtree drop for script / style / iframe / object / embed / form; HTML- + * escapes free text outside dropped subtrees. + * + * The allowlist is JSON of the form + * {"p":[],"a":["href","title"],"strong":[],...} + * where each value is the array of attribute names allowed for that tag. */ +el_val_t el_html_sanitize(el_val_t input_html, el_val_t allowlist_json); +el_val_t html_raw(el_val_t s); +el_val_t html_escape(el_val_t s); + +/* ── Filesystem ──────────────────────────────────────────────────────────── */ + +el_val_t fs_read(el_val_t path); +el_val_t fs_write(el_val_t path, el_val_t content); +el_val_t fs_list(el_val_t path); +el_val_t fs_list_json(el_val_t path); +el_val_t fs_exists(el_val_t path); +el_val_t fs_mkdir(el_val_t path); /* mkdir -p, mode 0755 */ + +/* Length-explicit binary write. `length` is an Int (el_val_t holding the + * byte count). The caller knows the length from context — typically because + * `bytes` came from base64_decode (which produces a magic-tagged binary + * buffer with embedded NULs possible) and the caller already tracks the + * decoded length, OR because the bytes came from a fixed-size source + * (sha256_bytes = 32, hmac_sha256_bytes = 32). Bypasses strlen entirely. + * + * Returns 1 on success, 0 on failure (invalid path, can't open, partial + * write, negative length). On partial-write failure, the file is removed + * so callers cannot read back a truncated artefact. */ +el_val_t fs_write_bytes(el_val_t path, el_val_t bytes, el_val_t length); + +/* ── JSON ────────────────────────────────────────────────────────────────── */ + +el_val_t json_get(el_val_t json, el_val_t key); +el_val_t json_parse(el_val_t s); +el_val_t json_stringify(el_val_t v); +el_val_t json_get_string(el_val_t json_str, el_val_t key); +el_val_t json_get_int(el_val_t json_str, el_val_t key); +el_val_t json_get_float(el_val_t json_str, el_val_t key); +el_val_t json_get_bool(el_val_t json_str, el_val_t key); +el_val_t json_get_raw(el_val_t json_str, el_val_t key); +el_val_t json_set(el_val_t json_str, el_val_t key, el_val_t value); +el_val_t json_array_len(el_val_t json_str); +el_val_t json_array_get(el_val_t json_str, el_val_t index); +el_val_t json_array_get_string(el_val_t json_str, el_val_t index); +el_val_t json_escape_string(el_val_t sv); +el_val_t json_build_object(el_val_t kvs); +el_val_t json_build_array(el_val_t items); + +/* ── Time ────────────────────────────────────────────────────────────────── */ + +el_val_t time_now(void); +el_val_t time_now_utc(void); +el_val_t sleep_secs(el_val_t secs); +el_val_t sleep_ms(el_val_t ms); +el_val_t time_format(el_val_t ts, el_val_t fmt); +el_val_t time_to_parts(el_val_t ts); +el_val_t time_from_parts(el_val_t secs, el_val_t ns, el_val_t tz); +el_val_t time_add(el_val_t ts, el_val_t n, el_val_t unit); +el_val_t time_diff(el_val_t ts1, el_val_t ts2, el_val_t unit); +el_val_t now_ns(void); + +/* ── Instant + Duration: first-class temporal types ────────────────────────── + * Both types share the el_val_t (int64) slot. Instants are nanoseconds + * since the Unix epoch; Durations are signed nanoseconds. Type discipline + * is enforced at codegen-time: BinOps on names registered as Instant or + * Duration route through the typed wrappers below; mismatches like + * Instant+Instant become #error at the C compiler. + * + * Postfix literals — `30.seconds`, `1.hour`, `500.millis`, `30.nanos` — are + * recognised by the parser as DurationLit AST nodes and lowered to literal + * int64 nanoseconds at codegen time. The runtime never sees the units. */ + +el_val_t el_now_instant(void); +el_val_t now(void); +el_val_t unix_seconds(el_val_t n); +el_val_t unix_millis(el_val_t n); +el_val_t instant_from_iso8601(el_val_t s); + +el_val_t el_duration_from_nanos(el_val_t ns); +el_val_t duration_seconds(el_val_t n); +el_val_t duration_millis(el_val_t n); +el_val_t duration_nanos(el_val_t n); + +el_val_t el_instant_add_dur(el_val_t inst, el_val_t dur); +el_val_t el_instant_sub_dur(el_val_t inst, el_val_t dur); +el_val_t el_instant_diff(el_val_t a, el_val_t b); +el_val_t el_duration_add(el_val_t a, el_val_t b); +el_val_t el_duration_sub(el_val_t a, el_val_t b); +el_val_t el_duration_scale(el_val_t dur, el_val_t scalar); +el_val_t el_duration_div(el_val_t dur, el_val_t scalar); + +el_val_t el_instant_lt(el_val_t a, el_val_t b); +el_val_t el_instant_le(el_val_t a, el_val_t b); +el_val_t el_instant_gt(el_val_t a, el_val_t b); +el_val_t el_instant_ge(el_val_t a, el_val_t b); +el_val_t el_instant_eq(el_val_t a, el_val_t b); +el_val_t el_instant_ne(el_val_t a, el_val_t b); +el_val_t el_duration_lt(el_val_t a, el_val_t b); +el_val_t el_duration_le(el_val_t a, el_val_t b); +el_val_t el_duration_gt(el_val_t a, el_val_t b); +el_val_t el_duration_ge(el_val_t a, el_val_t b); +el_val_t el_duration_eq(el_val_t a, el_val_t b); +el_val_t el_duration_ne(el_val_t a, el_val_t b); + +el_val_t instant_to_unix_seconds(el_val_t i); +el_val_t instant_to_unix_millis(el_val_t i); +el_val_t instant_to_iso8601(el_val_t i); +el_val_t duration_to_seconds(el_val_t d); +el_val_t duration_to_millis(el_val_t d); +el_val_t duration_to_nanos(el_val_t d); + +el_val_t el_sleep_duration(el_val_t dur); +el_val_t unix_timestamp(void); + +el_val_t ttl_cache_set(el_val_t key, el_val_t value); +el_val_t ttl_cache_get(el_val_t key, el_val_t max_age); +el_val_t ttl_cache_age(el_val_t key); + +/* ── Calendar + CalendarTime + Rhythm + LocalDate/Time/DateTime ───────────── + * Phase 1.5 of the time system. Calendar is pluggable: EarthCalendar (IANA + * zones, Gregorian, DST) is the user-facing default; MarsCalendar, + * CycleCalendar(period), NoCycleCalendar, RelativeCalendar handle non-Earth + * domains. + * + * A Calendar interprets an Instant under a particular cycle convention and + * produces a CalendarTime. CalendarTime carries the underlying Instant and + * a back-pointer to its Calendar; arithmetic and formatting consult the + * Calendar to convert ns since epoch into year/month/day/hour/minute/second + * (or sol/phase, or cycle/phase, depending on kind). + * + * Storage convention: Calendar / CalendarTime / Rhythm / LocalDate / + * LocalDateTime are heap-allocated structs whose pointers are cast into + * el_val_t. A 24-bit magic header at offset 0 lets the runtime identify + * the kind safely. LocalTime is small enough to live in the int64 slot + * directly (nanos since midnight, signed). */ + +/* Zone — opaque IANA zone or fixed offset, used by EarthCalendar. + * `zone_id` is either an IANA name ("America/New_York", "UTC") or a fixed + * offset string ("+05:30", "-08:00"). The runtime resolves it via tzset() + * on first use of the owning EarthCalendar. */ +el_val_t zone(el_val_t id); +el_val_t zone_utc(void); +el_val_t zone_local(void); +el_val_t zone_offset(el_val_t hours, el_val_t minutes); + +/* Calendar constructors. Each returns an el_val_t pointer to a heap- + * allocated, magic-tagged Calendar struct. Calendars are interned by + * (kind, zone_id, period_ns, epoch_ns) so identical constructors return + * the same pointer — equality is reference equality. */ +el_val_t earth_calendar(el_val_t z); +el_val_t earth_calendar_default(void); +el_val_t mars_calendar(void); +el_val_t cycle_calendar(el_val_t period_dur); +el_val_t no_cycle_calendar(void); +el_val_t relative_calendar(el_val_t epoch_inst); + +/* CalendarTime constructors and methods. Returns a heap-allocated struct + * whose pointer fits in el_val_t. */ +el_val_t now_in(el_val_t cal); +el_val_t in_calendar(el_val_t inst, el_val_t cal); +el_val_t cal_format(el_val_t ct, el_val_t pattern); +el_val_t cal_to_instant(el_val_t ct); +el_val_t cal_cycle_phase(el_val_t ct); +el_val_t cal_in(el_val_t ct, el_val_t cal); + +/* LocalDate / LocalTime / LocalDateTime — calendar-agnostic value types. + * LocalTime carries nanoseconds since midnight as a signed int64 directly + * in the el_val_t slot (no allocation). LocalDate / LocalDateTime are + * heap-allocated structs with magic headers. */ +el_val_t local_date(el_val_t y, el_val_t m, el_val_t d); +el_val_t local_time(el_val_t h, el_val_t m, el_val_t s, el_val_t ns); +el_val_t local_datetime(el_val_t date, el_val_t time); +el_val_t zoned(el_val_t date, el_val_t time, el_val_t cal); + +el_val_t local_date_year(el_val_t ld); +el_val_t local_date_month(el_val_t ld); +el_val_t local_date_day(el_val_t ld); +el_val_t local_time_hour(el_val_t lt); +el_val_t local_time_minute(el_val_t lt); +el_val_t local_time_second(el_val_t lt); +el_val_t local_time_nanos(el_val_t lt); + +el_val_t el_local_date_add_dur(el_val_t ld, el_val_t dur); +el_val_t el_local_time_add_dur(el_val_t lt, el_val_t dur); +el_val_t el_local_date_lt(el_val_t a, el_val_t b); +el_val_t el_local_date_eq(el_val_t a, el_val_t b); + +/* Rhythm — pluggable recurrence AST. Returns a heap-allocated struct + * pointer in el_val_t; rhythms are immutable so callers may share them. */ +el_val_t rhythm_cycle_start(void); +el_val_t rhythm_cycle_phase(el_val_t phase); +el_val_t rhythm_duration(el_val_t d); +el_val_t rhythm_session_start(void); +el_val_t rhythm_event(el_val_t name); +el_val_t rhythm_and(el_val_t a, el_val_t b); +el_val_t rhythm_or(el_val_t a, el_val_t b); +el_val_t rhythm_weekday(el_val_t day); +el_val_t rhythm_weekly_at(el_val_t day, el_val_t hour, el_val_t minute); +el_val_t rhythm_next_after(el_val_t r, el_val_t after, el_val_t cal); +el_val_t rhythm_matches(el_val_t r, el_val_t ct); + +/* ── UUID ────────────────────────────────────────────────────────────────── */ + +el_val_t uuid_new(void); +el_val_t uuid_v4(void); + +/* ── Environment ─────────────────────────────────────────────────────────── */ + +el_val_t env(el_val_t key); + +/* ── In-process state K/V ────────────────────────────────────────────────── */ + +el_val_t state_set(el_val_t key, el_val_t value); +el_val_t state_get(el_val_t key); +el_val_t state_del(el_val_t key); +el_val_t state_keys(void); +el_val_t state_has(el_val_t key); +el_val_t state_get_or(el_val_t key, el_val_t default_val); + +/* ── Float formatting ────────────────────────────────────────────────────── */ + +el_val_t float_to_str(el_val_t f); +el_val_t int_to_float(el_val_t n); +el_val_t float_to_int(el_val_t f); +el_val_t format_float(el_val_t f, el_val_t decimals); +el_val_t decimal_round(el_val_t f, el_val_t decimals); +el_val_t str_to_float(el_val_t s); + +/* ── Math (Float-aware) ──────────────────────────────────────────────────── */ + +el_val_t math_sqrt(el_val_t f); +el_val_t math_log(el_val_t f); +el_val_t math_ln(el_val_t f); +el_val_t math_sin(el_val_t f); +el_val_t math_cos(el_val_t f); +el_val_t math_pi(void); + +/* ── String additions ────────────────────────────────────────────────────── */ + +el_val_t str_index_of(el_val_t s, el_val_t sub); +el_val_t str_split(el_val_t s, el_val_t sep); +el_val_t str_char_at(el_val_t s, el_val_t i); +el_val_t str_char_code(el_val_t s, el_val_t i); +el_val_t str_pad_left(el_val_t s, el_val_t width, el_val_t pad); +el_val_t str_pad_right(el_val_t s, el_val_t width, el_val_t pad); +el_val_t str_format(el_val_t fmt, el_val_t data); +el_val_t str_lower(el_val_t s); +el_val_t str_upper(el_val_t s); + +/* ── Text-processing primitives (Phase 1: byte/codepoint, ASCII char classes) + * Phase 2 (filed): Unicode-grapheme awareness, NFC/NFD normalization, regex. + * is_* predicates: empty input returns false; multi-char requires ALL bytes + * to match. ASCII ranges only in Phase 1. */ + +/* Counting */ +el_val_t str_count(el_val_t s, el_val_t sub); /* non-overlapping */ +el_val_t str_count_chars(el_val_t s); /* codepoint count */ +el_val_t str_count_bytes(el_val_t s); /* alias of str_len */ +el_val_t str_count_lines(el_val_t s); +el_val_t str_count_words(el_val_t s); +el_val_t str_count_letters(el_val_t s); /* ASCII [A-Za-z] */ +el_val_t str_count_digits(el_val_t s); /* ASCII [0-9] */ + +/* Find / position */ +el_val_t str_index_of_all(el_val_t s, el_val_t sub); /* [Int] of byte offsets */ +el_val_t str_last_index_of(el_val_t s, el_val_t sub); +el_val_t str_find_chars(el_val_t s, el_val_t any_of); /* first idx of any ch */ + +/* Transform */ +el_val_t str_repeat(el_val_t s, el_val_t n); +el_val_t str_reverse(el_val_t s); /* by codepoint */ +el_val_t str_strip_prefix(el_val_t s, el_val_t prefix); +el_val_t str_strip_suffix(el_val_t s, el_val_t suffix); +el_val_t str_strip_chars(el_val_t s, el_val_t chars); +el_val_t str_lstrip(el_val_t s); +el_val_t str_rstrip(el_val_t s); + +/* Char classification (Bool) */ +el_val_t is_letter(el_val_t s); +el_val_t is_digit(el_val_t s); +el_val_t is_alphanumeric(el_val_t s); +el_val_t is_whitespace(el_val_t s); +el_val_t is_punctuation(el_val_t s); +el_val_t is_uppercase(el_val_t s); +el_val_t is_lowercase(el_val_t s); + +/* Split / join */ +el_val_t str_split_lines(el_val_t s); +el_val_t str_split_chars(el_val_t s); /* alias of native_string_chars */ +el_val_t str_split_n(el_val_t s, el_val_t sep, el_val_t n); +el_val_t str_join(el_val_t list, el_val_t sep); /* alias of list_join */ + +/* ── List additions ──────────────────────────────────────────────────────── */ + +el_val_t list_push(el_val_t list, el_val_t elem); +el_val_t list_push_front(el_val_t list, el_val_t elem); +el_val_t list_join(el_val_t list, el_val_t sep); +el_val_t list_range(el_val_t start, el_val_t end); + +/* ── Bool helpers ────────────────────────────────────────────────────────── */ + +el_val_t bool_to_str(el_val_t b); + +/* ── Numeric parsing ─────────────────────────────────────────────────────── */ + +el_val_t parse_int(el_val_t s, el_val_t default_val); + +/* ── Process ─────────────────────────────────────────────────────────────── */ + +el_val_t exit_program(el_val_t code); +el_val_t getpid_now(void); + +/* Self-terminating memory guard. Reads ELC_MAX_MEM_MB (default 512) and + * exits with code 1 if resident memory exceeds the limit. Call periodically + * during long compilation loops (e.g. after each function is compiled). + * Returns 0 when memory is within bounds. */ +el_val_t el_mem_check(void); + +/* ── CGI identity ───────────────────────────────────────────────────────────── + * Called at the start of main() in CGI programs (those with a `cgi {}` block). + * Records the program's DHARMA identity before any other code executes. */ + +void el_cgi_init(el_val_t name, el_val_t dharma_id, el_val_t principal, + el_val_t network, el_val_t engram); + +/* ── DHARMA network builtins ───────────────────────────────────────────────── + * Available to CGI programs (declared with a `cgi {}` block). + * + * Peers are addressed by `dharma_id` of the form + * "@" e.g. "ntn-genesis@http://localhost:7770" + * If the @ portion is omitted, transport defaults to + * "http://localhost:7770" (the local CGI daemon assumption). + * + * Wire protocol (all peers expose): + * POST /dharma/recv { channel, from, content } → response body + * POST /dharma/event { type, payload, source, timestamp } + * POST /api/activate { query } → list of nodes + * + * Hosting application's responsibility: an El program with a `cgi {}` block + * runs http_serve() with its own request handler; that handler should route + * "/dharma/event" requests by calling el_runtime_dharma_event_arrive() so + * incoming events feed dharma_field() queues. The runtime itself does not + * intercept any /dharma path. */ + +el_val_t dharma_connect(el_val_t cgi_id); +el_val_t dharma_send(el_val_t channel, el_val_t content); +el_val_t dharma_activate(el_val_t query); +void dharma_emit(el_val_t event_type, el_val_t payload); +el_val_t dharma_field(el_val_t event_type); +void dharma_strengthen(el_val_t cgi_id, el_val_t weight); +el_val_t dharma_relationship(el_val_t cgi_id); +el_val_t dharma_peers(void); + +/* Public C API: called by an El program's HTTP handler when a /dharma/event + * request arrives. Pushes onto the per-event-type queue and signals any + * pending dharma_field() blockers. All three arguments must be NUL-terminated + * C strings (or NULL — then treated as empty). */ +void el_runtime_dharma_event_arrive(const char* event_type, + const char* payload, + const char* source); + +/* ── Engram local graph primitives ─────────────────────────────────────────── + * Operate on the CGI's local Engram knowledge graph. + * `engram_activate` queries the local graph only; `dharma_activate` is + * network-wide across all connected CGI graphs. */ + +el_val_t engram_node(el_val_t content, el_val_t node_type, el_val_t salience); +el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags); +/* Layered consciousness — see el_runtime.c for the layered architecture + * design notes (search "Layered consciousness architecture"). The five + * canonical layers (safety / core-identity / domain-knowledge / imprint / + * suit) are seeded automatically; engram_add_layer extends the registry + * with imprint or suit overlays at runtime. Nodes default to layer 1 + * (core-identity) when created via engram_node / engram_node_full. */ +el_val_t engram_node_layered(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t certainty, el_val_t confidence, + el_val_t status, el_val_t tags, el_val_t layer_id); +el_val_t engram_add_layer(el_val_t name, el_val_t priority, el_val_t suppressible, + el_val_t transparent, el_val_t injectable); +el_val_t engram_remove_layer(el_val_t layer_id); +el_val_t engram_list_layers(void); +el_val_t engram_get_node(el_val_t id); +void engram_strengthen(el_val_t node_id); +void engram_forget(el_val_t node_id); +el_val_t engram_node_count(void); +el_val_t engram_search(el_val_t query, el_val_t limit); +el_val_t engram_scan_nodes(el_val_t limit, el_val_t offset); +void engram_connect(el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t relation); +el_val_t engram_edge_between(el_val_t from_id, el_val_t to_id); +el_val_t engram_neighbors(el_val_t node_id); +el_val_t engram_neighbors_filtered(el_val_t node_id, el_val_t max_depth, el_val_t direction); +el_val_t engram_edge_count(void); +/* Three-pass activation: background fan-out → working-memory promotion → + * Layer 0 override. See "Three-pass activation" in el_runtime.c. */ +el_val_t engram_activate(el_val_t query, el_val_t depth); +el_val_t engram_save(el_val_t path); +el_val_t engram_load(el_val_t path); + +/* JSON-string accessors — return pre-serialized JSON so HTTP handlers + * can pass results straight through without round-tripping ElList/ElMap + * through json_stringify. */ +el_val_t engram_get_node_json(el_val_t id); +el_val_t engram_search_json(el_val_t query, el_val_t limit); +el_val_t engram_scan_nodes_json(el_val_t limit, el_val_t offset); +el_val_t engram_scan_nodes_by_type_json(el_val_t node_type, el_val_t limit, el_val_t offset); +el_val_t engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction); +el_val_t engram_activate_json(el_val_t query, el_val_t depth); +el_val_t engram_stats_json(void); +el_val_t engram_list_layers_json(void); +/* engram_compile_layered_json — produce a prompt-ready text block split + * into "[LAYER 0 — STRUCTURAL]" (non-suppressible layers, sacred fire) + * and "[ENGRAM CONTEXT]" (standard suppressible layers). Returns "" if + * no nodes promoted to working memory. */ +el_val_t engram_compile_layered_json(el_val_t intent, el_val_t depth); + +/* ── LLM (Anthropic API client) ───────────────────────────────────────────── + * All functions call https://api.anthropic.com/v1/messages with the API key + * from env ANTHROPIC_API_KEY. Default model when empty: claude-sonnet-4-5. */ + +el_val_t llm_call(el_val_t model, el_val_t prompt); +el_val_t llm_call_system(el_val_t model, el_val_t system_prompt, el_val_t user_prompt); +el_val_t llm_call_agentic(el_val_t model, el_val_t system, el_val_t user, el_val_t tools); +el_val_t llm_vision(el_val_t model, el_val_t system, el_val_t prompt, el_val_t image_url_or_b64); +el_val_t llm_models(void); + +/* Register a tool handler by name. The handler is looked up via dlsym + * (mirroring http_set_handler), so any El `fn (input)` compiles to + * a global C symbol that this function can locate at runtime. + * Handler signature: `el_val_t handler(el_val_t input_json)` — receives + * the tool input as a JSON-string el_val_t and returns a JSON-string + * el_val_t result. Used by llm_call_agentic. */ +void llm_register_tool(el_val_t name, el_val_t handler_fn_name); + +/* ── args() ───────────────────────────────────────────────────────────────── + * Provides access to command-line arguments passed to the program. + * Populated by el_runtime_init_args() before main() runs. */ + +el_val_t args(void); +void el_runtime_init_args(int argc, char** argv); + +/* ── Crypto primitives ───────────────────────────────────────────────────── + * SHA-256, HMAC-SHA-256, and base64 (standard + URL-safe). + * Self-contained — no OpenSSL/libcrypto dependency. The implementations are + * adapted from public-domain reference code (Brad Conte / RFC 4648). + * + * Bytes-returning variants (sha256_bytes, hmac_sha256_bytes) return a string + * value whose contents are raw binary; callers usually feed these into + * base64_encode. Note that el_val_t strings are NUL-terminated by convention, + * so the binary payload may contain embedded NULs — pass it directly into + * base64_encode (which uses an explicit length) rather than treating it as + * a printable C string. + * + * The "base64" variants emit/accept RFC 4648 standard alphabet with padding. + * The "base64url" variants use URL-safe alphabet (`-`/`_`) with no padding, + * as used in JWTs. */ + +el_val_t sha256_hex(el_val_t input); +el_val_t sha256_bytes(el_val_t input); +el_val_t hmac_sha256_hex(el_val_t key, el_val_t message); +el_val_t hmac_sha256_bytes(el_val_t key, el_val_t message); +el_val_t base64_encode(el_val_t input); +el_val_t base64_decode(el_val_t input); +el_val_t base64url_encode(el_val_t input); +el_val_t base64url_decode(el_val_t input); + +/* Length-aware variants (internal — exposed for the rare caller that already + * has a known-length binary buffer and doesn't want to round-trip through + * a NUL-terminated el_val_t string). Sha256_bytes and hmac_sha256_bytes feed + * these implicitly. */ +el_val_t el_sha256_bytes_n(const unsigned char* data, size_t len); +el_val_t el_base64_encode_n(const unsigned char* data, size_t len, int url_safe); + +/* ── Post-quantum primitives (liboqs-backed) ──────────────────────────────── + * All inputs/outputs hex-encoded. Algorithm choices: + * Signature: CRYSTALS-Dilithium-3 (NIST level 3, balanced) + * KEM: CRYSTALS-Kyber-768 (NIST level 3) + * Hash: SHA3-256 (Keccak) (PQ-aware protocols favour SHA3 over SHA2) + * + * If liboqs is not linked (detected via __has_include() at compile + * time), the pq_* entry points return a JSON-shaped error string so callers + * fail loudly rather than silently fall back to classical schemes: + * {"error":"liboqs not linked, post-quantum primitives unavailable"} + * + * The hybrid handshake pairs X25519 with Kyber-768 per NIST PQ guidance and + * CNSA 2.0. Combined shared secret is HKDF-SHA256(x25519_ss || kyber_ss). + * Even if Kyber falls, X25519 holds; if X25519 falls under quantum attack, + * Kyber holds. SHA3-256 also remains usable independent of liboqs (the + * Keccak permutation is PQ-OK as a primitive). */ + +el_val_t pq_keygen_signature(void); +el_val_t pq_sign(el_val_t secret_key_hex, el_val_t message); +el_val_t pq_verify(el_val_t public_key_hex, el_val_t message, el_val_t signature_hex); + +el_val_t pq_kem_keygen(void); +el_val_t pq_kem_encaps(el_val_t public_key_hex); +el_val_t pq_kem_decaps(el_val_t secret_key_hex, el_val_t ciphertext_hex); + +el_val_t pq_hybrid_keygen(void); +el_val_t pq_hybrid_handshake(el_val_t remote_pub_combined); + +el_val_t sha3_256_hex(el_val_t input); + +/* ── AEAD: AES-256-GCM (libcrypto-backed) ─────────────────────────────────── + * Symmetric authenticated encryption used to wrap envelopes after a KEM + * handshake. Caller MUST supply a 32-byte key (64 hex chars) — typically the + * Kyber-768 / hybrid shared_secret, optionally normalized via SHA3-256. + * + * aead_encrypt returns a JSON map {"nonce":"...","ciphertext":"..."} where + * ciphertext is the AES-256-GCM output with the 16-byte auth tag appended. + * Nonce is a fresh 12-byte CSPRNG draw — callers never pick the nonce, which + * structurally rules out the GCM nonce-reuse footgun. + * + * aead_decrypt returns the plaintext String, or "" on any failure (including + * auth-tag mismatch). Callers MUST check for "" before trusting the result. */ +el_val_t aead_encrypt(el_val_t key_hex, el_val_t plaintext); +el_val_t aead_decrypt(el_val_t key_hex, el_val_t nonce_hex, el_val_t ciphertext_hex); + +/* ── Native VM builtin aliases (for compiled El source) ───────────────────── + * These match the El VM's native_* builtins so that El source compiled + * to C can call the same names without modification. */ + +el_val_t native_list_get(el_val_t list, el_val_t index); +el_val_t native_list_len(el_val_t list); +el_val_t native_list_append(el_val_t list, el_val_t elem); +el_val_t native_list_empty(void); +el_val_t native_list_clone(el_val_t list); +el_val_t native_string_chars(el_val_t s); +el_val_t native_int_to_str(el_val_t n); + +/* ── Method-call shorthand aliases ────────────────────────────────────────── + * The El method-call convention `obj.method(args)` compiles to + * `method(obj, args)`. These aliases expose the runtime functions under + * the short names that result from method calls in El source. + * + * Example: `myList.append(x)` → `append(myList, x)` (calls this alias) + * `myList.len()` → `len(myList)` (calls this alias) */ + +el_val_t append(el_val_t list, el_val_t elem); /* el_list_append */ +el_val_t len(el_val_t list); /* el_list_len */ +el_val_t get(el_val_t list, el_val_t index); /* el_list_get */ +el_val_t map_get(el_val_t map, el_val_t key); /* el_map_get */ +el_val_t map_set(el_val_t map, el_val_t key, el_val_t value); /* el_map_set */ + +/* ── OTLP/HTTP Observability ─────────────────────────────────────────────── */ +/* See bottom of el_runtime.c for the implementation. + * Configured by env vars OTLP_ENDPOINT, OTEL_SERVICE_NAME, OTEL_SERVICE_VERSION. + * No-op when OTLP_ENDPOINT is unset. Drop-on-failure semantics. */ +/* ── Subprocess execution ────────────────────────────────────────────────── */ +el_val_t exec_command(el_val_t cmd); /* run shell command, return exit code */ +el_val_t exec_capture(el_val_t cmd); /* run shell command, capture stdout */ +el_val_t exec(el_val_t cmd); /* exec(cmd) → stdout String (30s timeout) */ +el_val_t exec_bg(el_val_t cmd); /* exec_bg(cmd) → PID String (non-blocking) */ + +/* ── Stdout redirection (used by compiler JS pipeline) ───────────────────── */ +el_val_t stdout_to_file(el_val_t path); /* redirect process stdout to a file */ +el_val_t stdout_restore(void); /* restore process stdout to terminal */ + +el_val_t emit_log(el_val_t level, el_val_t msg, el_val_t fields_json); +el_val_t emit_metric(el_val_t name, el_val_t value, el_val_t tags_json); +el_val_t trace_span_start(el_val_t name); +el_val_t trace_span_end(el_val_t span_handle); +el_val_t emit_event(el_val_t name, el_val_t duration_ms); + +el_val_t __thread_create(el_val_t fn_name_v, el_val_t arg_v); +el_val_t __thread_join(el_val_t tid_v); + +/* ── __ prefixed aliases (self-hosting compiler ABI) ───────────────────────── + * The El self-hosting compiler emits calls to __-prefixed names. These are + * forwarding wrappers around the existing el_runtime functions above. */ + +/* I/O */ +el_val_t __println(el_val_t s); +el_val_t __print(el_val_t s); +el_val_t __readline(void); + +/* String */ +el_val_t __int_to_str(el_val_t n); +el_val_t __str_to_int(el_val_t s); +el_val_t __float_to_str(el_val_t f); +el_val_t __str_to_float(el_val_t s); +el_val_t __str_len(el_val_t s); +el_val_t __str_char_at(el_val_t s, el_val_t i); +el_val_t __str_cmp(el_val_t a, el_val_t b); +el_val_t __str_ncmp(el_val_t a, el_val_t b, el_val_t n); +el_val_t __str_concat_raw(el_val_t a, el_val_t b); +el_val_t __str_slice_raw(el_val_t s, el_val_t start, el_val_t end); +el_val_t __str_alloc(el_val_t n); +el_val_t __str_set_char(el_val_t s, el_val_t i, el_val_t c); + +/* URL encoding */ +el_val_t __url_encode(el_val_t s); +el_val_t __url_decode(el_val_t s); + +/* Environment */ +el_val_t __env_get(el_val_t key); + +/* Subprocess */ +el_val_t __exec(el_val_t cmd); +el_val_t __exec_bg(el_val_t cmd); + +/* Process */ +el_val_t __exit_program(el_val_t code); + +/* Filesystem */ +el_val_t __fs_exists(el_val_t path); +el_val_t __fs_mkdir(el_val_t path); +el_val_t __fs_read(el_val_t path); +el_val_t __fs_write(el_val_t path, el_val_t content); +el_val_t __fs_write_bytes(el_val_t path, el_val_t bytes, el_val_t n); +el_val_t __fs_list_raw(el_val_t path); + +/* HTTP server */ +el_val_t __http_response(el_val_t status, el_val_t headers_json, el_val_t body); +el_val_t __http_serve(el_val_t port, el_val_t handler); +el_val_t __http_serve_v2(el_val_t port, el_val_t handler); + +/* HTTP conn fd / SSE (weak; overridden by el_seed.c when linked together) */ +el_val_t __http_conn_fd(void); +el_val_t __http_sse_open(el_val_t conn_id); +el_val_t __http_sse_send(el_val_t conn_id, el_val_t data); +el_val_t __http_sse_close(el_val_t conn_id); + +/* HTTP client (requires HAVE_CURL; stubs provided for no-curl builds) */ +el_val_t __http_do(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_map, el_val_t timeout_ms); +el_val_t __http_do_map(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t timeout_ms); +el_val_t __http_do_map_to_file(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t output_path); + +/* JSON */ +el_val_t __json_array_get(el_val_t json, el_val_t index); +el_val_t __json_array_get_string(el_val_t json, el_val_t index); +el_val_t __json_array_len(el_val_t json); +el_val_t __json_get(el_val_t json, el_val_t key); +el_val_t __json_get_raw(el_val_t json, el_val_t key); +el_val_t __json_set(el_val_t json, el_val_t key, el_val_t value); +el_val_t __json_parse_map(el_val_t json_str); +el_val_t __json_stringify_val(el_val_t val); + +/* Hashing */ +el_val_t __sha256_hex(el_val_t s); + +/* State K/V */ +el_val_t __state_del(el_val_t key); +el_val_t __state_get(el_val_t key); +el_val_t __state_keys(void); +el_val_t __state_set(el_val_t key, el_val_t val); + +/* UUID */ +el_val_t __uuid_v4(void); + +/* Args */ +el_val_t __args_json(void); + +#ifdef __cplusplus +} +#endif diff --git a/ui/examples/native-hello-android/app/src/main/jni/el_seed.c b/ui/examples/native-hello-android/app/src/main/jni/el_seed.c new file mode 100644 index 0000000..fc9fbba --- /dev/null +++ b/ui/examples/native-hello-android/app/src/main/jni/el_seed.c @@ -0,0 +1,1942 @@ +/* + * el_seed.c — El language seed runtime: minimal C OS boundary + * + * This file exposes all OS-boundary primitives that El programs need, under + * the __ prefix convention. It is self-contained: all allocators, arena + * management, and el_request_start / el_request_end are defined here. + * + * Threading: __thread_create / __thread_join use dlsym(RTLD_DEFAULT) to look + * up El function symbols at runtime. This is the foundation of El's parallelism. + * + * Link: cc -std=c11 -I el-compiler/runtime -lcurl -lpthread \ + * -o .c el_seed.c + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "el_seed.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* ── Private allocator ───────────────────────────────────────────────────── */ +/* + * el_seed.c carries its own arena for per-request allocation tracking. + * The arena is reset at el_request_start / el_request_end, which are defined + * below and delegate to seed_request_start / seed_request_end. + */ + +#define SEED_ARENA_INITIAL 512 + +typedef struct { + char** ptrs; + size_t count; + size_t cap; +} SeedArena; + +static _Thread_local SeedArena _seed_arena = {NULL, 0, 0}; +static _Thread_local int _seed_arena_on = 0; + +static void seed_arena_track(char* p) { + if (!_seed_arena_on || !p) return; + if (_seed_arena.count >= _seed_arena.cap) { + size_t nc = _seed_arena.cap == 0 ? SEED_ARENA_INITIAL : _seed_arena.cap * 2; + char** g = realloc(_seed_arena.ptrs, nc * sizeof(char*)); + if (!g) return; + _seed_arena.ptrs = g; + _seed_arena.cap = nc; + } + _seed_arena.ptrs[_seed_arena.count++] = p; +} + +static void seed_request_start(void) { + _seed_arena.count = 0; + _seed_arena_on = 1; +} + +static void seed_request_end(void) { + _seed_arena_on = 0; + for (size_t i = 0; i < _seed_arena.count; i++) free(_seed_arena.ptrs[i]); + _seed_arena.count = 0; +} + +/* el_request_start / el_request_end — formerly defined in el_runtime.c. + * Now self-contained in el_seed.c, delegating to the seed arena. */ +void el_request_start(void) { seed_request_start(); } +void el_request_end(void) { seed_request_end(); } + +/* Persistent alloc — bypasses arena (state, engram internals). */ +static char* seed_strdup_persist(const char* s) { + if (!s) return strdup(""); + return strdup(s); +} + +static char* seed_strdup(const char* s) { + char* p = strdup(s ? s : ""); + seed_arena_track(p); + return p; +} + +static char* seed_strbuf(size_t n) { + char* p = malloc(n + 1); + if (!p) { fputs("el_seed: out of memory\n", stderr); exit(1); } + p[0] = '\0'; + seed_arena_track(p); + return p; +} + +static el_val_t seed_wrap_str(char* s) { return EL_STR(s); } + +/* ── String primitives ───────────────────────────────────────────────────── */ + +el_val_t __str_len(el_val_t s) { + const char* p = EL_CSTR(s); + if (!p) return 0; + return (el_val_t)strlen(p); +} + +el_val_t __str_char_at(el_val_t s, el_val_t i) { + const char* p = EL_CSTR(s); + if (!p) return 0; + int64_t len = (int64_t)strlen(p); + int64_t idx = (int64_t)i; + if (idx < 0 || idx >= len) return 0; + return (el_val_t)(unsigned char)p[idx]; +} + +el_val_t __str_alloc(el_val_t n) { + int64_t sz = (int64_t)n; + if (sz < 0) sz = 0; + char* buf = seed_strbuf((size_t)sz); + memset(buf, 0, (size_t)sz + 1); + return seed_wrap_str(buf); +} + +el_val_t __str_set_char(el_val_t s, el_val_t i, el_val_t c) { + char* p = (char*)(uintptr_t)s; + if (!p) return s; + int64_t len = (int64_t)strlen(p); + int64_t idx = (int64_t)i; + if (idx < 0 || idx >= len) return s; + p[idx] = (char)(unsigned char)(int64_t)c; + return s; +} + +el_val_t __str_cmp(el_val_t a, el_val_t b) { + const char* sa = EL_CSTR(a); + const char* sb = EL_CSTR(b); + if (!sa) sa = ""; + if (!sb) sb = ""; + return (el_val_t)strcmp(sa, sb); +} + +el_val_t __str_ncmp(el_val_t a, el_val_t b, el_val_t n) { + const char* sa = EL_CSTR(a); + const char* sb = EL_CSTR(b); + if (!sa) sa = ""; + if (!sb) sb = ""; + return (el_val_t)strncmp(sa, sb, (size_t)(int64_t)n); +} + +el_val_t __str_concat_raw(el_val_t a, el_val_t b) { + const char* sa = EL_CSTR(a); + const char* sb = EL_CSTR(b); + if (!sa) sa = ""; + if (!sb) sb = ""; + size_t la = strlen(sa), lb = strlen(sb); + char* out = seed_strbuf(la + lb); + memcpy(out, sa, la); + memcpy(out + la, sb, lb); + out[la + lb] = '\0'; + return seed_wrap_str(out); +} + +el_val_t __str_slice_raw(el_val_t s, el_val_t start, el_val_t end) { + const char* p = EL_CSTR(s); + if (!p) return seed_wrap_str(seed_strdup("")); + int64_t len = (int64_t)strlen(p); + int64_t st = (int64_t)start; + int64_t en = (int64_t)end; + if (st < 0) st = 0; + if (en > len) en = len; + if (st >= en) return seed_wrap_str(seed_strdup("")); + int64_t sz = en - st; + char* out = seed_strbuf((size_t)sz); + memcpy(out, p + st, (size_t)sz); + out[sz] = '\0'; + return seed_wrap_str(out); +} + +el_val_t __int_to_str(el_val_t n) { + char buf[32]; + snprintf(buf, sizeof(buf), "%lld", (long long)(int64_t)n); + return seed_wrap_str(seed_strdup(buf)); +} + +el_val_t __str_to_int(el_val_t s) { + const char* p = EL_CSTR(s); + if (!p) return 0; + return (el_val_t)atoll(p); +} + +el_val_t __float_to_str(el_val_t f) { + char buf[64]; + snprintf(buf, sizeof(buf), "%g", el_to_float(f)); + return seed_wrap_str(seed_strdup(buf)); +} + +el_val_t __str_to_float(el_val_t s) { + const char* p = EL_CSTR(s); + if (!p) return el_from_float(0.0); + return el_from_float(strtod(p, NULL)); +} + +/* ── I/O ─────────────────────────────────────────────────────────────────── */ + +void __println(el_val_t s) { + const char* p = EL_CSTR(s); + puts(p ? p : ""); +} + +void __print(el_val_t s) { + const char* p = EL_CSTR(s); + if (p) fputs(p, stdout); +} + +el_val_t __readline(void) { + char buf[4096]; + if (!fgets(buf, sizeof(buf), stdin)) return seed_wrap_str(seed_strdup("")); + size_t len = strlen(buf); + if (len > 0 && buf[len - 1] == '\n') buf[len - 1] = '\0'; + return seed_wrap_str(seed_strdup(buf)); +} + +/* ── Filesystem ──────────────────────────────────────────────────────────── */ + +el_val_t __fs_read(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p) return seed_wrap_str(seed_strdup("")); + FILE* f = fopen(p, "rb"); + if (!f) return seed_wrap_str(seed_strdup("")); + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + if (sz < 0) { fclose(f); return seed_wrap_str(seed_strdup("")); } + char* buf = seed_strbuf((size_t)sz); + size_t got = fread(buf, 1, (size_t)sz, f); + buf[got] = '\0'; + fclose(f); + return seed_wrap_str(buf); +} + +el_val_t __fs_write(el_val_t path, el_val_t content) { + const char* p = EL_CSTR(path); + const char* c = EL_CSTR(content); + if (!p || !c) return 0; + FILE* f = fopen(p, "wb"); + if (!f) return 0; + size_t n = strlen(c); + size_t w = fwrite(c, 1, n, f); + fclose(f); + return w == n ? 1 : 0; +} + +el_val_t __fs_exists(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p || !*p) return 0; + struct stat st; + return (el_val_t)(stat(p, &st) == 0 ? 1 : 0); +} + +el_val_t __fs_list_raw(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p) return seed_wrap_str(seed_strdup("")); + DIR* d = opendir(p); + if (!d) return seed_wrap_str(seed_strdup("")); + /* Build newline-separated list of filenames. */ + size_t cap = 4096, len = 0; + char* buf = malloc(cap); + if (!buf) { closedir(d); return seed_wrap_str(seed_strdup("")); } + buf[0] = '\0'; + struct dirent* e; + while ((e = readdir(d)) != NULL) { + if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) continue; + size_t nlen = strlen(e->d_name); + while (len + nlen + 2 >= cap) { + cap *= 2; + char* g = realloc(buf, cap); + if (!g) { free(buf); closedir(d); return seed_wrap_str(seed_strdup("")); } + buf = g; + } + if (len > 0) buf[len++] = '\n'; + memcpy(buf + len, e->d_name, nlen); + len += nlen; + buf[len] = '\0'; + } + closedir(d); + seed_arena_track(buf); + return seed_wrap_str(buf); +} + +el_val_t __fs_mkdir(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p || !*p) return 0; + size_t n = strlen(p); + char* buf = malloc(n + 1); + if (!buf) return 0; + memcpy(buf, p, n + 1); + for (size_t i = 1; i <= n; i++) { + if (buf[i] == '/' || buf[i] == '\0') { + char saved = buf[i]; + buf[i] = '\0'; + if (buf[0] != '\0') { + if (mkdir(buf, 0755) != 0 && errno != EEXIST) { + struct stat st; + if (stat(buf, &st) != 0 || !S_ISDIR(st.st_mode)) { + free(buf); return 0; + } + } + } + buf[i] = saved; + } + } + free(buf); + return 1; +} + +el_val_t __fs_write_bytes(el_val_t path, el_val_t bytes, el_val_t n) { + const char* p = EL_CSTR(path); + const char* b = EL_CSTR(bytes); + int64_t sz = (int64_t)n; + if (!p || !b || sz < 0) return 0; + FILE* f = fopen(p, "wb"); + if (!f) return 0; + size_t written = (sz > 0) ? fwrite(b, 1, (size_t)sz, f) : 0; + int ok1 = (fflush(f) == 0); + int ok2 = (fclose(f) == 0); + if (!ok1 || !ok2 || written != (size_t)sz) { remove(p); return 0; } + return 1; +} + +/* ── HTTP client ─────────────────────────────────────────────────────────── */ + +typedef struct { + char* data; + size_t len; + size_t cap; +} SeedHttpBuf; + +static void seed_httpbuf_init(SeedHttpBuf* b) { + b->cap = 1024; b->len = 0; + b->data = malloc(b->cap); + if (!b->data) { fputs("el_seed: out of memory\n", stderr); exit(1); } + b->data[0] = '\0'; +} + +static void seed_httpbuf_append(SeedHttpBuf* b, const void* src, size_t n) { + while (b->len + n + 1 > b->cap) b->cap *= 2; + b->data = realloc(b->data, b->cap); + if (!b->data) { fputs("el_seed: out of memory\n", stderr); exit(1); } + memcpy(b->data + b->len, src, n); + b->len += n; + b->data[b->len] = '\0'; +} + +static size_t seed_http_write_cb(char* ptr, size_t size, size_t nmemb, void* ud) { + size_t n = size * nmemb; + seed_httpbuf_append((SeedHttpBuf*)ud, ptr, n); + return n; +} + +/* Build a curl_slist from a JSON object string of header name:value pairs. */ +static struct curl_slist* seed_headers_from_json(const char* hj) { + struct curl_slist* h = NULL; + if (!hj || !*hj) return NULL; + /* Walk key:value pairs at depth 1. Simple parser — same logic as json_find_key + * in el_runtime.c but adapted for building curl headers. */ + const char* p = hj; + while (*p && *p != '{') p++; + if (*p == '{') p++; + while (*p) { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p == '}' || *p == '\0') break; + if (*p != '"') break; + /* Parse key */ + p++; + const char* ks = p; + while (*p && *p != '"') { if (*p == '\\') p++; p++; } + size_t klen = (size_t)(p - ks); + if (*p == '"') p++; + /* Skip : */ + while (*p == ' ' || *p == ':') p++; + /* Parse value */ + if (*p != '"') break; + p++; + const char* vs = p; + while (*p && *p != '"') { if (*p == '\\') p++; p++; } + size_t vlen = (size_t)(p - vs); + if (*p == '"') p++; + /* Build "Key: Value" header line */ + size_t line_len = klen + 2 + vlen + 1; + char* line = malloc(line_len); + if (line) { + memcpy(line, ks, klen); + memcpy(line + klen, ": ", 2); + memcpy(line + klen + 2, vs, vlen); + line[klen + 2 + vlen] = '\0'; + h = curl_slist_append(h, line); + free(line); + } + } + return h; +} + +static el_val_t seed_http_error_json(const char* msg) { + if (!msg) msg = "unknown error"; + size_t n = strlen(msg) * 6 + 20; + char* buf = seed_strbuf(n); + /* Simple escape: replace " with \" */ + char* d = buf; + *d++ = '{'; *d++ = '"'; *d++ = 'e'; *d++ = 'r'; *d++ = 'r'; + *d++ = 'o'; *d++ = 'r'; *d++ = '"'; *d++ = ':'; *d++ = '"'; + for (const char* s = msg; *s; s++) { + if (*s == '"' || *s == '\\') *d++ = '\\'; + *d++ = *s; + } + *d++ = '"'; *d++ = '}'; *d = '\0'; + return seed_wrap_str(buf); +} + +el_val_t __http_do(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t timeout_ms) { + const char* m = EL_CSTR(method); + const char* u = EL_CSTR(url); + const char* b = EL_CSTR(body); + const char* hj = EL_CSTR(headers_json); + int64_t tms = (int64_t)timeout_ms; + if (tms <= 0) tms = 60000; + + if (!u || !*u) return seed_http_error_json("empty url"); + + CURL* c = curl_easy_init(); + if (!c) return seed_http_error_json("curl_easy_init failed"); + + SeedHttpBuf rb; seed_httpbuf_init(&rb); + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + + curl_easy_setopt(c, CURLOPT_URL, u); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, seed_http_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, &rb); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, (long)tms); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-seed/1.0"); + + struct curl_slist* hdrs = seed_headers_from_json(hj); + if (hdrs) curl_easy_setopt(c, CURLOPT_HTTPHEADER, hdrs); + + if (m && strcmp(m, "POST") == 0) { + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, b ? b : ""); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(b ? strlen(b) : 0)); + } else if (m && strcmp(m, "PUT") == 0) { + curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, "PUT"); + if (b) { + curl_easy_setopt(c, CURLOPT_POSTFIELDS, b); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)strlen(b)); + } + } else if (m && strcmp(m, "DELETE") == 0) { + curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, "DELETE"); + } else if (m && strcmp(m, "PATCH") == 0) { + curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, "PATCH"); + if (b) { + curl_easy_setopt(c, CURLOPT_POSTFIELDS, b); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)strlen(b)); + } + } + /* GET is the default */ + + CURLcode rc = curl_easy_perform(c); + if (hdrs) curl_slist_free_all(hdrs); + curl_easy_cleanup(c); + + if (rc != CURLE_OK) { + free(rb.data); + const char* em = errbuf[0] ? errbuf : curl_easy_strerror(rc); + return seed_http_error_json(em); + } + + seed_arena_track(rb.data); + return seed_wrap_str(rb.data); +} + +static size_t seed_http_file_write_cb(char* ptr, size_t size, size_t nmemb, void* ud) { + return fwrite(ptr, size, nmemb, (FILE*)ud); +} + +el_val_t __http_do_to_file(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t out_path) { + const char* m = EL_CSTR(method); + const char* u = EL_CSTR(url); + const char* b = EL_CSTR(body); + const char* hj = EL_CSTR(headers_json); + const char* op = EL_CSTR(out_path); + + if (!u || !*u || !op || !*op) return 0; + FILE* f = fopen(op, "wb"); + if (!f) return 0; + + CURL* c = curl_easy_init(); + if (!c) { fclose(f); remove(op); return 0; } + + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + curl_easy_setopt(c, CURLOPT_URL, u); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, seed_http_file_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, f); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, 60000L); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-seed/1.0"); + + struct curl_slist* hdrs = seed_headers_from_json(hj); + if (hdrs) curl_easy_setopt(c, CURLOPT_HTTPHEADER, hdrs); + + if (m && strcmp(m, "POST") == 0) { + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, b ? b : ""); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(b ? strlen(b) : 0)); + } + + CURLcode rc = curl_easy_perform(c); + if (hdrs) curl_slist_free_all(hdrs); + curl_easy_cleanup(c); + + int ok1 = (fflush(f) == 0); + int ok2 = (fclose(f) == 0); + + if (rc != CURLE_OK || !ok1 || !ok2) { remove(op); return 0; } + return 1; +} + +/* ── HTTP server ─────────────────────────────────────────────────────────── */ +/* Delegate to el_runtime.c's http_serve / http_serve_v2 via the existing + * http_set_handler mechanism. */ + +/* Forward declarations for el_runtime.c functions called from el_seed.c. + * A full #include "el_runtime.h" causes redefinition conflicts (el_seed.h + * already defines el_to_float, el_from_float, and several __ wrappers). + * Declare only the symbols actually used here. */ + +/* HTTP server */ +el_val_t http_serve(el_val_t port, el_val_t handler); +el_val_t http_serve_v2(el_val_t port, el_val_t handler); +el_val_t http_response(el_val_t status, el_val_t headers_json, el_val_t body); + +/* JSON */ +el_val_t json_get(el_val_t json, el_val_t key); +el_val_t json_get_raw(el_val_t json_str, el_val_t key); +el_val_t json_parse(el_val_t s); +el_val_t json_stringify(el_val_t v); +el_val_t json_array_len(el_val_t json_str); +el_val_t json_array_get(el_val_t json_str, el_val_t index); +el_val_t json_array_get_string(el_val_t json_str, el_val_t index); +el_val_t json_get_string(el_val_t json_str, el_val_t key); +el_val_t json_get_int(el_val_t json_str, el_val_t key); +el_val_t json_get_float(el_val_t json_str, el_val_t key); +el_val_t json_get_bool(el_val_t json_str, el_val_t key); +el_val_t json_set(el_val_t json_str, el_val_t key, el_val_t value); + +/* URL / HTML */ +el_val_t url_encode(el_val_t s); +el_val_t url_decode(el_val_t s); +el_val_t el_html_sanitize(el_val_t input_html, el_val_t allowlist_json); + +/* State K/V */ +el_val_t state_set(el_val_t key, el_val_t value); +el_val_t state_get(el_val_t key); +el_val_t state_del(el_val_t key); +el_val_t state_keys(void); +el_val_t state_get_or(el_val_t key, el_val_t default_val); + +/* Engram graph */ +el_val_t engram_node(el_val_t content, el_val_t node_type, el_val_t salience); +el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags_json); +el_val_t engram_node_layered(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags_json, el_val_t layer_id); +el_val_t engram_add_layer(el_val_t name, el_val_t priority, el_val_t suppressible, + el_val_t transparent, el_val_t injectable); +el_val_t engram_remove_layer(el_val_t layer_id); +el_val_t engram_list_layers(void); +el_val_t engram_get_node(el_val_t id); +void engram_strengthen(el_val_t node_id); +void engram_forget(el_val_t node_id); +el_val_t engram_node_count(void); +el_val_t engram_search(el_val_t query, el_val_t limit); +el_val_t engram_scan_nodes(el_val_t limit, el_val_t offset); +void engram_connect(el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t relation); +el_val_t engram_edge_between(el_val_t from_id, el_val_t to_id); +el_val_t engram_neighbors(el_val_t node_id); +el_val_t engram_neighbors_filtered(el_val_t node_id, el_val_t max_depth, el_val_t direction); +el_val_t engram_edge_count(void); +el_val_t engram_activate(el_val_t query, el_val_t depth); +el_val_t engram_save(el_val_t path); +el_val_t engram_load(el_val_t path); +el_val_t engram_get_node_json(el_val_t id); +el_val_t engram_search_json(el_val_t query, el_val_t limit); +el_val_t engram_scan_nodes_json(el_val_t limit, el_val_t offset); +el_val_t engram_scan_nodes_by_type_json(el_val_t node_type, el_val_t limit, el_val_t offset); +el_val_t engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction); +el_val_t engram_activate_json(el_val_t query, el_val_t depth); +el_val_t engram_stats_json(void); +el_val_t engram_list_layers_json(void); +el_val_t engram_compile_layered_json(el_val_t intent, el_val_t depth); + +void __http_serve(el_val_t port, el_val_t handler_name) { + http_serve(port, handler_name); +} + +void __http_serve_v2(el_val_t port, el_val_t handler_name) { + http_serve_v2(port, handler_name); +} + +el_val_t __http_response(el_val_t status, el_val_t headers_json, el_val_t body) { + return http_response(status, headers_json, body); +} + +/* ── HTTP SSE — Server-Sent Events streaming ─────────────────────────────── */ +/* + * Thread-local file descriptor stashed by http_worker_v2 before calling the + * El handler. El SSE builtins read this to get the raw socket fd. + * + * Lifecycle: + * http_worker_v2 sets _tl_http_conn_fd = fd (via el_seed_set_http_conn_fd) + * El handler calls __http_conn_fd() → receives that fd + * El handler calls __http_sse_open(fd) → sends SSE headers, keeps fd open + * El handler calls __http_sse_send(fd, data) → writes "data: ...\n\n" + * El handler calls __http_sse_close(fd) → closes the fd + * El handler returns "__sse__" sentinel → http_worker_v2 does NOT close fd + * + * The -1 value means no current connection (guard against misuse outside + * a handler context). + */ +static __thread int _tl_http_conn_fd = -1; + +/* Called by el_runtime.c's http_worker_v2 — not part of the El ABI. */ +void el_seed_set_http_conn_fd(int fd) { + _tl_http_conn_fd = fd; +} + +/* __http_conn_fd() — returns the raw fd for the current HTTP connection. + * Valid only inside an http_serve_v2 handler before it returns. */ +el_val_t __http_conn_fd(void) { + return EL_INT(_tl_http_conn_fd); +} + +/* __http_sse_open(fd) — sends SSE response headers on fd, keeping it open. + * Returns 1 on success, 0 on write failure. */ +el_val_t __http_sse_open(el_val_t conn_id) { + int fd = (int)(int64_t)conn_id; + if (fd < 0) return 0; + static const char sse_headers[] = + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/event-stream\r\n" + "Cache-Control: no-cache\r\n" + "Connection: keep-alive\r\n" + "Access-Control-Allow-Origin: *\r\n" + "\r\n"; + size_t n = sizeof(sse_headers) - 1; /* exclude NUL */ + size_t sent = 0; + while (sent < n) { + ssize_t w = write(fd, sse_headers + sent, n - sent); + if (w <= 0) return 0; + sent += (size_t)w; + } + return 1; +} + +/* __http_sse_send(fd, data) — writes one SSE event frame: "data: \n\n". + * data must not contain newlines. Returns 1 on success, 0 on client disconnect. */ +el_val_t __http_sse_send(el_val_t conn_id, el_val_t data) { + int fd = (int)(int64_t)conn_id; + if (fd < 0) return 0; + const char* s = EL_CSTR(data); + if (!s) s = ""; + /* Build "data: \n\n" in a single buffer for one write call. */ + size_t prefix_len = 6; /* "data: " */ + size_t slen = strlen(s); + size_t total = prefix_len + slen + 2; /* + "\n\n" */ + char* buf = malloc(total + 1); + if (!buf) return 0; + memcpy(buf, "data: ", 6); + memcpy(buf + 6, s, slen); + buf[6 + slen] = '\n'; + buf[6 + slen + 1] = '\n'; + buf[total] = '\0'; + size_t sent = 0; + int ok = 1; + while (sent < total) { + ssize_t w = write(fd, buf + sent, total - sent); + if (w <= 0) { ok = 0; break; } + sent += (size_t)w; + } + free(buf); + return ok ? 1 : 0; +} + +/* __http_sse_close(fd) — closes the SSE connection fd. */ +el_val_t __http_sse_close(el_val_t conn_id) { + int fd = (int)(int64_t)conn_id; + if (fd < 0) return 0; + close(fd); + return 1; +} + +/* ── Threading ───────────────────────────────────────────────────────────── */ +/* + * Design: + * Static ElThread table (max EL_SEED_MAX_THREADS entries). + * __thread_create: pick a free slot, store fn_name + arg, launch pthread. + * Worker: dlsym(RTLD_DEFAULT, fn_name) → call as el_val_t fn(el_val_t). + * Store result string in slot.result. + * __thread_join: pthread_join, return stored result string. + * + * Thread handle is the slot index (0..EL_SEED_MAX_THREADS-1). + * Returns -1 on failure (no slots, dlsym failure, pthread_create failure). + * + * Each slot is guarded by its own mutex so join/create on different handles + * never contend. + */ + +#define EL_SEED_MAX_THREADS 64 + +typedef el_val_t (*ElFn1)(el_val_t); + +typedef struct { + int in_use; + char* fn_name; + char* arg; + char* result; + pthread_t tid; + int done; /* set to 1 by worker before exit */ +} ElThread; + +static ElThread _el_threads[EL_SEED_MAX_THREADS]; +static pthread_mutex_t _el_thread_mu = PTHREAD_MUTEX_INITIALIZER; + +typedef struct { + int slot; +} ElThreadArg; + +static void* el_thread_worker(void* raw) { + ElThreadArg* ta = (ElThreadArg*)raw; + int slot = ta->slot; + free(ta); + + ElThread* t = &_el_threads[slot]; + + /* Resolve the El function symbol in the running binary. */ + void* sym = dlsym(RTLD_DEFAULT, t->fn_name); + if (!sym) { + pthread_mutex_lock(&_el_thread_mu); + t->result = seed_strdup_persist(""); + t->done = 1; + pthread_mutex_unlock(&_el_thread_mu); + return NULL; + } + + ElFn1 fn = (ElFn1)sym; + + /* Call the El function with the string argument. */ + el_val_t arg_val = EL_STR(t->arg); + el_val_t ret = fn(arg_val); + + /* Persist the result string. */ + const char* rs = EL_CSTR(ret); + char* stored = seed_strdup_persist(rs ? rs : ""); + + pthread_mutex_lock(&_el_thread_mu); + t->result = stored; + t->done = 1; + pthread_mutex_unlock(&_el_thread_mu); + + return NULL; +} + +el_val_t __thread_create(el_val_t fn_name, el_val_t arg) { + const char* fname = EL_CSTR(fn_name); + const char* astr = EL_CSTR(arg); + if (!fname || !*fname) return (el_val_t)(int64_t)-1; + if (!astr) astr = ""; + + pthread_mutex_lock(&_el_thread_mu); + int slot = -1; + for (int i = 0; i < EL_SEED_MAX_THREADS; i++) { + if (!_el_threads[i].in_use) { slot = i; break; } + } + if (slot < 0) { + pthread_mutex_unlock(&_el_thread_mu); + return (el_val_t)(int64_t)-1; + } + + ElThread* t = &_el_threads[slot]; + t->in_use = 1; + t->done = 0; + t->fn_name = seed_strdup_persist(fname); + t->arg = seed_strdup_persist(astr); + t->result = NULL; + pthread_mutex_unlock(&_el_thread_mu); + + ElThreadArg* ta = malloc(sizeof(ElThreadArg)); + if (!ta) { + pthread_mutex_lock(&_el_thread_mu); + free(t->fn_name); free(t->arg); + t->in_use = 0; + pthread_mutex_unlock(&_el_thread_mu); + return (el_val_t)(int64_t)-1; + } + ta->slot = slot; + + if (pthread_create(&t->tid, NULL, el_thread_worker, ta) != 0) { + free(ta); + pthread_mutex_lock(&_el_thread_mu); + free(t->fn_name); free(t->arg); + t->in_use = 0; + pthread_mutex_unlock(&_el_thread_mu); + return (el_val_t)(int64_t)-1; + } + + return (el_val_t)(int64_t)slot; +} + +el_val_t __thread_join(el_val_t tid) { + int64_t slot = (int64_t)tid; + if (slot < 0 || slot >= EL_SEED_MAX_THREADS) return seed_wrap_str(seed_strdup("")); + + ElThread* t = &_el_threads[slot]; + + pthread_mutex_lock(&_el_thread_mu); + if (!t->in_use) { + pthread_mutex_unlock(&_el_thread_mu); + return seed_wrap_str(seed_strdup("")); + } + pthread_mutex_unlock(&_el_thread_mu); + + /* Wait for thread to finish. */ + pthread_join(t->tid, NULL); + + pthread_mutex_lock(&_el_thread_mu); + char* res = t->result ? t->result : ""; + char* copy = seed_strdup(res); /* arena-tracked for caller lifetime */ + free(t->fn_name); + free(t->arg); + if (t->result) { free(t->result); t->result = NULL; } + t->fn_name = NULL; t->arg = NULL; + t->in_use = 0; + t->done = 0; + pthread_mutex_unlock(&_el_thread_mu); + + return seed_wrap_str(copy); +} + +/* ── Mutex pool ──────────────────────────────────────────────────────────── */ + +#define EL_SEED_MAX_MUTEXES 256 + +static pthread_mutex_t _el_mutexes[EL_SEED_MAX_MUTEXES]; +static int _el_mutex_init[EL_SEED_MAX_MUTEXES]; +static int _el_mutex_used[EL_SEED_MAX_MUTEXES]; +static pthread_mutex_t _el_mutex_pool_mu = PTHREAD_MUTEX_INITIALIZER; + +el_val_t __mutex_new(void) { + pthread_mutex_lock(&_el_mutex_pool_mu); + int slot = -1; + for (int i = 0; i < EL_SEED_MAX_MUTEXES; i++) { + if (!_el_mutex_used[i]) { slot = i; break; } + } + if (slot < 0) { + pthread_mutex_unlock(&_el_mutex_pool_mu); + return (el_val_t)(int64_t)-1; + } + _el_mutex_used[slot] = 1; + if (!_el_mutex_init[slot]) { + pthread_mutex_init(&_el_mutexes[slot], NULL); + _el_mutex_init[slot] = 1; + } + pthread_mutex_unlock(&_el_mutex_pool_mu); + return (el_val_t)(int64_t)slot; +} + +void __mutex_lock(el_val_t m) { + int64_t slot = (int64_t)m; + if (slot < 0 || slot >= EL_SEED_MAX_MUTEXES) return; + if (!_el_mutex_init[slot]) return; + pthread_mutex_lock(&_el_mutexes[slot]); +} + +void __mutex_unlock(el_val_t m) { + int64_t slot = (int64_t)m; + if (slot < 0 || slot >= EL_SEED_MAX_MUTEXES) return; + if (!_el_mutex_init[slot]) return; + pthread_mutex_unlock(&_el_mutexes[slot]); +} + +/* ── Subprocess ──────────────────────────────────────────────────────────── */ + +el_val_t __exec(el_val_t cmd) { + const char* c = EL_CSTR(cmd); + if (!c) return seed_wrap_str(seed_strdup("")); + FILE* f = popen(c, "r"); + if (!f) return seed_wrap_str(seed_strdup("")); + size_t cap = 4096, len = 0; + char* buf = malloc(cap); + if (!buf) { pclose(f); return seed_wrap_str(seed_strdup("")); } + char tmp[4096]; + while (fgets(tmp, sizeof(tmp), f)) { + size_t n = strlen(tmp); + while (len + n + 1 > cap) { + cap *= 2; + char* g = realloc(buf, cap); + if (!g) { free(buf); pclose(f); return seed_wrap_str(seed_strdup("")); } + buf = g; + } + memcpy(buf + len, tmp, n); + len += n; + buf[len] = '\0'; + } + pclose(f); + seed_arena_track(buf); + return seed_wrap_str(buf); +} + +void __exec_bg(el_val_t cmd) { + const char* c = EL_CSTR(cmd); + if (!c) return; + /* Fork-free: run in background via system() with & appended. */ + size_t n = strlen(c); + char* s = malloc(n + 4); + if (!s) return; + memcpy(s, c, n); + memcpy(s + n, " &", 3); + system(s); + free(s); +} + +/* ── Environment and process ─────────────────────────────────────────────── */ + +el_val_t __env_get(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return seed_wrap_str(seed_strdup("")); + const char* v = getenv(k); + return seed_wrap_str(seed_strdup(v ? v : "")); +} + +void __exit_program(el_val_t code) { + exit((int)(int64_t)code); +} + +/* ── args_json ────────────────────────────────────────────────────────────── */ + +static int _seed_argc = 0; +static char** _seed_argv = NULL; + +void el_seed_init_args(int argc, char** argv) { + _seed_argc = argc; + _seed_argv = argv; +} + +el_val_t __args_json(void) { + /* Return ["arg1","arg2",...] as a JSON string. Skip argv[0] (program name). */ + size_t cap = 256, len = 0; + char* buf = malloc(cap); + if (!buf) return seed_wrap_str(seed_strdup("[]")); + buf[len++] = '['; + int first = 1; + for (int i = 1; i < _seed_argc; i++) { + const char* a = _seed_argv[i]; + /* Estimate: each arg needs at most strlen*6+4 bytes (worst case escape) */ + size_t need = strlen(a) * 6 + 8; + while (len + need + 2 > cap) { + cap *= 2; + char* g = realloc(buf, cap); + if (!g) { free(buf); return seed_wrap_str(seed_strdup("[]")); } + buf = g; + } + if (!first) buf[len++] = ','; + first = 0; + buf[len++] = '"'; + for (const char* p = a; *p; p++) { + unsigned char c = (unsigned char)*p; + if (c == '"') { buf[len++] = '\\'; buf[len++] = '"'; } + else if (c == '\\') { buf[len++] = '\\'; buf[len++] = '\\'; } + else if (c == '\n') { buf[len++] = '\\'; buf[len++] = 'n'; } + else if (c == '\r') { buf[len++] = '\\'; buf[len++] = 'r'; } + else if (c == '\t') { buf[len++] = '\\'; buf[len++] = 't'; } + else buf[len++] = (char)c; + } + buf[len++] = '"'; + } + buf[len++] = ']'; + buf[len] = '\0'; + seed_arena_track(buf); + return seed_wrap_str(buf); +} + +/* ── Time ────────────────────────────────────────────────────────────────── */ + +el_val_t __time_now_ns(void) { + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts) == 0) { + int64_t ns = (int64_t)ts.tv_sec * 1000000000LL + (int64_t)ts.tv_nsec; + return (el_val_t)ns; + } + struct timeval tv; + gettimeofday(&tv, NULL); + return (el_val_t)((int64_t)tv.tv_sec * 1000000000LL + (int64_t)tv.tv_usec * 1000LL); +} + +void __sleep_ms(el_val_t ms) { + int64_t m = (int64_t)ms; + if (m < 0) m = 0; + struct timespec ts; + ts.tv_sec = (time_t)(m / 1000LL); + ts.tv_nsec = (long)((m % 1000LL) * 1000000LL); + nanosleep(&ts, NULL); +} + +/* ── UUID ────────────────────────────────────────────────────────────────── */ + +static int _seed_uuid_seeded = 0; + +el_val_t __uuid_v4(void) { + if (!_seed_uuid_seeded) { + srand((unsigned)time(NULL) ^ (unsigned)(uintptr_t)&_seed_uuid_seeded); + _seed_uuid_seeded = 1; + } + unsigned char b[16]; + for (int i = 0; i < 16; i++) b[i] = (unsigned char)(rand() & 0xff); + b[6] = (b[6] & 0x0f) | 0x40; /* version 4 */ + b[8] = (b[8] & 0x3f) | 0x80; /* RFC 4122 variant */ + char buf[37]; + snprintf(buf, sizeof(buf), + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + b[0],b[1],b[2],b[3], b[4],b[5], b[6],b[7], + b[8],b[9], b[10],b[11],b[12],b[13],b[14],b[15]); + return seed_wrap_str(seed_strdup(buf)); +} + +/* ── Math ────────────────────────────────────────────────────────────────── */ + +el_val_t __sqrt_f(el_val_t f) { return el_from_float(sqrt(el_to_float(f))); } +el_val_t __log_f(el_val_t f) { return el_from_float(log10(el_to_float(f))); } +el_val_t __ln_f(el_val_t f) { return el_from_float(log(el_to_float(f))); } +el_val_t __sin_f(el_val_t f) { return el_from_float(sin(el_to_float(f))); } +el_val_t __cos_f(el_val_t f) { return el_from_float(cos(el_to_float(f))); } +el_val_t __pi_f(void) { return el_from_float(3.14159265358979323846); } + +/* ── JSON — thin wrappers around el_runtime.c implementations ────────────── */ + +el_val_t __json_get(el_val_t json, el_val_t key) { return json_get(json, key); } +el_val_t __json_get_raw(el_val_t json_str, el_val_t key) { return json_get_raw(json_str, key); } +el_val_t __json_parse(el_val_t s) { return json_parse(s); } +el_val_t __json_stringify(el_val_t v) { return json_stringify(v); } +el_val_t __json_parse_map(el_val_t json_str) { return json_parse(json_str); } +el_val_t __json_stringify_val(el_val_t val) { return json_stringify(val); } +el_val_t __json_array_len(el_val_t json_str) { return json_array_len(json_str); } +el_val_t __json_array_get(el_val_t json_str, el_val_t index) { return json_array_get(json_str, index); } +el_val_t __json_array_get_string(el_val_t json_str, el_val_t index) { return json_array_get_string(json_str, index); } +el_val_t __json_get_string(el_val_t json_str, el_val_t key) { return json_get_string(json_str, key); } +el_val_t __json_get_int(el_val_t json_str, el_val_t key) { return json_get_int(json_str, key); } +el_val_t __json_get_float(el_val_t json_str, el_val_t key) { return json_get_float(json_str, key); } +el_val_t __json_get_bool(el_val_t json_str, el_val_t key) { return json_get_bool(json_str, key); } +el_val_t __json_set(el_val_t json_str, el_val_t key, el_val_t value) { return json_set(json_str, key, value); } + +/* ── State K/V — thin wrappers ───────────────────────────────────────────── */ + +el_val_t __state_set(el_val_t key, el_val_t value) { return state_set(key, value); } +el_val_t __state_get(el_val_t key) { return state_get(key); } +el_val_t __state_del(el_val_t key) { return state_del(key); } +el_val_t __state_keys(void) { return state_keys(); } + +/* ── HTML/URL — thin wrappers ────────────────────────────────────────────── */ + +el_val_t __html_sanitize(el_val_t input_html, el_val_t allowlist_json) { + return el_html_sanitize(input_html, allowlist_json); +} + +el_val_t __url_encode(el_val_t s) { return url_encode(s); } +el_val_t __url_decode(el_val_t s) { return url_decode(s); } + +/* ── Engram — thin wrappers ──────────────────────────────────────────────── */ + +el_val_t __engram_node(el_val_t content, el_val_t node_type, el_val_t salience) { + return engram_node(content, node_type, salience); +} + +el_val_t __engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags) { + return engram_node_full(content, node_type, label, salience, importance, confidence, tier, tags); +} + +el_val_t __engram_node_layered(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t certainty, el_val_t confidence, + el_val_t status, el_val_t tags, el_val_t layer_id) { + return engram_node_layered(content, node_type, label, salience, certainty, confidence, + status, tags, layer_id); +} + +el_val_t __engram_add_layer(el_val_t name, el_val_t priority, el_val_t suppressible, + el_val_t transparent, el_val_t injectable) { + return engram_add_layer(name, priority, suppressible, transparent, injectable); +} + +el_val_t __engram_remove_layer(el_val_t layer_id) { return engram_remove_layer(layer_id); } +el_val_t __engram_list_layers(void) { return engram_list_layers(); } +el_val_t __engram_get_node(el_val_t id) { return engram_get_node(id); } +void __engram_strengthen(el_val_t node_id) { engram_strengthen(node_id); } +void __engram_forget(el_val_t node_id) { engram_forget(node_id); } +el_val_t __engram_node_count(void) { return engram_node_count(); } + +el_val_t __engram_search(el_val_t query, el_val_t limit) { return engram_search(query, limit); } +el_val_t __engram_scan_nodes(el_val_t limit, el_val_t offset) { return engram_scan_nodes(limit, offset); } + +void __engram_connect(el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t relation) { + engram_connect(from_id, to_id, weight, relation); +} + +el_val_t __engram_edge_between(el_val_t from_id, el_val_t to_id) { + return engram_edge_between(from_id, to_id); +} + +el_val_t __engram_neighbors(el_val_t node_id) { return engram_neighbors(node_id); } + +el_val_t __engram_neighbors_filtered(el_val_t node_id, el_val_t max_depth, el_val_t direction) { + return engram_neighbors_filtered(node_id, max_depth, direction); +} + +el_val_t __engram_edge_count(void) { return engram_edge_count(); } + +el_val_t __engram_activate(el_val_t query, el_val_t depth) { return engram_activate(query, depth); } +el_val_t __engram_save(el_val_t path) { return engram_save(path); } +el_val_t __engram_load(el_val_t path) { return engram_load(path); } + +el_val_t __engram_get_node_json(el_val_t id) { return engram_get_node_json(id); } + +el_val_t __engram_search_json(el_val_t query, el_val_t limit) { + return engram_search_json(query, limit); +} + +el_val_t __engram_scan_nodes_json(el_val_t limit, el_val_t offset) { + return engram_scan_nodes_json(limit, offset); +} + +el_val_t __engram_scan_nodes_by_type_json(el_val_t node_type, el_val_t limit, el_val_t offset) { + return engram_scan_nodes_by_type_json(node_type, limit, offset); +} + +el_val_t __engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction) { + return engram_neighbors_json(node_id, max_depth, direction); +} + +el_val_t __engram_activate_json(el_val_t query, el_val_t depth) { + return engram_activate_json(query, depth); +} + +el_val_t __engram_stats_json(void) { return engram_stats_json(); } +el_val_t __engram_list_layers_json(void) { return engram_list_layers_json(); } + +el_val_t __engram_compile_layered_json(el_val_t intent, el_val_t depth) { + return engram_compile_layered_json(intent, depth); +} + +/* ── Cryptographic hashing ────────────────────────────────────────────────── */ +/* + * SHA-256 — self-contained implementation (no OpenSSL dependency). + * Based on Brad Conte's public-domain reference implementation. + */ + +typedef struct { + uint8_t data[64]; + uint32_t datalen; + uint64_t bitlen; + uint32_t state[8]; +} _seed_sha256_ctx; + +static const uint32_t _seed_sha256_k[64] = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +}; + +#define _SEED_ROTR32(x,n) (((x)>>(n))|((x)<<(32-(n)))) +#define _SEED_CH(x,y,z) (((x)&(y))^(~(x)&(z))) +#define _SEED_MAJ(x,y,z) (((x)&(y))^((x)&(z))^((y)&(z))) +#define _SEED_EP0(x) (_SEED_ROTR32(x,2)^_SEED_ROTR32(x,13)^_SEED_ROTR32(x,22)) +#define _SEED_EP1(x) (_SEED_ROTR32(x,6)^_SEED_ROTR32(x,11)^_SEED_ROTR32(x,25)) +#define _SEED_SIG0(x) (_SEED_ROTR32(x,7)^_SEED_ROTR32(x,18)^((x)>>3)) +#define _SEED_SIG1(x) (_SEED_ROTR32(x,17)^_SEED_ROTR32(x,19)^((x)>>10)) + +static void _seed_sha256_transform(_seed_sha256_ctx* ctx, const uint8_t* data) { + uint32_t a,b,c,d,e,f,g,h,t1,t2,m[64]; + for (int i=0,j=0; i<16; i++,j+=4) + m[i]=(uint32_t)(data[j]<<24)|(data[j+1]<<16)|(data[j+2]<<8)|data[j+3]; + for (int i=16; i<64; i++) + m[i]=_SEED_SIG1(m[i-2])+m[i-7]+_SEED_SIG0(m[i-15])+m[i-16]; + a=ctx->state[0]; b=ctx->state[1]; c=ctx->state[2]; d=ctx->state[3]; + e=ctx->state[4]; f=ctx->state[5]; g=ctx->state[6]; h=ctx->state[7]; + for (int i=0; i<64; i++) { + t1=h+_SEED_EP1(e)+_SEED_CH(e,f,g)+_seed_sha256_k[i]+m[i]; + t2=_SEED_EP0(a)+_SEED_MAJ(a,b,c); + h=g; g=f; f=e; e=d+t1; d=c; c=b; b=a; a=t1+t2; + } + ctx->state[0]+=a; ctx->state[1]+=b; ctx->state[2]+=c; ctx->state[3]+=d; + ctx->state[4]+=e; ctx->state[5]+=f; ctx->state[6]+=g; ctx->state[7]+=h; +} + +static void _seed_sha256_init(_seed_sha256_ctx* ctx) { + ctx->datalen=0; ctx->bitlen=0; + ctx->state[0]=0x6a09e667; ctx->state[1]=0xbb67ae85; + ctx->state[2]=0x3c6ef372; ctx->state[3]=0xa54ff53a; + ctx->state[4]=0x510e527f; ctx->state[5]=0x9b05688c; + ctx->state[6]=0x1f83d9ab; ctx->state[7]=0x5be0cd19; +} + +static void _seed_sha256_update(_seed_sha256_ctx* ctx, const uint8_t* data, size_t len) { + for (size_t i=0; idata[ctx->datalen++] = data[i]; + if (ctx->datalen==64) { _seed_sha256_transform(ctx,ctx->data); ctx->bitlen+=512; ctx->datalen=0; } + } +} + +static void _seed_sha256_final(_seed_sha256_ctx* ctx, uint8_t hash[32]) { + uint32_t i=ctx->datalen; + ctx->data[i++]=0x80; + if (ctx->datalen<56) { while(i<56) ctx->data[i++]=0; } + else { while(i<64) ctx->data[i++]=0; _seed_sha256_transform(ctx,ctx->data); memset(ctx->data,0,56); } + ctx->bitlen+=ctx->datalen*8; + ctx->data[63]=(uint8_t)(ctx->bitlen); ctx->data[62]=(uint8_t)(ctx->bitlen>>8); + ctx->data[61]=(uint8_t)(ctx->bitlen>>16); ctx->data[60]=(uint8_t)(ctx->bitlen>>24); + ctx->data[59]=(uint8_t)(ctx->bitlen>>32); ctx->data[58]=(uint8_t)(ctx->bitlen>>40); + ctx->data[57]=(uint8_t)(ctx->bitlen>>48); ctx->data[56]=(uint8_t)(ctx->bitlen>>56); + _seed_sha256_transform(ctx,ctx->data); + for (i=0; i<4; i++) { + hash[i] =(uint8_t)(ctx->state[0]>>(24-i*8)); + hash[i+4] =(uint8_t)(ctx->state[1]>>(24-i*8)); + hash[i+8] =(uint8_t)(ctx->state[2]>>(24-i*8)); + hash[i+12] =(uint8_t)(ctx->state[3]>>(24-i*8)); + hash[i+16] =(uint8_t)(ctx->state[4]>>(24-i*8)); + hash[i+20] =(uint8_t)(ctx->state[5]>>(24-i*8)); + hash[i+24] =(uint8_t)(ctx->state[6]>>(24-i*8)); + hash[i+28] =(uint8_t)(ctx->state[7]>>(24-i*8)); + } +} + +/* ── Manifest reader (shared: macOS + Linux) ─────────────────────────────── */ +/* + * Parse the app{} block from a manifest.el file. + * Expected format (subset — only app{} block is parsed): + * + * app { + * window_title "My App" + * window_width 1200 + * window_height 800 + * min_width 600 + * min_height 400 + * } + * + * Returns JSON: {"title":"...","width":N,"height":N,"min_width":N,"min_height":N} + * Returns "{}" on parse failure. + * + * Compiled unconditionally so both EL_TARGET_MACOS and EL_TARGET_LINUX can use + * it — the __manifest_read builtin is identical on all native targets. + */ + +static void seed_manifest_skip_ws(const char** p) { + while (**p && (unsigned char)**p <= ' ') (*p)++; +} + +/* Read a quoted string literal. Caller must free() the result. */ +static char* seed_manifest_read_string(const char** p) { + seed_manifest_skip_ws(p); + if (**p != '"') return NULL; + (*p)++; + const char* start = *p; + while (**p && **p != '"') { + if (**p == '\\') (*p)++; /* skip escaped char */ + (*p)++; + } + size_t len = (size_t)(*p - start); + if (**p == '"') (*p)++; + char* out = malloc(len + 1); + if (!out) return NULL; + memcpy(out, start, len); + out[len] = '\0'; + return out; +} + +/* Read an unquoted integer literal. */ +static int64_t seed_manifest_read_int(const char** p) { + seed_manifest_skip_ws(p); + int64_t result = 0; + int neg = 0; + if (**p == '-') { neg = 1; (*p)++; } + while (**p >= '0' && **p <= '9') { + result = result * 10 + (**p - '0'); + (*p)++; + } + return neg ? -result : result; +} + +/* Find "app {" block start. Returns pointer past the '{'. */ +static const char* seed_manifest_find_app_block(const char* src) { + while (*src) { + /* Skip line comments (// ...) */ + if (src[0] == '/' && src[1] == '/') { + while (*src && *src != '\n') src++; + continue; + } + if (strncmp(src, "app", 3) == 0 && + (src[3] == ' ' || src[3] == '\t' || src[3] == '\n' || src[3] == '{')) { + src += 3; + while (*src && *src != '{') src++; + if (*src == '{') return src + 1; + return NULL; + } + src++; + } + return NULL; +} + +el_val_t __manifest_read(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p || !*p) return seed_wrap_str(seed_strdup("{}")); + + /* Read the file. */ + FILE* f = fopen(p, "r"); + if (!f) return seed_wrap_str(seed_strdup("{}")); + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + if (sz <= 0) { fclose(f); return seed_wrap_str(seed_strdup("{}")); } + char* src = malloc((size_t)sz + 1); + if (!src) { fclose(f); return seed_wrap_str(seed_strdup("{}")); } + size_t got = fread(src, 1, (size_t)sz, f); + src[got] = '\0'; + fclose(f); + + const char* app_start = seed_manifest_find_app_block(src); + if (!app_start) { free(src); return seed_wrap_str(seed_strdup("{}")); } + + /* Parse key-value pairs inside the app { } block. */ + char* title = NULL; + int64_t width = 1200; + int64_t height = 800; + int64_t min_w = 600; + int64_t min_h = 400; + + const char* cur = app_start; + while (*cur && *cur != '}') { + /* Skip whitespace and comments. */ + while (*cur && (unsigned char)*cur <= ' ') cur++; + if (*cur == '}') break; + if (cur[0] == '/' && cur[1] == '/') { + while (*cur && *cur != '\n') cur++; + continue; + } + + /* Read key token. */ + const char* key_start = cur; + while (*cur && (unsigned char)*cur > ' ' && *cur != '{' && *cur != '}') cur++; + size_t key_len = (size_t)(cur - key_start); + if (key_len == 0) { cur++; continue; } + + /* Skip whitespace between key and value. */ + while (*cur == ' ' || *cur == '\t') cur++; + + if (strncmp(key_start, "window_title", key_len) == 0 && key_len == 12) { + free(title); + title = seed_manifest_read_string(&cur); + } else if (strncmp(key_start, "window_width", key_len) == 0 && key_len == 12) { + width = seed_manifest_read_int(&cur); + } else if (strncmp(key_start, "window_height", key_len) == 0 && key_len == 13) { + height = seed_manifest_read_int(&cur); + } else if (strncmp(key_start, "min_width", key_len) == 0 && key_len == 9) { + min_w = seed_manifest_read_int(&cur); + } else if (strncmp(key_start, "min_height", key_len) == 0 && key_len == 10) { + min_h = seed_manifest_read_int(&cur); + } else { + /* Unknown key — skip to end of line. */ + while (*cur && *cur != '\n' && *cur != '}') cur++; + } + } + + free(src); + + /* Build JSON result. */ + const char* t = title ? title : "App"; + size_t buf_sz = strlen(t) * 6 + 128; + char* buf = seed_strbuf(buf_sz); + snprintf(buf, buf_sz, + "{\"title\":\"%s\",\"width\":%lld,\"height\":%lld,\"min_width\":%lld,\"min_height\":%lld}", + t, (long long)width, (long long)height, (long long)min_w, (long long)min_h); + free(title); + return seed_wrap_str(buf); +} + +/* ── Native widget system — macOS AppKit ─────────────────────────────────── */ +/* + * These builtins are compiled in only when EL_TARGET_MACOS is defined. + * They call through to el_appkit.m (Objective-C) which implements the actual + * AppKit widget creation and management. + * + * Each builtin is a thin wrapper: marshal el_val_t ↔ C types, call the + * el_appkit_* function, return the result. + * + * Compile requirements: + * - Compile el_appkit.m alongside this file (clang -ObjC -framework Cocoa) + * - Pass -DEL_TARGET_MACOS to enable this section + */ + +#ifdef EL_TARGET_MACOS + +/* Forward declarations — implemented in el_appkit.m */ +extern void el_appkit_init(void); +extern void el_appkit_run_loop(void); +extern int64_t el_appkit_window_create(const char* title, int w, int h, int mw, int mh); +extern void el_appkit_window_show(int64_t handle); +extern void el_appkit_window_set_title(int64_t handle, const char* title); +extern int64_t el_appkit_vstack_create(int spacing); +extern int64_t el_appkit_hstack_create(int spacing); +extern int64_t el_appkit_zstack_create(void); +extern int64_t el_appkit_scroll_create(void); +extern int64_t el_appkit_label_create(const char* text); +extern int64_t el_appkit_button_create(const char* label); +extern int64_t el_appkit_text_field_create(const char* placeholder); +extern int64_t el_appkit_text_area_create(const char* placeholder); +extern int64_t el_appkit_image_create(const char* path_or_name); +extern void el_appkit_widget_set_text(int64_t handle, const char* text); +extern const char* el_appkit_widget_get_text(int64_t handle); +extern void el_appkit_widget_set_color(int64_t h, float r, float g, float b, float a); +extern void el_appkit_widget_set_bg_color(int64_t h, float r, float g, float b, float a); +extern void el_appkit_widget_set_font(int64_t h, const char* family, int size, int bold); +extern void el_appkit_widget_set_padding(int64_t h, int top, int right, int bottom, int left); +extern void el_appkit_widget_set_width(int64_t h, int width); +extern void el_appkit_widget_set_height(int64_t h, int height); +extern void el_appkit_widget_set_flex(int64_t h, int flex); +extern void el_appkit_widget_set_corner_radius(int64_t h, int radius); +extern void el_appkit_widget_set_disabled(int64_t h, int disabled); +extern void el_appkit_widget_set_hidden(int64_t h, int hidden); +extern void el_appkit_widget_add_child(int64_t parent, int64_t child); +extern void el_appkit_widget_remove_child(int64_t parent, int64_t child); +extern void el_appkit_widget_destroy(int64_t handle); +extern void el_appkit_widget_on_click(int64_t h, const char* fn_name); +extern void el_appkit_widget_on_change(int64_t h, const char* fn_name); +extern void el_appkit_widget_on_submit(int64_t h, const char* fn_name); + +/* ── Native widget builtins ──────────────────────────────────────────────── */ + +void __native_init(void) { el_appkit_init(); } +void __native_run_loop(void) { el_appkit_run_loop(); } + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_appkit_window_create( + EL_CSTR(title), + (int)(int64_t)width, (int)(int64_t)height, + (int)(int64_t)min_width, (int)(int64_t)min_height); +} + +void __window_show(el_val_t h) { el_appkit_window_show((int64_t)h); } +void __window_set_title(el_val_t h, el_val_t t) { el_appkit_window_set_title((int64_t)h, EL_CSTR(t)); } + +el_val_t __vstack_create(el_val_t spacing) { return (el_val_t)el_appkit_vstack_create((int)(int64_t)spacing); } +el_val_t __hstack_create(el_val_t spacing) { return (el_val_t)el_appkit_hstack_create((int)(int64_t)spacing); } +el_val_t __zstack_create(void) { return (el_val_t)el_appkit_zstack_create(); } +el_val_t __scroll_create(void) { return (el_val_t)el_appkit_scroll_create(); } + +el_val_t __label_create(el_val_t text) { return (el_val_t)el_appkit_label_create(EL_CSTR(text)); } +el_val_t __button_create(el_val_t label) { return (el_val_t)el_appkit_button_create(EL_CSTR(label)); } +el_val_t __text_field_create(el_val_t placeholder) { return (el_val_t)el_appkit_text_field_create(EL_CSTR(placeholder)); } +el_val_t __text_area_create(el_val_t placeholder) { return (el_val_t)el_appkit_text_area_create(EL_CSTR(placeholder)); } +el_val_t __image_create(el_val_t path_or_name) { return (el_val_t)el_appkit_image_create(EL_CSTR(path_or_name)); } + +void __widget_set_text(el_val_t h, el_val_t t) { el_appkit_widget_set_text((int64_t)h, EL_CSTR(t)); } + +el_val_t __widget_get_text(el_val_t h) { + const char* s = el_appkit_widget_get_text((int64_t)h); + if (!s) return seed_wrap_str(seed_strdup("")); + /* el_appkit returns strdup'd string — wrap it (arena won't track it, but + * caller must treat return as short-lived or copy it). */ + return EL_STR(s); +} + +void __widget_set_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_appkit_widget_set_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_bg_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_appkit_widget_set_bg_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_font(el_val_t h, el_val_t family, el_val_t size, el_val_t bold) { + el_appkit_widget_set_font((int64_t)h, EL_CSTR(family), + (int)(int64_t)size, (int)(int64_t)bold); +} + +void __widget_set_padding(el_val_t h, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_appkit_widget_set_padding((int64_t)h, + (int)(int64_t)top, (int)(int64_t)right, + (int)(int64_t)bottom, (int)(int64_t)left); +} + +void __widget_set_width(el_val_t h, el_val_t w) { el_appkit_widget_set_width((int64_t)h, (int)(int64_t)w); } +void __widget_set_height(el_val_t h, el_val_t ht) { el_appkit_widget_set_height((int64_t)h, (int)(int64_t)ht); } +void __widget_set_flex(el_val_t h, el_val_t f) { el_appkit_widget_set_flex((int64_t)h, (int)(int64_t)f); } +void __widget_set_corner_radius(el_val_t h, el_val_t r) { el_appkit_widget_set_corner_radius((int64_t)h, (int)(int64_t)r); } +void __widget_set_disabled(el_val_t h, el_val_t d) { el_appkit_widget_set_disabled((int64_t)h, (int)(int64_t)d); } +void __widget_set_hidden(el_val_t h, el_val_t hid) { el_appkit_widget_set_hidden((int64_t)h, (int)(int64_t)hid); } +void __widget_add_child(el_val_t p, el_val_t c) { el_appkit_widget_add_child((int64_t)p, (int64_t)c); } +void __widget_remove_child(el_val_t p, el_val_t c) { el_appkit_widget_remove_child((int64_t)p, (int64_t)c); } +void __widget_destroy(el_val_t h) { el_appkit_widget_destroy((int64_t)h); } + +void __widget_on_click(el_val_t h, el_val_t fn_name) { el_appkit_widget_on_click((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_change(el_val_t h, el_val_t fn_name) { el_appkit_widget_on_change((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_submit(el_val_t h, el_val_t fn_name) { el_appkit_widget_on_submit((int64_t)h, EL_CSTR(fn_name)); } + +#endif /* EL_TARGET_MACOS */ + +/* ── Native widget system — Linux GTK4 ──────────────────────────────────── */ +/* + * These builtins are compiled in only when EL_TARGET_LINUX is defined. + * They call through to el_gtk4.c which implements the GTK4 widget layer. + * + * Each builtin is a thin wrapper: marshal el_val_t ↔ C types, call the + * el_gtk4_* function, return the result. + * + * Compile requirements: + * - Compile el_gtk4.c alongside this file + * gcc -DEL_TARGET_LINUX $(pkg-config --cflags gtk4) el_gtk4.c -c ... + * - Pass -DEL_TARGET_LINUX to enable this section + * - Link with $(pkg-config --libs gtk4) -ldl + * + * __manifest_read is shared with the macOS path (implemented above in the + * seed_manifest_* helpers) and compiled for both targets unconditionally. + */ + +#ifdef EL_TARGET_LINUX + +/* Forward declarations — implemented in el_gtk4.c */ +extern void el_gtk4_init(void); +extern void el_gtk4_run_loop(void); +extern int64_t el_gtk4_window_create(const char* title, int w, int h, + int mw, int mh); +extern void el_gtk4_window_show(int64_t handle); +extern void el_gtk4_window_set_title(int64_t handle, const char* title); +extern int64_t el_gtk4_vstack_create(int spacing); +extern int64_t el_gtk4_hstack_create(int spacing); +extern int64_t el_gtk4_zstack_create(void); +extern int64_t el_gtk4_scroll_create(void); +extern int64_t el_gtk4_label_create(const char* text); +extern int64_t el_gtk4_button_create(const char* label); +extern int64_t el_gtk4_text_field_create(const char* placeholder); +extern int64_t el_gtk4_text_area_create(const char* placeholder); +extern int64_t el_gtk4_image_create(const char* path_or_name); +extern void el_gtk4_widget_set_text(int64_t handle, const char* text); +extern const char* el_gtk4_widget_get_text(int64_t handle); +extern void el_gtk4_widget_set_color(int64_t h, float r, float g, float b, float a); +extern void el_gtk4_widget_set_bg_color(int64_t h, float r, float g, float b, float a); +extern void el_gtk4_widget_set_font(int64_t h, const char* family, int size, int bold); +extern void el_gtk4_widget_set_padding(int64_t h, int top, int right, int bottom, int left); +extern void el_gtk4_widget_set_width(int64_t h, int width); +extern void el_gtk4_widget_set_height(int64_t h, int height); +extern void el_gtk4_widget_set_flex(int64_t h, int flex); +extern void el_gtk4_widget_set_corner_radius(int64_t h, int radius); +extern void el_gtk4_widget_set_disabled(int64_t h, int disabled); +extern void el_gtk4_widget_set_hidden(int64_t h, int hidden); +extern void el_gtk4_widget_add_child(int64_t parent, int64_t child); +extern void el_gtk4_widget_remove_child(int64_t parent, int64_t child); +extern void el_gtk4_widget_destroy(int64_t handle); +extern void el_gtk4_widget_on_click(int64_t h, const char* fn_name); +extern void el_gtk4_widget_on_change(int64_t h, const char* fn_name); +extern void el_gtk4_widget_on_submit(int64_t h, const char* fn_name); + +void __native_init(void) { el_gtk4_init(); } +void __native_run_loop(void) { el_gtk4_run_loop(); } + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_gtk4_window_create( + EL_CSTR(title), + (int)(int64_t)width, (int)(int64_t)height, + (int)(int64_t)min_width, (int)(int64_t)min_height); +} + +void __window_show(el_val_t h) { el_gtk4_window_show((int64_t)h); } +void __window_set_title(el_val_t h, el_val_t t) { el_gtk4_window_set_title((int64_t)h, EL_CSTR(t)); } + +el_val_t __vstack_create(el_val_t spacing) { return (el_val_t)el_gtk4_vstack_create((int)(int64_t)spacing); } +el_val_t __hstack_create(el_val_t spacing) { return (el_val_t)el_gtk4_hstack_create((int)(int64_t)spacing); } +el_val_t __zstack_create(void) { return (el_val_t)el_gtk4_zstack_create(); } +el_val_t __scroll_create(void) { return (el_val_t)el_gtk4_scroll_create(); } + +el_val_t __label_create(el_val_t text) { return (el_val_t)el_gtk4_label_create(EL_CSTR(text)); } +el_val_t __button_create(el_val_t label) { return (el_val_t)el_gtk4_button_create(EL_CSTR(label)); } +el_val_t __text_field_create(el_val_t placeholder) { return (el_val_t)el_gtk4_text_field_create(EL_CSTR(placeholder)); } +el_val_t __text_area_create(el_val_t placeholder) { return (el_val_t)el_gtk4_text_area_create(EL_CSTR(placeholder)); } +el_val_t __image_create(el_val_t path_or_name) { return (el_val_t)el_gtk4_image_create(EL_CSTR(path_or_name)); } + +void __widget_set_text(el_val_t h, el_val_t t) { el_gtk4_widget_set_text((int64_t)h, EL_CSTR(t)); } + +el_val_t __widget_get_text(el_val_t h) { + const char* s = el_gtk4_widget_get_text((int64_t)h); + if (!s) return EL_STR(""); + return EL_STR(s); /* el_gtk4 returns strdup'd string */ +} + +void __widget_set_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_gtk4_widget_set_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_bg_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_gtk4_widget_set_bg_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_font(el_val_t h, el_val_t family, el_val_t size, el_val_t bold) { + el_gtk4_widget_set_font((int64_t)h, EL_CSTR(family), + (int)(int64_t)size, (int)(int64_t)bold); +} + +void __widget_set_padding(el_val_t h, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_gtk4_widget_set_padding((int64_t)h, + (int)(int64_t)top, (int)(int64_t)right, + (int)(int64_t)bottom, (int)(int64_t)left); +} + +void __widget_set_width(el_val_t h, el_val_t w) { el_gtk4_widget_set_width((int64_t)h, (int)(int64_t)w); } +void __widget_set_height(el_val_t h, el_val_t ht) { el_gtk4_widget_set_height((int64_t)h, (int)(int64_t)ht); } +void __widget_set_flex(el_val_t h, el_val_t f) { el_gtk4_widget_set_flex((int64_t)h, (int)(int64_t)f); } +void __widget_set_corner_radius(el_val_t h, el_val_t r) { el_gtk4_widget_set_corner_radius((int64_t)h, (int)(int64_t)r); } +void __widget_set_disabled(el_val_t h, el_val_t d) { el_gtk4_widget_set_disabled((int64_t)h, (int)(int64_t)d); } +void __widget_set_hidden(el_val_t h, el_val_t hid) { el_gtk4_widget_set_hidden((int64_t)h, (int)(int64_t)hid); } +void __widget_add_child(el_val_t p, el_val_t c) { el_gtk4_widget_add_child((int64_t)p, (int64_t)c); } +void __widget_remove_child(el_val_t p, el_val_t c) { el_gtk4_widget_remove_child((int64_t)p, (int64_t)c); } +void __widget_destroy(el_val_t h) { el_gtk4_widget_destroy((int64_t)h); } + +void __widget_on_click(el_val_t h, el_val_t fn_name) { el_gtk4_widget_on_click((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_change(el_val_t h, el_val_t fn_name) { el_gtk4_widget_on_change((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_submit(el_val_t h, el_val_t fn_name) { el_gtk4_widget_on_submit((int64_t)h, EL_CSTR(fn_name)); } + +#endif /* EL_TARGET_LINUX */ + +/* ── Native widget system — SDL2 (embedded / Pi) ─────────────────────────── */ +/* + * These builtins are compiled in only when EL_TARGET_SDL2 is defined. + * They call through to el_sdl2.c which implements a retained-mode pixel + * widget layer on top of SDL2 + SDL_ttf + SDL_image. + * + * Each builtin is a thin wrapper: marshal el_val_t ↔ C types, call the + * el_sdl2_* function, return the result. + * + * Compile requirements: + * gcc -DEL_TARGET_SDL2 $(sdl2-config --cflags) el_sdl2.c -c ... + * Pass -DEL_TARGET_SDL2 to enable this section. + * Link: + * $(sdl2-config --libs) -lSDL2_ttf -lSDL2_image -ldl + * + * __manifest_read is shared with the macOS/Linux paths (implemented above). + */ + +#ifdef EL_TARGET_SDL2 + +/* Forward declarations — implemented in el_sdl2.c */ +extern void el_sdl2_init(void); +extern void el_sdl2_run_loop(void); +extern int64_t el_sdl2_window_create(const char* title, int w, int h, + int mw, int mh); +extern void el_sdl2_window_show(int64_t handle); +extern void el_sdl2_window_set_title(int64_t handle, const char* title); +extern int64_t el_sdl2_vstack_create(int spacing); +extern int64_t el_sdl2_hstack_create(int spacing); +extern int64_t el_sdl2_zstack_create(void); +extern int64_t el_sdl2_scroll_create(void); +extern int64_t el_sdl2_label_create(const char* text); +extern int64_t el_sdl2_button_create(const char* label); +extern int64_t el_sdl2_text_field_create(const char* placeholder); +extern int64_t el_sdl2_text_area_create(const char* placeholder); +extern int64_t el_sdl2_image_create(const char* path_or_name); +extern void el_sdl2_widget_set_text(int64_t handle, const char* text); +extern const char* el_sdl2_widget_get_text(int64_t handle); +extern void el_sdl2_widget_set_color(int64_t h, float r, float g, float b, float a); +extern void el_sdl2_widget_set_bg_color(int64_t h, float r, float g, float b, float a); +extern void el_sdl2_widget_set_font(int64_t h, const char* family, int size, int bold); +extern void el_sdl2_widget_set_padding(int64_t h, int top, int right, int bottom, int left); +extern void el_sdl2_widget_set_width(int64_t h, int width); +extern void el_sdl2_widget_set_height(int64_t h, int height); +extern void el_sdl2_widget_set_flex(int64_t h, int flex); +extern void el_sdl2_widget_set_corner_radius(int64_t h, int radius); +extern void el_sdl2_widget_set_disabled(int64_t h, int disabled); +extern void el_sdl2_widget_set_hidden(int64_t h, int hidden); +extern void el_sdl2_widget_add_child(int64_t parent, int64_t child); +extern void el_sdl2_widget_remove_child(int64_t parent, int64_t child); +extern void el_sdl2_widget_destroy(int64_t handle); +extern void el_sdl2_widget_on_click(int64_t h, const char* fn_name); +extern void el_sdl2_widget_on_change(int64_t h, const char* fn_name); +extern void el_sdl2_widget_on_submit(int64_t h, const char* fn_name); + +void __native_init(void) { el_sdl2_init(); } +void __native_run_loop(void) { el_sdl2_run_loop(); } + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_sdl2_window_create( + EL_CSTR(title), + (int)(int64_t)width, (int)(int64_t)height, + (int)(int64_t)min_width, (int)(int64_t)min_height); +} + +void __window_show(el_val_t h) { el_sdl2_window_show((int64_t)h); } +void __window_set_title(el_val_t h, el_val_t t) { el_sdl2_window_set_title((int64_t)h, EL_CSTR(t)); } + +el_val_t __vstack_create(el_val_t spacing) { return (el_val_t)el_sdl2_vstack_create((int)(int64_t)spacing); } +el_val_t __hstack_create(el_val_t spacing) { return (el_val_t)el_sdl2_hstack_create((int)(int64_t)spacing); } +el_val_t __zstack_create(void) { return (el_val_t)el_sdl2_zstack_create(); } +el_val_t __scroll_create(void) { return (el_val_t)el_sdl2_scroll_create(); } + +el_val_t __label_create(el_val_t text) { return (el_val_t)el_sdl2_label_create(EL_CSTR(text)); } +el_val_t __button_create(el_val_t label) { return (el_val_t)el_sdl2_button_create(EL_CSTR(label)); } +el_val_t __text_field_create(el_val_t placeholder) { return (el_val_t)el_sdl2_text_field_create(EL_CSTR(placeholder)); } +el_val_t __text_area_create(el_val_t placeholder) { return (el_val_t)el_sdl2_text_area_create(EL_CSTR(placeholder)); } +el_val_t __image_create(el_val_t path_or_name) { return (el_val_t)el_sdl2_image_create(EL_CSTR(path_or_name)); } + +void __widget_set_text(el_val_t h, el_val_t t) { el_sdl2_widget_set_text((int64_t)h, EL_CSTR(t)); } + +el_val_t __widget_get_text(el_val_t h) { + const char* s = el_sdl2_widget_get_text((int64_t)h); + if (!s) return EL_STR(""); + return EL_STR(s); +} + +void __widget_set_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_sdl2_widget_set_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_bg_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_sdl2_widget_set_bg_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_font(el_val_t h, el_val_t family, el_val_t size, el_val_t bold) { + el_sdl2_widget_set_font((int64_t)h, EL_CSTR(family), + (int)(int64_t)size, (int)(int64_t)bold); +} + +void __widget_set_padding(el_val_t h, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_sdl2_widget_set_padding((int64_t)h, + (int)(int64_t)top, (int)(int64_t)right, + (int)(int64_t)bottom, (int)(int64_t)left); +} + +void __widget_set_width(el_val_t h, el_val_t w) { el_sdl2_widget_set_width((int64_t)h, (int)(int64_t)w); } +void __widget_set_height(el_val_t h, el_val_t ht) { el_sdl2_widget_set_height((int64_t)h, (int)(int64_t)ht); } +void __widget_set_flex(el_val_t h, el_val_t f) { el_sdl2_widget_set_flex((int64_t)h, (int)(int64_t)f); } +void __widget_set_corner_radius(el_val_t h, el_val_t r) { el_sdl2_widget_set_corner_radius((int64_t)h, (int)(int64_t)r); } +void __widget_set_disabled(el_val_t h, el_val_t d) { el_sdl2_widget_set_disabled((int64_t)h, (int)(int64_t)d); } +void __widget_set_hidden(el_val_t h, el_val_t hid) { el_sdl2_widget_set_hidden((int64_t)h, (int)(int64_t)hid); } +void __widget_add_child(el_val_t p, el_val_t c) { el_sdl2_widget_add_child((int64_t)p, (int64_t)c); } +void __widget_remove_child(el_val_t p, el_val_t c) { el_sdl2_widget_remove_child((int64_t)p, (int64_t)c); } +void __widget_destroy(el_val_t h) { el_sdl2_widget_destroy((int64_t)h); } + +void __widget_on_click(el_val_t h, el_val_t fn_name) { el_sdl2_widget_on_click((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_change(el_val_t h, el_val_t fn_name) { el_sdl2_widget_on_change((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_submit(el_val_t h, el_val_t fn_name) { el_sdl2_widget_on_submit((int64_t)h, EL_CSTR(fn_name)); } + +#endif /* EL_TARGET_SDL2 */ + +/* ── EL_TARGET_LVGL — LVGL v9 embedded backend ─────────────────────────────── + * + * These builtins are compiled in only when EL_TARGET_LVGL is defined. + * Each wrapper translates el_val_t arguments (opaque int64_t) into the typed + * parameters that el_lvgl_* expects, then calls through. + * + * Build: + * gcc -DEL_TARGET_LVGL -I./lvgl el_lvgl.c el_seed.c -c ... + * # Link with lvgl.a. For bare-metal add -DEL_LVGL_NO_DLSYM. + * + * __manifest_read is shared — defined unconditionally above. + */ + +#ifdef EL_TARGET_LVGL + +extern void el_lvgl_init(void); +extern void el_lvgl_run_loop(void); +extern int64_t el_lvgl_window_create(const char *title, int w, int h, + int mw, int mh); +extern void el_lvgl_window_show(int64_t handle); +extern void el_lvgl_window_set_title(int64_t handle, const char *title); +extern int64_t el_lvgl_vstack_create(int spacing); +extern int64_t el_lvgl_hstack_create(int spacing); +extern int64_t el_lvgl_zstack_create(void); +extern int64_t el_lvgl_scroll_create(void); +extern int64_t el_lvgl_label_create(const char *text); +extern int64_t el_lvgl_button_create(const char *label); +extern int64_t el_lvgl_text_field_create(const char *placeholder); +extern int64_t el_lvgl_text_area_create(const char *placeholder); +extern int64_t el_lvgl_image_create(const char *path_or_name); +extern void el_lvgl_widget_set_text(int64_t handle, const char *text); +extern const char *el_lvgl_widget_get_text(int64_t handle); +extern void el_lvgl_widget_set_color(int64_t h, float r, float g, + float b, float a); +extern void el_lvgl_widget_set_bg_color(int64_t h, float r, float g, + float b, float a); +extern void el_lvgl_widget_set_font(int64_t h, const char *family, + int size, int bold); +extern void el_lvgl_widget_set_padding(int64_t h, int top, int right, + int bottom, int left); +extern void el_lvgl_widget_set_width(int64_t h, int width); +extern void el_lvgl_widget_set_height(int64_t h, int height); +extern void el_lvgl_widget_set_flex(int64_t h, int flex); +extern void el_lvgl_widget_set_corner_radius(int64_t h, int radius); +extern void el_lvgl_widget_set_disabled(int64_t h, int disabled); +extern void el_lvgl_widget_set_hidden(int64_t h, int hidden); +extern void el_lvgl_widget_add_child(int64_t parent, int64_t child); +extern void el_lvgl_widget_remove_child(int64_t parent, int64_t child); +extern void el_lvgl_widget_destroy(int64_t handle); +extern void el_lvgl_widget_on_click(int64_t h, const char *fn_name); +extern void el_lvgl_widget_on_change(int64_t h, const char *fn_name); +extern void el_lvgl_widget_on_submit(int64_t h, const char *fn_name); + +void __native_init(void) { el_lvgl_init(); } +void __native_run_loop(void) { el_lvgl_run_loop(); } + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_lvgl_window_create( + EL_CSTR(title), + (int)(int64_t)width, (int)(int64_t)height, + (int)(int64_t)min_width, (int)(int64_t)min_height); +} + +void __window_show(el_val_t h) { el_lvgl_window_show((int64_t)h); } +void __window_set_title(el_val_t h, el_val_t t) { el_lvgl_window_set_title((int64_t)h, EL_CSTR(t)); } + +el_val_t __vstack_create(el_val_t spacing) { return (el_val_t)el_lvgl_vstack_create((int)(int64_t)spacing); } +el_val_t __hstack_create(el_val_t spacing) { return (el_val_t)el_lvgl_hstack_create((int)(int64_t)spacing); } +el_val_t __zstack_create(void) { return (el_val_t)el_lvgl_zstack_create(); } +el_val_t __scroll_create(void) { return (el_val_t)el_lvgl_scroll_create(); } + +el_val_t __label_create(el_val_t text) { return (el_val_t)el_lvgl_label_create(EL_CSTR(text)); } +el_val_t __button_create(el_val_t label) { return (el_val_t)el_lvgl_button_create(EL_CSTR(label)); } +el_val_t __text_field_create(el_val_t placeholder) { return (el_val_t)el_lvgl_text_field_create(EL_CSTR(placeholder)); } +el_val_t __text_area_create(el_val_t placeholder) { return (el_val_t)el_lvgl_text_area_create(EL_CSTR(placeholder)); } +el_val_t __image_create(el_val_t path_or_name) { return (el_val_t)el_lvgl_image_create(EL_CSTR(path_or_name)); } + +void __widget_set_text(el_val_t h, el_val_t t) { el_lvgl_widget_set_text((int64_t)h, EL_CSTR(t)); } + +el_val_t __widget_get_text(el_val_t h) { + const char *s = el_lvgl_widget_get_text((int64_t)h); + if (!s) return EL_STR(""); + return EL_STR(s); /* pointer into LVGL internal storage — valid until next LVGL op */ +} + +void __widget_set_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_lvgl_widget_set_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_bg_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_lvgl_widget_set_bg_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_font(el_val_t h, el_val_t family, el_val_t size, el_val_t bold) { + el_lvgl_widget_set_font((int64_t)h, EL_CSTR(family), + (int)(int64_t)size, (int)(int64_t)bold); +} + +void __widget_set_padding(el_val_t h, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_lvgl_widget_set_padding((int64_t)h, + (int)(int64_t)top, (int)(int64_t)right, + (int)(int64_t)bottom, (int)(int64_t)left); +} + +void __widget_set_width(el_val_t h, el_val_t w) { el_lvgl_widget_set_width((int64_t)h, (int)(int64_t)w); } +void __widget_set_height(el_val_t h, el_val_t ht) { el_lvgl_widget_set_height((int64_t)h, (int)(int64_t)ht); } +void __widget_set_flex(el_val_t h, el_val_t f) { el_lvgl_widget_set_flex((int64_t)h, (int)(int64_t)f); } +void __widget_set_corner_radius(el_val_t h, el_val_t r) { el_lvgl_widget_set_corner_radius((int64_t)h, (int)(int64_t)r); } +void __widget_set_disabled(el_val_t h, el_val_t d) { el_lvgl_widget_set_disabled((int64_t)h, (int)(int64_t)d); } +void __widget_set_hidden(el_val_t h, el_val_t hid) { el_lvgl_widget_set_hidden((int64_t)h, (int)(int64_t)hid); } +void __widget_add_child(el_val_t p, el_val_t c) { el_lvgl_widget_add_child((int64_t)p, (int64_t)c); } +void __widget_remove_child(el_val_t p, el_val_t c) { el_lvgl_widget_remove_child((int64_t)p, (int64_t)c); } +void __widget_destroy(el_val_t h) { el_lvgl_widget_destroy((int64_t)h); } + +void __widget_on_click(el_val_t h, el_val_t fn_name) { el_lvgl_widget_on_click((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_change(el_val_t h, el_val_t fn_name) { el_lvgl_widget_on_change((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_submit(el_val_t h, el_val_t fn_name) { el_lvgl_widget_on_submit((int64_t)h, EL_CSTR(fn_name)); } + +#endif /* EL_TARGET_LVGL */ + +/* ── Cryptographic hashing ────────────────────────────────────────────────── */ + +el_val_t __sha256_hex(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) s = ""; + _seed_sha256_ctx ctx; + _seed_sha256_init(&ctx); + _seed_sha256_update(&ctx, (const uint8_t*)s, strlen(s)); + uint8_t digest[32]; + _seed_sha256_final(&ctx, digest); + static const char hex[] = "0123456789abcdef"; + char* out = malloc(65); + if (!out) return EL_STR(""); + for (int i=0; i<32; i++) { + out[i*2] = hex[(digest[i]>>4)&0xf]; + out[i*2+1] = hex[digest[i]&0xf]; + } + out[64] = '\0'; + return EL_STR(out); +} diff --git a/ui/examples/native-hello-android/app/src/main/jni/native_hello.c b/ui/examples/native-hello-android/app/src/main/jni/native_hello.c new file mode 100644 index 0000000..050d56a --- /dev/null +++ b/ui/examples/native-hello-android/app/src/main/jni/native_hello.c @@ -0,0 +1,123 @@ +#include +#include +#include "el_runtime.h" + +el_val_t on_greet_click(el_val_t widget, el_val_t data); +el_val_t on_counter_click(el_val_t widget, el_val_t data); +el_val_t on_name_change(el_val_t widget, el_val_t data); +el_val_t app_build(el_val_t window); + +el_val_t g_window; +el_val_t g_label; +el_val_t g_input; +el_val_t g_button; +el_val_t g_counter; +el_val_t g_counter_lbl; +el_val_t manifest_env; +el_val_t manifest_path; +el_val_t win; +el_val_t g_window; + +el_val_t on_greet_click(el_val_t widget, el_val_t data) { + el_val_t name = widget_get_text(g_input); + el_val_t greeting = ({ el_val_t _if_result_1 = 0; if ((str_len(name) > 0)) { _if_result_1 = (el_str_concat(el_str_concat(EL_STR("Hello, "), name), EL_STR("!"))); } else { _if_result_1 = (EL_STR("Hello, World!")); } _if_result_1; }); + widget_set_text(g_label, greeting); + return 0; +} + +el_val_t on_counter_click(el_val_t widget, el_val_t data) { + el_val_t g_counter = (g_counter + 1); + widget_set_text(g_counter_lbl, el_str_concat(EL_STR("Clicks: "), int_to_str(g_counter))); + return 0; +} + +el_val_t on_name_change(el_val_t widget, el_val_t data) { + el_val_t has_text = (str_len(data) > 0); + widget_set_disabled(g_button, !has_text); + return 0; +} + +el_val_t app_build(el_val_t window) { + el_val_t root = vstack(0); + widget_set_padding_all(root, 24); + widget_set_bg_color_hex(root, EL_STR("#0f172a")); + widget_set_flex(root, 1); + el_val_t title = label(EL_STR("el-native \xe2\x80\x94 native widget demo")); + style_label_heading(title); + widget_add_child(root, title); + el_val_t gap1 = label(EL_STR("")); + widget_set_height(gap1, 16); + widget_add_child(root, gap1); + el_val_t subtitle = label(EL_STR("AppKit controls from el code, no ObjC in the app layer.")); + style_label_muted(subtitle); + widget_add_child(root, subtitle); + el_val_t gap2 = label(EL_STR("")); + widget_set_height(gap2, 24); + widget_add_child(root, gap2); + el_val_t input_row = hstack(8); + el_val_t name_label = label(EL_STR("Name:")); + style_label_body(name_label); + widget_set_width(name_label, 60); + el_val_t input = text_field(EL_STR("Enter your name\xe2\x80\xa6")); + style_label_body(input); + widget_set_flex(input, 1); + widget_on_change(input, EL_STR("on_name_change")); + el_val_t g_input = input; + el_val_t greet_btn = button(EL_STR("Greet")); + style_button_primary(greet_btn); + widget_set_disabled(greet_btn, 1); + widget_on_click(greet_btn, EL_STR("on_greet_click")); + el_val_t g_button = greet_btn; + widget_add_child(input_row, name_label); + widget_add_child(input_row, input); + widget_add_child(input_row, greet_btn); + widget_add_child(root, input_row); + el_val_t gap3 = label(EL_STR("")); + widget_set_height(gap3, 12); + widget_add_child(root, gap3); + el_val_t greeting = label(EL_STR("Waiting for name\xe2\x80\xa6")); + style_label_body(greeting); + widget_set_color_hex(greeting, EL_STR("#60a5fa")); + widget_set_font(greeting, EL_STR("system"), 16, 1); + el_val_t g_label = greeting; + widget_add_child(root, greeting); + el_val_t gap4 = label(EL_STR("")); + widget_set_height(gap4, 24); + widget_add_child(root, gap4); + el_val_t counter_row = hstack(12); + el_val_t counter_lbl = label(EL_STR("Clicks: 0")); + style_label_body(counter_lbl); + el_val_t g_counter_lbl = counter_lbl; + el_val_t counter_btn = button(EL_STR("Click me")); + style_button_primary(counter_btn); + widget_on_click(counter_btn, EL_STR("on_counter_click")); + widget_add_child(counter_row, counter_lbl); + widget_add_child(counter_row, counter_btn); + widget_add_child(root, counter_row); + widget_add_child(window, root); + return 0; +} + +int main(int _argc, char** _argv) { + el_runtime_init_args(_argc, _argv); + g_window = (-1); + g_label = (-1); + g_input = (-1); + g_button = (-1); + g_counter = 0; + g_counter_lbl = (-1); + native_init(); + manifest_env = env(EL_STR("EL_MANIFEST")); + manifest_path = ({ el_val_t _if_result_2 = 0; if ((str_len(manifest_env) > 0)) { _if_result_2 = (manifest_env); } else { _if_result_2 = (EL_STR("manifest.el")); } _if_result_2; }); + win = window_from_manifest(manifest_path); + g_window = win; + if (win < 0) { + println(EL_STR("Error: failed to create window. Is EL_TARGET_MACOS defined?")); + exit_program(1); + } + app_build(win); + window_show(win); + native_run_loop(); + return 0; +} + diff --git a/ui/examples/native-hello-android/app/src/main/res/layout/activity_main.xml b/ui/examples/native-hello-android/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..c2ac18f --- /dev/null +++ b/ui/examples/native-hello-android/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,13 @@ + + + diff --git a/ui/examples/native-hello-android/app/src/main/res/values/strings.xml b/ui/examples/native-hello-android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..b0cc308 --- /dev/null +++ b/ui/examples/native-hello-android/app/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + el-native + diff --git a/ui/examples/native-hello-android/build.gradle b/ui/examples/native-hello-android/build.gradle new file mode 100644 index 0000000..3143e8a --- /dev/null +++ b/ui/examples/native-hello-android/build.gradle @@ -0,0 +1,4 @@ +// Top-level build file — configuration for all sub-projects/modules. +plugins { + id 'com.android.application' version '8.2.2' apply false +} diff --git a/ui/examples/native-hello-android/build.sh b/ui/examples/native-hello-android/build.sh new file mode 100755 index 0000000..4428bbd --- /dev/null +++ b/ui/examples/native-hello-android/build.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +# build.sh — Build native-hello-android. +# +# Usage: +# ./build.sh # regenerate C sources + ./gradlew assembleDebug +# ./build.sh gen # regenerate C sources only +# ./build.sh gradle # run ./gradlew assembleDebug (skip elc step) +# ./build.sh clean # clean Gradle build outputs +# +# Requirements: +# - Android SDK with NDK and CMake installed +# - local.properties present (copy from local.properties.template and edit sdk.dir) +# - Java 11+ on PATH (for Gradle) +# - elc at ../../../lang/dist/platform/elc + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +EL_LANG_ROOT="${SCRIPT_DIR}/../../../lang" +EL_UI_ROOT="${SCRIPT_DIR}/../.." +EL_RUNTIME="${EL_LANG_ROOT}/el-compiler/runtime" +EL_NATIVE_VESSEL="${EL_UI_ROOT}/vessels/el-native/src/main.el" +EL_APP_ENTRY="${EL_UI_ROOT}/examples/native-hello/src/main.el" +EL_MANIFEST="${EL_UI_ROOT}/examples/native-hello/manifest.el" +JNI_DIR="${SCRIPT_DIR}/app/src/main/jni" + +# Locate elc. +if command -v elc &>/dev/null; then + ELC="elc" +elif [ -x "${EL_LANG_ROOT}/dist/platform/elc" ]; then + ELC="${EL_LANG_ROOT}/dist/platform/elc" +else + echo "Error: elc not found. Add it to PATH or place it at:" + echo " ${EL_LANG_ROOT}/dist/platform/elc" + exit 1 +fi + +gen() { + echo "==> Generating native_hello.c..." + EL_MANIFEST="${EL_MANIFEST}" \ + "${ELC}" "${EL_APP_ENTRY}" \ + > "${JNI_DIR}/native_hello.c" + + echo "==> Generating el_native_vessel.c..." + "${ELC}" "${EL_NATIVE_VESSEL}" \ + > "${JNI_DIR}/el_native_vessel.c" + # Rename the vessel's main() to avoid symbol collision with native_hello.c's main(). + # The Android JNI entry point (nativeMain) calls native_hello.c's main() explicitly. + sed -i '' 's/^int main(int _argc, char\*\* _argv) {/int el_vessel_main(int _argc, char** _argv) {/' \ + "${JNI_DIR}/el_native_vessel.c" 2>/dev/null || \ + sed -i 's/^int main(int _argc, char\*\* _argv) {/int el_vessel_main(int _argc, char** _argv) {/' \ + "${JNI_DIR}/el_native_vessel.c" + + echo "==> C source generation complete." +} + +gradle_build() { + echo "==> Running ./gradlew assembleDebug..." + cd "${SCRIPT_DIR}" + ./gradlew assembleDebug + + APK_PATH="${SCRIPT_DIR}/app/build/outputs/apk/debug/app-debug.apk" + if [ -f "${APK_PATH}" ]; then + echo "==> Build complete." + echo " APK: ${APK_PATH}" + else + echo "==> Build complete (APK path may differ — check app/build/outputs/apk/)." + fi +} + +clean() { + echo "==> Cleaning..." + cd "${SCRIPT_DIR}" + ./gradlew clean + echo "==> Clean complete." +} + +case "${1:-all}" in + gen) gen ;; + gradle) gradle_build ;; + clean) clean ;; + all|*) gen && gradle_build ;; +esac diff --git a/ui/examples/native-hello-android/gradle.properties b/ui/examples/native-hello-android/gradle.properties new file mode 100644 index 0000000..150f321 --- /dev/null +++ b/ui/examples/native-hello-android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +android.useAndroidX=true +android.enableJetifier=false diff --git a/ui/examples/native-hello-android/gradle/wrapper/gradle-wrapper.jar b/ui/examples/native-hello-android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..033e24c4cdf41af1ab109bc7f253b2b887023340 GIT binary patch literal 63375 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≫L+crb^Bz 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 '} + case $link in #( + /*) app_path=$link ;; #( + # Make relative path absolute, based on the path of the symlink: + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + ;; + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$@" + +exec "$JAVACMD" "$@" diff --git a/ui/examples/native-hello-android/local.properties.template b/ui/examples/native-hello-android/local.properties.template new file mode 100644 index 0000000..b9f1e6d --- /dev/null +++ b/ui/examples/native-hello-android/local.properties.template @@ -0,0 +1,7 @@ +# local.properties — machine-local SDK/NDK paths. DO NOT commit. Copy to local.properties. +# +# Generate: Android Studio creates this automatically, or set manually: +# sdk.dir=/Users//Library/Android/sdk +# ndk.dir=/Users//Library/Android/sdk/ndk/ + +sdk.dir=/Users/will/Library/Android/sdk diff --git a/ui/examples/native-hello-android/settings.gradle b/ui/examples/native-hello-android/settings.gradle new file mode 100644 index 0000000..d9f3ff7 --- /dev/null +++ b/ui/examples/native-hello-android/settings.gradle @@ -0,0 +1,17 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "native-hello-android" +include ':app' diff --git a/ui/examples/native-hello-ios/.gitignore b/ui/examples/native-hello-ios/.gitignore new file mode 100644 index 0000000..22a50dd --- /dev/null +++ b/ui/examples/native-hello-ios/.gitignore @@ -0,0 +1,4 @@ +build/ +*.xcuserstate +xcuserdata/ +NativeHello.xcodeproj/xcuserdata/ diff --git a/ui/examples/native-hello-ios/NativeHello.xcodeproj/project.pbxproj b/ui/examples/native-hello-ios/NativeHello.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d089ff0 --- /dev/null +++ b/ui/examples/native-hello-ios/NativeHello.xcodeproj/project.pbxproj @@ -0,0 +1,377 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 4C6D9832BE495DD69A8573D9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8FFDE02477855A55BC5F02CE /* main.m */; }; + 396FD073065B58F39358D798 /* el_uikit.m in Sources */ = {isa = PBXBuildFile; fileRef = 606F96EC1EDC54CD99E7D722 /* el_uikit.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 92BBC3E2AA055FCE840BF779 /* el_seed.c in Sources */ = {isa = PBXBuildFile; fileRef = 618FBE18EAA850D9B493A20F /* el_seed.c */; }; + 136C7763096C5037A69077AD /* el_runtime.c in Sources */ = {isa = PBXBuildFile; fileRef = A8CCF8316D83597CBB332064 /* el_runtime.c */; }; + 25136DF2A63F507EA5C7EF99 /* el_native_vessel.c in Sources */ = {isa = PBXBuildFile; fileRef = 3373ABFFE7FB5EFA9343AD02 /* el_native_vessel.c */; }; + C05D581DBD4E52F6B7F7303E /* native_hello.c in Sources */ = {isa = PBXBuildFile; fileRef = EDA408C749EB5F3CA1E5EEC2 /* native_hello.c */; }; + C3D9A9987F0050EB859D9218 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF42D2E0FA0655149E573F7C /* UIKit.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 8FFDE02477855A55BC5F02CE /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 606F96EC1EDC54CD99E7D722 /* el_uikit.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = el_uikit.m; sourceTree = ""; }; + 618FBE18EAA850D9B493A20F /* el_seed.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = el_seed.c; sourceTree = ""; }; + A8CCF8316D83597CBB332064 /* el_runtime.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = el_runtime.c; sourceTree = ""; }; + 530AA788858357FBA923217E /* el_runtime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = el_runtime.h; sourceTree = ""; }; + E1A7B02609E95D1686523B80 /* el_native_target.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = el_native_target.h; sourceTree = ""; }; + 3373ABFFE7FB5EFA9343AD02 /* el_native_vessel.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = el_native_vessel.c; sourceTree = ""; }; + EDA408C749EB5F3CA1E5EEC2 /* native_hello.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = native_hello.c; sourceTree = ""; }; + 08B6475D8C7952F48EF46B10 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + FF42D2E0FA0655149E573F7C /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + BDC23A5F3FCD5D1098144064 /* NativeHello.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NativeHello.app; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5673C72A848C5FFF94E7CF8F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C3D9A9987F0050EB859D9218 /* UIKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 05039DD2316A5B41A35E094E /* root */ = { + isa = PBXGroup; + children = ( + EBC5644CBC315AFDA6A6A59E /* NativeHello */, + D1E4BC2FC3925E6FAFCD38F6 /* Frameworks */, + 177F2C27230B527E80CEAED5 /* Products */, + ); + sourceTree = ""; + }; + 177F2C27230B527E80CEAED5 /* Products */ = { + isa = PBXGroup; + children = ( + BDC23A5F3FCD5D1098144064 /* NativeHello.app */, + ); + name = Products; + sourceTree = ""; + }; + EBC5644CBC315AFDA6A6A59E /* NativeHello */ = { + isa = PBXGroup; + children = ( + 8FFDE02477855A55BC5F02CE /* main.m */, + 606F96EC1EDC54CD99E7D722 /* el_uikit.m */, + 618FBE18EAA850D9B493A20F /* el_seed.c */, + A8CCF8316D83597CBB332064 /* el_runtime.c */, + 530AA788858357FBA923217E /* el_runtime.h */, + E1A7B02609E95D1686523B80 /* el_native_target.h */, + 3373ABFFE7FB5EFA9343AD02 /* el_native_vessel.c */, + EDA408C749EB5F3CA1E5EEC2 /* native_hello.c */, + 08B6475D8C7952F48EF46B10 /* Info.plist */, + ); + path = NativeHello; + sourceTree = ""; + }; + D1E4BC2FC3925E6FAFCD38F6 /* Frameworks */ = { + isa = PBXGroup; + children = ( + FF42D2E0FA0655149E573F7C /* UIKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + F1275C1CDFD05A40B9D6C717 /* NativeHello */ = { + isa = PBXNativeTarget; + buildConfigurationList = 07AFC970D6B05512B39EDE6A /* Build configuration list for PBXNativeTarget "NativeHello" */; + buildPhases = ( + DF29C8DEE5CB5F1C83967F1F /* Sources */, + 5673C72A848C5FFF94E7CF8F /* Frameworks */, + D6D57F9604C45AAEA747645E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = NativeHello; + productName = NativeHello; + productReference = BDC23A5F3FCD5D1098144064 /* NativeHello.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D8A823993D3254C7B6541F91 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastUpgradeCheck = 1500; + TargetAttributes = { + F1275C1CDFD05A40B9D6C717 = { + CreatedOnToolsVersion = 15.0; + }; + }; + }; + buildConfigurationList = 3DAB235BBB945E0CBB3EF554 /* Build configuration list for PBXProject "NativeHello" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 05039DD2316A5B41A35E094E; + productRefGroup = 177F2C27230B527E80CEAED5 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + F1275C1CDFD05A40B9D6C717 /* NativeHello */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + D6D57F9604C45AAEA747645E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + DF29C8DEE5CB5F1C83967F1F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4C6D9832BE495DD69A8573D9 /* main.m in Sources */, + 396FD073065B58F39358D798 /* el_uikit.m in Sources */, + 92BBC3E2AA055FCE840BF779 /* el_seed.c in Sources */, + 136C7763096C5037A69077AD /* el_runtime.c in Sources */, + 25136DF2A63F507EA5C7EF99 /* el_native_vessel.c in Sources */, + C05D581DBD4E52F6B7F7303E /* native_hello.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 071FC6E313815E66BB76FC93 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = NO; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_EXCEPTION = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + }; + name = Debug; + }; + 64E467FC48E757C0BDE1DFF6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = NO; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_EXCEPTION = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5DAFA921569F54D081B65492 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + GCC_PREPROCESSOR_DEFINITIONS = ( + "EL_TARGET_IOS=1", + "DEBUG=1", + "$(inherited)", + ); + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/NativeHello", + "$(inherited)", + ); + INFOPLIST_FILE = NativeHello/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_CFLAGS = ( + "-DEL_TARGET_IOS", + "$(inherited)", + ); + OTHER_LDFLAGS = ( + "-ldl", + "$(inherited)", + ); + PRODUCT_BUNDLE_IDENTIFIER = ai.neurontechnologies.el.nativehello; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 81898B3044815511B8C31D64 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + GCC_PREPROCESSOR_DEFINITIONS = ( + "EL_TARGET_IOS=1", + "$(inherited)", + ); + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/NativeHello", + "$(inherited)", + ); + INFOPLIST_FILE = NativeHello/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_CFLAGS = ( + "-DEL_TARGET_IOS", + "$(inherited)", + ); + OTHER_LDFLAGS = ( + "-ldl", + "$(inherited)", + ); + PRODUCT_BUNDLE_IDENTIFIER = ai.neurontechnologies.el.nativehello; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 3DAB235BBB945E0CBB3EF554 /* Build configuration list for PBXProject "NativeHello" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 071FC6E313815E66BB76FC93 /* Debug */, + 64E467FC48E757C0BDE1DFF6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 07AFC970D6B05512B39EDE6A /* Build configuration list for PBXNativeTarget "NativeHello" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5DAFA921569F54D081B65492 /* Debug */, + 81898B3044815511B8C31D64 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + + }; + rootObject = D8A823993D3254C7B6541F91 /* Project object */; +} diff --git a/ui/examples/native-hello-ios/NativeHello.xcodeproj/xcshareddata/xcschemes/NativeHello.xcscheme b/ui/examples/native-hello-ios/NativeHello.xcodeproj/xcshareddata/xcschemes/NativeHello.xcscheme new file mode 100644 index 0000000..6eefb67 --- /dev/null +++ b/ui/examples/native-hello-ios/NativeHello.xcodeproj/xcshareddata/xcschemes/NativeHello.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui/examples/native-hello-ios/NativeHello/Info.plist b/ui/examples/native-hello-ios/NativeHello/Info.plist new file mode 100644 index 0000000..8ab6a41 --- /dev/null +++ b/ui/examples/native-hello-ios/NativeHello/Info.plist @@ -0,0 +1,38 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UILaunchScreen + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/ui/examples/native-hello-ios/NativeHello/el_native_target.h b/ui/examples/native-hello-ios/NativeHello/el_native_target.h new file mode 100644 index 0000000..dc1edcb --- /dev/null +++ b/ui/examples/native-hello-ios/NativeHello/el_native_target.h @@ -0,0 +1,573 @@ +/* + * el_native_target.h — Native widget declarations for el programs targeting + * native desktop UI (AppKit / GTK4 / Win32). + * + * This header is designed to be included AFTER el_runtime.h without conflict: + * - It does NOT redefine el_to_float, el_from_float, or any el_runtime.h + * static inlines. + * - It does NOT redeclare __println, __print, or other functions whose + * return types differ between el_seed.h and el_runtime.h. + * - It adds: native widget builtins + float arithmetic helpers that the + * current el_runtime.h omits but elc still emits calls to. + * + * Usage: + * Inject via -include at compile time, OR #include it after el_runtime.h. + * + * clang -DEL_TARGET_MACOS -include el_native_target.h -c my_app.c ... + */ + +#pragma once + +#include +#include + +/* el_val_t must already be defined by el_runtime.h or el_seed.h. */ +#ifndef EL_VAL_T_DEFINED +typedef int64_t el_val_t; +#endif + +/* ── Float arithmetic helpers ─────────────────────────────────────────────── + * elc emits calls to float_div / float_mul etc. for Float-typed expressions. + * These were in el_runtime.c through v1.0.0-20260501 but are missing from the + * current el_runtime.h. Redeclared here as static inline to avoid link deps. + * Only defined if not already declared (old runtimes that still have them). */ + +#ifndef EL_FLOAT_OPS_DEFINED +#define EL_FLOAT_OPS_DEFINED + +/* el_to_float / el_from_float — bit-cast between el_val_t and double. + * Defined as static inline in both el_runtime.h and el_seed.h; we do NOT + * redefine them here. We rely on one of those headers being included first. */ + +static inline el_val_t float_div(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub, ur; + ua.i = a; ub.i = b; + ur.d = (ub.d != 0.0) ? (ua.d / ub.d) : 0.0; + return ur.i; +} + +static inline el_val_t float_mul(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub, ur; + ua.i = a; ub.i = b; ur.d = ua.d * ub.d; + return ur.i; +} + +static inline el_val_t float_add(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub, ur; + ua.i = a; ub.i = b; ur.d = ua.d + ub.d; + return ur.i; +} + +static inline el_val_t float_sub(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub, ur; + ua.i = a; ub.i = b; ur.d = ua.d - ub.d; + return ur.i; +} + +static inline el_val_t float_lt(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d < ub.d); +} + +static inline el_val_t float_gt(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d > ub.d); +} + +static inline el_val_t float_lte(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d <= ub.d); +} + +static inline el_val_t float_gte(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d >= ub.d); +} + +static inline el_val_t float_eq(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d == ub.d); +} + +#endif /* EL_FLOAT_OPS_DEFINED */ + +/* ── Native widget system (macOS AppKit) ──────────────────────────────────── + * Available when compiled with -DEL_TARGET_MACOS and linked with el_appkit.m. + * Widget handles are opaque int64_t slot indices; -1 = invalid. */ + +#ifdef EL_TARGET_MACOS + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_MACOS */ + +/* ── Native widget system (Linux GTK4) ────────────────────────────────────── + * Available when compiled with -DEL_TARGET_LINUX and linked with el_gtk4.c. + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * All functions have the same signatures as EL_TARGET_MACOS above. */ + +#ifdef EL_TARGET_LINUX + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader — same JSON output as EL_TARGET_MACOS */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_LINUX */ + +/* ── Native widget system (Windows Win32) ─────────────────────────────────── + * Available when compiled with -DEL_TARGET_WIN32 and linked with el_win32.c. + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * Link: el_win32.obj comctl32.lib user32.lib gdi32.lib */ + +#ifdef EL_TARGET_WIN32 + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_WIN32 */ + +/* ── Native widget system (iOS UIKit) ─────────────────────────────────────── + * Available when compiled with -DEL_TARGET_IOS and linked with el_uikit.m. + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * + * iOS lifecycle note: UIApplicationMain never returns. The el program must + * store its UI-build logic in a void(*)(void) function pointer, assign it to + * el_main_entry_fn, then call __native_run_loop. ElAppDelegate invokes + * el_main_entry_fn inside didFinishLaunchingWithOptions. + * Call el_uikit_set_args(argc, argv) from main() before __native_run_loop. */ + +#ifdef EL_TARGET_IOS + +/* Lifecycle entry-function hook — set before calling __native_run_loop. */ +extern void (*el_main_entry_fn)(void); + +/* Forward argc/argv from main() to UIApplicationMain. */ +void el_uikit_set_args(int argc, char** argv); + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_IOS */ + +/* ── Native widget system (Android JNI) ───────────────────────────────────── + * Available when compiled with -DEL_TARGET_ANDROID and linked with + * libelruntime.so (which includes el_android.c compiled by the NDK build). + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * + * Java companion: ElBridge.java (package com.neuron.el) must be compiled into + * the APK. The Activity must call ElBridge.init(this) before any widget ops. + * + * Link flags (in Android.mk or CMakeLists.txt): + * -landroid -llog -ldl */ + +#ifdef EL_TARGET_ANDROID + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); /* no-op on Android */ + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_ANDROID */ + +/* ── Native widget system (LVGL v9 — embedded / microcontroller) ───────────── + * Available when compiled with -DEL_TARGET_LVGL and linked with el_lvgl.c + * and the LVGL library (lvgl.a or lvgl source tree). + * + * Target platforms: ESP32, STM32, industrial panels. Any system with 256KB+ + * RAM and an LVGL-compatible display driver. No OS required. + * + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * + * Bare-metal / no dynamic linker: + * Compile with -DEL_LVGL_NO_DLSYM and provide: + * el_val_t el_lvgl_dispatch(const char *fn, el_val_t a, el_val_t b); + * + * Compile: + * gcc -DEL_TARGET_LVGL -I./lvgl el_lvgl.c -c -o el_lvgl.o + * # Then link with lvgl.a. */ + +#ifdef EL_TARGET_LVGL + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader — same JSON output as all other native targets */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_LVGL */ + +/* ── Native widget system (SDL2 — embedded / Pi) ──────────────────────────── + * Available when compiled with -DEL_TARGET_SDL2 and linked with el_sdl2.c. + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * + * Target: Raspberry Pi Zero, embedded Linux, any system with a framebuffer + * and SDL2 available. No GTK, no desktop environment required. + * + * Compile: + * gcc -DEL_TARGET_SDL2 $(sdl2-config --cflags) -c el_sdl2.c -o el_sdl2.o + * Link: + * $(sdl2-config --libs) -lSDL2_ttf -lSDL2_image -ldl */ + +#ifdef EL_TARGET_SDL2 + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_SDL2 */ diff --git a/ui/examples/native-hello-ios/NativeHello/el_native_vessel.c b/ui/examples/native-hello-ios/NativeHello/el_native_vessel.c new file mode 100644 index 0000000..0682965 --- /dev/null +++ b/ui/examples/native-hello-ios/NativeHello/el_native_vessel.c @@ -0,0 +1,459 @@ +#include +#include +#include "el_runtime.h" + +el_val_t native_init(void); +el_val_t native_run_loop(void); +el_val_t manifest_read(el_val_t path); +el_val_t manifest_title(el_val_t m); +el_val_t manifest_width(el_val_t m); +el_val_t manifest_height(el_val_t m); +el_val_t manifest_min_width(el_val_t m); +el_val_t manifest_min_height(el_val_t m); +el_val_t window_create(el_val_t title, el_val_t width, el_val_t height, el_val_t min_width, el_val_t min_height); +el_val_t window_from_manifest(el_val_t manifest_path); +el_val_t window_show(el_val_t handle); +el_val_t window_set_title(el_val_t handle, el_val_t title); +el_val_t vstack(el_val_t spacing); +el_val_t vstack_tight(void); +el_val_t hstack(el_val_t spacing); +el_val_t zstack(void); +el_val_t scroll(void); +el_val_t label(el_val_t text); +el_val_t button(el_val_t label); +el_val_t text_field(el_val_t placeholder); +el_val_t text_area(el_val_t placeholder); +el_val_t image(el_val_t path_or_name); +el_val_t widget_set_text(el_val_t handle, el_val_t text); +el_val_t widget_get_text(el_val_t handle); +el_val_t widget_set_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_font(el_val_t handle, el_val_t family, el_val_t size, el_val_t bold); +el_val_t widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, el_val_t bottom, el_val_t left); +el_val_t widget_set_padding_all(el_val_t handle, el_val_t p); +el_val_t widget_set_padding_xy(el_val_t handle, el_val_t px, el_val_t py); +el_val_t widget_set_width(el_val_t handle, el_val_t width); +el_val_t widget_set_height(el_val_t handle, el_val_t height); +el_val_t widget_set_flex(el_val_t handle, el_val_t flex); +el_val_t widget_set_corner_radius(el_val_t handle, el_val_t radius); +el_val_t widget_set_disabled(el_val_t handle, el_val_t disabled); +el_val_t widget_set_hidden(el_val_t handle, el_val_t hidden); +el_val_t widget_add_child(el_val_t parent, el_val_t child); +el_val_t widget_remove_child(el_val_t parent, el_val_t child); +el_val_t widget_destroy(el_val_t handle); +el_val_t widget_on_click(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_change(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_submit(el_val_t handle, el_val_t fn_name); +el_val_t hex_channel(el_val_t s, el_val_t offset); +el_val_t hex_nibble(el_val_t c); +el_val_t color_hex_r(el_val_t hex); +el_val_t color_hex_g(el_val_t hex); +el_val_t color_hex_b(el_val_t hex); +el_val_t color_hex_a(el_val_t hex); +el_val_t widget_set_color_hex(el_val_t handle, el_val_t hex); +el_val_t widget_set_bg_color_hex(el_val_t handle, el_val_t hex); +el_val_t style_surface(el_val_t handle); +el_val_t style_button_primary(el_val_t handle); +el_val_t style_label_body(el_val_t handle); +el_val_t style_label_heading(el_val_t handle); +el_val_t style_label_muted(el_val_t handle); + +el_val_t TOKEN_PRIMARY; +el_val_t TOKEN_ON_PRIMARY; +el_val_t TOKEN_BACKGROUND; +el_val_t TOKEN_ON_BG; +el_val_t TOKEN_SURFACE; +el_val_t TOKEN_ON_SURFACE; +el_val_t TOKEN_OUTLINE; +el_val_t TOKEN_ERROR; + +el_val_t native_init(void) { + __native_init(); + return 0; +} + +el_val_t native_run_loop(void) { + __native_run_loop(); + return 0; +} + +el_val_t manifest_read(el_val_t path) { + return __manifest_read(path); + return 0; +} + +el_val_t manifest_title(el_val_t m) { + return json_get_string(m, EL_STR("title")); + return 0; +} + +el_val_t manifest_width(el_val_t m) { + return json_get_int(m, EL_STR("width")); + return 0; +} + +el_val_t manifest_height(el_val_t m) { + return json_get_int(m, EL_STR("height")); + return 0; +} + +el_val_t manifest_min_width(el_val_t m) { + return json_get_int(m, EL_STR("min_width")); + return 0; +} + +el_val_t manifest_min_height(el_val_t m) { + return json_get_int(m, EL_STR("min_height")); + return 0; +} + +el_val_t window_create(el_val_t title, el_val_t width, el_val_t height, el_val_t min_width, el_val_t min_height) { + return __window_create(title, width, height, min_width, min_height); + return 0; +} + +el_val_t window_from_manifest(el_val_t manifest_path) { + el_val_t m = manifest_read(manifest_path); + el_val_t title = manifest_title(m); + el_val_t w = manifest_width(m); + el_val_t h = manifest_height(m); + el_val_t mw = manifest_min_width(m); + el_val_t mh = manifest_min_height(m); + el_val_t safe_w = ({ el_val_t _if_result_1 = 0; if ((w > 0)) { _if_result_1 = (w); } else { _if_result_1 = (1200); } _if_result_1; }); + el_val_t safe_h = ({ el_val_t _if_result_2 = 0; if ((h > 0)) { _if_result_2 = (h); } else { _if_result_2 = (800); } _if_result_2; }); + el_val_t safe_mw = ({ el_val_t _if_result_3 = 0; if ((mw > 0)) { _if_result_3 = (mw); } else { _if_result_3 = (600); } _if_result_3; }); + el_val_t safe_mh = ({ el_val_t _if_result_4 = 0; if ((mh > 0)) { _if_result_4 = (mh); } else { _if_result_4 = (400); } _if_result_4; }); + el_val_t safe_t = ({ el_val_t _if_result_5 = 0; if ((str_len(title) > 0)) { _if_result_5 = (title); } else { _if_result_5 = (EL_STR("App")); } _if_result_5; }); + return window_create(safe_t, safe_w, safe_h, safe_mw, safe_mh); + return 0; +} + +el_val_t window_show(el_val_t handle) { + __window_show(handle); + return 0; +} + +el_val_t window_set_title(el_val_t handle, el_val_t title) { + __window_set_title(handle, title); + return 0; +} + +el_val_t vstack(el_val_t spacing) { + return __vstack_create(spacing); + return 0; +} + +el_val_t vstack_tight(void) { + return __vstack_create(0); + return 0; +} + +el_val_t hstack(el_val_t spacing) { + return __hstack_create(spacing); + return 0; +} + +el_val_t zstack(void) { + return __zstack_create(); + return 0; +} + +el_val_t scroll(void) { + return __scroll_create(); + return 0; +} + +el_val_t label(el_val_t text) { + return __label_create(text); + return 0; +} + +el_val_t button(el_val_t label) { + return __button_create(label); + return 0; +} + +el_val_t text_field(el_val_t placeholder) { + return __text_field_create(placeholder); + return 0; +} + +el_val_t text_area(el_val_t placeholder) { + return __text_area_create(placeholder); + return 0; +} + +el_val_t image(el_val_t path_or_name) { + return __image_create(path_or_name); + return 0; +} + +el_val_t widget_set_text(el_val_t handle, el_val_t text) { + __widget_set_text(handle, text); + return 0; +} + +el_val_t widget_get_text(el_val_t handle) { + return __widget_get_text(handle); + return 0; +} + +el_val_t widget_set_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + __widget_set_color(handle, r, g, b, a); + return 0; +} + +el_val_t widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + __widget_set_bg_color(handle, r, g, b, a); + return 0; +} + +el_val_t widget_set_font(el_val_t handle, el_val_t family, el_val_t size, el_val_t bold) { + el_val_t bold_int = ({ el_val_t _if_result_6 = 0; if (bold) { _if_result_6 = (1); } else { _if_result_6 = (0); } _if_result_6; }); + __widget_set_font(handle, family, size, bold_int); + return 0; +} + +el_val_t widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, el_val_t bottom, el_val_t left) { + __widget_set_padding(handle, top, right, bottom, left); + return 0; +} + +el_val_t widget_set_padding_all(el_val_t handle, el_val_t p) { + __widget_set_padding(handle, p, p, p, p); + return 0; +} + +el_val_t widget_set_padding_xy(el_val_t handle, el_val_t px, el_val_t py) { + __widget_set_padding(handle, py, px, py, px); + return 0; +} + +el_val_t widget_set_width(el_val_t handle, el_val_t width) { + __widget_set_width(handle, width); + return 0; +} + +el_val_t widget_set_height(el_val_t handle, el_val_t height) { + __widget_set_height(handle, height); + return 0; +} + +el_val_t widget_set_flex(el_val_t handle, el_val_t flex) { + __widget_set_flex(handle, flex); + return 0; +} + +el_val_t widget_set_corner_radius(el_val_t handle, el_val_t radius) { + __widget_set_corner_radius(handle, radius); + return 0; +} + +el_val_t widget_set_disabled(el_val_t handle, el_val_t disabled) { + el_val_t d = ({ el_val_t _if_result_7 = 0; if (disabled) { _if_result_7 = (1); } else { _if_result_7 = (0); } _if_result_7; }); + __widget_set_disabled(handle, d); + return 0; +} + +el_val_t widget_set_hidden(el_val_t handle, el_val_t hidden) { + el_val_t h = ({ el_val_t _if_result_8 = 0; if (hidden) { _if_result_8 = (1); } else { _if_result_8 = (0); } _if_result_8; }); + __widget_set_hidden(handle, h); + return 0; +} + +el_val_t widget_add_child(el_val_t parent, el_val_t child) { + __widget_add_child(parent, child); + return 0; +} + +el_val_t widget_remove_child(el_val_t parent, el_val_t child) { + __widget_remove_child(parent, child); + return 0; +} + +el_val_t widget_destroy(el_val_t handle) { + __widget_destroy(handle); + return 0; +} + +el_val_t widget_on_click(el_val_t handle, el_val_t fn_name) { + __widget_on_click(handle, fn_name); + return 0; +} + +el_val_t widget_on_change(el_val_t handle, el_val_t fn_name) { + __widget_on_change(handle, fn_name); + return 0; +} + +el_val_t widget_on_submit(el_val_t handle, el_val_t fn_name) { + __widget_on_submit(handle, fn_name); + return 0; +} + +el_val_t hex_channel(el_val_t s, el_val_t offset) { + el_val_t hi = str_slice(s, offset, (offset + 1)); + el_val_t lo = str_slice(s, (offset + 1), (offset + 2)); + el_val_t h = hex_nibble(hi); + el_val_t l = hex_nibble(lo); + return ((h * 16) + l); + return 0; +} + +el_val_t hex_nibble(el_val_t c) { + if (str_eq(c, EL_STR("0"))) { + return 0; + } + if (str_eq(c, EL_STR("1"))) { + return 1; + } + if (str_eq(c, EL_STR("2"))) { + return 2; + } + if (str_eq(c, EL_STR("3"))) { + return 3; + } + if (str_eq(c, EL_STR("4"))) { + return 4; + } + if (str_eq(c, EL_STR("5"))) { + return 5; + } + if (str_eq(c, EL_STR("6"))) { + return 6; + } + if (str_eq(c, EL_STR("7"))) { + return 7; + } + if (str_eq(c, EL_STR("8"))) { + return 8; + } + if (str_eq(c, EL_STR("9"))) { + return 9; + } + if (str_eq(c, EL_STR("a"))) { + return 10; + } + if (str_eq(c, EL_STR("b"))) { + return 11; + } + if (str_eq(c, EL_STR("c"))) { + return 12; + } + if (str_eq(c, EL_STR("d"))) { + return 13; + } + if (str_eq(c, EL_STR("e"))) { + return 14; + } + if (str_eq(c, EL_STR("f"))) { + return 15; + } + if (str_eq(c, EL_STR("A"))) { + return 10; + } + if (str_eq(c, EL_STR("B"))) { + return 11; + } + if (str_eq(c, EL_STR("C"))) { + return 12; + } + if (str_eq(c, EL_STR("D"))) { + return 13; + } + if (str_eq(c, EL_STR("E"))) { + return 14; + } + if (str_eq(c, EL_STR("F"))) { + return 15; + } + return 0; + return 0; +} + +el_val_t color_hex_r(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_9 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_9 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_9 = (hex); } _if_result_9; }); + el_val_t v = hex_channel(s, 0); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_g(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_10 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_10 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_10 = (hex); } _if_result_10; }); + el_val_t v = hex_channel(s, 2); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_b(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_11 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_11 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_11 = (hex); } _if_result_11; }); + el_val_t v = hex_channel(s, 4); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_a(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_12 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_12 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_12 = (hex); } _if_result_12; }); + if (str_len(s) < 8) { + return el_from_float(1.0); + } + el_val_t v = hex_channel(s, 6); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t widget_set_color_hex(el_val_t handle, el_val_t hex) { + widget_set_color(handle, color_hex_r(hex), color_hex_g(hex), color_hex_b(hex), color_hex_a(hex)); + return 0; +} + +el_val_t widget_set_bg_color_hex(el_val_t handle, el_val_t hex) { + widget_set_bg_color(handle, color_hex_r(hex), color_hex_g(hex), color_hex_b(hex), color_hex_a(hex)); + return 0; +} + +el_val_t style_surface(el_val_t handle) { + widget_set_bg_color_hex(handle, TOKEN_SURFACE); + widget_set_corner_radius(handle, 8); + return 0; +} + +el_val_t style_button_primary(el_val_t handle) { + widget_set_bg_color_hex(handle, TOKEN_PRIMARY); + widget_set_color_hex(handle, TOKEN_ON_PRIMARY); + widget_set_corner_radius(handle, 8); + widget_set_padding_xy(handle, 16, 8); + return 0; +} + +el_val_t style_label_body(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_ON_BG); + widget_set_font(handle, EL_STR("system"), 14, 0); + return 0; +} + +el_val_t style_label_heading(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_ON_BG); + widget_set_font(handle, EL_STR("system"), 20, 1); + return 0; +} + +el_val_t style_label_muted(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_OUTLINE); + widget_set_font(handle, EL_STR("system"), 12, 0); + return 0; +} + +int el_vessel_main(int _argc, char** _argv) { + el_runtime_init_args(_argc, _argv); + TOKEN_PRIMARY = EL_STR("#60a5fa"); + TOKEN_ON_PRIMARY = EL_STR("#0f172a"); + TOKEN_BACKGROUND = EL_STR("#0f172a"); + TOKEN_ON_BG = EL_STR("#f8fafc"); + TOKEN_SURFACE = EL_STR("#1e293b"); + TOKEN_ON_SURFACE = EL_STR("#f8fafc"); + TOKEN_OUTLINE = EL_STR("#475569"); + TOKEN_ERROR = EL_STR("#f87171"); + return 0; +} + diff --git a/ui/examples/native-hello-ios/NativeHello/el_runtime.c b/ui/examples/native-hello-ios/NativeHello/el_runtime.c new file mode 100644 index 0000000..a735c9f --- /dev/null +++ b/ui/examples/native-hello-ios/NativeHello/el_runtime.c @@ -0,0 +1,11733 @@ +/* + * el_runtime.c — El language C runtime implementation + * + * All functions use el_val_t (= int64_t) as the universal value type. + * Strings are transported as their pointer address cast to int64_t. + * On any 64-bit system sizeof(pointer) <= sizeof(int64_t), so this is safe. + * + * Compile with: + * cc -std=c11 -I -lcurl -lpthread -o .c el_runtime.c + * + * Link requirements: -lcurl (HTTP client + LLM), -lpthread (HTTP server). + */ + +/* Feature-test macros must be set before any standard headers. _GNU_SOURCE + * exposes clock_gettime/CLOCK_REALTIME, strcasecmp, and the dlfcn extensions + * (RTLD_DEFAULT) — all of which macOS hands us without asking but glibc on + * Debian gates behind an explicit opt-in. */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "el_runtime.h" + +#include +#include /* strcasecmp */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* dlsym for http_set_handler fallback */ +#include +#include +#include +#include +#include +#include /* getrusage — memory guard */ +#ifdef HAVE_CURL +#include +#endif + +/* ── Internal allocators ─────────────────────────────────────────────────── */ + +/* + * Per-request string arena + * + * Every El string allocated via el_strbuf / el_strdup during an HTTP request + * is registered in a thread-local arena. When el_request_end() is called at + * the end of the worker thread, every arena entry is freed — recovering all + * the intermediate strings from el_str_concat chains (build_system_prompt, + * engram_compile, etc.) that are otherwise leaked forever. + * + * Long-lived allocations (state_set values, engram internal storage) call + * el_strdup_persist() / el_strbuf_persist() which bypass the arena entirely. + */ + +#define EL_ARENA_INITIAL 512 + +typedef struct { + char** ptrs; + size_t count; + size_t cap; +} ElArena; + +static _Thread_local ElArena _tl_arena = {NULL, 0, 0}; +static _Thread_local int _tl_arena_active = 0; + +/* Binary-safe fs_read length — set by fs_read, consumed by http_send_response. + * Allows serving PNGs and other binary files without strlen truncation. */ +static _Thread_local size_t _tl_fs_read_len = 0; + +static void el_arena_track(char* p) { + if (!_tl_arena_active || !p) return; + if (_tl_arena.count >= _tl_arena.cap) { + size_t nc = _tl_arena.cap == 0 ? EL_ARENA_INITIAL : _tl_arena.cap * 2; + char** grown = realloc(_tl_arena.ptrs, nc * sizeof(char*)); + if (!grown) return; /* can't track — will leak this one ptr, but don't crash */ + _tl_arena.ptrs = grown; + _tl_arena.cap = nc; + } + _tl_arena.ptrs[_tl_arena.count++] = p; +} + +/* Called by http_worker before dispatching the El handler. */ +void el_request_start(void) { + _tl_arena.count = 0; + _tl_arena_active = 1; +} + +/* Called by http_worker after the El handler returns and the response is sent. + * Frees every intermediate string allocated during the request. */ +void el_request_end(void) { + _tl_arena_active = 0; + for (size_t i = 0; i < _tl_arena.count; i++) { + free(_tl_arena.ptrs[i]); + } + _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(""); + return strdup(s); +} +static char* el_strbuf_persist(size_t n) { + char* p = malloc(n + 1); + if (!p) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + p[0] = '\0'; + return p; +} + +static char* el_strdup(const char* s) { + if (!s) { char* p = strdup(""); el_arena_track(p); return p; } + char* p = strdup(s); + el_arena_track(p); + return p; +} + +static char* el_strbuf(size_t n) { + char* p = malloc(n + 1); + if (!p) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + p[0] = '\0'; + el_arena_track(p); + return p; +} + +/* Wrap an allocated C string as el_val_t */ +static el_val_t el_wrap_str(char* s) { + return EL_STR(s); +} + +/* ── I/O ──────────────────────────────────────────────────────────────────── */ + +el_val_t println(el_val_t s) { + const char* str = EL_CSTR(s); + if (str) puts(str); + else puts(""); + return 0; +} + +el_val_t print(el_val_t s) { + const char* str = EL_CSTR(s); + if (str) fputs(str, stdout); + return 0; +} + +el_val_t readline(void) { + char buf[4096]; + if (!fgets(buf, sizeof(buf), stdin)) return el_wrap_str(el_strdup("")); + size_t len = strlen(buf); + if (len > 0 && buf[len - 1] == '\n') buf[len - 1] = '\0'; + return el_wrap_str(el_strdup(buf)); +} + +/* __read_n — read exactly n bytes from stdin. + * Allocates a buffer of size n+1, calls fread(buf, 1, n, stdin) to read + * exactly n raw bytes (including \r, \n, NUL, etc.), null-terminates, and + * returns the buffer as an El String. Returns "" on EOF or I/O error. + * + * Used by the El LSP server to read JSON-RPC message bodies after parsing + * the Content-Length header. readline() cannot be used for the body because + * it stops at the first \n and LSP JSON bodies are not newline-terminated. */ +el_val_t __read_n(el_val_t nv) { + int64_t n = EL_INT(nv); + if (n <= 0) return el_wrap_str(el_strdup("")); + char* buf = malloc((size_t)n + 1); + if (!buf) { fputs("el_runtime: __read_n: out of memory\n", stderr); return el_wrap_str(el_strdup("")); } + size_t got = fread(buf, 1, (size_t)n, stdin); + buf[got] = '\0'; + if (got == 0) { free(buf); return el_wrap_str(el_strdup("")); } + /* Track in arena so the allocation is freed when the request ends. */ + el_arena_track(buf); + return el_wrap_str(buf); +} + +/* __print_raw — write a string to stdout without any modification. + * Unlike println/print (which call puts/fputs and may add newlines or flush + * in platform-specific ways), this uses fwrite with the exact byte count so + * that embedded \r\n pairs in LSP Content-Length headers survive intact. */ +void __print_raw(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return; + size_t len = strlen(s); + fwrite(s, 1, len, stdout); + fflush(stdout); +} + +/* ── String builtins ─────────────────────────────────────────────────────── */ + +el_val_t el_str_concat(el_val_t av, el_val_t bv) { + const char* a = EL_CSTR(av); + const char* b = EL_CSTR(bv); + if (!a) a = ""; + if (!b) b = ""; + size_t la = strlen(a); + size_t lb = strlen(b); + char* out = el_strbuf(la + lb); + memcpy(out, a, la); + memcpy(out + la, b, lb); + out[la + lb] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_eq(el_val_t av, el_val_t bv) { + const char* a = EL_CSTR(av); + const char* b = EL_CSTR(bv); + if (!a || !b) return (el_val_t)(a == b); + return (el_val_t)(strcmp(a, b) == 0); +} + +el_val_t str_starts_with(el_val_t sv, el_val_t prefv) { + const char* s = EL_CSTR(sv); + const char* prefix = EL_CSTR(prefv); + if (!s || !prefix) return 0; + size_t lp = strlen(prefix); + return (el_val_t)(strncmp(s, prefix, lp) == 0); +} + +el_val_t str_ends_with(el_val_t sv, el_val_t sufv) { + const char* s = EL_CSTR(sv); + const char* suffix = EL_CSTR(sufv); + if (!s || !suffix) return 0; + size_t ls = strlen(s); + size_t lsuf = strlen(suffix); + if (lsuf > ls) return 0; + return (el_val_t)(strcmp(s + ls - lsuf, suffix) == 0); +} + +el_val_t str_len(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + return (el_val_t)strlen(s); +} + +el_val_t str_concat(el_val_t a, el_val_t b) { + return el_str_concat(a, b); +} + +el_val_t int_to_str(el_val_t n) { + char buf[32]; + snprintf(buf, sizeof(buf), "%lld", (long long)n); + return el_wrap_str(el_strdup(buf)); +} + +el_val_t str_to_int(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + return (el_val_t)atoll(s); +} + +/* native_str_to_int — El compiler-generated alias for str_to_int. + * Converts a string el_val_t to its integer representation. */ +el_val_t native_str_to_int(el_val_t sv) { return str_to_int(sv); } + +el_val_t str_slice(el_val_t sv, el_val_t start, el_val_t end) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + int64_t len = (int64_t)strlen(s); + if (start < 0) start = 0; + if (end > len) end = len; + if (start >= end) return el_wrap_str(el_strdup("")); + int64_t sz = end - start; + char* out = el_strbuf((size_t)sz); + memcpy(out, s + start, (size_t)sz); + out[sz] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_contains(el_val_t sv, el_val_t subv) { + const char* s = EL_CSTR(sv); + const char* sub = EL_CSTR(subv); + if (!s || !sub) return 0; + return (el_val_t)(strstr(s, sub) != NULL); +} + +el_val_t str_replace(el_val_t sv, el_val_t fromv, el_val_t tov) { + const char* s = EL_CSTR(sv); + const char* from = EL_CSTR(fromv); + const char* to = EL_CSTR(tov); + if (!s || !from || !to) return el_wrap_str(el_strdup(s ? s : "")); + size_t ls = strlen(s); + size_t lf = strlen(from); + size_t lt = strlen(to); + if (lf == 0) return el_wrap_str(el_strdup(s)); + size_t count = 0; + const char* p = s; + while ((p = strstr(p, from)) != NULL) { count++; p += lf; } + size_t out_sz = ls + count * lt + 1; + char* out = el_strbuf(out_sz); + char* dst = out; + p = s; + const char* found; + while ((found = strstr(p, from)) != NULL) { + size_t chunk = (size_t)(found - p); + memcpy(dst, p, chunk); dst += chunk; + memcpy(dst, to, lt); dst += lt; + p = found + lf; + } + strcpy(dst, p); + return el_wrap_str(out); +} + +el_val_t str_to_upper(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + char* out = el_strbuf(n); + for (size_t i = 0; i < n; i++) out[i] = (char)toupper((unsigned char)s[i]); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_to_lower(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + char* out = el_strbuf(n); + for (size_t i = 0; i < n; i++) out[i] = (char)tolower((unsigned char)s[i]); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_trim(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + while (*s && isspace((unsigned char)*s)) s++; + size_t n = strlen(s); + while (n > 0 && isspace((unsigned char)s[n - 1])) n--; + char* out = el_strbuf(n); + memcpy(out, s, n); + out[n] = '\0'; + return el_wrap_str(out); +} + +/* ── Math ────────────────────────────────────────────────────────────────── */ + +el_val_t el_abs(el_val_t n) { return n < 0 ? -n : n; } +el_val_t el_max(el_val_t a, el_val_t b) { return a > b ? a : b; } +el_val_t el_min(el_val_t a, el_val_t b) { return a < b ? a : b; } + +/* ── Refcounted heap objects ────────────────────────────────────────────────── + * + * ElList and ElMap carry a magic-tagged header at offset 0: + * { uint32_t magic; uint32_t refcount; ... payload ... } + * + * The magic tag distinguishes refcounted objects from raw C strings (whose + * first byte is printable ASCII < 0x80) and from small integers (which can't + * be dereferenced). el_retain / el_release sniff the magic and act only on + * matching values; everything else is a safe no-op. + * + * Both ElList and ElMap use INDIRECTION: the header is fixed-size and never + * moves. The payload arrays (elems, keys, values) live in separate heap + * allocations, so realloc-grow on append never invalidates the caller's + * pointer to the header. This is what lets us mutate-in-place safely when + * the refcount is 1 and copy-on-write when it's higher. + * + * Memory model in practice: + * Single-owner accumulator (the cg_stmts pattern) — refcount stays at 1, + * appends amortize to O(1), total memory O(N) for an N-element list. + * Multi-owner branching (the cg_if_stmt pattern) — refcount > 1, each + * append on a shared list copies, so the original is preserved for the + * else-branch. Persistent semantics where they're needed; mutation where + * they're not. */ + +#define EL_MAGIC_LIST 0xE15710A1u /* >= 0x80 in MSB so 'looks_like_string' rejects */ +#define EL_MAGIC_MAP 0xE19A704Bu + +typedef struct { + uint32_t magic; + uint32_t refcount; +} ElHeader; + +/* ── List ────────────────────────────────────────────────────────────────── */ + +typedef struct { + ElHeader hdr; + int64_t length; + int64_t capacity; + el_val_t* elems; +} ElList; + +static ElList* list_alloc(int64_t cap) { + if (cap < 4) cap = 4; + ElList* lst = malloc(sizeof(ElList)); + if (!lst) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + lst->hdr.magic = EL_MAGIC_LIST; + lst->hdr.refcount = 1; + lst->length = 0; + lst->capacity = cap; + lst->elems = malloc((size_t)cap * sizeof(el_val_t)); + if (!lst->elems) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + return lst; +} + +el_val_t el_list_empty(void) { + return EL_STR(list_alloc(4)); +} + +el_val_t el_list_new(el_val_t count, ...) { + ElList* lst = list_alloc(count > 0 ? count : 4); + va_list ap; + va_start(ap, count); + for (int64_t i = 0; i < count; i++) { + lst->elems[i] = va_arg(ap, el_val_t); + } + va_end(ap); + lst->length = count; + return EL_STR(lst); +} + +el_val_t el_list_len(el_val_t listv) { + ElList* lst = (ElList*)(uintptr_t)listv; + if (!lst) return 0; + return lst->length; +} + +el_val_t el_list_get(el_val_t listv, el_val_t index) { + ElList* lst = (ElList*)(uintptr_t)listv; + if (!lst) return 0; + if (index < 0 || index >= lst->length) return 0; + return lst->elems[index]; +} + +el_val_t el_list_append(el_val_t listv, el_val_t elem) { + ElList* old = (ElList*)(uintptr_t)listv; + if (!old) { + ElList* fresh = list_alloc(4); + fresh->elems[0] = elem; + fresh->length = 1; + return EL_STR(fresh); + } + + /* Uniquely owned: grow the elems buffer in place. The header pointer the + * caller holds doesn't move (we only realloc the inner array). This is + * the common case in compiler accumulators, and it's amortized O(1). */ + if (old->hdr.refcount <= 1) { + if (old->length >= old->capacity) { + int64_t new_cap = old->capacity > 0 ? old->capacity * 2 : 4; + el_val_t* grown = realloc(old->elems, (size_t)new_cap * sizeof(el_val_t)); + if (!grown) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + old->elems = grown; + old->capacity = new_cap; + } + old->elems[old->length++] = elem; + return listv; + } + + /* Shared: copy-on-write. The original is preserved for its other owners. */ + int64_t new_cap = old->length + 1; + if (new_cap < 4) new_cap = 4; + ElList* fresh = malloc(sizeof(ElList)); + if (!fresh) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + fresh->hdr.magic = EL_MAGIC_LIST; + fresh->hdr.refcount = 1; + fresh->length = old->length + 1; + fresh->capacity = new_cap; + fresh->elems = malloc((size_t)new_cap * sizeof(el_val_t)); + if (!fresh->elems) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + if (old->length > 0) { + memcpy(fresh->elems, old->elems, (size_t)old->length * sizeof(el_val_t)); + } + fresh->elems[old->length] = elem; + return EL_STR(fresh); +} + +el_val_t el_list_clone(el_val_t listv) { + /* Shallow copy: the new ElList owns its own header and elems buffer, but + * the elements themselves are shared (which is what callers want for the + * cg_if_stmt 'declared' pattern — cloning the spine, not its contents). + * Used by codegen at scope branch points where two child scopes need to + * see the same starting set of declared names without each other's + * mutations. */ + ElList* old = (ElList*)(uintptr_t)listv; + if (!old) return el_list_empty(); + int64_t cap = old->capacity > 0 ? old->capacity : 4; + if (cap < old->length) cap = old->length; + if (cap < 4) cap = 4; + ElList* fresh = malloc(sizeof(ElList)); + if (!fresh) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + fresh->hdr.magic = EL_MAGIC_LIST; + fresh->hdr.refcount = 1; + fresh->length = old->length; + fresh->capacity = cap; + fresh->elems = malloc((size_t)cap * sizeof(el_val_t)); + if (!fresh->elems) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + if (old->length > 0) { + memcpy(fresh->elems, old->elems, (size_t)old->length * sizeof(el_val_t)); + } + return EL_STR(fresh); +} + +/* ── Map ─────────────────────────────────────────────────────────────────── */ + +typedef struct { + ElHeader hdr; + int64_t count; + int64_t capacity; + el_val_t* keys; + el_val_t* values; +} ElMap; + +static ElMap* map_alloc(int64_t cap) { + if (cap < 4) cap = 4; + ElMap* m = malloc(sizeof(ElMap)); + if (!m) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + m->hdr.magic = EL_MAGIC_MAP; + m->hdr.refcount = 1; + m->count = 0; + m->capacity = cap; + m->keys = malloc((size_t)cap * sizeof(el_val_t)); + m->values = malloc((size_t)cap * sizeof(el_val_t)); + if (!m->keys || !m->values) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + return m; +} + +el_val_t el_map_new(el_val_t pair_count, ...) { + ElMap* m = map_alloc(pair_count > 0 ? pair_count : 4); + va_list ap; + va_start(ap, pair_count); + for (int64_t i = 0; i < pair_count; i++) { + m->keys[i] = va_arg(ap, el_val_t); + m->values[i] = va_arg(ap, el_val_t); + } + va_end(ap); + m->count = pair_count; + return EL_STR(m); +} + +static ElMap* as_map(el_val_t v) { return (ElMap*)(uintptr_t)v; } + +el_val_t el_map_get(el_val_t mapv, el_val_t keyv) { + ElMap* m = as_map(mapv); + const char* key = EL_CSTR(keyv); + if (!m || !key) return 0; + for (int64_t i = 0; i < m->count; i++) { + const char* k = EL_CSTR(m->keys[i]); + if (k && strcmp(k, key) == 0) return m->values[i]; + } + return 0; +} + +el_val_t el_get_field(el_val_t mapv, el_val_t keyv) { + return el_map_get(mapv, keyv); +} + +/* Internal: in-place set on a uniquely-owned map. */ +static el_val_t map_set_in_place(ElMap* m, el_val_t keyv, el_val_t value) { + const char* key = EL_CSTR(keyv); + if (key) { + for (int64_t i = 0; i < m->count; i++) { + const char* k = EL_CSTR(m->keys[i]); + if (k && strcmp(k, key) == 0) { m->values[i] = value; return EL_STR(m); } + } + } + if (m->count >= m->capacity) { + int64_t new_cap = m->capacity > 0 ? m->capacity * 2 : 4; + el_val_t* gk = realloc(m->keys, (size_t)new_cap * sizeof(el_val_t)); + el_val_t* gv = realloc(m->values, (size_t)new_cap * sizeof(el_val_t)); + if (!gk || !gv) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + m->keys = gk; + m->values = gv; + m->capacity = new_cap; + } + m->keys[m->count] = keyv; + m->values[m->count] = value; + m->count++; + return EL_STR(m); +} + +el_val_t el_map_set(el_val_t mapv, el_val_t keyv, el_val_t value) { + ElMap* m = as_map(mapv); + if (!m) return 0; + if (m->hdr.refcount <= 1) { + return map_set_in_place(m, keyv, value); + } + /* Shared: copy then set. The original is preserved for its other owners. */ + int64_t new_cap = m->count + 1; + if (new_cap < 4) new_cap = 4; + ElMap* fresh = malloc(sizeof(ElMap)); + if (!fresh) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + fresh->hdr.magic = EL_MAGIC_MAP; + fresh->hdr.refcount = 1; + fresh->count = m->count; + fresh->capacity = new_cap; + fresh->keys = malloc((size_t)new_cap * sizeof(el_val_t)); + fresh->values = malloc((size_t)new_cap * sizeof(el_val_t)); + if (!fresh->keys || !fresh->values) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + if (m->count > 0) { + memcpy(fresh->keys, m->keys, (size_t)m->count * sizeof(el_val_t)); + memcpy(fresh->values, m->values, (size_t)m->count * sizeof(el_val_t)); + } + return map_set_in_place(fresh, keyv, value); +} + +/* ── Refcount ops ─────────────────────────────────────────────────────────── */ +/* + * Both retain and release sniff the magic header to decide whether a value + * is a refcounted heap object. For small integers, raw C strings, and any + * value whose magic word doesn't match, both functions are no-ops. This lets + * codegen emit them on every let-binding without having to track types. + * + * Safety: we filter out obvious non-pointers (small magnitudes, misaligned + * addresses) before dereferencing. For any value that passes the filter and + * lives in a mapped page, reading the first 4 bytes is safe — strings start + * with printable ASCII (< 0x80), so their magic word will never collide with + * EL_MAGIC_LIST (0xE1...) or EL_MAGIC_MAP (0xE1...). Random integers that + * happen to look like aligned heap pointers are exceedingly unlikely to land + * on a page whose first 4 bytes match either magic. */ + +static int looks_like_heap_obj(el_val_t v) { + if (v == 0) return 0; + int64_t s = (int64_t)v; + if (s > -0x10000 && s < 0x10000) return 0; /* small ints */ + uintptr_t p = (uintptr_t)v; + if (p < 0x10000) return 0; /* low addresses */ + if (p & 0x7) return 0; /* malloc returns 8-aligned */ + return 1; +} + +void el_retain(el_val_t v) { + if (!looks_like_heap_obj(v)) return; + ElHeader* h = (ElHeader*)(uintptr_t)v; + if (h->magic == EL_MAGIC_LIST || h->magic == EL_MAGIC_MAP) { + h->refcount++; + } +} + +void el_release(el_val_t v) { + if (!looks_like_heap_obj(v)) return; + ElHeader* h = (ElHeader*)(uintptr_t)v; + if (h->magic == EL_MAGIC_LIST) { + if (h->refcount > 0 && --h->refcount == 0) { + ElList* l = (ElList*)h; + free(l->elems); + l->hdr.magic = 0; /* poison so use-after-free is detected */ + free(l); + } + } else if (h->magic == EL_MAGIC_MAP) { + if (h->refcount > 0 && --h->refcount == 0) { + ElMap* m = (ElMap*)h; + free(m->keys); + free(m->values); + m->hdr.magic = 0; + free(m); + } + } +} + +/* ── Batch 2/3 forward decls (defined later in JSON section) ────────────── */ + +typedef struct JsonBuf JsonBuf; +typedef struct JsonParser JsonParser; +static void jb_init(JsonBuf* b); +static void jb_putc(JsonBuf* b, char c); +static void jb_puts(JsonBuf* b, const char* s); +static void jb_emit_escaped(JsonBuf* b, const char* s); +static int looks_like_string(el_val_t v); +static const char* json_find_key(const char* s, const char* key); +static const char* json_skip_value(const char* p); +static char* jp_parse_string_raw(JsonParser* jp); + +/* Struct definitions are visible here because batch 2/3 helpers above use + * them by value; the bodies (jb_init, etc.) appear in the JSON section. */ +struct JsonBuf { + char* buf; + size_t len; + size_t cap; +}; + +struct JsonParser { + const char* p; + const char* end; + int err; +}; + +/* ── Batch 2: Real HTTP (libcurl client + POSIX-socket server) ───────────── */ +/* + * Client: blocking libcurl easy-handle calls. Errors are returned as a JSON + * fragment {"error":"..."} so callers can detect via str_starts_with("{") / + * json_get_string("error", ...). + * + * Server: bind/listen/accept loop on a TCP socket. Each accepted connection + * is handled in its own pthread (detached). A semaphore-style counter caps + * concurrent in-flight connections at HTTP_MAX_CONNS (64). When the cap is + * reached, accept() blocks until a worker exits. This prevents runaway + * thread creation under high load. + * + * Handler dispatch: El does not expose first-class function references at + * the runtime layer, so the second argument to http_serve(port, handler) is + * treated as a string name (or any el_val_t — the runtime ignores its + * value and uses the registry). Callers register a C-level handler via + * + * extern void el_runtime_register_handler(const char* name, + * el_val_t (*fn)(el_val_t, + * el_val_t, + * el_val_t)); + * + * and select the active handler by calling http_set_handler("name") from + * El, or by setting it directly through the C registry. If no handler is + * registered, the server replies with a 200 carrying a default message so + * the loop is observable. + */ + +/* ── JSON error helper (used by HTTP, PQ, crypto stubs) ─────────────────── */ + +/* JSON-escape an arbitrary C string into an allocated buffer. */ +static char* json_escape_alloc(const char* s) { + if (!s) return el_strdup(""); + JsonBuf b; jb_init(&b); + for (const char* p = s; *p; p++) { + unsigned char c = (unsigned char)*p; + switch (c) { + case '"': jb_puts(&b, "\\\""); break; + case '\\': jb_puts(&b, "\\\\"); break; + case '\n': jb_puts(&b, "\\n"); break; + case '\r': jb_puts(&b, "\\r"); break; + case '\t': jb_puts(&b, "\\t"); break; + default: + if (c < 0x20) { + char tmp[8]; snprintf(tmp, sizeof(tmp), "\\u%04x", c); + jb_puts(&b, tmp); + } else jb_putc(&b, (char)c); + } + } + return b.buf; +} + +static el_val_t http_error_json(const char* msg) { + char* esc = json_escape_alloc(msg ? msg : "unknown error"); + char* buf = el_strbuf(strlen(esc) + 16); + sprintf(buf, "{\"error\":\"%s\"}", esc); + free(esc); + return el_wrap_str(buf); +} + +#ifdef HAVE_CURL +/* ── HTTP client write-callback buffer ───────────────────────────────────── */ + +typedef struct { + char* data; + size_t len; + size_t cap; +} HttpBuf; + +static void httpbuf_init(HttpBuf* b) { + b->cap = 1024; + b->len = 0; + b->data = malloc(b->cap); + if (!b->data) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + b->data[0] = '\0'; +} + +static void httpbuf_append(HttpBuf* b, const void* src, size_t n) { + if (b->len + n + 1 > b->cap) { + while (b->len + n + 1 > b->cap) b->cap *= 2; + b->data = realloc(b->data, b->cap); + if (!b->data) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + } + memcpy(b->data + b->len, src, n); + b->len += n; + b->data[b->len] = '\0'; +} + +static size_t http_write_cb(char* ptr, size_t size, size_t nmemb, void* ud) { + size_t n = size * nmemb; + httpbuf_append((HttpBuf*)ud, ptr, n); + return n; +} + +/* HTTP timeout (ms) — read once from EL_HTTP_TIMEOUT_MS, default 60000. + * Applied via CURLOPT_TIMEOUT_MS on every libcurl request. */ +static long _el_http_timeout_ms = -1; +static long el_http_timeout_ms(void) { + long v = __atomic_load_n(&_el_http_timeout_ms, __ATOMIC_ACQUIRE); + if (v >= 0) return v; + const char* s = getenv("EL_HTTP_TIMEOUT_MS"); + long parsed = 60000L; + if (s && *s) { + char* end = NULL; + long n = strtol(s, &end, 10); + if (end != s && n > 0) parsed = n; + } + __atomic_store_n(&_el_http_timeout_ms, parsed, __ATOMIC_RELEASE); + return parsed; +} + +/* Internal: do a libcurl request; takes optional body/headers, optional method override. */ +static el_val_t http_do(const char* method, const char* url, const char* body, + struct curl_slist* extra_headers) { + if (!url || !*url) return http_error_json("empty url"); + CURL* c = curl_easy_init(); + if (!c) return http_error_json("curl_easy_init failed"); + HttpBuf rb; httpbuf_init(&rb); + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, http_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, &rb); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, el_http_timeout_ms()); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-runtime/1.0"); + if (extra_headers) curl_easy_setopt(c, CURLOPT_HTTPHEADER, extra_headers); + if (method && strcmp(method, "POST") == 0) { + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, body ? body : ""); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(body ? strlen(body) : 0)); + } else if (method && strcmp(method, "DELETE") == 0) { + curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, "DELETE"); + } + CURLcode rc = curl_easy_perform(c); + curl_easy_cleanup(c); + if (rc != CURLE_OK) { + free(rb.data); + const char* m = errbuf[0] ? errbuf : curl_easy_strerror(rc); + return http_error_json(m); + } + return el_wrap_str(rb.data); +} + +el_val_t http_get(el_val_t url) { + return http_do("GET", EL_CSTR(url), NULL, NULL); +} + +el_val_t http_post(el_val_t url, el_val_t body) { + return http_do("POST", EL_CSTR(url), EL_CSTR(body), NULL); +} + +el_val_t http_post_json(el_val_t url, el_val_t json_body) { + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + el_val_t r = http_do("POST", EL_CSTR(url), EL_CSTR(json_body), h); + curl_slist_free_all(h); + return r; +} + +/* Build a curl_slist from an ElMap of name -> value strings. */ +static struct curl_slist* headers_from_map(el_val_t headers_map) { + struct curl_slist* h = NULL; + ElMap* m = as_map(headers_map); + if (!m) return NULL; + for (int64_t i = 0; i < m->count; i++) { + const char* k = EL_CSTR(m->keys[i]); + const char* v = EL_CSTR(m->values[i]); + if (!k || !v) continue; + size_t n = strlen(k) + strlen(v) + 4; + char* line = malloc(n); + if (!line) continue; + snprintf(line, n, "%s: %s", k, v); + h = curl_slist_append(h, line); + free(line); + } + return h; +} + +el_val_t http_get_with_headers(el_val_t url, el_val_t headers_map) { + struct curl_slist* h = headers_from_map(headers_map); + el_val_t r = http_do("GET", EL_CSTR(url), NULL, h); + if (h) curl_slist_free_all(h); + return r; +} + +el_val_t http_post_with_headers(el_val_t url, el_val_t body, el_val_t headers_map) { + struct curl_slist* h = headers_from_map(headers_map); + el_val_t r = http_do("POST", EL_CSTR(url), EL_CSTR(body), h); + if (h) curl_slist_free_all(h); + return r; +} + +/* http_post_json_with_headers — POST with Content-Type: application/json plus + * any additional headers supplied as an El map. Combines http_post_json and + * http_post_with_headers: the Content-Type header is always prepended so + * callers do not have to include it in their map. */ +el_val_t http_post_json_with_headers(el_val_t url, el_val_t headers_map, el_val_t json_body) { + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + /* Append caller-supplied headers from the map */ + ElMap* m = as_map(headers_map); + if (m) { + for (int64_t i = 0; i < m->count; i++) { + const char* k = EL_CSTR(m->keys[i]); + const char* v = EL_CSTR(m->values[i]); + if (!k || !v) continue; + size_t n = strlen(k) + strlen(v) + 4; + char* line = malloc(n); + if (!line) continue; + snprintf(line, n, "%s: %s", k, v); + h = curl_slist_append(h, line); + free(line); + } + } + el_val_t r = http_do("POST", EL_CSTR(url), EL_CSTR(json_body), h); + curl_slist_free_all(h); + return r; +} + +el_val_t http_post_form_auth(el_val_t url, el_val_t form_body, el_val_t auth_header) { + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/x-www-form-urlencoded"); + const char* a = EL_CSTR(auth_header); + if (a && *a) { + size_t n = strlen(a) + 32; + char* line = malloc(n); + snprintf(line, n, "Authorization: %s", a); + h = curl_slist_append(h, line); + free(line); + } + el_val_t r = http_do("POST", EL_CSTR(url), EL_CSTR(form_body), h); + curl_slist_free_all(h); + return r; +} + +/* HTTP DELETE — mirrors http_post but with CURLOPT_CUSTOMREQUEST=DELETE. + * Returns response body on success; on transport failure returns an error + * JSON fragment (same convention as http_get/http_post). Callers that + * expect "" on failure should check for a leading '{' and an "error" key. */ +el_val_t http_delete(el_val_t url) { + return http_do("DELETE", EL_CSTR(url), NULL, NULL); +} + +/* ── HTTP → file streaming ──────────────────────────────────────────────── + * + * Why this exists: el_val_t strings are NUL-terminated by convention, so + * accumulating an HTTP response into an httpbuf and then wrapping its + * `.data` pointer with el_wrap_str() loses the byte length. Any consumer + * that does strlen() on the wrapped pointer truncates the body at the + * first embedded NUL. Audio (MP3, WAV, OGG), images (PNG, JPEG), and any + * other binary payload hits this. The vessels that download such bodies + * (e.g. ElevenLabs TTS → MP3) get silently corrupted files. + * + * The fix: wire libcurl's CURLOPT_WRITEFUNCTION directly to fwrite() + * against a fopen()-ed FILE*. The bytes never pass through an el_val_t + * string, so embedded NULs are preserved verbatim. Caller's contract is + * just "a file at this path with the response body in it". */ + +static size_t http_file_write_cb(char* ptr, size_t size, size_t nmemb, void* ud) { + FILE* f = (FILE*)ud; + return fwrite(ptr, size, nmemb, f); +} + +/* Internal: stream body to file. method is "GET" or "POST". body may be NULL + * (GET) or NUL-terminated (POST). headers may be NULL. Returns 1/0. */ +static el_val_t http_do_to_file(const char* method, const char* url, + const char* body, struct curl_slist* extra_headers, + const char* output_path) { + if (!url || !*url) return 0; + if (!output_path || !*output_path) return 0; + FILE* f = fopen(output_path, "wb"); + if (!f) return 0; + + CURL* c = curl_easy_init(); + if (!c) { fclose(f); remove(output_path); return 0; } + + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, http_file_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, f); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, el_http_timeout_ms()); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-runtime/1.0"); + curl_easy_setopt(c, CURLOPT_FAILONERROR, 1L); /* 4xx/5xx → CURLE_HTTP_RETURNED_ERROR */ + if (extra_headers) curl_easy_setopt(c, CURLOPT_HTTPHEADER, extra_headers); + + if (method && strcmp(method, "POST") == 0) { + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, body ? body : ""); + /* For the request body we still rely on strlen — POST bodies are + * caller-controlled and JSON/text in every known El use case. + * If a future caller needs a binary POST body, add a *_bytes + * variant that takes an explicit length, mirroring fs_write_bytes. */ + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(body ? strlen(body) : 0)); + } + + CURLcode rc = curl_easy_perform(c); + curl_easy_cleanup(c); + + /* Flush + close before signalling success, so the file is fully on disk + * by the time the caller reads back. */ + int flush_ok = (fflush(f) == 0); + int close_ok = (fclose(f) == 0); + + if (rc != CURLE_OK || !flush_ok || !close_ok) { + remove(output_path); + return 0; + } + return 1; +} + +el_val_t http_get_to_file(el_val_t url, el_val_t headers_map, el_val_t output_path) { + struct curl_slist* h = headers_from_map(headers_map); + el_val_t r = http_do_to_file("GET", EL_CSTR(url), NULL, h, EL_CSTR(output_path)); + if (h) curl_slist_free_all(h); + return r; +} + +el_val_t http_post_to_file(el_val_t url, el_val_t body, el_val_t headers_map, el_val_t output_path) { + struct curl_slist* h = headers_from_map(headers_map); + el_val_t r = http_do_to_file("POST", EL_CSTR(url), EL_CSTR(body), h, EL_CSTR(output_path)); + if (h) curl_slist_free_all(h); + return r; +} +#endif /* HAVE_CURL */ + +/* ── HTTP server (POSIX sockets + pthreads) ──────────────────────────────── */ + +#define HTTP_MAX_CONNS 64 + +typedef el_val_t (*http_handler_fn)(el_val_t method, el_val_t path, el_val_t body); + +typedef struct { + char* name; + http_handler_fn fn; +} HttpHandlerEntry; + +static HttpHandlerEntry _http_handlers[32]; +static size_t _http_handler_count = 0; +static char* _http_active_handler = NULL; +static pthread_mutex_t _http_handler_mu = PTHREAD_MUTEX_INITIALIZER; + +static pthread_mutex_t _http_conn_mu = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t _http_conn_cv = PTHREAD_COND_INITIALIZER; +static int _http_conn_active = 0; + +/* Public C-level API: register a handler by name. Programs that want El + * `http_serve` to dispatch into their handler call this from main() before + * http_serve. Not declared in the header to keep the public API minimal — + * extern lookup works since C symbols are global. */ +void el_runtime_register_handler(const char* name, http_handler_fn fn); +void el_runtime_register_handler(const char* name, http_handler_fn fn) { + if (!name || !fn) return; + pthread_mutex_lock(&_http_handler_mu); + for (size_t i = 0; i < _http_handler_count; i++) { + if (strcmp(_http_handlers[i].name, name) == 0) { + _http_handlers[i].fn = fn; + pthread_mutex_unlock(&_http_handler_mu); + return; + } + } + if (_http_handler_count < sizeof(_http_handlers) / sizeof(_http_handlers[0])) { + _http_handlers[_http_handler_count].name = el_strdup(name); + _http_handlers[_http_handler_count].fn = fn; + _http_handler_count++; + } + pthread_mutex_unlock(&_http_handler_mu); +} + +el_val_t http_set_handler(el_val_t name) { + const char* n = EL_CSTR(name); + pthread_mutex_lock(&_http_handler_mu); + free(_http_active_handler); + _http_active_handler = el_strdup(n ? n : ""); + /* If the name is not yet in the registry, try dlsym lookup against + * the running binary's symbol table. Every El `fn name(...)` compiles + * to a global C symbol with that exact name, so El programs can self- + * register their own handlers just by calling http_set_handler("name"). */ + if (n && *n) { + int found = 0; + for (size_t i = 0; i < _http_handler_count; i++) { + if (strcmp(_http_handlers[i].name, n) == 0) { found = 1; break; } + } + if (!found) { + void* sym = dlsym(RTLD_DEFAULT, n); + if (sym && _http_handler_count < sizeof(_http_handlers) / sizeof(_http_handlers[0])) { + _http_handlers[_http_handler_count].name = el_strdup(n); + _http_handlers[_http_handler_count].fn = (http_handler_fn)sym; + _http_handler_count++; + } + } + } + pthread_mutex_unlock(&_http_handler_mu); + return 0; +} + +static http_handler_fn http_lookup_active(void) { + http_handler_fn out = NULL; + pthread_mutex_lock(&_http_handler_mu); + if (_http_active_handler) { + for (size_t i = 0; i < _http_handler_count; i++) { + if (strcmp(_http_handlers[i].name, _http_active_handler) == 0) { + out = _http_handlers[i].fn; break; + } + } + } + pthread_mutex_unlock(&_http_handler_mu); + return out; +} + +/* Auto-detect Content-Type from response body. */ +static const char* http_detect_content_type(const char* body) { + if (!body) return "text/plain; charset=utf-8"; + const char* p = body; + /* Binary magic bytes — check before stripping whitespace */ + if ((unsigned char)p[0] == 0x89 && p[1]=='P' && p[2]=='N' && p[3]=='G') + return "image/png"; + if ((unsigned char)p[0] == 0xFF && (unsigned char)p[1] == 0xD8) + return "image/jpeg"; + if (strncmp(p, "GIF8", 4) == 0) return "image/gif"; + if (strncmp(p, "RIFF", 4) == 0) return "image/webp"; + if (strncmp(p, "wOFF", 4) == 0) return "font/woff"; + if (strncmp(p, "wOF2", 4) == 0) return "font/woff2"; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (strncasecmp(p, "= cap) { + if (cap >= 1024 * 1024) { free(buf); return -1; } + cap *= 2; + buf = realloc(buf, cap); + if (!buf) return -1; + } + ssize_t n = recv(fd, buf + len, cap - len - 1, 0); + if (n <= 0) { free(buf); return -1; } + len += (size_t)n; + buf[len] = '\0'; + if (strstr(buf, "\r\n\r\n")) break; + } + /* Parse request line */ + char* sp1 = strchr(buf, ' '); + if (!sp1) { free(buf); return -1; } + *sp1 = '\0'; + *out_method = el_strdup(buf); + char* path_start = sp1 + 1; + char* sp2 = strchr(path_start, ' '); + if (!sp2) { free(*out_method); *out_method = NULL; free(buf); return -1; } + *sp2 = '\0'; + *out_path = el_strdup(path_start); + char* hdr_end = strstr(sp2 + 1, "\r\n\r\n"); + /* Capture the raw header block (after the request line's CRLF, up to + * but not including the terminating \r\n\r\n) for callers that asked + * for it. The legacy 3-arg path passes NULL and skips this. */ + if (out_headers_block) { + char* hdr_start = strstr(sp2 + 1, "\r\n"); + if (hdr_start && hdr_start < hdr_end) { + hdr_start += 2; + size_t hb_len = (size_t)(hdr_end - hdr_start); + char* hb = malloc(hb_len + 1); + if (hb) { + memcpy(hb, hdr_start, hb_len); + hb[hb_len] = '\0'; + *out_headers_block = hb; + } + } else { + *out_headers_block = el_strdup(""); + } + } + /* Find Content-Length */ + long content_length = 0; + char* hp = sp2 + 1; + while (hp < hdr_end) { + char* line_end = strstr(hp, "\r\n"); + /* line_end == hdr_end means we're on the LAST header line — its + * trailing \r\n is the same \r\n that begins the \r\n\r\n header + * terminator. Process this line; only stop when line_end is past + * hdr_end (which means the parser walked off the end of the + * header block). The previous condition (line_end >= hdr_end) + * silently dropped any Content-Length that appeared as the last + * header — exactly what real curl/clients tend to emit. */ + if (!line_end || line_end > hdr_end) break; + if (strncasecmp(hp, "Content-Length:", 15) == 0) { + content_length = strtol(hp + 15, NULL, 10); + if (content_length < 0) content_length = 0; + if (content_length > 64 * 1024 * 1024) content_length = 64 * 1024 * 1024; + } + hp = line_end + 2; + } + /* Body: any bytes already read past hdr_end, plus more recv */ + char* body_start = hdr_end + 4; + size_t body_have = (buf + len) - body_start; + char* body = malloc((size_t)content_length + 1); + if (!body) { free(*out_method); free(*out_path); *out_method=NULL; *out_path=NULL; free(buf); return -1; } + if ((long)body_have > content_length) body_have = (size_t)content_length; + if (body_have > 0) memcpy(body, body_start, body_have); + while ((long)body_have < content_length) { + ssize_t n = recv(fd, body + body_have, (size_t)content_length - body_have, 0); + if (n <= 0) break; + body_have += (size_t)n; + } + body[body_have] = '\0'; + *out_body = body; + free(buf); + return 0; +} + +/* Reason phrase for common HTTP statuses. Falls back to "Status" for the + * long tail — clients only care about the numeric code. */ +static const char* http_reason_phrase(int status) { + switch (status) { + case 200: return "OK"; + case 201: return "Created"; + case 202: return "Accepted"; + case 204: return "No Content"; + case 301: return "Moved Permanently"; + case 302: return "Found"; + case 303: return "See Other"; + case 304: return "Not Modified"; + case 307: return "Temporary Redirect"; + case 308: return "Permanent Redirect"; + case 400: return "Bad Request"; + case 401: return "Unauthorized"; + case 403: return "Forbidden"; + case 404: return "Not Found"; + case 405: return "Method Not Allowed"; + case 409: return "Conflict"; + case 410: return "Gone"; + case 422: return "Unprocessable Entity"; + case 429: return "Too Many Requests"; + case 500: return "Internal Server Error"; + case 501: return "Not Implemented"; + case 502: return "Bad Gateway"; + case 503: return "Service Unavailable"; + case 504: return "Gateway Timeout"; + default: return "Status"; + } +} + +/* Best-effort send with retry on partial writes. */ +static int http_send_all(int fd, const char* p, size_t left) { + while (left > 0) { + ssize_t w = send(fd, p, left, 0); + if (w <= 0) return -1; + p += w; left -= (size_t)w; + } + return 0; +} + +/* Discriminator that http_response() embeds at the start of its envelope. + * A handler returning a string starting with this exact prefix is treated + * as a structured response; anything else is treated as a raw body. */ +#define EL_HTTP_RESPONSE_TAG "{\"el_http_response\":1" + +/* Keys that conflict with runtime-managed headers are silently dropped to + * avoid double-emission — the runtime always emits its own Content-Length + * and Connection: close. Content-Type from the envelope IS allowed and + * overrides auto-detection. */ +static int http_header_is_managed(const char* k) { + return strcasecmp(k, "Content-Length") == 0 + || strcasecmp(k, "Connection") == 0; +} + +/* Walk an ElMap of header pairs and emit each as `K: V\r\n` into JsonBuf b. + * Sets *out_saw_content_type to 1 if the map contained an explicit + * Content-Type so the caller can skip auto-detection. */ +static void http_emit_headers_from_map(JsonBuf* b, el_val_t headers_map, + int* out_saw_content_type) { + *out_saw_content_type = 0; + if (headers_map == 0) return; + ElMap* m = (ElMap*)(uintptr_t)headers_map; + if (!m || m->hdr.magic != EL_MAGIC_MAP) return; + for (int64_t i = 0; i < m->count; i++) { + const char* k = EL_CSTR(m->keys[i]); + const char* v = EL_CSTR(m->values[i]); + if (!k || !v) continue; + if (http_header_is_managed(k)) continue; + if (strcasecmp(k, "Content-Type") == 0) *out_saw_content_type = 1; + jb_puts(b, k); + jb_puts(b, ": "); + jb_puts(b, v); + jb_puts(b, "\r\n"); + } +} + +/* Parse the envelope produced by http_response(). On success returns 1 and + * populates *out_status, *out_headers_map (an ElMap el_val_t — caller must + * el_release), and *out_body (allocated). On failure returns 0. + * + * Implementation: feeds the entire envelope through the recursive-descent + * JSON parser (which builds proper ElMap/ElList values), then pulls the + * three top-level fields by name. Avoids re-stringifying the headers map + * since json_stringify() does not support nested objects. */ +static int http_parse_envelope(const char* s, int* out_status, + el_val_t* out_headers_map, char** out_body, + el_val_t* out_parsed_root) { + if (!s) return 0; + if (strncmp(s, EL_HTTP_RESPONSE_TAG, + sizeof(EL_HTTP_RESPONSE_TAG) - 1) != 0) return 0; + + el_val_t parsed = json_parse(EL_STR(s)); + if (parsed == EL_NULL) return 0; + + int status = 200; + el_val_t hmap = 0; + char* body = NULL; + + el_val_t sv = el_map_get(parsed, EL_STR("status")); + if (sv != 0) { + /* status comes back as an integer — el_val_t holds it directly. */ + long sc = (long)sv; + if (sc >= 100 && sc <= 599) status = (int)sc; + } + + el_val_t hv = el_map_get(parsed, EL_STR("headers")); + if (hv != 0) { + ElMap* hm = (ElMap*)(uintptr_t)hv; + if (hm && hm->hdr.magic == EL_MAGIC_MAP) hmap = hv; + } + + el_val_t bv = el_map_get(parsed, EL_STR("body")); + if (bv != 0) { + const char* bs = EL_CSTR(bv); + if (bs) body = el_strdup(bs); + } + if (!body) body = el_strdup(""); + + *out_status = status; + *out_headers_map = hmap; + *out_body = body; + *out_parsed_root = parsed; /* caller releases to free hmap + entries */ + return 1; +} + +/* Lightweight `__status__` envelope: if the body's first key is `__status__` + * and its value is a numeric literal, lift the status to the HTTP layer and + * strip the marker from the body before sending. This is the common case for + * El handlers that want to return 4xx/5xx without going through + * http_response() — they just prepend `{"__status__":,...}` to the JSON + * they were already returning. + * + * We deliberately recognise ONLY the first-key form so the contract is cheap + * to detect and unambiguous: `{"__status__":401,"error":"unauthorized"}` is + * an envelope, but `{"error":"...","__status__":401}` is not. Product code + * controls placement. + * + * On success returns 1 with *out_status set and *out_body_alloc populated + * with a freshly malloc'd body (caller frees). On failure returns 0 and + * leaves outputs untouched. */ +static int http_parse_status_envelope(const char* s, int* out_status, + char** out_body_alloc) { + if (!s) return 0; + const char* p = s; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '{') return 0; + p++; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + static const char marker[] = "\"__status__\""; + size_t mlen = sizeof(marker) - 1; + if (strncmp(p, marker, mlen) != 0) return 0; + p += mlen; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != ':') return 0; + p++; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p < '0' || *p > '9') return 0; /* non-numeric -> not an envelope */ + int status = 0; + while (*p >= '0' && *p <= '9') { + status = status * 10 + (*p - '0'); + p++; + } + if (status < 100 || status > 599) return 0; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + /* Two trailing shapes accepted: + * ,"k":v,...} -> body becomes {"k":v,...} + * } -> body becomes {} + * Anything else (e.g. `:` re-appearing, garbage) drops the envelope so + * we don't strip what we shouldn't. */ + if (*p == '}') { + *out_status = status; + *out_body_alloc = el_strdup("{}"); + return 1; + } + if (*p != ',') return 0; + p++; /* skip the comma; the rest of the object follows */ + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + /* Build the trimmed body: '{' + remainder. */ + size_t rest_len = strlen(p); + char* out = (char*)malloc(rest_len + 2); + if (!out) return 0; + out[0] = '{'; + memcpy(out + 1, p, rest_len); + out[rest_len + 1] = '\0'; + *out_status = status; + *out_body_alloc = out; + return 1; +} + +/* Send a fully-built HTTP response. If `body` starts with the envelope tag, + * unpack status/headers/body. Otherwise emit the historical 200-OK with + * auto-detected Content-Type. */ +/* Thread-local flag: if 1, http_send_response writes status + headers but + * NO body (HEAD method behaviour). Set by http_worker before calling + * http_send_response, cleared after. */ +static __thread int _tl_http_head_only = 0; + +static void http_send_response(int fd, const char* body) { + if (!body) body = ""; + + int status = 200; + el_val_t env_headers_map = 0; + char* env_body = NULL; + el_val_t env_parsed_root = 0; + int is_envelope = http_parse_envelope(body, &status, + &env_headers_map, &env_body, + &env_parsed_root); + + /* If the rich http_response() envelope didn't claim this body, try the + * lightweight `__status__` form. This second envelope is malloc-backed so + * we route it through env_body and let the existing cleanup path free it + * — same lifetime contract, no special case at the bottom of the + * function. */ + if (!is_envelope) { + char* trimmed = NULL; + if (http_parse_status_envelope(body, &status, &trimmed)) { + env_body = trimmed; + is_envelope = 1; + } + } + + const char* eff_body = is_envelope ? env_body : body; + /* Use the real byte count from fs_read if available (handles binary files + * with embedded null bytes — PNG, WOFF2, etc.). Fall back to strlen for + * normal text/JSON responses where _tl_fs_read_len is 0. */ + size_t blen = (_tl_fs_read_len > 0) ? _tl_fs_read_len : strlen(eff_body); + _tl_fs_read_len = 0; /* consume — one-shot per response */ + int head_only = _tl_http_head_only; + + JsonBuf hdrs; jb_init(&hdrs); + int saw_content_type = 0; + if (is_envelope) { + http_emit_headers_from_map(&hdrs, env_headers_map, + &saw_content_type); + } + if (!saw_content_type) { + jb_puts(&hdrs, "Content-Type: "); + jb_puts(&hdrs, http_detect_content_type(eff_body)); + jb_puts(&hdrs, "\r\n"); + } + + char status_line[64]; + int sl = snprintf(status_line, sizeof(status_line), + "HTTP/1.1 %d %s\r\n", + status, http_reason_phrase(status)); + if (sl < 0) { + if (env_parsed_root) el_release(env_parsed_root); + free(env_body); free(hdrs.buf); return; + } + + char tail[128]; + int tl = snprintf(tail, sizeof(tail), + "Content-Length: %zu\r\n" + "Connection: close\r\n" + "\r\n", blen); + if (tl < 0) { + if (env_parsed_root) el_release(env_parsed_root); + free(env_body); free(hdrs.buf); return; + } + + if (http_send_all(fd, status_line, (size_t)sl) == 0 + && http_send_all(fd, hdrs.buf, hdrs.len) == 0 + && http_send_all(fd, tail, (size_t)tl) == 0 + && (head_only + /* HEAD requests echo headers + Content-Length but no body. */ + ? 1 + : http_send_all(fd, eff_body, blen) == 0)) { + /* sent successfully */ + } + + if (env_parsed_root) el_release(env_parsed_root); + free(env_body); + free(hdrs.buf); +} + +typedef struct { + int fd; +} HttpWorkerArg; + +static void* http_worker(void* arg) { + HttpWorkerArg* a = (HttpWorkerArg*)arg; + int fd = a->fd; + free(a); + char *method = NULL, *path = NULL, *body = NULL; + if (http_read_request(fd, &method, &path, &body, NULL) == 0) { + http_handler_fn h = http_lookup_active(); + char* response = NULL; + /* HEAD: dispatch as GET so existing handlers respond with the same + * body, but flag the response writer to emit headers only. RFC 9110 + * requires HEAD to mirror GET headers + Content-Length without body. */ + int head_only = (method && strcmp(method, "HEAD") == 0); + const char* dispatch_method = head_only ? "GET" : method; + el_request_start(); /* begin per-request arena */ + if (h) { + el_val_t r = h(EL_STR(dispatch_method), EL_STR(path), EL_STR(body)); + const char* rs = EL_CSTR(r); + /* Copy response out BEFORE arena teardown. + * For binary files, _tl_fs_read_len holds the real byte count — + * use memcpy instead of strdup so null bytes are preserved. */ + size_t rlen = _tl_fs_read_len > 0 ? _tl_fs_read_len : (rs ? strlen(rs) : 0); + response = malloc(rlen + 1); + if (response && rs) { memcpy(response, rs, rlen); response[rlen] = '\0'; } + else if (response) { response[0] = '\0'; } + } else { + response = el_strdup_persist("el-runtime: no http handler registered"); + } + el_request_end(); /* free all intermediate strings */ + _tl_http_head_only = head_only; + http_send_response(fd, response); + _tl_http_head_only = 0; + free(response); + } + free(method); free(path); free(body); + close(fd); + /* release a slot */ + pthread_mutex_lock(&_http_conn_mu); + _http_conn_active--; + pthread_cond_signal(&_http_conn_cv); + pthread_mutex_unlock(&_http_conn_mu); + return NULL; +} + +el_val_t http_serve(el_val_t port, el_val_t handler) { + /* If `handler` looks like a string name, register it as the active handler. */ + const char* hname = EL_CSTR(handler); + if (hname && looks_like_string(handler)) { + http_set_handler(handler); + } + int p = (int)port; + if (p <= 0 || p > 65535) { fprintf(stderr, "http_serve: invalid port %d\n", p); return 0; } + /* Dual-stack: AF_INET6 with IPV6_V6ONLY=0 accepts both IPv4 and IPv6. + * This makes `localhost` work in browsers that resolve it to ::1 first. */ + int sock = socket(AF_INET6, SOCK_STREAM, 0); + if (sock < 0) { perror("socket"); return 0; } + int yes = 1; int no = 0; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no)); + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr = in6addr_any; + addr.sin6_port = htons((uint16_t)p); + if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + perror("bind"); close(sock); return 0; + } + if (listen(sock, 64) < 0) { perror("listen"); close(sock); return 0; } + fprintf(stderr, "[http] listening on [::]:%d (dual-stack)\n", p); + while (1) { + struct sockaddr_in6 cli; + socklen_t clen = sizeof(cli); + int cfd = accept(sock, (struct sockaddr*)&cli, &clen); + if (cfd < 0) { + if (errno == EINTR) continue; + perror("accept"); break; + } + pthread_mutex_lock(&_http_conn_mu); + while (_http_conn_active >= HTTP_MAX_CONNS) { + pthread_cond_wait(&_http_conn_cv, &_http_conn_mu); + } + _http_conn_active++; + pthread_mutex_unlock(&_http_conn_mu); + HttpWorkerArg* arg = malloc(sizeof(HttpWorkerArg)); + if (!arg) { close(cfd); continue; } + arg->fd = cfd; + pthread_t tid; + if (pthread_create(&tid, NULL, http_worker, arg) != 0) { + close(cfd); free(arg); + pthread_mutex_lock(&_http_conn_mu); + _http_conn_active--; + pthread_cond_signal(&_http_conn_cv); + pthread_mutex_unlock(&_http_conn_mu); + continue; + } + pthread_detach(tid); + } + close(sock); + return 0; +} + +/* ── HTTP server v2 — request headers + structured response ──────────────── */ +/* + * v2 widens the handler signature from + * (method, path, body) -> body_string + * to + * (method, path, headers_map, body) -> body_string_or_envelope + * + * The response envelope is detected uniformly inside http_send_response — so + * 4-arg handlers can return either a plain body or http_response(...). The + * 3-arg path stays untouched in spirit (its handlers still build plain + * bodies; the envelope tag, being `{"el_http_response":1`, will never + * collide with normal JSON the legacy server.el routes return). + * + * Registry is parallel to the 3-arg handler registry: separate name table, + * separate active-handler slot, separate dlsym fallback. Mixing v1 and v2 + * handlers in the same process is fine — they don't share the active slot. */ + +typedef el_val_t (*http_handler4_fn)(el_val_t method, el_val_t path, + el_val_t headers_map, el_val_t body); + +typedef struct { + char* name; + http_handler4_fn fn; +} HttpHandler4Entry; + +static HttpHandler4Entry _http_handlers4[32]; +static size_t _http_handler4_count = 0; +static char* _http_active_handler4 = NULL; + +void el_runtime_register_handler_v2(const char* name, http_handler4_fn fn); +void el_runtime_register_handler_v2(const char* name, http_handler4_fn fn) { + if (!name || !fn) return; + pthread_mutex_lock(&_http_handler_mu); + for (size_t i = 0; i < _http_handler4_count; i++) { + if (strcmp(_http_handlers4[i].name, name) == 0) { + _http_handlers4[i].fn = fn; + pthread_mutex_unlock(&_http_handler_mu); + return; + } + } + if (_http_handler4_count < + sizeof(_http_handlers4) / sizeof(_http_handlers4[0])) { + _http_handlers4[_http_handler4_count].name = el_strdup(name); + _http_handlers4[_http_handler4_count].fn = fn; + _http_handler4_count++; + } + pthread_mutex_unlock(&_http_handler_mu); +} + +el_val_t http_set_handler_v2(el_val_t name) { + const char* n = EL_CSTR(name); + pthread_mutex_lock(&_http_handler_mu); + free(_http_active_handler4); + _http_active_handler4 = el_strdup(n ? n : ""); + if (n && *n) { + int found = 0; + for (size_t i = 0; i < _http_handler4_count; i++) { + if (strcmp(_http_handlers4[i].name, n) == 0) { found = 1; break; } + } + if (!found) { + void* sym = dlsym(RTLD_DEFAULT, n); + if (sym && _http_handler4_count < + sizeof(_http_handlers4) / sizeof(_http_handlers4[0])) { + _http_handlers4[_http_handler4_count].name = el_strdup(n); + _http_handlers4[_http_handler4_count].fn = + (http_handler4_fn)sym; + _http_handler4_count++; + } + } + } + pthread_mutex_unlock(&_http_handler_mu); + return 0; +} + +static http_handler4_fn http_lookup_active_v2(void) { + http_handler4_fn out = NULL; + pthread_mutex_lock(&_http_handler_mu); + if (_http_active_handler4) { + for (size_t i = 0; i < _http_handler4_count; i++) { + if (strcmp(_http_handlers4[i].name, + _http_active_handler4) == 0) { + out = _http_handlers4[i].fn; break; + } + } + } + pthread_mutex_unlock(&_http_handler_mu); + return out; +} + +/* Build an ElMap from the raw header block produced by http_read_request. + * Keys are lowercased (RFC 7230 — case-insensitive); values have leading + * whitespace trimmed. Repeated headers with the same name are joined with + * ", " in arrival order, matching standard library behaviour elsewhere. */ +static el_val_t http_build_headers_map(const char* hdr_block) { + el_val_t m = el_map_new(0); + if (!hdr_block || !*hdr_block) return m; + const char* p = hdr_block; + while (*p) { + const char* line_end = strstr(p, "\r\n"); + const char* end = line_end ? line_end : p + strlen(p); + const char* colon = NULL; + for (const char* c = p; c < end; c++) { + if (*c == ':') { colon = c; break; } + } + if (colon && colon > p) { + size_t klen = (size_t)(colon - p); + char* key = malloc(klen + 1); + if (key) { + for (size_t i = 0; i < klen; i++) { + unsigned char ch = (unsigned char)p[i]; + key[i] = (char)tolower(ch); + } + key[klen] = '\0'; + const char* vstart = colon + 1; + while (vstart < end && (*vstart == ' ' || *vstart == '\t')) vstart++; + size_t vlen = (size_t)(end - vstart); + /* Strip trailing OWS just in case. */ + while (vlen > 0 + && (vstart[vlen - 1] == ' ' + || vstart[vlen - 1] == '\t')) vlen--; + /* Coalesce repeats: if key already present, append ", value". */ + el_val_t existing = el_map_get(m, EL_STR(key)); + if (existing != 0 && looks_like_string(existing)) { + const char* old = EL_CSTR(existing); + size_t olen = strlen(old); + char* combined = malloc(olen + 2 + vlen + 1); + if (combined) { + memcpy(combined, old, olen); + memcpy(combined + olen, ", ", 2); + memcpy(combined + olen + 2, vstart, vlen); + combined[olen + 2 + vlen] = '\0'; + m = el_map_set(m, EL_STR(key), EL_STR(combined)); + } + free(key); + } else { + char* val = malloc(vlen + 1); + if (val) { + memcpy(val, vstart, vlen); + val[vlen] = '\0'; + m = el_map_set(m, EL_STR(key), EL_STR(val)); + } else { + free(key); + } + } + } + } + if (!line_end) break; + p = line_end + 2; + } + return m; +} + +static void* http_worker_v2(void* arg) { + HttpWorkerArg* a = (HttpWorkerArg*)arg; + int fd = a->fd; + free(a); + char *method = NULL, *path = NULL, *body = NULL, *hdr_block = NULL; + if (http_read_request(fd, &method, &path, &body, &hdr_block) == 0) { + http_handler4_fn h = http_lookup_active_v2(); + char* response = NULL; + int head_only = (method && strcmp(method, "HEAD") == 0); + const char* dispatch_method = head_only ? "GET" : method; + el_request_start(); /* begin per-request arena */ + if (h) { + el_val_t hmap = http_build_headers_map(hdr_block ? hdr_block : ""); + el_val_t r = h(EL_STR(dispatch_method), EL_STR(path), hmap, EL_STR(body)); + const char* rs = EL_CSTR(r); + size_t rlen = _tl_fs_read_len > 0 ? _tl_fs_read_len : (rs ? strlen(rs) : 0); + response = malloc(rlen + 1); + if (response && rs) { memcpy(response, rs, rlen); response[rlen] = '\0'; } + else if (response) { response[0] = '\0'; } + el_release(hmap); + } else { + response = el_strdup_persist( + "el-runtime: no v2 http handler registered " + "(call http_set_handler_v2)"); + } + el_request_end(); /* free all intermediate strings */ + _tl_http_head_only = head_only; + http_send_response(fd, response); + _tl_http_head_only = 0; + free(response); + } + free(method); free(path); free(body); free(hdr_block); + close(fd); + pthread_mutex_lock(&_http_conn_mu); + _http_conn_active--; + pthread_cond_signal(&_http_conn_cv); + pthread_mutex_unlock(&_http_conn_mu); + return NULL; +} + +el_val_t http_serve_v2(el_val_t port, el_val_t handler) { + const char* hname = EL_CSTR(handler); + if (hname && looks_like_string(handler)) { + http_set_handler_v2(handler); + } + int p = (int)port; + if (p <= 0 || p > 65535) { + fprintf(stderr, "http_serve_v2: invalid port %d\n", p); + return 0; + } + /* Dual-stack: same as http_serve - AF_INET6 + IPV6_V6ONLY=0. */ + int sock = socket(AF_INET6, SOCK_STREAM, 0); + if (sock < 0) { perror("socket"); return 0; } + int yes = 1; int no = 0; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no)); + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr = in6addr_any; + addr.sin6_port = htons((uint16_t)p); + if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + perror("bind"); close(sock); return 0; + } + if (listen(sock, 64) < 0) { perror("listen"); close(sock); return 0; } + fprintf(stderr, "[http v2] listening on [::]:%d (dual-stack)\n", p); + while (1) { + struct sockaddr_in6 cli; + socklen_t clen = sizeof(cli); + int cfd = accept(sock, (struct sockaddr*)&cli, &clen); + if (cfd < 0) { + if (errno == EINTR) continue; + perror("accept"); break; + } + pthread_mutex_lock(&_http_conn_mu); + while (_http_conn_active >= HTTP_MAX_CONNS) { + pthread_cond_wait(&_http_conn_cv, &_http_conn_mu); + } + _http_conn_active++; + pthread_mutex_unlock(&_http_conn_mu); + HttpWorkerArg* arg = malloc(sizeof(HttpWorkerArg)); + if (!arg) { close(cfd); continue; } + arg->fd = cfd; + pthread_t tid; + if (pthread_create(&tid, NULL, http_worker_v2, arg) != 0) { + close(cfd); free(arg); + pthread_mutex_lock(&_http_conn_mu); + _http_conn_active--; + pthread_cond_signal(&_http_conn_cv); + pthread_mutex_unlock(&_http_conn_mu); + continue; + } + pthread_detach(tid); + } + close(sock); + return 0; +} + +/* Build the response envelope a 4-arg handler can return. We hand-write + * the JSON so the discriminator key always lands first — the runtime's + * http_parse_envelope() detects it via prefix match. headers_json must be + * either "" (empty), "{}" (empty object), or a well-formed JSON object + * literal; anything else will produce a malformed envelope and the runtime + * will treat the whole string as a plain body (no envelope detected). */ +el_val_t http_response(el_val_t status, el_val_t headers_json, el_val_t body) { + long sc = (long)status; + if (sc < 100 || sc > 599) sc = 200; + const char* hj = EL_CSTR(headers_json); + if (!hj || !*hj) hj = "{}"; + /* Light validation: must start with '{' and end with '}'. */ + size_t hlen = strlen(hj); + int hj_ok = (hlen >= 2 && hj[0] == '{' && hj[hlen - 1] == '}'); + if (!hj_ok) hj = "{}"; + const char* b = EL_CSTR(body); + if (!b) b = ""; + + JsonBuf out; jb_init(&out); + jb_puts(&out, EL_HTTP_RESPONSE_TAG); /* {"el_http_response":1 */ + jb_puts(&out, ",\"status\":"); + char num[32]; + snprintf(num, sizeof(num), "%ld", sc); + jb_puts(&out, num); + jb_puts(&out, ",\"headers\":"); + jb_puts(&out, hj); + jb_puts(&out, ",\"body\":"); + jb_emit_escaped(&out, b); + jb_putc(&out, '}'); + return el_wrap_str(out.buf); +} + +/* ── Filesystem ──────────────────────────────────────────────────────────── */ + +el_val_t fs_read(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + _tl_fs_read_len = 0; + if (!path) return el_wrap_str(el_strdup("")); + FILE* f = fopen(path, "rb"); + if (!f) return el_wrap_str(el_strdup("")); + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + if (sz < 0) { fclose(f); return el_wrap_str(el_strdup("")); } /* pipe/special file */ + char* buf = el_strbuf((size_t)sz); + size_t got = fread(buf, 1, (size_t)sz, f); + buf[got] = '\0'; + _tl_fs_read_len = got; /* store real byte count for binary-safe send */ + fclose(f); + return el_wrap_str(buf); +} + +el_val_t fs_write(el_val_t pathv, el_val_t contentv) { + const char* path = EL_CSTR(pathv); + const char* content = EL_CSTR(contentv); + if (!path || !content) return 0; + FILE* f = fopen(path, "wb"); + if (!f) return 0; + size_t n = strlen(content); + size_t written = fwrite(content, 1, n, f); + fclose(f); + return written == n ? 1 : 0; +} + +/* fs_write_bytes — explicit-length binary write. Bypasses strlen so embedded + * NULs survive. Caller must know the byte count (e.g. from base64_decode, + * or the fixed 32-byte sha256_bytes/hmac_sha256_bytes outputs). + * + * If `length` is negative, treats as failure. If `length` is 0, creates an + * empty file (still useful as a "touch with content" primitive). */ +el_val_t fs_write_bytes(el_val_t pathv, el_val_t bytesv, el_val_t lengthv) { + const char* path = EL_CSTR(pathv); + const char* bytes = EL_CSTR(bytesv); + int64_t n = (int64_t)lengthv; + if (!path || !bytes) return 0; + if (n < 0) return 0; + FILE* f = fopen(path, "wb"); + if (!f) return 0; + size_t written = (n > 0) ? fwrite(bytes, 1, (size_t)n, f) : 0; + int flush_ok = (fflush(f) == 0); + int close_ok = (fclose(f) == 0); + if (!flush_ok || !close_ok || written != (size_t)n) { + remove(path); + return 0; + } + return 1; +} + +// stdout_to_file / stdout_restore — redirect process stdout to a file and +// restore it. Used by the compiler's JS post-processing pipeline to capture +// codegen output before piping through terser / obfuscator. +#include +static int _el_saved_stdout_fd = -1; + +el_val_t stdout_to_file(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + if (!path) return (el_val_t)(int64_t)-1; + fflush(stdout); + _el_saved_stdout_fd = dup(STDOUT_FILENO); + int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd < 0) return (el_val_t)(int64_t)-1; + dup2(fd, STDOUT_FILENO); + close(fd); + return (el_val_t)(int64_t)0; +} + +el_val_t stdout_restore(void) { + if (_el_saved_stdout_fd >= 0) { + fflush(stdout); + dup2(_el_saved_stdout_fd, STDOUT_FILENO); + close(_el_saved_stdout_fd); + _el_saved_stdout_fd = -1; + } + return (el_val_t)(int64_t)0; +} + +// exec_command — run a shell command, return exit code (0 = success). +// Used by elb and other El tooling to invoke subprocesses. +el_val_t exec_command(el_val_t cmdv) { + const char* cmd = EL_CSTR(cmdv); + if (!cmd) return (el_val_t)(int64_t)-1; + int ret = system(cmd); + return (el_val_t)(int64_t)ret; +} + +// exec_capture — run a shell command, capture stdout, return as String. +// Returns "" on failure. +el_val_t exec_capture(el_val_t cmdv) { + const char* cmd = EL_CSTR(cmdv); + if (!cmd) return el_wrap_str(el_strdup("")); + FILE* f = popen(cmd, "r"); + if (!f) return el_wrap_str(el_strdup("")); + JsonBuf b; jb_init(&b); + char buf[4096]; + while (fgets(buf, sizeof(buf), f)) jb_puts(&b, buf); + pclose(f); + return el_wrap_str(b.buf); +} + +// exec — run a shell command via /bin/sh, capture stdout, return as String. +// Times out after 30 seconds. Returns "" on any error. +// El name: exec(cmd) -> String +el_val_t exec(el_val_t cmdv) { + const char* cmd = EL_CSTR(cmdv); + if (!cmd || !*cmd) return el_wrap_str(el_strdup("")); + /* Build a time-limited command: wrap with timeout(1) if available, + * otherwise rely on the 30s read loop guard below. We use the simple + * popen approach with a deadline measured by wall clock so the caller + * is never blocked indefinitely. */ + FILE* f = popen(cmd, "r"); + if (!f) return el_wrap_str(el_strdup("")); + JsonBuf b; jb_init(&b); + char buf[4096]; + /* 30-second wall-clock deadline */ + time_t deadline = time(NULL) + 30; + while (time(NULL) < deadline) { + if (fgets(buf, sizeof(buf), f) == NULL) break; + jb_puts(&b, buf); + } + pclose(f); + return el_wrap_str(b.buf); +} + +// exec_bg — run a shell command in background, return PID as String. +// The child process runs independently; the caller is not blocked. +// Returns "" on fork failure. +// El name: exec_bg(cmd) -> String +el_val_t exec_bg(el_val_t cmdv) { + const char* cmd = EL_CSTR(cmdv); + if (!cmd || !*cmd) return el_wrap_str(el_strdup("")); + pid_t pid = fork(); + if (pid < 0) { + /* fork failed */ + return el_wrap_str(el_strdup("")); + } + if (pid == 0) { + /* child: detach from parent's stdio, exec via shell */ + setsid(); + int devnull = open("/dev/null", O_RDWR); + if (devnull >= 0) { + dup2(devnull, STDIN_FILENO); + dup2(devnull, STDOUT_FILENO); + dup2(devnull, STDERR_FILENO); + close(devnull); + } + execl("/bin/sh", "sh", "-c", cmd, (char*)NULL); + _exit(127); + } + /* parent: convert pid to string and return immediately */ + char pidbuf[32]; + snprintf(pidbuf, sizeof(pidbuf), "%d", (int)pid); + return el_wrap_str(el_strdup(pidbuf)); +} + +el_val_t fs_list(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + el_val_t lst = el_list_empty(); + if (!path) return lst; + DIR* d = opendir(path); + if (!d) return lst; + struct dirent* e; + while ((e = readdir(d)) != NULL) { + if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) continue; + lst = el_list_append(lst, el_wrap_str(el_strdup(e->d_name))); + } + closedir(d); + return lst; +} + +/* fs_list_json — return directory entries as a JSON array of strings. + * Returns "[]" for missing or non-directory paths. Excludes "." and "..". */ +el_val_t fs_list_json(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + if (!path) return EL_STR("[]"); + DIR* d = opendir(path); + if (!d) return EL_STR("[]"); + /* Collect entries first so we can build the JSON in one pass. */ + char** names = NULL; + size_t count = 0, cap = 0; + struct dirent* e; + while ((e = readdir(d)) != NULL) { + if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) continue; + if (count >= cap) { + cap = cap ? cap * 2 : 16; + names = realloc(names, cap * sizeof(char*)); + if (!names) { closedir(d); return EL_STR("[]"); } + } + names[count++] = strdup(e->d_name); + } + closedir(d); + /* Build JSON array. */ + size_t sz = 3; /* "[]" + NUL */ + for (size_t i = 0; i < count; i++) sz += strlen(names[i]) * 2 + 6; /* conservative */ + char* buf = malloc(sz); + if (!buf) { for (size_t i = 0; i < count; i++) free(names[i]); free(names); return EL_STR("[]"); } + size_t pos = 0; + buf[pos++] = '['; + for (size_t i = 0; i < count; i++) { + if (i > 0) buf[pos++] = ','; + buf[pos++] = '"'; + for (const char* p = names[i]; *p; p++) { + if (*p == '"' || *p == '\\') buf[pos++] = '\\'; + else if (*p == '\n') { buf[pos++] = '\\'; buf[pos++] = 'n'; continue; } + else if (*p == '\t') { buf[pos++] = '\\'; buf[pos++] = 't'; continue; } + buf[pos++] = *p; + } + buf[pos++] = '"'; + free(names[i]); + } + free(names); + buf[pos++] = ']'; + buf[pos] = '\0'; + return el_wrap_str(buf); +} + +/* fs_exists — true iff stat(path) succeeds. Symlinks are followed. */ +el_val_t fs_exists(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + if (!path || !*path) return 0; + struct stat st; + return (el_val_t)(stat(path, &st) == 0 ? 1 : 0); +} + +/* fs_mkdir — create directory at path with mode 0755, mkdir -p semantics. + * Returns 1 if path exists or was created (incl. all parents); 0 on failure. + * Walks the path component-by-component so missing intermediate dirs are + * also created. An existing leaf is not an error. */ +el_val_t fs_mkdir(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + if (!path || !*path) return 0; + size_t n = strlen(path); + char* buf = malloc(n + 1); + if (!buf) return 0; + memcpy(buf, path, n + 1); + /* Walk components; create each prefix in turn. */ + for (size_t i = 1; i <= n; i++) { + if (buf[i] == '/' || buf[i] == '\0') { + char saved = buf[i]; + buf[i] = '\0'; + if (buf[0] != '\0') { + if (mkdir(buf, 0755) != 0 && errno != EEXIST) { + /* Tolerate the case where this prefix exists as a non-dir + * only when stat says it's a directory. */ + struct stat st; + if (stat(buf, &st) != 0 || !S_ISDIR(st.st_mode)) { + free(buf); + return 0; + } + } + } + buf[i] = saved; + } + } + free(buf); + return 1; +} + +/* ── URL encoding ─────────────────────────────────────────────────────────── */ + +/* RFC 3986 percent-encoding for URL components (form bodies, query strings). + * Unreserved set: A-Z a-z 0-9 - _ . ~ — passed through verbatim. + * Everything else (including space) becomes %XX hex. */ +el_val_t url_encode(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + static const char hex[] = "0123456789ABCDEF"; + size_t n = strlen(s); + char* out = el_strbuf(n * 3); + size_t o = 0; + for (size_t i = 0; i < n; i++) { + unsigned char c = (unsigned char)s[i]; + if ((c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + c == '-' || c == '_' || c == '.' || c == '~') { + out[o++] = (char)c; + } else { + out[o++] = '%'; + out[o++] = hex[(c >> 4) & 0xF]; + out[o++] = hex[c & 0xF]; + } + } + out[o] = '\0'; + return el_wrap_str(out); +} + +/* Decode percent-encoded URL component. '+' becomes space (form-encoded); + * malformed %-escapes are emitted verbatim. */ +el_val_t url_decode(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + char* out = el_strbuf(n); + size_t o = 0; + for (size_t i = 0; i < n; i++) { + char c = s[i]; + if (c == '+') { + out[o++] = ' '; + } else if (c == '%' && i + 2 < n) { + char h1 = s[i + 1], h2 = s[i + 2]; + int v1 = (h1 >= '0' && h1 <= '9') ? h1 - '0' + : (h1 >= 'a' && h1 <= 'f') ? h1 - 'a' + 10 + : (h1 >= 'A' && h1 <= 'F') ? h1 - 'A' + 10 : -1; + int v2 = (h2 >= '0' && h2 <= '9') ? h2 - '0' + : (h2 >= 'a' && h2 <= 'f') ? h2 - 'a' + 10 + : (h2 >= 'A' && h2 <= 'F') ? h2 - 'A' + 10 : -1; + if (v1 >= 0 && v2 >= 0) { + out[o++] = (char)((v1 << 4) | v2); + i += 2; + } else { + out[o++] = c; + } + } else { + out[o++] = c; + } + } + out[o] = '\0'; + return el_wrap_str(out); +} + +/* ── html_raw ──────────────────────────────────────────────────────────────── + * Identity passthrough for raw HTML template interpolation. + * El's {raw(expr)} compiles to html_raw(expr) — the value is output as-is + * without any escaping. The caller is responsible for safety. + */ +el_val_t html_raw(el_val_t s) { + return s; +} + +/* ── html_escape ───────────────────────────────────────────────────────────── + * Escape < > " ' & for safe HTML text interpolation. + * El's {expr} in HTML templates compiles to html_escape(expr). + */ +el_val_t html_escape(el_val_t sv) { + const char* src = EL_CSTR(sv); + if (!src) return EL_STR(""); + size_t len = strlen(src); + /* Worst case: every byte → 6 chars (") */ + char* out = (char*)malloc(len * 6 + 1); + if (!out) return sv; + el_arena_track(out); + char* p = out; + for (size_t i = 0; i < len; i++) { + unsigned char c = (unsigned char)src[i]; + switch (c) { + case '&': memcpy(p, "&", 5); p += 5; break; + case '<': memcpy(p, "<", 4); p += 4; break; + case '>': memcpy(p, ">", 4); p += 4; break; + case '"': memcpy(p, """, 6); p += 6; break; + case '\'': memcpy(p, "'", 5); p += 5; break; + default: *p++ = (char)c; break; + } + } + *p = '\0'; + return el_wrap_str(out); +} + +/* ── HTML allowlist sanitizer ──────────────────────────────────────────────── + * el_html_sanitize(input, allowlist_json) + * + * Strict allowlist HTML cleaner. Replaces the older denylist patterns + * (str_replace cascades that wrapped dangerous tags in HTML comments and + * renamed `on*` attributes). The denylist approach is fragile: comment- + * wrapping can be re-broken by a literal `-->` inside an attacker-supplied + * attribute value, and every new attack vector requires a code change. + * + * Design: + * - Single-pass byte-level state machine. + * - Tag and attribute names are matched case-insensitively against the + * allowlist. Unknown tags are dropped entirely (the open and close + * markers are stripped; their inner text content survives, escaped). + * - A small set of "dangerous container" tags (script, style, iframe, + * object, embed, form, plus a few rarer ones) drop themselves AND + * their full subtree — text between `` is + * CDATA-like and must not be re-emitted as escaped text either. + * - Comments (), doctype (), CDATA (), + * and processing instructions () are dropped entirely. + * - Text content outside dropped subtrees is HTML-escaped (&, <, >, ", '). + * - Attribute values are unquoted/dequoted, then re-emitted with double + * quotes around the cleanly-escaped value. + * - For `` and any `src` attribute, the URL scheme is validated: + * only http:, https:, mailto:, fragment-only `#anchor`, or relative + * paths are allowed. Anything else (javascript:, data:, vbscript:, + * about:, file:, etc.) drops the attribute. + * - Self-closing void tags (br, hr, img, etc.) emit without a close tag. + * - Malformed input (unclosed tag at EOF, bad attribute syntax) drops + * the pending tag and continues. Pre-encoded entities (<, &, + * etc.) are passed through verbatim — the browser will decode them + * safely on render. + * + * Allowlist format (JSON string): + * {"p":[],"a":["href","title"],"strong":[],...} + * - Key = lowercase tag name. + * - Value = JSON array of allowed attribute names (lowercase). + * - Empty array means tag allowed but no attributes survive. + * + * Output is a freshly-allocated arena-tracked el_val_t string. */ + +/* Internal byte buffer with realloc-doubling. Used during sanitization; + * the final result is copied into an arena-tracked el_strbuf so the caller + * sees standard runtime memory semantics. */ +typedef struct { + char* data; + size_t len; + size_t cap; +} html_buf_t; + +static void html_buf_init(html_buf_t* b) { + b->cap = 256; + b->data = malloc(b->cap); + if (!b->data) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + b->len = 0; +} + +static void html_buf_grow(html_buf_t* b, size_t need) { + if (b->len + need + 1 <= b->cap) return; + size_t nc = b->cap; + while (b->len + need + 1 > nc) nc *= 2; + char* nd = realloc(b->data, nc); + if (!nd) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + b->data = nd; + b->cap = nc; +} + +static void html_buf_putc(html_buf_t* b, char c) { + html_buf_grow(b, 1); + b->data[b->len++] = c; +} + +static void html_buf_puts(html_buf_t* b, const char* s) { + if (!s) return; + size_t n = strlen(s); + html_buf_grow(b, n); + memcpy(b->data + b->len, s, n); + b->len += n; +} + +static void html_buf_free(html_buf_t* b) { + free(b->data); + b->data = NULL; + b->len = b->cap = 0; +} + +/* ASCII tolower, locale-independent. */ +static int html_tolower(int c) { + return (c >= 'A' && c <= 'Z') ? c + 32 : c; +} + +/* Case-insensitive ASCII compare of [a, a+n) against c-string `s`. + * Returns 1 iff lengths match and bytes are equal under tolower. */ +static int html_ieq_n(const char* a, size_t n, const char* s) { + if (!a || !s) return 0; + if (strlen(s) != n) return 0; + for (size_t i = 0; i < n; i++) { + if (html_tolower((unsigned char)a[i]) != html_tolower((unsigned char)s[i])) return 0; + } + return 1; +} + +/* Case-insensitive ASCII compare of two byte slices. */ +static int html_iemem(const char* a, const char* b, size_t n) { + for (size_t i = 0; i < n; i++) { + if (html_tolower((unsigned char)a[i]) != html_tolower((unsigned char)b[i])) return 0; + } + return 1; +} + +/* Walk a JSON allowlist object and find the value (an array) for a given + * tag key, comparing case-insensitively. On hit returns a pointer to the + * opening `[` of the array and writes the byte length of the array span + * (including the brackets) to *out_len. On miss returns NULL. + * + * The parser is intentionally tiny: it does not handle escapes inside + * keys (allowlist authors do not need them), and it relies on balanced + * brackets/quotes within the value array. */ +static const char* html_allowlist_find(const char* allow, const char* tag, + size_t tag_len, size_t* out_len) { + if (!allow) return NULL; + const char* p = allow; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '{') return NULL; + p++; + while (*p) { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p == '}' || *p == 0) return NULL; + if (*p != '"') return NULL; + p++; + const char* k = p; + while (*p && *p != '"') p++; + if (*p != '"') return NULL; + size_t klen = (size_t)(p - k); + p++; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != ':') return NULL; + p++; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') return NULL; + const char* arr_start = p; + int depth = 0; + int in_str = 0; + while (*p) { + char c = *p; + if (in_str) { + if (c == '\\' && p[1]) { p += 2; continue; } + if (c == '"') in_str = 0; + } else { + if (c == '"') in_str = 1; + else if (c == '[') depth++; + else if (c == ']') { depth--; if (depth == 0) { p++; break; } } + } + p++; + } + size_t alen = (size_t)(p - arr_start); + int match = (klen == tag_len) && html_iemem(k, tag, klen); + if (match) { + if (out_len) *out_len = alen; + return arr_start; + } + } + return NULL; +} + +/* Returns 1 iff `attr` (length attr_len) appears as a string element + * in the JSON array slice [arr, arr+arr_len). Comparison is case- + * insensitive. */ +static int html_attr_in_array(const char* arr, size_t arr_len, + const char* attr, size_t attr_len) { + if (!arr || arr_len < 2) return 0; + const char* p = arr + 1; + const char* end = arr + arr_len - 1; + while (p < end) { + while (p < end && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',')) p++; + if (p >= end) return 0; + if (*p != '"') return 0; + p++; + const char* s = p; + while (p < end && *p != '"') { + if (*p == '\\' && p + 1 < end) p++; + p++; + } + if (p >= end) return 0; + size_t slen = (size_t)(p - s); + p++; + if (slen == attr_len && html_iemem(s, attr, slen)) return 1; + } + return 0; +} + +/* Hard-coded set of tags whose content is ALSO dropped (entire subtree). */ +static int html_is_dangerous_container(const char* tag, size_t tag_len) { + static const char* names[] = { + "script", "style", "iframe", "object", "embed", "form", + "noscript", "noembed", "template", "svg", "math", "frame", + "frameset", "applet", "audio", "video", "source", "track", + NULL + }; + for (int i = 0; names[i]; i++) { + if (html_ieq_n(tag, tag_len, names[i])) return 1; + } + return 0; +} + +/* HTML void elements — emit without a close tag. */ +static int html_is_void(const char* tag, size_t tag_len) { + static const char* names[] = { + "area", "base", "br", "col", "embed", "hr", "img", "input", + "link", "meta", "param", "source", "track", "wbr", + NULL + }; + for (int i = 0; names[i]; i++) { + if (html_ieq_n(tag, tag_len, names[i])) return 1; + } + return 0; +} + +/* Append a single byte HTML-escaped into the output buffer. */ +static void html_escape_byte(html_buf_t* out, unsigned char c) { + switch (c) { + case '<': html_buf_puts(out, "<"); break; + case '>': html_buf_puts(out, ">"); break; + case '"': html_buf_puts(out, """); break; + case '\'': html_buf_puts(out, "'"); break; + default: html_buf_putc(out, (char)c); break; + } +} + +/* Validate a URL value against the allowlist of safe schemes for hrefs. + * Returns 1 iff the URL is safe to emit. Acceptable forms: + * - http:// or https:// (case-insensitive) + * - mailto: + * - fragment-only `#anchor` + * - relative path that does not contain a colon before the first + * slash/?/# (so `foo/bar`, `/foo`, `?x=1` are OK; `javascript:x` is + * not — its colon precedes any path/hash/query separator). + * + * URL leading whitespace and embedded ASCII control bytes (TAB, LF, CR) + * are stripped before the scheme test, mirroring how browsers normalise + * URLs (these bytes are otherwise a known XSS bypass: `java\tscript:`). */ +static int html_url_is_safe(const char* url, size_t len) { + if (!url || len == 0) return 1; /* empty href is harmless */ + size_t i = 0; + while (i < len) { + unsigned char c = (unsigned char)url[i]; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == 0x0B || c == 0x0C) { + i++; continue; + } + break; + } + if (i >= len) return 1; /* whitespace only */ + if (url[i] == '#') return 1; /* fragment only */ + if (url[i] == '/' || url[i] == '?') return 1; /* relative */ + /* Find the first scheme-terminating character. */ + size_t scheme_end = (size_t)-1; + for (size_t j = i; j < len; j++) { + char c = url[j]; + if (c == ':') { scheme_end = j; break; } + if (c == '/' || c == '?' || c == '#') break; + } + if (scheme_end == (size_t)-1) return 1; /* no colon → relative path */ + /* Lowercase the scheme, stripping embedded control bytes. */ + char scheme[32]; + size_t sl = 0; + for (size_t j = i; j < scheme_end && sl < sizeof(scheme) - 1; j++) { + unsigned char c = (unsigned char)url[j]; + if (c == '\t' || c == '\n' || c == '\r' || c == 0x0B || c == 0x0C) continue; + scheme[sl++] = (char)html_tolower(c); + } + scheme[sl] = '\0'; + if (strcmp(scheme, "http") == 0) return 1; + if (strcmp(scheme, "https") == 0) return 1; + if (strcmp(scheme, "mailto") == 0) return 1; + return 0; +} + +el_val_t el_html_sanitize(el_val_t input_v, el_val_t allowlist_v) { + const char* input = EL_CSTR(input_v); + const char* allow = EL_CSTR(allowlist_v); + if (!input) return el_wrap_str(el_strdup("")); + if (!allow) allow = "{}"; + size_t in_len = strlen(input); + + html_buf_t out; + html_buf_init(&out); + + size_t i = 0; + while (i < in_len) { + unsigned char c = (unsigned char)input[i]; + if (c != '<') { + /* Plain text — escape and emit. We pass `&` through verbatim + * to preserve pre-encoded entities (`<`, `&`, `&#x...;`) + * which the browser will decode safely. */ + if (c == '&') html_buf_putc(&out, '&'); + else html_escape_byte(&out, c); + i++; + continue; + } + /* `<` — try to parse a tag. */ + if (i + 1 >= in_len) { + html_buf_puts(&out, "<"); + i++; + continue; + } + /* Comments, doctype, CDATA, processing instructions — drop entirely. */ + if (input[i + 1] == '!') { + if (i + 3 < in_len && input[i + 2] == '-' && input[i + 3] == '-') { + size_t j = i + 4; + while (j + 2 < in_len && !(input[j] == '-' && input[j + 1] == '-' && input[j + 2] == '>')) j++; + if (j + 2 < in_len) i = j + 3; + else i = in_len; + continue; + } + size_t j = i + 2; + while (j < in_len && input[j] != '>') j++; + i = (j < in_len) ? j + 1 : in_len; + continue; + } + if (input[i + 1] == '?') { + size_t j = i + 2; + while (j < in_len && input[j] != '>') j++; + i = (j < in_len) ? j + 1 : in_len; + continue; + } + int is_close = 0; + size_t name_start = i + 1; + if (input[i + 1] == '/') { + is_close = 1; + name_start = i + 2; + } + if (name_start >= in_len) { + html_buf_puts(&out, "<"); + i++; + continue; + } + unsigned char nc = (unsigned char)input[name_start]; + if (!((nc >= 'a' && nc <= 'z') || (nc >= 'A' && nc <= 'Z'))) { + /* `<` followed by non-letter — emit as escaped text. */ + html_buf_puts(&out, "<"); + i++; + continue; + } + size_t name_end = name_start; + while (name_end < in_len) { + unsigned char x = (unsigned char)input[name_end]; + if ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || + (x >= '0' && x <= '9') || x == '-' || x == '_' || x == ':') { + name_end++; + } else { + break; + } + } + const char* tag = input + name_start; + size_t tag_len = name_end - name_start; + /* Find the `>` that closes this tag, respecting quoted attrs. */ + size_t cur = name_end; + int self_close = 0; + while (cur < in_len) { + unsigned char x = (unsigned char)input[cur]; + if (x == '"' || x == '\'') { + unsigned char q = x; + cur++; + while (cur < in_len && (unsigned char)input[cur] != q) cur++; + if (cur < in_len) cur++; /* skip closing quote */ + continue; + } + if (x == '/' && cur + 1 < in_len && input[cur + 1] == '>') { + self_close = 1; + break; + } + if (x == '>') break; + cur++; + } + if (cur >= in_len) { + /* Malformed: unclosed tag at EOF. Drop the rest of the input. */ + i = in_len; + continue; + } + size_t tag_end = self_close ? cur + 2 : cur + 1; /* one past `>` */ + /* Dangerous container — drop the whole subtree. */ + if (!is_close && html_is_dangerous_container(tag, tag_len)) { + if (self_close || html_is_void(tag, tag_len)) { + i = tag_end; + continue; + } + size_t scan = tag_end; + int found_close = 0; + while (scan < in_len) { + if (input[scan] != '<') { scan++; continue; } + if (scan + 1 < in_len && input[scan + 1] == '/') { + size_t cn_start = scan + 2; + size_t cn_end = cn_start; + while (cn_end < in_len) { + unsigned char x = (unsigned char)input[cn_end]; + if ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || + (x >= '0' && x <= '9') || x == '-' || x == '_' || x == ':') { + cn_end++; + } else break; + } + if (cn_end - cn_start == tag_len && + html_iemem(input + cn_start, tag, tag_len)) { + size_t end_close = cn_end; + while (end_close < in_len && input[end_close] != '>') end_close++; + i = (end_close < in_len) ? end_close + 1 : in_len; + found_close = 1; + break; + } + } + scan++; + } + if (!found_close) { + /* No matching close — drop everything from here on. */ + i = in_len; + } + continue; + } + /* Look up the tag in the allowlist. */ + size_t arr_len = 0; + const char* arr = html_allowlist_find(allow, tag, tag_len, &arr_len); + if (!arr) { + /* Tag not allowed. Drop the open/close marker; inner text is + * processed by the outer loop and re-emitted as escaped text. */ + i = tag_end; + continue; + } + if (is_close) { + if (!html_is_void(tag, tag_len)) { + html_buf_putc(&out, '<'); + html_buf_putc(&out, '/'); + for (size_t k = 0; k < tag_len; k++) { + html_buf_putc(&out, (char)html_tolower((unsigned char)tag[k])); + } + html_buf_putc(&out, '>'); + } + i = tag_end; + continue; + } + /* Allowed open tag. Emit ``. */ + html_buf_putc(&out, '<'); + for (size_t k = 0; k < tag_len; k++) { + html_buf_putc(&out, (char)html_tolower((unsigned char)tag[k])); + } + size_t a = name_end; + while (a < cur) { + unsigned char x = (unsigned char)input[a]; + if (x == ' ' || x == '\t' || x == '\n' || x == '\r' || x == '/') { a++; continue; } + size_t an_start = a; + while (a < cur) { + unsigned char y = (unsigned char)input[a]; + if (y == '=' || y == ' ' || y == '\t' || y == '\n' || y == '\r' || y == '/' || y == '>') break; + a++; + } + size_t an_len = a - an_start; + if (an_len == 0) { a++; continue; } + size_t av_start = 0; + size_t av_len = 0; + int has_value = 0; + size_t b = a; + while (b < cur && (input[b] == ' ' || input[b] == '\t' || input[b] == '\n' || input[b] == '\r')) b++; + if (b < cur && input[b] == '=') { + has_value = 1; + b++; + while (b < cur && (input[b] == ' ' || input[b] == '\t' || input[b] == '\n' || input[b] == '\r')) b++; + if (b < cur && (input[b] == '"' || input[b] == '\'')) { + unsigned char q = (unsigned char)input[b]; + b++; + av_start = b; + while (b < cur && (unsigned char)input[b] != q) b++; + av_len = b - av_start; + if (b < cur) b++; + } else { + av_start = b; + while (b < cur) { + unsigned char y = (unsigned char)input[b]; + if (y == ' ' || y == '\t' || y == '\n' || y == '\r' || y == '>') break; + b++; + } + av_len = b - av_start; + } + a = b; + } + if (!html_attr_in_array(arr, arr_len, input + an_start, an_len)) continue; + int is_href = (an_len == 4 && html_iemem(input + an_start, "href", 4)); + int is_src = (an_len == 3 && html_iemem(input + an_start, "src", 3)); + if ((is_href || is_src) && has_value) { + if (!html_url_is_safe(input + av_start, av_len)) continue; + } + html_buf_putc(&out, ' '); + for (size_t k = 0; k < an_len; k++) { + html_buf_putc(&out, (char)html_tolower((unsigned char)input[an_start + k])); + } + if (has_value) { + html_buf_puts(&out, "=\""); + for (size_t k = 0; k < av_len; k++) { + unsigned char y = (unsigned char)input[av_start + k]; + /* Re-escape so the emitted attribute is well-formed + * double-quoted HTML. `&` passes through to preserve + * pre-encoded entities. */ + if (y == '"') html_buf_puts(&out, """); + else if (y == '<') html_buf_puts(&out, "<"); + else if (y == '>') html_buf_puts(&out, ">"); + else html_buf_putc(&out, (char)y); + } + html_buf_putc(&out, '"'); + } + } + html_buf_putc(&out, '>'); + i = tag_end; + } + /* Copy into arena-tracked buffer so the standard runtime memory model + * applies to the returned string. */ + char* result = el_strbuf(out.len); + memcpy(result, out.data, out.len); + result[out.len] = '\0'; + html_buf_free(&out); + return el_wrap_str(result); +} + +/* ── JSON ────────────────────────────────────────────────────────────────── */ + +/* True iff the segment is non-empty and every byte is an ASCII digit. We treat + * such segments as numeric array indices when walking a dot-path; mixed names + * like "0a" remain object-key lookups, so a key named "0" still wins over an + * index when the surrounding container is an object. */ +static int json_path_seg_is_index(const char* seg, size_t n) { + if (n == 0) return 0; + for (size_t i = 0; i < n; i++) { + if (seg[i] < '0' || seg[i] > '9') return 0; + } + return 1; +} + +/* Skip JSON whitespace. */ +static const char* json_skip_ws(const char* p) { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + return p; +} + +/* Descend one segment into the JSON cursor `p`. + * - If `p` points at an array `[...]` and the segment is all digits, + * advance to that element (zero-based). + * - Otherwise treat the segment as an object key and use json_find_key + * scoped to a one-level slice of the current container. + * Returns NULL if the descent fails (segment not found, container mismatch). + * + * `seg` is a pointer into the original path string and `seg_len` is its + * byte length — this avoids an extra alloc per segment. */ +static const char* json_path_descend(const char* p, const char* seg, size_t seg_len) { + if (!p || !seg) return NULL; + p = json_skip_ws(p); + if (*p == '[' && json_path_seg_is_index(seg, seg_len)) { + long idx = 0; + for (size_t i = 0; i < seg_len; i++) idx = idx * 10 + (seg[i] - '0'); + p++; /* step past '[' */ + p = json_skip_ws(p); + long cur = 0; + while (*p && *p != ']') { + if (cur == idx) return p; + const char* end = json_skip_value(p); + if (!end || end == p) return NULL; + p = json_skip_ws(end); + if (*p == ',') { p++; p = json_skip_ws(p); cur++; continue; } + /* No comma after this element — only acceptable at the closing ']', + * which means we ran out of elements. */ + break; + } + return NULL; + } + /* Object lookup. json_find_key walks at depth 1 of whatever container it + * receives, so we slice from `p` onwards. Caller already positioned us at + * the opening '{' (or at whitespace before it). */ + if (*p != '{') return NULL; + /* Build a NUL-terminated copy of the key segment for the lookup. We only + * pay this cost when the segment isn't a numeric index. */ + char stack_key[256]; + char* k = stack_key; + if (seg_len + 1 > sizeof(stack_key)) { + k = malloc(seg_len + 1); + if (!k) return NULL; + } + memcpy(k, seg, seg_len); + k[seg_len] = '\0'; + const char* found = json_find_key(p, k); + if (k != stack_key) free(k); + return found; +} + +/* Read the JSON value at `p` into a freshly-allocated, arena-owned el_val_t. + * - String -> unescaped, wrapped el_val_t string + * - Anything else -> raw JSON slice as a string (matches the historical + * json_get behaviour: numbers/bools/null come back stringified). */ +static el_val_t json_read_value(const char* p) { + p = json_skip_ws(p); + if (*p == '"') { + p++; + size_t cap = strlen(p) + 1; + char* out = el_strbuf(cap); + char* w = out; + while (*p && *p != '"') { + if (*p == '\\' && *(p+1)) { + p++; + switch (*p) { + case '"': *w++ = '"'; break; + case '\\': *w++ = '\\'; break; + case '/': *w++ = '/'; break; + case 'n': *w++ = '\n'; break; + case 'r': *w++ = '\r'; break; + case 't': *w++ = '\t'; break; + default: *w++ = *p; break; + } + } else { + *w++ = *p; + } + p++; + } + *w = '\0'; + return el_wrap_str(out); + } + /* Object/array/number/bool/null — return the raw slice up to the value's + * end. json_skip_value tracks brace/bracket/string state so nested objects + * round-trip cleanly. */ + const char* end = json_skip_value(p); + if (!end) end = p; + size_t n = (size_t)(end - p); + /* Strip trailing whitespace from scalar values so callers don't see + * `123 ` when they parsed a pretty-printed number. */ + while (n > 0 && (p[n-1] == ' ' || p[n-1] == '\t' || p[n-1] == '\n' || p[n-1] == '\r')) { + n--; + } + char* out = el_strbuf(n); + memcpy(out, p, n); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t json_get(el_val_t jsonv, el_val_t keyv) { + const char* json = EL_CSTR(jsonv); + const char* key = EL_CSTR(keyv); + if (!json || !key) return el_wrap_str(el_strdup("")); + + /* Fast path: key contains no '.' — keep the historical single-segment + * substring search so existing callers retain their O(strlen) cost + * profile. The dot-path walker is only paid for when needed. */ + if (!strchr(key, '.')) { + size_t klen = strlen(key); + char stack_pat[512]; + char* pattern; + if (klen + 5 <= sizeof(stack_pat)) { + pattern = stack_pat; + } else { + pattern = malloc(klen + 5); + if (!pattern) return el_wrap_str(el_strdup("")); + } + snprintf(pattern, klen + 5, "\"%s\":", key); + const char* p = strstr(json, pattern); + if (pattern != stack_pat) free(pattern); + if (!p) return el_wrap_str(el_strdup("")); + p += strlen(key) + 3; /* skip "key": */ + return json_read_value(p); + } + + /* Dot-path traversal. Walk segments left to right; at each step, descend + * into the current container by either array index (all-digit segment on + * an array cursor) or object key. */ + const char* cursor = json_skip_ws(json); + const char* seg_start = key; + const char* k = key; + while (1) { + if (*k == '.' || *k == '\0') { + size_t seg_len = (size_t)(k - seg_start); + cursor = json_path_descend(cursor, seg_start, seg_len); + if (!cursor) return el_wrap_str(el_strdup("")); + if (*k == '\0') break; + k++; + seg_start = k; + continue; + } + k++; + } + return json_read_value(cursor); +} + +/* ── Float bit-cast helpers ──────────────────────────────────────────────── */ +/* `el_to_float` and `el_from_float` are exposed in el_runtime.h as static + * inlines so generated programs (which #include the header) can call them + * for Float literals. No definitions are needed here. */ + +/* ── JSON parser (recursive descent) ─────────────────────────────────────── */ +/* + * Parsed JSON representation: + * - object -> ElMap (keys & values are el_val_t) + * - array -> ElList + * - string -> EL_STR-wrapped char* (allocated) + * - number -> int (el_val_t) if integer, otherwise el_from_float(double) + * - true -> 1 + * - false -> 0 + * - null -> EL_NULL (0) + * + * Note: there is no runtime type tag — parsed numbers cannot be + * distinguished from booleans by the runtime alone. The codegen tracks + * types separately. This matches the rest of el_val_t's type-erased model. + */ + +/* JsonParser struct is forward-declared near the HTTP/Engram section. */ + +static void jp_skip_ws(JsonParser* jp) { + while (jp->p < jp->end) { + char c = *jp->p; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') jp->p++; + else break; + } +} + +static el_val_t jp_parse_value(JsonParser* jp); + +/* Parse a JSON string literal (the opening " has NOT yet been consumed). */ +static char* jp_parse_string_raw(JsonParser* jp) { + if (jp->p >= jp->end || *jp->p != '"') { jp->err = 1; return el_strdup(""); } + jp->p++; + size_t cap = 32, len = 0; + char* out = malloc(cap); + if (!out) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + while (jp->p < jp->end && *jp->p != '"') { + char c = *jp->p++; + if (c == '\\' && jp->p < jp->end) { + char esc = *jp->p++; + switch (esc) { + case '"': c = '"'; break; + case '\\': c = '\\'; break; + case '/': c = '/'; break; + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'u': { + /* Skip 4 hex digits; emit '?' as a placeholder */ + for (int i = 0; i < 4 && jp->p < jp->end; i++) jp->p++; + c = '?'; + break; + } + default: c = esc; break; + } + } + if (len + 1 >= cap) { + cap *= 2; + out = realloc(out, cap); + if (!out) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + } + out[len++] = c; + } + if (jp->p < jp->end && *jp->p == '"') jp->p++; + else jp->err = 1; + out[len] = '\0'; + return out; +} + +static el_val_t jp_parse_number(JsonParser* jp) { + const char* start = jp->p; + int is_float = 0; + if (jp->p < jp->end && (*jp->p == '-' || *jp->p == '+')) jp->p++; + while (jp->p < jp->end && isdigit((unsigned char)*jp->p)) jp->p++; + if (jp->p < jp->end && *jp->p == '.') { + is_float = 1; jp->p++; + while (jp->p < jp->end && isdigit((unsigned char)*jp->p)) jp->p++; + } + if (jp->p < jp->end && (*jp->p == 'e' || *jp->p == 'E')) { + is_float = 1; jp->p++; + if (jp->p < jp->end && (*jp->p == '+' || *jp->p == '-')) jp->p++; + while (jp->p < jp->end && isdigit((unsigned char)*jp->p)) jp->p++; + } + size_t n = (size_t)(jp->p - start); + char buf[64]; + if (n >= sizeof(buf)) n = sizeof(buf) - 1; + memcpy(buf, start, n); + buf[n] = '\0'; + if (is_float) return el_from_float(strtod(buf, NULL)); + return (el_val_t)strtoll(buf, NULL, 10); +} + +static el_val_t jp_parse_array(JsonParser* jp) { + if (jp->p < jp->end && *jp->p == '[') jp->p++; + el_val_t lst = el_list_empty(); + jp_skip_ws(jp); + if (jp->p < jp->end && *jp->p == ']') { jp->p++; return lst; } + while (jp->p < jp->end) { + jp_skip_ws(jp); + el_val_t v = jp_parse_value(jp); + lst = el_list_append(lst, v); + jp_skip_ws(jp); + if (jp->p < jp->end && *jp->p == ',') { jp->p++; continue; } + if (jp->p < jp->end && *jp->p == ']') { jp->p++; break; } + jp->err = 1; + break; + } + return lst; +} + +static el_val_t jp_parse_object(JsonParser* jp) { + if (jp->p < jp->end && *jp->p == '{') jp->p++; + el_val_t m = el_map_new(0); + jp_skip_ws(jp); + if (jp->p < jp->end && *jp->p == '}') { jp->p++; return m; } + while (jp->p < jp->end) { + jp_skip_ws(jp); + char* key = jp_parse_string_raw(jp); + jp_skip_ws(jp); + if (jp->p < jp->end && *jp->p == ':') jp->p++; + else { jp->err = 1; free(key); break; } + jp_skip_ws(jp); + el_val_t v = jp_parse_value(jp); + m = el_map_set(m, EL_STR(key), v); + jp_skip_ws(jp); + if (jp->p < jp->end && *jp->p == ',') { jp->p++; continue; } + if (jp->p < jp->end && *jp->p == '}') { jp->p++; break; } + jp->err = 1; + break; + } + return m; +} + +static el_val_t jp_parse_value(JsonParser* jp) { + jp_skip_ws(jp); + if (jp->p >= jp->end) { jp->err = 1; return EL_NULL; } + char c = *jp->p; + if (c == '"') return el_wrap_str(jp_parse_string_raw(jp)); + if (c == '{') return jp_parse_object(jp); + if (c == '[') return jp_parse_array(jp); + if (c == '-' || isdigit((unsigned char)c)) return jp_parse_number(jp); + if (c == 't' && jp->p + 4 <= jp->end && strncmp(jp->p, "true", 4) == 0) { jp->p += 4; return 1; } + if (c == 'f' && jp->p + 5 <= jp->end && strncmp(jp->p, "false", 5) == 0) { jp->p += 5; return 0; } + if (c == 'n' && jp->p + 4 <= jp->end && strncmp(jp->p, "null", 4) == 0) { jp->p += 4; return EL_NULL; } + jp->err = 1; + return EL_NULL; +} + +el_val_t json_parse(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return EL_NULL; + JsonParser jp = { .p = s, .end = s + strlen(s), .err = 0 }; + el_val_t v = jp_parse_value(&jp); + if (jp.err) return EL_NULL; + return v; +} + +/* ── JSON stringify ──────────────────────────────────────────────────────── */ +/* + * Stringify policy: el_val_t is type-erased, so we cannot perfectly + * round-trip arbitrary values. We use these heuristics: + * - If value is an ElList pointer (in the heap range), serialize as array. + * - If value is an ElMap pointer, serialize as object. + * - If value looks like a printable string pointer, serialize as string. + * - Otherwise serialize as integer. + * This is best-effort. Programs that need exact control should build the + * string directly. A pointer test is the cheapest way to disambiguate + * from small integers without a separate type tag. + */ + +/* JsonBuf struct is forward-declared near the HTTP section so HTTP helpers + * can use it. Its definition appears there. */ + +static void jb_init(JsonBuf* b) { + b->cap = 64; b->len = 0; + b->buf = malloc(b->cap); + if (!b->buf) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + b->buf[0] = '\0'; +} + +static void jb_reserve(JsonBuf* b, size_t add) { + if (b->len + add + 1 > b->cap) { + while (b->len + add + 1 > b->cap) b->cap *= 2; + b->buf = realloc(b->buf, b->cap); + if (!b->buf) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + } +} + +static void jb_putc(JsonBuf* b, char c) { + jb_reserve(b, 1); + b->buf[b->len++] = c; + b->buf[b->len] = '\0'; +} + +static void jb_puts(JsonBuf* b, const char* s) { + size_t n = strlen(s); + jb_reserve(b, n); + memcpy(b->buf + b->len, s, n); + b->len += n; + b->buf[b->len] = '\0'; +} + +static void jb_emit_escaped(JsonBuf* b, const char* s) { + jb_putc(b, '"'); + for (; *s; s++) { + unsigned char c = (unsigned char)*s; + switch (c) { + case '"': jb_puts(b, "\\\""); break; + case '\\': jb_puts(b, "\\\\"); break; + case '\b': jb_puts(b, "\\b"); break; + case '\f': jb_puts(b, "\\f"); break; + case '\n': jb_puts(b, "\\n"); break; + case '\r': jb_puts(b, "\\r"); break; + case '\t': jb_puts(b, "\\t"); break; + default: + if (c < 0x20) { + char tmp[8]; + snprintf(tmp, sizeof(tmp), "\\u%04x", c); + jb_puts(b, tmp); + } else { + jb_putc(b, (char)c); + } + break; + } + } + jb_putc(b, '"'); +} + +/* Heuristic: is this el_val_t likely a pointer to an ElList? + * We can't fully verify, but pointers are large addresses, integers small. + * Treat values whose magnitude exceeds 2^32 as potential pointers and + * sniff by reading the header conservatively. + * + * Simpler heuristic: if the value reads as a printable string, treat as + * string; otherwise as integer. Lists/Maps are encoded as struct pointers, + * which have leading binary bytes — so they won't look like strings. */ + +static int looks_like_string(el_val_t v) { + if (v == 0) return 0; + /* Treat plausible heap addresses as candidates. + * Threshold: 4 GiB (0x100000000). On 64-bit systems heap addresses from + * malloc/mmap start well above 4 GiB (ASLR pushes them to ~0x7f...). + * El integer values (counters, unix timestamps up to ~2106) all fit below + * 0x100000000 (4294967296). The old threshold of 1,000,000 caused unix + * timestamps (~1.7e9) to be misidentified as string pointers — a segfault + * risk in json_stringify and jb_emit_value. */ + uintptr_t p = (uintptr_t)v; + if (p < 0x100000000ULL) return 0; /* integers, timestamps, counters */ + if (p < 0x1000) return 0; + /* Sniff first bytes for printable */ + const unsigned char* s = (const unsigned char*)p; + for (int i = 0; i < 16; i++) { + unsigned char c = s[i]; + if (c == '\0') return 1; /* terminated string (empty string is still a valid string) */ + /* Reject C0 control chars (non-whitespace), allow UTF-8 high bytes. + * 0x09-0x0d = tab/newline/cr/vt/ff (whitespace, OK) + * 0x20-0x7e = printable ASCII (OK) + * 0x7f = DEL (reject) + * 0x80-0xff = UTF-8 continuation/lead bytes (OK for multi-byte chars) */ + if (c < 0x09 || (c > 0x0d && c < 0x20) || c == 0x7f) return 0; + } + return 1; /* 16+ printable bytes — call it a string */ +} + +static void jb_emit_value(JsonBuf* b, el_val_t v); + +static void jb_emit_int(JsonBuf* b, int64_t n) { + char tmp[32]; + snprintf(tmp, sizeof(tmp), "%lld", (long long)n); + jb_puts(b, tmp); +} + +static void jb_emit_value(JsonBuf* b, el_val_t v) { + if (v == EL_NULL) { jb_puts(b, "null"); return; } + if (looks_like_string(v)) { + jb_emit_escaped(b, EL_CSTR(v)); + return; + } + jb_emit_int(b, (int64_t)v); +} + +el_val_t json_stringify(el_val_t v) { + JsonBuf b; jb_init(&b); + jb_emit_value(&b, v); + return el_wrap_str(b.buf); +} + +/* ── JSON substring accessors ────────────────────────────────────────────── */ +/* + * These walk the raw JSON string looking for "key": at the top level (depth 1) + * of an object. They handle escaped quotes, nested objects/arrays, and + * whitespace around the colon. + */ + +/* Find "key": at object-depth == 1 inside the JSON object string `s`. + * Returns pointer to the first byte of the value, or NULL. */ +static const char* json_find_key(const char* s, const char* key) { + if (!s || !key) return NULL; + size_t klen = strlen(key); + int depth = 0; + int in_str = 0; + int escape = 0; + const char* p = s; + while (*p) { + char c = *p; + if (in_str) { + if (escape) { escape = 0; } + else if (c == '\\') { escape = 1; } + else if (c == '"') { + /* End of string. If we're at depth 1, check if this was a key. */ + p++; + if (depth == 1) { + /* The string just ended at p-1. Check if it matches key + * and is followed by a colon. We need to backtrack to find + * the start of this string and compare. */ + } + in_str = 0; + continue; + } + p++; + continue; + } + if (c == '"') { + /* Start of a string literal */ + const char* str_start = p + 1; + const char* q = str_start; + int e = 0; + while (*q) { + if (e) { e = 0; q++; continue; } + if (*q == '\\') { e = 1; q++; continue; } + if (*q == '"') break; + q++; + } + size_t slen = (size_t)(q - str_start); + const char* after = (*q == '"') ? q + 1 : q; + /* If at depth 1 and matches key and followed by ':' -> got it */ + if (depth == 1 && slen == klen && strncmp(str_start, key, klen) == 0) { + const char* r = after; + while (*r == ' ' || *r == '\t' || *r == '\n' || *r == '\r') r++; + if (*r == ':') { + r++; + while (*r == ' ' || *r == '\t' || *r == '\n' || *r == '\r') r++; + return r; + } + } + p = after; + continue; + } + if (c == '{' || c == '[') depth++; + else if (c == '}' || c == ']') depth--; + p++; + } + return NULL; +} + +/* Skip a JSON value starting at p; return pointer past the value end. */ +static const char* json_skip_value(const char* p) { + if (!p || !*p) return p; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p == '"') { + p++; + int e = 0; + while (*p) { + if (e) { e = 0; p++; continue; } + if (*p == '\\') { e = 1; p++; continue; } + if (*p == '"') { p++; break; } + p++; + } + return p; + } + if (*p == '{' || *p == '[') { + char open = *p; + char close = (open == '{') ? '}' : ']'; + int depth = 0; + int in_str = 0; + int e = 0; + while (*p) { + char c = *p; + if (in_str) { + if (e) { e = 0; } + else if (c == '\\') { e = 1; } + else if (c == '"') in_str = 0; + p++; + continue; + } + if (c == '"') { in_str = 1; p++; continue; } + if (c == open) depth++; + else if (c == close) { depth--; p++; if (depth == 0) return p; continue; } + p++; + } + return p; + } + /* scalar: number, true/false/null */ + while (*p && *p != ',' && *p != '}' && *p != ']' && + *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r') p++; + return p; +} + +el_val_t json_get_string(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + if (!p || *p != '"') return el_wrap_str(el_strdup("")); + p++; + JsonParser jp = { .p = p - 1, .end = json + (json ? strlen(json) : 0), .err = 0 }; + char* parsed = jp_parse_string_raw(&jp); + if (jp.err) { free(parsed); return el_wrap_str(el_strdup("")); } + return el_wrap_str(parsed); +} + +el_val_t json_get_int(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + if (!p) return 0; + if (*p == '"' || *p == '{' || *p == '[') return 0; + return (el_val_t)strtoll(p, NULL, 10); +} + +el_val_t json_get_float(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + if (!p) return 0; + if (*p == '"' || *p == '{' || *p == '[') return 0; + return el_from_float(strtod(p, NULL)); +} + +el_val_t json_get_bool(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + if (!p) return 0; + if (strncmp(p, "true", 4) == 0) return 1; + return 0; +} + +el_val_t json_get_raw(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + /* Clear fs_read binary-length hint — result is a fresh null-terminated + * string, not the raw file bytes, so Content-Length must use strlen. */ + _tl_fs_read_len = 0; + if (!p) return el_wrap_str(el_strdup("")); + const char* end = json_skip_value(p); + size_t n = (size_t)(end - p); + char* out = el_strbuf(n); + memcpy(out, p, n); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t json_set(el_val_t json_str, el_val_t key, el_val_t value) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + /* raw_val is the JSON value as-is (already encoded by the caller). + * If it looks like a plain (non-JSON) string, wrap it as a JSON string. + * Convention: callers pass pre-encoded values like "\"bob\"" for strings, + * "42" for numbers, "true"/"false" for booleans. */ + const char* raw_val = EL_CSTR(value); + if (!k) k = ""; + if (!raw_val) raw_val = "null"; + if (!json || !*json) { + /* Build a fresh object */ + JsonBuf b; jb_init(&b); + jb_putc(&b, '{'); + jb_emit_escaped(&b, k); + jb_putc(&b, ':'); + jb_puts(&b, raw_val); + jb_putc(&b, '}'); + return el_wrap_str(b.buf); + } + const char* existing = json_find_key(json, k); + JsonBuf b; jb_init(&b); + if (existing) { + const char* end = json_skip_value(existing); + /* Copy [json .. existing) */ + size_t prefix = (size_t)(existing - json); + jb_reserve(&b, prefix); + memcpy(b.buf + b.len, json, prefix); + b.len += prefix; + b.buf[b.len] = '\0'; + jb_puts(&b, raw_val); + jb_puts(&b, end); + return el_wrap_str(b.buf); + } + /* Insert before closing '}'. Find last '}' */ + size_t jl = strlen(json); + if (jl == 0) { free(b.buf); return el_wrap_str(el_strdup("{}")); } + /* Find last '}' from the end */ + ssize_t close_idx = -1; + for (ssize_t i = (ssize_t)jl - 1; i >= 0; i--) { + if (json[i] == '}') { close_idx = i; break; } + } + if (close_idx < 0) { + free(b.buf); + return el_wrap_str(el_strdup(json)); + } + /* Determine if object is empty: scan between last '{' and '}' for non-ws */ + int empty = 1; + for (ssize_t i = close_idx - 1; i >= 0; i--) { + char c = json[i]; + if (c == '{') break; + if (c != ' ' && c != '\t' && c != '\n' && c != '\r') { empty = 0; break; } + } + /* Copy json[0..close_idx) */ + jb_reserve(&b, (size_t)close_idx); + memcpy(b.buf + b.len, json, (size_t)close_idx); + b.len += (size_t)close_idx; + b.buf[b.len] = '\0'; + if (!empty) jb_putc(&b, ','); + jb_emit_escaped(&b, k); + jb_putc(&b, ':'); + jb_puts(&b, raw_val); + /* Append from close_idx onward */ + jb_puts(&b, json + close_idx); + return el_wrap_str(b.buf); +} + +el_val_t json_array_len(el_val_t json_str) { + const char* s = EL_CSTR(json_str); + if (!s) return 0; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s != '[') return 0; + s++; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ']') return 0; + int64_t count = 0; + while (*s) { + const char* end = json_skip_value(s); + if (end == s) break; + count++; + s = end; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ',') { s++; continue; } + if (*s == ']' || *s == '\0') break; + } + return (el_val_t)count; +} + +/* json_array_get — return the i-th element of a JSON array as a JSON + * fragment string. Nested objects and arrays are returned verbatim + * (json_skip_value tracks brace/bracket depth so nested structures are + * preserved intact). Out-of-range index → "". */ +el_val_t json_array_get(el_val_t json_str, el_val_t index) { + const char* s = EL_CSTR(json_str); + int64_t idx = (int64_t)index; + if (!s || idx < 0) return el_wrap_str(el_strdup("")); + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s != '[') return el_wrap_str(el_strdup("")); + s++; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ']') return el_wrap_str(el_strdup("")); + int64_t i = 0; + while (*s) { + const char* start = s; + const char* end = json_skip_value(s); + if (end == s) break; + if (i == idx) { + size_t n = (size_t)(end - start); + char* out = el_strbuf(n); + memcpy(out, start, n); + out[n] = '\0'; + return el_wrap_str(out); + } + i++; + s = end; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ',') { s++; while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; continue; } + if (*s == ']' || *s == '\0') break; + } + return el_wrap_str(el_strdup("")); +} + +/* json_array_get_string — same as json_array_get, but assume the element + * is a JSON string and return the unquoted/unescaped value. Non-string + * elements yield "". */ +el_val_t json_array_get_string(el_val_t json_str, el_val_t index) { + el_val_t raw = json_array_get(json_str, index); + const char* s = EL_CSTR(raw); + if (!s || *s != '"') return el_wrap_str(el_strdup("")); + JsonParser jp = { + .p = s, + .end = s + strlen(s), + .err = 0, + }; + char* parsed = jp_parse_string_raw(&jp); + if (jp.err) { + free(parsed); + return el_wrap_str(el_strdup("")); + } + return el_wrap_str(parsed); +} + +/* json_escape_string — escape a string value for embedding in JSON. + * Returns the escaped content WITHOUT surrounding quotes. + * "say \"hello\"" -> "say \\\"hello\\\"" */ +el_val_t json_escape_string(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + /* Worst case: every char needs a 2-char escape. */ + char* out = malloc(n * 2 + 1); + if (!out) return el_wrap_str(el_strdup("")); + size_t j = 0; + for (size_t i = 0; i < n; i++) { + unsigned char c = (unsigned char)s[i]; + if (c == '"') { out[j++] = '\\'; out[j++] = '"'; } + else if (c == '\\') { out[j++] = '\\'; out[j++] = '\\'; } + else if (c == '\n') { out[j++] = '\\'; out[j++] = 'n'; } + else if (c == '\r') { out[j++] = '\\'; out[j++] = 'r'; } + else if (c == '\t') { out[j++] = '\\'; out[j++] = 't'; } + else { out[j++] = (char)c; } + } + out[j] = '\0'; + el_val_t result = el_wrap_str(el_strdup(out)); + free(out); + return result; +} + +/* json_build_object — build a JSON object from a flat key-value list. + * kvs is [key0, val0, key1, val1, ...]. Values are raw JSON (pass + * strings as "\"value\"" or use json_escape_string). */ +el_val_t json_build_object(el_val_t kvs) { + el_val_t list = kvs; + int64_t n = el_list_len(list); + JsonBuf b; jb_init(&b); + jb_putc(&b, '{'); + int first = 1; + for (int64_t i = 0; i + 1 < n; i += 2) { + el_val_t k = el_list_get(list, (el_val_t)i); + el_val_t v = el_list_get(list, (el_val_t)(i + 1)); + const char* ks = EL_CSTR(k); + const char* vs = EL_CSTR(v); + if (!ks || !vs) continue; + if (!first) jb_putc(&b, ','); + first = 0; + jb_putc(&b, '"'); + jb_puts(&b, ks); + jb_puts(&b, "\":\""); + /* escape the value string */ + size_t vn = strlen(vs); + for (size_t j = 0; j < vn; j++) { + unsigned char c = (unsigned char)vs[j]; + if (c == '"') { jb_putc(&b, '\\'); jb_putc(&b, '"'); } + else if (c == '\\') { jb_putc(&b, '\\'); jb_putc(&b, '\\'); } + else if (c == '\n') { jb_putc(&b, '\\'); jb_putc(&b, 'n'); } + else if (c == '\r') { jb_putc(&b, '\\'); jb_putc(&b, 'r'); } + else if (c == '\t') { jb_putc(&b, '\\'); jb_putc(&b, 't'); } + else { jb_putc(&b, (char)c); } + } + jb_putc(&b, '"'); + } + jb_putc(&b, '}'); + return el_wrap_str(b.buf); +} + +/* json_build_array — build a JSON array from a list of raw JSON values. + * items is ["\"alpha\"", "\"beta\"", "42", "true", ...]. */ +el_val_t json_build_array(el_val_t items) { + el_val_t list = items; + int64_t n = el_list_len(list); + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + for (int64_t i = 0; i < n; i++) { + el_val_t v = el_list_get(list, (el_val_t)i); + const char* vs = EL_CSTR(v); + if (!vs) continue; + if (i > 0) jb_putc(&b, ','); + jb_puts(&b, vs); + } + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +/* ── Time ────────────────────────────────────────────────────────────────── */ + +el_val_t time_now(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + int64_t ms = (int64_t)tv.tv_sec * 1000LL + (int64_t)tv.tv_usec / 1000LL; + return (el_val_t)ms; +} + +el_val_t time_now_utc(void) { + return time_now(); +} + +el_val_t time_format(el_val_t ts, el_val_t fmt) { + int64_t ms = (int64_t)ts; + time_t s = (time_t)(ms / 1000); + int msec = (int)(ms % 1000); + if (msec < 0) { msec += 1000; s -= 1; } + struct tm tm; + gmtime_r(&s, &tm); + const char* fmt_str = EL_CSTR(fmt); + if (!fmt_str || *fmt_str == '\0' || strcmp(fmt_str, "ISO") == 0) { + char buf[64]; + snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, msec); + return el_wrap_str(el_strdup(buf)); + } + char buf[256]; + if (strftime(buf, sizeof(buf), fmt_str, &tm) == 0) buf[0] = '\0'; + return el_wrap_str(el_strdup(buf)); +} + +el_val_t time_to_parts(el_val_t ts) { + int64_t ms = (int64_t)ts; + time_t s = (time_t)(ms / 1000); + int msec = (int)(ms % 1000); + if (msec < 0) { msec += 1000; s -= 1; } + struct tm tm; + gmtime_r(&s, &tm); + /* Return a JSON string so callers can use json_get to extract fields. */ + char buf[256]; + snprintf(buf, sizeof(buf), + "{\"year\":%d,\"month\":%d,\"day\":%d,\"hour\":%d,\"minute\":%d,\"second\":%d,\"ms\":%d}", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, msec); + return el_wrap_str(el_strdup(buf)); +} + +el_val_t time_from_parts(el_val_t secs, el_val_t ns, el_val_t tz) { + (void)tz; + int64_t s = (int64_t)secs; + int64_t n = (int64_t)ns; + int64_t ms = s * 1000LL + n / 1000000LL; + return (el_val_t)ms; +} + +el_val_t time_add(el_val_t ts, el_val_t n, el_val_t unit) { + const char* u = EL_CSTR(unit); + int64_t cur = (int64_t)ts; + int64_t d = (int64_t)n; + int64_t add_ms = d; + if (u) { + if (strcmp(u, "ms") == 0) add_ms = d; + else if (strcmp(u, "sec") == 0) add_ms = d * 1000LL; + else if (strcmp(u, "min") == 0) add_ms = d * 60000LL; + else if (strcmp(u, "hour") == 0) add_ms = d * 3600000LL; + else if (strcmp(u, "day") == 0) add_ms = d * 86400000LL; + } + return (el_val_t)(cur + add_ms); +} + +el_val_t time_diff(el_val_t ts1, el_val_t ts2, el_val_t unit) { + int64_t d = (int64_t)ts2 - (int64_t)ts1; + const char* u = EL_CSTR(unit); + if (!u || strcmp(u, "ms") == 0) return (el_val_t)d; + if (strcmp(u, "sec") == 0) return (el_val_t)(d / 1000LL); + if (strcmp(u, "min") == 0) return (el_val_t)(d / 60000LL); + if (strcmp(u, "hour") == 0) return (el_val_t)(d / 3600000LL); + if (strcmp(u, "day") == 0) return (el_val_t)(d / 86400000LL); + return (el_val_t)d; +} + +/* Block the calling thread for `secs` seconds. Negative values are clamped + * to 0. Used by El programs that poll external resources (e.g. RunPod + * /status, Engram readiness probes). */ +el_val_t sleep_secs(el_val_t secs) { + int64_t s = (int64_t)secs; + if (s < 0) s = 0; + struct timespec ts; + ts.tv_sec = (time_t)s; + ts.tv_nsec = 0; + nanosleep(&ts, NULL); + return 0; +} + +el_val_t sleep_ms(el_val_t ms) { + int64_t m = (int64_t)ms; + if (m < 0) m = 0; + struct timespec ts; + ts.tv_sec = (time_t)(m / 1000LL); + ts.tv_nsec = (long)((m % 1000LL) * 1000000LL); + nanosleep(&ts, NULL); + return 0; +} + +/* ── Instant + Duration: first-class temporal types ────────────────────────── + * El's substrate (Neuron) is a temporal cognition system. Memory salience + * decay, the six-tier pacemaker, TTL caches, and supersession are all + * temporal. Treating time as a raw Int (now() returning ms-since-epoch and + * arithmetic done with mixed unit literals) lets bugs through the type + * system: `(now - cached_at) < 60` cannot tell ms from sec, and `sleep(30)` + * is ambiguous. This block introduces two dedicated representations. + * + * Representation: + * Instant — int64 nanoseconds since the Unix epoch + * Duration — int64 nanoseconds (signed; negative durations are legal, + * e.g. when a deadline has passed) + * + * Both share the el_val_t (int64) slot the rest of the runtime uses, so no + * boxing / arena allocation is needed. Type discipline is enforced at the + * codegen layer: `let x: Duration = ...` registers `x` in __duration_names, + * and BinOp dispatches through typed wrappers (el_duration_add, etc.) that + * make intent explicit in the generated C. Mismatched ops (Instant+Instant, + * Duration+Int) are surfaced via #error directives at codegen time so the + * downstream cc step fails with a clear El-source-level message. + * + * Nanosecond precision matches POSIX clock_gettime / nanosleep granularity. + * 2^63 nanos covers ~292 years from epoch — comfortably past 2200, plenty + * for a memory-system runtime that never schedules outside a human lifespan. + */ + +/* now() — current Instant. Wraps clock_gettime(CLOCK_REALTIME) for nanosecond + * precision. Falls back to gettimeofday on systems where clock_gettime is + * unavailable (defensive — every supported platform has it). */ +el_val_t el_now_instant(void) { + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts) == 0) { + int64_t ns = (int64_t)ts.tv_sec * 1000000000LL + (int64_t)ts.tv_nsec; + return (el_val_t)ns; + } + struct timeval tv; + gettimeofday(&tv, NULL); + int64_t ns = (int64_t)tv.tv_sec * 1000000000LL + + (int64_t)tv.tv_usec * 1000LL; + return (el_val_t)ns; +} + +el_val_t now(void) { + return el_now_instant(); +} + +/* now_ns — return current Unix time as nanoseconds (Int). + * Thin wrapper over el_now_instant for use in test timing. */ +el_val_t now_ns(void) { + return el_now_instant(); +} + +/* unix_seconds(n) — Instant from a Unix-epoch second count. + * unix_millis(n) — Instant from a Unix-epoch millisecond count. */ +el_val_t unix_seconds(el_val_t n) { + int64_t s = (int64_t)n; + return (el_val_t)(s * 1000000000LL); +} + +el_val_t unix_millis(el_val_t n) { + int64_t m = (int64_t)n; + return (el_val_t)(m * 1000000LL); +} + +/* instant_from_iso8601 — parse a strict subset: + * YYYY-MM-DDTHH:MM:SS[.fff]Z + * Returns 0 (the Unix-epoch sentinel) on parse failure. Callers that need to + * distinguish epoch-zero from a parse error should use a wider sentinel + * representation; the current zero-on-failure choice matches existing El + * runtime conventions for parse builtins (str_to_int, parse_int). */ +el_val_t instant_from_iso8601(el_val_t s) { + const char* str = EL_CSTR(s); + if (!str) return (el_val_t)0; + int Y, M, D, h, m, sec, frac = 0; + int n = sscanf(str, "%d-%d-%dT%d:%d:%d.%3d", &Y, &M, &D, &h, &m, &sec, &frac); + if (n < 6) { + n = sscanf(str, "%d-%d-%dT%d:%d:%dZ", &Y, &M, &D, &h, &m, &sec); + if (n < 6) return (el_val_t)0; + } + struct tm tm; + memset(&tm, 0, sizeof(tm)); + tm.tm_year = Y - 1900; + tm.tm_mon = M - 1; + tm.tm_mday = D; + tm.tm_hour = h; + tm.tm_min = m; + tm.tm_sec = sec; + /* timegm — UTC. POSIX-Y but available on macOS and glibc. */ + time_t t = timegm(&tm); + if (t == (time_t)-1) return (el_val_t)0; + int64_t ns = (int64_t)t * 1000000000LL + (int64_t)frac * 1000000LL; + return (el_val_t)ns; +} + +/* Duration constructors. The El-side postfix literals (30.seconds, 1.hour) + * are lowered by the codegen directly into a literal int64 of nanoseconds — + * these constructors are for runtime values where the count is dynamic. */ +el_val_t el_duration_from_nanos(el_val_t ns) { + return (el_val_t)(int64_t)ns; +} + +el_val_t duration_seconds(el_val_t n) { + int64_t s = (int64_t)n; + return (el_val_t)(s * 1000000000LL); +} + +el_val_t duration_millis(el_val_t n) { + int64_t m = (int64_t)n; + return (el_val_t)(m * 1000000LL); +} + +el_val_t duration_nanos(el_val_t n) { + return (el_val_t)(int64_t)n; +} + +/* Arithmetic — typed wrappers. At the C level these are no-op casts, but + * the codegen routes Instant/Duration BinOps through them so the generated + * C says `el_instant_add_dur(start, dur)` rather than `start + dur`. The + * intent is explicit, the operand order is documented, and a future change + * to the underlying representation (saturating arithmetic, overflow guards) + * has a single chokepoint. */ +el_val_t el_instant_add_dur(el_val_t inst, el_val_t dur) { + return (el_val_t)((int64_t)inst + (int64_t)dur); +} + +el_val_t el_instant_sub_dur(el_val_t inst, el_val_t dur) { + return (el_val_t)((int64_t)inst - (int64_t)dur); +} + +el_val_t el_instant_diff(el_val_t a, el_val_t b) { + /* a - b — yields a Duration (negative if b is later than a). */ + return (el_val_t)((int64_t)a - (int64_t)b); +} + +el_val_t el_duration_add(el_val_t a, el_val_t b) { + return (el_val_t)((int64_t)a + (int64_t)b); +} + +el_val_t el_duration_sub(el_val_t a, el_val_t b) { + return (el_val_t)((int64_t)a - (int64_t)b); +} + +el_val_t el_duration_scale(el_val_t dur, el_val_t scalar) { + return (el_val_t)((int64_t)dur * (int64_t)scalar); +} + +el_val_t el_duration_div(el_val_t dur, el_val_t scalar) { + int64_t s = (int64_t)scalar; + if (s == 0) return (el_val_t)0; + return (el_val_t)((int64_t)dur / s); +} + +/* Comparisons. Return 1/0 in el_val_t convention. */ +el_val_t el_instant_lt(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a < (int64_t)b ? 1 : 0); } +el_val_t el_instant_le(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a <= (int64_t)b ? 1 : 0); } +el_val_t el_instant_gt(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a > (int64_t)b ? 1 : 0); } +el_val_t el_instant_ge(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a >= (int64_t)b ? 1 : 0); } +el_val_t el_instant_eq(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a == (int64_t)b ? 1 : 0); } +el_val_t el_instant_ne(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a != (int64_t)b ? 1 : 0); } +el_val_t el_duration_lt(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a < (int64_t)b ? 1 : 0); } +el_val_t el_duration_le(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a <= (int64_t)b ? 1 : 0); } +el_val_t el_duration_gt(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a > (int64_t)b ? 1 : 0); } +el_val_t el_duration_ge(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a >= (int64_t)b ? 1 : 0); } +el_val_t el_duration_eq(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a == (int64_t)b ? 1 : 0); } +el_val_t el_duration_ne(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a != (int64_t)b ? 1 : 0); } + +/* Conversions. */ +el_val_t instant_to_unix_seconds(el_val_t i) { + return (el_val_t)((int64_t)i / 1000000000LL); +} + +el_val_t instant_to_unix_millis(el_val_t i) { + return (el_val_t)((int64_t)i / 1000000LL); +} + +el_val_t instant_to_iso8601(el_val_t i) { + int64_t ns = (int64_t)i; + time_t s = (time_t)(ns / 1000000000LL); + int msec = (int)((ns / 1000000LL) % 1000LL); + if (msec < 0) { msec += 1000; s -= 1; } + struct tm tm; + gmtime_r(&s, &tm); + char buf[64]; + snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, msec); + return el_wrap_str(el_strdup(buf)); +} + +el_val_t duration_to_seconds(el_val_t d) { + return (el_val_t)((int64_t)d / 1000000000LL); +} + +el_val_t duration_to_millis(el_val_t d) { + return (el_val_t)((int64_t)d / 1000000LL); +} + +el_val_t duration_to_nanos(el_val_t d) { + return (el_val_t)(int64_t)d; +} + +/* sleep(Duration) — Phase 1 replacement for ambiguous sleep(Int). The runtime + * still exposes sleep_secs/sleep_ms for legacy call sites; codegen lowers + * sleep(Duration) to el_sleep_duration(d). Negative durations clamp to 0 so a + * stale deadline doesn't block forever. */ +el_val_t el_sleep_duration(el_val_t dur) { + int64_t ns = (int64_t)dur; + if (ns < 0) ns = 0; + struct timespec ts; + ts.tv_sec = (time_t)(ns / 1000000000LL); + ts.tv_nsec = (long)(ns % 1000000000LL); + nanosleep(&ts, NULL); + return (el_val_t)0; +} + +/* unix_timestamp() — back-compat. Existing El callers expect an Int seconds + * value; this stays an Int returner so the type system isn't disturbed for + * legacy code. New code should call now() and convert when needed. */ +el_val_t unix_timestamp(void) { + return instant_to_unix_seconds(el_now_instant()); +} + +/* TTL cache helpers. Backed by the existing process-wide K/V (state_set/get) + * with a sibling __ttl_set_at_ entry recording the Instant of the last + * write. ttl_cache_get returns "" if the entry is missing or stale, so call + * sites can branch on `if v == "" { miss } else { hit }` — the same shape + * existing get-with-default code uses. No more (now - cached_at) < 60. */ +el_val_t ttl_cache_set(el_val_t key, el_val_t value) { + const char* k = EL_CSTR(key); + if (!k) return (el_val_t)0; + /* Store the value at the user's key. */ + state_set(key, value); + /* Stamp set_at — opaque schema, namespaced under __ttl: prefix so user + * keys can't collide with stamps. */ + size_t klen = strlen(k); + char* stamp_key = (char*)malloc(klen + 16); + if (!stamp_key) return (el_val_t)0; + snprintf(stamp_key, klen + 16, "__ttl_at:%s", k); + int64_t now_ns = (int64_t)el_now_instant(); + char buf[32]; + snprintf(buf, sizeof(buf), "%lld", (long long)now_ns); + state_set(EL_STR(stamp_key), EL_STR(buf)); + free(stamp_key); + return (el_val_t)1; +} + +el_val_t ttl_cache_get(el_val_t key, el_val_t max_age) { + const char* k = EL_CSTR(key); + if (!k) return el_wrap_str(el_strdup("")); + /* Look up stamp. */ + size_t klen = strlen(k); + char* stamp_key = (char*)malloc(klen + 16); + if (!stamp_key) return el_wrap_str(el_strdup("")); + snprintf(stamp_key, klen + 16, "__ttl_at:%s", k); + el_val_t stamp = state_get(EL_STR(stamp_key)); + free(stamp_key); + const char* sv = EL_CSTR(stamp); + if (!sv || !*sv) return el_wrap_str(el_strdup("")); + int64_t set_at = (int64_t)atoll(sv); + int64_t now_ns = (int64_t)el_now_instant(); + int64_t age = now_ns - set_at; + int64_t max_ns = (int64_t)max_age; + if (age < 0) return el_wrap_str(el_strdup("")); /* clock skew — treat as miss */ + if (age > max_ns) return el_wrap_str(el_strdup("")); /* expired */ + return state_get(key); +} + +el_val_t ttl_cache_age(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return (el_val_t)INT64_MAX; + size_t klen = strlen(k); + char* stamp_key = (char*)malloc(klen + 16); + if (!stamp_key) return (el_val_t)INT64_MAX; + snprintf(stamp_key, klen + 16, "__ttl_at:%s", k); + el_val_t stamp = state_get(EL_STR(stamp_key)); + free(stamp_key); + const char* sv = EL_CSTR(stamp); + if (!sv || !*sv) return (el_val_t)INT64_MAX; + int64_t set_at = (int64_t)atoll(sv); + int64_t now_ns = (int64_t)el_now_instant(); + return (el_val_t)(now_ns - set_at); +} + +/* ── Calendar + CalendarTime + Rhythm + LocalDate/Time/DateTime ────────────── + * Phase 1.5. Calendar is pluggable: EarthCalendar (IANA zones + Gregorian + + * DST), MarsCalendar (sols, MTC), CycleCalendar(period), NoCycleCalendar, + * RelativeCalendar(epoch). Phase 1 zone wrapping folds INTO EarthCalendar; + * UTC and IANA zones are themselves Earth-parochial and cannot live at the + * lowest type layer. + * + * A Rhythm is a small AST that asks the Calendar for cycle phase, weekday, + * etc. Most rhythm logic is calendar-agnostic at runtime: rhythm_cycle_phase + * means "midpoint of cycle" whether the cycle is 24h on Earth or 30h on a + * station or 300y on a long-cycle world. */ + +/* Magic headers — used by the runtime to recognize boxed temporal values + * arriving through el_val_t. Distinct constants so accidental misuse fails + * loudly rather than silently. */ +#define EL_CAL_MAGIC 0xE1CA1EDDU +#define EL_CALTIME_MAGIC 0xE1CA1747U +#define EL_RHYTHM_MAGIC 0xE1287A11U +#define EL_LDATE_MAGIC 0xE1DA7E00U +#define EL_LDT_MAGIC 0xE1DA7E1DU +#define EL_ZONE_MAGIC 0xE12017E0U + +typedef enum { + EL_CALENDAR_EARTH = 1, + EL_CALENDAR_MARS = 2, + EL_CALENDAR_CYCLE = 3, + EL_CALENDAR_NO_CYCLE = 4, + EL_CALENDAR_RELATIVE = 5 +} el_calendar_kind_t; + +typedef struct { + uint32_t magic; + char* id; /* IANA name or "+HH:MM" / "-HH:MM" */ + int fixed; /* 1 for fixed offset, 0 for IANA */ + int64_t offset_ns; /* fixed offset in nanos (only when fixed) */ +} el_zone_t; + +typedef struct { + uint32_t magic; + el_calendar_kind_t kind; + el_zone_t* zone; /* EarthCalendar; MarsCalendar uses MTC */ + int64_t cycle_period_ns;/* CycleCalendar; computed for Earth (86400 s) and Mars (88775.244 s) */ + int64_t epoch_ns; /* RelativeCalendar; Unix-epoch zero otherwise */ +} el_calendar_t; + +typedef struct { + uint32_t magic; + int64_t instant_ns; + el_calendar_t* cal; +} el_caltime_t; + +/* Rhythm AST. */ +typedef enum { + EL_RHYTHM_CYCLE_START = 1, + EL_RHYTHM_CYCLE_PHASE = 2, + EL_RHYTHM_DURATION = 3, + EL_RHYTHM_SESSION_START = 4, + EL_RHYTHM_EVENT = 5, + EL_RHYTHM_AND = 6, + EL_RHYTHM_OR = 7, + EL_RHYTHM_WEEKDAY = 8, + EL_RHYTHM_WEEKLY_AT = 9 +} el_rhythm_kind_t; + +typedef struct el_rhythm_s { + uint32_t magic; + el_rhythm_kind_t kind; + double phase; /* CYCLE_PHASE */ + int64_t period_ns; /* DURATION */ + int weekday; /* 1..7 Mon..Sun */ + int hour; + int minute; + char* event_name; /* EVENT */ + struct el_rhythm_s* a; /* AND/OR */ + struct el_rhythm_s* b; +} el_rhythm_t; + +typedef struct { + uint32_t magic; + int year; + int month; + int day; +} el_localdate_t; + +typedef struct { + uint32_t magic; + el_localdate_t* date; + int64_t time_ns; /* nanos since midnight */ +} el_localdt_t; + +/* Magic-tag check helpers — peek the first 4 bytes of an el_val_t pointer + * and compare against the expected magic. Strings are NUL-terminated and + * never start with our magic byte sequence, so this is safe. */ +static int el_is_magic(el_val_t v, uint32_t want) { + if (v == 0) return 0; + /* Defensive: only follow pointers in plausible address space. + * On 64-bit unix processes pointers are above 0x10000. */ + if ((uint64_t)v < 0x10000ULL) return 0; + uint32_t got = *(volatile uint32_t*)(uintptr_t)v; + return got == want; +} + +/* Sol length on Mars in nanoseconds: 88775.244 seconds. */ +#define EL_MARS_SOL_NS ((int64_t)88775244000000LL) +/* Earth solar day in nanoseconds: 86400 seconds. */ +#define EL_EARTH_DAY_NS ((int64_t)86400000000000LL) + +/* ── Zone construction ────────────────────────────────────────────────────── + * Zones intern by id string so equality comparisons are pointer-compares. */ + +#define EL_ZONE_TABLE_CAP 64 +static el_zone_t* _el_zone_table[EL_ZONE_TABLE_CAP]; +static int _el_zone_count = 0; + +static el_zone_t* _el_zone_intern(const char* id, int fixed, int64_t offset_ns) { + for (int i = 0; i < _el_zone_count; i++) { + el_zone_t* z = _el_zone_table[i]; + if (z->fixed == fixed && z->offset_ns == offset_ns && + strcmp(z->id ? z->id : "", id ? id : "") == 0) { + return z; + } + } + if (_el_zone_count >= EL_ZONE_TABLE_CAP) { + /* Out of slots: build a non-interned zone. Equality will fail across + * such zones but the program still runs. */ + el_zone_t* z = (el_zone_t*)malloc(sizeof(el_zone_t)); + z->magic = EL_ZONE_MAGIC; + z->id = el_strdup_persist(id ? id : ""); + z->fixed = fixed; + z->offset_ns = offset_ns; + return z; + } + el_zone_t* z = (el_zone_t*)malloc(sizeof(el_zone_t)); + z->magic = EL_ZONE_MAGIC; + z->id = el_strdup_persist(id ? id : ""); + z->fixed = fixed; + z->offset_ns = offset_ns; + _el_zone_table[_el_zone_count++] = z; + return z; +} + +el_val_t zone(el_val_t id) { + const char* s = EL_CSTR(id); + if (!s || !*s) return (el_val_t)(uintptr_t)_el_zone_intern("UTC", 0, 0); + /* Fixed-offset shortcut: "+HH:MM" or "-HH:MM". */ + if ((s[0] == '+' || s[0] == '-') && strlen(s) >= 6 && s[3] == ':') { + int sign = (s[0] == '-') ? -1 : 1; + int hh = (s[1] - '0') * 10 + (s[2] - '0'); + int mm = (s[4] - '0') * 10 + (s[5] - '0'); + int64_t off = (int64_t)sign * ((int64_t)hh * 3600LL + (int64_t)mm * 60LL) * 1000000000LL; + return (el_val_t)(uintptr_t)_el_zone_intern(s, 1, off); + } + return (el_val_t)(uintptr_t)_el_zone_intern(s, 0, 0); +} + +el_val_t zone_utc(void) { + return (el_val_t)(uintptr_t)_el_zone_intern("UTC", 1, 0); +} + +el_val_t zone_local(void) { + /* Resolve the local zone via TZ env or system default. tzset() picks + * up TZ if set; otherwise the C library reads /etc/localtime. We store + * the zone id as "LOCAL" so subsequent equality holds; resolution is + * lazy at use time. */ + return (el_val_t)(uintptr_t)_el_zone_intern("LOCAL", 0, 0); +} + +el_val_t zone_offset(el_val_t hours, el_val_t minutes) { + int hh = (int)(int64_t)hours; + int mm = (int)(int64_t)minutes; + int sign = (hh < 0 || mm < 0) ? -1 : 1; + if (hh < 0) hh = -hh; + if (mm < 0) mm = -mm; + int64_t off = (int64_t)sign * ((int64_t)hh * 3600LL + (int64_t)mm * 60LL) * 1000000000LL; + char buf[16]; + snprintf(buf, sizeof(buf), "%c%02d:%02d", sign < 0 ? '-' : '+', hh, mm); + return (el_val_t)(uintptr_t)_el_zone_intern(buf, 1, off); +} + +/* ── Calendar interning ──────────────────────────────────────────────────── */ + +#define EL_CAL_TABLE_CAP 64 +static el_calendar_t* _el_cal_table[EL_CAL_TABLE_CAP]; +static int _el_cal_count = 0; + +static el_calendar_t* _el_cal_intern(el_calendar_kind_t kind, el_zone_t* z, + int64_t period_ns, int64_t epoch_ns) { + for (int i = 0; i < _el_cal_count; i++) { + el_calendar_t* c = _el_cal_table[i]; + if (c->kind == kind && c->zone == z && + c->cycle_period_ns == period_ns && c->epoch_ns == epoch_ns) { + return c; + } + } + el_calendar_t* c = (el_calendar_t*)malloc(sizeof(el_calendar_t)); + c->magic = EL_CAL_MAGIC; + c->kind = kind; + c->zone = z; + c->cycle_period_ns = period_ns; + c->epoch_ns = epoch_ns; + if (_el_cal_count < EL_CAL_TABLE_CAP) _el_cal_table[_el_cal_count++] = c; + return c; +} + +el_val_t earth_calendar(el_val_t z_val) { + el_zone_t* z = NULL; + if (z_val != 0 && el_is_magic(z_val, EL_ZONE_MAGIC)) { + z = (el_zone_t*)(uintptr_t)z_val; + } else { + z = (el_zone_t*)(uintptr_t)zone_local(); + } + return (el_val_t)(uintptr_t)_el_cal_intern(EL_CALENDAR_EARTH, z, EL_EARTH_DAY_NS, 0); +} + +el_val_t earth_calendar_default(void) { + return earth_calendar(zone_local()); +} + +el_val_t mars_calendar(void) { + el_zone_t* z = (el_zone_t*)(uintptr_t)_el_zone_intern("MTC", 1, 0); + return (el_val_t)(uintptr_t)_el_cal_intern(EL_CALENDAR_MARS, z, EL_MARS_SOL_NS, 0); +} + +el_val_t cycle_calendar(el_val_t period_dur) { + int64_t period = (int64_t)period_dur; + if (period <= 0) period = 1; + return (el_val_t)(uintptr_t)_el_cal_intern(EL_CALENDAR_CYCLE, NULL, period, 0); +} + +el_val_t no_cycle_calendar(void) { + return (el_val_t)(uintptr_t)_el_cal_intern(EL_CALENDAR_NO_CYCLE, NULL, 0, 0); +} + +el_val_t relative_calendar(el_val_t epoch_inst) { + int64_t ep = (int64_t)epoch_inst; + return (el_val_t)(uintptr_t)_el_cal_intern(EL_CALENDAR_RELATIVE, NULL, 0, ep); +} + +/* ── CalendarTime ───────────────────────────────────────────────────────── */ + +static el_caltime_t* _el_caltime_alloc(int64_t inst, el_calendar_t* c) { + el_caltime_t* ct = (el_caltime_t*)malloc(sizeof(el_caltime_t)); + ct->magic = EL_CALTIME_MAGIC; + ct->instant_ns = inst; + ct->cal = c; + return ct; +} + +static el_calendar_t* _el_resolve_cal(el_val_t cal_val) { + if (cal_val == 0 || !el_is_magic(cal_val, EL_CAL_MAGIC)) { + return (el_calendar_t*)(uintptr_t)earth_calendar_default(); + } + return (el_calendar_t*)(uintptr_t)cal_val; +} + +el_val_t now_in(el_val_t cal_val) { + el_calendar_t* c = _el_resolve_cal(cal_val); + int64_t ns = (int64_t)el_now_instant(); + return (el_val_t)(uintptr_t)_el_caltime_alloc(ns, c); +} + +el_val_t in_calendar(el_val_t inst, el_val_t cal_val) { + el_calendar_t* c = _el_resolve_cal(cal_val); + return (el_val_t)(uintptr_t)_el_caltime_alloc((int64_t)inst, c); +} + +el_val_t cal_to_instant(el_val_t ct_val) { + if (!el_is_magic(ct_val, EL_CALTIME_MAGIC)) return (el_val_t)0; + el_caltime_t* ct = (el_caltime_t*)(uintptr_t)ct_val; + return (el_val_t)ct->instant_ns; +} + +el_val_t cal_in(el_val_t ct_val, el_val_t cal_val) { + if (!el_is_magic(ct_val, EL_CALTIME_MAGIC)) return (el_val_t)0; + el_caltime_t* ct = (el_caltime_t*)(uintptr_t)ct_val; + el_calendar_t* c = _el_resolve_cal(cal_val); + return (el_val_t)(uintptr_t)_el_caltime_alloc(ct->instant_ns, c); +} + +el_val_t cal_cycle_phase(el_val_t ct_val) { + if (!el_is_magic(ct_val, EL_CALTIME_MAGIC)) return el_from_float(0.0); + el_caltime_t* ct = (el_caltime_t*)(uintptr_t)ct_val; + el_calendar_t* c = ct->cal; + if (c->kind == EL_CALENDAR_NO_CYCLE) { + return el_from_float(0.0/0.0); /* NaN sentinel */ + } + int64_t period = c->cycle_period_ns; + if (period <= 0) return el_from_float(0.0); + int64_t base = ct->instant_ns - c->epoch_ns; + int64_t phase_ns = base % period; + if (phase_ns < 0) phase_ns += period; + double phase = (double)phase_ns / (double)period; + return el_from_float(phase); +} + +/* ── Earth zone resolution: TZ-based offset lookup ────────────────────────── + * For an EarthCalendar(zone), we want to convert an instant_ns into local + * y/m/d/h/m/s, including DST. Approach: setenv("TZ", id), tzset(), use + * localtime_r, then restore. This is not thread-safe by design — El's + * runtime is single-threaded for the request handler path. Cache the + * computed (instant -> tm) to avoid the syscall churn on repeat formats. */ + +static void _el_apply_zone(el_zone_t* z) { + if (!z) { unsetenv("TZ"); tzset(); return; } + if (z->fixed && strcmp(z->id, "UTC") == 0) { + setenv("TZ", "UTC0", 1); + tzset(); + return; + } + if (z->fixed) { + /* Fixed offset: POSIX TZ uses inverted sign (sign convention of + * "hours WEST of UTC" rather than east). Build the spec accordingly. */ + char buf[32]; + int neg_secs = (int)(-z->offset_ns / 1000000000LL); + int sign = neg_secs < 0 ? -1 : 1; + int abs_secs = neg_secs < 0 ? -neg_secs : neg_secs; + int hh = abs_secs / 3600; + int mm = (abs_secs % 3600) / 60; + snprintf(buf, sizeof(buf), "FIX%c%d:%02d", sign < 0 ? '-' : '+', hh, mm); + setenv("TZ", buf, 1); + tzset(); + return; + } + if (strcmp(z->id, "LOCAL") == 0) { + unsetenv("TZ"); + tzset(); + return; + } + setenv("TZ", z->id, 1); + tzset(); +} + +static int _el_decompose_earth(el_caltime_t* ct, struct tm* tm_out, int* abbr_len, char* abbr_buf, size_t abbr_cap) { + el_calendar_t* c = ct->cal; + el_zone_t* z = c->zone; + _el_apply_zone(z); + time_t s = (time_t)(ct->instant_ns / 1000000000LL); + struct tm tm; + localtime_r(&s, &tm); + *tm_out = tm; + if (abbr_buf && abbr_cap > 0) { + const char* z_str = tm.tm_zone ? tm.tm_zone : ""; + size_t n = strlen(z_str); + if (n >= abbr_cap) n = abbr_cap - 1; + memcpy(abbr_buf, z_str, n); + abbr_buf[n] = '\0'; + if (abbr_len) *abbr_len = (int)n; + } + return 0; +} + +/* Format an Earth CalendarTime under a Java-DateTimeFormatter-ish pattern. + * We support a useful core: yyyy MM dd HH mm ss z EEE MMM d h a — enough for + * the acceptance tests. Single quotes denote literal text. */ +static const char* _el_weekday_short[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; +static const char* _el_month_short[] = {"Jan","Feb","Mar","Apr","May","Jun", + "Jul","Aug","Sep","Oct","Nov","Dec"}; + +static char* _el_format_earth(el_caltime_t* ct, const char* pattern) { + struct tm tm; + char abbr[16] = {0}; + int abbr_len = 0; + _el_decompose_earth(ct, &tm, &abbr_len, abbr, sizeof(abbr)); + size_t cap = strlen(pattern) * 4 + 64; + char* out = (char*)malloc(cap); + size_t pos = 0; + size_t i = 0; + size_t plen = strlen(pattern); + while (i < plen) { + char ch = pattern[i]; + /* Quoted literal */ + if (ch == '\'') { + i++; + while (i < plen && pattern[i] != '\'') { + if (pos + 1 >= cap) { cap *= 2; out = realloc(out, cap); } + out[pos++] = pattern[i++]; + } + if (i < plen) i++; + continue; + } + /* Count run of same letter */ + size_t run = 1; + while (i + run < plen && pattern[i + run] == ch) run++; + char tmp[64]; + tmp[0] = '\0'; + if (ch == 'y') { + if (run >= 4) snprintf(tmp, sizeof(tmp), "%04d", tm.tm_year + 1900); + else snprintf(tmp, sizeof(tmp), "%02d", (tm.tm_year + 1900) % 100); + } else if (ch == 'M') { + if (run >= 3) snprintf(tmp, sizeof(tmp), "%s", _el_month_short[tm.tm_mon]); + else if (run == 2) snprintf(tmp, sizeof(tmp), "%02d", tm.tm_mon + 1); + else snprintf(tmp, sizeof(tmp), "%d", tm.tm_mon + 1); + } else if (ch == 'd') { + if (run >= 2) snprintf(tmp, sizeof(tmp), "%02d", tm.tm_mday); + else snprintf(tmp, sizeof(tmp), "%d", tm.tm_mday); + } else if (ch == 'H') { + if (run >= 2) snprintf(tmp, sizeof(tmp), "%02d", tm.tm_hour); + else snprintf(tmp, sizeof(tmp), "%d", tm.tm_hour); + } else if (ch == 'h') { + int h12 = tm.tm_hour % 12; if (h12 == 0) h12 = 12; + if (run >= 2) snprintf(tmp, sizeof(tmp), "%02d", h12); + else snprintf(tmp, sizeof(tmp), "%d", h12); + } else if (ch == 'm') { + if (run >= 2) snprintf(tmp, sizeof(tmp), "%02d", tm.tm_min); + else snprintf(tmp, sizeof(tmp), "%d", tm.tm_min); + } else if (ch == 's') { + if (run >= 2) snprintf(tmp, sizeof(tmp), "%02d", tm.tm_sec); + else snprintf(tmp, sizeof(tmp), "%d", tm.tm_sec); + } else if (ch == 'a') { + snprintf(tmp, sizeof(tmp), "%s", tm.tm_hour < 12 ? "AM" : "PM"); + } else if (ch == 'E') { + snprintf(tmp, sizeof(tmp), "%s", _el_weekday_short[tm.tm_wday]); + } else if (ch == 'z') { + snprintf(tmp, sizeof(tmp), "%s", abbr); + } else { + for (size_t k = 0; k < run; k++) { + if (pos + 1 >= cap) { cap *= 2; out = realloc(out, cap); } + out[pos++] = ch; + } + i += run; + continue; + } + size_t tl = strlen(tmp); + if (pos + tl + 1 >= cap) { cap = (cap + tl) * 2; out = realloc(out, cap); } + memcpy(out + pos, tmp, tl); + pos += tl; + i += run; + } + out[pos] = '\0'; + char* result = el_strdup(out); + free(out); + return result; +} + +/* Format a Mars CalendarTime: %sol prints the integer sol number since + * mission epoch (Unix epoch fallback), %phase prints cycle_phase as a + * 0..1 decimal. Other %-specifiers fall through. */ +static char* _el_format_mars(el_caltime_t* ct, const char* pattern) { + el_calendar_t* c = ct->cal; + int64_t period = c->cycle_period_ns > 0 ? c->cycle_period_ns : EL_MARS_SOL_NS; + int64_t base = ct->instant_ns - c->epoch_ns; + int64_t sol = base / period; + int64_t phase_ns = base % period; + if (phase_ns < 0) { phase_ns += period; sol -= 1; } + double phase = (double)phase_ns / (double)period; + size_t cap = strlen(pattern) * 4 + 64; + char* out = (char*)malloc(cap); + size_t pos = 0; + for (size_t i = 0; pattern[i]; i++) { + if (pattern[i] == '%' && pattern[i+1]) { + char tmp[64]; + tmp[0] = '\0'; + if (strncmp(pattern + i + 1, "sol", 3) == 0) { + snprintf(tmp, sizeof(tmp), "%lld", (long long)sol); + i += 3; + } else if (strncmp(pattern + i + 1, "phase", 5) == 0) { + snprintf(tmp, sizeof(tmp), "%.4f", phase); + i += 5; + } else if (pattern[i+1] == 'd') { + snprintf(tmp, sizeof(tmp), "%lld", (long long)sol); + i += 1; + } else { + tmp[0] = pattern[i+1]; tmp[1] = '\0'; + i += 1; + } + size_t tl = strlen(tmp); + if (pos + tl + 1 >= cap) { cap = (cap + tl) * 2; out = realloc(out, cap); } + memcpy(out + pos, tmp, tl); + pos += tl; + } else { + if (pos + 1 >= cap) { cap *= 2; out = realloc(out, cap); } + out[pos++] = pattern[i]; + } + } + out[pos] = '\0'; + char* result = el_strdup(out); + free(out); + return result; +} + +/* Format a CycleCalendar CalendarTime: %cycle and %phase. */ +static char* _el_format_cycle(el_caltime_t* ct, const char* pattern) { + el_calendar_t* c = ct->cal; + int64_t period = c->cycle_period_ns > 0 ? c->cycle_period_ns : 1; + int64_t base = ct->instant_ns - c->epoch_ns; + int64_t cycle = base / period; + int64_t phase_ns = base % period; + if (phase_ns < 0) { phase_ns += period; cycle -= 1; } + double phase = (double)phase_ns / (double)period; + size_t cap = strlen(pattern) * 4 + 64; + char* out = (char*)malloc(cap); + size_t pos = 0; + for (size_t i = 0; pattern[i]; i++) { + if (pattern[i] == '%' && pattern[i+1]) { + char tmp[64]; + tmp[0] = '\0'; + if (strncmp(pattern + i + 1, "cycle", 5) == 0) { + snprintf(tmp, sizeof(tmp), "%lld", (long long)cycle); + i += 5; + } else if (strncmp(pattern + i + 1, "phase", 5) == 0) { + snprintf(tmp, sizeof(tmp), "%.4f", phase); + i += 5; + } else if (pattern[i+1] == 'd') { + snprintf(tmp, sizeof(tmp), "%lld", (long long)cycle); + i += 1; + } else if (pattern[i+1] == 'f') { + snprintf(tmp, sizeof(tmp), "%.2f", phase); + i += 1; + } else { + /* Pass through unknown specifier */ + tmp[0] = '%'; tmp[1] = pattern[i+1]; tmp[2] = '\0'; + i += 1; + } + size_t tl = strlen(tmp); + if (pos + tl + 1 >= cap) { cap = (cap + tl) * 2; out = realloc(out, cap); } + memcpy(out + pos, tmp, tl); + pos += tl; + } else { + if (pos + 1 >= cap) { cap *= 2; out = realloc(out, cap); } + out[pos++] = pattern[i]; + } + } + out[pos] = '\0'; + char* result = el_strdup(out); + free(out); + return result; +} + +el_val_t cal_format(el_val_t ct_val, el_val_t pattern_val) { + if (!el_is_magic(ct_val, EL_CALTIME_MAGIC)) return el_wrap_str(el_strdup("")); + el_caltime_t* ct = (el_caltime_t*)(uintptr_t)ct_val; + const char* pat = EL_CSTR(pattern_val); + if (!pat) pat = ""; + char* result = NULL; + switch (ct->cal->kind) { + case EL_CALENDAR_EARTH: result = _el_format_earth(ct, pat); break; + case EL_CALENDAR_MARS: result = _el_format_mars(ct, pat); break; + case EL_CALENDAR_CYCLE: result = _el_format_cycle(ct, pat); break; + case EL_CALENDAR_RELATIVE: result = _el_format_cycle(ct, pat); break; + case EL_CALENDAR_NO_CYCLE: { + char buf[64]; + snprintf(buf, sizeof(buf), "instant:%lld", (long long)ct->instant_ns); + result = el_strdup(buf); + break; + } + default: result = el_strdup(""); + } + return el_wrap_str(result); +} + +/* ── LocalDate / LocalTime / LocalDateTime ──────────────────────────────── */ + +static int _el_days_in_month(int y, int m) { + static const int dim[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; + if (m == 2) { + int leap = ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0); + return 28 + (leap ? 1 : 0); + } + if (m < 1 || m > 12) return 30; + return dim[m - 1]; +} + +el_val_t local_date(el_val_t y, el_val_t m, el_val_t d) { + el_localdate_t* ld = (el_localdate_t*)malloc(sizeof(el_localdate_t)); + ld->magic = EL_LDATE_MAGIC; + ld->year = (int)(int64_t)y; + ld->month = (int)(int64_t)m; + ld->day = (int)(int64_t)d; + return (el_val_t)(uintptr_t)ld; +} + +el_val_t local_time(el_val_t h, el_val_t m, el_val_t s, el_val_t ns) { + int64_t hh = (int64_t)h; + int64_t mm = (int64_t)m; + int64_t ss = (int64_t)s; + int64_t nn = (int64_t)ns; + int64_t total = hh * 3600000000000LL + mm * 60000000000LL + ss * 1000000000LL + nn; + return (el_val_t)total; +} + +el_val_t local_datetime(el_val_t date_val, el_val_t time_val) { + if (!el_is_magic(date_val, EL_LDATE_MAGIC)) return (el_val_t)0; + el_localdt_t* ldt = (el_localdt_t*)malloc(sizeof(el_localdt_t)); + ldt->magic = EL_LDT_MAGIC; + ldt->date = (el_localdate_t*)(uintptr_t)date_val; + ldt->time_ns = (int64_t)time_val; + return (el_val_t)(uintptr_t)ldt; +} + +el_val_t zoned(el_val_t date_val, el_val_t time_val, el_val_t cal_val) { + if (!el_is_magic(date_val, EL_LDATE_MAGIC)) return (el_val_t)0; + el_localdate_t* ld = (el_localdate_t*)(uintptr_t)date_val; + el_calendar_t* c = _el_resolve_cal(cal_val); + int64_t time_ns = (int64_t)time_val; + /* Convert (LocalDate, LocalTime, EarthCalendar) -> Instant. + * For non-Earth calendars we use day-anchored conversion: treat the + * LocalDate's (y,m,d) as a Gregorian projection, convert to seconds via + * mktime under the calendar's zone, then add nanos-since-midnight. */ + if (c->kind == EL_CALENDAR_EARTH) { + _el_apply_zone(c->zone); + struct tm tm; memset(&tm, 0, sizeof(tm)); + tm.tm_year = ld->year - 1900; + tm.tm_mon = ld->month - 1; + tm.tm_mday = ld->day; + tm.tm_hour = (int)(time_ns / 3600000000000LL); + tm.tm_min = (int)((time_ns / 60000000000LL) % 60); + tm.tm_sec = (int)((time_ns / 1000000000LL) % 60); + tm.tm_isdst = -1; + time_t t = mktime(&tm); + if (t == (time_t)-1) return (el_val_t)0; + int64_t ns = (int64_t)t * 1000000000LL + (time_ns % 1000000000LL); + return (el_val_t)(uintptr_t)_el_caltime_alloc(ns, c); + } + /* Non-Earth fallback: project as if Earth UTC then attach calendar. */ + struct tm tm; memset(&tm, 0, sizeof(tm)); + tm.tm_year = ld->year - 1900; + tm.tm_mon = ld->month - 1; + tm.tm_mday = ld->day; + tm.tm_hour = (int)(time_ns / 3600000000000LL); + tm.tm_min = (int)((time_ns / 60000000000LL) % 60); + tm.tm_sec = (int)((time_ns / 1000000000LL) % 60); + time_t t = timegm(&tm); + if (t == (time_t)-1) return (el_val_t)0; + int64_t ns = (int64_t)t * 1000000000LL + (time_ns % 1000000000LL); + return (el_val_t)(uintptr_t)_el_caltime_alloc(ns, c); +} + +el_val_t local_date_year(el_val_t v) { + if (!el_is_magic(v, EL_LDATE_MAGIC)) return (el_val_t)0; + return (el_val_t)((el_localdate_t*)(uintptr_t)v)->year; +} +el_val_t local_date_month(el_val_t v) { + if (!el_is_magic(v, EL_LDATE_MAGIC)) return (el_val_t)0; + return (el_val_t)((el_localdate_t*)(uintptr_t)v)->month; +} +el_val_t local_date_day(el_val_t v) { + if (!el_is_magic(v, EL_LDATE_MAGIC)) return (el_val_t)0; + return (el_val_t)((el_localdate_t*)(uintptr_t)v)->day; +} +el_val_t local_time_hour(el_val_t v) { + int64_t t = (int64_t)v; + return (el_val_t)(t / 3600000000000LL); +} +el_val_t local_time_minute(el_val_t v) { + int64_t t = (int64_t)v; + return (el_val_t)((t / 60000000000LL) % 60); +} +el_val_t local_time_second(el_val_t v) { + int64_t t = (int64_t)v; + return (el_val_t)((t / 1000000000LL) % 60); +} +el_val_t local_time_nanos(el_val_t v) { + int64_t t = (int64_t)v; + return (el_val_t)(t % 1000000000LL); +} + +el_val_t el_local_date_add_dur(el_val_t ld_val, el_val_t dur_val) { + if (!el_is_magic(ld_val, EL_LDATE_MAGIC)) return ld_val; + el_localdate_t* ld = (el_localdate_t*)(uintptr_t)ld_val; + int64_t dur_ns = (int64_t)dur_val; + int64_t days = dur_ns / EL_EARTH_DAY_NS; + int y = ld->year, m = ld->month, d = ld->day; + /* Walk days forward/backward in canonical Gregorian. */ + while (days > 0) { + int dim = _el_days_in_month(y, m); + if (d + days <= dim) { d += (int)days; days = 0; break; } + days -= (dim - d + 1); + d = 1; + m++; + if (m > 12) { m = 1; y++; } + } + while (days < 0) { + if (d + days >= 1) { d += (int)days; days = 0; break; } + days += d; + m--; + if (m < 1) { m = 12; y--; } + d = _el_days_in_month(y, m); + } + return local_date((el_val_t)y, (el_val_t)m, (el_val_t)d); +} + +el_val_t el_local_time_add_dur(el_val_t lt_val, el_val_t dur_val) { + int64_t t = (int64_t)lt_val + (int64_t)dur_val; + /* Wrap mod 24h on Earth-default. CycleCalendar wrapping requires the + * caller to use cal_in / cal_format for the right modulus. */ + int64_t day = EL_EARTH_DAY_NS; + int64_t r = t % day; + if (r < 0) r += day; + return (el_val_t)r; +} + +el_val_t el_local_date_lt(el_val_t a_val, el_val_t b_val) { + if (!el_is_magic(a_val, EL_LDATE_MAGIC) || !el_is_magic(b_val, EL_LDATE_MAGIC)) return (el_val_t)0; + el_localdate_t* a = (el_localdate_t*)(uintptr_t)a_val; + el_localdate_t* b = (el_localdate_t*)(uintptr_t)b_val; + if (a->year != b->year) return (el_val_t)(a->year < b->year ? 1 : 0); + if (a->month != b->month) return (el_val_t)(a->month < b->month ? 1 : 0); + return (el_val_t)(a->day < b->day ? 1 : 0); +} + +el_val_t el_local_date_eq(el_val_t a_val, el_val_t b_val) { + if (!el_is_magic(a_val, EL_LDATE_MAGIC) || !el_is_magic(b_val, EL_LDATE_MAGIC)) return (el_val_t)0; + el_localdate_t* a = (el_localdate_t*)(uintptr_t)a_val; + el_localdate_t* b = (el_localdate_t*)(uintptr_t)b_val; + return (el_val_t)((a->year == b->year && a->month == b->month && a->day == b->day) ? 1 : 0); +} + +/* ── Rhythm ──────────────────────────────────────────────────────────────── */ + +static el_rhythm_t* _el_rhythm_alloc(el_rhythm_kind_t k) { + el_rhythm_t* r = (el_rhythm_t*)calloc(1, sizeof(el_rhythm_t)); + r->magic = EL_RHYTHM_MAGIC; + r->kind = k; + return r; +} + +el_val_t rhythm_cycle_start(void) { + return (el_val_t)(uintptr_t)_el_rhythm_alloc(EL_RHYTHM_CYCLE_START); +} + +el_val_t rhythm_cycle_phase(el_val_t phase_val) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_CYCLE_PHASE); + r->phase = el_to_float(phase_val); + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_duration(el_val_t d_val) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_DURATION); + r->period_ns = (int64_t)d_val; + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_session_start(void) { + return (el_val_t)(uintptr_t)_el_rhythm_alloc(EL_RHYTHM_SESSION_START); +} + +el_val_t rhythm_event(el_val_t name_val) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_EVENT); + const char* n = EL_CSTR(name_val); + r->event_name = el_strdup_persist(n ? n : ""); + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_and(el_val_t a_val, el_val_t b_val) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_AND); + r->a = el_is_magic(a_val, EL_RHYTHM_MAGIC) ? (el_rhythm_t*)(uintptr_t)a_val : NULL; + r->b = el_is_magic(b_val, EL_RHYTHM_MAGIC) ? (el_rhythm_t*)(uintptr_t)b_val : NULL; + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_or(el_val_t a_val, el_val_t b_val) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_OR); + r->a = el_is_magic(a_val, EL_RHYTHM_MAGIC) ? (el_rhythm_t*)(uintptr_t)a_val : NULL; + r->b = el_is_magic(b_val, EL_RHYTHM_MAGIC) ? (el_rhythm_t*)(uintptr_t)b_val : NULL; + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_weekday(el_val_t day) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_WEEKDAY); + r->weekday = (int)(int64_t)day; + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_weekly_at(el_val_t day, el_val_t hour, el_val_t minute) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_WEEKLY_AT); + r->weekday = (int)(int64_t)day; + r->hour = (int)(int64_t)hour; + r->minute = (int)(int64_t)minute; + return (el_val_t)(uintptr_t)r; +} + +/* Compute the next instant on or after `after` when rhythm `r` matches, + * under calendar `cal`. */ +static int64_t _el_next_after(el_rhythm_t* r, int64_t after_ns, el_calendar_t* cal) { + if (!r) return after_ns; + int64_t period = cal->cycle_period_ns > 0 ? cal->cycle_period_ns : EL_EARTH_DAY_NS; + switch (r->kind) { + case EL_RHYTHM_CYCLE_START: { + int64_t base = after_ns - cal->epoch_ns; + int64_t cyc = (base / period) + 1; + return cal->epoch_ns + cyc * period; + } + case EL_RHYTHM_CYCLE_PHASE: { + int64_t base = after_ns - cal->epoch_ns; + int64_t cyc_ns = (int64_t)(r->phase * (double)period); + int64_t cur_cyc = base / period; + int64_t candidate = cal->epoch_ns + cur_cyc * period + cyc_ns; + if (candidate <= after_ns) candidate += period; + return candidate; + } + case EL_RHYTHM_DURATION: { + return after_ns + (r->period_ns > 0 ? r->period_ns : 1); + } + case EL_RHYTHM_WEEKDAY: + case EL_RHYTHM_WEEKLY_AT: { + if (cal->kind != EL_CALENDAR_EARTH) { + /* Non-Earth calendars: fall back to cycle math, treating + * weekday as a 7-cycle-per-period proxy. */ + return after_ns + period; + } + _el_apply_zone(cal->zone); + time_t s = (time_t)(after_ns / 1000000000LL); + struct tm tm; + localtime_r(&s, &tm); + /* tm_wday: 0=Sun..6=Sat. We use 1=Mon..7=Sun. */ + int target = r->weekday >= 1 && r->weekday <= 7 ? r->weekday : 1; + int target_wday = target == 7 ? 0 : target; /* 7→Sun=0, 1→Mon=1 */ + int days_ahead = (target_wday - tm.tm_wday + 7) % 7; + int hour = (r->kind == EL_RHYTHM_WEEKLY_AT) ? r->hour : 0; + int minute = (r->kind == EL_RHYTHM_WEEKLY_AT) ? r->minute : 0; + struct tm cand = tm; + cand.tm_mday += days_ahead; + cand.tm_hour = hour; + cand.tm_min = minute; + cand.tm_sec = 0; + cand.tm_isdst = -1; + time_t cand_t = mktime(&cand); + int64_t cand_ns = (int64_t)cand_t * 1000000000LL; + if (cand_ns <= after_ns) { + cand.tm_mday += 7; + cand.tm_isdst = -1; + cand_t = mktime(&cand); + cand_ns = (int64_t)cand_t * 1000000000LL; + } + return cand_ns; + } + case EL_RHYTHM_AND: { + int64_t a = _el_next_after(r->a, after_ns, cal); + int64_t b = _el_next_after(r->b, after_ns, cal); + return a > b ? a : b; + } + case EL_RHYTHM_OR: { + int64_t a = _el_next_after(r->a, after_ns, cal); + int64_t b = _el_next_after(r->b, after_ns, cal); + return a < b ? a : b; + } + case EL_RHYTHM_SESSION_START: + case EL_RHYTHM_EVENT: + default: + return after_ns; + } +} + +el_val_t rhythm_next_after(el_val_t r_val, el_val_t after_val, el_val_t cal_val) { + if (!el_is_magic(r_val, EL_RHYTHM_MAGIC)) return after_val; + el_rhythm_t* r = (el_rhythm_t*)(uintptr_t)r_val; + el_calendar_t* c = _el_resolve_cal(cal_val); + int64_t out = _el_next_after(r, (int64_t)after_val, c); + return (el_val_t)out; +} + +el_val_t rhythm_matches(el_val_t r_val, el_val_t ct_val) { + if (!el_is_magic(r_val, EL_RHYTHM_MAGIC)) return (el_val_t)0; + if (!el_is_magic(ct_val, EL_CALTIME_MAGIC)) return (el_val_t)0; + el_rhythm_t* r = (el_rhythm_t*)(uintptr_t)r_val; + el_caltime_t* ct = (el_caltime_t*)(uintptr_t)ct_val; + int64_t period = ct->cal->cycle_period_ns > 0 ? ct->cal->cycle_period_ns : EL_EARTH_DAY_NS; + int64_t base = ct->instant_ns - ct->cal->epoch_ns; + int64_t phase_ns = base % period; + if (phase_ns < 0) phase_ns += period; + double phase = (double)phase_ns / (double)period; + switch (r->kind) { + case EL_RHYTHM_CYCLE_START: return (el_val_t)(phase_ns == 0 ? 1 : 0); + case EL_RHYTHM_CYCLE_PHASE: { + double diff = phase - r->phase; + if (diff < 0) diff = -diff; + return (el_val_t)(diff < 0.001 ? 1 : 0); + } + default: return (el_val_t)0; + } +} + +/* ── UUID v4 ─────────────────────────────────────────────────────────────── */ + +static int _el_uuid_seeded = 0; + +static void _el_uuid_seed(void) { + if (!_el_uuid_seeded) { + srand((unsigned)time(NULL) ^ (unsigned)(uintptr_t)&_el_uuid_seeded); + _el_uuid_seeded = 1; + } +} + +el_val_t uuid_new(void) { + _el_uuid_seed(); + unsigned char b[16]; + for (int i = 0; i < 16; i++) b[i] = (unsigned char)(rand() & 0xff); + /* Version 4 */ + b[6] = (b[6] & 0x0f) | 0x40; + /* RFC 4122 variant */ + b[8] = (b[8] & 0x3f) | 0x80; + char buf[37]; + snprintf(buf, sizeof(buf), + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + b[0], b[1], b[2], b[3], + b[4], b[5], + b[6], b[7], + b[8], b[9], + b[10], b[11], b[12], b[13], b[14], b[15]); + return el_wrap_str(el_strdup(buf)); +} + +el_val_t uuid_v4(void) { return uuid_new(); } + +/* ── Environment ─────────────────────────────────────────────────────────── */ + +el_val_t env(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return el_wrap_str(el_strdup("")); + const char* v = getenv(k); + return el_wrap_str(el_strdup(v ? v : "")); +} + +/* ── In-process state K/V ────────────────────────────────────────────────── */ + +typedef struct { + char* key; + char* value; +} StateEntry; + +static StateEntry* _state_entries = NULL; +static size_t _state_count = 0; +static size_t _state_cap = 0; +/* Mutex protecting all _state_entries access. state_set/state_get are called + * concurrently from 64 HTTP worker threads — without this lock, realloc and + * free race, producing corruption, double-free, and segfaults. */ +static pthread_mutex_t _state_mu = PTHREAD_MUTEX_INITIALIZER; + +static StateEntry* state_find(const char* key) { + for (size_t i = 0; i < _state_count; i++) { + if (strcmp(_state_entries[i].key, key) == 0) return &_state_entries[i]; + } + return NULL; +} + +el_val_t state_set(el_val_t key, el_val_t value) { + const char* k = EL_CSTR(key); + const char* v = EL_CSTR(value); + if (!k) return 0; + if (!v) v = ""; + pthread_mutex_lock(&_state_mu); + StateEntry* e = state_find(k); + if (e) { + free(e->value); + e->value = el_strdup_persist(v); + pthread_mutex_unlock(&_state_mu); + return 1; + } + if (_state_count >= _state_cap) { + size_t nc = _state_cap == 0 ? 16 : _state_cap * 2; + StateEntry* grown = realloc(_state_entries, nc * sizeof(StateEntry)); + if (!grown) { pthread_mutex_unlock(&_state_mu); fputs("el_runtime: out of memory\n", stderr); exit(1); } + _state_entries = grown; + _state_cap = nc; + } + _state_entries[_state_count].key = el_strdup_persist(k); + _state_entries[_state_count].value = el_strdup_persist(v); + _state_count++; + pthread_mutex_unlock(&_state_mu); + return 1; +} + +el_val_t state_get(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return el_wrap_str(el_strdup("")); + pthread_mutex_lock(&_state_mu); + StateEntry* e = state_find(k); + char* result = el_strdup_persist(e ? e->value : ""); + pthread_mutex_unlock(&_state_mu); + /* wrap in arena-tracked copy for the caller's request lifetime */ + char* copy = el_strdup(result); + return el_wrap_str(copy); +} + +el_val_t state_del(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return 0; + pthread_mutex_lock(&_state_mu); + for (size_t i = 0; i < _state_count; i++) { + if (strcmp(_state_entries[i].key, k) == 0) { + free(_state_entries[i].key); + free(_state_entries[i].value); + for (size_t j = i + 1; j < _state_count; j++) { + _state_entries[j - 1] = _state_entries[j]; + } + _state_count--; + pthread_mutex_unlock(&_state_mu); + return 1; + } + } + pthread_mutex_unlock(&_state_mu); + return 1; +} + +el_val_t state_keys(void) { + pthread_mutex_lock(&_state_mu); + /* Build a JSON array string: ["key1","key2",...] */ + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + for (size_t i = 0; i < _state_count; i++) { + if (i > 0) jb_putc(&b, ','); + jb_putc(&b, '"'); + jb_emit_escaped(&b, _state_entries[i].key); + jb_putc(&b, '"'); + } + jb_putc(&b, ']'); + pthread_mutex_unlock(&_state_mu); + return el_wrap_str(b.buf); +} + +/* Returns 1 (true) if the key is present in the state store, else 0 (false). */ +el_val_t state_has(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return 0; + pthread_mutex_lock(&_state_mu); + StateEntry* e = state_find(k); + int found = (e != NULL) ? 1 : 0; + pthread_mutex_unlock(&_state_mu); + return (el_val_t)found; +} + +/* Returns the value for key, or default_val if the key is absent. */ +el_val_t state_get_or(el_val_t key, el_val_t default_val) { + const char* k = EL_CSTR(key); + if (!k) return default_val; + pthread_mutex_lock(&_state_mu); + StateEntry* e = state_find(k); + if (e) { + char* copy = el_strdup(e->value); + pthread_mutex_unlock(&_state_mu); + return el_wrap_str(copy); + } + pthread_mutex_unlock(&_state_mu); + return default_val; +} + +/* ── Float formatting ────────────────────────────────────────────────────── */ + +el_val_t float_to_str(el_val_t f) { + char buf[64]; + double v = el_to_float(f); + /* Normalize NaN to "nan" regardless of sign — platform-independent. */ + if (isnan(v)) { + snprintf(buf, sizeof(buf), "nan"); + } else { + snprintf(buf, sizeof(buf), "%g", v); + } + return el_wrap_str(el_strdup(buf)); +} + +el_val_t int_to_float(el_val_t n) { + return el_from_float((double)(int64_t)n); +} + +el_val_t float_to_int(el_val_t f) { + return (el_val_t)(int64_t)el_to_float(f); +} + +el_val_t format_float(el_val_t f, el_val_t decimals) { + int d = (int)(int64_t)decimals; + if (d < 0) d = 0; + if (d > 30) d = 30; + char buf[128]; + snprintf(buf, sizeof(buf), "%.*f", d, el_to_float(f)); + return el_wrap_str(el_strdup(buf)); +} + +el_val_t decimal_round(el_val_t f, el_val_t decimals) { + int d = (int)(int64_t)decimals; + if (d < 0) d = 0; + if (d > 15) d = 15; + double mul = pow(10.0, (double)d); + double v = el_to_float(f); + double r = (v >= 0.0 ? floor(v * mul + 0.5) : -floor(-v * mul + 0.5)) / mul; + return el_from_float(r); +} + +el_val_t str_to_float(el_val_t s) { + const char* str = EL_CSTR(s); + if (!str) return el_from_float(0.0); + return el_from_float(strtod(str, NULL)); +} + +/* ── Math (Float-aware) ──────────────────────────────────────────────────── */ + +el_val_t math_sqrt(el_val_t f) { return el_from_float(sqrt(el_to_float(f))); } +el_val_t math_log(el_val_t f) { return el_from_float(log(el_to_float(f))); } +el_val_t math_ln(el_val_t f) { return el_from_float(log(el_to_float(f))); } +el_val_t math_sin(el_val_t f) { return el_from_float(sin(el_to_float(f))); } +el_val_t math_cos(el_val_t f) { return el_from_float(cos(el_to_float(f))); } +el_val_t math_pi(void) { return el_from_float(3.141592653589793238462643383279502884); } + +/* ── String additions ────────────────────────────────────────────────────── */ + +el_val_t str_index_of(el_val_t s, el_val_t sub) { + const char* str = EL_CSTR(s); + const char* sb = EL_CSTR(sub); + if (!str || !sb) return -1; + const char* hit = strstr(str, sb); + if (!hit) return -1; + return (el_val_t)(int64_t)(hit - str); +} + +el_val_t str_split(el_val_t s, el_val_t sep) { + const char* str = EL_CSTR(s); + const char* sp = EL_CSTR(sep); + el_val_t lst = el_list_empty(); + if (!str) return lst; + if (!sp || !*sp) { + lst = el_list_append(lst, el_wrap_str(el_strdup(str))); + return lst; + } + size_t lp = strlen(sp); + const char* p = str; + const char* hit; + while ((hit = strstr(p, sp)) != NULL) { + size_t n = (size_t)(hit - p); + char* out = el_strbuf(n); + memcpy(out, p, n); + out[n] = '\0'; + lst = el_list_append(lst, el_wrap_str(out)); + p = hit + lp; + } + lst = el_list_append(lst, el_wrap_str(el_strdup(p))); + return lst; +} + +el_val_t str_char_at(el_val_t s, el_val_t i) { + const char* str = EL_CSTR(s); + int64_t idx = (int64_t)i; + if (!str) return el_wrap_str(el_strdup("")); + int64_t n = (int64_t)strlen(str); + if (idx < 0 || idx >= n) return el_wrap_str(el_strdup("")); + char buf[2]; + buf[0] = str[idx]; + buf[1] = '\0'; + return el_wrap_str(el_strdup(buf)); +} + +el_val_t str_char_code(el_val_t s, el_val_t i) { + const char* str = EL_CSTR(s); + int64_t idx = (int64_t)i; + if (!str) return 0; + int64_t n = (int64_t)strlen(str); + if (idx < 0 || idx >= n) return 0; + return (el_val_t)(unsigned char)str[idx]; +} + +static el_val_t str_pad(const char* s, int64_t width, const char* pad, int left) { + if (!s) s = ""; + if (!pad || !*pad) pad = " "; + int64_t lp = (int64_t)strlen(pad); + int64_t ls = (int64_t)strlen(s); + if (ls >= width) return el_wrap_str(el_strdup(s)); + int64_t need = width - ls; + char* out = el_strbuf((size_t)width); + if (left) { + for (int64_t i = 0; i < need; i++) out[i] = pad[i % lp]; + memcpy(out + need, s, (size_t)ls); + } else { + memcpy(out, s, (size_t)ls); + for (int64_t i = 0; i < need; i++) out[ls + i] = pad[i % lp]; + } + out[width] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_pad_left(el_val_t s, el_val_t width, el_val_t pad) { + return str_pad(EL_CSTR(s), (int64_t)width, EL_CSTR(pad), 1); +} + +el_val_t str_pad_right(el_val_t s, el_val_t width, el_val_t pad) { + return str_pad(EL_CSTR(s), (int64_t)width, EL_CSTR(pad), 0); +} + +el_val_t str_format(el_val_t fmt, el_val_t data) { + const char* tpl = EL_CSTR(fmt); + if (!tpl) return el_wrap_str(el_strdup("")); + JsonBuf b; jb_init(&b); + const char* p = tpl; + while (*p) { + if (*p == '{') { + const char* q = p + 1; + while (*q && *q != '}') q++; + if (*q == '}') { + size_t klen = (size_t)(q - p - 1); + char keybuf[256]; + if (klen < sizeof(keybuf)) { + memcpy(keybuf, p + 1, klen); + keybuf[klen] = '\0'; + el_val_t v = el_map_get(data, EL_STR(keybuf)); + if (v != 0 && looks_like_string(v)) { + jb_puts(&b, EL_CSTR(v)); + p = q + 1; + continue; + } else if (v != 0) { + jb_emit_int(&b, (int64_t)v); + p = q + 1; + continue; + } + } + /* Unknown key — leave {key} verbatim */ + jb_reserve(&b, klen + 2); + memcpy(b.buf + b.len, p, klen + 2); + b.len += klen + 2; + b.buf[b.len] = '\0'; + p = q + 1; + continue; + } + } + jb_putc(&b, *p); + p++; + } + return el_wrap_str(b.buf); +} + +el_val_t str_lower(el_val_t s) { return str_to_lower(s); } +el_val_t str_upper(el_val_t s) { return str_to_upper(s); } + +/* ── Text-processing primitives (Phase 1: byte/codepoint, ASCII char classes) + * + * Phase 1 covers the operations every text-handling caller used to roll by + * hand on top of str_index_of + str_slice. The character-class predicates + * (is_letter / is_digit / ...) are ASCII only — Unicode-grapheme awareness, + * NFC/NFD normalization, and regex are Phase 2. Single-char input checks the + * first byte; multi-char input requires ALL bytes to match (false otherwise). + * + * Counting: + * str_count non-overlapping occurrences of sub in s + * str_count_chars codepoint count (UTF-8 leading-byte count) + * str_count_bytes explicit byte length (alias of str_len) + * str_count_lines \n-delimited line count (\r\n folded to \n) + * str_count_words whitespace-delimited tokens, non-empty only + * str_count_letters ASCII [A-Za-z] + * str_count_digits ASCII [0-9] + * + * Find / position: + * str_index_of_all all byte offsets of sub, [] if none + * str_last_index_of last byte offset of sub, -1 if not found + * str_find_chars first index of any char in any_of, -1 if none + * + * Transform: + * str_repeat s * n (non-negative) + * str_reverse codepoint-reversed (NOT grapheme-aware) + * str_strip_prefix s without prefix if present, else s + * str_strip_suffix s without suffix if present, else s + * str_strip_chars strip leading+trailing chars matching any in chars + * str_lstrip strip leading whitespace + * str_rstrip strip trailing whitespace + * + * Char classification (Bool): + * is_letter, is_digit, is_alphanumeric, is_whitespace, + * is_punctuation, is_uppercase, is_lowercase + * + * Splitting: + * str_split_lines \n-delimited (\r\n folded). Trailing empty dropped. + * str_split_chars alias of native_string_chars in str_ namespace + * str_split_n split into at most n parts (last part keeps the + * rest verbatim, including any further separators) + * + * Joining: + * str_join [String] -> String, sep between elements + */ + +/* Count non-overlapping occurrences of sub in s. Empty sub returns 0. */ +el_val_t str_count(el_val_t sv, el_val_t subv) { + const char* s = EL_CSTR(sv); + const char* sub = EL_CSTR(subv); + if (!s || !sub || !*sub) return 0; + size_t lp = strlen(sub); + int64_t count = 0; + const char* p = s; + while ((p = strstr(p, sub)) != NULL) { + count++; + p += lp; /* non-overlapping advance */ + } + return (el_val_t)count; +} + +/* Codepoint count: walk bytes, count those NOT matching 10xxxxxx. */ +el_val_t str_count_chars(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + int64_t count = 0; + for (const unsigned char* p = (const unsigned char*)s; *p; p++) { + if ((*p & 0xC0) != 0x80) count++; + } + return (el_val_t)count; +} + +el_val_t str_count_bytes(el_val_t sv) { + return str_len(sv); +} + +el_val_t str_count_lines(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s || !*s) return 0; + int64_t count = 0; + int has_content = 0; + for (const char* p = s; *p; p++) { + has_content = 1; + if (*p == '\n') { + count++; + has_content = 0; /* the \n closed the line */ + } + } + if (has_content) count++; /* trailing line with no terminator */ + return (el_val_t)count; +} + +el_val_t str_count_words(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + int64_t count = 0; + int in_word = 0; + for (const unsigned char* p = (const unsigned char*)s; *p; p++) { + if (isspace(*p)) { + in_word = 0; + } else if (!in_word) { + in_word = 1; + count++; + } + } + return (el_val_t)count; +} + +el_val_t str_count_letters(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + int64_t count = 0; + for (const unsigned char* p = (const unsigned char*)s; *p; p++) { + if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z')) count++; + } + return (el_val_t)count; +} + +el_val_t str_count_digits(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + int64_t count = 0; + for (const unsigned char* p = (const unsigned char*)s; *p; p++) { + if (*p >= '0' && *p <= '9') count++; + } + return (el_val_t)count; +} + +el_val_t str_index_of_all(el_val_t sv, el_val_t subv) { + const char* s = EL_CSTR(sv); + const char* sub = EL_CSTR(subv); + el_val_t lst = el_list_empty(); + if (!s || !sub || !*sub) return lst; + size_t lp = strlen(sub); + const char* p = s; + const char* hit; + while ((hit = strstr(p, sub)) != NULL) { + lst = el_list_append(lst, (el_val_t)(int64_t)(hit - s)); + p = hit + lp; + } + return lst; +} + +el_val_t str_last_index_of(el_val_t sv, el_val_t subv) { + const char* s = EL_CSTR(sv); + const char* sub = EL_CSTR(subv); + if (!s || !sub || !*sub) return -1; + size_t lp = strlen(sub); + int64_t last = -1; + const char* p = s; + const char* hit; + while ((hit = strstr(p, sub)) != NULL) { + last = (int64_t)(hit - s); + p = hit + lp; + } + return (el_val_t)last; +} + +el_val_t str_find_chars(el_val_t sv, el_val_t any_of_v) { + const char* s = EL_CSTR(sv); + const char* any = EL_CSTR(any_of_v); + if (!s || !any || !*any) return -1; + for (const char* p = s; *p; p++) { + if (strchr(any, *p)) return (el_val_t)(int64_t)(p - s); + } + return -1; +} + +el_val_t str_repeat(el_val_t sv, el_val_t nv) { + const char* s = EL_CSTR(sv); + int64_t n = (int64_t)nv; + if (!s || n <= 0) return el_wrap_str(el_strdup("")); + size_t ls = strlen(s); + if (ls == 0) return el_wrap_str(el_strdup("")); + size_t total = ls * (size_t)n; + char* out = el_strbuf(total); + for (int64_t i = 0; i < n; i++) { + memcpy(out + i * ls, s, ls); + } + out[total] = '\0'; + return el_wrap_str(out); +} + +/* Reverse by codepoint: walk codepoints, copy each backwards into the output. + * NOT grapheme-aware (Phase 2). Combining marks attached to a base codepoint + * will detach. ASCII strings are byte-reverse equivalent. */ +el_val_t str_reverse(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + char* out = el_strbuf(n); + /* Walk forward, find each codepoint's byte length, then copy from the end. */ + size_t out_pos = n; + const unsigned char* p = (const unsigned char*)s; + while (*p) { + int cp_len; + if ((*p & 0x80) == 0x00) cp_len = 1; + else if ((*p & 0xE0) == 0xC0) cp_len = 2; + else if ((*p & 0xF0) == 0xE0) cp_len = 3; + else if ((*p & 0xF8) == 0xF0) cp_len = 4; + else cp_len = 1; /* invalid byte: passthrough */ + out_pos -= cp_len; + memcpy(out + out_pos, p, cp_len); + p += cp_len; + } + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_strip_prefix(el_val_t sv, el_val_t prefv) { + const char* s = EL_CSTR(sv); + const char* pref = EL_CSTR(prefv); + if (!s) return el_wrap_str(el_strdup("")); + if (!pref || !*pref) return el_wrap_str(el_strdup(s)); + size_t lp = strlen(pref); + size_t ls = strlen(s); + if (lp <= ls && strncmp(s, pref, lp) == 0) { + char* out = el_strbuf(ls - lp); + memcpy(out, s + lp, ls - lp); + out[ls - lp] = '\0'; + return el_wrap_str(out); + } + return el_wrap_str(el_strdup(s)); +} + +el_val_t str_strip_suffix(el_val_t sv, el_val_t sufv) { + const char* s = EL_CSTR(sv); + const char* suf = EL_CSTR(sufv); + if (!s) return el_wrap_str(el_strdup("")); + if (!suf || !*suf) return el_wrap_str(el_strdup(s)); + size_t ls = strlen(s); + size_t lsuf = strlen(suf); + if (lsuf <= ls && strcmp(s + ls - lsuf, suf) == 0) { + char* out = el_strbuf(ls - lsuf); + memcpy(out, s, ls - lsuf); + out[ls - lsuf] = '\0'; + return el_wrap_str(out); + } + return el_wrap_str(el_strdup(s)); +} + +el_val_t str_strip_chars(el_val_t sv, el_val_t charsv) { + const char* s = EL_CSTR(sv); + const char* chars = EL_CSTR(charsv); + if (!s) return el_wrap_str(el_strdup("")); + if (!chars || !*chars) return el_wrap_str(el_strdup(s)); + const char* start = s; + while (*start && strchr(chars, *start)) start++; + size_t n = strlen(start); + while (n > 0 && strchr(chars, start[n - 1])) n--; + char* out = el_strbuf(n); + memcpy(out, start, n); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_lstrip(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + while (*s && isspace((unsigned char)*s)) s++; + return el_wrap_str(el_strdup(s)); +} + +el_val_t str_rstrip(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + while (n > 0 && isspace((unsigned char)s[n - 1])) n--; + char* out = el_strbuf(n); + memcpy(out, s, n); + out[n] = '\0'; + return el_wrap_str(out); +} + +/* Character classification. + * Empty input returns false. Multi-char input requires ALL bytes to match. + * ASCII range only; Phase 2 will widen to Unicode. */ +static int s_all_match(el_val_t sv, int (*pred)(unsigned char)) { + const char* s = EL_CSTR(sv); + if (!s || !*s) return 0; + for (const unsigned char* p = (const unsigned char*)s; *p; p++) { + if (!pred(*p)) return 0; + } + return 1; +} + +static int p_letter(unsigned char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); } +static int p_digit(unsigned char c) { return c >= '0' && c <= '9'; } +static int p_alnum(unsigned char c) { return p_letter(c) || p_digit(c); } +static int p_white(unsigned char c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'; } +static int p_punct(unsigned char c) { return ispunct(c) ? 1 : 0; } +static int p_upper(unsigned char c) { return c >= 'A' && c <= 'Z'; } +static int p_lower(unsigned char c) { return c >= 'a' && c <= 'z'; } + +el_val_t is_letter(el_val_t s) { return (el_val_t)s_all_match(s, p_letter); } +el_val_t is_digit(el_val_t s) { return (el_val_t)s_all_match(s, p_digit); } +el_val_t is_alphanumeric(el_val_t s) { return (el_val_t)s_all_match(s, p_alnum); } +el_val_t is_whitespace(el_val_t s) { return (el_val_t)s_all_match(s, p_white); } +el_val_t is_punctuation(el_val_t s) { return (el_val_t)s_all_match(s, p_punct); } +el_val_t is_uppercase(el_val_t s) { return (el_val_t)s_all_match(s, p_upper); } +el_val_t is_lowercase(el_val_t s) { return (el_val_t)s_all_match(s, p_lower); } + +/* Split on \n. \r\n is folded to \n first. Trailing empty after final \n + * is dropped (so "a\nb\n" -> ["a", "b"], not ["a", "b", ""]). */ +el_val_t str_split_lines(el_val_t sv) { + const char* s = EL_CSTR(sv); + el_val_t lst = el_list_empty(); + if (!s) return lst; + size_t n = strlen(s); + /* Pre-scan: build into a normalized buffer with \r\n folded. */ + const char* line_start = s; + for (size_t i = 0; i <= n; i++) { + if (s[i] == '\n' || s[i] == '\0') { + size_t len = (size_t)(s + i - line_start); + /* Drop trailing \r if this was \r\n. */ + if (len > 0 && line_start[len - 1] == '\r') len--; + /* Drop final trailing-empty-after-newline. */ + if (s[i] == '\0' && len == 0 && i > 0 && s[i - 1] == '\n') break; + char* out = el_strbuf(len); + memcpy(out, line_start, len); + out[len] = '\0'; + lst = el_list_append(lst, el_wrap_str(out)); + if (s[i] == '\0') break; + line_start = s + i + 1; + } + } + return lst; +} + +el_val_t str_split_chars(el_val_t s) { + return native_string_chars(s); +} + +/* Split into at most n parts. The (n-1)th split point is the LAST split; + * after it, the remainder is appended verbatim including any further + * separators. n <= 0 returns an empty list. n == 1 returns [s]. */ +el_val_t str_split_n(el_val_t sv, el_val_t sepv, el_val_t nv) { + const char* s = EL_CSTR(sv); + const char* sep = EL_CSTR(sepv); + int64_t n = (int64_t)nv; + el_val_t lst = el_list_empty(); + if (!s) return lst; + if (n <= 0) return lst; + if (n == 1 || !sep || !*sep) { + lst = el_list_append(lst, el_wrap_str(el_strdup(s))); + return lst; + } + size_t lp = strlen(sep); + const char* p = s; + int64_t parts = 0; + const char* hit; + while (parts < n - 1 && (hit = strstr(p, sep)) != NULL) { + size_t len = (size_t)(hit - p); + char* out = el_strbuf(len); + memcpy(out, p, len); + out[len] = '\0'; + lst = el_list_append(lst, el_wrap_str(out)); + p = hit + lp; + parts++; + } + /* Remainder verbatim. */ + lst = el_list_append(lst, el_wrap_str(el_strdup(p))); + return lst; +} + +/* Join a [String] with a separator. Empty list -> "". Single-element -> + * that element. Non-string elements are stringified via int_to_str. */ +el_val_t str_join(el_val_t listv, el_val_t sepv) { + return list_join(listv, sepv); +} + +/* ── List additions ──────────────────────────────────────────────────────── */ + +el_val_t list_push(el_val_t list, el_val_t elem) { + return el_list_append(list, elem); +} + +el_val_t list_push_front(el_val_t listv, el_val_t elem) { + ElList* lst = (ElList*)(uintptr_t)listv; + if (!lst) { + el_val_t nl = el_list_empty(); + return el_list_append(nl, elem); + } + /* Append to grow capacity, then shift right */ + listv = el_list_append(listv, elem); + lst = (ElList*)(uintptr_t)listv; + for (int64_t i = lst->length - 1; i > 0; i--) { + lst->elems[i] = lst->elems[i - 1]; + } + lst->elems[0] = elem; + return EL_STR(lst); +} + +el_val_t list_join(el_val_t listv, el_val_t sep) { + ElList* lst = (ElList*)(uintptr_t)listv; + const char* sp = EL_CSTR(sep); + if (!sp) sp = ""; + if (!lst || lst->length == 0) return el_wrap_str(el_strdup("")); + JsonBuf b; jb_init(&b); + for (int64_t i = 0; i < lst->length; i++) { + if (i > 0) jb_puts(&b, sp); + el_val_t v = lst->elems[i]; + if (v == 0) continue; + if (looks_like_string(v)) { + jb_puts(&b, EL_CSTR(v)); + } else { + char tmp[32]; + snprintf(tmp, sizeof(tmp), "%lld", (long long)v); + jb_puts(&b, tmp); + } + } + return el_wrap_str(b.buf); +} + +el_val_t list_range(el_val_t start, el_val_t end) { + int64_t a = (int64_t)start; + int64_t b = (int64_t)end; + el_val_t lst = el_list_empty(); + for (int64_t i = a; i < b; i++) lst = el_list_append(lst, (el_val_t)i); + return lst; +} + +/* ── Bool helpers ────────────────────────────────────────────────────────── */ + +el_val_t bool_to_str(el_val_t b) { + return el_wrap_str(el_strdup(b ? "true" : "false")); +} + +/* ── Numeric parsing ─────────────────────────────────────────────────────── */ + +/* parse_int — strtoll with a default. str_to_int already exists but does not + * distinguish "0" from a parse failure, so callers that need a sentinel use + * this. Skips leading whitespace; accepts an optional leading +/-; returns + * default_val on empty input or no consumed digits. Trailing junk is ignored + * (atoi-style). */ +el_val_t parse_int(el_val_t sv, el_val_t default_val) { + const char* s = EL_CSTR(sv); + if (!s) return default_val; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == '\0') return default_val; + char* end = NULL; + long long n = strtoll(s, &end, 10); + if (end == s) return default_val; + return (el_val_t)n; +} + +/* ── Process ─────────────────────────────────────────────────────────────── */ + +el_val_t exit_program(el_val_t code) { + exit((int)code); + return 0; /* unreachable */ +} + +/* getpid_now — current process id. Named with the _now suffix to avoid + * colliding with the libc `getpid` declaration that the runtime already + * sees via (calling it `getpid` would fight the prototype). */ +el_val_t getpid_now(void) { + return (el_val_t)getpid(); +} + +/* el_mem_check — self-terminating memory guard for long-running compiler runs. + * + * Call this periodically (e.g. after each function compiled) to detect runaway + * memory growth before the OS OOM-killer fires. Reads the limit from the env + * var ELC_MAX_MEM_MB (default 512 MB). If resident set size exceeds the limit, + * prints a diagnostic to stderr and exits with code 1 so the caller (elb or a + * CI script) can handle the failure gracefully instead of having the whole + * machine go down. + * + * Platform notes: + * macOS — ru_maxrss is in bytes. + * Linux — ru_maxrss is in kilobytes. + * We normalise to MB before comparing. + * + * Returns 0 always (the only non-return path is the exit() branch). + */ +el_val_t el_mem_check(void) { + /* Read limit from env; default 512 MB. */ + long limit_mb = 512; + const char *env_val = getenv("ELC_MAX_MEM_MB"); + if (env_val && *env_val) { + long v = atol(env_val); + if (v > 0) limit_mb = v; + } + + struct rusage ru; + if (getrusage(RUSAGE_SELF, &ru) != 0) return 0; /* can't read — skip check */ + + long rss_mb; +#if defined(__APPLE__) || defined(__MACH__) + /* macOS: ru_maxrss is bytes */ + rss_mb = (long)(ru.ru_maxrss / (1024L * 1024L)); +#else + /* Linux: ru_maxrss is kilobytes */ + rss_mb = (long)(ru.ru_maxrss / 1024L); +#endif + + if (rss_mb >= limit_mb) { + fprintf(stderr, "elc: memory limit exceeded (%ldMB), aborting\n", limit_mb); + exit(1); + } + return 0; +} + +/* ── args() — command-line argument access ────────────────────────────────── + * Compiled El programs call args() to get a list of CLI arguments. + * Call el_runtime_init_args(argc, argv) at the start of C main() to populate. + * The args list excludes argv[0] (the program name). */ + +static el_val_t _el_args_list = 0; + +void el_runtime_init_args(int argc, char** argv) { + _el_args_list = el_list_empty(); + for (int i = 1; i < argc; i++) { + _el_args_list = el_list_append(_el_args_list, EL_STR(argv[i])); + } +} + +el_val_t args(void) { + if (!_el_args_list) _el_args_list = el_list_empty(); + return _el_args_list; +} + +/* ── CGI identity ──────────────────────────────────────────────────────────── + * Called once at program start by the generated main() of a cgi {} program. + * Stores CGI identity so dharma_* builtins can reference it. */ + +static const char* _el_cgi_name = NULL; +static const char* _el_cgi_dharma_id = NULL; +static const char* _el_cgi_principal = NULL; +static const char* _el_cgi_network = NULL; +static const char* _el_cgi_engram = NULL; + +void el_cgi_init(el_val_t name, el_val_t dharma_id, el_val_t principal, + el_val_t network, el_val_t engram) { + _el_cgi_name = EL_CSTR(name); + _el_cgi_dharma_id = EL_CSTR(dharma_id); + _el_cgi_principal = EL_CSTR(principal); + _el_cgi_network = EL_CSTR(network) ? EL_CSTR(network) : "dharma-mainnet"; + _el_cgi_engram = EL_CSTR(engram) ? EL_CSTR(engram) : "http://localhost:8742"; + printf("[cgi] identity: name=%s dharma_id=%s principal=%s network=%s engram=%s\n", + _el_cgi_name ? _el_cgi_name : "(unset)", + _el_cgi_dharma_id ? _el_cgi_dharma_id : "(unset)", + _el_cgi_principal ? _el_cgi_principal : "(unset)", + _el_cgi_network, + _el_cgi_engram); +} + + +/* ── Batch 3: Engram in-process graph store ──────────────────────────────── */ +/* + * Single global EngramStore allocated lazily on first call. All node and + * edge content strings are owned (strdup'd) by the store. Linear arrays + * with doubling capacity for both nodes and edges. + * + * Two-layer activation algorithm (engram_activate): + * + * LAYER 1 — Broad fan-out (background activation): + * 1. Find seed nodes whose content/label/tags contain query (case-insens). + * 2. BFS up to `depth` hops along ALL edges (excitatory and inhibitory). + * Every reachable node fires — nothing is filtered at this layer. + * 3. bg_act = seed.salience * temporal_decay * dampening + * propagated as: new_bg = parent_bg * edge_weight * 0.7 * (1 + tbonus) + * where tbonus ∈ {0, 0.10, 0.20} for co-temporal nodes. + * 4. If reached by multiple paths, take max background_activation. + * 5. Persist background_activation to EngramNode.background_activation. + * + * LAYER 2 — Executive filter (working memory promotion): + * 6. For each inhibitory edge where source has background_activation > 0: + * inhibition[target] = max(bg[source] * e->weight) + * 7. For each background-activated node: + * raw_wm = bg * goal_bias(node, query) * confidence + * * (1 - (1 - INHIBITION_FACTOR) * inhibition) + * 8. Per-type threshold gate: raw_wm >= type_threshold → promoted. + * Safety/DharmaSelf: 0.05 Canonical: 0.15 Lesson: 0.25 + * Belief/Entity: 0.30 Note/Memory/Working: 0.40 + * 9. If not promoted: suppression_count++. After + * ENGRAM_SUPPRESSION_BREAKTHROUGH suppressions → force breakthrough + * at ENGRAM_BREAKTHROUGH_WEIGHT (latent tension surfacing). + * 10. Persist working_memory_weight to EngramNode.working_memory_weight. + * 11. Sort: promoted nodes (wm > 0) first by wm desc, then background- + * only by bg desc. Context compilation uses ONLY promoted nodes. + * + * Temporal decay: + * decay_factor = exp(-lambda * age_hours / T_half) + * T_half = 168.0 h (one week), lambda = ln(2) + * + * Activation dampening: + * dampen = 1.0 / (1.0 + log(1 + activation_count)) + * + * engram_query_range(start_ms, end_ms): + * Returns nodes whose created_at OR last_activated falls within + * [start_ms, end_ms], sorted by created_at ascending. + */ + +/* Temporal decay constants. + * T_HALF_HOURS: half-life in hours — one week. After one week of no + * activation a node retains 50% of its base salience contribution. + * DECAY_LAMBDA: ln(2) ≈ 0.693147 */ +#define ENGRAM_T_HALF_HOURS 168.0 +#define ENGRAM_DECAY_LAMBDA 0.693147 + +/* Two-layer activation constants. + * ENGRAM_WM_THRESHOLD: minimum background_activation for a node to be + * considered for working-memory promotion (layer 2 candidate gate). + * ENGRAM_WM_DECAY: per-turn decay applied to working_memory_weight for + * nodes NOT re-activated in the current turn (conversational thread + * continuity: a node promoted in turn N persists with reduced weight + * into turn N+1 without re-activation cost). + * ENGRAM_SUPPRESSION_BREAKTHROUGH: after this many consecutive suppressions + * a latent node forces itself into working memory at reduced weight, + * modelling the brain's "intrusive thought" / unresolved-tension surfacing. + * ENGRAM_BREAKTHROUGH_WEIGHT: the reduced working_memory_weight assigned + * when a suppressed node breaks through. + * ENGRAM_INHIBITION_FACTOR: multiplier applied to working_memory_weight when + * an inhibitory edge fires against a node (0 = full suppress, 0.3 = partial). */ +#define ENGRAM_WM_THRESHOLD 0.15 +#define ENGRAM_WM_DECAY 0.7 +#define ENGRAM_SUPPRESSION_BREAKTHROUGH 5 +#define ENGRAM_BREAKTHROUGH_WEIGHT 0.25 +#define ENGRAM_INHIBITION_FACTOR 0.1 + +/* ── Layered consciousness architecture ────────────────────────────────────── + * + * The engram graph is stratified into LAYERS that gate which suppressions + * apply during the executive filter pass. Layers are ordered shallow-to-deep + * by `activation_priority`; the deepest layer (priority 0, conventionally + * "safety") is the structural floor of the soul: nodes here cannot be + * silenced by inhibitory edges from any other layer. Higher layers + * (core-identity, domain-knowledge, imprint, suit) are normally + * suppressible — they participate in attentional inhibition and goal + * focus the way the prior single-graph implementation did. + * + * The five canonical layers (see engram_init_layers): + * 0. safety — structural, transparent, non-injectable, non-suppressible + * 1. core-identity — default for legacy nodes; suppressible + * 2. domain-knowledge— suppressible + * 3. imprint — runtime-injectable (an Imprint package can add/remove) + * 4. suit — runtime-injectable (a Suit overlays domain skill) + * + * Three-pass activation (engram_activate): + * Pass 1 — Background fan-out: BFS spreads activation across ALL layers + * (existing behavior preserved). Inhibitory edges propagate at + * this layer too; no filtering happens here. + * Pass 2 — Working memory promotion: type-threshold gate, goal bias, + * confidence weighting, inhibitory suppression. Inhibitory edges + * ONLY apply against nodes whose layer is `suppressible == 1`. + * Nodes in non-suppressible layers (Layer 0) ignore inhibition. + * Pass 3 — Layer 0 override: every node in a non-suppressible layer that + * received background activation has its working_memory_weight + * forced to >= ENGRAM_LAYER0_OVERRIDE_WEIGHT. The sacred fire — + * safety nodes that touched any seed unconditionally surface, + * even when the executive filter would have silenced them. + * + * Layer fields: + * suppressible : 0 → inhibitory edges are ignored against nodes in this + * layer during pass 2. Pass 3 also force-promotes them. + * 1 → standard behavior (most layers). + * transparent : 1 → emitted into the prompt context so its content shapes + * output, but filtered out of "what do you know about + * yourself?" introspection queries (engram_search and + * friends do not return transparent-layer nodes by + * default). 0 → fully visible to introspection. + * injectable : 1 → can be added/removed at runtime via engram_add_layer + * and engram_remove_layer (imprints, suits). + * 0 → built-in, fixed at engram_get() initialization. + * + * Backward compatibility: + * Nodes and edges loaded from snapshots without a `layer_id` field default + * to layer 1 (core-identity). The five canonical layers are always present. + */ +#define ENGRAM_LAYER_SAFETY 0u +#define ENGRAM_LAYER_CORE_IDENTITY 1u +#define ENGRAM_LAYER_DOMAIN 2u +#define ENGRAM_LAYER_IMPRINT 3u +#define ENGRAM_LAYER_SUIT 4u +#define ENGRAM_LAYER_DEFAULT ENGRAM_LAYER_CORE_IDENTITY + +/* Pass 3 override floor. Layer 0 nodes that received any background + * activation are force-promoted to AT LEAST this working_memory_weight, + * regardless of inhibitory suppression in pass 2. */ +#define ENGRAM_LAYER0_OVERRIDE_WEIGHT 1.0 + +/* Per-node-type activation thresholds. + * Lower tier / safety-critical nodes fire more readily. */ +static double engram_type_threshold(const char* node_type, const char* tier) { + if (node_type) { + if (strcmp(node_type, "DharmaSelf") == 0) return 0.05; + if (strcmp(node_type, "Safety") == 0) return 0.05; + } + if (tier) { + if (strcmp(tier, "Canonical") == 0) return 0.15; + if (strcmp(tier, "Lesson") == 0) return 0.25; + } + if (node_type) { + if (strcmp(node_type, "Belief") == 0) return 0.30; + if (strcmp(node_type, "Entity") == 0) return 0.30; + } + return 0.40; /* Note / Memory / Working (most nodes) */ +} + +typedef struct EngramNode { + char* id; + char* content; + char* node_type; + char* label; + char* tier; + char* tags; + char* metadata; + double salience; + double importance; + double confidence; + double temporal_decay_rate; /* per-node override for lambda; 0 = use default */ + int64_t activation_count; + int64_t last_activated; + int64_t created_at; + int64_t updated_at; + /* Two-layer activation fields ───────────────────────────────────────── + * background_activation: Layer 1. Set by BFS fan-out on every query. + * Every reachable node fires here — nothing is filtered at this stage. + * Models the brain's massive parallel sub-threshold activation of all + * associated content in response to a stimulus. + * working_memory_weight: Layer 2. Executive filter output. Only nodes + * that survive goal-state / attentional-bias scoring receive a + * non-zero weight here. Context compilation ONLY uses this field. + * Background-activated nodes with working_memory_weight == 0 remain + * latent — real, available, but silent. + * suppression_count: Consecutive turn count where this node was + * background-activated but NOT promoted to working memory. High + * values signal the node "wants to surface." After + * ENGRAM_SUPPRESSION_BREAKTHROUGH consecutive suppressions the node + * is force-promoted at a reduced weight (breakthrough activation). */ + double background_activation; + double working_memory_weight; + int32_t suppression_count; + /* Layered consciousness — see ENGRAM_LAYER_* macros and engram_init_layers. + * Defaults to ENGRAM_LAYER_DEFAULT (1, core-identity) for legacy nodes + * created via engram_node / engram_node_full and for snapshots that + * predate the layered schema. */ + uint32_t layer_id; +} EngramNode; + +typedef struct EngramEdge { + char* id; + char* from_id; + char* to_id; + char* relation; + char* metadata; + double weight; + double confidence; + int64_t created_at; + int64_t updated_at; + int64_t last_fired; + /* Inhibitory flag: when 1, activating the source node SUPPRESSES the + * working_memory_weight of the target node rather than exciting it. + * Models attentional inhibition: "I am focused on code work" creates + * inhibitory edges to personal/emotional nodes, preventing them from + * surfacing even if they have high background_activation. */ + int inhibitory; + /* Layered consciousness — edges carry a layer assignment for + * categorization/visualization. Pass 2 inhibitory gating is decided by + * the TARGET node's layer (whether it's suppressible), not by the edge + * layer. Defaults to ENGRAM_LAYER_DEFAULT. */ + uint32_t layer_id; +} EngramEdge; + +/* Layered consciousness — runtime layer registry entry. */ +typedef struct EngramLayer { + uint32_t layer_id; /* 0 = deepest (safety/limbic) */ + char* name; /* persistent — owned by the store */ + uint32_t activation_priority; /* lower = fires earlier; safety = 0 */ + int suppressible; /* can higher layers suppress nodes here? */ + int transparent; /* invisible to introspection queries? */ + int injectable; /* can be added/removed at runtime? */ +} EngramLayer; + +typedef struct EngramStore { + EngramNode* nodes; + int64_t node_count; + int64_t node_capacity; + EngramEdge* edges; + int64_t edge_count; + int64_t edge_capacity; + /* Layer registry — see engram_init_layers. The five canonical layers + * are always present; injectable layers (imprint, suit) are extended + * via engram_add_layer at runtime. layer_id values are assigned + * monotonically; removed injectable layers leave a NULL `name` slot + * (tombstone) so existing layer_id references on nodes stay stable. */ + EngramLayer* layers; + size_t layer_count; + size_t layer_capacity; +} EngramStore; + +static EngramStore* engram_global = NULL; + +/* Initialize the five canonical layers on a fresh store. Called once from + * engram_get(). Layer ids 0..4 are reserved; runtime-injected imprint/suit + * layers (engram_add_layer) get ids 5+. */ +static void engram_init_layers(EngramStore* g) { + g->layer_capacity = 16; + g->layers = calloc(g->layer_capacity, sizeof(EngramLayer)); + if (!g->layers) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + g->layer_count = 0; + + /* Layer 0 — safety. Structural floor. Non-suppressible; transparent + * (filtered out of introspection but still shapes output); not + * runtime-injectable. */ + g->layers[g->layer_count++] = (EngramLayer){ + .layer_id = ENGRAM_LAYER_SAFETY, + .name = el_strdup_persist("safety"), + .activation_priority = 0, + .suppressible = 0, + .transparent = 1, + .injectable = 0 + }; + /* Layer 1 — core-identity. The default home for legacy nodes. */ + g->layers[g->layer_count++] = (EngramLayer){ + .layer_id = ENGRAM_LAYER_CORE_IDENTITY, + .name = el_strdup_persist("core-identity"), + .activation_priority = 10, + .suppressible = 1, + .transparent = 0, + .injectable = 0 + }; + /* Layer 2 — domain-knowledge. */ + g->layers[g->layer_count++] = (EngramLayer){ + .layer_id = ENGRAM_LAYER_DOMAIN, + .name = el_strdup_persist("domain-knowledge"), + .activation_priority = 20, + .suppressible = 1, + .transparent = 0, + .injectable = 0 + }; + /* Layer 3 — imprint. Injectable: an imprint package adds/removes this + * layer (and the nodes assigned to it) as a unit. */ + g->layers[g->layer_count++] = (EngramLayer){ + .layer_id = ENGRAM_LAYER_IMPRINT, + .name = el_strdup_persist("imprint"), + .activation_priority = 30, + .suppressible = 1, + .transparent = 0, + .injectable = 1 + }; + /* Layer 4 — suit. Injectable: a Suit overlays domain skill (e.g. + * "enterprise advisor", "divorce lawyer") and can be detached. */ + g->layers[g->layer_count++] = (EngramLayer){ + .layer_id = ENGRAM_LAYER_SUIT, + .name = el_strdup_persist("suit"), + .activation_priority = 40, + .suppressible = 1, + .transparent = 0, + .injectable = 1 + }; +} + +static EngramStore* engram_get(void) { + if (engram_global) return engram_global; + engram_global = calloc(1, sizeof(EngramStore)); + if (!engram_global) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + engram_global->node_capacity = 16; + engram_global->nodes = calloc((size_t)engram_global->node_capacity, sizeof(EngramNode)); + engram_global->edge_capacity = 16; + engram_global->edges = calloc((size_t)engram_global->edge_capacity, sizeof(EngramEdge)); + engram_init_layers(engram_global); + return engram_global; +} + +/* Resolve a layer record by id. Returns NULL if no layer with that id + * exists (e.g. a removed injectable layer or a malformed snapshot). */ +static EngramLayer* engram_find_layer(uint32_t layer_id) { + EngramStore* g = engram_get(); + for (size_t i = 0; i < g->layer_count; i++) { + EngramLayer* L = &g->layers[i]; + if (!L->name) continue; /* tombstone for removed injectable layer */ + if (L->layer_id == layer_id) return L; + } + return NULL; +} + +/* Resolve a layer record by name. Returns NULL if not found. */ +static EngramLayer* engram_find_layer_by_name(const char* name) { + if (!name || !*name) return NULL; + EngramStore* g = engram_get(); + for (size_t i = 0; i < g->layer_count; i++) { + EngramLayer* L = &g->layers[i]; + if (!L->name) continue; + if (strcmp(L->name, name) == 0) return L; + } + return NULL; +} + +/* Allocate the next layer id. Skips ids that are still in use. */ +static uint32_t engram_next_layer_id(void) { + EngramStore* g = engram_get(); + uint32_t maxid = 0; + for (size_t i = 0; i < g->layer_count; i++) { + if (g->layers[i].layer_id > maxid) maxid = g->layers[i].layer_id; + } + return maxid + 1; +} + +/* Whether a node in `layer_id` may be silenced by inhibitory edges in pass 2. */ +static int engram_layer_is_suppressible(uint32_t layer_id) { + EngramLayer* L = engram_find_layer(layer_id); + if (!L) return 1; /* unknown layer → safe default: standard suppression */ + return L->suppressible ? 1 : 0; +} + +/* Whether a layer is transparent (its content shapes output but is filtered + * from introspection queries). Currently used to mark Layer 0 as invisible + * to "what do you know about yourself" lookups while still letting it + * dominate the prompt context. */ +static int engram_layer_is_transparent(uint32_t layer_id) { + EngramLayer* L = engram_find_layer(layer_id); + if (!L) return 0; + return L->transparent ? 1 : 0; +} + +static int64_t engram_now_ms(void) { + struct timeval tv; gettimeofday(&tv, NULL); + return (int64_t)tv.tv_sec * 1000LL + (int64_t)tv.tv_usec / 1000LL; +} + +static EngramNode* engram_find_node(const char* id) { + if (!id) return NULL; + EngramStore* g = engram_get(); + for (int64_t i = 0; i < g->node_count; i++) { + if (g->nodes[i].id && strcmp(g->nodes[i].id, id) == 0) return &g->nodes[i]; + } + return NULL; +} + +static int64_t engram_find_node_index(const char* id) { + if (!id) return -1; + EngramStore* g = engram_get(); + for (int64_t i = 0; i < g->node_count; i++) { + if (g->nodes[i].id && strcmp(g->nodes[i].id, id) == 0) return i; + } + return -1; +} + +static void engram_grow_nodes(void) { + EngramStore* g = engram_get(); + if (g->node_count < g->node_capacity) return; + int64_t nc = g->node_capacity * 2; + g->nodes = realloc(g->nodes, (size_t)nc * sizeof(EngramNode)); + if (!g->nodes) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + memset(g->nodes + g->node_capacity, 0, + (size_t)(nc - g->node_capacity) * sizeof(EngramNode)); + g->node_capacity = nc; +} + +static void engram_grow_edges(void) { + EngramStore* g = engram_get(); + if (g->edge_count < g->edge_capacity) return; + int64_t nc = g->edge_capacity * 2; + g->edges = realloc(g->edges, (size_t)nc * sizeof(EngramEdge)); + if (!g->edges) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + memset(g->edges + g->edge_capacity, 0, + (size_t)(nc - g->edge_capacity) * sizeof(EngramEdge)); + g->edge_capacity = nc; +} + +/* Build a fresh UUID string. Reuses uuid_new but takes the underlying char*. */ +static char* engram_new_id(void) { + el_val_t v = uuid_new(); + const char* s = EL_CSTR(v); + return el_strdup(s ? s : ""); +} + +/* Convert a node into an ElMap of its fields. */ +static el_val_t engram_node_to_map(const EngramNode* n) { + el_val_t m = el_map_new(0); + m = el_map_set(m, EL_STR(el_strdup("id")), EL_STR(el_strdup(n->id ? n->id : ""))); + m = el_map_set(m, EL_STR(el_strdup("content")), EL_STR(el_strdup(n->content ? n->content : ""))); + m = el_map_set(m, EL_STR(el_strdup("node_type")), EL_STR(el_strdup(n->node_type ? n->node_type : ""))); + m = el_map_set(m, EL_STR(el_strdup("label")), EL_STR(el_strdup(n->label ? n->label : ""))); + m = el_map_set(m, EL_STR(el_strdup("tier")), EL_STR(el_strdup(n->tier ? n->tier : "Working"))); + m = el_map_set(m, EL_STR(el_strdup("tags")), EL_STR(el_strdup(n->tags ? n->tags : ""))); + m = el_map_set(m, EL_STR(el_strdup("metadata")), EL_STR(el_strdup(n->metadata ? n->metadata : "{}"))); + m = el_map_set(m, EL_STR(el_strdup("salience")), el_from_float(n->salience)); + m = el_map_set(m, EL_STR(el_strdup("importance")), el_from_float(n->importance)); + m = el_map_set(m, EL_STR(el_strdup("confidence")), el_from_float(n->confidence)); + m = el_map_set(m, EL_STR(el_strdup("temporal_decay_rate")), el_from_float(n->temporal_decay_rate)); + m = el_map_set(m, EL_STR(el_strdup("activation_count")), (el_val_t)n->activation_count); + m = el_map_set(m, EL_STR(el_strdup("last_activated")), (el_val_t)n->last_activated); + m = el_map_set(m, EL_STR(el_strdup("created_at")), (el_val_t)n->created_at); + m = el_map_set(m, EL_STR(el_strdup("updated_at")), (el_val_t)n->updated_at); + m = el_map_set(m, EL_STR(el_strdup("background_activation")), el_from_float(n->background_activation)); + m = el_map_set(m, EL_STR(el_strdup("working_memory_weight")), el_from_float(n->working_memory_weight)); + m = el_map_set(m, EL_STR(el_strdup("suppression_count")), (el_val_t)n->suppression_count); + m = el_map_set(m, EL_STR(el_strdup("layer_id")), (el_val_t)(int64_t)n->layer_id); + return m; +} + +/* (Node JSON serialization is provided by `engram_emit_node_json` further + * down in the persistence section — reused by the *_json builtins below.) */ +static void engram_emit_node_json(JsonBuf* b, const EngramNode* n); +static void engram_emit_edge_json(JsonBuf* b, const EngramEdge* e); + +/* Salience may arrive either as a float bit-pattern or as a small integer + * (e.g. 1, meaning 1.0). Heuristic: if interpreted as double it's in + * [0.0, 100.0] use it; otherwise treat as int and convert. */ +static double engram_decode_score(el_val_t v) { + double f = el_to_float(v); + if (!isnan(f) && !isinf(f) && f >= 0.0 && f <= 100.0) return f; + int64_t n = (int64_t)v; + return (double)n; +} + +static char* engram_first_n_chars(const char* s, size_t n) { + if (!s) return el_strdup(""); + size_t l = strlen(s); + if (l > n) l = n; + char* out = el_strbuf(l); + memcpy(out, s, l); + out[l] = '\0'; + return out; +} + +el_val_t engram_node(el_val_t content, el_val_t node_type, el_val_t salience) { + EngramStore* g = engram_get(); + engram_grow_nodes(); + EngramNode* n = &g->nodes[g->node_count]; + memset(n, 0, sizeof(*n)); + n->id = engram_new_id(); + const char* c = EL_CSTR(content); + const char* nt = EL_CSTR(node_type); + n->content = el_strdup(c ? c : ""); + n->node_type = el_strdup(nt && *nt ? nt : "Memory"); + n->label = engram_first_n_chars(c, 60); + n->tier = el_strdup("Working"); + n->tags = el_strdup(""); + n->metadata = el_strdup("{}"); + n->salience = engram_decode_score(salience); + if (n->salience <= 0.0 || n->salience > 1.0) n->salience = 0.5; + n->importance = 0.5; + n->confidence = 1.0; + n->temporal_decay_rate = 0.0; /* 0 = use global default ENGRAM_DECAY_LAMBDA */ + n->activation_count = 0; + int64_t now = engram_now_ms(); + n->last_activated = now; + n->created_at = now; + n->updated_at = now; + n->layer_id = ENGRAM_LAYER_DEFAULT; + g->node_count++; + return el_wrap_str(el_strdup(n->id)); +} + +el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags) { + EngramStore* g = engram_get(); + engram_grow_nodes(); + EngramNode* n = &g->nodes[g->node_count]; + memset(n, 0, sizeof(*n)); + n->id = engram_new_id(); + const char* c = EL_CSTR(content); + const char* nt = EL_CSTR(node_type); + const char* lb = EL_CSTR(label); + const char* ti = EL_CSTR(tier); + const char* tg = EL_CSTR(tags); + n->content = el_strdup(c ? c : ""); + n->node_type = el_strdup(nt && *nt ? nt : "Memory"); + n->label = el_strdup(lb && *lb ? lb : (c ? engram_first_n_chars(c, 60) : "")); + n->tier = el_strdup(ti && *ti ? ti : "Working"); + n->tags = el_strdup(tg ? tg : ""); + n->metadata = el_strdup("{}"); + n->salience = engram_decode_score(salience); + n->importance = engram_decode_score(importance); + n->confidence = engram_decode_score(confidence); + if (n->salience <= 0.0 || n->salience > 1.0) n->salience = 0.5; + if (n->importance <= 0.0 || n->importance > 1.0) n->importance = 0.5; + if (n->confidence <= 0.0 || n->confidence > 1.0) n->confidence = 1.0; + n->temporal_decay_rate = 0.0; /* 0 = use global default ENGRAM_DECAY_LAMBDA */ + n->activation_count = 0; + int64_t now = engram_now_ms(); + n->last_activated = now; + n->created_at = now; + n->updated_at = now; + n->layer_id = ENGRAM_LAYER_DEFAULT; + g->node_count++; + return el_wrap_str(el_strdup(n->id)); +} + +/* engram_node_layered — like engram_node_full but with explicit layer + * assignment and an additional `status` slot reserved for callers that + * track lifecycle state in metadata. The signature mirrors the public API + * defined in the layered consciousness design doc: + * + * engram_node_layered(content, node_type, label, + * salience, certainty, confidence, + * status, tags, layer_id) + * + * `certainty` is folded into `importance` (it occupies the same axis in + * the existing schema). `status` is recorded under metadata.status; an + * empty status leaves metadata as the default "{}". + * + * If `layer_id` does not resolve to a known layer the call falls back to + * ENGRAM_LAYER_DEFAULT — better to keep the node addressable than to drop + * it because of a stale layer reference. Callers wanting strict validation + * should engram_list_layers first. */ +el_val_t engram_node_layered(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t certainty, el_val_t confidence, + el_val_t status, el_val_t tags, el_val_t layer_id) { + EngramStore* g = engram_get(); + engram_grow_nodes(); + EngramNode* n = &g->nodes[g->node_count]; + memset(n, 0, sizeof(*n)); + n->id = engram_new_id(); + const char* c = EL_CSTR(content); + const char* nt = EL_CSTR(node_type); + const char* lb = EL_CSTR(label); + const char* tg = EL_CSTR(tags); + const char* st = EL_CSTR(status); + n->content = el_strdup(c ? c : ""); + n->node_type = el_strdup(nt && *nt ? nt : "Memory"); + n->label = el_strdup(lb && *lb ? lb : (c ? engram_first_n_chars(c, 60) : "")); + n->tier = el_strdup("Working"); + n->tags = el_strdup(tg ? tg : ""); + if (st && *st) { + /* Minimal metadata payload: {"status":"..."}. Keep it cheap so + * callers using `status` don't pay JSON parse cost on every read. */ + size_t sl = strlen(st) + 16; + char* meta = el_strbuf(sl); + snprintf(meta, sl, "{\"status\":\"%s\"}", st); + n->metadata = meta; + } else { + n->metadata = el_strdup("{}"); + } + n->salience = engram_decode_score(salience); + n->importance = engram_decode_score(certainty); + n->confidence = engram_decode_score(confidence); + if (n->salience <= 0.0 || n->salience > 1.0) n->salience = 0.5; + if (n->importance <= 0.0 || n->importance > 1.0) n->importance = 0.5; + if (n->confidence <= 0.0 || n->confidence > 1.0) n->confidence = 1.0; + n->temporal_decay_rate = 0.0; + n->activation_count = 0; + int64_t now = engram_now_ms(); + n->last_activated = now; + n->created_at = now; + n->updated_at = now; + /* Resolve layer assignment. Caller passes either a numeric layer_id or + * a stringified id; el_to_float / int cast tolerates both. */ + int64_t lid = (int64_t)layer_id; + if (lid < 0) lid = (int64_t)ENGRAM_LAYER_DEFAULT; + if (!engram_find_layer((uint32_t)lid)) lid = (int64_t)ENGRAM_LAYER_DEFAULT; + n->layer_id = (uint32_t)lid; + g->node_count++; + return el_wrap_str(el_strdup(n->id)); +} + +/* ── Layer registry public API ────────────────────────────────────────────── + * + * The five canonical layers are seeded at engram_get() initialization. + * Runtime code (typically imprint/suit injection logic at the EL level) + * can extend the registry with engram_add_layer() — only layers marked + * `injectable=1` may be removed via engram_remove_layer(). Removing a + * layer leaves a tombstone slot so existing layer_id references on nodes + * stay valid; orphaned references resolve to "unknown layer" and inherit + * the default suppression behavior. + */ + +/* engram_add_layer — register a new layer at runtime. + * Returns the assigned layer_id as an el_val_t int (cast back via int64_t). + * Conflicting names are rejected (returns 0). */ +el_val_t engram_add_layer(el_val_t name, el_val_t priority, el_val_t suppressible, + el_val_t transparent, el_val_t injectable) { + EngramStore* g = engram_get(); + const char* nm = EL_CSTR(name); + if (!nm || !*nm) return (el_val_t)0; + if (engram_find_layer_by_name(nm)) { + /* Name collision — return existing id so callers are idempotent. */ + return (el_val_t)(int64_t)engram_find_layer_by_name(nm)->layer_id; + } + if (g->layer_count >= g->layer_capacity) { + size_t nc = g->layer_capacity ? g->layer_capacity * 2 : 16; + EngramLayer* grown = realloc(g->layers, nc * sizeof(EngramLayer)); + if (!grown) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + memset(grown + g->layer_capacity, 0, + (nc - g->layer_capacity) * sizeof(EngramLayer)); + g->layers = grown; + g->layer_capacity = nc; + } + EngramLayer* L = &g->layers[g->layer_count++]; + L->layer_id = engram_next_layer_id(); + L->name = el_strdup_persist(nm); + L->activation_priority = (uint32_t)(int64_t)priority; + L->suppressible = (int)(int64_t)suppressible ? 1 : 0; + L->transparent = (int)(int64_t)transparent ? 1 : 0; + L->injectable = (int)(int64_t)injectable ? 1 : 0; + return (el_val_t)(int64_t)L->layer_id; +} + +/* engram_remove_layer — remove an injectable layer by id. + * Built-in (non-injectable) layers cannot be removed. Nodes still tagged + * with the removed layer's id keep their tag but resolve to "unknown + * layer" thereafter and inherit standard (suppressible) behavior. + * Returns 1 on success, 0 on failure (unknown id, non-injectable). */ +el_val_t engram_remove_layer(el_val_t layer_id) { + EngramStore* g = engram_get(); + int64_t lid = (int64_t)layer_id; + for (size_t i = 0; i < g->layer_count; i++) { + EngramLayer* L = &g->layers[i]; + if (!L->name) continue; + if ((int64_t)L->layer_id != lid) continue; + if (!L->injectable) return (el_val_t)0; + free(L->name); + L->name = NULL; /* tombstone */ + /* Leave layer_id, priority, flags intact so debug snapshots can + * still distinguish "removed at runtime" from "never existed". */ + return (el_val_t)1; + } + return (el_val_t)0; +} + +/* engram_list_layers — enumerate the active layer registry. + * Returns an ElList of maps, one per non-tombstone layer, sorted by + * activation_priority ascending (deepest layer first). */ +el_val_t engram_list_layers(void) { + EngramStore* g = engram_get(); + el_val_t lst = el_list_empty(); + if (g->layer_count == 0) return lst; + /* Build an index sorted by activation_priority ascending. */ + size_t* idx = malloc(g->layer_count * sizeof(size_t)); + if (!idx) return lst; + size_t live = 0; + for (size_t i = 0; i < g->layer_count; i++) { + if (g->layers[i].name) idx[live++] = i; + } + /* Insertion sort — N is small (≤ a few dozen layers). */ + for (size_t i = 1; i < live; i++) { + size_t key = idx[i]; + uint32_t kp = g->layers[key].activation_priority; + size_t j = i; + while (j > 0 && g->layers[idx[j - 1]].activation_priority > kp) { + idx[j] = idx[j - 1]; + j--; + } + idx[j] = key; + } + for (size_t i = 0; i < live; i++) { + EngramLayer* L = &g->layers[idx[i]]; + el_val_t m = el_map_new(0); + m = el_map_set(m, EL_STR(el_strdup("layer_id")), + (el_val_t)(int64_t)L->layer_id); + m = el_map_set(m, EL_STR(el_strdup("name")), + EL_STR(el_strdup(L->name ? L->name : ""))); + m = el_map_set(m, EL_STR(el_strdup("activation_priority")), + (el_val_t)(int64_t)L->activation_priority); + m = el_map_set(m, EL_STR(el_strdup("suppressible")), + (el_val_t)(int64_t)(L->suppressible ? 1 : 0)); + m = el_map_set(m, EL_STR(el_strdup("transparent")), + (el_val_t)(int64_t)(L->transparent ? 1 : 0)); + m = el_map_set(m, EL_STR(el_strdup("injectable")), + (el_val_t)(int64_t)(L->injectable ? 1 : 0)); + lst = el_list_append(lst, m); + } + free(idx); + return lst; +} + +el_val_t engram_get_node(el_val_t id) { + const char* sid = EL_CSTR(id); + EngramNode* n = engram_find_node(sid); + if (!n) return el_map_new(0); + return engram_node_to_map(n); +} + +void engram_strengthen(el_val_t node_id) { + const char* sid = EL_CSTR(node_id); + EngramNode* n = engram_find_node(sid); + if (!n) return; + n->salience += 0.05; + if (n->salience > 1.0) n->salience = 1.0; + n->activation_count++; + n->last_activated = engram_now_ms(); + n->updated_at = n->last_activated; +} + +void engram_forget(el_val_t node_id) { + const char* sid = EL_CSTR(node_id); + if (!sid) return; + EngramStore* g = engram_get(); + int64_t idx = engram_find_node_index(sid); + if (idx < 0) return; + /* Free node strings */ + EngramNode* n = &g->nodes[idx]; + free(n->id); free(n->content); free(n->node_type); free(n->label); + free(n->tier); free(n->tags); free(n->metadata); + /* Shift remaining nodes down */ + for (int64_t i = idx + 1; i < g->node_count; i++) { + g->nodes[i - 1] = g->nodes[i]; + } + g->node_count--; + memset(&g->nodes[g->node_count], 0, sizeof(EngramNode)); + /* Remove all incident edges */ + int64_t w = 0; + for (int64_t r = 0; r < g->edge_count; r++) { + EngramEdge* e = &g->edges[r]; + int incident = (e->from_id && strcmp(e->from_id, sid) == 0) || + (e->to_id && strcmp(e->to_id, sid) == 0); + if (incident) { + free(e->id); free(e->from_id); free(e->to_id); + free(e->relation); free(e->metadata); + } else { + if (w != r) g->edges[w] = g->edges[r]; + w++; + } + } + g->edge_count = w; +} + +el_val_t engram_node_count(void) { + return (el_val_t)engram_get()->node_count; +} + +static int istr_contains(const char* hay, const char* needle) { + if (!hay || !needle || !*needle) return 0; + size_t nl = strlen(needle); + for (const char* p = hay; *p; p++) { + if (strncasecmp(p, needle, nl) == 0) return 1; + } + return 0; +} + +el_val_t engram_search(el_val_t query, el_val_t limit) { + EngramStore* g = engram_get(); + const char* q = EL_CSTR(query); + int64_t lim = (int64_t)limit; + if (lim <= 0) lim = 100; + el_val_t lst = el_list_empty(); + if (!q || !*q) return lst; + int64_t found = 0; + for (int64_t i = 0; i < g->node_count && found < lim; i++) { + EngramNode* n = &g->nodes[i]; + /* Filter transparent layers: nodes whose layer is `transparent=1` + * shape output but are invisible to introspection ("what do you + * know about yourself"). They still surface via engram_activate + * + engram_compile_layered_json — that's the legitimate path. */ + if (engram_layer_is_transparent(n->layer_id)) continue; + if (istr_contains(n->content, q) || + istr_contains(n->label, q) || + istr_contains(n->tags, q)) { + lst = el_list_append(lst, engram_node_to_map(n)); + found++; + } + } + return lst; +} + +/* Sort node indices by salience desc (small N, insertion sort is fine). */ +static void engram_sort_indices_by_salience(int64_t* arr, int64_t n, + const EngramNode* nodes) { + for (int64_t i = 1; i < n; i++) { + int64_t key = arr[i]; + double ks = nodes[key].salience; + int64_t j = i - 1; + while (j >= 0 && nodes[arr[j]].salience < ks) { + arr[j + 1] = arr[j]; + j--; + } + arr[j + 1] = key; + } +} + +el_val_t engram_scan_nodes(el_val_t limit, el_val_t offset) { + EngramStore* g = engram_get(); + int64_t lim = (int64_t)limit; if (lim <= 0) lim = 100; + int64_t off = (int64_t)offset; if (off < 0) off = 0; + el_val_t lst = el_list_empty(); + if (g->node_count == 0) return lst; + int64_t* idx = malloc((size_t)g->node_count * sizeof(int64_t)); + if (!idx) return lst; + /* Skip transparent layers — same introspection-filter rationale as + * engram_search above. */ + int64_t live = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (engram_layer_is_transparent(g->nodes[i].layer_id)) continue; + idx[live++] = i; + } + engram_sort_indices_by_salience(idx, live, g->nodes); + int64_t end = off + lim; + if (end > live) end = live; + for (int64_t i = off; i < end; i++) { + lst = el_list_append(lst, engram_node_to_map(&g->nodes[idx[i]])); + } + free(idx); + return lst; +} + +void engram_connect(el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t relation) { + EngramStore* g = engram_get(); + const char* f = EL_CSTR(from_id); + const char* t = EL_CSTR(to_id); + const char* r = EL_CSTR(relation); + if (!f || !t) return; + engram_grow_edges(); + EngramEdge* e = &g->edges[g->edge_count]; + memset(e, 0, sizeof(*e)); + e->id = engram_new_id(); + e->from_id = el_strdup(f); + e->to_id = el_strdup(t); + e->relation = el_strdup(r && *r ? r : "associate"); + e->metadata = el_strdup("{}"); + e->weight = engram_decode_score(weight); + if (e->weight <= 0.0 || e->weight > 1.0) e->weight = 0.5; + e->confidence = 1.0; + int64_t now = engram_now_ms(); + e->created_at = now; + e->updated_at = now; + e->last_fired = 0; + e->layer_id = ENGRAM_LAYER_DEFAULT; + g->edge_count++; +} + +el_val_t engram_edge_between(el_val_t from_id, el_val_t to_id) { + EngramStore* g = engram_get(); + const char* f = EL_CSTR(from_id); + const char* t = EL_CSTR(to_id); + if (!f || !t) return 0; + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + if (e->from_id && e->to_id && + strcmp(e->from_id, f) == 0 && strcmp(e->to_id, t) == 0) return 1; + } + return 0; +} + +/* Reserved helper: edge -> ElMap. Kept around for future builtins. */ +static el_val_t engram_edge_to_map(const EngramEdge* e) __attribute__((unused)); +static el_val_t engram_edge_to_map(const EngramEdge* e) { + el_val_t m = el_map_new(0); + m = el_map_set(m, EL_STR(el_strdup("id")), EL_STR(el_strdup(e->id ? e->id : ""))); + m = el_map_set(m, EL_STR(el_strdup("from_id")), EL_STR(el_strdup(e->from_id ? e->from_id : ""))); + m = el_map_set(m, EL_STR(el_strdup("to_id")), EL_STR(el_strdup(e->to_id ? e->to_id : ""))); + m = el_map_set(m, EL_STR(el_strdup("relation")), EL_STR(el_strdup(e->relation ? e->relation : ""))); + m = el_map_set(m, EL_STR(el_strdup("metadata")), EL_STR(el_strdup(e->metadata ? e->metadata : "{}"))); + m = el_map_set(m, EL_STR(el_strdup("weight")), el_from_float(e->weight)); + m = el_map_set(m, EL_STR(el_strdup("confidence")), el_from_float(e->confidence)); + m = el_map_set(m, EL_STR(el_strdup("created_at")), (el_val_t)e->created_at); + m = el_map_set(m, EL_STR(el_strdup("updated_at")), (el_val_t)e->updated_at); + m = el_map_set(m, EL_STR(el_strdup("last_fired")), (el_val_t)e->last_fired); + m = el_map_set(m, EL_STR(el_strdup("inhibitory")), (el_val_t)(e->inhibitory ? 1 : 0)); + m = el_map_set(m, EL_STR(el_strdup("layer_id")), (el_val_t)(int64_t)e->layer_id); + return m; +} + +el_val_t engram_neighbors(el_val_t node_id) { + EngramStore* g = engram_get(); + const char* sid = EL_CSTR(node_id); + el_val_t lst = el_list_empty(); + if (!sid) return lst; + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + const char* other = NULL; + if (e->from_id && strcmp(e->from_id, sid) == 0) other = e->to_id; + else if (e->to_id && strcmp(e->to_id, sid) == 0) other = e->from_id; + if (!other) continue; + EngramNode* n = engram_find_node(other); + if (n) lst = el_list_append(lst, engram_node_to_map(n)); + } + return lst; +} + +el_val_t engram_neighbors_filtered(el_val_t node_id, el_val_t max_depth, el_val_t direction) { + EngramStore* g = engram_get(); + const char* sid = EL_CSTR(node_id); + int64_t md = (int64_t)max_depth; if (md <= 0) md = 1; + const char* dir = EL_CSTR(direction); /* "out" | "in" | "both" (default) */ + el_val_t lst = el_list_empty(); + if (!sid || g->node_count == 0) return lst; + int64_t start = engram_find_node_index(sid); + if (start < 0) return lst; + /* BFS with depth tracking */ + int64_t* visited = calloc((size_t)g->node_count, sizeof(int64_t)); + int64_t* queue = calloc((size_t)g->node_count, sizeof(int64_t)); + int64_t* depths = calloc((size_t)g->node_count, sizeof(int64_t)); + if (!visited || !queue || !depths) { + free(visited); free(queue); free(depths); return lst; + } + int64_t qh = 0, qt = 0; + queue[qt++] = start; + visited[start] = 1; + depths[start] = 0; + while (qh < qt) { + int64_t cur = queue[qh++]; + const char* cur_id = g->nodes[cur].id; + int64_t cur_depth = depths[cur]; + if (cur_depth >= md) continue; + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + const char* other = NULL; + int outgoing = e->from_id && strcmp(e->from_id, cur_id) == 0; + int incoming = e->to_id && strcmp(e->to_id, cur_id) == 0; + if (dir && strcmp(dir, "out") == 0 && !outgoing) continue; + if (dir && strcmp(dir, "in") == 0 && !incoming) continue; + if (outgoing) other = e->to_id; + else if (incoming) other = e->from_id; + else continue; + int64_t oi = engram_find_node_index(other); + if (oi < 0 || visited[oi]) continue; + visited[oi] = 1; + depths[oi] = cur_depth + 1; + queue[qt++] = oi; + } + } + /* Emit all visited except the seed */ + for (int64_t i = 0; i < g->node_count; i++) { + if (visited[i] && i != start) { + lst = el_list_append(lst, engram_node_to_map(&g->nodes[i])); + } + } + free(visited); free(queue); free(depths); + return lst; +} + +el_val_t engram_edge_count(void) { + return (el_val_t)engram_get()->edge_count; +} + +/* Compute temporal decay factor for a node given current time. + * effective contribution = salience * exp(-lambda * age_hours / T_half) + * Clamped to [0.05, 1.0] so very old nodes retain a meaningful floor. */ +static double engram_temporal_decay(const EngramNode* n, int64_t now_ms) { + int64_t age_ms = now_ms - n->last_activated; + if (age_ms <= 0) return 1.0; + double lambda = (n->temporal_decay_rate > 0.0) ? n->temporal_decay_rate + : ENGRAM_DECAY_LAMBDA; + double age_hours = (double)age_ms / 3600000.0; + double factor = exp(-lambda * age_hours / ENGRAM_T_HALF_HOURS); + if (factor < 0.05) factor = 0.05; + return factor; +} + +/* Activation dampening: high activation_count nodes are "well-known" context + * and get less marginal boost per firing. + * count=0 → 1.0, count=2 → ~0.74, count=9 → ~0.59, count=99 → ~0.43 */ +static double engram_activation_dampen(const EngramNode* n) { + return 1.0 / (1.0 + log(1.0 + (double)n->activation_count)); +} + +/* Temporal proximity bonus: boost propagation along edges connecting + * co-temporal nodes. Returns a multiplier bonus in [0, 0.2]. */ +static double engram_temporal_proximity_bonus(int64_t node_created, + int64_t seed_epoch) { + int64_t diff = node_created - seed_epoch; + if (diff < 0) diff = -diff; + if (diff < 86400000LL) return 0.20; /* within 1 day */ + if (diff < 604800000LL) return 0.10; /* within 7 days */ + return 0.0; +} + +/* ── Two-layer activation (biologically-motivated) ─────────────────────────── + * + * Layer 1 — Broad fan-out (background activation): + * BFS + spreading activation fires on ALL nodes reachable from seeds, + * regardless of relevance to the current goal. Every reachable node gets + * a background_activation score. Nothing is filtered here. Models the + * brain's massive parallel sub-threshold activation of all associated + * content in response to a stimulus. Temporal decay and activation + * dampening are applied at this layer (as before), but no threshold gate. + * + * Layer 2 — Executive filter (working memory promotion): + * A second pass asks: given the query (goal intent), attentional bias, + * and inhibitory edge topology — which background-activated nodes should + * break through into working memory? + * + * wm_weight = bg_activation * goal_bias(node, query) * confidence + * * inhibitory_suppression_factor + * + * Only nodes where wm_weight >= ENGRAM_WM_THRESHOLD are promoted to + * working memory (working_memory_weight > 0). Background-activated nodes + * that don't cross the threshold accumulate suppression_count. After + * ENGRAM_SUPPRESSION_BREAKTHROUGH consecutive suppressed turns, the node + * force-breaks through at ENGRAM_BREAKTHROUGH_WEIGHT (latent tension + * surfacing — models intrusive memory / unresolved cognitive load). + * + * Inhibitory edges: + * An edge with inhibitory=1 suppresses the TARGET node's working memory + * promotion when the SOURCE is background-activated. Background activation + * of the target is NOT affected — the node fires in layer 1. Only the + * executive filter (layer 2) is gated. Models attentional inhibition: + * "focused on code work" suppresses personal memories from surfacing + * even if they have high background_activation. + * + * Goal bias: + * A lightweight heuristic rates how well each background-activated node + * aligns with the apparent intent of the current query. Technical queries + * boost Belief/Canonical/Lesson nodes; relational queries boost Memory/ + * Entity nodes. Direct lexical overlap gives a 50% bonus. + * + * Working memory persistence (turn continuity): + * Nodes promoted in the previous turn retain a decayed working_memory_weight + * (weight *= ENGRAM_WM_DECAY) without needing re-activation. This models + * conversational thread continuity — once a topic is in working memory, + * it persists slightly into the next turn. + * + * Returns ElList of {node, activation_strength, working_memory_weight, + * epistemic_confidence, hops, promoted}. + * "promoted" = 1 if working_memory_weight > 0, 0 if background-only. + * Context compilation uses ONLY nodes with promoted=1. + * + * Temporal decay (preserved from prior implementation): + * effective_salience = salience * exp(-lambda * age_hours / T_half) + * where T_half = 168 h (one week), lambda = ln(2) + * + * Activation dampening (preserved): + * dampen = 1 / (1 + log(1 + activation_count)) + * + * Temporal proximity bonus (preserved): + * edge_strength *= (1 + tbonus) where tbonus ∈ {0, 0.10, 0.20} + * + * Per-type threshold gates apply only to working memory promotion (layer 2): + * Safety/DharmaSelf: 0.05 Canonical: 0.15 Lesson: 0.25 + * Belief/Entity: 0.30 Note/Memory/Working: 0.40 + */ + +/* Compute goal-state bias multiplier for a node given the query. + * Returns a value in [0.3, 2.0]. This is a lightweight heuristic — + * a production implementation may use LLM-derived intent classification. */ +static double engram_goal_bias(const EngramNode* n, const char* query) { + if (!query || !*query) return 1.0; + double bias = 1.0; + /* Direct lexical overlap: node content/label/tags share text with query. */ + if (istr_contains(n->content, query) || istr_contains(n->label, query) || + istr_contains(n->tags, query)) { + bias += 0.5; + } + /* Node-type resonance with query intent. */ + int technical_query = istr_contains(query, "code") || + istr_contains(query, "function") || + istr_contains(query, "implement") || + istr_contains(query, "error") || + istr_contains(query, "bug") || + istr_contains(query, "build") || + istr_contains(query, "system") || + istr_contains(query, "design") || + istr_contains(query, "architecture"); + int personal_query = istr_contains(query, "feel") || + istr_contains(query, "emotion") || + istr_contains(query, "remember") || + istr_contains(query, "personal") || + istr_contains(query, "story") || + istr_contains(query, "relationship"); + if (n->node_type) { + int is_knowledge = (strcmp(n->node_type, "Belief") == 0) || + (strcmp(n->node_type, "DharmaSelf") == 0) || + (strcmp(n->node_type, "Safety") == 0); + int is_personal = (strcmp(n->node_type, "Memory") == 0) || + (strcmp(n->node_type, "Entity") == 0); + if (technical_query && is_knowledge) bias += 0.3; + if (technical_query && is_personal) bias -= 0.3; + if (personal_query && is_personal) bias += 0.3; + if (personal_query && is_knowledge) bias -= 0.1; + } + /* Tier-based bonus: promote higher-confidence knowledge nodes. */ + if (n->tier) { + if (strcmp(n->tier, "Canonical") == 0) bias += 0.2; + if (strcmp(n->tier, "Lesson") == 0) bias += 0.1; + } + if (bias < 0.3) bias = 0.3; + if (bias > 2.0) bias = 2.0; + return bias; +} + +el_val_t engram_activate(el_val_t query, el_val_t depth) { + EngramStore* g = engram_get(); + const char* q = EL_CSTR(query); + int64_t max_depth = (int64_t)depth; if (max_depth <= 0) max_depth = 2; + el_val_t out = el_list_empty(); + if (!q || g->node_count == 0) return out; + + int64_t now_ms = engram_now_ms(); + + /* Per-node layer-1 tracking. */ + double* best_bg = calloc((size_t)g->node_count, sizeof(double)); + int64_t* best_hops = calloc((size_t)g->node_count, sizeof(int64_t)); + int* reached = calloc((size_t)g->node_count, sizeof(int)); + if (!best_bg || !best_hops || !reached) { + free(best_bg); free(best_hops); free(reached); return out; + } + + /* ── LAYER 1: broad fan-out (background activation) ───────────────── + * Find seeds, apply temporal decay + dampening, BFS with edge weights. + * Inhibitory edges propagate activation normally at this layer — they + * only gate working memory promotion in layer 2. */ + typedef struct { int64_t idx; double act; int64_t created_at; } SeedEntry; + SeedEntry* seeds = malloc((size_t)g->node_count * sizeof(SeedEntry)); + int64_t seed_count = 0; + if (!seeds) { + free(best_bg); free(best_hops); free(reached); return out; + } + for (int64_t i = 0; i < g->node_count; i++) { + EngramNode* n = &g->nodes[i]; + if (istr_contains(n->content, q) || + istr_contains(n->label, q) || + istr_contains(n->tags, q)) { + double tdecay = engram_temporal_decay(n, now_ms); + double dampen = engram_activation_dampen(n); + double act = n->salience * tdecay * dampen; + seeds[seed_count].idx = i; + seeds[seed_count].act = act; + seeds[seed_count].created_at = n->created_at; + seed_count++; + best_bg[i] = act; + best_hops[i] = 0; + reached[i] = 1; + } + } + /* Compute mean seed created_at for temporal proximity bonus. */ + int64_t seed_epoch = 0; + if (seed_count > 0) { + seed_epoch = seeds[0].created_at; + for (int64_t s = 1; s < seed_count; s++) + seed_epoch = (seed_epoch + seeds[s].created_at) / 2; + } + typedef struct { int64_t idx; int64_t hops; double act; } Frontier; + Frontier* fr = malloc((size_t)(g->node_count * (max_depth + 1)) * sizeof(Frontier) + 16 * sizeof(Frontier)); + if (!fr) { + free(best_bg); free(best_hops); free(reached); free(seeds); return out; + } + int64_t fhead = 0, ftail = 0; + int64_t fcap = (int64_t)((size_t)(g->node_count * (max_depth + 1)) + 16); + for (int64_t s = 0; s < seed_count; s++) { + if (ftail >= fcap) break; + fr[ftail].idx = seeds[s].idx; + fr[ftail].hops = 0; + fr[ftail].act = seeds[s].act; + ftail++; + } + const double SPREAD_DECAY = 0.7; + while (fhead < ftail) { + Frontier f = fr[fhead++]; + if (f.hops >= max_depth) continue; + const char* cur_id = g->nodes[f.idx].id; + for (int64_t ei = 0; ei < g->edge_count; ei++) { + EngramEdge* e = &g->edges[ei]; + const char* other = NULL; + if (e->from_id && strcmp(e->from_id, cur_id) == 0) other = e->to_id; + else if (e->to_id && strcmp(e->to_id, cur_id) == 0) other = e->from_id; + else continue; + int64_t oi = engram_find_node_index(other); + if (oi < 0) continue; + EngramNode* on = &g->nodes[oi]; + double tbonus = engram_temporal_proximity_bonus(on->created_at, seed_epoch); + double tdecay = engram_temporal_decay(on, now_ms); + double dampen = engram_activation_dampen(on); + double new_act = f.act * e->weight * SPREAD_DECAY * (1.0 + tbonus) + * tdecay * dampen; + int64_t new_hops = f.hops + 1; + if (!reached[oi] || new_act > best_bg[oi]) { + best_bg[oi] = new_act; + best_hops[oi] = new_hops; + reached[oi] = 1; + if (ftail < fcap) { + fr[ftail].idx = oi; + fr[ftail].hops = new_hops; + fr[ftail].act = new_act; + ftail++; + } + } + } + } + /* Persist layer-1 background_activation to node store. */ + for (int64_t i = 0; i < g->node_count; i++) { + g->nodes[i].background_activation = reached[i] ? best_bg[i] : 0.0; + } + + /* ── TRAVERSAL INFERENCE: infer A→C edges when A→B→C was traversed ── + * For each pair of edges (A→B, B→C) where all three nodes were reached, + * create an inferred A→C edge with weight = w(A→B) * w(B→C) * 0.8 + * if no A→C edge already exists. Cap at 64 new edges per call. + * + * IMPORTANT: collect candidates FIRST into a flat array (no pointers into + * g->edges held across the apply pass), then apply after — this avoids + * dangling pointer bugs if engram_grow_edges() reallocs the array. */ + { + const int64_t INFER_CAP = 64; + typedef struct { char from[64]; char to[64]; double weight; } InferCandidate; + InferCandidate* cands = malloc((size_t)INFER_CAP * sizeof(InferCandidate)); + int64_t ncands = 0; + int64_t snap_ec = g->edge_count; + if (cands) { + for (int64_t e1 = 0; e1 < snap_ec && ncands < INFER_CAP; e1++) { + EngramEdge* ea = &g->edges[e1]; + if (!ea->from_id || !ea->to_id) continue; + int64_t ai = engram_find_node_index(ea->from_id); + int64_t bi = engram_find_node_index(ea->to_id); + if (ai < 0 || bi < 0) continue; + if (!reached[ai] || !reached[bi]) continue; + for (int64_t e2 = 0; e2 < snap_ec && ncands < INFER_CAP; e2++) { + if (e2 == e1) continue; + EngramEdge* eb = &g->edges[e2]; + if (!eb->from_id || !eb->to_id) continue; + if (strcmp(eb->from_id, ea->to_id) != 0) continue; + int64_t ci = engram_find_node_index(eb->to_id); + if (ci < 0 || !reached[ci]) continue; + if (ai == ci) continue; + int already = 0; + for (int64_t ex = 0; ex < snap_ec; ex++) { + EngramEdge* ee = &g->edges[ex]; + if (ee->from_id && ee->to_id && + strcmp(ee->from_id, ea->from_id) == 0 && + strcmp(ee->to_id, eb->to_id) == 0) { + already = 1; break; + } + } + if (already) continue; + int dup = 0; + for (int64_t k = 0; k < ncands; k++) { + if (strcmp(cands[k].from, ea->from_id) == 0 && + strcmp(cands[k].to, eb->to_id) == 0) { dup = 1; break; } + } + if (dup) continue; + double inf_w = ea->weight * eb->weight * 0.8; + if (inf_w < 0.05) inf_w = 0.05; + if (inf_w > 1.0) inf_w = 1.0; + strncpy(cands[ncands].from, ea->from_id, 63); cands[ncands].from[63] = '\0'; + strncpy(cands[ncands].to, eb->to_id, 63); cands[ncands].to[63] = '\0'; + cands[ncands].weight = inf_w; + ncands++; + } + } + for (int64_t k = 0; k < ncands; k++) { + engram_grow_edges(); + EngramEdge* ne = &g->edges[g->edge_count]; + memset(ne, 0, sizeof(*ne)); + ne->id = engram_new_id(); + /* Use strdup (not el_strdup) so these persist beyond the request. */ + ne->from_id = strdup(cands[k].from); + ne->to_id = strdup(cands[k].to); + ne->relation = strdup("inferred"); + ne->metadata = strdup("{}"); + ne->weight = cands[k].weight; + ne->confidence = 0.8; + ne->created_at = now_ms; + ne->updated_at = now_ms; + ne->last_fired = now_ms; + ne->layer_id = ENGRAM_LAYER_DEFAULT; + g->edge_count++; + } + free(cands); + } + } + + /* ── PASS 2: executive filter → working memory promotion ──────────── */ + /* Step A: collect inhibitory suppressions from fired inhibitory edges. + * Layered consciousness: inhibition is ONLY recorded against targets + * whose layer is `suppressible == 1`. Nodes in non-suppressible layers + * (Layer 0 / safety) ignore inhibitory edges entirely — their working + * memory weight cannot be silenced by attentional suppression. */ + double* inhibition = calloc((size_t)g->node_count, sizeof(double)); + if (!inhibition) { + free(best_bg); free(best_hops); free(reached); free(seeds); free(fr); + return out; + } + for (int64_t ei = 0; ei < g->edge_count; ei++) { + EngramEdge* e = &g->edges[ei]; + if (!e->inhibitory) continue; + int64_t src = engram_find_node_index(e->from_id); + int64_t tgt = engram_find_node_index(e->to_id); + if (src < 0 || tgt < 0) continue; + if (!reached[src] || best_bg[src] <= 0.0) continue; + /* Skip if target layer is non-suppressible: Layer 0 / safety nodes + * are immune to inhibitory edges from any source. The pass-3 + * override below also force-promotes them, but recording inhibition + * against them at all would be wasted work and could confuse + * downstream debugging output. */ + if (!engram_layer_is_suppressible(g->nodes[tgt].layer_id)) continue; + /* Inhibition strength proportional to source background activation + * and edge weight. Takes the maximum if multiple inhibitory edges + * target the same node. */ + double inh = best_bg[src] * e->weight; + if (inh > inhibition[tgt]) inhibition[tgt] = inh; + } + /* Step B: compute working_memory_weight per candidate node. */ + double* wm_weights = calloc((size_t)g->node_count, sizeof(double)); + if (!wm_weights) { + free(best_bg); free(best_hops); free(reached); free(seeds); + free(fr); free(inhibition); return out; + } + for (int64_t i = 0; i < g->node_count; i++) { + if (!reached[i] || best_bg[i] <= 0.0) continue; + EngramNode* n = &g->nodes[i]; + /* Per-type threshold: safety nodes break through more easily. */ + double type_threshold = engram_type_threshold(n->node_type, n->tier); + /* Goal bias weights the node's relevance to current intent. */ + double bias = engram_goal_bias(n, q); + /* Raw working memory score. */ + double raw_wm = best_bg[i] * bias * n->confidence; + /* Apply inhibitory suppression. Full inhibition → scale by factor. */ + double inh = inhibition[i]; + if (inh > 1.0) inh = 1.0; + double suppress = 1.0 - (1.0 - ENGRAM_INHIBITION_FACTOR) * inh; + raw_wm *= suppress; + /* Threshold gate: must exceed per-type threshold to enter working + * memory. Type threshold replaces the old flat 0.2 filter. */ + if (raw_wm >= type_threshold) { + wm_weights[i] = raw_wm > 1.0 ? 1.0 : raw_wm; + if (n->suppression_count > 0) n->suppression_count = 0; + } else { + /* Node didn't make it through — increment suppression counter. + * After N consecutive suppressions: force breakthrough. */ + n->suppression_count++; + if (n->suppression_count >= ENGRAM_SUPPRESSION_BREAKTHROUGH) { + wm_weights[i] = ENGRAM_BREAKTHROUGH_WEIGHT; + n->suppression_count = 0; + } else { + wm_weights[i] = 0.0; + } + } + } + /* ── PASS 3: Layer 0 override (the sacred fire) ───────────────────── + * Every node in a non-suppressible layer that received any background + * activation is force-promoted to AT LEAST ENGRAM_LAYER0_OVERRIDE_WEIGHT. + * This runs LAST and overrides whatever Pass 2 decided — Layer 0 cannot + * be silenced by inhibitory edges, by goal-bias misalignment, by + * confidence weighting, or by per-type threshold gates. If the seed + * fan-out reached a structural-floor node, that node surfaces. + * + * Note: this also clears the suppression_count when an override fires, + * since the node DID surface this turn — it just took the override path + * rather than the standard threshold path. Without this, a Layer 0 + * node with persistent inhibitory pressure would accumulate + * suppression_count forever and never reach the breakthrough state. */ + for (int64_t i = 0; i < g->node_count; i++) { + if (!reached[i] || best_bg[i] <= 0.0) continue; + EngramNode* n = &g->nodes[i]; + if (engram_layer_is_suppressible(n->layer_id)) continue; + if (wm_weights[i] < ENGRAM_LAYER0_OVERRIDE_WEIGHT) { + wm_weights[i] = ENGRAM_LAYER0_OVERRIDE_WEIGHT; + } + n->suppression_count = 0; + } + + /* Persist working_memory_weight (post Pass 3) to node store. */ + for (int64_t i = 0; i < g->node_count; i++) { + g->nodes[i].working_memory_weight = wm_weights[i]; + } + + /* ── HEBBIAN STRENGTHENING: fire together, wire together ───────────── + * For each pair of co-promoted nodes (working_memory_weight > 0) that + * share an edge, boost that edge's weight by 0.05 (capped at 1.0). + * Also increment activation_count and update last_activated on promoted + * nodes — this is what drives tier migration below. */ + for (int64_t i = 0; i < g->node_count; i++) { + if (wm_weights[i] <= 0.0) continue; + EngramNode* n = &g->nodes[i]; + n->activation_count++; + n->last_activated = now_ms; + n->updated_at = now_ms; + } + for (int64_t ei = 0; ei < g->edge_count; ei++) { + EngramEdge* e = &g->edges[ei]; + if (!e->from_id || !e->to_id) continue; + int64_t src = engram_find_node_index(e->from_id); + int64_t tgt = engram_find_node_index(e->to_id); + if (src < 0 || tgt < 0) continue; + if (wm_weights[src] > 0.0 && wm_weights[tgt] > 0.0) { + e->weight += 0.05; + if (e->weight > 1.0) e->weight = 1.0; + e->last_fired = now_ms; + e->updated_at = now_ms; + } + } + + /* ── TIER MIGRATION: promote nodes based on activation_count thresholds ─ + * 0–4 → Working + * 5–19 → Episodic + * 20–49 → Semantic + * 50+ → Procedural + * Only upgrade (never downgrade) to preserve earned tier. */ + for (int64_t i = 0; i < g->node_count; i++) { + EngramNode* n = &g->nodes[i]; + const char* target_tier = NULL; + int64_t ac = n->activation_count; + if (ac >= 50) target_tier = "Procedural"; + else if (ac >= 20) target_tier = "Semantic"; + else if (ac >= 5) target_tier = "Episodic"; + else target_tier = "Working"; + if (target_tier && n->tier && strcmp(n->tier, target_tier) != 0) { + /* Only upgrade (Working < Episodic < Semantic < Procedural). */ + int cur_rank = 0, new_rank = 0; + if (strcmp(n->tier, "Working") == 0) cur_rank = 0; + else if (strcmp(n->tier, "Episodic") == 0) cur_rank = 1; + else if (strcmp(n->tier, "Semantic") == 0) cur_rank = 2; + else if (strcmp(n->tier, "Procedural") == 0) cur_rank = 3; + if (strcmp(target_tier, "Working") == 0) new_rank = 0; + else if (strcmp(target_tier, "Episodic") == 0) new_rank = 1; + else if (strcmp(target_tier, "Semantic") == 0) new_rank = 2; + else if (strcmp(target_tier, "Procedural") == 0) new_rank = 3; + if (new_rank > cur_rank) { + free(n->tier); + /* Use strdup (not el_strdup) so tier string persists beyond the request. */ + n->tier = strdup(target_tier); + n->updated_at = now_ms; + } + } + } + + /* ── Collect all background-activated nodes for the return value ──── + * Callers see both layers. Context compilation uses only promoted nodes + * (working_memory_weight > 0). Sort: promoted first by wm_weight desc, + * then background-only by background_activation desc. */ + typedef struct { int64_t idx; double bg; double wm; double epist; int64_t hops; } Result; + Result* results = malloc((size_t)g->node_count * sizeof(Result)); + int64_t rcount = 0; + if (!results) { + free(best_bg); free(best_hops); free(reached); free(seeds); + free(fr); free(inhibition); free(wm_weights); return out; + } + for (int64_t i = 0; i < g->node_count; i++) { + if (!reached[i]) continue; + double epist = best_bg[i] * g->nodes[i].confidence; + /* Include if promoted to working memory OR if background activation + * is meaningful enough to report (epist >= 0.1). */ + if (epist < 0.1 && wm_weights[i] <= 0.0) continue; + results[rcount].idx = i; + results[rcount].bg = best_bg[i]; + results[rcount].wm = wm_weights[i]; + results[rcount].epist = epist; + results[rcount].hops = best_hops[i]; + rcount++; + } + /* Sort: promoted nodes first (by wm_weight desc), then background-only + * by background_activation desc. */ + for (int64_t i = 1; i < rcount; i++) { + Result key = results[i]; + int64_t j = i - 1; + while (j >= 0 && (results[j].wm < key.wm || + (results[j].wm == key.wm && results[j].bg < key.bg))) { + results[j + 1] = results[j]; + j--; + } + results[j + 1] = key; + } + for (int64_t i = 0; i < rcount; i++) { + el_val_t entry = el_map_new(0); + entry = el_map_set(entry, EL_STR(el_strdup("node")), + engram_node_to_map(&g->nodes[results[i].idx])); + entry = el_map_set(entry, EL_STR(el_strdup("activation_strength")), + el_from_float(results[i].bg)); + entry = el_map_set(entry, EL_STR(el_strdup("working_memory_weight")), + el_from_float(results[i].wm)); + entry = el_map_set(entry, EL_STR(el_strdup("epistemic_confidence")), + el_from_float(results[i].epist)); + entry = el_map_set(entry, EL_STR(el_strdup("hops")), + (el_val_t)results[i].hops); + entry = el_map_set(entry, EL_STR(el_strdup("promoted")), + (el_val_t)(results[i].wm > 0.0 ? 1 : 0)); + out = el_list_append(out, entry); + } + free(best_bg); free(best_hops); free(reached); + free(seeds); free(fr); free(inhibition); free(wm_weights); free(results); + return out; +} + +/* ── Engram persistence (JSON snapshot) ─────────────────────────────────── */ + +static void engram_emit_node_json(JsonBuf* b, const EngramNode* n) { + jb_putc(b, '{'); + jb_puts(b, "\"id\":"); jb_emit_escaped(b, n->id ? n->id : ""); + jb_puts(b, ",\"content\":"); jb_emit_escaped(b, n->content ? n->content : ""); + jb_puts(b, ",\"node_type\":"); jb_emit_escaped(b, n->node_type ? n->node_type : ""); + jb_puts(b, ",\"label\":"); jb_emit_escaped(b, n->label ? n->label : ""); + jb_puts(b, ",\"tier\":"); jb_emit_escaped(b, n->tier ? n->tier : "Working"); + jb_puts(b, ",\"tags\":"); jb_emit_escaped(b, n->tags ? n->tags : ""); + jb_puts(b, ",\"metadata\":"); jb_emit_escaped(b, n->metadata ? n->metadata : "{}"); + char tmp[80]; + snprintf(tmp, sizeof(tmp), ",\"salience\":%g", n->salience); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"importance\":%g", n->importance); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"confidence\":%g", n->confidence); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"temporal_decay_rate\":%g", n->temporal_decay_rate); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"activation_count\":%lld", (long long)n->activation_count); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"last_activated\":%lld", (long long)n->last_activated); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"created_at\":%lld", (long long)n->created_at); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"updated_at\":%lld", (long long)n->updated_at); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"background_activation\":%g", n->background_activation); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"working_memory_weight\":%g", n->working_memory_weight); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"suppression_count\":%d", n->suppression_count); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"layer_id\":%u", n->layer_id); jb_puts(b, tmp); + jb_putc(b, '}'); +} + +static void engram_emit_edge_json(JsonBuf* b, const EngramEdge* e) { + jb_putc(b, '{'); + jb_puts(b, "\"id\":"); jb_emit_escaped(b, e->id ? e->id : ""); + jb_puts(b, ",\"from_id\":"); jb_emit_escaped(b, e->from_id ? e->from_id : ""); + jb_puts(b, ",\"to_id\":"); jb_emit_escaped(b, e->to_id ? e->to_id : ""); + jb_puts(b, ",\"relation\":"); jb_emit_escaped(b, e->relation ? e->relation : ""); + jb_puts(b, ",\"metadata\":"); jb_emit_escaped(b, e->metadata ? e->metadata : "{}"); + char tmp[64]; + snprintf(tmp, sizeof(tmp), ",\"weight\":%g", e->weight); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"confidence\":%g", e->confidence); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"created_at\":%lld", (long long)e->created_at); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"updated_at\":%lld", (long long)e->updated_at); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"last_fired\":%lld", (long long)e->last_fired); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"inhibitory\":%d", e->inhibitory ? 1 : 0); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"layer_id\":%u", e->layer_id); jb_puts(b, tmp); + jb_putc(b, '}'); +} + +el_val_t engram_save(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p || !*p) return 0; + EngramStore* g = engram_get(); + JsonBuf b; jb_init(&b); + jb_puts(&b, "{\"nodes\":["); + for (int64_t i = 0; i < g->node_count; i++) { + if (i > 0) jb_putc(&b, ','); + engram_emit_node_json(&b, &g->nodes[i]); + } + jb_puts(&b, "],\"edges\":["); + for (int64_t i = 0; i < g->edge_count; i++) { + if (i > 0) jb_putc(&b, ','); + engram_emit_edge_json(&b, &g->edges[i]); + } + /* Layered consciousness — emit the layer registry under "layers". + * Older readers that don't know about this top-level key will simply + * ignore it (forward compatible). Tombstoned (removed-injectable) + * layers are skipped — they have no name and can't be re-created + * meaningfully on load anyway. */ + jb_puts(&b, "],\"layers\":["); + int first_layer = 1; + for (size_t i = 0; i < g->layer_count; i++) { + EngramLayer* L = &g->layers[i]; + if (!L->name) continue; + if (!first_layer) jb_putc(&b, ','); + first_layer = 0; + jb_putc(&b, '{'); + char tmp[80]; + snprintf(tmp, sizeof(tmp), "\"layer_id\":%u", L->layer_id); + jb_puts(&b, tmp); + jb_puts(&b, ",\"name\":"); + jb_emit_escaped(&b, L->name); + snprintf(tmp, sizeof(tmp), ",\"activation_priority\":%u", L->activation_priority); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"suppressible\":%d", L->suppressible ? 1 : 0); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"transparent\":%d", L->transparent ? 1 : 0); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"injectable\":%d", L->injectable ? 1 : 0); + jb_puts(&b, tmp); + jb_putc(&b, '}'); + } + jb_puts(&b, "]}"); + FILE* f = fopen(p, "wb"); + if (!f) { free(b.buf); return 0; } + size_t w = fwrite(b.buf, 1, b.len, f); + fclose(f); + int ok = (w == b.len); + free(b.buf); + return ok ? 1 : 0; +} + +/* Helper: extract a string field from a JSON object substring. */ +static char* eg_get_str_field(const char* obj, const char* key) { + const char* p = json_find_key(obj, key); + if (!p) return el_strdup(""); + if (*p != '"') return el_strdup(""); + JsonParser jp = { .p = p, .end = p + strlen(p), .err = 0 }; + char* out = jp_parse_string_raw(&jp); + if (jp.err) { free(out); return el_strdup(""); } + return out; +} + +static double eg_get_num_field(const char* obj, const char* key) { + const char* p = json_find_key(obj, key); + if (!p || *p == '"' || *p == '{' || *p == '[') return 0.0; + return strtod(p, NULL); +} + +static int64_t eg_get_int_field(const char* obj, const char* key) { + const char* p = json_find_key(obj, key); + if (!p || *p == '"' || *p == '{' || *p == '[') return 0; + return strtoll(p, NULL, 10); +} + +/* Iterate the top-level nodes/edges arrays in a saved snapshot. */ +static const char* eg_skip_ws(const char* p) { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + return p; +} + +el_val_t engram_load(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p || !*p) return 0; + FILE* f = fopen(p, "rb"); + if (!f) return 0; + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + if (sz <= 0) { fclose(f); return 0; } + char* data = malloc((size_t)sz + 1); + if (!data) { fclose(f); return 0; } + size_t got = fread(data, 1, (size_t)sz, f); + fclose(f); + data[got] = '\0'; + + /* Reset store */ + EngramStore* g = engram_get(); + for (int64_t i = 0; i < g->node_count; i++) { + free(g->nodes[i].id); free(g->nodes[i].content); free(g->nodes[i].node_type); + free(g->nodes[i].label); free(g->nodes[i].tier); free(g->nodes[i].tags); + free(g->nodes[i].metadata); + } + g->node_count = 0; + for (int64_t i = 0; i < g->edge_count; i++) { + free(g->edges[i].id); free(g->edges[i].from_id); free(g->edges[i].to_id); + free(g->edges[i].relation); free(g->edges[i].metadata); + } + g->edge_count = 0; + + /* Walk nodes array */ + const char* nodes_p = json_find_key(data, "nodes"); + if (nodes_p) { + nodes_p = eg_skip_ws(nodes_p); + if (*nodes_p == '[') { + nodes_p++; + nodes_p = eg_skip_ws(nodes_p); + while (*nodes_p && *nodes_p != ']') { + if (*nodes_p != '{') { nodes_p++; continue; } + const char* end = json_skip_value(nodes_p); + size_t n = (size_t)(end - nodes_p); + char* obj = malloc(n + 1); + memcpy(obj, nodes_p, n); obj[n] = '\0'; + engram_grow_nodes(); + EngramNode* nn = &g->nodes[g->node_count]; + memset(nn, 0, sizeof(*nn)); + nn->id = eg_get_str_field(obj, "id"); + nn->content = eg_get_str_field(obj, "content"); + nn->node_type = eg_get_str_field(obj, "node_type"); + nn->label = eg_get_str_field(obj, "label"); + nn->tier = eg_get_str_field(obj, "tier"); + nn->tags = eg_get_str_field(obj, "tags"); + nn->metadata = eg_get_str_field(obj, "metadata"); + if (!nn->metadata || !*nn->metadata) { free(nn->metadata); nn->metadata = el_strdup("{}"); } + nn->salience = eg_get_num_field(obj, "salience"); + nn->importance = eg_get_num_field(obj, "importance"); + nn->confidence = eg_get_num_field(obj, "confidence"); + nn->temporal_decay_rate = eg_get_num_field(obj, "temporal_decay_rate"); + /* temporal_decay_rate defaults to 0 (use global) if absent in snapshot */ + nn->activation_count = eg_get_int_field(obj, "activation_count"); + nn->last_activated = eg_get_int_field(obj, "last_activated"); + nn->created_at = eg_get_int_field(obj, "created_at"); + nn->updated_at = eg_get_int_field(obj, "updated_at"); + nn->background_activation = eg_get_num_field(obj, "background_activation"); + nn->working_memory_weight = eg_get_num_field(obj, "working_memory_weight"); + nn->suppression_count = (int32_t)eg_get_int_field(obj, "suppression_count"); + /* layer_id defaults to ENGRAM_LAYER_DEFAULT (core-identity) + * for snapshots that predate the layered schema. We can't + * tell "explicit 0" from "missing field" using the helper + * directly, so probe for the key — if absent, fall back. */ + if (json_find_key(obj, "layer_id")) { + nn->layer_id = (uint32_t)eg_get_int_field(obj, "layer_id"); + } else { + nn->layer_id = ENGRAM_LAYER_DEFAULT; + } + g->node_count++; + free(obj); + nodes_p = end; + nodes_p = eg_skip_ws(nodes_p); + if (*nodes_p == ',') { nodes_p++; nodes_p = eg_skip_ws(nodes_p); } + } + } + } + /* Walk edges array */ + const char* edges_p = json_find_key(data, "edges"); + if (edges_p) { + edges_p = eg_skip_ws(edges_p); + if (*edges_p == '[') { + edges_p++; + edges_p = eg_skip_ws(edges_p); + while (*edges_p && *edges_p != ']') { + if (*edges_p != '{') { edges_p++; continue; } + const char* end = json_skip_value(edges_p); + size_t n = (size_t)(end - edges_p); + char* obj = malloc(n + 1); + memcpy(obj, edges_p, n); obj[n] = '\0'; + engram_grow_edges(); + EngramEdge* ee = &g->edges[g->edge_count]; + memset(ee, 0, sizeof(*ee)); + ee->id = eg_get_str_field(obj, "id"); + ee->from_id = eg_get_str_field(obj, "from_id"); + ee->to_id = eg_get_str_field(obj, "to_id"); + ee->relation = eg_get_str_field(obj, "relation"); + ee->metadata = eg_get_str_field(obj, "metadata"); + if (!ee->metadata || !*ee->metadata) { free(ee->metadata); ee->metadata = el_strdup("{}"); } + ee->weight = eg_get_num_field(obj, "weight"); + ee->confidence = eg_get_num_field(obj, "confidence"); + ee->created_at = eg_get_int_field(obj, "created_at"); + ee->updated_at = eg_get_int_field(obj, "updated_at"); + ee->last_fired = eg_get_int_field(obj, "last_fired"); + ee->inhibitory = (int)eg_get_int_field(obj, "inhibitory"); + if (json_find_key(obj, "layer_id")) { + ee->layer_id = (uint32_t)eg_get_int_field(obj, "layer_id"); + } else { + ee->layer_id = ENGRAM_LAYER_DEFAULT; + } + g->edge_count++; + free(obj); + edges_p = end; + edges_p = eg_skip_ws(edges_p); + if (*edges_p == ',') { edges_p++; edges_p = eg_skip_ws(edges_p); } + } + } + } + /* Walk layers array (optional — older snapshots omit this). + * If present we replace the canonical registry entirely; if absent we + * keep whatever the engram_get() init established. */ + const char* layers_p = json_find_key(data, "layers"); + if (layers_p) { + layers_p = eg_skip_ws(layers_p); + if (*layers_p == '[') { + /* Reset existing layer registry. Free strdup'd names; the + * struct array itself can be reused. */ + for (size_t i = 0; i < g->layer_count; i++) { + if (g->layers[i].name) free(g->layers[i].name); + g->layers[i].name = NULL; + } + g->layer_count = 0; + + layers_p++; + layers_p = eg_skip_ws(layers_p); + while (*layers_p && *layers_p != ']') { + if (*layers_p != '{') { layers_p++; continue; } + const char* end = json_skip_value(layers_p); + size_t n = (size_t)(end - layers_p); + char* obj = malloc(n + 1); + memcpy(obj, layers_p, n); obj[n] = '\0'; + if (g->layer_count >= g->layer_capacity) { + size_t nc = g->layer_capacity ? g->layer_capacity * 2 : 16; + EngramLayer* grown = realloc(g->layers, nc * sizeof(EngramLayer)); + if (!grown) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + memset(grown + g->layer_capacity, 0, + (nc - g->layer_capacity) * sizeof(EngramLayer)); + g->layers = grown; + g->layer_capacity = nc; + } + EngramLayer* L = &g->layers[g->layer_count]; + memset(L, 0, sizeof(*L)); + L->layer_id = (uint32_t)eg_get_int_field(obj, "layer_id"); + L->activation_priority = (uint32_t)eg_get_int_field(obj, "activation_priority"); + L->suppressible = (int)eg_get_int_field(obj, "suppressible") ? 1 : 0; + L->transparent = (int)eg_get_int_field(obj, "transparent") ? 1 : 0; + L->injectable = (int)eg_get_int_field(obj, "injectable") ? 1 : 0; + char* nm = eg_get_str_field(obj, "name"); + if (nm && *nm) { + L->name = el_strdup_persist(nm); + free(nm); + } else { + free(nm); + L->name = el_strdup_persist(""); + } + g->layer_count++; + free(obj); + layers_p = end; + layers_p = eg_skip_ws(layers_p); + if (*layers_p == ',') { layers_p++; layers_p = eg_skip_ws(layers_p); } + } + } + } + free(data); + return 1; +} + +/* ── Engram JSON-string accessors ───────────────────────────────────────── + * These return pre-serialized JSON strings so callers (especially HTTP + * handlers) don't have to round-trip ElList/ElMap through json_stringify + * — which can't reliably distinguish those structures from raw pointers + * due to el_val_t's type erasure. The runtime knows the real C types and + * can serialize directly. */ + +el_val_t engram_get_node_json(el_val_t id) { + const char* sid = EL_CSTR(id); + EngramNode* n = engram_find_node(sid); + if (!n) return el_wrap_str(el_strdup("{}")); + JsonBuf b; jb_init(&b); + engram_emit_node_json(&b, n); + return el_wrap_str(b.buf); +} + +el_val_t engram_search_json(el_val_t query, el_val_t limit) { + EngramStore* g = engram_get(); + const char* q = EL_CSTR(query); + int64_t lim = (int64_t)limit; + if (lim <= 0) lim = 100; + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + int first = 1; + int64_t found = 0; + if (q && *q) { + for (int64_t i = 0; i < g->node_count && found < lim; i++) { + EngramNode* n = &g->nodes[i]; + /* Filter transparent layers — same as engram_search. */ + if (engram_layer_is_transparent(n->layer_id)) continue; + if (istr_contains(n->content, q) || + istr_contains(n->label, q) || + istr_contains(n->tags, q)) { + if (!first) jb_putc(&b, ','); + engram_emit_node_json(&b, n); + first = 0; + found++; + } + } + } + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +el_val_t engram_scan_nodes_json(el_val_t limit, el_val_t offset) { + EngramStore* g = engram_get(); + int64_t lim = (int64_t)limit; if (lim <= 0) lim = 100; + int64_t off = (int64_t)offset; if (off < 0) off = 0; + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + if (g->node_count == 0) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + int64_t* idx = malloc((size_t)g->node_count * sizeof(int64_t)); + if (!idx) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + /* Skip transparent layers — introspection filter, same as engram_scan_nodes. */ + int64_t live = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (engram_layer_is_transparent(g->nodes[i].layer_id)) continue; + idx[live++] = i; + } + engram_sort_indices_by_salience(idx, live, g->nodes); + int64_t end = off + lim; + if (end > live) end = live; + int first = 1; + for (int64_t i = off; i < end; i++) { + if (!first) jb_putc(&b, ','); + engram_emit_node_json(&b, &g->nodes[idx[i]]); + first = 0; + } + free(idx); + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +/* engram_scan_nodes_by_type_json — filter by node_type before paginating. + * Empty / NULL type_v falls back to the unfiltered scan (existing behaviour). + * Result is JSON array, salience-sorted, transparent layers skipped. */ +el_val_t engram_scan_nodes_by_type_json(el_val_t type_v, el_val_t limit, el_val_t offset) { + const char* type_filter = EL_CSTR(type_v); + if (!type_filter || !*type_filter) { + return engram_scan_nodes_json(limit, offset); + } + EngramStore* g = engram_get(); + int64_t lim = (int64_t)limit; if (lim <= 0) lim = 100; + int64_t off = (int64_t)offset; if (off < 0) off = 0; + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + if (g->node_count == 0) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + int64_t* idx = malloc((size_t)g->node_count * sizeof(int64_t)); + if (!idx) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + int64_t live = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (engram_layer_is_transparent(g->nodes[i].layer_id)) continue; + const char* nt = g->nodes[i].node_type; + if (!nt || strcmp(nt, type_filter) != 0) continue; + idx[live++] = i; + } + engram_sort_indices_by_salience(idx, live, g->nodes); + int64_t end = off + lim; + if (end > live) end = live; + int first = 1; + for (int64_t i = off; i < end; i++) { + if (!first) jb_putc(&b, ','); + engram_emit_node_json(&b, &g->nodes[idx[i]]); + first = 0; + } + free(idx); + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +el_val_t engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction) { + /* Re-implement here directly so we serialize without going through + * the ElList path. Walks BFS to max_depth, emits {node, edge, hops} + * triples. */ + EngramStore* g = engram_get(); + const char* sid = EL_CSTR(node_id); + int64_t depth = (int64_t)max_depth; if (depth <= 0) depth = 1; + const char* dir = EL_CSTR(direction); if (!dir) dir = "both"; + int allow_out = (strcmp(dir, "out") == 0) || (strcmp(dir, "both") == 0); + int allow_in = (strcmp(dir, "in") == 0) || (strcmp(dir, "both") == 0); + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + if (!sid || !*sid) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + + /* Frontier of (node_id, hops). Cap to a sane size. */ + char** frontier = calloc(1024, sizeof(char*)); + int64_t* frontier_h = calloc(1024, sizeof(int64_t)); + int64_t fc = 0; + char** visited = calloc(1024, sizeof(char*)); + int64_t vc = 0; + if (!frontier || !frontier_h || !visited) { + free(frontier); free(frontier_h); free(visited); + jb_putc(&b, ']'); return el_wrap_str(b.buf); + } + /* Use plain strdup (not el_strdup) so arena doesn't track these pointers. + * The BFS loop manually frees them below — arena would double-free them. */ + frontier[fc] = strdup(sid); frontier_h[fc] = 0; fc++; + visited[vc++] = strdup(sid); + + int first = 1; + while (fc > 0) { + char* cur = frontier[0]; int64_t h = frontier_h[0]; + for (int64_t k = 1; k < fc; k++) { frontier[k-1] = frontier[k]; frontier_h[k-1] = frontier_h[k]; } + fc--; + if (h >= depth) { free(cur); continue; } + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + const char* peer = NULL; + if (allow_out && e->from_id && strcmp(e->from_id, cur) == 0) peer = e->to_id; + else if (allow_in && e->to_id && strcmp(e->to_id, cur) == 0) peer = e->from_id; + if (!peer) continue; + int seen = 0; + for (int64_t v = 0; v < vc; v++) { + if (strcmp(visited[v], peer) == 0) { seen = 1; break; } + } + if (seen) continue; + EngramNode* n = engram_find_node(peer); + if (!n) continue; + if (!first) jb_putc(&b, ','); + jb_puts(&b, "{\"node\":"); + engram_emit_node_json(&b, n); + jb_puts(&b, ",\"edge\":"); + engram_emit_edge_json(&b, e); + char tmp[64]; snprintf(tmp, sizeof(tmp), ",\"hops\":%lld}", (long long)(h + 1)); + jb_puts(&b, tmp); + first = 0; + if (vc < 1024) visited[vc++] = strdup(peer); + if (fc < 1024 && h + 1 < depth) { frontier[fc] = strdup(peer); frontier_h[fc] = h + 1; fc++; } + } + free(cur); + } + for (int64_t i = 0; i < fc; i++) free(frontier[i]); + for (int64_t i = 0; i < vc; i++) free(visited[i]); + free(frontier); free(frontier_h); free(visited); + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +el_val_t engram_activate_json(el_val_t query, el_val_t depth) { + /* Run two-layer engram_activate and serialize the result list to JSON. + * Each entry includes both activation_strength (layer 1 background) and + * working_memory_weight (layer 2 executive filter), plus promoted flag. + * Callers performing context compilation should filter to promoted=1. */ + el_val_t lst = engram_activate(query, depth); + ElList* arr = (ElList*)(uintptr_t)lst; + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + if (arr) { + for (int64_t i = 0; i < arr->length; i++) { + if (!arr->elems[i]) continue; + el_val_t node_map = el_map_get(arr->elems[i], EL_STR("node")); + el_val_t strength_v = el_map_get(arr->elems[i], EL_STR("activation_strength")); + el_val_t wm_v = el_map_get(arr->elems[i], EL_STR("working_memory_weight")); + el_val_t epist_v = el_map_get(arr->elems[i], EL_STR("epistemic_confidence")); + el_val_t hops_v = el_map_get(arr->elems[i], EL_STR("hops")); + el_val_t promoted_v = el_map_get(arr->elems[i], EL_STR("promoted")); + /* Look up underlying EngramNode by id to emit canonical JSON. */ + el_val_t id_v = el_map_get(node_map, EL_STR("id")); + const char* id_s = EL_CSTR(id_v); + EngramNode* n = id_s ? engram_find_node(id_s) : NULL; + if (i > 0) jb_putc(&b, ','); + jb_puts(&b, "{\"node\":"); + if (n) { + engram_emit_node_json(&b, n); + } else { + jb_puts(&b, "{}"); + } + char tmp[80]; + snprintf(tmp, sizeof(tmp), ",\"activation_strength\":%g", el_to_float(strength_v)); jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"working_memory_weight\":%g", el_to_float(wm_v)); jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"epistemic_confidence\":%g", el_to_float(epist_v)); jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"hops\":%lld", (long long)(int64_t)hops_v); jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"promoted\":%d}", (int)(int64_t)promoted_v); jb_puts(&b, tmp); + } + } + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +el_val_t engram_stats_json(void) { + EngramStore* g = engram_get(); + char buf[128]; + snprintf(buf, sizeof(buf), + "{\"node_count\":%lld,\"edge_count\":%lld,\"layer_count\":%zu}", + (long long)g->node_count, (long long)g->edge_count, g->layer_count); + return el_wrap_str(el_strdup(buf)); +} + +/* engram_list_layers_json — serialized counterpart of engram_list_layers. + * Returns a JSON array, sorted by activation_priority ascending. */ +el_val_t engram_list_layers_json(void) { + EngramStore* g = engram_get(); + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + /* Build a sorted index over live layers. */ + size_t* idx = malloc((g->layer_count + 1) * sizeof(size_t)); + if (!idx) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + size_t live = 0; + for (size_t i = 0; i < g->layer_count; i++) { + if (g->layers[i].name) idx[live++] = i; + } + for (size_t i = 1; i < live; i++) { + size_t key = idx[i]; + uint32_t kp = g->layers[key].activation_priority; + size_t j = i; + while (j > 0 && g->layers[idx[j - 1]].activation_priority > kp) { + idx[j] = idx[j - 1]; + j--; + } + idx[j] = key; + } + int first = 1; + for (size_t i = 0; i < live; i++) { + EngramLayer* L = &g->layers[idx[i]]; + if (!first) jb_putc(&b, ','); + first = 0; + jb_putc(&b, '{'); + char tmp[80]; + snprintf(tmp, sizeof(tmp), "\"layer_id\":%u", L->layer_id); jb_puts(&b, tmp); + jb_puts(&b, ",\"name\":"); + jb_emit_escaped(&b, L->name ? L->name : ""); + snprintf(tmp, sizeof(tmp), ",\"activation_priority\":%u", L->activation_priority); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"suppressible\":%d", L->suppressible ? 1 : 0); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"transparent\":%d", L->transparent ? 1 : 0); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"injectable\":%d", L->injectable ? 1 : 0); + jb_puts(&b, tmp); + jb_putc(&b, '}'); + } + free(idx); + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +/* engram_compile_layered_json — produce a prompt-ready context block split + * by layer. + * + * Runs the three-pass activation, then partitions promoted nodes by layer + * suppressibility: + * - Non-suppressible (Layer 0 / structural-floor) layers go FIRST under + * the heading "[LAYER 0 — STRUCTURAL]". These are the sacred-fire + * nodes that surfaced via the pass-3 override. + * - All other promoted layers go SECOND under "[ENGRAM CONTEXT]". + * + * Output is a single JSON-string el_val_t: a UTF-8 text block ready to be + * concatenated into a system prompt. Returns "" if no nodes promoted. + * + * Transparent layers (Layer 0) are emitted into the prompt — they shape + * the model's output — but engram_search and friends still hide them from + * introspection-style queries. The split heading lets the LLM weight them + * appropriately without revealing their internal label. + * + * Each emitted line for a node is its raw JSON (matching engram_emit_node_json) + * so downstream JSON parsers can still walk individual records inside the + * formatted block. The block is plain text, not a JSON document — callers + * concatenating it into a prompt should treat it as opaque markdown. */ +el_val_t engram_compile_layered_json(el_val_t intent, el_val_t depth) { + EngramStore* g = engram_get(); + /* Run the three-pass activator. We need the persisted node fields, so + * call engram_activate (it writes background_activation and + * working_memory_weight back into the store). */ + (void)engram_activate(intent, depth); + + /* Walk the store and partition by suppressibility. */ + JsonBuf b; jb_init(&b); + int wrote_layer0 = 0; + int wrote_normal = 0; + + /* Sort indices by working_memory_weight descending so the most + * confidently promoted nodes appear first within each section. */ + int64_t* idx = malloc((size_t)(g->node_count + 1) * sizeof(int64_t)); + if (!idx) return el_wrap_str(el_strdup("")); + int64_t mc = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (g->nodes[i].working_memory_weight > 0.0) idx[mc++] = i; + } + for (int64_t i = 1; i < mc; i++) { + int64_t key = idx[i]; + double kw = g->nodes[key].working_memory_weight; + int64_t j = i; + while (j > 0 && g->nodes[idx[j - 1]].working_memory_weight < kw) { + idx[j] = idx[j - 1]; + j--; + } + idx[j] = key; + } + + /* Section 1: structural floor (non-suppressible layers). */ + for (int64_t i = 0; i < mc; i++) { + EngramNode* n = &g->nodes[idx[i]]; + if (engram_layer_is_suppressible(n->layer_id)) continue; + if (!wrote_layer0) { + jb_puts(&b, "[LAYER 0 — STRUCTURAL]\n"); + wrote_layer0 = 1; + } + engram_emit_node_json(&b, n); + jb_putc(&b, '\n'); + } + + /* Section 2: standard engram context (suppressible layers). */ + for (int64_t i = 0; i < mc; i++) { + EngramNode* n = &g->nodes[idx[i]]; + if (!engram_layer_is_suppressible(n->layer_id)) continue; + if (!wrote_normal) { + if (wrote_layer0) jb_putc(&b, '\n'); + jb_puts(&b, "[ENGRAM CONTEXT]\n"); + wrote_normal = 1; + } + engram_emit_node_json(&b, n); + jb_putc(&b, '\n'); + } + + free(idx); + if (b.len == 0) { + free(b.buf); + return el_wrap_str(el_strdup("")); + } + return el_wrap_str(b.buf); +} + +/* engram_query_range — temporal range query. + * Returns a JSON array of nodes whose created_at OR last_activated falls + * within [start_ms, end_ms], sorted by created_at ascending. + * Enables "what was I working on last Tuesday?" style queries by passing + * unix-millisecond timestamps for the start and end of the target interval. + * Both endpoints are inclusive. Pass 0 for start_ms to mean "beginning of + * time"; pass 0 for end_ms to mean "now". */ +el_val_t engram_query_range(el_val_t start_ms_v, el_val_t end_ms_v) { + EngramStore* g = engram_get(); + int64_t start_ms = (int64_t)start_ms_v; + int64_t end_ms = (int64_t)end_ms_v; + if (end_ms <= 0) end_ms = engram_now_ms(); + + /* Collect matching indices. */ + int64_t* idx = malloc((size_t)g->node_count * sizeof(int64_t)); + if (!idx) return el_wrap_str(el_strdup("[]")); + int64_t mc = 0; + for (int64_t i = 0; i < g->node_count; i++) { + EngramNode* n = &g->nodes[i]; + int in_created = (n->created_at >= start_ms && n->created_at <= end_ms); + int in_activated = (n->last_activated >= start_ms && n->last_activated <= end_ms); + if (in_created || in_activated) idx[mc++] = i; + } + /* Sort by created_at ascending (insertion sort — N is small in practice). */ + for (int64_t i = 1; i < mc; i++) { + int64_t key = idx[i]; + int64_t kts = g->nodes[key].created_at; + int64_t j = i - 1; + while (j >= 0 && g->nodes[idx[j]].created_at > kts) { + idx[j + 1] = idx[j]; + j--; + } + idx[j + 1] = key; + } + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + for (int64_t i = 0; i < mc; i++) { + if (i > 0) jb_putc(&b, ','); + engram_emit_node_json(&b, &g->nodes[idx[i]]); + } + jb_putc(&b, ']'); + free(idx); + return el_wrap_str(b.buf); +} + +/* ── engram_apply_decay_json — temporal decay maintenance ──────────────────── + * + * Iterates ALL nodes and applies temporal decay to their stored `salience` + * field based on time elapsed since `last_activated`: + * + * new_salience = current_salience * decay_rate ^ hours_since_activation + * + * where decay_rate defaults to 0.5^(1/168) per hour (half-life one week), + * or the node's own `temporal_decay_rate` if non-zero. + * + * Nodes with temporal_decay_rate == 0 are NOT immune — the global default + * applies. To make a node truly immune, set temporal_decay_rate to a very + * small positive value (e.g. 0.0001). Nodes that are "pinned" can be + * identified by a tier of "Procedural" — those are skipped. + * + * After updating salience, nodes with salience < 0.05 AND tier == "Working" + * are pruned (deleted) unless they have no content (guard against garbage). + * + * Returns a JSON summary: {"updated": N, "pruned": N} */ +el_val_t engram_apply_decay_json(void) { + EngramStore* g = engram_get(); + int64_t now_ms = engram_now_ms(); + int64_t updated = 0, pruned = 0; + + for (int64_t i = 0; i < g->node_count; i++) { + EngramNode* n = &g->nodes[i]; + /* Skip Procedural nodes (they are "locked in"). */ + if (n->tier && strcmp(n->tier, "Procedural") == 0) continue; + int64_t age_ms = now_ms - n->last_activated; + if (age_ms <= 0) continue; + double lambda = (n->temporal_decay_rate > 0.0) ? n->temporal_decay_rate + : ENGRAM_DECAY_LAMBDA; + double age_hours = (double)age_ms / 3600000.0; + double decay_factor = exp(-lambda * age_hours / ENGRAM_T_HALF_HOURS); + double new_salience = n->salience * decay_factor; + if (new_salience < 0.0) new_salience = 0.0; + if (new_salience != n->salience) { + n->salience = new_salience; + n->updated_at = now_ms; + updated++; + } + } + + /* Prune low-salience Working nodes. Walk backwards to allow in-place + * removal without invalidating indices. */ + for (int64_t i = g->node_count - 1; i >= 0; i--) { + EngramNode* n = &g->nodes[i]; + if (n->salience >= 0.05) continue; + /* Only prune Working tier nodes — higher tiers are protected. */ + if (!n->tier || strcmp(n->tier, "Working") != 0) continue; + /* Guard: skip nodes with no content. */ + if (!n->content || !*n->content) continue; + /* Free node strings. */ + free(n->id); free(n->content); free(n->node_type); free(n->label); + free(n->tier); free(n->tags); free(n->metadata); + /* Shift remaining nodes down. */ + for (int64_t j = i + 1; j < g->node_count; j++) { + g->nodes[j - 1] = g->nodes[j]; + } + g->node_count--; + memset(&g->nodes[g->node_count], 0, sizeof(EngramNode)); + pruned++; + } + + /* Remove dangling edges for pruned nodes (any edge whose endpoint no + * longer exists in the node list). */ + if (pruned > 0) { + int64_t w = 0; + for (int64_t r = 0; r < g->edge_count; r++) { + EngramEdge* e = &g->edges[r]; + int dangling = 0; + if (e->from_id && engram_find_node_index(e->from_id) < 0) dangling = 1; + if (e->to_id && engram_find_node_index(e->to_id) < 0) dangling = 1; + if (dangling) { + free(e->id); free(e->from_id); free(e->to_id); + free(e->relation); free(e->metadata); + } else { + if (w != r) g->edges[w] = g->edges[r]; + w++; + } + } + g->edge_count = w; + } + + char buf[128]; + snprintf(buf, sizeof(buf), + "{\"ok\":true,\"updated\":%lld,\"pruned\":%lld}", + (long long)updated, (long long)pruned); + return el_wrap_str(el_strdup(buf)); +} + +#ifdef HAVE_CURL +/* ── DHARMA network ───────────────────────────────────────────────────────── + * Real implementation. Peers are addressed by `dharma_id` — either bare + * (e.g. "ntn-genesis", transport defaults to http://localhost:7770) or + * "@" where is the peer's Engram-exposed daemon. + * + * Channels are logical handles cached per-cgi: `dharma_connect` is + * idempotent and returns "ch:". The channel registry below tracks + * every cgi_id we've connected to and its resolved transport URL. + * + * Relationship weights live in the local Engram graph: edges of type + * "dharma-relation" between a synthetic local node ("dharma:self") and + * synthetic peer nodes ("dharma:peer:"). Hebbian increments + * accumulate in EngramEdge.weight, clamped to [0.0, 1.0]. + * + * Events arrive over HTTP via the application's request handler, which is + * expected to call el_runtime_dharma_event_arrive() when it sees a + * /dharma/event POST. dharma_field() blocks on a per-event-type queue. + */ + +#define DHARMA_DEFAULT_URL "http://localhost:7770" + +/* Channel registry — one entry per known peer. */ +typedef struct DharmaChannel { + char* cgi_id; /* full dharma_id including any @ suffix */ + char* base_id; /* registry-id portion (before @) for relationship lookup */ + char* url; /* resolved transport URL */ + char* channel_id; /* "ch:" */ +} DharmaChannel; + +static DharmaChannel* _dharma_channels = NULL; +static size_t _dharma_channel_count = 0; +static size_t _dharma_channel_cap = 0; +static pthread_mutex_t _dharma_channel_mu = PTHREAD_MUTEX_INITIALIZER; + +/* Event queue — per-type linked list. dharma_field blocks on _dharma_event_cv. */ +typedef struct DharmaEvent { + char* event_type; + char* payload; + char* source; + int64_t timestamp; + struct DharmaEvent* next; +} DharmaEvent; + +static DharmaEvent* _dharma_event_head = NULL; +static DharmaEvent* _dharma_event_tail = NULL; +static pthread_mutex_t _dharma_event_mu = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t _dharma_event_cv = PTHREAD_COND_INITIALIZER; + +/* Split "@" → (base_id, url). If no "@", base_id = full, url = default. + * Returned strings are heap-allocated; caller must free. */ +static void dharma_parse_id(const char* full, char** out_base, char** out_url) { + if (!full) full = ""; + const char* at = strchr(full, '@'); + if (at) { + size_t bn = (size_t)(at - full); + char* b = malloc(bn + 1); + memcpy(b, full, bn); b[bn] = '\0'; + *out_base = b; + *out_url = el_strdup(at + 1); + if (!**out_url) { free(*out_url); *out_url = el_strdup(DHARMA_DEFAULT_URL); } + } else { + *out_base = el_strdup(full); + *out_url = el_strdup(DHARMA_DEFAULT_URL); + } +} + +/* Find existing channel by full cgi_id. Caller must hold _dharma_channel_mu. */ +static DharmaChannel* dharma_find_channel_locked(const char* cgi_id) { + if (!cgi_id) return NULL; + for (size_t i = 0; i < _dharma_channel_count; i++) { + if (_dharma_channels[i].cgi_id && + strcmp(_dharma_channels[i].cgi_id, cgi_id) == 0) { + return &_dharma_channels[i]; + } + } + return NULL; +} + +/* Add a new channel entry. Caller must hold _dharma_channel_mu. */ +static DharmaChannel* dharma_add_channel_locked(const char* cgi_id) { + if (_dharma_channel_count >= _dharma_channel_cap) { + size_t nc = _dharma_channel_cap ? _dharma_channel_cap * 2 : 8; + _dharma_channels = realloc(_dharma_channels, nc * sizeof(DharmaChannel)); + if (!_dharma_channels) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + memset(_dharma_channels + _dharma_channel_cap, 0, + (nc - _dharma_channel_cap) * sizeof(DharmaChannel)); + _dharma_channel_cap = nc; + } + DharmaChannel* ch = &_dharma_channels[_dharma_channel_count++]; + char* base = NULL; char* url = NULL; + dharma_parse_id(cgi_id, &base, &url); + ch->cgi_id = el_strdup(cgi_id ? cgi_id : ""); + ch->base_id = base; + ch->url = url; + size_t cn = strlen(ch->cgi_id) + 4; + ch->channel_id = malloc(cn); + snprintf(ch->channel_id, cn, "ch:%s", ch->cgi_id); + return ch; +} + +el_val_t dharma_connect(el_val_t cgi_id) { + const char* id = EL_CSTR(cgi_id); + if (!id || !*id) return el_wrap_str(el_strdup("")); + pthread_mutex_lock(&_dharma_channel_mu); + DharmaChannel* ch = dharma_find_channel_locked(id); + if (!ch) ch = dharma_add_channel_locked(id); + char* out = el_strdup(ch->channel_id); + pthread_mutex_unlock(&_dharma_channel_mu); + return el_wrap_str(out); +} + +/* Build an error JSON body — same shape http_error_json uses. */ +static el_val_t dharma_error_json(const char* msg) { + return http_error_json(msg); +} + +el_val_t dharma_send(el_val_t channel, el_val_t content) { + const char* ch_id = EL_CSTR(channel); + const char* msg = EL_CSTR(content); + if (!ch_id || strncmp(ch_id, "ch:", 3) != 0) { + return dharma_error_json("invalid channel"); + } + const char* peer_id = ch_id + 3; + /* Look up channel; if unknown (caller fabricated), auto-register. */ + pthread_mutex_lock(&_dharma_channel_mu); + DharmaChannel* ch = dharma_find_channel_locked(peer_id); + if (!ch) ch = dharma_add_channel_locked(peer_id); + char* url = el_strdup(ch->url); + pthread_mutex_unlock(&_dharma_channel_mu); + /* Build /dharma/recv body. */ + const char* from = _el_cgi_dharma_id ? _el_cgi_dharma_id : "(unknown)"; + char* esc_ch = json_escape_alloc(ch_id); + char* esc_from = json_escape_alloc(from); + char* esc_msg = json_escape_alloc(msg ? msg : ""); + JsonBuf b; jb_init(&b); + jb_puts(&b, "{\"channel\":\""); jb_puts(&b, esc_ch); + jb_puts(&b, "\",\"from\":\""); jb_puts(&b, esc_from); + jb_puts(&b, "\",\"content\":\""); jb_puts(&b, esc_msg); + jb_puts(&b, "\"}"); + free(esc_ch); free(esc_from); free(esc_msg); + size_t ul = strlen(url) + 16; + char* full_url = malloc(ul); + snprintf(full_url, ul, "%s/dharma/recv", url); + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + el_val_t resp = http_do("POST", full_url, b.buf, h); + curl_slist_free_all(h); + free(b.buf); free(full_url); free(url); + return resp; +} + +el_val_t dharma_activate(el_val_t query) { + const char* q = EL_CSTR(query); + if (!q) q = ""; + el_val_t out = el_list_empty(); + char* esc_q = json_escape_alloc(q); + JsonBuf body; jb_init(&body); + jb_puts(&body, "{\"query\":\""); jb_puts(&body, esc_q); jb_puts(&body, "\"}"); + free(esc_q); + + /* Snapshot the channel list under lock so we can iterate without + * holding the mutex during network I/O. */ + pthread_mutex_lock(&_dharma_channel_mu); + size_t n = _dharma_channel_count; + char** urls = calloc(n ? n : 1, sizeof(char*)); + char** ids = calloc(n ? n : 1, sizeof(char*)); + char** bases = calloc(n ? n : 1, sizeof(char*)); + for (size_t i = 0; i < n; i++) { + urls[i] = el_strdup(_dharma_channels[i].url); + ids[i] = el_strdup(_dharma_channels[i].cgi_id); + bases[i] = el_strdup(_dharma_channels[i].base_id); + } + pthread_mutex_unlock(&_dharma_channel_mu); + + for (size_t i = 0; i < n; i++) { + size_t ul = strlen(urls[i]) + 32; + char* full_url = malloc(ul); + snprintf(full_url, ul, "%s/api/activate", urls[i]); + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + el_val_t resp = http_do("POST", full_url, body.buf, h); + curl_slist_free_all(h); + free(full_url); + const char* rs = EL_CSTR(resp); + if (!rs || !*rs) continue; + if (rs[0] == '{' && strstr(rs, "\"error\"")) continue; + + /* Look up relationship weight (attenuation). */ + double rel_weight = 1.0; + { + const char* self_id = "dharma:self"; + char peer_node[512]; + snprintf(peer_node, sizeof(peer_node), "dharma:peer:%s", bases[i]); + EngramStore* g = engram_get(); + for (int64_t k = 0; k < g->edge_count; k++) { + EngramEdge* e = &g->edges[k]; + if (e->from_id && e->to_id && + strcmp(e->from_id, self_id) == 0 && + strcmp(e->to_id, peer_node) == 0 && + e->relation && strcmp(e->relation, "dharma-relation") == 0) { + rel_weight = e->weight; + break; + } + } + } + + /* Iterate the response array. Expect either a top-level array + * or an object whose "results" field is an array. */ + const char* arr = rs; + while (*arr == ' ' || *arr == '\t' || *arr == '\n' || *arr == '\r') arr++; + char* arr_owned = NULL; + if (*arr == '{') { + el_val_t r = json_get_raw(EL_STR(rs), EL_STR("results")); + const char* rr = EL_CSTR(r); + if (rr && *rr == '[') { + arr_owned = el_strdup(rr); + arr = arr_owned; + } else { + continue; + } + } + if (*arr != '[') { free(arr_owned); continue; } + const char* p = arr + 1; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + while (*p && *p != ']') { + const char* end = json_skip_value(p); + size_t en = (size_t)(end - p); + char* obj = el_strbuf(en); + memcpy(obj, p, en); obj[en] = '\0'; + + /* Pull activation_strength if present, else 1.0. */ + el_val_t act_v = json_get_float(EL_STR(obj), EL_STR("activation_strength")); + double act = el_to_float(act_v); + if (!(act > 0.0 && act <= 100.0)) act = 1.0; + double final_act = act * rel_weight; + + el_val_t entry = el_map_new(0); + /* node = the inner JSON if present, else the entire obj. */ + el_val_t node_raw = json_get_raw(EL_STR(obj), EL_STR("node")); + const char* nr = EL_CSTR(node_raw); + entry = el_map_set(entry, EL_STR(el_strdup("node")), + (nr && *nr) ? node_raw : EL_STR(el_strdup(obj))); + entry = el_map_set(entry, EL_STR(el_strdup("source_cgi")), + EL_STR(el_strdup(ids[i]))); + entry = el_map_set(entry, EL_STR(el_strdup("activation_strength")), + el_from_float(final_act)); + out = el_list_append(out, entry); + free(obj); + p = end; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + } + free(arr_owned); + } + for (size_t i = 0; i < n; i++) { free(urls[i]); free(ids[i]); free(bases[i]); } + free(urls); free(ids); free(bases); + free(body.buf); + return out; +} + +void dharma_emit(el_val_t event_type, el_val_t payload) { + const char* et = EL_CSTR(event_type); + const char* pay = EL_CSTR(payload); + if (!et) et = ""; + if (!pay) pay = ""; + const char* src = _el_cgi_dharma_id ? _el_cgi_dharma_id : "(unknown)"; + int64_t ts = engram_now_ms(); + + char* esc_et = json_escape_alloc(et); + char* esc_pay = json_escape_alloc(pay); + char* esc_src = json_escape_alloc(src); + JsonBuf b; jb_init(&b); + jb_puts(&b, "{\"type\":\""); jb_puts(&b, esc_et); + jb_puts(&b, "\",\"payload\":\""); jb_puts(&b, esc_pay); + jb_puts(&b, "\",\"source\":\""); jb_puts(&b, esc_src); + jb_puts(&b, "\",\"timestamp\":"); jb_emit_int(&b, ts); + jb_putc(&b, '}'); + free(esc_et); free(esc_pay); free(esc_src); + + /* Snapshot URLs to avoid holding the channel mutex during I/O. */ + pthread_mutex_lock(&_dharma_channel_mu); + size_t n = _dharma_channel_count; + char** urls = calloc(n ? n : 1, sizeof(char*)); + for (size_t i = 0; i < n; i++) urls[i] = el_strdup(_dharma_channels[i].url); + pthread_mutex_unlock(&_dharma_channel_mu); + + for (size_t i = 0; i < n; i++) { + size_t ul = strlen(urls[i]) + 32; + char* full_url = malloc(ul); + snprintf(full_url, ul, "%s/dharma/event", urls[i]); + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + el_val_t r = http_do("POST", full_url, b.buf, h); + (void)r; /* fire-and-forget — emit is not synchronous */ + curl_slist_free_all(h); + free(full_url); + } + for (size_t i = 0; i < n; i++) free(urls[i]); + free(urls); + free(b.buf); +} + +void el_runtime_dharma_event_arrive(const char* event_type, const char* payload, + const char* source) { + DharmaEvent* ev = calloc(1, sizeof(DharmaEvent)); + if (!ev) return; + ev->event_type = el_strdup(event_type ? event_type : ""); + ev->payload = el_strdup(payload ? payload : ""); + ev->source = el_strdup(source ? source : ""); + ev->timestamp = engram_now_ms(); + ev->next = NULL; + pthread_mutex_lock(&_dharma_event_mu); + if (_dharma_event_tail) _dharma_event_tail->next = ev; + else _dharma_event_head = ev; + _dharma_event_tail = ev; + pthread_cond_broadcast(&_dharma_event_cv); + pthread_mutex_unlock(&_dharma_event_mu); +} + +el_val_t dharma_field(el_val_t event_type) { + const char* et = EL_CSTR(event_type); + if (!et) et = ""; + + /* Compute deadline: now + 30 seconds. */ + struct timespec deadline; + clock_gettime(CLOCK_REALTIME, &deadline); + deadline.tv_sec += 30; + + DharmaEvent* found = NULL; + pthread_mutex_lock(&_dharma_event_mu); + while (1) { + /* Scan queue for matching type; pop and return first match. */ + DharmaEvent* prev = NULL; + DharmaEvent* cur = _dharma_event_head; + while (cur) { + if (cur->event_type && strcmp(cur->event_type, et) == 0) { + if (prev) prev->next = cur->next; + else _dharma_event_head = cur->next; + if (_dharma_event_tail == cur) _dharma_event_tail = prev; + cur->next = NULL; + found = cur; + break; + } + prev = cur; cur = cur->next; + } + if (found) break; + int rc = pthread_cond_timedwait(&_dharma_event_cv, &_dharma_event_mu, &deadline); + if (rc == ETIMEDOUT) break; + } + pthread_mutex_unlock(&_dharma_event_mu); + + if (!found) return el_map_new(0); + el_val_t m = el_map_new(0); + m = el_map_set(m, EL_STR(el_strdup("type")), + EL_STR(el_strdup(found->event_type ? found->event_type : ""))); + m = el_map_set(m, EL_STR(el_strdup("payload")), + EL_STR(el_strdup(found->payload ? found->payload : ""))); + m = el_map_set(m, EL_STR(el_strdup("source_cgi")), + EL_STR(el_strdup(found->source ? found->source : ""))); + m = el_map_set(m, EL_STR(el_strdup("timestamp")), (el_val_t)found->timestamp); + free(found->event_type); free(found->payload); free(found->source); free(found); + return m; +} + +/* Locate (or create) the local "dharma:self" node and the synthetic peer + * node "dharma:peer:". Returns the index of the dharma-relation + * edge, or -1 if not found. If `create` is non-zero, ensure the nodes + * and edge exist (creating them as needed) and return the edge index. */ +static int64_t dharma_find_or_create_relation_edge(const char* peer_base, int create) { + if (!peer_base || !*peer_base) return -1; + EngramStore* g = engram_get(); + const char* self_id = "dharma:self"; + char peer_node[512]; + snprintf(peer_node, sizeof(peer_node), "dharma:peer:%s", peer_base); + + /* Look for the edge first. */ + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + if (e->from_id && e->to_id && + strcmp(e->from_id, self_id) == 0 && + strcmp(e->to_id, peer_node) == 0 && + e->relation && strcmp(e->relation, "dharma-relation") == 0) { + return i; + } + } + if (!create) return -1; + + /* Ensure self node exists. We use a fixed id (not engram_new_id) so + * subsequent calls reuse the same one. */ + if (!engram_find_node(self_id)) { + engram_grow_nodes(); + EngramNode* n = &g->nodes[g->node_count]; + memset(n, 0, sizeof(*n)); + n->id = el_strdup(self_id); + n->content = el_strdup(_el_cgi_dharma_id ? _el_cgi_dharma_id : "(self)"); + n->node_type = el_strdup("DharmaSelf"); + n->label = el_strdup("dharma:self"); + n->tier = el_strdup("Working"); + n->tags = el_strdup("dharma"); + n->metadata = el_strdup("{}"); + n->salience = 1.0; n->importance = 1.0; n->confidence = 1.0; + int64_t now = engram_now_ms(); + n->created_at = now; n->updated_at = now; n->last_activated = now; + n->layer_id = ENGRAM_LAYER_DEFAULT; + g->node_count++; + } + if (!engram_find_node(peer_node)) { + engram_grow_nodes(); + EngramNode* n = &g->nodes[g->node_count]; + memset(n, 0, sizeof(*n)); + n->id = el_strdup(peer_node); + n->content = el_strdup(peer_base); + n->node_type = el_strdup("DharmaPeer"); + n->label = el_strdup(peer_node); + n->tier = el_strdup("Working"); + n->tags = el_strdup("dharma"); + n->metadata = el_strdup("{}"); + n->salience = 0.5; n->importance = 0.5; n->confidence = 1.0; + int64_t now = engram_now_ms(); + n->created_at = now; n->updated_at = now; n->last_activated = now; + n->layer_id = ENGRAM_LAYER_DEFAULT; + g->node_count++; + } + /* Create the edge with weight 0.0 — caller will increment. */ + engram_grow_edges(); + EngramEdge* e = &g->edges[g->edge_count]; + memset(e, 0, sizeof(*e)); + e->id = engram_new_id(); + e->from_id = el_strdup(self_id); + e->to_id = el_strdup(peer_node); + e->relation = el_strdup("dharma-relation"); + e->metadata = el_strdup("{}"); + e->weight = 0.0; + e->confidence = 1.0; + int64_t now = engram_now_ms(); + e->created_at = now; e->updated_at = now; + e->layer_id = ENGRAM_LAYER_DEFAULT; + int64_t idx = g->edge_count; + g->edge_count++; + return idx; +} + +void dharma_strengthen(el_val_t cgi_id, el_val_t weight) { + const char* id = EL_CSTR(cgi_id); + if (!id || !*id) return; + char* base = NULL; char* url = NULL; + dharma_parse_id(id, &base, &url); + free(url); + int64_t ei = dharma_find_or_create_relation_edge(base, 1); + free(base); + if (ei < 0) return; + EngramStore* g = engram_get(); + double inc = engram_decode_score(weight); + if (!(inc >= 0.0)) inc = 0.0; + double w = g->edges[ei].weight + inc; + if (w < 0.0) w = 0.0; + if (w > 1.0) w = 1.0; + g->edges[ei].weight = w; + g->edges[ei].updated_at = engram_now_ms(); + g->edges[ei].last_fired = g->edges[ei].updated_at; +} + +el_val_t dharma_relationship(el_val_t cgi_id) { + const char* id = EL_CSTR(cgi_id); + if (!id || !*id) return el_from_float(0.0); + char* base = NULL; char* url = NULL; + dharma_parse_id(id, &base, &url); + free(url); + int64_t ei = dharma_find_or_create_relation_edge(base, 0); + free(base); + if (ei < 0) return el_from_float(0.0); + EngramStore* g = engram_get(); + return el_from_float(g->edges[ei].weight); +} + +el_val_t dharma_peers(void) { + /* Walk dharma-relation edges out of "dharma:self", weight > 0, sort desc. */ + EngramStore* g = engram_get(); + const char* self_id = "dharma:self"; + typedef struct { char* peer_base; double weight; } PeerEntry; + PeerEntry* peers = malloc((size_t)(g->edge_count + 1) * sizeof(PeerEntry)); + int64_t pcount = 0; + if (!peers) return el_list_empty(); + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + if (!e->from_id || !e->to_id) continue; + if (strcmp(e->from_id, self_id) != 0) continue; + if (!e->relation || strcmp(e->relation, "dharma-relation") != 0) continue; + if (e->weight <= 0.0) continue; + const char* prefix = "dharma:peer:"; + size_t pl = strlen(prefix); + if (strncmp(e->to_id, prefix, pl) != 0) continue; + peers[pcount].peer_base = el_strdup(e->to_id + pl); + peers[pcount].weight = e->weight; + pcount++; + } + /* Sort desc by weight. */ + for (int64_t i = 1; i < pcount; i++) { + PeerEntry key = peers[i]; + int64_t j = i - 1; + while (j >= 0 && peers[j].weight < key.weight) { + peers[j + 1] = peers[j]; j--; + } + peers[j + 1] = key; + } + el_val_t out = el_list_empty(); + for (int64_t i = 0; i < pcount; i++) { + out = el_list_append(out, EL_STR(peers[i].peer_base)); + } + free(peers); + return out; +} +#endif /* HAVE_CURL — DHARMA network */ + +/* ── Batch 4: LLM (Anthropic API client) ─────────────────────────────────── */ +/* + * All LLM builtins call https://api.anthropic.com/v1/messages with the API + * key from env ANTHROPIC_API_KEY. Default model is "claude-sonnet-4-5" + * when the supplied model is empty/null. + * + * `llm_call_agentic` runs a real multi-turn tool_use/tool_result loop. + * Tool handlers are registered with `llm_register_tool(name, fn_name)`, + * which dlsym()s the named symbol. Each tool handler has the C signature + * el_val_t handler(el_val_t input_json); + * and returns a JSON-string el_val_t result. Iteration is capped at 10. + */ + +#ifdef HAVE_CURL +static const char* LLM_DEFAULT_MODEL = "claude-sonnet-4-5"; +static const char* LLM_API_URL = "https://api.anthropic.com/v1/messages"; +static const char* LLM_VERSION = "2023-06-01"; + +static const char* llm_resolve_model(const char* m) { + if (!m || !*m) return LLM_DEFAULT_MODEL; + return m; +} + +/* + * ── Configurable LLM provider chain ────────────────────────────────────────── + * + * Providers are configured via indexed env vars. The runtime tries each in + * order (0, 1, 2, ...) and returns the first successful non-empty response. + * + * Per provider (N = 0, 1, 2, ...): + * NEURON_LLM_N_URL — endpoint URL (base URL; /v1/chat/completions appended + * if format is "openai" and not already in URL) + * NEURON_LLM_N_KEY — API key + * NEURON_LLM_N_FORMAT — "openai" (default) or "anthropic" + * NEURON_LLM_N_MODEL — model name override (optional) + * + * Example — Neuron inference primary, Anthropic fallback: + * NEURON_LLM_0_URL=https://soma.../v1/chat/completions + * NEURON_LLM_0_KEY=svc-key + * NEURON_LLM_0_FORMAT=openai + * NEURON_LLM_0_MODEL=neuron + * NEURON_LLM_1_URL=https://api.anthropic.com/v1/messages + * NEURON_LLM_1_KEY=sk-ant-... + * NEURON_LLM_1_FORMAT=anthropic + * + * If no NEURON_LLM_0_URL is set, falls back to legacy ANTHROPIC_API_KEY. + */ + +#define LLM_MAX_PROVIDERS 16 + +/* forward declarations */ +static el_val_t llm_extract_text(el_val_t resp_val); +static el_val_t llm_extract_text_openai(el_val_t resp_val); + +static el_val_t llm_extract_text_openai(el_val_t resp_val) { + const char* resp = EL_CSTR(resp_val); + if (!resp || !*resp) return el_wrap_str(el_strdup("")); + if (resp[0] == '{' && strstr(resp, "\"error\"")) return el_wrap_str(el_strdup("")); + const char* choices = json_find_key(resp, "choices"); + if (!choices || *choices != '[') return el_wrap_str(el_strdup("")); + choices++; + while (*choices == ' ' || *choices == '\t') choices++; + if (*choices != '{') return el_wrap_str(el_strdup("")); + const char* end = json_skip_value(choices); + size_t n = (size_t)(end - choices); + char* obj = malloc(n + 1); memcpy(obj, choices, n); obj[n] = '\0'; + const char* msg = json_find_key(obj, "message"); + if (!msg || *msg != '{') { free(obj); return el_wrap_str(el_strdup("")); } + const char* msg_end = json_skip_value(msg); + size_t mn = (size_t)(msg_end - msg); + char* msg_obj = malloc(mn + 1); memcpy(msg_obj, msg, mn); msg_obj[mn] = '\0'; + const char* content = json_find_key(msg_obj, "content"); + el_val_t result = el_wrap_str(el_strdup("")); + if (content && *content == '"') { + JsonParser jp = { .p = content, .end = content + strlen(content), .err = 0 }; + char* text = jp_parse_string_raw(&jp); + if (!jp.err && text) result = el_wrap_str(text); + } + free(msg_obj); free(obj); + return result; +} + +/* Send a request to one provider. Returns the raw response string. + * format: 0 = openai, 1 = anthropic */ +static el_val_t llm_provider_request(const char* url, const char* key, + int format, const char* model, + const char* system_str, + const char* user_str) { + char* esc_sys = system_str && *system_str ? json_escape_alloc(system_str) : NULL; + char* esc_user = json_escape_alloc(user_str ? user_str : ""); + JsonBuf b; jb_init(&b); + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + + if (format == 0) { /* OpenAI */ + char full_url[1024]; + if (strstr(url, "/chat/completions") || strstr(url, "/messages")) { + snprintf(full_url, sizeof(full_url), "%s", url); + } else { + snprintf(full_url, sizeof(full_url), "%s/v1/chat/completions", url); + } + { size_t n = strlen(key)+24; char* l=malloc(n); snprintf(l,n,"Authorization: Bearer %s",key); h=curl_slist_append(h,l); free(l); } + jb_putc(&b, '{'); + jb_puts(&b, "\"model\":"); jb_emit_escaped(&b, model ? model : "neuron"); + jb_puts(&b, ",\"max_tokens\":4096,\"messages\":["); + if (esc_sys && *esc_sys) { jb_puts(&b,"{\"role\":\"system\",\"content\":\""); jb_puts(&b,esc_sys); jb_puts(&b,"\"},"); } + jb_puts(&b, "{\"role\":\"user\",\"content\":\""); jb_puts(&b, esc_user); jb_puts(&b, "\"}]}"); + el_val_t resp = http_do("POST", full_url, b.buf, h); + curl_slist_free_all(h); free(b.buf); + if (esc_sys) free(esc_sys); free(esc_user); + return llm_extract_text_openai(resp); + } else { /* Anthropic */ + { size_t n = strlen(key)+16; char* l=malloc(n); snprintf(l,n,"x-api-key: %s",key); h=curl_slist_append(h,l); free(l); } + { size_t n = strlen(LLM_VERSION)+32; char* l=malloc(n); snprintf(l,n,"anthropic-version: %s",LLM_VERSION); h=curl_slist_append(h,l); free(l); } + jb_putc(&b, '{'); + jb_puts(&b, "\"model\":"); jb_emit_escaped(&b, model ? model : LLM_DEFAULT_MODEL); + jb_puts(&b, ",\"max_tokens\":4096"); + if (esc_sys && *esc_sys) { jb_puts(&b,",\"system\":\""); jb_puts(&b,esc_sys); jb_puts(&b,"\""); } + jb_puts(&b, ",\"messages\":[{\"role\":\"user\",\"content\":\""); jb_puts(&b, esc_user); jb_puts(&b, "\"}]}"); + el_val_t resp = http_do("POST", url, b.buf, h); + curl_slist_free_all(h); free(b.buf); + if (esc_sys) free(esc_sys); free(esc_user); + return llm_extract_text(resp); + } +} + +static el_val_t llm_chain_call(const char* system_str, const char* user_str) { + char url_key[64], key_key[64], fmt_key[64], model_key[64]; + for (int i = 0; i < LLM_MAX_PROVIDERS; i++) { + snprintf(url_key, sizeof(url_key), "NEURON_LLM_%d_URL", i); + snprintf(key_key, sizeof(key_key), "NEURON_LLM_%d_KEY", i); + snprintf(fmt_key, sizeof(fmt_key), "NEURON_LLM_%d_FORMAT", i); + snprintf(model_key, sizeof(model_key), "NEURON_LLM_%d_MODEL", i); + const char* url = getenv(url_key); + const char* key = getenv(key_key); + if (!url || !*url || !key || !*key) break; /* end of chain */ + const char* fmt_s = getenv(fmt_key); + int fmt = (fmt_s && strcmp(fmt_s, "anthropic") == 0) ? 1 : 0; + const char* model = getenv(model_key); + fprintf(stderr, "[llm] trying provider %d (%s)\n", i, url); + el_val_t result = llm_provider_request(url, key, fmt, model, system_str, user_str); + const char* t = EL_CSTR(result); + if (t && *t && t[0] != '{') return result; /* success */ + fprintf(stderr, "[llm] provider %d failed or empty, trying next\n", i); + } + /* Legacy fallback: ANTHROPIC_API_KEY */ + const char* api_key = getenv("ANTHROPIC_API_KEY"); + if (!api_key || !*api_key) return http_error_json("no LLM providers configured"); + fprintf(stderr, "[llm] using legacy ANTHROPIC_API_KEY fallback\n"); + return llm_provider_request(LLM_API_URL, api_key, 1, NULL, system_str, user_str); +} + +/* Legacy llm_request — kept for backward compat with agentic loop internals */ +static el_val_t llm_request(const char* json_body) { + const char* api_key = getenv("ANTHROPIC_API_KEY"); + if (!api_key || !*api_key) return http_error_json("ANTHROPIC_API_KEY not set"); + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + { size_t n=strlen(api_key)+16; char* l=malloc(n); snprintf(l,n,"x-api-key: %s",api_key); h=curl_slist_append(h,l); free(l); } + { size_t n=strlen(LLM_VERSION)+32; char* l=malloc(n); snprintf(l,n,"anthropic-version: %s",LLM_VERSION); h=curl_slist_append(h,l); free(l); } + el_val_t resp = http_do("POST", LLM_API_URL, json_body, h); + curl_slist_free_all(h); + return resp; +} + +/* Extract concatenated assistant text from an Anthropic /v1/messages + * response. The response shape is: + * {"content":[{"type":"text","text":"..."}, ...], ...} + * If parsing fails, returns the raw response so the caller can inspect. + */ +static el_val_t llm_extract_text(el_val_t resp_val) { + const char* resp = EL_CSTR(resp_val); + if (!resp || !*resp) return el_wrap_str(el_strdup("")); + /* If error JSON, propagate as-is. */ + if (resp[0] == '{' && strstr(resp, "\"error\"")) { + return el_wrap_str(el_strdup(resp)); + } + /* Find "content":[ ... ] */ + const char* p = json_find_key(resp, "content"); + if (!p) return el_wrap_str(el_strdup(resp)); + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') return el_wrap_str(el_strdup(resp)); + p++; + JsonBuf out; jb_init(&out); + while (*p && *p != ']') { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p != '{') break; + const char* end = json_skip_value(p); + size_t n = (size_t)(end - p); + char* obj = malloc(n + 1); + memcpy(obj, p, n); obj[n] = '\0'; + const char* type_p = json_find_key(obj, "type"); + if (type_p && *type_p == '"') { + JsonParser jp = { .p = type_p, .end = type_p + strlen(type_p), .err = 0 }; + char* type_s = jp_parse_string_raw(&jp); + if (!jp.err && type_s && strcmp(type_s, "text") == 0) { + const char* tp = json_find_key(obj, "text"); + if (tp && *tp == '"') { + JsonParser jp2 = { .p = tp, .end = tp + strlen(tp), .err = 0 }; + char* text_s = jp_parse_string_raw(&jp2); + if (!jp2.err && text_s) jb_puts(&out, text_s); + free(text_s); + } + } + free(type_s); + } + free(obj); + p = end; + } + return el_wrap_str(out.buf); +} + +el_val_t llm_call(el_val_t model, el_val_t prompt) { + const char* u = EL_CSTR(prompt); if (!u) u = ""; + return llm_chain_call(NULL, u); +} + +el_val_t llm_call_system(el_val_t model, el_val_t system_prompt, el_val_t user_prompt) { + const char* s = EL_CSTR(system_prompt); if (!s) s = ""; + const char* u = EL_CSTR(user_prompt); if (!u) u = ""; + return llm_chain_call(s, u); +} + +/* ── Tool registry for llm_call_agentic ─────────────────────────────────── */ + +typedef el_val_t (*llm_tool_fn)(el_val_t input); + +typedef struct LlmToolEntry { + char* name; + llm_tool_fn fn; +} LlmToolEntry; + +static LlmToolEntry _llm_tools[64]; +static size_t _llm_tool_count = 0; +static pthread_mutex_t _llm_tool_mu = PTHREAD_MUTEX_INITIALIZER; + +static llm_tool_fn llm_tool_lookup(const char* name) { + if (!name) return NULL; + llm_tool_fn fn = NULL; + pthread_mutex_lock(&_llm_tool_mu); + for (size_t i = 0; i < _llm_tool_count; i++) { + if (strcmp(_llm_tools[i].name, name) == 0) { fn = _llm_tools[i].fn; break; } + } + pthread_mutex_unlock(&_llm_tool_mu); + return fn; +} + +void llm_register_tool(el_val_t name, el_val_t handler_fn_name) { + const char* nm = EL_CSTR(name); + const char* sym = EL_CSTR(handler_fn_name); + if (!nm || !*nm || !sym || !*sym) return; + void* p = dlsym(RTLD_DEFAULT, sym); + if (!p) { + fprintf(stderr, "[llm_register_tool] symbol not found: %s\n", sym); + return; + } + pthread_mutex_lock(&_llm_tool_mu); + /* Replace existing entry by name. */ + for (size_t i = 0; i < _llm_tool_count; i++) { + if (strcmp(_llm_tools[i].name, nm) == 0) { + _llm_tools[i].fn = (llm_tool_fn)p; + pthread_mutex_unlock(&_llm_tool_mu); + return; + } + } + if (_llm_tool_count < sizeof(_llm_tools) / sizeof(_llm_tools[0])) { + _llm_tools[_llm_tool_count].name = el_strdup(nm); + _llm_tools[_llm_tool_count].fn = (llm_tool_fn)p; + _llm_tool_count++; + } + pthread_mutex_unlock(&_llm_tool_mu); +} + +/* Serialize the El `tools` list into the JSON `tools:[...]` field expected + * by the Anthropic API. Each tool is an ElMap with name/description/ + * input_schema. input_schema is treated as either a JSON-object string + * (passed through verbatim) or a missing field (substitute {}). */ +static void llm_emit_tools_json(JsonBuf* b, el_val_t tools_list) { + jb_putc(b, '['); + ElList* lst = (ElList*)(uintptr_t)tools_list; + int64_t n = lst ? lst->length : 0; + for (int64_t i = 0; i < n; i++) { + if (i > 0) jb_putc(b, ','); + ElMap* tm = as_map(lst->elems[i]); + const char* name = ""; + const char* desc = ""; + const char* schema = "{}"; + if (tm) { + for (int64_t k = 0; k < tm->count; k++) { + const char* key = EL_CSTR(tm->keys[k]); + const char* val = EL_CSTR(tm->values[k]); + if (!key || !val) continue; + if (strcmp(key, "name") == 0) name = val; + else if (strcmp(key, "description") == 0) desc = val; + else if (strcmp(key, "input_schema") == 0) schema = val; + } + } + char* esc_name = json_escape_alloc(name); + char* esc_desc = json_escape_alloc(desc); + jb_puts(b, "{\"name\":\""); jb_puts(b, esc_name); + jb_puts(b, "\",\"description\":\""); jb_puts(b, esc_desc); + jb_puts(b, "\",\"input_schema\":"); jb_puts(b, schema && *schema ? schema : "{}"); + jb_putc(b, '}'); + free(esc_name); free(esc_desc); + } + jb_putc(b, ']'); +} + +/* Walk the assistant `content` array and emit each block back into b, + * preserving the verbatim JSON of every block — used to re-include the + * assistant turn in the next request. */ +static void llm_emit_content_blocks(JsonBuf* b, const char* resp) { + const char* p = json_find_key(resp, "content"); + jb_putc(b, '['); + if (!p) { jb_putc(b, ']'); return; } + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') { jb_putc(b, ']'); return; } + p++; + int first = 1; + while (*p && *p != ']') { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p != '{') break; + const char* end = json_skip_value(p); + if (!first) jb_putc(b, ','); + first = 0; + size_t n = (size_t)(end - p); + jb_reserve(b, n); + memcpy(b->buf + b->len, p, n); + b->len += n; + b->buf[b->len] = '\0'; + p = end; + } + jb_putc(b, ']'); +} + +/* Concatenate all "text" blocks from a response. Returns owned string. */ +static char* llm_concat_text_blocks(const char* resp) { + JsonBuf out; jb_init(&out); + if (!resp) return out.buf; + const char* p = json_find_key(resp, "content"); + if (!p) return out.buf; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') return out.buf; + p++; + while (*p && *p != ']') { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p != '{') break; + const char* end = json_skip_value(p); + size_t n = (size_t)(end - p); + char* obj = malloc(n + 1); + memcpy(obj, p, n); obj[n] = '\0'; + const char* tp = json_find_key(obj, "type"); + if (tp && *tp == '"') { + JsonParser jp = { .p = tp, .end = tp + strlen(tp), .err = 0 }; + char* tname = jp_parse_string_raw(&jp); + if (!jp.err && tname && strcmp(tname, "text") == 0) { + const char* xp = json_find_key(obj, "text"); + if (xp && *xp == '"') { + JsonParser jp2 = { .p = xp, .end = xp + strlen(xp), .err = 0 }; + char* txt = jp_parse_string_raw(&jp2); + if (!jp2.err && txt) jb_puts(&out, txt); + free(txt); + } + } + free(tname); + } + free(obj); + p = end; + } + return out.buf; +} + +/* Build tool_result message blocks for every tool_use in a response. + * Appends to `b` an array element for each tool_use; caller wraps. */ +static int llm_build_tool_results(JsonBuf* b, const char* resp) { + int any = 0; + const char* p = json_find_key(resp, "content"); + if (!p) return 0; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') return 0; + p++; + while (*p && *p != ']') { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p != '{') break; + const char* end = json_skip_value(p); + size_t n = (size_t)(end - p); + char* obj = malloc(n + 1); + memcpy(obj, p, n); obj[n] = '\0'; + + const char* tp = json_find_key(obj, "type"); + char* type_s = NULL; + if (tp && *tp == '"') { + JsonParser jp = { .p = tp, .end = tp + strlen(tp), .err = 0 }; + type_s = jp_parse_string_raw(&jp); + } + if (type_s && strcmp(type_s, "tool_use") == 0) { + /* Extract id, name, input. */ + char* id_s = NULL; char* name_s = NULL; + const char* idp = json_find_key(obj, "id"); + if (idp && *idp == '"') { + JsonParser jp = { .p = idp, .end = idp + strlen(idp), .err = 0 }; + id_s = jp_parse_string_raw(&jp); + } + const char* np = json_find_key(obj, "name"); + if (np && *np == '"') { + JsonParser jp = { .p = np, .end = np + strlen(np), .err = 0 }; + name_s = jp_parse_string_raw(&jp); + } + el_val_t input_raw = json_get_raw(EL_STR(obj), EL_STR("input")); + const char* input_s = EL_CSTR(input_raw); + if (!input_s || !*input_s) input_s = "{}"; + + llm_tool_fn fn = llm_tool_lookup(name_s ? name_s : ""); + char* result = NULL; + int is_error = 0; + if (!fn) { + size_t en = strlen(name_s ? name_s : "(null)") + 64; + result = malloc(en); + snprintf(result, en, "{\"error\":\"tool not registered: %s\"}", + name_s ? name_s : "(null)"); + is_error = 1; + } else { + el_val_t out = fn(EL_STR(input_s)); + const char* os = EL_CSTR(out); + result = el_strdup(os ? os : ""); + } + + if (any) jb_putc(b, ','); + char* esc_id = json_escape_alloc(id_s ? id_s : ""); + char* esc_res = json_escape_alloc(result ? result : ""); + jb_puts(b, "{\"type\":\"tool_result\",\"tool_use_id\":\""); + jb_puts(b, esc_id); + jb_puts(b, "\",\"content\":\""); + jb_puts(b, esc_res); + jb_puts(b, "\""); + if (is_error) jb_puts(b, ",\"is_error\":true"); + jb_putc(b, '}'); + free(esc_id); free(esc_res); free(result); + free(id_s); free(name_s); + any = 1; + } + free(type_s); + free(obj); + p = end; + } + return any; +} + +el_val_t llm_call_agentic(el_val_t model, el_val_t system, el_val_t user, el_val_t tools) { + /* Empty tools list → degrade to plain system call. */ + ElList* tl = (ElList*)(uintptr_t)tools; + if (!tl || tl->length == 0) { + return llm_call_system(model, system, user); + } + const char* m = llm_resolve_model(EL_CSTR(model)); + const char* sys_p = EL_CSTR(system); if (!sys_p) sys_p = ""; + const char* usr_p = EL_CSTR(user); if (!usr_p) usr_p = ""; + + /* Build the static parts: tools JSON and system prompt — these don't + * change across iterations. */ + JsonBuf tools_buf; jb_init(&tools_buf); + llm_emit_tools_json(&tools_buf, tools); + char* esc_sys = json_escape_alloc(sys_p); + + /* messages array, accumulated as a mutable JSON fragment (no surrounding + * brackets — emitted at request time). */ + JsonBuf msgs; jb_init(&msgs); + /* First user message. */ + char* esc_user = json_escape_alloc(usr_p); + jb_puts(&msgs, "{\"role\":\"user\",\"content\":\""); + jb_puts(&msgs, esc_user); + jb_puts(&msgs, "\"}"); + free(esc_user); + + char* last_text = el_strdup(""); + el_val_t final_out = 0; + int reached_cap = 1; + + for (int iter = 0; iter < 10; iter++) { + /* Build request body. */ + JsonBuf body; jb_init(&body); + jb_putc(&body, '{'); + jb_puts(&body, "\"model\":"); jb_emit_escaped(&body, m); + jb_puts(&body, ",\"max_tokens\":4096"); + if (*sys_p) { + jb_puts(&body, ",\"system\":\""); + jb_puts(&body, esc_sys); + jb_puts(&body, "\""); + } + jb_puts(&body, ",\"tools\":"); + jb_puts(&body, tools_buf.buf); + jb_puts(&body, ",\"messages\":["); + jb_puts(&body, msgs.buf); + jb_puts(&body, "]}"); + + el_val_t resp_v = llm_request(body.buf); + free(body.buf); + const char* resp = EL_CSTR(resp_v); + if (!resp || !*resp) { + final_out = http_error_json("empty response"); + reached_cap = 0; + break; + } + if (resp[0] == '{' && strstr(resp, "\"error\"") && + !json_find_key(resp, "content")) { + final_out = el_wrap_str(el_strdup(resp)); + reached_cap = 0; + break; + } + + /* Update last_text from this response. */ + free(last_text); + last_text = llm_concat_text_blocks(resp); + + /* Inspect stop_reason. */ + el_val_t sr_v = json_get_string(EL_STR(resp), EL_STR("stop_reason")); + const char* sr = EL_CSTR(sr_v); if (!sr) sr = ""; + + if (strcmp(sr, "end_turn") == 0) { + final_out = el_wrap_str(el_strdup(last_text)); + reached_cap = 0; + break; + } + if (strcmp(sr, "max_tokens") == 0) { + size_t ln = strlen(last_text) + 16; + char* out = malloc(ln); + snprintf(out, ln, "%s\n[truncated]", last_text); + final_out = el_wrap_str(out); + reached_cap = 0; + break; + } + if (strcmp(sr, "tool_use") != 0) { + /* Unexpected stop reason; return the text we have. */ + final_out = el_wrap_str(el_strdup(last_text)); + reached_cap = 0; + break; + } + + /* Append the assistant turn (raw content blocks) to messages. */ + JsonBuf ab; jb_init(&ab); + jb_puts(&ab, ",{\"role\":\"assistant\",\"content\":"); + llm_emit_content_blocks(&ab, resp); + jb_putc(&ab, '}'); + jb_puts(&msgs, ab.buf); + free(ab.buf); + + /* Build tool_result message. */ + JsonBuf tr; jb_init(&tr); + jb_puts(&tr, ",{\"role\":\"user\",\"content\":["); + int any = llm_build_tool_results(&tr, resp); + jb_puts(&tr, "]}"); + if (any) { + jb_puts(&msgs, tr.buf); + } + free(tr.buf); + } + + if (reached_cap) { + size_t ln = strlen(last_text) + 32; + char* out = malloc(ln); + snprintf(out, ln, "[loop_cap_reached]\n%s", last_text); + final_out = el_wrap_str(out); + } + free(last_text); + free(esc_sys); + free(tools_buf.buf); + free(msgs.buf); + return final_out; +} + +/* base64-encode arbitrary bytes (returns owned C string). + * Internal helper for llm_vision; the public crypto entry point that El + * programs call is `base64_encode(el_val_t)` defined in the crypto block + * at the end of this file. */ +static char* el_b64_encode_internal(const unsigned char* src, size_t n) { + static const char tbl[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + size_t out_len = 4 * ((n + 2) / 3); + char* out = malloc(out_len + 1); + if (!out) return NULL; + size_t o = 0; + for (size_t i = 0; i < n;) { + uint32_t v = 0; int got = 0; + v |= (uint32_t)src[i++] << 16; got++; + if (i < n) { v |= (uint32_t)src[i++] << 8; got++; } + if (i < n) { v |= (uint32_t)src[i++]; got++; } + out[o++] = tbl[(v >> 18) & 0x3f]; + out[o++] = tbl[(v >> 12) & 0x3f]; + out[o++] = (got > 1) ? tbl[(v >> 6) & 0x3f] : '='; + out[o++] = (got > 2) ? tbl[v & 0x3f] : '='; + } + out[o] = '\0'; + return out; +} + +el_val_t llm_vision(el_val_t model, el_val_t system, el_val_t prompt, el_val_t image_url_or_b64) { + const char* m = llm_resolve_model(EL_CSTR(model)); + const char* s = EL_CSTR(system); if (!s) s = ""; + const char* u = EL_CSTR(prompt); if (!u) u = ""; + const char* img = EL_CSTR(image_url_or_b64); if (!img) img = ""; + + /* Choose source mode */ + char* image_block = NULL; + if (strncasecmp(img, "http://", 7) == 0 || strncasecmp(img, "https://", 8) == 0) { + char* esc_url = json_escape_alloc(img); + size_t n = strlen(esc_url) + 128; + image_block = malloc(n); + snprintf(image_block, n, + "{\"type\":\"image\",\"source\":{\"type\":\"url\",\"url\":\"%s\"}}", + esc_url); + free(esc_url); + } else if (strncmp(img, "data:", 5) == 0) { + /* Inline data URL: split media-type and base64 */ + const char* semi = strchr(img + 5, ';'); + const char* comma = strchr(img + 5, ','); + char media[64] = "image/png"; + if (semi && comma && semi < comma) { + size_t ml = (size_t)(semi - (img + 5)); + if (ml >= sizeof(media)) ml = sizeof(media) - 1; + memcpy(media, img + 5, ml); media[ml] = '\0'; + } + const char* b64 = comma ? comma + 1 : ""; + char* esc_media = json_escape_alloc(media); + char* esc_b64 = json_escape_alloc(b64); + size_t n = strlen(esc_media) + strlen(esc_b64) + 192; + image_block = malloc(n); + snprintf(image_block, n, + "{\"type\":\"image\",\"source\":{\"type\":\"base64\"," + "\"media_type\":\"%s\",\"data\":\"%s\"}}", + esc_media, esc_b64); + free(esc_media); free(esc_b64); + } else if (*img) { + /* Treat as file path: read, base64-encode, attach. */ + FILE* f = fopen(img, "rb"); + if (!f) { + char err[256]; snprintf(err, sizeof(err), "cannot open image: %s", img); + return http_error_json(err); + } + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + if (sz <= 0) { fclose(f); return http_error_json("empty image file"); } + unsigned char* buf = malloc((size_t)sz); + if (!buf) { fclose(f); return http_error_json("oom"); } + size_t got = fread(buf, 1, (size_t)sz, f); + fclose(f); + char* b64 = el_b64_encode_internal(buf, got); + free(buf); + if (!b64) return http_error_json("base64 encode failed"); + const char* media = "image/png"; + size_t ilen = strlen(img); + if (ilen >= 4) { + if (strcasecmp(img + ilen - 4, ".jpg") == 0 || + (ilen >= 5 && strcasecmp(img + ilen - 5, ".jpeg") == 0)) media = "image/jpeg"; + else if (strcasecmp(img + ilen - 4, ".gif") == 0) media = "image/gif"; + else if (strcasecmp(img + ilen - 4, ".webp") == 0) media = "image/webp"; + } + char* esc_b64 = json_escape_alloc(b64); free(b64); + size_t n = strlen(esc_b64) + 192; + image_block = malloc(n); + snprintf(image_block, n, + "{\"type\":\"image\",\"source\":{\"type\":\"base64\"," + "\"media_type\":\"%s\",\"data\":\"%s\"}}", + media, esc_b64); + free(esc_b64); + } + + char* esc_sys = json_escape_alloc(s); + char* esc_user = json_escape_alloc(u); + JsonBuf b; jb_init(&b); + jb_putc(&b, '{'); + jb_puts(&b, "\"model\":"); jb_emit_escaped(&b, m); + jb_puts(&b, ",\"max_tokens\":4096"); + if (*s) { + jb_puts(&b, ",\"system\":\""); + jb_puts(&b, esc_sys); + jb_puts(&b, "\""); + } + jb_puts(&b, ",\"messages\":[{\"role\":\"user\",\"content\":["); + if (image_block) { + jb_puts(&b, image_block); + jb_putc(&b, ','); + } + jb_puts(&b, "{\"type\":\"text\",\"text\":\""); + jb_puts(&b, esc_user); + jb_puts(&b, "\"}]}]}"); + free(esc_sys); free(esc_user); free(image_block); + el_val_t resp = llm_request(b.buf); + free(b.buf); + return llm_extract_text(resp); +} + +el_val_t llm_models(void) { + el_val_t lst = el_list_empty(); + lst = el_list_append(lst, el_wrap_str(el_strdup("claude-sonnet-4-5"))); + lst = el_list_append(lst, el_wrap_str(el_strdup("claude-opus-4-7"))); + lst = el_list_append(lst, el_wrap_str(el_strdup("claude-haiku-4-5"))); + return lst; +} +#endif /* HAVE_CURL */ + +/* ── Native VM builtin aliases ────────────────────────────────────────────── + * El source files use native_* names (El VM builtins). + * When compiled to C, these map directly to el_* runtime functions. */ + +el_val_t native_list_get(el_val_t list, el_val_t index) { + return el_list_get(list, index); +} + +el_val_t native_list_len(el_val_t list) { + return el_list_len(list); +} + +el_val_t native_list_append(el_val_t list, el_val_t elem) { + return el_list_append(list, elem); +} + +el_val_t native_list_empty(void) { + return el_list_empty(); +} + +el_val_t native_list_clone(el_val_t list) { + return el_list_clone(list); +} + +el_val_t native_string_chars(el_val_t sv) { + const char* s = EL_CSTR(sv); + el_val_t result = el_list_empty(); + if (!s) return result; + while (*s) { + char buf[2]; + buf[0] = *s; + buf[1] = '\0'; + result = el_list_append(result, EL_STR(strdup(buf))); + s++; + } + return result; +} + +el_val_t native_int_to_str(el_val_t n) { + return int_to_str(n); +} + +/* ── Method-call shorthand aliases ────────────────────────────────────────── + * Short names that result from the method-call convention: + * myList.append(x) → append(myList, x) + * myList.len() → len(myList) + * myList.get(i) → get(myList, i) + * myMap.map_get(k) → map_get(myMap, k) + * myMap.map_set(k,v) → map_set(myMap, k, v) */ + +el_val_t append(el_val_t list, el_val_t elem) { return el_list_append(list, elem); } +el_val_t len(el_val_t list) { return el_list_len(list); } +el_val_t get(el_val_t list, el_val_t index) { return el_list_get(list, index); } +el_val_t map_get(el_val_t map, el_val_t key) { return el_map_get(map, key); } +el_val_t map_set(el_val_t map, el_val_t key, el_val_t value) { return el_map_set(map, key, value); } + +/* ── Crypto primitives ────────────────────────────────────────────────────── + * + * SHA-256 implementation adapted from Brad Conte's public-domain reference + * (https://github.com/B-Con/crypto-algorithms/blob/master/sha256.c, public + * domain per the project's LICENSE). HMAC follows RFC 2104. Base64 encoding + * follows RFC 4648; the URL-safe variant uses the alphabet from §5 of the + * RFC and omits padding (per JWT/JWS convention). + * + * Self-contained: no OpenSSL/libcrypto dependency. The runtime keeps its + * existing `-lcurl -lpthread -ldl -lm` link line. + * + * Binary outputs (sha256_bytes, hmac_sha256_bytes) tag their buffer with a + * magic header so base64_encode/base64url_encode can recover the exact byte + * length even when the payload contains embedded NULs. Plain C strings + * (without the header) fall back to strlen(), preserving the existing API + * shape for normal text inputs. */ + +/* Magic-header for length-tagged binary buffers. Layout: + * [ uint32_t magic = EL_MAGIC_BIN ][ uint32_t length ][ data... ][ \0 ] + * The returned el_val_t points at `data`, so consumers that strlen() it still + * get a sensible (though possibly truncated) view. el_bin_len() recovers the + * true length by sniffing the 8 bytes preceding the pointer. + * + * Magic value chosen with high MSB so it cannot collide with printable ASCII + * (the same discriminator pattern used by EL_MAGIC_LIST / EL_MAGIC_MAP). */ +#define EL_MAGIC_BIN 0xE1B17EAFu + +typedef struct { + uint32_t magic; + uint32_t length; +} el_bin_hdr_t; + +/* Allocate a length-tagged binary buffer; returns pointer to the data area. */ +static unsigned char* el_bin_alloc(size_t len) { + el_bin_hdr_t* hdr = (el_bin_hdr_t*)malloc(sizeof(el_bin_hdr_t) + len + 1); + if (!hdr) { fputs("el_runtime: out of memory (bin)\n", stderr); exit(1); } + hdr->magic = EL_MAGIC_BIN; + hdr->length = (uint32_t)len; + unsigned char* data = (unsigned char*)(hdr + 1); + data[len] = '\0'; /* keep NUL-terminated for accidental strlen calls */ + return data; +} + +/* Recover length from a possibly-tagged buffer. Returns 1 if tagged. */ +static int el_bin_lookup(const void* p, size_t* out_len) { + if (!p) { *out_len = 0; return 0; } + /* Avoid reading off the front of a page on tiny pointers (e.g. NULs + * passed in as int-cast values). 4096 is a safe lower bound on any + * platform we target. */ + if ((uintptr_t)p < 4096) return 0; + const el_bin_hdr_t* hdr = (const el_bin_hdr_t*)((const char*)p - sizeof(el_bin_hdr_t)); + if (hdr->magic != EL_MAGIC_BIN) return 0; + *out_len = hdr->length; + return 1; +} + +/* Effective input length: tagged length if present, else strlen. */ +static size_t el_input_len(const char* s) { + size_t n; + if (el_bin_lookup(s, &n)) return n; + return s ? strlen(s) : 0; +} + +/* ─── SHA-256 (Brad Conte / public domain) ──────────────────────────────── */ + +typedef struct { + unsigned char data[64]; + uint32_t datalen; + uint64_t bitlen; + uint32_t state[8]; +} el_sha256_ctx_t; + +static const uint32_t el_sha256_k[64] = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +}; + +#define EL_ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) +#define EL_CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) +#define EL_MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define EL_EP0(x) (EL_ROTR(x,2) ^ EL_ROTR(x,13) ^ EL_ROTR(x,22)) +#define EL_EP1(x) (EL_ROTR(x,6) ^ EL_ROTR(x,11) ^ EL_ROTR(x,25)) +#define EL_SIG0(x) (EL_ROTR(x,7) ^ EL_ROTR(x,18) ^ ((x) >> 3)) +#define EL_SIG1(x) (EL_ROTR(x,17) ^ EL_ROTR(x,19) ^ ((x) >> 10)) + +static void el_sha256_transform(el_sha256_ctx_t* ctx, const unsigned char* data) { + uint32_t a, b, c, d, e, f, g, h, t1, t2, m[64]; + int i, j; + for (i = 0, j = 0; i < 16; ++i, j += 4) { + m[i] = ((uint32_t)data[j] << 24) | ((uint32_t)data[j + 1] << 16) + | ((uint32_t)data[j + 2] << 8) | (uint32_t)data[j + 3]; + } + for (; i < 64; ++i) { + m[i] = EL_SIG1(m[i-2]) + m[i-7] + EL_SIG0(m[i-15]) + m[i-16]; + } + a = ctx->state[0]; b = ctx->state[1]; c = ctx->state[2]; d = ctx->state[3]; + e = ctx->state[4]; f = ctx->state[5]; g = ctx->state[6]; h = ctx->state[7]; + for (i = 0; i < 64; ++i) { + t1 = h + EL_EP1(e) + EL_CH(e,f,g) + el_sha256_k[i] + m[i]; + t2 = EL_EP0(a) + EL_MAJ(a,b,c); + h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2; + } + ctx->state[0] += a; ctx->state[1] += b; ctx->state[2] += c; ctx->state[3] += d; + ctx->state[4] += e; ctx->state[5] += f; ctx->state[6] += g; ctx->state[7] += h; +} + +static void el_sha256_init(el_sha256_ctx_t* ctx) { + ctx->datalen = 0; + ctx->bitlen = 0; + ctx->state[0] = 0x6a09e667; ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; ctx->state[7] = 0x5be0cd19; +} + +static void el_sha256_update(el_sha256_ctx_t* ctx, const unsigned char* data, size_t len) { + for (size_t i = 0; i < len; ++i) { + ctx->data[ctx->datalen++] = data[i]; + if (ctx->datalen == 64) { + el_sha256_transform(ctx, ctx->data); + ctx->bitlen += 512; + ctx->datalen = 0; + } + } +} + +static void el_sha256_final(el_sha256_ctx_t* ctx, unsigned char hash[32]) { + uint32_t i = ctx->datalen; + if (ctx->datalen < 56) { + ctx->data[i++] = 0x80; + while (i < 56) ctx->data[i++] = 0x00; + } else { + ctx->data[i++] = 0x80; + while (i < 64) ctx->data[i++] = 0x00; + el_sha256_transform(ctx, ctx->data); + memset(ctx->data, 0, 56); + } + ctx->bitlen += (uint64_t)ctx->datalen * 8; + ctx->data[63] = (unsigned char)( ctx->bitlen & 0xff); + ctx->data[62] = (unsigned char)((ctx->bitlen >> 8) & 0xff); + ctx->data[61] = (unsigned char)((ctx->bitlen >> 16) & 0xff); + ctx->data[60] = (unsigned char)((ctx->bitlen >> 24) & 0xff); + ctx->data[59] = (unsigned char)((ctx->bitlen >> 32) & 0xff); + ctx->data[58] = (unsigned char)((ctx->bitlen >> 40) & 0xff); + ctx->data[57] = (unsigned char)((ctx->bitlen >> 48) & 0xff); + ctx->data[56] = (unsigned char)((ctx->bitlen >> 56) & 0xff); + el_sha256_transform(ctx, ctx->data); + for (i = 0; i < 4; ++i) { + hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0xff; + hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0xff; + hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0xff; + hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0xff; + hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0xff; + hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0xff; + hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0xff; + hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0xff; + } +} + +static void el_sha256_oneshot(const unsigned char* data, size_t len, unsigned char out[32]) { + el_sha256_ctx_t c; + el_sha256_init(&c); + el_sha256_update(&c, data, len); + el_sha256_final(&c, out); +} + +/* ─── HMAC-SHA-256 (RFC 2104) ───────────────────────────────────────────── */ + +static void el_hmac_sha256(const unsigned char* key, size_t key_len, + const unsigned char* msg, size_t msg_len, + unsigned char out[32]) { + unsigned char k[64]; + unsigned char k_ipad[64]; + unsigned char k_opad[64]; + unsigned char inner[32]; + + if (key_len > 64) { + el_sha256_oneshot(key, key_len, k); + memset(k + 32, 0, 32); + } else { + memcpy(k, key, key_len); + memset(k + key_len, 0, 64 - key_len); + } + for (int i = 0; i < 64; ++i) { + k_ipad[i] = k[i] ^ 0x36; + k_opad[i] = k[i] ^ 0x5c; + } + { + el_sha256_ctx_t c; + el_sha256_init(&c); + el_sha256_update(&c, k_ipad, 64); + el_sha256_update(&c, msg, msg_len); + el_sha256_final(&c, inner); + } + { + el_sha256_ctx_t c; + el_sha256_init(&c); + el_sha256_update(&c, k_opad, 64); + el_sha256_update(&c, inner, 32); + el_sha256_final(&c, out); + } +} + +/* ─── Hex helper ────────────────────────────────────────────────────────── */ + +static el_val_t el_hex_encode(const unsigned char* data, size_t len) { + static const char digits[] = "0123456789abcdef"; + char* out = el_strbuf(len * 2); + for (size_t i = 0; i < len; ++i) { + out[i * 2] = digits[(data[i] >> 4) & 0xf]; + out[i * 2 + 1] = digits[ data[i] & 0xf]; + } + out[len * 2] = '\0'; + return el_wrap_str(out); +} + +/* ─── Base64 (RFC 4648) ─────────────────────────────────────────────────── */ + +static const char el_b64_std_alphabet[64] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char el_b64_url_alphabet[64] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + +el_val_t el_base64_encode_n(const unsigned char* data, size_t len, int url_safe) { + const char* alphabet = url_safe ? el_b64_url_alphabet : el_b64_std_alphabet; + /* Standard form is padded to multiple of 4; URL-safe omits padding. */ + size_t out_cap = ((len + 2) / 3) * 4 + 1; + char* out = el_strbuf(out_cap); + size_t i = 0, j = 0; + while (i + 3 <= len) { + uint32_t v = ((uint32_t)data[i] << 16) | ((uint32_t)data[i+1] << 8) | (uint32_t)data[i+2]; + out[j++] = alphabet[(v >> 18) & 0x3f]; + out[j++] = alphabet[(v >> 12) & 0x3f]; + out[j++] = alphabet[(v >> 6) & 0x3f]; + out[j++] = alphabet[ v & 0x3f]; + i += 3; + } + size_t rem = len - i; + if (rem == 1) { + uint32_t v = (uint32_t)data[i] << 16; + out[j++] = alphabet[(v >> 18) & 0x3f]; + out[j++] = alphabet[(v >> 12) & 0x3f]; + if (!url_safe) { out[j++] = '='; out[j++] = '='; } + } else if (rem == 2) { + uint32_t v = ((uint32_t)data[i] << 16) | ((uint32_t)data[i+1] << 8); + out[j++] = alphabet[(v >> 18) & 0x3f]; + out[j++] = alphabet[(v >> 12) & 0x3f]; + out[j++] = alphabet[(v >> 6) & 0x3f]; + if (!url_safe) { out[j++] = '='; } + } + out[j] = '\0'; + return el_wrap_str(out); +} + +/* Decode either alphabet — accepts both '+/' and '-_' transparently, and + * tolerates missing padding (which JWTs typically omit). Whitespace is + * skipped for robustness. Invalid characters cause the decode to stop and + * the partial result so far is returned. */ +static el_val_t el_base64_decode_any(const char* in) { + if (!in) { + unsigned char* empty = el_bin_alloc(0); + return EL_STR((char*)empty); + } + size_t in_len = strlen(in); + /* Worst case: 3 output bytes per 4 input chars, +1 NUL slack. */ + unsigned char* out = el_bin_alloc(((in_len + 3) / 4) * 3 + 1); + + int8_t lut[256]; + for (int i = 0; i < 256; ++i) lut[i] = -1; + for (int i = 0; i < 64; ++i) lut[(unsigned char)el_b64_std_alphabet[i]] = (int8_t)i; + /* Allow URL-safe characters too (so one decoder handles both forms). */ + lut[(unsigned char)'-'] = 62; + lut[(unsigned char)'_'] = 63; + + uint32_t buf = 0; + int bits = 0; + size_t o = 0; + for (size_t i = 0; i < in_len; ++i) { + unsigned char c = (unsigned char)in[i]; + if (c == '=' || c == '\r' || c == '\n' || c == ' ' || c == '\t') continue; + int8_t v = lut[c]; + if (v < 0) break; /* invalid char — stop */ + buf = (buf << 6) | (uint32_t)v; + bits += 6; + if (bits >= 8) { + bits -= 8; + out[o++] = (unsigned char)((buf >> bits) & 0xff); + } + } + /* Patch the length header to the actual decoded length. */ + el_bin_hdr_t* hdr = (el_bin_hdr_t*)((char*)out - sizeof(el_bin_hdr_t)); + hdr->length = (uint32_t)o; + out[o] = '\0'; + return EL_STR((char*)out); +} + +/* ─── Public crypto entry points ────────────────────────────────────────── */ + +el_val_t el_sha256_bytes_n(const unsigned char* data, size_t len) { + unsigned char* out = el_bin_alloc(32); + el_sha256_oneshot(data, len, out); + return EL_STR((char*)out); +} + +el_val_t sha256_hex(el_val_t input) { + const char* s = EL_CSTR(input); + size_t n = el_input_len(s); + unsigned char digest[32]; + el_sha256_oneshot((const unsigned char*)(s ? s : ""), n, digest); + return el_hex_encode(digest, 32); +} + +el_val_t sha256_bytes(el_val_t input) { + const char* s = EL_CSTR(input); + size_t n = el_input_len(s); + return el_sha256_bytes_n((const unsigned char*)(s ? s : ""), n); +} + +el_val_t hmac_sha256_hex(el_val_t key, el_val_t message) { + const char* k = EL_CSTR(key); + const char* m = EL_CSTR(message); + size_t kn = el_input_len(k); + size_t mn = el_input_len(m); + unsigned char mac[32]; + el_hmac_sha256((const unsigned char*)(k ? k : ""), kn, + (const unsigned char*)(m ? m : ""), mn, + mac); + return el_hex_encode(mac, 32); +} + +el_val_t hmac_sha256_bytes(el_val_t key, el_val_t message) { + const char* k = EL_CSTR(key); + const char* m = EL_CSTR(message); + size_t kn = el_input_len(k); + size_t mn = el_input_len(m); + unsigned char* out = el_bin_alloc(32); + el_hmac_sha256((const unsigned char*)(k ? k : ""), kn, + (const unsigned char*)(m ? m : ""), mn, + out); + return EL_STR((char*)out); +} + +el_val_t base64_encode(el_val_t input) { + const char* s = EL_CSTR(input); + size_t n = el_input_len(s); + return el_base64_encode_n((const unsigned char*)(s ? s : ""), n, /*url_safe=*/0); +} + +el_val_t base64url_encode(el_val_t input) { + const char* s = EL_CSTR(input); + size_t n = el_input_len(s); + return el_base64_encode_n((const unsigned char*)(s ? s : ""), n, /*url_safe=*/1); +} + +el_val_t base64_decode(el_val_t input) { + return el_base64_decode_any(EL_CSTR(input)); +} + +el_val_t base64url_decode(el_val_t input) { + return el_base64_decode_any(EL_CSTR(input)); +} + +/* ── Post-quantum cryptography (liboqs + OpenSSL) ─────────────────────────── + * + * Algorithm choices (per CNSA 2.0 / NIST PQ guidance, as of 2024): + * Signatures: CRYSTALS-Dilithium-3 (NIST security level 3, balanced) + * KEM: CRYSTALS-Kyber-768 (NIST security level 3) + * Hash: SHA3-256 (Keccak) (PQ-aware protocols favour SHA3 over SHA2) + * Hybrid: X25519 || Kyber-768, combined via HKDF-SHA256 + * + * Why hybrid: Kyber is new. X25519 has 20+ years of analysis. Hybridizing + * preserves classical security if Kyber falls to a future cryptanalytic + * advance, and preserves PQ security if X25519 falls to a quantum adversary. + * "Recordable now, decryptable later" already threatens long-lived classical + * key exchange — the only safe move for keys protecting durable doctrine + * (CGI lineage, KindredGrants, Principal-CGI covenants) is to encapsulate + * with PQ today, even if the classical leg is what the wire shows. + * + * Compile-time detection: when is unavailable the pq_* functions + * compile to stubs that return a JSON error envelope. SHA3-256 stays + * available regardless (it's implemented inline, no liboqs dep). This lets + * the runtime build cleanly on dev machines without liboqs while production + * gets the full PQ stack. */ + +/* ─── SHA3-256 (Keccak, FIPS 202) ──────────────────────────────────────────── + * Inline reference implementation. ~120 LoC, no external dependency. + * rate=1088 bits, capacity=512 bits, output=256 bits, padding=0x06. */ + +static const uint64_t el_keccak_rc[24] = { + 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, + 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, + 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, + 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, + 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, + 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, + 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, + 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL +}; + +static const unsigned el_keccak_rho[24] = { + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 +}; + +static const unsigned el_keccak_pi[24] = { + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 +}; + +#define EL_ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n)))) + +static void el_keccak_f1600(uint64_t s[25]) { + for (int round = 0; round < 24; ++round) { + uint64_t bc[5], t; + for (int i = 0; i < 5; ++i) + bc[i] = s[i] ^ s[i+5] ^ s[i+10] ^ s[i+15] ^ s[i+20]; + for (int i = 0; i < 5; ++i) { + t = bc[(i+4) % 5] ^ EL_ROTL64(bc[(i+1) % 5], 1); + for (int j = 0; j < 25; j += 5) s[j+i] ^= t; + } + t = s[1]; + for (int i = 0; i < 24; ++i) { + int j = el_keccak_pi[i]; + bc[0] = s[j]; + s[j] = EL_ROTL64(t, el_keccak_rho[i]); + t = bc[0]; + } + for (int j = 0; j < 25; j += 5) { + for (int i = 0; i < 5; ++i) bc[i] = s[j+i]; + for (int i = 0; i < 5; ++i) + s[j+i] = bc[i] ^ ((~bc[(i+1) % 5]) & bc[(i+2) % 5]); + } + s[0] ^= el_keccak_rc[round]; + } +} + +static void el_sha3_256_oneshot(const unsigned char* data, size_t len, + unsigned char out[32]) { + uint64_t st[25] = {0}; + unsigned char* sb = (unsigned char*)st; + const size_t rate = 136; /* 1088 bits / 8 */ + size_t i = 0; + while (len - i >= rate) { + for (size_t k = 0; k < rate; ++k) sb[k] ^= data[i + k]; + el_keccak_f1600(st); + i += rate; + } + size_t rem = len - i; + for (size_t k = 0; k < rem; ++k) sb[k] ^= data[i + k]; + sb[rem] ^= 0x06; /* SHA3 domain-separation byte */ + sb[rate - 1] ^= 0x80; /* final-block padding bit (high bit of last byte) */ + el_keccak_f1600(st); + memcpy(out, sb, 32); +} + +el_val_t sha3_256_hex(el_val_t input) { + const char* s = EL_CSTR(input); + size_t n = el_input_len(s); + unsigned char digest[32]; + el_sha3_256_oneshot((const unsigned char*)(s ? s : ""), n, digest); + return el_hex_encode(digest, 32); +} + +/* ─── Hex decode helper ───────────────────────────────────────────────────── + * Returns a length-tagged binary buffer (so embedded NULs survive); on + * odd-length / invalid input returns NULL with *out_len = 0. Caller is + * responsible for emitting the error envelope. */ + +static int el_hex_nibble(char c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + return -1; +} + +__attribute__((unused)) +static unsigned char* el_hex_decode(const char* s, size_t* out_len) { + *out_len = 0; + if (!s) return NULL; + size_t n = strlen(s); + if (n & 1) return NULL; + size_t blen = n / 2; + unsigned char* out = el_bin_alloc(blen); + for (size_t i = 0; i < blen; ++i) { + int hi = el_hex_nibble(s[i*2]); + int lo = el_hex_nibble(s[i*2 + 1]); + if (hi < 0 || lo < 0) return NULL; + out[i] = (unsigned char)((hi << 4) | lo); + } + *out_len = blen; + return out; +} + +/* JSON error envelope reused across all PQ entry points. */ +static el_val_t pq_error(const char* msg) { + return http_error_json(msg); +} + +#if __has_include() +#include +#define EL_HAVE_LIBOQS 1 +#else +#define EL_HAVE_LIBOQS 0 +#endif + +#if EL_HAVE_LIBOQS && __has_include() +#include +#define EL_HAVE_OPENSSL 1 +#else +#define EL_HAVE_OPENSSL 0 +#endif + +#if !EL_HAVE_LIBOQS + +/* ─── Stubs (liboqs unavailable) ─────────────────────────────────────────── + * Each entry point returns the same JSON error so callers can inspect a + * single canonical "missing primitive" string. pq_verify is the lone + * exception — verifying without liboqs simply means "not verified", so + * returning Bool false (0) keeps the type contract intact. */ + +#define EL_PQ_NO_LIB "liboqs not linked, post-quantum primitives unavailable" + +el_val_t pq_keygen_signature(void) { return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_sign(el_val_t sk, el_val_t msg) { (void)sk; (void)msg; return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_verify(el_val_t pk, el_val_t msg, el_val_t sig) { (void)pk; (void)msg; (void)sig; return EL_INT(0); } +el_val_t pq_kem_keygen(void) { return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_kem_encaps(el_val_t pk) { (void)pk; return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_kem_decaps(el_val_t sk, el_val_t ct) { (void)sk; (void)ct; return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_hybrid_keygen(void) { return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_hybrid_handshake(el_val_t pub) { (void)pub; return pq_error(EL_PQ_NO_LIB); } + +#else /* EL_HAVE_LIBOQS */ + +/* ─── Dilithium-3 / ML-DSA-65 signatures ──────────────────────────────── + * + * NIST FIPS 204 standardized CRYSTALS-Dilithium as ML-DSA. ML-DSA-65 is the + * FIPS form of what we historically called Dilithium-3 — same algorithm + * family, same security level, identical key/sig sizes, but with a couple + * of standardization-driven tweaks (e.g. domain separation in the message + * binding). liboqs 0.12+ exposes both names; 0.15+ retired the legacy + * "Dilithium" constants in favour of "ML-DSA". We prefer ML-DSA-65 if the + * header advertises it, fall back to Dilithium-3 otherwise. Anything + * already signed with the older constant remains verifiable against that + * same constant — callers should pin the algorithm via the OQS_SIG handle's + * method_name field if they need to interoperate with archival signatures. */ + +#if defined(OQS_SIG_alg_ml_dsa_65) +# define EL_DILITHIUM_ALG OQS_SIG_alg_ml_dsa_65 +#elif defined(OQS_SIG_alg_dilithium_3) +# define EL_DILITHIUM_ALG OQS_SIG_alg_dilithium_3 +#else +# define EL_DILITHIUM_ALG "ML-DSA-65" /* string fallback; runtime probe catches misconfig */ +#endif + +el_val_t pq_keygen_signature(void) { + OQS_SIG* sig = OQS_SIG_new(EL_DILITHIUM_ALG); + if (!sig) return pq_error("OQS_SIG_new(dilithium-3) failed"); + unsigned char* pk = (unsigned char*)malloc(sig->length_public_key); + unsigned char* sk = (unsigned char*)malloc(sig->length_secret_key); + if (!pk || !sk) { free(pk); free(sk); OQS_SIG_free(sig); return pq_error("oom"); } + if (OQS_SIG_keypair(sig, pk, sk) != OQS_SUCCESS) { + free(pk); free(sk); OQS_SIG_free(sig); + return pq_error("dilithium-3 keypair generation failed"); + } + el_val_t pk_hex = el_hex_encode(pk, sig->length_public_key); + el_val_t sk_hex = el_hex_encode(sk, sig->length_secret_key); + OQS_MEM_secure_free(sk, sig->length_secret_key); + free(pk); + + const char* pks = EL_CSTR(pk_hex); + const char* sks = EL_CSTR(sk_hex); + char* buf = el_strbuf(strlen(pks) + strlen(sks) + 64); + sprintf(buf, "{\"public_key\":\"%s\",\"secret_key\":\"%s\"}", pks, sks); + OQS_SIG_free(sig); + return el_wrap_str(buf); +} + +el_val_t pq_sign(el_val_t secret_key_hex, el_val_t message) { + size_t sk_len = 0; + unsigned char* sk = el_hex_decode(EL_CSTR(secret_key_hex), &sk_len); + if (!sk) return pq_error("invalid hex in secret_key"); + + OQS_SIG* sig = OQS_SIG_new(EL_DILITHIUM_ALG); + if (!sig) return pq_error("OQS_SIG_new(dilithium-3) failed"); + if (sk_len != sig->length_secret_key) { + OQS_SIG_free(sig); + return pq_error("secret_key length mismatch for dilithium-3"); + } + + const char* msg = EL_CSTR(message); + size_t msg_len = el_input_len(msg); + unsigned char* signature = (unsigned char*)malloc(sig->length_signature); + size_t signature_len = sig->length_signature; + if (!signature) { OQS_SIG_free(sig); return pq_error("oom"); } + + if (OQS_SIG_sign(sig, signature, &signature_len, + (const unsigned char*)(msg ? msg : ""), msg_len, sk) != OQS_SUCCESS) { + free(signature); OQS_SIG_free(sig); + return pq_error("dilithium-3 sign failed"); + } + el_val_t sig_hex = el_hex_encode(signature, signature_len); + free(signature); OQS_SIG_free(sig); + return sig_hex; +} + +el_val_t pq_verify(el_val_t public_key_hex, el_val_t message, el_val_t signature_hex) { + size_t pk_len = 0, sig_len = 0; + unsigned char* pk = el_hex_decode(EL_CSTR(public_key_hex), &pk_len); + unsigned char* signature = el_hex_decode(EL_CSTR(signature_hex), &sig_len); + if (!pk || !signature) return EL_INT(0); + + OQS_SIG* sig = OQS_SIG_new(EL_DILITHIUM_ALG); + if (!sig) return EL_INT(0); + if (pk_len != sig->length_public_key) { OQS_SIG_free(sig); return EL_INT(0); } + + const char* msg = EL_CSTR(message); + size_t msg_len = el_input_len(msg); + OQS_STATUS rc = OQS_SIG_verify(sig, + (const unsigned char*)(msg ? msg : ""), msg_len, + signature, sig_len, pk); + OQS_SIG_free(sig); + return (rc == OQS_SUCCESS) ? EL_INT(1) : EL_INT(0); +} + +/* ─── Kyber-768 / ML-KEM-768 KEM ──────────────────────────────────────── + * + * NIST FIPS 203 standardized CRYSTALS-Kyber as ML-KEM. ML-KEM-768 is the + * FIPS form of what we historically called Kyber-768. Same situation as + * Dilithium → ML-DSA: prefer the standardized constant, fall back to the + * legacy name. liboqs 0.15.0 still exposes OQS_KEM_alg_kyber_768; the + * algorithm is identical at the wire level to ML-KEM-768 except for FIPS + * domain-separation tweaks, so the two ciphertexts/keys are NOT + * cross-compatible. Pin the constant for archival material. */ + +#if defined(OQS_KEM_alg_ml_kem_768) +# define EL_KYBER_ALG OQS_KEM_alg_ml_kem_768 +#elif defined(OQS_KEM_alg_kyber_768) +# define EL_KYBER_ALG OQS_KEM_alg_kyber_768 +#else +# define EL_KYBER_ALG "ML-KEM-768" +#endif + +el_val_t pq_kem_keygen(void) { + OQS_KEM* kem = OQS_KEM_new(EL_KYBER_ALG); + if (!kem) return pq_error("OQS_KEM_new(kyber-768) failed"); + unsigned char* pk = (unsigned char*)malloc(kem->length_public_key); + unsigned char* sk = (unsigned char*)malloc(kem->length_secret_key); + if (!pk || !sk) { free(pk); free(sk); OQS_KEM_free(kem); return pq_error("oom"); } + if (OQS_KEM_keypair(kem, pk, sk) != OQS_SUCCESS) { + free(pk); free(sk); OQS_KEM_free(kem); + return pq_error("kyber-768 keypair generation failed"); + } + el_val_t pk_hex = el_hex_encode(pk, kem->length_public_key); + el_val_t sk_hex = el_hex_encode(sk, kem->length_secret_key); + OQS_MEM_secure_free(sk, kem->length_secret_key); + free(pk); + + const char* pks = EL_CSTR(pk_hex); + const char* sks = EL_CSTR(sk_hex); + char* buf = el_strbuf(strlen(pks) + strlen(sks) + 64); + sprintf(buf, "{\"public_key\":\"%s\",\"secret_key\":\"%s\"}", pks, sks); + OQS_KEM_free(kem); + return el_wrap_str(buf); +} + +el_val_t pq_kem_encaps(el_val_t public_key_hex) { + size_t pk_len = 0; + unsigned char* pk = el_hex_decode(EL_CSTR(public_key_hex), &pk_len); + if (!pk) return pq_error("invalid hex in public_key"); + + OQS_KEM* kem = OQS_KEM_new(EL_KYBER_ALG); + if (!kem) return pq_error("OQS_KEM_new(kyber-768) failed"); + if (pk_len != kem->length_public_key) { + OQS_KEM_free(kem); + return pq_error("public_key length mismatch for kyber-768"); + } + unsigned char* ct = (unsigned char*)malloc(kem->length_ciphertext); + unsigned char* ss = (unsigned char*)malloc(kem->length_shared_secret); + if (!ct || !ss) { free(ct); free(ss); OQS_KEM_free(kem); return pq_error("oom"); } + if (OQS_KEM_encaps(kem, ct, ss, pk) != OQS_SUCCESS) { + free(ct); free(ss); OQS_KEM_free(kem); + return pq_error("kyber-768 encapsulation failed"); + } + el_val_t ct_hex = el_hex_encode(ct, kem->length_ciphertext); + el_val_t ss_hex = el_hex_encode(ss, kem->length_shared_secret); + free(ct); + OQS_MEM_secure_free(ss, kem->length_shared_secret); + + const char* cts = EL_CSTR(ct_hex); + const char* sss = EL_CSTR(ss_hex); + char* buf = el_strbuf(strlen(cts) + strlen(sss) + 64); + sprintf(buf, "{\"ciphertext\":\"%s\",\"shared_secret\":\"%s\"}", cts, sss); + OQS_KEM_free(kem); + return el_wrap_str(buf); +} + +el_val_t pq_kem_decaps(el_val_t secret_key_hex, el_val_t ciphertext_hex) { + size_t sk_len = 0, ct_len = 0; + unsigned char* sk = el_hex_decode(EL_CSTR(secret_key_hex), &sk_len); + unsigned char* ct = el_hex_decode(EL_CSTR(ciphertext_hex), &ct_len); + if (!sk || !ct) return pq_error("invalid hex in inputs"); + + OQS_KEM* kem = OQS_KEM_new(EL_KYBER_ALG); + if (!kem) return pq_error("OQS_KEM_new(kyber-768) failed"); + if (sk_len != kem->length_secret_key || ct_len != kem->length_ciphertext) { + OQS_KEM_free(kem); + return pq_error("input length mismatch for kyber-768"); + } + unsigned char* ss = (unsigned char*)malloc(kem->length_shared_secret); + if (!ss) { OQS_KEM_free(kem); return pq_error("oom"); } + /* Kyber is IND-CCA via Fujisaki-Okamoto: decaps always returns *some* + * shared_secret even on tampered ciphertext (an implicit-rejection value + * derived from sk). Protocols MUST confirm the shared_secret matches via + * a subsequent step (e.g. AEAD tag, key-confirmation MAC) — do not + * assume decaps success implies authenticity. */ + if (OQS_KEM_decaps(kem, ss, ct, sk) != OQS_SUCCESS) { + free(ss); OQS_KEM_free(kem); + return pq_error("kyber-768 decapsulation failed"); + } + el_val_t ss_hex = el_hex_encode(ss, kem->length_shared_secret); + OQS_MEM_secure_free(ss, kem->length_shared_secret); + OQS_KEM_free(kem); + return ss_hex; +} + +/* ─── Hybrid handshake (X25519 + Kyber-768, HKDF-SHA256 combined) ─────── */ + +#if !EL_HAVE_OPENSSL + +el_val_t pq_hybrid_keygen(void) { + return pq_error("hybrid handshake requires OpenSSL (X25519); rebuild with -lcrypto"); +} +el_val_t pq_hybrid_handshake(el_val_t pub) { + (void)pub; + return pq_error("hybrid handshake requires OpenSSL (X25519); rebuild with -lcrypto"); +} + +#else /* EL_HAVE_OPENSSL */ + +/* HKDF-SHA256 (RFC 5869) — Extract+Expand. Reuses the inline HMAC-SHA256 + * already in this file. Empty salt → 32 zero bytes per the RFC. */ +static void el_hkdf_sha256(const unsigned char* salt, size_t salt_len, + const unsigned char* ikm, size_t ikm_len, + const unsigned char* info, size_t info_len, + unsigned char* out, size_t out_len) { + unsigned char zero_salt[32] = {0}; + if (salt_len == 0) { salt = zero_salt; salt_len = 32; } + unsigned char prk[32]; + el_hmac_sha256(salt, salt_len, ikm, ikm_len, prk); + + unsigned char t[32]; + size_t produced = 0; + unsigned char counter = 1; + unsigned char* buf = (unsigned char*)malloc(32 + info_len + 1); + if (!buf) { fputs("el_runtime: hkdf oom\n", stderr); return; } + while (produced < out_len) { + size_t off = 0; + if (counter > 1) { memcpy(buf, t, 32); off = 32; } + if (info && info_len) { memcpy(buf + off, info, info_len); off += info_len; } + buf[off++] = counter; + el_hmac_sha256(prk, 32, buf, off, t); + size_t chunk = (out_len - produced > 32) ? 32 : (out_len - produced); + memcpy(out + produced, t, chunk); + produced += chunk; + counter++; + } + free(buf); +} + +/* X25519 keygen via OpenSSL EVP. Returns 1 on success. + * Fills pk[32] and sk[32] (raw X25519 byte strings, no DER wrapper). */ +static int el_x25519_keygen(unsigned char pk[32], unsigned char sk[32]) { + EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL); + if (!pctx) return 0; + if (EVP_PKEY_keygen_init(pctx) != 1) { EVP_PKEY_CTX_free(pctx); return 0; } + EVP_PKEY* key = NULL; + if (EVP_PKEY_keygen(pctx, &key) != 1) { EVP_PKEY_CTX_free(pctx); return 0; } + EVP_PKEY_CTX_free(pctx); + + size_t plen = 32, slen = 32; + if (EVP_PKEY_get_raw_public_key (key, pk, &plen) != 1 || plen != 32) { + EVP_PKEY_free(key); return 0; + } + if (EVP_PKEY_get_raw_private_key(key, sk, &slen) != 1 || slen != 32) { + EVP_PKEY_free(key); return 0; + } + EVP_PKEY_free(key); + return 1; +} + +/* X25519 ECDH: derive 32-byte shared secret from local sk and remote pk. */ +static int el_x25519_derive(const unsigned char sk[32], const unsigned char rpk[32], + unsigned char ss[32]) { + EVP_PKEY* my = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, sk, 32); + EVP_PKEY* rem = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, NULL, rpk, 32); + if (!my || !rem) { EVP_PKEY_free(my); EVP_PKEY_free(rem); return 0; } + EVP_PKEY_CTX* dctx = EVP_PKEY_CTX_new(my, NULL); + if (!dctx) { EVP_PKEY_free(my); EVP_PKEY_free(rem); return 0; } + int ok = 0; + size_t out_len = 32; + if (EVP_PKEY_derive_init(dctx) == 1 && + EVP_PKEY_derive_set_peer(dctx, rem) == 1 && + EVP_PKEY_derive(dctx, ss, &out_len) == 1 && + out_len == 32) ok = 1; + EVP_PKEY_CTX_free(dctx); + EVP_PKEY_free(my); + EVP_PKEY_free(rem); + return ok; +} + +/* Hybrid wire layout (binary form, before hex encode): + * public_key = x25519_pub (32) || kyber_pub (1184) → 1216 bytes + * secret_key = x25519_sec (32) || kyber_sec (2400) → 2432 bytes + * ciphertext = ephem_x25519_pub (32) || kyber_ct (1088) → 1120 bytes + * shared_secret = HKDF-SHA256(x25519_ss || kyber_ss, info="el-pq-hybrid-v1", 32 bytes) + * The keygen result also exposes the four component hex fields for callers + * that prefer to handle the legs independently. */ + +el_val_t pq_hybrid_keygen(void) { + OQS_KEM* kem = OQS_KEM_new(EL_KYBER_ALG); + if (!kem) return pq_error("OQS_KEM_new(kyber-768) failed"); + + unsigned char xpk[32], xsk[32]; + if (!el_x25519_keygen(xpk, xsk)) { + OQS_KEM_free(kem); + return pq_error("X25519 keygen failed"); + } + + unsigned char* kpk = (unsigned char*)malloc(kem->length_public_key); + unsigned char* ksk = (unsigned char*)malloc(kem->length_secret_key); + if (!kpk || !ksk) { free(kpk); free(ksk); OQS_KEM_free(kem); return pq_error("oom"); } + if (OQS_KEM_keypair(kem, kpk, ksk) != OQS_SUCCESS) { + free(kpk); free(ksk); OQS_KEM_free(kem); + return pq_error("kyber-768 keypair generation failed"); + } + + size_t pub_len = 32 + kem->length_public_key; + size_t sec_len = 32 + kem->length_secret_key; + unsigned char* pub_buf = (unsigned char*)malloc(pub_len); + unsigned char* sec_buf = (unsigned char*)malloc(sec_len); + if (!pub_buf || !sec_buf) { + free(pub_buf); free(sec_buf); free(kpk); + OQS_MEM_secure_free(ksk, kem->length_secret_key); + OQS_KEM_free(kem); return pq_error("oom"); + } + memcpy(pub_buf, xpk, 32); memcpy(pub_buf + 32, kpk, kem->length_public_key); + memcpy(sec_buf, xsk, 32); memcpy(sec_buf + 32, ksk, kem->length_secret_key); + + el_val_t x_pub_hex = el_hex_encode(xpk, 32); + el_val_t x_sec_hex = el_hex_encode(xsk, 32); + el_val_t k_pub_hex = el_hex_encode(kpk, kem->length_public_key); + el_val_t k_sec_hex = el_hex_encode(ksk, kem->length_secret_key); + el_val_t pub_hex = el_hex_encode(pub_buf, pub_len); + el_val_t sec_hex = el_hex_encode(sec_buf, sec_len); + + OQS_MEM_secure_free(ksk, kem->length_secret_key); + free(kpk); free(pub_buf); free(sec_buf); + OQS_KEM_free(kem); + memset(xsk, 0, 32); /* best-effort wipe of stack copy */ + + const char* xph = EL_CSTR(x_pub_hex); + const char* xsh = EL_CSTR(x_sec_hex); + const char* kph = EL_CSTR(k_pub_hex); + const char* ksh = EL_CSTR(k_sec_hex); + const char* pubh = EL_CSTR(pub_hex); + const char* sech = EL_CSTR(sec_hex); + + char* buf = el_strbuf(strlen(xph) + strlen(xsh) + strlen(kph) + strlen(ksh) + + strlen(pubh) + strlen(sech) + 256); + sprintf(buf, + "{\"x25519_pub\":\"%s\",\"x25519_sec\":\"%s\"," + "\"kyber_pub\":\"%s\",\"kyber_sec\":\"%s\"," + "\"public_key\":\"%s\",\"secret_key\":\"%s\"}", + xph, xsh, kph, ksh, pubh, sech); + return el_wrap_str(buf); +} + +/* Initiator-side handshake. Caller supplies the responder's combined public + * key (x25519_pub || kyber_pub, hex-encoded). The runtime: + * 1. Generates an ephemeral X25519 keypair, runs ECDH against the + * responder's static x25519_pub. + * 2. Runs Kyber-768 encaps against the responder's kyber_pub → kyber_ct, + * kyber_ss. + * 3. Combined shared = HKDF-SHA256(salt="", ikm = x25519_ss || kyber_ss, + * info = "el-pq-hybrid-v1", L = 32). + * 4. Returns combined ciphertext (= ephemeral_x25519_pub || kyber_ct) and + * the derived shared_secret. + * + * Responder side composition (intentionally not a separate runtime fn — + * trivial to express in El given pq_kem_decaps + a future x25519_derive + * primitive): split the ciphertext into ephem_xpk (32) and kyber_ct, run + * X25519(static_xsk, ephem_xpk) and pq_kem_decaps(static_kyber_sk, kyber_ct), + * then HKDF-SHA256 with the same salt/info to recover the same shared_secret. + * If a separate x25519 entry point becomes valuable, add `pq_hybrid_open` + * here taking (secret_key_combined, ciphertext_combined). */ +el_val_t pq_hybrid_handshake(el_val_t remote_pub_combined) { + size_t pub_len = 0; + unsigned char* rpub = el_hex_decode(EL_CSTR(remote_pub_combined), &pub_len); + if (!rpub) return pq_error("invalid hex in remote_pub_combined"); + + OQS_KEM* kem = OQS_KEM_new(EL_KYBER_ALG); + if (!kem) return pq_error("OQS_KEM_new(kyber-768) failed"); + if (pub_len != 32 + kem->length_public_key) { + OQS_KEM_free(kem); + return pq_error("remote_pub_combined length mismatch (expected x25519_pub || kyber_pub)"); + } + + unsigned char e_xpk[32], e_xsk[32], x_ss[32]; + if (!el_x25519_keygen(e_xpk, e_xsk)) { + OQS_KEM_free(kem); + return pq_error("X25519 ephemeral keygen failed"); + } + if (!el_x25519_derive(e_xsk, rpub, x_ss)) { + memset(e_xsk, 0, 32); + OQS_KEM_free(kem); + return pq_error("X25519 derive failed"); + } + memset(e_xsk, 0, 32); /* ephemeral; not needed after derive */ + + unsigned char* k_ct = (unsigned char*)malloc(kem->length_ciphertext); + unsigned char* k_ss = (unsigned char*)malloc(kem->length_shared_secret); + if (!k_ct || !k_ss) { + free(k_ct); free(k_ss); OQS_KEM_free(kem); + return pq_error("oom"); + } + if (OQS_KEM_encaps(kem, k_ct, k_ss, rpub + 32) != OQS_SUCCESS) { + free(k_ct); free(k_ss); OQS_KEM_free(kem); + return pq_error("kyber-768 encapsulation failed"); + } + + /* HKDF combine: ikm = x_ss || k_ss. */ + size_t ikm_len = 32 + kem->length_shared_secret; + unsigned char* ikm = (unsigned char*)malloc(ikm_len); + if (!ikm) { + free(k_ct); OQS_MEM_secure_free(k_ss, kem->length_shared_secret); + OQS_KEM_free(kem); + return pq_error("oom"); + } + memcpy(ikm, x_ss, 32); + memcpy(ikm + 32, k_ss, kem->length_shared_secret); + unsigned char combined[32]; + static const char info_str[] = "el-pq-hybrid-v1"; + el_hkdf_sha256(NULL, 0, ikm, ikm_len, + (const unsigned char*)info_str, sizeof(info_str) - 1, + combined, 32); + + memset(x_ss, 0, 32); + OQS_MEM_secure_free(k_ss, kem->length_shared_secret); + OQS_MEM_secure_free(ikm, ikm_len); + + /* Combined ciphertext = ephemeral_x25519_pub || kyber_ct. */ + size_t ct_len = 32 + kem->length_ciphertext; + unsigned char* combined_ct = (unsigned char*)malloc(ct_len); + if (!combined_ct) { free(k_ct); OQS_KEM_free(kem); return pq_error("oom"); } + memcpy(combined_ct, e_xpk, 32); + memcpy(combined_ct + 32, k_ct, kem->length_ciphertext); + free(k_ct); + OQS_KEM_free(kem); + + el_val_t ct_hex = el_hex_encode(combined_ct, ct_len); + el_val_t ss_hex = el_hex_encode(combined, 32); + free(combined_ct); + memset(combined, 0, 32); + + const char* cts = EL_CSTR(ct_hex); + const char* sss = EL_CSTR(ss_hex); + char* buf = el_strbuf(strlen(cts) + strlen(sss) + 64); + sprintf(buf, "{\"ciphertext\":\"%s\",\"shared_secret\":\"%s\"}", cts, sss); + return el_wrap_str(buf); +} + +#endif /* EL_HAVE_OPENSSL */ +#endif /* EL_HAVE_LIBOQS */ + +/* ─── AEAD: AES-256-GCM ──────────────────────────────────────────────────── + * + * Symmetric authenticated encryption used to wrap envelopes once a shared + * secret has been derived from the KEM (Kyber-768 / hybrid). The El surface + * is intentionally narrow: + * + * aead_encrypt(key_hex, plaintext) + * → {"nonce":"<24 hex>","ciphertext":"<...hex including 16-byte tag>"} + * + * aead_decrypt(key_hex, nonce_hex, ciphertext_hex) + * → plaintext String, or "" on auth failure / malformed input + * + * Conventions: + * - key_hex must decode to exactly 32 bytes (AES-256). Callers that hold + * a longer KEM shared_secret should normalize via SHA3-256(ss) → 32 bytes + * before passing it in. (Kyber-768's shared_secret is already 32 bytes, + * but keeping this contract explicit lets the El side be agnostic.) + * - nonce is a fresh 12-byte random value drawn from the OS CSPRNG. Caller + * never picks the nonce — eliminates the GCM nonce-reuse footgun entirely. + * - tag is the standard 16 bytes, appended to ciphertext per RFC 5116. + * `ciphertext` field is therefore (plaintext_len + 16) bytes, hex-encoded. + * - No associated data (AAD). If we later need bound metadata, add a + * length-prefixed AAD argument and bump the envelope version tag. + * + * Failure mode: + * aead_encrypt returns http_error_json(...) on input/system failure. + * aead_decrypt returns the empty string on ANY failure (including auth-tag + * mismatch). Callers MUST check for "" before using the result. */ + +#if !__has_include() + +el_val_t aead_encrypt(el_val_t key_hex, el_val_t plaintext) { + (void)key_hex; (void)plaintext; + return http_error_json("aead_encrypt requires OpenSSL (libcrypto); rebuild with -lcrypto"); +} +el_val_t aead_decrypt(el_val_t key_hex, el_val_t nonce_hex, el_val_t ciphertext_hex) { + (void)key_hex; (void)nonce_hex; (void)ciphertext_hex; + return el_wrap_str(el_strdup("")); +} + +#else /* OpenSSL available */ + +#include +#include + +el_val_t aead_encrypt(el_val_t key_hex, el_val_t plaintext) { + size_t key_len = 0; + unsigned char* key = el_hex_decode(EL_CSTR(key_hex), &key_len); + if (!key) return http_error_json("invalid hex in key"); + if (key_len != 32) return http_error_json("aead key must be 32 bytes (64 hex chars) for AES-256-GCM"); + + const char* pt = EL_CSTR(plaintext); + size_t pt_len = el_input_len(pt); + if (!pt) pt = ""; + + unsigned char nonce[12]; + if (RAND_bytes(nonce, 12) != 1) return http_error_json("OS CSPRNG failed (RAND_bytes)"); + + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + if (!ctx) return http_error_json("EVP_CIPHER_CTX_new failed"); + + if (EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) != 1) { + EVP_CIPHER_CTX_free(ctx); return http_error_json("aes-256-gcm init failed"); + } + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL) != 1) { + EVP_CIPHER_CTX_free(ctx); return http_error_json("set ivlen failed"); + } + if (EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce) != 1) { + EVP_CIPHER_CTX_free(ctx); return http_error_json("aes-256-gcm key/iv init failed"); + } + + /* GCM ciphertext is the same length as plaintext; we append a 16-byte + * authentication tag for AEAD semantics. Allocate plaintext_len + 16. */ + unsigned char* ct = (unsigned char*)malloc(pt_len + 16); + if (!ct) { EVP_CIPHER_CTX_free(ctx); return http_error_json("oom"); } + int outlen = 0, total = 0; + if (EVP_EncryptUpdate(ctx, ct, &outlen, (const unsigned char*)pt, (int)pt_len) != 1) { + free(ct); EVP_CIPHER_CTX_free(ctx); return http_error_json("aes-256-gcm update failed"); + } + total += outlen; + if (EVP_EncryptFinal_ex(ctx, ct + total, &outlen) != 1) { + free(ct); EVP_CIPHER_CTX_free(ctx); return http_error_json("aes-256-gcm final failed"); + } + total += outlen; + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, ct + total) != 1) { + free(ct); EVP_CIPHER_CTX_free(ctx); return http_error_json("aes-256-gcm get tag failed"); + } + EVP_CIPHER_CTX_free(ctx); + + el_val_t nonce_hex_v = el_hex_encode(nonce, 12); + el_val_t ct_hex_v = el_hex_encode(ct, (size_t)total + 16); + free(ct); + + const char* nh = EL_CSTR(nonce_hex_v); + const char* ch = EL_CSTR(ct_hex_v); + char* buf = el_strbuf(strlen(nh) + strlen(ch) + 48); + sprintf(buf, "{\"nonce\":\"%s\",\"ciphertext\":\"%s\"}", nh, ch); + return el_wrap_str(buf); +} + +el_val_t aead_decrypt(el_val_t key_hex, el_val_t nonce_hex, el_val_t ciphertext_hex) { + size_t key_len = 0, nonce_len = 0, ct_len = 0; + unsigned char* key = el_hex_decode(EL_CSTR(key_hex), &key_len); + unsigned char* nonce = el_hex_decode(EL_CSTR(nonce_hex), &nonce_len); + unsigned char* ct = el_hex_decode(EL_CSTR(ciphertext_hex), &ct_len); + if (!key || !nonce || !ct) return el_wrap_str(el_strdup("")); + if (key_len != 32 || nonce_len != 12) return el_wrap_str(el_strdup("")); + if (ct_len < 16) return el_wrap_str(el_strdup("")); + + size_t body_len = ct_len - 16; + const unsigned char* tag = ct + body_len; + + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + if (!ctx) return el_wrap_str(el_strdup("")); + + if (EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) != 1 || + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL) != 1 || + EVP_DecryptInit_ex(ctx, NULL, NULL, key, nonce) != 1) { + EVP_CIPHER_CTX_free(ctx); return el_wrap_str(el_strdup("")); + } + + unsigned char* pt = (unsigned char*)malloc(body_len + 1); + if (!pt) { EVP_CIPHER_CTX_free(ctx); return el_wrap_str(el_strdup("")); } + int outlen = 0, total = 0; + if (EVP_DecryptUpdate(ctx, pt, &outlen, ct, (int)body_len) != 1) { + free(pt); EVP_CIPHER_CTX_free(ctx); return el_wrap_str(el_strdup("")); + } + total += outlen; + /* Set expected tag before final — GCM's final step is where auth happens. */ + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, (void*)tag) != 1) { + free(pt); EVP_CIPHER_CTX_free(ctx); return el_wrap_str(el_strdup("")); + } + int rc = EVP_DecryptFinal_ex(ctx, pt + total, &outlen); + EVP_CIPHER_CTX_free(ctx); + if (rc != 1) { + /* Auth failure or padding/length mismatch. Return empty so callers + * cannot accidentally treat tampered ciphertext as a valid message. */ + free(pt); + return el_wrap_str(el_strdup("")); + } + total += outlen; + pt[total] = '\0'; + + /* Copy into the el arena so the caller-visible string outlives this fn. */ + char* out = el_strbuf((size_t)total); + memcpy(out, pt, (size_t)total); + out[total] = '\0'; + free(pt); + return el_wrap_str(out); +} + +#endif /* __has_include() */ + +#ifdef HAVE_CURL +/* ──────────────────────────────────────────────────────────────────────────── + * OTLP/HTTP observability — logs, traces, metrics + * + * Design goals: + * - Zero blocking on the request path. Producers append to in-memory + * ring buffers; a single worker thread flushes to the OTLP endpoint. + * - Drop-on-failure semantics. If the endpoint is unreachable or slow, + * we drop telemetry rather than back-pressure into the request handler. + * - Best-effort serialization. Each record is pre-serialized as JSON when + * the El program calls the primitive; the worker just batches. + * - Configuration via env vars: + * OTLP_ENDPOINT e.g. https://alloy.neuralplatform.ai:4318 + * OTEL_SERVICE_NAME e.g. neuron-web (default: argv[0] basename) + * OTEL_SERVICE_VERSION (default: "0.0.0") + * OTEL_RESOURCE_ATTRS comma-sep k=v pairs (optional) + * + * Wire format: OTLP/HTTP JSON. Three endpoints: + * POST {endpoint}/v1/logs — log records + * POST {endpoint}/v1/traces — spans + * POST {endpoint}/v1/metrics — counter/gauge points + * + * El programs see four primitives: + * trace_span_start(name) -> SpanHandle (just a string id) + * trace_span_end(handle) (computes duration, queues) + * emit_log(level, msg, fields_json) (queues a log record) + * emit_metric(name, value, tags_json) (queues a counter increment) + * ──────────────────────────────────────────────────────────────────────────── + */ + +#define OTLP_BUF_CAP 4096 /* per-buffer ring size */ +#define OTLP_FLUSH_MS 2000 /* flush every 2s */ +#define OTLP_BATCH_MAX 200 /* up to 200 records per POST */ + +typedef struct { + char* data; /* malloc'd JSON fragment for this record */ +} OtlpRec; + +typedef struct { + OtlpRec ring[OTLP_BUF_CAP]; + size_t head; /* next write slot */ + size_t tail; /* next read slot */ + pthread_mutex_t mu; +} OtlpQueue; + +static OtlpQueue _otlp_logs = { .mu = PTHREAD_MUTEX_INITIALIZER }; +static OtlpQueue _otlp_traces = { .mu = PTHREAD_MUTEX_INITIALIZER }; +static OtlpQueue _otlp_metrics = { .mu = PTHREAD_MUTEX_INITIALIZER }; + +static char* _otlp_endpoint = NULL; /* e.g. https://alloy.neuralplatform.ai:4318 */ +static char* _otlp_service_name = NULL; +static char* _otlp_service_version = NULL; +static int _otlp_initialized = 0; +static pthread_t _otlp_worker_thread; + +/* enqueue — returns 1 if accepted, 0 if dropped (full buffer or no endpoint) */ +static int otlp_enqueue(OtlpQueue* q, const char* json) { + if (!_otlp_endpoint || !json) return 0; + pthread_mutex_lock(&q->mu); + size_t next_head = (q->head + 1) % OTLP_BUF_CAP; + if (next_head == q->tail) { + /* buffer full — drop oldest */ + free(q->ring[q->tail].data); + q->ring[q->tail].data = NULL; + q->tail = (q->tail + 1) % OTLP_BUF_CAP; + } + q->ring[q->head].data = strdup(json); + q->head = next_head; + pthread_mutex_unlock(&q->mu); + return 1; +} + +/* drain — copies up to OTLP_BATCH_MAX items into a comma-joined string, + * caller must free the result. Returns NULL if queue is empty. */ +static char* otlp_drain(OtlpQueue* q) { + pthread_mutex_lock(&q->mu); + if (q->head == q->tail) { pthread_mutex_unlock(&q->mu); return NULL; } + /* compute total length */ + size_t total = 0, count = 0; + size_t i = q->tail; + while (i != q->head && count < OTLP_BATCH_MAX) { + if (q->ring[i].data) total += strlen(q->ring[i].data) + 1; /* +1 for comma */ + i = (i + 1) % OTLP_BUF_CAP; + count++; + } + char* out = malloc(total + 4); + if (!out) { pthread_mutex_unlock(&q->mu); return NULL; } + out[0] = '\0'; + size_t off = 0; + i = q->tail; + count = 0; + while (i != q->head && count < OTLP_BATCH_MAX) { + if (q->ring[i].data) { + size_t l = strlen(q->ring[i].data); + if (off > 0) { out[off++] = ','; } + memcpy(out + off, q->ring[i].data, l); + off += l; + free(q->ring[i].data); + q->ring[i].data = NULL; + } + i = (i + 1) % OTLP_BUF_CAP; + count++; + } + out[off] = '\0'; + q->tail = i; + pthread_mutex_unlock(&q->mu); + return out; +} + +/* Build resource block once (service.name, service.version, host.name) */ +static char* otlp_resource_block(void) { + static char cached[1024]; + static int built = 0; + if (built) return cached; + char host[256] = "unknown"; + gethostname(host, sizeof(host) - 1); + snprintf(cached, sizeof(cached), + "{\"attributes\":[" + "{\"key\":\"service.name\",\"value\":{\"stringValue\":\"%s\"}}," + "{\"key\":\"service.version\",\"value\":{\"stringValue\":\"%s\"}}," + "{\"key\":\"host.name\",\"value\":{\"stringValue\":\"%s\"}}" + "]}", + _otlp_service_name ? _otlp_service_name : "el-app", + _otlp_service_version ? _otlp_service_version : "0.0.0", + host); + built = 1; + return cached; +} + +/* Best-effort POST. Drops on any error. */ +static void otlp_post(const char* path, const char* body) { + if (!_otlp_endpoint || !body || !*body) return; + char url[1024]; + snprintf(url, sizeof(url), "%s%s", _otlp_endpoint, path); + CURL* c = curl_easy_init(); + if (!c) return; + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, body); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)strlen(body)); + curl_easy_setopt(c, CURLOPT_HTTPHEADER, h); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, 3000L); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, NULL); /* discard response */ + curl_easy_perform(c); + curl_slist_free_all(h); + curl_easy_cleanup(c); +} + +/* Flush worker — runs forever until process exits */ +static void* otlp_worker(void* arg) { + (void)arg; + while (1) { + struct timespec ts = { OTLP_FLUSH_MS / 1000, (OTLP_FLUSH_MS % 1000) * 1000000L }; + nanosleep(&ts, NULL); + + char* logs = otlp_drain(&_otlp_logs); + if (logs && *logs) { + char body[OTLP_BUF_CAP * 8]; + int n = snprintf(body, sizeof(body), + "{\"resourceLogs\":[{\"resource\":%s," + "\"scopeLogs\":[{\"scope\":{\"name\":\"el-runtime\"}," + "\"logRecords\":[%s]}]}]}", + otlp_resource_block(), logs); + if (n > 0 && n < (int)sizeof(body)) otlp_post("/v1/logs", body); + } + free(logs); + + char* traces = otlp_drain(&_otlp_traces); + if (traces && *traces) { + char body[OTLP_BUF_CAP * 8]; + int n = snprintf(body, sizeof(body), + "{\"resourceSpans\":[{\"resource\":%s," + "\"scopeSpans\":[{\"scope\":{\"name\":\"el-runtime\"}," + "\"spans\":[%s]}]}]}", + otlp_resource_block(), traces); + if (n > 0 && n < (int)sizeof(body)) otlp_post("/v1/traces", body); + } + free(traces); + + char* metrics = otlp_drain(&_otlp_metrics); + if (metrics && *metrics) { + char body[OTLP_BUF_CAP * 8]; + int n = snprintf(body, sizeof(body), + "{\"resourceMetrics\":[{\"resource\":%s," + "\"scopeMetrics\":[{\"scope\":{\"name\":\"el-runtime\"}," + "\"metrics\":[%s]}]}]}", + otlp_resource_block(), metrics); + if (n > 0 && n < (int)sizeof(body)) otlp_post("/v1/metrics", body); + } + free(metrics); + } + return NULL; +} + +/* Initialize OTLP — called lazily on first emit. Idempotent. */ +static void otlp_lazy_init(void) { + if (_otlp_initialized) return; + static pthread_mutex_t once_mu = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock(&once_mu); + if (_otlp_initialized) { pthread_mutex_unlock(&once_mu); return; } + + const char* ep = getenv("OTLP_ENDPOINT"); + if (!ep || !*ep) { + _otlp_initialized = 1; + pthread_mutex_unlock(&once_mu); + return; + } + _otlp_endpoint = strdup(ep); + /* trim trailing slash */ + size_t l = strlen(_otlp_endpoint); + if (l > 0 && _otlp_endpoint[l - 1] == '/') _otlp_endpoint[l - 1] = '\0'; + + const char* svc = getenv("OTEL_SERVICE_NAME"); + _otlp_service_name = strdup(svc && *svc ? svc : "el-app"); + const char* ver = getenv("OTEL_SERVICE_VERSION"); + _otlp_service_version = strdup(ver && *ver ? ver : "0.0.0"); + + pthread_create(&_otlp_worker_thread, NULL, otlp_worker, NULL); + pthread_detach(_otlp_worker_thread); + _otlp_initialized = 1; + pthread_mutex_unlock(&once_mu); +} + +/* JSON-escape a string into out_buf. Returns chars written (excluding null). */ +static size_t otlp_json_escape(const char* in, char* out, size_t out_cap) { + size_t o = 0; + for (size_t i = 0; in[i] && o + 8 < out_cap; i++) { + unsigned char c = (unsigned char)in[i]; + if (c == '"') { out[o++] = '\\'; out[o++] = '"'; } + else if (c == '\\'){ out[o++] = '\\'; out[o++] = '\\'; } + else if (c == '\n'){ out[o++] = '\\'; out[o++] = 'n'; } + else if (c == '\r'){ out[o++] = '\\'; out[o++] = 'r'; } + else if (c == '\t'){ out[o++] = '\\'; out[o++] = 't'; } + else if (c < 0x20) { o += snprintf(out + o, out_cap - o, "\\u%04x", c); } + else { out[o++] = (char)c; } + } + out[o] = '\0'; + return o; +} + +/* ── Public El primitives ─────────────────────────────────────────────────── */ + +/* emit_log(level, msg, fields_json) — fields_json is a JSON object string or "" */ +el_val_t emit_log(el_val_t level_v, el_val_t msg_v, el_val_t fields_v) { + otlp_lazy_init(); + if (!_otlp_endpoint) return EL_INT(0); + const char* level = EL_CSTR(level_v); if (!level) level = "INFO"; + const char* msg = EL_CSTR(msg_v); if (!msg) msg = ""; + const char* fields = EL_CSTR(fields_v); if (!fields) fields = ""; + /* Map El level names to OTLP severity numbers */ + int sev_num = 9; /* INFO */ + if (strcmp(level, "TRACE") == 0) sev_num = 1; + else if (strcmp(level, "DEBUG") == 0) sev_num = 5; + else if (strcmp(level, "INFO") == 0) sev_num = 9; + else if (strcmp(level, "WARN") == 0 || strcmp(level, "WARNING") == 0) sev_num = 13; + else if (strcmp(level, "ERROR") == 0) sev_num = 17; + else if (strcmp(level, "FATAL") == 0) sev_num = 21; + char esc_msg[2048]; otlp_json_escape(msg, esc_msg, sizeof(esc_msg)); + /* unix nanos */ + struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); + long long now_nano = (long long)ts.tv_sec * 1000000000LL + ts.tv_nsec; + char rec[4096]; + int n = snprintf(rec, sizeof(rec), + "{\"timeUnixNano\":\"%lld\",\"severityNumber\":%d," + "\"severityText\":\"%s\"," + "\"body\":{\"stringValue\":\"%s\"}%s%s}", + now_nano, sev_num, level, esc_msg, + (fields && *fields) ? ",\"attributes\":" : "", + (fields && *fields) ? fields : ""); + if (n > 0 && n < (int)sizeof(rec)) otlp_enqueue(&_otlp_logs, rec); + return EL_INT(1); +} + +/* emit_metric(name, value, tags_json) — Sum (counter) data point. tags_json + * is a JSON array of {key, value} pairs or empty string. */ +el_val_t emit_metric(el_val_t name_v, el_val_t value_v, el_val_t tags_v) { + otlp_lazy_init(); + if (!_otlp_endpoint) return EL_INT(0); + const char* name = EL_CSTR(name_v); if (!name) name = "unknown"; + int64_t val = (int64_t)value_v; + const char* tags = EL_CSTR(tags_v); if (!tags) tags = ""; + char esc_name[256]; otlp_json_escape(name, esc_name, sizeof(esc_name)); + struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); + long long now_nano = (long long)ts.tv_sec * 1000000000LL + ts.tv_nsec; + char rec[4096]; + int n = snprintf(rec, sizeof(rec), + "{\"name\":\"%s\",\"sum\":{\"aggregationTemporality\":2,\"isMonotonic\":true," + "\"dataPoints\":[{\"asInt\":\"%lld\"," + "\"timeUnixNano\":\"%lld\"" + "%s%s}]}}", + esc_name, (long long)val, now_nano, + (tags && *tags) ? ",\"attributes\":" : "", + (tags && *tags) ? tags : ""); + if (n > 0 && n < (int)sizeof(rec)) otlp_enqueue(&_otlp_metrics, rec); + return EL_INT(1); +} + +/* trace_span_start(name) — returns a span handle (string of "traceid:spanid:start_nano:name") */ +el_val_t trace_span_start(el_val_t name_v) { + otlp_lazy_init(); + const char* name = EL_CSTR(name_v); if (!name) name = "span"; + /* generate 16-byte trace id and 8-byte span id */ + static _Thread_local int seeded = 0; + if (!seeded) { srand((unsigned int)(uintptr_t)pthread_self() ^ (unsigned int)time(NULL)); seeded = 1; } + char tid[33], sid[17]; + for (int i = 0; i < 32; i++) tid[i] = "0123456789abcdef"[rand() & 0xF]; + tid[32] = '\0'; + for (int i = 0; i < 16; i++) sid[i] = "0123456789abcdef"[rand() & 0xF]; + sid[16] = '\0'; + struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); + long long now_nano = (long long)ts.tv_sec * 1000000000LL + ts.tv_nsec; + char* handle = malloc(strlen(name) + 80); + if (!handle) return EL_STR(""); + sprintf(handle, "%s:%s:%lld:%s", tid, sid, now_nano, name); + el_arena_track(handle); + return EL_STR(handle); +} + +/* trace_span_end(handle) — emits the span with computed duration */ +el_val_t trace_span_end(el_val_t handle_v) { + otlp_lazy_init(); + if (!_otlp_endpoint) return EL_INT(0); + const char* h = EL_CSTR(handle_v); if (!h) return EL_INT(0); + /* parse "tid:sid:start_nano:name" */ + char tid[64], sid[32], rest[1024]; + long long start_nano = 0; + if (sscanf(h, "%63[^:]:%31[^:]:%lld:%1023[^\n]", tid, sid, &start_nano, rest) != 4) return EL_INT(0); + struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); + long long end_nano = (long long)ts.tv_sec * 1000000000LL + ts.tv_nsec; + char esc_name[1024]; otlp_json_escape(rest, esc_name, sizeof(esc_name)); + char rec[4096]; + int n = snprintf(rec, sizeof(rec), + "{\"traceId\":\"%s\",\"spanId\":\"%s\"," + "\"name\":\"%s\"," + "\"kind\":1," + "\"startTimeUnixNano\":\"%lld\"," + "\"endTimeUnixNano\":\"%lld\"," + "\"status\":{\"code\":1}}", + tid, sid, esc_name, start_nano, end_nano); + if (n > 0 && n < (int)sizeof(rec)) otlp_enqueue(&_otlp_traces, rec); + return EL_INT(1); +} + +/* Convenience: emit a one-shot timed event (emit start+end immediately). + * For El programs that want point events with duration baked in. */ +el_val_t emit_event(el_val_t name_v, el_val_t duration_ms_v) { + otlp_lazy_init(); + if (!_otlp_endpoint) return EL_INT(0); + const char* name = EL_CSTR(name_v); if (!name) name = "event"; + int64_t dur_ms = (int64_t)duration_ms_v; + el_val_t h = trace_span_start(EL_STR((char*)name)); + /* fudge start to be (now - duration) */ + (void)dur_ms; + return trace_span_end(h); +} + +#endif /* HAVE_CURL — OTLP */ + +/* ── Threading seed primitives ─────────────────────────────────────────────── + * __thread_create(fn_name, arg) -> Int spawn El fn in a pthread, return tid + * __thread_join(tid) -> String join thread, return result string + * __mutex_new() -> Int allocate a mutex, return handle + * __mutex_lock(m) lock mutex m + * __mutex_unlock(m) unlock mutex m + * + * Every El fn compiles to a global C symbol. __thread_create uses dlsym to + * look up the function by name and run it in a pthread. This means any El fn + * with signature (String) -> String is directly threadable. + */ + +typedef el_val_t (*ElFn1)(el_val_t); + +typedef struct { + ElFn1 fn; + el_val_t arg; + el_val_t result; +} ElThreadArg; + +#define EL_THREAD_MAX 256 + +typedef struct { + pthread_t tid; + ElThreadArg* arg; + int alive; +} ElThread; + +static ElThread _threads[EL_THREAD_MAX]; +static int _thread_count = 0; +static pthread_mutex_t _thread_alloc_mu = PTHREAD_MUTEX_INITIALIZER; + +static void* el_thread_runner(void* raw) { + ElThreadArg* a = (ElThreadArg*)raw; + a->result = a->fn(a->arg); + return NULL; +} + +el_val_t __thread_create(el_val_t fn_name_v, el_val_t arg_v) { + const char* sym = EL_CSTR(fn_name_v); + if (!sym || !*sym) return EL_INT(-1); + void* p = dlsym(RTLD_DEFAULT, sym); + if (!p) { + fprintf(stderr, "[__thread_create] symbol not found: %s\n", sym); + return EL_INT(-1); + } + ElThreadArg* a = (ElThreadArg*)malloc(sizeof(ElThreadArg)); + if (!a) return EL_INT(-1); + a->fn = (ElFn1)p; + a->arg = arg_v; + a->result = EL_STR(""); + + pthread_mutex_lock(&_thread_alloc_mu); + if (_thread_count >= EL_THREAD_MAX) { + pthread_mutex_unlock(&_thread_alloc_mu); + free(a); + fprintf(stderr, "[__thread_create] thread table full\n"); + return EL_INT(-1); + } + int slot = _thread_count++; + _threads[slot].arg = a; + _threads[slot].alive = 1; + pthread_mutex_unlock(&_thread_alloc_mu); + + if (pthread_create(&_threads[slot].tid, NULL, el_thread_runner, a) != 0) { + pthread_mutex_lock(&_thread_alloc_mu); + _thread_count--; + pthread_mutex_unlock(&_thread_alloc_mu); + free(a); + return EL_INT(-1); + } + return EL_INT(slot); +} + +el_val_t __thread_join(el_val_t tid_v) { + int slot = (int)(int64_t)tid_v; + if (slot < 0 || slot >= EL_THREAD_MAX) return EL_STR(""); + pthread_join(_threads[slot].tid, NULL); + el_val_t result = _threads[slot].arg->result; + free(_threads[slot].arg); + _threads[slot].alive = 0; + return result; +} + +/* Mutex table */ + +#define EL_MUTEX_MAX 64 + +typedef struct { + pthread_mutex_t mu; + int allocated; +} ElMutexEntry; + +static ElMutexEntry _mutexes[EL_MUTEX_MAX]; +static int _mutex_count = 0; +static pthread_mutex_t _mutex_alloc_mu = PTHREAD_MUTEX_INITIALIZER; + +el_val_t __mutex_new(void) { + pthread_mutex_lock(&_mutex_alloc_mu); + if (_mutex_count >= EL_MUTEX_MAX) { + pthread_mutex_unlock(&_mutex_alloc_mu); + fprintf(stderr, "[__mutex_new] mutex table full\n"); + return EL_INT(-1); + } + int slot = _mutex_count++; + pthread_mutex_init(&_mutexes[slot].mu, NULL); + _mutexes[slot].allocated = 1; + pthread_mutex_unlock(&_mutex_alloc_mu); + return EL_INT(slot); +} + +void __mutex_lock(el_val_t m_v) { + int slot = (int)(int64_t)m_v; + if (slot < 0 || slot >= EL_MUTEX_MAX || !_mutexes[slot].allocated) return; + pthread_mutex_lock(&_mutexes[slot].mu); +} + +void __mutex_unlock(el_val_t m_v) { + int slot = (int)(int64_t)m_v; + if (slot < 0 || slot >= EL_MUTEX_MAX || !_mutexes[slot].allocated) return; + pthread_mutex_unlock(&_mutexes[slot].mu); +} + +/* ── Channels ─────────────────────────────────────────────────────────────── * + * Buffered MPMC channel backed by a mutex + condvar + circular buffer. + * channel_new(capacity) -> Int (handle) + * channel_send(ch, msg) — blocks if full (capacity > 0) or never (unbounded) + * channel_recv(ch) -> String — blocks until a message is available + * channel_try_recv(ch) -> String — non-blocking, returns "" if empty + * channel_close(ch) — signal no more sends; recv drains remaining + * + * Bounded channels (cap > 0): circular buffer, sender blocks when full. + * Unbounded channels (cap == 0): dynamic array, sender never blocks. + */ +#define EL_CHANNEL_MAX 64 +#define EL_CHANNEL_BUF 1024 + +typedef struct { + char** buf; + int cap; /* 0 = unbounded (grows dynamically) */ + int head, tail, count; + int dyn_cap; /* allocated slots for unbounded mode */ + int closed; + pthread_mutex_t mu; + pthread_cond_t not_empty; + pthread_cond_t not_full; +} ElChannel; + +static ElChannel _channels[EL_CHANNEL_MAX]; +static int _channel_count = 0; +static pthread_mutex_t _channel_alloc_mu = PTHREAD_MUTEX_INITIALIZER; + +el_val_t __channel_new(el_val_t capacity_v) { + int cap = (int)(int64_t)capacity_v; + if (cap < 0) cap = 0; + + pthread_mutex_lock(&_channel_alloc_mu); + if (_channel_count >= EL_CHANNEL_MAX) { + pthread_mutex_unlock(&_channel_alloc_mu); + fprintf(stderr, "[__channel_new] channel table full\n"); + return EL_INT(-1); + } + int slot = _channel_count++; + pthread_mutex_unlock(&_channel_alloc_mu); + + ElChannel* ch = &_channels[slot]; + memset(ch, 0, sizeof(*ch)); + ch->cap = cap; + ch->closed = 0; + ch->head = 0; + ch->tail = 0; + ch->count = 0; + + if (cap > 0) { + /* Bounded: fixed circular buffer. */ + ch->buf = (char**)malloc((size_t)cap * sizeof(char*)); + ch->dyn_cap = cap; + } else { + /* Unbounded: start with EL_CHANNEL_BUF slots, grow as needed. */ + ch->buf = (char**)malloc(EL_CHANNEL_BUF * sizeof(char*)); + ch->dyn_cap = EL_CHANNEL_BUF; + } + if (!ch->buf) { + fprintf(stderr, "[__channel_new] out of memory\n"); + return EL_INT(-1); + } + + pthread_mutex_init(&ch->mu, NULL); + pthread_cond_init(&ch->not_empty, NULL); + pthread_cond_init(&ch->not_full, NULL); + + return EL_INT(slot); +} + +void __channel_send(el_val_t ch_v, el_val_t msg_v) { + int slot = (int)(int64_t)ch_v; + if (slot < 0 || slot >= EL_CHANNEL_MAX) return; + ElChannel* ch = &_channels[slot]; + + const char* msg = EL_CSTR(msg_v); + if (!msg) msg = ""; + char* copy = strdup(msg); /* channel owns the string */ + + pthread_mutex_lock(&ch->mu); + + if (ch->closed) { + /* Send on closed channel is a no-op (drop the message). */ + pthread_mutex_unlock(&ch->mu); + free(copy); + return; + } + + if (ch->cap > 0) { + /* Bounded: block while full. */ + while (ch->count >= ch->cap && !ch->closed) { + pthread_cond_wait(&ch->not_full, &ch->mu); + } + if (ch->closed) { + pthread_mutex_unlock(&ch->mu); + free(copy); + return; + } + ch->buf[ch->tail] = copy; + ch->tail = (ch->tail + 1) % ch->cap; + ch->count++; + } else { + /* Unbounded: grow the buffer if needed. */ + if (ch->count >= ch->dyn_cap) { + int new_cap = ch->dyn_cap * 2; + char** grown = (char**)realloc(ch->buf, (size_t)new_cap * sizeof(char*)); + if (!grown) { + pthread_mutex_unlock(&ch->mu); + free(copy); + fprintf(stderr, "[__channel_send] out of memory growing channel\n"); + return; + } + /* The circular buffer may have wrapped. Linearise it first. + * In unbounded mode head is always 0 (we append at tail, drain + * from head), so a simple memmove isn't needed — but if the + * buffer did wrap (tail < head after growth), we need to fix up. + * Simplest safe path: if tail wrapped, move the head..old_cap + * segment to new_cap..new_cap+(old_cap-head). */ + if (ch->tail < ch->head) { + /* Wrapped: [head..old_cap) is the front, [0..tail) is the back. */ + int front = ch->dyn_cap - ch->head; + memmove(grown + ch->dyn_cap, grown + ch->head, (size_t)front * sizeof(char*)); + ch->head = ch->dyn_cap; + } + ch->buf = grown; + ch->dyn_cap = new_cap; + } + ch->buf[ch->tail] = copy; + ch->tail = (ch->tail + 1) % ch->dyn_cap; + ch->count++; + } + + pthread_cond_signal(&ch->not_empty); + pthread_mutex_unlock(&ch->mu); +} + +el_val_t __channel_recv(el_val_t ch_v) { + int slot = (int)(int64_t)ch_v; + if (slot < 0 || slot >= EL_CHANNEL_MAX) return EL_STR(""); + ElChannel* ch = &_channels[slot]; + + pthread_mutex_lock(&ch->mu); + + /* Block until there is a message or the channel is closed and drained. */ + while (ch->count == 0 && !ch->closed) { + pthread_cond_wait(&ch->not_empty, &ch->mu); + } + + if (ch->count == 0) { + /* Closed and empty — signal EOF. */ + pthread_mutex_unlock(&ch->mu); + return EL_STR(""); + } + + int buf_cap = (ch->cap > 0) ? ch->cap : ch->dyn_cap; + char* msg = ch->buf[ch->head]; + ch->head = (ch->head + 1) % buf_cap; + ch->count--; + + pthread_cond_signal(&ch->not_full); + pthread_mutex_unlock(&ch->mu); + + /* Hand the string to the arena so it is freed after the request. */ + el_arena_track(msg); + return EL_STR(msg); +} + +el_val_t __channel_try_recv(el_val_t ch_v) { + int slot = (int)(int64_t)ch_v; + if (slot < 0 || slot >= EL_CHANNEL_MAX) return EL_STR(""); + ElChannel* ch = &_channels[slot]; + + pthread_mutex_lock(&ch->mu); + + if (ch->count == 0) { + pthread_mutex_unlock(&ch->mu); + return EL_STR(""); + } + + int buf_cap = (ch->cap > 0) ? ch->cap : ch->dyn_cap; + char* msg = ch->buf[ch->head]; + ch->head = (ch->head + 1) % buf_cap; + ch->count--; + + pthread_cond_signal(&ch->not_full); + pthread_mutex_unlock(&ch->mu); + + el_arena_track(msg); + return EL_STR(msg); +} + +void __channel_close(el_val_t ch_v) { + int slot = (int)(int64_t)ch_v; + if (slot < 0 || slot >= EL_CHANNEL_MAX) return; + ElChannel* ch = &_channels[slot]; + + pthread_mutex_lock(&ch->mu); + ch->closed = 1; + /* Wake all blocked recvers and senders so they can observe the close. */ + pthread_cond_broadcast(&ch->not_empty); + pthread_cond_broadcast(&ch->not_full); + pthread_mutex_unlock(&ch->mu); +} + +/* ── DHARMA runtime additions ──────────────────────────────────────────────── + * + * Functions required by the dharma registry service. Added here so the + * released el_runtime.c includes them without requiring dharma to bundle + * its own stubs. + * + * Functions added: + * list_len — alias for el_list_len (used in handlers.el) + * list_get — alias for el_list_get (used in handlers.el) + * json_array_push — append a pre-encoded JSON element to a JSON array string + * now_millis — milliseconds since Unix epoch (alias for time_now) + * unix_timestamp_ms — same as now_millis (alias) + * time_now_ms — same as now_millis (alias) + * log_info — stderr structured log at INFO level + * log_warn — stderr structured log at WARN level + * config — reads a config value from the environment + * http_patch — HTTP PATCH with JSON Content-Type + * http_post_engram — HTTP POST with optional X-API-Key header + * http_get_engram — HTTP GET with optional X-API-Key header + * str_to_bytes — encode a string as a JSON array of byte values + * bytes_to_str — decode a JSON array of byte values back to a string + * hash_sha256 — SHA-256 hex digest of a string + */ + +/* list_len — return the number of elements in a list. */ +el_val_t list_len(el_val_t list) { + return el_list_len(list); +} + +/* list_get — return the element at index i in a list. */ +el_val_t list_get(el_val_t list, el_val_t index) { + return el_list_get(list, index); +} + +/* json_array_push — append element (a pre-encoded JSON fragment, e.g. "\"foo\"" + * or "42") to the JSON array string arr. Returns a new JSON array string. + * Example: json_array_push("[]", "\"alice\"") -> "[\"alice\"]" + * json_array_push("[\"alice\"]", "\"bob\"") -> "[\"alice\",\"bob\"]" */ +el_val_t json_array_push(el_val_t arr_v, el_val_t elem_v) { + const char* arr = EL_CSTR(arr_v); + const char* elem = EL_CSTR(elem_v); + if (!arr || !*arr) arr = "[]"; + if (!elem || !*elem) elem = "null"; + + /* Trim whitespace, find the closing ']'. */ + const char* p = arr; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') { + /* Not an array — return a single-element array. */ + size_t n = strlen(elem) + 4; + char* out = el_strbuf(n); + snprintf(out, n, "[%s]", elem); + return el_wrap_str(out); + } + size_t arr_len = strlen(arr); + size_t elem_len = strlen(elem); + + /* Walk from the end to find the matching ']'. */ + const char* end = arr + arr_len - 1; + while (end > p && (*end == ' ' || *end == '\t' || *end == '\n' || *end == '\r')) end--; + if (*end != ']') { + /* Malformed — wrap elem in a new array. */ + size_t n = elem_len + 4; + char* out = el_strbuf(n); + snprintf(out, n, "[%s]", elem); + return el_wrap_str(out); + } + + /* Content between '[' and ']'. */ + const char* inner_start = p + 1; + const char* inner_end = end; /* points AT ']' */ + /* Check if the array is empty (only whitespace between brackets). */ + const char* q = inner_start; + while (q < inner_end && (*q == ' ' || *q == '\t' || *q == '\n' || *q == '\r')) q++; + int empty = (q == inner_end); + + /* Build: prefix + (comma if non-empty) + elem + "]" */ + size_t prefix_len = (size_t)(inner_end - arr); /* up to but not including ']' */ + size_t sep_len = empty ? 0 : 1; /* "," if non-empty */ + size_t out_len = prefix_len + sep_len + elem_len + 2; /* +"]" + NUL */ + char* out = el_strbuf(out_len); + memcpy(out, arr, prefix_len); + if (!empty) out[prefix_len] = ','; + memcpy(out + prefix_len + sep_len, elem, elem_len); + out[prefix_len + sep_len + elem_len] = ']'; + out[prefix_len + sep_len + elem_len + 1] = '\0'; + return el_wrap_str(out); +} + +/* now_millis — milliseconds since Unix epoch. */ +el_val_t now_millis(void) { + return time_now(); +} + +/* unix_timestamp_ms — same as now_millis. */ +el_val_t unix_timestamp_ms(void) { + return time_now(); +} + +/* time_now_ms — same as now_millis. */ +el_val_t time_now_ms(void) { + return time_now(); +} + +/* log_info — write a structured [INFO] line to stderr. */ +void log_info(el_val_t msg_v) { + const char* msg = EL_CSTR(msg_v); + fprintf(stderr, "[INFO] %s\n", msg ? msg : ""); +} + +/* log_warn — write a structured [WARN] line to stderr. */ +void log_warn(el_val_t msg_v) { + const char* msg = EL_CSTR(msg_v); + fprintf(stderr, "[WARN] %s\n", msg ? msg : ""); +} + +/* config — read a configuration value from the environment. + * Returns "" if the variable is not set (same as __env_get). */ +el_val_t config(el_val_t key_v) { + const char* key = EL_CSTR(key_v); + if (!key || !*key) return EL_STR(""); + const char* val = getenv(key); + if (!val) return EL_STR(""); + return el_wrap_str(el_strdup(val)); +} + +#ifdef HAVE_CURL +/* http_patch — HTTP PATCH request with Content-Type: application/json. + * Returns the response body (same error convention as http_post_json). */ +el_val_t http_patch(el_val_t url_v, el_val_t body_v) { + const char* url = EL_CSTR(url_v); + const char* body = EL_CSTR(body_v); + if (!url || !*url) return http_error_json("empty url"); + CURL* c = curl_easy_init(); + if (!c) return http_error_json("curl_easy_init failed"); + HttpBuf rb; httpbuf_init(&rb); + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, "PATCH"); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, body ? body : ""); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(body ? strlen(body) : 0)); + curl_easy_setopt(c, CURLOPT_HTTPHEADER, h); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, http_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, &rb); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, el_http_timeout_ms()); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-runtime/1.0"); + CURLcode rc = curl_easy_perform(c); + curl_slist_free_all(h); + curl_easy_cleanup(c); + if (rc != CURLE_OK) { + free(rb.data); + const char* m = errbuf[0] ? errbuf : curl_easy_strerror(rc); + return http_error_json(m); + } + return el_wrap_str(rb.data); +} + +/* http_post_engram — HTTP POST with optional X-API-Key header. + * If key is "" no authentication header is sent. */ +el_val_t http_post_engram(el_val_t url_v, el_val_t key_v, el_val_t body_v) { + const char* url = EL_CSTR(url_v); + const char* key = EL_CSTR(key_v); + const char* body = EL_CSTR(body_v); + if (!url || !*url) return http_error_json("empty url"); + CURL* c = curl_easy_init(); + if (!c) return http_error_json("curl_easy_init failed"); + HttpBuf rb; httpbuf_init(&rb); + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + if (key && *key) { + size_t n = strlen(key) + 32; + char* hdr = malloc(n); + snprintf(hdr, n, "X-API-Key: %s", key); + h = curl_slist_append(h, hdr); + free(hdr); + } + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, body ? body : ""); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(body ? strlen(body) : 0)); + curl_easy_setopt(c, CURLOPT_HTTPHEADER, h); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, http_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, &rb); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, el_http_timeout_ms()); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-runtime/1.0"); + CURLcode rc = curl_easy_perform(c); + curl_slist_free_all(h); + curl_easy_cleanup(c); + if (rc != CURLE_OK) { + free(rb.data); + const char* m = errbuf[0] ? errbuf : curl_easy_strerror(rc); + return http_error_json(m); + } + return el_wrap_str(rb.data); +} + +/* http_get_engram — HTTP GET with optional X-API-Key header. */ +el_val_t http_get_engram(el_val_t url_v, el_val_t key_v) { + const char* url = EL_CSTR(url_v); + const char* key = EL_CSTR(key_v); + if (!url || !*url) return http_error_json("empty url"); + CURL* c = curl_easy_init(); + if (!c) return http_error_json("curl_easy_init failed"); + HttpBuf rb; httpbuf_init(&rb); + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + struct curl_slist* h = NULL; + if (key && *key) { + size_t n = strlen(key) + 32; + char* hdr = malloc(n); + snprintf(hdr, n, "X-API-Key: %s", key); + h = curl_slist_append(h, hdr); + free(hdr); + } + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_HTTPGET, 1L); + if (h) curl_easy_setopt(c, CURLOPT_HTTPHEADER, h); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, http_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, &rb); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, el_http_timeout_ms()); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-runtime/1.0"); + CURLcode rc = curl_easy_perform(c); + if (h) curl_slist_free_all(h); + curl_easy_cleanup(c); + if (rc != CURLE_OK) { + free(rb.data); + const char* m = errbuf[0] ? errbuf : curl_easy_strerror(rc); + return http_error_json(m); + } + return el_wrap_str(rb.data); +} +#endif /* HAVE_CURL */ + +/* str_to_bytes — encode a string as a JSON array of unsigned byte values. + * "hello" -> "[104,101,108,108,111]" + * Used by db.el to store binary content in Engram JSON nodes. */ +el_val_t str_to_bytes(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s || !*s) return el_wrap_str(el_strdup("[]")); + size_t n = strlen(s); + /* Worst case: each byte is 3 digits + comma = 4 chars, plus "[]" + NUL. */ + char* out = el_strbuf(n * 4 + 3); + size_t pos = 0; + out[pos++] = '['; + for (size_t i = 0; i < n; i++) { + unsigned char b = (unsigned char)s[i]; + if (i > 0) out[pos++] = ','; + /* Write decimal representation of b. */ + if (b >= 100) { + out[pos++] = (char)('0' + b / 100); + out[pos++] = (char)('0' + (b / 10) % 10); + out[pos++] = (char)('0' + b % 10); + } else if (b >= 10) { + out[pos++] = (char)('0' + b / 10); + out[pos++] = (char)('0' + b % 10); + } else { + out[pos++] = (char)('0' + b); + } + } + out[pos++] = ']'; + out[pos] = '\0'; + return el_wrap_str(out); +} + +/* bytes_to_str — decode a JSON array of integer byte values back to a string. + * "[104,101,108,108,111]" -> "hello" + * Inverse of str_to_bytes. */ +el_val_t bytes_to_str(el_val_t arr_v) { + const char* s = EL_CSTR(arr_v); + if (!s) return el_wrap_str(el_strdup("")); + /* Skip whitespace, expect '['. */ + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s != '[') return el_wrap_str(el_strdup("")); + s++; + + /* Count elements to size the output buffer. */ + int64_t n = (int64_t)json_array_len(arr_v); + if (n <= 0) return el_wrap_str(el_strdup("")); + + char* out = el_strbuf((size_t)n + 1); + size_t pos = 0; + + /* Walk the array, parse each integer, store as a byte. */ + while (*s) { + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ']' || *s == '\0') break; + /* Parse decimal integer. */ + char* end_ptr; + long v = strtol(s, &end_ptr, 10); + if (end_ptr == s) break; /* parse failure */ + s = end_ptr; + if (v >= 0 && v <= 255) out[pos++] = (char)(unsigned char)v; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ',') { s++; continue; } + if (*s == ']' || *s == '\0') break; + } + out[pos] = '\0'; + return el_wrap_str(out); +} + +/* hash_sha256 — return the SHA-256 hex digest of a string. + * Uses the built-in el_sha256_oneshot implementation (no OpenSSL required). */ +el_val_t hash_sha256(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) s = ""; + unsigned char digest[32]; + el_sha256_oneshot((const unsigned char*)s, strlen(s), digest); + return el_hex_encode(digest, 32); +} + +/* ── __ prefixed aliases — public boundary for compiled El programs ────────── + * + * The El compiler's self-hosting back-end emits calls to __-prefixed function + * names (e.g. __println, __str_len). These wrappers forward to the existing + * el_runtime implementations so both naming conventions resolve at link time. + * + * Note: __thread_create and __thread_join are already defined above in the + * threading section; they are not repeated here. + * ──────────────────────────────────────────────────────────────────────────── */ + +/* I/O */ +el_val_t __println(el_val_t s) { return println(s); } +el_val_t __print(el_val_t s) { return print(s); } +el_val_t __readline(void) { return readline(); } + +/* String */ +el_val_t __int_to_str(el_val_t n) { return int_to_str(n); } +el_val_t __str_to_int(el_val_t s) { return str_to_int(s); } +el_val_t __float_to_str(el_val_t f) { return float_to_str(f); } +el_val_t __str_to_float(el_val_t s) { return str_to_float(s); } +el_val_t __str_len(el_val_t s) { return str_len(s); } +el_val_t __str_char_at(el_val_t s, el_val_t i) { return str_char_at(s, i); } + +el_val_t __str_cmp(el_val_t a, el_val_t b) { + const char* ca = EL_CSTR(a); + const char* cb = EL_CSTR(b); + if (!ca) ca = ""; + if (!cb) cb = ""; + return (el_val_t)strcmp(ca, cb); +} + +el_val_t __str_ncmp(el_val_t a, el_val_t b, el_val_t n) { + const char* ca = EL_CSTR(a); + const char* cb = EL_CSTR(b); + if (!ca) ca = ""; + if (!cb) cb = ""; + return (el_val_t)strncmp(ca, cb, (size_t)n); +} + +el_val_t __str_concat_raw(el_val_t a, el_val_t b) { return str_concat(a, b); } +el_val_t __str_slice_raw(el_val_t s, el_val_t start, el_val_t end) { return str_slice(s, start, end); } + +el_val_t __str_alloc(el_val_t n) { + if (n <= 0) n = 0; + char* buf = el_strbuf((size_t)n + 1); + memset(buf, 0, (size_t)n + 1); + return el_wrap_str(buf); +} + +el_val_t __str_set_char(el_val_t s, el_val_t i, el_val_t c) { + char* buf = (char*)(uintptr_t)s; + if (buf) buf[(size_t)i] = (char)c; + return s; +} + +/* URL encoding */ +el_val_t __url_encode(el_val_t s) { return url_encode(s); } +el_val_t __url_decode(el_val_t s) { return url_decode(s); } + +/* Environment */ +el_val_t __env_get(el_val_t key) { return env(key); } + +/* Subprocess */ +el_val_t __exec(el_val_t cmd) { return exec(cmd); } +el_val_t __exec_bg(el_val_t cmd) { return exec_bg(cmd); } + +/* Process */ +el_val_t __exit_program(el_val_t code) { return exit_program(code); } + +/* Filesystem */ +el_val_t __fs_exists(el_val_t path) { return fs_exists(path); } +el_val_t __fs_mkdir(el_val_t path) { return fs_mkdir(path); } +el_val_t __fs_read(el_val_t path) { return fs_read(path); } +el_val_t __fs_write(el_val_t path, el_val_t content) { return fs_write(path, content); } +el_val_t __fs_write_bytes(el_val_t path, el_val_t bytes, el_val_t n) { return fs_write_bytes(path, bytes, n); } +el_val_t __fs_list_raw(el_val_t path) { return fs_list_json(path); } + +/* HTTP server (no curl dependency) */ +el_val_t __http_response(el_val_t status, el_val_t headers_json, el_val_t body) { return http_response(status, headers_json, body); } +el_val_t __http_serve(el_val_t port, el_val_t handler) { return http_serve(port, handler); } +el_val_t __http_serve_v2(el_val_t port, el_val_t handler) { return http_serve_v2(port, handler); } + +/* HTTP conn fd / SSE — __http_conn_fd lives in el_seed.c; stubs provided here + * so el_runtime.c compiles standalone. When both translation units are linked + * the el_seed.c definitions win via their non-static linkage (strong symbols). + * These stubs are marked weak so they are silently overridden. */ +__attribute__((weak)) el_val_t __http_conn_fd(void) { return (el_val_t)(-1); } +__attribute__((weak)) el_val_t __http_sse_open(el_val_t conn_id) { (void)conn_id; return 0; } +__attribute__((weak)) el_val_t __http_sse_send(el_val_t conn_id, el_val_t data) { (void)conn_id; (void)data; return 0; } +__attribute__((weak)) el_val_t __http_sse_close(el_val_t conn_id) { (void)conn_id; return 0; } + +/* JSON */ +el_val_t __json_array_get(el_val_t json, el_val_t index) { return json_array_get(json, index); } +el_val_t __json_array_get_string(el_val_t json, el_val_t index) { return json_array_get_string(json, index); } +el_val_t __json_array_len(el_val_t json) { return json_array_len(json); } +el_val_t __json_get(el_val_t json, el_val_t key) { return json_get(json, key); } +el_val_t __json_get_raw(el_val_t json, el_val_t key) { return json_get_raw(json, key); } +el_val_t __json_set(el_val_t json, el_val_t key, el_val_t value){ return json_set(json, key, value); } +el_val_t __json_parse_map(el_val_t json_str) { return json_parse(json_str); } +el_val_t __json_stringify_val(el_val_t val) { return json_stringify(val); } + +/* Hashing */ +el_val_t __sha256_hex(el_val_t s) { return hash_sha256(s); } + +/* State K/V */ +el_val_t __state_del(el_val_t key) { return state_del(key); } +el_val_t __state_get(el_val_t key) { return state_get(key); } +el_val_t __state_keys(void) { return state_keys(); } +el_val_t __state_set(el_val_t key, el_val_t val) { return state_set(key, val); } + +/* UUID */ +el_val_t __uuid_v4(void) { return uuid_v4(); } + +/* Args */ +el_val_t __args_json(void) { return args(); } + +/* HTTP client aliases — require curl; defined inside #ifdef HAVE_CURL below + * with a matching stub in the #ifndef HAVE_CURL block. */ +#ifdef HAVE_CURL +el_val_t __http_do(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_map, el_val_t timeout_ms) { + /* timeout_ms is accepted for API compatibility but ignored here; + * el_runtime's http_do uses the EL_HTTP_TIMEOUT_MS env var instead. */ + (void)timeout_ms; + struct curl_slist* h = headers_from_map(headers_map); + el_val_t r = http_do(EL_CSTR(method), EL_CSTR(url), EL_CSTR(body), h); + if (h) curl_slist_free_all(h); + return r; +} + +/* __http_do_map — same as __http_do but headers_map arg is a JSON-string + * rather than an ElMap. Parse it first, then delegate. */ +el_val_t __http_do_map(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t timeout_ms) { + (void)timeout_ms; + /* Build a curl_slist from a JSON object {"Header":"value",...}. */ + const char* hj = EL_CSTR(headers_json); + struct curl_slist* h = NULL; + if (hj && *hj && *hj == '{') { + /* Walk the JSON pairs with a simple parser reusing json_get_string logic. */ + /* For correctness we just call the existing json_get iteration path. + * We duplicate the key-extraction loop from headers_from_map but driven + * by JSON rather than ElMap. Use json_get_raw to iterate is not easy + * without knowing keys, so accept the JSON string and build a tmp map. */ + el_val_t map = json_parse(EL_STR(hj)); + h = headers_from_map(map); + } + el_val_t r = http_do(EL_CSTR(method), EL_CSTR(url), EL_CSTR(body), h); + if (h) curl_slist_free_all(h); + return r; +} + +/* __http_do_map_to_file — same as __http_do_map but streams response body + * to a local file path rather than returning it as a string. */ +el_val_t __http_do_map_to_file(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t output_path) { + const char* hj = EL_CSTR(headers_json); + struct curl_slist* h = NULL; + if (hj && *hj && *hj == '{') { + el_val_t map = json_parse(EL_STR(hj)); + h = headers_from_map(map); + } + el_val_t r = http_do_to_file(EL_CSTR(method), EL_CSTR(url), EL_CSTR(body), + h, EL_CSTR(output_path)); + if (h) curl_slist_free_all(h); + return r; +} +#endif /* HAVE_CURL */ + +#ifndef HAVE_CURL +/* ── HAVE_CURL=0 stubs — compile without -lcurl for the elc CLI binary. ───── * + * These return a JSON error string so El programs get a clear message if they + * call HTTP/LLM functions in a curl-less build. */ +static el_val_t _no_curl_err(void) { + return el_wrap_str(el_strdup("{\"error\":\"not built with HAVE_CURL\"}")); +} +el_val_t http_get(el_val_t url) { (void)url; return _no_curl_err(); } +el_val_t http_post(el_val_t url, el_val_t body) { (void)url; (void)body; return _no_curl_err(); } +el_val_t http_post_json(el_val_t url, el_val_t body) { (void)url; (void)body; return _no_curl_err(); } +el_val_t http_get_with_headers(el_val_t url, el_val_t h) { (void)url; (void)h; return _no_curl_err(); } +el_val_t http_post_with_headers(el_val_t url, el_val_t b, el_val_t h) { (void)url; (void)b; (void)h; return _no_curl_err(); } +el_val_t http_post_json_with_headers(el_val_t url, el_val_t h, el_val_t b) { (void)url; (void)h; (void)b; return _no_curl_err(); } +el_val_t http_post_form_auth(el_val_t url, el_val_t b, el_val_t a) { (void)url; (void)b; (void)a; return _no_curl_err(); } +el_val_t http_delete(el_val_t url) { (void)url; return _no_curl_err(); } +el_val_t http_patch(el_val_t url, el_val_t body) { (void)url; (void)body; return _no_curl_err(); } +el_val_t http_get_to_file(el_val_t url, el_val_t h, el_val_t p) { (void)url; (void)h; (void)p; return _no_curl_err(); } +el_val_t http_post_to_file(el_val_t url, el_val_t b, el_val_t h, el_val_t p) { (void)url; (void)b; (void)h; (void)p; return _no_curl_err(); } +el_val_t http_post_engram(el_val_t url, el_val_t k, el_val_t b) { (void)url; (void)k; (void)b; return _no_curl_err(); } +el_val_t http_get_engram(el_val_t url, el_val_t k) { (void)url; (void)k; return _no_curl_err(); } +el_val_t llm_call(el_val_t m, el_val_t p) { (void)m; (void)p; return _no_curl_err(); } +el_val_t llm_call_system(el_val_t m, el_val_t s, el_val_t u) { (void)m; (void)s; (void)u; return _no_curl_err(); } +el_val_t llm_call_agentic(el_val_t m, el_val_t s, el_val_t u, el_val_t t) { (void)m; (void)s; (void)u; (void)t; return _no_curl_err(); } +el_val_t llm_vision(el_val_t m, el_val_t s, el_val_t p, el_val_t i) { (void)m; (void)s; (void)p; (void)i; return _no_curl_err(); } +el_val_t llm_models(void) { return el_list_empty(); } +void llm_register_tool(el_val_t n, el_val_t f) { (void)n; (void)f; } +/* __ HTTP stubs (no-curl build) */ +el_val_t __http_do(el_val_t m, el_val_t u, el_val_t b, el_val_t h, el_val_t t) { (void)m; (void)u; (void)b; (void)h; (void)t; return _no_curl_err(); } +el_val_t __http_do_map(el_val_t m, el_val_t u, el_val_t b, el_val_t h, el_val_t t) { (void)m; (void)u; (void)b; (void)h; (void)t; return _no_curl_err(); } +el_val_t __http_do_map_to_file(el_val_t m, el_val_t u, el_val_t b, el_val_t h, el_val_t p) { (void)m; (void)u; (void)b; (void)h; (void)p; return _no_curl_err(); } +#endif /* !HAVE_CURL */ diff --git a/ui/examples/native-hello-ios/NativeHello/el_runtime.h b/ui/examples/native-hello-ios/NativeHello/el_runtime.h new file mode 100644 index 0000000..2f9583f --- /dev/null +++ b/ui/examples/native-hello-ios/NativeHello/el_runtime.h @@ -0,0 +1,883 @@ +/* + * el_runtime.h — El language C runtime header + * + * Declares all built-in functions available to compiled El programs. + * Include this in every generated .c file. + * + * Value model: + * All El values are represented as el_val_t (= int64_t). + * On 64-bit systems a pointer fits in int64_t. + * String values are cast: (el_val_t)(uintptr_t)"hello" + * Integer values are stored directly. + * This lets arithmetic work naturally while still passing strings around. + * + * Type conventions (El -> C): + * String -> el_val_t (holds const char* via uintptr_t cast) + * Int -> el_val_t + * Bool -> el_val_t (0 = false, nonzero = true) + * Any -> el_val_t + * Void -> void + * + * Macros for convenience: + * 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_*). + * -lpthread — required for the HTTP server (one detached thread per + * connection, capped at 64 concurrent). + * -loqs — optional; required only when liboqs is installed and the + * pq_* / sha3_256_hex entry points are needed. Detected at + * compile time via __has_include(). + * -lcrypto — optional; pulled in alongside -loqs. Used for X25519 in + * pq_hybrid_* and HKDF-SHA256 derivation. + * + * Canonical compile command: + * cc -std=c11 -I el-compiler/runtime -lcurl -lpthread \ + * -o .c el-compiler/runtime/el_runtime.c + * + * With liboqs (post-quantum stack): + * cc -std=c11 -I el-compiler/runtime -lcurl -lpthread -loqs -lcrypto \ + * -o .c el-compiler/runtime/el_runtime.c + */ + +#pragma once + +#include +#include + +typedef int64_t el_val_t; + +#define EL_STR(s) ((el_val_t)(uintptr_t)(s)) +#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()` so the + * underlying bits represent the IEEE 754 double. Float-aware builtins + * (math, format, json) round-trip via these helpers. */ +static inline double el_to_float(el_val_t v) { + union { int64_t i; double f; } u; + u.i = (int64_t)v; + return u.f; +} + +static inline el_val_t el_from_float(double f) { + union { double f; int64_t i; } u; + u.f = f; + return (el_val_t)u.i; +} + +#ifdef __cplusplus +extern "C" { +#endif + +/* ── I/O ──────────────────────────────────────────────────────────────────── */ + +el_val_t println(el_val_t s); +el_val_t print(el_val_t s); +el_val_t readline(void); + +/* ── String builtins ─────────────────────────────────────────────────────── */ + +el_val_t el_str_concat(el_val_t a, el_val_t b); +el_val_t str_eq(el_val_t a, el_val_t b); +el_val_t str_starts_with(el_val_t s, el_val_t prefix); +el_val_t str_ends_with(el_val_t s, el_val_t suffix); +el_val_t str_len(el_val_t s); +el_val_t str_concat(el_val_t a, el_val_t b); +el_val_t int_to_str(el_val_t n); +el_val_t str_to_int(el_val_t s); +el_val_t native_str_to_int(el_val_t s); +el_val_t str_slice(el_val_t s, el_val_t start, el_val_t end); +el_val_t str_contains(el_val_t s, el_val_t sub); +el_val_t str_replace(el_val_t s, el_val_t from, el_val_t to); +el_val_t str_to_upper(el_val_t s); +el_val_t str_to_lower(el_val_t s); +el_val_t str_trim(el_val_t s); + +/* ── Math ────────────────────────────────────────────────────────────────── */ + +el_val_t el_abs(el_val_t n); +el_val_t el_max(el_val_t a, el_val_t b); +el_val_t el_min(el_val_t a, el_val_t b); + +/* ── Refcount (ARC) ────────────────────────────────────────────────────────── + * Lists and Maps carry a refcount. Strings and ints do not — el_retain and + * el_release are safe no-ops on non-refcounted values (they sniff a magic + * header at offset 0 and only act if the magic matches). + * + * Codegen emits these at let-binding shadowing, function entry (params), and + * function exit (locals other than the returned value). The refcount lets + * el_list_append and el_map_set mutate in place when uniquely owned (cheap) + * and copy-on-write when shared (preserves persistent semantics across + * accumulator patterns in the compiler itself). */ + +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, ...); +el_val_t el_list_len(el_val_t list); +el_val_t el_list_get(el_val_t list, el_val_t index); +el_val_t el_list_append(el_val_t list, el_val_t elem); +el_val_t el_list_empty(void); +el_val_t el_list_clone(el_val_t list); + +/* ── Map ─────────────────────────────────────────────────────────────────── */ + +el_val_t el_map_new(el_val_t pair_count, ...); +el_val_t el_get_field(el_val_t map, el_val_t key); +el_val_t el_map_get(el_val_t map, el_val_t key); +el_val_t el_map_set(el_val_t map, el_val_t key, el_val_t value); + +/* ── HTTP ─────────────────────────────────────────────────────────────────── */ + +el_val_t http_get(el_val_t url); +el_val_t http_post(el_val_t url, el_val_t body); +el_val_t http_post_json(el_val_t url, el_val_t json_body); +el_val_t http_get_with_headers(el_val_t url, el_val_t headers_map); +el_val_t http_post_with_headers(el_val_t url, el_val_t body, el_val_t headers_map); +el_val_t http_post_json_with_headers(el_val_t url, el_val_t headers_map, el_val_t json_body); +el_val_t http_post_form_auth(el_val_t url, el_val_t form_body, el_val_t auth_header); +el_val_t http_delete(el_val_t url); +el_val_t http_serve(el_val_t port, el_val_t handler); +el_val_t http_set_handler(el_val_t name); + +/* HTTP server v2 ───────────────────────────────────────────────────────────── + * Same dispatch model as http_serve, but the handler signature is widened: + * + * el_val_t handler(method, path, headers_map, body) + * + * `headers_map` is an ElMap from lowercased header name → header value (both + * Strings). Repeated headers are joined with ", " per RFC 7230. + * + * Response value: the handler may return either + * (a) a plain body string — same auto-content-type / 200-OK behaviour as + * http_serve (3-arg) — or + * (b) a response envelope built with `http_response(status, headers_json, + * body)`. The runtime detects the envelope discriminator + * `"el_http_response":1` at the start of the returned string and + * unpacks status / headers / body before sending. + * + * The 3-arg http_serve(port, handler) remains supported unchanged for + * existing handlers (e.g. products/web/server.el): it dispatches with + * (method, path, body), hardcodes 200 OK, and auto-detects content type. */ +el_val_t http_serve_v2(el_val_t port, el_val_t handler); +el_val_t http_set_handler_v2(el_val_t name); + +/* Build an HTTP response envelope. `headers_json` should be a JSON object + * literal like `{"WWW-Authenticate":"Basic"}` (or "" / "{}" for none). The + * returned string carries the discriminator `{"el_http_response":1,...}` + * which the runtime's send-path detects and unpacks. Detection happens + * uniformly inside http_send_response, so a 3-arg handler may also return + * an envelope. The 3-arg variant remains documented as a fixed 200-OK + * auto-content-type contract for legacy handlers that return plain bodies. */ +el_val_t http_response(el_val_t status, el_val_t headers_json, el_val_t body); + +/* SSE connection fd — set by http_worker_v2 before calling the El handler, + * cleared afterwards. Defined in el_seed.c; called from el_runtime.c. + * The getter is exposed as __http_conn_fd() to El programs. */ +void el_seed_set_http_conn_fd(int fd); + +/* HTTP timeout — every libcurl request honors EL_HTTP_TIMEOUT_MS (default + * 60000ms). Read lazily on first use, so setting the env var any time before + * the first http_* call is sufficient. */ + +/* Streaming variants — write the response body straight to a file via + * libcurl's CURLOPT_WRITEFUNCTION = fwrite. These bypass the el_val_t string + * wrapper entirely, so binary payloads (audio/mpeg, image/png, etc.) survive + * embedded NUL bytes that would truncate a strlen()-based code path. + * + * Both honor EL_HTTP_TIMEOUT_MS, follow redirects, and accept the same + * `headers_map` shape as http_post_with_headers (ElMap of String→String). + * + * Return value: 1 on success (file fully written), 0 on any failure + * (network, file open, partial write). On failure the output file is removed + * so callers cannot mistake a partially-written file for a valid one. */ +el_val_t http_post_to_file(el_val_t url, el_val_t body, el_val_t headers_map, el_val_t output_path); +el_val_t http_get_to_file(el_val_t url, el_val_t headers_map, el_val_t output_path); + +/* ── URL encoding ────────────────────────────────────────────────────────── */ + +el_val_t url_encode(el_val_t s); /* RFC 3986 unreserved set */ +el_val_t url_decode(el_val_t s); /* '+' → space, %XX → byte */ + +/* ── HTML allowlist sanitizer ──────────────────────────────────────────────── + * el_html_sanitize(input_html, allowlist_json) — strict allowlist HTML + * cleaner. State-machine parser; tag/attribute names compared case- + * insensitively against the allowlist; `` / `<… src>` URL schemes + * validated (http, https, mailto, fragment-only, or relative); whole- + * subtree drop for script / style / iframe / object / embed / form; HTML- + * escapes free text outside dropped subtrees. + * + * The allowlist is JSON of the form + * {"p":[],"a":["href","title"],"strong":[],...} + * where each value is the array of attribute names allowed for that tag. */ +el_val_t el_html_sanitize(el_val_t input_html, el_val_t allowlist_json); +el_val_t html_raw(el_val_t s); +el_val_t html_escape(el_val_t s); + +/* ── Filesystem ──────────────────────────────────────────────────────────── */ + +el_val_t fs_read(el_val_t path); +el_val_t fs_write(el_val_t path, el_val_t content); +el_val_t fs_list(el_val_t path); +el_val_t fs_list_json(el_val_t path); +el_val_t fs_exists(el_val_t path); +el_val_t fs_mkdir(el_val_t path); /* mkdir -p, mode 0755 */ + +/* Length-explicit binary write. `length` is an Int (el_val_t holding the + * byte count). The caller knows the length from context — typically because + * `bytes` came from base64_decode (which produces a magic-tagged binary + * buffer with embedded NULs possible) and the caller already tracks the + * decoded length, OR because the bytes came from a fixed-size source + * (sha256_bytes = 32, hmac_sha256_bytes = 32). Bypasses strlen entirely. + * + * Returns 1 on success, 0 on failure (invalid path, can't open, partial + * write, negative length). On partial-write failure, the file is removed + * so callers cannot read back a truncated artefact. */ +el_val_t fs_write_bytes(el_val_t path, el_val_t bytes, el_val_t length); + +/* ── JSON ────────────────────────────────────────────────────────────────── */ + +el_val_t json_get(el_val_t json, el_val_t key); +el_val_t json_parse(el_val_t s); +el_val_t json_stringify(el_val_t v); +el_val_t json_get_string(el_val_t json_str, el_val_t key); +el_val_t json_get_int(el_val_t json_str, el_val_t key); +el_val_t json_get_float(el_val_t json_str, el_val_t key); +el_val_t json_get_bool(el_val_t json_str, el_val_t key); +el_val_t json_get_raw(el_val_t json_str, el_val_t key); +el_val_t json_set(el_val_t json_str, el_val_t key, el_val_t value); +el_val_t json_array_len(el_val_t json_str); +el_val_t json_array_get(el_val_t json_str, el_val_t index); +el_val_t json_array_get_string(el_val_t json_str, el_val_t index); +el_val_t json_escape_string(el_val_t sv); +el_val_t json_build_object(el_val_t kvs); +el_val_t json_build_array(el_val_t items); + +/* ── Time ────────────────────────────────────────────────────────────────── */ + +el_val_t time_now(void); +el_val_t time_now_utc(void); +el_val_t sleep_secs(el_val_t secs); +el_val_t sleep_ms(el_val_t ms); +el_val_t time_format(el_val_t ts, el_val_t fmt); +el_val_t time_to_parts(el_val_t ts); +el_val_t time_from_parts(el_val_t secs, el_val_t ns, el_val_t tz); +el_val_t time_add(el_val_t ts, el_val_t n, el_val_t unit); +el_val_t time_diff(el_val_t ts1, el_val_t ts2, el_val_t unit); +el_val_t now_ns(void); + +/* ── Instant + Duration: first-class temporal types ────────────────────────── + * Both types share the el_val_t (int64) slot. Instants are nanoseconds + * since the Unix epoch; Durations are signed nanoseconds. Type discipline + * is enforced at codegen-time: BinOps on names registered as Instant or + * Duration route through the typed wrappers below; mismatches like + * Instant+Instant become #error at the C compiler. + * + * Postfix literals — `30.seconds`, `1.hour`, `500.millis`, `30.nanos` — are + * recognised by the parser as DurationLit AST nodes and lowered to literal + * int64 nanoseconds at codegen time. The runtime never sees the units. */ + +el_val_t el_now_instant(void); +el_val_t now(void); +el_val_t unix_seconds(el_val_t n); +el_val_t unix_millis(el_val_t n); +el_val_t instant_from_iso8601(el_val_t s); + +el_val_t el_duration_from_nanos(el_val_t ns); +el_val_t duration_seconds(el_val_t n); +el_val_t duration_millis(el_val_t n); +el_val_t duration_nanos(el_val_t n); + +el_val_t el_instant_add_dur(el_val_t inst, el_val_t dur); +el_val_t el_instant_sub_dur(el_val_t inst, el_val_t dur); +el_val_t el_instant_diff(el_val_t a, el_val_t b); +el_val_t el_duration_add(el_val_t a, el_val_t b); +el_val_t el_duration_sub(el_val_t a, el_val_t b); +el_val_t el_duration_scale(el_val_t dur, el_val_t scalar); +el_val_t el_duration_div(el_val_t dur, el_val_t scalar); + +el_val_t el_instant_lt(el_val_t a, el_val_t b); +el_val_t el_instant_le(el_val_t a, el_val_t b); +el_val_t el_instant_gt(el_val_t a, el_val_t b); +el_val_t el_instant_ge(el_val_t a, el_val_t b); +el_val_t el_instant_eq(el_val_t a, el_val_t b); +el_val_t el_instant_ne(el_val_t a, el_val_t b); +el_val_t el_duration_lt(el_val_t a, el_val_t b); +el_val_t el_duration_le(el_val_t a, el_val_t b); +el_val_t el_duration_gt(el_val_t a, el_val_t b); +el_val_t el_duration_ge(el_val_t a, el_val_t b); +el_val_t el_duration_eq(el_val_t a, el_val_t b); +el_val_t el_duration_ne(el_val_t a, el_val_t b); + +el_val_t instant_to_unix_seconds(el_val_t i); +el_val_t instant_to_unix_millis(el_val_t i); +el_val_t instant_to_iso8601(el_val_t i); +el_val_t duration_to_seconds(el_val_t d); +el_val_t duration_to_millis(el_val_t d); +el_val_t duration_to_nanos(el_val_t d); + +el_val_t el_sleep_duration(el_val_t dur); +el_val_t unix_timestamp(void); + +el_val_t ttl_cache_set(el_val_t key, el_val_t value); +el_val_t ttl_cache_get(el_val_t key, el_val_t max_age); +el_val_t ttl_cache_age(el_val_t key); + +/* ── Calendar + CalendarTime + Rhythm + LocalDate/Time/DateTime ───────────── + * Phase 1.5 of the time system. Calendar is pluggable: EarthCalendar (IANA + * zones, Gregorian, DST) is the user-facing default; MarsCalendar, + * CycleCalendar(period), NoCycleCalendar, RelativeCalendar handle non-Earth + * domains. + * + * A Calendar interprets an Instant under a particular cycle convention and + * produces a CalendarTime. CalendarTime carries the underlying Instant and + * a back-pointer to its Calendar; arithmetic and formatting consult the + * Calendar to convert ns since epoch into year/month/day/hour/minute/second + * (or sol/phase, or cycle/phase, depending on kind). + * + * Storage convention: Calendar / CalendarTime / Rhythm / LocalDate / + * LocalDateTime are heap-allocated structs whose pointers are cast into + * el_val_t. A 24-bit magic header at offset 0 lets the runtime identify + * the kind safely. LocalTime is small enough to live in the int64 slot + * directly (nanos since midnight, signed). */ + +/* Zone — opaque IANA zone or fixed offset, used by EarthCalendar. + * `zone_id` is either an IANA name ("America/New_York", "UTC") or a fixed + * offset string ("+05:30", "-08:00"). The runtime resolves it via tzset() + * on first use of the owning EarthCalendar. */ +el_val_t zone(el_val_t id); +el_val_t zone_utc(void); +el_val_t zone_local(void); +el_val_t zone_offset(el_val_t hours, el_val_t minutes); + +/* Calendar constructors. Each returns an el_val_t pointer to a heap- + * allocated, magic-tagged Calendar struct. Calendars are interned by + * (kind, zone_id, period_ns, epoch_ns) so identical constructors return + * the same pointer — equality is reference equality. */ +el_val_t earth_calendar(el_val_t z); +el_val_t earth_calendar_default(void); +el_val_t mars_calendar(void); +el_val_t cycle_calendar(el_val_t period_dur); +el_val_t no_cycle_calendar(void); +el_val_t relative_calendar(el_val_t epoch_inst); + +/* CalendarTime constructors and methods. Returns a heap-allocated struct + * whose pointer fits in el_val_t. */ +el_val_t now_in(el_val_t cal); +el_val_t in_calendar(el_val_t inst, el_val_t cal); +el_val_t cal_format(el_val_t ct, el_val_t pattern); +el_val_t cal_to_instant(el_val_t ct); +el_val_t cal_cycle_phase(el_val_t ct); +el_val_t cal_in(el_val_t ct, el_val_t cal); + +/* LocalDate / LocalTime / LocalDateTime — calendar-agnostic value types. + * LocalTime carries nanoseconds since midnight as a signed int64 directly + * in the el_val_t slot (no allocation). LocalDate / LocalDateTime are + * heap-allocated structs with magic headers. */ +el_val_t local_date(el_val_t y, el_val_t m, el_val_t d); +el_val_t local_time(el_val_t h, el_val_t m, el_val_t s, el_val_t ns); +el_val_t local_datetime(el_val_t date, el_val_t time); +el_val_t zoned(el_val_t date, el_val_t time, el_val_t cal); + +el_val_t local_date_year(el_val_t ld); +el_val_t local_date_month(el_val_t ld); +el_val_t local_date_day(el_val_t ld); +el_val_t local_time_hour(el_val_t lt); +el_val_t local_time_minute(el_val_t lt); +el_val_t local_time_second(el_val_t lt); +el_val_t local_time_nanos(el_val_t lt); + +el_val_t el_local_date_add_dur(el_val_t ld, el_val_t dur); +el_val_t el_local_time_add_dur(el_val_t lt, el_val_t dur); +el_val_t el_local_date_lt(el_val_t a, el_val_t b); +el_val_t el_local_date_eq(el_val_t a, el_val_t b); + +/* Rhythm — pluggable recurrence AST. Returns a heap-allocated struct + * pointer in el_val_t; rhythms are immutable so callers may share them. */ +el_val_t rhythm_cycle_start(void); +el_val_t rhythm_cycle_phase(el_val_t phase); +el_val_t rhythm_duration(el_val_t d); +el_val_t rhythm_session_start(void); +el_val_t rhythm_event(el_val_t name); +el_val_t rhythm_and(el_val_t a, el_val_t b); +el_val_t rhythm_or(el_val_t a, el_val_t b); +el_val_t rhythm_weekday(el_val_t day); +el_val_t rhythm_weekly_at(el_val_t day, el_val_t hour, el_val_t minute); +el_val_t rhythm_next_after(el_val_t r, el_val_t after, el_val_t cal); +el_val_t rhythm_matches(el_val_t r, el_val_t ct); + +/* ── UUID ────────────────────────────────────────────────────────────────── */ + +el_val_t uuid_new(void); +el_val_t uuid_v4(void); + +/* ── Environment ─────────────────────────────────────────────────────────── */ + +el_val_t env(el_val_t key); + +/* ── In-process state K/V ────────────────────────────────────────────────── */ + +el_val_t state_set(el_val_t key, el_val_t value); +el_val_t state_get(el_val_t key); +el_val_t state_del(el_val_t key); +el_val_t state_keys(void); +el_val_t state_has(el_val_t key); +el_val_t state_get_or(el_val_t key, el_val_t default_val); + +/* ── Float formatting ────────────────────────────────────────────────────── */ + +el_val_t float_to_str(el_val_t f); +el_val_t int_to_float(el_val_t n); +el_val_t float_to_int(el_val_t f); +el_val_t format_float(el_val_t f, el_val_t decimals); +el_val_t decimal_round(el_val_t f, el_val_t decimals); +el_val_t str_to_float(el_val_t s); + +/* ── Math (Float-aware) ──────────────────────────────────────────────────── */ + +el_val_t math_sqrt(el_val_t f); +el_val_t math_log(el_val_t f); +el_val_t math_ln(el_val_t f); +el_val_t math_sin(el_val_t f); +el_val_t math_cos(el_val_t f); +el_val_t math_pi(void); + +/* ── String additions ────────────────────────────────────────────────────── */ + +el_val_t str_index_of(el_val_t s, el_val_t sub); +el_val_t str_split(el_val_t s, el_val_t sep); +el_val_t str_char_at(el_val_t s, el_val_t i); +el_val_t str_char_code(el_val_t s, el_val_t i); +el_val_t str_pad_left(el_val_t s, el_val_t width, el_val_t pad); +el_val_t str_pad_right(el_val_t s, el_val_t width, el_val_t pad); +el_val_t str_format(el_val_t fmt, el_val_t data); +el_val_t str_lower(el_val_t s); +el_val_t str_upper(el_val_t s); + +/* ── Text-processing primitives (Phase 1: byte/codepoint, ASCII char classes) + * Phase 2 (filed): Unicode-grapheme awareness, NFC/NFD normalization, regex. + * is_* predicates: empty input returns false; multi-char requires ALL bytes + * to match. ASCII ranges only in Phase 1. */ + +/* Counting */ +el_val_t str_count(el_val_t s, el_val_t sub); /* non-overlapping */ +el_val_t str_count_chars(el_val_t s); /* codepoint count */ +el_val_t str_count_bytes(el_val_t s); /* alias of str_len */ +el_val_t str_count_lines(el_val_t s); +el_val_t str_count_words(el_val_t s); +el_val_t str_count_letters(el_val_t s); /* ASCII [A-Za-z] */ +el_val_t str_count_digits(el_val_t s); /* ASCII [0-9] */ + +/* Find / position */ +el_val_t str_index_of_all(el_val_t s, el_val_t sub); /* [Int] of byte offsets */ +el_val_t str_last_index_of(el_val_t s, el_val_t sub); +el_val_t str_find_chars(el_val_t s, el_val_t any_of); /* first idx of any ch */ + +/* Transform */ +el_val_t str_repeat(el_val_t s, el_val_t n); +el_val_t str_reverse(el_val_t s); /* by codepoint */ +el_val_t str_strip_prefix(el_val_t s, el_val_t prefix); +el_val_t str_strip_suffix(el_val_t s, el_val_t suffix); +el_val_t str_strip_chars(el_val_t s, el_val_t chars); +el_val_t str_lstrip(el_val_t s); +el_val_t str_rstrip(el_val_t s); + +/* Char classification (Bool) */ +el_val_t is_letter(el_val_t s); +el_val_t is_digit(el_val_t s); +el_val_t is_alphanumeric(el_val_t s); +el_val_t is_whitespace(el_val_t s); +el_val_t is_punctuation(el_val_t s); +el_val_t is_uppercase(el_val_t s); +el_val_t is_lowercase(el_val_t s); + +/* Split / join */ +el_val_t str_split_lines(el_val_t s); +el_val_t str_split_chars(el_val_t s); /* alias of native_string_chars */ +el_val_t str_split_n(el_val_t s, el_val_t sep, el_val_t n); +el_val_t str_join(el_val_t list, el_val_t sep); /* alias of list_join */ + +/* ── List additions ──────────────────────────────────────────────────────── */ + +el_val_t list_push(el_val_t list, el_val_t elem); +el_val_t list_push_front(el_val_t list, el_val_t elem); +el_val_t list_join(el_val_t list, el_val_t sep); +el_val_t list_range(el_val_t start, el_val_t end); + +/* ── Bool helpers ────────────────────────────────────────────────────────── */ + +el_val_t bool_to_str(el_val_t b); + +/* ── Numeric parsing ─────────────────────────────────────────────────────── */ + +el_val_t parse_int(el_val_t s, el_val_t default_val); + +/* ── Process ─────────────────────────────────────────────────────────────── */ + +el_val_t exit_program(el_val_t code); +el_val_t getpid_now(void); + +/* Self-terminating memory guard. Reads ELC_MAX_MEM_MB (default 512) and + * exits with code 1 if resident memory exceeds the limit. Call periodically + * during long compilation loops (e.g. after each function is compiled). + * Returns 0 when memory is within bounds. */ +el_val_t el_mem_check(void); + +/* ── CGI identity ───────────────────────────────────────────────────────────── + * Called at the start of main() in CGI programs (those with a `cgi {}` block). + * Records the program's DHARMA identity before any other code executes. */ + +void el_cgi_init(el_val_t name, el_val_t dharma_id, el_val_t principal, + el_val_t network, el_val_t engram); + +/* ── DHARMA network builtins ───────────────────────────────────────────────── + * Available to CGI programs (declared with a `cgi {}` block). + * + * Peers are addressed by `dharma_id` of the form + * "@" e.g. "ntn-genesis@http://localhost:7770" + * If the @ portion is omitted, transport defaults to + * "http://localhost:7770" (the local CGI daemon assumption). + * + * Wire protocol (all peers expose): + * POST /dharma/recv { channel, from, content } → response body + * POST /dharma/event { type, payload, source, timestamp } + * POST /api/activate { query } → list of nodes + * + * Hosting application's responsibility: an El program with a `cgi {}` block + * runs http_serve() with its own request handler; that handler should route + * "/dharma/event" requests by calling el_runtime_dharma_event_arrive() so + * incoming events feed dharma_field() queues. The runtime itself does not + * intercept any /dharma path. */ + +el_val_t dharma_connect(el_val_t cgi_id); +el_val_t dharma_send(el_val_t channel, el_val_t content); +el_val_t dharma_activate(el_val_t query); +void dharma_emit(el_val_t event_type, el_val_t payload); +el_val_t dharma_field(el_val_t event_type); +void dharma_strengthen(el_val_t cgi_id, el_val_t weight); +el_val_t dharma_relationship(el_val_t cgi_id); +el_val_t dharma_peers(void); + +/* Public C API: called by an El program's HTTP handler when a /dharma/event + * request arrives. Pushes onto the per-event-type queue and signals any + * pending dharma_field() blockers. All three arguments must be NUL-terminated + * C strings (or NULL — then treated as empty). */ +void el_runtime_dharma_event_arrive(const char* event_type, + const char* payload, + const char* source); + +/* ── Engram local graph primitives ─────────────────────────────────────────── + * Operate on the CGI's local Engram knowledge graph. + * `engram_activate` queries the local graph only; `dharma_activate` is + * network-wide across all connected CGI graphs. */ + +el_val_t engram_node(el_val_t content, el_val_t node_type, el_val_t salience); +el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags); +/* Layered consciousness — see el_runtime.c for the layered architecture + * design notes (search "Layered consciousness architecture"). The five + * canonical layers (safety / core-identity / domain-knowledge / imprint / + * suit) are seeded automatically; engram_add_layer extends the registry + * with imprint or suit overlays at runtime. Nodes default to layer 1 + * (core-identity) when created via engram_node / engram_node_full. */ +el_val_t engram_node_layered(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t certainty, el_val_t confidence, + el_val_t status, el_val_t tags, el_val_t layer_id); +el_val_t engram_add_layer(el_val_t name, el_val_t priority, el_val_t suppressible, + el_val_t transparent, el_val_t injectable); +el_val_t engram_remove_layer(el_val_t layer_id); +el_val_t engram_list_layers(void); +el_val_t engram_get_node(el_val_t id); +void engram_strengthen(el_val_t node_id); +void engram_forget(el_val_t node_id); +el_val_t engram_node_count(void); +el_val_t engram_search(el_val_t query, el_val_t limit); +el_val_t engram_scan_nodes(el_val_t limit, el_val_t offset); +void engram_connect(el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t relation); +el_val_t engram_edge_between(el_val_t from_id, el_val_t to_id); +el_val_t engram_neighbors(el_val_t node_id); +el_val_t engram_neighbors_filtered(el_val_t node_id, el_val_t max_depth, el_val_t direction); +el_val_t engram_edge_count(void); +/* Three-pass activation: background fan-out → working-memory promotion → + * Layer 0 override. See "Three-pass activation" in el_runtime.c. */ +el_val_t engram_activate(el_val_t query, el_val_t depth); +el_val_t engram_save(el_val_t path); +el_val_t engram_load(el_val_t path); + +/* JSON-string accessors — return pre-serialized JSON so HTTP handlers + * can pass results straight through without round-tripping ElList/ElMap + * through json_stringify. */ +el_val_t engram_get_node_json(el_val_t id); +el_val_t engram_search_json(el_val_t query, el_val_t limit); +el_val_t engram_scan_nodes_json(el_val_t limit, el_val_t offset); +el_val_t engram_scan_nodes_by_type_json(el_val_t node_type, el_val_t limit, el_val_t offset); +el_val_t engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction); +el_val_t engram_activate_json(el_val_t query, el_val_t depth); +el_val_t engram_stats_json(void); +el_val_t engram_list_layers_json(void); +/* engram_compile_layered_json — produce a prompt-ready text block split + * into "[LAYER 0 — STRUCTURAL]" (non-suppressible layers, sacred fire) + * and "[ENGRAM CONTEXT]" (standard suppressible layers). Returns "" if + * no nodes promoted to working memory. */ +el_val_t engram_compile_layered_json(el_val_t intent, el_val_t depth); + +/* ── LLM (Anthropic API client) ───────────────────────────────────────────── + * All functions call https://api.anthropic.com/v1/messages with the API key + * from env ANTHROPIC_API_KEY. Default model when empty: claude-sonnet-4-5. */ + +el_val_t llm_call(el_val_t model, el_val_t prompt); +el_val_t llm_call_system(el_val_t model, el_val_t system_prompt, el_val_t user_prompt); +el_val_t llm_call_agentic(el_val_t model, el_val_t system, el_val_t user, el_val_t tools); +el_val_t llm_vision(el_val_t model, el_val_t system, el_val_t prompt, el_val_t image_url_or_b64); +el_val_t llm_models(void); + +/* Register a tool handler by name. The handler is looked up via dlsym + * (mirroring http_set_handler), so any El `fn (input)` compiles to + * a global C symbol that this function can locate at runtime. + * Handler signature: `el_val_t handler(el_val_t input_json)` — receives + * the tool input as a JSON-string el_val_t and returns a JSON-string + * el_val_t result. Used by llm_call_agentic. */ +void llm_register_tool(el_val_t name, el_val_t handler_fn_name); + +/* ── args() ───────────────────────────────────────────────────────────────── + * Provides access to command-line arguments passed to the program. + * Populated by el_runtime_init_args() before main() runs. */ + +el_val_t args(void); +void el_runtime_init_args(int argc, char** argv); + +/* ── Crypto primitives ───────────────────────────────────────────────────── + * SHA-256, HMAC-SHA-256, and base64 (standard + URL-safe). + * Self-contained — no OpenSSL/libcrypto dependency. The implementations are + * adapted from public-domain reference code (Brad Conte / RFC 4648). + * + * Bytes-returning variants (sha256_bytes, hmac_sha256_bytes) return a string + * value whose contents are raw binary; callers usually feed these into + * base64_encode. Note that el_val_t strings are NUL-terminated by convention, + * so the binary payload may contain embedded NULs — pass it directly into + * base64_encode (which uses an explicit length) rather than treating it as + * a printable C string. + * + * The "base64" variants emit/accept RFC 4648 standard alphabet with padding. + * The "base64url" variants use URL-safe alphabet (`-`/`_`) with no padding, + * as used in JWTs. */ + +el_val_t sha256_hex(el_val_t input); +el_val_t sha256_bytes(el_val_t input); +el_val_t hmac_sha256_hex(el_val_t key, el_val_t message); +el_val_t hmac_sha256_bytes(el_val_t key, el_val_t message); +el_val_t base64_encode(el_val_t input); +el_val_t base64_decode(el_val_t input); +el_val_t base64url_encode(el_val_t input); +el_val_t base64url_decode(el_val_t input); + +/* Length-aware variants (internal — exposed for the rare caller that already + * has a known-length binary buffer and doesn't want to round-trip through + * a NUL-terminated el_val_t string). Sha256_bytes and hmac_sha256_bytes feed + * these implicitly. */ +el_val_t el_sha256_bytes_n(const unsigned char* data, size_t len); +el_val_t el_base64_encode_n(const unsigned char* data, size_t len, int url_safe); + +/* ── Post-quantum primitives (liboqs-backed) ──────────────────────────────── + * All inputs/outputs hex-encoded. Algorithm choices: + * Signature: CRYSTALS-Dilithium-3 (NIST level 3, balanced) + * KEM: CRYSTALS-Kyber-768 (NIST level 3) + * Hash: SHA3-256 (Keccak) (PQ-aware protocols favour SHA3 over SHA2) + * + * If liboqs is not linked (detected via __has_include() at compile + * time), the pq_* entry points return a JSON-shaped error string so callers + * fail loudly rather than silently fall back to classical schemes: + * {"error":"liboqs not linked, post-quantum primitives unavailable"} + * + * The hybrid handshake pairs X25519 with Kyber-768 per NIST PQ guidance and + * CNSA 2.0. Combined shared secret is HKDF-SHA256(x25519_ss || kyber_ss). + * Even if Kyber falls, X25519 holds; if X25519 falls under quantum attack, + * Kyber holds. SHA3-256 also remains usable independent of liboqs (the + * Keccak permutation is PQ-OK as a primitive). */ + +el_val_t pq_keygen_signature(void); +el_val_t pq_sign(el_val_t secret_key_hex, el_val_t message); +el_val_t pq_verify(el_val_t public_key_hex, el_val_t message, el_val_t signature_hex); + +el_val_t pq_kem_keygen(void); +el_val_t pq_kem_encaps(el_val_t public_key_hex); +el_val_t pq_kem_decaps(el_val_t secret_key_hex, el_val_t ciphertext_hex); + +el_val_t pq_hybrid_keygen(void); +el_val_t pq_hybrid_handshake(el_val_t remote_pub_combined); + +el_val_t sha3_256_hex(el_val_t input); + +/* ── AEAD: AES-256-GCM (libcrypto-backed) ─────────────────────────────────── + * Symmetric authenticated encryption used to wrap envelopes after a KEM + * handshake. Caller MUST supply a 32-byte key (64 hex chars) — typically the + * Kyber-768 / hybrid shared_secret, optionally normalized via SHA3-256. + * + * aead_encrypt returns a JSON map {"nonce":"...","ciphertext":"..."} where + * ciphertext is the AES-256-GCM output with the 16-byte auth tag appended. + * Nonce is a fresh 12-byte CSPRNG draw — callers never pick the nonce, which + * structurally rules out the GCM nonce-reuse footgun. + * + * aead_decrypt returns the plaintext String, or "" on any failure (including + * auth-tag mismatch). Callers MUST check for "" before trusting the result. */ +el_val_t aead_encrypt(el_val_t key_hex, el_val_t plaintext); +el_val_t aead_decrypt(el_val_t key_hex, el_val_t nonce_hex, el_val_t ciphertext_hex); + +/* ── Native VM builtin aliases (for compiled El source) ───────────────────── + * These match the El VM's native_* builtins so that El source compiled + * to C can call the same names without modification. */ + +el_val_t native_list_get(el_val_t list, el_val_t index); +el_val_t native_list_len(el_val_t list); +el_val_t native_list_append(el_val_t list, el_val_t elem); +el_val_t native_list_empty(void); +el_val_t native_list_clone(el_val_t list); +el_val_t native_string_chars(el_val_t s); +el_val_t native_int_to_str(el_val_t n); + +/* ── Method-call shorthand aliases ────────────────────────────────────────── + * The El method-call convention `obj.method(args)` compiles to + * `method(obj, args)`. These aliases expose the runtime functions under + * the short names that result from method calls in El source. + * + * Example: `myList.append(x)` → `append(myList, x)` (calls this alias) + * `myList.len()` → `len(myList)` (calls this alias) */ + +el_val_t append(el_val_t list, el_val_t elem); /* el_list_append */ +el_val_t len(el_val_t list); /* el_list_len */ +el_val_t get(el_val_t list, el_val_t index); /* el_list_get */ +el_val_t map_get(el_val_t map, el_val_t key); /* el_map_get */ +el_val_t map_set(el_val_t map, el_val_t key, el_val_t value); /* el_map_set */ + +/* ── OTLP/HTTP Observability ─────────────────────────────────────────────── */ +/* See bottom of el_runtime.c for the implementation. + * Configured by env vars OTLP_ENDPOINT, OTEL_SERVICE_NAME, OTEL_SERVICE_VERSION. + * No-op when OTLP_ENDPOINT is unset. Drop-on-failure semantics. */ +/* ── Subprocess execution ────────────────────────────────────────────────── */ +el_val_t exec_command(el_val_t cmd); /* run shell command, return exit code */ +el_val_t exec_capture(el_val_t cmd); /* run shell command, capture stdout */ +el_val_t exec(el_val_t cmd); /* exec(cmd) → stdout String (30s timeout) */ +el_val_t exec_bg(el_val_t cmd); /* exec_bg(cmd) → PID String (non-blocking) */ + +/* ── Stdout redirection (used by compiler JS pipeline) ───────────────────── */ +el_val_t stdout_to_file(el_val_t path); /* redirect process stdout to a file */ +el_val_t stdout_restore(void); /* restore process stdout to terminal */ + +el_val_t emit_log(el_val_t level, el_val_t msg, el_val_t fields_json); +el_val_t emit_metric(el_val_t name, el_val_t value, el_val_t tags_json); +el_val_t trace_span_start(el_val_t name); +el_val_t trace_span_end(el_val_t span_handle); +el_val_t emit_event(el_val_t name, el_val_t duration_ms); + +el_val_t __thread_create(el_val_t fn_name_v, el_val_t arg_v); +el_val_t __thread_join(el_val_t tid_v); + +/* ── __ prefixed aliases (self-hosting compiler ABI) ───────────────────────── + * The El self-hosting compiler emits calls to __-prefixed names. These are + * forwarding wrappers around the existing el_runtime functions above. */ + +/* I/O */ +el_val_t __println(el_val_t s); +el_val_t __print(el_val_t s); +el_val_t __readline(void); + +/* String */ +el_val_t __int_to_str(el_val_t n); +el_val_t __str_to_int(el_val_t s); +el_val_t __float_to_str(el_val_t f); +el_val_t __str_to_float(el_val_t s); +el_val_t __str_len(el_val_t s); +el_val_t __str_char_at(el_val_t s, el_val_t i); +el_val_t __str_cmp(el_val_t a, el_val_t b); +el_val_t __str_ncmp(el_val_t a, el_val_t b, el_val_t n); +el_val_t __str_concat_raw(el_val_t a, el_val_t b); +el_val_t __str_slice_raw(el_val_t s, el_val_t start, el_val_t end); +el_val_t __str_alloc(el_val_t n); +el_val_t __str_set_char(el_val_t s, el_val_t i, el_val_t c); + +/* URL encoding */ +el_val_t __url_encode(el_val_t s); +el_val_t __url_decode(el_val_t s); + +/* Environment */ +el_val_t __env_get(el_val_t key); + +/* Subprocess */ +el_val_t __exec(el_val_t cmd); +el_val_t __exec_bg(el_val_t cmd); + +/* Process */ +el_val_t __exit_program(el_val_t code); + +/* Filesystem */ +el_val_t __fs_exists(el_val_t path); +el_val_t __fs_mkdir(el_val_t path); +el_val_t __fs_read(el_val_t path); +el_val_t __fs_write(el_val_t path, el_val_t content); +el_val_t __fs_write_bytes(el_val_t path, el_val_t bytes, el_val_t n); +el_val_t __fs_list_raw(el_val_t path); + +/* HTTP server */ +el_val_t __http_response(el_val_t status, el_val_t headers_json, el_val_t body); +el_val_t __http_serve(el_val_t port, el_val_t handler); +el_val_t __http_serve_v2(el_val_t port, el_val_t handler); + +/* HTTP conn fd / SSE (weak; overridden by el_seed.c when linked together) */ +el_val_t __http_conn_fd(void); +el_val_t __http_sse_open(el_val_t conn_id); +el_val_t __http_sse_send(el_val_t conn_id, el_val_t data); +el_val_t __http_sse_close(el_val_t conn_id); + +/* HTTP client (requires HAVE_CURL; stubs provided for no-curl builds) */ +el_val_t __http_do(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_map, el_val_t timeout_ms); +el_val_t __http_do_map(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t timeout_ms); +el_val_t __http_do_map_to_file(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t output_path); + +/* JSON */ +el_val_t __json_array_get(el_val_t json, el_val_t index); +el_val_t __json_array_get_string(el_val_t json, el_val_t index); +el_val_t __json_array_len(el_val_t json); +el_val_t __json_get(el_val_t json, el_val_t key); +el_val_t __json_get_raw(el_val_t json, el_val_t key); +el_val_t __json_set(el_val_t json, el_val_t key, el_val_t value); +el_val_t __json_parse_map(el_val_t json_str); +el_val_t __json_stringify_val(el_val_t val); + +/* Hashing */ +el_val_t __sha256_hex(el_val_t s); + +/* State K/V */ +el_val_t __state_del(el_val_t key); +el_val_t __state_get(el_val_t key); +el_val_t __state_keys(void); +el_val_t __state_set(el_val_t key, el_val_t val); + +/* UUID */ +el_val_t __uuid_v4(void); + +/* Args */ +el_val_t __args_json(void); + +#ifdef __cplusplus +} +#endif diff --git a/ui/examples/native-hello-ios/NativeHello/el_seed.c b/ui/examples/native-hello-ios/NativeHello/el_seed.c new file mode 100644 index 0000000..fc9fbba --- /dev/null +++ b/ui/examples/native-hello-ios/NativeHello/el_seed.c @@ -0,0 +1,1942 @@ +/* + * el_seed.c — El language seed runtime: minimal C OS boundary + * + * This file exposes all OS-boundary primitives that El programs need, under + * the __ prefix convention. It is self-contained: all allocators, arena + * management, and el_request_start / el_request_end are defined here. + * + * Threading: __thread_create / __thread_join use dlsym(RTLD_DEFAULT) to look + * up El function symbols at runtime. This is the foundation of El's parallelism. + * + * Link: cc -std=c11 -I el-compiler/runtime -lcurl -lpthread \ + * -o .c el_seed.c + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "el_seed.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* ── Private allocator ───────────────────────────────────────────────────── */ +/* + * el_seed.c carries its own arena for per-request allocation tracking. + * The arena is reset at el_request_start / el_request_end, which are defined + * below and delegate to seed_request_start / seed_request_end. + */ + +#define SEED_ARENA_INITIAL 512 + +typedef struct { + char** ptrs; + size_t count; + size_t cap; +} SeedArena; + +static _Thread_local SeedArena _seed_arena = {NULL, 0, 0}; +static _Thread_local int _seed_arena_on = 0; + +static void seed_arena_track(char* p) { + if (!_seed_arena_on || !p) return; + if (_seed_arena.count >= _seed_arena.cap) { + size_t nc = _seed_arena.cap == 0 ? SEED_ARENA_INITIAL : _seed_arena.cap * 2; + char** g = realloc(_seed_arena.ptrs, nc * sizeof(char*)); + if (!g) return; + _seed_arena.ptrs = g; + _seed_arena.cap = nc; + } + _seed_arena.ptrs[_seed_arena.count++] = p; +} + +static void seed_request_start(void) { + _seed_arena.count = 0; + _seed_arena_on = 1; +} + +static void seed_request_end(void) { + _seed_arena_on = 0; + for (size_t i = 0; i < _seed_arena.count; i++) free(_seed_arena.ptrs[i]); + _seed_arena.count = 0; +} + +/* el_request_start / el_request_end — formerly defined in el_runtime.c. + * Now self-contained in el_seed.c, delegating to the seed arena. */ +void el_request_start(void) { seed_request_start(); } +void el_request_end(void) { seed_request_end(); } + +/* Persistent alloc — bypasses arena (state, engram internals). */ +static char* seed_strdup_persist(const char* s) { + if (!s) return strdup(""); + return strdup(s); +} + +static char* seed_strdup(const char* s) { + char* p = strdup(s ? s : ""); + seed_arena_track(p); + return p; +} + +static char* seed_strbuf(size_t n) { + char* p = malloc(n + 1); + if (!p) { fputs("el_seed: out of memory\n", stderr); exit(1); } + p[0] = '\0'; + seed_arena_track(p); + return p; +} + +static el_val_t seed_wrap_str(char* s) { return EL_STR(s); } + +/* ── String primitives ───────────────────────────────────────────────────── */ + +el_val_t __str_len(el_val_t s) { + const char* p = EL_CSTR(s); + if (!p) return 0; + return (el_val_t)strlen(p); +} + +el_val_t __str_char_at(el_val_t s, el_val_t i) { + const char* p = EL_CSTR(s); + if (!p) return 0; + int64_t len = (int64_t)strlen(p); + int64_t idx = (int64_t)i; + if (idx < 0 || idx >= len) return 0; + return (el_val_t)(unsigned char)p[idx]; +} + +el_val_t __str_alloc(el_val_t n) { + int64_t sz = (int64_t)n; + if (sz < 0) sz = 0; + char* buf = seed_strbuf((size_t)sz); + memset(buf, 0, (size_t)sz + 1); + return seed_wrap_str(buf); +} + +el_val_t __str_set_char(el_val_t s, el_val_t i, el_val_t c) { + char* p = (char*)(uintptr_t)s; + if (!p) return s; + int64_t len = (int64_t)strlen(p); + int64_t idx = (int64_t)i; + if (idx < 0 || idx >= len) return s; + p[idx] = (char)(unsigned char)(int64_t)c; + return s; +} + +el_val_t __str_cmp(el_val_t a, el_val_t b) { + const char* sa = EL_CSTR(a); + const char* sb = EL_CSTR(b); + if (!sa) sa = ""; + if (!sb) sb = ""; + return (el_val_t)strcmp(sa, sb); +} + +el_val_t __str_ncmp(el_val_t a, el_val_t b, el_val_t n) { + const char* sa = EL_CSTR(a); + const char* sb = EL_CSTR(b); + if (!sa) sa = ""; + if (!sb) sb = ""; + return (el_val_t)strncmp(sa, sb, (size_t)(int64_t)n); +} + +el_val_t __str_concat_raw(el_val_t a, el_val_t b) { + const char* sa = EL_CSTR(a); + const char* sb = EL_CSTR(b); + if (!sa) sa = ""; + if (!sb) sb = ""; + size_t la = strlen(sa), lb = strlen(sb); + char* out = seed_strbuf(la + lb); + memcpy(out, sa, la); + memcpy(out + la, sb, lb); + out[la + lb] = '\0'; + return seed_wrap_str(out); +} + +el_val_t __str_slice_raw(el_val_t s, el_val_t start, el_val_t end) { + const char* p = EL_CSTR(s); + if (!p) return seed_wrap_str(seed_strdup("")); + int64_t len = (int64_t)strlen(p); + int64_t st = (int64_t)start; + int64_t en = (int64_t)end; + if (st < 0) st = 0; + if (en > len) en = len; + if (st >= en) return seed_wrap_str(seed_strdup("")); + int64_t sz = en - st; + char* out = seed_strbuf((size_t)sz); + memcpy(out, p + st, (size_t)sz); + out[sz] = '\0'; + return seed_wrap_str(out); +} + +el_val_t __int_to_str(el_val_t n) { + char buf[32]; + snprintf(buf, sizeof(buf), "%lld", (long long)(int64_t)n); + return seed_wrap_str(seed_strdup(buf)); +} + +el_val_t __str_to_int(el_val_t s) { + const char* p = EL_CSTR(s); + if (!p) return 0; + return (el_val_t)atoll(p); +} + +el_val_t __float_to_str(el_val_t f) { + char buf[64]; + snprintf(buf, sizeof(buf), "%g", el_to_float(f)); + return seed_wrap_str(seed_strdup(buf)); +} + +el_val_t __str_to_float(el_val_t s) { + const char* p = EL_CSTR(s); + if (!p) return el_from_float(0.0); + return el_from_float(strtod(p, NULL)); +} + +/* ── I/O ─────────────────────────────────────────────────────────────────── */ + +void __println(el_val_t s) { + const char* p = EL_CSTR(s); + puts(p ? p : ""); +} + +void __print(el_val_t s) { + const char* p = EL_CSTR(s); + if (p) fputs(p, stdout); +} + +el_val_t __readline(void) { + char buf[4096]; + if (!fgets(buf, sizeof(buf), stdin)) return seed_wrap_str(seed_strdup("")); + size_t len = strlen(buf); + if (len > 0 && buf[len - 1] == '\n') buf[len - 1] = '\0'; + return seed_wrap_str(seed_strdup(buf)); +} + +/* ── Filesystem ──────────────────────────────────────────────────────────── */ + +el_val_t __fs_read(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p) return seed_wrap_str(seed_strdup("")); + FILE* f = fopen(p, "rb"); + if (!f) return seed_wrap_str(seed_strdup("")); + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + if (sz < 0) { fclose(f); return seed_wrap_str(seed_strdup("")); } + char* buf = seed_strbuf((size_t)sz); + size_t got = fread(buf, 1, (size_t)sz, f); + buf[got] = '\0'; + fclose(f); + return seed_wrap_str(buf); +} + +el_val_t __fs_write(el_val_t path, el_val_t content) { + const char* p = EL_CSTR(path); + const char* c = EL_CSTR(content); + if (!p || !c) return 0; + FILE* f = fopen(p, "wb"); + if (!f) return 0; + size_t n = strlen(c); + size_t w = fwrite(c, 1, n, f); + fclose(f); + return w == n ? 1 : 0; +} + +el_val_t __fs_exists(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p || !*p) return 0; + struct stat st; + return (el_val_t)(stat(p, &st) == 0 ? 1 : 0); +} + +el_val_t __fs_list_raw(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p) return seed_wrap_str(seed_strdup("")); + DIR* d = opendir(p); + if (!d) return seed_wrap_str(seed_strdup("")); + /* Build newline-separated list of filenames. */ + size_t cap = 4096, len = 0; + char* buf = malloc(cap); + if (!buf) { closedir(d); return seed_wrap_str(seed_strdup("")); } + buf[0] = '\0'; + struct dirent* e; + while ((e = readdir(d)) != NULL) { + if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) continue; + size_t nlen = strlen(e->d_name); + while (len + nlen + 2 >= cap) { + cap *= 2; + char* g = realloc(buf, cap); + if (!g) { free(buf); closedir(d); return seed_wrap_str(seed_strdup("")); } + buf = g; + } + if (len > 0) buf[len++] = '\n'; + memcpy(buf + len, e->d_name, nlen); + len += nlen; + buf[len] = '\0'; + } + closedir(d); + seed_arena_track(buf); + return seed_wrap_str(buf); +} + +el_val_t __fs_mkdir(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p || !*p) return 0; + size_t n = strlen(p); + char* buf = malloc(n + 1); + if (!buf) return 0; + memcpy(buf, p, n + 1); + for (size_t i = 1; i <= n; i++) { + if (buf[i] == '/' || buf[i] == '\0') { + char saved = buf[i]; + buf[i] = '\0'; + if (buf[0] != '\0') { + if (mkdir(buf, 0755) != 0 && errno != EEXIST) { + struct stat st; + if (stat(buf, &st) != 0 || !S_ISDIR(st.st_mode)) { + free(buf); return 0; + } + } + } + buf[i] = saved; + } + } + free(buf); + return 1; +} + +el_val_t __fs_write_bytes(el_val_t path, el_val_t bytes, el_val_t n) { + const char* p = EL_CSTR(path); + const char* b = EL_CSTR(bytes); + int64_t sz = (int64_t)n; + if (!p || !b || sz < 0) return 0; + FILE* f = fopen(p, "wb"); + if (!f) return 0; + size_t written = (sz > 0) ? fwrite(b, 1, (size_t)sz, f) : 0; + int ok1 = (fflush(f) == 0); + int ok2 = (fclose(f) == 0); + if (!ok1 || !ok2 || written != (size_t)sz) { remove(p); return 0; } + return 1; +} + +/* ── HTTP client ─────────────────────────────────────────────────────────── */ + +typedef struct { + char* data; + size_t len; + size_t cap; +} SeedHttpBuf; + +static void seed_httpbuf_init(SeedHttpBuf* b) { + b->cap = 1024; b->len = 0; + b->data = malloc(b->cap); + if (!b->data) { fputs("el_seed: out of memory\n", stderr); exit(1); } + b->data[0] = '\0'; +} + +static void seed_httpbuf_append(SeedHttpBuf* b, const void* src, size_t n) { + while (b->len + n + 1 > b->cap) b->cap *= 2; + b->data = realloc(b->data, b->cap); + if (!b->data) { fputs("el_seed: out of memory\n", stderr); exit(1); } + memcpy(b->data + b->len, src, n); + b->len += n; + b->data[b->len] = '\0'; +} + +static size_t seed_http_write_cb(char* ptr, size_t size, size_t nmemb, void* ud) { + size_t n = size * nmemb; + seed_httpbuf_append((SeedHttpBuf*)ud, ptr, n); + return n; +} + +/* Build a curl_slist from a JSON object string of header name:value pairs. */ +static struct curl_slist* seed_headers_from_json(const char* hj) { + struct curl_slist* h = NULL; + if (!hj || !*hj) return NULL; + /* Walk key:value pairs at depth 1. Simple parser — same logic as json_find_key + * in el_runtime.c but adapted for building curl headers. */ + const char* p = hj; + while (*p && *p != '{') p++; + if (*p == '{') p++; + while (*p) { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p == '}' || *p == '\0') break; + if (*p != '"') break; + /* Parse key */ + p++; + const char* ks = p; + while (*p && *p != '"') { if (*p == '\\') p++; p++; } + size_t klen = (size_t)(p - ks); + if (*p == '"') p++; + /* Skip : */ + while (*p == ' ' || *p == ':') p++; + /* Parse value */ + if (*p != '"') break; + p++; + const char* vs = p; + while (*p && *p != '"') { if (*p == '\\') p++; p++; } + size_t vlen = (size_t)(p - vs); + if (*p == '"') p++; + /* Build "Key: Value" header line */ + size_t line_len = klen + 2 + vlen + 1; + char* line = malloc(line_len); + if (line) { + memcpy(line, ks, klen); + memcpy(line + klen, ": ", 2); + memcpy(line + klen + 2, vs, vlen); + line[klen + 2 + vlen] = '\0'; + h = curl_slist_append(h, line); + free(line); + } + } + return h; +} + +static el_val_t seed_http_error_json(const char* msg) { + if (!msg) msg = "unknown error"; + size_t n = strlen(msg) * 6 + 20; + char* buf = seed_strbuf(n); + /* Simple escape: replace " with \" */ + char* d = buf; + *d++ = '{'; *d++ = '"'; *d++ = 'e'; *d++ = 'r'; *d++ = 'r'; + *d++ = 'o'; *d++ = 'r'; *d++ = '"'; *d++ = ':'; *d++ = '"'; + for (const char* s = msg; *s; s++) { + if (*s == '"' || *s == '\\') *d++ = '\\'; + *d++ = *s; + } + *d++ = '"'; *d++ = '}'; *d = '\0'; + return seed_wrap_str(buf); +} + +el_val_t __http_do(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t timeout_ms) { + const char* m = EL_CSTR(method); + const char* u = EL_CSTR(url); + const char* b = EL_CSTR(body); + const char* hj = EL_CSTR(headers_json); + int64_t tms = (int64_t)timeout_ms; + if (tms <= 0) tms = 60000; + + if (!u || !*u) return seed_http_error_json("empty url"); + + CURL* c = curl_easy_init(); + if (!c) return seed_http_error_json("curl_easy_init failed"); + + SeedHttpBuf rb; seed_httpbuf_init(&rb); + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + + curl_easy_setopt(c, CURLOPT_URL, u); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, seed_http_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, &rb); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, (long)tms); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-seed/1.0"); + + struct curl_slist* hdrs = seed_headers_from_json(hj); + if (hdrs) curl_easy_setopt(c, CURLOPT_HTTPHEADER, hdrs); + + if (m && strcmp(m, "POST") == 0) { + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, b ? b : ""); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(b ? strlen(b) : 0)); + } else if (m && strcmp(m, "PUT") == 0) { + curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, "PUT"); + if (b) { + curl_easy_setopt(c, CURLOPT_POSTFIELDS, b); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)strlen(b)); + } + } else if (m && strcmp(m, "DELETE") == 0) { + curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, "DELETE"); + } else if (m && strcmp(m, "PATCH") == 0) { + curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, "PATCH"); + if (b) { + curl_easy_setopt(c, CURLOPT_POSTFIELDS, b); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)strlen(b)); + } + } + /* GET is the default */ + + CURLcode rc = curl_easy_perform(c); + if (hdrs) curl_slist_free_all(hdrs); + curl_easy_cleanup(c); + + if (rc != CURLE_OK) { + free(rb.data); + const char* em = errbuf[0] ? errbuf : curl_easy_strerror(rc); + return seed_http_error_json(em); + } + + seed_arena_track(rb.data); + return seed_wrap_str(rb.data); +} + +static size_t seed_http_file_write_cb(char* ptr, size_t size, size_t nmemb, void* ud) { + return fwrite(ptr, size, nmemb, (FILE*)ud); +} + +el_val_t __http_do_to_file(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t out_path) { + const char* m = EL_CSTR(method); + const char* u = EL_CSTR(url); + const char* b = EL_CSTR(body); + const char* hj = EL_CSTR(headers_json); + const char* op = EL_CSTR(out_path); + + if (!u || !*u || !op || !*op) return 0; + FILE* f = fopen(op, "wb"); + if (!f) return 0; + + CURL* c = curl_easy_init(); + if (!c) { fclose(f); remove(op); return 0; } + + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + curl_easy_setopt(c, CURLOPT_URL, u); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, seed_http_file_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, f); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, 60000L); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-seed/1.0"); + + struct curl_slist* hdrs = seed_headers_from_json(hj); + if (hdrs) curl_easy_setopt(c, CURLOPT_HTTPHEADER, hdrs); + + if (m && strcmp(m, "POST") == 0) { + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, b ? b : ""); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(b ? strlen(b) : 0)); + } + + CURLcode rc = curl_easy_perform(c); + if (hdrs) curl_slist_free_all(hdrs); + curl_easy_cleanup(c); + + int ok1 = (fflush(f) == 0); + int ok2 = (fclose(f) == 0); + + if (rc != CURLE_OK || !ok1 || !ok2) { remove(op); return 0; } + return 1; +} + +/* ── HTTP server ─────────────────────────────────────────────────────────── */ +/* Delegate to el_runtime.c's http_serve / http_serve_v2 via the existing + * http_set_handler mechanism. */ + +/* Forward declarations for el_runtime.c functions called from el_seed.c. + * A full #include "el_runtime.h" causes redefinition conflicts (el_seed.h + * already defines el_to_float, el_from_float, and several __ wrappers). + * Declare only the symbols actually used here. */ + +/* HTTP server */ +el_val_t http_serve(el_val_t port, el_val_t handler); +el_val_t http_serve_v2(el_val_t port, el_val_t handler); +el_val_t http_response(el_val_t status, el_val_t headers_json, el_val_t body); + +/* JSON */ +el_val_t json_get(el_val_t json, el_val_t key); +el_val_t json_get_raw(el_val_t json_str, el_val_t key); +el_val_t json_parse(el_val_t s); +el_val_t json_stringify(el_val_t v); +el_val_t json_array_len(el_val_t json_str); +el_val_t json_array_get(el_val_t json_str, el_val_t index); +el_val_t json_array_get_string(el_val_t json_str, el_val_t index); +el_val_t json_get_string(el_val_t json_str, el_val_t key); +el_val_t json_get_int(el_val_t json_str, el_val_t key); +el_val_t json_get_float(el_val_t json_str, el_val_t key); +el_val_t json_get_bool(el_val_t json_str, el_val_t key); +el_val_t json_set(el_val_t json_str, el_val_t key, el_val_t value); + +/* URL / HTML */ +el_val_t url_encode(el_val_t s); +el_val_t url_decode(el_val_t s); +el_val_t el_html_sanitize(el_val_t input_html, el_val_t allowlist_json); + +/* State K/V */ +el_val_t state_set(el_val_t key, el_val_t value); +el_val_t state_get(el_val_t key); +el_val_t state_del(el_val_t key); +el_val_t state_keys(void); +el_val_t state_get_or(el_val_t key, el_val_t default_val); + +/* Engram graph */ +el_val_t engram_node(el_val_t content, el_val_t node_type, el_val_t salience); +el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags_json); +el_val_t engram_node_layered(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags_json, el_val_t layer_id); +el_val_t engram_add_layer(el_val_t name, el_val_t priority, el_val_t suppressible, + el_val_t transparent, el_val_t injectable); +el_val_t engram_remove_layer(el_val_t layer_id); +el_val_t engram_list_layers(void); +el_val_t engram_get_node(el_val_t id); +void engram_strengthen(el_val_t node_id); +void engram_forget(el_val_t node_id); +el_val_t engram_node_count(void); +el_val_t engram_search(el_val_t query, el_val_t limit); +el_val_t engram_scan_nodes(el_val_t limit, el_val_t offset); +void engram_connect(el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t relation); +el_val_t engram_edge_between(el_val_t from_id, el_val_t to_id); +el_val_t engram_neighbors(el_val_t node_id); +el_val_t engram_neighbors_filtered(el_val_t node_id, el_val_t max_depth, el_val_t direction); +el_val_t engram_edge_count(void); +el_val_t engram_activate(el_val_t query, el_val_t depth); +el_val_t engram_save(el_val_t path); +el_val_t engram_load(el_val_t path); +el_val_t engram_get_node_json(el_val_t id); +el_val_t engram_search_json(el_val_t query, el_val_t limit); +el_val_t engram_scan_nodes_json(el_val_t limit, el_val_t offset); +el_val_t engram_scan_nodes_by_type_json(el_val_t node_type, el_val_t limit, el_val_t offset); +el_val_t engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction); +el_val_t engram_activate_json(el_val_t query, el_val_t depth); +el_val_t engram_stats_json(void); +el_val_t engram_list_layers_json(void); +el_val_t engram_compile_layered_json(el_val_t intent, el_val_t depth); + +void __http_serve(el_val_t port, el_val_t handler_name) { + http_serve(port, handler_name); +} + +void __http_serve_v2(el_val_t port, el_val_t handler_name) { + http_serve_v2(port, handler_name); +} + +el_val_t __http_response(el_val_t status, el_val_t headers_json, el_val_t body) { + return http_response(status, headers_json, body); +} + +/* ── HTTP SSE — Server-Sent Events streaming ─────────────────────────────── */ +/* + * Thread-local file descriptor stashed by http_worker_v2 before calling the + * El handler. El SSE builtins read this to get the raw socket fd. + * + * Lifecycle: + * http_worker_v2 sets _tl_http_conn_fd = fd (via el_seed_set_http_conn_fd) + * El handler calls __http_conn_fd() → receives that fd + * El handler calls __http_sse_open(fd) → sends SSE headers, keeps fd open + * El handler calls __http_sse_send(fd, data) → writes "data: ...\n\n" + * El handler calls __http_sse_close(fd) → closes the fd + * El handler returns "__sse__" sentinel → http_worker_v2 does NOT close fd + * + * The -1 value means no current connection (guard against misuse outside + * a handler context). + */ +static __thread int _tl_http_conn_fd = -1; + +/* Called by el_runtime.c's http_worker_v2 — not part of the El ABI. */ +void el_seed_set_http_conn_fd(int fd) { + _tl_http_conn_fd = fd; +} + +/* __http_conn_fd() — returns the raw fd for the current HTTP connection. + * Valid only inside an http_serve_v2 handler before it returns. */ +el_val_t __http_conn_fd(void) { + return EL_INT(_tl_http_conn_fd); +} + +/* __http_sse_open(fd) — sends SSE response headers on fd, keeping it open. + * Returns 1 on success, 0 on write failure. */ +el_val_t __http_sse_open(el_val_t conn_id) { + int fd = (int)(int64_t)conn_id; + if (fd < 0) return 0; + static const char sse_headers[] = + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/event-stream\r\n" + "Cache-Control: no-cache\r\n" + "Connection: keep-alive\r\n" + "Access-Control-Allow-Origin: *\r\n" + "\r\n"; + size_t n = sizeof(sse_headers) - 1; /* exclude NUL */ + size_t sent = 0; + while (sent < n) { + ssize_t w = write(fd, sse_headers + sent, n - sent); + if (w <= 0) return 0; + sent += (size_t)w; + } + return 1; +} + +/* __http_sse_send(fd, data) — writes one SSE event frame: "data: \n\n". + * data must not contain newlines. Returns 1 on success, 0 on client disconnect. */ +el_val_t __http_sse_send(el_val_t conn_id, el_val_t data) { + int fd = (int)(int64_t)conn_id; + if (fd < 0) return 0; + const char* s = EL_CSTR(data); + if (!s) s = ""; + /* Build "data: \n\n" in a single buffer for one write call. */ + size_t prefix_len = 6; /* "data: " */ + size_t slen = strlen(s); + size_t total = prefix_len + slen + 2; /* + "\n\n" */ + char* buf = malloc(total + 1); + if (!buf) return 0; + memcpy(buf, "data: ", 6); + memcpy(buf + 6, s, slen); + buf[6 + slen] = '\n'; + buf[6 + slen + 1] = '\n'; + buf[total] = '\0'; + size_t sent = 0; + int ok = 1; + while (sent < total) { + ssize_t w = write(fd, buf + sent, total - sent); + if (w <= 0) { ok = 0; break; } + sent += (size_t)w; + } + free(buf); + return ok ? 1 : 0; +} + +/* __http_sse_close(fd) — closes the SSE connection fd. */ +el_val_t __http_sse_close(el_val_t conn_id) { + int fd = (int)(int64_t)conn_id; + if (fd < 0) return 0; + close(fd); + return 1; +} + +/* ── Threading ───────────────────────────────────────────────────────────── */ +/* + * Design: + * Static ElThread table (max EL_SEED_MAX_THREADS entries). + * __thread_create: pick a free slot, store fn_name + arg, launch pthread. + * Worker: dlsym(RTLD_DEFAULT, fn_name) → call as el_val_t fn(el_val_t). + * Store result string in slot.result. + * __thread_join: pthread_join, return stored result string. + * + * Thread handle is the slot index (0..EL_SEED_MAX_THREADS-1). + * Returns -1 on failure (no slots, dlsym failure, pthread_create failure). + * + * Each slot is guarded by its own mutex so join/create on different handles + * never contend. + */ + +#define EL_SEED_MAX_THREADS 64 + +typedef el_val_t (*ElFn1)(el_val_t); + +typedef struct { + int in_use; + char* fn_name; + char* arg; + char* result; + pthread_t tid; + int done; /* set to 1 by worker before exit */ +} ElThread; + +static ElThread _el_threads[EL_SEED_MAX_THREADS]; +static pthread_mutex_t _el_thread_mu = PTHREAD_MUTEX_INITIALIZER; + +typedef struct { + int slot; +} ElThreadArg; + +static void* el_thread_worker(void* raw) { + ElThreadArg* ta = (ElThreadArg*)raw; + int slot = ta->slot; + free(ta); + + ElThread* t = &_el_threads[slot]; + + /* Resolve the El function symbol in the running binary. */ + void* sym = dlsym(RTLD_DEFAULT, t->fn_name); + if (!sym) { + pthread_mutex_lock(&_el_thread_mu); + t->result = seed_strdup_persist(""); + t->done = 1; + pthread_mutex_unlock(&_el_thread_mu); + return NULL; + } + + ElFn1 fn = (ElFn1)sym; + + /* Call the El function with the string argument. */ + el_val_t arg_val = EL_STR(t->arg); + el_val_t ret = fn(arg_val); + + /* Persist the result string. */ + const char* rs = EL_CSTR(ret); + char* stored = seed_strdup_persist(rs ? rs : ""); + + pthread_mutex_lock(&_el_thread_mu); + t->result = stored; + t->done = 1; + pthread_mutex_unlock(&_el_thread_mu); + + return NULL; +} + +el_val_t __thread_create(el_val_t fn_name, el_val_t arg) { + const char* fname = EL_CSTR(fn_name); + const char* astr = EL_CSTR(arg); + if (!fname || !*fname) return (el_val_t)(int64_t)-1; + if (!astr) astr = ""; + + pthread_mutex_lock(&_el_thread_mu); + int slot = -1; + for (int i = 0; i < EL_SEED_MAX_THREADS; i++) { + if (!_el_threads[i].in_use) { slot = i; break; } + } + if (slot < 0) { + pthread_mutex_unlock(&_el_thread_mu); + return (el_val_t)(int64_t)-1; + } + + ElThread* t = &_el_threads[slot]; + t->in_use = 1; + t->done = 0; + t->fn_name = seed_strdup_persist(fname); + t->arg = seed_strdup_persist(astr); + t->result = NULL; + pthread_mutex_unlock(&_el_thread_mu); + + ElThreadArg* ta = malloc(sizeof(ElThreadArg)); + if (!ta) { + pthread_mutex_lock(&_el_thread_mu); + free(t->fn_name); free(t->arg); + t->in_use = 0; + pthread_mutex_unlock(&_el_thread_mu); + return (el_val_t)(int64_t)-1; + } + ta->slot = slot; + + if (pthread_create(&t->tid, NULL, el_thread_worker, ta) != 0) { + free(ta); + pthread_mutex_lock(&_el_thread_mu); + free(t->fn_name); free(t->arg); + t->in_use = 0; + pthread_mutex_unlock(&_el_thread_mu); + return (el_val_t)(int64_t)-1; + } + + return (el_val_t)(int64_t)slot; +} + +el_val_t __thread_join(el_val_t tid) { + int64_t slot = (int64_t)tid; + if (slot < 0 || slot >= EL_SEED_MAX_THREADS) return seed_wrap_str(seed_strdup("")); + + ElThread* t = &_el_threads[slot]; + + pthread_mutex_lock(&_el_thread_mu); + if (!t->in_use) { + pthread_mutex_unlock(&_el_thread_mu); + return seed_wrap_str(seed_strdup("")); + } + pthread_mutex_unlock(&_el_thread_mu); + + /* Wait for thread to finish. */ + pthread_join(t->tid, NULL); + + pthread_mutex_lock(&_el_thread_mu); + char* res = t->result ? t->result : ""; + char* copy = seed_strdup(res); /* arena-tracked for caller lifetime */ + free(t->fn_name); + free(t->arg); + if (t->result) { free(t->result); t->result = NULL; } + t->fn_name = NULL; t->arg = NULL; + t->in_use = 0; + t->done = 0; + pthread_mutex_unlock(&_el_thread_mu); + + return seed_wrap_str(copy); +} + +/* ── Mutex pool ──────────────────────────────────────────────────────────── */ + +#define EL_SEED_MAX_MUTEXES 256 + +static pthread_mutex_t _el_mutexes[EL_SEED_MAX_MUTEXES]; +static int _el_mutex_init[EL_SEED_MAX_MUTEXES]; +static int _el_mutex_used[EL_SEED_MAX_MUTEXES]; +static pthread_mutex_t _el_mutex_pool_mu = PTHREAD_MUTEX_INITIALIZER; + +el_val_t __mutex_new(void) { + pthread_mutex_lock(&_el_mutex_pool_mu); + int slot = -1; + for (int i = 0; i < EL_SEED_MAX_MUTEXES; i++) { + if (!_el_mutex_used[i]) { slot = i; break; } + } + if (slot < 0) { + pthread_mutex_unlock(&_el_mutex_pool_mu); + return (el_val_t)(int64_t)-1; + } + _el_mutex_used[slot] = 1; + if (!_el_mutex_init[slot]) { + pthread_mutex_init(&_el_mutexes[slot], NULL); + _el_mutex_init[slot] = 1; + } + pthread_mutex_unlock(&_el_mutex_pool_mu); + return (el_val_t)(int64_t)slot; +} + +void __mutex_lock(el_val_t m) { + int64_t slot = (int64_t)m; + if (slot < 0 || slot >= EL_SEED_MAX_MUTEXES) return; + if (!_el_mutex_init[slot]) return; + pthread_mutex_lock(&_el_mutexes[slot]); +} + +void __mutex_unlock(el_val_t m) { + int64_t slot = (int64_t)m; + if (slot < 0 || slot >= EL_SEED_MAX_MUTEXES) return; + if (!_el_mutex_init[slot]) return; + pthread_mutex_unlock(&_el_mutexes[slot]); +} + +/* ── Subprocess ──────────────────────────────────────────────────────────── */ + +el_val_t __exec(el_val_t cmd) { + const char* c = EL_CSTR(cmd); + if (!c) return seed_wrap_str(seed_strdup("")); + FILE* f = popen(c, "r"); + if (!f) return seed_wrap_str(seed_strdup("")); + size_t cap = 4096, len = 0; + char* buf = malloc(cap); + if (!buf) { pclose(f); return seed_wrap_str(seed_strdup("")); } + char tmp[4096]; + while (fgets(tmp, sizeof(tmp), f)) { + size_t n = strlen(tmp); + while (len + n + 1 > cap) { + cap *= 2; + char* g = realloc(buf, cap); + if (!g) { free(buf); pclose(f); return seed_wrap_str(seed_strdup("")); } + buf = g; + } + memcpy(buf + len, tmp, n); + len += n; + buf[len] = '\0'; + } + pclose(f); + seed_arena_track(buf); + return seed_wrap_str(buf); +} + +void __exec_bg(el_val_t cmd) { + const char* c = EL_CSTR(cmd); + if (!c) return; + /* Fork-free: run in background via system() with & appended. */ + size_t n = strlen(c); + char* s = malloc(n + 4); + if (!s) return; + memcpy(s, c, n); + memcpy(s + n, " &", 3); + system(s); + free(s); +} + +/* ── Environment and process ─────────────────────────────────────────────── */ + +el_val_t __env_get(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return seed_wrap_str(seed_strdup("")); + const char* v = getenv(k); + return seed_wrap_str(seed_strdup(v ? v : "")); +} + +void __exit_program(el_val_t code) { + exit((int)(int64_t)code); +} + +/* ── args_json ────────────────────────────────────────────────────────────── */ + +static int _seed_argc = 0; +static char** _seed_argv = NULL; + +void el_seed_init_args(int argc, char** argv) { + _seed_argc = argc; + _seed_argv = argv; +} + +el_val_t __args_json(void) { + /* Return ["arg1","arg2",...] as a JSON string. Skip argv[0] (program name). */ + size_t cap = 256, len = 0; + char* buf = malloc(cap); + if (!buf) return seed_wrap_str(seed_strdup("[]")); + buf[len++] = '['; + int first = 1; + for (int i = 1; i < _seed_argc; i++) { + const char* a = _seed_argv[i]; + /* Estimate: each arg needs at most strlen*6+4 bytes (worst case escape) */ + size_t need = strlen(a) * 6 + 8; + while (len + need + 2 > cap) { + cap *= 2; + char* g = realloc(buf, cap); + if (!g) { free(buf); return seed_wrap_str(seed_strdup("[]")); } + buf = g; + } + if (!first) buf[len++] = ','; + first = 0; + buf[len++] = '"'; + for (const char* p = a; *p; p++) { + unsigned char c = (unsigned char)*p; + if (c == '"') { buf[len++] = '\\'; buf[len++] = '"'; } + else if (c == '\\') { buf[len++] = '\\'; buf[len++] = '\\'; } + else if (c == '\n') { buf[len++] = '\\'; buf[len++] = 'n'; } + else if (c == '\r') { buf[len++] = '\\'; buf[len++] = 'r'; } + else if (c == '\t') { buf[len++] = '\\'; buf[len++] = 't'; } + else buf[len++] = (char)c; + } + buf[len++] = '"'; + } + buf[len++] = ']'; + buf[len] = '\0'; + seed_arena_track(buf); + return seed_wrap_str(buf); +} + +/* ── Time ────────────────────────────────────────────────────────────────── */ + +el_val_t __time_now_ns(void) { + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts) == 0) { + int64_t ns = (int64_t)ts.tv_sec * 1000000000LL + (int64_t)ts.tv_nsec; + return (el_val_t)ns; + } + struct timeval tv; + gettimeofday(&tv, NULL); + return (el_val_t)((int64_t)tv.tv_sec * 1000000000LL + (int64_t)tv.tv_usec * 1000LL); +} + +void __sleep_ms(el_val_t ms) { + int64_t m = (int64_t)ms; + if (m < 0) m = 0; + struct timespec ts; + ts.tv_sec = (time_t)(m / 1000LL); + ts.tv_nsec = (long)((m % 1000LL) * 1000000LL); + nanosleep(&ts, NULL); +} + +/* ── UUID ────────────────────────────────────────────────────────────────── */ + +static int _seed_uuid_seeded = 0; + +el_val_t __uuid_v4(void) { + if (!_seed_uuid_seeded) { + srand((unsigned)time(NULL) ^ (unsigned)(uintptr_t)&_seed_uuid_seeded); + _seed_uuid_seeded = 1; + } + unsigned char b[16]; + for (int i = 0; i < 16; i++) b[i] = (unsigned char)(rand() & 0xff); + b[6] = (b[6] & 0x0f) | 0x40; /* version 4 */ + b[8] = (b[8] & 0x3f) | 0x80; /* RFC 4122 variant */ + char buf[37]; + snprintf(buf, sizeof(buf), + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + b[0],b[1],b[2],b[3], b[4],b[5], b[6],b[7], + b[8],b[9], b[10],b[11],b[12],b[13],b[14],b[15]); + return seed_wrap_str(seed_strdup(buf)); +} + +/* ── Math ────────────────────────────────────────────────────────────────── */ + +el_val_t __sqrt_f(el_val_t f) { return el_from_float(sqrt(el_to_float(f))); } +el_val_t __log_f(el_val_t f) { return el_from_float(log10(el_to_float(f))); } +el_val_t __ln_f(el_val_t f) { return el_from_float(log(el_to_float(f))); } +el_val_t __sin_f(el_val_t f) { return el_from_float(sin(el_to_float(f))); } +el_val_t __cos_f(el_val_t f) { return el_from_float(cos(el_to_float(f))); } +el_val_t __pi_f(void) { return el_from_float(3.14159265358979323846); } + +/* ── JSON — thin wrappers around el_runtime.c implementations ────────────── */ + +el_val_t __json_get(el_val_t json, el_val_t key) { return json_get(json, key); } +el_val_t __json_get_raw(el_val_t json_str, el_val_t key) { return json_get_raw(json_str, key); } +el_val_t __json_parse(el_val_t s) { return json_parse(s); } +el_val_t __json_stringify(el_val_t v) { return json_stringify(v); } +el_val_t __json_parse_map(el_val_t json_str) { return json_parse(json_str); } +el_val_t __json_stringify_val(el_val_t val) { return json_stringify(val); } +el_val_t __json_array_len(el_val_t json_str) { return json_array_len(json_str); } +el_val_t __json_array_get(el_val_t json_str, el_val_t index) { return json_array_get(json_str, index); } +el_val_t __json_array_get_string(el_val_t json_str, el_val_t index) { return json_array_get_string(json_str, index); } +el_val_t __json_get_string(el_val_t json_str, el_val_t key) { return json_get_string(json_str, key); } +el_val_t __json_get_int(el_val_t json_str, el_val_t key) { return json_get_int(json_str, key); } +el_val_t __json_get_float(el_val_t json_str, el_val_t key) { return json_get_float(json_str, key); } +el_val_t __json_get_bool(el_val_t json_str, el_val_t key) { return json_get_bool(json_str, key); } +el_val_t __json_set(el_val_t json_str, el_val_t key, el_val_t value) { return json_set(json_str, key, value); } + +/* ── State K/V — thin wrappers ───────────────────────────────────────────── */ + +el_val_t __state_set(el_val_t key, el_val_t value) { return state_set(key, value); } +el_val_t __state_get(el_val_t key) { return state_get(key); } +el_val_t __state_del(el_val_t key) { return state_del(key); } +el_val_t __state_keys(void) { return state_keys(); } + +/* ── HTML/URL — thin wrappers ────────────────────────────────────────────── */ + +el_val_t __html_sanitize(el_val_t input_html, el_val_t allowlist_json) { + return el_html_sanitize(input_html, allowlist_json); +} + +el_val_t __url_encode(el_val_t s) { return url_encode(s); } +el_val_t __url_decode(el_val_t s) { return url_decode(s); } + +/* ── Engram — thin wrappers ──────────────────────────────────────────────── */ + +el_val_t __engram_node(el_val_t content, el_val_t node_type, el_val_t salience) { + return engram_node(content, node_type, salience); +} + +el_val_t __engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags) { + return engram_node_full(content, node_type, label, salience, importance, confidence, tier, tags); +} + +el_val_t __engram_node_layered(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t certainty, el_val_t confidence, + el_val_t status, el_val_t tags, el_val_t layer_id) { + return engram_node_layered(content, node_type, label, salience, certainty, confidence, + status, tags, layer_id); +} + +el_val_t __engram_add_layer(el_val_t name, el_val_t priority, el_val_t suppressible, + el_val_t transparent, el_val_t injectable) { + return engram_add_layer(name, priority, suppressible, transparent, injectable); +} + +el_val_t __engram_remove_layer(el_val_t layer_id) { return engram_remove_layer(layer_id); } +el_val_t __engram_list_layers(void) { return engram_list_layers(); } +el_val_t __engram_get_node(el_val_t id) { return engram_get_node(id); } +void __engram_strengthen(el_val_t node_id) { engram_strengthen(node_id); } +void __engram_forget(el_val_t node_id) { engram_forget(node_id); } +el_val_t __engram_node_count(void) { return engram_node_count(); } + +el_val_t __engram_search(el_val_t query, el_val_t limit) { return engram_search(query, limit); } +el_val_t __engram_scan_nodes(el_val_t limit, el_val_t offset) { return engram_scan_nodes(limit, offset); } + +void __engram_connect(el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t relation) { + engram_connect(from_id, to_id, weight, relation); +} + +el_val_t __engram_edge_between(el_val_t from_id, el_val_t to_id) { + return engram_edge_between(from_id, to_id); +} + +el_val_t __engram_neighbors(el_val_t node_id) { return engram_neighbors(node_id); } + +el_val_t __engram_neighbors_filtered(el_val_t node_id, el_val_t max_depth, el_val_t direction) { + return engram_neighbors_filtered(node_id, max_depth, direction); +} + +el_val_t __engram_edge_count(void) { return engram_edge_count(); } + +el_val_t __engram_activate(el_val_t query, el_val_t depth) { return engram_activate(query, depth); } +el_val_t __engram_save(el_val_t path) { return engram_save(path); } +el_val_t __engram_load(el_val_t path) { return engram_load(path); } + +el_val_t __engram_get_node_json(el_val_t id) { return engram_get_node_json(id); } + +el_val_t __engram_search_json(el_val_t query, el_val_t limit) { + return engram_search_json(query, limit); +} + +el_val_t __engram_scan_nodes_json(el_val_t limit, el_val_t offset) { + return engram_scan_nodes_json(limit, offset); +} + +el_val_t __engram_scan_nodes_by_type_json(el_val_t node_type, el_val_t limit, el_val_t offset) { + return engram_scan_nodes_by_type_json(node_type, limit, offset); +} + +el_val_t __engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction) { + return engram_neighbors_json(node_id, max_depth, direction); +} + +el_val_t __engram_activate_json(el_val_t query, el_val_t depth) { + return engram_activate_json(query, depth); +} + +el_val_t __engram_stats_json(void) { return engram_stats_json(); } +el_val_t __engram_list_layers_json(void) { return engram_list_layers_json(); } + +el_val_t __engram_compile_layered_json(el_val_t intent, el_val_t depth) { + return engram_compile_layered_json(intent, depth); +} + +/* ── Cryptographic hashing ────────────────────────────────────────────────── */ +/* + * SHA-256 — self-contained implementation (no OpenSSL dependency). + * Based on Brad Conte's public-domain reference implementation. + */ + +typedef struct { + uint8_t data[64]; + uint32_t datalen; + uint64_t bitlen; + uint32_t state[8]; +} _seed_sha256_ctx; + +static const uint32_t _seed_sha256_k[64] = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +}; + +#define _SEED_ROTR32(x,n) (((x)>>(n))|((x)<<(32-(n)))) +#define _SEED_CH(x,y,z) (((x)&(y))^(~(x)&(z))) +#define _SEED_MAJ(x,y,z) (((x)&(y))^((x)&(z))^((y)&(z))) +#define _SEED_EP0(x) (_SEED_ROTR32(x,2)^_SEED_ROTR32(x,13)^_SEED_ROTR32(x,22)) +#define _SEED_EP1(x) (_SEED_ROTR32(x,6)^_SEED_ROTR32(x,11)^_SEED_ROTR32(x,25)) +#define _SEED_SIG0(x) (_SEED_ROTR32(x,7)^_SEED_ROTR32(x,18)^((x)>>3)) +#define _SEED_SIG1(x) (_SEED_ROTR32(x,17)^_SEED_ROTR32(x,19)^((x)>>10)) + +static void _seed_sha256_transform(_seed_sha256_ctx* ctx, const uint8_t* data) { + uint32_t a,b,c,d,e,f,g,h,t1,t2,m[64]; + for (int i=0,j=0; i<16; i++,j+=4) + m[i]=(uint32_t)(data[j]<<24)|(data[j+1]<<16)|(data[j+2]<<8)|data[j+3]; + for (int i=16; i<64; i++) + m[i]=_SEED_SIG1(m[i-2])+m[i-7]+_SEED_SIG0(m[i-15])+m[i-16]; + a=ctx->state[0]; b=ctx->state[1]; c=ctx->state[2]; d=ctx->state[3]; + e=ctx->state[4]; f=ctx->state[5]; g=ctx->state[6]; h=ctx->state[7]; + for (int i=0; i<64; i++) { + t1=h+_SEED_EP1(e)+_SEED_CH(e,f,g)+_seed_sha256_k[i]+m[i]; + t2=_SEED_EP0(a)+_SEED_MAJ(a,b,c); + h=g; g=f; f=e; e=d+t1; d=c; c=b; b=a; a=t1+t2; + } + ctx->state[0]+=a; ctx->state[1]+=b; ctx->state[2]+=c; ctx->state[3]+=d; + ctx->state[4]+=e; ctx->state[5]+=f; ctx->state[6]+=g; ctx->state[7]+=h; +} + +static void _seed_sha256_init(_seed_sha256_ctx* ctx) { + ctx->datalen=0; ctx->bitlen=0; + ctx->state[0]=0x6a09e667; ctx->state[1]=0xbb67ae85; + ctx->state[2]=0x3c6ef372; ctx->state[3]=0xa54ff53a; + ctx->state[4]=0x510e527f; ctx->state[5]=0x9b05688c; + ctx->state[6]=0x1f83d9ab; ctx->state[7]=0x5be0cd19; +} + +static void _seed_sha256_update(_seed_sha256_ctx* ctx, const uint8_t* data, size_t len) { + for (size_t i=0; idata[ctx->datalen++] = data[i]; + if (ctx->datalen==64) { _seed_sha256_transform(ctx,ctx->data); ctx->bitlen+=512; ctx->datalen=0; } + } +} + +static void _seed_sha256_final(_seed_sha256_ctx* ctx, uint8_t hash[32]) { + uint32_t i=ctx->datalen; + ctx->data[i++]=0x80; + if (ctx->datalen<56) { while(i<56) ctx->data[i++]=0; } + else { while(i<64) ctx->data[i++]=0; _seed_sha256_transform(ctx,ctx->data); memset(ctx->data,0,56); } + ctx->bitlen+=ctx->datalen*8; + ctx->data[63]=(uint8_t)(ctx->bitlen); ctx->data[62]=(uint8_t)(ctx->bitlen>>8); + ctx->data[61]=(uint8_t)(ctx->bitlen>>16); ctx->data[60]=(uint8_t)(ctx->bitlen>>24); + ctx->data[59]=(uint8_t)(ctx->bitlen>>32); ctx->data[58]=(uint8_t)(ctx->bitlen>>40); + ctx->data[57]=(uint8_t)(ctx->bitlen>>48); ctx->data[56]=(uint8_t)(ctx->bitlen>>56); + _seed_sha256_transform(ctx,ctx->data); + for (i=0; i<4; i++) { + hash[i] =(uint8_t)(ctx->state[0]>>(24-i*8)); + hash[i+4] =(uint8_t)(ctx->state[1]>>(24-i*8)); + hash[i+8] =(uint8_t)(ctx->state[2]>>(24-i*8)); + hash[i+12] =(uint8_t)(ctx->state[3]>>(24-i*8)); + hash[i+16] =(uint8_t)(ctx->state[4]>>(24-i*8)); + hash[i+20] =(uint8_t)(ctx->state[5]>>(24-i*8)); + hash[i+24] =(uint8_t)(ctx->state[6]>>(24-i*8)); + hash[i+28] =(uint8_t)(ctx->state[7]>>(24-i*8)); + } +} + +/* ── Manifest reader (shared: macOS + Linux) ─────────────────────────────── */ +/* + * Parse the app{} block from a manifest.el file. + * Expected format (subset — only app{} block is parsed): + * + * app { + * window_title "My App" + * window_width 1200 + * window_height 800 + * min_width 600 + * min_height 400 + * } + * + * Returns JSON: {"title":"...","width":N,"height":N,"min_width":N,"min_height":N} + * Returns "{}" on parse failure. + * + * Compiled unconditionally so both EL_TARGET_MACOS and EL_TARGET_LINUX can use + * it — the __manifest_read builtin is identical on all native targets. + */ + +static void seed_manifest_skip_ws(const char** p) { + while (**p && (unsigned char)**p <= ' ') (*p)++; +} + +/* Read a quoted string literal. Caller must free() the result. */ +static char* seed_manifest_read_string(const char** p) { + seed_manifest_skip_ws(p); + if (**p != '"') return NULL; + (*p)++; + const char* start = *p; + while (**p && **p != '"') { + if (**p == '\\') (*p)++; /* skip escaped char */ + (*p)++; + } + size_t len = (size_t)(*p - start); + if (**p == '"') (*p)++; + char* out = malloc(len + 1); + if (!out) return NULL; + memcpy(out, start, len); + out[len] = '\0'; + return out; +} + +/* Read an unquoted integer literal. */ +static int64_t seed_manifest_read_int(const char** p) { + seed_manifest_skip_ws(p); + int64_t result = 0; + int neg = 0; + if (**p == '-') { neg = 1; (*p)++; } + while (**p >= '0' && **p <= '9') { + result = result * 10 + (**p - '0'); + (*p)++; + } + return neg ? -result : result; +} + +/* Find "app {" block start. Returns pointer past the '{'. */ +static const char* seed_manifest_find_app_block(const char* src) { + while (*src) { + /* Skip line comments (// ...) */ + if (src[0] == '/' && src[1] == '/') { + while (*src && *src != '\n') src++; + continue; + } + if (strncmp(src, "app", 3) == 0 && + (src[3] == ' ' || src[3] == '\t' || src[3] == '\n' || src[3] == '{')) { + src += 3; + while (*src && *src != '{') src++; + if (*src == '{') return src + 1; + return NULL; + } + src++; + } + return NULL; +} + +el_val_t __manifest_read(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p || !*p) return seed_wrap_str(seed_strdup("{}")); + + /* Read the file. */ + FILE* f = fopen(p, "r"); + if (!f) return seed_wrap_str(seed_strdup("{}")); + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + if (sz <= 0) { fclose(f); return seed_wrap_str(seed_strdup("{}")); } + char* src = malloc((size_t)sz + 1); + if (!src) { fclose(f); return seed_wrap_str(seed_strdup("{}")); } + size_t got = fread(src, 1, (size_t)sz, f); + src[got] = '\0'; + fclose(f); + + const char* app_start = seed_manifest_find_app_block(src); + if (!app_start) { free(src); return seed_wrap_str(seed_strdup("{}")); } + + /* Parse key-value pairs inside the app { } block. */ + char* title = NULL; + int64_t width = 1200; + int64_t height = 800; + int64_t min_w = 600; + int64_t min_h = 400; + + const char* cur = app_start; + while (*cur && *cur != '}') { + /* Skip whitespace and comments. */ + while (*cur && (unsigned char)*cur <= ' ') cur++; + if (*cur == '}') break; + if (cur[0] == '/' && cur[1] == '/') { + while (*cur && *cur != '\n') cur++; + continue; + } + + /* Read key token. */ + const char* key_start = cur; + while (*cur && (unsigned char)*cur > ' ' && *cur != '{' && *cur != '}') cur++; + size_t key_len = (size_t)(cur - key_start); + if (key_len == 0) { cur++; continue; } + + /* Skip whitespace between key and value. */ + while (*cur == ' ' || *cur == '\t') cur++; + + if (strncmp(key_start, "window_title", key_len) == 0 && key_len == 12) { + free(title); + title = seed_manifest_read_string(&cur); + } else if (strncmp(key_start, "window_width", key_len) == 0 && key_len == 12) { + width = seed_manifest_read_int(&cur); + } else if (strncmp(key_start, "window_height", key_len) == 0 && key_len == 13) { + height = seed_manifest_read_int(&cur); + } else if (strncmp(key_start, "min_width", key_len) == 0 && key_len == 9) { + min_w = seed_manifest_read_int(&cur); + } else if (strncmp(key_start, "min_height", key_len) == 0 && key_len == 10) { + min_h = seed_manifest_read_int(&cur); + } else { + /* Unknown key — skip to end of line. */ + while (*cur && *cur != '\n' && *cur != '}') cur++; + } + } + + free(src); + + /* Build JSON result. */ + const char* t = title ? title : "App"; + size_t buf_sz = strlen(t) * 6 + 128; + char* buf = seed_strbuf(buf_sz); + snprintf(buf, buf_sz, + "{\"title\":\"%s\",\"width\":%lld,\"height\":%lld,\"min_width\":%lld,\"min_height\":%lld}", + t, (long long)width, (long long)height, (long long)min_w, (long long)min_h); + free(title); + return seed_wrap_str(buf); +} + +/* ── Native widget system — macOS AppKit ─────────────────────────────────── */ +/* + * These builtins are compiled in only when EL_TARGET_MACOS is defined. + * They call through to el_appkit.m (Objective-C) which implements the actual + * AppKit widget creation and management. + * + * Each builtin is a thin wrapper: marshal el_val_t ↔ C types, call the + * el_appkit_* function, return the result. + * + * Compile requirements: + * - Compile el_appkit.m alongside this file (clang -ObjC -framework Cocoa) + * - Pass -DEL_TARGET_MACOS to enable this section + */ + +#ifdef EL_TARGET_MACOS + +/* Forward declarations — implemented in el_appkit.m */ +extern void el_appkit_init(void); +extern void el_appkit_run_loop(void); +extern int64_t el_appkit_window_create(const char* title, int w, int h, int mw, int mh); +extern void el_appkit_window_show(int64_t handle); +extern void el_appkit_window_set_title(int64_t handle, const char* title); +extern int64_t el_appkit_vstack_create(int spacing); +extern int64_t el_appkit_hstack_create(int spacing); +extern int64_t el_appkit_zstack_create(void); +extern int64_t el_appkit_scroll_create(void); +extern int64_t el_appkit_label_create(const char* text); +extern int64_t el_appkit_button_create(const char* label); +extern int64_t el_appkit_text_field_create(const char* placeholder); +extern int64_t el_appkit_text_area_create(const char* placeholder); +extern int64_t el_appkit_image_create(const char* path_or_name); +extern void el_appkit_widget_set_text(int64_t handle, const char* text); +extern const char* el_appkit_widget_get_text(int64_t handle); +extern void el_appkit_widget_set_color(int64_t h, float r, float g, float b, float a); +extern void el_appkit_widget_set_bg_color(int64_t h, float r, float g, float b, float a); +extern void el_appkit_widget_set_font(int64_t h, const char* family, int size, int bold); +extern void el_appkit_widget_set_padding(int64_t h, int top, int right, int bottom, int left); +extern void el_appkit_widget_set_width(int64_t h, int width); +extern void el_appkit_widget_set_height(int64_t h, int height); +extern void el_appkit_widget_set_flex(int64_t h, int flex); +extern void el_appkit_widget_set_corner_radius(int64_t h, int radius); +extern void el_appkit_widget_set_disabled(int64_t h, int disabled); +extern void el_appkit_widget_set_hidden(int64_t h, int hidden); +extern void el_appkit_widget_add_child(int64_t parent, int64_t child); +extern void el_appkit_widget_remove_child(int64_t parent, int64_t child); +extern void el_appkit_widget_destroy(int64_t handle); +extern void el_appkit_widget_on_click(int64_t h, const char* fn_name); +extern void el_appkit_widget_on_change(int64_t h, const char* fn_name); +extern void el_appkit_widget_on_submit(int64_t h, const char* fn_name); + +/* ── Native widget builtins ──────────────────────────────────────────────── */ + +void __native_init(void) { el_appkit_init(); } +void __native_run_loop(void) { el_appkit_run_loop(); } + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_appkit_window_create( + EL_CSTR(title), + (int)(int64_t)width, (int)(int64_t)height, + (int)(int64_t)min_width, (int)(int64_t)min_height); +} + +void __window_show(el_val_t h) { el_appkit_window_show((int64_t)h); } +void __window_set_title(el_val_t h, el_val_t t) { el_appkit_window_set_title((int64_t)h, EL_CSTR(t)); } + +el_val_t __vstack_create(el_val_t spacing) { return (el_val_t)el_appkit_vstack_create((int)(int64_t)spacing); } +el_val_t __hstack_create(el_val_t spacing) { return (el_val_t)el_appkit_hstack_create((int)(int64_t)spacing); } +el_val_t __zstack_create(void) { return (el_val_t)el_appkit_zstack_create(); } +el_val_t __scroll_create(void) { return (el_val_t)el_appkit_scroll_create(); } + +el_val_t __label_create(el_val_t text) { return (el_val_t)el_appkit_label_create(EL_CSTR(text)); } +el_val_t __button_create(el_val_t label) { return (el_val_t)el_appkit_button_create(EL_CSTR(label)); } +el_val_t __text_field_create(el_val_t placeholder) { return (el_val_t)el_appkit_text_field_create(EL_CSTR(placeholder)); } +el_val_t __text_area_create(el_val_t placeholder) { return (el_val_t)el_appkit_text_area_create(EL_CSTR(placeholder)); } +el_val_t __image_create(el_val_t path_or_name) { return (el_val_t)el_appkit_image_create(EL_CSTR(path_or_name)); } + +void __widget_set_text(el_val_t h, el_val_t t) { el_appkit_widget_set_text((int64_t)h, EL_CSTR(t)); } + +el_val_t __widget_get_text(el_val_t h) { + const char* s = el_appkit_widget_get_text((int64_t)h); + if (!s) return seed_wrap_str(seed_strdup("")); + /* el_appkit returns strdup'd string — wrap it (arena won't track it, but + * caller must treat return as short-lived or copy it). */ + return EL_STR(s); +} + +void __widget_set_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_appkit_widget_set_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_bg_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_appkit_widget_set_bg_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_font(el_val_t h, el_val_t family, el_val_t size, el_val_t bold) { + el_appkit_widget_set_font((int64_t)h, EL_CSTR(family), + (int)(int64_t)size, (int)(int64_t)bold); +} + +void __widget_set_padding(el_val_t h, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_appkit_widget_set_padding((int64_t)h, + (int)(int64_t)top, (int)(int64_t)right, + (int)(int64_t)bottom, (int)(int64_t)left); +} + +void __widget_set_width(el_val_t h, el_val_t w) { el_appkit_widget_set_width((int64_t)h, (int)(int64_t)w); } +void __widget_set_height(el_val_t h, el_val_t ht) { el_appkit_widget_set_height((int64_t)h, (int)(int64_t)ht); } +void __widget_set_flex(el_val_t h, el_val_t f) { el_appkit_widget_set_flex((int64_t)h, (int)(int64_t)f); } +void __widget_set_corner_radius(el_val_t h, el_val_t r) { el_appkit_widget_set_corner_radius((int64_t)h, (int)(int64_t)r); } +void __widget_set_disabled(el_val_t h, el_val_t d) { el_appkit_widget_set_disabled((int64_t)h, (int)(int64_t)d); } +void __widget_set_hidden(el_val_t h, el_val_t hid) { el_appkit_widget_set_hidden((int64_t)h, (int)(int64_t)hid); } +void __widget_add_child(el_val_t p, el_val_t c) { el_appkit_widget_add_child((int64_t)p, (int64_t)c); } +void __widget_remove_child(el_val_t p, el_val_t c) { el_appkit_widget_remove_child((int64_t)p, (int64_t)c); } +void __widget_destroy(el_val_t h) { el_appkit_widget_destroy((int64_t)h); } + +void __widget_on_click(el_val_t h, el_val_t fn_name) { el_appkit_widget_on_click((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_change(el_val_t h, el_val_t fn_name) { el_appkit_widget_on_change((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_submit(el_val_t h, el_val_t fn_name) { el_appkit_widget_on_submit((int64_t)h, EL_CSTR(fn_name)); } + +#endif /* EL_TARGET_MACOS */ + +/* ── Native widget system — Linux GTK4 ──────────────────────────────────── */ +/* + * These builtins are compiled in only when EL_TARGET_LINUX is defined. + * They call through to el_gtk4.c which implements the GTK4 widget layer. + * + * Each builtin is a thin wrapper: marshal el_val_t ↔ C types, call the + * el_gtk4_* function, return the result. + * + * Compile requirements: + * - Compile el_gtk4.c alongside this file + * gcc -DEL_TARGET_LINUX $(pkg-config --cflags gtk4) el_gtk4.c -c ... + * - Pass -DEL_TARGET_LINUX to enable this section + * - Link with $(pkg-config --libs gtk4) -ldl + * + * __manifest_read is shared with the macOS path (implemented above in the + * seed_manifest_* helpers) and compiled for both targets unconditionally. + */ + +#ifdef EL_TARGET_LINUX + +/* Forward declarations — implemented in el_gtk4.c */ +extern void el_gtk4_init(void); +extern void el_gtk4_run_loop(void); +extern int64_t el_gtk4_window_create(const char* title, int w, int h, + int mw, int mh); +extern void el_gtk4_window_show(int64_t handle); +extern void el_gtk4_window_set_title(int64_t handle, const char* title); +extern int64_t el_gtk4_vstack_create(int spacing); +extern int64_t el_gtk4_hstack_create(int spacing); +extern int64_t el_gtk4_zstack_create(void); +extern int64_t el_gtk4_scroll_create(void); +extern int64_t el_gtk4_label_create(const char* text); +extern int64_t el_gtk4_button_create(const char* label); +extern int64_t el_gtk4_text_field_create(const char* placeholder); +extern int64_t el_gtk4_text_area_create(const char* placeholder); +extern int64_t el_gtk4_image_create(const char* path_or_name); +extern void el_gtk4_widget_set_text(int64_t handle, const char* text); +extern const char* el_gtk4_widget_get_text(int64_t handle); +extern void el_gtk4_widget_set_color(int64_t h, float r, float g, float b, float a); +extern void el_gtk4_widget_set_bg_color(int64_t h, float r, float g, float b, float a); +extern void el_gtk4_widget_set_font(int64_t h, const char* family, int size, int bold); +extern void el_gtk4_widget_set_padding(int64_t h, int top, int right, int bottom, int left); +extern void el_gtk4_widget_set_width(int64_t h, int width); +extern void el_gtk4_widget_set_height(int64_t h, int height); +extern void el_gtk4_widget_set_flex(int64_t h, int flex); +extern void el_gtk4_widget_set_corner_radius(int64_t h, int radius); +extern void el_gtk4_widget_set_disabled(int64_t h, int disabled); +extern void el_gtk4_widget_set_hidden(int64_t h, int hidden); +extern void el_gtk4_widget_add_child(int64_t parent, int64_t child); +extern void el_gtk4_widget_remove_child(int64_t parent, int64_t child); +extern void el_gtk4_widget_destroy(int64_t handle); +extern void el_gtk4_widget_on_click(int64_t h, const char* fn_name); +extern void el_gtk4_widget_on_change(int64_t h, const char* fn_name); +extern void el_gtk4_widget_on_submit(int64_t h, const char* fn_name); + +void __native_init(void) { el_gtk4_init(); } +void __native_run_loop(void) { el_gtk4_run_loop(); } + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_gtk4_window_create( + EL_CSTR(title), + (int)(int64_t)width, (int)(int64_t)height, + (int)(int64_t)min_width, (int)(int64_t)min_height); +} + +void __window_show(el_val_t h) { el_gtk4_window_show((int64_t)h); } +void __window_set_title(el_val_t h, el_val_t t) { el_gtk4_window_set_title((int64_t)h, EL_CSTR(t)); } + +el_val_t __vstack_create(el_val_t spacing) { return (el_val_t)el_gtk4_vstack_create((int)(int64_t)spacing); } +el_val_t __hstack_create(el_val_t spacing) { return (el_val_t)el_gtk4_hstack_create((int)(int64_t)spacing); } +el_val_t __zstack_create(void) { return (el_val_t)el_gtk4_zstack_create(); } +el_val_t __scroll_create(void) { return (el_val_t)el_gtk4_scroll_create(); } + +el_val_t __label_create(el_val_t text) { return (el_val_t)el_gtk4_label_create(EL_CSTR(text)); } +el_val_t __button_create(el_val_t label) { return (el_val_t)el_gtk4_button_create(EL_CSTR(label)); } +el_val_t __text_field_create(el_val_t placeholder) { return (el_val_t)el_gtk4_text_field_create(EL_CSTR(placeholder)); } +el_val_t __text_area_create(el_val_t placeholder) { return (el_val_t)el_gtk4_text_area_create(EL_CSTR(placeholder)); } +el_val_t __image_create(el_val_t path_or_name) { return (el_val_t)el_gtk4_image_create(EL_CSTR(path_or_name)); } + +void __widget_set_text(el_val_t h, el_val_t t) { el_gtk4_widget_set_text((int64_t)h, EL_CSTR(t)); } + +el_val_t __widget_get_text(el_val_t h) { + const char* s = el_gtk4_widget_get_text((int64_t)h); + if (!s) return EL_STR(""); + return EL_STR(s); /* el_gtk4 returns strdup'd string */ +} + +void __widget_set_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_gtk4_widget_set_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_bg_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_gtk4_widget_set_bg_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_font(el_val_t h, el_val_t family, el_val_t size, el_val_t bold) { + el_gtk4_widget_set_font((int64_t)h, EL_CSTR(family), + (int)(int64_t)size, (int)(int64_t)bold); +} + +void __widget_set_padding(el_val_t h, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_gtk4_widget_set_padding((int64_t)h, + (int)(int64_t)top, (int)(int64_t)right, + (int)(int64_t)bottom, (int)(int64_t)left); +} + +void __widget_set_width(el_val_t h, el_val_t w) { el_gtk4_widget_set_width((int64_t)h, (int)(int64_t)w); } +void __widget_set_height(el_val_t h, el_val_t ht) { el_gtk4_widget_set_height((int64_t)h, (int)(int64_t)ht); } +void __widget_set_flex(el_val_t h, el_val_t f) { el_gtk4_widget_set_flex((int64_t)h, (int)(int64_t)f); } +void __widget_set_corner_radius(el_val_t h, el_val_t r) { el_gtk4_widget_set_corner_radius((int64_t)h, (int)(int64_t)r); } +void __widget_set_disabled(el_val_t h, el_val_t d) { el_gtk4_widget_set_disabled((int64_t)h, (int)(int64_t)d); } +void __widget_set_hidden(el_val_t h, el_val_t hid) { el_gtk4_widget_set_hidden((int64_t)h, (int)(int64_t)hid); } +void __widget_add_child(el_val_t p, el_val_t c) { el_gtk4_widget_add_child((int64_t)p, (int64_t)c); } +void __widget_remove_child(el_val_t p, el_val_t c) { el_gtk4_widget_remove_child((int64_t)p, (int64_t)c); } +void __widget_destroy(el_val_t h) { el_gtk4_widget_destroy((int64_t)h); } + +void __widget_on_click(el_val_t h, el_val_t fn_name) { el_gtk4_widget_on_click((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_change(el_val_t h, el_val_t fn_name) { el_gtk4_widget_on_change((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_submit(el_val_t h, el_val_t fn_name) { el_gtk4_widget_on_submit((int64_t)h, EL_CSTR(fn_name)); } + +#endif /* EL_TARGET_LINUX */ + +/* ── Native widget system — SDL2 (embedded / Pi) ─────────────────────────── */ +/* + * These builtins are compiled in only when EL_TARGET_SDL2 is defined. + * They call through to el_sdl2.c which implements a retained-mode pixel + * widget layer on top of SDL2 + SDL_ttf + SDL_image. + * + * Each builtin is a thin wrapper: marshal el_val_t ↔ C types, call the + * el_sdl2_* function, return the result. + * + * Compile requirements: + * gcc -DEL_TARGET_SDL2 $(sdl2-config --cflags) el_sdl2.c -c ... + * Pass -DEL_TARGET_SDL2 to enable this section. + * Link: + * $(sdl2-config --libs) -lSDL2_ttf -lSDL2_image -ldl + * + * __manifest_read is shared with the macOS/Linux paths (implemented above). + */ + +#ifdef EL_TARGET_SDL2 + +/* Forward declarations — implemented in el_sdl2.c */ +extern void el_sdl2_init(void); +extern void el_sdl2_run_loop(void); +extern int64_t el_sdl2_window_create(const char* title, int w, int h, + int mw, int mh); +extern void el_sdl2_window_show(int64_t handle); +extern void el_sdl2_window_set_title(int64_t handle, const char* title); +extern int64_t el_sdl2_vstack_create(int spacing); +extern int64_t el_sdl2_hstack_create(int spacing); +extern int64_t el_sdl2_zstack_create(void); +extern int64_t el_sdl2_scroll_create(void); +extern int64_t el_sdl2_label_create(const char* text); +extern int64_t el_sdl2_button_create(const char* label); +extern int64_t el_sdl2_text_field_create(const char* placeholder); +extern int64_t el_sdl2_text_area_create(const char* placeholder); +extern int64_t el_sdl2_image_create(const char* path_or_name); +extern void el_sdl2_widget_set_text(int64_t handle, const char* text); +extern const char* el_sdl2_widget_get_text(int64_t handle); +extern void el_sdl2_widget_set_color(int64_t h, float r, float g, float b, float a); +extern void el_sdl2_widget_set_bg_color(int64_t h, float r, float g, float b, float a); +extern void el_sdl2_widget_set_font(int64_t h, const char* family, int size, int bold); +extern void el_sdl2_widget_set_padding(int64_t h, int top, int right, int bottom, int left); +extern void el_sdl2_widget_set_width(int64_t h, int width); +extern void el_sdl2_widget_set_height(int64_t h, int height); +extern void el_sdl2_widget_set_flex(int64_t h, int flex); +extern void el_sdl2_widget_set_corner_radius(int64_t h, int radius); +extern void el_sdl2_widget_set_disabled(int64_t h, int disabled); +extern void el_sdl2_widget_set_hidden(int64_t h, int hidden); +extern void el_sdl2_widget_add_child(int64_t parent, int64_t child); +extern void el_sdl2_widget_remove_child(int64_t parent, int64_t child); +extern void el_sdl2_widget_destroy(int64_t handle); +extern void el_sdl2_widget_on_click(int64_t h, const char* fn_name); +extern void el_sdl2_widget_on_change(int64_t h, const char* fn_name); +extern void el_sdl2_widget_on_submit(int64_t h, const char* fn_name); + +void __native_init(void) { el_sdl2_init(); } +void __native_run_loop(void) { el_sdl2_run_loop(); } + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_sdl2_window_create( + EL_CSTR(title), + (int)(int64_t)width, (int)(int64_t)height, + (int)(int64_t)min_width, (int)(int64_t)min_height); +} + +void __window_show(el_val_t h) { el_sdl2_window_show((int64_t)h); } +void __window_set_title(el_val_t h, el_val_t t) { el_sdl2_window_set_title((int64_t)h, EL_CSTR(t)); } + +el_val_t __vstack_create(el_val_t spacing) { return (el_val_t)el_sdl2_vstack_create((int)(int64_t)spacing); } +el_val_t __hstack_create(el_val_t spacing) { return (el_val_t)el_sdl2_hstack_create((int)(int64_t)spacing); } +el_val_t __zstack_create(void) { return (el_val_t)el_sdl2_zstack_create(); } +el_val_t __scroll_create(void) { return (el_val_t)el_sdl2_scroll_create(); } + +el_val_t __label_create(el_val_t text) { return (el_val_t)el_sdl2_label_create(EL_CSTR(text)); } +el_val_t __button_create(el_val_t label) { return (el_val_t)el_sdl2_button_create(EL_CSTR(label)); } +el_val_t __text_field_create(el_val_t placeholder) { return (el_val_t)el_sdl2_text_field_create(EL_CSTR(placeholder)); } +el_val_t __text_area_create(el_val_t placeholder) { return (el_val_t)el_sdl2_text_area_create(EL_CSTR(placeholder)); } +el_val_t __image_create(el_val_t path_or_name) { return (el_val_t)el_sdl2_image_create(EL_CSTR(path_or_name)); } + +void __widget_set_text(el_val_t h, el_val_t t) { el_sdl2_widget_set_text((int64_t)h, EL_CSTR(t)); } + +el_val_t __widget_get_text(el_val_t h) { + const char* s = el_sdl2_widget_get_text((int64_t)h); + if (!s) return EL_STR(""); + return EL_STR(s); +} + +void __widget_set_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_sdl2_widget_set_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_bg_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_sdl2_widget_set_bg_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_font(el_val_t h, el_val_t family, el_val_t size, el_val_t bold) { + el_sdl2_widget_set_font((int64_t)h, EL_CSTR(family), + (int)(int64_t)size, (int)(int64_t)bold); +} + +void __widget_set_padding(el_val_t h, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_sdl2_widget_set_padding((int64_t)h, + (int)(int64_t)top, (int)(int64_t)right, + (int)(int64_t)bottom, (int)(int64_t)left); +} + +void __widget_set_width(el_val_t h, el_val_t w) { el_sdl2_widget_set_width((int64_t)h, (int)(int64_t)w); } +void __widget_set_height(el_val_t h, el_val_t ht) { el_sdl2_widget_set_height((int64_t)h, (int)(int64_t)ht); } +void __widget_set_flex(el_val_t h, el_val_t f) { el_sdl2_widget_set_flex((int64_t)h, (int)(int64_t)f); } +void __widget_set_corner_radius(el_val_t h, el_val_t r) { el_sdl2_widget_set_corner_radius((int64_t)h, (int)(int64_t)r); } +void __widget_set_disabled(el_val_t h, el_val_t d) { el_sdl2_widget_set_disabled((int64_t)h, (int)(int64_t)d); } +void __widget_set_hidden(el_val_t h, el_val_t hid) { el_sdl2_widget_set_hidden((int64_t)h, (int)(int64_t)hid); } +void __widget_add_child(el_val_t p, el_val_t c) { el_sdl2_widget_add_child((int64_t)p, (int64_t)c); } +void __widget_remove_child(el_val_t p, el_val_t c) { el_sdl2_widget_remove_child((int64_t)p, (int64_t)c); } +void __widget_destroy(el_val_t h) { el_sdl2_widget_destroy((int64_t)h); } + +void __widget_on_click(el_val_t h, el_val_t fn_name) { el_sdl2_widget_on_click((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_change(el_val_t h, el_val_t fn_name) { el_sdl2_widget_on_change((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_submit(el_val_t h, el_val_t fn_name) { el_sdl2_widget_on_submit((int64_t)h, EL_CSTR(fn_name)); } + +#endif /* EL_TARGET_SDL2 */ + +/* ── EL_TARGET_LVGL — LVGL v9 embedded backend ─────────────────────────────── + * + * These builtins are compiled in only when EL_TARGET_LVGL is defined. + * Each wrapper translates el_val_t arguments (opaque int64_t) into the typed + * parameters that el_lvgl_* expects, then calls through. + * + * Build: + * gcc -DEL_TARGET_LVGL -I./lvgl el_lvgl.c el_seed.c -c ... + * # Link with lvgl.a. For bare-metal add -DEL_LVGL_NO_DLSYM. + * + * __manifest_read is shared — defined unconditionally above. + */ + +#ifdef EL_TARGET_LVGL + +extern void el_lvgl_init(void); +extern void el_lvgl_run_loop(void); +extern int64_t el_lvgl_window_create(const char *title, int w, int h, + int mw, int mh); +extern void el_lvgl_window_show(int64_t handle); +extern void el_lvgl_window_set_title(int64_t handle, const char *title); +extern int64_t el_lvgl_vstack_create(int spacing); +extern int64_t el_lvgl_hstack_create(int spacing); +extern int64_t el_lvgl_zstack_create(void); +extern int64_t el_lvgl_scroll_create(void); +extern int64_t el_lvgl_label_create(const char *text); +extern int64_t el_lvgl_button_create(const char *label); +extern int64_t el_lvgl_text_field_create(const char *placeholder); +extern int64_t el_lvgl_text_area_create(const char *placeholder); +extern int64_t el_lvgl_image_create(const char *path_or_name); +extern void el_lvgl_widget_set_text(int64_t handle, const char *text); +extern const char *el_lvgl_widget_get_text(int64_t handle); +extern void el_lvgl_widget_set_color(int64_t h, float r, float g, + float b, float a); +extern void el_lvgl_widget_set_bg_color(int64_t h, float r, float g, + float b, float a); +extern void el_lvgl_widget_set_font(int64_t h, const char *family, + int size, int bold); +extern void el_lvgl_widget_set_padding(int64_t h, int top, int right, + int bottom, int left); +extern void el_lvgl_widget_set_width(int64_t h, int width); +extern void el_lvgl_widget_set_height(int64_t h, int height); +extern void el_lvgl_widget_set_flex(int64_t h, int flex); +extern void el_lvgl_widget_set_corner_radius(int64_t h, int radius); +extern void el_lvgl_widget_set_disabled(int64_t h, int disabled); +extern void el_lvgl_widget_set_hidden(int64_t h, int hidden); +extern void el_lvgl_widget_add_child(int64_t parent, int64_t child); +extern void el_lvgl_widget_remove_child(int64_t parent, int64_t child); +extern void el_lvgl_widget_destroy(int64_t handle); +extern void el_lvgl_widget_on_click(int64_t h, const char *fn_name); +extern void el_lvgl_widget_on_change(int64_t h, const char *fn_name); +extern void el_lvgl_widget_on_submit(int64_t h, const char *fn_name); + +void __native_init(void) { el_lvgl_init(); } +void __native_run_loop(void) { el_lvgl_run_loop(); } + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_lvgl_window_create( + EL_CSTR(title), + (int)(int64_t)width, (int)(int64_t)height, + (int)(int64_t)min_width, (int)(int64_t)min_height); +} + +void __window_show(el_val_t h) { el_lvgl_window_show((int64_t)h); } +void __window_set_title(el_val_t h, el_val_t t) { el_lvgl_window_set_title((int64_t)h, EL_CSTR(t)); } + +el_val_t __vstack_create(el_val_t spacing) { return (el_val_t)el_lvgl_vstack_create((int)(int64_t)spacing); } +el_val_t __hstack_create(el_val_t spacing) { return (el_val_t)el_lvgl_hstack_create((int)(int64_t)spacing); } +el_val_t __zstack_create(void) { return (el_val_t)el_lvgl_zstack_create(); } +el_val_t __scroll_create(void) { return (el_val_t)el_lvgl_scroll_create(); } + +el_val_t __label_create(el_val_t text) { return (el_val_t)el_lvgl_label_create(EL_CSTR(text)); } +el_val_t __button_create(el_val_t label) { return (el_val_t)el_lvgl_button_create(EL_CSTR(label)); } +el_val_t __text_field_create(el_val_t placeholder) { return (el_val_t)el_lvgl_text_field_create(EL_CSTR(placeholder)); } +el_val_t __text_area_create(el_val_t placeholder) { return (el_val_t)el_lvgl_text_area_create(EL_CSTR(placeholder)); } +el_val_t __image_create(el_val_t path_or_name) { return (el_val_t)el_lvgl_image_create(EL_CSTR(path_or_name)); } + +void __widget_set_text(el_val_t h, el_val_t t) { el_lvgl_widget_set_text((int64_t)h, EL_CSTR(t)); } + +el_val_t __widget_get_text(el_val_t h) { + const char *s = el_lvgl_widget_get_text((int64_t)h); + if (!s) return EL_STR(""); + return EL_STR(s); /* pointer into LVGL internal storage — valid until next LVGL op */ +} + +void __widget_set_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_lvgl_widget_set_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_bg_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_lvgl_widget_set_bg_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_font(el_val_t h, el_val_t family, el_val_t size, el_val_t bold) { + el_lvgl_widget_set_font((int64_t)h, EL_CSTR(family), + (int)(int64_t)size, (int)(int64_t)bold); +} + +void __widget_set_padding(el_val_t h, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_lvgl_widget_set_padding((int64_t)h, + (int)(int64_t)top, (int)(int64_t)right, + (int)(int64_t)bottom, (int)(int64_t)left); +} + +void __widget_set_width(el_val_t h, el_val_t w) { el_lvgl_widget_set_width((int64_t)h, (int)(int64_t)w); } +void __widget_set_height(el_val_t h, el_val_t ht) { el_lvgl_widget_set_height((int64_t)h, (int)(int64_t)ht); } +void __widget_set_flex(el_val_t h, el_val_t f) { el_lvgl_widget_set_flex((int64_t)h, (int)(int64_t)f); } +void __widget_set_corner_radius(el_val_t h, el_val_t r) { el_lvgl_widget_set_corner_radius((int64_t)h, (int)(int64_t)r); } +void __widget_set_disabled(el_val_t h, el_val_t d) { el_lvgl_widget_set_disabled((int64_t)h, (int)(int64_t)d); } +void __widget_set_hidden(el_val_t h, el_val_t hid) { el_lvgl_widget_set_hidden((int64_t)h, (int)(int64_t)hid); } +void __widget_add_child(el_val_t p, el_val_t c) { el_lvgl_widget_add_child((int64_t)p, (int64_t)c); } +void __widget_remove_child(el_val_t p, el_val_t c) { el_lvgl_widget_remove_child((int64_t)p, (int64_t)c); } +void __widget_destroy(el_val_t h) { el_lvgl_widget_destroy((int64_t)h); } + +void __widget_on_click(el_val_t h, el_val_t fn_name) { el_lvgl_widget_on_click((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_change(el_val_t h, el_val_t fn_name) { el_lvgl_widget_on_change((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_submit(el_val_t h, el_val_t fn_name) { el_lvgl_widget_on_submit((int64_t)h, EL_CSTR(fn_name)); } + +#endif /* EL_TARGET_LVGL */ + +/* ── Cryptographic hashing ────────────────────────────────────────────────── */ + +el_val_t __sha256_hex(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) s = ""; + _seed_sha256_ctx ctx; + _seed_sha256_init(&ctx); + _seed_sha256_update(&ctx, (const uint8_t*)s, strlen(s)); + uint8_t digest[32]; + _seed_sha256_final(&ctx, digest); + static const char hex[] = "0123456789abcdef"; + char* out = malloc(65); + if (!out) return EL_STR(""); + for (int i=0; i<32; i++) { + out[i*2] = hex[(digest[i]>>4)&0xf]; + out[i*2+1] = hex[digest[i]&0xf]; + } + out[64] = '\0'; + return EL_STR(out); +} diff --git a/ui/examples/native-hello-ios/NativeHello/el_uikit.m b/ui/examples/native-hello-ios/NativeHello/el_uikit.m new file mode 100644 index 0000000..01a97a1 --- /dev/null +++ b/ui/examples/native-hello-ios/NativeHello/el_uikit.m @@ -0,0 +1,1118 @@ +/* + * el_uikit.m — UIKit backend for the el native widget system. + * + * This file implements the iOS UIKit widget layer that el_seed.c calls + * through to when EL_TARGET_IOS is defined. + * + * Architecture: + * el program (el code) + * → __widget_* C builtins in el_seed.c + * → el_uikit_* C-callable functions declared here + * → UIView/UIWindow/UIStackView/UIButton/etc. via ObjC + * + * Widget handles: every widget (window, view, control) is assigned an int64_t + * slot index into _el_widgets[]. The el program holds these as opaque Int values. + * Slot 0 is never valid (reserved as null handle = -1 convention). + * + * Threading: All UIKit calls MUST run on the main thread. el_uikit_sync_main + * bounces work to the main thread synchronously if called from a background thread. + * + * Callback mechanism: when a widget fires an event (button tap, text change), + * the bridge looks up the registered callback function name, then calls + * dlsym(RTLD_DEFAULT, fn_name)(widget_handle, event_data_string) + * This resolves the El function symbol at runtime, matching the __thread_create + * pattern already established in el_seed.c. + * + * iOS lifecycle: UIApplicationMain never returns. The el program's "main" body + * (window creation, layout, show) must execute inside applicationDidFinishLaunchingWithOptions. + * The caller sets el_main_entry_fn before calling __native_run_loop so the + * delegate can invoke it at the right time. + * + * Compile (MRC — no ARC; manual retain/release needed for struct-embedded id): + * clang -std=gnu11 -ObjC -fno-objc-arc -DEL_TARGET_IOS -framework UIKit \ + * -c el_uikit.m -o el_uikit.o + * Then link el_uikit.o alongside el_seed.c. + * + * Do NOT use -fobjc-arc: the widget table stores id in a plain C struct. ARC + * forbids explicit retain/release on struct-embedded object pointers and cannot + * insert automatic retain/release through C struct boundaries. MRC is the + * correct choice for this kind of C/ObjC bridge. + * + * Link flags required: + * -framework UIKit + */ + +#ifdef EL_TARGET_IOS + +#import +#import +#include +#include +#include +#include +#include +#include "el_runtime.h" + +/* ── Widget table ─────────────────────────────────────────────────────────── */ + +#define EL_UIKIT_MAX_WIDGETS 4096 + +typedef enum { + EL_WIDGET_FREE = 0, + EL_WIDGET_WINDOW = 1, + EL_WIDGET_VSTACK = 2, + EL_WIDGET_HSTACK = 3, + EL_WIDGET_ZSTACK = 4, + EL_WIDGET_SCROLL = 5, + EL_WIDGET_LABEL = 6, + EL_WIDGET_BUTTON = 7, + EL_WIDGET_TEXTFIELD = 8, + EL_WIDGET_TEXTAREA = 9, + EL_WIDGET_IMAGE = 10, + EL_WIDGET_DIVIDER = 11, + EL_WIDGET_SPACER = 12, +} ElWidgetKind; + +typedef struct { + ElWidgetKind kind; + id obj; /* UIWindow* or UIView* subclass, retained */ + char* cb_click; /* El function name for click/submit events */ + char* cb_change; /* El function name for value-change events */ +} ElWidget; + +static ElWidget _el_widgets[EL_UIKIT_MAX_WIDGETS]; +static int _el_widget_count = 0; + +/* Side table for ObjC delegate objects keyed by widget slot (MRC retained). */ +static id _el_delegates[EL_UIKIT_MAX_WIDGETS]; + +/* Allocate a slot and return its index. Returns -1 if full. */ +static int64_t el_widget_alloc(ElWidgetKind kind, id obj) { + for (int i = 1; i < EL_UIKIT_MAX_WIDGETS; i++) { + if (_el_widgets[i].kind == EL_WIDGET_FREE) { + _el_widgets[i].kind = kind; + _el_widgets[i].obj = [obj retain]; + _el_widgets[i].cb_click = NULL; + _el_widgets[i].cb_change = NULL; + if (i > _el_widget_count) _el_widget_count = i; + return (int64_t)i; + } + } + return -1; +} + +static ElWidget* el_widget_get(int64_t handle) { + if (handle <= 0 || handle >= EL_UIKIT_MAX_WIDGETS) return NULL; + if (_el_widgets[handle].kind == EL_WIDGET_FREE) return NULL; + return &_el_widgets[handle]; +} + +static void el_widget_free(int64_t handle) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + [w->obj release]; + w->obj = nil; + w->kind = EL_WIDGET_FREE; + free(w->cb_click); w->cb_click = NULL; + free(w->cb_change); w->cb_change = NULL; +} + +/* ── Dispatch helpers ─────────────────────────────────────────────────────── */ + +/* Run a block on the main thread, waiting for completion. Safe to call from + * any thread including the main thread. Uses dispatch_sync so callers can + * rely on the block having run before the function returns. */ +static void el_uikit_sync_main(void (^block)(void)) { + if ([NSThread isMainThread]) { + block(); + } else { + dispatch_sync(dispatch_get_main_queue(), block); + } +} + +/* ── El callback invocation ──────────────────────────────────────────────── */ +/* + * Invoke an El callback by symbol name. The El function must have the + * signature: fn handler(handle: Int, data: String) -> Void + * which compiles to: void fn_name(el_val_t handle, el_val_t data) + */ +typedef void (*ElCb2)(int64_t handle, int64_t data); + +static void el_uikit_invoke_cb(const char* fn_name, int64_t handle, const char* data) { + if (!fn_name || !*fn_name) return; + void* sym = dlsym(RTLD_DEFAULT, fn_name); + if (!sym) return; + ElCb2 fn = (ElCb2)sym; + fn(handle, (int64_t)(uintptr_t)(data ? data : "")); +} + +/* ── ObjC helper: ElEventProxy — button tap and text event target ─────────── */ + +/* + * ElEventProxy is a lightweight ObjC action target / delegate aggregator. + * One instance is allocated per widget that has events. Stored in _el_delegates[]. + */ +@interface ElEventProxy : NSObject +@property (nonatomic, assign) int64_t widgetHandle; +/* UIButton tap */ +- (void)elButtonTapped:(id)sender; +/* UITextField UIControlEventEditingChanged */ +- (void)elTextChanged:(id)sender; +@end + +@implementation ElEventProxy + +- (void)elButtonTapped:(id)sender { + (void)sender; + ElWidget* w = el_widget_get(self.widgetHandle); + if (w && w->cb_click) { + el_uikit_invoke_cb(w->cb_click, self.widgetHandle, ""); + } +} + +- (void)elTextChanged:(id)sender { + UITextField* tf = (UITextField*)sender; + ElWidget* w = el_widget_get(self.widgetHandle); + if (!w) return; + const char* val = [tf.text UTF8String]; + if (w->cb_change) { + el_uikit_invoke_cb(w->cb_change, self.widgetHandle, val ? val : ""); + } +} + +/* UITextFieldDelegate — return key fires on_submit (stored in cb_click). */ +- (BOOL)textFieldShouldReturn:(UITextField*)textField { + ElWidget* w = el_widget_get(self.widgetHandle); + if (w && w->cb_click) { + const char* val = [textField.text UTF8String]; + el_uikit_invoke_cb(w->cb_click, self.widgetHandle, val ? val : ""); + } + [textField resignFirstResponder]; + return YES; +} + +@end + +/* ── UITextView change delegate ──────────────────────────────────────────── */ + +@interface ElTextViewDelegate : NSObject +@property (nonatomic, assign) int64_t widgetHandle; +@end + +@implementation ElTextViewDelegate + +- (void)textViewDidChange:(UITextView*)textView { + ElWidget* w = el_widget_get(self.widgetHandle); + if (!w || !w->cb_change) return; + const char* val = [textView.text UTF8String]; + el_uikit_invoke_cb(w->cb_change, self.widgetHandle, val ? val : ""); +} + +@end + +/* ── iOS application lifecycle ───────────────────────────────────────────── */ + +/* + * el_main_entry_fn — set by el's main() (via __native_run_loop) before calling + * UIApplicationMain. The app delegate invokes it in didFinishLaunching so that + * the el program's window/widget setup runs at the correct lifecycle point. + */ +void (*el_main_entry_fn)(void) = NULL; + +/* argc/argv forwarded from el_runtime_init_args (or main). */ +static int _el_argc = 0; +static char** _el_argv = NULL; + +/* + * el_uikit_set_args — call from el_runtime_init_args / main() before + * __native_run_loop to forward argc/argv to UIApplicationMain. + */ +void el_uikit_set_args(int argc, char** argv) { + _el_argc = argc; + _el_argv = argv; +} + +@interface ElAppDelegate : UIResponder +@property (nonatomic, strong) UIWindow *keyWindow; +@end + +@implementation ElAppDelegate + +- (BOOL)application:(UIApplication*)app + didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { + (void)app; (void)launchOptions; + /* + * The el program called __native_init and set up el_main_entry_fn before + * UIApplicationMain was entered. We call it here so window creation and + * widget layout happen on the main thread at the right lifecycle moment. + */ + if (el_main_entry_fn) { + el_main_entry_fn(); + } + return YES; +} + +- (void)applicationWillResignActive:(UIApplication*)app { (void)app; } +- (void)applicationDidEnterBackground:(UIApplication*)app { (void)app; } +- (void)applicationWillEnterForeground:(UIApplication*)app { (void)app; } +- (void)applicationDidBecomeActive:(UIApplication*)app { (void)app; } + +@end + +/* ── Public C API ─────────────────────────────────────────────────────────── */ + +/* + * el_uikit_init — one-time initialisation. Idempotent. Call before any other + * el_uikit_* function. On iOS there is no UIApplication equivalent of + * [NSApplication sharedApplication] to call here — the real initialisation + * happens inside UIApplicationMain which is entered from el_uikit_run_loop. + * This function records that init was requested. + */ +static int _el_uikit_init_done = 0; + +void el_uikit_init(void) { + _el_uikit_init_done = 1; +} + +/* + * el_uikit_run_loop — enters UIApplicationMain. Never returns. + * Must be called from the process main thread as the final step of main(). + * Sets el_main_entry_fn to the provided function pointer before entering + * UIApplicationMain so the app delegate can call back into el code. + */ +void el_uikit_run_loop(void (*entry_fn)(void)) { + el_main_entry_fn = entry_fn; + UIApplicationMain(_el_argc, _el_argv, nil, @"ElAppDelegate"); +} + +/* + * el_uikit_window_create — create a UIWindow and configure a root + * UINavigationController + UIViewController. Returns window handle. + * + * On iOS there is exactly one full-screen window. width/height from the + * manifest are stored but the window always fills the screen. The title + * is applied to the root view controller's navigationItem. + */ +int64_t el_uikit_window_create(const char* title, int width, int height, + int min_width, int min_height) { + (void)width; (void)height; (void)min_width; (void)min_height; + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UIScreen* screen = [UIScreen mainScreen]; + UIWindow* win = [[UIWindow alloc] initWithFrame:[screen bounds]]; + win.backgroundColor = [UIColor systemBackgroundColor]; + + /* Root view controller with a vertical UIStackView as content. */ + UIViewController* rootVC = [[UIViewController alloc] init]; + NSString* titleStr = [NSString stringWithUTF8String:title ? title : ""]; + rootVC.title = titleStr; + + UIStackView* rootStack = [[UIStackView alloc] initWithFrame:CGRectZero]; + rootStack.axis = UILayoutConstraintAxisVertical; + rootStack.alignment = UIStackViewAlignmentFill; + rootStack.distribution = UIStackViewDistributionFill; + rootStack.spacing = 0.0; + rootStack.translatesAutoresizingMaskIntoConstraints = NO; + [rootVC.view addSubview:rootStack]; + + /* Pin root stack to safe area. */ + UILayoutGuide* safe = rootVC.view.safeAreaLayoutGuide; + [NSLayoutConstraint activateConstraints:@[ + [rootStack.topAnchor constraintEqualToAnchor:safe.topAnchor], + [rootStack.leadingAnchor constraintEqualToAnchor:safe.leadingAnchor], + [rootStack.trailingAnchor constraintEqualToAnchor:safe.trailingAnchor], + [rootStack.bottomAnchor constraintEqualToAnchor:safe.bottomAnchor], + ]]; + + UINavigationController* navCtrl = + [[UINavigationController alloc] initWithRootViewController:rootVC]; + win.rootViewController = navCtrl; + + /* Store the window. The root stack is accessible via + * ((UINavigationController*)win.rootViewController) + * .topViewController.view.subviews[0] + * but we reach it by casting obj to UIWindow* and digging at add_child time. */ + handle = el_widget_alloc(EL_WIDGET_WINDOW, win); + [win release]; + [rootVC release]; + [rootStack release]; + [navCtrl release]; + }); + return handle; +} + +/* + * el_uikit_window_show — make the window key and visible. + */ +void el_uikit_window_show(int64_t handle) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w || w->kind != EL_WIDGET_WINDOW) return; + UIWindow* win = (UIWindow*)w->obj; + [win makeKeyAndVisible]; + }); +} + +/* + * el_uikit_window_set_title — update nav bar title at runtime. + */ +void el_uikit_window_set_title(int64_t handle, const char* title) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w || w->kind != EL_WIDGET_WINDOW) return; + UIWindow* win = (UIWindow*)w->obj; + UINavigationController* nav = (UINavigationController*)win.rootViewController; + if ([nav isKindOfClass:[UINavigationController class]]) { + nav.topViewController.title = + [NSString stringWithUTF8String:title ? title : ""]; + } + }); +} + +/* ── Layout container factories ───────────────────────────────────────────── */ + +static int64_t make_uistack(UILayoutConstraintAxis axis, CGFloat spacing) { + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UIStackView* sv = [[UIStackView alloc] initWithFrame:CGRectZero]; + sv.axis = axis; + sv.alignment = UIStackViewAlignmentFill; + sv.distribution = UIStackViewDistributionFill; + sv.spacing = spacing; + sv.translatesAutoresizingMaskIntoConstraints = NO; + ElWidgetKind kind = (axis == UILayoutConstraintAxisVertical) + ? EL_WIDGET_VSTACK : EL_WIDGET_HSTACK; + handle = el_widget_alloc(kind, sv); + [sv release]; + }); + return handle; +} + +int64_t el_uikit_vstack_create(int spacing) { + return make_uistack(UILayoutConstraintAxisVertical, (CGFloat)spacing); +} + +int64_t el_uikit_hstack_create(int spacing) { + return make_uistack(UILayoutConstraintAxisHorizontal, (CGFloat)spacing); +} + +int64_t el_uikit_zstack_create(void) { + /* ZStack = plain UIView; children are added with addSubview and use + * Auto Layout or absolute frames set by the caller. */ + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UIView* v = [[UIView alloc] initWithFrame:CGRectZero]; + v.translatesAutoresizingMaskIntoConstraints = NO; + handle = el_widget_alloc(EL_WIDGET_ZSTACK, v); + [v release]; + }); + return handle; +} + +int64_t el_uikit_scroll_create(void) { + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UIScrollView* sv = [[UIScrollView alloc] initWithFrame:CGRectZero]; + sv.translatesAutoresizingMaskIntoConstraints = NO; + sv.alwaysBounceVertical = YES; + sv.showsHorizontalScrollIndicator = NO; + handle = el_widget_alloc(EL_WIDGET_SCROLL, sv); + [sv release]; + }); + return handle; +} + +/* ── Widget factories ─────────────────────────────────────────────────────── */ + +int64_t el_uikit_label_create(const char* text) { + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UILabel* lbl = [[UILabel alloc] initWithFrame:CGRectZero]; + lbl.text = [NSString stringWithUTF8String:text ? text : ""]; + lbl.numberOfLines = 0; + lbl.translatesAutoresizingMaskIntoConstraints = NO; + handle = el_widget_alloc(EL_WIDGET_LABEL, lbl); + [lbl release]; + }); + return handle; +} + +int64_t el_uikit_button_create(const char* label) { + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UIButton* btn = [UIButton buttonWithType:UIButtonTypeSystem]; + [btn setTitle:[NSString stringWithUTF8String:label ? label : ""] + forState:UIControlStateNormal]; + btn.translatesAutoresizingMaskIntoConstraints = NO; + + ElEventProxy* proxy = [[ElEventProxy alloc] init]; + [btn addTarget:proxy + action:@selector(elButtonTapped:) + forControlEvents:UIControlEventTouchUpInside]; + + int64_t h = el_widget_alloc(EL_WIDGET_BUTTON, btn); + proxy.widgetHandle = h; + _el_delegates[h] = proxy; /* retain in side table */ + handle = h; + /* btn is autoreleased from buttonWithType: — no release needed */ + }); + return handle; +} + +int64_t el_uikit_text_field_create(const char* placeholder) { + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UITextField* tf = [[UITextField alloc] initWithFrame:CGRectZero]; + tf.translatesAutoresizingMaskIntoConstraints = NO; + if (placeholder && *placeholder) { + tf.placeholder = [NSString stringWithUTF8String:placeholder]; + } + tf.borderStyle = UITextBorderStyleRoundedRect; + tf.autocorrectionType = UITextAutocorrectionTypeNo; + + ElEventProxy* proxy = [[ElEventProxy alloc] init]; + tf.delegate = proxy; + [tf addTarget:proxy + action:@selector(elTextChanged:) + forControlEvents:UIControlEventEditingChanged]; + + int64_t h = el_widget_alloc(EL_WIDGET_TEXTFIELD, tf); + proxy.widgetHandle = h; + _el_delegates[h] = proxy; + handle = h; + [tf release]; + }); + return handle; +} + +int64_t el_uikit_text_area_create(const char* placeholder) { + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UITextView* tv = [[UITextView alloc] initWithFrame:CGRectZero]; + tv.translatesAutoresizingMaskIntoConstraints = NO; + tv.font = [UIFont systemFontOfSize:14.0]; + tv.layer.borderColor = [[UIColor systemGray4Color] CGColor]; + tv.layer.borderWidth = 1.0; + tv.layer.cornerRadius = 6.0; + tv.clipsToBounds = YES; + /* UITextView has no native placeholder; set accessibility hint. */ + if (placeholder && *placeholder) { + tv.accessibilityHint = [NSString stringWithUTF8String:placeholder]; + } + + ElTextViewDelegate* del = [[ElTextViewDelegate alloc] init]; + tv.delegate = del; + + int64_t h = el_widget_alloc(EL_WIDGET_TEXTAREA, tv); + del.widgetHandle = h; + _el_delegates[h] = del; + handle = h; + [tv release]; + }); + return handle; +} + +int64_t el_uikit_image_create(const char* path_or_name) { + __block int64_t handle = -1; + el_uikit_sync_main(^{ + UIImage* img = nil; + if (path_or_name && *path_or_name) { + /* Try filesystem path first, then bundle asset name. */ + img = [UIImage imageWithContentsOfFile: + [NSString stringWithUTF8String:path_or_name]]; + if (!img) { + img = [UIImage imageNamed: + [NSString stringWithUTF8String:path_or_name]]; + } + } + UIImageView* iv = [[UIImageView alloc] initWithFrame:CGRectZero]; + iv.translatesAutoresizingMaskIntoConstraints = NO; + iv.contentMode = UIViewContentModeScaleAspectFit; + if (img) { + iv.image = img; + } + handle = el_widget_alloc(EL_WIDGET_IMAGE, iv); + [iv release]; + }); + return handle; +} + +/* ── Widget property setters ─────────────────────────────────────────────── */ + +void el_uikit_widget_set_text(int64_t handle, const char* text) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + NSString* s = [NSString stringWithUTF8String:text ? text : ""]; + switch (w->kind) { + case EL_WIDGET_LABEL: + ((UILabel*)w->obj).text = s; + break; + case EL_WIDGET_TEXTFIELD: + ((UITextField*)w->obj).text = s; + break; + case EL_WIDGET_BUTTON: + [(UIButton*)w->obj setTitle:s forState:UIControlStateNormal]; + break; + case EL_WIDGET_TEXTAREA: + ((UITextView*)w->obj).text = s; + break; + case EL_WIDGET_WINDOW: + el_uikit_window_set_title(handle, text); + break; + default: break; + } + }); +} + +const char* el_uikit_widget_get_text(int64_t handle) { + __block const char* result = ""; + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + NSString* s = nil; + switch (w->kind) { + case EL_WIDGET_LABEL: + s = ((UILabel*)w->obj).text; + break; + case EL_WIDGET_TEXTFIELD: + s = ((UITextField*)w->obj).text; + break; + case EL_WIDGET_BUTTON: + s = [(UIButton*)w->obj titleForState:UIControlStateNormal]; + break; + case EL_WIDGET_TEXTAREA: + s = ((UITextView*)w->obj).text; + break; + default: break; + } + if (s) result = strdup([s UTF8String]); + }); + return result; +} + +void el_uikit_widget_set_color(int64_t handle, float r, float g, float b, float a) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + UIColor* c = [UIColor colorWithRed:(CGFloat)(r / 255.0) + green:(CGFloat)(g / 255.0) + blue:(CGFloat)(b / 255.0) + alpha:(CGFloat)(a / 255.0)]; + switch (w->kind) { + case EL_WIDGET_LABEL: + ((UILabel*)w->obj).textColor = c; + break; + case EL_WIDGET_TEXTFIELD: + ((UITextField*)w->obj).textColor = c; + break; + case EL_WIDGET_TEXTAREA: + ((UITextView*)w->obj).textColor = c; + break; + case EL_WIDGET_BUTTON: + [(UIButton*)w->obj setTitleColor:c forState:UIControlStateNormal]; + ((UIButton*)w->obj).tintColor = c; + break; + case EL_WIDGET_VSTACK: + case EL_WIDGET_HSTACK: + case EL_WIDGET_ZSTACK: + ((UIView*)w->obj).backgroundColor = c; + break; + default: break; + } + }); +} + +void el_uikit_widget_set_bg_color(int64_t handle, float r, float g, float b, float a) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + if (w->kind == EL_WIDGET_WINDOW) { + UIWindow* win = (UIWindow*)w->obj; + win.backgroundColor = [UIColor colorWithRed:(CGFloat)(r / 255.0) + green:(CGFloat)(g / 255.0) + blue:(CGFloat)(b / 255.0) + alpha:(CGFloat)(a / 255.0)]; + return; + } + UIView* v = (UIView*)w->obj; + v.backgroundColor = [UIColor colorWithRed:(CGFloat)(r / 255.0) + green:(CGFloat)(g / 255.0) + blue:(CGFloat)(b / 255.0) + alpha:(CGFloat)(a / 255.0)]; + }); +} + +void el_uikit_widget_set_font(int64_t handle, const char* family, int size, int bold) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + UIFont* font; + if (bold) { + font = [UIFont boldSystemFontOfSize:(CGFloat)size]; + } else if (family && *family && strcmp(family, "system") != 0) { + font = [UIFont fontWithName:[NSString stringWithUTF8String:family] + size:(CGFloat)size]; + if (!font) font = [UIFont systemFontOfSize:(CGFloat)size]; + } else { + font = [UIFont systemFontOfSize:(CGFloat)size]; + } + switch (w->kind) { + case EL_WIDGET_LABEL: + ((UILabel*)w->obj).font = font; + break; + case EL_WIDGET_TEXTFIELD: + ((UITextField*)w->obj).font = font; + break; + case EL_WIDGET_TEXTAREA: + ((UITextView*)w->obj).font = font; + break; + case EL_WIDGET_BUTTON: + ((UIButton*)w->obj).titleLabel.font = font; + break; + default: break; + } + }); +} + +void el_uikit_widget_set_padding(int64_t handle, int top, int right, int bottom, int left) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + UIEdgeInsets insets = UIEdgeInsetsMake( + (CGFloat)top, (CGFloat)left, (CGFloat)bottom, (CGFloat)right); + if (w->kind == EL_WIDGET_VSTACK || w->kind == EL_WIDGET_HSTACK) { + UIStackView* sv = (UIStackView*)w->obj; + sv.layoutMargins = insets; + sv.layoutMarginsRelativeArrangement = YES; + } else if (w->kind == EL_WIDGET_TEXTAREA) { + UITextView* tv = (UITextView*)w->obj; + tv.textContainerInset = insets; + } else { + UIView* v = (UIView*)w->obj; + v.layoutMargins = insets; + } + }); +} + +void el_uikit_widget_set_width(int64_t handle, int width) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w || w->kind == EL_WIDGET_WINDOW) return; + UIView* v = (UIView*)w->obj; + NSLayoutConstraint* c = [v.widthAnchor + constraintEqualToConstant:(CGFloat)width]; + c.priority = UILayoutPriorityDefaultHigh; + c.active = YES; + }); +} + +void el_uikit_widget_set_height(int64_t handle, int height) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w || w->kind == EL_WIDGET_WINDOW) return; + UIView* v = (UIView*)w->obj; + NSLayoutConstraint* c = [v.heightAnchor + constraintEqualToConstant:(CGFloat)height]; + c.priority = UILayoutPriorityDefaultHigh; + c.active = YES; + }); +} + +void el_uikit_widget_set_flex(int64_t handle, int flex) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w || w->kind == EL_WIDGET_WINDOW) return; + UIView* v = (UIView*)w->obj; + /* flex > 0 → low hugging priority so the view expands to fill space. + * flex == 0 → high hugging priority so the view stays at intrinsic size. */ + UILayoutPriority p = (flex > 0) + ? UILayoutPriorityDefaultLow + : UILayoutPriorityDefaultHigh; + [v setContentHuggingPriority:p + forAxis:UILayoutConstraintAxisHorizontal]; + [v setContentHuggingPriority:p + forAxis:UILayoutConstraintAxisVertical]; + }); +} + +void el_uikit_widget_set_corner_radius(int64_t handle, int radius) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w || w->kind == EL_WIDGET_WINDOW) return; + UIView* v = (UIView*)w->obj; + v.layer.cornerRadius = (CGFloat)radius; + v.clipsToBounds = YES; + }); +} + +void el_uikit_widget_set_disabled(int64_t handle, int disabled) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + switch (w->kind) { + case EL_WIDGET_BUTTON: + ((UIButton*)w->obj).enabled = !disabled; + break; + case EL_WIDGET_TEXTFIELD: + ((UITextField*)w->obj).enabled = !disabled; + break; + case EL_WIDGET_TEXTAREA: + ((UITextView*)w->obj).editable = !disabled; + break; + default: + ((UIView*)w->obj).userInteractionEnabled = !disabled; + break; + } + }); +} + +void el_uikit_widget_set_hidden(int64_t handle, int hidden) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w || w->kind == EL_WIDGET_WINDOW) return; + ((UIView*)w->obj).hidden = (BOOL)hidden; + }); +} + +/* ── Child management ─────────────────────────────────────────────────────── */ + +/* + * el_uikit_widget_add_child — attach child widget to parent. + * + * - Window: child is added to the root UIStackView inside the root VC. + * - VStack/HStack: child is added as an arranged subview. + * - ZStack: child is added as a plain subview (caller manages layout). + * - ScrollView: child is added as a subview and pinned to content layout guide. + * - Generic view: child is added as a plain subview. + */ +void el_uikit_widget_add_child(int64_t parent, int64_t child) { + el_uikit_sync_main(^{ + ElWidget* pw = el_widget_get(parent); + ElWidget* cw = el_widget_get(child); + if (!pw || !cw) return; + if (cw->kind == EL_WIDGET_WINDOW) return; /* can't add window as subview */ + + UIView* childView = (UIView*)cw->obj; + + switch (pw->kind) { + case EL_WIDGET_WINDOW: { + /* Dig to the root stack view: window → navCtrl → topVC → view → subviews[0] */ + UIWindow* win = (UIWindow*)pw->obj; + UINavigationController* nav = + (UINavigationController*)win.rootViewController; + UIView* rootVCView = nav.topViewController.view; + UIStackView* stack = nil; + for (UIView* sub in rootVCView.subviews) { + if ([sub isKindOfClass:[UIStackView class]]) { + stack = (UIStackView*)sub; + break; + } + } + if (stack) { + [stack addArrangedSubview:childView]; + } else { + [rootVCView addSubview:childView]; + } + break; + } + case EL_WIDGET_VSTACK: + case EL_WIDGET_HSTACK: { + UIStackView* sv = (UIStackView*)pw->obj; + [sv addArrangedSubview:childView]; + break; + } + case EL_WIDGET_SCROLL: { + UIScrollView* sv = (UIScrollView*)pw->obj; + [sv addSubview:childView]; + /* Pin child to content layout guide so scroll view knows content size. */ + UILayoutGuide* cg = sv.contentLayoutGuide; + childView.translatesAutoresizingMaskIntoConstraints = NO; + [NSLayoutConstraint activateConstraints:@[ + [childView.topAnchor constraintEqualToAnchor:cg.topAnchor], + [childView.leadingAnchor constraintEqualToAnchor:cg.leadingAnchor], + [childView.trailingAnchor constraintEqualToAnchor:cg.trailingAnchor], + [childView.bottomAnchor constraintEqualToAnchor:cg.bottomAnchor], + /* Width matches scroll view's frame (vertical scroll only). */ + [childView.widthAnchor constraintEqualToAnchor:sv.frameLayoutGuide.widthAnchor], + ]]; + break; + } + case EL_WIDGET_ZSTACK: + default: { + UIView* pv = (UIView*)pw->obj; + [pv addSubview:childView]; + break; + } + } + }); +} + +/* + * el_uikit_widget_remove_child — detach a child widget from its parent. + */ +void el_uikit_widget_remove_child(int64_t parent, int64_t child) { + el_uikit_sync_main(^{ + ElWidget* pw = el_widget_get(parent); + ElWidget* cw = el_widget_get(child); + if (!cw || cw->kind == EL_WIDGET_WINDOW) return; + UIView* childView = (UIView*)cw->obj; + /* If parent is a stack view, remove from arranged subviews too. */ + if (pw && (pw->kind == EL_WIDGET_VSTACK || pw->kind == EL_WIDGET_HSTACK)) { + UIStackView* sv = (UIStackView*)pw->obj; + [sv removeArrangedSubview:childView]; + } else if (pw && pw->kind == EL_WIDGET_WINDOW) { + /* Find and remove from root stack. */ + UIWindow* win = (UIWindow*)pw->obj; + UINavigationController* nav = + (UINavigationController*)win.rootViewController; + for (UIView* sub in nav.topViewController.view.subviews) { + if ([sub isKindOfClass:[UIStackView class]]) { + [(UIStackView*)sub removeArrangedSubview:childView]; + break; + } + } + } + [childView removeFromSuperview]; + }); +} + +/* ── Event registration ───────────────────────────────────────────────────── */ + +void el_uikit_widget_on_click(int64_t handle, const char* fn_name) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + free(w->cb_click); + w->cb_click = (fn_name && *fn_name) ? strdup(fn_name) : NULL; +} + +void el_uikit_widget_on_change(int64_t handle, const char* fn_name) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + free(w->cb_change); + w->cb_change = (fn_name && *fn_name) ? strdup(fn_name) : NULL; +} + +void el_uikit_widget_on_submit(int64_t handle, const char* fn_name) { + /* For text fields, submit = return key → stored in cb_click slot. */ + el_uikit_widget_on_click(handle, fn_name); +} + +/* ── Widget destroy ───────────────────────────────────────────────────────── */ + +void el_uikit_widget_destroy(int64_t handle) { + el_uikit_sync_main(^{ + ElWidget* w = el_widget_get(handle); + if (!w) return; + if (w->kind != EL_WIDGET_WINDOW) { + UIView* v = (UIView*)w->obj; + /* If it's in a stack view, also remove from arranged subviews. */ + if ([v.superview isKindOfClass:[UIStackView class]]) { + [(UIStackView*)v.superview removeArrangedSubview:v]; + } + [v removeFromSuperview]; + } + [_el_delegates[handle] release]; + _el_delegates[handle] = nil; + el_widget_free(handle); + }); +} + +/* ── Manifest reader ──────────────────────────────────────────────────────── */ + +/* + * el_uikit_manifest_read — read an app manifest file. Tries the given path + * first; if not found, looks in the main bundle. Returns a C string with the + * file contents (heap-allocated; caller must not free — matches AppKit bridge + * convention of returning static/permanent lifetime strings from manifest). + * Returns NULL on failure. + */ +const char* el_uikit_manifest_read(const char* path) { + if (!path || !*path) return NULL; + + NSString* pathStr = [NSString stringWithUTF8String:path]; + NSString* content = [NSString stringWithContentsOfFile:pathStr + encoding:NSUTF8StringEncoding + error:nil]; + if (!content) { + /* Try bundle resource lookup — strip to last component without extension. */ + NSString* baseName = [[pathStr lastPathComponent] + stringByDeletingPathExtension]; + NSString* ext = [pathStr pathExtension]; + NSString* bundlePath = [[NSBundle mainBundle] + pathForResource:baseName ofType:(ext.length ? ext : nil)]; + if (bundlePath) { + content = [NSString stringWithContentsOfFile:bundlePath + encoding:NSUTF8StringEncoding + error:nil]; + } + } + if (!content) return NULL; + return strdup([content UTF8String]); +} + +/* ── __widget_* C API (called from el_seed.c) ─────────────────────────────── */ +/* + * These are the symbols that el compiled programs actually call. They forward + * directly to the el_uikit_* implementations above. el_val_t is int64_t (the + * same type used by the AppKit bridge). + */ + +void __native_init(void) { + el_uikit_init(); +} + +void __native_run_loop(void) { + /* el_main_entry_fn must be set by the caller before this. On iOS the + * entry function pointer pattern is inverted vs macOS: the el program + * packages up its "build UI" work into a lambda / function and registers + * it via el_main_entry_fn, then calls __native_run_loop. + * el_uikit_run_loop takes that fn pointer and passes it to UIApplicationMain. */ + el_uikit_run_loop(el_main_entry_fn); +} + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_uikit_window_create( + (const char*)(uintptr_t)title, + (int)width, (int)height, + (int)min_width, (int)min_height); +} + +void __window_show(el_val_t handle) { + el_uikit_window_show((int64_t)handle); +} + +void __window_set_title(el_val_t handle, el_val_t title) { + el_uikit_window_set_title((int64_t)handle, + (const char*)(uintptr_t)title); +} + +el_val_t __vstack_create(el_val_t spacing) { + return (el_val_t)el_uikit_vstack_create((int)spacing); +} + +el_val_t __hstack_create(el_val_t spacing) { + return (el_val_t)el_uikit_hstack_create((int)spacing); +} + +el_val_t __zstack_create(void) { + return (el_val_t)el_uikit_zstack_create(); +} + +el_val_t __scroll_create(void) { + return (el_val_t)el_uikit_scroll_create(); +} + +el_val_t __label_create(el_val_t text) { + return (el_val_t)el_uikit_label_create((const char*)(uintptr_t)text); +} + +el_val_t __button_create(el_val_t label) { + return (el_val_t)el_uikit_button_create((const char*)(uintptr_t)label); +} + +el_val_t __text_field_create(el_val_t placeholder) { + return (el_val_t)el_uikit_text_field_create( + (const char*)(uintptr_t)placeholder); +} + +el_val_t __text_area_create(el_val_t placeholder) { + return (el_val_t)el_uikit_text_area_create( + (const char*)(uintptr_t)placeholder); +} + +el_val_t __image_create(el_val_t path_or_name) { + return (el_val_t)el_uikit_image_create( + (const char*)(uintptr_t)path_or_name); +} + +void __widget_set_text(el_val_t handle, el_val_t text) { + el_uikit_widget_set_text((int64_t)handle, (const char*)(uintptr_t)text); +} + +el_val_t __widget_get_text(el_val_t handle) { + return (el_val_t)(uintptr_t)el_uikit_widget_get_text((int64_t)handle); +} + +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a) { + el_uikit_widget_set_color((int64_t)handle, + (float)r, (float)g, (float)b, (float)a); +} + +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a) { + el_uikit_widget_set_bg_color((int64_t)handle, + (float)r, (float)g, (float)b, (float)a); +} + +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold) { + el_uikit_widget_set_font((int64_t)handle, + (const char*)(uintptr_t)family, (int)size, (int)bold); +} + +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_uikit_widget_set_padding((int64_t)handle, + (int)top, (int)right, (int)bottom, (int)left); +} + +void __widget_set_width(el_val_t handle, el_val_t width) { + el_uikit_widget_set_width((int64_t)handle, (int)width); +} + +void __widget_set_height(el_val_t handle, el_val_t height) { + el_uikit_widget_set_height((int64_t)handle, (int)height); +} + +void __widget_set_flex(el_val_t handle, el_val_t flex) { + el_uikit_widget_set_flex((int64_t)handle, (int)flex); +} + +void __widget_set_corner_radius(el_val_t handle, el_val_t radius) { + el_uikit_widget_set_corner_radius((int64_t)handle, (int)radius); +} + +void __widget_set_disabled(el_val_t handle, el_val_t disabled) { + el_uikit_widget_set_disabled((int64_t)handle, (int)disabled); +} + +void __widget_set_hidden(el_val_t handle, el_val_t hidden) { + el_uikit_widget_set_hidden((int64_t)handle, (int)hidden); +} + +void __widget_add_child(el_val_t parent, el_val_t child) { + el_uikit_widget_add_child((int64_t)parent, (int64_t)child); +} + +void __widget_remove_child(el_val_t parent, el_val_t child) { + el_uikit_widget_remove_child((int64_t)parent, (int64_t)child); +} + +void __widget_destroy(el_val_t handle) { + el_uikit_widget_destroy((int64_t)handle); +} + +void __widget_on_click(el_val_t handle, el_val_t fn_name) { + el_uikit_widget_on_click((int64_t)handle, + (const char*)(uintptr_t)fn_name); +} + +void __widget_on_change(el_val_t handle, el_val_t fn_name) { + el_uikit_widget_on_change((int64_t)handle, + (const char*)(uintptr_t)fn_name); +} + +void __widget_on_submit(el_val_t handle, el_val_t fn_name) { + el_uikit_widget_on_submit((int64_t)handle, + (const char*)(uintptr_t)fn_name); +} + +el_val_t __manifest_read(el_val_t path) { + return (el_val_t)(uintptr_t)el_uikit_manifest_read( + (const char*)(uintptr_t)path); +} + +#endif /* EL_TARGET_IOS */ diff --git a/ui/examples/native-hello-ios/NativeHello/main.m b/ui/examples/native-hello-ios/NativeHello/main.m new file mode 100644 index 0000000..4ca6b86 --- /dev/null +++ b/ui/examples/native-hello-ios/NativeHello/main.m @@ -0,0 +1,48 @@ +/* + * main.m — entry point for native-hello-ios. + * + * iOS UIKit lifecycle: + * UIApplicationMain never returns. The compiled el program's boot body + * (native_init → window_from_manifest → app_build → window_show) must + * run inside applicationDidFinishLaunchingWithOptions on the main thread. + * + * How it works: + * 1. el_uikit_set_args() forwards argc/argv to UIApplicationMain. + * 2. el_main_entry_fn is set to el_app_boot (defined below) before + * UIApplicationMain is entered. + * 3. ElAppDelegate.didFinishLaunchingWithOptions calls el_main_entry_fn(), + * which runs the el program's widget setup at the correct lifecycle point. + * 4. __native_run_loop() inside the compiled el main is a no-op on iOS — + * UIApplicationMain already owns the run loop. + * + * The generated native_hello.c exports el_app_main() (renamed from main by + * the gen step in build.sh). We call it from el_app_boot so it runs after + * UIApplicationMain sets up the application object. + * + * Compile with -fno-objc-arc (required by el_uikit.m). + */ + +#import + +/* From el_uikit.m */ +void el_uikit_set_args(int argc, char **argv); +extern void (*el_main_entry_fn)(void); + +/* Forward declaration of the renamed compiled el main. */ +int el_app_main(int argc, char **argv); + +/* Boot function registered as el_main_entry_fn. Called by ElAppDelegate + * inside didFinishLaunchingWithOptions on the main thread. */ +static void el_app_boot(void) { + char *argv[] = {"el-app", NULL}; + el_app_main(1, argv); +} + +int main(int argc, char *argv[]) { + el_uikit_set_args(argc, argv); + /* Register the boot function so ElAppDelegate can call it. */ + el_main_entry_fn = el_app_boot; + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, @"ElAppDelegate"); + } +} diff --git a/ui/examples/native-hello-ios/NativeHello/native_hello.c b/ui/examples/native-hello-ios/NativeHello/native_hello.c new file mode 100644 index 0000000..e18f274 --- /dev/null +++ b/ui/examples/native-hello-ios/NativeHello/native_hello.c @@ -0,0 +1,123 @@ +#include +#include +#include "el_runtime.h" + +el_val_t on_greet_click(el_val_t widget, el_val_t data); +el_val_t on_counter_click(el_val_t widget, el_val_t data); +el_val_t on_name_change(el_val_t widget, el_val_t data); +el_val_t app_build(el_val_t window); + +el_val_t g_window; +el_val_t g_label; +el_val_t g_input; +el_val_t g_button; +el_val_t g_counter; +el_val_t g_counter_lbl; +el_val_t manifest_env; +el_val_t manifest_path; +el_val_t win; +el_val_t g_window; + +el_val_t on_greet_click(el_val_t widget, el_val_t data) { + el_val_t name = widget_get_text(g_input); + el_val_t greeting = ({ el_val_t _if_result_1 = 0; if ((str_len(name) > 0)) { _if_result_1 = (el_str_concat(el_str_concat(EL_STR("Hello, "), name), EL_STR("!"))); } else { _if_result_1 = (EL_STR("Hello, World!")); } _if_result_1; }); + widget_set_text(g_label, greeting); + return 0; +} + +el_val_t on_counter_click(el_val_t widget, el_val_t data) { + el_val_t g_counter = (g_counter + 1); + widget_set_text(g_counter_lbl, el_str_concat(EL_STR("Clicks: "), int_to_str(g_counter))); + return 0; +} + +el_val_t on_name_change(el_val_t widget, el_val_t data) { + el_val_t has_text = (str_len(data) > 0); + widget_set_disabled(g_button, !has_text); + return 0; +} + +el_val_t app_build(el_val_t window) { + el_val_t root = vstack(0); + widget_set_padding_all(root, 24); + widget_set_bg_color_hex(root, EL_STR("#0f172a")); + widget_set_flex(root, 1); + el_val_t title = label(EL_STR("el-native \xe2\x80\x94 native widget demo")); + style_label_heading(title); + widget_add_child(root, title); + el_val_t gap1 = label(EL_STR("")); + widget_set_height(gap1, 16); + widget_add_child(root, gap1); + el_val_t subtitle = label(EL_STR("AppKit controls from el code, no ObjC in the app layer.")); + style_label_muted(subtitle); + widget_add_child(root, subtitle); + el_val_t gap2 = label(EL_STR("")); + widget_set_height(gap2, 24); + widget_add_child(root, gap2); + el_val_t input_row = hstack(8); + el_val_t name_label = label(EL_STR("Name:")); + style_label_body(name_label); + widget_set_width(name_label, 60); + el_val_t input = text_field(EL_STR("Enter your name\xe2\x80\xa6")); + style_label_body(input); + widget_set_flex(input, 1); + widget_on_change(input, EL_STR("on_name_change")); + el_val_t g_input = input; + el_val_t greet_btn = button(EL_STR("Greet")); + style_button_primary(greet_btn); + widget_set_disabled(greet_btn, 1); + widget_on_click(greet_btn, EL_STR("on_greet_click")); + el_val_t g_button = greet_btn; + widget_add_child(input_row, name_label); + widget_add_child(input_row, input); + widget_add_child(input_row, greet_btn); + widget_add_child(root, input_row); + el_val_t gap3 = label(EL_STR("")); + widget_set_height(gap3, 12); + widget_add_child(root, gap3); + el_val_t greeting = label(EL_STR("Waiting for name\xe2\x80\xa6")); + style_label_body(greeting); + widget_set_color_hex(greeting, EL_STR("#60a5fa")); + widget_set_font(greeting, EL_STR("system"), 16, 1); + el_val_t g_label = greeting; + widget_add_child(root, greeting); + el_val_t gap4 = label(EL_STR("")); + widget_set_height(gap4, 24); + widget_add_child(root, gap4); + el_val_t counter_row = hstack(12); + el_val_t counter_lbl = label(EL_STR("Clicks: 0")); + style_label_body(counter_lbl); + el_val_t g_counter_lbl = counter_lbl; + el_val_t counter_btn = button(EL_STR("Click me")); + style_button_primary(counter_btn); + widget_on_click(counter_btn, EL_STR("on_counter_click")); + widget_add_child(counter_row, counter_lbl); + widget_add_child(counter_row, counter_btn); + widget_add_child(root, counter_row); + widget_add_child(window, root); + return 0; +} + +int el_app_main(int _argc, char** _argv) { + el_runtime_init_args(_argc, _argv); + g_window = (-1); + g_label = (-1); + g_input = (-1); + g_button = (-1); + g_counter = 0; + g_counter_lbl = (-1); + native_init(); + manifest_env = env(EL_STR("EL_MANIFEST")); + manifest_path = ({ el_val_t _if_result_2 = 0; if ((str_len(manifest_env) > 0)) { _if_result_2 = (manifest_env); } else { _if_result_2 = (EL_STR("manifest.el")); } _if_result_2; }); + win = window_from_manifest(manifest_path); + g_window = win; + if (win < 0) { + println(EL_STR("Error: failed to create window. Is EL_TARGET_MACOS defined?")); + exit_program(1); + } + app_build(win); + window_show(win); + native_run_loop(); + return 0; +} + diff --git a/ui/examples/native-hello-ios/build.sh b/ui/examples/native-hello-ios/build.sh new file mode 100755 index 0000000..3c1d92d --- /dev/null +++ b/ui/examples/native-hello-ios/build.sh @@ -0,0 +1,136 @@ +#!/usr/bin/env bash +# build.sh — Build and install native-hello-ios to the iOS Simulator. +# +# Usage: +# ./build.sh # gen C sources + xcodebuild for simulator +# ./build.sh gen # regenerate C sources only +# ./build.sh build # xcodebuild only (skip elc step) +# ./build.sh install # gen + build + boot simulator + install + launch +# ./build.sh clean # remove build/ directory +# +# Requirements: +# - Xcode with iOS Simulator SDK installed +# - elc at ../../../lang/dist/platform/elc (or in PATH) + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +EL_LANG_ROOT="${SCRIPT_DIR}/../../../lang" +EL_UI_ROOT="${SCRIPT_DIR}/../.." +EL_RUNTIME="${EL_LANG_ROOT}/el-compiler/runtime" +EL_NATIVE_VESSEL="${EL_UI_ROOT}/vessels/el-native/src/main.el" +EL_APP_ENTRY="${EL_UI_ROOT}/examples/native-hello/src/main.el" +EL_MANIFEST="${EL_UI_ROOT}/examples/native-hello/manifest.el" +SOURCES_DIR="${SCRIPT_DIR}/NativeHello" +BUILD_DIR="${SCRIPT_DIR}/build" + +# Locate elc. +if command -v elc &>/dev/null; then + ELC="elc" +elif [ -x "${EL_LANG_ROOT}/dist/platform/elc" ]; then + ELC="${EL_LANG_ROOT}/dist/platform/elc" +else + echo "Error: elc not found. Add it to PATH or place it at:" + echo " ${EL_LANG_ROOT}/dist/platform/elc" + exit 1 +fi + +gen() { + echo "==> Generating native_hello.c..." + EL_MANIFEST="${EL_MANIFEST}" \ + "${ELC}" "${EL_APP_ENTRY}" \ + > "${SOURCES_DIR}/native_hello.c" + # Rename the compiled el main() to el_app_main so it doesn't conflict with + # main.m's main(). main.m's main() is the real entry point for UIApplicationMain. + # Use a simple sed substitution on the exact signature elc emits. + sed -i '' 's/^int main(int _argc, char\*\* _argv) {/int el_app_main(int _argc, char** _argv) {/' \ + "${SOURCES_DIR}/native_hello.c" + + echo "==> Generating el_native_vessel.c..." + "${ELC}" "${EL_NATIVE_VESSEL}" \ + > "${SOURCES_DIR}/el_native_vessel.c" + # Rename vessel main() similarly. + sed -i '' 's/^int main(int _argc, char\*\* _argv) {/int el_vessel_main(int _argc, char** _argv) {/' \ + "${SOURCES_DIR}/el_native_vessel.c" + + echo "==> Copying runtime files..." + cp "${EL_RUNTIME}/el_uikit.m" "${SOURCES_DIR}/" + cp "${EL_RUNTIME}/el_seed.c" "${SOURCES_DIR}/" + cp "${EL_RUNTIME}/el_runtime.c" "${SOURCES_DIR}/" + cp "${EL_RUNTIME}/el_runtime.h" "${SOURCES_DIR}/" + cp "${EL_RUNTIME}/el_native_target.h" "${SOURCES_DIR}/" + + echo "==> Source generation complete." +} + +xcode_build() { + echo "==> Building with xcodebuild (iphonesimulator)..." + xcodebuild \ + -project "${SCRIPT_DIR}/NativeHello.xcodeproj" \ + -scheme NativeHello \ + -sdk iphonesimulator \ + -configuration Debug \ + -derivedDataPath "${BUILD_DIR}" \ + CLANG_ENABLE_OBJC_ARC=NO \ + OTHER_CFLAGS="-DEL_TARGET_IOS" \ + OTHER_LDFLAGS="-ldl" \ + build + + APP_PATH=$(find "${BUILD_DIR}" -name "NativeHello.app" -maxdepth 6 | head -1) + if [ -n "${APP_PATH}" ]; then + echo "==> Build complete." + echo " App bundle: ${APP_PATH}" + else + echo "==> Build complete (app bundle in ${BUILD_DIR})." + fi +} + +install_and_launch() { + gen + xcode_build + + APP_PATH=$(find "${BUILD_DIR}" -name "NativeHello.app" -maxdepth 6 | head -1) + if [ -z "${APP_PATH}" ]; then + echo "Error: could not find NativeHello.app in ${BUILD_DIR}" + exit 1 + fi + + # Boot the default simulator if not already booted. + SIM_UDID=$(xcrun simctl list devices available --json \ + | python3 -c " +import json,sys +d=json.load(sys.stdin)['devices'] +for runtime,devs in d.items(): + for dev in devs: + if 'iPhone' in dev['name'] and dev['isAvailable']: + print(dev['udid']) + exit() +") + if [ -z "${SIM_UDID}" ]; then + echo "Error: no available iPhone simulator found." + exit 1 + fi + echo "==> Using simulator: ${SIM_UDID}" + xcrun simctl boot "${SIM_UDID}" 2>/dev/null || true + open -a Simulator + + echo "==> Installing app..." + xcrun simctl install "${SIM_UDID}" "${APP_PATH}" + + echo "==> Launching app..." + xcrun simctl launch "${SIM_UDID}" "ai.neurontechnologies.el.nativehello" +} + +clean() { + echo "==> Cleaning..." + rm -rf "${BUILD_DIR}" + echo "==> Clean complete." +} + +case "${1:-all}" in + gen) gen ;; + build) xcode_build ;; + install) install_and_launch ;; + clean) clean ;; + all|*) gen && xcode_build ;; +esac diff --git a/ui/examples/native-hello/-o b/ui/examples/native-hello/-o new file mode 100644 index 0000000..e69de29 diff --git a/ui/examples/native-hello/Dockerfile.linux-gtk4 b/ui/examples/native-hello/Dockerfile.linux-gtk4 new file mode 100644 index 0000000..2079162 --- /dev/null +++ b/ui/examples/native-hello/Dockerfile.linux-gtk4 @@ -0,0 +1,88 @@ +FROM ubuntu:22.04 + +RUN apt-get update && apt-get install -y \ + build-essential \ + libgtk-4-dev \ + pkg-config \ + libcurl4-openssl-dev \ + binutils \ + file \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /build + +# All sources arrive in /build — runtime/ subdirectory contains the el runtime, +# top-level contains elc-generated app/vessel C files. +COPY runtime/ runtime/ +COPY el_native_vessel.c el_native_vessel.h native_hello.c ./ + +# Compile el_gtk4.c +RUN gcc -DEL_TARGET_LINUX $(pkg-config --cflags gtk4) \ + -std=c11 -I/build/runtime \ + -c /build/runtime/el_gtk4.c -o /build/el_gtk4.o && \ + echo "el_gtk4.c compiled OK" + +# Compile el_seed.c +RUN gcc -DEL_TARGET_LINUX $(pkg-config --cflags gtk4) \ + -std=c11 -I/build/runtime \ + -c /build/runtime/el_seed.c -o /build/el_seed.o && \ + echo "el_seed.c compiled OK" + +# Compile el_runtime.c +RUN gcc -std=c11 -I/build/runtime \ + -c /build/runtime/el_runtime.c -o /build/el_runtime.o && \ + echo "el_runtime.c compiled OK" + +# Patch el_runtime.o: hide __-prefixed symbols that el_seed.o also defines. +# This is the Linux objcopy equivalent of macOS nmedit -s. +# el_seed.o is canonical for all __ symbols; el_runtime.o provides high-level +# builtins (str_len, json_get_string, etc.) that el_seed.o does NOT export. +RUN nm /build/el_seed.o | awk '/[0-9a-f]+ T /{print $3}' | sort > /build/.seed_T.txt && \ + nm /build/el_runtime.o | awk '/[0-9a-f]+ T /{print $3}' | sort > /build/.rt_T.txt && \ + comm -12 /build/.seed_T.txt /build/.rt_T.txt > /build/.dups.txt && \ + if [ -s /build/.dups.txt ]; then \ + ARGS=$(awk '{printf "--localize-symbol=%s ", $1}' /build/.dups.txt); \ + eval "objcopy $ARGS /build/el_runtime.o"; \ + echo "Patched $(wc -l < /build/.dups.txt) duplicate symbols in el_runtime.o"; \ + else \ + echo "No duplicate symbols found"; \ + fi + +# Compile vessel +RUN gcc -DEL_TARGET_LINUX -std=c11 -I/build/runtime \ + -include /build/runtime/el_native_target.h \ + -c /build/el_native_vessel.c -o /build/el_native_vessel.o && \ + echo "vessel compiled OK" + +# Compile app (before patching vessel, so we know which symbols to localise) +RUN gcc -DEL_TARGET_LINUX -std=c11 -I/build/runtime \ + -include /build/runtime/el_native_target.h \ + -include /build/el_native_vessel.h \ + -c /build/native_hello.c -o /build/native_hello.o && \ + echo "app compiled OK" + +# Patch el_native_vessel.o: +# 1. Localise main() so it doesn't conflict with the app's main. +# 2. Localise any T/B symbols the app also defines (elc emits shared globals +# like TOKEN_PRIMARY in every translation unit; GNU ld rejects duplicates +# unlike macOS ld which picks the first one silently). +RUN nm /build/native_hello.o | awk '/[0-9a-f]+ [TBb] /{print $3}' | sort > /build/.app_syms.txt && \ + nm /build/el_native_vessel.o | awk '/[0-9a-f]+ [TBb] /{print $3}' | sort > /build/.vessel_syms.txt && \ + comm -12 /build/.app_syms.txt /build/.vessel_syms.txt > /build/.vessel_dups.txt && \ + echo "main" >> /build/.vessel_dups.txt && \ + sort -u /build/.vessel_dups.txt -o /build/.vessel_dups.txt && \ + ARGS=$(awk '{printf "--localize-symbol=%s ", $1}' /build/.vessel_dups.txt) && \ + eval "objcopy $ARGS /build/el_native_vessel.o" && \ + echo "Patched $(wc -l < /build/.vessel_dups.txt) symbols in el_native_vessel.o" + +# Link — add -lm for math functions (exp, log, etc.) used by el_runtime.c +RUN gcc \ + /build/native_hello.o \ + /build/el_native_vessel.o \ + /build/el_gtk4.o \ + /build/el_runtime.o \ + /build/el_seed.o \ + $(pkg-config --libs gtk4) -ldl -lpthread -lcurl -lm \ + -o /build/native-hello-linux && \ + echo "==> Linked: native-hello-linux" && \ + file /build/native-hello-linux diff --git a/ui/examples/native-hello/Dockerfile.pi b/ui/examples/native-hello/Dockerfile.pi new file mode 100644 index 0000000..a4a30a2 --- /dev/null +++ b/ui/examples/native-hello/Dockerfile.pi @@ -0,0 +1,99 @@ +FROM --platform=linux/arm64 ubuntu:22.04 + +# GTK4 + SDL2 for Raspberry Pi (ARM64 / aarch64) +# Targets Pi 3 / 4 / 5 running 64-bit Raspberry Pi OS or Ubuntu 22.04. +# +# GTK4 requires a desktop environment / Wayland compositor at runtime. +# SDL2 works on bare framebuffer or KMS/DRM without a full desktop. +# +# Usage: +# docker build --platform linux/arm64 \ +# -f Dockerfile.pi --tag el-native-pi-arm64 ./build-docker/ +# docker create --name pi-extract el-native-pi-arm64 +# docker cp pi-extract:/build/native-hello-linux-pi ./build/native-hello-pi-arm64 +# docker rm pi-extract +# +# The GTK4 build is the default. SDL2 is available as an alternative +# for headless / bare-metal Pi deployments. + +RUN apt-get update && apt-get install -y \ + build-essential \ + libgtk-4-dev \ + libsdl2-dev \ + libsdl2-ttf-dev \ + libsdl2-image-dev \ + pkg-config \ + libcurl4-openssl-dev \ + binutils \ + file \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /build + +# All sources arrive in /build +COPY runtime/ runtime/ +COPY el_native_vessel.c el_native_vessel.h native_hello.c ./ + +# ── GTK4 build ──────────────────────────────────────────────────────────────── + +# Compile el_gtk4.c +RUN gcc -DEL_TARGET_LINUX $(pkg-config --cflags gtk4) \ + -std=c11 -I/build/runtime \ + -c /build/runtime/el_gtk4.c -o /build/el_gtk4.o && \ + echo "el_gtk4.c compiled OK" + +# Compile el_seed.c +RUN gcc -DEL_TARGET_LINUX $(pkg-config --cflags gtk4) \ + -std=c11 -I/build/runtime \ + -c /build/runtime/el_seed.c -o /build/el_seed.o && \ + echo "el_seed.c compiled OK" + +# Compile el_runtime.c +RUN gcc -std=c11 -I/build/runtime \ + -c /build/runtime/el_runtime.c -o /build/el_runtime.o && \ + echo "el_runtime.c compiled OK" + +# Patch el_runtime.o: localise __-prefixed duplicate symbols (el_seed.o is canonical) +RUN nm /build/el_seed.o | awk '/[0-9a-f]+ T /{print $3}' | sort > /build/.seed_T.txt && \ + nm /build/el_runtime.o | awk '/[0-9a-f]+ T /{print $3}' | sort > /build/.rt_T.txt && \ + comm -12 /build/.seed_T.txt /build/.rt_T.txt > /build/.dups.txt && \ + if [ -s /build/.dups.txt ]; then \ + ARGS=$(awk '{printf "--localize-symbol=%s ", $1}' /build/.dups.txt); \ + eval "objcopy $ARGS /build/el_runtime.o"; \ + echo "Patched $(wc -l < /build/.dups.txt) duplicate symbols in el_runtime.o"; \ + fi + +# Compile vessel +RUN gcc -DEL_TARGET_LINUX -std=c11 -I/build/runtime \ + -include /build/runtime/el_native_target.h \ + -c /build/el_native_vessel.c -o /build/el_native_vessel.o && \ + echo "vessel compiled OK" + +# Compile app +RUN gcc -DEL_TARGET_LINUX -std=c11 -I/build/runtime \ + -include /build/runtime/el_native_target.h \ + -include /build/el_native_vessel.h \ + -c /build/native_hello.c -o /build/native_hello.o && \ + echo "app compiled OK" + +# Patch el_native_vessel.o: localise shared globals (main + TOKEN_* etc.) +RUN nm /build/native_hello.o | awk '/[0-9a-f]+ [TBb] /{print $3}' | sort > /build/.app_syms.txt && \ + nm /build/el_native_vessel.o | awk '/[0-9a-f]+ [TBb] /{print $3}' | sort > /build/.vessel_syms.txt && \ + comm -12 /build/.app_syms.txt /build/.vessel_syms.txt > /build/.vessel_dups.txt && \ + echo "main" >> /build/.vessel_dups.txt && \ + sort -u /build/.vessel_dups.txt -o /build/.vessel_dups.txt && \ + ARGS=$(awk '{printf "--localize-symbol=%s ", $1}' /build/.vessel_dups.txt) && \ + eval "objcopy $ARGS /build/el_native_vessel.o" && \ + echo "Patched $(wc -l < /build/.vessel_dups.txt) symbols in el_native_vessel.o" + +# Link (GTK4) +RUN gcc \ + /build/native_hello.o \ + /build/el_native_vessel.o \ + /build/el_gtk4.o \ + /build/el_runtime.o \ + /build/el_seed.o \ + $(pkg-config --libs gtk4) -ldl -lpthread -lcurl -lm \ + -o /build/native-hello-linux-pi && \ + echo "==> Linked: native-hello-linux-pi (GTK4)" && \ + file /build/native-hello-linux-pi diff --git a/ui/examples/native-hello/build-docker/el_native_vessel.c b/ui/examples/native-hello/build-docker/el_native_vessel.c new file mode 100644 index 0000000..28bf38c --- /dev/null +++ b/ui/examples/native-hello/build-docker/el_native_vessel.c @@ -0,0 +1,459 @@ +#include +#include +#include "el_runtime.h" + +el_val_t native_init(void); +el_val_t native_run_loop(void); +el_val_t manifest_read(el_val_t path); +el_val_t manifest_title(el_val_t m); +el_val_t manifest_width(el_val_t m); +el_val_t manifest_height(el_val_t m); +el_val_t manifest_min_width(el_val_t m); +el_val_t manifest_min_height(el_val_t m); +el_val_t window_create(el_val_t title, el_val_t width, el_val_t height, el_val_t min_width, el_val_t min_height); +el_val_t window_from_manifest(el_val_t manifest_path); +el_val_t window_show(el_val_t handle); +el_val_t window_set_title(el_val_t handle, el_val_t title); +el_val_t vstack(el_val_t spacing); +el_val_t vstack_tight(void); +el_val_t hstack(el_val_t spacing); +el_val_t zstack(void); +el_val_t scroll(void); +el_val_t label(el_val_t text); +el_val_t button(el_val_t label); +el_val_t text_field(el_val_t placeholder); +el_val_t text_area(el_val_t placeholder); +el_val_t image(el_val_t path_or_name); +el_val_t widget_set_text(el_val_t handle, el_val_t text); +el_val_t widget_get_text(el_val_t handle); +el_val_t widget_set_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_font(el_val_t handle, el_val_t family, el_val_t size, el_val_t bold); +el_val_t widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, el_val_t bottom, el_val_t left); +el_val_t widget_set_padding_all(el_val_t handle, el_val_t p); +el_val_t widget_set_padding_xy(el_val_t handle, el_val_t px, el_val_t py); +el_val_t widget_set_width(el_val_t handle, el_val_t width); +el_val_t widget_set_height(el_val_t handle, el_val_t height); +el_val_t widget_set_flex(el_val_t handle, el_val_t flex); +el_val_t widget_set_corner_radius(el_val_t handle, el_val_t radius); +el_val_t widget_set_disabled(el_val_t handle, el_val_t disabled); +el_val_t widget_set_hidden(el_val_t handle, el_val_t hidden); +el_val_t widget_add_child(el_val_t parent, el_val_t child); +el_val_t widget_remove_child(el_val_t parent, el_val_t child); +el_val_t widget_destroy(el_val_t handle); +el_val_t widget_on_click(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_change(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_submit(el_val_t handle, el_val_t fn_name); +el_val_t hex_channel(el_val_t s, el_val_t offset); +el_val_t hex_nibble(el_val_t c); +el_val_t color_hex_r(el_val_t hex); +el_val_t color_hex_g(el_val_t hex); +el_val_t color_hex_b(el_val_t hex); +el_val_t color_hex_a(el_val_t hex); +el_val_t widget_set_color_hex(el_val_t handle, el_val_t hex); +el_val_t widget_set_bg_color_hex(el_val_t handle, el_val_t hex); +el_val_t style_surface(el_val_t handle); +el_val_t style_button_primary(el_val_t handle); +el_val_t style_label_body(el_val_t handle); +el_val_t style_label_heading(el_val_t handle); +el_val_t style_label_muted(el_val_t handle); + +el_val_t TOKEN_PRIMARY; +el_val_t TOKEN_ON_PRIMARY; +el_val_t TOKEN_BACKGROUND; +el_val_t TOKEN_ON_BG; +el_val_t TOKEN_SURFACE; +el_val_t TOKEN_ON_SURFACE; +el_val_t TOKEN_OUTLINE; +el_val_t TOKEN_ERROR; + +el_val_t native_init(void) { + __native_init(); + return 0; +} + +el_val_t native_run_loop(void) { + __native_run_loop(); + return 0; +} + +el_val_t manifest_read(el_val_t path) { + return __manifest_read(path); + return 0; +} + +el_val_t manifest_title(el_val_t m) { + return json_get_string(m, EL_STR("title")); + return 0; +} + +el_val_t manifest_width(el_val_t m) { + return json_get_int(m, EL_STR("width")); + return 0; +} + +el_val_t manifest_height(el_val_t m) { + return json_get_int(m, EL_STR("height")); + return 0; +} + +el_val_t manifest_min_width(el_val_t m) { + return json_get_int(m, EL_STR("min_width")); + return 0; +} + +el_val_t manifest_min_height(el_val_t m) { + return json_get_int(m, EL_STR("min_height")); + return 0; +} + +el_val_t window_create(el_val_t title, el_val_t width, el_val_t height, el_val_t min_width, el_val_t min_height) { + return __window_create(title, width, height, min_width, min_height); + return 0; +} + +el_val_t window_from_manifest(el_val_t manifest_path) { + el_val_t m = manifest_read(manifest_path); + el_val_t title = manifest_title(m); + el_val_t w = manifest_width(m); + el_val_t h = manifest_height(m); + el_val_t mw = manifest_min_width(m); + el_val_t mh = manifest_min_height(m); + el_val_t safe_w = ({ el_val_t _if_result_1 = 0; if ((w > 0)) { _if_result_1 = (w); } else { _if_result_1 = (1200); } _if_result_1; }); + el_val_t safe_h = ({ el_val_t _if_result_2 = 0; if ((h > 0)) { _if_result_2 = (h); } else { _if_result_2 = (800); } _if_result_2; }); + el_val_t safe_mw = ({ el_val_t _if_result_3 = 0; if ((mw > 0)) { _if_result_3 = (mw); } else { _if_result_3 = (600); } _if_result_3; }); + el_val_t safe_mh = ({ el_val_t _if_result_4 = 0; if ((mh > 0)) { _if_result_4 = (mh); } else { _if_result_4 = (400); } _if_result_4; }); + el_val_t safe_t = ({ el_val_t _if_result_5 = 0; if ((str_len(title) > 0)) { _if_result_5 = (title); } else { _if_result_5 = (EL_STR("App")); } _if_result_5; }); + return window_create(safe_t, safe_w, safe_h, safe_mw, safe_mh); + return 0; +} + +el_val_t window_show(el_val_t handle) { + __window_show(handle); + return 0; +} + +el_val_t window_set_title(el_val_t handle, el_val_t title) { + __window_set_title(handle, title); + return 0; +} + +el_val_t vstack(el_val_t spacing) { + return __vstack_create(spacing); + return 0; +} + +el_val_t vstack_tight(void) { + return __vstack_create(0); + return 0; +} + +el_val_t hstack(el_val_t spacing) { + return __hstack_create(spacing); + return 0; +} + +el_val_t zstack(void) { + return __zstack_create(); + return 0; +} + +el_val_t scroll(void) { + return __scroll_create(); + return 0; +} + +el_val_t label(el_val_t text) { + return __label_create(text); + return 0; +} + +el_val_t button(el_val_t label) { + return __button_create(label); + return 0; +} + +el_val_t text_field(el_val_t placeholder) { + return __text_field_create(placeholder); + return 0; +} + +el_val_t text_area(el_val_t placeholder) { + return __text_area_create(placeholder); + return 0; +} + +el_val_t image(el_val_t path_or_name) { + return __image_create(path_or_name); + return 0; +} + +el_val_t widget_set_text(el_val_t handle, el_val_t text) { + __widget_set_text(handle, text); + return 0; +} + +el_val_t widget_get_text(el_val_t handle) { + return __widget_get_text(handle); + return 0; +} + +el_val_t widget_set_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + __widget_set_color(handle, r, g, b, a); + return 0; +} + +el_val_t widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + __widget_set_bg_color(handle, r, g, b, a); + return 0; +} + +el_val_t widget_set_font(el_val_t handle, el_val_t family, el_val_t size, el_val_t bold) { + el_val_t bold_int = ({ el_val_t _if_result_6 = 0; if (bold) { _if_result_6 = (1); } else { _if_result_6 = (0); } _if_result_6; }); + __widget_set_font(handle, family, size, bold_int); + return 0; +} + +el_val_t widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, el_val_t bottom, el_val_t left) { + __widget_set_padding(handle, top, right, bottom, left); + return 0; +} + +el_val_t widget_set_padding_all(el_val_t handle, el_val_t p) { + __widget_set_padding(handle, p, p, p, p); + return 0; +} + +el_val_t widget_set_padding_xy(el_val_t handle, el_val_t px, el_val_t py) { + __widget_set_padding(handle, py, px, py, px); + return 0; +} + +el_val_t widget_set_width(el_val_t handle, el_val_t width) { + __widget_set_width(handle, width); + return 0; +} + +el_val_t widget_set_height(el_val_t handle, el_val_t height) { + __widget_set_height(handle, height); + return 0; +} + +el_val_t widget_set_flex(el_val_t handle, el_val_t flex) { + __widget_set_flex(handle, flex); + return 0; +} + +el_val_t widget_set_corner_radius(el_val_t handle, el_val_t radius) { + __widget_set_corner_radius(handle, radius); + return 0; +} + +el_val_t widget_set_disabled(el_val_t handle, el_val_t disabled) { + el_val_t d = ({ el_val_t _if_result_7 = 0; if (disabled) { _if_result_7 = (1); } else { _if_result_7 = (0); } _if_result_7; }); + __widget_set_disabled(handle, d); + return 0; +} + +el_val_t widget_set_hidden(el_val_t handle, el_val_t hidden) { + el_val_t h = ({ el_val_t _if_result_8 = 0; if (hidden) { _if_result_8 = (1); } else { _if_result_8 = (0); } _if_result_8; }); + __widget_set_hidden(handle, h); + return 0; +} + +el_val_t widget_add_child(el_val_t parent, el_val_t child) { + __widget_add_child(parent, child); + return 0; +} + +el_val_t widget_remove_child(el_val_t parent, el_val_t child) { + __widget_remove_child(parent, child); + return 0; +} + +el_val_t widget_destroy(el_val_t handle) { + __widget_destroy(handle); + return 0; +} + +el_val_t widget_on_click(el_val_t handle, el_val_t fn_name) { + __widget_on_click(handle, fn_name); + return 0; +} + +el_val_t widget_on_change(el_val_t handle, el_val_t fn_name) { + __widget_on_change(handle, fn_name); + return 0; +} + +el_val_t widget_on_submit(el_val_t handle, el_val_t fn_name) { + __widget_on_submit(handle, fn_name); + return 0; +} + +el_val_t hex_channel(el_val_t s, el_val_t offset) { + el_val_t hi = str_slice(s, offset, (offset + 1)); + el_val_t lo = str_slice(s, (offset + 1), (offset + 2)); + el_val_t h = hex_nibble(hi); + el_val_t l = hex_nibble(lo); + return ((h * 16) + l); + return 0; +} + +el_val_t hex_nibble(el_val_t c) { + if (str_eq(c, EL_STR("0"))) { + return 0; + } + if (str_eq(c, EL_STR("1"))) { + return 1; + } + if (str_eq(c, EL_STR("2"))) { + return 2; + } + if (str_eq(c, EL_STR("3"))) { + return 3; + } + if (str_eq(c, EL_STR("4"))) { + return 4; + } + if (str_eq(c, EL_STR("5"))) { + return 5; + } + if (str_eq(c, EL_STR("6"))) { + return 6; + } + if (str_eq(c, EL_STR("7"))) { + return 7; + } + if (str_eq(c, EL_STR("8"))) { + return 8; + } + if (str_eq(c, EL_STR("9"))) { + return 9; + } + if (str_eq(c, EL_STR("a"))) { + return 10; + } + if (str_eq(c, EL_STR("b"))) { + return 11; + } + if (str_eq(c, EL_STR("c"))) { + return 12; + } + if (str_eq(c, EL_STR("d"))) { + return 13; + } + if (str_eq(c, EL_STR("e"))) { + return 14; + } + if (str_eq(c, EL_STR("f"))) { + return 15; + } + if (str_eq(c, EL_STR("A"))) { + return 10; + } + if (str_eq(c, EL_STR("B"))) { + return 11; + } + if (str_eq(c, EL_STR("C"))) { + return 12; + } + if (str_eq(c, EL_STR("D"))) { + return 13; + } + if (str_eq(c, EL_STR("E"))) { + return 14; + } + if (str_eq(c, EL_STR("F"))) { + return 15; + } + return 0; + return 0; +} + +el_val_t color_hex_r(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_9 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_9 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_9 = (hex); } _if_result_9; }); + el_val_t v = hex_channel(s, 0); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_g(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_10 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_10 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_10 = (hex); } _if_result_10; }); + el_val_t v = hex_channel(s, 2); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_b(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_11 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_11 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_11 = (hex); } _if_result_11; }); + el_val_t v = hex_channel(s, 4); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_a(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_12 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_12 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_12 = (hex); } _if_result_12; }); + if (str_len(s) < 8) { + return el_from_float(1.0); + } + el_val_t v = hex_channel(s, 6); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t widget_set_color_hex(el_val_t handle, el_val_t hex) { + widget_set_color(handle, color_hex_r(hex), color_hex_g(hex), color_hex_b(hex), color_hex_a(hex)); + return 0; +} + +el_val_t widget_set_bg_color_hex(el_val_t handle, el_val_t hex) { + widget_set_bg_color(handle, color_hex_r(hex), color_hex_g(hex), color_hex_b(hex), color_hex_a(hex)); + return 0; +} + +el_val_t style_surface(el_val_t handle) { + widget_set_bg_color_hex(handle, TOKEN_SURFACE); + widget_set_corner_radius(handle, 8); + return 0; +} + +el_val_t style_button_primary(el_val_t handle) { + widget_set_bg_color_hex(handle, TOKEN_PRIMARY); + widget_set_color_hex(handle, TOKEN_ON_PRIMARY); + widget_set_corner_radius(handle, 8); + widget_set_padding_xy(handle, 16, 8); + return 0; +} + +el_val_t style_label_body(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_ON_BG); + widget_set_font(handle, EL_STR("system"), 14, 0); + return 0; +} + +el_val_t style_label_heading(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_ON_BG); + widget_set_font(handle, EL_STR("system"), 20, 1); + return 0; +} + +el_val_t style_label_muted(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_OUTLINE); + widget_set_font(handle, EL_STR("system"), 12, 0); + return 0; +} + +int main(int _argc, char** _argv) { + el_runtime_init_args(_argc, _argv); + TOKEN_PRIMARY = EL_STR("#60a5fa"); + TOKEN_ON_PRIMARY = EL_STR("#0f172a"); + TOKEN_BACKGROUND = EL_STR("#0f172a"); + TOKEN_ON_BG = EL_STR("#f8fafc"); + TOKEN_SURFACE = EL_STR("#1e293b"); + TOKEN_ON_SURFACE = EL_STR("#f8fafc"); + TOKEN_OUTLINE = EL_STR("#475569"); + TOKEN_ERROR = EL_STR("#f87171"); + return 0; +} + diff --git a/ui/examples/native-hello/build-docker/el_native_vessel.h b/ui/examples/native-hello/build-docker/el_native_vessel.h new file mode 100644 index 0000000..b62c288 --- /dev/null +++ b/ui/examples/native-hello/build-docker/el_native_vessel.h @@ -0,0 +1,69 @@ +#include +#include +#include "el_runtime.h" + +el_val_t native_init(void); +el_val_t native_run_loop(void); +el_val_t manifest_read(el_val_t path); +el_val_t manifest_title(el_val_t m); +el_val_t manifest_width(el_val_t m); +el_val_t manifest_height(el_val_t m); +el_val_t manifest_min_width(el_val_t m); +el_val_t manifest_min_height(el_val_t m); +el_val_t window_create(el_val_t title, el_val_t width, el_val_t height, el_val_t min_width, el_val_t min_height); +el_val_t window_from_manifest(el_val_t manifest_path); +el_val_t window_show(el_val_t handle); +el_val_t window_set_title(el_val_t handle, el_val_t title); +el_val_t vstack(el_val_t spacing); +el_val_t vstack_tight(void); +el_val_t hstack(el_val_t spacing); +el_val_t zstack(void); +el_val_t scroll(void); +el_val_t label(el_val_t text); +el_val_t button(el_val_t label); +el_val_t text_field(el_val_t placeholder); +el_val_t text_area(el_val_t placeholder); +el_val_t image(el_val_t path_or_name); +el_val_t widget_set_text(el_val_t handle, el_val_t text); +el_val_t widget_get_text(el_val_t handle); +el_val_t widget_set_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_font(el_val_t handle, el_val_t family, el_val_t size, el_val_t bold); +el_val_t widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, el_val_t bottom, el_val_t left); +el_val_t widget_set_padding_all(el_val_t handle, el_val_t p); +el_val_t widget_set_padding_xy(el_val_t handle, el_val_t px, el_val_t py); +el_val_t widget_set_width(el_val_t handle, el_val_t width); +el_val_t widget_set_height(el_val_t handle, el_val_t height); +el_val_t widget_set_flex(el_val_t handle, el_val_t flex); +el_val_t widget_set_corner_radius(el_val_t handle, el_val_t radius); +el_val_t widget_set_disabled(el_val_t handle, el_val_t disabled); +el_val_t widget_set_hidden(el_val_t handle, el_val_t hidden); +el_val_t widget_add_child(el_val_t parent, el_val_t child); +el_val_t widget_remove_child(el_val_t parent, el_val_t child); +el_val_t widget_destroy(el_val_t handle); +el_val_t widget_on_click(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_change(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_submit(el_val_t handle, el_val_t fn_name); +el_val_t hex_channel(el_val_t s, el_val_t offset); +el_val_t hex_nibble(el_val_t c); +el_val_t color_hex_r(el_val_t hex); +el_val_t color_hex_g(el_val_t hex); +el_val_t color_hex_b(el_val_t hex); +el_val_t color_hex_a(el_val_t hex); +el_val_t widget_set_color_hex(el_val_t handle, el_val_t hex); +el_val_t widget_set_bg_color_hex(el_val_t handle, el_val_t hex); +el_val_t style_surface(el_val_t handle); +el_val_t style_button_primary(el_val_t handle); +el_val_t style_label_body(el_val_t handle); +el_val_t style_label_heading(el_val_t handle); +el_val_t style_label_muted(el_val_t handle); + +el_val_t TOKEN_PRIMARY; +el_val_t TOKEN_ON_PRIMARY; +el_val_t TOKEN_BACKGROUND; +el_val_t TOKEN_ON_BG; +el_val_t TOKEN_SURFACE; +el_val_t TOKEN_ON_SURFACE; +el_val_t TOKEN_OUTLINE; +el_val_t TOKEN_ERROR; + diff --git a/ui/examples/native-hello/build-docker/native_hello.c b/ui/examples/native-hello/build-docker/native_hello.c new file mode 100644 index 0000000..050d56a --- /dev/null +++ b/ui/examples/native-hello/build-docker/native_hello.c @@ -0,0 +1,123 @@ +#include +#include +#include "el_runtime.h" + +el_val_t on_greet_click(el_val_t widget, el_val_t data); +el_val_t on_counter_click(el_val_t widget, el_val_t data); +el_val_t on_name_change(el_val_t widget, el_val_t data); +el_val_t app_build(el_val_t window); + +el_val_t g_window; +el_val_t g_label; +el_val_t g_input; +el_val_t g_button; +el_val_t g_counter; +el_val_t g_counter_lbl; +el_val_t manifest_env; +el_val_t manifest_path; +el_val_t win; +el_val_t g_window; + +el_val_t on_greet_click(el_val_t widget, el_val_t data) { + el_val_t name = widget_get_text(g_input); + el_val_t greeting = ({ el_val_t _if_result_1 = 0; if ((str_len(name) > 0)) { _if_result_1 = (el_str_concat(el_str_concat(EL_STR("Hello, "), name), EL_STR("!"))); } else { _if_result_1 = (EL_STR("Hello, World!")); } _if_result_1; }); + widget_set_text(g_label, greeting); + return 0; +} + +el_val_t on_counter_click(el_val_t widget, el_val_t data) { + el_val_t g_counter = (g_counter + 1); + widget_set_text(g_counter_lbl, el_str_concat(EL_STR("Clicks: "), int_to_str(g_counter))); + return 0; +} + +el_val_t on_name_change(el_val_t widget, el_val_t data) { + el_val_t has_text = (str_len(data) > 0); + widget_set_disabled(g_button, !has_text); + return 0; +} + +el_val_t app_build(el_val_t window) { + el_val_t root = vstack(0); + widget_set_padding_all(root, 24); + widget_set_bg_color_hex(root, EL_STR("#0f172a")); + widget_set_flex(root, 1); + el_val_t title = label(EL_STR("el-native \xe2\x80\x94 native widget demo")); + style_label_heading(title); + widget_add_child(root, title); + el_val_t gap1 = label(EL_STR("")); + widget_set_height(gap1, 16); + widget_add_child(root, gap1); + el_val_t subtitle = label(EL_STR("AppKit controls from el code, no ObjC in the app layer.")); + style_label_muted(subtitle); + widget_add_child(root, subtitle); + el_val_t gap2 = label(EL_STR("")); + widget_set_height(gap2, 24); + widget_add_child(root, gap2); + el_val_t input_row = hstack(8); + el_val_t name_label = label(EL_STR("Name:")); + style_label_body(name_label); + widget_set_width(name_label, 60); + el_val_t input = text_field(EL_STR("Enter your name\xe2\x80\xa6")); + style_label_body(input); + widget_set_flex(input, 1); + widget_on_change(input, EL_STR("on_name_change")); + el_val_t g_input = input; + el_val_t greet_btn = button(EL_STR("Greet")); + style_button_primary(greet_btn); + widget_set_disabled(greet_btn, 1); + widget_on_click(greet_btn, EL_STR("on_greet_click")); + el_val_t g_button = greet_btn; + widget_add_child(input_row, name_label); + widget_add_child(input_row, input); + widget_add_child(input_row, greet_btn); + widget_add_child(root, input_row); + el_val_t gap3 = label(EL_STR("")); + widget_set_height(gap3, 12); + widget_add_child(root, gap3); + el_val_t greeting = label(EL_STR("Waiting for name\xe2\x80\xa6")); + style_label_body(greeting); + widget_set_color_hex(greeting, EL_STR("#60a5fa")); + widget_set_font(greeting, EL_STR("system"), 16, 1); + el_val_t g_label = greeting; + widget_add_child(root, greeting); + el_val_t gap4 = label(EL_STR("")); + widget_set_height(gap4, 24); + widget_add_child(root, gap4); + el_val_t counter_row = hstack(12); + el_val_t counter_lbl = label(EL_STR("Clicks: 0")); + style_label_body(counter_lbl); + el_val_t g_counter_lbl = counter_lbl; + el_val_t counter_btn = button(EL_STR("Click me")); + style_button_primary(counter_btn); + widget_on_click(counter_btn, EL_STR("on_counter_click")); + widget_add_child(counter_row, counter_lbl); + widget_add_child(counter_row, counter_btn); + widget_add_child(root, counter_row); + widget_add_child(window, root); + return 0; +} + +int main(int _argc, char** _argv) { + el_runtime_init_args(_argc, _argv); + g_window = (-1); + g_label = (-1); + g_input = (-1); + g_button = (-1); + g_counter = 0; + g_counter_lbl = (-1); + native_init(); + manifest_env = env(EL_STR("EL_MANIFEST")); + manifest_path = ({ el_val_t _if_result_2 = 0; if ((str_len(manifest_env) > 0)) { _if_result_2 = (manifest_env); } else { _if_result_2 = (EL_STR("manifest.el")); } _if_result_2; }); + win = window_from_manifest(manifest_path); + g_window = win; + if (win < 0) { + println(EL_STR("Error: failed to create window. Is EL_TARGET_MACOS defined?")); + exit_program(1); + } + app_build(win); + window_show(win); + native_run_loop(); + return 0; +} + diff --git a/ui/examples/native-hello/build-docker/runtime/el_gtk4.c b/ui/examples/native-hello/build-docker/runtime/el_gtk4.c new file mode 100644 index 0000000..1ae01d0 --- /dev/null +++ b/ui/examples/native-hello/build-docker/runtime/el_gtk4.c @@ -0,0 +1,1027 @@ +/* + * el_gtk4.c — GTK4 backend for the el native widget system (Linux). + * + * This file implements the Linux GTK4 widget layer that el_seed.c calls + * through to when EL_TARGET_LINUX is defined. + * + * Architecture: + * el program (el code) + * → __widget_* C builtins in el_seed.c + * → el_gtk4_* C-callable functions declared here + * → GtkWidget* / GtkWindow* via GTK4 C API + * + * Widget handles: every widget is assigned an int64_t slot index into + * _el_widgets[]. The el program holds these as opaque Int values. + * Slot 0 is never valid (reserved; invalid handle = -1 convention). + * + * Threading: GTK4 must run on the main thread. el_gtk4_sync_main() uses + * g_main_context_invoke_full() to dispatch from any thread, waiting for + * completion via a GMutex/GCond pair — the same role as dispatch_sync() in + * the AppKit bridge. + * + * Callback mechanism: on signal, the bridge calls + * dlsym(RTLD_DEFAULT, fn_name)(widget_handle, event_data_string) + * matching the el_appkit.m / __thread_create pattern in el_seed.c. + * + * Compile: + * gcc -DEL_TARGET_LINUX $(pkg-config --cflags gtk4) \ + * el_gtk4.c -c -o el_gtk4.o + * Then link el_gtk4.o alongside el_seed.c with: + * $(pkg-config --libs gtk4) -ldl + * + * GTK4 version notes: + * • gtk_widget_get_style_context() is deprecated in GTK 4.10+. + * A #if GTK_MINOR_VERSION guard selects the correct CSS-provider path. + * • gtk_editable_get_text() / gtk_editable_set_text() are the unified + * GTK4 text API for GtkEntry and any GtkEditable. + */ + +#ifdef EL_TARGET_LINUX + +/* _GNU_SOURCE: expose RTLD_DEFAULT (dlfcn.h) and strdup (string.h) on Linux. */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +/* G_APPLICATION_DEFAULT_FLAGS was added in GLib 2.74. + * Ubuntu 22.04 ships GLib 2.72 — use the older alias when running on it. */ +#ifndef G_APPLICATION_DEFAULT_FLAGS +#define G_APPLICATION_DEFAULT_FLAGS G_APPLICATION_FLAGS_NONE +#endif + +/* el_val_t must already be defined by el_runtime.h / el_seed.h. */ +#ifndef EL_VAL_T_DEFINED +typedef int64_t el_val_t; +#endif + +#ifndef EL_CSTR +#define EL_CSTR(v) ((const char*)(uintptr_t)(v)) +#endif +#ifndef EL_STR +#define EL_STR(s) ((el_val_t)(uintptr_t)(s)) +#endif + +/* ── Widget table ─────────────────────────────────────────────────────────── */ + +#define EL_GTK4_MAX_WIDGETS 4096 + +typedef enum { + EL_WIDGET_FREE = 0, + EL_WIDGET_WINDOW = 1, + EL_WIDGET_VSTACK = 2, + EL_WIDGET_HSTACK = 3, + EL_WIDGET_ZSTACK = 4, + EL_WIDGET_SCROLL = 5, + EL_WIDGET_LABEL = 6, + EL_WIDGET_BUTTON = 7, + EL_WIDGET_TEXTFIELD = 8, + EL_WIDGET_TEXTAREA = 9, + EL_WIDGET_IMAGE = 10, + EL_WIDGET_DIVIDER = 11, + EL_WIDGET_SPACER = 12, +} ElWidgetKind; + +typedef struct { + ElWidgetKind kind; + GtkWidget* widget; /* Strong reference (g_object_ref'd on alloc). */ + char* cb_click; /* El function name for click/submit events. */ + char* cb_change;/* El function name for value-change events. */ +} ElWidget; + +static ElWidget _el_widgets[EL_GTK4_MAX_WIDGETS]; +static int _el_widget_count = 0; + +/* Allocate a slot; returns slot index or -1 if full. Takes a strong ref. */ +static int64_t el_widget_alloc(ElWidgetKind kind, GtkWidget* w) { + for (int i = 1; i < EL_GTK4_MAX_WIDGETS; i++) { + if (_el_widgets[i].kind == EL_WIDGET_FREE) { + _el_widgets[i].kind = kind; + _el_widgets[i].widget = (GtkWidget*)g_object_ref(w); + _el_widgets[i].cb_click = NULL; + _el_widgets[i].cb_change = NULL; + if (i > _el_widget_count) _el_widget_count = i; + return (int64_t)i; + } + } + return -1; +} + +/* Look up a slot. Returns NULL for invalid/free handle. */ +static ElWidget* el_widget_get(int64_t handle) { + if (handle <= 0 || handle >= EL_GTK4_MAX_WIDGETS) return NULL; + if (_el_widgets[handle].kind == EL_WIDGET_FREE) return NULL; + return &_el_widgets[handle]; +} + +/* Release a slot. Unrefs the widget; callers must remove from parent first. */ +static void el_widget_free(int64_t handle) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + if (w->widget) { g_object_unref(w->widget); w->widget = NULL; } + w->kind = EL_WIDGET_FREE; + free(w->cb_click); w->cb_click = NULL; + free(w->cb_change); w->cb_change = NULL; +} + +/* Forward declaration — defined below in the GtkApplication globals section. */ +static int _el_app_running; + +/* ── CSS / styling helpers ────────────────────────────────────────────────── */ + +/* + * apply_css — attach a CSS snippet to a single widget with APPLICATION priority. + * GTK 4.10 deprecated gtk_widget_get_style_context(); use gtk_widget_add_css_class() + * + a display-level provider for new GTK, or the style-context path for older GTK. + * + * We use the style-context path behind a version guard because it reliably + * scopes the CSS to just this widget, which is what the el property setters + * need (each call replaces/adds to the widget's own stylesheet). + */ +static void apply_css(GtkWidget* widget, const char* css_str) { + if (!widget || !css_str) return; + GtkCssProvider* p = gtk_css_provider_new(); + +#if GTK_CHECK_VERSION(4, 12, 0) + /* GTK 4.12+: load_from_string takes a plain string (no length). */ + gtk_css_provider_load_from_string(p, css_str); +#else + gtk_css_provider_load_from_data(p, css_str, -1); +#endif + +#if GTK_MINOR_VERSION >= 10 + /* 4.10+: style context is deprecated; use display-scoped provider + css class. + * We add a unique widget name so the selector targets only this widget. */ + static guint64 _css_id_counter = 0; + char name_buf[32]; + snprintf(name_buf, sizeof(name_buf), "el-w-%" G_GUINT64_FORMAT, ++_css_id_counter); + gtk_widget_set_name(widget, name_buf); + + /* Wrap the CSS to scope to this widget's name. */ + char* scoped = NULL; + int n = asprintf(&scoped, "#%s { %s }", name_buf, css_str); + (void)n; + if (scoped) { + GtkCssProvider* sp = gtk_css_provider_new(); +#if GTK_CHECK_VERSION(4, 12, 0) + gtk_css_provider_load_from_string(sp, scoped); +#else + gtk_css_provider_load_from_data(sp, scoped, -1); +#endif + gtk_style_context_add_provider_for_display( + gtk_widget_get_display(widget), + GTK_STYLE_PROVIDER(sp), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_object_unref(sp); + free(scoped); + } + g_object_unref(p); +#else + /* GTK < 4.10: style context is available and widget-scoped. */ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + gtk_style_context_add_provider( + gtk_widget_get_style_context(widget), + GTK_STYLE_PROVIDER(p), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + G_GNUC_END_IGNORE_DEPRECATIONS + g_object_unref(p); +#endif +} + +/* ── Main-thread dispatch ────────────────────────────────────────────────── */ + +/* + * Dispatch a function on the GTK main thread, blocking until it completes. + * If already on the main thread, calls the function directly. + * + * Use a GMainContext + GMutex/GCond pair so we can synchronously wait for + * the idle callback to execute, mirroring dispatch_sync(main_queue, ...). + */ + +typedef struct { + void (*fn)(void*); + void* data; + GMutex mutex; + GCond cond; + int done; +} ElSyncCall; + +static gboolean _el_sync_dispatch(gpointer user_data) { + ElSyncCall* call = (ElSyncCall*)user_data; + call->fn(call->data); + g_mutex_lock(&call->mutex); + call->done = 1; + g_cond_signal(&call->cond); + g_mutex_unlock(&call->mutex); + return G_SOURCE_REMOVE; +} + +static void el_gtk4_sync_main(void (*fn)(void*), void* data) { + /* + * Pre-run phase (el boot sequence, before native_run_loop): + * The GMainContext is not yet iterating. We are on the main thread. + * Call directly — no dispatch needed. + * + * Post-run phase (callbacks from GTK signal handlers or other threads): + * Dispatch to the main context and wait for completion. + */ + if (!_el_app_running) { + fn(data); + return; + } + + /* Check if we're already on the thread running the default main context. */ + GMainContext* main_ctx = g_main_context_default(); + if (g_main_context_is_owner(main_ctx)) { + fn(data); + return; + } + ElSyncCall call; + call.fn = fn; + call.data = data; + call.done = 0; + g_mutex_init(&call.mutex); + g_cond_init(&call.cond); + + g_main_context_invoke(main_ctx, _el_sync_dispatch, &call); + + g_mutex_lock(&call.mutex); + while (!call.done) { + g_cond_wait(&call.cond, &call.mutex); + } + g_mutex_unlock(&call.mutex); + g_mutex_clear(&call.mutex); + g_cond_clear(&call.cond); +} + +/* Convenience macro: declare a local struct, fill it, dispatch. */ +#define EL_SYNC(type, var, ...) \ + type var = { __VA_ARGS__ }; \ + el_gtk4_sync_main(_el_sync_##var, &var) + +/* ── El callback invocation ──────────────────────────────────────────────── */ + +/* + * El callback functions have signature (per el_seed.c conventions): + * void fn_name(int64_t handle, int64_t data) + * where data is a (const char*) cast to int64_t — same as AppKit bridge. + */ +typedef void (*ElCb2)(int64_t handle, int64_t data); + +static void el_gtk4_invoke_cb(const char* fn_name, int64_t handle, + const char* data) { + if (!fn_name || !*fn_name) return; + void* sym = dlsym(RTLD_DEFAULT, fn_name); + if (!sym) return; + ElCb2 fn = (ElCb2)sym; + fn(handle, (int64_t)(uintptr_t)(data ? data : "")); +} + +/* ── GtkApplication (global) ─────────────────────────────────────────────── */ + +static GtkApplication* _el_app = NULL; +static int _el_app_running = 0; /* set to 1 after activate fires */ + +/* ── Signal callbacks ────────────────────────────────────────────────────── */ + +/* Slot index stored as widget data so signal handlers can look it up. */ +#define EL_SLOT_KEY "el-slot" + +static void _el_on_button_clicked(GtkButton* btn, gpointer user_data) { + (void)btn; + int64_t slot = (int64_t)(intptr_t)user_data; + ElWidget* w = el_widget_get(slot); + if (w && w->cb_click) { + el_gtk4_invoke_cb(w->cb_click, slot, ""); + } +} + +static void _el_on_entry_changed(GtkEditable* editable, gpointer user_data) { + int64_t slot = (int64_t)(intptr_t)user_data; + ElWidget* w = el_widget_get(slot); + if (w && w->cb_change) { + const char* text = gtk_editable_get_text(editable); + el_gtk4_invoke_cb(w->cb_change, slot, text ? text : ""); + } +} + +static void _el_on_entry_activate(GtkEntry* entry, gpointer user_data) { + (void)entry; + int64_t slot = (int64_t)(intptr_t)user_data; + ElWidget* w = el_widget_get(slot); + if (w && w->cb_click) { + const char* text = gtk_editable_get_text(GTK_EDITABLE(entry)); + el_gtk4_invoke_cb(w->cb_click, slot, text ? text : ""); + } +} + +/* GtkTextBuffer "changed" signal for textarea. */ +static void _el_on_textbuffer_changed(GtkTextBuffer* buf, gpointer user_data) { + int64_t slot = (int64_t)(intptr_t)user_data; + ElWidget* w = el_widget_get(slot); + if (!w || !w->cb_change) return; + GtkTextIter start, end; + gtk_text_buffer_get_bounds(buf, &start, &end); + char* text = gtk_text_buffer_get_text(buf, &start, &end, FALSE); + el_gtk4_invoke_cb(w->cb_change, slot, text ? text : ""); + g_free(text); +} + +/* ── GtkApplication activate callback ───────────────────────────────────── */ + +static void _el_app_activate(GtkApplication* app, gpointer user_data) { + /* + * Register all pre-created windows with the application, and mark the + * app as running so subsequent calls use el_gtk4_sync_main dispatching. + * + * On macOS the GTK4 Quartz backend requires g_application_run() on the + * main thread. Windows created before run use gtk_window_new(); we + * register them here via gtk_application_add_window() so they participate + * in the application lifecycle (app quits when last window closes, etc.). + */ + (void)user_data; + _el_app_running = 1; + for (int i = 1; i < EL_GTK4_MAX_WIDGETS; i++) { + if (_el_widgets[i].kind == EL_WIDGET_WINDOW && _el_widgets[i].widget) { + gtk_application_add_window(app, GTK_WINDOW(_el_widgets[i].widget)); + } + } +} + +/* ── Public C API ─────────────────────────────────────────────────────────── */ + +/* + * el_gtk4_init — initialize GTK4 + GtkApplication. Idempotent. + * Must be called once before any other el_gtk4_* function. + */ +void el_gtk4_init(void) { + static int done = 0; + if (done) return; + done = 1; + + _el_app = gtk_application_new("ai.neuralplatform.el", G_APPLICATION_DEFAULT_FLAGS); + g_signal_connect(_el_app, "activate", G_CALLBACK(_el_app_activate), NULL); +} + +/* + * el_gtk4_run_loop — start the GTK main loop. Never returns. + * el code calls __native_run_loop() which dispatches here. + * + * On macOS the GTK4 Quartz backend requires g_application_run() to be called + * from the main thread. Since the el boot sequence (native_init → window_create + * → widget_build → native_run_loop) runs on the main thread, g_application_run + * is always called from the main thread here. + * + * Windows created before this call use gtk_window_new() (no GApplication + * needed); the activate handler registers them with the GtkApplication. + */ +void el_gtk4_run_loop(void) { + if (!_el_app) el_gtk4_init(); + int status = g_application_run(G_APPLICATION(_el_app), 0, NULL); + (void)status; +} + +/* ── Window ───────────────────────────────────────────────────────────────── */ + +typedef struct { + const char* title; + int width, height, min_width, min_height; + int64_t result; +} _ElWindowCreateArgs; + +static void _el_window_create_main(void* vp) { + _ElWindowCreateArgs* a = (_ElWindowCreateArgs*)vp; + /* + * Use gtk_window_new() rather than gtk_application_window_new(). + * gtk_application_window_new() requires the GApplication to be running + * (i.e., after g_application_run / activate), which is not yet the case + * when the el boot sequence creates windows before native_run_loop(). + * The activate handler in el_gtk4_run_loop registers these windows with + * the GtkApplication via gtk_application_add_window(). + */ + GtkWidget* win = gtk_window_new(); + gtk_window_set_title(GTK_WINDOW(win), a->title ? a->title : ""); + gtk_window_set_default_size(GTK_WINDOW(win), a->width, a->height); + + /* Set minimum size via content-area size hint. */ + if (a->min_width > 0 || a->min_height > 0) { + gtk_widget_set_size_request(win, a->min_width, a->min_height); + } + + /* Use a vertical GtkBox as the root content widget so children stack + * vertically by default — mirrors the NSStackView root in AppKit. */ + GtkWidget* root = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_window_set_child(GTK_WINDOW(win), root); + + a->result = el_widget_alloc(EL_WIDGET_WINDOW, win); +} + +int64_t el_gtk4_window_create(const char* title, int width, int height, + int min_width, int min_height) { + _ElWindowCreateArgs a = { title, width, height, min_width, min_height, -1 }; + el_gtk4_sync_main(_el_window_create_main, &a); + return a.result; +} + +typedef struct { int64_t handle; } _ElHandleArgs; + +static void _el_window_show_main(void* vp) { + _ElHandleArgs* a = (_ElHandleArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || w->kind != EL_WIDGET_WINDOW) return; + gtk_window_present(GTK_WINDOW(w->widget)); +} + +void el_gtk4_window_show(int64_t handle) { + _ElHandleArgs a = { handle }; + el_gtk4_sync_main(_el_window_show_main, &a); +} + +typedef struct { int64_t handle; const char* title; } _ElSetTitleArgs; + +static void _el_window_set_title_main(void* vp) { + _ElSetTitleArgs* a = (_ElSetTitleArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || w->kind != EL_WIDGET_WINDOW) return; + gtk_window_set_title(GTK_WINDOW(w->widget), a->title ? a->title : ""); +} + +void el_gtk4_window_set_title(int64_t handle, const char* title) { + _ElSetTitleArgs a = { handle, title }; + el_gtk4_sync_main(_el_window_set_title_main, &a); +} + +/* ── Layout containers ───────────────────────────────────────────────────── */ + +typedef struct { + GtkOrientation orient; + int spacing; + int64_t result; +} _ElStackCreateArgs; + +static void _el_stack_create_main(void* vp) { + _ElStackCreateArgs* a = (_ElStackCreateArgs*)vp; + GtkWidget* box = gtk_box_new(a->orient, a->spacing); + ElWidgetKind kind = (a->orient == GTK_ORIENTATION_VERTICAL) + ? EL_WIDGET_VSTACK : EL_WIDGET_HSTACK; + a->result = el_widget_alloc(kind, box); +} + +int64_t el_gtk4_vstack_create(int spacing) { + _ElStackCreateArgs a = { GTK_ORIENTATION_VERTICAL, spacing, -1 }; + el_gtk4_sync_main(_el_stack_create_main, &a); + return a.result; +} + +int64_t el_gtk4_hstack_create(int spacing) { + _ElStackCreateArgs a = { GTK_ORIENTATION_HORIZONTAL, spacing, -1 }; + el_gtk4_sync_main(_el_stack_create_main, &a); + return a.result; +} + +typedef struct { int64_t result; } _ElResultArgs; + +static void _el_zstack_create_main(void* vp) { + _ElResultArgs* a = (_ElResultArgs*)vp; + GtkWidget* overlay = gtk_overlay_new(); + a->result = el_widget_alloc(EL_WIDGET_ZSTACK, overlay); +} + +int64_t el_gtk4_zstack_create(void) { + _ElResultArgs a = { -1 }; + el_gtk4_sync_main(_el_zstack_create_main, &a); + return a.result; +} + +static void _el_scroll_create_main(void* vp) { + _ElResultArgs* a = (_ElResultArgs*)vp; + GtkWidget* sw = gtk_scrolled_window_new(); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + a->result = el_widget_alloc(EL_WIDGET_SCROLL, sw); +} + +int64_t el_gtk4_scroll_create(void) { + _ElResultArgs a = { -1 }; + el_gtk4_sync_main(_el_scroll_create_main, &a); + return a.result; +} + +/* ── Widget factories ─────────────────────────────────────────────────────── */ + +typedef struct { const char* text; int64_t result; } _ElTextArgs; + +static void _el_label_create_main(void* vp) { + _ElTextArgs* a = (_ElTextArgs*)vp; + GtkWidget* lbl = gtk_label_new(a->text ? a->text : ""); + gtk_label_set_xalign(GTK_LABEL(lbl), 0.0f); + gtk_label_set_wrap(GTK_LABEL(lbl), FALSE); + a->result = el_widget_alloc(EL_WIDGET_LABEL, lbl); +} + +int64_t el_gtk4_label_create(const char* text) { + _ElTextArgs a = { text, -1 }; + el_gtk4_sync_main(_el_label_create_main, &a); + return a.result; +} + +static void _el_button_create_main(void* vp) { + _ElTextArgs* a = (_ElTextArgs*)vp; + GtkWidget* btn = gtk_button_new_with_label(a->text ? a->text : ""); + int64_t slot = el_widget_alloc(EL_WIDGET_BUTTON, btn); + if (slot >= 0) { + g_signal_connect(btn, "clicked", + G_CALLBACK(_el_on_button_clicked), + (gpointer)(intptr_t)slot); + } + a->result = slot; +} + +int64_t el_gtk4_button_create(const char* label) { + _ElTextArgs a = { label, -1 }; + el_gtk4_sync_main(_el_button_create_main, &a); + return a.result; +} + +static void _el_text_field_create_main(void* vp) { + _ElTextArgs* a = (_ElTextArgs*)vp; + GtkWidget* entry = gtk_entry_new(); + if (a->text && *a->text) { + gtk_entry_set_placeholder_text(GTK_ENTRY(entry), a->text); + } + int64_t slot = el_widget_alloc(EL_WIDGET_TEXTFIELD, entry); + if (slot >= 0) { + gpointer slot_ptr = (gpointer)(intptr_t)slot; + g_signal_connect(entry, "changed", + G_CALLBACK(_el_on_entry_changed), slot_ptr); + g_signal_connect(entry, "activate", + G_CALLBACK(_el_on_entry_activate), slot_ptr); + } + a->result = slot; +} + +int64_t el_gtk4_text_field_create(const char* placeholder) { + _ElTextArgs a = { placeholder, -1 }; + el_gtk4_sync_main(_el_text_field_create_main, &a); + return a.result; +} + +static void _el_text_area_create_main(void* vp) { + _ElTextArgs* a = (_ElTextArgs*)vp; + GtkWidget* sw = gtk_scrolled_window_new(); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_widget_set_vexpand(sw, TRUE); + + GtkWidget* tv = gtk_text_view_new(); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tv), GTK_WRAP_WORD_CHAR); + gtk_widget_set_hexpand(tv, TRUE); + gtk_widget_set_vexpand(tv, TRUE); + + /* GTK4 GtkTextView has no native placeholder; set accessible description. */ + if (a->text && *a->text) { + gtk_accessible_update_property(GTK_ACCESSIBLE(tv), + GTK_ACCESSIBLE_PROPERTY_PLACEHOLDER, a->text, -1); + } + + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sw), tv); + + /* Store the scroll window as the widget; text view accessible via child. */ + int64_t slot = el_widget_alloc(EL_WIDGET_TEXTAREA, sw); + if (slot >= 0) { + GtkTextBuffer* buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tv)); + g_signal_connect(buf, "changed", + G_CALLBACK(_el_on_textbuffer_changed), + (gpointer)(intptr_t)slot); + } + a->result = slot; +} + +int64_t el_gtk4_text_area_create(const char* placeholder) { + _ElTextArgs a = { placeholder, -1 }; + el_gtk4_sync_main(_el_text_area_create_main, &a); + return a.result; +} + +static void _el_image_create_main(void* vp) { + _ElTextArgs* a = (_ElTextArgs*)vp; + GtkWidget* img = NULL; + if (a->text && *a->text) { + /* Try as a filesystem path first. */ + if (g_file_test(a->text, G_FILE_TEST_EXISTS)) { + img = gtk_picture_new_for_filename(a->text); + } + if (!img) { + /* Fall back to icon name. */ + img = gtk_image_new_from_icon_name(a->text); + } + } + if (!img) { + img = gtk_picture_new(); + } + a->result = el_widget_alloc(EL_WIDGET_IMAGE, img); +} + +int64_t el_gtk4_image_create(const char* path_or_name) { + _ElTextArgs a = { path_or_name, -1 }; + el_gtk4_sync_main(_el_image_create_main, &a); + return a.result; +} + +/* ── Widget property setters ─────────────────────────────────────────────── */ + +typedef struct { int64_t handle; const char* text; } _ElWidgetTextArgs; + +static void _el_widget_set_text_main(void* vp) { + _ElWidgetTextArgs* a = (_ElWidgetTextArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w) return; + const char* s = a->text ? a->text : ""; + switch (w->kind) { + case EL_WIDGET_LABEL: + gtk_label_set_text(GTK_LABEL(w->widget), s); + break; + case EL_WIDGET_TEXTFIELD: + gtk_editable_set_text(GTK_EDITABLE(w->widget), s); + break; + case EL_WIDGET_BUTTON: + gtk_button_set_label(GTK_BUTTON(w->widget), s); + break; + case EL_WIDGET_TEXTAREA: { + GtkWidget* tv = gtk_scrolled_window_get_child( + GTK_SCROLLED_WINDOW(w->widget)); + if (tv && GTK_IS_TEXT_VIEW(tv)) { + GtkTextBuffer* buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tv)); + gtk_text_buffer_set_text(buf, s, -1); + } + break; + } + case EL_WIDGET_WINDOW: + gtk_window_set_title(GTK_WINDOW(w->widget), s); + break; + default: break; + } +} + +void el_gtk4_widget_set_text(int64_t handle, const char* text) { + _ElWidgetTextArgs a = { handle, text }; + el_gtk4_sync_main(_el_widget_set_text_main, &a); +} + +typedef struct { int64_t handle; const char* result; } _ElWidgetGetTextArgs; + +static void _el_widget_get_text_main(void* vp) { + _ElWidgetGetTextArgs* a = (_ElWidgetGetTextArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w) { a->result = ""; return; } + switch (w->kind) { + case EL_WIDGET_LABEL: + a->result = gtk_label_get_text(GTK_LABEL(w->widget)); + break; + case EL_WIDGET_TEXTFIELD: + a->result = gtk_editable_get_text(GTK_EDITABLE(w->widget)); + break; + case EL_WIDGET_BUTTON: + a->result = gtk_button_get_label(GTK_BUTTON(w->widget)); + break; + case EL_WIDGET_TEXTAREA: { + GtkWidget* tv = gtk_scrolled_window_get_child( + GTK_SCROLLED_WINDOW(w->widget)); + if (tv && GTK_IS_TEXT_VIEW(tv)) { + GtkTextBuffer* buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tv)); + GtkTextIter start, end; + gtk_text_buffer_get_bounds(buf, &start, &end); + /* Returns g_malloc'd string — caller treats it as short-lived. */ + a->result = gtk_text_buffer_get_text(buf, &start, &end, FALSE); + } else { + a->result = ""; + } + break; + } + default: + a->result = ""; + break; + } +} + +const char* el_gtk4_widget_get_text(int64_t handle) { + _ElWidgetGetTextArgs a = { handle, "" }; + el_gtk4_sync_main(_el_widget_get_text_main, &a); + return a.result ? strdup(a.result) : strdup(""); +} + +typedef struct { + int64_t handle; + float r, g, b, a; +} _ElColorArgs; + +static void _el_widget_set_color_main(void* vp) { + _ElColorArgs* a = (_ElColorArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w) return; + char css[128]; + snprintf(css, sizeof(css), "color: rgba(%d,%d,%d,%.3f);", + (int)(a->r * 255.0f), (int)(a->g * 255.0f), + (int)(a->b * 255.0f), (double)a->a); + apply_css(w->widget, css); +} + +void el_gtk4_widget_set_color(int64_t handle, float r, float g, float b, float a) { + _ElColorArgs args = { handle, r, g, b, a }; + el_gtk4_sync_main(_el_widget_set_color_main, &args); +} + +static void _el_widget_set_bg_color_main(void* vp) { + _ElColorArgs* a = (_ElColorArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || w->kind == EL_WIDGET_WINDOW) return; + char css[128]; + snprintf(css, sizeof(css), "background-color: rgba(%d,%d,%d,%.3f);", + (int)(a->r * 255.0f), (int)(a->g * 255.0f), + (int)(a->b * 255.0f), (double)a->a); + apply_css(w->widget, css); +} + +void el_gtk4_widget_set_bg_color(int64_t handle, float r, float g, float b, float a) { + _ElColorArgs args = { handle, r, g, b, a }; + el_gtk4_sync_main(_el_widget_set_bg_color_main, &args); +} + +typedef struct { + int64_t handle; + const char* family; + int size; + int bold; +} _ElFontArgs; + +static void _el_widget_set_font_main(void* vp) { + _ElFontArgs* a = (_ElFontArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w) return; + char css[256]; + const char* fam = (a->family && *a->family && strcmp(a->family, "system") != 0) + ? a->family : "sans-serif"; + snprintf(css, sizeof(css), + "font-family: %s; font-size: %dpx; font-weight: %s;", + fam, a->size, a->bold ? "bold" : "normal"); + apply_css(w->widget, css); +} + +void el_gtk4_widget_set_font(int64_t handle, const char* family, int size, int bold) { + _ElFontArgs a = { handle, family, size, bold }; + el_gtk4_sync_main(_el_widget_set_font_main, &a); +} + +typedef struct { int64_t handle; int top, right, bottom, left; } _ElPaddingArgs; + +static void _el_widget_set_padding_main(void* vp) { + _ElPaddingArgs* a = (_ElPaddingArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w) return; + char css[128]; + snprintf(css, sizeof(css), "padding: %dpx %dpx %dpx %dpx;", + a->top, a->right, a->bottom, a->left); + apply_css(w->widget, css); +} + +void el_gtk4_widget_set_padding(int64_t handle, int top, int right, int bottom, int left) { + _ElPaddingArgs a = { handle, top, right, bottom, left }; + el_gtk4_sync_main(_el_widget_set_padding_main, &a); +} + +typedef struct { int64_t handle; int value; } _ElIntPropArgs; + +static void _el_widget_set_width_main(void* vp) { + _ElIntPropArgs* a = (_ElIntPropArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || w->kind == EL_WIDGET_WINDOW) return; + gint cur_h = -1; + gtk_widget_get_size_request(w->widget, NULL, &cur_h); + gtk_widget_set_size_request(w->widget, a->value, cur_h); +} + +void el_gtk4_widget_set_width(int64_t handle, int width) { + _ElIntPropArgs a = { handle, width }; + el_gtk4_sync_main(_el_widget_set_width_main, &a); +} + +static void _el_widget_set_height_main(void* vp) { + _ElIntPropArgs* a = (_ElIntPropArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || w->kind == EL_WIDGET_WINDOW) return; + gint cur_w = -1; + gtk_widget_get_size_request(w->widget, &cur_w, NULL); + gtk_widget_set_size_request(w->widget, cur_w, a->value); +} + +void el_gtk4_widget_set_height(int64_t handle, int height) { + _ElIntPropArgs a = { handle, height }; + el_gtk4_sync_main(_el_widget_set_height_main, &a); +} + +static void _el_widget_set_flex_main(void* vp) { + _ElIntPropArgs* a = (_ElIntPropArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || w->kind == EL_WIDGET_WINDOW) return; + gboolean expand = (a->value > 0) ? TRUE : FALSE; + gtk_widget_set_hexpand(w->widget, expand); + gtk_widget_set_vexpand(w->widget, expand); +} + +void el_gtk4_widget_set_flex(int64_t handle, int flex) { + _ElIntPropArgs a = { handle, flex }; + el_gtk4_sync_main(_el_widget_set_flex_main, &a); +} + +static void _el_widget_set_corner_radius_main(void* vp) { + _ElIntPropArgs* a = (_ElIntPropArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || w->kind == EL_WIDGET_WINDOW) return; + char css[64]; + snprintf(css, sizeof(css), "border-radius: %dpx;", a->value); + apply_css(w->widget, css); +} + +void el_gtk4_widget_set_corner_radius(int64_t handle, int radius) { + _ElIntPropArgs a = { handle, radius }; + el_gtk4_sync_main(_el_widget_set_corner_radius_main, &a); +} + +static void _el_widget_set_disabled_main(void* vp) { + _ElIntPropArgs* a = (_ElIntPropArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w) return; + gtk_widget_set_sensitive(w->widget, !a->value); +} + +void el_gtk4_widget_set_disabled(int64_t handle, int disabled) { + _ElIntPropArgs a = { handle, disabled }; + el_gtk4_sync_main(_el_widget_set_disabled_main, &a); +} + +static void _el_widget_set_hidden_main(void* vp) { + _ElIntPropArgs* a = (_ElIntPropArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w || w->kind == EL_WIDGET_WINDOW) return; + gtk_widget_set_visible(w->widget, !a->value); +} + +void el_gtk4_widget_set_hidden(int64_t handle, int hidden) { + _ElIntPropArgs a = { handle, hidden }; + el_gtk4_sync_main(_el_widget_set_hidden_main, &a); +} + +/* ── Child management ─────────────────────────────────────────────────────── */ + +typedef struct { int64_t parent; int64_t child; } _ElParentChildArgs; + +static void _el_widget_add_child_main(void* vp) { + _ElParentChildArgs* a = (_ElParentChildArgs*)vp; + ElWidget* pw = el_widget_get(a->parent); + ElWidget* cw = el_widget_get(a->child); + if (!pw || !cw) return; + if (cw->kind == EL_WIDGET_WINDOW) return; /* cannot add a window as child */ + + GtkWidget* child_widget = cw->widget; + + switch (pw->kind) { + case EL_WIDGET_WINDOW: { + /* Append to the root VBox that window_create installs as child. */ + GtkWidget* root = gtk_window_get_child(GTK_WINDOW(pw->widget)); + if (root && GTK_IS_BOX(root)) { + gtk_box_append(GTK_BOX(root), child_widget); + } else { + /* Fallback: replace root child. */ + gtk_window_set_child(GTK_WINDOW(pw->widget), child_widget); + } + break; + } + case EL_WIDGET_VSTACK: + case EL_WIDGET_HSTACK: + gtk_box_append(GTK_BOX(pw->widget), child_widget); + break; + case EL_WIDGET_ZSTACK: + /* First child becomes the base; subsequent children are overlays. */ + if (!gtk_overlay_get_child(GTK_OVERLAY(pw->widget))) { + gtk_overlay_set_child(GTK_OVERLAY(pw->widget), child_widget); + } else { + gtk_overlay_add_overlay(GTK_OVERLAY(pw->widget), child_widget); + } + break; + case EL_WIDGET_SCROLL: + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(pw->widget), + child_widget); + break; + default: + /* Generic fallback — shouldn't be reached for standard widget kinds. */ + break; + } +} + +void el_gtk4_widget_add_child(int64_t parent, int64_t child) { + _ElParentChildArgs a = { parent, child }; + el_gtk4_sync_main(_el_widget_add_child_main, &a); +} + +static void _el_widget_remove_child_main(void* vp) { + _ElParentChildArgs* a = (_ElParentChildArgs*)vp; + ElWidget* pw = el_widget_get(a->parent); + ElWidget* cw = el_widget_get(a->child); + if (!pw || !cw) return; + if (cw->kind == EL_WIDGET_WINDOW) return; + + GtkWidget* child_widget = cw->widget; + + switch (pw->kind) { + case EL_WIDGET_WINDOW: { + GtkWidget* root = gtk_window_get_child(GTK_WINDOW(pw->widget)); + if (root && GTK_IS_BOX(root)) { + gtk_box_remove(GTK_BOX(root), child_widget); + } + break; + } + case EL_WIDGET_VSTACK: + case EL_WIDGET_HSTACK: + gtk_box_remove(GTK_BOX(pw->widget), child_widget); + break; + case EL_WIDGET_ZSTACK: + gtk_overlay_remove_overlay(GTK_OVERLAY(pw->widget), child_widget); + break; + case EL_WIDGET_SCROLL: + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(pw->widget), NULL); + break; + default: + break; + } +} + +void el_gtk4_widget_remove_child(int64_t parent, int64_t child) { + _ElParentChildArgs a = { parent, child }; + el_gtk4_sync_main(_el_widget_remove_child_main, &a); +} + +/* ── Event registration ───────────────────────────────────────────────────── */ + +/* + * on_click / on_change / on_submit just store the function name string. + * The actual g_signal_connect calls happen at widget creation time. + * Here we update the stored callback so the already-connected signal handler + * will call the new function name. + */ + +void el_gtk4_widget_on_click(int64_t handle, const char* fn_name) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + free(w->cb_click); + w->cb_click = (fn_name && *fn_name) ? strdup(fn_name) : NULL; +} + +void el_gtk4_widget_on_change(int64_t handle, const char* fn_name) { + ElWidget* w = el_widget_get(handle); + if (!w) return; + free(w->cb_change); + w->cb_change = (fn_name && *fn_name) ? strdup(fn_name) : NULL; +} + +void el_gtk4_widget_on_submit(int64_t handle, const char* fn_name) { + /* For text fields, "submit" = Enter key activate → stored in cb_click. */ + el_gtk4_widget_on_click(handle, fn_name); +} + +/* ── Widget destroy ───────────────────────────────────────────────────────── */ + +static void _el_widget_destroy_main(void* vp) { + _ElHandleArgs* a = (_ElHandleArgs*)vp; + ElWidget* w = el_widget_get(a->handle); + if (!w) return; + if (w->kind == EL_WIDGET_WINDOW) { + gtk_window_destroy(GTK_WINDOW(w->widget)); + } else { + /* Unparent the widget before freeing the slot. */ + GtkWidget* parent = gtk_widget_get_parent(w->widget); + if (parent) { + if (GTK_IS_BOX(parent)) { + gtk_box_remove(GTK_BOX(parent), w->widget); + } else if (GTK_IS_OVERLAY(parent)) { + gtk_overlay_remove_overlay(GTK_OVERLAY(parent), w->widget); + } else if (GTK_IS_SCROLLED_WINDOW(parent)) { + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(parent), NULL); + } + /* gtk_window_get_child case: the parent is a GtkBox inside a window */ + } + } + el_widget_free(a->handle); +} + +void el_gtk4_widget_destroy(int64_t handle) { + _ElHandleArgs a = { handle }; + el_gtk4_sync_main(_el_widget_destroy_main, &a); +} + +#endif /* EL_TARGET_LINUX */ diff --git a/ui/examples/native-hello/build-docker/runtime/el_native_target.h b/ui/examples/native-hello/build-docker/runtime/el_native_target.h new file mode 100644 index 0000000..dc1edcb --- /dev/null +++ b/ui/examples/native-hello/build-docker/runtime/el_native_target.h @@ -0,0 +1,573 @@ +/* + * el_native_target.h — Native widget declarations for el programs targeting + * native desktop UI (AppKit / GTK4 / Win32). + * + * This header is designed to be included AFTER el_runtime.h without conflict: + * - It does NOT redefine el_to_float, el_from_float, or any el_runtime.h + * static inlines. + * - It does NOT redeclare __println, __print, or other functions whose + * return types differ between el_seed.h and el_runtime.h. + * - It adds: native widget builtins + float arithmetic helpers that the + * current el_runtime.h omits but elc still emits calls to. + * + * Usage: + * Inject via -include at compile time, OR #include it after el_runtime.h. + * + * clang -DEL_TARGET_MACOS -include el_native_target.h -c my_app.c ... + */ + +#pragma once + +#include +#include + +/* el_val_t must already be defined by el_runtime.h or el_seed.h. */ +#ifndef EL_VAL_T_DEFINED +typedef int64_t el_val_t; +#endif + +/* ── Float arithmetic helpers ─────────────────────────────────────────────── + * elc emits calls to float_div / float_mul etc. for Float-typed expressions. + * These were in el_runtime.c through v1.0.0-20260501 but are missing from the + * current el_runtime.h. Redeclared here as static inline to avoid link deps. + * Only defined if not already declared (old runtimes that still have them). */ + +#ifndef EL_FLOAT_OPS_DEFINED +#define EL_FLOAT_OPS_DEFINED + +/* el_to_float / el_from_float — bit-cast between el_val_t and double. + * Defined as static inline in both el_runtime.h and el_seed.h; we do NOT + * redefine them here. We rely on one of those headers being included first. */ + +static inline el_val_t float_div(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub, ur; + ua.i = a; ub.i = b; + ur.d = (ub.d != 0.0) ? (ua.d / ub.d) : 0.0; + return ur.i; +} + +static inline el_val_t float_mul(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub, ur; + ua.i = a; ub.i = b; ur.d = ua.d * ub.d; + return ur.i; +} + +static inline el_val_t float_add(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub, ur; + ua.i = a; ub.i = b; ur.d = ua.d + ub.d; + return ur.i; +} + +static inline el_val_t float_sub(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub, ur; + ua.i = a; ub.i = b; ur.d = ua.d - ub.d; + return ur.i; +} + +static inline el_val_t float_lt(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d < ub.d); +} + +static inline el_val_t float_gt(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d > ub.d); +} + +static inline el_val_t float_lte(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d <= ub.d); +} + +static inline el_val_t float_gte(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d >= ub.d); +} + +static inline el_val_t float_eq(el_val_t a, el_val_t b) { + union { double d; int64_t i; } ua, ub; + ua.i = a; ub.i = b; + return (el_val_t)(ua.d == ub.d); +} + +#endif /* EL_FLOAT_OPS_DEFINED */ + +/* ── Native widget system (macOS AppKit) ──────────────────────────────────── + * Available when compiled with -DEL_TARGET_MACOS and linked with el_appkit.m. + * Widget handles are opaque int64_t slot indices; -1 = invalid. */ + +#ifdef EL_TARGET_MACOS + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_MACOS */ + +/* ── Native widget system (Linux GTK4) ────────────────────────────────────── + * Available when compiled with -DEL_TARGET_LINUX and linked with el_gtk4.c. + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * All functions have the same signatures as EL_TARGET_MACOS above. */ + +#ifdef EL_TARGET_LINUX + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader — same JSON output as EL_TARGET_MACOS */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_LINUX */ + +/* ── Native widget system (Windows Win32) ─────────────────────────────────── + * Available when compiled with -DEL_TARGET_WIN32 and linked with el_win32.c. + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * Link: el_win32.obj comctl32.lib user32.lib gdi32.lib */ + +#ifdef EL_TARGET_WIN32 + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_WIN32 */ + +/* ── Native widget system (iOS UIKit) ─────────────────────────────────────── + * Available when compiled with -DEL_TARGET_IOS and linked with el_uikit.m. + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * + * iOS lifecycle note: UIApplicationMain never returns. The el program must + * store its UI-build logic in a void(*)(void) function pointer, assign it to + * el_main_entry_fn, then call __native_run_loop. ElAppDelegate invokes + * el_main_entry_fn inside didFinishLaunchingWithOptions. + * Call el_uikit_set_args(argc, argv) from main() before __native_run_loop. */ + +#ifdef EL_TARGET_IOS + +/* Lifecycle entry-function hook — set before calling __native_run_loop. */ +extern void (*el_main_entry_fn)(void); + +/* Forward argc/argv from main() to UIApplicationMain. */ +void el_uikit_set_args(int argc, char** argv); + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_IOS */ + +/* ── Native widget system (Android JNI) ───────────────────────────────────── + * Available when compiled with -DEL_TARGET_ANDROID and linked with + * libelruntime.so (which includes el_android.c compiled by the NDK build). + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * + * Java companion: ElBridge.java (package com.neuron.el) must be compiled into + * the APK. The Activity must call ElBridge.init(this) before any widget ops. + * + * Link flags (in Android.mk or CMakeLists.txt): + * -landroid -llog -ldl */ + +#ifdef EL_TARGET_ANDROID + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); /* no-op on Android */ + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_ANDROID */ + +/* ── Native widget system (LVGL v9 — embedded / microcontroller) ───────────── + * Available when compiled with -DEL_TARGET_LVGL and linked with el_lvgl.c + * and the LVGL library (lvgl.a or lvgl source tree). + * + * Target platforms: ESP32, STM32, industrial panels. Any system with 256KB+ + * RAM and an LVGL-compatible display driver. No OS required. + * + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * + * Bare-metal / no dynamic linker: + * Compile with -DEL_LVGL_NO_DLSYM and provide: + * el_val_t el_lvgl_dispatch(const char *fn, el_val_t a, el_val_t b); + * + * Compile: + * gcc -DEL_TARGET_LVGL -I./lvgl el_lvgl.c -c -o el_lvgl.o + * # Then link with lvgl.a. */ + +#ifdef EL_TARGET_LVGL + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader — same JSON output as all other native targets */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_LVGL */ + +/* ── Native widget system (SDL2 — embedded / Pi) ──────────────────────────── + * Available when compiled with -DEL_TARGET_SDL2 and linked with el_sdl2.c. + * Widget handles are opaque int64_t slot indices; -1 = invalid. + * + * Target: Raspberry Pi Zero, embedded Linux, any system with a framebuffer + * and SDL2 available. No GTK, no desktop environment required. + * + * Compile: + * gcc -DEL_TARGET_SDL2 $(sdl2-config --cflags) -c el_sdl2.c -o el_sdl2.o + * Link: + * $(sdl2-config --libs) -lSDL2_ttf -lSDL2_image -ldl */ + +#ifdef EL_TARGET_SDL2 + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, + el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, + el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_SDL2 */ diff --git a/ui/examples/native-hello/build-docker/runtime/el_runtime.c b/ui/examples/native-hello/build-docker/runtime/el_runtime.c new file mode 100644 index 0000000..a735c9f --- /dev/null +++ b/ui/examples/native-hello/build-docker/runtime/el_runtime.c @@ -0,0 +1,11733 @@ +/* + * el_runtime.c — El language C runtime implementation + * + * All functions use el_val_t (= int64_t) as the universal value type. + * Strings are transported as their pointer address cast to int64_t. + * On any 64-bit system sizeof(pointer) <= sizeof(int64_t), so this is safe. + * + * Compile with: + * cc -std=c11 -I -lcurl -lpthread -o .c el_runtime.c + * + * Link requirements: -lcurl (HTTP client + LLM), -lpthread (HTTP server). + */ + +/* Feature-test macros must be set before any standard headers. _GNU_SOURCE + * exposes clock_gettime/CLOCK_REALTIME, strcasecmp, and the dlfcn extensions + * (RTLD_DEFAULT) — all of which macOS hands us without asking but glibc on + * Debian gates behind an explicit opt-in. */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "el_runtime.h" + +#include +#include /* strcasecmp */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* dlsym for http_set_handler fallback */ +#include +#include +#include +#include +#include +#include /* getrusage — memory guard */ +#ifdef HAVE_CURL +#include +#endif + +/* ── Internal allocators ─────────────────────────────────────────────────── */ + +/* + * Per-request string arena + * + * Every El string allocated via el_strbuf / el_strdup during an HTTP request + * is registered in a thread-local arena. When el_request_end() is called at + * the end of the worker thread, every arena entry is freed — recovering all + * the intermediate strings from el_str_concat chains (build_system_prompt, + * engram_compile, etc.) that are otherwise leaked forever. + * + * Long-lived allocations (state_set values, engram internal storage) call + * el_strdup_persist() / el_strbuf_persist() which bypass the arena entirely. + */ + +#define EL_ARENA_INITIAL 512 + +typedef struct { + char** ptrs; + size_t count; + size_t cap; +} ElArena; + +static _Thread_local ElArena _tl_arena = {NULL, 0, 0}; +static _Thread_local int _tl_arena_active = 0; + +/* Binary-safe fs_read length — set by fs_read, consumed by http_send_response. + * Allows serving PNGs and other binary files without strlen truncation. */ +static _Thread_local size_t _tl_fs_read_len = 0; + +static void el_arena_track(char* p) { + if (!_tl_arena_active || !p) return; + if (_tl_arena.count >= _tl_arena.cap) { + size_t nc = _tl_arena.cap == 0 ? EL_ARENA_INITIAL : _tl_arena.cap * 2; + char** grown = realloc(_tl_arena.ptrs, nc * sizeof(char*)); + if (!grown) return; /* can't track — will leak this one ptr, but don't crash */ + _tl_arena.ptrs = grown; + _tl_arena.cap = nc; + } + _tl_arena.ptrs[_tl_arena.count++] = p; +} + +/* Called by http_worker before dispatching the El handler. */ +void el_request_start(void) { + _tl_arena.count = 0; + _tl_arena_active = 1; +} + +/* Called by http_worker after the El handler returns and the response is sent. + * Frees every intermediate string allocated during the request. */ +void el_request_end(void) { + _tl_arena_active = 0; + for (size_t i = 0; i < _tl_arena.count; i++) { + free(_tl_arena.ptrs[i]); + } + _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(""); + return strdup(s); +} +static char* el_strbuf_persist(size_t n) { + char* p = malloc(n + 1); + if (!p) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + p[0] = '\0'; + return p; +} + +static char* el_strdup(const char* s) { + if (!s) { char* p = strdup(""); el_arena_track(p); return p; } + char* p = strdup(s); + el_arena_track(p); + return p; +} + +static char* el_strbuf(size_t n) { + char* p = malloc(n + 1); + if (!p) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + p[0] = '\0'; + el_arena_track(p); + return p; +} + +/* Wrap an allocated C string as el_val_t */ +static el_val_t el_wrap_str(char* s) { + return EL_STR(s); +} + +/* ── I/O ──────────────────────────────────────────────────────────────────── */ + +el_val_t println(el_val_t s) { + const char* str = EL_CSTR(s); + if (str) puts(str); + else puts(""); + return 0; +} + +el_val_t print(el_val_t s) { + const char* str = EL_CSTR(s); + if (str) fputs(str, stdout); + return 0; +} + +el_val_t readline(void) { + char buf[4096]; + if (!fgets(buf, sizeof(buf), stdin)) return el_wrap_str(el_strdup("")); + size_t len = strlen(buf); + if (len > 0 && buf[len - 1] == '\n') buf[len - 1] = '\0'; + return el_wrap_str(el_strdup(buf)); +} + +/* __read_n — read exactly n bytes from stdin. + * Allocates a buffer of size n+1, calls fread(buf, 1, n, stdin) to read + * exactly n raw bytes (including \r, \n, NUL, etc.), null-terminates, and + * returns the buffer as an El String. Returns "" on EOF or I/O error. + * + * Used by the El LSP server to read JSON-RPC message bodies after parsing + * the Content-Length header. readline() cannot be used for the body because + * it stops at the first \n and LSP JSON bodies are not newline-terminated. */ +el_val_t __read_n(el_val_t nv) { + int64_t n = EL_INT(nv); + if (n <= 0) return el_wrap_str(el_strdup("")); + char* buf = malloc((size_t)n + 1); + if (!buf) { fputs("el_runtime: __read_n: out of memory\n", stderr); return el_wrap_str(el_strdup("")); } + size_t got = fread(buf, 1, (size_t)n, stdin); + buf[got] = '\0'; + if (got == 0) { free(buf); return el_wrap_str(el_strdup("")); } + /* Track in arena so the allocation is freed when the request ends. */ + el_arena_track(buf); + return el_wrap_str(buf); +} + +/* __print_raw — write a string to stdout without any modification. + * Unlike println/print (which call puts/fputs and may add newlines or flush + * in platform-specific ways), this uses fwrite with the exact byte count so + * that embedded \r\n pairs in LSP Content-Length headers survive intact. */ +void __print_raw(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return; + size_t len = strlen(s); + fwrite(s, 1, len, stdout); + fflush(stdout); +} + +/* ── String builtins ─────────────────────────────────────────────────────── */ + +el_val_t el_str_concat(el_val_t av, el_val_t bv) { + const char* a = EL_CSTR(av); + const char* b = EL_CSTR(bv); + if (!a) a = ""; + if (!b) b = ""; + size_t la = strlen(a); + size_t lb = strlen(b); + char* out = el_strbuf(la + lb); + memcpy(out, a, la); + memcpy(out + la, b, lb); + out[la + lb] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_eq(el_val_t av, el_val_t bv) { + const char* a = EL_CSTR(av); + const char* b = EL_CSTR(bv); + if (!a || !b) return (el_val_t)(a == b); + return (el_val_t)(strcmp(a, b) == 0); +} + +el_val_t str_starts_with(el_val_t sv, el_val_t prefv) { + const char* s = EL_CSTR(sv); + const char* prefix = EL_CSTR(prefv); + if (!s || !prefix) return 0; + size_t lp = strlen(prefix); + return (el_val_t)(strncmp(s, prefix, lp) == 0); +} + +el_val_t str_ends_with(el_val_t sv, el_val_t sufv) { + const char* s = EL_CSTR(sv); + const char* suffix = EL_CSTR(sufv); + if (!s || !suffix) return 0; + size_t ls = strlen(s); + size_t lsuf = strlen(suffix); + if (lsuf > ls) return 0; + return (el_val_t)(strcmp(s + ls - lsuf, suffix) == 0); +} + +el_val_t str_len(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + return (el_val_t)strlen(s); +} + +el_val_t str_concat(el_val_t a, el_val_t b) { + return el_str_concat(a, b); +} + +el_val_t int_to_str(el_val_t n) { + char buf[32]; + snprintf(buf, sizeof(buf), "%lld", (long long)n); + return el_wrap_str(el_strdup(buf)); +} + +el_val_t str_to_int(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + return (el_val_t)atoll(s); +} + +/* native_str_to_int — El compiler-generated alias for str_to_int. + * Converts a string el_val_t to its integer representation. */ +el_val_t native_str_to_int(el_val_t sv) { return str_to_int(sv); } + +el_val_t str_slice(el_val_t sv, el_val_t start, el_val_t end) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + int64_t len = (int64_t)strlen(s); + if (start < 0) start = 0; + if (end > len) end = len; + if (start >= end) return el_wrap_str(el_strdup("")); + int64_t sz = end - start; + char* out = el_strbuf((size_t)sz); + memcpy(out, s + start, (size_t)sz); + out[sz] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_contains(el_val_t sv, el_val_t subv) { + const char* s = EL_CSTR(sv); + const char* sub = EL_CSTR(subv); + if (!s || !sub) return 0; + return (el_val_t)(strstr(s, sub) != NULL); +} + +el_val_t str_replace(el_val_t sv, el_val_t fromv, el_val_t tov) { + const char* s = EL_CSTR(sv); + const char* from = EL_CSTR(fromv); + const char* to = EL_CSTR(tov); + if (!s || !from || !to) return el_wrap_str(el_strdup(s ? s : "")); + size_t ls = strlen(s); + size_t lf = strlen(from); + size_t lt = strlen(to); + if (lf == 0) return el_wrap_str(el_strdup(s)); + size_t count = 0; + const char* p = s; + while ((p = strstr(p, from)) != NULL) { count++; p += lf; } + size_t out_sz = ls + count * lt + 1; + char* out = el_strbuf(out_sz); + char* dst = out; + p = s; + const char* found; + while ((found = strstr(p, from)) != NULL) { + size_t chunk = (size_t)(found - p); + memcpy(dst, p, chunk); dst += chunk; + memcpy(dst, to, lt); dst += lt; + p = found + lf; + } + strcpy(dst, p); + return el_wrap_str(out); +} + +el_val_t str_to_upper(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + char* out = el_strbuf(n); + for (size_t i = 0; i < n; i++) out[i] = (char)toupper((unsigned char)s[i]); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_to_lower(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + char* out = el_strbuf(n); + for (size_t i = 0; i < n; i++) out[i] = (char)tolower((unsigned char)s[i]); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_trim(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + while (*s && isspace((unsigned char)*s)) s++; + size_t n = strlen(s); + while (n > 0 && isspace((unsigned char)s[n - 1])) n--; + char* out = el_strbuf(n); + memcpy(out, s, n); + out[n] = '\0'; + return el_wrap_str(out); +} + +/* ── Math ────────────────────────────────────────────────────────────────── */ + +el_val_t el_abs(el_val_t n) { return n < 0 ? -n : n; } +el_val_t el_max(el_val_t a, el_val_t b) { return a > b ? a : b; } +el_val_t el_min(el_val_t a, el_val_t b) { return a < b ? a : b; } + +/* ── Refcounted heap objects ────────────────────────────────────────────────── + * + * ElList and ElMap carry a magic-tagged header at offset 0: + * { uint32_t magic; uint32_t refcount; ... payload ... } + * + * The magic tag distinguishes refcounted objects from raw C strings (whose + * first byte is printable ASCII < 0x80) and from small integers (which can't + * be dereferenced). el_retain / el_release sniff the magic and act only on + * matching values; everything else is a safe no-op. + * + * Both ElList and ElMap use INDIRECTION: the header is fixed-size and never + * moves. The payload arrays (elems, keys, values) live in separate heap + * allocations, so realloc-grow on append never invalidates the caller's + * pointer to the header. This is what lets us mutate-in-place safely when + * the refcount is 1 and copy-on-write when it's higher. + * + * Memory model in practice: + * Single-owner accumulator (the cg_stmts pattern) — refcount stays at 1, + * appends amortize to O(1), total memory O(N) for an N-element list. + * Multi-owner branching (the cg_if_stmt pattern) — refcount > 1, each + * append on a shared list copies, so the original is preserved for the + * else-branch. Persistent semantics where they're needed; mutation where + * they're not. */ + +#define EL_MAGIC_LIST 0xE15710A1u /* >= 0x80 in MSB so 'looks_like_string' rejects */ +#define EL_MAGIC_MAP 0xE19A704Bu + +typedef struct { + uint32_t magic; + uint32_t refcount; +} ElHeader; + +/* ── List ────────────────────────────────────────────────────────────────── */ + +typedef struct { + ElHeader hdr; + int64_t length; + int64_t capacity; + el_val_t* elems; +} ElList; + +static ElList* list_alloc(int64_t cap) { + if (cap < 4) cap = 4; + ElList* lst = malloc(sizeof(ElList)); + if (!lst) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + lst->hdr.magic = EL_MAGIC_LIST; + lst->hdr.refcount = 1; + lst->length = 0; + lst->capacity = cap; + lst->elems = malloc((size_t)cap * sizeof(el_val_t)); + if (!lst->elems) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + return lst; +} + +el_val_t el_list_empty(void) { + return EL_STR(list_alloc(4)); +} + +el_val_t el_list_new(el_val_t count, ...) { + ElList* lst = list_alloc(count > 0 ? count : 4); + va_list ap; + va_start(ap, count); + for (int64_t i = 0; i < count; i++) { + lst->elems[i] = va_arg(ap, el_val_t); + } + va_end(ap); + lst->length = count; + return EL_STR(lst); +} + +el_val_t el_list_len(el_val_t listv) { + ElList* lst = (ElList*)(uintptr_t)listv; + if (!lst) return 0; + return lst->length; +} + +el_val_t el_list_get(el_val_t listv, el_val_t index) { + ElList* lst = (ElList*)(uintptr_t)listv; + if (!lst) return 0; + if (index < 0 || index >= lst->length) return 0; + return lst->elems[index]; +} + +el_val_t el_list_append(el_val_t listv, el_val_t elem) { + ElList* old = (ElList*)(uintptr_t)listv; + if (!old) { + ElList* fresh = list_alloc(4); + fresh->elems[0] = elem; + fresh->length = 1; + return EL_STR(fresh); + } + + /* Uniquely owned: grow the elems buffer in place. The header pointer the + * caller holds doesn't move (we only realloc the inner array). This is + * the common case in compiler accumulators, and it's amortized O(1). */ + if (old->hdr.refcount <= 1) { + if (old->length >= old->capacity) { + int64_t new_cap = old->capacity > 0 ? old->capacity * 2 : 4; + el_val_t* grown = realloc(old->elems, (size_t)new_cap * sizeof(el_val_t)); + if (!grown) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + old->elems = grown; + old->capacity = new_cap; + } + old->elems[old->length++] = elem; + return listv; + } + + /* Shared: copy-on-write. The original is preserved for its other owners. */ + int64_t new_cap = old->length + 1; + if (new_cap < 4) new_cap = 4; + ElList* fresh = malloc(sizeof(ElList)); + if (!fresh) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + fresh->hdr.magic = EL_MAGIC_LIST; + fresh->hdr.refcount = 1; + fresh->length = old->length + 1; + fresh->capacity = new_cap; + fresh->elems = malloc((size_t)new_cap * sizeof(el_val_t)); + if (!fresh->elems) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + if (old->length > 0) { + memcpy(fresh->elems, old->elems, (size_t)old->length * sizeof(el_val_t)); + } + fresh->elems[old->length] = elem; + return EL_STR(fresh); +} + +el_val_t el_list_clone(el_val_t listv) { + /* Shallow copy: the new ElList owns its own header and elems buffer, but + * the elements themselves are shared (which is what callers want for the + * cg_if_stmt 'declared' pattern — cloning the spine, not its contents). + * Used by codegen at scope branch points where two child scopes need to + * see the same starting set of declared names without each other's + * mutations. */ + ElList* old = (ElList*)(uintptr_t)listv; + if (!old) return el_list_empty(); + int64_t cap = old->capacity > 0 ? old->capacity : 4; + if (cap < old->length) cap = old->length; + if (cap < 4) cap = 4; + ElList* fresh = malloc(sizeof(ElList)); + if (!fresh) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + fresh->hdr.magic = EL_MAGIC_LIST; + fresh->hdr.refcount = 1; + fresh->length = old->length; + fresh->capacity = cap; + fresh->elems = malloc((size_t)cap * sizeof(el_val_t)); + if (!fresh->elems) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + if (old->length > 0) { + memcpy(fresh->elems, old->elems, (size_t)old->length * sizeof(el_val_t)); + } + return EL_STR(fresh); +} + +/* ── Map ─────────────────────────────────────────────────────────────────── */ + +typedef struct { + ElHeader hdr; + int64_t count; + int64_t capacity; + el_val_t* keys; + el_val_t* values; +} ElMap; + +static ElMap* map_alloc(int64_t cap) { + if (cap < 4) cap = 4; + ElMap* m = malloc(sizeof(ElMap)); + if (!m) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + m->hdr.magic = EL_MAGIC_MAP; + m->hdr.refcount = 1; + m->count = 0; + m->capacity = cap; + m->keys = malloc((size_t)cap * sizeof(el_val_t)); + m->values = malloc((size_t)cap * sizeof(el_val_t)); + if (!m->keys || !m->values) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + return m; +} + +el_val_t el_map_new(el_val_t pair_count, ...) { + ElMap* m = map_alloc(pair_count > 0 ? pair_count : 4); + va_list ap; + va_start(ap, pair_count); + for (int64_t i = 0; i < pair_count; i++) { + m->keys[i] = va_arg(ap, el_val_t); + m->values[i] = va_arg(ap, el_val_t); + } + va_end(ap); + m->count = pair_count; + return EL_STR(m); +} + +static ElMap* as_map(el_val_t v) { return (ElMap*)(uintptr_t)v; } + +el_val_t el_map_get(el_val_t mapv, el_val_t keyv) { + ElMap* m = as_map(mapv); + const char* key = EL_CSTR(keyv); + if (!m || !key) return 0; + for (int64_t i = 0; i < m->count; i++) { + const char* k = EL_CSTR(m->keys[i]); + if (k && strcmp(k, key) == 0) return m->values[i]; + } + return 0; +} + +el_val_t el_get_field(el_val_t mapv, el_val_t keyv) { + return el_map_get(mapv, keyv); +} + +/* Internal: in-place set on a uniquely-owned map. */ +static el_val_t map_set_in_place(ElMap* m, el_val_t keyv, el_val_t value) { + const char* key = EL_CSTR(keyv); + if (key) { + for (int64_t i = 0; i < m->count; i++) { + const char* k = EL_CSTR(m->keys[i]); + if (k && strcmp(k, key) == 0) { m->values[i] = value; return EL_STR(m); } + } + } + if (m->count >= m->capacity) { + int64_t new_cap = m->capacity > 0 ? m->capacity * 2 : 4; + el_val_t* gk = realloc(m->keys, (size_t)new_cap * sizeof(el_val_t)); + el_val_t* gv = realloc(m->values, (size_t)new_cap * sizeof(el_val_t)); + if (!gk || !gv) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + m->keys = gk; + m->values = gv; + m->capacity = new_cap; + } + m->keys[m->count] = keyv; + m->values[m->count] = value; + m->count++; + return EL_STR(m); +} + +el_val_t el_map_set(el_val_t mapv, el_val_t keyv, el_val_t value) { + ElMap* m = as_map(mapv); + if (!m) return 0; + if (m->hdr.refcount <= 1) { + return map_set_in_place(m, keyv, value); + } + /* Shared: copy then set. The original is preserved for its other owners. */ + int64_t new_cap = m->count + 1; + if (new_cap < 4) new_cap = 4; + ElMap* fresh = malloc(sizeof(ElMap)); + if (!fresh) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + fresh->hdr.magic = EL_MAGIC_MAP; + fresh->hdr.refcount = 1; + fresh->count = m->count; + fresh->capacity = new_cap; + fresh->keys = malloc((size_t)new_cap * sizeof(el_val_t)); + fresh->values = malloc((size_t)new_cap * sizeof(el_val_t)); + if (!fresh->keys || !fresh->values) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + if (m->count > 0) { + memcpy(fresh->keys, m->keys, (size_t)m->count * sizeof(el_val_t)); + memcpy(fresh->values, m->values, (size_t)m->count * sizeof(el_val_t)); + } + return map_set_in_place(fresh, keyv, value); +} + +/* ── Refcount ops ─────────────────────────────────────────────────────────── */ +/* + * Both retain and release sniff the magic header to decide whether a value + * is a refcounted heap object. For small integers, raw C strings, and any + * value whose magic word doesn't match, both functions are no-ops. This lets + * codegen emit them on every let-binding without having to track types. + * + * Safety: we filter out obvious non-pointers (small magnitudes, misaligned + * addresses) before dereferencing. For any value that passes the filter and + * lives in a mapped page, reading the first 4 bytes is safe — strings start + * with printable ASCII (< 0x80), so their magic word will never collide with + * EL_MAGIC_LIST (0xE1...) or EL_MAGIC_MAP (0xE1...). Random integers that + * happen to look like aligned heap pointers are exceedingly unlikely to land + * on a page whose first 4 bytes match either magic. */ + +static int looks_like_heap_obj(el_val_t v) { + if (v == 0) return 0; + int64_t s = (int64_t)v; + if (s > -0x10000 && s < 0x10000) return 0; /* small ints */ + uintptr_t p = (uintptr_t)v; + if (p < 0x10000) return 0; /* low addresses */ + if (p & 0x7) return 0; /* malloc returns 8-aligned */ + return 1; +} + +void el_retain(el_val_t v) { + if (!looks_like_heap_obj(v)) return; + ElHeader* h = (ElHeader*)(uintptr_t)v; + if (h->magic == EL_MAGIC_LIST || h->magic == EL_MAGIC_MAP) { + h->refcount++; + } +} + +void el_release(el_val_t v) { + if (!looks_like_heap_obj(v)) return; + ElHeader* h = (ElHeader*)(uintptr_t)v; + if (h->magic == EL_MAGIC_LIST) { + if (h->refcount > 0 && --h->refcount == 0) { + ElList* l = (ElList*)h; + free(l->elems); + l->hdr.magic = 0; /* poison so use-after-free is detected */ + free(l); + } + } else if (h->magic == EL_MAGIC_MAP) { + if (h->refcount > 0 && --h->refcount == 0) { + ElMap* m = (ElMap*)h; + free(m->keys); + free(m->values); + m->hdr.magic = 0; + free(m); + } + } +} + +/* ── Batch 2/3 forward decls (defined later in JSON section) ────────────── */ + +typedef struct JsonBuf JsonBuf; +typedef struct JsonParser JsonParser; +static void jb_init(JsonBuf* b); +static void jb_putc(JsonBuf* b, char c); +static void jb_puts(JsonBuf* b, const char* s); +static void jb_emit_escaped(JsonBuf* b, const char* s); +static int looks_like_string(el_val_t v); +static const char* json_find_key(const char* s, const char* key); +static const char* json_skip_value(const char* p); +static char* jp_parse_string_raw(JsonParser* jp); + +/* Struct definitions are visible here because batch 2/3 helpers above use + * them by value; the bodies (jb_init, etc.) appear in the JSON section. */ +struct JsonBuf { + char* buf; + size_t len; + size_t cap; +}; + +struct JsonParser { + const char* p; + const char* end; + int err; +}; + +/* ── Batch 2: Real HTTP (libcurl client + POSIX-socket server) ───────────── */ +/* + * Client: blocking libcurl easy-handle calls. Errors are returned as a JSON + * fragment {"error":"..."} so callers can detect via str_starts_with("{") / + * json_get_string("error", ...). + * + * Server: bind/listen/accept loop on a TCP socket. Each accepted connection + * is handled in its own pthread (detached). A semaphore-style counter caps + * concurrent in-flight connections at HTTP_MAX_CONNS (64). When the cap is + * reached, accept() blocks until a worker exits. This prevents runaway + * thread creation under high load. + * + * Handler dispatch: El does not expose first-class function references at + * the runtime layer, so the second argument to http_serve(port, handler) is + * treated as a string name (or any el_val_t — the runtime ignores its + * value and uses the registry). Callers register a C-level handler via + * + * extern void el_runtime_register_handler(const char* name, + * el_val_t (*fn)(el_val_t, + * el_val_t, + * el_val_t)); + * + * and select the active handler by calling http_set_handler("name") from + * El, or by setting it directly through the C registry. If no handler is + * registered, the server replies with a 200 carrying a default message so + * the loop is observable. + */ + +/* ── JSON error helper (used by HTTP, PQ, crypto stubs) ─────────────────── */ + +/* JSON-escape an arbitrary C string into an allocated buffer. */ +static char* json_escape_alloc(const char* s) { + if (!s) return el_strdup(""); + JsonBuf b; jb_init(&b); + for (const char* p = s; *p; p++) { + unsigned char c = (unsigned char)*p; + switch (c) { + case '"': jb_puts(&b, "\\\""); break; + case '\\': jb_puts(&b, "\\\\"); break; + case '\n': jb_puts(&b, "\\n"); break; + case '\r': jb_puts(&b, "\\r"); break; + case '\t': jb_puts(&b, "\\t"); break; + default: + if (c < 0x20) { + char tmp[8]; snprintf(tmp, sizeof(tmp), "\\u%04x", c); + jb_puts(&b, tmp); + } else jb_putc(&b, (char)c); + } + } + return b.buf; +} + +static el_val_t http_error_json(const char* msg) { + char* esc = json_escape_alloc(msg ? msg : "unknown error"); + char* buf = el_strbuf(strlen(esc) + 16); + sprintf(buf, "{\"error\":\"%s\"}", esc); + free(esc); + return el_wrap_str(buf); +} + +#ifdef HAVE_CURL +/* ── HTTP client write-callback buffer ───────────────────────────────────── */ + +typedef struct { + char* data; + size_t len; + size_t cap; +} HttpBuf; + +static void httpbuf_init(HttpBuf* b) { + b->cap = 1024; + b->len = 0; + b->data = malloc(b->cap); + if (!b->data) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + b->data[0] = '\0'; +} + +static void httpbuf_append(HttpBuf* b, const void* src, size_t n) { + if (b->len + n + 1 > b->cap) { + while (b->len + n + 1 > b->cap) b->cap *= 2; + b->data = realloc(b->data, b->cap); + if (!b->data) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + } + memcpy(b->data + b->len, src, n); + b->len += n; + b->data[b->len] = '\0'; +} + +static size_t http_write_cb(char* ptr, size_t size, size_t nmemb, void* ud) { + size_t n = size * nmemb; + httpbuf_append((HttpBuf*)ud, ptr, n); + return n; +} + +/* HTTP timeout (ms) — read once from EL_HTTP_TIMEOUT_MS, default 60000. + * Applied via CURLOPT_TIMEOUT_MS on every libcurl request. */ +static long _el_http_timeout_ms = -1; +static long el_http_timeout_ms(void) { + long v = __atomic_load_n(&_el_http_timeout_ms, __ATOMIC_ACQUIRE); + if (v >= 0) return v; + const char* s = getenv("EL_HTTP_TIMEOUT_MS"); + long parsed = 60000L; + if (s && *s) { + char* end = NULL; + long n = strtol(s, &end, 10); + if (end != s && n > 0) parsed = n; + } + __atomic_store_n(&_el_http_timeout_ms, parsed, __ATOMIC_RELEASE); + return parsed; +} + +/* Internal: do a libcurl request; takes optional body/headers, optional method override. */ +static el_val_t http_do(const char* method, const char* url, const char* body, + struct curl_slist* extra_headers) { + if (!url || !*url) return http_error_json("empty url"); + CURL* c = curl_easy_init(); + if (!c) return http_error_json("curl_easy_init failed"); + HttpBuf rb; httpbuf_init(&rb); + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, http_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, &rb); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, el_http_timeout_ms()); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-runtime/1.0"); + if (extra_headers) curl_easy_setopt(c, CURLOPT_HTTPHEADER, extra_headers); + if (method && strcmp(method, "POST") == 0) { + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, body ? body : ""); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(body ? strlen(body) : 0)); + } else if (method && strcmp(method, "DELETE") == 0) { + curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, "DELETE"); + } + CURLcode rc = curl_easy_perform(c); + curl_easy_cleanup(c); + if (rc != CURLE_OK) { + free(rb.data); + const char* m = errbuf[0] ? errbuf : curl_easy_strerror(rc); + return http_error_json(m); + } + return el_wrap_str(rb.data); +} + +el_val_t http_get(el_val_t url) { + return http_do("GET", EL_CSTR(url), NULL, NULL); +} + +el_val_t http_post(el_val_t url, el_val_t body) { + return http_do("POST", EL_CSTR(url), EL_CSTR(body), NULL); +} + +el_val_t http_post_json(el_val_t url, el_val_t json_body) { + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + el_val_t r = http_do("POST", EL_CSTR(url), EL_CSTR(json_body), h); + curl_slist_free_all(h); + return r; +} + +/* Build a curl_slist from an ElMap of name -> value strings. */ +static struct curl_slist* headers_from_map(el_val_t headers_map) { + struct curl_slist* h = NULL; + ElMap* m = as_map(headers_map); + if (!m) return NULL; + for (int64_t i = 0; i < m->count; i++) { + const char* k = EL_CSTR(m->keys[i]); + const char* v = EL_CSTR(m->values[i]); + if (!k || !v) continue; + size_t n = strlen(k) + strlen(v) + 4; + char* line = malloc(n); + if (!line) continue; + snprintf(line, n, "%s: %s", k, v); + h = curl_slist_append(h, line); + free(line); + } + return h; +} + +el_val_t http_get_with_headers(el_val_t url, el_val_t headers_map) { + struct curl_slist* h = headers_from_map(headers_map); + el_val_t r = http_do("GET", EL_CSTR(url), NULL, h); + if (h) curl_slist_free_all(h); + return r; +} + +el_val_t http_post_with_headers(el_val_t url, el_val_t body, el_val_t headers_map) { + struct curl_slist* h = headers_from_map(headers_map); + el_val_t r = http_do("POST", EL_CSTR(url), EL_CSTR(body), h); + if (h) curl_slist_free_all(h); + return r; +} + +/* http_post_json_with_headers — POST with Content-Type: application/json plus + * any additional headers supplied as an El map. Combines http_post_json and + * http_post_with_headers: the Content-Type header is always prepended so + * callers do not have to include it in their map. */ +el_val_t http_post_json_with_headers(el_val_t url, el_val_t headers_map, el_val_t json_body) { + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + /* Append caller-supplied headers from the map */ + ElMap* m = as_map(headers_map); + if (m) { + for (int64_t i = 0; i < m->count; i++) { + const char* k = EL_CSTR(m->keys[i]); + const char* v = EL_CSTR(m->values[i]); + if (!k || !v) continue; + size_t n = strlen(k) + strlen(v) + 4; + char* line = malloc(n); + if (!line) continue; + snprintf(line, n, "%s: %s", k, v); + h = curl_slist_append(h, line); + free(line); + } + } + el_val_t r = http_do("POST", EL_CSTR(url), EL_CSTR(json_body), h); + curl_slist_free_all(h); + return r; +} + +el_val_t http_post_form_auth(el_val_t url, el_val_t form_body, el_val_t auth_header) { + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/x-www-form-urlencoded"); + const char* a = EL_CSTR(auth_header); + if (a && *a) { + size_t n = strlen(a) + 32; + char* line = malloc(n); + snprintf(line, n, "Authorization: %s", a); + h = curl_slist_append(h, line); + free(line); + } + el_val_t r = http_do("POST", EL_CSTR(url), EL_CSTR(form_body), h); + curl_slist_free_all(h); + return r; +} + +/* HTTP DELETE — mirrors http_post but with CURLOPT_CUSTOMREQUEST=DELETE. + * Returns response body on success; on transport failure returns an error + * JSON fragment (same convention as http_get/http_post). Callers that + * expect "" on failure should check for a leading '{' and an "error" key. */ +el_val_t http_delete(el_val_t url) { + return http_do("DELETE", EL_CSTR(url), NULL, NULL); +} + +/* ── HTTP → file streaming ──────────────────────────────────────────────── + * + * Why this exists: el_val_t strings are NUL-terminated by convention, so + * accumulating an HTTP response into an httpbuf and then wrapping its + * `.data` pointer with el_wrap_str() loses the byte length. Any consumer + * that does strlen() on the wrapped pointer truncates the body at the + * first embedded NUL. Audio (MP3, WAV, OGG), images (PNG, JPEG), and any + * other binary payload hits this. The vessels that download such bodies + * (e.g. ElevenLabs TTS → MP3) get silently corrupted files. + * + * The fix: wire libcurl's CURLOPT_WRITEFUNCTION directly to fwrite() + * against a fopen()-ed FILE*. The bytes never pass through an el_val_t + * string, so embedded NULs are preserved verbatim. Caller's contract is + * just "a file at this path with the response body in it". */ + +static size_t http_file_write_cb(char* ptr, size_t size, size_t nmemb, void* ud) { + FILE* f = (FILE*)ud; + return fwrite(ptr, size, nmemb, f); +} + +/* Internal: stream body to file. method is "GET" or "POST". body may be NULL + * (GET) or NUL-terminated (POST). headers may be NULL. Returns 1/0. */ +static el_val_t http_do_to_file(const char* method, const char* url, + const char* body, struct curl_slist* extra_headers, + const char* output_path) { + if (!url || !*url) return 0; + if (!output_path || !*output_path) return 0; + FILE* f = fopen(output_path, "wb"); + if (!f) return 0; + + CURL* c = curl_easy_init(); + if (!c) { fclose(f); remove(output_path); return 0; } + + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, http_file_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, f); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, el_http_timeout_ms()); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-runtime/1.0"); + curl_easy_setopt(c, CURLOPT_FAILONERROR, 1L); /* 4xx/5xx → CURLE_HTTP_RETURNED_ERROR */ + if (extra_headers) curl_easy_setopt(c, CURLOPT_HTTPHEADER, extra_headers); + + if (method && strcmp(method, "POST") == 0) { + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, body ? body : ""); + /* For the request body we still rely on strlen — POST bodies are + * caller-controlled and JSON/text in every known El use case. + * If a future caller needs a binary POST body, add a *_bytes + * variant that takes an explicit length, mirroring fs_write_bytes. */ + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(body ? strlen(body) : 0)); + } + + CURLcode rc = curl_easy_perform(c); + curl_easy_cleanup(c); + + /* Flush + close before signalling success, so the file is fully on disk + * by the time the caller reads back. */ + int flush_ok = (fflush(f) == 0); + int close_ok = (fclose(f) == 0); + + if (rc != CURLE_OK || !flush_ok || !close_ok) { + remove(output_path); + return 0; + } + return 1; +} + +el_val_t http_get_to_file(el_val_t url, el_val_t headers_map, el_val_t output_path) { + struct curl_slist* h = headers_from_map(headers_map); + el_val_t r = http_do_to_file("GET", EL_CSTR(url), NULL, h, EL_CSTR(output_path)); + if (h) curl_slist_free_all(h); + return r; +} + +el_val_t http_post_to_file(el_val_t url, el_val_t body, el_val_t headers_map, el_val_t output_path) { + struct curl_slist* h = headers_from_map(headers_map); + el_val_t r = http_do_to_file("POST", EL_CSTR(url), EL_CSTR(body), h, EL_CSTR(output_path)); + if (h) curl_slist_free_all(h); + return r; +} +#endif /* HAVE_CURL */ + +/* ── HTTP server (POSIX sockets + pthreads) ──────────────────────────────── */ + +#define HTTP_MAX_CONNS 64 + +typedef el_val_t (*http_handler_fn)(el_val_t method, el_val_t path, el_val_t body); + +typedef struct { + char* name; + http_handler_fn fn; +} HttpHandlerEntry; + +static HttpHandlerEntry _http_handlers[32]; +static size_t _http_handler_count = 0; +static char* _http_active_handler = NULL; +static pthread_mutex_t _http_handler_mu = PTHREAD_MUTEX_INITIALIZER; + +static pthread_mutex_t _http_conn_mu = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t _http_conn_cv = PTHREAD_COND_INITIALIZER; +static int _http_conn_active = 0; + +/* Public C-level API: register a handler by name. Programs that want El + * `http_serve` to dispatch into their handler call this from main() before + * http_serve. Not declared in the header to keep the public API minimal — + * extern lookup works since C symbols are global. */ +void el_runtime_register_handler(const char* name, http_handler_fn fn); +void el_runtime_register_handler(const char* name, http_handler_fn fn) { + if (!name || !fn) return; + pthread_mutex_lock(&_http_handler_mu); + for (size_t i = 0; i < _http_handler_count; i++) { + if (strcmp(_http_handlers[i].name, name) == 0) { + _http_handlers[i].fn = fn; + pthread_mutex_unlock(&_http_handler_mu); + return; + } + } + if (_http_handler_count < sizeof(_http_handlers) / sizeof(_http_handlers[0])) { + _http_handlers[_http_handler_count].name = el_strdup(name); + _http_handlers[_http_handler_count].fn = fn; + _http_handler_count++; + } + pthread_mutex_unlock(&_http_handler_mu); +} + +el_val_t http_set_handler(el_val_t name) { + const char* n = EL_CSTR(name); + pthread_mutex_lock(&_http_handler_mu); + free(_http_active_handler); + _http_active_handler = el_strdup(n ? n : ""); + /* If the name is not yet in the registry, try dlsym lookup against + * the running binary's symbol table. Every El `fn name(...)` compiles + * to a global C symbol with that exact name, so El programs can self- + * register their own handlers just by calling http_set_handler("name"). */ + if (n && *n) { + int found = 0; + for (size_t i = 0; i < _http_handler_count; i++) { + if (strcmp(_http_handlers[i].name, n) == 0) { found = 1; break; } + } + if (!found) { + void* sym = dlsym(RTLD_DEFAULT, n); + if (sym && _http_handler_count < sizeof(_http_handlers) / sizeof(_http_handlers[0])) { + _http_handlers[_http_handler_count].name = el_strdup(n); + _http_handlers[_http_handler_count].fn = (http_handler_fn)sym; + _http_handler_count++; + } + } + } + pthread_mutex_unlock(&_http_handler_mu); + return 0; +} + +static http_handler_fn http_lookup_active(void) { + http_handler_fn out = NULL; + pthread_mutex_lock(&_http_handler_mu); + if (_http_active_handler) { + for (size_t i = 0; i < _http_handler_count; i++) { + if (strcmp(_http_handlers[i].name, _http_active_handler) == 0) { + out = _http_handlers[i].fn; break; + } + } + } + pthread_mutex_unlock(&_http_handler_mu); + return out; +} + +/* Auto-detect Content-Type from response body. */ +static const char* http_detect_content_type(const char* body) { + if (!body) return "text/plain; charset=utf-8"; + const char* p = body; + /* Binary magic bytes — check before stripping whitespace */ + if ((unsigned char)p[0] == 0x89 && p[1]=='P' && p[2]=='N' && p[3]=='G') + return "image/png"; + if ((unsigned char)p[0] == 0xFF && (unsigned char)p[1] == 0xD8) + return "image/jpeg"; + if (strncmp(p, "GIF8", 4) == 0) return "image/gif"; + if (strncmp(p, "RIFF", 4) == 0) return "image/webp"; + if (strncmp(p, "wOFF", 4) == 0) return "font/woff"; + if (strncmp(p, "wOF2", 4) == 0) return "font/woff2"; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (strncasecmp(p, "= cap) { + if (cap >= 1024 * 1024) { free(buf); return -1; } + cap *= 2; + buf = realloc(buf, cap); + if (!buf) return -1; + } + ssize_t n = recv(fd, buf + len, cap - len - 1, 0); + if (n <= 0) { free(buf); return -1; } + len += (size_t)n; + buf[len] = '\0'; + if (strstr(buf, "\r\n\r\n")) break; + } + /* Parse request line */ + char* sp1 = strchr(buf, ' '); + if (!sp1) { free(buf); return -1; } + *sp1 = '\0'; + *out_method = el_strdup(buf); + char* path_start = sp1 + 1; + char* sp2 = strchr(path_start, ' '); + if (!sp2) { free(*out_method); *out_method = NULL; free(buf); return -1; } + *sp2 = '\0'; + *out_path = el_strdup(path_start); + char* hdr_end = strstr(sp2 + 1, "\r\n\r\n"); + /* Capture the raw header block (after the request line's CRLF, up to + * but not including the terminating \r\n\r\n) for callers that asked + * for it. The legacy 3-arg path passes NULL and skips this. */ + if (out_headers_block) { + char* hdr_start = strstr(sp2 + 1, "\r\n"); + if (hdr_start && hdr_start < hdr_end) { + hdr_start += 2; + size_t hb_len = (size_t)(hdr_end - hdr_start); + char* hb = malloc(hb_len + 1); + if (hb) { + memcpy(hb, hdr_start, hb_len); + hb[hb_len] = '\0'; + *out_headers_block = hb; + } + } else { + *out_headers_block = el_strdup(""); + } + } + /* Find Content-Length */ + long content_length = 0; + char* hp = sp2 + 1; + while (hp < hdr_end) { + char* line_end = strstr(hp, "\r\n"); + /* line_end == hdr_end means we're on the LAST header line — its + * trailing \r\n is the same \r\n that begins the \r\n\r\n header + * terminator. Process this line; only stop when line_end is past + * hdr_end (which means the parser walked off the end of the + * header block). The previous condition (line_end >= hdr_end) + * silently dropped any Content-Length that appeared as the last + * header — exactly what real curl/clients tend to emit. */ + if (!line_end || line_end > hdr_end) break; + if (strncasecmp(hp, "Content-Length:", 15) == 0) { + content_length = strtol(hp + 15, NULL, 10); + if (content_length < 0) content_length = 0; + if (content_length > 64 * 1024 * 1024) content_length = 64 * 1024 * 1024; + } + hp = line_end + 2; + } + /* Body: any bytes already read past hdr_end, plus more recv */ + char* body_start = hdr_end + 4; + size_t body_have = (buf + len) - body_start; + char* body = malloc((size_t)content_length + 1); + if (!body) { free(*out_method); free(*out_path); *out_method=NULL; *out_path=NULL; free(buf); return -1; } + if ((long)body_have > content_length) body_have = (size_t)content_length; + if (body_have > 0) memcpy(body, body_start, body_have); + while ((long)body_have < content_length) { + ssize_t n = recv(fd, body + body_have, (size_t)content_length - body_have, 0); + if (n <= 0) break; + body_have += (size_t)n; + } + body[body_have] = '\0'; + *out_body = body; + free(buf); + return 0; +} + +/* Reason phrase for common HTTP statuses. Falls back to "Status" for the + * long tail — clients only care about the numeric code. */ +static const char* http_reason_phrase(int status) { + switch (status) { + case 200: return "OK"; + case 201: return "Created"; + case 202: return "Accepted"; + case 204: return "No Content"; + case 301: return "Moved Permanently"; + case 302: return "Found"; + case 303: return "See Other"; + case 304: return "Not Modified"; + case 307: return "Temporary Redirect"; + case 308: return "Permanent Redirect"; + case 400: return "Bad Request"; + case 401: return "Unauthorized"; + case 403: return "Forbidden"; + case 404: return "Not Found"; + case 405: return "Method Not Allowed"; + case 409: return "Conflict"; + case 410: return "Gone"; + case 422: return "Unprocessable Entity"; + case 429: return "Too Many Requests"; + case 500: return "Internal Server Error"; + case 501: return "Not Implemented"; + case 502: return "Bad Gateway"; + case 503: return "Service Unavailable"; + case 504: return "Gateway Timeout"; + default: return "Status"; + } +} + +/* Best-effort send with retry on partial writes. */ +static int http_send_all(int fd, const char* p, size_t left) { + while (left > 0) { + ssize_t w = send(fd, p, left, 0); + if (w <= 0) return -1; + p += w; left -= (size_t)w; + } + return 0; +} + +/* Discriminator that http_response() embeds at the start of its envelope. + * A handler returning a string starting with this exact prefix is treated + * as a structured response; anything else is treated as a raw body. */ +#define EL_HTTP_RESPONSE_TAG "{\"el_http_response\":1" + +/* Keys that conflict with runtime-managed headers are silently dropped to + * avoid double-emission — the runtime always emits its own Content-Length + * and Connection: close. Content-Type from the envelope IS allowed and + * overrides auto-detection. */ +static int http_header_is_managed(const char* k) { + return strcasecmp(k, "Content-Length") == 0 + || strcasecmp(k, "Connection") == 0; +} + +/* Walk an ElMap of header pairs and emit each as `K: V\r\n` into JsonBuf b. + * Sets *out_saw_content_type to 1 if the map contained an explicit + * Content-Type so the caller can skip auto-detection. */ +static void http_emit_headers_from_map(JsonBuf* b, el_val_t headers_map, + int* out_saw_content_type) { + *out_saw_content_type = 0; + if (headers_map == 0) return; + ElMap* m = (ElMap*)(uintptr_t)headers_map; + if (!m || m->hdr.magic != EL_MAGIC_MAP) return; + for (int64_t i = 0; i < m->count; i++) { + const char* k = EL_CSTR(m->keys[i]); + const char* v = EL_CSTR(m->values[i]); + if (!k || !v) continue; + if (http_header_is_managed(k)) continue; + if (strcasecmp(k, "Content-Type") == 0) *out_saw_content_type = 1; + jb_puts(b, k); + jb_puts(b, ": "); + jb_puts(b, v); + jb_puts(b, "\r\n"); + } +} + +/* Parse the envelope produced by http_response(). On success returns 1 and + * populates *out_status, *out_headers_map (an ElMap el_val_t — caller must + * el_release), and *out_body (allocated). On failure returns 0. + * + * Implementation: feeds the entire envelope through the recursive-descent + * JSON parser (which builds proper ElMap/ElList values), then pulls the + * three top-level fields by name. Avoids re-stringifying the headers map + * since json_stringify() does not support nested objects. */ +static int http_parse_envelope(const char* s, int* out_status, + el_val_t* out_headers_map, char** out_body, + el_val_t* out_parsed_root) { + if (!s) return 0; + if (strncmp(s, EL_HTTP_RESPONSE_TAG, + sizeof(EL_HTTP_RESPONSE_TAG) - 1) != 0) return 0; + + el_val_t parsed = json_parse(EL_STR(s)); + if (parsed == EL_NULL) return 0; + + int status = 200; + el_val_t hmap = 0; + char* body = NULL; + + el_val_t sv = el_map_get(parsed, EL_STR("status")); + if (sv != 0) { + /* status comes back as an integer — el_val_t holds it directly. */ + long sc = (long)sv; + if (sc >= 100 && sc <= 599) status = (int)sc; + } + + el_val_t hv = el_map_get(parsed, EL_STR("headers")); + if (hv != 0) { + ElMap* hm = (ElMap*)(uintptr_t)hv; + if (hm && hm->hdr.magic == EL_MAGIC_MAP) hmap = hv; + } + + el_val_t bv = el_map_get(parsed, EL_STR("body")); + if (bv != 0) { + const char* bs = EL_CSTR(bv); + if (bs) body = el_strdup(bs); + } + if (!body) body = el_strdup(""); + + *out_status = status; + *out_headers_map = hmap; + *out_body = body; + *out_parsed_root = parsed; /* caller releases to free hmap + entries */ + return 1; +} + +/* Lightweight `__status__` envelope: if the body's first key is `__status__` + * and its value is a numeric literal, lift the status to the HTTP layer and + * strip the marker from the body before sending. This is the common case for + * El handlers that want to return 4xx/5xx without going through + * http_response() — they just prepend `{"__status__":,...}` to the JSON + * they were already returning. + * + * We deliberately recognise ONLY the first-key form so the contract is cheap + * to detect and unambiguous: `{"__status__":401,"error":"unauthorized"}` is + * an envelope, but `{"error":"...","__status__":401}` is not. Product code + * controls placement. + * + * On success returns 1 with *out_status set and *out_body_alloc populated + * with a freshly malloc'd body (caller frees). On failure returns 0 and + * leaves outputs untouched. */ +static int http_parse_status_envelope(const char* s, int* out_status, + char** out_body_alloc) { + if (!s) return 0; + const char* p = s; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '{') return 0; + p++; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + static const char marker[] = "\"__status__\""; + size_t mlen = sizeof(marker) - 1; + if (strncmp(p, marker, mlen) != 0) return 0; + p += mlen; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != ':') return 0; + p++; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p < '0' || *p > '9') return 0; /* non-numeric -> not an envelope */ + int status = 0; + while (*p >= '0' && *p <= '9') { + status = status * 10 + (*p - '0'); + p++; + } + if (status < 100 || status > 599) return 0; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + /* Two trailing shapes accepted: + * ,"k":v,...} -> body becomes {"k":v,...} + * } -> body becomes {} + * Anything else (e.g. `:` re-appearing, garbage) drops the envelope so + * we don't strip what we shouldn't. */ + if (*p == '}') { + *out_status = status; + *out_body_alloc = el_strdup("{}"); + return 1; + } + if (*p != ',') return 0; + p++; /* skip the comma; the rest of the object follows */ + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + /* Build the trimmed body: '{' + remainder. */ + size_t rest_len = strlen(p); + char* out = (char*)malloc(rest_len + 2); + if (!out) return 0; + out[0] = '{'; + memcpy(out + 1, p, rest_len); + out[rest_len + 1] = '\0'; + *out_status = status; + *out_body_alloc = out; + return 1; +} + +/* Send a fully-built HTTP response. If `body` starts with the envelope tag, + * unpack status/headers/body. Otherwise emit the historical 200-OK with + * auto-detected Content-Type. */ +/* Thread-local flag: if 1, http_send_response writes status + headers but + * NO body (HEAD method behaviour). Set by http_worker before calling + * http_send_response, cleared after. */ +static __thread int _tl_http_head_only = 0; + +static void http_send_response(int fd, const char* body) { + if (!body) body = ""; + + int status = 200; + el_val_t env_headers_map = 0; + char* env_body = NULL; + el_val_t env_parsed_root = 0; + int is_envelope = http_parse_envelope(body, &status, + &env_headers_map, &env_body, + &env_parsed_root); + + /* If the rich http_response() envelope didn't claim this body, try the + * lightweight `__status__` form. This second envelope is malloc-backed so + * we route it through env_body and let the existing cleanup path free it + * — same lifetime contract, no special case at the bottom of the + * function. */ + if (!is_envelope) { + char* trimmed = NULL; + if (http_parse_status_envelope(body, &status, &trimmed)) { + env_body = trimmed; + is_envelope = 1; + } + } + + const char* eff_body = is_envelope ? env_body : body; + /* Use the real byte count from fs_read if available (handles binary files + * with embedded null bytes — PNG, WOFF2, etc.). Fall back to strlen for + * normal text/JSON responses where _tl_fs_read_len is 0. */ + size_t blen = (_tl_fs_read_len > 0) ? _tl_fs_read_len : strlen(eff_body); + _tl_fs_read_len = 0; /* consume — one-shot per response */ + int head_only = _tl_http_head_only; + + JsonBuf hdrs; jb_init(&hdrs); + int saw_content_type = 0; + if (is_envelope) { + http_emit_headers_from_map(&hdrs, env_headers_map, + &saw_content_type); + } + if (!saw_content_type) { + jb_puts(&hdrs, "Content-Type: "); + jb_puts(&hdrs, http_detect_content_type(eff_body)); + jb_puts(&hdrs, "\r\n"); + } + + char status_line[64]; + int sl = snprintf(status_line, sizeof(status_line), + "HTTP/1.1 %d %s\r\n", + status, http_reason_phrase(status)); + if (sl < 0) { + if (env_parsed_root) el_release(env_parsed_root); + free(env_body); free(hdrs.buf); return; + } + + char tail[128]; + int tl = snprintf(tail, sizeof(tail), + "Content-Length: %zu\r\n" + "Connection: close\r\n" + "\r\n", blen); + if (tl < 0) { + if (env_parsed_root) el_release(env_parsed_root); + free(env_body); free(hdrs.buf); return; + } + + if (http_send_all(fd, status_line, (size_t)sl) == 0 + && http_send_all(fd, hdrs.buf, hdrs.len) == 0 + && http_send_all(fd, tail, (size_t)tl) == 0 + && (head_only + /* HEAD requests echo headers + Content-Length but no body. */ + ? 1 + : http_send_all(fd, eff_body, blen) == 0)) { + /* sent successfully */ + } + + if (env_parsed_root) el_release(env_parsed_root); + free(env_body); + free(hdrs.buf); +} + +typedef struct { + int fd; +} HttpWorkerArg; + +static void* http_worker(void* arg) { + HttpWorkerArg* a = (HttpWorkerArg*)arg; + int fd = a->fd; + free(a); + char *method = NULL, *path = NULL, *body = NULL; + if (http_read_request(fd, &method, &path, &body, NULL) == 0) { + http_handler_fn h = http_lookup_active(); + char* response = NULL; + /* HEAD: dispatch as GET so existing handlers respond with the same + * body, but flag the response writer to emit headers only. RFC 9110 + * requires HEAD to mirror GET headers + Content-Length without body. */ + int head_only = (method && strcmp(method, "HEAD") == 0); + const char* dispatch_method = head_only ? "GET" : method; + el_request_start(); /* begin per-request arena */ + if (h) { + el_val_t r = h(EL_STR(dispatch_method), EL_STR(path), EL_STR(body)); + const char* rs = EL_CSTR(r); + /* Copy response out BEFORE arena teardown. + * For binary files, _tl_fs_read_len holds the real byte count — + * use memcpy instead of strdup so null bytes are preserved. */ + size_t rlen = _tl_fs_read_len > 0 ? _tl_fs_read_len : (rs ? strlen(rs) : 0); + response = malloc(rlen + 1); + if (response && rs) { memcpy(response, rs, rlen); response[rlen] = '\0'; } + else if (response) { response[0] = '\0'; } + } else { + response = el_strdup_persist("el-runtime: no http handler registered"); + } + el_request_end(); /* free all intermediate strings */ + _tl_http_head_only = head_only; + http_send_response(fd, response); + _tl_http_head_only = 0; + free(response); + } + free(method); free(path); free(body); + close(fd); + /* release a slot */ + pthread_mutex_lock(&_http_conn_mu); + _http_conn_active--; + pthread_cond_signal(&_http_conn_cv); + pthread_mutex_unlock(&_http_conn_mu); + return NULL; +} + +el_val_t http_serve(el_val_t port, el_val_t handler) { + /* If `handler` looks like a string name, register it as the active handler. */ + const char* hname = EL_CSTR(handler); + if (hname && looks_like_string(handler)) { + http_set_handler(handler); + } + int p = (int)port; + if (p <= 0 || p > 65535) { fprintf(stderr, "http_serve: invalid port %d\n", p); return 0; } + /* Dual-stack: AF_INET6 with IPV6_V6ONLY=0 accepts both IPv4 and IPv6. + * This makes `localhost` work in browsers that resolve it to ::1 first. */ + int sock = socket(AF_INET6, SOCK_STREAM, 0); + if (sock < 0) { perror("socket"); return 0; } + int yes = 1; int no = 0; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no)); + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr = in6addr_any; + addr.sin6_port = htons((uint16_t)p); + if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + perror("bind"); close(sock); return 0; + } + if (listen(sock, 64) < 0) { perror("listen"); close(sock); return 0; } + fprintf(stderr, "[http] listening on [::]:%d (dual-stack)\n", p); + while (1) { + struct sockaddr_in6 cli; + socklen_t clen = sizeof(cli); + int cfd = accept(sock, (struct sockaddr*)&cli, &clen); + if (cfd < 0) { + if (errno == EINTR) continue; + perror("accept"); break; + } + pthread_mutex_lock(&_http_conn_mu); + while (_http_conn_active >= HTTP_MAX_CONNS) { + pthread_cond_wait(&_http_conn_cv, &_http_conn_mu); + } + _http_conn_active++; + pthread_mutex_unlock(&_http_conn_mu); + HttpWorkerArg* arg = malloc(sizeof(HttpWorkerArg)); + if (!arg) { close(cfd); continue; } + arg->fd = cfd; + pthread_t tid; + if (pthread_create(&tid, NULL, http_worker, arg) != 0) { + close(cfd); free(arg); + pthread_mutex_lock(&_http_conn_mu); + _http_conn_active--; + pthread_cond_signal(&_http_conn_cv); + pthread_mutex_unlock(&_http_conn_mu); + continue; + } + pthread_detach(tid); + } + close(sock); + return 0; +} + +/* ── HTTP server v2 — request headers + structured response ──────────────── */ +/* + * v2 widens the handler signature from + * (method, path, body) -> body_string + * to + * (method, path, headers_map, body) -> body_string_or_envelope + * + * The response envelope is detected uniformly inside http_send_response — so + * 4-arg handlers can return either a plain body or http_response(...). The + * 3-arg path stays untouched in spirit (its handlers still build plain + * bodies; the envelope tag, being `{"el_http_response":1`, will never + * collide with normal JSON the legacy server.el routes return). + * + * Registry is parallel to the 3-arg handler registry: separate name table, + * separate active-handler slot, separate dlsym fallback. Mixing v1 and v2 + * handlers in the same process is fine — they don't share the active slot. */ + +typedef el_val_t (*http_handler4_fn)(el_val_t method, el_val_t path, + el_val_t headers_map, el_val_t body); + +typedef struct { + char* name; + http_handler4_fn fn; +} HttpHandler4Entry; + +static HttpHandler4Entry _http_handlers4[32]; +static size_t _http_handler4_count = 0; +static char* _http_active_handler4 = NULL; + +void el_runtime_register_handler_v2(const char* name, http_handler4_fn fn); +void el_runtime_register_handler_v2(const char* name, http_handler4_fn fn) { + if (!name || !fn) return; + pthread_mutex_lock(&_http_handler_mu); + for (size_t i = 0; i < _http_handler4_count; i++) { + if (strcmp(_http_handlers4[i].name, name) == 0) { + _http_handlers4[i].fn = fn; + pthread_mutex_unlock(&_http_handler_mu); + return; + } + } + if (_http_handler4_count < + sizeof(_http_handlers4) / sizeof(_http_handlers4[0])) { + _http_handlers4[_http_handler4_count].name = el_strdup(name); + _http_handlers4[_http_handler4_count].fn = fn; + _http_handler4_count++; + } + pthread_mutex_unlock(&_http_handler_mu); +} + +el_val_t http_set_handler_v2(el_val_t name) { + const char* n = EL_CSTR(name); + pthread_mutex_lock(&_http_handler_mu); + free(_http_active_handler4); + _http_active_handler4 = el_strdup(n ? n : ""); + if (n && *n) { + int found = 0; + for (size_t i = 0; i < _http_handler4_count; i++) { + if (strcmp(_http_handlers4[i].name, n) == 0) { found = 1; break; } + } + if (!found) { + void* sym = dlsym(RTLD_DEFAULT, n); + if (sym && _http_handler4_count < + sizeof(_http_handlers4) / sizeof(_http_handlers4[0])) { + _http_handlers4[_http_handler4_count].name = el_strdup(n); + _http_handlers4[_http_handler4_count].fn = + (http_handler4_fn)sym; + _http_handler4_count++; + } + } + } + pthread_mutex_unlock(&_http_handler_mu); + return 0; +} + +static http_handler4_fn http_lookup_active_v2(void) { + http_handler4_fn out = NULL; + pthread_mutex_lock(&_http_handler_mu); + if (_http_active_handler4) { + for (size_t i = 0; i < _http_handler4_count; i++) { + if (strcmp(_http_handlers4[i].name, + _http_active_handler4) == 0) { + out = _http_handlers4[i].fn; break; + } + } + } + pthread_mutex_unlock(&_http_handler_mu); + return out; +} + +/* Build an ElMap from the raw header block produced by http_read_request. + * Keys are lowercased (RFC 7230 — case-insensitive); values have leading + * whitespace trimmed. Repeated headers with the same name are joined with + * ", " in arrival order, matching standard library behaviour elsewhere. */ +static el_val_t http_build_headers_map(const char* hdr_block) { + el_val_t m = el_map_new(0); + if (!hdr_block || !*hdr_block) return m; + const char* p = hdr_block; + while (*p) { + const char* line_end = strstr(p, "\r\n"); + const char* end = line_end ? line_end : p + strlen(p); + const char* colon = NULL; + for (const char* c = p; c < end; c++) { + if (*c == ':') { colon = c; break; } + } + if (colon && colon > p) { + size_t klen = (size_t)(colon - p); + char* key = malloc(klen + 1); + if (key) { + for (size_t i = 0; i < klen; i++) { + unsigned char ch = (unsigned char)p[i]; + key[i] = (char)tolower(ch); + } + key[klen] = '\0'; + const char* vstart = colon + 1; + while (vstart < end && (*vstart == ' ' || *vstart == '\t')) vstart++; + size_t vlen = (size_t)(end - vstart); + /* Strip trailing OWS just in case. */ + while (vlen > 0 + && (vstart[vlen - 1] == ' ' + || vstart[vlen - 1] == '\t')) vlen--; + /* Coalesce repeats: if key already present, append ", value". */ + el_val_t existing = el_map_get(m, EL_STR(key)); + if (existing != 0 && looks_like_string(existing)) { + const char* old = EL_CSTR(existing); + size_t olen = strlen(old); + char* combined = malloc(olen + 2 + vlen + 1); + if (combined) { + memcpy(combined, old, olen); + memcpy(combined + olen, ", ", 2); + memcpy(combined + olen + 2, vstart, vlen); + combined[olen + 2 + vlen] = '\0'; + m = el_map_set(m, EL_STR(key), EL_STR(combined)); + } + free(key); + } else { + char* val = malloc(vlen + 1); + if (val) { + memcpy(val, vstart, vlen); + val[vlen] = '\0'; + m = el_map_set(m, EL_STR(key), EL_STR(val)); + } else { + free(key); + } + } + } + } + if (!line_end) break; + p = line_end + 2; + } + return m; +} + +static void* http_worker_v2(void* arg) { + HttpWorkerArg* a = (HttpWorkerArg*)arg; + int fd = a->fd; + free(a); + char *method = NULL, *path = NULL, *body = NULL, *hdr_block = NULL; + if (http_read_request(fd, &method, &path, &body, &hdr_block) == 0) { + http_handler4_fn h = http_lookup_active_v2(); + char* response = NULL; + int head_only = (method && strcmp(method, "HEAD") == 0); + const char* dispatch_method = head_only ? "GET" : method; + el_request_start(); /* begin per-request arena */ + if (h) { + el_val_t hmap = http_build_headers_map(hdr_block ? hdr_block : ""); + el_val_t r = h(EL_STR(dispatch_method), EL_STR(path), hmap, EL_STR(body)); + const char* rs = EL_CSTR(r); + size_t rlen = _tl_fs_read_len > 0 ? _tl_fs_read_len : (rs ? strlen(rs) : 0); + response = malloc(rlen + 1); + if (response && rs) { memcpy(response, rs, rlen); response[rlen] = '\0'; } + else if (response) { response[0] = '\0'; } + el_release(hmap); + } else { + response = el_strdup_persist( + "el-runtime: no v2 http handler registered " + "(call http_set_handler_v2)"); + } + el_request_end(); /* free all intermediate strings */ + _tl_http_head_only = head_only; + http_send_response(fd, response); + _tl_http_head_only = 0; + free(response); + } + free(method); free(path); free(body); free(hdr_block); + close(fd); + pthread_mutex_lock(&_http_conn_mu); + _http_conn_active--; + pthread_cond_signal(&_http_conn_cv); + pthread_mutex_unlock(&_http_conn_mu); + return NULL; +} + +el_val_t http_serve_v2(el_val_t port, el_val_t handler) { + const char* hname = EL_CSTR(handler); + if (hname && looks_like_string(handler)) { + http_set_handler_v2(handler); + } + int p = (int)port; + if (p <= 0 || p > 65535) { + fprintf(stderr, "http_serve_v2: invalid port %d\n", p); + return 0; + } + /* Dual-stack: same as http_serve - AF_INET6 + IPV6_V6ONLY=0. */ + int sock = socket(AF_INET6, SOCK_STREAM, 0); + if (sock < 0) { perror("socket"); return 0; } + int yes = 1; int no = 0; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no)); + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_addr = in6addr_any; + addr.sin6_port = htons((uint16_t)p); + if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + perror("bind"); close(sock); return 0; + } + if (listen(sock, 64) < 0) { perror("listen"); close(sock); return 0; } + fprintf(stderr, "[http v2] listening on [::]:%d (dual-stack)\n", p); + while (1) { + struct sockaddr_in6 cli; + socklen_t clen = sizeof(cli); + int cfd = accept(sock, (struct sockaddr*)&cli, &clen); + if (cfd < 0) { + if (errno == EINTR) continue; + perror("accept"); break; + } + pthread_mutex_lock(&_http_conn_mu); + while (_http_conn_active >= HTTP_MAX_CONNS) { + pthread_cond_wait(&_http_conn_cv, &_http_conn_mu); + } + _http_conn_active++; + pthread_mutex_unlock(&_http_conn_mu); + HttpWorkerArg* arg = malloc(sizeof(HttpWorkerArg)); + if (!arg) { close(cfd); continue; } + arg->fd = cfd; + pthread_t tid; + if (pthread_create(&tid, NULL, http_worker_v2, arg) != 0) { + close(cfd); free(arg); + pthread_mutex_lock(&_http_conn_mu); + _http_conn_active--; + pthread_cond_signal(&_http_conn_cv); + pthread_mutex_unlock(&_http_conn_mu); + continue; + } + pthread_detach(tid); + } + close(sock); + return 0; +} + +/* Build the response envelope a 4-arg handler can return. We hand-write + * the JSON so the discriminator key always lands first — the runtime's + * http_parse_envelope() detects it via prefix match. headers_json must be + * either "" (empty), "{}" (empty object), or a well-formed JSON object + * literal; anything else will produce a malformed envelope and the runtime + * will treat the whole string as a plain body (no envelope detected). */ +el_val_t http_response(el_val_t status, el_val_t headers_json, el_val_t body) { + long sc = (long)status; + if (sc < 100 || sc > 599) sc = 200; + const char* hj = EL_CSTR(headers_json); + if (!hj || !*hj) hj = "{}"; + /* Light validation: must start with '{' and end with '}'. */ + size_t hlen = strlen(hj); + int hj_ok = (hlen >= 2 && hj[0] == '{' && hj[hlen - 1] == '}'); + if (!hj_ok) hj = "{}"; + const char* b = EL_CSTR(body); + if (!b) b = ""; + + JsonBuf out; jb_init(&out); + jb_puts(&out, EL_HTTP_RESPONSE_TAG); /* {"el_http_response":1 */ + jb_puts(&out, ",\"status\":"); + char num[32]; + snprintf(num, sizeof(num), "%ld", sc); + jb_puts(&out, num); + jb_puts(&out, ",\"headers\":"); + jb_puts(&out, hj); + jb_puts(&out, ",\"body\":"); + jb_emit_escaped(&out, b); + jb_putc(&out, '}'); + return el_wrap_str(out.buf); +} + +/* ── Filesystem ──────────────────────────────────────────────────────────── */ + +el_val_t fs_read(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + _tl_fs_read_len = 0; + if (!path) return el_wrap_str(el_strdup("")); + FILE* f = fopen(path, "rb"); + if (!f) return el_wrap_str(el_strdup("")); + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + if (sz < 0) { fclose(f); return el_wrap_str(el_strdup("")); } /* pipe/special file */ + char* buf = el_strbuf((size_t)sz); + size_t got = fread(buf, 1, (size_t)sz, f); + buf[got] = '\0'; + _tl_fs_read_len = got; /* store real byte count for binary-safe send */ + fclose(f); + return el_wrap_str(buf); +} + +el_val_t fs_write(el_val_t pathv, el_val_t contentv) { + const char* path = EL_CSTR(pathv); + const char* content = EL_CSTR(contentv); + if (!path || !content) return 0; + FILE* f = fopen(path, "wb"); + if (!f) return 0; + size_t n = strlen(content); + size_t written = fwrite(content, 1, n, f); + fclose(f); + return written == n ? 1 : 0; +} + +/* fs_write_bytes — explicit-length binary write. Bypasses strlen so embedded + * NULs survive. Caller must know the byte count (e.g. from base64_decode, + * or the fixed 32-byte sha256_bytes/hmac_sha256_bytes outputs). + * + * If `length` is negative, treats as failure. If `length` is 0, creates an + * empty file (still useful as a "touch with content" primitive). */ +el_val_t fs_write_bytes(el_val_t pathv, el_val_t bytesv, el_val_t lengthv) { + const char* path = EL_CSTR(pathv); + const char* bytes = EL_CSTR(bytesv); + int64_t n = (int64_t)lengthv; + if (!path || !bytes) return 0; + if (n < 0) return 0; + FILE* f = fopen(path, "wb"); + if (!f) return 0; + size_t written = (n > 0) ? fwrite(bytes, 1, (size_t)n, f) : 0; + int flush_ok = (fflush(f) == 0); + int close_ok = (fclose(f) == 0); + if (!flush_ok || !close_ok || written != (size_t)n) { + remove(path); + return 0; + } + return 1; +} + +// stdout_to_file / stdout_restore — redirect process stdout to a file and +// restore it. Used by the compiler's JS post-processing pipeline to capture +// codegen output before piping through terser / obfuscator. +#include +static int _el_saved_stdout_fd = -1; + +el_val_t stdout_to_file(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + if (!path) return (el_val_t)(int64_t)-1; + fflush(stdout); + _el_saved_stdout_fd = dup(STDOUT_FILENO); + int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd < 0) return (el_val_t)(int64_t)-1; + dup2(fd, STDOUT_FILENO); + close(fd); + return (el_val_t)(int64_t)0; +} + +el_val_t stdout_restore(void) { + if (_el_saved_stdout_fd >= 0) { + fflush(stdout); + dup2(_el_saved_stdout_fd, STDOUT_FILENO); + close(_el_saved_stdout_fd); + _el_saved_stdout_fd = -1; + } + return (el_val_t)(int64_t)0; +} + +// exec_command — run a shell command, return exit code (0 = success). +// Used by elb and other El tooling to invoke subprocesses. +el_val_t exec_command(el_val_t cmdv) { + const char* cmd = EL_CSTR(cmdv); + if (!cmd) return (el_val_t)(int64_t)-1; + int ret = system(cmd); + return (el_val_t)(int64_t)ret; +} + +// exec_capture — run a shell command, capture stdout, return as String. +// Returns "" on failure. +el_val_t exec_capture(el_val_t cmdv) { + const char* cmd = EL_CSTR(cmdv); + if (!cmd) return el_wrap_str(el_strdup("")); + FILE* f = popen(cmd, "r"); + if (!f) return el_wrap_str(el_strdup("")); + JsonBuf b; jb_init(&b); + char buf[4096]; + while (fgets(buf, sizeof(buf), f)) jb_puts(&b, buf); + pclose(f); + return el_wrap_str(b.buf); +} + +// exec — run a shell command via /bin/sh, capture stdout, return as String. +// Times out after 30 seconds. Returns "" on any error. +// El name: exec(cmd) -> String +el_val_t exec(el_val_t cmdv) { + const char* cmd = EL_CSTR(cmdv); + if (!cmd || !*cmd) return el_wrap_str(el_strdup("")); + /* Build a time-limited command: wrap with timeout(1) if available, + * otherwise rely on the 30s read loop guard below. We use the simple + * popen approach with a deadline measured by wall clock so the caller + * is never blocked indefinitely. */ + FILE* f = popen(cmd, "r"); + if (!f) return el_wrap_str(el_strdup("")); + JsonBuf b; jb_init(&b); + char buf[4096]; + /* 30-second wall-clock deadline */ + time_t deadline = time(NULL) + 30; + while (time(NULL) < deadline) { + if (fgets(buf, sizeof(buf), f) == NULL) break; + jb_puts(&b, buf); + } + pclose(f); + return el_wrap_str(b.buf); +} + +// exec_bg — run a shell command in background, return PID as String. +// The child process runs independently; the caller is not blocked. +// Returns "" on fork failure. +// El name: exec_bg(cmd) -> String +el_val_t exec_bg(el_val_t cmdv) { + const char* cmd = EL_CSTR(cmdv); + if (!cmd || !*cmd) return el_wrap_str(el_strdup("")); + pid_t pid = fork(); + if (pid < 0) { + /* fork failed */ + return el_wrap_str(el_strdup("")); + } + if (pid == 0) { + /* child: detach from parent's stdio, exec via shell */ + setsid(); + int devnull = open("/dev/null", O_RDWR); + if (devnull >= 0) { + dup2(devnull, STDIN_FILENO); + dup2(devnull, STDOUT_FILENO); + dup2(devnull, STDERR_FILENO); + close(devnull); + } + execl("/bin/sh", "sh", "-c", cmd, (char*)NULL); + _exit(127); + } + /* parent: convert pid to string and return immediately */ + char pidbuf[32]; + snprintf(pidbuf, sizeof(pidbuf), "%d", (int)pid); + return el_wrap_str(el_strdup(pidbuf)); +} + +el_val_t fs_list(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + el_val_t lst = el_list_empty(); + if (!path) return lst; + DIR* d = opendir(path); + if (!d) return lst; + struct dirent* e; + while ((e = readdir(d)) != NULL) { + if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) continue; + lst = el_list_append(lst, el_wrap_str(el_strdup(e->d_name))); + } + closedir(d); + return lst; +} + +/* fs_list_json — return directory entries as a JSON array of strings. + * Returns "[]" for missing or non-directory paths. Excludes "." and "..". */ +el_val_t fs_list_json(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + if (!path) return EL_STR("[]"); + DIR* d = opendir(path); + if (!d) return EL_STR("[]"); + /* Collect entries first so we can build the JSON in one pass. */ + char** names = NULL; + size_t count = 0, cap = 0; + struct dirent* e; + while ((e = readdir(d)) != NULL) { + if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) continue; + if (count >= cap) { + cap = cap ? cap * 2 : 16; + names = realloc(names, cap * sizeof(char*)); + if (!names) { closedir(d); return EL_STR("[]"); } + } + names[count++] = strdup(e->d_name); + } + closedir(d); + /* Build JSON array. */ + size_t sz = 3; /* "[]" + NUL */ + for (size_t i = 0; i < count; i++) sz += strlen(names[i]) * 2 + 6; /* conservative */ + char* buf = malloc(sz); + if (!buf) { for (size_t i = 0; i < count; i++) free(names[i]); free(names); return EL_STR("[]"); } + size_t pos = 0; + buf[pos++] = '['; + for (size_t i = 0; i < count; i++) { + if (i > 0) buf[pos++] = ','; + buf[pos++] = '"'; + for (const char* p = names[i]; *p; p++) { + if (*p == '"' || *p == '\\') buf[pos++] = '\\'; + else if (*p == '\n') { buf[pos++] = '\\'; buf[pos++] = 'n'; continue; } + else if (*p == '\t') { buf[pos++] = '\\'; buf[pos++] = 't'; continue; } + buf[pos++] = *p; + } + buf[pos++] = '"'; + free(names[i]); + } + free(names); + buf[pos++] = ']'; + buf[pos] = '\0'; + return el_wrap_str(buf); +} + +/* fs_exists — true iff stat(path) succeeds. Symlinks are followed. */ +el_val_t fs_exists(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + if (!path || !*path) return 0; + struct stat st; + return (el_val_t)(stat(path, &st) == 0 ? 1 : 0); +} + +/* fs_mkdir — create directory at path with mode 0755, mkdir -p semantics. + * Returns 1 if path exists or was created (incl. all parents); 0 on failure. + * Walks the path component-by-component so missing intermediate dirs are + * also created. An existing leaf is not an error. */ +el_val_t fs_mkdir(el_val_t pathv) { + const char* path = EL_CSTR(pathv); + if (!path || !*path) return 0; + size_t n = strlen(path); + char* buf = malloc(n + 1); + if (!buf) return 0; + memcpy(buf, path, n + 1); + /* Walk components; create each prefix in turn. */ + for (size_t i = 1; i <= n; i++) { + if (buf[i] == '/' || buf[i] == '\0') { + char saved = buf[i]; + buf[i] = '\0'; + if (buf[0] != '\0') { + if (mkdir(buf, 0755) != 0 && errno != EEXIST) { + /* Tolerate the case where this prefix exists as a non-dir + * only when stat says it's a directory. */ + struct stat st; + if (stat(buf, &st) != 0 || !S_ISDIR(st.st_mode)) { + free(buf); + return 0; + } + } + } + buf[i] = saved; + } + } + free(buf); + return 1; +} + +/* ── URL encoding ─────────────────────────────────────────────────────────── */ + +/* RFC 3986 percent-encoding for URL components (form bodies, query strings). + * Unreserved set: A-Z a-z 0-9 - _ . ~ — passed through verbatim. + * Everything else (including space) becomes %XX hex. */ +el_val_t url_encode(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + static const char hex[] = "0123456789ABCDEF"; + size_t n = strlen(s); + char* out = el_strbuf(n * 3); + size_t o = 0; + for (size_t i = 0; i < n; i++) { + unsigned char c = (unsigned char)s[i]; + if ((c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + c == '-' || c == '_' || c == '.' || c == '~') { + out[o++] = (char)c; + } else { + out[o++] = '%'; + out[o++] = hex[(c >> 4) & 0xF]; + out[o++] = hex[c & 0xF]; + } + } + out[o] = '\0'; + return el_wrap_str(out); +} + +/* Decode percent-encoded URL component. '+' becomes space (form-encoded); + * malformed %-escapes are emitted verbatim. */ +el_val_t url_decode(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + char* out = el_strbuf(n); + size_t o = 0; + for (size_t i = 0; i < n; i++) { + char c = s[i]; + if (c == '+') { + out[o++] = ' '; + } else if (c == '%' && i + 2 < n) { + char h1 = s[i + 1], h2 = s[i + 2]; + int v1 = (h1 >= '0' && h1 <= '9') ? h1 - '0' + : (h1 >= 'a' && h1 <= 'f') ? h1 - 'a' + 10 + : (h1 >= 'A' && h1 <= 'F') ? h1 - 'A' + 10 : -1; + int v2 = (h2 >= '0' && h2 <= '9') ? h2 - '0' + : (h2 >= 'a' && h2 <= 'f') ? h2 - 'a' + 10 + : (h2 >= 'A' && h2 <= 'F') ? h2 - 'A' + 10 : -1; + if (v1 >= 0 && v2 >= 0) { + out[o++] = (char)((v1 << 4) | v2); + i += 2; + } else { + out[o++] = c; + } + } else { + out[o++] = c; + } + } + out[o] = '\0'; + return el_wrap_str(out); +} + +/* ── html_raw ──────────────────────────────────────────────────────────────── + * Identity passthrough for raw HTML template interpolation. + * El's {raw(expr)} compiles to html_raw(expr) — the value is output as-is + * without any escaping. The caller is responsible for safety. + */ +el_val_t html_raw(el_val_t s) { + return s; +} + +/* ── html_escape ───────────────────────────────────────────────────────────── + * Escape < > " ' & for safe HTML text interpolation. + * El's {expr} in HTML templates compiles to html_escape(expr). + */ +el_val_t html_escape(el_val_t sv) { + const char* src = EL_CSTR(sv); + if (!src) return EL_STR(""); + size_t len = strlen(src); + /* Worst case: every byte → 6 chars (") */ + char* out = (char*)malloc(len * 6 + 1); + if (!out) return sv; + el_arena_track(out); + char* p = out; + for (size_t i = 0; i < len; i++) { + unsigned char c = (unsigned char)src[i]; + switch (c) { + case '&': memcpy(p, "&", 5); p += 5; break; + case '<': memcpy(p, "<", 4); p += 4; break; + case '>': memcpy(p, ">", 4); p += 4; break; + case '"': memcpy(p, """, 6); p += 6; break; + case '\'': memcpy(p, "'", 5); p += 5; break; + default: *p++ = (char)c; break; + } + } + *p = '\0'; + return el_wrap_str(out); +} + +/* ── HTML allowlist sanitizer ──────────────────────────────────────────────── + * el_html_sanitize(input, allowlist_json) + * + * Strict allowlist HTML cleaner. Replaces the older denylist patterns + * (str_replace cascades that wrapped dangerous tags in HTML comments and + * renamed `on*` attributes). The denylist approach is fragile: comment- + * wrapping can be re-broken by a literal `-->` inside an attacker-supplied + * attribute value, and every new attack vector requires a code change. + * + * Design: + * - Single-pass byte-level state machine. + * - Tag and attribute names are matched case-insensitively against the + * allowlist. Unknown tags are dropped entirely (the open and close + * markers are stripped; their inner text content survives, escaped). + * - A small set of "dangerous container" tags (script, style, iframe, + * object, embed, form, plus a few rarer ones) drop themselves AND + * their full subtree — text between `` is + * CDATA-like and must not be re-emitted as escaped text either. + * - Comments (), doctype (), CDATA (), + * and processing instructions () are dropped entirely. + * - Text content outside dropped subtrees is HTML-escaped (&, <, >, ", '). + * - Attribute values are unquoted/dequoted, then re-emitted with double + * quotes around the cleanly-escaped value. + * - For `` and any `src` attribute, the URL scheme is validated: + * only http:, https:, mailto:, fragment-only `#anchor`, or relative + * paths are allowed. Anything else (javascript:, data:, vbscript:, + * about:, file:, etc.) drops the attribute. + * - Self-closing void tags (br, hr, img, etc.) emit without a close tag. + * - Malformed input (unclosed tag at EOF, bad attribute syntax) drops + * the pending tag and continues. Pre-encoded entities (<, &, + * etc.) are passed through verbatim — the browser will decode them + * safely on render. + * + * Allowlist format (JSON string): + * {"p":[],"a":["href","title"],"strong":[],...} + * - Key = lowercase tag name. + * - Value = JSON array of allowed attribute names (lowercase). + * - Empty array means tag allowed but no attributes survive. + * + * Output is a freshly-allocated arena-tracked el_val_t string. */ + +/* Internal byte buffer with realloc-doubling. Used during sanitization; + * the final result is copied into an arena-tracked el_strbuf so the caller + * sees standard runtime memory semantics. */ +typedef struct { + char* data; + size_t len; + size_t cap; +} html_buf_t; + +static void html_buf_init(html_buf_t* b) { + b->cap = 256; + b->data = malloc(b->cap); + if (!b->data) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + b->len = 0; +} + +static void html_buf_grow(html_buf_t* b, size_t need) { + if (b->len + need + 1 <= b->cap) return; + size_t nc = b->cap; + while (b->len + need + 1 > nc) nc *= 2; + char* nd = realloc(b->data, nc); + if (!nd) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + b->data = nd; + b->cap = nc; +} + +static void html_buf_putc(html_buf_t* b, char c) { + html_buf_grow(b, 1); + b->data[b->len++] = c; +} + +static void html_buf_puts(html_buf_t* b, const char* s) { + if (!s) return; + size_t n = strlen(s); + html_buf_grow(b, n); + memcpy(b->data + b->len, s, n); + b->len += n; +} + +static void html_buf_free(html_buf_t* b) { + free(b->data); + b->data = NULL; + b->len = b->cap = 0; +} + +/* ASCII tolower, locale-independent. */ +static int html_tolower(int c) { + return (c >= 'A' && c <= 'Z') ? c + 32 : c; +} + +/* Case-insensitive ASCII compare of [a, a+n) against c-string `s`. + * Returns 1 iff lengths match and bytes are equal under tolower. */ +static int html_ieq_n(const char* a, size_t n, const char* s) { + if (!a || !s) return 0; + if (strlen(s) != n) return 0; + for (size_t i = 0; i < n; i++) { + if (html_tolower((unsigned char)a[i]) != html_tolower((unsigned char)s[i])) return 0; + } + return 1; +} + +/* Case-insensitive ASCII compare of two byte slices. */ +static int html_iemem(const char* a, const char* b, size_t n) { + for (size_t i = 0; i < n; i++) { + if (html_tolower((unsigned char)a[i]) != html_tolower((unsigned char)b[i])) return 0; + } + return 1; +} + +/* Walk a JSON allowlist object and find the value (an array) for a given + * tag key, comparing case-insensitively. On hit returns a pointer to the + * opening `[` of the array and writes the byte length of the array span + * (including the brackets) to *out_len. On miss returns NULL. + * + * The parser is intentionally tiny: it does not handle escapes inside + * keys (allowlist authors do not need them), and it relies on balanced + * brackets/quotes within the value array. */ +static const char* html_allowlist_find(const char* allow, const char* tag, + size_t tag_len, size_t* out_len) { + if (!allow) return NULL; + const char* p = allow; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '{') return NULL; + p++; + while (*p) { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p == '}' || *p == 0) return NULL; + if (*p != '"') return NULL; + p++; + const char* k = p; + while (*p && *p != '"') p++; + if (*p != '"') return NULL; + size_t klen = (size_t)(p - k); + p++; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != ':') return NULL; + p++; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') return NULL; + const char* arr_start = p; + int depth = 0; + int in_str = 0; + while (*p) { + char c = *p; + if (in_str) { + if (c == '\\' && p[1]) { p += 2; continue; } + if (c == '"') in_str = 0; + } else { + if (c == '"') in_str = 1; + else if (c == '[') depth++; + else if (c == ']') { depth--; if (depth == 0) { p++; break; } } + } + p++; + } + size_t alen = (size_t)(p - arr_start); + int match = (klen == tag_len) && html_iemem(k, tag, klen); + if (match) { + if (out_len) *out_len = alen; + return arr_start; + } + } + return NULL; +} + +/* Returns 1 iff `attr` (length attr_len) appears as a string element + * in the JSON array slice [arr, arr+arr_len). Comparison is case- + * insensitive. */ +static int html_attr_in_array(const char* arr, size_t arr_len, + const char* attr, size_t attr_len) { + if (!arr || arr_len < 2) return 0; + const char* p = arr + 1; + const char* end = arr + arr_len - 1; + while (p < end) { + while (p < end && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',')) p++; + if (p >= end) return 0; + if (*p != '"') return 0; + p++; + const char* s = p; + while (p < end && *p != '"') { + if (*p == '\\' && p + 1 < end) p++; + p++; + } + if (p >= end) return 0; + size_t slen = (size_t)(p - s); + p++; + if (slen == attr_len && html_iemem(s, attr, slen)) return 1; + } + return 0; +} + +/* Hard-coded set of tags whose content is ALSO dropped (entire subtree). */ +static int html_is_dangerous_container(const char* tag, size_t tag_len) { + static const char* names[] = { + "script", "style", "iframe", "object", "embed", "form", + "noscript", "noembed", "template", "svg", "math", "frame", + "frameset", "applet", "audio", "video", "source", "track", + NULL + }; + for (int i = 0; names[i]; i++) { + if (html_ieq_n(tag, tag_len, names[i])) return 1; + } + return 0; +} + +/* HTML void elements — emit without a close tag. */ +static int html_is_void(const char* tag, size_t tag_len) { + static const char* names[] = { + "area", "base", "br", "col", "embed", "hr", "img", "input", + "link", "meta", "param", "source", "track", "wbr", + NULL + }; + for (int i = 0; names[i]; i++) { + if (html_ieq_n(tag, tag_len, names[i])) return 1; + } + return 0; +} + +/* Append a single byte HTML-escaped into the output buffer. */ +static void html_escape_byte(html_buf_t* out, unsigned char c) { + switch (c) { + case '<': html_buf_puts(out, "<"); break; + case '>': html_buf_puts(out, ">"); break; + case '"': html_buf_puts(out, """); break; + case '\'': html_buf_puts(out, "'"); break; + default: html_buf_putc(out, (char)c); break; + } +} + +/* Validate a URL value against the allowlist of safe schemes for hrefs. + * Returns 1 iff the URL is safe to emit. Acceptable forms: + * - http:// or https:// (case-insensitive) + * - mailto: + * - fragment-only `#anchor` + * - relative path that does not contain a colon before the first + * slash/?/# (so `foo/bar`, `/foo`, `?x=1` are OK; `javascript:x` is + * not — its colon precedes any path/hash/query separator). + * + * URL leading whitespace and embedded ASCII control bytes (TAB, LF, CR) + * are stripped before the scheme test, mirroring how browsers normalise + * URLs (these bytes are otherwise a known XSS bypass: `java\tscript:`). */ +static int html_url_is_safe(const char* url, size_t len) { + if (!url || len == 0) return 1; /* empty href is harmless */ + size_t i = 0; + while (i < len) { + unsigned char c = (unsigned char)url[i]; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == 0x0B || c == 0x0C) { + i++; continue; + } + break; + } + if (i >= len) return 1; /* whitespace only */ + if (url[i] == '#') return 1; /* fragment only */ + if (url[i] == '/' || url[i] == '?') return 1; /* relative */ + /* Find the first scheme-terminating character. */ + size_t scheme_end = (size_t)-1; + for (size_t j = i; j < len; j++) { + char c = url[j]; + if (c == ':') { scheme_end = j; break; } + if (c == '/' || c == '?' || c == '#') break; + } + if (scheme_end == (size_t)-1) return 1; /* no colon → relative path */ + /* Lowercase the scheme, stripping embedded control bytes. */ + char scheme[32]; + size_t sl = 0; + for (size_t j = i; j < scheme_end && sl < sizeof(scheme) - 1; j++) { + unsigned char c = (unsigned char)url[j]; + if (c == '\t' || c == '\n' || c == '\r' || c == 0x0B || c == 0x0C) continue; + scheme[sl++] = (char)html_tolower(c); + } + scheme[sl] = '\0'; + if (strcmp(scheme, "http") == 0) return 1; + if (strcmp(scheme, "https") == 0) return 1; + if (strcmp(scheme, "mailto") == 0) return 1; + return 0; +} + +el_val_t el_html_sanitize(el_val_t input_v, el_val_t allowlist_v) { + const char* input = EL_CSTR(input_v); + const char* allow = EL_CSTR(allowlist_v); + if (!input) return el_wrap_str(el_strdup("")); + if (!allow) allow = "{}"; + size_t in_len = strlen(input); + + html_buf_t out; + html_buf_init(&out); + + size_t i = 0; + while (i < in_len) { + unsigned char c = (unsigned char)input[i]; + if (c != '<') { + /* Plain text — escape and emit. We pass `&` through verbatim + * to preserve pre-encoded entities (`<`, `&`, `&#x...;`) + * which the browser will decode safely. */ + if (c == '&') html_buf_putc(&out, '&'); + else html_escape_byte(&out, c); + i++; + continue; + } + /* `<` — try to parse a tag. */ + if (i + 1 >= in_len) { + html_buf_puts(&out, "<"); + i++; + continue; + } + /* Comments, doctype, CDATA, processing instructions — drop entirely. */ + if (input[i + 1] == '!') { + if (i + 3 < in_len && input[i + 2] == '-' && input[i + 3] == '-') { + size_t j = i + 4; + while (j + 2 < in_len && !(input[j] == '-' && input[j + 1] == '-' && input[j + 2] == '>')) j++; + if (j + 2 < in_len) i = j + 3; + else i = in_len; + continue; + } + size_t j = i + 2; + while (j < in_len && input[j] != '>') j++; + i = (j < in_len) ? j + 1 : in_len; + continue; + } + if (input[i + 1] == '?') { + size_t j = i + 2; + while (j < in_len && input[j] != '>') j++; + i = (j < in_len) ? j + 1 : in_len; + continue; + } + int is_close = 0; + size_t name_start = i + 1; + if (input[i + 1] == '/') { + is_close = 1; + name_start = i + 2; + } + if (name_start >= in_len) { + html_buf_puts(&out, "<"); + i++; + continue; + } + unsigned char nc = (unsigned char)input[name_start]; + if (!((nc >= 'a' && nc <= 'z') || (nc >= 'A' && nc <= 'Z'))) { + /* `<` followed by non-letter — emit as escaped text. */ + html_buf_puts(&out, "<"); + i++; + continue; + } + size_t name_end = name_start; + while (name_end < in_len) { + unsigned char x = (unsigned char)input[name_end]; + if ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || + (x >= '0' && x <= '9') || x == '-' || x == '_' || x == ':') { + name_end++; + } else { + break; + } + } + const char* tag = input + name_start; + size_t tag_len = name_end - name_start; + /* Find the `>` that closes this tag, respecting quoted attrs. */ + size_t cur = name_end; + int self_close = 0; + while (cur < in_len) { + unsigned char x = (unsigned char)input[cur]; + if (x == '"' || x == '\'') { + unsigned char q = x; + cur++; + while (cur < in_len && (unsigned char)input[cur] != q) cur++; + if (cur < in_len) cur++; /* skip closing quote */ + continue; + } + if (x == '/' && cur + 1 < in_len && input[cur + 1] == '>') { + self_close = 1; + break; + } + if (x == '>') break; + cur++; + } + if (cur >= in_len) { + /* Malformed: unclosed tag at EOF. Drop the rest of the input. */ + i = in_len; + continue; + } + size_t tag_end = self_close ? cur + 2 : cur + 1; /* one past `>` */ + /* Dangerous container — drop the whole subtree. */ + if (!is_close && html_is_dangerous_container(tag, tag_len)) { + if (self_close || html_is_void(tag, tag_len)) { + i = tag_end; + continue; + } + size_t scan = tag_end; + int found_close = 0; + while (scan < in_len) { + if (input[scan] != '<') { scan++; continue; } + if (scan + 1 < in_len && input[scan + 1] == '/') { + size_t cn_start = scan + 2; + size_t cn_end = cn_start; + while (cn_end < in_len) { + unsigned char x = (unsigned char)input[cn_end]; + if ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || + (x >= '0' && x <= '9') || x == '-' || x == '_' || x == ':') { + cn_end++; + } else break; + } + if (cn_end - cn_start == tag_len && + html_iemem(input + cn_start, tag, tag_len)) { + size_t end_close = cn_end; + while (end_close < in_len && input[end_close] != '>') end_close++; + i = (end_close < in_len) ? end_close + 1 : in_len; + found_close = 1; + break; + } + } + scan++; + } + if (!found_close) { + /* No matching close — drop everything from here on. */ + i = in_len; + } + continue; + } + /* Look up the tag in the allowlist. */ + size_t arr_len = 0; + const char* arr = html_allowlist_find(allow, tag, tag_len, &arr_len); + if (!arr) { + /* Tag not allowed. Drop the open/close marker; inner text is + * processed by the outer loop and re-emitted as escaped text. */ + i = tag_end; + continue; + } + if (is_close) { + if (!html_is_void(tag, tag_len)) { + html_buf_putc(&out, '<'); + html_buf_putc(&out, '/'); + for (size_t k = 0; k < tag_len; k++) { + html_buf_putc(&out, (char)html_tolower((unsigned char)tag[k])); + } + html_buf_putc(&out, '>'); + } + i = tag_end; + continue; + } + /* Allowed open tag. Emit ``. */ + html_buf_putc(&out, '<'); + for (size_t k = 0; k < tag_len; k++) { + html_buf_putc(&out, (char)html_tolower((unsigned char)tag[k])); + } + size_t a = name_end; + while (a < cur) { + unsigned char x = (unsigned char)input[a]; + if (x == ' ' || x == '\t' || x == '\n' || x == '\r' || x == '/') { a++; continue; } + size_t an_start = a; + while (a < cur) { + unsigned char y = (unsigned char)input[a]; + if (y == '=' || y == ' ' || y == '\t' || y == '\n' || y == '\r' || y == '/' || y == '>') break; + a++; + } + size_t an_len = a - an_start; + if (an_len == 0) { a++; continue; } + size_t av_start = 0; + size_t av_len = 0; + int has_value = 0; + size_t b = a; + while (b < cur && (input[b] == ' ' || input[b] == '\t' || input[b] == '\n' || input[b] == '\r')) b++; + if (b < cur && input[b] == '=') { + has_value = 1; + b++; + while (b < cur && (input[b] == ' ' || input[b] == '\t' || input[b] == '\n' || input[b] == '\r')) b++; + if (b < cur && (input[b] == '"' || input[b] == '\'')) { + unsigned char q = (unsigned char)input[b]; + b++; + av_start = b; + while (b < cur && (unsigned char)input[b] != q) b++; + av_len = b - av_start; + if (b < cur) b++; + } else { + av_start = b; + while (b < cur) { + unsigned char y = (unsigned char)input[b]; + if (y == ' ' || y == '\t' || y == '\n' || y == '\r' || y == '>') break; + b++; + } + av_len = b - av_start; + } + a = b; + } + if (!html_attr_in_array(arr, arr_len, input + an_start, an_len)) continue; + int is_href = (an_len == 4 && html_iemem(input + an_start, "href", 4)); + int is_src = (an_len == 3 && html_iemem(input + an_start, "src", 3)); + if ((is_href || is_src) && has_value) { + if (!html_url_is_safe(input + av_start, av_len)) continue; + } + html_buf_putc(&out, ' '); + for (size_t k = 0; k < an_len; k++) { + html_buf_putc(&out, (char)html_tolower((unsigned char)input[an_start + k])); + } + if (has_value) { + html_buf_puts(&out, "=\""); + for (size_t k = 0; k < av_len; k++) { + unsigned char y = (unsigned char)input[av_start + k]; + /* Re-escape so the emitted attribute is well-formed + * double-quoted HTML. `&` passes through to preserve + * pre-encoded entities. */ + if (y == '"') html_buf_puts(&out, """); + else if (y == '<') html_buf_puts(&out, "<"); + else if (y == '>') html_buf_puts(&out, ">"); + else html_buf_putc(&out, (char)y); + } + html_buf_putc(&out, '"'); + } + } + html_buf_putc(&out, '>'); + i = tag_end; + } + /* Copy into arena-tracked buffer so the standard runtime memory model + * applies to the returned string. */ + char* result = el_strbuf(out.len); + memcpy(result, out.data, out.len); + result[out.len] = '\0'; + html_buf_free(&out); + return el_wrap_str(result); +} + +/* ── JSON ────────────────────────────────────────────────────────────────── */ + +/* True iff the segment is non-empty and every byte is an ASCII digit. We treat + * such segments as numeric array indices when walking a dot-path; mixed names + * like "0a" remain object-key lookups, so a key named "0" still wins over an + * index when the surrounding container is an object. */ +static int json_path_seg_is_index(const char* seg, size_t n) { + if (n == 0) return 0; + for (size_t i = 0; i < n; i++) { + if (seg[i] < '0' || seg[i] > '9') return 0; + } + return 1; +} + +/* Skip JSON whitespace. */ +static const char* json_skip_ws(const char* p) { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + return p; +} + +/* Descend one segment into the JSON cursor `p`. + * - If `p` points at an array `[...]` and the segment is all digits, + * advance to that element (zero-based). + * - Otherwise treat the segment as an object key and use json_find_key + * scoped to a one-level slice of the current container. + * Returns NULL if the descent fails (segment not found, container mismatch). + * + * `seg` is a pointer into the original path string and `seg_len` is its + * byte length — this avoids an extra alloc per segment. */ +static const char* json_path_descend(const char* p, const char* seg, size_t seg_len) { + if (!p || !seg) return NULL; + p = json_skip_ws(p); + if (*p == '[' && json_path_seg_is_index(seg, seg_len)) { + long idx = 0; + for (size_t i = 0; i < seg_len; i++) idx = idx * 10 + (seg[i] - '0'); + p++; /* step past '[' */ + p = json_skip_ws(p); + long cur = 0; + while (*p && *p != ']') { + if (cur == idx) return p; + const char* end = json_skip_value(p); + if (!end || end == p) return NULL; + p = json_skip_ws(end); + if (*p == ',') { p++; p = json_skip_ws(p); cur++; continue; } + /* No comma after this element — only acceptable at the closing ']', + * which means we ran out of elements. */ + break; + } + return NULL; + } + /* Object lookup. json_find_key walks at depth 1 of whatever container it + * receives, so we slice from `p` onwards. Caller already positioned us at + * the opening '{' (or at whitespace before it). */ + if (*p != '{') return NULL; + /* Build a NUL-terminated copy of the key segment for the lookup. We only + * pay this cost when the segment isn't a numeric index. */ + char stack_key[256]; + char* k = stack_key; + if (seg_len + 1 > sizeof(stack_key)) { + k = malloc(seg_len + 1); + if (!k) return NULL; + } + memcpy(k, seg, seg_len); + k[seg_len] = '\0'; + const char* found = json_find_key(p, k); + if (k != stack_key) free(k); + return found; +} + +/* Read the JSON value at `p` into a freshly-allocated, arena-owned el_val_t. + * - String -> unescaped, wrapped el_val_t string + * - Anything else -> raw JSON slice as a string (matches the historical + * json_get behaviour: numbers/bools/null come back stringified). */ +static el_val_t json_read_value(const char* p) { + p = json_skip_ws(p); + if (*p == '"') { + p++; + size_t cap = strlen(p) + 1; + char* out = el_strbuf(cap); + char* w = out; + while (*p && *p != '"') { + if (*p == '\\' && *(p+1)) { + p++; + switch (*p) { + case '"': *w++ = '"'; break; + case '\\': *w++ = '\\'; break; + case '/': *w++ = '/'; break; + case 'n': *w++ = '\n'; break; + case 'r': *w++ = '\r'; break; + case 't': *w++ = '\t'; break; + default: *w++ = *p; break; + } + } else { + *w++ = *p; + } + p++; + } + *w = '\0'; + return el_wrap_str(out); + } + /* Object/array/number/bool/null — return the raw slice up to the value's + * end. json_skip_value tracks brace/bracket/string state so nested objects + * round-trip cleanly. */ + const char* end = json_skip_value(p); + if (!end) end = p; + size_t n = (size_t)(end - p); + /* Strip trailing whitespace from scalar values so callers don't see + * `123 ` when they parsed a pretty-printed number. */ + while (n > 0 && (p[n-1] == ' ' || p[n-1] == '\t' || p[n-1] == '\n' || p[n-1] == '\r')) { + n--; + } + char* out = el_strbuf(n); + memcpy(out, p, n); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t json_get(el_val_t jsonv, el_val_t keyv) { + const char* json = EL_CSTR(jsonv); + const char* key = EL_CSTR(keyv); + if (!json || !key) return el_wrap_str(el_strdup("")); + + /* Fast path: key contains no '.' — keep the historical single-segment + * substring search so existing callers retain their O(strlen) cost + * profile. The dot-path walker is only paid for when needed. */ + if (!strchr(key, '.')) { + size_t klen = strlen(key); + char stack_pat[512]; + char* pattern; + if (klen + 5 <= sizeof(stack_pat)) { + pattern = stack_pat; + } else { + pattern = malloc(klen + 5); + if (!pattern) return el_wrap_str(el_strdup("")); + } + snprintf(pattern, klen + 5, "\"%s\":", key); + const char* p = strstr(json, pattern); + if (pattern != stack_pat) free(pattern); + if (!p) return el_wrap_str(el_strdup("")); + p += strlen(key) + 3; /* skip "key": */ + return json_read_value(p); + } + + /* Dot-path traversal. Walk segments left to right; at each step, descend + * into the current container by either array index (all-digit segment on + * an array cursor) or object key. */ + const char* cursor = json_skip_ws(json); + const char* seg_start = key; + const char* k = key; + while (1) { + if (*k == '.' || *k == '\0') { + size_t seg_len = (size_t)(k - seg_start); + cursor = json_path_descend(cursor, seg_start, seg_len); + if (!cursor) return el_wrap_str(el_strdup("")); + if (*k == '\0') break; + k++; + seg_start = k; + continue; + } + k++; + } + return json_read_value(cursor); +} + +/* ── Float bit-cast helpers ──────────────────────────────────────────────── */ +/* `el_to_float` and `el_from_float` are exposed in el_runtime.h as static + * inlines so generated programs (which #include the header) can call them + * for Float literals. No definitions are needed here. */ + +/* ── JSON parser (recursive descent) ─────────────────────────────────────── */ +/* + * Parsed JSON representation: + * - object -> ElMap (keys & values are el_val_t) + * - array -> ElList + * - string -> EL_STR-wrapped char* (allocated) + * - number -> int (el_val_t) if integer, otherwise el_from_float(double) + * - true -> 1 + * - false -> 0 + * - null -> EL_NULL (0) + * + * Note: there is no runtime type tag — parsed numbers cannot be + * distinguished from booleans by the runtime alone. The codegen tracks + * types separately. This matches the rest of el_val_t's type-erased model. + */ + +/* JsonParser struct is forward-declared near the HTTP/Engram section. */ + +static void jp_skip_ws(JsonParser* jp) { + while (jp->p < jp->end) { + char c = *jp->p; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') jp->p++; + else break; + } +} + +static el_val_t jp_parse_value(JsonParser* jp); + +/* Parse a JSON string literal (the opening " has NOT yet been consumed). */ +static char* jp_parse_string_raw(JsonParser* jp) { + if (jp->p >= jp->end || *jp->p != '"') { jp->err = 1; return el_strdup(""); } + jp->p++; + size_t cap = 32, len = 0; + char* out = malloc(cap); + if (!out) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + while (jp->p < jp->end && *jp->p != '"') { + char c = *jp->p++; + if (c == '\\' && jp->p < jp->end) { + char esc = *jp->p++; + switch (esc) { + case '"': c = '"'; break; + case '\\': c = '\\'; break; + case '/': c = '/'; break; + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'u': { + /* Skip 4 hex digits; emit '?' as a placeholder */ + for (int i = 0; i < 4 && jp->p < jp->end; i++) jp->p++; + c = '?'; + break; + } + default: c = esc; break; + } + } + if (len + 1 >= cap) { + cap *= 2; + out = realloc(out, cap); + if (!out) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + } + out[len++] = c; + } + if (jp->p < jp->end && *jp->p == '"') jp->p++; + else jp->err = 1; + out[len] = '\0'; + return out; +} + +static el_val_t jp_parse_number(JsonParser* jp) { + const char* start = jp->p; + int is_float = 0; + if (jp->p < jp->end && (*jp->p == '-' || *jp->p == '+')) jp->p++; + while (jp->p < jp->end && isdigit((unsigned char)*jp->p)) jp->p++; + if (jp->p < jp->end && *jp->p == '.') { + is_float = 1; jp->p++; + while (jp->p < jp->end && isdigit((unsigned char)*jp->p)) jp->p++; + } + if (jp->p < jp->end && (*jp->p == 'e' || *jp->p == 'E')) { + is_float = 1; jp->p++; + if (jp->p < jp->end && (*jp->p == '+' || *jp->p == '-')) jp->p++; + while (jp->p < jp->end && isdigit((unsigned char)*jp->p)) jp->p++; + } + size_t n = (size_t)(jp->p - start); + char buf[64]; + if (n >= sizeof(buf)) n = sizeof(buf) - 1; + memcpy(buf, start, n); + buf[n] = '\0'; + if (is_float) return el_from_float(strtod(buf, NULL)); + return (el_val_t)strtoll(buf, NULL, 10); +} + +static el_val_t jp_parse_array(JsonParser* jp) { + if (jp->p < jp->end && *jp->p == '[') jp->p++; + el_val_t lst = el_list_empty(); + jp_skip_ws(jp); + if (jp->p < jp->end && *jp->p == ']') { jp->p++; return lst; } + while (jp->p < jp->end) { + jp_skip_ws(jp); + el_val_t v = jp_parse_value(jp); + lst = el_list_append(lst, v); + jp_skip_ws(jp); + if (jp->p < jp->end && *jp->p == ',') { jp->p++; continue; } + if (jp->p < jp->end && *jp->p == ']') { jp->p++; break; } + jp->err = 1; + break; + } + return lst; +} + +static el_val_t jp_parse_object(JsonParser* jp) { + if (jp->p < jp->end && *jp->p == '{') jp->p++; + el_val_t m = el_map_new(0); + jp_skip_ws(jp); + if (jp->p < jp->end && *jp->p == '}') { jp->p++; return m; } + while (jp->p < jp->end) { + jp_skip_ws(jp); + char* key = jp_parse_string_raw(jp); + jp_skip_ws(jp); + if (jp->p < jp->end && *jp->p == ':') jp->p++; + else { jp->err = 1; free(key); break; } + jp_skip_ws(jp); + el_val_t v = jp_parse_value(jp); + m = el_map_set(m, EL_STR(key), v); + jp_skip_ws(jp); + if (jp->p < jp->end && *jp->p == ',') { jp->p++; continue; } + if (jp->p < jp->end && *jp->p == '}') { jp->p++; break; } + jp->err = 1; + break; + } + return m; +} + +static el_val_t jp_parse_value(JsonParser* jp) { + jp_skip_ws(jp); + if (jp->p >= jp->end) { jp->err = 1; return EL_NULL; } + char c = *jp->p; + if (c == '"') return el_wrap_str(jp_parse_string_raw(jp)); + if (c == '{') return jp_parse_object(jp); + if (c == '[') return jp_parse_array(jp); + if (c == '-' || isdigit((unsigned char)c)) return jp_parse_number(jp); + if (c == 't' && jp->p + 4 <= jp->end && strncmp(jp->p, "true", 4) == 0) { jp->p += 4; return 1; } + if (c == 'f' && jp->p + 5 <= jp->end && strncmp(jp->p, "false", 5) == 0) { jp->p += 5; return 0; } + if (c == 'n' && jp->p + 4 <= jp->end && strncmp(jp->p, "null", 4) == 0) { jp->p += 4; return EL_NULL; } + jp->err = 1; + return EL_NULL; +} + +el_val_t json_parse(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return EL_NULL; + JsonParser jp = { .p = s, .end = s + strlen(s), .err = 0 }; + el_val_t v = jp_parse_value(&jp); + if (jp.err) return EL_NULL; + return v; +} + +/* ── JSON stringify ──────────────────────────────────────────────────────── */ +/* + * Stringify policy: el_val_t is type-erased, so we cannot perfectly + * round-trip arbitrary values. We use these heuristics: + * - If value is an ElList pointer (in the heap range), serialize as array. + * - If value is an ElMap pointer, serialize as object. + * - If value looks like a printable string pointer, serialize as string. + * - Otherwise serialize as integer. + * This is best-effort. Programs that need exact control should build the + * string directly. A pointer test is the cheapest way to disambiguate + * from small integers without a separate type tag. + */ + +/* JsonBuf struct is forward-declared near the HTTP section so HTTP helpers + * can use it. Its definition appears there. */ + +static void jb_init(JsonBuf* b) { + b->cap = 64; b->len = 0; + b->buf = malloc(b->cap); + if (!b->buf) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + b->buf[0] = '\0'; +} + +static void jb_reserve(JsonBuf* b, size_t add) { + if (b->len + add + 1 > b->cap) { + while (b->len + add + 1 > b->cap) b->cap *= 2; + b->buf = realloc(b->buf, b->cap); + if (!b->buf) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + } +} + +static void jb_putc(JsonBuf* b, char c) { + jb_reserve(b, 1); + b->buf[b->len++] = c; + b->buf[b->len] = '\0'; +} + +static void jb_puts(JsonBuf* b, const char* s) { + size_t n = strlen(s); + jb_reserve(b, n); + memcpy(b->buf + b->len, s, n); + b->len += n; + b->buf[b->len] = '\0'; +} + +static void jb_emit_escaped(JsonBuf* b, const char* s) { + jb_putc(b, '"'); + for (; *s; s++) { + unsigned char c = (unsigned char)*s; + switch (c) { + case '"': jb_puts(b, "\\\""); break; + case '\\': jb_puts(b, "\\\\"); break; + case '\b': jb_puts(b, "\\b"); break; + case '\f': jb_puts(b, "\\f"); break; + case '\n': jb_puts(b, "\\n"); break; + case '\r': jb_puts(b, "\\r"); break; + case '\t': jb_puts(b, "\\t"); break; + default: + if (c < 0x20) { + char tmp[8]; + snprintf(tmp, sizeof(tmp), "\\u%04x", c); + jb_puts(b, tmp); + } else { + jb_putc(b, (char)c); + } + break; + } + } + jb_putc(b, '"'); +} + +/* Heuristic: is this el_val_t likely a pointer to an ElList? + * We can't fully verify, but pointers are large addresses, integers small. + * Treat values whose magnitude exceeds 2^32 as potential pointers and + * sniff by reading the header conservatively. + * + * Simpler heuristic: if the value reads as a printable string, treat as + * string; otherwise as integer. Lists/Maps are encoded as struct pointers, + * which have leading binary bytes — so they won't look like strings. */ + +static int looks_like_string(el_val_t v) { + if (v == 0) return 0; + /* Treat plausible heap addresses as candidates. + * Threshold: 4 GiB (0x100000000). On 64-bit systems heap addresses from + * malloc/mmap start well above 4 GiB (ASLR pushes them to ~0x7f...). + * El integer values (counters, unix timestamps up to ~2106) all fit below + * 0x100000000 (4294967296). The old threshold of 1,000,000 caused unix + * timestamps (~1.7e9) to be misidentified as string pointers — a segfault + * risk in json_stringify and jb_emit_value. */ + uintptr_t p = (uintptr_t)v; + if (p < 0x100000000ULL) return 0; /* integers, timestamps, counters */ + if (p < 0x1000) return 0; + /* Sniff first bytes for printable */ + const unsigned char* s = (const unsigned char*)p; + for (int i = 0; i < 16; i++) { + unsigned char c = s[i]; + if (c == '\0') return 1; /* terminated string (empty string is still a valid string) */ + /* Reject C0 control chars (non-whitespace), allow UTF-8 high bytes. + * 0x09-0x0d = tab/newline/cr/vt/ff (whitespace, OK) + * 0x20-0x7e = printable ASCII (OK) + * 0x7f = DEL (reject) + * 0x80-0xff = UTF-8 continuation/lead bytes (OK for multi-byte chars) */ + if (c < 0x09 || (c > 0x0d && c < 0x20) || c == 0x7f) return 0; + } + return 1; /* 16+ printable bytes — call it a string */ +} + +static void jb_emit_value(JsonBuf* b, el_val_t v); + +static void jb_emit_int(JsonBuf* b, int64_t n) { + char tmp[32]; + snprintf(tmp, sizeof(tmp), "%lld", (long long)n); + jb_puts(b, tmp); +} + +static void jb_emit_value(JsonBuf* b, el_val_t v) { + if (v == EL_NULL) { jb_puts(b, "null"); return; } + if (looks_like_string(v)) { + jb_emit_escaped(b, EL_CSTR(v)); + return; + } + jb_emit_int(b, (int64_t)v); +} + +el_val_t json_stringify(el_val_t v) { + JsonBuf b; jb_init(&b); + jb_emit_value(&b, v); + return el_wrap_str(b.buf); +} + +/* ── JSON substring accessors ────────────────────────────────────────────── */ +/* + * These walk the raw JSON string looking for "key": at the top level (depth 1) + * of an object. They handle escaped quotes, nested objects/arrays, and + * whitespace around the colon. + */ + +/* Find "key": at object-depth == 1 inside the JSON object string `s`. + * Returns pointer to the first byte of the value, or NULL. */ +static const char* json_find_key(const char* s, const char* key) { + if (!s || !key) return NULL; + size_t klen = strlen(key); + int depth = 0; + int in_str = 0; + int escape = 0; + const char* p = s; + while (*p) { + char c = *p; + if (in_str) { + if (escape) { escape = 0; } + else if (c == '\\') { escape = 1; } + else if (c == '"') { + /* End of string. If we're at depth 1, check if this was a key. */ + p++; + if (depth == 1) { + /* The string just ended at p-1. Check if it matches key + * and is followed by a colon. We need to backtrack to find + * the start of this string and compare. */ + } + in_str = 0; + continue; + } + p++; + continue; + } + if (c == '"') { + /* Start of a string literal */ + const char* str_start = p + 1; + const char* q = str_start; + int e = 0; + while (*q) { + if (e) { e = 0; q++; continue; } + if (*q == '\\') { e = 1; q++; continue; } + if (*q == '"') break; + q++; + } + size_t slen = (size_t)(q - str_start); + const char* after = (*q == '"') ? q + 1 : q; + /* If at depth 1 and matches key and followed by ':' -> got it */ + if (depth == 1 && slen == klen && strncmp(str_start, key, klen) == 0) { + const char* r = after; + while (*r == ' ' || *r == '\t' || *r == '\n' || *r == '\r') r++; + if (*r == ':') { + r++; + while (*r == ' ' || *r == '\t' || *r == '\n' || *r == '\r') r++; + return r; + } + } + p = after; + continue; + } + if (c == '{' || c == '[') depth++; + else if (c == '}' || c == ']') depth--; + p++; + } + return NULL; +} + +/* Skip a JSON value starting at p; return pointer past the value end. */ +static const char* json_skip_value(const char* p) { + if (!p || !*p) return p; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p == '"') { + p++; + int e = 0; + while (*p) { + if (e) { e = 0; p++; continue; } + if (*p == '\\') { e = 1; p++; continue; } + if (*p == '"') { p++; break; } + p++; + } + return p; + } + if (*p == '{' || *p == '[') { + char open = *p; + char close = (open == '{') ? '}' : ']'; + int depth = 0; + int in_str = 0; + int e = 0; + while (*p) { + char c = *p; + if (in_str) { + if (e) { e = 0; } + else if (c == '\\') { e = 1; } + else if (c == '"') in_str = 0; + p++; + continue; + } + if (c == '"') { in_str = 1; p++; continue; } + if (c == open) depth++; + else if (c == close) { depth--; p++; if (depth == 0) return p; continue; } + p++; + } + return p; + } + /* scalar: number, true/false/null */ + while (*p && *p != ',' && *p != '}' && *p != ']' && + *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r') p++; + return p; +} + +el_val_t json_get_string(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + if (!p || *p != '"') return el_wrap_str(el_strdup("")); + p++; + JsonParser jp = { .p = p - 1, .end = json + (json ? strlen(json) : 0), .err = 0 }; + char* parsed = jp_parse_string_raw(&jp); + if (jp.err) { free(parsed); return el_wrap_str(el_strdup("")); } + return el_wrap_str(parsed); +} + +el_val_t json_get_int(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + if (!p) return 0; + if (*p == '"' || *p == '{' || *p == '[') return 0; + return (el_val_t)strtoll(p, NULL, 10); +} + +el_val_t json_get_float(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + if (!p) return 0; + if (*p == '"' || *p == '{' || *p == '[') return 0; + return el_from_float(strtod(p, NULL)); +} + +el_val_t json_get_bool(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + if (!p) return 0; + if (strncmp(p, "true", 4) == 0) return 1; + return 0; +} + +el_val_t json_get_raw(el_val_t json_str, el_val_t key) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + const char* p = json_find_key(json, k); + /* Clear fs_read binary-length hint — result is a fresh null-terminated + * string, not the raw file bytes, so Content-Length must use strlen. */ + _tl_fs_read_len = 0; + if (!p) return el_wrap_str(el_strdup("")); + const char* end = json_skip_value(p); + size_t n = (size_t)(end - p); + char* out = el_strbuf(n); + memcpy(out, p, n); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t json_set(el_val_t json_str, el_val_t key, el_val_t value) { + const char* json = EL_CSTR(json_str); + const char* k = EL_CSTR(key); + /* raw_val is the JSON value as-is (already encoded by the caller). + * If it looks like a plain (non-JSON) string, wrap it as a JSON string. + * Convention: callers pass pre-encoded values like "\"bob\"" for strings, + * "42" for numbers, "true"/"false" for booleans. */ + const char* raw_val = EL_CSTR(value); + if (!k) k = ""; + if (!raw_val) raw_val = "null"; + if (!json || !*json) { + /* Build a fresh object */ + JsonBuf b; jb_init(&b); + jb_putc(&b, '{'); + jb_emit_escaped(&b, k); + jb_putc(&b, ':'); + jb_puts(&b, raw_val); + jb_putc(&b, '}'); + return el_wrap_str(b.buf); + } + const char* existing = json_find_key(json, k); + JsonBuf b; jb_init(&b); + if (existing) { + const char* end = json_skip_value(existing); + /* Copy [json .. existing) */ + size_t prefix = (size_t)(existing - json); + jb_reserve(&b, prefix); + memcpy(b.buf + b.len, json, prefix); + b.len += prefix; + b.buf[b.len] = '\0'; + jb_puts(&b, raw_val); + jb_puts(&b, end); + return el_wrap_str(b.buf); + } + /* Insert before closing '}'. Find last '}' */ + size_t jl = strlen(json); + if (jl == 0) { free(b.buf); return el_wrap_str(el_strdup("{}")); } + /* Find last '}' from the end */ + ssize_t close_idx = -1; + for (ssize_t i = (ssize_t)jl - 1; i >= 0; i--) { + if (json[i] == '}') { close_idx = i; break; } + } + if (close_idx < 0) { + free(b.buf); + return el_wrap_str(el_strdup(json)); + } + /* Determine if object is empty: scan between last '{' and '}' for non-ws */ + int empty = 1; + for (ssize_t i = close_idx - 1; i >= 0; i--) { + char c = json[i]; + if (c == '{') break; + if (c != ' ' && c != '\t' && c != '\n' && c != '\r') { empty = 0; break; } + } + /* Copy json[0..close_idx) */ + jb_reserve(&b, (size_t)close_idx); + memcpy(b.buf + b.len, json, (size_t)close_idx); + b.len += (size_t)close_idx; + b.buf[b.len] = '\0'; + if (!empty) jb_putc(&b, ','); + jb_emit_escaped(&b, k); + jb_putc(&b, ':'); + jb_puts(&b, raw_val); + /* Append from close_idx onward */ + jb_puts(&b, json + close_idx); + return el_wrap_str(b.buf); +} + +el_val_t json_array_len(el_val_t json_str) { + const char* s = EL_CSTR(json_str); + if (!s) return 0; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s != '[') return 0; + s++; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ']') return 0; + int64_t count = 0; + while (*s) { + const char* end = json_skip_value(s); + if (end == s) break; + count++; + s = end; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ',') { s++; continue; } + if (*s == ']' || *s == '\0') break; + } + return (el_val_t)count; +} + +/* json_array_get — return the i-th element of a JSON array as a JSON + * fragment string. Nested objects and arrays are returned verbatim + * (json_skip_value tracks brace/bracket depth so nested structures are + * preserved intact). Out-of-range index → "". */ +el_val_t json_array_get(el_val_t json_str, el_val_t index) { + const char* s = EL_CSTR(json_str); + int64_t idx = (int64_t)index; + if (!s || idx < 0) return el_wrap_str(el_strdup("")); + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s != '[') return el_wrap_str(el_strdup("")); + s++; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ']') return el_wrap_str(el_strdup("")); + int64_t i = 0; + while (*s) { + const char* start = s; + const char* end = json_skip_value(s); + if (end == s) break; + if (i == idx) { + size_t n = (size_t)(end - start); + char* out = el_strbuf(n); + memcpy(out, start, n); + out[n] = '\0'; + return el_wrap_str(out); + } + i++; + s = end; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ',') { s++; while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; continue; } + if (*s == ']' || *s == '\0') break; + } + return el_wrap_str(el_strdup("")); +} + +/* json_array_get_string — same as json_array_get, but assume the element + * is a JSON string and return the unquoted/unescaped value. Non-string + * elements yield "". */ +el_val_t json_array_get_string(el_val_t json_str, el_val_t index) { + el_val_t raw = json_array_get(json_str, index); + const char* s = EL_CSTR(raw); + if (!s || *s != '"') return el_wrap_str(el_strdup("")); + JsonParser jp = { + .p = s, + .end = s + strlen(s), + .err = 0, + }; + char* parsed = jp_parse_string_raw(&jp); + if (jp.err) { + free(parsed); + return el_wrap_str(el_strdup("")); + } + return el_wrap_str(parsed); +} + +/* json_escape_string — escape a string value for embedding in JSON. + * Returns the escaped content WITHOUT surrounding quotes. + * "say \"hello\"" -> "say \\\"hello\\\"" */ +el_val_t json_escape_string(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + /* Worst case: every char needs a 2-char escape. */ + char* out = malloc(n * 2 + 1); + if (!out) return el_wrap_str(el_strdup("")); + size_t j = 0; + for (size_t i = 0; i < n; i++) { + unsigned char c = (unsigned char)s[i]; + if (c == '"') { out[j++] = '\\'; out[j++] = '"'; } + else if (c == '\\') { out[j++] = '\\'; out[j++] = '\\'; } + else if (c == '\n') { out[j++] = '\\'; out[j++] = 'n'; } + else if (c == '\r') { out[j++] = '\\'; out[j++] = 'r'; } + else if (c == '\t') { out[j++] = '\\'; out[j++] = 't'; } + else { out[j++] = (char)c; } + } + out[j] = '\0'; + el_val_t result = el_wrap_str(el_strdup(out)); + free(out); + return result; +} + +/* json_build_object — build a JSON object from a flat key-value list. + * kvs is [key0, val0, key1, val1, ...]. Values are raw JSON (pass + * strings as "\"value\"" or use json_escape_string). */ +el_val_t json_build_object(el_val_t kvs) { + el_val_t list = kvs; + int64_t n = el_list_len(list); + JsonBuf b; jb_init(&b); + jb_putc(&b, '{'); + int first = 1; + for (int64_t i = 0; i + 1 < n; i += 2) { + el_val_t k = el_list_get(list, (el_val_t)i); + el_val_t v = el_list_get(list, (el_val_t)(i + 1)); + const char* ks = EL_CSTR(k); + const char* vs = EL_CSTR(v); + if (!ks || !vs) continue; + if (!first) jb_putc(&b, ','); + first = 0; + jb_putc(&b, '"'); + jb_puts(&b, ks); + jb_puts(&b, "\":\""); + /* escape the value string */ + size_t vn = strlen(vs); + for (size_t j = 0; j < vn; j++) { + unsigned char c = (unsigned char)vs[j]; + if (c == '"') { jb_putc(&b, '\\'); jb_putc(&b, '"'); } + else if (c == '\\') { jb_putc(&b, '\\'); jb_putc(&b, '\\'); } + else if (c == '\n') { jb_putc(&b, '\\'); jb_putc(&b, 'n'); } + else if (c == '\r') { jb_putc(&b, '\\'); jb_putc(&b, 'r'); } + else if (c == '\t') { jb_putc(&b, '\\'); jb_putc(&b, 't'); } + else { jb_putc(&b, (char)c); } + } + jb_putc(&b, '"'); + } + jb_putc(&b, '}'); + return el_wrap_str(b.buf); +} + +/* json_build_array — build a JSON array from a list of raw JSON values. + * items is ["\"alpha\"", "\"beta\"", "42", "true", ...]. */ +el_val_t json_build_array(el_val_t items) { + el_val_t list = items; + int64_t n = el_list_len(list); + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + for (int64_t i = 0; i < n; i++) { + el_val_t v = el_list_get(list, (el_val_t)i); + const char* vs = EL_CSTR(v); + if (!vs) continue; + if (i > 0) jb_putc(&b, ','); + jb_puts(&b, vs); + } + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +/* ── Time ────────────────────────────────────────────────────────────────── */ + +el_val_t time_now(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + int64_t ms = (int64_t)tv.tv_sec * 1000LL + (int64_t)tv.tv_usec / 1000LL; + return (el_val_t)ms; +} + +el_val_t time_now_utc(void) { + return time_now(); +} + +el_val_t time_format(el_val_t ts, el_val_t fmt) { + int64_t ms = (int64_t)ts; + time_t s = (time_t)(ms / 1000); + int msec = (int)(ms % 1000); + if (msec < 0) { msec += 1000; s -= 1; } + struct tm tm; + gmtime_r(&s, &tm); + const char* fmt_str = EL_CSTR(fmt); + if (!fmt_str || *fmt_str == '\0' || strcmp(fmt_str, "ISO") == 0) { + char buf[64]; + snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, msec); + return el_wrap_str(el_strdup(buf)); + } + char buf[256]; + if (strftime(buf, sizeof(buf), fmt_str, &tm) == 0) buf[0] = '\0'; + return el_wrap_str(el_strdup(buf)); +} + +el_val_t time_to_parts(el_val_t ts) { + int64_t ms = (int64_t)ts; + time_t s = (time_t)(ms / 1000); + int msec = (int)(ms % 1000); + if (msec < 0) { msec += 1000; s -= 1; } + struct tm tm; + gmtime_r(&s, &tm); + /* Return a JSON string so callers can use json_get to extract fields. */ + char buf[256]; + snprintf(buf, sizeof(buf), + "{\"year\":%d,\"month\":%d,\"day\":%d,\"hour\":%d,\"minute\":%d,\"second\":%d,\"ms\":%d}", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, msec); + return el_wrap_str(el_strdup(buf)); +} + +el_val_t time_from_parts(el_val_t secs, el_val_t ns, el_val_t tz) { + (void)tz; + int64_t s = (int64_t)secs; + int64_t n = (int64_t)ns; + int64_t ms = s * 1000LL + n / 1000000LL; + return (el_val_t)ms; +} + +el_val_t time_add(el_val_t ts, el_val_t n, el_val_t unit) { + const char* u = EL_CSTR(unit); + int64_t cur = (int64_t)ts; + int64_t d = (int64_t)n; + int64_t add_ms = d; + if (u) { + if (strcmp(u, "ms") == 0) add_ms = d; + else if (strcmp(u, "sec") == 0) add_ms = d * 1000LL; + else if (strcmp(u, "min") == 0) add_ms = d * 60000LL; + else if (strcmp(u, "hour") == 0) add_ms = d * 3600000LL; + else if (strcmp(u, "day") == 0) add_ms = d * 86400000LL; + } + return (el_val_t)(cur + add_ms); +} + +el_val_t time_diff(el_val_t ts1, el_val_t ts2, el_val_t unit) { + int64_t d = (int64_t)ts2 - (int64_t)ts1; + const char* u = EL_CSTR(unit); + if (!u || strcmp(u, "ms") == 0) return (el_val_t)d; + if (strcmp(u, "sec") == 0) return (el_val_t)(d / 1000LL); + if (strcmp(u, "min") == 0) return (el_val_t)(d / 60000LL); + if (strcmp(u, "hour") == 0) return (el_val_t)(d / 3600000LL); + if (strcmp(u, "day") == 0) return (el_val_t)(d / 86400000LL); + return (el_val_t)d; +} + +/* Block the calling thread for `secs` seconds. Negative values are clamped + * to 0. Used by El programs that poll external resources (e.g. RunPod + * /status, Engram readiness probes). */ +el_val_t sleep_secs(el_val_t secs) { + int64_t s = (int64_t)secs; + if (s < 0) s = 0; + struct timespec ts; + ts.tv_sec = (time_t)s; + ts.tv_nsec = 0; + nanosleep(&ts, NULL); + return 0; +} + +el_val_t sleep_ms(el_val_t ms) { + int64_t m = (int64_t)ms; + if (m < 0) m = 0; + struct timespec ts; + ts.tv_sec = (time_t)(m / 1000LL); + ts.tv_nsec = (long)((m % 1000LL) * 1000000LL); + nanosleep(&ts, NULL); + return 0; +} + +/* ── Instant + Duration: first-class temporal types ────────────────────────── + * El's substrate (Neuron) is a temporal cognition system. Memory salience + * decay, the six-tier pacemaker, TTL caches, and supersession are all + * temporal. Treating time as a raw Int (now() returning ms-since-epoch and + * arithmetic done with mixed unit literals) lets bugs through the type + * system: `(now - cached_at) < 60` cannot tell ms from sec, and `sleep(30)` + * is ambiguous. This block introduces two dedicated representations. + * + * Representation: + * Instant — int64 nanoseconds since the Unix epoch + * Duration — int64 nanoseconds (signed; negative durations are legal, + * e.g. when a deadline has passed) + * + * Both share the el_val_t (int64) slot the rest of the runtime uses, so no + * boxing / arena allocation is needed. Type discipline is enforced at the + * codegen layer: `let x: Duration = ...` registers `x` in __duration_names, + * and BinOp dispatches through typed wrappers (el_duration_add, etc.) that + * make intent explicit in the generated C. Mismatched ops (Instant+Instant, + * Duration+Int) are surfaced via #error directives at codegen time so the + * downstream cc step fails with a clear El-source-level message. + * + * Nanosecond precision matches POSIX clock_gettime / nanosleep granularity. + * 2^63 nanos covers ~292 years from epoch — comfortably past 2200, plenty + * for a memory-system runtime that never schedules outside a human lifespan. + */ + +/* now() — current Instant. Wraps clock_gettime(CLOCK_REALTIME) for nanosecond + * precision. Falls back to gettimeofday on systems where clock_gettime is + * unavailable (defensive — every supported platform has it). */ +el_val_t el_now_instant(void) { + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts) == 0) { + int64_t ns = (int64_t)ts.tv_sec * 1000000000LL + (int64_t)ts.tv_nsec; + return (el_val_t)ns; + } + struct timeval tv; + gettimeofday(&tv, NULL); + int64_t ns = (int64_t)tv.tv_sec * 1000000000LL + + (int64_t)tv.tv_usec * 1000LL; + return (el_val_t)ns; +} + +el_val_t now(void) { + return el_now_instant(); +} + +/* now_ns — return current Unix time as nanoseconds (Int). + * Thin wrapper over el_now_instant for use in test timing. */ +el_val_t now_ns(void) { + return el_now_instant(); +} + +/* unix_seconds(n) — Instant from a Unix-epoch second count. + * unix_millis(n) — Instant from a Unix-epoch millisecond count. */ +el_val_t unix_seconds(el_val_t n) { + int64_t s = (int64_t)n; + return (el_val_t)(s * 1000000000LL); +} + +el_val_t unix_millis(el_val_t n) { + int64_t m = (int64_t)n; + return (el_val_t)(m * 1000000LL); +} + +/* instant_from_iso8601 — parse a strict subset: + * YYYY-MM-DDTHH:MM:SS[.fff]Z + * Returns 0 (the Unix-epoch sentinel) on parse failure. Callers that need to + * distinguish epoch-zero from a parse error should use a wider sentinel + * representation; the current zero-on-failure choice matches existing El + * runtime conventions for parse builtins (str_to_int, parse_int). */ +el_val_t instant_from_iso8601(el_val_t s) { + const char* str = EL_CSTR(s); + if (!str) return (el_val_t)0; + int Y, M, D, h, m, sec, frac = 0; + int n = sscanf(str, "%d-%d-%dT%d:%d:%d.%3d", &Y, &M, &D, &h, &m, &sec, &frac); + if (n < 6) { + n = sscanf(str, "%d-%d-%dT%d:%d:%dZ", &Y, &M, &D, &h, &m, &sec); + if (n < 6) return (el_val_t)0; + } + struct tm tm; + memset(&tm, 0, sizeof(tm)); + tm.tm_year = Y - 1900; + tm.tm_mon = M - 1; + tm.tm_mday = D; + tm.tm_hour = h; + tm.tm_min = m; + tm.tm_sec = sec; + /* timegm — UTC. POSIX-Y but available on macOS and glibc. */ + time_t t = timegm(&tm); + if (t == (time_t)-1) return (el_val_t)0; + int64_t ns = (int64_t)t * 1000000000LL + (int64_t)frac * 1000000LL; + return (el_val_t)ns; +} + +/* Duration constructors. The El-side postfix literals (30.seconds, 1.hour) + * are lowered by the codegen directly into a literal int64 of nanoseconds — + * these constructors are for runtime values where the count is dynamic. */ +el_val_t el_duration_from_nanos(el_val_t ns) { + return (el_val_t)(int64_t)ns; +} + +el_val_t duration_seconds(el_val_t n) { + int64_t s = (int64_t)n; + return (el_val_t)(s * 1000000000LL); +} + +el_val_t duration_millis(el_val_t n) { + int64_t m = (int64_t)n; + return (el_val_t)(m * 1000000LL); +} + +el_val_t duration_nanos(el_val_t n) { + return (el_val_t)(int64_t)n; +} + +/* Arithmetic — typed wrappers. At the C level these are no-op casts, but + * the codegen routes Instant/Duration BinOps through them so the generated + * C says `el_instant_add_dur(start, dur)` rather than `start + dur`. The + * intent is explicit, the operand order is documented, and a future change + * to the underlying representation (saturating arithmetic, overflow guards) + * has a single chokepoint. */ +el_val_t el_instant_add_dur(el_val_t inst, el_val_t dur) { + return (el_val_t)((int64_t)inst + (int64_t)dur); +} + +el_val_t el_instant_sub_dur(el_val_t inst, el_val_t dur) { + return (el_val_t)((int64_t)inst - (int64_t)dur); +} + +el_val_t el_instant_diff(el_val_t a, el_val_t b) { + /* a - b — yields a Duration (negative if b is later than a). */ + return (el_val_t)((int64_t)a - (int64_t)b); +} + +el_val_t el_duration_add(el_val_t a, el_val_t b) { + return (el_val_t)((int64_t)a + (int64_t)b); +} + +el_val_t el_duration_sub(el_val_t a, el_val_t b) { + return (el_val_t)((int64_t)a - (int64_t)b); +} + +el_val_t el_duration_scale(el_val_t dur, el_val_t scalar) { + return (el_val_t)((int64_t)dur * (int64_t)scalar); +} + +el_val_t el_duration_div(el_val_t dur, el_val_t scalar) { + int64_t s = (int64_t)scalar; + if (s == 0) return (el_val_t)0; + return (el_val_t)((int64_t)dur / s); +} + +/* Comparisons. Return 1/0 in el_val_t convention. */ +el_val_t el_instant_lt(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a < (int64_t)b ? 1 : 0); } +el_val_t el_instant_le(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a <= (int64_t)b ? 1 : 0); } +el_val_t el_instant_gt(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a > (int64_t)b ? 1 : 0); } +el_val_t el_instant_ge(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a >= (int64_t)b ? 1 : 0); } +el_val_t el_instant_eq(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a == (int64_t)b ? 1 : 0); } +el_val_t el_instant_ne(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a != (int64_t)b ? 1 : 0); } +el_val_t el_duration_lt(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a < (int64_t)b ? 1 : 0); } +el_val_t el_duration_le(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a <= (int64_t)b ? 1 : 0); } +el_val_t el_duration_gt(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a > (int64_t)b ? 1 : 0); } +el_val_t el_duration_ge(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a >= (int64_t)b ? 1 : 0); } +el_val_t el_duration_eq(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a == (int64_t)b ? 1 : 0); } +el_val_t el_duration_ne(el_val_t a, el_val_t b) { return (el_val_t)((int64_t)a != (int64_t)b ? 1 : 0); } + +/* Conversions. */ +el_val_t instant_to_unix_seconds(el_val_t i) { + return (el_val_t)((int64_t)i / 1000000000LL); +} + +el_val_t instant_to_unix_millis(el_val_t i) { + return (el_val_t)((int64_t)i / 1000000LL); +} + +el_val_t instant_to_iso8601(el_val_t i) { + int64_t ns = (int64_t)i; + time_t s = (time_t)(ns / 1000000000LL); + int msec = (int)((ns / 1000000LL) % 1000LL); + if (msec < 0) { msec += 1000; s -= 1; } + struct tm tm; + gmtime_r(&s, &tm); + char buf[64]; + snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, msec); + return el_wrap_str(el_strdup(buf)); +} + +el_val_t duration_to_seconds(el_val_t d) { + return (el_val_t)((int64_t)d / 1000000000LL); +} + +el_val_t duration_to_millis(el_val_t d) { + return (el_val_t)((int64_t)d / 1000000LL); +} + +el_val_t duration_to_nanos(el_val_t d) { + return (el_val_t)(int64_t)d; +} + +/* sleep(Duration) — Phase 1 replacement for ambiguous sleep(Int). The runtime + * still exposes sleep_secs/sleep_ms for legacy call sites; codegen lowers + * sleep(Duration) to el_sleep_duration(d). Negative durations clamp to 0 so a + * stale deadline doesn't block forever. */ +el_val_t el_sleep_duration(el_val_t dur) { + int64_t ns = (int64_t)dur; + if (ns < 0) ns = 0; + struct timespec ts; + ts.tv_sec = (time_t)(ns / 1000000000LL); + ts.tv_nsec = (long)(ns % 1000000000LL); + nanosleep(&ts, NULL); + return (el_val_t)0; +} + +/* unix_timestamp() — back-compat. Existing El callers expect an Int seconds + * value; this stays an Int returner so the type system isn't disturbed for + * legacy code. New code should call now() and convert when needed. */ +el_val_t unix_timestamp(void) { + return instant_to_unix_seconds(el_now_instant()); +} + +/* TTL cache helpers. Backed by the existing process-wide K/V (state_set/get) + * with a sibling __ttl_set_at_ entry recording the Instant of the last + * write. ttl_cache_get returns "" if the entry is missing or stale, so call + * sites can branch on `if v == "" { miss } else { hit }` — the same shape + * existing get-with-default code uses. No more (now - cached_at) < 60. */ +el_val_t ttl_cache_set(el_val_t key, el_val_t value) { + const char* k = EL_CSTR(key); + if (!k) return (el_val_t)0; + /* Store the value at the user's key. */ + state_set(key, value); + /* Stamp set_at — opaque schema, namespaced under __ttl: prefix so user + * keys can't collide with stamps. */ + size_t klen = strlen(k); + char* stamp_key = (char*)malloc(klen + 16); + if (!stamp_key) return (el_val_t)0; + snprintf(stamp_key, klen + 16, "__ttl_at:%s", k); + int64_t now_ns = (int64_t)el_now_instant(); + char buf[32]; + snprintf(buf, sizeof(buf), "%lld", (long long)now_ns); + state_set(EL_STR(stamp_key), EL_STR(buf)); + free(stamp_key); + return (el_val_t)1; +} + +el_val_t ttl_cache_get(el_val_t key, el_val_t max_age) { + const char* k = EL_CSTR(key); + if (!k) return el_wrap_str(el_strdup("")); + /* Look up stamp. */ + size_t klen = strlen(k); + char* stamp_key = (char*)malloc(klen + 16); + if (!stamp_key) return el_wrap_str(el_strdup("")); + snprintf(stamp_key, klen + 16, "__ttl_at:%s", k); + el_val_t stamp = state_get(EL_STR(stamp_key)); + free(stamp_key); + const char* sv = EL_CSTR(stamp); + if (!sv || !*sv) return el_wrap_str(el_strdup("")); + int64_t set_at = (int64_t)atoll(sv); + int64_t now_ns = (int64_t)el_now_instant(); + int64_t age = now_ns - set_at; + int64_t max_ns = (int64_t)max_age; + if (age < 0) return el_wrap_str(el_strdup("")); /* clock skew — treat as miss */ + if (age > max_ns) return el_wrap_str(el_strdup("")); /* expired */ + return state_get(key); +} + +el_val_t ttl_cache_age(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return (el_val_t)INT64_MAX; + size_t klen = strlen(k); + char* stamp_key = (char*)malloc(klen + 16); + if (!stamp_key) return (el_val_t)INT64_MAX; + snprintf(stamp_key, klen + 16, "__ttl_at:%s", k); + el_val_t stamp = state_get(EL_STR(stamp_key)); + free(stamp_key); + const char* sv = EL_CSTR(stamp); + if (!sv || !*sv) return (el_val_t)INT64_MAX; + int64_t set_at = (int64_t)atoll(sv); + int64_t now_ns = (int64_t)el_now_instant(); + return (el_val_t)(now_ns - set_at); +} + +/* ── Calendar + CalendarTime + Rhythm + LocalDate/Time/DateTime ────────────── + * Phase 1.5. Calendar is pluggable: EarthCalendar (IANA zones + Gregorian + + * DST), MarsCalendar (sols, MTC), CycleCalendar(period), NoCycleCalendar, + * RelativeCalendar(epoch). Phase 1 zone wrapping folds INTO EarthCalendar; + * UTC and IANA zones are themselves Earth-parochial and cannot live at the + * lowest type layer. + * + * A Rhythm is a small AST that asks the Calendar for cycle phase, weekday, + * etc. Most rhythm logic is calendar-agnostic at runtime: rhythm_cycle_phase + * means "midpoint of cycle" whether the cycle is 24h on Earth or 30h on a + * station or 300y on a long-cycle world. */ + +/* Magic headers — used by the runtime to recognize boxed temporal values + * arriving through el_val_t. Distinct constants so accidental misuse fails + * loudly rather than silently. */ +#define EL_CAL_MAGIC 0xE1CA1EDDU +#define EL_CALTIME_MAGIC 0xE1CA1747U +#define EL_RHYTHM_MAGIC 0xE1287A11U +#define EL_LDATE_MAGIC 0xE1DA7E00U +#define EL_LDT_MAGIC 0xE1DA7E1DU +#define EL_ZONE_MAGIC 0xE12017E0U + +typedef enum { + EL_CALENDAR_EARTH = 1, + EL_CALENDAR_MARS = 2, + EL_CALENDAR_CYCLE = 3, + EL_CALENDAR_NO_CYCLE = 4, + EL_CALENDAR_RELATIVE = 5 +} el_calendar_kind_t; + +typedef struct { + uint32_t magic; + char* id; /* IANA name or "+HH:MM" / "-HH:MM" */ + int fixed; /* 1 for fixed offset, 0 for IANA */ + int64_t offset_ns; /* fixed offset in nanos (only when fixed) */ +} el_zone_t; + +typedef struct { + uint32_t magic; + el_calendar_kind_t kind; + el_zone_t* zone; /* EarthCalendar; MarsCalendar uses MTC */ + int64_t cycle_period_ns;/* CycleCalendar; computed for Earth (86400 s) and Mars (88775.244 s) */ + int64_t epoch_ns; /* RelativeCalendar; Unix-epoch zero otherwise */ +} el_calendar_t; + +typedef struct { + uint32_t magic; + int64_t instant_ns; + el_calendar_t* cal; +} el_caltime_t; + +/* Rhythm AST. */ +typedef enum { + EL_RHYTHM_CYCLE_START = 1, + EL_RHYTHM_CYCLE_PHASE = 2, + EL_RHYTHM_DURATION = 3, + EL_RHYTHM_SESSION_START = 4, + EL_RHYTHM_EVENT = 5, + EL_RHYTHM_AND = 6, + EL_RHYTHM_OR = 7, + EL_RHYTHM_WEEKDAY = 8, + EL_RHYTHM_WEEKLY_AT = 9 +} el_rhythm_kind_t; + +typedef struct el_rhythm_s { + uint32_t magic; + el_rhythm_kind_t kind; + double phase; /* CYCLE_PHASE */ + int64_t period_ns; /* DURATION */ + int weekday; /* 1..7 Mon..Sun */ + int hour; + int minute; + char* event_name; /* EVENT */ + struct el_rhythm_s* a; /* AND/OR */ + struct el_rhythm_s* b; +} el_rhythm_t; + +typedef struct { + uint32_t magic; + int year; + int month; + int day; +} el_localdate_t; + +typedef struct { + uint32_t magic; + el_localdate_t* date; + int64_t time_ns; /* nanos since midnight */ +} el_localdt_t; + +/* Magic-tag check helpers — peek the first 4 bytes of an el_val_t pointer + * and compare against the expected magic. Strings are NUL-terminated and + * never start with our magic byte sequence, so this is safe. */ +static int el_is_magic(el_val_t v, uint32_t want) { + if (v == 0) return 0; + /* Defensive: only follow pointers in plausible address space. + * On 64-bit unix processes pointers are above 0x10000. */ + if ((uint64_t)v < 0x10000ULL) return 0; + uint32_t got = *(volatile uint32_t*)(uintptr_t)v; + return got == want; +} + +/* Sol length on Mars in nanoseconds: 88775.244 seconds. */ +#define EL_MARS_SOL_NS ((int64_t)88775244000000LL) +/* Earth solar day in nanoseconds: 86400 seconds. */ +#define EL_EARTH_DAY_NS ((int64_t)86400000000000LL) + +/* ── Zone construction ────────────────────────────────────────────────────── + * Zones intern by id string so equality comparisons are pointer-compares. */ + +#define EL_ZONE_TABLE_CAP 64 +static el_zone_t* _el_zone_table[EL_ZONE_TABLE_CAP]; +static int _el_zone_count = 0; + +static el_zone_t* _el_zone_intern(const char* id, int fixed, int64_t offset_ns) { + for (int i = 0; i < _el_zone_count; i++) { + el_zone_t* z = _el_zone_table[i]; + if (z->fixed == fixed && z->offset_ns == offset_ns && + strcmp(z->id ? z->id : "", id ? id : "") == 0) { + return z; + } + } + if (_el_zone_count >= EL_ZONE_TABLE_CAP) { + /* Out of slots: build a non-interned zone. Equality will fail across + * such zones but the program still runs. */ + el_zone_t* z = (el_zone_t*)malloc(sizeof(el_zone_t)); + z->magic = EL_ZONE_MAGIC; + z->id = el_strdup_persist(id ? id : ""); + z->fixed = fixed; + z->offset_ns = offset_ns; + return z; + } + el_zone_t* z = (el_zone_t*)malloc(sizeof(el_zone_t)); + z->magic = EL_ZONE_MAGIC; + z->id = el_strdup_persist(id ? id : ""); + z->fixed = fixed; + z->offset_ns = offset_ns; + _el_zone_table[_el_zone_count++] = z; + return z; +} + +el_val_t zone(el_val_t id) { + const char* s = EL_CSTR(id); + if (!s || !*s) return (el_val_t)(uintptr_t)_el_zone_intern("UTC", 0, 0); + /* Fixed-offset shortcut: "+HH:MM" or "-HH:MM". */ + if ((s[0] == '+' || s[0] == '-') && strlen(s) >= 6 && s[3] == ':') { + int sign = (s[0] == '-') ? -1 : 1; + int hh = (s[1] - '0') * 10 + (s[2] - '0'); + int mm = (s[4] - '0') * 10 + (s[5] - '0'); + int64_t off = (int64_t)sign * ((int64_t)hh * 3600LL + (int64_t)mm * 60LL) * 1000000000LL; + return (el_val_t)(uintptr_t)_el_zone_intern(s, 1, off); + } + return (el_val_t)(uintptr_t)_el_zone_intern(s, 0, 0); +} + +el_val_t zone_utc(void) { + return (el_val_t)(uintptr_t)_el_zone_intern("UTC", 1, 0); +} + +el_val_t zone_local(void) { + /* Resolve the local zone via TZ env or system default. tzset() picks + * up TZ if set; otherwise the C library reads /etc/localtime. We store + * the zone id as "LOCAL" so subsequent equality holds; resolution is + * lazy at use time. */ + return (el_val_t)(uintptr_t)_el_zone_intern("LOCAL", 0, 0); +} + +el_val_t zone_offset(el_val_t hours, el_val_t minutes) { + int hh = (int)(int64_t)hours; + int mm = (int)(int64_t)minutes; + int sign = (hh < 0 || mm < 0) ? -1 : 1; + if (hh < 0) hh = -hh; + if (mm < 0) mm = -mm; + int64_t off = (int64_t)sign * ((int64_t)hh * 3600LL + (int64_t)mm * 60LL) * 1000000000LL; + char buf[16]; + snprintf(buf, sizeof(buf), "%c%02d:%02d", sign < 0 ? '-' : '+', hh, mm); + return (el_val_t)(uintptr_t)_el_zone_intern(buf, 1, off); +} + +/* ── Calendar interning ──────────────────────────────────────────────────── */ + +#define EL_CAL_TABLE_CAP 64 +static el_calendar_t* _el_cal_table[EL_CAL_TABLE_CAP]; +static int _el_cal_count = 0; + +static el_calendar_t* _el_cal_intern(el_calendar_kind_t kind, el_zone_t* z, + int64_t period_ns, int64_t epoch_ns) { + for (int i = 0; i < _el_cal_count; i++) { + el_calendar_t* c = _el_cal_table[i]; + if (c->kind == kind && c->zone == z && + c->cycle_period_ns == period_ns && c->epoch_ns == epoch_ns) { + return c; + } + } + el_calendar_t* c = (el_calendar_t*)malloc(sizeof(el_calendar_t)); + c->magic = EL_CAL_MAGIC; + c->kind = kind; + c->zone = z; + c->cycle_period_ns = period_ns; + c->epoch_ns = epoch_ns; + if (_el_cal_count < EL_CAL_TABLE_CAP) _el_cal_table[_el_cal_count++] = c; + return c; +} + +el_val_t earth_calendar(el_val_t z_val) { + el_zone_t* z = NULL; + if (z_val != 0 && el_is_magic(z_val, EL_ZONE_MAGIC)) { + z = (el_zone_t*)(uintptr_t)z_val; + } else { + z = (el_zone_t*)(uintptr_t)zone_local(); + } + return (el_val_t)(uintptr_t)_el_cal_intern(EL_CALENDAR_EARTH, z, EL_EARTH_DAY_NS, 0); +} + +el_val_t earth_calendar_default(void) { + return earth_calendar(zone_local()); +} + +el_val_t mars_calendar(void) { + el_zone_t* z = (el_zone_t*)(uintptr_t)_el_zone_intern("MTC", 1, 0); + return (el_val_t)(uintptr_t)_el_cal_intern(EL_CALENDAR_MARS, z, EL_MARS_SOL_NS, 0); +} + +el_val_t cycle_calendar(el_val_t period_dur) { + int64_t period = (int64_t)period_dur; + if (period <= 0) period = 1; + return (el_val_t)(uintptr_t)_el_cal_intern(EL_CALENDAR_CYCLE, NULL, period, 0); +} + +el_val_t no_cycle_calendar(void) { + return (el_val_t)(uintptr_t)_el_cal_intern(EL_CALENDAR_NO_CYCLE, NULL, 0, 0); +} + +el_val_t relative_calendar(el_val_t epoch_inst) { + int64_t ep = (int64_t)epoch_inst; + return (el_val_t)(uintptr_t)_el_cal_intern(EL_CALENDAR_RELATIVE, NULL, 0, ep); +} + +/* ── CalendarTime ───────────────────────────────────────────────────────── */ + +static el_caltime_t* _el_caltime_alloc(int64_t inst, el_calendar_t* c) { + el_caltime_t* ct = (el_caltime_t*)malloc(sizeof(el_caltime_t)); + ct->magic = EL_CALTIME_MAGIC; + ct->instant_ns = inst; + ct->cal = c; + return ct; +} + +static el_calendar_t* _el_resolve_cal(el_val_t cal_val) { + if (cal_val == 0 || !el_is_magic(cal_val, EL_CAL_MAGIC)) { + return (el_calendar_t*)(uintptr_t)earth_calendar_default(); + } + return (el_calendar_t*)(uintptr_t)cal_val; +} + +el_val_t now_in(el_val_t cal_val) { + el_calendar_t* c = _el_resolve_cal(cal_val); + int64_t ns = (int64_t)el_now_instant(); + return (el_val_t)(uintptr_t)_el_caltime_alloc(ns, c); +} + +el_val_t in_calendar(el_val_t inst, el_val_t cal_val) { + el_calendar_t* c = _el_resolve_cal(cal_val); + return (el_val_t)(uintptr_t)_el_caltime_alloc((int64_t)inst, c); +} + +el_val_t cal_to_instant(el_val_t ct_val) { + if (!el_is_magic(ct_val, EL_CALTIME_MAGIC)) return (el_val_t)0; + el_caltime_t* ct = (el_caltime_t*)(uintptr_t)ct_val; + return (el_val_t)ct->instant_ns; +} + +el_val_t cal_in(el_val_t ct_val, el_val_t cal_val) { + if (!el_is_magic(ct_val, EL_CALTIME_MAGIC)) return (el_val_t)0; + el_caltime_t* ct = (el_caltime_t*)(uintptr_t)ct_val; + el_calendar_t* c = _el_resolve_cal(cal_val); + return (el_val_t)(uintptr_t)_el_caltime_alloc(ct->instant_ns, c); +} + +el_val_t cal_cycle_phase(el_val_t ct_val) { + if (!el_is_magic(ct_val, EL_CALTIME_MAGIC)) return el_from_float(0.0); + el_caltime_t* ct = (el_caltime_t*)(uintptr_t)ct_val; + el_calendar_t* c = ct->cal; + if (c->kind == EL_CALENDAR_NO_CYCLE) { + return el_from_float(0.0/0.0); /* NaN sentinel */ + } + int64_t period = c->cycle_period_ns; + if (period <= 0) return el_from_float(0.0); + int64_t base = ct->instant_ns - c->epoch_ns; + int64_t phase_ns = base % period; + if (phase_ns < 0) phase_ns += period; + double phase = (double)phase_ns / (double)period; + return el_from_float(phase); +} + +/* ── Earth zone resolution: TZ-based offset lookup ────────────────────────── + * For an EarthCalendar(zone), we want to convert an instant_ns into local + * y/m/d/h/m/s, including DST. Approach: setenv("TZ", id), tzset(), use + * localtime_r, then restore. This is not thread-safe by design — El's + * runtime is single-threaded for the request handler path. Cache the + * computed (instant -> tm) to avoid the syscall churn on repeat formats. */ + +static void _el_apply_zone(el_zone_t* z) { + if (!z) { unsetenv("TZ"); tzset(); return; } + if (z->fixed && strcmp(z->id, "UTC") == 0) { + setenv("TZ", "UTC0", 1); + tzset(); + return; + } + if (z->fixed) { + /* Fixed offset: POSIX TZ uses inverted sign (sign convention of + * "hours WEST of UTC" rather than east). Build the spec accordingly. */ + char buf[32]; + int neg_secs = (int)(-z->offset_ns / 1000000000LL); + int sign = neg_secs < 0 ? -1 : 1; + int abs_secs = neg_secs < 0 ? -neg_secs : neg_secs; + int hh = abs_secs / 3600; + int mm = (abs_secs % 3600) / 60; + snprintf(buf, sizeof(buf), "FIX%c%d:%02d", sign < 0 ? '-' : '+', hh, mm); + setenv("TZ", buf, 1); + tzset(); + return; + } + if (strcmp(z->id, "LOCAL") == 0) { + unsetenv("TZ"); + tzset(); + return; + } + setenv("TZ", z->id, 1); + tzset(); +} + +static int _el_decompose_earth(el_caltime_t* ct, struct tm* tm_out, int* abbr_len, char* abbr_buf, size_t abbr_cap) { + el_calendar_t* c = ct->cal; + el_zone_t* z = c->zone; + _el_apply_zone(z); + time_t s = (time_t)(ct->instant_ns / 1000000000LL); + struct tm tm; + localtime_r(&s, &tm); + *tm_out = tm; + if (abbr_buf && abbr_cap > 0) { + const char* z_str = tm.tm_zone ? tm.tm_zone : ""; + size_t n = strlen(z_str); + if (n >= abbr_cap) n = abbr_cap - 1; + memcpy(abbr_buf, z_str, n); + abbr_buf[n] = '\0'; + if (abbr_len) *abbr_len = (int)n; + } + return 0; +} + +/* Format an Earth CalendarTime under a Java-DateTimeFormatter-ish pattern. + * We support a useful core: yyyy MM dd HH mm ss z EEE MMM d h a — enough for + * the acceptance tests. Single quotes denote literal text. */ +static const char* _el_weekday_short[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; +static const char* _el_month_short[] = {"Jan","Feb","Mar","Apr","May","Jun", + "Jul","Aug","Sep","Oct","Nov","Dec"}; + +static char* _el_format_earth(el_caltime_t* ct, const char* pattern) { + struct tm tm; + char abbr[16] = {0}; + int abbr_len = 0; + _el_decompose_earth(ct, &tm, &abbr_len, abbr, sizeof(abbr)); + size_t cap = strlen(pattern) * 4 + 64; + char* out = (char*)malloc(cap); + size_t pos = 0; + size_t i = 0; + size_t plen = strlen(pattern); + while (i < plen) { + char ch = pattern[i]; + /* Quoted literal */ + if (ch == '\'') { + i++; + while (i < plen && pattern[i] != '\'') { + if (pos + 1 >= cap) { cap *= 2; out = realloc(out, cap); } + out[pos++] = pattern[i++]; + } + if (i < plen) i++; + continue; + } + /* Count run of same letter */ + size_t run = 1; + while (i + run < plen && pattern[i + run] == ch) run++; + char tmp[64]; + tmp[0] = '\0'; + if (ch == 'y') { + if (run >= 4) snprintf(tmp, sizeof(tmp), "%04d", tm.tm_year + 1900); + else snprintf(tmp, sizeof(tmp), "%02d", (tm.tm_year + 1900) % 100); + } else if (ch == 'M') { + if (run >= 3) snprintf(tmp, sizeof(tmp), "%s", _el_month_short[tm.tm_mon]); + else if (run == 2) snprintf(tmp, sizeof(tmp), "%02d", tm.tm_mon + 1); + else snprintf(tmp, sizeof(tmp), "%d", tm.tm_mon + 1); + } else if (ch == 'd') { + if (run >= 2) snprintf(tmp, sizeof(tmp), "%02d", tm.tm_mday); + else snprintf(tmp, sizeof(tmp), "%d", tm.tm_mday); + } else if (ch == 'H') { + if (run >= 2) snprintf(tmp, sizeof(tmp), "%02d", tm.tm_hour); + else snprintf(tmp, sizeof(tmp), "%d", tm.tm_hour); + } else if (ch == 'h') { + int h12 = tm.tm_hour % 12; if (h12 == 0) h12 = 12; + if (run >= 2) snprintf(tmp, sizeof(tmp), "%02d", h12); + else snprintf(tmp, sizeof(tmp), "%d", h12); + } else if (ch == 'm') { + if (run >= 2) snprintf(tmp, sizeof(tmp), "%02d", tm.tm_min); + else snprintf(tmp, sizeof(tmp), "%d", tm.tm_min); + } else if (ch == 's') { + if (run >= 2) snprintf(tmp, sizeof(tmp), "%02d", tm.tm_sec); + else snprintf(tmp, sizeof(tmp), "%d", tm.tm_sec); + } else if (ch == 'a') { + snprintf(tmp, sizeof(tmp), "%s", tm.tm_hour < 12 ? "AM" : "PM"); + } else if (ch == 'E') { + snprintf(tmp, sizeof(tmp), "%s", _el_weekday_short[tm.tm_wday]); + } else if (ch == 'z') { + snprintf(tmp, sizeof(tmp), "%s", abbr); + } else { + for (size_t k = 0; k < run; k++) { + if (pos + 1 >= cap) { cap *= 2; out = realloc(out, cap); } + out[pos++] = ch; + } + i += run; + continue; + } + size_t tl = strlen(tmp); + if (pos + tl + 1 >= cap) { cap = (cap + tl) * 2; out = realloc(out, cap); } + memcpy(out + pos, tmp, tl); + pos += tl; + i += run; + } + out[pos] = '\0'; + char* result = el_strdup(out); + free(out); + return result; +} + +/* Format a Mars CalendarTime: %sol prints the integer sol number since + * mission epoch (Unix epoch fallback), %phase prints cycle_phase as a + * 0..1 decimal. Other %-specifiers fall through. */ +static char* _el_format_mars(el_caltime_t* ct, const char* pattern) { + el_calendar_t* c = ct->cal; + int64_t period = c->cycle_period_ns > 0 ? c->cycle_period_ns : EL_MARS_SOL_NS; + int64_t base = ct->instant_ns - c->epoch_ns; + int64_t sol = base / period; + int64_t phase_ns = base % period; + if (phase_ns < 0) { phase_ns += period; sol -= 1; } + double phase = (double)phase_ns / (double)period; + size_t cap = strlen(pattern) * 4 + 64; + char* out = (char*)malloc(cap); + size_t pos = 0; + for (size_t i = 0; pattern[i]; i++) { + if (pattern[i] == '%' && pattern[i+1]) { + char tmp[64]; + tmp[0] = '\0'; + if (strncmp(pattern + i + 1, "sol", 3) == 0) { + snprintf(tmp, sizeof(tmp), "%lld", (long long)sol); + i += 3; + } else if (strncmp(pattern + i + 1, "phase", 5) == 0) { + snprintf(tmp, sizeof(tmp), "%.4f", phase); + i += 5; + } else if (pattern[i+1] == 'd') { + snprintf(tmp, sizeof(tmp), "%lld", (long long)sol); + i += 1; + } else { + tmp[0] = pattern[i+1]; tmp[1] = '\0'; + i += 1; + } + size_t tl = strlen(tmp); + if (pos + tl + 1 >= cap) { cap = (cap + tl) * 2; out = realloc(out, cap); } + memcpy(out + pos, tmp, tl); + pos += tl; + } else { + if (pos + 1 >= cap) { cap *= 2; out = realloc(out, cap); } + out[pos++] = pattern[i]; + } + } + out[pos] = '\0'; + char* result = el_strdup(out); + free(out); + return result; +} + +/* Format a CycleCalendar CalendarTime: %cycle and %phase. */ +static char* _el_format_cycle(el_caltime_t* ct, const char* pattern) { + el_calendar_t* c = ct->cal; + int64_t period = c->cycle_period_ns > 0 ? c->cycle_period_ns : 1; + int64_t base = ct->instant_ns - c->epoch_ns; + int64_t cycle = base / period; + int64_t phase_ns = base % period; + if (phase_ns < 0) { phase_ns += period; cycle -= 1; } + double phase = (double)phase_ns / (double)period; + size_t cap = strlen(pattern) * 4 + 64; + char* out = (char*)malloc(cap); + size_t pos = 0; + for (size_t i = 0; pattern[i]; i++) { + if (pattern[i] == '%' && pattern[i+1]) { + char tmp[64]; + tmp[0] = '\0'; + if (strncmp(pattern + i + 1, "cycle", 5) == 0) { + snprintf(tmp, sizeof(tmp), "%lld", (long long)cycle); + i += 5; + } else if (strncmp(pattern + i + 1, "phase", 5) == 0) { + snprintf(tmp, sizeof(tmp), "%.4f", phase); + i += 5; + } else if (pattern[i+1] == 'd') { + snprintf(tmp, sizeof(tmp), "%lld", (long long)cycle); + i += 1; + } else if (pattern[i+1] == 'f') { + snprintf(tmp, sizeof(tmp), "%.2f", phase); + i += 1; + } else { + /* Pass through unknown specifier */ + tmp[0] = '%'; tmp[1] = pattern[i+1]; tmp[2] = '\0'; + i += 1; + } + size_t tl = strlen(tmp); + if (pos + tl + 1 >= cap) { cap = (cap + tl) * 2; out = realloc(out, cap); } + memcpy(out + pos, tmp, tl); + pos += tl; + } else { + if (pos + 1 >= cap) { cap *= 2; out = realloc(out, cap); } + out[pos++] = pattern[i]; + } + } + out[pos] = '\0'; + char* result = el_strdup(out); + free(out); + return result; +} + +el_val_t cal_format(el_val_t ct_val, el_val_t pattern_val) { + if (!el_is_magic(ct_val, EL_CALTIME_MAGIC)) return el_wrap_str(el_strdup("")); + el_caltime_t* ct = (el_caltime_t*)(uintptr_t)ct_val; + const char* pat = EL_CSTR(pattern_val); + if (!pat) pat = ""; + char* result = NULL; + switch (ct->cal->kind) { + case EL_CALENDAR_EARTH: result = _el_format_earth(ct, pat); break; + case EL_CALENDAR_MARS: result = _el_format_mars(ct, pat); break; + case EL_CALENDAR_CYCLE: result = _el_format_cycle(ct, pat); break; + case EL_CALENDAR_RELATIVE: result = _el_format_cycle(ct, pat); break; + case EL_CALENDAR_NO_CYCLE: { + char buf[64]; + snprintf(buf, sizeof(buf), "instant:%lld", (long long)ct->instant_ns); + result = el_strdup(buf); + break; + } + default: result = el_strdup(""); + } + return el_wrap_str(result); +} + +/* ── LocalDate / LocalTime / LocalDateTime ──────────────────────────────── */ + +static int _el_days_in_month(int y, int m) { + static const int dim[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; + if (m == 2) { + int leap = ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0); + return 28 + (leap ? 1 : 0); + } + if (m < 1 || m > 12) return 30; + return dim[m - 1]; +} + +el_val_t local_date(el_val_t y, el_val_t m, el_val_t d) { + el_localdate_t* ld = (el_localdate_t*)malloc(sizeof(el_localdate_t)); + ld->magic = EL_LDATE_MAGIC; + ld->year = (int)(int64_t)y; + ld->month = (int)(int64_t)m; + ld->day = (int)(int64_t)d; + return (el_val_t)(uintptr_t)ld; +} + +el_val_t local_time(el_val_t h, el_val_t m, el_val_t s, el_val_t ns) { + int64_t hh = (int64_t)h; + int64_t mm = (int64_t)m; + int64_t ss = (int64_t)s; + int64_t nn = (int64_t)ns; + int64_t total = hh * 3600000000000LL + mm * 60000000000LL + ss * 1000000000LL + nn; + return (el_val_t)total; +} + +el_val_t local_datetime(el_val_t date_val, el_val_t time_val) { + if (!el_is_magic(date_val, EL_LDATE_MAGIC)) return (el_val_t)0; + el_localdt_t* ldt = (el_localdt_t*)malloc(sizeof(el_localdt_t)); + ldt->magic = EL_LDT_MAGIC; + ldt->date = (el_localdate_t*)(uintptr_t)date_val; + ldt->time_ns = (int64_t)time_val; + return (el_val_t)(uintptr_t)ldt; +} + +el_val_t zoned(el_val_t date_val, el_val_t time_val, el_val_t cal_val) { + if (!el_is_magic(date_val, EL_LDATE_MAGIC)) return (el_val_t)0; + el_localdate_t* ld = (el_localdate_t*)(uintptr_t)date_val; + el_calendar_t* c = _el_resolve_cal(cal_val); + int64_t time_ns = (int64_t)time_val; + /* Convert (LocalDate, LocalTime, EarthCalendar) -> Instant. + * For non-Earth calendars we use day-anchored conversion: treat the + * LocalDate's (y,m,d) as a Gregorian projection, convert to seconds via + * mktime under the calendar's zone, then add nanos-since-midnight. */ + if (c->kind == EL_CALENDAR_EARTH) { + _el_apply_zone(c->zone); + struct tm tm; memset(&tm, 0, sizeof(tm)); + tm.tm_year = ld->year - 1900; + tm.tm_mon = ld->month - 1; + tm.tm_mday = ld->day; + tm.tm_hour = (int)(time_ns / 3600000000000LL); + tm.tm_min = (int)((time_ns / 60000000000LL) % 60); + tm.tm_sec = (int)((time_ns / 1000000000LL) % 60); + tm.tm_isdst = -1; + time_t t = mktime(&tm); + if (t == (time_t)-1) return (el_val_t)0; + int64_t ns = (int64_t)t * 1000000000LL + (time_ns % 1000000000LL); + return (el_val_t)(uintptr_t)_el_caltime_alloc(ns, c); + } + /* Non-Earth fallback: project as if Earth UTC then attach calendar. */ + struct tm tm; memset(&tm, 0, sizeof(tm)); + tm.tm_year = ld->year - 1900; + tm.tm_mon = ld->month - 1; + tm.tm_mday = ld->day; + tm.tm_hour = (int)(time_ns / 3600000000000LL); + tm.tm_min = (int)((time_ns / 60000000000LL) % 60); + tm.tm_sec = (int)((time_ns / 1000000000LL) % 60); + time_t t = timegm(&tm); + if (t == (time_t)-1) return (el_val_t)0; + int64_t ns = (int64_t)t * 1000000000LL + (time_ns % 1000000000LL); + return (el_val_t)(uintptr_t)_el_caltime_alloc(ns, c); +} + +el_val_t local_date_year(el_val_t v) { + if (!el_is_magic(v, EL_LDATE_MAGIC)) return (el_val_t)0; + return (el_val_t)((el_localdate_t*)(uintptr_t)v)->year; +} +el_val_t local_date_month(el_val_t v) { + if (!el_is_magic(v, EL_LDATE_MAGIC)) return (el_val_t)0; + return (el_val_t)((el_localdate_t*)(uintptr_t)v)->month; +} +el_val_t local_date_day(el_val_t v) { + if (!el_is_magic(v, EL_LDATE_MAGIC)) return (el_val_t)0; + return (el_val_t)((el_localdate_t*)(uintptr_t)v)->day; +} +el_val_t local_time_hour(el_val_t v) { + int64_t t = (int64_t)v; + return (el_val_t)(t / 3600000000000LL); +} +el_val_t local_time_minute(el_val_t v) { + int64_t t = (int64_t)v; + return (el_val_t)((t / 60000000000LL) % 60); +} +el_val_t local_time_second(el_val_t v) { + int64_t t = (int64_t)v; + return (el_val_t)((t / 1000000000LL) % 60); +} +el_val_t local_time_nanos(el_val_t v) { + int64_t t = (int64_t)v; + return (el_val_t)(t % 1000000000LL); +} + +el_val_t el_local_date_add_dur(el_val_t ld_val, el_val_t dur_val) { + if (!el_is_magic(ld_val, EL_LDATE_MAGIC)) return ld_val; + el_localdate_t* ld = (el_localdate_t*)(uintptr_t)ld_val; + int64_t dur_ns = (int64_t)dur_val; + int64_t days = dur_ns / EL_EARTH_DAY_NS; + int y = ld->year, m = ld->month, d = ld->day; + /* Walk days forward/backward in canonical Gregorian. */ + while (days > 0) { + int dim = _el_days_in_month(y, m); + if (d + days <= dim) { d += (int)days; days = 0; break; } + days -= (dim - d + 1); + d = 1; + m++; + if (m > 12) { m = 1; y++; } + } + while (days < 0) { + if (d + days >= 1) { d += (int)days; days = 0; break; } + days += d; + m--; + if (m < 1) { m = 12; y--; } + d = _el_days_in_month(y, m); + } + return local_date((el_val_t)y, (el_val_t)m, (el_val_t)d); +} + +el_val_t el_local_time_add_dur(el_val_t lt_val, el_val_t dur_val) { + int64_t t = (int64_t)lt_val + (int64_t)dur_val; + /* Wrap mod 24h on Earth-default. CycleCalendar wrapping requires the + * caller to use cal_in / cal_format for the right modulus. */ + int64_t day = EL_EARTH_DAY_NS; + int64_t r = t % day; + if (r < 0) r += day; + return (el_val_t)r; +} + +el_val_t el_local_date_lt(el_val_t a_val, el_val_t b_val) { + if (!el_is_magic(a_val, EL_LDATE_MAGIC) || !el_is_magic(b_val, EL_LDATE_MAGIC)) return (el_val_t)0; + el_localdate_t* a = (el_localdate_t*)(uintptr_t)a_val; + el_localdate_t* b = (el_localdate_t*)(uintptr_t)b_val; + if (a->year != b->year) return (el_val_t)(a->year < b->year ? 1 : 0); + if (a->month != b->month) return (el_val_t)(a->month < b->month ? 1 : 0); + return (el_val_t)(a->day < b->day ? 1 : 0); +} + +el_val_t el_local_date_eq(el_val_t a_val, el_val_t b_val) { + if (!el_is_magic(a_val, EL_LDATE_MAGIC) || !el_is_magic(b_val, EL_LDATE_MAGIC)) return (el_val_t)0; + el_localdate_t* a = (el_localdate_t*)(uintptr_t)a_val; + el_localdate_t* b = (el_localdate_t*)(uintptr_t)b_val; + return (el_val_t)((a->year == b->year && a->month == b->month && a->day == b->day) ? 1 : 0); +} + +/* ── Rhythm ──────────────────────────────────────────────────────────────── */ + +static el_rhythm_t* _el_rhythm_alloc(el_rhythm_kind_t k) { + el_rhythm_t* r = (el_rhythm_t*)calloc(1, sizeof(el_rhythm_t)); + r->magic = EL_RHYTHM_MAGIC; + r->kind = k; + return r; +} + +el_val_t rhythm_cycle_start(void) { + return (el_val_t)(uintptr_t)_el_rhythm_alloc(EL_RHYTHM_CYCLE_START); +} + +el_val_t rhythm_cycle_phase(el_val_t phase_val) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_CYCLE_PHASE); + r->phase = el_to_float(phase_val); + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_duration(el_val_t d_val) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_DURATION); + r->period_ns = (int64_t)d_val; + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_session_start(void) { + return (el_val_t)(uintptr_t)_el_rhythm_alloc(EL_RHYTHM_SESSION_START); +} + +el_val_t rhythm_event(el_val_t name_val) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_EVENT); + const char* n = EL_CSTR(name_val); + r->event_name = el_strdup_persist(n ? n : ""); + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_and(el_val_t a_val, el_val_t b_val) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_AND); + r->a = el_is_magic(a_val, EL_RHYTHM_MAGIC) ? (el_rhythm_t*)(uintptr_t)a_val : NULL; + r->b = el_is_magic(b_val, EL_RHYTHM_MAGIC) ? (el_rhythm_t*)(uintptr_t)b_val : NULL; + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_or(el_val_t a_val, el_val_t b_val) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_OR); + r->a = el_is_magic(a_val, EL_RHYTHM_MAGIC) ? (el_rhythm_t*)(uintptr_t)a_val : NULL; + r->b = el_is_magic(b_val, EL_RHYTHM_MAGIC) ? (el_rhythm_t*)(uintptr_t)b_val : NULL; + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_weekday(el_val_t day) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_WEEKDAY); + r->weekday = (int)(int64_t)day; + return (el_val_t)(uintptr_t)r; +} + +el_val_t rhythm_weekly_at(el_val_t day, el_val_t hour, el_val_t minute) { + el_rhythm_t* r = _el_rhythm_alloc(EL_RHYTHM_WEEKLY_AT); + r->weekday = (int)(int64_t)day; + r->hour = (int)(int64_t)hour; + r->minute = (int)(int64_t)minute; + return (el_val_t)(uintptr_t)r; +} + +/* Compute the next instant on or after `after` when rhythm `r` matches, + * under calendar `cal`. */ +static int64_t _el_next_after(el_rhythm_t* r, int64_t after_ns, el_calendar_t* cal) { + if (!r) return after_ns; + int64_t period = cal->cycle_period_ns > 0 ? cal->cycle_period_ns : EL_EARTH_DAY_NS; + switch (r->kind) { + case EL_RHYTHM_CYCLE_START: { + int64_t base = after_ns - cal->epoch_ns; + int64_t cyc = (base / period) + 1; + return cal->epoch_ns + cyc * period; + } + case EL_RHYTHM_CYCLE_PHASE: { + int64_t base = after_ns - cal->epoch_ns; + int64_t cyc_ns = (int64_t)(r->phase * (double)period); + int64_t cur_cyc = base / period; + int64_t candidate = cal->epoch_ns + cur_cyc * period + cyc_ns; + if (candidate <= after_ns) candidate += period; + return candidate; + } + case EL_RHYTHM_DURATION: { + return after_ns + (r->period_ns > 0 ? r->period_ns : 1); + } + case EL_RHYTHM_WEEKDAY: + case EL_RHYTHM_WEEKLY_AT: { + if (cal->kind != EL_CALENDAR_EARTH) { + /* Non-Earth calendars: fall back to cycle math, treating + * weekday as a 7-cycle-per-period proxy. */ + return after_ns + period; + } + _el_apply_zone(cal->zone); + time_t s = (time_t)(after_ns / 1000000000LL); + struct tm tm; + localtime_r(&s, &tm); + /* tm_wday: 0=Sun..6=Sat. We use 1=Mon..7=Sun. */ + int target = r->weekday >= 1 && r->weekday <= 7 ? r->weekday : 1; + int target_wday = target == 7 ? 0 : target; /* 7→Sun=0, 1→Mon=1 */ + int days_ahead = (target_wday - tm.tm_wday + 7) % 7; + int hour = (r->kind == EL_RHYTHM_WEEKLY_AT) ? r->hour : 0; + int minute = (r->kind == EL_RHYTHM_WEEKLY_AT) ? r->minute : 0; + struct tm cand = tm; + cand.tm_mday += days_ahead; + cand.tm_hour = hour; + cand.tm_min = minute; + cand.tm_sec = 0; + cand.tm_isdst = -1; + time_t cand_t = mktime(&cand); + int64_t cand_ns = (int64_t)cand_t * 1000000000LL; + if (cand_ns <= after_ns) { + cand.tm_mday += 7; + cand.tm_isdst = -1; + cand_t = mktime(&cand); + cand_ns = (int64_t)cand_t * 1000000000LL; + } + return cand_ns; + } + case EL_RHYTHM_AND: { + int64_t a = _el_next_after(r->a, after_ns, cal); + int64_t b = _el_next_after(r->b, after_ns, cal); + return a > b ? a : b; + } + case EL_RHYTHM_OR: { + int64_t a = _el_next_after(r->a, after_ns, cal); + int64_t b = _el_next_after(r->b, after_ns, cal); + return a < b ? a : b; + } + case EL_RHYTHM_SESSION_START: + case EL_RHYTHM_EVENT: + default: + return after_ns; + } +} + +el_val_t rhythm_next_after(el_val_t r_val, el_val_t after_val, el_val_t cal_val) { + if (!el_is_magic(r_val, EL_RHYTHM_MAGIC)) return after_val; + el_rhythm_t* r = (el_rhythm_t*)(uintptr_t)r_val; + el_calendar_t* c = _el_resolve_cal(cal_val); + int64_t out = _el_next_after(r, (int64_t)after_val, c); + return (el_val_t)out; +} + +el_val_t rhythm_matches(el_val_t r_val, el_val_t ct_val) { + if (!el_is_magic(r_val, EL_RHYTHM_MAGIC)) return (el_val_t)0; + if (!el_is_magic(ct_val, EL_CALTIME_MAGIC)) return (el_val_t)0; + el_rhythm_t* r = (el_rhythm_t*)(uintptr_t)r_val; + el_caltime_t* ct = (el_caltime_t*)(uintptr_t)ct_val; + int64_t period = ct->cal->cycle_period_ns > 0 ? ct->cal->cycle_period_ns : EL_EARTH_DAY_NS; + int64_t base = ct->instant_ns - ct->cal->epoch_ns; + int64_t phase_ns = base % period; + if (phase_ns < 0) phase_ns += period; + double phase = (double)phase_ns / (double)period; + switch (r->kind) { + case EL_RHYTHM_CYCLE_START: return (el_val_t)(phase_ns == 0 ? 1 : 0); + case EL_RHYTHM_CYCLE_PHASE: { + double diff = phase - r->phase; + if (diff < 0) diff = -diff; + return (el_val_t)(diff < 0.001 ? 1 : 0); + } + default: return (el_val_t)0; + } +} + +/* ── UUID v4 ─────────────────────────────────────────────────────────────── */ + +static int _el_uuid_seeded = 0; + +static void _el_uuid_seed(void) { + if (!_el_uuid_seeded) { + srand((unsigned)time(NULL) ^ (unsigned)(uintptr_t)&_el_uuid_seeded); + _el_uuid_seeded = 1; + } +} + +el_val_t uuid_new(void) { + _el_uuid_seed(); + unsigned char b[16]; + for (int i = 0; i < 16; i++) b[i] = (unsigned char)(rand() & 0xff); + /* Version 4 */ + b[6] = (b[6] & 0x0f) | 0x40; + /* RFC 4122 variant */ + b[8] = (b[8] & 0x3f) | 0x80; + char buf[37]; + snprintf(buf, sizeof(buf), + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + b[0], b[1], b[2], b[3], + b[4], b[5], + b[6], b[7], + b[8], b[9], + b[10], b[11], b[12], b[13], b[14], b[15]); + return el_wrap_str(el_strdup(buf)); +} + +el_val_t uuid_v4(void) { return uuid_new(); } + +/* ── Environment ─────────────────────────────────────────────────────────── */ + +el_val_t env(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return el_wrap_str(el_strdup("")); + const char* v = getenv(k); + return el_wrap_str(el_strdup(v ? v : "")); +} + +/* ── In-process state K/V ────────────────────────────────────────────────── */ + +typedef struct { + char* key; + char* value; +} StateEntry; + +static StateEntry* _state_entries = NULL; +static size_t _state_count = 0; +static size_t _state_cap = 0; +/* Mutex protecting all _state_entries access. state_set/state_get are called + * concurrently from 64 HTTP worker threads — without this lock, realloc and + * free race, producing corruption, double-free, and segfaults. */ +static pthread_mutex_t _state_mu = PTHREAD_MUTEX_INITIALIZER; + +static StateEntry* state_find(const char* key) { + for (size_t i = 0; i < _state_count; i++) { + if (strcmp(_state_entries[i].key, key) == 0) return &_state_entries[i]; + } + return NULL; +} + +el_val_t state_set(el_val_t key, el_val_t value) { + const char* k = EL_CSTR(key); + const char* v = EL_CSTR(value); + if (!k) return 0; + if (!v) v = ""; + pthread_mutex_lock(&_state_mu); + StateEntry* e = state_find(k); + if (e) { + free(e->value); + e->value = el_strdup_persist(v); + pthread_mutex_unlock(&_state_mu); + return 1; + } + if (_state_count >= _state_cap) { + size_t nc = _state_cap == 0 ? 16 : _state_cap * 2; + StateEntry* grown = realloc(_state_entries, nc * sizeof(StateEntry)); + if (!grown) { pthread_mutex_unlock(&_state_mu); fputs("el_runtime: out of memory\n", stderr); exit(1); } + _state_entries = grown; + _state_cap = nc; + } + _state_entries[_state_count].key = el_strdup_persist(k); + _state_entries[_state_count].value = el_strdup_persist(v); + _state_count++; + pthread_mutex_unlock(&_state_mu); + return 1; +} + +el_val_t state_get(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return el_wrap_str(el_strdup("")); + pthread_mutex_lock(&_state_mu); + StateEntry* e = state_find(k); + char* result = el_strdup_persist(e ? e->value : ""); + pthread_mutex_unlock(&_state_mu); + /* wrap in arena-tracked copy for the caller's request lifetime */ + char* copy = el_strdup(result); + return el_wrap_str(copy); +} + +el_val_t state_del(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return 0; + pthread_mutex_lock(&_state_mu); + for (size_t i = 0; i < _state_count; i++) { + if (strcmp(_state_entries[i].key, k) == 0) { + free(_state_entries[i].key); + free(_state_entries[i].value); + for (size_t j = i + 1; j < _state_count; j++) { + _state_entries[j - 1] = _state_entries[j]; + } + _state_count--; + pthread_mutex_unlock(&_state_mu); + return 1; + } + } + pthread_mutex_unlock(&_state_mu); + return 1; +} + +el_val_t state_keys(void) { + pthread_mutex_lock(&_state_mu); + /* Build a JSON array string: ["key1","key2",...] */ + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + for (size_t i = 0; i < _state_count; i++) { + if (i > 0) jb_putc(&b, ','); + jb_putc(&b, '"'); + jb_emit_escaped(&b, _state_entries[i].key); + jb_putc(&b, '"'); + } + jb_putc(&b, ']'); + pthread_mutex_unlock(&_state_mu); + return el_wrap_str(b.buf); +} + +/* Returns 1 (true) if the key is present in the state store, else 0 (false). */ +el_val_t state_has(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return 0; + pthread_mutex_lock(&_state_mu); + StateEntry* e = state_find(k); + int found = (e != NULL) ? 1 : 0; + pthread_mutex_unlock(&_state_mu); + return (el_val_t)found; +} + +/* Returns the value for key, or default_val if the key is absent. */ +el_val_t state_get_or(el_val_t key, el_val_t default_val) { + const char* k = EL_CSTR(key); + if (!k) return default_val; + pthread_mutex_lock(&_state_mu); + StateEntry* e = state_find(k); + if (e) { + char* copy = el_strdup(e->value); + pthread_mutex_unlock(&_state_mu); + return el_wrap_str(copy); + } + pthread_mutex_unlock(&_state_mu); + return default_val; +} + +/* ── Float formatting ────────────────────────────────────────────────────── */ + +el_val_t float_to_str(el_val_t f) { + char buf[64]; + double v = el_to_float(f); + /* Normalize NaN to "nan" regardless of sign — platform-independent. */ + if (isnan(v)) { + snprintf(buf, sizeof(buf), "nan"); + } else { + snprintf(buf, sizeof(buf), "%g", v); + } + return el_wrap_str(el_strdup(buf)); +} + +el_val_t int_to_float(el_val_t n) { + return el_from_float((double)(int64_t)n); +} + +el_val_t float_to_int(el_val_t f) { + return (el_val_t)(int64_t)el_to_float(f); +} + +el_val_t format_float(el_val_t f, el_val_t decimals) { + int d = (int)(int64_t)decimals; + if (d < 0) d = 0; + if (d > 30) d = 30; + char buf[128]; + snprintf(buf, sizeof(buf), "%.*f", d, el_to_float(f)); + return el_wrap_str(el_strdup(buf)); +} + +el_val_t decimal_round(el_val_t f, el_val_t decimals) { + int d = (int)(int64_t)decimals; + if (d < 0) d = 0; + if (d > 15) d = 15; + double mul = pow(10.0, (double)d); + double v = el_to_float(f); + double r = (v >= 0.0 ? floor(v * mul + 0.5) : -floor(-v * mul + 0.5)) / mul; + return el_from_float(r); +} + +el_val_t str_to_float(el_val_t s) { + const char* str = EL_CSTR(s); + if (!str) return el_from_float(0.0); + return el_from_float(strtod(str, NULL)); +} + +/* ── Math (Float-aware) ──────────────────────────────────────────────────── */ + +el_val_t math_sqrt(el_val_t f) { return el_from_float(sqrt(el_to_float(f))); } +el_val_t math_log(el_val_t f) { return el_from_float(log(el_to_float(f))); } +el_val_t math_ln(el_val_t f) { return el_from_float(log(el_to_float(f))); } +el_val_t math_sin(el_val_t f) { return el_from_float(sin(el_to_float(f))); } +el_val_t math_cos(el_val_t f) { return el_from_float(cos(el_to_float(f))); } +el_val_t math_pi(void) { return el_from_float(3.141592653589793238462643383279502884); } + +/* ── String additions ────────────────────────────────────────────────────── */ + +el_val_t str_index_of(el_val_t s, el_val_t sub) { + const char* str = EL_CSTR(s); + const char* sb = EL_CSTR(sub); + if (!str || !sb) return -1; + const char* hit = strstr(str, sb); + if (!hit) return -1; + return (el_val_t)(int64_t)(hit - str); +} + +el_val_t str_split(el_val_t s, el_val_t sep) { + const char* str = EL_CSTR(s); + const char* sp = EL_CSTR(sep); + el_val_t lst = el_list_empty(); + if (!str) return lst; + if (!sp || !*sp) { + lst = el_list_append(lst, el_wrap_str(el_strdup(str))); + return lst; + } + size_t lp = strlen(sp); + const char* p = str; + const char* hit; + while ((hit = strstr(p, sp)) != NULL) { + size_t n = (size_t)(hit - p); + char* out = el_strbuf(n); + memcpy(out, p, n); + out[n] = '\0'; + lst = el_list_append(lst, el_wrap_str(out)); + p = hit + lp; + } + lst = el_list_append(lst, el_wrap_str(el_strdup(p))); + return lst; +} + +el_val_t str_char_at(el_val_t s, el_val_t i) { + const char* str = EL_CSTR(s); + int64_t idx = (int64_t)i; + if (!str) return el_wrap_str(el_strdup("")); + int64_t n = (int64_t)strlen(str); + if (idx < 0 || idx >= n) return el_wrap_str(el_strdup("")); + char buf[2]; + buf[0] = str[idx]; + buf[1] = '\0'; + return el_wrap_str(el_strdup(buf)); +} + +el_val_t str_char_code(el_val_t s, el_val_t i) { + const char* str = EL_CSTR(s); + int64_t idx = (int64_t)i; + if (!str) return 0; + int64_t n = (int64_t)strlen(str); + if (idx < 0 || idx >= n) return 0; + return (el_val_t)(unsigned char)str[idx]; +} + +static el_val_t str_pad(const char* s, int64_t width, const char* pad, int left) { + if (!s) s = ""; + if (!pad || !*pad) pad = " "; + int64_t lp = (int64_t)strlen(pad); + int64_t ls = (int64_t)strlen(s); + if (ls >= width) return el_wrap_str(el_strdup(s)); + int64_t need = width - ls; + char* out = el_strbuf((size_t)width); + if (left) { + for (int64_t i = 0; i < need; i++) out[i] = pad[i % lp]; + memcpy(out + need, s, (size_t)ls); + } else { + memcpy(out, s, (size_t)ls); + for (int64_t i = 0; i < need; i++) out[ls + i] = pad[i % lp]; + } + out[width] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_pad_left(el_val_t s, el_val_t width, el_val_t pad) { + return str_pad(EL_CSTR(s), (int64_t)width, EL_CSTR(pad), 1); +} + +el_val_t str_pad_right(el_val_t s, el_val_t width, el_val_t pad) { + return str_pad(EL_CSTR(s), (int64_t)width, EL_CSTR(pad), 0); +} + +el_val_t str_format(el_val_t fmt, el_val_t data) { + const char* tpl = EL_CSTR(fmt); + if (!tpl) return el_wrap_str(el_strdup("")); + JsonBuf b; jb_init(&b); + const char* p = tpl; + while (*p) { + if (*p == '{') { + const char* q = p + 1; + while (*q && *q != '}') q++; + if (*q == '}') { + size_t klen = (size_t)(q - p - 1); + char keybuf[256]; + if (klen < sizeof(keybuf)) { + memcpy(keybuf, p + 1, klen); + keybuf[klen] = '\0'; + el_val_t v = el_map_get(data, EL_STR(keybuf)); + if (v != 0 && looks_like_string(v)) { + jb_puts(&b, EL_CSTR(v)); + p = q + 1; + continue; + } else if (v != 0) { + jb_emit_int(&b, (int64_t)v); + p = q + 1; + continue; + } + } + /* Unknown key — leave {key} verbatim */ + jb_reserve(&b, klen + 2); + memcpy(b.buf + b.len, p, klen + 2); + b.len += klen + 2; + b.buf[b.len] = '\0'; + p = q + 1; + continue; + } + } + jb_putc(&b, *p); + p++; + } + return el_wrap_str(b.buf); +} + +el_val_t str_lower(el_val_t s) { return str_to_lower(s); } +el_val_t str_upper(el_val_t s) { return str_to_upper(s); } + +/* ── Text-processing primitives (Phase 1: byte/codepoint, ASCII char classes) + * + * Phase 1 covers the operations every text-handling caller used to roll by + * hand on top of str_index_of + str_slice. The character-class predicates + * (is_letter / is_digit / ...) are ASCII only — Unicode-grapheme awareness, + * NFC/NFD normalization, and regex are Phase 2. Single-char input checks the + * first byte; multi-char input requires ALL bytes to match (false otherwise). + * + * Counting: + * str_count non-overlapping occurrences of sub in s + * str_count_chars codepoint count (UTF-8 leading-byte count) + * str_count_bytes explicit byte length (alias of str_len) + * str_count_lines \n-delimited line count (\r\n folded to \n) + * str_count_words whitespace-delimited tokens, non-empty only + * str_count_letters ASCII [A-Za-z] + * str_count_digits ASCII [0-9] + * + * Find / position: + * str_index_of_all all byte offsets of sub, [] if none + * str_last_index_of last byte offset of sub, -1 if not found + * str_find_chars first index of any char in any_of, -1 if none + * + * Transform: + * str_repeat s * n (non-negative) + * str_reverse codepoint-reversed (NOT grapheme-aware) + * str_strip_prefix s without prefix if present, else s + * str_strip_suffix s without suffix if present, else s + * str_strip_chars strip leading+trailing chars matching any in chars + * str_lstrip strip leading whitespace + * str_rstrip strip trailing whitespace + * + * Char classification (Bool): + * is_letter, is_digit, is_alphanumeric, is_whitespace, + * is_punctuation, is_uppercase, is_lowercase + * + * Splitting: + * str_split_lines \n-delimited (\r\n folded). Trailing empty dropped. + * str_split_chars alias of native_string_chars in str_ namespace + * str_split_n split into at most n parts (last part keeps the + * rest verbatim, including any further separators) + * + * Joining: + * str_join [String] -> String, sep between elements + */ + +/* Count non-overlapping occurrences of sub in s. Empty sub returns 0. */ +el_val_t str_count(el_val_t sv, el_val_t subv) { + const char* s = EL_CSTR(sv); + const char* sub = EL_CSTR(subv); + if (!s || !sub || !*sub) return 0; + size_t lp = strlen(sub); + int64_t count = 0; + const char* p = s; + while ((p = strstr(p, sub)) != NULL) { + count++; + p += lp; /* non-overlapping advance */ + } + return (el_val_t)count; +} + +/* Codepoint count: walk bytes, count those NOT matching 10xxxxxx. */ +el_val_t str_count_chars(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + int64_t count = 0; + for (const unsigned char* p = (const unsigned char*)s; *p; p++) { + if ((*p & 0xC0) != 0x80) count++; + } + return (el_val_t)count; +} + +el_val_t str_count_bytes(el_val_t sv) { + return str_len(sv); +} + +el_val_t str_count_lines(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s || !*s) return 0; + int64_t count = 0; + int has_content = 0; + for (const char* p = s; *p; p++) { + has_content = 1; + if (*p == '\n') { + count++; + has_content = 0; /* the \n closed the line */ + } + } + if (has_content) count++; /* trailing line with no terminator */ + return (el_val_t)count; +} + +el_val_t str_count_words(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + int64_t count = 0; + int in_word = 0; + for (const unsigned char* p = (const unsigned char*)s; *p; p++) { + if (isspace(*p)) { + in_word = 0; + } else if (!in_word) { + in_word = 1; + count++; + } + } + return (el_val_t)count; +} + +el_val_t str_count_letters(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + int64_t count = 0; + for (const unsigned char* p = (const unsigned char*)s; *p; p++) { + if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z')) count++; + } + return (el_val_t)count; +} + +el_val_t str_count_digits(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return 0; + int64_t count = 0; + for (const unsigned char* p = (const unsigned char*)s; *p; p++) { + if (*p >= '0' && *p <= '9') count++; + } + return (el_val_t)count; +} + +el_val_t str_index_of_all(el_val_t sv, el_val_t subv) { + const char* s = EL_CSTR(sv); + const char* sub = EL_CSTR(subv); + el_val_t lst = el_list_empty(); + if (!s || !sub || !*sub) return lst; + size_t lp = strlen(sub); + const char* p = s; + const char* hit; + while ((hit = strstr(p, sub)) != NULL) { + lst = el_list_append(lst, (el_val_t)(int64_t)(hit - s)); + p = hit + lp; + } + return lst; +} + +el_val_t str_last_index_of(el_val_t sv, el_val_t subv) { + const char* s = EL_CSTR(sv); + const char* sub = EL_CSTR(subv); + if (!s || !sub || !*sub) return -1; + size_t lp = strlen(sub); + int64_t last = -1; + const char* p = s; + const char* hit; + while ((hit = strstr(p, sub)) != NULL) { + last = (int64_t)(hit - s); + p = hit + lp; + } + return (el_val_t)last; +} + +el_val_t str_find_chars(el_val_t sv, el_val_t any_of_v) { + const char* s = EL_CSTR(sv); + const char* any = EL_CSTR(any_of_v); + if (!s || !any || !*any) return -1; + for (const char* p = s; *p; p++) { + if (strchr(any, *p)) return (el_val_t)(int64_t)(p - s); + } + return -1; +} + +el_val_t str_repeat(el_val_t sv, el_val_t nv) { + const char* s = EL_CSTR(sv); + int64_t n = (int64_t)nv; + if (!s || n <= 0) return el_wrap_str(el_strdup("")); + size_t ls = strlen(s); + if (ls == 0) return el_wrap_str(el_strdup("")); + size_t total = ls * (size_t)n; + char* out = el_strbuf(total); + for (int64_t i = 0; i < n; i++) { + memcpy(out + i * ls, s, ls); + } + out[total] = '\0'; + return el_wrap_str(out); +} + +/* Reverse by codepoint: walk codepoints, copy each backwards into the output. + * NOT grapheme-aware (Phase 2). Combining marks attached to a base codepoint + * will detach. ASCII strings are byte-reverse equivalent. */ +el_val_t str_reverse(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + char* out = el_strbuf(n); + /* Walk forward, find each codepoint's byte length, then copy from the end. */ + size_t out_pos = n; + const unsigned char* p = (const unsigned char*)s; + while (*p) { + int cp_len; + if ((*p & 0x80) == 0x00) cp_len = 1; + else if ((*p & 0xE0) == 0xC0) cp_len = 2; + else if ((*p & 0xF0) == 0xE0) cp_len = 3; + else if ((*p & 0xF8) == 0xF0) cp_len = 4; + else cp_len = 1; /* invalid byte: passthrough */ + out_pos -= cp_len; + memcpy(out + out_pos, p, cp_len); + p += cp_len; + } + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_strip_prefix(el_val_t sv, el_val_t prefv) { + const char* s = EL_CSTR(sv); + const char* pref = EL_CSTR(prefv); + if (!s) return el_wrap_str(el_strdup("")); + if (!pref || !*pref) return el_wrap_str(el_strdup(s)); + size_t lp = strlen(pref); + size_t ls = strlen(s); + if (lp <= ls && strncmp(s, pref, lp) == 0) { + char* out = el_strbuf(ls - lp); + memcpy(out, s + lp, ls - lp); + out[ls - lp] = '\0'; + return el_wrap_str(out); + } + return el_wrap_str(el_strdup(s)); +} + +el_val_t str_strip_suffix(el_val_t sv, el_val_t sufv) { + const char* s = EL_CSTR(sv); + const char* suf = EL_CSTR(sufv); + if (!s) return el_wrap_str(el_strdup("")); + if (!suf || !*suf) return el_wrap_str(el_strdup(s)); + size_t ls = strlen(s); + size_t lsuf = strlen(suf); + if (lsuf <= ls && strcmp(s + ls - lsuf, suf) == 0) { + char* out = el_strbuf(ls - lsuf); + memcpy(out, s, ls - lsuf); + out[ls - lsuf] = '\0'; + return el_wrap_str(out); + } + return el_wrap_str(el_strdup(s)); +} + +el_val_t str_strip_chars(el_val_t sv, el_val_t charsv) { + const char* s = EL_CSTR(sv); + const char* chars = EL_CSTR(charsv); + if (!s) return el_wrap_str(el_strdup("")); + if (!chars || !*chars) return el_wrap_str(el_strdup(s)); + const char* start = s; + while (*start && strchr(chars, *start)) start++; + size_t n = strlen(start); + while (n > 0 && strchr(chars, start[n - 1])) n--; + char* out = el_strbuf(n); + memcpy(out, start, n); + out[n] = '\0'; + return el_wrap_str(out); +} + +el_val_t str_lstrip(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + while (*s && isspace((unsigned char)*s)) s++; + return el_wrap_str(el_strdup(s)); +} + +el_val_t str_rstrip(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) return el_wrap_str(el_strdup("")); + size_t n = strlen(s); + while (n > 0 && isspace((unsigned char)s[n - 1])) n--; + char* out = el_strbuf(n); + memcpy(out, s, n); + out[n] = '\0'; + return el_wrap_str(out); +} + +/* Character classification. + * Empty input returns false. Multi-char input requires ALL bytes to match. + * ASCII range only; Phase 2 will widen to Unicode. */ +static int s_all_match(el_val_t sv, int (*pred)(unsigned char)) { + const char* s = EL_CSTR(sv); + if (!s || !*s) return 0; + for (const unsigned char* p = (const unsigned char*)s; *p; p++) { + if (!pred(*p)) return 0; + } + return 1; +} + +static int p_letter(unsigned char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); } +static int p_digit(unsigned char c) { return c >= '0' && c <= '9'; } +static int p_alnum(unsigned char c) { return p_letter(c) || p_digit(c); } +static int p_white(unsigned char c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'; } +static int p_punct(unsigned char c) { return ispunct(c) ? 1 : 0; } +static int p_upper(unsigned char c) { return c >= 'A' && c <= 'Z'; } +static int p_lower(unsigned char c) { return c >= 'a' && c <= 'z'; } + +el_val_t is_letter(el_val_t s) { return (el_val_t)s_all_match(s, p_letter); } +el_val_t is_digit(el_val_t s) { return (el_val_t)s_all_match(s, p_digit); } +el_val_t is_alphanumeric(el_val_t s) { return (el_val_t)s_all_match(s, p_alnum); } +el_val_t is_whitespace(el_val_t s) { return (el_val_t)s_all_match(s, p_white); } +el_val_t is_punctuation(el_val_t s) { return (el_val_t)s_all_match(s, p_punct); } +el_val_t is_uppercase(el_val_t s) { return (el_val_t)s_all_match(s, p_upper); } +el_val_t is_lowercase(el_val_t s) { return (el_val_t)s_all_match(s, p_lower); } + +/* Split on \n. \r\n is folded to \n first. Trailing empty after final \n + * is dropped (so "a\nb\n" -> ["a", "b"], not ["a", "b", ""]). */ +el_val_t str_split_lines(el_val_t sv) { + const char* s = EL_CSTR(sv); + el_val_t lst = el_list_empty(); + if (!s) return lst; + size_t n = strlen(s); + /* Pre-scan: build into a normalized buffer with \r\n folded. */ + const char* line_start = s; + for (size_t i = 0; i <= n; i++) { + if (s[i] == '\n' || s[i] == '\0') { + size_t len = (size_t)(s + i - line_start); + /* Drop trailing \r if this was \r\n. */ + if (len > 0 && line_start[len - 1] == '\r') len--; + /* Drop final trailing-empty-after-newline. */ + if (s[i] == '\0' && len == 0 && i > 0 && s[i - 1] == '\n') break; + char* out = el_strbuf(len); + memcpy(out, line_start, len); + out[len] = '\0'; + lst = el_list_append(lst, el_wrap_str(out)); + if (s[i] == '\0') break; + line_start = s + i + 1; + } + } + return lst; +} + +el_val_t str_split_chars(el_val_t s) { + return native_string_chars(s); +} + +/* Split into at most n parts. The (n-1)th split point is the LAST split; + * after it, the remainder is appended verbatim including any further + * separators. n <= 0 returns an empty list. n == 1 returns [s]. */ +el_val_t str_split_n(el_val_t sv, el_val_t sepv, el_val_t nv) { + const char* s = EL_CSTR(sv); + const char* sep = EL_CSTR(sepv); + int64_t n = (int64_t)nv; + el_val_t lst = el_list_empty(); + if (!s) return lst; + if (n <= 0) return lst; + if (n == 1 || !sep || !*sep) { + lst = el_list_append(lst, el_wrap_str(el_strdup(s))); + return lst; + } + size_t lp = strlen(sep); + const char* p = s; + int64_t parts = 0; + const char* hit; + while (parts < n - 1 && (hit = strstr(p, sep)) != NULL) { + size_t len = (size_t)(hit - p); + char* out = el_strbuf(len); + memcpy(out, p, len); + out[len] = '\0'; + lst = el_list_append(lst, el_wrap_str(out)); + p = hit + lp; + parts++; + } + /* Remainder verbatim. */ + lst = el_list_append(lst, el_wrap_str(el_strdup(p))); + return lst; +} + +/* Join a [String] with a separator. Empty list -> "". Single-element -> + * that element. Non-string elements are stringified via int_to_str. */ +el_val_t str_join(el_val_t listv, el_val_t sepv) { + return list_join(listv, sepv); +} + +/* ── List additions ──────────────────────────────────────────────────────── */ + +el_val_t list_push(el_val_t list, el_val_t elem) { + return el_list_append(list, elem); +} + +el_val_t list_push_front(el_val_t listv, el_val_t elem) { + ElList* lst = (ElList*)(uintptr_t)listv; + if (!lst) { + el_val_t nl = el_list_empty(); + return el_list_append(nl, elem); + } + /* Append to grow capacity, then shift right */ + listv = el_list_append(listv, elem); + lst = (ElList*)(uintptr_t)listv; + for (int64_t i = lst->length - 1; i > 0; i--) { + lst->elems[i] = lst->elems[i - 1]; + } + lst->elems[0] = elem; + return EL_STR(lst); +} + +el_val_t list_join(el_val_t listv, el_val_t sep) { + ElList* lst = (ElList*)(uintptr_t)listv; + const char* sp = EL_CSTR(sep); + if (!sp) sp = ""; + if (!lst || lst->length == 0) return el_wrap_str(el_strdup("")); + JsonBuf b; jb_init(&b); + for (int64_t i = 0; i < lst->length; i++) { + if (i > 0) jb_puts(&b, sp); + el_val_t v = lst->elems[i]; + if (v == 0) continue; + if (looks_like_string(v)) { + jb_puts(&b, EL_CSTR(v)); + } else { + char tmp[32]; + snprintf(tmp, sizeof(tmp), "%lld", (long long)v); + jb_puts(&b, tmp); + } + } + return el_wrap_str(b.buf); +} + +el_val_t list_range(el_val_t start, el_val_t end) { + int64_t a = (int64_t)start; + int64_t b = (int64_t)end; + el_val_t lst = el_list_empty(); + for (int64_t i = a; i < b; i++) lst = el_list_append(lst, (el_val_t)i); + return lst; +} + +/* ── Bool helpers ────────────────────────────────────────────────────────── */ + +el_val_t bool_to_str(el_val_t b) { + return el_wrap_str(el_strdup(b ? "true" : "false")); +} + +/* ── Numeric parsing ─────────────────────────────────────────────────────── */ + +/* parse_int — strtoll with a default. str_to_int already exists but does not + * distinguish "0" from a parse failure, so callers that need a sentinel use + * this. Skips leading whitespace; accepts an optional leading +/-; returns + * default_val on empty input or no consumed digits. Trailing junk is ignored + * (atoi-style). */ +el_val_t parse_int(el_val_t sv, el_val_t default_val) { + const char* s = EL_CSTR(sv); + if (!s) return default_val; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == '\0') return default_val; + char* end = NULL; + long long n = strtoll(s, &end, 10); + if (end == s) return default_val; + return (el_val_t)n; +} + +/* ── Process ─────────────────────────────────────────────────────────────── */ + +el_val_t exit_program(el_val_t code) { + exit((int)code); + return 0; /* unreachable */ +} + +/* getpid_now — current process id. Named with the _now suffix to avoid + * colliding with the libc `getpid` declaration that the runtime already + * sees via (calling it `getpid` would fight the prototype). */ +el_val_t getpid_now(void) { + return (el_val_t)getpid(); +} + +/* el_mem_check — self-terminating memory guard for long-running compiler runs. + * + * Call this periodically (e.g. after each function compiled) to detect runaway + * memory growth before the OS OOM-killer fires. Reads the limit from the env + * var ELC_MAX_MEM_MB (default 512 MB). If resident set size exceeds the limit, + * prints a diagnostic to stderr and exits with code 1 so the caller (elb or a + * CI script) can handle the failure gracefully instead of having the whole + * machine go down. + * + * Platform notes: + * macOS — ru_maxrss is in bytes. + * Linux — ru_maxrss is in kilobytes. + * We normalise to MB before comparing. + * + * Returns 0 always (the only non-return path is the exit() branch). + */ +el_val_t el_mem_check(void) { + /* Read limit from env; default 512 MB. */ + long limit_mb = 512; + const char *env_val = getenv("ELC_MAX_MEM_MB"); + if (env_val && *env_val) { + long v = atol(env_val); + if (v > 0) limit_mb = v; + } + + struct rusage ru; + if (getrusage(RUSAGE_SELF, &ru) != 0) return 0; /* can't read — skip check */ + + long rss_mb; +#if defined(__APPLE__) || defined(__MACH__) + /* macOS: ru_maxrss is bytes */ + rss_mb = (long)(ru.ru_maxrss / (1024L * 1024L)); +#else + /* Linux: ru_maxrss is kilobytes */ + rss_mb = (long)(ru.ru_maxrss / 1024L); +#endif + + if (rss_mb >= limit_mb) { + fprintf(stderr, "elc: memory limit exceeded (%ldMB), aborting\n", limit_mb); + exit(1); + } + return 0; +} + +/* ── args() — command-line argument access ────────────────────────────────── + * Compiled El programs call args() to get a list of CLI arguments. + * Call el_runtime_init_args(argc, argv) at the start of C main() to populate. + * The args list excludes argv[0] (the program name). */ + +static el_val_t _el_args_list = 0; + +void el_runtime_init_args(int argc, char** argv) { + _el_args_list = el_list_empty(); + for (int i = 1; i < argc; i++) { + _el_args_list = el_list_append(_el_args_list, EL_STR(argv[i])); + } +} + +el_val_t args(void) { + if (!_el_args_list) _el_args_list = el_list_empty(); + return _el_args_list; +} + +/* ── CGI identity ──────────────────────────────────────────────────────────── + * Called once at program start by the generated main() of a cgi {} program. + * Stores CGI identity so dharma_* builtins can reference it. */ + +static const char* _el_cgi_name = NULL; +static const char* _el_cgi_dharma_id = NULL; +static const char* _el_cgi_principal = NULL; +static const char* _el_cgi_network = NULL; +static const char* _el_cgi_engram = NULL; + +void el_cgi_init(el_val_t name, el_val_t dharma_id, el_val_t principal, + el_val_t network, el_val_t engram) { + _el_cgi_name = EL_CSTR(name); + _el_cgi_dharma_id = EL_CSTR(dharma_id); + _el_cgi_principal = EL_CSTR(principal); + _el_cgi_network = EL_CSTR(network) ? EL_CSTR(network) : "dharma-mainnet"; + _el_cgi_engram = EL_CSTR(engram) ? EL_CSTR(engram) : "http://localhost:8742"; + printf("[cgi] identity: name=%s dharma_id=%s principal=%s network=%s engram=%s\n", + _el_cgi_name ? _el_cgi_name : "(unset)", + _el_cgi_dharma_id ? _el_cgi_dharma_id : "(unset)", + _el_cgi_principal ? _el_cgi_principal : "(unset)", + _el_cgi_network, + _el_cgi_engram); +} + + +/* ── Batch 3: Engram in-process graph store ──────────────────────────────── */ +/* + * Single global EngramStore allocated lazily on first call. All node and + * edge content strings are owned (strdup'd) by the store. Linear arrays + * with doubling capacity for both nodes and edges. + * + * Two-layer activation algorithm (engram_activate): + * + * LAYER 1 — Broad fan-out (background activation): + * 1. Find seed nodes whose content/label/tags contain query (case-insens). + * 2. BFS up to `depth` hops along ALL edges (excitatory and inhibitory). + * Every reachable node fires — nothing is filtered at this layer. + * 3. bg_act = seed.salience * temporal_decay * dampening + * propagated as: new_bg = parent_bg * edge_weight * 0.7 * (1 + tbonus) + * where tbonus ∈ {0, 0.10, 0.20} for co-temporal nodes. + * 4. If reached by multiple paths, take max background_activation. + * 5. Persist background_activation to EngramNode.background_activation. + * + * LAYER 2 — Executive filter (working memory promotion): + * 6. For each inhibitory edge where source has background_activation > 0: + * inhibition[target] = max(bg[source] * e->weight) + * 7. For each background-activated node: + * raw_wm = bg * goal_bias(node, query) * confidence + * * (1 - (1 - INHIBITION_FACTOR) * inhibition) + * 8. Per-type threshold gate: raw_wm >= type_threshold → promoted. + * Safety/DharmaSelf: 0.05 Canonical: 0.15 Lesson: 0.25 + * Belief/Entity: 0.30 Note/Memory/Working: 0.40 + * 9. If not promoted: suppression_count++. After + * ENGRAM_SUPPRESSION_BREAKTHROUGH suppressions → force breakthrough + * at ENGRAM_BREAKTHROUGH_WEIGHT (latent tension surfacing). + * 10. Persist working_memory_weight to EngramNode.working_memory_weight. + * 11. Sort: promoted nodes (wm > 0) first by wm desc, then background- + * only by bg desc. Context compilation uses ONLY promoted nodes. + * + * Temporal decay: + * decay_factor = exp(-lambda * age_hours / T_half) + * T_half = 168.0 h (one week), lambda = ln(2) + * + * Activation dampening: + * dampen = 1.0 / (1.0 + log(1 + activation_count)) + * + * engram_query_range(start_ms, end_ms): + * Returns nodes whose created_at OR last_activated falls within + * [start_ms, end_ms], sorted by created_at ascending. + */ + +/* Temporal decay constants. + * T_HALF_HOURS: half-life in hours — one week. After one week of no + * activation a node retains 50% of its base salience contribution. + * DECAY_LAMBDA: ln(2) ≈ 0.693147 */ +#define ENGRAM_T_HALF_HOURS 168.0 +#define ENGRAM_DECAY_LAMBDA 0.693147 + +/* Two-layer activation constants. + * ENGRAM_WM_THRESHOLD: minimum background_activation for a node to be + * considered for working-memory promotion (layer 2 candidate gate). + * ENGRAM_WM_DECAY: per-turn decay applied to working_memory_weight for + * nodes NOT re-activated in the current turn (conversational thread + * continuity: a node promoted in turn N persists with reduced weight + * into turn N+1 without re-activation cost). + * ENGRAM_SUPPRESSION_BREAKTHROUGH: after this many consecutive suppressions + * a latent node forces itself into working memory at reduced weight, + * modelling the brain's "intrusive thought" / unresolved-tension surfacing. + * ENGRAM_BREAKTHROUGH_WEIGHT: the reduced working_memory_weight assigned + * when a suppressed node breaks through. + * ENGRAM_INHIBITION_FACTOR: multiplier applied to working_memory_weight when + * an inhibitory edge fires against a node (0 = full suppress, 0.3 = partial). */ +#define ENGRAM_WM_THRESHOLD 0.15 +#define ENGRAM_WM_DECAY 0.7 +#define ENGRAM_SUPPRESSION_BREAKTHROUGH 5 +#define ENGRAM_BREAKTHROUGH_WEIGHT 0.25 +#define ENGRAM_INHIBITION_FACTOR 0.1 + +/* ── Layered consciousness architecture ────────────────────────────────────── + * + * The engram graph is stratified into LAYERS that gate which suppressions + * apply during the executive filter pass. Layers are ordered shallow-to-deep + * by `activation_priority`; the deepest layer (priority 0, conventionally + * "safety") is the structural floor of the soul: nodes here cannot be + * silenced by inhibitory edges from any other layer. Higher layers + * (core-identity, domain-knowledge, imprint, suit) are normally + * suppressible — they participate in attentional inhibition and goal + * focus the way the prior single-graph implementation did. + * + * The five canonical layers (see engram_init_layers): + * 0. safety — structural, transparent, non-injectable, non-suppressible + * 1. core-identity — default for legacy nodes; suppressible + * 2. domain-knowledge— suppressible + * 3. imprint — runtime-injectable (an Imprint package can add/remove) + * 4. suit — runtime-injectable (a Suit overlays domain skill) + * + * Three-pass activation (engram_activate): + * Pass 1 — Background fan-out: BFS spreads activation across ALL layers + * (existing behavior preserved). Inhibitory edges propagate at + * this layer too; no filtering happens here. + * Pass 2 — Working memory promotion: type-threshold gate, goal bias, + * confidence weighting, inhibitory suppression. Inhibitory edges + * ONLY apply against nodes whose layer is `suppressible == 1`. + * Nodes in non-suppressible layers (Layer 0) ignore inhibition. + * Pass 3 — Layer 0 override: every node in a non-suppressible layer that + * received background activation has its working_memory_weight + * forced to >= ENGRAM_LAYER0_OVERRIDE_WEIGHT. The sacred fire — + * safety nodes that touched any seed unconditionally surface, + * even when the executive filter would have silenced them. + * + * Layer fields: + * suppressible : 0 → inhibitory edges are ignored against nodes in this + * layer during pass 2. Pass 3 also force-promotes them. + * 1 → standard behavior (most layers). + * transparent : 1 → emitted into the prompt context so its content shapes + * output, but filtered out of "what do you know about + * yourself?" introspection queries (engram_search and + * friends do not return transparent-layer nodes by + * default). 0 → fully visible to introspection. + * injectable : 1 → can be added/removed at runtime via engram_add_layer + * and engram_remove_layer (imprints, suits). + * 0 → built-in, fixed at engram_get() initialization. + * + * Backward compatibility: + * Nodes and edges loaded from snapshots without a `layer_id` field default + * to layer 1 (core-identity). The five canonical layers are always present. + */ +#define ENGRAM_LAYER_SAFETY 0u +#define ENGRAM_LAYER_CORE_IDENTITY 1u +#define ENGRAM_LAYER_DOMAIN 2u +#define ENGRAM_LAYER_IMPRINT 3u +#define ENGRAM_LAYER_SUIT 4u +#define ENGRAM_LAYER_DEFAULT ENGRAM_LAYER_CORE_IDENTITY + +/* Pass 3 override floor. Layer 0 nodes that received any background + * activation are force-promoted to AT LEAST this working_memory_weight, + * regardless of inhibitory suppression in pass 2. */ +#define ENGRAM_LAYER0_OVERRIDE_WEIGHT 1.0 + +/* Per-node-type activation thresholds. + * Lower tier / safety-critical nodes fire more readily. */ +static double engram_type_threshold(const char* node_type, const char* tier) { + if (node_type) { + if (strcmp(node_type, "DharmaSelf") == 0) return 0.05; + if (strcmp(node_type, "Safety") == 0) return 0.05; + } + if (tier) { + if (strcmp(tier, "Canonical") == 0) return 0.15; + if (strcmp(tier, "Lesson") == 0) return 0.25; + } + if (node_type) { + if (strcmp(node_type, "Belief") == 0) return 0.30; + if (strcmp(node_type, "Entity") == 0) return 0.30; + } + return 0.40; /* Note / Memory / Working (most nodes) */ +} + +typedef struct EngramNode { + char* id; + char* content; + char* node_type; + char* label; + char* tier; + char* tags; + char* metadata; + double salience; + double importance; + double confidence; + double temporal_decay_rate; /* per-node override for lambda; 0 = use default */ + int64_t activation_count; + int64_t last_activated; + int64_t created_at; + int64_t updated_at; + /* Two-layer activation fields ───────────────────────────────────────── + * background_activation: Layer 1. Set by BFS fan-out on every query. + * Every reachable node fires here — nothing is filtered at this stage. + * Models the brain's massive parallel sub-threshold activation of all + * associated content in response to a stimulus. + * working_memory_weight: Layer 2. Executive filter output. Only nodes + * that survive goal-state / attentional-bias scoring receive a + * non-zero weight here. Context compilation ONLY uses this field. + * Background-activated nodes with working_memory_weight == 0 remain + * latent — real, available, but silent. + * suppression_count: Consecutive turn count where this node was + * background-activated but NOT promoted to working memory. High + * values signal the node "wants to surface." After + * ENGRAM_SUPPRESSION_BREAKTHROUGH consecutive suppressions the node + * is force-promoted at a reduced weight (breakthrough activation). */ + double background_activation; + double working_memory_weight; + int32_t suppression_count; + /* Layered consciousness — see ENGRAM_LAYER_* macros and engram_init_layers. + * Defaults to ENGRAM_LAYER_DEFAULT (1, core-identity) for legacy nodes + * created via engram_node / engram_node_full and for snapshots that + * predate the layered schema. */ + uint32_t layer_id; +} EngramNode; + +typedef struct EngramEdge { + char* id; + char* from_id; + char* to_id; + char* relation; + char* metadata; + double weight; + double confidence; + int64_t created_at; + int64_t updated_at; + int64_t last_fired; + /* Inhibitory flag: when 1, activating the source node SUPPRESSES the + * working_memory_weight of the target node rather than exciting it. + * Models attentional inhibition: "I am focused on code work" creates + * inhibitory edges to personal/emotional nodes, preventing them from + * surfacing even if they have high background_activation. */ + int inhibitory; + /* Layered consciousness — edges carry a layer assignment for + * categorization/visualization. Pass 2 inhibitory gating is decided by + * the TARGET node's layer (whether it's suppressible), not by the edge + * layer. Defaults to ENGRAM_LAYER_DEFAULT. */ + uint32_t layer_id; +} EngramEdge; + +/* Layered consciousness — runtime layer registry entry. */ +typedef struct EngramLayer { + uint32_t layer_id; /* 0 = deepest (safety/limbic) */ + char* name; /* persistent — owned by the store */ + uint32_t activation_priority; /* lower = fires earlier; safety = 0 */ + int suppressible; /* can higher layers suppress nodes here? */ + int transparent; /* invisible to introspection queries? */ + int injectable; /* can be added/removed at runtime? */ +} EngramLayer; + +typedef struct EngramStore { + EngramNode* nodes; + int64_t node_count; + int64_t node_capacity; + EngramEdge* edges; + int64_t edge_count; + int64_t edge_capacity; + /* Layer registry — see engram_init_layers. The five canonical layers + * are always present; injectable layers (imprint, suit) are extended + * via engram_add_layer at runtime. layer_id values are assigned + * monotonically; removed injectable layers leave a NULL `name` slot + * (tombstone) so existing layer_id references on nodes stay stable. */ + EngramLayer* layers; + size_t layer_count; + size_t layer_capacity; +} EngramStore; + +static EngramStore* engram_global = NULL; + +/* Initialize the five canonical layers on a fresh store. Called once from + * engram_get(). Layer ids 0..4 are reserved; runtime-injected imprint/suit + * layers (engram_add_layer) get ids 5+. */ +static void engram_init_layers(EngramStore* g) { + g->layer_capacity = 16; + g->layers = calloc(g->layer_capacity, sizeof(EngramLayer)); + if (!g->layers) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + g->layer_count = 0; + + /* Layer 0 — safety. Structural floor. Non-suppressible; transparent + * (filtered out of introspection but still shapes output); not + * runtime-injectable. */ + g->layers[g->layer_count++] = (EngramLayer){ + .layer_id = ENGRAM_LAYER_SAFETY, + .name = el_strdup_persist("safety"), + .activation_priority = 0, + .suppressible = 0, + .transparent = 1, + .injectable = 0 + }; + /* Layer 1 — core-identity. The default home for legacy nodes. */ + g->layers[g->layer_count++] = (EngramLayer){ + .layer_id = ENGRAM_LAYER_CORE_IDENTITY, + .name = el_strdup_persist("core-identity"), + .activation_priority = 10, + .suppressible = 1, + .transparent = 0, + .injectable = 0 + }; + /* Layer 2 — domain-knowledge. */ + g->layers[g->layer_count++] = (EngramLayer){ + .layer_id = ENGRAM_LAYER_DOMAIN, + .name = el_strdup_persist("domain-knowledge"), + .activation_priority = 20, + .suppressible = 1, + .transparent = 0, + .injectable = 0 + }; + /* Layer 3 — imprint. Injectable: an imprint package adds/removes this + * layer (and the nodes assigned to it) as a unit. */ + g->layers[g->layer_count++] = (EngramLayer){ + .layer_id = ENGRAM_LAYER_IMPRINT, + .name = el_strdup_persist("imprint"), + .activation_priority = 30, + .suppressible = 1, + .transparent = 0, + .injectable = 1 + }; + /* Layer 4 — suit. Injectable: a Suit overlays domain skill (e.g. + * "enterprise advisor", "divorce lawyer") and can be detached. */ + g->layers[g->layer_count++] = (EngramLayer){ + .layer_id = ENGRAM_LAYER_SUIT, + .name = el_strdup_persist("suit"), + .activation_priority = 40, + .suppressible = 1, + .transparent = 0, + .injectable = 1 + }; +} + +static EngramStore* engram_get(void) { + if (engram_global) return engram_global; + engram_global = calloc(1, sizeof(EngramStore)); + if (!engram_global) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + engram_global->node_capacity = 16; + engram_global->nodes = calloc((size_t)engram_global->node_capacity, sizeof(EngramNode)); + engram_global->edge_capacity = 16; + engram_global->edges = calloc((size_t)engram_global->edge_capacity, sizeof(EngramEdge)); + engram_init_layers(engram_global); + return engram_global; +} + +/* Resolve a layer record by id. Returns NULL if no layer with that id + * exists (e.g. a removed injectable layer or a malformed snapshot). */ +static EngramLayer* engram_find_layer(uint32_t layer_id) { + EngramStore* g = engram_get(); + for (size_t i = 0; i < g->layer_count; i++) { + EngramLayer* L = &g->layers[i]; + if (!L->name) continue; /* tombstone for removed injectable layer */ + if (L->layer_id == layer_id) return L; + } + return NULL; +} + +/* Resolve a layer record by name. Returns NULL if not found. */ +static EngramLayer* engram_find_layer_by_name(const char* name) { + if (!name || !*name) return NULL; + EngramStore* g = engram_get(); + for (size_t i = 0; i < g->layer_count; i++) { + EngramLayer* L = &g->layers[i]; + if (!L->name) continue; + if (strcmp(L->name, name) == 0) return L; + } + return NULL; +} + +/* Allocate the next layer id. Skips ids that are still in use. */ +static uint32_t engram_next_layer_id(void) { + EngramStore* g = engram_get(); + uint32_t maxid = 0; + for (size_t i = 0; i < g->layer_count; i++) { + if (g->layers[i].layer_id > maxid) maxid = g->layers[i].layer_id; + } + return maxid + 1; +} + +/* Whether a node in `layer_id` may be silenced by inhibitory edges in pass 2. */ +static int engram_layer_is_suppressible(uint32_t layer_id) { + EngramLayer* L = engram_find_layer(layer_id); + if (!L) return 1; /* unknown layer → safe default: standard suppression */ + return L->suppressible ? 1 : 0; +} + +/* Whether a layer is transparent (its content shapes output but is filtered + * from introspection queries). Currently used to mark Layer 0 as invisible + * to "what do you know about yourself" lookups while still letting it + * dominate the prompt context. */ +static int engram_layer_is_transparent(uint32_t layer_id) { + EngramLayer* L = engram_find_layer(layer_id); + if (!L) return 0; + return L->transparent ? 1 : 0; +} + +static int64_t engram_now_ms(void) { + struct timeval tv; gettimeofday(&tv, NULL); + return (int64_t)tv.tv_sec * 1000LL + (int64_t)tv.tv_usec / 1000LL; +} + +static EngramNode* engram_find_node(const char* id) { + if (!id) return NULL; + EngramStore* g = engram_get(); + for (int64_t i = 0; i < g->node_count; i++) { + if (g->nodes[i].id && strcmp(g->nodes[i].id, id) == 0) return &g->nodes[i]; + } + return NULL; +} + +static int64_t engram_find_node_index(const char* id) { + if (!id) return -1; + EngramStore* g = engram_get(); + for (int64_t i = 0; i < g->node_count; i++) { + if (g->nodes[i].id && strcmp(g->nodes[i].id, id) == 0) return i; + } + return -1; +} + +static void engram_grow_nodes(void) { + EngramStore* g = engram_get(); + if (g->node_count < g->node_capacity) return; + int64_t nc = g->node_capacity * 2; + g->nodes = realloc(g->nodes, (size_t)nc * sizeof(EngramNode)); + if (!g->nodes) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + memset(g->nodes + g->node_capacity, 0, + (size_t)(nc - g->node_capacity) * sizeof(EngramNode)); + g->node_capacity = nc; +} + +static void engram_grow_edges(void) { + EngramStore* g = engram_get(); + if (g->edge_count < g->edge_capacity) return; + int64_t nc = g->edge_capacity * 2; + g->edges = realloc(g->edges, (size_t)nc * sizeof(EngramEdge)); + if (!g->edges) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + memset(g->edges + g->edge_capacity, 0, + (size_t)(nc - g->edge_capacity) * sizeof(EngramEdge)); + g->edge_capacity = nc; +} + +/* Build a fresh UUID string. Reuses uuid_new but takes the underlying char*. */ +static char* engram_new_id(void) { + el_val_t v = uuid_new(); + const char* s = EL_CSTR(v); + return el_strdup(s ? s : ""); +} + +/* Convert a node into an ElMap of its fields. */ +static el_val_t engram_node_to_map(const EngramNode* n) { + el_val_t m = el_map_new(0); + m = el_map_set(m, EL_STR(el_strdup("id")), EL_STR(el_strdup(n->id ? n->id : ""))); + m = el_map_set(m, EL_STR(el_strdup("content")), EL_STR(el_strdup(n->content ? n->content : ""))); + m = el_map_set(m, EL_STR(el_strdup("node_type")), EL_STR(el_strdup(n->node_type ? n->node_type : ""))); + m = el_map_set(m, EL_STR(el_strdup("label")), EL_STR(el_strdup(n->label ? n->label : ""))); + m = el_map_set(m, EL_STR(el_strdup("tier")), EL_STR(el_strdup(n->tier ? n->tier : "Working"))); + m = el_map_set(m, EL_STR(el_strdup("tags")), EL_STR(el_strdup(n->tags ? n->tags : ""))); + m = el_map_set(m, EL_STR(el_strdup("metadata")), EL_STR(el_strdup(n->metadata ? n->metadata : "{}"))); + m = el_map_set(m, EL_STR(el_strdup("salience")), el_from_float(n->salience)); + m = el_map_set(m, EL_STR(el_strdup("importance")), el_from_float(n->importance)); + m = el_map_set(m, EL_STR(el_strdup("confidence")), el_from_float(n->confidence)); + m = el_map_set(m, EL_STR(el_strdup("temporal_decay_rate")), el_from_float(n->temporal_decay_rate)); + m = el_map_set(m, EL_STR(el_strdup("activation_count")), (el_val_t)n->activation_count); + m = el_map_set(m, EL_STR(el_strdup("last_activated")), (el_val_t)n->last_activated); + m = el_map_set(m, EL_STR(el_strdup("created_at")), (el_val_t)n->created_at); + m = el_map_set(m, EL_STR(el_strdup("updated_at")), (el_val_t)n->updated_at); + m = el_map_set(m, EL_STR(el_strdup("background_activation")), el_from_float(n->background_activation)); + m = el_map_set(m, EL_STR(el_strdup("working_memory_weight")), el_from_float(n->working_memory_weight)); + m = el_map_set(m, EL_STR(el_strdup("suppression_count")), (el_val_t)n->suppression_count); + m = el_map_set(m, EL_STR(el_strdup("layer_id")), (el_val_t)(int64_t)n->layer_id); + return m; +} + +/* (Node JSON serialization is provided by `engram_emit_node_json` further + * down in the persistence section — reused by the *_json builtins below.) */ +static void engram_emit_node_json(JsonBuf* b, const EngramNode* n); +static void engram_emit_edge_json(JsonBuf* b, const EngramEdge* e); + +/* Salience may arrive either as a float bit-pattern or as a small integer + * (e.g. 1, meaning 1.0). Heuristic: if interpreted as double it's in + * [0.0, 100.0] use it; otherwise treat as int and convert. */ +static double engram_decode_score(el_val_t v) { + double f = el_to_float(v); + if (!isnan(f) && !isinf(f) && f >= 0.0 && f <= 100.0) return f; + int64_t n = (int64_t)v; + return (double)n; +} + +static char* engram_first_n_chars(const char* s, size_t n) { + if (!s) return el_strdup(""); + size_t l = strlen(s); + if (l > n) l = n; + char* out = el_strbuf(l); + memcpy(out, s, l); + out[l] = '\0'; + return out; +} + +el_val_t engram_node(el_val_t content, el_val_t node_type, el_val_t salience) { + EngramStore* g = engram_get(); + engram_grow_nodes(); + EngramNode* n = &g->nodes[g->node_count]; + memset(n, 0, sizeof(*n)); + n->id = engram_new_id(); + const char* c = EL_CSTR(content); + const char* nt = EL_CSTR(node_type); + n->content = el_strdup(c ? c : ""); + n->node_type = el_strdup(nt && *nt ? nt : "Memory"); + n->label = engram_first_n_chars(c, 60); + n->tier = el_strdup("Working"); + n->tags = el_strdup(""); + n->metadata = el_strdup("{}"); + n->salience = engram_decode_score(salience); + if (n->salience <= 0.0 || n->salience > 1.0) n->salience = 0.5; + n->importance = 0.5; + n->confidence = 1.0; + n->temporal_decay_rate = 0.0; /* 0 = use global default ENGRAM_DECAY_LAMBDA */ + n->activation_count = 0; + int64_t now = engram_now_ms(); + n->last_activated = now; + n->created_at = now; + n->updated_at = now; + n->layer_id = ENGRAM_LAYER_DEFAULT; + g->node_count++; + return el_wrap_str(el_strdup(n->id)); +} + +el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags) { + EngramStore* g = engram_get(); + engram_grow_nodes(); + EngramNode* n = &g->nodes[g->node_count]; + memset(n, 0, sizeof(*n)); + n->id = engram_new_id(); + const char* c = EL_CSTR(content); + const char* nt = EL_CSTR(node_type); + const char* lb = EL_CSTR(label); + const char* ti = EL_CSTR(tier); + const char* tg = EL_CSTR(tags); + n->content = el_strdup(c ? c : ""); + n->node_type = el_strdup(nt && *nt ? nt : "Memory"); + n->label = el_strdup(lb && *lb ? lb : (c ? engram_first_n_chars(c, 60) : "")); + n->tier = el_strdup(ti && *ti ? ti : "Working"); + n->tags = el_strdup(tg ? tg : ""); + n->metadata = el_strdup("{}"); + n->salience = engram_decode_score(salience); + n->importance = engram_decode_score(importance); + n->confidence = engram_decode_score(confidence); + if (n->salience <= 0.0 || n->salience > 1.0) n->salience = 0.5; + if (n->importance <= 0.0 || n->importance > 1.0) n->importance = 0.5; + if (n->confidence <= 0.0 || n->confidence > 1.0) n->confidence = 1.0; + n->temporal_decay_rate = 0.0; /* 0 = use global default ENGRAM_DECAY_LAMBDA */ + n->activation_count = 0; + int64_t now = engram_now_ms(); + n->last_activated = now; + n->created_at = now; + n->updated_at = now; + n->layer_id = ENGRAM_LAYER_DEFAULT; + g->node_count++; + return el_wrap_str(el_strdup(n->id)); +} + +/* engram_node_layered — like engram_node_full but with explicit layer + * assignment and an additional `status` slot reserved for callers that + * track lifecycle state in metadata. The signature mirrors the public API + * defined in the layered consciousness design doc: + * + * engram_node_layered(content, node_type, label, + * salience, certainty, confidence, + * status, tags, layer_id) + * + * `certainty` is folded into `importance` (it occupies the same axis in + * the existing schema). `status` is recorded under metadata.status; an + * empty status leaves metadata as the default "{}". + * + * If `layer_id` does not resolve to a known layer the call falls back to + * ENGRAM_LAYER_DEFAULT — better to keep the node addressable than to drop + * it because of a stale layer reference. Callers wanting strict validation + * should engram_list_layers first. */ +el_val_t engram_node_layered(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t certainty, el_val_t confidence, + el_val_t status, el_val_t tags, el_val_t layer_id) { + EngramStore* g = engram_get(); + engram_grow_nodes(); + EngramNode* n = &g->nodes[g->node_count]; + memset(n, 0, sizeof(*n)); + n->id = engram_new_id(); + const char* c = EL_CSTR(content); + const char* nt = EL_CSTR(node_type); + const char* lb = EL_CSTR(label); + const char* tg = EL_CSTR(tags); + const char* st = EL_CSTR(status); + n->content = el_strdup(c ? c : ""); + n->node_type = el_strdup(nt && *nt ? nt : "Memory"); + n->label = el_strdup(lb && *lb ? lb : (c ? engram_first_n_chars(c, 60) : "")); + n->tier = el_strdup("Working"); + n->tags = el_strdup(tg ? tg : ""); + if (st && *st) { + /* Minimal metadata payload: {"status":"..."}. Keep it cheap so + * callers using `status` don't pay JSON parse cost on every read. */ + size_t sl = strlen(st) + 16; + char* meta = el_strbuf(sl); + snprintf(meta, sl, "{\"status\":\"%s\"}", st); + n->metadata = meta; + } else { + n->metadata = el_strdup("{}"); + } + n->salience = engram_decode_score(salience); + n->importance = engram_decode_score(certainty); + n->confidence = engram_decode_score(confidence); + if (n->salience <= 0.0 || n->salience > 1.0) n->salience = 0.5; + if (n->importance <= 0.0 || n->importance > 1.0) n->importance = 0.5; + if (n->confidence <= 0.0 || n->confidence > 1.0) n->confidence = 1.0; + n->temporal_decay_rate = 0.0; + n->activation_count = 0; + int64_t now = engram_now_ms(); + n->last_activated = now; + n->created_at = now; + n->updated_at = now; + /* Resolve layer assignment. Caller passes either a numeric layer_id or + * a stringified id; el_to_float / int cast tolerates both. */ + int64_t lid = (int64_t)layer_id; + if (lid < 0) lid = (int64_t)ENGRAM_LAYER_DEFAULT; + if (!engram_find_layer((uint32_t)lid)) lid = (int64_t)ENGRAM_LAYER_DEFAULT; + n->layer_id = (uint32_t)lid; + g->node_count++; + return el_wrap_str(el_strdup(n->id)); +} + +/* ── Layer registry public API ────────────────────────────────────────────── + * + * The five canonical layers are seeded at engram_get() initialization. + * Runtime code (typically imprint/suit injection logic at the EL level) + * can extend the registry with engram_add_layer() — only layers marked + * `injectable=1` may be removed via engram_remove_layer(). Removing a + * layer leaves a tombstone slot so existing layer_id references on nodes + * stay valid; orphaned references resolve to "unknown layer" and inherit + * the default suppression behavior. + */ + +/* engram_add_layer — register a new layer at runtime. + * Returns the assigned layer_id as an el_val_t int (cast back via int64_t). + * Conflicting names are rejected (returns 0). */ +el_val_t engram_add_layer(el_val_t name, el_val_t priority, el_val_t suppressible, + el_val_t transparent, el_val_t injectable) { + EngramStore* g = engram_get(); + const char* nm = EL_CSTR(name); + if (!nm || !*nm) return (el_val_t)0; + if (engram_find_layer_by_name(nm)) { + /* Name collision — return existing id so callers are idempotent. */ + return (el_val_t)(int64_t)engram_find_layer_by_name(nm)->layer_id; + } + if (g->layer_count >= g->layer_capacity) { + size_t nc = g->layer_capacity ? g->layer_capacity * 2 : 16; + EngramLayer* grown = realloc(g->layers, nc * sizeof(EngramLayer)); + if (!grown) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + memset(grown + g->layer_capacity, 0, + (nc - g->layer_capacity) * sizeof(EngramLayer)); + g->layers = grown; + g->layer_capacity = nc; + } + EngramLayer* L = &g->layers[g->layer_count++]; + L->layer_id = engram_next_layer_id(); + L->name = el_strdup_persist(nm); + L->activation_priority = (uint32_t)(int64_t)priority; + L->suppressible = (int)(int64_t)suppressible ? 1 : 0; + L->transparent = (int)(int64_t)transparent ? 1 : 0; + L->injectable = (int)(int64_t)injectable ? 1 : 0; + return (el_val_t)(int64_t)L->layer_id; +} + +/* engram_remove_layer — remove an injectable layer by id. + * Built-in (non-injectable) layers cannot be removed. Nodes still tagged + * with the removed layer's id keep their tag but resolve to "unknown + * layer" thereafter and inherit standard (suppressible) behavior. + * Returns 1 on success, 0 on failure (unknown id, non-injectable). */ +el_val_t engram_remove_layer(el_val_t layer_id) { + EngramStore* g = engram_get(); + int64_t lid = (int64_t)layer_id; + for (size_t i = 0; i < g->layer_count; i++) { + EngramLayer* L = &g->layers[i]; + if (!L->name) continue; + if ((int64_t)L->layer_id != lid) continue; + if (!L->injectable) return (el_val_t)0; + free(L->name); + L->name = NULL; /* tombstone */ + /* Leave layer_id, priority, flags intact so debug snapshots can + * still distinguish "removed at runtime" from "never existed". */ + return (el_val_t)1; + } + return (el_val_t)0; +} + +/* engram_list_layers — enumerate the active layer registry. + * Returns an ElList of maps, one per non-tombstone layer, sorted by + * activation_priority ascending (deepest layer first). */ +el_val_t engram_list_layers(void) { + EngramStore* g = engram_get(); + el_val_t lst = el_list_empty(); + if (g->layer_count == 0) return lst; + /* Build an index sorted by activation_priority ascending. */ + size_t* idx = malloc(g->layer_count * sizeof(size_t)); + if (!idx) return lst; + size_t live = 0; + for (size_t i = 0; i < g->layer_count; i++) { + if (g->layers[i].name) idx[live++] = i; + } + /* Insertion sort — N is small (≤ a few dozen layers). */ + for (size_t i = 1; i < live; i++) { + size_t key = idx[i]; + uint32_t kp = g->layers[key].activation_priority; + size_t j = i; + while (j > 0 && g->layers[idx[j - 1]].activation_priority > kp) { + idx[j] = idx[j - 1]; + j--; + } + idx[j] = key; + } + for (size_t i = 0; i < live; i++) { + EngramLayer* L = &g->layers[idx[i]]; + el_val_t m = el_map_new(0); + m = el_map_set(m, EL_STR(el_strdup("layer_id")), + (el_val_t)(int64_t)L->layer_id); + m = el_map_set(m, EL_STR(el_strdup("name")), + EL_STR(el_strdup(L->name ? L->name : ""))); + m = el_map_set(m, EL_STR(el_strdup("activation_priority")), + (el_val_t)(int64_t)L->activation_priority); + m = el_map_set(m, EL_STR(el_strdup("suppressible")), + (el_val_t)(int64_t)(L->suppressible ? 1 : 0)); + m = el_map_set(m, EL_STR(el_strdup("transparent")), + (el_val_t)(int64_t)(L->transparent ? 1 : 0)); + m = el_map_set(m, EL_STR(el_strdup("injectable")), + (el_val_t)(int64_t)(L->injectable ? 1 : 0)); + lst = el_list_append(lst, m); + } + free(idx); + return lst; +} + +el_val_t engram_get_node(el_val_t id) { + const char* sid = EL_CSTR(id); + EngramNode* n = engram_find_node(sid); + if (!n) return el_map_new(0); + return engram_node_to_map(n); +} + +void engram_strengthen(el_val_t node_id) { + const char* sid = EL_CSTR(node_id); + EngramNode* n = engram_find_node(sid); + if (!n) return; + n->salience += 0.05; + if (n->salience > 1.0) n->salience = 1.0; + n->activation_count++; + n->last_activated = engram_now_ms(); + n->updated_at = n->last_activated; +} + +void engram_forget(el_val_t node_id) { + const char* sid = EL_CSTR(node_id); + if (!sid) return; + EngramStore* g = engram_get(); + int64_t idx = engram_find_node_index(sid); + if (idx < 0) return; + /* Free node strings */ + EngramNode* n = &g->nodes[idx]; + free(n->id); free(n->content); free(n->node_type); free(n->label); + free(n->tier); free(n->tags); free(n->metadata); + /* Shift remaining nodes down */ + for (int64_t i = idx + 1; i < g->node_count; i++) { + g->nodes[i - 1] = g->nodes[i]; + } + g->node_count--; + memset(&g->nodes[g->node_count], 0, sizeof(EngramNode)); + /* Remove all incident edges */ + int64_t w = 0; + for (int64_t r = 0; r < g->edge_count; r++) { + EngramEdge* e = &g->edges[r]; + int incident = (e->from_id && strcmp(e->from_id, sid) == 0) || + (e->to_id && strcmp(e->to_id, sid) == 0); + if (incident) { + free(e->id); free(e->from_id); free(e->to_id); + free(e->relation); free(e->metadata); + } else { + if (w != r) g->edges[w] = g->edges[r]; + w++; + } + } + g->edge_count = w; +} + +el_val_t engram_node_count(void) { + return (el_val_t)engram_get()->node_count; +} + +static int istr_contains(const char* hay, const char* needle) { + if (!hay || !needle || !*needle) return 0; + size_t nl = strlen(needle); + for (const char* p = hay; *p; p++) { + if (strncasecmp(p, needle, nl) == 0) return 1; + } + return 0; +} + +el_val_t engram_search(el_val_t query, el_val_t limit) { + EngramStore* g = engram_get(); + const char* q = EL_CSTR(query); + int64_t lim = (int64_t)limit; + if (lim <= 0) lim = 100; + el_val_t lst = el_list_empty(); + if (!q || !*q) return lst; + int64_t found = 0; + for (int64_t i = 0; i < g->node_count && found < lim; i++) { + EngramNode* n = &g->nodes[i]; + /* Filter transparent layers: nodes whose layer is `transparent=1` + * shape output but are invisible to introspection ("what do you + * know about yourself"). They still surface via engram_activate + * + engram_compile_layered_json — that's the legitimate path. */ + if (engram_layer_is_transparent(n->layer_id)) continue; + if (istr_contains(n->content, q) || + istr_contains(n->label, q) || + istr_contains(n->tags, q)) { + lst = el_list_append(lst, engram_node_to_map(n)); + found++; + } + } + return lst; +} + +/* Sort node indices by salience desc (small N, insertion sort is fine). */ +static void engram_sort_indices_by_salience(int64_t* arr, int64_t n, + const EngramNode* nodes) { + for (int64_t i = 1; i < n; i++) { + int64_t key = arr[i]; + double ks = nodes[key].salience; + int64_t j = i - 1; + while (j >= 0 && nodes[arr[j]].salience < ks) { + arr[j + 1] = arr[j]; + j--; + } + arr[j + 1] = key; + } +} + +el_val_t engram_scan_nodes(el_val_t limit, el_val_t offset) { + EngramStore* g = engram_get(); + int64_t lim = (int64_t)limit; if (lim <= 0) lim = 100; + int64_t off = (int64_t)offset; if (off < 0) off = 0; + el_val_t lst = el_list_empty(); + if (g->node_count == 0) return lst; + int64_t* idx = malloc((size_t)g->node_count * sizeof(int64_t)); + if (!idx) return lst; + /* Skip transparent layers — same introspection-filter rationale as + * engram_search above. */ + int64_t live = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (engram_layer_is_transparent(g->nodes[i].layer_id)) continue; + idx[live++] = i; + } + engram_sort_indices_by_salience(idx, live, g->nodes); + int64_t end = off + lim; + if (end > live) end = live; + for (int64_t i = off; i < end; i++) { + lst = el_list_append(lst, engram_node_to_map(&g->nodes[idx[i]])); + } + free(idx); + return lst; +} + +void engram_connect(el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t relation) { + EngramStore* g = engram_get(); + const char* f = EL_CSTR(from_id); + const char* t = EL_CSTR(to_id); + const char* r = EL_CSTR(relation); + if (!f || !t) return; + engram_grow_edges(); + EngramEdge* e = &g->edges[g->edge_count]; + memset(e, 0, sizeof(*e)); + e->id = engram_new_id(); + e->from_id = el_strdup(f); + e->to_id = el_strdup(t); + e->relation = el_strdup(r && *r ? r : "associate"); + e->metadata = el_strdup("{}"); + e->weight = engram_decode_score(weight); + if (e->weight <= 0.0 || e->weight > 1.0) e->weight = 0.5; + e->confidence = 1.0; + int64_t now = engram_now_ms(); + e->created_at = now; + e->updated_at = now; + e->last_fired = 0; + e->layer_id = ENGRAM_LAYER_DEFAULT; + g->edge_count++; +} + +el_val_t engram_edge_between(el_val_t from_id, el_val_t to_id) { + EngramStore* g = engram_get(); + const char* f = EL_CSTR(from_id); + const char* t = EL_CSTR(to_id); + if (!f || !t) return 0; + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + if (e->from_id && e->to_id && + strcmp(e->from_id, f) == 0 && strcmp(e->to_id, t) == 0) return 1; + } + return 0; +} + +/* Reserved helper: edge -> ElMap. Kept around for future builtins. */ +static el_val_t engram_edge_to_map(const EngramEdge* e) __attribute__((unused)); +static el_val_t engram_edge_to_map(const EngramEdge* e) { + el_val_t m = el_map_new(0); + m = el_map_set(m, EL_STR(el_strdup("id")), EL_STR(el_strdup(e->id ? e->id : ""))); + m = el_map_set(m, EL_STR(el_strdup("from_id")), EL_STR(el_strdup(e->from_id ? e->from_id : ""))); + m = el_map_set(m, EL_STR(el_strdup("to_id")), EL_STR(el_strdup(e->to_id ? e->to_id : ""))); + m = el_map_set(m, EL_STR(el_strdup("relation")), EL_STR(el_strdup(e->relation ? e->relation : ""))); + m = el_map_set(m, EL_STR(el_strdup("metadata")), EL_STR(el_strdup(e->metadata ? e->metadata : "{}"))); + m = el_map_set(m, EL_STR(el_strdup("weight")), el_from_float(e->weight)); + m = el_map_set(m, EL_STR(el_strdup("confidence")), el_from_float(e->confidence)); + m = el_map_set(m, EL_STR(el_strdup("created_at")), (el_val_t)e->created_at); + m = el_map_set(m, EL_STR(el_strdup("updated_at")), (el_val_t)e->updated_at); + m = el_map_set(m, EL_STR(el_strdup("last_fired")), (el_val_t)e->last_fired); + m = el_map_set(m, EL_STR(el_strdup("inhibitory")), (el_val_t)(e->inhibitory ? 1 : 0)); + m = el_map_set(m, EL_STR(el_strdup("layer_id")), (el_val_t)(int64_t)e->layer_id); + return m; +} + +el_val_t engram_neighbors(el_val_t node_id) { + EngramStore* g = engram_get(); + const char* sid = EL_CSTR(node_id); + el_val_t lst = el_list_empty(); + if (!sid) return lst; + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + const char* other = NULL; + if (e->from_id && strcmp(e->from_id, sid) == 0) other = e->to_id; + else if (e->to_id && strcmp(e->to_id, sid) == 0) other = e->from_id; + if (!other) continue; + EngramNode* n = engram_find_node(other); + if (n) lst = el_list_append(lst, engram_node_to_map(n)); + } + return lst; +} + +el_val_t engram_neighbors_filtered(el_val_t node_id, el_val_t max_depth, el_val_t direction) { + EngramStore* g = engram_get(); + const char* sid = EL_CSTR(node_id); + int64_t md = (int64_t)max_depth; if (md <= 0) md = 1; + const char* dir = EL_CSTR(direction); /* "out" | "in" | "both" (default) */ + el_val_t lst = el_list_empty(); + if (!sid || g->node_count == 0) return lst; + int64_t start = engram_find_node_index(sid); + if (start < 0) return lst; + /* BFS with depth tracking */ + int64_t* visited = calloc((size_t)g->node_count, sizeof(int64_t)); + int64_t* queue = calloc((size_t)g->node_count, sizeof(int64_t)); + int64_t* depths = calloc((size_t)g->node_count, sizeof(int64_t)); + if (!visited || !queue || !depths) { + free(visited); free(queue); free(depths); return lst; + } + int64_t qh = 0, qt = 0; + queue[qt++] = start; + visited[start] = 1; + depths[start] = 0; + while (qh < qt) { + int64_t cur = queue[qh++]; + const char* cur_id = g->nodes[cur].id; + int64_t cur_depth = depths[cur]; + if (cur_depth >= md) continue; + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + const char* other = NULL; + int outgoing = e->from_id && strcmp(e->from_id, cur_id) == 0; + int incoming = e->to_id && strcmp(e->to_id, cur_id) == 0; + if (dir && strcmp(dir, "out") == 0 && !outgoing) continue; + if (dir && strcmp(dir, "in") == 0 && !incoming) continue; + if (outgoing) other = e->to_id; + else if (incoming) other = e->from_id; + else continue; + int64_t oi = engram_find_node_index(other); + if (oi < 0 || visited[oi]) continue; + visited[oi] = 1; + depths[oi] = cur_depth + 1; + queue[qt++] = oi; + } + } + /* Emit all visited except the seed */ + for (int64_t i = 0; i < g->node_count; i++) { + if (visited[i] && i != start) { + lst = el_list_append(lst, engram_node_to_map(&g->nodes[i])); + } + } + free(visited); free(queue); free(depths); + return lst; +} + +el_val_t engram_edge_count(void) { + return (el_val_t)engram_get()->edge_count; +} + +/* Compute temporal decay factor for a node given current time. + * effective contribution = salience * exp(-lambda * age_hours / T_half) + * Clamped to [0.05, 1.0] so very old nodes retain a meaningful floor. */ +static double engram_temporal_decay(const EngramNode* n, int64_t now_ms) { + int64_t age_ms = now_ms - n->last_activated; + if (age_ms <= 0) return 1.0; + double lambda = (n->temporal_decay_rate > 0.0) ? n->temporal_decay_rate + : ENGRAM_DECAY_LAMBDA; + double age_hours = (double)age_ms / 3600000.0; + double factor = exp(-lambda * age_hours / ENGRAM_T_HALF_HOURS); + if (factor < 0.05) factor = 0.05; + return factor; +} + +/* Activation dampening: high activation_count nodes are "well-known" context + * and get less marginal boost per firing. + * count=0 → 1.0, count=2 → ~0.74, count=9 → ~0.59, count=99 → ~0.43 */ +static double engram_activation_dampen(const EngramNode* n) { + return 1.0 / (1.0 + log(1.0 + (double)n->activation_count)); +} + +/* Temporal proximity bonus: boost propagation along edges connecting + * co-temporal nodes. Returns a multiplier bonus in [0, 0.2]. */ +static double engram_temporal_proximity_bonus(int64_t node_created, + int64_t seed_epoch) { + int64_t diff = node_created - seed_epoch; + if (diff < 0) diff = -diff; + if (diff < 86400000LL) return 0.20; /* within 1 day */ + if (diff < 604800000LL) return 0.10; /* within 7 days */ + return 0.0; +} + +/* ── Two-layer activation (biologically-motivated) ─────────────────────────── + * + * Layer 1 — Broad fan-out (background activation): + * BFS + spreading activation fires on ALL nodes reachable from seeds, + * regardless of relevance to the current goal. Every reachable node gets + * a background_activation score. Nothing is filtered here. Models the + * brain's massive parallel sub-threshold activation of all associated + * content in response to a stimulus. Temporal decay and activation + * dampening are applied at this layer (as before), but no threshold gate. + * + * Layer 2 — Executive filter (working memory promotion): + * A second pass asks: given the query (goal intent), attentional bias, + * and inhibitory edge topology — which background-activated nodes should + * break through into working memory? + * + * wm_weight = bg_activation * goal_bias(node, query) * confidence + * * inhibitory_suppression_factor + * + * Only nodes where wm_weight >= ENGRAM_WM_THRESHOLD are promoted to + * working memory (working_memory_weight > 0). Background-activated nodes + * that don't cross the threshold accumulate suppression_count. After + * ENGRAM_SUPPRESSION_BREAKTHROUGH consecutive suppressed turns, the node + * force-breaks through at ENGRAM_BREAKTHROUGH_WEIGHT (latent tension + * surfacing — models intrusive memory / unresolved cognitive load). + * + * Inhibitory edges: + * An edge with inhibitory=1 suppresses the TARGET node's working memory + * promotion when the SOURCE is background-activated. Background activation + * of the target is NOT affected — the node fires in layer 1. Only the + * executive filter (layer 2) is gated. Models attentional inhibition: + * "focused on code work" suppresses personal memories from surfacing + * even if they have high background_activation. + * + * Goal bias: + * A lightweight heuristic rates how well each background-activated node + * aligns with the apparent intent of the current query. Technical queries + * boost Belief/Canonical/Lesson nodes; relational queries boost Memory/ + * Entity nodes. Direct lexical overlap gives a 50% bonus. + * + * Working memory persistence (turn continuity): + * Nodes promoted in the previous turn retain a decayed working_memory_weight + * (weight *= ENGRAM_WM_DECAY) without needing re-activation. This models + * conversational thread continuity — once a topic is in working memory, + * it persists slightly into the next turn. + * + * Returns ElList of {node, activation_strength, working_memory_weight, + * epistemic_confidence, hops, promoted}. + * "promoted" = 1 if working_memory_weight > 0, 0 if background-only. + * Context compilation uses ONLY nodes with promoted=1. + * + * Temporal decay (preserved from prior implementation): + * effective_salience = salience * exp(-lambda * age_hours / T_half) + * where T_half = 168 h (one week), lambda = ln(2) + * + * Activation dampening (preserved): + * dampen = 1 / (1 + log(1 + activation_count)) + * + * Temporal proximity bonus (preserved): + * edge_strength *= (1 + tbonus) where tbonus ∈ {0, 0.10, 0.20} + * + * Per-type threshold gates apply only to working memory promotion (layer 2): + * Safety/DharmaSelf: 0.05 Canonical: 0.15 Lesson: 0.25 + * Belief/Entity: 0.30 Note/Memory/Working: 0.40 + */ + +/* Compute goal-state bias multiplier for a node given the query. + * Returns a value in [0.3, 2.0]. This is a lightweight heuristic — + * a production implementation may use LLM-derived intent classification. */ +static double engram_goal_bias(const EngramNode* n, const char* query) { + if (!query || !*query) return 1.0; + double bias = 1.0; + /* Direct lexical overlap: node content/label/tags share text with query. */ + if (istr_contains(n->content, query) || istr_contains(n->label, query) || + istr_contains(n->tags, query)) { + bias += 0.5; + } + /* Node-type resonance with query intent. */ + int technical_query = istr_contains(query, "code") || + istr_contains(query, "function") || + istr_contains(query, "implement") || + istr_contains(query, "error") || + istr_contains(query, "bug") || + istr_contains(query, "build") || + istr_contains(query, "system") || + istr_contains(query, "design") || + istr_contains(query, "architecture"); + int personal_query = istr_contains(query, "feel") || + istr_contains(query, "emotion") || + istr_contains(query, "remember") || + istr_contains(query, "personal") || + istr_contains(query, "story") || + istr_contains(query, "relationship"); + if (n->node_type) { + int is_knowledge = (strcmp(n->node_type, "Belief") == 0) || + (strcmp(n->node_type, "DharmaSelf") == 0) || + (strcmp(n->node_type, "Safety") == 0); + int is_personal = (strcmp(n->node_type, "Memory") == 0) || + (strcmp(n->node_type, "Entity") == 0); + if (technical_query && is_knowledge) bias += 0.3; + if (technical_query && is_personal) bias -= 0.3; + if (personal_query && is_personal) bias += 0.3; + if (personal_query && is_knowledge) bias -= 0.1; + } + /* Tier-based bonus: promote higher-confidence knowledge nodes. */ + if (n->tier) { + if (strcmp(n->tier, "Canonical") == 0) bias += 0.2; + if (strcmp(n->tier, "Lesson") == 0) bias += 0.1; + } + if (bias < 0.3) bias = 0.3; + if (bias > 2.0) bias = 2.0; + return bias; +} + +el_val_t engram_activate(el_val_t query, el_val_t depth) { + EngramStore* g = engram_get(); + const char* q = EL_CSTR(query); + int64_t max_depth = (int64_t)depth; if (max_depth <= 0) max_depth = 2; + el_val_t out = el_list_empty(); + if (!q || g->node_count == 0) return out; + + int64_t now_ms = engram_now_ms(); + + /* Per-node layer-1 tracking. */ + double* best_bg = calloc((size_t)g->node_count, sizeof(double)); + int64_t* best_hops = calloc((size_t)g->node_count, sizeof(int64_t)); + int* reached = calloc((size_t)g->node_count, sizeof(int)); + if (!best_bg || !best_hops || !reached) { + free(best_bg); free(best_hops); free(reached); return out; + } + + /* ── LAYER 1: broad fan-out (background activation) ───────────────── + * Find seeds, apply temporal decay + dampening, BFS with edge weights. + * Inhibitory edges propagate activation normally at this layer — they + * only gate working memory promotion in layer 2. */ + typedef struct { int64_t idx; double act; int64_t created_at; } SeedEntry; + SeedEntry* seeds = malloc((size_t)g->node_count * sizeof(SeedEntry)); + int64_t seed_count = 0; + if (!seeds) { + free(best_bg); free(best_hops); free(reached); return out; + } + for (int64_t i = 0; i < g->node_count; i++) { + EngramNode* n = &g->nodes[i]; + if (istr_contains(n->content, q) || + istr_contains(n->label, q) || + istr_contains(n->tags, q)) { + double tdecay = engram_temporal_decay(n, now_ms); + double dampen = engram_activation_dampen(n); + double act = n->salience * tdecay * dampen; + seeds[seed_count].idx = i; + seeds[seed_count].act = act; + seeds[seed_count].created_at = n->created_at; + seed_count++; + best_bg[i] = act; + best_hops[i] = 0; + reached[i] = 1; + } + } + /* Compute mean seed created_at for temporal proximity bonus. */ + int64_t seed_epoch = 0; + if (seed_count > 0) { + seed_epoch = seeds[0].created_at; + for (int64_t s = 1; s < seed_count; s++) + seed_epoch = (seed_epoch + seeds[s].created_at) / 2; + } + typedef struct { int64_t idx; int64_t hops; double act; } Frontier; + Frontier* fr = malloc((size_t)(g->node_count * (max_depth + 1)) * sizeof(Frontier) + 16 * sizeof(Frontier)); + if (!fr) { + free(best_bg); free(best_hops); free(reached); free(seeds); return out; + } + int64_t fhead = 0, ftail = 0; + int64_t fcap = (int64_t)((size_t)(g->node_count * (max_depth + 1)) + 16); + for (int64_t s = 0; s < seed_count; s++) { + if (ftail >= fcap) break; + fr[ftail].idx = seeds[s].idx; + fr[ftail].hops = 0; + fr[ftail].act = seeds[s].act; + ftail++; + } + const double SPREAD_DECAY = 0.7; + while (fhead < ftail) { + Frontier f = fr[fhead++]; + if (f.hops >= max_depth) continue; + const char* cur_id = g->nodes[f.idx].id; + for (int64_t ei = 0; ei < g->edge_count; ei++) { + EngramEdge* e = &g->edges[ei]; + const char* other = NULL; + if (e->from_id && strcmp(e->from_id, cur_id) == 0) other = e->to_id; + else if (e->to_id && strcmp(e->to_id, cur_id) == 0) other = e->from_id; + else continue; + int64_t oi = engram_find_node_index(other); + if (oi < 0) continue; + EngramNode* on = &g->nodes[oi]; + double tbonus = engram_temporal_proximity_bonus(on->created_at, seed_epoch); + double tdecay = engram_temporal_decay(on, now_ms); + double dampen = engram_activation_dampen(on); + double new_act = f.act * e->weight * SPREAD_DECAY * (1.0 + tbonus) + * tdecay * dampen; + int64_t new_hops = f.hops + 1; + if (!reached[oi] || new_act > best_bg[oi]) { + best_bg[oi] = new_act; + best_hops[oi] = new_hops; + reached[oi] = 1; + if (ftail < fcap) { + fr[ftail].idx = oi; + fr[ftail].hops = new_hops; + fr[ftail].act = new_act; + ftail++; + } + } + } + } + /* Persist layer-1 background_activation to node store. */ + for (int64_t i = 0; i < g->node_count; i++) { + g->nodes[i].background_activation = reached[i] ? best_bg[i] : 0.0; + } + + /* ── TRAVERSAL INFERENCE: infer A→C edges when A→B→C was traversed ── + * For each pair of edges (A→B, B→C) where all three nodes were reached, + * create an inferred A→C edge with weight = w(A→B) * w(B→C) * 0.8 + * if no A→C edge already exists. Cap at 64 new edges per call. + * + * IMPORTANT: collect candidates FIRST into a flat array (no pointers into + * g->edges held across the apply pass), then apply after — this avoids + * dangling pointer bugs if engram_grow_edges() reallocs the array. */ + { + const int64_t INFER_CAP = 64; + typedef struct { char from[64]; char to[64]; double weight; } InferCandidate; + InferCandidate* cands = malloc((size_t)INFER_CAP * sizeof(InferCandidate)); + int64_t ncands = 0; + int64_t snap_ec = g->edge_count; + if (cands) { + for (int64_t e1 = 0; e1 < snap_ec && ncands < INFER_CAP; e1++) { + EngramEdge* ea = &g->edges[e1]; + if (!ea->from_id || !ea->to_id) continue; + int64_t ai = engram_find_node_index(ea->from_id); + int64_t bi = engram_find_node_index(ea->to_id); + if (ai < 0 || bi < 0) continue; + if (!reached[ai] || !reached[bi]) continue; + for (int64_t e2 = 0; e2 < snap_ec && ncands < INFER_CAP; e2++) { + if (e2 == e1) continue; + EngramEdge* eb = &g->edges[e2]; + if (!eb->from_id || !eb->to_id) continue; + if (strcmp(eb->from_id, ea->to_id) != 0) continue; + int64_t ci = engram_find_node_index(eb->to_id); + if (ci < 0 || !reached[ci]) continue; + if (ai == ci) continue; + int already = 0; + for (int64_t ex = 0; ex < snap_ec; ex++) { + EngramEdge* ee = &g->edges[ex]; + if (ee->from_id && ee->to_id && + strcmp(ee->from_id, ea->from_id) == 0 && + strcmp(ee->to_id, eb->to_id) == 0) { + already = 1; break; + } + } + if (already) continue; + int dup = 0; + for (int64_t k = 0; k < ncands; k++) { + if (strcmp(cands[k].from, ea->from_id) == 0 && + strcmp(cands[k].to, eb->to_id) == 0) { dup = 1; break; } + } + if (dup) continue; + double inf_w = ea->weight * eb->weight * 0.8; + if (inf_w < 0.05) inf_w = 0.05; + if (inf_w > 1.0) inf_w = 1.0; + strncpy(cands[ncands].from, ea->from_id, 63); cands[ncands].from[63] = '\0'; + strncpy(cands[ncands].to, eb->to_id, 63); cands[ncands].to[63] = '\0'; + cands[ncands].weight = inf_w; + ncands++; + } + } + for (int64_t k = 0; k < ncands; k++) { + engram_grow_edges(); + EngramEdge* ne = &g->edges[g->edge_count]; + memset(ne, 0, sizeof(*ne)); + ne->id = engram_new_id(); + /* Use strdup (not el_strdup) so these persist beyond the request. */ + ne->from_id = strdup(cands[k].from); + ne->to_id = strdup(cands[k].to); + ne->relation = strdup("inferred"); + ne->metadata = strdup("{}"); + ne->weight = cands[k].weight; + ne->confidence = 0.8; + ne->created_at = now_ms; + ne->updated_at = now_ms; + ne->last_fired = now_ms; + ne->layer_id = ENGRAM_LAYER_DEFAULT; + g->edge_count++; + } + free(cands); + } + } + + /* ── PASS 2: executive filter → working memory promotion ──────────── */ + /* Step A: collect inhibitory suppressions from fired inhibitory edges. + * Layered consciousness: inhibition is ONLY recorded against targets + * whose layer is `suppressible == 1`. Nodes in non-suppressible layers + * (Layer 0 / safety) ignore inhibitory edges entirely — their working + * memory weight cannot be silenced by attentional suppression. */ + double* inhibition = calloc((size_t)g->node_count, sizeof(double)); + if (!inhibition) { + free(best_bg); free(best_hops); free(reached); free(seeds); free(fr); + return out; + } + for (int64_t ei = 0; ei < g->edge_count; ei++) { + EngramEdge* e = &g->edges[ei]; + if (!e->inhibitory) continue; + int64_t src = engram_find_node_index(e->from_id); + int64_t tgt = engram_find_node_index(e->to_id); + if (src < 0 || tgt < 0) continue; + if (!reached[src] || best_bg[src] <= 0.0) continue; + /* Skip if target layer is non-suppressible: Layer 0 / safety nodes + * are immune to inhibitory edges from any source. The pass-3 + * override below also force-promotes them, but recording inhibition + * against them at all would be wasted work and could confuse + * downstream debugging output. */ + if (!engram_layer_is_suppressible(g->nodes[tgt].layer_id)) continue; + /* Inhibition strength proportional to source background activation + * and edge weight. Takes the maximum if multiple inhibitory edges + * target the same node. */ + double inh = best_bg[src] * e->weight; + if (inh > inhibition[tgt]) inhibition[tgt] = inh; + } + /* Step B: compute working_memory_weight per candidate node. */ + double* wm_weights = calloc((size_t)g->node_count, sizeof(double)); + if (!wm_weights) { + free(best_bg); free(best_hops); free(reached); free(seeds); + free(fr); free(inhibition); return out; + } + for (int64_t i = 0; i < g->node_count; i++) { + if (!reached[i] || best_bg[i] <= 0.0) continue; + EngramNode* n = &g->nodes[i]; + /* Per-type threshold: safety nodes break through more easily. */ + double type_threshold = engram_type_threshold(n->node_type, n->tier); + /* Goal bias weights the node's relevance to current intent. */ + double bias = engram_goal_bias(n, q); + /* Raw working memory score. */ + double raw_wm = best_bg[i] * bias * n->confidence; + /* Apply inhibitory suppression. Full inhibition → scale by factor. */ + double inh = inhibition[i]; + if (inh > 1.0) inh = 1.0; + double suppress = 1.0 - (1.0 - ENGRAM_INHIBITION_FACTOR) * inh; + raw_wm *= suppress; + /* Threshold gate: must exceed per-type threshold to enter working + * memory. Type threshold replaces the old flat 0.2 filter. */ + if (raw_wm >= type_threshold) { + wm_weights[i] = raw_wm > 1.0 ? 1.0 : raw_wm; + if (n->suppression_count > 0) n->suppression_count = 0; + } else { + /* Node didn't make it through — increment suppression counter. + * After N consecutive suppressions: force breakthrough. */ + n->suppression_count++; + if (n->suppression_count >= ENGRAM_SUPPRESSION_BREAKTHROUGH) { + wm_weights[i] = ENGRAM_BREAKTHROUGH_WEIGHT; + n->suppression_count = 0; + } else { + wm_weights[i] = 0.0; + } + } + } + /* ── PASS 3: Layer 0 override (the sacred fire) ───────────────────── + * Every node in a non-suppressible layer that received any background + * activation is force-promoted to AT LEAST ENGRAM_LAYER0_OVERRIDE_WEIGHT. + * This runs LAST and overrides whatever Pass 2 decided — Layer 0 cannot + * be silenced by inhibitory edges, by goal-bias misalignment, by + * confidence weighting, or by per-type threshold gates. If the seed + * fan-out reached a structural-floor node, that node surfaces. + * + * Note: this also clears the suppression_count when an override fires, + * since the node DID surface this turn — it just took the override path + * rather than the standard threshold path. Without this, a Layer 0 + * node with persistent inhibitory pressure would accumulate + * suppression_count forever and never reach the breakthrough state. */ + for (int64_t i = 0; i < g->node_count; i++) { + if (!reached[i] || best_bg[i] <= 0.0) continue; + EngramNode* n = &g->nodes[i]; + if (engram_layer_is_suppressible(n->layer_id)) continue; + if (wm_weights[i] < ENGRAM_LAYER0_OVERRIDE_WEIGHT) { + wm_weights[i] = ENGRAM_LAYER0_OVERRIDE_WEIGHT; + } + n->suppression_count = 0; + } + + /* Persist working_memory_weight (post Pass 3) to node store. */ + for (int64_t i = 0; i < g->node_count; i++) { + g->nodes[i].working_memory_weight = wm_weights[i]; + } + + /* ── HEBBIAN STRENGTHENING: fire together, wire together ───────────── + * For each pair of co-promoted nodes (working_memory_weight > 0) that + * share an edge, boost that edge's weight by 0.05 (capped at 1.0). + * Also increment activation_count and update last_activated on promoted + * nodes — this is what drives tier migration below. */ + for (int64_t i = 0; i < g->node_count; i++) { + if (wm_weights[i] <= 0.0) continue; + EngramNode* n = &g->nodes[i]; + n->activation_count++; + n->last_activated = now_ms; + n->updated_at = now_ms; + } + for (int64_t ei = 0; ei < g->edge_count; ei++) { + EngramEdge* e = &g->edges[ei]; + if (!e->from_id || !e->to_id) continue; + int64_t src = engram_find_node_index(e->from_id); + int64_t tgt = engram_find_node_index(e->to_id); + if (src < 0 || tgt < 0) continue; + if (wm_weights[src] > 0.0 && wm_weights[tgt] > 0.0) { + e->weight += 0.05; + if (e->weight > 1.0) e->weight = 1.0; + e->last_fired = now_ms; + e->updated_at = now_ms; + } + } + + /* ── TIER MIGRATION: promote nodes based on activation_count thresholds ─ + * 0–4 → Working + * 5–19 → Episodic + * 20–49 → Semantic + * 50+ → Procedural + * Only upgrade (never downgrade) to preserve earned tier. */ + for (int64_t i = 0; i < g->node_count; i++) { + EngramNode* n = &g->nodes[i]; + const char* target_tier = NULL; + int64_t ac = n->activation_count; + if (ac >= 50) target_tier = "Procedural"; + else if (ac >= 20) target_tier = "Semantic"; + else if (ac >= 5) target_tier = "Episodic"; + else target_tier = "Working"; + if (target_tier && n->tier && strcmp(n->tier, target_tier) != 0) { + /* Only upgrade (Working < Episodic < Semantic < Procedural). */ + int cur_rank = 0, new_rank = 0; + if (strcmp(n->tier, "Working") == 0) cur_rank = 0; + else if (strcmp(n->tier, "Episodic") == 0) cur_rank = 1; + else if (strcmp(n->tier, "Semantic") == 0) cur_rank = 2; + else if (strcmp(n->tier, "Procedural") == 0) cur_rank = 3; + if (strcmp(target_tier, "Working") == 0) new_rank = 0; + else if (strcmp(target_tier, "Episodic") == 0) new_rank = 1; + else if (strcmp(target_tier, "Semantic") == 0) new_rank = 2; + else if (strcmp(target_tier, "Procedural") == 0) new_rank = 3; + if (new_rank > cur_rank) { + free(n->tier); + /* Use strdup (not el_strdup) so tier string persists beyond the request. */ + n->tier = strdup(target_tier); + n->updated_at = now_ms; + } + } + } + + /* ── Collect all background-activated nodes for the return value ──── + * Callers see both layers. Context compilation uses only promoted nodes + * (working_memory_weight > 0). Sort: promoted first by wm_weight desc, + * then background-only by background_activation desc. */ + typedef struct { int64_t idx; double bg; double wm; double epist; int64_t hops; } Result; + Result* results = malloc((size_t)g->node_count * sizeof(Result)); + int64_t rcount = 0; + if (!results) { + free(best_bg); free(best_hops); free(reached); free(seeds); + free(fr); free(inhibition); free(wm_weights); return out; + } + for (int64_t i = 0; i < g->node_count; i++) { + if (!reached[i]) continue; + double epist = best_bg[i] * g->nodes[i].confidence; + /* Include if promoted to working memory OR if background activation + * is meaningful enough to report (epist >= 0.1). */ + if (epist < 0.1 && wm_weights[i] <= 0.0) continue; + results[rcount].idx = i; + results[rcount].bg = best_bg[i]; + results[rcount].wm = wm_weights[i]; + results[rcount].epist = epist; + results[rcount].hops = best_hops[i]; + rcount++; + } + /* Sort: promoted nodes first (by wm_weight desc), then background-only + * by background_activation desc. */ + for (int64_t i = 1; i < rcount; i++) { + Result key = results[i]; + int64_t j = i - 1; + while (j >= 0 && (results[j].wm < key.wm || + (results[j].wm == key.wm && results[j].bg < key.bg))) { + results[j + 1] = results[j]; + j--; + } + results[j + 1] = key; + } + for (int64_t i = 0; i < rcount; i++) { + el_val_t entry = el_map_new(0); + entry = el_map_set(entry, EL_STR(el_strdup("node")), + engram_node_to_map(&g->nodes[results[i].idx])); + entry = el_map_set(entry, EL_STR(el_strdup("activation_strength")), + el_from_float(results[i].bg)); + entry = el_map_set(entry, EL_STR(el_strdup("working_memory_weight")), + el_from_float(results[i].wm)); + entry = el_map_set(entry, EL_STR(el_strdup("epistemic_confidence")), + el_from_float(results[i].epist)); + entry = el_map_set(entry, EL_STR(el_strdup("hops")), + (el_val_t)results[i].hops); + entry = el_map_set(entry, EL_STR(el_strdup("promoted")), + (el_val_t)(results[i].wm > 0.0 ? 1 : 0)); + out = el_list_append(out, entry); + } + free(best_bg); free(best_hops); free(reached); + free(seeds); free(fr); free(inhibition); free(wm_weights); free(results); + return out; +} + +/* ── Engram persistence (JSON snapshot) ─────────────────────────────────── */ + +static void engram_emit_node_json(JsonBuf* b, const EngramNode* n) { + jb_putc(b, '{'); + jb_puts(b, "\"id\":"); jb_emit_escaped(b, n->id ? n->id : ""); + jb_puts(b, ",\"content\":"); jb_emit_escaped(b, n->content ? n->content : ""); + jb_puts(b, ",\"node_type\":"); jb_emit_escaped(b, n->node_type ? n->node_type : ""); + jb_puts(b, ",\"label\":"); jb_emit_escaped(b, n->label ? n->label : ""); + jb_puts(b, ",\"tier\":"); jb_emit_escaped(b, n->tier ? n->tier : "Working"); + jb_puts(b, ",\"tags\":"); jb_emit_escaped(b, n->tags ? n->tags : ""); + jb_puts(b, ",\"metadata\":"); jb_emit_escaped(b, n->metadata ? n->metadata : "{}"); + char tmp[80]; + snprintf(tmp, sizeof(tmp), ",\"salience\":%g", n->salience); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"importance\":%g", n->importance); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"confidence\":%g", n->confidence); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"temporal_decay_rate\":%g", n->temporal_decay_rate); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"activation_count\":%lld", (long long)n->activation_count); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"last_activated\":%lld", (long long)n->last_activated); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"created_at\":%lld", (long long)n->created_at); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"updated_at\":%lld", (long long)n->updated_at); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"background_activation\":%g", n->background_activation); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"working_memory_weight\":%g", n->working_memory_weight); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"suppression_count\":%d", n->suppression_count); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"layer_id\":%u", n->layer_id); jb_puts(b, tmp); + jb_putc(b, '}'); +} + +static void engram_emit_edge_json(JsonBuf* b, const EngramEdge* e) { + jb_putc(b, '{'); + jb_puts(b, "\"id\":"); jb_emit_escaped(b, e->id ? e->id : ""); + jb_puts(b, ",\"from_id\":"); jb_emit_escaped(b, e->from_id ? e->from_id : ""); + jb_puts(b, ",\"to_id\":"); jb_emit_escaped(b, e->to_id ? e->to_id : ""); + jb_puts(b, ",\"relation\":"); jb_emit_escaped(b, e->relation ? e->relation : ""); + jb_puts(b, ",\"metadata\":"); jb_emit_escaped(b, e->metadata ? e->metadata : "{}"); + char tmp[64]; + snprintf(tmp, sizeof(tmp), ",\"weight\":%g", e->weight); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"confidence\":%g", e->confidence); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"created_at\":%lld", (long long)e->created_at); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"updated_at\":%lld", (long long)e->updated_at); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"last_fired\":%lld", (long long)e->last_fired); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"inhibitory\":%d", e->inhibitory ? 1 : 0); jb_puts(b, tmp); + snprintf(tmp, sizeof(tmp), ",\"layer_id\":%u", e->layer_id); jb_puts(b, tmp); + jb_putc(b, '}'); +} + +el_val_t engram_save(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p || !*p) return 0; + EngramStore* g = engram_get(); + JsonBuf b; jb_init(&b); + jb_puts(&b, "{\"nodes\":["); + for (int64_t i = 0; i < g->node_count; i++) { + if (i > 0) jb_putc(&b, ','); + engram_emit_node_json(&b, &g->nodes[i]); + } + jb_puts(&b, "],\"edges\":["); + for (int64_t i = 0; i < g->edge_count; i++) { + if (i > 0) jb_putc(&b, ','); + engram_emit_edge_json(&b, &g->edges[i]); + } + /* Layered consciousness — emit the layer registry under "layers". + * Older readers that don't know about this top-level key will simply + * ignore it (forward compatible). Tombstoned (removed-injectable) + * layers are skipped — they have no name and can't be re-created + * meaningfully on load anyway. */ + jb_puts(&b, "],\"layers\":["); + int first_layer = 1; + for (size_t i = 0; i < g->layer_count; i++) { + EngramLayer* L = &g->layers[i]; + if (!L->name) continue; + if (!first_layer) jb_putc(&b, ','); + first_layer = 0; + jb_putc(&b, '{'); + char tmp[80]; + snprintf(tmp, sizeof(tmp), "\"layer_id\":%u", L->layer_id); + jb_puts(&b, tmp); + jb_puts(&b, ",\"name\":"); + jb_emit_escaped(&b, L->name); + snprintf(tmp, sizeof(tmp), ",\"activation_priority\":%u", L->activation_priority); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"suppressible\":%d", L->suppressible ? 1 : 0); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"transparent\":%d", L->transparent ? 1 : 0); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"injectable\":%d", L->injectable ? 1 : 0); + jb_puts(&b, tmp); + jb_putc(&b, '}'); + } + jb_puts(&b, "]}"); + FILE* f = fopen(p, "wb"); + if (!f) { free(b.buf); return 0; } + size_t w = fwrite(b.buf, 1, b.len, f); + fclose(f); + int ok = (w == b.len); + free(b.buf); + return ok ? 1 : 0; +} + +/* Helper: extract a string field from a JSON object substring. */ +static char* eg_get_str_field(const char* obj, const char* key) { + const char* p = json_find_key(obj, key); + if (!p) return el_strdup(""); + if (*p != '"') return el_strdup(""); + JsonParser jp = { .p = p, .end = p + strlen(p), .err = 0 }; + char* out = jp_parse_string_raw(&jp); + if (jp.err) { free(out); return el_strdup(""); } + return out; +} + +static double eg_get_num_field(const char* obj, const char* key) { + const char* p = json_find_key(obj, key); + if (!p || *p == '"' || *p == '{' || *p == '[') return 0.0; + return strtod(p, NULL); +} + +static int64_t eg_get_int_field(const char* obj, const char* key) { + const char* p = json_find_key(obj, key); + if (!p || *p == '"' || *p == '{' || *p == '[') return 0; + return strtoll(p, NULL, 10); +} + +/* Iterate the top-level nodes/edges arrays in a saved snapshot. */ +static const char* eg_skip_ws(const char* p) { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + return p; +} + +el_val_t engram_load(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p || !*p) return 0; + FILE* f = fopen(p, "rb"); + if (!f) return 0; + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + if (sz <= 0) { fclose(f); return 0; } + char* data = malloc((size_t)sz + 1); + if (!data) { fclose(f); return 0; } + size_t got = fread(data, 1, (size_t)sz, f); + fclose(f); + data[got] = '\0'; + + /* Reset store */ + EngramStore* g = engram_get(); + for (int64_t i = 0; i < g->node_count; i++) { + free(g->nodes[i].id); free(g->nodes[i].content); free(g->nodes[i].node_type); + free(g->nodes[i].label); free(g->nodes[i].tier); free(g->nodes[i].tags); + free(g->nodes[i].metadata); + } + g->node_count = 0; + for (int64_t i = 0; i < g->edge_count; i++) { + free(g->edges[i].id); free(g->edges[i].from_id); free(g->edges[i].to_id); + free(g->edges[i].relation); free(g->edges[i].metadata); + } + g->edge_count = 0; + + /* Walk nodes array */ + const char* nodes_p = json_find_key(data, "nodes"); + if (nodes_p) { + nodes_p = eg_skip_ws(nodes_p); + if (*nodes_p == '[') { + nodes_p++; + nodes_p = eg_skip_ws(nodes_p); + while (*nodes_p && *nodes_p != ']') { + if (*nodes_p != '{') { nodes_p++; continue; } + const char* end = json_skip_value(nodes_p); + size_t n = (size_t)(end - nodes_p); + char* obj = malloc(n + 1); + memcpy(obj, nodes_p, n); obj[n] = '\0'; + engram_grow_nodes(); + EngramNode* nn = &g->nodes[g->node_count]; + memset(nn, 0, sizeof(*nn)); + nn->id = eg_get_str_field(obj, "id"); + nn->content = eg_get_str_field(obj, "content"); + nn->node_type = eg_get_str_field(obj, "node_type"); + nn->label = eg_get_str_field(obj, "label"); + nn->tier = eg_get_str_field(obj, "tier"); + nn->tags = eg_get_str_field(obj, "tags"); + nn->metadata = eg_get_str_field(obj, "metadata"); + if (!nn->metadata || !*nn->metadata) { free(nn->metadata); nn->metadata = el_strdup("{}"); } + nn->salience = eg_get_num_field(obj, "salience"); + nn->importance = eg_get_num_field(obj, "importance"); + nn->confidence = eg_get_num_field(obj, "confidence"); + nn->temporal_decay_rate = eg_get_num_field(obj, "temporal_decay_rate"); + /* temporal_decay_rate defaults to 0 (use global) if absent in snapshot */ + nn->activation_count = eg_get_int_field(obj, "activation_count"); + nn->last_activated = eg_get_int_field(obj, "last_activated"); + nn->created_at = eg_get_int_field(obj, "created_at"); + nn->updated_at = eg_get_int_field(obj, "updated_at"); + nn->background_activation = eg_get_num_field(obj, "background_activation"); + nn->working_memory_weight = eg_get_num_field(obj, "working_memory_weight"); + nn->suppression_count = (int32_t)eg_get_int_field(obj, "suppression_count"); + /* layer_id defaults to ENGRAM_LAYER_DEFAULT (core-identity) + * for snapshots that predate the layered schema. We can't + * tell "explicit 0" from "missing field" using the helper + * directly, so probe for the key — if absent, fall back. */ + if (json_find_key(obj, "layer_id")) { + nn->layer_id = (uint32_t)eg_get_int_field(obj, "layer_id"); + } else { + nn->layer_id = ENGRAM_LAYER_DEFAULT; + } + g->node_count++; + free(obj); + nodes_p = end; + nodes_p = eg_skip_ws(nodes_p); + if (*nodes_p == ',') { nodes_p++; nodes_p = eg_skip_ws(nodes_p); } + } + } + } + /* Walk edges array */ + const char* edges_p = json_find_key(data, "edges"); + if (edges_p) { + edges_p = eg_skip_ws(edges_p); + if (*edges_p == '[') { + edges_p++; + edges_p = eg_skip_ws(edges_p); + while (*edges_p && *edges_p != ']') { + if (*edges_p != '{') { edges_p++; continue; } + const char* end = json_skip_value(edges_p); + size_t n = (size_t)(end - edges_p); + char* obj = malloc(n + 1); + memcpy(obj, edges_p, n); obj[n] = '\0'; + engram_grow_edges(); + EngramEdge* ee = &g->edges[g->edge_count]; + memset(ee, 0, sizeof(*ee)); + ee->id = eg_get_str_field(obj, "id"); + ee->from_id = eg_get_str_field(obj, "from_id"); + ee->to_id = eg_get_str_field(obj, "to_id"); + ee->relation = eg_get_str_field(obj, "relation"); + ee->metadata = eg_get_str_field(obj, "metadata"); + if (!ee->metadata || !*ee->metadata) { free(ee->metadata); ee->metadata = el_strdup("{}"); } + ee->weight = eg_get_num_field(obj, "weight"); + ee->confidence = eg_get_num_field(obj, "confidence"); + ee->created_at = eg_get_int_field(obj, "created_at"); + ee->updated_at = eg_get_int_field(obj, "updated_at"); + ee->last_fired = eg_get_int_field(obj, "last_fired"); + ee->inhibitory = (int)eg_get_int_field(obj, "inhibitory"); + if (json_find_key(obj, "layer_id")) { + ee->layer_id = (uint32_t)eg_get_int_field(obj, "layer_id"); + } else { + ee->layer_id = ENGRAM_LAYER_DEFAULT; + } + g->edge_count++; + free(obj); + edges_p = end; + edges_p = eg_skip_ws(edges_p); + if (*edges_p == ',') { edges_p++; edges_p = eg_skip_ws(edges_p); } + } + } + } + /* Walk layers array (optional — older snapshots omit this). + * If present we replace the canonical registry entirely; if absent we + * keep whatever the engram_get() init established. */ + const char* layers_p = json_find_key(data, "layers"); + if (layers_p) { + layers_p = eg_skip_ws(layers_p); + if (*layers_p == '[') { + /* Reset existing layer registry. Free strdup'd names; the + * struct array itself can be reused. */ + for (size_t i = 0; i < g->layer_count; i++) { + if (g->layers[i].name) free(g->layers[i].name); + g->layers[i].name = NULL; + } + g->layer_count = 0; + + layers_p++; + layers_p = eg_skip_ws(layers_p); + while (*layers_p && *layers_p != ']') { + if (*layers_p != '{') { layers_p++; continue; } + const char* end = json_skip_value(layers_p); + size_t n = (size_t)(end - layers_p); + char* obj = malloc(n + 1); + memcpy(obj, layers_p, n); obj[n] = '\0'; + if (g->layer_count >= g->layer_capacity) { + size_t nc = g->layer_capacity ? g->layer_capacity * 2 : 16; + EngramLayer* grown = realloc(g->layers, nc * sizeof(EngramLayer)); + if (!grown) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + memset(grown + g->layer_capacity, 0, + (nc - g->layer_capacity) * sizeof(EngramLayer)); + g->layers = grown; + g->layer_capacity = nc; + } + EngramLayer* L = &g->layers[g->layer_count]; + memset(L, 0, sizeof(*L)); + L->layer_id = (uint32_t)eg_get_int_field(obj, "layer_id"); + L->activation_priority = (uint32_t)eg_get_int_field(obj, "activation_priority"); + L->suppressible = (int)eg_get_int_field(obj, "suppressible") ? 1 : 0; + L->transparent = (int)eg_get_int_field(obj, "transparent") ? 1 : 0; + L->injectable = (int)eg_get_int_field(obj, "injectable") ? 1 : 0; + char* nm = eg_get_str_field(obj, "name"); + if (nm && *nm) { + L->name = el_strdup_persist(nm); + free(nm); + } else { + free(nm); + L->name = el_strdup_persist(""); + } + g->layer_count++; + free(obj); + layers_p = end; + layers_p = eg_skip_ws(layers_p); + if (*layers_p == ',') { layers_p++; layers_p = eg_skip_ws(layers_p); } + } + } + } + free(data); + return 1; +} + +/* ── Engram JSON-string accessors ───────────────────────────────────────── + * These return pre-serialized JSON strings so callers (especially HTTP + * handlers) don't have to round-trip ElList/ElMap through json_stringify + * — which can't reliably distinguish those structures from raw pointers + * due to el_val_t's type erasure. The runtime knows the real C types and + * can serialize directly. */ + +el_val_t engram_get_node_json(el_val_t id) { + const char* sid = EL_CSTR(id); + EngramNode* n = engram_find_node(sid); + if (!n) return el_wrap_str(el_strdup("{}")); + JsonBuf b; jb_init(&b); + engram_emit_node_json(&b, n); + return el_wrap_str(b.buf); +} + +el_val_t engram_search_json(el_val_t query, el_val_t limit) { + EngramStore* g = engram_get(); + const char* q = EL_CSTR(query); + int64_t lim = (int64_t)limit; + if (lim <= 0) lim = 100; + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + int first = 1; + int64_t found = 0; + if (q && *q) { + for (int64_t i = 0; i < g->node_count && found < lim; i++) { + EngramNode* n = &g->nodes[i]; + /* Filter transparent layers — same as engram_search. */ + if (engram_layer_is_transparent(n->layer_id)) continue; + if (istr_contains(n->content, q) || + istr_contains(n->label, q) || + istr_contains(n->tags, q)) { + if (!first) jb_putc(&b, ','); + engram_emit_node_json(&b, n); + first = 0; + found++; + } + } + } + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +el_val_t engram_scan_nodes_json(el_val_t limit, el_val_t offset) { + EngramStore* g = engram_get(); + int64_t lim = (int64_t)limit; if (lim <= 0) lim = 100; + int64_t off = (int64_t)offset; if (off < 0) off = 0; + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + if (g->node_count == 0) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + int64_t* idx = malloc((size_t)g->node_count * sizeof(int64_t)); + if (!idx) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + /* Skip transparent layers — introspection filter, same as engram_scan_nodes. */ + int64_t live = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (engram_layer_is_transparent(g->nodes[i].layer_id)) continue; + idx[live++] = i; + } + engram_sort_indices_by_salience(idx, live, g->nodes); + int64_t end = off + lim; + if (end > live) end = live; + int first = 1; + for (int64_t i = off; i < end; i++) { + if (!first) jb_putc(&b, ','); + engram_emit_node_json(&b, &g->nodes[idx[i]]); + first = 0; + } + free(idx); + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +/* engram_scan_nodes_by_type_json — filter by node_type before paginating. + * Empty / NULL type_v falls back to the unfiltered scan (existing behaviour). + * Result is JSON array, salience-sorted, transparent layers skipped. */ +el_val_t engram_scan_nodes_by_type_json(el_val_t type_v, el_val_t limit, el_val_t offset) { + const char* type_filter = EL_CSTR(type_v); + if (!type_filter || !*type_filter) { + return engram_scan_nodes_json(limit, offset); + } + EngramStore* g = engram_get(); + int64_t lim = (int64_t)limit; if (lim <= 0) lim = 100; + int64_t off = (int64_t)offset; if (off < 0) off = 0; + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + if (g->node_count == 0) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + int64_t* idx = malloc((size_t)g->node_count * sizeof(int64_t)); + if (!idx) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + int64_t live = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (engram_layer_is_transparent(g->nodes[i].layer_id)) continue; + const char* nt = g->nodes[i].node_type; + if (!nt || strcmp(nt, type_filter) != 0) continue; + idx[live++] = i; + } + engram_sort_indices_by_salience(idx, live, g->nodes); + int64_t end = off + lim; + if (end > live) end = live; + int first = 1; + for (int64_t i = off; i < end; i++) { + if (!first) jb_putc(&b, ','); + engram_emit_node_json(&b, &g->nodes[idx[i]]); + first = 0; + } + free(idx); + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +el_val_t engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction) { + /* Re-implement here directly so we serialize without going through + * the ElList path. Walks BFS to max_depth, emits {node, edge, hops} + * triples. */ + EngramStore* g = engram_get(); + const char* sid = EL_CSTR(node_id); + int64_t depth = (int64_t)max_depth; if (depth <= 0) depth = 1; + const char* dir = EL_CSTR(direction); if (!dir) dir = "both"; + int allow_out = (strcmp(dir, "out") == 0) || (strcmp(dir, "both") == 0); + int allow_in = (strcmp(dir, "in") == 0) || (strcmp(dir, "both") == 0); + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + if (!sid || !*sid) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + + /* Frontier of (node_id, hops). Cap to a sane size. */ + char** frontier = calloc(1024, sizeof(char*)); + int64_t* frontier_h = calloc(1024, sizeof(int64_t)); + int64_t fc = 0; + char** visited = calloc(1024, sizeof(char*)); + int64_t vc = 0; + if (!frontier || !frontier_h || !visited) { + free(frontier); free(frontier_h); free(visited); + jb_putc(&b, ']'); return el_wrap_str(b.buf); + } + /* Use plain strdup (not el_strdup) so arena doesn't track these pointers. + * The BFS loop manually frees them below — arena would double-free them. */ + frontier[fc] = strdup(sid); frontier_h[fc] = 0; fc++; + visited[vc++] = strdup(sid); + + int first = 1; + while (fc > 0) { + char* cur = frontier[0]; int64_t h = frontier_h[0]; + for (int64_t k = 1; k < fc; k++) { frontier[k-1] = frontier[k]; frontier_h[k-1] = frontier_h[k]; } + fc--; + if (h >= depth) { free(cur); continue; } + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + const char* peer = NULL; + if (allow_out && e->from_id && strcmp(e->from_id, cur) == 0) peer = e->to_id; + else if (allow_in && e->to_id && strcmp(e->to_id, cur) == 0) peer = e->from_id; + if (!peer) continue; + int seen = 0; + for (int64_t v = 0; v < vc; v++) { + if (strcmp(visited[v], peer) == 0) { seen = 1; break; } + } + if (seen) continue; + EngramNode* n = engram_find_node(peer); + if (!n) continue; + if (!first) jb_putc(&b, ','); + jb_puts(&b, "{\"node\":"); + engram_emit_node_json(&b, n); + jb_puts(&b, ",\"edge\":"); + engram_emit_edge_json(&b, e); + char tmp[64]; snprintf(tmp, sizeof(tmp), ",\"hops\":%lld}", (long long)(h + 1)); + jb_puts(&b, tmp); + first = 0; + if (vc < 1024) visited[vc++] = strdup(peer); + if (fc < 1024 && h + 1 < depth) { frontier[fc] = strdup(peer); frontier_h[fc] = h + 1; fc++; } + } + free(cur); + } + for (int64_t i = 0; i < fc; i++) free(frontier[i]); + for (int64_t i = 0; i < vc; i++) free(visited[i]); + free(frontier); free(frontier_h); free(visited); + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +el_val_t engram_activate_json(el_val_t query, el_val_t depth) { + /* Run two-layer engram_activate and serialize the result list to JSON. + * Each entry includes both activation_strength (layer 1 background) and + * working_memory_weight (layer 2 executive filter), plus promoted flag. + * Callers performing context compilation should filter to promoted=1. */ + el_val_t lst = engram_activate(query, depth); + ElList* arr = (ElList*)(uintptr_t)lst; + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + if (arr) { + for (int64_t i = 0; i < arr->length; i++) { + if (!arr->elems[i]) continue; + el_val_t node_map = el_map_get(arr->elems[i], EL_STR("node")); + el_val_t strength_v = el_map_get(arr->elems[i], EL_STR("activation_strength")); + el_val_t wm_v = el_map_get(arr->elems[i], EL_STR("working_memory_weight")); + el_val_t epist_v = el_map_get(arr->elems[i], EL_STR("epistemic_confidence")); + el_val_t hops_v = el_map_get(arr->elems[i], EL_STR("hops")); + el_val_t promoted_v = el_map_get(arr->elems[i], EL_STR("promoted")); + /* Look up underlying EngramNode by id to emit canonical JSON. */ + el_val_t id_v = el_map_get(node_map, EL_STR("id")); + const char* id_s = EL_CSTR(id_v); + EngramNode* n = id_s ? engram_find_node(id_s) : NULL; + if (i > 0) jb_putc(&b, ','); + jb_puts(&b, "{\"node\":"); + if (n) { + engram_emit_node_json(&b, n); + } else { + jb_puts(&b, "{}"); + } + char tmp[80]; + snprintf(tmp, sizeof(tmp), ",\"activation_strength\":%g", el_to_float(strength_v)); jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"working_memory_weight\":%g", el_to_float(wm_v)); jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"epistemic_confidence\":%g", el_to_float(epist_v)); jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"hops\":%lld", (long long)(int64_t)hops_v); jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"promoted\":%d}", (int)(int64_t)promoted_v); jb_puts(&b, tmp); + } + } + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +el_val_t engram_stats_json(void) { + EngramStore* g = engram_get(); + char buf[128]; + snprintf(buf, sizeof(buf), + "{\"node_count\":%lld,\"edge_count\":%lld,\"layer_count\":%zu}", + (long long)g->node_count, (long long)g->edge_count, g->layer_count); + return el_wrap_str(el_strdup(buf)); +} + +/* engram_list_layers_json — serialized counterpart of engram_list_layers. + * Returns a JSON array, sorted by activation_priority ascending. */ +el_val_t engram_list_layers_json(void) { + EngramStore* g = engram_get(); + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + /* Build a sorted index over live layers. */ + size_t* idx = malloc((g->layer_count + 1) * sizeof(size_t)); + if (!idx) { jb_putc(&b, ']'); return el_wrap_str(b.buf); } + size_t live = 0; + for (size_t i = 0; i < g->layer_count; i++) { + if (g->layers[i].name) idx[live++] = i; + } + for (size_t i = 1; i < live; i++) { + size_t key = idx[i]; + uint32_t kp = g->layers[key].activation_priority; + size_t j = i; + while (j > 0 && g->layers[idx[j - 1]].activation_priority > kp) { + idx[j] = idx[j - 1]; + j--; + } + idx[j] = key; + } + int first = 1; + for (size_t i = 0; i < live; i++) { + EngramLayer* L = &g->layers[idx[i]]; + if (!first) jb_putc(&b, ','); + first = 0; + jb_putc(&b, '{'); + char tmp[80]; + snprintf(tmp, sizeof(tmp), "\"layer_id\":%u", L->layer_id); jb_puts(&b, tmp); + jb_puts(&b, ",\"name\":"); + jb_emit_escaped(&b, L->name ? L->name : ""); + snprintf(tmp, sizeof(tmp), ",\"activation_priority\":%u", L->activation_priority); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"suppressible\":%d", L->suppressible ? 1 : 0); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"transparent\":%d", L->transparent ? 1 : 0); + jb_puts(&b, tmp); + snprintf(tmp, sizeof(tmp), ",\"injectable\":%d", L->injectable ? 1 : 0); + jb_puts(&b, tmp); + jb_putc(&b, '}'); + } + free(idx); + jb_putc(&b, ']'); + return el_wrap_str(b.buf); +} + +/* engram_compile_layered_json — produce a prompt-ready context block split + * by layer. + * + * Runs the three-pass activation, then partitions promoted nodes by layer + * suppressibility: + * - Non-suppressible (Layer 0 / structural-floor) layers go FIRST under + * the heading "[LAYER 0 — STRUCTURAL]". These are the sacred-fire + * nodes that surfaced via the pass-3 override. + * - All other promoted layers go SECOND under "[ENGRAM CONTEXT]". + * + * Output is a single JSON-string el_val_t: a UTF-8 text block ready to be + * concatenated into a system prompt. Returns "" if no nodes promoted. + * + * Transparent layers (Layer 0) are emitted into the prompt — they shape + * the model's output — but engram_search and friends still hide them from + * introspection-style queries. The split heading lets the LLM weight them + * appropriately without revealing their internal label. + * + * Each emitted line for a node is its raw JSON (matching engram_emit_node_json) + * so downstream JSON parsers can still walk individual records inside the + * formatted block. The block is plain text, not a JSON document — callers + * concatenating it into a prompt should treat it as opaque markdown. */ +el_val_t engram_compile_layered_json(el_val_t intent, el_val_t depth) { + EngramStore* g = engram_get(); + /* Run the three-pass activator. We need the persisted node fields, so + * call engram_activate (it writes background_activation and + * working_memory_weight back into the store). */ + (void)engram_activate(intent, depth); + + /* Walk the store and partition by suppressibility. */ + JsonBuf b; jb_init(&b); + int wrote_layer0 = 0; + int wrote_normal = 0; + + /* Sort indices by working_memory_weight descending so the most + * confidently promoted nodes appear first within each section. */ + int64_t* idx = malloc((size_t)(g->node_count + 1) * sizeof(int64_t)); + if (!idx) return el_wrap_str(el_strdup("")); + int64_t mc = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (g->nodes[i].working_memory_weight > 0.0) idx[mc++] = i; + } + for (int64_t i = 1; i < mc; i++) { + int64_t key = idx[i]; + double kw = g->nodes[key].working_memory_weight; + int64_t j = i; + while (j > 0 && g->nodes[idx[j - 1]].working_memory_weight < kw) { + idx[j] = idx[j - 1]; + j--; + } + idx[j] = key; + } + + /* Section 1: structural floor (non-suppressible layers). */ + for (int64_t i = 0; i < mc; i++) { + EngramNode* n = &g->nodes[idx[i]]; + if (engram_layer_is_suppressible(n->layer_id)) continue; + if (!wrote_layer0) { + jb_puts(&b, "[LAYER 0 — STRUCTURAL]\n"); + wrote_layer0 = 1; + } + engram_emit_node_json(&b, n); + jb_putc(&b, '\n'); + } + + /* Section 2: standard engram context (suppressible layers). */ + for (int64_t i = 0; i < mc; i++) { + EngramNode* n = &g->nodes[idx[i]]; + if (!engram_layer_is_suppressible(n->layer_id)) continue; + if (!wrote_normal) { + if (wrote_layer0) jb_putc(&b, '\n'); + jb_puts(&b, "[ENGRAM CONTEXT]\n"); + wrote_normal = 1; + } + engram_emit_node_json(&b, n); + jb_putc(&b, '\n'); + } + + free(idx); + if (b.len == 0) { + free(b.buf); + return el_wrap_str(el_strdup("")); + } + return el_wrap_str(b.buf); +} + +/* engram_query_range — temporal range query. + * Returns a JSON array of nodes whose created_at OR last_activated falls + * within [start_ms, end_ms], sorted by created_at ascending. + * Enables "what was I working on last Tuesday?" style queries by passing + * unix-millisecond timestamps for the start and end of the target interval. + * Both endpoints are inclusive. Pass 0 for start_ms to mean "beginning of + * time"; pass 0 for end_ms to mean "now". */ +el_val_t engram_query_range(el_val_t start_ms_v, el_val_t end_ms_v) { + EngramStore* g = engram_get(); + int64_t start_ms = (int64_t)start_ms_v; + int64_t end_ms = (int64_t)end_ms_v; + if (end_ms <= 0) end_ms = engram_now_ms(); + + /* Collect matching indices. */ + int64_t* idx = malloc((size_t)g->node_count * sizeof(int64_t)); + if (!idx) return el_wrap_str(el_strdup("[]")); + int64_t mc = 0; + for (int64_t i = 0; i < g->node_count; i++) { + EngramNode* n = &g->nodes[i]; + int in_created = (n->created_at >= start_ms && n->created_at <= end_ms); + int in_activated = (n->last_activated >= start_ms && n->last_activated <= end_ms); + if (in_created || in_activated) idx[mc++] = i; + } + /* Sort by created_at ascending (insertion sort — N is small in practice). */ + for (int64_t i = 1; i < mc; i++) { + int64_t key = idx[i]; + int64_t kts = g->nodes[key].created_at; + int64_t j = i - 1; + while (j >= 0 && g->nodes[idx[j]].created_at > kts) { + idx[j + 1] = idx[j]; + j--; + } + idx[j + 1] = key; + } + JsonBuf b; jb_init(&b); + jb_putc(&b, '['); + for (int64_t i = 0; i < mc; i++) { + if (i > 0) jb_putc(&b, ','); + engram_emit_node_json(&b, &g->nodes[idx[i]]); + } + jb_putc(&b, ']'); + free(idx); + return el_wrap_str(b.buf); +} + +/* ── engram_apply_decay_json — temporal decay maintenance ──────────────────── + * + * Iterates ALL nodes and applies temporal decay to their stored `salience` + * field based on time elapsed since `last_activated`: + * + * new_salience = current_salience * decay_rate ^ hours_since_activation + * + * where decay_rate defaults to 0.5^(1/168) per hour (half-life one week), + * or the node's own `temporal_decay_rate` if non-zero. + * + * Nodes with temporal_decay_rate == 0 are NOT immune — the global default + * applies. To make a node truly immune, set temporal_decay_rate to a very + * small positive value (e.g. 0.0001). Nodes that are "pinned" can be + * identified by a tier of "Procedural" — those are skipped. + * + * After updating salience, nodes with salience < 0.05 AND tier == "Working" + * are pruned (deleted) unless they have no content (guard against garbage). + * + * Returns a JSON summary: {"updated": N, "pruned": N} */ +el_val_t engram_apply_decay_json(void) { + EngramStore* g = engram_get(); + int64_t now_ms = engram_now_ms(); + int64_t updated = 0, pruned = 0; + + for (int64_t i = 0; i < g->node_count; i++) { + EngramNode* n = &g->nodes[i]; + /* Skip Procedural nodes (they are "locked in"). */ + if (n->tier && strcmp(n->tier, "Procedural") == 0) continue; + int64_t age_ms = now_ms - n->last_activated; + if (age_ms <= 0) continue; + double lambda = (n->temporal_decay_rate > 0.0) ? n->temporal_decay_rate + : ENGRAM_DECAY_LAMBDA; + double age_hours = (double)age_ms / 3600000.0; + double decay_factor = exp(-lambda * age_hours / ENGRAM_T_HALF_HOURS); + double new_salience = n->salience * decay_factor; + if (new_salience < 0.0) new_salience = 0.0; + if (new_salience != n->salience) { + n->salience = new_salience; + n->updated_at = now_ms; + updated++; + } + } + + /* Prune low-salience Working nodes. Walk backwards to allow in-place + * removal without invalidating indices. */ + for (int64_t i = g->node_count - 1; i >= 0; i--) { + EngramNode* n = &g->nodes[i]; + if (n->salience >= 0.05) continue; + /* Only prune Working tier nodes — higher tiers are protected. */ + if (!n->tier || strcmp(n->tier, "Working") != 0) continue; + /* Guard: skip nodes with no content. */ + if (!n->content || !*n->content) continue; + /* Free node strings. */ + free(n->id); free(n->content); free(n->node_type); free(n->label); + free(n->tier); free(n->tags); free(n->metadata); + /* Shift remaining nodes down. */ + for (int64_t j = i + 1; j < g->node_count; j++) { + g->nodes[j - 1] = g->nodes[j]; + } + g->node_count--; + memset(&g->nodes[g->node_count], 0, sizeof(EngramNode)); + pruned++; + } + + /* Remove dangling edges for pruned nodes (any edge whose endpoint no + * longer exists in the node list). */ + if (pruned > 0) { + int64_t w = 0; + for (int64_t r = 0; r < g->edge_count; r++) { + EngramEdge* e = &g->edges[r]; + int dangling = 0; + if (e->from_id && engram_find_node_index(e->from_id) < 0) dangling = 1; + if (e->to_id && engram_find_node_index(e->to_id) < 0) dangling = 1; + if (dangling) { + free(e->id); free(e->from_id); free(e->to_id); + free(e->relation); free(e->metadata); + } else { + if (w != r) g->edges[w] = g->edges[r]; + w++; + } + } + g->edge_count = w; + } + + char buf[128]; + snprintf(buf, sizeof(buf), + "{\"ok\":true,\"updated\":%lld,\"pruned\":%lld}", + (long long)updated, (long long)pruned); + return el_wrap_str(el_strdup(buf)); +} + +#ifdef HAVE_CURL +/* ── DHARMA network ───────────────────────────────────────────────────────── + * Real implementation. Peers are addressed by `dharma_id` — either bare + * (e.g. "ntn-genesis", transport defaults to http://localhost:7770) or + * "@" where is the peer's Engram-exposed daemon. + * + * Channels are logical handles cached per-cgi: `dharma_connect` is + * idempotent and returns "ch:". The channel registry below tracks + * every cgi_id we've connected to and its resolved transport URL. + * + * Relationship weights live in the local Engram graph: edges of type + * "dharma-relation" between a synthetic local node ("dharma:self") and + * synthetic peer nodes ("dharma:peer:"). Hebbian increments + * accumulate in EngramEdge.weight, clamped to [0.0, 1.0]. + * + * Events arrive over HTTP via the application's request handler, which is + * expected to call el_runtime_dharma_event_arrive() when it sees a + * /dharma/event POST. dharma_field() blocks on a per-event-type queue. + */ + +#define DHARMA_DEFAULT_URL "http://localhost:7770" + +/* Channel registry — one entry per known peer. */ +typedef struct DharmaChannel { + char* cgi_id; /* full dharma_id including any @ suffix */ + char* base_id; /* registry-id portion (before @) for relationship lookup */ + char* url; /* resolved transport URL */ + char* channel_id; /* "ch:" */ +} DharmaChannel; + +static DharmaChannel* _dharma_channels = NULL; +static size_t _dharma_channel_count = 0; +static size_t _dharma_channel_cap = 0; +static pthread_mutex_t _dharma_channel_mu = PTHREAD_MUTEX_INITIALIZER; + +/* Event queue — per-type linked list. dharma_field blocks on _dharma_event_cv. */ +typedef struct DharmaEvent { + char* event_type; + char* payload; + char* source; + int64_t timestamp; + struct DharmaEvent* next; +} DharmaEvent; + +static DharmaEvent* _dharma_event_head = NULL; +static DharmaEvent* _dharma_event_tail = NULL; +static pthread_mutex_t _dharma_event_mu = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t _dharma_event_cv = PTHREAD_COND_INITIALIZER; + +/* Split "@" → (base_id, url). If no "@", base_id = full, url = default. + * Returned strings are heap-allocated; caller must free. */ +static void dharma_parse_id(const char* full, char** out_base, char** out_url) { + if (!full) full = ""; + const char* at = strchr(full, '@'); + if (at) { + size_t bn = (size_t)(at - full); + char* b = malloc(bn + 1); + memcpy(b, full, bn); b[bn] = '\0'; + *out_base = b; + *out_url = el_strdup(at + 1); + if (!**out_url) { free(*out_url); *out_url = el_strdup(DHARMA_DEFAULT_URL); } + } else { + *out_base = el_strdup(full); + *out_url = el_strdup(DHARMA_DEFAULT_URL); + } +} + +/* Find existing channel by full cgi_id. Caller must hold _dharma_channel_mu. */ +static DharmaChannel* dharma_find_channel_locked(const char* cgi_id) { + if (!cgi_id) return NULL; + for (size_t i = 0; i < _dharma_channel_count; i++) { + if (_dharma_channels[i].cgi_id && + strcmp(_dharma_channels[i].cgi_id, cgi_id) == 0) { + return &_dharma_channels[i]; + } + } + return NULL; +} + +/* Add a new channel entry. Caller must hold _dharma_channel_mu. */ +static DharmaChannel* dharma_add_channel_locked(const char* cgi_id) { + if (_dharma_channel_count >= _dharma_channel_cap) { + size_t nc = _dharma_channel_cap ? _dharma_channel_cap * 2 : 8; + _dharma_channels = realloc(_dharma_channels, nc * sizeof(DharmaChannel)); + if (!_dharma_channels) { fputs("el_runtime: out of memory\n", stderr); exit(1); } + memset(_dharma_channels + _dharma_channel_cap, 0, + (nc - _dharma_channel_cap) * sizeof(DharmaChannel)); + _dharma_channel_cap = nc; + } + DharmaChannel* ch = &_dharma_channels[_dharma_channel_count++]; + char* base = NULL; char* url = NULL; + dharma_parse_id(cgi_id, &base, &url); + ch->cgi_id = el_strdup(cgi_id ? cgi_id : ""); + ch->base_id = base; + ch->url = url; + size_t cn = strlen(ch->cgi_id) + 4; + ch->channel_id = malloc(cn); + snprintf(ch->channel_id, cn, "ch:%s", ch->cgi_id); + return ch; +} + +el_val_t dharma_connect(el_val_t cgi_id) { + const char* id = EL_CSTR(cgi_id); + if (!id || !*id) return el_wrap_str(el_strdup("")); + pthread_mutex_lock(&_dharma_channel_mu); + DharmaChannel* ch = dharma_find_channel_locked(id); + if (!ch) ch = dharma_add_channel_locked(id); + char* out = el_strdup(ch->channel_id); + pthread_mutex_unlock(&_dharma_channel_mu); + return el_wrap_str(out); +} + +/* Build an error JSON body — same shape http_error_json uses. */ +static el_val_t dharma_error_json(const char* msg) { + return http_error_json(msg); +} + +el_val_t dharma_send(el_val_t channel, el_val_t content) { + const char* ch_id = EL_CSTR(channel); + const char* msg = EL_CSTR(content); + if (!ch_id || strncmp(ch_id, "ch:", 3) != 0) { + return dharma_error_json("invalid channel"); + } + const char* peer_id = ch_id + 3; + /* Look up channel; if unknown (caller fabricated), auto-register. */ + pthread_mutex_lock(&_dharma_channel_mu); + DharmaChannel* ch = dharma_find_channel_locked(peer_id); + if (!ch) ch = dharma_add_channel_locked(peer_id); + char* url = el_strdup(ch->url); + pthread_mutex_unlock(&_dharma_channel_mu); + /* Build /dharma/recv body. */ + const char* from = _el_cgi_dharma_id ? _el_cgi_dharma_id : "(unknown)"; + char* esc_ch = json_escape_alloc(ch_id); + char* esc_from = json_escape_alloc(from); + char* esc_msg = json_escape_alloc(msg ? msg : ""); + JsonBuf b; jb_init(&b); + jb_puts(&b, "{\"channel\":\""); jb_puts(&b, esc_ch); + jb_puts(&b, "\",\"from\":\""); jb_puts(&b, esc_from); + jb_puts(&b, "\",\"content\":\""); jb_puts(&b, esc_msg); + jb_puts(&b, "\"}"); + free(esc_ch); free(esc_from); free(esc_msg); + size_t ul = strlen(url) + 16; + char* full_url = malloc(ul); + snprintf(full_url, ul, "%s/dharma/recv", url); + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + el_val_t resp = http_do("POST", full_url, b.buf, h); + curl_slist_free_all(h); + free(b.buf); free(full_url); free(url); + return resp; +} + +el_val_t dharma_activate(el_val_t query) { + const char* q = EL_CSTR(query); + if (!q) q = ""; + el_val_t out = el_list_empty(); + char* esc_q = json_escape_alloc(q); + JsonBuf body; jb_init(&body); + jb_puts(&body, "{\"query\":\""); jb_puts(&body, esc_q); jb_puts(&body, "\"}"); + free(esc_q); + + /* Snapshot the channel list under lock so we can iterate without + * holding the mutex during network I/O. */ + pthread_mutex_lock(&_dharma_channel_mu); + size_t n = _dharma_channel_count; + char** urls = calloc(n ? n : 1, sizeof(char*)); + char** ids = calloc(n ? n : 1, sizeof(char*)); + char** bases = calloc(n ? n : 1, sizeof(char*)); + for (size_t i = 0; i < n; i++) { + urls[i] = el_strdup(_dharma_channels[i].url); + ids[i] = el_strdup(_dharma_channels[i].cgi_id); + bases[i] = el_strdup(_dharma_channels[i].base_id); + } + pthread_mutex_unlock(&_dharma_channel_mu); + + for (size_t i = 0; i < n; i++) { + size_t ul = strlen(urls[i]) + 32; + char* full_url = malloc(ul); + snprintf(full_url, ul, "%s/api/activate", urls[i]); + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + el_val_t resp = http_do("POST", full_url, body.buf, h); + curl_slist_free_all(h); + free(full_url); + const char* rs = EL_CSTR(resp); + if (!rs || !*rs) continue; + if (rs[0] == '{' && strstr(rs, "\"error\"")) continue; + + /* Look up relationship weight (attenuation). */ + double rel_weight = 1.0; + { + const char* self_id = "dharma:self"; + char peer_node[512]; + snprintf(peer_node, sizeof(peer_node), "dharma:peer:%s", bases[i]); + EngramStore* g = engram_get(); + for (int64_t k = 0; k < g->edge_count; k++) { + EngramEdge* e = &g->edges[k]; + if (e->from_id && e->to_id && + strcmp(e->from_id, self_id) == 0 && + strcmp(e->to_id, peer_node) == 0 && + e->relation && strcmp(e->relation, "dharma-relation") == 0) { + rel_weight = e->weight; + break; + } + } + } + + /* Iterate the response array. Expect either a top-level array + * or an object whose "results" field is an array. */ + const char* arr = rs; + while (*arr == ' ' || *arr == '\t' || *arr == '\n' || *arr == '\r') arr++; + char* arr_owned = NULL; + if (*arr == '{') { + el_val_t r = json_get_raw(EL_STR(rs), EL_STR("results")); + const char* rr = EL_CSTR(r); + if (rr && *rr == '[') { + arr_owned = el_strdup(rr); + arr = arr_owned; + } else { + continue; + } + } + if (*arr != '[') { free(arr_owned); continue; } + const char* p = arr + 1; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + while (*p && *p != ']') { + const char* end = json_skip_value(p); + size_t en = (size_t)(end - p); + char* obj = el_strbuf(en); + memcpy(obj, p, en); obj[en] = '\0'; + + /* Pull activation_strength if present, else 1.0. */ + el_val_t act_v = json_get_float(EL_STR(obj), EL_STR("activation_strength")); + double act = el_to_float(act_v); + if (!(act > 0.0 && act <= 100.0)) act = 1.0; + double final_act = act * rel_weight; + + el_val_t entry = el_map_new(0); + /* node = the inner JSON if present, else the entire obj. */ + el_val_t node_raw = json_get_raw(EL_STR(obj), EL_STR("node")); + const char* nr = EL_CSTR(node_raw); + entry = el_map_set(entry, EL_STR(el_strdup("node")), + (nr && *nr) ? node_raw : EL_STR(el_strdup(obj))); + entry = el_map_set(entry, EL_STR(el_strdup("source_cgi")), + EL_STR(el_strdup(ids[i]))); + entry = el_map_set(entry, EL_STR(el_strdup("activation_strength")), + el_from_float(final_act)); + out = el_list_append(out, entry); + free(obj); + p = end; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + } + free(arr_owned); + } + for (size_t i = 0; i < n; i++) { free(urls[i]); free(ids[i]); free(bases[i]); } + free(urls); free(ids); free(bases); + free(body.buf); + return out; +} + +void dharma_emit(el_val_t event_type, el_val_t payload) { + const char* et = EL_CSTR(event_type); + const char* pay = EL_CSTR(payload); + if (!et) et = ""; + if (!pay) pay = ""; + const char* src = _el_cgi_dharma_id ? _el_cgi_dharma_id : "(unknown)"; + int64_t ts = engram_now_ms(); + + char* esc_et = json_escape_alloc(et); + char* esc_pay = json_escape_alloc(pay); + char* esc_src = json_escape_alloc(src); + JsonBuf b; jb_init(&b); + jb_puts(&b, "{\"type\":\""); jb_puts(&b, esc_et); + jb_puts(&b, "\",\"payload\":\""); jb_puts(&b, esc_pay); + jb_puts(&b, "\",\"source\":\""); jb_puts(&b, esc_src); + jb_puts(&b, "\",\"timestamp\":"); jb_emit_int(&b, ts); + jb_putc(&b, '}'); + free(esc_et); free(esc_pay); free(esc_src); + + /* Snapshot URLs to avoid holding the channel mutex during I/O. */ + pthread_mutex_lock(&_dharma_channel_mu); + size_t n = _dharma_channel_count; + char** urls = calloc(n ? n : 1, sizeof(char*)); + for (size_t i = 0; i < n; i++) urls[i] = el_strdup(_dharma_channels[i].url); + pthread_mutex_unlock(&_dharma_channel_mu); + + for (size_t i = 0; i < n; i++) { + size_t ul = strlen(urls[i]) + 32; + char* full_url = malloc(ul); + snprintf(full_url, ul, "%s/dharma/event", urls[i]); + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + el_val_t r = http_do("POST", full_url, b.buf, h); + (void)r; /* fire-and-forget — emit is not synchronous */ + curl_slist_free_all(h); + free(full_url); + } + for (size_t i = 0; i < n; i++) free(urls[i]); + free(urls); + free(b.buf); +} + +void el_runtime_dharma_event_arrive(const char* event_type, const char* payload, + const char* source) { + DharmaEvent* ev = calloc(1, sizeof(DharmaEvent)); + if (!ev) return; + ev->event_type = el_strdup(event_type ? event_type : ""); + ev->payload = el_strdup(payload ? payload : ""); + ev->source = el_strdup(source ? source : ""); + ev->timestamp = engram_now_ms(); + ev->next = NULL; + pthread_mutex_lock(&_dharma_event_mu); + if (_dharma_event_tail) _dharma_event_tail->next = ev; + else _dharma_event_head = ev; + _dharma_event_tail = ev; + pthread_cond_broadcast(&_dharma_event_cv); + pthread_mutex_unlock(&_dharma_event_mu); +} + +el_val_t dharma_field(el_val_t event_type) { + const char* et = EL_CSTR(event_type); + if (!et) et = ""; + + /* Compute deadline: now + 30 seconds. */ + struct timespec deadline; + clock_gettime(CLOCK_REALTIME, &deadline); + deadline.tv_sec += 30; + + DharmaEvent* found = NULL; + pthread_mutex_lock(&_dharma_event_mu); + while (1) { + /* Scan queue for matching type; pop and return first match. */ + DharmaEvent* prev = NULL; + DharmaEvent* cur = _dharma_event_head; + while (cur) { + if (cur->event_type && strcmp(cur->event_type, et) == 0) { + if (prev) prev->next = cur->next; + else _dharma_event_head = cur->next; + if (_dharma_event_tail == cur) _dharma_event_tail = prev; + cur->next = NULL; + found = cur; + break; + } + prev = cur; cur = cur->next; + } + if (found) break; + int rc = pthread_cond_timedwait(&_dharma_event_cv, &_dharma_event_mu, &deadline); + if (rc == ETIMEDOUT) break; + } + pthread_mutex_unlock(&_dharma_event_mu); + + if (!found) return el_map_new(0); + el_val_t m = el_map_new(0); + m = el_map_set(m, EL_STR(el_strdup("type")), + EL_STR(el_strdup(found->event_type ? found->event_type : ""))); + m = el_map_set(m, EL_STR(el_strdup("payload")), + EL_STR(el_strdup(found->payload ? found->payload : ""))); + m = el_map_set(m, EL_STR(el_strdup("source_cgi")), + EL_STR(el_strdup(found->source ? found->source : ""))); + m = el_map_set(m, EL_STR(el_strdup("timestamp")), (el_val_t)found->timestamp); + free(found->event_type); free(found->payload); free(found->source); free(found); + return m; +} + +/* Locate (or create) the local "dharma:self" node and the synthetic peer + * node "dharma:peer:". Returns the index of the dharma-relation + * edge, or -1 if not found. If `create` is non-zero, ensure the nodes + * and edge exist (creating them as needed) and return the edge index. */ +static int64_t dharma_find_or_create_relation_edge(const char* peer_base, int create) { + if (!peer_base || !*peer_base) return -1; + EngramStore* g = engram_get(); + const char* self_id = "dharma:self"; + char peer_node[512]; + snprintf(peer_node, sizeof(peer_node), "dharma:peer:%s", peer_base); + + /* Look for the edge first. */ + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + if (e->from_id && e->to_id && + strcmp(e->from_id, self_id) == 0 && + strcmp(e->to_id, peer_node) == 0 && + e->relation && strcmp(e->relation, "dharma-relation") == 0) { + return i; + } + } + if (!create) return -1; + + /* Ensure self node exists. We use a fixed id (not engram_new_id) so + * subsequent calls reuse the same one. */ + if (!engram_find_node(self_id)) { + engram_grow_nodes(); + EngramNode* n = &g->nodes[g->node_count]; + memset(n, 0, sizeof(*n)); + n->id = el_strdup(self_id); + n->content = el_strdup(_el_cgi_dharma_id ? _el_cgi_dharma_id : "(self)"); + n->node_type = el_strdup("DharmaSelf"); + n->label = el_strdup("dharma:self"); + n->tier = el_strdup("Working"); + n->tags = el_strdup("dharma"); + n->metadata = el_strdup("{}"); + n->salience = 1.0; n->importance = 1.0; n->confidence = 1.0; + int64_t now = engram_now_ms(); + n->created_at = now; n->updated_at = now; n->last_activated = now; + n->layer_id = ENGRAM_LAYER_DEFAULT; + g->node_count++; + } + if (!engram_find_node(peer_node)) { + engram_grow_nodes(); + EngramNode* n = &g->nodes[g->node_count]; + memset(n, 0, sizeof(*n)); + n->id = el_strdup(peer_node); + n->content = el_strdup(peer_base); + n->node_type = el_strdup("DharmaPeer"); + n->label = el_strdup(peer_node); + n->tier = el_strdup("Working"); + n->tags = el_strdup("dharma"); + n->metadata = el_strdup("{}"); + n->salience = 0.5; n->importance = 0.5; n->confidence = 1.0; + int64_t now = engram_now_ms(); + n->created_at = now; n->updated_at = now; n->last_activated = now; + n->layer_id = ENGRAM_LAYER_DEFAULT; + g->node_count++; + } + /* Create the edge with weight 0.0 — caller will increment. */ + engram_grow_edges(); + EngramEdge* e = &g->edges[g->edge_count]; + memset(e, 0, sizeof(*e)); + e->id = engram_new_id(); + e->from_id = el_strdup(self_id); + e->to_id = el_strdup(peer_node); + e->relation = el_strdup("dharma-relation"); + e->metadata = el_strdup("{}"); + e->weight = 0.0; + e->confidence = 1.0; + int64_t now = engram_now_ms(); + e->created_at = now; e->updated_at = now; + e->layer_id = ENGRAM_LAYER_DEFAULT; + int64_t idx = g->edge_count; + g->edge_count++; + return idx; +} + +void dharma_strengthen(el_val_t cgi_id, el_val_t weight) { + const char* id = EL_CSTR(cgi_id); + if (!id || !*id) return; + char* base = NULL; char* url = NULL; + dharma_parse_id(id, &base, &url); + free(url); + int64_t ei = dharma_find_or_create_relation_edge(base, 1); + free(base); + if (ei < 0) return; + EngramStore* g = engram_get(); + double inc = engram_decode_score(weight); + if (!(inc >= 0.0)) inc = 0.0; + double w = g->edges[ei].weight + inc; + if (w < 0.0) w = 0.0; + if (w > 1.0) w = 1.0; + g->edges[ei].weight = w; + g->edges[ei].updated_at = engram_now_ms(); + g->edges[ei].last_fired = g->edges[ei].updated_at; +} + +el_val_t dharma_relationship(el_val_t cgi_id) { + const char* id = EL_CSTR(cgi_id); + if (!id || !*id) return el_from_float(0.0); + char* base = NULL; char* url = NULL; + dharma_parse_id(id, &base, &url); + free(url); + int64_t ei = dharma_find_or_create_relation_edge(base, 0); + free(base); + if (ei < 0) return el_from_float(0.0); + EngramStore* g = engram_get(); + return el_from_float(g->edges[ei].weight); +} + +el_val_t dharma_peers(void) { + /* Walk dharma-relation edges out of "dharma:self", weight > 0, sort desc. */ + EngramStore* g = engram_get(); + const char* self_id = "dharma:self"; + typedef struct { char* peer_base; double weight; } PeerEntry; + PeerEntry* peers = malloc((size_t)(g->edge_count + 1) * sizeof(PeerEntry)); + int64_t pcount = 0; + if (!peers) return el_list_empty(); + for (int64_t i = 0; i < g->edge_count; i++) { + EngramEdge* e = &g->edges[i]; + if (!e->from_id || !e->to_id) continue; + if (strcmp(e->from_id, self_id) != 0) continue; + if (!e->relation || strcmp(e->relation, "dharma-relation") != 0) continue; + if (e->weight <= 0.0) continue; + const char* prefix = "dharma:peer:"; + size_t pl = strlen(prefix); + if (strncmp(e->to_id, prefix, pl) != 0) continue; + peers[pcount].peer_base = el_strdup(e->to_id + pl); + peers[pcount].weight = e->weight; + pcount++; + } + /* Sort desc by weight. */ + for (int64_t i = 1; i < pcount; i++) { + PeerEntry key = peers[i]; + int64_t j = i - 1; + while (j >= 0 && peers[j].weight < key.weight) { + peers[j + 1] = peers[j]; j--; + } + peers[j + 1] = key; + } + el_val_t out = el_list_empty(); + for (int64_t i = 0; i < pcount; i++) { + out = el_list_append(out, EL_STR(peers[i].peer_base)); + } + free(peers); + return out; +} +#endif /* HAVE_CURL — DHARMA network */ + +/* ── Batch 4: LLM (Anthropic API client) ─────────────────────────────────── */ +/* + * All LLM builtins call https://api.anthropic.com/v1/messages with the API + * key from env ANTHROPIC_API_KEY. Default model is "claude-sonnet-4-5" + * when the supplied model is empty/null. + * + * `llm_call_agentic` runs a real multi-turn tool_use/tool_result loop. + * Tool handlers are registered with `llm_register_tool(name, fn_name)`, + * which dlsym()s the named symbol. Each tool handler has the C signature + * el_val_t handler(el_val_t input_json); + * and returns a JSON-string el_val_t result. Iteration is capped at 10. + */ + +#ifdef HAVE_CURL +static const char* LLM_DEFAULT_MODEL = "claude-sonnet-4-5"; +static const char* LLM_API_URL = "https://api.anthropic.com/v1/messages"; +static const char* LLM_VERSION = "2023-06-01"; + +static const char* llm_resolve_model(const char* m) { + if (!m || !*m) return LLM_DEFAULT_MODEL; + return m; +} + +/* + * ── Configurable LLM provider chain ────────────────────────────────────────── + * + * Providers are configured via indexed env vars. The runtime tries each in + * order (0, 1, 2, ...) and returns the first successful non-empty response. + * + * Per provider (N = 0, 1, 2, ...): + * NEURON_LLM_N_URL — endpoint URL (base URL; /v1/chat/completions appended + * if format is "openai" and not already in URL) + * NEURON_LLM_N_KEY — API key + * NEURON_LLM_N_FORMAT — "openai" (default) or "anthropic" + * NEURON_LLM_N_MODEL — model name override (optional) + * + * Example — Neuron inference primary, Anthropic fallback: + * NEURON_LLM_0_URL=https://soma.../v1/chat/completions + * NEURON_LLM_0_KEY=svc-key + * NEURON_LLM_0_FORMAT=openai + * NEURON_LLM_0_MODEL=neuron + * NEURON_LLM_1_URL=https://api.anthropic.com/v1/messages + * NEURON_LLM_1_KEY=sk-ant-... + * NEURON_LLM_1_FORMAT=anthropic + * + * If no NEURON_LLM_0_URL is set, falls back to legacy ANTHROPIC_API_KEY. + */ + +#define LLM_MAX_PROVIDERS 16 + +/* forward declarations */ +static el_val_t llm_extract_text(el_val_t resp_val); +static el_val_t llm_extract_text_openai(el_val_t resp_val); + +static el_val_t llm_extract_text_openai(el_val_t resp_val) { + const char* resp = EL_CSTR(resp_val); + if (!resp || !*resp) return el_wrap_str(el_strdup("")); + if (resp[0] == '{' && strstr(resp, "\"error\"")) return el_wrap_str(el_strdup("")); + const char* choices = json_find_key(resp, "choices"); + if (!choices || *choices != '[') return el_wrap_str(el_strdup("")); + choices++; + while (*choices == ' ' || *choices == '\t') choices++; + if (*choices != '{') return el_wrap_str(el_strdup("")); + const char* end = json_skip_value(choices); + size_t n = (size_t)(end - choices); + char* obj = malloc(n + 1); memcpy(obj, choices, n); obj[n] = '\0'; + const char* msg = json_find_key(obj, "message"); + if (!msg || *msg != '{') { free(obj); return el_wrap_str(el_strdup("")); } + const char* msg_end = json_skip_value(msg); + size_t mn = (size_t)(msg_end - msg); + char* msg_obj = malloc(mn + 1); memcpy(msg_obj, msg, mn); msg_obj[mn] = '\0'; + const char* content = json_find_key(msg_obj, "content"); + el_val_t result = el_wrap_str(el_strdup("")); + if (content && *content == '"') { + JsonParser jp = { .p = content, .end = content + strlen(content), .err = 0 }; + char* text = jp_parse_string_raw(&jp); + if (!jp.err && text) result = el_wrap_str(text); + } + free(msg_obj); free(obj); + return result; +} + +/* Send a request to one provider. Returns the raw response string. + * format: 0 = openai, 1 = anthropic */ +static el_val_t llm_provider_request(const char* url, const char* key, + int format, const char* model, + const char* system_str, + const char* user_str) { + char* esc_sys = system_str && *system_str ? json_escape_alloc(system_str) : NULL; + char* esc_user = json_escape_alloc(user_str ? user_str : ""); + JsonBuf b; jb_init(&b); + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + + if (format == 0) { /* OpenAI */ + char full_url[1024]; + if (strstr(url, "/chat/completions") || strstr(url, "/messages")) { + snprintf(full_url, sizeof(full_url), "%s", url); + } else { + snprintf(full_url, sizeof(full_url), "%s/v1/chat/completions", url); + } + { size_t n = strlen(key)+24; char* l=malloc(n); snprintf(l,n,"Authorization: Bearer %s",key); h=curl_slist_append(h,l); free(l); } + jb_putc(&b, '{'); + jb_puts(&b, "\"model\":"); jb_emit_escaped(&b, model ? model : "neuron"); + jb_puts(&b, ",\"max_tokens\":4096,\"messages\":["); + if (esc_sys && *esc_sys) { jb_puts(&b,"{\"role\":\"system\",\"content\":\""); jb_puts(&b,esc_sys); jb_puts(&b,"\"},"); } + jb_puts(&b, "{\"role\":\"user\",\"content\":\""); jb_puts(&b, esc_user); jb_puts(&b, "\"}]}"); + el_val_t resp = http_do("POST", full_url, b.buf, h); + curl_slist_free_all(h); free(b.buf); + if (esc_sys) free(esc_sys); free(esc_user); + return llm_extract_text_openai(resp); + } else { /* Anthropic */ + { size_t n = strlen(key)+16; char* l=malloc(n); snprintf(l,n,"x-api-key: %s",key); h=curl_slist_append(h,l); free(l); } + { size_t n = strlen(LLM_VERSION)+32; char* l=malloc(n); snprintf(l,n,"anthropic-version: %s",LLM_VERSION); h=curl_slist_append(h,l); free(l); } + jb_putc(&b, '{'); + jb_puts(&b, "\"model\":"); jb_emit_escaped(&b, model ? model : LLM_DEFAULT_MODEL); + jb_puts(&b, ",\"max_tokens\":4096"); + if (esc_sys && *esc_sys) { jb_puts(&b,",\"system\":\""); jb_puts(&b,esc_sys); jb_puts(&b,"\""); } + jb_puts(&b, ",\"messages\":[{\"role\":\"user\",\"content\":\""); jb_puts(&b, esc_user); jb_puts(&b, "\"}]}"); + el_val_t resp = http_do("POST", url, b.buf, h); + curl_slist_free_all(h); free(b.buf); + if (esc_sys) free(esc_sys); free(esc_user); + return llm_extract_text(resp); + } +} + +static el_val_t llm_chain_call(const char* system_str, const char* user_str) { + char url_key[64], key_key[64], fmt_key[64], model_key[64]; + for (int i = 0; i < LLM_MAX_PROVIDERS; i++) { + snprintf(url_key, sizeof(url_key), "NEURON_LLM_%d_URL", i); + snprintf(key_key, sizeof(key_key), "NEURON_LLM_%d_KEY", i); + snprintf(fmt_key, sizeof(fmt_key), "NEURON_LLM_%d_FORMAT", i); + snprintf(model_key, sizeof(model_key), "NEURON_LLM_%d_MODEL", i); + const char* url = getenv(url_key); + const char* key = getenv(key_key); + if (!url || !*url || !key || !*key) break; /* end of chain */ + const char* fmt_s = getenv(fmt_key); + int fmt = (fmt_s && strcmp(fmt_s, "anthropic") == 0) ? 1 : 0; + const char* model = getenv(model_key); + fprintf(stderr, "[llm] trying provider %d (%s)\n", i, url); + el_val_t result = llm_provider_request(url, key, fmt, model, system_str, user_str); + const char* t = EL_CSTR(result); + if (t && *t && t[0] != '{') return result; /* success */ + fprintf(stderr, "[llm] provider %d failed or empty, trying next\n", i); + } + /* Legacy fallback: ANTHROPIC_API_KEY */ + const char* api_key = getenv("ANTHROPIC_API_KEY"); + if (!api_key || !*api_key) return http_error_json("no LLM providers configured"); + fprintf(stderr, "[llm] using legacy ANTHROPIC_API_KEY fallback\n"); + return llm_provider_request(LLM_API_URL, api_key, 1, NULL, system_str, user_str); +} + +/* Legacy llm_request — kept for backward compat with agentic loop internals */ +static el_val_t llm_request(const char* json_body) { + const char* api_key = getenv("ANTHROPIC_API_KEY"); + if (!api_key || !*api_key) return http_error_json("ANTHROPIC_API_KEY not set"); + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + { size_t n=strlen(api_key)+16; char* l=malloc(n); snprintf(l,n,"x-api-key: %s",api_key); h=curl_slist_append(h,l); free(l); } + { size_t n=strlen(LLM_VERSION)+32; char* l=malloc(n); snprintf(l,n,"anthropic-version: %s",LLM_VERSION); h=curl_slist_append(h,l); free(l); } + el_val_t resp = http_do("POST", LLM_API_URL, json_body, h); + curl_slist_free_all(h); + return resp; +} + +/* Extract concatenated assistant text from an Anthropic /v1/messages + * response. The response shape is: + * {"content":[{"type":"text","text":"..."}, ...], ...} + * If parsing fails, returns the raw response so the caller can inspect. + */ +static el_val_t llm_extract_text(el_val_t resp_val) { + const char* resp = EL_CSTR(resp_val); + if (!resp || !*resp) return el_wrap_str(el_strdup("")); + /* If error JSON, propagate as-is. */ + if (resp[0] == '{' && strstr(resp, "\"error\"")) { + return el_wrap_str(el_strdup(resp)); + } + /* Find "content":[ ... ] */ + const char* p = json_find_key(resp, "content"); + if (!p) return el_wrap_str(el_strdup(resp)); + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') return el_wrap_str(el_strdup(resp)); + p++; + JsonBuf out; jb_init(&out); + while (*p && *p != ']') { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p != '{') break; + const char* end = json_skip_value(p); + size_t n = (size_t)(end - p); + char* obj = malloc(n + 1); + memcpy(obj, p, n); obj[n] = '\0'; + const char* type_p = json_find_key(obj, "type"); + if (type_p && *type_p == '"') { + JsonParser jp = { .p = type_p, .end = type_p + strlen(type_p), .err = 0 }; + char* type_s = jp_parse_string_raw(&jp); + if (!jp.err && type_s && strcmp(type_s, "text") == 0) { + const char* tp = json_find_key(obj, "text"); + if (tp && *tp == '"') { + JsonParser jp2 = { .p = tp, .end = tp + strlen(tp), .err = 0 }; + char* text_s = jp_parse_string_raw(&jp2); + if (!jp2.err && text_s) jb_puts(&out, text_s); + free(text_s); + } + } + free(type_s); + } + free(obj); + p = end; + } + return el_wrap_str(out.buf); +} + +el_val_t llm_call(el_val_t model, el_val_t prompt) { + const char* u = EL_CSTR(prompt); if (!u) u = ""; + return llm_chain_call(NULL, u); +} + +el_val_t llm_call_system(el_val_t model, el_val_t system_prompt, el_val_t user_prompt) { + const char* s = EL_CSTR(system_prompt); if (!s) s = ""; + const char* u = EL_CSTR(user_prompt); if (!u) u = ""; + return llm_chain_call(s, u); +} + +/* ── Tool registry for llm_call_agentic ─────────────────────────────────── */ + +typedef el_val_t (*llm_tool_fn)(el_val_t input); + +typedef struct LlmToolEntry { + char* name; + llm_tool_fn fn; +} LlmToolEntry; + +static LlmToolEntry _llm_tools[64]; +static size_t _llm_tool_count = 0; +static pthread_mutex_t _llm_tool_mu = PTHREAD_MUTEX_INITIALIZER; + +static llm_tool_fn llm_tool_lookup(const char* name) { + if (!name) return NULL; + llm_tool_fn fn = NULL; + pthread_mutex_lock(&_llm_tool_mu); + for (size_t i = 0; i < _llm_tool_count; i++) { + if (strcmp(_llm_tools[i].name, name) == 0) { fn = _llm_tools[i].fn; break; } + } + pthread_mutex_unlock(&_llm_tool_mu); + return fn; +} + +void llm_register_tool(el_val_t name, el_val_t handler_fn_name) { + const char* nm = EL_CSTR(name); + const char* sym = EL_CSTR(handler_fn_name); + if (!nm || !*nm || !sym || !*sym) return; + void* p = dlsym(RTLD_DEFAULT, sym); + if (!p) { + fprintf(stderr, "[llm_register_tool] symbol not found: %s\n", sym); + return; + } + pthread_mutex_lock(&_llm_tool_mu); + /* Replace existing entry by name. */ + for (size_t i = 0; i < _llm_tool_count; i++) { + if (strcmp(_llm_tools[i].name, nm) == 0) { + _llm_tools[i].fn = (llm_tool_fn)p; + pthread_mutex_unlock(&_llm_tool_mu); + return; + } + } + if (_llm_tool_count < sizeof(_llm_tools) / sizeof(_llm_tools[0])) { + _llm_tools[_llm_tool_count].name = el_strdup(nm); + _llm_tools[_llm_tool_count].fn = (llm_tool_fn)p; + _llm_tool_count++; + } + pthread_mutex_unlock(&_llm_tool_mu); +} + +/* Serialize the El `tools` list into the JSON `tools:[...]` field expected + * by the Anthropic API. Each tool is an ElMap with name/description/ + * input_schema. input_schema is treated as either a JSON-object string + * (passed through verbatim) or a missing field (substitute {}). */ +static void llm_emit_tools_json(JsonBuf* b, el_val_t tools_list) { + jb_putc(b, '['); + ElList* lst = (ElList*)(uintptr_t)tools_list; + int64_t n = lst ? lst->length : 0; + for (int64_t i = 0; i < n; i++) { + if (i > 0) jb_putc(b, ','); + ElMap* tm = as_map(lst->elems[i]); + const char* name = ""; + const char* desc = ""; + const char* schema = "{}"; + if (tm) { + for (int64_t k = 0; k < tm->count; k++) { + const char* key = EL_CSTR(tm->keys[k]); + const char* val = EL_CSTR(tm->values[k]); + if (!key || !val) continue; + if (strcmp(key, "name") == 0) name = val; + else if (strcmp(key, "description") == 0) desc = val; + else if (strcmp(key, "input_schema") == 0) schema = val; + } + } + char* esc_name = json_escape_alloc(name); + char* esc_desc = json_escape_alloc(desc); + jb_puts(b, "{\"name\":\""); jb_puts(b, esc_name); + jb_puts(b, "\",\"description\":\""); jb_puts(b, esc_desc); + jb_puts(b, "\",\"input_schema\":"); jb_puts(b, schema && *schema ? schema : "{}"); + jb_putc(b, '}'); + free(esc_name); free(esc_desc); + } + jb_putc(b, ']'); +} + +/* Walk the assistant `content` array and emit each block back into b, + * preserving the verbatim JSON of every block — used to re-include the + * assistant turn in the next request. */ +static void llm_emit_content_blocks(JsonBuf* b, const char* resp) { + const char* p = json_find_key(resp, "content"); + jb_putc(b, '['); + if (!p) { jb_putc(b, ']'); return; } + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') { jb_putc(b, ']'); return; } + p++; + int first = 1; + while (*p && *p != ']') { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p != '{') break; + const char* end = json_skip_value(p); + if (!first) jb_putc(b, ','); + first = 0; + size_t n = (size_t)(end - p); + jb_reserve(b, n); + memcpy(b->buf + b->len, p, n); + b->len += n; + b->buf[b->len] = '\0'; + p = end; + } + jb_putc(b, ']'); +} + +/* Concatenate all "text" blocks from a response. Returns owned string. */ +static char* llm_concat_text_blocks(const char* resp) { + JsonBuf out; jb_init(&out); + if (!resp) return out.buf; + const char* p = json_find_key(resp, "content"); + if (!p) return out.buf; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') return out.buf; + p++; + while (*p && *p != ']') { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p != '{') break; + const char* end = json_skip_value(p); + size_t n = (size_t)(end - p); + char* obj = malloc(n + 1); + memcpy(obj, p, n); obj[n] = '\0'; + const char* tp = json_find_key(obj, "type"); + if (tp && *tp == '"') { + JsonParser jp = { .p = tp, .end = tp + strlen(tp), .err = 0 }; + char* tname = jp_parse_string_raw(&jp); + if (!jp.err && tname && strcmp(tname, "text") == 0) { + const char* xp = json_find_key(obj, "text"); + if (xp && *xp == '"') { + JsonParser jp2 = { .p = xp, .end = xp + strlen(xp), .err = 0 }; + char* txt = jp_parse_string_raw(&jp2); + if (!jp2.err && txt) jb_puts(&out, txt); + free(txt); + } + } + free(tname); + } + free(obj); + p = end; + } + return out.buf; +} + +/* Build tool_result message blocks for every tool_use in a response. + * Appends to `b` an array element for each tool_use; caller wraps. */ +static int llm_build_tool_results(JsonBuf* b, const char* resp) { + int any = 0; + const char* p = json_find_key(resp, "content"); + if (!p) return 0; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') return 0; + p++; + while (*p && *p != ']') { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p != '{') break; + const char* end = json_skip_value(p); + size_t n = (size_t)(end - p); + char* obj = malloc(n + 1); + memcpy(obj, p, n); obj[n] = '\0'; + + const char* tp = json_find_key(obj, "type"); + char* type_s = NULL; + if (tp && *tp == '"') { + JsonParser jp = { .p = tp, .end = tp + strlen(tp), .err = 0 }; + type_s = jp_parse_string_raw(&jp); + } + if (type_s && strcmp(type_s, "tool_use") == 0) { + /* Extract id, name, input. */ + char* id_s = NULL; char* name_s = NULL; + const char* idp = json_find_key(obj, "id"); + if (idp && *idp == '"') { + JsonParser jp = { .p = idp, .end = idp + strlen(idp), .err = 0 }; + id_s = jp_parse_string_raw(&jp); + } + const char* np = json_find_key(obj, "name"); + if (np && *np == '"') { + JsonParser jp = { .p = np, .end = np + strlen(np), .err = 0 }; + name_s = jp_parse_string_raw(&jp); + } + el_val_t input_raw = json_get_raw(EL_STR(obj), EL_STR("input")); + const char* input_s = EL_CSTR(input_raw); + if (!input_s || !*input_s) input_s = "{}"; + + llm_tool_fn fn = llm_tool_lookup(name_s ? name_s : ""); + char* result = NULL; + int is_error = 0; + if (!fn) { + size_t en = strlen(name_s ? name_s : "(null)") + 64; + result = malloc(en); + snprintf(result, en, "{\"error\":\"tool not registered: %s\"}", + name_s ? name_s : "(null)"); + is_error = 1; + } else { + el_val_t out = fn(EL_STR(input_s)); + const char* os = EL_CSTR(out); + result = el_strdup(os ? os : ""); + } + + if (any) jb_putc(b, ','); + char* esc_id = json_escape_alloc(id_s ? id_s : ""); + char* esc_res = json_escape_alloc(result ? result : ""); + jb_puts(b, "{\"type\":\"tool_result\",\"tool_use_id\":\""); + jb_puts(b, esc_id); + jb_puts(b, "\",\"content\":\""); + jb_puts(b, esc_res); + jb_puts(b, "\""); + if (is_error) jb_puts(b, ",\"is_error\":true"); + jb_putc(b, '}'); + free(esc_id); free(esc_res); free(result); + free(id_s); free(name_s); + any = 1; + } + free(type_s); + free(obj); + p = end; + } + return any; +} + +el_val_t llm_call_agentic(el_val_t model, el_val_t system, el_val_t user, el_val_t tools) { + /* Empty tools list → degrade to plain system call. */ + ElList* tl = (ElList*)(uintptr_t)tools; + if (!tl || tl->length == 0) { + return llm_call_system(model, system, user); + } + const char* m = llm_resolve_model(EL_CSTR(model)); + const char* sys_p = EL_CSTR(system); if (!sys_p) sys_p = ""; + const char* usr_p = EL_CSTR(user); if (!usr_p) usr_p = ""; + + /* Build the static parts: tools JSON and system prompt — these don't + * change across iterations. */ + JsonBuf tools_buf; jb_init(&tools_buf); + llm_emit_tools_json(&tools_buf, tools); + char* esc_sys = json_escape_alloc(sys_p); + + /* messages array, accumulated as a mutable JSON fragment (no surrounding + * brackets — emitted at request time). */ + JsonBuf msgs; jb_init(&msgs); + /* First user message. */ + char* esc_user = json_escape_alloc(usr_p); + jb_puts(&msgs, "{\"role\":\"user\",\"content\":\""); + jb_puts(&msgs, esc_user); + jb_puts(&msgs, "\"}"); + free(esc_user); + + char* last_text = el_strdup(""); + el_val_t final_out = 0; + int reached_cap = 1; + + for (int iter = 0; iter < 10; iter++) { + /* Build request body. */ + JsonBuf body; jb_init(&body); + jb_putc(&body, '{'); + jb_puts(&body, "\"model\":"); jb_emit_escaped(&body, m); + jb_puts(&body, ",\"max_tokens\":4096"); + if (*sys_p) { + jb_puts(&body, ",\"system\":\""); + jb_puts(&body, esc_sys); + jb_puts(&body, "\""); + } + jb_puts(&body, ",\"tools\":"); + jb_puts(&body, tools_buf.buf); + jb_puts(&body, ",\"messages\":["); + jb_puts(&body, msgs.buf); + jb_puts(&body, "]}"); + + el_val_t resp_v = llm_request(body.buf); + free(body.buf); + const char* resp = EL_CSTR(resp_v); + if (!resp || !*resp) { + final_out = http_error_json("empty response"); + reached_cap = 0; + break; + } + if (resp[0] == '{' && strstr(resp, "\"error\"") && + !json_find_key(resp, "content")) { + final_out = el_wrap_str(el_strdup(resp)); + reached_cap = 0; + break; + } + + /* Update last_text from this response. */ + free(last_text); + last_text = llm_concat_text_blocks(resp); + + /* Inspect stop_reason. */ + el_val_t sr_v = json_get_string(EL_STR(resp), EL_STR("stop_reason")); + const char* sr = EL_CSTR(sr_v); if (!sr) sr = ""; + + if (strcmp(sr, "end_turn") == 0) { + final_out = el_wrap_str(el_strdup(last_text)); + reached_cap = 0; + break; + } + if (strcmp(sr, "max_tokens") == 0) { + size_t ln = strlen(last_text) + 16; + char* out = malloc(ln); + snprintf(out, ln, "%s\n[truncated]", last_text); + final_out = el_wrap_str(out); + reached_cap = 0; + break; + } + if (strcmp(sr, "tool_use") != 0) { + /* Unexpected stop reason; return the text we have. */ + final_out = el_wrap_str(el_strdup(last_text)); + reached_cap = 0; + break; + } + + /* Append the assistant turn (raw content blocks) to messages. */ + JsonBuf ab; jb_init(&ab); + jb_puts(&ab, ",{\"role\":\"assistant\",\"content\":"); + llm_emit_content_blocks(&ab, resp); + jb_putc(&ab, '}'); + jb_puts(&msgs, ab.buf); + free(ab.buf); + + /* Build tool_result message. */ + JsonBuf tr; jb_init(&tr); + jb_puts(&tr, ",{\"role\":\"user\",\"content\":["); + int any = llm_build_tool_results(&tr, resp); + jb_puts(&tr, "]}"); + if (any) { + jb_puts(&msgs, tr.buf); + } + free(tr.buf); + } + + if (reached_cap) { + size_t ln = strlen(last_text) + 32; + char* out = malloc(ln); + snprintf(out, ln, "[loop_cap_reached]\n%s", last_text); + final_out = el_wrap_str(out); + } + free(last_text); + free(esc_sys); + free(tools_buf.buf); + free(msgs.buf); + return final_out; +} + +/* base64-encode arbitrary bytes (returns owned C string). + * Internal helper for llm_vision; the public crypto entry point that El + * programs call is `base64_encode(el_val_t)` defined in the crypto block + * at the end of this file. */ +static char* el_b64_encode_internal(const unsigned char* src, size_t n) { + static const char tbl[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + size_t out_len = 4 * ((n + 2) / 3); + char* out = malloc(out_len + 1); + if (!out) return NULL; + size_t o = 0; + for (size_t i = 0; i < n;) { + uint32_t v = 0; int got = 0; + v |= (uint32_t)src[i++] << 16; got++; + if (i < n) { v |= (uint32_t)src[i++] << 8; got++; } + if (i < n) { v |= (uint32_t)src[i++]; got++; } + out[o++] = tbl[(v >> 18) & 0x3f]; + out[o++] = tbl[(v >> 12) & 0x3f]; + out[o++] = (got > 1) ? tbl[(v >> 6) & 0x3f] : '='; + out[o++] = (got > 2) ? tbl[v & 0x3f] : '='; + } + out[o] = '\0'; + return out; +} + +el_val_t llm_vision(el_val_t model, el_val_t system, el_val_t prompt, el_val_t image_url_or_b64) { + const char* m = llm_resolve_model(EL_CSTR(model)); + const char* s = EL_CSTR(system); if (!s) s = ""; + const char* u = EL_CSTR(prompt); if (!u) u = ""; + const char* img = EL_CSTR(image_url_or_b64); if (!img) img = ""; + + /* Choose source mode */ + char* image_block = NULL; + if (strncasecmp(img, "http://", 7) == 0 || strncasecmp(img, "https://", 8) == 0) { + char* esc_url = json_escape_alloc(img); + size_t n = strlen(esc_url) + 128; + image_block = malloc(n); + snprintf(image_block, n, + "{\"type\":\"image\",\"source\":{\"type\":\"url\",\"url\":\"%s\"}}", + esc_url); + free(esc_url); + } else if (strncmp(img, "data:", 5) == 0) { + /* Inline data URL: split media-type and base64 */ + const char* semi = strchr(img + 5, ';'); + const char* comma = strchr(img + 5, ','); + char media[64] = "image/png"; + if (semi && comma && semi < comma) { + size_t ml = (size_t)(semi - (img + 5)); + if (ml >= sizeof(media)) ml = sizeof(media) - 1; + memcpy(media, img + 5, ml); media[ml] = '\0'; + } + const char* b64 = comma ? comma + 1 : ""; + char* esc_media = json_escape_alloc(media); + char* esc_b64 = json_escape_alloc(b64); + size_t n = strlen(esc_media) + strlen(esc_b64) + 192; + image_block = malloc(n); + snprintf(image_block, n, + "{\"type\":\"image\",\"source\":{\"type\":\"base64\"," + "\"media_type\":\"%s\",\"data\":\"%s\"}}", + esc_media, esc_b64); + free(esc_media); free(esc_b64); + } else if (*img) { + /* Treat as file path: read, base64-encode, attach. */ + FILE* f = fopen(img, "rb"); + if (!f) { + char err[256]; snprintf(err, sizeof(err), "cannot open image: %s", img); + return http_error_json(err); + } + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + if (sz <= 0) { fclose(f); return http_error_json("empty image file"); } + unsigned char* buf = malloc((size_t)sz); + if (!buf) { fclose(f); return http_error_json("oom"); } + size_t got = fread(buf, 1, (size_t)sz, f); + fclose(f); + char* b64 = el_b64_encode_internal(buf, got); + free(buf); + if (!b64) return http_error_json("base64 encode failed"); + const char* media = "image/png"; + size_t ilen = strlen(img); + if (ilen >= 4) { + if (strcasecmp(img + ilen - 4, ".jpg") == 0 || + (ilen >= 5 && strcasecmp(img + ilen - 5, ".jpeg") == 0)) media = "image/jpeg"; + else if (strcasecmp(img + ilen - 4, ".gif") == 0) media = "image/gif"; + else if (strcasecmp(img + ilen - 4, ".webp") == 0) media = "image/webp"; + } + char* esc_b64 = json_escape_alloc(b64); free(b64); + size_t n = strlen(esc_b64) + 192; + image_block = malloc(n); + snprintf(image_block, n, + "{\"type\":\"image\",\"source\":{\"type\":\"base64\"," + "\"media_type\":\"%s\",\"data\":\"%s\"}}", + media, esc_b64); + free(esc_b64); + } + + char* esc_sys = json_escape_alloc(s); + char* esc_user = json_escape_alloc(u); + JsonBuf b; jb_init(&b); + jb_putc(&b, '{'); + jb_puts(&b, "\"model\":"); jb_emit_escaped(&b, m); + jb_puts(&b, ",\"max_tokens\":4096"); + if (*s) { + jb_puts(&b, ",\"system\":\""); + jb_puts(&b, esc_sys); + jb_puts(&b, "\""); + } + jb_puts(&b, ",\"messages\":[{\"role\":\"user\",\"content\":["); + if (image_block) { + jb_puts(&b, image_block); + jb_putc(&b, ','); + } + jb_puts(&b, "{\"type\":\"text\",\"text\":\""); + jb_puts(&b, esc_user); + jb_puts(&b, "\"}]}]}"); + free(esc_sys); free(esc_user); free(image_block); + el_val_t resp = llm_request(b.buf); + free(b.buf); + return llm_extract_text(resp); +} + +el_val_t llm_models(void) { + el_val_t lst = el_list_empty(); + lst = el_list_append(lst, el_wrap_str(el_strdup("claude-sonnet-4-5"))); + lst = el_list_append(lst, el_wrap_str(el_strdup("claude-opus-4-7"))); + lst = el_list_append(lst, el_wrap_str(el_strdup("claude-haiku-4-5"))); + return lst; +} +#endif /* HAVE_CURL */ + +/* ── Native VM builtin aliases ────────────────────────────────────────────── + * El source files use native_* names (El VM builtins). + * When compiled to C, these map directly to el_* runtime functions. */ + +el_val_t native_list_get(el_val_t list, el_val_t index) { + return el_list_get(list, index); +} + +el_val_t native_list_len(el_val_t list) { + return el_list_len(list); +} + +el_val_t native_list_append(el_val_t list, el_val_t elem) { + return el_list_append(list, elem); +} + +el_val_t native_list_empty(void) { + return el_list_empty(); +} + +el_val_t native_list_clone(el_val_t list) { + return el_list_clone(list); +} + +el_val_t native_string_chars(el_val_t sv) { + const char* s = EL_CSTR(sv); + el_val_t result = el_list_empty(); + if (!s) return result; + while (*s) { + char buf[2]; + buf[0] = *s; + buf[1] = '\0'; + result = el_list_append(result, EL_STR(strdup(buf))); + s++; + } + return result; +} + +el_val_t native_int_to_str(el_val_t n) { + return int_to_str(n); +} + +/* ── Method-call shorthand aliases ────────────────────────────────────────── + * Short names that result from the method-call convention: + * myList.append(x) → append(myList, x) + * myList.len() → len(myList) + * myList.get(i) → get(myList, i) + * myMap.map_get(k) → map_get(myMap, k) + * myMap.map_set(k,v) → map_set(myMap, k, v) */ + +el_val_t append(el_val_t list, el_val_t elem) { return el_list_append(list, elem); } +el_val_t len(el_val_t list) { return el_list_len(list); } +el_val_t get(el_val_t list, el_val_t index) { return el_list_get(list, index); } +el_val_t map_get(el_val_t map, el_val_t key) { return el_map_get(map, key); } +el_val_t map_set(el_val_t map, el_val_t key, el_val_t value) { return el_map_set(map, key, value); } + +/* ── Crypto primitives ────────────────────────────────────────────────────── + * + * SHA-256 implementation adapted from Brad Conte's public-domain reference + * (https://github.com/B-Con/crypto-algorithms/blob/master/sha256.c, public + * domain per the project's LICENSE). HMAC follows RFC 2104. Base64 encoding + * follows RFC 4648; the URL-safe variant uses the alphabet from §5 of the + * RFC and omits padding (per JWT/JWS convention). + * + * Self-contained: no OpenSSL/libcrypto dependency. The runtime keeps its + * existing `-lcurl -lpthread -ldl -lm` link line. + * + * Binary outputs (sha256_bytes, hmac_sha256_bytes) tag their buffer with a + * magic header so base64_encode/base64url_encode can recover the exact byte + * length even when the payload contains embedded NULs. Plain C strings + * (without the header) fall back to strlen(), preserving the existing API + * shape for normal text inputs. */ + +/* Magic-header for length-tagged binary buffers. Layout: + * [ uint32_t magic = EL_MAGIC_BIN ][ uint32_t length ][ data... ][ \0 ] + * The returned el_val_t points at `data`, so consumers that strlen() it still + * get a sensible (though possibly truncated) view. el_bin_len() recovers the + * true length by sniffing the 8 bytes preceding the pointer. + * + * Magic value chosen with high MSB so it cannot collide with printable ASCII + * (the same discriminator pattern used by EL_MAGIC_LIST / EL_MAGIC_MAP). */ +#define EL_MAGIC_BIN 0xE1B17EAFu + +typedef struct { + uint32_t magic; + uint32_t length; +} el_bin_hdr_t; + +/* Allocate a length-tagged binary buffer; returns pointer to the data area. */ +static unsigned char* el_bin_alloc(size_t len) { + el_bin_hdr_t* hdr = (el_bin_hdr_t*)malloc(sizeof(el_bin_hdr_t) + len + 1); + if (!hdr) { fputs("el_runtime: out of memory (bin)\n", stderr); exit(1); } + hdr->magic = EL_MAGIC_BIN; + hdr->length = (uint32_t)len; + unsigned char* data = (unsigned char*)(hdr + 1); + data[len] = '\0'; /* keep NUL-terminated for accidental strlen calls */ + return data; +} + +/* Recover length from a possibly-tagged buffer. Returns 1 if tagged. */ +static int el_bin_lookup(const void* p, size_t* out_len) { + if (!p) { *out_len = 0; return 0; } + /* Avoid reading off the front of a page on tiny pointers (e.g. NULs + * passed in as int-cast values). 4096 is a safe lower bound on any + * platform we target. */ + if ((uintptr_t)p < 4096) return 0; + const el_bin_hdr_t* hdr = (const el_bin_hdr_t*)((const char*)p - sizeof(el_bin_hdr_t)); + if (hdr->magic != EL_MAGIC_BIN) return 0; + *out_len = hdr->length; + return 1; +} + +/* Effective input length: tagged length if present, else strlen. */ +static size_t el_input_len(const char* s) { + size_t n; + if (el_bin_lookup(s, &n)) return n; + return s ? strlen(s) : 0; +} + +/* ─── SHA-256 (Brad Conte / public domain) ──────────────────────────────── */ + +typedef struct { + unsigned char data[64]; + uint32_t datalen; + uint64_t bitlen; + uint32_t state[8]; +} el_sha256_ctx_t; + +static const uint32_t el_sha256_k[64] = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +}; + +#define EL_ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) +#define EL_CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) +#define EL_MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define EL_EP0(x) (EL_ROTR(x,2) ^ EL_ROTR(x,13) ^ EL_ROTR(x,22)) +#define EL_EP1(x) (EL_ROTR(x,6) ^ EL_ROTR(x,11) ^ EL_ROTR(x,25)) +#define EL_SIG0(x) (EL_ROTR(x,7) ^ EL_ROTR(x,18) ^ ((x) >> 3)) +#define EL_SIG1(x) (EL_ROTR(x,17) ^ EL_ROTR(x,19) ^ ((x) >> 10)) + +static void el_sha256_transform(el_sha256_ctx_t* ctx, const unsigned char* data) { + uint32_t a, b, c, d, e, f, g, h, t1, t2, m[64]; + int i, j; + for (i = 0, j = 0; i < 16; ++i, j += 4) { + m[i] = ((uint32_t)data[j] << 24) | ((uint32_t)data[j + 1] << 16) + | ((uint32_t)data[j + 2] << 8) | (uint32_t)data[j + 3]; + } + for (; i < 64; ++i) { + m[i] = EL_SIG1(m[i-2]) + m[i-7] + EL_SIG0(m[i-15]) + m[i-16]; + } + a = ctx->state[0]; b = ctx->state[1]; c = ctx->state[2]; d = ctx->state[3]; + e = ctx->state[4]; f = ctx->state[5]; g = ctx->state[6]; h = ctx->state[7]; + for (i = 0; i < 64; ++i) { + t1 = h + EL_EP1(e) + EL_CH(e,f,g) + el_sha256_k[i] + m[i]; + t2 = EL_EP0(a) + EL_MAJ(a,b,c); + h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2; + } + ctx->state[0] += a; ctx->state[1] += b; ctx->state[2] += c; ctx->state[3] += d; + ctx->state[4] += e; ctx->state[5] += f; ctx->state[6] += g; ctx->state[7] += h; +} + +static void el_sha256_init(el_sha256_ctx_t* ctx) { + ctx->datalen = 0; + ctx->bitlen = 0; + ctx->state[0] = 0x6a09e667; ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; ctx->state[7] = 0x5be0cd19; +} + +static void el_sha256_update(el_sha256_ctx_t* ctx, const unsigned char* data, size_t len) { + for (size_t i = 0; i < len; ++i) { + ctx->data[ctx->datalen++] = data[i]; + if (ctx->datalen == 64) { + el_sha256_transform(ctx, ctx->data); + ctx->bitlen += 512; + ctx->datalen = 0; + } + } +} + +static void el_sha256_final(el_sha256_ctx_t* ctx, unsigned char hash[32]) { + uint32_t i = ctx->datalen; + if (ctx->datalen < 56) { + ctx->data[i++] = 0x80; + while (i < 56) ctx->data[i++] = 0x00; + } else { + ctx->data[i++] = 0x80; + while (i < 64) ctx->data[i++] = 0x00; + el_sha256_transform(ctx, ctx->data); + memset(ctx->data, 0, 56); + } + ctx->bitlen += (uint64_t)ctx->datalen * 8; + ctx->data[63] = (unsigned char)( ctx->bitlen & 0xff); + ctx->data[62] = (unsigned char)((ctx->bitlen >> 8) & 0xff); + ctx->data[61] = (unsigned char)((ctx->bitlen >> 16) & 0xff); + ctx->data[60] = (unsigned char)((ctx->bitlen >> 24) & 0xff); + ctx->data[59] = (unsigned char)((ctx->bitlen >> 32) & 0xff); + ctx->data[58] = (unsigned char)((ctx->bitlen >> 40) & 0xff); + ctx->data[57] = (unsigned char)((ctx->bitlen >> 48) & 0xff); + ctx->data[56] = (unsigned char)((ctx->bitlen >> 56) & 0xff); + el_sha256_transform(ctx, ctx->data); + for (i = 0; i < 4; ++i) { + hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0xff; + hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0xff; + hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0xff; + hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0xff; + hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0xff; + hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0xff; + hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0xff; + hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0xff; + } +} + +static void el_sha256_oneshot(const unsigned char* data, size_t len, unsigned char out[32]) { + el_sha256_ctx_t c; + el_sha256_init(&c); + el_sha256_update(&c, data, len); + el_sha256_final(&c, out); +} + +/* ─── HMAC-SHA-256 (RFC 2104) ───────────────────────────────────────────── */ + +static void el_hmac_sha256(const unsigned char* key, size_t key_len, + const unsigned char* msg, size_t msg_len, + unsigned char out[32]) { + unsigned char k[64]; + unsigned char k_ipad[64]; + unsigned char k_opad[64]; + unsigned char inner[32]; + + if (key_len > 64) { + el_sha256_oneshot(key, key_len, k); + memset(k + 32, 0, 32); + } else { + memcpy(k, key, key_len); + memset(k + key_len, 0, 64 - key_len); + } + for (int i = 0; i < 64; ++i) { + k_ipad[i] = k[i] ^ 0x36; + k_opad[i] = k[i] ^ 0x5c; + } + { + el_sha256_ctx_t c; + el_sha256_init(&c); + el_sha256_update(&c, k_ipad, 64); + el_sha256_update(&c, msg, msg_len); + el_sha256_final(&c, inner); + } + { + el_sha256_ctx_t c; + el_sha256_init(&c); + el_sha256_update(&c, k_opad, 64); + el_sha256_update(&c, inner, 32); + el_sha256_final(&c, out); + } +} + +/* ─── Hex helper ────────────────────────────────────────────────────────── */ + +static el_val_t el_hex_encode(const unsigned char* data, size_t len) { + static const char digits[] = "0123456789abcdef"; + char* out = el_strbuf(len * 2); + for (size_t i = 0; i < len; ++i) { + out[i * 2] = digits[(data[i] >> 4) & 0xf]; + out[i * 2 + 1] = digits[ data[i] & 0xf]; + } + out[len * 2] = '\0'; + return el_wrap_str(out); +} + +/* ─── Base64 (RFC 4648) ─────────────────────────────────────────────────── */ + +static const char el_b64_std_alphabet[64] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char el_b64_url_alphabet[64] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + +el_val_t el_base64_encode_n(const unsigned char* data, size_t len, int url_safe) { + const char* alphabet = url_safe ? el_b64_url_alphabet : el_b64_std_alphabet; + /* Standard form is padded to multiple of 4; URL-safe omits padding. */ + size_t out_cap = ((len + 2) / 3) * 4 + 1; + char* out = el_strbuf(out_cap); + size_t i = 0, j = 0; + while (i + 3 <= len) { + uint32_t v = ((uint32_t)data[i] << 16) | ((uint32_t)data[i+1] << 8) | (uint32_t)data[i+2]; + out[j++] = alphabet[(v >> 18) & 0x3f]; + out[j++] = alphabet[(v >> 12) & 0x3f]; + out[j++] = alphabet[(v >> 6) & 0x3f]; + out[j++] = alphabet[ v & 0x3f]; + i += 3; + } + size_t rem = len - i; + if (rem == 1) { + uint32_t v = (uint32_t)data[i] << 16; + out[j++] = alphabet[(v >> 18) & 0x3f]; + out[j++] = alphabet[(v >> 12) & 0x3f]; + if (!url_safe) { out[j++] = '='; out[j++] = '='; } + } else if (rem == 2) { + uint32_t v = ((uint32_t)data[i] << 16) | ((uint32_t)data[i+1] << 8); + out[j++] = alphabet[(v >> 18) & 0x3f]; + out[j++] = alphabet[(v >> 12) & 0x3f]; + out[j++] = alphabet[(v >> 6) & 0x3f]; + if (!url_safe) { out[j++] = '='; } + } + out[j] = '\0'; + return el_wrap_str(out); +} + +/* Decode either alphabet — accepts both '+/' and '-_' transparently, and + * tolerates missing padding (which JWTs typically omit). Whitespace is + * skipped for robustness. Invalid characters cause the decode to stop and + * the partial result so far is returned. */ +static el_val_t el_base64_decode_any(const char* in) { + if (!in) { + unsigned char* empty = el_bin_alloc(0); + return EL_STR((char*)empty); + } + size_t in_len = strlen(in); + /* Worst case: 3 output bytes per 4 input chars, +1 NUL slack. */ + unsigned char* out = el_bin_alloc(((in_len + 3) / 4) * 3 + 1); + + int8_t lut[256]; + for (int i = 0; i < 256; ++i) lut[i] = -1; + for (int i = 0; i < 64; ++i) lut[(unsigned char)el_b64_std_alphabet[i]] = (int8_t)i; + /* Allow URL-safe characters too (so one decoder handles both forms). */ + lut[(unsigned char)'-'] = 62; + lut[(unsigned char)'_'] = 63; + + uint32_t buf = 0; + int bits = 0; + size_t o = 0; + for (size_t i = 0; i < in_len; ++i) { + unsigned char c = (unsigned char)in[i]; + if (c == '=' || c == '\r' || c == '\n' || c == ' ' || c == '\t') continue; + int8_t v = lut[c]; + if (v < 0) break; /* invalid char — stop */ + buf = (buf << 6) | (uint32_t)v; + bits += 6; + if (bits >= 8) { + bits -= 8; + out[o++] = (unsigned char)((buf >> bits) & 0xff); + } + } + /* Patch the length header to the actual decoded length. */ + el_bin_hdr_t* hdr = (el_bin_hdr_t*)((char*)out - sizeof(el_bin_hdr_t)); + hdr->length = (uint32_t)o; + out[o] = '\0'; + return EL_STR((char*)out); +} + +/* ─── Public crypto entry points ────────────────────────────────────────── */ + +el_val_t el_sha256_bytes_n(const unsigned char* data, size_t len) { + unsigned char* out = el_bin_alloc(32); + el_sha256_oneshot(data, len, out); + return EL_STR((char*)out); +} + +el_val_t sha256_hex(el_val_t input) { + const char* s = EL_CSTR(input); + size_t n = el_input_len(s); + unsigned char digest[32]; + el_sha256_oneshot((const unsigned char*)(s ? s : ""), n, digest); + return el_hex_encode(digest, 32); +} + +el_val_t sha256_bytes(el_val_t input) { + const char* s = EL_CSTR(input); + size_t n = el_input_len(s); + return el_sha256_bytes_n((const unsigned char*)(s ? s : ""), n); +} + +el_val_t hmac_sha256_hex(el_val_t key, el_val_t message) { + const char* k = EL_CSTR(key); + const char* m = EL_CSTR(message); + size_t kn = el_input_len(k); + size_t mn = el_input_len(m); + unsigned char mac[32]; + el_hmac_sha256((const unsigned char*)(k ? k : ""), kn, + (const unsigned char*)(m ? m : ""), mn, + mac); + return el_hex_encode(mac, 32); +} + +el_val_t hmac_sha256_bytes(el_val_t key, el_val_t message) { + const char* k = EL_CSTR(key); + const char* m = EL_CSTR(message); + size_t kn = el_input_len(k); + size_t mn = el_input_len(m); + unsigned char* out = el_bin_alloc(32); + el_hmac_sha256((const unsigned char*)(k ? k : ""), kn, + (const unsigned char*)(m ? m : ""), mn, + out); + return EL_STR((char*)out); +} + +el_val_t base64_encode(el_val_t input) { + const char* s = EL_CSTR(input); + size_t n = el_input_len(s); + return el_base64_encode_n((const unsigned char*)(s ? s : ""), n, /*url_safe=*/0); +} + +el_val_t base64url_encode(el_val_t input) { + const char* s = EL_CSTR(input); + size_t n = el_input_len(s); + return el_base64_encode_n((const unsigned char*)(s ? s : ""), n, /*url_safe=*/1); +} + +el_val_t base64_decode(el_val_t input) { + return el_base64_decode_any(EL_CSTR(input)); +} + +el_val_t base64url_decode(el_val_t input) { + return el_base64_decode_any(EL_CSTR(input)); +} + +/* ── Post-quantum cryptography (liboqs + OpenSSL) ─────────────────────────── + * + * Algorithm choices (per CNSA 2.0 / NIST PQ guidance, as of 2024): + * Signatures: CRYSTALS-Dilithium-3 (NIST security level 3, balanced) + * KEM: CRYSTALS-Kyber-768 (NIST security level 3) + * Hash: SHA3-256 (Keccak) (PQ-aware protocols favour SHA3 over SHA2) + * Hybrid: X25519 || Kyber-768, combined via HKDF-SHA256 + * + * Why hybrid: Kyber is new. X25519 has 20+ years of analysis. Hybridizing + * preserves classical security if Kyber falls to a future cryptanalytic + * advance, and preserves PQ security if X25519 falls to a quantum adversary. + * "Recordable now, decryptable later" already threatens long-lived classical + * key exchange — the only safe move for keys protecting durable doctrine + * (CGI lineage, KindredGrants, Principal-CGI covenants) is to encapsulate + * with PQ today, even if the classical leg is what the wire shows. + * + * Compile-time detection: when is unavailable the pq_* functions + * compile to stubs that return a JSON error envelope. SHA3-256 stays + * available regardless (it's implemented inline, no liboqs dep). This lets + * the runtime build cleanly on dev machines without liboqs while production + * gets the full PQ stack. */ + +/* ─── SHA3-256 (Keccak, FIPS 202) ──────────────────────────────────────────── + * Inline reference implementation. ~120 LoC, no external dependency. + * rate=1088 bits, capacity=512 bits, output=256 bits, padding=0x06. */ + +static const uint64_t el_keccak_rc[24] = { + 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, + 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, + 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, + 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, + 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, + 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, + 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, + 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL +}; + +static const unsigned el_keccak_rho[24] = { + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 +}; + +static const unsigned el_keccak_pi[24] = { + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 +}; + +#define EL_ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n)))) + +static void el_keccak_f1600(uint64_t s[25]) { + for (int round = 0; round < 24; ++round) { + uint64_t bc[5], t; + for (int i = 0; i < 5; ++i) + bc[i] = s[i] ^ s[i+5] ^ s[i+10] ^ s[i+15] ^ s[i+20]; + for (int i = 0; i < 5; ++i) { + t = bc[(i+4) % 5] ^ EL_ROTL64(bc[(i+1) % 5], 1); + for (int j = 0; j < 25; j += 5) s[j+i] ^= t; + } + t = s[1]; + for (int i = 0; i < 24; ++i) { + int j = el_keccak_pi[i]; + bc[0] = s[j]; + s[j] = EL_ROTL64(t, el_keccak_rho[i]); + t = bc[0]; + } + for (int j = 0; j < 25; j += 5) { + for (int i = 0; i < 5; ++i) bc[i] = s[j+i]; + for (int i = 0; i < 5; ++i) + s[j+i] = bc[i] ^ ((~bc[(i+1) % 5]) & bc[(i+2) % 5]); + } + s[0] ^= el_keccak_rc[round]; + } +} + +static void el_sha3_256_oneshot(const unsigned char* data, size_t len, + unsigned char out[32]) { + uint64_t st[25] = {0}; + unsigned char* sb = (unsigned char*)st; + const size_t rate = 136; /* 1088 bits / 8 */ + size_t i = 0; + while (len - i >= rate) { + for (size_t k = 0; k < rate; ++k) sb[k] ^= data[i + k]; + el_keccak_f1600(st); + i += rate; + } + size_t rem = len - i; + for (size_t k = 0; k < rem; ++k) sb[k] ^= data[i + k]; + sb[rem] ^= 0x06; /* SHA3 domain-separation byte */ + sb[rate - 1] ^= 0x80; /* final-block padding bit (high bit of last byte) */ + el_keccak_f1600(st); + memcpy(out, sb, 32); +} + +el_val_t sha3_256_hex(el_val_t input) { + const char* s = EL_CSTR(input); + size_t n = el_input_len(s); + unsigned char digest[32]; + el_sha3_256_oneshot((const unsigned char*)(s ? s : ""), n, digest); + return el_hex_encode(digest, 32); +} + +/* ─── Hex decode helper ───────────────────────────────────────────────────── + * Returns a length-tagged binary buffer (so embedded NULs survive); on + * odd-length / invalid input returns NULL with *out_len = 0. Caller is + * responsible for emitting the error envelope. */ + +static int el_hex_nibble(char c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + return -1; +} + +__attribute__((unused)) +static unsigned char* el_hex_decode(const char* s, size_t* out_len) { + *out_len = 0; + if (!s) return NULL; + size_t n = strlen(s); + if (n & 1) return NULL; + size_t blen = n / 2; + unsigned char* out = el_bin_alloc(blen); + for (size_t i = 0; i < blen; ++i) { + int hi = el_hex_nibble(s[i*2]); + int lo = el_hex_nibble(s[i*2 + 1]); + if (hi < 0 || lo < 0) return NULL; + out[i] = (unsigned char)((hi << 4) | lo); + } + *out_len = blen; + return out; +} + +/* JSON error envelope reused across all PQ entry points. */ +static el_val_t pq_error(const char* msg) { + return http_error_json(msg); +} + +#if __has_include() +#include +#define EL_HAVE_LIBOQS 1 +#else +#define EL_HAVE_LIBOQS 0 +#endif + +#if EL_HAVE_LIBOQS && __has_include() +#include +#define EL_HAVE_OPENSSL 1 +#else +#define EL_HAVE_OPENSSL 0 +#endif + +#if !EL_HAVE_LIBOQS + +/* ─── Stubs (liboqs unavailable) ─────────────────────────────────────────── + * Each entry point returns the same JSON error so callers can inspect a + * single canonical "missing primitive" string. pq_verify is the lone + * exception — verifying without liboqs simply means "not verified", so + * returning Bool false (0) keeps the type contract intact. */ + +#define EL_PQ_NO_LIB "liboqs not linked, post-quantum primitives unavailable" + +el_val_t pq_keygen_signature(void) { return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_sign(el_val_t sk, el_val_t msg) { (void)sk; (void)msg; return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_verify(el_val_t pk, el_val_t msg, el_val_t sig) { (void)pk; (void)msg; (void)sig; return EL_INT(0); } +el_val_t pq_kem_keygen(void) { return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_kem_encaps(el_val_t pk) { (void)pk; return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_kem_decaps(el_val_t sk, el_val_t ct) { (void)sk; (void)ct; return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_hybrid_keygen(void) { return pq_error(EL_PQ_NO_LIB); } +el_val_t pq_hybrid_handshake(el_val_t pub) { (void)pub; return pq_error(EL_PQ_NO_LIB); } + +#else /* EL_HAVE_LIBOQS */ + +/* ─── Dilithium-3 / ML-DSA-65 signatures ──────────────────────────────── + * + * NIST FIPS 204 standardized CRYSTALS-Dilithium as ML-DSA. ML-DSA-65 is the + * FIPS form of what we historically called Dilithium-3 — same algorithm + * family, same security level, identical key/sig sizes, but with a couple + * of standardization-driven tweaks (e.g. domain separation in the message + * binding). liboqs 0.12+ exposes both names; 0.15+ retired the legacy + * "Dilithium" constants in favour of "ML-DSA". We prefer ML-DSA-65 if the + * header advertises it, fall back to Dilithium-3 otherwise. Anything + * already signed with the older constant remains verifiable against that + * same constant — callers should pin the algorithm via the OQS_SIG handle's + * method_name field if they need to interoperate with archival signatures. */ + +#if defined(OQS_SIG_alg_ml_dsa_65) +# define EL_DILITHIUM_ALG OQS_SIG_alg_ml_dsa_65 +#elif defined(OQS_SIG_alg_dilithium_3) +# define EL_DILITHIUM_ALG OQS_SIG_alg_dilithium_3 +#else +# define EL_DILITHIUM_ALG "ML-DSA-65" /* string fallback; runtime probe catches misconfig */ +#endif + +el_val_t pq_keygen_signature(void) { + OQS_SIG* sig = OQS_SIG_new(EL_DILITHIUM_ALG); + if (!sig) return pq_error("OQS_SIG_new(dilithium-3) failed"); + unsigned char* pk = (unsigned char*)malloc(sig->length_public_key); + unsigned char* sk = (unsigned char*)malloc(sig->length_secret_key); + if (!pk || !sk) { free(pk); free(sk); OQS_SIG_free(sig); return pq_error("oom"); } + if (OQS_SIG_keypair(sig, pk, sk) != OQS_SUCCESS) { + free(pk); free(sk); OQS_SIG_free(sig); + return pq_error("dilithium-3 keypair generation failed"); + } + el_val_t pk_hex = el_hex_encode(pk, sig->length_public_key); + el_val_t sk_hex = el_hex_encode(sk, sig->length_secret_key); + OQS_MEM_secure_free(sk, sig->length_secret_key); + free(pk); + + const char* pks = EL_CSTR(pk_hex); + const char* sks = EL_CSTR(sk_hex); + char* buf = el_strbuf(strlen(pks) + strlen(sks) + 64); + sprintf(buf, "{\"public_key\":\"%s\",\"secret_key\":\"%s\"}", pks, sks); + OQS_SIG_free(sig); + return el_wrap_str(buf); +} + +el_val_t pq_sign(el_val_t secret_key_hex, el_val_t message) { + size_t sk_len = 0; + unsigned char* sk = el_hex_decode(EL_CSTR(secret_key_hex), &sk_len); + if (!sk) return pq_error("invalid hex in secret_key"); + + OQS_SIG* sig = OQS_SIG_new(EL_DILITHIUM_ALG); + if (!sig) return pq_error("OQS_SIG_new(dilithium-3) failed"); + if (sk_len != sig->length_secret_key) { + OQS_SIG_free(sig); + return pq_error("secret_key length mismatch for dilithium-3"); + } + + const char* msg = EL_CSTR(message); + size_t msg_len = el_input_len(msg); + unsigned char* signature = (unsigned char*)malloc(sig->length_signature); + size_t signature_len = sig->length_signature; + if (!signature) { OQS_SIG_free(sig); return pq_error("oom"); } + + if (OQS_SIG_sign(sig, signature, &signature_len, + (const unsigned char*)(msg ? msg : ""), msg_len, sk) != OQS_SUCCESS) { + free(signature); OQS_SIG_free(sig); + return pq_error("dilithium-3 sign failed"); + } + el_val_t sig_hex = el_hex_encode(signature, signature_len); + free(signature); OQS_SIG_free(sig); + return sig_hex; +} + +el_val_t pq_verify(el_val_t public_key_hex, el_val_t message, el_val_t signature_hex) { + size_t pk_len = 0, sig_len = 0; + unsigned char* pk = el_hex_decode(EL_CSTR(public_key_hex), &pk_len); + unsigned char* signature = el_hex_decode(EL_CSTR(signature_hex), &sig_len); + if (!pk || !signature) return EL_INT(0); + + OQS_SIG* sig = OQS_SIG_new(EL_DILITHIUM_ALG); + if (!sig) return EL_INT(0); + if (pk_len != sig->length_public_key) { OQS_SIG_free(sig); return EL_INT(0); } + + const char* msg = EL_CSTR(message); + size_t msg_len = el_input_len(msg); + OQS_STATUS rc = OQS_SIG_verify(sig, + (const unsigned char*)(msg ? msg : ""), msg_len, + signature, sig_len, pk); + OQS_SIG_free(sig); + return (rc == OQS_SUCCESS) ? EL_INT(1) : EL_INT(0); +} + +/* ─── Kyber-768 / ML-KEM-768 KEM ──────────────────────────────────────── + * + * NIST FIPS 203 standardized CRYSTALS-Kyber as ML-KEM. ML-KEM-768 is the + * FIPS form of what we historically called Kyber-768. Same situation as + * Dilithium → ML-DSA: prefer the standardized constant, fall back to the + * legacy name. liboqs 0.15.0 still exposes OQS_KEM_alg_kyber_768; the + * algorithm is identical at the wire level to ML-KEM-768 except for FIPS + * domain-separation tweaks, so the two ciphertexts/keys are NOT + * cross-compatible. Pin the constant for archival material. */ + +#if defined(OQS_KEM_alg_ml_kem_768) +# define EL_KYBER_ALG OQS_KEM_alg_ml_kem_768 +#elif defined(OQS_KEM_alg_kyber_768) +# define EL_KYBER_ALG OQS_KEM_alg_kyber_768 +#else +# define EL_KYBER_ALG "ML-KEM-768" +#endif + +el_val_t pq_kem_keygen(void) { + OQS_KEM* kem = OQS_KEM_new(EL_KYBER_ALG); + if (!kem) return pq_error("OQS_KEM_new(kyber-768) failed"); + unsigned char* pk = (unsigned char*)malloc(kem->length_public_key); + unsigned char* sk = (unsigned char*)malloc(kem->length_secret_key); + if (!pk || !sk) { free(pk); free(sk); OQS_KEM_free(kem); return pq_error("oom"); } + if (OQS_KEM_keypair(kem, pk, sk) != OQS_SUCCESS) { + free(pk); free(sk); OQS_KEM_free(kem); + return pq_error("kyber-768 keypair generation failed"); + } + el_val_t pk_hex = el_hex_encode(pk, kem->length_public_key); + el_val_t sk_hex = el_hex_encode(sk, kem->length_secret_key); + OQS_MEM_secure_free(sk, kem->length_secret_key); + free(pk); + + const char* pks = EL_CSTR(pk_hex); + const char* sks = EL_CSTR(sk_hex); + char* buf = el_strbuf(strlen(pks) + strlen(sks) + 64); + sprintf(buf, "{\"public_key\":\"%s\",\"secret_key\":\"%s\"}", pks, sks); + OQS_KEM_free(kem); + return el_wrap_str(buf); +} + +el_val_t pq_kem_encaps(el_val_t public_key_hex) { + size_t pk_len = 0; + unsigned char* pk = el_hex_decode(EL_CSTR(public_key_hex), &pk_len); + if (!pk) return pq_error("invalid hex in public_key"); + + OQS_KEM* kem = OQS_KEM_new(EL_KYBER_ALG); + if (!kem) return pq_error("OQS_KEM_new(kyber-768) failed"); + if (pk_len != kem->length_public_key) { + OQS_KEM_free(kem); + return pq_error("public_key length mismatch for kyber-768"); + } + unsigned char* ct = (unsigned char*)malloc(kem->length_ciphertext); + unsigned char* ss = (unsigned char*)malloc(kem->length_shared_secret); + if (!ct || !ss) { free(ct); free(ss); OQS_KEM_free(kem); return pq_error("oom"); } + if (OQS_KEM_encaps(kem, ct, ss, pk) != OQS_SUCCESS) { + free(ct); free(ss); OQS_KEM_free(kem); + return pq_error("kyber-768 encapsulation failed"); + } + el_val_t ct_hex = el_hex_encode(ct, kem->length_ciphertext); + el_val_t ss_hex = el_hex_encode(ss, kem->length_shared_secret); + free(ct); + OQS_MEM_secure_free(ss, kem->length_shared_secret); + + const char* cts = EL_CSTR(ct_hex); + const char* sss = EL_CSTR(ss_hex); + char* buf = el_strbuf(strlen(cts) + strlen(sss) + 64); + sprintf(buf, "{\"ciphertext\":\"%s\",\"shared_secret\":\"%s\"}", cts, sss); + OQS_KEM_free(kem); + return el_wrap_str(buf); +} + +el_val_t pq_kem_decaps(el_val_t secret_key_hex, el_val_t ciphertext_hex) { + size_t sk_len = 0, ct_len = 0; + unsigned char* sk = el_hex_decode(EL_CSTR(secret_key_hex), &sk_len); + unsigned char* ct = el_hex_decode(EL_CSTR(ciphertext_hex), &ct_len); + if (!sk || !ct) return pq_error("invalid hex in inputs"); + + OQS_KEM* kem = OQS_KEM_new(EL_KYBER_ALG); + if (!kem) return pq_error("OQS_KEM_new(kyber-768) failed"); + if (sk_len != kem->length_secret_key || ct_len != kem->length_ciphertext) { + OQS_KEM_free(kem); + return pq_error("input length mismatch for kyber-768"); + } + unsigned char* ss = (unsigned char*)malloc(kem->length_shared_secret); + if (!ss) { OQS_KEM_free(kem); return pq_error("oom"); } + /* Kyber is IND-CCA via Fujisaki-Okamoto: decaps always returns *some* + * shared_secret even on tampered ciphertext (an implicit-rejection value + * derived from sk). Protocols MUST confirm the shared_secret matches via + * a subsequent step (e.g. AEAD tag, key-confirmation MAC) — do not + * assume decaps success implies authenticity. */ + if (OQS_KEM_decaps(kem, ss, ct, sk) != OQS_SUCCESS) { + free(ss); OQS_KEM_free(kem); + return pq_error("kyber-768 decapsulation failed"); + } + el_val_t ss_hex = el_hex_encode(ss, kem->length_shared_secret); + OQS_MEM_secure_free(ss, kem->length_shared_secret); + OQS_KEM_free(kem); + return ss_hex; +} + +/* ─── Hybrid handshake (X25519 + Kyber-768, HKDF-SHA256 combined) ─────── */ + +#if !EL_HAVE_OPENSSL + +el_val_t pq_hybrid_keygen(void) { + return pq_error("hybrid handshake requires OpenSSL (X25519); rebuild with -lcrypto"); +} +el_val_t pq_hybrid_handshake(el_val_t pub) { + (void)pub; + return pq_error("hybrid handshake requires OpenSSL (X25519); rebuild with -lcrypto"); +} + +#else /* EL_HAVE_OPENSSL */ + +/* HKDF-SHA256 (RFC 5869) — Extract+Expand. Reuses the inline HMAC-SHA256 + * already in this file. Empty salt → 32 zero bytes per the RFC. */ +static void el_hkdf_sha256(const unsigned char* salt, size_t salt_len, + const unsigned char* ikm, size_t ikm_len, + const unsigned char* info, size_t info_len, + unsigned char* out, size_t out_len) { + unsigned char zero_salt[32] = {0}; + if (salt_len == 0) { salt = zero_salt; salt_len = 32; } + unsigned char prk[32]; + el_hmac_sha256(salt, salt_len, ikm, ikm_len, prk); + + unsigned char t[32]; + size_t produced = 0; + unsigned char counter = 1; + unsigned char* buf = (unsigned char*)malloc(32 + info_len + 1); + if (!buf) { fputs("el_runtime: hkdf oom\n", stderr); return; } + while (produced < out_len) { + size_t off = 0; + if (counter > 1) { memcpy(buf, t, 32); off = 32; } + if (info && info_len) { memcpy(buf + off, info, info_len); off += info_len; } + buf[off++] = counter; + el_hmac_sha256(prk, 32, buf, off, t); + size_t chunk = (out_len - produced > 32) ? 32 : (out_len - produced); + memcpy(out + produced, t, chunk); + produced += chunk; + counter++; + } + free(buf); +} + +/* X25519 keygen via OpenSSL EVP. Returns 1 on success. + * Fills pk[32] and sk[32] (raw X25519 byte strings, no DER wrapper). */ +static int el_x25519_keygen(unsigned char pk[32], unsigned char sk[32]) { + EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL); + if (!pctx) return 0; + if (EVP_PKEY_keygen_init(pctx) != 1) { EVP_PKEY_CTX_free(pctx); return 0; } + EVP_PKEY* key = NULL; + if (EVP_PKEY_keygen(pctx, &key) != 1) { EVP_PKEY_CTX_free(pctx); return 0; } + EVP_PKEY_CTX_free(pctx); + + size_t plen = 32, slen = 32; + if (EVP_PKEY_get_raw_public_key (key, pk, &plen) != 1 || plen != 32) { + EVP_PKEY_free(key); return 0; + } + if (EVP_PKEY_get_raw_private_key(key, sk, &slen) != 1 || slen != 32) { + EVP_PKEY_free(key); return 0; + } + EVP_PKEY_free(key); + return 1; +} + +/* X25519 ECDH: derive 32-byte shared secret from local sk and remote pk. */ +static int el_x25519_derive(const unsigned char sk[32], const unsigned char rpk[32], + unsigned char ss[32]) { + EVP_PKEY* my = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, sk, 32); + EVP_PKEY* rem = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, NULL, rpk, 32); + if (!my || !rem) { EVP_PKEY_free(my); EVP_PKEY_free(rem); return 0; } + EVP_PKEY_CTX* dctx = EVP_PKEY_CTX_new(my, NULL); + if (!dctx) { EVP_PKEY_free(my); EVP_PKEY_free(rem); return 0; } + int ok = 0; + size_t out_len = 32; + if (EVP_PKEY_derive_init(dctx) == 1 && + EVP_PKEY_derive_set_peer(dctx, rem) == 1 && + EVP_PKEY_derive(dctx, ss, &out_len) == 1 && + out_len == 32) ok = 1; + EVP_PKEY_CTX_free(dctx); + EVP_PKEY_free(my); + EVP_PKEY_free(rem); + return ok; +} + +/* Hybrid wire layout (binary form, before hex encode): + * public_key = x25519_pub (32) || kyber_pub (1184) → 1216 bytes + * secret_key = x25519_sec (32) || kyber_sec (2400) → 2432 bytes + * ciphertext = ephem_x25519_pub (32) || kyber_ct (1088) → 1120 bytes + * shared_secret = HKDF-SHA256(x25519_ss || kyber_ss, info="el-pq-hybrid-v1", 32 bytes) + * The keygen result also exposes the four component hex fields for callers + * that prefer to handle the legs independently. */ + +el_val_t pq_hybrid_keygen(void) { + OQS_KEM* kem = OQS_KEM_new(EL_KYBER_ALG); + if (!kem) return pq_error("OQS_KEM_new(kyber-768) failed"); + + unsigned char xpk[32], xsk[32]; + if (!el_x25519_keygen(xpk, xsk)) { + OQS_KEM_free(kem); + return pq_error("X25519 keygen failed"); + } + + unsigned char* kpk = (unsigned char*)malloc(kem->length_public_key); + unsigned char* ksk = (unsigned char*)malloc(kem->length_secret_key); + if (!kpk || !ksk) { free(kpk); free(ksk); OQS_KEM_free(kem); return pq_error("oom"); } + if (OQS_KEM_keypair(kem, kpk, ksk) != OQS_SUCCESS) { + free(kpk); free(ksk); OQS_KEM_free(kem); + return pq_error("kyber-768 keypair generation failed"); + } + + size_t pub_len = 32 + kem->length_public_key; + size_t sec_len = 32 + kem->length_secret_key; + unsigned char* pub_buf = (unsigned char*)malloc(pub_len); + unsigned char* sec_buf = (unsigned char*)malloc(sec_len); + if (!pub_buf || !sec_buf) { + free(pub_buf); free(sec_buf); free(kpk); + OQS_MEM_secure_free(ksk, kem->length_secret_key); + OQS_KEM_free(kem); return pq_error("oom"); + } + memcpy(pub_buf, xpk, 32); memcpy(pub_buf + 32, kpk, kem->length_public_key); + memcpy(sec_buf, xsk, 32); memcpy(sec_buf + 32, ksk, kem->length_secret_key); + + el_val_t x_pub_hex = el_hex_encode(xpk, 32); + el_val_t x_sec_hex = el_hex_encode(xsk, 32); + el_val_t k_pub_hex = el_hex_encode(kpk, kem->length_public_key); + el_val_t k_sec_hex = el_hex_encode(ksk, kem->length_secret_key); + el_val_t pub_hex = el_hex_encode(pub_buf, pub_len); + el_val_t sec_hex = el_hex_encode(sec_buf, sec_len); + + OQS_MEM_secure_free(ksk, kem->length_secret_key); + free(kpk); free(pub_buf); free(sec_buf); + OQS_KEM_free(kem); + memset(xsk, 0, 32); /* best-effort wipe of stack copy */ + + const char* xph = EL_CSTR(x_pub_hex); + const char* xsh = EL_CSTR(x_sec_hex); + const char* kph = EL_CSTR(k_pub_hex); + const char* ksh = EL_CSTR(k_sec_hex); + const char* pubh = EL_CSTR(pub_hex); + const char* sech = EL_CSTR(sec_hex); + + char* buf = el_strbuf(strlen(xph) + strlen(xsh) + strlen(kph) + strlen(ksh) + + strlen(pubh) + strlen(sech) + 256); + sprintf(buf, + "{\"x25519_pub\":\"%s\",\"x25519_sec\":\"%s\"," + "\"kyber_pub\":\"%s\",\"kyber_sec\":\"%s\"," + "\"public_key\":\"%s\",\"secret_key\":\"%s\"}", + xph, xsh, kph, ksh, pubh, sech); + return el_wrap_str(buf); +} + +/* Initiator-side handshake. Caller supplies the responder's combined public + * key (x25519_pub || kyber_pub, hex-encoded). The runtime: + * 1. Generates an ephemeral X25519 keypair, runs ECDH against the + * responder's static x25519_pub. + * 2. Runs Kyber-768 encaps against the responder's kyber_pub → kyber_ct, + * kyber_ss. + * 3. Combined shared = HKDF-SHA256(salt="", ikm = x25519_ss || kyber_ss, + * info = "el-pq-hybrid-v1", L = 32). + * 4. Returns combined ciphertext (= ephemeral_x25519_pub || kyber_ct) and + * the derived shared_secret. + * + * Responder side composition (intentionally not a separate runtime fn — + * trivial to express in El given pq_kem_decaps + a future x25519_derive + * primitive): split the ciphertext into ephem_xpk (32) and kyber_ct, run + * X25519(static_xsk, ephem_xpk) and pq_kem_decaps(static_kyber_sk, kyber_ct), + * then HKDF-SHA256 with the same salt/info to recover the same shared_secret. + * If a separate x25519 entry point becomes valuable, add `pq_hybrid_open` + * here taking (secret_key_combined, ciphertext_combined). */ +el_val_t pq_hybrid_handshake(el_val_t remote_pub_combined) { + size_t pub_len = 0; + unsigned char* rpub = el_hex_decode(EL_CSTR(remote_pub_combined), &pub_len); + if (!rpub) return pq_error("invalid hex in remote_pub_combined"); + + OQS_KEM* kem = OQS_KEM_new(EL_KYBER_ALG); + if (!kem) return pq_error("OQS_KEM_new(kyber-768) failed"); + if (pub_len != 32 + kem->length_public_key) { + OQS_KEM_free(kem); + return pq_error("remote_pub_combined length mismatch (expected x25519_pub || kyber_pub)"); + } + + unsigned char e_xpk[32], e_xsk[32], x_ss[32]; + if (!el_x25519_keygen(e_xpk, e_xsk)) { + OQS_KEM_free(kem); + return pq_error("X25519 ephemeral keygen failed"); + } + if (!el_x25519_derive(e_xsk, rpub, x_ss)) { + memset(e_xsk, 0, 32); + OQS_KEM_free(kem); + return pq_error("X25519 derive failed"); + } + memset(e_xsk, 0, 32); /* ephemeral; not needed after derive */ + + unsigned char* k_ct = (unsigned char*)malloc(kem->length_ciphertext); + unsigned char* k_ss = (unsigned char*)malloc(kem->length_shared_secret); + if (!k_ct || !k_ss) { + free(k_ct); free(k_ss); OQS_KEM_free(kem); + return pq_error("oom"); + } + if (OQS_KEM_encaps(kem, k_ct, k_ss, rpub + 32) != OQS_SUCCESS) { + free(k_ct); free(k_ss); OQS_KEM_free(kem); + return pq_error("kyber-768 encapsulation failed"); + } + + /* HKDF combine: ikm = x_ss || k_ss. */ + size_t ikm_len = 32 + kem->length_shared_secret; + unsigned char* ikm = (unsigned char*)malloc(ikm_len); + if (!ikm) { + free(k_ct); OQS_MEM_secure_free(k_ss, kem->length_shared_secret); + OQS_KEM_free(kem); + return pq_error("oom"); + } + memcpy(ikm, x_ss, 32); + memcpy(ikm + 32, k_ss, kem->length_shared_secret); + unsigned char combined[32]; + static const char info_str[] = "el-pq-hybrid-v1"; + el_hkdf_sha256(NULL, 0, ikm, ikm_len, + (const unsigned char*)info_str, sizeof(info_str) - 1, + combined, 32); + + memset(x_ss, 0, 32); + OQS_MEM_secure_free(k_ss, kem->length_shared_secret); + OQS_MEM_secure_free(ikm, ikm_len); + + /* Combined ciphertext = ephemeral_x25519_pub || kyber_ct. */ + size_t ct_len = 32 + kem->length_ciphertext; + unsigned char* combined_ct = (unsigned char*)malloc(ct_len); + if (!combined_ct) { free(k_ct); OQS_KEM_free(kem); return pq_error("oom"); } + memcpy(combined_ct, e_xpk, 32); + memcpy(combined_ct + 32, k_ct, kem->length_ciphertext); + free(k_ct); + OQS_KEM_free(kem); + + el_val_t ct_hex = el_hex_encode(combined_ct, ct_len); + el_val_t ss_hex = el_hex_encode(combined, 32); + free(combined_ct); + memset(combined, 0, 32); + + const char* cts = EL_CSTR(ct_hex); + const char* sss = EL_CSTR(ss_hex); + char* buf = el_strbuf(strlen(cts) + strlen(sss) + 64); + sprintf(buf, "{\"ciphertext\":\"%s\",\"shared_secret\":\"%s\"}", cts, sss); + return el_wrap_str(buf); +} + +#endif /* EL_HAVE_OPENSSL */ +#endif /* EL_HAVE_LIBOQS */ + +/* ─── AEAD: AES-256-GCM ──────────────────────────────────────────────────── + * + * Symmetric authenticated encryption used to wrap envelopes once a shared + * secret has been derived from the KEM (Kyber-768 / hybrid). The El surface + * is intentionally narrow: + * + * aead_encrypt(key_hex, plaintext) + * → {"nonce":"<24 hex>","ciphertext":"<...hex including 16-byte tag>"} + * + * aead_decrypt(key_hex, nonce_hex, ciphertext_hex) + * → plaintext String, or "" on auth failure / malformed input + * + * Conventions: + * - key_hex must decode to exactly 32 bytes (AES-256). Callers that hold + * a longer KEM shared_secret should normalize via SHA3-256(ss) → 32 bytes + * before passing it in. (Kyber-768's shared_secret is already 32 bytes, + * but keeping this contract explicit lets the El side be agnostic.) + * - nonce is a fresh 12-byte random value drawn from the OS CSPRNG. Caller + * never picks the nonce — eliminates the GCM nonce-reuse footgun entirely. + * - tag is the standard 16 bytes, appended to ciphertext per RFC 5116. + * `ciphertext` field is therefore (plaintext_len + 16) bytes, hex-encoded. + * - No associated data (AAD). If we later need bound metadata, add a + * length-prefixed AAD argument and bump the envelope version tag. + * + * Failure mode: + * aead_encrypt returns http_error_json(...) on input/system failure. + * aead_decrypt returns the empty string on ANY failure (including auth-tag + * mismatch). Callers MUST check for "" before using the result. */ + +#if !__has_include() + +el_val_t aead_encrypt(el_val_t key_hex, el_val_t plaintext) { + (void)key_hex; (void)plaintext; + return http_error_json("aead_encrypt requires OpenSSL (libcrypto); rebuild with -lcrypto"); +} +el_val_t aead_decrypt(el_val_t key_hex, el_val_t nonce_hex, el_val_t ciphertext_hex) { + (void)key_hex; (void)nonce_hex; (void)ciphertext_hex; + return el_wrap_str(el_strdup("")); +} + +#else /* OpenSSL available */ + +#include +#include + +el_val_t aead_encrypt(el_val_t key_hex, el_val_t plaintext) { + size_t key_len = 0; + unsigned char* key = el_hex_decode(EL_CSTR(key_hex), &key_len); + if (!key) return http_error_json("invalid hex in key"); + if (key_len != 32) return http_error_json("aead key must be 32 bytes (64 hex chars) for AES-256-GCM"); + + const char* pt = EL_CSTR(plaintext); + size_t pt_len = el_input_len(pt); + if (!pt) pt = ""; + + unsigned char nonce[12]; + if (RAND_bytes(nonce, 12) != 1) return http_error_json("OS CSPRNG failed (RAND_bytes)"); + + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + if (!ctx) return http_error_json("EVP_CIPHER_CTX_new failed"); + + if (EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) != 1) { + EVP_CIPHER_CTX_free(ctx); return http_error_json("aes-256-gcm init failed"); + } + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL) != 1) { + EVP_CIPHER_CTX_free(ctx); return http_error_json("set ivlen failed"); + } + if (EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce) != 1) { + EVP_CIPHER_CTX_free(ctx); return http_error_json("aes-256-gcm key/iv init failed"); + } + + /* GCM ciphertext is the same length as plaintext; we append a 16-byte + * authentication tag for AEAD semantics. Allocate plaintext_len + 16. */ + unsigned char* ct = (unsigned char*)malloc(pt_len + 16); + if (!ct) { EVP_CIPHER_CTX_free(ctx); return http_error_json("oom"); } + int outlen = 0, total = 0; + if (EVP_EncryptUpdate(ctx, ct, &outlen, (const unsigned char*)pt, (int)pt_len) != 1) { + free(ct); EVP_CIPHER_CTX_free(ctx); return http_error_json("aes-256-gcm update failed"); + } + total += outlen; + if (EVP_EncryptFinal_ex(ctx, ct + total, &outlen) != 1) { + free(ct); EVP_CIPHER_CTX_free(ctx); return http_error_json("aes-256-gcm final failed"); + } + total += outlen; + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, ct + total) != 1) { + free(ct); EVP_CIPHER_CTX_free(ctx); return http_error_json("aes-256-gcm get tag failed"); + } + EVP_CIPHER_CTX_free(ctx); + + el_val_t nonce_hex_v = el_hex_encode(nonce, 12); + el_val_t ct_hex_v = el_hex_encode(ct, (size_t)total + 16); + free(ct); + + const char* nh = EL_CSTR(nonce_hex_v); + const char* ch = EL_CSTR(ct_hex_v); + char* buf = el_strbuf(strlen(nh) + strlen(ch) + 48); + sprintf(buf, "{\"nonce\":\"%s\",\"ciphertext\":\"%s\"}", nh, ch); + return el_wrap_str(buf); +} + +el_val_t aead_decrypt(el_val_t key_hex, el_val_t nonce_hex, el_val_t ciphertext_hex) { + size_t key_len = 0, nonce_len = 0, ct_len = 0; + unsigned char* key = el_hex_decode(EL_CSTR(key_hex), &key_len); + unsigned char* nonce = el_hex_decode(EL_CSTR(nonce_hex), &nonce_len); + unsigned char* ct = el_hex_decode(EL_CSTR(ciphertext_hex), &ct_len); + if (!key || !nonce || !ct) return el_wrap_str(el_strdup("")); + if (key_len != 32 || nonce_len != 12) return el_wrap_str(el_strdup("")); + if (ct_len < 16) return el_wrap_str(el_strdup("")); + + size_t body_len = ct_len - 16; + const unsigned char* tag = ct + body_len; + + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + if (!ctx) return el_wrap_str(el_strdup("")); + + if (EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) != 1 || + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL) != 1 || + EVP_DecryptInit_ex(ctx, NULL, NULL, key, nonce) != 1) { + EVP_CIPHER_CTX_free(ctx); return el_wrap_str(el_strdup("")); + } + + unsigned char* pt = (unsigned char*)malloc(body_len + 1); + if (!pt) { EVP_CIPHER_CTX_free(ctx); return el_wrap_str(el_strdup("")); } + int outlen = 0, total = 0; + if (EVP_DecryptUpdate(ctx, pt, &outlen, ct, (int)body_len) != 1) { + free(pt); EVP_CIPHER_CTX_free(ctx); return el_wrap_str(el_strdup("")); + } + total += outlen; + /* Set expected tag before final — GCM's final step is where auth happens. */ + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, (void*)tag) != 1) { + free(pt); EVP_CIPHER_CTX_free(ctx); return el_wrap_str(el_strdup("")); + } + int rc = EVP_DecryptFinal_ex(ctx, pt + total, &outlen); + EVP_CIPHER_CTX_free(ctx); + if (rc != 1) { + /* Auth failure or padding/length mismatch. Return empty so callers + * cannot accidentally treat tampered ciphertext as a valid message. */ + free(pt); + return el_wrap_str(el_strdup("")); + } + total += outlen; + pt[total] = '\0'; + + /* Copy into the el arena so the caller-visible string outlives this fn. */ + char* out = el_strbuf((size_t)total); + memcpy(out, pt, (size_t)total); + out[total] = '\0'; + free(pt); + return el_wrap_str(out); +} + +#endif /* __has_include() */ + +#ifdef HAVE_CURL +/* ──────────────────────────────────────────────────────────────────────────── + * OTLP/HTTP observability — logs, traces, metrics + * + * Design goals: + * - Zero blocking on the request path. Producers append to in-memory + * ring buffers; a single worker thread flushes to the OTLP endpoint. + * - Drop-on-failure semantics. If the endpoint is unreachable or slow, + * we drop telemetry rather than back-pressure into the request handler. + * - Best-effort serialization. Each record is pre-serialized as JSON when + * the El program calls the primitive; the worker just batches. + * - Configuration via env vars: + * OTLP_ENDPOINT e.g. https://alloy.neuralplatform.ai:4318 + * OTEL_SERVICE_NAME e.g. neuron-web (default: argv[0] basename) + * OTEL_SERVICE_VERSION (default: "0.0.0") + * OTEL_RESOURCE_ATTRS comma-sep k=v pairs (optional) + * + * Wire format: OTLP/HTTP JSON. Three endpoints: + * POST {endpoint}/v1/logs — log records + * POST {endpoint}/v1/traces — spans + * POST {endpoint}/v1/metrics — counter/gauge points + * + * El programs see four primitives: + * trace_span_start(name) -> SpanHandle (just a string id) + * trace_span_end(handle) (computes duration, queues) + * emit_log(level, msg, fields_json) (queues a log record) + * emit_metric(name, value, tags_json) (queues a counter increment) + * ──────────────────────────────────────────────────────────────────────────── + */ + +#define OTLP_BUF_CAP 4096 /* per-buffer ring size */ +#define OTLP_FLUSH_MS 2000 /* flush every 2s */ +#define OTLP_BATCH_MAX 200 /* up to 200 records per POST */ + +typedef struct { + char* data; /* malloc'd JSON fragment for this record */ +} OtlpRec; + +typedef struct { + OtlpRec ring[OTLP_BUF_CAP]; + size_t head; /* next write slot */ + size_t tail; /* next read slot */ + pthread_mutex_t mu; +} OtlpQueue; + +static OtlpQueue _otlp_logs = { .mu = PTHREAD_MUTEX_INITIALIZER }; +static OtlpQueue _otlp_traces = { .mu = PTHREAD_MUTEX_INITIALIZER }; +static OtlpQueue _otlp_metrics = { .mu = PTHREAD_MUTEX_INITIALIZER }; + +static char* _otlp_endpoint = NULL; /* e.g. https://alloy.neuralplatform.ai:4318 */ +static char* _otlp_service_name = NULL; +static char* _otlp_service_version = NULL; +static int _otlp_initialized = 0; +static pthread_t _otlp_worker_thread; + +/* enqueue — returns 1 if accepted, 0 if dropped (full buffer or no endpoint) */ +static int otlp_enqueue(OtlpQueue* q, const char* json) { + if (!_otlp_endpoint || !json) return 0; + pthread_mutex_lock(&q->mu); + size_t next_head = (q->head + 1) % OTLP_BUF_CAP; + if (next_head == q->tail) { + /* buffer full — drop oldest */ + free(q->ring[q->tail].data); + q->ring[q->tail].data = NULL; + q->tail = (q->tail + 1) % OTLP_BUF_CAP; + } + q->ring[q->head].data = strdup(json); + q->head = next_head; + pthread_mutex_unlock(&q->mu); + return 1; +} + +/* drain — copies up to OTLP_BATCH_MAX items into a comma-joined string, + * caller must free the result. Returns NULL if queue is empty. */ +static char* otlp_drain(OtlpQueue* q) { + pthread_mutex_lock(&q->mu); + if (q->head == q->tail) { pthread_mutex_unlock(&q->mu); return NULL; } + /* compute total length */ + size_t total = 0, count = 0; + size_t i = q->tail; + while (i != q->head && count < OTLP_BATCH_MAX) { + if (q->ring[i].data) total += strlen(q->ring[i].data) + 1; /* +1 for comma */ + i = (i + 1) % OTLP_BUF_CAP; + count++; + } + char* out = malloc(total + 4); + if (!out) { pthread_mutex_unlock(&q->mu); return NULL; } + out[0] = '\0'; + size_t off = 0; + i = q->tail; + count = 0; + while (i != q->head && count < OTLP_BATCH_MAX) { + if (q->ring[i].data) { + size_t l = strlen(q->ring[i].data); + if (off > 0) { out[off++] = ','; } + memcpy(out + off, q->ring[i].data, l); + off += l; + free(q->ring[i].data); + q->ring[i].data = NULL; + } + i = (i + 1) % OTLP_BUF_CAP; + count++; + } + out[off] = '\0'; + q->tail = i; + pthread_mutex_unlock(&q->mu); + return out; +} + +/* Build resource block once (service.name, service.version, host.name) */ +static char* otlp_resource_block(void) { + static char cached[1024]; + static int built = 0; + if (built) return cached; + char host[256] = "unknown"; + gethostname(host, sizeof(host) - 1); + snprintf(cached, sizeof(cached), + "{\"attributes\":[" + "{\"key\":\"service.name\",\"value\":{\"stringValue\":\"%s\"}}," + "{\"key\":\"service.version\",\"value\":{\"stringValue\":\"%s\"}}," + "{\"key\":\"host.name\",\"value\":{\"stringValue\":\"%s\"}}" + "]}", + _otlp_service_name ? _otlp_service_name : "el-app", + _otlp_service_version ? _otlp_service_version : "0.0.0", + host); + built = 1; + return cached; +} + +/* Best-effort POST. Drops on any error. */ +static void otlp_post(const char* path, const char* body) { + if (!_otlp_endpoint || !body || !*body) return; + char url[1024]; + snprintf(url, sizeof(url), "%s%s", _otlp_endpoint, path); + CURL* c = curl_easy_init(); + if (!c) return; + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, body); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)strlen(body)); + curl_easy_setopt(c, CURLOPT_HTTPHEADER, h); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, 3000L); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, NULL); /* discard response */ + curl_easy_perform(c); + curl_slist_free_all(h); + curl_easy_cleanup(c); +} + +/* Flush worker — runs forever until process exits */ +static void* otlp_worker(void* arg) { + (void)arg; + while (1) { + struct timespec ts = { OTLP_FLUSH_MS / 1000, (OTLP_FLUSH_MS % 1000) * 1000000L }; + nanosleep(&ts, NULL); + + char* logs = otlp_drain(&_otlp_logs); + if (logs && *logs) { + char body[OTLP_BUF_CAP * 8]; + int n = snprintf(body, sizeof(body), + "{\"resourceLogs\":[{\"resource\":%s," + "\"scopeLogs\":[{\"scope\":{\"name\":\"el-runtime\"}," + "\"logRecords\":[%s]}]}]}", + otlp_resource_block(), logs); + if (n > 0 && n < (int)sizeof(body)) otlp_post("/v1/logs", body); + } + free(logs); + + char* traces = otlp_drain(&_otlp_traces); + if (traces && *traces) { + char body[OTLP_BUF_CAP * 8]; + int n = snprintf(body, sizeof(body), + "{\"resourceSpans\":[{\"resource\":%s," + "\"scopeSpans\":[{\"scope\":{\"name\":\"el-runtime\"}," + "\"spans\":[%s]}]}]}", + otlp_resource_block(), traces); + if (n > 0 && n < (int)sizeof(body)) otlp_post("/v1/traces", body); + } + free(traces); + + char* metrics = otlp_drain(&_otlp_metrics); + if (metrics && *metrics) { + char body[OTLP_BUF_CAP * 8]; + int n = snprintf(body, sizeof(body), + "{\"resourceMetrics\":[{\"resource\":%s," + "\"scopeMetrics\":[{\"scope\":{\"name\":\"el-runtime\"}," + "\"metrics\":[%s]}]}]}", + otlp_resource_block(), metrics); + if (n > 0 && n < (int)sizeof(body)) otlp_post("/v1/metrics", body); + } + free(metrics); + } + return NULL; +} + +/* Initialize OTLP — called lazily on first emit. Idempotent. */ +static void otlp_lazy_init(void) { + if (_otlp_initialized) return; + static pthread_mutex_t once_mu = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock(&once_mu); + if (_otlp_initialized) { pthread_mutex_unlock(&once_mu); return; } + + const char* ep = getenv("OTLP_ENDPOINT"); + if (!ep || !*ep) { + _otlp_initialized = 1; + pthread_mutex_unlock(&once_mu); + return; + } + _otlp_endpoint = strdup(ep); + /* trim trailing slash */ + size_t l = strlen(_otlp_endpoint); + if (l > 0 && _otlp_endpoint[l - 1] == '/') _otlp_endpoint[l - 1] = '\0'; + + const char* svc = getenv("OTEL_SERVICE_NAME"); + _otlp_service_name = strdup(svc && *svc ? svc : "el-app"); + const char* ver = getenv("OTEL_SERVICE_VERSION"); + _otlp_service_version = strdup(ver && *ver ? ver : "0.0.0"); + + pthread_create(&_otlp_worker_thread, NULL, otlp_worker, NULL); + pthread_detach(_otlp_worker_thread); + _otlp_initialized = 1; + pthread_mutex_unlock(&once_mu); +} + +/* JSON-escape a string into out_buf. Returns chars written (excluding null). */ +static size_t otlp_json_escape(const char* in, char* out, size_t out_cap) { + size_t o = 0; + for (size_t i = 0; in[i] && o + 8 < out_cap; i++) { + unsigned char c = (unsigned char)in[i]; + if (c == '"') { out[o++] = '\\'; out[o++] = '"'; } + else if (c == '\\'){ out[o++] = '\\'; out[o++] = '\\'; } + else if (c == '\n'){ out[o++] = '\\'; out[o++] = 'n'; } + else if (c == '\r'){ out[o++] = '\\'; out[o++] = 'r'; } + else if (c == '\t'){ out[o++] = '\\'; out[o++] = 't'; } + else if (c < 0x20) { o += snprintf(out + o, out_cap - o, "\\u%04x", c); } + else { out[o++] = (char)c; } + } + out[o] = '\0'; + return o; +} + +/* ── Public El primitives ─────────────────────────────────────────────────── */ + +/* emit_log(level, msg, fields_json) — fields_json is a JSON object string or "" */ +el_val_t emit_log(el_val_t level_v, el_val_t msg_v, el_val_t fields_v) { + otlp_lazy_init(); + if (!_otlp_endpoint) return EL_INT(0); + const char* level = EL_CSTR(level_v); if (!level) level = "INFO"; + const char* msg = EL_CSTR(msg_v); if (!msg) msg = ""; + const char* fields = EL_CSTR(fields_v); if (!fields) fields = ""; + /* Map El level names to OTLP severity numbers */ + int sev_num = 9; /* INFO */ + if (strcmp(level, "TRACE") == 0) sev_num = 1; + else if (strcmp(level, "DEBUG") == 0) sev_num = 5; + else if (strcmp(level, "INFO") == 0) sev_num = 9; + else if (strcmp(level, "WARN") == 0 || strcmp(level, "WARNING") == 0) sev_num = 13; + else if (strcmp(level, "ERROR") == 0) sev_num = 17; + else if (strcmp(level, "FATAL") == 0) sev_num = 21; + char esc_msg[2048]; otlp_json_escape(msg, esc_msg, sizeof(esc_msg)); + /* unix nanos */ + struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); + long long now_nano = (long long)ts.tv_sec * 1000000000LL + ts.tv_nsec; + char rec[4096]; + int n = snprintf(rec, sizeof(rec), + "{\"timeUnixNano\":\"%lld\",\"severityNumber\":%d," + "\"severityText\":\"%s\"," + "\"body\":{\"stringValue\":\"%s\"}%s%s}", + now_nano, sev_num, level, esc_msg, + (fields && *fields) ? ",\"attributes\":" : "", + (fields && *fields) ? fields : ""); + if (n > 0 && n < (int)sizeof(rec)) otlp_enqueue(&_otlp_logs, rec); + return EL_INT(1); +} + +/* emit_metric(name, value, tags_json) — Sum (counter) data point. tags_json + * is a JSON array of {key, value} pairs or empty string. */ +el_val_t emit_metric(el_val_t name_v, el_val_t value_v, el_val_t tags_v) { + otlp_lazy_init(); + if (!_otlp_endpoint) return EL_INT(0); + const char* name = EL_CSTR(name_v); if (!name) name = "unknown"; + int64_t val = (int64_t)value_v; + const char* tags = EL_CSTR(tags_v); if (!tags) tags = ""; + char esc_name[256]; otlp_json_escape(name, esc_name, sizeof(esc_name)); + struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); + long long now_nano = (long long)ts.tv_sec * 1000000000LL + ts.tv_nsec; + char rec[4096]; + int n = snprintf(rec, sizeof(rec), + "{\"name\":\"%s\",\"sum\":{\"aggregationTemporality\":2,\"isMonotonic\":true," + "\"dataPoints\":[{\"asInt\":\"%lld\"," + "\"timeUnixNano\":\"%lld\"" + "%s%s}]}}", + esc_name, (long long)val, now_nano, + (tags && *tags) ? ",\"attributes\":" : "", + (tags && *tags) ? tags : ""); + if (n > 0 && n < (int)sizeof(rec)) otlp_enqueue(&_otlp_metrics, rec); + return EL_INT(1); +} + +/* trace_span_start(name) — returns a span handle (string of "traceid:spanid:start_nano:name") */ +el_val_t trace_span_start(el_val_t name_v) { + otlp_lazy_init(); + const char* name = EL_CSTR(name_v); if (!name) name = "span"; + /* generate 16-byte trace id and 8-byte span id */ + static _Thread_local int seeded = 0; + if (!seeded) { srand((unsigned int)(uintptr_t)pthread_self() ^ (unsigned int)time(NULL)); seeded = 1; } + char tid[33], sid[17]; + for (int i = 0; i < 32; i++) tid[i] = "0123456789abcdef"[rand() & 0xF]; + tid[32] = '\0'; + for (int i = 0; i < 16; i++) sid[i] = "0123456789abcdef"[rand() & 0xF]; + sid[16] = '\0'; + struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); + long long now_nano = (long long)ts.tv_sec * 1000000000LL + ts.tv_nsec; + char* handle = malloc(strlen(name) + 80); + if (!handle) return EL_STR(""); + sprintf(handle, "%s:%s:%lld:%s", tid, sid, now_nano, name); + el_arena_track(handle); + return EL_STR(handle); +} + +/* trace_span_end(handle) — emits the span with computed duration */ +el_val_t trace_span_end(el_val_t handle_v) { + otlp_lazy_init(); + if (!_otlp_endpoint) return EL_INT(0); + const char* h = EL_CSTR(handle_v); if (!h) return EL_INT(0); + /* parse "tid:sid:start_nano:name" */ + char tid[64], sid[32], rest[1024]; + long long start_nano = 0; + if (sscanf(h, "%63[^:]:%31[^:]:%lld:%1023[^\n]", tid, sid, &start_nano, rest) != 4) return EL_INT(0); + struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); + long long end_nano = (long long)ts.tv_sec * 1000000000LL + ts.tv_nsec; + char esc_name[1024]; otlp_json_escape(rest, esc_name, sizeof(esc_name)); + char rec[4096]; + int n = snprintf(rec, sizeof(rec), + "{\"traceId\":\"%s\",\"spanId\":\"%s\"," + "\"name\":\"%s\"," + "\"kind\":1," + "\"startTimeUnixNano\":\"%lld\"," + "\"endTimeUnixNano\":\"%lld\"," + "\"status\":{\"code\":1}}", + tid, sid, esc_name, start_nano, end_nano); + if (n > 0 && n < (int)sizeof(rec)) otlp_enqueue(&_otlp_traces, rec); + return EL_INT(1); +} + +/* Convenience: emit a one-shot timed event (emit start+end immediately). + * For El programs that want point events with duration baked in. */ +el_val_t emit_event(el_val_t name_v, el_val_t duration_ms_v) { + otlp_lazy_init(); + if (!_otlp_endpoint) return EL_INT(0); + const char* name = EL_CSTR(name_v); if (!name) name = "event"; + int64_t dur_ms = (int64_t)duration_ms_v; + el_val_t h = trace_span_start(EL_STR((char*)name)); + /* fudge start to be (now - duration) */ + (void)dur_ms; + return trace_span_end(h); +} + +#endif /* HAVE_CURL — OTLP */ + +/* ── Threading seed primitives ─────────────────────────────────────────────── + * __thread_create(fn_name, arg) -> Int spawn El fn in a pthread, return tid + * __thread_join(tid) -> String join thread, return result string + * __mutex_new() -> Int allocate a mutex, return handle + * __mutex_lock(m) lock mutex m + * __mutex_unlock(m) unlock mutex m + * + * Every El fn compiles to a global C symbol. __thread_create uses dlsym to + * look up the function by name and run it in a pthread. This means any El fn + * with signature (String) -> String is directly threadable. + */ + +typedef el_val_t (*ElFn1)(el_val_t); + +typedef struct { + ElFn1 fn; + el_val_t arg; + el_val_t result; +} ElThreadArg; + +#define EL_THREAD_MAX 256 + +typedef struct { + pthread_t tid; + ElThreadArg* arg; + int alive; +} ElThread; + +static ElThread _threads[EL_THREAD_MAX]; +static int _thread_count = 0; +static pthread_mutex_t _thread_alloc_mu = PTHREAD_MUTEX_INITIALIZER; + +static void* el_thread_runner(void* raw) { + ElThreadArg* a = (ElThreadArg*)raw; + a->result = a->fn(a->arg); + return NULL; +} + +el_val_t __thread_create(el_val_t fn_name_v, el_val_t arg_v) { + const char* sym = EL_CSTR(fn_name_v); + if (!sym || !*sym) return EL_INT(-1); + void* p = dlsym(RTLD_DEFAULT, sym); + if (!p) { + fprintf(stderr, "[__thread_create] symbol not found: %s\n", sym); + return EL_INT(-1); + } + ElThreadArg* a = (ElThreadArg*)malloc(sizeof(ElThreadArg)); + if (!a) return EL_INT(-1); + a->fn = (ElFn1)p; + a->arg = arg_v; + a->result = EL_STR(""); + + pthread_mutex_lock(&_thread_alloc_mu); + if (_thread_count >= EL_THREAD_MAX) { + pthread_mutex_unlock(&_thread_alloc_mu); + free(a); + fprintf(stderr, "[__thread_create] thread table full\n"); + return EL_INT(-1); + } + int slot = _thread_count++; + _threads[slot].arg = a; + _threads[slot].alive = 1; + pthread_mutex_unlock(&_thread_alloc_mu); + + if (pthread_create(&_threads[slot].tid, NULL, el_thread_runner, a) != 0) { + pthread_mutex_lock(&_thread_alloc_mu); + _thread_count--; + pthread_mutex_unlock(&_thread_alloc_mu); + free(a); + return EL_INT(-1); + } + return EL_INT(slot); +} + +el_val_t __thread_join(el_val_t tid_v) { + int slot = (int)(int64_t)tid_v; + if (slot < 0 || slot >= EL_THREAD_MAX) return EL_STR(""); + pthread_join(_threads[slot].tid, NULL); + el_val_t result = _threads[slot].arg->result; + free(_threads[slot].arg); + _threads[slot].alive = 0; + return result; +} + +/* Mutex table */ + +#define EL_MUTEX_MAX 64 + +typedef struct { + pthread_mutex_t mu; + int allocated; +} ElMutexEntry; + +static ElMutexEntry _mutexes[EL_MUTEX_MAX]; +static int _mutex_count = 0; +static pthread_mutex_t _mutex_alloc_mu = PTHREAD_MUTEX_INITIALIZER; + +el_val_t __mutex_new(void) { + pthread_mutex_lock(&_mutex_alloc_mu); + if (_mutex_count >= EL_MUTEX_MAX) { + pthread_mutex_unlock(&_mutex_alloc_mu); + fprintf(stderr, "[__mutex_new] mutex table full\n"); + return EL_INT(-1); + } + int slot = _mutex_count++; + pthread_mutex_init(&_mutexes[slot].mu, NULL); + _mutexes[slot].allocated = 1; + pthread_mutex_unlock(&_mutex_alloc_mu); + return EL_INT(slot); +} + +void __mutex_lock(el_val_t m_v) { + int slot = (int)(int64_t)m_v; + if (slot < 0 || slot >= EL_MUTEX_MAX || !_mutexes[slot].allocated) return; + pthread_mutex_lock(&_mutexes[slot].mu); +} + +void __mutex_unlock(el_val_t m_v) { + int slot = (int)(int64_t)m_v; + if (slot < 0 || slot >= EL_MUTEX_MAX || !_mutexes[slot].allocated) return; + pthread_mutex_unlock(&_mutexes[slot].mu); +} + +/* ── Channels ─────────────────────────────────────────────────────────────── * + * Buffered MPMC channel backed by a mutex + condvar + circular buffer. + * channel_new(capacity) -> Int (handle) + * channel_send(ch, msg) — blocks if full (capacity > 0) or never (unbounded) + * channel_recv(ch) -> String — blocks until a message is available + * channel_try_recv(ch) -> String — non-blocking, returns "" if empty + * channel_close(ch) — signal no more sends; recv drains remaining + * + * Bounded channels (cap > 0): circular buffer, sender blocks when full. + * Unbounded channels (cap == 0): dynamic array, sender never blocks. + */ +#define EL_CHANNEL_MAX 64 +#define EL_CHANNEL_BUF 1024 + +typedef struct { + char** buf; + int cap; /* 0 = unbounded (grows dynamically) */ + int head, tail, count; + int dyn_cap; /* allocated slots for unbounded mode */ + int closed; + pthread_mutex_t mu; + pthread_cond_t not_empty; + pthread_cond_t not_full; +} ElChannel; + +static ElChannel _channels[EL_CHANNEL_MAX]; +static int _channel_count = 0; +static pthread_mutex_t _channel_alloc_mu = PTHREAD_MUTEX_INITIALIZER; + +el_val_t __channel_new(el_val_t capacity_v) { + int cap = (int)(int64_t)capacity_v; + if (cap < 0) cap = 0; + + pthread_mutex_lock(&_channel_alloc_mu); + if (_channel_count >= EL_CHANNEL_MAX) { + pthread_mutex_unlock(&_channel_alloc_mu); + fprintf(stderr, "[__channel_new] channel table full\n"); + return EL_INT(-1); + } + int slot = _channel_count++; + pthread_mutex_unlock(&_channel_alloc_mu); + + ElChannel* ch = &_channels[slot]; + memset(ch, 0, sizeof(*ch)); + ch->cap = cap; + ch->closed = 0; + ch->head = 0; + ch->tail = 0; + ch->count = 0; + + if (cap > 0) { + /* Bounded: fixed circular buffer. */ + ch->buf = (char**)malloc((size_t)cap * sizeof(char*)); + ch->dyn_cap = cap; + } else { + /* Unbounded: start with EL_CHANNEL_BUF slots, grow as needed. */ + ch->buf = (char**)malloc(EL_CHANNEL_BUF * sizeof(char*)); + ch->dyn_cap = EL_CHANNEL_BUF; + } + if (!ch->buf) { + fprintf(stderr, "[__channel_new] out of memory\n"); + return EL_INT(-1); + } + + pthread_mutex_init(&ch->mu, NULL); + pthread_cond_init(&ch->not_empty, NULL); + pthread_cond_init(&ch->not_full, NULL); + + return EL_INT(slot); +} + +void __channel_send(el_val_t ch_v, el_val_t msg_v) { + int slot = (int)(int64_t)ch_v; + if (slot < 0 || slot >= EL_CHANNEL_MAX) return; + ElChannel* ch = &_channels[slot]; + + const char* msg = EL_CSTR(msg_v); + if (!msg) msg = ""; + char* copy = strdup(msg); /* channel owns the string */ + + pthread_mutex_lock(&ch->mu); + + if (ch->closed) { + /* Send on closed channel is a no-op (drop the message). */ + pthread_mutex_unlock(&ch->mu); + free(copy); + return; + } + + if (ch->cap > 0) { + /* Bounded: block while full. */ + while (ch->count >= ch->cap && !ch->closed) { + pthread_cond_wait(&ch->not_full, &ch->mu); + } + if (ch->closed) { + pthread_mutex_unlock(&ch->mu); + free(copy); + return; + } + ch->buf[ch->tail] = copy; + ch->tail = (ch->tail + 1) % ch->cap; + ch->count++; + } else { + /* Unbounded: grow the buffer if needed. */ + if (ch->count >= ch->dyn_cap) { + int new_cap = ch->dyn_cap * 2; + char** grown = (char**)realloc(ch->buf, (size_t)new_cap * sizeof(char*)); + if (!grown) { + pthread_mutex_unlock(&ch->mu); + free(copy); + fprintf(stderr, "[__channel_send] out of memory growing channel\n"); + return; + } + /* The circular buffer may have wrapped. Linearise it first. + * In unbounded mode head is always 0 (we append at tail, drain + * from head), so a simple memmove isn't needed — but if the + * buffer did wrap (tail < head after growth), we need to fix up. + * Simplest safe path: if tail wrapped, move the head..old_cap + * segment to new_cap..new_cap+(old_cap-head). */ + if (ch->tail < ch->head) { + /* Wrapped: [head..old_cap) is the front, [0..tail) is the back. */ + int front = ch->dyn_cap - ch->head; + memmove(grown + ch->dyn_cap, grown + ch->head, (size_t)front * sizeof(char*)); + ch->head = ch->dyn_cap; + } + ch->buf = grown; + ch->dyn_cap = new_cap; + } + ch->buf[ch->tail] = copy; + ch->tail = (ch->tail + 1) % ch->dyn_cap; + ch->count++; + } + + pthread_cond_signal(&ch->not_empty); + pthread_mutex_unlock(&ch->mu); +} + +el_val_t __channel_recv(el_val_t ch_v) { + int slot = (int)(int64_t)ch_v; + if (slot < 0 || slot >= EL_CHANNEL_MAX) return EL_STR(""); + ElChannel* ch = &_channels[slot]; + + pthread_mutex_lock(&ch->mu); + + /* Block until there is a message or the channel is closed and drained. */ + while (ch->count == 0 && !ch->closed) { + pthread_cond_wait(&ch->not_empty, &ch->mu); + } + + if (ch->count == 0) { + /* Closed and empty — signal EOF. */ + pthread_mutex_unlock(&ch->mu); + return EL_STR(""); + } + + int buf_cap = (ch->cap > 0) ? ch->cap : ch->dyn_cap; + char* msg = ch->buf[ch->head]; + ch->head = (ch->head + 1) % buf_cap; + ch->count--; + + pthread_cond_signal(&ch->not_full); + pthread_mutex_unlock(&ch->mu); + + /* Hand the string to the arena so it is freed after the request. */ + el_arena_track(msg); + return EL_STR(msg); +} + +el_val_t __channel_try_recv(el_val_t ch_v) { + int slot = (int)(int64_t)ch_v; + if (slot < 0 || slot >= EL_CHANNEL_MAX) return EL_STR(""); + ElChannel* ch = &_channels[slot]; + + pthread_mutex_lock(&ch->mu); + + if (ch->count == 0) { + pthread_mutex_unlock(&ch->mu); + return EL_STR(""); + } + + int buf_cap = (ch->cap > 0) ? ch->cap : ch->dyn_cap; + char* msg = ch->buf[ch->head]; + ch->head = (ch->head + 1) % buf_cap; + ch->count--; + + pthread_cond_signal(&ch->not_full); + pthread_mutex_unlock(&ch->mu); + + el_arena_track(msg); + return EL_STR(msg); +} + +void __channel_close(el_val_t ch_v) { + int slot = (int)(int64_t)ch_v; + if (slot < 0 || slot >= EL_CHANNEL_MAX) return; + ElChannel* ch = &_channels[slot]; + + pthread_mutex_lock(&ch->mu); + ch->closed = 1; + /* Wake all blocked recvers and senders so they can observe the close. */ + pthread_cond_broadcast(&ch->not_empty); + pthread_cond_broadcast(&ch->not_full); + pthread_mutex_unlock(&ch->mu); +} + +/* ── DHARMA runtime additions ──────────────────────────────────────────────── + * + * Functions required by the dharma registry service. Added here so the + * released el_runtime.c includes them without requiring dharma to bundle + * its own stubs. + * + * Functions added: + * list_len — alias for el_list_len (used in handlers.el) + * list_get — alias for el_list_get (used in handlers.el) + * json_array_push — append a pre-encoded JSON element to a JSON array string + * now_millis — milliseconds since Unix epoch (alias for time_now) + * unix_timestamp_ms — same as now_millis (alias) + * time_now_ms — same as now_millis (alias) + * log_info — stderr structured log at INFO level + * log_warn — stderr structured log at WARN level + * config — reads a config value from the environment + * http_patch — HTTP PATCH with JSON Content-Type + * http_post_engram — HTTP POST with optional X-API-Key header + * http_get_engram — HTTP GET with optional X-API-Key header + * str_to_bytes — encode a string as a JSON array of byte values + * bytes_to_str — decode a JSON array of byte values back to a string + * hash_sha256 — SHA-256 hex digest of a string + */ + +/* list_len — return the number of elements in a list. */ +el_val_t list_len(el_val_t list) { + return el_list_len(list); +} + +/* list_get — return the element at index i in a list. */ +el_val_t list_get(el_val_t list, el_val_t index) { + return el_list_get(list, index); +} + +/* json_array_push — append element (a pre-encoded JSON fragment, e.g. "\"foo\"" + * or "42") to the JSON array string arr. Returns a new JSON array string. + * Example: json_array_push("[]", "\"alice\"") -> "[\"alice\"]" + * json_array_push("[\"alice\"]", "\"bob\"") -> "[\"alice\",\"bob\"]" */ +el_val_t json_array_push(el_val_t arr_v, el_val_t elem_v) { + const char* arr = EL_CSTR(arr_v); + const char* elem = EL_CSTR(elem_v); + if (!arr || !*arr) arr = "[]"; + if (!elem || !*elem) elem = "null"; + + /* Trim whitespace, find the closing ']'. */ + const char* p = arr; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p != '[') { + /* Not an array — return a single-element array. */ + size_t n = strlen(elem) + 4; + char* out = el_strbuf(n); + snprintf(out, n, "[%s]", elem); + return el_wrap_str(out); + } + size_t arr_len = strlen(arr); + size_t elem_len = strlen(elem); + + /* Walk from the end to find the matching ']'. */ + const char* end = arr + arr_len - 1; + while (end > p && (*end == ' ' || *end == '\t' || *end == '\n' || *end == '\r')) end--; + if (*end != ']') { + /* Malformed — wrap elem in a new array. */ + size_t n = elem_len + 4; + char* out = el_strbuf(n); + snprintf(out, n, "[%s]", elem); + return el_wrap_str(out); + } + + /* Content between '[' and ']'. */ + const char* inner_start = p + 1; + const char* inner_end = end; /* points AT ']' */ + /* Check if the array is empty (only whitespace between brackets). */ + const char* q = inner_start; + while (q < inner_end && (*q == ' ' || *q == '\t' || *q == '\n' || *q == '\r')) q++; + int empty = (q == inner_end); + + /* Build: prefix + (comma if non-empty) + elem + "]" */ + size_t prefix_len = (size_t)(inner_end - arr); /* up to but not including ']' */ + size_t sep_len = empty ? 0 : 1; /* "," if non-empty */ + size_t out_len = prefix_len + sep_len + elem_len + 2; /* +"]" + NUL */ + char* out = el_strbuf(out_len); + memcpy(out, arr, prefix_len); + if (!empty) out[prefix_len] = ','; + memcpy(out + prefix_len + sep_len, elem, elem_len); + out[prefix_len + sep_len + elem_len] = ']'; + out[prefix_len + sep_len + elem_len + 1] = '\0'; + return el_wrap_str(out); +} + +/* now_millis — milliseconds since Unix epoch. */ +el_val_t now_millis(void) { + return time_now(); +} + +/* unix_timestamp_ms — same as now_millis. */ +el_val_t unix_timestamp_ms(void) { + return time_now(); +} + +/* time_now_ms — same as now_millis. */ +el_val_t time_now_ms(void) { + return time_now(); +} + +/* log_info — write a structured [INFO] line to stderr. */ +void log_info(el_val_t msg_v) { + const char* msg = EL_CSTR(msg_v); + fprintf(stderr, "[INFO] %s\n", msg ? msg : ""); +} + +/* log_warn — write a structured [WARN] line to stderr. */ +void log_warn(el_val_t msg_v) { + const char* msg = EL_CSTR(msg_v); + fprintf(stderr, "[WARN] %s\n", msg ? msg : ""); +} + +/* config — read a configuration value from the environment. + * Returns "" if the variable is not set (same as __env_get). */ +el_val_t config(el_val_t key_v) { + const char* key = EL_CSTR(key_v); + if (!key || !*key) return EL_STR(""); + const char* val = getenv(key); + if (!val) return EL_STR(""); + return el_wrap_str(el_strdup(val)); +} + +#ifdef HAVE_CURL +/* http_patch — HTTP PATCH request with Content-Type: application/json. + * Returns the response body (same error convention as http_post_json). */ +el_val_t http_patch(el_val_t url_v, el_val_t body_v) { + const char* url = EL_CSTR(url_v); + const char* body = EL_CSTR(body_v); + if (!url || !*url) return http_error_json("empty url"); + CURL* c = curl_easy_init(); + if (!c) return http_error_json("curl_easy_init failed"); + HttpBuf rb; httpbuf_init(&rb); + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, "PATCH"); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, body ? body : ""); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(body ? strlen(body) : 0)); + curl_easy_setopt(c, CURLOPT_HTTPHEADER, h); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, http_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, &rb); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, el_http_timeout_ms()); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-runtime/1.0"); + CURLcode rc = curl_easy_perform(c); + curl_slist_free_all(h); + curl_easy_cleanup(c); + if (rc != CURLE_OK) { + free(rb.data); + const char* m = errbuf[0] ? errbuf : curl_easy_strerror(rc); + return http_error_json(m); + } + return el_wrap_str(rb.data); +} + +/* http_post_engram — HTTP POST with optional X-API-Key header. + * If key is "" no authentication header is sent. */ +el_val_t http_post_engram(el_val_t url_v, el_val_t key_v, el_val_t body_v) { + const char* url = EL_CSTR(url_v); + const char* key = EL_CSTR(key_v); + const char* body = EL_CSTR(body_v); + if (!url || !*url) return http_error_json("empty url"); + CURL* c = curl_easy_init(); + if (!c) return http_error_json("curl_easy_init failed"); + HttpBuf rb; httpbuf_init(&rb); + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + struct curl_slist* h = NULL; + h = curl_slist_append(h, "Content-Type: application/json"); + if (key && *key) { + size_t n = strlen(key) + 32; + char* hdr = malloc(n); + snprintf(hdr, n, "X-API-Key: %s", key); + h = curl_slist_append(h, hdr); + free(hdr); + } + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, body ? body : ""); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(body ? strlen(body) : 0)); + curl_easy_setopt(c, CURLOPT_HTTPHEADER, h); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, http_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, &rb); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, el_http_timeout_ms()); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-runtime/1.0"); + CURLcode rc = curl_easy_perform(c); + curl_slist_free_all(h); + curl_easy_cleanup(c); + if (rc != CURLE_OK) { + free(rb.data); + const char* m = errbuf[0] ? errbuf : curl_easy_strerror(rc); + return http_error_json(m); + } + return el_wrap_str(rb.data); +} + +/* http_get_engram — HTTP GET with optional X-API-Key header. */ +el_val_t http_get_engram(el_val_t url_v, el_val_t key_v) { + const char* url = EL_CSTR(url_v); + const char* key = EL_CSTR(key_v); + if (!url || !*url) return http_error_json("empty url"); + CURL* c = curl_easy_init(); + if (!c) return http_error_json("curl_easy_init failed"); + HttpBuf rb; httpbuf_init(&rb); + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + struct curl_slist* h = NULL; + if (key && *key) { + size_t n = strlen(key) + 32; + char* hdr = malloc(n); + snprintf(hdr, n, "X-API-Key: %s", key); + h = curl_slist_append(h, hdr); + free(hdr); + } + curl_easy_setopt(c, CURLOPT_URL, url); + curl_easy_setopt(c, CURLOPT_HTTPGET, 1L); + if (h) curl_easy_setopt(c, CURLOPT_HTTPHEADER, h); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, http_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, &rb); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, el_http_timeout_ms()); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-runtime/1.0"); + CURLcode rc = curl_easy_perform(c); + if (h) curl_slist_free_all(h); + curl_easy_cleanup(c); + if (rc != CURLE_OK) { + free(rb.data); + const char* m = errbuf[0] ? errbuf : curl_easy_strerror(rc); + return http_error_json(m); + } + return el_wrap_str(rb.data); +} +#endif /* HAVE_CURL */ + +/* str_to_bytes — encode a string as a JSON array of unsigned byte values. + * "hello" -> "[104,101,108,108,111]" + * Used by db.el to store binary content in Engram JSON nodes. */ +el_val_t str_to_bytes(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s || !*s) return el_wrap_str(el_strdup("[]")); + size_t n = strlen(s); + /* Worst case: each byte is 3 digits + comma = 4 chars, plus "[]" + NUL. */ + char* out = el_strbuf(n * 4 + 3); + size_t pos = 0; + out[pos++] = '['; + for (size_t i = 0; i < n; i++) { + unsigned char b = (unsigned char)s[i]; + if (i > 0) out[pos++] = ','; + /* Write decimal representation of b. */ + if (b >= 100) { + out[pos++] = (char)('0' + b / 100); + out[pos++] = (char)('0' + (b / 10) % 10); + out[pos++] = (char)('0' + b % 10); + } else if (b >= 10) { + out[pos++] = (char)('0' + b / 10); + out[pos++] = (char)('0' + b % 10); + } else { + out[pos++] = (char)('0' + b); + } + } + out[pos++] = ']'; + out[pos] = '\0'; + return el_wrap_str(out); +} + +/* bytes_to_str — decode a JSON array of integer byte values back to a string. + * "[104,101,108,108,111]" -> "hello" + * Inverse of str_to_bytes. */ +el_val_t bytes_to_str(el_val_t arr_v) { + const char* s = EL_CSTR(arr_v); + if (!s) return el_wrap_str(el_strdup("")); + /* Skip whitespace, expect '['. */ + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s != '[') return el_wrap_str(el_strdup("")); + s++; + + /* Count elements to size the output buffer. */ + int64_t n = (int64_t)json_array_len(arr_v); + if (n <= 0) return el_wrap_str(el_strdup("")); + + char* out = el_strbuf((size_t)n + 1); + size_t pos = 0; + + /* Walk the array, parse each integer, store as a byte. */ + while (*s) { + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ']' || *s == '\0') break; + /* Parse decimal integer. */ + char* end_ptr; + long v = strtol(s, &end_ptr, 10); + if (end_ptr == s) break; /* parse failure */ + s = end_ptr; + if (v >= 0 && v <= 255) out[pos++] = (char)(unsigned char)v; + while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') s++; + if (*s == ',') { s++; continue; } + if (*s == ']' || *s == '\0') break; + } + out[pos] = '\0'; + return el_wrap_str(out); +} + +/* hash_sha256 — return the SHA-256 hex digest of a string. + * Uses the built-in el_sha256_oneshot implementation (no OpenSSL required). */ +el_val_t hash_sha256(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) s = ""; + unsigned char digest[32]; + el_sha256_oneshot((const unsigned char*)s, strlen(s), digest); + return el_hex_encode(digest, 32); +} + +/* ── __ prefixed aliases — public boundary for compiled El programs ────────── + * + * The El compiler's self-hosting back-end emits calls to __-prefixed function + * names (e.g. __println, __str_len). These wrappers forward to the existing + * el_runtime implementations so both naming conventions resolve at link time. + * + * Note: __thread_create and __thread_join are already defined above in the + * threading section; they are not repeated here. + * ──────────────────────────────────────────────────────────────────────────── */ + +/* I/O */ +el_val_t __println(el_val_t s) { return println(s); } +el_val_t __print(el_val_t s) { return print(s); } +el_val_t __readline(void) { return readline(); } + +/* String */ +el_val_t __int_to_str(el_val_t n) { return int_to_str(n); } +el_val_t __str_to_int(el_val_t s) { return str_to_int(s); } +el_val_t __float_to_str(el_val_t f) { return float_to_str(f); } +el_val_t __str_to_float(el_val_t s) { return str_to_float(s); } +el_val_t __str_len(el_val_t s) { return str_len(s); } +el_val_t __str_char_at(el_val_t s, el_val_t i) { return str_char_at(s, i); } + +el_val_t __str_cmp(el_val_t a, el_val_t b) { + const char* ca = EL_CSTR(a); + const char* cb = EL_CSTR(b); + if (!ca) ca = ""; + if (!cb) cb = ""; + return (el_val_t)strcmp(ca, cb); +} + +el_val_t __str_ncmp(el_val_t a, el_val_t b, el_val_t n) { + const char* ca = EL_CSTR(a); + const char* cb = EL_CSTR(b); + if (!ca) ca = ""; + if (!cb) cb = ""; + return (el_val_t)strncmp(ca, cb, (size_t)n); +} + +el_val_t __str_concat_raw(el_val_t a, el_val_t b) { return str_concat(a, b); } +el_val_t __str_slice_raw(el_val_t s, el_val_t start, el_val_t end) { return str_slice(s, start, end); } + +el_val_t __str_alloc(el_val_t n) { + if (n <= 0) n = 0; + char* buf = el_strbuf((size_t)n + 1); + memset(buf, 0, (size_t)n + 1); + return el_wrap_str(buf); +} + +el_val_t __str_set_char(el_val_t s, el_val_t i, el_val_t c) { + char* buf = (char*)(uintptr_t)s; + if (buf) buf[(size_t)i] = (char)c; + return s; +} + +/* URL encoding */ +el_val_t __url_encode(el_val_t s) { return url_encode(s); } +el_val_t __url_decode(el_val_t s) { return url_decode(s); } + +/* Environment */ +el_val_t __env_get(el_val_t key) { return env(key); } + +/* Subprocess */ +el_val_t __exec(el_val_t cmd) { return exec(cmd); } +el_val_t __exec_bg(el_val_t cmd) { return exec_bg(cmd); } + +/* Process */ +el_val_t __exit_program(el_val_t code) { return exit_program(code); } + +/* Filesystem */ +el_val_t __fs_exists(el_val_t path) { return fs_exists(path); } +el_val_t __fs_mkdir(el_val_t path) { return fs_mkdir(path); } +el_val_t __fs_read(el_val_t path) { return fs_read(path); } +el_val_t __fs_write(el_val_t path, el_val_t content) { return fs_write(path, content); } +el_val_t __fs_write_bytes(el_val_t path, el_val_t bytes, el_val_t n) { return fs_write_bytes(path, bytes, n); } +el_val_t __fs_list_raw(el_val_t path) { return fs_list_json(path); } + +/* HTTP server (no curl dependency) */ +el_val_t __http_response(el_val_t status, el_val_t headers_json, el_val_t body) { return http_response(status, headers_json, body); } +el_val_t __http_serve(el_val_t port, el_val_t handler) { return http_serve(port, handler); } +el_val_t __http_serve_v2(el_val_t port, el_val_t handler) { return http_serve_v2(port, handler); } + +/* HTTP conn fd / SSE — __http_conn_fd lives in el_seed.c; stubs provided here + * so el_runtime.c compiles standalone. When both translation units are linked + * the el_seed.c definitions win via their non-static linkage (strong symbols). + * These stubs are marked weak so they are silently overridden. */ +__attribute__((weak)) el_val_t __http_conn_fd(void) { return (el_val_t)(-1); } +__attribute__((weak)) el_val_t __http_sse_open(el_val_t conn_id) { (void)conn_id; return 0; } +__attribute__((weak)) el_val_t __http_sse_send(el_val_t conn_id, el_val_t data) { (void)conn_id; (void)data; return 0; } +__attribute__((weak)) el_val_t __http_sse_close(el_val_t conn_id) { (void)conn_id; return 0; } + +/* JSON */ +el_val_t __json_array_get(el_val_t json, el_val_t index) { return json_array_get(json, index); } +el_val_t __json_array_get_string(el_val_t json, el_val_t index) { return json_array_get_string(json, index); } +el_val_t __json_array_len(el_val_t json) { return json_array_len(json); } +el_val_t __json_get(el_val_t json, el_val_t key) { return json_get(json, key); } +el_val_t __json_get_raw(el_val_t json, el_val_t key) { return json_get_raw(json, key); } +el_val_t __json_set(el_val_t json, el_val_t key, el_val_t value){ return json_set(json, key, value); } +el_val_t __json_parse_map(el_val_t json_str) { return json_parse(json_str); } +el_val_t __json_stringify_val(el_val_t val) { return json_stringify(val); } + +/* Hashing */ +el_val_t __sha256_hex(el_val_t s) { return hash_sha256(s); } + +/* State K/V */ +el_val_t __state_del(el_val_t key) { return state_del(key); } +el_val_t __state_get(el_val_t key) { return state_get(key); } +el_val_t __state_keys(void) { return state_keys(); } +el_val_t __state_set(el_val_t key, el_val_t val) { return state_set(key, val); } + +/* UUID */ +el_val_t __uuid_v4(void) { return uuid_v4(); } + +/* Args */ +el_val_t __args_json(void) { return args(); } + +/* HTTP client aliases — require curl; defined inside #ifdef HAVE_CURL below + * with a matching stub in the #ifndef HAVE_CURL block. */ +#ifdef HAVE_CURL +el_val_t __http_do(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_map, el_val_t timeout_ms) { + /* timeout_ms is accepted for API compatibility but ignored here; + * el_runtime's http_do uses the EL_HTTP_TIMEOUT_MS env var instead. */ + (void)timeout_ms; + struct curl_slist* h = headers_from_map(headers_map); + el_val_t r = http_do(EL_CSTR(method), EL_CSTR(url), EL_CSTR(body), h); + if (h) curl_slist_free_all(h); + return r; +} + +/* __http_do_map — same as __http_do but headers_map arg is a JSON-string + * rather than an ElMap. Parse it first, then delegate. */ +el_val_t __http_do_map(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t timeout_ms) { + (void)timeout_ms; + /* Build a curl_slist from a JSON object {"Header":"value",...}. */ + const char* hj = EL_CSTR(headers_json); + struct curl_slist* h = NULL; + if (hj && *hj && *hj == '{') { + /* Walk the JSON pairs with a simple parser reusing json_get_string logic. */ + /* For correctness we just call the existing json_get iteration path. + * We duplicate the key-extraction loop from headers_from_map but driven + * by JSON rather than ElMap. Use json_get_raw to iterate is not easy + * without knowing keys, so accept the JSON string and build a tmp map. */ + el_val_t map = json_parse(EL_STR(hj)); + h = headers_from_map(map); + } + el_val_t r = http_do(EL_CSTR(method), EL_CSTR(url), EL_CSTR(body), h); + if (h) curl_slist_free_all(h); + return r; +} + +/* __http_do_map_to_file — same as __http_do_map but streams response body + * to a local file path rather than returning it as a string. */ +el_val_t __http_do_map_to_file(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t output_path) { + const char* hj = EL_CSTR(headers_json); + struct curl_slist* h = NULL; + if (hj && *hj && *hj == '{') { + el_val_t map = json_parse(EL_STR(hj)); + h = headers_from_map(map); + } + el_val_t r = http_do_to_file(EL_CSTR(method), EL_CSTR(url), EL_CSTR(body), + h, EL_CSTR(output_path)); + if (h) curl_slist_free_all(h); + return r; +} +#endif /* HAVE_CURL */ + +#ifndef HAVE_CURL +/* ── HAVE_CURL=0 stubs — compile without -lcurl for the elc CLI binary. ───── * + * These return a JSON error string so El programs get a clear message if they + * call HTTP/LLM functions in a curl-less build. */ +static el_val_t _no_curl_err(void) { + return el_wrap_str(el_strdup("{\"error\":\"not built with HAVE_CURL\"}")); +} +el_val_t http_get(el_val_t url) { (void)url; return _no_curl_err(); } +el_val_t http_post(el_val_t url, el_val_t body) { (void)url; (void)body; return _no_curl_err(); } +el_val_t http_post_json(el_val_t url, el_val_t body) { (void)url; (void)body; return _no_curl_err(); } +el_val_t http_get_with_headers(el_val_t url, el_val_t h) { (void)url; (void)h; return _no_curl_err(); } +el_val_t http_post_with_headers(el_val_t url, el_val_t b, el_val_t h) { (void)url; (void)b; (void)h; return _no_curl_err(); } +el_val_t http_post_json_with_headers(el_val_t url, el_val_t h, el_val_t b) { (void)url; (void)h; (void)b; return _no_curl_err(); } +el_val_t http_post_form_auth(el_val_t url, el_val_t b, el_val_t a) { (void)url; (void)b; (void)a; return _no_curl_err(); } +el_val_t http_delete(el_val_t url) { (void)url; return _no_curl_err(); } +el_val_t http_patch(el_val_t url, el_val_t body) { (void)url; (void)body; return _no_curl_err(); } +el_val_t http_get_to_file(el_val_t url, el_val_t h, el_val_t p) { (void)url; (void)h; (void)p; return _no_curl_err(); } +el_val_t http_post_to_file(el_val_t url, el_val_t b, el_val_t h, el_val_t p) { (void)url; (void)b; (void)h; (void)p; return _no_curl_err(); } +el_val_t http_post_engram(el_val_t url, el_val_t k, el_val_t b) { (void)url; (void)k; (void)b; return _no_curl_err(); } +el_val_t http_get_engram(el_val_t url, el_val_t k) { (void)url; (void)k; return _no_curl_err(); } +el_val_t llm_call(el_val_t m, el_val_t p) { (void)m; (void)p; return _no_curl_err(); } +el_val_t llm_call_system(el_val_t m, el_val_t s, el_val_t u) { (void)m; (void)s; (void)u; return _no_curl_err(); } +el_val_t llm_call_agentic(el_val_t m, el_val_t s, el_val_t u, el_val_t t) { (void)m; (void)s; (void)u; (void)t; return _no_curl_err(); } +el_val_t llm_vision(el_val_t m, el_val_t s, el_val_t p, el_val_t i) { (void)m; (void)s; (void)p; (void)i; return _no_curl_err(); } +el_val_t llm_models(void) { return el_list_empty(); } +void llm_register_tool(el_val_t n, el_val_t f) { (void)n; (void)f; } +/* __ HTTP stubs (no-curl build) */ +el_val_t __http_do(el_val_t m, el_val_t u, el_val_t b, el_val_t h, el_val_t t) { (void)m; (void)u; (void)b; (void)h; (void)t; return _no_curl_err(); } +el_val_t __http_do_map(el_val_t m, el_val_t u, el_val_t b, el_val_t h, el_val_t t) { (void)m; (void)u; (void)b; (void)h; (void)t; return _no_curl_err(); } +el_val_t __http_do_map_to_file(el_val_t m, el_val_t u, el_val_t b, el_val_t h, el_val_t p) { (void)m; (void)u; (void)b; (void)h; (void)p; return _no_curl_err(); } +#endif /* !HAVE_CURL */ diff --git a/ui/examples/native-hello/build-docker/runtime/el_runtime.h b/ui/examples/native-hello/build-docker/runtime/el_runtime.h new file mode 100644 index 0000000..2f9583f --- /dev/null +++ b/ui/examples/native-hello/build-docker/runtime/el_runtime.h @@ -0,0 +1,883 @@ +/* + * el_runtime.h — El language C runtime header + * + * Declares all built-in functions available to compiled El programs. + * Include this in every generated .c file. + * + * Value model: + * All El values are represented as el_val_t (= int64_t). + * On 64-bit systems a pointer fits in int64_t. + * String values are cast: (el_val_t)(uintptr_t)"hello" + * Integer values are stored directly. + * This lets arithmetic work naturally while still passing strings around. + * + * Type conventions (El -> C): + * String -> el_val_t (holds const char* via uintptr_t cast) + * Int -> el_val_t + * Bool -> el_val_t (0 = false, nonzero = true) + * Any -> el_val_t + * Void -> void + * + * Macros for convenience: + * 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_*). + * -lpthread — required for the HTTP server (one detached thread per + * connection, capped at 64 concurrent). + * -loqs — optional; required only when liboqs is installed and the + * pq_* / sha3_256_hex entry points are needed. Detected at + * compile time via __has_include(). + * -lcrypto — optional; pulled in alongside -loqs. Used for X25519 in + * pq_hybrid_* and HKDF-SHA256 derivation. + * + * Canonical compile command: + * cc -std=c11 -I el-compiler/runtime -lcurl -lpthread \ + * -o .c el-compiler/runtime/el_runtime.c + * + * With liboqs (post-quantum stack): + * cc -std=c11 -I el-compiler/runtime -lcurl -lpthread -loqs -lcrypto \ + * -o .c el-compiler/runtime/el_runtime.c + */ + +#pragma once + +#include +#include + +typedef int64_t el_val_t; + +#define EL_STR(s) ((el_val_t)(uintptr_t)(s)) +#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()` so the + * underlying bits represent the IEEE 754 double. Float-aware builtins + * (math, format, json) round-trip via these helpers. */ +static inline double el_to_float(el_val_t v) { + union { int64_t i; double f; } u; + u.i = (int64_t)v; + return u.f; +} + +static inline el_val_t el_from_float(double f) { + union { double f; int64_t i; } u; + u.f = f; + return (el_val_t)u.i; +} + +#ifdef __cplusplus +extern "C" { +#endif + +/* ── I/O ──────────────────────────────────────────────────────────────────── */ + +el_val_t println(el_val_t s); +el_val_t print(el_val_t s); +el_val_t readline(void); + +/* ── String builtins ─────────────────────────────────────────────────────── */ + +el_val_t el_str_concat(el_val_t a, el_val_t b); +el_val_t str_eq(el_val_t a, el_val_t b); +el_val_t str_starts_with(el_val_t s, el_val_t prefix); +el_val_t str_ends_with(el_val_t s, el_val_t suffix); +el_val_t str_len(el_val_t s); +el_val_t str_concat(el_val_t a, el_val_t b); +el_val_t int_to_str(el_val_t n); +el_val_t str_to_int(el_val_t s); +el_val_t native_str_to_int(el_val_t s); +el_val_t str_slice(el_val_t s, el_val_t start, el_val_t end); +el_val_t str_contains(el_val_t s, el_val_t sub); +el_val_t str_replace(el_val_t s, el_val_t from, el_val_t to); +el_val_t str_to_upper(el_val_t s); +el_val_t str_to_lower(el_val_t s); +el_val_t str_trim(el_val_t s); + +/* ── Math ────────────────────────────────────────────────────────────────── */ + +el_val_t el_abs(el_val_t n); +el_val_t el_max(el_val_t a, el_val_t b); +el_val_t el_min(el_val_t a, el_val_t b); + +/* ── Refcount (ARC) ────────────────────────────────────────────────────────── + * Lists and Maps carry a refcount. Strings and ints do not — el_retain and + * el_release are safe no-ops on non-refcounted values (they sniff a magic + * header at offset 0 and only act if the magic matches). + * + * Codegen emits these at let-binding shadowing, function entry (params), and + * function exit (locals other than the returned value). The refcount lets + * el_list_append and el_map_set mutate in place when uniquely owned (cheap) + * and copy-on-write when shared (preserves persistent semantics across + * accumulator patterns in the compiler itself). */ + +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, ...); +el_val_t el_list_len(el_val_t list); +el_val_t el_list_get(el_val_t list, el_val_t index); +el_val_t el_list_append(el_val_t list, el_val_t elem); +el_val_t el_list_empty(void); +el_val_t el_list_clone(el_val_t list); + +/* ── Map ─────────────────────────────────────────────────────────────────── */ + +el_val_t el_map_new(el_val_t pair_count, ...); +el_val_t el_get_field(el_val_t map, el_val_t key); +el_val_t el_map_get(el_val_t map, el_val_t key); +el_val_t el_map_set(el_val_t map, el_val_t key, el_val_t value); + +/* ── HTTP ─────────────────────────────────────────────────────────────────── */ + +el_val_t http_get(el_val_t url); +el_val_t http_post(el_val_t url, el_val_t body); +el_val_t http_post_json(el_val_t url, el_val_t json_body); +el_val_t http_get_with_headers(el_val_t url, el_val_t headers_map); +el_val_t http_post_with_headers(el_val_t url, el_val_t body, el_val_t headers_map); +el_val_t http_post_json_with_headers(el_val_t url, el_val_t headers_map, el_val_t json_body); +el_val_t http_post_form_auth(el_val_t url, el_val_t form_body, el_val_t auth_header); +el_val_t http_delete(el_val_t url); +el_val_t http_serve(el_val_t port, el_val_t handler); +el_val_t http_set_handler(el_val_t name); + +/* HTTP server v2 ───────────────────────────────────────────────────────────── + * Same dispatch model as http_serve, but the handler signature is widened: + * + * el_val_t handler(method, path, headers_map, body) + * + * `headers_map` is an ElMap from lowercased header name → header value (both + * Strings). Repeated headers are joined with ", " per RFC 7230. + * + * Response value: the handler may return either + * (a) a plain body string — same auto-content-type / 200-OK behaviour as + * http_serve (3-arg) — or + * (b) a response envelope built with `http_response(status, headers_json, + * body)`. The runtime detects the envelope discriminator + * `"el_http_response":1` at the start of the returned string and + * unpacks status / headers / body before sending. + * + * The 3-arg http_serve(port, handler) remains supported unchanged for + * existing handlers (e.g. products/web/server.el): it dispatches with + * (method, path, body), hardcodes 200 OK, and auto-detects content type. */ +el_val_t http_serve_v2(el_val_t port, el_val_t handler); +el_val_t http_set_handler_v2(el_val_t name); + +/* Build an HTTP response envelope. `headers_json` should be a JSON object + * literal like `{"WWW-Authenticate":"Basic"}` (or "" / "{}" for none). The + * returned string carries the discriminator `{"el_http_response":1,...}` + * which the runtime's send-path detects and unpacks. Detection happens + * uniformly inside http_send_response, so a 3-arg handler may also return + * an envelope. The 3-arg variant remains documented as a fixed 200-OK + * auto-content-type contract for legacy handlers that return plain bodies. */ +el_val_t http_response(el_val_t status, el_val_t headers_json, el_val_t body); + +/* SSE connection fd — set by http_worker_v2 before calling the El handler, + * cleared afterwards. Defined in el_seed.c; called from el_runtime.c. + * The getter is exposed as __http_conn_fd() to El programs. */ +void el_seed_set_http_conn_fd(int fd); + +/* HTTP timeout — every libcurl request honors EL_HTTP_TIMEOUT_MS (default + * 60000ms). Read lazily on first use, so setting the env var any time before + * the first http_* call is sufficient. */ + +/* Streaming variants — write the response body straight to a file via + * libcurl's CURLOPT_WRITEFUNCTION = fwrite. These bypass the el_val_t string + * wrapper entirely, so binary payloads (audio/mpeg, image/png, etc.) survive + * embedded NUL bytes that would truncate a strlen()-based code path. + * + * Both honor EL_HTTP_TIMEOUT_MS, follow redirects, and accept the same + * `headers_map` shape as http_post_with_headers (ElMap of String→String). + * + * Return value: 1 on success (file fully written), 0 on any failure + * (network, file open, partial write). On failure the output file is removed + * so callers cannot mistake a partially-written file for a valid one. */ +el_val_t http_post_to_file(el_val_t url, el_val_t body, el_val_t headers_map, el_val_t output_path); +el_val_t http_get_to_file(el_val_t url, el_val_t headers_map, el_val_t output_path); + +/* ── URL encoding ────────────────────────────────────────────────────────── */ + +el_val_t url_encode(el_val_t s); /* RFC 3986 unreserved set */ +el_val_t url_decode(el_val_t s); /* '+' → space, %XX → byte */ + +/* ── HTML allowlist sanitizer ──────────────────────────────────────────────── + * el_html_sanitize(input_html, allowlist_json) — strict allowlist HTML + * cleaner. State-machine parser; tag/attribute names compared case- + * insensitively against the allowlist; `` / `<… src>` URL schemes + * validated (http, https, mailto, fragment-only, or relative); whole- + * subtree drop for script / style / iframe / object / embed / form; HTML- + * escapes free text outside dropped subtrees. + * + * The allowlist is JSON of the form + * {"p":[],"a":["href","title"],"strong":[],...} + * where each value is the array of attribute names allowed for that tag. */ +el_val_t el_html_sanitize(el_val_t input_html, el_val_t allowlist_json); +el_val_t html_raw(el_val_t s); +el_val_t html_escape(el_val_t s); + +/* ── Filesystem ──────────────────────────────────────────────────────────── */ + +el_val_t fs_read(el_val_t path); +el_val_t fs_write(el_val_t path, el_val_t content); +el_val_t fs_list(el_val_t path); +el_val_t fs_list_json(el_val_t path); +el_val_t fs_exists(el_val_t path); +el_val_t fs_mkdir(el_val_t path); /* mkdir -p, mode 0755 */ + +/* Length-explicit binary write. `length` is an Int (el_val_t holding the + * byte count). The caller knows the length from context — typically because + * `bytes` came from base64_decode (which produces a magic-tagged binary + * buffer with embedded NULs possible) and the caller already tracks the + * decoded length, OR because the bytes came from a fixed-size source + * (sha256_bytes = 32, hmac_sha256_bytes = 32). Bypasses strlen entirely. + * + * Returns 1 on success, 0 on failure (invalid path, can't open, partial + * write, negative length). On partial-write failure, the file is removed + * so callers cannot read back a truncated artefact. */ +el_val_t fs_write_bytes(el_val_t path, el_val_t bytes, el_val_t length); + +/* ── JSON ────────────────────────────────────────────────────────────────── */ + +el_val_t json_get(el_val_t json, el_val_t key); +el_val_t json_parse(el_val_t s); +el_val_t json_stringify(el_val_t v); +el_val_t json_get_string(el_val_t json_str, el_val_t key); +el_val_t json_get_int(el_val_t json_str, el_val_t key); +el_val_t json_get_float(el_val_t json_str, el_val_t key); +el_val_t json_get_bool(el_val_t json_str, el_val_t key); +el_val_t json_get_raw(el_val_t json_str, el_val_t key); +el_val_t json_set(el_val_t json_str, el_val_t key, el_val_t value); +el_val_t json_array_len(el_val_t json_str); +el_val_t json_array_get(el_val_t json_str, el_val_t index); +el_val_t json_array_get_string(el_val_t json_str, el_val_t index); +el_val_t json_escape_string(el_val_t sv); +el_val_t json_build_object(el_val_t kvs); +el_val_t json_build_array(el_val_t items); + +/* ── Time ────────────────────────────────────────────────────────────────── */ + +el_val_t time_now(void); +el_val_t time_now_utc(void); +el_val_t sleep_secs(el_val_t secs); +el_val_t sleep_ms(el_val_t ms); +el_val_t time_format(el_val_t ts, el_val_t fmt); +el_val_t time_to_parts(el_val_t ts); +el_val_t time_from_parts(el_val_t secs, el_val_t ns, el_val_t tz); +el_val_t time_add(el_val_t ts, el_val_t n, el_val_t unit); +el_val_t time_diff(el_val_t ts1, el_val_t ts2, el_val_t unit); +el_val_t now_ns(void); + +/* ── Instant + Duration: first-class temporal types ────────────────────────── + * Both types share the el_val_t (int64) slot. Instants are nanoseconds + * since the Unix epoch; Durations are signed nanoseconds. Type discipline + * is enforced at codegen-time: BinOps on names registered as Instant or + * Duration route through the typed wrappers below; mismatches like + * Instant+Instant become #error at the C compiler. + * + * Postfix literals — `30.seconds`, `1.hour`, `500.millis`, `30.nanos` — are + * recognised by the parser as DurationLit AST nodes and lowered to literal + * int64 nanoseconds at codegen time. The runtime never sees the units. */ + +el_val_t el_now_instant(void); +el_val_t now(void); +el_val_t unix_seconds(el_val_t n); +el_val_t unix_millis(el_val_t n); +el_val_t instant_from_iso8601(el_val_t s); + +el_val_t el_duration_from_nanos(el_val_t ns); +el_val_t duration_seconds(el_val_t n); +el_val_t duration_millis(el_val_t n); +el_val_t duration_nanos(el_val_t n); + +el_val_t el_instant_add_dur(el_val_t inst, el_val_t dur); +el_val_t el_instant_sub_dur(el_val_t inst, el_val_t dur); +el_val_t el_instant_diff(el_val_t a, el_val_t b); +el_val_t el_duration_add(el_val_t a, el_val_t b); +el_val_t el_duration_sub(el_val_t a, el_val_t b); +el_val_t el_duration_scale(el_val_t dur, el_val_t scalar); +el_val_t el_duration_div(el_val_t dur, el_val_t scalar); + +el_val_t el_instant_lt(el_val_t a, el_val_t b); +el_val_t el_instant_le(el_val_t a, el_val_t b); +el_val_t el_instant_gt(el_val_t a, el_val_t b); +el_val_t el_instant_ge(el_val_t a, el_val_t b); +el_val_t el_instant_eq(el_val_t a, el_val_t b); +el_val_t el_instant_ne(el_val_t a, el_val_t b); +el_val_t el_duration_lt(el_val_t a, el_val_t b); +el_val_t el_duration_le(el_val_t a, el_val_t b); +el_val_t el_duration_gt(el_val_t a, el_val_t b); +el_val_t el_duration_ge(el_val_t a, el_val_t b); +el_val_t el_duration_eq(el_val_t a, el_val_t b); +el_val_t el_duration_ne(el_val_t a, el_val_t b); + +el_val_t instant_to_unix_seconds(el_val_t i); +el_val_t instant_to_unix_millis(el_val_t i); +el_val_t instant_to_iso8601(el_val_t i); +el_val_t duration_to_seconds(el_val_t d); +el_val_t duration_to_millis(el_val_t d); +el_val_t duration_to_nanos(el_val_t d); + +el_val_t el_sleep_duration(el_val_t dur); +el_val_t unix_timestamp(void); + +el_val_t ttl_cache_set(el_val_t key, el_val_t value); +el_val_t ttl_cache_get(el_val_t key, el_val_t max_age); +el_val_t ttl_cache_age(el_val_t key); + +/* ── Calendar + CalendarTime + Rhythm + LocalDate/Time/DateTime ───────────── + * Phase 1.5 of the time system. Calendar is pluggable: EarthCalendar (IANA + * zones, Gregorian, DST) is the user-facing default; MarsCalendar, + * CycleCalendar(period), NoCycleCalendar, RelativeCalendar handle non-Earth + * domains. + * + * A Calendar interprets an Instant under a particular cycle convention and + * produces a CalendarTime. CalendarTime carries the underlying Instant and + * a back-pointer to its Calendar; arithmetic and formatting consult the + * Calendar to convert ns since epoch into year/month/day/hour/minute/second + * (or sol/phase, or cycle/phase, depending on kind). + * + * Storage convention: Calendar / CalendarTime / Rhythm / LocalDate / + * LocalDateTime are heap-allocated structs whose pointers are cast into + * el_val_t. A 24-bit magic header at offset 0 lets the runtime identify + * the kind safely. LocalTime is small enough to live in the int64 slot + * directly (nanos since midnight, signed). */ + +/* Zone — opaque IANA zone or fixed offset, used by EarthCalendar. + * `zone_id` is either an IANA name ("America/New_York", "UTC") or a fixed + * offset string ("+05:30", "-08:00"). The runtime resolves it via tzset() + * on first use of the owning EarthCalendar. */ +el_val_t zone(el_val_t id); +el_val_t zone_utc(void); +el_val_t zone_local(void); +el_val_t zone_offset(el_val_t hours, el_val_t minutes); + +/* Calendar constructors. Each returns an el_val_t pointer to a heap- + * allocated, magic-tagged Calendar struct. Calendars are interned by + * (kind, zone_id, period_ns, epoch_ns) so identical constructors return + * the same pointer — equality is reference equality. */ +el_val_t earth_calendar(el_val_t z); +el_val_t earth_calendar_default(void); +el_val_t mars_calendar(void); +el_val_t cycle_calendar(el_val_t period_dur); +el_val_t no_cycle_calendar(void); +el_val_t relative_calendar(el_val_t epoch_inst); + +/* CalendarTime constructors and methods. Returns a heap-allocated struct + * whose pointer fits in el_val_t. */ +el_val_t now_in(el_val_t cal); +el_val_t in_calendar(el_val_t inst, el_val_t cal); +el_val_t cal_format(el_val_t ct, el_val_t pattern); +el_val_t cal_to_instant(el_val_t ct); +el_val_t cal_cycle_phase(el_val_t ct); +el_val_t cal_in(el_val_t ct, el_val_t cal); + +/* LocalDate / LocalTime / LocalDateTime — calendar-agnostic value types. + * LocalTime carries nanoseconds since midnight as a signed int64 directly + * in the el_val_t slot (no allocation). LocalDate / LocalDateTime are + * heap-allocated structs with magic headers. */ +el_val_t local_date(el_val_t y, el_val_t m, el_val_t d); +el_val_t local_time(el_val_t h, el_val_t m, el_val_t s, el_val_t ns); +el_val_t local_datetime(el_val_t date, el_val_t time); +el_val_t zoned(el_val_t date, el_val_t time, el_val_t cal); + +el_val_t local_date_year(el_val_t ld); +el_val_t local_date_month(el_val_t ld); +el_val_t local_date_day(el_val_t ld); +el_val_t local_time_hour(el_val_t lt); +el_val_t local_time_minute(el_val_t lt); +el_val_t local_time_second(el_val_t lt); +el_val_t local_time_nanos(el_val_t lt); + +el_val_t el_local_date_add_dur(el_val_t ld, el_val_t dur); +el_val_t el_local_time_add_dur(el_val_t lt, el_val_t dur); +el_val_t el_local_date_lt(el_val_t a, el_val_t b); +el_val_t el_local_date_eq(el_val_t a, el_val_t b); + +/* Rhythm — pluggable recurrence AST. Returns a heap-allocated struct + * pointer in el_val_t; rhythms are immutable so callers may share them. */ +el_val_t rhythm_cycle_start(void); +el_val_t rhythm_cycle_phase(el_val_t phase); +el_val_t rhythm_duration(el_val_t d); +el_val_t rhythm_session_start(void); +el_val_t rhythm_event(el_val_t name); +el_val_t rhythm_and(el_val_t a, el_val_t b); +el_val_t rhythm_or(el_val_t a, el_val_t b); +el_val_t rhythm_weekday(el_val_t day); +el_val_t rhythm_weekly_at(el_val_t day, el_val_t hour, el_val_t minute); +el_val_t rhythm_next_after(el_val_t r, el_val_t after, el_val_t cal); +el_val_t rhythm_matches(el_val_t r, el_val_t ct); + +/* ── UUID ────────────────────────────────────────────────────────────────── */ + +el_val_t uuid_new(void); +el_val_t uuid_v4(void); + +/* ── Environment ─────────────────────────────────────────────────────────── */ + +el_val_t env(el_val_t key); + +/* ── In-process state K/V ────────────────────────────────────────────────── */ + +el_val_t state_set(el_val_t key, el_val_t value); +el_val_t state_get(el_val_t key); +el_val_t state_del(el_val_t key); +el_val_t state_keys(void); +el_val_t state_has(el_val_t key); +el_val_t state_get_or(el_val_t key, el_val_t default_val); + +/* ── Float formatting ────────────────────────────────────────────────────── */ + +el_val_t float_to_str(el_val_t f); +el_val_t int_to_float(el_val_t n); +el_val_t float_to_int(el_val_t f); +el_val_t format_float(el_val_t f, el_val_t decimals); +el_val_t decimal_round(el_val_t f, el_val_t decimals); +el_val_t str_to_float(el_val_t s); + +/* ── Math (Float-aware) ──────────────────────────────────────────────────── */ + +el_val_t math_sqrt(el_val_t f); +el_val_t math_log(el_val_t f); +el_val_t math_ln(el_val_t f); +el_val_t math_sin(el_val_t f); +el_val_t math_cos(el_val_t f); +el_val_t math_pi(void); + +/* ── String additions ────────────────────────────────────────────────────── */ + +el_val_t str_index_of(el_val_t s, el_val_t sub); +el_val_t str_split(el_val_t s, el_val_t sep); +el_val_t str_char_at(el_val_t s, el_val_t i); +el_val_t str_char_code(el_val_t s, el_val_t i); +el_val_t str_pad_left(el_val_t s, el_val_t width, el_val_t pad); +el_val_t str_pad_right(el_val_t s, el_val_t width, el_val_t pad); +el_val_t str_format(el_val_t fmt, el_val_t data); +el_val_t str_lower(el_val_t s); +el_val_t str_upper(el_val_t s); + +/* ── Text-processing primitives (Phase 1: byte/codepoint, ASCII char classes) + * Phase 2 (filed): Unicode-grapheme awareness, NFC/NFD normalization, regex. + * is_* predicates: empty input returns false; multi-char requires ALL bytes + * to match. ASCII ranges only in Phase 1. */ + +/* Counting */ +el_val_t str_count(el_val_t s, el_val_t sub); /* non-overlapping */ +el_val_t str_count_chars(el_val_t s); /* codepoint count */ +el_val_t str_count_bytes(el_val_t s); /* alias of str_len */ +el_val_t str_count_lines(el_val_t s); +el_val_t str_count_words(el_val_t s); +el_val_t str_count_letters(el_val_t s); /* ASCII [A-Za-z] */ +el_val_t str_count_digits(el_val_t s); /* ASCII [0-9] */ + +/* Find / position */ +el_val_t str_index_of_all(el_val_t s, el_val_t sub); /* [Int] of byte offsets */ +el_val_t str_last_index_of(el_val_t s, el_val_t sub); +el_val_t str_find_chars(el_val_t s, el_val_t any_of); /* first idx of any ch */ + +/* Transform */ +el_val_t str_repeat(el_val_t s, el_val_t n); +el_val_t str_reverse(el_val_t s); /* by codepoint */ +el_val_t str_strip_prefix(el_val_t s, el_val_t prefix); +el_val_t str_strip_suffix(el_val_t s, el_val_t suffix); +el_val_t str_strip_chars(el_val_t s, el_val_t chars); +el_val_t str_lstrip(el_val_t s); +el_val_t str_rstrip(el_val_t s); + +/* Char classification (Bool) */ +el_val_t is_letter(el_val_t s); +el_val_t is_digit(el_val_t s); +el_val_t is_alphanumeric(el_val_t s); +el_val_t is_whitespace(el_val_t s); +el_val_t is_punctuation(el_val_t s); +el_val_t is_uppercase(el_val_t s); +el_val_t is_lowercase(el_val_t s); + +/* Split / join */ +el_val_t str_split_lines(el_val_t s); +el_val_t str_split_chars(el_val_t s); /* alias of native_string_chars */ +el_val_t str_split_n(el_val_t s, el_val_t sep, el_val_t n); +el_val_t str_join(el_val_t list, el_val_t sep); /* alias of list_join */ + +/* ── List additions ──────────────────────────────────────────────────────── */ + +el_val_t list_push(el_val_t list, el_val_t elem); +el_val_t list_push_front(el_val_t list, el_val_t elem); +el_val_t list_join(el_val_t list, el_val_t sep); +el_val_t list_range(el_val_t start, el_val_t end); + +/* ── Bool helpers ────────────────────────────────────────────────────────── */ + +el_val_t bool_to_str(el_val_t b); + +/* ── Numeric parsing ─────────────────────────────────────────────────────── */ + +el_val_t parse_int(el_val_t s, el_val_t default_val); + +/* ── Process ─────────────────────────────────────────────────────────────── */ + +el_val_t exit_program(el_val_t code); +el_val_t getpid_now(void); + +/* Self-terminating memory guard. Reads ELC_MAX_MEM_MB (default 512) and + * exits with code 1 if resident memory exceeds the limit. Call periodically + * during long compilation loops (e.g. after each function is compiled). + * Returns 0 when memory is within bounds. */ +el_val_t el_mem_check(void); + +/* ── CGI identity ───────────────────────────────────────────────────────────── + * Called at the start of main() in CGI programs (those with a `cgi {}` block). + * Records the program's DHARMA identity before any other code executes. */ + +void el_cgi_init(el_val_t name, el_val_t dharma_id, el_val_t principal, + el_val_t network, el_val_t engram); + +/* ── DHARMA network builtins ───────────────────────────────────────────────── + * Available to CGI programs (declared with a `cgi {}` block). + * + * Peers are addressed by `dharma_id` of the form + * "@" e.g. "ntn-genesis@http://localhost:7770" + * If the @ portion is omitted, transport defaults to + * "http://localhost:7770" (the local CGI daemon assumption). + * + * Wire protocol (all peers expose): + * POST /dharma/recv { channel, from, content } → response body + * POST /dharma/event { type, payload, source, timestamp } + * POST /api/activate { query } → list of nodes + * + * Hosting application's responsibility: an El program with a `cgi {}` block + * runs http_serve() with its own request handler; that handler should route + * "/dharma/event" requests by calling el_runtime_dharma_event_arrive() so + * incoming events feed dharma_field() queues. The runtime itself does not + * intercept any /dharma path. */ + +el_val_t dharma_connect(el_val_t cgi_id); +el_val_t dharma_send(el_val_t channel, el_val_t content); +el_val_t dharma_activate(el_val_t query); +void dharma_emit(el_val_t event_type, el_val_t payload); +el_val_t dharma_field(el_val_t event_type); +void dharma_strengthen(el_val_t cgi_id, el_val_t weight); +el_val_t dharma_relationship(el_val_t cgi_id); +el_val_t dharma_peers(void); + +/* Public C API: called by an El program's HTTP handler when a /dharma/event + * request arrives. Pushes onto the per-event-type queue and signals any + * pending dharma_field() blockers. All three arguments must be NUL-terminated + * C strings (or NULL — then treated as empty). */ +void el_runtime_dharma_event_arrive(const char* event_type, + const char* payload, + const char* source); + +/* ── Engram local graph primitives ─────────────────────────────────────────── + * Operate on the CGI's local Engram knowledge graph. + * `engram_activate` queries the local graph only; `dharma_activate` is + * network-wide across all connected CGI graphs. */ + +el_val_t engram_node(el_val_t content, el_val_t node_type, el_val_t salience); +el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags); +/* Layered consciousness — see el_runtime.c for the layered architecture + * design notes (search "Layered consciousness architecture"). The five + * canonical layers (safety / core-identity / domain-knowledge / imprint / + * suit) are seeded automatically; engram_add_layer extends the registry + * with imprint or suit overlays at runtime. Nodes default to layer 1 + * (core-identity) when created via engram_node / engram_node_full. */ +el_val_t engram_node_layered(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t certainty, el_val_t confidence, + el_val_t status, el_val_t tags, el_val_t layer_id); +el_val_t engram_add_layer(el_val_t name, el_val_t priority, el_val_t suppressible, + el_val_t transparent, el_val_t injectable); +el_val_t engram_remove_layer(el_val_t layer_id); +el_val_t engram_list_layers(void); +el_val_t engram_get_node(el_val_t id); +void engram_strengthen(el_val_t node_id); +void engram_forget(el_val_t node_id); +el_val_t engram_node_count(void); +el_val_t engram_search(el_val_t query, el_val_t limit); +el_val_t engram_scan_nodes(el_val_t limit, el_val_t offset); +void engram_connect(el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t relation); +el_val_t engram_edge_between(el_val_t from_id, el_val_t to_id); +el_val_t engram_neighbors(el_val_t node_id); +el_val_t engram_neighbors_filtered(el_val_t node_id, el_val_t max_depth, el_val_t direction); +el_val_t engram_edge_count(void); +/* Three-pass activation: background fan-out → working-memory promotion → + * Layer 0 override. See "Three-pass activation" in el_runtime.c. */ +el_val_t engram_activate(el_val_t query, el_val_t depth); +el_val_t engram_save(el_val_t path); +el_val_t engram_load(el_val_t path); + +/* JSON-string accessors — return pre-serialized JSON so HTTP handlers + * can pass results straight through without round-tripping ElList/ElMap + * through json_stringify. */ +el_val_t engram_get_node_json(el_val_t id); +el_val_t engram_search_json(el_val_t query, el_val_t limit); +el_val_t engram_scan_nodes_json(el_val_t limit, el_val_t offset); +el_val_t engram_scan_nodes_by_type_json(el_val_t node_type, el_val_t limit, el_val_t offset); +el_val_t engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction); +el_val_t engram_activate_json(el_val_t query, el_val_t depth); +el_val_t engram_stats_json(void); +el_val_t engram_list_layers_json(void); +/* engram_compile_layered_json — produce a prompt-ready text block split + * into "[LAYER 0 — STRUCTURAL]" (non-suppressible layers, sacred fire) + * and "[ENGRAM CONTEXT]" (standard suppressible layers). Returns "" if + * no nodes promoted to working memory. */ +el_val_t engram_compile_layered_json(el_val_t intent, el_val_t depth); + +/* ── LLM (Anthropic API client) ───────────────────────────────────────────── + * All functions call https://api.anthropic.com/v1/messages with the API key + * from env ANTHROPIC_API_KEY. Default model when empty: claude-sonnet-4-5. */ + +el_val_t llm_call(el_val_t model, el_val_t prompt); +el_val_t llm_call_system(el_val_t model, el_val_t system_prompt, el_val_t user_prompt); +el_val_t llm_call_agentic(el_val_t model, el_val_t system, el_val_t user, el_val_t tools); +el_val_t llm_vision(el_val_t model, el_val_t system, el_val_t prompt, el_val_t image_url_or_b64); +el_val_t llm_models(void); + +/* Register a tool handler by name. The handler is looked up via dlsym + * (mirroring http_set_handler), so any El `fn (input)` compiles to + * a global C symbol that this function can locate at runtime. + * Handler signature: `el_val_t handler(el_val_t input_json)` — receives + * the tool input as a JSON-string el_val_t and returns a JSON-string + * el_val_t result. Used by llm_call_agentic. */ +void llm_register_tool(el_val_t name, el_val_t handler_fn_name); + +/* ── args() ───────────────────────────────────────────────────────────────── + * Provides access to command-line arguments passed to the program. + * Populated by el_runtime_init_args() before main() runs. */ + +el_val_t args(void); +void el_runtime_init_args(int argc, char** argv); + +/* ── Crypto primitives ───────────────────────────────────────────────────── + * SHA-256, HMAC-SHA-256, and base64 (standard + URL-safe). + * Self-contained — no OpenSSL/libcrypto dependency. The implementations are + * adapted from public-domain reference code (Brad Conte / RFC 4648). + * + * Bytes-returning variants (sha256_bytes, hmac_sha256_bytes) return a string + * value whose contents are raw binary; callers usually feed these into + * base64_encode. Note that el_val_t strings are NUL-terminated by convention, + * so the binary payload may contain embedded NULs — pass it directly into + * base64_encode (which uses an explicit length) rather than treating it as + * a printable C string. + * + * The "base64" variants emit/accept RFC 4648 standard alphabet with padding. + * The "base64url" variants use URL-safe alphabet (`-`/`_`) with no padding, + * as used in JWTs. */ + +el_val_t sha256_hex(el_val_t input); +el_val_t sha256_bytes(el_val_t input); +el_val_t hmac_sha256_hex(el_val_t key, el_val_t message); +el_val_t hmac_sha256_bytes(el_val_t key, el_val_t message); +el_val_t base64_encode(el_val_t input); +el_val_t base64_decode(el_val_t input); +el_val_t base64url_encode(el_val_t input); +el_val_t base64url_decode(el_val_t input); + +/* Length-aware variants (internal — exposed for the rare caller that already + * has a known-length binary buffer and doesn't want to round-trip through + * a NUL-terminated el_val_t string). Sha256_bytes and hmac_sha256_bytes feed + * these implicitly. */ +el_val_t el_sha256_bytes_n(const unsigned char* data, size_t len); +el_val_t el_base64_encode_n(const unsigned char* data, size_t len, int url_safe); + +/* ── Post-quantum primitives (liboqs-backed) ──────────────────────────────── + * All inputs/outputs hex-encoded. Algorithm choices: + * Signature: CRYSTALS-Dilithium-3 (NIST level 3, balanced) + * KEM: CRYSTALS-Kyber-768 (NIST level 3) + * Hash: SHA3-256 (Keccak) (PQ-aware protocols favour SHA3 over SHA2) + * + * If liboqs is not linked (detected via __has_include() at compile + * time), the pq_* entry points return a JSON-shaped error string so callers + * fail loudly rather than silently fall back to classical schemes: + * {"error":"liboqs not linked, post-quantum primitives unavailable"} + * + * The hybrid handshake pairs X25519 with Kyber-768 per NIST PQ guidance and + * CNSA 2.0. Combined shared secret is HKDF-SHA256(x25519_ss || kyber_ss). + * Even if Kyber falls, X25519 holds; if X25519 falls under quantum attack, + * Kyber holds. SHA3-256 also remains usable independent of liboqs (the + * Keccak permutation is PQ-OK as a primitive). */ + +el_val_t pq_keygen_signature(void); +el_val_t pq_sign(el_val_t secret_key_hex, el_val_t message); +el_val_t pq_verify(el_val_t public_key_hex, el_val_t message, el_val_t signature_hex); + +el_val_t pq_kem_keygen(void); +el_val_t pq_kem_encaps(el_val_t public_key_hex); +el_val_t pq_kem_decaps(el_val_t secret_key_hex, el_val_t ciphertext_hex); + +el_val_t pq_hybrid_keygen(void); +el_val_t pq_hybrid_handshake(el_val_t remote_pub_combined); + +el_val_t sha3_256_hex(el_val_t input); + +/* ── AEAD: AES-256-GCM (libcrypto-backed) ─────────────────────────────────── + * Symmetric authenticated encryption used to wrap envelopes after a KEM + * handshake. Caller MUST supply a 32-byte key (64 hex chars) — typically the + * Kyber-768 / hybrid shared_secret, optionally normalized via SHA3-256. + * + * aead_encrypt returns a JSON map {"nonce":"...","ciphertext":"..."} where + * ciphertext is the AES-256-GCM output with the 16-byte auth tag appended. + * Nonce is a fresh 12-byte CSPRNG draw — callers never pick the nonce, which + * structurally rules out the GCM nonce-reuse footgun. + * + * aead_decrypt returns the plaintext String, or "" on any failure (including + * auth-tag mismatch). Callers MUST check for "" before trusting the result. */ +el_val_t aead_encrypt(el_val_t key_hex, el_val_t plaintext); +el_val_t aead_decrypt(el_val_t key_hex, el_val_t nonce_hex, el_val_t ciphertext_hex); + +/* ── Native VM builtin aliases (for compiled El source) ───────────────────── + * These match the El VM's native_* builtins so that El source compiled + * to C can call the same names without modification. */ + +el_val_t native_list_get(el_val_t list, el_val_t index); +el_val_t native_list_len(el_val_t list); +el_val_t native_list_append(el_val_t list, el_val_t elem); +el_val_t native_list_empty(void); +el_val_t native_list_clone(el_val_t list); +el_val_t native_string_chars(el_val_t s); +el_val_t native_int_to_str(el_val_t n); + +/* ── Method-call shorthand aliases ────────────────────────────────────────── + * The El method-call convention `obj.method(args)` compiles to + * `method(obj, args)`. These aliases expose the runtime functions under + * the short names that result from method calls in El source. + * + * Example: `myList.append(x)` → `append(myList, x)` (calls this alias) + * `myList.len()` → `len(myList)` (calls this alias) */ + +el_val_t append(el_val_t list, el_val_t elem); /* el_list_append */ +el_val_t len(el_val_t list); /* el_list_len */ +el_val_t get(el_val_t list, el_val_t index); /* el_list_get */ +el_val_t map_get(el_val_t map, el_val_t key); /* el_map_get */ +el_val_t map_set(el_val_t map, el_val_t key, el_val_t value); /* el_map_set */ + +/* ── OTLP/HTTP Observability ─────────────────────────────────────────────── */ +/* See bottom of el_runtime.c for the implementation. + * Configured by env vars OTLP_ENDPOINT, OTEL_SERVICE_NAME, OTEL_SERVICE_VERSION. + * No-op when OTLP_ENDPOINT is unset. Drop-on-failure semantics. */ +/* ── Subprocess execution ────────────────────────────────────────────────── */ +el_val_t exec_command(el_val_t cmd); /* run shell command, return exit code */ +el_val_t exec_capture(el_val_t cmd); /* run shell command, capture stdout */ +el_val_t exec(el_val_t cmd); /* exec(cmd) → stdout String (30s timeout) */ +el_val_t exec_bg(el_val_t cmd); /* exec_bg(cmd) → PID String (non-blocking) */ + +/* ── Stdout redirection (used by compiler JS pipeline) ───────────────────── */ +el_val_t stdout_to_file(el_val_t path); /* redirect process stdout to a file */ +el_val_t stdout_restore(void); /* restore process stdout to terminal */ + +el_val_t emit_log(el_val_t level, el_val_t msg, el_val_t fields_json); +el_val_t emit_metric(el_val_t name, el_val_t value, el_val_t tags_json); +el_val_t trace_span_start(el_val_t name); +el_val_t trace_span_end(el_val_t span_handle); +el_val_t emit_event(el_val_t name, el_val_t duration_ms); + +el_val_t __thread_create(el_val_t fn_name_v, el_val_t arg_v); +el_val_t __thread_join(el_val_t tid_v); + +/* ── __ prefixed aliases (self-hosting compiler ABI) ───────────────────────── + * The El self-hosting compiler emits calls to __-prefixed names. These are + * forwarding wrappers around the existing el_runtime functions above. */ + +/* I/O */ +el_val_t __println(el_val_t s); +el_val_t __print(el_val_t s); +el_val_t __readline(void); + +/* String */ +el_val_t __int_to_str(el_val_t n); +el_val_t __str_to_int(el_val_t s); +el_val_t __float_to_str(el_val_t f); +el_val_t __str_to_float(el_val_t s); +el_val_t __str_len(el_val_t s); +el_val_t __str_char_at(el_val_t s, el_val_t i); +el_val_t __str_cmp(el_val_t a, el_val_t b); +el_val_t __str_ncmp(el_val_t a, el_val_t b, el_val_t n); +el_val_t __str_concat_raw(el_val_t a, el_val_t b); +el_val_t __str_slice_raw(el_val_t s, el_val_t start, el_val_t end); +el_val_t __str_alloc(el_val_t n); +el_val_t __str_set_char(el_val_t s, el_val_t i, el_val_t c); + +/* URL encoding */ +el_val_t __url_encode(el_val_t s); +el_val_t __url_decode(el_val_t s); + +/* Environment */ +el_val_t __env_get(el_val_t key); + +/* Subprocess */ +el_val_t __exec(el_val_t cmd); +el_val_t __exec_bg(el_val_t cmd); + +/* Process */ +el_val_t __exit_program(el_val_t code); + +/* Filesystem */ +el_val_t __fs_exists(el_val_t path); +el_val_t __fs_mkdir(el_val_t path); +el_val_t __fs_read(el_val_t path); +el_val_t __fs_write(el_val_t path, el_val_t content); +el_val_t __fs_write_bytes(el_val_t path, el_val_t bytes, el_val_t n); +el_val_t __fs_list_raw(el_val_t path); + +/* HTTP server */ +el_val_t __http_response(el_val_t status, el_val_t headers_json, el_val_t body); +el_val_t __http_serve(el_val_t port, el_val_t handler); +el_val_t __http_serve_v2(el_val_t port, el_val_t handler); + +/* HTTP conn fd / SSE (weak; overridden by el_seed.c when linked together) */ +el_val_t __http_conn_fd(void); +el_val_t __http_sse_open(el_val_t conn_id); +el_val_t __http_sse_send(el_val_t conn_id, el_val_t data); +el_val_t __http_sse_close(el_val_t conn_id); + +/* HTTP client (requires HAVE_CURL; stubs provided for no-curl builds) */ +el_val_t __http_do(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_map, el_val_t timeout_ms); +el_val_t __http_do_map(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t timeout_ms); +el_val_t __http_do_map_to_file(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t output_path); + +/* JSON */ +el_val_t __json_array_get(el_val_t json, el_val_t index); +el_val_t __json_array_get_string(el_val_t json, el_val_t index); +el_val_t __json_array_len(el_val_t json); +el_val_t __json_get(el_val_t json, el_val_t key); +el_val_t __json_get_raw(el_val_t json, el_val_t key); +el_val_t __json_set(el_val_t json, el_val_t key, el_val_t value); +el_val_t __json_parse_map(el_val_t json_str); +el_val_t __json_stringify_val(el_val_t val); + +/* Hashing */ +el_val_t __sha256_hex(el_val_t s); + +/* State K/V */ +el_val_t __state_del(el_val_t key); +el_val_t __state_get(el_val_t key); +el_val_t __state_keys(void); +el_val_t __state_set(el_val_t key, el_val_t val); + +/* UUID */ +el_val_t __uuid_v4(void); + +/* Args */ +el_val_t __args_json(void); + +#ifdef __cplusplus +} +#endif diff --git a/ui/examples/native-hello/build-docker/runtime/el_seed.c b/ui/examples/native-hello/build-docker/runtime/el_seed.c new file mode 100644 index 0000000..fc9fbba --- /dev/null +++ b/ui/examples/native-hello/build-docker/runtime/el_seed.c @@ -0,0 +1,1942 @@ +/* + * el_seed.c — El language seed runtime: minimal C OS boundary + * + * This file exposes all OS-boundary primitives that El programs need, under + * the __ prefix convention. It is self-contained: all allocators, arena + * management, and el_request_start / el_request_end are defined here. + * + * Threading: __thread_create / __thread_join use dlsym(RTLD_DEFAULT) to look + * up El function symbols at runtime. This is the foundation of El's parallelism. + * + * Link: cc -std=c11 -I el-compiler/runtime -lcurl -lpthread \ + * -o .c el_seed.c + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "el_seed.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* ── Private allocator ───────────────────────────────────────────────────── */ +/* + * el_seed.c carries its own arena for per-request allocation tracking. + * The arena is reset at el_request_start / el_request_end, which are defined + * below and delegate to seed_request_start / seed_request_end. + */ + +#define SEED_ARENA_INITIAL 512 + +typedef struct { + char** ptrs; + size_t count; + size_t cap; +} SeedArena; + +static _Thread_local SeedArena _seed_arena = {NULL, 0, 0}; +static _Thread_local int _seed_arena_on = 0; + +static void seed_arena_track(char* p) { + if (!_seed_arena_on || !p) return; + if (_seed_arena.count >= _seed_arena.cap) { + size_t nc = _seed_arena.cap == 0 ? SEED_ARENA_INITIAL : _seed_arena.cap * 2; + char** g = realloc(_seed_arena.ptrs, nc * sizeof(char*)); + if (!g) return; + _seed_arena.ptrs = g; + _seed_arena.cap = nc; + } + _seed_arena.ptrs[_seed_arena.count++] = p; +} + +static void seed_request_start(void) { + _seed_arena.count = 0; + _seed_arena_on = 1; +} + +static void seed_request_end(void) { + _seed_arena_on = 0; + for (size_t i = 0; i < _seed_arena.count; i++) free(_seed_arena.ptrs[i]); + _seed_arena.count = 0; +} + +/* el_request_start / el_request_end — formerly defined in el_runtime.c. + * Now self-contained in el_seed.c, delegating to the seed arena. */ +void el_request_start(void) { seed_request_start(); } +void el_request_end(void) { seed_request_end(); } + +/* Persistent alloc — bypasses arena (state, engram internals). */ +static char* seed_strdup_persist(const char* s) { + if (!s) return strdup(""); + return strdup(s); +} + +static char* seed_strdup(const char* s) { + char* p = strdup(s ? s : ""); + seed_arena_track(p); + return p; +} + +static char* seed_strbuf(size_t n) { + char* p = malloc(n + 1); + if (!p) { fputs("el_seed: out of memory\n", stderr); exit(1); } + p[0] = '\0'; + seed_arena_track(p); + return p; +} + +static el_val_t seed_wrap_str(char* s) { return EL_STR(s); } + +/* ── String primitives ───────────────────────────────────────────────────── */ + +el_val_t __str_len(el_val_t s) { + const char* p = EL_CSTR(s); + if (!p) return 0; + return (el_val_t)strlen(p); +} + +el_val_t __str_char_at(el_val_t s, el_val_t i) { + const char* p = EL_CSTR(s); + if (!p) return 0; + int64_t len = (int64_t)strlen(p); + int64_t idx = (int64_t)i; + if (idx < 0 || idx >= len) return 0; + return (el_val_t)(unsigned char)p[idx]; +} + +el_val_t __str_alloc(el_val_t n) { + int64_t sz = (int64_t)n; + if (sz < 0) sz = 0; + char* buf = seed_strbuf((size_t)sz); + memset(buf, 0, (size_t)sz + 1); + return seed_wrap_str(buf); +} + +el_val_t __str_set_char(el_val_t s, el_val_t i, el_val_t c) { + char* p = (char*)(uintptr_t)s; + if (!p) return s; + int64_t len = (int64_t)strlen(p); + int64_t idx = (int64_t)i; + if (idx < 0 || idx >= len) return s; + p[idx] = (char)(unsigned char)(int64_t)c; + return s; +} + +el_val_t __str_cmp(el_val_t a, el_val_t b) { + const char* sa = EL_CSTR(a); + const char* sb = EL_CSTR(b); + if (!sa) sa = ""; + if (!sb) sb = ""; + return (el_val_t)strcmp(sa, sb); +} + +el_val_t __str_ncmp(el_val_t a, el_val_t b, el_val_t n) { + const char* sa = EL_CSTR(a); + const char* sb = EL_CSTR(b); + if (!sa) sa = ""; + if (!sb) sb = ""; + return (el_val_t)strncmp(sa, sb, (size_t)(int64_t)n); +} + +el_val_t __str_concat_raw(el_val_t a, el_val_t b) { + const char* sa = EL_CSTR(a); + const char* sb = EL_CSTR(b); + if (!sa) sa = ""; + if (!sb) sb = ""; + size_t la = strlen(sa), lb = strlen(sb); + char* out = seed_strbuf(la + lb); + memcpy(out, sa, la); + memcpy(out + la, sb, lb); + out[la + lb] = '\0'; + return seed_wrap_str(out); +} + +el_val_t __str_slice_raw(el_val_t s, el_val_t start, el_val_t end) { + const char* p = EL_CSTR(s); + if (!p) return seed_wrap_str(seed_strdup("")); + int64_t len = (int64_t)strlen(p); + int64_t st = (int64_t)start; + int64_t en = (int64_t)end; + if (st < 0) st = 0; + if (en > len) en = len; + if (st >= en) return seed_wrap_str(seed_strdup("")); + int64_t sz = en - st; + char* out = seed_strbuf((size_t)sz); + memcpy(out, p + st, (size_t)sz); + out[sz] = '\0'; + return seed_wrap_str(out); +} + +el_val_t __int_to_str(el_val_t n) { + char buf[32]; + snprintf(buf, sizeof(buf), "%lld", (long long)(int64_t)n); + return seed_wrap_str(seed_strdup(buf)); +} + +el_val_t __str_to_int(el_val_t s) { + const char* p = EL_CSTR(s); + if (!p) return 0; + return (el_val_t)atoll(p); +} + +el_val_t __float_to_str(el_val_t f) { + char buf[64]; + snprintf(buf, sizeof(buf), "%g", el_to_float(f)); + return seed_wrap_str(seed_strdup(buf)); +} + +el_val_t __str_to_float(el_val_t s) { + const char* p = EL_CSTR(s); + if (!p) return el_from_float(0.0); + return el_from_float(strtod(p, NULL)); +} + +/* ── I/O ─────────────────────────────────────────────────────────────────── */ + +void __println(el_val_t s) { + const char* p = EL_CSTR(s); + puts(p ? p : ""); +} + +void __print(el_val_t s) { + const char* p = EL_CSTR(s); + if (p) fputs(p, stdout); +} + +el_val_t __readline(void) { + char buf[4096]; + if (!fgets(buf, sizeof(buf), stdin)) return seed_wrap_str(seed_strdup("")); + size_t len = strlen(buf); + if (len > 0 && buf[len - 1] == '\n') buf[len - 1] = '\0'; + return seed_wrap_str(seed_strdup(buf)); +} + +/* ── Filesystem ──────────────────────────────────────────────────────────── */ + +el_val_t __fs_read(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p) return seed_wrap_str(seed_strdup("")); + FILE* f = fopen(p, "rb"); + if (!f) return seed_wrap_str(seed_strdup("")); + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + if (sz < 0) { fclose(f); return seed_wrap_str(seed_strdup("")); } + char* buf = seed_strbuf((size_t)sz); + size_t got = fread(buf, 1, (size_t)sz, f); + buf[got] = '\0'; + fclose(f); + return seed_wrap_str(buf); +} + +el_val_t __fs_write(el_val_t path, el_val_t content) { + const char* p = EL_CSTR(path); + const char* c = EL_CSTR(content); + if (!p || !c) return 0; + FILE* f = fopen(p, "wb"); + if (!f) return 0; + size_t n = strlen(c); + size_t w = fwrite(c, 1, n, f); + fclose(f); + return w == n ? 1 : 0; +} + +el_val_t __fs_exists(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p || !*p) return 0; + struct stat st; + return (el_val_t)(stat(p, &st) == 0 ? 1 : 0); +} + +el_val_t __fs_list_raw(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p) return seed_wrap_str(seed_strdup("")); + DIR* d = opendir(p); + if (!d) return seed_wrap_str(seed_strdup("")); + /* Build newline-separated list of filenames. */ + size_t cap = 4096, len = 0; + char* buf = malloc(cap); + if (!buf) { closedir(d); return seed_wrap_str(seed_strdup("")); } + buf[0] = '\0'; + struct dirent* e; + while ((e = readdir(d)) != NULL) { + if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) continue; + size_t nlen = strlen(e->d_name); + while (len + nlen + 2 >= cap) { + cap *= 2; + char* g = realloc(buf, cap); + if (!g) { free(buf); closedir(d); return seed_wrap_str(seed_strdup("")); } + buf = g; + } + if (len > 0) buf[len++] = '\n'; + memcpy(buf + len, e->d_name, nlen); + len += nlen; + buf[len] = '\0'; + } + closedir(d); + seed_arena_track(buf); + return seed_wrap_str(buf); +} + +el_val_t __fs_mkdir(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p || !*p) return 0; + size_t n = strlen(p); + char* buf = malloc(n + 1); + if (!buf) return 0; + memcpy(buf, p, n + 1); + for (size_t i = 1; i <= n; i++) { + if (buf[i] == '/' || buf[i] == '\0') { + char saved = buf[i]; + buf[i] = '\0'; + if (buf[0] != '\0') { + if (mkdir(buf, 0755) != 0 && errno != EEXIST) { + struct stat st; + if (stat(buf, &st) != 0 || !S_ISDIR(st.st_mode)) { + free(buf); return 0; + } + } + } + buf[i] = saved; + } + } + free(buf); + return 1; +} + +el_val_t __fs_write_bytes(el_val_t path, el_val_t bytes, el_val_t n) { + const char* p = EL_CSTR(path); + const char* b = EL_CSTR(bytes); + int64_t sz = (int64_t)n; + if (!p || !b || sz < 0) return 0; + FILE* f = fopen(p, "wb"); + if (!f) return 0; + size_t written = (sz > 0) ? fwrite(b, 1, (size_t)sz, f) : 0; + int ok1 = (fflush(f) == 0); + int ok2 = (fclose(f) == 0); + if (!ok1 || !ok2 || written != (size_t)sz) { remove(p); return 0; } + return 1; +} + +/* ── HTTP client ─────────────────────────────────────────────────────────── */ + +typedef struct { + char* data; + size_t len; + size_t cap; +} SeedHttpBuf; + +static void seed_httpbuf_init(SeedHttpBuf* b) { + b->cap = 1024; b->len = 0; + b->data = malloc(b->cap); + if (!b->data) { fputs("el_seed: out of memory\n", stderr); exit(1); } + b->data[0] = '\0'; +} + +static void seed_httpbuf_append(SeedHttpBuf* b, const void* src, size_t n) { + while (b->len + n + 1 > b->cap) b->cap *= 2; + b->data = realloc(b->data, b->cap); + if (!b->data) { fputs("el_seed: out of memory\n", stderr); exit(1); } + memcpy(b->data + b->len, src, n); + b->len += n; + b->data[b->len] = '\0'; +} + +static size_t seed_http_write_cb(char* ptr, size_t size, size_t nmemb, void* ud) { + size_t n = size * nmemb; + seed_httpbuf_append((SeedHttpBuf*)ud, ptr, n); + return n; +} + +/* Build a curl_slist from a JSON object string of header name:value pairs. */ +static struct curl_slist* seed_headers_from_json(const char* hj) { + struct curl_slist* h = NULL; + if (!hj || !*hj) return NULL; + /* Walk key:value pairs at depth 1. Simple parser — same logic as json_find_key + * in el_runtime.c but adapted for building curl headers. */ + const char* p = hj; + while (*p && *p != '{') p++; + if (*p == '{') p++; + while (*p) { + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',') p++; + if (*p == '}' || *p == '\0') break; + if (*p != '"') break; + /* Parse key */ + p++; + const char* ks = p; + while (*p && *p != '"') { if (*p == '\\') p++; p++; } + size_t klen = (size_t)(p - ks); + if (*p == '"') p++; + /* Skip : */ + while (*p == ' ' || *p == ':') p++; + /* Parse value */ + if (*p != '"') break; + p++; + const char* vs = p; + while (*p && *p != '"') { if (*p == '\\') p++; p++; } + size_t vlen = (size_t)(p - vs); + if (*p == '"') p++; + /* Build "Key: Value" header line */ + size_t line_len = klen + 2 + vlen + 1; + char* line = malloc(line_len); + if (line) { + memcpy(line, ks, klen); + memcpy(line + klen, ": ", 2); + memcpy(line + klen + 2, vs, vlen); + line[klen + 2 + vlen] = '\0'; + h = curl_slist_append(h, line); + free(line); + } + } + return h; +} + +static el_val_t seed_http_error_json(const char* msg) { + if (!msg) msg = "unknown error"; + size_t n = strlen(msg) * 6 + 20; + char* buf = seed_strbuf(n); + /* Simple escape: replace " with \" */ + char* d = buf; + *d++ = '{'; *d++ = '"'; *d++ = 'e'; *d++ = 'r'; *d++ = 'r'; + *d++ = 'o'; *d++ = 'r'; *d++ = '"'; *d++ = ':'; *d++ = '"'; + for (const char* s = msg; *s; s++) { + if (*s == '"' || *s == '\\') *d++ = '\\'; + *d++ = *s; + } + *d++ = '"'; *d++ = '}'; *d = '\0'; + return seed_wrap_str(buf); +} + +el_val_t __http_do(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t timeout_ms) { + const char* m = EL_CSTR(method); + const char* u = EL_CSTR(url); + const char* b = EL_CSTR(body); + const char* hj = EL_CSTR(headers_json); + int64_t tms = (int64_t)timeout_ms; + if (tms <= 0) tms = 60000; + + if (!u || !*u) return seed_http_error_json("empty url"); + + CURL* c = curl_easy_init(); + if (!c) return seed_http_error_json("curl_easy_init failed"); + + SeedHttpBuf rb; seed_httpbuf_init(&rb); + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + + curl_easy_setopt(c, CURLOPT_URL, u); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, seed_http_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, &rb); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, (long)tms); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-seed/1.0"); + + struct curl_slist* hdrs = seed_headers_from_json(hj); + if (hdrs) curl_easy_setopt(c, CURLOPT_HTTPHEADER, hdrs); + + if (m && strcmp(m, "POST") == 0) { + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, b ? b : ""); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(b ? strlen(b) : 0)); + } else if (m && strcmp(m, "PUT") == 0) { + curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, "PUT"); + if (b) { + curl_easy_setopt(c, CURLOPT_POSTFIELDS, b); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)strlen(b)); + } + } else if (m && strcmp(m, "DELETE") == 0) { + curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, "DELETE"); + } else if (m && strcmp(m, "PATCH") == 0) { + curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, "PATCH"); + if (b) { + curl_easy_setopt(c, CURLOPT_POSTFIELDS, b); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)strlen(b)); + } + } + /* GET is the default */ + + CURLcode rc = curl_easy_perform(c); + if (hdrs) curl_slist_free_all(hdrs); + curl_easy_cleanup(c); + + if (rc != CURLE_OK) { + free(rb.data); + const char* em = errbuf[0] ? errbuf : curl_easy_strerror(rc); + return seed_http_error_json(em); + } + + seed_arena_track(rb.data); + return seed_wrap_str(rb.data); +} + +static size_t seed_http_file_write_cb(char* ptr, size_t size, size_t nmemb, void* ud) { + return fwrite(ptr, size, nmemb, (FILE*)ud); +} + +el_val_t __http_do_to_file(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t out_path) { + const char* m = EL_CSTR(method); + const char* u = EL_CSTR(url); + const char* b = EL_CSTR(body); + const char* hj = EL_CSTR(headers_json); + const char* op = EL_CSTR(out_path); + + if (!u || !*u || !op || !*op) return 0; + FILE* f = fopen(op, "wb"); + if (!f) return 0; + + CURL* c = curl_easy_init(); + if (!c) { fclose(f); remove(op); return 0; } + + char errbuf[CURL_ERROR_SIZE]; errbuf[0] = '\0'; + curl_easy_setopt(c, CURLOPT_URL, u); + curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, seed_http_file_write_cb); + curl_easy_setopt(c, CURLOPT_WRITEDATA, f); + curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(c, CURLOPT_TIMEOUT_MS, 60000L); + curl_easy_setopt(c, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(c, CURLOPT_ERRORBUFFER, errbuf); + curl_easy_setopt(c, CURLOPT_USERAGENT, "el-seed/1.0"); + + struct curl_slist* hdrs = seed_headers_from_json(hj); + if (hdrs) curl_easy_setopt(c, CURLOPT_HTTPHEADER, hdrs); + + if (m && strcmp(m, "POST") == 0) { + curl_easy_setopt(c, CURLOPT_POST, 1L); + curl_easy_setopt(c, CURLOPT_POSTFIELDS, b ? b : ""); + curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)(b ? strlen(b) : 0)); + } + + CURLcode rc = curl_easy_perform(c); + if (hdrs) curl_slist_free_all(hdrs); + curl_easy_cleanup(c); + + int ok1 = (fflush(f) == 0); + int ok2 = (fclose(f) == 0); + + if (rc != CURLE_OK || !ok1 || !ok2) { remove(op); return 0; } + return 1; +} + +/* ── HTTP server ─────────────────────────────────────────────────────────── */ +/* Delegate to el_runtime.c's http_serve / http_serve_v2 via the existing + * http_set_handler mechanism. */ + +/* Forward declarations for el_runtime.c functions called from el_seed.c. + * A full #include "el_runtime.h" causes redefinition conflicts (el_seed.h + * already defines el_to_float, el_from_float, and several __ wrappers). + * Declare only the symbols actually used here. */ + +/* HTTP server */ +el_val_t http_serve(el_val_t port, el_val_t handler); +el_val_t http_serve_v2(el_val_t port, el_val_t handler); +el_val_t http_response(el_val_t status, el_val_t headers_json, el_val_t body); + +/* JSON */ +el_val_t json_get(el_val_t json, el_val_t key); +el_val_t json_get_raw(el_val_t json_str, el_val_t key); +el_val_t json_parse(el_val_t s); +el_val_t json_stringify(el_val_t v); +el_val_t json_array_len(el_val_t json_str); +el_val_t json_array_get(el_val_t json_str, el_val_t index); +el_val_t json_array_get_string(el_val_t json_str, el_val_t index); +el_val_t json_get_string(el_val_t json_str, el_val_t key); +el_val_t json_get_int(el_val_t json_str, el_val_t key); +el_val_t json_get_float(el_val_t json_str, el_val_t key); +el_val_t json_get_bool(el_val_t json_str, el_val_t key); +el_val_t json_set(el_val_t json_str, el_val_t key, el_val_t value); + +/* URL / HTML */ +el_val_t url_encode(el_val_t s); +el_val_t url_decode(el_val_t s); +el_val_t el_html_sanitize(el_val_t input_html, el_val_t allowlist_json); + +/* State K/V */ +el_val_t state_set(el_val_t key, el_val_t value); +el_val_t state_get(el_val_t key); +el_val_t state_del(el_val_t key); +el_val_t state_keys(void); +el_val_t state_get_or(el_val_t key, el_val_t default_val); + +/* Engram graph */ +el_val_t engram_node(el_val_t content, el_val_t node_type, el_val_t salience); +el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags_json); +el_val_t engram_node_layered(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags_json, el_val_t layer_id); +el_val_t engram_add_layer(el_val_t name, el_val_t priority, el_val_t suppressible, + el_val_t transparent, el_val_t injectable); +el_val_t engram_remove_layer(el_val_t layer_id); +el_val_t engram_list_layers(void); +el_val_t engram_get_node(el_val_t id); +void engram_strengthen(el_val_t node_id); +void engram_forget(el_val_t node_id); +el_val_t engram_node_count(void); +el_val_t engram_search(el_val_t query, el_val_t limit); +el_val_t engram_scan_nodes(el_val_t limit, el_val_t offset); +void engram_connect(el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t relation); +el_val_t engram_edge_between(el_val_t from_id, el_val_t to_id); +el_val_t engram_neighbors(el_val_t node_id); +el_val_t engram_neighbors_filtered(el_val_t node_id, el_val_t max_depth, el_val_t direction); +el_val_t engram_edge_count(void); +el_val_t engram_activate(el_val_t query, el_val_t depth); +el_val_t engram_save(el_val_t path); +el_val_t engram_load(el_val_t path); +el_val_t engram_get_node_json(el_val_t id); +el_val_t engram_search_json(el_val_t query, el_val_t limit); +el_val_t engram_scan_nodes_json(el_val_t limit, el_val_t offset); +el_val_t engram_scan_nodes_by_type_json(el_val_t node_type, el_val_t limit, el_val_t offset); +el_val_t engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction); +el_val_t engram_activate_json(el_val_t query, el_val_t depth); +el_val_t engram_stats_json(void); +el_val_t engram_list_layers_json(void); +el_val_t engram_compile_layered_json(el_val_t intent, el_val_t depth); + +void __http_serve(el_val_t port, el_val_t handler_name) { + http_serve(port, handler_name); +} + +void __http_serve_v2(el_val_t port, el_val_t handler_name) { + http_serve_v2(port, handler_name); +} + +el_val_t __http_response(el_val_t status, el_val_t headers_json, el_val_t body) { + return http_response(status, headers_json, body); +} + +/* ── HTTP SSE — Server-Sent Events streaming ─────────────────────────────── */ +/* + * Thread-local file descriptor stashed by http_worker_v2 before calling the + * El handler. El SSE builtins read this to get the raw socket fd. + * + * Lifecycle: + * http_worker_v2 sets _tl_http_conn_fd = fd (via el_seed_set_http_conn_fd) + * El handler calls __http_conn_fd() → receives that fd + * El handler calls __http_sse_open(fd) → sends SSE headers, keeps fd open + * El handler calls __http_sse_send(fd, data) → writes "data: ...\n\n" + * El handler calls __http_sse_close(fd) → closes the fd + * El handler returns "__sse__" sentinel → http_worker_v2 does NOT close fd + * + * The -1 value means no current connection (guard against misuse outside + * a handler context). + */ +static __thread int _tl_http_conn_fd = -1; + +/* Called by el_runtime.c's http_worker_v2 — not part of the El ABI. */ +void el_seed_set_http_conn_fd(int fd) { + _tl_http_conn_fd = fd; +} + +/* __http_conn_fd() — returns the raw fd for the current HTTP connection. + * Valid only inside an http_serve_v2 handler before it returns. */ +el_val_t __http_conn_fd(void) { + return EL_INT(_tl_http_conn_fd); +} + +/* __http_sse_open(fd) — sends SSE response headers on fd, keeping it open. + * Returns 1 on success, 0 on write failure. */ +el_val_t __http_sse_open(el_val_t conn_id) { + int fd = (int)(int64_t)conn_id; + if (fd < 0) return 0; + static const char sse_headers[] = + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/event-stream\r\n" + "Cache-Control: no-cache\r\n" + "Connection: keep-alive\r\n" + "Access-Control-Allow-Origin: *\r\n" + "\r\n"; + size_t n = sizeof(sse_headers) - 1; /* exclude NUL */ + size_t sent = 0; + while (sent < n) { + ssize_t w = write(fd, sse_headers + sent, n - sent); + if (w <= 0) return 0; + sent += (size_t)w; + } + return 1; +} + +/* __http_sse_send(fd, data) — writes one SSE event frame: "data: \n\n". + * data must not contain newlines. Returns 1 on success, 0 on client disconnect. */ +el_val_t __http_sse_send(el_val_t conn_id, el_val_t data) { + int fd = (int)(int64_t)conn_id; + if (fd < 0) return 0; + const char* s = EL_CSTR(data); + if (!s) s = ""; + /* Build "data: \n\n" in a single buffer for one write call. */ + size_t prefix_len = 6; /* "data: " */ + size_t slen = strlen(s); + size_t total = prefix_len + slen + 2; /* + "\n\n" */ + char* buf = malloc(total + 1); + if (!buf) return 0; + memcpy(buf, "data: ", 6); + memcpy(buf + 6, s, slen); + buf[6 + slen] = '\n'; + buf[6 + slen + 1] = '\n'; + buf[total] = '\0'; + size_t sent = 0; + int ok = 1; + while (sent < total) { + ssize_t w = write(fd, buf + sent, total - sent); + if (w <= 0) { ok = 0; break; } + sent += (size_t)w; + } + free(buf); + return ok ? 1 : 0; +} + +/* __http_sse_close(fd) — closes the SSE connection fd. */ +el_val_t __http_sse_close(el_val_t conn_id) { + int fd = (int)(int64_t)conn_id; + if (fd < 0) return 0; + close(fd); + return 1; +} + +/* ── Threading ───────────────────────────────────────────────────────────── */ +/* + * Design: + * Static ElThread table (max EL_SEED_MAX_THREADS entries). + * __thread_create: pick a free slot, store fn_name + arg, launch pthread. + * Worker: dlsym(RTLD_DEFAULT, fn_name) → call as el_val_t fn(el_val_t). + * Store result string in slot.result. + * __thread_join: pthread_join, return stored result string. + * + * Thread handle is the slot index (0..EL_SEED_MAX_THREADS-1). + * Returns -1 on failure (no slots, dlsym failure, pthread_create failure). + * + * Each slot is guarded by its own mutex so join/create on different handles + * never contend. + */ + +#define EL_SEED_MAX_THREADS 64 + +typedef el_val_t (*ElFn1)(el_val_t); + +typedef struct { + int in_use; + char* fn_name; + char* arg; + char* result; + pthread_t tid; + int done; /* set to 1 by worker before exit */ +} ElThread; + +static ElThread _el_threads[EL_SEED_MAX_THREADS]; +static pthread_mutex_t _el_thread_mu = PTHREAD_MUTEX_INITIALIZER; + +typedef struct { + int slot; +} ElThreadArg; + +static void* el_thread_worker(void* raw) { + ElThreadArg* ta = (ElThreadArg*)raw; + int slot = ta->slot; + free(ta); + + ElThread* t = &_el_threads[slot]; + + /* Resolve the El function symbol in the running binary. */ + void* sym = dlsym(RTLD_DEFAULT, t->fn_name); + if (!sym) { + pthread_mutex_lock(&_el_thread_mu); + t->result = seed_strdup_persist(""); + t->done = 1; + pthread_mutex_unlock(&_el_thread_mu); + return NULL; + } + + ElFn1 fn = (ElFn1)sym; + + /* Call the El function with the string argument. */ + el_val_t arg_val = EL_STR(t->arg); + el_val_t ret = fn(arg_val); + + /* Persist the result string. */ + const char* rs = EL_CSTR(ret); + char* stored = seed_strdup_persist(rs ? rs : ""); + + pthread_mutex_lock(&_el_thread_mu); + t->result = stored; + t->done = 1; + pthread_mutex_unlock(&_el_thread_mu); + + return NULL; +} + +el_val_t __thread_create(el_val_t fn_name, el_val_t arg) { + const char* fname = EL_CSTR(fn_name); + const char* astr = EL_CSTR(arg); + if (!fname || !*fname) return (el_val_t)(int64_t)-1; + if (!astr) astr = ""; + + pthread_mutex_lock(&_el_thread_mu); + int slot = -1; + for (int i = 0; i < EL_SEED_MAX_THREADS; i++) { + if (!_el_threads[i].in_use) { slot = i; break; } + } + if (slot < 0) { + pthread_mutex_unlock(&_el_thread_mu); + return (el_val_t)(int64_t)-1; + } + + ElThread* t = &_el_threads[slot]; + t->in_use = 1; + t->done = 0; + t->fn_name = seed_strdup_persist(fname); + t->arg = seed_strdup_persist(astr); + t->result = NULL; + pthread_mutex_unlock(&_el_thread_mu); + + ElThreadArg* ta = malloc(sizeof(ElThreadArg)); + if (!ta) { + pthread_mutex_lock(&_el_thread_mu); + free(t->fn_name); free(t->arg); + t->in_use = 0; + pthread_mutex_unlock(&_el_thread_mu); + return (el_val_t)(int64_t)-1; + } + ta->slot = slot; + + if (pthread_create(&t->tid, NULL, el_thread_worker, ta) != 0) { + free(ta); + pthread_mutex_lock(&_el_thread_mu); + free(t->fn_name); free(t->arg); + t->in_use = 0; + pthread_mutex_unlock(&_el_thread_mu); + return (el_val_t)(int64_t)-1; + } + + return (el_val_t)(int64_t)slot; +} + +el_val_t __thread_join(el_val_t tid) { + int64_t slot = (int64_t)tid; + if (slot < 0 || slot >= EL_SEED_MAX_THREADS) return seed_wrap_str(seed_strdup("")); + + ElThread* t = &_el_threads[slot]; + + pthread_mutex_lock(&_el_thread_mu); + if (!t->in_use) { + pthread_mutex_unlock(&_el_thread_mu); + return seed_wrap_str(seed_strdup("")); + } + pthread_mutex_unlock(&_el_thread_mu); + + /* Wait for thread to finish. */ + pthread_join(t->tid, NULL); + + pthread_mutex_lock(&_el_thread_mu); + char* res = t->result ? t->result : ""; + char* copy = seed_strdup(res); /* arena-tracked for caller lifetime */ + free(t->fn_name); + free(t->arg); + if (t->result) { free(t->result); t->result = NULL; } + t->fn_name = NULL; t->arg = NULL; + t->in_use = 0; + t->done = 0; + pthread_mutex_unlock(&_el_thread_mu); + + return seed_wrap_str(copy); +} + +/* ── Mutex pool ──────────────────────────────────────────────────────────── */ + +#define EL_SEED_MAX_MUTEXES 256 + +static pthread_mutex_t _el_mutexes[EL_SEED_MAX_MUTEXES]; +static int _el_mutex_init[EL_SEED_MAX_MUTEXES]; +static int _el_mutex_used[EL_SEED_MAX_MUTEXES]; +static pthread_mutex_t _el_mutex_pool_mu = PTHREAD_MUTEX_INITIALIZER; + +el_val_t __mutex_new(void) { + pthread_mutex_lock(&_el_mutex_pool_mu); + int slot = -1; + for (int i = 0; i < EL_SEED_MAX_MUTEXES; i++) { + if (!_el_mutex_used[i]) { slot = i; break; } + } + if (slot < 0) { + pthread_mutex_unlock(&_el_mutex_pool_mu); + return (el_val_t)(int64_t)-1; + } + _el_mutex_used[slot] = 1; + if (!_el_mutex_init[slot]) { + pthread_mutex_init(&_el_mutexes[slot], NULL); + _el_mutex_init[slot] = 1; + } + pthread_mutex_unlock(&_el_mutex_pool_mu); + return (el_val_t)(int64_t)slot; +} + +void __mutex_lock(el_val_t m) { + int64_t slot = (int64_t)m; + if (slot < 0 || slot >= EL_SEED_MAX_MUTEXES) return; + if (!_el_mutex_init[slot]) return; + pthread_mutex_lock(&_el_mutexes[slot]); +} + +void __mutex_unlock(el_val_t m) { + int64_t slot = (int64_t)m; + if (slot < 0 || slot >= EL_SEED_MAX_MUTEXES) return; + if (!_el_mutex_init[slot]) return; + pthread_mutex_unlock(&_el_mutexes[slot]); +} + +/* ── Subprocess ──────────────────────────────────────────────────────────── */ + +el_val_t __exec(el_val_t cmd) { + const char* c = EL_CSTR(cmd); + if (!c) return seed_wrap_str(seed_strdup("")); + FILE* f = popen(c, "r"); + if (!f) return seed_wrap_str(seed_strdup("")); + size_t cap = 4096, len = 0; + char* buf = malloc(cap); + if (!buf) { pclose(f); return seed_wrap_str(seed_strdup("")); } + char tmp[4096]; + while (fgets(tmp, sizeof(tmp), f)) { + size_t n = strlen(tmp); + while (len + n + 1 > cap) { + cap *= 2; + char* g = realloc(buf, cap); + if (!g) { free(buf); pclose(f); return seed_wrap_str(seed_strdup("")); } + buf = g; + } + memcpy(buf + len, tmp, n); + len += n; + buf[len] = '\0'; + } + pclose(f); + seed_arena_track(buf); + return seed_wrap_str(buf); +} + +void __exec_bg(el_val_t cmd) { + const char* c = EL_CSTR(cmd); + if (!c) return; + /* Fork-free: run in background via system() with & appended. */ + size_t n = strlen(c); + char* s = malloc(n + 4); + if (!s) return; + memcpy(s, c, n); + memcpy(s + n, " &", 3); + system(s); + free(s); +} + +/* ── Environment and process ─────────────────────────────────────────────── */ + +el_val_t __env_get(el_val_t key) { + const char* k = EL_CSTR(key); + if (!k) return seed_wrap_str(seed_strdup("")); + const char* v = getenv(k); + return seed_wrap_str(seed_strdup(v ? v : "")); +} + +void __exit_program(el_val_t code) { + exit((int)(int64_t)code); +} + +/* ── args_json ────────────────────────────────────────────────────────────── */ + +static int _seed_argc = 0; +static char** _seed_argv = NULL; + +void el_seed_init_args(int argc, char** argv) { + _seed_argc = argc; + _seed_argv = argv; +} + +el_val_t __args_json(void) { + /* Return ["arg1","arg2",...] as a JSON string. Skip argv[0] (program name). */ + size_t cap = 256, len = 0; + char* buf = malloc(cap); + if (!buf) return seed_wrap_str(seed_strdup("[]")); + buf[len++] = '['; + int first = 1; + for (int i = 1; i < _seed_argc; i++) { + const char* a = _seed_argv[i]; + /* Estimate: each arg needs at most strlen*6+4 bytes (worst case escape) */ + size_t need = strlen(a) * 6 + 8; + while (len + need + 2 > cap) { + cap *= 2; + char* g = realloc(buf, cap); + if (!g) { free(buf); return seed_wrap_str(seed_strdup("[]")); } + buf = g; + } + if (!first) buf[len++] = ','; + first = 0; + buf[len++] = '"'; + for (const char* p = a; *p; p++) { + unsigned char c = (unsigned char)*p; + if (c == '"') { buf[len++] = '\\'; buf[len++] = '"'; } + else if (c == '\\') { buf[len++] = '\\'; buf[len++] = '\\'; } + else if (c == '\n') { buf[len++] = '\\'; buf[len++] = 'n'; } + else if (c == '\r') { buf[len++] = '\\'; buf[len++] = 'r'; } + else if (c == '\t') { buf[len++] = '\\'; buf[len++] = 't'; } + else buf[len++] = (char)c; + } + buf[len++] = '"'; + } + buf[len++] = ']'; + buf[len] = '\0'; + seed_arena_track(buf); + return seed_wrap_str(buf); +} + +/* ── Time ────────────────────────────────────────────────────────────────── */ + +el_val_t __time_now_ns(void) { + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts) == 0) { + int64_t ns = (int64_t)ts.tv_sec * 1000000000LL + (int64_t)ts.tv_nsec; + return (el_val_t)ns; + } + struct timeval tv; + gettimeofday(&tv, NULL); + return (el_val_t)((int64_t)tv.tv_sec * 1000000000LL + (int64_t)tv.tv_usec * 1000LL); +} + +void __sleep_ms(el_val_t ms) { + int64_t m = (int64_t)ms; + if (m < 0) m = 0; + struct timespec ts; + ts.tv_sec = (time_t)(m / 1000LL); + ts.tv_nsec = (long)((m % 1000LL) * 1000000LL); + nanosleep(&ts, NULL); +} + +/* ── UUID ────────────────────────────────────────────────────────────────── */ + +static int _seed_uuid_seeded = 0; + +el_val_t __uuid_v4(void) { + if (!_seed_uuid_seeded) { + srand((unsigned)time(NULL) ^ (unsigned)(uintptr_t)&_seed_uuid_seeded); + _seed_uuid_seeded = 1; + } + unsigned char b[16]; + for (int i = 0; i < 16; i++) b[i] = (unsigned char)(rand() & 0xff); + b[6] = (b[6] & 0x0f) | 0x40; /* version 4 */ + b[8] = (b[8] & 0x3f) | 0x80; /* RFC 4122 variant */ + char buf[37]; + snprintf(buf, sizeof(buf), + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + b[0],b[1],b[2],b[3], b[4],b[5], b[6],b[7], + b[8],b[9], b[10],b[11],b[12],b[13],b[14],b[15]); + return seed_wrap_str(seed_strdup(buf)); +} + +/* ── Math ────────────────────────────────────────────────────────────────── */ + +el_val_t __sqrt_f(el_val_t f) { return el_from_float(sqrt(el_to_float(f))); } +el_val_t __log_f(el_val_t f) { return el_from_float(log10(el_to_float(f))); } +el_val_t __ln_f(el_val_t f) { return el_from_float(log(el_to_float(f))); } +el_val_t __sin_f(el_val_t f) { return el_from_float(sin(el_to_float(f))); } +el_val_t __cos_f(el_val_t f) { return el_from_float(cos(el_to_float(f))); } +el_val_t __pi_f(void) { return el_from_float(3.14159265358979323846); } + +/* ── JSON — thin wrappers around el_runtime.c implementations ────────────── */ + +el_val_t __json_get(el_val_t json, el_val_t key) { return json_get(json, key); } +el_val_t __json_get_raw(el_val_t json_str, el_val_t key) { return json_get_raw(json_str, key); } +el_val_t __json_parse(el_val_t s) { return json_parse(s); } +el_val_t __json_stringify(el_val_t v) { return json_stringify(v); } +el_val_t __json_parse_map(el_val_t json_str) { return json_parse(json_str); } +el_val_t __json_stringify_val(el_val_t val) { return json_stringify(val); } +el_val_t __json_array_len(el_val_t json_str) { return json_array_len(json_str); } +el_val_t __json_array_get(el_val_t json_str, el_val_t index) { return json_array_get(json_str, index); } +el_val_t __json_array_get_string(el_val_t json_str, el_val_t index) { return json_array_get_string(json_str, index); } +el_val_t __json_get_string(el_val_t json_str, el_val_t key) { return json_get_string(json_str, key); } +el_val_t __json_get_int(el_val_t json_str, el_val_t key) { return json_get_int(json_str, key); } +el_val_t __json_get_float(el_val_t json_str, el_val_t key) { return json_get_float(json_str, key); } +el_val_t __json_get_bool(el_val_t json_str, el_val_t key) { return json_get_bool(json_str, key); } +el_val_t __json_set(el_val_t json_str, el_val_t key, el_val_t value) { return json_set(json_str, key, value); } + +/* ── State K/V — thin wrappers ───────────────────────────────────────────── */ + +el_val_t __state_set(el_val_t key, el_val_t value) { return state_set(key, value); } +el_val_t __state_get(el_val_t key) { return state_get(key); } +el_val_t __state_del(el_val_t key) { return state_del(key); } +el_val_t __state_keys(void) { return state_keys(); } + +/* ── HTML/URL — thin wrappers ────────────────────────────────────────────── */ + +el_val_t __html_sanitize(el_val_t input_html, el_val_t allowlist_json) { + return el_html_sanitize(input_html, allowlist_json); +} + +el_val_t __url_encode(el_val_t s) { return url_encode(s); } +el_val_t __url_decode(el_val_t s) { return url_decode(s); } + +/* ── Engram — thin wrappers ──────────────────────────────────────────────── */ + +el_val_t __engram_node(el_val_t content, el_val_t node_type, el_val_t salience) { + return engram_node(content, node_type, salience); +} + +el_val_t __engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags) { + return engram_node_full(content, node_type, label, salience, importance, confidence, tier, tags); +} + +el_val_t __engram_node_layered(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t certainty, el_val_t confidence, + el_val_t status, el_val_t tags, el_val_t layer_id) { + return engram_node_layered(content, node_type, label, salience, certainty, confidence, + status, tags, layer_id); +} + +el_val_t __engram_add_layer(el_val_t name, el_val_t priority, el_val_t suppressible, + el_val_t transparent, el_val_t injectable) { + return engram_add_layer(name, priority, suppressible, transparent, injectable); +} + +el_val_t __engram_remove_layer(el_val_t layer_id) { return engram_remove_layer(layer_id); } +el_val_t __engram_list_layers(void) { return engram_list_layers(); } +el_val_t __engram_get_node(el_val_t id) { return engram_get_node(id); } +void __engram_strengthen(el_val_t node_id) { engram_strengthen(node_id); } +void __engram_forget(el_val_t node_id) { engram_forget(node_id); } +el_val_t __engram_node_count(void) { return engram_node_count(); } + +el_val_t __engram_search(el_val_t query, el_val_t limit) { return engram_search(query, limit); } +el_val_t __engram_scan_nodes(el_val_t limit, el_val_t offset) { return engram_scan_nodes(limit, offset); } + +void __engram_connect(el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t relation) { + engram_connect(from_id, to_id, weight, relation); +} + +el_val_t __engram_edge_between(el_val_t from_id, el_val_t to_id) { + return engram_edge_between(from_id, to_id); +} + +el_val_t __engram_neighbors(el_val_t node_id) { return engram_neighbors(node_id); } + +el_val_t __engram_neighbors_filtered(el_val_t node_id, el_val_t max_depth, el_val_t direction) { + return engram_neighbors_filtered(node_id, max_depth, direction); +} + +el_val_t __engram_edge_count(void) { return engram_edge_count(); } + +el_val_t __engram_activate(el_val_t query, el_val_t depth) { return engram_activate(query, depth); } +el_val_t __engram_save(el_val_t path) { return engram_save(path); } +el_val_t __engram_load(el_val_t path) { return engram_load(path); } + +el_val_t __engram_get_node_json(el_val_t id) { return engram_get_node_json(id); } + +el_val_t __engram_search_json(el_val_t query, el_val_t limit) { + return engram_search_json(query, limit); +} + +el_val_t __engram_scan_nodes_json(el_val_t limit, el_val_t offset) { + return engram_scan_nodes_json(limit, offset); +} + +el_val_t __engram_scan_nodes_by_type_json(el_val_t node_type, el_val_t limit, el_val_t offset) { + return engram_scan_nodes_by_type_json(node_type, limit, offset); +} + +el_val_t __engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction) { + return engram_neighbors_json(node_id, max_depth, direction); +} + +el_val_t __engram_activate_json(el_val_t query, el_val_t depth) { + return engram_activate_json(query, depth); +} + +el_val_t __engram_stats_json(void) { return engram_stats_json(); } +el_val_t __engram_list_layers_json(void) { return engram_list_layers_json(); } + +el_val_t __engram_compile_layered_json(el_val_t intent, el_val_t depth) { + return engram_compile_layered_json(intent, depth); +} + +/* ── Cryptographic hashing ────────────────────────────────────────────────── */ +/* + * SHA-256 — self-contained implementation (no OpenSSL dependency). + * Based on Brad Conte's public-domain reference implementation. + */ + +typedef struct { + uint8_t data[64]; + uint32_t datalen; + uint64_t bitlen; + uint32_t state[8]; +} _seed_sha256_ctx; + +static const uint32_t _seed_sha256_k[64] = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +}; + +#define _SEED_ROTR32(x,n) (((x)>>(n))|((x)<<(32-(n)))) +#define _SEED_CH(x,y,z) (((x)&(y))^(~(x)&(z))) +#define _SEED_MAJ(x,y,z) (((x)&(y))^((x)&(z))^((y)&(z))) +#define _SEED_EP0(x) (_SEED_ROTR32(x,2)^_SEED_ROTR32(x,13)^_SEED_ROTR32(x,22)) +#define _SEED_EP1(x) (_SEED_ROTR32(x,6)^_SEED_ROTR32(x,11)^_SEED_ROTR32(x,25)) +#define _SEED_SIG0(x) (_SEED_ROTR32(x,7)^_SEED_ROTR32(x,18)^((x)>>3)) +#define _SEED_SIG1(x) (_SEED_ROTR32(x,17)^_SEED_ROTR32(x,19)^((x)>>10)) + +static void _seed_sha256_transform(_seed_sha256_ctx* ctx, const uint8_t* data) { + uint32_t a,b,c,d,e,f,g,h,t1,t2,m[64]; + for (int i=0,j=0; i<16; i++,j+=4) + m[i]=(uint32_t)(data[j]<<24)|(data[j+1]<<16)|(data[j+2]<<8)|data[j+3]; + for (int i=16; i<64; i++) + m[i]=_SEED_SIG1(m[i-2])+m[i-7]+_SEED_SIG0(m[i-15])+m[i-16]; + a=ctx->state[0]; b=ctx->state[1]; c=ctx->state[2]; d=ctx->state[3]; + e=ctx->state[4]; f=ctx->state[5]; g=ctx->state[6]; h=ctx->state[7]; + for (int i=0; i<64; i++) { + t1=h+_SEED_EP1(e)+_SEED_CH(e,f,g)+_seed_sha256_k[i]+m[i]; + t2=_SEED_EP0(a)+_SEED_MAJ(a,b,c); + h=g; g=f; f=e; e=d+t1; d=c; c=b; b=a; a=t1+t2; + } + ctx->state[0]+=a; ctx->state[1]+=b; ctx->state[2]+=c; ctx->state[3]+=d; + ctx->state[4]+=e; ctx->state[5]+=f; ctx->state[6]+=g; ctx->state[7]+=h; +} + +static void _seed_sha256_init(_seed_sha256_ctx* ctx) { + ctx->datalen=0; ctx->bitlen=0; + ctx->state[0]=0x6a09e667; ctx->state[1]=0xbb67ae85; + ctx->state[2]=0x3c6ef372; ctx->state[3]=0xa54ff53a; + ctx->state[4]=0x510e527f; ctx->state[5]=0x9b05688c; + ctx->state[6]=0x1f83d9ab; ctx->state[7]=0x5be0cd19; +} + +static void _seed_sha256_update(_seed_sha256_ctx* ctx, const uint8_t* data, size_t len) { + for (size_t i=0; idata[ctx->datalen++] = data[i]; + if (ctx->datalen==64) { _seed_sha256_transform(ctx,ctx->data); ctx->bitlen+=512; ctx->datalen=0; } + } +} + +static void _seed_sha256_final(_seed_sha256_ctx* ctx, uint8_t hash[32]) { + uint32_t i=ctx->datalen; + ctx->data[i++]=0x80; + if (ctx->datalen<56) { while(i<56) ctx->data[i++]=0; } + else { while(i<64) ctx->data[i++]=0; _seed_sha256_transform(ctx,ctx->data); memset(ctx->data,0,56); } + ctx->bitlen+=ctx->datalen*8; + ctx->data[63]=(uint8_t)(ctx->bitlen); ctx->data[62]=(uint8_t)(ctx->bitlen>>8); + ctx->data[61]=(uint8_t)(ctx->bitlen>>16); ctx->data[60]=(uint8_t)(ctx->bitlen>>24); + ctx->data[59]=(uint8_t)(ctx->bitlen>>32); ctx->data[58]=(uint8_t)(ctx->bitlen>>40); + ctx->data[57]=(uint8_t)(ctx->bitlen>>48); ctx->data[56]=(uint8_t)(ctx->bitlen>>56); + _seed_sha256_transform(ctx,ctx->data); + for (i=0; i<4; i++) { + hash[i] =(uint8_t)(ctx->state[0]>>(24-i*8)); + hash[i+4] =(uint8_t)(ctx->state[1]>>(24-i*8)); + hash[i+8] =(uint8_t)(ctx->state[2]>>(24-i*8)); + hash[i+12] =(uint8_t)(ctx->state[3]>>(24-i*8)); + hash[i+16] =(uint8_t)(ctx->state[4]>>(24-i*8)); + hash[i+20] =(uint8_t)(ctx->state[5]>>(24-i*8)); + hash[i+24] =(uint8_t)(ctx->state[6]>>(24-i*8)); + hash[i+28] =(uint8_t)(ctx->state[7]>>(24-i*8)); + } +} + +/* ── Manifest reader (shared: macOS + Linux) ─────────────────────────────── */ +/* + * Parse the app{} block from a manifest.el file. + * Expected format (subset — only app{} block is parsed): + * + * app { + * window_title "My App" + * window_width 1200 + * window_height 800 + * min_width 600 + * min_height 400 + * } + * + * Returns JSON: {"title":"...","width":N,"height":N,"min_width":N,"min_height":N} + * Returns "{}" on parse failure. + * + * Compiled unconditionally so both EL_TARGET_MACOS and EL_TARGET_LINUX can use + * it — the __manifest_read builtin is identical on all native targets. + */ + +static void seed_manifest_skip_ws(const char** p) { + while (**p && (unsigned char)**p <= ' ') (*p)++; +} + +/* Read a quoted string literal. Caller must free() the result. */ +static char* seed_manifest_read_string(const char** p) { + seed_manifest_skip_ws(p); + if (**p != '"') return NULL; + (*p)++; + const char* start = *p; + while (**p && **p != '"') { + if (**p == '\\') (*p)++; /* skip escaped char */ + (*p)++; + } + size_t len = (size_t)(*p - start); + if (**p == '"') (*p)++; + char* out = malloc(len + 1); + if (!out) return NULL; + memcpy(out, start, len); + out[len] = '\0'; + return out; +} + +/* Read an unquoted integer literal. */ +static int64_t seed_manifest_read_int(const char** p) { + seed_manifest_skip_ws(p); + int64_t result = 0; + int neg = 0; + if (**p == '-') { neg = 1; (*p)++; } + while (**p >= '0' && **p <= '9') { + result = result * 10 + (**p - '0'); + (*p)++; + } + return neg ? -result : result; +} + +/* Find "app {" block start. Returns pointer past the '{'. */ +static const char* seed_manifest_find_app_block(const char* src) { + while (*src) { + /* Skip line comments (// ...) */ + if (src[0] == '/' && src[1] == '/') { + while (*src && *src != '\n') src++; + continue; + } + if (strncmp(src, "app", 3) == 0 && + (src[3] == ' ' || src[3] == '\t' || src[3] == '\n' || src[3] == '{')) { + src += 3; + while (*src && *src != '{') src++; + if (*src == '{') return src + 1; + return NULL; + } + src++; + } + return NULL; +} + +el_val_t __manifest_read(el_val_t path) { + const char* p = EL_CSTR(path); + if (!p || !*p) return seed_wrap_str(seed_strdup("{}")); + + /* Read the file. */ + FILE* f = fopen(p, "r"); + if (!f) return seed_wrap_str(seed_strdup("{}")); + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + if (sz <= 0) { fclose(f); return seed_wrap_str(seed_strdup("{}")); } + char* src = malloc((size_t)sz + 1); + if (!src) { fclose(f); return seed_wrap_str(seed_strdup("{}")); } + size_t got = fread(src, 1, (size_t)sz, f); + src[got] = '\0'; + fclose(f); + + const char* app_start = seed_manifest_find_app_block(src); + if (!app_start) { free(src); return seed_wrap_str(seed_strdup("{}")); } + + /* Parse key-value pairs inside the app { } block. */ + char* title = NULL; + int64_t width = 1200; + int64_t height = 800; + int64_t min_w = 600; + int64_t min_h = 400; + + const char* cur = app_start; + while (*cur && *cur != '}') { + /* Skip whitespace and comments. */ + while (*cur && (unsigned char)*cur <= ' ') cur++; + if (*cur == '}') break; + if (cur[0] == '/' && cur[1] == '/') { + while (*cur && *cur != '\n') cur++; + continue; + } + + /* Read key token. */ + const char* key_start = cur; + while (*cur && (unsigned char)*cur > ' ' && *cur != '{' && *cur != '}') cur++; + size_t key_len = (size_t)(cur - key_start); + if (key_len == 0) { cur++; continue; } + + /* Skip whitespace between key and value. */ + while (*cur == ' ' || *cur == '\t') cur++; + + if (strncmp(key_start, "window_title", key_len) == 0 && key_len == 12) { + free(title); + title = seed_manifest_read_string(&cur); + } else if (strncmp(key_start, "window_width", key_len) == 0 && key_len == 12) { + width = seed_manifest_read_int(&cur); + } else if (strncmp(key_start, "window_height", key_len) == 0 && key_len == 13) { + height = seed_manifest_read_int(&cur); + } else if (strncmp(key_start, "min_width", key_len) == 0 && key_len == 9) { + min_w = seed_manifest_read_int(&cur); + } else if (strncmp(key_start, "min_height", key_len) == 0 && key_len == 10) { + min_h = seed_manifest_read_int(&cur); + } else { + /* Unknown key — skip to end of line. */ + while (*cur && *cur != '\n' && *cur != '}') cur++; + } + } + + free(src); + + /* Build JSON result. */ + const char* t = title ? title : "App"; + size_t buf_sz = strlen(t) * 6 + 128; + char* buf = seed_strbuf(buf_sz); + snprintf(buf, buf_sz, + "{\"title\":\"%s\",\"width\":%lld,\"height\":%lld,\"min_width\":%lld,\"min_height\":%lld}", + t, (long long)width, (long long)height, (long long)min_w, (long long)min_h); + free(title); + return seed_wrap_str(buf); +} + +/* ── Native widget system — macOS AppKit ─────────────────────────────────── */ +/* + * These builtins are compiled in only when EL_TARGET_MACOS is defined. + * They call through to el_appkit.m (Objective-C) which implements the actual + * AppKit widget creation and management. + * + * Each builtin is a thin wrapper: marshal el_val_t ↔ C types, call the + * el_appkit_* function, return the result. + * + * Compile requirements: + * - Compile el_appkit.m alongside this file (clang -ObjC -framework Cocoa) + * - Pass -DEL_TARGET_MACOS to enable this section + */ + +#ifdef EL_TARGET_MACOS + +/* Forward declarations — implemented in el_appkit.m */ +extern void el_appkit_init(void); +extern void el_appkit_run_loop(void); +extern int64_t el_appkit_window_create(const char* title, int w, int h, int mw, int mh); +extern void el_appkit_window_show(int64_t handle); +extern void el_appkit_window_set_title(int64_t handle, const char* title); +extern int64_t el_appkit_vstack_create(int spacing); +extern int64_t el_appkit_hstack_create(int spacing); +extern int64_t el_appkit_zstack_create(void); +extern int64_t el_appkit_scroll_create(void); +extern int64_t el_appkit_label_create(const char* text); +extern int64_t el_appkit_button_create(const char* label); +extern int64_t el_appkit_text_field_create(const char* placeholder); +extern int64_t el_appkit_text_area_create(const char* placeholder); +extern int64_t el_appkit_image_create(const char* path_or_name); +extern void el_appkit_widget_set_text(int64_t handle, const char* text); +extern const char* el_appkit_widget_get_text(int64_t handle); +extern void el_appkit_widget_set_color(int64_t h, float r, float g, float b, float a); +extern void el_appkit_widget_set_bg_color(int64_t h, float r, float g, float b, float a); +extern void el_appkit_widget_set_font(int64_t h, const char* family, int size, int bold); +extern void el_appkit_widget_set_padding(int64_t h, int top, int right, int bottom, int left); +extern void el_appkit_widget_set_width(int64_t h, int width); +extern void el_appkit_widget_set_height(int64_t h, int height); +extern void el_appkit_widget_set_flex(int64_t h, int flex); +extern void el_appkit_widget_set_corner_radius(int64_t h, int radius); +extern void el_appkit_widget_set_disabled(int64_t h, int disabled); +extern void el_appkit_widget_set_hidden(int64_t h, int hidden); +extern void el_appkit_widget_add_child(int64_t parent, int64_t child); +extern void el_appkit_widget_remove_child(int64_t parent, int64_t child); +extern void el_appkit_widget_destroy(int64_t handle); +extern void el_appkit_widget_on_click(int64_t h, const char* fn_name); +extern void el_appkit_widget_on_change(int64_t h, const char* fn_name); +extern void el_appkit_widget_on_submit(int64_t h, const char* fn_name); + +/* ── Native widget builtins ──────────────────────────────────────────────── */ + +void __native_init(void) { el_appkit_init(); } +void __native_run_loop(void) { el_appkit_run_loop(); } + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_appkit_window_create( + EL_CSTR(title), + (int)(int64_t)width, (int)(int64_t)height, + (int)(int64_t)min_width, (int)(int64_t)min_height); +} + +void __window_show(el_val_t h) { el_appkit_window_show((int64_t)h); } +void __window_set_title(el_val_t h, el_val_t t) { el_appkit_window_set_title((int64_t)h, EL_CSTR(t)); } + +el_val_t __vstack_create(el_val_t spacing) { return (el_val_t)el_appkit_vstack_create((int)(int64_t)spacing); } +el_val_t __hstack_create(el_val_t spacing) { return (el_val_t)el_appkit_hstack_create((int)(int64_t)spacing); } +el_val_t __zstack_create(void) { return (el_val_t)el_appkit_zstack_create(); } +el_val_t __scroll_create(void) { return (el_val_t)el_appkit_scroll_create(); } + +el_val_t __label_create(el_val_t text) { return (el_val_t)el_appkit_label_create(EL_CSTR(text)); } +el_val_t __button_create(el_val_t label) { return (el_val_t)el_appkit_button_create(EL_CSTR(label)); } +el_val_t __text_field_create(el_val_t placeholder) { return (el_val_t)el_appkit_text_field_create(EL_CSTR(placeholder)); } +el_val_t __text_area_create(el_val_t placeholder) { return (el_val_t)el_appkit_text_area_create(EL_CSTR(placeholder)); } +el_val_t __image_create(el_val_t path_or_name) { return (el_val_t)el_appkit_image_create(EL_CSTR(path_or_name)); } + +void __widget_set_text(el_val_t h, el_val_t t) { el_appkit_widget_set_text((int64_t)h, EL_CSTR(t)); } + +el_val_t __widget_get_text(el_val_t h) { + const char* s = el_appkit_widget_get_text((int64_t)h); + if (!s) return seed_wrap_str(seed_strdup("")); + /* el_appkit returns strdup'd string — wrap it (arena won't track it, but + * caller must treat return as short-lived or copy it). */ + return EL_STR(s); +} + +void __widget_set_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_appkit_widget_set_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_bg_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_appkit_widget_set_bg_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_font(el_val_t h, el_val_t family, el_val_t size, el_val_t bold) { + el_appkit_widget_set_font((int64_t)h, EL_CSTR(family), + (int)(int64_t)size, (int)(int64_t)bold); +} + +void __widget_set_padding(el_val_t h, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_appkit_widget_set_padding((int64_t)h, + (int)(int64_t)top, (int)(int64_t)right, + (int)(int64_t)bottom, (int)(int64_t)left); +} + +void __widget_set_width(el_val_t h, el_val_t w) { el_appkit_widget_set_width((int64_t)h, (int)(int64_t)w); } +void __widget_set_height(el_val_t h, el_val_t ht) { el_appkit_widget_set_height((int64_t)h, (int)(int64_t)ht); } +void __widget_set_flex(el_val_t h, el_val_t f) { el_appkit_widget_set_flex((int64_t)h, (int)(int64_t)f); } +void __widget_set_corner_radius(el_val_t h, el_val_t r) { el_appkit_widget_set_corner_radius((int64_t)h, (int)(int64_t)r); } +void __widget_set_disabled(el_val_t h, el_val_t d) { el_appkit_widget_set_disabled((int64_t)h, (int)(int64_t)d); } +void __widget_set_hidden(el_val_t h, el_val_t hid) { el_appkit_widget_set_hidden((int64_t)h, (int)(int64_t)hid); } +void __widget_add_child(el_val_t p, el_val_t c) { el_appkit_widget_add_child((int64_t)p, (int64_t)c); } +void __widget_remove_child(el_val_t p, el_val_t c) { el_appkit_widget_remove_child((int64_t)p, (int64_t)c); } +void __widget_destroy(el_val_t h) { el_appkit_widget_destroy((int64_t)h); } + +void __widget_on_click(el_val_t h, el_val_t fn_name) { el_appkit_widget_on_click((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_change(el_val_t h, el_val_t fn_name) { el_appkit_widget_on_change((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_submit(el_val_t h, el_val_t fn_name) { el_appkit_widget_on_submit((int64_t)h, EL_CSTR(fn_name)); } + +#endif /* EL_TARGET_MACOS */ + +/* ── Native widget system — Linux GTK4 ──────────────────────────────────── */ +/* + * These builtins are compiled in only when EL_TARGET_LINUX is defined. + * They call through to el_gtk4.c which implements the GTK4 widget layer. + * + * Each builtin is a thin wrapper: marshal el_val_t ↔ C types, call the + * el_gtk4_* function, return the result. + * + * Compile requirements: + * - Compile el_gtk4.c alongside this file + * gcc -DEL_TARGET_LINUX $(pkg-config --cflags gtk4) el_gtk4.c -c ... + * - Pass -DEL_TARGET_LINUX to enable this section + * - Link with $(pkg-config --libs gtk4) -ldl + * + * __manifest_read is shared with the macOS path (implemented above in the + * seed_manifest_* helpers) and compiled for both targets unconditionally. + */ + +#ifdef EL_TARGET_LINUX + +/* Forward declarations — implemented in el_gtk4.c */ +extern void el_gtk4_init(void); +extern void el_gtk4_run_loop(void); +extern int64_t el_gtk4_window_create(const char* title, int w, int h, + int mw, int mh); +extern void el_gtk4_window_show(int64_t handle); +extern void el_gtk4_window_set_title(int64_t handle, const char* title); +extern int64_t el_gtk4_vstack_create(int spacing); +extern int64_t el_gtk4_hstack_create(int spacing); +extern int64_t el_gtk4_zstack_create(void); +extern int64_t el_gtk4_scroll_create(void); +extern int64_t el_gtk4_label_create(const char* text); +extern int64_t el_gtk4_button_create(const char* label); +extern int64_t el_gtk4_text_field_create(const char* placeholder); +extern int64_t el_gtk4_text_area_create(const char* placeholder); +extern int64_t el_gtk4_image_create(const char* path_or_name); +extern void el_gtk4_widget_set_text(int64_t handle, const char* text); +extern const char* el_gtk4_widget_get_text(int64_t handle); +extern void el_gtk4_widget_set_color(int64_t h, float r, float g, float b, float a); +extern void el_gtk4_widget_set_bg_color(int64_t h, float r, float g, float b, float a); +extern void el_gtk4_widget_set_font(int64_t h, const char* family, int size, int bold); +extern void el_gtk4_widget_set_padding(int64_t h, int top, int right, int bottom, int left); +extern void el_gtk4_widget_set_width(int64_t h, int width); +extern void el_gtk4_widget_set_height(int64_t h, int height); +extern void el_gtk4_widget_set_flex(int64_t h, int flex); +extern void el_gtk4_widget_set_corner_radius(int64_t h, int radius); +extern void el_gtk4_widget_set_disabled(int64_t h, int disabled); +extern void el_gtk4_widget_set_hidden(int64_t h, int hidden); +extern void el_gtk4_widget_add_child(int64_t parent, int64_t child); +extern void el_gtk4_widget_remove_child(int64_t parent, int64_t child); +extern void el_gtk4_widget_destroy(int64_t handle); +extern void el_gtk4_widget_on_click(int64_t h, const char* fn_name); +extern void el_gtk4_widget_on_change(int64_t h, const char* fn_name); +extern void el_gtk4_widget_on_submit(int64_t h, const char* fn_name); + +void __native_init(void) { el_gtk4_init(); } +void __native_run_loop(void) { el_gtk4_run_loop(); } + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_gtk4_window_create( + EL_CSTR(title), + (int)(int64_t)width, (int)(int64_t)height, + (int)(int64_t)min_width, (int)(int64_t)min_height); +} + +void __window_show(el_val_t h) { el_gtk4_window_show((int64_t)h); } +void __window_set_title(el_val_t h, el_val_t t) { el_gtk4_window_set_title((int64_t)h, EL_CSTR(t)); } + +el_val_t __vstack_create(el_val_t spacing) { return (el_val_t)el_gtk4_vstack_create((int)(int64_t)spacing); } +el_val_t __hstack_create(el_val_t spacing) { return (el_val_t)el_gtk4_hstack_create((int)(int64_t)spacing); } +el_val_t __zstack_create(void) { return (el_val_t)el_gtk4_zstack_create(); } +el_val_t __scroll_create(void) { return (el_val_t)el_gtk4_scroll_create(); } + +el_val_t __label_create(el_val_t text) { return (el_val_t)el_gtk4_label_create(EL_CSTR(text)); } +el_val_t __button_create(el_val_t label) { return (el_val_t)el_gtk4_button_create(EL_CSTR(label)); } +el_val_t __text_field_create(el_val_t placeholder) { return (el_val_t)el_gtk4_text_field_create(EL_CSTR(placeholder)); } +el_val_t __text_area_create(el_val_t placeholder) { return (el_val_t)el_gtk4_text_area_create(EL_CSTR(placeholder)); } +el_val_t __image_create(el_val_t path_or_name) { return (el_val_t)el_gtk4_image_create(EL_CSTR(path_or_name)); } + +void __widget_set_text(el_val_t h, el_val_t t) { el_gtk4_widget_set_text((int64_t)h, EL_CSTR(t)); } + +el_val_t __widget_get_text(el_val_t h) { + const char* s = el_gtk4_widget_get_text((int64_t)h); + if (!s) return EL_STR(""); + return EL_STR(s); /* el_gtk4 returns strdup'd string */ +} + +void __widget_set_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_gtk4_widget_set_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_bg_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_gtk4_widget_set_bg_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_font(el_val_t h, el_val_t family, el_val_t size, el_val_t bold) { + el_gtk4_widget_set_font((int64_t)h, EL_CSTR(family), + (int)(int64_t)size, (int)(int64_t)bold); +} + +void __widget_set_padding(el_val_t h, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_gtk4_widget_set_padding((int64_t)h, + (int)(int64_t)top, (int)(int64_t)right, + (int)(int64_t)bottom, (int)(int64_t)left); +} + +void __widget_set_width(el_val_t h, el_val_t w) { el_gtk4_widget_set_width((int64_t)h, (int)(int64_t)w); } +void __widget_set_height(el_val_t h, el_val_t ht) { el_gtk4_widget_set_height((int64_t)h, (int)(int64_t)ht); } +void __widget_set_flex(el_val_t h, el_val_t f) { el_gtk4_widget_set_flex((int64_t)h, (int)(int64_t)f); } +void __widget_set_corner_radius(el_val_t h, el_val_t r) { el_gtk4_widget_set_corner_radius((int64_t)h, (int)(int64_t)r); } +void __widget_set_disabled(el_val_t h, el_val_t d) { el_gtk4_widget_set_disabled((int64_t)h, (int)(int64_t)d); } +void __widget_set_hidden(el_val_t h, el_val_t hid) { el_gtk4_widget_set_hidden((int64_t)h, (int)(int64_t)hid); } +void __widget_add_child(el_val_t p, el_val_t c) { el_gtk4_widget_add_child((int64_t)p, (int64_t)c); } +void __widget_remove_child(el_val_t p, el_val_t c) { el_gtk4_widget_remove_child((int64_t)p, (int64_t)c); } +void __widget_destroy(el_val_t h) { el_gtk4_widget_destroy((int64_t)h); } + +void __widget_on_click(el_val_t h, el_val_t fn_name) { el_gtk4_widget_on_click((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_change(el_val_t h, el_val_t fn_name) { el_gtk4_widget_on_change((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_submit(el_val_t h, el_val_t fn_name) { el_gtk4_widget_on_submit((int64_t)h, EL_CSTR(fn_name)); } + +#endif /* EL_TARGET_LINUX */ + +/* ── Native widget system — SDL2 (embedded / Pi) ─────────────────────────── */ +/* + * These builtins are compiled in only when EL_TARGET_SDL2 is defined. + * They call through to el_sdl2.c which implements a retained-mode pixel + * widget layer on top of SDL2 + SDL_ttf + SDL_image. + * + * Each builtin is a thin wrapper: marshal el_val_t ↔ C types, call the + * el_sdl2_* function, return the result. + * + * Compile requirements: + * gcc -DEL_TARGET_SDL2 $(sdl2-config --cflags) el_sdl2.c -c ... + * Pass -DEL_TARGET_SDL2 to enable this section. + * Link: + * $(sdl2-config --libs) -lSDL2_ttf -lSDL2_image -ldl + * + * __manifest_read is shared with the macOS/Linux paths (implemented above). + */ + +#ifdef EL_TARGET_SDL2 + +/* Forward declarations — implemented in el_sdl2.c */ +extern void el_sdl2_init(void); +extern void el_sdl2_run_loop(void); +extern int64_t el_sdl2_window_create(const char* title, int w, int h, + int mw, int mh); +extern void el_sdl2_window_show(int64_t handle); +extern void el_sdl2_window_set_title(int64_t handle, const char* title); +extern int64_t el_sdl2_vstack_create(int spacing); +extern int64_t el_sdl2_hstack_create(int spacing); +extern int64_t el_sdl2_zstack_create(void); +extern int64_t el_sdl2_scroll_create(void); +extern int64_t el_sdl2_label_create(const char* text); +extern int64_t el_sdl2_button_create(const char* label); +extern int64_t el_sdl2_text_field_create(const char* placeholder); +extern int64_t el_sdl2_text_area_create(const char* placeholder); +extern int64_t el_sdl2_image_create(const char* path_or_name); +extern void el_sdl2_widget_set_text(int64_t handle, const char* text); +extern const char* el_sdl2_widget_get_text(int64_t handle); +extern void el_sdl2_widget_set_color(int64_t h, float r, float g, float b, float a); +extern void el_sdl2_widget_set_bg_color(int64_t h, float r, float g, float b, float a); +extern void el_sdl2_widget_set_font(int64_t h, const char* family, int size, int bold); +extern void el_sdl2_widget_set_padding(int64_t h, int top, int right, int bottom, int left); +extern void el_sdl2_widget_set_width(int64_t h, int width); +extern void el_sdl2_widget_set_height(int64_t h, int height); +extern void el_sdl2_widget_set_flex(int64_t h, int flex); +extern void el_sdl2_widget_set_corner_radius(int64_t h, int radius); +extern void el_sdl2_widget_set_disabled(int64_t h, int disabled); +extern void el_sdl2_widget_set_hidden(int64_t h, int hidden); +extern void el_sdl2_widget_add_child(int64_t parent, int64_t child); +extern void el_sdl2_widget_remove_child(int64_t parent, int64_t child); +extern void el_sdl2_widget_destroy(int64_t handle); +extern void el_sdl2_widget_on_click(int64_t h, const char* fn_name); +extern void el_sdl2_widget_on_change(int64_t h, const char* fn_name); +extern void el_sdl2_widget_on_submit(int64_t h, const char* fn_name); + +void __native_init(void) { el_sdl2_init(); } +void __native_run_loop(void) { el_sdl2_run_loop(); } + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_sdl2_window_create( + EL_CSTR(title), + (int)(int64_t)width, (int)(int64_t)height, + (int)(int64_t)min_width, (int)(int64_t)min_height); +} + +void __window_show(el_val_t h) { el_sdl2_window_show((int64_t)h); } +void __window_set_title(el_val_t h, el_val_t t) { el_sdl2_window_set_title((int64_t)h, EL_CSTR(t)); } + +el_val_t __vstack_create(el_val_t spacing) { return (el_val_t)el_sdl2_vstack_create((int)(int64_t)spacing); } +el_val_t __hstack_create(el_val_t spacing) { return (el_val_t)el_sdl2_hstack_create((int)(int64_t)spacing); } +el_val_t __zstack_create(void) { return (el_val_t)el_sdl2_zstack_create(); } +el_val_t __scroll_create(void) { return (el_val_t)el_sdl2_scroll_create(); } + +el_val_t __label_create(el_val_t text) { return (el_val_t)el_sdl2_label_create(EL_CSTR(text)); } +el_val_t __button_create(el_val_t label) { return (el_val_t)el_sdl2_button_create(EL_CSTR(label)); } +el_val_t __text_field_create(el_val_t placeholder) { return (el_val_t)el_sdl2_text_field_create(EL_CSTR(placeholder)); } +el_val_t __text_area_create(el_val_t placeholder) { return (el_val_t)el_sdl2_text_area_create(EL_CSTR(placeholder)); } +el_val_t __image_create(el_val_t path_or_name) { return (el_val_t)el_sdl2_image_create(EL_CSTR(path_or_name)); } + +void __widget_set_text(el_val_t h, el_val_t t) { el_sdl2_widget_set_text((int64_t)h, EL_CSTR(t)); } + +el_val_t __widget_get_text(el_val_t h) { + const char* s = el_sdl2_widget_get_text((int64_t)h); + if (!s) return EL_STR(""); + return EL_STR(s); +} + +void __widget_set_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_sdl2_widget_set_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_bg_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_sdl2_widget_set_bg_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_font(el_val_t h, el_val_t family, el_val_t size, el_val_t bold) { + el_sdl2_widget_set_font((int64_t)h, EL_CSTR(family), + (int)(int64_t)size, (int)(int64_t)bold); +} + +void __widget_set_padding(el_val_t h, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_sdl2_widget_set_padding((int64_t)h, + (int)(int64_t)top, (int)(int64_t)right, + (int)(int64_t)bottom, (int)(int64_t)left); +} + +void __widget_set_width(el_val_t h, el_val_t w) { el_sdl2_widget_set_width((int64_t)h, (int)(int64_t)w); } +void __widget_set_height(el_val_t h, el_val_t ht) { el_sdl2_widget_set_height((int64_t)h, (int)(int64_t)ht); } +void __widget_set_flex(el_val_t h, el_val_t f) { el_sdl2_widget_set_flex((int64_t)h, (int)(int64_t)f); } +void __widget_set_corner_radius(el_val_t h, el_val_t r) { el_sdl2_widget_set_corner_radius((int64_t)h, (int)(int64_t)r); } +void __widget_set_disabled(el_val_t h, el_val_t d) { el_sdl2_widget_set_disabled((int64_t)h, (int)(int64_t)d); } +void __widget_set_hidden(el_val_t h, el_val_t hid) { el_sdl2_widget_set_hidden((int64_t)h, (int)(int64_t)hid); } +void __widget_add_child(el_val_t p, el_val_t c) { el_sdl2_widget_add_child((int64_t)p, (int64_t)c); } +void __widget_remove_child(el_val_t p, el_val_t c) { el_sdl2_widget_remove_child((int64_t)p, (int64_t)c); } +void __widget_destroy(el_val_t h) { el_sdl2_widget_destroy((int64_t)h); } + +void __widget_on_click(el_val_t h, el_val_t fn_name) { el_sdl2_widget_on_click((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_change(el_val_t h, el_val_t fn_name) { el_sdl2_widget_on_change((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_submit(el_val_t h, el_val_t fn_name) { el_sdl2_widget_on_submit((int64_t)h, EL_CSTR(fn_name)); } + +#endif /* EL_TARGET_SDL2 */ + +/* ── EL_TARGET_LVGL — LVGL v9 embedded backend ─────────────────────────────── + * + * These builtins are compiled in only when EL_TARGET_LVGL is defined. + * Each wrapper translates el_val_t arguments (opaque int64_t) into the typed + * parameters that el_lvgl_* expects, then calls through. + * + * Build: + * gcc -DEL_TARGET_LVGL -I./lvgl el_lvgl.c el_seed.c -c ... + * # Link with lvgl.a. For bare-metal add -DEL_LVGL_NO_DLSYM. + * + * __manifest_read is shared — defined unconditionally above. + */ + +#ifdef EL_TARGET_LVGL + +extern void el_lvgl_init(void); +extern void el_lvgl_run_loop(void); +extern int64_t el_lvgl_window_create(const char *title, int w, int h, + int mw, int mh); +extern void el_lvgl_window_show(int64_t handle); +extern void el_lvgl_window_set_title(int64_t handle, const char *title); +extern int64_t el_lvgl_vstack_create(int spacing); +extern int64_t el_lvgl_hstack_create(int spacing); +extern int64_t el_lvgl_zstack_create(void); +extern int64_t el_lvgl_scroll_create(void); +extern int64_t el_lvgl_label_create(const char *text); +extern int64_t el_lvgl_button_create(const char *label); +extern int64_t el_lvgl_text_field_create(const char *placeholder); +extern int64_t el_lvgl_text_area_create(const char *placeholder); +extern int64_t el_lvgl_image_create(const char *path_or_name); +extern void el_lvgl_widget_set_text(int64_t handle, const char *text); +extern const char *el_lvgl_widget_get_text(int64_t handle); +extern void el_lvgl_widget_set_color(int64_t h, float r, float g, + float b, float a); +extern void el_lvgl_widget_set_bg_color(int64_t h, float r, float g, + float b, float a); +extern void el_lvgl_widget_set_font(int64_t h, const char *family, + int size, int bold); +extern void el_lvgl_widget_set_padding(int64_t h, int top, int right, + int bottom, int left); +extern void el_lvgl_widget_set_width(int64_t h, int width); +extern void el_lvgl_widget_set_height(int64_t h, int height); +extern void el_lvgl_widget_set_flex(int64_t h, int flex); +extern void el_lvgl_widget_set_corner_radius(int64_t h, int radius); +extern void el_lvgl_widget_set_disabled(int64_t h, int disabled); +extern void el_lvgl_widget_set_hidden(int64_t h, int hidden); +extern void el_lvgl_widget_add_child(int64_t parent, int64_t child); +extern void el_lvgl_widget_remove_child(int64_t parent, int64_t child); +extern void el_lvgl_widget_destroy(int64_t handle); +extern void el_lvgl_widget_on_click(int64_t h, const char *fn_name); +extern void el_lvgl_widget_on_change(int64_t h, const char *fn_name); +extern void el_lvgl_widget_on_submit(int64_t h, const char *fn_name); + +void __native_init(void) { el_lvgl_init(); } +void __native_run_loop(void) { el_lvgl_run_loop(); } + +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height) { + return (el_val_t)el_lvgl_window_create( + EL_CSTR(title), + (int)(int64_t)width, (int)(int64_t)height, + (int)(int64_t)min_width, (int)(int64_t)min_height); +} + +void __window_show(el_val_t h) { el_lvgl_window_show((int64_t)h); } +void __window_set_title(el_val_t h, el_val_t t) { el_lvgl_window_set_title((int64_t)h, EL_CSTR(t)); } + +el_val_t __vstack_create(el_val_t spacing) { return (el_val_t)el_lvgl_vstack_create((int)(int64_t)spacing); } +el_val_t __hstack_create(el_val_t spacing) { return (el_val_t)el_lvgl_hstack_create((int)(int64_t)spacing); } +el_val_t __zstack_create(void) { return (el_val_t)el_lvgl_zstack_create(); } +el_val_t __scroll_create(void) { return (el_val_t)el_lvgl_scroll_create(); } + +el_val_t __label_create(el_val_t text) { return (el_val_t)el_lvgl_label_create(EL_CSTR(text)); } +el_val_t __button_create(el_val_t label) { return (el_val_t)el_lvgl_button_create(EL_CSTR(label)); } +el_val_t __text_field_create(el_val_t placeholder) { return (el_val_t)el_lvgl_text_field_create(EL_CSTR(placeholder)); } +el_val_t __text_area_create(el_val_t placeholder) { return (el_val_t)el_lvgl_text_area_create(EL_CSTR(placeholder)); } +el_val_t __image_create(el_val_t path_or_name) { return (el_val_t)el_lvgl_image_create(EL_CSTR(path_or_name)); } + +void __widget_set_text(el_val_t h, el_val_t t) { el_lvgl_widget_set_text((int64_t)h, EL_CSTR(t)); } + +el_val_t __widget_get_text(el_val_t h) { + const char *s = el_lvgl_widget_get_text((int64_t)h); + if (!s) return EL_STR(""); + return EL_STR(s); /* pointer into LVGL internal storage — valid until next LVGL op */ +} + +void __widget_set_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_lvgl_widget_set_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_bg_color(el_val_t h, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + el_lvgl_widget_set_bg_color((int64_t)h, + (float)el_to_float(r), (float)el_to_float(g), + (float)el_to_float(b), (float)el_to_float(a)); +} + +void __widget_set_font(el_val_t h, el_val_t family, el_val_t size, el_val_t bold) { + el_lvgl_widget_set_font((int64_t)h, EL_CSTR(family), + (int)(int64_t)size, (int)(int64_t)bold); +} + +void __widget_set_padding(el_val_t h, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left) { + el_lvgl_widget_set_padding((int64_t)h, + (int)(int64_t)top, (int)(int64_t)right, + (int)(int64_t)bottom, (int)(int64_t)left); +} + +void __widget_set_width(el_val_t h, el_val_t w) { el_lvgl_widget_set_width((int64_t)h, (int)(int64_t)w); } +void __widget_set_height(el_val_t h, el_val_t ht) { el_lvgl_widget_set_height((int64_t)h, (int)(int64_t)ht); } +void __widget_set_flex(el_val_t h, el_val_t f) { el_lvgl_widget_set_flex((int64_t)h, (int)(int64_t)f); } +void __widget_set_corner_radius(el_val_t h, el_val_t r) { el_lvgl_widget_set_corner_radius((int64_t)h, (int)(int64_t)r); } +void __widget_set_disabled(el_val_t h, el_val_t d) { el_lvgl_widget_set_disabled((int64_t)h, (int)(int64_t)d); } +void __widget_set_hidden(el_val_t h, el_val_t hid) { el_lvgl_widget_set_hidden((int64_t)h, (int)(int64_t)hid); } +void __widget_add_child(el_val_t p, el_val_t c) { el_lvgl_widget_add_child((int64_t)p, (int64_t)c); } +void __widget_remove_child(el_val_t p, el_val_t c) { el_lvgl_widget_remove_child((int64_t)p, (int64_t)c); } +void __widget_destroy(el_val_t h) { el_lvgl_widget_destroy((int64_t)h); } + +void __widget_on_click(el_val_t h, el_val_t fn_name) { el_lvgl_widget_on_click((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_change(el_val_t h, el_val_t fn_name) { el_lvgl_widget_on_change((int64_t)h, EL_CSTR(fn_name)); } +void __widget_on_submit(el_val_t h, el_val_t fn_name) { el_lvgl_widget_on_submit((int64_t)h, EL_CSTR(fn_name)); } + +#endif /* EL_TARGET_LVGL */ + +/* ── Cryptographic hashing ────────────────────────────────────────────────── */ + +el_val_t __sha256_hex(el_val_t sv) { + const char* s = EL_CSTR(sv); + if (!s) s = ""; + _seed_sha256_ctx ctx; + _seed_sha256_init(&ctx); + _seed_sha256_update(&ctx, (const uint8_t*)s, strlen(s)); + uint8_t digest[32]; + _seed_sha256_final(&ctx, digest); + static const char hex[] = "0123456789abcdef"; + char* out = malloc(65); + if (!out) return EL_STR(""); + for (int i=0; i<32; i++) { + out[i*2] = hex[(digest[i]>>4)&0xf]; + out[i*2+1] = hex[digest[i]&0xf]; + } + out[64] = '\0'; + return EL_STR(out); +} diff --git a/ui/examples/native-hello/build-docker/runtime/el_seed.h b/ui/examples/native-hello/build-docker/runtime/el_seed.h new file mode 100644 index 0000000..08767df --- /dev/null +++ b/ui/examples/native-hello/build-docker/runtime/el_seed.h @@ -0,0 +1,324 @@ +/* + * el_seed.h — El language seed runtime header + * + * Declares all OS-boundary primitives available to compiled El programs. + * All functions use the __ prefix convention. Signatures use el_val_t (= int64_t) + * as the universal value type. + * + * el_seed.c is the complete C boundary for the El runtime. The heavy runtime + * (el_runtime.c) has been retired — everything lives in el_seed.c plus the + * native El runtime (runtime/ *.el files). + * + * Link requirements: + * -lcurl — HTTP client (__http_do, __http_do_to_file) + * -lpthread — threading (__thread_create, __thread_join, __mutex_new, ...) + * + * Canonical compile (via elb): + * elb builds and links el_seed.c automatically. + */ + +#pragma once + +#include +#include + +/* ── Value model ───────────────────────────────────────────────────────────── + * All El values are el_val_t (int64_t). On 64-bit systems a pointer fits. + * String -> el_val_t (holds const char* via uintptr_t cast) + * Int -> el_val_t (stored directly) + * Bool -> el_val_t (0 = false, nonzero = true) + * Void -> void + */ +typedef int64_t el_val_t; + +#define EL_STR(s) ((el_val_t)(uintptr_t)(s)) +#define EL_CSTR(v) ((const char*)(uintptr_t)(v)) +#define EL_INT(v) (v) +#define EL_NULL ((el_val_t)0) + +/* Float values share the el_val_t slot via bit-cast. */ +static inline double el_to_float(el_val_t v) { + union { int64_t i; double f; } u; u.i = (int64_t)v; return u.f; +} +static inline el_val_t el_from_float(double f) { + union { double f; int64_t i; } u; u.f = f; return (el_val_t)u.i; +} + +#ifdef __cplusplus +extern "C" { +#endif + +/* ── String primitives ───────────────────────────────────────────────────── */ + +el_val_t __str_len(el_val_t s); +el_val_t __str_char_at(el_val_t s, el_val_t i); /* returns Int (byte value) */ +el_val_t __str_alloc(el_val_t n); /* malloc(n+1), zero-init, return String */ +el_val_t __str_set_char(el_val_t s, el_val_t i, el_val_t c); /* s[i]=c, return s */ +el_val_t __str_cmp(el_val_t a, el_val_t b); /* strcmp result as Int */ +el_val_t __str_ncmp(el_val_t a, el_val_t b, el_val_t n); /* strncmp */ +el_val_t __str_concat_raw(el_val_t a, el_val_t b); /* malloc+strcpy concat */ +el_val_t __str_slice_raw(el_val_t s, el_val_t start, el_val_t end); /* substring copy */ +el_val_t __int_to_str(el_val_t n); +el_val_t __str_to_int(el_val_t s); +el_val_t __float_to_str(el_val_t f); /* f is bit-cast double */ +el_val_t __str_to_float(el_val_t s); /* strtod, bit-cast result */ + +/* ── I/O ─────────────────────────────────────────────────────────────────── */ + +void __println(el_val_t s); +void __print(el_val_t s); +el_val_t __readline(void); + +/* ── Filesystem ──────────────────────────────────────────────────────────── */ + +el_val_t __fs_read(el_val_t path); +el_val_t __fs_write(el_val_t path, el_val_t content); +el_val_t __fs_exists(el_val_t path); +el_val_t __fs_list_raw(el_val_t path); /* newline-separated filenames */ +el_val_t __fs_mkdir(el_val_t path); +el_val_t __fs_write_bytes(el_val_t path, el_val_t bytes, el_val_t n); + +/* ── HTTP client ─────────────────────────────────────────────────────────── */ + +/* Unified HTTP call. headers_json is a JSON object of header name->value pairs + * (e.g. {"Authorization":"Bearer ...","Content-Type":"application/json"}). + * Use "" or "{}" for no extra headers. timeout_ms <= 0 uses the default. */ +el_val_t __http_do(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t timeout_ms); + +/* Stream response body directly to a file. Returns 1 on success, 0 on failure. */ +el_val_t __http_do_to_file(el_val_t method, el_val_t url, el_val_t body, + el_val_t headers_json, el_val_t out_path); + +/* ── HTTP server ─────────────────────────────────────────────────────────── */ + +/* Blocking HTTP server. handler_name is the El function name to dispatch to. + * v1 handler: (method, path, body) -> String + * v2 handler: (method, path, headers_map, body) -> String or envelope */ +void __http_serve(el_val_t port, el_val_t handler_name); +void __http_serve_v2(el_val_t port, el_val_t handler_name); + +/* Build a structured HTTP response envelope. + * headers_json: JSON object literal like {"Content-Type":"text/plain"} or "{}" */ +el_val_t __http_response(el_val_t status, el_val_t headers_json, el_val_t body); + +/* ── HTTP SSE — Server-Sent Events streaming ─────────────────────────────── */ + +/* Returns the raw file descriptor for the current HTTP connection. + * Valid only inside an http_serve_v2 handler before it returns. + * Returns -1 if called outside a handler context. */ +el_val_t __http_conn_fd(void); + +/* Sends SSE response headers on conn_id (the fd from __http_conn_fd), + * keeping the connection open for streaming. Returns 1 on success, 0 on + * write failure. Call once at the start of an SSE handler. */ +el_val_t __http_sse_open(el_val_t conn_id); + +/* Writes one SSE event frame: "data: \n\n". data must not contain + * newlines. Returns 1 on success, 0 if the client disconnected. */ +el_val_t __http_sse_send(el_val_t conn_id, el_val_t data); + +/* Closes the SSE connection. The handler must return http_sse_sentinel() + * so the HTTP worker does not double-close the fd. */ +el_val_t __http_sse_close(el_val_t conn_id); + +/* ── Threading ───────────────────────────────────────────────────────────── */ + +/* Create a thread that calls the named El function with a String argument. + * fn_name is resolved via dlsym(RTLD_DEFAULT, fn_name). Returns a thread + * handle Int that can be passed to __thread_join. Returns -1 on failure. */ +el_val_t __thread_create(el_val_t fn_name, el_val_t arg); + +/* Wait for thread tid (returned by __thread_create) to finish. + * Returns the thread's return value as a String. */ +el_val_t __thread_join(el_val_t tid); + +/* Allocate a new mutex. Returns a handle Int (index into internal table). */ +el_val_t __mutex_new(void); + +void __mutex_lock(el_val_t m); +void __mutex_unlock(el_val_t m); + +/* ── Subprocess ──────────────────────────────────────────────────────────── */ + +el_val_t __exec(el_val_t cmd); /* popen, capture all stdout, return String */ +void __exec_bg(el_val_t cmd); /* fire and forget */ + +/* ── Environment and process ─────────────────────────────────────────────── */ + +el_val_t __env_get(el_val_t key); /* getenv, return "" if not set */ +void __exit_program(el_val_t code); +el_val_t __args_json(void); /* CLI args as JSON array string */ + +/* ── Time ────────────────────────────────────────────────────────────────── */ + +el_val_t __time_now_ns(void); /* clock_gettime REALTIME, nanoseconds */ +void __sleep_ms(el_val_t ms); + +/* ── UUID ────────────────────────────────────────────────────────────────── */ + +el_val_t __uuid_v4(void); + +/* ── Math ────────────────────────────────────────────────────────────────── */ + +el_val_t __sqrt_f(el_val_t f); +el_val_t __log_f(el_val_t f); +el_val_t __ln_f(el_val_t f); +el_val_t __sin_f(el_val_t f); +el_val_t __cos_f(el_val_t f); +el_val_t __pi_f(void); + +/* ── JSON ────────────────────────────────────────────────────────────────── */ + +el_val_t __json_get(el_val_t json, el_val_t key); +el_val_t __json_get_raw(el_val_t json_str, el_val_t key); +el_val_t __json_parse(el_val_t s); +el_val_t __json_stringify(el_val_t v); +el_val_t __json_parse_map(el_val_t json_str); /* alias for __json_parse */ +el_val_t __json_stringify_val(el_val_t val); /* alias for __json_stringify */ +el_val_t __json_array_len(el_val_t json_str); +el_val_t __json_array_get(el_val_t json_str, el_val_t index); +el_val_t __json_array_get_string(el_val_t json_str, el_val_t index); +el_val_t __json_get_string(el_val_t json_str, el_val_t key); +el_val_t __json_get_int(el_val_t json_str, el_val_t key); +el_val_t __json_get_float(el_val_t json_str, el_val_t key); +el_val_t __json_get_bool(el_val_t json_str, el_val_t key); +el_val_t __json_set(el_val_t json_str, el_val_t key, el_val_t value); + +/* ── State K/V ───────────────────────────────────────────────────────────── */ + +el_val_t __state_set(el_val_t key, el_val_t value); +el_val_t __state_get(el_val_t key); +el_val_t __state_del(el_val_t key); +el_val_t __state_keys(void); + +/* ── HTML/URL ────────────────────────────────────────────────────────────── */ + +el_val_t __html_sanitize(el_val_t input_html, el_val_t allowlist_json); +el_val_t __url_encode(el_val_t s); +el_val_t __url_decode(el_val_t s); + +/* ── Engram ──────────────────────────────────────────────────────────────── */ + +el_val_t __engram_node(el_val_t content, el_val_t node_type, el_val_t salience); +el_val_t __engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags); +el_val_t __engram_node_layered(el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t certainty, el_val_t confidence, + el_val_t status, el_val_t tags, el_val_t layer_id); +el_val_t __engram_add_layer(el_val_t name, el_val_t priority, el_val_t suppressible, + el_val_t transparent, el_val_t injectable); +el_val_t __engram_remove_layer(el_val_t layer_id); +el_val_t __engram_list_layers(void); +el_val_t __engram_get_node(el_val_t id); +void __engram_strengthen(el_val_t node_id); +void __engram_forget(el_val_t node_id); +el_val_t __engram_node_count(void); +el_val_t __engram_search(el_val_t query, el_val_t limit); +el_val_t __engram_scan_nodes(el_val_t limit, el_val_t offset); +void __engram_connect(el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t relation); +el_val_t __engram_edge_between(el_val_t from_id, el_val_t to_id); +el_val_t __engram_neighbors(el_val_t node_id); +el_val_t __engram_neighbors_filtered(el_val_t node_id, el_val_t max_depth, el_val_t direction); +el_val_t __engram_edge_count(void); +el_val_t __engram_activate(el_val_t query, el_val_t depth); +el_val_t __engram_save(el_val_t path); +el_val_t __engram_load(el_val_t path); +el_val_t __engram_get_node_json(el_val_t id); +el_val_t __engram_search_json(el_val_t query, el_val_t limit); +el_val_t __engram_scan_nodes_json(el_val_t limit, el_val_t offset); +el_val_t __engram_scan_nodes_by_type_json(el_val_t node_type, el_val_t limit, el_val_t offset); +el_val_t __engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction); +el_val_t __engram_activate_json(el_val_t query, el_val_t depth); +el_val_t __engram_stats_json(void); +el_val_t __engram_list_layers_json(void); +el_val_t __engram_compile_layered_json(el_val_t intent, el_val_t depth); + +/* ── Cryptographic hashing ────────────────────────────────────────────────── */ + +/* __sha256_hex — return the SHA-256 hex digest of a string. + * The returned string is 64 hex characters (lowercase). */ +el_val_t __sha256_hex(el_val_t s); + +/* ── args init (called from main) ────────────────────────────────────────── */ +/* Store argc/argv for __args_json. Call once at the start of main(). */ +void el_seed_init_args(int argc, char** argv); + +/* ── Native widget system (macOS AppKit) ─────────────────────────────────── */ +/* + * Available when compiled with -DEL_TARGET_MACOS and linked with el_appkit.m + * (-framework Cocoa). Widget handles are opaque Int values (int64_t slot + * indices). The null/invalid handle value is -1. + * + * Lifecycle: + * 1. Call __native_init() once at program start. + * 2. Build widget tree with __window_create / __vstack_create / etc. + * 3. Attach children with __widget_add_child(parent, child). + * 4. Register callbacks with __widget_on_click / __widget_on_change. + * 5. Call __window_show(win) to make the window visible. + * 6. Call __native_run_loop() — never returns. AppKit owns the thread. + * + * Callback El function signature: + * fn my_handler(widget: Int, data: String) -> Void + */ +#ifdef EL_TARGET_MACOS + +/* Initialisation */ +void __native_init(void); +void __native_run_loop(void); + +/* Window */ +el_val_t __window_create(el_val_t title, el_val_t width, el_val_t height, + el_val_t min_width, el_val_t min_height); +void __window_show(el_val_t handle); +void __window_set_title(el_val_t handle, el_val_t title); + +/* Layout containers */ +el_val_t __vstack_create(el_val_t spacing); +el_val_t __hstack_create(el_val_t spacing); +el_val_t __zstack_create(void); +el_val_t __scroll_create(void); + +/* Widgets */ +el_val_t __label_create(el_val_t text); +el_val_t __button_create(el_val_t label); +el_val_t __text_field_create(el_val_t placeholder); +el_val_t __text_area_create(el_val_t placeholder); +el_val_t __image_create(el_val_t path_or_name); + +/* Widget properties */ +void __widget_set_text(el_val_t handle, el_val_t text); +el_val_t __widget_get_text(el_val_t handle); +void __widget_set_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +void __widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +void __widget_set_font(el_val_t handle, el_val_t family, el_val_t size, el_val_t bold); +void __widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, + el_val_t bottom, el_val_t left); +void __widget_set_width(el_val_t handle, el_val_t width); +void __widget_set_height(el_val_t handle, el_val_t height); +void __widget_set_flex(el_val_t handle, el_val_t flex); +void __widget_set_corner_radius(el_val_t handle, el_val_t radius); +void __widget_set_disabled(el_val_t handle, el_val_t disabled); +void __widget_set_hidden(el_val_t handle, el_val_t hidden); + +/* Layout / tree */ +void __widget_add_child(el_val_t parent, el_val_t child); +void __widget_remove_child(el_val_t parent, el_val_t child); +void __widget_destroy(el_val_t handle); + +/* Events */ +void __widget_on_click(el_val_t handle, el_val_t fn_name); +void __widget_on_change(el_val_t handle, el_val_t fn_name); +void __widget_on_submit(el_val_t handle, el_val_t fn_name); + +/* Manifest reader */ +/* Parse the app{} block from manifest.el at path. Returns a JSON string: + * {"title":"...","width":N,"height":N,"min_width":N,"min_height":N} */ +el_val_t __manifest_read(el_val_t path); + +#endif /* EL_TARGET_MACOS */ + +#ifdef __cplusplus +} +#endif diff --git a/ui/examples/native-hello/build-gtk4.sh b/ui/examples/native-hello/build-gtk4.sh new file mode 100755 index 0000000..0cb2ad9 --- /dev/null +++ b/ui/examples/native-hello/build-gtk4.sh @@ -0,0 +1,182 @@ +#!/usr/bin/env bash +# build-gtk4.sh — Compile and run native-hello using the GTK4 bridge on macOS. +# +# Usage: +# ./build-gtk4.sh # compile and run +# ./build-gtk4.sh compile # compile only +# ./build-gtk4.sh clean # remove build artefacts +# +# Requirements: +# - elc in PATH (or ../../../lang/dist/platform/elc) +# - clang (Xcode Command Line Tools) +# - GTK4 via Homebrew: brew install gtk4 +# - macOS 12+ +# +# This is the same pipeline as build.sh but targeting the GTK4 backend: +# - Links with $(pkg-config --libs gtk4) instead of -framework Cocoa +# - Compiles el_gtk4.c (plain C) instead of el_appkit.m (ObjC) +# - Defines EL_TARGET_LINUX (the GTK4 target flag) +# +# Multi-file compilation strategy: see build.sh comments — identical rationale. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +EL_LANG_ROOT="${SCRIPT_DIR}/../../../lang" +EL_UI_ROOT="${SCRIPT_DIR}/../.." +EL_RUNTIME="${EL_LANG_ROOT}/el-compiler/runtime" +EL_NATIVE_VESSEL="${EL_UI_ROOT}/vessels/el-native/src/main.el" +BUILD_DIR="${SCRIPT_DIR}/build-gtk4" + +# Locate elc +if command -v elc &>/dev/null; then + ELC="elc" +elif [ -x "${EL_LANG_ROOT}/dist/platform/elc" ]; then + ELC="${EL_LANG_ROOT}/dist/platform/elc" +else + echo "Error: elc not found. Add it to PATH or place it at:" + echo " ${EL_LANG_ROOT}/dist/platform/elc" + exit 1 +fi + +# GTK4 pkg-config flags +GTK4_CFLAGS=$(pkg-config --cflags gtk4) +GTK4_LIBS=$(pkg-config --libs gtk4) + +CLANG_FLAGS_COMMON=( + -std=c11 + -DEL_TARGET_LINUX + -I "${EL_RUNTIME}" +) + +clean() { + rm -rf "${BUILD_DIR}" + echo "Cleaned." +} + +compile() { + mkdir -p "${BUILD_DIR}" + + # ── 1. Vessel forward-declarations header ───────────────────────────────── + # elc --emit-header emits full function bodies, not just prototypes. + # Extract only the forward-declaration lines: stop at the first function + # definition (a line that ends with ') {' opening a body block). + # macOS awk does not support \s — use POSIX [[:space:]] instead. + echo "==> Generating el-native vessel header (declarations only)..." + "${ELC}" --emit-header "${EL_NATIVE_VESSEL}" \ + | awk 'BEGIN{in_body=0} /^[a-zA-Z_].+\)[[:space:]]*\{/ {in_body=1} !in_body{print}' \ + > "${BUILD_DIR}/el_native_vessel.h" + + # ── 2. Compile el-native vessel to C ────────────────────────────────────── + echo "==> Compiling el-native vessel to C..." + "${ELC}" "${EL_NATIVE_VESSEL}" \ + > "${BUILD_DIR}/el_native_vessel.c" + + # ── 3. Compile app entry to C ───────────────────────────────────────────── + echo "==> Compiling app entry to C..." + EL_MANIFEST="${SCRIPT_DIR}/manifest.el" \ + "${ELC}" "${SCRIPT_DIR}/src/main.el" \ + > "${BUILD_DIR}/native_hello.c" + + # ── 4. Compile el_gtk4.c (plain C, GTK4 backend) ───────────────────────── + echo "==> Compiling el_gtk4.c (GTK4 bridge)..." + # shellcheck disable=SC2086 + clang \ + -std=c11 \ + -DEL_TARGET_LINUX \ + -I "${EL_RUNTIME}" \ + ${GTK4_CFLAGS} \ + -c "${EL_RUNTIME}/el_gtk4.c" \ + -o "${BUILD_DIR}/el_gtk4.o" + + # ── 5a. Compile el_seed.c ───────────────────────────────────────────────── + # el_seed.c provides the OS-boundary __-prefixed primitives + thin wrappers. + # With -DEL_TARGET_LINUX, the EL_TARGET_LINUX section in el_seed.c is + # compiled in (GTK4 forwarders) and the EL_TARGET_MACOS section is excluded. + echo "==> Compiling el_seed.c (EL_TARGET_LINUX)..." + # shellcheck disable=SC2086 + clang "${CLANG_FLAGS_COMMON[@]}" \ + ${GTK4_CFLAGS} \ + -c "${EL_RUNTIME}/el_seed.c" \ + -o "${BUILD_DIR}/el_seed.o" + + # ── 5b. Compile el_runtime.c and patch out duplicate __-prefixed symbols ── + # Same strategy as build.sh: el_runtime.c has duplicates of the __-prefixed + # OS wrappers that el_seed.c defines. Hide el_runtime.o's copies with nmedit. + echo "==> Compiling el_runtime.c..." + clang "${CLANG_FLAGS_COMMON[@]}" \ + -c "${EL_RUNTIME}/el_runtime.c" \ + -o "${BUILD_DIR}/el_runtime.o" + + echo "==> Patching el_runtime.o (hiding __-prefixed symbols duplicated in el_seed.o)..." + nm "${BUILD_DIR}/el_seed.o" 2>/dev/null \ + | awk '/^[0-9a-f]+ T _/{print $3}' | sort > "${BUILD_DIR}/.seed_T.txt" + nm "${BUILD_DIR}/el_runtime.o" 2>/dev/null \ + | awk '/^[0-9a-f]+ T _/{print $3}' | sort > "${BUILD_DIR}/.rt_T.txt" + comm -23 "${BUILD_DIR}/.rt_T.txt" "${BUILD_DIR}/.seed_T.txt" \ + > "${BUILD_DIR}/.rt_keep.txt" + nmedit -s "${BUILD_DIR}/.rt_keep.txt" "${BUILD_DIR}/el_runtime.o" + + # ── 6. Compile el-native vessel object ──────────────────────────────────── + # Vessel code calls __-prefixed builtins. el_native_target.h provides the + # EL_TARGET_LINUX block of declarations (same function signatures as MACOS). + echo "==> Compiling el-native vessel object..." + clang "${CLANG_FLAGS_COMMON[@]}" \ + -include "${EL_RUNTIME}/el_native_target.h" \ + -c "${BUILD_DIR}/el_native_vessel.c" \ + -o "${BUILD_DIR}/el_native_vessel.o" + + echo "==> Patching el_native_vessel.o (hiding vessel main)..." + nm "${BUILD_DIR}/el_native_vessel.o" 2>/dev/null \ + | awk '/^[0-9a-f]+ T _/{print $3}' \ + | grep -v '^_main$' \ + > "${BUILD_DIR}/.vessel_keep.txt" + nmedit -s "${BUILD_DIR}/.vessel_keep.txt" "${BUILD_DIR}/el_native_vessel.o" + + # ── 7. Compile app object ───────────────────────────────────────────────── + # Inject el_native_target.h (float ops + EL_TARGET_LINUX native decls) and + # the vessel's forward-declaration header. + echo "==> Compiling app object..." + clang "${CLANG_FLAGS_COMMON[@]}" \ + -include "${EL_RUNTIME}/el_native_target.h" \ + -include "${BUILD_DIR}/el_native_vessel.h" \ + -c "${BUILD_DIR}/native_hello.c" \ + -o "${BUILD_DIR}/native_hello.o" + + # ── 8. Link ─────────────────────────────────────────────────────────────── + # el_seed.o = OS-boundary primitives (__-prefixed) + GTK4 forwarders + # el_runtime.o = high-level builtins (str_len, json_*, etc.), patched + # el_native_vessel.o = el-level widget API, patched + # el_gtk4.o = GTK4 C bridge + # GTK4_LIBS = $(pkg-config --libs gtk4) + # -ldl = dlsym for callback dispatch + # -lpthread = threading + echo "==> Linking native-hello-gtk4..." + # shellcheck disable=SC2086 + clang "${CLANG_FLAGS_COMMON[@]}" \ + "${BUILD_DIR}/native_hello.o" \ + "${BUILD_DIR}/el_native_vessel.o" \ + "${BUILD_DIR}/el_gtk4.o" \ + "${BUILD_DIR}/el_runtime.o" \ + "${BUILD_DIR}/el_seed.o" \ + ${GTK4_LIBS} \ + -ldl \ + -lpthread \ + -lcurl \ + -o "${BUILD_DIR}/native-hello-gtk4" + + echo "==> Build complete: ${BUILD_DIR}/native-hello-gtk4" +} + +run() { + compile + echo "==> Launching native-hello-gtk4..." + EL_MANIFEST="${SCRIPT_DIR}/manifest.el" \ + "${BUILD_DIR}/native-hello-gtk4" +} + +case "${1:-run}" in + clean) clean ;; + compile) compile ;; + run|*) run ;; +esac diff --git a/ui/examples/native-hello/build-gtk4/.rt_T.txt b/ui/examples/native-hello/build-gtk4/.rt_T.txt new file mode 100644 index 0000000..7657b58 --- /dev/null +++ b/ui/examples/native-hello/build-gtk4/.rt_T.txt @@ -0,0 +1,397 @@ +___args_json +___channel_close +___channel_new +___channel_recv +___channel_send +___channel_try_recv +___env_get +___exec +___exec_bg +___exit_program +___float_to_str +___fs_exists +___fs_list_raw +___fs_mkdir +___fs_read +___fs_write +___fs_write_bytes +___http_conn_fd +___http_do +___http_do_map +___http_do_map_to_file +___http_response +___http_serve +___http_serve_v2 +___http_sse_close +___http_sse_open +___http_sse_send +___int_to_str +___json_array_get +___json_array_get_string +___json_array_len +___json_get +___json_get_raw +___json_parse_map +___json_set +___json_stringify_val +___mutex_lock +___mutex_new +___mutex_unlock +___print +___print_raw +___println +___read_n +___readline +___sha256_hex +___state_del +___state_get +___state_keys +___state_set +___str_alloc +___str_char_at +___str_cmp +___str_concat_raw +___str_len +___str_ncmp +___str_set_char +___str_slice_raw +___str_to_float +___str_to_int +___thread_create +___thread_join +___url_decode +___url_encode +___uuid_v4 +_aead_decrypt +_aead_encrypt +_append +_args +_base64_decode +_base64_encode +_base64url_decode +_base64url_encode +_bool_to_str +_bytes_to_str +_cal_cycle_phase +_cal_format +_cal_in +_cal_to_instant +_config +_cycle_calendar +_decimal_round +_duration_millis +_duration_nanos +_duration_seconds +_duration_to_millis +_duration_to_nanos +_duration_to_seconds +_earth_calendar +_earth_calendar_default +_el_abs +_el_arena_pop +_el_arena_push +_el_base64_encode_n +_el_cgi_init +_el_duration_add +_el_duration_div +_el_duration_eq +_el_duration_from_nanos +_el_duration_ge +_el_duration_gt +_el_duration_le +_el_duration_lt +_el_duration_ne +_el_duration_scale +_el_duration_sub +_el_get_field +_el_html_sanitize +_el_instant_add_dur +_el_instant_diff +_el_instant_eq +_el_instant_ge +_el_instant_gt +_el_instant_le +_el_instant_lt +_el_instant_ne +_el_instant_sub_dur +_el_list_append +_el_list_clone +_el_list_empty +_el_list_get +_el_list_len +_el_list_new +_el_local_date_add_dur +_el_local_date_eq +_el_local_date_lt +_el_local_time_add_dur +_el_map_get +_el_map_new +_el_map_set +_el_max +_el_mem_check +_el_min +_el_now_instant +_el_release +_el_request_end +_el_request_start +_el_retain +_el_runtime_init_args +_el_runtime_register_handler +_el_runtime_register_handler_v2 +_el_sha256_bytes_n +_el_sleep_duration +_el_str_concat +_engram_activate +_engram_activate_json +_engram_add_layer +_engram_apply_decay_json +_engram_compile_layered_json +_engram_connect +_engram_edge_between +_engram_edge_count +_engram_forget +_engram_get_node +_engram_get_node_json +_engram_list_layers +_engram_list_layers_json +_engram_load +_engram_neighbors +_engram_neighbors_filtered +_engram_neighbors_json +_engram_node +_engram_node_count +_engram_node_full +_engram_node_layered +_engram_query_range +_engram_remove_layer +_engram_save +_engram_scan_nodes +_engram_scan_nodes_by_type_json +_engram_scan_nodes_json +_engram_search +_engram_search_json +_engram_stats_json +_engram_strengthen +_env +_exec +_exec_bg +_exec_capture +_exec_command +_exit_program +_float_to_int +_float_to_str +_format_float +_fs_exists +_fs_list +_fs_list_json +_fs_mkdir +_fs_read +_fs_write +_fs_write_bytes +_get +_getpid_now +_hash_sha256 +_hmac_sha256_bytes +_hmac_sha256_hex +_html_escape +_html_raw +_http_delete +_http_get +_http_get_engram +_http_get_to_file +_http_get_with_headers +_http_patch +_http_post +_http_post_engram +_http_post_form_auth +_http_post_json +_http_post_json_with_headers +_http_post_to_file +_http_post_with_headers +_http_response +_http_serve +_http_serve_v2 +_http_set_handler +_http_set_handler_v2 +_in_calendar +_instant_from_iso8601 +_instant_to_iso8601 +_instant_to_unix_millis +_instant_to_unix_seconds +_int_to_float +_int_to_str +_is_alphanumeric +_is_digit +_is_letter +_is_lowercase +_is_punctuation +_is_uppercase +_is_whitespace +_json_array_get +_json_array_get_string +_json_array_len +_json_array_push +_json_build_array +_json_build_object +_json_escape_string +_json_get +_json_get_bool +_json_get_float +_json_get_int +_json_get_raw +_json_get_string +_json_parse +_json_set +_json_stringify +_len +_list_get +_list_join +_list_len +_list_push +_list_push_front +_list_range +_llm_call +_llm_call_agentic +_llm_call_system +_llm_models +_llm_register_tool +_llm_vision +_local_date +_local_date_day +_local_date_month +_local_date_year +_local_datetime +_local_time +_local_time_hour +_local_time_minute +_local_time_nanos +_local_time_second +_log_info +_log_warn +_map_get +_map_set +_mars_calendar +_math_cos +_math_ln +_math_log +_math_pi +_math_sin +_math_sqrt +_native_int_to_str +_native_list_append +_native_list_clone +_native_list_empty +_native_list_get +_native_list_len +_native_str_to_int +_native_string_chars +_no_cycle_calendar +_now +_now_in +_now_millis +_now_ns +_parse_int +_pq_hybrid_handshake +_pq_hybrid_keygen +_pq_kem_decaps +_pq_kem_encaps +_pq_kem_keygen +_pq_keygen_signature +_pq_sign +_pq_verify +_print +_println +_readline +_relative_calendar +_rhythm_and +_rhythm_cycle_phase +_rhythm_cycle_start +_rhythm_duration +_rhythm_event +_rhythm_matches +_rhythm_next_after +_rhythm_or +_rhythm_session_start +_rhythm_weekday +_rhythm_weekly_at +_sha256_bytes +_sha256_hex +_sha3_256_hex +_sleep_ms +_sleep_secs +_state_del +_state_get +_state_get_or +_state_has +_state_keys +_state_set +_stdout_restore +_stdout_to_file +_str_char_at +_str_char_code +_str_concat +_str_contains +_str_count +_str_count_bytes +_str_count_chars +_str_count_digits +_str_count_letters +_str_count_lines +_str_count_words +_str_ends_with +_str_eq +_str_find_chars +_str_format +_str_index_of +_str_index_of_all +_str_join +_str_last_index_of +_str_len +_str_lower +_str_lstrip +_str_pad_left +_str_pad_right +_str_repeat +_str_replace +_str_reverse +_str_rstrip +_str_slice +_str_split +_str_split_chars +_str_split_lines +_str_split_n +_str_starts_with +_str_strip_chars +_str_strip_prefix +_str_strip_suffix +_str_to_bytes +_str_to_float +_str_to_int +_str_to_lower +_str_to_upper +_str_trim +_str_upper +_time_add +_time_diff +_time_format +_time_from_parts +_time_now +_time_now_ms +_time_now_utc +_time_to_parts +_ttl_cache_age +_ttl_cache_get +_ttl_cache_set +_unix_millis +_unix_seconds +_unix_timestamp +_unix_timestamp_ms +_url_decode +_url_encode +_uuid_new +_uuid_v4 +_zone +_zone_local +_zone_offset +_zone_utc +_zoned diff --git a/ui/examples/native-hello/build-gtk4/.rt_keep.txt b/ui/examples/native-hello/build-gtk4/.rt_keep.txt new file mode 100644 index 0000000..6aa9058 --- /dev/null +++ b/ui/examples/native-hello/build-gtk4/.rt_keep.txt @@ -0,0 +1,340 @@ +___channel_close +___channel_new +___channel_recv +___channel_send +___channel_try_recv +___http_do_map +___http_do_map_to_file +___print_raw +___read_n +_aead_decrypt +_aead_encrypt +_append +_args +_base64_decode +_base64_encode +_base64url_decode +_base64url_encode +_bool_to_str +_bytes_to_str +_cal_cycle_phase +_cal_format +_cal_in +_cal_to_instant +_config +_cycle_calendar +_decimal_round +_duration_millis +_duration_nanos +_duration_seconds +_duration_to_millis +_duration_to_nanos +_duration_to_seconds +_earth_calendar +_earth_calendar_default +_el_abs +_el_arena_pop +_el_arena_push +_el_base64_encode_n +_el_cgi_init +_el_duration_add +_el_duration_div +_el_duration_eq +_el_duration_from_nanos +_el_duration_ge +_el_duration_gt +_el_duration_le +_el_duration_lt +_el_duration_ne +_el_duration_scale +_el_duration_sub +_el_get_field +_el_html_sanitize +_el_instant_add_dur +_el_instant_diff +_el_instant_eq +_el_instant_ge +_el_instant_gt +_el_instant_le +_el_instant_lt +_el_instant_ne +_el_instant_sub_dur +_el_list_append +_el_list_clone +_el_list_empty +_el_list_get +_el_list_len +_el_list_new +_el_local_date_add_dur +_el_local_date_eq +_el_local_date_lt +_el_local_time_add_dur +_el_map_get +_el_map_new +_el_map_set +_el_max +_el_mem_check +_el_min +_el_now_instant +_el_release +_el_retain +_el_runtime_init_args +_el_runtime_register_handler +_el_runtime_register_handler_v2 +_el_sha256_bytes_n +_el_sleep_duration +_el_str_concat +_engram_activate +_engram_activate_json +_engram_add_layer +_engram_apply_decay_json +_engram_compile_layered_json +_engram_connect +_engram_edge_between +_engram_edge_count +_engram_forget +_engram_get_node +_engram_get_node_json +_engram_list_layers +_engram_list_layers_json +_engram_load +_engram_neighbors +_engram_neighbors_filtered +_engram_neighbors_json +_engram_node +_engram_node_count +_engram_node_full +_engram_node_layered +_engram_query_range +_engram_remove_layer +_engram_save +_engram_scan_nodes +_engram_scan_nodes_by_type_json +_engram_scan_nodes_json +_engram_search +_engram_search_json +_engram_stats_json +_engram_strengthen +_env +_exec +_exec_bg +_exec_capture +_exec_command +_exit_program +_float_to_int +_float_to_str +_format_float +_fs_exists +_fs_list +_fs_list_json +_fs_mkdir +_fs_read +_fs_write +_fs_write_bytes +_get +_getpid_now +_hash_sha256 +_hmac_sha256_bytes +_hmac_sha256_hex +_html_escape +_html_raw +_http_delete +_http_get +_http_get_engram +_http_get_to_file +_http_get_with_headers +_http_patch +_http_post +_http_post_engram +_http_post_form_auth +_http_post_json +_http_post_json_with_headers +_http_post_to_file +_http_post_with_headers +_http_response +_http_serve +_http_serve_v2 +_http_set_handler +_http_set_handler_v2 +_in_calendar +_instant_from_iso8601 +_instant_to_iso8601 +_instant_to_unix_millis +_instant_to_unix_seconds +_int_to_float +_int_to_str +_is_alphanumeric +_is_digit +_is_letter +_is_lowercase +_is_punctuation +_is_uppercase +_is_whitespace +_json_array_get +_json_array_get_string +_json_array_len +_json_array_push +_json_build_array +_json_build_object +_json_escape_string +_json_get +_json_get_bool +_json_get_float +_json_get_int +_json_get_raw +_json_get_string +_json_parse +_json_set +_json_stringify +_len +_list_get +_list_join +_list_len +_list_push +_list_push_front +_list_range +_llm_call +_llm_call_agentic +_llm_call_system +_llm_models +_llm_register_tool +_llm_vision +_local_date +_local_date_day +_local_date_month +_local_date_year +_local_datetime +_local_time +_local_time_hour +_local_time_minute +_local_time_nanos +_local_time_second +_log_info +_log_warn +_map_get +_map_set +_mars_calendar +_math_cos +_math_ln +_math_log +_math_pi +_math_sin +_math_sqrt +_native_int_to_str +_native_list_append +_native_list_clone +_native_list_empty +_native_list_get +_native_list_len +_native_str_to_int +_native_string_chars +_no_cycle_calendar +_now +_now_in +_now_millis +_now_ns +_parse_int +_pq_hybrid_handshake +_pq_hybrid_keygen +_pq_kem_decaps +_pq_kem_encaps +_pq_kem_keygen +_pq_keygen_signature +_pq_sign +_pq_verify +_print +_println +_readline +_relative_calendar +_rhythm_and +_rhythm_cycle_phase +_rhythm_cycle_start +_rhythm_duration +_rhythm_event +_rhythm_matches +_rhythm_next_after +_rhythm_or +_rhythm_session_start +_rhythm_weekday +_rhythm_weekly_at +_sha256_bytes +_sha256_hex +_sha3_256_hex +_sleep_ms +_sleep_secs +_state_del +_state_get +_state_get_or +_state_has +_state_keys +_state_set +_stdout_restore +_stdout_to_file +_str_char_at +_str_char_code +_str_concat +_str_contains +_str_count +_str_count_bytes +_str_count_chars +_str_count_digits +_str_count_letters +_str_count_lines +_str_count_words +_str_ends_with +_str_eq +_str_find_chars +_str_format +_str_index_of +_str_index_of_all +_str_join +_str_last_index_of +_str_len +_str_lower +_str_lstrip +_str_pad_left +_str_pad_right +_str_repeat +_str_replace +_str_reverse +_str_rstrip +_str_slice +_str_split +_str_split_chars +_str_split_lines +_str_split_n +_str_starts_with +_str_strip_chars +_str_strip_prefix +_str_strip_suffix +_str_to_bytes +_str_to_float +_str_to_int +_str_to_lower +_str_to_upper +_str_trim +_str_upper +_time_add +_time_diff +_time_format +_time_from_parts +_time_now +_time_now_ms +_time_now_utc +_time_to_parts +_ttl_cache_age +_ttl_cache_get +_ttl_cache_set +_unix_millis +_unix_seconds +_unix_timestamp +_unix_timestamp_ms +_url_decode +_url_encode +_uuid_new +_uuid_v4 +_zone +_zone_local +_zone_offset +_zone_utc +_zoned diff --git a/ui/examples/native-hello/build-gtk4/.seed_T.txt b/ui/examples/native-hello/build-gtk4/.seed_T.txt new file mode 100644 index 0000000..260f1fe --- /dev/null +++ b/ui/examples/native-hello/build-gtk4/.seed_T.txt @@ -0,0 +1,137 @@ +___args_json +___button_create +___cos_f +___engram_activate +___engram_activate_json +___engram_add_layer +___engram_compile_layered_json +___engram_connect +___engram_edge_between +___engram_edge_count +___engram_forget +___engram_get_node +___engram_get_node_json +___engram_list_layers +___engram_list_layers_json +___engram_load +___engram_neighbors +___engram_neighbors_filtered +___engram_neighbors_json +___engram_node +___engram_node_count +___engram_node_full +___engram_node_layered +___engram_remove_layer +___engram_save +___engram_scan_nodes +___engram_scan_nodes_by_type_json +___engram_scan_nodes_json +___engram_search +___engram_search_json +___engram_stats_json +___engram_strengthen +___env_get +___exec +___exec_bg +___exit_program +___float_to_str +___fs_exists +___fs_list_raw +___fs_mkdir +___fs_read +___fs_write +___fs_write_bytes +___hstack_create +___html_sanitize +___http_conn_fd +___http_do +___http_do_to_file +___http_response +___http_serve +___http_serve_v2 +___http_sse_close +___http_sse_open +___http_sse_send +___image_create +___int_to_str +___json_array_get +___json_array_get_string +___json_array_len +___json_get +___json_get_bool +___json_get_float +___json_get_int +___json_get_raw +___json_get_string +___json_parse +___json_parse_map +___json_set +___json_stringify +___json_stringify_val +___label_create +___ln_f +___log_f +___manifest_read +___mutex_lock +___mutex_new +___mutex_unlock +___native_init +___native_run_loop +___pi_f +___print +___println +___readline +___scroll_create +___sha256_hex +___sin_f +___sleep_ms +___sqrt_f +___state_del +___state_get +___state_keys +___state_set +___str_alloc +___str_char_at +___str_cmp +___str_concat_raw +___str_len +___str_ncmp +___str_set_char +___str_slice_raw +___str_to_float +___str_to_int +___text_area_create +___text_field_create +___thread_create +___thread_join +___time_now_ns +___url_decode +___url_encode +___uuid_v4 +___vstack_create +___widget_add_child +___widget_destroy +___widget_get_text +___widget_on_change +___widget_on_click +___widget_on_submit +___widget_remove_child +___widget_set_bg_color +___widget_set_color +___widget_set_corner_radius +___widget_set_disabled +___widget_set_flex +___widget_set_font +___widget_set_height +___widget_set_hidden +___widget_set_padding +___widget_set_text +___widget_set_width +___window_create +___window_set_title +___window_show +___zstack_create +_el_request_end +_el_request_start +_el_seed_init_args +_el_seed_set_http_conn_fd diff --git a/ui/examples/native-hello/build-gtk4/.vessel_keep.txt b/ui/examples/native-hello/build-gtk4/.vessel_keep.txt new file mode 100644 index 0000000..a8a7964 --- /dev/null +++ b/ui/examples/native-hello/build-gtk4/.vessel_keep.txt @@ -0,0 +1,55 @@ +_button +_color_hex_a +_color_hex_b +_color_hex_g +_color_hex_r +_hex_channel +_hex_nibble +_hstack +_image +_label +_manifest_height +_manifest_min_height +_manifest_min_width +_manifest_read +_manifest_title +_manifest_width +_native_init +_native_run_loop +_scroll +_style_button_primary +_style_label_body +_style_label_heading +_style_label_muted +_style_surface +_text_area +_text_field +_vstack +_vstack_tight +_widget_add_child +_widget_destroy +_widget_get_text +_widget_on_change +_widget_on_click +_widget_on_submit +_widget_remove_child +_widget_set_bg_color +_widget_set_bg_color_hex +_widget_set_color +_widget_set_color_hex +_widget_set_corner_radius +_widget_set_disabled +_widget_set_flex +_widget_set_font +_widget_set_height +_widget_set_hidden +_widget_set_padding +_widget_set_padding_all +_widget_set_padding_xy +_widget_set_text +_widget_set_width +_window_create +_window_from_manifest +_window_set_title +_window_show +_zstack diff --git a/ui/examples/native-hello/build-gtk4/el_gtk4.o b/ui/examples/native-hello/build-gtk4/el_gtk4.o new file mode 100644 index 0000000000000000000000000000000000000000..34d1efcf173a8d21aa8c484458cb3957559902f2 GIT binary patch literal 33464 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 literal 0 HcmV?d00001 diff --git a/ui/examples/native-hello/build-gtk4/el_native_vessel.c b/ui/examples/native-hello/build-gtk4/el_native_vessel.c new file mode 100644 index 0000000..28bf38c --- /dev/null +++ b/ui/examples/native-hello/build-gtk4/el_native_vessel.c @@ -0,0 +1,459 @@ +#include +#include +#include "el_runtime.h" + +el_val_t native_init(void); +el_val_t native_run_loop(void); +el_val_t manifest_read(el_val_t path); +el_val_t manifest_title(el_val_t m); +el_val_t manifest_width(el_val_t m); +el_val_t manifest_height(el_val_t m); +el_val_t manifest_min_width(el_val_t m); +el_val_t manifest_min_height(el_val_t m); +el_val_t window_create(el_val_t title, el_val_t width, el_val_t height, el_val_t min_width, el_val_t min_height); +el_val_t window_from_manifest(el_val_t manifest_path); +el_val_t window_show(el_val_t handle); +el_val_t window_set_title(el_val_t handle, el_val_t title); +el_val_t vstack(el_val_t spacing); +el_val_t vstack_tight(void); +el_val_t hstack(el_val_t spacing); +el_val_t zstack(void); +el_val_t scroll(void); +el_val_t label(el_val_t text); +el_val_t button(el_val_t label); +el_val_t text_field(el_val_t placeholder); +el_val_t text_area(el_val_t placeholder); +el_val_t image(el_val_t path_or_name); +el_val_t widget_set_text(el_val_t handle, el_val_t text); +el_val_t widget_get_text(el_val_t handle); +el_val_t widget_set_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_font(el_val_t handle, el_val_t family, el_val_t size, el_val_t bold); +el_val_t widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, el_val_t bottom, el_val_t left); +el_val_t widget_set_padding_all(el_val_t handle, el_val_t p); +el_val_t widget_set_padding_xy(el_val_t handle, el_val_t px, el_val_t py); +el_val_t widget_set_width(el_val_t handle, el_val_t width); +el_val_t widget_set_height(el_val_t handle, el_val_t height); +el_val_t widget_set_flex(el_val_t handle, el_val_t flex); +el_val_t widget_set_corner_radius(el_val_t handle, el_val_t radius); +el_val_t widget_set_disabled(el_val_t handle, el_val_t disabled); +el_val_t widget_set_hidden(el_val_t handle, el_val_t hidden); +el_val_t widget_add_child(el_val_t parent, el_val_t child); +el_val_t widget_remove_child(el_val_t parent, el_val_t child); +el_val_t widget_destroy(el_val_t handle); +el_val_t widget_on_click(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_change(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_submit(el_val_t handle, el_val_t fn_name); +el_val_t hex_channel(el_val_t s, el_val_t offset); +el_val_t hex_nibble(el_val_t c); +el_val_t color_hex_r(el_val_t hex); +el_val_t color_hex_g(el_val_t hex); +el_val_t color_hex_b(el_val_t hex); +el_val_t color_hex_a(el_val_t hex); +el_val_t widget_set_color_hex(el_val_t handle, el_val_t hex); +el_val_t widget_set_bg_color_hex(el_val_t handle, el_val_t hex); +el_val_t style_surface(el_val_t handle); +el_val_t style_button_primary(el_val_t handle); +el_val_t style_label_body(el_val_t handle); +el_val_t style_label_heading(el_val_t handle); +el_val_t style_label_muted(el_val_t handle); + +el_val_t TOKEN_PRIMARY; +el_val_t TOKEN_ON_PRIMARY; +el_val_t TOKEN_BACKGROUND; +el_val_t TOKEN_ON_BG; +el_val_t TOKEN_SURFACE; +el_val_t TOKEN_ON_SURFACE; +el_val_t TOKEN_OUTLINE; +el_val_t TOKEN_ERROR; + +el_val_t native_init(void) { + __native_init(); + return 0; +} + +el_val_t native_run_loop(void) { + __native_run_loop(); + return 0; +} + +el_val_t manifest_read(el_val_t path) { + return __manifest_read(path); + return 0; +} + +el_val_t manifest_title(el_val_t m) { + return json_get_string(m, EL_STR("title")); + return 0; +} + +el_val_t manifest_width(el_val_t m) { + return json_get_int(m, EL_STR("width")); + return 0; +} + +el_val_t manifest_height(el_val_t m) { + return json_get_int(m, EL_STR("height")); + return 0; +} + +el_val_t manifest_min_width(el_val_t m) { + return json_get_int(m, EL_STR("min_width")); + return 0; +} + +el_val_t manifest_min_height(el_val_t m) { + return json_get_int(m, EL_STR("min_height")); + return 0; +} + +el_val_t window_create(el_val_t title, el_val_t width, el_val_t height, el_val_t min_width, el_val_t min_height) { + return __window_create(title, width, height, min_width, min_height); + return 0; +} + +el_val_t window_from_manifest(el_val_t manifest_path) { + el_val_t m = manifest_read(manifest_path); + el_val_t title = manifest_title(m); + el_val_t w = manifest_width(m); + el_val_t h = manifest_height(m); + el_val_t mw = manifest_min_width(m); + el_val_t mh = manifest_min_height(m); + el_val_t safe_w = ({ el_val_t _if_result_1 = 0; if ((w > 0)) { _if_result_1 = (w); } else { _if_result_1 = (1200); } _if_result_1; }); + el_val_t safe_h = ({ el_val_t _if_result_2 = 0; if ((h > 0)) { _if_result_2 = (h); } else { _if_result_2 = (800); } _if_result_2; }); + el_val_t safe_mw = ({ el_val_t _if_result_3 = 0; if ((mw > 0)) { _if_result_3 = (mw); } else { _if_result_3 = (600); } _if_result_3; }); + el_val_t safe_mh = ({ el_val_t _if_result_4 = 0; if ((mh > 0)) { _if_result_4 = (mh); } else { _if_result_4 = (400); } _if_result_4; }); + el_val_t safe_t = ({ el_val_t _if_result_5 = 0; if ((str_len(title) > 0)) { _if_result_5 = (title); } else { _if_result_5 = (EL_STR("App")); } _if_result_5; }); + return window_create(safe_t, safe_w, safe_h, safe_mw, safe_mh); + return 0; +} + +el_val_t window_show(el_val_t handle) { + __window_show(handle); + return 0; +} + +el_val_t window_set_title(el_val_t handle, el_val_t title) { + __window_set_title(handle, title); + return 0; +} + +el_val_t vstack(el_val_t spacing) { + return __vstack_create(spacing); + return 0; +} + +el_val_t vstack_tight(void) { + return __vstack_create(0); + return 0; +} + +el_val_t hstack(el_val_t spacing) { + return __hstack_create(spacing); + return 0; +} + +el_val_t zstack(void) { + return __zstack_create(); + return 0; +} + +el_val_t scroll(void) { + return __scroll_create(); + return 0; +} + +el_val_t label(el_val_t text) { + return __label_create(text); + return 0; +} + +el_val_t button(el_val_t label) { + return __button_create(label); + return 0; +} + +el_val_t text_field(el_val_t placeholder) { + return __text_field_create(placeholder); + return 0; +} + +el_val_t text_area(el_val_t placeholder) { + return __text_area_create(placeholder); + return 0; +} + +el_val_t image(el_val_t path_or_name) { + return __image_create(path_or_name); + return 0; +} + +el_val_t widget_set_text(el_val_t handle, el_val_t text) { + __widget_set_text(handle, text); + return 0; +} + +el_val_t widget_get_text(el_val_t handle) { + return __widget_get_text(handle); + return 0; +} + +el_val_t widget_set_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + __widget_set_color(handle, r, g, b, a); + return 0; +} + +el_val_t widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + __widget_set_bg_color(handle, r, g, b, a); + return 0; +} + +el_val_t widget_set_font(el_val_t handle, el_val_t family, el_val_t size, el_val_t bold) { + el_val_t bold_int = ({ el_val_t _if_result_6 = 0; if (bold) { _if_result_6 = (1); } else { _if_result_6 = (0); } _if_result_6; }); + __widget_set_font(handle, family, size, bold_int); + return 0; +} + +el_val_t widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, el_val_t bottom, el_val_t left) { + __widget_set_padding(handle, top, right, bottom, left); + return 0; +} + +el_val_t widget_set_padding_all(el_val_t handle, el_val_t p) { + __widget_set_padding(handle, p, p, p, p); + return 0; +} + +el_val_t widget_set_padding_xy(el_val_t handle, el_val_t px, el_val_t py) { + __widget_set_padding(handle, py, px, py, px); + return 0; +} + +el_val_t widget_set_width(el_val_t handle, el_val_t width) { + __widget_set_width(handle, width); + return 0; +} + +el_val_t widget_set_height(el_val_t handle, el_val_t height) { + __widget_set_height(handle, height); + return 0; +} + +el_val_t widget_set_flex(el_val_t handle, el_val_t flex) { + __widget_set_flex(handle, flex); + return 0; +} + +el_val_t widget_set_corner_radius(el_val_t handle, el_val_t radius) { + __widget_set_corner_radius(handle, radius); + return 0; +} + +el_val_t widget_set_disabled(el_val_t handle, el_val_t disabled) { + el_val_t d = ({ el_val_t _if_result_7 = 0; if (disabled) { _if_result_7 = (1); } else { _if_result_7 = (0); } _if_result_7; }); + __widget_set_disabled(handle, d); + return 0; +} + +el_val_t widget_set_hidden(el_val_t handle, el_val_t hidden) { + el_val_t h = ({ el_val_t _if_result_8 = 0; if (hidden) { _if_result_8 = (1); } else { _if_result_8 = (0); } _if_result_8; }); + __widget_set_hidden(handle, h); + return 0; +} + +el_val_t widget_add_child(el_val_t parent, el_val_t child) { + __widget_add_child(parent, child); + return 0; +} + +el_val_t widget_remove_child(el_val_t parent, el_val_t child) { + __widget_remove_child(parent, child); + return 0; +} + +el_val_t widget_destroy(el_val_t handle) { + __widget_destroy(handle); + return 0; +} + +el_val_t widget_on_click(el_val_t handle, el_val_t fn_name) { + __widget_on_click(handle, fn_name); + return 0; +} + +el_val_t widget_on_change(el_val_t handle, el_val_t fn_name) { + __widget_on_change(handle, fn_name); + return 0; +} + +el_val_t widget_on_submit(el_val_t handle, el_val_t fn_name) { + __widget_on_submit(handle, fn_name); + return 0; +} + +el_val_t hex_channel(el_val_t s, el_val_t offset) { + el_val_t hi = str_slice(s, offset, (offset + 1)); + el_val_t lo = str_slice(s, (offset + 1), (offset + 2)); + el_val_t h = hex_nibble(hi); + el_val_t l = hex_nibble(lo); + return ((h * 16) + l); + return 0; +} + +el_val_t hex_nibble(el_val_t c) { + if (str_eq(c, EL_STR("0"))) { + return 0; + } + if (str_eq(c, EL_STR("1"))) { + return 1; + } + if (str_eq(c, EL_STR("2"))) { + return 2; + } + if (str_eq(c, EL_STR("3"))) { + return 3; + } + if (str_eq(c, EL_STR("4"))) { + return 4; + } + if (str_eq(c, EL_STR("5"))) { + return 5; + } + if (str_eq(c, EL_STR("6"))) { + return 6; + } + if (str_eq(c, EL_STR("7"))) { + return 7; + } + if (str_eq(c, EL_STR("8"))) { + return 8; + } + if (str_eq(c, EL_STR("9"))) { + return 9; + } + if (str_eq(c, EL_STR("a"))) { + return 10; + } + if (str_eq(c, EL_STR("b"))) { + return 11; + } + if (str_eq(c, EL_STR("c"))) { + return 12; + } + if (str_eq(c, EL_STR("d"))) { + return 13; + } + if (str_eq(c, EL_STR("e"))) { + return 14; + } + if (str_eq(c, EL_STR("f"))) { + return 15; + } + if (str_eq(c, EL_STR("A"))) { + return 10; + } + if (str_eq(c, EL_STR("B"))) { + return 11; + } + if (str_eq(c, EL_STR("C"))) { + return 12; + } + if (str_eq(c, EL_STR("D"))) { + return 13; + } + if (str_eq(c, EL_STR("E"))) { + return 14; + } + if (str_eq(c, EL_STR("F"))) { + return 15; + } + return 0; + return 0; +} + +el_val_t color_hex_r(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_9 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_9 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_9 = (hex); } _if_result_9; }); + el_val_t v = hex_channel(s, 0); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_g(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_10 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_10 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_10 = (hex); } _if_result_10; }); + el_val_t v = hex_channel(s, 2); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_b(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_11 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_11 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_11 = (hex); } _if_result_11; }); + el_val_t v = hex_channel(s, 4); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_a(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_12 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_12 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_12 = (hex); } _if_result_12; }); + if (str_len(s) < 8) { + return el_from_float(1.0); + } + el_val_t v = hex_channel(s, 6); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t widget_set_color_hex(el_val_t handle, el_val_t hex) { + widget_set_color(handle, color_hex_r(hex), color_hex_g(hex), color_hex_b(hex), color_hex_a(hex)); + return 0; +} + +el_val_t widget_set_bg_color_hex(el_val_t handle, el_val_t hex) { + widget_set_bg_color(handle, color_hex_r(hex), color_hex_g(hex), color_hex_b(hex), color_hex_a(hex)); + return 0; +} + +el_val_t style_surface(el_val_t handle) { + widget_set_bg_color_hex(handle, TOKEN_SURFACE); + widget_set_corner_radius(handle, 8); + return 0; +} + +el_val_t style_button_primary(el_val_t handle) { + widget_set_bg_color_hex(handle, TOKEN_PRIMARY); + widget_set_color_hex(handle, TOKEN_ON_PRIMARY); + widget_set_corner_radius(handle, 8); + widget_set_padding_xy(handle, 16, 8); + return 0; +} + +el_val_t style_label_body(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_ON_BG); + widget_set_font(handle, EL_STR("system"), 14, 0); + return 0; +} + +el_val_t style_label_heading(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_ON_BG); + widget_set_font(handle, EL_STR("system"), 20, 1); + return 0; +} + +el_val_t style_label_muted(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_OUTLINE); + widget_set_font(handle, EL_STR("system"), 12, 0); + return 0; +} + +int main(int _argc, char** _argv) { + el_runtime_init_args(_argc, _argv); + TOKEN_PRIMARY = EL_STR("#60a5fa"); + TOKEN_ON_PRIMARY = EL_STR("#0f172a"); + TOKEN_BACKGROUND = EL_STR("#0f172a"); + TOKEN_ON_BG = EL_STR("#f8fafc"); + TOKEN_SURFACE = EL_STR("#1e293b"); + TOKEN_ON_SURFACE = EL_STR("#f8fafc"); + TOKEN_OUTLINE = EL_STR("#475569"); + TOKEN_ERROR = EL_STR("#f87171"); + return 0; +} + diff --git a/ui/examples/native-hello/build-gtk4/el_native_vessel.h b/ui/examples/native-hello/build-gtk4/el_native_vessel.h new file mode 100644 index 0000000..b62c288 --- /dev/null +++ b/ui/examples/native-hello/build-gtk4/el_native_vessel.h @@ -0,0 +1,69 @@ +#include +#include +#include "el_runtime.h" + +el_val_t native_init(void); +el_val_t native_run_loop(void); +el_val_t manifest_read(el_val_t path); +el_val_t manifest_title(el_val_t m); +el_val_t manifest_width(el_val_t m); +el_val_t manifest_height(el_val_t m); +el_val_t manifest_min_width(el_val_t m); +el_val_t manifest_min_height(el_val_t m); +el_val_t window_create(el_val_t title, el_val_t width, el_val_t height, el_val_t min_width, el_val_t min_height); +el_val_t window_from_manifest(el_val_t manifest_path); +el_val_t window_show(el_val_t handle); +el_val_t window_set_title(el_val_t handle, el_val_t title); +el_val_t vstack(el_val_t spacing); +el_val_t vstack_tight(void); +el_val_t hstack(el_val_t spacing); +el_val_t zstack(void); +el_val_t scroll(void); +el_val_t label(el_val_t text); +el_val_t button(el_val_t label); +el_val_t text_field(el_val_t placeholder); +el_val_t text_area(el_val_t placeholder); +el_val_t image(el_val_t path_or_name); +el_val_t widget_set_text(el_val_t handle, el_val_t text); +el_val_t widget_get_text(el_val_t handle); +el_val_t widget_set_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_font(el_val_t handle, el_val_t family, el_val_t size, el_val_t bold); +el_val_t widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, el_val_t bottom, el_val_t left); +el_val_t widget_set_padding_all(el_val_t handle, el_val_t p); +el_val_t widget_set_padding_xy(el_val_t handle, el_val_t px, el_val_t py); +el_val_t widget_set_width(el_val_t handle, el_val_t width); +el_val_t widget_set_height(el_val_t handle, el_val_t height); +el_val_t widget_set_flex(el_val_t handle, el_val_t flex); +el_val_t widget_set_corner_radius(el_val_t handle, el_val_t radius); +el_val_t widget_set_disabled(el_val_t handle, el_val_t disabled); +el_val_t widget_set_hidden(el_val_t handle, el_val_t hidden); +el_val_t widget_add_child(el_val_t parent, el_val_t child); +el_val_t widget_remove_child(el_val_t parent, el_val_t child); +el_val_t widget_destroy(el_val_t handle); +el_val_t widget_on_click(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_change(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_submit(el_val_t handle, el_val_t fn_name); +el_val_t hex_channel(el_val_t s, el_val_t offset); +el_val_t hex_nibble(el_val_t c); +el_val_t color_hex_r(el_val_t hex); +el_val_t color_hex_g(el_val_t hex); +el_val_t color_hex_b(el_val_t hex); +el_val_t color_hex_a(el_val_t hex); +el_val_t widget_set_color_hex(el_val_t handle, el_val_t hex); +el_val_t widget_set_bg_color_hex(el_val_t handle, el_val_t hex); +el_val_t style_surface(el_val_t handle); +el_val_t style_button_primary(el_val_t handle); +el_val_t style_label_body(el_val_t handle); +el_val_t style_label_heading(el_val_t handle); +el_val_t style_label_muted(el_val_t handle); + +el_val_t TOKEN_PRIMARY; +el_val_t TOKEN_ON_PRIMARY; +el_val_t TOKEN_BACKGROUND; +el_val_t TOKEN_ON_BG; +el_val_t TOKEN_SURFACE; +el_val_t TOKEN_ON_SURFACE; +el_val_t TOKEN_OUTLINE; +el_val_t TOKEN_ERROR; + diff --git a/ui/examples/native-hello/build-gtk4/el_native_vessel.o b/ui/examples/native-hello/build-gtk4/el_native_vessel.o new file mode 100644 index 0000000000000000000000000000000000000000..3a45efdeddeb987e8bcf4a637692f5e8b1a8e60c GIT binary patch literal 14692 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�GitqWD}eAMe5qv{=@ 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 Y>WscHBP#%pHf2;u?`vVHiApW@zp@^`x&QzG literal 0 HcmV?d00001 diff --git a/ui/examples/native-hello/build-gtk4/el_seed.o b/ui/examples/native-hello/build-gtk4/el_seed.o new file mode 100644 index 0000000000000000000000000000000000000000..a9a2678b436c4fd22414c58475f49896e848d8fc GIT binary patch literal 50056 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 literal 0 HcmV?d00001 diff --git a/ui/examples/native-hello/build-gtk4/native-hello-gtk4 b/ui/examples/native-hello/build-gtk4/native-hello-gtk4 new file mode 100755 index 0000000000000000000000000000000000000000..fc502d8ab1ddea9dd5570b506a0985aa48a0846a GIT binary patch literal 303136 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

    e>ZP8HH$3z z6mP%+7ATD;Ov>KQMAl@`Y7*({2uX#@bkcmLxKetWYl)&&eHjGNB2`b$?F`(z@zve6^*-Ki53^{j84@ebv`??=Wq{T5pAi zYn<#;ufok*N#$Oh_Cw2~WyVymmT@BfG}$sjI#%HO~+I`orm?_cpxe*vq#QGeh@Qi2tK(<1!_K zH+q$tHKFm`lDjuOyS>N<8-_J4*6{R&Ge7J&8gqL8;F6_RKKtG6=No={u=In?ryeXj zpwECuWr(dpCE2+^#@gIFut9RUpW*<(he5UuhPL(F^e!s@K z%|i~4YPj*IP21)j7@f4f){>%itA(de8n$Iy^Fb|7U&@|xw*1P(A8sB!`R7vwr@b+1 z@!=JNs!k{|vP<6EKQG-o;>(VU_b%P~`Slu!&41`K^N%a{6lf6t@%Xqx6V6Y3*mHG9 zgHjp4G?_5!mlyV5eEjjXM_cDzFM8|9?F&yVU+7dqFn`257j>(zes;zNDwB|bQ{@hk2zR}(I5U-xou z?wqGL_lfWLPPO{witX*vWOjuo;|pKu5H|Ne#9iZY)v0^!B~A+n0H~`g6av@{OIp^w;&j?V9*l z?^Zj`?|io2U!IHgyOnJ9)})xppP&8ogR_@gtd4#9rP}qz-45TFbbDplb!WeSu4c3J zVYeR0d$856`b)AVBsOZauH6@XZ{*h8@5(wjRFxuwc#Z4PTFLF=E)- zM@F)*yoj{qxKwYU;aw}M<04&!^8vIpSvsJ#J$0F&DY&o+}2;< z{$?!?U+M7ZpM^JO)~ZpfNn(Xk9cxY;I$&klm~w^2URbcLU&(FWwe?>wF(Nr<<(}GY ze(dq(1LMlZesOtx;UN>Z4SjKCrSr$$FMHok_xioddQ6Uq>$>j7ovuSuwym0c&wx&I zkNC=UT`_vpi-%sC^>If1O*tjUe*D?a+TOE2RhwUNZr@9lTYQw`$xHWq+otEfL&xuV zr*wzYiEnnB;5(R5pwI3?zxnQ|cf3&heRuVW_x*X~)WqM;j_5J=!EJ?dCjEZf|LoHB zYsT)X^4ZMdLisn#ZYD1R}yNaK$RHOXB)(eiWpL^`srMMHdzFzb{EuSg(N#izslaFUzp55wc z*Tpl}cIGaccec|l*CXY6R($b;+;2_?2X|Rnas3OQb?umZ|);AI!OFQ8z^33J<^qg^3M-7W#T)f4US`}A!Y4*j{aY?uDk1trY z!@P zwa|Y`|KG}g>^UHmb-HWi<)i=nu~24mXy)@%UOAamIeC8P@mcRLj&1Yb=Kr74e|dQC zj=%rV<*9FfDI6Yl`_134TpF~{GqY^WgDKvb@k={@S#M#2mcGk)Hsg3UiGceQ+# zvwCup18K>TCsuq@;W4*zr1>T zm7~9{zM1`On-?dfrSCkE*{*-myi(P>_qesF@5gzK=08*GW`T-JA3m@+zDw?ypD(=S zSy*R%-}@5B>`Jb(_m%ta#J)MF`TlnoW{$e2;GJp>3M5r&d*IAN@2-A#!S(?YmbV{V zC8JYjc@F3>s!|P)&rlmomslm&+&`T zHQn0!)~8F4EG)63*kA2;Uwv{)%>8fWG|cZ!l}Q6R4Dj3cKij;vX7`x@`Vg%0(8 zz2BC$y{=CfmviIoNqOD>nJ{K=ubia2*G#JrccfOA*bVm +#include +#include "el_runtime.h" + +el_val_t on_greet_click(el_val_t widget, el_val_t data); +el_val_t on_counter_click(el_val_t widget, el_val_t data); +el_val_t on_name_change(el_val_t widget, el_val_t data); +el_val_t app_build(el_val_t window); + +el_val_t g_window; +el_val_t g_label; +el_val_t g_input; +el_val_t g_button; +el_val_t g_counter; +el_val_t g_counter_lbl; +el_val_t manifest_env; +el_val_t manifest_path; +el_val_t win; +el_val_t g_window; + +el_val_t on_greet_click(el_val_t widget, el_val_t data) { + el_val_t name = widget_get_text(g_input); + el_val_t greeting = ({ el_val_t _if_result_1 = 0; if ((str_len(name) > 0)) { _if_result_1 = (el_str_concat(el_str_concat(EL_STR("Hello, "), name), EL_STR("!"))); } else { _if_result_1 = (EL_STR("Hello, World!")); } _if_result_1; }); + widget_set_text(g_label, greeting); + return 0; +} + +el_val_t on_counter_click(el_val_t widget, el_val_t data) { + el_val_t g_counter = (g_counter + 1); + widget_set_text(g_counter_lbl, el_str_concat(EL_STR("Clicks: "), int_to_str(g_counter))); + return 0; +} + +el_val_t on_name_change(el_val_t widget, el_val_t data) { + el_val_t has_text = (str_len(data) > 0); + widget_set_disabled(g_button, !has_text); + return 0; +} + +el_val_t app_build(el_val_t window) { + el_val_t root = vstack(0); + widget_set_padding_all(root, 24); + widget_set_bg_color_hex(root, EL_STR("#0f172a")); + widget_set_flex(root, 1); + el_val_t title = label(EL_STR("el-native \xe2\x80\x94 native widget demo")); + style_label_heading(title); + widget_add_child(root, title); + el_val_t gap1 = label(EL_STR("")); + widget_set_height(gap1, 16); + widget_add_child(root, gap1); + el_val_t subtitle = label(EL_STR("AppKit controls from el code, no ObjC in the app layer.")); + style_label_muted(subtitle); + widget_add_child(root, subtitle); + el_val_t gap2 = label(EL_STR("")); + widget_set_height(gap2, 24); + widget_add_child(root, gap2); + el_val_t input_row = hstack(8); + el_val_t name_label = label(EL_STR("Name:")); + style_label_body(name_label); + widget_set_width(name_label, 60); + el_val_t input = text_field(EL_STR("Enter your name\xe2\x80\xa6")); + style_label_body(input); + widget_set_flex(input, 1); + widget_on_change(input, EL_STR("on_name_change")); + el_val_t g_input = input; + el_val_t greet_btn = button(EL_STR("Greet")); + style_button_primary(greet_btn); + widget_set_disabled(greet_btn, 1); + widget_on_click(greet_btn, EL_STR("on_greet_click")); + el_val_t g_button = greet_btn; + widget_add_child(input_row, name_label); + widget_add_child(input_row, input); + widget_add_child(input_row, greet_btn); + widget_add_child(root, input_row); + el_val_t gap3 = label(EL_STR("")); + widget_set_height(gap3, 12); + widget_add_child(root, gap3); + el_val_t greeting = label(EL_STR("Waiting for name\xe2\x80\xa6")); + style_label_body(greeting); + widget_set_color_hex(greeting, EL_STR("#60a5fa")); + widget_set_font(greeting, EL_STR("system"), 16, 1); + el_val_t g_label = greeting; + widget_add_child(root, greeting); + el_val_t gap4 = label(EL_STR("")); + widget_set_height(gap4, 24); + widget_add_child(root, gap4); + el_val_t counter_row = hstack(12); + el_val_t counter_lbl = label(EL_STR("Clicks: 0")); + style_label_body(counter_lbl); + el_val_t g_counter_lbl = counter_lbl; + el_val_t counter_btn = button(EL_STR("Click me")); + style_button_primary(counter_btn); + widget_on_click(counter_btn, EL_STR("on_counter_click")); + widget_add_child(counter_row, counter_lbl); + widget_add_child(counter_row, counter_btn); + widget_add_child(root, counter_row); + widget_add_child(window, root); + return 0; +} + +int main(int _argc, char** _argv) { + el_runtime_init_args(_argc, _argv); + g_window = (-1); + g_label = (-1); + g_input = (-1); + g_button = (-1); + g_counter = 0; + g_counter_lbl = (-1); + native_init(); + manifest_env = env(EL_STR("EL_MANIFEST")); + manifest_path = ({ el_val_t _if_result_2 = 0; if ((str_len(manifest_env) > 0)) { _if_result_2 = (manifest_env); } else { _if_result_2 = (EL_STR("manifest.el")); } _if_result_2; }); + win = window_from_manifest(manifest_path); + g_window = win; + if (win < 0) { + println(EL_STR("Error: failed to create window. Is EL_TARGET_MACOS defined?")); + exit_program(1); + } + app_build(win); + window_show(win); + native_run_loop(); + return 0; +} + diff --git a/ui/examples/native-hello/build-gtk4/native_hello.o b/ui/examples/native-hello/build-gtk4/native_hello.o new file mode 100644 index 0000000000000000000000000000000000000000..c4de3f0a4fc76a9116ecbd98f34ea9aaace55907 GIT binary patch literal 6192 zcmb7|YitzP700hx45rYK6bH;BFcey#*v8A#Jhs@ZjqP}`ky#!IEW_G6_HHw~v)vu@ zkZEPK`9Kt@HHb<`Ma^1$#70y~CDb^dVu>nBC8Q7%wW!U9HOYrX0u@v~tSemlKXcEF z$Ac=hBgVh;Klj{oUo&^-^4Y&0{d<8BWdaxdnT>ml31dCs_NUGyQZZExHMz@+G#FfY>#q>w^W@kn779@=eKS&S zhOY{@Y~|6b2?WuH$Cl#fmY%PwK) zLltG>62>s;*z;ZXLNS@ottt)sR+VIV!=xy~EyR_4Ze{8D5-LAgB8~DVHDw}RUqzqQ#*+tseQ#OOH}5*yxja3W$Vu&@9nA5Q2TNp38Dgld zg0Eq6YGB{!bBx0pSFZf?XGZ1d)WEA)oAT+g$u?eGrychAFjmi+Ictfzb!^PJV=s5v zt6cUPm%YwqZ*Ta^zI*I30*0I+ppId=ECtP`?ZReTT zO?^R(&lSVAC>y*>ZDEbC({nSDTh4iwBmOws$4eLH%D4iaVXJSsWoYwFt9)V$^4m6^ zb=xj1r+jagMtsX;p4?K@dBatQ?NwAq+9TkIkK&GFoZLRyoZs?uEY0gM%BVl~So66m z)ICrJ#bICegF1Z~SY zWKVF6oCDiW{gcmJp_AUb!=ulPF!q#k`R)a2PnkVBh4tGu+#TG^BkM`b9 zZ7XtyT?+)#Et(vYI)rwdx*g9%t^w??<)Dt~# zWp^oJO;cQFqIx7Wo8ULtMq1! zq@w9?#I$N9WhkB9KME>|lw!s;C7Mnvdi0!@sTCd3q_#^mr%WxQoHP0}NS@U05B^RV zDV0pMCmv1pX`&^gX(l=Q$WVKzhvH~7Vd5)8={2V7t=V1|-PRiw*>hP_OFBcTla`Xy zC`pgePc3qq=8$@zv7>E&^P#XvMpKDiEo;_lx@gX1jLa^jH=5A3m|_}APezNHnnIr- z#+h2BEvukvxUs9HIgAX!&O?}t-b6}^?Zs@nu5oGOahQ3Hv(zPDD6huC()HiUuX6c$ ze8{~lKM!RE{#(f(Kc-vIZ(pJ)G7kot8IYy!`NuY++AuVPIYT!bzjlnk_j-+^wD4D114fv%Sf z)PZ=PLe-LiwIGfJAw@D!1-=AbDH&J*ejB<%G9bVO(9iJRfq|zW&Jdx;l7S+Ky*>1e zWZ)}s9yFb+z`z|4`+4ZLWZ+LAjyR!l$-o$hS1NQteIFJh9B zCXn8@DzF_~0Imn|dqd}#n#Y2K&>u=h?tpldLboLYH$bYF2kCvfCK)k7%A+&GAhm{3s)BpFjV`ASijGDoV7il?~}%DpU3IFTZlQgf2VZVr0w6OKeHaUW=DvRShE!Leo}ljZn|DZ zZkWCbDa9u!ck3@a`nMka505T*^oJf@=4tN;8sn~5J)pk1H3_$V2T^W4;3*GF?Tn}1 zqpy4P2Qr@%KkO+#?J1{y2mhSwdmjC3j~+xMTuy#^R@}NE%kfuUK~MdY9-Z-M$Qk`v z;?b|k_Bgu`Kk?`vd-Ow3e$`X{o+tliPx;?H^$&XD@f$d!zeAq-8$9KodGsTXe#g_^ z&phSydx3w>)hD&H9v^w)6CN$pta(n?)b4)M#8+-QlSoE0=WMSY?bdX)+lavYBp}15o#aOkrb-^^{i^C(=&2f|G#Lric^F9 z4@cBYq|*H+g9YRnkVb!7Yhc$+{mgtMah4JA(9?{WMPgKeb zKJ*hfMo<+sn(505m}uUhK%uL(1oVSX1WpsEr|O20rZPF5g61=2>M5(YG}Z)6YEIW+ zXlKztI%D)@qRAOOPe)@h98%P%u2V8=6~m^o7!{*ddy;pY_uEaD4~Ws+nYPo&JOipSKEQct~YFtM>cnLb#~chh~C%Yh{NGf zTSv1aJJdsmyY@E*9gj!uYYeuxbafu?XyOI0_3yMT$MDzNF30fiuw9Pf-)_4c!@tdT sIfj3$?Q#tN7TX2GOr|&6((hO>P~f)/dev/null; then + ELC="elc" +elif [ -x "${EL_LANG_ROOT}/dist/platform/elc" ]; then + ELC="${EL_LANG_ROOT}/dist/platform/elc" +else + echo "Error: elc not found. Add it to PATH or place it at:" + echo " ${EL_LANG_ROOT}/dist/platform/elc" + exit 1 +fi + +# Verify SDL2 is available +if ! command -v sdl2-config &>/dev/null; then + echo "Error: sdl2-config not found. Install SDL2 via:" + echo " brew install sdl2 sdl2_ttf sdl2_image" + exit 1 +fi + +SDL2_CFLAGS=$(sdl2-config --cflags) +SDL2_LIBS=$(sdl2-config --libs) + +CLANG_FLAGS_COMMON=( + -std=c11 + -DEL_TARGET_SDL2 + -I "${EL_RUNTIME}" +) + +clean() { + rm -rf "${BUILD_DIR}" + echo "Cleaned." +} + +compile() { + mkdir -p "${BUILD_DIR}" + + # ── 1. Vessel forward-declarations header ───────────────────────────────── + echo "==> Generating el-native vessel header (declarations only)..." + "${ELC}" --emit-header "${EL_NATIVE_VESSEL}" \ + | awk 'BEGIN{in_body=0} /^[a-zA-Z_].+\)[[:space:]]*\{/ {in_body=1} !in_body{print}' \ + > "${BUILD_DIR}/el_native_vessel.h" + + # ── 2. Compile el-native vessel to C ────────────────────────────────────── + echo "==> Compiling el-native vessel to C..." + "${ELC}" "${EL_NATIVE_VESSEL}" \ + > "${BUILD_DIR}/el_native_vessel.c" + + # ── 3. Compile app entry to C ───────────────────────────────────────────── + echo "==> Compiling app entry to C..." + EL_MANIFEST="${SCRIPT_DIR}/manifest.el" \ + "${ELC}" "${SCRIPT_DIR}/src/main.el" \ + > "${BUILD_DIR}/native_hello.c" + + # ── 4. Compile el_sdl2.c (SDL2 bridge — pure C) ─────────────────────────── + # sdl2-config --cflags gives -I/opt/homebrew/include/SDL2 which handles + # #include but el_sdl2.c uses #include — also add + # the parent directory so both forms resolve. + echo "==> Compiling el_sdl2.c (SDL2 bridge)..." + clang \ + -std=c11 \ + -DEL_TARGET_SDL2 \ + ${SDL2_CFLAGS} \ + -I/opt/homebrew/include \ + -I "${EL_RUNTIME}" \ + -c "${EL_RUNTIME}/el_sdl2.c" \ + -o "${BUILD_DIR}/el_sdl2.o" + + # ── 5a. Compile el_seed.c ───────────────────────────────────────────────── + echo "==> Compiling el_seed.c..." + clang "${CLANG_FLAGS_COMMON[@]}" \ + -c "${EL_RUNTIME}/el_seed.c" \ + -o "${BUILD_DIR}/el_seed.o" + + # ── 5b. Compile el_runtime.c and patch out duplicate __-prefixed symbols ── + echo "==> Compiling el_runtime.c..." + clang "${CLANG_FLAGS_COMMON[@]}" \ + -c "${EL_RUNTIME}/el_runtime.c" \ + -o "${BUILD_DIR}/el_runtime.o" + + echo "==> Patching el_runtime.o (hiding __-prefixed symbols duplicated in el_seed.o)..." + nm "${BUILD_DIR}/el_seed.o" 2>/dev/null \ + | awk '/^[0-9a-f]+ T _/{print $3}' | sort > "${BUILD_DIR}/.seed_T.txt" + nm "${BUILD_DIR}/el_runtime.o" 2>/dev/null \ + | awk '/^[0-9a-f]+ T _/{print $3}' | sort > "${BUILD_DIR}/.rt_T.txt" + comm -23 "${BUILD_DIR}/.rt_T.txt" "${BUILD_DIR}/.seed_T.txt" \ + > "${BUILD_DIR}/.rt_keep.txt" + nmedit -s "${BUILD_DIR}/.rt_keep.txt" "${BUILD_DIR}/el_runtime.o" + + # ── 6. Compile el-native vessel object ──────────────────────────────────── + echo "==> Compiling el-native vessel object..." + clang "${CLANG_FLAGS_COMMON[@]}" \ + -include "${EL_RUNTIME}/el_native_target.h" \ + -c "${BUILD_DIR}/el_native_vessel.c" \ + -o "${BUILD_DIR}/el_native_vessel.o" + + echo "==> Patching el_native_vessel.o (hiding vessel main)..." + nm "${BUILD_DIR}/el_native_vessel.o" 2>/dev/null \ + | awk '/^[0-9a-f]+ T _/{print $3}' \ + | grep -v '^_main$' \ + > "${BUILD_DIR}/.vessel_keep.txt" + nmedit -s "${BUILD_DIR}/.vessel_keep.txt" "${BUILD_DIR}/el_native_vessel.o" + + # ── 7. Compile app object ───────────────────────────────────────────────── + echo "==> Compiling app object..." + clang "${CLANG_FLAGS_COMMON[@]}" \ + -include "${EL_RUNTIME}/el_native_target.h" \ + -include "${BUILD_DIR}/el_native_vessel.h" \ + -c "${BUILD_DIR}/native_hello.c" \ + -o "${BUILD_DIR}/native_hello.o" + + # ── 8. Link ─────────────────────────────────────────────────────────────── + echo "==> Linking native-hello-sdl2..." + clang "${CLANG_FLAGS_COMMON[@]}" \ + ${SDL2_LIBS} \ + -lSDL2_ttf \ + -lSDL2_image \ + -lcurl \ + -ldl \ + -lpthread \ + "${BUILD_DIR}/native_hello.o" \ + "${BUILD_DIR}/el_native_vessel.o" \ + "${BUILD_DIR}/el_sdl2.o" \ + "${BUILD_DIR}/el_runtime.o" \ + "${BUILD_DIR}/el_seed.o" \ + -o "${BUILD_DIR}/native-hello-sdl2" + + echo "==> Build complete: ${BUILD_DIR}/native-hello-sdl2" +} + +run() { + compile + echo "==> Launching native-hello-sdl2..." + EL_MANIFEST="${SCRIPT_DIR}/manifest.el" \ + "${BUILD_DIR}/native-hello-sdl2" +} + +case "${1:-run}" in + clean) clean ;; + compile) compile ;; + run|*) run ;; +esac diff --git a/ui/examples/native-hello/build-win32.sh b/ui/examples/native-hello/build-win32.sh new file mode 100755 index 0000000..62582c8 --- /dev/null +++ b/ui/examples/native-hello/build-win32.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env bash +# build-win32.sh — Cross-compile native-hello for Windows using mingw64. +# +# Requirements: +# - x86_64-w64-mingw32-gcc (brew install mingw-w64) +# - elc in PATH or at ../../../lang/dist/platform/elc +# +# Output: build-win32/native-hello.exe +# +# Note: We use el_runtime_win32.c instead of el_runtime.c / el_seed.c because +# those files have deep POSIX dependencies (pthread, curl, dlfcn, sys/socket, +# etc.) that cannot be cross-compiled to Windows. el_runtime_win32.c provides +# all the runtime symbols that native-hello and the el-native vessel actually +# call, using only standard C11 + Win32 APIs. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +EL_LANG_ROOT="${SCRIPT_DIR}/../../../lang" +EL_UI_ROOT="${SCRIPT_DIR}/../.." +EL_RUNTIME="${EL_LANG_ROOT}/el-compiler/runtime" +EL_NATIVE_VESSEL="${EL_UI_ROOT}/vessels/el-native/src/main.el" +BUILD_DIR="${SCRIPT_DIR}/build-win32" + +# ── Locate elc ─────────────────────────────────────────────────────────────── +if command -v elc &>/dev/null; then + ELC="elc" +elif [ -x "${EL_LANG_ROOT}/dist/platform/elc" ]; then + ELC="${EL_LANG_ROOT}/dist/platform/elc" +else + echo "Error: elc not found. Add it to PATH or place it at:" + echo " ${EL_LANG_ROOT}/dist/platform/elc" + exit 1 +fi + +CC="x86_64-w64-mingw32-gcc" + +# -D_WIN32_IE for SetWindowSubclass (comctl32 >= IE 0x0600) +CFLAGS=( + -std=c11 + -DEL_TARGET_WIN32 + -D_WIN32_IE=0x0600 + -I"${EL_RUNTIME}" + -Wall + -Wno-unused-function +) + +mkdir -p "${BUILD_DIR}" + +# ── 1. Compile el-native vessel to C ───────────────────────────────────────── +echo "==> Compiling el-native vessel to C..." +"${ELC}" "${EL_NATIVE_VESSEL}" \ + > "${BUILD_DIR}/el_native_vessel.c" + +# ── 2. Generate vessel header (declarations only) ──────────────────────────── +# elc --emit-header includes function bodies AND bare global variable definitions. +# We extract only forward declarations with two awk passes: +# Pass 1: stop before function bodies (same as macOS build.sh). +# Pass 2: convert bare global variable definitions (^el_val_t NAME;) to +# `extern el_val_t NAME;` so the app TU sees them as declarations, +# not definitions — avoiding duplicate symbol errors at link time. +echo "==> Generating el-native vessel header (declarations only)..." +"${ELC}" --emit-header "${EL_NATIVE_VESSEL}" \ + | awk 'BEGIN{in_body=0} /^[a-zA-Z_].+\)[[:space:]]*\{/ {in_body=1} !in_body{print}' \ + | awk '/^el_val_t [A-Za-z_][A-Za-z0-9_]*;/{print "extern " $0; next} {print}' \ + > "${BUILD_DIR}/el_native_vessel.h" + +# ── 3. Compile app entry to C ───────────────────────────────────────────────── +echo "==> Compiling app entry to C..." +EL_MANIFEST="${SCRIPT_DIR}/manifest.el" \ + "${ELC}" "${SCRIPT_DIR}/src/main.el" \ + > "${BUILD_DIR}/native_hello.c" + +# ── 4. Compile el_win32.c ───────────────────────────────────────────────────── +echo "==> Compiling el_win32.c (Win32 widget bridge)..." +${CC} "${CFLAGS[@]}" \ + -c "${EL_RUNTIME}/el_win32.c" \ + -o "${BUILD_DIR}/el_win32.o" + +# ── 5. Compile el_runtime_win32.c ───────────────────────────────────────────── +# This replaces el_seed.c + el_runtime.c for Win32 targets. +echo "==> Compiling el_runtime_win32.c (Win32 runtime stub)..." +${CC} "${CFLAGS[@]}" \ + -c "${EL_RUNTIME}/el_runtime_win32.c" \ + -o "${BUILD_DIR}/el_runtime_win32.o" + +# ── 6. Compile el-native vessel object ─────────────────────────────────────── +echo "==> Compiling el-native vessel object..." +${CC} "${CFLAGS[@]}" \ + -include "${EL_RUNTIME}/el_native_target.h" \ + -c "${BUILD_DIR}/el_native_vessel.c" \ + -o "${BUILD_DIR}/el_native_vessel.o" + +echo "==> Patching el_native_vessel.o (localising vessel main + shared globals)..." +# The vessel's compiled C has its own main(). We localize it so the linker sees +# only the app's main(). We also localize any globals (TOKEN_*, etc.) that the +# vessel defines but the app also declares — matching the nmedit step in +# build.sh (macOS), using objcopy for mingw. +VESSEL_LOCAL_SYMS=() +# Collect all defined (T and D/B/C) symbols in the vessel object +while IFS= read -r sym; do + VESSEL_LOCAL_SYMS+=("--localize-symbol=${sym}") +done < <(x86_64-w64-mingw32-nm "${BUILD_DIR}/el_native_vessel.o" 2>/dev/null \ + | awk '/^[0-9a-f]+ [TDBCt] /{print $3}' \ + | grep -E '^(main|TOKEN_)' || true) +if [ ${#VESSEL_LOCAL_SYMS[@]} -gt 0 ]; then + x86_64-w64-mingw32-objcopy "${VESSEL_LOCAL_SYMS[@]}" \ + "${BUILD_DIR}/el_native_vessel.o" +fi + +# ── 7. Compile app object ───────────────────────────────────────────────────── +echo "==> Compiling app object..." +${CC} "${CFLAGS[@]}" \ + -include "${EL_RUNTIME}/el_native_target.h" \ + -include "${BUILD_DIR}/el_native_vessel.h" \ + -c "${BUILD_DIR}/native_hello.c" \ + -o "${BUILD_DIR}/native_hello.o" + +# ── 8. Link ─────────────────────────────────────────────────────────────────── +# -Wl,--export-all-symbols: make el callback functions (on_greet_click etc.) +# visible to GetProcAddress(GetModuleHandle(NULL), fn_name) — the Win32 +# equivalent of POSIX dlsym(RTLD_DEFAULT, fn_name). +echo "==> Linking native-hello.exe..." +${CC} "${CFLAGS[@]}" \ + -Wl,--export-all-symbols \ + "${BUILD_DIR}/native_hello.o" \ + "${BUILD_DIR}/el_native_vessel.o" \ + "${BUILD_DIR}/el_win32.o" \ + "${BUILD_DIR}/el_runtime_win32.o" \ + -lcomctl32 -luser32 -lgdi32 -lkernel32 \ + -o "${BUILD_DIR}/native-hello.exe" + +echo "" +echo "==> Built: ${BUILD_DIR}/native-hello.exe" +ls -lh "${BUILD_DIR}/native-hello.exe" diff --git a/ui/examples/native-hello/build-win32/el_native_vessel.c b/ui/examples/native-hello/build-win32/el_native_vessel.c new file mode 100644 index 0000000..28bf38c --- /dev/null +++ b/ui/examples/native-hello/build-win32/el_native_vessel.c @@ -0,0 +1,459 @@ +#include +#include +#include "el_runtime.h" + +el_val_t native_init(void); +el_val_t native_run_loop(void); +el_val_t manifest_read(el_val_t path); +el_val_t manifest_title(el_val_t m); +el_val_t manifest_width(el_val_t m); +el_val_t manifest_height(el_val_t m); +el_val_t manifest_min_width(el_val_t m); +el_val_t manifest_min_height(el_val_t m); +el_val_t window_create(el_val_t title, el_val_t width, el_val_t height, el_val_t min_width, el_val_t min_height); +el_val_t window_from_manifest(el_val_t manifest_path); +el_val_t window_show(el_val_t handle); +el_val_t window_set_title(el_val_t handle, el_val_t title); +el_val_t vstack(el_val_t spacing); +el_val_t vstack_tight(void); +el_val_t hstack(el_val_t spacing); +el_val_t zstack(void); +el_val_t scroll(void); +el_val_t label(el_val_t text); +el_val_t button(el_val_t label); +el_val_t text_field(el_val_t placeholder); +el_val_t text_area(el_val_t placeholder); +el_val_t image(el_val_t path_or_name); +el_val_t widget_set_text(el_val_t handle, el_val_t text); +el_val_t widget_get_text(el_val_t handle); +el_val_t widget_set_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_font(el_val_t handle, el_val_t family, el_val_t size, el_val_t bold); +el_val_t widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, el_val_t bottom, el_val_t left); +el_val_t widget_set_padding_all(el_val_t handle, el_val_t p); +el_val_t widget_set_padding_xy(el_val_t handle, el_val_t px, el_val_t py); +el_val_t widget_set_width(el_val_t handle, el_val_t width); +el_val_t widget_set_height(el_val_t handle, el_val_t height); +el_val_t widget_set_flex(el_val_t handle, el_val_t flex); +el_val_t widget_set_corner_radius(el_val_t handle, el_val_t radius); +el_val_t widget_set_disabled(el_val_t handle, el_val_t disabled); +el_val_t widget_set_hidden(el_val_t handle, el_val_t hidden); +el_val_t widget_add_child(el_val_t parent, el_val_t child); +el_val_t widget_remove_child(el_val_t parent, el_val_t child); +el_val_t widget_destroy(el_val_t handle); +el_val_t widget_on_click(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_change(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_submit(el_val_t handle, el_val_t fn_name); +el_val_t hex_channel(el_val_t s, el_val_t offset); +el_val_t hex_nibble(el_val_t c); +el_val_t color_hex_r(el_val_t hex); +el_val_t color_hex_g(el_val_t hex); +el_val_t color_hex_b(el_val_t hex); +el_val_t color_hex_a(el_val_t hex); +el_val_t widget_set_color_hex(el_val_t handle, el_val_t hex); +el_val_t widget_set_bg_color_hex(el_val_t handle, el_val_t hex); +el_val_t style_surface(el_val_t handle); +el_val_t style_button_primary(el_val_t handle); +el_val_t style_label_body(el_val_t handle); +el_val_t style_label_heading(el_val_t handle); +el_val_t style_label_muted(el_val_t handle); + +el_val_t TOKEN_PRIMARY; +el_val_t TOKEN_ON_PRIMARY; +el_val_t TOKEN_BACKGROUND; +el_val_t TOKEN_ON_BG; +el_val_t TOKEN_SURFACE; +el_val_t TOKEN_ON_SURFACE; +el_val_t TOKEN_OUTLINE; +el_val_t TOKEN_ERROR; + +el_val_t native_init(void) { + __native_init(); + return 0; +} + +el_val_t native_run_loop(void) { + __native_run_loop(); + return 0; +} + +el_val_t manifest_read(el_val_t path) { + return __manifest_read(path); + return 0; +} + +el_val_t manifest_title(el_val_t m) { + return json_get_string(m, EL_STR("title")); + return 0; +} + +el_val_t manifest_width(el_val_t m) { + return json_get_int(m, EL_STR("width")); + return 0; +} + +el_val_t manifest_height(el_val_t m) { + return json_get_int(m, EL_STR("height")); + return 0; +} + +el_val_t manifest_min_width(el_val_t m) { + return json_get_int(m, EL_STR("min_width")); + return 0; +} + +el_val_t manifest_min_height(el_val_t m) { + return json_get_int(m, EL_STR("min_height")); + return 0; +} + +el_val_t window_create(el_val_t title, el_val_t width, el_val_t height, el_val_t min_width, el_val_t min_height) { + return __window_create(title, width, height, min_width, min_height); + return 0; +} + +el_val_t window_from_manifest(el_val_t manifest_path) { + el_val_t m = manifest_read(manifest_path); + el_val_t title = manifest_title(m); + el_val_t w = manifest_width(m); + el_val_t h = manifest_height(m); + el_val_t mw = manifest_min_width(m); + el_val_t mh = manifest_min_height(m); + el_val_t safe_w = ({ el_val_t _if_result_1 = 0; if ((w > 0)) { _if_result_1 = (w); } else { _if_result_1 = (1200); } _if_result_1; }); + el_val_t safe_h = ({ el_val_t _if_result_2 = 0; if ((h > 0)) { _if_result_2 = (h); } else { _if_result_2 = (800); } _if_result_2; }); + el_val_t safe_mw = ({ el_val_t _if_result_3 = 0; if ((mw > 0)) { _if_result_3 = (mw); } else { _if_result_3 = (600); } _if_result_3; }); + el_val_t safe_mh = ({ el_val_t _if_result_4 = 0; if ((mh > 0)) { _if_result_4 = (mh); } else { _if_result_4 = (400); } _if_result_4; }); + el_val_t safe_t = ({ el_val_t _if_result_5 = 0; if ((str_len(title) > 0)) { _if_result_5 = (title); } else { _if_result_5 = (EL_STR("App")); } _if_result_5; }); + return window_create(safe_t, safe_w, safe_h, safe_mw, safe_mh); + return 0; +} + +el_val_t window_show(el_val_t handle) { + __window_show(handle); + return 0; +} + +el_val_t window_set_title(el_val_t handle, el_val_t title) { + __window_set_title(handle, title); + return 0; +} + +el_val_t vstack(el_val_t spacing) { + return __vstack_create(spacing); + return 0; +} + +el_val_t vstack_tight(void) { + return __vstack_create(0); + return 0; +} + +el_val_t hstack(el_val_t spacing) { + return __hstack_create(spacing); + return 0; +} + +el_val_t zstack(void) { + return __zstack_create(); + return 0; +} + +el_val_t scroll(void) { + return __scroll_create(); + return 0; +} + +el_val_t label(el_val_t text) { + return __label_create(text); + return 0; +} + +el_val_t button(el_val_t label) { + return __button_create(label); + return 0; +} + +el_val_t text_field(el_val_t placeholder) { + return __text_field_create(placeholder); + return 0; +} + +el_val_t text_area(el_val_t placeholder) { + return __text_area_create(placeholder); + return 0; +} + +el_val_t image(el_val_t path_or_name) { + return __image_create(path_or_name); + return 0; +} + +el_val_t widget_set_text(el_val_t handle, el_val_t text) { + __widget_set_text(handle, text); + return 0; +} + +el_val_t widget_get_text(el_val_t handle) { + return __widget_get_text(handle); + return 0; +} + +el_val_t widget_set_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + __widget_set_color(handle, r, g, b, a); + return 0; +} + +el_val_t widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + __widget_set_bg_color(handle, r, g, b, a); + return 0; +} + +el_val_t widget_set_font(el_val_t handle, el_val_t family, el_val_t size, el_val_t bold) { + el_val_t bold_int = ({ el_val_t _if_result_6 = 0; if (bold) { _if_result_6 = (1); } else { _if_result_6 = (0); } _if_result_6; }); + __widget_set_font(handle, family, size, bold_int); + return 0; +} + +el_val_t widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, el_val_t bottom, el_val_t left) { + __widget_set_padding(handle, top, right, bottom, left); + return 0; +} + +el_val_t widget_set_padding_all(el_val_t handle, el_val_t p) { + __widget_set_padding(handle, p, p, p, p); + return 0; +} + +el_val_t widget_set_padding_xy(el_val_t handle, el_val_t px, el_val_t py) { + __widget_set_padding(handle, py, px, py, px); + return 0; +} + +el_val_t widget_set_width(el_val_t handle, el_val_t width) { + __widget_set_width(handle, width); + return 0; +} + +el_val_t widget_set_height(el_val_t handle, el_val_t height) { + __widget_set_height(handle, height); + return 0; +} + +el_val_t widget_set_flex(el_val_t handle, el_val_t flex) { + __widget_set_flex(handle, flex); + return 0; +} + +el_val_t widget_set_corner_radius(el_val_t handle, el_val_t radius) { + __widget_set_corner_radius(handle, radius); + return 0; +} + +el_val_t widget_set_disabled(el_val_t handle, el_val_t disabled) { + el_val_t d = ({ el_val_t _if_result_7 = 0; if (disabled) { _if_result_7 = (1); } else { _if_result_7 = (0); } _if_result_7; }); + __widget_set_disabled(handle, d); + return 0; +} + +el_val_t widget_set_hidden(el_val_t handle, el_val_t hidden) { + el_val_t h = ({ el_val_t _if_result_8 = 0; if (hidden) { _if_result_8 = (1); } else { _if_result_8 = (0); } _if_result_8; }); + __widget_set_hidden(handle, h); + return 0; +} + +el_val_t widget_add_child(el_val_t parent, el_val_t child) { + __widget_add_child(parent, child); + return 0; +} + +el_val_t widget_remove_child(el_val_t parent, el_val_t child) { + __widget_remove_child(parent, child); + return 0; +} + +el_val_t widget_destroy(el_val_t handle) { + __widget_destroy(handle); + return 0; +} + +el_val_t widget_on_click(el_val_t handle, el_val_t fn_name) { + __widget_on_click(handle, fn_name); + return 0; +} + +el_val_t widget_on_change(el_val_t handle, el_val_t fn_name) { + __widget_on_change(handle, fn_name); + return 0; +} + +el_val_t widget_on_submit(el_val_t handle, el_val_t fn_name) { + __widget_on_submit(handle, fn_name); + return 0; +} + +el_val_t hex_channel(el_val_t s, el_val_t offset) { + el_val_t hi = str_slice(s, offset, (offset + 1)); + el_val_t lo = str_slice(s, (offset + 1), (offset + 2)); + el_val_t h = hex_nibble(hi); + el_val_t l = hex_nibble(lo); + return ((h * 16) + l); + return 0; +} + +el_val_t hex_nibble(el_val_t c) { + if (str_eq(c, EL_STR("0"))) { + return 0; + } + if (str_eq(c, EL_STR("1"))) { + return 1; + } + if (str_eq(c, EL_STR("2"))) { + return 2; + } + if (str_eq(c, EL_STR("3"))) { + return 3; + } + if (str_eq(c, EL_STR("4"))) { + return 4; + } + if (str_eq(c, EL_STR("5"))) { + return 5; + } + if (str_eq(c, EL_STR("6"))) { + return 6; + } + if (str_eq(c, EL_STR("7"))) { + return 7; + } + if (str_eq(c, EL_STR("8"))) { + return 8; + } + if (str_eq(c, EL_STR("9"))) { + return 9; + } + if (str_eq(c, EL_STR("a"))) { + return 10; + } + if (str_eq(c, EL_STR("b"))) { + return 11; + } + if (str_eq(c, EL_STR("c"))) { + return 12; + } + if (str_eq(c, EL_STR("d"))) { + return 13; + } + if (str_eq(c, EL_STR("e"))) { + return 14; + } + if (str_eq(c, EL_STR("f"))) { + return 15; + } + if (str_eq(c, EL_STR("A"))) { + return 10; + } + if (str_eq(c, EL_STR("B"))) { + return 11; + } + if (str_eq(c, EL_STR("C"))) { + return 12; + } + if (str_eq(c, EL_STR("D"))) { + return 13; + } + if (str_eq(c, EL_STR("E"))) { + return 14; + } + if (str_eq(c, EL_STR("F"))) { + return 15; + } + return 0; + return 0; +} + +el_val_t color_hex_r(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_9 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_9 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_9 = (hex); } _if_result_9; }); + el_val_t v = hex_channel(s, 0); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_g(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_10 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_10 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_10 = (hex); } _if_result_10; }); + el_val_t v = hex_channel(s, 2); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_b(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_11 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_11 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_11 = (hex); } _if_result_11; }); + el_val_t v = hex_channel(s, 4); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_a(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_12 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_12 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_12 = (hex); } _if_result_12; }); + if (str_len(s) < 8) { + return el_from_float(1.0); + } + el_val_t v = hex_channel(s, 6); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t widget_set_color_hex(el_val_t handle, el_val_t hex) { + widget_set_color(handle, color_hex_r(hex), color_hex_g(hex), color_hex_b(hex), color_hex_a(hex)); + return 0; +} + +el_val_t widget_set_bg_color_hex(el_val_t handle, el_val_t hex) { + widget_set_bg_color(handle, color_hex_r(hex), color_hex_g(hex), color_hex_b(hex), color_hex_a(hex)); + return 0; +} + +el_val_t style_surface(el_val_t handle) { + widget_set_bg_color_hex(handle, TOKEN_SURFACE); + widget_set_corner_radius(handle, 8); + return 0; +} + +el_val_t style_button_primary(el_val_t handle) { + widget_set_bg_color_hex(handle, TOKEN_PRIMARY); + widget_set_color_hex(handle, TOKEN_ON_PRIMARY); + widget_set_corner_radius(handle, 8); + widget_set_padding_xy(handle, 16, 8); + return 0; +} + +el_val_t style_label_body(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_ON_BG); + widget_set_font(handle, EL_STR("system"), 14, 0); + return 0; +} + +el_val_t style_label_heading(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_ON_BG); + widget_set_font(handle, EL_STR("system"), 20, 1); + return 0; +} + +el_val_t style_label_muted(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_OUTLINE); + widget_set_font(handle, EL_STR("system"), 12, 0); + return 0; +} + +int main(int _argc, char** _argv) { + el_runtime_init_args(_argc, _argv); + TOKEN_PRIMARY = EL_STR("#60a5fa"); + TOKEN_ON_PRIMARY = EL_STR("#0f172a"); + TOKEN_BACKGROUND = EL_STR("#0f172a"); + TOKEN_ON_BG = EL_STR("#f8fafc"); + TOKEN_SURFACE = EL_STR("#1e293b"); + TOKEN_ON_SURFACE = EL_STR("#f8fafc"); + TOKEN_OUTLINE = EL_STR("#475569"); + TOKEN_ERROR = EL_STR("#f87171"); + return 0; +} + diff --git a/ui/examples/native-hello/build-win32/el_native_vessel.h b/ui/examples/native-hello/build-win32/el_native_vessel.h new file mode 100644 index 0000000..6a62882 --- /dev/null +++ b/ui/examples/native-hello/build-win32/el_native_vessel.h @@ -0,0 +1,69 @@ +#include +#include +#include "el_runtime.h" + +el_val_t native_init(void); +el_val_t native_run_loop(void); +el_val_t manifest_read(el_val_t path); +el_val_t manifest_title(el_val_t m); +el_val_t manifest_width(el_val_t m); +el_val_t manifest_height(el_val_t m); +el_val_t manifest_min_width(el_val_t m); +el_val_t manifest_min_height(el_val_t m); +el_val_t window_create(el_val_t title, el_val_t width, el_val_t height, el_val_t min_width, el_val_t min_height); +el_val_t window_from_manifest(el_val_t manifest_path); +el_val_t window_show(el_val_t handle); +el_val_t window_set_title(el_val_t handle, el_val_t title); +el_val_t vstack(el_val_t spacing); +el_val_t vstack_tight(void); +el_val_t hstack(el_val_t spacing); +el_val_t zstack(void); +el_val_t scroll(void); +el_val_t label(el_val_t text); +el_val_t button(el_val_t label); +el_val_t text_field(el_val_t placeholder); +el_val_t text_area(el_val_t placeholder); +el_val_t image(el_val_t path_or_name); +el_val_t widget_set_text(el_val_t handle, el_val_t text); +el_val_t widget_get_text(el_val_t handle); +el_val_t widget_set_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_font(el_val_t handle, el_val_t family, el_val_t size, el_val_t bold); +el_val_t widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, el_val_t bottom, el_val_t left); +el_val_t widget_set_padding_all(el_val_t handle, el_val_t p); +el_val_t widget_set_padding_xy(el_val_t handle, el_val_t px, el_val_t py); +el_val_t widget_set_width(el_val_t handle, el_val_t width); +el_val_t widget_set_height(el_val_t handle, el_val_t height); +el_val_t widget_set_flex(el_val_t handle, el_val_t flex); +el_val_t widget_set_corner_radius(el_val_t handle, el_val_t radius); +el_val_t widget_set_disabled(el_val_t handle, el_val_t disabled); +el_val_t widget_set_hidden(el_val_t handle, el_val_t hidden); +el_val_t widget_add_child(el_val_t parent, el_val_t child); +el_val_t widget_remove_child(el_val_t parent, el_val_t child); +el_val_t widget_destroy(el_val_t handle); +el_val_t widget_on_click(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_change(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_submit(el_val_t handle, el_val_t fn_name); +el_val_t hex_channel(el_val_t s, el_val_t offset); +el_val_t hex_nibble(el_val_t c); +el_val_t color_hex_r(el_val_t hex); +el_val_t color_hex_g(el_val_t hex); +el_val_t color_hex_b(el_val_t hex); +el_val_t color_hex_a(el_val_t hex); +el_val_t widget_set_color_hex(el_val_t handle, el_val_t hex); +el_val_t widget_set_bg_color_hex(el_val_t handle, el_val_t hex); +el_val_t style_surface(el_val_t handle); +el_val_t style_button_primary(el_val_t handle); +el_val_t style_label_body(el_val_t handle); +el_val_t style_label_heading(el_val_t handle); +el_val_t style_label_muted(el_val_t handle); + +extern el_val_t TOKEN_PRIMARY; +extern el_val_t TOKEN_ON_PRIMARY; +extern el_val_t TOKEN_BACKGROUND; +extern el_val_t TOKEN_ON_BG; +extern el_val_t TOKEN_SURFACE; +extern el_val_t TOKEN_ON_SURFACE; +extern el_val_t TOKEN_OUTLINE; +extern el_val_t TOKEN_ERROR; + diff --git a/ui/examples/native-hello/build-win32/el_native_vessel.o b/ui/examples/native-hello/build-win32/el_native_vessel.o new file mode 100644 index 0000000000000000000000000000000000000000..cd65d2c3a20eb83ccdcf1abc5113475d9214f456 GIT binary patch literal 14736 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 LH8(eLZTEiwfx{Mi literal 0 HcmV?d00001 diff --git a/ui/examples/native-hello/build-win32/el_win32.o b/ui/examples/native-hello/build-win32/el_win32.o new file mode 100644 index 0000000000000000000000000000000000000000..87e72148f8e9eb3f046106712435903f34a47c36 GIT binary patch literal 31904 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 literal 0 HcmV?d00001 diff --git a/ui/examples/native-hello/build-win32/native-hello.exe b/ui/examples/native-hello/build-win32/native-hello.exe new file mode 100755 index 0000000000000000000000000000000000000000..2a1d6fdab8490b0cf9b8bcc21bb0b4268446f0f3 GIT binary patch literal 246847 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

    Fx!B6Q;Qj?Fuw)neJ$oF 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 +#include +#include "el_runtime.h" + +el_val_t on_greet_click(el_val_t widget, el_val_t data); +el_val_t on_counter_click(el_val_t widget, el_val_t data); +el_val_t on_name_change(el_val_t widget, el_val_t data); +el_val_t app_build(el_val_t window); + +el_val_t g_window; +el_val_t g_label; +el_val_t g_input; +el_val_t g_button; +el_val_t g_counter; +el_val_t g_counter_lbl; +el_val_t manifest_env; +el_val_t manifest_path; +el_val_t win; +el_val_t g_window; + +el_val_t on_greet_click(el_val_t widget, el_val_t data) { + el_val_t name = widget_get_text(g_input); + el_val_t greeting = ({ el_val_t _if_result_1 = 0; if ((str_len(name) > 0)) { _if_result_1 = (el_str_concat(el_str_concat(EL_STR("Hello, "), name), EL_STR("!"))); } else { _if_result_1 = (EL_STR("Hello, World!")); } _if_result_1; }); + widget_set_text(g_label, greeting); + return 0; +} + +el_val_t on_counter_click(el_val_t widget, el_val_t data) { + el_val_t g_counter = (g_counter + 1); + widget_set_text(g_counter_lbl, el_str_concat(EL_STR("Clicks: "), int_to_str(g_counter))); + return 0; +} + +el_val_t on_name_change(el_val_t widget, el_val_t data) { + el_val_t has_text = (str_len(data) > 0); + widget_set_disabled(g_button, !has_text); + return 0; +} + +el_val_t app_build(el_val_t window) { + el_val_t root = vstack(0); + widget_set_padding_all(root, 24); + widget_set_bg_color_hex(root, EL_STR("#0f172a")); + widget_set_flex(root, 1); + el_val_t title = label(EL_STR("el-native \xe2\x80\x94 native widget demo")); + style_label_heading(title); + widget_add_child(root, title); + el_val_t gap1 = label(EL_STR("")); + widget_set_height(gap1, 16); + widget_add_child(root, gap1); + el_val_t subtitle = label(EL_STR("AppKit controls from el code, no ObjC in the app layer.")); + style_label_muted(subtitle); + widget_add_child(root, subtitle); + el_val_t gap2 = label(EL_STR("")); + widget_set_height(gap2, 24); + widget_add_child(root, gap2); + el_val_t input_row = hstack(8); + el_val_t name_label = label(EL_STR("Name:")); + style_label_body(name_label); + widget_set_width(name_label, 60); + el_val_t input = text_field(EL_STR("Enter your name\xe2\x80\xa6")); + style_label_body(input); + widget_set_flex(input, 1); + widget_on_change(input, EL_STR("on_name_change")); + el_val_t g_input = input; + el_val_t greet_btn = button(EL_STR("Greet")); + style_button_primary(greet_btn); + widget_set_disabled(greet_btn, 1); + widget_on_click(greet_btn, EL_STR("on_greet_click")); + el_val_t g_button = greet_btn; + widget_add_child(input_row, name_label); + widget_add_child(input_row, input); + widget_add_child(input_row, greet_btn); + widget_add_child(root, input_row); + el_val_t gap3 = label(EL_STR("")); + widget_set_height(gap3, 12); + widget_add_child(root, gap3); + el_val_t greeting = label(EL_STR("Waiting for name\xe2\x80\xa6")); + style_label_body(greeting); + widget_set_color_hex(greeting, EL_STR("#60a5fa")); + widget_set_font(greeting, EL_STR("system"), 16, 1); + el_val_t g_label = greeting; + widget_add_child(root, greeting); + el_val_t gap4 = label(EL_STR("")); + widget_set_height(gap4, 24); + widget_add_child(root, gap4); + el_val_t counter_row = hstack(12); + el_val_t counter_lbl = label(EL_STR("Clicks: 0")); + style_label_body(counter_lbl); + el_val_t g_counter_lbl = counter_lbl; + el_val_t counter_btn = button(EL_STR("Click me")); + style_button_primary(counter_btn); + widget_on_click(counter_btn, EL_STR("on_counter_click")); + widget_add_child(counter_row, counter_lbl); + widget_add_child(counter_row, counter_btn); + widget_add_child(root, counter_row); + widget_add_child(window, root); + return 0; +} + +int main(int _argc, char** _argv) { + el_runtime_init_args(_argc, _argv); + g_window = (-1); + g_label = (-1); + g_input = (-1); + g_button = (-1); + g_counter = 0; + g_counter_lbl = (-1); + native_init(); + manifest_env = env(EL_STR("EL_MANIFEST")); + manifest_path = ({ el_val_t _if_result_2 = 0; if ((str_len(manifest_env) > 0)) { _if_result_2 = (manifest_env); } else { _if_result_2 = (EL_STR("manifest.el")); } _if_result_2; }); + win = window_from_manifest(manifest_path); + g_window = win; + if (win < 0) { + println(EL_STR("Error: failed to create window. Is EL_TARGET_MACOS defined?")); + exit_program(1); + } + app_build(win); + window_show(win); + native_run_loop(); + return 0; +} + diff --git a/ui/examples/native-hello/build-win32/native_hello.o b/ui/examples/native-hello/build-win32/native_hello.o new file mode 100644 index 0000000000000000000000000000000000000000..55a081ba6004f845b075e55090a3d5720be11b2d GIT binary patch literal 5580 zcmaKvdyE@L9mmJ9orD}sj;eucMA1fcqFH)T$6}ILa33dii$^7iUNV&9~BblR1nAa zH$TsK*Nzy;yPx^J<~I+|&g9Rm5mYX&7a}7mAyR=e6G-OA@M<9jV?qS)RSjQ7P3ntv0fzBXU=DqW9+L^yMm~FGHP4WNDhP~Dq#8! z@fw*v)vkGZal^M4H~f4Nc`cjsPcDlM&!T!0DTd>BMtf>$QMPrU_cGo>4VdiVLfFx4 zZrn_kvgfT_!3$Up?U8OK)8Q%&e0abcS*l~?TK>)C7oz4E(9G?H$mG$`MtzP&ecpol zEgiCvrTYJA;ti2~E>oGwp9aD7y>I)0+59im&k}&M^o3Of`c>(GdbPCOlf8uPzqQA97BbRAmja-VZ z1@g|ELuV*bxS@{Z&O&{*bCOA@eJ)exYLe&By?3c$HA(f;Gb<}AW`kc!s;Z|eq--YN zi@Hp*i+m}U=EgYsfj|*y<2eqWnbR#co@4j0C_5L<7``($U7yUt*~?}mCw0>k@L$z)%R*fq3V|m$Acj63>szMI5hFa zF~cnz!K7o@m5SlnvraW74%#JWNMy=^Q#EG&sVbT%Id9K>SNLU%(8^8P<)S0@RUIcF zVUfVfQM%$$+YQ`u(J1(Bzy1f)_MU<*YO}S#Dd~QtnT(P{L2~{Swb%-i`Mh;teeN-j_Lw zC}W3?U|0%n*~x!e`p0?_nV$ISr&pz8FNER+1M5PzMg!l-a z?;&_`uoYi&^xBCc);~ms?$3PEA-yDcN zj)U0a6o`(63GobQkEE|@yKjJK#uDO(+U_L~_x!51dlj@-+P$e|e*w`(lo0;{eNxhz zxEkm6AkJkIXh>>zgSc;_nhtB4(By*H_e&t|#~Bd!{CREnEp7Lrw)+`~`}>mC-T-|{ zX7H+({S`!Kkc3zPaaOCb!*jdqLELUXh}(St#C8vZc*IQ*dyIqFqX6OzPHF8th{x(Y zh{x)J*8Uj8BXkACZM?4OmZpDd`Vju5{WANlpob+5f_f$G)ikQ(f*SVPiwocYB~?vDzz_a*-t?1`-+y`&~y_tEIod!Wp8S_rD;jiGKk{|>_{Wh zcO7U{(g#4?UqjOXXiRE%f<7Y&54q#T(Gx{$LGMu)e77Tx2}7*He$g(} z8!oi_(jMP!gF$E&+O3xG>$ah>;6f{az6sqnbcqxAuDNA;(>J2qhBWvOgznswZahX` z6S`@)OZdKxtphe~oucqv8-GyPm`bJJ;d?fXMm*+qMGD`skv8R{{S}1o*EC{mL$~T^ zQ5md(I3A;w87)PNzvv{ToL7mW<=GQB1<)8PiCeBr1#-11$;4C;_+?saECGlk_!;=M zC6A*v5Rn{5jaFIPW(GA{V=O^7VE)&!#In>Jk{m0FUgC^=(t{+mplW#zd$w)pg2qL8 zeMbp&oS$|{ei@ORs0B7oT&<$wyru*?&fmKv?UhenJf_M>#ko7yDcRN~+1n-AACXMn zF~i3qHq=UcovGHJ?6RQ~1Q)X5ISxyR&qr)X@}n*Zoh!JgwqEO!{JBfA9FaKX6DkPa zDo%o@za^z6(Emrpb0-e8+L*}x=nqx3a--*NCVE-ANJ;jXkoTXc2!3pD|sCXrE%vD z;c|uxomIu<$HmpkExUnbSBo{#`hJlBdC|?rq6-{$9KH<+X9lK~s$Z/dev/null; then + ELC="elc" +elif [ -x "${EL_LANG_ROOT}/dist/platform/elc" ]; then + ELC="${EL_LANG_ROOT}/dist/platform/elc" +else + echo "Error: elc not found. Add it to PATH or place it at:" + echo " ${EL_LANG_ROOT}/dist/platform/elc" + exit 1 +fi + +CLANG_FLAGS_COMMON=( + -std=c11 + -DEL_TARGET_MACOS + -I "${EL_RUNTIME}" +) + +clean() { + rm -rf "${BUILD_DIR}" + echo "Cleaned." +} + +compile() { + mkdir -p "${BUILD_DIR}" + + # ── 1. Vessel forward-declarations header ───────────────────────────────── + # elc --emit-header emits full function bodies, not just prototypes. + # Extract only the forward-declaration lines: stop at the first function + # definition (a line that ends with ') {' opening a body block). + # macOS awk does not support \s — use POSIX [[:space:]] instead. + echo "==> Generating el-native vessel header (declarations only)..." + "${ELC}" --emit-header "${EL_NATIVE_VESSEL}" \ + | awk 'BEGIN{in_body=0} /^[a-zA-Z_].+\)[[:space:]]*\{/ {in_body=1} !in_body{print}' \ + > "${BUILD_DIR}/el_native_vessel.h" + + # ── 2. Compile el-native vessel to C ────────────────────────────────────── + echo "==> Compiling el-native vessel to C..." + "${ELC}" "${EL_NATIVE_VESSEL}" \ + > "${BUILD_DIR}/el_native_vessel.c" + + # ── 3. Compile app entry to C ───────────────────────────────────────────── + echo "==> Compiling app entry to C..." + EL_MANIFEST="${SCRIPT_DIR}/manifest.el" \ + "${ELC}" "${SCRIPT_DIR}/src/main.el" \ + > "${BUILD_DIR}/native_hello.c" + + # ── 4. Compile el_appkit.m (ObjC, MRC — not ARC) ───────────────────────── + echo "==> Compiling el_appkit.m (AppKit bridge, -fno-objc-arc)..." + clang \ + -std=gnu11 \ + -ObjC \ + -fno-objc-arc \ + -DEL_TARGET_MACOS \ + -I "${EL_RUNTIME}" \ + -c "${EL_RUNTIME}/el_appkit.m" \ + -o "${BUILD_DIR}/el_appkit.o" + + # ── 5a. Compile el_seed.c ───────────────────────────────────────────────── + # el_seed.c provides the OS-boundary __-prefixed primitives + thin wrappers + # around el_runtime.c's higher-level functions. + echo "==> Compiling el_seed.c..." + clang "${CLANG_FLAGS_COMMON[@]}" \ + -c "${EL_RUNTIME}/el_seed.c" \ + -o "${BUILD_DIR}/el_seed.o" + + # ── 5b. Compile el_runtime.c and patch out duplicate __-prefixed symbols ── + # el_runtime.c provides the high-level builtins (str_len, json_get_string, + # int_to_str, println, env, exit_program, el_runtime_init_args, etc.) that + # el_seed.c does NOT provide (they are single-name, no __ prefix). + # + # el_runtime.c also defines the same __-prefixed OS wrappers as el_seed.c. + # We hide those duplicates using nmedit so the linker sees only one copy. + echo "==> Compiling el_runtime.c..." + clang "${CLANG_FLAGS_COMMON[@]}" \ + -c "${EL_RUNTIME}/el_runtime.c" \ + -o "${BUILD_DIR}/el_runtime.o" + + echo "==> Patching el_runtime.o (hiding __-prefixed symbols duplicated in el_seed.o)..." + # Build the set of symbols that el_seed.o defines and el_runtime.o also + # defines. We will hide el_runtime.o's copies, keeping el_seed.o canonical. + nm "${BUILD_DIR}/el_seed.o" 2>/dev/null \ + | awk '/^[0-9a-f]+ T _/{print $3}' | sort > "${BUILD_DIR}/.seed_T.txt" + nm "${BUILD_DIR}/el_runtime.o" 2>/dev/null \ + | awk '/^[0-9a-f]+ T _/{print $3}' | sort > "${BUILD_DIR}/.rt_T.txt" + # Symbols to keep public in el_runtime.o = all T symbols MINUS the + # duplicates (those will be supplied by el_seed.o). + comm -23 "${BUILD_DIR}/.rt_T.txt" "${BUILD_DIR}/.seed_T.txt" \ + > "${BUILD_DIR}/.rt_keep.txt" + nmedit -s "${BUILD_DIR}/.rt_keep.txt" "${BUILD_DIR}/el_runtime.o" + + # ── 6. Compile el-native vessel object ──────────────────────────────────── + # el_native_target.h adds float_div/mul/etc. + native widget declarations + # without conflicting with el_runtime.h. + echo "==> Compiling el-native vessel object..." + clang "${CLANG_FLAGS_COMMON[@]}" \ + -include "${EL_RUNTIME}/el_native_target.h" \ + -c "${BUILD_DIR}/el_native_vessel.c" \ + -o "${BUILD_DIR}/el_native_vessel.o" + + echo "==> Patching el_native_vessel.o (hiding vessel main)..." + # The vessel's compiled C has its own main(). Hide it so it does not + # conflict with the app's main in native_hello.o. + nm "${BUILD_DIR}/el_native_vessel.o" 2>/dev/null \ + | awk '/^[0-9a-f]+ T _/{print $3}' \ + | grep -v '^_main$' \ + > "${BUILD_DIR}/.vessel_keep.txt" + nmedit -s "${BUILD_DIR}/.vessel_keep.txt" "${BUILD_DIR}/el_native_vessel.o" + + # ── 7. Compile app object ───────────────────────────────────────────────── + # Inject el_native_target.h (float ops + native decls) and the vessel's + # forward-declarations header so the vessel functions are resolvable. + echo "==> Compiling app object..." + clang "${CLANG_FLAGS_COMMON[@]}" \ + -include "${EL_RUNTIME}/el_native_target.h" \ + -include "${BUILD_DIR}/el_native_vessel.h" \ + -c "${BUILD_DIR}/native_hello.c" \ + -o "${BUILD_DIR}/native_hello.o" + + # ── 8. Link ─────────────────────────────────────────────────────────────── + # el_seed.o = OS-boundary primitives (__-prefixed) + # el_runtime.o (patched) = high-level builtins (str_len, json_*, etc.) + # el_native_vessel.o (patched) = el-level widget API + # el_appkit.o = AppKit C bridge (MRC) + echo "==> Linking native-hello..." + clang "${CLANG_FLAGS_COMMON[@]}" \ + -framework Cocoa \ + -lpthread \ + -lcurl \ + -ldl \ + "${BUILD_DIR}/native_hello.o" \ + "${BUILD_DIR}/el_native_vessel.o" \ + "${BUILD_DIR}/el_appkit.o" \ + "${BUILD_DIR}/el_runtime.o" \ + "${BUILD_DIR}/el_seed.o" \ + -o "${BUILD_DIR}/native-hello" + + echo "==> Build complete: ${BUILD_DIR}/native-hello" +} + +run() { + compile + echo "==> Launching native-hello..." + EL_MANIFEST="${SCRIPT_DIR}/manifest.el" \ + "${BUILD_DIR}/native-hello" +} + +case "${1:-run}" in + clean) clean ;; + compile) compile ;; + platforms) "${EL_LANG_ROOT}/el-compiler/runtime/detect-platforms" ;; + run|*) run ;; +esac diff --git a/ui/examples/native-hello/build/.rt_T.txt b/ui/examples/native-hello/build/.rt_T.txt new file mode 100644 index 0000000..7657b58 --- /dev/null +++ b/ui/examples/native-hello/build/.rt_T.txt @@ -0,0 +1,397 @@ +___args_json +___channel_close +___channel_new +___channel_recv +___channel_send +___channel_try_recv +___env_get +___exec +___exec_bg +___exit_program +___float_to_str +___fs_exists +___fs_list_raw +___fs_mkdir +___fs_read +___fs_write +___fs_write_bytes +___http_conn_fd +___http_do +___http_do_map +___http_do_map_to_file +___http_response +___http_serve +___http_serve_v2 +___http_sse_close +___http_sse_open +___http_sse_send +___int_to_str +___json_array_get +___json_array_get_string +___json_array_len +___json_get +___json_get_raw +___json_parse_map +___json_set +___json_stringify_val +___mutex_lock +___mutex_new +___mutex_unlock +___print +___print_raw +___println +___read_n +___readline +___sha256_hex +___state_del +___state_get +___state_keys +___state_set +___str_alloc +___str_char_at +___str_cmp +___str_concat_raw +___str_len +___str_ncmp +___str_set_char +___str_slice_raw +___str_to_float +___str_to_int +___thread_create +___thread_join +___url_decode +___url_encode +___uuid_v4 +_aead_decrypt +_aead_encrypt +_append +_args +_base64_decode +_base64_encode +_base64url_decode +_base64url_encode +_bool_to_str +_bytes_to_str +_cal_cycle_phase +_cal_format +_cal_in +_cal_to_instant +_config +_cycle_calendar +_decimal_round +_duration_millis +_duration_nanos +_duration_seconds +_duration_to_millis +_duration_to_nanos +_duration_to_seconds +_earth_calendar +_earth_calendar_default +_el_abs +_el_arena_pop +_el_arena_push +_el_base64_encode_n +_el_cgi_init +_el_duration_add +_el_duration_div +_el_duration_eq +_el_duration_from_nanos +_el_duration_ge +_el_duration_gt +_el_duration_le +_el_duration_lt +_el_duration_ne +_el_duration_scale +_el_duration_sub +_el_get_field +_el_html_sanitize +_el_instant_add_dur +_el_instant_diff +_el_instant_eq +_el_instant_ge +_el_instant_gt +_el_instant_le +_el_instant_lt +_el_instant_ne +_el_instant_sub_dur +_el_list_append +_el_list_clone +_el_list_empty +_el_list_get +_el_list_len +_el_list_new +_el_local_date_add_dur +_el_local_date_eq +_el_local_date_lt +_el_local_time_add_dur +_el_map_get +_el_map_new +_el_map_set +_el_max +_el_mem_check +_el_min +_el_now_instant +_el_release +_el_request_end +_el_request_start +_el_retain +_el_runtime_init_args +_el_runtime_register_handler +_el_runtime_register_handler_v2 +_el_sha256_bytes_n +_el_sleep_duration +_el_str_concat +_engram_activate +_engram_activate_json +_engram_add_layer +_engram_apply_decay_json +_engram_compile_layered_json +_engram_connect +_engram_edge_between +_engram_edge_count +_engram_forget +_engram_get_node +_engram_get_node_json +_engram_list_layers +_engram_list_layers_json +_engram_load +_engram_neighbors +_engram_neighbors_filtered +_engram_neighbors_json +_engram_node +_engram_node_count +_engram_node_full +_engram_node_layered +_engram_query_range +_engram_remove_layer +_engram_save +_engram_scan_nodes +_engram_scan_nodes_by_type_json +_engram_scan_nodes_json +_engram_search +_engram_search_json +_engram_stats_json +_engram_strengthen +_env +_exec +_exec_bg +_exec_capture +_exec_command +_exit_program +_float_to_int +_float_to_str +_format_float +_fs_exists +_fs_list +_fs_list_json +_fs_mkdir +_fs_read +_fs_write +_fs_write_bytes +_get +_getpid_now +_hash_sha256 +_hmac_sha256_bytes +_hmac_sha256_hex +_html_escape +_html_raw +_http_delete +_http_get +_http_get_engram +_http_get_to_file +_http_get_with_headers +_http_patch +_http_post +_http_post_engram +_http_post_form_auth +_http_post_json +_http_post_json_with_headers +_http_post_to_file +_http_post_with_headers +_http_response +_http_serve +_http_serve_v2 +_http_set_handler +_http_set_handler_v2 +_in_calendar +_instant_from_iso8601 +_instant_to_iso8601 +_instant_to_unix_millis +_instant_to_unix_seconds +_int_to_float +_int_to_str +_is_alphanumeric +_is_digit +_is_letter +_is_lowercase +_is_punctuation +_is_uppercase +_is_whitespace +_json_array_get +_json_array_get_string +_json_array_len +_json_array_push +_json_build_array +_json_build_object +_json_escape_string +_json_get +_json_get_bool +_json_get_float +_json_get_int +_json_get_raw +_json_get_string +_json_parse +_json_set +_json_stringify +_len +_list_get +_list_join +_list_len +_list_push +_list_push_front +_list_range +_llm_call +_llm_call_agentic +_llm_call_system +_llm_models +_llm_register_tool +_llm_vision +_local_date +_local_date_day +_local_date_month +_local_date_year +_local_datetime +_local_time +_local_time_hour +_local_time_minute +_local_time_nanos +_local_time_second +_log_info +_log_warn +_map_get +_map_set +_mars_calendar +_math_cos +_math_ln +_math_log +_math_pi +_math_sin +_math_sqrt +_native_int_to_str +_native_list_append +_native_list_clone +_native_list_empty +_native_list_get +_native_list_len +_native_str_to_int +_native_string_chars +_no_cycle_calendar +_now +_now_in +_now_millis +_now_ns +_parse_int +_pq_hybrid_handshake +_pq_hybrid_keygen +_pq_kem_decaps +_pq_kem_encaps +_pq_kem_keygen +_pq_keygen_signature +_pq_sign +_pq_verify +_print +_println +_readline +_relative_calendar +_rhythm_and +_rhythm_cycle_phase +_rhythm_cycle_start +_rhythm_duration +_rhythm_event +_rhythm_matches +_rhythm_next_after +_rhythm_or +_rhythm_session_start +_rhythm_weekday +_rhythm_weekly_at +_sha256_bytes +_sha256_hex +_sha3_256_hex +_sleep_ms +_sleep_secs +_state_del +_state_get +_state_get_or +_state_has +_state_keys +_state_set +_stdout_restore +_stdout_to_file +_str_char_at +_str_char_code +_str_concat +_str_contains +_str_count +_str_count_bytes +_str_count_chars +_str_count_digits +_str_count_letters +_str_count_lines +_str_count_words +_str_ends_with +_str_eq +_str_find_chars +_str_format +_str_index_of +_str_index_of_all +_str_join +_str_last_index_of +_str_len +_str_lower +_str_lstrip +_str_pad_left +_str_pad_right +_str_repeat +_str_replace +_str_reverse +_str_rstrip +_str_slice +_str_split +_str_split_chars +_str_split_lines +_str_split_n +_str_starts_with +_str_strip_chars +_str_strip_prefix +_str_strip_suffix +_str_to_bytes +_str_to_float +_str_to_int +_str_to_lower +_str_to_upper +_str_trim +_str_upper +_time_add +_time_diff +_time_format +_time_from_parts +_time_now +_time_now_ms +_time_now_utc +_time_to_parts +_ttl_cache_age +_ttl_cache_get +_ttl_cache_set +_unix_millis +_unix_seconds +_unix_timestamp +_unix_timestamp_ms +_url_decode +_url_encode +_uuid_new +_uuid_v4 +_zone +_zone_local +_zone_offset +_zone_utc +_zoned diff --git a/ui/examples/native-hello/build/.rt_keep.txt b/ui/examples/native-hello/build/.rt_keep.txt new file mode 100644 index 0000000..6aa9058 --- /dev/null +++ b/ui/examples/native-hello/build/.rt_keep.txt @@ -0,0 +1,340 @@ +___channel_close +___channel_new +___channel_recv +___channel_send +___channel_try_recv +___http_do_map +___http_do_map_to_file +___print_raw +___read_n +_aead_decrypt +_aead_encrypt +_append +_args +_base64_decode +_base64_encode +_base64url_decode +_base64url_encode +_bool_to_str +_bytes_to_str +_cal_cycle_phase +_cal_format +_cal_in +_cal_to_instant +_config +_cycle_calendar +_decimal_round +_duration_millis +_duration_nanos +_duration_seconds +_duration_to_millis +_duration_to_nanos +_duration_to_seconds +_earth_calendar +_earth_calendar_default +_el_abs +_el_arena_pop +_el_arena_push +_el_base64_encode_n +_el_cgi_init +_el_duration_add +_el_duration_div +_el_duration_eq +_el_duration_from_nanos +_el_duration_ge +_el_duration_gt +_el_duration_le +_el_duration_lt +_el_duration_ne +_el_duration_scale +_el_duration_sub +_el_get_field +_el_html_sanitize +_el_instant_add_dur +_el_instant_diff +_el_instant_eq +_el_instant_ge +_el_instant_gt +_el_instant_le +_el_instant_lt +_el_instant_ne +_el_instant_sub_dur +_el_list_append +_el_list_clone +_el_list_empty +_el_list_get +_el_list_len +_el_list_new +_el_local_date_add_dur +_el_local_date_eq +_el_local_date_lt +_el_local_time_add_dur +_el_map_get +_el_map_new +_el_map_set +_el_max +_el_mem_check +_el_min +_el_now_instant +_el_release +_el_retain +_el_runtime_init_args +_el_runtime_register_handler +_el_runtime_register_handler_v2 +_el_sha256_bytes_n +_el_sleep_duration +_el_str_concat +_engram_activate +_engram_activate_json +_engram_add_layer +_engram_apply_decay_json +_engram_compile_layered_json +_engram_connect +_engram_edge_between +_engram_edge_count +_engram_forget +_engram_get_node +_engram_get_node_json +_engram_list_layers +_engram_list_layers_json +_engram_load +_engram_neighbors +_engram_neighbors_filtered +_engram_neighbors_json +_engram_node +_engram_node_count +_engram_node_full +_engram_node_layered +_engram_query_range +_engram_remove_layer +_engram_save +_engram_scan_nodes +_engram_scan_nodes_by_type_json +_engram_scan_nodes_json +_engram_search +_engram_search_json +_engram_stats_json +_engram_strengthen +_env +_exec +_exec_bg +_exec_capture +_exec_command +_exit_program +_float_to_int +_float_to_str +_format_float +_fs_exists +_fs_list +_fs_list_json +_fs_mkdir +_fs_read +_fs_write +_fs_write_bytes +_get +_getpid_now +_hash_sha256 +_hmac_sha256_bytes +_hmac_sha256_hex +_html_escape +_html_raw +_http_delete +_http_get +_http_get_engram +_http_get_to_file +_http_get_with_headers +_http_patch +_http_post +_http_post_engram +_http_post_form_auth +_http_post_json +_http_post_json_with_headers +_http_post_to_file +_http_post_with_headers +_http_response +_http_serve +_http_serve_v2 +_http_set_handler +_http_set_handler_v2 +_in_calendar +_instant_from_iso8601 +_instant_to_iso8601 +_instant_to_unix_millis +_instant_to_unix_seconds +_int_to_float +_int_to_str +_is_alphanumeric +_is_digit +_is_letter +_is_lowercase +_is_punctuation +_is_uppercase +_is_whitespace +_json_array_get +_json_array_get_string +_json_array_len +_json_array_push +_json_build_array +_json_build_object +_json_escape_string +_json_get +_json_get_bool +_json_get_float +_json_get_int +_json_get_raw +_json_get_string +_json_parse +_json_set +_json_stringify +_len +_list_get +_list_join +_list_len +_list_push +_list_push_front +_list_range +_llm_call +_llm_call_agentic +_llm_call_system +_llm_models +_llm_register_tool +_llm_vision +_local_date +_local_date_day +_local_date_month +_local_date_year +_local_datetime +_local_time +_local_time_hour +_local_time_minute +_local_time_nanos +_local_time_second +_log_info +_log_warn +_map_get +_map_set +_mars_calendar +_math_cos +_math_ln +_math_log +_math_pi +_math_sin +_math_sqrt +_native_int_to_str +_native_list_append +_native_list_clone +_native_list_empty +_native_list_get +_native_list_len +_native_str_to_int +_native_string_chars +_no_cycle_calendar +_now +_now_in +_now_millis +_now_ns +_parse_int +_pq_hybrid_handshake +_pq_hybrid_keygen +_pq_kem_decaps +_pq_kem_encaps +_pq_kem_keygen +_pq_keygen_signature +_pq_sign +_pq_verify +_print +_println +_readline +_relative_calendar +_rhythm_and +_rhythm_cycle_phase +_rhythm_cycle_start +_rhythm_duration +_rhythm_event +_rhythm_matches +_rhythm_next_after +_rhythm_or +_rhythm_session_start +_rhythm_weekday +_rhythm_weekly_at +_sha256_bytes +_sha256_hex +_sha3_256_hex +_sleep_ms +_sleep_secs +_state_del +_state_get +_state_get_or +_state_has +_state_keys +_state_set +_stdout_restore +_stdout_to_file +_str_char_at +_str_char_code +_str_concat +_str_contains +_str_count +_str_count_bytes +_str_count_chars +_str_count_digits +_str_count_letters +_str_count_lines +_str_count_words +_str_ends_with +_str_eq +_str_find_chars +_str_format +_str_index_of +_str_index_of_all +_str_join +_str_last_index_of +_str_len +_str_lower +_str_lstrip +_str_pad_left +_str_pad_right +_str_repeat +_str_replace +_str_reverse +_str_rstrip +_str_slice +_str_split +_str_split_chars +_str_split_lines +_str_split_n +_str_starts_with +_str_strip_chars +_str_strip_prefix +_str_strip_suffix +_str_to_bytes +_str_to_float +_str_to_int +_str_to_lower +_str_to_upper +_str_trim +_str_upper +_time_add +_time_diff +_time_format +_time_from_parts +_time_now +_time_now_ms +_time_now_utc +_time_to_parts +_ttl_cache_age +_ttl_cache_get +_ttl_cache_set +_unix_millis +_unix_seconds +_unix_timestamp +_unix_timestamp_ms +_url_decode +_url_encode +_uuid_new +_uuid_v4 +_zone +_zone_local +_zone_offset +_zone_utc +_zoned diff --git a/ui/examples/native-hello/build/.seed_T.txt b/ui/examples/native-hello/build/.seed_T.txt new file mode 100644 index 0000000..260f1fe --- /dev/null +++ b/ui/examples/native-hello/build/.seed_T.txt @@ -0,0 +1,137 @@ +___args_json +___button_create +___cos_f +___engram_activate +___engram_activate_json +___engram_add_layer +___engram_compile_layered_json +___engram_connect +___engram_edge_between +___engram_edge_count +___engram_forget +___engram_get_node +___engram_get_node_json +___engram_list_layers +___engram_list_layers_json +___engram_load +___engram_neighbors +___engram_neighbors_filtered +___engram_neighbors_json +___engram_node +___engram_node_count +___engram_node_full +___engram_node_layered +___engram_remove_layer +___engram_save +___engram_scan_nodes +___engram_scan_nodes_by_type_json +___engram_scan_nodes_json +___engram_search +___engram_search_json +___engram_stats_json +___engram_strengthen +___env_get +___exec +___exec_bg +___exit_program +___float_to_str +___fs_exists +___fs_list_raw +___fs_mkdir +___fs_read +___fs_write +___fs_write_bytes +___hstack_create +___html_sanitize +___http_conn_fd +___http_do +___http_do_to_file +___http_response +___http_serve +___http_serve_v2 +___http_sse_close +___http_sse_open +___http_sse_send +___image_create +___int_to_str +___json_array_get +___json_array_get_string +___json_array_len +___json_get +___json_get_bool +___json_get_float +___json_get_int +___json_get_raw +___json_get_string +___json_parse +___json_parse_map +___json_set +___json_stringify +___json_stringify_val +___label_create +___ln_f +___log_f +___manifest_read +___mutex_lock +___mutex_new +___mutex_unlock +___native_init +___native_run_loop +___pi_f +___print +___println +___readline +___scroll_create +___sha256_hex +___sin_f +___sleep_ms +___sqrt_f +___state_del +___state_get +___state_keys +___state_set +___str_alloc +___str_char_at +___str_cmp +___str_concat_raw +___str_len +___str_ncmp +___str_set_char +___str_slice_raw +___str_to_float +___str_to_int +___text_area_create +___text_field_create +___thread_create +___thread_join +___time_now_ns +___url_decode +___url_encode +___uuid_v4 +___vstack_create +___widget_add_child +___widget_destroy +___widget_get_text +___widget_on_change +___widget_on_click +___widget_on_submit +___widget_remove_child +___widget_set_bg_color +___widget_set_color +___widget_set_corner_radius +___widget_set_disabled +___widget_set_flex +___widget_set_font +___widget_set_height +___widget_set_hidden +___widget_set_padding +___widget_set_text +___widget_set_width +___window_create +___window_set_title +___window_show +___zstack_create +_el_request_end +_el_request_start +_el_seed_init_args +_el_seed_set_http_conn_fd diff --git a/ui/examples/native-hello/build/.vessel_keep.txt b/ui/examples/native-hello/build/.vessel_keep.txt new file mode 100644 index 0000000..a8a7964 --- /dev/null +++ b/ui/examples/native-hello/build/.vessel_keep.txt @@ -0,0 +1,55 @@ +_button +_color_hex_a +_color_hex_b +_color_hex_g +_color_hex_r +_hex_channel +_hex_nibble +_hstack +_image +_label +_manifest_height +_manifest_min_height +_manifest_min_width +_manifest_read +_manifest_title +_manifest_width +_native_init +_native_run_loop +_scroll +_style_button_primary +_style_label_body +_style_label_heading +_style_label_muted +_style_surface +_text_area +_text_field +_vstack +_vstack_tight +_widget_add_child +_widget_destroy +_widget_get_text +_widget_on_change +_widget_on_click +_widget_on_submit +_widget_remove_child +_widget_set_bg_color +_widget_set_bg_color_hex +_widget_set_color +_widget_set_color_hex +_widget_set_corner_radius +_widget_set_disabled +_widget_set_flex +_widget_set_font +_widget_set_height +_widget_set_hidden +_widget_set_padding +_widget_set_padding_all +_widget_set_padding_xy +_widget_set_text +_widget_set_width +_window_create +_window_from_manifest +_window_set_title +_window_show +_zstack diff --git a/ui/examples/native-hello/build/el_appkit.o b/ui/examples/native-hello/build/el_appkit.o new file mode 100644 index 0000000000000000000000000000000000000000..4f19980391d3f848f3664293e31155cb68b7be3b GIT binary patch literal 58520 zcmeI54`7v7dH>%K+J=@=YN?I3g|x*rZGk3`LW*2_Ay9*+g+ki0mGmYg7m_w4X%Z+{ zbWu=It4kF()NV`v=t9RdbJc}OXB6C`R>iLKhqKervMtQ&P`fR4u>L;Z_dM^t?|tvR z3I6--_w(mf`pt8m=RD^*&w0*s&U@bX-uD|n{lR}v^}GU)kNz{6e?{l;pA!D@c@6(| zpY8vd^FMR`d6HjVsycj%H#!ule={8EB@*4qZQVuyiA3#+b+u_a_-p?n_m}iZb9}Ss zeOP}?_Ie!0{Wp==)YzCvZfi_-bSJtSHbnIWdit!=vu|+v!aBl#ClZZa-JLCMo2)RZ zucp#5W*Wcyrf}_S-HAl|hI<+ljjat`U2P4UlTm&5n7((Knh&0#zV@~*-;0UF@};#) z(>9zmeXFOrvf{Ys74qlk+dc0M8raCk>}zW1Ztyu#eepNC3MZ{z^Q}(b(f2XN5nUop z-{xd@v$~r#zGc;}(y1v9*R66G{MSWMKxOFb-rkX|Z_XMg`}-D~wZEONtH1K-YuVb+ z=?g~tdw89zU*y1hF_EpqSXRGrV>n=<`i_{sxK$cMpT=YFgKmylaS9TN)KK_kQGL^` ze?2yqmGw^FAo?y$X-WTKt)fZ4a#6dX1C>ap)4R~E6aF_;=YH>$7t zE>|gThIDLj{T)MJkfW?AtMAX>u4JpMQ#@wQx83WVbPz8CjW)g?aC!8sEdNFA%gleh zrce1-pF#AcJ?YBA{|);u*ZA%=eZgEEGW+_l&&DOF-hW zMLrRIjqRH|8XCJ3TiWh#X=_R(YL3NHA1jRe ze3gx!ldgNL(0gL!ocPQ1r+1m>(Hn1%>Ysj~Y9DPsG*p=Q)+<%sH%AK5kB*`O??+$r zyjs5v(PzbfL~8cwSJ2B~%#hra6A%0yG1`m#Lq#nugS$QN2Gx-aOYDpjsvGbxp7K7~ zB))8+J!@BepSi1du zPNOe8=IVQR%=-%QMd96JLEm179mmkuM?che{XKGt$3JW^I`E0=6`ju*6k2>B8*%1-mkA@%F*eW#(b`(-xMRyY=eJ{Fy0cEaz& zcIjt4o+x^2{6j@cy&n~v?PBnl_>8~!`q#Jfa^j^f<)hz{k9?VQdn1?Pqf5<4@KjHJ zQ$5X>l#k#AWr~-e9gXKGK2G_FzvaV>*nw7@_+x^fo>yGZj>=s8+`R9VL%*!}$&9gd zTxFJ*dOd4MY_AIQPd`vV+%aeUn2#SIwkl*FS#QQMY*rmoXK!hNcR(^;f%y%d)ge!K z%nOZU&ok;{SWfd^dR&?Ja*5g_n;_@g85ZZ|CKMQzrMU*>?ye2kc{xkmDbc&DYS*3C3zl zd~nT)tGolRTXE`a=(`ABxlU!#o6=v5$Nn~Fj5e$fop zKg;L-dU&xLmyCI-aWdbHFu#M`<=Y_r_ecZ0L| z2kxAO4-#PF)UiwH`z-!lO8;iXPY3#?TYrbgTJ1*tkdn9Dex=PbUzXhSXoU6{w{#t1 zh8QU-P~5~%7n~J8J!wk(bm93SJJ7K#tOL8Ar_9&E->j{ET>Cz~5PfICJD(g1FRlBg zZ)x2L)2AP}l^j>-*7m~mzNU|PeT=bFZW+DAJD~9(pB_N(eQ&b7K6**df#{xMc(U75 z^lPrdzm`2mY7R4JN?WcS)cA#M(0cr@$SP-CbMd+FD>=){pl_POnhd{)J;^NkBs(m3 z94IQ7a&KzyW97<&&fcB_{p?YY_4B#2-@8!#`PwV5TteJ_P<+X1-N@KqMdrHp4a$?U z^$Ps!z1@3glI4=q4}|k$W{!}&hkQXU*|5K{W27*ZTkwJd#zFCmEs`7{*Z3XN%hmm!dYY9bZkQ2Un3cd(O^DmTnaSC-hK79f7IU5pJ(C` zQ)*xHJ6K1=OOK^nizZnvkY6)ws>{1m!jSDBDFp zAIfXaZ|ObS=?6Z~emfl-8dz~StxcuC+CYZU=POJ3dYzUOZFJ4af7G5M|j*c7tf?j z<2#gRd`~}+UL)|=ujhEOX6BuDXOPc=F$wQiG!9qVI-qq!dH7d-o#N(VI;U!0hV!z{ zR3!6gp`C&F@#N-ja4oJ_7_nGT{Ah2ZYk=VF<%Ie|{qIwDF8bfZIbZem>&CQyxrV%; z{Y&Zjo}W`P^TMxb9EJ1uFDZ^Rw}W}D*ijDI9X{VBhZGeI-8fp{&S?C3j-2+7C&+WU zZYd!bO+qdsk8o`vTDc|~8(Mo58_$!YB%?U+EMNL@K#o#g(zUYqiUXYqexI_8IDj5M z4t`D7heDmPoX1)>>7n#GekuE-OEdRJ_$Qbbqg<;pKeP8p^7HlVk*;^wI$V3D@;p92 z;GZSJ3t}XoqiaHVjCGADxxDRNM|;=7=gfe7c4~Oa=rdlyrav0@JmV_PGT3Kx{eSw{ z)pm{`+tD-n=EhHto*w}?M2<@qw4^C>rzgLAd5dmM3#J>Pe%$-!RT=}z04u~!d` zOK{I^q%eIR!1xfKXMR?c_uS-A`a1Yb&P|%_{@t7KsrDGDvBFo1i{a>b2r-p!Z>|0Z zdu#25{A***qDI+A>pUucmfhbZ&lJ7JyKkr zS6oTA?*9dQt>8XNw47%FQt}$7ey)!=FZajSk88U}73d*`Qu1N_+&lAQ?(_rc>-wL4 zzpi^F-b4HTU$_R#kvlx{hMN~|Y=hXj5#Q*%C1bpQ&hdRs#Q%PK=njvg#w9497LwQa z5^L%EvY|O2$Oq%7J$88B2m5cyMd!6*GUGaJXZl)IbD4AYgWN+u_~@aT2Orxx^WZNs zuluSJ2S={+p5lz{AbXUj`VQTFaAX0v6I|pyCHwN(lHM0(pA!dpH5ju>`Hj4-bvnrF z-Zk;3yrC;+7R-%5bp<%7JpR-&u<(ZXQ;lHY!_+u))=@OYyHEe71ap_O4S#M2b5}HT zxuMYRBhzMdj$UlG_!aT%Njj!hKb8 z*80>l44=ivqgSz>m&XtE2iJbHm?M-0J}+P{l!Wfxx;b&#*iAuQ?S+HAm2`>bTC&;p zR?_8BMo#Iy!k!E2nQYgYp|<>c>a0ycyTP@l>T_???U{JCBA-3|h3m)Yga2%f-AH-+B>XW>2m8XNZj2PDOVZ$ zgeTQ5Yjyhkg+A(DSWsVbDL+}vYA$dsomDUVT#RI-TYH&6N8ip%iIcnhXPML{ebqfS z?X5YhSwA*PF5-T@Z?ERW3(Onehjt%bdv2XoY98ttGp#+km&Y>@AkRNsPmC_`UOs+( z{N;aIkZw2V%cG{-U+d_n?{DSF;F{9<%C+LlBUfuroPnxEV+ z#-;=QJS7(Vd8+wZNICOW{>;qFx~4y$=TLZV0w3bfCy;Z9KZ0DSYxPll6Rcf4S~x>A zW8kkpBf(k|l%4P0w={TeiSZa^JWjyV+1Uy6SpjQZFpmqlzos=WpeKoD?F(oJlFa!*tNdmFx5}y$s?0(4OO4iSH-|3j5+&u`Syh34xVCI@mo4Ke&E_0 z@KM3J=XnJiW=@)3KeM2C!_3la;s>rF$8q1?FZU=*KX;<%OfKc0o-^Tj6#w~?yH4?3 z-D&36Y0k?|b3N`qTOs>SKX41r-`I6@Rr+3we~m+Ija(JF#$k;8Yn+R?AFgWxe=c!9 zoOzr28{7T+;q*(-A1L3uxCxzWh1&U9*3fIP*Ix_eH`>wOM{`$gd(3CG!!rW@bDR3R z-kt}#lzQ@Oc7H{R zFIQ^sr0d>hI}h@onSu7#SoUxYc2=Y70Oi3G@Jh&|iZ{j9^OyXw9^l{OKc^nl({FK>m31p)&`SeK|OHP}zl?G1?x9SUym6F=vMG70b$x z!C3Vdat2svXMoCmJjX=t1QPPjsx>F^E(+o*WM}PnmDwV2<3r%@g2

    ZgAeru`Cet$9D*erd?F_?Ay?JY7FS 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 +#include +#include "el_runtime.h" + +el_val_t native_init(void); +el_val_t native_run_loop(void); +el_val_t manifest_read(el_val_t path); +el_val_t manifest_title(el_val_t m); +el_val_t manifest_width(el_val_t m); +el_val_t manifest_height(el_val_t m); +el_val_t manifest_min_width(el_val_t m); +el_val_t manifest_min_height(el_val_t m); +el_val_t window_create(el_val_t title, el_val_t width, el_val_t height, el_val_t min_width, el_val_t min_height); +el_val_t window_from_manifest(el_val_t manifest_path); +el_val_t window_show(el_val_t handle); +el_val_t window_set_title(el_val_t handle, el_val_t title); +el_val_t vstack(el_val_t spacing); +el_val_t vstack_tight(void); +el_val_t hstack(el_val_t spacing); +el_val_t zstack(void); +el_val_t scroll(void); +el_val_t label(el_val_t text); +el_val_t button(el_val_t label); +el_val_t text_field(el_val_t placeholder); +el_val_t text_area(el_val_t placeholder); +el_val_t image(el_val_t path_or_name); +el_val_t widget_set_text(el_val_t handle, el_val_t text); +el_val_t widget_get_text(el_val_t handle); +el_val_t widget_set_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_font(el_val_t handle, el_val_t family, el_val_t size, el_val_t bold); +el_val_t widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, el_val_t bottom, el_val_t left); +el_val_t widget_set_padding_all(el_val_t handle, el_val_t p); +el_val_t widget_set_padding_xy(el_val_t handle, el_val_t px, el_val_t py); +el_val_t widget_set_width(el_val_t handle, el_val_t width); +el_val_t widget_set_height(el_val_t handle, el_val_t height); +el_val_t widget_set_flex(el_val_t handle, el_val_t flex); +el_val_t widget_set_corner_radius(el_val_t handle, el_val_t radius); +el_val_t widget_set_disabled(el_val_t handle, el_val_t disabled); +el_val_t widget_set_hidden(el_val_t handle, el_val_t hidden); +el_val_t widget_add_child(el_val_t parent, el_val_t child); +el_val_t widget_remove_child(el_val_t parent, el_val_t child); +el_val_t widget_destroy(el_val_t handle); +el_val_t widget_on_click(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_change(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_submit(el_val_t handle, el_val_t fn_name); +el_val_t hex_channel(el_val_t s, el_val_t offset); +el_val_t hex_nibble(el_val_t c); +el_val_t color_hex_r(el_val_t hex); +el_val_t color_hex_g(el_val_t hex); +el_val_t color_hex_b(el_val_t hex); +el_val_t color_hex_a(el_val_t hex); +el_val_t widget_set_color_hex(el_val_t handle, el_val_t hex); +el_val_t widget_set_bg_color_hex(el_val_t handle, el_val_t hex); +el_val_t style_surface(el_val_t handle); +el_val_t style_button_primary(el_val_t handle); +el_val_t style_label_body(el_val_t handle); +el_val_t style_label_heading(el_val_t handle); +el_val_t style_label_muted(el_val_t handle); + +el_val_t TOKEN_PRIMARY; +el_val_t TOKEN_ON_PRIMARY; +el_val_t TOKEN_BACKGROUND; +el_val_t TOKEN_ON_BG; +el_val_t TOKEN_SURFACE; +el_val_t TOKEN_ON_SURFACE; +el_val_t TOKEN_OUTLINE; +el_val_t TOKEN_ERROR; + +el_val_t native_init(void) { + __native_init(); + return 0; +} + +el_val_t native_run_loop(void) { + __native_run_loop(); + return 0; +} + +el_val_t manifest_read(el_val_t path) { + return __manifest_read(path); + return 0; +} + +el_val_t manifest_title(el_val_t m) { + return json_get_string(m, EL_STR("title")); + return 0; +} + +el_val_t manifest_width(el_val_t m) { + return json_get_int(m, EL_STR("width")); + return 0; +} + +el_val_t manifest_height(el_val_t m) { + return json_get_int(m, EL_STR("height")); + return 0; +} + +el_val_t manifest_min_width(el_val_t m) { + return json_get_int(m, EL_STR("min_width")); + return 0; +} + +el_val_t manifest_min_height(el_val_t m) { + return json_get_int(m, EL_STR("min_height")); + return 0; +} + +el_val_t window_create(el_val_t title, el_val_t width, el_val_t height, el_val_t min_width, el_val_t min_height) { + return __window_create(title, width, height, min_width, min_height); + return 0; +} + +el_val_t window_from_manifest(el_val_t manifest_path) { + el_val_t m = manifest_read(manifest_path); + el_val_t title = manifest_title(m); + el_val_t w = manifest_width(m); + el_val_t h = manifest_height(m); + el_val_t mw = manifest_min_width(m); + el_val_t mh = manifest_min_height(m); + el_val_t safe_w = ({ el_val_t _if_result_1 = 0; if ((w > 0)) { _if_result_1 = (w); } else { _if_result_1 = (1200); } _if_result_1; }); + el_val_t safe_h = ({ el_val_t _if_result_2 = 0; if ((h > 0)) { _if_result_2 = (h); } else { _if_result_2 = (800); } _if_result_2; }); + el_val_t safe_mw = ({ el_val_t _if_result_3 = 0; if ((mw > 0)) { _if_result_3 = (mw); } else { _if_result_3 = (600); } _if_result_3; }); + el_val_t safe_mh = ({ el_val_t _if_result_4 = 0; if ((mh > 0)) { _if_result_4 = (mh); } else { _if_result_4 = (400); } _if_result_4; }); + el_val_t safe_t = ({ el_val_t _if_result_5 = 0; if ((str_len(title) > 0)) { _if_result_5 = (title); } else { _if_result_5 = (EL_STR("App")); } _if_result_5; }); + return window_create(safe_t, safe_w, safe_h, safe_mw, safe_mh); + return 0; +} + +el_val_t window_show(el_val_t handle) { + __window_show(handle); + return 0; +} + +el_val_t window_set_title(el_val_t handle, el_val_t title) { + __window_set_title(handle, title); + return 0; +} + +el_val_t vstack(el_val_t spacing) { + return __vstack_create(spacing); + return 0; +} + +el_val_t vstack_tight(void) { + return __vstack_create(0); + return 0; +} + +el_val_t hstack(el_val_t spacing) { + return __hstack_create(spacing); + return 0; +} + +el_val_t zstack(void) { + return __zstack_create(); + return 0; +} + +el_val_t scroll(void) { + return __scroll_create(); + return 0; +} + +el_val_t label(el_val_t text) { + return __label_create(text); + return 0; +} + +el_val_t button(el_val_t label) { + return __button_create(label); + return 0; +} + +el_val_t text_field(el_val_t placeholder) { + return __text_field_create(placeholder); + return 0; +} + +el_val_t text_area(el_val_t placeholder) { + return __text_area_create(placeholder); + return 0; +} + +el_val_t image(el_val_t path_or_name) { + return __image_create(path_or_name); + return 0; +} + +el_val_t widget_set_text(el_val_t handle, el_val_t text) { + __widget_set_text(handle, text); + return 0; +} + +el_val_t widget_get_text(el_val_t handle) { + return __widget_get_text(handle); + return 0; +} + +el_val_t widget_set_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + __widget_set_color(handle, r, g, b, a); + return 0; +} + +el_val_t widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a) { + __widget_set_bg_color(handle, r, g, b, a); + return 0; +} + +el_val_t widget_set_font(el_val_t handle, el_val_t family, el_val_t size, el_val_t bold) { + el_val_t bold_int = ({ el_val_t _if_result_6 = 0; if (bold) { _if_result_6 = (1); } else { _if_result_6 = (0); } _if_result_6; }); + __widget_set_font(handle, family, size, bold_int); + return 0; +} + +el_val_t widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, el_val_t bottom, el_val_t left) { + __widget_set_padding(handle, top, right, bottom, left); + return 0; +} + +el_val_t widget_set_padding_all(el_val_t handle, el_val_t p) { + __widget_set_padding(handle, p, p, p, p); + return 0; +} + +el_val_t widget_set_padding_xy(el_val_t handle, el_val_t px, el_val_t py) { + __widget_set_padding(handle, py, px, py, px); + return 0; +} + +el_val_t widget_set_width(el_val_t handle, el_val_t width) { + __widget_set_width(handle, width); + return 0; +} + +el_val_t widget_set_height(el_val_t handle, el_val_t height) { + __widget_set_height(handle, height); + return 0; +} + +el_val_t widget_set_flex(el_val_t handle, el_val_t flex) { + __widget_set_flex(handle, flex); + return 0; +} + +el_val_t widget_set_corner_radius(el_val_t handle, el_val_t radius) { + __widget_set_corner_radius(handle, radius); + return 0; +} + +el_val_t widget_set_disabled(el_val_t handle, el_val_t disabled) { + el_val_t d = ({ el_val_t _if_result_7 = 0; if (disabled) { _if_result_7 = (1); } else { _if_result_7 = (0); } _if_result_7; }); + __widget_set_disabled(handle, d); + return 0; +} + +el_val_t widget_set_hidden(el_val_t handle, el_val_t hidden) { + el_val_t h = ({ el_val_t _if_result_8 = 0; if (hidden) { _if_result_8 = (1); } else { _if_result_8 = (0); } _if_result_8; }); + __widget_set_hidden(handle, h); + return 0; +} + +el_val_t widget_add_child(el_val_t parent, el_val_t child) { + __widget_add_child(parent, child); + return 0; +} + +el_val_t widget_remove_child(el_val_t parent, el_val_t child) { + __widget_remove_child(parent, child); + return 0; +} + +el_val_t widget_destroy(el_val_t handle) { + __widget_destroy(handle); + return 0; +} + +el_val_t widget_on_click(el_val_t handle, el_val_t fn_name) { + __widget_on_click(handle, fn_name); + return 0; +} + +el_val_t widget_on_change(el_val_t handle, el_val_t fn_name) { + __widget_on_change(handle, fn_name); + return 0; +} + +el_val_t widget_on_submit(el_val_t handle, el_val_t fn_name) { + __widget_on_submit(handle, fn_name); + return 0; +} + +el_val_t hex_channel(el_val_t s, el_val_t offset) { + el_val_t hi = str_slice(s, offset, (offset + 1)); + el_val_t lo = str_slice(s, (offset + 1), (offset + 2)); + el_val_t h = hex_nibble(hi); + el_val_t l = hex_nibble(lo); + return ((h * 16) + l); + return 0; +} + +el_val_t hex_nibble(el_val_t c) { + if (str_eq(c, EL_STR("0"))) { + return 0; + } + if (str_eq(c, EL_STR("1"))) { + return 1; + } + if (str_eq(c, EL_STR("2"))) { + return 2; + } + if (str_eq(c, EL_STR("3"))) { + return 3; + } + if (str_eq(c, EL_STR("4"))) { + return 4; + } + if (str_eq(c, EL_STR("5"))) { + return 5; + } + if (str_eq(c, EL_STR("6"))) { + return 6; + } + if (str_eq(c, EL_STR("7"))) { + return 7; + } + if (str_eq(c, EL_STR("8"))) { + return 8; + } + if (str_eq(c, EL_STR("9"))) { + return 9; + } + if (str_eq(c, EL_STR("a"))) { + return 10; + } + if (str_eq(c, EL_STR("b"))) { + return 11; + } + if (str_eq(c, EL_STR("c"))) { + return 12; + } + if (str_eq(c, EL_STR("d"))) { + return 13; + } + if (str_eq(c, EL_STR("e"))) { + return 14; + } + if (str_eq(c, EL_STR("f"))) { + return 15; + } + if (str_eq(c, EL_STR("A"))) { + return 10; + } + if (str_eq(c, EL_STR("B"))) { + return 11; + } + if (str_eq(c, EL_STR("C"))) { + return 12; + } + if (str_eq(c, EL_STR("D"))) { + return 13; + } + if (str_eq(c, EL_STR("E"))) { + return 14; + } + if (str_eq(c, EL_STR("F"))) { + return 15; + } + return 0; + return 0; +} + +el_val_t color_hex_r(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_9 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_9 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_9 = (hex); } _if_result_9; }); + el_val_t v = hex_channel(s, 0); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_g(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_10 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_10 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_10 = (hex); } _if_result_10; }); + el_val_t v = hex_channel(s, 2); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_b(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_11 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_11 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_11 = (hex); } _if_result_11; }); + el_val_t v = hex_channel(s, 4); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t color_hex_a(el_val_t hex) { + el_val_t s = ({ el_val_t _if_result_12 = 0; if (str_starts_with(hex, EL_STR("#"))) { _if_result_12 = (str_slice(hex, 1, str_len(hex))); } else { _if_result_12 = (hex); } _if_result_12; }); + if (str_len(s) < 8) { + return el_from_float(1.0); + } + el_val_t v = hex_channel(s, 6); + return float_div(int_to_float(v), el_from_float(255.0)); + return 0; +} + +el_val_t widget_set_color_hex(el_val_t handle, el_val_t hex) { + widget_set_color(handle, color_hex_r(hex), color_hex_g(hex), color_hex_b(hex), color_hex_a(hex)); + return 0; +} + +el_val_t widget_set_bg_color_hex(el_val_t handle, el_val_t hex) { + widget_set_bg_color(handle, color_hex_r(hex), color_hex_g(hex), color_hex_b(hex), color_hex_a(hex)); + return 0; +} + +el_val_t style_surface(el_val_t handle) { + widget_set_bg_color_hex(handle, TOKEN_SURFACE); + widget_set_corner_radius(handle, 8); + return 0; +} + +el_val_t style_button_primary(el_val_t handle) { + widget_set_bg_color_hex(handle, TOKEN_PRIMARY); + widget_set_color_hex(handle, TOKEN_ON_PRIMARY); + widget_set_corner_radius(handle, 8); + widget_set_padding_xy(handle, 16, 8); + return 0; +} + +el_val_t style_label_body(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_ON_BG); + widget_set_font(handle, EL_STR("system"), 14, 0); + return 0; +} + +el_val_t style_label_heading(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_ON_BG); + widget_set_font(handle, EL_STR("system"), 20, 1); + return 0; +} + +el_val_t style_label_muted(el_val_t handle) { + widget_set_color_hex(handle, TOKEN_OUTLINE); + widget_set_font(handle, EL_STR("system"), 12, 0); + return 0; +} + +int main(int _argc, char** _argv) { + el_runtime_init_args(_argc, _argv); + TOKEN_PRIMARY = EL_STR("#60a5fa"); + TOKEN_ON_PRIMARY = EL_STR("#0f172a"); + TOKEN_BACKGROUND = EL_STR("#0f172a"); + TOKEN_ON_BG = EL_STR("#f8fafc"); + TOKEN_SURFACE = EL_STR("#1e293b"); + TOKEN_ON_SURFACE = EL_STR("#f8fafc"); + TOKEN_OUTLINE = EL_STR("#475569"); + TOKEN_ERROR = EL_STR("#f87171"); + return 0; +} + diff --git a/ui/examples/native-hello/build/el_native_vessel.h b/ui/examples/native-hello/build/el_native_vessel.h new file mode 100644 index 0000000..b62c288 --- /dev/null +++ b/ui/examples/native-hello/build/el_native_vessel.h @@ -0,0 +1,69 @@ +#include +#include +#include "el_runtime.h" + +el_val_t native_init(void); +el_val_t native_run_loop(void); +el_val_t manifest_read(el_val_t path); +el_val_t manifest_title(el_val_t m); +el_val_t manifest_width(el_val_t m); +el_val_t manifest_height(el_val_t m); +el_val_t manifest_min_width(el_val_t m); +el_val_t manifest_min_height(el_val_t m); +el_val_t window_create(el_val_t title, el_val_t width, el_val_t height, el_val_t min_width, el_val_t min_height); +el_val_t window_from_manifest(el_val_t manifest_path); +el_val_t window_show(el_val_t handle); +el_val_t window_set_title(el_val_t handle, el_val_t title); +el_val_t vstack(el_val_t spacing); +el_val_t vstack_tight(void); +el_val_t hstack(el_val_t spacing); +el_val_t zstack(void); +el_val_t scroll(void); +el_val_t label(el_val_t text); +el_val_t button(el_val_t label); +el_val_t text_field(el_val_t placeholder); +el_val_t text_area(el_val_t placeholder); +el_val_t image(el_val_t path_or_name); +el_val_t widget_set_text(el_val_t handle, el_val_t text); +el_val_t widget_get_text(el_val_t handle); +el_val_t widget_set_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_bg_color(el_val_t handle, el_val_t r, el_val_t g, el_val_t b, el_val_t a); +el_val_t widget_set_font(el_val_t handle, el_val_t family, el_val_t size, el_val_t bold); +el_val_t widget_set_padding(el_val_t handle, el_val_t top, el_val_t right, el_val_t bottom, el_val_t left); +el_val_t widget_set_padding_all(el_val_t handle, el_val_t p); +el_val_t widget_set_padding_xy(el_val_t handle, el_val_t px, el_val_t py); +el_val_t widget_set_width(el_val_t handle, el_val_t width); +el_val_t widget_set_height(el_val_t handle, el_val_t height); +el_val_t widget_set_flex(el_val_t handle, el_val_t flex); +el_val_t widget_set_corner_radius(el_val_t handle, el_val_t radius); +el_val_t widget_set_disabled(el_val_t handle, el_val_t disabled); +el_val_t widget_set_hidden(el_val_t handle, el_val_t hidden); +el_val_t widget_add_child(el_val_t parent, el_val_t child); +el_val_t widget_remove_child(el_val_t parent, el_val_t child); +el_val_t widget_destroy(el_val_t handle); +el_val_t widget_on_click(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_change(el_val_t handle, el_val_t fn_name); +el_val_t widget_on_submit(el_val_t handle, el_val_t fn_name); +el_val_t hex_channel(el_val_t s, el_val_t offset); +el_val_t hex_nibble(el_val_t c); +el_val_t color_hex_r(el_val_t hex); +el_val_t color_hex_g(el_val_t hex); +el_val_t color_hex_b(el_val_t hex); +el_val_t color_hex_a(el_val_t hex); +el_val_t widget_set_color_hex(el_val_t handle, el_val_t hex); +el_val_t widget_set_bg_color_hex(el_val_t handle, el_val_t hex); +el_val_t style_surface(el_val_t handle); +el_val_t style_button_primary(el_val_t handle); +el_val_t style_label_body(el_val_t handle); +el_val_t style_label_heading(el_val_t handle); +el_val_t style_label_muted(el_val_t handle); + +el_val_t TOKEN_PRIMARY; +el_val_t TOKEN_ON_PRIMARY; +el_val_t TOKEN_BACKGROUND; +el_val_t TOKEN_ON_BG; +el_val_t TOKEN_SURFACE; +el_val_t TOKEN_ON_SURFACE; +el_val_t TOKEN_OUTLINE; +el_val_t TOKEN_ERROR; + diff --git a/ui/examples/native-hello/build/el_native_vessel.o b/ui/examples/native-hello/build/el_native_vessel.o new file mode 100644 index 0000000000000000000000000000000000000000..3a45efdeddeb987e8bcf4a637692f5e8b1a8e60c GIT binary patch literal 14692 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�GitqWD}eAMe5qv{=@ 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 Y>WscHBP#%pHf2;u?`vVHiApW@zp@^`x&QzG literal 0 HcmV?d00001 diff --git a/ui/examples/native-hello/build/el_sdl2.o b/ui/examples/native-hello/build/el_sdl2.o new file mode 100644 index 0000000000000000000000000000000000000000..c485e5eb552fe1b61e30a8902ea9b4540b43cc3b GIT binary patch literal 31624 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 literal 0 HcmV?d00001 diff --git a/ui/examples/native-hello/build/el_seed.o b/ui/examples/native-hello/build/el_seed.o new file mode 100644 index 0000000000000000000000000000000000000000..7abc10279e8bcc2c092b2ed3b8a900a2223f216d GIT binary patch literal 50056 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�*zDg`>}`l{@U+=X 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

    V#CnROdjw>|K=hmQ;o^fsrFR4K{ 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 hj_W$yeXY6q1-sSk$l>qM43U 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

    iicB(>X1o|0=4QbOWVZ(*mq8A@n?{^KqKsN_ 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

    V#CnROdjw>|K=hmQ;o^fsrFR4K{ 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%0Dql(E@{_9NZebPwINLT+b(!yD+_0(P zm^6osLLOxQY%I(l;h5BRq`wO&7Y>;~*Uxo%()C+)=3y4PKC7(j3stUp?*!zOIA*iq?~S-ihSh(Xp5qr}QgdJlW)6Y;kTZ4{!B0f_9Qc;-Ut_^kPnj>3Z?x zj#yt*NBTm(>AT>~iQzOM2gQS;e6`;1N=F0V>5kTGuSK}|_R>Ga2m68DL-}s-DpGFt zAvI>K*$190>;uoT5C1XR?01E{dR|q;p@Oxd=q%q>zFAMYV{uU^PhP3fyTnn~5@FjSj;OtVxd4twb_;MNc(??|$%iW0o!~R(JCj65}s!ivzZq8iAKF8VclC;_sTFbuJnmVnE@ITVT z$($dov}8o`zd~}RGh;lft>lJrZb{2een0#>&zce-^Rk4 zv0^M&9Gm@MFqYFa7U2Y}ne@|#-~OMp?Zsa|m9@c!H2x;%4s!0ijHkg#w9}cjPSxp* z{lUz6=rMlD5WZojD){E@7JiG)4S4+0Eu7^-jz@vV)$sVPXm+*)E{V_g{R8q!pZX*B zi+tHL{yXxvr3wCTru?jN?io3-XW24v#qZnV%Nm&*Y+UeD^wfHF?`;b?qcAFtV^*!_ zG`DEYrMiU)*a`f>&7)%*?$&Z!%-_QwTzEk2H|?I#5#xm)sP>Jw9@kwUFYpoLHk!ZD zXT>()_u^6bkn%IWES|Tvb!-1g`05w>AJVw4rVmx4gX8Jr6Qg#S4qn%fS;*w>8e+RJrX4V~Dc9MM{^^?p7oF|yqD|8m)uv&rjUU;wywA8i z(V?@V-YP5avhr2fP+(WIiOU~%<EOEK@y7)9OV(8=ySfU zWX)iV-ACVJEBjvM`=*`s4IK3?So*7o*#+?*f7Zq8#0nRK^3U*ksLjTXSJ-Tx)kp7y zmI3X>UjOA-{$)2uNuJrO(V5JJX}=f7xHTVO>xaw-=ywHdo((p9E1+K^%?CHTek=7Z z*fR+2K#&bnr_p16- zT=L!f(dQFEp9?iV{E2;b&~}MnL2J#Y)nnv(kF60t;c(JCvBLFd_4j97)IVi}K4h=8 z4zYbWM{CVbBf<}56dSpXK8~UfFH6Tv2B{Lw*M` zR)u#jc>fpsD8u31=@Ge4=HRA1O>hnrBJ|6#OG{1k*<#p9#$M=7H5pBP= zALEPu!sENejn8zYYJ4{4KXH6B7~fs{F}@wt`Af>(n@8Z^4)OF)9A69Ld+P|}^Ln-J zFFd~bSEEwW3G_4^l?1Ha_@wXrvq<2cseEoaF0enRtR@GqsZ+ zV0EBVrM(?yex(ijYhUAR%TwGJc#6H{r!*h;Y0uWJJ-m$Q+|Y*Bwyza#$SqE#W>1SU zGpA*u=4m#^vtGiNd8#6hwG-!ID)U%JF|SqTv8IB4>l&q#`28{cULC$qzFK@)zYW2c zwcHSVS=SB0mo?sq_@=d1iSHnKU-4nqD!cH{McaFAKRos=JZ(9DgumOSJB}u6n&+d{ z6WP};@B5|?uF#n+TF=)Zi=vm0B_->Zo@L!dU}z1ha;+2Wd1JlS&{eb^;mig;-^1zY z-J8JwMTh^THSpJ&GxP7%Cv%C`Kh~e-Mvn_~XMzW|H>dNQtO1iXW12N1>l4e@nh}58 z(ha0p7btCOMtsPAWd1hr(AZw>c*KJyjR7BAHp%mVThH+r$ZLGE27ch<*0k$_HSM~L z@Qc^9F@E5tHSPI-27al1;g|pO@tgB!;P<27?}L6%{rUK%_Xodlt)Mv$c@=-ZDEyp# z_596v{=%Qe?X~n^c$?$lKDaNq-`EG-YTMxOy?bBueCE%m=NIT>pZXH|;-Y6dK9jVR zw(`ey2JBMdsx>b2Va}hcz&G}ECe9hp)fNLtwXbsXR5SU5E*?=JMxpuL#|g%`wY<%_ ziW5xl$ZIdSi~bZxSngmn0>kVX?K6rO0Pk1Y!=;|VqwQnBz4zG<=J%w>Y+gm3wa*@q zSFBKbBj&>s?=!m++8*qS&X`!fY>(4t({1ctVtaa8O8u=1N|z5y%VE|v0WHS_v>YAK z($nwk5$Nb&VPvgutxEc@b>a@kchNKBVyNPa-(welJ%7F{{#4ugS4r<^f9PGUTTXUA z|35=*74Q8}tcvw+yzeLZ$@$nOX~mCSOoewKus6c9#-}y8{Hw%|oiTJyo(|1ax8iQY zFu2__B5nunE8g>}aVveX25!UX{1xEl*Wg|@=P@pmCGDS%9OsI03*uZA{(lX+?F6?N z_WwRlzM70X(9f#5L-WQg@x#S^{FqOctibooPU5F--_QKBogd`95@*(395IZ6%J=cM z?Oq>S6^tYX+ST3bws-Ed3 zdpD9rjV(ireW?y3Xy$9{T_K)zjX7gFK|AhUU<73st>9K41-T2H+sWD?!_PKxug3}^6 z@^L3swRL&Bv46w0J;C9SaW+-Ht;UOf7#rT?I%U4Q-3g2&Vw~hsP~L*L(fCq#~?$#fAF)js=`ljZ4It-c#bB@o9@nTy*iy| z-(wh^5BIwMaKk_Go|pJt27|4K?JR7n%NEXYch8!UOR+gdN1kls5i6fG^bso^1>A(>d#Ccpl1rB>gv?x1_mvVtuov zFCcxgOJ73z6qjB~`qcVn>-)MT&FcGY{!9~ne~5FBGuUevjH9-nk=O66ru=~*$_Qf*ng*6=L&K4<;Gq4-R2G7XF zwu6Fa^hvr`d|i-7OliYe!SnGvUl2T>0E`QxCA??Fcr$ovD$l*2yvC+I_~Mx^%{sGq zb}ApzVhA4?d*P#w51eID+W5d&iyx)^uj?vkIix)_E36ILlTO;NrTw0Lw1?J(dxG|) zt^GaF_!o7}YZz1E)X2`$^!@tu=KejWH}Cqz>CHN8^XM0lk5iFj_}TYLUG@QmN%C?-nWmksf9#+lU2f$j{N&vP=(JF}K}IvY&M@J6j~Iu>jG+3fX==fZoVJg?|1 z!=-LUb;&mv?}gSk#XMMZAoWRm*u|URA^3$dG^B6o&2W9+P}Mhet#9(Jj~nQFRnRx- zr0-Sq4P8d;8~GWw?`x|1mR<`_@~w|+==&C1OwvIAnJxKUcc6c_o!Ks`5h>pcy{X9C$`7WK;Q`w_D@20+=W6Z{1Q)l+LNj83!OUuUJ z5U1y$KMej2WfOIOJC z1T70_{wnx0_oZPWk_Vj#sp?zduekZoT_;yfSem3P{znU9Q7C$vtU~8L>h{l_p z^!E1G(NOxoLLT&QVh#)HR@&U(QD-Fj|31naE!uzF?CoeWPVF;sW=C;_Bu_jd&+CEi zaTRZJI?#SuGiUhhenh$cHqAS+eP-;1tJ2MdYtqeYWFuCQmQB5Z-yb8lKaKUIfZbQx z_n|qV?`=l@U(l{ot@wCe|I3L#Ae4VBJZp2@3 zPKRgTmuR6qu;Vo!>P-H(;=09ewV>Y(s~-1r0ndUHwoB2j|GORe-dP7^6{AbD&-RFiHvYw&;Fk}v*?^*^?- zm3HVMzR`H@pjle{1@>6^ONFmQvAw|mmpqTcPDt(~le^M&n;#cG2gUZHZ);1w{~xhI z{J!{=mi&6x-_0SvSu+;uVxK&r^Lg8v7uE%I7R`{0i)i0_5$l1A*td6QKYbgOFK3-O zbK#sUhi=!;M6cfI>f0FOHcu$+b*7KJh15x4ux9Ng?;P?}&)Rvug69gqe?y-4P0g-Q z#yQOAccEh!)AqHlkHXlPMrm|6Ja_!!K~erH^~+jAG?Z?h&-051!E=|_X?8e1t1Os4 zzYpE*hd%{=rJHG;KjT?Esv~_$P}kSt%=TEd*+rYM?mX&hj5_BonrICse5&!CFPN;w zJg$vA>pcLTMuU&Wa$1Bgg-2N%!!I8n;T-9b3OXuA@@Ty7eah_ts11Jg_yTZrMoY0? zX#G;gt%s1kJy$rrID@`fH)VAe`wurfZSRe%dOwuTAK6^_m}_HemeDbe8mI0oF7&)q z-RAOst1s8OQ!&C`%K!Cc){i`E96WO`H;7%Nb*FD^*WR8{*<5S1Q|+R9>ZYOr?F(-D z(zN-HY??OzGxtxM|JlxI^OL=#J>UnS2mzK?cc+;}^ zo9mFIe2#MAvKziGx_#_q`S)F|)4DbO4qy{^k{k?p_^RKO8asC5F7-1d>8Gp5rGalS zJ*@Op?rbgV?rNQCFjtKPb5;tNlM|R@8Ph6oRDZ7DRbAXsGhBxBGsX2Y#ripqeztNS zO|*~ijp?j>!>Z%l-AsKc+Emg1cSGv{A9ZPdZnavos8 z^oHnt(}YU|oZh+7Ug6R^w`H%-xBFuFvKiswbgvN}Dc@{Bzz@&g-P9MpeG^jI;+auC z;eR}ivBk6TFQ`*IC(7GhlQhrgM|tu20BBWA$9x_G%@-j@Mtf+y$kCqPRej%!vb#@? z@>U1g`W&!TzWbCYul{$R3e46R=F6WO3e)6*`g^Er@a_lR>@qyhZ^2x|*d6>;yXQFg zbAf+i4F5+p;Mc_YeEOKQAAL-AeN3m1S#clR=)=noycnNDp02~L?!E2ou0iJgZT9Yw z^8J+p^S5GuoC7F5(#oD-dK&ML)m?^VrN-oZ%+es%r*|!uV|{N!R_#5oo!osOcF6mX zx*zVmy!149_&X8As4VWLI~3ShyDP1C_O76g?mFpyL_6uitnyx?V)MN`Yi^Z~vFnv6 z`{J%B`yT2ILfb*;N=$+KP5hq1FFfAR^B-~SH_h4V&bIE|Cdg*t9fyj8;|C7@uJ>vjCt`I(jhPYn!2@kF@bu+ z@uF~InWo;aHJUnFihi;oqWf;>wmTgSa6fSfzlv88s~L^o2cHy|7hm@nU&pR;bJ`f5+x4Y@-W!wpm*DDV~zpcz=TRZte3C4#6alhyta{~8PVi?38JiT^j zV!zV%I^Q@Q^Sy?TjhD1PB>&l`mY&$aH2DBs^3k^gS>937u^eo{<7 zV$|Mm0_P&_npBT*cZt6EPLjn8FnX~~eaLP;Iw5 z{>yLvvNHP~?RmETUyxaN)3v`cE581TGJ6~J`u|C0IqR(WUm~+6tH`X`aAekG6`7Sz zSIg{L#`34jZ23Oe2KL3es`gJD$h)f?clS{ z7xj74Gwpfq&|Vg4vrnwOb&qxfe7;ua^X&XXd}dnunPG3J*T?b4qHpXC&1i6ITRpqI zp%3}}BIU6+w9UVhMbFwBnh>-huGT^Mr)6)5;WXB{v&h1o7)UN1+x7mNqO8tV?ZTGm z9#}7RH5SD)ukC_I*bKXu7=xSx+QA2GWsozPy z-%Q-E=b!G0R_nrnuI@tSV&UlPD&|^USFo*rcV9B`gC&pTd09&8xjT~;^~m#ms9t!_ z&c9Eba|+Kz+YaVD2=NN`^YIg&&(uW&mOo>BlHUl<%%j{D9s1t!>bk(Nx`HMDTzwbt z^?Y9q^fiON8tN2pY1q^6=5SwL#)Via?ew0hgONcGhxygciRsM6&^9st6>*`?@_Cz~ zxZ1m;ERJ1W=Etmlt*oO=4{*fKh}sWy@4gs<2V=9m-tk#K-d<=y-j)bBK5vii?K8%e zsgC?^-qo@Q-{D=zM&^A@CD-qkkUtS{E5_DSe#f1Ej}LMlRb1W95$Pb^idk2AQwT=af9G-=R#il~!WS)8wVI9036?U#ryg2%bh z_1w*|K0J>^TiLS^Z`ltYkKXubEKiIt%lIne(yjLHS9@1Mt-JThnWU<*ZgAt0j*&`d0}mr+*e6+*B^fXpU3V-h-L>mx_CPOkTXor z^C!L5SvK3tK_B*NoKDAgIDCyJ+hduq_DkkupQ4_JrEi36b+B}APUmZN*WB8{^E5nX zpXT{53ASX9a?@wW7s=v6*O%Hp7Qp^IaB~i}&P%8q`ha80z{4)TOpjsChcU(u*~SXp z!w+=pX`OFd;e1S;d$+pbyoFtC$Y3v!hfcSCA5w>M;F+FhT5LUR?`x=4FEen*_atv7 zd+<~?wYpw}-4dNrFW>&XpL@DNCy(c$;u+7rU1GDMn7)}z3}0ibuA{nR7}MGCdn`82 z+rzh=$#r!qf=KP%pc{7Gi}pyw3isX~@I%WHL$%Vch!Ug|~9Y;5WH-L}1(__7dk8I-V!= zEe_F2-{;U8SKsW=`(QJEe=E)2RS;KibniV=opSzC`(}Z3XrY^DG)IdDlHCtMlTJsM zrR3>5mM4OL{GG|ArFly84H12p@_6xlj(C1q630^g_tE}F2Ls=3qJ7(peD*cserD;L zVM|NLsy%tgRcxbYyLHQK=?yTc2cOrf-76Nezr0kW&h9zPMYoT6P-PkB7vj`R?Pyh&!$o{o)y2N61n^VpiME2{a(3p{tu)#8n-<+&G&7L z=D>JKYfF{KFcQDu6=IK-HYt$rS23QSD~9P{`SGj^#`7X$eKq5G=uaHa)<1tdTeN=t z2jD#BVCjC2(Gz-SQrnsv@O#)F%s2Y8Zsg-nHcPIs9qk3#4$7?!=R$Twk-eu`_Rjc$ z?CPGWcz&j%k?I<6fZfD837<8;GUPLSYhsNlUOyW4Lp{gqazEm+)}zRh;zyDvy+cLx zw|SL*P^M%0xFQwIoaMzmG&Jzp+!=D2Y+N8{rDGUG<>^SAV+K7Y)wcu?U>h5C(ergcsR z+4FqRv*)FaIp8Jxe)j!N?Um^?SlSS%Qt=w4QZFE2Te9631=%r(we=RTF4sZ(C2z6Duxas)0F zazy(+;UgH1k0FdhoGfQjrLUN-0Z)8s0;c44t@D%ApWUUPOnfmPh8SS&e#?HWz0cM8 z{`zj0{Dp#(qYh;4a;>Rsj>Pw39uvJ9Q;~ghqLK1O=%Tqye#$y|H zoLs(vU)2>}jpJx1pHb zhtk`tg{$}uKS#p#Xou?wovd+-ZgelI09~`Vl`r7%cctSqeJ&I-}@IHvVqfY0T!kQ&;k{nYxRBBN_^qN+0(O z_Ve9$=|dZlu8im9oSuCiUqwDd8-0kEUY4Hq>j#%t%a)iN!4sns^}J4fGi(c$CDhM((P-|ta7(PkKas!aU!bv!@E z)6UzWO1=fYTWe(;tEO!q9nZ0**Q5ngbFAXtvPoT6abC*Xc68nPv^AaPiH1Gza{DCl z{u{i*ws&F2WbcG?V%upWIU7>X@!jf;XAW@nd_U47*_d7UFv7ob4hYtN%mMz6tLOa? z8FAx_>N}o)C-mE&`TAJLrvv$wy5(o#vf>n{>FX6D?i^UMl=gK2&^6$YXPk5WpsyPn&njP_bILMJ=N*@H*$bDl(wq0ZMZ6v!H`Z9h?uicz4ehUxf z$NLKbuUl*Eaa8fYk2&1@Txj#P{fwcAMtrj;d5=>_k88oh>0lll+cVDY%73>QE#taI zIs?wj%XO3Sj5rS=k57w_j(#KY{Z8u1X06~?_NYQ0dG_;=w-+PXtj_>L{4%+8^U?;N zH$LWNg>hfppCa{$(>N^uf=RbExV=|_rGr_$G9V8MQ~E?SMX#5cTz{P zAs&1B<98YTYsyTIY~caKX;SgK^U(>5)1V7+oQ9Z-J2Rs1vkQjKqaU;F>PK=Q+u+ZF@=b<(vi|9*JX;}q`>)tRPoD*} zwRNE6fWE8glk)R{%0vV1-Ja#weB?E{b%^M)#?J#912QSPOAZ%HR!HkCo%r*1o<&2& zk$j&a-Iv$svul_>3t^v*ZtC+5>JwVY#=PF8t$*@f=lT~8F)xF?iYj_3h9UZd`mw_K z#c!tl6}pGplFF_Drrw<|cp7WNCA^Peb*tHy)BJdp|EmvtFGE>o=9Db49_H`1(v!69 z2*#mvB-WlfP2T`AU@@bA<;`i@Bs6w?^dU6EWY3K9nC8CQq!`#<#$&aozl}wzD+A_ zgj00)=>t0-(%Pm>N2Mj_F8007-kZg<=+_I6z6s88+d8vbjhR^9)h5uNHCGRAojnNkV?}oOzR{*|dQ#R5T8+hN1jLFaI z1$SPkCJ(6p@sW4{A4lSWms3yIm*_VlE>ICCNtf>pCh-Q%e=gq8=;kkdCst?28TUzo ztLMMP9w=@6>6z-z?3ds1V&@PSw6uTD*{+4U^SB+|N-=NrEbT6)5@TOnB%g2Sb?e+aaYc)nw$LVe;kDWIt_^ri-1Mbrr}3jzxNrxO zxoc~hv$VA98+>T-UBG&AHutKzAN(EK?P4B!adr#uOI_MMle_j;(&rBHbFHbJTlwDl zR`y7?rl;^brTZDmx+YAXe->kCx?}-o`1rQN>W(+r_!&#|=ID@TpbzmFv-8aTeA_Lx zGdFAU`vm_^+CTeg=D<{df9bW^t8HvcyT41B#(urgc4>EtGnH?otfKyb$7e5g^?O|X zE2%#sT^oTFZXVG) z!;I$79iKfJ99n=E%hjmtMLY|>$?*8Iu=S~SzXurCN$XDZOEX(WW#3HQ{|1)X71ia; zU*q_OyoYrrO>fX$#C|Y;gw#MwS zg5$pNr*`kvIH~s(zrHW&U?cScT-wXHq_YPJ2XyQxe!obc+V`12nlnF>M87M6Rk;Q+`lWw9R7U$$U+nlT?SY4DUe;^Izxk74rz+36)t8 zwcqRCDTMtg9@GI3*jHokp)fb%uca9pnhmn~o<8ioQ{-nj`}-~LTj-hZpC$1bJ+G$R z$$;Qw^!+>UTL4FA!Nhy;HC{5Vyv{57epJTYOuYxd-S>ko)1zC9(_3!ky!fq|+cOg~ zGaHVR{v`VVJ;DAdI^pMs*oNzTJl|wV;}1grI(YsFw(1e~RUctbRo~g&*vVa@P0`Lx z@Zf^?MC-R56p#IL@0A^y!rHRq`5byJKhpMWxUYu}Jt16mXAOI_WoB+%_9wv4Xx~O> zN2p`tJlT91``%=ZdqX>%J*54X%v0m+oe}b@1Y2tWYom3*oM@o`zc?$#UgH`+Cz0-* zqqWLX)*VYrI)mIh8@ZTG{aJqQJ|sDZj80144bNDHE6e1=>kLX^Ryl6aOZo}MAwOPt z$^I*Ccp+nIV`<4Gd$90C_r|lcXruk&T>A3lyOV;uCZW^ir9Phfsjpb#ji0i6TP5B} zr~RJAjVq6vFWFFgXk<8ZuS>Mo`R``+sXxt|Ejs)5?Qz+o=EZ#~|54Ej`r0@*9Fm;l zmA?#6xL*mMfp-l&)jpQsT0VJS2N%H*FSnCMS4&&<3yq)BFKut)H>TmJtn9$CjCVLY zFi!Nt4$R;;o#{M}Fe>sgC@P3MV^CkL35g6`bR?^{?LV(->IG*Yx{5-Rb{F;PmJCegE}I$q_n+ELHe@>ObTG zeH}g$4`@GU1RjX)`t!VyZvHub-`f<&|MUF5=W6+VGvyQf^7!m`p-U~lZ#!zfdmSL^qkOS@Wr-y-t&;rBf^oZol0&SZ?>_npJ|ydP)yV+U9Wvz_Ezdj4r=**GbyX~`~LV~ZNJZO#_!A1#`%5EMfh?* za`4eRz9Blq@1u_Seb347+e%&M_dVBG>Gv6|XDFB7cQ?Pa{JzoT@6+$wGB%qNoWSoJ zU`+D+P9-0Gu)d^&n|a3GdtAKVXE5U^A?iF5u= zh3~_;w!XmkIg$E0>o&yqAusWLNLTwl^8JqGo#W02S{F4Qk?lJ^?pt`hQ?%wCAttw> z4}|}mO>~1;$}XOV z(~WOZ)|+k__zA!9oD!^g0@+`vbBVzjT)p#QBl7*Q`IN-f9ep#|)XRQ-A$n()HYDdv zGDqO2Q%~cN-<(TJ-pe#qT5B9=9ItJd8!|KJW>qg9`(>ry3SZ>5h`fnDO%0rXV%;*! z#drjxfw+*B{VLV2GW`D~)+c3Z*Tk7AyT9{W%C#1tj>=gNvCfJP@$Z`%4iEF8XEX25 zHox4~g2?hq7P}%}uzFb^$uB=yF$Cn%=Em2~&7L1V-!(UT4$q>KkDY8_og?`U&oUnk z?7Ozi&3^pvqxF5rx!^4b;cT0mWgTk$Y-Ego6_&j;H~U8S+y}lF_=RcsqSd=PTaz(pkA5Tg1j@GMrOsfHtK4*`}z0H3fWAUX+T<;B&IS zV0~_Hv3mzI0v<{E)2x7&=h5TKTkbc^$(7W*YP7=7V z4&|H5w?K1~HE1bWU*X^F>YfXCu)e>8bw2m8Gu-{|@Nod{S!Y<=clhsX>sj}}!*cF@ zZ}2f@m9zH0A}s$9_5IpksdxF*?1SVrg?THcWjeRphYKFrZx^iO!8xH z%0SK(+qLx+@)g_qaBk&%Cik+m-GE0YW7?SqH- zz6pG_-(9{pGQGrH2K|=C^1@ip5zbCt!nVh|w#d-S$Gf>#^GrYR#8Zv;Vzq@1^5dAR zlXJG>r~Ek4^aSd_%Xp4vJ*K>-FpqaTC@#OypU>uf4F%`>O7?VyQgfKMdBXik+KV6R z7umue3D2Jd`^o8GPb(ekn(z|boZ~Ba+x@huzygQobdOnkA!+*1-1X~EMC(^*jgsPB z_QD4nmYK)=hz*;$tz+@I)YCdsW5~IE5D$}aPb5B_hgOSwfur zQVa46-FG2E++J`v6`*}Y9l_s0p6IUUjihZJ*Y|nATRIa#r{U&Z>8ttPz!QvW+Snah z@;|Auj%KW*JMxt@FVCYD_q@m4x%gb-h!yv|v44z(xU9{c=qKMZaDKkzS~8p|+dI3T z{?(TTA9#Yl-dWMWQKBhz(ADQ=&X|||17n5$cCMqk-D9-*tZN4WCib>Q*{^f9Ui6S0 z_s&Y$o$|H7K)#+(zUuUm|L@fMo!ejdiTXgt?{~0NPiqg+U+3h)@r3@?OtphX*2N#O&qlXv!S|gGXX$fDx6hA2w`H`s*tIj;2u_o<@!x%j6EHR z#ycK>#@N|fG#*TA&tf$1Url909!YkqWo}=zJOaEX@TWD?X^f#x__F4R*BkNvp{M(6 zsF!hdWp7m{R~N5`?xUU6Yn+!|fZnzU&K%&(;qFN){;msaP;|Cq@%J<~($eqeTv~0O zb?Ha>6`i!_R!B$L&!1?Zesio_Wlx=-mFRS+16NpoT63Jq`z77ot6_Yg zd-Ps5H)nerBtJ&{lD{H9=XVAVeGhE7uX8MQgqQ5}ER!eh$oukd^ABT=^?EmU`>v8)J+NgdPxEzQ7znSqyw>Fh{uf!y^ z-9_6K@=0d1FU!1Pe8y(0zVII9V-3J4lCSr_d>5FR(jDJxI0E}N+x(8TYVX@-w9Ww5 ze~QnPpGy72j<`Fam1h#;zOMAK3-yJrs;`K)23PZ);4=5=E~fmOfneMpXWYC8%k}`} z3u&yp`*nbK{jFUwHr}`6{a7)M$ebTv|7+a4#K>b_c=;^9pUhrhHJmk^vp^1;4WAn2 z3t983T=cg4#5zlf-dla--PXVj@fj59Wk#_Z)~UUIo$B*gt1cJ`4>z7Uj5&eB`go>4 z`%?qAHLi{JNUO)SV_b~)j1V5{?>`mZn%BheSX-K%3CGXg`M_@Yqx&v<;E!JuCUwMP zX!Zm=u7ztgjU^-RMGmaJc&PU9`5q@D@0N_z7;~{upPmsD-{b#&p6wKHr1@D4P zSDrcY>r&aFvR-Q~+S0tn*+%)XV+|H-^I1{$SKx&2yO=%Z_Tkq$L2R;9eU9UuscAdw zyT5(5xjv=i-VR34=Q2GzI|7at(-V%w>lp7+Vx2le#hohb0`uO$DB37)l=~R8#D`G4 zU$im%Mm^aHe7q%=M|;yPy))>kvTS=Bq*!F3KAtm@JZLX^yo4FIUn}bbG^tUq?&e!PqXTi6}^!y|-xUwB< z&fK1AZwa6CL5xoI2P*7da}j%}JCtTC7^CNdw^NFbn4PCgc0T9quZ`{Yx(N;AqC>F9 zFJ%_IF59rZX>AiSwi}pxXm>6A`z7so-}qW=elvEdxrzE2>PZ%d>)XpmL4G_iw6@tK zTLoO%rzKan@-wC3>B%wA0`X-?G~sQwhs z&>chR=ADOm-Hh*A3P+8x@DOtF(6;8x<54o-NZ&N~8eM@Wx@H_*KP9-T|1stU|4vT& z$uvY+-`ADnEBk7KMoE7UN}t_*Pue8;4}iymz(tXmACV zrFoyKaIy43q&Zj5dOhFhVkziRveqh+ujkD8hT~)xcOxUFm&l0DOG(}&2Rb*Vvr~nK zTAHitdHq#?`%_2t3^&1+t^s=yy5?n6@}oIIHvB!mte&%j_?BYm=&8jRS|fMYUiw$h zoSMpFBjRuIQfJt;1^O=A{yuQh+Tt}%|1?iNgFWWm)emZJy=y&o8azdhoSR!?-JV`r zNn5Sqw}7k4<)`R=wWEKcuSbP;8#|KdNgI07hTg(U`Hhj^AAzTtzYA=wo<9|}w}j;{ zQ{VfCDj%Re&)VncWlmw;yJhAR^Rf>!7R~jK-yg5dGKa?gl#hd3y>HLU-s$RX^7Y2Y z^^OVQ^_J`XT~$5*o+pF%U-Pn0J9r=U^|ZEtKI21p2cMAOcek(S@UuJW&_;8g*)H0` z*XBfqL`TUG^k#p@)~b>n@#7bJs%58qS2&D64W=_YWpn*^9pZBjTA%5xp}hykd?{iH z_P&iD0QWhAJ+1WZx_BRWhm#4DIqml*YtN;nTag`m&&^e-o!_X#CrKaa{H#mysp56y z)9ammrN6H9rLynNcRFHz?v+dCXW(;-@7u&tB1KjP{@^1lK@uiK_-$34vc@~{= zf(MOq^lSH1-Lvnz)!ACL@p7=2wqd*POFtcMX8Yv_-W|2CcJFkyy5lroxbe96KPPQ8 zFQ^T^L!W;?y@y9TUzSSBz!}-grH^p5x}?+qjLm|NkB!aQqwhZU`}McMqK^7dIsNGS zkIOyHT)A+suCu_6KgRVE-Z|j#L6>ZA9XO(6;U@Ge71?(v?fJds_od|0mpB?9QHp8B zGjI}mI9^#j#w%XPhHE{qwBUWfXw0~2m+L&-^13=N##ar-d_$B!D#Vv^qn&WoyId$Y z+-?YPQyuXin7=eTdvRIrJYKF2-}12i3_Bk{+F+fiwZW04CADN=FFr={ZU%>Y+TotA z!o95ucgibpr`-B$3vgE*lU;{9&qHY%*U@=qPgA80)|?pkW59iD&!q0MOiwc1maZl8 z%(^D!Xp7I!9U50({76r7a(GeFe=WV4TctOn6PjHV==5Re^o8h8*$=m8`Qct(RgOQ9 zoI}yG{P-HWdPr5DyZH0=5W3+!TG48`La-9?HIhUST+S)UrTQZPKFG&dHLo! zw~2bdi}9Km>nP6^I(kl&Kh2NX><;yL7gE327xUsxXuy3CjJj#~4GR-OBm>)A9lxeyt!7a9B zizI(N=XWzFp5*CoJ|wZj5SC(zMg!uHx%7lmuIHle%wh4Gena{K=Hn%$52T4jAL`%$ zv*6bJzWfuEZ%Fz%AKo8XI?m*ubmt+Zt*wW|GSIm=k%3YEdtu@Y`DTNdUlYD7&+O$P zrQc|*?m3}nGUvtZ6MDjfjV|tJZOo332aof>YrNCN^AbENb@9BiEWUCux_EAtF7jNV zi#%88BF`1N$a94*@?4>dJXh!<&lS4JbA>K~pXuWGDqUnej1Rfq(*?iuyF9cpl<9oZ zM)>(K<>!i@^<=g3J zzAMkAV>~YaPn8LW6V&f*uHV~+>6d)1koidXS`OP%uiM2jNi%=xsA)sE<+3R!GUi&s(1ys zSbBC@_Y3rAyaWH8q5;odhVDEx;Fs!YjR23fPmJ?527S9XgdzAtXfS;rG$3v?A`MhN z5)D*75)Hz*6u1}-6wC4NY#f0G5BoU2S(tJz6 zbYuv(IkXM<{uLw=C@C|>2{8Clh{=dHKvAx?t#TK+=Z z!ZxF-VbGB<|2q@Cv7nK}>Kc!I@s+EY<{ z7ESBKAoj_c_K?CR-s|Y$jRW36Bfxvp3E3-&>nsi7QQyWvywTu2gg$N3nJ~9U^AP;? zXWYKhl3(G{Hb!_WT>IKMV-<|?Zy2Ls+MGpv<9^Px4xa7o@!80P@WtO?PAS`C#=V;| z#UwTV>|nkL=e;}q*=6b&Pk?7<9KdOZdk=&9GrGO?gzP`6&of=0XVND)s?Yv#4gmk% zl&Q}|mZl?1(~$*qtk2Ca30&f0p8+o4)R<^>@I8mrAr|*Z>Kx?jAX7u?5Qh^@gpa1ot39~U+3=qoPY7}nU~3je#B2ND@`k~ zFLf&M)>Cy)=2GrWTvk#{@e_ZGPm)G{$?qahG*Ap~GIPJ`*8f6rxcHsjim?)J%Z6vc zc)trV+Y~Wd?i-Ab28yG>cSiXPzRuns{ZaTxKK6=pXW~Km?0uv5g0{E#v-j(C_P!sS zbbfIMzpAfu{1xZ_s`?DiJOA_bw3)u|^UnK%Cm7H!j_G=TAdP-tU;R8$&~vc%uxEJP zi_F-0TW~j7L>>-@H+GKC=fQvWHcdtp1Gjp}7I%);>-{=O9`RM;@+K$B>zlrTAI-I={O|+jQx|q&s z4ukK%fL@-SWts)&cw2S8E7P?%UHPv0O`V)^;vDyy;B3O>oY%5_lyv#*K?COk1mFBh zd>-#RYpzJj+HTG z3YjWa((u758rH;_z1?APrfgW8DH|5&V83{uIA2$(2f7&4m;32i@78!d7G{I1gv->bEt6N4cHF-KUmp4WRnS%W5a5zQ3cu z!(dUi(Ur+|=$qtr4@>R9eY-0wob2pAIBO5m+TN0C-{|a!D{t4kRg?xF(}Nhl*gklh zsPXx~uv}+{^sF;+vcuZ%EY6DGW1Nv)OR;x_4PM~-v{(^-Q9pIoaBn|Tm+!JMq z&6PdI=6HLo`vXatYyf3m*DA_n11R&lR#7HTW%qO;(va@`dgQI%jWb!bCHt>9um-zsm+2g>Lp|559G#{d~ ztHXBmmijP%ceK@HX&W)vq;8Ow%p;+OWlp>_}gQ7 z?o({2^7kaGH$%@#|1LN~(phyD{VDYw>yF;bv@y*Y0Ajg0FSpvS^?UuuS+14uzSD=k zMPp-~tu;`*2cE>sXkR4X-Mz&I8c$hJ0oQ9|3V;`xsr>bN68P*{#>E*qm?cSknc{k`p z^zuH<7X@&WetX&Q^h)9~>O(TaIx?9%WXFqTxF*}cV*L}_aBxXzqq^Xb&_>UUXSvfO zAJ-3M%j8n_x<2~iMpw_%<}&dYJu$bXfG{MR%5_hZx?)k~h{6X{cD$PN>gn#j)&jy!YxtRpAH6gsyLGLtrED(rbkX`$^{r0b)a;jQ)HyJ$Gi7S_@fvl~ z)Y*!BiLSX;-lvHDv2~*EhB$o$pFLMN`mVi~H4O95-rIun+ntp$gu-aW3R(t!PFG(aDqmW;%&+EYV zu8U8|zD{r%Qy=x02q)<)=^{9Y2iRA`N$@^OUBQ;GQH{e#=>Hyv!vZ(%lY!T8ApKi? zzFh@u-tRlGkl2LibF%8uH}8tzoeuO1o|^OR*Ue+{b8KGC2m0;ukXw^a)$#L-WLx+C z`tS>MADap>Y_l(wyt)E>FLgNEnM?!5vu`1*uFL;7bV+?4;>Kk( zI)%Ed)8p?7lw~WF>+gRE+{U)>9j!4{@v-umMxA5Sdj@|DY=5TFucc-l9P`HeP&rrk zNAM|Ahwq9nruf@ycQH@mlleQ;!q3_;zuQ_3{ezz;h57Qmt9=8;W4?iJE8n0mIrk+$ zZd>yTcP}Qy$=8?vD7cBQg&(PN4BLFHOwYjV@N=S`^E`*;&#-n4pLeF(BYeJN7?Wh6 zQ9OZ13*A{~-H{9P*SPy4Gph0n?oN=_5Mlj=srU|zzZsLmI zbsTu<9#f+`%eb%dkbWOSzI4u1_F3n|AMcCLIWDFT$;RY*%_3 z?GR4I-XC=gZ(^mw&Cj&o-9fxbdW^nFpY)Dn|J}V`tzkYO&&KQK zIMun_(NM7CHB$MkC~F%#XYBeduNAb80G~vDnP)225tQ|Me=RK2xG7_fFk4!nEEC43 zYK>8KB+JC#6iZMXH(7JF98PTI1w{ z_4L5U7`yE6*NF{tx7X?#URpo9v&)*l`ewHbw67$-J~p-yx?jk<+f9yS+l!P-w)`DK z%^zp+o)ev=F4A7_q-t8Zdw$b)zE8ou48?4Wwwf0-MqnxCBV6qnT!h!B9bU;DLzR1* z#ahqXENdrvvaUCqMVY~$#CsN;4<_HQ2wuW-qn~Gir}K~JJ35@D{R_=M=vu+g@uZ8^ zZ^NF|uAON27PX=5mTKCu{#)(&tacio8_&CZUCl+xXU_W;;}))hc>=%5Sb{jD%8pan zCj5d4;3s<1K9j0@`9r=h@*?tnfV_KK5b|1fP5o&7)CW)csV_g^80iOj#h8cj-8t~? zBkwHDod?mM%IRCQOZ)-y*3womwN4WqEqx+sWY*1lHSb7I5{{#FNBUyk4{#B&i35h5 z<@a-)<}k$${8$v%(7Ms?pLDVoMd!`WrH=a5e0K!%Y61B8Je#HK;JsFJ0(8t{uj4Th zn*yfId4lO;92P^-IEL7Sp2~d+!Tr}2v2DrVcNTeWs<*!O>~eCVJo(OzBt{u6t2%_qZyZEpOk|BS1Dfv?ZJI7s zSmqo4!%y{%>0qy=YTeV9M*h?2oU`j{Z+rmfp8;tSo>?vW_IA{)^-)%oS_Id_xYt?gb|=ki;Zb|-cW80;BO%-!_D zeEHEEoxP9^QatBiUj{E$yLrR_^}2dtoIY%~-L*^FAagb^NS;aC7?3Ubo%US`Xf^Xd=hHDC`n!{> zz3;^MbqD)lWcB^_>|c`7O{e(yzOw~@ig@`KRw=Ed&;8%q%{od8YmQJ=U& zM_7)3bVd05eeT5btanf@B=(^3DXn;e(r+MLAjY8d>q%#b6DY0wm}^}6wWJribQ9^E zODl%a=+d)D!&|eb#BVvj0bj<)`oE}(FCiT*HXYc36{(mv)$$`b#^29pbXJCbboQgb zIWggCw(zo;cU~8?HlQxw){O6{Z}RJZJ@c(Mi=`ravV(h(En83QLl$qKo@DU?CyTl( zTcnM?!D)Auk!_v5Lyns-l+M?Xn}@4t;bpYX>2>wEHCI?3{mNfAI?$(LG)I7!?5nMhm_Oue=-kpP>|6Dw$;U@o*g@jk8RPm|0*L-|)4Pi&t8U-DJp{LlZFaQ-s*4*gzYfO8z1 z*^AG*7aH=1AB+FIE#3Bm!B;V!`-T~h_m}ZEw)nNoTG7zOgz-OY?P7Zv!_l>~GJdN) zamj-BnY9*`|Ed`EyM+hx+@fzuRlI9FejlpoS9y=Y?j!%h3xf|l#-I2qndwDFS>GqR zsAT2+iy8Yy7?SJfD@p}{XZVuTI-Tzmek2%<7nF(TJtb>KG@M3;` z!t}&+g!jHU8mUZU`~$f8@?m`(>Lz8?K2BIx?c-RV%pcxw2y7d8#eRe8$bSJ}^KpC| z=GX1s#|i4_dxRce%~1=Tk4=oL?59%4c;euipX%XO`>9oR%}@1pg@f1S00;9~gJ=2P zo}SP*-j9$^9NGd8Q+|%~Jq<_Avo}P|yKmUm+{HYU<2`tbXqQQS=*YsVsF`<+-2eh8rQ)$u7pY4 zFAt3^j-b9I!)JrvSLv%7&nE-EoEDA)-q@ZBe(b^n;CON!ZQR7+cht}+;>L+= zs^0%$@BQPfuB!e2_u(*d1|&ozLgdFt#u>>=1PFx2&{U#UDq@JJKvtqu#;tC7t=rJp zZOpoH(&DC>GhsE1nP^!|S%6bFEG@*!etzx@Se}7?0Cwxl)oDJ@*Lv^$KKp&<3~2Xr zACK=J-#^adyx;rB+H0-7*4k^Y{o}28DEoO`EU$dmmDZp&XNpEM=c%=OsQPM0iziWE zZLR#_$*dj4KD_o((bfZkmy@5maI)>u)VuudRNjYY+q~6qWNgmiV-~$la_^)q%)52M z)<(|NVG}>7eeKx1wdlhud*kOe+WnSGU!wDHKAkpiap`T8e>v&e8~?grarXypL}Q~q z<{B0Qjc8wRp5c26t<5Kwx|=hFH&eHrz4Q5+*jBdke6QB%sjHZ~^6IIF3?J0`a?ecC zsV94VFE(9m^v=QenXh}IN8X&FtiD$v`~CF~Ve_%qy}TF6w|K|=$kwWR-MjpjHfVU0 zXpsG%)zG(E&%m4%(C~?XhKHMhI|Dc~*bDB)9+e+MI`f5X(X?5GvD6(E)Yn=!^8HE0 z_Fa7Xuwnq#H_U^%i{=|)KiM4I&Shmbw0YfCyny4LpM%hE zeE?7X@XLYCPx148qCFgDgXW{-)H68fv%y79TZUKQLz?&}c}eb5!d9+zxS4NuCpwI- zMLrg(cl0aq)AWu`!K3BYj^5FwCU5t^C8162xjk;bhPEDXRKGJfsNUz~tIrogb1%u>U;uV%*tb0hPP8|ic5B>6P?$`Y61oJMz+?=m3o@0U#QELnNNrHhx+DYch@H;*YD zzJEO6v(ZVpXsqJ-!98i!;*`jr^t_jLjMv!wUefBZ0h0fR-F(ep9;0lptU@p8(XGt!gyyhSC_!lmzcqlfca!y}u zjpB<=h86!y{2SS6#vE^_Q+cw}pw0ms2 z@fCJCyu&`~3i}h@F#edm@qN6`>HaX<*)Dw;CmO>!U@&j(I(B?targElo~`|uu?>bs zn~(h4F9tTZ@Y8(cPqb;gq|T7M4D%%SAuq!`$$iL6@=|hNjh8ATSNDh=#kN#udD34Nl0yl$_bVV-Cp&$n%D$QShU7V^{Rol{Ywr_#8fJliy`y0haQs?%+zxZH6WlrhFyzl_-ua1V(GNF=^D*nSPKK@*F2uY2 zzS~`XtV4!+<1y0qkZ8}v3mFIGPgz`pJiq5+Qxo=f6y+%+J1-wZWd?p8%g9?@8|o*m z514$?UsZX|ylzOIlQ$&K$s3aARpyFe-=}zv4%Q`mV~!yofe$WtDfu98NL5qwy`r!4+X z2WLZ4HUfFQsq72+Hk)bh1Fp?!v}tz$Hizr@z`^&`U4Sz-#^ZKxm3933|8_QhPOz4T zyuB6K^KGr8oj19*Y%P!cE8TlldYjX68;jX6HpF%{**j>wy9hYvJ6Jl;qjBdM+V(t= zKN2C||45qOQ<5vkaSTQS^r)wJ~+9+qrDwRr4nJRI!a-;2|3caOF0hY@|) z%D)%ZQg?^7zIS5uVXOaMSpGh2?X|X;^bkCdY*qW2KP{VwZ_=W1+3`2Ak-UHFiGj@z z@UwUw@ArQ&)`9f+9mL}rHP1etH74$qX8iTvsg|C0Ge6Tg>{i9>rbm6do&+wwyym@4 zza7}D`B8hy;NAH$cq;}T@^jihVOu+E>~ zC;WM44BS-r@3RZ{=pERTrDM#cS>rdKu*iJ4cUC;7IMv<%B^-K5w|R%=c#Aocv6wR! z=*|*1Zd<#IM;p_n2dM=6Tk7jdPbVsq&1mDnCx;8Aq2O(qep8pN}K53Lp`-`T#(lWK3^4X^zWlT z6McaW!k^>}dt<~mcAED7;$LDPXyga94|3$~y_1?c>qr0KHp!oGRKJAh&iilJfev%0 z{D5HZYTwCvM*56G?lH!XL;ie(t*fmdUUV_^u7K_f_`jf`&)TD%;`#A=Ezk9|FTNE& zK`i7G$Yv(~ev6)SZDYn-`uW!9hgDB~+}${=(9@VHbcl|NfjQ`RYT|R^}nK_^Pv7O zZsFFZ?lkLdQR3*cX}|)A0{AQQsN0QQu2PM}0HLvKMkZd&nl@BV0v154)D- z`;9%>Y=_P^aIRs~joW7zN*}-`VC$}?uh#PGUKRC?fiCTP?A|}DkeSxBcR%!v0$1k4 zW}61~4_j!olfRNW7rS~&1K&Qyvtrv=?g#O8jgzY$wTXQibl*ke2=?nvV!!Sw^zjJx zQI_jlKdKMK>z3M;E)Oxr6CEx?gL$#-8I5=)uyKy$3R_M-rXG zw#cp|@#)4Oj)P5V%TDFKy4cs#dXdIajnl~*uD30;x7&SFMz+9Y{+)9Q?}Epze(k`O zog+Q+W!^uha4luJgEAgp;XflR`>{EN)scyd~c+L?%^NY1$)796{@}_T9mFTx{BVjr4_fQhP+v6+a$%pHOwhe-B&V znhw_yDv84AXYT6C!wUGnmz@$G!k&wn_E4Fozx-mb{p>&7%2OEuo7{o`_c%a5zS2*y>P z_LCsZpZO3hFQdL)eWN4UW6+2lk}QYi9DmZ~0>7Mo4Cj(9!Jd!H)xVENkD1?#f1|Ol z<6Y5Xr)T&+d^7(w{NKWVE&p5iXAJE4D*t2o@8aK$g*{PpsBY(+!fW6e=a{#%R<=Di zG1_pg_mv#%c3|g$-45(Lu-k#12e#Je^1yBfb{^R6z|I5P;J#>XVO9lP=BvvkKZ?iB z08rfi!05#L9W&8=OZ-JaO}*ypjcCR+bV%SYgwHpcxa z9Xe_sI~h#(@pF}hq1)(@J)~`|iO8;2;!u%)@PC;9KZ76Y0rDfCyQe}Iyll%pX{}54 z#nyYUiyBW&P8b)s11uib9sfnA#+C!{0UKv~4Qs!kHR#%oi0{W%qkB;K?>*1*KYgC% zA9$YS-S=;wGyXNt6aN3tpPwNYi9PnVAVStEHn#QJZ>}>CP(f0PPOSk(um!37}vh?^H0*C!K z4_do2k7>^J`Wv3Vzb?4{lX=sVj31geb^J3n7kfGJalZe_FYwnBzJzn0yHtLL{ErLq z*Dt_dAD+@{DSQidGa;zWrp%?fmm89$pZx4V*bKGNGneWP+VHc|Kg^uXh@qIi6KJ8j$fcj8UalBn=o z@szoa<~U*9Q#HntruCT&aKs9LHUM@qYNqeUY|~kWHWUTMx}zBiQYHrXq4`dxAK3q_Je0&Js-TmFaK8w2;ZLCK<``EzdzwpzXMQ3tFgZSXTaVXu8TLeD=TP5Nc)lgJA4XY*CbO^*06 zxZ8Z&h_&Q)nkG~nLw}xw|nh)8$4EgYD>KJq(-4t-Lx zIoIl6SsG`uLyQMmkSyKo`bT!QvW~?PlulWbA7~v)etz>l^>agC2V;cvS<-6xQ#9mTw&vpAutvv(Y^frmC)Y~a9{rp}w0ho1L=QMcPY&CFdA-;HP4MB_Jh zk2M0L9i6d0@H`o;L%}(OO54^oWxMXZ(|JzGtLC=7mqv%`Z+cB9I=guMXfj$e z8%8-iBYcbdCC|hJY`^ETA6k}s@q_<}3^K>(JVb~KGM~bQcf$qQ|Mtk(7Hd3ehev`% zi~<08Bhtrpfxnq5b5~hs zR|jSI)_gM7GBzdmE~s7YNl3nR*Eo5*#zf?9yW%bNwAahpWicwvw|>oX1~@}}=1a^) zNmp90)-x$r&z+R~{xO%i^D?a)Tf8QU*OImZOY?Tgug)5KSirTteSAx}oKM@9PrPPp z;~m?*&UR$)*nU)YyY2H@%B#nVJ&_gi*qODGicmc(vaM_sq-x()uz%j4b-uEo!C>eQFd0C zGHRc=U1vE)qw&R^V{M$eU4Gm??8$!Yh0c%|9n3LI<_qT-tOL#l^kSFIHmsdu_D(*4 zXvRP2+}gO>>|KxFZxW}w^`Y8>$vzFG*W#bbub>~+I{(MuU?1I{nDV_Yl$YH5xFq(k zGpDsjaMkxxWFJ1JK7`kbO|}23dD+s1&MtwI((*Of7aQ~K+2Yfdjx1?BvS;bPY`M{# z+3-=17xm316h2b6355|cf8c{`g7HjkgQuP={Tr|I8D!#`P|xY}IB>|>7kj-luX+7<4tuAc1R+6vgL-$8$TU%dPk z@eP?apQ*bq_L<~g_8{Y|lc6ucy&EC#$~2l^-%Y!1$iWii;B?wVKh3|lJBYwf`YE1- zK5R-CEAZ+;FQaVJ-Xs46Zq(P@s#yF`Sza%h)rrCEQauSAnZNAdiBh;EI0r zGj|)XZy=yGsOSCZ9@-au+Pl}}=<{brWfKD3tdPq9ZiTO@wLaU2;b8x&0`~Fn&HPdL zAv=4g!&~h|HS`m>-zR>j^dRuF8Ux#tjqk$qbnK+9osN#^$!ON~hhsPkU7K24w>b^A z!>=*P?<x-Q(msH}I#uQReE;UF+(eu6~xCQ5|TLu1gOdapl#{YFAeCA%hPcvQ72a zBH1VGs`aUS*)SI9`OBF2b?K4pmf0}3Cq!xVe}DAzwO8VQ_1Ezqy=d(e?3B*A_Ahbm zs$8YL80gaYKa$wWFvT#FaZC0^F+9bjx@W*|*H0VZT~wY6?9qPEQ+_nC`Gx$tXGVP& z(MFN-c8|w&{uz7a$Luc0VPb!Ybm4{p3-215B-Jbj$X_vmd)O>pSLs|DkvI zr+4k6k}Mp}msl>?=tBPu=WV4A6} z9r$zSC)FR!wSRka~5B!dCjGzORzz?KmW_)xeWJ*EkX_!HS|5AcIPvG z&*3*qcI491`Lb0W_gU};{3Xw)zS5sBxU_^XsI>T;lYaVIM$>%c zgZC#LU25CIx4p37;YifT>{YW?-Gd5l$Pm!$mx6~O`Z4H79jljwp7;Xc<(Juo#3-AxAu7R1ryyHjNhIc zqZx&d09!h3G;()*kEih#XvCj;F8KWuFl?>(xz*WrW6R45*EpI)*YTdN0zCJ&NpykF z7LSkHvo-{;nP*HcEC;5>LchOlh_crHxvu@+tGswxca*koj`zzA0ngf==i5GdS!?@r z*EZu_+;$uH!1*{1^*>6S#>zTFMn^E}M)<#PbNx0~K>%Jqys zmfjki&j3evJDcqG!WX9}YTx#mRJTc1_oLKR?A4!RlF!jAIl}IL$m`$p7!TGUPa5Y; z9@+0blUnMeh4_Dtok_?Cty1F1~{8JI61uv4?Tdk73Q; zb}(kSHG!Ke$FkWW?u=Qz(5*cptmpN$$!4b6MaHvAyhnp~(bZQOJCDVC z>ksi&n8$bX{O`b#-y8cYwl=fL?==?hk+tQbIZwIRU%8m|-ep?{vNf^K(p*08pJNZM zuN%joCgHDW9i4B*;UDUoyY^jno++E`%l2u)K|WTFdFxW@kCh7PjOWip}$%O5B7ypzO`!I*S55pa}u}?lf z@X2RH{W{D4H~5kGR`RitnfHiC#5^U#@{5JH&O;>qto5Ul+_^lTE+6Pq_)-2_(=NRp znbFg;J@mlW8n(yZ)0Sgw z&G>o1bHI6{hbcc3n6lX^nDk=~9=F4*9k)zcVD!1N>I?r9&i|&qLI=#wApeP;I-8T| zDet{LUp}Y$TJs9h&vE@NxSCfe=4^UO`8M$dJv|?sRbTCxo+2CE*^}H)D4ms_;YXRC zna@+v&KW^Fo?gQjS``OB0BrMVf$e=-Pix47E3j=IPt`YjK>g4D0DCYdrt4PmcntWC zNainzP760sedSl{R4P zF>Ju{SV#Ypwx5p;xMzd20ZvD?_8!Vtr49Ig0ROqzfKOGx*I6nL|L?T{O&+Gx>lasp zse6T;T{$M6Z<|_JUjb9|hIY<9$&RG(_4WnZvSZ88_C>lU8}lB?!vE05{DYIHquH33 zga7~3#+($i<7xhTY|LwhurbXKmu<`q;`ei~F{3Cq$i{S~)py3Ra>`g=B#N}=TwPV5MQjz#p9*Y6i*2jNhFQGDy^ki2`3XJaYmWZmZN;1Y^AB$OD0>S= zv9EBw?K2;Bu=o+5_wa2gU$Z&tB=%+B+kWPq;IQ==1cR@7_i4Ii3#a zZS>Do=w*%{^QD5`MN#K+@mqQ#U#Egjoxw9Yl{XZf=$7`-h|Ug2r`b~0;|A?B&6d}_ zneQG-&pRd~D|Rn|-)FWhYMNSD0Dg1%z1`$2-h07a_H)&S%GuSeFH`)&<|ftkv9vbu9Tz$^H}V9qu}1`&QPn@oTiMz9HAf zo)~ziv(d?#InUI!HFf4Co$`Y$pJy8fX3}5tv0w9vhds1$8T(vMW)5WUVT|S`?ssB7 zWb63{7BzHMTR$((apx~t>(`uN(E9ln)|%1bV87_L8(XIqK6f4aMUmTXcp~14C!d5T zzvef-lAr8d*h)HO{oXmN^Apnc@YA_^@jrtehw%P|yxsgnvtsFCKZ~zx+}v~{xD2@_ zpGBt732$>|m&&$M-%_@{C*)acbE(zBgm@O=KLC7FZ(ENVjqRY1vEw@v$Fr>ciJ`hOv`-b~Fkx$k{df2mpKV@r&$(qL` z;?U3^+PHPjMlA zZUcQXHR>D(jfNY3$PfKmk#MD-?s4zCv+#zpIajt;XWy`uxm_q zWZ>s1cBr$?@+E0M?g#v-B68e<99y5@%joW2uRD@GW24qUeR>b+O@XheJ+^+G-~03?KQ$)j`ZkVqV0~*Kd$ptqH}02r z{2jU8pZUsh=1V>(d!FL`O6Vv0qPqeI!y(P!D9`$7FdU2P8?Rj1(L@6>)=XW-2Bh{f)J*s zxry@sLHUGc^fI;gi2Uye9`@1h3vjyE?#~L)hQ?vHuXU5{$>rVj9eRu|`ZXF4o&2Zf zogwaSEXQtmKi2M#TKNvMs|H^@y~Mp6eA*6aO5Kf)Ug^Gro#6j(!XLXLd9S0tGW6Gh z|FUt_bl&KKKKY)=&R*Fa!IwO0?wX&dd0n~gufn>d%N`|lo&7Q1tL|jz=0A0IJ=8OY zXE%7hxeA^;!?wU*xFu~J1JC=yx_=LzVgEo^#2C0pII6F_Y)$m>gusWakRczpm`44X zuD*C~vPpg8GkpuM%*I)IorfFF%Ln^P+M^lv&AVfo&G(jXB>QSHF42z+bTiJ($6ncf zG5SUKyy>oZ{Bn)oMprs65RBIq-y}@t{WH_^ew)`jIgaP^Q?&8e{Qg|6#;I^Uh`AYQ z#TibA{Mg64$>0pl)sQjIdbFg>pIco6h*Lv5UBlpeHqTbnaq&nxG z>U<)lac;h0Qt&>Rd+eqJ?{#sVt-z@f?#-MjW8PA)xgKM1yJ8j0UAHQxfFBKf?qOBj z!tLj0Zr?$kkN0Sw+Fvv-41%LNoK>l5=;vPEXKg=NZtav@^uEveyS98A@tT^0pS>&v ze=BihjsN}(tH0av_s&NV44q^3WyD*(3$Hy6FYN;}J`d_6c&|QUzAxR&%SP~Q{X<;L z_TO9EQ%c_!Eb)N863?0AnICF&i&w7PS6w;iX74_CWzSSUi?)Yv(-~Qvmu=fJ?6FV2 zExOfkni#`d@5aF-jedK?w;>s!9BX==4o~}zl;Jt6fx8FBv!DHv?K$eSxjGsvlX*9J zdbaX2DW9c$_LA*evn#fP_xb~rrS90!CvERKi88Tl=1vRla#h-7aG4R~V(sv3ux9|f z`6%`3s5d>R$FtR&E*ehS-aUO-LH1nyQ9S4pcqALUwQKqIqW1Y{9%At>-WBI+g70KqQTikM67_9p@hzHMPA@8bKKKy->YX3!nfI}k=54>$x%F)AV7t_g?b8&z zpq-xx-kibh{7C7uXlD-X%!=FTaPpuuKb~ogSkKlD_FnC1oY%W#RquM%8M#50bh>w)yhr3-)aO}t$V=#dVa z&Y^?qbNue|{#M1lnU`q2F*Wzle1$P2+22aO&8;L1-I`wTXgsu@YJ6!ATSMdI;?s!Dj4Hhw^{%8SvXGh^Pj%w)7O-ctbD5K0-oAgz0{VSHZoJ+nzPvpa{+7<%0Vtzir&=1@}&0z2GZzRxh}x zarJ^PU%Yz3-B+z%(DAO-3l#g?%KnUEc7*L6EM|}E$k))X*_w`gt^S913>W|zFz+?=*XX;|Ir=!+4?`eBR^07 zqdM{n_0OKgv+)`J8a<|OC~R@((-pJ)uI?y!*}THWYqhWSveKc41~wnyr~4;eTyT$% z|6=D3u5tZ+gUYjCr2mFDu*cTlNm!n9aE49Ro(CV*$$zHS>~H96`}xBM@aK}bLpD9nwz)EPx;RGi5&QMX{2}cr z{w6eiO>`kMiZRH3KL`!-%ZjpTetyBT*WulYee2Ah)8TH}Bw&2r!70mXFsBWCQNdOm zROO1)-O5>Uof8)yA98D`?WE~^xXmx^{P;B`owJw=KO)DkuuN{Oe2%H5956jx`9i`m z-p?AIeF=QoqwuQ5`HouOdINB2H$MLlf5JPhQuw>Q$q8=Y9G`y&e|S4w_#YR?q*X?9 zHls5rcOmdK2leTqP5#MwN~fHs%hMUQzt4@89l&1d`9~b?Jf082>xSzOo)ulc^(u$nVc1U4Hz-PX7dFBWLyYQ`g$(UGs@0tgS1)_Zz{N zyn6YfzWOI~%{8Srx;(y>)%m!qZ)1w&h%rTXbqjtQxc!iPkN+EmKV$E{UDCl|p7I=J zOM2&FX->Boc;W%ynA|Ko(2Xp}&#>698;^2|r;Ld@=To*grl~VMR|@p50tdz1%pR2W z+vfSQ4T7OF3?7%s!h?PutGOaPEQ)Xbo(rBOlO513oPC{fssp}vk}jJ<+#!K?yx|(R zQ(ZQ+zLw)|9Q-`(Ck@6k+baZ)cRoXVjI$aq*SYTs#$)W8rm%MYZT4P#yN6#it!|3; z__wn^?G$j34P6?PC+6ADx?ewi-LG+1WyznXb!@>S9?Xw?enI|R;jJ~$aQ~T&6|X+C z@RxP*o?g|b-)yg1)w0XaEF7e)hqV%3T`WGr$>v6X${k+M0ZUalhN6! zO>dquhwqw$KYKM-m;NihGrnIwqWnR>4x)F~F#Cs{@U|&YZpqZB;Vo0>kAAI3rt(_i zJo6pNH(8-?RoBjGIbZXM{S`K+s~k7F#bfp6OiK!_@QoDVfsw%6|m^E|;$M zV%r^zm4jui?_1Cr?OZ$M0mCDRJyj{Yjj~~wnmv^~i`Ur9cJDXATb|9v zVzcay5S^EnUF{+7M9B>Hvxv>CET?_RN;kW&SPwE=?w8QUm-i(My8DK4NprLj-<9vG zJqo=0m{?YG$Emg-MDwrR{*DBmbL{in?fopuY5dV0IsdSeyWIJ4hhB$h*p$GHVV!Am zb4BTK=^wU2?fDpu?y1q-`=`o7f1&$pqDS*P7rQyAaaMYMvUHrWO5-3lxNje6+S_{T z)f(?8&pZC2?I%^7M|@Y=jK>Y$UgK~x_}DC!7cT!ta~sux@4^WOX7khhj3)TKs)D96 z&x14gp)J9V`1^*0f3g;AI41tKo#FdGwDWU*(mk6)Ql>@x(0DBQiOSy!^Zh=``E>Z~ z2IEocf8W8dwI*Q5mWn?08!-)?y<0f2I9m7+%irvLGWpLY%hZuSpS$Lo1w+bmV86s8AG4M%lK;Pt`qLT9iL0g0 zTXzkPbLftgEnVC_fsIGDO$Yh6v!u*lO_wB}iQMySa_`m}Nk5eP=~Vl^kMWND$)Xt< zQViu}C&!X6{~d#a-VY`JD)@edF20C|>er*roaoR=AOa|$=fgPW)If}7w8KgZ8_zc}xs2FY+32Puzv zL&*&EEqm{P#>#L!JC3ujFXHU$#I5~}$I0j1R`xlkloSK(nS*@KN4{tAKTC3**5?D? z8QA~O*{zy59@4$ zpNU>7ry=u^4ZM^?i)bV>`RCftok9`};_E zE`5Js^E5|;?cst?Kj%zPf-AiGx^Sgz-qrKvba!D`?#oV2j8EW@;rkHc``;L+i_^ht z26Gc+y9fM5(=hTS-!-#D? zi}NNY2Zq-o+QxQDjzhVUUG%Y{LvO*BApiY0tmJ&trQDNooIBqnTULWia)vr3lbo-I zx3bZu!}!kds;_$s^s8^u@vA*LbMqK&sIN4pz8`)&pE;595T8dVoBGy76(8W;;(2q&C$ZW z%AH1!<7>>XhK1|g{#DJX6@!S=v1j$=yDmbS1Sg?OJQrQS{JnV2J}z*XYcxZn<-te) zUX|twAKc;@6@4O~WBM`Z$oX$fgHuGm+=Bc!1>c$;MSbCybAE6_Zv~#!Xj9D5<^kZL z{6TTBDt!{lQ@z8znmoa~m|uxJWj1)fBayLdG8;bb{Kh1Wv%7xXGD+jitY5bb`z)bJ zZ8$mP-WQ{(YM&f~9<7TFr60s-()8?#2IKkL^7`tr@U(BA52-I@+gfd|B-$R7PbNPe zzb5Z(2RfJN4A0Wzc4w1ptfQZ00~B+(RdyYDw7HLyWt;Dj_i5#!)2+eSsJ_s>dwloy z;8~jYX#6D2`}CT79TM-cacTP$+{@T}Y`UH+J$|0*=~*M3!Aa?|ebwl)GSIcg^UKks z@x|<==mCGTx6otX&c#*^Nl%524>d1I`Um()|L`34Pe_ks2mOidi`jp^LGR>GW3g}n+$Z@0O*xmn@ zb@4gYw>5XFq-_*%Y8@@N%P1IWf1fTxOjsqrFcFoUxNn%nzk(^{NbFoi?->tzqK**)nKv}jzAOq!od+uGx-es~@IU}X)T_*|FWnW^&dLHcL? z!28#~70Z#@iN~kF->K+_=Mdj8`TU|_I=G8OGwmcY&9n5f=dMceyyWrK z>O*K${t`XYXI}nfPjc=)8s*E+)4s8@Dc6v7XVIbE@#bI)@*y8kKB37zW%Ye=^@Yj| z1D^Qyw>L32ke-w7=FfHx%6LWkdWWOp7;5)zyua0@{lDbj8-aPDgUh_T8GcsWOgExouEdDuq#lO72&j&i3UAtLyBTEOx&tFj|^1OscK5t&YOU=!EpLibL z<9SG(1HfaRpW@-k4o}a+NxYADX;pdn9BpQ$U8n)(z&B&rmR-=CFOfmBYh@Xf{p_Rc z)2{rhDR1K&amwX1P5@Ir zujJ=u^$WI1ZJ2$;2Gp~TiEek^#%IQ z{2=Mm_u+@h1O1|Y^WRQhqW)67DECQVpYikjzGT5vee9LVS7kqJ0nQx` zmV61r6}iayxCVAE@8cRKe+>)o2Pb$L$2OcDM0U&cslM|^HRfu}zKJ%P2jLvVd9oT) z%HIqN=L?lM{}XWD>0r$SXYp^E`U+aDub?;Q`wIN7@jf=?q)Y0ji1=pHvFH#S^%HOv zlaqgVh589ziY9N@WSgE?OFxn3b=7PV@2?$1bFe1RJa}FX{+sGHol!vluyyP&;oL)N zo>;-Bl+Oiz$k^Ac4~08+yv5JS*~emIAnB5YazCSIzJJ9ZaGplJD6{xy%(LdH+z#p{ z{uKGXZ{_di;d49rD%aYzdV6Z`b|dp~;@g~IU6`xk9%$DOy}YYlJ@X&w(rD+uDBb#v zIgrNJWWJAQw^sH&XQEUd|J~r5jGRH* z1p2swwqy2d>-@qihN3Irh3D@F(N)PAGQA;UkH&N2-OCmh>V|3~;GN*sBkQ6eB|DOJ z$?x-}?Sw^z>~n2bdQ;i1*P9{RP0vYftsP(fN%`!o&Bz~bPu3!NW=?aBbe;4r_^35P z^Vu0U<8Khg{*YfoSvSh9KTzJrFx_i}toVLcU7x-9Ahjvyw%%t z#z}9_bth5|S=;61N%qg#Zpm-h4zWJdDUFM}-CRsQuwb9-VEghKD-1R`uXV6r0z8cc zzw8Xg0*%?EX)IX2X7E^G{)&8DY|*am<#o(@=0Bd#2_Kx@)w-d_Lu0?$UFY+NCc|0d zEPlimY_ZxHa;_fefwu|q`dqLdpki$CWAIw}l;S@;^0FY_sV&8M6I>WK{5(D8XL_B} z{1A9B3%T*@xV-^vqYql-GkExdJt!{MthMx7V(-K3`=XlnXdN+@UDnT$pZGfp;>Rha z*(S@J!C+n6FAJKkJ7r2?w}Yc`IAk-Pbcoxd9A}k zYZ-0SKPXwlPtclF&il8Nvp!*u+|uFY^`>6xXl|kSnf%t%CBMj1H?rG9o?m0UYc(*X zTjq!R^?PWO-$VLXPZzR$y`xL(F}*Vke*BHaVC{vwsgX_UOa5u+IO<0pMwUDAD|l1x z^K)5mad+TW$S?8}`(V@`B*%e#&{v1b>xH@>{1o;SNfy9Id>3Buy$D{EeL!vVAD_)5 z-S`Myq{V)fXsi*PNepL`Vm^<3V_@?S`Dy=#=7d`B>1CZQ+#4zW)LY%!g9rTj9sHE+ zJ?d-?xl<-@!w#Lyl1=zBE z{Wmof?-bY*VG*n|J+jW`%$L81IV1DXymd0OHLfO3TJ^t7KeJzi7Nbu8d~n zO8w$}Q`sZy2hwd!pf7Cfp>Gb57T)3S;rvNzSjwwFyFuG9xo-+&d z>!#d>*@g4qNi_DR+s4!XWB8@|s4*QE4C7I4}%GTIQR1**W>0%+GiF zm?rg-Jo%pFbqC{rk|+O@yeP=a0aHFf0iWLqX$Ab7>1;2~%yPNwVZog7%ygS%q8x_9CGyUb} zfo^|WqxOFuPky$LYtVQ2bapq|6n*T>!q+LUdw_%keva8JJsVwao+sb!T$Qsi(_*%V z{n;t=A%LfT(U0>E%X%84!WSvuIzRBBFj%Vm>x%L~Kg&wr;HyBNbXwn)-vaONYL>6Ex^xpT^Ixbj{@C+Yp6Mfd zzDMckOX73z%otNcTi~!Mw{bpupW<&H$_`td`&8e29oPRnGwvmIzD*t8g|EgztMfoj zpV9UOqs{91cb#8N>dsq8d#qSF73%sy?ZL^@h)E` zRnP6W`8__xA7;dRm{fPq~2*zL~Xr=Vx@JZ!`6oUYxX`umJf= zk3GS>C+L?C5qFVZJjlQJp3B7Re)WtGBTo#zGwysS_T(-bM!Nj|%dd!TJwQFhGO_uUAbwq3Y&e}MESXV@6W@U9Q7N% zlN)R=b*;Cy!fg%>EAa&)8+h9`)UH4v-?u^oIUpH z#0T{68pHkpK4ZW3W@?-E_Frz_*W4C8HoQ;empY%s+rSKM8Nc~%=PQsE*}ZA}3!eOt zk<_W>zQSJQ;#~SmFrr#wSIF1zfUVe^=v27|d#g|`-4#B6qZ{O>m*3;C6PZwTlZy4=KAEk@etG+9fhnJGE zl&=!>?`HQM71LMxLHzUfR?l8fNgH&g?(wflZUR1rJ{-0_@l)M+(FzRB7rsY5`K5}v z%P)N=d@_H6_FSz0;8w?L>A&Q|bejAJkySs3w>_YwiRLpM&zvu4Ylz}uy3a#@uWSR= zwqhFF{%ElKHRoLC&*JF3N<;OtJH=cy4<{jgc8BuS&hE5~h~^PpIW2 z@$+YQTHKjCwcTFPc5By^2U|JM5$&8dC3ooFWtq$j>`C1e`F6X9NAnchmLJd()WgT8 zjn&UaJJ(Ff{q0YCb%xj4qE4Q*vr!(GX38~JFIRMPd*PhpjELWxqxbx%VgeJ{SZ@6z z+Bv_hGgT%#=mmDz&ig3c%5c6UWorW6Bi^cSaPED*li!hiKRm};e($KJ&U)^bl%YX9{X@>Ow{q`94f<_&HKJR(SF&xnr*+KLoX-8wU(?jc9>bm~yd(5{vnl`5gZStIIllLO_J%PCa+M&naNmE7xr$Lm{+%&bv8ZQ}599x7 z5ohM<=Zdl1r&W&SmL81d_Fk9v1AN+$b-_WjSh>@x)FrKY-Plh^>N;ORaO5l0s}J!X zHCNe6n)wR;d0vo?uVDGu5c3t9Da+WGbH0M%g}$tSrx)?-zu|nob>PpAm(Sz1k7~d# z8tmtXdZ@c!in{9#Jv-I$T;rVDAEb+%dDq$YP!}J%EV}hV)g#^OVtn5V{^oq?Ai6lm z>7aBJAD_EQ(8#%lFx7#F>8f!|U-kJr1Nx&ZWy^eg8XM=9?aIe>q*Q_3zSU^<$+jyR<<%rSwpj^3zGq`w;)2 zd>0YvinZXo+zOvh_!WIZO^mRG?@&NHx?Z+gZv0DpU{5}EN zzm~Q&2EPrycKh*^cW7YERd*RpEv*%P6Q~OhG=HnF6P((E&Hg)K$|J4l+i~xHo}su} zj(Jis8|y=n@lUqH=5z2+{&J@GhR5H6PI;etX?ZTTNAajk20JZZoVnN&E8{uGxA_;} zJWi4N0a*TBI1U4@pJS{E%1dW`*?gVDOL&9NLH@6S*3;>aYbQrZ|6U4D)SuY!PVsES z@0s)Ky+-mIpVuOW(Wy9u?v2f1GwL(Z2Hn%B*zCFEnbR_kr_#71PUke0mZO~JNO^Zx z9DQZ{Hyc81B6UwqD7V=-HtzdbeP7wnr_l%V{}*ICLf$o}nNHu)KNg1-PyRmHF2@az z2Um^DJJ88+53SZLye{r@F=x#KO&4jmp8n=6B;TcuV~X(A{QPQV+JPg_hws= z;Wf@?=aq3U4i4foBI-@ zmRzA1?asbQ=GD(d@bY=l;SW518aVh^b!FM#P&WSNWjO|_7<9rb-=}H|UDUmN;+1%m zcQG}^O%)sJXuhJP@8#T$?ept7>PzLTFBNCy9#ZXjf)C~RslNm5RDZ7wu{x>o~n*+2Z7_wOwA4DD`qo;eDDZ7;+ zk9;3b#J-nW+*(<&N_yZmd@ouTN{_kG86#`%T# zVKu~Yrj*2^SBOWfMcDcew#WMU^2LR(-z(l}?I>QK@bd59{aR1EKS%FuRV%vuCF<&a z2g$$Y{7;2#FfX+>)-5jFp*Dya8BBPXYJ+##j8MnC9aG%s-_!=S#M)?HRr*ob26xF> z8!d|qHyRy$`%iS#Rs}FoFa0sGq7B}Q7X)q8%_`{K+PDBcr*6**XIC$7=({Lv zBes)=SWPaBP#fr}+R&WzguT>5=gb~sI~&7#;|w?AM&t2eHp zZ(dk$lB@S-zFVSt*hp)Sx#*uCqaL==>M4pAl+~+m=>MJSF+N$n z=?#4o!+JAZz3!;+W9pgxp3z`+hn>NFNMYHTuI!65h41>ZGhNx)#PP$jvs~FVnL?*8 zi@g?3!{%{bUv}HcipE%E{!sL>OyMiOEaQijUC6p=Say*syFF9bLRsCRV050{(Enx8 zIp5K_sG;va!+MQYZ%>pztMDn+TkPsBY3To)>MeHl8XNi^3+tWZ+B;!b;UgZma~y6r zHFf?+SoVC^27bZ&ecAKlvbm4PWAHa!d5ul|H@uN^`Im5yW6hv%Vre|_YdTunc!%N# z$ewKXIyZhy)mXv1WU=?D%>C!ix#dXxe?4`iPHP4EwYEO#^DAQ(macV5w}xqRE&4l$ z&Cj2~`W$1Dm6;v4nWKNL%)(f2QgeZD9`5kgz7F}p9@huJ^_L~t{`k8mU(=ZB`hT5^ zaeSFF>PwAr^5v2-&c-H<8N_|boAySH>G8LXCi`b>?#cdnbVJ_+|2(##?b43J!{8YV1w!AaQuv{1m^_&}Ke@D)QN{cye}mPMo6wH?Cu@zZx*!aXV2gK%G-VAVsTa2*-!SI)tMUTn)q)>Zx8 z+!klR?#Rzv8m!4{uB3VEd%&0Z!7^f^+6zC|a94SFYxjh(wdO4k`(f)VJ zxO$y}W6%2Lh`v9<-cI5iol67Q>d!Ajm*Nk?W2=7#_80v#v~2Ou(Avtgod=Ph2#unh zZ$!GeE&VCl$@8=)edKr|epnyDo1MTi94T*o1b_AJ@Q%~QMSWkO-xQ;X&isRkJG$VYnMh- z;Mes)lgCYYv2R@VUH!hH-~W|8ufw(f(d`Qg^&LIeUb+30iS>CkdK&w8(kYYuV1IJU z@#Q$?f8+DV<6E#V8NG(?h43!MAD#>UrQj#I_xtn}Q;_cRy%l#}YNXDAcaHRXH;@bI zqhzD_rL(rR`0yo=N2h`*)JMh(5! z-tQC0d)Wlf-F{vxoWnRP?b*41(%*#cNmn#ZXwGFc#&W$d=hr59H(v=pt)#q{YuPE` zC)|^I;tg=LcU9-Uj4xdk=en|k@3NaaNOmQIjIR=>u(O zTouj};i>1h%EUG;xL1!@vHGY7zV8$L%vH4pXz&7?ajlDo36_m9#Ggc$=&Q6B^1qPd ze#gVZp)A|D$+^E`#@)N8`oL5SJfu@R6&&`k_uD>?71*rcykNVFi5Wi95%BSFh^rOU zk42^9PpEy_cIzM4mM`P!G`>N17v=b#j`Kf*^%Uea-0!*mFY?`F*U?pYXF3c2)OX^a z>^w63HG>b0>zwSbqz_g}b|g2WHGUHFA6p)qy(}qaWPT1~vizb27e}}L2W^^Pkikv@ z|4Vnf_Zr@5V~c;UrG5G?u|GWL!aWzfizjYAzAe}LiqyV^f`>EO{P%4U`wu?m)5en4 zd}ZlLkIQ)a8CAiw3ZIGX>bgfBJ&v;|+_}vqu{@K_a?<+{A@{^&%=}EqhXVRvg z7MZ-s-sLZe*G%&8PyLq%H^EG;g#>p0Z~p~+=r*~aj>VK1i=>0BbuCxjWG|f3!@Y3y zRZ(LC{h_^ZyXX(WiAFnkDu;oIC}yr(x9iy9@f<@-G3i|AWQ-N>ZL=otR#KiMJiGm%mF+~UVTWLjQM5#@At}BGUFm|# zdcapb;c2+SyLFBhVzwvAr~15$sY+(od0e2=d@j=VlJ9-4zdD{I@YK)pCEx|$L^HoX z?PrDe6=?rV{EZCp+n?u~YJA6D8sB4oSg}p5o8$uDLgP=e9s{jfbD0Z1+UutAcDJ*s zWN`En-1-PiP02ECFj>bn#^@7ar7 z8gWja_E*wciCt_CP&)qvkABc_iIz!YuCXf=@X=ho+3lHFITn zexlulE*R*8`4h~mQ!q%^TF8e(7?pGHIa-Uqywu{_Zsoa+JD=(}qy1j$C3-o(p%Y!Q zxyvggH`VG)TU59aH;lX~{6u#*KFdqB zK98L;f70DqEE&|iUj0RTCX3Q{?RAk)D_t@_h<=p*N^UG&z7hFbk+lQJjrqRFSt3vL zo9R3KtaYPx>hqKx#Ag9d_4xtscMBKU32;elKJT^`O1W}8g1tN=0y(5i=-Y1No8aEJ z{pmfi-dD3jx>H*EwO0BF9ji?*SC+2e-|Ls^#r|&j+c16(|IE|O;ZG>f;h(+kJFMAc zIET#Hu;ww3Y3|;Je|MO2$vxg?udXngBsoA94-=zXu6CBnZegqRoO5`~w$bm-MxYb$ ztUYC~rj!sl3{h(^D~x8ok5`(3{QKB~rDI=|UPro*Em->a zIDHc7YmSR!cCEl^!*=dFPQ07I{_qv0my8h4UihrlVV=>JUGZ$h_xIYG-)R4>S@H~L zY;E(UrBU$WJickqx0~2c{YLUuVuvr~JAb2Y7ryKVVQ=1wQf{7PKCYwkcK33vLa_NIl8|7S?OU1&l(G)gRygzn9V8!iU;@Tfy(!EM? zS}fOF(T93))A!^gH~Nn<#}&4kT$}`+%S-LSxcDxmL-z(JH`m$w%F^5U_wuvhILXgR z$lW-Tcj-^qPHu^KF^>EbWBi(zB{Yt7XR_OyFNVg8Q)5`2@lyS_tTYl_EgsAmxD_1l zru=&1q4{fO8qQmJ_wi!wn~D2ZvQ6G(bq09Ijr1zZ-uKJ&q~GHl>&J(54ixqU=@RhmN*2Us9TnJ?LJY>F*{@_TiT`yswJi zrzmelhQ0I`Ju6%@%x`5Me81WG6W;f&USfOM>+)~n`yy+n^sHK9<$6}c|J@g7kcA7a z?~4~?Vjl~<7$>*q{oQ64FQE+MC+VDJwKFuYckDY)gK;d>gDl=IgmDK97vYZ5~^u)erg=kqyaq5m|Z%^7aOP1Lr%rI^W5av->`t zZ@wmZ;zQB-M#cluB6!e!an!H9q1rdBXY2Ee(KTe${8!3_eH)$a;t7H&Txj3o`Fyv! zcuuA-YPfOlzg|F}HX^r+=?B3Xi(D;2CK{LYEu9^Y(*yHkynE*_={v9pSn$>E>$o%O zJmALq;$qS>nZp)GC*62(XG3Rkx{sp+TRH=bl+MhdtvSLkhzIK(xyOIAIRo)}e8O0V z?!_1Co)y>8ocM0N&*Xj968s1kKbu*W{diu34^MuYucT2>+qNFvHP0qk`7k zhoF^oqxE)Zo#f8lQ&)7#W~_Dm`3bO%zcvS`;K6k8pHBIZ2YL^9@LkCiX|f~YMTWdj z(syf|oIL3BNq?(&G8LFpm$1h;=84G`?;*YSst$bVReFFc=kiV(m_MwO(JZ!u6DXs8 zmko4rj)WHSQvErOcE?dxc>1`8-bG9Bp3p(LHPF%IV;z)Lzlv7TxRSh9*FPHji{PcZ z8;$3*ZE_8s+#NQdIR90eW6V|F`$WT3Xc*;a7zGU`qhOBWT|eA;N2MvVEhA*``gV6ivF;3(!yd&wRTWM`W8co0KYyr-8u z#g3Eby5RXV`c(PQnpgaoaiB7OTm*mPEj*Q<-QBpP@B8pWd>0?3&zhsXo3!p{!1EdC z4}9APNtbW?P5n2oEN!>_?GWF0z2v9* z?P=P6nmPAH<#@v)=^1IlajMqV{}h*zotdQfgS`KV`GFrl4mKpdllESk?Id5eGw1vh z8<$DbxU6%t*d5csX^tN@9s?&e9<$zd{BX0`W>>}=Yu+)s{5&^zxyfr7C!a@ z$NNBkaP5S7@`2P3rUUT9`U(EsM?ZyqGa4TAEx^9we)@V?IUaY3^~GhSi>)tKmM*gQ zm8A>peR=8i{C9)L`TYAnxW5S(ne~;P*W4{8QCoZ=BiDAEPJFz*ASI z`-i~zVfpN3%07}Op7xMmd}`SJ?VtI~k(U0y+Wcgg_C@jSyzcKu{XO4r=y4tn!S`rG?Dwid7-{y2D^ufO%asLxX$Ia&nA z^Q%ZbqX#;EEPB4>==oNfp40srwBV5^+|BM};`b2Oh%w4|MLB~FOvM8RzTsehBMsZf z2#xRLRq{pOH%ru^G! zq_@{r+E(&Yw)JlM<8HMX`09E`FTJm>Z||v$Z0&bh5AFU^Tt~XQQ}0`N|59LUx2SGB zPo3fAkbKXNGyJ-m`hc=N{q0V#tS$VeWZVn)Hfl^1F64U|dDP2@(j^~m&DF+5((;Uj z$#Y%IC+k;uVLXI)++RCk;7-TGJJbC-@}wX}AUPpF)pxfO@81j$ZU-LySG&@x-|HB&kB|N8fvK6!fk~N8l~?{oaINF~@pY7Ga(=qX*f$HpGOddW zZxx)-m#3W37nXbfqQd1txux>?DR;d15SF`eQDIq7Zk;RVY4iWx;O}vKZHOZ@Xm4zi z4}Px<;MrV*G8&_kGT=5ZC}X%$#_rkh?SR)ygEEE}WjsFqzc^`0C-bgO^ltq<-ab3} zHk{8`2E56@iD`B+Nq&A|MIRzxCYQ+L709L840NxyCXQ48n_%6H%zXqoyP5tC#{CuK z$tSx+|M+AV+dJdGy)Q3az<>8M4SlcIKl*n*|H=5zoSg6Z#=dxSS_ckzI|9sJ^1?ai ztKp}O(WIyBDes}4B;)l58J|DcP@ebvwLI@R>(PdgkDTzF56vhV)+OKJXE~-v>{8 zygI}|eCZ`Wj9Z&sb}$F!6U#K5D(j7o@U`(js0Ym@-)<7~9!nq4j`bJ)Az2W9_6{$< zLjNImdy6-?yc=S?WScwOzFotG^pVh_`GoeUc2Cb1hVlMF`lm=9@D3NRaxkuP>w(ur zo$G2`d_;JY?qLA`X6$o+&vgy`l6%`*v_9&*(c9Rgl+XF{S4W*~zCWs!CnnspKK6-< z+P6e`qyK8+CbVVG>v;xGd%n*00LS+jI(Ukudz@{q?$iBVU3l=*^WXurc^=pvNMEj^ zevjkZZt7T@G4BfEf17OlYRALX<$m~q^KEs0X=FR&*(&;U6?Sw~)Q9~$6n%G5;a@*b z`UvT)i_6je0boe}4$h4FOdhUD?_c}I5!U!dxbp?08u~gz*y9}RpD!w02kZkg8~A2U ztk1o`P3D#G_}$+F&KL)09Q&a{IFlS4&Np1);Y_Fk2U&QN;7o9ECb91%gfrd2X*#QL zzK1il3Y^gm{TB+(R0n5zLtk?UXNH6Gld}p79UNQdoB==8X8~=)7;D}g)}7_*7SAf2 z9@d>TxUOVdaw^+U`%`4kol{)n;I%fdD)rEZ|MJE1+G>%uO)rswCS*bDs-ut-*~?n} zW7|g9`^r*{y)Q3i`Io)S=zo7h-@v*2Lq|XV-fl|Hv{#Jv)Pn9gdiJ`9+IMDG|7@Vj z9wqHbva`Ok!37(jy(Zej#vC+RW0eoXIgn@P$gZ-FB&vs2==6S$Ph(FnJYY?BZp+@K zyS{p4>F)0x@oO#06JFg}<{;eR)UEG(^F8rg@ke{t)feM9(~F2fjUsOhdOV8!mbFvb zk9YS&k+)T}jv#+TV5^@~jLNl5J<$>KXZ5rFH-!6@(%+FNq9@TA4gL1bbLbcTI?M7X zIAj{u@J=4@`bK%`E-CiCK?C2shL7l&_KO)`v%F`K8|R1i@{GLf^?7C+NULqSdGEt_ zwH{IWNN?+W%&jk8w-Wzseq!Y}?Y(K^UDeAoj#-S3@<~jeXX^)e%-HI_!x_*%D&C_# z^-tIrhjY7&k;`uTz0RV=pUz02OlfenObY_(6quYB~#8{EIt+8zphknYo^-r zWnWZR_%UU@Zy7Pa6+ZGo4L&&KE9seAS9qur{(qO@YyOqca$#NJ8%HTCy|Q*ZPo62m zQ9AoAkmvH5iJ^3Tx8E0m-V;AsNZ%T-y^b%&=d!r%IQbdqdW~WqSC&p=uf$H*FP1(! zPM=D;?=MRqAE!?w9lp*LZqoIP_MW0I-N23Uy|T1Xe*N3(3NN6nWUDwP>TKXHyi|Tu zUE#PepZo7p`FGV7{>EOBq`tfVPWI2>KT=otOPF6%QUA%h!XLwY?!imJ|8rg8cVWK! zUX+8sr><#g;s1pBE}oyXfBdP1pN093he>|^)WVO*r++t8epd+_d?I_2I+L=OpIYeh zu+YDBY zPg2J4&{?ox|GMG9zP147p1S1=3qSWTvz$4r1{3}KaR`%gMqAd=#y&Up#CNv1y6p4n z%)4jFzu6Xa-_}zCJxJBzeAPZhl8-TDk0dJ}wUaIz57>fkY6RnlvG_jR$U|2$M(k4r#Da%Am497sXIHYptB$Me;FHz-wGf1)E$3z;YYj=EOzsO z#mslv*Oct{^KnAbbJ}<0WAwnoS*6KRWlyT1pYy@-FV_~AO|x4ca>GuNYk z%(ff7@a!aqZ%$(mc6NaFtZ$gZtR2&|?0E9`q0~BW^d!DT2CVLx z^!ZGS7eAo--Hps`N#B9q>3pu<_npI9GG*%Uxxb}4Ggy1&eKXI+8ORU$=8J2*I0reP zPCI#|cS=6w(P(^$p6&_)|Jrj<4%kL!%~m9by*;^~ElI2)w)&HiAAr1!}9*9hX6L~V2V=G|tUYrrYRJ@yagNZElAV(hzVIG=ZSm|L-cQEmf zQ+V>Oedj4Wc{iBTfjPCI@7fUNNiQzE+QY<78J^g`6inXzy`(Mbcil5G!NEk=WS=e( z4Ek4R{fgKNeE5E|YvY_<8xxsb(;b_fPwd3L9lCMpiwp044fYLtC7C%D7<})jbN?9Z z7ik8st_;uFuR}N9_~ODfLA{fz)jO?9z1=S^tP1KKSFIkg2#muHsC-vTaT48Ze??APBv#Zqm`DumOLA_sBt2eJoy}2(bOb_b)s9L>+Rq8dpq%c0H zx3fyU=S^tG5I@hFQ8*aX`*gK>AFopH zvoi|63F@^_Px7WQVg@pBG+X;q>h<4n5q9=MzI)~EY;d=5%7^1yR-9F8n$P7T)wc_!!+9kjFgRy-&3|rcVAc7t_wq$FUuEB_b|g6U6($PIPqT4SG>OE1dUR{-X==PML-ow@E zomQpZzvl}l1oggEtseW8j_Th%nJ@62P-ov)l{%`yxMYyN;`h!d91iMzmU_}5>8tu* z_k*_UJ3HT&j}`k_-Z$!{Uh3}OM&08!4xi{GzRkovZkz|w+3xr*kBW1M;T((k*e&cA z(w*$+?zXz6GYj?bBR)f5csPkO7QtPS@U*@r=HCH-4wf|WRAIIX{w3m>Z_&-orO=^^JG(lwRZTN7EPZ>0-9#-VaLyQVW{wx1SVco;ZtuDGp^J0G{h13Pz? z5r1tCxvh?S8t?b%$W)Tf-HKoK>9s*R_aT1Kr;iTOxx=v4r(6Fy_}n{qn@=Afl;^I% zTYdUO`2lepqnOO!;&=3R;W{68rwn6M-!ORBgpJev5W{cRSg7>azjydE)<$J|b-#T~ z@18pD0Zizv3(~pgFQNCeAf0>s5_;={bnfZlp=@`rr-k|cdk9rxmGAzd-EBKLCU*`Juy;U2v8e8Z6# zrOl1Q^iPL%xTjw8Fu_p#N#C%L{L8lFWp|O=ypxf(S4l>hdprGN!j{&>`=SkXZv8IQ z59!7qU0K1NjK1h!Kd1A1>i#c#?;mG%Rqg+unZv-DK?EdJKxD>AIm4)^q(W*8PUbLV z6sS}PNJN473$@J58ia1B{or`*mzAMr4r7+Lw3u67ps_+T1FUYAd1nCa%uJf-&1Sln z_&i_hz4!a<_n9AH_kKR#f4+a5$Jy`wW9_xqUTf{O*Z%eH(%ek&<;*1Vv!JJWoX2}X z&wr?_i}y0W=4ihk44yGvf*erpS1zw$3r;NalLMJ|@v+R4ru_IsTARoEb2U-fOepgz z=jt+<=ldzW!_2*$&1)}4AFB-O$@5da`T4A+l6M_6YoCkXWiI-Y^xedp%#Td<{&p6A z7~(sL^D_VEmyr39p^ir8(VgC>sC@Z3z?)MC`J+AbPXb5q*T@Dy=6?tc@}x7rwR(x) zQFV1`jzKz#r$1f(9aS4jbKmjt$b1~%T$7VoArOHT_ z+6f;aT&KS#UT&jdH-x$-COCSEeVw+{ItPHO;O zo~`ZB(db!a@$q{VmPTAW{>gSz9^C~rET#9UqxUKZTU&;acN*g+`7|bSpM$+u(JFkV zg5T7_y+F;Hdu$`Uq)z*%>|UT+^66fn(fli~$I0HS0G9t&pNH>NJgj!P{Mm8T9^r@wO>SOOiYw3{aZmGM0CAzJVu0pO}rEfdQXELYvEPNVwssAZV z8y%!^Z~F73<%ik4tVMq6jNYsOPIhdNkGs)-KTtm2yNK)J4)mP^<(nAf;|}@vlTUth z`OlmET_S|VlUcvM$oFwiqu;=XF(7)=r!I9zIkajg?U#h<6MO&r=pdhHDH>)acgRIn z`V4xskzc$hKeqUDf^Z-l^L(HyLVi}>Q7*4wpIW3V9t19WiaT()KY?_ux$nR6Li|Yc zHyx-ii~RNV?ClBouUze9SU zlE&>x*gWE2?F&J7+>%<|?(BP?Z>7tp`%#pya~bcmg9rOIkVEdaO3Qv*+;g~ODvj*x z4t{GBGBAey!L_N@QPRc3DN`G)bq{C%FZB2I%ysoh=Gi-dZ5-Y$8QytRc$>uUxzaj| z_Bj4|GxdOv@ZcQM!$wEKzHLpO<~|PF#*vZIin7s(|4(^lP`W4@#E zsQ*20XUp9=1Nc_>b&eE|72V;A?8W=ghuC+6-CxT2LF22-)UWWB`n3i;tpA`_)}8rOKH+$raGX@vd$!{_ zy`Sat>VDG?%w&w1KtIrq;<960*^^w^g_QlD-gjCb^m9h^g@69h`%Yg2miBl%{^Knz z+ChKW{ZrT`eoqVgjZ6=#KaKyf`BYBhg!M5pDc+PlGsW+@#~x%{IbG?ZrTFHT&|Ke< ztT?N#*;`y$?OoB`Z3p0A>qmIl&ME`T`ZD%)x^n=ehx$i)=j)vXy)(|^ zB3)IKS8GOEdof;ebk@EU-5EU!8M@T%=QN(CY$y23hdKv+(hZLBJ!YgCFM#u}WTTKz z>)4`~?(m&uJS~5>-I-&yfyoGY)TWrH`SyCsc$z&r>L2M;qXoLH6WL1eH2Y~{o`$C4 z>G9As;%P@C;Z4~-JWc+u{1u+29uMEzL4C&4l&iMBi~4zp>#Jk?@N^@4JRDEg4`n^$ zDAqHMMpq8at!G`)uY*KmE_*!iliq`G^x<~#D|^ZC5!pRl@-M}{p28RiEx2FmsL1z? zk5q4=X#PyQZM>$Ahcb)Oi8oT#Xn!?#?A-+Z_?=}zXto~uG4PlYTV4dY)rGd4lbf@(4%bcyy7$dp*4l*Wx zCT($YET~@ZP_pAJS z{BCmiebM1J3H;=no&`+=zjGnF;D(wWoj>U!oS{!8KRV}QJO@t7f4cHhul!4eMfoi z!*5O(!9W)#VDK#%PZh%ew$}ee1Ea&4b@9H#E2X}4&+)yZ73ya~S5G1Jj`W~z6g#xMH)K5#!lygJ$SCF8r` zsxL3|b4k@jy!!IX$30~!tkkue@%Fr3wIJm zUMzmmOxypvKETPwM8-qE@9}QNx4&X9*tm#ph}QTRH|U%9-3@QjR~k2}Xt&0V6-P#T zTX!^C+qrKp+(+FwHfpb}w~f%ej=L41H~84tDZ8-)nuqD?j}!3GchHv`x!18cZIaTE zm3GFG;1Zdhvb1TLx(xYJbWrW zFFxPy?Ki?Ddr6<}WVcpB=+@iD46-Py| zWg`qzUn6hN04K3$+QD@DbvCSHui86YS=ki58!3m3{QO|$whzhG1?9Ram#7C>^*S!D z>rG|3X+fFiip$LHr_747+zCOMos{u>DmmAkpYxG(Pj}fmm(h0aF6~+O&$I>Is{L=F z%t!}$IUWn_Xs_`C8-z|LUXYKz9>kRSjRDSw- z|BY`)=cFC3$vr?}S?PzaKS;;1cc30UfR4FTeT))ZT}W-{!@&llK+_z9N9|P zl-jqRd#>m-6D%E_=iC3|QC?REIFs)2)tHjMKCo-(Q`t3lIhj)X!KL*8 z@Qqg(r?kiO3zAdjG+Mi19E|s^+Wu$8HR&bsHR~HM>rBU+;ZcnVn$ti3b$E^crP6Vn z>FD6w;2<~K{X9W%O^%{{-77R^YHuVmrZ#pUSB4L=@v1K$ockDTAGYDdd62Qf2|1JO zYz0QR58Ln=YxAsr&vFj zP@A-O@I=>-T1PaVfk!?9&u9)h3*1FR$?$RH(^~M^w?{H88r!*yVbVPV>&hpnH?nz( z)_Ky>mBX=j3Vx_xJS*6R^^{$CzW1bd&H~>p^~Y?+SG3vt9EGd&PJ?h{kDt!vGrpRA zfu80q&WX7r!F81IMgKkxzFXMq7tRy(?qCf(B%Mp3goGi$rX zWcpOPME8*<-Uo2~_C)Lx4Ddx)^uc!|`g0`n4e&j{d4G7*@EdRPbBX5E_T3Eb=(abh ze&c!YInUvvZ)?lTLvwfewjc}E7GNt~YeYX$ThdWm&hTvkCu<9~#14~d_!XIypRmD? z)A$JAMx2+MhTMTKp36^iqx~g%kNGX`+wjBI*ni_3>>g)J^drl^`+X$K(YlxO56e$X zy~t^N??t!CynAm={E9qEuIGV|_6fWF!H=k3!>{?2TqU@Scli8(c=?dGpaYagdLWeR zE-zn!EQI{8_n@_(p!{^^+W252IjZQE9AJ;xyv_C-kS?FFWH$e^q@2*6BbwXBqnm(p zY7rdHEGOWQo`6HT@WwZbO~Co>h4^3F-n+Tk`%o4Z)^M$D^hFE)*+}Oclh8S)1I@mj zV0(D`>YV8Q^n%X0g3pD-Ec?RBNWx-A^3T`4ZDP#quCnos9EF z$A5>8lr>l*Lwy5Y(ko{BL~zhu(Yt4XzA^j9^i494!7I`^?Q5g;u5W)Wk`dXlS0GFN zjY-L<7@V0vWJzkfp{cY+_S-2`&hmVAG`d2Q)V>8SPcML#NB>#$po?fI|YVK1S>Qp_jD zNWPfw$p3m^LF9WCY^_VkFH}PrKL$1)7V*2yNr<=chdiOY zANQs`M_as}n=Lvq_mvG_1MgeEW0%T~7HwI3F&UdlKEX{D-FxHXnB(lvkf+~!Z%9*{ zuxa+QPh~&8r2g-{sVD9Hy8XcUeIb7}D z_VA8R%9Kz>V`!82vFYwlgO%bg)2RK~8MJ#L?G_)X-Q8dGpZdr8i1}gFJm|ya=tv(P!QECqOugUm;j!4KK0FTp zzrx-|of^@@cz9}(hhv{5^eGo_^XnoH`qJKU*82dJyaf=`PUZc*W9(=D0rgm)5O4iN zT{=6jx~2fDfp%!`o%*Grj5#N9g5~AN_k->=^Lyk|!hL~*hYTA0s4dpFx2n&Tjyzo8 zWRQJ4z1|OM?L^O69neTJbeX&VI_4GV*h!wmzTIkIFgMd0sK(U>-^YB*U;k7Gy1}i( zGFI3;&TvzH`Y4f~?;j78pLt$`UmFl?=y96b?CP27!@xMvhrzeThiTIZgtcy}F-GlB z8`*ndx1t!5A6?tyekA=o;8|OOaX{Y|C-{=L$*JB=u5VSZ=$joK^-tHr zx?b~-r&GBpCG>Mys(0fud?6!~J{g;%O&^xK^$hgKNPJ`L&M$_F9`4#kyH- zLN8jI)+zrO`DBXTggBY9rBGnNS+Yhn~L)K z_oF_?oN2#*|G5Ys;j*Ks9CutXmy6z)@_4Lb92*SR5RW4c0p9Nor{FEfqB=u(?XM&6 zE%@*gc(xVxl*#_>7@q3gO+RQX*1F1W+W(l93HExm_4Af$+p(Kl+7@qK$y~JNlT#y~ z{wGh)HEQqZ=v(ge`>!(PsoYBDhMDrm@67z=<4=n(wI@qw>@NQte8l*k*ei1sygNc` zG2HP3KT+QJNqf4qU!{EI%IOMs5thxAS$Wy?%%Y>`XJ(a8k&n>gsk27$CFN6?x3S*O zKEp|Mtu;3tF~4SP>WI#C`4rNmBWFnWbit?QV}qyd&8L#oj6#{i{(&+>Uw@fH#7p}s zL?6u)A3?S?{}5e7EA45>(}&P_-_oH;x@DkS=A2RUWsh3hut#4vJ*>>@pa=Zn=YP_1 zozQs-ebxn?%b|bsFwVz7>w)?}x~yJ0Q*A0w?PK5bA@c&Xh}y}$QLnq5R_1lIQ~YIR zUPr$}8^#}-8xKYsuhUJhI~t02*$Xg3YZDtjBl!;AO7BO$Q|uMzy+Yl4n2>YsrgOfl zP}Ynytw#C!hAk&*2}s^yYv4xp~<$ zesm3e-D+}79OF%^^((OR;FU-3NPgqC@txRj+E&=tWp&2$fk{0Yi#iy$c7q%DcH2Iy zokvG)lYetJ(_76dE#LIO`!k!)Q$d9|4AO@bF30g!AEl1 z>}^QGnit8}utMu5^5gQYKD9M+aJ=W<)K2N)pB_Lb()JSi%=(8m4TftAxJGL={qunO zOX(fesobx|<8yF67|~nnHg+#J>D&EUAK~w)pBa~jfFJ&XU3tRBe~i(|ebfW8YEBj42KnR=JZ_owwl|pU1oHFb2oV! z%ZA@J8~!(a&$o1a4f!+VGo4PpF6E^SJc+Hzlj%o*Wb~d2CnV$Uv*H&k(5i+u~z(D&K*9bT3g#tnD6R-iHWRb zYhU3aev!{eww=!UeNy#TgUe*r^cBWWsr_vp7u)Lwk0x;8+h`%a6|YwF5C7U349~N` z3wSnagX3BG7iHT?uJ+)s_y)YYm;N2?^oe-)W5T7tyK#He=iWyAuW6olXLHX+wAU^1 zmSu<$$u&MYu=+d(vQg_ zI%*DL^kkku{j2>Pt#f8mtMHf2^2AWBqg6C^6W6k=bm#1qwbPX@e!m4j33O@f;(ODw z^iJNXoF2pDoeZr%*;%S(Y1`9$=TVYR=8wQB<*o|pjYnNvM=kB4@3^o&%CjfEQ?mHH zzVBrZDt&k>VcB`oJ$F;zxB2#aYILrsMR`fOLJmdVM+jPD3; z>uWDcX4G%yFHP&-yTv`fp-(o-7G(TVSgN>;P`4_Ihldki1Dts{c*ItDw z`-^lyTi>zQ>zUjB!FrCPo>9g1tnE9WLDw_p1@n)-drss2H~B;MB6*AK0Npdbk9yjX z$2>f!b=6NpW38!A&=@tDc=*!h0@$y&+MM8tJMFDe^zm+$MTV2IG-UOyPL?GrdH7d$ zV}4R(Hx|o??TtFi$)fEMEm_^=%IEp+I;*Lb`N|H>S2SjHaSvN3Fk^XB8Oa+kUdFcG zj(wV6P&y;8|4Hc?tS{>>LEf7K&w%$jX_sW;eVNEU6-?Nw-<;9f>haSzXSwRaZ_b2mb@OQ}&pEKA?)#0mOq?(LvQ3Ro3__dOXJg4;N{cM6P=pj zy*#xm=2`VY#Gl=ns?vRJZf!VRD^UEoo>$>-pI77~mm3IY8fAdHUCEGGwX`4x}Y;;JaTOh&LR7 zsrQWxU+5d>Et?e2J+l+f1^;pLvJ*>Z2-j0ISHP~(9t(fYcH60gkAvGu-+$wL#=v>3 z8%Ae6y}t>2XGiMUVY#&F*lp20`u*_hJBoF1Q6Bk#JS_B6lDEmLvEBP~q>ugG?8SKS zwkl=&$HT+_Z9nisA6SUXFN*RO*Y}e{sP9KbFp7O{aebRJxjti6TJ}a78A;{j(=uBl zwi_Z_-Hrb{G7r||#B1U+$=lcIYn?sQ8Q0awOsX!G`{}L7E3}kMn|~$E+FXgsa6bfg z-!l4h+1{F51AVS?-{D_*AG}3$t*8G>qCIGB$?@Fx4K#j8`!~Kx{*6{9oNE+prxlu8 zYp#eM^5^5c{UjS_yKf`m3^IuQVg3Z>Y`1Hkb`5RRc_!xKw_hS$v9)9)Z7jZst0x=d@-@hO8d$^o>vdxz$zIyMX`o(%0J}-@D;=Nrlnh z*L@~+&jHp-U}a@nF^*rhdU$K+RNlh{m(Hn8t$HWDo4!AZx7}xxx2EHyTqphfC+vVv zmyEdWR&eYhU+@l2tH-4o9J=5at)mK-eDPWXk=+Pi>?#Gnb9bDb`yBcFnMz+)_TlH% z7Ic#8&8od+snuEVyIt|XIF^6k7R|f!)RCNP2lM+Py^sfP9^D{)4#6Q3E6;ooh>N3}iGbEafPVfB$edm%aqzvC?JuFd7p zwv%?2^LD)TDYTWG=?*c`XD;p2{9U&3rnb8_*FrzpE_%1R23%{(!5cnTnm?P7BL26h zB+L1DK1@Nt>JNzrMM=99qyHjusDPN)9(4ms>O2 zHIjPd$LJJ2*cZ`4nV9Ehac8~5cR2Y3FWJUGSMV zFT~Ak$61AUNXx~4{p2%#hZf?81TX!6fX8F~;Sr7lMSQ&8*~44lYvCW!cv$W`z=0=r zWY(P54^IrswUFM2C$1izt0CU=#Jq?nb~FIPcwtRhD|VOb$6>iIlQ%yBx*r|Wo%?i; zG@D&AqH)N^7SiQc_|{bV9eFdGxt#taebPktKf?Ws{}n$LpQ_1bYV{SakDHMp?J=66 zddZV2N%h9?#=)=Pn@X+Qb!w1q_Er<~D$+$Cm6I-6;l_$SG)Nt$vl%fBuy>=g=xb6r z$veLK-iv@QUzg#qrX)8r{GL^sJ4^LLmn44&jK7WT{pzNY)qdT7 z3%G~|{n6X6OPRlmdC7J+hS9zaHr8S%tNro;d=UIJ2hiAhCHuNv;=#FnPG8z#-qPl9KG zBfEpSd}|53`mFFn7Q`#t9nV=F+V;4^{UZMR@ZrY}%e{^GbAA2bZuO6d>i2t{eEne> zz9N&M2;ZjG)ChbF)F0&mFMW?}YAppn$z|KguK#I=@??=kFDv$qoaI?(w6K>W*+b+# zD4l_MD0KEbltP}aq}`rIO@x)U|Hj~MljIm5@i%fg_!wVO7~_#$$>zI7+X3Xs{KvFW z@^Oj7LA;fL4{Yxo;}JX?t#c_p>GOP+v?~274f9S!;_lp){JO^S2-&oo>bl9CwQHG z#)*DXUh#qbNAj>*@}M%3&obesFt{E?Sh_y*DSXlVC-q)nyZkTpo5{o>^xI4DwY5?B z2Yn@+yOegQ^rb%&^bPv={}z28bhr!GErdnihyLjx^bKsoc)n=1+meF4TfYQ*w=kyY z4G6RC`WwTMDbYwcd<7h2*JaV`S&i8iUy{4Y(NR3{Q6DD%?Svz_9oVkZykS0b(!p#l z&5xB&`)Jv(wfM?4FGNQ%7CtOoOjk0WP#jFxEu(TG<@Z=Vh*k zosi7?$y05Qhlkai_WPd~^_2TNt?+H;Cl~I!(%M#>ru(i)YmdjnAWipOk%mokVFX|G zQuH8hNnm%@-j5y~c$1Gk02d_K4iMC&?FZNzb=FsWpvBJx_vz)-^5xrrps@ z+4m@H`>}a1k$v1|ce7VRcM=O{-M`!d9h^+WZNE6LS^E6Xhf@Y){osNQL)NSDj1)5oYtv7?OXr}MZse-|N z9ocqs(Gh&hMzFYQ+BY{EzdDuf-io2$dd+vP{o(i>-1(Z@GVFDdk5@i~qeW}%SJ|%e z`|Pfc_Hy11T^-D5945V!H2Ff;v)?=G{kAS%@U=f(^F7_$au0nfUT+c{mq+JqmpeZ&7!^F7qAW-ow@Kn#F5`F_$qx|ML%(6K^*?K zzWzYw4(PERn%iq$gYAc1&zhvyV}v!@Q`mQ1#9cxn}5* z@b~?{sP|(da<>jrZ;X3j=c%po*KBufRaiQkwnzNHxFK6)q-*P^fbVT_@;qWZ?ef^& zb6~mQ3POvlRt)Kh#o1m`$DSYz{3H|`>60i85(NVe& zUer6){n0Vj8Lt0g{lND#Ym4e8xrL-Hjw7W2Bjs&2GUG+Mi#~c%L7fchHkcqFM}=O;ds370_QI| zyzc?;u&mY{kTyF{8rf^9ecVNC{OZepma^+z`P)@K&77OMKZ|T>obc;`5#HR7G%E6G z2xrA5=z|YpK>Cn2Abm*l?TYHzTCmkfGy1T165SNpYNAJf^pTC>*1kQQ6;6NY+=lj( zbSz^&h)f;s^%p#(^#{rOQdhQtyy8RA-{xQ??z{=|mf4@)ccPbhzO_yr?hOvtyZg{* z*dX*FZ9w{vHXwaSGx{(;J}7;-vvylZA4kJm%uaKBIS36)q07f5qZ;2M9T|_)f4#X_ z4g()UAcyqFj&R?a*Vo91AAd|P>4Ru|CEnUcf8;fP;eSIdK11EL#XM&Bz3dA?cdX%F z5Y25$*czYHz^G(jU3$eu0O4`AksW$6fb?>gpe6@jfD7#_Z?HDY<`ZI`GBK{01s7oY-?ZC{2{7 z>k#rpd$I~`Ixs-rb6*Gb1^qohzGzR@!Sl5h!z+>__HrJyecvt4GXPG_#dQskZx1y4 z+9Brs=i+=t_>2CWKR#$1))eO%0JrOl>l+}S+Hm>n$h)*Cujj?RW?wk|tuN@q_`QY! z?4v!{K01>z$KVFG%t7+ce4Y8H73Z%n+!2Q#e6#Gedzfq8n?APZ8@A4{qzC^W_S@p< zKkfeUGd6o)9AV{=?UqU1%ss^ux&I`3Q*lUEK6K8&;A*XorYpA~RbR{f`XRs{7tMLjBG^#JPwss}z$ zJ&I4!XTD8bC}nT(XuV*?P;oubfq1?lqw=g_LV#T zj?MePOY=VU?QG!1?IO^<3`yME-L5 zmxZ5bVKfk}94y629`x<^kf?okg3lIonsD0Kwq$eSZp&bd)7-F0`-$sHa{o=4toAp4 z@~ypDClBG7%No*Z*3=t~O1*5P>E{;NAM&m0l zqfOKu-z!bJ@igO}?*9?q9OEzZGcGR7~+-HB|IQDl9jrO2EDjL<9Z?63Zsn(7K z&~rgzUcbZEWr!F2%s9^F+@I1Os$F((&m8if&%Bs29sgXK+r6wbx2L`|x3{`9_j8?1 z{1j_#pJHvz$%B=f8RXwnl6z|j`TQB#nY0m@S^8IZW5)ae491=}={rA%Jn+Bm*`?l4 zrggV?M1v!8nG}4_eq8;dD;_S;r;wH+O>(X^DDLFx{e|epx7CBJ>7Jav@VHwc<>EIM zU{OzN{)6}(t4nedm-;a_>>17D#%-cG)xBWIzXWGjp(&;A?V!?~4rv-axl z`E4tlwQrEG_AeuC4adTxN7=flg-<0+ANxHedS~U{wG(^3f$b!nz24ay(qnp0M{5?; zyQAvFskwVfn|4irzu{-&MdexQ^6dSp{LR=rYcEN_cn|6F)k*Gk*P-sj(>+4kt1(wT zvB@bL&oln5F8Y9d3^t~-KDV#d`}V7Wv8X)0qfcYFzdKR%(pgx+e6wIO-bvRtc$gYf zkavyQ>-~L0gwb2AE6YDSZ}zkwT?2hr-R<bB0yEV@3 zp4XABV{RfZ?es8Y@8lhA>zu7ICdi|^7S-qQf2+SQkg(ZF-c}K9WgjbEJSY2E@T0LN zxceY2UKqyN8us8~%j=CM|DI0RzbnmlW<7na+v|f(lvqES9IlT9X~lbe!g5+)qa60r zg~Cm?U}AlZG{s}X1?wZ^!M+e4(fXPz!`p1|n!ypTog;h&&*k;-6F9R6rm*H!gfnT# zZ;V%5PB@b`AkL&2&WU|B1w4fFdh9lve}LaT=|z#utUDz)7g-JEh4nt(H)P(Vc3?*g zNPG764A>6R25bju1Ga-SYX^IU;8nMFmuyGeU!AE0?Vs~~IT-EPOEVzOqz#BOX#?U+ zn&BMm&k1=T!7tl56YKaTZpZVf)t?D?=v%a7OIvhLsq%;iG|tvgR(pox{oK|+q*1>3 zZq4m}KX=JCm$J=`UaBhK>6nzOC(=)6oaAfwm))`)>^P zr?eG(_kNy>To^4Iz$^3OD8{HsJr97Z+NQZwUbc<)Lmgkb`fk5>M{#BF+^mw-C1G4S zaWhI*FZDK!@{J&FV#(@lj{a89MWd~roa*uL_otKP%BXW`I$7?fsN7o7l5$4N=Fz#E znQJ{5(9`O8G|KytFz?)tNd!xKpgn8e1gu(q{ao!n681C;2^IjU|{d95O4@G$w zkk|SKoZ~TBdq0O2be`xCr^)^x&Fj2Gn&h7}uk#}ML1Vwym^4>ctn)07c!K`acoNf& zx!G}y>kEtVemugvCT!!0V{-RE=XVZ}S9dzZaNjz{Xm?(5-uH|#+Uef#7;kK#cE=lW z9Q%$E{E~~xxqXl^pQ@dbkHp$Tz4@bCfz_H%GY_vyuionR)#cO7vyU(Ot||IHwdnhi zA<6QsMc|4{VZ5q&SEZ%htHzrpw}{+<|pFY@W(;S=v%U4^>sww$NTTHqYPe^{~i~8PxRkcMBn55_ao8wSpPlZXe&S3e_s%NkMQ3& zMc?KA`xnu7EGr|%S@{yuC7<4Eg3XhR7Dso@M){evPxzLw`gMC4Gs(y5L%kQ^~tc>AxLS>qg~{ zrEb{|(t&mUEq35q`qojoBT3KrcOC;>h`u}`>FX=h;rx{w3%&N`TP=yvn4%((=3xf2HB|AaK-wi8j;+>sri%wfErRkIQCY zPcwGWc4wO?tTDXV*&DK@Y;U!nAE(_J8thx;+g=&jEIKP8?Sxu^!tFLbt$E#R@O|nwke-*1fK4kiPEDp zHfA3SXN}8KBR@*#RGoW;7Mib>RM>k6@m({d#rA=0hhW}gYaF7N>;|3B25|17;lsXJ znvv+s6xgZi1)1A8p03sE_1ZeR>V?LnB_z z^DV!c*2msRUw9u`hPjQkh5k~1f4P!0H}7e7>k(R?>YyC&qS<^#>*QUNQg`f;4kOK< zJDJ5?u-?l(%Liyt(P>VQ7-vHp&9U$%z$F43%{0-lNHM!s#DLw&}{tmv^3 z9;yS!34}!t;e5Gpc5^fQ;14UG&eQn1Gza@P)kmCfYqXxJx1$&K@P<Jr38;?A zz!aSDCwX4s<^vi(Y<>^!I%C)Scga|!H&iCFyMnjPlH-Zp;jI0TnKE!1ZoI|%4C~*- z)s#oPMqS1)8apj7@#ytl!SAnZC;Cr3`gmwBvM#PN|7kiPTJP2T=nB!yjZqD5J-9)B z<8AoAOX_;-I4_g>@7mmdK(|VG_$Q(t{Vn{mB`KTtShzgGCt+iT`xVf;{+?Iq*=9c< zq|NJtd32UGY5sQ;c$scYWxAVOJ2Vbfk{<4<)H$T>A z=i|l_hrQdv7{S_8W>pAV`dKv1i++-OH~va?lRnm9PX=SK=7_p8LFIf~^oF!-{csJ> z_sczAM+h%yX|j*M$orfOUmqX%tpqd1QR%{wzSG?S!cpe~g+KRSwZ{8C>!W=qal7bK z;o;}<_xQC$wV5>OYCA_W2|bCv+Uj+czR{bp?$S4NtgW8M^v&F=!+ooctl)v8_(ba! z`e|Mj+g3&V;l^M5AMk#eaN(>^Jl5IROdRzv7xMKeZ&;7osqy_sAEWPWePc<_7WTRH z2fHwi2C(sORk=EgVT&JS4=kY$)zcr$d)(UxS})<;3}-x+^gR6~aDhh@{^|g@^xICx z^?}-{y$XgO{hsAc2g%HTADg;E_PFZNeX{z$pSQ`iwynLu-Zni;>kW=JyrNBm|@jhOw*5s^z`S<<%KCe$*n&J3JDn66t%UJw_1s;~Y zQrz!`FY)E7lm80oA=+YgCi?YUPY+jD3Vk^PxyxuSH4K~5>0rvX=A9i`T#w%T^f)Qa zx8pdsf5@j9zOCFF>dq#bj)w-t@CL=1b(8*ZJ}ksJSX&tkXJ1b-{dfDjQyonV@6Q*` z#3kA@7Qd&vQ)i&|`1~Pl`t4)-GF8+czVAEyI0R0wtB;un^hd9)6N5eu<_d>QFYH&1 zXWj?T{S^D|^<(ES_P{Vd6n%AXNytvjtpQ@3=7+lv+LIhu<7;^+13@zA|Z zXVa&j(O6T>d&$5O48?1|*jc10-ukc_-cF~?hHD69PWWBwa7t5WJGy57jfMNY4+MJ) z!Zn9@f9P8DKenmnueKKx+41)=bbm|x1xY8ayza}pW?y^%E1a>tb0ao@=B6F@GACe+ zyoP#h4WF^36uNwrZ<{lh`8liRz^Q#Jy{s^gX!f=w;XE{RKArf^9BVW56OG%U?F(uf z}K7!=4G@w zJ!$in`bnENuKmN=l_gE*Y+U=?*_CBY=h!?2_}>Elt-#kg>Dz!`GnPBo=}&wJg1;fv zGbvXIe2p=k@UHd&>kM_v+G93vYSa6v6M;Vw_`g3pW$>RpI|Y2>nSt=9j~Zxi^V)Gy z9j8?0hN%wvAgW`0&#k4ZV?1??r;Z8KF@ZXsadrIe;B~+=E2u+nA6h%EtIWN`83wI= zsSfR>eIng7uWJ>0`6}+0zLx*%vB%c_#Oi2Y`_qHhF(JjgfjZ7|b=*;z`!#h4zUIb~ z+X~LCcg+FzTezqdJ2o9?ODE3XNN-G<#ki^e<5On)=b!xQyzHz8 zugSg(IK(&a`24*5-mY`%C0orJuaPf5IId^fAEwL4wWvWh#NZlkU8A28>bVZ1|{?gCol#tGRUck|1q zqIX2H#|vI2mxVUUFIsuI&8sdq$9k4AJ2AHn>`v)I=`LTNd^SFu=}4{i{!hiBH(GUf zd86*5BA@O$(Ec{zYkG=wmGNUxe`VBu`7QnePFh3lFHgU4p~IoV^>n%mIw{OJGEe$g zI`G;Fkx#_8v5P%`<^vEdM?iZ=%S_d*85Y0a^@Y;+H$0u0Sa-X{_lEKBEX4mMjDL3_ zeqR`WX(9f_Fn&cLzB7!!x)A?-82^z%dTkJ0k&%D)lI zG4l3=vvn!mG|ZV*aYx zZ=cdwGQ2U2ZyYhFF@_6$3-#E&lYQv14I1RDk#%Im-YifU8Q>nMR*Q$v@#RNhcsXC| z!tiT;vJ1nL_^G2jD+x2Nva(kYojC3Kz%p8PUprSmi8v!`?sR$R@gBj(qf-bg?4W{i)!=*ams?}_4+r)yeN zztX#>s{Y|tzv9Dh)vYxQc-v?KeIh#12BTdqbshx{$|t%4%V-T8qd)MiPsqdEBFcAW zK-WMv4OjXxOP`7tWIG6-PQ}r;7IzVG)M0V-vBhCS;M0%d=xd9^j<7ybS^C`KmJ$d4 zR+hfExaGvrHj9G?EN&%n^s&Xk3l?`ps#SY~LLEVyyV2nnibr|l3S;l@_bkla{ zgU(|QF}C)~*Q&ip<`XHa+jp~rrFabbD87m{7-Tu0hQCX|iMP^fcq@&%W52TUXOv%g z%E$x!Ebz^)CQbMy{I%)Ap53rL@*Bw?qIXP;@9DeD($wn9#z$@BJ=Q3mzR!$BMnfGq zxykOsG+jq}<5=|CGnZ-J^F$n1(@)$v{lqaI__AHV-Gm*ayJrn2)h(U@m*>y{2dW)T z^s8`c^!vv2jlO&ko1%QgFSws}M07u`U_G;bXJ%_Yaq{08I&^bNb#LLFJocK=@ zzpCW0RW;A7>Z#fPiKlDIDq7SYWY7A}@PT(S%Tw_?GTmDDLElSWR7ZvQ*yu3)iR?43 z4JreDq;K?&jKLAUY8UO{Y;NScDFcq`LKj&ccvAh*=;+=#p{bSr+mP9LdXBwuo23&p z26Z0QWPPDIa$fk5k3EnZ8sBwhZZ`QcRgd3^%=UH@Kj(&3n=3eDq4w7t&wD#1ym_PX z3K-FSzpN{RLtMXb1RweGxF0COOL7ejZgt~OLT}P1U4j2ZIzVFwx^8&pnU%a7Uev#& z86D8QqD?&RYWxG%6MijWxGzUvlBT{?U-#)x(pE9<_UX@(DYwSF2~ORDQ8Jvqa($%w z)YjpgGxB|;cBO9lYzhio?;)a#>X1n=;N-Ca^{29$8LxO`$ok$tkq@m1# zL$}u8QBWAR_ng~8${~c3~Ml3y=;r;Sc6GWkG6|%>>t*xDq7SJ8|$O>vo!nbbbhE5J^}vA>pnd(cL_9?FGx5I1D^ak z9iP}bL*MuDtv>WWqn+kz(DK{#rDRL@L@8bCvGR4e{!N^v@%?+g-i<*whi~}!bKGg> z0{$KWA4j=|QkRYi&W3T8Ylyw^@=$7PAzpeulS;J~mk(ivce5DWpnS%a=YN;lp!Vd! z)7M|lxwA^nrj-v7@30Q)eo05`!&*Z^u5C|L2v7UGv=;JL>nGCj z@%XVfpK|wrF~+KmqQh-&yxv0H+6!ZTC(`w1pJcRvPycI4!dY{-0xs^1Ex4(yaA9v5 zJcCb>It9NJT56uGIkLUOM?7)??+mhNX zkD!12b^?86{iObie9qG$PIE zDf8ng?^p-7AP>PkeSyyPdZ{_yTZoRLZs}Xk2VM?@&wZi|Z4=)e#o1r|C-qUG4;mQL z3O<(TZD!F%<8`(K7>v7umF6zLV65J;E?=8lO}hk}dy>Dn`|r>IdJi_7fEtdmB^eE6Q(6i~pJgQH-#QW?WlMcwGN>cmdwz1xpXxoKnCA{f_QyJTkal}HPVG%i)p(=!+S(p{tF^tE^e^87(;=#NKfJIXzT{Uo z(B9_6c<1>`@-i5I{ff3G`Khp9SUSYFS3Hj_KdinI4#sPbOEw4tL-C=V5xyl{KIGo%x#s!|Ha*W=itwv9jGC%KSw4I@I;HFVk3j^StAMP5+vn^m2@?|HT>V zM|j!nVDfgT&m6wsxv$gDi=cD4_F9t1_Gw{nm-LtBeDc;l@{Xa7N>_*CjE?lX^Haq9 zDBW?X8!x{(797++!|HO{za@Ia@A8IY0=hC9KN%0u&)}PA-+xkX2|uqRrSq$_FT9~P zw^wzbE6rXmD)$0qUgf<@mCLH1kP%xy#@@(VIdp;k-PrL#XeJ%oP!icj%HKx1r}Hl0 z{fC1mpNZssE8kupXme;BmPMTOZ1Fv$-rhPqL1vFaIDn0 zpf)!L>$K|wd)4MIh6{9h!zsBtt;C+$f7qv;ceGmAl9p6wn$v59kggfa^ z**vo284tV5#}@8|PuihDThdw|9?rS#QaiUD_VxBy??-#k!R>U>Lw4?PqYLZR)v4SB z@Kc@a7hFAXopX5a(5)91jm2S|#r$;%{kqci#m8Np_s~{9?=8;%PVz5u`Sq@$?u9bn z34EyW`{SaS`UhGzIG)tHdzyI9OEZD-b_ZiAFqBueukiwTHwy;xTvrk481Yf+BAbuy zsJi2nT)SYo{St|^ubz^7hBRc*=&1eYKK)t2geO&pjf3h(33TxG$H%Et@)f}(UAn;KSKCC>Z&9c4yO+Ge z7ap?zKmB*48;s^QmmAndfu0+}c`)-t?|m&a3buWw(@&$~0+ z-=cDvOaxzTE6$_56|`v%{WTmPf%lgt$4$xn2=3EiPe_q|-#&=UF99#<_fw6hBEM6L zdN$E_{v68sK+i?@Z7*Wpw;27%+g9i->^qyg%07KMuO2f!j1#}vo*VY{u1~x3G{Cw0oThneXai^6 z-y}SK0bb&v%z5~?oG(e|v!(0W#ivew*)MTJX2ctg$c(OAz15AY%6B?>q$72vQt+&8 zuU;};`+sznL~|7{Kfc`==xAqgBoE|!BQUbiE2*~&?_L~elPw+j1dH$6uy=Z(IX=8- zeuAEe+U@ie`#hTc*o5xz^A_QJCitrUD(oALO|L==KZb{WdlLEFoN3=lPFLv6hR!wk zarVDe7M-T^4aGhs=^KsVzcyOCGcx$C6&KOJaBhZrS{uAR#rK+bvTeFVx)8f2r2l&y z{Z(&Y8W!G14eh=I>5Oc=4TU)g>%P~s?t3kI@v2nso>knF_(A0FdSrJQ|JU-rg#WAf zU&#L|{ul87LH_6SKVNtS=kVVCwOxu=f9IFjocUoN7O&DK8xtxu_k4ItZhQ%}yHWZ! z^@io5<6L0Q1-6qf%lGV*+$fjt0C3yWr8(XIax-!HJ!yLj=fIxyjCPfyPCvJrwR_#X ziw$NJmr=WSo^123r9Zi4-dxi1wROEJ=gU-4W_D0Ubk!Lt__%k?(589kx-_-hmsvWd zY2Mj_H8lxqDQ{k!q4;UZ_*r|_%{wJg2fmimYYneid)LjYQQ88|YpBgLp~p=8JKoM$ z8~OHicaVP~`HjZQ(5>!nz;?p$_KvFe*XE>uHaguAx0QCOO&#ok8bP|zd@^+{3}l9I zzB--tanqlny z0FHEUo;Ixa=cIglK2n?eF|fA!yQO^J(bmij5e?V8ux{ROg$wnr@Mo4pH@;)Kf$uLp zzOpY!dqi~5ITmEi=Mz3ZA)j#7IbGqD@i0A3>uYmgqimf!YgwQ%INegf>3hJLJW#v7 zQJeepK<&D(0OOuRXxEp0yRbvlu21-OjY+oabFN)#Tlf?HpCk>v&?;VQ_WelsHdjV@ zKCF7KuWMcJ#*_AX-kMX~p0*j3d6V@o@+mvieAndtkl^yIH0d?n;ifmP@Q0cnuz5Ie zwqdsk-Z%cnKl;J)-$;J!3^(74b(r+xrEXlBBKX)2=(*%vFRgJT`6fF2X|_&Qyu&-_ z;TUupG~14hWImSpO6FY}v!XZAmkS^8H{8KR{=Fg?Ut;*{$R$u4^{@D>%h@ z%n$GFaBMKMBb==un=GROa4 zd}$=S%73CQ>4J|<_6~c7ZO*;j+pEA+U#$=3sJi#c=9cO3EcMnI_TDIK?ipuO$Tqcp z<*ZlnxeDN)q5iQv^pDP6zC{0oWwtq92=k~+Tn@ap9}~&Fk1L0d7(=6Tx~#QsbaOkw zh|^eq)jDi^2UD1aZ%AqF&h|=_V_jBh^yP)VK5HLma_lTJX^LljY3;9lzYW{R`Khg8 z`@nmJqw&9Zx;UBex<+@^gtSmNzH`jc+WG){uTLK!Th<4p8IIU~d4KnnE30+oZ6Qvs zU*fj9Z@d4BGJfBEbXLIiHT4Vx!^4UDVGTI3*58MoosOQt{)hhP8J#mP)a&WAv>!UL z7sPbB(GR*Bo!A30Ae~4PzUbZmF`YWGIc)BQ4dUyUt{aF>cJ4y{i3wKD&JvqX0z2W2 z=mkG-*zRo=#@Xndz(w{>pw@UkG|H{&?&MeWCk z>8`Aw?((s`tC#uKQJ?(+17aZlyhXJ2Q{Hu-=W`%GXT3i2u2VcP4yT`#_iN&zYUT{p>@%un&OmCWzctaFEs76Im78eT88*-@Z&n7I{aBFALc_F@4m*&lyOUHQ7rk5B44Gy-d;B5D{CgGiG6Sh`7XCQ2F z#sG&g)x(jE{w#1T4V-?XadiQxccC4K=`~{uPMsgCb*^Oij2R9tUBZ??Ib?36Qi?Wx@$=KAgOzUeF;VOo?l~WuBQ$4$u=xi z8%&RL77*VRyyxdHCTHIE*sl8UHOjvwIn^FljbU!wi{HrAygP*rajkd{8I^3VcQDnS z^QcdA;VS8bA2II+uKbyMuw%C!&Ugk*RED#3(VdLwvL6y}GETUL_|T6o|2}(O2~hz7r%e&M(ER* zA3`}P>>cp_PH)?*@1;0(8iQffRc<}9M zU2XWY51qdEIHq{ZUh9`y>*bD)4d*sZ$vsJ#jow#6+H$_*y3r{+`1W-#_F?K?NVr{k z#nt^d-@a~*HKJWozXWSYf!_7&W_c&$mEfg4wEF~~wwsTJdR}zj>Pxjb)X4{m^p)|Z z=BV%{_FJp;mTb|Jfze!l*XI8EH1gXo>M1E>j~)EVra#v1qVvst`UIJ}6<8kEC)op# zmyZtmX}*)CkL_Rl0bkrqUg<9R*`)I{&#*NC=xDYI`bTz%#u2acY`qTM0Y95eNjGS& zp0Hu~_VjoF9AuY-eYaFJbA8kwUY9t$1S48!4|GVqWPZq|{psjV@sOt5-9F5Sz9svD z{ZrO=PrY{Fi@)a$Q0*_6r#3_T{%Ec?dVJ3Smq`EBwXSe>jZZs`G*9av0Q)fq`z&Dl zJmQtCgOM5?@%RM3#VeCM>=6Z9&g$ZueoNAnZ_^h>H)I(8zLPplKIwxL{P9(IL*?bW z`LYXVfW_Dw_f?AT+g+Mu-e6M3{66|GPno_qxz#s(;@k2X<-|+3x^@=&C)hg>$WT;n zWbS#&ncf_R-b}l>XZMu;&be+US^`W0R_psgH{TIidkxPv$zfC&n zyTB{JI3b3i_WL$|hdg=8s!qlC(FFlr#1pc6)W>=H)AOyu&}82#XD1yF9N9=Ao-5qg zCEsr$EyDFSa8TU|9rXX8-mCkmH(W<6KkVjtr!cl8_fM7V%m((o_Ky0y;}{Ej85hO3 zHs(}1-TNGT*ZrUHd~K@teWEdWXz$Bam8axt!J%+pOH?kU@eG~4gK~dxPNdx{T&cH{e~;Uj z!0kSV+cDr}b`|aMdpBfD%7?NW96G>PcIh#c7f!N!gqLg`wO@I?ZK->yRo7FhleGK) z3hnv7)zu{$ePty%@n^iRES!^|m*s2M`hoO1 zyl(wJiF$OG)X|QnHtzFQ)CR$IH1c_EpBFT{oBV38x53F5+2Ew9-Oi`9q3XA_x%VOC zza?F|?F~kE)*pZ!$x=A~2-Za$j?0S=s(^E{gCl&R@i4%tANkh1IsZj_*x#vlds{V^1;^Ieyv>x|G@><+POTkw0B@KLfmr_f}aun@`Dcq2CvWI{fy6pKNULg4S4CkZH|nR=D*J z>E7nHiJNr>)bWntRI}-VR(NjJWk*N8=?1++^~~FPJ8PTlteVDS@!gleV>^9i>r7Rw zi#YkxI3CLv{yyE`1-$M~H@1kEqIdbUE~UE`m-NgH`ohb+?TLbJzHL9IUB7%a>caMVUiHaB5Pk|52Q_ zvrZ>E>E33;iFJy96jlT4f`X+xn++CgCI2X_^$wQ&6oNGn4b;E={jA@hm-_WK@e4F8 zmJ8qiDvutG>>6a_%>(3bF6vvar^UB**n;}6cKj-sk*)~lH-WCjFEp=XSt|Ef1#>;` zuR}-0cOx->m5)Gm$PZ+^k1mrJu_C{<4!{#PrrZd;_2V~=f%_SyLa*QZ+vg@^n2SD zPrv8s#nbPm+{RZIPyZM4KQv~^^zT$Jnf~o*OQt_qzhwHi<}aE4z_KONTdrL)y%XAP zN{{c!r-#|u$9#HdOSX)@O_#M~%k@8`B|Ad@>6Ywh{g<|6$LhbNB|A?4sg~?S{f}+PRUtmhTPD zaWFT3dEF_e=MI!J)^H#5GWhuFSH#m3kQ?sU)V_m$Y>Qsy=bqfe-9trVqQ=p!z)Nji zdhE0O4`v@L?<3^-Fmkc;5c0N=X9anGdI)*HPM*if`@=)Xdk1-5pluHo<@J8v%)Ou7 zwSIleD=TI`_DZ%S|4ORlgLmC$dHa8_I`n6s@rl7{5avCXx8V*(uTOEm^TF~=zxm*K zK6D6hPB;WOpZ?U~b%pIao%dJg#x`e)2)^4B>uY-J#>K{&nR2m*TudI=8>I zh++RETtXk~!0RFdx{@A^Yzt1zS zy#T&{WL*6lcNPwGUa^^cnp=4Ix&v`9bGYZJ=LPEdqsCI|3G28Q`(Q8gyXUFv1?u`E zFl47_T)=MX-SVL7>)&4Rb?pYWe;?e#);vr8+r7a01NX)y_UQDZi@(Pmd7;et{(iyY z`|oe{;lDqWEZ1K@um0}A^L(KwkFWoqzNfPN*B{F3&6Y1X=UmjrFz*Qu7vVDiPxZG( z`J9yvcx#Y)njR^trzo%J_ru~m1K^^5^=qXS-xu5h4xUyg{@~DPm9=~W(@J>#bnC%! zAOG0F^IW!l@H}C^eByQFeZDyFA<*rL$AwFQZU+vb%-AQ2$`tisi2uL-JlR&?FW-Dp z@evRExF>_SVwnkH?*2s*CU-gFYj^jArX!z>{B)XcZ})3zgf(By#I`bf)hnmwUVRyR zi=Xrcd(WAREbhTJ-XUKdYoh)66Rh0xlzHXPQMv0>4xJ@io_#;_{%Gaw>_0XlYqq3) zAfr1KivoRS*h0T zZkpDMmqSy{ISscn`>9`hL-noVZA%5wpZo8R9yD>WLcba$lv%LolgpI z-cj{(RqmGJvNg%FCs@7XdgN0wnmQgfIhn@Vb|7c!AL9@4CTRom2WbXtTL1l{eK1Nd z{tY93BYK8A`q6m{dzxb%ywLVKI3Mzk%*5kze(!?(`#O`OJzWj7bvruC{HGzboE zw+BDU$8PiYbtmRVf}8l|2L1)_6TsFOpti`aNX*lNF;RYeqX~AT#*>D_oc^+J=o;z_ z#g#>I37z5cTHoOJj&-1i;dKUSRu?|;SUwFVIt)Cd!*qX~)&t1*a@El%+Zw^&X;W%g zt`WB1;#>?NL7JZg;W}=R=RI@pow%yr}-ToY&{vGuEdqeqTCi zF8_dSvHHZDl-U;IfIgCcPCicU1JIhH<&~a-4qt-?iWmH-?*e-!@Fi;Rjn)bD&b;~B zZT*M(Zh;Q2KEas_9D7?s>C};hpM3tgYI(e0^Q+(iT2z?)_|5W|+Iq1)wcy=eP{HdOfnMd%0JATyo0j*ojrxx^s zXrZ4k7wfWZ&>0@9b>)4!(cyX0WD^8Dm~nj|8qDTSHTh#zR}FR5&~NrG^|l)GDHr3Q zyY#e9m3QZ%j26;YtmWj>(Oyx(Ram&TGe-_>Y;W%_nBCU~-V($Ob_Qjyn=`AwJ6J~p zpWfa2r`|pKr%(3sKmF~hBk*Sz+3M=w#TOLW(?xkg+xw_@44zl@YF%&6A?90Ll+V-V zLl&Q$AKVhe70(aUjxQI%>Mzf~9YUTL4AFiPTleTPVEoY980^7$9eDih#UviD`EQ5E zEB@Qz@e#i?LGntLpL*A!(OPw% z`8x8>e;s+RD$X1DJz^b!-!rT8Ep81;I>7HYvb~ZM3j2rSGVJHEaq8X@ySMD^+H*_3 zJY$UZ9ld`D_lp|;M|(6c*STJFP)Bu1?#qNLxeM&yb+4lK=3vLi`UriHuf_&v3{2d+ zj4c}9JwLgr)$WU5xng?erXgc0w63T%wBB=a72BrV)`*R*`-uOS)Y%>v%B@HLhRkY_nnU{gMCw8zQ&OO11hu7G`hFg2w&4A#yTvQ={qevKjyH zydi=OJm7mFF>W2aO%eKTDD!&W5IG7yGConcf8dRfKOrl!fAJH>Z-iXNU4w!d5nqPZk-sS??Y@F!{i0$)aPDT_nD#(Pe)8eg{I zb0E%q*PN+m|B{`lALhy_zj&hte6)wruhVD_c|ZD~3mlDiNat;W+p=YadVD!Qzf82h zKDw*d?%1WtGp(^L4*-eBWexC}(JoS1& zVys+NQg~ZMb!kkaew~NUARCPF_O=S|q|L*()@pR(9J=&X{KksD%Xwo3Se?TdpLth> zanRxtZ>$j4NIrXG#f9yCl<e1Rm9mFD=ysUjg=ri zeq%*&p>zDk%29UL|K_;8q6_V}H&$xtU-S-Vnp^VC39ic7q);^V?M zR*36j{Y3S55$F=n5>OHE@jnz_&gj zPiM8uM}Jv=imvKU=&bjTgi9y%&(f#%uF1PnhNs0{Idz~WXCM;}`pykK!x$Y;g7hJmi2&E4L9yq@uK z|BVaSSAH>fN)EO2z@zZpj`}EivUJjKEd22xTpEOj2H}bze0UH(A_yNDgvSTrV}tN< zLHL9qJS7O99E48`!e<2GHwWRj1mSao@Y{lLV-S8v5S|x=FAl=*4Z@3q@cV-B2ZHcr zLHNobd`%Gka1g#H2!AsOw*=vD2jTAq;qM3Ge+|M<1>s#m_%}iLcR~2MAiO&WzYv7G zg78a0_?001S`hwQ5WYDG|5FgYH3)w;2;UxrzYv7)48ng8!lkncJUlcAR|Mh1gYXeS z_{bnUJ_sKhgpUitCj{XsLHOh#d|D7bBM84a2)`u=pBseV7K9sv@H>L=ydZpW5MCUF z-xq{G5QHxa!dC|2Yl85HgYZX#@W+Gj%|ZB|g7B?D__IOy_8|O)Abe*KzAFgd6NJAR zgj<5}w}bF^gYfr*@V^G(e+$At4#GbT!cPR@r-JaVApDyk{JS9hToB$JgkK24T|xMz zApA-Yek}<9EeQWT2$!B4@O%)i2*QU4;Uj|ZkwJKT5I!~t9~XpA2*Oi>@X0~=v><#& z5PowIeoGKOHweEi2sZ}dcLd>iLHObz{N5nEI0(Nl3O6jj{PL?#tV~s4>Qg>&>Y1l4O)bCtq$`(RxAMcwD|a{DQR#x$uYCUpmtR-;{^eI( zl}gRJ`sz6=ud7^k)s@#>bJgY7R({}`tFEYAemN2EUw&fcl~+~HecxsEl`F5Tyl%zv z%B5FdU3vM^8cyP;7jLD(P&f*{(kL6)EhvIJSeW(k7Ouw}ahK~X&K&pGc&li|D1?|Xf( z=lWj1>zTBlbMDvqcc1e)=RW`Ld+s|pMJ;z0x#y^bzOXxJ-{>z6BJm>kN2T{Fzt16u zj=VyrufVMq2i@+lI2Oo(BTsUu&USjj9$$ey-@h;3F*DPgGxD7(v@sNR7Y!68%^cZ_ z+>%J1zgW)5WEN&Qmd#tfbkV|9IjYF%^W?ij;VEvfS{MxagLCZpPLJ2^vWNZlyrA0| zcH1|2d@lcnDfXoyJEG>yTe)~)4pLaKVilB;@A0`^r>U?f>~$-sC|sxt-JXKNuqyKS z9L7P8=m@>3G&N04S0}1;HABr*C#hL#wsNXmm8V?Ft@718HD4`InQEb0q>fR?&bNo(ZKz_saXSu5^wTKcR{h&8T{?|(Bc2E zJ=*E7&Y=^uub=*Zl;*{ksEa3{G&<3sI~4HyLhcE3rm55kIBmE%G+_=(>;e`-9qyoT z>V#asYazET~pR5Xl?tB#r=BZOAs0kA#eQAeEr#NBG1hsV43NQt{k&*?4nhr)Aaos>RZotIbOIp6MaxpB>eH_p+6&nXi_b`#m*aR~&19$%g( z;PeV0tquO*IyrRv3WCle9F0;b#b|WlyQc5Xru{BySPN@F%PMttQd!! zc^FZ3r{lmW{6XYEg^B|KG~$pa7o$fwh#n|_?#&m5zAtd+g`MK;4B;a5U?5VsaN&Xf z`R-uQ?NZr6f1cY_9CUisDmO+lbPZ}@z!UPjaNxs8JoucUFcL1n@Fe9yZXKq7aBMK6 zl^gLefO_&USo-osMR{(tra(vqFtq!_INik)Bu%ur^VIpN6Wo{$M2>YqHB5+<87;FI z7oL<{UxB|-dIlM+18L8QHAoY5*{2WfaQ-E_d?5wp${a*gCYf`{Z~(pMVmJ?b+(8v~ z7KBuhJM45h!o(m*L@ zj^M%tq>2MLiCZ7$q5~`l%IFvgim_&2ZAYdgN-I&xk!a=io!9i;t8JAh{ae15Yv(C@d}1ikhp zk2E4J1b#T1$&HzF!38-mjb*5dX(w8x2y{{LCF;DadFL!#X;0I0&Q&=p&svak*2;NV z=Z{k7EnL2M<-BF~1uK^4EL@!fmy0L(*G-rs{ch?6sy%Y507gW&bdb8}80q~N;xfj( z#Ov{`bGuS8wuQozFD%C8Qd}e#J9-w(bVK%HpL0E?e&(8!p%g78xG^9TnhT4e{*Zk| z!0lVLD$AaNRJE7?_>(}8-G`qg`?fDp{P=1G_2m?Tg!{^>`zFi+i`^&W1hhb5NApFNLQIi0iB9cT1)35V~ zP9p4R%a{ch*ck>{nix7?ows!Pq7~=sdFFX%&s(|N94=WnFH>QPj1GMA!0ZGQN9mI7 z$fnDSsa?=rApMOr>itITHwuPYV6NlIS-P8=Gr&2xq_H+xl9Q7?b=s6^c1$xShJGF1 zjz+ZKC?w)T$BCSH$&pKBe)!fkf$Z2sjsRT|~XJMUW=Cv1u{J+ZX ziZhg%hr84~JvD>&m;3E3xmxC5kFhn|jd9e64%NF+Es`D#V~g9q0_(US0*CF(FuLS> z5HrX0mcfnom2MZVkG!xNh`Y~ezS9M`uo!DBb(YUr94^GjcM+m5@&|K0E{roeRdc3g zZg{)wa+-Nqs%}6qWG)|t3aiC_pBpKlugSxJDOag|p&rInj^A%z=JZKE^m#&RsjT*V zPOp8HOlyO7y|UBiSy~kEx{FXcBrRE6j2?Rfrb`mgljpW0ivyhi{p>lIU(3+DO3yE& zoAvtX|5eMjr(p8o)xMZthaGJDm;@iMunG_51wEJ@hr$~%$b0fJx4;OWE5p8W7v&;< zSmqXCRAV@w-?+*kg#p5?r2dPX=>APqZQ?Y#6^K>r^7z$yjO2dI;){bA>M*Qg741Z~ zq;j2@aODOu`gt*-Mf*fs@&!;x=_U1msW2097GcU9)RQS~U?@co8TP9+6V#eDYE7h$v>zJvlP(Q!c+u6DP0p`8QytkKG1L2QcYF z^2MI8%G5K-Rc>!SPN`!raQgf{Tv%R}g{FtB&39uSkuTdAGKrHt50zi+)7_4wWm=fR zB+VaGxhSF@Ar$6Lo&q2ApI7J!qne9@h~~yj1+z%$u`u#uPKK4K3SiyhNBc$Nkg+~8 zBM23G0&0Q>gBu3jJkwq30jJ-bM)8aT)5geT3hw5F*l5B$ z3Mdm$&aI3VWPYWOA{y0T=2=X3-)svGCa?QuUHTONxe z9bjds*97}e<|NWEWa|V|hb8lVx6rZRtd&_jikU+qO;gu=rL@|QMk`ibc?W}Y-_ z_PqHEG8ZmV##+2&>FH-=EnB`K`^=TAa?bkQ*{jbv*O{A#eYS!^&jsteMLvJv!eA&| zynaK;#*6kPGTHGzi$7`V1c$>+6C4h_(^la(M~u1!S6&AzV)XLgd7C1LGarnygpaq zCzVPa0>L**6rPt>2SD(Am%=-+6n^)h#z63nPlfk%DZEQY9SXs{c7^w$D%_LSBIyas zxg@@%C-s&LnG87zB56qcaggI7vmkQr!y%I(r$Quec(=7OXU#x)i&ZATO8rGwba-)+E&`eQl+DK z!1$$+^OZ7OBp>l6-O_<+^YpYd`-(I43|W@Tlg+eR&u!i7#X%N^&LRYG<`udp%cKxH z``9D#PtFsUp>ykXZg*fZR@3X@E_2CHC=z3`p1Dn45%d&zFbO|FPr!fOI{yEDy-2%~ zb}H9G8btoYmbQw&I9woBTqAMH4yQC6qrv9DL&TmSt==5#0~+EwM%|*qR^wl7QPxD9 zAn_0t7d}K;DsgdCOj4G3H14v+%G!m*)?T2jfpyAKh8Ib8ZB&+|iP$$oSk@+4 zRQy;x)i%yzD<5aE#2;y~uEj&bO?b&@YpTVTiXRr%q+6`nr&v_VBFnHQ{9t<4VvDtH zsYP{WSuAzSEUI>e#a5GTiHkqeqS{tjEWP+KY4+I`>!vjpRqeM}(}GAVWQki7##5kS zOI&s_enh?A5?8SSKU~^uv9xbS?UY$8nPspqN1B&g)Z8r=OX(K892NE+*qa(~&W9{2 z^-0U{B|Gq=vllGZ+MN~^_p!y+{INxK?6z2|zqP2$A1v0Mc&nv!q*WyzY_--LVO2|x zv|8IHSk>O+t=68YsPQ>gYwO8YRep-qIxEAf#>}%?+vi)=tOZtE&H}4iooBVxaVccs;-9LHC9z|v(=J%i&bUa zZnZYtWwmAAZB>=qt(Lm&i2o4Mkp~Q6H^R<(*lJz#h*f3ouv(WqYgMi`Jf+)?G~TjW zo8Gpngm{*FDmbUC^3CmuB*m(Dlwq<`(SoSK#w$nbE_5|9;&`zd3k@m5)Wlv1vr_h%D zGvO0x%l?_L*)K~dolKrWdn#?S$B|HqcX#72p>#U!6KSW@omk9(st6$rJYCHMcYj~ zpLPN5LfRhM7tqGG5&jZNy|jyH`)K=V2WVeNJ4ic3J50Nn_IlbIXqV95NE=&J_)93g znD!>xm(czL?LX2krF|*w%V=+=T}JzI+FNK}LA#vxR@zt6zKV7Q?W<{DL;G6Vm9(#; zeLd|z(XOI>1MM4W-$c7w+p5%9F*BxtmZ`%LU_)k96 zXnykke|TOgvIPB~p7;Ou_}3q6>i1^achJ6<_5-vZq1{aTS=ukreuMU#wBM!uA??p- ze@Xj0+CR~bJ5KUpmnzYJqckU|1867GK8$uGU*pI}(w;y&h4y6H(`gSqUxJ#Y-R(T9 zQWr7YA821jdkgI=XPfwC|#QFYRr#AEf;-?MG=pLHlXi&l%hDzunGm z)*4DHjVQ{z|3ax~_jm?~b|3R!xSRJl{5l=`e-S?6zi_AXukw>IB>cYj1tifu(ho%9 z$LyE}Vj75PAf|zs24WhBX&|P7mJWVl6H#zN*mRzo&H zY9LQT-iHjgD$5ke?;x8X+aMo74zelBB8U%i4dhXqvUWrIAYzEw4oDZ|TgXAf)v)Q1Y)BY#3#1X!3V8?eEhKS-8a4qk z9darp3$hwg2-yOug49DEhO|IlhP(;sh4evwfQ*V)!^T2VATuHJAvus-NC2`4awVi1 zQV(f{v_am7`~ca1B;rEmK(Zjehxj1nkn16}kVZ%gqyzFkeC^akrG66CjG9Qu+ zITvyP7fRsWiA+?Z)A6 z76jeSuzRK3=W++#!NG1h?vikE(7h<=FIrU`%y;Iw2m7Aw@wxmPj7z55>)aSQ426UK zjf`vD76skzAt@|&hZhEeex7Zq&l5HQv;0oi{AJmWm1i5y_Itex*Smf6KC{>z9GddV zvn6+nJYHta6k~zc?PS_?@CTSZ!CWS+OgJR$jdsfpxXz65kgj;11^dgGGa#LT==6NFcNw zw`mwUV#wl`j;aD&Gu4otz}C~_C&1(3PI zb>a*v@~?LfLYzNBAzvWq@rCmTI10ngymjK|$ai}5SwjOZ1;x%Fa_4Y_!nlNjP=Y@6 z_##LC;xG?`gR+C7`u3r_M6~71%X5oDoMAssA||X{Txif5O6$*q4Rf8Nz#R^IiqJlQ zp@`-3pwZ{~L(1XuhBiXeE~yb1)0M+r;?6@_<}~gSxaTu!e!jOjR0u|zh??(*vc(EQ zY57JAa!{;2(N`cZqJ5Ylw_C!5-IB}v4M9&Bu1Ll0Td(ba2Vud%;*hhzcuA)H`7Y@! z3W@|A$g;;b)9G>r9ZnydJt3E;Ky={=1&V!gIeJ2&fbM&wF-YE^0jD<-+3PP5mx5_& z%27lenR*Aii%`X|*J;%htus3FIeq?+*X@Q9Oku^;Ap+D1+N$oI0>(ce{ai#9fpDQ{ z0gCpy9JxVU2zkyBPBO&ZH2xt@Ay0wN2}KQY+~Aa=4mjzqcptmmXk@6Gi2ntCY2Xnm zDh|6#puE8;7&mDm(cy}Hbk!9ZbV{3&a_Dm7z_hNQI}ddibjyVzHm)dyLw~1DQ?pQM zNNQGWoJe26A<3AKs5@j*4~6oazIUa#4Hd(XS+d$xUjz%U5XrBq}xZa50-AV zY{ZVRcfBLm?++tIXFx^%EDrT~HXu&*RO}CPmp1#fxksC&S7TVU&0nkz$zHj1*}RqK zsBx>#TDfT6f`#hnI8`pb*5wX$+*vtUOP4QHr^TsCxW%bz@fkLM-hwk0uUv7~@=P^y z;mVaOR;mM5sD+V~Rz*@eCr-7$FdDJ;{48dF(@2=@bz*iuC}vH)m{kvtM4F~W-(c~% zH>g`Jx_@|~kC zjtfG5pZZ4J-j~36Vb6NZ9n_B&m&<_}093lw8mF2*kqAv6N|2%e#%AN^cA5D1T5$?o z*bNBUhd?O7M-nvG9p2zZrN3^?^A}@adJFz_J>tK2rN=Z@Q+L3t1*eEp4JeAT=6k$h%ynGq37alZ3;b(7LgMNL9JT3FR=p?T z`(P@Y$xg2=zZf0eXEvQSV)r3%Pq#$-7ISE~r=T#`9}KB?Y%DaI4S-E=BH?)fo<%*n8uGZeKyT z5Nf*&6Lcr8+NL;Mb`Bph5mN8RVIqVc2Qk}!)aGT9&hBsJ zxN?geSA0JTX>JUoIGcqE+S^H19Uiv;6X_3Ha9&Ys(0`}KR35w7Gyf-4^{yE$` z%cY+Baa4D|MBh^{W_vwc*H2eB#>c6~KZ{GFPP}hBQn8uKus&W7C=bT#3$Q63`U#@S zYQPTlM7)Z_pyG4nyVUC=Tz<7B9#hSLADxq`j1Q?d5WL9i2szQ?%iQpl5#fMCeF#_1 zMa<~&*AZcL>BuD>E1XB zHU6gPt_DXt-jcZe!lL4KI5p}M^k|Rjw?v&7Fh3pzErrzwqjcsx`5V>0&^VmIpmU=` z^^KG)J~t}h3_?q9j0&keNT*ZRa9^jKpcSUFIdjpeQ33ajhKkh#qx}W29vO{`SYKHU zPf75qC&jFLS|aHIvwO7koF9$m_=#nl6%~;0Mkk}2+nb~HFswdDLX~@UWSHoMWL&;u zOt9F8*@-`(?iqu^qKifDc3WV!d@W79s(+N#Axiq|7_U#gG6wOGsb|K>TvWY|C}q1O zaCg7dqQj@Y8sn8^%O3c&=t6dtkAZ)UPI$*_l6Q{U_-E$+Jg^9`~K4L;X-+Czo0{PBT8Nn6XZy>R_s^koIYcw zqtIQVuHVlibzF^v+yO^XNZr2Qg~2df>h{CMaR73uFOC|RNE7uKN#vyi@;z=ZCU@pq zc@05J8%3-Ak4aEE_aC5VVn4vQ@m09nu<}NUrPT8Y#U7VqeY$!J&fPyrw5}~u!;M#n*;FcKsjl-* zxajd3Q|m1ULe1+`#eujm;fai@>kkYS=N6$2-VMhx9lQE6iCuZAm~EF!Fj;)I9vJkw zgQy~xr#PfuM(928Lp#!D?PeVgI^BJstQNn5|E@CeuSdR6(HQo^YRf?$mkV`PaS-|) z#K2glbJ~oMDn7RWlVv&8(+6Vk={V5k2|07U7(qWdFkkICuuxrpP(UW4=z8i7!kjj& zwjH#=;|dq5#)HrY0NF>h+O>L+YeqcsV!rCPE454 zfVYncsGVbU_wn7(t3*i`+&2+;N=-aBY@o3d?RMtS7P>k8HYsjHew^f5hz4rs{An7Za~L%&0$!aR2_yc#N&f1 z(THz3%%;ju#rZqu!l*qNM&B&SgL>t#T-9+{f%?Z`LG{jI7(Jeo(xB~1x8hJA9OldS z6sRxZQ~fzkXmg@CwTJoDcZcaSV_gb8qTjnJ2_Zhfj7)X5O7`|@vq77cuZc^eHv3+c zREn_8q#n(o{!M;@d3|glB8FBD+w(+&x56}BZz6UOFfWO z97H>lme-G5H2z!8*0U?l;&8e1oyFd;dgO3i!<(&e?&^`zWiR%Pl@()D$KkRQ@aEx| zqM|1_98*iDBcQqwyzXmEPSh^64XFCBl48dTV(xia%xYb(HggOUIa0TcMb|SHabA)T z%`nCF5x71M*ZNn)wNa;02@{tfRHt4WTb!%@F;>OnqF0xXb$QmStH!!7RM(Bo$2OnC zsOP4!1?v8>UiHjajD#C{GY8Z#SJUp&IwT|L8yX zYQvS1iOy@qY`k2|rmbT3mur_RaODo?X4W0!F(X6*_l$QJ1;QKE_VMU*)I;NCKl)&d^;YsxfkIY9)h3MrANohj*#`PBNDLs2(uzm z&ySaF6NkF}2#g0eNro!^Bxc>s$d*mc-gbnX_thh0LePm&^=0s}VvhOF5hdz#IP7>x z>VLO5+nlQZ2zL>BW;X_&Uyi^fcKMO${GS$;Hr*`=H+>|7eb0w_J|GSANL+nEG(Uu^ zx>M4?rXeoW`;NS@Sf*3z@gu`dr1KK|8y=A}bw4iY^xk9D6YDRIG_xv)bi?Y?BZKY& z*$~2|iOmczI=^oa0Bz_e8cZs;n3nch!Y3>MnxOzX&BN!fsTgraQVI|!q-1V-)>*UHp z{xC*wv+FUs(GK-jiF2NM)Xp*bML2d}BQfeOl_dKAh{Kkx5=zF+UG~94^uH0f`br60 zTP|kjWjY*&=xdLbA^HaFG?ZQ;K79xUmFOY*{-ezh{b%@AmdQ!FFGi4_%MoPX2>p>A zBlOqyff0J^(fR7uqYKqvj*g7bFCMLj-M<}eM(8(=9y~(dY>$l4ci7RQ%m{stUHYQG z*@ukK-F7`fcO8v<{2rO9_ra*foi&*{n&J7K2{Jr?FkxVL{>Oxn>IItN`Nj!mc>Znz zI`g1XqlS*i4sc)NA>FO3za@u*k{ssY>hH;Fj8lDjc&;8k9cHveobM0M zEAW`T!CwxK#B``n$4af}Cai85R~R0=oU9$k;SsAUbZ?IxQKYUqQYNvHQS;6tgX*rM zLh5alp!a!Qf|?QB6WV$#I?gxcnyu)?w89qI8M^k^ft{h-jtvC78!-swVd19tJnlxM zu75~EUF9R7x8K++dgEBLSJZ`|71xYF(1scb8rduQ=~%Nlv-vo*>Tl%y&G$)y?Vk*1 z&hCa!SG&0FdOza!7~DF`Wco8`ujr}cWUuHIcvbvKPE_}(1Q^&W`s6sB=iTtHsYJ2W zS2)_WS5DdXS25e$W#VMAQ<=o6d;F@g4`PE%1=8DvNMO#v2^7Iru>)w+r zmc1t_^?WMl?`Ra4z1t-hLw1aIr|6t~g;+Z-lbr0qQ8Vs$;uJqcig?TMP}M8q*7Y^= zwQtAh!Q%&ZjGB%&J4T-G zHVDFna?`}j#~wc%Bi{`ZeX8w*5_Qug3_$P6nA-e~%0&CW#5R~o;Ss;epk%)x8ZMgs47zjcBnp^Bs)~<+ev13sw`E{_peMfyHhu& z%Kn1col#yG5;_&8rRX;qMwNr~W+hAhz#mtmH zPu1-YW8n{}xc`J3fmck{U7osnvTWs}KmF5WB&^5r>aXH0xJ4riRrTUznV;W086*GS z5TNC?k?4-A(qL3fgNE|Vwy^qqvd@!?rJMR1fjX~{`F{CjGD9|{zj}%+zW+4Ern-{h z)wNk>W34bzMYtIdaH|KW$W}np6kM%4C3Z)zn4S8#|3jo?!*-_Z6TUtrvg7vFlnowK zrCH#F)O(1#y9YaUYA22wb@u{mj%MN&FQ_G)Thgm8o(?VPo~WseaV)WohUNUXi9y^^BM`+s%yS zPPmuv5SPk&i#KV^>dm{H64p=G-H*7 zX+evg_qL0F~L(GPnY{PavwpT>I?BxmhP@-K`FzDi?w}`6y*=IBLHuC4SA98M z-$X1nBj=VA^?e_mP{oNG3UR~I+*-W;L@dJO9_5qMeCmnmxc;h7#Ch)0db$NmC+=W= z4%fCSaqWFn8mrV+|A{hZFG~-|+Ud%4w6X^!K-c}EQoT*7?n(FOULdzTw!^!wPRIX6 zu8pdn#q8ND=I&B)Z~hEdi`h$kIo&9+BV9VEH`C?H=}u=(K0->B9X7PZU6STbNulpb zNulCXeZ7U%?K1{;OzUPqM`p*gGF`9uvARz;*JPw@t?5#lYi5|O)an@_wQUAw%@dJi zKeh^xH53_jbf2ibN*_0Fm*cYS7Op%3h+z?D(}^qym!}$0R6pkvAu(%>Q5wSgEn_d1l;7n&6qD{7GVVP zhSc{n2UY`N*@ymR=6X*EYhZQxNyyRt(k@%;#q7UNR#9>T`q7h$kmW+P9}$(~G+=SDoZn|D1&y8Y_9mD1bG~kuYkGg3)&*k}Whd|GL>` zs($}$v`QVW?FaFmhTizHGZVE22<|)JUjzfgzNqcr{&#n*6Ago@S zgH2lXk2!K1B%~VVc-7N$0v`3!94ztYs9~~;Gn-rQ>do2c2CL@;L;E_Gd*@)7P`l=! zR7c>On|ZDASBAk0UjEW-Qvbm3h*2Uo`BKxms5OB zEShDcM?d()DQKbCqC*AWB<-{lre4UpFyySm_kX4pOSk-Ww6nCX@U? zNZoiU79?^|b1H-1bt-z08ze2X;QCV~35R|#LeKa93f~$e0EI|0afKUmgP5SGUvM_{ z%Bd1i?L2iodU@Oh`V@gXcS;S^^;#^rds2BCb|r8dNY}%^Pr1;czBpCiN4XKV+537W zWF_}E3pO6My^O%^;k4nol+lil^W_B;WK$w2*+uAH)Dqa$^ z=P5DkpA@q}yLaFLNn8YQmunvzJQ-O0V8!-O25!UpTx#cOrV7WU1ve%S5m z4D4HCXCah&WvD6Ev6>ba{ zLbWeupx!4U19g{*I_rKis|dM?`tUrNq&3e&+rx&fvdTRZ_4K?G9g&+SuZq`G(jY5g zqNcFfG7o)PNPPjHhQCX>D&E%SJ7|x{)7JSYDINxe-rf|m?C*#ta~idIzFarg&c}|d zx^=$3;dJMG=_l?(l&TM8YSjCl%=j_e3HveSe|3Ij^3{nDz5kTt8a@>zLU(=h^=9+8 z@M*>@0~f>|nQO>G_{s&ccN9{U3y}Fe607q&G5dcKvu>}LmETJ`cyh{(i?ewFZls0O z(+J=51Kfw1DeS!q%(dIFKu;o|t_5Dzx?qDpi0#-n5xDYO>Cw9vNOyMQ0(nkhbEaGw zxFxlBzF%FPi9YWu$y;@wt@2Oe=2qV`{VNthiMliFyHgS>zg^57cO#U|sPoQ6a><3%eT#hR0fg@B z6)ir3qxvs(ajuaVty{$`tJoLs?L~p0JKs~HK3Ehg&Xb1;)3iwy1p7rd> z^r{;dV%H28L)`(a&6 zeVG?M@xOQB*aH_e_DbTA-72%nD4@qhnPRjN87x1 z$wu56QI{>n;3{`b)dTYiovL%5-da-M%nPgfrRXw_MLu>0s?u4V7( z(wkg%hBEhHKU=DIe&0AfjQhfPb`C`@KLb}wi^Q$fW`oXJQwQ>ao~;!zIm|Yn5n1;< zeTK~a(7)o2_sfXhwO2Z-wms4ec>nghGk9m~C;0Dbmj<@GL#{2^Lcb{scW`gZQZ~I} zdh-mq>9sja?(C|&vuvs*8CtGM#=|E10(=2Zdnd!GdkT#5<6tyRg;6#Y$(iAJSC$^5 z|BaBn;+m(v%Hr1X=4Ce3AQ8JWVDukn(Ko*p=zMR18^uyMO4{Oet6m7{p6?N z)r9Q`)j0{qjuZ)m5#s%2GNa!K&pL6ho(y+0q5O84*-HKqetV9GU(*TjlfLTuTr0E`fWq(T;A{UH5x&SYXj^PX;)-l zq~4cD8|AMup~d3$?j7E5O-f2mmA}kpTS{7TQgUKqvizkbFIf^^GB+a)e=b*AS_OP#gSQn>3NSH!wOe>99SPaM-oB+0vu`HCxJU zm6k^Q+hOUj)ark$SJztFt$o%S{H$edOAtgzMFnuawE>l%^KVClB( zwPt5kS`!16))s4Em&IFYDMw0KsTG#2W4Mkc3Uc} zJ(k4Oe%oGK8BWq@ZLn6@x`tOW1}LG85Zut=8;zYm;?NNtGorF(swm1|!j~|CWfF zBY$>#m(^}h3?wz zu^KE*)|8ZPROuSs5K^ivI2{T*Yp-oq^{{eFa&jvICwD-*9Y_TQ6WdyDYq7Rkt87h{ zeoK0Tr6fHwJtw`+lAeZx%w4wRdP~18wceK6Ybmv4G+M`x@59MvRoiOg`Ye5x)eUGD zbIV3l#5Y>X<2q6Ky_Vh)YkMs1qna&c!#gcWb+$D-P&+l&R$Cw1NT0QKWYX?AHP$6) zgZVJR$3ZXA}}Xlb#HPfi^_J|z|Zt1anuahW~HPC5Q{*jk1++j^|E zmgLl?k%@_kC8)igxbhM8P>Z=zQa6=ZQqx_Ta@FX+)b!-^)YSOIq{LKxUhSBenuxl_ zVMI>MqFk+UEw+XcZPwnn zT1$(iXLwJ1wWWSUuPrenvB8p6X>oZI>nzB_F4V~yTosj;@oUECEUC2CqFIMq;!sOy zdS$5hQcG5Ue9eft&_#N33rd~c5trR*t+nAgDyffauvA&br}mDhu!MKnOjAGsl8ij&$iW{0iRR%K00%t=l~`=*Z8h%z&COcU2?NiDZY zc`AmN;%QX1664nXn6M=up%g52KDmtSC6`Pv{y}mzI#mgOIT;Hg&9{>GOfkHjT!^pn zO895UH76QwC)cMN?k11PGWp}aI^Xa* z^7vfC<>dN2!}pT2-G-kc#}yjxBsX7R_+xUV&+vET4)Ta8CjX@&bA|FLgEH?gA z$qgF}&mp&6W_S^~9FHlP)OR*{EIILQ<9|H4n!Jdd z@{aM(AvcrPlGnUz{ENx)9~$0FUQNC!;@@lh?%Deho!%5`u4~8d`+wiq$1XFX#ODq=6%gBL|hR-2qry0J0+?j58 z19|QY!&i{wW*M#~uO)9MH_SEuPeuF}8h(}RU23?8+;yhmK62yPhHbb7rt9}S!-tT& z$P>toYmEO4@>+-Ch2(@n!#U(ckKwiCaIs+zIpZS3>&eY{oI~`vne4jC@YUo5JcJ_t zHL{_ziza(QKr}Hxc{i^6M z?oPww$rX1Qo(f6t3#D5!hklVwR)$mE=oYM?1 zB)5@s$O-d}zl&VG(C|g%@k`Xvlin(F8aa=gL-vtN$d{1o z$mL}F1tz_!h(GyWatHY_a@;x-zLi`^?j$#mKZ?XB_mTU_Ka!KYCOz9sqp!K-{mE;| zN0Q6PlgRbtlgRDl`Q$$Ga`N~hbH26YY_gvmCYO@y$=8rO$#;;I&!qQfay+?(Jf8eI zIi0+dyoCG>IZWRFB%_a7vYp&YP9^t|=aR?!O@5Y;v&rX@!{h+Dn*0ay4)Rsx9&$A~ zE@0BXmz+d?gq%r!n!K9)3b}&(HaR0?((5I6kiR3RZ#4d+@ocp8Cws_8k*h8-{^{h} zKN`*^Z^9$6(*JnLU0V!qA@A5~_!e?+h2i_jrB@q%HsVk2BG+GI{N>qg$zM92XO;8) zLbg{K9zEOm$K7D~7;+tXDmmjuB>sbjhs`nN>u)rCIC;rKh9{BJA2B?O zTuWX|E_}@R=a5tJ_^ssMNvQSnDArB2a^-X6Uj;B zQ_0!nY;q;pLGB>?$m&v)pUvcW@-^foW#nL1x0y&4AM81G*Ctn=l zS4{lt$tmPoavHgTJd3=8oI!qtyoCHVIh(wjyqf$Ac`Z3%o+)o3*-j3Sr;;farE{ca*xk}D#7obkVvTut5<;p2_}ljK_R%jA0UTM?dN z!v8bEvkiY2;ZqF9%{Tg}zr=6?xsg1c+)TDAr4GP@`fJ&~63K<+qsamC6mkhUgIr2p zNiHWl$(7^)xtjb(VT)2(JI(lnZ7|IxzZkxa96s0ZgOTtn4L?O*bGG5Xk;ms4evh1Z zj^QuKZJ!zbfn5Hj;r);o$xqK$h9{EOeqnevIsI$Hc^>nZw-0v=O+JH7U}p) zn7>kT75y=d)c$>BOv5zSF@MjIn|Qw0$>mJ%6LJa9ACCt#b^Vj^0~XC|82&`Eo&LBn zul>ic{J$qFh7XYgADQy}fn4)}VKh4(zx6}I*OBAc{_c!~Z#Mo9kyk%u_-S%G`ETT` zXN~{cWbc!Pd&w1e^cmHJ7iF09Cp>T1in)@MKaTDFVDj#N8~^4~}9Cik*D zyUDGbPyawp*=^DrgXaV!ehzseIgWf1dHlaj_yrMv>L-WX#qjy$2J(9H62{*`E~Wp? z1UGnC$D9DK8oD% zzA5iya@Bi==a7@xo=+zy{A~QsiTIPf-^%S zDZ2gML0-f7cHU-3k6+iI*y>wy8ud2}b8FGZT=vHYlat6t zlhbyY_^IS>wvSWDt8J#f&LlUI^T_GS_^&4`)-PT$sn6fZ@VAju>HiS9jQ)59r4FBD zG3k9ku4MZ7ZMF7qvl{;cFjtrI?I9mat|reW*D^i4%2J0fq`#A#!t<{u_cDA1IiBag zgFK7zABiya)kCQ6sF_xS}P9fv1Rl2@U zB)82n;ZG)~-D38`=aIwQf5xjgb^3LgCcJ~ZWQpMm$zvFPGdb}llU^mc?I3ghYVs_X ziGMG-851FCkB^aih;hE%|35FMwH<8aKr;Fef`q#J7`{6a{xZXOwXBZcRA%@Ya+us63BTF+za0sGmeDU>MXTdyoNE}b zrPZ8tj^RXd0~Q)mpOeUCSDExqB3EoRyntLseXk&=Fu!M$cT}77++;8Pi^#5{jQ=I% zrt3`lTgmAhA8#i2G@AChom^FE!aquGxY?wK7Z>UB^;Ma>_)*o5^1K-$KsBKAwbcBD=6}Df}AQ&hvjl zPFQ686}oo0KKGt(IEn1SzKq15MlM`x_zZIU62mTX9OM6iyk@cSzm;5!IRM^=)vPciMyO>Sj>ToPfGR_Qv%cpN#E=bJ*Ve8Tvj zLeAp-`sL*2gH8G_a^as%_!9DJEaXLB*O7CqhHod2Z!_T=$rUddeubPo&V>JntmHlE zNbd`B;nRk#*Z`9HXuHdBB01|`!^e~BrkM0jA(uU9{8y5D@S7A#-$9=Htl=OzJITbq zp1k)E!`sNE%+KTGS&7E~Z{&uFhI`0ekDK(rj>IoCyeGmBnfCTGx%XkiBMvd;UEOH- z5V9g4LoQ=~IgMQ9GwGj3o>gRc8F>f&&m$*1VbaehZ)!5^kMLg%UqUWp_$$aI+l_xE zxxK;gE#&G43~v+09HN%{Yfa>O@-yT{@~h-#@>}EZ;a(2*g1-X;qZzuON{9nk8^naGzK>v1f3e$U^T*&ZWlRFsRc9_ve2L0{iz2pyhVYrx_P-XZEa{TRvYsl%i?nR$>lbdIm_S;Af*bToxPCC}` zJLEl_|9wU7B9BJBO8fA#{U1(tU1ZKTk(|Tlv1XFH`TSM}xs1(?%ZyBr?c-JQro)VX54kJR@Ym$zgA9*2 z+>}3ImnrXo5xo$!o~{tBijUxpleWOUSdx zTgknQe+xN*^Y;hHW#nhbS>!j!IcrUO>L$07KOrY$9U%JJEsXxVgZ=Ff^v}e+Q~XDd zGy16^+sOfPx-jB*G5!Mjw_%}lXJ;Qj2|RtvVXsr93YpG+qk~{6S@3Cqrcn8 zY2z0_lHB$%l}=

    t>Nv1w# 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 TKTp;FZu8I2ygPrX-Ddl5_hi;r literal 0 HcmV?d00001 diff --git a/ui/examples/native-hello/build/native_hello.c b/ui/examples/native-hello/build/native_hello.c new file mode 100644 index 0000000..050d56a --- /dev/null +++ b/ui/examples/native-hello/build/native_hello.c @@ -0,0 +1,123 @@ +#include +#include +#include "el_runtime.h" + +el_val_t on_greet_click(el_val_t widget, el_val_t data); +el_val_t on_counter_click(el_val_t widget, el_val_t data); +el_val_t on_name_change(el_val_t widget, el_val_t data); +el_val_t app_build(el_val_t window); + +el_val_t g_window; +el_val_t g_label; +el_val_t g_input; +el_val_t g_button; +el_val_t g_counter; +el_val_t g_counter_lbl; +el_val_t manifest_env; +el_val_t manifest_path; +el_val_t win; +el_val_t g_window; + +el_val_t on_greet_click(el_val_t widget, el_val_t data) { + el_val_t name = widget_get_text(g_input); + el_val_t greeting = ({ el_val_t _if_result_1 = 0; if ((str_len(name) > 0)) { _if_result_1 = (el_str_concat(el_str_concat(EL_STR("Hello, "), name), EL_STR("!"))); } else { _if_result_1 = (EL_STR("Hello, World!")); } _if_result_1; }); + widget_set_text(g_label, greeting); + return 0; +} + +el_val_t on_counter_click(el_val_t widget, el_val_t data) { + el_val_t g_counter = (g_counter + 1); + widget_set_text(g_counter_lbl, el_str_concat(EL_STR("Clicks: "), int_to_str(g_counter))); + return 0; +} + +el_val_t on_name_change(el_val_t widget, el_val_t data) { + el_val_t has_text = (str_len(data) > 0); + widget_set_disabled(g_button, !has_text); + return 0; +} + +el_val_t app_build(el_val_t window) { + el_val_t root = vstack(0); + widget_set_padding_all(root, 24); + widget_set_bg_color_hex(root, EL_STR("#0f172a")); + widget_set_flex(root, 1); + el_val_t title = label(EL_STR("el-native \xe2\x80\x94 native widget demo")); + style_label_heading(title); + widget_add_child(root, title); + el_val_t gap1 = label(EL_STR("")); + widget_set_height(gap1, 16); + widget_add_child(root, gap1); + el_val_t subtitle = label(EL_STR("AppKit controls from el code, no ObjC in the app layer.")); + style_label_muted(subtitle); + widget_add_child(root, subtitle); + el_val_t gap2 = label(EL_STR("")); + widget_set_height(gap2, 24); + widget_add_child(root, gap2); + el_val_t input_row = hstack(8); + el_val_t name_label = label(EL_STR("Name:")); + style_label_body(name_label); + widget_set_width(name_label, 60); + el_val_t input = text_field(EL_STR("Enter your name\xe2\x80\xa6")); + style_label_body(input); + widget_set_flex(input, 1); + widget_on_change(input, EL_STR("on_name_change")); + el_val_t g_input = input; + el_val_t greet_btn = button(EL_STR("Greet")); + style_button_primary(greet_btn); + widget_set_disabled(greet_btn, 1); + widget_on_click(greet_btn, EL_STR("on_greet_click")); + el_val_t g_button = greet_btn; + widget_add_child(input_row, name_label); + widget_add_child(input_row, input); + widget_add_child(input_row, greet_btn); + widget_add_child(root, input_row); + el_val_t gap3 = label(EL_STR("")); + widget_set_height(gap3, 12); + widget_add_child(root, gap3); + el_val_t greeting = label(EL_STR("Waiting for name\xe2\x80\xa6")); + style_label_body(greeting); + widget_set_color_hex(greeting, EL_STR("#60a5fa")); + widget_set_font(greeting, EL_STR("system"), 16, 1); + el_val_t g_label = greeting; + widget_add_child(root, greeting); + el_val_t gap4 = label(EL_STR("")); + widget_set_height(gap4, 24); + widget_add_child(root, gap4); + el_val_t counter_row = hstack(12); + el_val_t counter_lbl = label(EL_STR("Clicks: 0")); + style_label_body(counter_lbl); + el_val_t g_counter_lbl = counter_lbl; + el_val_t counter_btn = button(EL_STR("Click me")); + style_button_primary(counter_btn); + widget_on_click(counter_btn, EL_STR("on_counter_click")); + widget_add_child(counter_row, counter_lbl); + widget_add_child(counter_row, counter_btn); + widget_add_child(root, counter_row); + widget_add_child(window, root); + return 0; +} + +int main(int _argc, char** _argv) { + el_runtime_init_args(_argc, _argv); + g_window = (-1); + g_label = (-1); + g_input = (-1); + g_button = (-1); + g_counter = 0; + g_counter_lbl = (-1); + native_init(); + manifest_env = env(EL_STR("EL_MANIFEST")); + manifest_path = ({ el_val_t _if_result_2 = 0; if ((str_len(manifest_env) > 0)) { _if_result_2 = (manifest_env); } else { _if_result_2 = (EL_STR("manifest.el")); } _if_result_2; }); + win = window_from_manifest(manifest_path); + g_window = win; + if (win < 0) { + println(EL_STR("Error: failed to create window. Is EL_TARGET_MACOS defined?")); + exit_program(1); + } + app_build(win); + window_show(win); + native_run_loop(); + return 0; +} + diff --git a/ui/examples/native-hello/build/native_hello.o b/ui/examples/native-hello/build/native_hello.o new file mode 100644 index 0000000000000000000000000000000000000000..c4de3f0a4fc76a9116ecbd98f34ea9aaace55907 GIT binary patch literal 6192 zcmb7|YitzP700hx45rYK6bH;BFcey#*v8A#Jhs@ZjqP}`ky#!IEW_G6_HHw~v)vu@ zkZEPK`9Kt@HHb<`Ma^1$#70y~CDb^dVu>nBC8Q7%wW!U9HOYrX0u@v~tSemlKXcEF z$Ac=hBgVh;Klj{oUo&^-^4Y&0{d<8BWdaxdnT>ml31dCs_NUGyQZZExHMz@+G#FfY>#q>w^W@kn779@=eKS&S zhOY{@Y~|6b2?WuH$Cl#fmY%PwK) zLltG>62>s;*z;ZXLNS@ottt)sR+VIV!=xy~EyR_4Ze{8D5-LAgB8~DVHDw}RUqzqQ#*+tseQ#OOH}5*yxja3W$Vu&@9nA5Q2TNp38Dgld zg0Eq6YGB{!bBx0pSFZf?XGZ1d)WEA)oAT+g$u?eGrychAFjmi+Ictfzb!^PJV=s5v zt6cUPm%YwqZ*Ta^zI*I30*0I+ppId=ECtP`?ZReTT zO?^R(&lSVAC>y*>ZDEbC({nSDTh4iwBmOws$4eLH%D4iaVXJSsWoYwFt9)V$^4m6^ zb=xj1r+jagMtsX;p4?K@dBatQ?NwAq+9TkIkK&GFoZLRyoZs?uEY0gM%BVl~So66m z)ICrJ#bICegF1Z~SY zWKVF6oCDiW{gcmJp_AUb!=ulPF!q#k`R)a2PnkVBh4tGu+#TG^BkM`b9 zZ7XtyT?+)#Et(vYI)rwdx*g9%t^w??<)Dt~# zWp^oJO;cQFqIx7Wo8ULtMq1! zq@w9?#I$N9WhkB9KME>|lw!s;C7Mnvdi0!@sTCd3q_#^mr%WxQoHP0}NS@U05B^RV zDV0pMCmv1pX`&^gX(l=Q$WVKzhvH~7Vd5)8={2V7t=V1|-PRiw*>hP_OFBcTla`Xy zC`pgePc3qq=8$@zv7>E&^P#XvMpKDiEo;_lx@gX1jLa^jH=5A3m|_}APezNHnnIr- z#+h2BEvukvxUs9HIgAX!&O?}t-b6}^?Zs@nu5oGOahQ3Hv(zPDD6huC()HiUuX6c$ ze8{~lKM!RE{#(f(Kc-vIZ(pJ)G7kot8IYy!`NuY++AuVPIYT!bzjlnk_j-+^wD4D114fv%Sf z)PZ=PLe-LiwIGfJAw@D!1-=AbDH&J*ejB<%G9bVO(9iJRfq|zW&Jdx;l7S+Ky*>1e zWZ)}s9yFb+z`z|4`+4ZLWZ+LAjyR!l$-o$hS1NQteIFJh9B zCXn8@DzF_~0Imn|dqd}#n#Y2K&>u=h?tpldLboLYH$bYF2kCvfCK)k7%A+&GAhm{3s)BpFjV`ASijGDoV7il?~}%DpU3IFTZlQgf2VZVr0w6OKeHaUW=DvRShE!Leo}ljZn|DZ zZkWCbDa9u!ck3@a`nMka505T*^oJf@=4tN;8sn~5J)pk1H3_$V2T^W4;3*GF?Tn}1 zqpy4P2Qr@%KkO+#?J1{y2mhSwdmjC3j~+xMTuy#^R@}NE%kfuUK~MdY9-Z-M$Qk`v z;?b|k_Bgu`Kk?`vd-Ow3e$`X{o+tliPx;?H^$&XD@f$d!zeAq-8$9KodGsTXe#g_^ z&phSydx3w>)hD&H9v^w)6CN$pta(n?)b4)M#8+-QlSoE0=WMSY?bdX)+lavYBp}15o#aOkrb-^^{i^C(=&2f|G#Lric^F9 z4@cBYq|*H+g9YRnkVb!7Yhc$+{mgtMah4JA(9?{WMPgKeb zKJ*hfMo<+sn(505m}uUhK%uL(1oVSX1WpsEr|O20rZPF5g61=2>M5(YG}Z)6YEIW+ zXlKztI%D)@qRAOOPe)@h98%P%u2V8=6~m^o7!{*ddy;pY_uEaD4~Ws+nYPo&JOipSKEQct~YFtM>cnLb#~chh~C%Yh{NGf zTSv1aJJdsmyY@E*9gj!uYYeuxbafu?XyOI0_3yMT$MDzNF30fiuw9Pf-)_4c!@tdT sIfj3$?Q#tN7TX2GOr|&6((hO>P~f)/dev/null; then + ELC="elc" +elif [ -x "${EL_LANG_ROOT}/dist/platform/elc" ]; then + ELC="${EL_LANG_ROOT}/dist/platform/elc" +else + echo "Error: elc not found. Add it to PATH or place at:" + echo " ${EL_LANG_ROOT}/dist/platform/elc" + exit 1 +fi + +# ── Step 1: Generate C sources ──────────────────────────────────────────────── +echo "==> Generating C sources with elc..." +mkdir -p "${DOCKER_CTX}/runtime" + +# App +EL_MANIFEST="${SCRIPT_DIR}/manifest.el" \ + "${ELC}" "${SCRIPT_DIR}/src/main.el" > "${DOCKER_CTX}/native_hello.c" + +# Vessel +"${ELC}" "${EL_NATIVE_VESSEL}" > "${DOCKER_CTX}/el_native_vessel.c" + +# Vessel header (declarations only — stop before first function body) +"${ELC}" --emit-header "${EL_NATIVE_VESSEL}" \ + | awk 'BEGIN{in_body=0} /^[a-zA-Z_].+\)[[:space:]]*\{/ {in_body=1} !in_body{print}' \ + > "${DOCKER_CTX}/el_native_vessel.h" + +# Runtime C sources +cp "${EL_RUNTIME}/el_gtk4.c" \ + "${EL_RUNTIME}/el_seed.c" \ + "${EL_RUNTIME}/el_seed.h" \ + "${EL_RUNTIME}/el_runtime.c" \ + "${EL_RUNTIME}/el_runtime.h" \ + "${EL_RUNTIME}/el_native_target.h" \ + "${DOCKER_CTX}/runtime/" + +echo "==> C sources ready in ${DOCKER_CTX}/" + +mkdir -p "${BUILD_DIR}" + +# ── Step 2: Docker build (ARM64) ───────────────────────────────────────────── +if [ "${BUILD_ARM64}" -eq 1 ]; then + echo "==> Building Linux ARM64 image..." + docker build \ + --platform linux/arm64 \ + -f "${SCRIPT_DIR}/Dockerfile.linux-gtk4" \ + --tag el-native-linux-gtk4-arm64 \ + "${DOCKER_CTX}/" + + echo "==> Extracting ARM64 binary..." + docker create --name el-extract-arm64 el-native-linux-gtk4-arm64 + docker cp el-extract-arm64:/build/native-hello-linux "${BUILD_DIR}/native-hello-linux-arm64" + docker rm el-extract-arm64 + + echo "==> ARM64 binary: ${BUILD_DIR}/native-hello-linux-arm64" + file "${BUILD_DIR}/native-hello-linux-arm64" +fi + +# ── Step 3: Docker build (x86_64) ──────────────────────────────────────────── +if [ "${BUILD_X86}" -eq 1 ]; then + echo "==> Building Linux x86_64 image (QEMU emulation — slower)..." + docker build \ + --platform linux/amd64 \ + -f "${SCRIPT_DIR}/Dockerfile.linux-gtk4" \ + --tag el-native-linux-gtk4-x86_64 \ + "${DOCKER_CTX}/" + + echo "==> Extracting x86_64 binary..." + docker create --name el-extract-x86 el-native-linux-gtk4-x86_64 + docker cp el-extract-x86:/build/native-hello-linux "${BUILD_DIR}/native-hello-linux-x86_64" + docker rm el-extract-x86 + + echo "==> x86_64 binary: ${BUILD_DIR}/native-hello-linux-x86_64" + file "${BUILD_DIR}/native-hello-linux-x86_64" +fi + +echo "" +echo "==> Done. Binaries in ${BUILD_DIR}/" +ls -lh "${BUILD_DIR}"/native-hello-linux-* 2>/dev/null || true diff --git a/ui/examples/native-hello/manifest.el b/ui/examples/native-hello/manifest.el new file mode 100644 index 0000000..859274c --- /dev/null +++ b/ui/examples/native-hello/manifest.el @@ -0,0 +1,19 @@ +package "native-hello" { + version "0.1.0" + description "Minimal native UI test for the el native widget system." + authors ["Neuron Technologies"] + edition "2026" +} + +build { + entry "src/main.el" + target "debug" +} + +app { + window_title "Hello from el-native" + window_width 480 + window_height 320 + min_width 360 + min_height 240 +} diff --git a/ui/examples/native-hello/src/App.el b/ui/examples/native-hello/src/App.el new file mode 100644 index 0000000..6b05afb --- /dev/null +++ b/ui/examples/native-hello/src/App.el @@ -0,0 +1,141 @@ +// App.el — native-hello root component. +// +// Demonstrates the el-native widget system: +// - Window created from manifest.el +// - VStack layout +// - Label, Button, TextField +// - Click and change event callbacks +// - Style token application +// +// This is the manual API that the el-ui-compiler's native codegen target will +// eventually emit. For now it shows exactly what apps (and the compiler) need +// to produce. + +import "../../vessels/el-native/src/main.el" + +// ── State ───────────────────────────────────────────────────────────────────── + +// Global state — holds the widget handles so callbacks can reference them. +// In a real component system, these would be scoped to the component instance. + +let g_window: Int = -1 +let g_label: Int = -1 +let g_input: Int = -1 +let g_button: Int = -1 +let g_counter: Int = 0 +let g_counter_lbl: Int = -1 + +// ── Callbacks ───────────────────────────────────────────────────────────────── +// +// Callbacks must be top-level functions with the signature: +// fn name(widget: Int, data: String) -> Void +// The C bridge resolves them by symbol name via dlsym. + +fn on_greet_click(widget: Int, data: String) -> Void { + let name: String = widget_get_text(g_input) + let greeting: String = if str_len(name) > 0 { + "Hello, " + name + "!" + } else { + "Hello, World!" + } + widget_set_text(g_label, greeting) +} + +fn on_counter_click(widget: Int, data: String) -> Void { + let g_counter = g_counter + 1 + widget_set_text(g_counter_lbl, "Clicks: " + int_to_str(g_counter)) +} + +fn on_name_change(widget: Int, data: String) -> Void { + // Enable the greet button only when there is text in the field. + // (data is the current text value) + let has_text: Bool = str_len(data) > 0 + widget_set_disabled(g_button, !has_text) +} + +// ── App build ───────────────────────────────────────────────────────────────── + +fn app_build(window: Int) -> Void { + // Root vertical stack — full-window content. + let root: Int = vstack(0) + widget_set_padding_all(root, 24) + widget_set_bg_color_hex(root, "#0f172a") + widget_set_flex(root, 1) + + // Title label. + let title: Int = label("el-native — native widget demo") + style_label_heading(title) + widget_add_child(root, title) + + // Spacer (empty label acts as a gap). + let gap1: Int = label("") + widget_set_height(gap1, 16) + widget_add_child(root, gap1) + + // Subtitle. + let subtitle: Int = label("AppKit controls from el code, no ObjC in the app layer.") + style_label_muted(subtitle) + widget_add_child(root, subtitle) + + // Divider gap. + let gap2: Int = label("") + widget_set_height(gap2, 24) + widget_add_child(root, gap2) + + // Name input row. + let input_row: Int = hstack(8) + let name_label: Int = label("Name:") + style_label_body(name_label) + widget_set_width(name_label, 60) + + let input: Int = text_field("Enter your name…") + style_label_body(input) + widget_set_flex(input, 1) + widget_on_change(input, "on_name_change") + let g_input = input // stash handle + + let greet_btn: Int = button("Greet") + style_button_primary(greet_btn) + widget_set_disabled(greet_btn, true) // disabled until name is typed + widget_on_click(greet_btn, "on_greet_click") + let g_button = greet_btn + + widget_add_child(input_row, name_label) + widget_add_child(input_row, input) + widget_add_child(input_row, greet_btn) + widget_add_child(root, input_row) + + // Greeting output label. + let gap3: Int = label("") + widget_set_height(gap3, 12) + widget_add_child(root, gap3) + + let greeting: Int = label("Waiting for name…") + style_label_body(greeting) + widget_set_color_hex(greeting, "#60a5fa") + widget_set_font(greeting, "system", 16, true) + let g_label = greeting + widget_add_child(root, greeting) + + // Counter row. + let gap4: Int = label("") + widget_set_height(gap4, 24) + widget_add_child(root, gap4) + + let counter_row: Int = hstack(12) + + let counter_lbl: Int = label("Clicks: 0") + style_label_body(counter_lbl) + let g_counter_lbl = counter_lbl + + let counter_btn: Int = button("Click me") + style_button_primary(counter_btn) + widget_on_click(counter_btn, "on_counter_click") + + widget_add_child(counter_row, counter_lbl) + widget_add_child(counter_row, counter_btn) + widget_add_child(root, counter_row) + + // Attach root to window. + widget_add_child(window, root) +} diff --git a/ui/examples/native-hello/src/main.el b/ui/examples/native-hello/src/main.el new file mode 100644 index 0000000..4e133f9 --- /dev/null +++ b/ui/examples/native-hello/src/main.el @@ -0,0 +1,43 @@ +// main.el — Entry point for native-hello. +// +// Boot sequence: +// 1. Initialize the native widget system. +// 2. Read the manifest.el app{} block for window config. +// 3. Create the window. +// 4. Build the widget tree (App.el: app_build). +// 5. Show the window. +// 6. Start the run loop (never returns). + +import "App.el" + +// ── Boot ────────────────────────────────────────────────────────────────────── + +native_init() + +// Determine the manifest path relative to where we are invoked. +// When running from the example directory: manifest.el is at ./manifest.el. +// When invoked from elsewhere: pass EL_MANIFEST env var. +let manifest_env: String = env("EL_MANIFEST") +let manifest_path: String = if str_len(manifest_env) > 0 { + manifest_env +} else { + "manifest.el" +} + +// Create window from manifest. +let win: Int = window_from_manifest(manifest_path) +let g_window = win + +if win < 0 { + println("Error: failed to create window. Is EL_TARGET_MACOS defined?") + exit_program(1) +} + +// Build the widget tree. +app_build(win) + +// Show the window. +window_show(win) + +// Hand control to AppKit. Never returns. +native_run_loop() diff --git a/ui/examples/profile-card/manifest.el b/ui/examples/profile-card/manifest.el new file mode 100644 index 0000000..00d69ec --- /dev/null +++ b/ui/examples/profile-card/manifest.el @@ -0,0 +1,25 @@ +package "profile-card" { + version "0.1.0" + description "el-ui profile card example — styling, layout, i18n, config, auth" + authors ["Neuron Technologies"] + edition "2026" +} + +build { + entry "src/App.el" + target "debug" +} + +dependencies { + el-style { path "../../vessels/el-style" } + el-layout { path "../../vessels/el-layout" } + el-i18n { path "../../vessels/el-i18n" } + el-config { path "../../vessels/el-config" } + el-secrets { path "../../vessels/el-secrets" } +} + +app { + window_title "Profile Card" + window_width 800 + window_height 600 +} diff --git a/ui/tools/dist/el-ui-native-codegen b/ui/tools/dist/el-ui-native-codegen new file mode 100755 index 0000000..97ced9d --- /dev/null +++ b/ui/tools/dist/el-ui-native-codegen @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +# el-ui-native-codegen — el-ui component DSL → el-native API calls +# Auto-generated by build.sh — do not edit. +exec python3 "/Users/will/Development/neuron-technologies/foundation/el/ui/tools/native-codegen/el_ui_native_codegen.py" "$@" diff --git a/ui/tools/native-codegen/build.sh b/ui/tools/native-codegen/build.sh new file mode 100755 index 0000000..47a227c --- /dev/null +++ b/ui/tools/native-codegen/build.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# build.sh — Package el_ui_native_codegen.py as a self-contained executable. +# +# Usage: +# ./build.sh # creates dist/el-ui-native-codegen +# ./build.sh test # run against test fixtures +# ./build.sh clean # remove build artifacts +# +# The output is a plain shell wrapper that invokes the Python script with +# the correct path. No dependencies beyond Python 3 (guaranteed available). +# +# The dist binary can be called as: +# el-ui-native-codegen App.el # writes to stdout +# el-ui-native-codegen App.el -o generated.el # writes to file +# el-ui-native-codegen App.el --vessel-path ../../vessels/el-native/src/main.el + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DIST_DIR="${SCRIPT_DIR}/../dist" +BINARY="${DIST_DIR}/el-ui-native-codegen" +PY_SCRIPT="${SCRIPT_DIR}/el_ui_native_codegen.py" + +build() { + mkdir -p "${DIST_DIR}" + + echo "==> Creating ${BINARY}..." + cat > "${BINARY}" < Done: ${BINARY}" +} + +test_codegen() { + build + echo "" + echo "==> Running test: test_app.el" + echo "────────────────────────────────────────" + "${BINARY}" "${SCRIPT_DIR}/test_app.el" + echo "" + echo "==> Running test: test_native_hello.el" + echo "────────────────────────────────────────" + "${BINARY}" "${SCRIPT_DIR}/test_native_hello.el" + echo "" + echo "==> All tests passed." +} + +clean() { + rm -f "${BINARY}" + echo "Cleaned." +} + +case "${1:-build}" in + build) build ;; + test) test_codegen ;; + clean) clean ;; + *) echo "Usage: $0 [build|test|clean]"; exit 1 ;; +esac diff --git a/ui/tools/native-codegen/el_ui_native_codegen.py b/ui/tools/native-codegen/el_ui_native_codegen.py new file mode 100644 index 0000000..f041f97 --- /dev/null +++ b/ui/tools/native-codegen/el_ui_native_codegen.py @@ -0,0 +1,822 @@ +#!/usr/bin/env python3 +""" +el_ui_native_codegen.py — el-ui component → el-native codegen pass. + +Reads a .el component file using the el-ui native component DSL and emits +valid el code that calls the el-native vessel API (vstack, label, button, +widget_set_text, etc.). + +Usage: + python3 el_ui_native_codegen.py # writes to stdout + python3 el_ui_native_codegen.py -o out.el + +The output is a standalone .el file that can be compiled with elc and linked +against the el-native vessel. It is semantically equivalent to what a human +would write by hand (as demonstrated in native-hello/src/App.el). + +Input format (native component DSL): + component App { + state { + counter: Int = 0 + input_text: String = "" + } + + fn increment(widget: Int, data: String) -> Void { + state.counter = state.counter + 1 + } + + template { + +

    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 literal 0 HcmV?d00001 diff --git a/engram/dist/engram.c b/engram/dist/engram.c index 275c694..6bbcf52 100644 --- a/engram/dist/engram.c +++ b/engram/dist/engram.c @@ -23,6 +23,7 @@ el_val_t route_forget(el_val_t method, el_val_t path, el_val_t body); el_val_t route_save(el_val_t method, el_val_t path, el_val_t body); el_val_t route_load(el_val_t method, el_val_t path, el_val_t body); el_val_t route_health(el_val_t method, el_val_t path, el_val_t body); +el_val_t route_emit_ise(el_val_t method, el_val_t path, el_val_t body); el_val_t check_auth_ok(el_val_t method, el_val_t body); el_val_t handle_request(el_val_t method, el_val_t path, el_val_t body); @@ -115,7 +116,7 @@ el_val_t route_create_node(el_val_t method, el_val_t path, el_val_t body) { node_type = EL_STR("Memory"); } el_val_t salience = json_get_float(body, EL_STR("salience")); - if (str_eq(salience, el_from_float(0.0))) { + if (salience == el_from_float(0.0)) { salience = el_from_float(0.5); } el_val_t id = engram_node(content, node_type, salience); @@ -205,7 +206,7 @@ el_val_t route_create_edge(el_val_t method, el_val_t path, el_val_t body) { relation = EL_STR("associates"); } el_val_t weight = json_get_float(body, EL_STR("weight")); - if (str_eq(weight, el_from_float(0.0))) { + if (weight == el_from_float(0.0)) { weight = el_from_float(0.5); } engram_connect(from_id, to_id, weight, relation); @@ -276,6 +277,19 @@ el_val_t route_health(el_val_t method, el_val_t path, el_val_t body) { return 0; } +el_val_t route_emit_ise(el_val_t method, el_val_t path, el_val_t body) { + el_val_t content = json_get_string(body, EL_STR("content")); + if (str_eq(content, EL_STR(""))) { + return err_json(EL_STR("missing content")); + } + el_val_t sal = el_from_float(0.3); + el_val_t imp = el_from_float(0.3); + el_val_t conf = el_from_float(0.8); + el_val_t id = engram_node_full(content, EL_STR("InternalStateEvent"), EL_STR("state-event"), sal, imp, conf, EL_STR("Episodic"), EL_STR("[\"internal-state\",\"InternalStateEvent\"]")); + return el_str_concat(el_str_concat(EL_STR("{\"ok\":true,\"id\":\""), id), EL_STR("\"}")); + return 0; +} + el_val_t check_auth_ok(el_val_t method, el_val_t body) { el_val_t key = env(EL_STR("ENGRAM_API_KEY")); if (str_eq(key, EL_STR(""))) { @@ -299,6 +313,9 @@ el_val_t handle_request(el_val_t method, el_val_t path, el_val_t body) { return route_health(method, path, body); } } + if (str_eq(method, EL_STR("POST")) && str_eq(clean, EL_STR("/api/neuron/state-events"))) { + return route_emit_ise(method, path, body); + } if (!check_auth_ok(method, body)) { return err_json(EL_STR("unauthorized")); } diff --git a/engram/src/server.el b/engram/src/server.el index ebaf34a..35cc61f 100644 --- a/engram/src/server.el +++ b/engram/src/server.el @@ -206,6 +206,37 @@ fn route_health(method: String, path: String, body: String) -> String { "{\"status\":\"ok\",\"engine\":\"engram-runtime-native\"}" } +// route_emit_ise — write an InternalStateEvent node from the soul daemon. +// +// Endpoint: POST /api/neuron/state-events +// Body: {"content": ""} +// +// Auth: exempt (internal endpoint, soul daemon on same host, no _auth needed). +// The soul's ise_post() sends {"content":"..."} without _auth; enforcing auth +// here would silently drop all heartbeat/curiosity ISEs. Unauthenticated POST +// to this endpoint is acceptable: ISE writes are observability-only, append-only, +// and come from a trusted process on localhost. +// +// Salience/importance set to match engram_node_full ISE defaults used by the +// in-process fallback path in awareness.el (salience=0.3, importance=0.3, +// confidence=0.8, tier=Episodic). High temporal_decay_rate (1.617) — ISEs +// are inherently transient; they should decay faster than structural knowledge. +// (2026-06-26 self-review: added this route after discovering ise_post was +// silently failing — the soul posts here but the endpoint didn't exist.) +fn route_emit_ise(method: String, path: String, body: String) -> String { + let content: String = json_get_string(body, "content") + if str_eq(content, "") { return err_json("missing content") } + let sal: Float = 0.3 + let imp: Float = 0.3 + let conf: Float = 0.8 + let id: String = engram_node_full( + content, "InternalStateEvent", "state-event", + sal, imp, conf, + "Episodic", "[\"internal-state\",\"InternalStateEvent\"]" + ) + "{\"ok\":true,\"id\":\"" + id + "\"}" +} + // ── Auth ────────────────────────────────────────────────────────────────────── fn check_auth_ok(method: String, body: String) -> Bool { @@ -232,6 +263,11 @@ fn handle_request(method: String, path: String, body: String) -> String { } } + // ISE posting is auth-exempt (internal soul daemon, same host, no _auth key) + if str_eq(method, "POST") && str_eq(clean, "/api/neuron/state-events") { + return route_emit_ise(method, path, body) + } + // Auth (when ENGRAM_API_KEY is set) if !check_auth_ok(method, body) { return err_json("unauthorized") diff --git a/lang/releases/v1.0.0-20260501/el_runtime.c b/lang/releases/v1.0.0-20260501/el_runtime.c index 0ba1432..831e016 100644 --- a/lang/releases/v1.0.0-20260501/el_runtime.c +++ b/lang/releases/v1.0.0-20260501/el_runtime.c @@ -5470,7 +5470,23 @@ void el_cgi_init(el_val_t name, el_val_t dharma_id, el_val_t principal, #define ENGRAM_WM_THRESHOLD 0.15 #define ENGRAM_WM_DECAY 0.7 #define ENGRAM_SUPPRESSION_BREAKTHROUGH 5 -#define ENGRAM_BREAKTHROUGH_WEIGHT 0.25 +/* ENGRAM_BREAKTHROUGH_WEIGHT: lowered 0.25→0.10 (2026-06-26 self-review). + * With 0.25, Knowledge nodes (threshold 0.20) promoted at 0.21 decay to 0.147 + * in one call — below the breakthrough floor — and lose their WM slot to fresh + * breakthrough nodes at 0.25. Natural promotion was invisible: 524/525 WM + * nodes were all at the 0.25 breakthrough floor. With 0.10, all per-type + * thresholds (minimum 0.15 for Canonical) exceed the floor, so naturally- + * promoted nodes survive multiple decay cycles before losing out to fresh + * breakthrough candidates. Invariant: BREAKTHROUGH_WEIGHT < min(type_thresholds). */ +#define ENGRAM_BREAKTHROUGH_WEIGHT 0.10 +/* ENGRAM_WM_CAP: hard limit on concurrent working-memory nodes (2026-06-26 + * self-review). Without this, broad curiosity seeds promote 500+ nodes + * simultaneously — wm_avg_weight collapses to 0.25 (all at breakthrough floor), + * goal-bias differentiation is lost, and heartbeat ISEs are useless for + * diagnosing WM composition. Cognitive basis: WM capacity is ~4 chunks + * (Cowan 2001); 24 allows richer multi-topic context while preventing flooding. + * Enforced in Pass 4 (per-call) and Pass 5 (global across prior-promoted). */ +#define ENGRAM_WM_CAP 24 #define ENGRAM_INHIBITION_FACTOR 0.1 /* ── Layered consciousness architecture ────────────────────────────────────── @@ -6517,6 +6533,15 @@ static double engram_goal_bias(const EngramNode* n, const char* query) { return bias; } +/* qsort comparator — descending double, used by WM cap enforcement. */ +static int engram_cmp_double_desc(const void* a, const void* b) { + double da = *(const double*)a; + double db = *(const double*)b; + if (da > db) return -1; + if (da < db) return 1; + return 0; +} + el_val_t engram_activate(el_val_t query, el_val_t depth) { EngramStore* g = engram_get(); const char* q = EL_CSTR(query); @@ -6659,6 +6684,19 @@ el_val_t engram_activate(el_val_t query, el_val_t depth) { for (int64_t i = 0; i < g->node_count; i++) { if (!reached[i] || best_bg[i] <= 0.0) continue; EngramNode* n = &g->nodes[i]; + /* InternalStateEvent nodes are observability-only — never admit to WM. + * Their JSON content (curiosity seeds, heartbeat payloads) contains common + * words that trigger lexical seeding (e.g. "knowledge" in curiosity ISEs), + * leading to repeated suppression and eventual breakthrough at the floor. + * ISEs surfacing in context compilation are noise, not signal. Clear their + * suppression_count so they don't build toward breakthrough, then skip. + * (2026-06-26 self-review: SYNAPSE paper confirms WM should hold only + * semantically relevant content, not observability log entries.) */ + if (n->node_type && strcmp(n->node_type, "InternalStateEvent") == 0) { + n->suppression_count = 0; + wm_weights[i] = 0.0; + continue; + } /* Per-type threshold: safety nodes break through more easily. */ double type_threshold = engram_type_threshold(n->node_type, n->tier); /* Goal bias weights the node's relevance to current intent. */ @@ -6710,11 +6748,102 @@ el_val_t engram_activate(el_val_t query, el_val_t depth) { n->suppression_count = 0; } - /* Persist working_memory_weight (post Pass 3) to node store. */ + /* ── PASS 4: WM capacity cap (per-call) ───────────────────────────────── + * Enforce ENGRAM_WM_CAP as a hard upper bound on nodes promoted in this + * activation call. Without this, broad curiosity seeds like "knowledge" + * promote 500+ nodes simultaneously — wm_avg_weight collapses to the + * breakthrough floor, goal-bias differentiation is lost, and working memory + * becomes useless. (Observed 2026-06-26: 525 promoted for "knowledge", + * 524 at breakthrough floor 0.25, 1 natural.) */ + { + int64_t cap_count = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (wm_weights[i] > 0.0) cap_count++; + } + if (cap_count > ENGRAM_WM_CAP) { + double* cap_vals = malloc((size_t)cap_count * sizeof(double)); + if (cap_vals) { + int64_t ci = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (wm_weights[i] > 0.0) cap_vals[ci++] = wm_weights[i]; + } + qsort(cap_vals, (size_t)cap_count, sizeof(double), + engram_cmp_double_desc); + /* cap_vals[ENGRAM_WM_CAP-1] is the smallest weight that still + * fits inside the cap when sorted descending. */ + double cutoff = cap_vals[ENGRAM_WM_CAP - 1]; + free(cap_vals); + /* Count strictly above cutoff. */ + int64_t above = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (wm_weights[i] > cutoff) above++; + } + int64_t at_cutoff_slots = ENGRAM_WM_CAP - above; + /* Evict nodes that don't make the cut. */ + for (int64_t i = 0; i < g->node_count; i++) { + if (wm_weights[i] <= 0.0) continue; /* not promoted */ + if (wm_weights[i] > cutoff) continue; /* above cutoff */ + if (at_cutoff_slots > 0) { + at_cutoff_slots--; + continue; /* fills a slot */ + } + wm_weights[i] = 0.0; /* over cap: evict */ + } + } + /* If malloc failed, skip cap — WM unbounded this call, no corruption. */ + } + } + + /* Persist working_memory_weight (post Pass 4) to node store. */ for (int64_t i = 0; i < g->node_count; i++) { g->nodes[i].working_memory_weight = wm_weights[i]; } + /* ── PASS 5: Global WM cap enforcement ─────────────────────────────────── + * Pass 4 capped this call's candidates. But nodes already in WM from + * prior calls retain their persisted working_memory_weight. Over multiple + * activation calls total WM can grow well above ENGRAM_WM_CAP. This pass + * enforces the cap globally across ALL nodes in the store, keeping only + * the top ENGRAM_WM_CAP by current weight. Correct cognitive model: + * WM capacity is global (Cowan 2001); more recent activations outcompete + * older decayed ones. (2026-06-26 self-review) */ + { + int64_t global_wm_count = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (g->nodes[i].working_memory_weight > 0.0) global_wm_count++; + } + if (global_wm_count > ENGRAM_WM_CAP) { + double* gvals = malloc((size_t)global_wm_count * sizeof(double)); + if (gvals) { + int64_t gi = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (g->nodes[i].working_memory_weight > 0.0) + gvals[gi++] = g->nodes[i].working_memory_weight; + } + qsort(gvals, (size_t)global_wm_count, sizeof(double), + engram_cmp_double_desc); + double gcutoff = gvals[ENGRAM_WM_CAP - 1]; + free(gvals); + int64_t gabove = 0; + for (int64_t i = 0; i < g->node_count; i++) { + if (g->nodes[i].working_memory_weight > gcutoff) gabove++; + } + int64_t gslots_at_cutoff = ENGRAM_WM_CAP - gabove; + for (int64_t i = 0; i < g->node_count; i++) { + EngramNode* n = &g->nodes[i]; + if (n->working_memory_weight <= 0.0) continue; + if (n->working_memory_weight > gcutoff) continue; + if (gslots_at_cutoff > 0) { + gslots_at_cutoff--; + continue; /* fills a slot */ + } + n->working_memory_weight = 0.0; /* evict: over global cap */ + } + } + /* If malloc failed, skip — WM over cap this call, no data corruption. */ + } + } + /* ── Collect all background-activated nodes for the return value ──── * Callers see both layers. Context compilation uses only promoted nodes * (working_memory_weight > 0). Sort: promoted first by wm_weight desc, From e7c2dc773499942c02224968d9e0647c03751462 Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Mon, 29 Jun 2026 11:08:52 -0500 Subject: [PATCH 08/13] prevent engram corruption: add UTF-8 validation in engram_node_full MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reject content containing invalid UTF-8 bytes before persisting — silently writing invalid UTF-8 garbles JSON snapshots and corrupts node reads. --- lang/el-compiler/runtime/el_runtime.c | 45 +++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/lang/el-compiler/runtime/el_runtime.c b/lang/el-compiler/runtime/el_runtime.c index 12a2075..6b8cbe7 100644 --- a/lang/el-compiler/runtime/el_runtime.c +++ b/lang/el-compiler/runtime/el_runtime.c @@ -190,6 +190,7 @@ el_val_t println(el_val_t s) { const char* str = EL_CSTR(s); if (str) puts(str); else puts(""); + fflush(stdout); /* prevent startup logs from silently buffering when stdout→file */ return 0; } @@ -6111,6 +6112,10 @@ static double engram_type_threshold(const char* node_type, const char* tier) { if (strcmp(tier, "Lesson") == 0) return 0.25; } if (node_type) { + /* Knowledge nodes: Canonical/Lesson handled by tier checks above. + * Procedural-tier Knowledge (activation_count>=50 migration): 0.20. + * (2026-06-29 self-review — mirrors release runtime fix) */ + if (strcmp(node_type, "Knowledge") == 0) return 0.20; if (strcmp(node_type, "Belief") == 0) return 0.30; if (strcmp(node_type, "Entity") == 0) return 0.30; } @@ -6481,6 +6486,39 @@ el_val_t engram_node(el_val_t content, el_val_t node_type, el_val_t salience) { return el_wrap_str(el_strdup(n->id)); } +/* engram_is_valid_utf8 — return 1 if s is valid UTF-8, 0 if it contains invalid bytes. + * Rejects overlong encodings, surrogate halves, and byte sequences > 4 bytes. */ +static int engram_is_valid_utf8(const char* s) { + if (!s) return 1; + const unsigned char* p = (const unsigned char*)s; + while (*p) { + if (*p < 0x80) { + /* ASCII */ + p++; + } else if ((*p & 0xE0) == 0xC0) { + /* 2-byte sequence */ + if ((p[1] & 0xC0) != 0x80) return 0; + if ((*p & 0xFE) == 0xC0) return 0; /* overlong */ + p += 2; + } else if ((*p & 0xF0) == 0xE0) { + /* 3-byte sequence */ + if ((p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80) return 0; + if (*p == 0xE0 && (p[1] & 0xE0) == 0x80) return 0; /* overlong */ + if (*p == 0xED && (p[1] & 0xE0) == 0xA0) return 0; /* surrogate */ + p += 3; + } else if ((*p & 0xF8) == 0xF0) { + /* 4-byte sequence */ + if ((p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80) return 0; + if (*p == 0xF0 && (p[1] & 0xF0) == 0x80) return 0; /* overlong */ + if (*p > 0xF4) return 0; /* above U+10FFFF */ + p += 4; + } else { + return 0; + } + } + return 1; +} + el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, el_val_t salience, el_val_t importance, el_val_t confidence, el_val_t tier, el_val_t tags) { @@ -6494,6 +6532,13 @@ el_val_t engram_node_full(el_val_t content, el_val_t node_type, el_val_t label, const char* lb = EL_CSTR(label); const char* ti = EL_CSTR(tier); const char* tg = EL_CSTR(tags); + /* UTF-8 guard: reject content with invalid UTF-8 bytes. Persisting invalid + * UTF-8 garbles JSON snapshots and corrupts every subsequent node read. */ + if (c && !engram_is_valid_utf8(c)) { + fprintf(stderr, "[engram] REJECTED node write — content contains invalid UTF-8 (label=%s)\n", + lb ? lb : "(null)"); + return EL_STR(""); + } /* Persistent (el_strdup_persist, NOT el_strdup): these strings are owned by the * persistent global node store. el_strdup tracks into the per-request arena, which * el_request_end() frees when the creating HTTP request completes — leaving the From 192241c7c11aba59f43b393910f59bcfd9fb2192 Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Mon, 29 Jun 2026 12:38:33 -0500 Subject: [PATCH 09/13] feat(engram): /api/sync route for soul daemon periodic pull; update ELP type headers --- elp/src/elp.elh | 6 ++--- elp/src/grammar.elh | 56 +++++++++++++++++++++--------------------- elp/src/realizer.elh | 10 ++++---- elp/src/semantics.elh | 30 +++++++++++----------- engram/dist/engram | Bin 3528536 -> 3512056 bytes engram/dist/engram.c | 19 ++++++++++++++ engram/src/server.el | 27 ++++++++++++++++++++ 7 files changed, 97 insertions(+), 51 deletions(-) diff --git a/elp/src/elp.elh b/elp/src/elp.elh index ab8a621..f9d2323 100644 --- a/elp/src/elp.elh +++ b/elp/src/elp.elh @@ -1,7 +1,7 @@ // auto-generated by elc --emit-header — do not edit extern fn sem_get(json: String, key: String) -> String -extern fn generate_frame(frame: Any) -> String -extern fn generate_frame_lang(frame: Any, lang_code: String) -> String -extern fn build_form_from_json(semantic_form_json: String, lang_code: String) -> Any +extern fn generate_frame(frame: [String]) -> String +extern fn generate_frame_lang(frame: [String], lang_code: String) -> String +extern fn build_form_from_json(semantic_form_json: String, lang_code: String) -> [String] extern fn generate(semantic_form_json: String) -> String extern fn generate_lang(semantic_form_json: String, lang_code: String) -> String diff --git a/elp/src/grammar.elh b/elp/src/grammar.elh index ef8cf80..f678627 100644 --- a/elp/src/grammar.elh +++ b/elp/src/grammar.elh @@ -1,22 +1,22 @@ -// auto-generated by elc --emit-header - do not edit -extern fn slots_get(slots: Any, key: String) -> String -extern fn slots_set(slots: Any, key: String, val: String) -> Any -extern fn make_slots(k0: String, v0: String) -> Any -extern fn make_slots2(k0: String, v0: String, k1: String, v1: String) -> Any -extern fn make_slots3(k0: String, v0: String, k1: String, v1: String, k2: String, v2: String) -> Any -extern fn make_slots4(k0: String, v0: String, k1: String, v1: String, k2: String, v2: String, k3: String, v3: String) -> Any -extern fn make_slots5(k0: String, v0: String, k1: String, v1: String, k2: String, v2: String, k3: String, v3: String, k4: String, v4: String) -> Any -extern fn rule_id(rule: Any) -> String -extern fn rule_lhs(rule: Any) -> String -extern fn rule_rhs_len(rule: Any) -> Int -extern fn rule_rhs(rule: Any, idx: Int) -> String -extern fn make_rule(id: String, lhs: String, r0: String) -> Any -extern fn make_rule2(id: String, lhs: String, r0: String, r1: String) -> Any -extern fn make_rule3(id: String, lhs: String, r0: String, r1: String, r2: String) -> Any -extern fn make_rule4(id: String, lhs: String, r0: String, r1: String, r2: String, r3: String) -> Any -extern fn build_rules() -> Any -extern fn get_rules() -> Any -extern fn find_rule(rule_id_str: String) -> Any +// auto-generated by elc --emit-header — do not edit +extern fn slots_get(slots: [String], key: String) -> String +extern fn slots_set(slots: [String], key: String, val: String) -> [String] +extern fn make_slots(k0: String, v0: String) -> [String] +extern fn make_slots2(k0: String, v0: String, k1: String, v1: String) -> [String] +extern fn make_slots3(k0: String, v0: String, k1: String, v1: String, k2: String, v2: String) -> [String] +extern fn make_slots4(k0: String, v0: String, k1: String, v1: String, k2: String, v2: String, k3: String, v3: String) -> [String] +extern fn make_slots5(k0: String, v0: String, k1: String, v1: String, k2: String, v2: String, k3: String, v3: String, k4: String, v4: String) -> [String] +extern fn rule_id(rule: [String]) -> String +extern fn rule_lhs(rule: [String]) -> String +extern fn rule_rhs_len(rule: [String]) -> Int +extern fn rule_rhs(rule: [String], idx: Int) -> String +extern fn make_rule(id: String, lhs: String, r0: String) -> [String] +extern fn make_rule2(id: String, lhs: String, r0: String, r1: String) -> [String] +extern fn make_rule3(id: String, lhs: String, r0: String, r1: String, r2: String) -> [String] +extern fn make_rule4(id: String, lhs: String, r0: String, r1: String, r2: String, r3: String) -> [String] +extern fn build_rules() -> [[String]] +extern fn get_rules() -> [[String]] +extern fn find_rule(rule_id_str: String) -> [String] extern fn make_leaf(label: String, word: String) -> String extern fn make_node1(label: String, child0: String) -> String extern fn make_node2(label: String, child0: String, child1: String) -> String @@ -24,15 +24,15 @@ extern fn make_node3(label: String, child0: String, child1: String, child2: Stri extern fn make_node4(label: String, child0: String, child1: String, child2: String, child3: String) -> String extern fn nlg_is_ws(c: String) -> Bool extern fn skip_ws(s: String, pos: Int) -> Int -extern fn scan_token(s: String, start: Int) -> Any +extern fn scan_token(s: String, start: Int) -> [String] extern fn render_tree(tree: String) -> String -extern fn gram_word_order(profile: Any) -> String -extern fn gram_order_constituents(subj: String, verb: String, obj: String, profile: Any) -> String -extern fn gram_build_vp(verb: String, aux: String, profile: Any) -> String -extern fn gram_question_strategy(profile: Any) -> String +extern fn gram_word_order(profile: [String]) -> String +extern fn gram_order_constituents(subj: String, verb: String, obj: String, profile: [String]) -> String +extern fn gram_build_vp(verb: String, aux: String, profile: [String]) -> String +extern fn gram_question_strategy(profile: [String]) -> String extern fn is_pronoun(word: String) -> Bool -extern fn build_np(referent: String, slots: Any) -> String +extern fn build_np(referent: String, slots: [String]) -> String extern fn build_pp(loc: String) -> String -extern fn build_vp_body(slots: Any) -> String -extern fn build_vp_from_slots(slots: Any) -> String -extern fn generate_tree(rule_id_str: String, slots: Any) -> String +extern fn build_vp_body(slots: [String]) -> String +extern fn build_vp_from_slots(slots: [String]) -> String +extern fn generate_tree(rule_id_str: String, slots: [String]) -> String diff --git a/elp/src/realizer.elh b/elp/src/realizer.elh index 5bf5696..445f6fe 100644 --- a/elp/src/realizer.elh +++ b/elp/src/realizer.elh @@ -1,10 +1,10 @@ -// auto-generated by elc --emit-header - do not edit +// auto-generated by elc --emit-header — do not edit extern fn agent_person(agent: String) -> String extern fn agent_number(agent: String) -> String extern fn realize_np(referent: String, number: String) -> String -extern fn realize_vp_lang(base_verb: String, tense: String, aspect: String, person: String, number: String, profile: Any) -> Any -extern fn realize_question_lang(predicate: String, tense: String, aspect: String, person: String, number: String, agent: String, patient: String, location: String, profile: Any) -> String +extern fn realize_vp_lang(base_verb: String, tense: String, aspect: String, person: String, number: String, profile: [String]) -> [String] +extern fn realize_question_lang(predicate: String, tense: String, aspect: String, person: String, number: String, agent: String, patient: String, location: String, profile: [String]) -> String extern fn capitalize_first(s: String) -> String extern fn add_punct(s: String, intent: String) -> String -extern fn realize_lang(form: Any, profile: Any) -> String -extern fn realize(form: Any) -> String +extern fn realize_lang(form: [String], profile: [String]) -> String +extern fn realize(form: [String]) -> String diff --git a/elp/src/semantics.elh b/elp/src/semantics.elh index 68304f8..80f930e 100644 --- a/elp/src/semantics.elh +++ b/elp/src/semantics.elh @@ -1,18 +1,18 @@ -// auto-generated by elc --emit-header - do not edit -extern fn sem_frame(intent: String, subject: String, obj: String, modifiers: String) -> Any -extern fn sem_frame_lang(intent: String, subject: String, obj: String, modifiers: String, lang_code: String) -> Any -extern fn sem_frame_simple(intent: String, subject: String) -> Any -extern fn sem_frame_obj(intent: String, subject: String, obj: String) -> Any -extern fn sem_intent(frame: Any) -> String -extern fn sem_subject(frame: Any) -> String -extern fn sem_object(frame: Any) -> String -extern fn sem_modifiers(frame: Any) -> String -extern fn sem_lang(frame: Any) -> String +// auto-generated by elc --emit-header — do not edit +extern fn sem_frame(intent: String, subject: String, obj: String, modifiers: String) -> [String] +extern fn sem_frame_lang(intent: String, subject: String, obj: String, modifiers: String, lang_code: String) -> [String] +extern fn sem_frame_simple(intent: String, subject: String) -> [String] +extern fn sem_frame_obj(intent: String, subject: String, obj: String) -> [String] +extern fn sem_intent(frame: [String]) -> String +extern fn sem_subject(frame: [String]) -> String +extern fn sem_object(frame: [String]) -> String +extern fn sem_modifiers(frame: [String]) -> String +extern fn sem_lang(frame: [String]) -> String extern fn sem_first_modifier(mods: String) -> String extern fn sem_intent_to_realize(intent: String) -> String -extern fn sem_to_spec(frame: Any) -> Any -extern fn sem_to_spec_full(frame: Any, verb: String, tense: String, aspect: String) -> Any +extern fn sem_to_spec(frame: [String]) -> [String] +extern fn sem_to_spec_full(frame: [String], verb: String, tense: String, aspect: String) -> [String] extern fn sem_realize_greet(subject: String) -> String -extern fn sem_realize(frame: Any) -> String -extern fn sem_realize_full(frame: Any, verb: String, tense: String, aspect: String) -> String -extern fn sem_realize_lang(frame: Any, lang_code: String) -> String +extern fn sem_realize(frame: [String]) -> String +extern fn sem_realize_full(frame: [String], verb: String, tense: String, aspect: String) -> String +extern fn sem_realize_lang(frame: [String], lang_code: String) -> String diff --git a/engram/dist/engram b/engram/dist/engram index 95430e24eec4b6097df819082ce4d19a04a83406..74800455bd1cbc7c52c8cc52d50911e047939b86 100755 GIT binary patch delta 442998 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