From 6d0f04375df942985292d0a6b6e487db9a09f3fa Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Mon, 16 Sep 2024 15:12:54 -0400 Subject: [PATCH] Have Text:matches() return an optional array of matches --- environment.c | 4 ++-- stdlib/patterns.c | 16 +++++++++++++--- stdlib/patterns.h | 2 +- test/paths.tm | 2 +- test/text.tm | 14 ++++++++++---- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/environment.c b/environment.c index d3e2706..228c5ac 100644 --- a/environment.c +++ b/environment.c @@ -294,7 +294,7 @@ env_t *new_compilation_unit(CORD *libname) // Text methods: {"ends_with", "Text$ends_with", "func(path:Path, suffix:Text)->Bool"}, {"has", "Text$has", "func(path:Path, pattern:Pattern)->Bool"}, - {"matches", "Text$matches", "func(path:Path, pattern:Pattern)->Bool"}, + {"matches", "Text$matches", "func(path:Path, pattern:Pattern)->[Text]?"}, {"replace", "Text$replace", "func(path:Path, pattern:Pattern, replacement:Text, backref=$/\\/, recursive=yes)->Path"}, {"replace_all", "Text$replace_all", "func(path:Path, replacements:{Pattern:Text}, backref=$/\\/, recursive=yes)->Path"}, {"starts_with", "Text$starts_with", "func(path:Path, prefix:Text)->Bool"}, @@ -320,7 +320,7 @@ env_t *new_compilation_unit(CORD *libname) {"lines", "Text$lines", "func(text:Text)->[Text]"}, {"lower", "Text$lower", "func(text:Text)->Text"}, {"map", "Text$map", "func(text:Text, pattern:Pattern, fn:func(text:Text)->Text)->Text"}, - {"matches", "Text$matches", "func(text:Text, pattern:Pattern)->Bool"}, + {"matches", "Text$matches", "func(text:Text, pattern:Pattern)->[Text]?"}, {"quoted", "Text$quoted", "func(text:Text, color=no)->Text"}, {"repeat", "Text$repeat", "func(text:Text, count:Int)->Text"}, {"replace", "Text$replace", "func(text:Text, pattern:Pattern, replacement:Text, backref=$/\\/, recursive=yes)->Text"}, diff --git a/stdlib/patterns.c b/stdlib/patterns.c index 0df06eb..701aff9 100644 --- a/stdlib/patterns.c +++ b/stdlib/patterns.c @@ -7,6 +7,7 @@ #include "arrays.h" #include "integers.h" +#include "optionals.h" #include "patterns.h" #include "tables.h" #include "text.h" @@ -824,10 +825,19 @@ PUREFUNC public bool Text$has(Text_t text, Pattern_t pattern) } } -PUREFUNC public bool Text$matches(Text_t text, Pattern_t pattern) +public OptionalArray_t Text$matches(Text_t text, Pattern_t pattern) { - int64_t m = match(text, 0, pattern, 0, NULL, 0); - return m == text.length; + capture_t captures[MAX_BACKREFS] = {}; + int64_t match_len = match(text, 0, pattern, 0, captures, 0); + if (match_len != text.length) + return NULL_ARRAY; + + Array_t capture_array = {}; + for (int i = 0; captures[i].occupied; i++) { + Text_t capture = Text$slice(text, I(captures[i].index+1), I(captures[i].index+captures[i].length)); + Array$insert(&capture_array, &capture, I(0), sizeof(Text_t)); + } + return capture_array; } public Array_t Text$find_all(Text_t text, Pattern_t pattern) diff --git a/stdlib/patterns.h b/stdlib/patterns.h index 804fb28..9825cf9 100644 --- a/stdlib/patterns.h +++ b/stdlib/patterns.h @@ -21,7 +21,7 @@ Text_t Text$trim(Text_t text, Pattern_t pattern, bool trim_left, bool trim_right Int_t Text$find(Text_t text, Pattern_t pattern, Int_t i, int64_t *match_length); Array_t Text$find_all(Text_t text, Pattern_t pattern); PUREFUNC bool Text$has(Text_t text, Pattern_t pattern); -PUREFUNC bool Text$matches(Text_t text, Pattern_t pattern); +Array_t Text$matches(Text_t text, Pattern_t pattern); Text_t Text$map(Text_t text, Pattern_t pattern, Closure_t fn); #define Pattern$hash Text$hash diff --git a/test/paths.tm b/test/paths.tm index 4ef0b02..92a1464 100644 --- a/test/paths.tm +++ b/test/paths.tm @@ -84,7 +84,7 @@ func main(): >> (./foo.txt):ends_with(".txt") = yes >> (./foo.txt):matches($|{..}/foo{..}|) - = yes + = [".", ".txt"]? >> (./foo.txt):replace($/.txt/, ".md") = (./foo.md) diff --git a/test/text.tm b/test/text.tm index f27eaf3..f87cedf 100644 --- a/test/text.tm +++ b/test/text.tm @@ -251,13 +251,19 @@ func main(): = " good(x, fn(y), BAD(z), w) " >> "Hello":matches($/{id}/) - = yes + = ["Hello"]? >> "Hello":matches($/{lower}/) - = no + = ![Text] >> "Hello":matches($/{upper}/) - = no + = ![Text] >> "Hello...":matches($/{id}/) - = no + = ![Text] + + if matches := "hello world":matches($/{id} {id}/): + >> matches + = ["hello", "world"] + else: + fail("Failed to match") >> "hello world":map($/world/, Text.upper) = "hello WORLD"