├── .gitmodules ├── LICENSE ├── README.md ├── build.zig └── src ├── main.zig └── wren.zig /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "wren"] 2 | path = wren 3 | url = https://github.com/wren-lang/wren 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Dante Catalfamo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wren-zig 2 | [Wren](https://wren.io/) bindings for [zig](https://ziglang.org/)! 3 | 4 | Wren is a fast lua-sized scripting language with classes and concurrency. 5 | 6 | Details on how embedding wren works [here](https://wren.io/embedding/). 7 | 8 | ## Bindings 9 | 10 | In `src/wren.zig` 11 | 12 | Contains both bare bindings and a zig wrapper 13 | 14 | ```zig 15 | wrenGetSlotDouble(vm, 0); 16 | 17 | vm.getSlotDouble(0); 18 | ``` 19 | 20 | ## Embedding 21 | 22 | Recursively clone this repository and add the following to your `build.zig`, with the paths changed to match the correct location 23 | 24 | ```zig 25 | const addWren = @import("wren-zig/build.zig").addWren; 26 | 27 | pub fn build(b: *std.build.Builder) void { 28 | [...] 29 | const exe = b.addExecutable("wren-zig", "src/main.zig"); 30 | addWren(exe); 31 | [...] 32 | } 33 | ``` 34 | 35 | ## Example 36 | 37 | A very basic example 38 | 39 | ```zig 40 | const std = @import("std"); 41 | const wren = @import("wren"); 42 | 43 | pub fn main() anyerror!void { 44 | var config = wren.newConfig(); 45 | config.write_fn = writeFn; 46 | config.error_fn = errorFn; 47 | var vm = wren.wrenNewVM(&config); 48 | defer vm.free(); 49 | 50 | try vm.interpret("main", "System.print(\"Hello, world!\")"); 51 | } 52 | 53 | pub export fn writeFn(vm: *wren.WrenVM, text: [*:0]const u8) void { 54 | _ = vm; 55 | const stdout = std.io.getStdOut().writer(); 56 | stdout.print("{s}", .{ text }) catch unreachable; 57 | } 58 | 59 | pub export fn errorFn(vm: *wren.WrenVM, error_type: wren.WrenErrorType, module: [*:0]const u8, line: c_int, msg: [*:0]const u8) void { 60 | _ = vm; 61 | const stderr = std.io.getStdErr().writer(); 62 | switch (error_type) { 63 | .WREN_ERROR_COMPILE => stderr.print("[{s} line {d}] [Error] {s}\n", .{ module, line, msg }) catch unreachable, 64 | .WREN_ERROR_STACK_TRACE => stderr.print("[{s} line {d}] in {s}\n", .{ module, line, msg }) catch unreachable, 65 | .WREN_ERROR_RUNTIME => stderr.print("[Runtime Error] {s}\n", .{ msg }) catch unreachable, 66 | } 67 | } 68 | ``` 69 | 70 | See `src/main.zig` for more advanced use cases 71 | -------------------------------------------------------------------------------- /build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const path = std.fs.path; 3 | 4 | pub fn build(b: *std.build.Builder) void { 5 | // Standard target options allows the person running `zig build` to choose 6 | // what target to build for. Here we do not override the defaults, which 7 | // means any target is allowed, and the default is native. Other options 8 | // for restricting supported target set are available. 9 | const target = b.standardTargetOptions(.{}); 10 | 11 | // Standard release options allow the person running `zig build` to select 12 | // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. 13 | const mode = b.standardReleaseOptions(); 14 | 15 | const exe = b.addExecutable("wren-zig", "src/main.zig"); 16 | addWren(exe); 17 | exe.setTarget(target); 18 | exe.setBuildMode(mode); 19 | exe.install(); 20 | 21 | const run_cmd = exe.run(); 22 | run_cmd.step.dependOn(b.getInstallStep()); 23 | if (b.args) |args| { 24 | run_cmd.addArgs(args); 25 | } 26 | 27 | const run_step = b.step("run", "Run the app"); 28 | run_step.dependOn(&run_cmd.step); 29 | 30 | const exe_tests = b.addTest("src/main.zig"); 31 | addWren(exe_tests); 32 | exe_tests.setTarget(target); 33 | exe_tests.setBuildMode(mode); 34 | 35 | const test_step = b.step("test", "Run unit tests"); 36 | test_step.dependOn(&exe_tests.step); 37 | } 38 | 39 | pub fn addWren(exe: *std.build.LibExeObjStep) void { 40 | var allocator = exe.builder.allocator; 41 | const src_path = path.dirname(@src().file) orelse "."; 42 | const include_path = path.join(allocator, &.{ src_path, "wren", "src", "include" }) catch unreachable; 43 | const vm_path = path.join(allocator, &.{ src_path, "wren", "src", "vm" }) catch unreachable; 44 | const optional_path = path.join(allocator, &.{ src_path, "wren", "src", "optional" }) catch unreachable; 45 | const package_path = path.join(allocator, &.{ src_path, "src", "wren.zig" }) catch unreachable; 46 | 47 | exe.addIncludePath(include_path); 48 | exe.addIncludePath(vm_path); 49 | exe.addIncludePath(optional_path); 50 | exe.linkSystemLibrary("m"); 51 | exe.addPackagePath("wren", package_path); 52 | 53 | for (vm_c_files) |vm_c_file| { 54 | const c_path = path.join(allocator, &.{ vm_path, vm_c_file }) catch unreachable; 55 | exe.addCSourceFile(c_path, &.{}); 56 | } 57 | 58 | for (optional_c_files) |opt_c_file| { 59 | const c_path = path.join(allocator, &.{ optional_path, opt_c_file }) catch unreachable; 60 | exe.addCSourceFile(c_path, &.{}); 61 | } 62 | } 63 | 64 | const optional_c_files = [_][]const u8 { 65 | "wren_opt_meta.c", 66 | "wren_opt_random.c", 67 | }; 68 | 69 | const vm_c_files = [_][]const u8 { 70 | "wren_compiler.c", 71 | "wren_core.c", 72 | "wren_debug.c", 73 | "wren_primitive.c", 74 | "wren_utils.c", 75 | "wren_value.c", 76 | "wren_vm.c", 77 | }; 78 | -------------------------------------------------------------------------------- /src/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const mem = std.mem; 3 | const wren = @import("wren"); 4 | 5 | pub fn main() anyerror!void { 6 | // Optional, use zig allocator for wren 7 | var gpa = std.heap.GeneralPurposeAllocator(.{}){}; 8 | defer _ = gpa.deinit(); 9 | var allocator = gpa.allocator(); 10 | var wren_alloc = wren.WrenAllocator.init(allocator); 11 | defer wren_alloc.deinit(); 12 | 13 | var config = wren.newConfig(); 14 | config.write_fn = writeFn; 15 | config.error_fn = errorFn; 16 | config.bind_foreign_method_fn = bindForeignMethod; 17 | 18 | // Setup zig allocator in wren 19 | config.reallocate_fn = wren.zigWrenAlloc; 20 | config.user_data = &wren_alloc; 21 | 22 | var vm = wren.wrenNewVM(&config); 23 | defer vm.free(); 24 | 25 | try vm.interpret("main", "System.print(\"Hello, world!\")"); 26 | 27 | const print_handle = vm.makeCallHandle("print(_)"); 28 | vm.ensureSlots(2); 29 | vm.getVariable("main", "System", 0); 30 | vm.setSlotString(1, "Hello from zig -> wren!"); 31 | try vm.call(print_handle); 32 | 33 | const foreignMethod = 34 | \\class Zig { 35 | \\ foreign static hello() 36 | \\ foreign static add(a, b) 37 | \\} 38 | ; 39 | try vm.interpret("main", foreignMethod); 40 | try vm.interpret("main", "System.print(Zig.hello())"); 41 | try vm.interpret("main", "System.print(Zig.add(2, 3))"); 42 | } 43 | 44 | pub export fn writeFn(vm: *wren.WrenVM, text: [*:0]const u8) void { 45 | _ = vm; 46 | const stdout = std.io.getStdOut().writer(); 47 | stdout.print("{s}", .{ text }) catch unreachable; 48 | } 49 | 50 | pub export fn errorFn(vm: *wren.WrenVM, error_type: wren.WrenErrorType, module: [*:0]const u8, line: c_int, msg: [*:0]const u8) void { 51 | _ = vm; 52 | const stderr = std.io.getStdErr().writer(); 53 | switch (error_type) { 54 | .WREN_ERROR_COMPILE => stderr.print("[{s} line {d}] [Error] {s}\n", .{ module, line, msg }) catch unreachable, 55 | .WREN_ERROR_STACK_TRACE => stderr.print("[{s} line {d}] in {s}\n", .{ module, line, msg }) catch unreachable, 56 | .WREN_ERROR_RUNTIME => stderr.print("[Runtime Error] {s}\n", .{ msg }) catch unreachable, 57 | } 58 | } 59 | 60 | pub export fn bindForeignMethod(vm: *wren.WrenVM, module: [*:0]const u8, class_name: [*:0]const u8, is_static: bool, signature: [*:0]const u8) ?wren.WrenForeignMethodFn { 61 | _ = vm; 62 | if (mem.eql(u8, mem.span(module), "main")) { 63 | if (mem.eql(u8, mem.span(class_name), "Zig")) { 64 | if (is_static) { 65 | if (mem.eql(u8, mem.span(signature), "add(_,_)")) { 66 | return zigAdd; 67 | } else if (mem.eql(u8, mem.span(signature), "hello()")) { 68 | return zigHello; 69 | } 70 | } 71 | } 72 | } 73 | return null; 74 | } 75 | 76 | pub export fn zigHello(vm: *wren.WrenVM) void { 77 | vm.setSlotString(0, "Hello from wren -> zig!"); 78 | } 79 | 80 | pub export fn zigAdd(vm: *wren.WrenVM) void { 81 | const a = vm.getSlotDouble(1); 82 | const b = vm.getSlotDouble(2); 83 | vm.setSlotDouble(0, a + b); 84 | } 85 | 86 | test "basic test" { 87 | try std.testing.expectEqual(10, 3 + 7); 88 | } 89 | 90 | test "ref all" { 91 | std.testing.refAllDecls(wren); 92 | std.testing.refAllDecls(wren.WrenVM); 93 | } 94 | -------------------------------------------------------------------------------- /src/wren.zig: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Dante Catalfamo 2 | // SPDX-License-Identifier: MIT 3 | 4 | const std = @import("std"); 5 | const mem = std.mem; 6 | 7 | /// A single virtual machine for executing Wren code. 8 | /// 9 | /// Wren has no global state, so all state stored by a running interpreter lives 10 | /// here. 11 | pub const WrenVM = opaque{ 12 | const Self = @This(); 13 | 14 | /// Disposes of all resources is use by [vm], which was previously created by a 15 | /// call to [wrenNewVM]. 16 | pub fn free(self: *Self) void { 17 | return wrenFreeVM(self); 18 | } 19 | 20 | /// Immediately run the garbage collector to free unused memory. 21 | pub fn collectGarbage(self: *Self) void { 22 | return wrenCollectGarbage(self); 23 | } 24 | 25 | /// Runs [source], a string of Wren source code in a new fiber in [vm] in the 26 | /// context of resolved [module]. 27 | pub fn interpret(self: *Self, module: [*:0]const u8, source: [*:0]const u8) !void { 28 | const value = wrenInterpret(self, module, source); 29 | switch (value) { 30 | .WREN_RESULT_COMPILE_ERROR => return error.CompileError, 31 | .WREN_RESULT_RUNTIME_ERROR => return error.RuntimeError, 32 | else => {} 33 | } 34 | } 35 | 36 | /// Creates a handle that can be used to invoke a method with [signature] on 37 | /// using a receiver and arguments that are set up on the stack. 38 | /// 39 | /// This handle can be used repeatedly to directly invoke that method from C 40 | /// code using [wrenCall]. 41 | /// 42 | /// When you are done with this handle, it must be released using 43 | /// [wrenReleaseHandle]. 44 | pub fn makeCallHandle(self: *Self, signature: [*:0]const u8) *WrenHandle { 45 | return wrenMakeCallHandle(self, signature); 46 | } 47 | 48 | /// Calls [method], using the receiver and arguments previously set up on the 49 | /// stack. 50 | /// 51 | /// [method] must have been created by a call to [wrenMakeCallHandle]. The 52 | /// arguments to the method must be already on the stack. The receiver should be 53 | /// in slot 0 with the remaining arguments following it, in order. It is an 54 | /// error if the number of arguments provided does not match the method's 55 | /// signature. 56 | /// 57 | /// After this returns, you can access the return value from slot 0 on the stack. 58 | pub fn call(self: *Self, method: *WrenHandle) !void { 59 | const value = wrenCall(self, method); 60 | switch (value) { 61 | .WREN_RESULT_COMPILE_ERROR => return error.CompileError, 62 | .WREN_RESULT_RUNTIME_ERROR => return error.RuntimeError, 63 | else => {} 64 | } 65 | } 66 | 67 | /// Releases the reference stored in [handle]. After calling this, [handle] can 68 | /// no longer be used. 69 | pub fn releaseHandle(self: *Self, handle: *WrenHandle) void { 70 | return wrenReleaseHandle(self, handle); 71 | } 72 | 73 | // The following functions are intended to be called from foreign methods or 74 | // finalizers. The interface Wren provides to a foreign method is like a 75 | // register machine: you are given a numbered array of slots that values can be 76 | // read from and written to. Values always live in a slot (unless explicitly 77 | // captured using wrenGetSlotHandle(), which ensures the garbage collector can 78 | // find them. 79 | // 80 | // When your foreign function is called, you are given one slot for the receiver 81 | // and each argument to the method. The receiver is in slot 0 and the arguments 82 | // are in increasingly numbered slots after that. You are free to read and 83 | // write to those slots as you want. If you want more slots to use as scratch 84 | // space, you can call wrenEnsureSlots() to add more. 85 | // 86 | // When your function returns, every slot except slot zero is discarded and the 87 | // value in slot zero is used as the return value of the method. If you don't 88 | // store a return value in that slot yourself, it will retain its previous 89 | // value, the receiver. 90 | // 91 | // While Wren is dynamically typed, C is not. This means the C interface has to 92 | // support the various types of primitive values a Wren variable can hold: bool, 93 | // double, string, etc. If we supported this for every operation in the C API, 94 | // there would be a combinatorial explosion of functions, like "get a 95 | // double-valued element from a list", "insert a string key and double value 96 | // into a map", etc. 97 | // 98 | // To avoid that, the only way to convert to and from a raw C value is by going 99 | // into and out of a slot. All other functions work with values already in a 100 | // slot. So, to add an element to a list, you put the list in one slot, and the 101 | // element in another. Then there is a single API function wrenInsertInList() 102 | // that takes the element out of that slot and puts it into the list. 103 | // 104 | // The goal of this API is to be easy to use while not compromising performance. 105 | // The latter means it does not do type or bounds checking at runtime except 106 | // using assertions which are generally removed from release builds. C is an 107 | // unsafe language, so it's up to you to be careful to use it correctly. In 108 | // return, you get a very fast FFI. 109 | 110 | /// Returns the number of slots available to the current foreign method. 111 | pub fn getSlotCount(self: *Self) c_int { 112 | return wrenGetSlotCount(self); 113 | } 114 | 115 | /// Ensures that the foreign method stack has at least [numSlots] available for 116 | /// use, growing the stack if needed. 117 | /// 118 | /// Does not shrink the stack if it has more than enough slots. 119 | /// 120 | /// It is an error to call this from a finalizer. 121 | pub fn ensureSlots(self: *Self, num_slots: c_int) void { 122 | return wrenEnsureSlots(self, num_slots); 123 | } 124 | 125 | /// Gets the type of the object in [slot]. 126 | pub fn getSlotType(self: *Self, slot: c_int) WrenType { 127 | return wrenGetSlotType(self, slot); 128 | } 129 | 130 | /// Reads a boolean value from [slot]. 131 | /// 132 | /// It is an error to call this if the slot does not contain a boolean value. 133 | pub fn getSlotBool(self: *Self, slot: c_int) bool { 134 | return wrenGetSlotBool(self, slot); 135 | } 136 | 137 | /// Reads a byte array from [slot]. 138 | /// 139 | /// The memory for the returned string is owned by Wren. You can inspect it 140 | /// while in your foreign method, but cannot keep a pointer to it after the 141 | /// function returns, since the garbage collector may reclaim it. 142 | /// 143 | /// Returns a pointer to the first byte of the array and fill [length] with the 144 | /// number of bytes in the array. 145 | /// 146 | /// It is an error to call this if the slot does not contain a string. 147 | pub fn getSlotBytes(self: *Self, slot: c_int) []const u8 { 148 | var len: c_int = 0; 149 | const ptr = wrenGetSlotBytes(self, slot, &len); 150 | const ptr_len = @intCast(usize, len); 151 | return ptr[0..ptr_len]; 152 | } 153 | 154 | /// Reads a number from [slot]. 155 | /// 156 | /// It is an error to call this if the slot does not contain a number. 157 | pub fn getSlotDouble(self: *Self, slot: c_int) f64 { 158 | return wrenGetSlotDouble(self, slot); 159 | } 160 | 161 | /// Reads a foreign object from [slot] and returns a pointer to the foreign data 162 | /// stored with it. 163 | /// 164 | /// It is an error to call this if the slot does not contain an instance of a 165 | /// foreign class. 166 | pub fn getSlotForeign(self: *Self, slot: c_int) void { 167 | return wrenGetSlotForeign(self, slot); 168 | } 169 | 170 | /// Reads a string from [slot]. 171 | /// 172 | /// The memory for the returned string is owned by Wren. You can inspect it 173 | /// while in your foreign method, but cannot keep a pointer to it after the 174 | /// function returns, since the garbage collector may reclaim it. 175 | /// 176 | /// It is an error to call this if the slot does not contain a string. 177 | pub fn getSlotString(self: *Self, slot: c_int) [*:0]const u8 { 178 | return wrenGetSlotString(self, slot); 179 | } 180 | 181 | /// Creates a handle for the value stored in [slot]. 182 | /// 183 | /// This will prevent the object that is referred to from being garbage collected 184 | /// until the handle is released by calling [wrenReleaseHandle()]. 185 | pub fn getSlotHandle(self: *Self, slot: c_int) *WrenHandle { 186 | return wrenGetSlotHandle(self, slot); 187 | } 188 | 189 | /// Stores the boolean [value] in [slot]. 190 | pub fn setSlotBool(self: *Self, slot: c_int, value: bool) void { 191 | return wrenSetSlotBool(self, slot, value); 192 | } 193 | 194 | /// Stores the array [length] of [bytes] in [slot]. 195 | /// 196 | /// The bytes are copied to a new string within Wren's heap, so you can free 197 | /// memory used by them after this is called. 198 | pub fn setSlotBytes(self: *Self, slot: c_int, bytes: []const u8) void { 199 | return wrenSetSlotBytes(self, slot, bytes.ptr, bytes.len); 200 | } 201 | 202 | /// Stores the numeric [value] in [slot]. 203 | pub fn setSlotDouble(self: *Self, slot: c_int, value: f64) void { 204 | return wrenSetSlotDouble(self, slot, value); 205 | } 206 | 207 | /// Creates a new instance of the foreign class stored in [classSlot] with [size] 208 | /// bytes of raw storage and places the resulting object in [slot]. 209 | /// 210 | /// This does not invoke the foreign class's constructor on the new instance. If 211 | /// you need that to happen, call the constructor from Wren, which will then 212 | /// call the allocator foreign method. In there, call this to create the object 213 | /// and then the constructor will be invoked when the allocator returns. 214 | /// 215 | /// Returns a pointer to the foreign object's data. 216 | pub fn setSlotNewForeign(self: *Self, slot: c_int, class_slot: c_int, size: usize) ?*anyopaque { 217 | return wrenSetSlotNewForeign(self, slot, class_slot, size); 218 | } 219 | 220 | /// Stores a new empty list in [slot]. 221 | pub fn setSlotNewList(self: *Self, slot: c_int) void { 222 | return wrenSetSlotNewList(self, slot); 223 | } 224 | 225 | /// Stores a new empty map in [slot]. 226 | pub fn setSlotNewMap(self: *Self, slot: c_int) void { 227 | return wrenSetSlotNewMap(self, slot); 228 | } 229 | 230 | /// Stores null in [slot]. 231 | pub fn setSlotNull(self: *Self, slot: c_int) void { 232 | return wrenSetSlotNull(self, slot); 233 | } 234 | 235 | /// Stores the string [text] in [slot]. 236 | /// 237 | /// The [text] is copied to a new string within Wren's heap, so you can free 238 | /// memory used by it after this is called. The length is calculated using 239 | /// [strlen()]. If the string may contain any null bytes in the middle, then you 240 | /// should use [wrenSetSlotBytes()] instead. 241 | pub fn setSlotString(self: *Self, slot: c_int, text: [*:0]const u8) void { 242 | return wrenSetSlotString(self, slot, text); 243 | } 244 | 245 | /// Stores the value captured in [handle] in [slot]. 246 | /// 247 | /// This does not release the handle for the value. 248 | pub fn setSlotHandle(self: *Self, slot: c_int, handle: *WrenHandle) void { 249 | return wrenSetSlotHandle(self, slot, handle); 250 | } 251 | 252 | /// Returns the number of elements in the list stored in [slot]. 253 | pub fn getListCount(self: *Self, slot: c_int) c_int { 254 | return wrenGetListCount(self, slot); 255 | } 256 | 257 | /// Reads element [index] from the list in [listSlot] and stores it in 258 | /// [elementSlot]. 259 | pub fn getListElement(self: *Self, list_slot: c_int, index: c_int, element_slot: c_int) void { 260 | return wrenGetListElement(self, list_slot, index, element_slot); 261 | } 262 | 263 | /// Sets the value stored at [index] in the list at [listSlot], 264 | /// to the value from [elementSlot]. 265 | pub fn setListElement(self: *Self, list_slot: c_int, index: c_int, element_slot: c_int) void { 266 | return wrenSetListElement(self, list_slot, index, element_slot); 267 | } 268 | 269 | /// Takes the value stored at [elementSlot] and inserts it into the list stored 270 | /// at [listSlot] at [index]. 271 | /// 272 | /// As in Wren, negative indexes can be used to insert from the end. To append 273 | /// an element, use `-1` for the index. 274 | pub fn insertInList(self: *Self, list_slot: c_int, index: c_int, element_slot: c_int) void { 275 | return wrenInsertInList(self, list_slot, index, element_slot); 276 | } 277 | 278 | /// Returns the number of entries in the map stored in [slot]. 279 | pub fn getMapCount(self: *Self, slot: c_int) c_int { 280 | return wrenGetMapCount(self, slot); 281 | } 282 | 283 | /// Returns true if the key in [keySlot] is found in the map placed in [mapSlot]. 284 | pub fn getMapContainsKey(self: *Self, map_slot: c_int, key_slot: c_int) bool { 285 | return wrenGetMapContainsKey(self, map_slot, key_slot); 286 | } 287 | 288 | /// Retrieves a value with the key in [keySlot] from the map in [mapSlot] and 289 | /// stores it in [valueSlot]. 290 | pub fn getMapValue(self: *Self, map_slot: c_int, key_slot: c_int, value_slot: c_int) void { 291 | return wrenGetMapValue(self, map_slot, key_slot, value_slot); 292 | } 293 | 294 | /// Takes the value stored at [valueSlot] and inserts it into the map stored 295 | /// at [mapSlot] with key [keySlot]. 296 | pub fn setMapValue(self: *Self, map_slot: c_int, key_slot: c_int, value_slot: c_int) void { 297 | return wrenSetMapValue(self, map_slot, key_slot, value_slot); 298 | } 299 | 300 | /// Removes a value from the map in [mapSlot], with the key from [keySlot], 301 | /// and place it in [removedValueSlot]. If not found, [removedValueSlot] is 302 | /// set to null, the same behaviour as the Wren Map API. 303 | pub fn removeMapValue(self: *Self, map_slot: c_int, key_slot: c_int, removed_value_slot: c_int) void { 304 | return wrenRemoveMapValue(self, map_slot, key_slot, removed_value_slot); 305 | } 306 | 307 | /// Looks up the top level variable with [name] in resolved [module] and stores 308 | /// it in [slot]. 309 | pub fn getVariable(self: *Self, module: [*:0]const u8, name: [*:0]const u8, slot: c_int) void { 310 | return wrenGetVariable(self, module, name, slot); 311 | } 312 | 313 | /// Looks up the top level variable with [name] in resolved [module], 314 | /// returns false if not found. The module must be imported at the time, 315 | /// use wrenHasModule to ensure that before calling. 316 | pub fn hasVariable(self: *Self, module: [*:0]const u8, name: [*:0]const u8) bool { 317 | return wrenHasVariable(self, module, name); 318 | } 319 | 320 | /// Returns true if [module] has been imported/resolved before, false if not. 321 | pub fn hasModule(self: *Self, module: [*:0]const u8) bool { 322 | return wrenHasModule(self, module); 323 | } 324 | 325 | /// Sets the current fiber to be aborted, and uses the value in [slot] as the 326 | /// runtime error object. 327 | pub fn abortFiber(self: *Self, slot: c_int) void { 328 | return wrenAbortFiber(self, slot); 329 | } 330 | 331 | /// Returns the user data associated with the WrenVM. 332 | pub fn getUserData(self: *Self) ?*anyopaque { 333 | return wrenGetUserData(self); 334 | } 335 | 336 | /// Sets user data associated with the WrenVM. 337 | pub fn setUserData(self: *Self, user_data: ?*anyopaque) void { 338 | return wrenSetUserData(self, user_data); 339 | } 340 | }; 341 | 342 | pub const WrenAllocator = struct { 343 | allocator: mem.Allocator, 344 | ptr_size_map: std.AutoHashMap(usize, usize), 345 | 346 | const Self = @This(); 347 | 348 | pub fn init(allocator: mem.Allocator) Self { 349 | return .{ 350 | .allocator = allocator, 351 | .ptr_size_map = std.AutoHashMap(usize, usize).init(allocator), 352 | }; 353 | } 354 | 355 | pub fn deinit(self: *Self) void { 356 | var iter = self.ptr_size_map.iterator(); 357 | while (iter.next()) |entry| { 358 | const ptr = @intToPtr([*]u8, entry.key_ptr.*); 359 | const size = entry.value_ptr.*; 360 | const memory = ptr[0..size]; 361 | self.allocator.free(memory); 362 | } 363 | self.ptr_size_map.deinit(); 364 | } 365 | 366 | pub fn alloc(self: *Self, size: usize) ?*anyopaque { 367 | const new_memory = self.allocator.alloc(u8, size) catch return null; 368 | self.ptr_size_map.put(@ptrToInt(new_memory.ptr), new_memory.len) catch return null; 369 | return new_memory.ptr; 370 | } 371 | 372 | pub fn realloc(self: *Self, old_ptr: *anyopaque, new_size: usize) ?*anyopaque { 373 | const old_size = self.ptr_size_map.get(@ptrToInt(old_ptr)) orelse return null; 374 | const old_memory = @ptrCast([*]u8, old_ptr)[0..old_size]; 375 | const new_memory = self.allocator.realloc(old_memory, new_size) catch return null; 376 | _ = self.ptr_size_map.remove(@ptrToInt(old_ptr)); 377 | self.ptr_size_map.put(@ptrToInt(new_memory.ptr), new_memory.len) catch return null; 378 | return new_memory.ptr; 379 | } 380 | 381 | pub fn free(self: *Self, ptr: *anyopaque) void { 382 | const size = self.ptr_size_map.get(@ptrToInt(ptr)) orelse unreachable; 383 | const memory = @ptrCast([*]u8, ptr)[0..size]; 384 | self.allocator.free(memory); 385 | _ = self.ptr_size_map.remove(@ptrToInt(ptr)); 386 | } 387 | }; 388 | 389 | pub export fn zigWrenAlloc(ptr: ?*anyopaque, size: usize, user_data: ?*anyopaque) ?*anyopaque { 390 | const zig_wren_alloc = @ptrCast(*WrenAllocator, @alignCast(@alignOf(WrenAllocator), user_data)); 391 | if (ptr == null and size == 0) { 392 | return null; 393 | } else if (ptr == null) { 394 | return zig_wren_alloc.alloc(size); 395 | } else if (size == 0) { 396 | zig_wren_alloc.free(ptr.?); 397 | return null; 398 | } else { 399 | return zig_wren_alloc.realloc(ptr.?, size); 400 | } 401 | } 402 | 403 | // Return an initialized wren configuration 404 | pub fn newConfig() WrenConfiguration { 405 | var config: WrenConfiguration = undefined; 406 | wrenInitConfiguration(&config); 407 | return config; 408 | } 409 | 410 | /// A handle to a Wren object. 411 | /// 412 | /// This lets code outside of the VM hold a persistent reference to an object. 413 | /// After a handle is acquired, and until it is released, this ensures the 414 | /// garbage collector will not reclaim the object it references. 415 | pub const WrenHandle = opaque{}; 416 | 417 | /// A generic allocation function that handles all explicit memory management 418 | /// used by Wren. It's used like so: 419 | /// 420 | /// - To allocate new memory, [memory] is NULL and [newSize] is the desired 421 | /// size. It should return the allocated memory or NULL on failure. 422 | /// 423 | /// - To attempt to grow an existing allocation, [memory] is the memory, and 424 | /// [newSize] is the desired size. It should return [memory] if it was able to 425 | /// grow it in place, or a new pointer if it had to move it. 426 | /// 427 | /// - To shrink memory, [memory] and [newSize] are the same as above but it will 428 | /// always return [memory]. 429 | /// 430 | /// - To free memory, [memory] will be the memory to free and [newSize] will be 431 | /// zero. It should return NULL. 432 | pub const WrenReallocateFn = *const fn (memory: ?*anyopaque, new_size: usize, user_data: ?*anyopaque) callconv(.C) ?*anyopaque; 433 | 434 | /// A function callable from Wren code, but implemented in C. 435 | pub const WrenForeignMethodFn = *const fn (vm: *WrenVM) callconv(.C) void; 436 | 437 | /// A finalizer function for freeing resources owned by an instance of a foreign 438 | /// class. Unlike most foreign methods, finalizers do not have access to the VM 439 | /// and should not interact with it since it's in the middle of a garbage 440 | /// collection. 441 | pub const WrenFinalizerFn = *const fn (data: *anyopaque) callconv(.C) void; 442 | 443 | /// Gives the host a chance to canonicalize the imported module name, 444 | /// potentially taking into account the (previously resolved) name of the module 445 | /// that contains the import. Typically, this is used to implement relative 446 | /// imports. 447 | pub const WrenResolveModuleFn = *const fn (vm: *WrenVM, importer: [*:0]const u8, name: [*:0]const u8) callconv(.C) [*:0]const u8; 448 | 449 | /// Called after loadModuleFn is called for module [name]. The original returned result 450 | /// is handed back to you in this callback, so that you can free 451 | /// memory if appropriate. 452 | pub const WrenLoadModuleCompleteFn = *const fn (vm: *WrenVM, name: [*:0]const u8, result: WrenLoadModuleResult) callconv(.C) void; 453 | 454 | /// The result of a loadModuleFn call. 455 | /// [source] is the source code for the module, or NULL if the module is not found. 456 | /// [onComplete] an optional callback that will be called once Wren is 457 | /// done with the result. 458 | pub const WrenLoadModuleResult = extern struct { 459 | name: [*:0]const u8, 460 | on_complete: WrenLoadModuleCompleteFn, 461 | user_data: *anyopaque, 462 | }; 463 | 464 | /// Loads and returns the source code for the module [name]. 465 | pub const WrenLoadModuleFn = *const fn (vm: *WrenVM, name: [*:0]const u8) callconv(.C) *WrenLoadModuleResult; 466 | 467 | /// Returns a pointer to a foreign method on [className] in [module] with 468 | /// [signature]. 469 | pub const WrenBindForeignMethodFn = *const fn (vm: *WrenVM, module: [*:0]const u8, class_name: [*:0]const u8, is_static: bool, signature: [*:0]const u8) callconv(.C) ?WrenForeignMethodFn; 470 | 471 | /// Displays a string of text to the user. 472 | pub const WrenWriteFn = *const fn (vm: *WrenVM, text: [*:0]const u8) callconv(.C) void; 473 | 474 | pub const WrenErrorType = enum(c_int) { 475 | /// A syntax or resolution error detected at compile time. 476 | WREN_ERROR_COMPILE, 477 | 478 | /// The error message for a runtime error. 479 | WREN_ERROR_RUNTIME, 480 | 481 | /// One entry of a runtime error's stack trace. 482 | WREN_ERROR_STACK_TRACE 483 | }; 484 | 485 | /// Reports an error to the user. 486 | /// 487 | /// An error detected during compile time is reported by calling this once with 488 | /// [type] `WREN_ERROR_COMPILE`, the resolved name of the [module] and [line] 489 | /// where the error occurs, and the compiler's error [message]. 490 | /// 491 | /// A runtime error is reported by calling this once with [type] 492 | /// `WREN_ERROR_RUNTIME`, no [module] or [line], and the runtime error's 493 | /// [message]. After that, a series of [type] `WREN_ERROR_STACK_TRACE` calls are 494 | /// made for each line in the stack trace. Each of those has the resolved 495 | /// [module] and [line] where the method or function is defined and [message] is 496 | /// the name of the method or function. 497 | pub const WrenErrorFn = *const fn (vm: *WrenVM, err_type: WrenErrorType, module: [*:0]const u8, line: c_int, message: [*:0]const u8) callconv(.C) void; 498 | 499 | pub const WrenForeignClassMethods = extern struct { 500 | /// The callback invoked when the foreign object is created. 501 | /// 502 | /// This must be provided. Inside the body of this, it must call 503 | /// [wrenSetSlotNewForeign()] exactly once. 504 | allocate: WrenForeignMethodFn, 505 | 506 | /// The callback invoked when the garbage collector is about to collect a 507 | /// foreign object's memory. 508 | /// 509 | /// This may be `NULL` if the foreign class does not need to finalize. 510 | finalize: WrenFinalizerFn, 511 | }; 512 | 513 | /// Returns a pair of pointers to the foreign methods used to allocate and 514 | /// finalize the data for instances of [className] in resolved [module]. 515 | pub const WrenBindForeignClassFn = *const fn (vm: *WrenVM, module: [*:0]const u8, class_name: [*:0]const u8) callconv(.C) *WrenForeignClassMethods; 516 | 517 | pub const WrenConfiguration = extern struct { 518 | /// The callback Wren will use to allocate, reallocate, and deallocate memory. 519 | /// 520 | /// If `NULL`, defaults to a built-in function that uses `realloc` and `free`. 521 | reallocate_fn: WrenReallocateFn, 522 | 523 | /// The callback Wren uses to resolve a module name. 524 | /// 525 | /// Some host applications may wish to support "relative" imports, where the 526 | /// meaning of an import string depends on the module that contains it. To 527 | /// support that without baking any policy into Wren itself, the VM gives the 528 | /// host a chance to resolve an import string. 529 | /// 530 | /// Before an import is loaded, it calls this, passing in the name of the 531 | /// module that contains the import and the import string. The host app can 532 | /// look at both of those and produce a new "canonical" string that uniquely 533 | /// identifies the module. This string is then used as the name of the module 534 | /// going forward. It is what is passed to [loadModuleFn], how duplicate 535 | /// imports of the same module are detected, and how the module is reported in 536 | /// stack traces. 537 | /// 538 | /// If you leave this function NULL, then the original import string is 539 | /// treated as the resolved string. 540 | /// 541 | /// If an import cannot be resolved by the embedder, it should return NULL and 542 | /// Wren will report that as a runtime error. 543 | /// 544 | /// Wren will take ownership of the string you return and free it for you, so 545 | /// it should be allocated using the same allocation function you provide 546 | /// above. 547 | resolve_module_fn: WrenResolveModuleFn, 548 | 549 | /// The callback Wren uses to load a module. 550 | /// 551 | /// Since Wren does not talk directly to the file system, it relies on the 552 | /// embedder to physically locate and read the source code for a module. The 553 | /// first time an import appears, Wren will call this and pass in the name of 554 | /// the module being imported. The method will return a result, which contains 555 | /// the source code for that module. Memory for the source is owned by the 556 | /// host application, and can be freed using the onComplete callback. 557 | /// 558 | /// This will only be called once for any given module name. Wren caches the 559 | /// result internally so subsequent imports of the same module will use the 560 | /// previous source and not call this. 561 | /// 562 | /// If a module with the given name could not be found by the embedder, it 563 | /// should return NULL and Wren will report that as a runtime error. 564 | load_module_fn: WrenLoadModuleFn, 565 | 566 | /// The callback Wren uses to find a foreign method and bind it to a class. 567 | /// 568 | /// When a foreign method is declared in a class, this will be called with the 569 | /// foreign method's module, class, and signature when the class body is 570 | /// executed. It should return a pointer to the foreign function that will be 571 | /// bound to that method. 572 | /// 573 | /// If the foreign function could not be found, this should return NULL and 574 | /// Wren will report it as runtime error. 575 | bind_foreign_method_fn: WrenBindForeignMethodFn, 576 | 577 | /// The callback Wren uses to find a foreign class and get its foreign methods. 578 | /// 579 | /// When a foreign class is declared, this will be called with the class's 580 | /// module and name when the class body is executed. It should return the 581 | /// foreign functions uses to allocate and (optionally) finalize the bytes 582 | /// stored in the foreign object when an instance is created. 583 | bind_foreign_class_fn: WrenBindForeignClassFn, 584 | 585 | /// The callback Wren uses to display text when `System.print()` or the other 586 | /// related functions are called. 587 | /// 588 | /// If this is `NULL`, Wren discards any printed text. 589 | write_fn: WrenWriteFn, 590 | 591 | /// The callback Wren uses to report errors. 592 | /// 593 | /// When an error occurs, this will be called with the module name, line 594 | /// number, and an error message. If this is `NULL`, Wren doesn't report any 595 | /// errors. 596 | error_fn: WrenErrorFn, 597 | 598 | /// The number of bytes Wren will allocate before triggering the first garbage 599 | /// collection. 600 | /// 601 | /// If zero, defaults to 10MB. 602 | initial_heap_size: usize, 603 | 604 | /// After a collection occurs, the threshold for the next collection is 605 | /// determined based on the number of bytes remaining in use. This allows Wren 606 | /// to shrink its memory usage automatically after reclaiming a large amount 607 | /// of memory. 608 | /// 609 | /// This can be used to ensure that the heap does not get too small, which can 610 | /// in turn lead to a large number of collections afterwards as the heap grows 611 | /// back to a usable size. 612 | /// 613 | /// If zero, defaults to 1MB. 614 | min_heap_size: usize, 615 | 616 | /// Wren will resize the heap automatically as the number of bytes 617 | /// remaining in use after a collection changes. This number determines the 618 | /// amount of additional memory Wren will use after a collection, as a 619 | /// percentage of the current heap size. 620 | /// 621 | /// For example, say that this is 50. After a garbage collection, when there 622 | /// are 400 bytes of memory still in use, the next collection will be triggered 623 | /// after a total of 600 bytes are allocated (including the 400 already in 624 | /// use.) 625 | /// 626 | /// Setting this to a smaller number wastes less memory, but triggers more 627 | /// frequent garbage collections. 628 | /// 629 | /// If zero, defaults to 50. 630 | heap_growth_percent: c_int, 631 | 632 | /// User-defined data associated with the VM. 633 | user_data: ?*anyopaque 634 | }; 635 | 636 | pub const WrenInterpretResult = enum(c_int) { 637 | WREN_RESULT_SUCCESS, 638 | WREN_RESULT_COMPILE_ERROR, 639 | WREN_RESULT_RUNTIME_ERROR 640 | }; 641 | 642 | /// The type of an object stored in a slot. 643 | /// 644 | /// This is not necessarily the object's *class*, but instead its low level 645 | /// representation type. 646 | pub const WrenType = enum(c_int) { 647 | WREN_TYPE_BOOL, 648 | WREN_TYPE_NUM, 649 | WREN_TYPE_FOREIGN, 650 | WREN_TYPE_LIST, 651 | WREN_TYPE_MAP, 652 | WREN_TYPE_NULL, 653 | WREN_TYPE_STRING, 654 | 655 | /// The object is of a type that isn't accessible by the C API. 656 | WREN_TYPE_UNKNOWN 657 | }; 658 | 659 | /// Get the current wren version number. 660 | /// 661 | /// Can be used to range checks over versions. 662 | pub extern fn wrenGetVersionNumber() c_int; 663 | 664 | /// Initializes [configuration] with all of its default values. 665 | /// 666 | /// Call this before setting the particular fields you care about. 667 | pub extern fn wrenInitConfiguration(configuration: *WrenConfiguration) void; 668 | 669 | /// Creates a new Wren virtual machine using the given [configuration]. Wren 670 | /// will copy the configuration data, so the argument passed to this can be 671 | /// freed after calling this. If [configuration] is `NULL`, uses a default 672 | /// configuration. 673 | pub extern fn wrenNewVM(configuration: ?*WrenConfiguration) *WrenVM; 674 | 675 | /// Disposes of all resources is use by [vm], which was previously created by a 676 | /// call to [wrenNewVM]. 677 | pub extern fn wrenFreeVM(vm: *WrenVM) void; 678 | 679 | /// Immediately run the garbage collector to free unused memory. 680 | pub extern fn wrenCollectGarbage(vm: *WrenVM) void; 681 | 682 | /// Runs [source], a string of Wren source code in a new fiber in [vm] in the 683 | /// context of resolved [module]. 684 | pub extern fn wrenInterpret(vm: *WrenVM, module: [*:0]const u8, source: [*:0]const u8) WrenInterpretResult; 685 | 686 | /// Creates a handle that can be used to invoke a method with [signature] on 687 | /// using a receiver and arguments that are set up on the stack. 688 | /// 689 | /// This handle can be used repeatedly to directly invoke that method from C 690 | /// code using [wrenCall]. 691 | /// 692 | /// When you are done with this handle, it must be released using 693 | /// [wrenReleaseHandle]. 694 | pub extern fn wrenMakeCallHandle(vm: *WrenVM, signature: [*:0]const u8) *WrenHandle; 695 | 696 | /// Calls [method], using the receiver and arguments previously set up on the 697 | /// stack. 698 | /// 699 | /// [method] must have been created by a call to [wrenMakeCallHandle]. The 700 | /// arguments to the method must be already on the stack. The receiver should be 701 | /// in slot 0 with the remaining arguments following it, in order. It is an 702 | /// error if the number of arguments provided does not match the method's 703 | /// signature. 704 | /// 705 | /// After this returns, you can access the return value from slot 0 on the stack. 706 | pub extern fn wrenCall(vm: *WrenVM, method: *WrenHandle) WrenInterpretResult; 707 | 708 | /// Releases the reference stored in [handle]. After calling this, [handle] can 709 | /// no longer be used. 710 | pub extern fn wrenReleaseHandle(vm: *WrenVM, handle: *WrenHandle) void; 711 | 712 | // The following functions are intended to be called from foreign methods or 713 | // finalizers. The interface Wren provides to a foreign method is like a 714 | // register machine: you are given a numbered array of slots that values can be 715 | // read from and written to. Values always live in a slot (unless explicitly 716 | // captured using wrenGetSlotHandle(), which ensures the garbage collector can 717 | // find them. 718 | // 719 | // When your foreign function is called, you are given one slot for the receiver 720 | // and each argument to the method. The receiver is in slot 0 and the arguments 721 | // are in increasingly numbered slots after that. You are free to read and 722 | // write to those slots as you want. If you want more slots to use as scratch 723 | // space, you can call wrenEnsureSlots() to add more. 724 | // 725 | // When your function returns, every slot except slot zero is discarded and the 726 | // value in slot zero is used as the return value of the method. If you don't 727 | // store a return value in that slot yourself, it will retain its previous 728 | // value, the receiver. 729 | // 730 | // While Wren is dynamically typed, C is not. This means the C interface has to 731 | // support the various types of primitive values a Wren variable can hold: bool, 732 | // double, string, etc. If we supported this for every operation in the C API, 733 | // there would be a combinatorial explosion of functions, like "get a 734 | // double-valued element from a list", "insert a string key and double value 735 | // into a map", etc. 736 | // 737 | // To avoid that, the only way to convert to and from a raw C value is by going 738 | // into and out of a slot. All other functions work with values already in a 739 | // slot. So, to add an element to a list, you put the list in one slot, and the 740 | // element in another. Then there is a single API function wrenInsertInList() 741 | // that takes the element out of that slot and puts it into the list. 742 | // 743 | // The goal of this API is to be easy to use while not compromising performance. 744 | // The latter means it does not do type or bounds checking at runtime except 745 | // using assertions which are generally removed from release builds. C is an 746 | // unsafe language, so it's up to you to be careful to use it correctly. In 747 | // return, you get a very fast FFI. 748 | 749 | /// Returns the number of slots available to the current foreign method. 750 | pub extern fn wrenGetSlotCount(vm: *WrenVM) c_int; 751 | 752 | /// Ensures that the foreign method stack has at least [numSlots] available for 753 | /// use, growing the stack if needed. 754 | /// 755 | /// Does not shrink the stack if it has more than enough slots. 756 | /// 757 | /// It is an error to call this from a finalizer. 758 | pub extern fn wrenEnsureSlots(vm: *WrenVM, num_slots: c_int) void; 759 | 760 | /// Gets the type of the object in [slot]. 761 | pub extern fn wrenGetSlotType(vm: *WrenVM, slot: c_int) WrenType; 762 | 763 | /// Reads a boolean value from [slot]. 764 | /// 765 | /// It is an error to call this if the slot does not contain a boolean value. 766 | pub extern fn wrenGetSlotBool(vm: *WrenVM, slot: c_int) bool; 767 | 768 | /// Reads a byte array from [slot]. 769 | /// 770 | /// The memory for the returned string is owned by Wren. You can inspect it 771 | /// while in your foreign method, but cannot keep a pointer to it after the 772 | /// function returns, since the garbage collector may reclaim it. 773 | /// 774 | /// Returns a pointer to the first byte of the array and fill [length] with the 775 | /// number of bytes in the array. 776 | /// 777 | /// It is an error to call this if the slot does not contain a string. 778 | pub extern fn wrenGetSlotBytes(vm: *WrenVM, slot: c_int, length: *c_int) [*]const u8; 779 | 780 | /// Reads a number from [slot]. 781 | /// 782 | /// It is an error to call this if the slot does not contain a number. 783 | pub extern fn wrenGetSlotDouble(vm: *WrenVM, slot: c_int) f64; 784 | 785 | /// Reads a foreign object from [slot] and returns a pointer to the foreign data 786 | /// stored with it. 787 | /// 788 | /// It is an error to call this if the slot does not contain an instance of a 789 | /// foreign class. 790 | pub extern fn wrenGetSlotForeign(vm: *WrenVM, slot: c_int) void; 791 | 792 | /// Reads a string from [slot]. 793 | /// 794 | /// The memory for the returned string is owned by Wren. You can inspect it 795 | /// while in your foreign method, but cannot keep a pointer to it after the 796 | /// function returns, since the garbage collector may reclaim it. 797 | /// 798 | /// It is an error to call this if the slot does not contain a string. 799 | pub extern fn wrenGetSlotString(vm: *WrenVM, slot: c_int) [*:0]const u8; 800 | 801 | /// Creates a handle for the value stored in [slot]. 802 | /// 803 | /// This will prevent the object that is referred to from being garbage collected 804 | /// until the handle is released by calling [wrenReleaseHandle()]. 805 | pub extern fn wrenGetSlotHandle(vm: *WrenVM, slot: c_int) *WrenHandle; 806 | 807 | /// Stores the boolean [value] in [slot]. 808 | pub extern fn wrenSetSlotBool(wm: *WrenVM, slot: c_int, value: bool) void; 809 | 810 | /// Stores the array [length] of [bytes] in [slot]. 811 | /// 812 | /// The bytes are copied to a new string within Wren's heap, so you can free 813 | /// memory used by them after this is called. 814 | pub extern fn wrenSetSlotBytes(vm: *WrenVM, slot: c_int, bytes: [*]const u8, length: usize) void; 815 | 816 | /// Stores the numeric [value] in [slot]. 817 | pub extern fn wrenSetSlotDouble(vm: *WrenVM, slot: c_int, value: f64) void; 818 | 819 | /// Creates a new instance of the foreign class stored in [classSlot] with [size] 820 | /// bytes of raw storage and places the resulting object in [slot]. 821 | /// 822 | /// This does not invoke the foreign class's constructor on the new instance. If 823 | /// you need that to happen, call the constructor from Wren, which will then 824 | /// call the allocator foreign method. In there, call this to create the object 825 | /// and then the constructor will be invoked when the allocator returns. 826 | /// 827 | /// Returns a pointer to the foreign object's data. 828 | pub extern fn wrenSetSlotNewForeign(vm: *WrenVM, slot: c_int, class_slot: c_int, size: usize) ?*anyopaque; 829 | 830 | /// Stores a new empty list in [slot]. 831 | pub extern fn wrenSetSlotNewList(vm: *WrenVM, slot: c_int) void; 832 | 833 | /// Stores a new empty map in [slot]. 834 | pub extern fn wrenSetSlotNewMap(vm: *WrenVM, slot: c_int) void; 835 | 836 | /// Stores null in [slot]. 837 | pub extern fn wrenSetSlotNull(vm: *WrenVM, slot: c_int) void; 838 | 839 | /// Stores the string [text] in [slot]. 840 | /// 841 | /// The [text] is copied to a new string within Wren's heap, so you can free 842 | /// memory used by it after this is called. The length is calculated using 843 | /// [strlen()]. If the string may contain any null bytes in the middle, then you 844 | /// should use [wrenSetSlotBytes()] instead. 845 | pub extern fn wrenSetSlotString(vm: *WrenVM, slot: c_int, text: [*:0]const u8) void; 846 | 847 | /// Stores the value captured in [handle] in [slot]. 848 | /// 849 | /// This does not release the handle for the value. 850 | pub extern fn wrenSetSlotHandle(vm: *WrenVM, slot: c_int, handle: *WrenHandle) void; 851 | 852 | /// Returns the number of elements in the list stored in [slot]. 853 | pub extern fn wrenGetListCount(vm: *WrenVM, slot: c_int) c_int; 854 | 855 | /// Reads element [index] from the list in [listSlot] and stores it in 856 | /// [elementSlot]. 857 | pub extern fn wrenGetListElement(vm: *WrenVM, list_slot: c_int, index: c_int, element_slot: c_int) void; 858 | 859 | /// Sets the value stored at [index] in the list at [listSlot], 860 | /// to the value from [elementSlot]. 861 | pub extern fn wrenSetListElement(vm: *WrenVM, list_slot: c_int, index: c_int, element_slot: c_int) void; 862 | 863 | /// Takes the value stored at [elementSlot] and inserts it into the list stored 864 | /// at [listSlot] at [index]. 865 | /// 866 | /// As in Wren, negative indexes can be used to insert from the end. To append 867 | /// an element, use `-1` for the index. 868 | pub extern fn wrenInsertInList(vm: *WrenVM, list_slot: c_int, index: c_int, element_slot: c_int) void; 869 | 870 | /// Returns the number of entries in the map stored in [slot]. 871 | pub extern fn wrenGetMapCount(vm: *WrenVM, slot: c_int) c_int; 872 | 873 | /// Returns true if the key in [keySlot] is found in the map placed in [mapSlot]. 874 | pub extern fn wrenGetMapContainsKey(vm: *WrenVM, map_slot: c_int, key_slot: c_int) bool; 875 | 876 | /// Retrieves a value with the key in [keySlot] from the map in [mapSlot] and 877 | /// stores it in [valueSlot]. 878 | pub extern fn wrenGetMapValue(vm: *WrenVM, map_slot: c_int, key_slot: c_int, value_slot: c_int) void; 879 | 880 | /// Takes the value stored at [valueSlot] and inserts it into the map stored 881 | /// at [mapSlot] with key [keySlot]. 882 | pub extern fn wrenSetMapValue(vm: *WrenVM, map_slot: c_int, key_slot: c_int, value_slot: c_int) void; 883 | 884 | /// Removes a value from the map in [mapSlot], with the key from [keySlot], 885 | /// and place it in [removedValueSlot]. If not found, [removedValueSlot] is 886 | /// set to null, the same behaviour as the Wren Map API. 887 | pub extern fn wrenRemoveMapValue(vm: *WrenVM, map_slot: c_int, key_slot: c_int, removed_value_slot: c_int) void; 888 | 889 | /// Looks up the top level variable with [name] in resolved [module] and stores 890 | /// it in [slot]. 891 | pub extern fn wrenGetVariable(vm: *WrenVM, module: [*:0]const u8, name: [*:0]const u8, slot: c_int) void; 892 | 893 | /// Looks up the top level variable with [name] in resolved [module], 894 | /// returns false if not found. The module must be imported at the time, 895 | /// use wrenHasModule to ensure that before calling. 896 | pub extern fn wrenHasVariable(vm: *WrenVM, module: [*:0]const u8, name: [*:0]const u8) bool; 897 | 898 | /// Returns true if [module] has been imported/resolved before, false if not. 899 | pub extern fn wrenHasModule(vm: *WrenVM, module: [*:0]const u8) bool; 900 | 901 | /// Sets the current fiber to be aborted, and uses the value in [slot] as the 902 | /// runtime error object. 903 | pub extern fn wrenAbortFiber(vm: *WrenVM, slot: c_int) void; 904 | 905 | /// Returns the user data associated with the WrenVM. 906 | pub extern fn wrenGetUserData(vm: *WrenVM) ?*anyopaque; 907 | 908 | /// Sets user data associated with the WrenVM. 909 | pub extern fn wrenSetUserData(vm: *WrenVM, user_data: ?*anyopaque) void; 910 | --------------------------------------------------------------------------------