Language Specification
Formal specification of Hew v0.2.0 — grammar, types, expressions, actors, concurrency, wire types, and FFI.
Contents
1. Program Structure
A Hew program is a sequence of items. Each .hew file is a module.
Program = { Item } ;
Item = Attribute* Visibility? ( Import | ConstDecl
| TypeDecl | TraitDecl | ImplDecl | WireDecl | FnDecl
| GenFnDecl | AsyncGenFnDecl | 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 network::tcp; // Import module
import network::tcp::Connection; // Import specific symbol
import network::tcp::{Connection, connect}; // Import multiple
import network::tcp::*; // Import all public symbols3. 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 ";" ;let x = 5; // immutable — cannot reassign
var y = 5; // mutable — can reassign
const MAX: i32 = 100; // compile-time constant
y = 10; // ok
// x = 10; // compile errorFunctions
FnDecl = "fn" Ident TypeParams? "(" Params? ")" RetType? WhereClause? Block ;
Params = Param { "," Param } ;
Param = Ident ":" Type ;
RetType = "->" Type ;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 = ("type" | "enum") Ident TypeParams? WhereClause? TypeBody ;
TypeBody = "{" { StructFieldDecl | VariantDecl | FnDecl } "}" ;
StructFieldDecl = Ident ":" Type ("," | ";") ;
ActorFieldDecl = ("let" | "var") Ident ":" Type ("=" Expr)? ";" ;
VariantDecl = Ident ( "(" TypeList ")" | "{" { StructFieldDecl } "}" )? "," ;type Point { x: f64; y: f64; }
type Config {
name: String; // immutable field (default)
var retries: i32; // mutable field
}
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 ;fn merge<K, V>(a: HashMap<K, V>, b: HashMap<K, V>) -> HashMap<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
| Type | Size | Description |
|---|---|---|
i8, i16, i32, i64 | 1/2/4/8 bytes | Signed integers |
u8, u16, u32, u64 | 1/2/4/8 bytes | Unsigned integers |
isize, usize | platform | Pointer-sized integers |
f32, f64 | 4/8 bytes | IEEE 754 floating point |
bool | 1 byte | Boolean (true/false) |
char | 4 bytes | Unicode 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 ">"
| "Generator" "<" Type ">" // Sync generator
| "AsyncGenerator" "<" Type ">" // Async generator
| "Stream" "<" Type ">" // First-class readable stream
| "Sink" "<" Type ">" // First-class writable sink
| "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 ")" // Multiple trait object
| "_" ; // Infer type from contextType Categories
- Value types (copy): integers, floats, bool, char, small fixed aggregates
- Owned heap types:
String,Vec<T>,HashMap<K,V>, user-defined types - Shared immutable:
Arc<T>whereT: 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.
| Context | Aliasing | Mutation | Borrow Checking |
|---|---|---|---|
| Within actor | Unrestricted | Unrestricted | None |
| Across actors | Not allowed | N/A | Move 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 } "}" ;trait Display {
fn display(self) -> String;
}
trait Iterator {
type Item;
fn next(it: Self) -> Option<Self::Item>;
}
type Point { x: f64; y: f64; }
impl Display for Point {
fn display(p: Point) -> String {
f"({p.x}, {p.y})"
}
}Built-in Marker Traits
Send— Type can safely cross actor boundariesFrozen— Deeply immutable and safely shareable. ImpliesSendCopy— 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.
fn log_anything(item: dyn Display) {
print(item.display());
}
// Multiple trait bounds
fn process(item: dyn(Display + Clone)) {
// ...
}6. Expressions & Operators
Operator Precedence
From highest to lowest:
| Precedence | Operators | Description |
|---|---|---|
| 1 (highest) | ? .field (args) [index] | Postfix |
| 2 | ! - ~ await | Unary prefix |
| 3 | * / % | Multiplicative |
| 4 | + - | Additive |
| 5 | << >> | Shift |
| 6 | .. ..= | Range |
| 7 | < <= > >= | Relational |
| 8 | == != =~ !~ | Equality / Match |
| 9 | && | Logical AND |
| 10 | & | Bitwise AND |
| 11 | ^ | Bitwise XOR |
| 12 | | | Bitwise OR |
| 13 | || | Logical OR |
| 14 | | after | Timeout combinator |
| 15 | <- | Send |
| 16 (lowest) | = += -= *= /= %= | Assignment |
Expression Grammar
Expr = UnsafeExpr | SendExpr ;
UnsafeExpr = "unsafe" Block ;
SendExpr = TimeoutExpr ( "<-" Expr )? ;
TimeoutExpr = OrExpr ( "|" "after" Expr )? ;
OrExpr = BitOrExpr { "||" BitOrExpr } ;
BitOrExpr = BitXorExpr { "|" BitXorExpr } ;
BitXorExpr = BitAndExpr { "^" BitAndExpr } ;
BitAndExpr = AndExpr { "&" AndExpr } ;
AndExpr = EqExpr { "&&" EqExpr } ;
EqExpr = RelExpr { ("==" | "!=" | "=~" | "!~") RelExpr } ;
RelExpr = RangeExpr { ("<" | "<=" | ">" | ">=") RangeExpr } ;
RangeExpr = ShiftExpr ( (".." | "..=") ShiftExpr )? ;
ShiftExpr = AddExpr { ("<<" | ">>") AddExpr } ;
AddExpr = MulExpr { ("+" | "-") MulExpr } ;
MulExpr = UnaryExpr { ("*" | "/" | "%") UnaryExpr } ;
UnaryExpr = ("!" | "-" | "~" | "await") UnaryExpr | PostfixExpr ;
PostfixExpr = Primary { "?" | "." Ident | "(" Args? ")" | "[" Expr "]" } ;Primary Expressions
Primary = Literal
| InterpolatedStr
| Ident ( "{" FieldInitList "}" )? // type init: Point { x: 1, y: 2 }
| "[" ExprList? "]" // array literal
| "[" Expr ";" Expr "]" // array repeat: [0; 256]
| "(" Expr ")" // grouping
| "(" ExprList ")" // tuple
| IfExpr | MatchExpr | Lambda | Spawn
| SelectExpr | JoinExpr
| Scope
| CooperateExpr | YieldExpr ;Closures (Lambda Expressions)
Arrow syntax for closures (pipe syntax |x| was removed in v0.2.0):
Lambda = "move"? "(" LambdaParams? ")" "=>" RetType? (Expr | Block) ;
LambdaParams = LambdaParam { "," LambdaParam } ;
LambdaParam = Ident ( ":" Type )? ;// Arrow syntax
let doubled = numbers.map((x) => x * 2);
// With type annotations
let f: fn(i32, i32) -> i32 = (x, y) => x + y;
// Move capture
let config = load_config();
let worker = spawn move (msg: Msg) => { use(config); };Error Propagation
The ? operator propagates errors from Result types. Functions return Result<T, E> and use ? for early return on error:
fn read_file(path: String) -> Result<String, IoError> {
let handle = open(path)?; // propagate on error
let content = read(handle)?;
Ok(content)
}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" "await"? 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.
// If expression
let status = if count > 0 { "active" } else { "idle" };
// Match expression
match 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 ;match value {
0 | 1 => println("zero or one"),
n if n < 0 => println("negative"),
n => println(f"positive: {n}"),
}
// Struct destructuring
match 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 patterns
match 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?
{ ActorFieldDecl | ReceiveFnDecl | ReceiveGenFnDecl | FnDecl | GenFnDecl }
"}" ;
ActorInit = "init" "(" Params? ")" Block ;
MailboxDecl = "mailbox" IntLit OverflowPolicy? ";" ;
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 Counter {
var count: i32 = 0;
mailbox 256;
// Fire-and-forget: no return type, no await needed
receive fn increment(n: i32) {
count += n;
}
// Request-response: has return type, caller must await
receive fn get() -> i32 {
count
}
fn validate(n: i32) -> bool { n >= 0 }
}
let counter = spawn Counter(count: 0);
counter.increment(10); // fire-and-forget
let n = (await counter.get())?; // request-responseLambda Actors
Spawn = "spawn" ( LambdaActor | ActorSpawn ) ;
ActorSpawn = Ident TypeArgs? "(" FieldInitList? ")" ; // Named fields
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.
// Fire-and-forget lambda actor
let worker = spawn (msg: i32) => { println(msg * 2); };
worker <- 42;
// Request-response lambda actor
let calc = spawn (x: i32) -> i32 => { x * x };
let result = (await calc <- 5)?;
// With move capture
let 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 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" ( "|" Ident "|" )? Block ;
(* Inside scope |s| { ... }, the binding s supports:
s.launch { expr } — launch a concurrent task, returns Task<T>
s.cancel() — request cancellation of all tasks
s.is_cancelled() — check cancellation state *)
CooperateExpr = "cooperate" ;
YieldExpr = "yield" Expr ;A scope block creates a structured concurrency boundary. All tasks launched within it must complete before the scope exits. Tasks are cooperatively scheduled within the actor's single thread. Use scope |s| { ... } to bind the scope handle to s.
scope |s| {
let a = s.launch { fetch_user(id1) };
let b = s.launch { 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 } TimeoutArm? "}" ;
SelectArm = Pattern ("from" | "<-") Expr "=>" Expr ","?
| "after" Expr "=>" Expr "," ;let result = select {
count from counter.get_count() => count * 2,
data from worker.get_data() => data.len,
after 1.seconds => -1,
};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 } ","? "}" ;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>:
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.
(* Struct-level attributes: #[json(NamingCase)] / #[yaml(NamingCase)] *)
NamingCase = "camelCase" | "PascalCase" | "snake_case"
| "SCREAMING_SNAKE" | "kebab-case" ;
WireDecl = "wire" ("type" | "enum") Ident WireBody ;
WireBody = "{" { WireFieldDecl | VariantDecl } "}" ;
WireFieldDecl = Ident ":" Type "@" IntLit WireAttr* ";" ;
WireAttr = "optional" | "deprecated" | "repeated"
| "default" "(" Expr ")"
| "json" "(" StringLit ")"
| "yaml" "(" StringLit ")"
| ReservedDecl ;
ReservedDecl = "reserved" "(" IntLit { "," IntLit } ")" ;#[json(camelCase)]
#[yaml(snake_case)]
wire type User {
name: String @1;
email: String @2;
age: u32 @3 optional;
role: Role @4 default(Role::Member);
// per-field key override:
user_id: u64 @5 json("id") yaml("id");
reserved(6, 7); // deleted fields
}
wire enum Role {
Admin;
Member;
Guest;
}Compatibility rules: field tag numbers must never be reused. Deleted fields must have their tags reserved.
Serialization: Wire types support Hew Binary Format (HBF) for compact binary encoding and JSON/YAML for interoperability. The compiler generates four functions per wire type:
// Generated automatically — no boilerplate needed
User_to_json(name, email, age, role, user_id) -> String
User_from_json(json: String) -> User
User_to_yaml(name, email, age, role, user_id) -> String
User_from_yaml(yaml: String) -> User
// Example:
let json = User_to_json("Alice", "alice@example.com", 30, Role::Member, 1);
// → {"age":30,"email":"alice@example.com","id":1,"name":"Alice","role":0}The struct-level #[json(NamingCase)] attribute sets the default key casing for all fields (e.g. user_id → userId with camelCase). Per-field json("key") attributes override the default for individual fields.
12. Foreign Function Interface
ExternBlock = "extern" StringLit? "{" { ExternFnDecl } "}" ;
ExternFnDecl = "fn" Ident "(" ExternParams? ")" RetType? Variadic? ";" ;
Variadic = ".." ;
ExternFnExport = "#[" "export" ( "(" StringLit ")" )? "]" ExternFnDef ;
ExternFnDef = "extern" 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)].
extern "C" {
fn malloc(size: usize) -> *var u8;
fn free(ptr: *var u8);
fn printf(fmt: *u8, ...) -> i32;
}
fn allocate(size: usize) -> *var u8 {
unsafe { malloc(size) }
}
#[export("hew_process")]
extern "C" fn process(data: *u8, len: usize) -> i32 {
// callable from C as hew_process()
}Type Mapping: Hew to C
| Hew Type | C Type |
|---|---|
i8...i64 | int8_t...int64_t |
u8...u64 | uint8_t...uint64_t |
isize / usize | ssize_t / size_t |
f32 / f64 | float / double |
bool | _Bool |
*T / *var T | const T* / T* |
fn(...) -> T | Function 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 ) ;// Integers
let dec = 1_000_000;
let hex = 0xFF;
let bin = 0b1010;
// Floats
let pi = 3.14;
let sci = 1.5e10;
// Strings
let s = "hello\nworld";
let raw = r"no escapes here";
let interp = f"count is {count + 1}";
// Durations
let 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.2.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 Programming Language — Formal Grammar (EBNF)
Version: 0.2.0
This is the authoritative grammar specification for the Hew
programming language. It is extracted from and kept in sync
with the full language specification at docs/specs/HEW-SPEC.md.
Notation follows ISO 14977 EBNF:
{ ... } — repetition (zero or more)
[ ... ] — optional (zero or one)
( ... ) — grouping
| — alternation
"..." — terminal string
(* ... *) — comment
============================================================ *)
(* Comments *)
Comment = LineComment | BlockComment | DocComment ;
LineComment = "//" { AnyChar } Newline ;
BlockComment = "/*" { AnyChar } "*/" ;
DocComment = "///" { AnyChar } Newline ;
(* Program structure *)
Program = { Item } ;
Item = Attribute* Visibility? ( Import
| ConstDecl
| TypeDecl
| TraitDecl
| ImplDecl
| WireDecl
| FnDecl
| GenFnDecl
| AsyncGenFnDecl
| ExternBlock
| ActorDecl
| SupervisorDecl ) ;
Visibility = "pub" ( "(" VisScope ")" )? ;
VisScope = "package" | "super" ;
(* Attributes *)
Attribute = "#[" AttrContent "]" ;
AttrContent = Ident ( "(" AttrArgs ")" )? ;
AttrArgs = AttrArg { "," AttrArg } ;
AttrArg = Ident ( "=" (StringLit | Ident) )?
| StringLit ;
(* Module system *)
Import = "import" ( StringLit | ModulePath ( "::" ImportSpec )? ) ";" ;
ModulePath = Ident { "::" Ident } ;
ImportSpec = Ident
| "{" Ident { "," Ident } "}"
| "*" ;
(* Constants and types *)
ConstDecl = "const" Ident ":" Type "=" Expr ";" ;
TypeDecl = ("type" | "enum") Ident TypeParams? WhereClause? TypeBody ;
(* Struct-level naming: #[json(camelCase)] / #[yaml(snake_case)] before wire decl *)
(* Valid naming conventions: camelCase, PascalCase, snake_case, SCREAMING_SNAKE, kebab-case *)
WireDecl = "wire" ("type" | "enum") Ident WireBody ;
TypeParams = "<" TypeParam { "," TypeParam } ">" ;
TypeParam = Ident ( ":" TraitBounds )? ;
TraitBounds = TraitBound { "+" TraitBound } ;
TraitBound = Ident TypeArgs? ;
(* Where clauses for complex bounds *)
WhereClause = "where" WherePredicate { "," WherePredicate } ;
WherePredicate = Type ":" TraitBounds
| AssociatedTypeBound ;
AssociatedTypeBound = Type "::" Ident ":" TraitBounds ;
TypeBody = "{" { StructFieldDecl | VariantDecl | FnDecl } "}" ;
WireBody = "{" { WireFieldDecl | VariantDecl } "}" ;
StructFieldDecl = Ident ":" Type ("," | ";") ;
ActorFieldDecl = ("let" | "var") Ident ":" Type ("=" Expr)? ";" ;
WireFieldDecl = Ident ":" Type "@" IntLit WireAttr* ";" ;
WireAttr = "optional" | "deprecated" | "repeated"
| ("default" "(" Expr ")") (* not yet implemented *)
| "json" "(" StringLit ")" (* per-field JSON key override *)
| "yaml" "(" StringLit ")" (* per-field YAML key override *)
| ReservedDecl ;
ReservedDecl = "reserved" "(" IntLit { "," IntLit } ")" ;
VariantDecl = Ident ( "(" TypeList ")" | "{" { StructFieldDecl } "}" )? ("," | ";") ;
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? "(" (SelfParam ("," Params)? | Params)? ")" RetType? WhereClause? ;
SelfParam = "self" ;
ImplDecl = "impl" TypeParams? TraitBound "for" Type WhereClause? "{" { FnDecl | AssociatedTypeImpl } "}" ;
AssociatedTypeImpl = "type" Ident "=" Type ";" ;
(* Actors *)
ActorDecl = "actor" Ident TraitSuper? "{"
ActorInit?
MailboxDecl?
{ ActorFieldDecl | ReceiveFnDecl | ReceiveGenFnDecl | FnDecl | GenFnDecl }
"}" ;
ActorInit = "init" "(" Params? ")" Block ;
MailboxDecl = "mailbox" IntLit OverflowPolicy? ";" ;
OverflowPolicy = "overflow" OverflowKind ;
OverflowKind = "block" | "drop_new" | "drop_old" | "fail"
| "coalesce" "(" Ident ")" CoalesceFallback? ;
CoalesceFallback = "fallback" OverflowKind ;
ReceiveFnDecl = "receive" "fn" Ident TypeParams? "(" Params? ")" RetType? WhereClause? Block ;
ReceiveGenFnDecl = "receive" "gen" "fn" Ident TypeParams? "(" Params? ")" "->" Type WhereClause? Block ;
(* Supervisors *)
SupervisorDecl = "supervisor" Ident "{"
{ SupervisorField | ChildSpec }
"}" ;
SupervisorField = "strategy" ":" SupervisorStrategy
| "max_restarts" ":" IntLit
| "window" ":" IntLit ;
SupervisorStrategy = "one_for_one" | "one_for_all" | "rest_for_one" ;
ChildSpec = "child" Ident ":" Ident ( "(" Args ")" )? RestartPolicy? ;
RestartPolicy = "permanent" | "transient" | "temporary" ;
(* FFI / Extern declarations *)
ExternBlock = "extern" StringLit? "{" { ExternFnDecl } "}" ;
ExternFnDecl = "fn" Ident "(" ExternParams? ")" RetType? Variadic? ";" ;
ExternParams = ExternParam { "," ExternParam } ;
ExternParam = Ident ":" Type ;
Variadic = ".." ;
ExternFnExport = "#[" "export" ( "(" StringLit ")" )? "]" ExternFnDef ;
ExternFnDef = "extern" StringLit "fn" Ident "(" Params? ")" RetType? Block ;
(* Functions *)
FnDecl = "fn" Ident TypeParams? "(" Params? ")" RetType? WhereClause? Block ;
GenFnDecl = "gen" "fn" Ident TypeParams? "(" Params? ")" "->" Type WhereClause? Block ;
AsyncGenFnDecl = "async" "gen" "fn" Ident TypeParams? "(" Params? ")" "->" Type 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 | DeferStmt | 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" "await"? Pattern "in" Expr Block ;
WhileStmt = "while" Expr Block ;
BreakStmt = "break" ("@" Ident)? Expr? ";" ;
ContinueStmt = "continue" ("@" Ident)? ";" ;
ReturnStmt = "return" Expr? ";" ;
DeferStmt = "defer" Expr ";" ;
ExprStmt = Expr ";" ;
(* Expressions *)
Expr = UnsafeExpr | SendExpr ;
UnsafeExpr = "unsafe" Block ;
SendExpr = TimeoutExpr ( "<-" Expr )? ; (* Send: actor <- msg *)
TimeoutExpr = OrExpr ( "|" "after" Expr )? ; (* Timeout: expr | after duration *)
OrExpr = BitOrExpr { "||" BitOrExpr } ;
BitOrExpr = BitXorExpr { "|" BitXorExpr } ;
BitXorExpr = BitAndExpr { "^" BitAndExpr } ;
BitAndExpr = AndExpr { "&" AndExpr } ;
AndExpr = EqExpr { "&&" EqExpr } ;
EqExpr = RelExpr { ("==" | "!=" | "=~" | "!~") RelExpr } ;
RelExpr = RangeExpr { ("<" | "<=" | ">" | ">=") RangeExpr } ;
RangeExpr = ShiftExpr ( (".." | "..=") ShiftExpr )? ;
ShiftExpr = AddExpr { ("<<" | ">>") AddExpr } ;
AddExpr = MulExpr { ("+" | "-") MulExpr } ; (* + also concatenates strings *)
MulExpr = UnaryExpr { ("*" | "/" | "%") UnaryExpr } ;
UnaryExpr = ("!" | "-" | "~" | "await") UnaryExpr | PostfixExpr ;
PostfixExpr = Primary { "?" | "." Ident | "(" Args? ")" | "[" Expr "]" } ;
Primary = Literal
| InterpolatedStr
| Ident ( "{" FieldInitList "}" )? (* Struct init: Point { x: 1, y: 2 } *)
| "[" ExprList? "]" (* Array literal *)
| "[" Expr ";" Expr "]" (* Array repeat: [0; 256] *)
| "(" Expr ")"
| "(" ExprList ")" (* Tuple *)
| IfExpr
| MatchExpr
| Lambda
| Spawn
| SelectExpr (* select { ... } *)
| JoinExpr (* join { ... } *)
| Scope (* scope { ... } or scope |s| { ... } *)
| CooperateExpr
| YieldExpr ;
FieldInitList = FieldInit { "," FieldInit } ","? ;
FieldInit = Ident ":" Expr ;
IfExpr = "if" Expr Block ( "else" (IfExpr | Block) )? ;
MatchExpr = "match" Expr "{" { MatchArm } "}" ;
Literal = IntLit | FloatLit | DurationLit | StringLit | RegexLiteral | "true" | "false" ;
ExprList = Expr { "," Expr } ;
Args = Expr { "," Expr } ;
(* Closures — arrow syntax only (v0.2.0: pipe syntax |x| removed) *)
Lambda = "move"? "(" LambdaParams? ")" "=>" RetType? (Expr | Block) ;
LambdaParams = LambdaParam { "," LambdaParam } ;
LambdaParam = Ident ( ":" Type )? ;
(* Actor operations *)
Spawn = "spawn" ( LambdaActor | ActorSpawn ) ;
ActorSpawn = Ident TypeArgs? "(" FieldInitList? ")" ; (* Named fields: spawn Counter(count: 0) *)
LambdaActor = "move"? "(" LambdaParams? ")" RetType? "=>" (Expr | Block) ;
(* Concurrency expressions *)
SelectExpr = "select" "{" { SelectArm } TimeoutArm? "}" ;
SelectArm = Pattern ("from" | "<-") Expr "=>" Expr ","? ;
TimeoutArm = "after" Expr "=>" Expr ","? ;
JoinExpr = "join" ("{" | "(") Expr { "," Expr } ","? ("}" | ")") ;
(* Structured concurrency *)
Scope = "scope" ( "|" Ident "|" )? Block ;
(* Inside a scope |s| { ... } block, the binding s supports:
s.launch { expr } — launch a concurrent task, returns Task<T>
s.cancel() — request cancellation of all tasks
s.is_cancelled() — check cancellation state *)
CooperateExpr = "cooperate" ;
YieldExpr = "yield" Expr ;
(* Types *)
(* Type aliases: "int" = i64, "uint" = u64, "byte" = u8, "float" = f64 *)
(* Integer literals default to int (i64), float literals default to float (f64) *)
Type = Ident TypeArgs?
| "Task" "<" Type ">" (* Task type: Task<T> *)
| "Scope" (* Scope type (within scope blocks) *)
| "ActorRef" "<" Type ">" (* Actor reference: ActorRef<A> *)
| "Actor" "<" Type ("," Type)? ">" (* Actor type: Actor<M> or Actor<M, R> *)
| "Arc" "<" Type ">" (* Atomic refcount: Arc<T> *)
| "Rc" "<" Type ">" (* Single-actor refcount: Rc<T> *)
| "Weak" "<" Type ">" (* Weak reference: Weak<T> *)
| "Result" "<" Type "," Type ">"
| "Option" "<" Type ">"
| "Generator" "<" Type ">" (* Sync generator: Generator<Y> *)
| "AsyncGenerator" "<" Type ">" (* Async generator: AsyncGenerator<Y> *)
| "Stream" "<" Type ">" (* First-class readable stream: Stream<T> *)
| "Sink" "<" Type ">" (* First-class writable sink: Sink<T> *)
| "Vec" "<" Type ">" (* Growable array: Vec<T> *)
| "HashMap" "<" Type "," Type ">" (* Hash map: HashMap<K, V> *)
| "(" TypeList? ")" (* Tuple type / 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 ")" (* Multiple trait object *)
| "_" ; (* Infer type from context *)
TypeArgs = "<" Type { "," Type } ">" ;
(* Wire types *)
(* Wire fields use standard Type — no separate WireType needed. *)
(* Pattern matching *)
Pattern = "_"
| LiteralPattern
| Ident
| Ident "(" PatternList? ")" (* Constructor pattern *)
| Ident "{" PatternFieldList? "}" (* Struct pattern *)
| "(" PatternList ")" (* Tuple pattern *)
| Pattern "|" Pattern ; (* Or-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 | "_" }
| "0o" OctDigit { OctDigit | "_" }
| "0b" BinDigit { BinDigit | "_" } ;
FloatLit = Digit { Digit } "." Digit { Digit } ( ("e" | "E") ("+" | "-")? Digit { Digit } )? ;
StringLit = '"' { Char | EscapeSeq } '"'
| 'r"' { AnyChar } '"' ; (* Raw string *)
InterpolatedStr = 'f"' { InterpPart } '"' ; (* f-string with expression support *)
InterpPart = Char | EscapeSeq | "{" Expr "}" ;
(* Template literals removed — use f-strings: f"hello {expr}" *)
RegexLiteral = 're"' { RegexChar } '"' ; (* Regex literal: re"pattern" *)
RegexChar = (* any char except unescaped " *) | '\"' | '\' AnyChar ;
Ident = Letter { Letter | Digit | "_" } ;
Letter = "a".."z" | "A".."Z" ;
Digit = "0".."9" ;
HexDigit = Digit | "a".."f" | "A".."F" ;
OctDigit = "0".."7" ;
BinDigit = "0" | "1" ;
EscapeSeq = "\" ( "n" | "r" | "t" | "\" | '"' | "0" | "x" HexDigit HexDigit ) ;