Custom formatter based on go's fmt package. ()

* Custom formatter based on go's fmt package.

* Cleanup

* Cleanup

* Added tengo.MaxStringLen check

* Cleanup
This commit is contained in:
earncef 2019-04-13 20:29:50 +02:00 committed by Daniel
parent bb07fa15b7
commit b2df4f579c
5 changed files with 1262 additions and 23 deletions

27
objects/builtin_format.go Normal file
View file

@ -0,0 +1,27 @@
package objects
func builtinFormat(args ...Object) (Object, error) {
numArgs := len(args)
if numArgs == 0 {
return nil, ErrWrongNumArguments
}
format, ok := args[0].(*String)
if !ok {
return nil, ErrInvalidArgumentType{
Name: "format",
Expected: "string",
Found: args[0].TypeName(),
}
}
if numArgs == 1 {
return format, nil // okay to return 'format' directly as String is immutable
}
s, err := Format(format.Value, args[1:]...)
if err != nil {
return nil, err
}
return &String{Value: s}, nil
}

View file

@ -111,4 +111,8 @@ var Builtins = []*BuiltinFunction{
Name: "type_name",
Value: builtinTypeName,
},
{
Name: "format",
Value: builtinFormat,
},
}

1212
objects/formatter.go Normal file

File diff suppressed because it is too large Load diff

View file

@ -157,6 +157,18 @@ func TestBuiltinFunction(t *testing.T) {
expect(t, `a := func(x) { return func() { return x } }; out = is_callable(a)`, nil, true) // function
expect(t, `a := func(x) { return func() { return x } }; out = is_callable(a(5))`, nil, true) // closure
expect(t, `out = is_callable(x)`, Opts().Symbol("x", &StringArray{Value: []string{"foo", "bar"}}).Skip2ndPass(), true) // user object
expect(t, `out = format("")`, nil, "")
expect(t, `out = format("foo")`, nil, "foo")
expect(t, `out = format("foo %d %v %s", 1, 2, "bar")`, nil, "foo 1 2 bar")
expect(t, `out = format("foo %v", [1, "bar", true])`, nil, `foo [1, "bar", true]`)
expect(t, `out = format("foo %v %d", [1, "bar", true], 19)`, nil, `foo [1, "bar", true] 19`)
expect(t, `out = format("foo %v", {"a": {"b": {"c": [1, 2, 3]}}})`, nil, `foo {a: {b: {c: [1, 2, 3]}}}`)
expect(t, `out = format("%v", [1, [2, [3, 4]]])`, nil, `[1, [2, [3, 4]]]`)
tengo.MaxStringLen = 9
expectError(t, `format("%s", "1234567890")`, nil, "exceeding string size limit")
tengo.MaxStringLen = 2147483647
}
func TestBytesN(t *testing.T) {

View file

@ -44,17 +44,12 @@ func fmtPrintf(args ...objects.Object) (ret objects.Object, err error) {
return nil, nil
}
formatArgs := make([]interface{}, numArgs-1)
for idx, arg := range args[1:] {
switch arg := arg.(type) {
case *objects.Int, *objects.Float, *objects.Bool, *objects.Char, *objects.String, *objects.Bytes:
formatArgs[idx] = objects.ToInterface(arg)
default:
formatArgs[idx] = arg
}
s, err := objects.Format(format.Value, args[1:]...)
if err != nil {
return nil, err
}
fmt.Printf(format.Value, formatArgs...)
fmt.Print(s)
return nil, nil
}
@ -89,20 +84,9 @@ func fmtSprintf(args ...objects.Object) (ret objects.Object, err error) {
return format, nil // okay to return 'format' directly as String is immutable
}
formatArgs := make([]interface{}, numArgs-1)
for idx, arg := range args[1:] {
switch arg := arg.(type) {
case *objects.Int, *objects.Float, *objects.Bool, *objects.Char, *objects.String, *objects.Bytes:
formatArgs[idx] = objects.ToInterface(arg)
default:
formatArgs[idx] = arg
}
}
s := fmt.Sprintf(format.Value, formatArgs...)
if len(s) > tengo.MaxStringLen {
return nil, objects.ErrStringLimit
s, err := objects.Format(format.Value, args[1:]...)
if err != nil {
return nil, err
}
return &objects.String{Value: s}, nil