diff --git a/core/product_config.rbc b/core/product_config.rbc index eab149a8da..4554a08d2e 100644 --- a/core/product_config.rbc +++ b/core/product_config.rbc @@ -385,7 +385,7 @@ def _addsuffix(suffix, string_or_list): def __words(string_or_list): if type(string_or_list) == "list": - return string_or_list + string_or_list = " ".join(string_or_list) return _mkstrip(string_or_list).split() # Handle manipulation functions. @@ -500,10 +500,15 @@ def _filter_out(pattern, text): Return: list of words """ - rex = __mk2regex(__words(pattern)) + patterns = [__mkparse_pattern(x) for x in __words(pattern)] res = [] for w in __words(text): - if not _regex_match(rex, w): + match = False + for p in patterns: + if __mkpattern_matches(p, w): + match = True + break + if not match: res.append(w) return res @@ -515,11 +520,13 @@ def _filter(pattern, text): which stands for any sequence of characters. text: string or list of words. """ - rex = __mk2regex(__words(pattern)) + patterns = [__mkparse_pattern(x) for x in __words(pattern)] res = [] for w in __words(text): - if _regex_match(rex, w): - res.append(w) + for p in patterns: + if __mkpattern_matches(p, w): + res.append(w) + break return res def _notdir(paths): @@ -529,15 +536,6 @@ def _notdir(paths): """ return " ".join([__base(w) for w in __words(paths)]) -def __mk2regex(words): - """Returns regular expression equivalent to Make pattern.""" - - # TODO(asmundak): this will mishandle '\%' - return "^(" + "|".join([w.replace("%", ".*", 1) for w in words if w]) + ")$" - -def _regex_match(regex, w): - return rblf_regex(regex, w) - def _require_artifacts_in_path(paths, allowed_paths): """TODO.""" pass @@ -594,7 +592,11 @@ def _mkinfo(file, message = ""): def __mkparse_pattern(pattern): - """Parses Make's patsubst pattern.""" + """Parses Make's patsubst pattern. + + This is equivalent to pattern.split('%', 1), except it + also takes into account escaping the % symbols. + """ in_escape = False res = [] acc = "" @@ -614,6 +616,21 @@ def __mkparse_pattern(pattern): res.append(acc) return res +def __mkpattern_matches(pattern, word): + """Returns if a pattern matches a given word. + + The pattern must be a list of strings of length at most 2. + This checks if word is either equal to the pattern or + starts/ends with the two parts of the pattern. + """ + if len(pattern) > 2: + fail("Pattern can have at most 2 components") + elif len(pattern) == 1: + return pattern[0]==word + else: + return ((len(word) >= len(pattern[0])+len(pattern[1])) + and word.startswith(pattern[0]) + and word.endswith(pattern[1])) def __mkpatsubst_word(parsed_pattern,parsed_subst, word): (before, after) = parsed_pattern @@ -635,12 +652,11 @@ def _mkpatsubst(pattern, replacement, s): $1 in regex terms). """ parsed_pattern = __mkparse_pattern(pattern) - words = s if type(s) == "list" else _mkstrip(s).split(" ") if len(parsed_pattern) == 1: - out_words = [ replacement if x == pattern else x for x in words] + out_words = [ replacement if x == pattern else x for x in __words(s)] else: parsed_replacement = __mkparse_pattern(replacement) - out_words = [__mkpatsubst_word(parsed_pattern, parsed_replacement, x) for x in words] + out_words = [__mkpatsubst_word(parsed_pattern, parsed_replacement, x) for x in __words(s)] return out_words if type(s) == "list" else " ".join(out_words) diff --git a/tests/run.rbc b/tests/run.rbc index a9b16734d5..82a5e727ca 100644 --- a/tests/run.rbc +++ b/tests/run.rbc @@ -53,7 +53,11 @@ assert_eq(["foo/%"], rblf.mkpatsubst("%", "%/%", ["foo"])) assert_eq(["from/a:to/a", "from/b:to/b"], rblf.product_copy_files_by_pattern("from/%", "to/%", "a b")) assert_eq([], rblf.filter(["a", "", "b"], "f")) -assert_eq(["", "b"], rblf.filter_out(["a", "" ], ["a", "", "b"] )) +assert_eq(["ab%c", "axyzb%c"], rblf.filter(["a%b%c"], ["ab%c", "axyzb%c", "axyzb%cd", "axyzbwc"])) +assert_eq(["abc", "bcd"], rblf.filter(["a%", "b%"], ["abc", "def", "bcd", "xabc"])) +assert_eq(["b", "ab"], rblf.filter_out(["a", "" ], ["a", "", "b", "ab"])) +assert_eq(["c"], rblf.filter_out(["a", "b" ], ["a", "b", "c"])) +assert_eq(["c"], rblf.filter_out(["a%", "b" ], ["abc", "b", "c"])) assert_eq("foo.c no_folder", rblf.notdir(["src/foo.c", "no_folder"])) assert_eq("foo.c no_folder", rblf.notdir("src/foo.c no_folder")) diff --git a/tools/rbcrun/host.go b/tools/rbcrun/host.go index 4915de9d07..c6e89f02c8 100644 --- a/tools/rbcrun/host.go +++ b/tools/rbcrun/host.go @@ -20,7 +20,6 @@ import ( "os" "os/exec" "path/filepath" - "regexp" "strings" "go.starlark.net/starlark" @@ -125,23 +124,6 @@ func fileExists(_ *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, return starlark.True, nil } -// regexMatch(pattern, s) returns True if s matches pattern (a regex) -func regexMatch(_ *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, - kwargs []starlark.Tuple) (starlark.Value, error) { - var pattern, s string - if err := starlark.UnpackPositionalArgs(b.Name(), args, kwargs, 2, &pattern, &s); err != nil { - return starlark.None, err - } - match, err := regexp.MatchString(pattern, s) - if err != nil { - return starlark.None, err - } - if match { - return starlark.True, nil - } - return starlark.False, nil -} - // wildcard(pattern, top=None) expands shell's glob pattern. If 'top' is present, // the 'top/pattern' is globbed and then 'top/' prefix is removed. func wildcard(_ *starlark.Thread, b *starlark.Builtin, args starlark.Tuple, @@ -291,8 +273,6 @@ func setup(env []string) { "rblf_file_exists": starlark.NewBuiltin("rblf_file_exists", fileExists), // To convert find-copy-subdir and product-copy-files-by pattern "rblf_find_files": starlark.NewBuiltin("rblf_find_files", find), - // To convert makefile's $(filter ...)/$(filter-out) - "rblf_regex": starlark.NewBuiltin("rblf_regex", regexMatch), // To convert makefile's $(shell cmd) "rblf_shell": starlark.NewBuiltin("rblf_shell", shell), // Output to stderr diff --git a/tools/rbcrun/host_test.go b/tools/rbcrun/host_test.go index 3be5ee67aa..97f6ce9e93 100644 --- a/tools/rbcrun/host_test.go +++ b/tools/rbcrun/host_test.go @@ -147,10 +147,6 @@ func TestLoad(t *testing.T) { } } -func TestRegex(t *testing.T) { - exerciseStarlarkTestFile(t, "testdata/regex.star") -} - func TestShell(t *testing.T) { if err := os.Setenv("TEST_DATA_DIR", dataDir()); err != nil { t.Fatal(err) diff --git a/tools/rbcrun/testdata/regex.star b/tools/rbcrun/testdata/regex.star deleted file mode 100644 index 04e1d424e9..0000000000 --- a/tools/rbcrun/testdata/regex.star +++ /dev/null @@ -1,13 +0,0 @@ -# Tests rblf_regex -load("assert.star", "assert") - - -def test(): - pattern = "^(foo.*bar|abc.*d|1.*)$" - for w in ("foobar", "fooxbar", "abcxd", "123"): - assert.true(rblf_regex(pattern, w), "%s should match %s" % (w, pattern)) - for w in ("afoobar", "abcde"): - assert.true(not rblf_regex(pattern, w), "%s should not match %s" % (w, pattern)) - - -test()