diff --git a/lang/el-compiler/runtime/el_runtime.c b/lang/el-compiler/runtime/el_runtime.c index 46e83f0..7ef3b6a 100644 --- a/lang/el-compiler/runtime/el_runtime.c +++ b/lang/el-compiler/runtime/el_runtime.c @@ -11221,6 +11221,159 @@ el_val_t hash_sha256(el_val_t sv) { 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; +} +#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 @@ -11247,4 +11400,7 @@ el_val_t llm_call_agentic(el_val_t m, el_val_t s, el_val_t u, el_val_t t) { (voi 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(); } #endif /* !HAVE_CURL */ diff --git a/lang/el-compiler/runtime/el_runtime.h b/lang/el-compiler/runtime/el_runtime.h index b9460ea..d2a6b01 100644 --- a/lang/el-compiler/runtime/el_runtime.h +++ b/lang/el-compiler/runtime/el_runtime.h @@ -781,6 +781,93 @@ 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); + +/* 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/lang/el-compiler/runtime/el_seed.c b/lang/el-compiler/runtime/el_seed.c index 5b47903..b509e48 100644 --- a/lang/el-compiler/runtime/el_seed.c +++ b/lang/el-compiler/runtime/el_seed.c @@ -990,6 +990,8 @@ el_val_t __json_get(el_val_t json, el_val_t key) { return j 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); } diff --git a/lang/el-compiler/runtime/el_seed.h b/lang/el-compiler/runtime/el_seed.h index 04d53ca..c502f10 100644 --- a/lang/el-compiler/runtime/el_seed.h +++ b/lang/el-compiler/runtime/el_seed.h @@ -174,6 +174,8 @@ 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);