@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.
Files changed (83) hide show
  1. package/README.md +2 -2
  2. package/dist/analysis/scope.js +33 -4
  3. package/dist/analysis/typeAnalyzer.js +260 -21
  4. package/dist/ast/symbols.js +29 -0
  5. package/dist/cli-utils/args.js +57 -0
  6. package/dist/cli-utils/colors.js +9 -0
  7. package/dist/cli-utils/file-utils.js +20 -0
  8. package/dist/cli-utils/spinner.js +55 -0
  9. package/dist/cli.js +105 -31
  10. package/dist/core/codegen/class-handlers.js +131 -0
  11. package/dist/core/codegen/control-flow-handlers.js +474 -0
  12. package/dist/core/codegen/declaration-handlers.js +36 -15
  13. package/dist/core/codegen/expression-handlers.js +579 -125
  14. package/dist/core/codegen/function-handlers.js +222 -37
  15. package/dist/core/codegen/helpers.js +158 -4
  16. package/dist/core/codegen/index.js +20 -8
  17. package/dist/core/codegen/literal-handlers.js +18 -6
  18. package/dist/core/codegen/statement-handlers.js +171 -228
  19. package/dist/core/codegen/visitor.js +31 -3
  20. package/package.json +3 -3
  21. package/src/prelude/any_value.hpp +510 -633
  22. package/src/prelude/any_value_access.hpp +151 -0
  23. package/src/prelude/any_value_defines.hpp +190 -0
  24. package/src/prelude/any_value_helpers.hpp +139 -225
  25. package/src/prelude/exception.hpp +32 -0
  26. package/src/prelude/exception_helpers.hpp +49 -0
  27. package/src/prelude/index.hpp +25 -9
  28. package/src/prelude/library/array.hpp +190 -0
  29. package/src/prelude/library/console.hpp +14 -13
  30. package/src/prelude/library/error.hpp +113 -0
  31. package/src/prelude/library/function.hpp +10 -0
  32. package/src/prelude/library/global.hpp +35 -4
  33. package/src/prelude/library/math.hpp +308 -0
  34. package/src/prelude/library/object.hpp +288 -0
  35. package/src/prelude/library/performance.hpp +2 -2
  36. package/src/prelude/library/process.hpp +39 -0
  37. package/src/prelude/library/promise.hpp +131 -0
  38. package/src/prelude/library/symbol.hpp +46 -59
  39. package/src/prelude/library/timer.hpp +92 -0
  40. package/src/prelude/scheduler.hpp +145 -0
  41. package/src/prelude/types.hpp +58 -1
  42. package/src/prelude/utils/access.hpp +345 -0
  43. package/src/prelude/utils/assignment_operators.hpp +99 -0
  44. package/src/prelude/utils/log_any_value/array.hpp +245 -0
  45. package/src/prelude/utils/log_any_value/config.hpp +32 -0
  46. package/src/prelude/utils/log_any_value/function.hpp +39 -0
  47. package/src/prelude/utils/log_any_value/fwd.hpp +15 -0
  48. package/src/prelude/utils/log_any_value/helpers.hpp +62 -0
  49. package/src/prelude/utils/log_any_value/log_any_value.hpp +94 -0
  50. package/src/prelude/utils/log_any_value/object.hpp +136 -0
  51. package/src/prelude/utils/log_any_value/primitives.hpp +43 -0
  52. package/src/prelude/utils/operators.hpp +751 -0
  53. package/src/prelude/utils/well_known_symbols.hpp +25 -0
  54. package/src/prelude/values/array.hpp +10 -7
  55. package/src/prelude/{descriptors.hpp → values/descriptors.hpp} +2 -2
  56. package/src/prelude/values/function.hpp +85 -51
  57. package/src/prelude/values/helpers/array.hpp +80 -35
  58. package/src/prelude/values/helpers/function.hpp +110 -77
  59. package/src/prelude/values/helpers/iterator.hpp +16 -10
  60. package/src/prelude/values/helpers/object.hpp +85 -10
  61. package/src/prelude/values/helpers/promise.hpp +181 -0
  62. package/src/prelude/values/helpers/string.hpp +3 -3
  63. package/src/prelude/values/helpers/symbol.hpp +2 -2
  64. package/src/prelude/values/iterator.hpp +14 -6
  65. package/src/prelude/values/object.hpp +14 -3
  66. package/src/prelude/values/promise.hpp +73 -0
  67. package/src/prelude/values/prototypes/array.hpp +855 -16
  68. package/src/prelude/values/prototypes/function.hpp +4 -4
  69. package/src/prelude/values/prototypes/iterator.hpp +11 -10
  70. package/src/prelude/values/prototypes/number.hpp +153 -0
  71. package/src/prelude/values/prototypes/object.hpp +26 -0
  72. package/src/prelude/values/prototypes/promise.hpp +134 -0
  73. package/src/prelude/values/prototypes/string.hpp +29 -29
  74. package/src/prelude/values/prototypes/symbol.hpp +22 -3
  75. package/src/prelude/values/shape.hpp +52 -0
  76. package/src/prelude/values/string.hpp +1 -1
  77. package/src/prelude/values/symbol.hpp +1 -1
  78. package/src/prelude/access.hpp +0 -91
  79. package/src/prelude/error.hpp +0 -31
  80. package/src/prelude/error_helpers.hpp +0 -59
  81. package/src/prelude/log_string.hpp +0 -407
  82. package/src/prelude/operators.hpp +0 -256
  83. 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<std::optional<AnyValue>> dense; // dense storage for small/contiguous indices
14
- std::unordered_map<uint32_t, std::optional<AnyValue>> sparse; // sparse indices (very large indices)
15
- std::unordered_map<std::string, AnyValue> props; // non-index string properties
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() = default;
19
- explicit JsArray(const std::vector<std::optional<AnyValue>> &items) : dense(items), length(items.size()) {}
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
- AnyValue get_property(const std::string &key);
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::vector<AnyValue> &)>> get; // getter = function or undefined
21
- std::optional<std::function<AnyValue(const std::vector<AnyValue> &)>> set; // setter = function or undefined
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
- namespace jspp
6
- {
7
- // Forward declaration of AnyValue
8
- class AnyValue;
9
-
10
- using JsFunctionCallable = std::variant<std::function<AnyValue(const std::vector<AnyValue> &)>, // 0: Normal
11
- std::function<jspp::JsIterator<jspp::AnyValue>(const std::vector<jspp::AnyValue> &)>>; // 1: Generator
12
-
13
- struct JsFunction
14
- {
15
- JsFunctionCallable callable;
16
- std::string name;
17
- std::unordered_map<std::string, AnyValue> props;
18
- bool is_generator;
19
-
20
- // ---- Constructor A: infer is_generator using index() ----
21
- JsFunction(const JsFunctionCallable &c,
22
- std::string n = {},
23
- std::unordered_map<std::string, AnyValue> p = {})
24
- : callable(c),
25
- name(std::move(n)),
26
- props(std::move(p)),
27
- is_generator(callable.index() == 1) // 1 = generator
28
- {
29
- }
30
-
31
- // ---- Constructor B: explicitly set is_generator ----
32
- JsFunction(const JsFunctionCallable &c,
33
- bool is_gen,
34
- std::string n = {},
35
- std::unordered_map<std::string, AnyValue> p = {})
36
- : callable(c),
37
- name(std::move(n)),
38
- props(std::move(p)),
39
- is_generator(is_gen)
40
- {
41
- // Optional debug check (no RTTI, no variant visitation):
42
- // if (callable.index() == 1 && !is_gen) { ... }
43
- // if (callable.index() == 0 && is_gen) { ... }
44
- }
45
-
46
- std::string to_std_string() const;
47
- AnyValue call(const std::vector<AnyValue> &args);
48
- AnyValue get_property(const std::string &key);
49
- AnyValue set_property(const std::string &key, const AnyValue &value);
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 "error.hpp"
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
- std::optional<AnyValue> itemVal;
19
+ const AnyValue *itemPtr = nullptr;
20
20
  if (i < dense.size())
21
21
  {
22
- itemVal = dense[i];
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
- itemVal = it->second;
29
+ itemPtr = &it->second;
30
30
  }
31
31
  }
32
32
 
33
- if (itemVal.has_value())
33
+ if (itemPtr && !itemPtr->is_uninitialized())
34
34
  {
35
- const auto &item = itemVal.value();
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
- jspp::AnyValue jspp::JsArray::get_property(const std::string &key)
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 prototype
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
- return AnyValue::resolve_property_for_read(dense[idx].value_or(AnyValue::make_undefined()));
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
- return AnyValue::resolve_property_for_read(it->second.value_or(AnyValue::make_undefined()));
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
- return AnyValue::resolve_property_for_write(proto_value, value);
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
- if (!dense[idx].has_value())
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
- auto it = sparse.find(idx);
158
- if (it != sparse.end())
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
- #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
- }
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
+ }