/* * tests/suite/infra.c — El runtime infrastructure functions for the test suite. * * The El test suite compiles runtime/*.el files into tests.c via elc, then links * only against el_seed.c (not the full el_runtime.c, which would cause ~120 * duplicate symbol errors). This file provides the infrastructure symbols that * tests.c references but that are NOT defined in either the generated El code or * el_seed.c: * * ─ ElList machinery: el_list_empty, el_list_append, el_list_len, el_list_get, * el_str_concat, native_list_*, len, get * ─ el_runtime_init_args (needed by the generated main()) * ─ Stubs for http_*, engram_*, el_html_sanitize (not needed by tests) * * These implementations are derived from el_runtime.c. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include "el_seed.h" #include #include #include #include #include /* ── String arena (minimal — no HTTP request lifecycle needed) ─────────────── */ static char* el_strdup(const char* s) { if (!s) return strdup(""); return strdup(s); } static char* el_strbuf(size_t n) { char* p = malloc(n + 1); if (!p) { fputs("infra: out of memory\n", stderr); exit(1); } p[0] = '\0'; return p; } static el_val_t el_wrap_str(char* s) { return EL_STR(s); } /* ── el_str_concat ────────────────────────────────────────────────────────── */ 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); } /* ── ElList ───────────────────────────────────────────────────────────────── */ #define EL_MAGIC_LIST 0xE15710A1u typedef struct { uint32_t magic; uint32_t refcount; } ElHeader; 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("infra: 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("infra: 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_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); } 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("infra: out of memory\n", stderr); exit(1); } old->elems = grown; old->capacity = new_cap; } old->elems[old->length++] = elem; return listv; } int64_t new_cap = old->length + 1; if (new_cap < 4) new_cap = 4; ElList* fresh = malloc(sizeof(ElList)); if (!fresh) { fputs("infra: 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("infra: 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); } /* ── native_list aliases ──────────────────────────────────────────────────── */ el_val_t native_list_empty(void) { return el_list_empty(); } 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_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); } /* ── len / get aliases ─────────────────────────────────────────────────────── */ 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_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])); } } /* ── HTTP stubs (not exercised by test suite) ─────────────────────────────── */ el_val_t http_post(el_val_t url, el_val_t body) { (void)url; (void)body; return EL_STR(""); } el_val_t http_post_json(el_val_t url, el_val_t body) { (void)url; (void)body; return EL_STR(""); } el_val_t http_post_with_headers(el_val_t url, el_val_t body, el_val_t headers) { (void)url; (void)body; (void)headers; return EL_STR(""); } el_val_t http_response(el_val_t status, el_val_t headers, el_val_t body) { (void)status; (void)headers; (void)body; return EL_STR(""); } void http_serve(el_val_t port, el_val_t handler) { (void)port; (void)handler; } void http_serve_v2(el_val_t port, el_val_t handler) { (void)port; (void)handler; } /* ── el_html_sanitize stub ────────────────────────────────────────────────── */ el_val_t el_html_sanitize(el_val_t input, el_val_t allowlist) { (void)allowlist; return input; } /* ── Engram stubs (not exercised by test suite) ───────────────────────────── */ el_val_t engram_node(el_val_t content, el_val_t node_type, el_val_t salience) { (void)content; (void)node_type; (void)salience; return EL_STR(""); } 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) { (void)content; (void)node_type; (void)label; (void)salience; (void)importance; (void)confidence; (void)tier; (void)tags; return EL_STR(""); } 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 tier, el_val_t layer_id, el_val_t tags) { (void)content; (void)node_type; (void)label; (void)salience; (void)certainty; (void)confidence; (void)tier; (void)layer_id; (void)tags; return EL_STR(""); } 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) { (void)name; (void)priority; (void)suppressible; (void)transparent; (void)injectable; return EL_STR(""); } el_val_t engram_remove_layer(el_val_t layer_id) { (void)layer_id; return (el_val_t)1; } el_val_t engram_list_layers(void) { return EL_STR("[]"); } el_val_t engram_list_layers_json(void) { return EL_STR("[]"); } el_val_t engram_get_node(el_val_t id) { (void)id; return EL_STR(""); } el_val_t engram_get_node_json(el_val_t id) { (void)id; return EL_STR("{}"); } void engram_strengthen(el_val_t node_id) { (void)node_id; } void engram_forget(el_val_t node_id) { (void)node_id; } el_val_t engram_node_count(void) { return 0; } el_val_t engram_edge_count(void) { return 0; } el_val_t engram_stats_json(void) { return EL_STR("{}"); } void engram_connect(el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t relation) { (void)from_id; (void)to_id; (void)weight; (void)relation; } el_val_t engram_edge_between(el_val_t from_id, el_val_t to_id) { (void)from_id; (void)to_id; return (el_val_t)0; } el_val_t engram_search(el_val_t query, el_val_t limit) { (void)query; (void)limit; return el_list_empty(); } el_val_t engram_search_json(el_val_t query, el_val_t limit) { (void)query; (void)limit; return EL_STR("[]"); } el_val_t engram_scan_nodes(el_val_t limit, el_val_t offset) { (void)limit; (void)offset; return el_list_empty(); } el_val_t engram_scan_nodes_json(el_val_t limit, el_val_t offset) { (void)limit; (void)offset; return EL_STR("[]"); } el_val_t engram_scan_nodes_by_type_json(el_val_t node_type, el_val_t limit, el_val_t offset) { (void)node_type; (void)limit; (void)offset; return EL_STR("[]"); } el_val_t engram_neighbors(el_val_t node_id, el_val_t limit) { (void)node_id; (void)limit; return el_list_empty(); } el_val_t engram_neighbors_filtered(el_val_t node_id, el_val_t relation, el_val_t limit) { (void)node_id; (void)relation; (void)limit; return el_list_empty(); } el_val_t engram_neighbors_json(el_val_t node_id, el_val_t limit) { (void)node_id; (void)limit; return EL_STR("[]"); } el_val_t engram_load(el_val_t path) { (void)path; return (el_val_t)1; } el_val_t engram_save(el_val_t path) { (void)path; return (el_val_t)1; } el_val_t engram_activate(el_val_t node_ids, el_val_t spread, el_val_t decay) { (void)node_ids; (void)spread; (void)decay; return el_list_empty(); } el_val_t engram_activate_json(el_val_t node_ids_json, el_val_t spread, el_val_t decay) { (void)node_ids_json; (void)spread; (void)decay; return EL_STR("[]"); } el_val_t engram_compile_layered_json(el_val_t node_id, el_val_t target_tokens, el_val_t strategy) { (void)node_id; (void)target_tokens; (void)strategy; return EL_STR("{}"); }