@ugo-studio/jspp 0.1.4 → 0.1.5
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/analysis/scope.js +17 -0
- package/dist/analysis/typeAnalyzer.js +7 -1
- package/dist/ast/symbols.js +29 -0
- package/dist/ast/types.js +0 -6
- package/dist/cli-utils/args.js +57 -0
- package/dist/cli-utils/colors.js +9 -0
- package/dist/cli-utils/file-utils.js +20 -0
- package/dist/cli-utils/spinner.js +55 -0
- package/dist/cli.js +105 -30
- package/dist/core/codegen/class-handlers.js +10 -6
- package/dist/core/codegen/control-flow-handlers.js +31 -21
- package/dist/core/codegen/declaration-handlers.js +10 -6
- package/dist/core/codegen/expression-handlers.js +202 -60
- package/dist/core/codegen/function-handlers.js +179 -70
- package/dist/core/codegen/helpers.js +107 -17
- package/dist/core/codegen/index.js +9 -8
- package/dist/core/codegen/literal-handlers.js +15 -6
- package/dist/core/codegen/statement-handlers.js +67 -53
- package/dist/core/codegen/visitor.js +3 -1
- package/package.json +1 -1
- package/src/prelude/any_value.hpp +195 -342
- package/src/prelude/any_value_access.hpp +78 -30
- package/src/prelude/any_value_defines.hpp +74 -35
- package/src/prelude/any_value_helpers.hpp +73 -180
- package/src/prelude/exception.hpp +1 -0
- package/src/prelude/exception_helpers.hpp +4 -4
- package/src/prelude/index.hpp +9 -2
- package/src/prelude/library/array.hpp +190 -0
- package/src/prelude/library/console.hpp +6 -5
- package/src/prelude/library/error.hpp +10 -8
- package/src/prelude/library/function.hpp +10 -0
- package/src/prelude/library/global.hpp +20 -0
- package/src/prelude/library/math.hpp +308 -0
- package/src/prelude/library/object.hpp +288 -0
- package/src/prelude/library/performance.hpp +1 -1
- package/src/prelude/library/process.hpp +39 -0
- package/src/prelude/library/promise.hpp +53 -43
- package/src/prelude/library/symbol.hpp +45 -57
- package/src/prelude/library/timer.hpp +6 -6
- package/src/prelude/types.hpp +48 -0
- package/src/prelude/utils/access.hpp +182 -11
- package/src/prelude/utils/assignment_operators.hpp +99 -0
- package/src/prelude/utils/log_any_value/array.hpp +8 -8
- package/src/prelude/utils/log_any_value/function.hpp +6 -4
- package/src/prelude/utils/log_any_value/object.hpp +41 -24
- package/src/prelude/utils/log_any_value/primitives.hpp +3 -1
- package/src/prelude/utils/operators.hpp +750 -274
- package/src/prelude/utils/well_known_symbols.hpp +12 -0
- package/src/prelude/values/array.hpp +8 -6
- package/src/prelude/values/descriptors.hpp +2 -2
- package/src/prelude/values/function.hpp +71 -62
- package/src/prelude/values/helpers/array.hpp +64 -28
- package/src/prelude/values/helpers/function.hpp +77 -92
- package/src/prelude/values/helpers/iterator.hpp +3 -3
- package/src/prelude/values/helpers/object.hpp +54 -9
- package/src/prelude/values/helpers/promise.hpp +3 -3
- package/src/prelude/values/iterator.hpp +1 -1
- package/src/prelude/values/object.hpp +10 -3
- package/src/prelude/values/promise.hpp +3 -3
- package/src/prelude/values/prototypes/array.hpp +851 -12
- package/src/prelude/values/prototypes/function.hpp +2 -2
- package/src/prelude/values/prototypes/iterator.hpp +5 -5
- package/src/prelude/values/prototypes/number.hpp +153 -0
- package/src/prelude/values/prototypes/object.hpp +2 -2
- package/src/prelude/values/prototypes/promise.hpp +40 -30
- package/src/prelude/values/prototypes/string.hpp +28 -28
- package/src/prelude/values/prototypes/symbol.hpp +20 -3
- package/src/prelude/values/shape.hpp +52 -0
|
@@ -5,59 +5,69 @@
|
|
|
5
5
|
#include "any_value.hpp"
|
|
6
6
|
#include "exception.hpp"
|
|
7
7
|
|
|
8
|
-
inline auto Promise = jspp::AnyValue::make_function([](const jspp::AnyValue&
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
inline auto Promise = jspp::AnyValue::make_function([](const jspp::AnyValue &thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
|
|
9
|
+
{
|
|
10
|
+
if (args.empty() || !args[0].is_function())
|
|
11
|
+
{
|
|
12
|
+
throw jspp::Exception::make_exception("Promise resolver undefined is not a function", "TypeError");
|
|
13
|
+
}
|
|
14
|
+
auto executor = args[0].as_function();
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
jspp::JsPromise promise;
|
|
17
|
+
auto state = promise.state; // Share state
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
// resolve function
|
|
20
|
+
auto resolveFn = jspp::AnyValue::make_function([state](const jspp::AnyValue &, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
|
|
21
|
+
{
|
|
19
22
|
jspp::JsPromise p; p.state = state;
|
|
20
23
|
p.resolve(args.empty() ? jspp::AnyValue::make_undefined() : args[0]);
|
|
21
|
-
return jspp::AnyValue::make_undefined();
|
|
22
|
-
}, "resolve");
|
|
24
|
+
return jspp::AnyValue::make_undefined(); }, "resolve");
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
// reject function
|
|
27
|
+
auto rejectFn = jspp::AnyValue::make_function([state](const jspp::AnyValue &, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
|
|
28
|
+
{
|
|
26
29
|
jspp::JsPromise p; p.state = state;
|
|
27
30
|
p.reject(args.empty() ? jspp::AnyValue::make_undefined() : args[0]);
|
|
28
|
-
return jspp::AnyValue::make_undefined();
|
|
29
|
-
}, "reject");
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
executor->call(jspp::AnyValue::make_undefined(), {resolveFn, rejectFn});
|
|
33
|
-
} catch (const jspp::Exception& e) {
|
|
34
|
-
promise.reject(*e.data);
|
|
35
|
-
} catch (...) {
|
|
36
|
-
promise.reject(jspp::AnyValue::make_string("Unknown error during Promise execution"));
|
|
37
|
-
}
|
|
31
|
+
return jspp::AnyValue::make_undefined(); }, "reject");
|
|
38
32
|
|
|
39
|
-
|
|
33
|
+
try
|
|
34
|
+
{
|
|
35
|
+
const jspp::AnyValue executorArgs[] = {resolveFn, rejectFn};
|
|
36
|
+
executor->call(jspp::Constants::UNDEFINED, std::span<const jspp::AnyValue>(executorArgs, 2));
|
|
37
|
+
}
|
|
38
|
+
catch (const jspp::Exception &e)
|
|
39
|
+
{
|
|
40
|
+
promise.reject(*e.data);
|
|
41
|
+
}
|
|
42
|
+
catch (...)
|
|
43
|
+
{
|
|
44
|
+
promise.reject(jspp::AnyValue::make_string("Unknown error during Promise execution"));
|
|
45
|
+
}
|
|
40
46
|
|
|
41
|
-
|
|
47
|
+
return jspp::AnyValue::make_promise(promise); },
|
|
48
|
+
"Promise");
|
|
42
49
|
|
|
43
|
-
struct PromiseInit
|
|
44
|
-
|
|
50
|
+
struct PromiseInit
|
|
51
|
+
{
|
|
52
|
+
PromiseInit()
|
|
53
|
+
{
|
|
45
54
|
// Promise.resolve(value)
|
|
46
|
-
Promise.define_data_property("resolve", jspp::AnyValue::make_function([](const jspp::AnyValue&,
|
|
55
|
+
Promise.define_data_property("resolve", jspp::AnyValue::make_function([](const jspp::AnyValue &, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
|
|
56
|
+
{
|
|
47
57
|
jspp::JsPromise p;
|
|
48
58
|
p.resolve(args.empty() ? jspp::AnyValue::make_undefined() : args[0]);
|
|
49
|
-
return jspp::AnyValue::make_promise(p);
|
|
50
|
-
}, "resolve"));
|
|
59
|
+
return jspp::AnyValue::make_promise(p); }, "resolve"));
|
|
51
60
|
|
|
52
61
|
// Promise.reject(reason)
|
|
53
|
-
Promise.define_data_property("reject", jspp::AnyValue::make_function([](const jspp::AnyValue&,
|
|
62
|
+
Promise.define_data_property("reject", jspp::AnyValue::make_function([](const jspp::AnyValue &, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
|
|
63
|
+
{
|
|
54
64
|
jspp::JsPromise p;
|
|
55
65
|
p.reject(args.empty() ? jspp::AnyValue::make_undefined() : args[0]);
|
|
56
|
-
return jspp::AnyValue::make_promise(p);
|
|
57
|
-
|
|
58
|
-
|
|
66
|
+
return jspp::AnyValue::make_promise(p); }, "reject"));
|
|
67
|
+
|
|
59
68
|
// Promise.all(iterable)
|
|
60
|
-
Promise.define_data_property("all", jspp::AnyValue::make_function([](const jspp::AnyValue&,
|
|
69
|
+
Promise.define_data_property("all", jspp::AnyValue::make_function([](const jspp::AnyValue &, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
|
|
70
|
+
{
|
|
61
71
|
// Basic implementation for arrays
|
|
62
72
|
if (args.empty() || !args[0].is_array()) {
|
|
63
73
|
// If not array, reject? Or treat as non-iterable?
|
|
@@ -73,16 +83,16 @@ struct PromiseInit {
|
|
|
73
83
|
}
|
|
74
84
|
|
|
75
85
|
auto arr = args[0].as_array();
|
|
76
|
-
size_t len = arr->length;
|
|
86
|
+
size_t len = static_cast<size_t>(arr->length);
|
|
77
87
|
if (len == 0) {
|
|
78
|
-
jspp::JsPromise p; p.resolve(jspp::AnyValue::make_array(
|
|
88
|
+
jspp::JsPromise p; p.resolve(jspp::AnyValue::make_array(std::vector<jspp::AnyValue>()));
|
|
79
89
|
return jspp::AnyValue::make_promise(p);
|
|
80
90
|
}
|
|
81
91
|
|
|
82
92
|
jspp::JsPromise masterPromise;
|
|
83
93
|
auto masterState = masterPromise.state;
|
|
84
94
|
|
|
85
|
-
auto results = std::make_shared<std::vector<
|
|
95
|
+
auto results = std::make_shared<std::vector<jspp::AnyValue>>(len, jspp::Constants::UNDEFINED);
|
|
86
96
|
auto count = std::make_shared<size_t>(len);
|
|
87
97
|
|
|
88
98
|
// Check if already rejected to avoid further processing
|
|
@@ -91,20 +101,21 @@ struct PromiseInit {
|
|
|
91
101
|
for (size_t i = 0; i < len; ++i) {
|
|
92
102
|
jspp::AnyValue item = arr->get_property(static_cast<uint32_t>(i));
|
|
93
103
|
|
|
94
|
-
auto handleResult = [masterState, results, count, i, rejected](jspp::AnyValue res) {
|
|
104
|
+
auto handleResult = [masterState, results, count, i, rejected](const jspp::AnyValue& res) {
|
|
95
105
|
if (*rejected) return;
|
|
96
106
|
(*results)[i] = res;
|
|
97
107
|
(*count)--;
|
|
98
108
|
if (*count == 0) {
|
|
99
109
|
jspp::JsPromise p; p.state = masterState;
|
|
100
|
-
p.resolve(jspp::AnyValue::make_array(*results));
|
|
110
|
+
p.resolve(jspp::AnyValue::make_array(std::move(*results)));
|
|
101
111
|
}
|
|
102
112
|
};
|
|
103
113
|
|
|
104
|
-
auto handleReject = [masterState, rejected](jspp::AnyValue reason) {
|
|
114
|
+
auto handleReject = [masterState, rejected](const jspp::AnyValue& reason) {
|
|
105
115
|
if (*rejected) return;
|
|
106
116
|
*rejected = true;
|
|
107
117
|
jspp::JsPromise p; p.state = masterState;
|
|
118
|
+
masterState->status =jspp::PromiseStatus::Rejected; // ensure master state updated
|
|
108
119
|
p.reject(reason);
|
|
109
120
|
};
|
|
110
121
|
|
|
@@ -115,7 +126,6 @@ struct PromiseInit {
|
|
|
115
126
|
}
|
|
116
127
|
}
|
|
117
128
|
|
|
118
|
-
return jspp::AnyValue::make_promise(masterPromise);
|
|
119
|
-
}, "all"));
|
|
129
|
+
return jspp::AnyValue::make_promise(masterPromise); }, "all"));
|
|
120
130
|
}
|
|
121
131
|
} promiseInit;
|
|
@@ -2,63 +2,51 @@
|
|
|
2
2
|
|
|
3
3
|
#include "types.hpp"
|
|
4
4
|
#include "utils/well_known_symbols.hpp"
|
|
5
|
-
|
|
6
5
|
#include "values/object.hpp"
|
|
7
6
|
#include "any_value.hpp"
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
// }
|
|
55
|
-
// }, "keyFor");
|
|
56
|
-
|
|
57
|
-
// // Attach static properties/methods to the Symbol object
|
|
58
|
-
// struct SymbolInit {
|
|
59
|
-
// SymbolInit() {
|
|
60
|
-
// Symbol.set_own_property("iterator", jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::iterator));
|
|
61
|
-
// Symbol.set_own_property("for", forFn);
|
|
62
|
-
// Symbol.set_own_property("keyFor", keyForFn);
|
|
63
|
-
// }
|
|
64
|
-
// } symbolInit;
|
|
8
|
+
// Define Symbol as a function
|
|
9
|
+
inline auto Symbol = jspp::AnyValue::make_function([](const jspp::AnyValue &thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
|
|
10
|
+
{
|
|
11
|
+
std::string description = "";
|
|
12
|
+
if (!args.empty() && !args[0].is_undefined()) {
|
|
13
|
+
description = args[0].to_std_string();
|
|
14
|
+
}
|
|
15
|
+
return jspp::AnyValue::make_symbol(description); }, "Symbol", false);
|
|
16
|
+
|
|
17
|
+
// Initialize Symbol properties
|
|
18
|
+
struct SymbolInit
|
|
19
|
+
{
|
|
20
|
+
SymbolInit()
|
|
21
|
+
{
|
|
22
|
+
// Static methods
|
|
23
|
+
Symbol.define_data_property("for", jspp::AnyValue::make_function([](const jspp::AnyValue &, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
|
|
24
|
+
{
|
|
25
|
+
std::string key = "";
|
|
26
|
+
if (!args.empty()) key = args[0].to_std_string();
|
|
27
|
+
return jspp::AnyValue::from_symbol(jspp::JsSymbol::for_global(key)); }, "for"));
|
|
28
|
+
|
|
29
|
+
Symbol.define_data_property("keyFor", jspp::AnyValue::make_function([](const jspp::AnyValue &, std::span<const jspp::AnyValue> args) -> jspp::AnyValue
|
|
30
|
+
{
|
|
31
|
+
if (args.empty() || !args[0].is_symbol()) throw jspp::Exception::make_exception("Symbol.keyFor requires a symbol", "TypeError");
|
|
32
|
+
auto sym = args[0].as_symbol();
|
|
33
|
+
auto key = jspp::JsSymbol::key_for(sym);
|
|
34
|
+
if (key.has_value()) return jspp::AnyValue::make_string(key.value());
|
|
35
|
+
return jspp::AnyValue::make_undefined(); }, "keyFor"));
|
|
36
|
+
|
|
37
|
+
// Well-known symbols
|
|
38
|
+
Symbol.define_data_property("iterator", jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::iterator), false, false, false);
|
|
39
|
+
Symbol.define_data_property("asyncIterator", jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::asyncIterator), false, false, false);
|
|
40
|
+
Symbol.define_data_property("hasInstance", jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::hasInstance), false, false, false);
|
|
41
|
+
Symbol.define_data_property("isConcatSpreadable", jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::isConcatSpreadable), false, false, false);
|
|
42
|
+
Symbol.define_data_property("match", jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::match), false, false, false);
|
|
43
|
+
Symbol.define_data_property("matchAll", jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::matchAll), false, false, false);
|
|
44
|
+
Symbol.define_data_property("replace", jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::replace), false, false, false);
|
|
45
|
+
Symbol.define_data_property("search", jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::search), false, false, false);
|
|
46
|
+
Symbol.define_data_property("species", jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::species), false, false, false);
|
|
47
|
+
Symbol.define_data_property("split", jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::split), false, false, false);
|
|
48
|
+
Symbol.define_data_property("toPrimitive", jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::toPrimitive), false, false, false);
|
|
49
|
+
Symbol.define_data_property("toStringTag", jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::toStringTag), false, false, false);
|
|
50
|
+
Symbol.define_data_property("unscopables", jspp::AnyValue::from_symbol(jspp::WellKnownSymbols::unscopables), false, false, false);
|
|
51
|
+
}
|
|
52
|
+
} symbolInit;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
#include "exception.hpp"
|
|
8
8
|
|
|
9
9
|
// setTimeout(callback, delay, ...args)
|
|
10
|
-
inline auto setTimeout = jspp::AnyValue::make_function([](const jspp::AnyValue& thisVal,
|
|
10
|
+
inline auto setTimeout = jspp::AnyValue::make_function([](const jspp::AnyValue& thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue {
|
|
11
11
|
if (args.empty() || !args[0].is_function()) {
|
|
12
12
|
throw jspp::Exception::make_exception("Callback must be a function", "TypeError");
|
|
13
13
|
}
|
|
@@ -26,7 +26,7 @@ inline auto setTimeout = jspp::AnyValue::make_function([](const jspp::AnyValue&
|
|
|
26
26
|
|
|
27
27
|
auto task = [callback, callArgs]() {
|
|
28
28
|
try {
|
|
29
|
-
callback.
|
|
29
|
+
callback.call(jspp::Constants::UNDEFINED, std::span<const jspp::AnyValue>(callArgs));
|
|
30
30
|
} catch (const jspp::Exception& e) {
|
|
31
31
|
std::cerr << "Uncaught exception in setTimeout: " << e.what() << "\n";
|
|
32
32
|
} catch (const std::exception& e) {
|
|
@@ -41,7 +41,7 @@ inline auto setTimeout = jspp::AnyValue::make_function([](const jspp::AnyValue&
|
|
|
41
41
|
}, "setTimeout");
|
|
42
42
|
|
|
43
43
|
// clearTimeout(id)
|
|
44
|
-
inline auto clearTimeout = jspp::AnyValue::make_function([](const jspp::AnyValue& thisVal,
|
|
44
|
+
inline auto clearTimeout = jspp::AnyValue::make_function([](const jspp::AnyValue& thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue {
|
|
45
45
|
if (!args.empty() && args[0].is_number()) {
|
|
46
46
|
size_t id = static_cast<size_t>(args[0].as_double());
|
|
47
47
|
jspp::Scheduler::instance().clear_timer(id);
|
|
@@ -50,7 +50,7 @@ inline auto clearTimeout = jspp::AnyValue::make_function([](const jspp::AnyValue
|
|
|
50
50
|
}, "clearTimeout");
|
|
51
51
|
|
|
52
52
|
// setInterval(callback, delay, ...args)
|
|
53
|
-
inline auto setInterval = jspp::AnyValue::make_function([](const jspp::AnyValue& thisVal,
|
|
53
|
+
inline auto setInterval = jspp::AnyValue::make_function([](const jspp::AnyValue& thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue {
|
|
54
54
|
if (args.empty() || !args[0].is_function()) {
|
|
55
55
|
throw jspp::Exception::make_exception("Callback must be a function", "TypeError");
|
|
56
56
|
}
|
|
@@ -68,7 +68,7 @@ inline auto setInterval = jspp::AnyValue::make_function([](const jspp::AnyValue&
|
|
|
68
68
|
|
|
69
69
|
auto task = [callback, callArgs]() {
|
|
70
70
|
try {
|
|
71
|
-
callback.
|
|
71
|
+
callback.call(jspp::Constants::UNDEFINED, std::span<const jspp::AnyValue>(callArgs));
|
|
72
72
|
} catch (const jspp::Exception& e) {
|
|
73
73
|
std::cerr << "Uncaught exception in setInterval: " << e.what() << "\n";
|
|
74
74
|
} catch (const std::exception& e) {
|
|
@@ -83,7 +83,7 @@ inline auto setInterval = jspp::AnyValue::make_function([](const jspp::AnyValue&
|
|
|
83
83
|
}, "setInterval");
|
|
84
84
|
|
|
85
85
|
// clearInterval(id)
|
|
86
|
-
inline auto clearInterval = jspp::AnyValue::make_function([](const jspp::AnyValue& thisVal,
|
|
86
|
+
inline auto clearInterval = jspp::AnyValue::make_function([](const jspp::AnyValue& thisVal, std::span<const jspp::AnyValue> args) -> jspp::AnyValue {
|
|
87
87
|
if (!args.empty() && args[0].is_number()) {
|
|
88
88
|
size_t id = static_cast<size_t>(args[0].as_double());
|
|
89
89
|
jspp::Scheduler::instance().clear_timer(id);
|
package/src/prelude/types.hpp
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
#include <set>
|
|
15
15
|
#include <cmath>
|
|
16
16
|
#include <optional>
|
|
17
|
+
#include <span>
|
|
17
18
|
|
|
18
19
|
// JSPP standard library
|
|
19
20
|
namespace jspp
|
|
@@ -42,7 +43,50 @@ namespace jspp
|
|
|
42
43
|
// Dynamic AnyValue
|
|
43
44
|
class AnyValue;
|
|
44
45
|
|
|
46
|
+
// Truthiness checker
|
|
47
|
+
const bool is_truthy(const double &val) noexcept;
|
|
48
|
+
const bool is_truthy(const std::string &val) noexcept;
|
|
49
|
+
const bool is_truthy(const AnyValue &val) noexcept;
|
|
50
|
+
|
|
51
|
+
// Basic equality operators
|
|
52
|
+
inline const bool is_strictly_equal_to_primitive(const AnyValue &lhs, const double &rhs) noexcept;
|
|
53
|
+
inline const bool is_strictly_equal_to_primitive(const double &lhs, const AnyValue &rhs) noexcept;
|
|
54
|
+
inline const bool is_strictly_equal_to_primitive(const double &lhs, const double &rhs) noexcept;
|
|
55
|
+
inline const bool is_strictly_equal_to_primitive(const AnyValue &lhs, const AnyValue &rhs) noexcept;
|
|
56
|
+
|
|
57
|
+
inline const bool is_equal_to_primitive(const AnyValue &lhs, const double &rhs) noexcept;
|
|
58
|
+
inline const bool is_equal_to_primitive(const double &lhs, const AnyValue &rhs) noexcept;
|
|
59
|
+
inline const bool is_equal_to_primitive(const double &lhs, const double &rhs) noexcept;
|
|
60
|
+
inline const bool is_equal_to_primitive(const AnyValue &lhs, const AnyValue &rhs) noexcept;
|
|
61
|
+
|
|
62
|
+
inline const AnyValue is_strictly_equal_to(const AnyValue &lhs, const double &rhs) noexcept;
|
|
63
|
+
inline const AnyValue is_strictly_equal_to(const double &lhs, const AnyValue &rhs) noexcept;
|
|
64
|
+
inline const AnyValue is_strictly_equal_to(const double &lhs, const double &rhs) noexcept;
|
|
65
|
+
inline const AnyValue is_strictly_equal_to(const AnyValue &lhs, const AnyValue &rhs) noexcept;
|
|
66
|
+
|
|
67
|
+
inline const AnyValue is_equal_to(const AnyValue &lhs, const double &rhs) noexcept;
|
|
68
|
+
inline const AnyValue is_equal_to(const double &lhs, const AnyValue &rhs) noexcept;
|
|
69
|
+
inline const AnyValue is_equal_to(const double &lhs, const double &rhs) noexcept;
|
|
70
|
+
inline const AnyValue is_equal_to(const AnyValue &lhs, const AnyValue &rhs) noexcept;
|
|
71
|
+
|
|
72
|
+
inline const AnyValue not_strictly_equal_to(const AnyValue &lhs, const double &rhs) noexcept;
|
|
73
|
+
inline const AnyValue not_strictly_equal_to(const double &lhs, const AnyValue &rhs) noexcept;
|
|
74
|
+
inline const AnyValue not_strictly_equal_to(const double &lhs, const double &rhs) noexcept;
|
|
75
|
+
inline const AnyValue not_strictly_equal_to(const AnyValue &lhs, const AnyValue &rhs) noexcept;
|
|
76
|
+
|
|
77
|
+
inline const AnyValue not_equal_to(const AnyValue &lhs, const double &rhs) noexcept;
|
|
78
|
+
inline const AnyValue not_equal_to(const double &lhs, const AnyValue &rhs) noexcept;
|
|
79
|
+
inline const AnyValue not_equal_to(const AnyValue &lhs, const AnyValue &rhs) noexcept;
|
|
80
|
+
|
|
81
|
+
// Bitwise operators
|
|
82
|
+
inline AnyValue unsigned_right_shift(const AnyValue &lhs, const AnyValue &rhs);
|
|
83
|
+
inline AnyValue unsigned_right_shift(const AnyValue &lhs, const double &rhs);
|
|
84
|
+
inline AnyValue unsigned_right_shift(const double &lhs, const AnyValue &rhs);
|
|
85
|
+
|
|
45
86
|
// Arithemetic operators
|
|
87
|
+
|
|
88
|
+
inline AnyValue pow(const double &lhs, const double &rhs);
|
|
89
|
+
inline AnyValue pow(const AnyValue &lhs, const double &rhs);
|
|
46
90
|
inline AnyValue pow(const AnyValue &lhs, const AnyValue &rhs);
|
|
47
91
|
|
|
48
92
|
// AnyValue prototypes
|
|
@@ -54,6 +98,10 @@ namespace jspp
|
|
|
54
98
|
{
|
|
55
99
|
inline std::optional<AnyValue> get(const std::string &key, JsString *self);
|
|
56
100
|
}
|
|
101
|
+
namespace NumberPrototypes
|
|
102
|
+
{
|
|
103
|
+
inline std::optional<AnyValue> get(const std::string &key, double self);
|
|
104
|
+
}
|
|
57
105
|
namespace ArrayPrototypes
|
|
58
106
|
{
|
|
59
107
|
inline std::optional<AnyValue> get(const std::string &key, JsArray *self);
|
|
@@ -64,9 +64,12 @@ namespace jspp
|
|
|
64
64
|
return var;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
inline AnyValue
|
|
67
|
+
inline const AnyValue type_of(const std::optional<AnyValue> &val = std::nullopt)
|
|
68
68
|
{
|
|
69
|
-
|
|
69
|
+
if (!val.has_value())
|
|
70
|
+
return AnyValue::make_string("undefined");
|
|
71
|
+
|
|
72
|
+
switch (val.value().get_type())
|
|
70
73
|
{
|
|
71
74
|
case JsType::Undefined:
|
|
72
75
|
return AnyValue::make_string("undefined");
|
|
@@ -83,17 +86,15 @@ namespace jspp
|
|
|
83
86
|
case JsType::Function:
|
|
84
87
|
return AnyValue::make_string("function");
|
|
85
88
|
case JsType::Object:
|
|
89
|
+
return AnyValue::make_string("object");
|
|
86
90
|
case JsType::Array:
|
|
91
|
+
return AnyValue::make_string("object");
|
|
87
92
|
case JsType::Iterator:
|
|
88
93
|
return AnyValue::make_string("object");
|
|
89
94
|
default:
|
|
90
95
|
return AnyValue::make_string("undefined");
|
|
91
96
|
}
|
|
92
97
|
}
|
|
93
|
-
inline AnyValue typeof() // for undeclared variables
|
|
94
|
-
{
|
|
95
|
-
return AnyValue::make_string("undefined");
|
|
96
|
-
}
|
|
97
98
|
|
|
98
99
|
// Helper function to get enumerable own property keys/values of an object
|
|
99
100
|
inline std::vector<std::string> get_object_keys(const AnyValue &obj)
|
|
@@ -103,10 +104,35 @@ namespace jspp
|
|
|
103
104
|
if (obj.is_object())
|
|
104
105
|
{
|
|
105
106
|
auto ptr = obj.as_object();
|
|
106
|
-
|
|
107
|
+
// Use shape's property_names for stable iteration order
|
|
108
|
+
for (const auto &key : ptr->shape->property_names)
|
|
107
109
|
{
|
|
108
|
-
if (
|
|
109
|
-
|
|
110
|
+
if (ptr->deleted_keys.count(key))
|
|
111
|
+
continue;
|
|
112
|
+
|
|
113
|
+
if (JsSymbol::is_internal_key(key))
|
|
114
|
+
continue;
|
|
115
|
+
|
|
116
|
+
auto offset_opt = ptr->shape->get_offset(key);
|
|
117
|
+
if (!offset_opt.has_value())
|
|
118
|
+
continue;
|
|
119
|
+
|
|
120
|
+
const auto &val = ptr->storage[offset_opt.value()];
|
|
121
|
+
|
|
122
|
+
if (val.is_data_descriptor())
|
|
123
|
+
{
|
|
124
|
+
if (val.as_data_descriptor()->enumerable)
|
|
125
|
+
keys.push_back(key);
|
|
126
|
+
}
|
|
127
|
+
else if (val.is_accessor_descriptor())
|
|
128
|
+
{
|
|
129
|
+
if (val.as_accessor_descriptor()->enumerable)
|
|
130
|
+
keys.push_back(key);
|
|
131
|
+
}
|
|
132
|
+
else
|
|
133
|
+
{
|
|
134
|
+
keys.push_back(key);
|
|
135
|
+
}
|
|
110
136
|
}
|
|
111
137
|
}
|
|
112
138
|
if (obj.is_function())
|
|
@@ -153,7 +179,7 @@ namespace jspp
|
|
|
153
179
|
auto gen_fn = obj.get_own_property(WellKnownSymbols::iterator->key);
|
|
154
180
|
if (gen_fn.is_function())
|
|
155
181
|
{
|
|
156
|
-
auto iter = gen_fn.
|
|
182
|
+
auto iter = gen_fn.call(obj, {}, WellKnownSymbols::iterator->key);
|
|
157
183
|
if (iter.is_iterator())
|
|
158
184
|
{
|
|
159
185
|
return iter;
|
|
@@ -170,5 +196,150 @@ namespace jspp
|
|
|
170
196
|
|
|
171
197
|
throw jspp::Exception::make_exception(name + " is not iterable", "TypeError");
|
|
172
198
|
}
|
|
199
|
+
|
|
200
|
+
inline AnyValue in(const AnyValue &lhs, const AnyValue &rhs)
|
|
201
|
+
{
|
|
202
|
+
if (!rhs.is_object() && !rhs.is_array() && !rhs.is_function() && !rhs.is_promise() && !rhs.is_iterator())
|
|
203
|
+
{
|
|
204
|
+
throw jspp::Exception::make_exception("Cannot use 'in' operator to search for '" + lhs.to_std_string() + "' in " + rhs.to_std_string(), "TypeError");
|
|
205
|
+
}
|
|
206
|
+
return AnyValue::make_boolean(rhs.has_property(lhs.to_std_string()));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
inline AnyValue instance_of(const AnyValue &lhs, const AnyValue &rhs)
|
|
210
|
+
{
|
|
211
|
+
if (!rhs.is_function())
|
|
212
|
+
{
|
|
213
|
+
throw jspp::Exception::make_exception("Right-hand side of 'instanceof' is not callable", "TypeError");
|
|
214
|
+
}
|
|
215
|
+
if (!lhs.is_object() && !lhs.is_array() && !lhs.is_function() && !lhs.is_promise() && !lhs.is_iterator())
|
|
216
|
+
{
|
|
217
|
+
return Constants::FALSE;
|
|
218
|
+
}
|
|
219
|
+
AnyValue targetProto = rhs.get_own_property("prototype");
|
|
220
|
+
if (!targetProto.is_object() && !targetProto.is_array() && !targetProto.is_function())
|
|
221
|
+
{
|
|
222
|
+
throw jspp::Exception::make_exception("Function has non-object prototype in instanceof check", "TypeError");
|
|
223
|
+
}
|
|
224
|
+
// Walk prototype chain of lhs
|
|
225
|
+
AnyValue current = lhs;
|
|
226
|
+
|
|
227
|
+
while (true)
|
|
228
|
+
{
|
|
229
|
+
AnyValue proto;
|
|
230
|
+
if (current.is_object())
|
|
231
|
+
{
|
|
232
|
+
auto p = current.as_object()->proto;
|
|
233
|
+
if (p)
|
|
234
|
+
proto = *p;
|
|
235
|
+
else
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
else if (current.is_array())
|
|
239
|
+
{
|
|
240
|
+
auto p = current.as_array()->proto;
|
|
241
|
+
if (p)
|
|
242
|
+
proto = *p;
|
|
243
|
+
else
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
else if (current.is_function())
|
|
247
|
+
{
|
|
248
|
+
auto p = current.as_function()->proto;
|
|
249
|
+
if (p)
|
|
250
|
+
proto = *p;
|
|
251
|
+
else
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
else if (current.is_promise())
|
|
255
|
+
{
|
|
256
|
+
// Promises don't store explicit proto yet in our impl
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
else
|
|
260
|
+
{
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
if (proto.is_null() || proto.is_undefined())
|
|
264
|
+
break;
|
|
265
|
+
if (is_strictly_equal_to_primitive(proto, targetProto))
|
|
266
|
+
return Constants::TRUE;
|
|
267
|
+
current = proto;
|
|
268
|
+
}
|
|
269
|
+
return Constants::FALSE;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
inline AnyValue delete_property(const AnyValue &obj, const AnyValue &key)
|
|
273
|
+
{
|
|
274
|
+
if (obj.is_object())
|
|
275
|
+
{
|
|
276
|
+
auto ptr = obj.as_object();
|
|
277
|
+
std::string key_str = key.to_std_string();
|
|
278
|
+
if (ptr->shape->get_offset(key_str).has_value())
|
|
279
|
+
{
|
|
280
|
+
ptr->deleted_keys.insert(key_str);
|
|
281
|
+
}
|
|
282
|
+
return Constants::TRUE;
|
|
283
|
+
}
|
|
284
|
+
if (obj.is_array())
|
|
285
|
+
{
|
|
286
|
+
auto ptr = obj.as_array();
|
|
287
|
+
std::string key_str = key.to_std_string();
|
|
288
|
+
if (JsArray::is_array_index(key_str))
|
|
289
|
+
{
|
|
290
|
+
uint32_t idx = static_cast<uint32_t>(std::stoull(key_str));
|
|
291
|
+
if (idx < ptr->dense.size())
|
|
292
|
+
{
|
|
293
|
+
ptr->dense[idx] = Constants::UNINITIALIZED;
|
|
294
|
+
}
|
|
295
|
+
else
|
|
296
|
+
{
|
|
297
|
+
ptr->sparse.erase(idx);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else
|
|
301
|
+
{
|
|
302
|
+
ptr->props.erase(key_str);
|
|
303
|
+
}
|
|
304
|
+
return Constants::TRUE;
|
|
305
|
+
}
|
|
306
|
+
if (obj.is_function())
|
|
307
|
+
{
|
|
308
|
+
auto ptr = obj.as_function();
|
|
309
|
+
ptr->props.erase(key.to_std_string());
|
|
310
|
+
return Constants::TRUE;
|
|
311
|
+
}
|
|
312
|
+
return Constants::TRUE;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
inline AnyValue optional_get_property(const AnyValue &obj, const std::string &key)
|
|
316
|
+
{
|
|
317
|
+
if (obj.is_null() || obj.is_undefined())
|
|
318
|
+
return Constants::UNDEFINED;
|
|
319
|
+
return obj.get_own_property(key);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
inline AnyValue optional_get_element(const AnyValue &obj, const AnyValue &key)
|
|
323
|
+
{
|
|
324
|
+
if (obj.is_null() || obj.is_undefined())
|
|
325
|
+
return Constants::UNDEFINED;
|
|
326
|
+
return obj.get_own_property(key);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
inline AnyValue optional_get_element(const AnyValue &obj, const double &key)
|
|
330
|
+
{
|
|
331
|
+
if (obj.is_null() || obj.is_undefined())
|
|
332
|
+
return Constants::UNDEFINED;
|
|
333
|
+
return obj.get_own_property(static_cast<uint32_t>(key));
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
inline AnyValue optional_call(const AnyValue &fn, const AnyValue &thisVal, std::span<const AnyValue> args, const std::optional<std::string> &name = std::nullopt)
|
|
337
|
+
{
|
|
338
|
+
if (fn.is_null() || fn.is_undefined())
|
|
339
|
+
return Constants::UNDEFINED;
|
|
340
|
+
return fn.call(thisVal, args, name);
|
|
341
|
+
}
|
|
342
|
+
|
|
173
343
|
}
|
|
174
|
-
|
|
344
|
+
|
|
345
|
+
}
|