Extract the common `map` and `where` methods from `List` into a new `Sequence` base class, making `List is Sequence` and `Range is Sequence`. Remove duplicate native method registrations for Range in wren_core.c and add new test files for Range map/where operations.
Replace the TODO-marked manual if-else logic in `Strength.weakest` and `Strength.strongest` with the ternary operator, and refactor the manual while-loop list filtering in `Variable.removeConstraint` to use the `.where()` method for cleaner, more idiomatic Wren code.
Add TOKEN_QUESTION token type and implement conditional() parsing function in wren_compiler.c to support the ternary conditional operator (condition ? then : else). Register fn_toString native in wren_core.c to return "<fn>" string for function objects. Include comprehensive test suite covering precedence, short-circuit evaluation, and error cases for missing tokens.
Implement a `where` method on the List class that takes a function `f` and returns a new list containing only elements for which `f.call(element)` returns true. The implementation is added both in the builtin core.wren source and embedded in the C library source string in wren_core.c. Also includes a new test file `test/list/where.wren` verifying filtering with matching and non-matching predicates.
In classDefinition in wren_compiler.c, add a check for TOKEN_RIGHT_BRACE before
requiring a newline after the last method definition, so that a closing brace
immediately following a method is accepted. Update test/class/syntax.wren with
a test case for this syntax.
Add special case in list_subscript native to return a new empty list when
the source list is empty and the requested range is [0..-1] (inclusive) or
[0...0] (exclusive). This enables using list[0..-1] as a universal copy
idiom that works even for empty lists. Update the List.+ operator to use
this idiom instead of manual iteration. Add test cases for both range
forms on empty lists.
The previous implementation of List.+ used conditional checks (`this.count > 0`, `that.count > 0`) before iterating, which caused the loop body to be skipped entirely for empty lists. This commit removes those guards, allowing the for-in loops to run unconditionally — the Wren VM's iterate/iterateValue protocol already handles the empty case correctly at the native level. Additionally, the `list_iterate` native in `wren_core.c` now returns `false` immediately when the list count is zero and the iterator argument is null, preventing an out-of-bounds index of 0 from being returned for empty lists. The test file `test/list/concat.wren` is renamed to `test/list/plus.wren` and extended with a check that the original list `a` remains unmodified after concatenation. A new test in `test/list/iterate.wren` verifies that iterating over an empty list returns `false`.
Move upvalue closing logic from the else branch to before the fiber completion check
to ensure upvalues are properly closed when a fiber finishes. Add test cases for
closure behavior across fiber yields and for Fiber.create argument type validation.
Add a new test file `this_in_static_method.wren` that validates `this` evaluates to the class object when used inside a static method, and removes the TODO comment from `this_in_method.wren` that previously noted this untested behavior.
In the compiler, when a bare name is encountered inside a class definition and it does not resolve to a local variable or global, emit an implicit `this.` load before the call, enabling getter, setter, and method calls without explicit receiver. Update all benchmark, builtin, and test files to remove redundant `this.` qualifiers, and add comprehensive test suites for implicit receiver behavior across instance, inherited, static, nested, and shadowing scenarios.
Add python3 as a new language entry in the benchmark runner configuration, enabling automated performance testing with Python 3. Update multiple benchmark scripts (binary_trees.py, delta_blue.py, fib.py, for.py, method_call.py) to be compatible with Python 3 by adding `from __future__ import print_function`, replacing `xrange` with a `range` polyfill, converting print statements to function calls, and replacing integer division with floor division. Remove the custom `OrderedCollection` class in delta_blue.py in favor of standard Python lists.
Add the DeltaBlue constraint-solving benchmark ported from Dart to Wren, along with supporting Lua and Python versions for cross-validation. The Wren implementation includes the full constraint hierarchy solver with strength classes, plan execution, and the standard DeltaBlue test harness. Register the benchmark in run_bench with expected output "7032700".
When shrinking a list's capacity, wrenReallocate may return a different
memory address. The previous code ignored the return value, leaving
list->elements pointing to freed memory. This fix assigns the result
back to list->elements and adds a regression test for grow/shrink
behavior.
The previous comparison `classObj->methods.count < symbol` incorrectly allowed
access when `symbol` equals `count`, which is out of bounds for zero-indexed
arrays. Changed both occurrences in `runInterpreter` to use `symbol >= count`
to properly guard against out-of-bounds access.
Add two new public API functions to the Wren VM for foreign function interface
(FFI) return values. wrenReturnNull sets the foreign call slot to a null value,
while wrenReturnString copies the provided text into a new Wren heap string,
supporting both explicit length and strlen-based length calculation. Both
functions include assertions to ensure they are called within a valid foreign
call context.
Add `numParams` field to `ObjFn` and `Compiler` structs to track expected parameter count. Refactor `parameterList` to return count and store it in compiler. Modify `endCompiler` to pass `numParams` to `wrenNewFunction`. Replace single `fn_call` native with 17 arity-specific `fn_call0` through `fn_call16` natives that validate argument count against `fn->numParams` via `callFunction` helper, returning error on missing args. Remove stale TODO comment in VM interpreter. Add test files `call_extra_arguments.wren` and `call_missing_arguments.wren`.
Migrate the clock timing functionality from the OS class to the IO class across all benchmark scripts and the core library. Remove the os_clock native function and its associated OS class definition from wren_core.c, while adding a new ioClock native in wren_io.c that uses the same clock()/CLOCKS_PER_SEC logic. Update all benchmark files (binary_trees, fib, for, method_call) to reference IO.clock instead of OS.clock for both start time and elapsed time calculations.
Replace monolithic corelib.wren with per-class builtin/*.wren files and generate_builtins.py script. Move IO class definition and its native writeString_ method from wren_core.c to new wren_io.c, adding wrenGetArgumentString and wrenDefineStaticMethod to the public API. Update Makefile target from corelib to builtin and remove generate_corelib.py.
Replace the TODO placeholder for error codes with a proper WrenInterpretResult enum
containing WREN_RESULT_SUCCESS, WREN_RESULT_COMPILE_ERROR, and
WREN_RESULT_RUNTIME_ERROR. Update wrenInterpret signature to return the new type
and refactor callers in main.c and wren_vm.c to use the enum values instead of
magic exit codes. Also add a startup banner to the REPL.
Replace TODO comments with proper error reporting for unterminated strings, incomplete Unicode escapes, and invalid escape sequences. Add five new test files covering each error case.
Replace all (void) POP() calls with a dedicated DROP() macro that decrements
fiber->stackSize directly, eliminating unused-value compiler warnings and
making the intent of discarding the stack top explicit throughout the
interpreter loop, logical operators, upvalue closing, and object construction.
Extract CSS modification time comparison into reusable `compare_modification_times` helper and apply it to CSS copying logic, ensuring style.css is recopied when source is newer than destination. Also fix output path from `build/docs/` to `build/site/` for generated HTML files.
Update the shebang line in both generate_corelib.py and generate_docs.py scripts to use
/usr/bin/env python instead of hardcoded /usr/bin/python, improving portability across
different Python installations and virtual environments.
Extend the list subscript operator to accept Range arguments in addition to plain numbers. When a Range is provided, the operator returns a new list containing the elements within that range, supporting inclusive (..) and exclusive (...) bounds, negative indices that count from the end, and automatic reversal for backwards ranges. Added validation functions for integer values and range bounds, with dedicated error messages for non-integer range endpoints and out-of-bounds conditions. Updated the test suite with comprehensive range subscript tests and removed the old test that only checked for non-numeric subscripts.
In the compiler's classDefinition function, the class name constant is now emitted as a separate CODE_CONSTANT instruction before CODE_CLASS, instead of being passed as a short argument to CODE_CLASS. The VM's CLASS case handler is updated to pop the class name string from the stack using PEEK2() instead of reading it from the constant table via READ_SHORT(). The comment in wren_vm.h is revised to document that the class name is now on the stack below the superclass.
Store the class name string in `ObjClass` during compilation and class creation, and expose it through a new `class_name` native method. Also update `object_toString` to return the class name for class instances and "instance of <name>" for regular instances.
Eliminate the dedicated CODE_SUBCLASS opcode and instead push a null value to indicate implicit inheritance from Object. This simplifies the bytecode interpreter by using a single CODE_CLASS instruction that checks the top of stack for a null sentinel to determine whether to use the implicit Object superclass or a user-provided superclass. The change also consolidates argument counting and debug printing logic, removing the now-unnecessary case branches for CODE_SUBCLASS across the compiler, VM, and debug modules.
The getNumArguments function was incorrectly returning the number of upvalues
as a direct count instead of accounting for the two bytes consumed per upvalue
in the bytecode stream. This caused the patching loop to exit prematurely when
processing closures with multiple upvalues, leading to corrupted bytecode offsets
and runtime crashes.
Add a check for feof(stdin) after fgets in the REPL input loop in src/main.c. When the user presses Ctrl-D, stdin is closed and fgets returns NULL without reading input. The new code detects this condition, prints a newline for clean terminal output, and returns 0 to exit the REPL gracefully instead of continuing with an empty or uninitialized line buffer. This resolves issue #6 where Ctrl-D caused undefined behavior or an infinite loop.
Introduce a Makefile providing convenience targets for building the wren
interpreter from source, cleaning build artifacts, running tests,
generating documentation, and building the core library. The default
target compiles all C sources under src/ with headers from include/,
places the resulting binary in build/Release/, and ensures the output
directory exists.
The for-in loop in Wren already increments the loop variable automatically, so the explicit `i = i + 1` inside the loop body was causing every other element to be skipped when building the string representation of a List. This fix removes the unnecessary increment from both the corelib.wren source and the embedded string in wren_core.c.
Replace six separate type-check functions (wrenIsClosure, wrenIsFiber, wrenIsFn, wrenIsInstance, wrenIsRange, wrenIsString) with a single wrenIsObjType that takes an ObjType parameter. Add IS_CLASS macro and runtime validation in the IS bytecode handler to ensure the right operand is a class, producing a clear error message when it is not. Add test case for non-class right operand.
Replace silent RETURN_NULL for non-numeric right operands with explicit runtime error via validateNum in four comparison primitives (num_lt, num_gt, num_lte, num_gte). Also remove redundant IS_NUM check in num_mod. Add four new test files verifying runtime error messages for each comparison operator when given a boolean operand.
Update the VM interpreter to treat null as falsey alongside false in if, while, for, and logical AND/OR operations. Remove the TODO comment and adjust short-circuit logic in OP_JUMP_IF and OP_JUMP_IF_NOT branches. Refactor existing test files into subdirectories (if/, logical_operator/, while/) and add dedicated truthiness tests for each construct. Remove old test/if.wren and update and/or tests to exclude null/0/"" truthiness checks now that null is falsey.
Extract the common pattern of checking and setting the FLAG_MARKED bit on an object into a dedicated static helper function. This eliminates repeated inline code across markInstance, markList, markUpvalue, markFiber, and other marking functions, improving maintainability and reducing the risk of inconsistencies in cycle detection.
The change converts a manual while loop with explicit counter variable `i` and increment
to a more idiomatic Wren for-in loop over the range `1..iterations`, improving code
clarity and reducing boilerplate in the tree check computation section.
Add isInclusive boolean to ObjRange struct to distinguish between inclusive (..) and exclusive (...) ranges. Update wrenNewRange signature to accept isInclusive parameter. Implement correct iteration logic for both ascending and descending ranges, handling empty exclusive ranges and floating-point iteration. Add type validation for range RHS operands. Update min/max/to properties to return raw endpoint values instead of adjusted ones. Add comprehensive test coverage for inclusive/exclusive ranges, negative ranges, empty ranges, floating-point iteration, isInclusive property, toString, and type error cases.
Remove the Range class definition from corelib.wren and implement it as a native C type with ObjRange struct, adding native methods for from, to, min, max, iterate, and iteratorValue. Move range operator handling from Num class to native num_dotDot and num_dotDotDot functions. Update VM to support OBJ_RANGE type in marking, printing, and type checking. Add comprehensive test suite for range operations including ordered, backwards, and exclusive ranges.
Update all four language implementations in the for-loop benchmark to use 1,000,000 iterations instead of 2,000,000, and adjust the expected sum in run_bench from 1999999000000 to 499999500000. Also move timer start to before list construction in Lua, Python, and Ruby, and inline the Wren sum loop into a single line.
Refactor the compiler to treat static methods as local variables defined in an implicit scope surrounding the class, eliminating the need for VM-level static method support. This changes `declareVariable` to use the previously consumed token, adds `declareNamedVariable` for explicit token consumption, and updates `parameterList` to use the new function. Adjusts VM bytecode ordering for `CODE_METHOD_INSTANCE` and `CODE_METHOD_STATIC` to pop the class before the function body. Adds comprehensive test coverage for static fields including closures, nested classes, default null values, instance method access, and error cases for field usage outside classes or in static methods.
Move fields, isStaticMethod, methodName, and methodLength from Compiler struct into a new ClassCompiler struct, replacing them with a single enclosingClass pointer. This consolidates class-level bookkeeping and simplifies the Compiler struct by grouping related fields.
Add a new token type TOKEN_STATIC_FIELD to the compiler's token enum and
update the lexer to distinguish between single underscore (TOKEN_FIELD)
and double underscore (TOKEN_STATIC_FIELD) prefixed names. The new token
is registered in the grammar rules table as UNUSED with a TODO comment
for future implementation.
Remove the metaclass inheritance chain that mirrored the class hierarchy, instead always binding metaclasses directly to Class. This prevents static methods from being inherited by subclasses. Also add a compile-time error when `super` is used inside a static method, since it would always delegate to Class without useful effect. Update the `isInsideMethod` check to use `compiler->fields` instead of walking the parent chain for correctness. Add test cases for the new restrictions and remove the old test that verified static method inheritance.
Add isStaticMethod flag to Compiler struct to track whether the current method is static. When compiling a field access, check this flag and emit a compile error if an instance field is used inside a static method. Initialize the flag to false for top-level code and propagate it from parent to child compilers for nested functions and methods.
Add a MAX_FIELDS constant (255) to wren_common.h and implement field overflow
validation in the compiler and VM. The compiler now emits an error when a class
declares more than 255 fields, and the VM checks for inherited field overflow
at class creation time, producing a descriptive runtime error. Also add four
test files (many_fields, many_inherited_fields, too_many_fields,
too_many_inherited_fields) to verify both valid and invalid field counts.
- Fixed "convention OOP background" to "conventional OOP background"
- Fixed "object-oriented programming" hyphenation in Lua example
- Fixed italic emphasis on "you" in rhetorical question
- Corrected other minor typographical errors throughout the document
- Fix receiver-less calls doc: change `this.foo(bar)` to `this.foo(arg)` and
`EnclosingClass.foo(bar)` to `EnclosingClass.foo(arg)` for consistency with
the parameter name used in the surrounding text.
- Update doc examples from deprecated `io.write` to `IO.print` to match
current API.
- Fix error message in `classDefinition` in `src/wren_compiler.c`: change
`"Expect '}' after class body."` to `"Expect '{' after class body."` to
correctly reference the expected token.
Add two LuaJIT benchmark configurations (with and without JIT) to the benchmark runner, refactor language command construction from fixed tuples to extensible lists, and adjust column widths for longer language names.
Add a new `isDone` native method to the Fiber class that returns true when the fiber has no remaining frames. Replace TODO comments with proper runtime error handling in `fiber_run`, `fiber_run1`, `fiber_yield`, and `fiber_yield1` to prevent running finished fibers or yielding from the main fiber. Include test cases verifying the new property and error conditions.
Add iteration over the VM's object linked list in wrenFreeVM to properly
deallocate all allocated GC objects before freeing the VM memory,
replacing the previous TODO placeholder comment.
In the compiler, when a `return` token is followed by a newline or right brace, emit CODE_NULL instead of parsing an expression. This enables bare `return` statements to implicitly return null. Also removes a stale TODO comment about setter parameters and fixes a typo in a comment in wren_core.c. Adds three test cases: one for explicit return in a function, one for bare return before a brace, and one for bare return before a newline.
Implement the remaining standard C escape codes in the readString function
of the Wren compiler, removing the TODO comment about missing escapes.
Adds handling for alert (a), backspace (b), form feed (f), carriage return (r),
and vertical tab (v) escape sequences.
Add core fiber functionality including Fiber.create, Fiber.run, Fiber.yield
primitives with value passing between fibers. Introduce PRIM_RUN_FIBER result
type for interpreter loop, add caller field to ObjFiber struct for yield
resumption, and update GC marking to traverse fiber caller chains. Modify
wrenNewFiber to accept a function/closure argument and initialize the first
call frame. Add debug stack printing with fiber pointer. Include test suite
covering fiber creation, run, yield, value passing, type checking, and
caller resumption.
Implement five new Num methods (ceil, cos, sin, sqrt, isNan) in wren_core.c and register them on the Num class. Add corresponding test files for ceil, floor, is_nan, and sqrt. Extend divide.wren with division-by-zero edge cases (inf, -inf, nan). Remove stale TODO comments from minus, multiply, and plus tests.
Add a new example file `example/mandelbrot.wren` that renders a zoomed-in
section of the Mandelbrot set using ASCII characters. The viewport covers
x from -1.5 to -1.1 and y from -0.2 to 0.1, with up to 80 iterations per
point and a 10-level density character palette for escaped points.
Replace single-byte jump offset emission and reading with two-byte (uint16) handling across all jump instructions (JUMP, LOOP, JUMP_IF, AND, OR). Add new emitJump helper that reserves a 16-bit placeholder, update patchJump to write the offset as big-endian short, and change VM opcode handlers to use READ_SHORT instead of READ_BYTE for jump offsets. This increases maximum jump distance from 255 to 65535 bytes, supporting larger generated bytecode.
Implement the `floor` native method on the `Num` class in `wren_core.c`, which delegates to C's `floor()` function to round a number down to the nearest integer value. Register the new method in `wrenInitializeCore` alongside the existing `abs` method.
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.
The previous buffer size of 21 bytes was insufficient to hold the longest possible
double representation formatted with "%.14g", which can reach 24 bytes including
the null terminator. Updated the buffer to 24 bytes and extracted the numeric
value into a local variable for clarity.
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.
Introduce a new `WREN_TRACE_GC` compile-time flag in `wren_common.h` to enable
dedicated GC tracing independently from general memory tracing. When either
`WREN_TRACE_MEMORY` or `WREN_TRACE_GC` is set, include `<time.h>` and modify
`collectGarbage()` to measure elapsed wall-clock time using `clock()`. The GC
trace now reports bytes before and after collection, bytes collected, the next
GC threshold, and the duration in seconds. Also move the `-- gc --` header
print and the `nextGC` calculation inside the tracing guard to avoid
side-effects when tracing is disabled.
Remove the deprecated validateIndexOld function and migrate all callers to the new validateIndex that reports runtime errors. Add validateString helper for string argument checking. Introduce comprehensive runtime error tests for list and string subscript operations, removeAt, and contains methods, replacing old silent null returns with proper error halting.
Replace the old validateIndex function with validateNum and validateInt helpers that produce descriptive runtime error messages. Add new test files covering invalid index types, out-of-bounds indices, and iterator validation for list insert, iterate, and iteratorValue methods. Rename existing number operator error tests to use consistent "must be a number" phrasing.
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.
Consolidate memory management by relocating the static freeObj function into wren_value.c as the public wrenFreeObj API, keeping allocation and deallocation co-located for better code organization.
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.
Rename the fields `nativeCallSlot` and `nativeCallNumArgs` to `foreignCallSlot` and
`foreignCallNumArgs` across `wren_vm.c` and `wren_vm.h` to accurately reflect that
these fields are used exclusively during foreign function calls, not native method
invocations. Update all references in `callForeign`, `wrenGetArgumentDouble`, and
`wrenReturnDouble` accordingly.
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.