The language follows a clean, restricted subset of Python syntax. Features intentionally omitted or modified from standard Python are summarized in Differences from Python.
Lines and Indentation
Code blocks are delimited by indentation. Indentation must use multiples of 4 spaces; tab characters are rejected.
Comments start with # and run to the end of the line. Blank lines and comment-only lines are ignored.
Each statement occupies a single logical line. Backslash line continuations (\) and semicolons (;) are not supported, though expressions inside parentheses (...) or brackets [...] may span multiple lines.
Identifiers and Keywords
Identifiers match [A-Za-z_][A-Za-z0-9_]*. Names starting with a double underscore (__) are reserved and forbidden.
Reserved keywords: def, return, if, elif, else, for, in, break, continue, pass, and, or, not, True, False.
User-defined names cannot shadow built-in function names, nor can a name switch kinds (between function, variable, constant, or port).
Top-level assignments whose identifier consists solely of uppercase letters, digits, and underscores (e.g., BLOCK_SIZE = 16) define immutable constants.
Literals
Type
Syntax
int
Decimal 255, hexadecimal 0xFF, binary 0b1010. Underscore separators (1_000) are allowed. Negative numbers use the unary - operator.
bool
True, False
bytes (hex)
h"87 23 af"
bytes (binary)
b"1010 0001"
bytes (UTF-8 text)
s"label" (UTF-8 encoded byte sequence)
string
"...". Supported escapes: \\, \", \n, \r, \t, \uNNNN. Single-quoted strings are not used.
[e1, e2, ...]. All elements must have the same type. An empty list requires an explicit type annotation, such as xs: list[bytes] = [].
Bytes Literals
The prefix (h, b, or s) must be attached directly to the opening double quote with no space (h "87" is a syntax error).
h"...": Contains only hexadecimal digits and optional spaces (spaces are ignored). No 0x prefix is allowed, and the total hex digit count must be even. h"" is the empty byte array.
b"...": Contains only 0, 1, and optional spaces. Every 8 bits form one byte, so the total bit count must be a multiple of 8.
s"...": Encodes the string characters as UTF-8 bytes.
Unlike Python, b"..." is a binary bit-string literal (0 and 1), not an ASCII byte literal. Use h"..." for hex bytes and s"..." for ASCII/UTF-8 text bytes.
Expression
Result (Hex)
h"87 23 af"
8723af
b"1000 0111"
87
s"0123"
30313233
s"0123" == h"30313233"
True
Adjacent literals of the same kind inside parentheses are concatenated automatically across lines, allowing multi-line keys or test vectors with per-line comments:
KEY = (h"00 11 22 33 44 55 66 77" # first 8 bytes
h"88 99 aa bb cc dd ee ff") # last 8 bytes
o = KEY
Statements
Statement
Form
Assignment
x = expr
Typed Assignment
x: int = expr
Augmented Assignment
x += e (also -=*=//=%=&=|=^=<<=>>=). Equivalent to x = x op e.
Subscript Assignment
b[i] = v, b[a:c] = part, b[o, n] = part, xs[i] = v (see Subscripts).
Tuple Unpacking
a, b = f(x), a, b = b, a
Conditional
if / elif / else
Loop
for x in iterable:
Control Flow
return, break, continue, pass
Call Statement
Standalone function call, e.g., fail("CODE", "message").
A variable's static type is fixed at its first assignment. Conditional expressions take the form val1 if cond else val2, where both branches have the same type:
o = "big" if n > 255 else "small"
Functions and Constants
Functions are defined only at the top level; nested functions are not permitted.
Every parameter requires a type annotation. Return types are written -> T or -> tuple[T1, T2]. Procedures with no return value omit -> and are called as standalone statements.
User functions do not support default parameter values, keyword arguments, or variadic arguments.
A function can access only its own parameters, local variables, functions defined earlier in the file, constants defined earlier, and built-in functions. It cannot access input or output port variables directly, which also prevents recursion and mutual recursion.
Every execution path in a value-returning function must end with a return statement (or fail).
Constants are top-level assignments with all-uppercase identifiers ([A-Z0-9_]+). Their initializer may use only literals, earlier constants, and built-in functions. Constants are immutable and visible inside functions.
Single byte as an int in 0..255 (negative indices count from the end).
b[a:c], b[:c], b[a:], b[:]
bytes
Slice bytes from index a up to c (exclusive).
b[o, n], b[o,]
bytes
Slice bytes by offset and length (omitting n slices to the end).
xs[i], xs[a:c], xs[o, n]
list[T]
Element T or sublist list[T].
Unlike Python, out-of-bounds indices or slice ranges do not silently clamp; if 0 ≤ start ≤ end ≤ len does not hold, evaluation fails with BYTES_OUT_OF_RANGE (or SCRIPT_INDEX_OUT_OF_RANGE for lists). In b[o, n], a negative n acts as an end position counted from the back (identical to b[o:n]).
In the table below, a is 00 11 22 33 44 55 66 77 88:
Expression
Result (Hex)
a[1, 3]
112233 (3 bytes starting at offset 1)
a[6,]
667788 (from offset 6 to the end)
a[6, -1]
6677 (same as a[6:-1])
a[6, -2]
66
a[-3, 3]
667788 (negative offset)
a[1:4]
112233
a[6:]
667788
a[6:-1]
6677
a[-1]
136 (0x88)
Subscript assignment updates bytes or list elements in place. Slice replacement requires the replacement bytes to have the exact same length as the target slice (otherwise fails with BYTES_LENGTH_MISMATCH):
o = a
o[1, 2] = h"ff ee"
for Loops and range
for x in xs: iterates over elements of list[T].
for v in b: iterates over each byte of bytes as an int in 0..255.
for i in range(n), range(start, stop), range(start, stop, step) iterates over integers. range may only appear as the iterable of a for loop, and step cannot be 0.
A single loop may iterate at most 1,048,576 times (checked before the loop starts).
total = 0
for v in b:
if v == 2:
continue
if v == 5:
break
total += v
String Formatting (f-strings)
f"..." interpolates expressions into a string. Format specifiers follow [[fill]align][sign][#][0][width][type]:
Value Type
Allowed Format Types
int
d (default), x, X, b, o. Sign (+, -, space), #, and zero-pad 0 apply only to int.
string
s (width, fill, and alignment).
bytes
x (default), X (two hex digits per byte, no separator).