iowo/docs/design/iowo-design.typ

232 lines
5.1 KiB
Text

#import "../template.typ": conf
#import "graphics.typ"
#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",
"abstract syntax tree",
"Abstract Syntax Tree",
"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%),
),
),
)
= 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
#graphics.stages-overview
== Source <source>
```iowo
open base.png >|
open stencil.png >|
mask
|> (invert | show)
|> show
```
Functional and pipeline-based.
However, in contrast to classic shell commands,
commands can have multiple outputs and multiple inputs.
=== Commands
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
- 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.
- May also contain spaces in its name.
==== Inputs <input>
- Based on position.
- Inputs can be provided both through the pipeline and ad-hoc.
- Ad-hoc inputs are called arguments.
- So all of these are equivalent:
```iowo
1 | add 2
add 1 2
[ 1 2 ] | add
```
==== Outputs
- Also based on position.
=== Pipelines <pipeline>
- Exchange data between streamers and consumers.
==== Simple forwarding
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
```
==== Splitting <splitting>
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
```
==== Combination <combination>
To throw multiple streamers into the inputs of a consumer, they can be _combined_:
```iowo
open base.png >|
open stencil.png >|
mask
```
However, since lists are automatically spliced into inputs, this is equivalent to the above:
```iowo
[
open base.png,
open stencil.png,
]
| mask
```
=== Comments
Done with any of `--` or `//`.
=== Data types
==== Lists
- Signified by `[]` braces.
- If thrown into a pipeline, it automatically works like a streamer.
- Can be delimited by commas.
- Must be delimited by commas if a contained streamer takes an input.
- May have a trailing comma.
- Outputs of streamers are spliced into the contained list.
- In effect, they are automatically flattened.
== Abstract Syntax Tree
Essentially just the source lexed and parsed.
== Graph IR
=== Optimizer
Merges and simplifies commands in the graph IR.
== Runtime
=== Scheduler
Looks at the graph IR and decides when the VM should execute what.
=== VM <vm>
= Open questions
- @input
- At which position are arguments injected into command 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
- 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?
- Should consumers be called sinks instead?
- Shorter
- More ambiguous if only looking at the first char though