commit 4c62c082965bf14b2931f2e4bb970d03faf25ff3
parent b0e4f055ad2182b44450e5750071cb4d26f9759a
Author: Pierre Curto <pierre.curto@gmail.com>
Date: Sun, 7 Aug 2022 12:53:19 +0200
strings: update riter and remove push
Remove function pointers and push fields on iterator.
Remove push function.
Fixes: https://todo.sr.ht/~sircmpwn/hare/572
Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
Diffstat:
4 files changed, 32 insertions(+), 46 deletions(-)
diff --git a/fmt/fmt.ha b/fmt/fmt.ha
@@ -208,11 +208,11 @@ export fn fprintf(
};
const idx = if (ascii::isdigit(r)) {
- strings::push(&iter, r);
+ strings::prev(&iter);
checkunused = false;
yield scan_uint(&iter): size;
} else {
- strings::push(&iter, r);
+ strings::prev(&iter);
i += 1;
yield i - 1;
};
@@ -368,7 +368,7 @@ fn scan_uint(iter: *strings::iterator) uint = {
if (ascii::isdigit(r)) {
append(num, r: u32: u8);
} else {
- strings::push(iter, r);
+ strings::prev(iter);
match (strconv::stou(strings::fromutf8(num))) {
case (strconv::invalid | strconv::overflow) =>
abort("Invalid format string (invalid index)");
@@ -401,7 +401,7 @@ fn scan_modifier_flags(iter: *strings::iterator, mod: *modifiers) void = {
case '+' =>
flags |= modflags::PLUS;
case =>
- strings::push(iter, r);
+ strings::prev(iter);
break;
};
};
@@ -430,7 +430,7 @@ fn scan_modifier_width(iter: *strings::iterator, mod: *modifiers) void = {
};
let is_digit = ascii::isdigit(r);
- strings::push(iter, r);
+ strings::prev(iter);
if (is_digit) {
mod.width = scan_uint(iter);
@@ -448,7 +448,7 @@ fn scan_modifier_precision(iter: *strings::iterator, mod: *modifiers) void = {
if (r == '.') {
mod.precision = scan_uint(iter);
} else {
- strings::push(iter, r);
+ strings::prev(iter);
};
};
@@ -470,7 +470,7 @@ fn scan_modifier_base(iter: *strings::iterator, mod: *modifiers) void = {
case 'b' =>
mod.base = strconv::base::BIN;
case =>
- strings::push(iter, r);
+ strings::prev(iter);
};
};
@@ -499,7 +499,7 @@ fn scan_parameter_index(iter: *strings::iterator, pi: *paramindex) void = {
};
let is_digit = ascii::isdigit(r);
- strings::push(iter, r);
+ strings::prev(iter);
if (is_digit) {
*pi = scan_uint(iter);
} else {
diff --git a/fnmatch/fnmatch.ha b/fnmatch/fnmatch.ha
@@ -270,7 +270,7 @@ fn match_bracket(
let end = advance_or_err(it)?;
if (end == ']') {
// '-' at the end matches itself
- strings::push(it, ']');
+ strings::prev(it);
last = '-';
found ||= (c == '-');
continue;
@@ -290,7 +290,7 @@ fn match_bracket(
let t = match_ctype(it, c)?;
found ||= t;
case =>
- strings::push(it, next_rune);
+ strings::prev(it);
found ||= (c == '[');
};
last = '[';
diff --git a/hare/module/scan.ha b/hare/module/scan.ha
@@ -425,7 +425,7 @@ export fn parsetags(in: str) ([]tag | void) = {
if (ascii::isalnum(r) || r == '_') {
strio::appendrune(&buf, r)!;
} else {
- strings::push(&iter, r);
+ strings::prev(&iter);
break;
};
};
diff --git a/strings/iter.ha b/strings/iter.ha
@@ -8,9 +8,7 @@ use encoding::utf8;
export type iterator = struct {
dec: utf8::decoder,
- push: (rune | void),
- next: *fn(_: *utf8::decoder) (rune | void | utf8::more | utf8::invalid),
- prev: *fn(_: *utf8::decoder) (rune | void | utf8::more | utf8::invalid),
+ reverse: bool,
};
// Initializes a string iterator, starting at the beginning of the string. You
@@ -28,21 +26,15 @@ export type iterator = struct {
// strings::next(&dup); // void
export fn iter(src: str) iterator = iterator {
dec = utf8::decode(src),
- push = void,
- next = &utf8::next,
- prev = &utf8::prev,
+ reverse = false,
};
// Initializes a string iterator, starting at the end of the string and moving
// backwards with each call to [[next]].
export fn riter(src: str) iterator = {
- // TODO: Add rnext et al to avoid blowing up the stack footprint with
- // next/prev pointers
let ret = iterator {
dec = utf8::decode(src),
- push = void,
- next = &utf8::prev,
- prev = &utf8::next,
+ reverse = true,
};
ret.dec.offs = len(src);
return ret;
@@ -56,13 +48,15 @@ export fn riter(src: str) iterator = {
// may cause linguistic errors to arise. To avoid this, you may need to use a
// third-party Unicode module instead.
export fn next(iter: *iterator) (rune | void) = {
- match (iter.push) {
- case let r: rune =>
- iter.push = void;
- return r;
- case void => void;
- };
- return match (iter.next(&iter.dec)) {
+ if (iter.reverse) {
+ return next_backward(iter);
+ } else {
+ return next_forward(iter);
+ };
+};
+
+fn next_forward(iter: *iterator) (rune | void) = {
+ return match (utf8::next(&iter.dec)) {
case void => void;
case (utf8::more | utf8::invalid) =>
abort("Invalid UTF-8 string (this should not happen)");
@@ -74,8 +68,15 @@ export fn next(iter: *iterator) (rune | void) = {
// Get the previous rune from an iterator, or void when at the start of the
// string.
export fn prev(iter: *iterator) (rune | void) = {
- assert(iter.push is void);
- return match (iter.prev(&iter.dec)) {
+ if (iter.reverse) {
+ return next_forward(iter);
+ } else {
+ return next_backward(iter);
+ };
+};
+
+fn next_backward(iter: *iterator) (rune | void) = {
+ return match (utf8::prev(&iter.dec)) {
case void =>
yield void;
case (utf8::more | utf8::invalid) =>
@@ -85,21 +86,8 @@ export fn prev(iter: *iterator) (rune | void) = {
};
};
-// Causes the next call to [[next]] to return the provided rune, effectively
-// un-reading it. The next call using this iterator *must* be [[next]]; all other
-// functions will cause the program to abort until the pushed rune is consumed.
-// This does not modify the underlying string, and as such, subsequent calls to
-// functions like [[prev]] or [[iterstr]] will behave as if push were never called.
-export fn push(iter: *iterator, r: rune) void = {
- // TODO: This should probably be removed, and the push field removed
- // from the struct.
- assert(iter.push is void);
- iter.push = r;
-};
-
// Return a substring from the next rune to the end of the string.
export fn iterstr(iter: *iterator) str = {
- assert(iter.push is void);
return fromutf8(iter.dec.src[iter.dec.offs..]);
};
@@ -128,8 +116,6 @@ export fn iterstr(iter: *iterator) str = {
};
assert(next(&s) is void);
assert(next(&s) is void);
- push(&s, 'q');
- assert(next(&s) as rune == 'q');
assert(prev(&s) as rune == 'は');
s = riter("にちは");