diff options
| author | eunhhu <[email protected]> | 2026-09-25 11:00:13 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-09-25 11:00:19 +0100 |
| commit | af3d6d38a1494607507f63ab6f2e120ea21bb315 (patch) | |
| tree | c886efa057e4e67b43cd1d06863304e6c527eb1e /prototypes/connections/pure-run.c | |
| parent | b238c3f3adf328127359d50eab3ffcee05737674 (diff) | |
| download | pure-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.c | 77 |
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; +} |
