This makes these operatios use constant stack space rather
than linear stackspace given the size of the inputs. This is important
to prevent certain parser input from causing a stack overflow - in
general, we try to avoid unbounded recursion.
Required a few changes to APIs, namely janet_root_fiber()
to get topmost fiber that is active in the current scheduler.
This is distinct from janet_current_fiber(), which gets the bottom
most fiber in the fiber stack - it might have a parent, and so cannot
be reliably resumed.
This is the kind of situation that makes symmetric coroutines more
attractive.
This way we can support fewer build configurations. Also, remove
all undefined behavior due to use of memcpy with NULL pointers. GCC
was exploiting this to remove NULL checks in some builds.
Also make integer to size_t casts explicit rather than relying on
int32_t * sizeof(x) = size_t. This is kind of a personal preference for
this problem.
Rather than messing with janet_core_dictionary, we
instead cache the core enevironment, and pull out the
needed tables from there. This is more flexible, more correct, and
also exposes janet_resolve_core, which can be easily used from the C
API.