diff options
author | Wim <wim@42.be> | 2020-01-09 21:52:19 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-09 21:52:19 +0100 |
commit | 9d84d6dd643c4017074e81465671cd9b25f9539a (patch) | |
tree | 8a767f91d655a6cf21d476e4fb7aa6fd8a952df8 /vendor/github.com/d5/tengo/v2/stdlib/text.go | |
parent | 0f708daf2d14dcca261ef98cc698a1b1f2a6aa74 (diff) | |
download | matterbridge-msglm-9d84d6dd643c4017074e81465671cd9b25f9539a.tar.gz matterbridge-msglm-9d84d6dd643c4017074e81465671cd9b25f9539a.tar.bz2 matterbridge-msglm-9d84d6dd643c4017074e81465671cd9b25f9539a.zip |
Update to tengo v2 (#976)
Diffstat (limited to 'vendor/github.com/d5/tengo/v2/stdlib/text.go')
-rw-r--r-- | vendor/github.com/d5/tengo/v2/stdlib/text.go | 1072 |
1 files changed, 1072 insertions, 0 deletions
diff --git a/vendor/github.com/d5/tengo/v2/stdlib/text.go b/vendor/github.com/d5/tengo/v2/stdlib/text.go new file mode 100644 index 00000000..d7d5d1da --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/text.go @@ -0,0 +1,1072 @@ +package stdlib + +import ( + "fmt" + "regexp" + "strconv" + "strings" + "unicode/utf8" + + "github.com/d5/tengo/v2" +) + +var textModule = map[string]tengo.Object{ + "re_match": &tengo.UserFunction{ + Name: "re_match", + Value: textREMatch, + }, // re_match(pattern, text) => bool/error + "re_find": &tengo.UserFunction{ + Name: "re_find", + Value: textREFind, + }, // re_find(pattern, text, count) => [[{text:,begin:,end:}]]/undefined + "re_replace": &tengo.UserFunction{ + Name: "re_replace", + Value: textREReplace, + }, // re_replace(pattern, text, repl) => string/error + "re_split": &tengo.UserFunction{ + Name: "re_split", + Value: textRESplit, + }, // re_split(pattern, text, count) => [string]/error + "re_compile": &tengo.UserFunction{ + Name: "re_compile", + Value: textRECompile, + }, // re_compile(pattern) => Regexp/error + "compare": &tengo.UserFunction{ + Name: "compare", + Value: FuncASSRI(strings.Compare), + }, // compare(a, b) => int + "contains": &tengo.UserFunction{ + Name: "contains", + Value: FuncASSRB(strings.Contains), + }, // contains(s, substr) => bool + "contains_any": &tengo.UserFunction{ + Name: "contains_any", + Value: FuncASSRB(strings.ContainsAny), + }, // contains_any(s, chars) => bool + "count": &tengo.UserFunction{ + Name: "count", + Value: FuncASSRI(strings.Count), + }, // count(s, substr) => int + "equal_fold": &tengo.UserFunction{ + Name: "equal_fold", + Value: FuncASSRB(strings.EqualFold), + }, // "equal_fold(s, t) => bool + "fields": &tengo.UserFunction{ + Name: "fields", + Value: FuncASRSs(strings.Fields), + }, // fields(s) => [string] + "has_prefix": &tengo.UserFunction{ + Name: "has_prefix", + Value: FuncASSRB(strings.HasPrefix), + }, // has_prefix(s, prefix) => bool + "has_suffix": &tengo.UserFunction{ + Name: "has_suffix", + Value: FuncASSRB(strings.HasSuffix), + }, // has_suffix(s, suffix) => bool + "index": &tengo.UserFunction{ + Name: "index", + Value: FuncASSRI(strings.Index), + }, // index(s, substr) => int + "index_any": &tengo.UserFunction{ + Name: "index_any", + Value: FuncASSRI(strings.IndexAny), + }, // index_any(s, chars) => int + "join": &tengo.UserFunction{ + Name: "join", + Value: textJoin, + }, // join(arr, sep) => string + "last_index": &tengo.UserFunction{ + Name: "last_index", + Value: FuncASSRI(strings.LastIndex), + }, // last_index(s, substr) => int + "last_index_any": &tengo.UserFunction{ + Name: "last_index_any", + Value: FuncASSRI(strings.LastIndexAny), + }, // last_index_any(s, chars) => int + "repeat": &tengo.UserFunction{ + Name: "repeat", + Value: textRepeat, + }, // repeat(s, count) => string + "replace": &tengo.UserFunction{ + Name: "replace", + Value: textReplace, + }, // replace(s, old, new, n) => string + "substr": &tengo.UserFunction{ + Name: "substr", + Value: textSubstring, + }, // substr(s, lower, upper) => string + "split": &tengo.UserFunction{ + Name: "split", + Value: FuncASSRSs(strings.Split), + }, // split(s, sep) => [string] + "split_after": &tengo.UserFunction{ + Name: "split_after", + Value: FuncASSRSs(strings.SplitAfter), + }, // split_after(s, sep) => [string] + "split_after_n": &tengo.UserFunction{ + Name: "split_after_n", + Value: FuncASSIRSs(strings.SplitAfterN), + }, // split_after_n(s, sep, n) => [string] + "split_n": &tengo.UserFunction{ + Name: "split_n", + Value: FuncASSIRSs(strings.SplitN), + }, // split_n(s, sep, n) => [string] + "title": &tengo.UserFunction{ + Name: "title", + Value: FuncASRS(strings.Title), + }, // title(s) => string + "to_lower": &tengo.UserFunction{ + Name: "to_lower", + Value: FuncASRS(strings.ToLower), + }, // to_lower(s) => string + "to_title": &tengo.UserFunction{ + Name: "to_title", + Value: FuncASRS(strings.ToTitle), + }, // to_title(s) => string + "to_upper": &tengo.UserFunction{ + Name: "to_upper", + Value: FuncASRS(strings.ToUpper), + }, // to_upper(s) => string + "pad_left": &tengo.UserFunction{ + Name: "pad_left", + Value: textPadLeft, + }, // pad_left(s, pad_len, pad_with) => string + "pad_right": &tengo.UserFunction{ + Name: "pad_right", + Value: textPadRight, + }, // pad_right(s, pad_len, pad_with) => string + "trim": &tengo.UserFunction{ + Name: "trim", + Value: FuncASSRS(strings.Trim), + }, // trim(s, cutset) => string + "trim_left": &tengo.UserFunction{ + Name: "trim_left", + Value: FuncASSRS(strings.TrimLeft), + }, // trim_left(s, cutset) => string + "trim_prefix": &tengo.UserFunction{ + Name: "trim_prefix", + Value: FuncASSRS(strings.TrimPrefix), + }, // trim_prefix(s, prefix) => string + "trim_right": &tengo.UserFunction{ + Name: "trim_right", + Value: FuncASSRS(strings.TrimRight), + }, // trim_right(s, cutset) => string + "trim_space": &tengo.UserFunction{ + Name: "trim_space", + Value: FuncASRS(strings.TrimSpace), + }, // trim_space(s) => string + "trim_suffix": &tengo.UserFunction{ + Name: "trim_suffix", + Value: FuncASSRS(strings.TrimSuffix), + }, // trim_suffix(s, suffix) => string + "atoi": &tengo.UserFunction{ + Name: "atoi", + Value: FuncASRIE(strconv.Atoi), + }, // atoi(str) => int/error + "format_bool": &tengo.UserFunction{ + Name: "format_bool", + Value: textFormatBool, + }, // format_bool(b) => string + "format_float": &tengo.UserFunction{ + Name: "format_float", + Value: textFormatFloat, + }, // format_float(f, fmt, prec, bits) => string + "format_int": &tengo.UserFunction{ + Name: "format_int", + Value: textFormatInt, + }, // format_int(i, base) => string + "itoa": &tengo.UserFunction{ + Name: "itoa", + Value: FuncAIRS(strconv.Itoa), + }, // itoa(i) => string + "parse_bool": &tengo.UserFunction{ + Name: "parse_bool", + Value: textParseBool, + }, // parse_bool(str) => bool/error + "parse_float": &tengo.UserFunction{ + Name: "parse_float", + Value: textParseFloat, + }, // parse_float(str, bits) => float/error + "parse_int": &tengo.UserFunction{ + Name: "parse_int", + Value: textParseInt, + }, // parse_int(str, base, bits) => int/error + "quote": &tengo.UserFunction{ + Name: "quote", + Value: FuncASRS(strconv.Quote), + }, // quote(str) => string + "unquote": &tengo.UserFunction{ + Name: "unquote", + Value: FuncASRSE(strconv.Unquote), + }, // unquote(str) => string/error +} + +func textREMatch(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + s2, ok := tengo.ToString(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + return + } + + matched, err := regexp.MatchString(s1, s2) + if err != nil { + ret = wrapError(err) + return + } + + if matched { + ret = tengo.TrueValue + } else { + ret = tengo.FalseValue + } + + return +} + +func textREFind(args ...tengo.Object) (ret tengo.Object, err error) { + numArgs := len(args) + if numArgs != 2 && numArgs != 3 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + re, err := regexp.Compile(s1) + if err != nil { + ret = wrapError(err) + return + } + + s2, ok := tengo.ToString(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + return + } + + if numArgs < 3 { + m := re.FindStringSubmatchIndex(s2) + if m == nil { + ret = tengo.UndefinedValue + return + } + + arr := &tengo.Array{} + for i := 0; i < len(m); i += 2 { + arr.Value = append(arr.Value, + &tengo.ImmutableMap{Value: map[string]tengo.Object{ + "text": &tengo.String{Value: s2[m[i]:m[i+1]]}, + "begin": &tengo.Int{Value: int64(m[i])}, + "end": &tengo.Int{Value: int64(m[i+1])}, + }}) + } + + ret = &tengo.Array{Value: []tengo.Object{arr}} + + return + } + + i3, ok := tengo.ToInt(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "int(compatible)", + Found: args[2].TypeName(), + } + return + } + m := re.FindAllStringSubmatchIndex(s2, i3) + if m == nil { + ret = tengo.UndefinedValue + return + } + + arr := &tengo.Array{} + for _, m := range m { + subMatch := &tengo.Array{} + for i := 0; i < len(m); i += 2 { + subMatch.Value = append(subMatch.Value, + &tengo.ImmutableMap{Value: map[string]tengo.Object{ + "text": &tengo.String{Value: s2[m[i]:m[i+1]]}, + "begin": &tengo.Int{Value: int64(m[i])}, + "end": &tengo.Int{Value: int64(m[i+1])}, + }}) + } + + arr.Value = append(arr.Value, subMatch) + } + + ret = arr + + return +} + +func textREReplace(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 3 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + s2, ok := tengo.ToString(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + return + } + + s3, ok := tengo.ToString(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "string(compatible)", + Found: args[2].TypeName(), + } + return + } + + re, err := regexp.Compile(s1) + if err != nil { + ret = wrapError(err) + } else { + s, ok := doTextRegexpReplace(re, s2, s3) + if !ok { + return nil, tengo.ErrStringLimit + } + + ret = &tengo.String{Value: s} + } + + return +} + +func textRESplit(args ...tengo.Object) (ret tengo.Object, err error) { + numArgs := len(args) + if numArgs != 2 && numArgs != 3 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + s2, ok := tengo.ToString(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + return + } + + var i3 = -1 + if numArgs > 2 { + i3, ok = tengo.ToInt(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "int(compatible)", + Found: args[2].TypeName(), + } + return + } + } + + re, err := regexp.Compile(s1) + if err != nil { + ret = wrapError(err) + return + } + + arr := &tengo.Array{} + for _, s := range re.Split(s2, i3) { + arr.Value = append(arr.Value, &tengo.String{Value: s}) + } + + ret = arr + + return +} + +func textRECompile(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + re, err := regexp.Compile(s1) + if err != nil { + ret = wrapError(err) + } else { + ret = makeTextRegexp(re) + } + + return +} + +func textReplace(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 4 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + s2, ok := tengo.ToString(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + return + } + + s3, ok := tengo.ToString(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "string(compatible)", + Found: args[2].TypeName(), + } + return + } + + i4, ok := tengo.ToInt(args[3]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "fourth", + Expected: "int(compatible)", + Found: args[3].TypeName(), + } + return + } + + s, ok := doTextReplace(s1, s2, s3, i4) + if !ok { + err = tengo.ErrStringLimit + return + } + + ret = &tengo.String{Value: s} + + return +} + +func textSubstring(args ...tengo.Object) (ret tengo.Object, err error) { + argslen := len(args) + if argslen != 2 && argslen != 3 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + i2, ok := tengo.ToInt(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + + strlen := len(s1) + i3 := strlen + if argslen == 3 { + i3, ok = tengo.ToInt(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "int(compatible)", + Found: args[2].TypeName(), + } + return + } + } + + if i2 > i3 { + err = tengo.ErrInvalidIndexType + return + } + + if i2 < 0 { + i2 = 0 + } else if i2 > strlen { + i2 = strlen + } + + if i3 < 0 { + i3 = 0 + } else if i3 > strlen { + i3 = strlen + } + + ret = &tengo.String{Value: s1[i2:i3]} + + return +} + +func textPadLeft(args ...tengo.Object) (ret tengo.Object, err error) { + argslen := len(args) + if argslen != 2 && argslen != 3 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + i2, ok := tengo.ToInt(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + + if i2 > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + + sLen := len(s1) + if sLen >= i2 { + ret = &tengo.String{Value: s1} + return + } + + s3 := " " + if argslen == 3 { + s3, ok = tengo.ToString(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "string(compatible)", + Found: args[2].TypeName(), + } + return + } + } + + padStrLen := len(s3) + if padStrLen == 0 { + ret = &tengo.String{Value: s1} + return + } + + padCount := ((i2 - padStrLen) / padStrLen) + 1 + retStr := strings.Repeat(s3, padCount) + s1 + ret = &tengo.String{Value: retStr[len(retStr)-i2:]} + + return +} + +func textPadRight(args ...tengo.Object) (ret tengo.Object, err error) { + argslen := len(args) + if argslen != 2 && argslen != 3 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + i2, ok := tengo.ToInt(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + + if i2 > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + + sLen := len(s1) + if sLen >= i2 { + ret = &tengo.String{Value: s1} + return + } + + s3 := " " + if argslen == 3 { + s3, ok = tengo.ToString(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "string(compatible)", + Found: args[2].TypeName(), + } + return + } + } + + padStrLen := len(s3) + if padStrLen == 0 { + ret = &tengo.String{Value: s1} + return + } + + padCount := ((i2 - padStrLen) / padStrLen) + 1 + retStr := s1 + strings.Repeat(s3, padCount) + ret = &tengo.String{Value: retStr[:i2]} + + return +} + +func textRepeat(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + + i2, ok := tengo.ToInt(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + } + + if len(s1)*i2 > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + + return &tengo.String{Value: strings.Repeat(s1, i2)}, nil +} + +func textJoin(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + + var slen int + var ss1 []string + switch arg0 := args[0].(type) { + case *tengo.Array: + for idx, a := range arg0.Value { + as, ok := tengo.ToString(a) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: fmt.Sprintf("first[%d]", idx), + Expected: "string(compatible)", + Found: a.TypeName(), + } + } + slen += len(as) + ss1 = append(ss1, as) + } + case *tengo.ImmutableArray: + for idx, a := range arg0.Value { + as, ok := tengo.ToString(a) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: fmt.Sprintf("first[%d]", idx), + Expected: "string(compatible)", + Found: a.TypeName(), + } + } + slen += len(as) + ss1 = append(ss1, as) + } + default: + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "array", + Found: args[0].TypeName(), + } + } + + s2, ok := tengo.ToString(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + } + + // make sure output length does not exceed the limit + if slen+len(s2)*(len(ss1)-1) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + + return &tengo.String{Value: strings.Join(ss1, s2)}, nil +} + +func textFormatBool(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + b1, ok := args[0].(*tengo.Bool) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "bool", + Found: args[0].TypeName(), + } + return + } + + if b1 == tengo.TrueValue { + ret = &tengo.String{Value: "true"} + } else { + ret = &tengo.String{Value: "false"} + } + + return +} + +func textFormatFloat(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 4 { + err = tengo.ErrWrongNumArguments + return + } + + f1, ok := args[0].(*tengo.Float) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "float", + Found: args[0].TypeName(), + } + return + } + + s2, ok := tengo.ToString(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + return + } + + i3, ok := tengo.ToInt(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "int(compatible)", + Found: args[2].TypeName(), + } + return + } + + i4, ok := tengo.ToInt(args[3]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "fourth", + Expected: "int(compatible)", + Found: args[3].TypeName(), + } + return + } + + ret = &tengo.String{Value: strconv.FormatFloat(f1.Value, s2[0], i3, i4)} + + return +} + +func textFormatInt(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + err = tengo.ErrWrongNumArguments + return + } + + i1, ok := args[0].(*tengo.Int) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int", + Found: args[0].TypeName(), + } + return + } + + i2, ok := tengo.ToInt(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + + ret = &tengo.String{Value: strconv.FormatInt(i1.Value, i2)} + + return +} + +func textParseBool(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := args[0].(*tengo.String) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string", + Found: args[0].TypeName(), + } + return + } + + parsed, err := strconv.ParseBool(s1.Value) + if err != nil { + ret = wrapError(err) + return + } + + if parsed { + ret = tengo.TrueValue + } else { + ret = tengo.FalseValue + } + + return +} + +func textParseFloat(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := args[0].(*tengo.String) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string", + Found: args[0].TypeName(), + } + return + } + + i2, ok := tengo.ToInt(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + + parsed, err := strconv.ParseFloat(s1.Value, i2) + if err != nil { + ret = wrapError(err) + return + } + + ret = &tengo.Float{Value: parsed} + + return +} + +func textParseInt(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 3 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := args[0].(*tengo.String) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string", + Found: args[0].TypeName(), + } + return + } + + i2, ok := tengo.ToInt(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + + i3, ok := tengo.ToInt(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "int(compatible)", + Found: args[2].TypeName(), + } + return + } + + parsed, err := strconv.ParseInt(s1.Value, i2, i3) + if err != nil { + ret = wrapError(err) + return + } + + ret = &tengo.Int{Value: parsed} + + return +} + +// Modified implementation of strings.Replace +// to limit the maximum length of output string. +func doTextReplace(s, old, new string, n int) (string, bool) { + if old == new || n == 0 { + return s, true // avoid allocation + } + + // Compute number of replacements. + if m := strings.Count(s, old); m == 0 { + return s, true // avoid allocation + } else if n < 0 || m < n { + n = m + } + + // Apply replacements to buffer. + t := make([]byte, len(s)+n*(len(new)-len(old))) + w := 0 + start := 0 + for i := 0; i < n; i++ { + j := start + if len(old) == 0 { + if i > 0 { + _, wid := utf8.DecodeRuneInString(s[start:]) + j += wid + } + } else { + j += strings.Index(s[start:], old) + } + + ssj := s[start:j] + if w+len(ssj)+len(new) > tengo.MaxStringLen { + return "", false + } + + w += copy(t[w:], ssj) + w += copy(t[w:], new) + start = j + len(old) + } + + ss := s[start:] + if w+len(ss) > tengo.MaxStringLen { + return "", false + } + + w += copy(t[w:], ss) + + return string(t[0:w]), true +} |