aboutsummaryrefslogtreecommitdiffstats
path: root/prototypes/connections/module.c
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-09-26 11:35:20 +0100
committereunhhu <[email protected]>2026-09-26 11:35:20 +0100
commit92f5545efb7aab0b3a4a4c73a65364ef519cd5d4 (patch)
tree10633f366478737d6bb25286ac074e7f4ded7b20 /prototypes/connections/module.c
parent6ca1a1e598b9aa2f0b8f3947c27883b45b366346 (diff)
downloadpure-92f5545efb7aab0b3a4a4c73a65364ef519cd5d4.tar.gz
pure-92f5545efb7aab0b3a4a4c73a65364ef519cd5d4.zip
Add first: the index of the first item a block keeps
A fifth fold kind, first, runs its block over the items until one leaves a non-zero number and pushes that item's index, typed as an index of the list, or fails not_found when none does. Handlers can so find the item to change by a condition, as a message naming a task by its title would.
Diffstat (limited to 'prototypes/connections/module.c')
-rw-r--r--prototypes/connections/module.c17
1 files changed, 13 insertions, 4 deletions
diff --git a/prototypes/connections/module.c b/prototypes/connections/module.c
index ffdcaf7..d616b9f 100644
--- a/prototypes/connections/module.c
+++ b/prototypes/connections/module.c
@@ -173,7 +173,7 @@ PURE_COLD static bool names_arg(const PureModule *m, unsigned kind, uint32_t arg
case A_CONSTANT: return arg < m->constants;
case A_UNIT: return arg <= PURE_UNIT_LINE;
case A_ROW: return (int)arg == row;
- case A_FOLD: return (arg & 0xFF) <= PURE_FOLD_MIN && state_of(m, arg >> 8 & 0xFF, PURE_STATE_LIST) && arg >> 16;
+ case A_FOLD: return (arg & 0xFF) <= PURE_FOLD_FIRST && state_of(m, arg >> 8 & 0xFF, PURE_STATE_LIST) && arg >> 16;
case A_NONE: case A_TARGET: case A_DEPTH: return true;
default: return state_of(m, arg, (uint8_t)(kind - A_STATE));
}
@@ -266,7 +266,9 @@ PURE_COLD static const char *verify_block(const PureModule *m, PureBlock block,
skip = arg >> 16;
if (view >= FOLD_ONE) REFUSE(view == FILTER ? "fold inside a filter" : "fold inside a fold");
if (skip > block.length - i - 1) REFUSE("fold block outside its block");
- const char *why = verify_block(m, (PureBlock){pc + 1, skip}, (arg & 0xFF) == PURE_FOLD_COUNT ? FOLD_ONE : FOLD_TWO,
+ unsigned how = arg & 0xFF;
+ const char *why = verify_block(m, (PureBlock){pc + 1, skip},
+ how == PURE_FOLD_COUNT || how == PURE_FOLD_FIRST ? FOLD_ONE : FOLD_TWO,
(int)(arg >> 8 & 0xFF), 0, &inner);
if (why) { *at = inner; return why; }
for (uint32_t k = i + 1; k <= i + skip; ++k) {
@@ -296,6 +298,11 @@ PURE_COLD static const char *verify_block(const PureModule *m, PureBlock block,
REFUSE(type == T_CURSOR ? "cursor of another text" : "index of another list");
}
unsigned char out = signature[op->op].out;
+ if (kind == A_FOLD && (arg & 0xFF) == PURE_FOLD_FIRST) { /* an index of its list */
+ out = T_INDEX;
+ of = O_ARG;
+ owner = arg >> 8 & 0xFF;
+ }
if (out == T_FIELD) out = m->field[shape->field_start + arg].type == PURE_FIELD_U32 ? T_NUM : T_BYTES;
if (out == T_ITEM) out = field_type(m, list_of(arg), item_field(arg));
if (out) {
@@ -959,14 +966,16 @@ static PureResult run(const PureModule *m, double *values, PureBlock block, Even
arena->used = mark;
if (status != PURE_OK) return status;
double value = out[0].num;
- if (how == PURE_FOLD_COUNT ? value == 0 : out[1].num == 0) continue;
+ if (how == PURE_FOLD_COUNT || how == PURE_FOLD_FIRST ? value == 0 : out[1].num == 0) continue;
+ if (how == PURE_FOLD_FIRST) { total = (double)row; any = true; break; }
total = how == PURE_FOLD_COUNT ? total + 1 : how == PURE_FOLD_SUM ? total + value :
!any ? value : how == PURE_FOLD_MAX ? maximum(total, value) : minimum(total, value);
any = true;
}
if (!any && how >= PURE_FOLD_MAX) { kind = PURE_FAULT_NOT_FOUND; goto failed; }
if (!isfinite(total)) { kind = PURE_FAULT_NON_FINITE; goto failed; }
- stack[sp++].num = total;
+ stack[sp].num = total;
+ stack[sp++].bytes.owner = (uint16_t)(arg >> 8 & 0xFF); /* first: the list the index is in */
continue;
}
case PURE_OP_PICK: stack[sp] = stack[sp - 1 - arg]; ++sp; continue;