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

Lexical structure

The character-level rules of rut source: files, comments, identifiers, the keyword set, and the enforced naming conventions.

Source model

  • Files are UTF-8, extension .rut. Both LF and CRLF line endings are accepted (CRLF is normalized); a leading BOM is skipped.
  • Comments:
    • // line comment
    • /* block comment */ — block comments do not nest
    • /// doc comment (also /** ... */) — attaches to the following declaration and is kept for tooling; it is not semantic
  • There is no off-side rule: statements end with ; (required), blocks are braced.

Identifiers and $

ident := (letter | "_" | "$") (letter | digit | "_" | "$")*

$ is an ordinary identifier character, valid anywhere in a name: on_mount$, viewport_size$, $temp, $x1, even $ alone. There is no $ punctuation token and no $-interpolation (f-string holes use { } — see Literals and inference).

The trailing $ is a naming convention, not a lexical category: it marks dispatch-inverted members — anything a runtime fires or owns rather than you calling it. Event props (on_click$), lifecycle hooks (on_mount$, before_destroy$), subscription updates (on_update$), watch controls (start$, stop$), engine atoms (viewport_size$), and mutation handles generally. Never on functions you call, widget builders, or types.

Keywords

The keyword set is exactly:

fnletmutifelse
whileforofreturnwhen
enumstructclasstraitimpl
requiresusepubstaticasync
awaitexternishostselect
truefalsenil

Contextual words — ordinary identifiers elsewhere:

WordSpecial meaning
typethe alias introducer (type Km = Meters; — see Type aliases and union bounds)
entryentry fn at module scope publishes the function to the embedder
selfthe explicit receiver, first parameter of an instance method
Selfnames the enclosing class inside its body; the class-private literal Self { .. }
newnot special — the conventional construction-method name (Rect.new(..)); there is no new expression
asthe numeric cast (x as u32) and the select arm bind
superonly inside pub(super)
builtindeclaration modes of the engine’s own surface (builtin fn, builtin primitive, builtin trait, builtin impl)

panic(msg) and assert(cond, msg?) are prelude functions, not keywords.

Reserved words

Each reserved word is a hard error whose message names the rut replacement:

ReservedError replacement
switch, case, matchwhen — arms are pattern -> body
null, undefined, voidabsence is nil on a ?T
anya trait type or opaque
typeof, instanceofx is T tests at runtime
extendsno inheritance — compose instead
interfacerut spells this trait
dataclassremoved — spell it struct
deleteno dynamic properties
initeration is for (let x of ..)
with—
var, constbindings spell let / let mut
privatemembers are private by default; add pub

Naming conventions (enforced)

  • Types are PascalCase — user types and parameterized builtins: Vec<T>, [T], Weak<T>, opaque, Task<T>, Point, Drawable. Scalars and simple buffers stay lowercase: i32, u8, f32, bool, str, bytes.
  • Functions and methods are lower_snake_case — unwrap_or(d), push(v), checked_add(y), spawn_worker(..).
  • Construction is a method call, never a type-call. User classes construct through their own class methods: Rect.new(3, 4), Rect.from(other), Version.parse(s) — see Classes and constructors. Only builtin surfaces keep call forms: bytes.zeroed(n), Weak(v), opaque(v), the repeat [v; n], and Vec<T>.from(..) (see Builtin generic types).
  • The trailing-$ marker is kept meaningful by this style rule alone; the compiler attaches no semantics to it.