Class symbol tables now grow on demand, and the relevant
instructions take 16-bit arguments. There's a small perf hit
for this, but only a few percent, which is good.
- Primitives can now signal an error.
- An error prints a callstack and ends the current (and right
now only) fiber.
- Arithmetic operators error if the operand is not a number.
- Real error for method not found.
- Associate source file name, and method names with functions.
- Debug line number info for functions.
Unfortunately, this regresses perf on fib about 15%, mostly
because of the better checking in arithmetic ops.
There's still a bunch of clean up to do, but this is a big step
in the right direction.
Currently, they have a hardcoded number of constants and
bytecodes. That wastes memory in most cases and fails
catastrophically when there is too much bytecode.
To fix this, we should use growable buffers for both during
compilation and then only create the FnObj when done compiling.
This moves a bunch of stuff around and gets it to the point
where functions are created at the end of compilation. It
doesn't yet size functions appropriately, but all tests are
passing, so this is a good checkpoint.
There's no point in packing it in a Value since it will always
be an ObjFn or ObjClosure. Leaving it an Obj* is a bit faster.
Also fixed a bug where it was freeing the closure's flexible
array of upvalues.
Added ".." and "..." infix operators. Num implements them to
return Range objects. Those in turn implement the iterator
protocol, so now numeric for loops are easy:
for (i in 1..10) { ... }
I also cleaned up the Wren benchmarks to use this.
In the process, I discovered the method_call benchmark really
just showed loop peformance, so I unrolled the loops in all of
the languages to stress method calls.