Public
Edited
Dec 9, 2023
1 fork
Insert cell
Insert cell
Insert cell
tasl= import("https://cdn.jsdelivr.net/npm/tasl@0.3.0-rc.3/+esm");
Insert cell
lezertasl= import("https://cdn.jsdelivr.net/npm/lezer-tasl@0.3.0/+esm");
Insert cell
tree = lezertasl.parser.parse(`# hello world
namespace s http://schema.org/

class s:Person {
s:name -> string
}
`)
Insert cell
parserTasl = generator.buildParser(taslGrammar)
Insert cell
render(parserTasl.parse(`
namespace s http://schema.org/
namespace ii http://iios.io/

# algebraic graph
class ii:Graph [
ii:Empty
ii:Vertex <- * ii:Node
ii:Connect <- {
ii:Edge -> * ii:Link
ii:Left -> * ii:Graph
ii:Right -> * ii:Graph
}
]

type ii:Node [
ii:Person <- s:Person
]

class s:Person {
s:name -> {
s:familyName -> string
s:givenName -> string
}
s:email -> uri
s:gender -> [
s:Male
s:Female
s:value <- string
]
}

class ii:Book {
s:name -> string
s:identifier -> uri
s:author -> * s:Person
}
`))
Insert cell
Insert cell
Insert cell
generator = import("https://cdn.jsdelivr.net/npm/@lezer/generator@1.5.1/+esm")
Insert cell
parserSample = generator.buildParser(`
@top Program { expression }

expression { Name | Number | BinaryExpression }

BinaryExpression { "(" expression ("+" | "-") expression ")" }

@tokens {
Name { @asciiLetter+ }
Number { @digit+ }
}
`)
Insert cell
function render(tree) {
let lists = ''
tree.iterate({
enter({type, from, to}) {
lists += `<ul><li>${type.name} (${from}→${to})`
},
leave() {
lists += '</ul>'
}
})
return Object.assign(html`${lists}`, { value: tree });
}
Insert cell
Insert cell
grammar = `
@top Instances { (statement? newline)* statement? }

@tokens {
OpenBrace[closedBy="CloseBrace"] { "{" }
CloseBrace[openedBy="OpenBrace"] { "}" }
OpenBracket[closedBy="CloseBracket"] { "[" }
CloseBracket[openedBy="OpenBracket"] { "]" }
RightArrow { "->" }
LeftArrow { "<-" }

newline { "\n" }
space { (" " | "\t")+ }
Comment { "#" ![\n]* }
identifier { std.asciiLetter (std.asciiLetter | std.digit)* }

Id { '0' | $[1-9] @digit* }

hexDig { $[0-9A-Fa-f] }
subDelims { $[!$&'()*+,;=] }
unreserved { $[A-Za-z0-9\-._~] }
pctEncoded { "%" hexDig hexDig }
decOctet { "25" $[0-5] | "2" $[0-4] std.digit | $[01]? std.digit std.digit? }
ipv4address { decOctet "." decOctet "." decOctet "." decOctet }
h16 { hexDig (hexDig (hexDig hexDig?)?)? }
ls32 { h16 ":" h16 | ipv4address }
ipv6address {
h16 ":" h16 ":" h16 ":" h16 ":" h16 ":" h16 ":" ls32
| "::" h16 ":" h16 ":" h16 ":" h16 ":" h16 ":" ls32
| h16? "::" h16 ":" h16 ":" h16 ":" h16 ":" ls32
| (h16 (":" h16)?)? "::" h16 ":" h16 ":" h16 ":" ls32
| (h16 (":" h16 (":" h16)?)?)? "::" h16 ":" h16 ":" ls32
| (h16 (":" h16 (":" h16 (":" h16)?)?)?)? "::" h16 ":" ls32
| (h16 (":" h16 (":" h16 (":" h16 (":" h16)?)?)?)?)? "::" ls32
| (h16 (":" h16 (":" h16 (":" h16 (":" h16 (":" h16)?)?)?)?)?)? "::" h16
| (h16 (":" h16 (":" h16 (":" h16 (":" h16 (":" h16 (":" h16)?)?)?)?)?)?)? "::"
}
ipvFuture { $[Vv] hexDig+ "." (unreserved | subDelims | ":")+ }
ipLiteral { "[" (ipv6address | ipvFuture) "]" }
regName { (unreserved | pctEncoded | subDelims)* }
host { ipLiteral | ipv4address | regName }
userinfo { (unreserved | pctEncoded | subDelims | ":")* }
authority { (userinfo "@")? host (":" std.digit+)? }
pchar { unreserved | pctEncoded | subDelims | ":" | "@" }
scheme { std.asciiLetter $[A-Za-z0-9+\-.]* }
uri { scheme ":" ("//" authority | "/"? pchar+) ("/" pchar*)* }

char { $[\\u{20}\\u{21}\\u{23}-\\u{5b}\\u{5d}-\\u{10ffff}] | "\\\\" esc }
esc { $["\\\/bfnrt] | "u" hex hex hex hex }
hex { $[0-9a-fA-F] }

unit { "()" } // the haskell way?
string { '"' char* '"' }
boolean { "true" | "false" }
// f32 { "" }
// f64 { "" }
// i64 { "" }
// i32 { "" }
// i16 { "" }
// i8 { "" }
// u64 { "" }
// u32 { "" }
// u16 { "" }
// u8 { "" }
// bytes { "" }
// JSON { "JSON" } // should we import the JSON grammar?

term { identifier ":" (pchar | "/" | "?")* pchar+ }
Namespace { uri $[/?#] }

@precedence { boolean, uri }
}

@skip { space | Comment }

delimited<element> { (newline element?)* newline }

Literal {
unit | string | boolean
// | f32 | f64 | i64 | i32 | i16 | i8 | u64 | u32 | u16 | u8
// | bytes
// | JSON
}

Key { term }

Element { Key "#" Value }
Value { uri | Literal | Product | Coproduct | Reference }

Product { OpenBrace delimited<Component>? CloseBrace }
Component { Key RightArrow Value }

Coproduct { OpenBracket delimited<Option>? CloseBracket }
Option { Key (LeftArrow Value)? }

Reference { "*" Key }

statement { NamespaceDefinition | ElementDeclaration }

NamespaceDefinition { @specialize[@name=namespace]<identifier, "namespace"> Prefix { identifier } Namespace }
ElementDeclaration { @specialize[@name=element]<identifier, "element"> Key Value }
`;
Insert cell
parser = generator.buildParser(grammar);
Insert cell
instances = `
namespace s http://schema.org/

s:Person#jun s:name#"Jun" s:email#jun@iilab.org s:gender#s:Male
# there's only one namespace so we allow it to be implicit
# Person#jun name#"Jun" email#jun@iilab.org gender#Male

# maybe for products we allow the values to be positional as in Haskell
# the tasl instance binary format uses lexicographical ordering of keys
# we would need to generate part of the grammar from the schema

# Person#jun "Jun" jun@iilab.org Male

# or we could do it a bit like csv
# Person#name#email#gender
# jun "Jun" ...

# Then we allow the multiline context
# Person#name#email#gender
# jun "Jun" jun@iilab.org Male
# jane "Jane" jane@example.org value#"non-binary"

# We would need a syntax for nested products
# Person#name{familyName#givenName}#email#gender
# jun "Doe" "Joe" joe@example.org Male
# jane "Doe" "Jane" jane@example.org value#"non-binary"

# It's a bit busy on the eye. Maybe good'ol csv is not such a bad idea?
# Person: name {familyName, givenName}, email, gender
# jun: "Doe" "Joe" joe@example.org Male
# jane: "Doe" "Jane" jane@example.org value#"non-binary"

`;
Insert cell
render(parser.parse(instances))
Insert cell
instanceTree = `
ex:Knowledge#typeclassopedia
ex:Knowledge#functor in#typeclassopedia a:root
ex:Knowledge#applicative in#typeclassopedia a:branch#functor
ex:Knowledge#monad in#typeclassopedia a:branch#applicative
`;
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more