Tzopilotl
Docs
GitHub

Tzopilotl by Example

1. Basic Syntax

1.1 Comments

-- Single line comment

/* Block comment
   spans multiple lines
   /* and can be nested */ */

1.2 Literals

-- Integer literals
42
0
123_456_789

-- Hexadecimal integer literals
0xFF
0x100
0xDeadBeef

-- Float literals (require a digit on both sides of the decimal point)
3.14
0.5
2.0

-- Fraction literals (integer/integer with no spaces around /)
1/2
3/4
-7/8

-- Fractions are automatically reduced
6/4                -- 3/2

-- A fraction literal cannot be immediately followed by /
-- to prevent ambiguity. Use spaces for division:
--   1/2/3    -- ERROR: ambiguous
--   1/2 / 3  -- OK: fraction 1/2 divided by 3

-- Imaginary literals
4i
1.5i

-- String literals
"hello world"

-- Symbol literals (interned strings, compared by pointer)
'ok
'error

-- Boolean literals
true
false

1.3 Multi-line and Raw Strings

An ordinary "..." string is single-line and processes backslash escapes (\n, \t, \", \\, \uhhhh, \Uhhhhhhhh). A literal newline inside it is an error.

For text that spans several lines — or that is easier to write without escaping — there are two raw string forms. Both span multiple lines and perform no escape processing: every character between the delimiters, including newlines and backslashes, is taken verbatim.

-- Triple-quoted raw string: delimited by """ ... """
let haiku = """
an old silent pond
a frog jumps into the pond—
splash! silence again
""";

-- Guillemet raw string: delimited by « ... »
let note = «She said "hello" and left.»;   -- quotes need no escaping

-- No escapes are interpreted: this string contains a literal
-- backslash-n, not a newline.
let raw = """C:\new\table""";

The content is captured exactly as written: there is no automatic stripping of the leading newline or of indentation. In the haiku above the string therefore begins with a newline (right after the opening """) and the lines are flush-left because they are written flush-left in the source.

Because the forms are raw, a triple-quoted string cannot contain the sequence """, and a guillemet string cannot contain » (nor do guillemets nest). Pick whichever delimiter does not occur in your text: use « » when the text contains double quotes or """, and use """ when it contains guillemets.

Raw strings are handy for embedding other source verbatim — for example a program to load into a silo, a synthdef body, or a block of JSON or template text — without escaping its quotes:

let silo0 = """
import audio_engine.*;
async fn voice(self Actor<Msg>, init Msg) Void {
    -- ...
}
voice spawn(Msg.int(0)) register('voice);
""";
attachVM(0);
await siloLoad(0, silo0);

1.4 Semicolons

-- Semicolons are required statement terminators
let x = 42;
let y = 10;

-- Exception: the last expression in a block is the implicit
-- return value and does NOT have a semicolon
fn square(x Int) Int {
    x * x       -- no semicolon: this is the return value
}

1.5 Printing Output

-- println prints its arguments separated by spaces, followed by a newline
println(42);                       -- 42
println("hello", "world");        -- hello world
println(1, 2.5, true);            -- 1 2.5 true
println();                          -- (empty line)

-- print is the same but without a trailing newline
print("x=");
println(42);                       -- x=42

-- Pipeline syntax works too
42 println;                         -- 42
"hello" println;                    -- hello

-- Auto-map with @ to print each element on its own line
[1, 2, 3] @ println;
-- 1
-- 2
-- 3

For large nested values there is also a width-aware pretty printer, prettyPrint / prettyString — see §26.