hare

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

commit 9244d60cf6ab00f16fd5663f247c7e9f33812762
parent d480082cfec1d2312428784aba7a3d332434e99b
Author: Drew DeVault <sir@cmpwn.com>
Date:   Mon,  1 Feb 2021 19:20:23 -0500

fmt: initial workitude

Diffstat:
Aencoding/utf8/encode.ha | 26++++++++++++++++++++++++++
Mfmt/fmt.ha | 54++++++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 76 insertions(+), 4 deletions(-)

diff --git a/encoding/utf8/encode.ha b/encoding/utf8/encode.ha @@ -0,0 +1,26 @@ +// Encodes a rune as UTF-8 and returns the result as a slice. The result is +// statically allocated; duplicate it if you aren't using it right away. +export fn encode_rune(r: rune) []u8 = { + let ch = r: u32, n = 0z, first = 0u8; + if (ch < 0x80u32) { + first = 0u8; + n = 1z; + } else if (ch < 0x800u32) { + first = 0xC0u8; + n = 2z; + } else if (ch < 0x10000u32) { + first = 0xE0u8; + n = 3z; + } else { + first = 0xF0u8; + n = 4z; + }; + + static let buf: [6]u8 = [0u8...]; + for (let i = n - 1z; i > 0z; i -= 1z) { + buf[i] = ch: u8 & 0x3Fu8 | 0x80u8; + ch >>= 6u32; + }; + buf[0] = ch: u8 | first; + return buf[..n]; +}; diff --git a/fmt/fmt.ha b/fmt/fmt.ha @@ -8,15 +8,61 @@ // used to specify additional constraints on the format in a type-specific // manner: '{0:x} will print a number in hexadecimal. // -// TODO: Document this more I guess +// TODO: More detail +use encoding::utf8; use io; +use strings; +use strconv; use types; // Tagged union of all types which are formattable. export type formattable = (...types::numeric | uintptr | str | *void); // Formats text for printing and writes it to an [io::stream]. -export fn fprintf(s: *io::stream, fmt: str, - args: formattable...) (io::error | size) = { - return io::unsupported: io::error; // TODO: Blocked on rune picking +export fn fprintf( + s: *io::stream, + fmt: str, + args: formattable... +) (io::error | size) = { + let n = 0z, i = 0z; + let iter = strings::iter(fmt); + for (true) { + let r: rune = match (strings::next(&iter)) { + void => break, + r: rune => r, + }; + + if (r == '{') { + r = match (strings::next(&iter)) { + void => abort("Invalid format string (unterminated '{')"), + r: rune => r, + }; + assert(r == '}'); // TODO + format(s, args[i]); + i += 1z; + continue; + }; + + match (io::write(s, utf8::encode_rune(r))) { + err: io::error => return err, + w: size => { + n += w; + }, + }; + }; + + return n; +}; + +fn format(out: *io::stream, arg: formattable) void = { + match (arg) { + // TODO: Use types::numeric (and strconv::numtos) when match is + // more fleshed out + i: int => { + let s = strconv::itos(i); + io::write(out, strings::to_utf8(s)); + }, + s: str => io::write(out, strings::to_utf8(s)), + * => abort("TODO: implement more formattable values"), + }; };