int() bool() and str()
This commit is contained in:
@@ -992,11 +992,11 @@ func TestBuiltins(t *testing.T) {
|
|||||||
`,
|
`,
|
||||||
expectedConstants: []interface{}{1},
|
expectedConstants: []interface{}{1},
|
||||||
expectedInstructions: []code.Instructions{
|
expectedInstructions: []code.Instructions{
|
||||||
code.Make(code.OpGetBuiltin, 5),
|
code.Make(code.OpGetBuiltin, 7),
|
||||||
code.Make(code.OpArray, 0),
|
code.Make(code.OpArray, 0),
|
||||||
code.Make(code.OpCall, 1),
|
code.Make(code.OpCall, 1),
|
||||||
code.Make(code.OpPop),
|
code.Make(code.OpPop),
|
||||||
code.Make(code.OpGetBuiltin, 8),
|
code.Make(code.OpGetBuiltin, 10),
|
||||||
code.Make(code.OpArray, 0),
|
code.Make(code.OpArray, 0),
|
||||||
code.Make(code.OpConstant, 0),
|
code.Make(code.OpConstant, 0),
|
||||||
code.Make(code.OpCall, 2),
|
code.Make(code.OpCall, 2),
|
||||||
@@ -1007,7 +1007,7 @@ func TestBuiltins(t *testing.T) {
|
|||||||
input: `fn() { return len([]) }`,
|
input: `fn() { return len([]) }`,
|
||||||
expectedConstants: []interface{}{
|
expectedConstants: []interface{}{
|
||||||
[]code.Instructions{
|
[]code.Instructions{
|
||||||
code.Make(code.OpGetBuiltin, 5),
|
code.Make(code.OpGetBuiltin, 7),
|
||||||
code.Make(code.OpArray, 0),
|
code.Make(code.OpArray, 0),
|
||||||
code.Make(code.OpCall, 1),
|
code.Make(code.OpCall, 1),
|
||||||
code.Make(code.OpReturn),
|
code.Make(code.OpReturn),
|
||||||
|
|||||||
@@ -411,12 +411,36 @@ func TestBuiltinFunctions(t *testing.T) {
|
|||||||
{`input()`, ""},
|
{`input()`, ""},
|
||||||
{`pop([])`, errors.New("cannot pop from an empty array")},
|
{`pop([])`, errors.New("cannot pop from an empty array")},
|
||||||
{`pop([1])`, 1},
|
{`pop([1])`, 1},
|
||||||
|
{`bool(1)`, true},
|
||||||
|
{`bool(0)`, false},
|
||||||
|
{`bool(true)`, true},
|
||||||
|
{`bool(false)`, false},
|
||||||
|
{`bool(null)`, false},
|
||||||
|
{`bool("")`, false},
|
||||||
|
{`bool("foo")`, true},
|
||||||
|
{`bool([])`, false},
|
||||||
|
{`bool([1, 2, 3])`, true},
|
||||||
|
{`bool({})`, false},
|
||||||
|
{`bool({"a": 1})`, true},
|
||||||
|
{`int(true)`, 1},
|
||||||
|
{`int(false)`, 0},
|
||||||
|
{`int(1)`, 1},
|
||||||
|
{`int("10")`, 10},
|
||||||
|
{`str(null)`, "null"},
|
||||||
|
{`str(true)`, "true"},
|
||||||
|
{`str(false)`, "false"},
|
||||||
|
{`str(10)`, "10"},
|
||||||
|
{`str("foo")`, "foo"},
|
||||||
|
{`str([1, 2, 3])`, "[1, 2, 3]"},
|
||||||
|
{`str({"a": 1})`, "{\"a\": 1}"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
evaluated := testEval(tt.input)
|
evaluated := testEval(tt.input)
|
||||||
|
|
||||||
switch expected := tt.expected.(type) {
|
switch expected := tt.expected.(type) {
|
||||||
|
case bool:
|
||||||
|
testBooleanObject(t, evaluated, expected)
|
||||||
case int:
|
case int:
|
||||||
testIntegerObject(t, evaluated, int64(expected))
|
testIntegerObject(t, evaluated, int64(expected))
|
||||||
case string:
|
case string:
|
||||||
|
|||||||
38
object/builtin_bool.go
Normal file
38
object/builtin_bool.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package object
|
||||||
|
|
||||||
|
// Bool ...
|
||||||
|
func Bool(args ...Object) Object {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return newError("wrong number of arguments. got=%d, want=1", len(args))
|
||||||
|
}
|
||||||
|
|
||||||
|
switch arg := args[0].(type) {
|
||||||
|
case *Null:
|
||||||
|
return &Boolean{Value: false}
|
||||||
|
case *Boolean:
|
||||||
|
return arg
|
||||||
|
case *Integer:
|
||||||
|
if arg.Value == 0 {
|
||||||
|
return &Boolean{Value: false}
|
||||||
|
}
|
||||||
|
return &Boolean{Value: true}
|
||||||
|
case *String:
|
||||||
|
if len(arg.Value) > 0 {
|
||||||
|
return &Boolean{Value: true}
|
||||||
|
}
|
||||||
|
return &Boolean{Value: false}
|
||||||
|
case *Array:
|
||||||
|
if len(arg.Elements) > 0 {
|
||||||
|
return &Boolean{Value: true}
|
||||||
|
}
|
||||||
|
return &Boolean{Value: false}
|
||||||
|
case *Hash:
|
||||||
|
if len(arg.Pairs) > 0 {
|
||||||
|
return &Boolean{Value: true}
|
||||||
|
}
|
||||||
|
return &Boolean{Value: false}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return newError("argument to `bool` not supported, got=%s", args[0].Type())
|
||||||
|
}
|
||||||
|
}
|
||||||
29
object/builtin_int.go
Normal file
29
object/builtin_int.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package object
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
// Int ...
|
||||||
|
func Int(args ...Object) Object {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return newError("wrong number of arguments. got=%d, want=1", len(args))
|
||||||
|
}
|
||||||
|
|
||||||
|
switch arg := args[0].(type) {
|
||||||
|
case *Boolean:
|
||||||
|
if arg.Value {
|
||||||
|
return &Integer{Value: 1}
|
||||||
|
}
|
||||||
|
return &Integer{Value: 0}
|
||||||
|
case *Integer:
|
||||||
|
return arg
|
||||||
|
case *String:
|
||||||
|
n, err := strconv.ParseInt(arg.Value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return newError("could not parse string to int: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Integer{Value: n}
|
||||||
|
default:
|
||||||
|
return newError("argument to `int` not supported, got=%s", args[0].Type())
|
||||||
|
}
|
||||||
|
}
|
||||||
19
object/builtin_str.go
Normal file
19
object/builtin_str.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Str ...
|
||||||
|
func Str(args ...Object) Object {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return newError("wrong number of arguments. got=%d, want=1", len(args))
|
||||||
|
}
|
||||||
|
|
||||||
|
arg, ok := args[0].(fmt.Stringer)
|
||||||
|
if !ok {
|
||||||
|
return newError("argument to `str` not supported, got %s", args[0].Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
return &String{Value: arg.String()}
|
||||||
|
}
|
||||||
@@ -17,6 +17,9 @@ var Builtins = map[string]*Builtin{
|
|||||||
"pop": {Name: "pop", Fn: Pop},
|
"pop": {Name: "pop", Fn: Pop},
|
||||||
"exit": {Name: "exit", Fn: Exit},
|
"exit": {Name: "exit", Fn: Exit},
|
||||||
"assert": {Name: "assert", Fn: Assert},
|
"assert": {Name: "assert", Fn: Assert},
|
||||||
|
"bool": {Name: "bool", Fn: Bool},
|
||||||
|
"int": {Name: "int", Fn: Int},
|
||||||
|
"str": {Name: "str", Fn: Str},
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuiltinsIndex ...
|
// BuiltinsIndex ...
|
||||||
|
|||||||
@@ -656,6 +656,28 @@ func TestBuiltinFunctions(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{`pop([1])`, 1},
|
{`pop([1])`, 1},
|
||||||
|
{`bool(1)`, true},
|
||||||
|
{`bool(0)`, false},
|
||||||
|
{`bool(true)`, true},
|
||||||
|
{`bool(false)`, false},
|
||||||
|
{`bool(null)`, false},
|
||||||
|
{`bool("")`, false},
|
||||||
|
{`bool("foo")`, true},
|
||||||
|
{`bool([])`, false},
|
||||||
|
{`bool([1, 2, 3])`, true},
|
||||||
|
{`bool({})`, false},
|
||||||
|
{`bool({"a": 1})`, true},
|
||||||
|
{`int(true)`, 1},
|
||||||
|
{`int(false)`, 0},
|
||||||
|
{`int(1)`, 1},
|
||||||
|
{`int("10")`, 10},
|
||||||
|
{`str(null)`, "null"},
|
||||||
|
{`str(true)`, "true"},
|
||||||
|
{`str(false)`, "false"},
|
||||||
|
{`str(10)`, "10"},
|
||||||
|
{`str("foo")`, "foo"},
|
||||||
|
{`str([1, 2, 3])`, "[1, 2, 3]"},
|
||||||
|
{`str({"a": 1})`, "{\"a\": 1}"},
|
||||||
}
|
}
|
||||||
|
|
||||||
runVmTests(t, tests)
|
runVmTests(t, tests)
|
||||||
|
|||||||
Reference in New Issue
Block a user