1 module wren; 2 3 // The Wren semantic version number components. 4 immutable enum int WREN_VERSION_MAJOR = 0; 5 immutable enum int WREN_VERSION_MINOR = 4; 6 immutable enum int WREN_VERSION_PATCH = 0; 7 8 // A human-friendly string representation of the version. 9 immutable(char)* WREN_VERSION_STRING = "0.4.0"; 10 11 // A monotonically increasing numeric representation of the version number. Use 12 // this if you want to do range checks over versions. 13 immutable enum int WREN_VERSION_NUMBER = WREN_VERSION_MAJOR * 1000000 + WREN_VERSION_MINOR * 1000 + WREN_VERSION_PATCH; 14 15 // A single virtual machine for executing Wren code. 16 // 17 // Wren has no global state, so all state stored by a running interpreter lives 18 // here. 19 struct WrenVM; 20 21 // A handle to a Wren object. 22 // 23 // This lets code outside of the VM hold a persistent reference to an object. 24 // After a handle is acquired, and until it is released, this ensures the 25 // garbage collector will not reclaim the object it references. 26 struct WrenHandle; 27 28 // A generic allocation function that handles all explicit memory management 29 // used by Wren. It's used like so: 30 // 31 // - To allocate new memory, [memory] is NULL and [newSize] is the desired 32 // size. It should return the allocated memory or NULL on failure. 33 // 34 // - To attempt to grow an existing allocation, [memory] is the memory, and 35 // [newSize] is the desired size. It should return [memory] if it was able to 36 // grow it in place, or a new pointer if it had to move it. 37 // 38 // - To shrink memory, [memory] and [newSize] are the same as above but it will 39 // always return [memory]. 40 // 41 // - To free memory, [memory] will be the memory to free and [newSize] will be 42 // zero. It should return NULL. 43 extern(C) alias WrenReallocateFn = void* function(void* memory, size_t newSize, void* userData); 44 45 // A function callable from Wren code, but implemented in C. 46 extern(C) alias WrenForeignMethodFn = void function(WrenVM* vm); 47 48 // A finalizer function for freeing resources owned by an instance of a foreign 49 // class. Unlike most foreign methods, finalizers do not have access to the VM 50 // and should not interact with it since it's in the middle of a garbage 51 // collection. 52 extern(C) alias WrenFinalizerFn = void function(void* data); 53 54 // Gives the host a chance to canonicalize the imported module name, 55 // potentially taking into account the (previously resolved) name of the module 56 // that contains the import. Typically, this is used to implement relative 57 // imports. 58 extern(C) alias WrenResolveModuleFn = const char* function(WrenVM* vm, const char* importer, const char* name); 59 60 // Called after loadModuleFn is called for module [name]. The original returned result 61 // is handed back to you in this callback, so that you can free memory if appropriate. 62 extern(C) alias WrenLoadModuleCompleteFn = void function(WrenVM* vm, const char* name, WrenLoadModuleResult result); 63 64 // The result of a loadModuleFn call. 65 // [source] is the source code for the module, or NULL if the module is not found. 66 // [onComplete] an optional callback that will be called once Wren is done with the result. 67 struct WrenLoadModuleResult 68 { 69 const char* source; 70 WrenLoadModuleCompleteFn onComplete; 71 void* userData; 72 } 73 74 // Loads and returns the source code for the module [name]. 75 extern(C) alias WrenLoadModuleFn = WrenLoadModuleResult function(WrenVM* vm, const char* name); 76 77 // Returns a pointer to a foreign method on [className] in [module] with 78 // [signature]. 79 extern(C) alias WrenBindForeignMethodFn = WrenForeignMethodFn function(WrenVM* vm, 80 const char* mod, 81 const char* className, 82 bool isStatic, 83 const char* signature); 84 85 // Displays a string of text to the user. 86 extern(C) alias WrenWriteFn = void function(WrenVM* vm, const char* text); 87 88 enum WrenErrorType 89 { 90 // A syntax or resolution error detected at compile time. 91 COMPILE, 92 93 // The error message for a runtime error. 94 RUNTIME, 95 96 // One entry of a runtime error's stack trace. 97 STACK_TRACE 98 } 99 100 // Reports an error to the user. 101 // 102 // An error detected during compile time is reported by calling this once with 103 // [type] `WREN_ERROR_COMPILE`, the resolved name of the [module] and [line] 104 // where the error occurs, and the compiler's error [message]. 105 // 106 // A runtime error is reported by calling this once with [type] 107 // `WREN_ERROR_RUNTIME`, no [module] or [line], and the runtime error's 108 // [message]. After that, a series of [type] `WREN_ERROR_STACK_TRACE` calls are 109 // made for each line in the stack trace. Each of those has the resolved 110 // [module] and [line] where the method or function is defined and [message] is 111 // the name of the method or function. 112 extern(C) alias WrenErrorFn = void function( 113 WrenVM* vm, WrenErrorType type, const char* mod, int line, 114 const char* message); 115 116 struct WrenForeignClassMethods 117 { 118 // The callback invoked when the foreign object is created. 119 // 120 // This must be provided. Inside the body of this, it must call 121 // [wrenSetSlotNewForeign()] exactly once. 122 WrenForeignMethodFn allocate; 123 124 // The callback invoked when the garbage collector is about to collect a 125 // foreign object's memory. 126 // 127 // This may be `NULL` if the foreign class does not need to finalize. 128 WrenFinalizerFn finalize; 129 } 130 131 // Returns a pair of pointers to the foreign methods used to allocate and 132 // finalize the data for instances of [className] in resolved [module]. 133 extern(C) alias WrenBindForeignClassFn = WrenForeignClassMethods function( 134 WrenVM* vm, const char* mod, const char* className); 135 136 struct WrenConfiguration 137 { 138 // The callback Wren will use to allocate, reallocate, and deallocate memory. 139 // 140 // If `NULL`, defaults to a built-in function that uses `realloc` and `free`. 141 WrenReallocateFn reallocateFn; 142 143 // The callback Wren uses to resolve a module name. 144 // 145 // Some host applications may wish to support "relative" imports, where the 146 // meaning of an import string depends on the module that contains it. To 147 // support that without baking any policy into Wren itself, the VM gives the 148 // host a chance to resolve an import string. 149 // 150 // Before an import is loaded, it calls this, passing in the name of the 151 // module that contains the import and the import string. The host app can 152 // look at both of those and produce a new "canonical" string that uniquely 153 // identifies the module. This string is then used as the name of the module 154 // going forward. It is what is passed to [loadModuleFn], how duplicate 155 // imports of the same module are detected, and how the module is reported in 156 // stack traces. 157 // 158 // If you leave this function NULL, then the original import string is 159 // treated as the resolved string. 160 // 161 // If an import cannot be resolved by the embedder, it should return NULL and 162 // Wren will report that as a runtime error. 163 // 164 // Wren will take ownership of the string you return and free it for you, so 165 // it should be allocated using the same allocation function you provide 166 // above. 167 WrenResolveModuleFn resolveModuleFn; 168 169 // The callback Wren uses to load a module. 170 // 171 // Since Wren does not talk directly to the file system, it relies on the 172 // embedder to physically locate and read the source code for a module. The 173 // first time an import appears, Wren will call this and pass in the name of 174 // the module being imported. The method will return a result, which contains 175 // the source code for that module. Memory for the source is owned by the 176 // host application, and can be freed using the onComplete callback. 177 // 178 // This will only be called once for any given module name. Wren caches the 179 // result internally so subsequent imports of the same module will use the 180 // previous source and not call this. 181 // 182 // If a module with the given name could not be found by the embedder, it 183 // should return NULL and Wren will report that as a runtime error. 184 WrenLoadModuleFn loadModuleFn; 185 186 // The callback Wren uses to find a foreign method and bind it to a class. 187 // 188 // When a foreign method is declared in a class, this will be called with the 189 // foreign method's module, class, and signature when the class body is 190 // executed. It should return a pointer to the foreign function that will be 191 // bound to that method. 192 // 193 // If the foreign function could not be found, this should return NULL and 194 // Wren will report it as runtime error. 195 WrenBindForeignMethodFn bindForeignMethodFn; 196 197 // The callback Wren uses to find a foreign class and get its foreign methods. 198 // 199 // When a foreign class is declared, this will be called with the class's 200 // module and name when the class body is executed. It should return the 201 // foreign functions uses to allocate and (optionally) finalize the bytes 202 // stored in the foreign object when an instance is created. 203 WrenBindForeignClassFn bindForeignClassFn; 204 205 // The callback Wren uses to display text when `System.print()` or the other 206 // related functions are called. 207 // 208 // If this is `NULL`, Wren discards any printed text. 209 WrenWriteFn writeFn; 210 211 // The callback Wren uses to report errors. 212 // 213 // When an error occurs, this will be called with the module name, line 214 // number, and an error message. If this is `NULL`, Wren doesn't report any 215 // errors. 216 WrenErrorFn errorFn; 217 218 // The number of bytes Wren will allocate before triggering the first garbage 219 // collection. 220 // 221 // If zero, defaults to 10MB. 222 size_t initialHeapSize; 223 224 // After a collection occurs, the threshold for the next collection is 225 // determined based on the number of bytes remaining in use. This allows Wren 226 // to shrink its memory usage automatically after reclaiming a large amount 227 // of memory. 228 // 229 // This can be used to ensure that the heap does not get too small, which can 230 // in turn lead to a large number of collections afterwards as the heap grows 231 // back to a usable size. 232 // 233 // If zero, defaults to 1MB. 234 size_t minHeapSize; 235 236 // Wren will resize the heap automatically as the number of bytes 237 // remaining in use after a collection changes. This number determines the 238 // amount of additional memory Wren will use after a collection, as a 239 // percentage of the current heap size. 240 // 241 // For example, say that this is 50. After a garbage collection, when there 242 // are 400 bytes of memory still in use, the next collection will be triggered 243 // after a total of 600 bytes are allocated (including the 400 already in 244 // use.) 245 // 246 // Setting this to a smaller number wastes less memory, but triggers more 247 // frequent garbage collections. 248 // 249 // If zero, defaults to 50. 250 int heapGrowthPercent; 251 252 // User-defined data associated with the VM. 253 void* userData; 254 255 } 256 257 enum WrenInterpretResult 258 { 259 SUCCESS, 260 COMPILE_ERROR, 261 RUNTIME_ERROR 262 } 263 264 // The type of an object stored in a slot. 265 // 266 // This is not necessarily the object's *class*, but instead its low level 267 // representation type. 268 enum WrenType 269 { 270 BOOL, 271 NUM, 272 FOREIGN, 273 LIST, 274 MAP, 275 NULL, 276 STRING, 277 278 // The object is of a type that isn't accessible by the C API. 279 UNKNOWN 280 } 281 282 // Get the current wren version number. 283 // 284 // Can be used to range checks over versions. 285 extern(C) int wrenGetVersionNumber(); 286 287 // Initializes [configuration] with all of its default values. 288 // 289 // Call this before setting the particular fields you care about. 290 extern(C) void wrenInitConfiguration(WrenConfiguration* configuration); 291 292 // Creates a new Wren virtual machine using the given [configuration]. Wren 293 // will copy the configuration data, so the argument passed to this can be 294 // freed after calling this. If [configuration] is `NULL`, uses a default 295 // configuration. 296 extern(C) WrenVM* wrenNewVM(WrenConfiguration* configuration); 297 298 // Disposes of all resources is use by [vm], which was previously created by a 299 // call to [wrenNewVM]. 300 extern(C) void wrenFreeVM(WrenVM* vm); 301 302 // Immediately run the garbage collector to free unused memory. 303 extern(C) void wrenCollectGarbage(WrenVM* vm); 304 305 // Runs [source], a string of Wren source code in a new fiber in [vm] in the 306 // context of resolved [module]. 307 extern(C) WrenInterpretResult wrenInterpret(WrenVM* vm, const char* mod, 308 const char* source); 309 310 // Creates a handle that can be used to invoke a method with [signature] on 311 // using a receiver and arguments that are set up on the stack. 312 // 313 // This handle can be used repeatedly to directly invoke that method from C 314 // code using [wrenCall]. 315 // 316 // When you are done with this handle, it must be released using 317 // [wrenReleaseHandle]. 318 extern(C) WrenHandle* wrenMakeCallHandle(WrenVM* vm, const char* signature); 319 320 // Calls [method], using the receiver and arguments previously set up on the 321 // stack. 322 // 323 // [method] must have been created by a call to [wrenMakeCallHandle]. The 324 // arguments to the method must be already on the stack. The receiver should be 325 // in slot 0 with the remaining arguments following it, in order. It is an 326 // error if the number of arguments provided does not match the method's 327 // signature. 328 // 329 // After this returns, you can access the return value from slot 0 on the stack. 330 extern(C) WrenInterpretResult wrenCall(WrenVM* vm, WrenHandle* method); 331 332 // Releases the reference stored in [handle]. After calling this, [handle] can 333 // no longer be used. 334 extern(C) void wrenReleaseHandle(WrenVM* vm, WrenHandle* handle); 335 336 // The following functions are intended to be called from foreign methods or 337 // finalizers. The interface Wren provides to a foreign method is like a 338 // register machine: you are given a numbered array of slots that values can be 339 // read from and written to. Values always live in a slot (unless explicitly 340 // captured using wrenGetSlotHandle(), which ensures the garbage collector can 341 // find them. 342 // 343 // When your foreign function is called, you are given one slot for the receiver 344 // and each argument to the method. The receiver is in slot 0 and the arguments 345 // are in increasingly numbered slots after that. You are free to read and 346 // write to those slots as you want. If you want more slots to use as scratch 347 // space, you can call wrenEnsureSlots() to add more. 348 // 349 // When your function returns, every slot except slot zero is discarded and the 350 // value in slot zero is used as the return value of the method. If you don't 351 // store a return value in that slot yourself, it will retain its previous 352 // value, the receiver. 353 // 354 // While Wren is dynamically typed, C is not. This means the C interface has to 355 // support the various types of primitive values a Wren variable can hold: bool, 356 // double, string, etc. If we supported this for every operation in the C API, 357 // there would be a combinatorial explosion of functions, like "get a 358 // double-valued element from a list", "insert a string key and double value 359 // into a map", etc. 360 // 361 // To avoid that, the only way to convert to and from a raw C value is by going 362 // into and out of a slot. All other functions work with values already in a 363 // slot. So, to add an element to a list, you put the list in one slot, and the 364 // element in another. Then there is a single API function wrenInsertInList() 365 // that takes the element out of that slot and puts it into the list. 366 // 367 // The goal of this API is to be easy to use while not compromising performance. 368 // The latter means it does not do type or bounds checking at runtime except 369 // using assertions which are generally removed from release builds. C is an 370 // unsafe language, so it's up to you to be careful to use it correctly. In 371 // return, you get a very fast FFI. 372 373 // Returns the number of slots available to the current foreign method. 374 extern(C) int wrenGetSlotCount(WrenVM* vm); 375 376 // Ensures that the foreign method stack has at least [numSlots] available for 377 // use, growing the stack if needed. 378 // 379 // Does not shrink the stack if it has more than enough slots. 380 // 381 // It is an error to call this from a finalizer. 382 extern(C) void wrenEnsureSlots(WrenVM* vm, int numSlots); 383 384 // Gets the type of the object in [slot]. 385 extern(C) WrenType wrenGetSlotType(WrenVM* vm, int slot); 386 387 // Reads a boolean value from [slot]. 388 // 389 // It is an error to call this if the slot does not contain a boolean value. 390 extern(C) bool wrenGetSlotBool(WrenVM* vm, int slot); 391 392 // Reads a byte array from [slot]. 393 // 394 // The memory for the returned string is owned by Wren. You can inspect it 395 // while in your foreign method, but cannot keep a pointer to it after the 396 // function returns, since the garbage collector may reclaim it. 397 // 398 // Returns a pointer to the first byte of the array and fill [length] with the 399 // number of bytes in the array. 400 // 401 // It is an error to call this if the slot does not contain a string. 402 extern(C) const(char)* wrenGetSlotBytes(WrenVM* vm, int slot, int* length); 403 404 // Reads a number from [slot]. 405 // 406 // It is an error to call this if the slot does not contain a number. 407 extern(C) double wrenGetSlotDouble(WrenVM* vm, int slot); 408 409 // Reads a foreign object from [slot] and returns a pointer to the foreign data 410 // stored with it. 411 // 412 // It is an error to call this if the slot does not contain an instance of a 413 // foreign class. 414 extern(C) void* wrenGetSlotForeign(WrenVM* vm, int slot); 415 416 // Reads a string from [slot]. 417 // 418 // The memory for the returned string is owned by Wren. You can inspect it 419 // while in your foreign method, but cannot keep a pointer to it after the 420 // function returns, since the garbage collector may reclaim it. 421 // 422 // It is an error to call this if the slot does not contain a string. 423 extern(C) const(char)* wrenGetSlotString(WrenVM* vm, int slot); 424 425 // Creates a handle for the value stored in [slot]. 426 // 427 // This will prevent the object that is referred to from being garbage collected 428 // until the handle is released by calling [wrenReleaseHandle()]. 429 extern(C) WrenHandle* wrenGetSlotHandle(WrenVM* vm, int slot); 430 431 // Stores the boolean [value] in [slot]. 432 extern(C) void wrenSetSlotBool(WrenVM* vm, int slot, bool value); 433 434 // Stores the array [length] of [bytes] in [slot]. 435 // 436 // The bytes are copied to a new string within Wren's heap, so you can free 437 // memory used by them after this is called. 438 extern(C) void wrenSetSlotBytes(WrenVM* vm, int slot, const char* bytes, size_t length); 439 440 // Stores the numeric [value] in [slot]. 441 extern(C) void wrenSetSlotDouble(WrenVM* vm, int slot, double value); 442 443 // Creates a new instance of the foreign class stored in [classSlot] with [size] 444 // bytes of raw storage and places the resulting object in [slot]. 445 // 446 // This does not invoke the foreign class's constructor on the new instance. If 447 // you need that to happen, call the constructor from Wren, which will then 448 // call the allocator foreign method. In there, call this to create the object 449 // and then the constructor will be invoked when the allocator returns. 450 // 451 // Returns a pointer to the foreign object's data. 452 extern(C) void* wrenSetSlotNewForeign(WrenVM* vm, int slot, int classSlot, size_t size); 453 454 // Stores a new empty list in [slot]. 455 extern(C) void wrenSetSlotNewList(WrenVM* vm, int slot); 456 457 // Stores a new empty map in [slot]. 458 extern(C) void wrenSetSlotNewMap(WrenVM* vm, int slot); 459 460 // Stores null in [slot]. 461 extern(C) void wrenSetSlotNull(WrenVM* vm, int slot); 462 463 // Stores the string [text] in [slot]. 464 // 465 // The [text] is copied to a new string within Wren's heap, so you can free 466 // memory used by it after this is called. The length is calculated using 467 // [strlen()]. If the string may contain any null bytes in the middle, then you 468 // should use [wrenSetSlotBytes()] instead. 469 extern(C) void wrenSetSlotString(WrenVM* vm, int slot, const char* text); 470 471 // Stores the value captured in [handle] in [slot]. 472 // 473 // This does not release the handle for the value. 474 extern(C) void wrenSetSlotHandle(WrenVM* vm, int slot, WrenHandle* handle); 475 476 // Returns the number of elements in the list stored in [slot]. 477 extern(C) int wrenGetListCount(WrenVM* vm, int slot); 478 479 // Reads element [index] from the list in [listSlot] and stores it in 480 // [elementSlot]. 481 extern(C) void wrenGetListElement(WrenVM* vm, int listSlot, int index, int elementSlot); 482 483 // Sets the value stored at [index] in the list at [listSlot], 484 // to the value from [elementSlot]. 485 extern(C) void wrenSetListElement(WrenVM* vm, int listSlot, int index, int elementSlot); 486 487 // Takes the value stored at [elementSlot] and inserts it into the list stored 488 // at [listSlot] at [index]. 489 // 490 // As in Wren, negative indexes can be used to insert from the end. To append 491 // an element, use `-1` for the index. 492 extern(C) void wrenInsertInList(WrenVM* vm, int listSlot, int index, int elementSlot); 493 494 // Returns the number of entries in the map stored in [slot]. 495 extern(C) int wrenGetMapCount(WrenVM* vm, int slot); 496 497 // Returns true if the key in [keySlot] is found in the map placed in [mapSlot]. 498 extern(C) bool wrenGetMapContainsKey(WrenVM* vm, int mapSlot, int keySlot); 499 500 // Retrieves a value with the key in [keySlot] from the map in [mapSlot] and 501 // stores it in [valueSlot]. 502 extern(C) void wrenGetMapValue(WrenVM* vm, int mapSlot, int keySlot, int valueSlot); 503 504 // Takes the value stored at [valueSlot] and inserts it into the map stored 505 // at [mapSlot] with key [keySlot]. 506 extern(C) void wrenSetMapValue(WrenVM* vm, int mapSlot, int keySlot, int valueSlot); 507 508 // Removes a value from the map in [mapSlot], with the key from [keySlot], 509 // and place it in [removedValueSlot]. If not found, [removedValueSlot] is 510 // set to null, the same behaviour as the Wren Map API. 511 extern(C) void wrenRemoveMapValue(WrenVM* vm, int mapSlot, int keySlot, 512 int removedValueSlot); 513 514 // Looks up the top level variable with [name] in resolved [module] and stores 515 // it in [slot]. 516 extern(C) void wrenGetVariable(WrenVM* vm, const char* mod, const char* name, 517 int slot); 518 519 // Looks up the top level variable with [name] in resolved [module], 520 // returns false if not found. The module must be imported at the time, 521 // use wrenHasModule to ensure that before calling. 522 extern(C) bool wrenHasVariable(WrenVM* vm, const char* mod, const char* name); 523 524 // Returns true if [module] has been imported/resolved before, false if not. 525 extern(C) bool wrenHasModule(WrenVM* vm, const char* mod); 526 527 // Sets the current fiber to be aborted, and uses the value in [slot] as the 528 // runtime error object. 529 extern(C) void wrenAbortFiber(WrenVM* vm, int slot); 530 531 // Returns the user data associated with the WrenVM. 532 extern(C) void* wrenGetUserData(WrenVM* vm); 533 534 // Sets user data associated with the WrenVM. 535 extern(C) void wrenSetUserData(WrenVM* vm, void* userData);