TODO
====
Correctness
-----------
* RECV instruction.
* Investigate why seemingly big-enough ARs are actually not big enough.
* Immutable values. This will help solve the problems of using
values as keys in a dictionary, and the problem of (not) sharing
data between processes.
* (BIG) Stack type checker in assembler.
* (BIG) Fix file processes to really be concurrent, esp. in read.
Use `select` (maybe export fd's to the scheduler.)
* (BIG) Error handling. Instead of just `assert()` (which isn't even there
when you define `NDEBUG`), throw an exception if the unexpected
happens. Or, send a message to the process which created this
process. (This will require `self` be accessible throughout the code
somehow.)
Testing
-------
* Falderal tests for all variants of conditionals.
* Falderal test for closures.
* Falderal test for sending and receiving messages.
* Falderal tests for dictionaries.
* Falderal test for portraying cyclic values.
* Falderal test for saving cycling values.
Accessibility
-------------
* Document C APIs (header files).
* enum success { SUCCESS = 1; FAILURE = 0; } and return this instead of int.
* Portray values from stream_render: %v or similar.
* Figure out way to debug messages received by file process
(can't write to file process, or you'll get an infinite loop.)
Portability
-----------
* Measure sizeof struct value et al in buildinfo. Spit out defines.
Think about how 64-bit systems will handle all this.
Footprint
---------
* "small immediates" embedded in appropriate VM instructions.
* Go back to having "functional values", but basically say
that these are ARs with zero space allocated for arguments / locals.
Then have a VM instruction to create an AR from a functional value.
(Maybe also have a VM instruction to create a full AR instead of a
functional value, from a label, for when you want to call it one-off.)
Performance
-----------
* Allow symbols (/strings) to be interned. There is of course a
tradeoff here, so "allow" rather than "require".
Maybe have VALUE_TAG being "small strings" (fit in a struct value,
so, like, 7 characters). Then many problems go away...?
* Option to create a (non-interned) symbol from a const string in
a way that does not copy the const string.
* More efficient access of free variables. Split each AR into two sections: bound variables
and free variables. The bound variables are stored in the AR itself. Free variables are
stored in some other AR; pointers to them are stored in this AR. Then accessing a bound
variable is only a single indirection. Tradeoff is that more work needs to be done when
creating a functional value.
* In ARs, store top-of-stack pointer as a machine pointer,
not a tuple index.