Skip to content

Repository files navigation

Axiom

GitHub CI

Functional programming that ships a binary, not a runtime.

Image

Algebraic data types, exhaustive matching and an effect system the compiler checks, lowered through LLVM to a native executable with no VM, no collector and no libc inside it.

The compiler is written in Axiom: 106,203 lines of it, which rebuild themselves from a committed LLVM seed until two successive compilers are byte-identical. And because the syntax is uniform S-expressions with a machine-readable diagnostic surface (AXSYM, AXDL, content-derived NIDs, --diagnostic-format=ai), it is as legible to an agent generating code as to the person reviewing it. That was a design goal, not an afterthought.

Where this fits: if you want a small, explicit, statically-typed language that produces a self-contained binary you can reason about instruction by instruction — and you would rather have a compiler that argues with you than one that guesses — Axiom is built for you. If you want a mature ecosystem, a package registry, or green threads, it is not there yet, and Implementation status says exactly how far each piece has got.


A whole program

(import IO)

; A custom effect
(effect Log
  (write :: (-> String Int)))

; If the param is not satisfied with a value greater than 0 then the compiler will fail with a backtrace.
;@axiom:pre((> n 0))
(:: work (-> Int Int))

(fn (work n)
  {
    (write "starting")
    (write "done")
    n
  }
)

(:: main Int)

;@axiom:effect(io)
(fn (main)
  {
    (handle (work 1) (Log IO) (lambda (m)
      {
        (println "[log] {m}")
        0
      }
    ))
    (handle (work 2) (Log) (lambda (m) 0))
    0
  }
)

; output:
;  [log] starting
;  [log] done

Install

curl -fsSL https://raw.githubusercontent.com/chrispaig3/axiom/trunk/scripts/install.sh | bash
export PATH="$HOME/.axiom/bin:$PATH"

It verifies the archive's SHA-256, then builds and runs a program that imports a standard-library module before reporting success. Archives are published for linux-aarch64 and darwin-aarch64; on any other host it says so and points here. linux-x86_64 is fully supported and tested — its CI leg runs the whole battery — it just has no prebuilt archive.

Building from a checkout needs no compiler: bootstrap/ carries the compiler's own LLVM IR, one file per target.

git clone https://github.com/chrispaig3/Axiom.git && cd Axiom
./scripts/bootstrap-from-seed.sh --install .axiom-bin

CONTRIBUTING § Quick Start has the prerequisites per platform and what the bootstrap is doing.

Quick start

Put this in hello.ax:

(import IO)

(:: main Int)
;@axiom:effect(io)
(fn (main)
  {
    (println "Hello from Axiom! 🚀")
    0
  })
axiom run hello.ax                              # compile and run
axiom build --input hello.ax --output hello     # or keep the binary
axiom explain AX3042                            # every code has a full explanation
axiom repl                                      # Axiom 0.7.5 - REPL

IO is Axiom's own standard library — that binary calls no C function, not for printing, not for allocation. Delete the ;@axiom:effect(io) line and the compiler tells you the claim is missing, with the path to the syscall.

For something the size of a real program, examples/ holds a batch job over a million records and the generator that writes this repository's own API reference. Both are run by a gate in CI, which is the only reason they still work.

Targets

--target selects the platform to generate code for, and with it both the syscall ABI and which platform modules the standard library resolves to:

axiom --target=linux-x86_64 emit-llvm main.ax -o main.ll

Supported: darwin-aarch64, darwin-x86_64, freebsd-x86_64, linux-aarch64, linux-x86_64, windows-x86_64. Defaults to the host.

A target joins that list when a CI leg executes what the compiler emits there. That is the definition of supported in this repository, stated here once; docs/reference.md, SECURITY.md and CONTRIBUTING.md point at this paragraph rather than restating it, and scripts/check-doc-drift.sh holds the copies of the list to each other and to the compiler's own --target table.

Two standing exceptions, named rather than left quiet. darwin-x86_64 predates the rule and is executed by no runner, which is why it ships no artifact; freebsd-aarch64 is assembled and relocation-checked but is executed by no runner either, because an aarch64 guest is TCG-emulated on every runner GitHub offers and the 300-minute budget was measured and dropped. scripts/check-release-targets.sh requires that sentence to be here: a target that is supported, ships nothing, and is tested nowhere makes the word mean nothing, so silence about one is a gate failure.


Documentation

Language reference The whole language, section by section
Examples Worked programs — a batch job, an API-reference generator — each one pinned by a gate
Implementation status What is complete, functional, or partial — with the fixture that proves each row
Standard library API Every public name, generated from the source and gated against it
Diagnostics AXDL, AXSYM, NID, and the agent-facing output formats
Memory model The allocator, reference counting, regions, and every rule's probe
Error model Result, Error, and how failure travels
FFI Calling Rust, and Rust calling Axiom
Effects Declaring, handling, and what the compiler checks
Agent harness The tooling built on the machine-readable surface
CONTRIBUTING Building, testing, the gate battery, and how to add to it

Contributing

Issues and pull requests are welcome. CONTRIBUTING.md has the project layout, how the compiler works, how to add a diagnostic or a standard-library function, and the rule every change here is held to: if you claim it, gate it.

Like what you see? ⭐ Star the repo and 🍴 fork it — a star helps other people find Axiom, and a fork is where your first contribution starts.

License

MIT — see LICENSE.

About

A functional programming language for humans and agents.

Resources

Contributing

Security policy

Stars

15 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages