Replace the single `loopBody` index with a `Loop` struct that tracks scope depth, enabling the compiler to emit correct scope-exit code when a `break` statement is encountered inside nested blocks. Also add `WREN_DUMP_COMPILED_CODE` debug flag and new test cases for closures capturing loop variables after break, return inside loops, and nested loop scoping.
Rename the IO.write method to IO.print, which now prints without a trailing newline, and add a new IO.print method that appends a newline after output. Update all benchmark, example, and test files to use IO.print instead of IO.write. Additionally, implement Unicode escape sequence parsing in the compiler's string tokenizer, supporting \uXXXX and \u{...} syntax with proper UTF-8 encoding for code points up to U+10FFFF.
Replace the fixed-size MAX_SYMBOLS array with a dynamically growing StringBuffer for symbol names, update all instruction encodings to use 16-bit operands for constants and method symbols, and refactor method binding to use a dynamic MethodBuffer per class. Remove the constant deduplication logic in addConstant and the commented-out struct fields in initCompiler.
Move bytecode and debug source line buffers out of Compiler struct to
simplify initialization, and add inline comments for source path, source
code, constants, locals, upvalues, and fields to improve readability of
the compiler's internal state layout.
Remove the single-purpose Buffer struct from wren_compiler.c and replace it with type-specific ByteBuffer and IntBuffer types generated via a DECLARE_BUFFER macro in wren_utils.h, with shared buffer logic implemented in wren_utils.c using a void* Buffer helper struct. This enables a growable line-number buffer for debug source lines.
Move SymbolTable struct and its associated functions (initSymbolTable, clearSymbolTable, addSymbol, findSymbol, ensureSymbol, getSymbolName) from wren_vm.c and wren_value.h into new wren_utils.c and wren_utils.h files. Rename all functions with wrenSymbolTable prefix for consistent naming convention, update all call sites across compiler, core, debug, and VM files, and relocate MAX_SYMBOLS constant to wren_common.h.
Introduce primitive error signaling, runtime error handling with callstack printing, and fiber termination on error. Add source file path and method name tracking to functions, along with debug line number information. Update arithmetic operators to error on non-numeric operands and implement proper "method not found" runtime errors. Refactor the test runner to expect runtime errors with exit code 70 (EX_SOFTWARE) and update the C API to accept source paths in wrenInterpret and wrenCompile. Rename WrenNativeMethodFn to WrenForeignMethodFn and adjust related typedefs. Add debug source line arrays to compilers and functions, and replace the old debug dump functions with new print-based variants that display line numbers.
In `wren_core.c`, `defineClass` and `wrenInitializeCore` now call `addSymbol` before allocating new class objects (`wrenNewClass`, `wrenNewSingleClass`), ensuring unpinned objects are not live when a GC-triggering symbol insertion occurs. In `wren_compiler.c`, `freeBuffer` now passes zero capacity to `wrenReallocate` and reuses `initBuffer` instead of manually zeroing fields, fixing a potential double-free or stale pointer on buffer reuse.
Add support for empty block bodies in the Wren compiler by early-returning
from `finishBlock` when a right brace is immediately matched. This permits
syntactically valid constructs like `{}`, `if (true) {}`, and empty function
or method bodies.
Fix a copy-paste error in `wrenGetArgumentDouble` where the assertion
checked `nativeCallSlot` and `nativeCallNumArgs` instead of the correct
`foreignCallSlot` and `foreignCallNumArgs` fields.
Add test cases covering standalone empty blocks, empty blocks in if/else
statements, and empty function and method bodies returning null.
Introduce the `WrenNativeMethodFn` callback type and `METHOD_FOREIGN` enum value to allow host applications to define C-implemented methods on Wren classes. Add `wrenDefineMethod`, `wrenGetArgumentDouble`, and `wrenReturnDouble` API functions, along with `nativeCallSlot` and `nativeCallNumArgs` VM fields to manage foreign call state. Implement `callForeign` in the interpreter loop to invoke native methods and handle stack cleanup. Move `MAX_PARAMETERS`, `MAX_METHOD_NAME`, and `MAX_METHOD_SIGNATURE` constants from `wren_compiler.c` to `wren_common.h` for shared use across the VM.
Pass WrenVM pointer to addSymbol, ensureSymbol, and clearSymbolTable to use
wrenReallocate for memory management instead of raw free/malloc, and remove
truncateSymbolTable and MAX_STRING constant as part of the cleanup.
Replace the static MAX_STRING-sized char array and fixed bytecode array in the compiler with a dynamic Buffer type that supports reallocation via wrenReallocate. Add initBuffer, ensureBufferCapacity, writeBuffer, and freeBuffer helpers to manage memory. This allows the compiler to handle arbitrarily long string literals and large function bodies without hitting hard-coded limits. Add test/long_function.wren (1013 lines) and test/long_string.wren to verify the fix.
Refactor ObjFn creation in endCompiler to pass all data (constants, bytecode, upvalues) directly to wrenNewFunction, eliminating the temporary post-construction assignment loop and memcpy. Update wrenNewFunction signature to accept these parameters, copy constants into a new owned array, and take ownership of the bytecode buffer. Adjust ObjFn struct to use dynamic bytecode pointer and bytecodeLength field instead of fixed-size array. Update memory tracking in markFn and cleanup in freeObj to handle the new dynamic bytecode allocation.
Restructure Compiler to use dynamic bytecode and constant buffers instead of
relying on ObjFn's fixed-size arrays. Move ObjFn creation to the end of
compilation, add wrenListAdd/Insert/RemoveAt helpers to wren_value, relocate
list capacity macros and ensureListCapacity into wren_value.c, and store a
Compiler pointer in WrenVM for GC safety during compilation.
Implement `..` and `...` infix operators on Num returning Range objects that support the iterator protocol, enabling concise numeric for loops like `for (i in 1..10)`. Add Range class with min/max properties and iterate/iteratorValue methods. Introduce TOKEN_DOTDOT and TOKEN_DOTDOTDOT lexer tokens with PREC_RANGE precedence in the compiler. Unroll method_call benchmark loops across all languages to stress dynamic dispatch instead of loop overhead, reducing iteration count from 1M to 100K with 10x unrolling. Update Wren benchmarks (binary_trees, fib, for) to use new range syntax. Add benchmark/README.md documenting each benchmark's purpose.
Remove the large switch statement that manually handled instruction argument counts for each opcode in wrenBindMethod(). Instead, use the existing getNumArguments() helper function to determine how many bytes each instruction consumes, reducing code duplication and making the method more maintainable when new instructions are added.
Add `for (variable in sequence)` syntax to the Wren language, introducing the `in` keyword token and compiler support for iterating over sequences using `iterate` and `iteratorValue` methods. Includes new benchmark files for Lua, Python, Ruby, and Wren, plus test cases covering single-expression bodies, block bodies, closures over loop variables, and break statements. Also fixes a missing POP() in CLOSE_UPVALUE and moves the while test file to a subdirectory.
Replace the block() function's expression-only body with a call to definition(), enabling flow control statements like `if (foo) return bar` and `if (i > 2) break` without requiring curly braces. Add new test files for return statements after if, else, while, and inside functions/methods, and update existing break tests to use the simplified syntax.
Add TOKEN_BREAK keyword recognition and a loopBody field to the compiler
to track the innermost loop's first instruction index. The break
statement emits a jump to the end of the current loop, and compile-time
errors are reported when break appears outside a loop body, inside a
function defined within a loop, or inside a method defined within a
loop. New test files verify correct behavior for break in while loops,
nested loops, and error cases for invalid break usage.
- Remove two TODO comments in wren_compiler.c about parameter length overflow check and assignment in named call
- Remove TODO about interning bool_toString and null_toString strings in wren_core.c
- Replace oversized 100-char temp buffer with precise 21-char buffer in num_toString, referencing Lua implementation
- Rename io_write native to io_writeString and remove TODO about calling toString on argument
Add a dedicated lexError function that marks compilation as failed and formats
error messages consistently with a trailing newline. Move line counting from
readRawToken into nextChar so that newlines are tracked during all lexer phases,
including block comment scanning. Replace the TODO placeholder in
skipBlockComment with a proper lexError call for unterminated block comments,
and add test cases for unterminated block and nested block comments.
Remove the CODE_DUP opcode from the compiler, debug printer, VM dispatch table, and enum definition. Also simplify several case blocks in the computed-goto interpreter by removing unnecessary braces and consolidating local variable declarations, and add a critical ordering comment to the dispatch table.
Introduce CODE_LOAD_FIELD_THIS and CODE_STORE_FIELD_THIS opcodes that bypass receiver stack operations when field access occurs directly within a method body. Refactor field() compiler to emit these faster instructions when compiler->methodName is set, and extract loadThis() helper to correctly resolve 'this' in nested functions. Update VM interpreter with dedicated dispatch cases that read receiver from frame->stackStart instead of popping, and add debug disassembly support. Add test cases for field closure capture and nested class field isolation, removing related TODO comments.
Remove the ResolvedName enum and its typedef, replacing the resolved parameter with a Code* loadInstruction pointer that directly returns the appropriate load instruction (CODE_LOAD_LOCAL, CODE_LOAD_UPVALUE, or CODE_LOAD_GLOBAL). This eliminates the intermediate enum and the TODO comment about ditching it, simplifying the variable resolution logic in the compiler.
Add a new test case `test/super/closure.wren` verifying that `super.toString` correctly resolves to the base class method when called from within a closure defined in a derived class. Refactor `resolveLocal` and `resolveUpvalue` to accept explicit name and length parameters instead of relying on the previously consumed token, enabling proper name resolution in nested closure scopes during superclass method dispatch.
In the compiler, when parsing a variable declaration, the `=` token is now optional. If present, the initializer expression is compiled as before. If absent, the variable is implicitly initialized to `null` via a call to `null(compiler, false)`. This change removes the previous `TODO` comment and the unconditional `consume` of `TOKEN_EQ`.
Two new test files verify the behavior for both global and local variables without initializers, asserting that reading such a variable yields `null`.
Add support for closing over "this" in function closures defined inside methods by naming the receiver local variable "this" in method compilers. Fix upvalue closing to copy the actual value instead of the stack top, and reorder return handling to close upvalues before storing the result. Add test cases for closure over "this", nested closures, and nested classes.
Implement list subscript setter (`[ ]=`) native method in wren_core.c, enabling assignment to list elements via bracket syntax. Extract duplicate parameter count validation logic into a shared `validateNumParameters` function in wren_compiler.c, replacing inline checks in both `parameterList` and `methodCall`. Add comprehensive test suite covering basic assignment, return value semantics, negative indices, and error cases for out-of-range and excessive arguments.
- Add TOKEN_LINE matching after list elements in compiler to allow newlines before commas or closing brackets
- Add tests for list newline handling, EOF after comma/element, and class name inside body
- Remove resolved TODOs for default constructors, inherited fields, metaclass is checks, zero comparison, and bitwise not behavior
Add support for setter methods in the compiler by detecting '=' after a method name in namedCall, compiling the assigned value, and emitting the setter instruction. Includes new test cases for instance setters, static setters, assignment associativity, grouping, operator precedence errors, setter result values, and same-name getter/setter methods. Also updates the super call test with a TODO for super setter calls.
Remove the `this new` constructor declaration syntax in favor of a `new` keyword that creates instances directly. Superclass constructors are now invoked via bare `super(args)` instead of `super.new(args)`, eliminating the semantic weirdness of calling a constructor on a partially-constructed instance. Update the compiler to treat `new` as a keyword token, replace the `isMethod` flag with `methodName`/`methodLength` fields, and change the VM's `NEW` opcode to pop the class from the stack before creating the instance. Add a default `new` native method on Object that returns `this`. Update all benchmarks and tests to use the new syntax.
Add detailed TODO notes in wren_compiler.c's method() function to document two unresolved issues: the lack of validation for matching superclass constructors, and the problematic instance context during super() compilation where field access like _someField in super(_someField) expressions could cause undefined behavior since the receiver is still the class at that point.
Refactor the method_call benchmark across Lua, Python, Ruby, and Wren to use proper inheritance with super calls instead of direct state manipulation. This ensures all languages benchmark super method invocations consistently.
Fix a bug in the Wren compiler where constructors weren't being bound correctly by extracting method binding logic into a dedicated `bindMethod` function that properly handles both instance and static methods against the class object.
Optimize if-statement compilation by restructuring jump instruction emission to eliminate unnecessary CODE_JUMP instructions when no else branch exists, reducing bytecode size for conditional blocks.
Update the superclass constructor test to verify inherited field access through super constructor chains, confirming correct field initialization across multiple inheritance levels.
Add support for explicit superclass constructor invocation in subclass constructors using `super.constructorName(args)` syntax before the opening brace. The metaclass inheritance hierarchy now mirrors the regular class chain, with `Class` as the root metaclass superclass instead of `Object`. Includes test cases for multi-level constructor delegation and static method inheritance.
Add isInsideMethod helper that walks the compiler's parent chain to detect
if the current compilation scope is within a method. Use it in super_()
to emit a compile error when 'super' is used at top level or inside a
top-level function, with corresponding test cases for both scenarios.
Migrate all boolean-typed parameters, return values, struct fields, and local variables from `int` (with 0/1 convention) to C99 `bool` (`true`/`false`). Update corresponding comments, macro definitions, and documentation strings to use `true`/`false` terminology instead of "non-zero"/"zero". Add `#include <stdbool.h>` to `src/main.c`, `src/wren_compiler.c`, and `src/wren_value.h`. Remove the stale TODO comment in `src/wren_common.h` that originally proposed this change.
Remove "(bob)" author prefix from all TODO comments in benchmark/method_call.wren, include/wren.h, src/main.c, src/wren_common.h, src/wren_compiler.c, src/wren_core.c, src/wren_value.c, src/wren_value.h, and src/wren_vm.c. Update the TODO_PATTERN regex in metrics script to match the new format without author parentheses. Also refactor test file counting in metrics to use os.walk with fnmatch for recursive directory traversal instead of glob.iglob.
Remove the METHOD_CTOR method type and CODE_METHOD_CTOR opcode, replacing them with a new CODE_NEW instruction that creates class instances directly in the bytecode. This simplifies the compiler by emitting CODE_NEW at the start of constructor bodies instead of relying on a separate method dispatch path, and eliminates the redundant METHOD_CTOR enum value from the method lookup logic.
Add CODE_SUPER_0 through CODE_SUPER_16 bytecodes to the VM for invoking inherited methods, along with a `namedCall` compiler helper that parses method names and argument lists after a dot. The interpreter dispatches super calls by walking up the class hierarchy from the receiver's immediate class, skipping methods defined on that class. Includes three test cases covering calling a different superclass method, calling the same method name, and indirectly inherited methods. Also fixes error formatting to handle newline tokens gracefully and adds a TODO note about not deduplicating placeholder constants for super calls.
Reorder the opcode enum values, dispatch table entries, switch-case handlers, and debug dump cases for CODE_LIST and CODE_CLOSURE to appear after CODE_RETURN and before CODE_CLASS, improving interpreter performance by reducing branch prediction misses for the more common instructions that now appear earlier in the switch.
Add a `defaultConstructor` function in the compiler that emits bytecode for a constructor returning the receiver, invoked during class compilation. Reorder `CODE_CLASS`, `CODE_SUBCLASS`, and method opcodes to the end of the interpret loop's jump table and switch cases, moving `CODE_CALL_0` through `CODE_CALL_16` earlier to compensate for branch alignment issues caused by removing code from `CODE_CLASS` and `CODE_CALL` handlers.
Add the TOKEN_SUPER token type to the token enum and register "super" as a reserved keyword in the readName function. Include TOKEN_SUPER in the nextToken skip-newlines switch and mark it as UNUSED in the grammar rules table, preparing the compiler for future super keyword support.
When a class is defined, its superclass is not known until runtime since class definitions are imperative statements. This adds a new wrenBindMethod function that walks the bytecode of a method after it is bound to a class, adjusting LOAD_FIELD/STORE_FIELD indices to account for inherited fields and patching superclass dispatch targets. The newClass function now correctly accumulates numFields from the superclass chain, and the VM calls wrenBindMethod when binding methods to a class. Includes new test files for inherited field access and the is operator.
Add MAX_METHOD_NAME constant and validation in copyName() to prevent method names exceeding 64 characters. When a method name is too long, the compiler now reports an error and truncates the name to the maximum allowed length. Also update MAX_METHOD_SIGNATURE to be derived from MAX_METHOD_NAME and MAX_PARAMETERS. Add test cases for valid 64-character method names, names that exceed the limit, and a call to an overlong method name.
Add TOKEN_TILDE token type and lexer support for the '~' character in the compiler. Implement the bitwise NOT operation as a native method on the Num class, operating on 32-bit unsigned integers. Include a new OPERATOR macro for prefix/infix operator grammar rules and add comprehensive test cases covering positive, negative, floating-point, and boundary values.
Add a new case in the `readRawToken` function within `src/wren_compiler.c` to map the semicolon character to the `TOKEN_LINE` token type, enabling semicolons to function as line separators in the Wren language parser.
Include a test file `test/semicolon.wren` that verifies the new behavior by using a semicolon to separate two statements on a single line, with the expected output "ok".
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.