# brolang Prototype error-tolerant Brolang compiler written in Odin. ```sh mkdir -p build odin build . -out:build/brolang ./build/brolang examples/programs/prototype -o build/prototype ./build/prototype ``` Programs may receive the system I/O capability explicitly. Readers and writers pair that implementation with a stream; `main func() ...` remains valid. ```bro io :: import "@std/io" main func(system io.Io) void { io.write_all(io.Writer { impl = system, stream = .stdout, }, "hello\n") catch |_| { return } } ``` Bodyless `c_func` declarations bind exact external symbols and require concrete types. C primitives use atomic target-dependent names and remain semantically distinct from exact-width Brolang primitives: ```bro strlen c_func(value *c_char) c_ulong ``` Additional native inputs and libraries are passed to the final `zig cc` invocation in command-line order: ```sh ./build/brolang examples/interop/manual -o build/manual \ --c-link examples/interop/manual/native.c ``` `--c-link` accepts C sources, object files, archives, and direct library paths. `--c-library-path ` becomes `-L`, and `--c-library ` becomes `-l`. `--c-include-path ` and `--c-define ` configure C preprocessing. Instead of passing these on the command line, a project can describe its build in Brolang itself. `brolang new ` creates a project with local `std` and `ffi` copies; `brolang init` does the same for the current directory without overwriting existing files. `brolang build [root]` reads a `config` constant from `root/build.bro` and compiles the program package it names. Without `root`, it searches the current directory and parents for the nearest `build.bro`. Build outputs are written to `root/build/`. ```bro b :: import "@std/build" config :: b.BuildConfig{ name = "manual", source = "src", libraries = &[], lib_paths = &[], includes = &[], defines = &[], links = &["examples/build/manual/native.c"], } ``` `name` is a plain executable name, and `source` is the program package relative to `build.bro`. The list fields map to the matching C options (`libraries` → `-l`, `lib_paths` → `-L`, `includes` → `-I`, `defines` → C defines, `links` → linker inputs) and, like those flags, their paths are relative to the invocation directory. Lists take the address of an array literal; empty lists are written `&[]`. See `examples/build/` for runnable projects. Relative `.h` imports create synthetic package namespaces backed by libclang: ```bro native :: import "../include/native.h" main func() void { _ = native.imported_add(20, 22) } ``` Header imports expose supported external functions, typedefs, C scalars, fixed arrays, complete plain structs and unions, function pointer typedefs, and pointers to opaque records. C `void*` imports as nullable `anyopaque` pointers. Plain records can be constructed with keyed literals, accessed by field, and passed or returned by value through fixed C signatures on `aarch64-macos`. Unsupported or incomplete records remain pointer-only. Header imports never add linker inputs; implementations must still be supplied explicitly with the C-prefixed linking options. Set `BROLANG_LIBCLANG_PATH` when libclang is not installed in a standard location. For offline bindings, `brolang --translate-c stdio.h` resolves standard C headers through the Zig libc headers used by the backend. ```bro native :: import "../include/native.h" pair native.Pair :: native.echo_pair(native.Pair { left = 20, right = 22 }) choice native.Choice :: native.Choice { integer = 42 } ``` Concrete `c_func` declarations and definitions can be passed to C function pointer parameters. Imported C callback typedefs are nullable, so calling one from Brolang requires an explicit unwrap: ```bro native :: import "../include/native.h" double c_func(value c_int) c_int { return value + value } call_mapper func(mapper native.Imported_Mapper) c_int { return mapper?(21) } ``` Native Brolang function pointer values use `*func(...) R`, with fallible channels written on the result: ```bro call func(callback *func(value i32) i32, value i32) i32 { return callback(value) } ``` Bodyless manual and imported C functions may be variadic: ```bro log_values c_func(tag c_int, ...) c_int ``` Zero-terminated byte strings can be passed directly to immutable C character pointers without making `u8` and `c_char` generally interchangeable: ```bro printf c_func(format *c_char, ...) c_int main func() void { _ = printf("answer: %d\n", 42) } ``` Arguments after `...` accept concrete scalars, pointers, and nullable pointers. Narrow integers are promoted to the target C `int` or `unsigned int`, and `f32`/`c_float` are promoted to `c_double`. Arrays, slices, structs, and other compound values must be converted to an explicit C-compatible representation before the call. Compilation phases are isolated under `compiler/`: ```text package loader -> per-file lexer/parser/AST -> checker/HIR -> lower/IR -> opt -> LLVM -> zig cc ``` Source diagnostics do not block executable generation. When recovery is possible, errors lower to runtime diagnostic traps; warnings do not trap. Any source diagnostic makes the compiler return status `1`. Infrastructure or backend failures return status `2`. Top-level function bodies are semantically checked lazily when a concrete specialization is demanded. Every immediate `.bro` file in the input directory belongs to the root package. Imports are relative directory paths and are local to the file that declares them. Imports beginning with `@` resolve from the project root: ```bro import "../math" other_math :: import "../math" mem :: import "@std/mem" value :: math.sum(other_math.value, 1) ``` Current prototype features: - Newline-terminated, multiline statements; `}` may terminate a block's final statement - `#` comments - Immutable `::` bindings, typed mutable `=` locals/globals, and `_` sinks - Exact-width signed/unsigned integers, `f32`, `f64`, `isize`, `usize`, and loose integer-constrained `int` - Target-dependent atomic `c_*` primitive types, `c_func`, complete `c_struct`, `opaque`, `anyopaque`, and V1 `ptr_cast(T, ptr)` - Arrays, sentinel arrays, single-item pointers, many-item pointers, sentinel many-item pointers, slices, sentinel slices, strings, character literals, optionals, and native structs - String literals as immutable pointers to static zero-terminated byte arrays - Pointer-preserving `.ptr`/`.len`, pointer-to-array indexing and slicing, postfix pointer dereference and optional unwrap, and keyed struct literals - Contextual integer constants and compile-time folding of addition and unary negation trees - Directory packages with merged declarations and file-local relative imports - Relative C header imports as synthetic package namespaces - Plain imported C structs/unions, fixed arrays, and C function pointer typedefs, including keyed literals, field access, callbacks, and Apple Silicon by-value ABI lowering - Qualified imported globals and functions with package-aware symbol mangling - Demand-monomorphized Brolang and C-ABI functions - Integer and type comptime parameters (`func($N usize) [N]u8`, `func($T type, value T) T`) specialized by explicit or uniquely inferred leading comptime arguments - Forced typed comptime expressions (`$sum(1, 2)`, `$Point { x = 1, y = 2 }`) and comptime value blocks (`${ yield 4 }`) - Zig-style comptime type factories returning anonymous native structs (`Box func($T type) type`, used as `Box(i32)`) - 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 - Native function pointer values and types (`*func(...) R`, `*func(...) R ! E`, `?*func(...) R`) - Typed allocation/reallocation through `std/mem` and generic dynamic arrays through `std/arraylist` - Bodyless concrete C function declarations with exact external symbol names - Bodyless manual and imported C variadic declarations with default argument promotions - Ordered linking of additional C sources, objects, archives, and libraries - Checked signed addition and unary negation - Float-only `/` plus explicit `div_trunc`, `div_floor`, `div_exact`, `div_ceil`, `rem`, and `mod` scalar builtins - Static, eager runtime, mutable runtime, and deferred problematic globals - Runtime diagnostics followed by `llvm.trap` See [LANGUAGE.md](LANGUAGE.md) for the concise implemented and planned language feature ledger, and [TODO.md](TODO.md) for the implementation roadmap. Compiler exit statuses: - `0`: executable produced without source diagnostics - `1`: executable produced with source diagnostics; errors may embed traps, warnings do not - `2`: executable could not be produced