321 lines
11 KiB
C
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("{}");
|
|
}
|