@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.
Files changed (38) hide show
  1. package/README.md +3 -0
  2. package/out/cjs/index.cjs +541 -561
  3. package/out/cjs/yo-cli.cjs +644 -664
  4. package/out/cjs/yo-lsp.cjs +585 -605
  5. package/out/esm/index.mjs +527 -547
  6. package/out/types/src/codegen/exprs/return.d.ts +1 -1
  7. package/out/types/src/codegen/types/generation.d.ts +0 -2
  8. package/out/types/src/codegen/utils/index.d.ts +2 -8
  9. package/out/types/src/evaluator/builtins/rc-fns.d.ts +0 -5
  10. package/out/types/src/evaluator/context.d.ts +7 -3
  11. package/out/types/src/evaluator/trait-checking.d.ts +2 -0
  12. package/out/types/src/evaluator/types/object.d.ts +2 -1
  13. package/out/types/src/evaluator/types/struct.d.ts +2 -1
  14. package/out/types/src/evaluator/types/utils.d.ts +3 -8
  15. package/out/types/src/expr.d.ts +1 -2
  16. package/out/types/src/function-value.d.ts +1 -0
  17. package/out/types/src/types/creators.d.ts +2 -3
  18. package/out/types/src/types/definitions.d.ts +1 -6
  19. package/out/types/src/types/guards.d.ts +5 -2
  20. package/out/types/src/types/tags.d.ts +0 -1
  21. package/out/types/tsconfig.tsbuildinfo +1 -1
  22. package/package.json +1 -1
  23. package/std/imm/list.yo +254 -0
  24. package/std/imm/map.yo +917 -0
  25. package/std/imm/set.yo +179 -0
  26. package/std/imm/sorted_map.yo +595 -0
  27. package/std/imm/sorted_set.yo +202 -0
  28. package/std/imm/string.yo +667 -0
  29. package/std/imm/vec.yo +456 -0
  30. package/std/prelude.yo +22 -5
  31. package/std/sync/channel.yo +92 -44
  32. package/std/sync/cond.yo +5 -1
  33. package/std/sync/mutex.yo +5 -1
  34. package/std/sync/once.yo +2 -1
  35. package/std/sync/rwlock.yo +2 -1
  36. package/std/sync/waitgroup.yo +2 -1
  37. package/out/types/src/codegen/exprs/arc.d.ts +0 -5
  38. package/out/types/src/evaluator/calls/arc.d.ts +0 -15
@@ -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
- { Deque } :: import "../collections/deque";
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
- Channel :: (fn(comptime(T) : Type) -> comptime(Type))
25
- object(
26
- _buf : Deque(T),
27
- _capacity : usize,
28
- _mutex : Mutex,
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 : bool
40
+ _closed : bool
32
41
  )
33
42
  ;
34
43
 
35
- impl(forall(T : Type), Channel(T),
36
- // Create a bounded channel with the given capacity.
37
- // Capacity must be > 0.
38
- new : (fn(capacity: usize) -> Self)(
39
- Self(
40
- _buf: Deque(T).new(),
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
- // Send a value into the channel.
50
- // Blocks if the channel is full until space becomes available.
51
- // Returns .Ok(()) on success, .Err(()) if the channel is closed.
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._buf.len() >= self._capacity) && (!(self._closed)))), {
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
- self._buf.push_back(value);
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
- // Receive a value from the channel.
72
- // Blocks if the channel is empty until a value is available.
73
- // Returns .Some(value) on success, .None if the channel is closed and empty.
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._buf.is_empty()) && (!(self._closed)))), {
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
- (result.is_some()) => self._not_full.signal(),
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 result;
111
+ return .Some(val);
87
112
  }),
88
113
 
89
- // Try to send a value without blocking.
90
- // Returns .Ok(()) if sent, .Err(()) if full or closed.
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._buf.len() >= self._capacity)) => {
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._buf.push_back(value);
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
- // Try to receive a value without blocking.
107
- // Returns .Some(value) if available, .None if empty.
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
- (result.is_some()) => self._not_full.signal(),
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 result;
151
+ return .Some(val);
117
152
  }),
118
153
 
119
- // Close the channel. No more values can be sent.
120
- // Pending recv() calls will return .None once the buffer is drained.
121
- // Pending send() calls will return .Err(()).
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
- // Check if the channel is closed.
165
+ /// Check if the channel is closed.
131
166
  is_closed : (fn(self: Self) -> bool)(
132
167
  self._closed
133
168
  ),
134
169
 
135
- // Return the number of values currently buffered.
170
+ /// Return the number of values currently buffered.
136
171
  len : (fn(self: Self) -> usize)(
137
- self._buf.len()
172
+ self._len
138
173
  ),
139
174
 
140
- // Check if the channel buffer is empty.
175
+ /// Check if the channel buffer is empty.
141
176
  is_empty : (fn(self: Self) -> bool)(
142
- self._buf.is_empty()
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
- Cond :: object(
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
- Mutex :: object(
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
@@ -18,7 +18,8 @@
18
18
  { Mutex } :: import "./mutex";
19
19
 
20
20
  /// Execute a function exactly once, thread-safely.
21
- Once :: object(
21
+ /// Uses atomic reference counting for safe cross-thread sharing.
22
+ Once :: atomic object(
22
23
  _done : bool,
23
24
  _mutex : Mutex
24
25
  );
@@ -21,7 +21,8 @@
21
21
  { Cond } :: import "./cond";
22
22
 
23
23
  /// Reader-writer lock built on `Mutex` and `Cond`.
24
- RwLock :: object(
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,
@@ -23,7 +23,8 @@
23
23
  { Cond } :: import "./cond";
24
24
 
25
25
  /// Synchronization primitive that blocks until a counter reaches zero.
26
- WaitGroup :: object(
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;