The callback and the opaque data are now grouped together in a struct
instead of being passed individually into the tokenizer.
This also exposes the string source reader struct and therefore removes
the need of heap allocating it. Neat!
We now no longer call malloc/free/... directly, but use an allocator object
that is passed around.
This was mainly done as a preparation for a garbage collector: The
collector will need to know, how much memory we're using, introducing the
collector abstraction will allow the GC to hook into the memory allocation
and observe the memory usage.
This has other potential applications:
- We could now be embedded into applications that can't use the libc
allocator.
- There could be an allocator that limits the total amount of used memory,
e.g. for sandboxing purposes.
- In our tests we could use this to simulate out of memory conditions
(implement an allocator that fails at the n-th allocation, increase n by
one and restart the test until there are no more faked OOM conditions).
The function signature of the allocator is basically exactly the same as
the one Lua uses.
Only for evaluating expressions for now and right now the only exposed
operation is to debug print a value on the stack, this obviously needs to
be expanded.
I've done this for two reasons:
1. A Lua-style stack API is much nicer to work with than to manually manage
refcounts.
2. We'll soon need a more sophisticated garbage collector (if you even want
to count the refcounting as garbage collection). For this, the GC will
need root objects to start tracing for live objects, the stack will be
one of these roots.