Add closure objects that wrap functions with captured upvalues, enabling
first-class closures that close over local variables from enclosing scopes.
Introduce new bytecode instructions (CODE_CLOSURE, CODE_LOAD_UPVALUE,
CODE_STORE_UPVALUE, CODE_CLOSE_UPVALUE, CODE_RETURN) and a CompilerUpvalue
tracking system with a MAX_UPVALUES limit of 256. Refactor the grammar to
strictly separate statements from expressions, fixing a bug where block
expressions incorrectly popped locals while temporaries remained on the
stack. Rename internal functions (wrenCallFunction, wrenDebugDumpInstruction,
wrenDebugDumpStack) and add Upvalue allocation, closure creation, and
debug dump support for the new instructions.
Change Token struct to store `const char* start` pointer and `int length` instead of integer start/end offsets. Update Lexer struct similarly, replacing `tokenStart` and `currentChar` offsets with direct pointers into the source string. Adjust Local struct's `length` field type from `size_t` to `int` for consistency. Simplify error reporting in `endCompiler` to use `printf` with `%.*s` format specifier and the new pointer/length fields, eliminating manual character-by-character printing loops.
Extract the common bytecode finalization logic into a dedicated endCompiler function that emits CODE_END and handles parent compiler function loading, replacing duplicated inline code. Update VM method definition opcodes to pop function from stack instead of reading from constants, enabling future closure support. Add TODO comments outlining planned closure capture mechanism and upvalue tracking requirements.
Extract identifier copying logic from subscript and call functions into a dedicated copyName helper function, reducing code duplication. Rename the method signature length constant to MAX_METHOD_SIGNATURE with updated documentation to clarify it includes arity spaces. Update subscript function to use the new constant name and remove stale TODO comment about handling >10 args.
Add a compile-time check in declareVariable() that emits an error when the number of simultaneous local variables reaches MAX_LOCALS (256), replacing the previous placeholder TODO. The limit is derived from the bytecode encoding constraint where CODE_LOAD_LOCAL and CODE_STORE_LOCAL use a single argument byte. Also move the MAX_LOCALS definition from a TODO comment to a proper #define, increasing the value from 255 to 256. Include four new test files: many_locals.wren (exactly 256 simultaneous locals), many_nonsimultaneous_locals.wren (more than 256 locals across nested scopes), too_many_locals.wren (257 simultaneous locals triggering the error), and too_many_locals_nested.wren (exceeding the limit across nested blocks).
Replace the linked-list Scope structure with a flat Local array indexed by depth, enabling proper shadowing semantics where inner declarations correctly hide outer ones. Remove the PUSH_SCOPE/POP_SCOPE macros and the SymbolTable-based locals tracking, replacing them with a MAX_LOCALS (255) fixed-size array that stores variable name, length, and depth. Add four new test cases covering local/parameter collision, nested block scoping, global shadowing, and local shadowing to validate the new behavior.
Add Lua, Python, Ruby, and Wren implementations of the binary_trees benchmark from the Computer Language Benchmarks Game. Update the benchmark runner to support multiple benchmarks with output validation, and fix the Wren compiler to handle the '\t' escape sequence in string literals.
The method function was incorrectly using the outer `compiler` pointer instead of the inner `methodCompiler` when emitting `CODE_LOAD_LOCAL` and its operand, causing incorrect bytecode generation for constructor receiver loading.
Add MAX_PARAMETERS constant set to 16 and extend VM bytecode instructions CODE_CALL_11 through CODE_CALL_16 to support the new limit. Introduce compile-time error messages when parameter or argument count exceeds 16 in function definitions, method declarations, subscript calls, and regular method calls. Add new native fiber call stubs fn_call9 through fn_call16 and register them in the core initialization. Include comprehensive test coverage for 9-16 parameter functions and methods, plus error tests for exceeding the limit in all contexts.
Add a check in the `field()` function to detect when a field is referenced outside of a class context. When `compiler->fields` is NULL (indicating no enclosing class), emit a clear error message "Cannot reference a field outside of a class definition." and assign a dummy field index of 255 to allow continued parsing with minimal cascading errors.
Also includes minor cleanup: remove two stale TODO comments about EOF checking and better error messages in `nextToken()` and `consume()`, and add a new test file `test/field/outside_class.wren` that verifies the error is produced for top-level field assignment.
Replace the fixed-size `MAX_PINNED` array of `Obj*` pointers with a dynamically allocated linked list of `PinnedObj` nodes, removing the 16-object limit and eliminating the `numPinned` counter. Update `pinObj` to accept a caller-provided `PinnedObj` stack variable and link it at the head of the list, and simplify `unpinObj` to pop the head without requiring the object argument. Adjust `wrenNewVM` to initialize the new `pinned` pointer to NULL, and modify `collectGarbage` to iterate the linked list instead of the array.