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);