add strconv functions
This commit is contained in:
parent
309b03bb30
commit
f752601ff2
4 changed files with 236 additions and 0 deletions
|
@ -829,3 +829,22 @@ func FuncAIRSsE(fn func(int) ([]string, error)) *objects.UserFunction {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
// FuncAIRS transform a function of 'func(int) string' signature
|
||||
// into a user function object.
|
||||
func FuncAIRS(fn func(int) string) *objects.UserFunction {
|
||||
return &objects.UserFunction{
|
||||
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||
if len(args) != 1 {
|
||||
return nil, objects.ErrWrongNumArguments
|
||||
}
|
||||
|
||||
i1, ok := objects.ToInt(args[0])
|
||||
if !ok {
|
||||
return nil, objects.ErrInvalidTypeConversion
|
||||
}
|
||||
|
||||
return &objects.String{Value: fn(i1)}, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -439,6 +439,15 @@ func TestFuncASSRB(t *testing.T) {
|
|||
assert.Equal(t, objects.ErrWrongNumArguments, err)
|
||||
}
|
||||
|
||||
func TestFuncAIRS(t *testing.T) {
|
||||
uf := stdlib.FuncAIRS(func(a int) string { return strconv.Itoa(a) })
|
||||
ret, err := uf.Call(&objects.Int{Value: 55})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, &objects.String{Value: "55"}, ret)
|
||||
ret, err = uf.Call()
|
||||
assert.Equal(t, objects.ErrWrongNumArguments, err)
|
||||
}
|
||||
|
||||
func array(elements ...objects.Object) *objects.Array {
|
||||
return &objects.Array{Value: elements}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package stdlib
|
|||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/d5/tengo/objects"
|
||||
|
@ -325,6 +326,196 @@ var textModule = map[string]objects.Object{
|
|||
"trim_space": FuncASRS(strings.TrimSpace),
|
||||
// trim_suffix(s, suffix) => string
|
||||
"trim_suffix": FuncASSRS(strings.TrimSuffix),
|
||||
// atoi(str) => int/error
|
||||
"atoi": FuncASRIE(strconv.Atoi),
|
||||
// format_bool(b) => string
|
||||
"format_bool": &objects.UserFunction{
|
||||
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||
if len(args) != 1 {
|
||||
err = objects.ErrWrongNumArguments
|
||||
return
|
||||
}
|
||||
|
||||
b1, ok := args[0].(*objects.Bool)
|
||||
if !ok {
|
||||
err = objects.ErrInvalidTypeConversion
|
||||
return
|
||||
}
|
||||
|
||||
if b1 == objects.TrueValue {
|
||||
ret = &objects.String{Value: "true"}
|
||||
} else {
|
||||
ret = &objects.String{Value: "false"}
|
||||
}
|
||||
|
||||
return
|
||||
},
|
||||
},
|
||||
// format_float(f, fmt, prec, bits) => string
|
||||
"format_float": &objects.UserFunction{
|
||||
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||
if len(args) != 4 {
|
||||
err = objects.ErrWrongNumArguments
|
||||
return
|
||||
}
|
||||
|
||||
f1, ok := args[0].(*objects.Float)
|
||||
if !ok {
|
||||
err = objects.ErrInvalidTypeConversion
|
||||
return
|
||||
}
|
||||
|
||||
s2, ok := objects.ToString(args[1])
|
||||
if !ok {
|
||||
err = objects.ErrInvalidTypeConversion
|
||||
return
|
||||
}
|
||||
|
||||
i3, ok := objects.ToInt(args[2])
|
||||
if !ok {
|
||||
err = objects.ErrInvalidTypeConversion
|
||||
return
|
||||
}
|
||||
|
||||
i4, ok := objects.ToInt(args[3])
|
||||
if !ok {
|
||||
err = objects.ErrInvalidTypeConversion
|
||||
return
|
||||
}
|
||||
|
||||
ret = &objects.String{Value: strconv.FormatFloat(f1.Value, s2[0], i3, i4)}
|
||||
|
||||
return
|
||||
},
|
||||
},
|
||||
// format_int(i, base) => string
|
||||
"format_int": &objects.UserFunction{
|
||||
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||
if len(args) != 2 {
|
||||
err = objects.ErrWrongNumArguments
|
||||
return
|
||||
}
|
||||
|
||||
i1, ok := args[0].(*objects.Int)
|
||||
if !ok {
|
||||
err = objects.ErrInvalidTypeConversion
|
||||
return
|
||||
}
|
||||
|
||||
i2, ok := objects.ToInt(args[1])
|
||||
if !ok {
|
||||
err = objects.ErrInvalidTypeConversion
|
||||
return
|
||||
}
|
||||
|
||||
ret = &objects.String{Value: strconv.FormatInt(i1.Value, i2)}
|
||||
|
||||
return
|
||||
},
|
||||
},
|
||||
// itoa(i) => string
|
||||
"itoa": FuncAIRS(strconv.Itoa),
|
||||
// parse_bool(str) => bool/error
|
||||
"parse_bool": &objects.UserFunction{
|
||||
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||
if len(args) != 1 {
|
||||
err = objects.ErrWrongNumArguments
|
||||
return
|
||||
}
|
||||
|
||||
s1, ok := args[0].(*objects.String)
|
||||
if !ok {
|
||||
err = objects.ErrInvalidTypeConversion
|
||||
return
|
||||
}
|
||||
|
||||
parsed, err := strconv.ParseBool(s1.Value)
|
||||
if err != nil {
|
||||
ret = wrapError(err)
|
||||
return
|
||||
}
|
||||
|
||||
if parsed {
|
||||
ret = objects.TrueValue
|
||||
} else {
|
||||
ret = objects.FalseValue
|
||||
}
|
||||
|
||||
return
|
||||
},
|
||||
},
|
||||
// parse_float(str, bits) => float/error
|
||||
"parse_float": &objects.UserFunction{
|
||||
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||
if len(args) != 2 {
|
||||
err = objects.ErrWrongNumArguments
|
||||
return
|
||||
}
|
||||
|
||||
s1, ok := args[0].(*objects.String)
|
||||
if !ok {
|
||||
err = objects.ErrInvalidTypeConversion
|
||||
return
|
||||
}
|
||||
|
||||
i2, ok := objects.ToInt(args[1])
|
||||
if !ok {
|
||||
err = objects.ErrInvalidTypeConversion
|
||||
return
|
||||
}
|
||||
|
||||
parsed, err := strconv.ParseFloat(s1.Value, i2)
|
||||
if err != nil {
|
||||
ret = wrapError(err)
|
||||
return
|
||||
}
|
||||
|
||||
ret = &objects.Float{Value: parsed}
|
||||
|
||||
return
|
||||
},
|
||||
},
|
||||
// parse_int(str, base, bits) => int/error
|
||||
"parse_int": &objects.UserFunction{
|
||||
Value: func(args ...objects.Object) (ret objects.Object, err error) {
|
||||
if len(args) != 3 {
|
||||
err = objects.ErrWrongNumArguments
|
||||
return
|
||||
}
|
||||
|
||||
s1, ok := args[0].(*objects.String)
|
||||
if !ok {
|
||||
err = objects.ErrInvalidTypeConversion
|
||||
return
|
||||
}
|
||||
|
||||
i2, ok := objects.ToInt(args[1])
|
||||
if !ok {
|
||||
err = objects.ErrInvalidTypeConversion
|
||||
return
|
||||
}
|
||||
|
||||
i3, ok := objects.ToInt(args[2])
|
||||
if !ok {
|
||||
err = objects.ErrInvalidTypeConversion
|
||||
return
|
||||
}
|
||||
|
||||
parsed, err := strconv.ParseInt(s1.Value, i2, i3)
|
||||
if err != nil {
|
||||
ret = wrapError(err)
|
||||
return
|
||||
}
|
||||
|
||||
ret = &objects.Int{Value: parsed}
|
||||
|
||||
return
|
||||
},
|
||||
},
|
||||
// quote(str) => string
|
||||
"quote": FuncASRS(strconv.Quote),
|
||||
// unquote(str) => string/error
|
||||
"unquote": FuncASRSE(strconv.Unquote),
|
||||
}
|
||||
|
||||
func stringsRegexpImmutableMap(re *regexp.Regexp) *objects.ImmutableMap {
|
||||
|
|
|
@ -180,4 +180,21 @@ func TestText(t *testing.T) {
|
|||
module(t, "text").call("contains", "abcde", "abcde").expect(true)
|
||||
module(t, "text").call("contains", "abc", "abcde").expect(false)
|
||||
module(t, "text").call("contains", "ab cd", "bc").expect(false)
|
||||
|
||||
module(t, "text").call("replace", "", "", "", -1).expect("")
|
||||
module(t, "text").call("replace", "abcd", "a", "x", -1).expect("xbcd")
|
||||
module(t, "text").call("replace", "aaaa", "a", "x", -1).expect("xxxx")
|
||||
module(t, "text").call("replace", "aaaa", "a", "x", 0).expect("aaaa")
|
||||
module(t, "text").call("replace", "aaaa", "a", "x", 2).expect("xxaa")
|
||||
module(t, "text").call("replace", "abcd", "bc", "x", -1).expect("axd")
|
||||
|
||||
module(t, "text").call("format_bool", true).expect("true")
|
||||
module(t, "text").call("format_bool", false).expect("false")
|
||||
module(t, "text").call("format_float", -19.84, 'f', -1, 64).expect("-19.84")
|
||||
module(t, "text").call("format_int", -1984, 10).expect("-1984")
|
||||
module(t, "text").call("format_int", 1984, 8).expect("3700")
|
||||
module(t, "text").call("parse_bool", "true").expect(true)
|
||||
module(t, "text").call("parse_bool", "0").expect(false)
|
||||
module(t, "text").call("parse_float", "-19.84", 64).expect(-19.84)
|
||||
module(t, "text").call("parse_int", "-1984", 10, 64).expect(-1984)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue