Data - pannous/warp GitHub Wiki
Data is unevaluated content never meant to run (vocabulary: charged): a data file, data e in a program,
and plain words (symbols). Angle usually uses the wasp data format:
# … stands for more fields
person{name="Joe"}
person{name:"Joe" number:12345 address:{street=…}}
Everything is a node internally. Nodes have internal primitive types:
In data, without evaluation these groupings are similar:
{1 2 3} [1 2 3] (1 2 3) all denote a list with 3 elements.
{a:1 b:2 c:3} [a:1 b:2 c:3] (a:1 b:2 c:3) all denote a map with 3 elements.
In a program they differ: () is a group evaluated on the spot, [] a list of evaluated elements, and {} is data by
default, an object whose : entries are uncharged, or a block of statements (charged sections 4 and 6).
A program is code; data is marked: data [cube 3] keeps the list unevaluated, and a word on its own is a symbol
(colors = [red green blue]). ! on data runs it as code, with a warning.
parse turns a text into such data, the same Node that data (…) gives, and the node words read it:
x = parse("n * 1")
x == data(n * 1) // yes
x.op // *
A text known at compile time is parsed then, any other text at run time (the host word parse_code). A text that
does not parse is an Error that try catches:
try parse("(1 2") else "bad" // "bad"
Quoted code remembers where it was written and the comment above it, or the one ending its line:
code = data (n * 1)
code.line // 1
code.column // 14
settings = data {
// how many
count: 3
}
settings#1.comment // how many
settings = data {
count: 3 // how many
size: 4
}
settings#1.comment // how many
Data stays data: a bare word in it is a symbol, even one that names something. Only ! and ${…} evaluate:
friends{peter created:now} // friends{peter created:now}
friends{peter created:now!} // the time the run reads it
There is a subtle difference between
person{name:"Joe" address{street:"no way 123"}}
person:{name="Joe" address:{street="no way 123"}}
While both construct an object person, the variant with colon constructs pure data while the variant without colon
constructs the person via a constructor, if available.
So if previously type person is defined like
a person has a random id
then Joe will automatically derive that id if constructed as person{name:"Joe"} (planned, card english-type-facts).
The pure data built with person:{name="Joe"} only has a soft-type of person, an elusive unenforced type hint.
Apart from the above canonical format, Angle can also consume lisp/wasp
/polish-notation style data:
(person (name Joe))
Since these formats have different semantics, the lisp style needs a special keyword to activate the slightly modified parser.
Another slightly different format called kdl treats each line as a node instead of list:
html lang="en" {
head {
meta charset="utf-8"
meta name="viewport" content="width=device-width, initial-scale=1.0"
meta \
name="description" \
content="kdl is a document language, mostly based on SDLang, with xml-like semantics"
title "kdl - Kat's Document Language"
link rel="stylesheet" href="/styles/global.css"
}
body {
main {
h1 class="text-4xl text-center" "kdl - Kat's Document Language"
section class="kdl-section" id="description" {
p {
- "kdl is a document language, mostly based on "
a href="https://sdlang.org" "SDLang"
- " with xml-like semantics that looks like you're invoking a bunch of CLI commands"
}
p "It's meant to be used both as a serialization format and a configuration language, and is light compared to XML."
}
}
}
}
To illustrate the difference, mutable x=7 is parsed as (mutable x)=7 in wasp and mutable[x=7] in kdl. Another difference is a significant white space behind node ids: form {} in wasp is a compile time ambiguity.
The only thing I don't like in kdl are
- string values need to be quoted
- the
-for text node_pointer without name/identifier/key. The (false) reason is that quotes at the beginning of node_pointer denote complex identifiers: person "home address":berlin This is fine, but the distinguishing syntax role should be: if a quoted node is empty it is a text node
With that rule both formats are nearly compatible and the remaining difference can be put behind a parser directive or flag. It is really just a question of whether 'space binds stronger than =' as in wasp or not as in kdl.
See significant whitespace and ambiguity
Since these are border cases, there is a compiler pragma/directive/flag to switch to each desired behavior on
demand
e.g. when parsing lisp, sexp, wasp, csv or kdl data; each such mode is also activated via file extension.
These seemingly different data formats are really structurally quite similar an create minimal bearing on the parser.