@shd101wyy/yo 0.0.28 → 0.0.30

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 (48) hide show
  1. package/README.md +20 -1
  2. package/out/cjs/index.cjs +7554 -7826
  3. package/out/cjs/yo-cli.cjs +7604 -7876
  4. package/out/esm/index.mjs +7453 -7725
  5. package/out/types/src/codegen/async/runtime-core.d.ts +2 -1
  6. package/out/types/src/codegen/async/runtime-io-common.d.ts +3 -1
  7. package/out/types/src/codegen/async/runtime-io-linux.d.ts +1 -0
  8. package/out/types/src/codegen/async/runtime-io-macos.d.ts +1 -0
  9. package/out/types/src/codegen/async/runtime-io-windows.d.ts +1 -0
  10. package/out/types/src/codegen/async/runtime.d.ts +2 -1
  11. package/out/types/src/codegen/async/state-machine.d.ts +18 -2
  12. package/out/types/src/codegen/functions/context.d.ts +5 -0
  13. package/out/types/src/codegen/parallelism/runtime.d.ts +2 -1
  14. package/out/types/src/codegen/utils/index.d.ts +2 -0
  15. package/out/types/src/target.d.ts +1 -0
  16. package/out/types/tsconfig.tsbuildinfo +1 -1
  17. package/package.json +1 -1
  18. package/std/cli/arg_parser.yo +365 -0
  19. package/std/collections/array_list.yo +108 -0
  20. package/std/collections/hash_map.yo +1 -1
  21. package/std/collections/hash_set.yo +7 -7
  22. package/std/collections/linked_list.yo +1 -1
  23. package/std/encoding/base64.yo +73 -0
  24. package/std/fs/file.yo +113 -6
  25. package/std/fs/types.yo +21 -0
  26. package/std/glob/glob.yo +206 -0
  27. package/std/http/http.yo +196 -0
  28. package/std/io/reader.yo +17 -0
  29. package/std/io/writer.yo +19 -0
  30. package/std/net/tcp.yo +1 -1
  31. package/std/prelude.yo +69 -0
  32. package/std/regex/compiler.yo +355 -0
  33. package/std/regex/flags.yo +104 -0
  34. package/std/regex/match.yo +83 -0
  35. package/std/regex/node.yo +283 -0
  36. package/std/regex/parser.yo +847 -0
  37. package/std/regex/regex.yo +714 -0
  38. package/std/regex/unicode.yo +365 -0
  39. package/std/regex/vm.yo +737 -0
  40. package/std/string/string.yo +398 -4
  41. package/std/sync/cond.yo +19 -19
  42. package/std/sync/mutex.yo +16 -16
  43. package/std/sys/bufio/buf_reader.yo +2 -2
  44. package/std/sys/future.yo +3 -3
  45. package/std/time/sleep.yo +18 -0
  46. package/std/toml/toml.yo +179 -0
  47. package/std/testing/assert.yo +0 -173
  48. package/std/time.yo +0 -13
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shd101wyy/yo",
3
3
  "displayName": "Yo",
4
- "version": "0.0.28",
4
+ "version": "0.0.30",
5
5
  "main": "./out/cjs/index.cjs",
6
6
  "module": "./out/esm/index.mjs",
7
7
  "types": "./out/types/src/index.d.ts",
@@ -0,0 +1,365 @@
1
+ open import "../collections/array_list";
2
+ open import "../string";
3
+
4
+ ArgKind :: enum(Flag, Opt, Positional);
5
+
6
+ ArgDef :: object(
7
+ _long_name : String,
8
+ _short_name : String,
9
+ _description : String,
10
+ _kind : ArgKind,
11
+ _default_value : String,
12
+ _required : bool
13
+ );
14
+
15
+ ParsedArgs :: object(
16
+ _set_flags : ArrayList(String),
17
+ _option_names : ArrayList(String),
18
+ _option_values : ArrayList(String),
19
+ _positionals : ArrayList(String),
20
+ _positional_names : ArrayList(String)
21
+ );
22
+
23
+ ArgParser :: object(
24
+ _name : String,
25
+ _description : String,
26
+ _args : ArrayList(ArgDef)
27
+ );
28
+
29
+ impl(ParsedArgs,
30
+ new : (fn() -> Self)(
31
+ Self(
32
+ _set_flags: ArrayList(String).new(),
33
+ _option_names: ArrayList(String).new(),
34
+ _option_values: ArrayList(String).new(),
35
+ _positionals: ArrayList(String).new(),
36
+ _positional_names: ArrayList(String).new()
37
+ )
38
+ ),
39
+
40
+ get_flag : (fn(self: Self, name: String) -> bool)(
41
+ self._set_flags.contains(name)
42
+ ),
43
+
44
+ _lookup : (fn(self: Self, names: ArrayList(String), values: ArrayList(String), name: String) -> Option(String))({
45
+ i := usize(0);
46
+ len := names.len();
47
+ (result : Option(String)) = .None;
48
+ while (i < len), (i = (i + usize(1))), {
49
+ match(names.get(i),
50
+ .Some(n) => {
51
+ cond(
52
+ (n == name) => {
53
+ result = values.get(i);
54
+ i = len;
55
+ },
56
+ true => ()
57
+ );
58
+ },
59
+ .None => ()
60
+ );
61
+ };
62
+ return result;
63
+ }),
64
+
65
+ get_option : (fn(self: Self, name: String) -> Option(String))(
66
+ self._lookup(self._option_names, self._option_values, name)
67
+ ),
68
+
69
+ get_positional : (fn(self: Self, name: String) -> Option(String))(
70
+ self._lookup(self._positional_names, self._positionals, name)
71
+ ),
72
+
73
+ get_positional_at : (fn(self: Self, index: usize) -> Option(String))(
74
+ self._positionals.get(index)
75
+ )
76
+ );
77
+
78
+ impl(ArgParser,
79
+ new : (fn(name: String, description: String) -> Self)(
80
+ Self(
81
+ _name: name,
82
+ _description: description,
83
+ _args: ArrayList(ArgDef).new()
84
+ )
85
+ ),
86
+
87
+ add_flag : (fn(self: Self, long_name: String, short_name: String, description: String) -> unit)({
88
+ self._args.push(ArgDef(
89
+ _long_name: long_name,
90
+ _short_name: short_name,
91
+ _description: description,
92
+ _kind: .Flag,
93
+ _default_value: ``,
94
+ _required: false
95
+ ));
96
+ }),
97
+
98
+ add_option : (fn(self: Self, long_name: String, short_name: String, description: String, default_value: String) -> unit)({
99
+ self._args.push(ArgDef(
100
+ _long_name: long_name,
101
+ _short_name: short_name,
102
+ _description: description,
103
+ _kind: .Opt,
104
+ _default_value: default_value,
105
+ _required: false
106
+ ));
107
+ }),
108
+
109
+ add_positional : (fn(self: Self, name: String, description: String) -> unit)({
110
+ self._args.push(ArgDef(
111
+ _long_name: name,
112
+ _short_name: ``,
113
+ _description: description,
114
+ _kind: .Positional,
115
+ _default_value: ``,
116
+ _required: true
117
+ ));
118
+ }),
119
+
120
+ _find_arg_index : (fn(self: Self, name: String) -> Option(usize))({
121
+ i := usize(0);
122
+ len := self._args.len();
123
+ (result : Option(usize)) = .None;
124
+ while (i < len), (i = (i + usize(1))), {
125
+ match(self._args.get(i),
126
+ .Some(arg_def) => {
127
+ cond(
128
+ ((arg_def._long_name == name) || (arg_def._short_name == name)) => {
129
+ result = .Some(i);
130
+ i = len;
131
+ },
132
+ true => ()
133
+ );
134
+ },
135
+ .None => ()
136
+ );
137
+ };
138
+ return result;
139
+ }),
140
+
141
+ help_text : (fn(self: Self) -> String)({
142
+ text := `Usage: ${self._name}\n${self._description}\n\n`;
143
+
144
+ has_positionals := false;
145
+ has_flags_or_options := false;
146
+ i := usize(0);
147
+ len := self._args.len();
148
+ while (i < len), (i = (i + usize(1))), {
149
+ match(self._args.get(i),
150
+ .Some(arg_def) => {
151
+ match(arg_def._kind,
152
+ .Flag => { has_flags_or_options = true; },
153
+ .Opt => { has_flags_or_options = true; },
154
+ .Positional => { has_positionals = true; }
155
+ );
156
+ },
157
+ .None => ()
158
+ );
159
+ };
160
+
161
+ cond(
162
+ has_positionals => {
163
+ text = text.concat(`Arguments:\n`);
164
+ j := usize(0);
165
+ while (j < len), (j = (j + usize(1))), {
166
+ match(self._args.get(j),
167
+ .Some(arg_def) => {
168
+ match(arg_def._kind,
169
+ .Positional => {
170
+ text = text.concat(` ${arg_def._long_name}\t${arg_def._description}\n`);
171
+ },
172
+ .Flag => (),
173
+ .Opt => ()
174
+ );
175
+ },
176
+ .None => ()
177
+ );
178
+ };
179
+ text = text.concat(`\n`);
180
+ },
181
+ true => ()
182
+ );
183
+
184
+ cond(
185
+ has_flags_or_options => {
186
+ text = text.concat(`Options:\n`);
187
+ k := usize(0);
188
+ while (k < len), (k = (k + usize(1))), {
189
+ match(self._args.get(k),
190
+ .Some(arg_def) => {
191
+ match(arg_def._kind,
192
+ .Flag => {
193
+ line := ` ${arg_def._long_name}`;
194
+ cond(
195
+ (!(arg_def._short_name.is_empty())) => {
196
+ line = line.concat(`, ${arg_def._short_name}`);
197
+ },
198
+ true => ()
199
+ );
200
+ line = line.concat(`\t${arg_def._description}\n`);
201
+ text = text.concat(line);
202
+ },
203
+ .Opt => {
204
+ line := ` ${arg_def._long_name}`;
205
+ cond(
206
+ (!(arg_def._short_name.is_empty())) => {
207
+ line = line.concat(`, ${arg_def._short_name}`);
208
+ },
209
+ true => ()
210
+ );
211
+ line = line.concat(` <value>\t${arg_def._description}`);
212
+ cond(
213
+ (!(arg_def._default_value.is_empty())) => {
214
+ line = line.concat(` (default: ${arg_def._default_value})`);
215
+ },
216
+ true => ()
217
+ );
218
+ line = line.concat(`\n`);
219
+ text = text.concat(line);
220
+ },
221
+ .Positional => ()
222
+ );
223
+ },
224
+ .None => ()
225
+ );
226
+ };
227
+ },
228
+ true => ()
229
+ );
230
+
231
+ text = text.concat(` --help, -h\tShow this help message\n`);
232
+ return text;
233
+ })
234
+ );
235
+
236
+ impl(ArgParser,
237
+ parse : (fn(self: Self, args: ArrayList(String)) -> Result(ParsedArgs, String))({
238
+ parsed := ParsedArgs.new();
239
+ arg_defs_len := self._args.len();
240
+
241
+ idx := usize(1);
242
+ args_len := args.len();
243
+ positional_idx := usize(0);
244
+ (err_msg : Option(String)) = .None;
245
+
246
+ while ((idx < args_len) && (err_msg.is_none())), {
247
+ match(args.get(idx),
248
+ .Some(current_arg) => {
249
+ cond(
250
+ ((current_arg == `--help`) || (current_arg == `-h`)) => {
251
+ err_msg = .Some(self.help_text());
252
+ },
253
+ current_arg.starts_with(`-`) => {
254
+ match(self._find_arg_index(current_arg),
255
+ .Some(arg_idx) => {
256
+ match(self._args.get(arg_idx),
257
+ .Some(def) => {
258
+ match(def._kind,
259
+ .Flag => {
260
+ parsed._set_flags.push(def._long_name);
261
+ },
262
+ .Opt => {
263
+ idx = (idx + usize(1));
264
+ cond(
265
+ (idx < args_len) => {
266
+ match(args.get(idx),
267
+ .Some(val) => {
268
+ parsed._option_names.push(def._long_name);
269
+ parsed._option_values.push(val);
270
+ },
271
+ .None => {
272
+ err_msg = .Some(`Missing value for option: ${def._long_name}`);
273
+ }
274
+ );
275
+ },
276
+ true => {
277
+ err_msg = .Some(`Missing value for option: ${def._long_name}`);
278
+ }
279
+ );
280
+ },
281
+ .Positional => ()
282
+ );
283
+ },
284
+ .None => ()
285
+ );
286
+ },
287
+ .None => {
288
+ err_msg = .Some(`Unknown argument: ${current_arg}`);
289
+ }
290
+ );
291
+ },
292
+ true => {
293
+ parsed._positionals.push(current_arg);
294
+ p_idx := usize(0);
295
+ p_count := usize(0);
296
+ while (p_idx < arg_defs_len), (p_idx = (p_idx + usize(1))), {
297
+ match(self._args.get(p_idx),
298
+ .Some(p_def) => {
299
+ match(p_def._kind,
300
+ .Positional => {
301
+ cond(
302
+ (p_count == positional_idx) => {
303
+ parsed._positional_names.push(p_def._long_name);
304
+ },
305
+ true => ()
306
+ );
307
+ p_count = (p_count + usize(1));
308
+ },
309
+ .Flag => (),
310
+ .Opt => ()
311
+ );
312
+ },
313
+ .None => ()
314
+ );
315
+ };
316
+ positional_idx = (positional_idx + usize(1));
317
+ }
318
+ );
319
+ },
320
+ .None => ()
321
+ );
322
+ idx = (idx + usize(1));
323
+ };
324
+
325
+ // Check for errors
326
+ match(err_msg,
327
+ .Some(msg) => {
328
+ return .Err(msg);
329
+ },
330
+ .None => ()
331
+ );
332
+
333
+ // Apply defaults for options not explicitly set
334
+ def_i := usize(0);
335
+ while (def_i < arg_defs_len), (def_i = (def_i + usize(1))), {
336
+ match(self._args.get(def_i),
337
+ .Some(def) => {
338
+ match(def._kind,
339
+ .Opt => {
340
+ cond(
341
+ ((!(parsed._option_names.contains(def._long_name))) && (!(def._default_value.is_empty()))) => {
342
+ parsed._option_names.push(def._long_name);
343
+ parsed._option_values.push(def._default_value);
344
+ },
345
+ true => ()
346
+ );
347
+ },
348
+ .Flag => (),
349
+ .Positional => ()
350
+ );
351
+ },
352
+ .None => ()
353
+ );
354
+ };
355
+
356
+ return .Ok(parsed);
357
+ })
358
+ );
359
+
360
+ export
361
+ ArgKind,
362
+ ArgDef,
363
+ ParsedArgs,
364
+ ArgParser
365
+ ;
@@ -509,6 +509,114 @@ impl(forall(T : Type), ArrayList(T),
509
509
  )
510
510
  );
511
511
 
512
+ impl(forall(T : Type), where(T <: Eq(T)), ArrayList(T),
513
+ /**
514
+ * Check if the list contains a value
515
+ */
516
+ contains : (fn(self: Self, value: T) -> bool)({
517
+ found := false;
518
+ match(self._ptr,
519
+ .Some(_ptr) => {
520
+ i := usize(0);
521
+ while(((i < self._length) && !(found)), i = (i + usize(1)), {
522
+ cond(
523
+ ((_ptr &+ i).* == value) => {
524
+ found = true;
525
+ },
526
+ true => ()
527
+ );
528
+ });
529
+ },
530
+ .None => ()
531
+ );
532
+ return found;
533
+ }),
534
+
535
+ /**
536
+ * Find the first index of a matching value
537
+ * Returns .Some(index) if found, .None otherwise
538
+ */
539
+ index_of : (fn(self: Self, value: T) -> Option(usize))({
540
+ (result : Option(usize)) = .None;
541
+ found := false;
542
+ match(self._ptr,
543
+ .Some(_ptr) => {
544
+ i := usize(0);
545
+ while(((i < self._length) && !(found)), i = (i + usize(1)), {
546
+ cond(
547
+ ((_ptr &+ i).* == value) => {
548
+ result = .Some(i);
549
+ found = true;
550
+ },
551
+ true => ()
552
+ );
553
+ });
554
+ },
555
+ .None => ()
556
+ );
557
+ return result;
558
+ })
559
+ );
560
+
561
+ impl(forall(T : Type), ArrayList(T),
562
+ /**
563
+ * Reverse elements in place
564
+ */
565
+ reverse : (fn(self: Self) -> unit)({
566
+ cond(
567
+ (self._length <= usize(1)) => (),
568
+ true =>
569
+ match(self._ptr,
570
+ .Some(_ptr) => {
571
+ i := usize(0);
572
+ j := (self._length - usize(1));
573
+ while((i < j), {i = (i + usize(1)); j = (j - usize(1));}, {
574
+ tmp := (_ptr &+ i).*;
575
+ (_ptr &+ i).* = (_ptr &+ j).*;
576
+ (_ptr &+ j).* = tmp;
577
+ });
578
+ },
579
+ .None => ()
580
+ )
581
+ );
582
+ })
583
+ );
584
+
585
+ impl(forall(T : Type), where(T <: Ord(T)), ArrayList(T),
586
+ /**
587
+ * Sort elements in ascending order using insertion sort
588
+ */
589
+ sort : (fn(self: Self) -> unit)({
590
+ cond(
591
+ (self._length <= usize(1)) => (),
592
+ true =>
593
+ match(self._ptr,
594
+ .Some(_ptr) => {
595
+ i := usize(1);
596
+ while((i < self._length), i = (i + usize(1)), {
597
+ key := (_ptr &+ i).*;
598
+ j := i;
599
+ shifting := cond(
600
+ (j > usize(0)) => ((_ptr &+ (j - usize(1))).* > key),
601
+ true => false
602
+ );
603
+ while(shifting, (), {
604
+ (_ptr &+ j).* = (_ptr &+ (j - usize(1))).*;
605
+ j = (j - usize(1));
606
+ shifting = cond(
607
+ (j > usize(0)) => ((_ptr &+ (j - usize(1))).* > key),
608
+ true => false
609
+ );
610
+ });
611
+ (_ptr &+ j).* = key;
612
+ });
613
+ },
614
+ .None => ()
615
+ )
616
+ );
617
+ })
618
+ );
619
+
512
620
  export
513
621
  ArrayList,
514
622
  ArrayListError,
@@ -427,7 +427,7 @@ impl(forall(K : Type, V : Type), where(K <: (Eq(K), Hash)), HashMap(K, V),
427
427
  /**
428
428
  * Check if a key exists in the map
429
429
  */
430
- has : (fn(self: Self, key: K) -> bool)(
430
+ contains_key : (fn(self: Self, key: K) -> bool)(
431
431
  {
432
432
  hash := key.hash();
433
433
  bucket_opt := Self._find_bucket(self, key, hash);
@@ -377,7 +377,7 @@ impl(forall(T : Type), where(T <: (Eq(T), Hash)), HashSet(T),
377
377
  /**
378
378
  * Check if an element exists in the set
379
379
  */
380
- has : (fn(self: Self, element: T) -> bool)(
380
+ contains : (fn(self: Self, element: T) -> bool)(
381
381
  {
382
382
  hash := element.hash();
383
383
  slot_opt := Self._find_slot(self, element, hash);
@@ -485,7 +485,7 @@ impl(forall(T : Type), where(T <: (Eq(T), Hash)), HashSet(T),
485
485
  cond(
486
486
  ((ctrl_byte != CTRL_EMPTY) && (ctrl_byte != CTRL_DELETED)) => {
487
487
  element := (data_ptr &+ i).*;
488
- contains_result := other.has(element);
488
+ contains_result := other.contains(element);
489
489
  cond(
490
490
  (contains_result == false) => {
491
491
  is_sub = false;
@@ -529,7 +529,7 @@ impl(forall(T : Type), where(T <: (Eq(T), Hash)), HashSet(T),
529
529
  cond(
530
530
  ((ctrl_byte != CTRL_EMPTY) && (ctrl_byte != CTRL_DELETED)) => {
531
531
  element := (data_ptr &+ i).*;
532
- contains_result := larger.has(element);
532
+ contains_result := larger.contains(element);
533
533
  cond(
534
534
  (contains_result == true) => {
535
535
  result = false;
@@ -626,7 +626,7 @@ impl(forall(T : Type), where(T <: (Eq(T), Hash)), HashSet(T),
626
626
  ((ctrl_byte != CTRL_EMPTY) && (ctrl_byte != CTRL_DELETED)) => {
627
627
  element := (data_ptr &+ i).*;
628
628
  cond(
629
- (larger.has(element)) => {
629
+ (larger.contains(element)) => {
630
630
  _ := result_set.add(element);
631
631
  },
632
632
  true => ()
@@ -660,7 +660,7 @@ impl(forall(T : Type), where(T <: (Eq(T), Hash)), HashSet(T),
660
660
  cond(
661
661
  ((ctrl_byte != CTRL_EMPTY) && (ctrl_byte != CTRL_DELETED)) => {
662
662
  element := (data_ptr &+ i).*;
663
- contains_result := other.has(element);
663
+ contains_result := other.contains(element);
664
664
  cond(
665
665
  (contains_result == false) => {
666
666
  _ := result_set.add(element);
@@ -696,7 +696,7 @@ impl(forall(T : Type), where(T <: (Eq(T), Hash)), HashSet(T),
696
696
  cond(
697
697
  ((ctrl_byte != CTRL_EMPTY) && (ctrl_byte != CTRL_DELETED)) => {
698
698
  element := (data_ptr &+ i).*;
699
- contains_result := other.has(element);
699
+ contains_result := other.contains(element);
700
700
  cond(
701
701
  (contains_result == false) => {
702
702
  _ := result_set.add(element);
@@ -716,7 +716,7 @@ impl(forall(T : Type), where(T <: (Eq(T), Hash)), HashSet(T),
716
716
  cond(
717
717
  ((ctrl_byte != CTRL_EMPTY) && (ctrl_byte != CTRL_DELETED)) => {
718
718
  element := (other_data_ptr &+ j).*;
719
- contains_result := self.has(element);
719
+ contains_result := self.contains(element);
720
720
  cond(
721
721
  (contains_result == false) => {
722
722
  _ := result_set.add(element);
@@ -368,7 +368,7 @@ impl(forall(T : Type), LinkedList(T),
368
368
  * Check if the list contains a value
369
369
  * O(n) time complexity
370
370
  */
371
- has : (fn(
371
+ contains : (fn(
372
372
  self: Self,
373
373
  value: T,
374
374
  where(T <: Eq(T))
@@ -127,3 +127,76 @@ base64_decode_url :: (fn(s: str, using(exn : Exception)) -> ArrayList(u8))(
127
127
  );
128
128
 
129
129
  export base64_decode, base64_decode_url;
130
+
131
+ // ============================================================================
132
+ // String-level convenience API
133
+ // ============================================================================
134
+
135
+ // Encode a String to standard base64.
136
+ base64_encode_string :: (fn(input: String) -> String)(
137
+ _encode_with(input.as_bytes(), _STD_ALPHA, true)
138
+ );
139
+
140
+ // Reverse lookup: base64 char to 0-63, or -1 for invalid.
141
+ _base64_index :: (fn(c: u8) -> i32)({
142
+ alpha := _STD_ALPHA;
143
+ i := usize(0);
144
+ while (i < usize(64)), (i = (i + usize(1))), {
145
+ cond(
146
+ (alpha.bytes(i) == c) => { return i32(i); },
147
+ true => ()
148
+ );
149
+ };
150
+ i32(-1)
151
+ });
152
+
153
+ // Decode a base64 String, ignoring whitespace. Returns Result.
154
+ base64_decode_string :: (fn(input: String) -> Result(String, String))({
155
+ raw := input.as_str();
156
+ cleaned := ArrayList(u8).new();
157
+ i := usize(0);
158
+ while (i < raw.len()), (i = (i + usize(1))), {
159
+ ch := raw.bytes(i);
160
+ cond(
161
+ (((ch == u8(32)) || (ch == u8(9))) || ((ch == u8(10)) || (ch == u8(13)))) => (),
162
+ true => { cleaned.push(ch); }
163
+ );
164
+ };
165
+ // Strip trailing padding
166
+ len := cleaned.len();
167
+ while ((len > usize(0)) && (cleaned.get((len - usize(1))).unwrap() == u8(61))), (len = (len - usize(1))), ();
168
+ out := ArrayList(u8).new();
169
+ j := usize(0);
170
+ while (j < len), (j = (j + usize(4))), {
171
+ v0 := _base64_index(cleaned.get(j).unwrap());
172
+ cond((v0 == i32(-1)) => { return .Err(`Invalid base64 input`); }, true => ());
173
+ v1 := cond(
174
+ ((j + usize(1)) < len) => {
175
+ tmp := _base64_index(cleaned.get((j + usize(1))).unwrap());
176
+ cond((tmp == i32(-1)) => { return .Err(`Invalid base64 input`); }, true => ());
177
+ tmp
178
+ },
179
+ true => i32(0)
180
+ );
181
+ out.push(u8(((v0 << i32(2)) | (v1 >> i32(4)))));
182
+ cond(
183
+ ((j + usize(2)) < len) => {
184
+ v2 := _base64_index(cleaned.get((j + usize(2))).unwrap());
185
+ cond((v2 == i32(-1)) => { return .Err(`Invalid base64 input`); }, true => ());
186
+ out.push(u8((((v1 & i32(15)) << i32(4)) | (v2 >> i32(2)))));
187
+ cond(
188
+ ((j + usize(3)) < len) => {
189
+ v3 := _base64_index(cleaned.get((j + usize(3))).unwrap());
190
+ cond((v3 == i32(-1)) => { return .Err(`Invalid base64 input`); }, true => ());
191
+ out.push(u8((((v2 & i32(3)) << i32(6)) | v3)));
192
+ },
193
+ true => ()
194
+ );
195
+ },
196
+ true => ()
197
+ );
198
+ };
199
+ .Ok(String.from_bytes(out))
200
+ });
201
+
202
+ export base64_encode_string, base64_decode_string;