flan/test/programs/dev-repl.flan
Joseph Ferano 20fedd4ad8 Printers for every shape a value can have
C-x C-e rendered the scalars and refused the rest, which made it a calculator
rather than a REPL. The renderer is now a compile-time walk over the type,
emitting a piece at a time: structs, nested structs, fixed arrays, slices,
options, enums by name, and pointers as their shape. A raylib Color comes back
through the FFI as (rl/Color {:r 17 :g 34 :b 51 :a 68}).

Piecewise emission is what makes composites possible at all - a struct is its
fields with punctuation between them, and concatenating that in generated IR
would need an allocator the language does not have.

u64 now renders, in C, with %llu. It used to refuse because i64->bytes is
signed and it would otherwise come back as -1, but refusing a whole struct
because one field is a u64 is much worse than adding a runtime entry point.
Strings are quoted and escaped in C for the same reason: unescaped content does
not round-trip and reads as a framing bug rather than as the value it is.

An enum renders as :name, recovered from the checker's table as a chain of
comparisons, since members are erased to i32 before the backend sees them; a
value outside the declared members falls through to its number, which is what
you would want to see. A pointer is rendered and never followed - it is the
only thing that could make the walk cycle, and dereferencing one a REPL was
handed is not a safe thing to do on someone's behalf.

Three bounds, easy to conflate. depth and span bound the walk, so sand's
[100 [100 u32]] grid does not unroll into ten thousand render sites. The output
is bounded once in the runtime, since a slice renders through a loop the
compiler cannot bound, and one place enforcing it means no renderer carries a
budget.

emit.ml's cast now treats an enum as the i32 it is. Nothing in the surface
language produces that - a keyword resolves against its enum and never widens -
but the renderer needs an enum's number when it falls outside the members.
2026-09-11 07:18:07 +07:00

20 lines
612 B
Plaintext

;;;; A program that just runs, for evaluating expressions against.
;;;;
;;;; Unlike dev-loop.flan it does not count reloads and stop: C-x C-e is a
;;;; thunk the agent runs at a frame boundary, so a program under test has to
;;;; keep reaching them. (agent/wait 5) is both the poll and the pacing — 5ms
;;;; of nothing, which is what a frame is when there is no frame.
(import agent "vendor:agent")
(defvar ticks i64)
(defn step [] i64
(set ticks (+ ticks 1))
ticks)
(defn main [] i32
(agent/start "/tmp/flan-dev-repl-fallback.sock")
(dotimes [i 4000]
(agent/wait 5)
(set ticks (step)))
0)