Files
brolang/LANGUAGE.md
T

183 lines
12 KiB
Markdown

# language features
This file is the compact current-state ledger. `TODO.md` remains the detailed
roadmap and milestone history.
## IMPLEMENTED
### source, declarations, and packages
- newline-terminated statements and `#` comments
- immutable `::` bindings, typed mutable `=` locals/globals, and `_` sinks
- immutable package globals, mutable runtime globals, function-local mutable locals, and mutable local declarations initialized with `undefined`
- package-level functions, globals, native type declarations, and `Name :: alias T`
- directory packages with merged declarations
- file-local relative imports, import aliases, and qualified member access
- transparent declaration aliases with `Name :: alias package.Member`; functions/type factories,
named types, and globals retain their original declaration or storage identity
- native top-level declarations beginning with `_` are visible only within their source file; locals, fields, parameters, and C declarations are unaffected
- relative `.h` imports as synthetic C header package namespaces
- root `main` validation with trap executable recovery for missing or unusable entry points
### scalar, aggregate, and pointer types
- exact-width integers, `isize`, `usize`, `f32`, `f64`, `bool`, `void`, `anyopaque`, and contextual `int`, `float`, and `range` constraints
- target-dependent C scalar primitives from `c_char` through `c_longdouble`, kept semantically distinct from native scalars
- contextual integer/float/character literals, backward type-demand inference through names and arithmetic, and compile-time folding for numeric constant expressions
- strict numeric conversion by default, widening where valid, C scalar coercions at C boundaries, and explicit scalar keyword casts such as `i32(x)` / `c_float(x)`
- compile-time `min_value(T)` and `max_value(T)` bounds for concrete native and C integer scalar types
- arrays `[N]T`, inferred-count arrays `[_]T`, sentinel arrays `[N;S]T`, compile-time expression array counts, slices `[]T` / `[;S]T`, single-item pointers `@T`, many-item pointers `*T`, and sentinel many-item pointers `[*;S]T`
- pointer mutability via `mut`, optional pointers as nullable pointers, pointer arithmetic for many-item pointers, postfix dereference `^`, and trapping optional unwrap `?`
- pointer-to-array `.len`, indexing, slicing, `.ptr` on slices and pointers-to-arrays, implicit address-taking for array-variable slices, and pointer/slice sentinel weakening
- `ptr_cast(T, ptr)` as a first-pass pointer-child retype that preserves optionality, pointer kind, mutability, and sentinel shape
- UTF-8 string literals as immutable pointers to static zero-terminated byte arrays, plus raw backtick multiline strings
- narrow immutable zero-terminated byte pointer/slice conversion to `*c_char` / `?*c_char` without general `u8`/`c_char` interchange
- optionals with `none`, `orelse`, postfix `?`, conditional unwraps, guarded unwraps, and left-to-right short-circuiting multi-unwraps
- nominal distinct types with exact backing construction, native enums with optional explicit integer backing and explicit backing-to-scalar casts, contextual enum literals, and imported C enums as target-backed integer aliases
- source-order native structs, opaque nominal records with `Name :: opaque`, complete `c_struct { ... }`, keyed record literals, native untagged unions, and native tagged unions `union(Enum)` / `union(enum)`
- void-payload tagged-union variants, anonymous struct payloads, contextual `.variant`, `.variant{payload}`, and `.variant{field = value}` construction
- native sum composition with `A | B` for unbacked enums and tagged unions, using program-global `u16` variant ids
- fallible channel types `T ! E`, where `E` is a native enum/tagged union or supported sum composition
#### keyword member names
Reserved keywords are valid native enum members and tagged-union variants when used in an
unambiguous member context:
```bro
TokenKind :: enum {
if
else
return
}
Token :: union(TokenKind) {
if i32
else void
return i32
}
conditional func() TokenKind { return TokenKind.if }
fallback func() TokenKind { return .else }
token func() Token { return Token{ if = 1 } }
```
Keyword variants also work with field access and `.variant` match patterns; `.else:` remains
distinct from the `else:` catch-all arm. No escaping syntax is required. Keywords remain reserved
for ordinary declarations, struct fields, untagged-union fields, and anonymous payload-struct
fields. `_` is not a keyword member name.
### expressions and control flow
- checked integer `+ - *`, unary `-`, float-only `/`, IEEE float arithmetic, comparisons, `!`, `and`, and `or`
- assignments and compound assignments `+= -= *= /=` with single evaluation of complex lvalues; `/=` is float-only
- field access through struct values and pointers, index/slice bounds contextually coerced to `usize`, and unsigned narrower index support
- boolean `if` / `else if` / `else`, braceless single-statement branches, and optional parenthesized conditions
- `while` loops with optional post-iteration update clauses
- `for` loops over ranges, arrays, slices, and pointers-to-arrays with copy captures, pointer captures `|@item|`, and optional `usize` index captures
- `break`, `continue`, labeled `break :label`, labeled `continue :label`, and labeled plain blocks
- bare block scopes and `defer`, including LIFO flushing on fall-through, `return`, `break`, and `continue`
- value blocks, value `if`, value loops, value `match`, `yield`, and labeled `yield :label value`
- `match` statements/expressions over enums, tagged unions, and scalars, including exhaustiveness checks, payload captures, pointer payload captures, multi-pattern arms, and scalar range patterns
- fallible `try`, fallback `catch`, and `catch |e| { ... }` handler blocks
- direct `return match ...` and `yield match ...` value-control-flow operands
#### division
`/` and `/=` accept only floating-point operands. Integer division must state its rounding and
remainder convention with one of these unqualified builtins:
| Builtin | Result |
| --- | --- |
| `div_trunc(a, b)` | quotient rounded toward zero |
| `div_floor(a, b)` | quotient rounded toward negative infinity |
| `div_exact(a, b)` | truncated quotient; traps unless it divides exactly |
| `div_ceil(a, b)` | quotient rounded toward positive infinity |
| `rem(a, b)` | remainder paired with `div_trunc`; sign follows `a` |
| `mod(a, b)` | modulus paired with `div_floor`; sign follows `b` |
The operands may be compatible concrete integer or float scalars. Existing literal coercion and
numeric widening rules apply, the result has the common operand type, and float quotients are
integral-valued floats. These identities hold when representable:
```bro
div_trunc(a, b) * b + rem(a, b) == a
div_floor(a, b) * b + mod(a, b) == a
```
Negative operands distinguish the operations:
```bro
div_trunc(-5, 3) == -1
div_floor(-5, 3) == -2
div_ceil(-5, 3) == -1
rem(-5, 3) == -2
mod(-5, 3) == 1
mod(5, -3) == -1
```
All six builtins diagnose a zero denominator at comptime and trap at runtime, including float
zero. Quotient operations also trap for signed `min_value(T), -1`; `rem` and `mod` return zero for
that pair. `div_exact` traps when `div_trunc(a, b) * b == a` is false in the operand type, so float
exactness follows floating-point equality. Other float NaN and infinity behavior follows the
underlying IEEE operations. Ordinary float `/` remains unchecked and therefore preserves IEEE
infinity/NaN behavior.
The six spellings are reserved only as direct unqualified calls. A qualified call such as
`math.div_floor(a, b)` resolves to an ordinary package function.
### functions, C interop, and linking
- demand-monomorphized Brolang and C-ABI functions
- integer comptime value parameters such as `make_array func($N usize) [N]u8`, specialized by value and omitted from the runtime ABI
- explicit comptime type parameters such as `max func($T type, a, b T) T`, specialized by type and omitted from the runtime ABI
- leading comptime type/integer parameters may be omitted when uniquely recoverable from runtime argument types or the immediate expected result; explicit calls remain valid
- comptime parameters must form one leading prefix before all runtime parameters
- forced typed comptime expressions such as `$sum(1, 2)`, `$Point { x = 1, y = 2 }`, and comptime value blocks such as `${ yield 4 }`
- comptime execution for bodyful Brolang functions with mutable locals, loops, `defer`, `match`, `try`/`catch`, pointer/slice storage mutation, pointer captures, and calls through comptime-known function values
- comptime type factories such as `Box func($T type) type { return struct { value T } }`; calls like `Box(i32)` are concrete nominal types and may appear anywhere a type is expected
- bodyful `c_func` definitions and bodyless `c_func` declarations with exact external symbol names
- concrete-only C signatures, C variadic declarations/calls, and C default argument promotions
- native function pointer values and types with `@func(...) R`, fallible `@func(...) R ! E`, optional `?@func(...) R`, and non-variadic native indirect calls
- Apple Silicon C ABI lowering for scalars, pointers, fixed-signature plain records/unions, small aggregates, homogeneous float aggregates, and indirect aggregate returns
- imported C typedefs, scalar constants, enum constants, fixed arrays, complete plain structs/unions, C `void*` as nullable `anyopaque` pointers, and pointers to opaque records
- imported external C object variables, including mutable variables and immutable object globals
- object-like scalar and plain record/union macro constants
- supported static inline C functions through generated external wrappers
- C function pointer types, imported nullable callback typedefs, concrete `c_func` callback values, and postfix calls through non-null function pointers
- `brolang translate-c <header.h>` for native `.bro` bindings from supported C declarations
- `brolang --translate-c stdio.h` for offline bindings from Zig-bundled standard C headers
- ordered linking of additional C sources, objects, archives, library paths, and libraries through compiler CLI options
### standard packages
- root `std` re-exports `ArrayList(T)` while its operations remain in `std/arraylist`
- `std/mem` generic slice equality, allocator contract with raw byte operations, typed `empty` / `alloc` / `realloc` / `free`, overflow checks, zero-sized-type support, and failure-preserving reallocation
- `std/arraylist` generic `ArrayList(T)` with direct `items` slice access, explicit capacity, allocator ownership, fallible reserve/append, clear, and deinit
- `std/io` explicit `Io` capabilities, `Reader`/`Writer` stream values, one-shot `read`/`write`, and allocation-free `write_all`
### compiler behavior
- error-tolerant compilation with diagnostics and runtime traps where recovery is possible
- lazy semantic checking of demanded function specializations
- static, eager runtime, mutable runtime, and deferred problematic globals with cycle diagnostics
- demand-driven LLVM declarations for referenced foreign functions
- root `main` may be parameterless or accept the canonical `@std/io Io`; the injected form is called through a synthesized no-argument C entry point
- replaceable dynamically loaded libclang C-import backend
- C-header import caching by canonical path, target, include paths, and defines
## PLANNED / DEFERRED
- aggregate comptime parameters and stable aggregate specialization keys
- tuples and native Brolang variadic functions
- exporting Brolang functions to C and broader target-specific C ABI lowering
- non-plain C record layouts such as bitfields, packed records, flexible arrays, qualified fields, and C variadic record arguments
- arenas, pools, build-mode heap policy, and escaping-allocation diagnostics
- recursive type factories, type reflection, and type-producing unions/enums
- broader Zig-style pointer/result casts beyond V1 `ptr_cast(T, ptr)`
- sum-type ABI/layout polish, including dynamic tag-width shrinking, all-void channel collapse, and cross-module global-id determinism
- backed/C enum composition and must-consume fallible linting
- result-to-argument type-demand propagation through function call boundaries
- distinct-type backing operators and reverse explicit conversions
- string concatenation operator