Remove regex functionality from rbcrun

As a first step to making .rbc files compatible with bazel,
remove regex support since bazel doesn't have it.

Fixes: 227384703
Test: ./out/rbcrun ./build/make/tests/run.rbc
Change-Id: I8b946c20cc42897a47a5516a167732f4e16b6158
diff --git a/core/product_config.rbc b/core/product_config.rbc
index eab149a..4554a08 100644
--- a/core/product_config.rbc
+++ b/core/product_config.rbc
@@ -385,7 +385,7 @@
 
 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 @@
     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 @@
          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 @@
     """
     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 __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 @@
     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 @@
     $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 a9b1673..82a5e72 100644
--- a/tests/run.rbc
+++ b/tests/run.rbc
@@ -53,7 +53,11 @@
 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 4915de9..c6e89f0 100644
--- a/tools/rbcrun/host.go
+++ b/tools/rbcrun/host.go
@@ -20,7 +20,6 @@
 	"os"
 	"os/exec"
 	"path/filepath"
-	"regexp"
 	"strings"
 
 	"go.starlark.net/starlark"
@@ -125,23 +124,6 @@
 	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 @@
 		"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 3be5ee6..97f6ce9 100644
--- a/tools/rbcrun/host_test.go
+++ b/tools/rbcrun/host_test.go
@@ -147,10 +147,6 @@
 	}
 }
 
-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 04e1d42..0000000
--- 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()