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 | |
16 | DEF_PRIMITIVE(bool_not) |
17 | { |
18 | RETURN_BOOL(!AS_BOOL(args[0])); |
19 | } |
20 | |
21 | DEF_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 | |
33 | DEF_PRIMITIVE(class_name) |
34 | { |
35 | RETURN_OBJ(AS_CLASS(args[0])->name); |
36 | } |
37 | |
38 | DEF_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 | |
48 | DEF_PRIMITIVE(class_toString) |
49 | { |
50 | RETURN_OBJ(AS_CLASS(args[0])->name); |
51 | } |
52 | |
53 | DEF_PRIMITIVE(class_attributes) |
54 | { |
55 | RETURN_VAL(AS_CLASS(args[0])->attributes); |
56 | } |
57 | |
58 | DEF_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 | |
71 | DEF_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. |
86 | static 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 | |
140 | DEF_PRIMITIVE(fiber_call) |
141 | { |
142 | return runFiber(vm, AS_FIBER(args[0]), args, true, false, "call" ); |
143 | } |
144 | |
145 | DEF_PRIMITIVE(fiber_call1) |
146 | { |
147 | return runFiber(vm, AS_FIBER(args[0]), args, true, true, "call" ); |
148 | } |
149 | |
150 | DEF_PRIMITIVE(fiber_current) |
151 | { |
152 | RETURN_OBJ(vm->fiber); |
153 | } |
154 | |
155 | DEF_PRIMITIVE(fiber_error) |
156 | { |
157 | RETURN_VAL(AS_FIBER(args[0])->error); |
158 | } |
159 | |
160 | DEF_PRIMITIVE(fiber_isDone) |
161 | { |
162 | ObjFiber* runFiber = AS_FIBER(args[0]); |
163 | RETURN_BOOL(runFiber->numFrames == 0 || wrenHasError(runFiber)); |
164 | } |
165 | |
166 | DEF_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 | |
174 | DEF_PRIMITIVE(fiber_transfer) |
175 | { |
176 | return runFiber(vm, AS_FIBER(args[0]), args, false, false, "transfer to" ); |
177 | } |
178 | |
179 | DEF_PRIMITIVE(fiber_transfer1) |
180 | { |
181 | return runFiber(vm, AS_FIBER(args[0]), args, false, true, "transfer to" ); |
182 | } |
183 | |
184 | DEF_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 | |
191 | DEF_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 | |
200 | DEF_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 | |
209 | DEF_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 | |
227 | DEF_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 | |
251 | DEF_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 | |
259 | DEF_PRIMITIVE(fn_arity) |
260 | { |
261 | RETURN_NUM(AS_CLOSURE(args[0])->fn->arity); |
262 | } |
263 | |
264 | static 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 | |
277 | DEF_FN_CALL(0) |
278 | DEF_FN_CALL(1) |
279 | DEF_FN_CALL(2) |
280 | DEF_FN_CALL(3) |
281 | DEF_FN_CALL(4) |
282 | DEF_FN_CALL(5) |
283 | DEF_FN_CALL(6) |
284 | DEF_FN_CALL(7) |
285 | DEF_FN_CALL(8) |
286 | DEF_FN_CALL(9) |
287 | DEF_FN_CALL(10) |
288 | DEF_FN_CALL(11) |
289 | DEF_FN_CALL(12) |
290 | DEF_FN_CALL(13) |
291 | DEF_FN_CALL(14) |
292 | DEF_FN_CALL(15) |
293 | DEF_FN_CALL(16) |
294 | |
295 | DEF_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]. |
301 | DEF_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 | |
317 | DEF_PRIMITIVE(list_new) |
318 | { |
319 | RETURN_OBJ(wrenNewList(vm, 0)); |
320 | } |
321 | |
322 | DEF_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. |
331 | DEF_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 | |
339 | DEF_PRIMITIVE(list_clear) |
340 | { |
341 | wrenValueBufferClear(vm, &AS_LIST(args[0])->elements); |
342 | RETURN_NULL; |
343 | } |
344 | |
345 | DEF_PRIMITIVE(list_count) |
346 | { |
347 | RETURN_NUM(AS_LIST(args[0])->elements.count); |
348 | } |
349 | |
350 | DEF_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 | |
363 | DEF_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 | |
384 | DEF_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 | |
393 | DEF_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 | |
402 | DEF_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 | |
409 | DEF_PRIMITIVE(list_indexOf) |
410 | { |
411 | ObjList* list = AS_LIST(args[0]); |
412 | RETURN_NUM(wrenListIndexOf(vm, list, args[1])); |
413 | } |
414 | |
415 | DEF_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 | |
430 | DEF_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 | |
462 | DEF_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 | |
473 | DEF_PRIMITIVE(map_new) |
474 | { |
475 | RETURN_OBJ(wrenNewMap(vm)); |
476 | } |
477 | |
478 | DEF_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 | |
489 | DEF_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. |
500 | DEF_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 | |
510 | DEF_PRIMITIVE(map_clear) |
511 | { |
512 | wrenMapClear(vm, AS_MAP(args[0])); |
513 | RETURN_NULL; |
514 | } |
515 | |
516 | DEF_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 | |
523 | DEF_PRIMITIVE(map_count) |
524 | { |
525 | RETURN_NUM(AS_MAP(args[0])->count); |
526 | } |
527 | |
528 | DEF_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 | |
561 | DEF_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 | |
568 | DEF_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 | |
583 | DEF_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 | |
598 | DEF_PRIMITIVE(null_not) |
599 | { |
600 | RETURN_VAL(TRUE_VAL); |
601 | } |
602 | |
603 | DEF_PRIMITIVE(null_toString) |
604 | { |
605 | RETURN_VAL(CONST_STRING(vm, "null" )); |
606 | } |
607 | |
608 | DEF_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 | |
640 | DEF_NUM_CONSTANT(infinity, INFINITY) |
641 | DEF_NUM_CONSTANT(nan, WREN_DOUBLE_NAN) |
642 | DEF_NUM_CONSTANT(pi, 3.14159265358979323846264338327950288) |
643 | DEF_NUM_CONSTANT(tau, 6.28318530717958647692528676655900577) |
644 | |
645 | DEF_NUM_CONSTANT(largest, DBL_MAX) |
646 | DEF_NUM_CONSTANT(smallest, DBL_MIN) |
647 | |
648 | DEF_NUM_CONSTANT(maxSafeInteger, 9007199254740991.0) |
649 | DEF_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 | |
659 | DEF_NUM_INFIX(minus, -, NUM) |
660 | DEF_NUM_INFIX(plus, +, NUM) |
661 | DEF_NUM_INFIX(multiply, *, NUM) |
662 | DEF_NUM_INFIX(divide, /, NUM) |
663 | DEF_NUM_INFIX(lt, <, BOOL) |
664 | DEF_NUM_INFIX(gt, >, BOOL) |
665 | DEF_NUM_INFIX(lte, <=, BOOL) |
666 | DEF_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 | |
678 | DEF_NUM_BITWISE(And, &) |
679 | DEF_NUM_BITWISE(Or, |) |
680 | DEF_NUM_BITWISE(Xor, ^) |
681 | DEF_NUM_BITWISE(LeftShift, <<) |
682 | DEF_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 | |
691 | DEF_NUM_FN(abs, fabs) |
692 | DEF_NUM_FN(acos, acos) |
693 | DEF_NUM_FN(asin, asin) |
694 | DEF_NUM_FN(atan, atan) |
695 | DEF_NUM_FN(cbrt, cbrt) |
696 | DEF_NUM_FN(ceil, ceil) |
697 | DEF_NUM_FN(cos, cos) |
698 | DEF_NUM_FN(floor, floor) |
699 | DEF_NUM_FN(negate, -) |
700 | DEF_NUM_FN(round, round) |
701 | DEF_NUM_FN(sin, sin) |
702 | DEF_NUM_FN(sqrt, sqrt) |
703 | DEF_NUM_FN(tan, tan) |
704 | DEF_NUM_FN(log, log) |
705 | DEF_NUM_FN(log2, log2) |
706 | DEF_NUM_FN(exp, exp) |
707 | |
708 | DEF_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 | |
714 | DEF_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 | |
720 | DEF_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 | |
726 | DEF_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 | |
732 | DEF_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 | |
741 | DEF_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 | |
750 | DEF_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 | |
757 | DEF_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 | |
766 | DEF_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 | |
775 | DEF_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 | |
787 | DEF_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 | |
794 | DEF_PRIMITIVE(num_fraction) |
795 | { |
796 | double unused; |
797 | RETURN_NUM(modf(AS_NUM(args[0]) , &unused)); |
798 | } |
799 | |
800 | DEF_PRIMITIVE(num_isInfinity) |
801 | { |
802 | RETURN_BOOL(isinf(AS_NUM(args[0]))); |
803 | } |
804 | |
805 | DEF_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 | |
812 | DEF_PRIMITIVE(num_isNan) |
813 | { |
814 | RETURN_BOOL(isnan(AS_NUM(args[0]))); |
815 | } |
816 | |
817 | DEF_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 | |
834 | DEF_PRIMITIVE(num_toString) |
835 | { |
836 | RETURN_VAL(wrenNumToString(vm, AS_NUM(args[0]))); |
837 | } |
838 | |
839 | DEF_PRIMITIVE(num_truncate) |
840 | { |
841 | double integer; |
842 | modf(AS_NUM(args[0]) , &integer); |
843 | RETURN_NUM(integer); |
844 | } |
845 | |
846 | DEF_PRIMITIVE(object_same) |
847 | { |
848 | RETURN_BOOL(wrenValuesEqual(args[1], args[2])); |
849 | } |
850 | |
851 | DEF_PRIMITIVE(object_not) |
852 | { |
853 | RETURN_VAL(FALSE_VAL); |
854 | } |
855 | |
856 | DEF_PRIMITIVE(object_eqeq) |
857 | { |
858 | RETURN_BOOL(wrenValuesEqual(args[0], args[1])); |
859 | } |
860 | |
861 | DEF_PRIMITIVE(object_bangeq) |
862 | { |
863 | RETURN_BOOL(!wrenValuesEqual(args[0], args[1])); |
864 | } |
865 | |
866 | DEF_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 | |
888 | DEF_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 | |
895 | DEF_PRIMITIVE(object_type) |
896 | { |
897 | RETURN_OBJ(wrenGetClass(vm, args[0])); |
898 | } |
899 | |
900 | DEF_PRIMITIVE(range_from) |
901 | { |
902 | RETURN_NUM(AS_RANGE(args[0])->from); |
903 | } |
904 | |
905 | DEF_PRIMITIVE(range_to) |
906 | { |
907 | RETURN_NUM(AS_RANGE(args[0])->to); |
908 | } |
909 | |
910 | DEF_PRIMITIVE(range_min) |
911 | { |
912 | ObjRange* range = AS_RANGE(args[0]); |
913 | RETURN_NUM(fmin(range->from, range->to)); |
914 | } |
915 | |
916 | DEF_PRIMITIVE(range_max) |
917 | { |
918 | ObjRange* range = AS_RANGE(args[0]); |
919 | RETURN_NUM(fmax(range->from, range->to)); |
920 | } |
921 | |
922 | DEF_PRIMITIVE(range_isInclusive) |
923 | { |
924 | RETURN_BOOL(AS_RANGE(args[0])->isInclusive); |
925 | } |
926 | |
927 | DEF_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 | |
958 | DEF_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 | |
964 | DEF_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 | |
982 | DEF_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 | |
999 | DEF_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 | |
1014 | DEF_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 | |
1024 | DEF_PRIMITIVE(string_byteCount) |
1025 | { |
1026 | RETURN_NUM(AS_STRING(args[0])->length); |
1027 | } |
1028 | |
1029 | DEF_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 | |
1045 | DEF_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 | |
1055 | DEF_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 | |
1069 | DEF_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 | |
1080 | DEF_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 | |
1093 | DEF_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 | |
1119 | DEF_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 | |
1142 | DEF_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 | |
1151 | DEF_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 | |
1164 | DEF_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 | |
1170 | DEF_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 | |
1195 | DEF_PRIMITIVE(string_toString) |
1196 | { |
1197 | RETURN_VAL(args[0]); |
1198 | } |
1199 | |
1200 | DEF_PRIMITIVE(system_clock) |
1201 | { |
1202 | RETURN_NUM((double)clock() / CLOCKS_PER_SEC); |
1203 | } |
1204 | |
1205 | DEF_PRIMITIVE(system_gc) |
1206 | { |
1207 | wrenCollectGarbage(vm); |
1208 | RETURN_NULL; |
1209 | } |
1210 | |
1211 | DEF_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]. |
1222 | static 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 | |
1235 | void 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 | |