@ugo-studio/jspp 0.1.4 → 0.1.6

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 (71) hide show
  1. package/dist/analysis/scope.js +17 -0
  2. package/dist/analysis/typeAnalyzer.js +7 -1
  3. package/dist/ast/symbols.js +32 -0
  4. package/dist/ast/types.js +0 -6
  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 -30
  10. package/dist/core/codegen/class-handlers.js +10 -6
  11. package/dist/core/codegen/control-flow-handlers.js +57 -28
  12. package/dist/core/codegen/declaration-handlers.js +10 -6
  13. package/dist/core/codegen/expression-handlers.js +206 -61
  14. package/dist/core/codegen/function-handlers.js +203 -76
  15. package/dist/core/codegen/helpers.js +125 -28
  16. package/dist/core/codegen/index.js +23 -15
  17. package/dist/core/codegen/literal-handlers.js +15 -6
  18. package/dist/core/codegen/statement-handlers.js +282 -84
  19. package/dist/core/codegen/visitor.js +3 -1
  20. package/package.json +1 -1
  21. package/src/prelude/any_value.hpp +221 -342
  22. package/src/prelude/any_value_access.hpp +168 -81
  23. package/src/prelude/any_value_defines.hpp +74 -35
  24. package/src/prelude/any_value_helpers.hpp +75 -180
  25. package/src/prelude/exception.hpp +1 -0
  26. package/src/prelude/exception_helpers.hpp +4 -4
  27. package/src/prelude/index.hpp +12 -2
  28. package/src/prelude/library/array.hpp +190 -0
  29. package/src/prelude/library/console.hpp +6 -5
  30. package/src/prelude/library/error.hpp +10 -8
  31. package/src/prelude/library/function.hpp +10 -0
  32. package/src/prelude/library/global.hpp +20 -0
  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 +1 -1
  36. package/src/prelude/library/process.hpp +39 -0
  37. package/src/prelude/library/promise.hpp +57 -55
  38. package/src/prelude/library/symbol.hpp +45 -57
  39. package/src/prelude/library/timer.hpp +6 -6
  40. package/src/prelude/types.hpp +54 -0
  41. package/src/prelude/utils/access.hpp +215 -11
  42. package/src/prelude/utils/assignment_operators.hpp +99 -0
  43. package/src/prelude/utils/log_any_value/array.hpp +8 -8
  44. package/src/prelude/utils/log_any_value/function.hpp +6 -4
  45. package/src/prelude/utils/log_any_value/object.hpp +41 -24
  46. package/src/prelude/utils/log_any_value/primitives.hpp +3 -1
  47. package/src/prelude/utils/operators.hpp +750 -274
  48. package/src/prelude/utils/well_known_symbols.hpp +12 -0
  49. package/src/prelude/values/array.hpp +8 -6
  50. package/src/prelude/values/async_iterator.hpp +79 -0
  51. package/src/prelude/values/descriptors.hpp +2 -2
  52. package/src/prelude/values/function.hpp +72 -62
  53. package/src/prelude/values/helpers/array.hpp +64 -28
  54. package/src/prelude/values/helpers/async_iterator.hpp +275 -0
  55. package/src/prelude/values/helpers/function.hpp +81 -92
  56. package/src/prelude/values/helpers/iterator.hpp +3 -3
  57. package/src/prelude/values/helpers/object.hpp +54 -9
  58. package/src/prelude/values/helpers/promise.hpp +13 -6
  59. package/src/prelude/values/iterator.hpp +1 -1
  60. package/src/prelude/values/object.hpp +10 -3
  61. package/src/prelude/values/promise.hpp +7 -11
  62. package/src/prelude/values/prototypes/array.hpp +851 -12
  63. package/src/prelude/values/prototypes/async_iterator.hpp +50 -0
  64. package/src/prelude/values/prototypes/function.hpp +2 -2
  65. package/src/prelude/values/prototypes/iterator.hpp +5 -5
  66. package/src/prelude/values/prototypes/number.hpp +153 -0
  67. package/src/prelude/values/prototypes/object.hpp +2 -2
  68. package/src/prelude/values/prototypes/promise.hpp +40 -30
  69. package/src/prelude/values/prototypes/string.hpp +28 -28
  70. package/src/prelude/values/prototypes/symbol.hpp +20 -3
  71. package/src/prelude/values/shape.hpp +52 -0
@@ -9,5 +9,17 @@ namespace jspp
9
9
  {
10
10
  // We use a specific prefix "@@" for well-known symbols to distinguish them from user symbols
11
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");
12
24
  }
13
25
  }
@@ -10,18 +10,20 @@ 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()) {}
20
- explicit JsArray(std::vector<std::optional<AnyValue>> &&items) : dense(std::move(items)), length(dense.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()) {}
21
22
 
22
23
  std::string to_std_string() const;
23
24
  JsIterator<AnyValue> get_iterator();
24
25
 
26
+ bool has_property(const std::string &key) const;
25
27
  AnyValue get_property(const std::string &key, const AnyValue &thisVal);
26
28
  AnyValue get_property(uint32_t idx);
27
29
  AnyValue set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal);
@@ -0,0 +1,79 @@
1
+ #pragma once
2
+
3
+ #include "types.hpp"
4
+ #include <coroutine>
5
+ #include <optional>
6
+ #include <queue>
7
+ #include <iostream>
8
+ #include <utility>
9
+ #include <exception>
10
+ #include "values/promise.hpp"
11
+ #include "scheduler.hpp"
12
+
13
+ namespace jspp
14
+ {
15
+ // Forward declaration of AnyValue
16
+ class AnyValue;
17
+
18
+ template <typename T>
19
+ class JsAsyncIterator
20
+ {
21
+ public:
22
+ struct promise_type
23
+ {
24
+ std::queue<std::pair<JsPromise, T>> pending_calls;
25
+ bool is_awaiting = false;
26
+ bool is_running = false;
27
+ T current_input;
28
+
29
+ JsAsyncIterator get_return_object()
30
+ {
31
+ return JsAsyncIterator{
32
+ std::coroutine_handle<promise_type>::from_promise(*this)};
33
+ }
34
+
35
+ std::suspend_always initial_suspend() noexcept { return {}; }
36
+
37
+ std::suspend_always final_suspend() noexcept { return {}; }
38
+
39
+ // Declarations
40
+ template <typename From>
41
+ auto yield_value(From &&from);
42
+
43
+ template <typename From>
44
+ void return_value(From &&from);
45
+
46
+ void unhandled_exception();
47
+
48
+ void fail_all(const AnyValue &reason);
49
+
50
+ auto await_transform(AnyValue value);
51
+ };
52
+
53
+ using handle_type = std::coroutine_handle<promise_type>;
54
+ handle_type handle;
55
+
56
+ explicit JsAsyncIterator(handle_type h) : handle(h) {}
57
+ JsAsyncIterator(JsAsyncIterator &&other) noexcept : handle(std::exchange(other.handle, nullptr)) {}
58
+
59
+ JsAsyncIterator(const JsAsyncIterator &) = delete;
60
+ JsAsyncIterator &operator=(const JsAsyncIterator &) = delete;
61
+
62
+ ~JsAsyncIterator()
63
+ {
64
+ if (handle)
65
+ handle.destroy();
66
+ }
67
+
68
+ std::unordered_map<std::string, AnyValue> props;
69
+
70
+ std::string to_std_string() const;
71
+
72
+ JsPromise next(const T &val = T());
73
+
74
+ AnyValue get_property(const std::string &key, const AnyValue &thisVal);
75
+ AnyValue set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal);
76
+
77
+ void resume_next();
78
+ };
79
+ }
@@ -17,8 +17,8 @@ namespace jspp
17
17
 
18
18
  struct AccessorDescriptor
19
19
  {
20
- std::optional<std::function<AnyValue(const AnyValue &, const std::vector<AnyValue> &)>> get; // getter = function or undefined
21
- std::optional<std::function<AnyValue(const 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,76 +1,86 @@
1
1
  #pragma once
2
2
 
3
3
  #include "types.hpp"
4
- #include <variant> // Ensure variant is included
4
+ #include <variant>
5
+ #include <optional>
5
6
 
6
7
  namespace jspp
7
8
  {
8
- // Forward declaration of AnyValue
9
- class AnyValue;
9
+ // Forward declaration of AnyValue
10
+ class AnyValue;
10
11
 
11
- using JsFunctionCallable = std::variant<std::function<AnyValue(const AnyValue &, const std::vector<AnyValue> &)>, // 0: Normal
12
- std::function<jspp::JsIterator<jspp::AnyValue>(const AnyValue &, const std::vector<jspp::AnyValue> &)>, // 1: Generator
13
- std::function<jspp::JsPromise(const AnyValue &, const std::vector<jspp::AnyValue> &)>>; // 2: Async
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
+ std::function<jspp::JsAsyncIterator<jspp::AnyValue>(const AnyValue &, std::span<const AnyValue>)>>; // 3: Async Generator
14
16
 
15
- struct JsFunction
17
+ struct JsFunction
18
+ {
19
+ JsFunctionCallable callable;
20
+ std::optional<std::string> name;
21
+ std::unordered_map<std::string, AnyValue> props;
22
+ std::shared_ptr<AnyValue> proto = nullptr;
23
+ bool is_generator;
24
+ bool is_async;
25
+ bool is_class;
26
+ bool is_constructor;
27
+
28
+ // ---- Constructor A: infer flags ----
29
+ JsFunction(const JsFunctionCallable &c,
30
+ std::optional<std::string> n = std::nullopt,
31
+ std::unordered_map<std::string, AnyValue> p = {},
32
+ bool is_cls = false,
33
+ bool is_ctor = true)
34
+ : callable(c),
35
+ name(std::move(n)),
36
+ props(std::move(p)),
37
+ is_generator(callable.index() == 1),
38
+ is_async(callable.index() == 2),
39
+ is_class(is_cls),
40
+ is_constructor(is_ctor && !is_generator && !is_async) // Generators and asyncs are never constructors
16
41
  {
17
- JsFunctionCallable callable;
18
- std::string name;
19
- std::unordered_map<std::string, AnyValue> props;
20
- std::shared_ptr<AnyValue> proto = nullptr;
21
- bool is_generator;
22
- bool is_async;
23
- bool is_class;
42
+ }
24
43
 
25
- // ---- Constructor A: infer flags ----
26
- JsFunction(const JsFunctionCallable &c,
27
- std::string n = {},
28
- std::unordered_map<std::string, AnyValue> p = {},
29
- bool is_cls = false)
30
- : callable(c),
31
- name(std::move(n)),
32
- props(std::move(p)),
33
- is_generator(callable.index() == 1),
34
- is_async(callable.index() == 2),
35
- is_class(is_cls)
36
- {
37
- }
44
+ // ---- Constructor B: explicit generator flag (backward compat) ----
45
+ JsFunction(const JsFunctionCallable &c,
46
+ bool is_gen,
47
+ std::optional<std::string> n = std::nullopt,
48
+ std::unordered_map<std::string, AnyValue> p = {},
49
+ bool is_cls = false,
50
+ bool is_ctor = true)
51
+ : callable(c),
52
+ name(std::move(n)),
53
+ props(std::move(p)),
54
+ is_generator(is_gen),
55
+ is_async(callable.index() == 2),
56
+ is_class(is_cls),
57
+ is_constructor(is_ctor && !is_gen && !is_async)
58
+ {
59
+ }
38
60
 
39
- // ---- Constructor B: explicit generator flag (backward compat) ----
40
- JsFunction(const JsFunctionCallable &c,
41
- bool is_gen,
42
- std::string n = {},
43
- std::unordered_map<std::string, AnyValue> p = {},
44
- bool is_cls = false)
45
- : callable(c),
46
- name(std::move(n)),
47
- props(std::move(p)),
48
- is_generator(is_gen),
49
- is_async(callable.index() == 2),
50
- is_class(is_cls)
51
- {
52
- }
53
-
54
- // ---- Constructor C: explicit async flag ----
55
- JsFunction(const JsFunctionCallable &c,
56
- bool is_gen,
57
- bool is_async_func,
58
- std::string n = {},
59
- std::unordered_map<std::string, AnyValue> p = {},
60
- bool is_cls = false)
61
- : callable(c),
62
- name(std::move(n)),
63
- props(std::move(p)),
64
- is_generator(is_gen),
65
- is_async(is_async_func),
66
- is_class(is_cls)
67
- {
68
- }
61
+ // ---- Constructor C: explicit async flag ----
62
+ JsFunction(const JsFunctionCallable &c,
63
+ bool is_gen,
64
+ bool is_async_func,
65
+ std::optional<std::string> n = std::nullopt,
66
+ std::unordered_map<std::string, AnyValue> p = {},
67
+ bool is_cls = false,
68
+ bool is_ctor = true)
69
+ : callable(c),
70
+ name(std::move(n)),
71
+ props(std::move(p)),
72
+ is_generator(is_gen),
73
+ is_async(is_async_func),
74
+ is_class(is_cls),
75
+ is_constructor(is_ctor && !is_gen && !is_async_func)
76
+ {
77
+ }
69
78
 
70
- std::string to_std_string() const;
71
- AnyValue call(const AnyValue &thisVal, const std::vector<AnyValue> &args);
79
+ std::string to_std_string() const;
80
+ AnyValue call(const AnyValue &thisVal, std::span<const AnyValue> args);
72
81
 
73
- AnyValue get_property(const std::string &key, const AnyValue &thisVal);
74
- AnyValue set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal);
75
- };
82
+ bool has_property(const std::string &key) const;
83
+ AnyValue get_property(const std::string &key, const AnyValue &thisVal);
84
+ AnyValue set_property(const std::string &key, const AnyValue &value, const AnyValue &thisVal);
85
+ };
76
86
  }
@@ -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,6 +57,32 @@ jspp::JsIterator<jspp::AnyValue> jspp::JsArray::get_iterator()
57
57
  co_return AnyValue::make_undefined();
58
58
  }
59
59
 
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
+
60
86
  jspp::AnyValue jspp::JsArray::get_property(const std::string &key, const AnyValue &thisVal)
61
87
  {
62
88
  if (
@@ -71,7 +97,26 @@ jspp::AnyValue jspp::JsArray::get_property(const std::string &key, const AnyValu
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
  {
@@ -88,12 +133,14 @@ jspp::AnyValue jspp::JsArray::get_property(uint32_t idx)
88
133
  {
89
134
  if (idx < dense.size())
90
135
  {
91
- return 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 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
  }
@@ -111,6 +158,12 @@ 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();
@@ -147,35 +200,18 @@ jspp::AnyValue jspp::JsArray::set_property(uint32_t idx, const AnyValue &value)
147
200
  const uint32_t DENSE_GROW_THRESHOLD = 1024;
148
201
  if (idx < dense.size())
149
202
  {
150
- if (!dense[idx].has_value())
151
- {
152
- dense[idx] = AnyValue::make_undefined();
153
- }
154
203
  dense[idx] = value;
155
204
  return value;
156
205
  }
157
206
  else if (idx <= dense.size() + DENSE_GROW_THRESHOLD)
158
207
  {
159
- dense.resize(idx + 1);
208
+ dense.resize(idx + 1, AnyValue::make_uninitialized());
160
209
  dense[idx] = value;
161
210
  return value;
162
211
  }
163
212
  else
164
213
  {
165
- auto it = sparse.find(idx);
166
- if (it != sparse.end())
167
- {
168
- if (!it->second.has_value())
169
- {
170
- it->second = AnyValue::make_undefined();
171
- }
172
- it->second = value;
173
- return value;
174
- }
175
- else
176
- {
177
- sparse[idx] = value;
178
- return value;
179
- }
214
+ sparse[idx] = value;
215
+ return value;
180
216
  }
181
217
  }