| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
| |
list[low .. high], as a fold's or a for's list, is the items whose keys
are from low up to before high (a list keyed by a number), read by key:
distinct(l.item for l in lines[o * 16 .. o * 16 + 16] where
stock[l.item].quantity < t) reads one order's lines, whatever its test
does outside them. It compiles to Pure's sliced folds and walks; an empty
for over a slice still computes its keys. Two diagnostics and an app of
slices are checked.
|
| |
|
|
|
|
|
|
| |
distinct(value for item in list [where condition]) counts the different
values the included items give, compiled to Pure's fold of kind 5 (SQL's
count(distinct ...)). An accepted app walks and folds a keyed list in a
range of its key (where l.id >= start && l.id < start + 16), which Pure
reads by key.
|
| |
|
|
|
|
|
|
|
|
|
| |
let name = value, in a handler, names a number or an index for the rest
of its block; name = value gives it a new value of the same kind; the
walks and folds inside read it. It compiles to Pure's locals (a slot an
event, 0 when it begins, never saved), a slot a let in a handler, so an
order's loop sums into a let and takes stock through an index let without
finding the item again. A let may not be a declared name, another let in
scope or the walked item, and holds no text. Nine diagnostics and an app
of lets are checked.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
| |
aup's check keeps what it owns: the language, the compiler, and apps written
in aup matching their references on Pure's loader. The HTTP host's checks
moved to Pure's tests/check.py, which builds its apps with this compiler.
|
| |
|
|
|
|
|
| |
Pure now keeps the app model, the store and pure-serve in core/, store/ and
serve/ with one top-level make; the earlier document server the parity
checks compare against stays in prototypes/connections.
|
| |
|
|
|
|
|
|
|
| |
A Python payments API answers 200 or 402 and repeats a key's first
answer; the sender's output is wired to it and its answers to the
charged input. With the sender killed (-9) while clients buy, the
app's paid and declined counts and paid total match the API's answers
one per key. The language notes say how answers arrive.
|
| |
|
|
|
|
|
|
|
| |
A Python HTTPS server with its own certificate stands for a webhook:
five orders arrive in order with the output's JSON shape and the
sender's headers, one answered 503 at first arrives again, and a
sender that does not trust the certificate delivers nothing and says
so.
|
| |
|
|
|
|
|
|
|
|
| |
Two served apps, the sender's output wired to the receiver's input
(pure-serve --send): four clients order while the receiver and then
the sender are killed (-9) and started again on their stores; the
receiver's count and total end equal to what the sender saved, an
order the receiver refuses is delivered once and holds nothing back,
and every acknowledged order is among the saved ones.
|
| |
|
|
|
|
|
|
|
|
|
| |
An output is a message the app sends, with fields and groups as a
message has; send ordered { item: x, to: { city: y } } gives every
field once, in any order, groups in their own braces, and compiles to
Pure's SEND. Diagnostics cover a missing field, a group given a value,
an unknown field, a mistyped value, a send to a message, a handler for
an output, a field given twice and reading an output as a state; kinds
in messages now carry their article (an output, a key input).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A message's field block may hold groups, nested as deep as the 31
characters of a path allow; the compiler flattens them into fields
named by their path (to.city), which Pure's module format takes, so
groups cost nothing at run time. A member chain on a message names a
field by its path; one that stops at a group, or names a field the
group lacks, is diagnosed, and a field's own member (m.text.bytes)
still reads the field. A module may have 64 message fields.
The JSON server check posts 100 random bodies with groups two deep
(members shuffled at every level, strings with escapes, control bytes,
Korean, emoji and U+2028) to pure-serve, which reads them in place, and
compares the answers and the table with a Python model; a group's fixed
field from the query and ten malformed group bodies are checked too.
Six diagnostics cover groups.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
pure-serve now always runs an app with states on an owner thread and
shows views from the snapshot of its last save (Pure 080), so the
server check expects an owner with one connection thread too and
views answered from snapshots. While six clients post and the server
is killed, two readers on other connections now check that each read
sees every point acknowledged before it was asked, that the total never
goes back, and that the total after the restart is at least any total
they saw: nothing unsaved was shown.
|
| |
|
|
|
|
|
|
|
|
| |
Views of a 1 MiB note are pipelined on one connection, more than the
kernel takes, while the note is replaced: each answer is one whole
version, the store mapping the waiting answers hold stays (through a
compaction too) and is unmapped once they are read, or once the reader
leaves without reading, and nothing stays charged. On one thread and
with an owner.
|
| |
|
|
|
|
| |
The limit's diagnostic now comes from fns that double what they inline,
and a module of some 12,000 instructions (200 KB) must compile and run.
|
| |
|
|
|
|
|
| |
A served app ticking every 50 ms counts its beats and stamps a posted
event with the server's clock, on one thread and with an owner, and a
restarted server goes on counting from the stored beats.
|
| |
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
| |
input add = message { title: text, points: number } now compiles, with
variable fields anywhere and several of them. The served-app checks post
300 random JSON objects (escapes, control bytes, Korean, surrogate pairs,
members in any order) and read them back as Python's json module does,
with a list of bodies that must be refused and why.
|
| |
|
|
|
|
|
| |
The random HTTP requests against the model and the kill -9 while clients
post also run with three connection threads handing requests to the
app's owner.
|
| |
|
|
|
|
|
|
|
| |
A keyed-list app is served by pure-serve and driven by random POSTs (a
message with query fields and a body, a text, a key) and GETs (a number,
a text, pages of a table): statuses, fault names, bodies and JSON rows
match a Python model, and every acknowledged event survives a restart
and a kill -9 while six clients post.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
| |
`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.
|
| |
|
|
|
|
|
| |
Two readers that stop reading keep one 1 MiB answer each waiting on
their sockets; a third read must get 503 payload_budget until one of
them goes.
|
| |
|
|
|
|
| |
A 1 MiB read sent over a slow socket must carry the version it read while
the document is replaced five times meanwhile.
|
| |
|
|
|
|
| |
Server parity and the kill -9 durability check also run with pure-serve
--threads 3.
|
| |
|
|
|
|
|
|
| |
The server checks run pure-serve, which replaced the module mode of the
old document server. A keep-alive client and pipelined requests (sent in
one write, and in writes that cut heads and bodies) must get the same
answers, in order, as separate connections.
|
| |
|
|
|
|
|
|
|
|
| |
The HTTP document server running editor.aup must answer random requests
exactly as the server running editor.pure (status, revision, error and
body); concurrent edits must share commits; and every edit it acknowledged
must survive kill -9. Every other stored run of the list app and the text
editor saves in bursts and still matches its reference model across
restarts.
|
| |
|
|
|
|
|
|
| |
The list app and the text editor run on a tree store through pure-run
--store, restarting at random points, and must keep matching their
reference models. The language notes state that a declared state is a
stored state when the host gives a store.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
aup now emits Pure module v3 and adds text states with string initializers,
cursors bound to a text, text inputs, string literals with escapes and
{interpolation} of numbers and text, cursor distances in chars and lines,
.start/.end, insert/remove, name.line(cursor), .chars/.lines/.bytes on text,
.chars/.line on cursors, and text(bytes)/bytes(text). Replies and replace
accept text as its UTF-8 bytes. Views are numbers or text. Up to 32 inputs.
examples/notes.aup is a small editor. make check replays random typing
(ASCII, Korean, emoji, combining marks, NUL, newlines), moves and deletions
against a Python reference model: 4,800 snapshots of text, cursor, mark and
views match. It also checks escapes and number text, 16 new diagnostics, a
document loaded into text and saved back, and all earlier parity; the
compiler and the Pure executor each pass under ASan/UBSan.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
aup check/build parse states, key inputs, views and handlers (with if/else
and else-if), resolve names, generate forward-only stack code and encode a
Pure module v1 deterministically. Diagnostics carry file:line:column.
make check loads every module with Pure's verifier, checks determinism, 20
diagnostics and accepted forms, replacement by name, 600 generated programs
and damaged sources (every emitted module verifies), and replays random event
scripts against the workbench Zig engine: 16,667 snapshots across counter,
toggle, charge, else-if and fault programs matched, including 921 failed
events. The sanitizer-built compiler passes the same checks.
|