hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit c8fa5a819a862b7e5b0a2bc5a986ca2b79ff0dcb
parent e7705d104acf25a709e9d873a5bdd54f4a664403
Author: Joe Finney <me@spxtr.net>
Date:   Thu, 22 Feb 2024 15:14:29 +0000

strconv: Minor stylistic fixes for stoi/stou.

- Doc string text improved: non-numeric characters are allowed for hex.
- Overflow checks put into a helper function.
- Tests brought into the same file as code. They're simple tests.

Signed-off-by: Joe Finney <me@spxtr.net>

Diffstat:
Dstrconv/+test/stoi_test.ha | 36------------------------------------
Dstrconv/+test/stou_test.ha | 25-------------------------
Mstrconv/stoi.ha | 162+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mstrconv/stou.ha | 162+++++++++++++++++++++++++++++++++++++++----------------------------------------
4 files changed, 168 insertions(+), 217 deletions(-)

diff --git a/strconv/+test/stoi_test.ha b/strconv/+test/stoi_test.ha @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// (c) Hare authors <https://harelang.org> - -use types; - -@test fn stoi() void = { - assert(stoi64("") as invalid == 0); - assert(stoi64("abc") as invalid == 0); - assert(stoi64("1a") as invalid == 1); - assert(stoi64("+") as invalid == 1); - assert(stoi64("-+") as invalid == 1); - assert(stoi64("-z") as invalid == 1); - - assert(stoi64("9223372036854775808") is overflow); - assert(stoi64("-9223372036854775809") is overflow); - - assert(stoi64("0") as i64 == 0); - assert(stoi64("1") as i64 == 1); - assert(stoi64("+1") as i64 == 1); - assert(stoi64("-1") as i64 == -1); - assert(stoi64("9223372036854775807") as i64 == types::I64_MAX); - assert(stoi64("-9223372036854775808") as i64 == types::I64_MIN); - - assert(stoi32("2147483648") is overflow); - assert(stoi32("-2147483649") is overflow); - - assert(stoi32("2147483647") as i32 == 2147483647); - assert(stoi32("-2147483648") as i32 == -2147483648); -}; - -@test fn stoib() void = { - assert(stoi64b("-7f", 16) as i64 == -0x7f); - assert(stoi64b("7F", 16) as i64 == 0x7f); - assert(stoi64b("37", 8) as i64 == 0o37); - assert(stoi64b("-110101", 2) as i64 == -0b110101); -}; diff --git a/strconv/+test/stou_test.ha b/strconv/+test/stou_test.ha @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// (c) Hare authors <https://harelang.org> - -@test fn stou() void = { - assert(stou64("") as invalid == 0); - assert(stou64("+") as invalid == 1); - assert(stou64("+a") as invalid == 1); - assert(stou64("abc") as invalid == 0); - assert(stou64("1a") as invalid == 1); - - assert(stou64("18446744073709551616") is overflow); - assert(stou64("184467440737095516150") is overflow); - assert(stou64("-1") is overflow); - - assert(stou64("0") as u64 == 0); - assert(stou64("1") as u64 == 1); - assert(stou64("18446744073709551615") as u64 == 18446744073709551615); -}; - -@test fn stoub() void = { - assert(stou64b("7f", 16) as u64 == 0x7f); - assert(stou64b("7F", 16) as u64 == 0x7f); - assert(stou64b("37", 8) as u64 == 0o37); - assert(stou64b("110101", 2) as u64 == 0b110101); -}; diff --git a/strconv/stoi.ha b/strconv/stoi.ha @@ -4,10 +4,9 @@ use strings; use types; -// Converts a string to an i64 in the given base. If the string contains any -// non-numeric characters, except '-' or '+' at the start, or if it's empty, -// [[invalid]] is returned. If the number is too large to be represented by an -// i64, [[overflow]] is returned. +// Converts a string to an i64 in the given base. Returns [[invalid]] if the +// string is empty or contains invalid characters. Returns [[overflow]] if the +// number is too large to be represented by an i64. export fn stoi64b(s: str, base: base) (i64 | invalid | overflow) = { let (sign, u) = parseint(s, base)?; // Two's complement: I64_MIN = -I64_MAX - 1 @@ -18,79 +17,96 @@ export fn stoi64b(s: str, base: base) (i64 | invalid | overflow) = { return u: i64 * (if (sign) -1 else 1); }; -// Converts a string to an i32 in the given base. If the string contains any -// non-numeric characters, except '-' or '+' at the start, or if it's empty, -// [[invalid]] is returned. If the number is too large to be represented by an -// i32, [[overflow]] is returned. -export fn stoi32b(s: str, base: base) (i32 | invalid | overflow) = { - let n = stoi64b(s, base)?; - if (n >= types::I32_MIN: i64 && n <= types::I32_MAX: i64) { - return n: i32; +fn stoiminmax( + s: str, + base: base, + min: i64, + max: i64, +) (i64 | invalid | overflow) = { + const n = stoi64b(s, base)?; + if (n < min || n > max) { + return overflow; }; - return overflow; + return n; }; -// Converts a string to an i16 in the given base. If the string contains any -// non-numeric characters, except '-' or '+' at the start, or if it's empty, -// [[invalid]] is returned. If the number is too large to be represented by an -// i16, [[overflow]] is returned. -export fn stoi16b(s: str, base: base) (i16 | invalid | overflow) = { - let n = stoi64b(s, base)?; - if (n >= types::I16_MIN: i64 && n <= types::I16_MAX: i64) { - return n: i16; - }; - return overflow; -}; +// Converts a string to an i32 in the given base. Returns [[invalid]] if the +// string is empty or contains invalid characters. Returns [[overflow]] if the +// number is too large to be represented by an i32. +export fn stoi32b(s: str, base: base) (i32 | invalid | overflow) = + stoiminmax(s, base, types::I32_MIN, types::I32_MAX)?: i32; -// Converts a string to an i8 in the given base. If the string contains any -// non-numeric characters, except '-' or '+' at the start, or if it's empty, -// [[invalid]] is returned. If the number is too large to be represented by an -// i8, [[overflow]] is returned. -export fn stoi8b(s: str, base: base) (i8 | invalid | overflow) = { - let n= stoi64b(s, base)?; - if (n >= types::I8_MIN: i64 && n <= types::I8_MAX: i64) { - return n: i8; - }; - return overflow; -}; +// Converts a string to an i16 in the given base. Returns [[invalid]] if the +// string is empty or contains invalid characters. Returns [[overflow]] if the +// number is too large to be represented by an i16. +export fn stoi16b(s: str, base: base) (i16 | invalid | overflow) = + stoiminmax(s, base, types::I16_MIN, types::I16_MAX)?: i16; + +// Converts a string to an i8 in the given base. Returns [[invalid]] if the +// string is empty or contains invalid characters. Returns [[overflow]] if the +// number is too large to be represented by an i8. +export fn stoi8b(s: str, base: base) (i8 | invalid | overflow) = + stoiminmax(s, base, types::I8_MIN, types::I8_MAX)?: i8; + +// Converts a string to an int in the given base. Returns [[invalid]] if the +// string is empty or contains invalid characters. Returns [[overflow]] if the +// number is too large to be represented by an int. +export fn stoib(s: str, base: base) (int | invalid | overflow) = + stoiminmax(s, base, types::INT_MIN, types::INT_MAX)?: int; + +// Converts a string to an i64 in base 10. Returns [[invalid]] if the string is +// empty or contains invalid characters. Returns [[overflow]] if the number is +// too large to be represented by an i64. +export fn stoi64(s: str) (i64 | invalid | overflow) = stoi64b(s, base::DEC); + +// Converts a string to an i32 in base 10. Returns [[invalid]] if the string is +// empty or contains invalid characters. Returns [[overflow]] if the number is +// too large to be represented by an i32. +export fn stoi32(s: str) (i32 | invalid | overflow) = stoi32b(s, base::DEC); -// Converts a string to an int in the given base. If the string contains any -// non-numeric characters, except '-' or '+' at the start, or if it's empty, -// [[invalid]] is returned. If the number is too large to be represented by an -// int, [[overflow]] is returned. -export fn stoib(s: str, base: base) (int | invalid | overflow) = { - static assert(size(int) == size(i32) || size(int) == size(i64)); - return - if (size(int) == size(i32)) stoi32b(s, base)?: int - else stoi64b(s, base)?: int; +// Converts a string to an i16 in base 10. Returns [[invalid]] if the string is +// empty or contains invalid characters. Returns [[overflow]] if the number is +// too large to be represented by an i16. +export fn stoi16(s: str) (i16 | invalid | overflow) = stoi16b(s, base::DEC); + +// Converts a string to an i8 in base 10. Returns [[invalid]] if the string is +// empty or contains invalid characters. Returns [[overflow]] if the number is +// too large to be represented by an i8. +export fn stoi8(s: str) (i8 | invalid | overflow) = stoi8b(s, base::DEC); + +// Converts a string to an int in base 10. Returns [[invalid]] if the string is +// empty or contains invalid characters. Returns [[overflow]] if the number is +// too large to be represented by an int. +export fn stoi(s: str) (int | invalid | overflow) = stoib(s, base::DEC); + +@test fn stoi() void = { + assert(stoi64("") as invalid == 0); + assert(stoi64("abc") as invalid == 0); + assert(stoi64("1a") as invalid == 1); + assert(stoi64("+") as invalid == 1); + assert(stoi64("-+") as invalid == 1); + assert(stoi64("-z") as invalid == 1); + + assert(stoi64("9223372036854775808") is overflow); + assert(stoi64("-9223372036854775809") is overflow); + + assert(stoi64("0") as i64 == 0); + assert(stoi64("1") as i64 == 1); + assert(stoi64("+1") as i64 == 1); + assert(stoi64("-1") as i64 == -1); + assert(stoi64("9223372036854775807") as i64 == types::I64_MAX); + assert(stoi64("-9223372036854775808") as i64 == types::I64_MIN); + + assert(stoi32("2147483648") is overflow); + assert(stoi32("-2147483649") is overflow); + + assert(stoi32("2147483647") as i32 == 2147483647); + assert(stoi32("-2147483648") as i32 == -2147483648); }; -// Converts a string to an i64 in base 10, If the string contains any -// non-numeric characters, or if it's empty, [[invalid]] is returned. If the -// number is too large to be represented by an i64, [[overflow]] is -// returned. -export fn stoi64(s: str) (i64 | invalid | overflow) = stoi64b(s, 10); - -// Converts a string to an i32 in base 10, If the string contains any -// non-numeric characters, or if it's empty, [[invalid]] is returned. If the -// number is too large to be represented by an i32, [[overflow]] is -// returned. -export fn stoi32(s: str) (i32 | invalid | overflow) = stoi32b(s, 10); - -// Converts a string to an i16 in base 10, If the string contains any -// non-numeric characters, or if it's empty, [[invalid]] is returned. If the -// number is too large to be represented by an i16, [[overflow]] is -// returned. -export fn stoi16(s: str) (i16 | invalid | overflow) = stoi16b(s, 10); - -// Converts a string to an i8 in base 10, If the string contains any -// non-numeric characters, or if it's empty, [[invalid]] is returned. If the -// number is too large to be represented by an i8, [[overflow]] is -// returned. -export fn stoi8(s: str) (i8 | invalid | overflow) = stoi8b(s, 10); - -// Converts a string to an int in base 10, If the string contains any -// non-numeric characters, or if it's empty, [[invalid]] is returned. If the -// number is too large to be represented by an int, [[overflow]] is -// returned. -export fn stoi(s: str) (int | invalid | overflow) = stoib(s, 10); +@test fn stoib() void = { + assert(stoi64b("-7f", 16) as i64 == -0x7f); + assert(stoi64b("7F", 16) as i64 == 0x7f); + assert(stoi64b("37", 8) as i64 == 0o37); + assert(stoi64b("-110101", 2) as i64 == -0b110101); +}; diff --git a/strconv/stou.ha b/strconv/stou.ha @@ -63,9 +63,9 @@ fn parseint(s: str, base: base) ((bool, u64) | invalid | overflow) = { return (sign, n); }; -// Converts a string to a u64 in the given base, If the string contains any -// non-numeric characters, or if it's empty, [[invalid]] is returned. If the -// number is too large to be represented by a u64, [[overflow]] is returned. +// Converts a string to a u64 in the given base. Returns [[invalid]] if the +// string is empty or contains invalid characters. Returns [[overflow]] if the +// number is too large to be represented by a u64. export fn stou64b(s: str, base: base) (u64 | invalid | overflow) = { let (sign, u) = parseint(s, base)?; if (sign) { @@ -74,97 +74,93 @@ export fn stou64b(s: str, base: base) (u64 | invalid | overflow) = { return u; }; -// Converts a string to a u32 in the given base, If the string contains any -// non-numeric characters, or if it's empty, [[invalid]] is returned. If the -// number is too large to be represented by a u32, [[overflow]] is returned. -export fn stou32b(s: str, base: base) (u32 | invalid | overflow) = { - let n = stou64b(s, base)?; - if (n <= types::U32_MAX: u64) { - return n: u32; - }; - return overflow; -}; - -// Converts a string to a u16 in the given base, If the string contains any -// non-numeric characters, or if it's empty, [[invalid]] is returned. If the -// number is too large to be represented by a u16, [[overflow]] is returned. -export fn stou16b(s: str, base: base) (u16 | invalid | overflow) = { - let n = stou64b(s, base)?; - if (n <= types::U16_MAX: u64) { - return n: u16; - }; - return overflow; -}; - -// Converts a string to a u8 in the given base, If the string contains any -// non-numeric characters, or if it's empty, [[invalid]] is returned. If the -// number is too large to be represented by a u8, [[overflow]] is returned. -export fn stou8b(s: str, base: base) (u8 | invalid | overflow) = { - let n = stou64b(s, base)?; - if (n <= types::U8_MAX: u64) { - return n: u8; - }; - return overflow; -}; - -// Converts a string to a uint in the given base, If the string contains any -// non-numeric characters, or if it's empty, [[invalid]] is returned. If the -// number is too large to be represented by a uint, [[overflow]] is returned. -export fn stoub(s: str, base: base) (uint | invalid | overflow) = { - static assert(size(uint) == size(u32) || size(uint) == size(u64)); - return - if (size(uint) == size(u32)) stou32b(s, base)?: uint - else stou64b(s, base)?: uint; -}; - -// Converts a string to a size in the given base, If the string contains any -// non-numeric characters, or if it's empty, [[invalid]] is returned. If the -// number is too large to be represented by a size, [[overflow]] is returned. -export fn stozb(s: str, base: base) (size | invalid | overflow) = { - static assert(size(size) == size(u32) || size(size) == size(u64)); - if (size(size) == size(u32)) { - match (stou32b(s, base)) { - case let v: (invalid | overflow) => - return v; - case let n: u32 => - return n: size; - }; - } else { - match (stou64b(s, base)) { - case let v: (invalid | overflow) => - return v; - case let n: u64 => - return n: size; - }; +fn stoumax(s: str, base: base, max: u64) (u64 | invalid | overflow) = { + const n = stou64b(s, base)?; + if (n > max) { + return overflow; }; + return n; }; -// Converts a string to a u64 in base 10, If the string contains any -// non-numeric characters, or if it's empty, [[invalid]] is returned. If the -// number is too large to be represented by a u64, [[overflow]] is returned. +// Converts a string to a u32 in the given base. Returns [[invalid]] if the +// string is empty or contains invalid characters. Returns [[overflow]] if the +// number is too large to be represented by a u32. +export fn stou32b(s: str, base: base) (u32 | invalid | overflow) = + stoumax(s, base, types::U32_MAX)?: u32; + +// Converts a string to a u16 in the given base. Returns [[invalid]] if the +// string is empty or contains invalid characters. Returns [[overflow]] if the +// number is too large to be represented by a u16. +export fn stou16b(s: str, base: base) (u16 | invalid | overflow) = + stoumax(s, base, types::U16_MAX)?: u16; + +// Converts a string to a u8 in the given base. Returns [[invalid]] if the +// string is empty or contains invalid characters. Returns [[overflow]] if the +// number is too large to be represented by a u8. +export fn stou8b(s: str, base: base) (u8 | invalid | overflow) = + stoumax(s, base, types::U8_MAX)?: u8; + +// Converts a string to a uint in the given base. Returns [[invalid]] if the +// string is empty or contains invalid characters. Returns [[overflow]] if the +// number is too large to be represented by a uint. +export fn stoub(s: str, base: base) (uint | invalid | overflow) = + stoumax(s, base, types::UINT_MAX)?: uint; + +// Converts a string to a size in the given base. Returns [[invalid]] if the +// string is empty or contains invalid characters. Returns [[overflow]] if the +// number is too large to be represented by a size. +export fn stozb(s: str, base: base) (size | invalid | overflow) = + stoumax(s, base, types::SIZE_MAX)?: size; + +// Converts a string to a u64 in base 10. Returns [[invalid]] if the string is +// empty or contains invalid characters. Returns [[overflow]] if the number is +// too large to be represented by a u64. export fn stou64(s: str) (u64 | invalid | overflow) = stou64b(s, base::DEC); -// Converts a string to a u32 in base 10, If the string contains any -// non-numeric characters, or if it's empty, [[invalid]] is returned. If the -// number is too large to be represented by a u32, [[overflow]] is returned. +// Converts a string to a u32 in base 10. Returns [[invalid]] if the string is +// empty or contains invalid characters. Returns [[overflow]] if the number is +// too large to be represented by a u32. export fn stou32(s: str) (u32 | invalid | overflow) = stou32b(s, base::DEC); -// Converts a string to a u16 in base 10, If the string contains any -// non-numeric characters, or if it's empty, [[invalid]] is returned. If the -// number is too large to be represented by a u16, [[overflow]] is returned. +// Converts a string to a u16 in base 10. Returns [[invalid]] if the string is +// empty or contains invalid characters. Returns [[overflow]] if the number is +// too large to be represented by a u16. export fn stou16(s: str) (u16 | invalid | overflow) = stou16b(s, base::DEC); -// Converts a string to a u8 in base 10, If the string contains any -// non-numeric characters, or if it's empty, [[invalid]] is returned. If the -// number is too large to be represented by a u8, [[overflow]] is returned. +// Converts a string to a u8 in base 10. Returns [[invalid]] if the string is +// empty or contains invalid characters. Returns [[overflow]] if the number is +// too large to be represented by a u8. export fn stou8(s: str) (u8 | invalid | overflow) = stou8b(s, base::DEC); -// Converts a string to a uint in base 10, If the string contains any -// non-numeric characters, or if it's empty, [[invalid]] is returned. If the -// number is too large to be represented by a uint, [[overflow]] is returned. +// Converts a string to a uint in base 10. Returns [[invalid]] if the string is +// empty or contains invalid characters. Returns [[overflow]] if the number is +// too large to be represented by a uint. export fn stou(s: str) (uint | invalid | overflow) = stoub(s, base::DEC); -// Converts a string to a size in base 10, If the string contains any -// non-numeric characters, or if it's empty, [[invalid]] is returned. If the -// number is too large to be represented by a size, [[overflow]] is returned. +// Converts a string to a size in base 10. Returns [[invalid]] if the string is +// empty or contains invalid characters. Returns [[overflow]] if the number is +// too large to be represented by a size. export fn stoz(s: str) (size | invalid | overflow) = stozb(s, base::DEC); + +@test fn stou() void = { + assert(stou64("") as invalid == 0); + assert(stou64("+") as invalid == 1); + assert(stou64("+a") as invalid == 1); + assert(stou64("abc") as invalid == 0); + assert(stou64("1a") as invalid == 1); + + assert(stou64("18446744073709551616") is overflow); + assert(stou64("184467440737095516150") is overflow); + assert(stou64("-1") is overflow); + + assert(stou64("0") as u64 == 0); + assert(stou64("1") as u64 == 1); + assert(stou64("18446744073709551615") as u64 == 18446744073709551615); +}; + +@test fn stoub() void = { + assert(stou64b("7f", 16) as u64 == 0x7f); + assert(stou64b("7F", 16) as u64 == 0x7f); + assert(stou64b("37", 8) as u64 == 0o37); + assert(stou64b("110101", 2) as u64 == 0b110101); +};