Language Specification

Formal specification of Hew v0.5.0 — grammar, types, expressions, actors, concurrency, wire types, and FFI.

1. Program Structure

A Hew program is a sequence of items. Each .hew file is a module.

Program    = { Item } ;

Item       = Attribute* Visibility? ( Import | ConstDecl | LetDecl | VarDecl
             | TypeDecl | TraitDecl | ImplDecl | WireDecl | FnDecl
             | ExternBlock | ActorDecl | SupervisorDecl ) ;

Items may be prefixed with attributes and visibility modifiers:

Attribute  = "#[" AttrContent "]" ;
AttrContent = Ident ( "(" AttrArgs ")" )? ;

Visibility = "pub" ( "(" VisScope ")" )? ;
VisScope   = "package" | "super" ;

Visibility levels: pub (public to all), pub(package) (package-private), pub(super) (parent module only), or no modifier (module-private).

2. Module System

Hew uses a file-based module system. Each .hew file is a module named after the file. Directories create nested namespaces. All declarations are private by default.

Import     = "import" ModulePath ( "::" ImportSpec )? ";" ;
ModulePath = Ident { "::" Ident } ;
ImportSpec = Ident
           | "{" Ident { "," Ident } "}"
           | "*" ;
Import syntax
import network::tcp;                         // Import moduleimport network::tcp::Connection;             // Import specific symbolimport network::tcp::{Connection, connect};  // Import multipleimport network::tcp::*;                      // Import all public symbols

3. Declarations

Bindings

let creates immutable bindings, var creates mutable bindings, and const declares compile-time constants. These are binding modes, not ownership annotations.

LetDecl   = "let" Ident ( ":" Type )? "=" Expr ";" ;
VarDecl   = "var" Ident ( ":" Type )? "=" Expr ";" ;
ConstDecl = "const" Ident ":" Type "=" Expr ";" ;
Bindings
let x = 5;          // immutable — cannot reassignvar y = 5;          // mutable — can reassignconst MAX: i32 = 100;  // compile-time constanty = 10;             // ok// x = 10;          // compile error

Functions

FnDecl  = "async"? "fn" Ident TypeParams? "(" Params? ")" RetType? WhereClause? Block ;
Params  = Param { "," Param } ;
Param   = Ident ":" Type ;
RetType = "->" Type ;
Functions
fn add(a: i32, b: i32) -> i32 {    a + b}fn max<T: Ord>(a: T, b: T) -> T {    if a > b { a } else { b }}

Structs and Enums

TypeDecl    = ("struct" | "enum") Ident TypeParams? WhereClause? TypeBody ;
TypeBody    = "{" { FieldDecl | VariantDecl | FnDecl } "}" ;
FieldDecl   = ("let" | "var") Ident ":" Type ("=" Expr)? ";" ;
VariantDecl = Ident ( "(" TypeList ")" | "{" { FieldDecl } "}" )? ";" ;
Structs and enums
struct Point { x: f64, y: f64 }struct Config {    let name: String;     // immutable field    var retries: i32 = 3; // mutable field with default}enum Shape {    Circle(f64);    Rectangle { width: f64, height: f64 };    Unit;}

Generics and Where Clauses

TypeParams     = "<" TypeParam { "," TypeParam } ">" ;
TypeParam      = Ident ( ":" TraitBounds )? ;
TraitBounds    = TraitBound { "+" TraitBound } ;
WhereClause    = "where" WherePredicate { "," WherePredicate } ;
WherePredicate = Type ":" TraitBounds | AssociatedTypeBound ;
Generics
fn merge<K, V>(a: Map<K, V>, b: Map<K, V>) -> Map<K, V>where    K: Hash + Eq + Send,    V: Clone + Send,{    // implementation}

4. Type System

Hew is statically typed with bidirectional type inference. All types are known at compile time.

Built-in Numeric Types

TypeSizeDescription
i8, i16, i32, i641/2/4/8 bytesSigned integers
u8, u16, u32, u641/2/4/8 bytesUnsigned integers
isize, usizeplatformPointer-sized integers
f32, f644/8 bytesIEEE 754 floating point
bool1 byteBoolean (true/false)
char4 bytesUnicode scalar value

All numeric types support explicit conversion methods: .to_i32(), .to_f64(), .to_usize(), etc.

Composite and Reference Types

Type = Ident TypeArgs?
     | "Task" "<" Type ">"                   // Async task
     | "Scope"                               // Structured concurrency scope
     | "ActorRef" "<" Type ">"                // Actor reference
     | "Actor" "<" Type ("," Type)? ">"       // Lambda actor type
     | "Arc" "<" Type ">"                     // Atomic refcount (cross-actor sharing)
     | "Rc" "<" Type ">"                      // Single-actor refcount
     | "Weak" "<" Type ">"                    // Weak reference
     | "Result" "<" Type "," Type ">"
     | "Option" "<" Type ">"
     | "Vec" "<" Type ">"                     // Growable array
     | "HashMap" "<" Type "," Type ">"        // Hash map
     | "(" TypeList? ")"                     // Tuple / Unit
     | "[" Type ";" IntLit "]"               // Fixed array
     | "[" Type "]"                          // Slice
     | "fn" "(" TypeList? ")" RetType?       // Function type
     | "*" "const"? Type                     // Immutable raw pointer
     | "*" "mut" Type                        // Mutable raw pointer
     | "dyn" TraitBound                      // Trait object
     | "dyn" "(" TraitBounds ")" ;

Type Categories

  • Value types (copy): integers, floats, bool, char, small fixed aggregates
  • Owned heap types: String, Vec<T>, Map<K,V>, user struct
  • Shared immutable: Arc<T> where T: Frozen
  • Actor references: ActorRef<A> — always sendable

Sendability Rule

A value may cross an actor boundary only if it satisfies Send. Send is satisfied if the value is a value type, is owned and transferred (move), is Frozen (deeply immutable), or is an actor reference. This is Hew's central compile-time guarantee: no data races without locks.

ContextAliasingMutationBorrow Checking
Within actorUnrestrictedUnrestrictedNone
Across actorsNot allowedN/AMove required

5. Traits

TraitDecl      = "trait" Ident TypeParams? TraitSuper? WhereClause?
                 "{" { TraitItem } "}" ;
TraitSuper     = ":" TraitBounds ;
TraitItem      = FnSig ";" | AssociatedType ;
AssociatedType = "type" Ident ( ":" TraitBounds )? ( "=" Type )? ";" ;

ImplDecl       = "impl" TypeParams? TraitBound "for" Type WhereClause?
                 "{" { FnDecl | AssociatedTypeImpl } "}" ;
Traits and implementations
trait Display {    fn display(self) -> String;}trait Iterator {    type Item;    fn next(self) -> Option<Self::Item>;}struct Point { x: f64, y: f64 }impl Display for Point {    fn display(self) -> String {        f"({self.x}, {self.y})"    }}

Built-in Marker Traits

  • Send — Type can safely cross actor boundaries
  • Frozen — Deeply immutable and safely shareable. Implies Send
  • Copy — Copied on assignment rather than moved (value types only)

Trait Objects

For dynamic dispatch, use dyn Trait. Trait objects are fat pointers (data pointer + vtable pointer). Object-safe traits require self receiver, no Self in return position, and no generic methods.

Trait objects
fn log_anything(item: dyn Display) {    print(item.display());}// Multiple trait boundsfn process(item: dyn(Display + Clone)) {    // ...}

6. Expressions & Operators

Operator Precedence

From highest to lowest:

PrecedenceOperatorsDescription
1 (highest)? .field (args) [index]Postfix
2! - awaitUnary prefix
3* / %Multiplicative
4+ -Additive
5.. ..=Range
6< <= > >=Relational
7== !=Equality
8and / &&Logical AND
9or / ||Logical OR
10| afterTimeout combinator
11<-Send
12 (lowest)= += -= *= /= %=Assignment

Expression Grammar

Expr        = TryExpr | UnsafeExpr | SendExpr ;
TryExpr     = "try" Block ;
UnsafeExpr  = "unsafe" Block ;
SendExpr    = TimeoutExpr ( "<-" Expr )? ;
TimeoutExpr = OrExpr ( "|" "after" Expr )? ;
OrExpr      = AndExpr { ("or" | "||") AndExpr } ;
AndExpr     = EqExpr { ("and" | "&&") EqExpr } ;
EqExpr      = RelExpr { ("==" | "!=") RelExpr } ;
RelExpr     = RangeExpr { ("<" | "<=" | ">" | ">=") RangeExpr } ;
RangeExpr   = AddExpr ( (".." | "..=") AddExpr )? ;
AddExpr     = MulExpr { ("+" | "-") MulExpr } ;
MulExpr     = UnaryExpr { ("*" | "/" | "%") UnaryExpr } ;
UnaryExpr   = ("!" | "-" | "await") UnaryExpr | PostfixExpr ;
PostfixExpr = Primary { "?" | "." Ident | "(" Args? ")" | "[" Expr "]" } ;

Primary Expressions

Primary = Literal
        | InterpolatedStr
        | Ident ( "{" FieldInitList "}" )?   // struct init
        | "[" ExprList? "]"                  // array literal
        | "[" Expr ";" Expr "]"              // array repeat: [0; 256]
        | "(" Expr ")"                       // grouping
        | "(" ExprList ")"                   // tuple
        | IfExpr | MatchExpr | Lambda | Spawn
        | SelectExpr | RaceExpr | JoinExpr
        | ScopeSpawn | ScopeCancel | ScopeCheck | Scope
        | YieldExpr ;

Closures (Lambda Expressions)

Two equivalent syntaxes — pipe and arrow:

Lambda       = "move"? ( PipeLambda | ArrowLambda ) ;
PipeLambda   = "|" LambdaParams? "|" RetType? (Expr | Block) ;
ArrowLambda  = "(" LambdaParams? ")" "=>" (Expr | Block) ;
LambdaParam  = Ident ( ":" Type )? ;
Closures
// Arrow syntaxlet doubled = numbers.map((x) => x * 2);// Pipe syntax (equivalent)let doubled = numbers.map(|x| x * 2);// With type annotationslet f: fn(i32, i32) -> i32 = (x, y) => x + y;// Move capturelet config = load_config();let worker = spawn move (msg: Msg) => { use(config); };

Try and Error Propagation

The ? operator propagates errors from Result types. The try expression catches errors within a scope:

Error handling
fn read_file(path: String) -> Result<String, IoError> {    let handle = open(path)?;   // propagate on error    let content = read(handle)?;    Ok(content)}let result = try {    dangerous_operation()?;    Ok(value)};

7. Statements & Control Flow

Block = "{" { Stmt } Expr? "}" ;

Stmt  = LetStmt | VarStmt | AssignStmt | IfStmt | MatchStmt
      | LoopStmt | ForStmt | WhileStmt
      | BreakStmt | ContinueStmt | ReturnStmt | ExprStmt
      | UnsafeBlock ;

Assignments

AssignStmt = LValue AssignOp Expr ";" ;
AssignOp   = "=" | "+=" | "-=" | "*=" | "/=" | "%=" ;
LValue     = Ident { "." Ident | "[" Expr "]" } ;

Control Flow

IfStmt       = "if" Expr Block ( "else" (IfStmt | Block) )? ;
MatchStmt    = "match" Expr "{" { MatchArm } "}" ;
MatchArm     = Pattern Guard? "=>" (Expr "," | Block) ;
Guard        = "if" Expr ;
LoopStmt     = ("'" Ident ":")? "loop" Block ;
ForStmt      = "for" Pattern "in" Expr Block ;
WhileStmt    = "while" Expr Block ;
BreakStmt    = "break" ("'" Ident)? Expr? ";" ;
ContinueStmt = "continue" ("'" Ident)? ";" ;
ReturnStmt   = "return" Expr? ";" ;

Both if and match are expressions — they return values. Loops support labeled breaks with 'label: syntax.

Control flow
// If expressionlet status = if count > 0 { "active" } else { "idle" };// Match expressionmatch shape {    Circle(r) => 3.14 * r * r,    Rectangle { width, height } => width * height,    Unit => 0.0,}// Labeled loop'outer: loop {    for item in items {        if item.done { break 'outer; }    }}

8. Pattern Matching

Pattern      = "_"                              // wildcard
             | LiteralPattern                     // literal value
             | Ident                              // binding
             | Ident "(" PatternList? ")"         // constructor
             | Ident "{" PatternFieldList? "}"   // struct destructuring
             | "(" PatternList ")"                // tuple
             | Pattern "|" Pattern ;              // or-pattern

PatternField = Ident ( ":" Pattern )? ;
Guard        = "if" Expr ;
Pattern matching
match value {    0 | 1 => println("zero or one"),    n if n < 0 => println("negative"),    n => println(f"positive: {n}"),}// Struct destructuringmatch point {    Point { x: 0, y } => println(f"on y-axis at {y}"),    Point { x, y: 0 } => println(f"on x-axis at {x}"),    Point { x, y } => println(f"({x}, {y})"),}// Nested constructor patternsmatch result {    Ok(Some(value)) => use(value),    Ok(None) => println("empty"),    Err(e) => println(f"error: {e}"),}

9. Actors & Supervisors

Actor Declaration

ActorDecl     = "actor" Ident TypeParams? TraitSuper? WhereClause? "{"
                  ActorInit?
                  MailboxDecl?
                  { FieldDecl | ReceiveFnDecl | FnDecl }
                "}" ;
ActorInit     = "init" "(" Params? ")" Block ;
MailboxDecl   = "mailbox" IntLit ";" ;
ReceiveFnDecl = "receive" "fn" Ident TypeParams? "(" Params? ")" RetType?
                WhereClause? Block ;

receive fn declares a message handler. Without a return type, it is fire-and-forget. With a return type, it is request-response (caller must await). fn declares a private internal method.

Actor
actor Counter {    var count: i32 = 0;    mailbox 256;    // Fire-and-forget: no return type, no await needed    receive fn increment(n: i32) {        self.count += n;    }    // Request-response: has return type, caller must await    receive fn get() -> i32 {        self.count    }    fn validate(n: i32) -> bool { n >= 0 }}let counter = spawn Counter { count: 0 };counter.increment(10);            // fire-and-forgetlet n = await counter.get();      // request-response

Lambda Actors

Spawn       = "spawn" ( LambdaActor | Primary "(" Args? ")" ) ;
LambdaActor = "move"? "(" LambdaParams? ")" RetType? "=>" (Expr | Block) ;

Lambda actors handle a single message type. Use <- to send messages. Captured values must implement Send; use move for ownership transfer.

Lambda actors
// Fire-and-forget lambda actorlet worker = spawn (msg: i32) => { println(msg * 2); };worker <- 42;// Request-response lambda actorlet calc = spawn (x: i32) -> i32 => { x * x };let result = await calc <- 5;// With move capturelet factor = 2;let multiplier = spawn move (x: i32) -> i32 => { x * factor };

Supervisor Declaration

SupervisorDecl = "supervisor" Ident "{" { ChildSpec } "}" ;
ChildSpec      = "child" Ident ":" Ident RestartSpec? ";" ;
RestartSpec    = "restart" "(" ("permanent" | "transient" | "temporary") ")"
                 ("budget" "(" IntLit "," DurationLit ")")?
                 ("strategy" "(" ("one_for_one" | "one_for_all"
                                | "rest_for_one") ")")? ;

Restart classification: permanent (always restart), transient (restart on abnormal exit), temporary (never restart). Exceeding the restart budget escalates failure to the parent supervisor.

Supervisor
supervisor AppSupervisor {    child db: DatabaseActor        restart(permanent)        budget(5, 30.s)        strategy(one_for_one);    child cache: CacheActor        restart(transient);    child logger: LogActor        restart(temporary);}

10. Structured Concurrency

Scope

Scope      = "scope" Block ;
ScopeSpawn = "scope" "." "spawn" Block ;
ScopeCancel = "scope" "." "cancel" "(" ")" ;
ScopeCheck = "scope" "." ("is_cancelled" | "check_cancelled") "(" ")" ;
YieldExpr  = "yield" ;

A scope block creates a structured concurrency boundary. All tasks spawned within it must complete before the scope exits. Tasks are cooperatively scheduled within the actor's single thread.

Scope and tasks
scope {    let a = scope.spawn { fetch_user(id1) };    let b = scope.spawn { fetch_user(id2) };    // Both run concurrently    let user1 = await a;    let user2 = await b;    merge_users(user1, user2)}

Select Expression

Waits for the first of several async operations to complete. Remaining operations are cancelled.

SelectExpr = "select" "{" SelectArm { SelectArm } "}" ;
SelectArm  = Ident "from" Expr "=>" Expr ","
           | "after" Expr "=>" Expr "," ;
Select
let result = select {    count from counter.get_count() => count * 2,    data from worker.get_data() => data.len,    after 1.seconds => -1,};

Race Expression

Spawns all branches concurrently and returns the first to complete. All expressions must have the same type.

RaceExpr = "race" "{" (Expr ",")+ ("after" Expr "=>" Expr ",")? "}" ;
Race
let fastest = race {    server1.fetch(key),    server2.fetch(key),    server3.fetch(key),    after 5.seconds => Err(Timeout),};

Join Expression

Runs all branches concurrently and waits for all to complete. Result is a tuple. Each branch may have a different type.

JoinExpr = "join" "{" Expr { "," Expr } ","? "}" ;
Join
let (users, posts, stats) = join {    db.fetch_users(),    db.fetch_posts(),    analytics.get_stats(),};

Timeout Combinator

The | after combinator wraps an individual await in a Result<T, Timeout>:

Timeout
let result = await counter.get_count() | after 1.seconds;// result: Result<i32, Timeout>

11. Wire Types

Wire types define network-serializable data with stable field tags, explicit optionality, and forward/backward compatibility guarantees.

WireDecl      = "wire" ("struct" | "enum") Ident WireBody ;
WireBody      = "{" { WireFieldDecl | VariantDecl } "}" ;
WireFieldDecl = Ident ":" WireType "@" IntLit WireAttr* ";" ;
WireAttr      = "optional" | "deprecated"
              | "default" "(" Expr ")" | ReservedDecl ;
ReservedDecl  = "reserved" "(" IntLit { "," IntLit } ")" ;

WireType      = "u8" | "u16" | "u32" | "u64"
              | "i8" | "i16" | "i32" | "i64"
              | "f32" | "f64"
              | "bool" | "bytes" | "string"
              | Ident | "list" "[" WireType "]" ;
Wire types
wire struct User {    name: string @1;    email: string @2;    age: u32 @3 optional;    role: Role @4 default(Role::Member);    reserved(5, 6);  // deleted fields}wire enum Role {    Admin;    Member;    Guest;}

Compatibility rules: field tag numbers must never be reused. Deleted fields must have their tags reserved. Wire types support Hew Binary Format (HBF) and JSON encoding.

12. Foreign Function Interface

ExternBlock  = ("foreign" | "extern") StringLit "{" { ExternFnDecl } "}" ;
ExternFnDecl = "fn" Ident "(" ExternParams? ")" RetType? Variadic? ";" ;
Variadic     = "..." ;

ExternFnExport = "#[" "export" ( "(" StringLit ")" )? "]" ExternFnDef ;
ExternFnDef    = "foreign" StringLit "fn" Ident "(" Params? ")" RetType? Block ;

UnsafeBlock = "unsafe" Block ;

All FFI calls are unsafe. Use safe wrapper patterns to expose a safe public API. C-compatible struct layout is specified with #[repr(C)].

FFI
foreign "C" {    fn malloc(size: usize) -> *mut u8;    fn free(ptr: *mut u8);    fn printf(fmt: *const u8, ...) -> i32;}fn allocate(size: usize) -> *mut u8 {    unsafe { malloc(size) }}#[export("hew_process")]foreign "C" fn process(data: *const u8, len: usize) -> i32 {    // callable from C as hew_process()}

Type Mapping: Hew to C

Hew TypeC Type
i8...i64int8_t...int64_t
u8...u64uint8_t...uint64_t
isize / usizessize_t / size_t
f32 / f64float / double
bool_Bool
*T / *mut Tconst T* / T*
fn(...) -> TFunction pointer

13. Literals & Lexical Elements

Comments

Comment      = LineComment | BlockComment | DocComment ;
LineComment  = "//" { AnyChar } Newline ;
BlockComment = "/*" { AnyChar } "*/" ;
DocComment   = "///" { AnyChar } Newline ;

Literals

Literal         = IntLit | FloatLit | StringLit | "true" | "false" ;
DurationLit     = IntLit ("ns" | "us" | "ms" | "s" | "m" | "h") ;
IntLit          = Digit { Digit | "_" }
                | "0x" HexDigit { HexDigit | "_" }
                | "0b" BinDigit { BinDigit | "_" } ;
FloatLit        = Digit { Digit } "." Digit { Digit }
                  ( ("e"|"E") ("+"|"-")? Digit { Digit } )? ;
StringLit       = '"' { Char | EscapeSeq } '"'
                | 'r"' { AnyChar } '"' ;
InterpolatedStr = 'f"' { Char | "{" Expr "}" } '"' ;
EscapeSeq       = "\\" ( "n" | "r" | "t" | "\\" | '"' | "0"
                       | "x" HexDigit HexDigit ) ;
Literals
// Integerslet dec = 1_000_000;let hex = 0xFF;let bin = 0b1010;// Floatslet pi = 3.14;let sci = 1.5e10;// Stringslet s = "hello\nworld";let raw = r"no escapes here";let interp = f"count is {count + 1}";// Durationslet timeout = 500.ms;let interval = 1.s;let budget = 30.s;

Identifiers

Ident    = Letter { Letter | Digit | "_" } ;
Letter   = "a".."z" | "A".."Z" ;
Digit    = "0".."9" ;
HexDigit = Digit | "a".."f" | "A".."F" ;
BinDigit = "0" | "1" ;

14. Full EBNF Grammar

The complete v0.5.0 EBNF grammar for reference. This covers the full Hew syntax including modules, traits, closures, pattern matching, control flow, structured concurrency, actor messaging, concurrency expressions, FFI, and where clauses.

Hew EBNF Grammar v0.5.0
(* Comments *)
Comment        = LineComment | BlockComment | DocComment ;
LineComment    = "//" { AnyChar } Newline ;
BlockComment   = "/*" { AnyChar } "*/" ;
DocComment     = "///" { AnyChar } Newline ;

(* Program structure *)
Program        = { Item } ;

Item           = Attribute* Visibility? ( Import
                             | ConstDecl
                             | LetDecl
                             | VarDecl
                             | TypeDecl
                             | TraitDecl
                             | ImplDecl
                             | WireDecl
                             | FnDecl
                             | ExternBlock
                             | ActorDecl
                             | SupervisorDecl ) ;

(* Module-level bindings *)
LetDecl        = "let" Ident ( ":" Type )? "=" Expr ";" ;
VarDecl        = "var" Ident ( ":" Type )? "=" Expr ";" ;

Visibility     = "pub" ( "(" VisScope ")" )? ;
VisScope       = "package" | "super" ;

(* Attributes *)
Attribute      = "#[" AttrContent "]" ;
AttrContent    = Ident ( "(" AttrArgs ")" )? ;
AttrArgs       = AttrArg { "," AttrArg } ;
AttrArg        = Ident | StringLit | Ident "=" (StringLit | Ident) ;

(* Module system *)
Import         = "import" ModulePath ( "::" ImportSpec )? ";" ;
ModulePath     = Ident { "::" Ident } ;
ImportSpec     = Ident
               | "{" Ident { "," Ident } "}"
               | "*" ;

(* Constants and types *)
ConstDecl      = "const" Ident ":" Type "=" Expr ";" ;

TypeDecl       = ("struct" | "enum") Ident TypeParams? WhereClause? TypeBody ;
WireDecl       = "wire" ("struct" | "enum") Ident WireBody ;

TypeParams     = "<" TypeParam { "," TypeParam } ">" ;
TypeParam      = Ident ( ":" TraitBounds )? ;
TraitBounds    = TraitBound { "+" TraitBound } ;
TraitBound     = Ident TypeArgs? ;

WhereClause    = "where" WherePredicate { "," WherePredicate } ;
WherePredicate = Type ":" TraitBounds
               | AssociatedTypeBound ;
AssociatedTypeBound = Type "::" Ident ":" TraitBounds ;

TypeBody       = "{" { FieldDecl | VariantDecl | FnDecl } "}" ;
WireBody       = "{" { WireFieldDecl | VariantDecl } "}" ;

FieldDecl      = ("let" | "var") Ident ":" Type ("=" Expr)? ";" ;
WireFieldDecl  = Ident ":" WireType "@" IntLit WireAttr* ";" ;
WireAttr       = "optional" | "deprecated"
               | ("default" "(" Expr ")") | ReservedDecl ;
ReservedDecl   = "reserved" "(" IntLit { "," IntLit } ")" ;

VariantDecl    = Ident ( "(" TypeList ")" | "{" { FieldDecl } "}" )? ";" ;
TypeList       = Type { "," Type } ;

(* Traits *)
TraitDecl      = "trait" Ident TypeParams? TraitSuper? WhereClause?
                 "{" { TraitItem } "}" ;
TraitSuper     = ":" TraitBounds ;
TraitItem      = FnSig ";"
               | AssociatedType ;
AssociatedType = "type" Ident ( ":" TraitBounds )? ( "=" Type )? ";" ;
FnSig          = "fn" Ident TypeParams? "(" Params? ")" RetType? WhereClause? ;

ImplDecl       = "impl" TypeParams? TraitBound "for" Type WhereClause?
                 "{" { FnDecl | AssociatedTypeImpl } "}" ;
AssociatedTypeImpl = "type" Ident "=" Type ";" ;

(* Actors *)
ActorDecl      = "actor" Ident TypeParams? TraitSuper? WhereClause? "{"
                   ActorInit?
                   MailboxDecl?
                   { FieldDecl | ReceiveFnDecl | FnDecl }
                 "}" ;
ActorInit      = "init" "(" Params? ")" Block ;
MailboxDecl    = "mailbox" IntLit ";" ;
ReceiveFnDecl  = "receive" "fn" Ident TypeParams? "(" Params? ")"
                 RetType? WhereClause? Block ;

(* Supervisors *)
SupervisorDecl = "supervisor" Ident "{" { ChildSpec } "}" ;
ChildSpec      = "child" Ident ":" Ident RestartSpec? ";" ;
RestartSpec    = "restart" "(" ("permanent" | "transient" | "temporary") ")"
                 ("budget" "(" IntLit "," DurationLit ")")?
                 ("strategy" "(" ("one_for_one" | "one_for_all"
                                | "rest_for_one") ")")? ;

(* FFI / Extern declarations *)
ExternBlock    = ("foreign" | "extern") StringLit "{" { ExternFnDecl } "}" ;
ExternFnDecl   = "fn" Ident "(" ExternParams? ")" RetType? Variadic? ";" ;
ExternParams   = ExternParam { "," ExternParam } ;
ExternParam    = Ident ":" Type ;
Variadic       = "..." ;

ExternFnExport = "#[" "export" ( "(" StringLit ")" )? "]" ExternFnDef ;
ExternFnDef    = "foreign" StringLit "fn" Ident "(" Params? ")" RetType? Block ;

(* Functions *)
FnDecl         = "async"? "fn" Ident TypeParams? "(" Params? ")"
                 RetType? WhereClause? Block ;
Params         = Param { "," Param } ;
Param          = Ident ":" Type ;
RetType        = "->" Type ;

(* Unsafe blocks *)
UnsafeBlock    = "unsafe" Block ;

(* Statements *)
Block          = "{" { Stmt } Expr? "}" ;

Stmt           = LetStmt | VarStmt | AssignStmt | IfStmt | MatchStmt
               | LoopStmt | ForStmt | WhileStmt
               | BreakStmt | ContinueStmt | ReturnStmt | ExprStmt
               | UnsafeBlock ;

LetStmt        = "let" Pattern ( ":" Type )? "=" Expr ";" ;
VarStmt        = "var" Ident ( ":" Type )? "=" Expr ";" ;
AssignStmt     = LValue AssignOp Expr ";" ;
AssignOp       = "=" | "+=" | "-=" | "*=" | "/=" | "%=" ;
LValue         = Ident { "." Ident | "[" Expr "]" } ;

IfStmt         = "if" Expr Block ( "else" (IfStmt | Block) )? ;
MatchStmt      = "match" Expr "{" { MatchArm } "}" ;
MatchArm       = Pattern Guard? "=>" (Expr "," | Block) ;
Guard          = "if" Expr ;

LoopStmt       = ("'" Ident ":")? "loop" Block ;
ForStmt        = "for" Pattern "in" Expr Block ;
WhileStmt      = "while" Expr Block ;
BreakStmt      = "break" ("'" Ident)? Expr? ";" ;
ContinueStmt   = "continue" ("'" Ident)? ";" ;
ReturnStmt     = "return" Expr? ";" ;
ExprStmt       = Expr ";" ;

(* Expressions *)
Expr           = TryExpr | UnsafeExpr | SendExpr ;
TryExpr        = "try" Block ;
UnsafeExpr     = "unsafe" Block ;
SendExpr       = TimeoutExpr ( "<-" Expr )? ;
TimeoutExpr    = OrExpr ( "|" "after" Expr )? ;
OrExpr         = AndExpr { ("or" | "||") AndExpr } ;
AndExpr        = EqExpr  { ("and" | "&&") EqExpr } ;
EqExpr         = RelExpr { ("==" | "!=") RelExpr } ;
RelExpr        = RangeExpr { ("<" | "<=" | ">" | ">=") RangeExpr } ;
RangeExpr      = AddExpr ( (".." | "..=") AddExpr )? ;
AddExpr        = MulExpr { ("+" | "-") MulExpr } ;
MulExpr        = UnaryExpr { ("*" | "/" | "%") UnaryExpr } ;
UnaryExpr      = ("!" | "-" | "await") UnaryExpr | PostfixExpr ;
PostfixExpr    = Primary { "?" | "." Ident | "(" Args? ")" | "[" Expr "]" } ;

Primary        = Literal
               | InterpolatedStr
               | Ident ( "{" FieldInitList "}" )?
               | "[" ExprList? "]"
               | "[" Expr ";" Expr "]"
               | "(" Expr ")"
               | "(" ExprList ")"
               | IfExpr
               | MatchExpr
               | Lambda
               | Spawn
               | SelectExpr
               | RaceExpr
               | JoinExpr
               | ScopeSpawn
               | ScopeCancel
               | ScopeCheck
               | Scope
               | YieldExpr ;

FieldInitList  = FieldInit { "," FieldInit } ","? ;
FieldInit      = Ident ":" Expr ;

IfExpr         = "if" Expr Block ( "else" (IfExpr | Block) )? ;
MatchExpr      = "match" Expr "{" { MatchArm } "}" ;

Literal        = IntLit | FloatLit | StringLit | "true" | "false" ;
ExprList       = Expr { "," Expr } ;
Args           = Expr { "," Expr } ;

(* Closures *)
Lambda         = "move"? ( PipeLambda | ArrowLambda ) ;
PipeLambda     = "|" LambdaParams? "|" RetType? (Expr | Block) ;
ArrowLambda    = "(" LambdaParams? ")" "=>" (Expr | Block) ;
LambdaParams   = LambdaParam { "," LambdaParam } ;
LambdaParam    = Ident ( ":" Type )? ;

(* Actor operations *)
Spawn          = "spawn" ( LambdaActor | (Primary "(" Args? ")") ) ;
LambdaActor    = "move"? "(" LambdaParams? ")" RetType? "=>" (Expr | Block) ;

(* Concurrency expressions *)
SelectExpr     = "select" "{" SelectArm { SelectArm } "}" ;
SelectArm      = Ident "from" Expr "=>" Expr ","
               | "after" Expr "=>" Expr "," ;

RaceExpr       = "race" "{" (Expr ",")+ ("after" Expr "=>" Expr ",")? "}" ;

JoinExpr       = "join" "{" Expr { "," Expr } ","? "}" ;

(* Structured concurrency *)
Scope          = "scope" Block ;
ScopeSpawn     = "scope" "." "spawn" Block ;
ScopeCancel    = "scope" "." "cancel" "(" ")" ;
ScopeCheck     = "scope" "." ("is_cancelled" | "check_cancelled") "(" ")" ;
YieldExpr      = "yield" ;

(* Types *)
Type           = Ident TypeArgs?
               | "Task" "<" Type ">"
               | "Scope"
               | "ActorRef" "<" Type ">"
               | "Actor" "<" Type ("," Type)? ">"
               | "Arc" "<" Type ">"
               | "Rc" "<" Type ">"
               | "Weak" "<" Type ">"
               | "Result" "<" Type "," Type ">"
               | "Option" "<" Type ">"
               | "Vec" "<" Type ">"
               | "HashMap" "<" Type "," Type ">"
               | "(" TypeList? ")"
               | "[" Type ";" IntLit "]"
               | "[" Type "]"
               | "fn" "(" TypeList? ")" RetType?
               | "*" "const"? Type
               | "*" "mut" Type
               | "dyn" TraitBound
               | "dyn" "(" TraitBounds ")" ;

TypeArgs       = "<" Type { "," Type } ">" ;

(* Wire types *)
WireType       = "u8" | "u16" | "u32" | "u64"
               | "i8" | "i16" | "i32" | "i64"
               | "f32" | "f64"
               | "bool" | "bytes" | "string"
               | Ident | ("list" "[" WireType "]") ;

(* Pattern matching *)
Pattern        = "_"
               | LiteralPattern
               | Ident
               | Ident "(" PatternList? ")"
               | Ident "{" PatternFieldList? "}"
               | "(" PatternList ")"
               | Pattern "|" Pattern ;

LiteralPattern = IntLit | FloatLit | StringLit | "true" | "false" ;
PatternList    = Pattern { "," Pattern } ;
PatternFieldList = PatternField { "," PatternField } ;
PatternField   = Ident ( ":" Pattern )? ;

(* Literals *)
DurationLit    = IntLit ("ns" | "us" | "ms" | "s" | "m" | "h") ;
IntLit         = Digit { Digit | "_" }
               | "0x" HexDigit { HexDigit | "_" }
               | "0b" BinDigit { BinDigit | "_" } ;
FloatLit       = Digit { Digit } "." Digit { Digit }
                 ( ("e" | "E") ("+" | "-")? Digit { Digit } )? ;
StringLit      = '"' { Char | EscapeSeq } '"'
               | 'r"' { AnyChar } '"' ;
InterpolatedStr = 'f"' { Char | "{" Expr "}" } '"' ;

Ident          = Letter { Letter | Digit | "_" } ;
Letter         = "a".."z" | "A".."Z" ;
Digit          = "0".."9" ;
HexDigit       = Digit | "a".."f" | "A".."F" ;
BinDigit       = "0" | "1" ;
EscapeSeq      = "\\" ( "n" | "r" | "t" | "\\" | '"' | "0"
                        | "x" HexDigit HexDigit ) ;