Flan # Flan **A statically typed Lisp for native games and interactive development.**
Flan is an experimental, ahead-of-time compiled Lisp for programs that need predictable memory use and a fast edit–run loop. It combines S-expressions, static types, explicit ownership, and a development session that can replace a function in a running program without resetting its state. It is being built around games, but the interesting part is broader: a compiled language where the running program remains available for inspection, experimentation, and small changes. In practical terms: you get parentheses, a debugger that would like to have a conversation, and no garbage collector quietly choosing the dramatic moment to join your frame loop. ## What it has - Native compilation through LLVM, plus an in-progress direct x86-64 backend. - C-like data layout: structs, fixed arrays, pointers, slices, and explicit allocation. There is no garbage collector. - Owned `Vec` and `Map` containers, plus checked moves and borrowing-oriented slice operations. - Generics, algebraic unions, enums, macros, packages, `defer`, and a C FFI. - Conditions and restarts for recoverable failures and interactive debugging. - A raylib package and a collection of ported raylib examples. - Native, WASI, and web build targets. The cross targets are useful but less complete than the native development workflow. The project is exploratory software, not a stable language release. Some features are deliberately refused while their semantics are still undecided; the compiler aims to say why rather than quietly accepting a partial version. It has opinions, but at least they arrive as error messages. ## Quick start Building requires a current OCaml/Dune toolchain, LLVM/Clang, and the native C toolchain. Raylib is only needed for programs that use the bundled graphics package. ```sh dune build dune exec ./bin/main.exe -- run web/examples/hello.flan ``` To build a standalone native executable: ```sh dune exec ./bin/main.exe -- build web/examples/hello.flan -o hello ./hello ``` The falling-sand demo uses raylib: ```sh dune exec ./bin/main.exe -- run sand.flan ``` Once you are iterating regularly, put the built executable on your `PATH` if you want to use the shorter `flan` commands shown below. ## The live development loop Start a long-lived development session: ```sh flan dev sand.flan ``` The program runs normally and publishes a local socket beside the source file. The bundled Emacs mode can attach to it, evaluate expressions in the live process, inspect a stopped program, and recompile a top-level function from the buffer. A body change takes effect on the next call; changing a function's signature is intentionally rejected. The program keeps its state, which is especially nice when you have finally arranged the sand into something almost worth saving. To set up the mode: ```elisp (add-to-list 'load-path "~/path/to/flan/emacs") (require 'flan-mode) ``` Then use `M-x flan-dev` to start and attach, or `C-c C-z` to attach to a session started in a terminal. The editor workflow is documented in [emacs/MANUAL.md](emacs/MANUAL.md). ## A small example ```lisp (defstruct AssetMissing [id i32]) (defn load-asset [id i32] i32 (signal (AssetMissing {.id id})) 100) (defn asset-or-placeholder [id i32] i32 (restart-case (load-asset id) (use-placeholder [] -1))) (defn main [] () (handler-bind [(AssetMissing [_] (invoke-restart 'use-placeholder))] (println (asset-or-placeholder 7)))) ``` Here a missing asset signals a typed condition. The handler chooses a restart, so execution continues with a placeholder instead of requiring error values to be threaded through every caller. See [web/examples/restart.flan](web/examples/restart.flan) for a runnable version. ## Commands ```text flan check type-check a program flan run [args...] build and run it flan build [-o out] [options] build a native executable flan dev [-s socket] start a live development session ``` Useful build options include `--debug`, `--sanitize`, `--no-bounds-checks`, `--x86`, and `--target=wasm32-wasi|web`. `run` is native-only; cross-built output should be run with an appropriate WASI runtime or browser. A `.wasm` file is not a tiny native executable in a trench coat. ## Checking it ```text dune test the suite. Seconds. Run it constantly. dune build @checks everything else that can fail. A couple of minutes. dune build @sanitize the corpus under ASan and UBSan. dune build @valgrind the corpus under memcheck. Tens of minutes. ``` `dune test` means "the language still works". `@checks` — which is `@page`, `@x86` and `@cells` — means "and everything written down about it is still true": the reference page's examples still print what the page says, the hand-written x86 backend still agrees with LLVM, and a `--dev` build still calls through its indirection cells. The two are separate on purpose. A suite that goes red because prose drifted teaches you to skim past red. But `@checks` only helps if it is run, and nothing runs it for you — there is no CI here. The convention that has to carry it is that a lane's handoff quotes `@checks`, the way the x86 handoffs already quote the survey's counts. Both of this repository's silent failures — two backend refusals that sat for a month, a page of examples that stopped compiling for two days — were found by accident, and neither would have survived one person typing one command. ## Project map - [web/index.html](web/index.html) — language reference and fuller examples. - [spec-memory.md](spec-memory.md) — ownership, containers, and generics. - [spec-conditions.md](spec-conditions.md) — conditions, handlers, and restarts. - [emacs/MANUAL.md](emacs/MANUAL.md) — the interactive editor workflow. - [docs/BUILT.md](docs/BUILT.md) — implementation rationale. - [NEXT.md](NEXT.md) — current work and known limits. ## License Flan is released under the [MIT License](LICENSE). Third-party material under `vendor/` is distributed under its own licenses.