Merge pull request #43 from d5/printf
add 'printf' and 'sprintf' builtin functions
This commit is contained in:
commit
a1bd73f238
5 changed files with 92 additions and 2 deletions
|
@ -697,7 +697,7 @@ func TestCompiler_Compile(t *testing.T) {
|
||||||
expect(t, `len([]);`,
|
expect(t, `len([]);`,
|
||||||
bytecode(
|
bytecode(
|
||||||
concat(
|
concat(
|
||||||
compiler.MakeInstruction(compiler.OpGetBuiltin, 1),
|
compiler.MakeInstruction(compiler.OpGetBuiltin, 3),
|
||||||
compiler.MakeInstruction(compiler.OpArray, 0),
|
compiler.MakeInstruction(compiler.OpArray, 0),
|
||||||
compiler.MakeInstruction(compiler.OpCall, 1),
|
compiler.MakeInstruction(compiler.OpCall, 1),
|
||||||
compiler.MakeInstruction(compiler.OpPop)),
|
compiler.MakeInstruction(compiler.OpPop)),
|
||||||
|
@ -710,7 +710,7 @@ func TestCompiler_Compile(t *testing.T) {
|
||||||
compiler.MakeInstruction(compiler.OpPop)),
|
compiler.MakeInstruction(compiler.OpPop)),
|
||||||
objectsArray(
|
objectsArray(
|
||||||
compiledFunction(0, 0,
|
compiledFunction(0, 0,
|
||||||
compiler.MakeInstruction(compiler.OpGetBuiltin, 1),
|
compiler.MakeInstruction(compiler.OpGetBuiltin, 3),
|
||||||
compiler.MakeInstruction(compiler.OpArray, 0),
|
compiler.MakeInstruction(compiler.OpArray, 0),
|
||||||
compiler.MakeInstruction(compiler.OpCall, 1),
|
compiler.MakeInstruction(compiler.OpCall, 1),
|
||||||
compiler.MakeInstruction(compiler.OpReturnValue, 1)))))
|
compiler.MakeInstruction(compiler.OpReturnValue, 1)))))
|
||||||
|
|
|
@ -7,6 +7,29 @@ Prints a string representation of the given variable to the standard output.
|
||||||
```golang
|
```golang
|
||||||
v := [1, 2, 3]
|
v := [1, 2, 3]
|
||||||
print(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
|
## len
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// print(args...)
|
||||||
func builtinPrint(args ...Object) (Object, error) {
|
func builtinPrint(args ...Object) (Object, error) {
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
if str, ok := arg.(*String); ok {
|
if str, ok := arg.(*String); ok {
|
||||||
|
@ -15,3 +16,52 @@ func builtinPrint(args ...Object) (Object, error) {
|
||||||
|
|
||||||
return nil, nil
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,14 @@ var Builtins = []NamedBuiltinFunc{
|
||||||
Name: "print",
|
Name: "print",
|
||||||
Func: builtinPrint,
|
Func: builtinPrint,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "printf",
|
||||||
|
Func: builtinPrintf,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "sprintf",
|
||||||
|
Func: builtinSprintf,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "len",
|
Name: "len",
|
||||||
Func: builtinLen,
|
Func: builtinLen,
|
||||||
|
|
|
@ -140,4 +140,13 @@ func TestBuiltinFunction(t *testing.T) {
|
||||||
|
|
||||||
expect(t, `out = from_json("5")`, 5.0)
|
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})
|
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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue