Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epidemian
GitHub Repository: epidemian/gravity
Path: blob/master/src/runtime/gravity_core.c
1218 views
1
//
2
// gravity_core.c
3
// gravity
4
//
5
// Created by Marco Bambini on 10/01/15.
6
// Copyright (c) 2015 CreoLabs. All rights reserved.
7
//
8
9
#include <math.h>
10
#include "gravity_core.h"
11
#include "gravity_hash.h"
12
#include "gravity_value.h"
13
#include "gravity_opcodes.h"
14
#include "gravity_macros.h"
15
#include "gravity_memory.h"
16
17
// Gravity base classes (the isa pointer in each object).
18
// Null and Undefined points to same class (Null) and they
19
// differs from the n field inside gravity_value_t.
20
// n == 0 means NULL while n == 1 means UNDEFINED so I can
21
// reuse the same methods for both.
22
//
23
// Intrinsic datatypes are:
24
// - Int
25
// - Float
26
// - Boolean
27
// - String
28
// For these classes 4 conveniente conversion methods are provided.
29
30
// How internal conversion works
31
//
32
// Conversion is driven by the v1 class, so v2 is usually converter to v1 class
33
// and if the result is not as expected (very likely in complex expression) then the user
34
// is invited to explicitly cast values to the desired types.
35
// If a propert conversion function is not found then a runtime error is raised.
36
37
// Special note about Integer class
38
//
39
// Integer not always drives conversion based on v1 class
40
// that's because we are trying to fix the common case where
41
// an integer is added to a float.
42
// Without the smart check an operation like:
43
// 1 + 2.3 will result in 3
44
// So the first check is about v2 class (v1 is known) and if v2 class is float
45
// then v1 is converted to float and the propert operator_float_* function is called.
46
47
// Special note about Integer class
48
//
49
// Bitshift Operators does not make any sense for floating point values
50
// as pointed out here: http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/bitshift.html
51
// a trick could be to use a pointer to an int to actually manipulate
52
// floating point value. Since this is more a trick then a real solution
53
// I decided to cast v2 to integer without any extra check.
54
// Only operator_float_bit* functions are affected by this trick.
55
56
// Special note about Null class
57
//
58
// Every value in gravity is initialized to Null
59
// and can partecipate in math operations.
60
// This class should be defined in a way to do be
61
// less dangerous as possibile and a Null value should
62
// be interpreted as a zero number (where possibile).
63
64
static bool core_inited = false; // initialize global classes just once
65
static uint32_t refcount = 0; // protect deallocation of global classes
66
67
// boxed
68
gravity_class_t *gravity_class_int;
69
gravity_class_t *gravity_class_float;
70
gravity_class_t *gravity_class_bool;
71
gravity_class_t *gravity_class_null;
72
// objects
73
gravity_class_t *gravity_class_string;
74
gravity_class_t *gravity_class_object;
75
gravity_class_t *gravity_class_function;
76
gravity_class_t *gravity_class_closure;
77
gravity_class_t *gravity_class_fiber;
78
gravity_class_t *gravity_class_class;
79
gravity_class_t *gravity_class_instance;
80
gravity_class_t *gravity_class_module;
81
gravity_class_t *gravity_class_list;
82
gravity_class_t *gravity_class_map;
83
gravity_class_t *gravity_class_range;
84
gravity_class_t *gravity_class_upvalue;
85
gravity_class_t *gravity_class_system;
86
87
#define SETMETA_INITED(c) gravity_class_get_meta(c)->is_inited = true
88
#define GET_VALUE(_idx) args[_idx]
89
#define RETURN_VALUE(_v,_i) do {gravity_vm_setslot(vm, _v, _i); return true;} while(0)
90
#define RETURN_CLOSURE(_v,_i) do {gravity_vm_setslot(vm, _v, _i); return false;} while(0)
91
#define RETURN_FIBER() return false
92
#define RETURN_NOVALUE() return true
93
#define RETURN_ERROR(...) do { \
94
char buffer[4096]; \
95
snprintf(buffer, sizeof(buffer), __VA_ARGS__); \
96
gravity_fiber_seterror(gravity_vm_fiber(vm), (const char *) buffer); \
97
return false; \
98
} while(0)
99
100
#define DECLARE_1VARIABLE(_v,_idx) register gravity_value_t _v = GET_VALUE(_idx)
101
#define DECLARE_2VARIABLES(_v1,_v2,_idx1,_idx2) DECLARE_1VARIABLE(_v1,_idx1);DECLARE_1VARIABLE(_v2,_idx2)
102
103
#define CHECK_VALID(_v, _msg) if (VALUE_ISA_NOTVALID(_v)) RETURN_ERROR(_msg)
104
#define INTERNAL_CONVERT_FLOAT(_v) _v = convert_value2float(vm,_v); CHECK_VALID(_v, "Unable to convert object to Float")
105
#define INTERNAL_CONVERT_BOOL(_v) _v = convert_value2bool(vm,_v); CHECK_VALID(_v, "Unable to convert object to Bool")
106
#define INTERNAL_CONVERT_INT(_v) _v = convert_value2int(vm,_v); CHECK_VALID(_v, "Unable to convert object to Int")
107
#define INTERNAL_CONVERT_STRING(_v) _v = convert_value2string(vm,_v); CHECK_VALID(_v, "Unable to convert object to String")
108
109
#define NEW_FUNCTION(_fptr) (gravity_function_new_internal(NULL, NULL, _fptr, 0))
110
#define NEW_CLOSURE_VALUE(_fptr) ((gravity_value_t){ .isa = gravity_class_closure, \
111
.p = (gravity_object_t *)gravity_closure_new(NULL, NEW_FUNCTION(_fptr))})
112
113
#define FUNCTION_ISA_SPECIAL(_f) (OBJECT_ISA_FUNCTION(_f) && (_f->tag == EXEC_TYPE_SPECIAL))
114
#define FUNCTION_ISA_DEFAULT_GETTER(_f) ((_f->index < GRAVITY_COMPUTED_INDEX) && (_f->special[EXEC_TYPE_SPECIAL_GETTER] == NULL))
115
#define FUNCTION_ISA_DEFAULT_SETTER(_f) ((_f->index < GRAVITY_COMPUTED_INDEX) && (_f->special[EXEC_TYPE_SPECIAL_SETTER] == NULL))
116
#define FUNCTION_ISA_GETTER(_f) (_f->special[EXEC_TYPE_SPECIAL_GETTER] != NULL)
117
#define FUNCTION_ISA_SETTER(_f) (_f->special[EXEC_TYPE_SPECIAL_SETTER] != NULL)
118
#define FUNCTION_ISA_BRIDGED(_f) (_f->index == GRAVITY_BRIDGE_INDEX)
119
120
// MARK: - Conversions -
121
122
static gravity_value_t convert_string2number (gravity_string_t *string, bool float_preferred) {
123
// empty string case
124
if (string->len == 0) return (float_preferred) ? VALUE_FROM_FLOAT(0.0) : VALUE_FROM_INT(0);
125
126
register const char *s = string->s;
127
register uint32_t len = string->len;
128
register int32_t sign = 1;
129
130
// check sign first
131
if ((s[0] == '-') || (s[0] == '+')) {
132
if (s[0] == '-') sign = -1;
133
++s; --len;
134
}
135
136
// check special HEX, OCT, BIN cases
137
if ((s[0] == '0') && (len > 2)) {
138
int64_t n = 0;
139
140
int c = toupper(s[1]);
141
if (c == 'B') n = number_from_bin(&s[2], len-2);
142
else if (c == 'O') n = number_from_oct(&s[2], len-2);
143
else if (c == 'X') n = number_from_hex(s, len);
144
if (sign == -1) n = -n;
145
return (float_preferred) ? VALUE_FROM_FLOAT((gravity_float_t)n) : VALUE_FROM_INT((gravity_int_t)n);
146
}
147
148
// default case
149
return (float_preferred) ? VALUE_FROM_FLOAT(strtod(string->s, NULL)) : VALUE_FROM_INT(strtoll(string->s, NULL, 0));
150
}
151
152
static bool convert_object_int (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
153
#pragma unused(vm, nargs)
154
gravity_value_t v = convert_value2int(vm, GET_VALUE(0));
155
if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert object to Int.");
156
RETURN_VALUE(v, rindex);
157
}
158
159
static bool convert_object_float (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
160
#pragma unused(vm, nargs)
161
gravity_value_t v = convert_value2float(vm, GET_VALUE(0));
162
if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert object to Float.");
163
RETURN_VALUE(v, rindex);
164
}
165
166
static bool convert_object_bool (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
167
#pragma unused(vm, nargs)
168
gravity_value_t v = convert_value2bool(vm, GET_VALUE(0));
169
if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert object to Bool.");
170
RETURN_VALUE(v, rindex);
171
}
172
173
static bool convert_object_string (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
174
#pragma unused(vm, nargs)
175
gravity_value_t v = convert_value2string(vm, GET_VALUE(0));
176
if (VALUE_ISA_NOTVALID(v)) RETURN_ERROR("Unable to convert object to String.");
177
RETURN_VALUE(v, rindex);
178
}
179
180
static inline gravity_value_t convert_map2string (gravity_vm *vm, gravity_map_t *map) {
181
#pragma unused(vm, map)
182
return VALUE_FROM_STRING(vm, "MAP", 3); //VALUE_FROM_NULL;
183
}
184
185
static inline gravity_value_t convert_list2string (gravity_vm *vm, gravity_list_t *list) {
186
// allocate initial memory to a 512 buffer
187
uint32_t len = 512;
188
char *buffer = mem_alloc(len+1);
189
buffer[0] = '[';
190
uint32_t pos = 1;
191
192
// loop to perform string concat
193
uint32_t count = (uint32_t) marray_size(list->array);
194
for (uint32_t i=0; i<count; ++i) {
195
gravity_value_t value = marray_get(list->array, i);
196
gravity_value_t value2 = convert_value2string(vm, value);
197
gravity_string_t *string = VALUE_ISA_VALID(value2) ? VALUE_AS_STRING(value2) : NULL;
198
199
char *s1 = (string) ? string->s : "N/A";
200
uint32_t len1 = (string) ? string->len : 3;
201
202
// check if buffer needs to be reallocated
203
if (len1+pos+2 > len) {
204
len = (len1+pos+2) + len;
205
buffer = mem_realloc(buffer, len);
206
}
207
208
// copy string to new buffer
209
memcpy(buffer+pos, s1, len1);
210
pos += len1;
211
212
// add separator
213
if (i+1 < count) {
214
memcpy(buffer+pos, ",", 1);
215
pos += 1;
216
}
217
}
218
219
// Write latest ] character
220
memcpy(buffer+pos, "]", 1);
221
buffer[++pos] = 0;
222
223
gravity_value_t result = VALUE_FROM_STRING(vm, buffer, pos);
224
mem_free(buffer);
225
return result;
226
}
227
228
inline gravity_value_t convert_value2int (gravity_vm *vm, gravity_value_t v) {
229
if (VALUE_ISA_INT(v)) return v;
230
231
// handle conversion for basic classes
232
if (VALUE_ISA_FLOAT(v)) return VALUE_FROM_INT((gravity_int_t)v.f);
233
if (VALUE_ISA_BOOL(v)) return VALUE_FROM_INT(v.n);
234
if (VALUE_ISA_NULL(v)) return VALUE_FROM_INT(0);
235
if (VALUE_ISA_UNDEFINED(v)) return VALUE_FROM_INT(0);
236
if (VALUE_ISA_STRING(v)) {return convert_string2number(VALUE_AS_STRING(v), false);}
237
238
// check if class implements the Int method
239
gravity_closure_t *closure = gravity_vm_fastlookup(vm, gravity_value_getclass(v), GRAVITY_INT_INDEX);
240
241
// sanity check (and break recursion)
242
if ((!closure) || ((closure->f->tag == EXEC_TYPE_INTERNAL) && (closure->f->internal == convert_object_int))) return VALUE_FROM_ERROR(NULL);
243
244
// execute closure and return its value
245
if (gravity_vm_runclosure(vm, closure, v, NULL, 0)) return gravity_vm_result(vm);
246
247
return VALUE_FROM_ERROR(NULL);
248
}
249
250
inline gravity_value_t convert_value2float (gravity_vm *vm, gravity_value_t v) {
251
if (VALUE_ISA_FLOAT(v)) return v;
252
253
// handle conversion for basic classes
254
if (VALUE_ISA_INT(v)) return VALUE_FROM_FLOAT((gravity_float_t)v.n);
255
if (VALUE_ISA_BOOL(v)) return VALUE_FROM_FLOAT(v.n);
256
if (VALUE_ISA_NULL(v)) return VALUE_FROM_FLOAT(0);
257
if (VALUE_ISA_UNDEFINED(v)) return VALUE_FROM_FLOAT(0);
258
if (VALUE_ISA_STRING(v)) {return convert_string2number(VALUE_AS_STRING(v), true);}
259
260
// check if class implements the Float method
261
gravity_closure_t *closure = gravity_vm_fastlookup(vm, gravity_value_getclass(v), GRAVITY_FLOAT_INDEX);
262
263
// sanity check (and break recursion)
264
if ((!closure) || ((closure->f->tag == EXEC_TYPE_INTERNAL) && (closure->f->internal == convert_object_float))) return VALUE_FROM_ERROR(NULL);
265
266
// execute closure and return its value
267
if (gravity_vm_runclosure(vm, closure, v, NULL, 0)) return gravity_vm_result(vm);
268
269
return VALUE_FROM_ERROR(NULL);
270
}
271
272
inline gravity_value_t convert_value2bool (gravity_vm *vm, gravity_value_t v) {
273
if (VALUE_ISA_BOOL(v)) return v;
274
275
// handle conversion for basic classes
276
if (VALUE_ISA_INT(v)) return VALUE_FROM_BOOL(v.n != 0);
277
if (VALUE_ISA_FLOAT(v)) return VALUE_FROM_BOOL(v.f != 0.0);
278
if (VALUE_ISA_NULL(v)) return VALUE_FROM_FALSE;
279
if (VALUE_ISA_UNDEFINED(v)) return VALUE_FROM_FALSE;
280
if (VALUE_ISA_STRING(v)) {
281
gravity_string_t *string = VALUE_AS_STRING(v);
282
if (string->len == 0) return VALUE_FROM_FALSE;
283
return VALUE_FROM_BOOL((strcmp(string->s, "false") != 0));
284
}
285
286
// check if class implements the Bool method
287
gravity_closure_t *closure = gravity_vm_fastlookup(vm, gravity_value_getclass(v), GRAVITY_BOOL_INDEX);
288
289
// sanity check (and break recursion)
290
if ((!closure) || ((closure->f->tag == EXEC_TYPE_INTERNAL) && (closure->f->internal == convert_object_bool))) return VALUE_FROM_BOOL(1);
291
292
// execute closure and return its value
293
if (gravity_vm_runclosure(vm, closure, v, NULL, 0)) return gravity_vm_result(vm);
294
295
return VALUE_FROM_ERROR(NULL);
296
}
297
298
inline gravity_value_t convert_value2string (gravity_vm *vm, gravity_value_t v) {
299
if (VALUE_ISA_STRING(v)) return v;
300
301
// handle conversion for basic classes
302
if (VALUE_ISA_INT(v)) {
303
char buffer[512];
304
#if GRAVITY_ENABLE_INT64
305
snprintf(buffer, sizeof(buffer), "%lld", v.n);
306
#else
307
snprintf(buffer, sizeof(buffer), "%d", v.n);
308
#endif
309
return VALUE_FROM_CSTRING(vm, buffer);
310
311
}
312
if (VALUE_ISA_BOOL(v)) return VALUE_FROM_CSTRING(vm, (v.n) ? "true" : "false");
313
if (VALUE_ISA_NULL(v)) return VALUE_FROM_CSTRING(vm, "null");
314
if (VALUE_ISA_UNDEFINED(v)) return VALUE_FROM_CSTRING(vm, "undefined");
315
if (VALUE_ISA_FLOAT(v)) {
316
char buffer[512];
317
snprintf(buffer, sizeof(buffer), "%f", v.f);
318
return VALUE_FROM_CSTRING(vm, buffer);
319
}
320
321
if (VALUE_ISA_CLASS(v)) {
322
const char *identifier = (VALUE_AS_CLASS(v)->identifier);
323
if (!identifier) identifier = "anonymous class";
324
return VALUE_FROM_CSTRING(vm, identifier);
325
}
326
327
if (VALUE_ISA_FUNCTION(v)) {
328
const char *identifier = (VALUE_AS_FUNCTION(v)->identifier);
329
if (!identifier) identifier = "anonymous func";
330
return VALUE_FROM_CSTRING(vm, identifier);
331
}
332
333
if (VALUE_ISA_CLOSURE(v)) {
334
const char *identifier = (VALUE_AS_CLOSURE(v)->f->identifier);
335
if (!identifier) identifier = "anonymous func";
336
return VALUE_FROM_CSTRING(vm, identifier);
337
}
338
339
if (VALUE_ISA_LIST(v)) {
340
gravity_list_t *list = VALUE_AS_LIST(v);
341
return convert_list2string(vm, list);
342
}
343
344
if (VALUE_ISA_MAP(v)) {
345
gravity_map_t *map = VALUE_AS_MAP(v);
346
return convert_map2string(vm, map);
347
}
348
349
// check if class implements the String method (avoiding infinte loop by checking for convert_object_string)
350
gravity_closure_t *closure = gravity_vm_fastlookup(vm, gravity_value_getclass(v), GRAVITY_STRING_INDEX);
351
352
// sanity check (and break recursion)
353
if ((!closure) || ((closure->f->tag == EXEC_TYPE_INTERNAL) && (closure->f->internal == convert_object_string))) return VALUE_FROM_ERROR(NULL);
354
355
// execute closure and return its value
356
if (gravity_vm_runclosure(vm, closure, v, NULL, 0)) return gravity_vm_result(vm);
357
358
return VALUE_FROM_ERROR(NULL);
359
}
360
361
// MARK: - Object Class -
362
363
static bool object_class (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
364
#pragma unused(vm, nargs)
365
gravity_class_t *c = gravity_value_getclass(GET_VALUE(0));
366
RETURN_VALUE(VALUE_FROM_OBJECT(c), rindex);
367
}
368
369
static bool object_internal_size (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
370
#pragma unused(vm, nargs)
371
gravity_int_t size = gravity_value_size(vm, GET_VALUE(0));
372
if (size == 0) size = sizeof(gravity_value_t);
373
RETURN_VALUE(VALUE_FROM_INT(size), rindex);
374
}
375
376
static bool object_isa (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
377
#pragma unused(vm, nargs)
378
379
gravity_class_t *c1 = gravity_value_getclass(GET_VALUE(0));
380
gravity_class_t *c2 = VALUE_AS_CLASS(GET_VALUE(1));
381
382
while (c1 != c2 && c1->superclass != NULL) {
383
c1 = c1->superclass;
384
}
385
386
RETURN_VALUE(VALUE_FROM_BOOL(c1 == c2), rindex);
387
}
388
389
390
static bool object_cmp (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
391
#pragma unused(vm, nargs)
392
if (gravity_value_equals(GET_VALUE(0), GET_VALUE(1))) RETURN_VALUE(VALUE_FROM_INT(0), rindex);
393
RETURN_VALUE(VALUE_FROM_INT(1), rindex);
394
}
395
396
static bool object_not (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
397
#pragma unused(vm, nargs)
398
// !obj
399
// if obj is NULL then result is true
400
// everything else must be false
401
RETURN_VALUE(VALUE_FROM_BOOL(VALUE_ISA_NULLCLASS(GET_VALUE(0))), rindex);
402
}
403
404
static bool object_real_load (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex, bool is_super) {
405
#pragma unused(vm, nargs)
406
407
// if there is a possibility that gravity_vm_runclosure is called then it is MANDATORY to save arguments before the call
408
gravity_value_t target = GET_VALUE(0);
409
gravity_value_t key = GET_VALUE(1);
410
411
// check if meta class needs to be initialized (it means if it contains valued static ivars)
412
// meta classes must be inited somewhere, this problem does not exist with instances since object creation itself trigger a class init
413
if (VALUE_ISA_CLASS(target)) {
414
gravity_class_t *c = VALUE_AS_CLASS(target);
415
gravity_class_t *meta = gravity_class_get_meta(c);
416
if (!meta->is_inited) {
417
meta->is_inited = true;
418
gravity_closure_t *closure = gravity_class_lookup_constructor(meta, 0);
419
if (closure) gravity_vm_runclosure(vm, closure, VALUE_FROM_OBJECT(meta), NULL, 0);
420
}
421
}
422
423
// retrieve class and process key
424
gravity_class_t *c = (is_super) ? VALUE_AS_CLASS(target) : gravity_value_getclass(target);
425
gravity_instance_t *instance = VALUE_ISA_INSTANCE(target) ? VALUE_AS_INSTANCE(target) : NULL;
426
427
// key is an int its an optimization for faster loading of ivar
428
if (VALUE_ISA_INT(key)) {
429
if (instance) RETURN_VALUE(instance->ivars[key.n], rindex); // instance case
430
RETURN_VALUE(c->ivars[key.n], rindex); // class case
431
}
432
433
// key must be a string in this version
434
if (!VALUE_ISA_STRING(key)) {
435
RETURN_ERROR("Unable to lookup non string value into class %s", c->identifier);
436
}
437
438
// lookup key in class c
439
gravity_object_t *obj = (gravity_object_t *)gravity_class_lookup(c, key);
440
gravity_closure_t *closure;
441
if (OBJECT_ISA_CLOSURE(obj)) {
442
closure = (gravity_closure_t *)obj;
443
if (!closure || !closure->f) {
444
// not explicitly declared so check for dynamic property in bridge case
445
gravity_delegate_t *delegate = gravity_vm_delegate(vm);
446
if ((instance) && (instance->xdata) && (delegate) && (delegate->bridge_getundef)) {
447
if (delegate->bridge_getundef(vm, instance->xdata, target, VALUE_AS_CSTRING(key), rindex)) return true;
448
}
449
goto execute_notfound;
450
}
451
452
// execute optimized default getter
453
if (FUNCTION_ISA_SPECIAL(closure->f)) {
454
if (FUNCTION_ISA_DEFAULT_GETTER(closure->f)) {
455
if (instance) RETURN_VALUE(instance->ivars[closure->f->index], rindex);
456
RETURN_VALUE(c->ivars[closure->f->index], rindex);
457
}
458
459
if (FUNCTION_ISA_GETTER(closure->f)) {
460
// returns a function to be executed using the return false trick
461
RETURN_CLOSURE(VALUE_FROM_OBJECT((gravity_closure_t *)closure->f->special[EXEC_TYPE_SPECIAL_GETTER]), rindex);
462
}
463
goto execute_notfound;
464
}
465
}
466
467
RETURN_VALUE(VALUE_FROM_OBJECT(obj), rindex);
468
469
execute_notfound:
470
// in case of not found error return the notfound function to be executed (MANDATORY)
471
closure = (gravity_closure_t *)gravity_class_lookup(c, gravity_vm_keyindex(vm, GRAVITY_NOTFOUND_INDEX));
472
RETURN_CLOSURE(VALUE_FROM_OBJECT(closure), rindex);
473
}
474
475
static bool object_loads (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
476
return object_real_load(vm, args, nargs, rindex, true);
477
}
478
479
static bool object_load (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
480
return object_real_load(vm, args, nargs, rindex, false);
481
}
482
483
static bool object_store (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
484
#pragma unused(vm, nargs, rindex)
485
486
// if there is a possibility that gravity_vm_runfunc is called then it is MANDATORY to save arguments before the call
487
gravity_value_t target = GET_VALUE(0);
488
gravity_value_t key = GET_VALUE(1);
489
gravity_value_t value = GET_VALUE(2);
490
491
// check if meta class needs to be initialized (it means if it contains valued static ivars)
492
// meta classes must be inited somewhere, this problem does not exist with classes since object creation itself trigger a class init
493
if (VALUE_ISA_CLASS(target)) {
494
gravity_class_t *c = VALUE_AS_CLASS(target);
495
gravity_class_t *meta = gravity_class_get_meta(c);
496
if (!meta->is_inited) {
497
meta->is_inited = true;
498
gravity_closure_t *closure = gravity_class_lookup_constructor(meta, 0);
499
if (closure) gravity_vm_runclosure(vm, closure, VALUE_FROM_OBJECT(meta), NULL, 0);
500
}
501
}
502
503
// retrieve class and process key
504
gravity_class_t *c = gravity_value_getclass(target);
505
gravity_instance_t *instance = VALUE_ISA_INSTANCE(target) ? VALUE_AS_INSTANCE(target) : NULL;
506
507
// key is an int its an optimization for faster loading of ivar
508
if (VALUE_ISA_INT(key)) {
509
if (instance) instance->ivars[key.n] = value;
510
else c->ivars[key.n] = value;
511
RETURN_NOVALUE();
512
}
513
514
// key must be a string in this version
515
if (!VALUE_ISA_STRING(key)) {
516
RETURN_ERROR("Unable to lookup non string value into class %s", c->identifier);
517
}
518
519
// lookup key in class c
520
gravity_object_t *obj = gravity_class_lookup(c, key);
521
if (!obj) goto execute_notfound;
522
523
gravity_closure_t *closure;
524
if (OBJECT_ISA_CLOSURE(obj)) {
525
closure = (gravity_closure_t *)obj;
526
if (!closure || !closure->f) {
527
// not explicitly declared so check for dynamic property in bridge case
528
gravity_delegate_t *delegate = gravity_vm_delegate(vm);
529
if ((instance) && (instance->xdata) && (delegate) && (delegate->bridge_setundef)) {
530
if (delegate->bridge_setundef(vm, instance->xdata, target, VALUE_AS_CSTRING(key), value)) RETURN_NOVALUE();
531
}
532
goto execute_notfound;
533
}
534
535
// check for special functions case
536
if (FUNCTION_ISA_SPECIAL(closure->f)) {
537
// execute optimized default setter
538
if (FUNCTION_ISA_DEFAULT_SETTER(closure->f)) {
539
if (instance) instance->ivars[closure->f->index] = value;
540
else c->ivars[closure->f->index] = value;
541
RETURN_NOVALUE();
542
}
543
544
if (FUNCTION_ISA_SETTER(closure->f)) {
545
// returns a function to be executed using the return false trick
546
RETURN_CLOSURE(VALUE_FROM_OBJECT((gravity_closure_t *)closure->f->special[EXEC_TYPE_SPECIAL_SETTER]), rindex);
547
}
548
goto execute_notfound;
549
}
550
}
551
552
RETURN_NOVALUE();
553
554
execute_notfound:
555
// in case of not found error return the notfound function to be executed (MANDATORY)
556
closure = (gravity_closure_t *)gravity_class_lookup(c, gravity_vm_keyindex(vm, GRAVITY_NOTFOUND_INDEX));
557
RETURN_CLOSURE(VALUE_FROM_OBJECT(closure), rindex);
558
}
559
560
static bool object_notfound (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
561
#pragma unused(nargs,rindex)
562
gravity_class_t *c = gravity_value_getclass(GET_VALUE(0));
563
gravity_value_t key = GET_VALUE(1); // vm_getslot(vm, rindex);
564
RETURN_ERROR("Unable to find %s into class %s", VALUE_AS_CSTRING(key), c->identifier);
565
}
566
567
static bool object_bind (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
568
#pragma unused(rindex)
569
570
// sanity check first
571
if (nargs < 3) RETURN_ERROR("Incorrect number of arguments.");
572
if (!VALUE_ISA_STRING(GET_VALUE(1))) RETURN_ERROR("First argument must be a String.");
573
if (!VALUE_ISA_CLOSURE(GET_VALUE(2))) RETURN_ERROR("Second argument must be a Closure.");
574
575
gravity_object_t *object = NULL;
576
if (VALUE_ISA_INSTANCE(GET_VALUE(0))) {
577
object = VALUE_AS_OBJECT(GET_VALUE(0));
578
} else if (VALUE_ISA_CLASS(GET_VALUE(0))) {
579
object = VALUE_AS_OBJECT(GET_VALUE(0));
580
} else {
581
RETURN_ERROR("bind method can be applied only to instances or classes.");
582
}
583
584
gravity_string_t *key = VALUE_AS_STRING(GET_VALUE(1));
585
gravity_class_t *c = gravity_value_getclass(GET_VALUE(0));
586
587
// check if instance has already an anonymous class added to its hierarchy
588
if (string_nocasencmp(c->identifier, GRAVITY_VM_ANONYMOUS_PREFIX, strlen(GRAVITY_VM_ANONYMOUS_PREFIX) != 0)) {
589
// no super anonymous class found so create a new one, set its super as c, and add it to the hierarchy
590
char *name = gravity_vm_anonymous(vm);
591
gravity_class_t *anon = gravity_class_new_pair(NULL, name, c, 0, 0);
592
object->objclass = anon;
593
c = anon;
594
595
// store anonymous class (and its meta) into VM special GC stack
596
// manually retains anonymous class that will retain its bound functions
597
gravity_gc_push(vm, (gravity_object_t *)anon);
598
gravity_gc_push(vm, (gravity_object_t *)gravity_class_get_meta(anon));
599
}
600
601
// add closure to anonymous class
602
gravity_class_bind(c, key->s, GET_VALUE(2));
603
RETURN_NOVALUE();
604
}
605
606
static bool object_unbind (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
607
#pragma unused(rindex)
608
609
// sanity check first
610
if (nargs < 2) RETURN_ERROR("Incorrect number of arguments.");
611
if (!VALUE_ISA_STRING(GET_VALUE(1))) RETURN_ERROR("Argument must be a String.");
612
613
// remove key/value from hash table
614
gravity_class_t *c = gravity_value_getclass(GET_VALUE(0));
615
gravity_hash_remove(c->htable, GET_VALUE(1));
616
617
RETURN_NOVALUE();
618
}
619
620
// MARK: - List Class -
621
622
static bool list_count (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
623
#pragma unused(vm, nargs)
624
gravity_list_t *list = VALUE_AS_LIST(GET_VALUE(0));
625
RETURN_VALUE(VALUE_FROM_INT(marray_size(list->array)), rindex);
626
}
627
628
static bool list_loadat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
629
#pragma unused(vm, nargs)
630
gravity_list_t *list = VALUE_AS_LIST(GET_VALUE(0));
631
gravity_value_t value = GET_VALUE(1);
632
if (!VALUE_ISA_INT(value)) RETURN_ERROR("An integer index is required to access a list item.");
633
634
register int32_t index = (int32_t)VALUE_AS_INT(value);
635
register uint32_t count = (uint32_t)marray_size(list->array);
636
637
if (index < 0) index = count + index;
638
if ((index < 0) || (index >= count)) RETURN_ERROR("Out of bounds error: index %d beyond bounds 0...%d", index, count-1);
639
640
RETURN_VALUE(marray_get(list->array, index), rindex);
641
}
642
643
static bool list_storeat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
644
#pragma unused(vm, nargs, rindex)
645
gravity_list_t *list = VALUE_AS_LIST(GET_VALUE(0));
646
gravity_value_t idxvalue = GET_VALUE(1);
647
gravity_value_t value = GET_VALUE(2);
648
if (!VALUE_ISA_INT(idxvalue)) RETURN_ERROR("An integer index is required to access a list item.");
649
650
register int32_t index = (int32_t)VALUE_AS_INT(idxvalue);
651
register uint32_t count = (uint32_t)marray_size(list->array);
652
653
if (index < 0) index = count + index;
654
if (index < 0) RETURN_ERROR("Out of bounds error: index %d beyond bounds 0...%d", index, count-1);
655
if (index > count) {
656
// handle list resizing here
657
marray_resize(gravity_value_t, list->array, index-count);
658
marray_nset(list->array, index+1);
659
for (size_t i=count; i<index; ++i) {
660
marray_set(list->array, i, VALUE_FROM_NULL);
661
}
662
marray_set(list->array, index, value);
663
}
664
665
marray_set(list->array, index, value);
666
RETURN_NOVALUE();
667
}
668
669
static bool list_push (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
670
#pragma unused(nargs)
671
gravity_list_t *list = VALUE_AS_LIST(GET_VALUE(0));
672
gravity_value_t value = GET_VALUE(1);
673
marray_push(gravity_value_t, list->array, value);
674
RETURN_VALUE(VALUE_FROM_INT(marray_size(list->array)), rindex);
675
}
676
677
static bool list_pop (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
678
#pragma unused(nargs)
679
gravity_list_t *list = VALUE_AS_LIST(GET_VALUE(0));
680
size_t count = marray_size(list->array);
681
if (count < 1) RETURN_ERROR("Unable to pop a value from an empty list.");
682
gravity_value_t value = marray_pop(list->array);
683
RETURN_VALUE(value, rindex);
684
}
685
686
static bool list_iterator (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
687
#pragma unused(vm, nargs)
688
gravity_list_t *list = VALUE_AS_LIST(GET_VALUE(0));
689
690
// check for empty list first
691
register uint32_t count = (uint32_t)marray_size(list->array);
692
if (count == 0) RETURN_VALUE(VALUE_FROM_FALSE, rindex);
693
694
// check for start of iteration
695
if (VALUE_ISA_NULL(GET_VALUE(1))) RETURN_VALUE(VALUE_FROM_INT(0), rindex);
696
697
// extract value
698
gravity_value_t value = GET_VALUE(1);
699
700
// check error condition
701
if (!VALUE_ISA_INT(value)) RETURN_ERROR("Iterator expects a numeric value here.");
702
703
// compute new value
704
gravity_int_t n = value.n;
705
if (n+1 < count) {
706
++n;
707
} else {
708
RETURN_VALUE(VALUE_FROM_FALSE, rindex);
709
}
710
711
// return new iterator
712
RETURN_VALUE(VALUE_FROM_INT(n), rindex);
713
}
714
715
static bool list_iterator_next (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
716
#pragma unused(vm, nargs)
717
gravity_list_t *list = VALUE_AS_LIST(GET_VALUE(0));
718
register int32_t index = (int32_t)VALUE_AS_INT(GET_VALUE(1));
719
RETURN_VALUE(marray_get(list->array, index), rindex);
720
}
721
722
static bool list_loop (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
723
if (nargs < 2) RETURN_ERROR("Incorrect number of arguments.");
724
if (!VALUE_ISA_CLOSURE(GET_VALUE(1))) RETURN_ERROR("Argument must be a Closure.");
725
726
gravity_closure_t *closure = VALUE_AS_CLOSURE(GET_VALUE(1)); // closure to execute
727
gravity_value_t value = GET_VALUE(0); // self parameter
728
gravity_list_t *list = VALUE_AS_LIST(value);
729
register gravity_int_t n = marray_size(list->array); // times to execute the loop
730
register gravity_int_t i = 0;
731
732
nanotime_t t1 = nanotime();
733
while (i < n) {
734
gravity_vm_runclosure(vm, closure, value, &marray_get(list->array, i), 1);
735
++i;
736
}
737
nanotime_t t2 = nanotime();
738
RETURN_VALUE(VALUE_FROM_INT(t2-t1), rindex);
739
}
740
741
// MARK: - Map Class -
742
743
static bool map_count (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
744
#pragma unused(vm, nargs)
745
gravity_map_t *map = VALUE_AS_MAP(GET_VALUE(0));
746
RETURN_VALUE(VALUE_FROM_INT(gravity_hash_count(map->hash)), rindex);
747
}
748
749
static void map_keys_array (gravity_hash_t *hashtable, gravity_value_t key, gravity_value_t value, void *data) {
750
#pragma unused (hashtable, value)
751
gravity_list_t *list = (gravity_list_t *)data;
752
marray_push(gravity_value_t, list->array, key);
753
}
754
755
static bool map_keys (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
756
#pragma unused(vm, nargs)
757
gravity_map_t *map = VALUE_AS_MAP(GET_VALUE(0));
758
uint32_t count = gravity_hash_count(map->hash);
759
760
gravity_list_t *list = gravity_list_new(vm, count);
761
gravity_hash_iterate(map->hash, map_keys_array, (void *)list);
762
RETURN_VALUE(VALUE_FROM_OBJECT(list), rindex);
763
}
764
765
static bool map_loadat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
766
#pragma unused(vm, nargs)
767
gravity_map_t *map = VALUE_AS_MAP(GET_VALUE(0));
768
gravity_value_t key = GET_VALUE(1);
769
770
gravity_value_t *value = gravity_hash_lookup(map->hash, key);
771
RETURN_VALUE((value) ? *value : VALUE_FROM_NULL, rindex);
772
}
773
774
static bool map_storeat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
775
#pragma unused(vm, nargs, rindex)
776
gravity_map_t *map = VALUE_AS_MAP(GET_VALUE(0));
777
gravity_value_t key = GET_VALUE(1);
778
gravity_value_t value = GET_VALUE(2);
779
780
gravity_hash_insert(map->hash, key, value);
781
RETURN_NOVALUE();
782
}
783
784
static bool map_remove (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
785
#pragma unused(vm, nargs)
786
gravity_map_t *map = VALUE_AS_MAP(GET_VALUE(0));
787
gravity_value_t key = GET_VALUE(1);
788
789
bool existed = gravity_hash_remove(map->hash, key);
790
RETURN_VALUE(VALUE_FROM_BOOL(existed), rindex);
791
}
792
793
static bool map_loop (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
794
if (nargs < 2) RETURN_ERROR("Incorrect number of arguments.");
795
if (!VALUE_ISA_CLOSURE(GET_VALUE(1))) RETURN_ERROR("Argument must be a Closure.");
796
797
gravity_closure_t *closure = VALUE_AS_CLOSURE(GET_VALUE(1)); // closure to execute
798
gravity_value_t value = GET_VALUE(0); // self parameter
799
gravity_map_t *map = VALUE_AS_MAP(GET_VALUE(0));
800
register gravity_int_t n = gravity_hash_count(map->hash); // times to execute the loop
801
register gravity_int_t i = 0;
802
803
// build keys array
804
gravity_list_t *list = gravity_list_new(vm, (uint32_t)n);
805
gravity_hash_iterate(map->hash, map_keys_array, (void *)list);
806
807
nanotime_t t1 = nanotime();
808
while (i < n) {
809
gravity_vm_runclosure(vm, closure, value, &marray_get(list->array, i), 1);
810
++i;
811
}
812
nanotime_t t2 = nanotime();
813
RETURN_VALUE(VALUE_FROM_INT(t2-t1), rindex);
814
}
815
816
// MARK: - Range Class -
817
818
static bool range_count (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
819
#pragma unused(vm, nargs)
820
gravity_range_t *range = VALUE_AS_RANGE(GET_VALUE(0));
821
gravity_int_t count = (range->to > range->from) ? (range->to - range->from) : (range->from - range->to);
822
RETURN_VALUE(VALUE_FROM_INT(count+1), rindex);
823
}
824
825
static bool range_loop (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
826
if (nargs < 2) RETURN_ERROR("Incorrect number of arguments.");
827
if (!VALUE_ISA_CLOSURE(GET_VALUE(1))) RETURN_ERROR("Argument must be a Closure.");
828
829
gravity_closure_t *closure = VALUE_AS_CLOSURE(GET_VALUE(1)); // closure to execute
830
gravity_value_t value = GET_VALUE(0); // self parameter
831
gravity_range_t *range = VALUE_AS_RANGE(value);
832
bool is_forward = range->from < range->to;
833
834
nanotime_t t1 = nanotime();
835
if (is_forward) {
836
register gravity_int_t n = range->to;
837
register gravity_int_t i = range->from;
838
while (i <= n) {
839
gravity_vm_runclosure(vm, closure, value, &VALUE_FROM_INT(i), 1);
840
++i;
841
}
842
} else {
843
register gravity_int_t n = range->from; // 5...1
844
register gravity_int_t i = range->to;
845
while (n >= i) {
846
gravity_vm_runclosure(vm, closure, value, &VALUE_FROM_INT(n), 1);
847
--n;
848
}
849
}
850
nanotime_t t2 = nanotime();
851
RETURN_VALUE(VALUE_FROM_INT(t2-t1), rindex);
852
}
853
854
static bool range_iterator (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
855
#pragma unused(vm, nargs)
856
gravity_range_t *range = VALUE_AS_RANGE(GET_VALUE(0));
857
858
// check for empty range first
859
if (range->from == range->to) RETURN_VALUE(VALUE_FROM_FALSE, rindex);
860
861
// check for start of iteration
862
if (VALUE_ISA_NULL(GET_VALUE(1))) RETURN_VALUE(VALUE_FROM_INT(range->from), rindex);
863
864
// extract value
865
gravity_value_t value = GET_VALUE(1);
866
867
// check error condition
868
if (!VALUE_ISA_INT(value)) RETURN_ERROR("Iterator expects a numeric value here.");
869
870
// compute new value
871
gravity_int_t n = value.n;
872
if (range->from < range->to) {
873
++n;
874
if (n > range->to) RETURN_VALUE(VALUE_FROM_FALSE, rindex);
875
} else {
876
--n;
877
if (n < range->to) RETURN_VALUE(VALUE_FROM_FALSE, rindex);
878
}
879
880
// return new iterator
881
RETURN_VALUE(VALUE_FROM_INT(n), rindex);
882
}
883
884
static bool range_iterator_next (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
885
#pragma unused(vm, nargs)
886
RETURN_VALUE(GET_VALUE(1), rindex);
887
}
888
889
static bool range_contains (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
890
#pragma unused(vm, nargs)
891
gravity_range_t *range = VALUE_AS_RANGE(GET_VALUE(0));
892
gravity_value_t value = GET_VALUE(1);
893
894
// check error condition
895
if (!VALUE_ISA_INT(value)) RETURN_ERROR("A numeric value is expected.");
896
897
RETURN_VALUE(VALUE_FROM_BOOL((value.n >= range->from) && (value.n <= range->to)), rindex);
898
}
899
900
// MARK: - Class Class -
901
902
static bool class_name (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
903
#pragma unused(vm, nargs)
904
gravity_class_t *c = (GET_VALUE(0).p);
905
RETURN_VALUE(VALUE_FROM_CSTRING(vm, c->identifier), rindex);
906
}
907
908
static bool class_exec (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
909
// if 1st argument is not a class that means that this execution is part of a inner classes chained init
910
// so retrieve class from callable object (that I am sure it is the right class)
911
// this is more an hack than an elegation solution, I really hope to find out a better way
912
if (!VALUE_ISA_CLASS(GET_VALUE(0))) args[0] = *(args-1);
913
914
// retrieve class (with sanity check)
915
if (!VALUE_ISA_CLASS(GET_VALUE(0))) RETURN_ERROR("Unable to execute non class object.");
916
gravity_class_t *c = (gravity_class_t *)GET_VALUE(0).p;
917
918
// perform alloc (then check for init)
919
gravity_instance_t *instance = gravity_instance_new(vm, c);
920
921
// if is inner class then ivar 0 is reserved for a reference to its outer class
922
if (c->has_outer) gravity_instance_setivar(instance, 0, gravity_vm_getslot(vm, 0));
923
924
// check for constructor function (-1 because self implicit parameter does not count)
925
gravity_closure_t *closure = (gravity_closure_t *)gravity_class_lookup_constructor(c, nargs-1);
926
927
// replace first parameter (self) to newly allocated instance
928
args[0] = VALUE_FROM_OBJECT(instance);
929
930
// if constructor found in this class then executes it
931
if (closure) RETURN_CLOSURE(VALUE_FROM_OBJECT(closure), rindex);
932
933
// no closure found (means no constructor found in this class)
934
gravity_delegate_t *delegate = gravity_vm_delegate(vm);
935
if (c->xdata && delegate && delegate->bridge_initinstance) {
936
// even if no closure is found try to execute the default bridge init instance (if class is bridged)
937
if (nargs != 1) RETURN_ERROR("No init with %d parameters found in class %s", nargs-1, c->identifier);
938
delegate->bridge_initinstance(vm, c->xdata, instance, args, nargs);
939
}
940
941
// in any case set destination register to newly allocated instance
942
RETURN_VALUE(VALUE_FROM_OBJECT(instance), rindex);
943
}
944
945
// MARK: - Float Class -
946
947
static bool operator_float_add (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
948
#pragma unused(vm, nargs)
949
950
DECLARE_2VARIABLES(v1, v2, 0, 1);
951
INTERNAL_CONVERT_FLOAT(v1);
952
INTERNAL_CONVERT_FLOAT(v2);
953
RETURN_VALUE(VALUE_FROM_FLOAT(v1.f + v2.f), rindex);
954
}
955
956
static bool operator_float_sub (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
957
#pragma unused(vm, nargs)
958
959
DECLARE_2VARIABLES(v1, v2, 0, 1);
960
INTERNAL_CONVERT_FLOAT(v1);
961
INTERNAL_CONVERT_FLOAT(v2);
962
RETURN_VALUE(VALUE_FROM_FLOAT(v1.f - v2.f), rindex);
963
}
964
965
static bool operator_float_div (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
966
#pragma unused(vm, nargs)
967
968
DECLARE_2VARIABLES(v1, v2, 0, 1);
969
INTERNAL_CONVERT_FLOAT(v1);
970
INTERNAL_CONVERT_FLOAT(v2);
971
972
if (v2.f == 0.0) RETURN_ERROR("Division by 0 error.");
973
RETURN_VALUE(VALUE_FROM_FLOAT(v1.f / v2.f), rindex);
974
}
975
976
static bool operator_float_mul (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
977
#pragma unused(vm, nargs)
978
979
DECLARE_2VARIABLES(v1, v2, 0, 1);
980
INTERNAL_CONVERT_FLOAT(v1);
981
INTERNAL_CONVERT_FLOAT(v2);
982
RETURN_VALUE(VALUE_FROM_FLOAT(v1.f * v2.f), rindex);
983
}
984
985
static bool operator_float_rem (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
986
#pragma unused(vm, nargs)
987
988
DECLARE_2VARIABLES(v1, v2, 0, 1);
989
INTERNAL_CONVERT_FLOAT(v1);
990
INTERNAL_CONVERT_FLOAT(v2);
991
992
// compute floating point modulus
993
#if GRAVITY_ENABLE_DOUBLE
994
RETURN_VALUE(VALUE_FROM_FLOAT(remainder(v1.f, v2.f)), rindex);
995
#else
996
RETURN_VALUE(VALUE_FROM_FLOAT(remainderf(v1.f, v2.f)), rindex);
997
#endif
998
}
999
1000
static bool operator_float_and (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1001
#pragma unused(vm, nargs)
1002
1003
DECLARE_2VARIABLES(v1, v2, 0, 1);
1004
INTERNAL_CONVERT_BOOL(v1);
1005
INTERNAL_CONVERT_BOOL(v2);
1006
RETURN_VALUE(VALUE_FROM_BOOL(v1.n && v2.n), rindex);
1007
}
1008
1009
static bool operator_float_or (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1010
#pragma unused(vm, nargs)
1011
1012
DECLARE_2VARIABLES(v1, v2, 0, 1);
1013
INTERNAL_CONVERT_BOOL(v1);
1014
INTERNAL_CONVERT_BOOL(v2);
1015
RETURN_VALUE(VALUE_FROM_BOOL(v1.n || v2.n), rindex);
1016
}
1017
1018
static bool operator_float_neg (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1019
#pragma unused(vm, nargs)
1020
RETURN_VALUE(VALUE_FROM_FLOAT(-GET_VALUE(0).f), rindex);
1021
}
1022
1023
static bool operator_float_not (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1024
#pragma unused(vm, nargs)
1025
RETURN_VALUE(VALUE_FROM_BOOL(!GET_VALUE(0).f), rindex);
1026
}
1027
1028
static bool operator_float_cmp (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1029
#pragma unused(vm, nargs)
1030
1031
DECLARE_2VARIABLES(v1, v2, 0, 1);
1032
INTERNAL_CONVERT_FLOAT(v2);
1033
if (v1.f == v2.f) RETURN_VALUE(VALUE_FROM_INT(0), rindex);
1034
if (v1.f > v2.f) RETURN_VALUE(VALUE_FROM_INT(1), rindex);
1035
RETURN_VALUE(VALUE_FROM_INT(-1), rindex);
1036
}
1037
1038
static bool function_float_round (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1039
#pragma unused(vm, nargs)
1040
1041
#if GRAVITY_ENABLE_DOUBLE
1042
RETURN_VALUE(VALUE_FROM_FLOAT(round(GET_VALUE(0).f)), rindex);
1043
#else
1044
RETURN_VALUE(VALUE_FROM_FLOAT(roundf(GET_VALUE(0).f)), rindex);
1045
#endif
1046
}
1047
1048
static bool function_float_floor (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1049
#pragma unused(vm, nargs)
1050
1051
#if GRAVITY_ENABLE_DOUBLE
1052
RETURN_VALUE(VALUE_FROM_FLOAT(floor(GET_VALUE(0).f)), rindex);
1053
#else
1054
RETURN_VALUE(VALUE_FROM_FLOAT(floorf(GET_VALUE(0).f)), rindex);
1055
#endif
1056
}
1057
1058
static bool function_float_ceil (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1059
#pragma unused(vm, nargs)
1060
1061
#if GRAVITY_ENABLE_DOUBLE
1062
RETURN_VALUE(VALUE_FROM_FLOAT(ceil(GET_VALUE(0).f)), rindex);
1063
#else
1064
RETURN_VALUE(VALUE_FROM_FLOAT(ceilf(GET_VALUE(0).f)), rindex);
1065
#endif
1066
}
1067
1068
// MARK: - Int Class -
1069
1070
// binary operators
1071
static bool operator_int_add (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1072
#pragma unused (nargs)
1073
DECLARE_2VARIABLES(v1, v2, 0, 1);
1074
INTERNAL_CONVERT_INT(v2);
1075
RETURN_VALUE(VALUE_FROM_INT(v1.n + v2.n), rindex);
1076
}
1077
1078
static bool operator_int_sub (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1079
#pragma unused (nargs)
1080
DECLARE_2VARIABLES(v1, v2, 0, 1);
1081
INTERNAL_CONVERT_INT(v2);
1082
RETURN_VALUE(VALUE_FROM_INT(v1.n - v2.n), rindex);
1083
}
1084
1085
static bool operator_int_div (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1086
#pragma unused (nargs)
1087
DECLARE_2VARIABLES(v1, v2, 0, 1);
1088
INTERNAL_CONVERT_INT(v2);
1089
1090
if (v2.n == 0) RETURN_ERROR("Division by 0 error.");
1091
RETURN_VALUE(VALUE_FROM_INT(v1.n / v2.n), rindex);
1092
}
1093
1094
static bool operator_int_mul (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1095
#pragma unused (nargs)
1096
DECLARE_2VARIABLES(v1, v2, 0, 1);
1097
INTERNAL_CONVERT_INT(v2);
1098
RETURN_VALUE(VALUE_FROM_INT(v1.n * v2.n), rindex);
1099
}
1100
1101
static bool operator_int_rem (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1102
#pragma unused (nargs)
1103
DECLARE_2VARIABLES(v1, v2, 0, 1);
1104
INTERNAL_CONVERT_INT(v2);
1105
RETURN_VALUE(VALUE_FROM_INT(v1.n % v2.n), rindex);
1106
}
1107
1108
static bool operator_int_and (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1109
#pragma unused (nargs)
1110
DECLARE_2VARIABLES(v1, v2, 0, 1);
1111
INTERNAL_CONVERT_BOOL(v1);
1112
INTERNAL_CONVERT_BOOL(v2);
1113
RETURN_VALUE(VALUE_FROM_BOOL(v1.n && v2.n), rindex);
1114
}
1115
1116
static bool operator_int_or (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1117
#pragma unused (nargs)
1118
DECLARE_2VARIABLES(v1, v2, 0, 1);
1119
INTERNAL_CONVERT_BOOL(v1);
1120
INTERNAL_CONVERT_BOOL(v2);
1121
RETURN_VALUE(VALUE_FROM_BOOL(v1.n || v2.n), rindex);
1122
}
1123
1124
static bool operator_int_neg (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1125
#pragma unused(vm, nargs)
1126
RETURN_VALUE(VALUE_FROM_INT(-GET_VALUE(0).n), rindex);
1127
}
1128
1129
static bool operator_int_not (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1130
#pragma unused(vm, nargs)
1131
RETURN_VALUE(VALUE_FROM_BOOL(!GET_VALUE(0).n), rindex);
1132
}
1133
1134
static bool operator_int_cmp (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1135
if (VALUE_ISA_FLOAT(args[1])) return operator_float_cmp(vm, args, nargs, rindex);
1136
1137
DECLARE_2VARIABLES(v1, v2, 0, 1);
1138
INTERNAL_CONVERT_INT(v2);
1139
if (v1.n == v2.n) RETURN_VALUE(VALUE_FROM_INT(0), rindex);
1140
if (v1.n > v2.n) RETURN_VALUE(VALUE_FROM_INT(1), rindex);
1141
RETURN_VALUE(VALUE_FROM_INT(-1), rindex);
1142
}
1143
1144
static bool int_loop (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1145
if (nargs < 2) RETURN_ERROR("Incorrect number of arguments.");
1146
if (!VALUE_ISA_CLOSURE(GET_VALUE(1))) RETURN_ERROR("Argument must be a Closure.");
1147
1148
gravity_closure_t *closure = VALUE_AS_CLOSURE(GET_VALUE(1)); // closure to execute
1149
gravity_value_t value = GET_VALUE(0); // self parameter
1150
register gravity_int_t n = value.n; // times to execute the loop
1151
register gravity_int_t i = 0;
1152
1153
nanotime_t t1 = nanotime();
1154
while (i < n) {
1155
gravity_vm_runclosure(vm, closure, value, &VALUE_FROM_INT(i), 1);
1156
++i;
1157
}
1158
nanotime_t t2 = nanotime();
1159
RETURN_VALUE(VALUE_FROM_INT(t2-t1), rindex);
1160
}
1161
1162
// MARK: - Bool Class -
1163
1164
static bool operator_bool_add (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1165
return operator_int_add(vm, args, nargs, rindex);
1166
}
1167
1168
static bool operator_bool_sub (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1169
return operator_int_sub(vm, args, nargs, rindex);
1170
}
1171
1172
static bool operator_bool_div (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1173
return operator_int_div(vm, args, nargs, rindex);
1174
}
1175
1176
static bool operator_bool_mul (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1177
return operator_int_mul(vm, args, nargs, rindex);
1178
}
1179
1180
static bool operator_bool_rem (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1181
return operator_int_rem(vm, args, nargs, rindex);
1182
}
1183
1184
static bool operator_bool_and (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1185
#pragma unused(vm, nargs)
1186
1187
DECLARE_2VARIABLES(v1, v2, 0, 1);
1188
INTERNAL_CONVERT_BOOL(v1);
1189
RETURN_VALUE(VALUE_FROM_BOOL(v1.n && v2.n), rindex);
1190
}
1191
1192
static bool operator_bool_or (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1193
#pragma unused(vm, nargs)
1194
1195
DECLARE_2VARIABLES(v1, v2, 0, 1);
1196
INTERNAL_CONVERT_BOOL(v1);
1197
RETURN_VALUE(VALUE_FROM_BOOL(v1.n || v2.n), rindex);
1198
}
1199
1200
static bool operator_bool_cmp (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1201
return operator_int_cmp(vm, args, nargs, rindex);
1202
}
1203
1204
// unary operators
1205
static bool operator_bool_neg (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1206
#pragma unused(vm, nargs)
1207
RETURN_VALUE(VALUE_FROM_INT(-GET_VALUE(0).n), rindex);
1208
}
1209
1210
static bool operator_bool_not (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1211
#pragma unused(vm, nargs)
1212
RETURN_VALUE(VALUE_FROM_INT(!GET_VALUE(0).n), rindex);
1213
}
1214
1215
// MARK: - String Class -
1216
1217
static bool operator_string_add (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1218
#pragma unused(vm, nargs)
1219
1220
DECLARE_2VARIABLES(v1, v2, 0, 1);
1221
INTERNAL_CONVERT_STRING(v2);
1222
1223
gravity_string_t *s1 = VALUE_AS_STRING(v1);
1224
gravity_string_t *s2 = VALUE_AS_STRING(v2);
1225
1226
uint32_t len = s1->len + s2->len;
1227
char buffer[4096];
1228
char *s = NULL;
1229
1230
// check if I can save an allocation
1231
if (len+1<sizeof(buffer)) s = buffer;
1232
else s = mem_alloc(len+1);
1233
1234
memcpy(s, s1->s, s1->len);
1235
memcpy(s+s1->len, s2->s, s2->len);
1236
1237
gravity_value_t v = VALUE_FROM_STRING(vm, s, len);
1238
if (s != NULL && s != buffer) mem_free(s);
1239
1240
RETURN_VALUE(v, rindex);
1241
}
1242
1243
static bool operator_string_sub (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1244
#pragma unused(vm, nargs)
1245
1246
DECLARE_2VARIABLES(v1, v2, 0, 1);
1247
INTERNAL_CONVERT_STRING(v2);
1248
1249
gravity_string_t *s1 = VALUE_AS_STRING(v1);
1250
gravity_string_t *s2 = VALUE_AS_STRING(v2);
1251
1252
// subtract s2 from s1
1253
char *found = strstr(s1->s, s2->s);
1254
if (!found) RETURN_VALUE(VALUE_FROM_STRING(vm, s1->s, s1->len), rindex);
1255
1256
// substring found
1257
// now check if entire substring must be considered
1258
uint32_t flen = (uint32_t)strlen(found);
1259
if (flen == s2->len) RETURN_VALUE(VALUE_FROM_STRING(vm, s1->s, (uint32_t)(found - s1->s)), rindex);
1260
1261
// substring found but cannot be entirely considered
1262
uint32_t alloc = MAXNUM(s1->len + s2->len +1, DEFAULT_MINSTRING_SIZE);
1263
char *s = mem_alloc(alloc);
1264
1265
uint32_t seek = (uint32_t)(found - s1->s);
1266
uint32_t len = seek + (flen - s2->len);
1267
memcpy(s, s1->s, seek);
1268
memcpy(s+seek, found+s2->len, flen - s2->len);
1269
1270
gravity_string_t *string = gravity_string_new(vm, s, len, alloc);
1271
RETURN_VALUE(VALUE_FROM_OBJECT(string), rindex);
1272
}
1273
1274
static bool operator_string_and (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1275
#pragma unused(vm, nargs)
1276
1277
DECLARE_2VARIABLES(v1, v2, 0, 1);
1278
INTERNAL_CONVERT_BOOL(v1);
1279
INTERNAL_CONVERT_BOOL(v2);
1280
1281
RETURN_VALUE(VALUE_FROM_BOOL(v1.n && v2.n), rindex);
1282
}
1283
1284
static bool operator_string_or (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1285
#pragma unused(vm, nargs)
1286
1287
DECLARE_2VARIABLES(v1, v2, 0, 1);
1288
INTERNAL_CONVERT_BOOL(v1);
1289
INTERNAL_CONVERT_BOOL(v2);
1290
1291
RETURN_VALUE(VALUE_FROM_BOOL(v1.n || v2.n), rindex);
1292
}
1293
1294
static bool operator_string_neg (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1295
#pragma unused(vm, nargs)
1296
1297
DECLARE_1VARIABLE(v1, 0);
1298
1299
// reverse the string
1300
gravity_string_t *s1 = VALUE_AS_STRING(v1);
1301
char *s = (char *)string_dup(s1->s);
1302
utf8_reverse(s);
1303
1304
gravity_string_t *string = gravity_string_new(vm, s, s1->len, s1->len);
1305
RETURN_VALUE(VALUE_FROM_OBJECT(string), rindex);
1306
}
1307
1308
static bool string_length (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1309
#pragma unused(vm, nargs)
1310
1311
DECLARE_1VARIABLE(v1, 0);
1312
gravity_string_t *s1 = VALUE_AS_STRING(v1);
1313
1314
RETURN_VALUE(VALUE_FROM_INT(s1->len), rindex);
1315
}
1316
1317
static bool operator_string_cmp (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1318
#pragma unused(vm, nargs)
1319
1320
DECLARE_2VARIABLES(v1, v2, 0, 1);
1321
INTERNAL_CONVERT_STRING(v2);
1322
1323
gravity_string_t *s1 = VALUE_AS_STRING(v1);
1324
gravity_string_t *s2 = VALUE_AS_STRING(v2);
1325
1326
RETURN_VALUE(VALUE_FROM_INT(strcmp(s1->s, s2->s)), rindex);
1327
}
1328
1329
// MARK: - Fiber Class -
1330
1331
static bool fiber_create (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1332
#pragma unused(nargs)
1333
1334
if (!VALUE_ISA_CLOSURE(GET_VALUE(1))) RETURN_ERROR("A function is expected as argument to Fiber.create.");
1335
1336
gravity_fiber_t *fiber = gravity_fiber_new(vm, VALUE_AS_CLOSURE(GET_VALUE(1)), 0, 0);
1337
RETURN_VALUE(VALUE_FROM_OBJECT(fiber), rindex);
1338
}
1339
1340
static bool fiber_run (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex, bool is_trying) {
1341
#pragma unused(nargs, rindex)
1342
1343
gravity_fiber_t *fiber = VALUE_AS_FIBER(GET_VALUE(0));
1344
1345
if (fiber->caller != NULL) RETURN_ERROR("Fiber has already been called.");
1346
1347
// remember who ran the fiber
1348
fiber->caller = gravity_vm_fiber(vm);
1349
1350
// set trying flag
1351
fiber->trying = is_trying;
1352
1353
// switch currently running fiber
1354
gravity_vm_setfiber(vm, fiber);
1355
1356
RETURN_FIBER();
1357
}
1358
1359
static bool fiber_exec (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1360
return fiber_run(vm, args, nargs, rindex, false);
1361
}
1362
1363
static bool fiber_try (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1364
return fiber_run(vm, args, nargs, rindex, true);
1365
}
1366
1367
static bool fiber_yield (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1368
#pragma unused(args, nargs, rindex)
1369
1370
gravity_fiber_t *fiber = gravity_vm_fiber(vm);
1371
gravity_vm_setfiber(vm, fiber->caller);
1372
1373
// unhook this fiber from the one that called it
1374
fiber->caller = NULL;
1375
fiber->trying = false;
1376
1377
RETURN_FIBER();
1378
}
1379
1380
static bool fiber_status (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1381
#pragma unused(nargs)
1382
1383
gravity_fiber_t *fiber = VALUE_AS_FIBER(GET_VALUE(0));
1384
RETURN_VALUE(VALUE_FROM_BOOL(fiber->nframes == 0 || fiber->error), rindex);
1385
}
1386
1387
static bool fiber_abort (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1388
#pragma unused(rindex)
1389
1390
gravity_value_t msg = (nargs > 0) ? GET_VALUE(1) : VALUE_FROM_NULL;
1391
if (!VALUE_ISA_STRING(msg)) RETURN_ERROR("Fiber.abort expects a string as argument.");
1392
1393
gravity_string_t *s = VALUE_AS_STRING(msg);
1394
RETURN_ERROR("%.*s", s->len, s->s);
1395
}
1396
1397
// MARK: - Null Class -
1398
1399
static bool operator_null_add (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1400
#pragma unused(vm,nargs)
1401
// NULL + v2 = v2
1402
RETURN_VALUE(args[1], rindex);
1403
}
1404
1405
static bool operator_null_sub (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1406
// NULL - v2 should be computed as -v2 in my opinion (since NULL is interpreted as zero)
1407
args[0] = VALUE_FROM_INT(0);
1408
return operator_int_sub(vm, args, nargs, rindex);
1409
}
1410
1411
static bool operator_null_div (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1412
#pragma unused(vm,args,nargs)
1413
// NULL / v2 = 0
1414
RETURN_VALUE(VALUE_FROM_INT(0), rindex);
1415
}
1416
1417
static bool operator_null_mul (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1418
#pragma unused(vm,args,nargs)
1419
// NULL * v2 = 0
1420
RETURN_VALUE(VALUE_FROM_INT(0), rindex);
1421
}
1422
1423
static bool operator_null_rem (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1424
#pragma unused(vm,args,nargs)
1425
// NULL % v2 = 0
1426
RETURN_VALUE(VALUE_FROM_INT(0), rindex);
1427
}
1428
1429
static bool operator_null_and (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1430
#pragma unused(vm,args,nargs)
1431
RETURN_VALUE(VALUE_FROM_BOOL(0), rindex);
1432
}
1433
1434
static bool operator_null_or (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1435
#pragma unused(vm,nargs)
1436
1437
DECLARE_1VARIABLE(v2, 1);
1438
INTERNAL_CONVERT_BOOL(v2);
1439
RETURN_VALUE(VALUE_FROM_BOOL(0 || v2.n), rindex);
1440
}
1441
1442
// unary operators
1443
static bool operator_null_neg (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1444
#pragma unused(vm,args,nargs)
1445
RETURN_VALUE(VALUE_FROM_BOOL(0), rindex);
1446
}
1447
1448
static bool operator_null_not (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1449
#pragma unused(vm,args,nargs)
1450
// !null = true in all the tested programming languages
1451
RETURN_VALUE(VALUE_FROM_BOOL(1), rindex);
1452
}
1453
1454
#if GRAVITY_NULL_SILENT
1455
static bool operator_null_silent (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1456
#pragma unused(vm,args,nargs)
1457
RETURN_VALUE(VALUE_FROM_NULL, rindex);
1458
}
1459
#endif
1460
1461
static bool operator_null_cmp (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1462
#pragma unused(vm,nargs)
1463
if (VALUE_ISA_UNDEFINED(args[0])) {
1464
// undefined case (undefined is equal ONLY to undefined)
1465
if (VALUE_ISA_UNDEFINED(args[1])) RETURN_VALUE(VALUE_FROM_BOOL(1), rindex);
1466
RETURN_VALUE(VALUE_FROM_BOOL(0), rindex);
1467
}
1468
1469
args[0] = VALUE_FROM_INT(0);
1470
return operator_int_cmp(vm, args, nargs, rindex);
1471
}
1472
1473
// MARK: - System -
1474
1475
static bool system_nanotime (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1476
#pragma unused(args,nargs)
1477
nanotime_t t = nanotime();
1478
RETURN_VALUE(VALUE_FROM_INT(t), rindex);
1479
}
1480
1481
static bool system_realprint (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex, bool cr) {
1482
#pragma unused (rindex)
1483
for (uint16_t i=1; i<nargs; ++i) {
1484
gravity_value_t v = GET_VALUE(i);
1485
INTERNAL_CONVERT_STRING(v);
1486
gravity_string_t *s = VALUE_AS_STRING(v);
1487
printf("%.*s", s->len, s->s);
1488
}
1489
if (cr) printf("\n");
1490
RETURN_NOVALUE();
1491
}
1492
1493
static bool system_put (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1494
return system_realprint(vm, args, nargs, rindex, false);
1495
}
1496
1497
static bool system_print (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1498
return system_realprint(vm, args, nargs, rindex, true);
1499
}
1500
1501
static bool system_get (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1502
#pragma unused (args, nargs)
1503
gravity_value_t key = GET_VALUE(1);
1504
if (!VALUE_ISA_STRING(key)) RETURN_VALUE(VALUE_FROM_NULL, rindex);
1505
RETURN_VALUE(gravity_vm_get(vm, VALUE_AS_CSTRING(key)), rindex);
1506
}
1507
1508
static bool system_set (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
1509
#pragma unused (nargs, rindex)
1510
gravity_value_t key = GET_VALUE(1);
1511
gravity_value_t value = GET_VALUE(2);
1512
if (!VALUE_ISA_STRING(key)) RETURN_NOVALUE();
1513
1514
bool result = gravity_vm_set(vm, VALUE_AS_CSTRING(key), value);
1515
if (!result) RETURN_ERROR("Unable to apply System setting.");
1516
RETURN_NOVALUE();
1517
}
1518
1519
1520
// MARK: - CORE -
1521
1522
static gravity_closure_t *computed_property (gravity_vm *vm, gravity_function_t *getter_func, gravity_function_t *setter_func) {
1523
gravity_closure_t *getter_closure = (getter_func) ? gravity_closure_new(vm, getter_func) : NULL;
1524
gravity_closure_t *setter_closure = (setter_func) ? gravity_closure_new(vm, setter_func) : NULL;
1525
gravity_function_t *f = gravity_function_new_special(vm, NULL, GRAVITY_COMPUTED_INDEX, getter_closure, setter_closure);
1526
return gravity_closure_new(vm, f);
1527
}
1528
1529
static void gravity_core_init (void) {
1530
// this function must be executed ONCE
1531
if (core_inited) return;
1532
core_inited = true;
1533
1534
mem_check(false);
1535
1536
// Creation order here is very important
1537
// for example in a earlier version the intrinsic classes
1538
// were created before the Function class
1539
// so when the isa pointer was set to gravity_class_function
1540
// it resulted in a NULL pointer
1541
1542
// Object and Class are special classes
1543
// Object has no superclass (so the lookup loop knows when to finish)
1544
// Class has Object as its superclass
1545
// Any other class without an explicit superclass automatically has Object as its super
1546
// Both Object and Class classes has Class set as metaclass
1547
// Any other class created with gravity_class_new_pair has "class meta" as its metaclass
1548
1549
// CORE CLASS DIAGRAM:
1550
//
1551
// ----> means class's superclass
1552
// ====> means class's metaclass
1553
//
1554
//
1555
// +--------------------+ +=========+
1556
// | | || ||
1557
// v | \/ ||
1558
// +--------------+ +--------------+ ||
1559
// | Object | ==> | Class |====+
1560
// +--------------+ +--------------+
1561
// ^ ^
1562
// | |
1563
// +--------------+ +--------------+
1564
// | Base | ==> | Base meta |
1565
// +--------------+ +--------------+
1566
// ^ ^
1567
// | |
1568
// +--------------+ +--------------+
1569
// | Subclass | ==> |Subclass meta |
1570
// +--------------+ +--------------+
1571
1572
// Create classes first and then bind methods
1573
// A class without a superclass in a subclass of Object.
1574
1575
// every class without a super will have OBJECT as its superclass
1576
gravity_class_object = gravity_class_new_single(NULL, GRAVITY_CLASS_OBJECT_NAME, 0);
1577
gravity_class_class = gravity_class_new_single(NULL, GRAVITY_CLASS_CLASS_NAME, 0);
1578
gravity_class_setsuper(gravity_class_class, gravity_class_object);
1579
1580
// manually set meta class and isa pointer for classes created without the gravity_class_new_pair
1581
// when gravity_class_new_single was called gravity_class_class was NULL so the isa pointer must be reset
1582
gravity_class_object->objclass = gravity_class_class; gravity_class_object->isa = gravity_class_class;
1583
gravity_class_class->objclass = gravity_class_class; gravity_class_class->isa = gravity_class_class;
1584
1585
// NULL in gravity_class_new_pair and NEW_FUNCTION macro because I do not want them to be in the GC
1586
gravity_class_function = gravity_class_new_pair(NULL, GRAVITY_CLASS_FUNCTION_NAME, NULL, 0, 0);
1587
gravity_class_fiber = gravity_class_new_pair(NULL, GRAVITY_CLASS_FIBER_NAME, NULL, 0, 0);
1588
gravity_class_instance = gravity_class_new_pair(NULL, GRAVITY_CLASS_INSTANCE_NAME, NULL, 0, 0);
1589
gravity_class_closure = gravity_class_new_pair(NULL, GRAVITY_CLASS_CLOSURE_NAME, NULL, 0, 0);
1590
gravity_class_upvalue = gravity_class_new_pair(NULL, GRAVITY_CLASS_UPVALUE_NAME, NULL, 0, 0);
1591
gravity_class_module = NULL;
1592
1593
// create intrinsic classes (intrinsic datatypes are: Int, Float, Bool, Null, String, List, Map and Range)
1594
gravity_class_int = gravity_class_new_pair(NULL, GRAVITY_CLASS_INT_NAME, NULL, 0, 0);
1595
gravity_class_float = gravity_class_new_pair(NULL, GRAVITY_CLASS_FLOAT_NAME, NULL, 0, 0);
1596
gravity_class_bool = gravity_class_new_pair(NULL, GRAVITY_CLASS_BOOL_NAME, NULL, 0, 0);
1597
gravity_class_null = gravity_class_new_pair(NULL, GRAVITY_CLASS_NULL_NAME, NULL, 0, 0);
1598
gravity_class_string = gravity_class_new_pair(NULL, GRAVITY_CLASS_STRING_NAME, NULL, 0, 0);
1599
gravity_class_list = gravity_class_new_pair(NULL, GRAVITY_CLASS_LIST_NAME, NULL, 0, 0);
1600
gravity_class_map = gravity_class_new_pair(NULL, GRAVITY_CLASS_MAP_NAME, NULL, 0, 0);
1601
gravity_class_range = gravity_class_new_pair(NULL, GRAVITY_CLASS_RANGE_NAME, NULL, 0, 0);
1602
1603
// OBJECT CLASS
1604
gravity_class_bind(gravity_class_object, GRAVITY_CLASS_CLASS_NAME, NEW_CLOSURE_VALUE(object_class));
1605
gravity_class_bind(gravity_class_object, GRAVITY_OPERATOR_ISA_NAME, NEW_CLOSURE_VALUE(object_isa));
1606
gravity_class_bind(gravity_class_object, GRAVITY_OPERATOR_CMP_NAME, NEW_CLOSURE_VALUE(object_cmp));
1607
gravity_class_bind(gravity_class_object, GRAVITY_CLASS_INT_NAME, NEW_CLOSURE_VALUE(convert_object_int));
1608
gravity_class_bind(gravity_class_object, GRAVITY_CLASS_FLOAT_NAME, NEW_CLOSURE_VALUE(convert_object_float));
1609
gravity_class_bind(gravity_class_object, GRAVITY_CLASS_BOOL_NAME, NEW_CLOSURE_VALUE(convert_object_bool));
1610
gravity_class_bind(gravity_class_object, GRAVITY_CLASS_STRING_NAME, NEW_CLOSURE_VALUE(convert_object_string));
1611
gravity_class_bind(gravity_class_object, GRAVITY_INTERNAL_LOAD_NAME, NEW_CLOSURE_VALUE(object_load));
1612
gravity_class_bind(gravity_class_object, GRAVITY_INTERNAL_LOADS_NAME, NEW_CLOSURE_VALUE(object_loads));
1613
gravity_class_bind(gravity_class_object, GRAVITY_INTERNAL_STORE_NAME, NEW_CLOSURE_VALUE(object_store));
1614
gravity_class_bind(gravity_class_object, GRAVITY_INTERNAL_NOTFOUND_NAME, NEW_CLOSURE_VALUE(object_notfound));
1615
gravity_class_bind(gravity_class_object, "_size", NEW_CLOSURE_VALUE(object_internal_size));
1616
gravity_class_bind(gravity_class_object, GRAVITY_OPERATOR_NOT_NAME, NEW_CLOSURE_VALUE(object_not));
1617
gravity_class_bind(gravity_class_object, "bind", NEW_CLOSURE_VALUE(object_bind));
1618
gravity_class_bind(gravity_class_object, "unbind", NEW_CLOSURE_VALUE(object_unbind));
1619
1620
// CLASS CLASS
1621
gravity_class_bind(gravity_class_class, "name", NEW_CLOSURE_VALUE(class_name));
1622
gravity_class_bind(gravity_class_class, GRAVITY_INTERNAL_EXEC_NAME, NEW_CLOSURE_VALUE(class_exec));
1623
1624
// LIST CLASS
1625
gravity_class_bind(gravity_class_list, "count", VALUE_FROM_OBJECT(computed_property(NULL, NEW_FUNCTION(list_count), NULL)));
1626
gravity_class_bind(gravity_class_list, ITERATOR_INIT_FUNCTION, NEW_CLOSURE_VALUE(list_iterator));
1627
gravity_class_bind(gravity_class_list, ITERATOR_NEXT_FUNCTION, NEW_CLOSURE_VALUE(list_iterator_next));
1628
gravity_class_bind(gravity_class_list, GRAVITY_INTERNAL_LOADAT_NAME, NEW_CLOSURE_VALUE(list_loadat));
1629
gravity_class_bind(gravity_class_list, GRAVITY_INTERNAL_STOREAT_NAME, NEW_CLOSURE_VALUE(list_storeat));
1630
gravity_class_bind(gravity_class_list, GRAVITY_INTERNAL_LOOP_NAME, NEW_CLOSURE_VALUE(list_loop));
1631
gravity_class_bind(gravity_class_list, "push", NEW_CLOSURE_VALUE(list_push));
1632
gravity_class_bind(gravity_class_list, "pop", NEW_CLOSURE_VALUE(list_pop));
1633
1634
// MAP CLASS
1635
gravity_class_bind(gravity_class_map, "keys", NEW_CLOSURE_VALUE(map_keys));
1636
gravity_class_bind(gravity_class_map, "remove", NEW_CLOSURE_VALUE(map_remove));
1637
gravity_class_bind(gravity_class_map, "count", VALUE_FROM_OBJECT(computed_property(NULL, NEW_FUNCTION(map_count), NULL)));
1638
gravity_class_bind(gravity_class_map, GRAVITY_INTERNAL_LOOP_NAME, NEW_CLOSURE_VALUE(map_loop));
1639
gravity_class_bind(gravity_class_map, GRAVITY_INTERNAL_LOADAT_NAME, NEW_CLOSURE_VALUE(map_loadat));
1640
gravity_class_bind(gravity_class_map, GRAVITY_INTERNAL_STOREAT_NAME, NEW_CLOSURE_VALUE(map_storeat));
1641
#if GRAVITY_MAP_DOTSUGAR
1642
gravity_class_bind(gravity_class_map, GRAVITY_INTERNAL_LOAD_NAME, NEW_CLOSURE_VALUE(map_loadat));
1643
gravity_class_bind(gravity_class_map, GRAVITY_INTERNAL_STORE_NAME, NEW_CLOSURE_VALUE(map_storeat));
1644
#endif
1645
1646
// RANGE CLASS
1647
gravity_class_bind(gravity_class_range, "count", VALUE_FROM_OBJECT(computed_property(NULL, NEW_FUNCTION(range_count), NULL)));
1648
gravity_class_bind(gravity_class_range, ITERATOR_INIT_FUNCTION, NEW_CLOSURE_VALUE(range_iterator));
1649
gravity_class_bind(gravity_class_range, ITERATOR_NEXT_FUNCTION, NEW_CLOSURE_VALUE(range_iterator_next));
1650
gravity_class_bind(gravity_class_range, "contains", NEW_CLOSURE_VALUE(range_contains));
1651
gravity_class_bind(gravity_class_range, GRAVITY_INTERNAL_LOOP_NAME, NEW_CLOSURE_VALUE(range_loop));
1652
1653
// INT CLASS
1654
gravity_class_bind(gravity_class_int, GRAVITY_OPERATOR_ADD_NAME, NEW_CLOSURE_VALUE(operator_int_add));
1655
gravity_class_bind(gravity_class_int, GRAVITY_OPERATOR_SUB_NAME, NEW_CLOSURE_VALUE(operator_int_sub));
1656
gravity_class_bind(gravity_class_int, GRAVITY_OPERATOR_DIV_NAME, NEW_CLOSURE_VALUE(operator_int_div));
1657
gravity_class_bind(gravity_class_int, GRAVITY_OPERATOR_MUL_NAME, NEW_CLOSURE_VALUE(operator_int_mul));
1658
gravity_class_bind(gravity_class_int, GRAVITY_OPERATOR_REM_NAME, NEW_CLOSURE_VALUE(operator_int_rem));
1659
gravity_class_bind(gravity_class_int, GRAVITY_OPERATOR_AND_NAME, NEW_CLOSURE_VALUE(operator_int_and));
1660
gravity_class_bind(gravity_class_int, GRAVITY_OPERATOR_OR_NAME, NEW_CLOSURE_VALUE(operator_int_or));
1661
gravity_class_bind(gravity_class_int, GRAVITY_OPERATOR_CMP_NAME, NEW_CLOSURE_VALUE(operator_int_cmp));
1662
// gravity_class_bind(gravity_class_int, GRAVITY_OPERATOR_BITOR_NAME, NEW_CLOSURE_VALUE(operator_int_bitor));
1663
// gravity_class_bind(gravity_class_int, GRAVITY_OPERATOR_BITAND_NAME, NEW_CLOSURE_VALUE(operator_int_bitand));
1664
// gravity_class_bind(gravity_class_int, GRAVITY_OPERATOR_BITXOR_NAME, NEW_CLOSURE_VALUE(operator_int_bitxor));
1665
// gravity_class_bind(gravity_class_int, GRAVITY_OPERATOR_BITLS_NAME, NEW_CLOSURE_VALUE(operator_int_bitls));
1666
// gravity_class_bind(gravity_class_int, GRAVITY_OPERATOR_BITRS_NAME, NEW_CLOSURE_VALUE(operator_int_bitrs));
1667
gravity_class_bind(gravity_class_int, GRAVITY_OPERATOR_NEG_NAME, NEW_CLOSURE_VALUE(operator_int_neg));
1668
gravity_class_bind(gravity_class_int, GRAVITY_OPERATOR_NOT_NAME, NEW_CLOSURE_VALUE(operator_int_not));
1669
gravity_class_bind(gravity_class_int, GRAVITY_INTERNAL_LOOP_NAME, NEW_CLOSURE_VALUE(int_loop));
1670
1671
// FLOAT CLASS
1672
gravity_class_bind(gravity_class_float, GRAVITY_OPERATOR_ADD_NAME, NEW_CLOSURE_VALUE(operator_float_add));
1673
gravity_class_bind(gravity_class_float, GRAVITY_OPERATOR_SUB_NAME, NEW_CLOSURE_VALUE(operator_float_sub));
1674
gravity_class_bind(gravity_class_float, GRAVITY_OPERATOR_DIV_NAME, NEW_CLOSURE_VALUE(operator_float_div));
1675
gravity_class_bind(gravity_class_float, GRAVITY_OPERATOR_MUL_NAME, NEW_CLOSURE_VALUE(operator_float_mul));
1676
gravity_class_bind(gravity_class_float, GRAVITY_OPERATOR_REM_NAME, NEW_CLOSURE_VALUE(operator_float_rem));
1677
gravity_class_bind(gravity_class_float, GRAVITY_OPERATOR_AND_NAME, NEW_CLOSURE_VALUE(operator_float_and));
1678
gravity_class_bind(gravity_class_float, GRAVITY_OPERATOR_OR_NAME, NEW_CLOSURE_VALUE(operator_float_or));
1679
gravity_class_bind(gravity_class_float, GRAVITY_OPERATOR_CMP_NAME, NEW_CLOSURE_VALUE(operator_float_cmp));
1680
gravity_class_bind(gravity_class_float, GRAVITY_OPERATOR_NEG_NAME, NEW_CLOSURE_VALUE(operator_float_neg));
1681
gravity_class_bind(gravity_class_float, GRAVITY_OPERATOR_NOT_NAME, NEW_CLOSURE_VALUE(operator_float_not));
1682
gravity_class_bind(gravity_class_float, "round", NEW_CLOSURE_VALUE(function_float_round));
1683
gravity_class_bind(gravity_class_float, "floor", NEW_CLOSURE_VALUE(function_float_floor));
1684
gravity_class_bind(gravity_class_float, "ceil", NEW_CLOSURE_VALUE(function_float_ceil));
1685
1686
// BOOL CLASS
1687
gravity_class_bind(gravity_class_bool, GRAVITY_OPERATOR_ADD_NAME, NEW_CLOSURE_VALUE(operator_bool_add));
1688
gravity_class_bind(gravity_class_bool, GRAVITY_OPERATOR_SUB_NAME, NEW_CLOSURE_VALUE(operator_bool_sub));
1689
gravity_class_bind(gravity_class_bool, GRAVITY_OPERATOR_DIV_NAME, NEW_CLOSURE_VALUE(operator_bool_div));
1690
gravity_class_bind(gravity_class_bool, GRAVITY_OPERATOR_MUL_NAME, NEW_CLOSURE_VALUE(operator_bool_mul));
1691
gravity_class_bind(gravity_class_bool, GRAVITY_OPERATOR_REM_NAME, NEW_CLOSURE_VALUE(operator_bool_rem));
1692
gravity_class_bind(gravity_class_bool, GRAVITY_OPERATOR_AND_NAME, NEW_CLOSURE_VALUE(operator_bool_and));
1693
gravity_class_bind(gravity_class_bool, GRAVITY_OPERATOR_OR_NAME, NEW_CLOSURE_VALUE(operator_bool_or));
1694
gravity_class_bind(gravity_class_bool, GRAVITY_OPERATOR_CMP_NAME, NEW_CLOSURE_VALUE(operator_bool_cmp));
1695
gravity_class_bind(gravity_class_bool, GRAVITY_OPERATOR_NEG_NAME, NEW_CLOSURE_VALUE(operator_bool_neg));
1696
gravity_class_bind(gravity_class_bool, GRAVITY_OPERATOR_NOT_NAME, NEW_CLOSURE_VALUE(operator_bool_not));
1697
1698
// STRING CLASS
1699
gravity_class_bind(gravity_class_string, GRAVITY_OPERATOR_ADD_NAME, NEW_CLOSURE_VALUE(operator_string_add));
1700
gravity_class_bind(gravity_class_string, GRAVITY_OPERATOR_SUB_NAME, NEW_CLOSURE_VALUE(operator_string_sub));
1701
gravity_class_bind(gravity_class_string, GRAVITY_OPERATOR_AND_NAME, NEW_CLOSURE_VALUE(operator_string_and));
1702
gravity_class_bind(gravity_class_string, GRAVITY_OPERATOR_OR_NAME, NEW_CLOSURE_VALUE(operator_string_or));
1703
gravity_class_bind(gravity_class_string, GRAVITY_OPERATOR_CMP_NAME, NEW_CLOSURE_VALUE(operator_string_cmp));
1704
gravity_class_bind(gravity_class_string, GRAVITY_OPERATOR_NEG_NAME, NEW_CLOSURE_VALUE(operator_string_neg));
1705
gravity_class_bind(gravity_class_string, "length", VALUE_FROM_OBJECT(computed_property(NULL, NEW_FUNCTION(string_length), NULL)));
1706
1707
// FIBER CLASS
1708
gravity_class_t *fiber_meta = gravity_class_get_meta(gravity_class_fiber);
1709
gravity_class_bind(fiber_meta, "create", NEW_CLOSURE_VALUE(fiber_create));
1710
gravity_class_bind(gravity_class_fiber, GRAVITY_INTERNAL_EXEC_NAME, NEW_CLOSURE_VALUE(fiber_exec));
1711
gravity_class_bind(gravity_class_fiber, "try", NEW_CLOSURE_VALUE(fiber_try));
1712
gravity_class_bind(fiber_meta, "yield", NEW_CLOSURE_VALUE(fiber_yield));
1713
gravity_class_bind(gravity_class_fiber, "status", NEW_CLOSURE_VALUE(fiber_status));
1714
gravity_class_bind(gravity_class_fiber, "abort", NEW_CLOSURE_VALUE(fiber_abort));
1715
1716
// BASIC OPERATIONS added also to NULL CLASS (and UNDEFINED since they points to the same class)
1717
// this is required because every variable is initialized by default to NULL
1718
gravity_class_bind(gravity_class_null, GRAVITY_OPERATOR_ADD_NAME, NEW_CLOSURE_VALUE(operator_null_add));
1719
gravity_class_bind(gravity_class_null, GRAVITY_OPERATOR_SUB_NAME, NEW_CLOSURE_VALUE(operator_null_sub));
1720
gravity_class_bind(gravity_class_null, GRAVITY_OPERATOR_DIV_NAME, NEW_CLOSURE_VALUE(operator_null_div));
1721
gravity_class_bind(gravity_class_null, GRAVITY_OPERATOR_MUL_NAME, NEW_CLOSURE_VALUE(operator_null_mul));
1722
gravity_class_bind(gravity_class_null, GRAVITY_OPERATOR_REM_NAME, NEW_CLOSURE_VALUE(operator_null_rem));
1723
gravity_class_bind(gravity_class_null, GRAVITY_OPERATOR_AND_NAME, NEW_CLOSURE_VALUE(operator_null_and));
1724
gravity_class_bind(gravity_class_null, GRAVITY_OPERATOR_OR_NAME, NEW_CLOSURE_VALUE(operator_null_or));
1725
gravity_class_bind(gravity_class_null, GRAVITY_OPERATOR_CMP_NAME, NEW_CLOSURE_VALUE(operator_null_cmp));
1726
gravity_class_bind(gravity_class_null, GRAVITY_OPERATOR_NEG_NAME, NEW_CLOSURE_VALUE(operator_null_neg));
1727
gravity_class_bind(gravity_class_null, GRAVITY_OPERATOR_NOT_NAME, NEW_CLOSURE_VALUE(operator_null_not));
1728
#if GRAVITY_NULL_SILENT
1729
gravity_class_bind(gravity_class_null, GRAVITY_INTERNAL_EXEC_NAME, NEW_CLOSURE_VALUE(operator_null_silent));
1730
gravity_class_bind(gravity_class_null, GRAVITY_INTERNAL_LOAD_NAME, NEW_CLOSURE_VALUE(operator_null_silent));
1731
gravity_class_bind(gravity_class_null, GRAVITY_INTERNAL_STORE_NAME, NEW_CLOSURE_VALUE(operator_null_silent));
1732
gravity_class_bind(gravity_class_null, GRAVITY_INTERNAL_NOTFOUND_NAME, NEW_CLOSURE_VALUE(operator_null_silent));
1733
#endif
1734
1735
// SYSTEM class
1736
gravity_class_system = gravity_class_new_pair(NULL, GRAVITY_CLASS_SYSTEM_NAME, NULL, 0, 0);
1737
gravity_class_t *system_meta = gravity_class_get_meta(gravity_class_system);
1738
gravity_class_bind(system_meta, GRAVITY_SYSTEM_NANOTIME_NAME, NEW_CLOSURE_VALUE(system_nanotime));
1739
gravity_class_bind(system_meta, GRAVITY_SYSTEM_PRINT_NAME, NEW_CLOSURE_VALUE(system_print));
1740
gravity_class_bind(system_meta, GRAVITY_SYSTEM_PUT_NAME, NEW_CLOSURE_VALUE(system_put));
1741
1742
gravity_value_t value = VALUE_FROM_OBJECT(computed_property(NULL, NEW_FUNCTION(system_get), NEW_FUNCTION(system_set)));
1743
gravity_class_bind(system_meta, "gcenabled", value);
1744
gravity_class_bind(system_meta, "gcminthreshold", value);
1745
gravity_class_bind(system_meta, "gcthreshold", value);
1746
gravity_class_bind(system_meta, "gcratio", value);
1747
1748
// INIT META
1749
SETMETA_INITED(gravity_class_int);
1750
SETMETA_INITED(gravity_class_float);
1751
SETMETA_INITED(gravity_class_bool);
1752
SETMETA_INITED(gravity_class_null);
1753
SETMETA_INITED(gravity_class_string);
1754
SETMETA_INITED(gravity_class_object);
1755
SETMETA_INITED(gravity_class_function);
1756
SETMETA_INITED(gravity_class_closure);
1757
SETMETA_INITED(gravity_class_fiber);
1758
SETMETA_INITED(gravity_class_class);
1759
SETMETA_INITED(gravity_class_instance);
1760
SETMETA_INITED(gravity_class_list);
1761
SETMETA_INITED(gravity_class_map);
1762
SETMETA_INITED(gravity_class_range);
1763
SETMETA_INITED(gravity_class_upvalue);
1764
SETMETA_INITED(gravity_class_system);
1765
//SETMETA_INITED(gravity_class_module);
1766
1767
mem_check(true);
1768
}
1769
1770
void gravity_core_free (void) {
1771
if (!core_inited) return;
1772
1773
// check if others VM are still running
1774
if (--refcount != 0) return;
1775
1776
// this function should never be called
1777
// it is just called when we need to internally check for memory leaks
1778
1779
mem_check(false);
1780
gravity_class_free_core(NULL, gravity_class_get_meta(gravity_class_int));
1781
gravity_class_free_core(NULL, gravity_class_int);
1782
gravity_class_free_core(NULL, gravity_class_get_meta(gravity_class_float));
1783
gravity_class_free_core(NULL, gravity_class_float);
1784
gravity_class_free_core(NULL, gravity_class_get_meta(gravity_class_bool));
1785
gravity_class_free_core(NULL, gravity_class_bool);
1786
gravity_class_free_core(NULL, gravity_class_get_meta(gravity_class_string));
1787
gravity_class_free_core(NULL, gravity_class_string);
1788
gravity_class_free_core(NULL, gravity_class_get_meta(gravity_class_null));
1789
gravity_class_free_core(NULL, gravity_class_null);
1790
gravity_class_free_core(NULL, gravity_class_get_meta(gravity_class_function));
1791
gravity_class_free_core(NULL, gravity_class_function);
1792
gravity_class_free_core(NULL, gravity_class_get_meta(gravity_class_closure));
1793
gravity_class_free_core(NULL, gravity_class_closure);
1794
gravity_class_free_core(NULL, gravity_class_get_meta(gravity_class_fiber));
1795
gravity_class_free_core(NULL, gravity_class_fiber);
1796
gravity_class_free_core(NULL, gravity_class_get_meta(gravity_class_instance));
1797
gravity_class_free_core(NULL, gravity_class_instance);
1798
gravity_class_free_core(NULL, gravity_class_get_meta(gravity_class_list));
1799
gravity_class_free_core(NULL, gravity_class_list);
1800
gravity_class_free_core(NULL, gravity_class_get_meta(gravity_class_map));
1801
gravity_class_free_core(NULL, gravity_class_map);
1802
gravity_class_free_core(NULL, gravity_class_get_meta(gravity_class_range));
1803
gravity_class_free_core(NULL, gravity_class_range);
1804
gravity_class_free_core(NULL, gravity_class_get_meta(gravity_class_upvalue));
1805
gravity_class_free_core(NULL, gravity_class_upvalue);
1806
1807
// before freeing the meta class we need to remove entries with duplicated functions
1808
gravity_class_t *system_meta = gravity_class_get_meta(gravity_class_system);
1809
{STATICVALUE_FROM_STRING(key, "gcminthreshold", strlen("gcminthreshold")); gravity_hash_remove(system_meta->htable, key);}
1810
{STATICVALUE_FROM_STRING(key, "gcthreshold", strlen("gcthreshold")); gravity_hash_remove(system_meta->htable, key);}
1811
{STATICVALUE_FROM_STRING(key, "gcratio", strlen("gcratio")); gravity_hash_remove(system_meta->htable, key);}
1812
gravity_class_free_core(NULL, system_meta);
1813
gravity_class_free_core(NULL, gravity_class_system);
1814
1815
// object must be the last class to be freed
1816
gravity_class_free_core(NULL, gravity_class_class);
1817
gravity_class_free_core(NULL, gravity_class_object);
1818
mem_check(true);
1819
1820
gravity_class_int = NULL;
1821
gravity_class_float = NULL;
1822
gravity_class_bool = NULL;
1823
gravity_class_string = NULL;
1824
gravity_class_object = NULL;
1825
gravity_class_null = NULL;
1826
gravity_class_function = NULL;
1827
gravity_class_closure = NULL;
1828
gravity_class_fiber = NULL;
1829
gravity_class_class = NULL;
1830
gravity_class_instance = NULL;
1831
gravity_class_list = NULL;
1832
gravity_class_map = NULL;
1833
gravity_class_range = NULL;
1834
gravity_class_upvalue = NULL;
1835
gravity_class_system = NULL;
1836
gravity_class_module = NULL;
1837
1838
core_inited = false;
1839
}
1840
1841
uint32_t gravity_core_identifiers (const char ***id) {
1842
static const char *list[] = {GRAVITY_CLASS_OBJECT_NAME, GRAVITY_CLASS_CLASS_NAME, GRAVITY_CLASS_BOOL_NAME, GRAVITY_CLASS_NULL_NAME,
1843
GRAVITY_CLASS_INT_NAME, GRAVITY_CLASS_FLOAT_NAME, GRAVITY_CLASS_FUNCTION_NAME, GRAVITY_CLASS_FIBER_NAME, GRAVITY_CLASS_STRING_NAME,
1844
GRAVITY_CLASS_INSTANCE_NAME, GRAVITY_CLASS_LIST_NAME, GRAVITY_CLASS_MAP_NAME, GRAVITY_CLASS_RANGE_NAME, GRAVITY_CLASS_SYSTEM_NAME,
1845
GRAVITY_CLASS_CLOSURE_NAME, GRAVITY_CLASS_UPVALUE_NAME};
1846
*id = list;
1847
return (sizeof(list) / sizeof(const char *));
1848
}
1849
1850
void gravity_core_register (gravity_vm *vm) {
1851
gravity_core_init();
1852
++refcount;
1853
if (!vm) return;
1854
1855
// register core classes inside VM
1856
if (gravity_vm_ismini(vm)) return;
1857
gravity_vm_setvalue(vm, GRAVITY_CLASS_OBJECT_NAME, VALUE_FROM_OBJECT(gravity_class_object));
1858
gravity_vm_setvalue(vm, GRAVITY_CLASS_CLASS_NAME, VALUE_FROM_OBJECT(gravity_class_class));
1859
gravity_vm_setvalue(vm, GRAVITY_CLASS_BOOL_NAME, VALUE_FROM_OBJECT(gravity_class_bool));
1860
gravity_vm_setvalue(vm, GRAVITY_CLASS_NULL_NAME, VALUE_FROM_OBJECT(gravity_class_null));
1861
gravity_vm_setvalue(vm, GRAVITY_CLASS_INT_NAME, VALUE_FROM_OBJECT(gravity_class_int));
1862
gravity_vm_setvalue(vm, GRAVITY_CLASS_FLOAT_NAME, VALUE_FROM_OBJECT(gravity_class_float));
1863
gravity_vm_setvalue(vm, GRAVITY_CLASS_FUNCTION_NAME, VALUE_FROM_OBJECT(gravity_class_function));
1864
gravity_vm_setvalue(vm, GRAVITY_CLASS_CLOSURE_NAME, VALUE_FROM_OBJECT(gravity_class_closure));
1865
gravity_vm_setvalue(vm, GRAVITY_CLASS_FIBER_NAME, VALUE_FROM_OBJECT(gravity_class_fiber));
1866
gravity_vm_setvalue(vm, GRAVITY_CLASS_STRING_NAME, VALUE_FROM_OBJECT(gravity_class_string));
1867
gravity_vm_setvalue(vm, GRAVITY_CLASS_INSTANCE_NAME, VALUE_FROM_OBJECT(gravity_class_instance));
1868
gravity_vm_setvalue(vm, GRAVITY_CLASS_LIST_NAME, VALUE_FROM_OBJECT(gravity_class_list));
1869
gravity_vm_setvalue(vm, GRAVITY_CLASS_MAP_NAME, VALUE_FROM_OBJECT(gravity_class_map));
1870
gravity_vm_setvalue(vm, GRAVITY_CLASS_RANGE_NAME, VALUE_FROM_OBJECT(gravity_class_range));
1871
gravity_vm_setvalue(vm, GRAVITY_CLASS_UPVALUE_NAME, VALUE_FROM_OBJECT(gravity_class_upvalue));
1872
gravity_vm_setvalue(vm, GRAVITY_CLASS_SYSTEM_NAME, VALUE_FROM_OBJECT(gravity_class_system));
1873
}
1874
1875
bool gravity_iscore_class (gravity_class_t *c) {
1876
return ((c == gravity_class_object) || (c == gravity_class_class) || (c == gravity_class_bool) ||
1877
(c == gravity_class_null) || (c == gravity_class_int) || (c == gravity_class_float) ||
1878
(c == gravity_class_function) || (c == gravity_class_fiber) || (c == gravity_class_string) ||
1879
(c == gravity_class_instance) || (c == gravity_class_list) || (c == gravity_class_map) ||
1880
(c == gravity_class_range) || (c == gravity_class_system) || (c == gravity_class_closure) ||
1881
(c == gravity_class_upvalue));
1882
}
1883
1884