@ugo-studio/jspp 0.1.2 → 0.1.3
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 +3 -1
- package/dist/analysis/scope.js +22 -11
- package/dist/analysis/typeAnalyzer.js +4 -3
- package/dist/cli.js +2 -2
- package/dist/core/codegen/expression-handlers.js +10 -6
- package/dist/core/codegen/function-handlers.js +27 -6
- package/dist/core/codegen/helpers.js +12 -8
- package/dist/core/codegen/index.js +3 -1
- package/dist/core/codegen/statement-handlers.js +53 -16
- package/dist/core/codegen/visitor.js +7 -1
- package/package.json +1 -1
- package/src/prelude/access.hpp +8 -3
- package/src/prelude/any_value.hpp +141 -241
- package/src/prelude/any_value_helpers.hpp +225 -0
- package/src/prelude/error_helpers.hpp +3 -3
- package/src/prelude/index.hpp +17 -3
- package/src/prelude/library/console.hpp +7 -7
- package/src/prelude/library/performance.hpp +25 -0
- package/src/prelude/library/symbol.hpp +60 -3
- package/src/prelude/log_string.hpp +10 -6
- package/src/prelude/operators.hpp +2 -2
- package/src/prelude/types.hpp +24 -6
- package/src/prelude/values/array.hpp +2 -0
- package/src/prelude/values/function.hpp +33 -1
- package/src/prelude/values/{operators → helpers}/array.hpp +14 -7
- package/src/prelude/values/helpers/function.hpp +77 -0
- package/src/prelude/values/helpers/iterator.hpp +101 -0
- package/src/prelude/values/helpers/string.hpp +50 -0
- package/src/prelude/values/helpers/symbol.hpp +23 -0
- package/src/prelude/values/iterator.hpp +88 -0
- package/src/prelude/values/object.hpp +2 -1
- package/src/prelude/values/prototypes/array.hpp +18 -11
- package/src/prelude/values/prototypes/function.hpp +26 -0
- package/src/prelude/values/prototypes/iterator.hpp +57 -0
- package/src/prelude/values/prototypes/string.hpp +366 -357
- package/src/prelude/values/prototypes/symbol.hpp +39 -0
- package/src/prelude/values/string.hpp +25 -0
- package/src/prelude/values/symbol.hpp +102 -0
- package/src/prelude/well_known_symbols.hpp +7 -3
- package/src/prelude/values/operators/function.hpp +0 -34
- /package/src/prelude/values/{operators → helpers}/object.hpp +0 -0
|
@@ -47,6 +47,16 @@ std::string jspp::JsArray::to_std_string() const
|
|
|
47
47
|
return result;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
jspp::JsIterator<jspp::AnyValue> jspp::JsArray::get_iterator()
|
|
51
|
+
{
|
|
52
|
+
for (uint64_t idx = 0; idx < length; ++idx)
|
|
53
|
+
{
|
|
54
|
+
co_yield get_property(static_cast<uint32_t>(idx));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
co_return AnyValue::make_undefined();
|
|
58
|
+
}
|
|
59
|
+
|
|
50
60
|
jspp::AnyValue jspp::JsArray::get_property(const std::string &key)
|
|
51
61
|
{
|
|
52
62
|
if (
|
|
@@ -100,14 +110,11 @@ jspp::AnyValue jspp::JsArray::set_property(const std::string &key, const AnyValu
|
|
|
100
110
|
else
|
|
101
111
|
{
|
|
102
112
|
// set prototype property if accessor descriptor
|
|
103
|
-
auto
|
|
104
|
-
if (
|
|
113
|
+
auto proto_val_opt = ArrayPrototypes::get(key, this);
|
|
114
|
+
if (proto_val_opt.has_value())
|
|
105
115
|
{
|
|
106
|
-
auto proto_value =
|
|
107
|
-
|
|
108
|
-
{
|
|
109
|
-
return AnyValue::resolve_property_for_write(proto_it.value(), value);
|
|
110
|
-
}
|
|
116
|
+
auto proto_value = proto_val_opt.value();
|
|
117
|
+
return AnyValue::resolve_property_for_write(proto_value, value);
|
|
111
118
|
}
|
|
112
119
|
|
|
113
120
|
// set own property
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <variant>
|
|
4
|
+
|
|
5
|
+
#include "types.hpp"
|
|
6
|
+
#include "values/function.hpp"
|
|
7
|
+
#include "any_value.hpp"
|
|
8
|
+
#include "values/prototypes/function.hpp"
|
|
9
|
+
|
|
10
|
+
std::string jspp::JsFunction::to_std_string() const
|
|
11
|
+
{
|
|
12
|
+
if (is_generator)
|
|
13
|
+
{
|
|
14
|
+
return "function* " + name + "() { [native code] }";
|
|
15
|
+
}
|
|
16
|
+
return "function " + name + "() { [native code] }";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
jspp::AnyValue jspp::JsFunction::call(const std::vector<AnyValue> &args)
|
|
20
|
+
{
|
|
21
|
+
|
|
22
|
+
if (std::function<AnyValue(const std::vector<AnyValue> &)> *func = std::get_if<0>(&callable))
|
|
23
|
+
{
|
|
24
|
+
return (*func)(args);
|
|
25
|
+
}
|
|
26
|
+
else if (std::function<jspp::JsIterator<jspp::AnyValue>(const std::vector<jspp::AnyValue> &)> *func = std::get_if<1>(&callable))
|
|
27
|
+
{
|
|
28
|
+
return AnyValue::from_iterator((*func)(args));
|
|
29
|
+
}
|
|
30
|
+
else
|
|
31
|
+
{
|
|
32
|
+
return AnyValue::make_undefined();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
jspp::AnyValue jspp::JsFunction::get_property(const std::string &key)
|
|
37
|
+
{
|
|
38
|
+
auto it = props.find(key);
|
|
39
|
+
if (it == props.end())
|
|
40
|
+
{
|
|
41
|
+
// check prototype
|
|
42
|
+
auto proto_it = FunctionPrototypes::get(key, this);
|
|
43
|
+
if (proto_it.has_value())
|
|
44
|
+
{
|
|
45
|
+
return AnyValue::resolve_property_for_read(proto_it.value());
|
|
46
|
+
}
|
|
47
|
+
// not found
|
|
48
|
+
return AnyValue::make_undefined();
|
|
49
|
+
}
|
|
50
|
+
return AnyValue::resolve_property_for_read(it->second);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
jspp::AnyValue jspp::JsFunction::set_property(const std::string &key, const AnyValue &value)
|
|
54
|
+
{
|
|
55
|
+
// set prototype property if accessor descriptor
|
|
56
|
+
auto proto_it = FunctionPrototypes::get(key, this);
|
|
57
|
+
if (proto_it.has_value())
|
|
58
|
+
{
|
|
59
|
+
auto proto_value = proto_it.value();
|
|
60
|
+
if (proto_value.is_accessor_descriptor())
|
|
61
|
+
{
|
|
62
|
+
return AnyValue::resolve_property_for_write(proto_value, value);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// set own property
|
|
67
|
+
auto it = props.find(key);
|
|
68
|
+
if (it != props.end())
|
|
69
|
+
{
|
|
70
|
+
return AnyValue::resolve_property_for_write(it->second, value);
|
|
71
|
+
}
|
|
72
|
+
else
|
|
73
|
+
{
|
|
74
|
+
props[key] = value;
|
|
75
|
+
return value;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include "values/iterator.hpp"
|
|
5
|
+
#include "any_value.hpp"
|
|
6
|
+
|
|
7
|
+
template <typename T>
|
|
8
|
+
std::string jspp::JsIterator<T>::to_std_string() const
|
|
9
|
+
{
|
|
10
|
+
return "[object Generator]";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
template <typename T>
|
|
14
|
+
jspp::JsIterator<T>::NextResult jspp::JsIterator<T>::next()
|
|
15
|
+
{
|
|
16
|
+
// If the generator is already finished or invalid, return {undefined, true}
|
|
17
|
+
if (!handle || handle.done())
|
|
18
|
+
return {std::nullopt, true};
|
|
19
|
+
|
|
20
|
+
// Resume execution until next co_yield or co_return
|
|
21
|
+
handle.resume();
|
|
22
|
+
|
|
23
|
+
if (handle.promise().exception_)
|
|
24
|
+
{
|
|
25
|
+
std::rethrow_exception(handle.promise().exception_);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// If handle.done() is TRUE, we hit co_return (value: X, done: true)
|
|
29
|
+
// If handle.done() is FALSE, we hit co_yield (value: X, done: false)
|
|
30
|
+
bool is_done = handle.done();
|
|
31
|
+
|
|
32
|
+
return {handle.promise().current_value, is_done};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
template <typename T>
|
|
36
|
+
std::vector<std::optional<T>> jspp::JsIterator<T>::to_vector()
|
|
37
|
+
{
|
|
38
|
+
std::vector<std::optional<AnyValue>> result;
|
|
39
|
+
while (true)
|
|
40
|
+
{
|
|
41
|
+
auto next = this->next();
|
|
42
|
+
if (next.done)
|
|
43
|
+
{
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
result.push_back(next.value);
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
template <typename T>
|
|
52
|
+
jspp::AnyValue jspp::JsIterator<T>::get_property(const std::string &key)
|
|
53
|
+
{
|
|
54
|
+
auto it = props.find(key);
|
|
55
|
+
if (it == props.end())
|
|
56
|
+
{
|
|
57
|
+
// check prototype
|
|
58
|
+
if constexpr (std::is_same_v<T, AnyValue>)
|
|
59
|
+
{
|
|
60
|
+
auto proto_it = IteratorPrototypes::get(key, this);
|
|
61
|
+
if (proto_it.has_value())
|
|
62
|
+
{
|
|
63
|
+
return AnyValue::resolve_property_for_read(proto_it.value());
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// prototype not found
|
|
67
|
+
return jspp::AnyValue::make_undefined();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return jspp::AnyValue::resolve_property_for_read(it->second);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
template <typename T>
|
|
74
|
+
jspp::AnyValue jspp::JsIterator<T>::set_property(const std::string &key, const AnyValue &value)
|
|
75
|
+
{
|
|
76
|
+
// set prototype property if accessor descriptor
|
|
77
|
+
if constexpr (std::is_same_v<T, AnyValue>)
|
|
78
|
+
{
|
|
79
|
+
auto proto_it = IteratorPrototypes::get(key, this);
|
|
80
|
+
if (proto_it.has_value())
|
|
81
|
+
{
|
|
82
|
+
auto proto_value = proto_it.value();
|
|
83
|
+
if (proto_value.is_accessor_descriptor())
|
|
84
|
+
{
|
|
85
|
+
return AnyValue::resolve_property_for_write(proto_it.value(), value);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// set own property
|
|
91
|
+
auto it = props.find(key);
|
|
92
|
+
if (it != props.end())
|
|
93
|
+
{
|
|
94
|
+
return jspp::AnyValue::resolve_property_for_write(it->second, value);
|
|
95
|
+
}
|
|
96
|
+
else
|
|
97
|
+
{
|
|
98
|
+
props[key] = value;
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include "values/array.hpp"
|
|
5
|
+
#include "values/string.hpp"
|
|
6
|
+
#include "error.hpp"
|
|
7
|
+
#include "any_value.hpp"
|
|
8
|
+
#include "values/prototypes/string.hpp"
|
|
9
|
+
|
|
10
|
+
std::string jspp::JsString::to_std_string() const
|
|
11
|
+
{
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
jspp::JsIterator<jspp::AnyValue> jspp::JsString::get_iterator()
|
|
16
|
+
{
|
|
17
|
+
size_t strLength = value.length();
|
|
18
|
+
for (size_t idx = 0; idx < strLength; idx++)
|
|
19
|
+
{
|
|
20
|
+
co_yield AnyValue::make_string(std::string(1, value[idx]));
|
|
21
|
+
}
|
|
22
|
+
co_return AnyValue::make_undefined();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
jspp::AnyValue jspp::JsString::get_property(const std::string &key)
|
|
26
|
+
{
|
|
27
|
+
// Check for prototype methods
|
|
28
|
+
auto proto_fn = StringPrototypes::get(key, this);
|
|
29
|
+
if (proto_fn.has_value())
|
|
30
|
+
{
|
|
31
|
+
return AnyValue::resolve_property_for_read(proto_fn.value());
|
|
32
|
+
}
|
|
33
|
+
// Handle character access by string index (e.g., "abc"["1"])
|
|
34
|
+
if (JsArray::is_array_index(key))
|
|
35
|
+
{
|
|
36
|
+
uint32_t idx = static_cast<uint32_t>(std::stoull(key));
|
|
37
|
+
return get_property(idx);
|
|
38
|
+
}
|
|
39
|
+
// not found
|
|
40
|
+
return AnyValue::make_undefined();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
jspp::AnyValue jspp::JsString::get_property(uint32_t idx)
|
|
44
|
+
{
|
|
45
|
+
if (idx < value.length())
|
|
46
|
+
{
|
|
47
|
+
return AnyValue::make_string(std::string(1, value[idx]));
|
|
48
|
+
}
|
|
49
|
+
return AnyValue::make_undefined();
|
|
50
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include "values/symbol.hpp"
|
|
5
|
+
#include "any_value.hpp"
|
|
6
|
+
#include "values/prototypes/symbol.hpp"
|
|
7
|
+
|
|
8
|
+
std::string jspp::JsSymbol::to_std_string() const
|
|
9
|
+
{
|
|
10
|
+
return "Symbol(" + description + ")";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
jspp::AnyValue jspp::JsSymbol::get_property(const std::string &key)
|
|
14
|
+
{
|
|
15
|
+
// check prototype
|
|
16
|
+
auto proto_it = SymbolPrototypes::get(key, this);
|
|
17
|
+
if (proto_it.has_value())
|
|
18
|
+
{
|
|
19
|
+
return AnyValue::resolve_property_for_read(proto_it.value());
|
|
20
|
+
}
|
|
21
|
+
// not found
|
|
22
|
+
return AnyValue::make_undefined();
|
|
23
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include <coroutine>
|
|
5
|
+
#include <optional>
|
|
6
|
+
#include <iostream>
|
|
7
|
+
#include <utility>
|
|
8
|
+
#include <exception>
|
|
9
|
+
|
|
10
|
+
namespace jspp
|
|
11
|
+
{
|
|
12
|
+
// Forward declaration of AnyValue
|
|
13
|
+
class AnyValue;
|
|
14
|
+
|
|
15
|
+
template <typename T>
|
|
16
|
+
class JsIterator
|
|
17
|
+
{
|
|
18
|
+
public:
|
|
19
|
+
struct NextResult
|
|
20
|
+
{
|
|
21
|
+
std::optional<T> value;
|
|
22
|
+
bool done;
|
|
23
|
+
};
|
|
24
|
+
struct promise_type
|
|
25
|
+
{
|
|
26
|
+
std::optional<T> current_value;
|
|
27
|
+
std::exception_ptr exception_;
|
|
28
|
+
|
|
29
|
+
JsIterator get_return_object()
|
|
30
|
+
{
|
|
31
|
+
return JsIterator{
|
|
32
|
+
std::coroutine_handle<promise_type>::from_promise(*this)};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
std::suspend_always initial_suspend() noexcept { return {}; }
|
|
36
|
+
|
|
37
|
+
// valid js generators allow access to the return value after completion,
|
|
38
|
+
// so we must suspend at the end to keep the promise (and value) alive.
|
|
39
|
+
std::suspend_always final_suspend() noexcept { return {}; }
|
|
40
|
+
|
|
41
|
+
// Handle co_yield
|
|
42
|
+
template <typename From>
|
|
43
|
+
std::suspend_always yield_value(From &&from)
|
|
44
|
+
{
|
|
45
|
+
current_value = std::forward<From>(from);
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Handle co_return
|
|
50
|
+
// This replaces return_void.
|
|
51
|
+
// It captures the final value and moves to final_suspend (implicit).
|
|
52
|
+
template <typename From>
|
|
53
|
+
void return_value(From &&from)
|
|
54
|
+
{
|
|
55
|
+
current_value = std::forward<From>(from);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
void unhandled_exception()
|
|
59
|
+
{
|
|
60
|
+
exception_ = std::current_exception();
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
using handle_type = std::coroutine_handle<promise_type>;
|
|
65
|
+
handle_type handle;
|
|
66
|
+
|
|
67
|
+
explicit JsIterator(handle_type h) : handle(h) {}
|
|
68
|
+
JsIterator(JsIterator &&other) noexcept : handle(std::exchange(other.handle, nullptr)) {}
|
|
69
|
+
|
|
70
|
+
// Delete copy constructor/assignment to ensure unique ownership of the handle
|
|
71
|
+
JsIterator(const JsIterator &) = delete;
|
|
72
|
+
JsIterator &operator=(const JsIterator &) = delete;
|
|
73
|
+
|
|
74
|
+
~JsIterator()
|
|
75
|
+
{
|
|
76
|
+
if (handle)
|
|
77
|
+
handle.destroy();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
std::unordered_map<std::string, AnyValue> props;
|
|
81
|
+
|
|
82
|
+
std::string to_std_string() const;
|
|
83
|
+
NextResult next();
|
|
84
|
+
std::vector<std::optional<T>> to_vector();
|
|
85
|
+
AnyValue get_property(const std::string &key);
|
|
86
|
+
AnyValue set_property(const std::string &key, const AnyValue &value);
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
namespace jspp
|
|
6
6
|
{
|
|
7
|
+
// Forward declaration of AnyValue
|
|
7
8
|
class AnyValue;
|
|
8
9
|
|
|
9
10
|
struct JsObject
|
|
10
11
|
{
|
|
11
|
-
std::
|
|
12
|
+
std::map<std::string, AnyValue> props;
|
|
12
13
|
|
|
13
14
|
std::string to_std_string() const;
|
|
14
15
|
AnyValue get_property(const std::string &key);
|
|
@@ -14,24 +14,31 @@ namespace jspp
|
|
|
14
14
|
{
|
|
15
15
|
inline std::optional<AnyValue> get(const std::string &key, JsArray *self)
|
|
16
16
|
{
|
|
17
|
-
|
|
18
17
|
// --- toString() method ---
|
|
19
|
-
if (key == "toString")
|
|
18
|
+
if (key == "toString" || key == WellKnownSymbols::toString->key)
|
|
20
19
|
{
|
|
21
|
-
return AnyValue::make_function([
|
|
20
|
+
return AnyValue::make_function([self](const std::vector<AnyValue> &_) -> AnyValue
|
|
22
21
|
{ return AnyValue::make_string(self->to_std_string()); },
|
|
23
22
|
key);
|
|
24
23
|
}
|
|
25
24
|
|
|
25
|
+
// --- [Symbol.iterator]() method ---
|
|
26
|
+
if (key == WellKnownSymbols::iterator->key)
|
|
27
|
+
{
|
|
28
|
+
return AnyValue::make_generator([self](const std::vector<AnyValue> &_) -> AnyValue
|
|
29
|
+
{ return AnyValue::from_iterator(self->get_iterator()); },
|
|
30
|
+
key);
|
|
31
|
+
}
|
|
32
|
+
|
|
26
33
|
// --- length property ---
|
|
27
34
|
if (key == "length")
|
|
28
35
|
{
|
|
29
|
-
auto getter = [
|
|
36
|
+
auto getter = [self](const std::vector<AnyValue> &args) -> AnyValue
|
|
30
37
|
{
|
|
31
38
|
return AnyValue::make_number(self->length);
|
|
32
39
|
};
|
|
33
40
|
|
|
34
|
-
auto setter = [
|
|
41
|
+
auto setter = [self](const std::vector<AnyValue> &args) -> AnyValue
|
|
35
42
|
{
|
|
36
43
|
if (args.empty())
|
|
37
44
|
{
|
|
@@ -79,7 +86,7 @@ namespace jspp
|
|
|
79
86
|
// --- push() method ---
|
|
80
87
|
if (key == "push")
|
|
81
88
|
{
|
|
82
|
-
return AnyValue::make_function([
|
|
89
|
+
return AnyValue::make_function([self](const std::vector<AnyValue> &args) -> AnyValue
|
|
83
90
|
{
|
|
84
91
|
for (const auto &arg : args)
|
|
85
92
|
{
|
|
@@ -92,7 +99,7 @@ namespace jspp
|
|
|
92
99
|
// --- pop() method ---
|
|
93
100
|
if (key == "pop")
|
|
94
101
|
{
|
|
95
|
-
return AnyValue::make_function([
|
|
102
|
+
return AnyValue::make_function([self](const std::vector<AnyValue> &args) -> AnyValue
|
|
96
103
|
{
|
|
97
104
|
if (self->length == 0)
|
|
98
105
|
{
|
|
@@ -117,7 +124,7 @@ namespace jspp
|
|
|
117
124
|
// --- shift() method ---
|
|
118
125
|
if (key == "shift")
|
|
119
126
|
{
|
|
120
|
-
return AnyValue::make_function([
|
|
127
|
+
return AnyValue::make_function([self](const std::vector<AnyValue> &args) -> AnyValue
|
|
121
128
|
{
|
|
122
129
|
if (self->length == 0)
|
|
123
130
|
{
|
|
@@ -148,7 +155,7 @@ namespace jspp
|
|
|
148
155
|
// --- unshift() method ---
|
|
149
156
|
if (key == "unshift")
|
|
150
157
|
{
|
|
151
|
-
return AnyValue::make_function([
|
|
158
|
+
return AnyValue::make_function([self](const std::vector<AnyValue> &args) -> AnyValue
|
|
152
159
|
{
|
|
153
160
|
size_t args_count = args.size();
|
|
154
161
|
if (args_count == 0)
|
|
@@ -175,7 +182,7 @@ namespace jspp
|
|
|
175
182
|
// --- join() method ---
|
|
176
183
|
if (key == "join")
|
|
177
184
|
{
|
|
178
|
-
return AnyValue::make_function([
|
|
185
|
+
return AnyValue::make_function([self](const std::vector<AnyValue> &args) -> AnyValue
|
|
179
186
|
{
|
|
180
187
|
std::string sep = ",";
|
|
181
188
|
if (!args.empty() && !args[0].is_undefined())
|
|
@@ -203,7 +210,7 @@ namespace jspp
|
|
|
203
210
|
// --- forEach() method ---
|
|
204
211
|
if (key == "forEach")
|
|
205
212
|
{
|
|
206
|
-
return AnyValue::make_function([
|
|
213
|
+
return AnyValue::make_function([self](const std::vector<AnyValue> &args) -> AnyValue
|
|
207
214
|
{
|
|
208
215
|
if (args.empty() || !args[0].is_function())
|
|
209
216
|
{
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include "values/function.hpp"
|
|
5
|
+
#include "any_value.hpp"
|
|
6
|
+
#include "error.hpp"
|
|
7
|
+
#include "operators.hpp"
|
|
8
|
+
|
|
9
|
+
namespace jspp
|
|
10
|
+
{
|
|
11
|
+
namespace FunctionPrototypes
|
|
12
|
+
{
|
|
13
|
+
inline std::optional<AnyValue> get(const std::string &key, JsFunction *self)
|
|
14
|
+
{
|
|
15
|
+
// --- toString() method ---
|
|
16
|
+
if (key == "toString" || key == WellKnownSymbols::toString->key)
|
|
17
|
+
{
|
|
18
|
+
return AnyValue::make_function([self](const std::vector<AnyValue> &_) -> AnyValue
|
|
19
|
+
{ return AnyValue::make_string(self->to_std_string()); },
|
|
20
|
+
key);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return std::nullopt;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "types.hpp"
|
|
4
|
+
#include "values/iterator.hpp"
|
|
5
|
+
#include "any_value.hpp"
|
|
6
|
+
#include "error.hpp"
|
|
7
|
+
#include "operators.hpp"
|
|
8
|
+
|
|
9
|
+
namespace jspp
|
|
10
|
+
{
|
|
11
|
+
namespace IteratorPrototypes
|
|
12
|
+
{
|
|
13
|
+
inline std::optional<AnyValue> get(const std::string &key, JsIterator<AnyValue> *self)
|
|
14
|
+
{
|
|
15
|
+
// --- toString() method ---
|
|
16
|
+
if (key == "toString" || key == WellKnownSymbols::toString->key)
|
|
17
|
+
{
|
|
18
|
+
return AnyValue::make_function([self](const std::vector<AnyValue> &) -> AnyValue
|
|
19
|
+
{ return AnyValue::make_string(self->to_std_string()); },
|
|
20
|
+
key);
|
|
21
|
+
}
|
|
22
|
+
// --- [Symbol.iterator]() method ---
|
|
23
|
+
if (key == WellKnownSymbols::iterator->key)
|
|
24
|
+
{
|
|
25
|
+
return AnyValue::make_function([self](const std::vector<AnyValue> &) -> AnyValue
|
|
26
|
+
{
|
|
27
|
+
// An iterator's iterator is itself.
|
|
28
|
+
// We need to return an AnyValue that holds a shared_ptr to this JsIterator.
|
|
29
|
+
// Since we only have a raw pointer `self`, we can't directly make a new shared_ptr.
|
|
30
|
+
// We'll return an AnyValue wrapping the raw pointer for now.
|
|
31
|
+
// This relies on the calling context to manage lifetime, which is true for `for-of`.
|
|
32
|
+
// A better solution might involve passing a shared_ptr to `self` into the prototype getters.
|
|
33
|
+
// For now, let's assume the object containing the iterator is alive.
|
|
34
|
+
return AnyValue::from_iterator_ref(self); },
|
|
35
|
+
key);
|
|
36
|
+
}
|
|
37
|
+
// --- next() method ---
|
|
38
|
+
if (key == "next")
|
|
39
|
+
{
|
|
40
|
+
return AnyValue::make_function([self](const std::vector<AnyValue> &) -> AnyValue
|
|
41
|
+
{
|
|
42
|
+
auto res = self->next();
|
|
43
|
+
return AnyValue::make_object({{"value",res.value.value_or(AnyValue::make_undefined())},{"done",AnyValue::make_boolean(res.done)},}); },
|
|
44
|
+
key);
|
|
45
|
+
}
|
|
46
|
+
// --- toArray() method ---
|
|
47
|
+
if (key == "toArray")
|
|
48
|
+
{
|
|
49
|
+
return AnyValue::make_function([self](const std::vector<AnyValue> &) -> AnyValue
|
|
50
|
+
{ return AnyValue::make_array(self->to_vector()); },
|
|
51
|
+
key);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return std::nullopt;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|