@ugo-studio/jspp 0.3.0 → 0.3.2

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.
Files changed (127) hide show
  1. package/LICENSE +25 -25
  2. package/README.md +20 -12
  3. package/dist/cli/args.js +22 -0
  4. package/dist/cli/compiler.js +53 -0
  5. package/dist/cli/index.js +43 -107
  6. package/dist/cli/pch.js +71 -0
  7. package/dist/cli/runner.js +23 -0
  8. package/dist/cli/spinner.js +27 -11
  9. package/dist/cli/transpiler.js +20 -0
  10. package/dist/cli/utils.js +59 -0
  11. package/dist/cli/wasm.js +70 -0
  12. package/dist/index.js +17 -6
  13. package/dist/{analysis → interpreter/analysis}/scope.js +38 -3
  14. package/dist/{analysis → interpreter/analysis}/typeAnalyzer.js +563 -28
  15. package/dist/{core → interpreter/core}/codegen/class-handlers.js +1 -1
  16. package/dist/{core → interpreter/core}/codegen/control-flow-handlers.js +12 -11
  17. package/dist/{core → interpreter/core}/codegen/declaration-handlers.js +28 -9
  18. package/dist/{core → interpreter/core}/codegen/destructuring-handlers.js +9 -4
  19. package/dist/{core → interpreter/core}/codegen/expression-handlers.js +82 -88
  20. package/dist/{core → interpreter/core}/codegen/function-handlers.js +159 -46
  21. package/dist/{core → interpreter/core}/codegen/helpers.js +170 -25
  22. package/dist/interpreter/core/codegen/index.js +156 -0
  23. package/dist/{core → interpreter/core}/codegen/literal-handlers.js +9 -0
  24. package/dist/{core → interpreter/core}/codegen/statement-handlers.js +47 -7
  25. package/package.json +6 -4
  26. package/scripts/precompile-headers.ts +293 -50
  27. package/scripts/setup-compiler.ts +63 -63
  28. package/scripts/setup-emsdk.ts +114 -0
  29. package/src/prelude/any_value.cpp +888 -0
  30. package/src/prelude/any_value.hpp +29 -24
  31. package/src/prelude/{exception_helpers.hpp → exception.cpp} +53 -53
  32. package/src/prelude/exception.hpp +27 -27
  33. package/src/prelude/iterator_instantiations.hpp +10 -0
  34. package/src/prelude/{index.hpp → jspp.hpp} +13 -17
  35. package/src/prelude/library/array.cpp +191 -0
  36. package/src/prelude/library/array.hpp +5 -178
  37. package/src/prelude/library/boolean.cpp +30 -0
  38. package/src/prelude/library/boolean.hpp +14 -0
  39. package/src/prelude/library/console.cpp +125 -0
  40. package/src/prelude/library/console.hpp +9 -97
  41. package/src/prelude/library/error.cpp +100 -0
  42. package/src/prelude/library/error.hpp +8 -108
  43. package/src/prelude/library/function.cpp +69 -0
  44. package/src/prelude/library/function.hpp +6 -5
  45. package/src/prelude/library/global.cpp +98 -0
  46. package/src/prelude/library/global.hpp +12 -28
  47. package/src/prelude/library/global_usings.hpp +15 -0
  48. package/src/prelude/library/math.cpp +261 -0
  49. package/src/prelude/library/math.hpp +8 -288
  50. package/src/prelude/library/object.cpp +379 -0
  51. package/src/prelude/library/object.hpp +5 -267
  52. package/src/prelude/library/performance.cpp +21 -0
  53. package/src/prelude/library/performance.hpp +5 -20
  54. package/src/prelude/library/process.cpp +38 -0
  55. package/src/prelude/library/process.hpp +3 -31
  56. package/src/prelude/library/promise.cpp +131 -0
  57. package/src/prelude/library/promise.hpp +5 -116
  58. package/src/prelude/library/symbol.cpp +56 -0
  59. package/src/prelude/library/symbol.hpp +5 -46
  60. package/src/prelude/library/timer.cpp +88 -0
  61. package/src/prelude/library/timer.hpp +11 -87
  62. package/src/prelude/runtime.cpp +19 -0
  63. package/src/prelude/types.hpp +26 -20
  64. package/src/prelude/utils/access.hpp +123 -32
  65. package/src/prelude/utils/assignment_operators.hpp +119 -99
  66. package/src/prelude/utils/log_any_value/array.hpp +61 -40
  67. package/src/prelude/utils/log_any_value/function.hpp +39 -39
  68. package/src/prelude/utils/log_any_value/log_any_value.hpp +1 -1
  69. package/src/prelude/utils/log_any_value/object.hpp +60 -3
  70. package/src/prelude/utils/log_any_value/primitives.hpp +1 -1
  71. package/src/prelude/utils/operators.hpp +109 -94
  72. package/src/prelude/utils/operators_native.hpp +349 -0
  73. package/src/prelude/utils/well_known_symbols.hpp +24 -24
  74. package/src/prelude/values/array.cpp +1399 -0
  75. package/src/prelude/values/array.hpp +4 -0
  76. package/src/prelude/values/async_iterator.cpp +251 -0
  77. package/src/prelude/values/async_iterator.hpp +60 -32
  78. package/src/prelude/values/boolean.cpp +64 -0
  79. package/src/prelude/values/function.cpp +262 -0
  80. package/src/prelude/values/function.hpp +10 -30
  81. package/src/prelude/values/iterator.cpp +309 -0
  82. package/src/prelude/values/iterator.hpp +33 -64
  83. package/src/prelude/values/number.cpp +221 -0
  84. package/src/prelude/values/object.cpp +200 -0
  85. package/src/prelude/values/object.hpp +4 -0
  86. package/src/prelude/values/promise.cpp +479 -0
  87. package/src/prelude/values/promise.hpp +9 -2
  88. package/src/prelude/values/prototypes/array.hpp +46 -1348
  89. package/src/prelude/values/prototypes/async_iterator.hpp +19 -61
  90. package/src/prelude/values/prototypes/boolean.hpp +24 -0
  91. package/src/prelude/values/prototypes/function.hpp +7 -46
  92. package/src/prelude/values/prototypes/iterator.hpp +15 -191
  93. package/src/prelude/values/prototypes/number.hpp +30 -210
  94. package/src/prelude/values/prototypes/object.hpp +7 -23
  95. package/src/prelude/values/prototypes/promise.hpp +8 -186
  96. package/src/prelude/values/prototypes/string.hpp +28 -553
  97. package/src/prelude/values/prototypes/symbol.hpp +9 -70
  98. package/src/prelude/values/shape.hpp +52 -52
  99. package/src/prelude/values/string.cpp +485 -0
  100. package/src/prelude/values/symbol.cpp +89 -0
  101. package/src/prelude/values/symbol.hpp +101 -101
  102. package/dist/cli/file-utils.js +0 -20
  103. package/dist/cli-utils/args.js +0 -59
  104. package/dist/cli-utils/colors.js +0 -9
  105. package/dist/cli-utils/file-utils.js +0 -20
  106. package/dist/cli-utils/spinner.js +0 -55
  107. package/dist/cli.js +0 -153
  108. package/dist/core/codegen/index.js +0 -86
  109. package/src/prelude/any_value_access.hpp +0 -170
  110. package/src/prelude/any_value_defines.hpp +0 -190
  111. package/src/prelude/any_value_helpers.hpp +0 -374
  112. package/src/prelude/utils/operators_primitive.hpp +0 -337
  113. package/src/prelude/values/helpers/array.hpp +0 -199
  114. package/src/prelude/values/helpers/async_iterator.hpp +0 -275
  115. package/src/prelude/values/helpers/function.hpp +0 -109
  116. package/src/prelude/values/helpers/iterator.hpp +0 -145
  117. package/src/prelude/values/helpers/object.hpp +0 -104
  118. package/src/prelude/values/helpers/promise.hpp +0 -254
  119. package/src/prelude/values/helpers/string.hpp +0 -37
  120. package/src/prelude/values/helpers/symbol.hpp +0 -21
  121. /package/dist/{ast → interpreter/ast}/symbols.js +0 -0
  122. /package/dist/{ast → interpreter/ast}/types.js +0 -0
  123. /package/dist/{core → interpreter/core}/codegen/visitor.js +0 -0
  124. /package/dist/{core → interpreter/core}/constants.js +0 -0
  125. /package/dist/{core → interpreter/core}/error.js +0 -0
  126. /package/dist/{core → interpreter/core}/parser.js +0 -0
  127. /package/dist/{core → interpreter/core}/traverser.js +0 -0
@@ -0,0 +1,379 @@
1
+ #include "jspp.hpp"
2
+ #include "library/object.hpp"
3
+
4
+ namespace jspp {
5
+ jspp::AnyValue Object = jspp::AnyValue::make_class(
6
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>([](jspp::AnyValue thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
7
+ {
8
+ if (args.empty() || args[0].is_undefined() || args[0].is_null()) {
9
+ return jspp::AnyValue::make_object({});
10
+ }
11
+ if (args[0].is_object() || args[0].is_array() || args[0].is_function() || args[0].is_promise() || args[0].is_iterator()) {
12
+ return args[0];
13
+ }
14
+ return jspp::AnyValue::make_object({});
15
+ }), "Object");
16
+
17
+ struct ObjectInit
18
+ {
19
+ ObjectInit()
20
+ {
21
+ Object.define_data_property("keys", jspp::AnyValue::make_function(
22
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
23
+ {
24
+ if (args.empty()) throw jspp::Exception::make_exception("Object.keys called on non-object", "TypeError");
25
+ auto obj = args[0];
26
+ if (obj.is_null() || obj.is_undefined()) throw jspp::Exception::make_exception("Object.keys called on null or undefined", "TypeError");
27
+
28
+ auto keys = jspp::Access::get_object_keys(obj);
29
+ std::vector<jspp::AnyValue> keyValues;
30
+ for(const auto& k : keys) {
31
+ keyValues.push_back(k);
32
+ }
33
+ return jspp::AnyValue::make_array(std::move(keyValues));
34
+ }), "keys"));
35
+
36
+ Object.define_data_property("values", jspp::AnyValue::make_function(
37
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
38
+ {
39
+ if (args.empty()) throw jspp::Exception::make_exception("Object.values called on non-object", "TypeError");
40
+ auto obj = args[0];
41
+ if (obj.is_null() || obj.is_undefined()) throw jspp::Exception::make_exception("Object.values called on null or undefined", "TypeError");
42
+
43
+ auto keys = jspp::Access::get_object_keys(obj);
44
+ std::vector<jspp::AnyValue> values;
45
+ for(const auto& k : keys) {
46
+ values.push_back(obj.get_own_property(k));
47
+ }
48
+ return jspp::AnyValue::make_array(std::move(values));
49
+ }), "values"));
50
+
51
+ Object.define_data_property("entries", jspp::AnyValue::make_function(
52
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
53
+ {
54
+ if (args.empty()) throw jspp::Exception::make_exception("Object.entries called on non-object", "TypeError");
55
+ auto obj = args[0];
56
+ if (obj.is_null() || obj.is_undefined()) throw jspp::Exception::make_exception("Object.entries called on null or undefined", "TypeError");
57
+
58
+ auto keys = jspp::Access::get_object_keys(obj);
59
+ std::vector<jspp::AnyValue> entries;
60
+ for(const auto& k : keys) {
61
+ std::vector<jspp::AnyValue> entry;
62
+ entry.push_back(k);
63
+ entry.push_back(obj.get_own_property(k));
64
+ entries.push_back(jspp::AnyValue::make_array(std::move(entry)));
65
+ }
66
+ return jspp::AnyValue::make_array(std::move(entries));
67
+ }), "entries"));
68
+
69
+ Object.define_data_property("assign", jspp::AnyValue::make_function(
70
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
71
+ {
72
+ if (args.empty()) throw jspp::Exception::make_exception("Cannot convert undefined or null to object", "TypeError");
73
+ auto target = args[0];
74
+ if (target.is_null() || target.is_undefined()) throw jspp::Exception::make_exception("Cannot convert undefined or null to object", "TypeError");
75
+
76
+ for (size_t i = 1; i < args.size(); ++i) {
77
+ auto source = args[i];
78
+ if (source.is_null() || source.is_undefined()) continue;
79
+
80
+ auto keys = jspp::Access::get_object_keys(source, true);
81
+ for(const auto& k : keys) {
82
+ auto val = source.get_own_property(k);
83
+ target.set_own_property(k, val);
84
+ }
85
+ }
86
+ return target;
87
+ }), "assign"));
88
+
89
+ Object.define_data_property("getOwnPropertySymbols", jspp::AnyValue::make_function(
90
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
91
+ {
92
+ if (args.empty()) throw jspp::Exception::make_exception("Object.getOwnPropertySymbols called on non-object", "TypeError");
93
+ auto obj = args[0];
94
+ if (obj.is_null() || obj.is_undefined()) throw jspp::Exception::make_exception("Object.getOwnPropertySymbols called on null or undefined", "TypeError");
95
+
96
+ auto keys = jspp::Access::get_object_keys(obj, true);
97
+ std::vector<jspp::AnyValue> symbolValues;
98
+ for(const auto& k : keys) {
99
+ if (k.is_symbol()) symbolValues.push_back(k);
100
+ }
101
+ return jspp::AnyValue::make_array(std::move(symbolValues));
102
+ }), "getOwnPropertySymbols"));
103
+
104
+ Object.define_data_property("is", jspp::AnyValue::make_function(
105
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
106
+ {
107
+ jspp::AnyValue v1 = args.size() > 0 ? args[0] : jspp::Constants::UNDEFINED;
108
+ jspp::AnyValue v2 = args.size() > 1 ? args[1] : jspp::Constants::UNDEFINED;
109
+
110
+ if (v1.is_number() && v2.is_number()) {
111
+ double d1 = v1.as_double();
112
+ double d2 = v2.as_double();
113
+ if (std::isnan(d1) && std::isnan(d2)) return jspp::Constants::TRUE;
114
+ if (d1 == 0 && d2 == 0) {
115
+ return jspp::AnyValue::make_boolean(std::signbit(d1) == std::signbit(d2));
116
+ }
117
+ return jspp::AnyValue::make_boolean(d1 == d2);
118
+ }
119
+
120
+ return jspp::is_strictly_equal_to(v1, v2);
121
+ }), "is"));
122
+
123
+ Object.define_data_property("getPrototypeOf", jspp::AnyValue::make_function(
124
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
125
+ {
126
+ if (args.empty()) throw jspp::Exception::make_exception("Object.getPrototypeOf called on non-object", "TypeError");
127
+ auto obj = args[0];
128
+
129
+ if (obj.is_object()) {
130
+ return obj.as_object()->proto;
131
+ }
132
+ if (obj.is_array()) {
133
+ return obj.as_array()->proto;
134
+ }
135
+ if (obj.is_function()) {
136
+ return obj.as_function()->proto;
137
+ }
138
+
139
+ return jspp::Constants::Null;
140
+ }), "getPrototypeOf"));
141
+
142
+ Object.define_data_property("setPrototypeOf", jspp::AnyValue::make_function(
143
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
144
+ {
145
+ if (args.size() < 2) throw jspp::Exception::make_exception("Object.setPrototypeOf requires at least 2 arguments", "TypeError");
146
+ auto obj = args[0];
147
+ auto proto = args[1];
148
+
149
+ if (!proto.is_object() && !proto.is_null()) {
150
+ throw jspp::Exception::make_exception("Object prototype may only be an Object or null", "TypeError");
151
+ }
152
+
153
+ if (obj.is_object()) {
154
+ obj.as_object()->proto = proto;
155
+ } else if (obj.is_array()) {
156
+ obj.as_array()->proto = proto;
157
+ } else if (obj.is_function()) {
158
+ obj.as_function()->proto = proto;
159
+ }
160
+
161
+ return obj;
162
+ }), "setPrototypeOf"));
163
+
164
+ Object.define_data_property("create", jspp::AnyValue::make_function(
165
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
166
+ {
167
+ if (args.empty()) throw jspp::Exception::make_exception("Object prototype may only be an Object or null", "TypeError");
168
+ auto proto = args[0];
169
+ if (!proto.is_object() && !proto.is_null()) {
170
+ throw jspp::Exception::make_exception("Object prototype may only be an Object or null", "TypeError");
171
+ }
172
+
173
+ auto newObj = jspp::AnyValue::make_object({}).set_prototype(proto);
174
+ return newObj;
175
+ }), "create"));
176
+
177
+ auto getDescHelper = [](jspp::AnyValue descVal) -> jspp::AnyValue
178
+ {
179
+ if (descVal.is_undefined())
180
+ return jspp::Constants::UNDEFINED;
181
+
182
+ auto result = jspp::AnyValue::make_object({});
183
+
184
+ if (descVal.is_data_descriptor())
185
+ {
186
+ auto d = descVal.as_data_descriptor();
187
+ result.set_own_property("value", d->value);
188
+ result.set_own_property("writable", jspp::AnyValue::make_boolean(d->writable));
189
+ result.set_own_property("enumerable", jspp::AnyValue::make_boolean(d->enumerable));
190
+ result.set_own_property("configurable", jspp::AnyValue::make_boolean(d->configurable));
191
+ }
192
+ else if (descVal.is_accessor_descriptor())
193
+ {
194
+ auto a = descVal.as_accessor_descriptor();
195
+ if (a->get.has_value())
196
+ {
197
+ result.set_own_property("get", jspp::AnyValue::make_function(
198
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>(a->get.value()), std::nullopt));
199
+ }
200
+ else
201
+ {
202
+ result.set_own_property("get", jspp::Constants::UNDEFINED);
203
+ }
204
+
205
+ if (a->set.has_value())
206
+ {
207
+ result.set_own_property("set", jspp::AnyValue::make_function(
208
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>(a->set.value()), std::nullopt));
209
+ }
210
+ else
211
+ {
212
+ result.set_own_property("set", jspp::Constants::UNDEFINED);
213
+ }
214
+ result.set_own_property("enumerable", jspp::AnyValue::make_boolean(a->enumerable));
215
+ result.set_own_property("configurable", jspp::AnyValue::make_boolean(a->configurable));
216
+ }
217
+ return result;
218
+ };
219
+
220
+ Object.define_data_property("getOwnPropertyDescriptor", jspp::AnyValue::make_function(
221
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>( [getDescHelper](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
222
+ {
223
+ if (args.empty()) throw jspp::Exception::make_exception("Object.getOwnPropertyDescriptor called on non-object", "TypeError");
224
+ auto obj = args[0];
225
+ if (obj.is_null() || obj.is_undefined()) throw jspp::Exception::make_exception("Object.getOwnPropertyDescriptor called on null or undefined", "TypeError");
226
+ jspp::AnyValue prop = args.size() > 1 ? args[1] : jspp::Constants::UNDEFINED;
227
+ return getDescHelper(obj.get_own_property_descriptor(prop));
228
+ }), "getOwnPropertyDescriptor"));
229
+
230
+ Object.define_data_property("defineProperty", jspp::AnyValue::make_function(
231
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
232
+ {
233
+ if (args.size() < 3) throw jspp::Exception::make_exception("Object.defineProperty requires 3 arguments", "TypeError");
234
+ auto obj = args[0];
235
+ if (!obj.is_object() && !obj.is_array() && !obj.is_function()) throw jspp::Exception::make_exception("Object.defineProperty called on non-object", "TypeError");
236
+
237
+ std::string prop = args[1].to_std_string();
238
+ auto descObj = args[2];
239
+
240
+ bool enumerable = false;
241
+ bool configurable = false;
242
+ bool writable = false;
243
+
244
+ if (descObj.has_property("enumerable")) enumerable = jspp::is_truthy(descObj.get_own_property("enumerable"));
245
+ if (descObj.has_property("configurable")) configurable = jspp::is_truthy(descObj.get_own_property("configurable"));
246
+ if (descObj.has_property("writable")) writable = jspp::is_truthy(descObj.get_own_property("writable"));
247
+
248
+ bool hasValue = descObj.has_property("value");
249
+ bool hasGet = descObj.has_property("get");
250
+ bool hasSet = descObj.has_property("set");
251
+
252
+ if (hasValue && (hasGet || hasSet)) {
253
+ throw jspp::Exception::make_exception("Invalid property descriptor. Cannot both specify accessors and a value or writable attribute", "TypeError");
254
+ }
255
+
256
+ if (hasValue) {
257
+ auto value = descObj.get_own_property("value");
258
+ obj.define_data_property(prop, value, writable, enumerable, configurable);
259
+ } else {
260
+ jspp::AnyValue getter = jspp::Constants::UNDEFINED;
261
+ jspp::AnyValue setter = jspp::Constants::UNDEFINED;
262
+
263
+ if (hasGet) getter = descObj.get_own_property("get");
264
+ if (hasSet) setter = descObj.get_own_property("set");
265
+
266
+ if (!getter.is_undefined() && !getter.is_function()) throw jspp::Exception::make_exception("Getter must be a function", "TypeError");
267
+ if (!setter.is_undefined() && !setter.is_function()) throw jspp::Exception::make_exception("Setter must be a function", "TypeError");
268
+
269
+ if (obj.is_object()) {
270
+ auto o_ptr = obj.as_object();
271
+ std::optional<std::function<jspp::AnyValue(jspp::AnyValue, std::span<const jspp::AnyValue>)>> getFunc;
272
+ std::optional<std::function<jspp::AnyValue(jspp::AnyValue, std::span<const jspp::AnyValue>)>> setFunc;
273
+
274
+ if (getter.is_function()) {
275
+ getFunc = [getter](jspp::AnyValue thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue {
276
+ return getter.call(thisVal, args);
277
+ };
278
+ }
279
+ if (setter.is_function()) {
280
+ setFunc = [setter](jspp::AnyValue thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue {
281
+ return setter.call(thisVal, args);
282
+ };
283
+ }
284
+
285
+ auto desc = jspp::AnyValue::make_accessor_descriptor(getFunc, setFunc, enumerable, configurable);
286
+ auto offset = o_ptr->shape->get_offset(prop);
287
+ if (offset.has_value()) {
288
+ o_ptr->storage[offset.value()] = desc;
289
+ } else {
290
+ o_ptr->shape = o_ptr->shape->transition(prop);
291
+ o_ptr->storage.push_back(desc);
292
+ }
293
+ }
294
+ }
295
+ return obj;
296
+ }), "defineProperty"));
297
+
298
+ Object.define_data_property("hasOwn", jspp::AnyValue::make_function(
299
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
300
+ {
301
+ if (args.empty()) throw jspp::Exception::make_exception("Object.hasOwn called on non-object", "TypeError");
302
+ auto obj = args[0];
303
+ if (obj.is_null() || obj.is_undefined()) throw jspp::Exception::make_exception("Object.hasOwn called on null or undefined", "TypeError");
304
+ std::string prop = args.size() > 1 ? args[1].to_std_string() : "undefined";
305
+
306
+ if (obj.is_object()) return jspp::AnyValue::make_boolean(obj.as_object()->shape->get_offset(prop).has_value());
307
+ if (obj.is_function()) return jspp::AnyValue::make_boolean(obj.as_function()->props.count(prop));
308
+ if (obj.is_array()) {
309
+ if (prop == "length") return jspp::Constants::TRUE;
310
+ if (jspp::JsArray::is_array_index(prop)) {
311
+ uint32_t idx = static_cast<uint32_t>(std::stoull(prop));
312
+ auto arr = obj.as_array();
313
+ if (idx < arr->dense.size() && !(arr->dense[idx].is_uninitialized())) return jspp::Constants::TRUE;
314
+ if (arr->sparse.count(idx)) return jspp::Constants::TRUE;
315
+ return jspp::Constants::FALSE;
316
+ }
317
+ return jspp::AnyValue::make_boolean(obj.as_array()->props.count(prop));
318
+ }
319
+ return jspp::Constants::FALSE;
320
+ }), "hasOwn"));
321
+
322
+ auto proto = Object.get_own_property("prototype");
323
+ proto.define_data_property("hasOwnProperty", jspp::AnyValue::make_function(
324
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>([](jspp::AnyValue thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
325
+ {
326
+ std::string prop = args.size() > 0 ? args[0].to_std_string() : "undefined";
327
+ if (thisVal.is_object()) return jspp::AnyValue::make_boolean(thisVal.as_object()->shape->get_offset(prop).has_value());
328
+ if (thisVal.is_function()) return jspp::AnyValue::make_boolean(thisVal.as_function()->props.count(prop));
329
+ if (thisVal.is_array()) {
330
+ if (prop == "length") return jspp::Constants::TRUE;
331
+ if (jspp::JsArray::is_array_index(prop)) {
332
+ uint32_t idx = static_cast<uint32_t>(std::stoull(prop));
333
+ auto arr = thisVal.as_array();
334
+ if (idx < arr->dense.size() && !(arr->dense[idx].is_uninitialized())) return jspp::Constants::TRUE;
335
+ if (arr->sparse.count(idx)) return jspp::Constants::TRUE;
336
+ return jspp::Constants::FALSE;
337
+ }
338
+ return jspp::AnyValue::make_boolean(thisVal.as_array()->props.count(prop));
339
+ }
340
+ return jspp::Constants::FALSE;
341
+ }), "hasOwnProperty"), true, false, true);
342
+
343
+ auto toStringFn = jspp::ObjectPrototypes::get("toString");
344
+ if (toStringFn.has_value()) {
345
+ proto.define_data_property("toString", toStringFn.value(), true, false, true);
346
+ }
347
+
348
+ proto.define_data_property("valueOf", jspp::AnyValue::make_function(
349
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>([](jspp::AnyValue thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
350
+ { return thisVal; }), "valueOf"), true, false, true);
351
+
352
+ proto.define_data_property("isPrototypeOf", jspp::AnyValue::make_function(
353
+ std::function<AnyValue(AnyValue, std::span<const AnyValue>)>([](jspp::AnyValue thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
354
+ {
355
+ if (args.empty() || !args[0].is_object()) return jspp::Constants::FALSE;
356
+ auto target = args[0];
357
+ auto current = target.get_own_property("__proto__");
358
+ if (current.is_undefined()) {
359
+ if (target.is_object()) current = target.as_object()->proto;
360
+ else if (target.is_array()) current = target.as_array()->proto;
361
+ else if (target.is_function()) current = target.as_function()->proto;
362
+ }
363
+
364
+ while (!current.is_null()) {
365
+ if (jspp::is_strictly_equal_to_native(current, thisVal)) return jspp::Constants::TRUE;
366
+ if (current.is_object()) current = current.as_object()->proto;
367
+ else if (current.is_array()) current = current.as_array()->proto;
368
+ else if (current.is_function()) current = current.as_function()->proto;
369
+ else break;
370
+ }
371
+ return jspp::Constants::FALSE;
372
+ }), "isPrototypeOf"), true, false, true);
373
+ }
374
+ };
375
+ void init_object()
376
+ {
377
+ static ObjectInit objectInit;
378
+ }
379
+ }
@@ -5,272 +5,10 @@
5
5
  #include "utils/access.hpp"
6
6
  #include "exception.hpp"
7
7
 
8
- // Define Object constructor
9
- inline auto Object = jspp::AnyValue::make_class([](jspp::AnyValue thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
10
- {
11
- if (args.empty() || args[0].is_undefined() || args[0].is_null()) {
12
- return jspp::AnyValue::make_object({});
13
- }
14
- // Return argument if it is an object
15
- if (args[0].is_object() || args[0].is_array() || args[0].is_function() || args[0].is_promise() || args[0].is_iterator()) {
16
- return args[0];
17
- }
18
- // TODO: Wrapper objects for primitives
19
- return jspp::AnyValue::make_object({}); }, "Object");
20
-
21
- struct ObjectInit
8
+ namespace jspp
22
9
  {
23
- ObjectInit()
24
- {
25
- // Object.keys(obj)
26
- Object.define_data_property("keys", jspp::AnyValue::make_function([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
27
- {
28
- if (args.empty()) throw jspp::Exception::make_exception("Object.keys called on non-object", "TypeError");
29
- auto obj = args[0];
30
- if (obj.is_null() || obj.is_undefined()) throw jspp::Exception::make_exception("Object.keys called on null or undefined", "TypeError");
31
-
32
- auto keys = jspp::Access::get_object_keys(obj);
33
- std::vector<jspp::AnyValue> keyValues;
34
- for(const auto& k : keys) {
35
- keyValues.push_back(jspp::AnyValue::make_string(k));
36
- }
37
- return jspp::AnyValue::make_array(std::move(keyValues)); }, "keys"));
38
-
39
- // Object.values(obj)
40
- Object.define_data_property("values", jspp::AnyValue::make_function([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
41
- {
42
- if (args.empty()) throw jspp::Exception::make_exception("Object.values called on non-object", "TypeError");
43
- auto obj = args[0];
44
- if (obj.is_null() || obj.is_undefined()) throw jspp::Exception::make_exception("Object.values called on null or undefined", "TypeError");
45
-
46
- auto keys = jspp::Access::get_object_keys(obj);
47
- std::vector<jspp::AnyValue> values;
48
- for(const auto& k : keys) {
49
- values.push_back(obj.get_property_with_receiver(k, obj));
50
- }
51
- return jspp::AnyValue::make_array(std::move(values)); }, "values"));
52
-
53
- // Object.entries(obj)
54
- Object.define_data_property("entries", jspp::AnyValue::make_function([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
55
- {
56
- if (args.empty()) throw jspp::Exception::make_exception("Object.entries called on non-object", "TypeError");
57
- auto obj = args[0];
58
- if (obj.is_null() || obj.is_undefined()) throw jspp::Exception::make_exception("Object.entries called on null or undefined", "TypeError");
59
-
60
- auto keys = jspp::Access::get_object_keys(obj);
61
- std::vector<jspp::AnyValue> entries;
62
- for(const auto& k : keys) {
63
- std::vector<jspp::AnyValue> entry;
64
- entry.push_back(jspp::AnyValue::make_string(k));
65
- entry.push_back(obj.get_property_with_receiver(k, obj));
66
- entries.push_back(jspp::AnyValue::make_array(std::move(entry)));
67
- }
68
- return jspp::AnyValue::make_array(std::move(entries)); }, "entries"));
69
-
70
- // Object.assign(target, ...sources)
71
- Object.define_data_property("assign", jspp::AnyValue::make_function([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
72
- {
73
- if (args.empty()) throw jspp::Exception::make_exception("Cannot convert undefined or null to object", "TypeError");
74
- auto target = args[0];
75
- if (target.is_null() || target.is_undefined()) throw jspp::Exception::make_exception("Cannot convert undefined or null to object", "TypeError");
76
-
77
- for (size_t i = 1; i < args.size(); ++i) {
78
- auto source = args[i];
79
- if (source.is_null() || source.is_undefined()) continue;
80
-
81
- auto keys = jspp::Access::get_object_keys(source);
82
- for(const auto& k : keys) {
83
- auto val = source.get_property_with_receiver(k, source);
84
- target.set_own_property(k, val);
85
- }
86
- }
87
- return target; }, "assign"));
88
-
89
- // Object.is(value1, value2)
90
- Object.define_data_property("is", jspp::AnyValue::make_function([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
91
- {
92
- jspp::AnyValue v1 = args.size() > 0 ? args[0] : jspp::Constants::UNDEFINED;
93
- jspp::AnyValue v2 = args.size() > 1 ? args[1] : jspp::Constants::UNDEFINED;
94
-
95
- if (v1.is_number() && v2.is_number()) {
96
- double d1 = v1.as_double();
97
- double d2 = v2.as_double();
98
- if (std::isnan(d1) && std::isnan(d2)) return jspp::Constants::TRUE;
99
- if (d1 == 0 && d2 == 0) {
100
- return jspp::AnyValue::make_boolean(std::signbit(d1) == std::signbit(d2));
101
- }
102
- return jspp::AnyValue::make_boolean(d1 == d2);
103
- }
104
-
105
- return jspp::is_strictly_equal_to(v1, v2); }, "is"));
106
-
107
- // Object.getPrototypeOf(obj)
108
- Object.define_data_property("getPrototypeOf", jspp::AnyValue::make_function([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
109
- {
110
- if (args.empty()) throw jspp::Exception::make_exception("Object.getPrototypeOf called on non-object", "TypeError");
111
- auto obj = args[0];
112
-
113
- if (obj.is_object()) {
114
- return obj.as_object()->proto;
115
- }
116
- if (obj.is_array()) {
117
- return obj.as_array()->proto;
118
- }
119
- if (obj.is_function()) {
120
- return obj.as_function()->proto;
121
- }
122
-
123
- return jspp::Constants::Null; }, "getPrototypeOf"));
124
-
125
- // Object.setPrototypeOf(obj, proto)
126
- Object.define_data_property("setPrototypeOf", jspp::AnyValue::make_function([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
127
- {
128
- if (args.size() < 2) throw jspp::Exception::make_exception("Object.setPrototypeOf requires at least 2 arguments", "TypeError");
129
- auto obj = args[0];
130
- auto proto = args[1];
131
-
132
- if (!proto.is_object() && !proto.is_null()) {
133
- throw jspp::Exception::make_exception("Object prototype may only be an Object or null", "TypeError");
134
- }
135
-
136
- if (obj.is_object()) {
137
- obj.as_object()->proto = proto;
138
- } else if (obj.is_array()) {
139
- obj.as_array()->proto = proto;
140
- } else if (obj.is_function()) {
141
- obj.as_function()->proto = proto;
142
- }
143
-
144
- return obj; }, "setPrototypeOf"));
145
-
146
- // Object.create(proto, [propertiesObject])
147
- Object.define_data_property("create", jspp::AnyValue::make_function([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
148
- {
149
- if (args.empty()) throw jspp::Exception::make_exception("Object prototype may only be an Object or null", "TypeError");
150
- auto proto = args[0];
151
- if (!proto.is_object() && !proto.is_null()) {
152
- throw jspp::Exception::make_exception("Object prototype may only be an Object or null", "TypeError");
153
- }
154
-
155
- auto newObj = jspp::AnyValue::make_object_with_proto({}, proto);
156
-
157
- if (args.size() > 1 && !args[1].is_undefined()) {
158
- // Object.defineProperties(newObj, propertiesObject)
159
- // TODO: implement defineProperties logic if needed.
160
- }
161
-
162
- return newObj; }, "create"));
163
-
164
- // Object.defineProperty(obj, prop, descriptor)
165
- Object.define_data_property("defineProperty", jspp::AnyValue::make_function([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
166
- {
167
- if (args.size() < 3) throw jspp::Exception::make_exception("Object.defineProperty requires 3 arguments", "TypeError");
168
- auto obj = args[0];
169
- if (!obj.is_object() && !obj.is_array() && !obj.is_function()) throw jspp::Exception::make_exception("Object.defineProperty called on non-object", "TypeError");
170
-
171
- std::string prop = args[1].to_std_string();
172
- auto descObj = args[2];
173
-
174
- bool enumerable = false;
175
- bool configurable = false;
176
- bool writable = false;
177
-
178
- if (descObj.has_property("enumerable")) enumerable = jspp::is_truthy(descObj.get_own_property("enumerable"));
179
- if (descObj.has_property("configurable")) configurable = jspp::is_truthy(descObj.get_own_property("configurable"));
180
- if (descObj.has_property("writable")) writable = jspp::is_truthy(descObj.get_own_property("writable"));
181
-
182
- bool hasValue = descObj.has_property("value");
183
- bool hasGet = descObj.has_property("get");
184
- bool hasSet = descObj.has_property("set");
185
-
186
- if (hasValue && (hasGet || hasSet)) {
187
- throw jspp::Exception::make_exception("Invalid property descriptor. Cannot both specify accessors and a value or writable attribute", "TypeError");
188
- }
189
-
190
- if (hasValue) {
191
- auto value = descObj.get_own_property("value");
192
- obj.define_data_property(prop, value, writable, enumerable, configurable);
193
- } else {
194
- jspp::AnyValue getter = jspp::Constants::UNDEFINED;
195
- jspp::AnyValue setter = jspp::Constants::UNDEFINED;
196
-
197
- if (hasGet) getter = descObj.get_own_property("get");
198
- if (hasSet) setter = descObj.get_own_property("set");
199
-
200
- if (!getter.is_undefined() && !getter.is_function()) throw jspp::Exception::make_exception("Getter must be a function: " + getter.to_std_string(), "TypeError");
201
- if (!setter.is_undefined() && !setter.is_function()) throw jspp::Exception::make_exception("Setter must be a function", "TypeError");
202
-
203
- if (obj.is_object()) {
204
- auto o_ptr = obj.as_object();
205
- std::optional<std::function<jspp::AnyValue(jspp::AnyValue, std::span<const jspp::AnyValue>)>> getFunc;
206
- std::optional<std::function<jspp::AnyValue(jspp::AnyValue, std::span<const jspp::AnyValue>)>> setFunc;
207
-
208
- if (getter.is_function()) {
209
- getFunc = [getter](jspp::AnyValue thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue {
210
- return getter.call(thisVal, args);
211
- };
212
- }
213
- if (setter.is_function()) {
214
- setFunc = [setter](jspp::AnyValue thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue {
215
- return setter.call(thisVal, args);
216
- };
217
- }
218
-
219
- auto desc = jspp::AnyValue::make_accessor_descriptor(getFunc, setFunc, enumerable, configurable);
220
- auto offset = o_ptr->shape->get_offset(prop);
221
- if (offset.has_value()) {
222
- o_ptr->storage[offset.value()] = desc;
223
- } else {
224
- o_ptr->shape = o_ptr->shape->transition(prop);
225
- o_ptr->storage.push_back(desc);
226
- }
227
- }
228
- }
229
-
230
- return obj; }, "defineProperty"));
231
-
232
- // Object.hasOwn(obj, prop)
233
- Object.define_data_property("hasOwn", jspp::AnyValue::make_function([](jspp::AnyValue, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
234
- {
235
- if (args.empty()) throw jspp::Exception::make_exception("Object.hasOwn called on non-object", "TypeError");
236
- auto obj = args[0];
237
- if (obj.is_null() || obj.is_undefined()) throw jspp::Exception::make_exception("Object.hasOwn called on null or undefined", "TypeError");
238
- std::string prop = args.size() > 1 ? args[1].to_std_string() : "undefined";
239
-
240
- if (obj.is_object()) return jspp::AnyValue::make_boolean(obj.as_object()->shape->get_offset(prop).has_value());
241
- if (obj.is_function()) return jspp::AnyValue::make_boolean(obj.as_function()->props.count(prop));
242
- if (obj.is_array()) {
243
- if (prop == "length") return jspp::Constants::TRUE;
244
- if (jspp::JsArray::is_array_index(prop)) {
245
- uint32_t idx = static_cast<uint32_t>(std::stoull(prop));
246
- auto arr = obj.as_array();
247
- if (idx < arr->dense.size() && !(arr->dense[idx].is_uninitialized())) return jspp::Constants::TRUE;
248
- if (arr->sparse.count(idx)) return jspp::Constants::TRUE;
249
- return jspp::Constants::FALSE;
250
- }
251
- return jspp::AnyValue::make_boolean(obj.as_array()->props.count(prop));
252
- }
253
-
254
- return jspp::Constants::FALSE; }, "hasOwn"));
10
+ extern AnyValue Object;
11
+ void init_object();
12
+ }
255
13
 
256
- // Object.prototype.hasOwnProperty
257
- auto proto = Object.get_own_property("prototype");
258
- proto.define_data_property("hasOwnProperty", jspp::AnyValue::make_function([](jspp::AnyValue thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
259
- {
260
- std::string prop = args.size() > 0 ? args[0].to_std_string() : "undefined";
261
- if (thisVal.is_object()) return jspp::AnyValue::make_boolean(thisVal.as_object()->shape->get_offset(prop).has_value());
262
- if (thisVal.is_function()) return jspp::AnyValue::make_boolean(thisVal.as_function()->props.count(prop));
263
- if (thisVal.is_array()) {
264
- if (prop == "length") return jspp::Constants::TRUE;
265
- if (jspp::JsArray::is_array_index(prop)) {
266
- uint32_t idx = static_cast<uint32_t>(std::stoull(prop));
267
- auto arr = thisVal.as_array();
268
- if (idx < arr->dense.size() && !(arr->dense[idx].is_uninitialized())) return jspp::Constants::TRUE;
269
- if (arr->sparse.count(idx)) return jspp::Constants::TRUE;
270
- return jspp::Constants::FALSE;
271
- }
272
- return jspp::AnyValue::make_boolean(thisVal.as_array()->props.count(prop));
273
- }
274
- return jspp::Constants::FALSE; }, "hasOwnProperty"));
275
- }
276
- } objectInit;
14
+ using jspp::Object;