1#ifndef wren_value_h
2#define wren_value_h
3
4#include <stdbool.h>
5#include <string.h>
6
7#include "wren_common.h"
8#include "wren_math.h"
9#include "wren_utils.h"
10
11// This defines the built-in types and their core representations in memory.
12// Since Wren is dynamically typed, any variable can hold a value of any type,
13// and the type can change at runtime. Implementing this efficiently is
14// critical for performance.
15//
16// The main type exposed by this is [Value]. A C variable of that type is a
17// storage location that can hold any Wren value. The stack, module variables,
18// and instance fields are all implemented in C as variables of type Value.
19//
20// The built-in types for booleans, numbers, and null are unboxed: their value
21// is stored directly in the Value, and copying a Value copies the value. Other
22// types--classes, instances of classes, functions, lists, and strings--are all
23// reference types. They are stored on the heap and the Value just stores a
24// pointer to it. Copying the Value copies a reference to the same object. The
25// Wren implementation calls these "Obj", or objects, though to a user, all
26// values are objects.
27//
28// There is also a special singleton value "undefined". It is used internally
29// but never appears as a real value to a user. It has two uses:
30//
31// - It is used to identify module variables that have been implicitly declared
32// by use in a forward reference but not yet explicitly declared. These only
33// exist during compilation and do not appear at runtime.
34//
35// - It is used to represent unused map entries in an ObjMap.
36//
37// There are two supported Value representations. The main one uses a technique
38// called "NaN tagging" (explained in detail below) to store a number, any of
39// the value types, or a pointer, all inside one double-precision floating
40// point number. A larger, slower, Value type that uses a struct to store these
41// is also supported, and is useful for debugging the VM.
42//
43// The representation is controlled by the `WREN_NAN_TAGGING` define. If that's
44// defined, Nan tagging is used.
45
46// These macros cast a Value to one of the specific object types. These do *not*
47// perform any validation, so must only be used after the Value has been
48// ensured to be the right type.
49#define AS_CLASS(value) ((ObjClass*)AS_OBJ(value)) // ObjClass*
50#define AS_CLOSURE(value) ((ObjClosure*)AS_OBJ(value)) // ObjClosure*
51#define AS_FIBER(v) ((ObjFiber*)AS_OBJ(v)) // ObjFiber*
52#define AS_FN(value) ((ObjFn*)AS_OBJ(value)) // ObjFn*
53#define AS_FOREIGN(v) ((ObjForeign*)AS_OBJ(v)) // ObjForeign*
54#define AS_INSTANCE(value) ((ObjInstance*)AS_OBJ(value)) // ObjInstance*
55#define AS_LIST(value) ((ObjList*)AS_OBJ(value)) // ObjList*
56#define AS_MAP(value) ((ObjMap*)AS_OBJ(value)) // ObjMap*
57#define AS_MODULE(value) ((ObjModule*)AS_OBJ(value)) // ObjModule*
58#define AS_NUM(value) (wrenValueToNum(value)) // double
59#define AS_RANGE(v) ((ObjRange*)AS_OBJ(v)) // ObjRange*
60#define AS_STRING(v) ((ObjString*)AS_OBJ(v)) // ObjString*
61#define AS_CSTRING(v) (AS_STRING(v)->value) // const char*
62
63// These macros promote a primitive C value to a full Wren Value. There are
64// more defined below that are specific to the Nan tagged or other
65// representation.
66#define BOOL_VAL(boolean) ((boolean) ? TRUE_VAL : FALSE_VAL) // boolean
67#define NUM_VAL(num) (wrenNumToValue(num)) // double
68#define OBJ_VAL(obj) (wrenObjectToValue((Obj*)(obj))) // Any Obj___*
69
70// These perform type tests on a Value, returning `true` if the Value is of the
71// given type.
72#define IS_BOOL(value) (wrenIsBool(value)) // Bool
73#define IS_CLASS(value) (wrenIsObjType(value, OBJ_CLASS)) // ObjClass
74#define IS_CLOSURE(value) (wrenIsObjType(value, OBJ_CLOSURE)) // ObjClosure
75#define IS_FIBER(value) (wrenIsObjType(value, OBJ_FIBER)) // ObjFiber
76#define IS_FN(value) (wrenIsObjType(value, OBJ_FN)) // ObjFn
77#define IS_FOREIGN(value) (wrenIsObjType(value, OBJ_FOREIGN)) // ObjForeign
78#define IS_INSTANCE(value) (wrenIsObjType(value, OBJ_INSTANCE)) // ObjInstance
79#define IS_LIST(value) (wrenIsObjType(value, OBJ_LIST)) // ObjList
80#define IS_MAP(value) (wrenIsObjType(value, OBJ_MAP)) // ObjMap
81#define IS_RANGE(value) (wrenIsObjType(value, OBJ_RANGE)) // ObjRange
82#define IS_STRING(value) (wrenIsObjType(value, OBJ_STRING)) // ObjString
83
84// Creates a new string object from [text], which should be a bare C string
85// literal. This determines the length of the string automatically at compile
86// time based on the size of the character array (-1 for the terminating '\0').
87#define CONST_STRING(vm, text) wrenNewStringLength((vm), (text), sizeof(text) - 1)
88
89// Identifies which specific type a heap-allocated object is.
90typedef enum {
91 OBJ_CLASS,
92 OBJ_CLOSURE,
93 OBJ_FIBER,
94 OBJ_FN,
95 OBJ_FOREIGN,
96 OBJ_INSTANCE,
97 OBJ_LIST,
98 OBJ_MAP,
99 OBJ_MODULE,
100 OBJ_RANGE,
101 OBJ_STRING,
102 OBJ_UPVALUE
103} ObjType;
104
105typedef struct sObjClass ObjClass;
106
107// Base struct for all heap-allocated objects.
108typedef struct sObj Obj;
109struct sObj
110{
111 ObjType type;
112 bool isDark;
113
114 // The object's class.
115 ObjClass* classObj;
116
117 // The next object in the linked list of all currently allocated objects.
118 struct sObj* next;
119};
120
121#if WREN_NAN_TAGGING
122
123typedef uint64_t Value;
124
125#else
126
127typedef enum
128{
129 VAL_FALSE,
130 VAL_NULL,
131 VAL_NUM,
132 VAL_TRUE,
133 VAL_UNDEFINED,
134 VAL_OBJ
135} ValueType;
136
137typedef struct
138{
139 ValueType type;
140 union
141 {
142 double num;
143 Obj* obj;
144 } as;
145} Value;
146
147#endif
148
149DECLARE_BUFFER(Value, Value);
150
151// A heap-allocated string object.
152struct sObjString
153{
154 Obj obj;
155
156 // Number of bytes in the string, not including the null terminator.
157 uint32_t length;
158
159 // The hash value of the string's contents.
160 uint32_t hash;
161
162 // Inline array of the string's bytes followed by a null terminator.
163 char value[FLEXIBLE_ARRAY];
164};
165
166// The dynamically allocated data structure for a variable that has been used
167// by a closure. Whenever a function accesses a variable declared in an
168// enclosing function, it will get to it through this.
169//
170// An upvalue can be either "closed" or "open". An open upvalue points directly
171// to a [Value] that is still stored on the fiber's stack because the local
172// variable is still in scope in the function where it's declared.
173//
174// When that local variable goes out of scope, the upvalue pointing to it will
175// be closed. When that happens, the value gets copied off the stack into the
176// upvalue itself. That way, it can have a longer lifetime than the stack
177// variable.
178typedef struct sObjUpvalue
179{
180 // The object header. Note that upvalues have this because they are garbage
181 // collected, but they are not first class Wren objects.
182 Obj obj;
183
184 // Pointer to the variable this upvalue is referencing.
185 Value* value;
186
187 // If the upvalue is closed (i.e. the local variable it was pointing to has
188 // been popped off the stack) then the closed-over value will be hoisted out
189 // of the stack into here. [value] will then be changed to point to this.
190 Value closed;
191
192 // Open upvalues are stored in a linked list by the fiber. This points to the
193 // next upvalue in that list.
194 struct sObjUpvalue* next;
195} ObjUpvalue;
196
197// The type of a primitive function.
198//
199// Primitives are similar to foreign functions, but have more direct access to
200// VM internals. It is passed the arguments in [args]. If it returns a value,
201// it places it in `args[0]` and returns `true`. If it causes a runtime error
202// or modifies the running fiber, it returns `false`.
203typedef bool (*Primitive)(WrenVM* vm, Value* args);
204
205// TODO: See if it's actually a perf improvement to have this in a separate
206// struct instead of in ObjFn.
207// Stores debugging information for a function used for things like stack
208// traces.
209typedef struct
210{
211 // The name of the function. Heap allocated and owned by the FnDebug.
212 char* name;
213
214 // An array of line numbers. There is one element in this array for each
215 // bytecode in the function's bytecode array. The value of that element is
216 // the line in the source code that generated that instruction.
217 IntBuffer sourceLines;
218} FnDebug;
219
220// A loaded module and the top-level variables it defines.
221//
222// While this is an Obj and is managed by the GC, it never appears as a
223// first-class object in Wren.
224typedef struct
225{
226 Obj obj;
227
228 // The currently defined top-level variables.
229 ValueBuffer variables;
230
231 // Symbol table for the names of all module variables. Indexes here directly
232 // correspond to entries in [variables].
233 SymbolTable variableNames;
234
235 // The name of the module.
236 ObjString* name;
237} ObjModule;
238
239// A function object. It wraps and owns the bytecode and other debug information
240// for a callable chunk of code.
241//
242// Function objects are not passed around and invoked directly. Instead, they
243// are always referenced by an [ObjClosure] which is the real first-class
244// representation of a function. This isn't strictly necessary if they function
245// has no upvalues, but lets the rest of the VM assume all called objects will
246// be closures.
247typedef struct
248{
249 Obj obj;
250
251 ByteBuffer code;
252 ValueBuffer constants;
253
254 // The module where this function was defined.
255 ObjModule* module;
256
257 // The maximum number of stack slots this function may use.
258 int maxSlots;
259
260 // The number of upvalues this function closes over.
261 int numUpvalues;
262
263 // The number of parameters this function expects. Used to ensure that .call
264 // handles a mismatch between number of parameters and arguments. This will
265 // only be set for fns, and not ObjFns that represent methods or scripts.
266 int arity;
267 FnDebug* debug;
268} ObjFn;
269
270// An instance of a first-class function and the environment it has closed over.
271// Unlike [ObjFn], this has captured the upvalues that the function accesses.
272typedef struct
273{
274 Obj obj;
275
276 // The function that this closure is an instance of.
277 ObjFn* fn;
278
279 // The upvalues this function has closed over.
280 ObjUpvalue* upvalues[FLEXIBLE_ARRAY];
281} ObjClosure;
282
283typedef struct
284{
285 // Pointer to the current (really next-to-be-executed) instruction in the
286 // function's bytecode.
287 uint8_t* ip;
288
289 // The closure being executed.
290 ObjClosure* closure;
291
292 // Pointer to the first stack slot used by this call frame. This will contain
293 // the receiver, followed by the function's parameters, then local variables
294 // and temporaries.
295 Value* stackStart;
296} CallFrame;
297
298// Tracks how this fiber has been invoked, aside from the ways that can be
299// detected from the state of other fields in the fiber.
300typedef enum
301{
302 // The fiber is being run from another fiber using a call to `try()`.
303 FIBER_TRY,
304
305 // The fiber was directly invoked by `runInterpreter()`. This means it's the
306 // initial fiber used by a call to `wrenCall()` or `wrenInterpret()`.
307 FIBER_ROOT,
308
309 // The fiber is invoked some other way. If [caller] is `NULL` then the fiber
310 // was invoked using `call()`. If [numFrames] is zero, then the fiber has
311 // finished running and is done. If [numFrames] is one and that frame's `ip`
312 // points to the first byte of code, the fiber has not been started yet.
313 FIBER_OTHER,
314} FiberState;
315
316typedef struct sObjFiber
317{
318 Obj obj;
319
320 // The stack of value slots. This is used for holding local variables and
321 // temporaries while the fiber is executing. It is heap-allocated and grown
322 // as needed.
323 Value* stack;
324
325 // A pointer to one past the top-most value on the stack.
326 Value* stackTop;
327
328 // The number of allocated slots in the stack array.
329 int stackCapacity;
330
331 // The stack of call frames. This is a dynamic array that grows as needed but
332 // never shrinks.
333 CallFrame* frames;
334
335 // The number of frames currently in use in [frames].
336 int numFrames;
337
338 // The number of [frames] allocated.
339 int frameCapacity;
340
341 // Pointer to the first node in the linked list of open upvalues that are
342 // pointing to values still on the stack. The head of the list will be the
343 // upvalue closest to the top of the stack, and then the list works downwards.
344 ObjUpvalue* openUpvalues;
345
346 // The fiber that ran this one. If this fiber is yielded, control will resume
347 // to this one. May be `NULL`.
348 struct sObjFiber* caller;
349
350 // If the fiber failed because of a runtime error, this will contain the
351 // error object. Otherwise, it will be null.
352 Value error;
353
354 FiberState state;
355} ObjFiber;
356
357typedef enum
358{
359 // A primitive method implemented in C in the VM. Unlike foreign methods,
360 // this can directly manipulate the fiber's stack.
361 METHOD_PRIMITIVE,
362
363 // A primitive that handles .call on Fn.
364 METHOD_FUNCTION_CALL,
365
366 // A externally-defined C method.
367 METHOD_FOREIGN,
368
369 // A normal user-defined method.
370 METHOD_BLOCK,
371
372 // No method for the given symbol.
373 METHOD_NONE
374} MethodType;
375
376typedef struct
377{
378 MethodType type;
379
380 // The method function itself. The [type] determines which field of the union
381 // is used.
382 union
383 {
384 Primitive primitive;
385 WrenForeignMethodFn foreign;
386 ObjClosure* closure;
387 } as;
388} Method;
389
390DECLARE_BUFFER(Method, Method);
391
392struct sObjClass
393{
394 Obj obj;
395 ObjClass* superclass;
396
397 // The number of fields needed for an instance of this class, including all
398 // of its superclass fields.
399 int numFields;
400
401 // The table of methods that are defined in or inherited by this class.
402 // Methods are called by symbol, and the symbol directly maps to an index in
403 // this table. This makes method calls fast at the expense of empty cells in
404 // the list for methods the class doesn't support.
405 //
406 // You can think of it as a hash table that never has collisions but has a
407 // really low load factor. Since methods are pretty small (just a type and a
408 // pointer), this should be a worthwhile trade-off.
409 MethodBuffer methods;
410
411 // The name of the class.
412 ObjString* name;
413
414 // The ClassAttribute for the class, if any
415 Value attributes;
416};
417
418typedef struct
419{
420 Obj obj;
421 uint8_t data[FLEXIBLE_ARRAY];
422} ObjForeign;
423
424typedef struct
425{
426 Obj obj;
427 Value fields[FLEXIBLE_ARRAY];
428} ObjInstance;
429
430typedef struct
431{
432 Obj obj;
433
434 // The elements in the list.
435 ValueBuffer elements;
436} ObjList;
437
438typedef struct
439{
440 // The entry's key, or UNDEFINED_VAL if the entry is not in use.
441 Value key;
442
443 // The value associated with the key. If the key is UNDEFINED_VAL, this will
444 // be false to indicate an open available entry or true to indicate a
445 // tombstone -- an entry that was previously in use but was then deleted.
446 Value value;
447} MapEntry;
448
449// A hash table mapping keys to values.
450//
451// We use something very simple: open addressing with linear probing. The hash
452// table is an array of entries. Each entry is a key-value pair. If the key is
453// the special UNDEFINED_VAL, it indicates no value is currently in that slot.
454// Otherwise, it's a valid key, and the value is the value associated with it.
455//
456// When entries are added, the array is dynamically scaled by GROW_FACTOR to
457// keep the number of filled slots under MAP_LOAD_PERCENT. Likewise, if the map
458// gets empty enough, it will be resized to a smaller array. When this happens,
459// all existing entries are rehashed and re-added to the new array.
460//
461// When an entry is removed, its slot is replaced with a "tombstone". This is an
462// entry whose key is UNDEFINED_VAL and whose value is TRUE_VAL. When probing
463// for a key, we will continue past tombstones, because the desired key may be
464// found after them if the key that was removed was part of a prior collision.
465// When the array gets resized, all tombstones are discarded.
466typedef struct
467{
468 Obj obj;
469
470 // The number of entries allocated.
471 uint32_t capacity;
472
473 // The number of entries in the map.
474 uint32_t count;
475
476 // Pointer to a contiguous array of [capacity] entries.
477 MapEntry* entries;
478} ObjMap;
479
480typedef struct
481{
482 Obj obj;
483
484 // The beginning of the range.
485 double from;
486
487 // The end of the range. May be greater or less than [from].
488 double to;
489
490 // True if [to] is included in the range.
491 bool isInclusive;
492} ObjRange;
493
494// An IEEE 754 double-precision float is a 64-bit value with bits laid out like:
495//
496// 1 Sign bit
497// | 11 Exponent bits
498// | | 52 Mantissa (i.e. fraction) bits
499// | | |
500// S[Exponent-][Mantissa------------------------------------------]
501//
502// The details of how these are used to represent numbers aren't really
503// relevant here as long we don't interfere with them. The important bit is NaN.
504//
505// An IEEE double can represent a few magical values like NaN ("not a number"),
506// Infinity, and -Infinity. A NaN is any value where all exponent bits are set:
507//
508// v--NaN bits
509// -11111111111----------------------------------------------------
510//
511// Here, "-" means "doesn't matter". Any bit sequence that matches the above is
512// a NaN. With all of those "-", it obvious there are a *lot* of different
513// bit patterns that all mean the same thing. NaN tagging takes advantage of
514// this. We'll use those available bit patterns to represent things other than
515// numbers without giving up any valid numeric values.
516//
517// NaN values come in two flavors: "signalling" and "quiet". The former are
518// intended to halt execution, while the latter just flow through arithmetic
519// operations silently. We want the latter. Quiet NaNs are indicated by setting
520// the highest mantissa bit:
521//
522// v--Highest mantissa bit
523// -[NaN ]1---------------------------------------------------
524//
525// If all of the NaN bits are set, it's not a number. Otherwise, it is.
526// That leaves all of the remaining bits as available for us to play with. We
527// stuff a few different kinds of things here: special singleton values like
528// "true", "false", and "null", and pointers to objects allocated on the heap.
529// We'll use the sign bit to distinguish singleton values from pointers. If
530// it's set, it's a pointer.
531//
532// v--Pointer or singleton?
533// S[NaN ]1---------------------------------------------------
534//
535// For singleton values, we just enumerate the different values. We'll use the
536// low bits of the mantissa for that, and only need a few:
537//
538// 3 Type bits--v
539// 0[NaN ]1------------------------------------------------[T]
540//
541// For pointers, we are left with 51 bits of mantissa to store an address.
542// That's more than enough room for a 32-bit address. Even 64-bit machines
543// only actually use 48 bits for addresses, so we've got plenty. We just stuff
544// the address right into the mantissa.
545//
546// Ta-da, double precision numbers, pointers, and a bunch of singleton values,
547// all stuffed into a single 64-bit sequence. Even better, we don't have to
548// do any masking or work to extract number values: they are unmodified. This
549// means math on numbers is fast.
550#if WREN_NAN_TAGGING
551
552// A mask that selects the sign bit.
553#define SIGN_BIT ((uint64_t)1 << 63)
554
555// The bits that must be set to indicate a quiet NaN.
556#define QNAN ((uint64_t)0x7ffc000000000000)
557
558// If the NaN bits are set, it's not a number.
559#define IS_NUM(value) (((value) & QNAN) != QNAN)
560
561// An object pointer is a NaN with a set sign bit.
562#define IS_OBJ(value) (((value) & (QNAN | SIGN_BIT)) == (QNAN | SIGN_BIT))
563
564#define IS_FALSE(value) ((value) == FALSE_VAL)
565#define IS_NULL(value) ((value) == NULL_VAL)
566#define IS_UNDEFINED(value) ((value) == UNDEFINED_VAL)
567
568// Masks out the tag bits used to identify the singleton value.
569#define MASK_TAG (7)
570
571// Tag values for the different singleton values.
572#define TAG_NAN (0)
573#define TAG_NULL (1)
574#define TAG_FALSE (2)
575#define TAG_TRUE (3)
576#define TAG_UNDEFINED (4)
577#define TAG_UNUSED2 (5)
578#define TAG_UNUSED3 (6)
579#define TAG_UNUSED4 (7)
580
581// Value -> 0 or 1.
582#define AS_BOOL(value) ((value) == TRUE_VAL)
583
584// Value -> Obj*.
585#define AS_OBJ(value) ((Obj*)(uintptr_t)((value) & ~(SIGN_BIT | QNAN)))
586
587// Singleton values.
588#define NULL_VAL ((Value)(uint64_t)(QNAN | TAG_NULL))
589#define FALSE_VAL ((Value)(uint64_t)(QNAN | TAG_FALSE))
590#define TRUE_VAL ((Value)(uint64_t)(QNAN | TAG_TRUE))
591#define UNDEFINED_VAL ((Value)(uint64_t)(QNAN | TAG_UNDEFINED))
592
593// Gets the singleton type tag for a Value (which must be a singleton).
594#define GET_TAG(value) ((int)((value) & MASK_TAG))
595
596#else
597
598// Value -> 0 or 1.
599#define AS_BOOL(value) ((value).type == VAL_TRUE)
600
601// Value -> Obj*.
602#define AS_OBJ(v) ((v).as.obj)
603
604// Determines if [value] is a garbage-collected object or not.
605#define IS_OBJ(value) ((value).type == VAL_OBJ)
606
607#define IS_FALSE(value) ((value).type == VAL_FALSE)
608#define IS_NULL(value) ((value).type == VAL_NULL)
609#define IS_NUM(value) ((value).type == VAL_NUM)
610#define IS_UNDEFINED(value) ((value).type == VAL_UNDEFINED)
611
612// Singleton values.
613#define FALSE_VAL ((Value){ VAL_FALSE, { 0 } })
614#define NULL_VAL ((Value){ VAL_NULL, { 0 } })
615#define TRUE_VAL ((Value){ VAL_TRUE, { 0 } })
616#define UNDEFINED_VAL ((Value){ VAL_UNDEFINED, { 0 } })
617
618#endif
619
620// Creates a new "raw" class. It has no metaclass or superclass whatsoever.
621// This is only used for bootstrapping the initial Object and Class classes,
622// which are a little special.
623ObjClass* wrenNewSingleClass(WrenVM* vm, int numFields, ObjString* name);
624
625// Makes [superclass] the superclass of [subclass], and causes subclass to
626// inherit its methods. This should be called before any methods are defined
627// on subclass.
628void wrenBindSuperclass(WrenVM* vm, ObjClass* subclass, ObjClass* superclass);
629
630// Creates a new class object as well as its associated metaclass.
631ObjClass* wrenNewClass(WrenVM* vm, ObjClass* superclass, int numFields,
632 ObjString* name);
633
634void wrenBindMethod(WrenVM* vm, ObjClass* classObj, int symbol, Method method);
635
636// Creates a new closure object that invokes [fn]. Allocates room for its
637// upvalues, but assumes outside code will populate it.
638ObjClosure* wrenNewClosure(WrenVM* vm, ObjFn* fn);
639
640// Creates a new fiber object that will invoke [closure].
641ObjFiber* wrenNewFiber(WrenVM* vm, ObjClosure* closure);
642
643// Adds a new [CallFrame] to [fiber] invoking [closure] whose stack starts at
644// [stackStart].
645static inline void wrenAppendCallFrame(WrenVM* vm, ObjFiber* fiber,
646 ObjClosure* closure, Value* stackStart)
647{
648 // The caller should have ensured we already have enough capacity.
649 ASSERT(fiber->frameCapacity > fiber->numFrames, "No memory for call frame.");
650
651 CallFrame* frame = &fiber->frames[fiber->numFrames++];
652 frame->stackStart = stackStart;
653 frame->closure = closure;
654 frame->ip = closure->fn->code.data;
655}
656
657// Ensures [fiber]'s stack has at least [needed] slots.
658void wrenEnsureStack(WrenVM* vm, ObjFiber* fiber, int needed);
659
660static inline bool wrenHasError(const ObjFiber* fiber)
661{
662 return !IS_NULL(fiber->error);
663}
664
665ObjForeign* wrenNewForeign(WrenVM* vm, ObjClass* classObj, size_t size);
666
667// Creates a new empty function. Before being used, it must have code,
668// constants, etc. added to it.
669ObjFn* wrenNewFunction(WrenVM* vm, ObjModule* module, int maxSlots);
670
671void wrenFunctionBindName(WrenVM* vm, ObjFn* fn, const char* name, int length);
672
673// Creates a new instance of the given [classObj].
674Value wrenNewInstance(WrenVM* vm, ObjClass* classObj);
675
676// Creates a new list with [numElements] elements (which are left
677// uninitialized.)
678ObjList* wrenNewList(WrenVM* vm, uint32_t numElements);
679
680// Inserts [value] in [list] at [index], shifting down the other elements.
681void wrenListInsert(WrenVM* vm, ObjList* list, Value value, uint32_t index);
682
683// Removes and returns the item at [index] from [list].
684Value wrenListRemoveAt(WrenVM* vm, ObjList* list, uint32_t index);
685
686// Searches for [value] in [list], returns the index or -1 if not found.
687int wrenListIndexOf(WrenVM* vm, ObjList* list, Value value);
688
689// Creates a new empty map.
690ObjMap* wrenNewMap(WrenVM* vm);
691
692// Validates that [arg] is a valid object for use as a map key. Returns true if
693// it is and returns false otherwise. Use validateKey usually, for a runtime error.
694// This separation exists to aid the API in surfacing errors to the developer as well.
695static inline bool wrenMapIsValidKey(Value arg);
696
697// Looks up [key] in [map]. If found, returns the value. Otherwise, returns
698// `UNDEFINED_VAL`.
699Value wrenMapGet(ObjMap* map, Value key);
700
701// Associates [key] with [value] in [map].
702void wrenMapSet(WrenVM* vm, ObjMap* map, Value key, Value value);
703
704void wrenMapClear(WrenVM* vm, ObjMap* map);
705
706// Removes [key] from [map], if present. Returns the value for the key if found
707// or `NULL_VAL` otherwise.
708Value wrenMapRemoveKey(WrenVM* vm, ObjMap* map, Value key);
709
710// Creates a new module.
711ObjModule* wrenNewModule(WrenVM* vm, ObjString* name);
712
713// Creates a new range from [from] to [to].
714Value wrenNewRange(WrenVM* vm, double from, double to, bool isInclusive);
715
716// Creates a new string object and copies [text] into it.
717//
718// [text] must be non-NULL.
719Value wrenNewString(WrenVM* vm, const char* text);
720
721// Creates a new string object of [length] and copies [text] into it.
722//
723// [text] may be NULL if [length] is zero.
724Value wrenNewStringLength(WrenVM* vm, const char* text, size_t length);
725
726// Creates a new string object by taking a range of characters from [source].
727// The range starts at [start], contains [count] bytes, and increments by
728// [step].
729Value wrenNewStringFromRange(WrenVM* vm, ObjString* source, int start,
730 uint32_t count, int step);
731
732// Produces a string representation of [value].
733Value wrenNumToString(WrenVM* vm, double value);
734
735// Creates a new formatted string from [format] and any additional arguments
736// used in the format string.
737//
738// This is a very restricted flavor of formatting, intended only for internal
739// use by the VM. Two formatting characters are supported, each of which reads
740// the next argument as a certain type:
741//
742// $ - A C string.
743// @ - A Wren string object.
744Value wrenStringFormat(WrenVM* vm, const char* format, ...);
745
746// Creates a new string containing the UTF-8 encoding of [value].
747Value wrenStringFromCodePoint(WrenVM* vm, int value);
748
749// Creates a new string from the integer representation of a byte
750Value wrenStringFromByte(WrenVM* vm, uint8_t value);
751
752// Creates a new string containing the code point in [string] starting at byte
753// [index]. If [index] points into the middle of a UTF-8 sequence, returns an
754// empty string.
755Value wrenStringCodePointAt(WrenVM* vm, ObjString* string, uint32_t index);
756
757// Search for the first occurence of [needle] within [haystack] and returns its
758// zero-based offset. Returns `UINT32_MAX` if [haystack] does not contain
759// [needle].
760uint32_t wrenStringFind(ObjString* haystack, ObjString* needle,
761 uint32_t startIndex);
762
763// Returns true if [a] and [b] represent the same string.
764static inline bool wrenStringEqualsCString(const ObjString* a,
765 const char* b, size_t length)
766{
767 return a->length == length && memcmp(a->value, b, length) == 0;
768}
769
770// Creates a new open upvalue pointing to [value] on the stack.
771ObjUpvalue* wrenNewUpvalue(WrenVM* vm, Value* value);
772
773// Mark [obj] as reachable and still in use. This should only be called
774// during the sweep phase of a garbage collection.
775void wrenGrayObj(WrenVM* vm, Obj* obj);
776
777// Mark [value] as reachable and still in use. This should only be called
778// during the sweep phase of a garbage collection.
779void wrenGrayValue(WrenVM* vm, Value value);
780
781// Mark the values in [buffer] as reachable and still in use. This should only
782// be called during the sweep phase of a garbage collection.
783void wrenGrayBuffer(WrenVM* vm, ValueBuffer* buffer);
784
785// Processes every object in the gray stack until all reachable objects have
786// been marked. After that, all objects are either white (freeable) or black
787// (in use and fully traversed).
788void wrenBlackenObjects(WrenVM* vm);
789
790// Releases all memory owned by [obj], including [obj] itself.
791void wrenFreeObj(WrenVM* vm, Obj* obj);
792
793// Returns the class of [value].
794//
795// Unlike wrenGetClassInline in wren_vm.h, this is not inlined. Inlining helps
796// performance (significantly) in some cases, but degrades it in others. The
797// ones used by the implementation were chosen to give the best results in the
798// benchmarks.
799ObjClass* wrenGetClass(WrenVM* vm, Value value);
800
801// Returns true if [a] and [b] are strictly the same value. This is identity
802// for object values, and value equality for unboxed values.
803static inline bool wrenValuesSame(Value a, Value b)
804{
805#if WREN_NAN_TAGGING
806 // Value types have unique bit representations and we compare object types
807 // by identity (i.e. pointer), so all we need to do is compare the bits.
808 return a == b;
809#else
810 if (a.type != b.type) return false;
811 if (a.type == VAL_NUM) return a.as.num == b.as.num;
812 return a.as.obj == b.as.obj;
813#endif
814}
815
816// Returns true if [a] and [b] are equivalent. Immutable values (null, bools,
817// numbers, ranges, and strings) are equal if they have the same data. All
818// other values are equal if they are identical objects.
819bool wrenValuesEqual(Value a, Value b);
820
821// Returns true if [value] is a bool. Do not call this directly, instead use
822// [IS_BOOL].
823static inline bool wrenIsBool(Value value)
824{
825#if WREN_NAN_TAGGING
826 return value == TRUE_VAL || value == FALSE_VAL;
827#else
828 return value.type == VAL_FALSE || value.type == VAL_TRUE;
829#endif
830}
831
832// Returns true if [value] is an object of type [type]. Do not call this
833// directly, instead use the [IS___] macro for the type in question.
834static inline bool wrenIsObjType(Value value, ObjType type)
835{
836 return IS_OBJ(value) && AS_OBJ(value)->type == type;
837}
838
839// Converts the raw object pointer [obj] to a [Value].
840static inline Value wrenObjectToValue(Obj* obj)
841{
842#if WREN_NAN_TAGGING
843 // The triple casting is necessary here to satisfy some compilers:
844 // 1. (uintptr_t) Convert the pointer to a number of the right size.
845 // 2. (uint64_t) Pad it up to 64 bits in 32-bit builds.
846 // 3. Or in the bits to make a tagged Nan.
847 // 4. Cast to a typedef'd value.
848 return (Value)(SIGN_BIT | QNAN | (uint64_t)(uintptr_t)(obj));
849#else
850 Value value;
851 value.type = VAL_OBJ;
852 value.as.obj = obj;
853 return value;
854#endif
855}
856
857// Interprets [value] as a [double].
858static inline double wrenValueToNum(Value value)
859{
860#if WREN_NAN_TAGGING
861 return wrenDoubleFromBits(value);
862#else
863 return value.as.num;
864#endif
865}
866
867// Converts [num] to a [Value].
868static inline Value wrenNumToValue(double num)
869{
870#if WREN_NAN_TAGGING
871 return wrenDoubleToBits(num);
872#else
873 Value value;
874 value.type = VAL_NUM;
875 value.as.num = num;
876 return value;
877#endif
878}
879
880static inline bool wrenMapIsValidKey(Value arg)
881{
882 return IS_BOOL(arg)
883 || IS_CLASS(arg)
884 || IS_NULL(arg)
885 || IS_NUM(arg)
886 || IS_RANGE(arg)
887 || IS_STRING(arg);
888}
889
890#endif
891