Commit Graph

238 Commits

Author SHA1 Message Date
Paul
c2da44aa62 fix: return false instead of NULL in findEntry for zero-capacity map lookup 2016-07-02 11:40:00 +00:00
Bob Nystrom
d955842cf9 perf: add hashBits mixing function to fix integer hash collisions in map
The raw XOR of double's 32-bit halves causes small integers to have zero low bits,
mapping all small integer keys to entry zero in the hash map. This introduces a
bit-mixing function inspired by Java's HashMap that sloshes high bits downward,
eliminating the pathological collision pattern. The map_numeric benchmark improves
by ~18%, and a contrived benchmark with keys up to 1000 becomes 52x faster.
2016-06-27 15:13:45 +00:00
Bob Nystrom
adad9f4b26 fix: prevent duplicate keys by reusing tombstones in map probe sequence
Previously, when inserting a key that already existed in the map but was
located after a tombstone in the probe sequence, the insertion would stop
at the first tombstone and add the key there, resulting in duplicate
entries for the same key. This fix introduces a `findEntry` function that
tracks the first encountered tombstone during probing and reuses it for
insertion only when the key is not found elsewhere in the sequence.
2016-06-27 14:14:52 +00:00
Bob Nystrom
a44b210191 fix: allow optional module loading when host omits loadModuleFn
Previously, wrenImportModule unconditionally called vm->config.loadModuleFn,
causing a crash when the host did not set that function pointer. Now the
call is guarded by a NULL check, so hosts without a module loader can still
load built-in optional modules like "random" or "meta".
2016-06-27 14:08:08 +00:00
Bob Nystrom
c726845c42 feat: implement expression evaluation and statement detection in REPL with Meta.compileExpression
Add executeInput() method to REPL that lexes input, determines if it's a statement or expression based on the first token, and evaluates accordingly using Meta.eval for statements or the new Meta.compileExpression for expressions. Extend Meta.compile_ foreign method with isExpression and printErrors parameters, update wrenCompile signature to support expression compilation mode, and add newline handling after equals in variable definitions.
2016-05-21 06:03:05 +00:00
Bob Nystrom
1de17224e8 feat: add wrenAbortFiber() API to abort current fiber with runtime error object
Add a new public API function `wrenAbortFiber()` that allows foreign methods to abort the currently executing fiber with a custom runtime error object. The function validates the API slot, then sets the fiber's error field to the value in the specified slot. The interpreter loop is updated to check for a non-null fiber error after calling a foreign method, triggering a runtime error if set. New test files (error.c, error.h, error.wren) demonstrate usage via a static Error.runtimeError foreign method, verifying that the error is propagated through Fiber.try() and that the fiber's isDone and error properties are correctly set. Xcode project updated to include the new error.c source file.
2016-06-10 02:14:21 +00:00
Bob Nystrom
caee692c32 docs: rename WrenValue to WrenHandle across embedding docs and C API
Rename the `WrenValue` type to `WrenHandle` in the public C header, update all
function signatures (`wrenMakeCallHandle`, `wrenCall`, `wrenReleaseHandle`),
and rename the documentation page from "Slots and Values" to "Slots and Handles"
with corresponding link updates throughout the embedding guide and module source
files.
2016-05-21 03:55:28 +00:00
Bob Nystrom
d717f0f174 fix: count subscript parameters in wrenMakeCallHandle for bracket signatures
Add missing loop to count underscore parameters in subscript operator signatures
starting with '['. Previously only counted parameters in parenthesized signatures,
causing incorrect arity for methods like `[_,_]` and `[_,_]=(_)`. Also adds
validation assertions for null and empty signatures, and extends test coverage
with unary, binary, subscript, and subscript-set operator call handles.
2016-05-04 13:29:44 +00:00
Bob Nystrom
07613f4eb0 style: align pointer asterisk to type name in MapEntry declarations across wren_value.c 2016-05-02 23:23:52 +00:00
Bob Nystrom
19fc5e7534 feat: always wrap functions in closures to simplify VM and improve invocation performance
Simplify the VM by ensuring all called objects are closures, removing the need for runtime checks between bare functions and closures. This eliminates the `IS_FN`/`IS_CLOSURE` branching in `validateFn`, `checkArity`, `bindMethod`, and `wrenNewFiber`, and changes `CallFrame.fn` from `Obj*` to `ObjClosure*`. The compiler now emits `CODE_CLOSURE` for all function declarations, even those without upvalues, trading a small allocation cost at declaration time for faster and more uniform invocation. Benchmarks show performance is neutral to slightly improved across all tested workloads.
2016-03-26 21:00:17 +00:00
Bob Nystrom
82103a64f9 refactor: replace eager optional module loading with lazy source and foreign method hooks 2016-03-17 14:49:43 +00:00
Bob Nystrom
7e72462d90 feat: add WrenErrorType enum and route runtime errors through config errorFn callback
Replace direct fprintf(stderr) calls in wrenDebugPrintStackTrace with invocations of the host-provided errorFn callback, passing WREN_ERROR_RUNTIME for the error message and WREN_ERROR_STACK_TRACE for each stack frame. Introduce the WrenErrorType enum in wren.h with WREN_ERROR_COMPILE, WREN_ERROR_RUNTIME, and WREN_ERROR_STACK_TRACE values, update the WrenErrorFn typedef to accept a type parameter, and modify reportError in cli/vm.c to switch on the error type for formatted output. Adjust wrenDebugPrintStackTrace signature to take WrenVM* instead of ObjFiber* to access the config, and update all call sites accordingly.
2016-03-17 14:17:03 +00:00
Bob Nystrom
63e462bb84 chore: remove unused stdarg.h, stdio.h, and stdlib.h includes from wren_compiler.c and wren_value.c 2016-03-17 14:04:09 +00:00
Bob Nystrom
d9ec3627cf feat: add WrenErrorFn callback to WrenConfiguration for custom error reporting
- Add `WrenErrorFn` typedef in wren.h accepting module, line, and message parameters
- Include `errorFn` slot in `WrenConfiguration` struct with documentation comment
- Initialize `errorFn` to NULL in `wrenInitConfiguration()` in wren_vm.c
- Replace direct `fprintf(stderr, ...)` in wren_compiler.c with call to `parser->vm->config.errorFn()`
- Add guard in wren_compiler.c to skip error reporting when `errorFn` is NULL
- Implement `reportError()` in cli/vm.c that writes formatted errors to stderr
- Wire `reportError` into config during `initVM()` in cli/vm.c
2016-03-16 15:04:03 +00:00
Bob Nystrom
f16e5c775f feat: report undefined variable errors on the line where they are used
Store the line number of first use in implicitly declared variables as a numeric value, then synthesize a token at that line when reporting the error, ensuring bounded error message length even for pathologically long variable names.
2016-03-16 15:00:28 +00:00
Bob Nystrom
5d42ce9ad6 refactor: extract duplicate method detection into declareMethod helper and rename instanceMethods buffer to methods 2016-03-15 14:15:55 +00:00
Bob Nystrom
1d546cf840 feat: prevent duplicate method definitions in class compilation
Add tracking of static and instance method names during class compilation to detect and report duplicate method definitions. Introduce `hasMethod` helper function and `staticMethods`/`instanceMethods` buffers in the `ClassCompiler` struct, along with a `name` field for identification. Include a new test case `duplicate_methods.wren` verifying error generation for duplicate instance and static methods, while allowing same-named methods across static/instance boundaries.
2016-03-15 13:54:49 +00:00
Bob Nystrom
c33dc205c3 chore: remove unused DUP opcode from compiler, debug, opcodes, and VM interpreter 2016-03-14 05:11:21 +00:00
Stephen Belanger
7913424c1c feat: replace generic BufferFind with dedicated hasMethod for duplicate detection
Replace the generic `wrenIntBufferFind` function with a specialized `hasMethod` helper that performs exact method symbol matching in the compiler. This change removes the generic `BufferFind` macro from the buffer utility system and introduces a focused implementation in `wren_compiler.c` that directly compares method symbols using `memcmp`. The error message for duplicate methods is also simplified to exclude the module name. Additionally, a new test file `duplicate_methods.wren` is added to verify error handling for duplicate instance and static method definitions.
2016-03-13 03:14:19 +00:00
Bob Nystrom
c30ee8a297 refactor: consolidate compile error formatting into single printError helper
Replace multiple fprintf calls in lexError and compileError with a unified printError function that formats the entire error message into a fixed-size buffer before outputting it as a single fprintf call. This centralizes error formatting logic and prepares for future integration of a host-provided error callback by eliminating scattered fprintf invocations.
2016-03-12 05:30:54 +00:00
Bob Nystrom
51d1bb6b3a refactor: move shebang detection into default case and remove separate '#' branch 2016-03-12 01:23:31 +00:00
Bob Nystrom
0f18db0097 refactor: move compiler function state directly into ObjFn to eliminate copying on completion 2016-03-04 15:49:34 +00:00
Bob Nystrom
53f4cb15c9 fix: remove wrenSetCompiler and fix compiler root not being popped on error 2016-03-04 01:48:47 +00:00
Bob Nystrom
d4df37703d refactor: replace manual error assignment with RETURN_ERROR and RETURN_ERROR_FMT macros across validation and fiber functions
Consolidate repetitive `vm->fiber->error = wrenStringFormat(...)` and `return false` patterns into two new macros defined in wren_primitive.h, reducing code duplication and improving consistency in error reporting for fiber operations, number parsing, and type validation helpers.
2016-03-04 01:11:52 +00:00
Bob Nystrom
db5223d14d feat: unify Fiber.try() error messages with call/transfer by adding verb parameter to runFiber
Add a `verb` string parameter to the `runFiber` helper function so that
`Fiber.try()` produces consistent error messages like "Cannot try a finished
fiber." instead of the previous generic fallback. Update all call sites
(`fiber_call`, `fiber_call1`, `fiber_transfer`, `fiber_transfer1`) to pass
the appropriate verb string, and add a new test case `try_error.wren`
verifying the error message for trying an aborted fiber.
2016-03-04 01:00:33 +00:00
Bob Nystrom
1ef9b77842 refactor: rename allowAssignment to canAssign and simplify parsePrecedence signature in wren_compiler.c 2016-03-04 00:30:48 +00:00
Bob Nystrom
b2469990c0 test: add test for creating a VM with null config and fix wrenNewVM to handle NULL config 2016-03-03 22:31:47 +00:00
MADGameStudio
1fed0800d1 fix: add NULL config check and fallback to defaults in wrenNewVM
When wrenNewVM is called with a NULL config pointer, the previous code
dereferenced it without checking, causing a crash. This commit adds a
NULL guard: if config is NULL, the VM is allocated using the default
reallocator and initialized with default configuration via
wrenInitConfiguration. The gray array allocation and nextGC field now
correctly reference vm->config instead of the potentially NULL config
parameter.
2016-03-03 16:58:50 +00:00
Stephen Belanger
b9b9611a8c fix: replace SymbolTable with IntBuffer for per-scope duplicate method detection 2016-02-28 20:53:34 +00:00
Bob Nystrom
443749b55d fix: correct typo 'wrenUpwrapClosure' to 'wrenUnwrapClosure' across multiple files
Fix the misspelled function name `wrenUpwrapClosure` to the correct `wrenUnwrapClosure` in wren_debug.c, wren_value.c, wren_value.h, and wren_vm.c. Also fix a minor grammar typo in wren_vm.c comment changing 'arguments' to 'argument'.
2016-02-28 00:23:48 +00:00
Bob Nystrom
06dad18184 docs: fix grammar and formatting in Wren VM comments and code 2016-02-28 00:05:50 +00:00
Bob Nystrom
0fde331974 refactor: replace import opcodes with core method calls for module loading
Remove CODE_LOAD_MODULE and CODE_IMPORT_VARIABLE opcodes, replacing them with calls to System.importModule(_) and System.getModuleVariable(_,_) primitives. This simplifies the interpreter loop, improves performance by reducing bytecode dispatch, and prepares for moving module loading logic into Wren source code for embedder flexibility.
2016-02-27 06:43:54 +00:00
Bob Nystrom
aca69b34e6 refactor: merge block() into statement() and remove redundant curly-block parsing
The block() function duplicated the curly-block parsing logic that statement() already handled for single-expression bodies. By removing block() and replacing its single call site in loopBody() with statement(), the compiler eliminates unnecessary indirection and simplifies the control flow parsing. The statement() comment is updated to clarify that it excludes variable binding statements like "var" and "class" which are not allowed in if-branch positions.
2016-02-25 15:04:48 +00:00
Bob Nystrom
b301e9f119 feat: implement eager * operator for String and List to repeat content by integer count
Add `*(count)` method to both String and List classes in wren_core.wren, enabling eager repetition of string characters or list elements. The operator validates that count is a non-negative integer, aborting with a clear error message otherwise. For strings, concatenates the original string count times; for lists, builds a new list by adding all elements count times. Includes comprehensive test cases for normal, zero, and edge-case inputs, plus error tests for negative, non-integer, and non-numeric counts. Also refactors existing list plus tests to use inline expressions and adds a plus_not_iterable error test.
2016-02-24 15:48:03 +00:00
Bob Nystrom
c9390c624b fix: add missing code block marker in list docs and simplify parens increment in compiler
- Add missing `:::wren` code block marker before the `removeAt` example in the list documentation to ensure proper syntax highlighting.
- Simplify the `parens` array increment in `readString` by combining the assignment and post-increment into a single expression.
2016-02-24 14:52:12 +00:00
Stephen Belanger
ed94957e91 feat: add duplicate method detection in class compiler with error reporting
Introduce a `methods` symbol table and `name` field to `ClassCompiler` struct to track method signatures during compilation. When a method is defined, check for existing entries in the table and emit a compile error if a duplicate is found, preventing silent method overrides. Initialize the class name string before class definition processing to support error messages referencing the class name.
2016-02-24 06:07:08 +00:00
Bob Nystrom
7f744565fc feat: convert Stat from Wren class with list fields to foreign class with native C accessors
Replace the Wren-implemented Stat class that stored stat fields in a list with a foreign class backed by the raw uv_fs_stat struct, enabling direct C-level access to stat data for future methods like isDirectory() using S_ISDIR().
2016-02-21 19:34:10 +00:00
Bob Nystrom
d53f9fa477 fix: include stdio.h for printf usage under debug trace flags in wren_vm.c 2016-02-20 21:36:22 +00:00
Bob Nystrom
fe3997f825 feat: add wrenGetSlotType API to query low-level type of object in a slot
Introduce a new public C API function wrenGetSlotType() that returns the
underlying representation type (bool, num, foreign, list, null, string,
or unknown) of the object stored in a given VM slot. This allows C
extensions to inspect slot contents without needing to call individual
type-checking functions or handle errors from mismatched accessors.

The implementation in wren_vm.c uses the existing IS_* macros to
determine the type and returns the corresponding WrenType enum value.
A new WrenType enum is added to wren.h with WREN_TYPE_BOOL,
WREN_TYPE_NUM, WREN_TYPE_FOREIGN, WREN_TYPE_LIST, WREN_TYPE_NULL,
WREN_TYPE_STRING, and WREN_TYPE_UNKNOWN.

Test coverage is added in test/api/slots.c with a slotTypes() foreign
method that verifies all seven type values, and a ForeignType foreign
class is introduced in slots.wren to provide a foreign object for
testing WREN_TYPE_FOREIGN. The test harness in main.c is updated to
support binding foreign class allocate methods via slotsBindClass().
2016-02-19 15:18:00 +00:00
Bob Nystrom
5d04ed2aed fix: add overflow check for jump distance in patchJump and emit error on too much code
Add a MAX_JUMP constant set to 2^16 and validate jump distance in patchJump to prevent silent overflow when bytecode exceeds the maximum representable offset. Also remove the TODO comment in endLoop since the forward jump error will be caught by patchJump. Include test cases jump_too_far.wren and loop_too_far.wren to verify the compiler correctly reports "Too much code to jump over." for both conditional and loop constructs.
2016-02-19 14:57:38 +00:00
Bob Nystrom
cdf3b64ab2 refactor: replace classSlot int with Variable struct in defineMethod and method
Replace the integer `classSlot` parameter with a `Variable` struct in both `defineMethod()` and `method()` functions, removing duplicate code that handled top-level vs local class loading by delegating to the new `loadVariable()` helper.
2016-02-12 15:43:44 +00:00
Bob Nystrom
6367195722 perf: replace strncmp with memcmp in variable declaration and resolution
In both declareVariable and resolveLocal functions within wren_compiler.c,
the string comparison using strncmp is replaced with memcmp since the
length parameter is already known and null-termination checking is
unnecessary for these fixed-length identifier comparisons. This avoids
the overhead of scanning for null terminators when comparing local
variable names against token or parameter strings.
2016-02-12 15:27:42 +00:00
Bob Nystrom
18bedf45e1 feat: introduce Variable struct to replace raw index and load instruction pair
Replace the ad-hoc output parameter pattern in resolveNonmodule with a proper Variable struct that bundles the variable's index and scope (local, upvalue, or module). This makes variable references a first-class concept in the compiler, eliminating the need to pass around a separate Code pointer for load instructions and improving code clarity throughout the compilation pipeline.
2016-02-12 15:16:41 +00:00
Bob Nystrom
87334da1df feat: replace wrenAllocateForeign with wrenSetSlotNewForeign supporting arbitrary slot and class selection
The old wrenAllocateForeign was limited to slot 0 and the class at the top of the API stack. The new wrenSetSlotNewForeign takes explicit slot and classSlot parameters, allowing foreign objects to be created in any slot from any class. All internal and test call sites updated to use the new API.
2016-01-24 17:25:04 +00:00
Bob Nystrom
deb833b1d8 feat: replace manual byte-buffer parsing with native C list creation in Directory.list()
The C directoryListCallback now directly builds a Wren list using wrenSetSlotNewList and wrenInsertInList, eliminating the temporary byte buffer that required manual splitting in Wren. The Wren side is simplified to a single return of the scheduler result. Additionally, the wrenCall and wrenCaptureValue functions are hardened: wrenCall discards extra temporary slots and calls with arity 0, wrenCaptureValue properly roots/unroots object values during handle creation, and the debug stack trace printer skips stub functions with NULL module pointers. A new test case verifies that wrenCall correctly ignores extra temporary slots on the stack.
2015-12-29 16:37:47 +00:00
Bob Nystrom
9f48ac681c feat: replace wrenGetMethod with slot-based wrenCall API using wrenMakeCallHandle and wrenEnsureSlots
Refactor the C API for invoking Wren methods from C code. Remove the old
wrenGetMethod and wrenCallVarArgs functions that used a type-string-based
argument marshalling system. Introduce a new slot-based approach where
callers first call wrenEnsureSlots to reserve space, then use wrenSetSlot___
functions to place the receiver and arguments on the stack, and finally call
wrenCall with a handle created by wrenMakeCallHandle. Results are retrieved
via wrenGetSlot___. This change simplifies the VM internals, eliminates
varargs parsing overhead, and yields a 185% speed improvement in the call
benchmark. Update all internal modules (scheduler, io, timer) and test files
to use the new API. Also fix fiber suspension to clear the API stack pointer
and adjust the interpreter to store the final fiber result at stack[0] for
C API access.
2015-12-29 15:58:47 +00:00
Bob Nystrom
1797c6c977 refactor: replace finalizer fiber with raw data pointer callback
Remove the dedicated finalizer fiber from WrenVM and change finalizer functions to accept a void* data pointer instead of a full WrenVM reference. This prevents user code from interacting with the VM during garbage collection, simplifying the GC path and eliminating the need for pre-allocated fiber infrastructure. Update the WrenForeignClassMethods struct, all built-in finalizers (file, test), and the binding/calling logic accordingly.
2015-12-28 16:06:29 +00:00
Bob Nystrom
6abebbe906 feat: expose wrenEnsureSlots API and rename foreignStackStart to apiStack for slot access outside foreign methods
Replace the internal `foreignStackStart` pointer with a public `apiStack` field
that tracks the base of available C API slots. Extract the static
`ensureStack` helper into a non-static `wrenEnsureStack` function declared in
the header, enabling `wrenEnsureSlots()` to create a fiber and stack when
called outside a foreign method. Update `callForeign` to use `apiStack` and
adjust `metaCompile` to write results through the new pointer. Add a
`ensureOutsideForeign` test that allocates slots on a fresh VM, verifies
slot count grows from 0 to 20, and exercises all 20 slots with double values
to confirm the stack is correctly initialized and usable.
2015-12-28 15:43:17 +00:00
Bob Nystrom
278d66bdc1 feat: use dedicated fiber for foreign finalizer stack to avoid allocation during GC
The finalizer fiber is pre-allocated in the VM and reused for each finalizer call, replacing the previous approach that used a raw stack pointer. This ensures no memory allocation occurs during garbage collection when finalizers are invoked. The change also properly resets the fiber after each finalizer call and updates the GC rooting to include the new fiber.
2015-12-28 05:43:08 +00:00
Bob Nystrom
633dbfeed1 feat: add Directory.list() foreign method and async directory listing to io module 2015-12-27 04:42:53 +00:00