Language Specification

Version 0.2.0 β€” Complete reference for the AXON language grammar, type system, and semantics.

🧠 Design Philosophy

AXON is built on four core principles that distinguish it from every human-facing language.

πŸ€–

AI-Native

Designed for language models to emit deterministically β€” no ambiguous syntax, no formatting choices, no implicit conversions.

⚑

Performance-First

Zero-cost abstractions, no garbage collector, no runtime overhead. Compiles to native code via QBE or LLVM.

πŸ”’

Explicit Everything

Every type annotation, every cast, every conversion is explicit. Nothing is inferred, nothing is implicit, nothing is hidden.

πŸ“

Minimal Surface

Small, orthogonal feature set. Each construct does one thing. No operator overloading, no macros, no variadic functions.

πŸ“ EBNF Grammar

The complete grammar for AXON's S-expression syntax. All source files use this notation.

axon-grammar.ebnf
(* ── Top Level ── *)
module       = "(" "module" { top_decl } ")" ;
top_decl     = fn_decl | extern_decl | struct_decl | const_decl | global_decl | enum_decl | sum_decl ;

(* ── Declarations ── *)
fn_decl      = "(" "fn" IDENT "(" { param } ")" type expr ")" ;
extern_decl  = "(" "extern" IDENT "(" { param } ")" type ")" ;
struct_decl  = "(" "struct" IDENT "(" { field } ")" ")" ;
const_decl   = "(" "const" IDENT type literal ")" ;
global_decl  = "(" "global" IDENT type expr ")" ;
enum_decl    = "(" "enum" IDENT int_type "(" { enum_variant } ")" ")" ;
enum_variant = "(" IDENT INT_LIT ")" ;
sum_decl     = "(" "sum" IDENT "(" { sum_variant } ")" ")" ;
sum_variant  = "(" IDENT { type } ")" ;
param        = "(" IDENT type ")" ;
field        = "(" IDENT type ")" ;

(* ── Types ── *)
type         = prim_type | ptr_type | array_type | struct_type | enum_type | sum_type | fnptr_type ;
prim_type    = "i8" | "i16" | "i32" | "i64" | "f32" | "f64" | "bool" | "void" ;
ptr_type     = "(" "ptr" type ")" ;
array_type   = "(" "array" type INT_LIT ")" ;
struct_type  = IDENT ;
enum_type    = IDENT ;
sum_type     = IDENT ;
fnptr_type   = "(" "fnptr" "(" { type } ")" type ")" ;

(* ── Expressions ── *)
expr         = literal | var_ref | binop | unop | call | block | if_expr
             | let_expr | set_expr | while_expr | cast_expr | deref_expr
             | addr_expr | field_expr | index_expr | struct_lit | match_expr
             | enum_lit | sum_lit ;
literal      = "(" type ( INT_LIT | FLOAT_LIT | "true" | "false" ) ")" ;
var_ref      = IDENT ;
binop        = "(" BIN_OP expr expr ")" ;
call         = "(" "call" expr { expr } ")" ;
block        = "(" "block" { expr } ")" ;
if_expr      = "(" "if" expr expr [ expr ] ")" ;
let_expr     = "(" "let" IDENT type expr ")" ;
set_expr     = "(" "set" IDENT expr ")" ;
while_expr   = "(" "while" expr expr ")" ;
cast_expr    = "(" "cast" type expr ")" ;
deref_expr   = "(" "deref" expr ")" ;
addr_expr    = "(" "addr" IDENT ")" ;
field_expr   = "(" "field" expr IDENT ")" ;
index_expr   = "(" "index" expr expr ")" ;
struct_lit   = "(" "struct" IDENT { "(" IDENT expr ")" } ")" ;
enum_lit     = "(" IDENT IDENT ")" ;            (* (Color Red) *)
sum_lit      = "(" IDENT "." IDENT { expr } ")" ;  (* (Option.Some (i64 42)) *)
match_expr  = "(" "match" expr { match_arm } ")" ;
match_arm    = "(" pattern expr ")" ;
pattern      = literal | enum_lit | sum_pat | "_" | "true" | "false" ;
sum_pat      = "(" IDENT "." IDENT { IDENT } ")" ;  (* (Option.Some val) *)

πŸ”’ Primitive Types

TypeSize (bytes)Description
i81Signed 8-bit integer
i162Signed 16-bit integer
i324Signed 32-bit integer
i648Signed 64-bit integer
f324IEEE 754 single-precision float
f648IEEE 754 double-precision float
bool1Boolean (true / false)
void0Unit type (no value)

πŸ“¦ Compound Types

TypeSyntaxDescription
Pointer(ptr T)Typed pointer to a value of type T
Array(array T N)Fixed-size array of N elements of type T
Struct(struct Name ((f1 T1) ...))Named product type with ordered fields
Enum(enum Name iN ((V1 0) ...))Nominal enum with explicit integer backing
Sum Type(sum Name ((V1 T1...) ...))Tagged union with per-variant payloads
Function Pointer(fnptr (T1 T2) Ret)Pointer to a function with given param/return types

🎯 Cast Rules

All type conversions in AXON are explicit via the (cast T expr) form. The following casts are allowed:

FromToSemantics
intintSign-extend or truncate to target width
intfloatSigned integer to floating-point conversion
floatintFloating-point to signed integer (truncate toward zero)
ptrptrReinterpret pointer type (no runtime cost)
enumintExtract underlying integer value from enum
intenumWrap integer as enum (value must be valid variant)

βš™οΈ Operators

All operators use prefix notation: (op lhs rhs). No operator overloading.

CategoryOperatorsOperand Types
Arithmetic+ - * / %int Γ— int, float Γ— float
Comparison== != < <= > >=int Γ— int, float Γ— float, enum Γ— enum (== != only)
Logical&& || !bool Γ— bool (! is unary)
Bitwise& | ^ ~ << >>int Γ— int (~ is unary)

🏷️ Enum Types

Enums are nominal integer-backed types with named variants. Each variant has an explicit integer value.

Syntax
;; Declaration
(enum EnumName backing_int_type ((Variant1 0) (Variant2 1) ...))

;; Construction (enum literal)
(EnumName VariantName)

;; Cast to integer
(cast i32 (Color Red))    ;; β†’ 0

;; Comparison
(== c (Color Blue))       ;; enum == enum β†’ bool

Example

direction.axs
(module
  (extern print_i64 ((n i64)) void)
  (enum Dir i32 ((North 0) (South 1) (East 2) (West 3)))

  (fn main () i32
    (block
      (let d Dir (Dir East))
      (call print_i64 (cast i64 d))  ;; prints 2
      (i32 0))))

Rules

  • Backing type must be an integer type (i8, i16, i32, i64)
  • All variant values must be explicit integer literals
  • Variant values must be unique within the enum
  • Enums support == and != comparison
  • Cast to/from backing int type via (cast ...)
  • Enums are type-safe: cannot assign one enum to another

🧬 Sum Types (Tagged Unions)

Sum types are algebraic data types where each variant can carry a different payload. The compiler auto-assigns sequential tag values and enforces exhaustive pattern matching.

Syntax
;; Declaration: auto-assigned tags 0, 1, 2, ...
(sum TypeName ((Variant1 type1 type2) (Variant2) (Variant3 type1)))

;; Construction (dot notation)
(TypeName.Variant1 expr1 expr2)
(TypeName.Variant2)

;; Pattern match with payload binding
(match value
  ((TypeName.Variant1 a b) ;; a, b bound to payload fields
    (add a b))
  ((TypeName.Variant2)
    (i64 0)))

Example

option.axs
(module
  (extern print_i64 ((n i64)) void)
  (sum Option ((None) (Some i64)))

  (fn unwrap_or ((opt Option) (default i64)) i64
    (match opt
      ((Option.Some val) val)
      ((Option.None)     default)))

  (fn main () i32
    (block
      (call print_i64 (call unwrap_or (Option.Some (i64 42)) (i64 0)))  ;; 42
      (call print_i64 (call unwrap_or (Option.None) (i64 -1)))           ;; -1
      (i32 0))))

Rules

  • Layout: i32 tag + aligned payload region (max variant size)
  • Tag values are auto-assigned: 0, 1, 2, ...
  • Variants may carry zero or more payload fields (positional, not named)
  • Construction uses dot notation: (Type.Variant payload...)
  • Payload count and types are checked at compile time
  • Sum types are nominal: different sum types with identical layouts are distinct
  • Pattern matching with binding introduces local variables scoped to the arm body

πŸ”€ Match Expressions

Pattern matching with exhaustiveness checking. Returns a value β€” every arm must produce the same type.

Syntax
(match scrutinee
  (pattern₁ result₁)
  (patternβ‚‚ resultβ‚‚)
  ...
  (_        default))

Exhaustiveness Rules

  • Enum: Must cover all variants, or include a wildcard _ arm
  • Sum: Must cover all variants, or include a wildcard _ arm β€” payload bindings scoped to arm body
  • Bool: Must cover both true and false, or include _
  • Integer: Must include a wildcard _ arm (infinite domain)

Enum Match

enum_match.axs
(enum Color i32 ((Red 0) (Green 1) (Blue 2)))

(match c
  ((Color Red)   (i64 10))
  ((Color Green) (i64 20))
  ((Color Blue)  (i64 30)))  ;; exhaustive: all 3 variants covered

Integer Match (wildcard required)

int_match.axs
(match x
  ((i32 0)  (i64 100))
  ((i32 1)  (i64 200))
  (_       (i64 999)))  ;; wildcard required for int

Bool Match

bool_match.axs
(match flag
  (true  (i64 1))
  (false (i64 0)))  ;; exhaustive: both values covered

πŸ”— Function Pointers

First-class function pointers with explicit type annotation and auto-coercion from named functions.

Type Syntax

fnptr type
;; Type: pointer to function (i64, i64) β†’ i64
(fnptr (i64 i64) i64)

;; Declare a local with fnptr type
(let fp (fnptr (i64 i64) i64) add)  ;; auto-coerce fn β†’ fnptr

;; Call via fnptr
(call fp (i64 3) (i64 4))        ;; β†’ 7

Auto-Coercion

When a named function is used where a fnptr is expected, the compiler automatically coerces it. No explicit cast is needed β€” just use the function name as an expression.

fnptr_coercion.axs
(fn double ((x i64)) i64 (* x (i64 2)))
(fn triple ((x i64)) i64 (* x (i64 3)))

(fn apply ((f (fnptr (i64) i64)) (val i64)) i64
  (call f val))

;; Usage: auto-coerces 'double' and 'triple' to fnptr
(call apply double (i64 5))  ;; β†’ 10
(call apply triple (i64 5))  ;; β†’ 15