aboutsummaryrefslogtreecommitdiffstats
path: root/prototypes/connections/pure-run.c
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-09-25 11:00:13 +0100
committereunhhu <[email protected]>2026-09-25 11:00:19 +0100
commitaf3d6d38a1494607507f63ab6f2e120ea21bb315 (patch)
treec886efa057e4e67b43cd1d06863304e6c527eb1e /prototypes/connections/pure-run.c
parentb238c3f3adf328127359d50eab3ffcee05737674 (diff)
downloadpure-af3d6d38a1494607507f63ab6f2e120ea21bb315.tar.gz
pure-af3d6d38a1494607507f63ab6f2e120ea21bb315.zip
Define Pure module format v1 with a static verifier
Pure now owns the format its toolchains target, as the JVM owns class files. A v1 module carries f64 states, key inputs, atomic event handlers and pure views. pure_module_load checks sizes, names, keys, operands, forward-only branches, reachability and stack heights at every join before anything runs, so execution needs no stack checks and each event is bounded by its handler length. PureApp runs events on a pending copy and replaces modules keeping states by name, without allocation. Semantics match the workbench engine, including IEEE minimum/maximum on signed zeros. test-module covers behaviour, atomic faults, 26 rejection checks and 20,000 damaged modules under ASan/UBSan; pure-run is a JSON test host.
Diffstat (limited to 'prototypes/connections/pure-run.c')
-rw-r--r--prototypes/connections/pure-run.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/prototypes/connections/pure-run.c b/prototypes/connections/pure-run.c
new file mode 100644
index 0000000..9059a1e
--- /dev/null
+++ b/prototypes/connections/pure-run.c
@@ -0,0 +1,77 @@
+#define _POSIX_C_SOURCE 200809L
+#include "module.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Test host for a verified module: reads commands from stdin and prints one
+ * JSON snapshot per command. Not a product interface.
+ * down NAME | up NAME | frame [N] | replace PATH | show */
+static const char *const fault_names[] = {"none", "divide", "non_finite", "clamp"};
+
+static bool load(const char *path, PureModule *module) {
+ FILE *file = fopen(path, "rb");
+ static unsigned char bytes[1 << 17];
+ size_t size = file ? fread(bytes, 1, sizeof(bytes), file) : 0;
+ bool ok = file && !ferror(file) && size < sizeof(bytes);
+ if (file) fclose(file);
+ char error[128];
+ if (!ok) { fprintf(stderr, "cannot read %s\n", path); return false; }
+ if (pure_module_load(bytes, size, module, error, sizeof(error)) != PURE_OK) {
+ fprintf(stderr, "%s: %s\n", path, error);
+ return false;
+ }
+ return true;
+}
+
+static void show(const PureApp *app, const char *failure) {
+ const PureModule *m = app->module;
+ printf("{\"states\":{");
+ for (uint32_t i = 0; i < m->states; ++i)
+ printf("%s\"%s\":%.17g", i ? "," : "", m->state_names[i], app->values[i]);
+ printf("},\"views\":{");
+ for (uint32_t i = 0; i < m->views; ++i) {
+ double value;
+ if (pure_app_view(app, i, &value)) printf("%s\"%s\":%.17g", i ? "," : "", m->view_names[i], value);
+ else printf("%s\"%s\":null", i ? "," : "", m->view_names[i]);
+ }
+ printf("},\"tick\":%llu,\"successfulEvents\":%llu,\"fault\":\"%s\",\"error\":%s%s%s}\n",
+ (unsigned long long)app->ticks, (unsigned long long)app->events, fault_names[app->fault],
+ failure ? "\"" : "", failure ? failure : "null", failure ? "\"" : "");
+}
+
+int main(int argc, char **argv) {
+ static PureModule modules[2];
+ if (argc != 2 || !load(argv[1], &modules[0])) {
+ if (argc != 2) fputs("pure-run MODULE < commands\n", stderr);
+ return 2;
+ }
+ unsigned active = 0;
+ PureApp app;
+ pure_app_start(&app, &modules[active]);
+ char line[4096];
+ int status = 0;
+ while (fgets(line, sizeof(line), stdin)) {
+ char command[16] = "", argument[4000] = "";
+ const char *failure = NULL;
+ line[strcspn(line, "\r\n")] = 0;
+ if (sscanf(line, "%15s %3999s", command, argument) < 1) continue;
+ if (!strcmp(command, "down") || !strcmp(command, "up")) {
+ int input = pure_module_input(app.module, argument);
+ if (input < 0) failure = "unknown input";
+ else if (pure_app_input(&app, (uint32_t)input, command[0] == 'd' ? PURE_EDGE_DOWN : PURE_EDGE_UP) != PURE_OK)
+ failure = "event failed";
+ } else if (!strcmp(command, "frame")) {
+ long count = *argument ? strtol(argument, NULL, 10) : 1;
+ if (count < 1 || count > 600) failure = "frame count";
+ for (long i = 0; !failure && i < count; ++i)
+ if (pure_app_frame(&app) != PURE_OK) failure = "event failed";
+ } else if (!strcmp(command, "replace")) {
+ if (!load(argument, &modules[!active])) failure = "invalid module";
+ else { active = !active; pure_app_replace(&app, &modules[active]); }
+ } else if (strcmp(command, "show")) failure = "unknown command";
+ if (failure) status = 1;
+ show(&app, failure);
+ }
+ return status;
+}