Files
brolang/README.md
T

4.7 KiB

brolang

Prototype error-tolerant Brolang compiler written in Odin.

mkdir -p build
odin build . -out:build/brolang
./build/brolang examples/programs/prototype -o build/prototype
./build/prototype

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:

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:

./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 <dir> becomes -L<dir>, and --c-library <name> becomes -l<name>. --c-include-path <dir> and --c-define <name[=value]> configure C preprocessing.

Relative .h imports create synthetic package namespaces backed by libclang:

native :: import "../include/native.h"

main :: func() void {
	_ = native.imported_add(20, 22)
}

Header imports expose supported external functions, typedefs, C scalars, and pointers to opaque records. They 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.

Bodyless manual and imported C functions may be variadic:

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:

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/:

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, invalid code lowers to runtime diagnostic traps and the compiler returns 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:

import "../math"
other_math :: import "../math"

value :: math.sum(other_math.value, 1)

Current prototype features:

  • Newline-terminated, multiline statements; } may terminate a block's final statement
  • # comments
  • Immutable :: bindings, mutable function-local = bindings, and _ sinks
  • Exact-width signed/unsigned integers, f32, f64, isize, usize, and loose integer-constrained int
  • Target-dependent atomic c_* primitive types, c_func, and pointer-only c_struct
  • 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
  • Qualified imported globals and functions with package-aware symbol mangling
  • Demand-monomorphized Brolang and C-ABI functions
  • 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
  • Static, eager runtime, and deferred problematic globals
  • Runtime diagnostics followed by llvm.trap

See LANGUAGE.md for the concise implemented and planned language feature ledger, and TODO.md for the implementation roadmap.

Compiler exit statuses:

  • 0: executable produced without source diagnostics
  • 1: executable produced with source diagnostics and embedded traps
  • 2: executable could not be produced