summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/d5/tengo/stdlib/text_regexp.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/d5/tengo/stdlib/text_regexp.go')
-rw-r--r--vendor/github.com/d5/tengo/stdlib/text_regexp.go228
1 files changed, 228 insertions, 0 deletions
diff --git a/vendor/github.com/d5/tengo/stdlib/text_regexp.go b/vendor/github.com/d5/tengo/stdlib/text_regexp.go
new file mode 100644
index 00000000..16f135bf
--- /dev/null
+++ b/vendor/github.com/d5/tengo/stdlib/text_regexp.go
@@ -0,0 +1,228 @@
+package stdlib
+
+import (
+ "regexp"
+
+ "github.com/d5/tengo"
+ "github.com/d5/tengo/objects"
+)
+
+func makeTextRegexp(re *regexp.Regexp) *objects.ImmutableMap {
+ return &objects.ImmutableMap{
+ Value: map[string]objects.Object{
+ // match(text) => bool
+ "match": &objects.UserFunction{
+ Value: func(args ...objects.Object) (ret objects.Object, err error) {
+ if len(args) != 1 {
+ err = objects.ErrWrongNumArguments
+ return
+ }
+
+ s1, ok := objects.ToString(args[0])
+ if !ok {
+ err = objects.ErrInvalidArgumentType{
+ Name: "first",
+ Expected: "string(compatible)",
+ Found: args[0].TypeName(),
+ }
+ return
+ }
+
+ if re.MatchString(s1) {
+ ret = objects.TrueValue
+ } else {
+ ret = objects.FalseValue
+ }
+
+ return
+ },
+ },
+
+ // find(text) => array(array({text:,begin:,end:}))/undefined
+ // find(text, maxCount) => array(array({text:,begin:,end:}))/undefined
+ "find": &objects.UserFunction{
+ Value: func(args ...objects.Object) (ret objects.Object, err error) {
+ numArgs := len(args)
+ if numArgs != 1 && numArgs != 2 {
+ err = objects.ErrWrongNumArguments
+ return
+ }
+
+ s1, ok := objects.ToString(args[0])
+ if !ok {
+ err = objects.ErrInvalidArgumentType{
+ Name: "first",
+ Expected: "string(compatible)",
+ Found: args[0].TypeName(),
+ }
+ return
+ }
+
+ if numArgs == 1 {
+ m := re.FindStringSubmatchIndex(s1)
+ if m == nil {
+ ret = objects.UndefinedValue
+ return
+ }
+
+ arr := &objects.Array{}
+ for i := 0; i < len(m); i += 2 {
+ arr.Value = append(arr.Value, &objects.ImmutableMap{Value: map[string]objects.Object{
+ "text": &objects.String{Value: s1[m[i]:m[i+1]]},
+ "begin": &objects.Int{Value: int64(m[i])},
+ "end": &objects.Int{Value: int64(m[i+1])},
+ }})
+ }
+
+ ret = &objects.Array{Value: []objects.Object{arr}}
+
+ return
+ }
+
+ i2, ok := objects.ToInt(args[1])
+ if !ok {
+ err = objects.ErrInvalidArgumentType{
+ Name: "second",
+ Expected: "int(compatible)",
+ Found: args[1].TypeName(),
+ }
+ return
+ }
+ m := re.FindAllStringSubmatchIndex(s1, i2)
+ if m == nil {
+ ret = objects.UndefinedValue
+ return
+ }
+
+ arr := &objects.Array{}
+ for _, m := range m {
+ subMatch := &objects.Array{}
+ for i := 0; i < len(m); i += 2 {
+ subMatch.Value = append(subMatch.Value, &objects.ImmutableMap{Value: map[string]objects.Object{
+ "text": &objects.String{Value: s1[m[i]:m[i+1]]},
+ "begin": &objects.Int{Value: int64(m[i])},
+ "end": &objects.Int{Value: int64(m[i+1])},
+ }})
+ }
+
+ arr.Value = append(arr.Value, subMatch)
+ }
+
+ ret = arr
+
+ return
+ },
+ },
+
+ // replace(src, repl) => string
+ "replace": &objects.UserFunction{
+ Value: func(args ...objects.Object) (ret objects.Object, err error) {
+ if len(args) != 2 {
+ err = objects.ErrWrongNumArguments
+ return
+ }
+
+ s1, ok := objects.ToString(args[0])
+ if !ok {
+ err = objects.ErrInvalidArgumentType{
+ Name: "first",
+ Expected: "string(compatible)",
+ Found: args[0].TypeName(),
+ }
+ return
+ }
+
+ s2, ok := objects.ToString(args[1])
+ if !ok {
+ err = objects.ErrInvalidArgumentType{
+ Name: "second",
+ Expected: "string(compatible)",
+ Found: args[1].TypeName(),
+ }
+ return
+ }
+
+ s, ok := doTextRegexpReplace(re, s1, s2)
+ if !ok {
+ return nil, objects.ErrStringLimit
+ }
+
+ ret = &objects.String{Value: s}
+
+ return
+ },
+ },
+
+ // split(text) => array(string)
+ // split(text, maxCount) => array(string)
+ "split": &objects.UserFunction{
+ Value: func(args ...objects.Object) (ret objects.Object, err error) {
+ numArgs := len(args)
+ if numArgs != 1 && numArgs != 2 {
+ err = objects.ErrWrongNumArguments
+ return
+ }
+
+ s1, ok := objects.ToString(args[0])
+ if !ok {
+ err = objects.ErrInvalidArgumentType{
+ Name: "first",
+ Expected: "string(compatible)",
+ Found: args[0].TypeName(),
+ }
+ return
+ }
+
+ var i2 = -1
+ if numArgs > 1 {
+ i2, ok = objects.ToInt(args[1])
+ if !ok {
+ err = objects.ErrInvalidArgumentType{
+ Name: "second",
+ Expected: "int(compatible)",
+ Found: args[1].TypeName(),
+ }
+ return
+ }
+ }
+
+ arr := &objects.Array{}
+ for _, s := range re.Split(s1, i2) {
+ arr.Value = append(arr.Value, &objects.String{Value: s})
+ }
+
+ ret = arr
+
+ return
+ },
+ },
+ },
+ }
+}
+
+// Size-limit checking implementation of regexp.ReplaceAllString.
+func doTextRegexpReplace(re *regexp.Regexp, src, repl string) (string, bool) {
+ idx := 0
+ out := ""
+
+ for _, m := range re.FindAllStringSubmatchIndex(src, -1) {
+ var exp []byte
+ exp = re.ExpandString(exp, repl, src, m)
+
+ if len(out)+m[0]-idx+len(exp) > tengo.MaxStringLen {
+ return "", false
+ }
+
+ out += src[idx:m[0]] + string(exp)
+ idx = m[1]
+ }
+ if idx < len(src) {
+ if len(out)+len(src)-idx > tengo.MaxStringLen {
+ return "", false
+ }
+
+ out += src[idx:]
+ }
+
+ return string(out), true
+}