@shd101wyy/yo 0.1.32 → 0.1.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/skills/yo-async-effects/async-effects-recipes.md +2 -2
- package/.github/skills/yo-core-patterns/SKILL.md +1 -1
- package/.github/skills/yo-core-patterns/core-patterns-cheatsheet.md +76 -22
- package/.github/skills/yo-syntax/SKILL.md +1 -1
- package/.github/skills/yo-syntax/syntax-cheatsheet.md +59 -67
- package/out/cjs/index.cjs +662 -574
- package/out/cjs/yo-cli.cjs +803 -715
- package/out/cjs/yo-lsp.cjs +771 -683
- package/out/esm/index.mjs +555 -467
- package/out/types/src/codegen/exprs/comptime-value.d.ts +2 -1
- package/out/types/src/codegen/functions/context.d.ts +1 -0
- package/out/types/src/codegen/types/generation.d.ts +1 -1
- package/out/types/src/codegen/utils/index.d.ts +2 -4
- package/out/types/src/evaluator/exprs/_expr.d.ts +1 -0
- package/out/types/src/evaluator/types/flowability.d.ts +22 -0
- package/out/types/src/expr.d.ts +4 -13
- package/out/types/src/types/creators.d.ts +2 -3
- package/out/types/src/types/definitions.d.ts +2 -3
- package/out/types/src/types/guards.d.ts +2 -2
- package/out/types/src/types/tags.d.ts +2 -2
- package/out/types/src/value-tag.d.ts +0 -1
- package/out/types/src/value.d.ts +2 -11
- package/out/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/std/alg/hash.yo +5 -3
- package/std/build.yo +46 -46
- package/std/collections/array_list.yo +73 -66
- package/std/collections/hash_map.yo +53 -95
- package/std/collections/list_view.yo +77 -0
- package/std/crypto/random.yo +5 -5
- package/std/encoding/base64.yo +12 -13
- package/std/encoding/hex.yo +6 -6
- package/std/encoding/json.yo +6 -5
- package/std/encoding/utf16.yo +9 -9
- package/std/env.yo +8 -8
- package/std/fmt/to_string.yo +12 -12
- package/std/http/client.yo +1 -1
- package/std/imm/list.yo +4 -3
- package/std/imm/map.yo +3 -2
- package/std/imm/set.yo +4 -3
- package/std/imm/sorted_map.yo +3 -2
- package/std/imm/sorted_set.yo +4 -3
- package/std/imm/string.yo +12 -5
- package/std/imm/vec.yo +8 -3
- package/std/prelude.yo +178 -401
- package/std/string/string.yo +198 -71
- package/std/url/index.yo +26 -26
- package/out/types/src/evaluator/types/slice.d.ts +0 -8
package/std/string/string.yo
CHANGED
|
@@ -3,6 +3,7 @@ pragma(Pragma.AllowUnsafe);
|
|
|
3
3
|
{ ArrayList } :: import("../collections/array_list.yo");
|
|
4
4
|
{ rune } :: import("./rune.yo");
|
|
5
5
|
{ memcpy, memcmp, strlen } :: import("../libc/string.yo");
|
|
6
|
+
{ fwrite, stderr } :: import("../libc/stdio.yo");
|
|
6
7
|
/// String operation error variants.
|
|
7
8
|
StringError :: enum(
|
|
8
9
|
/// The input bytes are not valid UTF-8.
|
|
@@ -162,14 +163,23 @@ impl(
|
|
|
162
163
|
* Get a str view into the string's UTF-8 bytes
|
|
163
164
|
* Returns a fat pointer (pointer + length) without copying
|
|
164
165
|
*/
|
|
165
|
-
|
|
166
|
+
/**
|
|
167
|
+
* PRIVILEGED raw view of the heap buffer (ptr + byte length) for C
|
|
168
|
+
* interop and pragma'd std internals. Naming RawSlice requires
|
|
169
|
+
* pragma(Pragma.AllowUnsafe); the view dangles if the String mutates
|
|
170
|
+
* or dies — callers must not let it escape the borrow site.
|
|
171
|
+
* (This replaces the deleted `as_str()`: heap bytes can no longer be
|
|
172
|
+
* viewed as `str`, which is the STATIC string view.
|
|
173
|
+
* See plans/SLICE_REWORK.md.)
|
|
174
|
+
*/
|
|
175
|
+
raw_bytes : (fn(self : Self) -> RawSlice(u8))(
|
|
166
176
|
match(
|
|
167
177
|
self._bytes,
|
|
168
|
-
.None =>
|
|
178
|
+
.None => RawSlice(u8)(ptr : *(u8)(""), len : usize(0)),
|
|
169
179
|
.Some(al) => match(
|
|
170
180
|
al._ptr,
|
|
171
|
-
.Some(p) =>
|
|
172
|
-
.None =>
|
|
181
|
+
.Some(p) => RawSlice(u8)(ptr : p, len : al._length),
|
|
182
|
+
.None => RawSlice(u8)(ptr : *(u8)(""), len : usize(0))
|
|
173
183
|
)
|
|
174
184
|
)
|
|
175
185
|
),
|
|
@@ -415,6 +425,31 @@ impl(
|
|
|
415
425
|
bytes_len : (fn(self : Self) -> usize)(
|
|
416
426
|
match(self._bytes,.Some(b) => b.len(),.None => usize(0))
|
|
417
427
|
),
|
|
428
|
+
/// Get the byte at the given index. Panics if the index is out of
|
|
429
|
+
/// bounds (mirrors `str`'s byte indexing). Use `bytes_len()` for the
|
|
430
|
+
/// valid range and `bytes()` for sequential iteration.
|
|
431
|
+
byte_at : (fn(self : Self, index : usize) -> u8)(
|
|
432
|
+
match(
|
|
433
|
+
self._bytes,
|
|
434
|
+
.Some(b) => match(
|
|
435
|
+
b.get(index),
|
|
436
|
+
.Some(v) => v,
|
|
437
|
+
.None => panic("String.byte_at: index out of bounds")
|
|
438
|
+
),
|
|
439
|
+
.None => panic("String.byte_at: index out of bounds")
|
|
440
|
+
)
|
|
441
|
+
),
|
|
442
|
+
/**
|
|
443
|
+
* Owned copy of the characters in `[r.start, r.end)` — `s(a..b)` lowers
|
|
444
|
+
* to this (JS-style range slicing; rune indices like `substring`).
|
|
445
|
+
*/
|
|
446
|
+
slice_copy : (fn(self : Self, r : Range(usize)) -> Self)(
|
|
447
|
+
self.substring(r.start, r.end)
|
|
448
|
+
),
|
|
449
|
+
/// Inclusive-range companion (`s(a..=b)`).
|
|
450
|
+
slice_copy_inclusive : (fn(self : Self, r : RangeInclusive(usize)) -> Self)(
|
|
451
|
+
self.substring(r.start, r.end + usize(1))
|
|
452
|
+
),
|
|
418
453
|
/**
|
|
419
454
|
* Extract a substring from start to end character indices (like JavaScript substring)
|
|
420
455
|
* Returns a new string containing characters from start (inclusive) to end (exclusive)
|
|
@@ -1414,6 +1449,143 @@ impl(
|
|
|
1414
1449
|
})
|
|
1415
1450
|
)
|
|
1416
1451
|
);
|
|
1452
|
+
/// Heterogeneous comparison: `String == str` (and `!=`). Compares bytes
|
|
1453
|
+
/// DIRECTLY against the static `str` — no intermediate view of the String's
|
|
1454
|
+
/// heap buffer is constructed (`as_str()` is being removed; see
|
|
1455
|
+
/// plans/SLICE_REWORK.md step 1). This is the replacement for the dominant
|
|
1456
|
+
/// `x.as_str() == "literal"` pattern: write `x == "literal"`.
|
|
1457
|
+
impl(
|
|
1458
|
+
String,
|
|
1459
|
+
Eq(str)(
|
|
1460
|
+
(==) : (fn(self : Self, other : str) -> bool)({
|
|
1461
|
+
(self_len : usize) = match(self._bytes,.Some(b) => b.len(),.None => usize(0));
|
|
1462
|
+
other_len := other.len();
|
|
1463
|
+
cond(
|
|
1464
|
+
(self_len != other_len) => false,
|
|
1465
|
+
(self_len == usize(0)) => true,
|
|
1466
|
+
true =>
|
|
1467
|
+
match(
|
|
1468
|
+
self._bytes,
|
|
1469
|
+
.Some(self_al) =>
|
|
1470
|
+
match(
|
|
1471
|
+
self_al.ptr(),
|
|
1472
|
+
// SAFETY: self_len equals other_len (checked above) and both
|
|
1473
|
+
// equal the respective byte counts; the str's backing is
|
|
1474
|
+
// static storage and the String's buffer is Rc-managed —
|
|
1475
|
+
// memcmp reads exactly self_len bytes from each.
|
|
1476
|
+
.Some(self_ptr) =>
|
|
1477
|
+
(unsafe(memcmp((*(void))(self_ptr), (*(void))(other.ptr()), self_len)) == int(0)),
|
|
1478
|
+
.None => false
|
|
1479
|
+
),
|
|
1480
|
+
.None => false
|
|
1481
|
+
)
|
|
1482
|
+
)
|
|
1483
|
+
})
|
|
1484
|
+
// `(!=)` comes from the trait's `?=` default (not(Self.(==)(lhs, rhs))),
|
|
1485
|
+
// which dispatches to this overload by argument types.
|
|
1486
|
+
)
|
|
1487
|
+
);
|
|
1488
|
+
/// The symmetric direction: `str == String` (and `!=`), so literal-first
|
|
1489
|
+
/// comparisons (`"x" == name`) work too. Lives here (not the prelude)
|
|
1490
|
+
/// because the prelude is layered below `String`.
|
|
1491
|
+
impl(
|
|
1492
|
+
str,
|
|
1493
|
+
Eq(String)(
|
|
1494
|
+
(==) : (fn(self : Self, other : String) -> bool)({
|
|
1495
|
+
self_len := self.len();
|
|
1496
|
+
(other_len : usize) = match(other._bytes,.Some(b) => b.len(),.None => usize(0));
|
|
1497
|
+
cond(
|
|
1498
|
+
(self_len != other_len) => false,
|
|
1499
|
+
(self_len == usize(0)) => true,
|
|
1500
|
+
true =>
|
|
1501
|
+
match(
|
|
1502
|
+
other._bytes,
|
|
1503
|
+
.Some(other_al) =>
|
|
1504
|
+
match(
|
|
1505
|
+
other_al.ptr(),
|
|
1506
|
+
// SAFETY: lengths equal & nonzero; str backing is static.
|
|
1507
|
+
.Some(other_ptr) =>
|
|
1508
|
+
(unsafe(memcmp((*(void))(self.ptr()), (*(void))(other_ptr), self_len)) == int(0)),
|
|
1509
|
+
.None => false
|
|
1510
|
+
),
|
|
1511
|
+
.None => false
|
|
1512
|
+
)
|
|
1513
|
+
)
|
|
1514
|
+
})
|
|
1515
|
+
// `(!=)` comes from the trait's `?=` default.
|
|
1516
|
+
)
|
|
1517
|
+
);
|
|
1518
|
+
/// Byte-lexicographic ordering, mirroring `str`'s `Ord(str)` impl in the
|
|
1519
|
+
/// prelude. Enables `a < b` on Strings directly (the `a.as_str() <
|
|
1520
|
+
/// b.as_str()` workaround is retired; see plans/SLICE_REWORK.md step 3).
|
|
1521
|
+
impl(
|
|
1522
|
+
String,
|
|
1523
|
+
Ord(String)(
|
|
1524
|
+
(<) : (fn(lhs : Self, rhs : Self) -> bool)({
|
|
1525
|
+
lhs_len := lhs.bytes_len();
|
|
1526
|
+
rhs_len := rhs.bytes_len();
|
|
1527
|
+
min_len := cond((lhs_len < rhs_len) => lhs_len, true => rhs_len);
|
|
1528
|
+
i := usize(0);
|
|
1529
|
+
while(i < min_len, i = (i + usize(1)), {
|
|
1530
|
+
cond(
|
|
1531
|
+
(lhs.byte_at(i) < rhs.byte_at(i)) => {
|
|
1532
|
+
return(true);
|
|
1533
|
+
},
|
|
1534
|
+
(lhs.byte_at(i) > rhs.byte_at(i)) => {
|
|
1535
|
+
return(false);
|
|
1536
|
+
},
|
|
1537
|
+
true => ()
|
|
1538
|
+
);
|
|
1539
|
+
});
|
|
1540
|
+
lhs_len < rhs_len
|
|
1541
|
+
}),
|
|
1542
|
+
(<=) : (fn(lhs : Self, rhs : Self) -> bool)({
|
|
1543
|
+
return(!(rhs < lhs));
|
|
1544
|
+
}),
|
|
1545
|
+
(>) : (fn(lhs : Self, rhs : Self) -> bool)({
|
|
1546
|
+
return(rhs < lhs);
|
|
1547
|
+
}),
|
|
1548
|
+
(>=) : (fn(lhs : Self, rhs : Self) -> bool)({
|
|
1549
|
+
return(!(lhs < rhs));
|
|
1550
|
+
})
|
|
1551
|
+
)
|
|
1552
|
+
);
|
|
1553
|
+
/// Search/pattern operations accepting a static `str` argument
|
|
1554
|
+
/// (plans/SLICE_REWORK.md step 1). Inherent methods cannot be overloaded
|
|
1555
|
+
/// in Yo, so the `str`-pattern variants of `contains`/`starts_with`/… are
|
|
1556
|
+
/// provided through this trait; method dispatch picks the overload by
|
|
1557
|
+
/// argument type (`x.contains("lit")` vs `x.contains(other_string)`).
|
|
1558
|
+
StrPattern :: trait(
|
|
1559
|
+
contains : (fn(self : Self, substr : str, (from_index : usize) ?= 0) -> bool),
|
|
1560
|
+
starts_with : (fn(self : Self, prefix : str, (position : usize) ?= 0) -> bool),
|
|
1561
|
+
ends_with : (fn(self : Self, suffix : str, (end_position : usize) ?= usize.MAX) -> bool),
|
|
1562
|
+
index_of : (fn(self : Self, substr : str, (from_index : usize) ?= 0) -> Option(usize)),
|
|
1563
|
+
last_index_of : (fn(self : Self, substr : str, (from_index : usize) ?= usize.MAX) -> Option(usize)),
|
|
1564
|
+
split : (fn(self : Self, separator : str) -> ArrayList(Self))
|
|
1565
|
+
);
|
|
1566
|
+
impl(
|
|
1567
|
+
String,
|
|
1568
|
+
StrPattern(
|
|
1569
|
+
contains : (fn(self : Self, substr : str, (from_index : usize) ?= 0) -> bool)(
|
|
1570
|
+
self.contains(String.from(substr), from_index)
|
|
1571
|
+
),
|
|
1572
|
+
starts_with : (fn(self : Self, prefix : str, (position : usize) ?= 0) -> bool)(
|
|
1573
|
+
self.starts_with(String.from(prefix), position)
|
|
1574
|
+
),
|
|
1575
|
+
ends_with : (fn(self : Self, suffix : str, (end_position : usize) ?= usize.MAX) -> bool)(
|
|
1576
|
+
self.ends_with(String.from(suffix), end_position)
|
|
1577
|
+
),
|
|
1578
|
+
index_of : (fn(self : Self, substr : str, (from_index : usize) ?= 0) -> Option(usize))(
|
|
1579
|
+
self.index_of(String.from(substr), from_index)
|
|
1580
|
+
),
|
|
1581
|
+
last_index_of : (fn(self : Self, substr : str, (from_index : usize) ?= usize.MAX) -> Option(usize))(
|
|
1582
|
+
self.last_index_of(String.from(substr), from_index)
|
|
1583
|
+
),
|
|
1584
|
+
split : (fn(self : Self, separator : str) -> ArrayList(Self))(
|
|
1585
|
+
self.split(String.from(separator))
|
|
1586
|
+
)
|
|
1587
|
+
)
|
|
1588
|
+
);
|
|
1417
1589
|
/// Hash trait implementation — FNV-1a hash over the string's bytes.
|
|
1418
1590
|
impl(
|
|
1419
1591
|
String,
|
|
@@ -1513,31 +1685,6 @@ impl(
|
|
|
1513
1685
|
)
|
|
1514
1686
|
)
|
|
1515
1687
|
);
|
|
1516
|
-
/// Byte-position iterator for `String` — yields `usize` byte indices.
|
|
1517
|
-
/// Used by `String.iter()`; the for-macro pairs each yielded position
|
|
1518
|
-
/// with `String.project(pos)` (Indexable from Phase C) to bind the
|
|
1519
|
-
/// body's `ref`-name to a byte in `self._bytes.Some`. See
|
|
1520
|
-
/// plans/ITERATOR_REDESIGN.md.
|
|
1521
|
-
_StringPosIter :: struct(
|
|
1522
|
-
_index : usize,
|
|
1523
|
-
_len : usize
|
|
1524
|
-
);
|
|
1525
|
-
impl(
|
|
1526
|
-
_StringPosIter,
|
|
1527
|
-
Iterator(
|
|
1528
|
-
Item : usize,
|
|
1529
|
-
next : (fn(ref(self) : Self) -> Option(usize))(
|
|
1530
|
-
cond(
|
|
1531
|
-
(self._index >= self._len) =>.None,
|
|
1532
|
-
true => {
|
|
1533
|
-
out := self._index;
|
|
1534
|
-
self._index = (self._index + usize(1));
|
|
1535
|
-
.Some(out)
|
|
1536
|
-
}
|
|
1537
|
-
)
|
|
1538
|
-
)
|
|
1539
|
-
)
|
|
1540
|
-
);
|
|
1541
1688
|
impl(
|
|
1542
1689
|
String,
|
|
1543
1690
|
/**
|
|
@@ -1552,17 +1699,6 @@ impl(
|
|
|
1552
1699
|
bytes : (fn(self : Self) -> StringBytes)(
|
|
1553
1700
|
StringBytes(_string : self, _index : usize(0))
|
|
1554
1701
|
),
|
|
1555
|
-
/// Byte-position iterator for `for(s, ref(b) => body)`. Yields
|
|
1556
|
-
/// `usize` byte indices; the for-macro pairs each with
|
|
1557
|
-
/// `s.project(pos)` (Indexable) so the body sees `ref(u8)` bound
|
|
1558
|
-
/// to each byte. Iteration is byte-level, not rune-level — for
|
|
1559
|
-
/// codepoint iteration use `chars()` explicitly.
|
|
1560
|
-
iter : (fn(ref(self) : Self) -> _StringPosIter)(
|
|
1561
|
-
_StringPosIter(
|
|
1562
|
-
_index : usize(0),
|
|
1563
|
-
_len : match(self._bytes,.Some(b) => b.len(),.None => usize(0))
|
|
1564
|
-
)
|
|
1565
|
-
),
|
|
1566
1702
|
/**
|
|
1567
1703
|
* Consume the string and return a rune iterator (default iteration)
|
|
1568
1704
|
*/
|
|
@@ -2157,27 +2293,6 @@ impl(
|
|
|
2157
2293
|
)
|
|
2158
2294
|
)
|
|
2159
2295
|
);
|
|
2160
|
-
/// String Indexable impl — projection-style byte access yielding
|
|
2161
|
-
/// `ref(u8)`. Body uses `unsafe(...)` because `&(bytes(pos))` produces
|
|
2162
|
-
/// a raw `*(u8)` borrow into `self._bytes.Some.bytes` storage; the
|
|
2163
|
-
/// `unsafe` wrap is the trusted escape from the flowability rule
|
|
2164
|
-
/// (privileged code only). See plans/ITERATOR_REDESIGN.md.
|
|
2165
|
-
impl(
|
|
2166
|
-
String,
|
|
2167
|
-
Indexable(usize)(
|
|
2168
|
-
Element : u8,
|
|
2169
|
-
project : (fn(ref(self) : Self, pos : usize) -> ref(u8))(
|
|
2170
|
-
match(
|
|
2171
|
-
self._bytes,
|
|
2172
|
-
// SAFETY: `pos < self.len()` is the precondition; the `_bytes` is the
|
|
2173
|
-
// String's own owned ArrayList whose `data[pos]` lives as long as the
|
|
2174
|
-
// ref-bound `self`. `bytes(pos)` is auto-bounds-checked by ArrayList.project.
|
|
2175
|
-
.Some(bytes) => unsafe(&(bytes(pos))),
|
|
2176
|
-
.None => panic("String: project on empty string")
|
|
2177
|
-
)
|
|
2178
|
-
)
|
|
2179
|
-
)
|
|
2180
|
-
);
|
|
2181
2296
|
/// Clone implementation — produces an independent byte-level copy.
|
|
2182
2297
|
impl(
|
|
2183
2298
|
String,
|
|
@@ -2205,29 +2320,41 @@ impl(
|
|
|
2205
2320
|
)
|
|
2206
2321
|
)
|
|
2207
2322
|
);
|
|
2208
|
-
/// Like `assert`, but accepts a runtime `String` message (e.g. a template
|
|
2209
|
-
/// string with interpolation: `` `error: ${value}` ``).
|
|
2210
|
-
///
|
|
2211
|
-
/// Example:
|
|
2212
|
-
/// name := String.from("rule1");
|
|
2213
|
-
/// assert_dyn(name.len() > usize(0), `Invalid rule name: ${name}`);
|
|
2214
|
-
assert_dyn :: (fn(flag : bool, msg : String) -> unit)({
|
|
2215
|
-
assert(flag, msg.as_str());
|
|
2216
|
-
});
|
|
2217
2323
|
/// Like `panic`, but accepts a runtime `String` message (e.g. a template
|
|
2218
2324
|
/// string with interpolation: `` `error: ${value}` ``).
|
|
2219
2325
|
///
|
|
2220
2326
|
/// Example:
|
|
2221
2327
|
/// panic_dyn(`Something went wrong: ${details}`);
|
|
2222
2328
|
panic_dyn :: (fn(msg : String) -> unit)({
|
|
2223
|
-
panic
|
|
2329
|
+
// Write the heap message bytes to stderr, then abort via panic.
|
|
2330
|
+
// (str is the STATIC string view now — a heap String can't be passed
|
|
2331
|
+
// to panic(str); see plans/SLICE_REWORK.md.)
|
|
2332
|
+
rb := msg.raw_bytes();
|
|
2333
|
+
// SAFETY: rb points into msg's live buffer for the duration of the call.
|
|
2334
|
+
// fwrite (ANSI C) instead of POSIX write(2, …) so the emitted C is portable
|
|
2335
|
+
// to Windows targets.
|
|
2336
|
+
___ := unsafe(fwrite(*(void)(rb.ptr), usize(1), rb.len, stderr));
|
|
2337
|
+
panic("");
|
|
2338
|
+
}); /// Like `assert`, but accepts a runtime `String` message (e.g. a template
|
|
2339
|
+
/// string with interpolation: `` `error: ${value}` ``).
|
|
2340
|
+
///
|
|
2341
|
+
/// Example:
|
|
2342
|
+
/// name := String.from("rule1");
|
|
2343
|
+
/// assert_dyn(name.len() > usize(0), `Invalid rule name: ${name}`);
|
|
2344
|
+
assert_dyn :: (fn(flag : bool, msg : String) -> unit)({
|
|
2345
|
+
cond(
|
|
2346
|
+
flag => (),
|
|
2347
|
+
true => panic_dyn(msg)
|
|
2348
|
+
);
|
|
2224
2349
|
});
|
|
2350
|
+
|
|
2225
2351
|
export(
|
|
2226
2352
|
String,
|
|
2227
2353
|
StringError,
|
|
2228
2354
|
StringChars,
|
|
2229
2355
|
StringBytes,
|
|
2230
2356
|
StringLines,
|
|
2357
|
+
StrPattern,
|
|
2231
2358
|
assert_dyn,
|
|
2232
2359
|
panic_dyn
|
|
2233
2360
|
);
|
package/std/url/index.yo
CHANGED
|
@@ -51,7 +51,7 @@ _DOT :: u8(46); // '.'
|
|
|
51
51
|
// ============================================================================
|
|
52
52
|
// Helper: parse port number from bytes
|
|
53
53
|
// ============================================================================
|
|
54
|
-
_parse_port :: (fn(s :
|
|
54
|
+
_parse_port :: (fn(s : String, start : usize, end : usize, exn : Exception) -> u16)({
|
|
55
55
|
cond(
|
|
56
56
|
(start >= end) => {
|
|
57
57
|
exn.throw(dyn(UrlError.InvalidPort));
|
|
@@ -61,7 +61,7 @@ _parse_port :: (fn(s : str, start : usize, end : usize, exn : Exception) -> u16)
|
|
|
61
61
|
val := u32(0);
|
|
62
62
|
i := start;
|
|
63
63
|
while(runtime(i < end), {
|
|
64
|
-
ch := s.
|
|
64
|
+
ch := s.byte_at(i);
|
|
65
65
|
cond(
|
|
66
66
|
((ch >= _ZERO) && (ch <= _NINE)) => {
|
|
67
67
|
val = ((val * u32(10)) + u32(ch - _ZERO));
|
|
@@ -95,15 +95,15 @@ impl(
|
|
|
95
95
|
// Parse a URL string.
|
|
96
96
|
// Supports: scheme://[userinfo@]host[:port]/path[?query][#fragment]
|
|
97
97
|
// Also supports scheme:path (opaque URIs like mailto:user@example.com)
|
|
98
|
-
parse : (fn(s :
|
|
98
|
+
parse : (fn(s : String, exn : Exception) -> Url)({
|
|
99
99
|
cond(
|
|
100
|
-
(s.
|
|
100
|
+
(s.bytes_len() == usize(0)) => {
|
|
101
101
|
exn.throw(dyn(UrlError.EmptyInput));
|
|
102
102
|
},
|
|
103
103
|
true => ()
|
|
104
104
|
);
|
|
105
105
|
pos := usize(0);
|
|
106
|
-
src_len := s.
|
|
106
|
+
src_len := s.bytes_len();
|
|
107
107
|
// --- Parse scheme ---
|
|
108
108
|
// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
|
|
109
109
|
scheme_end := usize(0);
|
|
@@ -114,7 +114,7 @@ impl(
|
|
|
114
114
|
true => ()
|
|
115
115
|
);
|
|
116
116
|
// First char must be a letter
|
|
117
|
-
first := s.
|
|
117
|
+
first := s.byte_at(usize(0));
|
|
118
118
|
cond(
|
|
119
119
|
(((first >= _LOWER_A) && (first <= _LOWER_Z)) || ((first >= _UPPER_A) && (first <= _UPPER_Z))) => (),
|
|
120
120
|
true => {
|
|
@@ -124,7 +124,7 @@ impl(
|
|
|
124
124
|
i := usize(1);
|
|
125
125
|
found_colon := false;
|
|
126
126
|
while(runtime(i < src_len), {
|
|
127
|
-
ch := s.
|
|
127
|
+
ch := s.byte_at(i);
|
|
128
128
|
cond(
|
|
129
129
|
(ch == _COLON) => {
|
|
130
130
|
scheme_end = i;
|
|
@@ -147,7 +147,7 @@ impl(
|
|
|
147
147
|
scheme_bytes := ArrayList(u8).new();
|
|
148
148
|
j := usize(0);
|
|
149
149
|
while(runtime(j < scheme_end), {
|
|
150
|
-
b := s.
|
|
150
|
+
b := s.byte_at(j);
|
|
151
151
|
// Normalize to lowercase
|
|
152
152
|
cond(
|
|
153
153
|
((b >= _UPPER_A) && (b <= _UPPER_Z)) => scheme_bytes.push(b + u8(32)),
|
|
@@ -160,7 +160,7 @@ impl(
|
|
|
160
160
|
// --- Check for authority (// prefix) ---
|
|
161
161
|
has_authority := false;
|
|
162
162
|
cond(
|
|
163
|
-
(((pos + usize(1)) < src_len) && ((s.
|
|
163
|
+
(((pos + usize(1)) < src_len) && ((s.byte_at(pos) == _SLASH) && (s.byte_at(pos + usize(1)) == _SLASH))) => {
|
|
164
164
|
has_authority = true;
|
|
165
165
|
pos = (pos + usize(2)); // skip '//'
|
|
166
166
|
},
|
|
@@ -178,7 +178,7 @@ impl(
|
|
|
178
178
|
auth_end := src_len;
|
|
179
179
|
k := pos;
|
|
180
180
|
while(runtime(k < src_len), {
|
|
181
|
-
ch := s.
|
|
181
|
+
ch := s.byte_at(k);
|
|
182
182
|
cond(
|
|
183
183
|
(((ch == _SLASH) || (ch == _QUESTION)) || (ch == _HASH)) => {
|
|
184
184
|
auth_end = k;
|
|
@@ -193,12 +193,12 @@ impl(
|
|
|
193
193
|
m := auth_start;
|
|
194
194
|
while(runtime(m < auth_end), {
|
|
195
195
|
cond(
|
|
196
|
-
(s.
|
|
196
|
+
(s.byte_at(m) == _AT) => {
|
|
197
197
|
// Everything before '@' is userinfo
|
|
198
198
|
ui_bytes := ArrayList(u8).new();
|
|
199
199
|
n := auth_start;
|
|
200
200
|
while(runtime(n < m), {
|
|
201
|
-
ui_bytes.push(s.
|
|
201
|
+
ui_bytes.push(s.byte_at(n));
|
|
202
202
|
n = (n + usize(1));
|
|
203
203
|
});
|
|
204
204
|
userinfo =.Some(String.from_bytes(ui_bytes));
|
|
@@ -212,10 +212,10 @@ impl(
|
|
|
212
212
|
// Parse host[:port]
|
|
213
213
|
// Check for IPv6 literal [...]
|
|
214
214
|
cond(
|
|
215
|
-
((host_start < auth_end) && (s.
|
|
215
|
+
((host_start < auth_end) && (s.byte_at(host_start) == _LBRACKET)) => {
|
|
216
216
|
// IPv6: find closing ']'
|
|
217
217
|
bracket_end := (host_start + usize(1));
|
|
218
|
-
while(runtime((bracket_end < auth_end) && (s.
|
|
218
|
+
while(runtime((bracket_end < auth_end) && (s.byte_at(bracket_end) != _RBRACKET)), {
|
|
219
219
|
bracket_end = (bracket_end + usize(1));
|
|
220
220
|
});
|
|
221
221
|
host_bytes := ArrayList(u8).new();
|
|
@@ -223,7 +223,7 @@ impl(
|
|
|
223
223
|
while(runtime(hh <= bracket_end), {
|
|
224
224
|
cond(
|
|
225
225
|
(hh < auth_end) => {
|
|
226
|
-
host_bytes.push(s.
|
|
226
|
+
host_bytes.push(s.byte_at(hh));
|
|
227
227
|
},
|
|
228
228
|
true => ()
|
|
229
229
|
);
|
|
@@ -233,7 +233,7 @@ impl(
|
|
|
233
233
|
// Check for port after ']:'
|
|
234
234
|
after_bracket := (bracket_end + usize(1));
|
|
235
235
|
cond(
|
|
236
|
-
((after_bracket < auth_end) && (s.
|
|
236
|
+
((after_bracket < auth_end) && (s.byte_at(after_bracket) == _COLON)) => {
|
|
237
237
|
port =.Some(_parse_port(s, after_bracket + usize(1), auth_end, exn));
|
|
238
238
|
},
|
|
239
239
|
true => ()
|
|
@@ -245,7 +245,7 @@ impl(
|
|
|
245
245
|
cp := host_start;
|
|
246
246
|
while(runtime(cp < auth_end), {
|
|
247
247
|
cond(
|
|
248
|
-
(s.
|
|
248
|
+
(s.byte_at(cp) == _COLON) => {
|
|
249
249
|
colon_pos =.Some(cp);
|
|
250
250
|
break;
|
|
251
251
|
},
|
|
@@ -260,7 +260,7 @@ impl(
|
|
|
260
260
|
host_b := ArrayList(u8).new();
|
|
261
261
|
hh2 := host_start;
|
|
262
262
|
while(runtime(hh2 < cp_val), {
|
|
263
|
-
host_b.push(s.
|
|
263
|
+
host_b.push(s.byte_at(hh2));
|
|
264
264
|
hh2 = (hh2 + usize(1));
|
|
265
265
|
});
|
|
266
266
|
host =.Some(String.from_bytes(host_b));
|
|
@@ -271,7 +271,7 @@ impl(
|
|
|
271
271
|
host_b := ArrayList(u8).new();
|
|
272
272
|
hh3 := host_start;
|
|
273
273
|
while(runtime(hh3 < auth_end), {
|
|
274
|
-
host_b.push(s.
|
|
274
|
+
host_b.push(s.byte_at(hh3));
|
|
275
275
|
hh3 = (hh3 + usize(1));
|
|
276
276
|
});
|
|
277
277
|
h := String.from_bytes(host_b);
|
|
@@ -294,7 +294,7 @@ impl(
|
|
|
294
294
|
path_end := src_len;
|
|
295
295
|
pp := pos;
|
|
296
296
|
while(runtime(pp < src_len), {
|
|
297
|
-
ch := s.
|
|
297
|
+
ch := s.byte_at(pp);
|
|
298
298
|
cond(
|
|
299
299
|
((ch == _QUESTION) || (ch == _HASH)) => {
|
|
300
300
|
path_end = pp;
|
|
@@ -309,7 +309,7 @@ impl(
|
|
|
309
309
|
path_bytes := ArrayList(u8).new();
|
|
310
310
|
pb := path_start;
|
|
311
311
|
while(runtime(pb < path_end), {
|
|
312
|
-
path_bytes.push(s.
|
|
312
|
+
path_bytes.push(s.byte_at(pb));
|
|
313
313
|
pb = (pb + usize(1));
|
|
314
314
|
});
|
|
315
315
|
path_str = String.from_bytes(path_bytes);
|
|
@@ -320,14 +320,14 @@ impl(
|
|
|
320
320
|
// --- Parse query ---
|
|
321
321
|
(query : Option(String)) =.None;
|
|
322
322
|
cond(
|
|
323
|
-
((pos < src_len) && (s.
|
|
323
|
+
((pos < src_len) && (s.byte_at(pos) == _QUESTION)) => {
|
|
324
324
|
pos = (pos + usize(1)); // skip '?'
|
|
325
325
|
q_start := pos;
|
|
326
326
|
q_end := src_len;
|
|
327
327
|
qq := pos;
|
|
328
328
|
while(runtime(qq < src_len), {
|
|
329
329
|
cond(
|
|
330
|
-
(s.
|
|
330
|
+
(s.byte_at(qq) == _HASH) => {
|
|
331
331
|
q_end = qq;
|
|
332
332
|
break;
|
|
333
333
|
},
|
|
@@ -338,7 +338,7 @@ impl(
|
|
|
338
338
|
q_bytes := ArrayList(u8).new();
|
|
339
339
|
qb := q_start;
|
|
340
340
|
while(runtime(qb < q_end), {
|
|
341
|
-
q_bytes.push(s.
|
|
341
|
+
q_bytes.push(s.byte_at(qb));
|
|
342
342
|
qb = (qb + usize(1));
|
|
343
343
|
});
|
|
344
344
|
query =.Some(String.from_bytes(q_bytes));
|
|
@@ -349,12 +349,12 @@ impl(
|
|
|
349
349
|
// --- Parse fragment ---
|
|
350
350
|
(fragment : Option(String)) =.None;
|
|
351
351
|
cond(
|
|
352
|
-
((pos < src_len) && (s.
|
|
352
|
+
((pos < src_len) && (s.byte_at(pos) == _HASH)) => {
|
|
353
353
|
pos = (pos + usize(1)); // skip '#'
|
|
354
354
|
f_bytes := ArrayList(u8).new();
|
|
355
355
|
fb := pos;
|
|
356
356
|
while(runtime(fb < src_len), {
|
|
357
|
-
f_bytes.push(s.
|
|
357
|
+
f_bytes.push(s.byte_at(fb));
|
|
358
358
|
fb = (fb + usize(1));
|
|
359
359
|
});
|
|
360
360
|
fragment =.Some(String.from_bytes(f_bytes));
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { Environment } from "../../env";
|
|
2
|
-
import { type FnCallExpr } from "../../expr";
|
|
3
|
-
import type { EvaluatorContext } from "../context";
|
|
4
|
-
export declare function evaluateSliceType({ expr, env, context, }: {
|
|
5
|
-
expr: FnCallExpr;
|
|
6
|
-
env: Environment;
|
|
7
|
-
context: EvaluatorContext;
|
|
8
|
-
}): FnCallExpr;
|