Editing this Documentation
Information Architecture
Section titled “Information Architecture”How-to guides
Section titled “How-to guides”Guides lead a user through a specific task they want to accomplish, often with a sequence of steps. Writing a good guide requires thinking about what your users are trying to do.
Further reading: how-to guides in the Diátaxis framework
Reference Pages
Section titled “Reference Pages”Reference pages are ideal for outlining how things work in terse and clear terms. Less concerned with telling a story or addressing a specific use case, they should give a comprehensive outline of what you’re documenting.
Further reading: reference pages in the Diátaxis framework
Regular snippet
Section titled “Regular snippet”public fun main() { print("Hello, World!")}With title
Section titled “With title”public fun main() { print("Hello, World!")}No frame:
echo "Command without frame"With frame (default):
echo "This terminal frame has no title"With title:
Write-Output "This one has a title!"Word wrap
Section titled “Word wrap”No wrapping (default):
cmake -D LLVM_DIR=<LLVM>/lib/cmake/llvm -D CMAKE_BUILD_TYPE=<build-type> -D BUILD_TESTING=1 -G Ninja -S . -B .buildWrap:
cmake -D LLVM_DIR=<LLVM>/lib/cmake/llvm -D CMAKE_BUILD_TYPE=<build-type> -D BUILD_TESTING=1 -G Ninja -S . -B .buildHanging indent:
cmake -D LLVM_DIR=<LLVM>/lib/cmake/llvm -D CMAKE_BUILD_TYPE=<build-type> -D BUILD_TESTING=1 -G Ninja -S . -B .buildHighlights
Section titled “Highlights”module struct SpawnFrame<E: Movable & Deinitializable>: Deinitializable {
/// The base frame object needed by the underlying implementation. private var base_frame: SpawnFrameBase
/// What needs to be called to produce the value in the future. private var f: [E]() -> Int
/// The result of the computation. private var r: Optional<Int>
/// Initializes `self` with `f`, and spawns the computation. module init(_ f: sink [E]() -> Int) { &self.base_frame = .new() &self.f = f &self.r = .none()
let local_f = fun (_ frame: inout SpawnFrameBase) -> Void { var this = PointerToMutable<Self>(type_punning: mutable_pointer[to: &frame]) &this.unsafe[].r = this.unsafe[].f() as _ } concore2full_spawn2(&self.base_frame, local_f) }
/// Awaits the result of the computation. /// /// - Note: May return on a different OS thread than the one that called this. fun await() inout -> Int { concore2full_await(self.base_frame) if let r: Int = self.r { let copy = r.copy() &self.r = .none() return copy } else { fatal_error() } }
/// Allocate an object of `Self` on the heap and initialize it with `f`. internal static fun allocate(_ f: sink [E]() -> Int) -> PointerToMutable<Self> { let p: PointerToMutable<Self> = .allocate(count: 1) Self.`init`(self: &p.unsafe[], f) return p }
}Squiggles
Section titled “Squiggles”public fun main() { let gravity = 9.81 &gravity = 11.2}Folder Structure
Section titled “Folder Structure”DirectorySources
DirectoryHello
- Hello.hylo
DirectoryGreetings
- Greetings.hylo
Runnable snippets
Section titled “Runnable snippets”Wrap a code block in <Playground> to let readers run it in their browser, edit it, and open it in
the full-screen playground. The code block renders as any other, highlights and
all; the compiler, compiled to WebAssembly (the npm package
@hylo-lang/hylo-wasm), is only downloaded
when a reader first runs a snippet. That is about 15 MB compressed, once, which the browser then
caches.
Only make a snippet runnable if the compiler can run it today. The expect attribute says what it
does, and the site’s tests check every snippet still does it; the site does not build if a snippet
has none, or if it misuses an attribute.
The import path is relative to the page: from a page in src/content/docs/docs/<section>/, the
component is four directories up.
import Playground from '../../../../components/playground/Playground.astro';Reference
Section titled “Reference”Every attribute of <Playground> and every marker of its code fences, with an example. Each
example shows its MDX and, under Preview, what it renders, which runs.
| Attribute | Values | Default |
|---|---|---|
expect |
exit N, trap, error, ok |
required |
outputs |
result, diagnostics, raw-ir, ir, llvm, assembly |
result |
focus |
names of functions | every function |
optimization |
{0} to {3} |
{0} |
stopAfter |
parsing, scoping, typing, lowering |
runs the program |
standardLibrary |
{true}, {false} |
{true} |
editable |
{true}, {false} |
{true} |
name |
a name, unique on the page | none |
continues |
the name of an earlier snippet of the page |
none |
contributes |
{true}, {false} |
{true} |
| Fence marker | Effect |
|---|---|
hidden |
compiled, not shown |
title="…" |
the file, shown as the caption |
file="…" |
the file, not shown |
| Several shown fences | tabs, one per file |
| Expressive Code’s markers | as in any code block |
expect
Section titled “expect”What the snippet does, which the site’s tests check: exit N (it runs and exits with status N),
trap (it runs and traps), error (it does not compile), or ok (it compiles, and runs to
completion if it is a program). Required.
<Playground expect="exit 42">```hylopublic fun main() -> Int32 { var x = 40 &x = x + 2 return if x == 42 { 42 } else { 1 }}```</Playground>public fun main() -> Int32 { var x = 40 &x = x + 2 return if x == 42 { 42 } else { 1 }}A snippet that does not compile shows its diagnostics; clicking one takes the reader to it.
<Playground expect="error">```hylopublic fun main() -> Int32 { 40 + 2 // Integer literals are `Int` unless something says otherwise.}```</Playground>public fun main() -> Int32 { 40 + 2 // Integer literals are `Int` unless something says otherwise.}<Playground expect="trap">```hylopublic fun main() -> Int32 { let divisor: Int32 = 0 return (1 as Int32) / divisor}```</Playground>public fun main() -> Int32 { let divisor: Int32 = 0 return (1 as Int32) / divisor}outputs
Section titled “outputs”What to show once the code has run, as tabs, in this order: result (the exit status, what the
program printed, and the diagnostics), diagnostics, raw-ir (Hylo IR before the mandatory
transformations), ir (Hylo IR), llvm (LLVM IR) and assembly (WebAssembly).
<Playground outputs="result diagnostics ir llvm assembly" expect="exit 7">```hylopublic fun main() -> Int32 { 7 }```</Playground>public fun main() -> Int32 { 7 }The functions to show in Hylo IR, by name, rather than all of them: main shows main,
factorial shows factorial(n:), and Int32.infix+ shows that operator.
<Playground outputs="ir" focus="factorial" expect="exit 120">```hylofun factorial(n: sink Int32) -> Int32 { var m: Int32 = 1 while n > (0 as Int32) { &m = m * n &n = n - (1 as Int32) } return m}
public fun main() -> Int32 { factorial(5 as Int32) }```</Playground>fun factorial(n: sink Int32) -> Int32 { var m: Int32 = 1 while n > (0 as Int32) { &m = m * n &n = n - (1 as Int32) } return m}
public fun main() -> Int32 { factorial(5 as Int32) }optimization
Section titled “optimization”LLVM’s optimization level, from {0} to {3}. Here the whole program folds to a constant.
<Playground outputs="result llvm" optimization={2} expect="exit 120">```hylofun factorial(n: sink Int32) -> Int32 { var m: Int32 = 1 while n > (0 as Int32) { &m = m * n &n = n - (1 as Int32) } return m}
public fun main() -> Int32 { factorial(5 as Int32) }```</Playground>fun factorial(n: sink Int32) -> Int32 { var m: Int32 = 1 while n > (0 as Int32) { &m = m * n &n = n - (1 as Int32) } return m}
public fun main() -> Int32 { factorial(5 as Int32) }stopAfter
Section titled “stopAfter”The phase after which compilation stops, for code that is not a program: typing checks it,
lowering also produces its Hylo IR. The button says Check rather than Run.
<Playground stopAfter="lowering" outputs="result ir" focus="sum" expect="ok">```hylostruct Pair is Deinitializable { public memberwise init public var a: Int32 public var b: Int32}
fun sum(_ p: Pair) -> Int32 { p.a + p.b }```</Playground>struct Pair is Deinitializable { public memberwise init public var a: Int32 public var b: Int32}
fun sum(_ p: Pair) -> Int32 { p.a + p.b }standardLibrary
Section titled “standardLibrary”{false} compiles the code without the standard library.
<Playground standardLibrary={false} stopAfter="typing" expect="ok">```hylotrait Shape {}struct Point is Shape {}fun identity<T>(_ x: sink T) -> T { x }```</Playground>trait Shape {}struct Point is Shape {}fun identity<T>(_ x: sink T) -> T { x }editable
Section titled “editable”{false} keeps the reader from editing the snippet; it still runs.
<Playground editable={false} expect="exit 3">```hylopublic fun main() -> Int32 { 3 }```</Playground>public fun main() -> Int32 { 3 }name and continues
Section titled “name and continues”A snippet named with name can be continued by any snippet after it on the same page, with
continues: the later one starts from all the files of the earlier one, hidden code included, so
a chain of snippets builds a program up as the prose explains it. Nothing of the snippets after one
is compiled with it, and “Open in the playground” opens the program as it stands there.
<Playground name="ref-point" stopAfter="typing" expect="ok">```hylopublic struct Point is Deinitializable { public memberwise init public var x: Int32 public var y: Int32}```</Playground>
<Playground continues="ref-point" expect="exit 3">```hylopublic fun main() -> Int32 { let p = Point(x: 1 as Int32, y: 2 as Int32) return p.x + p.y}```</Playground>public struct Point is Deinitializable { public memberwise init public var x: Int32 public var y: Int32}public fun main() -> Int32 { let p = Point(x: 1 as Int32, y: 2 as Int32) return p.x + p.y}contributes
Section titled “contributes”{false} leaves the snippet’s own code out of the snippets continuing it, which start from what it
continues instead: a mistake or a digression does not end up in the program.
<Playground name="ref-mistake" continues="ref-point" contributes={false} expect="error">```hylopublic fun main() -> Int32 { Point(x: 1, y: 2).x}```</Playground>
<Playground continues="ref-mistake" expect="exit 1">```hylopublic fun main() -> Int32 { Point(x: 1 as Int32, y: 2 as Int32).x}```</Playground>public fun main() -> Int32 { Point(x: 1, y: 2).x}public fun main() -> Int32 { Point(x: 1 as Int32, y: 2 as Int32).x}hidden
Section titled “hidden”A fence marked hidden is compiled with the snippet but not shown. Each fence adds its code at
the end of its file, in the order written, so a hidden fence may open what a shown one closes.
Readers edit only the code they see.
<Playground expect="exit 42">```hylo hiddenpublic fun main() -> Int32 {``````hylo var x: Int32 = 40 &x = x + (2 as Int32) return x``````hylo hidden}```</Playground> var x: Int32 = 40 &x = x + (2 as Int32) return xThe file the fence goes into, which the code block shows as its caption. A fence naming no file
goes into the snippet’s own file: main.hylo, or main2.hylo and so on if the program already
has a file of that name. A later snippet continues a file by naming it. Diagnostics name the files.
<Playground name="ref-shapes" stopAfter="typing" expect="ok">```hylo title="shape.hylo"trait Shape { fun area() -> Int32}```</Playground>
<Playground continues="ref-shapes" stopAfter="typing" expect="ok">```hylo title="shape.hylo"fun twice<T is Shape>(s: T) -> Int32 { s.area() + s.area() }```</Playground>trait Shape { fun area() -> Int32}fun twice<T is Shape>(s: T) -> Int32 { s.area() + s.area() }The file the fence goes into, without showing its name; a title is then any caption.
<Playground expect="exit 6">```hylo hidden file="rect.hylo"struct Rect is Deinitializable { public memberwise init public var w: Int32 public var h: Int32}``````hylo file="main.hylo" title="Using a type from another file"public fun main() -> Int32 { let r = Rect(w: 2 as Int32, h: 3 as Int32) return r.w * r.h}```</Playground>public fun main() -> Int32 { let r = Rect(w: 2 as Int32, h: 3 as Int32) return r.w * r.h}Several files, as tabs
Section titled “Several files, as tabs”A snippet shows at most one fence of each file, and shows the fences of several files as tabs, named after the files. Editing it gives each its own editor, and a diagnostic takes the reader to the right tab.
<Playground expect="exit 10">```hylo title="main.hylo"public fun main() -> Int32 { triangle(4 as Int32) }``````hylo title="triangle.hylo"/// Returns 1 + 2 + … + n.fun triangle(n: Int32) -> Int32 { var total: Int32 = 0 var i: Int32 = 1 while i <= n { &total = total + i &i = i + (1 as Int32) } return total}```</Playground>public fun main() -> Int32 { triangle(4 as Int32) }/// Returns 1 + 2 + … + n.fun triangle(n: Int32) -> Int32 { var total: Int32 = 0 var i: Int32 = 1 while i <= n { &total = total + i &i = i + (1 as Int32) } return total}Expressive Code’s markers
Section titled “Expressive Code’s markers”The markers of every code block apply to the fences shown, such as highlighting lines ({7}) and
folding them away until the reader unfolds them (collapse={1-3}).
<Playground expect="exit 120">```hylo {7} collapse={1-3}fun factorial(n: sink Int32) -> Int32 { var m: Int32 = 1 while n > (0 as Int32) { &m = m * n &n = n - (1 as Int32) } return m}
public fun main() -> Int32 { factorial(5 as Int32) }```</Playground>3 collapsed lines
fun factorial(n: sink Int32) -> Int32 { var m: Int32 = 1 while n > (0 as Int32) { &m = m * n &n = n - (1 as Int32) } return m}
public fun main() -> Int32 { factorial(5 as Int32) }The Hylo IR and the WebAssembly assembly LLVM prints have code fence
languages of their own, hylo-ir and wasm-asm:
fun main(set %p0: Int32) {%b0: %r0 = subfield %p0 at 0 as i32 %r1 = access [set] %r0 %r2 = store i32 42 to %r1 %r3 = end %r1 %r4 = return}
