@shd101wyy/yo 0.1.15 → 0.1.16
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 +3 -0
- package/out/cjs/index.cjs +541 -561
- package/out/cjs/yo-cli.cjs +644 -664
- package/out/cjs/yo-lsp.cjs +585 -605
- package/out/esm/index.mjs +527 -547
- package/out/types/src/codegen/exprs/return.d.ts +1 -1
- package/out/types/src/codegen/types/generation.d.ts +0 -2
- package/out/types/src/codegen/utils/index.d.ts +2 -8
- package/out/types/src/evaluator/builtins/rc-fns.d.ts +0 -5
- package/out/types/src/evaluator/context.d.ts +7 -3
- package/out/types/src/evaluator/trait-checking.d.ts +2 -0
- package/out/types/src/evaluator/types/object.d.ts +2 -1
- package/out/types/src/evaluator/types/struct.d.ts +2 -1
- package/out/types/src/evaluator/types/utils.d.ts +3 -8
- package/out/types/src/expr.d.ts +1 -2
- package/out/types/src/function-value.d.ts +1 -0
- package/out/types/src/types/creators.d.ts +2 -3
- package/out/types/src/types/definitions.d.ts +1 -6
- package/out/types/src/types/guards.d.ts +5 -2
- package/out/types/src/types/tags.d.ts +0 -1
- package/out/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/std/imm/list.yo +254 -0
- package/std/imm/map.yo +917 -0
- package/std/imm/set.yo +179 -0
- package/std/imm/sorted_map.yo +595 -0
- package/std/imm/sorted_set.yo +202 -0
- package/std/imm/string.yo +667 -0
- package/std/imm/vec.yo +456 -0
- package/std/prelude.yo +22 -5
- package/std/sync/channel.yo +92 -44
- package/std/sync/cond.yo +5 -1
- package/std/sync/mutex.yo +5 -1
- package/std/sync/once.yo +2 -1
- package/std/sync/rwlock.yo +2 -1
- package/std/sync/waitgroup.yo +2 -1
- package/out/types/src/codegen/exprs/arc.d.ts +0 -5
- package/out/types/src/evaluator/calls/arc.d.ts +0 -15
package/std/sync/channel.yo
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
//! Bounded multi-producer multi-consumer (MPMC) channel.
|
|
2
2
|
//! Uses blocking send/recv via condition variables — does not require IO.
|
|
3
3
|
//!
|
|
4
|
+
//! Channel uses `atomic object` with atomic reference counting, so it can be
|
|
5
|
+
//! safely shared across threads without `Arc` wrapping.
|
|
6
|
+
//!
|
|
4
7
|
//! # Example
|
|
5
8
|
//!
|
|
6
9
|
//! ```rust
|
|
@@ -16,43 +19,53 @@
|
|
|
16
19
|
//! t.join();
|
|
17
20
|
//! ```
|
|
18
21
|
|
|
19
|
-
{
|
|
22
|
+
{ GlobalAllocator } :: import "../allocator";
|
|
23
|
+
{ malloc, free } :: GlobalAllocator;
|
|
20
24
|
{ Mutex } :: import "./mutex";
|
|
21
25
|
{ Cond } :: import "./cond";
|
|
22
26
|
|
|
23
27
|
/// Thread-safe bounded channel for passing values between threads.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
/// Uses atomic reference counting — implements `Send` and can be
|
|
29
|
+
/// safely shared across threads without `Arc` wrapping.
|
|
30
|
+
/// T must implement `Send` to ensure values are safe to transfer between threads.
|
|
31
|
+
Channel :: (fn(comptime(T) : Type, where(T <: Send)) -> comptime(Type))
|
|
32
|
+
atomic object(
|
|
33
|
+
_data : *(T),
|
|
34
|
+
_head : usize,
|
|
35
|
+
_len : usize,
|
|
36
|
+
_capacity : usize,
|
|
37
|
+
_mutex : Mutex,
|
|
29
38
|
_not_empty : Cond,
|
|
30
39
|
_not_full : Cond,
|
|
31
|
-
_closed
|
|
40
|
+
_closed : bool
|
|
32
41
|
)
|
|
33
42
|
;
|
|
34
43
|
|
|
35
|
-
impl(forall(T : Type), Channel(T),
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
new : (fn(capacity: usize) -> Self)(
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
impl(forall(T : Type), Channel(T), where(T <: Send),
|
|
45
|
+
/// Create a bounded channel with the given capacity.
|
|
46
|
+
/// Capacity must be > 0.
|
|
47
|
+
new : (fn(capacity: usize) -> Self)({
|
|
48
|
+
assert((capacity > usize(0)), "Channel.new: capacity must be > 0");
|
|
49
|
+
(ptr : *(T)) = *(T)(malloc((capacity * sizeof(T))).unwrap());
|
|
50
|
+
return Self(
|
|
51
|
+
_data: ptr,
|
|
52
|
+
_head: usize(0),
|
|
53
|
+
_len: usize(0),
|
|
41
54
|
_capacity: capacity,
|
|
42
55
|
_mutex: Mutex.new(),
|
|
43
56
|
_not_empty: Cond.new(),
|
|
44
57
|
_not_full: Cond.new(),
|
|
45
58
|
_closed: false
|
|
46
|
-
)
|
|
47
|
-
),
|
|
59
|
+
);
|
|
60
|
+
}),
|
|
48
61
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
62
|
+
/// Send a value into the channel.
|
|
63
|
+
/// Blocks if the channel is full until space becomes available.
|
|
64
|
+
/// Returns .Ok(()) on success, .Err(()) if the channel is closed.
|
|
52
65
|
send : (fn(self: Self, value: T) -> Result(unit, unit))({
|
|
53
66
|
self._mutex.lock();
|
|
54
67
|
// Wait while buffer is full and channel is not closed
|
|
55
|
-
while runtime(((self.
|
|
68
|
+
while runtime(((self._len >= self._capacity) && (!(self._closed)))), {
|
|
56
69
|
self._not_full.wait(self._mutex);
|
|
57
70
|
};
|
|
58
71
|
cond(
|
|
@@ -62,63 +75,85 @@ impl(forall(T : Type), Channel(T),
|
|
|
62
75
|
},
|
|
63
76
|
true => ()
|
|
64
77
|
);
|
|
65
|
-
|
|
78
|
+
// Write value at tail position
|
|
79
|
+
(tail : usize) = ((self._head + self._len) % self._capacity);
|
|
80
|
+
consume((self._data &+ tail).* = value);
|
|
81
|
+
self._len = (self._len + usize(1));
|
|
66
82
|
self._not_empty.signal();
|
|
67
83
|
self._mutex.unlock();
|
|
68
84
|
return .Ok(());
|
|
69
85
|
}),
|
|
70
86
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
87
|
+
/// Receive a value from the channel.
|
|
88
|
+
/// Blocks if the channel is empty until a value is available.
|
|
89
|
+
/// Returns .Some(value) on success, .None if the channel is closed and empty.
|
|
74
90
|
recv : (fn(self: Self) -> ?T)({
|
|
75
91
|
self._mutex.lock();
|
|
76
92
|
// Wait while buffer is empty and channel is not closed
|
|
77
|
-
while runtime(((self.
|
|
93
|
+
while runtime(((self._len == usize(0)) && (!(self._closed)))), {
|
|
78
94
|
self._not_empty.wait(self._mutex);
|
|
79
95
|
};
|
|
80
|
-
result := self._buf.pop_front();
|
|
81
96
|
cond(
|
|
82
|
-
(
|
|
97
|
+
(self._len == usize(0)) => {
|
|
98
|
+
self._mutex.unlock();
|
|
99
|
+
return .None;
|
|
100
|
+
},
|
|
83
101
|
true => ()
|
|
84
102
|
);
|
|
103
|
+
// Read value at head position and neutralize the slot's RC
|
|
104
|
+
element_ptr := (self._data &+ self._head);
|
|
105
|
+
(val : T) = element_ptr.*;
|
|
106
|
+
unsafe.drop(element_ptr.*);
|
|
107
|
+
self._head = ((self._head + usize(1)) % self._capacity);
|
|
108
|
+
self._len = (self._len - usize(1));
|
|
109
|
+
self._not_full.signal();
|
|
85
110
|
self._mutex.unlock();
|
|
86
|
-
return
|
|
111
|
+
return .Some(val);
|
|
87
112
|
}),
|
|
88
113
|
|
|
89
|
-
|
|
90
|
-
|
|
114
|
+
/// Try to send a value without blocking.
|
|
115
|
+
/// Returns .Ok(()) if sent, .Err(()) if full or closed.
|
|
91
116
|
try_send : (fn(self: Self, value: T) -> Result(unit, unit))({
|
|
92
117
|
self._mutex.lock();
|
|
93
118
|
cond(
|
|
94
|
-
(self._closed || (self.
|
|
119
|
+
(self._closed || (self._len >= self._capacity)) => {
|
|
95
120
|
self._mutex.unlock();
|
|
96
121
|
return .Err(());
|
|
97
122
|
},
|
|
98
123
|
true => ()
|
|
99
124
|
);
|
|
100
|
-
self.
|
|
125
|
+
(tail : usize) = ((self._head + self._len) % self._capacity);
|
|
126
|
+
consume((self._data &+ tail).* = value);
|
|
127
|
+
self._len = (self._len + usize(1));
|
|
101
128
|
self._not_empty.signal();
|
|
102
129
|
self._mutex.unlock();
|
|
103
130
|
return .Ok(());
|
|
104
131
|
}),
|
|
105
132
|
|
|
106
|
-
|
|
107
|
-
|
|
133
|
+
/// Try to receive a value without blocking.
|
|
134
|
+
/// Returns .Some(value) if available, .None if empty.
|
|
108
135
|
try_recv : (fn(self: Self) -> ?T)({
|
|
109
136
|
self._mutex.lock();
|
|
110
|
-
result := self._buf.pop_front();
|
|
111
137
|
cond(
|
|
112
|
-
(
|
|
138
|
+
(self._len == usize(0)) => {
|
|
139
|
+
self._mutex.unlock();
|
|
140
|
+
return .None;
|
|
141
|
+
},
|
|
113
142
|
true => ()
|
|
114
143
|
);
|
|
144
|
+
element_ptr := (self._data &+ self._head);
|
|
145
|
+
(val : T) = element_ptr.*;
|
|
146
|
+
unsafe.drop(element_ptr.*);
|
|
147
|
+
self._head = ((self._head + usize(1)) % self._capacity);
|
|
148
|
+
self._len = (self._len - usize(1));
|
|
149
|
+
self._not_full.signal();
|
|
115
150
|
self._mutex.unlock();
|
|
116
|
-
return
|
|
151
|
+
return .Some(val);
|
|
117
152
|
}),
|
|
118
153
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
154
|
+
/// Close the channel. No more values can be sent.
|
|
155
|
+
/// Pending recv() calls will return .None once the buffer is drained.
|
|
156
|
+
/// Pending send() calls will return .Err(()).
|
|
122
157
|
close : (fn(self: Self) -> unit)({
|
|
123
158
|
self._mutex.lock();
|
|
124
159
|
self._closed = true;
|
|
@@ -127,20 +162,33 @@ impl(forall(T : Type), Channel(T),
|
|
|
127
162
|
self._mutex.unlock();
|
|
128
163
|
}),
|
|
129
164
|
|
|
130
|
-
|
|
165
|
+
/// Check if the channel is closed.
|
|
131
166
|
is_closed : (fn(self: Self) -> bool)(
|
|
132
167
|
self._closed
|
|
133
168
|
),
|
|
134
169
|
|
|
135
|
-
|
|
170
|
+
/// Return the number of values currently buffered.
|
|
136
171
|
len : (fn(self: Self) -> usize)(
|
|
137
|
-
self.
|
|
172
|
+
self._len
|
|
138
173
|
),
|
|
139
174
|
|
|
140
|
-
|
|
175
|
+
/// Check if the channel buffer is empty.
|
|
141
176
|
is_empty : (fn(self: Self) -> bool)(
|
|
142
|
-
self.
|
|
177
|
+
(self._len == usize(0))
|
|
143
178
|
)
|
|
144
179
|
);
|
|
145
180
|
|
|
181
|
+
// Dispose: drop remaining elements and free the buffer
|
|
182
|
+
impl(forall(T : Type), Channel(T), where(T <: Send), Dispose(
|
|
183
|
+
dispose : (fn(self: Self) -> unit)({
|
|
184
|
+
(i : usize) = usize(0);
|
|
185
|
+
while runtime((i < self._len)), {
|
|
186
|
+
(idx : usize) = ((self._head + i) % self._capacity);
|
|
187
|
+
unsafe.drop((self._data &+ idx).*);
|
|
188
|
+
i = (i + usize(1));
|
|
189
|
+
};
|
|
190
|
+
free(.Some(*(void)(self._data)));
|
|
191
|
+
})
|
|
192
|
+
));
|
|
193
|
+
|
|
146
194
|
export Channel;
|
package/std/sync/cond.yo
CHANGED
|
@@ -11,6 +11,9 @@ extern "Yo",
|
|
|
11
11
|
__yo_cond_destroy : (fn(cv : *(__YO_COND_TYPE)) -> unit)
|
|
12
12
|
;
|
|
13
13
|
|
|
14
|
+
impl(__YO_COND_TYPE, Send());
|
|
15
|
+
impl(__YO_COND_TYPE, Acyclic());
|
|
16
|
+
|
|
14
17
|
/// Low-level condition variable (manual lifetime via `destroy`).
|
|
15
18
|
cond_t :: newtype(
|
|
16
19
|
cv : __YO_COND_TYPE
|
|
@@ -38,7 +41,8 @@ impl(cond_t,
|
|
|
38
41
|
);
|
|
39
42
|
|
|
40
43
|
/// Reference-counted condition variable with automatic cleanup via `Dispose`.
|
|
41
|
-
|
|
44
|
+
/// Uses atomic reference counting for safe cross-thread sharing.
|
|
45
|
+
Cond :: atomic object(
|
|
42
46
|
cv : __YO_COND_TYPE
|
|
43
47
|
);
|
|
44
48
|
impl(Cond,
|
package/std/sync/mutex.yo
CHANGED
|
@@ -8,6 +8,9 @@ extern "Yo",
|
|
|
8
8
|
__yo_mutex_destroy : (fn(mutex : *(__YO_THREAD_SYNC_TYPE)) -> unit)
|
|
9
9
|
;
|
|
10
10
|
|
|
11
|
+
impl(__YO_THREAD_SYNC_TYPE, Send());
|
|
12
|
+
impl(__YO_THREAD_SYNC_TYPE, Acyclic());
|
|
13
|
+
|
|
11
14
|
/// Low-level mutex (manual lifetime via `destroy`).
|
|
12
15
|
mutex_t :: newtype(
|
|
13
16
|
mutex : __YO_THREAD_SYNC_TYPE
|
|
@@ -31,7 +34,8 @@ impl(mutex_t,
|
|
|
31
34
|
);
|
|
32
35
|
|
|
33
36
|
/// Reference-counted mutex with automatic cleanup via `Dispose`.
|
|
34
|
-
|
|
37
|
+
/// Uses atomic reference counting for safe cross-thread sharing.
|
|
38
|
+
Mutex :: atomic object(
|
|
35
39
|
mutex : __YO_THREAD_SYNC_TYPE
|
|
36
40
|
);
|
|
37
41
|
impl(Mutex,
|
package/std/sync/once.yo
CHANGED
package/std/sync/rwlock.yo
CHANGED
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
{ Cond } :: import "./cond";
|
|
22
22
|
|
|
23
23
|
/// Reader-writer lock built on `Mutex` and `Cond`.
|
|
24
|
-
|
|
24
|
+
/// Uses atomic reference counting for safe cross-thread sharing.
|
|
25
|
+
RwLock :: atomic object(
|
|
25
26
|
_readers : i32,
|
|
26
27
|
_writer : bool,
|
|
27
28
|
_mutex : Mutex,
|
package/std/sync/waitgroup.yo
CHANGED
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
{ Cond } :: import "./cond";
|
|
24
24
|
|
|
25
25
|
/// Synchronization primitive that blocks until a counter reaches zero.
|
|
26
|
-
|
|
26
|
+
/// Uses atomic reference counting for safe cross-thread sharing.
|
|
27
|
+
WaitGroup :: atomic object(
|
|
27
28
|
_count : i32,
|
|
28
29
|
_mutex : Mutex,
|
|
29
30
|
_cv : Cond
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { FnCallExpr } from "../../expr";
|
|
2
|
-
import { type CodeGenContext } from "../utils";
|
|
3
|
-
export declare function generateYoArcDispose(expr: FnCallExpr, indent: string, context: CodeGenContext): string;
|
|
4
|
-
export declare function isArcTypeCall(expr: FnCallExpr): boolean;
|
|
5
|
-
export declare function generateArcTypeCall(expr: FnCallExpr, indent: string, context: CodeGenContext): string;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { type Environment } from "../../env";
|
|
2
|
-
import { type FnCallExpr } from "../../expr";
|
|
3
|
-
import type { ArcType } from "../../types/definitions";
|
|
4
|
-
import type { EvaluatorContext } from "../context";
|
|
5
|
-
export declare function evaluateArcTypeCall({ expr, env, context, }: {
|
|
6
|
-
expr: FnCallExpr;
|
|
7
|
-
env: Environment;
|
|
8
|
-
context: EvaluatorContext;
|
|
9
|
-
}): FnCallExpr;
|
|
10
|
-
export declare function evaluateArcValueCall({ expr, env, context, arcType, }: {
|
|
11
|
-
expr: FnCallExpr;
|
|
12
|
-
env: Environment;
|
|
13
|
-
context: EvaluatorContext;
|
|
14
|
-
arcType: ArcType;
|
|
15
|
-
}): FnCallExpr;
|