@ugo-studio/jspp 0.1.3 → 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/README.md +2 -2
- package/dist/analysis/scope.js +33 -4
- package/dist/analysis/typeAnalyzer.js +260 -21
- package/dist/ast/symbols.js +29 -0
- 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 -31
- package/dist/core/codegen/class-handlers.js +131 -0
- package/dist/core/codegen/control-flow-handlers.js +474 -0
- package/dist/core/codegen/declaration-handlers.js +36 -15
- package/dist/core/codegen/expression-handlers.js +579 -125
- package/dist/core/codegen/function-handlers.js +222 -37
- package/dist/core/codegen/helpers.js +158 -4
- package/dist/core/codegen/index.js +20 -8
- package/dist/core/codegen/literal-handlers.js +18 -6
- package/dist/core/codegen/statement-handlers.js +171 -228
- package/dist/core/codegen/visitor.js +31 -3
- package/package.json +3 -3
- package/src/prelude/any_value.hpp +510 -633
- package/src/prelude/any_value_access.hpp +151 -0
- package/src/prelude/any_value_defines.hpp +190 -0
- package/src/prelude/any_value_helpers.hpp +139 -225
- package/src/prelude/exception.hpp +32 -0
- package/src/prelude/exception_helpers.hpp +49 -0
- package/src/prelude/index.hpp +25 -9
- package/src/prelude/library/array.hpp +190 -0
- package/src/prelude/library/console.hpp +14 -13
- package/src/prelude/library/error.hpp +113 -0
- package/src/prelude/library/function.hpp +10 -0
- package/src/prelude/library/global.hpp +35 -4
- package/src/prelude/library/math.hpp +308 -0
- package/src/prelude/library/object.hpp +288 -0
- package/src/prelude/library/performance.hpp +2 -2
- package/src/prelude/library/process.hpp +39 -0
- package/src/prelude/library/promise.hpp +131 -0
- package/src/prelude/library/symbol.hpp +46 -59
- package/src/prelude/library/timer.hpp +92 -0
- package/src/prelude/scheduler.hpp +145 -0
- package/src/prelude/types.hpp +58 -1
- package/src/prelude/utils/access.hpp +345 -0
- package/src/prelude/utils/assignment_operators.hpp +99 -0
- package/src/prelude/utils/log_any_value/array.hpp +245 -0
- package/src/prelude/utils/log_any_value/config.hpp +32 -0
- package/src/prelude/utils/log_any_value/function.hpp +39 -0
- package/src/prelude/utils/log_any_value/fwd.hpp +15 -0
- package/src/prelude/utils/log_any_value/helpers.hpp +62 -0
- package/src/prelude/utils/log_any_value/log_any_value.hpp +94 -0
- package/src/prelude/utils/log_any_value/object.hpp +136 -0
- package/src/prelude/utils/log_any_value/primitives.hpp +43 -0
- package/src/prelude/utils/operators.hpp +751 -0
- package/src/prelude/utils/well_known_symbols.hpp +25 -0
- package/src/prelude/values/array.hpp +10 -7
- package/src/prelude/{descriptors.hpp → values/descriptors.hpp} +2 -2
- package/src/prelude/values/function.hpp +85 -51
- package/src/prelude/values/helpers/array.hpp +80 -35
- package/src/prelude/values/helpers/function.hpp +110 -77
- package/src/prelude/values/helpers/iterator.hpp +16 -10
- package/src/prelude/values/helpers/object.hpp +85 -10
- package/src/prelude/values/helpers/promise.hpp +181 -0
- package/src/prelude/values/helpers/string.hpp +3 -3
- package/src/prelude/values/helpers/symbol.hpp +2 -2
- package/src/prelude/values/iterator.hpp +14 -6
- package/src/prelude/values/object.hpp +14 -3
- package/src/prelude/values/promise.hpp +73 -0
- package/src/prelude/values/prototypes/array.hpp +855 -16
- package/src/prelude/values/prototypes/function.hpp +4 -4
- package/src/prelude/values/prototypes/iterator.hpp +11 -10
- package/src/prelude/values/prototypes/number.hpp +153 -0
- package/src/prelude/values/prototypes/object.hpp +26 -0
- package/src/prelude/values/prototypes/promise.hpp +134 -0
- package/src/prelude/values/prototypes/string.hpp +29 -29
- package/src/prelude/values/prototypes/symbol.hpp +22 -3
- package/src/prelude/values/shape.hpp +52 -0
- package/src/prelude/values/string.hpp +1 -1
- package/src/prelude/values/symbol.hpp +1 -1
- package/src/prelude/access.hpp +0 -91
- package/src/prelude/error.hpp +0 -31
- package/src/prelude/error_helpers.hpp +0 -59
- package/src/prelude/log_string.hpp +0 -407
- package/src/prelude/operators.hpp +0 -256
- package/src/prelude/well_known_symbols.hpp +0 -14
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "values/symbol.hpp"
|
|
4
|
+
#include <memory>
|
|
5
|
+
|
|
6
|
+
namespace jspp
|
|
7
|
+
{
|
|
8
|
+
namespace WellKnownSymbols
|
|
9
|
+
{
|
|
10
|
+
// We use a specific prefix "@@" for well-known symbols to distinguish them from user symbols
|
|
11
|
+
inline std::shared_ptr<JsSymbol> iterator = std::make_shared<JsSymbol>("Symbol.iterator", "@@iterator");
|
|
12
|
+
inline std::shared_ptr<JsSymbol> asyncIterator = std::make_shared<JsSymbol>("Symbol.asyncIterator", "@@asyncIterator");
|
|
13
|
+
inline std::shared_ptr<JsSymbol> hasInstance = std::make_shared<JsSymbol>("Symbol.hasInstance", "@@hasInstance");
|
|
14
|
+
inline std::shared_ptr<JsSymbol> isConcatSpreadable = std::make_shared<JsSymbol>("Symbol.isConcatSpreadable", "@@isConcatSpreadable");
|
|
15
|
+
inline std::shared_ptr<JsSymbol> match = std::make_shared<JsSymbol>("Symbol.match", "@@match");
|
|
16
|
+
inline std::shared_ptr<JsSymbol> matchAll = std::make_shared<JsSymbol>("Symbol.matchAll", "@@matchAll");
|
|
17
|
+
inline std::shared_ptr<JsSymbol> replace = std::make_shared<JsSymbol>("Symbol.replace", "@@replace");
|
|
18
|
+
inline std::shared_ptr<JsSymbol> search = std::make_shared<JsSymbol>("Symbol.search", "@@search");
|
|
19
|
+
inline std::shared_ptr<JsSymbol> species = std::make_shared<JsSymbol>("Symbol.species", "@@species");
|
|
20
|
+
inline std::shared_ptr<JsSymbol> split = std::make_shared<JsSymbol>("Symbol.split", "@@split");
|
|
21
|
+
inline std::shared_ptr<JsSymbol> toPrimitive = std::make_shared<JsSymbol>("Symbol.toPrimitive", "@@toPrimitive");
|
|
22
|
+
inline std::shared_ptr<JsSymbol> toStringTag = std::make_shared<JsSymbol>("Symbol.toStringTag", "@@toStringTag");
|
|
23
|
+
inline std::shared_ptr<JsSymbol> unscopables = std::make_shared<JsSymbol>("Symbol.unscopables", "@@unscopables");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -10,20 +10,23 @@ namespace jspp
|
|
|
10
10
|
|
|
11
11
|
struct JsArray
|
|
12
12
|
{
|
|
13
|
-
std::vector<
|
|
14
|
-
std::unordered_map<uint32_t,
|
|
15
|
-
std::unordered_map<std::string, AnyValue> props;
|
|
13
|
+
std::vector<AnyValue> dense; // dense storage for small/contiguous indices
|
|
14
|
+
std::unordered_map<uint32_t, AnyValue> sparse; // sparse indices (very large indices)
|
|
15
|
+
std::unordered_map<std::string, AnyValue> props; // non-index string properties
|
|
16
|
+
std::shared_ptr<AnyValue> proto;
|
|
16
17
|
uint64_t length = 0;
|
|
17
18
|
|
|
18
|
-
JsArray()
|
|
19
|
-
explicit JsArray(const std::vector<
|
|
19
|
+
JsArray() : proto(nullptr) {}
|
|
20
|
+
explicit JsArray(const std::vector<AnyValue> &items) : dense(items), proto(nullptr), length(items.size()) {}
|
|
21
|
+
explicit JsArray(std::vector<AnyValue> &&items) : dense(std::move(items)), proto(nullptr), length(dense.size()) {}
|
|
20
22
|
|
|
21
23
|
std::string to_std_string() const;
|
|
22
24
|
JsIterator<AnyValue> get_iterator();
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
bool has_property(const std::string &key) const;
|
|
27
|
+
AnyValue get_property(const std::string &key, const AnyValue &thisVal);
|
|
25
28
|
AnyValue get_property(uint32_t idx);
|
|
26
|
-
AnyValue set_property(const std::string &key, const AnyValue &value);
|
|
29
|
+
AnyValue set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal);
|
|
27
30
|
AnyValue set_property(uint32_t idx, const AnyValue &value);
|
|
28
31
|
|
|
29
32
|
static bool is_array_index(const std::string &s)
|
|
@@ -17,8 +17,8 @@ namespace jspp
|
|
|
17
17
|
|
|
18
18
|
struct AccessorDescriptor
|
|
19
19
|
{
|
|
20
|
-
std::optional<std::function<AnyValue(const std::
|
|
21
|
-
std::optional<std::function<AnyValue(const std::
|
|
20
|
+
std::optional<std::function<AnyValue(const AnyValue &, std::span<const AnyValue>)>> get; // getter = function or undefined
|
|
21
|
+
std::optional<std::function<AnyValue(const AnyValue &, std::span<const AnyValue>)>> set; // setter = function or undefined
|
|
22
22
|
bool enumerable = false;
|
|
23
23
|
bool configurable = true;
|
|
24
24
|
};
|
|
@@ -1,51 +1,85 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include "types.hpp"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include <variant>
|
|
5
|
+
#include <optional>
|
|
6
|
+
|
|
7
|
+
namespace jspp
|
|
8
|
+
{
|
|
9
|
+
// Forward declaration of AnyValue
|
|
10
|
+
class AnyValue;
|
|
11
|
+
|
|
12
|
+
using JsFunctionCallable = std::variant<std::function<AnyValue(const AnyValue &, std::span<const AnyValue>)>, // 0: Normal
|
|
13
|
+
std::function<jspp::JsIterator<jspp::AnyValue>(const AnyValue &, std::span<const AnyValue>)>, // 1: Generator
|
|
14
|
+
std::function<jspp::JsPromise(const AnyValue &, std::span<const AnyValue>)>>; // 2: Async
|
|
15
|
+
|
|
16
|
+
struct JsFunction
|
|
17
|
+
{
|
|
18
|
+
JsFunctionCallable callable;
|
|
19
|
+
std::optional<std::string> name;
|
|
20
|
+
std::unordered_map<std::string, AnyValue> props;
|
|
21
|
+
std::shared_ptr<AnyValue> proto = nullptr;
|
|
22
|
+
bool is_generator;
|
|
23
|
+
bool is_async;
|
|
24
|
+
bool is_class;
|
|
25
|
+
bool is_constructor;
|
|
26
|
+
|
|
27
|
+
// ---- Constructor A: infer flags ----
|
|
28
|
+
JsFunction(const JsFunctionCallable &c,
|
|
29
|
+
std::optional<std::string> n = std::nullopt,
|
|
30
|
+
std::unordered_map<std::string, AnyValue> p = {},
|
|
31
|
+
bool is_cls = false,
|
|
32
|
+
bool is_ctor = true)
|
|
33
|
+
: callable(c),
|
|
34
|
+
name(std::move(n)),
|
|
35
|
+
props(std::move(p)),
|
|
36
|
+
is_generator(callable.index() == 1),
|
|
37
|
+
is_async(callable.index() == 2),
|
|
38
|
+
is_class(is_cls),
|
|
39
|
+
is_constructor(is_ctor && !is_generator && !is_async) // Generators and asyncs are never constructors
|
|
40
|
+
{
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ---- Constructor B: explicit generator flag (backward compat) ----
|
|
44
|
+
JsFunction(const JsFunctionCallable &c,
|
|
45
|
+
bool is_gen,
|
|
46
|
+
std::optional<std::string> n = std::nullopt,
|
|
47
|
+
std::unordered_map<std::string, AnyValue> p = {},
|
|
48
|
+
bool is_cls = false,
|
|
49
|
+
bool is_ctor = true)
|
|
50
|
+
: callable(c),
|
|
51
|
+
name(std::move(n)),
|
|
52
|
+
props(std::move(p)),
|
|
53
|
+
is_generator(is_gen),
|
|
54
|
+
is_async(callable.index() == 2),
|
|
55
|
+
is_class(is_cls),
|
|
56
|
+
is_constructor(is_ctor && !is_gen && !is_async)
|
|
57
|
+
{
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ---- Constructor C: explicit async flag ----
|
|
61
|
+
JsFunction(const JsFunctionCallable &c,
|
|
62
|
+
bool is_gen,
|
|
63
|
+
bool is_async_func,
|
|
64
|
+
std::optional<std::string> n = std::nullopt,
|
|
65
|
+
std::unordered_map<std::string, AnyValue> p = {},
|
|
66
|
+
bool is_cls = false,
|
|
67
|
+
bool is_ctor = true)
|
|
68
|
+
: callable(c),
|
|
69
|
+
name(std::move(n)),
|
|
70
|
+
props(std::move(p)),
|
|
71
|
+
is_generator(is_gen),
|
|
72
|
+
is_async(is_async_func),
|
|
73
|
+
is_class(is_cls),
|
|
74
|
+
is_constructor(is_ctor && !is_gen && !is_async_func)
|
|
75
|
+
{
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
std::string to_std_string() const;
|
|
79
|
+
AnyValue call(const AnyValue &thisVal, std::span<const AnyValue> args);
|
|
80
|
+
|
|
81
|
+
bool has_property(const std::string &key) const;
|
|
82
|
+
AnyValue get_property(const std::string &key, const AnyValue &thisVal);
|
|
83
|
+
AnyValue set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal);
|
|
84
|
+
};
|
|
85
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
#include "types.hpp"
|
|
4
4
|
#include "values/array.hpp"
|
|
5
|
-
#include "
|
|
5
|
+
#include "exception.hpp"
|
|
6
6
|
#include "any_value.hpp"
|
|
7
7
|
#include "values/prototypes/array.hpp"
|
|
8
8
|
|
|
@@ -16,23 +16,23 @@ std::string jspp::JsArray::to_std_string() const
|
|
|
16
16
|
std::string result = "";
|
|
17
17
|
for (uint64_t i = 0; i < length; ++i)
|
|
18
18
|
{
|
|
19
|
-
|
|
19
|
+
const AnyValue *itemPtr = nullptr;
|
|
20
20
|
if (i < dense.size())
|
|
21
21
|
{
|
|
22
|
-
|
|
22
|
+
itemPtr = &dense[i];
|
|
23
23
|
}
|
|
24
24
|
else
|
|
25
25
|
{
|
|
26
26
|
auto it = sparse.find(static_cast<uint32_t>(i));
|
|
27
27
|
if (it != sparse.end())
|
|
28
28
|
{
|
|
29
|
-
|
|
29
|
+
itemPtr = &it->second;
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
if (
|
|
33
|
+
if (itemPtr && !itemPtr->is_uninitialized())
|
|
34
34
|
{
|
|
35
|
-
const auto &item =
|
|
35
|
+
const auto &item = *itemPtr;
|
|
36
36
|
if (!item.is_undefined() && !item.is_null())
|
|
37
37
|
{
|
|
38
38
|
result += item.to_std_string();
|
|
@@ -57,7 +57,33 @@ jspp::JsIterator<jspp::AnyValue> jspp::JsArray::get_iterator()
|
|
|
57
57
|
co_return AnyValue::make_undefined();
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
bool jspp::JsArray::has_property(const std::string &key) const
|
|
61
|
+
{
|
|
62
|
+
if (key == "length")
|
|
63
|
+
return true;
|
|
64
|
+
if (is_array_index(key))
|
|
65
|
+
{
|
|
66
|
+
uint32_t idx = static_cast<uint32_t>(std::stoull(key));
|
|
67
|
+
if (idx < dense.size())
|
|
68
|
+
return true;
|
|
69
|
+
if (sparse.find(idx) != sparse.end())
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
if (props.find(key) != props.end())
|
|
73
|
+
return true;
|
|
74
|
+
|
|
75
|
+
if (proto && !(*proto).is_null() && !(*proto).is_undefined())
|
|
76
|
+
{
|
|
77
|
+
if ((*proto).has_property(key))
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (ArrayPrototypes::get(key, const_cast<JsArray *>(this)).has_value())
|
|
82
|
+
return true;
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
jspp::AnyValue jspp::JsArray::get_property(const std::string &key, const AnyValue &thisVal)
|
|
61
87
|
{
|
|
62
88
|
if (
|
|
63
89
|
!key.empty() && std::isdigit(static_cast<unsigned char>(key[0])) // Quick check: if the first character is not a digit, it can't be a standard index.
|
|
@@ -71,16 +97,35 @@ jspp::AnyValue jspp::JsArray::get_property(const std::string &key)
|
|
|
71
97
|
auto it = props.find(key);
|
|
72
98
|
if (it == props.end())
|
|
73
99
|
{
|
|
74
|
-
// check
|
|
100
|
+
// check special own properties (length)
|
|
101
|
+
if (key == "length")
|
|
102
|
+
{
|
|
103
|
+
auto proto_it = ArrayPrototypes::get(key, this);
|
|
104
|
+
if (proto_it.has_value())
|
|
105
|
+
{
|
|
106
|
+
return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// check explicit proto chain
|
|
111
|
+
if (proto && !(*proto).is_null() && !(*proto).is_undefined())
|
|
112
|
+
{
|
|
113
|
+
if ((*proto).has_property(key))
|
|
114
|
+
{
|
|
115
|
+
return (*proto).get_property_with_receiver(key, thisVal);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// check prototype (implicit Array.prototype)
|
|
75
120
|
auto proto_it = ArrayPrototypes::get(key, this);
|
|
76
121
|
if (proto_it.has_value())
|
|
77
122
|
{
|
|
78
|
-
return AnyValue::resolve_property_for_read(proto_it.value());
|
|
123
|
+
return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
|
|
79
124
|
}
|
|
80
125
|
// not found
|
|
81
126
|
return AnyValue::make_undefined();
|
|
82
127
|
}
|
|
83
|
-
return AnyValue::resolve_property_for_read(it->second);
|
|
128
|
+
return AnyValue::resolve_property_for_read(it->second, thisVal, key);
|
|
84
129
|
}
|
|
85
130
|
}
|
|
86
131
|
|
|
@@ -88,17 +133,19 @@ jspp::AnyValue jspp::JsArray::get_property(uint32_t idx)
|
|
|
88
133
|
{
|
|
89
134
|
if (idx < dense.size())
|
|
90
135
|
{
|
|
91
|
-
|
|
136
|
+
const auto &val = dense[idx];
|
|
137
|
+
return val.is_uninitialized() ? AnyValue::make_undefined() : val;
|
|
92
138
|
}
|
|
93
139
|
const auto &it = sparse.find(idx);
|
|
94
140
|
if (it != sparse.end())
|
|
95
141
|
{
|
|
96
|
-
|
|
142
|
+
const auto &val = it->second;
|
|
143
|
+
return val.is_uninitialized() ? AnyValue::make_undefined() : val;
|
|
97
144
|
}
|
|
98
145
|
return AnyValue::make_undefined();
|
|
99
146
|
}
|
|
100
147
|
|
|
101
|
-
jspp::AnyValue jspp::JsArray::set_property(const std::string &key, const AnyValue &value)
|
|
148
|
+
jspp::AnyValue jspp::JsArray::set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal)
|
|
102
149
|
{
|
|
103
150
|
if (
|
|
104
151
|
!key.empty() && std::isdigit(static_cast<unsigned char>(key[0])) // Quick check: if the first character is not a digit, it can't be a standard index.
|
|
@@ -111,17 +158,30 @@ jspp::AnyValue jspp::JsArray::set_property(const std::string &key, const AnyValu
|
|
|
111
158
|
{
|
|
112
159
|
// set prototype property if accessor descriptor
|
|
113
160
|
auto proto_val_opt = ArrayPrototypes::get(key, this);
|
|
161
|
+
if (!proto_val_opt.has_value() && proto && !(*proto).is_null() && !(*proto).is_undefined())
|
|
162
|
+
{
|
|
163
|
+
// This is a bit simplified, ideally we should call get_property on proto to check descriptors
|
|
164
|
+
// For now, let's assume if it's not in ArrayPrototypes, it might be in the explicit proto chain
|
|
165
|
+
}
|
|
166
|
+
|
|
114
167
|
if (proto_val_opt.has_value())
|
|
115
168
|
{
|
|
116
169
|
auto proto_value = proto_val_opt.value();
|
|
117
|
-
|
|
170
|
+
if (proto_value.is_accessor_descriptor())
|
|
171
|
+
{
|
|
172
|
+
return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
|
|
173
|
+
}
|
|
174
|
+
if (proto_value.is_data_descriptor() && !proto_value.as_data_descriptor()->writable)
|
|
175
|
+
{
|
|
176
|
+
return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
|
|
177
|
+
}
|
|
118
178
|
}
|
|
119
179
|
|
|
120
180
|
// set own property
|
|
121
181
|
auto it = props.find(key);
|
|
122
182
|
if (it != props.end())
|
|
123
183
|
{
|
|
124
|
-
return AnyValue::resolve_property_for_write(it->second, value);
|
|
184
|
+
return AnyValue::resolve_property_for_write(it->second, thisVal, value, key);
|
|
125
185
|
}
|
|
126
186
|
else
|
|
127
187
|
{
|
|
@@ -140,33 +200,18 @@ jspp::AnyValue jspp::JsArray::set_property(uint32_t idx, const AnyValue &value)
|
|
|
140
200
|
const uint32_t DENSE_GROW_THRESHOLD = 1024;
|
|
141
201
|
if (idx < dense.size())
|
|
142
202
|
{
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
dense[idx] = AnyValue::make_undefined();
|
|
146
|
-
}
|
|
147
|
-
return AnyValue::resolve_property_for_write(dense[idx].value(), value);
|
|
203
|
+
dense[idx] = value;
|
|
204
|
+
return value;
|
|
148
205
|
}
|
|
149
206
|
else if (idx <= dense.size() + DENSE_GROW_THRESHOLD)
|
|
150
207
|
{
|
|
151
|
-
dense.resize(idx + 1);
|
|
208
|
+
dense.resize(idx + 1, AnyValue::make_uninitialized());
|
|
152
209
|
dense[idx] = value;
|
|
153
210
|
return value;
|
|
154
211
|
}
|
|
155
212
|
else
|
|
156
213
|
{
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
{
|
|
160
|
-
if (!it->second.has_value())
|
|
161
|
-
{
|
|
162
|
-
it->second = AnyValue::make_undefined();
|
|
163
|
-
}
|
|
164
|
-
return AnyValue::resolve_property_for_write(it->second.value(), value);
|
|
165
|
-
}
|
|
166
|
-
else
|
|
167
|
-
{
|
|
168
|
-
sparse[idx] = value;
|
|
169
|
-
return value;
|
|
170
|
-
}
|
|
214
|
+
sparse[idx] = value;
|
|
215
|
+
return value;
|
|
171
216
|
}
|
|
172
217
|
}
|
|
@@ -1,77 +1,110 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include <variant>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
#include "
|
|
7
|
-
#include "
|
|
8
|
-
#include "
|
|
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
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <variant>
|
|
4
|
+
#include <optional>
|
|
5
|
+
|
|
6
|
+
#include "types.hpp"
|
|
7
|
+
#include "values/function.hpp"
|
|
8
|
+
#include "any_value.hpp"
|
|
9
|
+
#include "values/prototypes/function.hpp"
|
|
10
|
+
|
|
11
|
+
namespace jspp
|
|
12
|
+
{
|
|
13
|
+
std::string JsFunction::to_std_string() const
|
|
14
|
+
{
|
|
15
|
+
std::string type_part = this->is_async ? "async function" : this->is_generator ? "function*"
|
|
16
|
+
: "function";
|
|
17
|
+
std::string name_part = this->name.value_or("");
|
|
18
|
+
return type_part + " " + name_part + "() { [native code] }";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
AnyValue JsFunction::call(const AnyValue &thisVal, std::span<const AnyValue> args)
|
|
22
|
+
{
|
|
23
|
+
if (std::function<AnyValue(const AnyValue &, std::span<const AnyValue>)> *func = std::get_if<0>(&callable))
|
|
24
|
+
{
|
|
25
|
+
return (*func)(thisVal, args);
|
|
26
|
+
}
|
|
27
|
+
else if (std::function<jspp::JsIterator<jspp::AnyValue>(const AnyValue &, std::span<const AnyValue>)> *func = std::get_if<1>(&callable))
|
|
28
|
+
{
|
|
29
|
+
return AnyValue::from_iterator((*func)(thisVal, args));
|
|
30
|
+
}
|
|
31
|
+
else if (std::function<jspp::JsPromise(const AnyValue &, std::span<const AnyValue>)> *func = std::get_if<2>(&callable))
|
|
32
|
+
{
|
|
33
|
+
return AnyValue::make_promise((*func)(thisVal, args));
|
|
34
|
+
}
|
|
35
|
+
else
|
|
36
|
+
{
|
|
37
|
+
return AnyValue::make_undefined();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
bool JsFunction::has_property(const std::string &key) const
|
|
42
|
+
{
|
|
43
|
+
if (props.find(key) != props.end())
|
|
44
|
+
return true;
|
|
45
|
+
if (proto && !(*proto).is_null() && !(*proto).is_undefined())
|
|
46
|
+
{
|
|
47
|
+
if ((*proto).has_property(key))
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
if (FunctionPrototypes::get(key, const_cast<JsFunction *>(this)).has_value())
|
|
51
|
+
return true;
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
AnyValue JsFunction::get_property(const std::string &key, const AnyValue &thisVal)
|
|
56
|
+
{
|
|
57
|
+
auto it = props.find(key);
|
|
58
|
+
if (it == props.end())
|
|
59
|
+
{
|
|
60
|
+
// check explicit proto chain (e.g. for classes extending other classes)
|
|
61
|
+
if (proto && !(*proto).is_null() && !(*proto).is_undefined())
|
|
62
|
+
{
|
|
63
|
+
if ((*proto).has_property(key))
|
|
64
|
+
{
|
|
65
|
+
return (*proto).get_property_with_receiver(key, thisVal);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// check prototype (implicit Function.prototype)
|
|
70
|
+
auto proto_it = FunctionPrototypes::get(key, this);
|
|
71
|
+
if (proto_it.has_value())
|
|
72
|
+
{
|
|
73
|
+
return AnyValue::resolve_property_for_read(proto_it.value(), thisVal, key);
|
|
74
|
+
}
|
|
75
|
+
// not found
|
|
76
|
+
return AnyValue::make_undefined();
|
|
77
|
+
}
|
|
78
|
+
return AnyValue::resolve_property_for_read(it->second, thisVal, key);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
AnyValue JsFunction::set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal)
|
|
82
|
+
{
|
|
83
|
+
// set prototype property if accessor descriptor
|
|
84
|
+
auto proto_it = FunctionPrototypes::get(key, this);
|
|
85
|
+
if (proto_it.has_value())
|
|
86
|
+
{
|
|
87
|
+
auto proto_value = proto_it.value();
|
|
88
|
+
if (proto_value.is_accessor_descriptor())
|
|
89
|
+
{
|
|
90
|
+
return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
|
|
91
|
+
}
|
|
92
|
+
if (proto_value.is_data_descriptor() && !proto_value.as_data_descriptor()->writable)
|
|
93
|
+
{
|
|
94
|
+
return AnyValue::resolve_property_for_write(proto_value, thisVal, value, key);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// set own property
|
|
99
|
+
auto it = props.find(key);
|
|
100
|
+
if (it != props.end())
|
|
101
|
+
{
|
|
102
|
+
return AnyValue::resolve_property_for_write(it->second, thisVal, value, key);
|
|
103
|
+
}
|
|
104
|
+
else
|
|
105
|
+
{
|
|
106
|
+
props[key] = value;
|
|
107
|
+
return value;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|