commit 9244d60cf6ab00f16fd5663f247c7e9f33812762
parent d480082cfec1d2312428784aba7a3d332434e99b
Author: Drew DeVault <sir@cmpwn.com>
Date: Mon, 1 Feb 2021 19:20:23 -0500
fmt: initial workitude
Diffstat:
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"),
+ };
};