BRAIDGROUP
RESEARCH & DEV
50. Documentation

Language Specification

The canonical language specification for Braid. This is the definitive reference covering all syntax rules, type rules, semantics, and the execution model.

1. Lexical Grammar

1.1 Character Set

Braid source files are UTF-8 encoded. The lexer recognizes ASCII letters, digits, underscores, and the following special characters: ( ) [ ] . , ; : = + - * / % ! < > | & @ # ' " _. Comments and string literals may contain any UTF-8 character.

1.2 Comments

Three comment styles are supported:

# Hash comment to end of line
// C++ style comment to end of line
/* Block comment spanning
   multiple lines */

1.3 Identifiers

Identifiers begin with a letter (a-z, A-Z) or underscore (_), followed by zero or more letters, digits, or underscores. Identifiers are case-sensitive. Keywords are reserved and cannot be used as identifiers.

valid:   x, _temp, myVar, FooBar123
invalid: 123abc, x-y, x.y, if

1.4 Literals

Integer:    42, 0, -17, 1000000
Float:      3.14, 0.5, -2.718, 100.0
String:     "hello", 'world', "nested 'quotes'"
Boolean:    true, false
Null:       nil

Integer literals are 64-bit signed integers. Float literals are 64-bit IEEE 754 double precision. String literals support single and double quotes. Boolean literals are true and false. The null value is nil.

1.5 Keywords (Reserved Words)

The following identifiers are reserved as keywords:

fn     let    if      else    while   return
struct enum   match   import  extern  impl
diameter pole  observe evolve native  model
true   false  with    async   await   spawn
device

Additionally, @autograd, @layer, and @param are decorator tokens used as prefixes.

2. Syntax Grammar

2.1 Program Structure

A Braid program consists of a sequence of declarations and statements at the top level. Declarations include function definitions, struct definitions, enum definitions, diameter definitions, imports, extern FFI declarations, native FFI declarations, model definitions, decorators, and impl blocks. Statements include variable declarations, return statements, if/else, while loops, match expressions, assignments, and expression statements.

2.2 Declarations

Function Declaration

fn name(param1: Type1, param2: Type2, ...) -&gt; ReturnType {
    // body
}

The fn keyword declares a named function. Parameters are comma-separated name: type pairs. The return type is specified with -> Type and is optional — if omitted, the function returns nil. The function body is a block enclosed in braces. Anonymous functions (closures) omit the name: fn(x: int) -&gt; int { return x * 2 }.

Variable Declaration

let name = value
let name: Type = value

The let keyword introduces a new binding. The type annotation is optional — the type is inferred from the initializer. Once bound, the variable can be reassigned with = but cannot be redeclared.

Struct Declaration

struct Point {
    x: int;
    y: int;
}

Defines a product type with named fields. Each field has a name and type. Fields are accessed with dot notation: point.x. Struct literals use named field initialization: Point { x: 10, y: 20 }. Maximum 16 fields per struct.

Enum Declaration

enum Color {
    Red, Green, Blue
}

Defines a sum type with named variants. Variants are accessed with dot notation: Color.Red. Enums support matching via match expressions.

Import Declaration

import std.io
import std.math
import ui.widget

Imports a module by dot-separated path. The compiler searches for .br or .bx files matching the path relative to the import search paths.

Extern FFI Declaration

extern fn sqrt(x: float) -&gt; float
extern fn srand(seed: int)

Binds to an external C function at link time. The function signature must match the C declaration.

Native FFI Declaration

native fn print_int(val: int)
native fn print_float(val: float)

Declares a runtime-linked FFI function implemented in the BraidVM C runtime. Invoked via the OP_INVOKE_FFI bytecode instruction.

Diameter Declaration

diameter name: {
    pole pole_a: {
        return value_a
    }
    pole pole_b: {
        return value_b
    }
}

Defines a dialectical reasoning construct with two opposing poles. Each pole is a block that returns a numeric value representing its force. The diameter maintains an internal state that evolves based on the tension between poles.

Model Definition

model name = BaseModel {
    param1: value1;
    param2: value2;
}

Defines an ML model configuration by instantiating a base model with hyperparameters. Each parameter is a key-value pair terminated by a semicolon.

Impl Block

impl TypeName {
    fn method(self, ...) -&gt; Type {
        // body
    }
}

Implements methods for a struct type. Methods receive self as the first parameter, which refers to the instance the method is called on.

Decorators

@autograd fn loss_fn(x: float, y: float) -&gt; float { ... }
@layer struct Linear {
    @param weight = tensor_init(128, 64);
    fn forward(self, x: tensor) -> tensor { ... }
}

@autograd marks a function for automatic differentiation. @layer marks a struct as a neural network layer. @param declares a trainable parameter inside a layer.

2.3 Statements

Block

{
    statement1;
    statement2;
}

A block is a sequence of statements enclosed in braces. Blocks create a new scope — variables declared inside a block are not visible outside.

Return Statement

return;
return expression;

Exits the current function. If no expression is given, nil is returned.

If/Else Statement

if condition { ... }
if condition { ... } else { ... }
if condition { ... } else if condition { ... } else { ... }

The condition must evaluate to bool. The else branch is optional and can chain additional if conditions.

While Loop

while condition {
    body;
}

Repeatedly executes the body while the condition is true. The condition must evaluate to bool.

Match Expression

match expr {
    pattern1 => expression_or_block,
    pattern2 => {
        body
    },
    _ => default
}

Pattern matching on integers, strings, booleans, enums, and nil. The wildcard _ matches any value. Each case can be a single expression (optionally comma-terminated) or a block.

Assignment

variable = expression
struct.field = expression
array[index] = expression

Reassigns a value to an existing mutable binding, struct field, or indexed element.

2.4 Expressions

Operator Precedence (Highest to Lowest)

PrecedenceOperatorsAssoc
1() [] .Left
2- !Right
3* / %Left
4+ -Left
5< <= > >= == !=Left
6&&Left
7||Left
8=Right

Primary Expressions

integer_literal     // 42
float_literal       // 3.14
string_literal      // "hello"
bool_literal        // true, false
nil_literal         // nil
identifier          // x, myVar
struct_literal      // Point { x: 10, y: 20 }
array_literal       // [1, 2, 3]
tensor_literal      // [[1, 2], [3, 4]]
fn_expression       // fn(x: int) -&gt; int { return x * 2 }
grouped_expr        // (expression)
evolve_expr         // evolve(diameter)
observe_expr        // observe(diameter)

Postfix Operations

expr.identifier     // field access, method call
expr(args)          // function call
expr[index]         // array/tensor index
expr[start:end]     // tensor slice
expr[..., dim]      // tensor slice with ellipsis

Tensor Slice Syntax

tensor[i]               // single index
tensor[i:j]             // range slice [i, j)
tensor[i:j:k]           // range slice with step
tensor[..., i:j]        // ellipsis for all preceding dims
tensor[i, j]            // multi-dimensional index

With Device Expression

with device("cuda") {
    // tensor operations here use GPU
}

Device Transfer

let gpu = tensor.to("cuda")
let cpu = tensor.to("cpu")

3. Type System

3.1 Primitive Types

TypeDescriptionSize
int64-bit signed integer8 bytes
float64-bit IEEE 754 double8 bytes
boolBoolean (true/false)1 byte
stringUTF-8 string (heap-allocated)Variable
nilNull/void type0 bytes

3.2 Composite Types

  • Struct types — Product types with named fields. Each field has a name and a type. Structs are value types (copied on assignment) but fields containing heap objects (strings, arrays, tensors) are reference-counted.
  • Enum types — Sum types with named variants. Each variant is a distinct value. Enum comparison uses variant identity.
  • Array types — Dynamic arrays of homogeneous elements. Denoted [Type] in type annotations. Elements are accessed by integer index.
  • Tensor types — N-dimensional arrays with shape and dtype. Denoted by [[...]] syntax. Supports 0-d to 8-d tensors.
  • Function types — Denoted (Type1, Type2) -> ReturnType. Functions are first-class values (closures).
  • Diameter types — Dialectical reasoning objects with internal state, two poles, and tension/resonance properties.

3.3 Type Inference

Braid uses Hindley-Milner type inference. Types are inferred from context without requiring explicit annotations, except on function parameters (required) and struct fields (required). Type variables are resolved through unification, and type errors are reported at compile time.

3.4 Type Checking Rules

  • Arithmetic operators (+ - * / %): Both operands must be int or both float. Mixed arithmetic is not allowed (no implicit casting).
  • Comparison operators (< <= > >=): Both operands must be int or both float. Return type is bool.
  • Equality operators (== !=): Operands must be the same type. Works on all types including structs, enums, and nil.
  • Logical operators (&& || !): Both operands must be bool.
  • Assignment (=): The assigned value must be assignable to the target type (same type or nil-compatible).
  • If/While conditions: Must evaluate to bool.
  • Return types: The returned expression must match the function's declared return type.

4. Evaluation Semantics

4.1 Expression Evaluation

Expressions are evaluated eagerly left-to-right. Binary operators short-circuit for logical && and ||. Function arguments are evaluated in order before the function call. Struct field initializers are evaluated in declaration order.

4.2 Function Calls

Function calls push a new stack frame. Arguments are passed by value (for primitives) or by reference-counted pointer (for objects). The callee returns a value via return, which is placed on the stack for the caller. Tail calls are optimized by the supercompiler.

4.3 Closure Semantics

Closures capture variables from the enclosing scope by reference (upvalues). The compiler emits OP_CLOSURE with OP_GET_UPVALUE/OP_SET_UPVALUE instructions. Captured variables remain live as long as any closure references them.

4.4 Diameter Semantics

A Diameter maintains an internal state vector S = (value, tension, resonance). The evolve() operation updates value by interpolating between pole_a and pole_b based on current tension. Tension evolves according to the difference between pole outputs — larger differences increase tension. Resonance measures the stability of tension over time. The observe() operation reads the current state properties.

4.5 Tensor Semantics

Tensor literals allocate N-dimensional arrays with type inference from element types. Indexing returns a scalar (zero-dimensional tensor) for individual elements or a sub-tensor for slices. Slicing returns a view (no data copy) when possible. Device transfer (.to("cuda")) moves data to GPU memory. Operations within with device() blocks execute on the specified device.

4.6 Autograd Semantics

Functions decorated with @autograd build a computation graph during the forward pass. Each operation records its inputs and creates a gradient function. The .backward() call traverses the graph in reverse, applying the chain rule to compute gradients. Trainable parameters (@param) accumulate gradients in .grad fields.

5. Memory Model

5.1 Automatic Reference Counting (ARC)

Every heap-allocated object (ObjString, ObjStruct, ObjArray, ObjFunction, ObjClosure, ObjDiameter, ObjTensor) has a ref_count field. When an object is referenced, the count is incremented. When a reference is removed (out of scope, reassignment), the count is decremented. When the count reaches zero, the object is immediately freed.

5.2 Cycle Detection

ARC cannot handle reference cycles. Braid's runtime includes a cycle collector that periodically traverses the object graph, marking reachable objects and collecting unreachable cycles. The marked and is_old fields in the object header support this.

5.3 Generational GC

Optionally, Braid can use a generational GC strategy. Objects are initially allocated as young (is_old = false). Survivors of young collections are promoted to old (is_old = true). Young collections scan only the young generation; full collections scan all objects.

5.4 Value Types vs Reference Types

Primitives (int, float, bool) are value types — they are copied by value. nil is a singleton. All other types are reference-counted heap objects: strings, structs (when they contain heap fields), arrays, functions, closures, diameters, tensors, maps, and bound methods.

6. Module System

6.1 Module Resolution

Modules are resolved by converting dot-separated import paths to filesystem paths. import std.io searches for std/io.br or std/io.bx relative to the current project's import paths. Standard library modules are under std/, UI modules under ui/.

6.2 Compilation Units

Each .br file is a compilation unit. A program may consist of multiple files connected via import declarations. The compiler resolves all imports transitively.

7. Compilation Model

7.1 Pipeline Stages

Source (.br)
  |-- [Lexer] --&gt; Token stream
  |-- [Parser] --> AST
  |-- [Type Checker] --> Typed AST (Hindley-Milner)
  |-- [Supercompiler] --> Optimized AST
  |-- [C Codegen] --> C source code
  |         OR
  |-- [IR Lowering] --> Braid IR
  |-- [IR Verifier] --> Verified IR
  |-- [MLIR Backend] (stub)
  |-- [LLVM Backend] (stub)
  |-- [Bytecode Build] --> .bx bytecode
  v
Native executable or bytecode

7.2 Bytecode Format

.bx header:
  Offset  Size  Field
  0       4     Magic: 'BRDC' (0x42524443)
  4       4     Version (uint32)
  8       4     Target kind (1=LLVM IR, 2=bytecode)
  12      4     Payload size (bytes)
  16      n     Payload data

7.3 Compilation Commands

CommandOutput
braidc parse file.brSyntax validation
braidc ast file.brAST tree
braidc ir file.brSSA IR
braidc ccodegen file.brC source
braidc build file.br -o out.bx.bx bytecode
braidc run file.brExecute

8. Standard Library (Planned)

ModuleContents
std.ioprint, read, file I/O
std.mathMath functions, constants
std.timeDates, timers, Duration
std.asyncAsync runtime, spawn, channels
ui.widgetWidget primitives (Bond)
ui.layoutLayout primitives
ui.renderRendering engine
ui.themeTheming system (Blend)

9. Concurrency Model

Braid's concurrency model is based on green threads (user-space threads managed by the runtime). The spawn keyword creates a new green thread. Communication is via shared memory with ARC safety. Async/await support for cooperative multitasking is planned via std.async. Channels and message passing are also planned.

10. FFI Model

Braid supports two FFI mechanisms:

  • Extern FFI (extern fn): Compile-time linking to C functions. The C codegen backend emits direct C function calls. Types must match C — int maps to int64_t, float to double, string to char*.
  • Native FFI (native fn): Runtime linking to functions built into the BraidVM. Invoked via OP_INVOKE_FFI bytecode instruction. Supports variable argument counts.

11. Related Pages