@ugo-studio/jspp 0.2.5 → 0.2.7

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 (54) hide show
  1. package/README.md +51 -36
  2. package/dist/analysis/scope.js +7 -0
  3. package/dist/analysis/typeAnalyzer.js +96 -43
  4. package/dist/ast/symbols.js +34 -24
  5. package/dist/cli/args.js +59 -0
  6. package/dist/cli/colors.js +9 -0
  7. package/dist/cli/file-utils.js +20 -0
  8. package/dist/cli/index.js +160 -0
  9. package/dist/cli/spinner.js +55 -0
  10. package/dist/core/codegen/class-handlers.js +8 -8
  11. package/dist/core/codegen/control-flow-handlers.js +19 -9
  12. package/dist/core/codegen/declaration-handlers.js +30 -10
  13. package/dist/core/codegen/expression-handlers.js +649 -161
  14. package/dist/core/codegen/function-handlers.js +107 -103
  15. package/dist/core/codegen/helpers.js +61 -14
  16. package/dist/core/codegen/index.js +13 -9
  17. package/dist/core/codegen/literal-handlers.js +4 -2
  18. package/dist/core/codegen/statement-handlers.js +147 -55
  19. package/dist/core/codegen/visitor.js +22 -2
  20. package/dist/core/constants.js +16 -0
  21. package/dist/core/error.js +58 -0
  22. package/dist/index.js +6 -3
  23. package/package.json +3 -3
  24. package/src/prelude/any_value.hpp +89 -59
  25. package/src/prelude/any_value_access.hpp +1 -1
  26. package/src/prelude/any_value_helpers.hpp +85 -43
  27. package/src/prelude/index.hpp +1 -0
  28. package/src/prelude/library/array.hpp +3 -2
  29. package/src/prelude/scheduler.hpp +144 -144
  30. package/src/prelude/types.hpp +8 -8
  31. package/src/prelude/utils/access.hpp +62 -6
  32. package/src/prelude/utils/assignment_operators.hpp +14 -14
  33. package/src/prelude/utils/log_any_value/array.hpp +0 -15
  34. package/src/prelude/utils/log_any_value/object.hpp +12 -10
  35. package/src/prelude/utils/log_any_value/primitives.hpp +2 -0
  36. package/src/prelude/utils/operators.hpp +117 -474
  37. package/src/prelude/utils/operators_primitive.hpp +337 -0
  38. package/src/prelude/values/helpers/array.hpp +4 -4
  39. package/src/prelude/values/helpers/async_iterator.hpp +2 -2
  40. package/src/prelude/values/helpers/function.hpp +3 -3
  41. package/src/prelude/values/helpers/iterator.hpp +2 -2
  42. package/src/prelude/values/helpers/object.hpp +3 -3
  43. package/src/prelude/values/helpers/promise.hpp +1 -1
  44. package/src/prelude/values/helpers/string.hpp +1 -1
  45. package/src/prelude/values/helpers/symbol.hpp +1 -1
  46. package/src/prelude/values/prototypes/array.hpp +1125 -853
  47. package/src/prelude/values/prototypes/async_iterator.hpp +32 -14
  48. package/src/prelude/values/prototypes/function.hpp +30 -18
  49. package/src/prelude/values/prototypes/iterator.hpp +40 -17
  50. package/src/prelude/values/prototypes/number.hpp +119 -62
  51. package/src/prelude/values/prototypes/object.hpp +10 -4
  52. package/src/prelude/values/prototypes/promise.hpp +167 -109
  53. package/src/prelude/values/prototypes/string.hpp +407 -231
  54. package/src/prelude/values/prototypes/symbol.hpp +45 -23
@@ -1,145 +1,145 @@
1
- #pragma once
2
- #include <deque>
3
- #include <functional>
4
- #include <chrono>
5
- #include <queue>
6
- #include <unordered_set>
7
- #include <vector>
8
- #include <thread>
9
- #include <iostream>
10
-
11
- namespace jspp {
12
- class Scheduler {
13
- public:
14
- using Task = std::function<void()>;
15
- using TimePoint = std::chrono::steady_clock::time_point;
16
-
17
- struct Timer {
18
- size_t id;
19
- TimePoint next_run;
20
- std::chrono::milliseconds interval; // 0 if not repeating
21
- Task task;
22
-
23
- // Min-heap priority queue (smallest time at top)
24
- bool operator>(const Timer& other) const {
25
- return next_run > other.next_run;
26
- }
27
- };
28
-
29
- static Scheduler& instance() {
30
- static Scheduler s;
31
- return s;
32
- }
33
-
34
- void enqueue(Task task) {
35
- tasks.push_back(std::move(task));
36
- }
37
-
38
- size_t set_timeout(Task task, size_t delay_ms) {
39
- return schedule_timer(std::move(task), delay_ms, false);
40
- }
41
-
42
- size_t set_interval(Task task, size_t delay_ms) {
43
- return schedule_timer(std::move(task), delay_ms, true);
44
- }
45
-
46
- void clear_timer(size_t id) {
47
- cancelled_timers.insert(id);
48
- }
49
-
50
- void run() {
51
- while (true) {
52
- bool has_work = false;
53
-
54
- // 1. Process all immediate tasks (microtask/task queue)
55
- while (!tasks.empty()) {
56
- Task task = tasks.front();
57
- tasks.pop_front();
58
- task();
59
- has_work = true;
60
- }
61
-
62
- // 2. Process timers
63
- auto now = std::chrono::steady_clock::now();
64
- while (!timers.empty()) {
65
- // Peek top
66
- const auto& top = timers.top();
67
-
68
- // Cleanup cancelled timers lazily
69
- if (cancelled_timers.count(top.id)) {
70
- cancelled_timers.erase(top.id);
71
- timers.pop();
72
- continue;
73
- }
74
-
75
- if (top.next_run <= now) {
76
- // Timer is ready
77
- Timer t = top;
78
- timers.pop();
79
-
80
- // Execute task
81
- t.task();
82
- has_work = true;
83
-
84
- // Reschedule if interval and not cancelled during execution
85
- if (t.interval.count() > 0 && cancelled_timers.find(t.id) == cancelled_timers.end()) {
86
- // Drift-safe(ish) scheduling: run next interval relative to now
87
- // Note: JS allows drift.
88
- t.next_run = std::chrono::steady_clock::now() + t.interval;
89
- timers.push(t);
90
- }
91
- } else {
92
- break; // Next timer is in the future
93
- }
94
- }
95
-
96
- // 3. Exit or Wait
97
- if (!has_work) {
98
- if (tasks.empty() && timers.empty()) {
99
- break; // No pending work, exit event loop
100
- }
101
-
102
- if (!timers.empty()) {
103
- auto next_time = timers.top().next_run;
104
- std::this_thread::sleep_until(next_time);
105
- }
106
- }
107
- }
108
- }
109
-
110
- bool has_tasks() const {
111
- return !tasks.empty() || !timers.empty();
112
- }
113
-
114
- private:
115
- std::deque<Task> tasks;
116
- std::priority_queue<Timer, std::vector<Timer>, std::greater<Timer>> timers;
117
- std::unordered_set<size_t> cancelled_timers;
118
- size_t next_timer_id = 1;
119
- const size_t MAX_TIMER_ID = 2147483647; // 2^31 - 1
120
-
121
- size_t schedule_timer(Task task, size_t delay_ms, bool repeat) {
122
- size_t id = next_timer_id++;
123
- if (next_timer_id > MAX_TIMER_ID) {
124
- next_timer_id = 1;
125
- }
126
-
127
- // If we wrap around, ensure we don't accidentally treat this new ID as cancelled
128
- // (in case an old timer with this ID is still lingering in the 'cancelled' set)
129
- if (cancelled_timers.count(id)) {
130
- cancelled_timers.erase(id);
131
- }
132
-
133
- auto now = std::chrono::steady_clock::now();
134
-
135
- Timer t;
136
- t.id = id;
137
- t.next_run = now + std::chrono::milliseconds(delay_ms);
138
- t.interval = repeat ? std::chrono::milliseconds(delay_ms) : std::chrono::milliseconds(0);
139
- t.task = std::move(task);
140
-
141
- timers.push(t);
142
- return id;
143
- }
144
- };
1
+ #pragma once
2
+ #include <deque>
3
+ #include <functional>
4
+ #include <chrono>
5
+ #include <queue>
6
+ #include <unordered_set>
7
+ #include <vector>
8
+ #include <thread>
9
+ #include <iostream>
10
+
11
+ namespace jspp {
12
+ class Scheduler {
13
+ public:
14
+ using Task = std::function<void()>;
15
+ using TimePoint = std::chrono::steady_clock::time_point;
16
+
17
+ struct Timer {
18
+ size_t id;
19
+ TimePoint next_run;
20
+ std::chrono::milliseconds interval; // 0 if not repeating
21
+ Task task;
22
+
23
+ // Min-heap priority queue (smallest time at top)
24
+ bool operator>(const Timer& other) const {
25
+ return next_run > other.next_run;
26
+ }
27
+ };
28
+
29
+ static Scheduler& instance() {
30
+ static Scheduler s;
31
+ return s;
32
+ }
33
+
34
+ void enqueue(Task task) {
35
+ tasks.push_back(std::move(task));
36
+ }
37
+
38
+ size_t set_timeout(Task task, size_t delay_ms) {
39
+ return schedule_timer(std::move(task), delay_ms, false);
40
+ }
41
+
42
+ size_t set_interval(Task task, size_t delay_ms) {
43
+ return schedule_timer(std::move(task), delay_ms, true);
44
+ }
45
+
46
+ void clear_timer(size_t id) {
47
+ cancelled_timers.insert(id);
48
+ }
49
+
50
+ void run() {
51
+ while (true) {
52
+ bool has_work = false;
53
+
54
+ // 1. Process all immediate tasks (microtask/task queue)
55
+ while (!tasks.empty()) {
56
+ Task task = tasks.front();
57
+ tasks.pop_front();
58
+ task();
59
+ has_work = true;
60
+ }
61
+
62
+ // 2. Process timers
63
+ auto now = std::chrono::steady_clock::now();
64
+ while (!timers.empty()) {
65
+ // Peek top
66
+ const auto& top = timers.top();
67
+
68
+ // Cleanup cancelled timers lazily
69
+ if (cancelled_timers.count(top.id)) {
70
+ cancelled_timers.erase(top.id);
71
+ timers.pop();
72
+ continue;
73
+ }
74
+
75
+ if (top.next_run <= now) {
76
+ // Timer is ready
77
+ Timer t = top;
78
+ timers.pop();
79
+
80
+ // Execute task
81
+ t.task();
82
+ has_work = true;
83
+
84
+ // Reschedule if interval and not cancelled during execution
85
+ if (t.interval.count() > 0 && cancelled_timers.find(t.id) == cancelled_timers.end()) {
86
+ // Drift-safe(ish) scheduling: run next interval relative to now
87
+ // Note: JS allows drift.
88
+ t.next_run = std::chrono::steady_clock::now() + t.interval;
89
+ timers.push(t);
90
+ }
91
+ } else {
92
+ break; // Next timer is in the future
93
+ }
94
+ }
95
+
96
+ // 3. Exit or Wait
97
+ if (!has_work) {
98
+ if (tasks.empty() && timers.empty()) {
99
+ break; // No pending work, exit event loop
100
+ }
101
+
102
+ if (!timers.empty()) {
103
+ auto next_time = timers.top().next_run;
104
+ std::this_thread::sleep_until(next_time);
105
+ }
106
+ }
107
+ }
108
+ }
109
+
110
+ bool has_tasks() const {
111
+ return !tasks.empty() || !timers.empty();
112
+ }
113
+
114
+ private:
115
+ std::deque<Task> tasks;
116
+ std::priority_queue<Timer, std::vector<Timer>, std::greater<Timer>> timers;
117
+ std::unordered_set<size_t> cancelled_timers;
118
+ size_t next_timer_id = 1;
119
+ const size_t MAX_TIMER_ID = 2147483647; // 2^31 - 1
120
+
121
+ size_t schedule_timer(Task task, size_t delay_ms, bool repeat) {
122
+ size_t id = next_timer_id++;
123
+ if (next_timer_id > MAX_TIMER_ID) {
124
+ next_timer_id = 1;
125
+ }
126
+
127
+ // If we wrap around, ensure we don't accidentally treat this new ID as cancelled
128
+ // (in case an old timer with this ID is still lingering in the 'cancelled' set)
129
+ if (cancelled_timers.count(id)) {
130
+ cancelled_timers.erase(id);
131
+ }
132
+
133
+ auto now = std::chrono::steady_clock::now();
134
+
135
+ Timer t;
136
+ t.id = id;
137
+ t.next_run = now + std::chrono::milliseconds(delay_ms);
138
+ t.interval = repeat ? std::chrono::milliseconds(delay_ms) : std::chrono::milliseconds(0);
139
+ t.task = std::move(task);
140
+
141
+ timers.push(t);
142
+ return id;
143
+ }
144
+ };
145
145
  }
@@ -146,34 +146,34 @@ namespace jspp
146
146
  // AnyValue prototypes
147
147
  namespace ObjectPrototypes
148
148
  {
149
- inline std::optional<AnyValue> get(const std::string &key, JsObject *self);
149
+ inline std::optional<AnyValue> get(const std::string &key);
150
150
  }
151
151
  namespace StringPrototypes
152
152
  {
153
- inline std::optional<AnyValue> get(const std::string &key, JsString *self);
153
+ inline std::optional<AnyValue> get(const std::string &key);
154
154
  }
155
155
  namespace NumberPrototypes
156
156
  {
157
- inline std::optional<AnyValue> get(const std::string &key, double self);
157
+ inline std::optional<AnyValue> get(const std::string &key);
158
158
  }
159
159
  namespace ArrayPrototypes
160
160
  {
161
- inline std::optional<AnyValue> get(const std::string &key, JsArray *self);
161
+ inline std::optional<AnyValue> get(const std::string &key);
162
162
  }
163
163
  namespace FunctionPrototypes
164
164
  {
165
- inline std::optional<AnyValue> get(const std::string &key, JsFunction *self);
165
+ inline std::optional<AnyValue> get(const std::string &key);
166
166
  }
167
167
  namespace PromisePrototypes
168
168
  {
169
- inline std::optional<AnyValue> get(const std::string &key, JsPromise *self);
169
+ inline std::optional<AnyValue> get(const std::string &key);
170
170
  }
171
171
  namespace IteratorPrototypes
172
172
  {
173
- inline std::optional<AnyValue> get(const std::string &key, JsIterator<AnyValue> *self);
173
+ inline std::optional<AnyValue> get(const std::string &key);
174
174
  }
175
175
  namespace SymbolPrototypes
176
176
  {
177
- inline std::optional<AnyValue> get(const std::string &key, JsSymbol *self);
177
+ inline std::optional<AnyValue> get(const std::string &key);
178
178
  }
179
179
  }
@@ -306,32 +306,88 @@ namespace jspp
306
306
  return Constants::TRUE;
307
307
  }
308
308
 
309
- inline AnyValue optional_get_property(const AnyValue &obj, const std::string &key)
309
+ inline AnyValue get_optional_property(const AnyValue &obj, const std::string &key)
310
310
  {
311
311
  if (obj.is_null() || obj.is_undefined())
312
312
  return Constants::UNDEFINED;
313
313
  return obj.get_own_property(key);
314
314
  }
315
315
 
316
- inline AnyValue optional_get_element(const AnyValue &obj, const AnyValue &key)
316
+ inline AnyValue get_optional_element(const AnyValue &obj, const AnyValue &key)
317
317
  {
318
318
  if (obj.is_null() || obj.is_undefined())
319
319
  return Constants::UNDEFINED;
320
320
  return obj.get_own_property(key);
321
321
  }
322
322
 
323
- inline AnyValue optional_get_element(const AnyValue &obj, const double &key)
323
+ inline AnyValue get_optional_element(const AnyValue &obj, const double &key)
324
324
  {
325
325
  if (obj.is_null() || obj.is_undefined())
326
326
  return Constants::UNDEFINED;
327
327
  return obj.get_own_property(static_cast<uint32_t>(key));
328
328
  }
329
329
 
330
- inline AnyValue optional_call(const AnyValue &fn, const AnyValue &thisVal, std::span<const AnyValue> args, const std::optional<std::string> &name = std::nullopt)
330
+ inline AnyValue call_optional_property(const AnyValue &obj, const std::string &key, std::span<const AnyValue> args, const std::optional<std::string> &expr = std::nullopt)
331
331
  {
332
- if (fn.is_null() || fn.is_undefined())
332
+ if (obj.is_null() || obj.is_undefined())
333
333
  return Constants::UNDEFINED;
334
- return fn.call(thisVal, args, name);
334
+ return obj.get_own_property(key).call(obj, args, expr);
335
+ }
336
+ inline AnyValue call_optional_property_with_optional_call(const AnyValue &obj, const std::string &key, std::span<const AnyValue> args, const std::optional<std::string> &expr = std::nullopt)
337
+ {
338
+ if (obj.is_null() || obj.is_undefined())
339
+ return Constants::UNDEFINED;
340
+ return obj.get_own_property(key).optional_call(obj, args, expr);
341
+ }
342
+
343
+ inline void spread_array(std::vector<AnyValue> &target, const AnyValue &source)
344
+ {
345
+ if (source.is_array())
346
+ {
347
+ auto arr = source.as_array();
348
+ target.reserve(target.size() + arr->length);
349
+ for (uint64_t i = 0; i < arr->length; ++i)
350
+ {
351
+ target.push_back(arr->get_property(static_cast<uint32_t>(i)));
352
+ }
353
+ }
354
+ else if (source.is_string())
355
+ {
356
+ auto s = source.as_string();
357
+ target.reserve(target.size() + s->value.length());
358
+ for (char c : s->value)
359
+ {
360
+ target.push_back(AnyValue::make_string(std::string(1, c)));
361
+ }
362
+ }
363
+ else if (source.is_object() || source.is_function() || source.is_iterator())
364
+ {
365
+ auto iter = get_object_value_iterator(source, "spread target");
366
+ auto next_fn = iter.get_own_property("next");
367
+ while (true)
368
+ {
369
+ auto next_res = next_fn.call(iter, {});
370
+ if (is_truthy(next_res.get_own_property("done")))
371
+ break;
372
+ target.push_back(next_res.get_own_property("value"));
373
+ }
374
+ }
375
+ else
376
+ {
377
+ throw jspp::Exception::make_exception("Spread syntax requires an iterable object", "TypeError");
378
+ }
379
+ }
380
+
381
+ inline void spread_object(AnyValue &target, const AnyValue &source)
382
+ {
383
+ if (source.is_null() || source.is_undefined())
384
+ return;
385
+
386
+ auto keys = get_object_keys(source);
387
+ for (const auto &key : keys)
388
+ {
389
+ target.set_own_property(key, source.get_property_with_receiver(key, source));
390
+ }
335
391
  }
336
392
 
337
393
  }
@@ -9,56 +9,56 @@ namespace jspp {
9
9
  // --- FRIEND IMPLEMENTATIONS ---
10
10
 
11
11
  inline AnyValue &operator+=(AnyValue &lhs, const AnyValue &rhs) {
12
- lhs = lhs + rhs;
12
+ lhs = jspp::add(lhs, rhs);
13
13
  return lhs;
14
14
  }
15
15
 
16
16
  inline AnyValue &operator-=(AnyValue &lhs, const AnyValue &rhs) {
17
- lhs = lhs - rhs;
17
+ lhs = jspp::sub(lhs, rhs);
18
18
  return lhs;
19
19
  }
20
20
 
21
21
  inline AnyValue &operator*=(AnyValue &lhs, const AnyValue &rhs) {
22
- lhs = lhs * rhs;
22
+ lhs = jspp::mul(lhs, rhs);
23
23
  return lhs;
24
24
  }
25
25
 
26
26
  inline AnyValue &operator/=(AnyValue &lhs, const AnyValue &rhs) {
27
- lhs = lhs / rhs;
27
+ lhs = jspp::div(lhs, rhs);
28
28
  return lhs;
29
29
  }
30
30
 
31
31
  inline AnyValue &operator%=(AnyValue &lhs, const AnyValue &rhs) {
32
- lhs = lhs % rhs;
32
+ lhs = jspp::mod(lhs, rhs);
33
33
  return lhs;
34
34
  }
35
35
 
36
36
  inline AnyValue &operator++(AnyValue &val) {
37
- val = val + 1.0;
37
+ val = jspp::add(val, 1.0);
38
38
  return val;
39
39
  }
40
40
 
41
41
  inline AnyValue operator++(AnyValue &val, int) {
42
42
  AnyValue temp = val;
43
- val = val + 1.0;
43
+ val = jspp::add(val, 1.0);
44
44
  return temp;
45
45
  }
46
46
 
47
47
  inline AnyValue &operator--(AnyValue &val) {
48
- val = val - 1.0;
48
+ val = jspp::sub(val, 1.0);
49
49
  return val;
50
50
  }
51
51
 
52
52
  inline AnyValue operator--(AnyValue &val, int) {
53
53
  AnyValue temp = val;
54
- val = val - 1.0;
54
+ val = jspp::sub(val, 1.0);
55
55
  return temp;
56
56
  }
57
57
 
58
58
  // --- OVERLOADS FOR PRIMITIVES ---
59
59
 
60
60
  inline AnyValue &operator+=(AnyValue &lhs, const double &rhs) {
61
- lhs = lhs + rhs;
61
+ lhs = jspp::add(lhs, rhs);
62
62
  return lhs;
63
63
  }
64
64
  inline AnyValue &operator+=(AnyValue &lhs, const int &rhs) {
@@ -66,7 +66,7 @@ namespace jspp {
66
66
  }
67
67
 
68
68
  inline AnyValue &operator-=(AnyValue &lhs, const double &rhs) {
69
- lhs = lhs - rhs;
69
+ lhs = jspp::sub(lhs, rhs);
70
70
  return lhs;
71
71
  }
72
72
  inline AnyValue &operator-=(AnyValue &lhs, const int &rhs) {
@@ -74,7 +74,7 @@ namespace jspp {
74
74
  }
75
75
 
76
76
  inline AnyValue &operator*=(AnyValue &lhs, const double &rhs) {
77
- lhs = lhs * rhs;
77
+ lhs = jspp::mul(lhs, rhs);
78
78
  return lhs;
79
79
  }
80
80
  inline AnyValue &operator*=(AnyValue &lhs, const int &rhs) {
@@ -82,7 +82,7 @@ namespace jspp {
82
82
  }
83
83
 
84
84
  inline AnyValue &operator/=(AnyValue &lhs, const double &rhs) {
85
- lhs = lhs / rhs;
85
+ lhs = jspp::div(lhs, rhs);
86
86
  return lhs;
87
87
  }
88
88
  inline AnyValue &operator/=(AnyValue &lhs, const int &rhs) {
@@ -90,7 +90,7 @@ namespace jspp {
90
90
  }
91
91
 
92
92
  inline AnyValue &operator%=(AnyValue &lhs, const double &rhs) {
93
- lhs = lhs % rhs;
93
+ lhs = jspp::mod(lhs, rhs);
94
94
  return lhs;
95
95
  }
96
96
  inline AnyValue &operator%=(AnyValue &lhs, const int &rhs) {
@@ -20,21 +20,6 @@ namespace jspp
20
20
  size_t item_count = static_cast<size_t>(arr->length);
21
21
  size_t prop_count = arr->props.size();
22
22
 
23
- // // If custom toString exists on the object, prefer it
24
- // auto itToString = arr->props.find("toString");
25
- // if (depth > 0 && itToString != arr->props.end() && itToString->second.is_function())
26
- // {
27
- // try
28
- // {
29
- // auto result = itToString->second.as_function()->call(itToString->second, {});
30
- // return to_log_string(result, visited, depth);
31
- // }
32
- // catch (...)
33
- // {
34
- // // ignore and fallback to manual formatting
35
- // }
36
- // }
37
-
38
23
  std::string indent(depth * 2, ' ');
39
24
  std::string next_indent((depth + 1) * 2, ' ');
40
25
  std::stringstream ss;
@@ -22,7 +22,7 @@ namespace jspp
22
22
 
23
23
  for (size_t i = 0; i < obj->storage.size(); ++i)
24
24
  {
25
- const auto& prop_val = obj->storage[i];
25
+ const auto &prop_val = obj->storage[i];
26
26
  if (!is_enumerable_property(prop_val))
27
27
  {
28
28
  prop_count--;
@@ -69,8 +69,8 @@ namespace jspp
69
69
  size_t current_prop = 0;
70
70
  for (size_t i = 0; i < obj->shape->property_names.size(); ++i)
71
71
  {
72
- const auto& key = obj->shape->property_names[i];
73
- const auto& prop_val = obj->storage[i];
72
+ const auto &key = obj->shape->property_names[i];
73
+ const auto &prop_val = obj->storage[i];
74
74
 
75
75
  if (!is_enumerable_property(prop_val))
76
76
  continue;
@@ -81,9 +81,10 @@ namespace jspp
81
81
  }
82
82
  else
83
83
  {
84
- ss << "\"" << key << "\"";
84
+ ss << Color::GREEN << "\"" << key << "\"" << Color::RESET;
85
85
  }
86
- ss << ": " << to_log_string(prop_val, visited, depth + 1);
86
+ ss << Color::BRIGHT_BLACK << ": " << Color::RESET;
87
+ ss << to_log_string(prop_val, visited, depth + 1);
87
88
  if (++current_prop < prop_count)
88
89
  ss << Color::BRIGHT_BLACK << ", " << Color::RESET;
89
90
  }
@@ -98,12 +99,12 @@ namespace jspp
98
99
  size_t props_shown = 0;
99
100
  for (size_t i = 0; i < obj->shape->property_names.size(); ++i)
100
101
  {
101
- const auto& key = obj->shape->property_names[i];
102
- const auto& prop_val = obj->storage[i];
102
+ const auto &key = obj->shape->property_names[i];
103
+ const auto &prop_val = obj->storage[i];
103
104
 
104
105
  if (props_shown >= MAX_OBJECT_PROPS)
105
106
  break;
106
-
107
+
107
108
  if (!is_enumerable_property(prop_val))
108
109
  continue;
109
110
 
@@ -117,9 +118,10 @@ namespace jspp
117
118
  }
118
119
  else
119
120
  {
120
- ss << "\"" << key << "\"";
121
+ ss << Color::GREEN << "\"" << key << "\"" << Color::RESET;
121
122
  }
122
- ss << ": " << to_log_string(prop_val, visited, depth + 1);
123
+ ss << Color::BRIGHT_BLACK << ": " << Color::RESET;
124
+ ss << to_log_string(prop_val, visited, depth + 1);
123
125
  props_shown++;
124
126
  }
125
127
  if (prop_count > MAX_OBJECT_PROPS)
@@ -14,8 +14,10 @@ namespace jspp
14
14
  inline std::optional<std::string> format_primitive(const AnyValue &val, int depth)
15
15
  {
16
16
  if (val.is_uninitialized())
17
+ {
17
18
  // THROW
18
19
  Exception::throw_uninitialized_reference("#<Object>");
20
+ }
19
21
  if (val.is_undefined())
20
22
  return Color::BRIGHT_BLACK + std::string("undefined") + Color::RESET;
21
23
  if (val.is_null())