From f2c63f95fdd1f9f2ed2a7d0075d4a844f797390e Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Sun, 3 May 2026 15:35:45 -0500 Subject: [PATCH] =?UTF-8?q?add=20runtime/fs.el,=20exec.el,=20env.el=20?= =?UTF-8?q?=E2=80=94=20filesystem,=20subprocess,=20environment=20in=20El?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrates fs_read/write/exists/mkdir/write_bytes/list, exec/exec_bg/exec_command/exec_capture, env/args/exit_program, state_set/get/del/keys, uuid_new/v4, and list helpers get/len from el_runtime.c into El source as thin wrappers over seed primitives. --- runtime/env.el | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ runtime/exec.el | 27 +++++++++++++++++ runtime/fs.el | 49 +++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 runtime/env.el create mode 100644 runtime/exec.el create mode 100644 runtime/fs.el diff --git a/runtime/env.el b/runtime/env.el new file mode 100644 index 0000000..c9883a9 --- /dev/null +++ b/runtime/env.el @@ -0,0 +1,77 @@ +// runtime/env.el — environment and process +// Covers: environment variables, command-line args, process exit, in-process +// state store, UUID generation, and list convenience helpers. + +// env — read an environment variable. Returns "" if the variable is not set. +fn env(key: String) -> String { + return __env_get(key) +} + +// args — command-line arguments as a list of strings. +// __args_json returns a JSON array (e.g. ["prog","arg1","arg2"]). +// The list is built by iterating over the array. +fn args() -> [String] { + let json: String = __args_json() + let n: Int = json_array_len(json) + let result: [String] = el_list_empty() + let i: Int = 0 + while i < n { + let item: String = json_array_get_string(json, i) + let result = el_list_append(result, item) + let i = i + 1 + } + return result +} + +// exit_program — terminate the process with the given exit code. +fn exit_program(code: Int) { + __exit_program(code) +} + +// ── List convenience helpers ─────────────────────────────────────────────── + +// get — index into a list. Thin alias for el_list_get used throughout the +// El stdlib so call sites read like `get(lst, i)` rather than the verbose form. +fn get(lst: [String], i: Int) -> String { + return el_list_get(lst, i) +} + +// len — length of a list. +fn len(lst: [String]) -> Int { + return el_list_len(lst) +} + +// ── In-process key-value state store ────────────────────────────────────── + +// state_set — store a string value under key. +fn state_set(key: String, val: String) { + __state_set(key, val) +} + +// state_get — retrieve value for key; returns "" if key not present. +fn state_get(key: String) -> String { + return __state_get(key) +} + +// state_del — remove key from the store. +fn state_del(key: String) { + __state_del(key) +} + +// state_keys — all keys currently in the store as a JSON array string. +fn state_keys() -> String { + return __state_keys() +} + +// ── UUID generation ──────────────────────────────────────────────────────── + +// uuid_new — generate a new random UUID v4. +fn uuid_new() -> String { + return __uuid_v4() +} + +// uuid_v4 — alias for uuid_new(); explicit version name for callers that +// need to be precise about the UUID variant. +fn uuid_v4() -> String { + return __uuid_v4() +} diff --git a/runtime/exec.el b/runtime/exec.el new file mode 100644 index 0000000..357d313 --- /dev/null +++ b/runtime/exec.el @@ -0,0 +1,27 @@ +// runtime/exec.el — subprocess execution +// All four names resolve to the same seed primitives so callers can use +// whichever name matches their mental model of the operation. + +// exec — run a shell command, capture stdout, return as String. +// Blocks until the subprocess exits (30-second wall-clock deadline in the +// seed layer). Returns "" on any error. +fn exec(cmd: String) -> String { + return __exec(cmd) +} + +// exec_bg — fire-and-forget subprocess. Returns immediately; no stdout. +fn exec_bg(cmd: String) { + __exec_bg(cmd) +} + +// exec_command — alias for exec(); preferred when callers care about side +// effects (e.g. invoking a build tool) rather than captured output. +fn exec_command(cmd: String) -> String { + return __exec(cmd) +} + +// exec_capture — alias for exec(); preferred when callers explicitly want +// to capture and process stdout. +fn exec_capture(cmd: String) -> String { + return __exec(cmd) +} diff --git a/runtime/fs.el b/runtime/fs.el new file mode 100644 index 0000000..d25ebc3 --- /dev/null +++ b/runtime/fs.el @@ -0,0 +1,49 @@ +// runtime/fs.el — filesystem operations +// Thin El wrappers over seed primitives; no logic beyond what is needed +// to present a clean API. The heavy lifting lives in el_runtime.c. + +fn fs_read(path: String) -> String { + return __fs_read(path) +} + +fn fs_write(path: String, content: String) -> Bool { + return __fs_write(path, content) +} + +fn fs_exists(path: String) -> Bool { + return __fs_exists(path) +} + +fn fs_mkdir(path: String) -> Bool { + return __fs_mkdir(path) +} + +fn fs_write_bytes(path: String, bytes: String, n: Int) -> Bool { + return __fs_write_bytes(path, bytes, n) +} + +// fs_list — return list of filenames in a directory. +// __fs_list_raw returns a newline-separated string (possibly with a trailing +// newline); callers that need a clean list should filter empty strings. +fn fs_list(path: String) -> [String] { + let raw: String = __fs_list_raw(path) + return str_split(raw, "\n") +} + +// fs_list_json — return a JSON array of filenames in a directory. +// Empty strings produced by a trailing newline are stripped before encoding. +fn fs_list_json(path: String) -> String { + let items: [String] = fs_list(path) + let n: Int = el_list_len(items) + let clean: [String] = el_list_empty() + let i: Int = 0 + while i < n { + let item: String = el_list_get(items, i) + let trimmed: String = str_trim(item) + if !str_eq(trimmed, "") { + let clean = el_list_append(clean, "\"" + trimmed + "\"") + } + let i = i + 1 + } + return json_build_array(clean) +}