Appendix A: A Simple Allocator
design-why-not-builtin

Why did we build the allocator in our language instead of adding alloc as a builtin?

Because we could. The allocator uses load64, store64, pointer arithmetic, and a linked list -- all things the language already supports. Making it a builtin would hide the mechanism. Making it a library function proves the language is powerful enough for systems programming.

This is the same philosophy as streq -- we wrote string comparison instead of importing it. And emit_num -- we wrote number-to-string conversion instead of calling a runtime function. The language builds its own tools. Each tool validates the language.

In production, you'd want the allocator to be fast (a buddy allocator, slab allocator, or similar). What we built here is slow (linear free-list search) but correct, and correct is what matters for understanding. The reader now knows what malloc does -- because they wrote it.

What we built: a complete memory allocator in 50 lines of the language we created from scratch. Bump allocation, free-list allocation, coalescing. A dynamic array built on top of it. No new language features, no builtins, no magic -- just load64, store64, and arithmetic.

The language is no longer just a compiler's implementation language. It's a systems programming language. A simple one, with rough edges, but real. You can build data structures in it. You can manage memory in it. You can write programs that don't know their size at compile time.

Not bad for a language that started with eval("3+5").

## Appendix B: Floating Point

Until now, our language has had one type: i64. Numbers, booleans, packed strings, array addresses, function return values -- all integers. This made the compiler simple: emit i64.add, always. No type checking, no type inference, no decisions.

Now we break that rule. We add f64 -- 64-bit floating point. This is a bigger change than it sounds. With two types, the compiler has to answer a new question for every operation: which add? i64.add or f64.add? The variable tables need to track types. The WAT output emits (local $x f64) instead of (local $x i64). The VM's stack carries values that might be integers or might be floats.

One type was simplicity. Two types is expressiveness. Let's see what it costs.

### Float literals

A float literal is a number with a decimal point. 3.14 is float. 3 is integer. The dot is the signal.