@shd101wyy/yo 0.1.21 → 0.1.22

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.
@@ -673,6 +673,32 @@ impl(forall(K : Type, V : Type), HashMap(K, V), Index(K)(
673
673
  })
674
674
  ));
675
675
 
676
+ /// Clone implementation for HashMap — deep-clones all key-value entries.
677
+ impl(forall(K : Type, V : Type),
678
+ where(K <: (Clone, Eq(K), Hash), V <: Clone),
679
+ HashMap(K, V),
680
+ Clone(
681
+ clone : (fn(self: *(Self)) -> Self)(
682
+ {
683
+ result := Self.new();
684
+ it := self.iter();
685
+ running := true;
686
+ while running, {
687
+ nxt := it.next();
688
+ match(nxt,
689
+ .None => { running = false; },
690
+ .Some(bucket_ptr) => {
691
+ k := (&(bucket_ptr.*.key)).clone();
692
+ v := (&(bucket_ptr.*.value)).clone();
693
+ result.set(k, v);
694
+ }
695
+ );
696
+ };
697
+ result
698
+ }
699
+ )
700
+ ));
701
+
676
702
  export
677
703
  HashMap,
678
704
  HashMapError,
@@ -682,3 +708,64 @@ export
682
708
  HashMapKeys,
683
709
  HashMapValues
684
710
  ;
711
+
712
+ // =============================================================================
713
+ // hash_map! literal macro
714
+ // =============================================================================
715
+
716
+ /// Internal helper: build a list of `tmp.set(k, v).unwrap()` statements from
717
+ /// a sequence of `k => v` arrow expressions.
718
+ __hash_map_build_sets :: (fn(comptime(tmp) : Expr, comptime(entries) : ExprList) -> comptime(ExprList))(
719
+ cond(
720
+ (entries.len() == usize(0)) => ExprList(),
721
+ true => {
722
+ first :: entries.car();
723
+ rest :: entries.cdr();
724
+ __ :: comptime_assert(first.is_fn_call(), "hash_map entries must use 'k => v'");
725
+ callee :: first.get_callee();
726
+ __1 :: comptime_assert((callee.is_atom() && (callee == quote(=>))), "hash_map entries must use 'k => v'");
727
+ pair :: first.get_args();
728
+ __2 :: comptime_assert((pair.len() == usize(2)), "hash_map entries must use 'k => v'");
729
+ key :: pair.car();
730
+ val :: pair.cdr().car();
731
+ stmt :: quote((unquote(tmp).set(unquote(key), unquote(val)).unwrap()));
732
+ stmt.cons(recur(tmp, rest))
733
+ }
734
+ )
735
+ );
736
+
737
+ /// `hash_map` macro — construct a `HashMap(K, V)` literal.
738
+ ///
739
+ /// `K` and `V` are inferred from the first entry's key and value via `typeof`,
740
+ /// so at least one entry is required.
741
+ ///
742
+ /// # Example
743
+ /// ```rust
744
+ /// m := hash_map(`a` => i32(1), `b` => i32(2));
745
+ /// ```
746
+ hash_map :: (fn(...(quote(entries))) -> unquote(Expr)) {
747
+ __ :: comptime_assert((entries.len() > usize(0)),
748
+ "hash_map requires at least one 'k => v' entry to infer K and V");
749
+ first :: entries.car();
750
+ __1 :: comptime_assert(first.is_fn_call(), "hash_map entries must use 'k => v'");
751
+ callee :: first.get_callee();
752
+ __2 :: comptime_assert((callee.is_atom() && (callee == quote(=>))), "hash_map entries must use 'k => v'");
753
+ pair :: first.get_args();
754
+ __3 :: comptime_assert((pair.len() == usize(2)), "hash_map entries must use 'k => v'");
755
+ first_key :: pair.car();
756
+ first_val :: pair.cdr().car();
757
+ rest :: entries.cdr();
758
+ tmp :: gensym("hash_map");
759
+ k_tmp :: gensym("hash_map_k0");
760
+ v_tmp :: gensym("hash_map_v0");
761
+ rest_sets :: __hash_map_build_sets(tmp, rest);
762
+ quote {
763
+ unquote(k_tmp) := unquote(first_key);
764
+ unquote(v_tmp) := unquote(first_val);
765
+ unquote(tmp) := HashMap(typeof(unquote(k_tmp)), typeof(unquote(v_tmp))).new();
766
+ unquote(tmp).set(unquote(k_tmp), unquote(v_tmp)).unwrap();
767
+ unquote_splicing(rest_sets);
768
+ unquote(tmp)
769
+ }
770
+ };
771
+ export hash_map;
@@ -833,3 +833,47 @@ export
833
833
  HashSetIter,
834
834
  HashSetIterPtr
835
835
  ;
836
+
837
+ // =============================================================================
838
+ // hash_set! literal macro
839
+ // =============================================================================
840
+
841
+ /// Internal helper: build a list of `tmp.add(elem).unwrap()` statements from `elems`.
842
+ __hash_set_build_adds :: (fn(comptime(tmp) : Expr, comptime(elems) : ExprList) -> comptime(ExprList))(
843
+ cond(
844
+ (elems.len() == usize(0)) => ExprList(),
845
+ true => {
846
+ first :: elems.car();
847
+ rest :: elems.cdr();
848
+ stmt :: quote((unquote(tmp).add(unquote(first)).unwrap()));
849
+ stmt.cons(recur(tmp, rest))
850
+ }
851
+ )
852
+ );
853
+
854
+ /// `hash_set` macro — construct a `HashSet(T)` literal.
855
+ ///
856
+ /// `T` is inferred from the first element via `typeof`, so at least one
857
+ /// element is required.
858
+ ///
859
+ /// # Example
860
+ /// ```rust
861
+ /// s := hash_set(i32(1), i32(2), i32(3));
862
+ /// ```
863
+ hash_set :: (fn(...(quote(elems))) -> unquote(Expr)) {
864
+ __ :: comptime_assert((elems.len() > usize(0)),
865
+ "hash_set requires at least one element to infer the element type");
866
+ first :: elems.car();
867
+ rest :: elems.cdr();
868
+ tmp :: gensym("hash_set");
869
+ first_tmp :: gensym("hash_set_first");
870
+ rest_adds :: __hash_set_build_adds(tmp, rest);
871
+ quote {
872
+ unquote(first_tmp) := unquote(first);
873
+ unquote(tmp) := HashSet(typeof(unquote(first_tmp))).new();
874
+ unquote(tmp).add(unquote(first_tmp)).unwrap();
875
+ unquote_splicing(rest_adds);
876
+ unquote(tmp)
877
+ }
878
+ };
879
+ export hash_set;
@@ -0,0 +1,244 @@
1
+ //! Insertion-ordered map.
2
+ //!
3
+ //! `OrderedMap(K, V)` preserves the order in which keys were first inserted,
4
+ //! similar to JavaScript's `Map` or Python's `dict` (≥ 3.7). Backed by a
5
+ //! `HashMap` for O(1) average-time lookup and an `ArrayList` of keys for
6
+ //! deterministic iteration order.
7
+ //!
8
+ //! # Complexity
9
+ //!
10
+ //! - `set` (new key): O(1) amortized
11
+ //! - `set` (existing key): O(1) — value updated in place, order unchanged
12
+ //! - `get` / `contains_key`: O(1) average
13
+ //! - `remove`: O(n) — must rebuild the key order list to skip the removed key
14
+ //! - `iter` / `keys` / `values`: O(n), in insertion order
15
+ //!
16
+ //! # Example
17
+ //!
18
+ //! ```rust
19
+ //! { OrderedMap } :: import "std/collections/ordered_map";
20
+ //!
21
+ //! m := OrderedMap(String, i32).new();
22
+ //! m.set(`alpha`, i32(1));
23
+ //! m.set(`beta`, i32(2));
24
+ //! m.set(`gamma`, i32(3));
25
+ //!
26
+ //! // Iteration yields keys in insertion order.
27
+ //! it := m.keys();
28
+ //! while true, {
29
+ //! match(it.next(),
30
+ //! .Some(k) => println(k),
31
+ //! .None => break
32
+ //! );
33
+ //! };
34
+ //! ```
35
+
36
+ open import "./array_list";
37
+ open import "./hash_map";
38
+
39
+ /// Ordered map preserving insertion order of keys.
40
+ /// Keys must implement `Eq` and `Hash`.
41
+ OrderedMap :: (fn(
42
+ comptime(K) : Type,
43
+ comptime(V) : Type,
44
+ where(K <: (Eq(K), Hash))
45
+ ) -> comptime(Type))
46
+ object(
47
+ _map : HashMap(K, V),
48
+ _order : ArrayList(K)
49
+ )
50
+ ;
51
+
52
+ impl(forall(K : Type, V : Type), where(K <: (Eq(K), Hash)), OrderedMap(K, V),
53
+ /// Create an empty `OrderedMap`.
54
+ new : (fn() -> Self)(
55
+ Self(
56
+ _map: HashMap(K, V).new(),
57
+ _order: ArrayList(K).new()
58
+ )
59
+ ),
60
+
61
+ /// Number of entries.
62
+ len : (fn(self : Self) -> usize)(self._map.len()),
63
+
64
+ /// Whether the map is empty.
65
+ is_empty : (fn(self : Self) -> bool)(self._map.is_empty()),
66
+
67
+ /// Returns `true` if `key` is present.
68
+ contains_key : (fn(self : Self, key : K) -> bool)(self._map.contains_key(key)),
69
+
70
+ /// Returns the value for `key`, or `.None`.
71
+ get : (fn(self : Self, key : K) -> Option(V))(self._map.get(key)),
72
+
73
+ /// Insert or update `key -> value`.
74
+ ///
75
+ /// - For a new key, appends `key` to the insertion order.
76
+ /// - For an existing key, only updates the value; order is preserved.
77
+ ///
78
+ /// Returns `Ok(.Some(old_value))` if key already existed, `Ok(.None)` for
79
+ /// a new key, or `.Err(_)` on allocation failure.
80
+ set : (fn(self : Self, key : K, value : V) -> Result(Option(V), HashMapError))({
81
+ is_new := !(self._map.contains_key(key));
82
+ result := self._map.set(key, value);
83
+ cond(
84
+ is_new => match(result,
85
+ .Ok(_) => { self._order.push(key); },
86
+ .Err(_) => ()
87
+ ),
88
+ true => ()
89
+ );
90
+ return result;
91
+ }),
92
+
93
+ /// Remove `key`. Returns the removed value or `.None`.
94
+ /// O(n) — rebuilds the key order list to drop the removed key.
95
+ remove : (fn(self : Self, key : K) -> Option(V))({
96
+ removed := self._map.remove(key);
97
+ match(removed,
98
+ .Some(_) => {
99
+ new_order := ArrayList(K).new();
100
+ i := usize(0);
101
+ n := self._order.len();
102
+ while (i < n), (i = (i + usize(1))), {
103
+ match(self._order.get(i),
104
+ .Some(k) => {
105
+ cond(
106
+ (k == key) => (),
107
+ true => { new_order.push(k); }
108
+ );
109
+ },
110
+ .None => ()
111
+ );
112
+ };
113
+ self._order = new_order;
114
+ },
115
+ .None => ()
116
+ );
117
+ return removed;
118
+ }),
119
+
120
+ /// Remove all entries.
121
+ clear : (fn(self : Self) -> unit)({
122
+ self._map.clear();
123
+ self._order = ArrayList(K).new();
124
+ })
125
+ );
126
+
127
+ /// Iterator over the keys of an `OrderedMap` in insertion order.
128
+ OrderedMapKeys :: (fn(
129
+ comptime(K) : Type,
130
+ comptime(V) : Type,
131
+ where(K <: (Eq(K), Hash))
132
+ ) -> comptime(Type))
133
+ object(
134
+ _map : OrderedMap(K, V),
135
+ _index : usize
136
+ )
137
+ ;
138
+
139
+ impl(forall(K : Type, V : Type), where(K <: (Eq(K), Hash)), OrderedMapKeys(K, V),
140
+ next : (fn(self : *(Self)) -> Option(K))({
141
+ cond(
142
+ (self._index >= self._map._order.len()) => { return .None; },
143
+ true => ()
144
+ );
145
+ k := self._map._order.get(self._index);
146
+ self._index = (self._index + usize(1));
147
+ return k;
148
+ })
149
+ );
150
+
151
+ /// Iterator over the values of an `OrderedMap` in insertion order.
152
+ OrderedMapValues :: (fn(
153
+ comptime(K) : Type,
154
+ comptime(V) : Type,
155
+ where(K <: (Eq(K), Hash))
156
+ ) -> comptime(Type))
157
+ object(
158
+ _map : OrderedMap(K, V),
159
+ _index : usize
160
+ )
161
+ ;
162
+
163
+ impl(forall(K : Type, V : Type), where(K <: (Eq(K), Hash)), OrderedMapValues(K, V),
164
+ next : (fn(self : *(Self)) -> Option(V))({
165
+ cond(
166
+ (self._index >= self._map._order.len()) => { return .None; },
167
+ true => ()
168
+ );
169
+ match(self._map._order.get(self._index),
170
+ .Some(k) => {
171
+ self._index = (self._index + usize(1));
172
+ return self._map._map.get(k);
173
+ },
174
+ .None => { return .None; }
175
+ );
176
+ })
177
+ );
178
+
179
+ /// Key-value pair yielded by `OrderedMapIter`.
180
+ OrderedMapEntry :: (fn(
181
+ comptime(K) : Type,
182
+ comptime(V) : Type
183
+ ) -> comptime(Type))
184
+ struct(
185
+ key : K,
186
+ value : V
187
+ )
188
+ ;
189
+
190
+ /// Iterator over `(key, value)` pairs of an `OrderedMap` in insertion order.
191
+ OrderedMapIter :: (fn(
192
+ comptime(K) : Type,
193
+ comptime(V) : Type,
194
+ where(K <: (Eq(K), Hash))
195
+ ) -> comptime(Type))
196
+ object(
197
+ _map : OrderedMap(K, V),
198
+ _index : usize
199
+ )
200
+ ;
201
+
202
+ impl(forall(K : Type, V : Type), where(K <: (Eq(K), Hash)), OrderedMapIter(K, V),
203
+ next : (fn(self : *(Self)) -> Option(OrderedMapEntry(K, V)))({
204
+ cond(
205
+ (self._index >= self._map._order.len()) => { return .None; },
206
+ true => ()
207
+ );
208
+ match(self._map._order.get(self._index),
209
+ .Some(k) => {
210
+ self._index = (self._index + usize(1));
211
+ match(self._map._map.get(k),
212
+ .Some(v) => { return .Some(OrderedMapEntry(K, V)(key: k, value: v)); },
213
+ .None => { return .None; }
214
+ );
215
+ },
216
+ .None => { return .None; }
217
+ );
218
+ })
219
+ );
220
+
221
+ impl(forall(K : Type, V : Type), where(K <: (Eq(K), Hash)), OrderedMap(K, V),
222
+ /// Iterator over keys in insertion order.
223
+ keys : (fn(self : Self) -> OrderedMapKeys(K, V))(
224
+ OrderedMapKeys(K, V)(_map: self, _index: usize(0))
225
+ ),
226
+
227
+ /// Iterator over values in insertion order.
228
+ values : (fn(self : Self) -> OrderedMapValues(K, V))(
229
+ OrderedMapValues(K, V)(_map: self, _index: usize(0))
230
+ ),
231
+
232
+ /// Iterator over `(key, value)` pairs in insertion order.
233
+ iter : (fn(self : Self) -> OrderedMapIter(K, V))(
234
+ OrderedMapIter(K, V)(_map: self, _index: usize(0))
235
+ )
236
+ );
237
+
238
+ export
239
+ OrderedMap,
240
+ OrderedMapEntry,
241
+ OrderedMapKeys,
242
+ OrderedMapValues,
243
+ OrderedMapIter
244
+ ;
@@ -1,43 +1,16 @@
1
- //! Process information, command-line arguments, environment variables, and platform detection.
2
-
3
- open import "./collections/array_list";
4
- open import "./string";
5
- open import "./path";
6
- { GlobalAllocator } :: import "./allocator";
1
+ //! Process environment: command-line arguments, environment variables,
2
+ //! and current working directory.
3
+ //!
4
+ //! Mirrors the layout of Rust's `std::env`. Platform/architecture detection
5
+ //! and child-process spawning live in `std/process`.
6
+
7
+ open import "../collections/array_list";
8
+ open import "../string";
9
+ open import "../path";
10
+ { platform, Platform } :: import "../process";
11
+ { GlobalAllocator } :: import "../allocator";
7
12
  { malloc, free } :: GlobalAllocator;
8
13
 
9
- /// Current target platform as a compile-time string.
10
- /// One of: "linux", "macos", "windows", "freebsd", "emscripten", "wasi".
11
- platform :: __yo_process_platform();
12
- export platform;
13
-
14
- /// Platform constants for compile-time platform comparisons.
15
- Platform :: {
16
- Linux : "linux",
17
- Macos : "macos",
18
- Windows : "windows",
19
- FreeBSD : "freebsd",
20
- Emscripten : "emscripten",
21
- Wasi : "wasi"
22
- };
23
- export Platform;
24
-
25
- /// Current target architecture as a compile-time string.
26
- /// One of: "x86_64", "aarch64", "x86", "arm", "wasm32".
27
- arch :: __yo_process_arch();
28
- export arch;
29
-
30
- /// Architecture constants for compile-time architecture comparisons.
31
- Arch :: {
32
- X86_64 : "x86_64",
33
- Aarch64 : "aarch64",
34
- X86 : "x86",
35
- Arm : "arm",
36
- Wasm32 : "wasm32"
37
- };
38
- export Arch;
39
-
40
-
41
14
  // === Low-level C interface ===
42
15
 
43
16
  extern "Yo",
@@ -71,11 +44,11 @@ export argv;
71
44
 
72
45
  /// Get command-line arguments as an `ArrayList(String)`.
73
46
  /// The first element is the program name.
74
- args :: (fn() -> ArrayList(String)) {
47
+ args :: (fn() -> ArrayList(String)) {
75
48
  raw := raw_args();
76
49
  i := usize(0);
77
50
  len := usize(argc());
78
-
51
+
79
52
  result := ArrayList(String).with_capacity(len);
80
53
 
81
54
  while i < len, {
@@ -90,11 +63,11 @@ export args;
90
63
 
91
64
  /// Environment variable access and manipulation.
92
65
  env :: impl {
93
- { getenv, setenv } :: import "./libc/stdlib";
66
+ { getenv, setenv } :: import "../libc/stdlib";
94
67
 
95
68
  /// Get the value of an environment variable by name.
96
69
  /// Returns `.None` if the variable is not set.
97
- get :: (fn(name : String) -> Option(String)) {
70
+ get :: (fn(name : String) -> Option(String)) {
98
71
  name_cstr := name.to_cstr().ptr().unwrap();
99
72
  val_ptr := getenv(*(char)(name_cstr));
100
73
  match(val_ptr,
@@ -109,28 +82,24 @@ env :: impl {
109
82
  set :: (fn(name : String, value : String, (overwrite : bool) ?= true) -> bool) {
110
83
  name_cstr := name.to_cstr().ptr().unwrap();
111
84
  value_cstr := value.to_cstr().ptr().unwrap();
112
-
85
+
113
86
  result := cond(
114
87
  (platform == Platform.Windows) => {
115
- // Windows: use _putenv_s (doesn't have overwrite parameter)
116
- { _putenv_s } :: import "./libc/windows";
117
-
88
+ { _putenv_s } :: import "../libc/windows";
89
+
118
90
  cond(
119
91
  overwrite =>
120
- // Always set on Windows (no native "don't overwrite" option)
121
92
  _putenv_s(*(char)(name_cstr), *(char)(value_cstr)),
122
93
  true => {
123
- // Check if variable exists first
124
94
  existing := getenv(*(char)(name_cstr));
125
95
  match(existing,
126
- .Some(_) => int(0), // Variable exists, don't overwrite (return success)
96
+ .Some(_) => int(0),
127
97
  .None => _putenv_s(*(char)(name_cstr), *(char)(value_cstr))
128
98
  )
129
99
  }
130
100
  )
131
101
  },
132
102
  true => {
133
- // Unix: use setenv
134
103
  overwrite_int := cond(
135
104
  overwrite => int(1),
136
105
  true => int(0)
@@ -138,7 +107,7 @@ env :: impl {
138
107
  setenv(*(char)(name_cstr), *(char)(value_cstr), overwrite_int)
139
108
  }
140
109
  );
141
-
110
+
142
111
  return result == int(0);
143
112
  };
144
113
  export set;
@@ -150,28 +119,22 @@ export env;
150
119
  cwd :: (fn() -> Result(Path, String))(
151
120
  cond(
152
121
  (platform == Platform.Windows) => {
153
- // Windows implementation using GetCurrentDirectoryW
154
- { GetCurrentDirectoryW, WideCharToMultiByte, CP_UTF8, WCHAR, DWORD } :: import "./libc/windows";
155
-
156
- // First, get the required buffer size
122
+ { GetCurrentDirectoryW, WideCharToMultiByte, CP_UTF8, WCHAR, DWORD } :: import "../libc/windows";
123
+
157
124
  required_size := GetCurrentDirectoryW(ulong(0), .None);
158
125
  cond(
159
126
  (required_size == ulong(0)) => .Err(`Failed to get current working directory on Windows`),
160
127
  true => {
161
- // Allocate buffer for wide characters
162
128
  wbuf := *(WCHAR)(malloc((usize(required_size) * usize(2))).unwrap());
163
-
164
- // Get the current directory in UTF-16
129
+
165
130
  actual_size := GetCurrentDirectoryW(required_size, .Some(wbuf));
166
-
131
+
167
132
  cond(
168
133
  (actual_size == ulong(0)) => {
169
134
  free(.Some(*(void)(wbuf)));
170
135
  .Err(`Failed to get current working directory on Windows`)
171
136
  },
172
137
  true => {
173
- // Convert UTF-16 to UTF-8
174
- // First, get the required buffer size for UTF-8
175
138
  utf8_size := WideCharToMultiByte(
176
139
  CP_UTF8,
177
140
  ulong(0),
@@ -182,17 +145,15 @@ cwd :: (fn() -> Result(Path, String))(
182
145
  .None,
183
146
  .None
184
147
  );
185
-
148
+
186
149
  cond(
187
150
  (utf8_size <= i32(0)) => {
188
151
  free(.Some(*(void)(wbuf)));
189
152
  .Err(`Failed to convert directory path to UTF-8`)
190
153
  },
191
154
  true => {
192
- // Allocate buffer for UTF-8 string
193
155
  utf8_buf := *(u8)(malloc((usize(utf8_size) + usize(1))).unwrap());
194
-
195
- // Convert to UTF-8
156
+
196
157
  result := WideCharToMultiByte(
197
158
  CP_UTF8,
198
159
  ulong(0),
@@ -203,16 +164,15 @@ cwd :: (fn() -> Result(Path, String))(
203
164
  .None,
204
165
  .None
205
166
  );
206
-
167
+
207
168
  free(.Some(*(void)(wbuf)));
208
-
169
+
209
170
  cond(
210
171
  (result <= i32(0)) => {
211
172
  free(.Some(*(void)(utf8_buf)));
212
173
  .Err(`Failed to convert directory path to UTF-8`)
213
174
  },
214
175
  true => {
215
- // Add null terminator
216
176
  (utf8_buf &+ usize(result)).* = u8(0);
217
177
  cwd_str := String.from_cstr(utf8_buf).unwrap();
218
178
  free(.Some(*(void)(utf8_buf)));
@@ -227,15 +187,13 @@ cwd :: (fn() -> Result(Path, String))(
227
187
  )
228
188
  },
229
189
  true => {
230
- // Unix-like implementation using getcwd
231
- { getcwd } :: import "./libc/unistd";
232
-
233
- // Allocate a buffer for the path (PATH_MAX is typically 4096)
190
+ { getcwd } :: import "../libc/unistd";
191
+
234
192
  buf_size := usize(4096);
235
193
  buf := *(char)(malloc(buf_size).unwrap());
236
-
194
+
237
195
  result_ptr := getcwd(buf, buf_size);
238
-
196
+
239
197
  match(result_ptr,
240
198
  .None => {
241
199
  free(.Some(*(void)(buf)));
@@ -257,26 +215,24 @@ export cwd;
257
215
  chdir :: (fn(path: Path) -> Result(unit, String))(
258
216
  cond(
259
217
  (platform == Platform.Windows) => {
260
- // Windows implementation using SetCurrentDirectoryA
261
- { SetCurrentDirectoryA, BOOL } :: import "./libc/windows";
262
-
218
+ { SetCurrentDirectoryA, BOOL } :: import "../libc/windows";
219
+
263
220
  path_str := path.to_string();
264
221
  path_cstr := path_str.to_cstr().ptr().unwrap();
265
222
  result := SetCurrentDirectoryA(*(char)(path_cstr));
266
-
223
+
267
224
  cond(
268
225
  (result == int(0)) => .Err(`Failed to change directory to: ${path_str}`),
269
226
  true => .Ok(())
270
227
  )
271
228
  },
272
229
  true => {
273
- // Unix-like implementation using chdir
274
- { chdir : unix_chdir } :: import "./libc/unistd";
275
-
230
+ { chdir : unix_chdir } :: import "../libc/unistd";
231
+
276
232
  path_str := path.to_string();
277
233
  path_cstr := path_str.to_cstr().ptr().unwrap();
278
234
  result := unix_chdir(*(char)(path_cstr));
279
-
235
+
280
236
  cond(
281
237
  (result != int(0)) => .Err(`Failed to change directory to: ${path_str}`),
282
238
  true => .Ok(())
@@ -285,10 +241,3 @@ chdir :: (fn(path: Path) -> Result(unit, String))(
285
241
  )
286
242
  );
287
243
  export chdir;
288
-
289
- /// Exit the process with the given status code.
290
- exit :: (fn(code : usize) -> unit) {
291
- { exit : _exit } :: import "./libc/stdlib";
292
- _exit(int(code));
293
- };
294
- export exit;
package/std/fs/temp.yo CHANGED
@@ -30,7 +30,8 @@ _dir_mod :: import "./dir";
30
30
  IO_temp :: import "../sys/temp";
31
31
  IO_file :: import "../sys/file";
32
32
  { memcpy } :: import "../libc/string";
33
- { platform, Platform, env } :: import "../process";
33
+ { platform, Platform } :: import "../process";
34
+ { env } :: import "../env";
34
35
 
35
36
  _default_tmp_dir :: (fn() -> String)(
36
37
  cond(
package/std/os/env.yo CHANGED
@@ -12,7 +12,8 @@
12
12
  //! ```
13
13
 
14
14
  open import "../string";
15
- { platform, Platform, env } :: import "../process";
15
+ { platform, Platform } :: import "../process";
16
+ { env } :: import "../env";
16
17
 
17
18
  // ============================================================================
18
19
  // Directory helpers