1#include <ctype.h>
2#include <errno.h>
3#include <float.h>
4#include <math.h>
5#include <string.h>
6#include <time.h>
7
8#include "wren_common.h"
9#include "wren_core.h"
10#include "wren_math.h"
11#include "wren_primitive.h"
12#include "wren_value.h"
13
14#include "wren_core.wren.inc"
15
16DEF_PRIMITIVE(bool_not)
17{
18 RETURN_BOOL(!AS_BOOL(args[0]));
19}
20
21DEF_PRIMITIVE(bool_toString)
22{
23 if (AS_BOOL(args[0]))
24 {
25 RETURN_VAL(CONST_STRING(vm, "true"));
26 }
27 else
28 {
29 RETURN_VAL(CONST_STRING(vm, "false"));
30 }
31}
32
33DEF_PRIMITIVE(class_name)
34{
35 RETURN_OBJ(AS_CLASS(args[0])->name);
36}
37
38DEF_PRIMITIVE(class_supertype)
39{
40 ObjClass* classObj = AS_CLASS(args[0]);
41
42 // Object has no superclass.
43 if (classObj->superclass == NULL) RETURN_NULL;
44
45 RETURN_OBJ(classObj->superclass);
46}
47
48DEF_PRIMITIVE(class_toString)
49{
50 RETURN_OBJ(AS_CLASS(args[0])->name);
51}
52
53DEF_PRIMITIVE(class_attributes)
54{
55 RETURN_VAL(AS_CLASS(args[0])->attributes);
56}
57
58DEF_PRIMITIVE(fiber_new)
59{
60 if (!validateFn(vm, args[1], "Argument")) return false;
61
62 ObjClosure* closure = AS_CLOSURE(args[1]);
63 if (closure->fn->arity > 1)
64 {
65 RETURN_ERROR("Function cannot take more than one parameter.");
66 }
67
68 RETURN_OBJ(wrenNewFiber(vm, closure));
69}
70
71DEF_PRIMITIVE(fiber_abort)
72{
73 vm->fiber->error = args[1];
74
75 // If the error is explicitly null, it's not really an abort.
76 return IS_NULL(args[1]);
77}
78
79// Transfer execution to [fiber] coming from the current fiber whose stack has
80// [args].
81//
82// [isCall] is true if [fiber] is being called and not transferred.
83//
84// [hasValue] is true if a value in [args] is being passed to the new fiber.
85// Otherwise, `null` is implicitly being passed.
86static bool runFiber(WrenVM* vm, ObjFiber* fiber, Value* args, bool isCall,
87 bool hasValue, const char* verb)
88{
89
90 if (wrenHasError(fiber))
91 {
92 RETURN_ERROR_FMT("Cannot $ an aborted fiber.", verb);
93 }
94
95 if (isCall)
96 {
97 // You can't call a called fiber, but you can transfer directly to it,
98 // which is why this check is gated on `isCall`. This way, after resuming a
99 // suspended fiber, it will run and then return to the fiber that called it
100 // and so on.
101 if (fiber->caller != NULL) RETURN_ERROR("Fiber has already been called.");
102
103 if (fiber->state == FIBER_ROOT) RETURN_ERROR("Cannot call root fiber.");
104
105 // Remember who ran it.
106 fiber->caller = vm->fiber;
107 }
108
109 if (fiber->numFrames == 0)
110 {
111 RETURN_ERROR_FMT("Cannot $ a finished fiber.", verb);
112 }
113
114 // When the calling fiber resumes, we'll store the result of the call in its
115 // stack. If the call has two arguments (the fiber and the value), we only
116 // need one slot for the result, so discard the other slot now.
117 if (hasValue) vm->fiber->stackTop--;
118
119 if (fiber->numFrames == 1 &&
120 fiber->frames[0].ip == fiber->frames[0].closure->fn->code.data)
121 {
122 // The fiber is being started for the first time. If its function takes a
123 // parameter, bind an argument to it.
124 if (fiber->frames[0].closure->fn->arity == 1)
125 {
126 fiber->stackTop[0] = hasValue ? args[1] : NULL_VAL;
127 fiber->stackTop++;
128 }
129 }
130 else
131 {
132 // The fiber is being resumed, make yield() or transfer() return the result.
133 fiber->stackTop[-1] = hasValue ? args[1] : NULL_VAL;
134 }
135
136 vm->fiber = fiber;
137 return false;
138}
139
140DEF_PRIMITIVE(fiber_call)
141{
142 return runFiber(vm, AS_FIBER(args[0]), args, true, false, "call");
143}
144
145DEF_PRIMITIVE(fiber_call1)
146{
147 return runFiber(vm, AS_FIBER(args[0]), args, true, true, "call");
148}
149
150DEF_PRIMITIVE(fiber_current)
151{
152 RETURN_OBJ(vm->fiber);
153}
154
155DEF_PRIMITIVE(fiber_error)
156{
157 RETURN_VAL(AS_FIBER(args[0])->error);
158}
159
160DEF_PRIMITIVE(fiber_isDone)
161{
162 ObjFiber* runFiber = AS_FIBER(args[0]);
163 RETURN_BOOL(runFiber->numFrames == 0 || wrenHasError(runFiber));
164}
165
166DEF_PRIMITIVE(fiber_suspend)
167{
168 // Switching to a null fiber tells the interpreter to stop and exit.
169 vm->fiber = NULL;
170 vm->apiStack = NULL;
171 return false;
172}
173
174DEF_PRIMITIVE(fiber_transfer)
175{
176 return runFiber(vm, AS_FIBER(args[0]), args, false, false, "transfer to");
177}
178
179DEF_PRIMITIVE(fiber_transfer1)
180{
181 return runFiber(vm, AS_FIBER(args[0]), args, false, true, "transfer to");
182}
183
184DEF_PRIMITIVE(fiber_transferError)
185{
186 runFiber(vm, AS_FIBER(args[0]), args, false, true, "transfer to");
187 vm->fiber->error = args[1];
188 return false;
189}
190
191DEF_PRIMITIVE(fiber_try)
192{
193 runFiber(vm, AS_FIBER(args[0]), args, true, false, "try");
194
195 // If we're switching to a valid fiber to try, remember that we're trying it.
196 if (!wrenHasError(vm->fiber)) vm->fiber->state = FIBER_TRY;
197 return false;
198}
199
200DEF_PRIMITIVE(fiber_try1)
201{
202 runFiber(vm, AS_FIBER(args[0]), args, true, true, "try");
203
204 // If we're switching to a valid fiber to try, remember that we're trying it.
205 if (!wrenHasError(vm->fiber)) vm->fiber->state = FIBER_TRY;
206 return false;
207}
208
209DEF_PRIMITIVE(fiber_yield)
210{
211 ObjFiber* current = vm->fiber;
212 vm->fiber = current->caller;
213
214 // Unhook this fiber from the one that called it.
215 current->caller = NULL;
216 current->state = FIBER_OTHER;
217
218 if (vm->fiber != NULL)
219 {
220 // Make the caller's run method return null.
221 vm->fiber->stackTop[-1] = NULL_VAL;
222 }
223
224 return false;
225}
226
227DEF_PRIMITIVE(fiber_yield1)
228{
229 ObjFiber* current = vm->fiber;
230 vm->fiber = current->caller;
231
232 // Unhook this fiber from the one that called it.
233 current->caller = NULL;
234 current->state = FIBER_OTHER;
235
236 if (vm->fiber != NULL)
237 {
238 // Make the caller's run method return the argument passed to yield.
239 vm->fiber->stackTop[-1] = args[1];
240
241 // When the yielding fiber resumes, we'll store the result of the yield
242 // call in its stack. Since Fiber.yield(value) has two arguments (the Fiber
243 // class and the value) and we only need one slot for the result, discard
244 // the other slot now.
245 current->stackTop--;
246 }
247
248 return false;
249}
250
251DEF_PRIMITIVE(fn_new)
252{
253 if (!validateFn(vm, args[1], "Argument")) return false;
254
255 // The block argument is already a function, so just return it.
256 RETURN_VAL(args[1]);
257}
258
259DEF_PRIMITIVE(fn_arity)
260{
261 RETURN_NUM(AS_CLOSURE(args[0])->fn->arity);
262}
263
264static void call_fn(WrenVM* vm, Value* args, int numArgs)
265{
266 // +1 to include the function itself.
267 wrenCallFunction(vm, vm->fiber, AS_CLOSURE(args[0]), numArgs + 1);
268}
269
270#define DEF_FN_CALL(numArgs) \
271 DEF_PRIMITIVE(fn_call##numArgs) \
272 { \
273 call_fn(vm, args, numArgs); \
274 return false; \
275 }
276
277DEF_FN_CALL(0)
278DEF_FN_CALL(1)
279DEF_FN_CALL(2)
280DEF_FN_CALL(3)
281DEF_FN_CALL(4)
282DEF_FN_CALL(5)
283DEF_FN_CALL(6)
284DEF_FN_CALL(7)
285DEF_FN_CALL(8)
286DEF_FN_CALL(9)
287DEF_FN_CALL(10)
288DEF_FN_CALL(11)
289DEF_FN_CALL(12)
290DEF_FN_CALL(13)
291DEF_FN_CALL(14)
292DEF_FN_CALL(15)
293DEF_FN_CALL(16)
294
295DEF_PRIMITIVE(fn_toString)
296{
297 RETURN_VAL(CONST_STRING(vm, "<fn>"));
298}
299
300// Creates a new list of size args[1], with all elements initialized to args[2].
301DEF_PRIMITIVE(list_filled)
302{
303 if (!validateInt(vm, args[1], "Size")) return false;
304 if (AS_NUM(args[1]) < 0) RETURN_ERROR("Size cannot be negative.");
305
306 uint32_t size = (uint32_t)AS_NUM(args[1]);
307 ObjList* list = wrenNewList(vm, size);
308
309 for (uint32_t i = 0; i < size; i++)
310 {
311 list->elements.data[i] = args[2];
312 }
313
314 RETURN_OBJ(list);
315}
316
317DEF_PRIMITIVE(list_new)
318{
319 RETURN_OBJ(wrenNewList(vm, 0));
320}
321
322DEF_PRIMITIVE(list_add)
323{
324 wrenValueBufferWrite(vm, &AS_LIST(args[0])->elements, args[1]);
325 RETURN_VAL(args[1]);
326}
327
328// Adds an element to the list and then returns the list itself. This is called
329// by the compiler when compiling list literals instead of using add() to
330// minimize stack churn.
331DEF_PRIMITIVE(list_addCore)
332{
333 wrenValueBufferWrite(vm, &AS_LIST(args[0])->elements, args[1]);
334
335 // Return the list.
336 RETURN_VAL(args[0]);
337}
338
339DEF_PRIMITIVE(list_clear)
340{
341 wrenValueBufferClear(vm, &AS_LIST(args[0])->elements);
342 RETURN_NULL;
343}
344
345DEF_PRIMITIVE(list_count)
346{
347 RETURN_NUM(AS_LIST(args[0])->elements.count);
348}
349
350DEF_PRIMITIVE(list_insert)
351{
352 ObjList* list = AS_LIST(args[0]);
353
354 // count + 1 here so you can "insert" at the very end.
355 uint32_t index = validateIndex(vm, args[1], list->elements.count + 1,
356 "Index");
357 if (index == UINT32_MAX) return false;
358
359 wrenListInsert(vm, list, args[2], index);
360 RETURN_VAL(args[2]);
361}
362
363DEF_PRIMITIVE(list_iterate)
364{
365 ObjList* list = AS_LIST(args[0]);
366
367 // If we're starting the iteration, return the first index.
368 if (IS_NULL(args[1]))
369 {
370 if (list->elements.count == 0) RETURN_FALSE;
371 RETURN_NUM(0);
372 }
373
374 if (!validateInt(vm, args[1], "Iterator")) return false;
375
376 // Stop if we're out of bounds.
377 double index = AS_NUM(args[1]);
378 if (index < 0 || index >= list->elements.count - 1) RETURN_FALSE;
379
380 // Otherwise, move to the next index.
381 RETURN_NUM(index + 1);
382}
383
384DEF_PRIMITIVE(list_iteratorValue)
385{
386 ObjList* list = AS_LIST(args[0]);
387 uint32_t index = validateIndex(vm, args[1], list->elements.count, "Iterator");
388 if (index == UINT32_MAX) return false;
389
390 RETURN_VAL(list->elements.data[index]);
391}
392
393DEF_PRIMITIVE(list_removeAt)
394{
395 ObjList* list = AS_LIST(args[0]);
396 uint32_t index = validateIndex(vm, args[1], list->elements.count, "Index");
397 if (index == UINT32_MAX) return false;
398
399 RETURN_VAL(wrenListRemoveAt(vm, list, index));
400}
401
402DEF_PRIMITIVE(list_removeValue) {
403 ObjList* list = AS_LIST(args[0]);
404 int index = wrenListIndexOf(vm, list, args[1]);
405 if(index == -1) RETURN_NULL;
406 RETURN_VAL(wrenListRemoveAt(vm, list, index));
407}
408
409DEF_PRIMITIVE(list_indexOf)
410{
411 ObjList* list = AS_LIST(args[0]);
412 RETURN_NUM(wrenListIndexOf(vm, list, args[1]));
413}
414
415DEF_PRIMITIVE(list_swap)
416{
417 ObjList* list = AS_LIST(args[0]);
418 uint32_t indexA = validateIndex(vm, args[1], list->elements.count, "Index 0");
419 if (indexA == UINT32_MAX) return false;
420 uint32_t indexB = validateIndex(vm, args[2], list->elements.count, "Index 1");
421 if (indexB == UINT32_MAX) return false;
422
423 Value a = list->elements.data[indexA];
424 list->elements.data[indexA] = list->elements.data[indexB];
425 list->elements.data[indexB] = a;
426
427 RETURN_NULL;
428}
429
430DEF_PRIMITIVE(list_subscript)
431{
432 ObjList* list = AS_LIST(args[0]);
433
434 if (IS_NUM(args[1]))
435 {
436 uint32_t index = validateIndex(vm, args[1], list->elements.count,
437 "Subscript");
438 if (index == UINT32_MAX) return false;
439
440 RETURN_VAL(list->elements.data[index]);
441 }
442
443 if (!IS_RANGE(args[1]))
444 {
445 RETURN_ERROR("Subscript must be a number or a range.");
446 }
447
448 int step;
449 uint32_t count = list->elements.count;
450 uint32_t start = calculateRange(vm, AS_RANGE(args[1]), &count, &step);
451 if (start == UINT32_MAX) return false;
452
453 ObjList* result = wrenNewList(vm, count);
454 for (uint32_t i = 0; i < count; i++)
455 {
456 result->elements.data[i] = list->elements.data[start + i * step];
457 }
458
459 RETURN_OBJ(result);
460}
461
462DEF_PRIMITIVE(list_subscriptSetter)
463{
464 ObjList* list = AS_LIST(args[0]);
465 uint32_t index = validateIndex(vm, args[1], list->elements.count,
466 "Subscript");
467 if (index == UINT32_MAX) return false;
468
469 list->elements.data[index] = args[2];
470 RETURN_VAL(args[2]);
471}
472
473DEF_PRIMITIVE(map_new)
474{
475 RETURN_OBJ(wrenNewMap(vm));
476}
477
478DEF_PRIMITIVE(map_subscript)
479{
480 if (!validateKey(vm, args[1])) return false;
481
482 ObjMap* map = AS_MAP(args[0]);
483 Value value = wrenMapGet(map, args[1]);
484 if (IS_UNDEFINED(value)) RETURN_NULL;
485
486 RETURN_VAL(value);
487}
488
489DEF_PRIMITIVE(map_subscriptSetter)
490{
491 if (!validateKey(vm, args[1])) return false;
492
493 wrenMapSet(vm, AS_MAP(args[0]), args[1], args[2]);
494 RETURN_VAL(args[2]);
495}
496
497// Adds an entry to the map and then returns the map itself. This is called by
498// the compiler when compiling map literals instead of using [_]=(_) to
499// minimize stack churn.
500DEF_PRIMITIVE(map_addCore)
501{
502 if (!validateKey(vm, args[1])) return false;
503
504 wrenMapSet(vm, AS_MAP(args[0]), args[1], args[2]);
505
506 // Return the map itself.
507 RETURN_VAL(args[0]);
508}
509
510DEF_PRIMITIVE(map_clear)
511{
512 wrenMapClear(vm, AS_MAP(args[0]));
513 RETURN_NULL;
514}
515
516DEF_PRIMITIVE(map_containsKey)
517{
518 if (!validateKey(vm, args[1])) return false;
519
520 RETURN_BOOL(!IS_UNDEFINED(wrenMapGet(AS_MAP(args[0]), args[1])));
521}
522
523DEF_PRIMITIVE(map_count)
524{
525 RETURN_NUM(AS_MAP(args[0])->count);
526}
527
528DEF_PRIMITIVE(map_iterate)
529{
530 ObjMap* map = AS_MAP(args[0]);
531
532 if (map->count == 0) RETURN_FALSE;
533
534 // If we're starting the iteration, start at the first used entry.
535 uint32_t index = 0;
536
537 // Otherwise, start one past the last entry we stopped at.
538 if (!IS_NULL(args[1]))
539 {
540 if (!validateInt(vm, args[1], "Iterator")) return false;
541
542 if (AS_NUM(args[1]) < 0) RETURN_FALSE;
543 index = (uint32_t)AS_NUM(args[1]);
544
545 if (index >= map->capacity) RETURN_FALSE;
546
547 // Advance the iterator.
548 index++;
549 }
550
551 // Find a used entry, if any.
552 for (; index < map->capacity; index++)
553 {
554 if (!IS_UNDEFINED(map->entries[index].key)) RETURN_NUM(index);
555 }
556
557 // If we get here, walked all of the entries.
558 RETURN_FALSE;
559}
560
561DEF_PRIMITIVE(map_remove)
562{
563 if (!validateKey(vm, args[1])) return false;
564
565 RETURN_VAL(wrenMapRemoveKey(vm, AS_MAP(args[0]), args[1]));
566}
567
568DEF_PRIMITIVE(map_keyIteratorValue)
569{
570 ObjMap* map = AS_MAP(args[0]);
571 uint32_t index = validateIndex(vm, args[1], map->capacity, "Iterator");
572 if (index == UINT32_MAX) return false;
573
574 MapEntry* entry = &map->entries[index];
575 if (IS_UNDEFINED(entry->key))
576 {
577 RETURN_ERROR("Invalid map iterator.");
578 }
579
580 RETURN_VAL(entry->key);
581}
582
583DEF_PRIMITIVE(map_valueIteratorValue)
584{
585 ObjMap* map = AS_MAP(args[0]);
586 uint32_t index = validateIndex(vm, args[1], map->capacity, "Iterator");
587 if (index == UINT32_MAX) return false;
588
589 MapEntry* entry = &map->entries[index];
590 if (IS_UNDEFINED(entry->key))
591 {
592 RETURN_ERROR("Invalid map iterator.");
593 }
594
595 RETURN_VAL(entry->value);
596}
597
598DEF_PRIMITIVE(null_not)
599{
600 RETURN_VAL(TRUE_VAL);
601}
602
603DEF_PRIMITIVE(null_toString)
604{
605 RETURN_VAL(CONST_STRING(vm, "null"));
606}
607
608DEF_PRIMITIVE(num_fromString)
609{
610 if (!validateString(vm, args[1], "Argument")) return false;
611
612 ObjString* string = AS_STRING(args[1]);
613
614 // Corner case: Can't parse an empty string.
615 if (string->length == 0) RETURN_NULL;
616
617 errno = 0;
618 char* end;
619 double number = strtod(string->value, &end);
620
621 // Skip past any trailing whitespace.
622 while (*end != '\0' && isspace((unsigned char)*end)) end++;
623
624 if (errno == ERANGE) RETURN_ERROR("Number literal is too large.");
625
626 // We must have consumed the entire string. Otherwise, it contains non-number
627 // characters and we can't parse it.
628 if (end < string->value + string->length) RETURN_NULL;
629
630 RETURN_NUM(number);
631}
632
633// Defines a primitive on Num that calls infix [op] and returns [type].
634#define DEF_NUM_CONSTANT(name, value) \
635 DEF_PRIMITIVE(num_##name) \
636 { \
637 RETURN_NUM(value); \
638 }
639
640DEF_NUM_CONSTANT(infinity, INFINITY)
641DEF_NUM_CONSTANT(nan, WREN_DOUBLE_NAN)
642DEF_NUM_CONSTANT(pi, 3.14159265358979323846264338327950288)
643DEF_NUM_CONSTANT(tau, 6.28318530717958647692528676655900577)
644
645DEF_NUM_CONSTANT(largest, DBL_MAX)
646DEF_NUM_CONSTANT(smallest, DBL_MIN)
647
648DEF_NUM_CONSTANT(maxSafeInteger, 9007199254740991.0)
649DEF_NUM_CONSTANT(minSafeInteger, -9007199254740991.0)
650
651// Defines a primitive on Num that calls infix [op] and returns [type].
652#define DEF_NUM_INFIX(name, op, type) \
653 DEF_PRIMITIVE(num_##name) \
654 { \
655 if (!validateNum(vm, args[1], "Right operand")) return false; \
656 RETURN_##type(AS_NUM(args[0]) op AS_NUM(args[1])); \
657 }
658
659DEF_NUM_INFIX(minus, -, NUM)
660DEF_NUM_INFIX(plus, +, NUM)
661DEF_NUM_INFIX(multiply, *, NUM)
662DEF_NUM_INFIX(divide, /, NUM)
663DEF_NUM_INFIX(lt, <, BOOL)
664DEF_NUM_INFIX(gt, >, BOOL)
665DEF_NUM_INFIX(lte, <=, BOOL)
666DEF_NUM_INFIX(gte, >=, BOOL)
667
668// Defines a primitive on Num that call infix bitwise [op].
669#define DEF_NUM_BITWISE(name, op) \
670 DEF_PRIMITIVE(num_bitwise##name) \
671 { \
672 if (!validateNum(vm, args[1], "Right operand")) return false; \
673 uint32_t left = (uint32_t)AS_NUM(args[0]); \
674 uint32_t right = (uint32_t)AS_NUM(args[1]); \
675 RETURN_NUM(left op right); \
676 }
677
678DEF_NUM_BITWISE(And, &)
679DEF_NUM_BITWISE(Or, |)
680DEF_NUM_BITWISE(Xor, ^)
681DEF_NUM_BITWISE(LeftShift, <<)
682DEF_NUM_BITWISE(RightShift, >>)
683
684// Defines a primitive method on Num that returns the result of [fn].
685#define DEF_NUM_FN(name, fn) \
686 DEF_PRIMITIVE(num_##name) \
687 { \
688 RETURN_NUM(fn(AS_NUM(args[0]))); \
689 }
690
691DEF_NUM_FN(abs, fabs)
692DEF_NUM_FN(acos, acos)
693DEF_NUM_FN(asin, asin)
694DEF_NUM_FN(atan, atan)
695DEF_NUM_FN(cbrt, cbrt)
696DEF_NUM_FN(ceil, ceil)
697DEF_NUM_FN(cos, cos)
698DEF_NUM_FN(floor, floor)
699DEF_NUM_FN(negate, -)
700DEF_NUM_FN(round, round)
701DEF_NUM_FN(sin, sin)
702DEF_NUM_FN(sqrt, sqrt)
703DEF_NUM_FN(tan, tan)
704DEF_NUM_FN(log, log)
705DEF_NUM_FN(log2, log2)
706DEF_NUM_FN(exp, exp)
707
708DEF_PRIMITIVE(num_mod)
709{
710 if (!validateNum(vm, args[1], "Right operand")) return false;
711 RETURN_NUM(fmod(AS_NUM(args[0]), AS_NUM(args[1])));
712}
713
714DEF_PRIMITIVE(num_eqeq)
715{
716 if (!IS_NUM(args[1])) RETURN_FALSE;
717 RETURN_BOOL(AS_NUM(args[0]) == AS_NUM(args[1]));
718}
719
720DEF_PRIMITIVE(num_bangeq)
721{
722 if (!IS_NUM(args[1])) RETURN_TRUE;
723 RETURN_BOOL(AS_NUM(args[0]) != AS_NUM(args[1]));
724}
725
726DEF_PRIMITIVE(num_bitwiseNot)
727{
728 // Bitwise operators always work on 32-bit unsigned ints.
729 RETURN_NUM(~(uint32_t)AS_NUM(args[0]));
730}
731
732DEF_PRIMITIVE(num_dotDot)
733{
734 if (!validateNum(vm, args[1], "Right hand side of range")) return false;
735
736 double from = AS_NUM(args[0]);
737 double to = AS_NUM(args[1]);
738 RETURN_VAL(wrenNewRange(vm, from, to, true));
739}
740
741DEF_PRIMITIVE(num_dotDotDot)
742{
743 if (!validateNum(vm, args[1], "Right hand side of range")) return false;
744
745 double from = AS_NUM(args[0]);
746 double to = AS_NUM(args[1]);
747 RETURN_VAL(wrenNewRange(vm, from, to, false));
748}
749
750DEF_PRIMITIVE(num_atan2)
751{
752 if (!validateNum(vm, args[1], "x value")) return false;
753
754 RETURN_NUM(atan2(AS_NUM(args[0]), AS_NUM(args[1])));
755}
756
757DEF_PRIMITIVE(num_min)
758{
759 if (!validateNum(vm, args[1], "Other value")) return false;
760
761 double value = AS_NUM(args[0]);
762 double other = AS_NUM(args[1]);
763 RETURN_NUM(value <= other ? value : other);
764}
765
766DEF_PRIMITIVE(num_max)
767{
768 if (!validateNum(vm, args[1], "Other value")) return false;
769
770 double value = AS_NUM(args[0]);
771 double other = AS_NUM(args[1]);
772 RETURN_NUM(value > other ? value : other);
773}
774
775DEF_PRIMITIVE(num_clamp)
776{
777 if (!validateNum(vm, args[1], "Min value")) return false;
778 if (!validateNum(vm, args[2], "Max value")) return false;
779
780 double value = AS_NUM(args[0]);
781 double min = AS_NUM(args[1]);
782 double max = AS_NUM(args[2]);
783 double result = (value < min) ? min : ((value > max) ? max : value);
784 RETURN_NUM(result);
785}
786
787DEF_PRIMITIVE(num_pow)
788{
789 if (!validateNum(vm, args[1], "Power value")) return false;
790
791 RETURN_NUM(pow(AS_NUM(args[0]), AS_NUM(args[1])));
792}
793
794DEF_PRIMITIVE(num_fraction)
795{
796 double unused;
797 RETURN_NUM(modf(AS_NUM(args[0]) , &unused));
798}
799
800DEF_PRIMITIVE(num_isInfinity)
801{
802 RETURN_BOOL(isinf(AS_NUM(args[0])));
803}
804
805DEF_PRIMITIVE(num_isInteger)
806{
807 double value = AS_NUM(args[0]);
808 if (isnan(value) || isinf(value)) RETURN_FALSE;
809 RETURN_BOOL(trunc(value) == value);
810}
811
812DEF_PRIMITIVE(num_isNan)
813{
814 RETURN_BOOL(isnan(AS_NUM(args[0])));
815}
816
817DEF_PRIMITIVE(num_sign)
818{
819 double value = AS_NUM(args[0]);
820 if (value > 0)
821 {
822 RETURN_NUM(1);
823 }
824 else if (value < 0)
825 {
826 RETURN_NUM(-1);
827 }
828 else
829 {
830 RETURN_NUM(0);
831 }
832}
833
834DEF_PRIMITIVE(num_toString)
835{
836 RETURN_VAL(wrenNumToString(vm, AS_NUM(args[0])));
837}
838
839DEF_PRIMITIVE(num_truncate)
840{
841 double integer;
842 modf(AS_NUM(args[0]) , &integer);
843 RETURN_NUM(integer);
844}
845
846DEF_PRIMITIVE(object_same)
847{
848 RETURN_BOOL(wrenValuesEqual(args[1], args[2]));
849}
850
851DEF_PRIMITIVE(object_not)
852{
853 RETURN_VAL(FALSE_VAL);
854}
855
856DEF_PRIMITIVE(object_eqeq)
857{
858 RETURN_BOOL(wrenValuesEqual(args[0], args[1]));
859}
860
861DEF_PRIMITIVE(object_bangeq)
862{
863 RETURN_BOOL(!wrenValuesEqual(args[0], args[1]));
864}
865
866DEF_PRIMITIVE(object_is)
867{
868 if (!IS_CLASS(args[1]))
869 {
870 RETURN_ERROR("Right operand must be a class.");
871 }
872
873 ObjClass *classObj = wrenGetClass(vm, args[0]);
874 ObjClass *baseClassObj = AS_CLASS(args[1]);
875
876 // Walk the superclass chain looking for the class.
877 do
878 {
879 if (baseClassObj == classObj) RETURN_BOOL(true);
880
881 classObj = classObj->superclass;
882 }
883 while (classObj != NULL);
884
885 RETURN_BOOL(false);
886}
887
888DEF_PRIMITIVE(object_toString)
889{
890 Obj* obj = AS_OBJ(args[0]);
891 Value name = OBJ_VAL(obj->classObj->name);
892 RETURN_VAL(wrenStringFormat(vm, "instance of @", name));
893}
894
895DEF_PRIMITIVE(object_type)
896{
897 RETURN_OBJ(wrenGetClass(vm, args[0]));
898}
899
900DEF_PRIMITIVE(range_from)
901{
902 RETURN_NUM(AS_RANGE(args[0])->from);
903}
904
905DEF_PRIMITIVE(range_to)
906{
907 RETURN_NUM(AS_RANGE(args[0])->to);
908}
909
910DEF_PRIMITIVE(range_min)
911{
912 ObjRange* range = AS_RANGE(args[0]);
913 RETURN_NUM(fmin(range->from, range->to));
914}
915
916DEF_PRIMITIVE(range_max)
917{
918 ObjRange* range = AS_RANGE(args[0]);
919 RETURN_NUM(fmax(range->from, range->to));
920}
921
922DEF_PRIMITIVE(range_isInclusive)
923{
924 RETURN_BOOL(AS_RANGE(args[0])->isInclusive);
925}
926
927DEF_PRIMITIVE(range_iterate)
928{
929 ObjRange* range = AS_RANGE(args[0]);
930
931 // Special case: empty range.
932 if (range->from == range->to && !range->isInclusive) RETURN_FALSE;
933
934 // Start the iteration.
935 if (IS_NULL(args[1])) RETURN_NUM(range->from);
936
937 if (!validateNum(vm, args[1], "Iterator")) return false;
938
939 double iterator = AS_NUM(args[1]);
940
941 // Iterate towards [to] from [from].
942 if (range->from < range->to)
943 {
944 iterator++;
945 if (iterator > range->to) RETURN_FALSE;
946 }
947 else
948 {
949 iterator--;
950 if (iterator < range->to) RETURN_FALSE;
951 }
952
953 if (!range->isInclusive && iterator == range->to) RETURN_FALSE;
954
955 RETURN_NUM(iterator);
956}
957
958DEF_PRIMITIVE(range_iteratorValue)
959{
960 // Assume the iterator is a number so that is the value of the range.
961 RETURN_VAL(args[1]);
962}
963
964DEF_PRIMITIVE(range_toString)
965{
966 ObjRange* range = AS_RANGE(args[0]);
967
968 Value from = wrenNumToString(vm, range->from);
969 wrenPushRoot(vm, AS_OBJ(from));
970
971 Value to = wrenNumToString(vm, range->to);
972 wrenPushRoot(vm, AS_OBJ(to));
973
974 Value result = wrenStringFormat(vm, "@$@", from,
975 range->isInclusive ? ".." : "...", to);
976
977 wrenPopRoot(vm);
978 wrenPopRoot(vm);
979 RETURN_VAL(result);
980}
981
982DEF_PRIMITIVE(string_fromCodePoint)
983{
984 if (!validateInt(vm, args[1], "Code point")) return false;
985
986 int codePoint = (int)AS_NUM(args[1]);
987 if (codePoint < 0)
988 {
989 RETURN_ERROR("Code point cannot be negative.");
990 }
991 else if (codePoint > 0x10ffff)
992 {
993 RETURN_ERROR("Code point cannot be greater than 0x10ffff.");
994 }
995
996 RETURN_VAL(wrenStringFromCodePoint(vm, codePoint));
997}
998
999DEF_PRIMITIVE(string_fromByte)
1000{
1001 if (!validateInt(vm, args[1], "Byte")) return false;
1002 int byte = (int) AS_NUM(args[1]);
1003 if (byte < 0)
1004 {
1005 RETURN_ERROR("Byte cannot be negative.");
1006 }
1007 else if (byte > 0xff)
1008 {
1009 RETURN_ERROR("Byte cannot be greater than 0xff.");
1010 }
1011 RETURN_VAL(wrenStringFromByte(vm, (uint8_t) byte));
1012}
1013
1014DEF_PRIMITIVE(string_byteAt)
1015{
1016 ObjString* string = AS_STRING(args[0]);
1017
1018 uint32_t index = validateIndex(vm, args[1], string->length, "Index");
1019 if (index == UINT32_MAX) return false;
1020
1021 RETURN_NUM((uint8_t)string->value[index]);
1022}
1023
1024DEF_PRIMITIVE(string_byteCount)
1025{
1026 RETURN_NUM(AS_STRING(args[0])->length);
1027}
1028
1029DEF_PRIMITIVE(string_codePointAt)
1030{
1031 ObjString* string = AS_STRING(args[0]);
1032
1033 uint32_t index = validateIndex(vm, args[1], string->length, "Index");
1034 if (index == UINT32_MAX) return false;
1035
1036 // If we are in the middle of a UTF-8 sequence, indicate that.
1037 const uint8_t* bytes = (uint8_t*)string->value;
1038 if ((bytes[index] & 0xc0) == 0x80) RETURN_NUM(-1);
1039
1040 // Decode the UTF-8 sequence.
1041 RETURN_NUM(wrenUtf8Decode((uint8_t*)string->value + index,
1042 string->length - index));
1043}
1044
1045DEF_PRIMITIVE(string_contains)
1046{
1047 if (!validateString(vm, args[1], "Argument")) return false;
1048
1049 ObjString* string = AS_STRING(args[0]);
1050 ObjString* search = AS_STRING(args[1]);
1051
1052 RETURN_BOOL(wrenStringFind(string, search, 0) != UINT32_MAX);
1053}
1054
1055DEF_PRIMITIVE(string_endsWith)
1056{
1057 if (!validateString(vm, args[1], "Argument")) return false;
1058
1059 ObjString* string = AS_STRING(args[0]);
1060 ObjString* search = AS_STRING(args[1]);
1061
1062 // Edge case: If the search string is longer then return false right away.
1063 if (search->length > string->length) RETURN_FALSE;
1064
1065 RETURN_BOOL(memcmp(string->value + string->length - search->length,
1066 search->value, search->length) == 0);
1067}
1068
1069DEF_PRIMITIVE(string_indexOf1)
1070{
1071 if (!validateString(vm, args[1], "Argument")) return false;
1072
1073 ObjString* string = AS_STRING(args[0]);
1074 ObjString* search = AS_STRING(args[1]);
1075
1076 uint32_t index = wrenStringFind(string, search, 0);
1077 RETURN_NUM(index == UINT32_MAX ? -1 : (int)index);
1078}
1079
1080DEF_PRIMITIVE(string_indexOf2)
1081{
1082 if (!validateString(vm, args[1], "Argument")) return false;
1083
1084 ObjString* string = AS_STRING(args[0]);
1085 ObjString* search = AS_STRING(args[1]);
1086 uint32_t start = validateIndex(vm, args[2], string->length, "Start");
1087 if (start == UINT32_MAX) return false;
1088
1089 uint32_t index = wrenStringFind(string, search, start);
1090 RETURN_NUM(index == UINT32_MAX ? -1 : (int)index);
1091}
1092
1093DEF_PRIMITIVE(string_iterate)
1094{
1095 ObjString* string = AS_STRING(args[0]);
1096
1097 // If we're starting the iteration, return the first index.
1098 if (IS_NULL(args[1]))
1099 {
1100 if (string->length == 0) RETURN_FALSE;
1101 RETURN_NUM(0);
1102 }
1103
1104 if (!validateInt(vm, args[1], "Iterator")) return false;
1105
1106 if (AS_NUM(args[1]) < 0) RETURN_FALSE;
1107 uint32_t index = (uint32_t)AS_NUM(args[1]);
1108
1109 // Advance to the beginning of the next UTF-8 sequence.
1110 do
1111 {
1112 index++;
1113 if (index >= string->length) RETURN_FALSE;
1114 } while ((string->value[index] & 0xc0) == 0x80);
1115
1116 RETURN_NUM(index);
1117}
1118
1119DEF_PRIMITIVE(string_iterateByte)
1120{
1121 ObjString* string = AS_STRING(args[0]);
1122
1123 // If we're starting the iteration, return the first index.
1124 if (IS_NULL(args[1]))
1125 {
1126 if (string->length == 0) RETURN_FALSE;
1127 RETURN_NUM(0);
1128 }
1129
1130 if (!validateInt(vm, args[1], "Iterator")) return false;
1131
1132 if (AS_NUM(args[1]) < 0) RETURN_FALSE;
1133 uint32_t index = (uint32_t)AS_NUM(args[1]);
1134
1135 // Advance to the next byte.
1136 index++;
1137 if (index >= string->length) RETURN_FALSE;
1138
1139 RETURN_NUM(index);
1140}
1141
1142DEF_PRIMITIVE(string_iteratorValue)
1143{
1144 ObjString* string = AS_STRING(args[0]);
1145 uint32_t index = validateIndex(vm, args[1], string->length, "Iterator");
1146 if (index == UINT32_MAX) return false;
1147
1148 RETURN_VAL(wrenStringCodePointAt(vm, string, index));
1149}
1150
1151DEF_PRIMITIVE(string_startsWith)
1152{
1153 if (!validateString(vm, args[1], "Argument")) return false;
1154
1155 ObjString* string = AS_STRING(args[0]);
1156 ObjString* search = AS_STRING(args[1]);
1157
1158 // Edge case: If the search string is longer then return false right away.
1159 if (search->length > string->length) RETURN_FALSE;
1160
1161 RETURN_BOOL(memcmp(string->value, search->value, search->length) == 0);
1162}
1163
1164DEF_PRIMITIVE(string_plus)
1165{
1166 if (!validateString(vm, args[1], "Right operand")) return false;
1167 RETURN_VAL(wrenStringFormat(vm, "@@", args[0], args[1]));
1168}
1169
1170DEF_PRIMITIVE(string_subscript)
1171{
1172 ObjString* string = AS_STRING(args[0]);
1173
1174 if (IS_NUM(args[1]))
1175 {
1176 int index = validateIndex(vm, args[1], string->length, "Subscript");
1177 if (index == -1) return false;
1178
1179 RETURN_VAL(wrenStringCodePointAt(vm, string, index));
1180 }
1181
1182 if (!IS_RANGE(args[1]))
1183 {
1184 RETURN_ERROR("Subscript must be a number or a range.");
1185 }
1186
1187 int step;
1188 uint32_t count = string->length;
1189 int start = calculateRange(vm, AS_RANGE(args[1]), &count, &step);
1190 if (start == -1) return false;
1191
1192 RETURN_VAL(wrenNewStringFromRange(vm, string, start, count, step));
1193}
1194
1195DEF_PRIMITIVE(string_toString)
1196{
1197 RETURN_VAL(args[0]);
1198}
1199
1200DEF_PRIMITIVE(system_clock)
1201{
1202 RETURN_NUM((double)clock() / CLOCKS_PER_SEC);
1203}
1204
1205DEF_PRIMITIVE(system_gc)
1206{
1207 wrenCollectGarbage(vm);
1208 RETURN_NULL;
1209}
1210
1211DEF_PRIMITIVE(system_writeString)
1212{
1213 if (vm->config.writeFn != NULL)
1214 {
1215 vm->config.writeFn(vm, AS_CSTRING(args[1]));
1216 }
1217
1218 RETURN_VAL(args[1]);
1219}
1220
1221// Creates either the Object or Class class in the core module with [name].
1222static ObjClass* defineClass(WrenVM* vm, ObjModule* module, const char* name)
1223{
1224 ObjString* nameString = AS_STRING(wrenNewString(vm, name));
1225 wrenPushRoot(vm, (Obj*)nameString);
1226
1227 ObjClass* classObj = wrenNewSingleClass(vm, 0, nameString);
1228
1229 wrenDefineVariable(vm, module, name, nameString->length, OBJ_VAL(classObj), NULL);
1230
1231 wrenPopRoot(vm);
1232 return classObj;
1233}
1234
1235void wrenInitializeCore(WrenVM* vm)
1236{
1237 ObjModule* coreModule = wrenNewModule(vm, NULL);
1238 wrenPushRoot(vm, (Obj*)coreModule);
1239
1240 // The core module's key is null in the module map.
1241 wrenMapSet(vm, vm->modules, NULL_VAL, OBJ_VAL(coreModule));
1242 wrenPopRoot(vm); // coreModule.
1243
1244 // Define the root Object class. This has to be done a little specially
1245 // because it has no superclass.
1246 vm->objectClass = defineClass(vm, coreModule, "Object");
1247 PRIMITIVE(vm->objectClass, "!", object_not);
1248 PRIMITIVE(vm->objectClass, "==(_)", object_eqeq);
1249 PRIMITIVE(vm->objectClass, "!=(_)", object_bangeq);
1250 PRIMITIVE(vm->objectClass, "is(_)", object_is);
1251 PRIMITIVE(vm->objectClass, "toString", object_toString);
1252 PRIMITIVE(vm->objectClass, "type", object_type);
1253
1254 // Now we can define Class, which is a subclass of Object.
1255 vm->classClass = defineClass(vm, coreModule, "Class");
1256 wrenBindSuperclass(vm, vm->classClass, vm->objectClass);
1257 PRIMITIVE(vm->classClass, "name", class_name);
1258 PRIMITIVE(vm->classClass, "supertype", class_supertype);
1259 PRIMITIVE(vm->classClass, "toString", class_toString);
1260 PRIMITIVE(vm->classClass, "attributes", class_attributes);
1261
1262 // Finally, we can define Object's metaclass which is a subclass of Class.
1263 ObjClass* objectMetaclass = defineClass(vm, coreModule, "Object metaclass");
1264
1265 // Wire up the metaclass relationships now that all three classes are built.
1266 vm->objectClass->obj.classObj = objectMetaclass;
1267 objectMetaclass->obj.classObj = vm->classClass;
1268 vm->classClass->obj.classObj = vm->classClass;
1269
1270 // Do this after wiring up the metaclasses so objectMetaclass doesn't get
1271 // collected.
1272 wrenBindSuperclass(vm, objectMetaclass, vm->classClass);
1273
1274 PRIMITIVE(objectMetaclass, "same(_,_)", object_same);
1275
1276 // The core class diagram ends up looking like this, where single lines point
1277 // to a class's superclass, and double lines point to its metaclass:
1278 //
1279 // .------------------------------------. .====.
1280 // | .---------------. | # #
1281 // v | v | v #
1282 // .---------. .-------------------. .-------. #
1283 // | Object |==>| Object metaclass |==>| Class |=="
1284 // '---------' '-------------------' '-------'
1285 // ^ ^ ^ ^ ^
1286 // | .--------------' # | #
1287 // | | # | #
1288 // .---------. .-------------------. # | # -.
1289 // | Base |==>| Base metaclass |======" | # |
1290 // '---------' '-------------------' | # |
1291 // ^ | # |
1292 // | .------------------' # | Example classes
1293 // | | # |
1294 // .---------. .-------------------. # |
1295 // | Derived |==>| Derived metaclass |==========" |
1296 // '---------' '-------------------' -'
1297
1298 // The rest of the classes can now be defined normally.
1299 wrenInterpret(vm, NULL, coreModuleSource);
1300
1301 vm->boolClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Bool"));
1302 PRIMITIVE(vm->boolClass, "toString", bool_toString);
1303 PRIMITIVE(vm->boolClass, "!", bool_not);
1304
1305 vm->fiberClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Fiber"));
1306 PRIMITIVE(vm->fiberClass->obj.classObj, "new(_)", fiber_new);
1307 PRIMITIVE(vm->fiberClass->obj.classObj, "abort(_)", fiber_abort);
1308 PRIMITIVE(vm->fiberClass->obj.classObj, "current", fiber_current);
1309 PRIMITIVE(vm->fiberClass->obj.classObj, "suspend()", fiber_suspend);
1310 PRIMITIVE(vm->fiberClass->obj.classObj, "yield()", fiber_yield);
1311 PRIMITIVE(vm->fiberClass->obj.classObj, "yield(_)", fiber_yield1);
1312 PRIMITIVE(vm->fiberClass, "call()", fiber_call);
1313 PRIMITIVE(vm->fiberClass, "call(_)", fiber_call1);
1314 PRIMITIVE(vm->fiberClass, "error", fiber_error);
1315 PRIMITIVE(vm->fiberClass, "isDone", fiber_isDone);
1316 PRIMITIVE(vm->fiberClass, "transfer()", fiber_transfer);
1317 PRIMITIVE(vm->fiberClass, "transfer(_)", fiber_transfer1);
1318 PRIMITIVE(vm->fiberClass, "transferError(_)", fiber_transferError);
1319 PRIMITIVE(vm->fiberClass, "try()", fiber_try);
1320 PRIMITIVE(vm->fiberClass, "try(_)", fiber_try1);
1321
1322 vm->fnClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Fn"));
1323 PRIMITIVE(vm->fnClass->obj.classObj, "new(_)", fn_new);
1324
1325 PRIMITIVE(vm->fnClass, "arity", fn_arity);
1326
1327 FUNCTION_CALL(vm->fnClass, "call()", fn_call0);
1328 FUNCTION_CALL(vm->fnClass, "call(_)", fn_call1);
1329 FUNCTION_CALL(vm->fnClass, "call(_,_)", fn_call2);
1330 FUNCTION_CALL(vm->fnClass, "call(_,_,_)", fn_call3);
1331 FUNCTION_CALL(vm->fnClass, "call(_,_,_,_)", fn_call4);
1332 FUNCTION_CALL(vm->fnClass, "call(_,_,_,_,_)", fn_call5);
1333 FUNCTION_CALL(vm->fnClass, "call(_,_,_,_,_,_)", fn_call6);
1334 FUNCTION_CALL(vm->fnClass, "call(_,_,_,_,_,_,_)", fn_call7);
1335 FUNCTION_CALL(vm->fnClass, "call(_,_,_,_,_,_,_,_)", fn_call8);
1336 FUNCTION_CALL(vm->fnClass, "call(_,_,_,_,_,_,_,_,_)", fn_call9);
1337 FUNCTION_CALL(vm->fnClass, "call(_,_,_,_,_,_,_,_,_,_)", fn_call10);
1338 FUNCTION_CALL(vm->fnClass, "call(_,_,_,_,_,_,_,_,_,_,_)", fn_call11);
1339 FUNCTION_CALL(vm->fnClass, "call(_,_,_,_,_,_,_,_,_,_,_,_)", fn_call12);
1340 FUNCTION_CALL(vm->fnClass, "call(_,_,_,_,_,_,_,_,_,_,_,_,_)", fn_call13);
1341 FUNCTION_CALL(vm->fnClass, "call(_,_,_,_,_,_,_,_,_,_,_,_,_,_)", fn_call14);
1342 FUNCTION_CALL(vm->fnClass, "call(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_)", fn_call15);
1343 FUNCTION_CALL(vm->fnClass, "call(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_)", fn_call16);
1344
1345 PRIMITIVE(vm->fnClass, "toString", fn_toString);
1346
1347 vm->nullClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Null"));
1348 PRIMITIVE(vm->nullClass, "!", null_not);
1349 PRIMITIVE(vm->nullClass, "toString", null_toString);
1350
1351 vm->numClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Num"));
1352 PRIMITIVE(vm->numClass->obj.classObj, "fromString(_)", num_fromString);
1353 PRIMITIVE(vm->numClass->obj.classObj, "infinity", num_infinity);
1354 PRIMITIVE(vm->numClass->obj.classObj, "nan", num_nan);
1355 PRIMITIVE(vm->numClass->obj.classObj, "pi", num_pi);
1356 PRIMITIVE(vm->numClass->obj.classObj, "tau", num_tau);
1357 PRIMITIVE(vm->numClass->obj.classObj, "largest", num_largest);
1358 PRIMITIVE(vm->numClass->obj.classObj, "smallest", num_smallest);
1359 PRIMITIVE(vm->numClass->obj.classObj, "maxSafeInteger", num_maxSafeInteger);
1360 PRIMITIVE(vm->numClass->obj.classObj, "minSafeInteger", num_minSafeInteger);
1361 PRIMITIVE(vm->numClass, "-(_)", num_minus);
1362 PRIMITIVE(vm->numClass, "+(_)", num_plus);
1363 PRIMITIVE(vm->numClass, "*(_)", num_multiply);
1364 PRIMITIVE(vm->numClass, "/(_)", num_divide);
1365 PRIMITIVE(vm->numClass, "<(_)", num_lt);
1366 PRIMITIVE(vm->numClass, ">(_)", num_gt);
1367 PRIMITIVE(vm->numClass, "<=(_)", num_lte);
1368 PRIMITIVE(vm->numClass, ">=(_)", num_gte);
1369 PRIMITIVE(vm->numClass, "&(_)", num_bitwiseAnd);
1370 PRIMITIVE(vm->numClass, "|(_)", num_bitwiseOr);
1371 PRIMITIVE(vm->numClass, "^(_)", num_bitwiseXor);
1372 PRIMITIVE(vm->numClass, "<<(_)", num_bitwiseLeftShift);
1373 PRIMITIVE(vm->numClass, ">>(_)", num_bitwiseRightShift);
1374 PRIMITIVE(vm->numClass, "abs", num_abs);
1375 PRIMITIVE(vm->numClass, "acos", num_acos);
1376 PRIMITIVE(vm->numClass, "asin", num_asin);
1377 PRIMITIVE(vm->numClass, "atan", num_atan);
1378 PRIMITIVE(vm->numClass, "cbrt", num_cbrt);
1379 PRIMITIVE(vm->numClass, "ceil", num_ceil);
1380 PRIMITIVE(vm->numClass, "cos", num_cos);
1381 PRIMITIVE(vm->numClass, "floor", num_floor);
1382 PRIMITIVE(vm->numClass, "-", num_negate);
1383 PRIMITIVE(vm->numClass, "round", num_round);
1384 PRIMITIVE(vm->numClass, "min(_)", num_min);
1385 PRIMITIVE(vm->numClass, "max(_)", num_max);
1386 PRIMITIVE(vm->numClass, "clamp(_,_)", num_clamp);
1387 PRIMITIVE(vm->numClass, "sin", num_sin);
1388 PRIMITIVE(vm->numClass, "sqrt", num_sqrt);
1389 PRIMITIVE(vm->numClass, "tan", num_tan);
1390 PRIMITIVE(vm->numClass, "log", num_log);
1391 PRIMITIVE(vm->numClass, "log2", num_log2);
1392 PRIMITIVE(vm->numClass, "exp", num_exp);
1393 PRIMITIVE(vm->numClass, "%(_)", num_mod);
1394 PRIMITIVE(vm->numClass, "~", num_bitwiseNot);
1395 PRIMITIVE(vm->numClass, "..(_)", num_dotDot);
1396 PRIMITIVE(vm->numClass, "...(_)", num_dotDotDot);
1397 PRIMITIVE(vm->numClass, "atan(_)", num_atan2);
1398 PRIMITIVE(vm->numClass, "pow(_)", num_pow);
1399 PRIMITIVE(vm->numClass, "fraction", num_fraction);
1400 PRIMITIVE(vm->numClass, "isInfinity", num_isInfinity);
1401 PRIMITIVE(vm->numClass, "isInteger", num_isInteger);
1402 PRIMITIVE(vm->numClass, "isNan", num_isNan);
1403 PRIMITIVE(vm->numClass, "sign", num_sign);
1404 PRIMITIVE(vm->numClass, "toString", num_toString);
1405 PRIMITIVE(vm->numClass, "truncate", num_truncate);
1406
1407 // These are defined just so that 0 and -0 are equal, which is specified by
1408 // IEEE 754 even though they have different bit representations.
1409 PRIMITIVE(vm->numClass, "==(_)", num_eqeq);
1410 PRIMITIVE(vm->numClass, "!=(_)", num_bangeq);
1411
1412 vm->stringClass = AS_CLASS(wrenFindVariable(vm, coreModule, "String"));
1413 PRIMITIVE(vm->stringClass->obj.classObj, "fromCodePoint(_)", string_fromCodePoint);
1414 PRIMITIVE(vm->stringClass->obj.classObj, "fromByte(_)", string_fromByte);
1415 PRIMITIVE(vm->stringClass, "+(_)", string_plus);
1416 PRIMITIVE(vm->stringClass, "[_]", string_subscript);
1417 PRIMITIVE(vm->stringClass, "byteAt_(_)", string_byteAt);
1418 PRIMITIVE(vm->stringClass, "byteCount_", string_byteCount);
1419 PRIMITIVE(vm->stringClass, "codePointAt_(_)", string_codePointAt);
1420 PRIMITIVE(vm->stringClass, "contains(_)", string_contains);
1421 PRIMITIVE(vm->stringClass, "endsWith(_)", string_endsWith);
1422 PRIMITIVE(vm->stringClass, "indexOf(_)", string_indexOf1);
1423 PRIMITIVE(vm->stringClass, "indexOf(_,_)", string_indexOf2);
1424 PRIMITIVE(vm->stringClass, "iterate(_)", string_iterate);
1425 PRIMITIVE(vm->stringClass, "iterateByte_(_)", string_iterateByte);
1426 PRIMITIVE(vm->stringClass, "iteratorValue(_)", string_iteratorValue);
1427 PRIMITIVE(vm->stringClass, "startsWith(_)", string_startsWith);
1428 PRIMITIVE(vm->stringClass, "toString", string_toString);
1429
1430 vm->listClass = AS_CLASS(wrenFindVariable(vm, coreModule, "List"));
1431 PRIMITIVE(vm->listClass->obj.classObj, "filled(_,_)", list_filled);
1432 PRIMITIVE(vm->listClass->obj.classObj, "new()", list_new);
1433 PRIMITIVE(vm->listClass, "[_]", list_subscript);
1434 PRIMITIVE(vm->listClass, "[_]=(_)", list_subscriptSetter);
1435 PRIMITIVE(vm->listClass, "add(_)", list_add);
1436 PRIMITIVE(vm->listClass, "addCore_(_)", list_addCore);
1437 PRIMITIVE(vm->listClass, "clear()", list_clear);
1438 PRIMITIVE(vm->listClass, "count", list_count);
1439 PRIMITIVE(vm->listClass, "insert(_,_)", list_insert);
1440 PRIMITIVE(vm->listClass, "iterate(_)", list_iterate);
1441 PRIMITIVE(vm->listClass, "iteratorValue(_)", list_iteratorValue);
1442 PRIMITIVE(vm->listClass, "removeAt(_)", list_removeAt);
1443 PRIMITIVE(vm->listClass, "remove(_)", list_removeValue);
1444 PRIMITIVE(vm->listClass, "indexOf(_)", list_indexOf);
1445 PRIMITIVE(vm->listClass, "swap(_,_)", list_swap);
1446
1447 vm->mapClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Map"));
1448 PRIMITIVE(vm->mapClass->obj.classObj, "new()", map_new);
1449 PRIMITIVE(vm->mapClass, "[_]", map_subscript);
1450 PRIMITIVE(vm->mapClass, "[_]=(_)", map_subscriptSetter);
1451 PRIMITIVE(vm->mapClass, "addCore_(_,_)", map_addCore);
1452 PRIMITIVE(vm->mapClass, "clear()", map_clear);
1453 PRIMITIVE(vm->mapClass, "containsKey(_)", map_containsKey);
1454 PRIMITIVE(vm->mapClass, "count", map_count);
1455 PRIMITIVE(vm->mapClass, "remove(_)", map_remove);
1456 PRIMITIVE(vm->mapClass, "iterate(_)", map_iterate);
1457 PRIMITIVE(vm->mapClass, "keyIteratorValue_(_)", map_keyIteratorValue);
1458 PRIMITIVE(vm->mapClass, "valueIteratorValue_(_)", map_valueIteratorValue);
1459
1460 vm->rangeClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Range"));
1461 PRIMITIVE(vm->rangeClass, "from", range_from);
1462 PRIMITIVE(vm->rangeClass, "to", range_to);
1463 PRIMITIVE(vm->rangeClass, "min", range_min);
1464 PRIMITIVE(vm->rangeClass, "max", range_max);
1465 PRIMITIVE(vm->rangeClass, "isInclusive", range_isInclusive);
1466 PRIMITIVE(vm->rangeClass, "iterate(_)", range_iterate);
1467 PRIMITIVE(vm->rangeClass, "iteratorValue(_)", range_iteratorValue);
1468 PRIMITIVE(vm->rangeClass, "toString", range_toString);
1469
1470 ObjClass* systemClass = AS_CLASS(wrenFindVariable(vm, coreModule, "System"));
1471 PRIMITIVE(systemClass->obj.classObj, "clock", system_clock);
1472 PRIMITIVE(systemClass->obj.classObj, "gc()", system_gc);
1473 PRIMITIVE(systemClass->obj.classObj, "writeString_(_)", system_writeString);
1474
1475 // While bootstrapping the core types and running the core module, a number
1476 // of string objects have been created, many of which were instantiated
1477 // before stringClass was stored in the VM. Some of them *must* be created
1478 // first -- the ObjClass for string itself has a reference to the ObjString
1479 // for its name.
1480 //
1481 // These all currently have a NULL classObj pointer, so go back and assign
1482 // them now that the string class is known.
1483 for (Obj* obj = vm->first; obj != NULL; obj = obj->next)
1484 {
1485 if (obj->type == OBJ_STRING) obj->classObj = vm->stringClass;
1486 }
1487}
1488