146 lines
5.0 KiB
Markdown
146 lines
5.0 KiB
Markdown
<div align="center">
|
||
|
||
<img src="assets/flan-logo.svg" alt="Flan" width="300">
|
||
|
||
# Flan
|
||
|
||
**A statically typed Lisp for native games and interactive development.**
|
||
|
||
</div>
|
||
|
||
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 <file.flan> type-check a program
|
||
flan run <file.flan> [args...] build and run it
|
||
flan build <file.flan> [-o out] [options] build a native executable
|
||
flan dev <file.flan> [-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.
|
||
|
||
## 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.
|