@ugo-studio/jspp 0.2.5 → 0.2.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.
- package/README.md +51 -36
- package/dist/analysis/scope.js +7 -0
- package/dist/analysis/typeAnalyzer.js +40 -19
- package/dist/ast/symbols.js +9 -8
- package/dist/cli/args.js +59 -0
- package/dist/cli/colors.js +9 -0
- package/dist/cli/file-utils.js +20 -0
- package/dist/cli/index.js +160 -0
- package/dist/cli/spinner.js +55 -0
- package/dist/core/codegen/control-flow-handlers.js +2 -2
- package/dist/core/codegen/declaration-handlers.js +9 -1
- package/dist/core/codegen/expression-handlers.js +101 -45
- package/dist/core/codegen/function-handlers.js +14 -3
- package/dist/core/codegen/helpers.js +33 -7
- package/dist/core/codegen/index.js +7 -5
- package/dist/core/codegen/statement-handlers.js +109 -37
- package/dist/core/codegen/visitor.js +22 -2
- package/dist/core/constants.js +16 -0
- package/dist/core/error.js +58 -0
- package/dist/index.js +6 -3
- package/package.json +3 -3
- package/src/prelude/scheduler.hpp +144 -144
- package/src/prelude/utils/log_any_value/object.hpp +12 -10
|
@@ -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
|
}
|
|
@@ -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&
|
|
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&
|
|
73
|
-
const auto&
|
|
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 << ": " <<
|
|
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&
|
|
102
|
-
const auto&
|
|
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 << ": " <<
|
|
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)
|