Appendices

Appendix A: Current Grammar and CLI

In this chapter

This appendix restates the implemented Orange 2026 surface for convenience. The lexical and grammar specification and the typed-literal semantics are normative, and the pure expression specification, the bindings and conversions specification, the arrays specification, the loops specification, the conditions specification, the lookups specification, the modules specification, the modular arithmetic specification, the blocks specification, the tuples specification, the bytes specification, the sizes specification, the byte order specification, the type parameters specification, the lengths specification, the tests specification, and the computed amounts specification are proposed under OEP-0005 through OEP-0021 and in the owner’s review. Where this summary and those documents differ, they control.

Grammar

The parser accepts exactly this grammar, with at most two tokens of lookahead, except that if before (, -, [, the word as, or the word with followed by [ scans forward, without backtracking, for a brace group followed by else, and a name followed by [ scans forward, reading each token at most twice over a whole source, for brackets that hold only integers, names, a name’s [n], +, -, *, /, %, ^, commas, and parentheses followed by (, which make it a call with sizes or types:

source_file     = edition_decl module_decl EOF ;
edition_decl    = "edition" "2026" ";" ;
module_decl     = "module" IDENTIFIER "{" use_decl* type_decl* member* "}" ;
member          = function_decl | test_decl ;
use_decl        = "use" IDENTIFIER ";" ;
type_decl       = "type" IDENTIFIER "=" declared_type ";" ;
function_decl   = "spec" IDENTIFIER "(" ")" spec_tail
                | "spec" IDENTIFIER size_params? "(" parameters? ")" typed_tail
                | "impl" IDENTIFIER "(" ")" empty_body ;
test_decl       = "test" STRING "{" binding* expression "}" ;
size_params     = "[" size_param ("," size_param)* "]" ;
size_param      = IDENTIFIER "in" (INTEGER ".." INTEGER | type_list) ;
type_list       = "{" declared_type ("," declared_type)* "}" ;
spec_tail       = empty_body | typed_tail ;
typed_tail      = "->" declared_type "{" binding* expression "}" ;
binding         = "let" pattern "=" expression ";" ;
pattern         = typed_name | "(" typed_name ("," typed_name)+ ","? ")" ;
typed_name      = IDENTIFIER ":" declared_type ;
empty_body      = "{" "}" ;
parameters      = parameter ("," parameter)* ","? ;
parameter       = IDENTIFIER ":" declared_type ;
declared_type   = element_type | tuple_type ;
tuple_type      = "(" element_type ("," element_type)+ ","? ")" ;
element_type    = parsed_type ("^" size)? ;
size            = INTEGER | IDENTIFIER | "(" expression ")" ;
parsed_type     = "Mod" "[" expression "]" | IDENTIFIER ("[" INTEGER "]")? ;

expression      = arithmetic | chain("&") | chain("|") | chain("^") | shift
                | comparison | chain("&&") | chain("||") | division
                | chain("++") | conversion | update ;
conversion      = prefixed "as" (parsed_type | tuple_type | order declared_type) ;
order           = "big" | "little" ;
update          = prefixed "with" "[" (expression | range) "]" "=" expression ;
arithmetic      = product (("+" | "-") product)* ;
product         = prefixed ("*" prefixed)* ;
chain(op)       = prefixed (op prefixed)+ ;
shift           = prefixed shift_operator prefixed ;
shift_operator  = "<<" | ">>" | "<<<" | ">>>" ;
comparison      = prefixed compare_op prefixed ;
compare_op      = "==" | "!=" | "<" | "<=" | ">" | ">=" ;
division        = prefixed ("/" | "%") prefixed ;
prefixed        = literal | ("-" | "~" | "!") prefixed | primary ;
literal         = "-"? INTEGER ;
primary         = IDENTIFIER suffix? | call suffix? | "(" expression ")"
                | byte_string | tuple | array | fill | loop | conditional ;
byte_string     = STRING | HEX_STRING ;
suffix          = "." INTEGER (index | slice)? | index | slice ;
tuple           = "(" expression ("," expression)+ ","? ")" ;
index           = "[" INTEGER "]" | "[" expression "]" ;
slice           = "[" range "]" ;
range           = expression ".." expression? | ".." expression ;
array           = "[" expression ("," expression)* ","? "]" ;
fill            = "[" expression ";" size "]" ;
loop            = "for" IDENTIFIER "in" size ".." size
                  "with" pattern "=" expression block ;
conditional     = "if" expression block "else" (block | conditional) ;
block           = "{" binding* expression "}" ;
call            = (IDENTIFIER "::")? IDENTIFIER sizes? "(" arguments? ")" ;
sizes           = "[" expression ("," expression)* "]" ;
arguments       = expression ("," expression)* ","? ;

Sources are valid UTF-8 of at most 16 MiB. Identifiers are ASCII. Integers may be decimal, 0b binary, or 0x hexadecimal, with single underscores between digits. edition, module, spec, impl, game, proof, and claim are reserved; the last three have no grammatical role yet. let, as, for, in, with, if, else, use, type, hex, big, little, true, and false are not reserved: let starts a binding only at the start of a body, step, or branch item before a name or a tuple pattern, as converts only after a complete operand, for starts a loop only before a name, in and with are words only in a loop’s header, in also between a size’s or a type parameter’s name and its bounds or list, with updates only after a complete operand and before [, if starts a conditional only where a condition can follow it, else is a word only after a conditional’s value, use and type start declarations only at the head of a module before its first function, Mod takes a modulus only before [, hex begins a hex string only directly before a quote, big and little are byte orders only directly after as and before ( or a name other than as and with, and true and false are values only where no name of that spelling is in scope. Line and nested block comments are trivia. <<, >>, <<<, >>>, and ++ are single tokens, matched longest first, and a string is a byte string of printable ASCII and escapes or, when hex touches its opening quote, a hex string of digit pairs and spaces. Operators from different groups, or two shifts, two comparisons, or two divisions, may not share a level without parentheses, and a conversion or an update shares a level with no operator and no other conversion or update. ^ after a declared type gives its array length; anywhere else it is exclusive or. Expressions may nest at most 64 levels deep, counting groups, tuples, calls, arrays, indices, slices, loops, conditionals, updates, moduli, and prefix operators, and reach height 256; a function declares at most 4 size parameters, 64 parameters, and 256 bindings and has at most 256 instances, a loop’s step or a branch at most 256 bindings, a call supplies at most 4 sizes and 256 arguments, an array literal lists at most 65,536 elements, a byte string holds 1 through 65,536 bytes, a tuple type, a tuple, and a tuple pattern hold at most 16 parts, and a loop’s bounds and a size parameter’s bounds satisfy 0 ≤ a < b ≤ 65536. A module declares at most 64 use declarations and 64 type declarations, and a program holds at most 64 modules, its root included.

Types and values

Type Values Displayed as
Int All mathematical integers (unbounded); a literal’s magnitude may use at most 16,384 significant bits Decimal, with - when negative
Bool The truth values true or false
Word[8] The integers modulo 2^8, 0 through 255 0x and 2 lowercase hex digits
Word[16] The integers modulo 2^16 0x and 4 lowercase hex digits
Word[32] The integers modulo 2^32 0x and 8 lowercase hex digits
Word[64] The integers modulo 2^64 0x and 16 lowercase hex digits
Mod[m] The integers modulo a constant m from 2 through 2^521 − 1, as least residues 0 through m − 1 Decimal
T^n Sequences of exactly n values of any type above, for n from 1 through 65,536 The elements in order, separated by a comma and a space and enclosed in [ and ]
(T, U, ...) Tuples of 2 through 16 values, each of a scalar or array type above and never a tuple The elements in order, separated by a comma and a space and enclosed in ( and )

No other type, width, or length is accepted; a name declared by type stands for the type it names. A modulus is a constant built from integer literals with +, -, *, <<, and parentheses, and two moduli are one type when they are equal. Word and residue literals are never wrapped, truncated, saturated, or coerced: a literal of Mod[m] has a magnitude less than m, and -n stands for m − n. No value changes type implicitly. e as T converts between any two scalar types other than Bool: it takes the integer value of e, the least residue for a residue, and, for Word[n] or Mod[m], its residue modulo 2^n or m. The operand’s type comes from its first name, call, conversion, or index, so a conversion of literals alone is an error. An array literal lists exactly as many elements as its type, and x[k] selects the element at position k, which must be proved below the length before anything runs. An index is checked as the word type of its first name, call, conversion, or element, and ranges over that type, narrowed by its operators; otherwise it is an Int built from integer literals, loop indices, and words converted with as Int, using +, -, *, /, %, and conditionals. An update, a fill, a join, a slice, or a slice update costs one evaluation step per 64 elements of the array it builds, or part of 64, and a byte string costs one. No operator but ++, and no conversion without a byte order, applies to a whole array, and an array’s elements are never arrays. A byte string "..." of printable ASCII characters and the escapes \", \\, \n, \r, \t, \0, and \xNN, or hex"..." of hex digit pairs, is the array Word[8]^n of its bytes. a ++ b is the elements of a followed by those of b, of one element type. x[a..b] is the elements of x from index a up to but not including b, x with [a..b] = v is x with them replaced by v, and an omitted bound is 0 or the length. A slice’s bounds are built from integer literals and loop indices with +, -, and * by a constant, and are proved a fixed positive distance apart and in range at every step. A tuple lists exactly as many elements as its type, p.k selects element k, counted from zero, and no operator, comparison, conversion, index, or update applies to a whole tuple; neither a tuple’s nor an array’s elements are ever tuples. A spec f[n in a..b, ...] stands for one instance for each value of its sizes, ordered with the first size changing slowest, and each instance is checked as the function written out with those values; only the first instance of a function in error is reported. A size is built from integer literals and size parameters with +, -, *, /, %, prefix -, and parentheses and computed exactly, with / and % Euclidean and total; it writes an array length, a fill length, or a loop bound, and a size parameter’s name is an Int constant, which index and slice analysis read as a literal. f[s, ...](args) calls the instance with those sizes, and f(args) the one instance whose array parameters have the lengths of its arguments. Sizes cost nothing at run time. A type parameter K in {T, U, ...} lists distinct types, resolved once and written without sizes; its name is a type in the function’s signature and body, never a value, and the function stands for one instance for each combination of its sizes’ values and types, with at most four parameters in brackets and 256 instances. A call’s entries are Int, Bool, a word, an array of them, a type declaration’s name, or the caller’s type parameter, matched by type equality; f(args) calls the one instance whose parameters have its arguments’ types, literal lengths deciding only where a type does not, and among several, the one whose result has the type its place expects. Types cost nothing at run time. e as big T and e as little T convert words, a word or an array of words, to words of the same number of bits, to Int, or to Mod[m], and an Int or a residue to words, through the number N the words spell, their first word most significant for big and least significant for little; a number becomes the words that spell its residue modulo 2 to the power of their width, and words become N, or N modulo m. The operand’s type is its first typed leaf’s, an array literal’s or a fill’s from its elements and its length. A conversion in a byte order costs one evaluation step per 64 bits of its width, or part of 64, and a conversion to Mod[m] also the cost of as Mod[m].

Operators

Expression On Int On Word[n] On Mod[m]
a + b, a - b, a * b Exact Modulo 2^n Modulo m
-a Exact negation Not defined; write 0 - a m − a, or 0 when a is 0
a & b, a | b, a ^ b Not defined Bitwise and, or, exclusive or Not defined
~a Not defined Bitwise complement Not defined
a << k, a >> k Not defined Logical shift left, right Not defined
a <<< k, a >>> k Not defined Rotation left, right Not defined
a / b Euclidean quotient Unsigned quotient a times the inverse of b, or 0 when b has none
a % b Euclidean remainder, 0 ≤ a % b < |b| Unsigned remainder Not defined
a == b, a != b Equality, giving Bool Equality, giving Bool Equality, giving Bool
a < b, a <= b, a > b, a >= b Order by value, giving Bool Unsigned order, giving Bool Not defined

For every type, a / 0 is 0, and a % 0 is a where % is defined. On Bool, !a, a && b, and a || b are negation, conjunction, and disjunction, evaluating every operand, and == and != compare. if c { a } else { b } has the type of both branches and evaluates only the one its Bool condition chooses; an else if chain is one conditional per arm.

An amount k written as one integer literal must be unsigned and from 0 through n − 1. Any other amount is an Int or a word, typed by its first typed leaf: a << k is floor(a · 2^k) and a >> k is floor(a · 2^−k) modulo 2^n, so a shift by n or more is 0 and a negative amount shifts the other way, and a rotation turns by k modulo n, at one evaluation step whatever k’s size. Calls name typed spec functions of the same module, or, as m::f(...), of a module m it uses, pass exactly one argument per parameter, and may not form a cycle; nor may the uses of a program. A let binding states its type, is in scope after its semicolon, and may not reuse the name of a parameter or another binding. A tuple pattern, as in let (s: T, c: U) = e; or a loop’s with (a: T, b: U) = e, names each element of its value and states each name’s type, and each of its names follows the same rules.

Commands

orangec [OPTIONS] <check|eval|lex> <FILE>...
orangec eval [--steps <N>] [--spec <NAME>]... [--stats] <FILE>
orangec test [--steps <N>] [--stats] <FILE>
orangec fmt <FILE>
orangec fmt --check <FILE>...
orangec doc <FILE>
orangec replay --function <MODULE::NAME> [--instance <N[,N...]>]
               --witness <FILE> [--steps <N>] [--stats] <SOURCE>
orangec keygen [--scheme <NAME>] [-o <FILE>]
orangec <enc|dec> [--key <FILE>] [--scheme <NAME>] [-o <FILE>] <FILE>
orangec schemes [<NAME>...]
Command Behavior
check Lexical, syntactic, and semantic validation; silent on success
eval Validate one program, then print each typed spec without parameters of its root module as module::name: Type = value, and each instance of a sized one as module::name[2]: Type = value
lex Print the deterministic token stream with byte spans
fmt Print one formatted source or check sources without changing them
doc Print standalone offline HTML for one parsed source
replay Validate one program and reference-evaluate a Boolean specification for exact typed local arguments
test Validate one program, then run its root module’s tests in source order, printing test "TITLE" ... ok or ... FAILED for each and a count; status 1 when any fails
keygen Make a random key for a scheme, mode 0600, never replacing a file
enc Seal one file as FILE.orange with its key’s scheme
dec Open one sealed file; output is published only if every chunk is authentic
schemes List the built-in schemes or check a scheme program

Options are --edition <YEAR> (only 2026, at most once), for eval, test and replay --steps <N> (a step budget from 1 through 1,073,741,824, at most once; default 1,048,576) and --stats (report each evaluated function’s or test’s steps and the total on standard error, after the values or the report), for eval only --spec <NAME> (evaluate only this function without parameters; up to 64 names), for fmt only --check (check one through 256 sources without changing files; otherwise fmt requires exactly one source), for replay --function <MODULE::NAME>, --witness <FILE> and optional --instance <N[,N...]> (an exact numeric finite-instance vector), --scheme <NAME> (a built-in name or a program path), --key <FILE> (default $XDG_CONFIG_HOME/orange/key), -o or --output <FILE>, -- to end option parsing, -h or --help, and -V or --version. A file name of - reads UTF-8 source from standard input, once per invocation. For check, eval, test and replay, each use m; reads the module m from m.or beside the file that names it, or from the current directory for standard input, once per program. Exit status is 0 on success, 1 on a compile or input failure, and 2 on a usage error.

Diagnostic families

Codes Phase Examples
ORC0001–ORC0009 Lexing Unexpected character, unterminated comment or string, malformed integer, token budget, malformed hex string
ORC0101–ORC0108 Parsing Expected syntax, unsupported edition, trailing syntax, parser budget, ungrouped operators
ORC0201–ORC0242 Semantic analysis Duplicate function, parameter, or binding, unsupported type or word width, negative or out-of-range word, magnitude limit, unknown name or function, name used before its binding, argument count, type mismatch, undefined operator, shift amount, call cycle, conversion operand without a type, unsupported array length, wrong element count, index out of range, index on a non-array, loop range empty or too large, Int index without a bound, comparison whose operands have no type, a use naming no module, a call qualified by a module not used, a cycle of uses, a duplicate module, a modulus that is not a constant from 2 through 2^521 − 1, a type declaration naming a built-in type or repeating a name, .k on a value that is not a tuple, a byte string character that is not printable ASCII, a slice whose length changes or is not positive, a size built from anything but literals and size parameters, a size’s range that is empty or too large, too many instances, a size outside its range, a wrong number of sizes, a call that fits no instance or several, words converted to words of a different width, a type listed twice, a type entry not listed or not a type, a call that fits no instance by its arguments’ types, a test’s title that is empty, too long, unprintable, or repeated
ORC0250–ORC0252 Formatting Formatter resource limit, inconsistent result, source requiring formatting under --check
ORC0260–ORC0261 Documentation Documentation resource limit or inconsistent construction
ORC0270–ORC0274 Witness replay Noncanonical argument value, type mismatch, decode resource limit, invalid binding or inconsistent replay
ORC0301 Evaluation Step budget, call depth, or Int result size exhausted
ORC1001–ORC1016 Command line Unreadable or oversized input, invalid UTF-8, duplicate standard input, output limit, key file, scheme, sealed-file format, a chunk that is not authentic, randomness, a --spec name that matches no function

Codes and their meanings are stable automation surfaces. Every resource budget fails closed with a diagnostic rather than a panic, hang, or partial success.