Reference

Input/Output

Generated from LANGUAGE.md at d971c06, 2026-10-15.

Print

Print "Hello, World!".
Print the x.
Print 'add numbers' of 3 and 5.

Print without newline:

Print "Loading: " without newline.
Print progress without newline.
Print "%".

Format Strings

Embed variables and expressions directly in strings using curly braces {}:

a text called name is "Alice".
a number called age is 25.
Print "Hello, {name}! You are {age} years old.".

Format Specifiers

SpecifierDescriptionExampleOutput
{var}Default formatting{name}Alice
{var:.N}N decimal places{pi:.2}3.14
{var:N}Pad to N characters{x:6} 42
{var:0N}Zero-pad to N chars{x:06}000042
{var:x}Hexadecimal (lowercase){n:x}0xff
{var:X}Hexadecimal (uppercase){n:X}0xFF
{var:b}Binary{n:b}101
{var:o}Octal{n:o}0o10
{var:04x}Padded hex{n:04x}0x00ff

The value inside {} must be a variable or expression, not a bare literal: {255:x} is rejected (255 is read as a variable name). The examples above assume a declared a number called n is 255. (set n to 5 or 8 for the binary and octal rows).

N is a count in both forms, and both render in full: {var:N} pads out to N characters and {var:.N} prints exactly N decimal places, correctly rounded (an exact tie goes to the even digit). Neither is capped (a very large N is simply a very large amount of output), but N has to be a count the compiler can hold, at most 9223372036854775807; past that it is a compile error naming the limit, not a width that quietly does nothing. A width may be zero - {var:0} and {var:00} pad nothing, the same no-op as any width too small to add characters. A precision past the value's exact decimal expansion pads with zeros, since the expansion has ended and not because accuracy has run out: a float is a binary fraction, so it always has an exact finite expansion, and {pi:.50} prints all fifty places of it. A whole number has an exact expansion too ( itself, then zeros), so {n:.2} on a number called n is 255. prints 255.00, and prints it exactly for every number Vox can hold.

A specifier has to be one in the table, and one the value's type can answer. A clause after the colon that is none of them is a compile error naming the valid forms. A width asks nothing of a type: every rendering is some number of characters long, so {var:N} is accepted whatever var is, and a number, a float, a text and a buffer are each padded out to N characters. The other two do ask something, and asking it of the wrong type is a compile error naming the way out, not a wrong answer:

  • {var:.N} counts places in a number's decimal expansion. A number, a float and a boolean have one; a text or a buffer does not.
  • {var:x}, {var:X}, {var:b} and {var:o} write a whole number in another base. A number and a boolean are whole numbers. A float is not; {ratio:b} is refused rather than quietly dropping the fraction, so write {ratio as a number:b} when that is what you meant, and neither is a text or a buffer.

Inside an expression hole the cast has nowhere to go (the braces a whole-expression cast needs are the hole's own), so work the value out into a number first and render that:

a float called ratio is 2.5.
a number called total is {ratio multiply 2.0} as a number.
Print "{total:x}".                (0x5)

A value, a list and a map render through their own routines, which ignore a specifier and print the value; a value's type is not known until it runs, so there is nothing to check.

The two compose: {var:8.2} asks for two decimal places, padded out to eight characters. The precision decides the digits and the width decides the padding, on a number and a float alike. So {n:8.2} on a number called n is 255. prints 255.00, and {n:08.2} prints 00255.00. (A width composes with a radix too, which is the {var:04x} row above.)

Expressions in Format Strings

a number called x is 10.
a number called y is 3.
Print "Sum: {x add y}".
Print "Product: {x multiply y}".
Print "Arguments: {arguments's count}".

Format Strings as Values

Format strings are expressions, not just print arguments. Used as a value, a format string materializes into a fresh NUL-terminated string, so it works as a text initializer or assignment and survives being carried through lists (e.g. into an Execute argument list):

a buffer called word is 64 bytes in size.
copy hello to word.

a text called tok is "{word}".        (text from buffer contents)
a text called path is "/bin/{tok}".   (text from another text)

a list called cmdargs is [].
append tok to cmdargs.
Execute "/bin/echo" with arguments cmdargs.

Each evaluation allocates a new string; the source buffer can be cleared and reused without affecting texts already created from it. A text variable reassigned from a format string releases the string it no longer holds.

Format Strings Everywhere

Every statement that takes a string value accepts a format string: write, buffer set/copy/append, filesystem paths (Create a directory called "{base}/{name}"), treating clauses, and function arguments. All sinks share one name resolver, so special names like {arguments's first} and {current time's hour}, format specifiers, and the 0x/0o hex/octal prefixes render identically whether the result is printed, written to a file, or built into a text or a buffer - a float's precision included: {ratio:.2} reads 2.50 in every one of them.

Declarations in Branches

A variable (or file handle) declared in EVERY branch of an if/otherwise chain definitely exists afterwards: it can be used after the branch and from inside functions, exactly like a top-level declaration. A name declared in only SOME branches remains scoped to its condition, and cross-condition use is still a compile error.

if 'output file' is empty then,
  Open a file for writing called output at 1.
Otherwise,
  Open a file for writing called output at 'output file'.

(output exists on every path - usable here and in functions)
write "hello\n" to output.

Escape Sequences

EscapeDescription
{{Literal {
}}Literal }
\nNewline
\tTab
\\Literal backslash

Example:

Print "Use {{braces}} for literal braces.".
Print "Tab:\there".
Print "Line1\nLine2".

Conditional Print

Print <default>, but if <condition> print <value>.

Chained conditions:

Print the number, but if <cond1> print "FizzBuzz" but if <cond2> print "Fizz" but if <cond3> print "Buzz".

Rules:

  • First matching condition wins
  • Chain with but if or and if
  • Default value prints if no conditions match