~sircmpwn/hare-dev

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
2 2

[PATCH hare] fix fmt::fprintf's '+' and '0' modifiers

Gabriel Schmotzer <smocerg@gmail.com>
Details
Message ID
<20220831164812.313-1-smocerg@gmail.com>
DKIM signature
pass
Download raw message
Patch: +93 -22
Fixes https://todo.sr.ht/~sircmpwn/hare/557

Signed-off-by: Gabriel Schmotzer <smocerg@gmail.com>
---
Additionally, the signature of math::signi was changed to correspond to
the "match" inside it.

 fmt/README   |   4 +-
 fmt/fmt.ha   | 109 ++++++++++++++++++++++++++++++++++++++++++---------
 math/ints.ha |   2 +-
 3 files changed, 93 insertions(+), 22 deletions(-)

diff --git a/fmt/README b/fmt/README
index 337e638e..9eb3a975 100644
--- a/fmt/README
+++ b/fmt/README
@@ -15,14 +15,14 @@ You may use a colon to add format modifiers; for example, "{:x}" will format an
argument in hexadecimal, and "{3:-10}" will left-align the 4rd argument (zero
indexed) to at least 10 characters.

The format modifiers takes the form of an optional flag character:
The format modifiers take the form of optional flag characters:

- "0": Numeric values are zero-padded up to the required width.
- "-": The value shall be left-aligned, and spaces inserted on the right to meet the required width. "-" takes precedence over "0" if both are used.
- " ": (a space) insert a space before positive numbers, where "-" would be if it were negative.
- "+": insert a "+" before positive numbers, where "-" would be if it were negative. "+" takes precedence over " " if both are used.

Following the flag, an optional decimal number shall specify the minimum width
Following the flags, an optional decimal number shall specify the minimum width
of this field. If "0" or "-" were not given, the default behavior shall be to
pad with spaces to achieve the necessary width.

diff --git a/fmt/fmt.ha b/fmt/fmt.ha
index c275ecab..4ddb14e4 100644
--- a/fmt/fmt.ha
+++ b/fmt/fmt.ha
@@ -9,6 +9,7 @@ use ascii;
use bufio;
use encoding::utf8;
use io;
use math;
use os;
use strconv;
use strings;
@@ -292,10 +293,21 @@ fn format(
	arg: formattable,
	mod: *modifiers,
) (size | io::error) = {
	let z = format_raw(io::empty, arg, mod)?;
	let z = 0z;

	let reprlen = 0z;
	if (mod.padding == padding::ALIGN_LEFT) {
		reprlen = format_raw(out, arg, mod, 0, [])?;
		z += reprlen;
	} else {
		reprlen = format_raw(io::empty, arg, mod, 0, [])?;
	};

	let padlen = 0z;
	let pad: []u8 = [];
	if (z < mod.width: size) {

	if (reprlen < mod.width: size) {
		padlen = mod.width: size - reprlen;
		pad = utf8::encoderune(switch (mod.padding) {
		case padding::ZEROES =>
			yield '0';
@@ -304,16 +316,18 @@ fn format(
		});
	};

	if (mod.padding == padding::ALIGN_LEFT) {
		format_raw(out, arg, mod)?;
	};

	for (z < mod.width: size) {
		z += io::write(out, pad)?;
	};

	if (mod.padding != padding::ALIGN_LEFT) {
		format_raw(out, arg, mod)?;
	if (arg is types::numeric && mod.padding == padding::ZEROES) {
		// if padlen != 0, then inner padding will be applied
		z += format_raw(out, arg, mod, padlen, pad)?;
	}
	else {
		for (let i = 0z; i < padlen) {
			i += io::write(out, pad)?;
		};
		z += padlen;
		if (mod.padding != padding::ALIGN_LEFT) {
			z += format_raw(out, arg, mod, 0, [])?;
		};
	};

	return z;
@@ -323,6 +337,8 @@ fn format_raw(
	out: io::handle,
	arg: formattable,
	mod: *modifiers,
	padlen: size,
	pad: []u8,
) (size | io::error) = {
	match (arg) {
	case let s: str =>
@@ -333,27 +349,62 @@ fn format_raw(
		return io::write(out,
			strings::toutf8(if (b) "true" else "false"));
	case let n: types::numeric =>
		const s = strconv::numerictosb(n, mod.base);
		return io::write(out, strings::toutf8(s));
		const (s1, s2) = get_split_number_repr(n, mod);
		let z = io::write(out, strings::toutf8(s1))?;
		// apply inner padding if required
		for (let i = 0z; i < padlen) {
			i += io::write(out, pad)?;
		};
		z += padlen;
		z += io::write(out, strings::toutf8(s2))?;
		return z;
	case let p: uintptr =>
		const s = strconv::uptrtosb(p, mod.base);
		return io::write(out, strings::toutf8(s));
	case let v: nullable *void =>
		match (v) {
		case let v: *void =>
			let n = io::write(out, strings::toutf8("0x"))?;
			let z = io::write(out, strings::toutf8("0x"))?;
			const s = strconv::uptrtosb(v: uintptr,
				strconv::base::HEX_LOWER);
			n += io::write(out, strings::toutf8(s))?;
			return n;
			z += io::write(out, strings::toutf8(s))?;
			return z;
		case null =>
			return format(out, "(null)", mod);
			return io::write(out, strings::toutf8("(null)"));
		};
	case void =>
		return io::write(out, strings::toutf8("void"));
	};
};

fn get_split_number_repr(n: types::numeric, mod: *modifiers) (str, str) = {
	const s = strconv::numerictosb(n, mod.base);
	if (is_negative(n)) {
		return (
			strings::sub(s, 0, 1),
			strings::sub(s, 1, strings::end)
		);
	} else {
		const prefix = switch (mod.negation) {
		case negation::PLUS  => yield "+";
		case negation::SPACE => yield " ";
		case negation::NONE  => yield "";
		};
		return (prefix, s);
	};
};

fn is_negative(n: types::numeric) bool = {
	match (n) {
	case let i: types::signed =>
		return math::signi(i) < 0;
	case let u: types::unsigned =>
		return false;
	case let f: types::floating =>
		return math::signf(f) < 0;
	};
};

fn scan_uint(iter: *strings::iterator) uint = {
	let num: []u8 = [];
	defer free(num);
@@ -551,12 +602,32 @@ fn scan_parametric_modifiers(iter: *strings::iterator, pi: *paramindex) void = {
		"world", &modifiers { ... },
	) == "|hello|world|hello|");

	assert(bsprintf(buf, "x: {:08x}", 0xBEEF) == "x: 0000beef");
	assert(bsprintf(buf, "x: {:8X}", 0xBEEF) == "x:     BEEF");
	assert(bsprintf(buf, "x: {:8X}", -0xBEEF) == "x:    -BEEF");
	assert(bsprintf(buf, "x: {:+8X}", 0xBEEF) == "x:    +BEEF");
	assert(bsprintf(buf, "x: {: 8X}", 0xBEEF) == "x:     BEEF");

	assert(bsprintf(buf, "x: {:+ 8X}", 0xBEEF) == "x:    +BEEF");

	assert(bsprintf(buf, "x: {:-8X}", 0xBEEF) == "x: BEEF    ");
	assert(bsprintf(buf, "x: {:-8X}", -0xBEEF) == "x: -BEEF   ");
	assert(bsprintf(buf, "x: {:-+8X}", 0xBEEF) == "x: +BEEF   ");
	assert(bsprintf(buf, "x: {:- 8X}", 0xBEEF) == "x:  BEEF   ");

	assert(bsprintf(buf, "x: {:08x}", 0xBEEF) == "x: 0000beef");
	assert(bsprintf(buf, "x: {:08x}", -0xBEEF) == "x: -000beef");
	assert(bsprintf(buf, "x: {:+08x}", 0xBEEF) == "x: +000beef");
	assert(bsprintf(buf, "x: {: 08x}", 0xBEEF) == "x:  000beef");

	assert(bsprintf(buf, "x: {:-08X}", 0xBEEF) == "x: BEEF    ");

	assert(bsprintf(buf, "x: {:o}", 0o755) == "x: 755");
	assert(bsprintf(buf, "x: {:b}", 0b11011) == "x: 11011");

	assert(bsprintf(buf, "x: {:8}", "hello") == "x:    hello");
	assert(bsprintf(buf, "x: {:-8}", "hello") == "x: hello   ");
	assert(bsprintf(buf, "x: {:08}", "hello") == "x: 000hello");

	assert(bsprintf(buf, "{} {} {} {} {}", true, false, null, 'x', void)
		== "true false (null) x void");
};
diff --git a/math/ints.ha b/math/ints.ha
index 99ea5f0e..6a580baa 100644
--- a/math/ints.ha
+++ b/math/ints.ha
@@ -136,7 +136,7 @@ export fn signi64(n: i64) i64 = {
};

// Return 1 if n is positive, -1 if it's negative and 0 if it's 0.
export fn signi(n: types::integer) i64 = {
export fn signi(n: types::signed) i64 = {
	match (n) {
	case let n: i8 =>
		return signi8(n): i64;
-- 
2.30.2

[hare/patches] build success

builds.sr.ht <builds@sr.ht>
Details
Message ID
<CMKDA532UYJ9.YT7RI92HAGL@cirno>
In-Reply-To
<20220831164812.313-1-smocerg@gmail.com> (view parent)
DKIM signature
missing
Download raw message
hare/patches: SUCCESS in 1m36s

[fix fmt::fprintf's '+' and '0' modifiers][0] from [Gabriel Schmotzer][1]

[0]: https://lists.sr.ht/~sircmpwn/hare-dev/patches/35049
[1]: smocerg@gmail.com

✓ #835700 SUCCESS hare/patches/alpine.yml  https://builds.sr.ht/~sircmpwn/job/835700
✓ #835701 SUCCESS hare/patches/freebsd.yml https://builds.sr.ht/~sircmpwn/job/835701
Details
Message ID
<CN2TGI8HT34M.H1YC1H83OLMH@taiga>
In-Reply-To
<20220831164812.313-1-smocerg@gmail.com> (view parent)
DKIM signature
pass
Download raw message
Thanks!

To git@git.sr.ht:~sircmpwn/hare
   27fd53f7..10cf8c9d  master -> master
Reply to thread Export thread (mbox)