Guesses whether the input is an expression or statement and handles it
appropriately. Finally, after over a year, the Wren REPL automatically
prints "3" if you type in "1 + 2". \o/
This has a couple of pros:
- It simplifies some code that used to have to check whether a called
thing is a bare function or a closure.
- It's faster because we don't need to do the above checks every time
something is called.
- It lets us more precisely type some fields that used to be Obj*
because they could hold an ObjClosure* or ObjFn*.
The cost is that we allocate a closure every time a function is
declared, even if it has no upvalues. Since functions are called way
more often than they are declared, this is still a net win.
On my Mac laptop:
api_call - wren 0.06s 0.0020 104.73%
api_foreign_method - wren 0.32s 0.0040 101.89%
binary_trees - wren 0.23s 0.0057 98.82%
binary_trees_gc - wren 0.79s 0.0170 98.46%
delta_blue - wren 0.13s 0.0031 101.36%
fib - wren 0.23s 0.0038 103.15%
fibers - wren 0.04s 0.0017 98.97%
for - wren 0.08s 0.0017 107.81%
method_call - wren 0.12s 0.0024 98.60%
map_numeric - wren 0.31s 0.0052 103.93%
map_string - wren 0.11s 0.0113 97.97%
string_equals - wren 0.20s 0.0023 107.75%
This turns those functions into general-purpose functions for writing
raw C values into slots on the foreign call stack.
Writing a return just means writing a value to slot 0.
- wrenGetArgumentCount() -> wrenGetSlotCount()
- wrenGetArgument___() -> wrenGetSlot___()
Also, the get functions assert that the value is the right type instead
of checking at runtime. This puts the onus on the caller to be safe,
but maximizes performance.