From 45f08639bf85eaa0dfa532bd20acd7193a031593 Mon Sep 17 00:00:00 2001 From: LunaStev Date: Wed, 14 Jan 2026 22:26:05 +0900 Subject: [PATCH] feat: expand standard library with math and string modules This commit populates the Wave standard library with foundational modules for mathematics and string manipulation. It also updates the library manifest and provides a basic README. Changes: - **Library Infrastructure**: - Added `std/README.md` to define the library's scope. - Updated `std/manifest.json` to include the `math` and `string` modules. - **`std/math` Module**: - `bits.wave`: Implemented bitwise utilities including `is_pow2`, `popcount`, `ctz32`, and integer logarithm functions (`ilog2`). - `float.wave`: Added `abs`, `min`, `max`, and `clamp` for `f32`. - `int.wave`: Added integer utilities including `abs`, `sign`, parity checks, ceiling/floor division, and a pointer-based `swap_i32`. - `num.wave`: Implemented `gcd`, `lcm`, and exponentiation (`pow_i32`). - **`std/string` Module**: - `ascii.wave`: Added ASCII character classification (digit, alpha, space, etc.) and case conversion. - `cmp.wave`: Implemented string equality, lexical comparison, and prefix/suffix checks (`starts_with`, `ends_with`). - `find.wave`: Added character and substring searching logic, including `find`, `contains`, and `count`. - `len.wave`: Added basic length and empty-string checks. - `trim.wave`: Implemented index-based whitespace trimming for strings. - **Cleanup**: - Removed obsolete `import("std::iosys")` calls from test files. These additions provide the essential building blocks for writing complex Wave applications using standardized utility functions. Signed-off-by: LunaStev --- std/README.md | 3 + std/io/format.wave | 3 - std/manifest.json | 2 +- std/math/bits.wave | 84 ++++++++++++++++++++++++ std/math/float.wave | 35 ++++++++++ std/math/int.wave | 94 +++++++++++++++++++++++++++ std/math/num.wave | 53 +++++++++++++++ std/string/ascii.wave | 83 +++++++++++++++++++++++ std/string/cmp.wave | 86 ++++++++++++++++++++++++ std/string/find.wave | 148 ++++++++++++++++++++++++++++++++++++++++++ std/string/hash.wave | 0 std/string/len.wave | 14 ++++ std/string/trim.wave | 49 ++++++++++++++ test/test3.wave | 2 - test/test58.wave | 2 - 15 files changed, 650 insertions(+), 8 deletions(-) create mode 100644 std/README.md delete mode 100644 std/io/format.wave create mode 100644 std/math/bits.wave create mode 100644 std/math/float.wave create mode 100644 std/math/int.wave create mode 100644 std/math/num.wave create mode 100644 std/string/ascii.wave create mode 100644 std/string/cmp.wave create mode 100644 std/string/find.wave create mode 100644 std/string/hash.wave create mode 100644 std/string/len.wave create mode 100644 std/string/trim.wave diff --git a/std/README.md b/std/README.md new file mode 100644 index 00000000..1ce852a7 --- /dev/null +++ b/std/README.md @@ -0,0 +1,3 @@ +# Wave Standard Library + +This is Wave's standard library. This standard library operates independently of Wave's compiler and is not part of the compiler itself. \ No newline at end of file diff --git a/std/io/format.wave b/std/io/format.wave deleted file mode 100644 index 9a66ebe3..00000000 --- a/std/io/format.wave +++ /dev/null @@ -1,3 +0,0 @@ -fun std_format_dummy() { - println("std::io::format loaded"); -} \ No newline at end of file diff --git a/std/manifest.json b/std/manifest.json index 30d3b55e..99c3c43c 100644 --- a/std/manifest.json +++ b/std/manifest.json @@ -1,5 +1,5 @@ { "name": "std", "format": 1, - "modules": ["io", "fs", "net", "math", "sys", "json"] + "modules": ["string", "math"] } diff --git a/std/math/bits.wave b/std/math/bits.wave new file mode 100644 index 00000000..af44114b --- /dev/null +++ b/std/math/bits.wave @@ -0,0 +1,84 @@ +fun is_pow2(x: i32) -> bool { + if (x <= 0) { + return false; + } + + if ((x & (x - 1)) == 0) { + return true; + } + + return false; +} + +fun align_down(x: i32, align: i32) -> i32 { + if (align <= 0) { + return x; + } + + return x & ~(align - 1); +} + +fun align_up(x: i32, align: i32) -> i32 { + if (align <= 0) { + return x; + } + + return (x + (align - 1)) & ~(align - 1); +} + +fun low_bit(x: i32) -> i32 { + return x & (-x); +} + +fun popcount(x0: i32) -> i32 { + let mut x: i32 = x0; + let mut c: i32 = 0; + + while (x != 0) { + x = x & (x - 1); + c += 1; + } + + return c; +} + +fun ctz32(x: i32) -> i32 { + if (x == 0) { + return 32; + } + + let lb: i32 = low_bit(x); + return popcount(lb - 1); +} + +fun bit_length(x0: i32) -> i32 { + if (x0 <= 0) { + return 0; + } + + let mut x: i32 = x0; + let mut n: i32 = 0; + + while (x > 0) { + x = x >> 1; + n += 1; + } + + return n; +} + +fun ilog2_floor(x: i32) -> i32 { + if (x <= 0) { + return -1; + } + + return bit_length(x) - 1; +} + +fun ilog2_ceil(x: i32) -> i32 { + if (x <= 1) { + return 0; + } + + return ilog2_floor(x - 1) + 1; +} diff --git a/std/math/float.wave b/std/math/float.wave new file mode 100644 index 00000000..52f65898 --- /dev/null +++ b/std/math/float.wave @@ -0,0 +1,35 @@ +fun abs_f32(x: f32) -> f32 { + if (x < 0.0) { + return -x; + } + + return x; +} + +fun min_f32(a: f32, b: f32) -> f32 { + if (a < b) { + return a; + } + + return b; +} + +fun max_f32(a: f32, b: f32) -> f32 { + if (a > b) { + return a; + } + + return b; +} + +fun clamp_f32(x: f32, lo: f32, hi: f32) -> f32 { + if (x < lo) { + return lo; + } + + if (x > hi) { + return hi; + } + + return x; +} diff --git a/std/math/int.wave b/std/math/int.wave new file mode 100644 index 00000000..57896425 --- /dev/null +++ b/std/math/int.wave @@ -0,0 +1,94 @@ +fun abs(x: i32) -> i32 { + if (x < 0) { + return -x; + } + + return x; +} + +fun min(a: i32, b: i32) -> i32 { + if (a < b) { + return a; + } + + return b; +} + +fun max(a: i32, b: i32) -> i32 { + if (a > b) { + return a; + } + + return b; +} + +fun clamp(x: i32, lo: i32, hi: i32) -> i32 { + if (x < lo) { + return lo; + } + + if (x > hi) { + return hi; + } + + return x; +} + +fun sign(x: i32) -> i32 { + if (x < 0) { + return -1; + } + + if (x > 0) { + return 1; + } + + return 0; +} + +fun is_even(x: i32) -> bool { + if ((x % 2) == 0) { + return true; + } + + return false; +} + +fun is_odd(x: i32) -> bool { + if ((x % 2) != 0) { + return true; + } + + return false; +} + +fun div_ceil_pos(a: i32, b: i32) -> i32 { + if (b == 0) { + return 0; + } + + if (a <= 0) { + return 0; + } + + return (a + (b - 1)) / b; +} + +fun div_floor_pos(a: i32, b: i32) -> i32 { + if (b == 0) { + return 0; + } + + if (a <= 0) { + return 0; + } + + return a / b; +} + +fun swap_i32(a: ptr, b: ptr) { + let t: i32 = deref a; + + deref a = deref b; + deref b = t; +} diff --git a/std/math/num.wave b/std/math/num.wave new file mode 100644 index 00000000..a43a3798 --- /dev/null +++ b/std/math/num.wave @@ -0,0 +1,53 @@ +fun gcd(a0: i32, b0: i32) -> i32 { + let mut a: i32 = a0; + let mut b: i32 = b0; + + if (a < 0) { + a = -a; + } + + if (b < 0) { + b = -b; + } + + while (b != 0) { + let t: i32 = a % b; + a = b; + b = t; + } + + return a; +} + +fun lcm(a: i32, b: i32) -> i32 { + if (a == 0 || b == 0) { + return 0; + } + + let g: i32 = gcd(a, b); + let x: i32 = a / g; + let mut r: i32 = x * b; + + if (r < 0) { + r = -r; + } + + return r; +} + +fun pow_i32(base0: i32, exp0: i32) -> i32 { + let mut base: i32 = base0; + let mut exp: i32 = exp0; + let mut result: i32 = 1; + + while (exp > 0) { + if ((exp & 1) == 1) { + result = result * base; + } + + base = base * base; + exp = exp >> 1; + } + + return result; +} diff --git a/std/string/ascii.wave b/std/string/ascii.wave new file mode 100644 index 00000000..27f4c03c --- /dev/null +++ b/std/string/ascii.wave @@ -0,0 +1,83 @@ +fun is_digit(c: u8) -> bool { + if (c >= 48 && c <= 57) { + return true; + } + + return false; +} + +fun is_lower(c: u8) -> bool { + if (c >= 97 && c <= 122) { + return true; + } + + return false; +} + +fun is_upper(c: u8) -> bool { + if (c >= 65 && c <= 90) { + return true; + } + + return false; +} + +fun is_alpha(c: u8) -> bool { + if (is_lower(c)) { + return true; + } + + if (is_upper(c)) { + return true; + } + + return false; +} + +fun is_alnum(c: u8) -> bool { + if (is_alpha(c)) { + return true; + } + + if (is_digit(c)) { + return true; + } + + return false; +} + +fun is_space(c: u8) -> bool { + if (c == 32) { + return true; + } + + if (c == 9) { + return true; + } + + if (c == 10) { + return true; + } + + if (c == 13) { + return true; + } + + return false; +} + +fun to_lower(c: u8) -> u8 { + if (is_upper(c)) { + return c + 32; + } + + return c; +} + +fun to_upper(c: u8) -> u8 { + if (is_lower(c)) { + return c - 32; + } + + return c; +} diff --git a/std/string/cmp.wave b/std/string/cmp.wave new file mode 100644 index 00000000..88005c88 --- /dev/null +++ b/std/string/cmp.wave @@ -0,0 +1,86 @@ +fun eq(a: str, b: str) -> bool { + let mut i: i32 = 0; + + while (true) { + let ca: u8 = a[i]; + let cb: u8 = b[i]; + + if (ca != cb) { + return false; + } + + if (ca == 0) { + return true; + } + + i += 1; + } + + return true; +} + +fun cmp(a: str, b: str) -> i32 { + let mut i: i32 = 0; + + while (true) { + let ca: u8 = a[i]; + let cb: u8 = b[i]; + + if (ca < cb) { + return -1; + } + + if (ca > cb) { + return 1; + } + + if (ca == 0) { + return 0; + } + + i += 1; + } + + return 0; +} + +fun starts_with(s: str, prefix: str) -> bool { + let mut i: i32 = 0; + + while (prefix[i] != 0) { + if (s[i] != prefix[i]) { + return false; + } + + i += 1; + } + + return true; +} + +fun ends_with(s: str, suffix: str) -> bool { + let mut sl: i32 = 0; + while (s[sl] != 0) { + sl += 1; + } + + let mut tl: i32 = 0; + while (suffix[tl] != 0) { + tl += 1; + } + + if (tl > sl) { + return false; + } + + let mut i: i32 = 0; + while (i < tl) { + if (s[sl - tl + i] != suffix[i]) { + return false; + } + + i += 1; + } + + return true; +} diff --git a/std/string/find.wave b/std/string/find.wave new file mode 100644 index 00000000..40b087a6 --- /dev/null +++ b/std/string/find.wave @@ -0,0 +1,148 @@ +fun find_char(s: str, c: u8) -> i32 { + let mut i: i32 = 0; + + while (s[i] != 0) { + if (s[i] == c) { + return i; + } + + i += 1; + } + + return -1; +} + +fun rfind_char(s: str, c: u8) -> i32 { + let mut last: i32 = -1; + let mut i: i32 = 0; + + while (s[i] != 0) { + if (s[i] == c) { + last = i; + } + + i += 1; + } + + return last; +} + +fun contains_char(s: str, c: u8) -> bool { + if (find_char(s, c) != -1) { + return true; + } + + return false; +} + +fun count_char(s: str, c: u8) -> i32 { + let mut i: i32 = 0; + let mut count: i32 = 0; + + while (s[i] != 0) { + if (s[i] == c) { + count += 1; + } + + i += 1; + } + + return count; +} + +fun find(s: str, needle: str) -> i32 { + if (needle[0] == 0) { + return 0; + } + + let mut nl: i32 = 0; + while (needle[nl] != 0) { + nl += 1; + } + + let mut sl: i32 = 0; + while (s[sl] != 0) { + sl += 1; + } + + if (nl > sl) { + return -1; + } + + let mut i: i32 = 0; + while (i <= (sl - nl)) { + let mut j: i32 = 0; + let mut ok: bool = true; + + while (j < nl) { + if (s[i + j] != needle[j]) { + ok = false; + j = nl; + } else { + j += 1; + } + } + + if (ok) { + return i; + } + + i += 1; + } + + return -1; +} + +fun contains(s: str, needle: str) -> bool { + if (find(s, needle) != -1) { + return true; + } + + return false; +} + +fun count(s: str, needle: str) -> i32 { + if (needle[0] == 0) { + return 0; + } + + let mut nl: i32 = 0; + while (needle[nl] != 0) { + nl += 1; + } + + let mut sl: i32 = 0; + while (s[sl] != 0) { + sl += 1; + } + + if (nl > sl) { + return 0; + } + + let mut i: i32 = 0; + let mut total: i32 = 0; + + while (i <= (sl - nl)) { + let mut j: i32 = 0; + let mut ok: bool = true; + + while (j < nl) { + if (s[i + j] != needle[j]) { + ok = false; + j = nl; + } else { + j += 1; + } + } + + if (ok) { + total += 1; + i += nl; + } else { + i += 1; + } + } + + return total; +} diff --git a/std/string/hash.wave b/std/string/hash.wave new file mode 100644 index 00000000..e69de29b diff --git a/std/string/len.wave b/std/string/len.wave new file mode 100644 index 00000000..417d3c04 --- /dev/null +++ b/std/string/len.wave @@ -0,0 +1,14 @@ +fun len(s: str) -> i32 { + let mut i: i32 = 0; + while (s[i] != 0) { + i += 1; + } + return i; +} + +fun is_empty(s: str) -> bool { + if (s[0] == 0) { + return true; + } + return false; +} diff --git a/std/string/trim.wave b/std/string/trim.wave new file mode 100644 index 00000000..6a98e5f8 --- /dev/null +++ b/std/string/trim.wave @@ -0,0 +1,49 @@ +fun trim_left_index(s: str) -> i32 { + let mut i: i32 = 0; + + while (s[i] != 0) { + let c: u8 = s[i]; + + if (c == 32 || c == 9 || c == 10 || c == 13) { + i += 1; + } else { + return i; + } + } + + return i; +} + +fun trim_right_index(s: str) -> i32 { + let mut sl: i32 = 0; + + while (s[sl] != 0) { + sl += 1; + } + + if (sl == 0) { + return 0; + } + + let mut i: i32 = sl - 1; + + while (i >= 0) { + let c: u8 = s[i]; + + if (c == 32 || c == 9 || c == 10 || c == 13) { + i -= 1; + } else { + return i + 1; + } + } + + return 0; +} + +fun trim_range(s: str, out_start: ptr, out_end: ptr) { + let start: i32 = trim_left_index(s); + let end: i32 = trim_right_index(s); + + deref out_start = start; + deref out_end = end; +} diff --git a/test/test3.wave b/test/test3.wave index e4164624..305fb497 100644 --- a/test/test3.wave +++ b/test/test3.wave @@ -1,5 +1,3 @@ -import("std::iosys"); - fun main() { let a :i32 = 10; var b :i32 = 5; diff --git a/test/test58.wave b/test/test58.wave index 91b5fc6a..ca7c183c 100644 --- a/test/test58.wave +++ b/test/test58.wave @@ -1,5 +1,3 @@ -import("std::iosys"); - fun main() { println("This should fail in standalone mode"); } \ No newline at end of file