AI Programming Guide

Everything an AI agent needs to write correct AXON programs. Critical rules, type system reference, common pitfalls, and complete syntax examples.

🚨 Critical Rules

⚠️ Every AI Agent Must Follow These Rules

  1. Every literal must be typed. Write (i32 42), never bare 42. There are no implicit type conversions.
  2. Every function call requires the call keyword. Write (call foo (i32 1)), never (foo (i32 1)).
  3. main must return i32. The entry point is always (fn main () i32 ...) and must return an i32 exit code.
  4. All expressions in a block are evaluated but only the last expression's value is the block's result.
  5. Enums are nominal types. You cannot compare enums of different types or use bare integers where enums are expected.
  6. Match must be exhaustive. Cover all enum variants or use _ wildcard for integer/bool match.

📋 Program Template

Every AXON program follows this structure. Copy this skeleton and fill in your logic.

template.axs
(module
  ;; External function declarations
  (extern print_i64 ((n i64)) void)

  ;; Enum declarations
  (enum Color i32 ((Red 0) (Green 1) (Blue 2)))

  ;; Struct declarations
  (struct Point ((x i32) (y i32)))

  ;; Helper functions
  (fn helper ((x i32)) i32
    (add x (i32 1)))

  ;; Entry point — must return i32
  (fn main () i32
    (block
      (call print_i64 (cast i64 (call helper (i32 41))))
      (i32 0))))

🏗️ Type Hierarchy

AXON has a small, explicit type system. Every value has exactly one type at all times.

CategoryTypesSizesNotes
Integersi8, i16, i32, i641, 2, 4, 8 bytesSigned, two's complement
Unsignedu8, u16, u32, u641, 2, 4, 8 bytesUnsigned integers
Floatsf32, f644, 8 bytesIEEE 754
Booleanbool1 bytetrue / false literals
Voidvoid0 bytesUsed for functions with no return value
Pointers(ptr T)8 bytesTyped pointer to T
Arrays(array T N)sizeof(T) × NFixed-size, value-type
Structs(struct Name (fields...))Sum of fieldsNamed, value-type
Enums(enum Name iN (variants...))Backing int sizeNominal, explicit values
Sum Types(sum Name ((V1 types...) ...))i32 tag + max(payload) alignedTagged union with payloads
Function Ptrs(fnptr (params...) ret)8 bytesFirst-class callable

🚫 Common Anti-Patterns

These are the most frequent mistakes AI agents make. Study these carefully.

❌ Missing Module Wrapper

;; WRONG — no module wrapper
(fn main () i32 (i32 0))

;; CORRECT
(module
  (fn main () i32 (i32 0)))

❌ Untyped Literal

;; WRONG — bare literal
(add x 1)

;; CORRECT — typed literal
(add x (i32 1))

❌ Missing call Keyword

;; WRONG — no call keyword
(print_i64 (i64 42))

;; CORRECT
(call print_i64 (i64 42))

❌ Mismatched If Types

;; WRONG — branches return different types
(if cond (i32 1) (i64 2))

;; CORRECT — both branches same type
(if cond (i32 1) (i32 2))

📑 Quick Reference

Literals

(i32 42)          ;; integer
(i64 -100)        ;; negative
(f64 3.14)        ;; float
(bool true)       ;; boolean
(u8 255)          ;; unsigned
"hello"           ;; string

Control Flow

(if cond then else)
(while cond body)
(block expr1 expr2)
(match val
  (pattern1 result1)
  (pattern2 result2)
  (_ default))

Variables

;; declare + initialize
(let x i32 (i32 10))

;; mutate
(set x (i32 20))

;; constants
(const PI f64 (f64 3.14159))

Functions

;; declaration
(fn add ((a i32) (b i32)) i32
  (add a b))

;; calling
(call add (i32 1) (i32 2))

;; extern
(extern puts ((s (ptr u8))) i32)

Types

;; enum
(enum Dir i32
  ((N 0) (S 1) (E 2) (W 3)))

;; struct
(struct Vec2
  ((x f64) (y f64)))

;; function pointer
(fnptr ((i32)) i32)

🏷️ Enum Guide

Declaration

Enums are nominal types with an explicit integer backing type and explicit variant values.

enum_declaration.axs
(enum Direction i32
  ((North 0) (South 1) (East 2) (West 3)))

Enum Literals

Reference enum variants with the type name followed by the variant name.

enum_literals.axs
(let d Direction (Direction North))
(set d (Direction South))

Comparison

Enums support eq and ne comparisons between values of the same enum type.

enum_compare.axs
(eq d (Direction North))  ;; returns bool
(ne d (Direction South))  ;; returns bool

Casting

Enums can be cast to their backing integer type.

enum_cast.axs
(cast i32 (Direction East))  ;; yields (i32 2)

🔀 Pattern Matching Guide

Enum Match (exhaustive)

All variants must be covered. No wildcard needed when all variants are listed.

match_enum.axs
(match color
  ((Color Red)   (i32 1))
  ((Color Green) (i32 2))
  ((Color Blue)  (i32 3)))

Integer Match with Wildcard

Integer match requires a _ wildcard fallback since integers have infinite range.

match_int.axs
(match x
  ((i32 0)  "zero")
  ((i32 1)  "one")
  (_        "other"))

Bool Match

Both true and false must be covered for exhaustiveness.

match_bool.axs
(match flag
  ((bool true)  (i32 1))
  ((bool false) (i32 0)))

Match as Expression

Match is an expression — it returns a value. All arms must return the same type.

match_expr.axs
(let result i32
  (match direction
    ((Direction North) (i32 0))
    ((Direction South) (i32 1))
    ((Direction East)  (i32 2))
    ((Direction West)  (i32 3))))

🧬 Sum Types Guide

Declaration

Sum types (tagged unions) have an i32 tag and variant-specific payload data. Each variant can carry zero or more typed fields.

sum_declaration.axs
;; A sum type with two variants:
;;   None — no payload
;;   Some — carries an i64
(sum Option ((None) (Some i64)))

;; A sum type with three variants and mixed payloads
(sum Shape
  ((Circle f64)
   (Rect f64 f64)
   (Empty)))

Construction (Dot Notation)

Construct sum type values using Type.Variant dot notation, followed by payload arguments if the variant has them.

sum_construct.axs
;; Variant with payload
(let x Option (Option.Some (i64 42)))

;; Variant without payload
(let y Option (Option.None))

Pattern Matching with Bindings

Match on sum type variants and bind payload fields to names. Matching must be exhaustive — cover all variants.

sum_match.axs
(match opt
  ;; bind the i64 payload to 'val'
  ((Option.Some val) val)
  ;; no payload — return default
  ((Option.None) (i64 0)))

Anti-Patterns

❌ Missing Payload Binding

;; WRONG — Some has a payload, must bind it
((Option.Some) (i64 0))

;; CORRECT — bind the payload
((Option.Some val) val)

❌ Wrong Construction Syntax

;; WRONG — bare variant name
(Some (i64 42))

;; CORRECT — Type.Variant dot notation
(Option.Some (i64 42))

❌ Non-Exhaustive Match

;; WRONG — missing None variant
(match opt
  ((Option.Some val) val))

;; CORRECT — all variants covered
(match opt
  ((Option.Some val) val)
  ((Option.None) (i64 0)))

🔗 Function Pointers Guide

fnptr Type

Function pointer types describe the signature of callable function values.

fnptr_type.axs
;; A function pointer that takes an i32 and returns i32
(fnptr ((i32)) i32)

;; A function pointer that takes two i64s and returns bool
(fnptr ((i64) (i64)) bool)

Storing Function References

Named functions auto-coerce to fnptr when assigned to a variable of fnptr type.

fnptr_store.axs
(fn double ((x i32)) i32
  (mul x (i32 2)))

;; auto-coerce named function to fnptr
(let f (fnptr ((i32)) i32) double)

Indirect Calls

Use call_indirect to invoke a function through a pointer.

fnptr_call.axs
(call_indirect f (i32 21))  ;; returns (i32 42)

Auto-Coercion

Named functions can be passed directly where a fnptr parameter is expected.

fnptr_coerce.axs
(fn apply ((f (fnptr ((i32)) i32)) (x i32)) i32
  (call_indirect f x))

;; pass named function — auto-coerced to fnptr
(call apply double (i32 5))  ;; returns (i32 10)

⚙️ Operators

Arithmetic Operators

OperatorSyntaxDescriptionOperand Types
add(add a b)Additionint, float
sub(sub a b)Subtractionint, float
mul(mul a b)Multiplicationint, float
div(div a b)Divisionint, float
mod(mod a b)Moduloint only

Comparison Operators

OperatorSyntaxDescriptionReturns
eq(eq a b)Equalbool
ne(ne a b)Not equalbool
gt(gt a b)Greater thanbool
lt(lt a b)Less thanbool
ge(ge a b)Greater or equalbool
le(le a b)Less or equalbool

Both operands must be the same type. Comparison operators also work on enum types (eq/ne only).