hare

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

commit fd0359ea21f152be1f82f33db5d3f3b2b297458b
parent 63b409faa151502c7bf219395759986626a9e0c6
Author: Andri Yngvason <andri@yngvason.is>
Date:   Sat,  6 Feb 2021 16:45:08 +0000

strconv: add string-to-integer converter

Diffstat:
Astrconv/+test/stoi.ha | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astrconv/stoi.ha | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 146 insertions(+), 0 deletions(-)

diff --git a/strconv/+test/stoi.ha b/strconv/+test/stoi.ha @@ -0,0 +1,55 @@ +fn is_invalid_i64(value: (i64 | invalid | overflow)) bool = { + return match (value) { + invalid => true, + * => false, + }; +}; + +fn is_overflow_i64(value: (i64 | invalid | overflow)) bool = { + return match (value) { + overflow => true, + * => false, + }; +}; + +fn is_number_i64(n: i64, value: (i64 | invalid | overflow)) bool = { + return match (value) { + v: i64 => v == n, + * => false, + }; +}; + +fn is_overflow_i32(value: (i32 | invalid | overflow)) bool = { + return match (value) { + overflow => true, + * => false, + }; +}; + +fn is_number_i32(n: i32, value: (i32 | invalid | overflow)) bool = { + return match (value) { + v: i32 => v == n, + * => false, + }; +}; + +@test fn stoi() void = { + assert(is_invalid_i64(stoi64(""))); + assert(is_invalid_i64(stoi64("abc"))); + assert(is_invalid_i64(stoi64("1a"))); + + assert(is_overflow_i64(stoi64("9223372036854775808"))); + assert(is_overflow_i64(stoi64("-9223372036854775809"))); + + assert(is_number_i64(0i64, stoi64("0"))); + assert(is_number_i64(1i64, stoi64("1"))); + assert(is_number_i64(-1i64, stoi64("-1"))); + assert(is_number_i64(9223372036854775807i64, stoi64("9223372036854775807"))); + assert(is_number_i64(-9223372036854775808i64, stoi64("-9223372036854775808"))); + + assert(is_overflow_i32(stoi32("2147483648"))); + assert(is_overflow_i32(stoi32("-2147483649"))); + + assert(is_number_i32(2147483647i32, stoi32("2147483647"))); + assert(is_number_i32(-2147483648i32, stoi32("-2147483648"))); +}; diff --git a/strconv/stoi.ha b/strconv/stoi.ha @@ -0,0 +1,91 @@ +use types; +use strings; + +// Converts a string to an i64 in base 10. If the string contains any +// non-numeric characters, except '-' at the start, or if it's empty, +// [strconv::invalid] is returned. If the number is too large to be represented +// by an i64, [strconv::overflow] is returned. +export fn stoi64(s: str) (i64 | invalid | overflow) = { + if (len(s) == 0z) return invalid; + let b = strings::to_utf8(s); + let sign = 1i64; + let max = types::I64_MAX: u64; + if (b[0] == '-': u32: u8) { + sign = -1i64; + max += 1u64; + }; + let u = if (sign < 0i64) stou64(strings::from_utf8_unsafe(b[1..])) + else stou64(s); + match(u) { + v: (invalid | overflow) => return v, + n: u64 => { + if (n > max) { + return overflow; + }; + return n: i64 * sign; + }, + }; +}; + +// Converts a string to an i32 in base 10. If the string contains any +// non-numeric characters, except '-' at the start, or if it's empty, +// [strconv::invalid] is returned. If the number is too large to be represented +// by an i32, [strconv::overflow] is returned. +export fn stoi32(s: str) (i32 | invalid | overflow) = { + match (stoi64(s)) { + v: (invalid | overflow) => return v, + n: i64 => { + if (n >= types::I32_MIN: i64 && n <= types::I32_MAX: i64) { + return n: i32; + }; + return overflow; + }, + }; +}; + +// Converts a string to an i16 in base 10. If the string contains any +// non-numeric characters, except '-' at the start, or if it's empty, +// [strconv::invalid] is returned. If the number is too large to be represented +// by an i16, [strconv::overflow] is returned. +export fn stoi16(s: str) (i16 | invalid | overflow) = { + match (stoi64(s)) { + v: (invalid | overflow) => return v, + n: i64 => { + if (n >= types::I16_MIN: i64 && n <= types::I16_MAX: i64) { + return n: i16; + }; + return overflow; + }, + }; +}; + +// Converts a string to an i8 in base 10. If the string contains any +// non-numeric characters, except '-' at the start, or if it's empty, +// [strconv::invalid] is returned. If the number is too large to be represented +// by an i8, [strconv::overflow] is returned. +export fn stoi8(s: str) (i8 | invalid | overflow) = { + match (stoi64(s)) { + v: (invalid | overflow) => return v, + n: i64 => { + if (n >= types::I8_MIN: i64 && n <= types::I8_MAX: i64) { + return n: i8; + }; + return overflow; + }, + }; +}; + +// Converts a string to an int in base 10. If the string contains any +// non-numeric characters, except '-' at the start, or if it's empty, +// [strconv::invalid] is returned. If the number is too large to be represented +// by an int, [strconv::overflow] is returned. +export fn stoi(s: str) (int | invalid | overflow) = { + static assert(size(int) == size(i32) || size(int) == size(i64)); + return if (size(int) == size(i32)) match (stoi32(s)) { + v: (invalid | overflow) => v, + n: i32 => n: int, + } else match (stoi64(s)) { + v: (invalid | overflow) => v, + n: i64 => n: int, + }; +};