Language Specification

Formal specification of Hew v0.2.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
             | TypeDecl | TraitDecl | ImplDecl | WireDecl | FnDecl
             | GenFnDecl | AsyncGenFnDecl | ExternBlock
             | ActorDecl | SupervisorDecl ) ;
Show Railroad Diagram
Generating diagram...

Items may be prefixed with attributes and visibility modifiers:

Attribute  = "#[" AttrContent "]" ;
AttrContent = Ident ( "(" AttrArgs ")" )? ;
Visibility = "pub" ( "(" VisScope ")" )? ;
VisScope   = "package" | "super" ;
Show Railroad Diagram
Generating diagram...

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 } "}"
           | "*" ;
Show Railroad Diagram
Generating diagram...
Import syntax
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 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 ";" ;
Show Railroad Diagram
Generating diagram...
Bindings
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 error

Functions

FnDecl  = "fn" Ident TypeParams? "(" Params? ")" RetType? WhereClause? Block ;
Params  = Param { "," Param } ;
Param   = Ident ":" Type ;
RetType = "->" Type ;
Show Railroad Diagram
Generating diagram...
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    = ("type" | "enum") Ident TypeParams? WhereClause? TypeBody ;
TypeBody        = "{" { StructFieldDecl | VariantDecl | FnDecl } "}" ;
StructFieldDecl = Ident ":" Type ("," | ";") ;
ActorFieldDecl  = ("let" | "var") Ident ":" Type ("=" Expr)? ";" ;
VariantDecl     = Ident ( "(" TypeList ")" | "{" { StructFieldDecl } "}" )? "," ;
Show Railroad Diagram
Generating diagram...
Structs and enums
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 ;
Show Railroad Diagram
Generating diagram...
Generics
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

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 ">"
     | "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 context
Show Railroad Diagram
Generating diagram...

Type 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> 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 } "}" ;
Show Railroad Diagram
Generating diagram...
Traits and implementations
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 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 bounds
fn 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<< >>Shift
6.. ..=Range
7< <= > >=Relational
8== != =~ !~Equality / Match
9&&Logical AND
10&Bitwise AND
11^Bitwise XOR
12|Bitwise OR
13||Logical OR
14| afterTimeout 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 "]" } ;
Show Railroad Diagram
Generating diagram...

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 ;
Show Railroad Diagram
Generating diagram...

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 )? ;
Show Railroad Diagram
Generating diagram...
Closures
// 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:

Error handling
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 ;
Show Railroad Diagram
Generating diagram...

Assignments

AssignStmt = LValue AssignOp Expr ";" ;
AssignOp   = "=" | "+=" | "-=" | "*=" | "/=" | "%=" ;
LValue     = Ident { "." Ident | "[" Expr "]" } ;
Show Railroad Diagram
Generating diagram...

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? ";" ;
Show Railroad Diagram
Generating diagram...

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

Control flow
// 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 ;
Show Railroad Diagram
Generating diagram...
Pattern matching
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 ;
Show Railroad Diagram
Generating diagram...

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) {
        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-response

Lambda Actors

Spawn       = "spawn" ( LambdaActor | ActorSpawn ) ;
ActorSpawn  = Ident TypeArgs? "(" FieldInitList? ")" ;  // Named fields
LambdaActor = "move"? "(" LambdaParams? ")" RetType? "=>" (Expr | Block) ;
Show Railroad Diagram
Generating diagram...

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 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") ")")? ;
Show Railroad Diagram
Generating diagram...

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" ( "|" 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 ;
Show Railroad Diagram
Generating diagram...

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 and tasks
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 "," ;
Show Railroad Diagram
Generating diagram...
Select
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 } ","? "}" ;
Show Railroad Diagram
Generating diagram...
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.

(* 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 } ")" ;
Show Railroad Diagram
Generating diagram...
Wire types
#[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 wire type functions
// 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_iduserId 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 ;
Show Railroad Diagram
Generating diagram...

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
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 TypeC Type
i8...i64int8_t...int64_t
u8...u64uint8_t...uint64_t
isize / usizessize_t / size_t
f32 / f64float / double
bool_Bool
*T / *var Tconst T* / T*
fn(...) -> TFunction pointer

13. Literals & Lexical Elements

Comments

Comment      = LineComment | BlockComment | DocComment ;
LineComment  = "//" { AnyChar } Newline ;
BlockComment = "/*" { AnyChar } "*/" ;
DocComment   = "///" { AnyChar } Newline ;
Show Railroad Diagram
Generating diagram...

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 ) ;
Show Railroad Diagram
Generating diagram...
Literals
// 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" ;
Show Railroad Diagram
Generating diagram...

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 EBNF Grammar v0.2.0
(* ============================================================
   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 ) ;