Skip to content

Commit

Permalink
add 'printf' and 'sprintf' builtin functions
Browse files Browse the repository at this point in the history
  • Loading branch information
d5 committed Jan 25, 2019
1 parent 1315489 commit 37016f4
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 0 deletions.
23 changes: 23 additions & 0 deletions docs/builtins.md
Expand Up @@ -7,6 +7,29 @@ Prints a string representation of the given variable to the standard output.
```golang
v := [1, 2, 3]
print(v) // "[1, 2, 3]"

print(1, 2, 3)
// "1"
// "2"
// "3"
```

## printf

Prints a formatted string to the standard output. It does not append the newline character at the end. The first argument must a String object. It's same as Go's `fmt.Printf`.

```golang
a := [1, 2, 3]
printf("foo %v", a) // "foo [1, 2, 3]"
```

## sprintf

Returns a formatted string. The first argument must be a String object. It's the same as Go's `fmt.Sprintf`.

```golang
a := [1, 2, 3]
b := sprintp("foo %v", a) // b == "foo [1, 2, 3]"
```

## len
Expand Down
50 changes: 50 additions & 0 deletions objects/builtin_print.go
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
)

// print(args...)
func builtinPrint(args ...Object) (Object, error) {
for _, arg := range args {
if str, ok := arg.(*String); ok {
Expand All @@ -15,3 +16,52 @@ func builtinPrint(args ...Object) (Object, error) {

return nil, nil
}

// printf("format", args...)
func builtinPrintf(args ...Object) (Object, error) {
numArgs := len(args)
if numArgs == 0 {
return nil, ErrWrongNumArguments
}

format, ok := args[0].(*String)
if !ok {
return nil, ErrInvalidTypeConversion
}
if numArgs == 1 {
fmt.Print(format)
return nil, nil
}

formatArgs := make([]interface{}, numArgs-1, numArgs-1)
for idx, arg := range args[1:] {
formatArgs[idx] = objectToInterface(arg)
}

fmt.Printf(format.Value, formatArgs...)

return nil, nil
}

// sprintf("format", args...)
func builtinSprintf(args ...Object) (Object, error) {
numArgs := len(args)
if numArgs == 0 {
return nil, ErrWrongNumArguments
}

format, ok := args[0].(*String)
if !ok {
return nil, ErrInvalidTypeConversion
}
if numArgs == 1 {
return format, nil // okay to return 'format' directly as String is immutable
}

formatArgs := make([]interface{}, numArgs-1, numArgs-1)
for idx, arg := range args[1:] {
formatArgs[idx] = objectToInterface(arg)
}

return &String{Value: fmt.Sprintf(format.Value, formatArgs...)}, nil
}
8 changes: 8 additions & 0 deletions objects/builtins.go
Expand Up @@ -12,6 +12,14 @@ var Builtins = []NamedBuiltinFunc{
Name: "print",
Func: builtinPrint,
},
{
Name: "printf",
Func: builtinPrintf,
},
{
Name: "sprintf",
Func: builtinSprintf,
},
{
Name: "len",
Func: builtinLen,
Expand Down
9 changes: 9 additions & 0 deletions runtime/vm_builtin_test.go
Expand Up @@ -140,4 +140,13 @@ func TestBuiltinFunction(t *testing.T) {

expect(t, `out = from_json("5")`, 5.0)
expect(t, `out = from_json("[\"bar\",1,1.8,56,true]")`, ARR{"bar", 1.0, 1.8, 56.0, true})

// sprintf
expect(t, `out = sprintf("")`, "")
expect(t, `out = sprintf("foo")`, "foo")
expect(t, `out = sprintf("foo %d %v %s", 1, 2, "bar")`, "foo 1 2 bar")
expect(t, `out = sprintf("foo %v", [1, "bar", true])`, "foo [1 bar true]")
expect(t, `out = sprintf("foo %v %d", [1, "bar", true], 19)`, "foo [1 bar true] 19")
expectError(t, `sprintf(1)`) // format has to be String
expectError(t, `sprintf('c')`) // format has to be String
}

0 comments on commit 37016f4

Please sign in to comment.