Compare commits
41 commits
32c981f245
...
746c81ab60
Author | SHA1 | Date | |
---|---|---|---|
746c81ab60 | |||
0615ea653c | |||
6006f92d9c | |||
7c9dca0ae2 | |||
ea2e5d6075 | |||
6ccfaedb13 | |||
e67c80a6a9 | |||
96374b6491 | |||
4788278d86 | |||
33aa131b95 | |||
e7db9c38f3 | |||
92aa3b4a3a | |||
24ffe91b66 | |||
666b4f9cb6 | |||
53cc3f26dd | |||
ec3d1310bf | |||
e986f0fc1d | |||
41e21bac16 | |||
a9b69094cc | |||
47f6025963 | |||
9a2f982d40 | |||
5f95f36214 | |||
ef7ab3e239 | |||
fe96a17551 | |||
35695537bd | |||
cbbe2c3253 | |||
221ca09961 | |||
bebf2a97a4 | |||
b9ea83b1c6 | |||
6bd07b639b | |||
9233b0e339 | |||
b30cbb4d7b | |||
32b547f9fa | |||
3746726245 | |||
6217a984a2 | |||
388827a50e | |||
efdfb5705e | |||
70256a7bfc | |||
b91e697449 | |||
e1dc5ce132 | |||
22a655fd24 |
12 changed files with 523 additions and 222 deletions
3
.envrc
3
.envrc
|
@ -1 +1,2 @@
|
|||
use flake . --impure
|
||||
use flake . --impure
|
||||
export TYPST_ROOT="$(pwd)/docs"
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,3 +3,4 @@
|
|||
/target
|
||||
.pre-commit-config.yaml
|
||||
*.pdf
|
||||
*.png
|
||||
|
|
|
@ -3,7 +3,6 @@ The current maintainers, that is,
|
|||
|
||||
- [@Schrottkatze](https://forge.katzen.cafe/schrottkatze)
|
||||
- [@multisamplednight](https://forge.katzen.cafe/multisamplednight)
|
||||
- @iota-xSK
|
||||
|
||||
are the entities to email, message or talk to if you feel like any interaction in the context of
|
||||
iOwO is not okay. We'll try to answer as soon as we can.
|
||||
|
|
|
@ -10,7 +10,7 @@ Before we get started, thank you for thinking about doing so!
|
|||
### Bugs
|
||||
|
||||
- Write out in detail which steps in which order are necessary to reproduce the bug.
|
||||
- Include environmental information as well, in specific
|
||||
- Include environmental information as well, in specific:
|
||||
- How did you install iOwO?
|
||||
- What version of iOwO are you running?
|
||||
- What operating system are you running?
|
||||
|
@ -19,9 +19,9 @@ Before we get started, thank you for thinking about doing so!
|
|||
|
||||
### Feature requests
|
||||
|
||||
- Be sure to include a motivation in which case your intended feature would be used,
|
||||
- Be sure to include a motivation in which case your intended feature would be used
|
||||
even if it seems obvious to you.
|
||||
- Estimate what would be needed to implement the feature.
|
||||
- Estimate what would be needed to implement the feature:
|
||||
- Is it an addition to the language itself?
|
||||
- Is it just a new command?
|
||||
- Does it ground-breakingly change how iOwO works?
|
||||
|
@ -42,6 +42,8 @@ Before we get started, thank you for thinking about doing so!
|
|||
1. combine your patches using `git diff --patch` and throw them in a file
|
||||
2. send that file to one of the maintainers per email
|
||||
- alongside with a description of what it does
|
||||
3. also mention in the mail that we should consider GitHub and GitLab mirrors,
|
||||
referring to this line
|
||||
|
||||
### Tech stack
|
||||
|
||||
|
@ -49,32 +51,36 @@ The techstack we operate on is
|
|||
|
||||
- [typst] for documents and concrete proposals
|
||||
- [Rust] for the actual code
|
||||
|
||||
So if you want to contribute functionality, take a look at [The Rust Programming Language book]!
|
||||
If you want to contribute thoughts and technical designs, then consider taking a ride through
|
||||
[typst's excellent tutorial]!
|
||||
|
||||
For creative things, we suggest using whatever **you** are comfortable with.
|
||||
Otherwise, we suggest these:
|
||||
|
||||
- [Inkscape], [GIMP] and [Blender] for promotional material like logos and posters
|
||||
- [Penpot] for layouting prototypes and the like
|
||||
|
||||
So if you want to contribute functionality, take a look at [The Rust Programming Language book]!
|
||||
If you want to contribute thoughts and techincal designs, then consider taking a ride through
|
||||
[typst's excellent tutorial]!
|
||||
If you want to contribute art or the like, do that in whatever **you** are most comfortable with!
|
||||
|
||||
[typst]: https://typst.app
|
||||
[Rust]: https://www.rust-lang.org
|
||||
[The Rust Programming Language book]: https://doc.rust-lang.org/book/
|
||||
[typst's excellent tutorial]: https://typst.app/docs/tutorial
|
||||
|
||||
[Inkscape]: https://inkscape.org/
|
||||
[GIMP]: https://www.gimp.org/
|
||||
[Blender]: https://www.blender.org/
|
||||
[Penpot]: https://penpot.app/
|
||||
[The Rust Programming Language book]: https://doc.rust-lang.org/book/
|
||||
[typst's excellent tutorial]: https://typst.app/docs/tutorial
|
||||
|
||||
## Politics
|
||||
|
||||
- Current maintainers are defined as the entities listed in the [code of conduct].
|
||||
- Current maintainers are defined as the entities listed in the [code of conduct]
|
||||
|
||||
### PRs
|
||||
|
||||
- Every PR requires an approving review from a maintainer (that is not the author) before merge.
|
||||
- Maintainers can merge their own PRs.
|
||||
- But only after approval.
|
||||
- Every PR requires an approving review from a maintainer (that is not the author) before merge
|
||||
- Maintainers can merge their own PRs
|
||||
- But only after approval
|
||||
|
||||
### Major decisions
|
||||
|
||||
|
@ -82,6 +88,33 @@ If you want to contribute art or the like, do that in whatever **you** are most
|
|||
- Agreement must be based on [informed consent].
|
||||
- In effect, a maintainer has to understand what they agree to.
|
||||
|
||||
# Interacting with PRs
|
||||
|
||||
Remember, be respectful.
|
||||
Entities invest their free time and motivation into making these changes,
|
||||
treat them appropiately.
|
||||
|
||||
- Since we mostly work based on forks, [git's remotes] work fairly good.
|
||||
- Replace things in pointy brackets (`<>`) respectively (and remove the pointy brackets).
|
||||
|
||||
## Initial steps for a new contributor or new local checkout
|
||||
|
||||
```sh
|
||||
git remote add <contributor-name> https://forge.katzen.cafe/<contributor-account>/iowo.git
|
||||
git remote update <contributor-name>
|
||||
```
|
||||
|
||||
## After setting up the remote
|
||||
|
||||
- You can repeat this step anytime you want to switch branches or update your local checkout.
|
||||
- The PR branch is visible just below the PR title on Forgejo, after the colon (`:`).
|
||||
|
||||
```sh
|
||||
git switch <pr-branch>
|
||||
git pull
|
||||
```
|
||||
|
||||
|
||||
[code of conduct]: ./CODE_OF_CONDUCT.md
|
||||
[informed consent]: https://en.wikipedia.org/wiki/Informed_consent
|
||||
|
||||
[git's remotes]: https://git-scm.com/docs/git-remote
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
#import "@preview/cetz:0.1.2"
|
||||
#import cetz.draw: *
|
||||
|
||||
// quick reference
|
||||
// - `graphic` is for inline icons/images
|
||||
// - `canvas` is for centered more prominent stuff
|
||||
// - `group` can be used in either of ^, but not standalone
|
||||
|
||||
#let graphic(what) = box({
|
||||
cetz.canvas({
|
||||
// any preamble-ish stuff can go here
|
||||
set-style(
|
||||
mark: (angle: 90deg)
|
||||
)
|
||||
|
||||
what
|
||||
})
|
||||
})
|
||||
|
||||
#let canvas(what) = {
|
||||
align(center, graphic(what))
|
||||
}
|
||||
|
||||
|
||||
// smaller stuff
|
||||
|
||||
#let arrow(length: 1cm, lift: 4pt, stroke: 1pt) = graphic({
|
||||
line((0, lift), (rel: (length, 0)), mark: (end: ">", stroke: stroke))
|
||||
|
||||
// hack for the bounding box bottom
|
||||
// so that `lift` even has any effect
|
||||
line((0, 0), (0, 0), stroke: none)
|
||||
})
|
||||
|
||||
// larger stuff
|
||||
|
||||
#let nodes(
|
||||
distance: 3cm,
|
||||
arrow-spacing: 0.15cm,
|
||||
// cetz will support rounded rects in 0.2.0
|
||||
style: (frame: "rect", padding: 0.1cm),
|
||||
..labels,
|
||||
) = group({
|
||||
let labels = labels.pos()
|
||||
|
||||
// draw each label itself
|
||||
for (i, label) in labels.enumerate() {
|
||||
if i != 0 {
|
||||
set-origin((distance, 0))
|
||||
}
|
||||
content((0, 0), name: "label-" + str(i), label, ..style)
|
||||
}
|
||||
|
||||
// then draw an arrow from each to each
|
||||
// since an arrow is between two, the last one can't be connected with the "next-to-last" one
|
||||
// so we leave it out
|
||||
for i in range(labels.len() - 1) {
|
||||
line(
|
||||
(rel: (arrow-spacing, 0), to: "label-" + str(i) + ".right"),
|
||||
(rel: (-arrow-spacing, 0), to: "label-" + str(i + 1) + ".left"),
|
||||
mark: (end: ">"),
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
#let stages-overview = canvas({
|
||||
nodes(
|
||||
[Source],
|
||||
[AST],
|
||||
[Graph IR],
|
||||
[Runtime],
|
||||
)
|
||||
})
|
||||
|
||||
// literally just for standalone display of the graphics alone
|
||||
#import "../template.typ": conf
|
||||
#show: conf
|
|
@ -1,119 +1,56 @@
|
|||
#import "../template.typ": conf
|
||||
#import "graphics.typ"
|
||||
#import "util/graphics.typ"
|
||||
#import graphics: arrow
|
||||
|
||||
#show: conf.with(title: [iOwO design], subtitle: [don't worry, we're just dreaming])
|
||||
|
||||
// highlight important terms in bold
|
||||
#let expand(it) = {
|
||||
("("
|
||||
+ upper(it.first())
|
||||
+ "|"
|
||||
+ it.first()
|
||||
+ ")"
|
||||
+ it.clusters().slice(1).join()
|
||||
+ "s?")
|
||||
}
|
||||
#let singlify(it) = {
|
||||
it = lower(it)
|
||||
if it.ends-with("s") {
|
||||
it = it.slice(0, -1)
|
||||
}
|
||||
it
|
||||
}
|
||||
#let terminate-recursion(it) = {
|
||||
let clusters = it.text.clusters()
|
||||
clusters.insert(1, "\u{FEFF}")
|
||||
clusters.join()
|
||||
}
|
||||
// even though it looks like this could be automated with a `query`,
|
||||
// this'd require wrapping the whole document in a show rule
|
||||
// at which point `query` doesn't find anything anymore
|
||||
#let terms = (
|
||||
"source",
|
||||
"ast",
|
||||
"graph IR",
|
||||
"runtime",
|
||||
|
||||
"optimizer",
|
||||
"scheduler",
|
||||
"VM",
|
||||
|
||||
"command",
|
||||
"pipeline",
|
||||
"input", "argument", "consumer",
|
||||
"output", "streamer",
|
||||
"modifier",
|
||||
)
|
||||
#let terms-trigger = regex(terms.map(expand).join("|"))
|
||||
#show raw: it => {
|
||||
// avoid making terms in codeblocks bold
|
||||
show terms-trigger: terminate-recursion
|
||||
it
|
||||
}
|
||||
#show terms-trigger: strong
|
||||
|
||||
// color codeblocks
|
||||
// haskell hl seems to work ok for this
|
||||
#show raw.where(lang: "iowo", block: true): it => {
|
||||
raw(it.text, lang: "haskell", block: true)
|
||||
}
|
||||
|
||||
// actual content lol
|
||||
|
||||
#outline(
|
||||
indent: auto,
|
||||
fill: line(
|
||||
length: 100%,
|
||||
stroke: (
|
||||
cap: "round",
|
||||
join: "round",
|
||||
thickness: 0.5pt,
|
||||
paint: luma(75%),
|
||||
),
|
||||
),
|
||||
#show: conf.with(
|
||||
title: [iOwO design],
|
||||
subtitle: [don't worry, we're just dreaming],
|
||||
)
|
||||
|
||||
= Type data model
|
||||
|
||||
== Requirements
|
||||
|
||||
- Color-aware
|
||||
- It can handle colors and colorspaces for images
|
||||
- OpenColorIO?
|
||||
- number/number type support
|
||||
- custom types (structs/enums)
|
||||
- algebraic enums
|
||||
- traits (`Numeric`...)
|
||||
|
||||
= Execution stages
|
||||
= Evaluation stages
|
||||
|
||||
#graphics.stages-overview
|
||||
|
||||
iOwO operates in stages.
|
||||
This has a number of benefits and implications:
|
||||
|
||||
- One can just work on one aspect of the stages without having to know about the rest.
|
||||
- Bugs are easier to trace down to one stage.
|
||||
- Stages are also replacable, pluggable and usable somewhere else.
|
||||
- For example,
|
||||
one could write a Just-In-Time compiler as a new executor to replace the runtime stage,
|
||||
while preserving the source #arrow() graph IR step.
|
||||
|
||||
However, this also makes the architecture somewhat more complicated. So here we try our best to describe how each stage looks like. If you have any feedback, feel free to drop it on #link("https://forge.katzen.cafe/katzen-cafe/iowo/issues")[the issues in the repository]!
|
||||
|
||||
== Source <source>
|
||||
|
||||
```iowo
|
||||
open base.png >|
|
||||
open stencil.png >|
|
||||
mask
|
||||
|> (invert | show)
|
||||
|> show
|
||||
|> (invert | show)
|
||||
```
|
||||
|
||||
Functional and pipeline-based.
|
||||
However, in contrast to classic shell commands,
|
||||
commands can have multiple outputs and multiple inputs.
|
||||
functions can have multiple outputs and multiple inputs.
|
||||
|
||||
=== Commands
|
||||
=== Functions
|
||||
|
||||
`open`, `invert`, `mask`, `show` and friends.
|
||||
|
||||
The foundation of actually "doing" something.
|
||||
|
||||
- Can have any, even infinite, amount of inputs and outputs.
|
||||
- Their amounts may or may not be equal.
|
||||
- Inputs and outputs must have their types explicitly declared.
|
||||
- An command with
|
||||
- An function with
|
||||
- at least one output is called a streamer.
|
||||
- at least one input is called a consumer.
|
||||
- _both_ at least one input and at least one output is _both_ a streamer and a consumer, and culminatively called a modifier.
|
||||
- _both_ at least one input and at least one output is _both_ a streamer and a consumer,
|
||||
and culminatively called a modifier.
|
||||
- May also contain spaces in its name.
|
||||
|
||||
==== Inputs <input>
|
||||
|
@ -124,9 +61,9 @@ The foundation of actually "doing" something.
|
|||
- So all of these are equivalent:
|
||||
|
||||
```iowo
|
||||
1 | add 2
|
||||
add 1 2
|
||||
[ 1 2 ] | add
|
||||
add 1 2 -- all inputs as arguments
|
||||
[ 1 2 ] | add -- all inputs through the pipeline
|
||||
1 | add 2 -- one input through the pipeline, one as argument
|
||||
```
|
||||
|
||||
==== Outputs
|
||||
|
@ -139,7 +76,9 @@ add 1 2
|
|||
|
||||
==== Simple forwarding
|
||||
|
||||
In the simplest case, where inputs map to outputs bijectively#footnote[one to one], pipelines are just pipes and forward unchanged:
|
||||
In the simplest case,
|
||||
where inputs map to outputs bijectively#footnote[one to one],
|
||||
pipelines are just pipes and forward unchanged:
|
||||
|
||||
```iowo
|
||||
open owo.png | invert | save owo.png
|
||||
|
@ -151,13 +90,14 @@ To handle each output of a streamer individually, they can be _split_:
|
|||
|
||||
```iowo
|
||||
mask
|
||||
|> invert -- would invert the unmasked part
|
||||
|> show -- would show the masked part
|
||||
|> invert -- would invert the unmasked part
|
||||
```
|
||||
|
||||
==== Combination <combination>
|
||||
|
||||
To throw multiple streamers into the inputs of a consumer, they can be _combined_:
|
||||
To throw multiple streamers into the inputs of a consumer,
|
||||
they can be _combined_:
|
||||
|
||||
```iowo
|
||||
open base.png >|
|
||||
|
@ -165,7 +105,8 @@ open stencil.png >|
|
|||
mask
|
||||
```
|
||||
|
||||
However, since lists are automatically spliced into inputs, this is equivalent to the above:
|
||||
However, since lists are automatically spliced into inputs,
|
||||
this is equivalent to the above:
|
||||
|
||||
```iowo
|
||||
[
|
||||
|
@ -193,15 +134,29 @@ Done with any of `--` or `//`.
|
|||
|
||||
== Graph IR
|
||||
|
||||
#graphics.graph-example
|
||||
|
||||
The parsed representation of the source, and also what the runtime operates on.
|
||||
|
||||
In a way, this is the AST, except that it's not a tree.
|
||||
|
||||
It is represented in iOwO using adjacencies, where essentially
|
||||
the vertices#footnote[Nodes or functions in this case.]
|
||||
and their edges#footnote[Connections or pipes in this case.]
|
||||
are stored separately.
|
||||
|
||||
=== Optimizer
|
||||
|
||||
Merges and simplifies commands in the graph IR.
|
||||
Merges and simplifies functions in the graph IR.
|
||||
|
||||
== Runtime
|
||||
== Runtime <runtime>
|
||||
|
||||
Runs through all functions in the graph IR.
|
||||
It does not have any significantly other representation,
|
||||
and despite its name there's _no_ bytecode involved.
|
||||
|
||||
Different runtimes are called executors.
|
||||
Executors operate on instructions instead of functions.
|
||||
|
||||
=== Scheduler
|
||||
|
||||
|
@ -212,19 +167,22 @@ Looks at the graph IR and decides when the VM should execute what.
|
|||
= Open questions
|
||||
|
||||
- @input
|
||||
- At which position are arguments injected into command inputs?
|
||||
- At which position are arguments injected into function inputs?
|
||||
- How could that be controlled if set to e.g. the end by default?
|
||||
- Not all inputs are order-independent, e.g. `div`
|
||||
- Should inputs and outputs really be positional?
|
||||
- Could make more complex commands hard to read
|
||||
- Could make more complex functions hard to read
|
||||
- But keyworded could also make code very noisy
|
||||
- Maybe a middle ground, such that at most 1 input is allowed to be positional?
|
||||
- @pipeline
|
||||
- We need some way to reshuffle and reorder outputs and inputs in a pipeline
|
||||
- @splitting
|
||||
- How would one split different outputs into a list?
|
||||
- Should outputs that are not thrown into a consumer be automatically displayed in some kind of debug view?
|
||||
- Or should that be done instead using a debug `show` command or the like?
|
||||
- @runtime
|
||||
- What is the difference between an instruction and a function?
|
||||
- Should outputs that are not thrown into a consumer
|
||||
be automatically displayed in some kind of debug view?
|
||||
- Or should that be done instead using a debug `show` function or the like?
|
||||
- Should consumers be called sinks instead?
|
||||
- Shorter
|
||||
- More ambiguous if only looking at the first char though
|
||||
|
|
38
docs/design/type-notation.typ
Normal file
38
docs/design/type-notation.typ
Normal file
|
@ -0,0 +1,38 @@
|
|||
#import "../template.typ": conf
|
||||
#show: conf
|
||||
|
||||
= Type/signature notation
|
||||
|
||||
Operator signature that takes two unnamed arbitrary numbers of the same type and returns another:
|
||||
|
||||
```iowo
|
||||
Op<T: Num> [ T T ] -> T
|
||||
```
|
||||
|
||||
Operator signature that takes any color and any number type, and returns a color again:
|
||||
```iowo
|
||||
Op<C: Color, M: Num> [ C M ] -> C
|
||||
```
|
||||
|
||||
Operator that takes a 32 bit signed integer and returns another:
|
||||
|
||||
```iowo
|
||||
Op i32 -> i32
|
||||
```
|
||||
|
||||
Operator that does the same with a generic arbitrary number type:
|
||||
|
||||
```iowo
|
||||
Op<T: Num> T -> T
|
||||
```
|
||||
|
||||
One dimensional list of 32 bit signed integers:
|
||||
|
||||
```iowo
|
||||
[i32]
|
||||
```
|
||||
|
||||
Due to inference, you'll also be able to use that in some mathematical operations with integers:
|
||||
|
||||
`[i32] + i32` is a valid operation, for example (of course, you can't add types.) But that wouldn't add the second one to the list, but rather add the single i32 to all values in the left hand side list). That would also work with more dimensional arrays and dynamic streams like videos.
|
||||
|
251
docs/design/util/graphics.typ
Normal file
251
docs/design/util/graphics.typ
Normal file
|
@ -0,0 +1,251 @@
|
|||
#import "@preview/cetz:0.1.2"
|
||||
#import cetz.draw: *
|
||||
|
||||
// quick reference
|
||||
// - `graphic` is for inline icons/images
|
||||
// - `canvas` is for centered more prominent stuff
|
||||
// - `group` can be used in either of ^, but not standalone
|
||||
|
||||
#let graphic(what) = box({
|
||||
cetz.canvas({
|
||||
// any preamble-ish stuff can go here
|
||||
set-style(
|
||||
mark: (angle: 90deg),
|
||||
stroke: (cap: "round", join: "round"),
|
||||
)
|
||||
|
||||
what
|
||||
})
|
||||
})
|
||||
|
||||
#let canvas(what) = {
|
||||
align(center, graphic(what))
|
||||
}
|
||||
|
||||
|
||||
// smaller stuff
|
||||
|
||||
#let arrow(length: 0.4cm, lift: 3pt, stroke: 1pt) = graphic({
|
||||
line((0, lift), (rel: (length, 0)), mark: (end: ">", stroke: stroke))
|
||||
|
||||
// hack for the bounding box bottom
|
||||
// so that `lift` even has any effect
|
||||
line((0, 0), (0, 0), stroke: none)
|
||||
})
|
||||
|
||||
// larger stuff
|
||||
|
||||
#let sequence(
|
||||
distance: 3cm,
|
||||
arrow-spacing: 0.15cm,
|
||||
// cetz will support rounded rects in 0.2.0
|
||||
style: (frame: "rect", padding: 0.1cm),
|
||||
..labels,
|
||||
) = group({
|
||||
let labels = labels.pos()
|
||||
|
||||
// draw each label itself
|
||||
for (i, label) in labels.enumerate() {
|
||||
if i != 0 {
|
||||
set-origin((distance, 0))
|
||||
}
|
||||
content((0, 0), name: "label-" + str(i), label, ..style)
|
||||
}
|
||||
|
||||
// then draw an arrow from each to each
|
||||
// since an arrow is between two, the last one can't be connected with the "next-to-last" one
|
||||
// so we leave it out
|
||||
for i in range(labels.len() - 1) {
|
||||
line(
|
||||
(rel: (arrow-spacing, 0), to: "label-" + str(i) + ".right"),
|
||||
(rel: (-arrow-spacing, 0), to: "label-" + str(i + 1) + ".left"),
|
||||
mark: (end: ">"),
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
#let stages-overview = canvas({
|
||||
sequence(
|
||||
[Source],
|
||||
[Graph IR],
|
||||
[Runtime],
|
||||
)
|
||||
})
|
||||
|
||||
// A few commands to help demonstration in the docs.
|
||||
// Supply a string to mark the input or output as simple.
|
||||
// (fwiw in typst, parenthesis around a single expression just evaluate the expression, and don't put it into an array)
|
||||
#let cmds = (
|
||||
"const": (
|
||||
inputs: (),
|
||||
outputs: ("data",),
|
||||
),
|
||||
"open": (
|
||||
inputs: ("path",),
|
||||
outputs: ("data",),
|
||||
),
|
||||
"save": (
|
||||
inputs: ("data", "path"),
|
||||
outputs: (),
|
||||
),
|
||||
"show": (
|
||||
inputs: ("data",),
|
||||
outputs: (),
|
||||
),
|
||||
"invert": (
|
||||
inputs: ("base",),
|
||||
outputs: ("",),
|
||||
),
|
||||
"mask": (
|
||||
inputs: ("base", "stencil"),
|
||||
outputs: ("masked", "rest"),
|
||||
),
|
||||
)
|
||||
|
||||
#let opposite(anchor) = {
|
||||
(
|
||||
"bottom": "top",
|
||||
"top": "bottom",
|
||||
)
|
||||
.at(anchor)
|
||||
}
|
||||
|
||||
#let sockets(
|
||||
start,
|
||||
stop,
|
||||
sockets,
|
||||
socket-size: (0.5, 0.1),
|
||||
socket-shape: "circle",
|
||||
parent-name: "",
|
||||
label-anchor: "bottom",
|
||||
) = {
|
||||
for (i, socket) in sockets.enumerate() {
|
||||
let x-ratio = (i + 1) / (sockets.len() + 1)
|
||||
let center = (start, x-ratio, stop)
|
||||
|
||||
let socket-name = parent-name + "/" + socket
|
||||
|
||||
let common-args = (name: socket-name, fill: black)
|
||||
if socket-shape == "rect" {
|
||||
rect(
|
||||
(rel: ((0, 0), -0.5, socket-size), to: center),
|
||||
(rel: socket-size),
|
||||
..common-args,
|
||||
)
|
||||
} else if socket-shape == "circle" {
|
||||
circle(
|
||||
center,
|
||||
radius: socket-size.at(1),
|
||||
..common-args,
|
||||
)
|
||||
} else {
|
||||
panic("unknown socket shape: `" + socket-shape + "`")
|
||||
}
|
||||
set-style(fill: none)
|
||||
|
||||
// don't ask why, I don't know myself
|
||||
let use-opposite-anchor = socket-shape == "circle"
|
||||
content(
|
||||
socket-name + "." + if use-opposite-anchor { opposite(label-anchor) } else { label-anchor },
|
||||
anchor: opposite(label-anchor),
|
||||
box(inset: 0.25em, text(8pt, socket)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#let node(
|
||||
at,
|
||||
size: (3, 1.5),
|
||||
ty: none,
|
||||
body: none,
|
||||
name: "unnamed",
|
||||
) = {
|
||||
set-origin(at)
|
||||
let label = [#ty]
|
||||
if body != none {
|
||||
label += [\ ] + text(0.7em, font: "IBM Plex Mono", body)
|
||||
size.at(1) += 0.5
|
||||
}
|
||||
rect((0, 0), (rel: size), name: name)
|
||||
content(((0, 0), 0.5, size), align(center, label))
|
||||
|
||||
// input and output sockets
|
||||
if ty == none { return }
|
||||
let ty = cmds.at(ty)
|
||||
|
||||
let sockets = sockets.with(parent-name: name)
|
||||
sockets(
|
||||
((0, 0), "|-", size),
|
||||
size,
|
||||
ty.inputs,
|
||||
)
|
||||
sockets(
|
||||
(0, 0),
|
||||
((0, 0), "-|", size),
|
||||
label-anchor: "top",
|
||||
ty.outputs,
|
||||
)
|
||||
|
||||
// helper text
|
||||
let helper(base, label, where) = {
|
||||
if not type(base) != list or base.len() != 0 {
|
||||
content(
|
||||
name + "." + where + "-left",
|
||||
anchor: "right",
|
||||
box(inset: 0.25em, text(fill: luma(75%), label))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
helper(ty.inputs, [in], "top")
|
||||
helper(ty.outputs, [out], "bottom")
|
||||
|
||||
// reset the origin transform so other nodes can still work in the global coord system
|
||||
// can't use groups since otherwise the anchors are not exported
|
||||
set-origin(((0, 0), -1, at))
|
||||
}
|
||||
|
||||
#let connect(from, to, bend: 1.5, mark-cfg: (size: 0.25, offset: 0.1)) = {
|
||||
bezier(
|
||||
from,
|
||||
to,
|
||||
(rel: (0, -bend * 1cm), to: from),
|
||||
(rel: (0, bend * 1cm), to: to),
|
||||
)
|
||||
mark(
|
||||
(rel: (0, mark-cfg.size + mark-cfg.offset), to: to),
|
||||
(rel: (0, -mark-cfg.size)),
|
||||
symbol: ">",
|
||||
)
|
||||
}
|
||||
|
||||
#let graph-example = canvas({
|
||||
let x = 3
|
||||
let y = -3
|
||||
node((-x, -0.75 * y), ty: "const", body: "\"base.png\"", name: "base")
|
||||
node((x, -0.75 * y), ty: "const", body: "\"stencil.png\"", name: "stencil")
|
||||
node((-x, 0), ty: "open", name: "a")
|
||||
node((x, 0), ty: "open", name: "b")
|
||||
node((0, y), ty: "mask", name: "c")
|
||||
node((-x, 2 * y), ty: "invert", name: "d")
|
||||
node((-x, 2.75 * y), ty: "show", name: "e")
|
||||
node((x, 2.75 * y), ty: "show", name: "f")
|
||||
|
||||
connect("base/data", "a/path")
|
||||
connect("stencil/data", "b/path")
|
||||
|
||||
connect("a/data", "c/base")
|
||||
connect("b/data", "c/stencil")
|
||||
|
||||
connect("c/masked", "d/base")
|
||||
connect("d/", "e/data")
|
||||
|
||||
connect("c/rest", "f/data", bend: 2.5)
|
||||
})
|
||||
|
||||
// literally just for standalone display of the graphics alone
|
||||
#import "../../template.typ": conf
|
||||
#show: conf
|
||||
#set page(width: auto, height: auto)
|
||||
|
||||
#graph-example
|
|
@ -8,6 +8,51 @@
|
|||
heading: (font: "Montserrat", weight: "regular"),
|
||||
)
|
||||
|
||||
#let expand(it) = {
|
||||
("("
|
||||
+ upper(it.first())
|
||||
+ "|"
|
||||
+ it.first()
|
||||
+ ")"
|
||||
+ it.clusters().slice(1).join()
|
||||
+ "s?")
|
||||
}
|
||||
#let singlify(it) = {
|
||||
it = lower(it)
|
||||
if it.ends-with("s") {
|
||||
it = it.slice(0, -1)
|
||||
}
|
||||
it
|
||||
}
|
||||
#let terminate-recursion(it) = {
|
||||
let clusters = it.text.clusters()
|
||||
clusters.insert(1, "\u{FEFF}")
|
||||
clusters.join()
|
||||
}
|
||||
// even though it looks like this could be automated with a `query`,
|
||||
// this'd require wrapping the whole document in a show rule
|
||||
// at which point `query` doesn't find anything anymore
|
||||
#let terms = (
|
||||
"source",
|
||||
"AST",
|
||||
"graph IR",
|
||||
"runtime",
|
||||
"executor",
|
||||
|
||||
"optimizer",
|
||||
"scheduler",
|
||||
"VM",
|
||||
|
||||
"function",
|
||||
"instruction",
|
||||
"pipeline",
|
||||
"input", "argument", "consumer",
|
||||
"output", "streamer",
|
||||
"modifier",
|
||||
)
|
||||
// yes, the shadowing is intentional to avoid accidentally using the list
|
||||
#let terms = regex("\\b(" + terms.map(expand).join("|") + ")\\b")
|
||||
|
||||
#let conf(
|
||||
title: none,
|
||||
subtitle: none,
|
||||
|
@ -26,10 +71,14 @@
|
|||
}
|
||||
}),
|
||||
)
|
||||
set par(justify: true)
|
||||
set text(..fonts.main)
|
||||
set heading(numbering: "A.1")
|
||||
|
||||
show heading: it => text(..fonts.heading, it)
|
||||
// color links
|
||||
show link: text.with(fill: blue)
|
||||
// prettify codeblocks
|
||||
show raw.where(block: true): box.with(
|
||||
fill: luma(95%),
|
||||
inset: 1.25em,
|
||||
|
@ -42,6 +91,35 @@
|
|||
inset: (x: 0.15em),
|
||||
radius: 0.25em,
|
||||
)
|
||||
show raw.where(block: true): it => {
|
||||
// don't try to put codeblocks into blocktext
|
||||
set par(justify: false)
|
||||
it
|
||||
}
|
||||
|
||||
// semi-strategically place pagebreaks for better orientation
|
||||
let pagebreak-before(it) = pagebreak() + it
|
||||
show heading.where(outlined: true): it => {
|
||||
if it.level <= 2 {
|
||||
pagebreak(weak: true)
|
||||
}
|
||||
|
||||
it
|
||||
}
|
||||
|
||||
// highlight important terms in bold
|
||||
show raw: it => {
|
||||
// avoid making terms in codeblocks bold
|
||||
show terms: terminate-recursion
|
||||
it
|
||||
}
|
||||
show terms: strong
|
||||
|
||||
// color codeblocks
|
||||
// haskell hl seems to work ok for this
|
||||
show raw.where(lang: "iowo", block: true): it => {
|
||||
raw(it.text, lang: "haskell", block: true)
|
||||
}
|
||||
|
||||
// document title
|
||||
if title != none {
|
||||
|
@ -55,6 +133,20 @@
|
|||
v(0.25cm)
|
||||
}
|
||||
|
||||
// outline and other prelude info
|
||||
outline(
|
||||
indent: auto,
|
||||
fill: line(
|
||||
length: 100%,
|
||||
stroke: (
|
||||
cap: "round",
|
||||
join: "round",
|
||||
thickness: 0.5pt,
|
||||
paint: luma(75%),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
// content itself
|
||||
doc
|
||||
}
|
||||
|
|
38
flake.lock
generated
38
flake.lock
generated
|
@ -8,11 +8,11 @@
|
|||
"pre-commit-hooks": "pre-commit-hooks"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1699541523,
|
||||
"narHash": "sha256-Rv0ryuBC5KtA/3YqwIEe58Tabu71qSGnGcGRd67mMUY=",
|
||||
"lastModified": 1704835383,
|
||||
"narHash": "sha256-SoC0rYR9iHW0dVOEmxNEfa8vk9dTK86P5iXTgHafmwM=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "14fdefc0bb80c3d6f3a18a491e33429b4064c371",
|
||||
"rev": "18ef9849d1ecac7a9a7920eb4f2e4adcf67a8c3a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -27,11 +27,11 @@
|
|||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1699510895,
|
||||
"narHash": "sha256-eaOkJUvHeYNW/xEoRotz0rHkKihKoQdWB1ctX4q1MTQ=",
|
||||
"lastModified": 1704867811,
|
||||
"narHash": "sha256-pG4O1vPpNSMjz7p/5x+/OH4tXC0thzAPbJ55kI/W5dU=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "8eeef23f2c8d092227af40eff98afe5b41891e3b",
|
||||
"rev": "93e89638c15512db65e931f26ce36edf8cfbb4a5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -186,11 +186,11 @@
|
|||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1699099776,
|
||||
"narHash": "sha256-X09iKJ27mGsGambGfkKzqvw5esP1L/Rf8H3u3fCqIiU=",
|
||||
"lastModified": 1704538339,
|
||||
"narHash": "sha256-1734d3mQuux9ySvwf6axRWZRBhtcZA9Q8eftD6EZg6U=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "85f1ba3e51676fa8cc604a3d863d729026a6b8eb",
|
||||
"rev": "46ae0210ce163b3cba6c7da08840c1d63de9c701",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -202,16 +202,16 @@
|
|||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1699291058,
|
||||
"narHash": "sha256-5ggduoaAMPHUy4riL+OrlAZE14Kh7JWX4oLEs22ZqfU=",
|
||||
"lastModified": 1704722960,
|
||||
"narHash": "sha256-mKGJ3sPsT6//s+Knglai5YflJUF2DGj7Ai6Ynopz0kI=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "41de143fda10e33be0f47eab2bfe08a50f234267",
|
||||
"rev": "317484b1ead87b9c1b8ac5261a8d2dd748a0492d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-23.05",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
|
@ -231,11 +231,11 @@
|
|||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1688056373,
|
||||
"narHash": "sha256-2+SDlNRTKsgo3LBRiMUcoEUb6sDViRNQhzJquZ4koOI=",
|
||||
"lastModified": 1704725188,
|
||||
"narHash": "sha256-qq8NbkhRZF1vVYQFt1s8Mbgo8knj+83+QlL5LBnYGpI=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "5843cf069272d92b60c3ed9e55b7a8989c01d4c7",
|
||||
"rev": "ea96f0c05924341c551a797aaba8126334c505d2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -255,11 +255,11 @@
|
|||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1699451299,
|
||||
"narHash": "sha256-7HJMyp62fCS6/aCCCASz8MdJM2/M8d1pBNukyLmPdwA=",
|
||||
"lastModified": 1704833483,
|
||||
"narHash": "sha256-Ox01mpYmjapNYaqOu4fMS/4Ma9NLd2rVNz6d4rJmcf4=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "7059ae2fc2d55fa20d7e2671597b516431129445",
|
||||
"rev": "ae6e73772432cfe35bb0ff6de6fdcfa908642b67",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
systems.url = "github:nix-systems/default";
|
||||
devenv.url = "github:cachix/devenv";
|
||||
fenix.url = "github:nix-community/fenix";
|
||||
|
@ -36,7 +36,7 @@
|
|||
rustfmt.enable = true;
|
||||
};
|
||||
|
||||
packages = [];
|
||||
packages = with pkgs; [just nushell typst];
|
||||
})
|
||||
];
|
||||
};
|
||||
|
|
15
justfile
15
justfile
|
@ -1,6 +1,11 @@
|
|||
# Compile all documentation as in proposals and design documents, placing them under `docs/compiled`.
|
||||
docs:
|
||||
for doc in $(fd '.typ' './docs' --exclude 'template*' --exclude 'util*'); do \
|
||||
typst compile $doc --root=docs; \
|
||||
mv "$(dirname $doc)/$(basename $doc .typ).pdf" docs/compiled/; \
|
||||
done
|
||||
|
||||
#!/usr/bin/env nu
|
||||
glob **/*.typ --exclude [**/{template.typ,util/**}] | par-each { |source|
|
||||
typst compile $source --root=docs
|
||||
let pdf = (
|
||||
(echo $source | path dirname)
|
||||
| path join (echo $source | path basename | str replace ".typ" ".pdf")
|
||||
)
|
||||
mv $pdf docs/compiled
|
||||
} | ignore
|
||||
|
|
Loading…
Add table
Reference in a new issue