diff options
Diffstat (limited to 'prototypes/connections')
| -rw-r--r-- | prototypes/connections/module.c | 17 | ||||
| -rw-r--r-- | prototypes/connections/module.h | 5 | ||||
| -rw-r--r-- | prototypes/connections/test-module.c | 8 |
3 files changed, 23 insertions, 7 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; diff --git a/prototypes/connections/module.h b/prototypes/connections/module.h index b57e11f..4264710 100644 --- a/prototypes/connections/module.h +++ b/prototypes/connections/module.h @@ -43,8 +43,9 @@ typedef enum { /* FOLD's argument: the kind (bits 0-7), the list state (8-15) and the length * of the block that follows (16-31), run once per item as a column of that * list. count counts the items whose block leaves a non-zero number; sum, - * max and min take a value and an include flag from their block. */ -typedef enum { PURE_FOLD_COUNT, PURE_FOLD_SUM, PURE_FOLD_MAX, PURE_FOLD_MIN } PureFold; + * max and min take a value and an include flag from their block; first gives + * the index of the first item whose block leaves a non-zero number. */ +typedef enum { PURE_FOLD_COUNT, PURE_FOLD_SUM, PURE_FOLD_MAX, PURE_FOLD_MIN, PURE_FOLD_FIRST } PureFold; typedef enum { PURE_KIND_KEY = 1, PURE_KIND_MESSAGE = 2, PURE_KIND_TEXT = 3 } PureInputKind; typedef enum { PURE_FIELD_U32 = 1, PURE_FIELD_BYTES = 2 } PureFieldType; diff --git a/prototypes/connections/test-module.c b/prototypes/connections/test-module.c index 6b11c3f..07a0cbb 100644 --- a/prototypes/connections/test-module.c +++ b/prototypes/connections/test-module.c @@ -1779,10 +1779,12 @@ static const O fold_code[] = { {FOLD, FOLDING(PURE_FOLD_MIN, 0, 5), 0}, {ROW, 0, 0}, {IG, F_POINTS, 0}, {ROW, 0, 0}, /* 30 fewest_open */ {IG, F_DONE, 0}, {NOT, 0, 0}, {C, 0, 10}, {FOLD, FOLDING(PURE_FOLD_COUNT, 0, 1), 0}, {C, 0, 1}, {ADD, 0, 0}, /* 36 count_plus */ + {FOLD, FOLDING(PURE_FOLD_FIRST, 0, 3), 0}, {ROW, 0, 0}, {IG, F_DONE, 0}, {NOT, 0, 0}, /* 40 first_open */ + {XN, 0, 0}, }; static const H fold_handlers[] = {{1, 0, 7}, {3, 7, 5}}; static const V fold_views[] = {{"open", 12, 4}, {"points", 16, 4}, {"longest", 20, 5}, {"done_points", 25, 5}, - {"fewest_open", 30, 6}, {"count_plus", 36, 4}}; + {"fewest_open", 30, 6}, {"count_plus", 36, 4}, {"first_open", 40, 5}}; static Spec fold_spec(const O *code, size_t count, const V *views, size_t nviews, const H *handlers, size_t nhandlers) { return (Spec){NULL, 0, fold_inputs, LEN(fold_inputs), views, nviews, handlers, nhandlers, code, count, NULL, 0, fold_states, 2, fold_constants, 1, NULL, 0, fold_records, 1, NULL, 0}; @@ -1795,6 +1797,7 @@ static void folds(void) { CHECK(pure_app_start(&app, &module_a, (PureData){0}) == PURE_OK); CHECK(number_view(&app, 0) == 0 && number_view(&app, 1) == 0 && !pure_app_view(&app, 2, &value)); CHECK(number_view(&app, 3) == 0 && !pure_app_view(&app, 4, &value) && number_view(&app, 5) == 10); + CHECK(!pure_app_view(&app, 6, &value)); /* no first open task yet */ const char *const words[] = {"a", "bbb", "\xea\xb0\x80\xea\xb0\x80"}; /* one, three and two characters */ for (size_t i = 0; i < 3; ++i) CHECK(pure_app_text(&app, 0, (PureSpan){(const unsigned char *)words[i], strlen(words[i])}) == PURE_OK); @@ -1802,8 +1805,11 @@ static void folds(void) { CHECK(number_view(&app, 3) == 0 && number_view(&app, 4) == 1 && number_view(&app, 5) == 13); CHECK(pure_app_input(&app, 1, PURE_EDGE_DOWN) == PURE_OK); /* the last task is done */ CHECK(number_view(&app, 0) == 2 && number_view(&app, 3) == 2 && number_view(&app, 4) == 1); + CHECK(number_view(&app, 6) == 0); /* the first open one: an index */ CHECK(pure_app_point(&app, 1, 0) == PURE_OK && pure_app_input(&app, 1, PURE_EDGE_DOWN) == PURE_OK); + CHECK(number_view(&app, 6) == 1); CHECK(pure_app_point(&app, 1, 1) == PURE_OK && pure_app_input(&app, 1, PURE_EDGE_DOWN) == PURE_OK); + CHECK(!pure_app_view(&app, 6, &value)); CHECK(number_view(&app, 0) == 0 && number_view(&app, 3) == 6 && !pure_app_view(&app, 4, &value)); /* none open */ pure_app_stop(&app); |
