3. Source text
3.1 Encoding#
Source is UTF-8. A byte-order mark is accepted and ignored only at byte zero. NUL bytes, invalid UTF-8, misleading bidirectional control characters, and look-alike punctuation are rejected. CRLF is normalised for parsing while source positions keep correct byte and line mappings.
Identifiers are ASCII: a letter or _, followed by letters, digits, or _. The standalone _ is the pattern wildcard; _unused is an ordinary name. Unicode is fully supported inside text and comments.
3.2 Layout#
A statement suite after : is either one simple statement on the same physical line or a newline followed by a block indented four spaces. Type, enum, union, and interface bodies always use the indented form.
if cached: return result
if image.width > maximum_width:
let scale = maximum_width / f64(image.width)
image.resize(scale)
- A same-line suite cannot contain a compound statement (
if,while,for,match,asm), a nested suite, or a second statement. - Tabs are errors with a machine-applicable replacement. There are no semicolons and no line continuations.
- Newlines terminate statements except inside
(),[], or{}, where they are spacing. Inside delimiters, a:that ends its line opens an indented suite, so amatchexpression or acatchhandler can be written as an argument. - A trailing comma is accepted in multi-line parameter, argument, tuple, array, and payload lists.
- Blank lines do not affect meaning. The formatter,
luce fmt, is the single authority on line breaking and indentation. - An
asmsuite (§8.9) is captured raw: its lines are not tokenised.
Why. Base keeps Luce's layout rather than adopting braces because a brace dialect would mean two parsers, two formatters, and a permanent "which style is this file" question, and every C programmer who has used Python has already learned that the adjustment takes a day. The one-line suite form covers the short if x: return cases that feel worst without braces.
3.3 Comments and documentation#
# An ordinary comment.
## A public summary used by `luce doc`.
## Further paragraphs are Markdown.
pub func area(width: f64, height: f64) -> f64:
return width * height
# begins a comment outside a string. Consecutive ## comments immediately before a declaration are its documentation. A ## block at the top of a file, separated from what follows by a blank line, documents the module.
3.4 Naming#
Types, interfaces, and unions are PascalCase; functions, methods, bindings, fields, cases, modules, and packages are snake_case; acronyms are words, HttpClient. Violations are formatter and linter diagnostics, never a change of meaning. The compiler relies on the convention in one place: a PascalCase name followed by [ in expression position is read as a generic instantiation (§7.6).
3.5 Scope#
Names resolve lexically. A module's declarations share one namespace and are order-independent. Members of a type have their own namespace. Locals are sequential; use before declaration is rejected. A local may not shadow another visible local, parameter, or imported name; renaming is the repair. A loop, catch, if let, or match binding owns its nested scope. A loop label (§8.5) lives in its own namespace.
The compiler-known core namespace cannot be redeclared: assert, discard, error, trap, hash, print, format_into, sizeof, alignof, offsetof, and the core type names. These parse as ordinary calls; only their checked types and semantics are special.
Why. No shadowing removes a refactoring hazard and keeps every diagnostic that names a binding unambiguous. Making sizeof a core name rather than a keyword keeps the grammar small: it is a call whose argument may be a type.
3.6 Reserved words#
and as asm break catch const continue defer elif else enum errdefer export
extern false for from func goto if implements import in interface is let
match mutating none not or pub recover return self struct test thread_local
true try type union var volatile while
Contextual words, meaningful only in the positions stated: void before *; packed and align before struct; inline before func; blocking and out in extern declarations; in, out, inout, reg, mem, clobber in an asm operand list; copy in a capture list. goto is reserved and unused (§8.6). class, new, weak, spawn are reserved in full Luce and rejected in Base with a diagnostic that names the tier they belong to.