Commit Graph

100 Commits

Author SHA1 Message Date
Bob Nystrom
520e841044 feat: add specialized LOAD_LOCAL_0..8 instructions to skip arg byte decode
Introduce nine new bytecode instructions (CODE_LOAD_LOCAL_0 through CODE_LOAD_LOCAL_8) that directly encode the local slot number in the opcode itself, eliminating the need to read and decode a separate argument byte for the most frequently accessed local variables. This optimization targets the hottest path in the interpreter, as LOAD_LOCAL is the most executed instruction across benchmarks (e.g., 3.75M times in delta_blue). The compiler's `loadLocal` helper emits the specialized opcode when the slot index is ≤8, falling back to the generic `CODE_LOAD_LOCAL` with an argument byte otherwise. The VM dispatch table and debug printer are updated accordingly. Benchmarks show consistent speedups: fib +7.3%, method_call +5.9%, binary_trees +1.9%, for +2.8%, delta_blue +1.0%.
2014-12-07 03:59:11 +00:00
Bob Nystrom
9b498b4638 fix: ensure all switch and unreachable paths return a value in release builds
In `getNumArguments`, add a `return 0` after the `UNREACHABLE()` default case to prevent
undefined behavior when assertions are disabled. In `wrenGetClass`, reorder the
`UNREACHABLE()` macro before the `return NULL` so the unreachable annotation is
always emitted. In `runInterpreter`, replace the `ASSERT(0, ...)` with an explicit
`UNREACHABLE()` and `return false` to guarantee a return value on all control paths
when the interpreter exits unexpectedly.
2014-12-02 05:36:06 +00:00
Bob Nystrom
3266491cf5 fix: correct break statement instruction size from 2 to 3 in endLoop to prevent code walker from misinterpreting arguments 2014-11-27 02:33:54 +00:00
Bob Nystrom
d9a42f21ba fix: add missing -lm link flag and fix GCC warnings for getline and switch coverage
Add -lm flag to both debug and release linker commands in Makefile to resolve
undefined math library references. Define _GNU_SOURCE in main.c to make getline()
available under GCC. Add default cases to switch statements in runFile and
getNumArguments to suppress -Wswitch warnings. Fix u_int8_t to uint8_t type in
wrenNewFunction declaration and definition for POSIX compliance.
2014-11-26 22:03:05 +00:00
Bob Nystrom
8abbc4197c feat: add MAX_VARIABLE_NAME limit and improve field overflow error message
Add a 64-character maximum identifier length with compile-time error reporting, and enhance the runtime field overflow error to include the class name and remove the TODO comment. Update test expectations for both limit scenarios.
2014-04-22 14:06:26 +00:00
Bob Nystrom
e665d4a9d3 feat: add closure test for shadowing closed-over variable with local
Add a new test case `shadow_closure_with_local.wren` that verifies a closed-over
variable can be shadowed by a local variable in an inner scope within the same
closure. The test ensures that the outer closure variable retains its value
outside the inner scope after the shadowing local goes out of scope.

Also remove an incomplete TODO comment from `reuse_closure_slot.wren` and add
a detailed TODO comment in `wren_compiler.c` discussing the design trade-off
between treating capitalized names as globals versus implicit `this` calls
when walking the scope chain.
2014-04-20 00:48:06 +00:00
Bob Nystrom
29f4b8167c feat: add zero-arg IO.print overload and remove newline skipping in parameter parsing
Add a static `print` method with no arguments that writes only a newline, enabling blank-line output. Remove the `ignoreNewlines` calls before closing parentheses in parameter lists and method calls, tightening syntax rules. Add a `strlen` TODO comment in symbol table lookup for future optimization. Move the `Foo.toString` test from `test/io/write.wren` to `test/io/print.wren` and delete the old write test file.
2014-04-19 18:44:51 +00:00
Bob Nystrom
fca506fdf1 feat: require parentheses around operator and setter method parameters in Wren
Enforce syntactic requirement for parentheses in operator method signatures (e.g., `+(other)` instead of `+ other`) and setter definitions (e.g., `bar=(value)` instead of `bar = value`). Update the compiler's `infixSignature`, `mixedSignature`, and `namedSignature` functions to consume explicit `(` and `)` tokens around parameter names. Migrate all built-in core library operator definitions and test fixtures to the new parenthesized syntax.
2014-04-09 00:54:37 +00:00
Bob Nystrom
2aaf6e5489 chore: rename debug and feature flags to consistent WREN_DEBUG_ and WREN_USE_ prefixes
Rename boolean defines from `true`/`false` to `1`/`0` for consistency, prefix debug flags with `WREN_DEBUG_`, add `WREN_USE_LIB_IO` flag to guard IO library loading, and wrap IO module includes and function declarations in conditional compilation blocks.
2014-04-07 14:45:09 +00:00
Bob Nystrom
e1cd942656 refactor: rename SymbolTable fields and flatten struct to StringBuffer alias
Replace the nested `SymbolTable` struct (containing a `StringBuffer names` field) with a direct `typedef StringBuffer SymbolTable`, updating all internal accesses from `symbols->names.data` to `symbols->data` and `symbols->names.count` to `symbols->count`. Rename `vm->methods` to `vm->methodNames` and `vm->globalSymbols` to `vm->globalNames` across the codebase, including debug printing, compiler symbol resolution, core initialization, and VM interpreter error messages. Remove the stale TODO comment about error codes in `wren.h` and adjust the `instantiate` method name to include a leading space to prevent direct user invocation.
2014-04-07 01:59:53 +00:00
Bob Nystrom
e7d2684d30 feat: replace fixed-size global array with growable ValueBuffer to support more than 256 globals
Replace the static `Value globals[MAX_GLOBALS]` array in WrenVM with a dynamic `ValueBuffer` that grows on demand, removing the 256-global limit. Introduce `wrenDefineGlobal()` helper that adds a named global to the symbol table and stores its value in the buffer, returning -2 when the 65536 limit is reached. Update all global access sites (compiler emit, runtime interpreter, GC marking, debug disassembly, core class definition) to use the buffer's data pointer and short (16-bit) opcode arguments instead of byte-sized ones. Add a regression test `many_globals.wren` that defines 8200 globals to verify the new capacity.
2014-04-06 23:16:15 +00:00
Bob Nystrom
4c4f32b5b2 feat: validate argument type in Fn.new and add runtime error test
Add type checking to the `fn_new` native function to ensure the argument
passed to `Fn.new` is either a function or closure. Previously, passing
an invalid type like an integer would silently succeed. Now it returns
a clear runtime error message: "Argument must be a function."

Also remove two stale TODO comments about newline handling in the
compiler that were no longer relevant to current parsing logic.
2014-04-05 01:13:13 +00:00
Bob Nystrom
093da7befb refactor: move newline handling from lexer into parser grammar rules
This change shifts newline tokenization from the lexer's readRawToken into the parser's nextToken, allowing the grammar to selectively ignore newlines in specific contexts (e.g., after operators like "|", "is", "for", "if", "while") while treating them as errors in others (e.g., after "var", "new", "class", "static", before commas in lists). The lexer now emits TOKEN_LINE for semicolons and newlines uniformly, and the parser decides which to elide. Test files are updated to reflect the new error expectations and to remove tests for newlines that are now grammatically allowed.
2014-04-04 14:51:18 +00:00
Bob Nystrom
a1365c4183 feat: unify block, function, and method body parsing to support single-expression implicit returns
Refactor `finishBlock` in `wren_compiler.c` to detect single-expression bodies (no newline after `{`) and leave a value on the stack, enabling implicit returns for methods and functions. Add `finishBody` wrapper to handle constructor flag. Update all benchmark and test `.wren` files to remove explicit `return` keywords from getters and single-expression methods, relying on the new implicit return behavior. Remove old `return_null_if_brace.wren` test, add `newline_body.wren`, `newline_in_expression_block.wren`, and `no_newline_before_close.wren` tests for edge cases.
2014-04-03 14:48:19 +00:00
Bob Nystrom
de2650b0ba fix: remove deprecated TOKEN_FN and old function syntax from wren compiler
Remove the TOKEN_FN enum value, its keyword mapping in readName, and the
associated function syntax handling from the tokenizer. Also clean up
unnecessary operator tokens from the newline-skipping switch in nextToken
to simplify the token processing logic.
2014-04-03 03:22:36 +00:00
Bob Nystrom
e20da2f070 feat: migrate all function literals from fn syntax to new Fn block syntax
Replace all occurrences of the old `fn` function literal syntax with the new `new Fn {|params| body}` block syntax across benchmark, test, and source files. Update the Wren compiler to handle the pipe operator as a block argument delimiter by removing `TOKEN_PIPE` from the newline-swallowing token list and adding explicit newline matching in `infixOp`. Adjust test expectations in `conditional/precedence.wren` to remove `fn`-based expressions and update `test/assignment/local.wren` to use the new syntax.
2014-04-03 02:41:53 +00:00
Bob Nystrom
81f20caf33 feat: replace CODE_NEW instruction with instantiate method call for class and Fn
Refactor the 'new' operator compilation to emit a method call to 'instantiate' on the class instead of using a dedicated bytecode instruction. This allows built-in types like Fn to override instantiation behavior, enabling `new Fn { ... }` to return the block argument directly. Remove the CODE_NEW opcode from the VM, compiler, and debug printer, and add native methods `class_instantiate`, `fn_instantiate`, `fn_new`, and `object_instantiate` to handle the new dispatch. Update test files to reflect the renamed `Function` class to `Fn`.
2014-04-03 00:42:30 +00:00
Bob Nystrom
c606e93516 feat: convert fiber tests to use block arguments instead of anonymous function literals
Update all fiber test files to replace `Fiber.create(fn { ... })` with `Fiber.create { ... }` block syntax, and add compiler support for parsing block bodies without requiring a newline after the opening brace. The compiler changes include removing `TOKEN_LEFT_BRACE` from the newline-discarding token list and adding `match(compiler, TOKEN_LINE)` calls in `finishBlock`, `methodCall`, `function`, and `block` to handle empty block bodies and inline expressions.
2014-04-03 00:31:58 +00:00
Bob Nystrom
5a017d17de feat: add block argument parsing with pipe-delimited parameters in method calls 2014-04-03 00:26:39 +00:00
Kyle Marek-Spartz
4f4251882d feat: enable custom bitwise operators | and & in wren compiler and add test
Add INFIX_OPERATOR entries for TOKEN_PIPE and TOKEN_AMP with PREC_BITWISE precedence in the compiler's grammar rules, replacing the previous UNUSED entries. This allows user-defined classes to implement custom `|` and `&` operator methods.

Include a new test file `test/custom_operators/bitwise.wren` that defines Amp and Pipe classes with their respective operator methods to validate the feature works correctly.
2014-02-16 18:01:40 +00:00
Bob Nystrom
73b92ca7f3 feat: add conditional operator and fn toString to wren compiler and core
Add TOKEN_QUESTION token type and implement conditional() parsing function in wren_compiler.c to support the ternary conditional operator (condition ? then : else). Register fn_toString native in wren_core.c to return "<fn>" string for function objects. Include comprehensive test suite covering precedence, short-circuit evaluation, and error cases for missing tokens.
2014-02-15 19:36:01 +00:00
Kyle Marek-Spartz
632cbf31b7 fix: correct typo in comment and remove redundant struct tag in Token definition 2014-02-15 06:15:51 +00:00
Bob Nystrom
5f505c2a02 fix: allow class body to end without newline after last method definition
In classDefinition in wren_compiler.c, add a check for TOKEN_RIGHT_BRACE before
requiring a newline after the last method definition, so that a closing brace
immediately following a method is accepted. Update test/class/syntax.wren with
a test case for this syntax.
2014-02-15 04:15:49 +00:00
Bob Nystrom
e3b3fef0fb feat: make this the implicit receiver for method calls inside class bodies
In the compiler, when a bare name is encountered inside a class definition and it does not resolve to a local variable or global, emit an implicit `this.` load before the call, enabling getter, setter, and method calls without explicit receiver. Update all benchmark, builtin, and test files to remove redundant `this.` qualifiers, and add comprehensive test suites for implicit receiver behavior across instance, inherited, static, nested, and shadowing scenarios.
2014-02-13 01:33:35 +00:00
Bob Nystrom
86015f4e48 feat: add numParams tracking and arity-checked fn.call variants for extra/missing args
Add `numParams` field to `ObjFn` and `Compiler` structs to track expected parameter count. Refactor `parameterList` to return count and store it in compiler. Modify `endCompiler` to pass `numParams` to `wrenNewFunction`. Replace single `fn_call` native with 17 arity-specific `fn_call0` through `fn_call16` natives that validate argument count against `fn->numParams` via `callFunction` helper, returning error on missing args. Remove stale TODO comment in VM interpreter. Add test files `call_extra_arguments.wren` and `call_missing_arguments.wren`.
2014-02-04 17:34:05 +00:00
Bob Nystrom
19e362f977 fix: add lexError calls for invalid string literals and unterminated strings in wren_compiler.c
Replace TODO comments with proper error reporting for unterminated strings, incomplete Unicode escapes, and invalid escape sequences. Add five new test files covering each error case.
2014-02-02 18:31:46 +00:00
Bob Nystrom
ea2ec33ce0 refactor: move class name from CODE_CLASS argument to stack in compiler and VM
In the compiler's classDefinition function, the class name constant is now emitted as a separate CODE_CONSTANT instruction before CODE_CLASS, instead of being passed as a short argument to CODE_CLASS. The VM's CLASS case handler is updated to pop the class name string from the stack using PEEK2() instead of reading it from the constant table via READ_SHORT(). The comment in wren_vm.h is revised to document that the class name is now on the stack below the superclass.
2014-01-29 15:47:09 +00:00
Bob Nystrom
e83296ea53 feat: add class name storage and expose via name method on class objects
Store the class name string in `ObjClass` during compilation and class creation, and expose it through a new `class_name` native method. Also update `object_toString` to return the class name for class instances and "instance of <name>" for regular instances.
2014-01-28 23:31:11 +00:00
Bob Nystrom
74b67eae67 refactor: remove separate CODE_SUBCLASS instruction, unify class creation with null sentinel
Eliminate the dedicated CODE_SUBCLASS opcode and instead push a null value to indicate implicit inheritance from Object. This simplifies the bytecode interpreter by using a single CODE_CLASS instruction that checks the top of stack for a null sentinel to determine whether to use the implicit Object superclass or a user-provided superclass. The change also consolidates argument counting and debug printing logic, removing the now-unnecessary case branches for CODE_SUBCLASS across the compiler, VM, and debug modules.
2014-01-27 01:25:38 +00:00
Bob Nystrom
4aa851cb64 fix: correct upvalue argument count calculation in bytecode patching loop
The getNumArguments function was incorrectly returning the number of upvalues
as a direct count instead of accounting for the two bytes consumed per upvalue
in the bytecode stream. This caused the patching loop to exit prematurely when
processing closures with multiple upvalues, leading to corrupted bytecode offsets
and runtime crashes.
2014-01-27 01:24:59 +00:00
Bob Nystrom
7ad96755f4 feat: implement static methods as local variables in implicit class scope
Refactor the compiler to treat static methods as local variables defined in an implicit scope surrounding the class, eliminating the need for VM-level static method support. This changes `declareVariable` to use the previously consumed token, adds `declareNamedVariable` for explicit token consumption, and updates `parameterList` to use the new function. Adjusts VM bytecode ordering for `CODE_METHOD_INSTANCE` and `CODE_METHOD_STATIC` to pop the class before the function body. Adds comprehensive test coverage for static fields including closures, nested classes, default null values, instance method access, and error cases for field usage outside classes or in static methods.
2014-01-19 21:01:51 +00:00
Bob Nystrom
9d71e765c8 refactor: extract class compilation state into dedicated ClassCompiler struct
Move fields, isStaticMethod, methodName, and methodLength from Compiler struct into a new ClassCompiler struct, replacing them with a single enclosingClass pointer. This consolidates class-level bookkeeping and simplifies the Compiler struct by grouping related fields.
2014-01-18 22:03:52 +00:00
Bob Nystrom
f2bf1104af feat: add TOKEN_STATIC_FIELD token for double-underscore prefixed identifiers
Add a new token type TOKEN_STATIC_FIELD to the compiler's token enum and
update the lexer to distinguish between single underscore (TOKEN_FIELD)
and double underscore (TOKEN_STATIC_FIELD) prefixed names. The new token
is registered in the grammar rules table as UNUSED with a TODO comment
for future implementation.
2014-01-18 17:33:18 +00:00
Bob Nystrom
15d9dc229c feat: prevent metaclass inheritance and disallow super in static methods
Remove the metaclass inheritance chain that mirrored the class hierarchy, instead always binding metaclasses directly to Class. This prevents static methods from being inherited by subclasses. Also add a compile-time error when `super` is used inside a static method, since it would always delegate to Class without useful effect. Update the `isInsideMethod` check to use `compiler->fields` instead of walking the parent chain for correctness. Add test cases for the new restrictions and remove the old test that verified static method inheritance.
2014-01-18 01:29:10 +00:00
Bob Nystrom
3663af8a27 fix: prevent instance field access inside static methods in wren compiler
Add isStaticMethod flag to Compiler struct to track whether the current method is static. When compiling a field access, check this flag and emit a compile error if an instance field is used inside a static method. Initialize the flag to false for top-level code and propagate it from parent to child compilers for nested functions and methods.
2014-01-16 15:09:43 +00:00
Bob Nystrom
7e196d9781 feat: add MAX_FIELDS constant and runtime overflow checks for class field limit of 255
Add a MAX_FIELDS constant (255) to wren_common.h and implement field overflow
validation in the compiler and VM. The compiler now emits an error when a class
declares more than 255 fields, and the VM checks for inherited field overflow
at class creation time, producing a descriptive runtime error. Also add four
test files (many_fields, many_inherited_fields, too_many_fields,
too_many_inherited_fields) to verify both valid and invalid field counts.
2014-01-15 15:59:10 +00:00
Bob Nystrom
b4437d5723 fix: recursively bind inherited field references inside nested closures in wrenBindMethodCode 2014-01-15 15:03:24 +00:00
b01dface
d15c36ee89 fix: correct error message token from '}' to '{' in class definition parser
The error message emitted when a left brace is expected after a class body
incorrectly referenced a closing brace '}' instead of the required opening
brace '{'. This fix updates the error string in the `classDefinition` function
within `src/wren_compiler.c` to accurately describe the expected token.
2014-01-14 01:21:25 +00:00
Bob Nystrom
08c38f92cb feat: allow implicit null return when return statement has no value
In the compiler, when a `return` token is followed by a newline or right brace, emit CODE_NULL instead of parsing an expression. This enables bare `return` statements to implicitly return null. Also removes a stale TODO comment about setter parameters and fixes a typo in a comment in wren_core.c. Adds three test cases: one for explicit return in a function, one for bare return before a brace, and one for bare return before a newline.
2014-01-13 03:37:11 +00:00
Bob Nystrom
2e34a5c42b feat: add support for escape sequences \a, \b, \f, \r, \v in string parsing
Implement the remaining standard C escape codes in the readString function
of the Wren compiler, removing the TODO comment about missing escapes.
Adds handling for alert (a), backspace (b), form feed (f), carriage return (r),
and vertical tab (v) escape sequences.
2014-01-13 03:24:30 +00:00
Bob Nystrom
33b0fae6f6 feat: extend jump offsets from 8-bit to 16-bit in compiler and VM
Replace single-byte jump offset emission and reading with two-byte (uint16) handling across all jump instructions (JUMP, LOOP, JUMP_IF, AND, OR). Add new emitJump helper that reserves a 16-bit placeholder, update patchJump to write the offset as big-endian short, and change VM opcode handlers to use READ_SHORT instead of READ_BYTE for jump offsets. This increases maximum jump distance from 255 to 65535 bytes, supporting larger generated bytecode.
2014-01-08 07:03:38 +00:00
Bob Nystrom
0ba6456214 fix: properly dispose loop-scoped variables and exit scopes on break
Replace the single `loopBody` index with a `Loop` struct that tracks scope depth, enabling the compiler to emit correct scope-exit code when a `break` statement is encountered inside nested blocks. Also add `WREN_DUMP_COMPILED_CODE` debug flag and new test cases for closures capturing loop variables after break, return inside loops, and nested loop scoping.
2014-01-06 16:01:04 +00:00
Bob Nystrom
c72db7d594 feat: rename IO.write to IO.print and add Unicode escape support in strings
Rename the IO.write method to IO.print, which now prints without a trailing newline, and add a new IO.print method that appends a newline after output. Update all benchmark, example, and test files to use IO.print instead of IO.write. Additionally, implement Unicode escape sequence parsing in the compiler's string tokenizer, supporting \uXXXX and \u{...} syntax with proper UTF-8 encoding for code points up to U+10FFFF.
2014-01-05 20:27:12 +00:00
Bob Nystrom
e23e0ce6a3 feat: remove hardcoded 256 symbol limit and switch to dynamic symbol table with 16-bit instruction arguments
Replace the fixed-size MAX_SYMBOLS array with a dynamically growing StringBuffer for symbol names, update all instruction encodings to use 16-bit operands for constants and method symbols, and refactor method binding to use a dynamic MethodBuffer per class. Remove the constant deduplication logic in addConstant and the commented-out struct fields in initCompiler.
2014-01-04 19:08:31 +00:00
Bob Nystrom
003d4f77f4 refactor: reorder and document fields in Compiler struct for clarity
Move bytecode and debug source line buffers out of Compiler struct to
simplify initialization, and add inline comments for source path, source
code, constants, locals, upvalues, and fields to improve readability of
the compiler's internal state layout.
2014-01-02 15:31:31 +00:00
Bob Nystrom
720b1b5d76 refactor: replace monolithic Buffer struct with generic macro-generated ByteBuffer and IntBuffer types
Remove the single-purpose Buffer struct from wren_compiler.c and replace it with type-specific ByteBuffer and IntBuffer types generated via a DECLARE_BUFFER macro in wren_utils.h, with shared buffer logic implemented in wren_utils.c using a void* Buffer helper struct. This enables a growable line-number buffer for debug source lines.
2014-01-02 06:23:03 +00:00
Bob Nystrom
b93bd62623 refactor: extract SymbolTable into dedicated wren_utils module with prefixed API
Move SymbolTable struct and its associated functions (initSymbolTable, clearSymbolTable, addSymbol, findSymbol, ensureSymbol, getSymbolName) from wren_vm.c and wren_value.h into new wren_utils.c and wren_utils.h files. Rename all functions with wrenSymbolTable prefix for consistent naming convention, update all call sites across compiler, core, debug, and VM files, and relocate MAX_SYMBOLS constant to wren_common.h.
2014-01-02 04:57:58 +00:00
Bob Nystrom
547107a086 feat: add runtime error support with source paths, line info, and stack traces
Introduce primitive error signaling, runtime error handling with callstack printing, and fiber termination on error. Add source file path and method name tracking to functions, along with debug line number information. Update arithmetic operators to error on non-numeric operands and implement proper "method not found" runtime errors. Refactor the test runner to expect runtime errors with exit code 70 (EX_SOFTWARE) and update the C API to accept source paths in wrenInterpret and wrenCompile. Rename WrenNativeMethodFn to WrenForeignMethodFn and adjust related typedefs. Add debug source line arrays to compilers and functions, and replace the old debug dump functions with new print-based variants that display line numbers.
2014-01-01 21:25:24 +00:00
Bob Nystrom
8a09c03cdd fix: reorder symbol table insertion before object allocation to prevent GC crashes
In `wren_core.c`, `defineClass` and `wrenInitializeCore` now call `addSymbol` before allocating new class objects (`wrenNewClass`, `wrenNewSingleClass`), ensuring unpinned objects are not live when a GC-triggering symbol insertion occurs. In `wren_compiler.c`, `freeBuffer` now passes zero capacity to `wrenReallocate` and reuses `initBuffer` instead of manually zeroing fields, fixing a potential double-free or stale pointer on buffer reuse.
2013-12-30 15:30:50 +00:00
Bob Nystrom
4f215f6531 feat: allow empty blocks in parser and fix native call slot assertion
Add support for empty block bodies in the Wren compiler by early-returning
from `finishBlock` when a right brace is immediately matched. This permits
syntactically valid constructs like `{}`, `if (true) {}`, and empty function
or method bodies.

Fix a copy-paste error in `wrenGetArgumentDouble` where the assertion
checked `nativeCallSlot` and `nativeCallNumArgs` instead of the correct
`foreignCallSlot` and `foreignCallNumArgs` fields.

Add test cases covering standalone empty blocks, empty blocks in if/else
statements, and empty function and method bodies returning null.
2013-12-29 18:46:21 +00:00