aboutsummaryrefslogtreecommitdiffstats
path: root/docs/design/002-dsl-direction.md
Commit message (Collapse)AuthorAgeFilesLines
* Give views argumentseunhhu2026-09-281-0/+20
| | | | | | | | | | | | | | | | view name(argument: type, ...) = ... declares a view that takes u32, number, bytes or text arguments, read by name in the view, in a table's filter and columns and in the folds inside them (compiled to FIELD of an arguments input named name.args that names its view, Pure's kind 6). A host gives them as the request's query: GET /views/balance?aid=42, and a table pages as before with from and count. A query compiled with aup query may take arguments too. An argument's name may not be a state or another declaration, nor the table's row, nor from or count (which page a table). Eight diagnostics and an app of views with arguments (a keyed lookup, a fold, a text, a table filtered by two of them whose column folds with one, a handler's fold reading its message) are checked.
* Walk lists with for, and take a message's rowseunhhu2026-09-281-1/+44
| | | | | | | | | | | | | | | | | | | for item in list [where condition] { ... } runs its block in a handler once for every item the list has, in order, the item an index of the list (read, changed, removed: a removed item does not skip the next). It compiles to Pure's EACH; a fold inside reads the walk's item as a fold in a column reads its row. A for adds nothing to the list it walks, holds no other for and does not reply, so it ends. A message field may be a list of a record (lines: list of Line): its rows arrive as a JSON array of objects and fill a list of their own, named order.lines in the module, which the handler walks, folds and counts (order.lines.count) and which is emptied when the event ends. So a transaction over many rows (an order taking stock line by line, all or nothing) and a bulk insert are one event. An output sends no rows. Nine diagnostics and an accepted app (rows in a group, where, a fold over the rows reading the walk's item, a walk that removes) are checked.
* Add time: now, every timers, floor and %eunhhu2026-09-261-0/+24
| | | | | | | | | | now is the time of the event a handler runs for (milliseconds since 1970, UTC), which a host gives and a script can replay; views cannot read it. input tick = every 1 second declares a timer (ms, second, minute or hour; 1 ms to a day). floor(x) and x % y, taking the divisor's sign as Python does, take times apart. Checked against a Python model over 3,600 random steps; nine diagnostics.
* Add keyed lists and text comparisoneunhhu2026-09-261-2/+39
| | | | | | | | | | | | | state xs: list of R by field keeps its items in that field's order, each key once: xs.add(R { ... }) places an item (a taken key fails the event with exists), xs[key] finds one by halving (its field, or its index), xs.has(key) asks, xs.remove(key) removes. append and insert are refused on a keyed list, add on another, and a key field is never assigned. Texts compare with == != < <= > >= by their bytes. Checked against a Python model over 3,600 random steps with a text-keyed and a number-keyed list; 13 diagnostics; examples/tally.aup.
* Add aup watch: build again when what a build read changeseunhhu2026-09-261-0/+22
| | | | | | | | | | A build records every path it opened or looked for and a digest of the bytes there, so a rebuild happens exactly when one of them reads differently: the source, a library (the one with the error too), or a library appearing where one was searched. A change is built once it reads the same twice in a row, so a file caught halfway through being written is never built; the module is replaced whole through a rename.
* Find an item with first(t in tasks where ...)eunhhu2026-09-261-0/+3
| | | | | | | | | | first(item in list [where condition]) is the index of the first item the condition keeps, typed as an index of that list: at = first(...), a field through first(...).title, or its .position. With no such item a view has no value and a handler fails not_found. A fold's result now takes member access like a call's. The random model check jumps to the first open task and shows its position; one diagnostic joins.
* Filter a table view with whereeunhhu2026-09-261-0/+4
| | | | | | | | | | | view open_list = each t in tasks where !t.done { ... } has a row for each item the condition keeps, in the list's order; the condition compiles to the table's filter block, generated like a column so it reads the row's item, and the view entry names the list in the byte after its type. A count, sum, max or min inside the condition is a compile error, as Pure refuses a fold in a filter. The random model check now compares a filtered table too; two diagnostics join.
* Add count, sum, max and min over a listeunhhu2026-09-261-0/+21
| | | | | | | | | | | | | | | count(t in tasks where !t.done), sum(t.points for t in tasks), and max and min in the same form compile to Pure's FOLD: the value and the where condition become a block run once per item, as a column of the list, so views count and add without a copy of the list or a state kept in step. max(a, b), min(a, b) and fns of the same names stay calls, told apart by the `for` after the first expression or the `name in` after count(. Inside the block only its item and states can be read; a parameter of the fn outside, the enclosing column's row, dt and a fold inside a fold are compile errors that say why. The checks run 3,600 random steps against a Python model and add seven diagnostics.
* Declare marks: cursors that stay before inserted texteunhhu2026-09-261-0/+4
| | | | | | | | `state from: mark in note` is a cursor that stays before text inserted at its position; `cursor in` goes after it, as a caret does. Everything a cursor takes, a mark takes too. The notes example's mark is now one, and its reference model agrees: typing at the mark leaves it in place.
* Record Vega's first component in the planeunhhu2026-09-251-1/+1
|
* Add fns and librarieseunhhu2026-09-251-2/+30
| | | | | | | | | | | | | | | | fn name(params) = value declares one expression, inlined where it is called: arguments are computed once onto the stack and the body reads them with PICK, so a fn costs no runtime call and keeps Pure's bound on work. Parameters take any kind of value; recursion is a compile error. use name reads name.aup beside the source or from AUP_PATH. A library declares only fns and uses, sees only its parameters, and is called as name.fn(...). Diagnostics now carry the file they are in, and the compiler takes a loader so that sources come from the host. examples/words.aup is such a library; examples/tasks.aup uses it and still matches its reference model.
* Add conditional expressions and table viewseunhhu2026-09-251-2/+27
| | | | | | | | | | | | | | | | | if c { a } else { b }, with else-if chains, is an expression anywhere a value goes. Only the chosen branch runs, every branch gives the same type, and nesting that would pass Pure's limit of 8 value-carrying joins is a compile error. view name = each row in list { column = value ... } declares a table with a row per item; columns read their row as an index of the list. An index now reads and writes its item's fields directly (at.title, at.done = 1), so 'position' cannot name a record field. examples/tasks.aup gains conditional views and a board table and still matches its reference model; a new check confirms the unchosen branch is never computed.
* Add records, lists and indiceseunhhu2026-09-251-2/+42
| | | | | | | | | | | | | | A record declares named number and text fields with defaults. A list of a record is runtime-owned state, and an index of a list always names one of its items: it follows its item across inserts and removes and stops at the ends. Items are read and changed by field (tasks[at].title), appended or inserted as record values whose missing fields take defaults, and removed by index. Using an index of another list is a compile error. examples/tasks.aup matches a Python reference model over 4,800 random steps, including events that fail on an empty list. Replacing it with a module whose record gained and reordered fields keeps every item.
* Document the text language as implementedeunhhu2026-09-251-1/+17
| | | | | | | Record v0b as complete: which text syntax exists, what is still missing (multi-line strings, formats, graphemes, words), the insertion rule for cursors, and how the text model and parity checks verify it.
* Compile messages and keyed documents to module v2eunhhu2026-09-251-1/+1
| | | | | | | | | | | | | | | | | | aup now emits Pure module v2 and adds keyed byte collections (state documents: bytes by key), message inputs by key with u32 and a trailing bytes field, on-message handlers, field access, name[key] reads and .bytes sizes, replace(a .. b, value), reply and require, all checked for number/bytes types with file:line:column diagnostics. The document editor and its size-bounded variant are rewritten in aup. make check runs them through pure-edit-module against pure-edit running the original editor.pure programs: 1,280 random show/edit/apply operations, including conflicts, limits, missing documents, budgets and invalid keys, produce byte-identical stdout, stderr and exit codes, and each CLI reads the other's store identically. v0a parity with the workbench engine, 33 diagnostics and generated/damaged programs still pass, also with a sanitizer-built compiler.
* Set the DSL direction and the text modeleunhhu2026-09-251-0/+70
aup declares connections and leaves storage, transactions and screen models to Pure. Interface vocabulary lives in Vega, an aup library, not in the language. text is one immutable UTF-8 type from a word to a 1 MiB document; positions are cursors bound to a value that stay on character boundaries and follow edits, lengths name their unit, and comparison is exact without silent normalization. Stages v0b-v0d and their acceptance tests are listed.