add strconv functions

This commit is contained in:
Daniel Kang 2019-01-29 15:05:03 -08:00
parent 309b03bb30
commit f752601ff2
4 changed files with 236 additions and 0 deletions

View file

@ -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
},
}
}

View file

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

View file

@ -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 {

View file

@ -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)
}