Extract `callMethodInstruction` and `callMethod` helper functions from the
existing `methodCall` function to reduce code duplication and improve
readability. Also fix comment formatting for argument arity overloading
and block argument inclusion.
Extract the duplicated argument list parsing logic from methodCall and
subscript into a shared finishArgumentList function. This unifies the
comma-separated expression parsing, arity tracking, and newline handling
into a single location. Also add a new test case verifying that newlines
after commas and before closing delimiters are correctly handled in both
method calls and subscript expressions.
When a script path contains no '/' character, strrchr returns NULL, causing a crash in the subsequent malloc and memcpy calls. This change adds a NULL check before attempting to extract the root directory, leaving rootDirectory as an empty string when no separator is present.
The monolithic Makefile is replaced with a thin wrapper that invokes
script/wren.mk for each configuration. Build artifacts are now placed
in bin/ (executables) and lib/ (static/shared libraries) instead of
the project root. The .gitignore is updated accordingly, and the
getting-started documentation reflects the new output layout.
Add three new bitwise operators (^, <<, >>) to the Wren compiler and runtime,
including tokenization, parsing with correct precedence, and native method
implementations operating on 32-bit unsigned integers. New test files verify
correct behavior for edge cases including max u32 values and operand type errors.
Create new modules.markdown guide explaining Wren's module system, import syntax, and top-level scoping. Update error-handling.markdown to use "Top-level variable" instead of "Global variable" in error messages. Revise variables.markdown to clarify top-level variable visibility and link to the new modules page. Add "Modules" link to the site navigation template.
Add token definitions for `<<`, `>>`, and `^` in the lexer with proper two-character parsing for shift operators. Register new infix operators at the BITWISE precedence level in the parser grammar. Implement native C functions for bitwise XOR, left shift, and right shift on 32-bit unsigned integers in the core runtime, and bind them as methods on the Num class. Include test files covering edge cases like max u32, overflow, and non-numeric operand errors.
Make the `for` clause in import statements optional, and support comma-separated lists of imported names when present. This removes the previous restriction of exactly one imported variable per import statement.
- Refactor `import()` in compiler to handle optional `for` clause with loop over comma-separated names
- Update existing tests to use comma-separated imports and omit `for` clause where appropriate
- Add new tests: `inside_block`, `name_collision`, `no_variable`
Add map_numeric and map_string benchmark scripts in Lua, Python, Ruby, and Wren to compare hash map insertion/lookup/deletion performance across languages. Register both new benchmarks in the benchmark runner script and fix its language executable paths to use WREN_DIR. Expose a new `IO.time` static method in the C IO module returning `time(NULL)` as a double. In the Makefile, split the monolithic `clean` target into separate removals for build artifacts, wren executables, and library variants to avoid accidental deletion of unrelated files. Remove hardcoded hash singleton constants from wren_value.c as they are no longer used.
Replace the runtime string-based `import_` method call with a new `CODE_IMPORT_VARIABLE` bytecode instruction that directly loads variables from other modules. This eliminates the overhead of calling a native method and string-based module lookup during import, moving the logic into the VM interpreter loop with a dedicated `importVariable` helper function. The change includes adding the opcode to the compiler's `import` function, implementing the runtime lookup in `wren_vm.c`, updating the debug disassembler, and removing the now-unnecessary `string_import` native from `wren_core.c`.
Replace the previous approach of calling a native `loadModule_` method on string objects with a new `CODE_LOAD_MODULE` bytecode instruction. This eliminates the need for the `string_loadModule` native function and the indirect fiber invocation through `PRIM_RUN_FIBER`. The new implementation directly handles module loading in the VM by compiling the module source, creating a fiber, and switching execution contexts. The compiler now emits `CODE_LOAD_MODULE` followed by a `CODE_POP` to discard the unused fiber result, instead of the previous `CODE_CONSTANT` + `CODE_CALL_0` sequence.
The import_ method on String was a builtin that combined module loading and variable lookup. This change removes that method and instead emits separate bytecode instructions in the compiler: first calling loadModule_ on the module, then calling import_ on the module with the variable name. The native function string_lookUpVariable is renamed to string_import to match the new import_ method name on String's metaclass.
The `loadModule_` primitive now returns a fiber when a module is loaded, and the C runtime handles calling it via `PRIM_RUN_FIBER` instead of the Wren code manually invoking the result. This removes the conditional `if (result != null) result.call` from the `import_` method in both the builtin source and the embedded libSource string, and adds `IS_FIBER` macro to `wren_value.h` for type checking in the native implementation.
The loadModule_ primitive now returns NULL for already-loaded modules and an error string for missing modules, shifting the error handling from Wren's Fiber.abort to C's native string return. The Wren import_ method simplifies to only call the result when non-null, removing the false/true branching logic.
Implement a new `IO.time` static method in the Wren IO module that returns the current Unix timestamp as a double by calling `time(NULL)`. This provides a simple way for Wren scripts to obtain wall-clock time, complementing the existing `IO.clock` method which measures CPU time. The method is registered in `wrenLoadIOLibrary` alongside the other IO primitives.
Replace the named constants HASH_FALSE, HASH_NAN, HASH_NULL, and HASH_TRUE
with inline integer literals in the hashValue function, eliminating the
unused HASH_NAN constant and the associated TODO comment about tuning.
Add TOKEN_IMPORT to the token enum and wire it into the keyword parser in readName(). Refactor string literal parsing by extracting stringConstant() helper that returns the constant index, allowing the new import parser to reuse it. Update all module test files to replace the old .import_() method calls with the new import "module" for Var syntax, and add new error test cases for missing string and missing for clause after import.
Extend the clean target in the Makefile to remove libwren.dylib and libwrend.dylib
alongside the existing .a and .so artifacts, ensuring complete cleanup on macOS
builds.
Replace the previous deletion strategy that required rehashing all entries after removal with a tombstone approach. When an entry is removed, its slot is marked with UNDEFINED_VAL key and TRUE_VAL value, allowing linear probing to continue past deleted slots during lookups. This prevents deletion from degrading to near-linear time in the presence of large clusters, matching the approach used by Python and Lua. Also refactor hashValue to hash raw bits of unboxed values under WREN_NAN_TAGGING, and update MapEntry documentation to clarify tombstone semantics.
Add new benchmark files (map_string.lua, map_string.py, map_string.rb, map_string.wren) that test map performance using string keys generated from adverb-adjective combinations. Rename existing numeric map benchmarks from maps.* to map_numeric.* and increase their iteration count from 100k to 1M. Register both benchmarks in script/benchmark.py with their expected output values.
Rename the benchmark script file from `script/run_bench.py` to `script/benchmark.py` and update the internal variable `HOME_DIR` to `WREN_DIR` for clarity, reflecting that the directory points to the Wren project root rather than a generic home directory.
Extract core module loading into separate `loadIntoCore` function and `getCoreModule` helper, replacing the old `getMainModule`. Implement `loadModule` that automatically imports all core module variables into every newly loaded module, enabling implicit visibility of core types (Bool, Class, Fiber, etc.) across all user modules. Add `wrenImportModule` public API for module loading with circular import detection. Increase `WREN_MAX_TEMP_ROOTS` from 4 to 5 to accommodate additional GC roots during module loading. Add test cases for cyclic imports (a.wren/b.wren) and implicit core imports (implicitly_imports_core.wren/module.wren).
The readModule function now concatenates ".wren" to the module path when constructing the full file path, increasing the path buffer by 5 bytes. All test files have been updated to use bare module names (without ".wren") in import_ calls, and the expected error messages in unknown_module and unknown_variable tests are adjusted accordingly. A trailing blank line is also removed from wren_vm.c.
Implement initial module system allowing Wren code to import other modules via a temporary `String.import_` method. The embedder must supply a `WrenLoadModuleFn` callback that returns source code for a given module name; the VM caches loaded modules and returns a fiber to execute the module body. Add `wrenImportModule` to the VM API, wire `loadModuleFn` into `WrenConfiguration`, and update the CLI interpreter to resolve imports relative to the entry script's directory. Include test cases for importing multiple variables, shared imports across modules, and verifying that variable bindings are independent across import sites.
Add Makefile targets for building shared libraries (.so/.dylib) alongside existing static libraries, with platform-specific linker flags for macOS and Linux. Refactor the internal string representation from raw `char*` to a `String` struct that tracks both buffer and length, updating all symbol table operations, debug printing, and string concatenation calls to use the new type. Fix a null-termination bug in `copyName` and add support for the `\0` escape sequence in string literals.
Instead of storing the main module directly in a dedicated field on WrenVM,
store it as a null-keyed entry in the new modules map. This eliminates the
redundant `vm->main` pointer and paves the way for supporting multiple named
modules. The change also adds `wrenFindVariable` as a public helper to look up
top-level variables in the main module, and updates `wrenNewFunction` to accept
an explicit module parameter instead of always using `vm->main`.
Add a period at the end of the "// 8-bit clean" comment in 12 string test files
(concatenation, contains, count, ends_with, equality, index_of, iterate,
iterator_value, join, starts_with, subscript, to_string) to make the comment
grammatically consistent with other comments in the test suite.
Add explicit length parameters to wrenStringConcat to support binary-safe string concatenation, with -1 sentinel for automatic strlen calculation. Implement wrenStringFind using Boyer-Moore-Horspool algorithm for efficient substring search, returning UINT32_MAX when needle not found. Update all callers in wren_core.c validation functions and wren_value.c metaclass creation to pass length arguments. Extend string/index_of.wren tests with edge cases including empty needle, full match, and complex overlapping patterns.
The wrenStringFind function previously returned the haystack length to indicate
a missing needle, which was ambiguous when the needle could legitimately appear
at the end of the string. This commit changes the sentinel value to UINT32_MAX,
updates all callers (string_contains, string_indexOf) to check against the new
sentinel, and adds explicit handling for empty needle and empty haystack edge
cases. The Boyer-Moore-Horspool implementation is also cleaned up with clearer
variable names and comments.
Implement wrenStringFind function using Boyer-Moore-Horspool algorithm with 256-entry shift table for efficient substring matching. Update string_contains, string_indexOf, and string_count native methods to use the new implementation, fixing the empty string corner case to always return true when search string is empty.
Break long wrenStringConcat calls across multiple lines in validateFn,
validateNum, validateIntValue, and validateString functions in
src/wren_core.c to stay within the 80-column limit. Also fix a comment
typo in src/wren_value.h: change "of" to "with" in the wrenStringConcat
documentation.
Add handling for the null character escape sequence '\0' in the readString function within wren_compiler.c. This extends the existing escape sequence handling to include the null character, allowing strings to contain embedded null bytes when explicitly escaped.
Replace all uses of strcpy() and strncpy() with memcpy() followed by explicit null-termination to avoid potential buffer over-reads and undefined behavior from non-null-terminated source strings. This change affects copyName() in wren_compiler.c, wrenSymbolTableAdd() in wren_utils.c, wrenNewFunction() and wrenNewString() in wren_value.c, and defineMethod() in wren_vm.c. Also converts the static "new" string initialization in new_() from strcpy to a C99 compound literal. Additionally fixes a minor whitespace alignment issue in string_endsWith() in wren_core.c.
The constant 2166136261 triggers a warning under GCC when compiling as C++ because it exceeds the maximum value for a signed 32-bit integer. Adding the 'u' suffix explicitly marks it as unsigned, eliminating the compiler warning without changing the hash algorithm's behavior.
Replace the char* based string buffer with a proper String struct that stores both the buffer pointer and length, eliminating strlen() calls in symbol table lookups. Update all symbol table consumers in debug printing, VM method resolution, and GC marking to access the .buffer field. Refactor Value union to use anonymous struct for num/obj fields, and change Obj flags to a bool marked field. Adjust ALLOCATE_FLEX macro to accept separate main type and array type parameters. Add regression test for map subscript on empty map returning null.
The previous implementation of hashValue had UNREACHABLE() placed after the switch statement, which could be reached when using NaN-tagging mode. This fix moves UNREACHABLE() into default cases within each switch branch, ensuring it's only triggered for truly unreachable paths.
Additionally, the Value struct is refactored to use an anonymous union for num and obj fields, preventing undefined behavior from accessing inactive union members. All related macros and inline functions (AS_OBJ, wrenValuesSame, wrenObjectToValue, wrenValueToNum, wrenNumToValue, and singleton value definitions) are updated to use the new `as` union member access pattern.
The macro now takes a main type, array element type, and element count, computing the total allocation as `sizeof(mainType) + sizeof(arrayType) * count`. This improves type safety and clarity at all call sites, which are updated to pass the element type (Upvalue*, Value, char) instead of manually computing byte sizes.
Replace the ObjFlags bitfield approach with a simple bool `marked` field on Obj, removing the FLAG_MARKED constant and all bitwise operations. Also add a guard in wrenMapFind to return UINT32_MAX when map capacity is zero, preventing a crash on empty map subscript lookups. Fix the validateKey function to not wrap the error string in OBJ_VAL.
Introduce conditional detection of Darwin target to set appropriate shared library flags and extension (.dylib instead of .so). Refactor static and shared library build targets into combined `libwren` and `libwrend` phony targets that produce both .a and .dylib/.so files, and update .gitignore to exclude the new .dylib artifacts.
Remove the FLAG_MARKED enum and ObjFlags bitfield, replacing them with a dedicated bool `marked` member in the Obj struct. Update all references in wren_value.c and wren_vm.c to use direct boolean assignment and checks instead of bitwise flag operations. This simplifies the GC marking logic and eliminates the need for manual bit manipulation.
Add early return of UINT32_MAX when map capacity is zero in wrenMapFind,
preventing a crash from modulo operation on zero during hash index calculation.
Includes regression test verifying subscript access on empty map returns null.
Replace the embedded `Module main` field in WrenVM with a pointer to a dynamically allocated `ObjModule`, adding a new OBJ_MODULE object type. Introduce `wrenNewModule()` constructor and `markModule()` GC tracer, update all references from `&vm->main` to `vm->main`, and remove the old `initModule`/`freeModule` static helpers.
Remove the FLAG_MARKED bitfield enum and replace the packed unsigned int flags field with a dedicated bool marked member in the Obj base struct. Update all references in wren_value.c and wren_vm.c to use direct boolean assignment and checks instead of bitwise operations, simplifying the garbage collection marking logic and eliminating the TODO about storing the flag off to the side.
Remove dedicated string equality and inequality native methods (string_eqeq, string_bangeq) and their registration in wrenInitializeCore, since wrenValuesEqual now handles string comparison correctly using memcmp instead of strncmp. Also add a new test file for range equality and inequality checks.
Functions now hold a reference to the module where they were defined and load module-level variables from there instead of from the VM's global table. This introduces a new Module struct with its own variable buffer and symbol table, replacing the VM-level globals and globalNames. The main module is stored directly in the VM as a temporary measure. Performance regresses slightly due to the indirection through the function's module pointer.
Remove the dedicated string equality operators (string_eqeq, string_bangeq) and their NATIVE registrations, switching object_eqeq and object_bangeq to use the generic wrenValuesEqual instead of wrenValuesSame. Also fix wrenValuesEqual to use memcmp instead of strncmp for string comparison. Add a new test file test/range/equality.wren verifying inclusive and exclusive range equality and inequality.
Eliminate the LIST opcode and its interpreter case, debug printing, and enum entry. Instead compile list literals by loading the List class, calling its constructor, then emitting DUP, element expression, CALL_1 for add(), and POP for each element. This removes interpreter loop code and lifts the previous 255-element limit on list literals.
Implement hexadecimal number literal support in the Wren compiler by adding a `number` field to the Parser struct, a `readHexDigit` helper that returns -1 for invalid hex chars, and a `readHexNumber` function that skips the 'x' prefix, accumulates hex digits, converts via strtol, and emits a TOKEN_NUMBER. Update `readNumber` to remove the TODO placeholder for hex support. Include test cases for valid hex literals (0xFF, 0x09, negative -0xFF) and an invalid hex literal (2xFF) that triggers a lex error.
Implement `containsKey()` native method on Map that returns a boolean indicating whether the given key exists in the map. Add `validateKey()` helper to reject non-value-type keys (objects, lists, fibers, etc.) with a clear runtime error. Refactor `wrenMapGet()` signature to return success/failure via bool and output the value through an out-parameter, enabling both `containsKey()` and the existing subscript operator to share the same key validation and lookup logic. Update `map_subscript` to return `null` instead of crashing when a key is not found. Add test cases for `containsKey` success/failure, and runtime error tests for invalid key types in subscript getter, setter, and containsKey.
Add MapKeySequence and MapValueSequence classes in core.wren to expose iterable key and value views on Map instances. Implement native iterate_, keyIteratorValue_, and valueIteratorValue_ primitives in wren_core.c to support these sequences. Replace the stub Map.toString with a full implementation that iterates keys and formats each entry as "key: value", handling empty maps and nested maps correctly. Include comprehensive test suites for key iteration, value iteration, iterator type validation, and toString output across multiple orderings.
Add DEF_NATIVE(map_clear) that frees the underlying entries array and resets
capacity and count to zero, returning null. Register the "clear" method on
the Map class in wrenInitializeCore and include a test verifying the map is
emptied and the return value is null.
Add support for map literals using `{}` syntax in the compiler, replacing the previous `new Map` constructor pattern. This introduces a new `map()` grammar function that loads the Map class, instantiates it, and compiles key-value pairs using subscript setter calls. A new `CODE_DUP` bytecode is added to duplicate the map reference on the stack for each element insertion. The change includes updated test files to use literal syntax and new error tests for edge cases like EOF after colon, comma, key, or value.
Implement the core Map data structure in Wren, including the ObjMap type with
hash table storage, native methods for instantiation, subscript get/set, and
count. Add Map class declaration to core.wren with a basic toString stub.
Introduce MapEntry struct and hash table growth logic with configurable load
factor. Add test files for map creation, count tracking, key type support
(including null, bool, num, string, range, and class keys), and growth
behavior. Refactor list capacity constants into shared MIN_CAPACITY and
GROW_FACTOR macros. Change object equality operators to use wrenValuesSame
instead of wrenValuesEqual.
Add a public `arity` getter to the Fn class that returns the number of required arguments for a function. Internally rename the `numParams` field to `arity` across the codebase for consistency, update the C API parameter name from `numParams` to `arity` in `wrenDefineMethod` and `wrenDefineStaticMethod`, and adjust the error message in `callFunction` to use the new field name. Also update documentation to clarify that extra arguments are ignored rather than causing an error, and add a new test file `test/function/arity.wren` verifying arity values from 0 to 4.
Add Visual Studio 2013 solution and project files under project/msvc2013/ directory, enabling native Windows builds without MinGW. Include Marco Lizza in AUTHORS for the contribution. Fix C89 compatibility issues for MSVC: disable computed goto via _MSC_VER check, define inline as _inline for non-C++ mode, change flexible array members from empty brackets to [0] syntax, and fix char to int type for readHexDigit return value. Refactor single-line if/while/for bodies in wren_compiler.c to use braces to satisfy MSVC stricter parsing.
Add String as a subclass of Sequence in core.wren and implement the iterator protocol for strings in wren_core.c. The string_iterate native advances through UTF-8 code point boundaries, while string_iteratorValue extracts the full code point at a given byte index. Includes comprehensive test coverage for iteration, edge cases (empty strings, mid-sequence positions), and error handling for invalid iterator types and out-of-bounds indices. Also updates documentation for String, List, and Sequence classes with iterator protocol details and usage examples.
Add runtime type validation to wrenGetArgumentBool, wrenGetArgumentDouble, and
wrenGetArgumentString in src/wren_vm.c, replacing TODO comments with actual
checks that return safe defaults (false, 0.0, NULL) on type mismatch.
Remove the unused wrenReturnNull function entirely from the VM implementation.
Update include/wren.h documentation for argument accessor functions to clarify
indexing semantics (including receiver at index 0) and document the new
type-checking behavior.
The diff reorders the `children` array of the `src` group in the Xcode project file,
moving `.c` files after their corresponding `.h` headers to match a consistent
header-before-source convention.
The modulo operator was incorrectly assigned PREC_TERM precedence, causing it to
bind less tightly than multiplication and division. This change promotes it to
PREC_FACTOR, matching the standard mathematical precedence where `%` has the
same binding strength as `*` and `/`.
A test case `IO.print(13 + 1 % 7)` is added to verify the fix, expecting `14`
(equivalent to `13 + (1 % 7)`) rather than the incorrect `(13 + 1) % 7 = 0`.
Rename all instances of "pinned" objects to "temporary roots" in wren_vm.c, wren_vm.h, and wren_common.h to better describe their stack-based lifecycle. Update the WREN_MAX_PINNED constant to WREN_MAX_TEMP_ROOTS, rename the vm->pinned array to vm->tempRoots, and rename vm->numPinned to vm->numTempRoots. Adjust all related comments and assertions to reflect the new terminology, including the GC stress test comment in wren_common.h.
Refactor parameter list parsing to support bracket-delimited parameters for
subscript operators. Extract finishParameterList from parameterList to handle
the common closing logic, and add TOKEN_RIGHT_BRACKET case for error messages.
Add comprehensive test suite for subscript getters and setters with 1-3
parameters in test/method/subscript_operators.wren.
- Insert "Getting acquainted" section in contributing guide with mailing list invitation
- Add proposal link for significant changes discussion before coding
- Promote mailing list as primary contact method in getting-started page
- Add link references for list, twitter, issue, and repo in getting-started
- Relocate wren.xcodeproj into project/xcode/ subdirectory
- Remove build_xcode/ from .gitignore as it is no longer at root level
- Update all internal PBXBuildFile references to use new file paths
The AS_OBJ macro on NaN-tagged architectures was performing a direct cast from
uint64_t to Obj* which triggers a pointer-to-integer cast warning on 32-bit
MinGW where sizeof(Obj*) is 4 bytes. Adding an intermediate cast to uintptr_t
ensures the value is properly truncated before conversion to the pointer type.
Also replaces IS_SINGLETON macro usage with direct NULL_VAL/UNDEFINED_VAL
comparisons and removes the now-unused IS_SINGLETON definition.
The CalculatedRange struct is removed from the header and calculateRange now returns the start index directly while using pointer parameters for length and step, simplifying the API and reducing struct overhead.
Extract range validation logic into a reusable `calculateRange` function that handles inclusive/exclusive bounds, negative indices, and direction stepping. Add `CalculatedRange` struct to `wren_core.h` and implement string subscript tests covering forward, backward, negative, and half-negative ranges along with comprehensive error cases for out-of-bounds and non-integer range endpoints.
Replace signed `int` with unsigned `uint8_t` for field indices in LOAD_FIELD_THIS, STORE_FIELD_THIS, LOAD_FIELD, and STORE_FIELD opcodes, and with `uint16_t` for jump offsets in JUMP, LOOP, and JUMP_IF opcodes. This eliminates sign-extension overhead and enables better code generation, yielding 1-7% performance gains across binary_trees, delta_blue, fib, for, and method_call benchmarks.
The consume() function previously returned a pointer to the consumed token,
and consumeLine() returned a boolean indicating success. Both return values
were never used by any callers. This change converts both functions to void,
eliminating dead code and simplifying the interface.
Add a new public API function `wrenGetArgumentBool` to the Wren VM that
allows foreign method implementations to retrieve boolean arguments from
the foreign call slot. The implementation includes assertions for null
slot, non-negative index, and bounds checking against the number of
arguments, and uses the existing AS_BOOL macro to extract the boolean
value from the slot.