| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
| |
opcodes as v7 has them now (the anchor's seven in the place of the thirteen), a state's type as a module has it (an anchor 2, a bool 4, an i64 5), MOVE and COUNT naming the text or list (IN); at.line adds 1 to Pure's lines counted from 0; the language as it was
|
| |
|
|
| |
no bytes by key, message by key, name[key] or .replace(first .. last, value), the opcodes DOC, DOC_SIZE and REPLACE (those after them moved up), the header 38 bytes; examples/editor.aup and bounded-editor.aup gone (examples/documents.aup does their work in a keyed list), and with them the parity with the earlier editor (documents_model checks the new one); diagnostics on documents rewritten for plain messages or gone (304); a module's records counted at their v7 place; a field changed by '=' said so where a call was written
|
| |
|
|
| |
default's bytes), x.body.bytes its length (LEN), a text going there only as bytes(t); no list keyed by bytes or by a list; examples/documents.aup: keyed byte documents as a keyed list of records, each edit checked against the revision it was made on; documents_model: random shows and edits (stale revisions, past the end, any bytes, up to 5,000 at once) against a model, in memory and on a store restarting six times (half of the runs in bursts), four seeds alike (1,280 steps); four diagnostics
|
| |
|
|
| |
records holding lists (a message's rows not yet); xs[i].items.append(...) into a stored item; xs[i].field = a let's list, [] or a list value; an item of the same record appended as it is (ys.append(y)); a test against a model: columns of cards of tags under random steps in memory and on a store restarting eight times (half of the runs saving in bursts), six seeds, every step's fault, states and a view reading the lists alike (2,400 snapshots, 54 restarts); the stored list diagnostic now the message's rows'
|
| |
|
|
| |
characters (Pure 027's stage 2c): a fn with a block (statements, return a, b; return alone gives nothing) or one a cycle of calls goes through runs as Pure's function (CALL), once for each kinds of arguments it is called with, in code of its own after the handlers' and views'; its parameters held by name as it begins, its let's lists, held values and registers each call's own (Pure's); -> types where it calls itself before a return says what it gives, a return's values wanted as those types; f(x) as a statement where it gives nothing, let a, b = f(x) and a, b = f(x) (lets and states) where it gives several; a view, a count, sum, max or min calls none; records' and variants' values: R { ... }, V.case(x), V.case and calls giving one onto the stack field by field, held by a name (name.field lets), passed and given back, matched (a case's value named, read only), appended (a call's value held first), an item and a record under an item's field passed as values (a function has its own lists), a list a value holds walked through a register, a list in a local (Pure's local type 4), R { ... } written where a let, an assignment, a return or an argument takes a value; never-run lines after a return or a break refused, no jump past an else whose then stops, the last arm of a match that names every case taken without asking; for ch in t: a text's characters as code points (a let's, a parameter's, a state's, a record's field, a message's text field), char(n); examples/json_tree.aup by recursive descent and a depth-first walk; 13 diagnostics, 2 accepted forms, a functions test against Python (40 random trees built and summed recursively, deepest and leaves as two values, 60 random texts' characters, a call without end failing as memory with nothing changed); the 2b compiler's modules for 49 sources byte for byte the same (json_tree.aup's match aside); three diagnostics' wording follows records being values
|
| |
|
|
| |
2b): a field may hold a record or a variant (flattened into paths: at.x; a variant's case a field of its own, its value at name.case) or a list of anything (list of Json, a variant holding itself through a list); variant V { case, case(type) } and V.case(value) where items are made; match item { case(name) => ... _ => ... } over an item of a variant or a variant in a field (the binding a field, a list read through a register, or fields under it; missing cases refused); x.items.append(...), xs.last.items.append, xs[i].items.append; for, folds, count, first, last and [i] over a list in a field; xs[i] an item of an unkeyed list; number(t) of a text; examples/json_tree.aup; 16 diagnostics, an accepted program, a nested values test
|
| |
|
|
| |
decide alone (Pure 027's stage 2a): {v:08x}, {p:.2f} (Python's mini-language, [0][width][.digits][d x X b o f]), a + b of texts or of bytes, b[a .. c] of bytes and of texts (a cut inside a character failing as encoding), byte(n), let s = bytes or text (16 of each a handler, s = s + e appending in place), while c { } as a count to 2^53 that breaks when c is false, && and || computing their right side only where it decides (an AND or OR still where it cannot fail: comparisons, states and fields, a walked item's fields, a number plus a small literal, what the left side computed; every module of the apps and benchmarks byte for byte the same but json's); examples/json.aup, examples/sha256.aup in formats and joined bytes; 14 diagnostics, one accepted form, 144 random formats against Python's format() and an app cutting at commas
|
| |
|
|
| |
& | ^ ~ << >> on i64s by Python's precedence (a shift's count a number or an i64), b[i] the byte at a position of bytes (a field's, an argument's, a parameter's, bytes(t)), list of i64 (number, bool, text) as records of one field whose items read as their values, a let's list begun with [elements], xs[i] read and written by position (not_found past the end), bytes(xs), and a, b = x, y and let a, b = x, y given at once; examples/sha256.aup; 12 diagnostics, one accepted form, 192 random bit expressions against Python's integers and an app of bytes and lists
|
| | |
|
| |
|
|
| |
(Pure 018)
|
| | |
|
| |
|
|
| |
(002)
|
| |
|
|
|
|
|
| |
The task list's module is the same with its record in a library (2,509
bytes); one record of a library's three goes into a module using one; a
migration of the same library moves what the app stored; eleven
diagnostics. The example compiles.
|
| |
|
|
|
|
|
|
|
| |
A library declares records as it does fns: an app writes store.User,
which is User in its module (Pure's record names are identifiers, one
namespace with states), so a record moved into a library leaves the
module as it was and another module reading the same store has the
same record. Only the library records an app's lists and rows use go
into its module; a record value is matched to its declaration.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
state, record, message, output and argument fields, lets, views, keys
and slices can be i64 (Pure 016 stage 2). An integer literal becomes
an i64 where the other side of an operation, a comparison or an
assignment is one; a literal-only side follows the other, found by
compiling it on trial and rolling back. + - * and negation fail the
event with overflow, / and % floor, and i64(x) and number(n) are the
only way between the two, so a mix is a diagnostic that says so.
The check adds 18 i64 diagnostics, i64 accepted forms (with a 30-deep
chain that must stay linear), an event-by-event program past 2^53
and at the edges, and i64 values in the generated programs.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A condition was any number, non-zero being true: done was a number field,
a view showed 1 for true, and done + 1 was no type error. Now bool is its
own type (Pure 016, module format v6):
- true and false; comparisons, text comparisons, has and ! && || give a
bool. Bools are equal or not; they are no numbers and have no order.
- if, conditional expressions, require, where (folds, walks, filtered
tables) take a bool. Given a number, the diagnostic says how to make
one: "if takes a bool, not a number: compare it, as in n != 0".
- Bool states (state on = false), record fields (done = false), message,
output and argument fields (ok: bool), lets, views and columns.
Interpolation writes true or false. A list is not keyed by a bool.
- The examples' flags are bools (charge's holding, toggle's visible,
tasks' done).
Checks: 20 bool diagnostics, a form using bools everywhere, an app whose
every output shows true and false (states, items, views, columns, text)
and whose replacement turns a number into a bool and back. Models hold
bools and compare them strictly: Python's True == 1 no longer hides a 1
where a true belongs. Generated programs are typed, numbers and bools.
|
| |
|
|
|
|
|
|
|
|
| |
A message's, a group's and a record's fields took a newline or a
semicolon after each, while a value's (Kept { id: 1, t: "a" }, send)
take commas, and the language's own examples declared
message { title: text, points: number } and to: { city: text, zip: u32 },
which did not compile. Now a comma, a newline or a semicolon ends a
declared field too (one after the last as well); without one it says
so.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Adding one field to the board two nodes share (Pure's research 105)
still meant the record, the output, three sends and the code applying
what the other node sent: the sends and the apply named every field.
..source, last in a record value's or a send's braces, gives the fields
not written from the source's fields of the same names: an item (an
index, a let, the item a for walks, list[key]) or the handler's message
(grouped fields by their paths). A record value gives what the source
lacks its default; a send still needs every field. list[i] = Record {
... } sets every field of the item, all of them given; a keyed list's
key does not change, so a value with another key fails the event
(limit) and changes nothing.
Both are the fields written out: the checks compare the modules byte
for byte, and run the key rule in pure-run. Seven diagnostics: a spread
not last, a source that is no item nor this handler's message (also
another handler's message), a spread inside a send's group, a send
field left empty, a whole item missing a field, a value that is no
record. The board now sends { ..at } and applies cards[k] = Card {
..remote }: a new field is written in two places, the record and the
output.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Growing a board two nodes share (Pure's research 105), one field took
five places, two of them the same list: the output a node sends its
changes on and the input it takes the other's with. A message may now
take the fields of a message input or output declared before, in their
order: input remote = message like changed.
The module is the same as with the fields written out, byte for byte
(checked). An unknown name, one that is no message, the message itself,
and an output taking an input's rows are diagnosed.
|
| | |
|
| |
|
|
|
|
|
|
|
|
| |
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 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.
|
| |
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
| |
Pure now loads only v5 modules, where a view entry's type is one byte
followed by the table it belongs to. Plain views encode as before, so the
output changes only in its magic. The view limit follows Pure's to 64.
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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 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.
|
|
|
aup is the language and toolchain for the Pure runtime, as Java and javac
are for the JVM. v0a unifies the workbench scalar dialect (state, key
inputs, atomic handlers, views) with the same numeric semantics; v0b drafts
byte values and runtime-owned persistent documents to replace the document
dialect. Parity with the existing executors is the acceptance test.
|