1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072 |
- 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
- }
|