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