Add a new error code (-3) from wrenDefineVariable to detect when a lowercase (local-style) module variable is referenced before its definition. The compiler now reports the line of the first use, improving diagnostics for forward-declared top-level variables.
The `printError` function in `wren_compiler.c` previously dereferenced
`parser->module->name->value` without checking if the module name is null,
causing a crash when compiling modules without assigned names. Now safely
falls back to the string `"<unknown>"` when the module name pointer is null.
Add bounds check in forStatement to ensure compiler->numLocals + 2 does not exceed MAX_LOCALS before calling addLocal for the hidden 'seq ' and iterator variables. Includes regression test with deeply nested for-loops that previously caused an array overflow.
When parsing hex numeric literals, the return value of strtoll (__int64) is
implicitly converted to double via the NUM_VAL macro. This adds an explicit
cast to double to silence the MSVC warning C4244 about potential loss of data
from a 64-bit integer to a double.
When a foreign class allocator calls wrenAbortFiber, the error flag is set on the fiber but the interpreter continues execution, causing the abort to be ignored. Add an explicit error check after createForeign() in the FOREIGN_CONSTRUCT case to trigger a runtime error and properly unwind the fiber when the allocator aborts.
The old hashBits function XORed the two 32-bit halves of a double and applied
Java HashMap-style mixing, but for small integers the low bits of the double
representation are mostly zero, causing nearly all keys to map to entry zero.
This replaces it with Thomas Wang's integer hash (as used by V8's
ComputeLongHash), which properly scatters bits across the 32-bit key space.
Also updates the map_numeric benchmark to iterate 2,000,000 entries (up from
1,000,000) and adjusts the expected output in util/benchmark.py accordingly.
Implement a new String.fromByte(_) static method that creates a single-byte string from an integer 0-255. Includes runtime validation for non-integer, non-numeric, negative, and out-of-range values. Adds the underlying wrenStringFromByte helper in wren_value.c and exposes it via a new DEF_PRIMITIVE in wren_core.c. Documents the method in the core string markdown and provides six test cases covering happy path and all error conditions.
The include guard macro in src/vm/wren_compiler.h was incorrectly named
wren_parser_h, likely a copy-paste artifact from the parser header.
This change corrects it to wren_compiler_h to match the actual filename
and prevent potential ODR violations when both headers are included.
Replace fixed-size ERROR_MESSAGE_SIZE buffer with dynamically sized array based on MAX_VARIABLE_NAME to avoid stack overflow when formatting error messages for tokens exceeding the original buffer capacity.
Introduce a static inline `wrenHasError` function in `wren_value.h` that encapsulates the `!IS_NULL(fiber->error)` pattern, improving code readability and maintainability. Replace all direct `IS_NULL(fiber->error)` checks across `wren_core.c`, `wren_vm.c`, and the interpreter loop with calls to this new helper. Additionally, clean up commented-out debug print statements and extraneous blank lines in the `trim` methods within the embedded core module source string, and add Michel Hermier to the AUTHORS file.
The core change in wren_vm.c replaces the save/restore pattern for vm->apiStack with a simple NULL assignment after foreign calls, enabling nested wrenCall invocations from within foreign method handlers. This is accompanied by new test files (call_calls_foreign.c/.h/.wren) that verify the re-entrant call path works correctly, along with Makefile and Xcode project updates to build and run the new tests. A minor typo fix in reset_stack_after_call_abort.c renames a handle variable from 'afterConstruct' to 'afterAbort' for consistency.
The previous fixed-size buffer `ERROR_MESSAGE_SIZE` could trigger a compiler warning
about truncation when formatting error labels with maximum-length variable names.
The new buffer size `10 + MAX_VARIABLE_NAME + 4 + 1` precisely accommodates the
format string "Error at '...'" plus the longest possible token name and null terminator,
eliminating the false positive warning on line 449.
The header guard was updated to match the actual filename, preventing potential
conflicts with a separate parser header and improving consistency across the codebase.
Add explicit check in `runFiber()` to reject calls to the root fiber, preventing VM crashes when a completed fiber's caller tries to resume it. Replace the boolean `callerIsTrying` field with a `FiberState` enum (`FIBER_TRY`, `FIBER_ROOT`, `FIBER_OTHER`) to track fiber invocation mode, updating all relevant primitives and initialization. Include new test cases (`call_root.wren`, `call_wren_call_root.*`) and re-entrancy documentation notes.
Replace direct `!IS_NULL(fiber->error)` checks across vm and core files with calls to the new `wrenHasError()` inline function, improving code readability and centralizing the error detection logic.
Remove the dedicated METHOD_FN_CALL method type and its associated arity-checking dispatch logic in the VM. Instead, define a shared `call()` helper that validates argument count and invokes `wrenCallFunction`, then generate individual `fn_call0` through `fn_call16` primitives via a macro. This eliminates the special-case method type while preserving identical behavior for all 17 call overloads.
Also rename the `fn` union member to `as` in the `Method` struct, update all references accordingly, and add a `benchmark_baseline` Makefile target for generating performance baselines.
- Add automatic docs deployment stage for master branch pushes in .travis.yml
- Include python3-markdown, python3-pygments, python3-setuptools, and ruby-sass as build dependencies
- Switch from container-based to sudo-required builds with trusty dist for custom Pygments lexer installation
- Ensure build directory exists before generating docs in Makefile
Introduce a path type classification system (absolute, relative, simple) to distinguish logical imports from relative ones. Implement automatic discovery of a "wren_modules" directory by walking up from the root directory. Refactor the CLI to return interpret results and exit codes instead of exiting directly. Extract cross-platform stat macros into a shared header. Update test API calls to use explicit relative paths.
Implement six new trimming methods on String: trim(), trim(chars), trimEnd(), trimEnd(chars), trimStart(), trimStart(chars). The core logic uses a private trim_ helper that accepts a chars string, converts it to code points, and iterates from the start and/or end of the string to remove matching characters. Default whitespace set is tab, carriage return, newline, and space. Includes comprehensive test coverage for default and custom character trimming, edge cases (empty strings, all-trimmed strings, 8-bit clean data), and runtime error when chars argument is not a string.
Add a bounds check in `forStatement` to ensure there is space for the two hidden local variables (sequence slot and iterator) before calling `addLocal`. Without this check, deeply nested for-loops could overflow the `locals` array, causing a buffer overrun. The fix emits a clear compiler error when `numLocals + 2` exceeds `MAX_LOCALS`, and includes a regression test with 85 nested for-loops that previously triggered the overflow.
When compiling a single expression, the parser now explicitly consumes the TOKEN_EOF token after parsing the expression. This ensures that any trailing garbage or unexpected tokens after the expression are caught and reported as errors, rather than being silently ignored. The comment for the non-expression path is also updated to clarify that it checks for end of file rather than end of block.
Replace strncpy with memcpy in readBuiltInModule to avoid potential string termination issues
when copying module source code, and increase ERROR_MESSAGE_SIZE from 60 to 80 to provide
more room for compiler error messages with long variable names.
Migrate the internal `String` struct to use the heap-allocated `ObjString*` throughout the compiler, debugger, VM, and value system. This unifies string representation, enables proper garbage collection of symbol table entries via new `wrenBlackenSymbolTable` function, and removes manual memory management for symbol names.
Add handling for UTF-8 byte order mark (BOM) at the start of source code
in wrenCompile function by checking for the three-byte sequence \xEF\xBB\xBF
and advancing the source pointer past it. Include a regression test file
(test/regression/520.wren) that contains a BOM to verify the fix works
correctly.
Add a MAX_PARAMETERS bound to the loop in signatureParameterList to prevent
buffer overflow when a method signature has an excessive number of parameters.
A compile error is already reported in such cases, but the unbounded loop could
still write past the end of the name buffer. Also add regression test 494.wren
to cover this scenario.
The compiler now always reserves slot zero for either the closure or method
receiver, eliminating a corner case where top-level REPL code lacked the
pre-allocated slot that function/method bodies expect. This ensures local
variables declared in REPL loops (e.g. `for (i in 1..2)`) get correct slot
indexes.
Additionally, inlines `wrenResetFiber` into `wrenNewFiber` and stores the
imported module's closure on the stack before invoking it, preventing a GC
from collecting the closure during import.
Introduce two new inline functions in wren_value.h: wrenStringEqualStrLength
compares an ObjString against a raw C string with known length, while
wrenStringsEqual compares two ObjString instances using hash pre-check and
delegating to wrenStringEqualStrLength. Refactor wrenSymbolTableFind in
wren_utils.c and wrenValuesEqual in wren_value.c to use these new helpers,
replacing inline memcmp calls for improved code clarity and reuse.
Unify string representation across the codebase by switching SymbolTable and method name storage from a manually-managed `String` struct (char* buffer + length) to `ObjString*` pointers. This eliminates duplicate string allocations in the meta API's `metaGetModuleVariables`, reduces memory management overhead by leveraging the existing GC for symbol strings, and adds `wrenBlackenSymbolTable` to properly trace these GC-roots during collection. The change touches the compiler, debug dumper, VM runtime error formatting, and module variable initialization to use `->value` and `->length` fields directly from `ObjString`.
Consolidate all Obj* type forward declarations from wren_value.h into wren_common.h
to centralize type definitions and reduce header dependencies. Convert anonymous
typedef structs to named structs with sObj* tags for consistent naming convention
across all object types.
The assertion for the `name` parameter in `wrenGetVariable` was incorrectly checking `module != NULL` instead of `name != NULL`. This fix ensures the variable name parameter is properly validated, preventing potential null pointer dereferences when retrieving variables.
Additionally, adds Marshall Bowers to the AUTHORS file.
The getNumArguments function had CODE_IMPORT_MODULE incorrectly returning 1 instead of 2, and CODE_IMPORT_VARIABLE returning 2 instead of 4. Additionally, wrenBindMethodCode had two bugs: it was incrementing ip before reading the instruction, causing incorrect opcode dispatch, and it was using ip++ instead of ip+1 for field offset adjustment, corrupting subsequent bytecode. The super instruction handling also incorrectly skipped over the symbol bytes before reading the constant index.
This breaking API change introduces a new `WrenResolveModuleFn` callback in the configuration that allows the host to canonicalize import module names, enabling relative imports. The `wrenInterpret()` function now requires a `module` parameter to specify the module name for the code being interpreted. The `wrenInterpretInModule()` function is removed in favor of the updated `wrenInterpret()`. The `metaCompile` function now dynamically looks up the caller's module name instead of hardcoding "main". New test files `resolution.c`, `resolution.h`, and `resolution.wren` are added to verify resolver behavior including null default, NULL return error, string rewriting, shared module deduplication, and importer propagation.
Add CODE_END_MODULE opcode to store the current ObjModule in vm->lastModule after module body execution. Modify IMPORT_VARIABLE to load variables from vm->lastModule instead of using a constant string operand for the module name. Update opcode definitions, debug dump, compiler import logic, and interpreter dispatch accordingly. Refactor variable lookup into getModuleVariable helper. Adjust formatting in wren_primitive.c and wren_opt_meta.c.
The compileInModule function now returns a closure directly instead of wrapping it in a fiber, simplifying the compilation pipeline and removing unnecessary fiber overhead for module imports. The wrenImportModule function is moved into wren_vm.c and rewritten to execute the imported module's closure immediately rather than returning a fiber for deferred execution. This change also adds a test for yielding from an imported module to verify correct behavior with the new execution model.
Remove redundant NULL-check branches for module parameter by merging the
wrenPopRoot call into a single conditional after compileInModule, eliminating
the early return path and simplifying control flow in the compilation entry point.
The assertion in `wrenGetVariable` was incorrectly checking `module != NULL` twice,
instead of checking `name != NULL` for the variable name parameter. This fix
ensures the second assertion validates the correct parameter, preventing
potential null pointer dereference when a NULL variable name is passed.
The getNumArguments function had CODE_IMPORT_MODULE incorrectly listed as a 1-argument
opcode and CODE_IMPORT_VARIABLE as a 2-argument opcode. This swap caused incorrect
bytecode parsing during method binding. Additionally, wrenBindMethodCode had two bugs:
the instruction fetch was incrementing ip before reading the opcode, and field offset
patching was using ip++ instead of ip+1, corrupting subsequent bytecode. The super
instruction handling also had an incorrect ip+=2 skip that removed the symbol offset
before reading the constant index.
The switch statement in getNumArguments covers all opcode cases, but the compiler
cannot prove exhaustiveness. Adding UNREACHABLE() followed by return 0 eliminates
the "control reaches end of non-void function" warning on strict compiler settings.