The finishParameterList function no longer needs to consume the closing delimiter
or produce error messages, as that responsibility has been moved to the callers.
The parameterList wrapper function has been inlined into its single call site,
simplifying the parameter parsing flow.
- Compile empty `()` as a valid method signature distinct from no parentheses
- Update `call()`, `clear()`, `run()`, `try()`, and `yield()` to use empty argument lists
- Revise documentation across multiple files to reflect new signature semantics
The method signature format has been changed from space-counted arity (e.g., "== ") to explicit parenthesized parameter lists (e.g., "==(_)"). This required updating the MAX_METHOD_SIGNATURE calculation to account for parentheses and parameter separators, replacing the old copyName helper with a new Signature struct and SignatureType enum, and rewriting the methodNotFound error message to display the full signature string instead of reconstructing arity from trailing spaces. All core method registrations in wren_core.c, wren_io.c, and corresponding test expectations have been updated to use the new signature format.
The wrenDefineMethod and wrenDefineStaticMethod functions now accept a single `signature` string parameter instead of separate `methodName` and `arity` arguments. This simplifies the API by letting callers specify the full method signature (including arity spaces) directly, removing the internal arity-to-spaces conversion logic in defineMethod. The change updates the header declaration, the internal defineMethod helper, and all call sites in wren_io.c to pass pre-formatted signatures.
Add new Precedence enum values (PREC_BITWISE_OR, PREC_BITWISE_XOR, PREC_BITWISE_AND, PREC_BITWISE_SHIFT) and a PREC_TERNARY level between assignment and logical operators. Update and_(), or_(), and conditional() to use the refined precedence constants. Include a test file verifying correct associativity and precedence ordering among bitwise operators (|, &, ^, <<) in expressions.
Previously, `Num.fromString` accepted strings like `"1.2prefix"` and returned the
leading numeric portion (`1.2`). This change makes parsing stricter by requiring
that the entire string be consumed after `strtod`, skipping only trailing
whitespace. If any non-whitespace characters remain after the number, the
function now returns `null` instead of a partial result.
The fix also adds an explicit empty-string check and updates the test suite to
reflect the new behavior, replacing the old `"1.2prefix"` success test with a
`"1.2suffix"` null-return test.
Implement a new `Num.fromString(value)` method that attempts to parse a string as a decimal literal and returns the corresponding `Num` instance, or `null` if parsing fails. The implementation uses `strtod` for conversion, validates the argument is a string at runtime, and includes tests for valid numbers, edge cases like leading/trailing whitespace and partial suffix parsing, non-number inputs returning null, and a runtime error when a non-string argument is passed. Also fixes a missing semicolon in the `toString` native registration and removes the hex literal TODO from the number literals test.
- Change `int` to `uint32_t` for iterator indices in `map_iterate` and `string_iterate` to match capacity/length types
- Update `String.length` field type from `int` to `uint32_t` in `wren_utils.h`
- Modify `wrenStringCodePointAt` parameter type from `int` to `uint32_t` and remove redundant negative index assertion
- Convert loop variable in `markMap` from `int` to `uint32_t` to match `map->capacity` type
- Add `-Wsign-compare`, `-Wtype-limits`, and `-Wuninitialized` compiler flags to catch future mismatches
The UINT32_MAX macro is defined in <stdint.h> but was not included, causing
compilation errors on platforms where it is not implicitly pulled in by other
headers. This commit adds the missing include to ensure the constant is
available for use in the source file.
Add before_install step to .travis.yml that updates apt packages and installs
gcc-multilib, enabling 32-bit C library headers and runtime for cross-compilation
in the CI environment.
The baseline file path was hardcoded as "benchmark/baseline.txt" in both read_baseline() and generate_baseline() functions, ignoring the BENCHMARK_DIR constant. This caused the baseline file to be created in the wrong directory when BENCHMARK_DIR differed from the default "benchmark" path. Changed both functions to construct the path using os.path.join(BENCHMARK_DIR, "baseline.txt") for consistency and correctness.
Remove conditional getcwd logic for MSVC and POSIX, replacing it with a simple
empty root directory string. This simplifies the import path resolution by
always using relative paths from the current working directory instead of
attempting to resolve an absolute root path at startup.
- Add platform-specific getcwd header includes for MSVC and POSIX
- Replace malloc-based rootDirectory assignment with a static 2048-byte buffer
- Initialize rootDirectory to point to the static buffer instead of an empty string
- Update runFile to use const char* for lastSlash and copy path directly into buffer
- Implement TODO in runRepl by calling getcwd to set rootDirectory to current working directory
Initialize vm->modules to NULL in wrenNewVM and create a module registry map to track loaded modules. In loadModule, check if a module has already been loaded via wrenMapFind; if found, reuse the existing module object instead of creating a new one, enabling successive wrenInterpret calls to execute in the same module context and preserve variable bindings across REPL invocations.
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.