commit 54d9ecbb0a564d7060a6df5ec3f271217970a838
parent a268bf7cdfa5e474b31e6018ba7843ff753e113b
Author: Sebastian <sebastian@sebsite.pw>
Date: Tue, 17 Jan 2023 01:03:48 -0500
regex: make find and findall return [][]capture
Previously, find and findall would return void if no matches were found.
This commit changes this behavior, so an empty slice is returned
instead.
Signed-off-by: Sebastian <sebastian@sebsite.pw>
Diffstat:
4 files changed, 70 insertions(+), 87 deletions(-)
diff --git a/cmd/haredoc/color.ha b/cmd/haredoc/color.ha
@@ -45,12 +45,7 @@ fn init_colors() void = {
const expr = regex::compile(`([a-z][a-z]*)=(_|[0-9;]*)`)!;
defer regex::finish(&expr);
- const matches = match (regex::findall(&expr, env_colors)) {
- case void =>
- return;
- case let matches: [][]regex::capture =>
- yield matches;
- };
+ const matches = regex::findall(&expr, env_colors);
defer regex::free_matches(matches);
for (let i = 0z; i < len(matches); i += 1) :colors {
diff --git a/regex/+test.ha b/regex/+test.ha
@@ -36,31 +36,30 @@ fn run_find_case(
};
defer finish(&re);
- match (find(&re, string)) {
- case void =>
+ const captures = find(&re, string);
+ defer free_captures(captures);
+ if (len(captures) == 0) {
if (expected == matchres::MATCH) {
fmt::errorfln("Expected expression /{}/ to match string \"{}\", but it did not",
expr, string)!;
abort();
};
+ return;
+ } else if (expected == matchres::NOMATCH) {
+ fmt::errorfln("Expected expression /{}/ to not match string \"{}\", but it did",
+ expr, string)!;
+ abort();
+ };
- case let captures: []capture =>
- defer free_captures(captures);
- if (expected == matchres::NOMATCH) {
- fmt::errorfln("Expected expression /{}/ to not match string \"{}\", but it did",
- expr, string)!;
- abort();
- };
- if (start: size != captures[0].start) {
- fmt::errorfln("Expected start of main capture to be {} but it was {}",
- start, captures[0].start)!;
- abort();
- };
- if (end: size != captures[0].end) {
- fmt::errorfln("Expected end of main capture to be {} but it was {}",
- end, captures[0].end)!;
- abort();
- };
+ if (start: size != captures[0].start) {
+ fmt::errorfln("Expected start of main capture to be {} but it was {}",
+ start, captures[0].start)!;
+ abort();
+ };
+ if (end: size != captures[0].end) {
+ fmt::errorfln("Expected end of main capture to be {} but it was {}",
+ end, captures[0].end)!;
+ abort();
};
};
@@ -68,15 +67,14 @@ fn run_submatch_case(
expr: str,
string: str,
expected: matchres,
- count: size,
targets: []str
) void = {
const re = compile(expr)!;
defer finish(&re);
- const captures = find(&re, string) as []capture;
+ const captures = find(&re, string);
defer free_captures(captures);
- assert(len(captures) == count, "Invalid number of captures");
+ assert(len(captures) == len(targets), "Invalid number of captures");
for (let i = 0z; i < len(targets); i += 1) {
assert(targets[i] == captures[i].content, "Invalid capture");
};
@@ -86,7 +84,6 @@ fn run_findall_case(
expr: str,
string: str,
expected: matchres,
- count: size,
targets: []str
) void = {
const re = match (compile(expr)) {
@@ -108,33 +105,30 @@ fn run_findall_case(
abort();
};
- match (findall(&re, string)) {
- case void =>
- if (expected == matchres::MATCH) {
- fmt::errorfln("Expected expression /{}/ to match string \"{}\", but it did not",
- expr, string)!;
- abort();
- };
+ const matches = findall(&re, string);
+ if (len(matches) == 0 && expected == matchres::MATCH) {
+ fmt::errorfln("Expected expression /{}/ to match string \"{}\", but it did not",
+ expr, string)!;
+ abort();
+ };
+ defer free_matches(matches);
- case let matches: [][]capture =>
- defer free_matches(matches);
- if (expected == matchres::NOMATCH) {
- fmt::errorfln("Expected expression /{}/ to not match string \"{}\", but it did",
- expr, string)!;
- abort();
- };
- if (count != len(matches)) {
- fmt::errorfln("Expected to find {} matches but found {}",
- count, len(matches))!;
+ if (expected == matchres::NOMATCH) {
+ fmt::errorfln("Expected expression /{}/ to not match string \"{}\", but it did",
+ expr, string)!;
+ abort();
+ };
+ if (len(targets) != len(matches)) {
+ fmt::errorfln("Expected expression /{}/ to find {} matches but found {}",
+ expr, len(targets), len(matches))!;
+ abort();
+ };
+ for (let i = 0z; i < len(matches); i += 1) {
+ if (matches[i][0].content != targets[i]) {
+ fmt::errorfln("Expected submatch of expression /{}/ to be {} but it was {}",
+ expr, targets[i], matches[i][0].content)!;
abort();
};
- for (let i = 0z; i < len(matches); i += 1) {
- if (matches[i][0].content != targets[i]) {
- fmt::errorfln("Expected submatch to be {} but it was {}",
- targets[i], matches[i][0].content)!;
- abort();
- };
- };
};
};
@@ -553,32 +547,30 @@ fn run_findall_case(
const submatch_cases = [
// literals
- (`aaa ([^ ]*) (...)`, "aaa bbb ccc", matchres::MATCH, 3z,
- ["aaa bbb ccc", "bbb", "ccc"]),
+ (`aaa ([^ ]*) (...)`, "aaa bbb ccc", matchres::MATCH,
+ ["aaa bbb ccc", "bbb", "ccc"]: []str),
];
for (let i = 0z; i < len(submatch_cases); i += 1) {
const expr = submatch_cases[i].0;
const string = submatch_cases[i].1;
const should_match = submatch_cases[i].2;
- const count = submatch_cases[i].3;
- const targets = submatch_cases[i].4;
- run_submatch_case(expr, string, should_match, count, targets);
+ const targets = submatch_cases[i].3;
+ run_submatch_case(expr, string, should_match, targets);
};
};
@test fn findall() void = {
const cases = [
- (`ab.`, "hello abc and abあ test abq thanks", matchres::MATCH, 3z,
- ["abc", "abあ", "abq"]),
+ (`ab.`, "hello abc and abあ test abq thanks", matchres::MATCH,
+ ["abc", "abあ", "abq"]: []str),
];
for (let i = 0z; i < len(cases); i += 1) {
const expr = cases[i].0;
const string = cases[i].1;
const should_match = cases[i].2;
- const count = cases[i].3;
- const targets = cases[i].4;
- run_findall_case(expr, string, should_match, count, targets);
+ const targets = cases[i].3;
+ run_findall_case(expr, string, should_match, targets);
};
};
diff --git a/regex/README b/regex/README
@@ -23,10 +23,8 @@ the longest match among the leftmost matches.
const does_match = regex::test(&re, "Hello Hare, hello Hare.");
fmt::printfln("matched? {}", does_match)!;
- const first_match = regex::find(&re, "Hello Hare, hello Hare.");
- match (first_match) {
- case void => void;
- case let captures: []regex::capture =>
+ const captures = regex::find(&re, "Hello Hare, hello Hare.");
+ if (len(captures) != 0) {
defer regex::free_captures(captures);
// captures[0]: The full matching string.
// captures[1...]: A capture for every capture group.
@@ -35,20 +33,16 @@ the longest match among the leftmost matches.
captures[0].end)!;
};
- const all_matches = regex::findall(&re, "Hello Hare, hello Hare.");
- match (all_matches) {
- case void => void;
- case let matches: [][]regex::capture =>
- defer regex::free_matches(matches);
- // matches[0]: All captures for the first match.
- // matches[0][0]: The full matching string for the first match.
- // matches[0][1...]: A capture for every capture group in the
- // first match.
- for (let i = 0z; i < len(matches); i += 1) {
- fmt::printfln("{} ({}, {})", matches[i][0].content,
- matches[i][0].start,
- matches[i][0].end)!;
- };
+ const matches = regex::findall(&re, "Hello Hare, hello Hare.");
+ defer regex::free_matches(matches);
+ // matches[0]: All captures for the first match.
+ // matches[0][0]: The full matching string for the first match.
+ // matches[0][1...]: A capture for every capture group in the
+ // first match.
+ for (let i = 0z; i < len(matches); i += 1) {
+ fmt::printfln("{} ({}, {})", matches[i][0].content,
+ matches[i][0].start,
+ matches[i][0].end)!;
};
[0]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04
diff --git a/regex/regex.ha b/regex/regex.ha
@@ -773,16 +773,21 @@ export fn test(re: *regex, string: str) bool = {
// Attempts to match a regular expression against a string and returns the
// longest leftmost match, or void if there is no match.
-export fn find(re: *regex, string: str) (void | []capture) = {
+export fn find(re: *regex, string: str) []capture = {
let str_idx = -1;
let str_iter = strings::iter(string);
let str_bytesize = 0z;
- return search(re, string, &str_iter, &str_idx, &str_bytesize, true);
+ match (search(re, string, &str_iter, &str_idx, &str_bytesize, true)) {
+ case let m: []capture =>
+ return m;
+ case void =>
+ return [];
+ };
};
// Attempts to match a regular expression against a string and returns all
// non-overlapping matches, or void if there are no matches.
-export fn findall(re: *regex, string: str) (void | [][]capture) = {
+export fn findall(re: *regex, string: str) [][]capture = {
let res: [][]capture = alloc([]);
let str_idx = -1;
let str_iter = strings::iter(string);
@@ -804,9 +809,6 @@ export fn findall(re: *regex, string: str) (void | [][]capture) = {
case void => break;
};
};
- if (len(res) == 0) {
- return void;
- };
return res;
};