hare

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

commit a451ac939c64cde8ed34e3755e043668b3bd4823
parent 59ee4d834e0661599af4abced30727f27ee458ce
Author: Drew DeVault <sir@cmpwn.com>
Date:   Fri, 12 Feb 2021 10:38:22 -0500

strconv: expand non-decimal base support

- Use an enum for the valid bases
- Update numeric.ha to support bases

Diffstat:
Mstrconv/numeric.ha | 66++++++++++++++++++++++++++++++++++++++++++++++--------------------
Mstrconv/types.ha | 12++++++++++++
Mstrconv/utos.ha | 40+++++++++++++++++++---------------------
3 files changed, 77 insertions(+), 41 deletions(-)

diff --git a/strconv/numeric.ha b/strconv/numeric.ha @@ -1,9 +1,10 @@ use types; -// Converts any [types::signed] to a string in base 10. The return value is +// Converts any [types::signed] to a string in a given base. The return value is // statically allocated and will be overwritten on subsequent calls; see // [strings::dup] to duplicate the result. -export fn signedtos(n: types::signed) const str = { +export fn signedtosb(n: types::signed, b: base) const str = { + assert(b == base::DEC); // TODO return match (n) { i: int => itos(i), i: i8 => i8tos(i), @@ -13,43 +14,68 @@ export fn signedtos(n: types::signed) const str = { }; }; -// Converts any [types::unsigned] to a string in base 10. The return value is +// Converts any [types::signed] to a string in base 10. The return value is // statically allocated and will be overwritten on subsequent calls; see // [strings::dup] to duplicate the result. -export fn unsignedtos(n: types::unsigned) const str = { +export fn signedtos(n: types::signed) const str = signedtosb(n, base::DEC); + +// Converts any [types::unsigned] to a string in a given base. The return value +// is statically allocated and will be overwritten on subsequent calls; see +// [strings::dup] to duplicate the result. +export fn unsignedtosb(n: types::unsigned, b: base) const str = { return match (n) { - u: size => ztos(u), - u: uint => utos(u), - u: u8 => u8tos(u), - u: u16 => u16tos(u), - u: u32 => u32tos(u), - u: u64 => u64tos(u), + u: size => ztosb(u, b), + u: uint => utosb(u, b), + u: u8 => u8tosb(u, b), + u: u16 => u16tosb(u, b), + u: u32 => u32tosb(u, b), + u: u64 => u64tosb(u, b), }; }; -// Converts any [types::integer] to a string in base 10. The return value is +// Converts any [types::unsigned] to a string in base 10. The return value is // statically allocated and will be overwritten on subsequent calls; see // [strings::dup] to duplicate the result. -export fn integertos(n: types::integer) const str = { +export fn unsignedtos(n: types::unsigned) const str = unsignedtosb(n, base::DEC); + +// Converts any [types::integer] to a string in a given base, which must be 2, +// 8, 10, or 16. The return value is statically allocated and will be +// overwritten on subsequent calls; see [strings::dup] to duplicate the result. +export fn integertosb(n: types::integer, b: base) const str = { return match (n) { - s: types::signed => signedtos(s), - u: types::unsigned => unsignedtos(u), + s: types::signed => signedtosb(s, b), + u: types::unsigned => unsignedtosb(u, b), }; }; -// Converts any [types::floating] to a string in base 10. The return value is +// Converts any [types::integer] to a string in base 10. The return value is // statically allocated and will be overwritten on subsequent calls; see // [strings::dup] to duplicate the result. -export fn floatingtos(n: types::floating) const str = { +export fn integertos(n: types::integer) const str = integertosb(n, base::DEC); + +// Converts any [types::floating] to a string in a given base. The return value +// is statically allocated and will be overwritten on subsequent calls; see +// [strings::dup] to duplicate the result. +export fn floatingtosb(n: types::floating, b: base) const str = { abort(); // TODO }; -// Converts any [types::numeric] to a string in base 10. The return value is +// Converts any [types::floating] to a string in base 10. The return value is // statically allocated and will be overwritten on subsequent calls; see // [strings::dup] to duplicate the result. -export fn numerictos(n: types::numeric) const str = { +export fn floatingtos(n: types::floating) const str = floatingtosb(n, base::DEC); + +// Converts any [types::numeric] to a string in a given base. The return value +// is statically allocated and will be overwritten on subsequent calls; see +// [strings::dup] to duplicate the result. +export fn numerictosb(n: types::numeric, b: base) const str = { return match (n) { - i: types::integer => integertos(i), - f: types::floating => floatingtos(f), + i: types::integer => integertosb(i, b), + f: types::floating => floatingtosb(f, b), }; }; + +// Converts any [types::numeric] to a string in base 10. The return value is +// statically allocated and will be overwritten on subsequent calls; see +// [strings::dup] to duplicate the result. +export fn numerictos(n: types::numeric) const str = numerictosb(n, base::DEC); diff --git a/strconv/types.ha b/strconv/types.ha @@ -4,3 +4,15 @@ export type invalid = void; // Indicates that the input number is too large to be represented by the // requested data type export type overflow = void; + +// The valid numeric bases for numeric conversions. +export type base = enum uint { + // Base 2, binary + BIN = 2, + // Base 8, octal + OCT = 8, + // Base 10, decimal + DEC = 10, + // Base 16, hexadecimal + HEX = 16, +}; diff --git a/strconv/utos.ha b/strconv/utos.ha @@ -3,11 +3,9 @@ use types; // Converts a u64 to a string, in the given base. The return value is statically // allocated and will be overwritten on subsequent calls; see [strings::dup] to -// duplicate the result. Valid bases are 2, 8, 10 and 16. -export fn u64tosb(u: u64, base: uint) const str = { +// duplicate the result. +export fn u64tosb(u: u64, b: base) const str = { static assert(types::U64_MAX == 18446744073709551615); - assert(base == 2 || base == 8 || base == 10 || base == 16); - static const lut: [_]rune = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', @@ -23,9 +21,9 @@ export fn u64tosb(u: u64, base: uint) const str = { }; for (u > 0u64) { - buf[s.length] = lut[(u % base: u64)]: u32: u8; + buf[s.length] = lut[(u % b: u64)]: u32: u8; s.length += 1; - u /= base; + u /= b; }; bytes::reverse(buf[..s.length]); @@ -35,33 +33,33 @@ export fn u64tosb(u: u64, base: uint) const str = { // Converts a u32 to a string, in the given base. The return value is statically // allocated and will be overwritten on subsequent calls; see [strings::dup] to -// duplicate the result. Valid bases are 2, 8, 10 and 16. -export fn u32tosb(u: u32, base: uint) const str = u64tosb(u: u32, base); +// duplicate the result. +export fn u32tosb(u: u32, b: base) const str = u64tosb(u: u32, b); // Converts a u16 to a string, in the given base. The return value is statically // allocated and will be overwritten on subsequent calls; see [strings::dup] to -// duplicate the result. Valid bases are 2, 8, 10 and 16. -export fn u16tosb(u: u16, base: uint) const str = u64tosb(u: u16, base); +// duplicate the result. +export fn u16tosb(u: u16, b: base) const str = u64tosb(u: u16, b); // Converts a u8 to a string, in the given base. The return value is statically // allocated and will be overwritten on subsequent calls; see [strings::dup] to -// duplicate the result. Valid bases are 2, 8, 10 and 16. -export fn u8tosb(u: u8, base: uint) const str = u64tosb(u: u8, base); +// duplicate the result. +export fn u8tosb(u: u8, b: base) const str = u64tosb(u: u8, b); // Converts a uint to a string, in the given base. The return value is // statically allocated and will be overwritten on subsequent calls; see -// [strings::dup] to duplicate the result. Valid bases are 2, 8, 10 and 16. -export fn utosb(u: uint, base: uint) const str = u64tosb(u: uint, base); +// [strings::dup] to duplicate the result. +export fn utosb(u: uint, b: base) const str = u64tosb(u: uint, b); // Converts a size to a string, in the given base. The return value is // statically allocated and will be overwritten on subsequent calls; see -// [strings::dup] to duplicate the result. Valid bases are 2, 8, 10 and 16. -export fn ztosb(u: uint, base: uint) const str = u64tosb(u: uint, base); +// [strings::dup] to duplicate the result. +export fn ztosb(u: size, b: base) const str = u64tosb(u: uint, b); // Converts a u64 to a string, in base 10. The return value is statically // allocated and will be overwritten on subsequent calls; see [strings::dup] to // duplicate the result. -export fn u64tos(u: u64) const str = u64tosb(u, 10u); +export fn u64tos(u: u64) const str = u64tosb(u, base::DEC); // Converts a u8 to a string, in base 10. The return value is statically // allocated and will be overwritten on subsequent calls; see [strings::dup] to @@ -94,10 +92,10 @@ export fn ztos(z: size) const str = u64tos(z: u64); export fn uptrtos(uptr: uintptr) const str = u64tos(uptr: u64); @test fn utosb() void = { - assert("11010" == u64tosb(0b11010, 2)); - assert("1234567" == u64tosb(0o1234567, 8)); - assert("123456789" == u64tosb(123456789, 10)); - assert("123456789ABCDEF" == u64tosb(0x123456789ABCDEF, 16)); + assert("11010" == u64tosb(0b11010, base::BIN)); + assert("1234567" == u64tosb(0o1234567, base::OCT)); + assert("123456789" == u64tosb(123456789, base::DEC)); + assert("123456789ABCDEF" == u64tosb(0x123456789ABCDEF, base::HEX)); }; @test fn utos() void = {