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