@ugo-studio/jspp 0.1.4 → 0.1.5

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