diff options
| author | eunhhu <[email protected]> | 2026-09-28 00:20:49 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-09-28 00:20:49 +0100 |
| commit | 32b16a23a7ca7080b32a2948cd7518053125dac9 (patch) | |
| tree | 2a5f2b6a9aa803dfa1e1af27b874ad0afeeedd9a | |
| parent | d03092f8dc3efe2231c817031be0a744ac6e60e1 (diff) | |
| download | aup-32b16a23a7ca7080b32a2948cd7518053125dac9.tar.gz aup-32b16a23a7ca7080b32a2948cd7518053125dac9.zip | |
Let a fold in a column read the column's row
A count, sum, max or min inside a table's column may now name the row the
column is evaluated for: per branch, the sum of its accounts
(sum(a.balance for a in accounts where a.bid == b.bid)), or per account,
how many are richer. The column's row inside the fold compiles to
OUTER_ROW, which Pure's verifier accepts only in a fold that runs in a
column; the fold's own item stays ROW. This is a correlated subquery, the
form SQL writes GROUP BY and self-joins with.
| -rw-r--r-- | compiler/compile.c | 8 | ||||
| -rw-r--r-- | tests/check.py | 4 |
2 files changed, 6 insertions, 6 deletions
diff --git a/compiler/compile.c b/compiler/compile.c index 3c4f0cc..6cfb903 100644 --- a/compiler/compile.c +++ b/compiler/compile.c @@ -17,7 +17,7 @@ enum { CONST, LOAD, DT, ADD, SUB, MUL, DIV, NEG, LT, LE, GT, GE, EQ, NE, AND, OR CUR_LOAD, CUR_START, CUR_END, CUR_MOVE, CUR_STORE, TEXT_INSERT, TEXT_REMOVE, TEXT_LINE, TEXT_SET, TEXT_FROM, BYTES_FROM, CUR_COUNT, LIST_COUNT, LIST_APPEND, LIST_INSERT, LIST_REMOVE, ITEM_GET, ITEM_SET, INDEX_LOAD, INDEX_STORE, INDEX_MOVE, INDEX_FIRST, INDEX_LAST, INDEX_NUM, ROW, - PICK, SLIDE, FOLD, TEXT_COMPARE, LIST_FIND, LIST_HAS, NOW, FLOOR, MOD, SEND }; + PICK, SLIDE, FOLD, TEXT_COMPARE, LIST_FIND, LIST_HAS, NOW, FLOOR, MOD, SEND, OUTER_ROW }; enum { FOLD_COUNT, FOLD_SUM, FOLD_MAX, FOLD_MIN, FOLD_FIRST }; enum { KIND_KEY = 1, KIND_MESSAGE = 2, KIND_TEXT = 3, KIND_TIMER = 4, KIND_OUTPUT = 5, FIELD_U32 = 1, FIELD_BYTES = 2, FIELD_NUMBER = 3, FIELD_TEXT = 4 }; enum { STATE_NUM = 0, STATE_TEXT = 1, STATE_CURSOR = 2, STATE_LIST = 3, STATE_INDEX = 4, UNIT_CHAR = 0, UNIT_LINE = 1 }; @@ -1650,10 +1650,10 @@ static Kind value(Compiler *c, const Expr *e, bool handler, int height) { if (fn_index(c, c->module, e->name) >= 0) return inline_fn(c, e, c->module, e->name, handler, height); if (c->module) fail_at(c, e->line, e->column, "'%s' is not a parameter; a library fn reads only its parameters", e->name); if (!c->scope && c->row >= 0 && !strcmp(e->name, c->view_row[c->row])) { - if (c->folding) - fail_at(c, e->line, e->column, "'%s' is the column's row; a count, sum, max or min reads only its own item", e->name); + /* In a count, sum, max or min the column's row is still there (a + * correlated fold: per branch, the sum of its accounts). */ int list = state_index(c, c->view_list[c->row]); - emit(c, e->line, e->column, ROW, (uint32_t)list, 0); + emit(c, e->line, e->column, c->folding ? OUTER_ROW : ROW, (uint32_t)list, 0); return (Kind){INDEX, list}; } int index = state_index(c, e->name); diff --git a/tests/check.py b/tests/check.py index 98d6e37..84fc9bd 100644 --- a/tests/check.py +++ b/tests/check.py @@ -196,8 +196,6 @@ DIAGNOSTICS = [ (LIST + 'view v = count(x in at)\n', '6:10', "'at' is not a list"), ('record T {\n t: text\n}\nstate xs: list of T\nview v = sum(x.t for x in xs)\n', '5:14', 'sum, max and min take numbers, not text'), - (LIST + 'view w = each r in xs {\n n = count(x in xs where x.a == r.a)\n}\n', '7:34', - "'r' is the column's row; a count, sum, max or min reads only its own item"), (LIST + 'fn f(n) = count(x in xs where x.a == n)\nview v = f(1)\n', '6:38', "'n' is a parameter outside this count, sum, max or min"), (LIST + 'view v = sum(dt for x in xs)\n', '6:14', 'dt is not available in count, sum, max or min'), @@ -234,6 +232,8 @@ DIAGNOSTICS = [ ] ACCEPTED = [ + # A fold in a column reads the column's row too (a correlated subquery). + LIST + 'view w = each r in xs {\n n = count(x in xs where x.a == r.a)\n}\n', SENDS + 'on buy {\n n = n + 1\n send ordered { to: { city: "Seoul" }, count: buy.count, item: buy.item }\n}\nview sent = n\n', # fns named like folds stay calls, and max of two values stays max 'fn sum(a, b) = a + b\nfn count(x) = x\nview v = sum(1, count(2)) + max(3, 4) + min(\n 5,\n 6\n)\n', |
