Files
will.anderson 254cbe0ac2
El SDK CI - dev / build-and-test (pull_request) Successful in 3m22s
fix: add __-prefixed runtime primitives expected by El compiler
The El compiler generates calls to __-prefixed C primitives from within
El stdlib compiled code (e.g. __println, __str_len, __json_get, etc).
These were absent from el_runtime.c, causing linker failures when
building el-install, elb, or epm with the current compiler.

Add 46 __-prefixed aliases/implementations in el_runtime.c covering:
- I/O: __println, __print, __readline
- String: __str_len, __str_cmp, __str_ncmp, __str_alloc, __str_set_char,
  __str_concat_raw, __str_slice_raw, __str_char_at, plus numeric converters
- FS: __fs_read, __fs_write, __fs_exists, __fs_mkdir, __fs_list_raw, etc
- HTTP: __http_do, __http_do_map, __http_serve, __http_serve_v2,
  __http_response, __http_sse_* (weak stubs)
- JSON: __json_get, __json_set, __json_parse_map, __json_stringify_val, etc
- State, env, exec, uuid, sha256, args
2026-05-06 20:36:49 -05:00

251 lines
13 KiB
C

/*
* 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 <stdint.h>
#include <stdlib.h>
/* ── 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: <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);
#ifdef __cplusplus
}
#endif