@shd101wyy/yo 0.1.4 → 0.1.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.
Files changed (38) hide show
  1. package/README.md +7 -6
  2. package/out/cjs/index.cjs +546 -535
  3. package/out/cjs/yo-cli.cjs +636 -623
  4. package/out/esm/index.mjs +478 -467
  5. package/out/types/src/codegen/codegen-c.d.ts +2 -0
  6. package/out/types/src/codegen/functions/context.d.ts +1 -0
  7. package/out/types/src/codegen/functions/generation.d.ts +10 -0
  8. package/out/types/src/codegen/utils/index.d.ts +1 -0
  9. package/out/types/src/env.d.ts +12 -1
  10. package/out/types/src/evaluator/builtins/build.d.ts +1 -0
  11. package/out/types/src/evaluator/context.d.ts +1 -0
  12. package/out/types/src/evaluator/types/enum.d.ts +1 -1
  13. package/out/types/src/evaluator/types/synthesizer.d.ts +6 -1
  14. package/out/types/src/expr.d.ts +2 -0
  15. package/out/types/src/target.d.ts +1 -0
  16. package/out/types/src/types/compatibility.d.ts +1 -1
  17. package/out/types/src/types/creators.d.ts +2 -1
  18. package/out/types/src/types/definitions.d.ts +11 -0
  19. package/out/types/src/types/guards.d.ts +2 -1
  20. package/out/types/src/types/tags.d.ts +2 -1
  21. package/out/types/src/value.d.ts +2 -1
  22. package/out/types/tsconfig.tsbuildinfo +1 -1
  23. package/package.json +1 -1
  24. package/std/build.yo +2 -1
  25. package/std/collections/array_list.yo +133 -1
  26. package/std/encoding/html.yo +283 -0
  27. package/std/encoding/html_char_utils.yo +36 -0
  28. package/std/encoding/html_entities.yo +2262 -0
  29. package/std/encoding/punycode.yo +366 -0
  30. package/std/fmt/to_string.yo +5 -4
  31. package/std/glob/index.yo +2 -2
  32. package/std/libc/wctype.yo +55 -0
  33. package/std/path.yo +6 -6
  34. package/std/prelude.yo +193 -7
  35. package/std/regex/parser.yo +69 -4
  36. package/std/regex/vm.yo +18 -31
  37. package/std/string/string.yo +1388 -1337
  38. package/std/string/unicode.yo +242 -0
@@ -1,5 +1,6 @@
1
1
  { ArrayList } :: import "../collections/array_list.yo";
2
2
  { rune } :: import "./rune.yo";
3
+ { memcpy, memcmp, strlen } :: import "../libc/string.yo";
3
4
 
4
5
  StringError :: enum(
5
6
  InvalidUtf8,
@@ -12,18 +13,30 @@ StringError :: enum(
12
13
  * Similar to JavaScript String, Python str, and Rust String.
13
14
  * Strings are immutable - all operations return new strings.
14
15
  *
15
- * Internal storage uses ArrayList(u8) for UTF-8 bytes.
16
+ * Internal storage uses Option(ArrayList(u8)) for UTF-8 bytes.
17
+ * An empty string is represented as .None (zero allocation).
16
18
  */
17
19
  String :: newtype(
18
- _bytes: ArrayList(u8)
20
+ _bytes: Option(ArrayList(u8))
19
21
  );
20
22
 
21
23
  impl(String,
22
24
  /**
23
- * Create a new empty string
25
+ * Create a new empty string (zero allocation)
24
26
  */
25
27
  new : (fn() -> Self)(
26
- Self(_bytes: ArrayList(u8).new())
28
+ Self(_bytes: .None)
29
+ ),
30
+
31
+ /**
32
+ * Create a new empty string with pre-allocated capacity for the given number of bytes.
33
+ * The string starts empty but can hold `capacity` bytes without reallocating.
34
+ */
35
+ with_capacity : (fn(capacity: usize) -> Self)(
36
+ cond(
37
+ (capacity == usize(0)) => Self(_bytes: .None),
38
+ true => Self(_bytes: .Some(ArrayList(u8).with_capacity(capacity)))
39
+ )
27
40
  ),
28
41
 
29
42
  /**
@@ -31,7 +44,10 @@ impl(String,
31
44
  * No validation is performed - the caller must ensure bytes are valid UTF-8
32
45
  */
33
46
  from_bytes : (fn(bytes: ArrayList(u8)) -> Self)(
34
- Self(_bytes: bytes)
47
+ cond(
48
+ (bytes.len() == usize(0)) => Self(_bytes: .None),
49
+ true => Self(_bytes: .Some(bytes))
50
+ )
35
51
  ),
36
52
 
37
53
  /**
@@ -40,18 +56,13 @@ impl(String,
40
56
  * Example: String.from(slice) where slice is str
41
57
  */
42
58
  from : (fn(slice: str) -> Self)({
43
- // Create a new ArrayList and copy bytes from the slice
44
- bytes := ArrayList(u8).with_capacity(slice.len());
45
-
46
- i := usize(0);
47
- while ((i < slice.len())),
48
- (i = (i + usize(1))),
49
- {
50
- byte := slice.bytes(i);
51
- bytes.push(byte);
52
- };
53
-
54
- return Self(_bytes: bytes);
59
+ slen := slice.len();
60
+ if((slen == usize(0)), {
61
+ return Self(_bytes: .None);
62
+ });
63
+ bytes := ArrayList(u8).with_capacity(slen);
64
+ bytes.extend_from_ptr(slice.ptr(), slen);
65
+ return Self(_bytes: .Some(bytes));
55
66
  }),
56
67
 
57
68
  /**
@@ -62,49 +73,29 @@ impl(String,
62
73
  * Note: We manually search for the null terminator by iterating
63
74
  */
64
75
  from_cstr : (fn(cstr: *(u8)) -> Result(Self, StringError))({
65
- // Create a new ArrayList to store the bytes
66
- bytes := ArrayList(u8).new();
67
-
68
- // Iterate through the C string until we find the null terminator
69
- i := usize(0);
70
- // FIXME: This is causing infinite loop during compile-time evaluation.
71
- // We need to check if the loop body has runtime expr, then we shouldn't consider it as infinite loop.
72
- while {f := true; f}, (i = (i + usize(1))), {
73
- // Access byte at index i using pointer arithmetic/
74
- byte_ptr := (cstr &+ i);
75
- byte := byte_ptr.*;
76
-
77
- // Stop when we find the null terminator
78
- cond(
79
- (byte == u8(0)) => break,
80
- true => bytes.push(byte)
81
- );
82
- };
83
-
84
- return .Ok(Self(_bytes: bytes));
76
+ len := strlen((*(char))(cstr));
77
+ if((len == usize(0)), {
78
+ return .Ok(Self(_bytes: .None));
79
+ });
80
+ bytes := ArrayList(u8).with_capacity(len);
81
+ bytes.extend_from_ptr(cstr, len);
82
+ return .Ok(Self(_bytes: .Some(bytes)));
85
83
  }),
86
84
 
87
85
  to_cstr : (fn(self: Self) -> ArrayList(u8))({
88
- bytes_len := self._bytes.len();
89
- bytes_with_null := ArrayList(u8).with_capacity(bytes_len + usize(1));
90
-
91
- // Copy existing bytes
92
- i := usize(0);
93
- while (i < bytes_len),
94
- (i = (i + usize(1))),
95
- {
96
- byte_opt := self._bytes.get(i);
97
- match(byte_opt,
98
- .Some(byte) => {
99
- bytes_with_null.push(byte);
100
- },
86
+ (bytes_len : usize) = match(self._bytes,
87
+ .Some(b) => b.len(),
88
+ .None => usize(0)
89
+ );
90
+ bytes_with_null := ArrayList(u8).with_capacity((bytes_len + usize(1)));
91
+ match(self._bytes,
92
+ .Some(b) => match(b.ptr(),
93
+ .Some(src) => bytes_with_null.extend_from_ptr(src, bytes_len),
101
94
  .None => ()
102
- );
103
- };
104
-
105
- // Add null terminator
95
+ ),
96
+ .None => ()
97
+ );
106
98
  bytes_with_null.push(u8(0));
107
-
108
99
  return bytes_with_null;
109
100
  }),
110
101
 
@@ -113,44 +104,55 @@ impl(String,
113
104
  * For "你好世界", this returns 4
114
105
  */
115
106
  len : (fn(self: Self) -> usize)({
116
- count := usize(0);
117
- byte_index := usize(0);
118
- total_bytes := self._bytes.len();
119
-
120
- while ((byte_index < total_bytes)),
121
- (byte_index = (byte_index + usize(1))),
122
- {
123
- byte_opt := self._bytes.get(byte_index);
124
- match(byte_opt,
125
- .Some(byte) => {
126
- // Count UTF-8 character start bytes (not continuation bytes)
127
- // Continuation bytes have pattern 10xxxxxx (0x80-0xBF)
128
- cond(
129
- ((byte < u8(0x80)) || (byte >= u8(0xC0))) => {
130
- count = (count + usize(1));
107
+ (inner : Option(ArrayList(u8))) = self._bytes;
108
+ match(inner,
109
+ .None => { return usize(0); },
110
+ .Some(al) => {
111
+ count := usize(0);
112
+ byte_index := usize(0);
113
+ total_bytes := al.len();
114
+
115
+ while ((byte_index < total_bytes)),
116
+ (byte_index = (byte_index + usize(1))),
117
+ {
118
+ byte_opt := al.get(byte_index);
119
+ match(byte_opt,
120
+ .Some(byte) => {
121
+ cond(
122
+ ((byte < u8(0x80)) || (byte >= u8(0xC0))) => {
123
+ count = (count + usize(1));
124
+ },
125
+ true => ()
126
+ );
131
127
  },
132
- true => ()
128
+ .None => ()
133
129
  );
134
- },
135
- .None => ()
136
- );
137
- };
138
-
139
- return count;
130
+ };
131
+
132
+ return count;
133
+ }
134
+ )
140
135
  }),
141
136
 
142
137
  /**
143
138
  * Check if the string is empty
144
139
  */
145
140
  is_empty : (fn(self: Self) -> bool)(
146
- (self._bytes.len() == usize(0))
141
+ match(self._bytes,
142
+ .None => true,
143
+ .Some(al) => (al.len() == usize(0))
144
+ )
147
145
  ),
148
146
 
149
147
  /**
150
148
  * Get a reference to the internal byte array
149
+ * Returns an empty ArrayList if the string is empty
151
150
  */
152
151
  as_bytes : (fn(self: Self) -> ArrayList(u8))(
153
- self._bytes
152
+ match(self._bytes,
153
+ .None => ArrayList(u8).new(),
154
+ .Some(al) => al
155
+ )
154
156
  ),
155
157
 
156
158
  // as_bytes : (fn(self: Self) -> ArrayList(u8))({
@@ -162,9 +164,12 @@ impl(String,
162
164
  * Returns a fat pointer (pointer + length) without copying
163
165
  */
164
166
  as_str : (fn(self: Self) -> str)(
165
- match(self._bytes._ptr,
166
- .Some(p) => str.from_raw_parts(p, self._bytes._length),
167
- .None => str.from_raw_parts(*(u8)(""), usize(0))
167
+ match(self._bytes,
168
+ .None => str.from_raw_parts(*(u8)(""), usize(0)),
169
+ .Some(al) => match(al._ptr,
170
+ .Some(p) => str.from_raw_parts(p, al._length),
171
+ .None => str.from_raw_parts(*(u8)(""), usize(0))
172
+ )
168
173
  )
169
174
  ),
170
175
 
@@ -173,70 +178,70 @@ impl(String,
173
178
  * Internal helper method
174
179
  */
175
180
  _decode_rune_at : (fn(self: Self, byte_index: usize) -> Option(rune))({
176
- first_byte_opt := self._bytes.get(byte_index);
177
- match(first_byte_opt,
178
- .Some(first_byte) => {
179
- // Determine how many bytes this UTF-8 character uses
180
- (res : Option(rune)) = cond(
181
- // 1-byte character: 0xxxxxxx (ASCII)
182
- (first_byte < u8(0x80)) => {
183
- codepoint := u32(first_byte);
184
- rune.from_u32(codepoint)
185
- },
186
- // 2-byte character: 110xxxxx 10xxxxxx
187
- ((first_byte >= u8(0xC0)) && (first_byte < u8(0xE0))) => {
188
- second_opt := self._bytes.get((byte_index + usize(1)));
189
- match(second_opt,
190
- .Some(second) => {
191
- codepoint := (((u32(first_byte) & u32(0x1F)) << u32(6)) | (u32(second) & u32(0x3F)));
181
+ (al : Option(ArrayList(u8))) = self._bytes;
182
+ match(al,
183
+ .None => { return .None; },
184
+ .Some(bytes) => {
185
+ first_byte_opt := bytes.get(byte_index);
186
+ match(first_byte_opt,
187
+ .Some(first_byte) => {
188
+ (res : Option(rune)) = cond(
189
+ (first_byte < u8(0x80)) => {
190
+ codepoint := u32(first_byte);
192
191
  rune.from_u32(codepoint)
193
192
  },
194
- .None => .None
195
- )
196
- },
197
- // 3-byte character: 1110xxxx 10xxxxxx 10xxxxxx
198
- ((first_byte >= u8(0xE0)) && (first_byte < u8(0xF0))) => {
199
- second_opt := self._bytes.get((byte_index + usize(1)));
200
- third_opt := self._bytes.get((byte_index + usize(2)));
201
- match(second_opt,
202
- .Some(second) =>
203
- match(third_opt,
204
- .Some(third) => {
205
- codepoint := ((((u32(first_byte) & u32(0x0F)) << u32(12)) | ((u32(second) & u32(0x3F)) << u32(6))) | (u32(third) & u32(0x3F)));
193
+ ((first_byte >= u8(0xC0)) && (first_byte < u8(0xE0))) => {
194
+ second_opt := bytes.get((byte_index + usize(1)));
195
+ match(second_opt,
196
+ .Some(second) => {
197
+ codepoint := (((u32(first_byte) & u32(0x1F)) << u32(6)) | (u32(second) & u32(0x3F)));
206
198
  rune.from_u32(codepoint)
207
199
  },
208
200
  .None => .None
209
- ),
210
- .None => .None
211
- )
212
- },
213
- // 4-byte character: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
214
- ((first_byte >= u8(0xF0)) && (first_byte < u8(0xF8))) => {
215
- second_opt := self._bytes.get((byte_index + usize(1)));
216
- third_opt := self._bytes.get((byte_index + usize(2)));
217
- fourth_opt := self._bytes.get((byte_index + usize(3)));
218
- match(second_opt,
219
- .Some(second) =>
220
- match(third_opt,
221
- .Some(third) =>
222
- match(fourth_opt,
223
- .Some(fourth) => {
224
- codepoint := (((((u32(first_byte) & u32(0x07)) << u32(18)) | ((u32(second) & u32(0x3F)) << u32(12))) | ((u32(third) & u32(0x3F)) << u32(6))) | (u32(fourth) & u32(0x3F)));
201
+ )
202
+ },
203
+ ((first_byte >= u8(0xE0)) && (first_byte < u8(0xF0))) => {
204
+ second_opt := bytes.get((byte_index + usize(1)));
205
+ third_opt := bytes.get((byte_index + usize(2)));
206
+ match(second_opt,
207
+ .Some(second) =>
208
+ match(third_opt,
209
+ .Some(third) => {
210
+ codepoint := ((((u32(first_byte) & u32(0x0F)) << u32(12)) | ((u32(second) & u32(0x3F)) << u32(6))) | (u32(third) & u32(0x3F)));
225
211
  rune.from_u32(codepoint)
226
212
  },
227
213
  .None => .None
228
214
  ),
229
215
  .None => .None
230
- ),
231
- .None => .None
232
- )
216
+ )
217
+ },
218
+ ((first_byte >= u8(0xF0)) && (first_byte < u8(0xF8))) => {
219
+ second_opt := bytes.get((byte_index + usize(1)));
220
+ third_opt := bytes.get((byte_index + usize(2)));
221
+ fourth_opt := bytes.get((byte_index + usize(3)));
222
+ match(second_opt,
223
+ .Some(second) =>
224
+ match(third_opt,
225
+ .Some(third) =>
226
+ match(fourth_opt,
227
+ .Some(fourth) => {
228
+ codepoint := (((((u32(first_byte) & u32(0x07)) << u32(18)) | ((u32(second) & u32(0x3F)) << u32(12))) | ((u32(third) & u32(0x3F)) << u32(6))) | (u32(fourth) & u32(0x3F)));
229
+ rune.from_u32(codepoint)
230
+ },
231
+ .None => .None
232
+ ),
233
+ .None => .None
234
+ ),
235
+ .None => .None
236
+ )
237
+ },
238
+ true => .None
239
+ );
240
+ return res;
233
241
  },
234
- // Invalid UTF-8 start byte
235
- true => .None
236
- );
237
- return res;
238
- },
239
- .None => .None
242
+ .None => .None
243
+ )
244
+ }
240
245
  )
241
246
  }),
242
247
 
@@ -246,135 +251,196 @@ impl(String,
246
251
  * For "你好世界", at(0) returns '你', at(1) returns '好', etc.
247
252
  */
248
253
  at : (fn(self: Self, index: usize) -> Option(rune))({
249
- char_count := usize(0);
250
- byte_index := usize(0);
251
- total_bytes := self._bytes.len();
252
-
253
- // Find the byte position of the character at the given index
254
- while ((byte_index < total_bytes)),
255
- (byte_index = (byte_index + usize(1))),
256
- {
257
- byte_opt := self._bytes.get(byte_index);
258
- match(byte_opt,
259
- .Some(byte) => {
260
- // Check if this is a UTF-8 character start byte
261
- is_start := ((byte < u8(0x80)) || (byte >= u8(0xC0)));
262
- cond(
263
- is_start => {
264
- // Found a character start byte
254
+ match(self._bytes,
255
+ .None => { return .None; },
256
+ .Some(al) => {
257
+ char_count := usize(0);
258
+ byte_index := usize(0);
259
+ total_bytes := al.len();
260
+
261
+ while ((byte_index < total_bytes)),
262
+ (byte_index = (byte_index + usize(1))),
263
+ {
264
+ byte_opt := al.get(byte_index);
265
+ match(byte_opt,
266
+ .Some(byte) => {
267
+ is_start := ((byte < u8(0x80)) || (byte >= u8(0xC0)));
265
268
  cond(
266
- (char_count == index) => {
267
- // This is the character we want, decode it
268
- return Self._decode_rune_at(self, byte_index);
269
+ is_start => {
270
+ cond(
271
+ (char_count == index) => {
272
+ return Self._decode_rune_at(self, byte_index);
273
+ },
274
+ true => {
275
+ char_count = (char_count + usize(1));
276
+ }
277
+ );
269
278
  },
270
- true => {
271
- // Not the right character yet, keep counting
272
- char_count = (char_count + usize(1));
273
- }
279
+ true => ()
274
280
  );
275
281
  },
276
- true => ()
282
+ .None => ()
277
283
  );
278
- },
279
- .None => ()
280
- );
281
- };
282
-
283
- // Index out of bounds
284
- return .None;
284
+ };
285
+
286
+ return .None;
287
+ }
288
+ )
285
289
  }),
286
290
 
287
291
  /**
288
292
  * Concatenate two strings (like JavaScript +)
289
293
  */
290
294
  concat : (fn(self: Self, other: Self) -> Self)({
291
- self_len := self._bytes.len();
292
- other_len := other._bytes.len();
295
+ (self_len : usize) = match(self._bytes, .Some(b) => b.len(), .None => usize(0));
296
+ (other_len : usize) = match(other._bytes, .Some(b) => b.len(), .None => usize(0));
297
+ if(((self_len == usize(0)) && (other_len == usize(0))), {
298
+ return Self(_bytes: .None);
299
+ });
293
300
  new_bytes := ArrayList(u8).with_capacity((self_len + other_len));
294
301
 
295
- // Copy bytes from self
296
- i := usize(0);
297
- while ((i < self_len)),
298
- (i = (i + usize(1))),
299
- {
300
- byte_opt := self._bytes.get(i);
301
- match(byte_opt,
302
- .Some(byte) => { new_bytes.push(byte); },
303
- .None => { panic("String.concat: failed to get byte from self"); }
304
- );
305
- };
302
+ match(self._bytes,
303
+ .Some(b) => match(b.ptr(),
304
+ .Some(p) => new_bytes.extend_from_ptr(p, self_len),
305
+ .None => ()
306
+ ),
307
+ .None => ()
308
+ );
306
309
 
307
- // Copy bytes from other
308
- j := usize(0);
309
- while ((j < other_len)),
310
- (j = (j + usize(1))),
311
- {
312
- byte_opt := other._bytes.get(j);
313
- match(byte_opt,
314
- .Some(byte) => { new_bytes.push(byte); },
315
- .None => { panic("String.concat: failed to get byte from other"); }
316
- );
317
- };
310
+ match(other._bytes,
311
+ .Some(b) => match(b.ptr(),
312
+ .Some(p) => new_bytes.extend_from_ptr(p, other_len),
313
+ .None => ()
314
+ ),
315
+ .None => ()
316
+ );
318
317
 
319
- return Self(_bytes: new_bytes);
318
+ return Self(_bytes: .Some(new_bytes));
319
+ }),
320
+
321
+ // Append another String to this String in-place (mutates self)
322
+ push_string : (fn(self: *(Self), other: Self) -> unit)({
323
+ (olen : usize) = match(other._bytes, .Some(b) => b.len(), .None => usize(0));
324
+ if((olen > usize(0)), {
325
+ match(other._bytes,
326
+ .Some(ob) => match(ob.ptr(),
327
+ .Some(p) => {
328
+ match(self.*._bytes,
329
+ .None => {
330
+ (new_al : ArrayList(u8)) = ArrayList(u8).with_capacity(olen);
331
+ new_al.extend_from_ptr(p, olen);
332
+ self.*._bytes = .Some(new_al);
333
+ },
334
+ .Some(al) => {
335
+ al.extend_from_ptr(p, olen);
336
+ }
337
+ );
338
+ },
339
+ .None => ()
340
+ ),
341
+ .None => ()
342
+ );
343
+ });
344
+ }),
345
+
346
+ push_str : (fn(self: *(Self), s: str) -> unit)({
347
+ (slen : usize) = s.len();
348
+ if((slen > usize(0)), {
349
+ match(self.*._bytes,
350
+ .None => {
351
+ (new_al : ArrayList(u8)) = ArrayList(u8).with_capacity(slen);
352
+ new_al.extend_from_ptr(s.ptr(), slen);
353
+ self.*._bytes = .Some(new_al);
354
+ },
355
+ .Some(al) => {
356
+ al.extend_from_ptr(s.ptr(), slen);
357
+ }
358
+ );
359
+ });
360
+ }),
361
+
362
+ push_byte : (fn(self: *(Self), b: u8) -> unit)({
363
+ match(self.*._bytes,
364
+ .None => {
365
+ (new_al : ArrayList(u8)) = ArrayList(u8).with_capacity(usize(8));
366
+ new_al.push(b);
367
+ self.*._bytes = .Some(new_al);
368
+ },
369
+ .Some(al) => {
370
+ al.push(b);
371
+ }
372
+ );
373
+ }),
374
+
375
+ reserve : (fn(self: *(Self), additional: usize) -> unit)({
376
+ match(self.*._bytes,
377
+ .None => {
378
+ self.*._bytes = .Some(ArrayList(u8).with_capacity(additional));
379
+ },
380
+ .Some(al) => {
381
+ (current_len : usize) = al.len();
382
+ al.ensure_total_capacity((current_len + additional));
383
+ }
384
+ );
320
385
  }),
321
386
 
387
+ // Get the number of bytes in the string (not Unicode characters)
388
+ bytes_len : (fn(self: Self) -> usize)(
389
+ match(self._bytes, .Some(b) => b.len(), .None => usize(0))
390
+ ),
391
+
322
392
  /**
323
393
  * Extract a substring from start to end character indices (like JavaScript substring)
324
394
  * Returns a new string containing characters from start (inclusive) to end (exclusive)
325
395
  * If end is greater than length, it will substring to the end of the string
326
396
  */
327
397
  substring : (fn(self: Self, start: usize, end: usize) -> Self)({
328
- total_bytes := self._bytes.len();
329
- new_bytes := ArrayList(u8).new();
330
-
331
- char_index := usize(0);
332
- byte_index := usize(0);
333
-
334
- while (byte_index < total_bytes),
335
- (byte_index = (byte_index + usize(1))),
336
- {
337
- byte_opt := self._bytes.get(byte_index);
338
- match(byte_opt,
339
- .Some(byte) => {
340
- is_start := ((byte < u8(0x80)) || (byte >= u8(0xC0)));
341
- cond(
342
- is_start => {
343
- cond(
344
- (char_index >= end) => break,
345
- ((char_index >= start) && (char_index < end)) => {
346
- new_bytes.push(byte);
347
- byte_len := cond(
348
- (byte < u8(0x80)) => usize(1),
349
- ((byte >= u8(0xC0)) && (byte < u8(0xE0))) => usize(2),
350
- ((byte >= u8(0xE0)) && (byte < u8(0xF0))) => usize(3),
351
- ((byte >= u8(0xF0)) && (byte < u8(0xF8))) => usize(4),
352
- true => usize(1)
353
- );
354
- k := usize(1);
355
- while ((k < byte_len)),
356
- (k = (k + usize(1))),
357
- {
358
- next_byte_opt := self._bytes.get((byte_index + k));
359
- match(next_byte_opt,
360
- .Some(next_byte) => { new_bytes.push(next_byte); },
361
- .None => ()
362
- );
363
- };
364
- byte_index = ((byte_index + byte_len) - usize(1));
365
- },
366
- true => ()
367
- );
368
- char_index = (char_index + usize(1));
369
- },
370
- true => ()
398
+ match(self._bytes,
399
+ .None => { return Self(_bytes: .None); },
400
+ .Some(al) => {
401
+ total_bytes := al.len();
402
+
403
+ if((start >= end), {
404
+ return Self(_bytes: .None);
405
+ });
406
+
407
+ (char_index : usize) = usize(0);
408
+ (byte_index : usize) = usize(0);
409
+ (start_byte : usize) = total_bytes;
410
+ (end_byte : usize) = total_bytes;
411
+
412
+ while (byte_index < total_bytes), {
413
+ if((char_index == start), { start_byte = byte_index; });
414
+ if((char_index == end), {
415
+ end_byte = byte_index;
416
+ break;
417
+ });
418
+ (b : u8) = al.get_unchecked(byte_index);
419
+ (byte_len : usize) = cond(
420
+ (b < u8(0x80)) => usize(1),
421
+ (b < u8(0xE0)) => usize(2),
422
+ (b < u8(0xF0)) => usize(3),
423
+ true => usize(4)
371
424
  );
372
- },
373
- .None => ()
374
- );
375
- };
376
-
377
- return Self(_bytes: new_bytes);
425
+ byte_index = (byte_index + byte_len);
426
+ char_index = (char_index + usize(1));
427
+ };
428
+ if((char_index == start), { start_byte = byte_index; });
429
+ if((char_index == end), { end_byte = byte_index; });
430
+
431
+ if((start_byte >= end_byte), {
432
+ return Self(_bytes: .None);
433
+ });
434
+
435
+ (count : usize) = (end_byte - start_byte);
436
+ new_bytes := ArrayList(u8).with_capacity(count);
437
+ match(al.ptr(),
438
+ .Some(src_p) => new_bytes.extend_from_ptr((src_p &+ start_byte), count),
439
+ .None => ()
440
+ );
441
+ Self(_bytes: .Some(new_bytes))
442
+ }
443
+ )
378
444
  }),
379
445
 
380
446
  /**
@@ -386,92 +452,97 @@ impl(String,
386
452
  cond(
387
453
  substr.is_empty() => .Some(from_index),
388
454
  true => {
389
- self_bytes := self._bytes.len();
390
- sub_bytes := substr._bytes.len();
455
+ (self_bytes : usize) = match(self._bytes, .Some(b) => b.len(), .None => usize(0));
456
+ (sub_bytes : usize) = match(substr._bytes, .Some(b) => b.len(), .None => usize(0));
391
457
 
392
458
  cond(
393
459
  (sub_bytes > self_bytes) => .None,
394
- true => {
395
- char_index := usize(0);
396
- byte_index := usize(0);
397
-
398
- // Skip to from_index character position
399
- while (((byte_index < self_bytes) && (char_index < from_index))),
400
- (byte_index = (byte_index + usize(1))),
401
- {
402
- first_byte_opt := self._bytes.get(byte_index);
403
- match(first_byte_opt,
404
- .Some(first_byte) => {
405
- is_start := ((first_byte < u8(0x80)) || (first_byte >= u8(0xC0)));
406
- cond(
407
- is_start => {
408
- char_index = (char_index + usize(1));
460
+ true => match(self._bytes,
461
+ .None => .None,
462
+ .Some(self_al) => match(substr._bytes,
463
+ .None => .None,
464
+ .Some(sub_al) => {
465
+ char_index := usize(0);
466
+ byte_index := usize(0);
467
+
468
+ while (((byte_index < self_bytes) && (char_index < from_index))),
469
+ (byte_index = (byte_index + usize(1))),
470
+ {
471
+ first_byte_opt := self_al.get(byte_index);
472
+ match(first_byte_opt,
473
+ .Some(first_byte) => {
474
+ is_start := ((first_byte < u8(0x80)) || (first_byte >= u8(0xC0)));
475
+ cond(
476
+ is_start => {
477
+ char_index = (char_index + usize(1));
478
+ },
479
+ true => ()
480
+ );
409
481
  },
410
- true => ()
482
+ .None => ()
411
483
  );
412
- },
413
- .None => ()
414
- );
415
- };
416
-
417
- while ((byte_index <= (self_bytes - sub_bytes))),
418
- (byte_index = (byte_index + usize(1))),
419
- {
420
- matches := true;
421
- j := usize(0);
422
- while ((j < sub_bytes)),
423
- (j = (j + usize(1))),
424
- {
425
- self_byte_opt := self._bytes.get((byte_index + j));
426
- sub_byte_opt := substr._bytes.get(j);
427
- match(self_byte_opt,
428
- .Some(self_byte) =>
429
- match(sub_byte_opt,
430
- .Some(sub_byte) => {
431
- cond(
432
- (self_byte != sub_byte) => {
484
+ };
485
+
486
+ while ((byte_index <= (self_bytes - sub_bytes))),
487
+ (byte_index = (byte_index + usize(1))),
488
+ {
489
+ matches := true;
490
+ j := usize(0);
491
+ while ((j < sub_bytes)),
492
+ (j = (j + usize(1))),
493
+ {
494
+ self_byte_opt := self_al.get((byte_index + j));
495
+ sub_byte_opt := sub_al.get(j);
496
+ match(self_byte_opt,
497
+ .Some(self_byte) =>
498
+ match(sub_byte_opt,
499
+ .Some(sub_byte) => {
500
+ cond(
501
+ (self_byte != sub_byte) => {
502
+ matches = false;
503
+ break;
504
+ },
505
+ true => ()
506
+ );
507
+ },
508
+ .None => {
433
509
  matches = false;
434
510
  break;
435
- },
436
- true => ()
437
- );
438
- },
511
+ }
512
+ ),
439
513
  .None => {
440
514
  matches = false;
441
515
  break;
442
516
  }
443
- ),
444
- .None => {
445
- matches = false;
446
- break;
447
- }
448
- );
449
- };
450
-
451
- cond(
452
- matches => {
453
- return .Some(char_index);
454
- },
455
- true => ()
456
- );
457
-
458
- first_byte_opt := self._bytes.get(byte_index);
459
- match(first_byte_opt,
460
- .Some(first_byte) => {
461
- is_start := ((first_byte < u8(0x80)) || (first_byte >= u8(0xC0)));
517
+ );
518
+ };
519
+
462
520
  cond(
463
- is_start => {
464
- char_index = (char_index + usize(1));
521
+ matches => {
522
+ return .Some(char_index);
465
523
  },
466
524
  true => ()
467
525
  );
468
- },
469
- .None => ()
470
- );
471
- };
472
-
473
- return .None;
474
- }
526
+
527
+ first_byte_opt := self_al.get(byte_index);
528
+ match(first_byte_opt,
529
+ .Some(first_byte) => {
530
+ is_start := ((first_byte < u8(0x80)) || (first_byte >= u8(0xC0)));
531
+ cond(
532
+ is_start => {
533
+ char_index = (char_index + usize(1));
534
+ },
535
+ true => ()
536
+ );
537
+ },
538
+ .None => ()
539
+ );
540
+ };
541
+
542
+ return .None;
543
+ }
544
+ )
545
+ )
475
546
  )
476
547
  }
477
548
  )
@@ -510,75 +581,93 @@ impl(String,
510
581
  result.push(new());
511
582
  return result;
512
583
  },
513
- true => {
514
- self_bytes := self._bytes.len();
515
- sep_bytes := separator._bytes.len();
516
-
517
- current_bytes := ArrayList(u8).new();
518
- byte_index := usize(0);
519
-
520
- while ((byte_index < self_bytes)),
521
- (byte_index = (byte_index + usize(1))),
522
- {
523
- matches := true;
524
- cond(
525
- ((byte_index + sep_bytes) <= self_bytes) => {
526
- j := usize(0);
527
- while ((j < sep_bytes)),
528
- (j = (j + usize(1))),
529
- {
530
- self_byte_opt := self._bytes.get((byte_index + j));
531
- sep_byte_opt := separator._bytes.get(j);
532
- match(self_byte_opt,
533
- .Some(self_byte) =>
534
- match(sep_byte_opt,
535
- .Some(sep_byte) => {
536
- cond(
537
- (self_byte != sep_byte) => {
584
+ true => match(self._bytes,
585
+ .None => {
586
+ result.push(new());
587
+ return result;
588
+ },
589
+ .Some(self_al) => match(separator._bytes,
590
+ .None => {
591
+ result.push(self);
592
+ return result;
593
+ },
594
+ .Some(sep_al) => {
595
+ self_bytes := self_al.len();
596
+ sep_bytes := sep_al.len();
597
+
598
+ current_bytes := ArrayList(u8).new();
599
+ byte_index := usize(0);
600
+
601
+ while ((byte_index < self_bytes)),
602
+ (byte_index = (byte_index + usize(1))),
603
+ {
604
+ matches := true;
605
+ cond(
606
+ ((byte_index + sep_bytes) <= self_bytes) => {
607
+ j := usize(0);
608
+ while ((j < sep_bytes)),
609
+ (j = (j + usize(1))),
610
+ {
611
+ self_byte_opt := self_al.get((byte_index + j));
612
+ sep_byte_opt := sep_al.get(j);
613
+ match(self_byte_opt,
614
+ .Some(self_byte) =>
615
+ match(sep_byte_opt,
616
+ .Some(sep_byte) => {
617
+ cond(
618
+ (self_byte != sep_byte) => {
619
+ matches = false;
620
+ break;
621
+ },
622
+ true => ()
623
+ );
624
+ },
625
+ .None => {
538
626
  matches = false;
539
627
  break;
540
- },
541
- true => ()
542
- );
543
- },
628
+ }
629
+ ),
544
630
  .None => {
545
631
  matches = false;
546
632
  break;
547
633
  }
548
- ),
549
- .None => {
550
- matches = false;
551
- break;
552
- }
553
- );
554
- };
555
- },
556
- true => {
557
- matches = false;
558
- }
559
- );
560
-
561
- cond(
562
- matches => {
563
- result.push(Self(_bytes: current_bytes));
564
- current_bytes = ArrayList(u8).new();
565
- byte_index = ((byte_index + sep_bytes) - usize(1));
566
- },
567
- true => {
568
- byte_opt := self._bytes.get(byte_index);
569
- match(byte_opt,
570
- .Some(byte) => {
571
- current_bytes.push(byte);
634
+ );
635
+ };
572
636
  },
573
- .None => ()
637
+ true => {
638
+ matches = false;
639
+ }
574
640
  );
575
- }
576
- );
577
- };
578
-
579
- result.push(Self(_bytes: current_bytes));
580
- return result;
581
- }
641
+
642
+ cond(
643
+ matches => {
644
+ cond(
645
+ (current_bytes.len() == usize(0)) => result.push(Self(_bytes: .None)),
646
+ true => result.push(Self(_bytes: .Some(current_bytes)))
647
+ );
648
+ current_bytes = ArrayList(u8).new();
649
+ byte_index = ((byte_index + sep_bytes) - usize(1));
650
+ },
651
+ true => {
652
+ byte_opt := self_al.get(byte_index);
653
+ match(byte_opt,
654
+ .Some(byte) => {
655
+ current_bytes.push(byte);
656
+ },
657
+ .None => ()
658
+ );
659
+ }
660
+ );
661
+ };
662
+
663
+ cond(
664
+ (current_bytes.len() == usize(0)) => result.push(Self(_bytes: .None)),
665
+ true => result.push(Self(_bytes: .Some(current_bytes)))
666
+ );
667
+ return result;
668
+ }
669
+ )
670
+ )
582
671
  )
583
672
  }),
584
673
 
@@ -590,110 +679,113 @@ impl(String,
590
679
  last_index_of : (fn(self: Self, substr: Self, (from_index : usize) ?= usize.MAX) -> Option(usize))(
591
680
  cond(
592
681
  substr.is_empty() => .Some(self.len()),
593
- true => {
594
- self_bytes := self._bytes.len();
595
- sub_bytes := substr._bytes.len();
596
-
597
- cond(
598
- (sub_bytes > self_bytes) => .None,
599
- true => {
600
- // Build a mapping of byte_index -> char_index for character start bytes
601
- char_positions := ArrayList(usize).new();
602
- byte_positions := ArrayList(usize).new();
682
+ true => match(self._bytes,
683
+ .None => .None,
684
+ .Some(self_al) => match(substr._bytes,
685
+ .None => .None,
686
+ .Some(sub_al) => {
687
+ self_bytes := self_al.len();
688
+ sub_bytes := sub_al.len();
603
689
 
604
- byte_idx := usize(0);
605
- char_idx := usize(0);
606
- while ((byte_idx < self_bytes)),
607
- (byte_idx = (byte_idx + usize(1))),
608
- {
609
- byte_opt := self._bytes.get(byte_idx);
610
- match(byte_opt,
611
- .Some(byte) => {
612
- is_start := ((byte < u8(0x80)) || (byte >= u8(0xC0)));
613
- cond(
614
- is_start => {
615
- char_positions.push(char_idx);
616
- byte_positions.push(byte_idx);
617
- char_idx = (char_idx + usize(1));
690
+ cond(
691
+ (sub_bytes > self_bytes) => .None,
692
+ true => {
693
+ char_positions := ArrayList(usize).new();
694
+ byte_positions := ArrayList(usize).new();
695
+
696
+ byte_idx := usize(0);
697
+ char_idx := usize(0);
698
+ while ((byte_idx < self_bytes)),
699
+ (byte_idx = (byte_idx + usize(1))),
700
+ {
701
+ byte_opt := self_al.get(byte_idx);
702
+ match(byte_opt,
703
+ .Some(byte) => {
704
+ is_start := ((byte < u8(0x80)) || (byte >= u8(0xC0)));
705
+ cond(
706
+ is_start => {
707
+ char_positions.push(char_idx);
708
+ byte_positions.push(byte_idx);
709
+ char_idx = (char_idx + usize(1));
710
+ },
711
+ true => ()
712
+ );
618
713
  },
619
- true => ()
714
+ .None => ()
620
715
  );
621
- },
622
- .None => ()
623
- );
624
- };
625
-
626
- // Determine max_char_index based on from_index
627
- max_char_index := cond(
628
- (from_index >= char_idx) => char_idx,
629
- true => (from_index + usize(1))
630
- );
631
-
632
- // Search backwards from the end
633
- (last_match : Option(usize)) = .None;
634
- i := usize(0);
635
- while ((i < char_positions.len())),
636
- (i = (i + usize(1))),
637
- {
638
- char_pos_opt := char_positions.get(i);
639
- byte_pos_opt := byte_positions.get(i);
640
- match(char_pos_opt,
641
- .Some(char_pos) =>
642
- match(byte_pos_opt,
643
- .Some(byte_pos) => {
644
- cond(
645
- (char_pos >= max_char_index) => break,
646
- ((byte_pos + sub_bytes) <= self_bytes) => {
647
- matches := true;
648
- j := usize(0);
649
- while ((j < sub_bytes)),
650
- (j = (j + usize(1))),
651
- {
652
- self_byte_opt := self._bytes.get((byte_pos + j));
653
- sub_byte_opt := substr._bytes.get(j);
654
- match(self_byte_opt,
655
- .Some(self_byte) =>
656
- match(sub_byte_opt,
657
- .Some(sub_byte) => {
658
- cond(
659
- (self_byte != sub_byte) => {
716
+ };
717
+
718
+ max_char_index := cond(
719
+ (from_index >= char_idx) => char_idx,
720
+ true => (from_index + usize(1))
721
+ );
722
+
723
+ (last_match : Option(usize)) = .None;
724
+ i := usize(0);
725
+ while ((i < char_positions.len())),
726
+ (i = (i + usize(1))),
727
+ {
728
+ char_pos_opt := char_positions.get(i);
729
+ byte_pos_opt := byte_positions.get(i);
730
+ match(char_pos_opt,
731
+ .Some(char_pos) =>
732
+ match(byte_pos_opt,
733
+ .Some(byte_pos) => {
734
+ cond(
735
+ (char_pos >= max_char_index) => break,
736
+ ((byte_pos + sub_bytes) <= self_bytes) => {
737
+ matches := true;
738
+ j := usize(0);
739
+ while ((j < sub_bytes)),
740
+ (j = (j + usize(1))),
741
+ {
742
+ self_byte_opt := self_al.get((byte_pos + j));
743
+ sub_byte_opt := sub_al.get(j);
744
+ match(self_byte_opt,
745
+ .Some(self_byte) =>
746
+ match(sub_byte_opt,
747
+ .Some(sub_byte) => {
748
+ cond(
749
+ (self_byte != sub_byte) => {
750
+ matches = false;
751
+ break;
752
+ },
753
+ true => ()
754
+ );
755
+ },
756
+ .None => {
660
757
  matches = false;
661
758
  break;
662
- },
663
- true => ()
664
- );
665
- },
759
+ }
760
+ ),
666
761
  .None => {
667
762
  matches = false;
668
763
  break;
669
764
  }
670
- ),
671
- .None => {
672
- matches = false;
673
- break;
674
- }
675
- );
676
- };
677
- cond(
678
- matches => {
679
- last_match = .Some(char_pos);
765
+ );
766
+ };
767
+ cond(
768
+ matches => {
769
+ last_match = .Some(char_pos);
770
+ },
771
+ true => ()
772
+ );
680
773
  },
681
774
  true => ()
682
775
  );
683
776
  },
684
- true => ()
685
- );
686
- },
777
+ .None => ()
778
+ ),
687
779
  .None => ()
688
- ),
689
- .None => ()
690
- );
691
- };
692
-
693
- return last_match;
780
+ );
781
+ };
782
+
783
+ return last_match;
784
+ }
785
+ )
694
786
  }
695
787
  )
696
- }
788
+ )
697
789
  )
698
790
  ),
699
791
 
@@ -702,83 +794,84 @@ impl(String,
702
794
  * position: The character index to start checking from (default 0)
703
795
  */
704
796
  starts_with : (fn(self: Self, prefix: Self, (position : usize) ?= 0) -> bool)({
705
- prefix_bytes := prefix._bytes.len();
706
- self_bytes := self._bytes.len();
797
+ (prefix_bytes : usize) = match(prefix._bytes, .Some(b) => b.len(), .None => usize(0));
798
+ (self_bytes : usize) = match(self._bytes, .Some(b) => b.len(), .None => usize(0));
707
799
 
708
800
  cond(
709
801
  (prefix_bytes == usize(0)) => true,
710
- true => {
711
- // Find the byte index corresponding to the position-th character
712
- char_index := usize(0);
713
- byte_index := usize(0);
714
-
715
- // Skip to the position-th character
716
- while (((byte_index < self_bytes) && (char_index < position))),
717
- (byte_index = (byte_index + usize(1))),
718
- {
719
- byte_opt := self._bytes.get(byte_index);
720
- match(byte_opt,
721
- .Some(byte) => {
722
- is_start := ((byte < u8(0x80)) || (byte >= u8(0xC0)));
723
- cond(
724
- is_start => {
725
- // Determine byte length of this UTF-8 character
726
- byte_len := cond(
727
- (byte < u8(0x80)) => usize(1),
728
- ((byte >= u8(0xC0)) && (byte < u8(0xE0))) => usize(2),
729
- ((byte >= u8(0xE0)) && (byte < u8(0xF0))) => usize(3),
730
- ((byte >= u8(0xF0)) && (byte < u8(0xF8))) => usize(4),
731
- true => usize(1)
802
+ true => match(self._bytes,
803
+ .None => false,
804
+ .Some(self_al) => match(prefix._bytes,
805
+ .None => true,
806
+ .Some(prefix_al) => {
807
+ char_index := usize(0);
808
+ byte_index := usize(0);
809
+
810
+ while (((byte_index < self_bytes) && (char_index < position))),
811
+ (byte_index = (byte_index + usize(1))),
812
+ {
813
+ byte_opt := self_al.get(byte_index);
814
+ match(byte_opt,
815
+ .Some(byte) => {
816
+ is_start := ((byte < u8(0x80)) || (byte >= u8(0xC0)));
817
+ cond(
818
+ is_start => {
819
+ byte_len := cond(
820
+ (byte < u8(0x80)) => usize(1),
821
+ ((byte >= u8(0xC0)) && (byte < u8(0xE0))) => usize(2),
822
+ ((byte >= u8(0xE0)) && (byte < u8(0xF0))) => usize(3),
823
+ ((byte >= u8(0xF0)) && (byte < u8(0xF8))) => usize(4),
824
+ true => usize(1)
825
+ );
826
+ byte_index = ((byte_index + byte_len) - usize(1));
827
+ char_index = (char_index + usize(1));
828
+ },
829
+ true => ()
732
830
  );
733
- byte_index = ((byte_index + byte_len) - usize(1));
734
- char_index = (char_index + usize(1));
735
831
  },
736
- true => ()
832
+ .None => ()
737
833
  );
738
- },
739
- .None => ()
740
- );
741
- };
742
-
743
- // Check if we have enough bytes left for the prefix
744
- cond(
745
- ((byte_index + prefix_bytes) > self_bytes) => false,
746
- true => {
747
- // Compare bytes starting at byte_index
748
- i := usize(0);
749
- matches := true;
750
- while ((i < prefix_bytes)),
751
- (i = (i + usize(1))),
752
- {
753
- self_byte_opt := self._bytes.get((byte_index + i));
754
- prefix_byte_opt := prefix._bytes.get(i);
755
- match(self_byte_opt,
756
- .Some(self_byte) =>
757
- match(prefix_byte_opt,
758
- .Some(prefix_byte) => {
759
- cond(
760
- (self_byte != prefix_byte) => {
834
+ };
835
+
836
+ cond(
837
+ ((byte_index + prefix_bytes) > self_bytes) => false,
838
+ true => {
839
+ i := usize(0);
840
+ matches := true;
841
+ while ((i < prefix_bytes)),
842
+ (i = (i + usize(1))),
843
+ {
844
+ self_byte_opt := self_al.get((byte_index + i));
845
+ prefix_byte_opt := prefix_al.get(i);
846
+ match(self_byte_opt,
847
+ .Some(self_byte) =>
848
+ match(prefix_byte_opt,
849
+ .Some(prefix_byte) => {
850
+ cond(
851
+ (self_byte != prefix_byte) => {
852
+ matches = false;
853
+ break;
854
+ },
855
+ true => ()
856
+ );
857
+ },
858
+ .None => {
761
859
  matches = false;
762
860
  break;
763
- },
764
- true => ()
765
- );
766
- },
861
+ }
862
+ ),
767
863
  .None => {
768
864
  matches = false;
769
865
  break;
770
866
  }
771
- ),
772
- .None => {
773
- matches = false;
774
- break;
775
- }
776
- );
777
- };
778
- return matches;
867
+ );
868
+ };
869
+ return matches;
870
+ }
871
+ )
779
872
  }
780
873
  )
781
- }
874
+ )
782
875
  )
783
876
  }),
784
877
 
@@ -787,91 +880,93 @@ impl(String,
787
880
  * end_position: The character length to consider (default is string length)
788
881
  */
789
882
  ends_with : (fn(self: Self, suffix: Self, (end_position : usize) ?= usize.MAX) -> bool)({
790
- suffix_bytes := suffix._bytes.len();
791
- self_bytes := self._bytes.len();
883
+ (suffix_bytes : usize) = match(suffix._bytes, .Some(b) => b.len(), .None => usize(0));
884
+ (self_bytes : usize) = match(self._bytes, .Some(b) => b.len(), .None => usize(0));
792
885
 
793
886
  cond(
794
887
  (suffix_bytes == usize(0)) => true,
795
- true => {
796
- // Determine the effective end position in characters
797
- string_char_len := self.len();
798
- effective_end := cond(
799
- (end_position == usize.MAX) => string_char_len,
800
- (end_position > string_char_len) => string_char_len,
801
- true => end_position
802
- );
803
-
804
- // Find the byte index corresponding to effective_end character position
805
- char_index := usize(0);
806
- byte_index := usize(0);
807
- end_byte_index := self_bytes;
808
-
809
- while ((byte_index < self_bytes)),
810
- (byte_index = (byte_index + usize(1))),
811
- {
812
- byte_opt := self._bytes.get(byte_index);
813
- match(byte_opt,
814
- .Some(byte) => {
815
- is_start := ((byte < u8(0x80)) || (byte >= u8(0xC0)));
816
- cond(
817
- is_start => {
888
+ true => match(self._bytes,
889
+ .None => false,
890
+ .Some(self_al) => match(suffix._bytes,
891
+ .None => true,
892
+ .Some(suffix_al) => {
893
+ string_char_len := self.len();
894
+ effective_end := cond(
895
+ (end_position == usize.MAX) => string_char_len,
896
+ (end_position > string_char_len) => string_char_len,
897
+ true => end_position
898
+ );
899
+
900
+ char_index := usize(0);
901
+ byte_index := usize(0);
902
+ end_byte_index := self_bytes;
903
+
904
+ while ((byte_index < self_bytes)),
905
+ (byte_index = (byte_index + usize(1))),
906
+ {
907
+ byte_opt := self_al.get(byte_index);
908
+ match(byte_opt,
909
+ .Some(byte) => {
910
+ is_start := ((byte < u8(0x80)) || (byte >= u8(0xC0)));
818
911
  cond(
819
- (char_index == effective_end) => {
820
- end_byte_index = byte_index;
821
- break;
912
+ is_start => {
913
+ cond(
914
+ (char_index == effective_end) => {
915
+ end_byte_index = byte_index;
916
+ break;
917
+ },
918
+ true => {
919
+ char_index = (char_index + usize(1));
920
+ }
921
+ );
822
922
  },
823
- true => {
824
- char_index = (char_index + usize(1));
825
- }
923
+ true => ()
826
924
  );
827
925
  },
828
- true => ()
926
+ .None => ()
829
927
  );
830
- },
831
- .None => ()
832
- );
833
- };
834
-
835
- // Check if suffix fits within the effective range
836
- cond(
837
- (suffix_bytes > end_byte_index) => false,
838
- true => {
839
- // Compare bytes: check if bytes before end_byte_index end with suffix
840
- offset := (end_byte_index - suffix_bytes);
841
- i := usize(0);
842
- matches := true;
843
- while ((i < suffix_bytes)),
844
- (i = (i + usize(1))),
845
- {
846
- self_byte_opt := self._bytes.get((offset + i));
847
- suffix_byte_opt := suffix._bytes.get(i);
848
- match(self_byte_opt,
849
- .Some(self_byte) =>
850
- match(suffix_byte_opt,
851
- .Some(suffix_byte) => {
852
- cond(
853
- (self_byte != suffix_byte) => {
928
+ };
929
+
930
+ cond(
931
+ (suffix_bytes > end_byte_index) => false,
932
+ true => {
933
+ offset := (end_byte_index - suffix_bytes);
934
+ i := usize(0);
935
+ matches := true;
936
+ while ((i < suffix_bytes)),
937
+ (i = (i + usize(1))),
938
+ {
939
+ self_byte_opt := self_al.get((offset + i));
940
+ suffix_byte_opt := suffix_al.get(i);
941
+ match(self_byte_opt,
942
+ .Some(self_byte) =>
943
+ match(suffix_byte_opt,
944
+ .Some(suffix_byte) => {
945
+ cond(
946
+ (self_byte != suffix_byte) => {
947
+ matches = false;
948
+ break;
949
+ },
950
+ true => ()
951
+ );
952
+ },
953
+ .None => {
854
954
  matches = false;
855
955
  break;
856
- },
857
- true => ()
858
- );
859
- },
956
+ }
957
+ ),
860
958
  .None => {
861
959
  matches = false;
862
960
  break;
863
961
  }
864
- ),
865
- .None => {
866
- matches = false;
867
- break;
868
- }
869
- );
870
- };
871
- return matches;
962
+ );
963
+ };
964
+ return matches;
965
+ }
966
+ )
872
967
  }
873
968
  )
874
- }
969
+ )
875
970
  )
876
971
  }),
877
972
 
@@ -881,132 +976,29 @@ impl(String,
881
976
  replace : (fn(self: Self, search_value: Self, new_value: Self) -> Self)(
882
977
  cond(
883
978
  search_value.is_empty() => {
884
- // If search is empty, prepend new_value
885
979
  return new_value.concat(self);
886
980
  },
887
- true => {
888
- self_bytes := self._bytes.len();
889
- search_bytes := search_value._bytes.len();
890
-
891
- // Find first occurrence at byte level
892
- byte_index := usize(0);
893
- (found_at : Option(usize)) = .None;
894
-
895
- while ((byte_index <= (self_bytes - search_bytes))),
896
- (byte_index = (byte_index + usize(1))),
897
- {
898
- matches := true;
899
- j := usize(0);
900
- while ((j < search_bytes)),
901
- (j = (j + usize(1))),
902
- {
903
- self_byte_opt := self._bytes.get((byte_index + j));
904
- search_byte_opt := search_value._bytes.get(j);
905
- match(self_byte_opt,
906
- .Some(self_byte) =>
907
- match(search_byte_opt,
908
- .Some(search_byte) => {
909
- cond(
910
- (self_byte != search_byte) => {
911
- matches = false;
912
- break;
913
- },
914
- true => ()
915
- );
916
- },
917
- .None => {
918
- matches = false;
919
- break;
920
- }
921
- ),
922
- .None => {
923
- matches = false;
924
- break;
925
- }
926
- );
927
- };
928
-
929
- cond(
930
- matches => {
931
- found_at = .Some(byte_index);
932
- break;
933
- },
934
- true => ()
935
- );
936
- };
937
-
938
- match(found_at,
939
- .Some(pos) => {
940
- new_bytes := ArrayList(u8).with_capacity(((self_bytes - search_bytes) + new_value._bytes.len()));
941
-
942
- // Copy bytes before match
943
- i := usize(0);
944
- while ((i < pos)),
945
- (i = (i + usize(1))),
946
- {
947
- byte_opt := self._bytes.get(i);
948
- match(byte_opt,
949
- .Some(byte) => { new_bytes.push(byte); },
950
- .None => ()
951
- );
952
- };
981
+ true => match(self._bytes,
982
+ .None => self,
983
+ .Some(self_al) => match(search_value._bytes,
984
+ .None => self,
985
+ .Some(search_al) => {
986
+ self_bytes := self_al.len();
987
+ search_bytes := search_al.len();
953
988
 
954
- // Copy replacement bytes
955
- k := usize(0);
956
- while ((k < new_value._bytes.len())),
957
- (k = (k + usize(1))),
958
- {
959
- byte_opt := new_value._bytes.get(k);
960
- match(byte_opt,
961
- .Some(byte) => { new_bytes.push(byte); },
962
- .None => ()
963
- );
964
- };
989
+ byte_index := usize(0);
990
+ (found_at : Option(usize)) = .None;
965
991
 
966
- // Copy bytes after match
967
- m := (pos + search_bytes);
968
- while ((m < self_bytes)),
969
- (m = (m + usize(1))),
992
+ while ((byte_index <= (self_bytes - search_bytes))),
993
+ (byte_index = (byte_index + usize(1))),
970
994
  {
971
- byte_opt := self._bytes.get(m);
972
- match(byte_opt,
973
- .Some(byte) => { new_bytes.push(byte); },
974
- .None => ()
975
- );
976
- };
977
-
978
- return Self(_bytes: new_bytes);
979
- },
980
- .None => self
981
- )
982
- }
983
- )
984
- ),
985
-
986
- /**
987
- * Replace all occurrences of search_value with new_value (like JavaScript replaceAll)
988
- */
989
- replace_all : (fn(self: Self, search_value: Self, new_value: Self) -> Self)(
990
- cond(
991
- search_value.is_empty() => self,
992
- true => {
993
- self_bytes := self._bytes.len();
994
- search_bytes := search_value._bytes.len();
995
- new_bytes := ArrayList(u8).new();
996
-
997
- byte_index := usize(0);
998
- while ((byte_index < self_bytes)),
999
- (byte_index = (byte_index + usize(1))),
1000
- {
1001
- matches := true;
1002
- cond(
1003
- ((byte_index + search_bytes) <= self_bytes) => {
995
+ matches := true;
1004
996
  j := usize(0);
1005
997
  while ((j < search_bytes)),
1006
998
  (j = (j + usize(1))),
1007
999
  {
1008
- self_byte_opt := self._bytes.get((byte_index + j));
1009
- search_byte_opt := search_value._bytes.get(j);
1000
+ self_byte_opt := self_al.get((byte_index + j));
1001
+ search_byte_opt := search_al.get(j);
1010
1002
  match(self_byte_opt,
1011
1003
  .Some(self_byte) =>
1012
1004
  match(search_byte_opt,
@@ -1030,39 +1022,141 @@ impl(String,
1030
1022
  }
1031
1023
  );
1032
1024
  };
1033
- },
1034
- true => {
1035
- matches = false;
1036
- }
1037
- );
1038
-
1039
- cond(
1040
- matches => {
1041
- // Copy replacement bytes
1042
- k := usize(0);
1043
- while ((k < new_value._bytes.len())),
1044
- (k = (k + usize(1))),
1045
- {
1046
- byte_opt := new_value._bytes.get(k);
1047
- match(byte_opt,
1048
- .Some(byte) => { new_bytes.push(byte); },
1025
+
1026
+ cond(
1027
+ matches => {
1028
+ found_at = .Some(byte_index);
1029
+ break;
1030
+ },
1031
+ true => ()
1032
+ );
1033
+ };
1034
+
1035
+ match(found_at,
1036
+ .Some(pos) => {
1037
+ (nv_bytes : usize) = match(new_value._bytes, .Some(b) => b.len(), .None => usize(0));
1038
+ new_bytes := ArrayList(u8).with_capacity(((self_bytes - search_bytes) + nv_bytes));
1039
+
1040
+ match(self_al.ptr(),
1041
+ .Some(p) => {
1042
+ if((pos > usize(0)), {
1043
+ new_bytes.extend_from_ptr(p, pos);
1044
+ });
1045
+ },
1049
1046
  .None => ()
1050
1047
  );
1051
- };
1052
- byte_index = ((byte_index + search_bytes) - usize(1));
1053
- },
1054
- true => {
1055
- byte_opt := self._bytes.get(byte_index);
1056
- match(byte_opt,
1057
- .Some(byte) => { new_bytes.push(byte); },
1058
- .None => ()
1048
+
1049
+ match(new_value._bytes,
1050
+ .Some(nv_al) => match(nv_al.ptr(),
1051
+ .Some(p) => new_bytes.extend_from_ptr(p, nv_bytes),
1052
+ .None => ()
1053
+ ),
1054
+ .None => ()
1055
+ );
1056
+
1057
+ (after_pos : usize) = (pos + search_bytes);
1058
+ if((after_pos < self_bytes), {
1059
+ match(self_al.ptr(),
1060
+ .Some(p) => new_bytes.extend_from_ptr((p &+ after_pos), (self_bytes - after_pos)),
1061
+ .None => ()
1062
+ );
1063
+ });
1064
+
1065
+ return Self(_bytes: .Some(new_bytes));
1066
+ },
1067
+ .None => self
1068
+ )
1069
+ }
1070
+ )
1071
+ )
1072
+ )
1073
+ ),
1074
+
1075
+ /**
1076
+ * Replace all occurrences of search_value with new_value (like JavaScript replaceAll)
1077
+ */
1078
+ replace_all : (fn(self: Self, search_value: Self, new_value: Self) -> Self)(
1079
+ cond(
1080
+ search_value.is_empty() => self,
1081
+ true => match(self._bytes,
1082
+ .None => self,
1083
+ .Some(self_al) => match(search_value._bytes,
1084
+ .None => self,
1085
+ .Some(search_al) => {
1086
+ self_bytes := self_al.len();
1087
+ search_bytes := search_al.len();
1088
+ new_bytes := ArrayList(u8).new();
1089
+
1090
+ byte_index := usize(0);
1091
+ while ((byte_index < self_bytes)),
1092
+ (byte_index = (byte_index + usize(1))),
1093
+ {
1094
+ matches := true;
1095
+ cond(
1096
+ ((byte_index + search_bytes) <= self_bytes) => {
1097
+ j := usize(0);
1098
+ while ((j < search_bytes)),
1099
+ (j = (j + usize(1))),
1100
+ {
1101
+ self_byte_opt := self_al.get((byte_index + j));
1102
+ search_byte_opt := search_al.get(j);
1103
+ match(self_byte_opt,
1104
+ .Some(self_byte) =>
1105
+ match(search_byte_opt,
1106
+ .Some(search_byte) => {
1107
+ cond(
1108
+ (self_byte != search_byte) => {
1109
+ matches = false;
1110
+ break;
1111
+ },
1112
+ true => ()
1113
+ );
1114
+ },
1115
+ .None => {
1116
+ matches = false;
1117
+ break;
1118
+ }
1119
+ ),
1120
+ .None => {
1121
+ matches = false;
1122
+ break;
1123
+ }
1124
+ );
1125
+ };
1126
+ },
1127
+ true => {
1128
+ matches = false;
1129
+ }
1059
1130
  );
1060
- }
1061
- );
1062
- };
1063
-
1064
- return Self(_bytes: new_bytes);
1065
- }
1131
+
1132
+ cond(
1133
+ matches => {
1134
+ match(new_value._bytes,
1135
+ .Some(nv_al) => match(nv_al.ptr(),
1136
+ .Some(p) => new_bytes.extend_from_ptr(p, nv_al.len()),
1137
+ .None => ()
1138
+ ),
1139
+ .None => ()
1140
+ );
1141
+ byte_index = ((byte_index + search_bytes) - usize(1));
1142
+ },
1143
+ true => {
1144
+ byte_opt := self_al.get(byte_index);
1145
+ match(byte_opt,
1146
+ .Some(byte) => { new_bytes.push(byte); },
1147
+ .None => ()
1148
+ );
1149
+ }
1150
+ );
1151
+ };
1152
+
1153
+ cond(
1154
+ (new_bytes.len() == usize(0)) => Self(_bytes: .None),
1155
+ true => Self(_bytes: .Some(new_bytes))
1156
+ )
1157
+ }
1158
+ )
1159
+ )
1066
1160
  )
1067
1161
  ),
1068
1162
 
@@ -1070,57 +1164,67 @@ impl(String,
1070
1164
  * Convert ASCII lowercase letters to uppercase (like JavaScript toUpperCase)
1071
1165
  * Note: Only handles ASCII a-z, not full Unicode case mapping
1072
1166
  */
1073
- to_uppercase : (fn(self: Self) -> Self)({
1074
- new_bytes := ArrayList(u8).with_capacity(self._bytes.len());
1075
-
1076
- i := usize(0);
1077
- while ((i < self._bytes.len())),
1078
- (i = (i + usize(1))),
1079
- {
1080
- byte_opt := self._bytes.get(i);
1081
- match(byte_opt,
1082
- .Some(byte) => {
1083
- // ASCII lowercase a-z is 0x61-0x7A, uppercase A-Z is 0x41-0x5A
1084
- new_byte := cond(
1085
- ((byte >= u8(0x61)) && (byte <= u8(0x7A))) => (byte - u8(0x20)),
1086
- true => byte
1167
+ to_uppercase : (fn(self: Self) -> Self)(
1168
+ match(self._bytes,
1169
+ .None => Self(_bytes: .None),
1170
+ .Some(al) => {
1171
+ (total : usize) = al.len();
1172
+ new_bytes := ArrayList(u8).with_capacity(total);
1173
+
1174
+ i := usize(0);
1175
+ while ((i < total)),
1176
+ (i = (i + usize(1))),
1177
+ {
1178
+ byte_opt := al.get(i);
1179
+ match(byte_opt,
1180
+ .Some(byte) => {
1181
+ new_byte := cond(
1182
+ ((byte >= u8(0x61)) && (byte <= u8(0x7A))) => (byte - u8(0x20)),
1183
+ true => byte
1184
+ );
1185
+ new_bytes.push(new_byte);
1186
+ },
1187
+ .None => ()
1087
1188
  );
1088
- new_bytes.push(new_byte);
1089
- },
1090
- .None => ()
1091
- );
1092
- };
1093
-
1094
- return Self(_bytes: new_bytes);
1095
- }),
1189
+ };
1190
+
1191
+ Self(_bytes: .Some(new_bytes))
1192
+ }
1193
+ )
1194
+ ),
1096
1195
 
1097
1196
  /**
1098
1197
  * Convert ASCII uppercase letters to lowercase (like JavaScript toLowerCase)
1099
1198
  * Note: Only handles ASCII A-Z, not full Unicode case mapping
1100
1199
  */
1101
- to_lowercase : (fn(self: Self) -> Self)({
1102
- new_bytes := ArrayList(u8).with_capacity(self._bytes.len());
1103
-
1104
- i := usize(0);
1105
- while ((i < self._bytes.len())),
1106
- (i = (i + usize(1))),
1107
- {
1108
- byte_opt := self._bytes.get(i);
1109
- match(byte_opt,
1110
- .Some(byte) => {
1111
- // ASCII uppercase A-Z is 0x41-0x5A, lowercase a-z is 0x61-0x7A
1112
- new_byte := cond(
1113
- ((byte >= u8(0x41)) && (byte <= u8(0x5A))) => (byte + u8(0x20)),
1114
- true => byte
1200
+ to_lowercase : (fn(self: Self) -> Self)(
1201
+ match(self._bytes,
1202
+ .None => Self(_bytes: .None),
1203
+ .Some(al) => {
1204
+ (total : usize) = al.len();
1205
+ new_bytes := ArrayList(u8).with_capacity(total);
1206
+
1207
+ i := usize(0);
1208
+ while ((i < total)),
1209
+ (i = (i + usize(1))),
1210
+ {
1211
+ byte_opt := al.get(i);
1212
+ match(byte_opt,
1213
+ .Some(byte) => {
1214
+ new_byte := cond(
1215
+ ((byte >= u8(0x41)) && (byte <= u8(0x5A))) => (byte + u8(0x20)),
1216
+ true => byte
1217
+ );
1218
+ new_bytes.push(new_byte);
1219
+ },
1220
+ .None => ()
1115
1221
  );
1116
- new_bytes.push(new_byte);
1117
- },
1118
- .None => ()
1119
- );
1120
- };
1121
-
1122
- return Self(_bytes: new_bytes);
1123
- }),
1222
+ };
1223
+
1224
+ Self(_bytes: .Some(new_bytes))
1225
+ }
1226
+ )
1227
+ ),
1124
1228
 
1125
1229
  /**
1126
1230
  * Helper to check if a byte is ASCII whitespace
@@ -1133,176 +1237,137 @@ impl(String,
1133
1237
  /**
1134
1238
  * Remove whitespace from both ends of the string (like JavaScript trim)
1135
1239
  */
1136
- trim : (fn(self: Self) -> Self)({
1137
- total_bytes := self._bytes.len();
1138
-
1139
- cond(
1140
- (total_bytes == usize(0)) => {
1141
- return new();
1142
- },
1143
- true => ()
1144
- );
1145
-
1146
- // Find start index (skip leading whitespace)
1147
- start_idx := usize(0);
1148
- while ((start_idx < total_bytes)),
1149
- (start_idx = (start_idx + usize(1))),
1150
- {
1151
- byte_opt := self._bytes.get(start_idx);
1152
- match(byte_opt,
1153
- .Some(byte) => {
1154
- is_ws := Self._is_whitespace_byte(byte);
1155
- cond(
1156
- (!(is_ws)) => break,
1157
- true => ()
1158
- );
1159
- },
1160
- .None => break
1161
- );
1162
- };
1163
-
1164
- // Find end index (skip trailing whitespace)
1165
- end_idx := total_bytes;
1166
- while ((end_idx > start_idx)),
1167
- (end_idx = (end_idx - usize(1))),
1168
- {
1169
- byte_opt := self._bytes.get((end_idx - usize(1)));
1170
- match(byte_opt,
1171
- .Some(byte) => {
1172
- is_ws := Self._is_whitespace_byte(byte);
1173
- cond(
1174
- (!(is_ws)) => break,
1175
- true => ()
1176
- );
1177
- },
1178
- .None => break
1179
- );
1180
- };
1181
-
1182
- cond(
1183
- (start_idx >= end_idx) => {
1184
- return new();
1185
- },
1186
- true => ()
1187
- );
1188
-
1189
- new_bytes := ArrayList(u8).with_capacity((end_idx - start_idx));
1190
- i := start_idx;
1191
- while ((i < end_idx)),
1192
- (i = (i + usize(1))),
1193
- {
1194
- byte_opt := self._bytes.get(i);
1195
- match(byte_opt,
1196
- .Some(byte) => { new_bytes.push(byte); },
1197
- .None => ()
1198
- );
1199
- };
1200
- return Self(_bytes: new_bytes);
1201
- }),
1240
+ trim : (fn(self: Self) -> Self)(
1241
+ match(self._bytes,
1242
+ .None => Self(_bytes: .None),
1243
+ .Some(al) => {
1244
+ total_bytes := al.len();
1245
+
1246
+ if((total_bytes == usize(0)), {
1247
+ return Self(_bytes: .None);
1248
+ });
1249
+
1250
+ (start_idx : usize) = usize(0);
1251
+ while (start_idx < total_bytes), {
1252
+ (b : u8) = al.get_unchecked(start_idx);
1253
+ if(!(Self._is_whitespace_byte(b)), { break; });
1254
+ start_idx = (start_idx + usize(1));
1255
+ };
1256
+
1257
+ (end_idx : usize) = total_bytes;
1258
+ while (end_idx > start_idx), {
1259
+ (b : u8) = al.get_unchecked((end_idx - usize(1)));
1260
+ if(!(Self._is_whitespace_byte(b)), { break; });
1261
+ end_idx = (end_idx - usize(1));
1262
+ };
1263
+
1264
+ if((start_idx >= end_idx), {
1265
+ return Self(_bytes: .None);
1266
+ });
1267
+
1268
+ (count : usize) = (end_idx - start_idx);
1269
+ new_bytes := ArrayList(u8).with_capacity(count);
1270
+ match(al.ptr(),
1271
+ .Some(p) => new_bytes.extend_from_ptr((p &+ start_idx), count),
1272
+ .None => ()
1273
+ );
1274
+ Self(_bytes: .Some(new_bytes))
1275
+ }
1276
+ )
1277
+ ),
1202
1278
 
1203
1279
  /**
1204
1280
  * Remove whitespace from the start of the string (like JavaScript trimStart)
1205
1281
  */
1206
- trim_start : (fn(self: Self) -> Self)({
1207
- total_bytes := self._bytes.len();
1208
-
1209
- cond(
1210
- (total_bytes == usize(0)) => {
1211
- return new();
1212
- },
1213
- true => ()
1214
- );
1215
-
1216
- // Find start index (skip leading whitespace)
1217
- start_idx := usize(0);
1218
- while ((start_idx < total_bytes)),
1219
- (start_idx = (start_idx + usize(1))),
1220
- {
1221
- byte_opt := self._bytes.get(start_idx);
1222
- match(byte_opt,
1223
- .Some(byte) => {
1224
- is_ws := Self._is_whitespace_byte(byte);
1225
- cond(
1226
- (!(is_ws)) => break,
1227
- true => ()
1228
- );
1229
- },
1230
- .None => break
1231
- );
1232
- };
1233
-
1234
- cond(
1235
- (start_idx >= total_bytes) => {
1236
- return new();
1237
- },
1238
- true => ()
1239
- );
1240
-
1241
- new_bytes := ArrayList(u8).with_capacity((total_bytes - start_idx));
1242
- i := start_idx;
1243
- while ((i < total_bytes)),
1244
- (i = (i + usize(1))),
1245
- {
1246
- byte_opt := self._bytes.get(i);
1247
- match(byte_opt,
1248
- .Some(byte) => { new_bytes.push(byte); },
1249
- .None => ()
1250
- );
1251
- };
1252
- return Self(_bytes: new_bytes);
1253
- }),
1282
+ trim_start : (fn(self: Self) -> Self)(
1283
+ match(self._bytes,
1284
+ .None => Self(_bytes: .None),
1285
+ .Some(al) => {
1286
+ total_bytes := al.len();
1287
+
1288
+ cond(
1289
+ (total_bytes == usize(0)) => Self(_bytes: .None),
1290
+ true => {
1291
+ start_idx := usize(0);
1292
+ while ((start_idx < total_bytes)),
1293
+ (start_idx = (start_idx + usize(1))),
1294
+ {
1295
+ byte_opt := al.get(start_idx);
1296
+ match(byte_opt,
1297
+ .Some(byte) => {
1298
+ is_ws := Self._is_whitespace_byte(byte);
1299
+ cond(
1300
+ (!(is_ws)) => break,
1301
+ true => ()
1302
+ );
1303
+ },
1304
+ .None => break
1305
+ );
1306
+ };
1307
+
1308
+ cond(
1309
+ (start_idx >= total_bytes) => Self(_bytes: .None),
1310
+ true => {
1311
+ (count : usize) = (total_bytes - start_idx);
1312
+ new_bytes := ArrayList(u8).with_capacity(count);
1313
+ match(al.ptr(),
1314
+ .Some(p) => new_bytes.extend_from_ptr((p &+ start_idx), count),
1315
+ .None => ()
1316
+ );
1317
+ Self(_bytes: .Some(new_bytes))
1318
+ }
1319
+ )
1320
+ }
1321
+ )
1322
+ }
1323
+ )
1324
+ ),
1254
1325
 
1255
1326
  /**
1256
1327
  * Remove whitespace from the end of the string (like JavaScript trimEnd)
1257
1328
  */
1258
- trim_end : (fn(self: Self) -> Self)({
1259
- total_bytes := self._bytes.len();
1260
-
1261
- cond(
1262
- (total_bytes == usize(0)) => {
1263
- return new();
1264
- },
1265
- true => ()
1266
- );
1267
-
1268
- // Find end index (skip trailing whitespace)
1269
- end_idx := total_bytes;
1270
- while ((end_idx > usize(0))),
1271
- (end_idx = (end_idx - usize(1))),
1272
- {
1273
- byte_opt := self._bytes.get((end_idx - usize(1)));
1274
- match(byte_opt,
1275
- .Some(byte) => {
1276
- is_ws := Self._is_whitespace_byte(byte);
1277
- cond(
1278
- (!(is_ws)) => break,
1279
- true => ()
1280
- );
1281
- },
1282
- .None => break
1283
- );
1284
- };
1285
-
1286
- cond(
1287
- (end_idx == usize(0)) => {
1288
- return new();
1289
- },
1290
- true => ()
1291
- );
1292
-
1293
- new_bytes := ArrayList(u8).with_capacity(end_idx);
1294
- i := usize(0);
1295
- while ((i < end_idx)),
1296
- (i = (i + usize(1))),
1297
- {
1298
- byte_opt := self._bytes.get(i);
1299
- match(byte_opt,
1300
- .Some(byte) => { new_bytes.push(byte); },
1301
- .None => ()
1302
- );
1303
- };
1304
- return Self(_bytes: new_bytes);
1305
- })
1329
+ trim_end : (fn(self: Self) -> Self)(
1330
+ match(self._bytes,
1331
+ .None => Self(_bytes: .None),
1332
+ .Some(al) => {
1333
+ total_bytes := al.len();
1334
+
1335
+ cond(
1336
+ (total_bytes == usize(0)) => Self(_bytes: .None),
1337
+ true => {
1338
+ end_idx := total_bytes;
1339
+ while ((end_idx > usize(0))),
1340
+ (end_idx = (end_idx - usize(1))),
1341
+ {
1342
+ byte_opt := al.get((end_idx - usize(1)));
1343
+ match(byte_opt,
1344
+ .Some(byte) => {
1345
+ is_ws := Self._is_whitespace_byte(byte);
1346
+ cond(
1347
+ (!(is_ws)) => break,
1348
+ true => ()
1349
+ );
1350
+ },
1351
+ .None => break
1352
+ );
1353
+ };
1354
+
1355
+ cond(
1356
+ (end_idx == usize(0)) => Self(_bytes: .None),
1357
+ true => {
1358
+ new_bytes := ArrayList(u8).with_capacity(end_idx);
1359
+ match(al.ptr(),
1360
+ .Some(p) => new_bytes.extend_from_ptr(p, end_idx),
1361
+ .None => ()
1362
+ );
1363
+ Self(_bytes: .Some(new_bytes))
1364
+ }
1365
+ )
1366
+ }
1367
+ )
1368
+ }
1369
+ )
1370
+ )
1306
1371
  );
1307
1372
 
1308
1373
  impl(String, Add(String, String)(
@@ -1313,43 +1378,31 @@ impl(String, Add(String, String)(
1313
1378
 
1314
1379
  impl(String, Eq(String)(
1315
1380
  (==) : (fn(self: Self, other: Self) -> bool)({
1316
- // First compare lengths
1317
- self_len := self._bytes.len();
1318
- other_len := other._bytes.len();
1381
+ (self_len : usize) = match(self._bytes, .Some(b) => b.len(), .None => usize(0));
1382
+ (other_len : usize) = match(other._bytes, .Some(b) => b.len(), .None => usize(0));
1319
1383
 
1320
1384
  cond(
1321
- (self_len != other_len) => {
1322
- return false;
1323
- },
1324
- true => ()
1325
- );
1326
-
1327
- // Compare each byte
1328
- i := usize(0);
1329
- while ((i < self_len)),
1330
- (i = (i + usize(1))),
1331
- {
1332
- self_byte_opt := self._bytes.get(i);
1333
- other_byte_opt := other._bytes.get(i);
1334
-
1335
- match(self_byte_opt,
1336
- .Some(self_byte) =>
1337
- match(other_byte_opt,
1338
- .Some(other_byte) => {
1339
- cond(
1340
- (self_byte != other_byte) => {
1341
- return false;
1342
- },
1343
- true => ()
1344
- );
1345
- },
1346
- .None => return false
1347
- ),
1348
- .None => return false
1349
- );
1350
- };
1351
-
1352
- return true;
1385
+ (self_len != other_len) => false,
1386
+ (self_len == usize(0)) => true,
1387
+ true =>
1388
+ match(self._bytes,
1389
+ .Some(self_al) =>
1390
+ match(other._bytes,
1391
+ .Some(other_al) =>
1392
+ match(self_al.ptr(),
1393
+ .Some(self_ptr) =>
1394
+ match(other_al.ptr(),
1395
+ .Some(other_ptr) =>
1396
+ (memcmp((*(void))(self_ptr), (*(void))(other_ptr), self_len) == int(0)),
1397
+ .None => false
1398
+ ),
1399
+ .None => false
1400
+ ),
1401
+ .None => false
1402
+ ),
1403
+ .None => false
1404
+ )
1405
+ )
1353
1406
  }),
1354
1407
  (!=) : (fn(self: Self, other: Self) -> bool)({
1355
1408
  return !(Self.(==)(self, other));
@@ -1358,21 +1411,25 @@ impl(String, Eq(String)(
1358
1411
 
1359
1412
  impl(String, Hash(
1360
1413
  (hash): (fn(self: *(Self)) -> u64)({
1361
- // FNV-1a hash over the bytes
1362
1414
  h := u64(14695981039346656037);
1363
- i := usize(0);
1364
- len := self.*._bytes.len();
1365
- while ((i < len)),
1366
- (i = (i + usize(1))),
1367
- {
1368
- match(self.*._bytes.get(i),
1369
- .Some(b) => {
1370
- h = (h ^ u64(b));
1371
- h = (h * u64(1099511628211));
1372
- },
1373
- .None => ()
1374
- );
1375
- };
1415
+ match(self.*._bytes,
1416
+ .None => (),
1417
+ .Some(al) => {
1418
+ i := usize(0);
1419
+ len := al.len();
1420
+ while ((i < len)),
1421
+ (i = (i + usize(1))),
1422
+ {
1423
+ match(al.get(i),
1424
+ .Some(b) => {
1425
+ h = (h ^ u64(b));
1426
+ h = (h * u64(1099511628211));
1427
+ },
1428
+ .None => ()
1429
+ );
1430
+ };
1431
+ }
1432
+ );
1376
1433
  h
1377
1434
  })
1378
1435
  ));
@@ -1391,27 +1448,29 @@ StringChars :: struct(
1391
1448
  impl(StringChars, Iterator(
1392
1449
  Item : rune,
1393
1450
  next : (fn(self : *(Self)) -> Option(rune))(
1394
- cond(
1395
- (self._byte_index >= self._string._bytes.len()) => .None,
1396
- true => {
1397
- first_byte_opt := self._string._bytes.get(self._byte_index);
1398
- match(first_byte_opt,
1399
- .Some(first_byte) => {
1400
- // Determine byte length of this UTF-8 character
1401
- (byte_len : usize) = cond(
1402
- (first_byte < u8(0x80)) => usize(1),
1403
- ((first_byte >= u8(0xC0)) && (first_byte < u8(0xE0))) => usize(2),
1404
- ((first_byte >= u8(0xE0)) && (first_byte < u8(0xF0))) => usize(3),
1405
- ((first_byte >= u8(0xF0)) && (first_byte < u8(0xF8))) => usize(4),
1406
- true => usize(1)
1407
- );
1408
- r := self._string._decode_rune_at(self._byte_index);
1409
- self._byte_index = (self._byte_index + byte_len);
1410
- r
1411
- },
1412
- .None => .None
1413
- )
1414
- }
1451
+ match(self._string._bytes,
1452
+ .None => .None,
1453
+ .Some(al) => cond(
1454
+ (self._byte_index >= al.len()) => .None,
1455
+ true => {
1456
+ first_byte_opt := al.get(self._byte_index);
1457
+ match(first_byte_opt,
1458
+ .Some(first_byte) => {
1459
+ (byte_len : usize) = cond(
1460
+ (first_byte < u8(0x80)) => usize(1),
1461
+ ((first_byte >= u8(0xC0)) && (first_byte < u8(0xE0))) => usize(2),
1462
+ ((first_byte >= u8(0xE0)) && (first_byte < u8(0xF0))) => usize(3),
1463
+ ((first_byte >= u8(0xF0)) && (first_byte < u8(0xF8))) => usize(4),
1464
+ true => usize(1)
1465
+ );
1466
+ r := self._string._decode_rune_at(self._byte_index);
1467
+ self._byte_index = (self._byte_index + byte_len);
1468
+ r
1469
+ },
1470
+ .None => .None
1471
+ )
1472
+ }
1473
+ )
1415
1474
  )
1416
1475
  )
1417
1476
  ));
@@ -1428,13 +1487,16 @@ StringBytes :: struct(
1428
1487
  impl(StringBytes, Iterator(
1429
1488
  Item : u8,
1430
1489
  next : (fn(self : *(Self)) -> Option(u8))(
1431
- cond(
1432
- (self._index >= self._string._bytes.len()) => .None,
1433
- true => {
1434
- byte_opt := self._string._bytes.get(self._index);
1435
- self._index = (self._index + usize(1));
1436
- byte_opt
1437
- }
1490
+ match(self._string._bytes,
1491
+ .None => .None,
1492
+ .Some(al) => cond(
1493
+ (self._index >= al.len()) => .None,
1494
+ true => {
1495
+ byte_opt := al.get(self._index);
1496
+ self._index = (self._index + usize(1));
1497
+ byte_opt
1498
+ }
1499
+ )
1438
1500
  )
1439
1501
  )
1440
1502
  ));
@@ -1476,363 +1538,352 @@ impl(String,
1476
1538
  * Parse the string as a signed 32-bit integer.
1477
1539
  * Returns .Some(value) on success, .None on failure (empty, invalid chars, overflow).
1478
1540
  */
1479
- parse_i32 : (fn(self: Self) -> Option(i32))({
1480
- total_bytes := self._bytes.len();
1481
- cond(
1482
- (total_bytes == usize(0)) => {
1483
- return .None;
1484
- },
1485
- true => ()
1486
- );
1487
-
1488
- idx := usize(0);
1489
-
1490
- // Check for sign
1491
- is_negative := false;
1492
- first_byte_opt := self._bytes.get(usize(0));
1493
- match(first_byte_opt,
1494
- .Some(first_byte) => {
1541
+ parse_i32 : (fn(self: Self) -> Option(i32))(
1542
+ match(self._bytes,
1543
+ .None => .None,
1544
+ .Some(al) => {
1545
+ total_bytes := al.len();
1495
1546
  cond(
1496
- (first_byte == u8(45)) => {
1497
- is_negative = true;
1498
- idx = usize(1);
1499
- },
1500
- (first_byte == u8(43)) => {
1501
- idx = usize(1);
1502
- },
1503
- true => ()
1504
- );
1505
- },
1506
- .None => {
1507
- return .None;
1508
- }
1509
- );
1510
-
1511
- // Must have at least one digit after sign
1512
- cond(
1513
- (idx >= total_bytes) => {
1514
- return .None;
1515
- },
1516
- true => ()
1517
- );
1518
-
1519
- result := i64(0);
1520
- has_digit := false;
1521
-
1522
- while ((idx < total_bytes)),
1523
- (idx = (idx + usize(1))),
1524
- {
1525
- byte_opt := self._bytes.get(idx);
1526
- match(byte_opt,
1527
- .Some(byte) => {
1528
- cond(
1529
- Self._is_digit_byte(byte) => {
1530
- digit := i64((byte - u8(48)));
1531
- result = ((result * i64(10)) + digit);
1532
- has_digit = true;
1533
- },
1534
- true => {
1535
- return .None;
1536
- }
1537
- );
1538
- },
1539
- .None => {
1540
- return .None;
1541
- }
1542
- );
1543
- };
1544
-
1545
- cond(
1546
- (!(has_digit)) => {
1547
- return .None;
1548
- },
1549
- true => ()
1550
- );
1551
-
1552
- final_val := cond(
1553
- is_negative => (i64(0) - result),
1554
- true => result
1555
- );
1547
+ (total_bytes == usize(0)) => .None,
1548
+ true => {
1549
+ idx := usize(0);
1550
+ is_negative := false;
1551
+ first_byte_opt := al.get(usize(0));
1552
+ match(first_byte_opt,
1553
+ .Some(first_byte) => {
1554
+ cond(
1555
+ (first_byte == u8(45)) => {
1556
+ is_negative = true;
1557
+ idx = usize(1);
1558
+ },
1559
+ (first_byte == u8(43)) => {
1560
+ idx = usize(1);
1561
+ },
1562
+ true => ()
1563
+ );
1564
+ },
1565
+ .None => {
1566
+ return .None;
1567
+ }
1568
+ );
1556
1569
 
1557
- // Check i32 range: -2147483648 to 2147483647
1558
- cond(
1559
- ((final_val < i64(-2147483648)) || (final_val > i64(2147483647))) => .None,
1560
- true => .Some(i32(final_val))
1570
+ cond(
1571
+ (idx >= total_bytes) => .None,
1572
+ true => {
1573
+ result := i64(0);
1574
+ has_digit := false;
1575
+
1576
+ while ((idx < total_bytes)),
1577
+ (idx = (idx + usize(1))),
1578
+ {
1579
+ byte_opt := al.get(idx);
1580
+ match(byte_opt,
1581
+ .Some(byte) => {
1582
+ cond(
1583
+ Self._is_digit_byte(byte) => {
1584
+ digit := i64((byte - u8(48)));
1585
+ result = ((result * i64(10)) + digit);
1586
+ has_digit = true;
1587
+ },
1588
+ true => {
1589
+ return .None;
1590
+ }
1591
+ );
1592
+ },
1593
+ .None => {
1594
+ return .None;
1595
+ }
1596
+ );
1597
+ };
1598
+
1599
+ cond(
1600
+ (!(has_digit)) => .None,
1601
+ true => {
1602
+ final_val := cond(
1603
+ is_negative => (i64(0) - result),
1604
+ true => result
1605
+ );
1606
+ cond(
1607
+ ((final_val < i64(-2147483648)) || (final_val > i64(2147483647))) => .None,
1608
+ true => .Some(i32(final_val))
1609
+ )
1610
+ }
1611
+ )
1612
+ }
1613
+ )
1614
+ }
1615
+ )
1616
+ }
1561
1617
  )
1562
- }),
1618
+ ),
1563
1619
 
1564
1620
  /**
1565
1621
  * Parse the string as a signed 64-bit integer.
1566
1622
  * Returns .Some(value) on success, .None on failure.
1567
1623
  * Note: does not detect i64 overflow during accumulation.
1568
1624
  */
1569
- parse_i64 : (fn(self: Self) -> Option(i64))({
1570
- total_bytes := self._bytes.len();
1571
- cond(
1572
- (total_bytes == usize(0)) => {
1573
- return .None;
1574
- },
1575
- true => ()
1576
- );
1577
-
1578
- idx := usize(0);
1579
-
1580
- is_negative := false;
1581
- first_byte_opt := self._bytes.get(usize(0));
1582
- match(first_byte_opt,
1583
- .Some(first_byte) => {
1625
+ parse_i64 : (fn(self: Self) -> Option(i64))(
1626
+ match(self._bytes,
1627
+ .None => .None,
1628
+ .Some(al) => {
1629
+ total_bytes := al.len();
1584
1630
  cond(
1585
- (first_byte == u8(45)) => {
1586
- is_negative = true;
1587
- idx = usize(1);
1588
- },
1589
- (first_byte == u8(43)) => {
1590
- idx = usize(1);
1591
- },
1592
- true => ()
1593
- );
1594
- },
1595
- .None => {
1596
- return .None;
1597
- }
1598
- );
1599
-
1600
- cond(
1601
- (idx >= total_bytes) => {
1602
- return .None;
1603
- },
1604
- true => ()
1605
- );
1606
-
1607
- result := i64(0);
1608
- has_digit := false;
1609
-
1610
- while ((idx < total_bytes)),
1611
- (idx = (idx + usize(1))),
1612
- {
1613
- byte_opt := self._bytes.get(idx);
1614
- match(byte_opt,
1615
- .Some(byte) => {
1616
- cond(
1617
- Self._is_digit_byte(byte) => {
1618
- digit := i64((byte - u8(48)));
1619
- result = ((result * i64(10)) + digit);
1620
- has_digit = true;
1621
- },
1622
- true => {
1623
- return .None;
1624
- }
1625
- );
1626
- },
1627
- .None => {
1628
- return .None;
1629
- }
1630
- );
1631
- };
1631
+ (total_bytes == usize(0)) => .None,
1632
+ true => {
1633
+ idx := usize(0);
1634
+ is_negative := false;
1635
+ first_byte_opt := al.get(usize(0));
1636
+ match(first_byte_opt,
1637
+ .Some(first_byte) => {
1638
+ cond(
1639
+ (first_byte == u8(45)) => {
1640
+ is_negative = true;
1641
+ idx = usize(1);
1642
+ },
1643
+ (first_byte == u8(43)) => {
1644
+ idx = usize(1);
1645
+ },
1646
+ true => ()
1647
+ );
1648
+ },
1649
+ .None => {
1650
+ return .None;
1651
+ }
1652
+ );
1632
1653
 
1633
- cond(
1634
- (!(has_digit)) => .None,
1635
- true => {
1636
- final_val := cond(
1637
- is_negative => (i64(0) - result),
1638
- true => result
1639
- );
1640
- return .Some(final_val);
1654
+ cond(
1655
+ (idx >= total_bytes) => .None,
1656
+ true => {
1657
+ result := i64(0);
1658
+ has_digit := false;
1659
+
1660
+ while ((idx < total_bytes)),
1661
+ (idx = (idx + usize(1))),
1662
+ {
1663
+ byte_opt := al.get(idx);
1664
+ match(byte_opt,
1665
+ .Some(byte) => {
1666
+ cond(
1667
+ Self._is_digit_byte(byte) => {
1668
+ digit := i64((byte - u8(48)));
1669
+ result = ((result * i64(10)) + digit);
1670
+ has_digit = true;
1671
+ },
1672
+ true => {
1673
+ return .None;
1674
+ }
1675
+ );
1676
+ },
1677
+ .None => {
1678
+ return .None;
1679
+ }
1680
+ );
1681
+ };
1682
+
1683
+ cond(
1684
+ (!(has_digit)) => .None,
1685
+ true => {
1686
+ final_val := cond(
1687
+ is_negative => (i64(0) - result),
1688
+ true => result
1689
+ );
1690
+ return .Some(final_val);
1691
+ }
1692
+ )
1693
+ }
1694
+ )
1695
+ }
1696
+ )
1641
1697
  }
1642
1698
  )
1643
- }),
1699
+ ),
1644
1700
 
1645
1701
  /**
1646
1702
  * Parse the string as an unsigned 32-bit integer.
1647
1703
  * Returns .Some(value) on success, .None on failure (empty, invalid chars, overflow, negative sign).
1648
1704
  */
1649
- parse_u32 : (fn(self: Self) -> Option(u32))({
1650
- total_bytes := self._bytes.len();
1651
- cond(
1652
- (total_bytes == usize(0)) => {
1653
- return .None;
1654
- },
1655
- true => ()
1656
- );
1657
-
1658
- idx := usize(0);
1659
-
1660
- // Optional '+' sign, but '-' is invalid for unsigned
1661
- first_byte_opt := self._bytes.get(usize(0));
1662
- match(first_byte_opt,
1663
- .Some(first_byte) => {
1664
- cond(
1665
- (first_byte == u8(45)) => {
1666
- return .None;
1667
- },
1668
- (first_byte == u8(43)) => {
1669
- idx = usize(1);
1670
- },
1671
- true => ()
1672
- );
1673
- },
1674
- .None => {
1675
- return .None;
1676
- }
1677
- );
1678
-
1679
- cond(
1680
- (idx >= total_bytes) => {
1681
- return .None;
1682
- },
1683
- true => ()
1684
- );
1685
-
1686
- result := u64(0);
1687
- has_digit := false;
1688
-
1689
- while ((idx < total_bytes)),
1690
- (idx = (idx + usize(1))),
1691
- {
1692
- byte_opt := self._bytes.get(idx);
1693
- match(byte_opt,
1694
- .Some(byte) => {
1695
- cond(
1696
- Self._is_digit_byte(byte) => {
1697
- digit := u64((byte - u8(48)));
1698
- result = ((result * u64(10)) + digit);
1699
- has_digit = true;
1700
- },
1701
- true => {
1702
- return .None;
1703
- }
1704
- );
1705
- },
1706
- .None => {
1707
- return .None;
1708
- }
1709
- );
1710
- };
1711
-
1712
- cond(
1713
- (!(has_digit)) => .None,
1714
- true => {
1715
- // Check u32 range: 0 to 4294967295
1705
+ parse_u32 : (fn(self: Self) -> Option(u32))(
1706
+ match(self._bytes,
1707
+ .None => .None,
1708
+ .Some(al) => {
1709
+ total_bytes := al.len();
1716
1710
  cond(
1717
- (result > u64(4294967295)) => {
1718
- return .None;
1719
- },
1711
+ (total_bytes == usize(0)) => .None,
1720
1712
  true => {
1721
- return .Some(u32(result));
1713
+ idx := usize(0);
1714
+ first_byte_opt := al.get(usize(0));
1715
+ match(first_byte_opt,
1716
+ .Some(first_byte) => {
1717
+ cond(
1718
+ (first_byte == u8(45)) => {
1719
+ return .None;
1720
+ },
1721
+ (first_byte == u8(43)) => {
1722
+ idx = usize(1);
1723
+ },
1724
+ true => ()
1725
+ );
1726
+ },
1727
+ .None => {
1728
+ return .None;
1729
+ }
1730
+ );
1731
+
1732
+ cond(
1733
+ (idx >= total_bytes) => .None,
1734
+ true => {
1735
+ result := u64(0);
1736
+ has_digit := false;
1737
+
1738
+ while ((idx < total_bytes)),
1739
+ (idx = (idx + usize(1))),
1740
+ {
1741
+ byte_opt := al.get(idx);
1742
+ match(byte_opt,
1743
+ .Some(byte) => {
1744
+ cond(
1745
+ Self._is_digit_byte(byte) => {
1746
+ digit := u64((byte - u8(48)));
1747
+ result = ((result * u64(10)) + digit);
1748
+ has_digit = true;
1749
+ },
1750
+ true => {
1751
+ return .None;
1752
+ }
1753
+ );
1754
+ },
1755
+ .None => {
1756
+ return .None;
1757
+ }
1758
+ );
1759
+ };
1760
+
1761
+ cond(
1762
+ (!(has_digit)) => .None,
1763
+ true => cond(
1764
+ (result > u64(4294967295)) => .None,
1765
+ true => .Some(u32(result))
1766
+ )
1767
+ )
1768
+ }
1769
+ )
1722
1770
  }
1723
- );
1771
+ )
1724
1772
  }
1725
1773
  )
1726
- }),
1774
+ ),
1727
1775
 
1728
1776
  /**
1729
1777
  * Parse the string as an unsigned 64-bit integer.
1730
1778
  * Returns .Some(value) on success, .None on failure.
1731
1779
  * Note: does not detect u64 overflow during accumulation.
1732
1780
  */
1733
- parse_u64 : (fn(self: Self) -> Option(u64))({
1734
- total_bytes := self._bytes.len();
1735
- cond(
1736
- (total_bytes == usize(0)) => {
1737
- return .None;
1738
- },
1739
- true => ()
1740
- );
1741
-
1742
- idx := usize(0);
1743
-
1744
- first_byte_opt := self._bytes.get(usize(0));
1745
- match(first_byte_opt,
1746
- .Some(first_byte) => {
1781
+ parse_u64 : (fn(self: Self) -> Option(u64))(
1782
+ match(self._bytes,
1783
+ .None => .None,
1784
+ .Some(al) => {
1785
+ total_bytes := al.len();
1747
1786
  cond(
1748
- (first_byte == u8(45)) => {
1749
- return .None;
1750
- },
1751
- (first_byte == u8(43)) => {
1752
- idx = usize(1);
1753
- },
1754
- true => ()
1755
- );
1756
- },
1757
- .None => {
1758
- return .None;
1759
- }
1760
- );
1761
-
1762
- cond(
1763
- (idx >= total_bytes) => {
1764
- return .None;
1765
- },
1766
- true => ()
1767
- );
1787
+ (total_bytes == usize(0)) => .None,
1788
+ true => {
1789
+ idx := usize(0);
1790
+ first_byte_opt := al.get(usize(0));
1791
+ match(first_byte_opt,
1792
+ .Some(first_byte) => {
1793
+ cond(
1794
+ (first_byte == u8(45)) => {
1795
+ return .None;
1796
+ },
1797
+ (first_byte == u8(43)) => {
1798
+ idx = usize(1);
1799
+ },
1800
+ true => ()
1801
+ );
1802
+ },
1803
+ .None => {
1804
+ return .None;
1805
+ }
1806
+ );
1768
1807
 
1769
- result := u64(0);
1770
- has_digit := false;
1771
-
1772
- while ((idx < total_bytes)),
1773
- (idx = (idx + usize(1))),
1774
- {
1775
- byte_opt := self._bytes.get(idx);
1776
- match(byte_opt,
1777
- .Some(byte) => {
1778
- cond(
1779
- Self._is_digit_byte(byte) => {
1780
- digit := u64((byte - u8(48)));
1781
- result = ((result * u64(10)) + digit);
1782
- has_digit = true;
1783
- },
1784
- true => {
1785
- return .None;
1786
- }
1787
- );
1788
- },
1789
- .None => {
1790
- return .None;
1791
- }
1792
- );
1793
- };
1808
+ cond(
1809
+ (idx >= total_bytes) => .None,
1810
+ true => {
1811
+ result := u64(0);
1812
+ has_digit := false;
1813
+
1814
+ while ((idx < total_bytes)),
1815
+ (idx = (idx + usize(1))),
1816
+ {
1817
+ byte_opt := al.get(idx);
1818
+ match(byte_opt,
1819
+ .Some(byte) => {
1820
+ cond(
1821
+ Self._is_digit_byte(byte) => {
1822
+ digit := u64((byte - u8(48)));
1823
+ result = ((result * u64(10)) + digit);
1824
+ has_digit = true;
1825
+ },
1826
+ true => {
1827
+ return .None;
1828
+ }
1829
+ );
1830
+ },
1831
+ .None => {
1832
+ return .None;
1833
+ }
1834
+ );
1835
+ };
1794
1836
 
1795
- cond(
1796
- (!(has_digit)) => .None,
1797
- true => .Some(result)
1837
+ cond(
1838
+ (!(has_digit)) => .None,
1839
+ true => .Some(result)
1840
+ )
1841
+ }
1842
+ )
1843
+ }
1844
+ )
1845
+ }
1798
1846
  )
1799
- }),
1847
+ ),
1800
1848
 
1801
1849
  /**
1802
1850
  * Parse the string as a boolean.
1803
1851
  * Returns .Some(true) for "true", .Some(false) for "false", .None for anything else.
1804
1852
  */
1805
- parse_bool : (fn(self: Self) -> Option(bool))({
1806
- total_bytes := self._bytes.len();
1807
- // "true" = 4 bytes: 116(t), 114(r), 117(u), 101(e)
1808
- // "false" = 5 bytes: 102(f), 97(a), 108(l), 115(s), 101(e)
1809
- cond(
1810
- (total_bytes == usize(4)) => {
1811
- b0 := self._bytes.get(usize(0)).unwrap_or(u8(0));
1812
- b1 := self._bytes.get(usize(1)).unwrap_or(u8(0));
1813
- b2 := self._bytes.get(usize(2)).unwrap_or(u8(0));
1814
- b3 := self._bytes.get(usize(3)).unwrap_or(u8(0));
1815
- cond(
1816
- ((b0 == u8(116)) && ((b1 == u8(114)) && ((b2 == u8(117)) && (b3 == u8(101))))) =>
1817
- .Some(true),
1818
- true => .None
1819
- )
1820
- },
1821
- (total_bytes == usize(5)) => {
1822
- b0 := self._bytes.get(usize(0)).unwrap_or(u8(0));
1823
- b1 := self._bytes.get(usize(1)).unwrap_or(u8(0));
1824
- b2 := self._bytes.get(usize(2)).unwrap_or(u8(0));
1825
- b3 := self._bytes.get(usize(3)).unwrap_or(u8(0));
1826
- b4 := self._bytes.get(usize(4)).unwrap_or(u8(0));
1853
+ parse_bool : (fn(self: Self) -> Option(bool))(
1854
+ match(self._bytes,
1855
+ .None => .None,
1856
+ .Some(al) => {
1857
+ total_bytes := al.len();
1827
1858
  cond(
1828
- ((b0 == u8(102)) && ((b1 == u8(97)) && ((b2 == u8(108)) && ((b3 == u8(115)) && (b4 == u8(101)))))) =>
1829
- .Some(false),
1859
+ (total_bytes == usize(4)) => {
1860
+ b0 := al.get(usize(0)).unwrap_or(u8(0));
1861
+ b1 := al.get(usize(1)).unwrap_or(u8(0));
1862
+ b2 := al.get(usize(2)).unwrap_or(u8(0));
1863
+ b3 := al.get(usize(3)).unwrap_or(u8(0));
1864
+ cond(
1865
+ ((b0 == u8(116)) && ((b1 == u8(114)) && ((b2 == u8(117)) && (b3 == u8(101))))) =>
1866
+ .Some(true),
1867
+ true => .None
1868
+ )
1869
+ },
1870
+ (total_bytes == usize(5)) => {
1871
+ b0 := al.get(usize(0)).unwrap_or(u8(0));
1872
+ b1 := al.get(usize(1)).unwrap_or(u8(0));
1873
+ b2 := al.get(usize(2)).unwrap_or(u8(0));
1874
+ b3 := al.get(usize(3)).unwrap_or(u8(0));
1875
+ b4 := al.get(usize(4)).unwrap_or(u8(0));
1876
+ cond(
1877
+ ((b0 == u8(102)) && ((b1 == u8(97)) && ((b2 == u8(108)) && ((b3 == u8(115)) && (b4 == u8(101)))))) =>
1878
+ .Some(false),
1879
+ true => .None
1880
+ )
1881
+ },
1830
1882
  true => .None
1831
1883
  )
1832
- },
1833
- true => .None
1884
+ }
1834
1885
  )
1835
- })
1886
+ )
1836
1887
  );
1837
1888
 
1838
1889
  export