Functions
The twelve constructs that take a value and give one back: eleven the compiler evaluates and splices into the text — rounding, separators and case — and !value, which reads one live, every frame.
#Compile time and render time
Twelve micronodes take a value as their body, compute a result and put the result where they stood. They divide by when that happens.
- Eleven run in the compiler. The result is spliced into the surrounding text as characters, and nothing else reaches the output — no node, no identifier, nothing a renderer has to know about.
- runs in the renderer, every frame, because the number it reports is one the canvas computes while the reader is moving it.
The book costs $!format:comma{{price}}(places: 2).
compiles to the single run The book costs $1,234.57.That is the whole trade for the eleven. The number is gone by the time the document renders: it cannot be re-formatted for another locale, animated, or bound to. What is bought for it is that the body is typed — !round:2{banana} is a compile error rather than something odd on the page.
#Writing a function
A function is written like any other micronode, and its first attribute is the implicit one, so !round:2{…} and !round{…}(places: 2) are the same thing. None of them carries a #id — there is no node for one to attach to.
!round:2{3.14159} 3.14
!format:comma{1234567} 1,234,567
!upper{hello} HELLO
!truncate:8{internationalisation} interna…The compile-time eleven run wherever {{…}} substitutes — in prose, in an attribute value, in a directive value — and nest inside out, because a body is expanded before it is typed:
!format:comma{!round:2{{price}}} 1,234.57Their output is never re-scanned. It is a value, not markup, so !upper can never turn data into structure. The two places they do not reach are the ones whose job is to preserve a sample verbatim: the body of , and the $…$ of .
#round, ceil, floor, abs, clamp and format
- — to
placesdecimals, half away from zero.!round{3.7}is4. - , and — up, down, and magnitude. No attributes.
- — held inside an interval:
!clamp:0..1{1.4}is1. - — separators.
commagroups in threes,percentscales by 100 and appends the sign,fixedusesplaceswithout grouping,scientificwrites a mantissa and exponent.
A result renders as the shortest exact decimal — no trailing zeros, no exponent, -0 normalised to 0.
format emits separators and never a currency symbol. The compiler carries no locale table and never will, so the symbol belongs to the sentence: $!format:comma{{price}}(places: 2).#upper, lower, title, truncate and pad
- , and — case, mapped locale-independently.
- — to a maximum
length, ending in anellipsiscounted inside it. A length with no room for the ellipsis is an error. - — widened to
lengthwith a filler, at thestartor theend. Lengths count Unicode scalar values.
There is no trim: text arriving in a function has already been trimmed.
#Why only !value reads a live number
A binding has no value until the document renders, and the compile-time eleven run before that. So reading one is an error rather than an em dash in the output:
The fitted slope is !round:2{#f.slope}.[reference]`round` is evaluated at compile time and cannot read the live value `#f.slope`. Wrap the reference in a library micronode that declares a `reference`-typed attribute instead
Rounding a live number is the renderer's job, which is the twelfth function's. takes the reference the other eleven refuse, and its digits, format and maths do for a live number what their attributes do for a fixed one:
The fitted slope is !value:#f.slope(digits: 2).