xbintsc 0.3.15 → 0.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/cli/main.js +4 -4
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/state.js +8 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/tables.js +8 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/graph.d.ts +8 -0
- package/dist/src/driver/bundler/graph.js +85 -0
- package/dist/src/driver/bundler/graph.js.map +1 -0
- package/dist/src/driver/bundler/merge.d.ts +11 -0
- package/dist/src/driver/bundler/merge.js +288 -0
- package/dist/src/driver/bundler/merge.js.map +1 -0
- package/dist/src/driver/bundler/resolve.d.ts +12 -0
- package/dist/src/driver/bundler/resolve.js +246 -0
- package/dist/src/driver/bundler/resolve.js.map +1 -0
- package/dist/src/driver/bundler/symbols.d.ts +15 -0
- package/dist/src/driver/bundler/symbols.js +51 -0
- package/dist/src/driver/bundler/symbols.js.map +1 -0
- package/dist/src/driver/bundler/types.d.ts +36 -0
- package/dist/src/driver/bundler/types.js +5 -0
- package/dist/src/driver/bundler/types.js.map +1 -0
- package/dist/src/driver/modules.d.ts +9 -16
- package/dist/src/driver/modules.js +8 -644
- package/dist/src/driver/modules.js.map +1 -1
- package/dist/src/extensions/catalog.js +2 -1
- package/dist/src/extensions/catalog.js.map +1 -1
- package/dist/src/extensions/gui/index.d.ts +24 -0
- package/dist/src/extensions/gui/index.js +101 -0
- package/dist/src/extensions/gui/index.js.map +1 -0
- package/dist/tests/e2e/compile-basics.test.d.ts +4 -0
- package/dist/tests/e2e/compile-basics.test.js +134 -0
- package/dist/tests/e2e/compile-basics.test.js.map +1 -0
- package/dist/tests/e2e/compile-builtins.test.d.ts +4 -0
- package/dist/tests/e2e/compile-builtins.test.js +191 -0
- package/dist/tests/e2e/compile-builtins.test.js.map +1 -0
- package/dist/tests/e2e/compile-control-flow.test.d.ts +4 -0
- package/dist/tests/e2e/compile-control-flow.test.js +190 -0
- package/dist/tests/e2e/compile-control-flow.test.js.map +1 -0
- package/dist/tests/e2e/compile-modules.test.d.ts +4 -0
- package/dist/tests/e2e/compile-modules.test.js +48 -0
- package/dist/tests/e2e/compile-modules.test.js.map +1 -0
- package/dist/tests/e2e/compile-objects-classes.test.d.ts +4 -0
- package/dist/tests/e2e/compile-objects-classes.test.js +362 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -0
- package/dist/tests/e2e/differential-helpers.d.ts +12 -0
- package/dist/tests/e2e/differential-helpers.js +16 -0
- package/dist/tests/e2e/differential-helpers.js.map +1 -0
- package/dist/tests/e2e/differential-language.test.d.ts +4 -0
- package/dist/tests/e2e/{differential.test.js → differential-language.test.js} +5 -287
- package/dist/tests/e2e/differential-language.test.js.map +1 -0
- package/dist/tests/e2e/differential-symbols.test.d.ts +4 -0
- package/dist/tests/e2e/differential-symbols.test.js +92 -0
- package/dist/tests/e2e/differential-symbols.test.js.map +1 -0
- package/dist/tests/e2e/differential-values.test.d.ts +4 -0
- package/dist/tests/e2e/differential-values.test.js +197 -0
- package/dist/tests/e2e/differential-values.test.js.map +1 -0
- package/dist/tests/e2e/gui.test.d.ts +12 -0
- package/dist/tests/e2e/gui.test.js +493 -0
- package/dist/tests/e2e/gui.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-buffer.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-buffer.test.js +97 -0
- package/dist/tests/e2e/runtime-coverage-buffer.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.js +149 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-node-modules.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-node-modules.test.js +177 -0
- package/dist/tests/e2e/runtime-coverage-node-modules.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-streams.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-streams.test.js +161 -0
- package/dist/tests/e2e/runtime-coverage-streams.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-system.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-system.test.js +91 -0
- package/dist/tests/e2e/runtime-coverage-system.test.js.map +1 -0
- package/dist/tests/e2e/timers.test.d.ts +7 -0
- package/dist/tests/e2e/timers.test.js +63 -0
- package/dist/tests/e2e/timers.test.js.map +1 -0
- package/package.json +2 -1
- package/runtime/ext_gui/css.cpp +743 -0
- package/runtime/ext_gui/css.h +98 -0
- package/runtime/ext_gui/document.cpp +264 -0
- package/runtime/ext_gui/document.h +89 -0
- package/runtime/ext_gui/dom.cpp +472 -0
- package/runtime/ext_gui/dom.h +71 -0
- package/runtime/ext_gui/gui.cpp +457 -0
- package/runtime/ext_gui/gui_engine.h +81 -0
- package/runtime/ext_gui/image.cpp +125 -0
- package/runtime/ext_gui/image.h +42 -0
- package/runtime/ext_gui/layout.cpp +748 -0
- package/runtime/ext_gui/layout.h +93 -0
- package/runtime/ext_gui/paint.cpp +137 -0
- package/runtime/ext_gui/paint.h +75 -0
- package/runtime/ext_gui/renderer.cpp +959 -0
- package/runtime/ext_gui/renderer.h +68 -0
- package/runtime/ext_gui/stb_image.h +7988 -0
- package/runtime/ext_gui/style.cpp +771 -0
- package/runtime/ext_gui/style.h +117 -0
- package/runtime/ext_gui/text.cpp +378 -0
- package/runtime/ext_gui/text.h +78 -0
- package/runtime/ext_gui/window.cpp +405 -0
- package/runtime/ext_node/fs/fs_common.h +13 -527
- package/runtime/ext_node/fs/parts/buffer-bridge.inc +6 -0
- package/runtime/ext_node/fs/parts/builtins.inc +69 -0
- package/runtime/ext_node/fs/parts/dir.inc +47 -0
- package/runtime/ext_node/fs/parts/encoding.inc +186 -0
- package/runtime/ext_node/fs/parts/errors.inc +66 -0
- package/runtime/ext_node/fs/parts/flags.inc +39 -0
- package/runtime/ext_node/fs/parts/platform.inc +86 -0
- package/runtime/ext_node/fs/parts/promisify.inc +15 -0
- package/runtime/ext_node/fs/parts/time.inc +9 -0
- package/runtime/rt.h +33 -0
- package/runtime/xt_builtins.c +4 -0
- package/runtime/xt_containers/access.inc +168 -0
- package/runtime/xt_containers/arrays.inc +108 -0
- package/runtime/xt_containers/boxes.inc +11 -0
- package/runtime/xt_containers/objects.inc +326 -0
- package/runtime/xt_containers.c +8 -618
- package/runtime/xt_io/base64.inc +87 -0
- package/runtime/xt_io/console.inc +119 -0
- package/runtime/xt_io/exception.inc +142 -0
- package/runtime/xt_io/inspect.inc +212 -0
- package/runtime/xt_io.c +8 -553
- package/runtime/xt_loop.c +262 -24
- package/runtime/xt_regex/api.inc +58 -0
- package/runtime/xt_regex/helpers.inc +68 -0
- package/runtime/xt_regex/matcher.inc +248 -0
- package/runtime/xt_regex/parser.inc +236 -0
- package/runtime/xt_regex/types.inc +58 -0
- package/runtime/xt_regex.h +9 -672
- package/runtime/xt_values/arithmetic.inc +150 -0
- package/runtime/xt_values/comparison.inc +112 -0
- package/runtime/xt_values/constructors.inc +41 -0
- package/runtime/xt_values/conversions.inc +115 -0
- package/runtime/xt_values/number-format.inc +180 -0
- package/runtime/xt_values/strings.inc +22 -0
- package/runtime/xt_values.c +10 -626
- package/scripts/build-gui.ts +317 -0
- package/src/cli/main.ts +4 -3
- package/src/codegen/generator/state.ts +8 -0
- package/src/codegen/generator/tables.ts +8 -0
- package/src/driver/bundler/graph.ts +95 -0
- package/src/driver/bundler/merge.ts +312 -0
- package/src/driver/bundler/resolve.ts +240 -0
- package/src/driver/bundler/symbols.ts +55 -0
- package/src/driver/bundler/types.ts +37 -0
- package/src/driver/modules.ts +9 -693
- package/src/extensions/catalog.ts +2 -1
- package/src/extensions/gui/index.ts +107 -0
- package/dist/tests/e2e/compile.test.d.ts +0 -8
- package/dist/tests/e2e/compile.test.js +0 -893
- package/dist/tests/e2e/compile.test.js.map +0 -1
- package/dist/tests/e2e/differential.test.d.ts +0 -7
- package/dist/tests/e2e/differential.test.js.map +0 -1
- package/dist/tests/e2e/runtime-coverage.test.d.ts +0 -11
- package/dist/tests/e2e/runtime-coverage.test.js +0 -646
- package/dist/tests/e2e/runtime-coverage.test.js.map +0 -1
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/* ------------------------------------------------------------------------- */
|
|
2
|
+
/* Arrays */
|
|
3
|
+
/* ------------------------------------------------------------------------- */
|
|
4
|
+
|
|
5
|
+
void xt_array_reserve(xt_array *array, uint32_t needed) {
|
|
6
|
+
if (needed <= array->capacity) return;
|
|
7
|
+
uint32_t capacity = array->capacity ? array->capacity * 2 : 8;
|
|
8
|
+
while (capacity < needed) capacity *= 2;
|
|
9
|
+
array->items = (xt_value *)realloc(array->items, sizeof(xt_value) * capacity);
|
|
10
|
+
if (!array->items) {
|
|
11
|
+
fprintf(stderr, "xbintsc: out of memory growing array\n");
|
|
12
|
+
abort();
|
|
13
|
+
}
|
|
14
|
+
for (uint32_t i = array->capacity; i < capacity; i++) array->items[i] = XT_UNDEFINED;
|
|
15
|
+
array->capacity = capacity;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
xt_value xt_array_new(int32_t count, xt_value *items) {
|
|
19
|
+
xt_array *array = (xt_array *)xt_alloc(sizeof(xt_array), XT_OBJECT_KIND_ARRAY);
|
|
20
|
+
array->length = 0;
|
|
21
|
+
array->capacity = 0;
|
|
22
|
+
array->items = NULL;
|
|
23
|
+
array->extra = XT_UNDEFINED;
|
|
24
|
+
if (count > 0) {
|
|
25
|
+
xt_array_reserve(array, (uint32_t)count);
|
|
26
|
+
for (int32_t i = 0; i < count; i++) array->items[i] = items[i];
|
|
27
|
+
array->length = (uint32_t)count;
|
|
28
|
+
}
|
|
29
|
+
return XT_FROM_PTR(XT_TAG_ARRAY, array);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* Named properties of an array live in a lazily-created side object. Returns
|
|
33
|
+
* XT_UNDEFINED when `create` is false and no such object exists yet. */
|
|
34
|
+
static xt_value xt_array_extra(xt_array *array, int create) {
|
|
35
|
+
if (!XT_IS_OBJECT(array->extra)) {
|
|
36
|
+
if (!create) return XT_UNDEFINED;
|
|
37
|
+
array->extra = xt_object_new();
|
|
38
|
+
}
|
|
39
|
+
return array->extra;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
xt_value xt_array_get(xt_value value, xt_value index) {
|
|
43
|
+
if (!XT_IS_ARRAY(value)) return XT_UNDEFINED;
|
|
44
|
+
xt_array *array = (xt_array *)XT_GET_PTR(value);
|
|
45
|
+
int32_t i = xt_to_int32(index);
|
|
46
|
+
if (i < 0 || (uint32_t)i >= array->length) return XT_UNDEFINED;
|
|
47
|
+
return array->items[i];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
xt_value xt_array_set(xt_value value, xt_value index, xt_value newValue) {
|
|
51
|
+
if (!XT_IS_ARRAY(value)) return newValue;
|
|
52
|
+
xt_array *array = (xt_array *)XT_GET_PTR(value);
|
|
53
|
+
int32_t i = xt_to_int32(index);
|
|
54
|
+
if (i < 0) return newValue;
|
|
55
|
+
xt_array_reserve(array, (uint32_t)i + 1);
|
|
56
|
+
for (uint32_t j = array->length; j < (uint32_t)i; j++) array->items[j] = XT_UNDEFINED;
|
|
57
|
+
array->items[i] = newValue;
|
|
58
|
+
if ((uint32_t)i >= array->length) array->length = (uint32_t)i + 1;
|
|
59
|
+
return newValue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
xt_value xt_array_push(xt_value value, xt_value newValue) {
|
|
63
|
+
if (!XT_IS_ARRAY(value)) return xt_number(0);
|
|
64
|
+
xt_array *array = (xt_array *)XT_GET_PTR(value);
|
|
65
|
+
xt_array_reserve(array, array->length + 1);
|
|
66
|
+
array->items[array->length++] = newValue;
|
|
67
|
+
return xt_number((double)array->length);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
xt_value xt_array_length(xt_value value) {
|
|
71
|
+
if (XT_IS_ARRAY(value)) return xt_number((double)((xt_array *)XT_GET_PTR(value))->length);
|
|
72
|
+
if (XT_IS_STRING(value)) return xt_number((double)xt_string_length(xt_as_string(value)));
|
|
73
|
+
/* Functions expose their arity as `.length`. */
|
|
74
|
+
if (XT_IS_FUNCTION(value)) {
|
|
75
|
+
int32_t arity = ((xt_function *)XT_GET_PTR(value))->arity;
|
|
76
|
+
return xt_number(arity >= 0 ? (double)arity : 0.0);
|
|
77
|
+
}
|
|
78
|
+
/* Objects such as Buffers expose a `length` property of their own. */
|
|
79
|
+
if (XT_IS_OBJECT(value)) return xt_object_get_cstr(value, "length");
|
|
80
|
+
return XT_UNDEFINED;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
xt_value xt_array_spread(xt_value target, xt_value source) {
|
|
84
|
+
if (!XT_IS_ARRAY(target)) return target;
|
|
85
|
+
if (XT_IS_ARRAY(source)) {
|
|
86
|
+
xt_array *dst = (xt_array *)XT_GET_PTR(target);
|
|
87
|
+
xt_array *src = (xt_array *)XT_GET_PTR(source);
|
|
88
|
+
xt_array_reserve(dst, dst->length + src->length);
|
|
89
|
+
for (uint32_t i = 0; i < src->length; i++) dst->items[dst->length++] = src->items[i];
|
|
90
|
+
return target;
|
|
91
|
+
}
|
|
92
|
+
/* Spreading a string/Map/Set/iterable iterates exactly like `for...of`. */
|
|
93
|
+
source = xt_iter_open(source);
|
|
94
|
+
for (int32_t i = 0; xt_truthy(xt_iter_has(source, xt_number((double)i))); i++) {
|
|
95
|
+
xt_array_push(target, xt_iter_value(source, xt_number((double)i)));
|
|
96
|
+
}
|
|
97
|
+
return target;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
int32_t xt_array_size(xt_value value) {
|
|
101
|
+
if (!XT_IS_ARRAY(value)) return 0;
|
|
102
|
+
return (int32_t)((xt_array *)XT_GET_PTR(value))->length;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
xt_value *xt_array_items(xt_value value) {
|
|
106
|
+
if (!XT_IS_ARRAY(value)) return NULL;
|
|
107
|
+
return ((xt_array *)XT_GET_PTR(value))->items;
|
|
108
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/* ------------------------------------------------------------------------- */
|
|
2
|
+
/* Boxes */
|
|
3
|
+
/* ------------------------------------------------------------------------- */
|
|
4
|
+
|
|
5
|
+
xt_value xt_box_new(xt_value value) { return xt_array_new(1, &value); }
|
|
6
|
+
|
|
7
|
+
xt_value xt_box_get(xt_value box) { return xt_array_get(box, xt_number(0)); }
|
|
8
|
+
|
|
9
|
+
xt_value xt_box_set(xt_value box, xt_value value) { return xt_array_set(box, xt_number(0), value); }
|
|
10
|
+
|
|
11
|
+
xt_value xt_is_nullish(xt_value value) { return xt_bool(value == XT_UNDEFINED || value == XT_NULL); }
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/* ------------------------------------------------------------------------- */
|
|
2
|
+
/* Objects */
|
|
3
|
+
/* ------------------------------------------------------------------------- */
|
|
4
|
+
|
|
5
|
+
static void xt_object_reserve(xt_object *obj, uint32_t needed) {
|
|
6
|
+
if (needed <= obj->capacity) return;
|
|
7
|
+
uint32_t capacity = obj->capacity ? obj->capacity * 2 : 8;
|
|
8
|
+
while (capacity < needed) capacity *= 2;
|
|
9
|
+
obj->properties = (xt_property *)realloc(obj->properties, sizeof(xt_property) * capacity);
|
|
10
|
+
if (!obj->properties) {
|
|
11
|
+
fprintf(stderr, "xbintsc: out of memory growing object\n");
|
|
12
|
+
abort();
|
|
13
|
+
}
|
|
14
|
+
obj->capacity = capacity;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
xt_value xt_object_new(void) { return xt_object_new_with_proto(XT_UNDEFINED); }
|
|
18
|
+
|
|
19
|
+
xt_value xt_object_new_with_proto(xt_value proto) {
|
|
20
|
+
xt_object *obj = (xt_object *)xt_alloc(sizeof(xt_object), XT_OBJECT_KIND_OBJECT);
|
|
21
|
+
obj->count = 0;
|
|
22
|
+
obj->capacity = 0;
|
|
23
|
+
obj->properties = NULL;
|
|
24
|
+
obj->prototype = proto;
|
|
25
|
+
obj->frozen = 0;
|
|
26
|
+
obj->is_array_base = 0;
|
|
27
|
+
return XT_FROM_PTR(XT_TAG_OBJECT, obj);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
xt_object *xt_as_object(xt_value value) {
|
|
31
|
+
if (XT_IS_OBJECT(value)) return (xt_object *)XT_GET_PTR(value);
|
|
32
|
+
if (XT_IS_FUNCTION(value)) {
|
|
33
|
+
/* Functions carry their own property bag (used for static members). */
|
|
34
|
+
xt_function *fn = (xt_function *)XT_GET_PTR(value);
|
|
35
|
+
if (!fn->properties) fn->properties = (xt_object *)XT_GET_PTR(xt_object_new_with_proto(XT_UNDEFINED));
|
|
36
|
+
return fn->properties;
|
|
37
|
+
}
|
|
38
|
+
return NULL;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static xt_property *xt_object_find(xt_object *obj, xt_value key) {
|
|
42
|
+
for (uint32_t i = 0; i < obj->count; i++) {
|
|
43
|
+
if (xt_property_key_equals(obj->properties[i].key, key)) return &obj->properties[i];
|
|
44
|
+
}
|
|
45
|
+
return NULL;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/*
|
|
49
|
+
* JavaScript enumerates own string keys in a canonical order: array-index
|
|
50
|
+
* keys (the canonical decimal form of an integer in [0, 2^32 - 2]) first, in
|
|
51
|
+
* ascending numeric order, then the remaining keys in insertion order. We keep
|
|
52
|
+
* the physical property array in exactly that order so every consumer
|
|
53
|
+
* (`Object.keys`, `for...in`, `JSON.stringify`, ...) is correct for free.
|
|
54
|
+
*/
|
|
55
|
+
static int xt_key_is_array_index(xt_string *key, uint32_t *out) {
|
|
56
|
+
if (key->length == 0 || key->length > 10) return 0;
|
|
57
|
+
if (key->data[0] == '0' && key->length != 1) return 0; /* "0" is canonical, "01" is not */
|
|
58
|
+
uint64_t value = 0;
|
|
59
|
+
for (uint32_t i = 0; i < key->length; i++) {
|
|
60
|
+
char ch = key->data[i];
|
|
61
|
+
if (ch < '0' || ch > '9') return 0;
|
|
62
|
+
value = value * 10 + (uint64_t)(ch - '0');
|
|
63
|
+
}
|
|
64
|
+
if (value > 4294967294ULL) return 0; /* 2^32 - 2 is the largest array index */
|
|
65
|
+
*out = (uint32_t)value;
|
|
66
|
+
return 1;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Insert a new property for `key`, preserving JavaScript key order. Symbols
|
|
70
|
+
* are not array indices and simply append in insertion order. */
|
|
71
|
+
static xt_property *xt_object_insert_property(xt_object *obj, xt_value key) {
|
|
72
|
+
uint32_t index = 0;
|
|
73
|
+
uint32_t position = obj->count;
|
|
74
|
+
if (XT_IS_STRING(key) && xt_key_is_array_index(xt_as_string(key), &index)) {
|
|
75
|
+
for (uint32_t i = 0; i < obj->count; i++) {
|
|
76
|
+
uint32_t existing = 0;
|
|
77
|
+
xt_value existingKey = obj->properties[i].key;
|
|
78
|
+
if (!XT_IS_STRING(existingKey) ||
|
|
79
|
+
!xt_key_is_array_index(xt_as_string(existingKey), &existing)) {
|
|
80
|
+
position = i; /* first non-index key: the integer prefix ends here */
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
if (existing > index) {
|
|
84
|
+
position = i;
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
xt_object_reserve(obj, obj->count + 1);
|
|
90
|
+
for (uint32_t i = obj->count; i > position; i--) obj->properties[i] = obj->properties[i - 1];
|
|
91
|
+
xt_property *prop = &obj->properties[position];
|
|
92
|
+
prop->key = key;
|
|
93
|
+
prop->value = XT_UNDEFINED;
|
|
94
|
+
prop->getter = XT_UNDEFINED;
|
|
95
|
+
prop->setter = XT_UNDEFINED;
|
|
96
|
+
obj->count++;
|
|
97
|
+
return prop;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
xt_property *xt_object_find_property(xt_object *obj, xt_value key) {
|
|
101
|
+
return obj ? xt_object_find(obj, key) : NULL;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Normalise a property key to a string value or a symbol value. */
|
|
105
|
+
xt_value xt_to_property_key(xt_value key) {
|
|
106
|
+
if (xt_is_symbol(key)) return key;
|
|
107
|
+
return xt_to_string(key);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* Two property keys are equal when they are the same symbol, or equal
|
|
111
|
+
* strings. */
|
|
112
|
+
int xt_property_key_equals(xt_value a, xt_value b) {
|
|
113
|
+
if (XT_IS_STRING(a) && XT_IS_STRING(b)) return xt_string_equals(xt_as_string(a), xt_as_string(b));
|
|
114
|
+
return a == b;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
static int xt_key_is_prototype(xt_value key) {
|
|
118
|
+
if (!XT_IS_STRING(key)) return 0;
|
|
119
|
+
xt_string *k = xt_as_string(key);
|
|
120
|
+
return k && k->length == 9 && memcmp(k->data, "prototype", 9) == 0;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
xt_value xt_object_get(xt_value value, xt_value key) {
|
|
124
|
+
/* A function's `.prototype` lives in a dedicated field (set by
|
|
125
|
+
`xt_function_set_prototype`), not in its property bag. Expose it as a
|
|
126
|
+
normal property so `Class.prototype` returns the object instances use. */
|
|
127
|
+
if (XT_IS_FUNCTION(value) && xt_key_is_prototype(key)) {
|
|
128
|
+
return ((xt_function *)XT_GET_PTR(value))->prototype;
|
|
129
|
+
}
|
|
130
|
+
xt_object *obj = xt_as_object(value);
|
|
131
|
+
if (!obj) return XT_UNDEFINED;
|
|
132
|
+
/* Only plain objects (and function property bags) use the `xt_object`
|
|
133
|
+
layout. Containers such as Map/Set/Date/RegExp/Promise/Array must not be
|
|
134
|
+
interpreted as property tables, or property lookup reads past the end of
|
|
135
|
+
their real representation. */
|
|
136
|
+
if (obj->header.kind != XT_OBJECT_KIND_OBJECT && obj->header.kind != XT_OBJECT_KIND_ERROR)
|
|
137
|
+
return XT_UNDEFINED;
|
|
138
|
+
xt_value k = xt_to_property_key(key);
|
|
139
|
+
/* Walk the prototype chain like JavaScript property lookup. */
|
|
140
|
+
xt_object *cur = obj;
|
|
141
|
+
while (cur) {
|
|
142
|
+
xt_property *prop = xt_object_find(cur, k);
|
|
143
|
+
if (prop) {
|
|
144
|
+
/* Invoke accessors with the original receiver as `this`, so getters
|
|
145
|
+
inherited from a prototype still see the instance. */
|
|
146
|
+
if (prop->getter != XT_UNDEFINED && XT_IS_FUNCTION(prop->getter)) {
|
|
147
|
+
return xt_call_with_this(prop->getter, value, 0, NULL);
|
|
148
|
+
}
|
|
149
|
+
if (prop->getter != XT_UNDEFINED) return XT_UNDEFINED;
|
|
150
|
+
return prop->value;
|
|
151
|
+
}
|
|
152
|
+
if (!XT_IS_OBJECT(cur->prototype)) break;
|
|
153
|
+
cur = (xt_object *)XT_GET_PTR(cur->prototype);
|
|
154
|
+
}
|
|
155
|
+
return XT_UNDEFINED;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
xt_value xt_object_set(xt_value value, xt_value key, xt_value newValue) {
|
|
159
|
+
if (XT_IS_FUNCTION(value) && xt_key_is_prototype(key)) {
|
|
160
|
+
return xt_function_set_prototype(value, newValue);
|
|
161
|
+
}
|
|
162
|
+
xt_object *obj = xt_as_object(value);
|
|
163
|
+
if (!obj) return newValue;
|
|
164
|
+
if (obj->header.kind != XT_OBJECT_KIND_OBJECT && obj->header.kind != XT_OBJECT_KIND_ERROR)
|
|
165
|
+
return newValue;
|
|
166
|
+
if (obj->frozen) return newValue;
|
|
167
|
+
xt_value k = xt_to_property_key(key);
|
|
168
|
+
xt_property *prop = xt_object_find(obj, k);
|
|
169
|
+
if (prop) {
|
|
170
|
+
if (prop->setter != XT_UNDEFINED) {
|
|
171
|
+
if (XT_IS_FUNCTION(prop->setter)) {
|
|
172
|
+
xt_value argument = newValue;
|
|
173
|
+
xt_call_with_this(prop->setter, value, 1, &argument);
|
|
174
|
+
}
|
|
175
|
+
return newValue;
|
|
176
|
+
}
|
|
177
|
+
if (prop->getter != XT_UNDEFINED) return newValue; /* accessor without setter */
|
|
178
|
+
prop->value = newValue;
|
|
179
|
+
return newValue;
|
|
180
|
+
}
|
|
181
|
+
/* No own property: an inherited accessor still intercepts the assignment
|
|
182
|
+
(JavaScript assigns through prototype setters instead of shadowing). */
|
|
183
|
+
xt_object *ancestor = XT_IS_OBJECT(obj->prototype) ? (xt_object *)XT_GET_PTR(obj->prototype) : NULL;
|
|
184
|
+
while (ancestor) {
|
|
185
|
+
xt_property *inherited = xt_object_find(ancestor, k);
|
|
186
|
+
if (inherited) {
|
|
187
|
+
if (inherited->setter != XT_UNDEFINED) {
|
|
188
|
+
if (XT_IS_FUNCTION(inherited->setter)) {
|
|
189
|
+
xt_value argument = newValue;
|
|
190
|
+
xt_call_with_this(inherited->setter, value, 1, &argument);
|
|
191
|
+
}
|
|
192
|
+
return newValue;
|
|
193
|
+
}
|
|
194
|
+
if (inherited->getter != XT_UNDEFINED) return newValue; /* getter-only accessor */
|
|
195
|
+
break; /* plain inherited data property: create an own shadowing property */
|
|
196
|
+
}
|
|
197
|
+
ancestor = XT_IS_OBJECT(ancestor->prototype) ? (xt_object *)XT_GET_PTR(ancestor->prototype) : NULL;
|
|
198
|
+
}
|
|
199
|
+
xt_property *inserted = xt_object_insert_property(obj, k);
|
|
200
|
+
inserted->value = newValue;
|
|
201
|
+
return newValue;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
static xt_property *xt_object_ensure_property(xt_object *obj, xt_value key) {
|
|
205
|
+
xt_value propertyKey = xt_to_property_key(key);
|
|
206
|
+
xt_property *prop = xt_object_find(obj, propertyKey);
|
|
207
|
+
if (prop) return prop;
|
|
208
|
+
return xt_object_insert_property(obj, propertyKey);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
xt_value xt_object_define_getter(xt_value value, xt_value key, xt_value getter) {
|
|
212
|
+
xt_object *obj = xt_as_object(value);
|
|
213
|
+
if (!obj) return value;
|
|
214
|
+
xt_object_ensure_property(obj, key)->getter = getter;
|
|
215
|
+
return value;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
xt_value xt_object_define_setter(xt_value value, xt_value key, xt_value setter) {
|
|
219
|
+
xt_object *obj = xt_as_object(value);
|
|
220
|
+
if (!obj) return value;
|
|
221
|
+
xt_object_ensure_property(obj, key)->setter = setter;
|
|
222
|
+
return value;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
xt_value xt_object_get_prototype(xt_value value) {
|
|
226
|
+
xt_object *obj = xt_as_object(value);
|
|
227
|
+
if (obj) return obj->prototype;
|
|
228
|
+
return XT_UNDEFINED;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
xt_value xt_object_set_prototype(xt_value value, xt_value proto) {
|
|
232
|
+
xt_object *obj = xt_as_object(value);
|
|
233
|
+
if (obj && !obj->frozen) obj->prototype = proto;
|
|
234
|
+
return value;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
xt_value xt_object_freeze(xt_value value) {
|
|
238
|
+
xt_object *obj = xt_as_object(value);
|
|
239
|
+
if (obj) obj->frozen = 1;
|
|
240
|
+
return value;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
int xt_object_is_frozen(xt_value value) {
|
|
244
|
+
xt_object *obj = xt_as_object(value);
|
|
245
|
+
return obj ? obj->frozen : 0;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
xt_value xt_object_has_own(xt_value value, xt_value key) {
|
|
249
|
+
xt_object *obj = xt_as_object(value);
|
|
250
|
+
if (!obj) return XT_FALSE;
|
|
251
|
+
return xt_bool(xt_object_find(obj, xt_to_property_key(key)) != NULL);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
xt_value xt_object_from_entries(xt_value entries) {
|
|
255
|
+
xt_value result = xt_object_new();
|
|
256
|
+
xt_array *array = xt_as_array(entries);
|
|
257
|
+
if (!array) return result;
|
|
258
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
259
|
+
xt_array *pair = xt_as_array(array->items[i]);
|
|
260
|
+
if (!pair || pair->length < 2) continue;
|
|
261
|
+
xt_object_set(result, pair->items[0], pair->items[1]);
|
|
262
|
+
}
|
|
263
|
+
return result;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
xt_value xt_object_has(xt_value value, xt_value key) {
|
|
267
|
+
if (!XT_IS_OBJECT(value)) return XT_FALSE;
|
|
268
|
+
xt_object *obj = (xt_object *)XT_GET_PTR(value);
|
|
269
|
+
return xt_bool(xt_object_find(obj, xt_to_property_key(key)) != NULL);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/* `Object.getOwnPropertySymbols`: the symbol-keyed own properties, in
|
|
273
|
+
* insertion order. String keys are skipped. */
|
|
274
|
+
xt_value xt_object_own_property_symbols(xt_value value) {
|
|
275
|
+
xt_value result = xt_array_new(0, NULL);
|
|
276
|
+
if (!XT_IS_OBJECT(value)) return result;
|
|
277
|
+
xt_object *obj = (xt_object *)XT_GET_PTR(value);
|
|
278
|
+
if (obj->header.kind != XT_OBJECT_KIND_OBJECT && obj->header.kind != XT_OBJECT_KIND_ERROR)
|
|
279
|
+
return result;
|
|
280
|
+
for (uint32_t i = 0; i < obj->count; i++) {
|
|
281
|
+
if (xt_is_symbol(obj->properties[i].key)) xt_array_push(result, obj->properties[i].key);
|
|
282
|
+
}
|
|
283
|
+
return result;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
xt_value xt_object_keys(xt_value value) {
|
|
287
|
+
xt_value result = xt_array_new(0, NULL);
|
|
288
|
+
if (XT_IS_OBJECT(value)) {
|
|
289
|
+
xt_object *obj = (xt_object *)XT_GET_PTR(value);
|
|
290
|
+
for (uint32_t i = 0; i < obj->count; i++) {
|
|
291
|
+
if (XT_IS_STRING(obj->properties[i].key)) xt_array_push(result, obj->properties[i].key);
|
|
292
|
+
}
|
|
293
|
+
return result;
|
|
294
|
+
}
|
|
295
|
+
if (XT_IS_ARRAY(value)) {
|
|
296
|
+
xt_array *array = (xt_array *)XT_GET_PTR(value);
|
|
297
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
298
|
+
char buffer[32];
|
|
299
|
+
snprintf(buffer, sizeof(buffer), "%u", i);
|
|
300
|
+
xt_array_push(result, xt_string_from_cstr(buffer));
|
|
301
|
+
}
|
|
302
|
+
if (XT_IS_OBJECT(array->extra)) {
|
|
303
|
+
xt_object *extra = (xt_object *)XT_GET_PTR(array->extra);
|
|
304
|
+
for (uint32_t i = 0; i < extra->count; i++) {
|
|
305
|
+
if (XT_IS_STRING(extra->properties[i].key)) xt_array_push(result, extra->properties[i].key);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return result;
|
|
309
|
+
}
|
|
310
|
+
if (XT_IS_STRING(value)) {
|
|
311
|
+
xt_string *s = xt_as_string(value);
|
|
312
|
+
for (uint32_t i = 0; i < s->length; i++) {
|
|
313
|
+
char buffer[32];
|
|
314
|
+
snprintf(buffer, sizeof(buffer), "%u", i);
|
|
315
|
+
xt_array_push(result, xt_string_from_cstr(buffer));
|
|
316
|
+
}
|
|
317
|
+
return result;
|
|
318
|
+
}
|
|
319
|
+
return result;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/* Convenience used by codegen for `obj.prop`. */
|
|
323
|
+
xt_value xt_object_get_cstr(xt_value value, const char *key) {
|
|
324
|
+
xt_value k = xt_string_from_cstr(key);
|
|
325
|
+
return xt_object_get(value, k);
|
|
326
|
+
}
|