aboutsummaryrefslogtreecommitdiffstats
path: root/prototypes/connections/module.c
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-09-26 17:55:14 +0100
committereunhhu <[email protected]>2026-09-26 17:55:14 +0100
commitef7ac7332f330fddc2de6194f926e0c0a84ca2b4 (patch)
treeb7e1764c6ffcbe6f2d7c64ead1b91b352e3b7b0a /prototypes/connections/module.c
parentae48b510c9eec3e47ea551b4c4cad640d13310cd (diff)
downloadpure-ef7ac7332f330fddc2de6194f926e0c0a84ca2b4.tar.gz
pure-ef7ac7332f330fddc2de6194f926e0c0a84ca2b4.zip
Add time: timers, now, floor and a floored modulo
An input may be a timer (kind 4, its period of 1 ms to a day in place of a key name): pure_app_tick delivers a tick, an event saved like a key's. NOW gives handlers the time the host set in PureApp.now (milliseconds since 1970, UTC), so a script replays any time and views stay functions of state; FLOOR and MOD take times apart, MOD taking the divisor's sign as floor division leaves it, a zero too. pure-run gains time MS and tick NAME.
Diffstat (limited to 'prototypes/connections/module.c')
-rw-r--r--prototypes/connections/module.c23
1 files changed, 23 insertions, 0 deletions
diff --git a/prototypes/connections/module.c b/prototypes/connections/module.c
index 7f22c49..73a9ed6 100644
--- a/prototypes/connections/module.c
+++ b/prototypes/connections/module.c
@@ -97,6 +97,8 @@ static const struct { unsigned char pops, in[3], out, where, arg, of; } signatur
[PURE_OP_TEXT_COMPARE] = {2, {T_TEXT, T_TEXT}, T_NUM, READ, A_RELATION, O_ANY},
[PURE_OP_LIST_FIND] = {1, {T_KEY}, T_INDEX, READ, A_KEYED, O_ARG},
[PURE_OP_LIST_HAS] = {1, {T_KEY}, T_NUM, READ, A_KEYED, O_ANY},
+ [PURE_OP_NOW] = {0, {0}, T_NUM, IN_HANDLER, A_NONE, O_ANY},
+ [PURE_OP_FLOOR] = NUMS(1), [PURE_OP_MOD] = NUMS(2),
};
#undef NUMS
#undef STATE
@@ -446,6 +448,12 @@ PURE_COLD PureResult pure_module_load(const void *bytes, size_t size, PureModule
REFUSE("text input shape", i);
continue;
}
+ if (shape->kind == PURE_KIND_TIMER) {
+ shape->period = read32(at + 8);
+ if (shape->keyed || shape->field_start || shape->field_count || !shape->period ||
+ shape->period > PURE_TIMER_LONGEST) REFUSE("timer input", i);
+ continue;
+ }
if (shape->kind != PURE_KIND_MESSAGE || read32(at + 8) || shape->field_start != next_field ||
shape->field_count > out->fields - next_field) REFUSE("message shape", i);
/* The prefix holds the fixed fields and the variable fields' lengths
@@ -771,6 +779,8 @@ static PureResult run(const PureModule *m, double *values, PureBlock block, Even
case PURE_OP_CONST: stack[sp++].num = op->value; continue;
case PURE_OP_LOAD: stack[sp++].num = values[arg]; continue;
case PURE_OP_DT: stack[sp++].num = ev->dt; continue;
+ case PURE_OP_NOW: stack[sp++].num = app->now; continue;
+ case PURE_OP_FLOOR: top->num = floor(top->num); continue;
case PURE_OP_STORE: case PURE_OP_CUR_STORE: values[arg] = stack[--sp].num; continue;
case PURE_OP_JZ: if (stack[--sp].num == 0) pc = arg; continue;
case PURE_OP_JMP: pc = arg; continue;
@@ -1069,6 +1079,12 @@ static PureResult run(const PureModule *m, double *values, PureBlock block, Even
case PURE_OP_AND: value = a != 0 && b != 0; break;
case PURE_OP_OR: value = a != 0 || b != 0; break;
case PURE_OP_MIN: value = minimum(a, b); break;
+ case PURE_OP_MOD: /* the divisor's sign, as floor division leaves it (a zero too) */
+ if (b == 0) { kind = PURE_FAULT_DIVIDE; goto failed; }
+ value = fmod(a, b);
+ if (value != 0 && (value < 0) != (b < 0)) value += b;
+ else if (value == 0) value = copysign(0.0, b);
+ break;
default: value = maximum(a, b); break;
}
if (!isfinite(value)) { kind = PURE_FAULT_NON_FINITE; goto failed; }
@@ -1266,6 +1282,13 @@ PureResult pure_app_frame(PureApp *app) {
return dispatch(app, 0, &ev);
}
+PureResult pure_app_tick(PureApp *app, uint32_t input) {
+ if (input >= app->module->inputs || app->module->input[input].kind != PURE_KIND_TIMER) return PURE_INVALID;
+ pure_app_finish(app);
+ Event ev = {.app = app, .arena = &app->arena};
+ return dispatch(app, 1 + 2 * input, &ev);
+}
+
PureResult pure_app_input(PureApp *app, uint32_t input, PureEdge edge) {
if (input >= app->module->inputs || app->module->input[input].kind != PURE_KIND_KEY ||
(edge != PURE_EDGE_DOWN && edge != PURE_EDGE_UP)) return PURE_INVALID;