Files
2026-05-05 01:38:51 -05:00

321 lines
11 KiB
C

/*
* 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 <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* ── 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("{}");
}