pkg/regexp: add Valid function

This means we can easily validate strings that must be Go regexps.

Change-Id: Ic7d3c717e723f692d16a48fe889e83fdfc60ee9e
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/4664
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/builtin_test.go b/cue/builtin_test.go
index 0ec2863..d1ebbd0 100644
--- a/cue/builtin_test.go
+++ b/cue/builtin_test.go
@@ -354,10 +354,17 @@
 		`[{A: "l", B: "o"},{A: "o", B: "o"},{A: "r", B: "o"}]`,
 	}, {
 		test("regexp", `regexp.FindAllNamedSubmatch(#"f(?P<A>optional)?"#, "fbla", -1)`),
-		`[{A: ""}]`}, {
+		`[{A: ""}]`,
+	}, {
 		test("regexp", `regexp.FindAllNamedSubmatch(#"f(?P<A>\w)(?P<B>\w)"#, "aglom", -1)`),
 		`_|_(error in call to regexp.FindAllNamedSubmatch: no match)`,
 	}, {
+		test("regexp", `regexp.Valid & "valid"`),
+		`"valid"`,
+	}, {
+		test("regexp", `regexp.Valid & "invalid)"`),
+		"_|_(error in call to regexp.Valid: error parsing regexp: unexpected ): `invalid)`)",
+	}, {
 		test("strconv", `strconv.FormatBool(true)`),
 		`"true"`,
 	}, {
diff --git a/cue/builtins.go b/cue/builtins.go
index d0a10c0..e8f631b 100644
--- a/cue/builtins.go
+++ b/cue/builtins.go
@@ -30,15 +30,14 @@
 	"unicode"
 	"unicode/utf8"
 
-	"github.com/cockroachdb/apd/v2"
-	goyaml "github.com/ghodss/yaml"
-	"golang.org/x/net/idna"
-
 	"cuelang.org/go/cue/errors"
 	"cuelang.org/go/cue/literal"
 	"cuelang.org/go/cue/parser"
 	"cuelang.org/go/internal"
 	"cuelang.org/go/internal/third_party/yaml"
+	"github.com/cockroachdb/apd/v2"
+	goyaml "github.com/ghodss/yaml"
+	"golang.org/x/net/idna"
 )
 
 func init() {
@@ -2419,6 +2418,19 @@
 	},
 	"regexp": &builtinPkg{
 		native: []*builtin{{
+			Name:   "Valid",
+			Params: []kind{stringKind},
+			Result: boolKind,
+			Func: func(c *callCtxt) {
+				pattern := c.string(0)
+				if c.do() {
+					c.ret, c.err = func() (interface{}, error) {
+						_, err := regexp.Compile(pattern)
+						return err == nil, err
+					}()
+				}
+			},
+		}, {
 			Name:   "Find",
 			Params: []kind{stringKind, stringKind},
 			Result: stringKind,
diff --git a/pkg/regexp/manual.go b/pkg/regexp/manual.go
index c9201d1..8208cbc 100644
--- a/pkg/regexp/manual.go
+++ b/pkg/regexp/manual.go
@@ -22,6 +22,13 @@
 
 var errNoMatch = errors.New("no match")
 
+// Valid reports whether the given regular expression
+// is valid.
+func Valid(pattern string) (bool, error) {
+	_, err := regexp.Compile(pattern)
+	return err == nil, err
+}
+
 // Find returns a string holding the text of the leftmost match in s of
 // the regular expression. It returns bottom if there was no match.
 func Find(pattern, s string) (string, error) {
diff --git a/pkg/strconv/strconv.go b/pkg/strconv/strconv.go
index e091af0..b3e556e 100644
--- a/pkg/strconv/strconv.go
+++ b/pkg/strconv/strconv.go
@@ -73,11 +73,10 @@
 // ParseInt interprets a string s in the given base (0, 2 to 36) and
 // bit size (0 to 64) and returns the corresponding value i.
 //
-// If base == 0, the base is implied by the string's prefix:
-// base 2 for "0b", base 8 for "0" or "0o", base 16 for "0x",
-// and base 10 otherwise. Also, for base == 0 only, underscore
-// characters are permitted per the Go integer literal syntax.
-// If base is below 0, is 1, or is above 36, an error is returned.
+// If the base argument is 0, the true base is implied by the string's
+// prefix: 2 for "0b", 8 for "0" or "0o", 16 for "0x", and 10 otherwise.
+// Also, for argument base 0 only, underscore characters are permitted
+// as defined by the Go syntax for integer literals.
 //
 // The bitSize argument specifies the integer type
 // that the result must fit into. Bit sizes 0, 8, 16, 32, and 64