The third silent failure was waiting, and it was the September 12th one again: web/index.html showed the value renderer spelling struct fields with colons, two days after the sweep that made them dots everywhere else. The check that should have said so was anchored in NEXT.md, which is a scratch document, so it had been reporting 'whatever this quotes has moved' into a report nobody could read. README gains a Checking it section: the four commands, what each one means, and the plain statement that nothing runs @checks for you. The convention it proposes is the one this repository already has -- a lane's handoff quotes its counts.
170 lines
6.2 KiB
Markdown
170 lines
6.2 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.
|
||
|
||
## 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.
|