Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Text Format

The TeaLeaf text format (.tl) is the human-readable representation. This page is the complete syntax reference.

Comments

Comments begin with # and extend to end of line:

# This is a line comment
name: alice  # inline comment

Comments are stripped during compilation to binary.

Strings

Simple (Unquoted)

Bare identifiers that contain no whitespace or special characters:

name: alice
host: localhost
status: active

Valid characters: letters, digits, _, -, .

Quoted

Double-quoted strings with escape sequences:

greeting: "hello world"
path: "C:\\Users\\name"
message: "line1\nline2"
tab_separated: "col1\tcol2"

Escape sequences: \\, \", \n, \t, \r, \b (backspace), \f (form feed), \uXXXX (Unicode code point, 4 hex digits)

Multiline (Triple-Quoted)

Triple-quoted strings with automatic leading whitespace removal:

description: """
  This is a multiline string.
  Leading whitespace is trimmed based on
  the indentation of the first content line.
  Useful for documentation blocks.
"""

Numbers

Integers

count: 42
negative: -17
zero: 0

Floats

price: 3.14
scientific: 6.022e23
negative_exp: 1.5e-10

Numbers with exponent notation but no decimal point (e.g., 1e3) are parsed as floats.

Hexadecimal

color: 0xFF5500
mask: 0x00A1

Binary Literals

flags: 0b1010
byte_val: 0b11110000

Both lowercase (0x, 0b) and uppercase (0X, 0B) prefixes are accepted.

Negative hex and binary literals are supported: -0xFF, -0b1010.

Bytes Literals

payload: b"cafef00d"
empty: b""
checksum: b"CAFE"

Hex digits only (uppercase or lowercase), even length, no spaces.

Special Float Values

not_a_number: NaN
positive_infinity: inf
negative_infinity: -inf

These keywords represent IEEE 754 special values. In JSON export, NaN and infinity values are converted to null.

Boolean and Null

enabled: true
disabled: false
missing: ~

The tilde (~) is the null literal.

Timestamps

ISO 8601 formatted date/time values:

# Date only
created: 2024-01-15

# Date and time (UTC)
updated: 2024-01-15T10:30:00Z

# With milliseconds
precise: 2024-01-15T10:30:00.123Z

# With timezone offset
local: 2024-01-15T10:30:00+05:30

Format: YYYY-MM-DD[THH:MM[:SS[.sss]][Z|+HH:MM|-HH:MM]]

Seconds (:SS) are optional and default to 00. Timestamps are stored internally as Unix milliseconds (i64).

Objects

Curly-brace delimited key-value collections:

# Inline
point: {x: 10, y: 20}

# Multi-line
config: {
  host: localhost,
  port: 8080,
  debug: false,
}

Trailing commas are allowed.

Arrays

Square-bracket delimited ordered collections:

numbers: [1, 2, 3, 4, 5]
mixed: [1, "hello", true, ~]
nested: [[1, 2], [3, 4]]
empty: []

Tuples

Parenthesized value lists. Outside of @table, tuples are parsed as plain arrays:

# This is an array [0, 0], NOT a struct
origin: (0, 0)

Inside a @table context, tuples are bound to the table’s schema:

@struct point (x: int, y: int)
points: @table point [
  (0, 0),       # bound to point schema
  (100, 200),
]

Maps

Ordered key-value maps with the @map directive. Unlike objects, maps support non-string keys:

# String keys
headers: @map {
  "Content-Type": "application/json",
  "Accept": "*/*",
}

# Integer keys
status_codes: @map {
  200: "OK",
  404: "Not Found",
  500: "Internal Server Error",
}

# Mixed value types
config: @map {
  name: "myapp",
  port: 8080,
  debug: true,
}

Maps preserve insertion order and support heterogeneous key types.

References

Define named values and reuse them:

# Define a reference
!node_a: {label: "Start", value: 1}
!node_b: {label: "End", value: 2}

# Use references
edges: [
  {from: !node_a, to: !node_b, weight: 1.0},
  {from: !node_b, to: !node_a, weight: 0.5},
]

# References can be used multiple times
nodes: [!node_a, !node_b]

References can be defined at the top level or inside objects.

Tagged Values

A colon prefix adds a discriminator tag to any value:

events: [
  :click {x: 100, y: 200},
  :scroll {delta: -50},
  :keypress {key: "Enter"},
]

Tags are useful for discriminated unions and variant types.

Unions

Named discriminated unions with @union:

@union shape {
  circle (radius: float),
  rectangle (width: float, height: float),
  point (),
}

shapes: [
  :circle (5.0),
  :rectangle (10.0, 20.0),
  :point (),
]

Union definitions are encoded in the binary schema table alongside struct definitions, preserving variant names, field names, and field types through compilation and decompilation.

Root Array

The @root-array directive marks the document as representing a top-level JSON array. This is primarily used for JSON round-trip fidelity.

When a root-level JSON array is imported via from-json, TeaLeaf stores each element as a numbered key (0, 1, 2, …) and emits @root-array so that to-json reconstructs the original array structure:

@root-array

0: {id: 1, name: alice}
1: {id: 2, name: bob}
2: {id: 3, name: carol}

Without @root-array, exporting to JSON would produce {"0": {...}, "1": {...}, ...}. With it, the output is [{...}, {...}, ...].

The directive takes no arguments and must appear before any data pairs.

Unknown Directives

Unknown directives (e.g., @custom) at the document top level are silently ignored. If a same-line argument follows the directive (e.g., @custom foo or @custom [1,2,3]), it is consumed and discarded. Arguments on the next line are not consumed — they are parsed as normal statements. This enables forward compatibility: files authored for a newer spec version can be partially parsed by older implementations that do not recognize new directives.

When an unknown directive appears as a value (e.g., key: @unknown [1,2,3]), it is treated as null. The argument expression is consumed but discarded.

File Includes

Import other TeaLeaf files:

@include "schemas/common.tl"
@include "./shared/config.tl"

Paths are resolved relative to the including file. Included schemas are available for @table use in the including file.

Formatting Rules

  • Trailing commas are allowed in objects, arrays, tuples, and maps
  • Whitespace is flexible – indent as you like
  • Key names follow identifier rules: start with letter or _, then letters, digits, _, -, .
  • Quoted keys are supported for names with special characters: "Content-Type": "application/json"