int() bool() and str()
Some checks failed
Build / build (push) Successful in 9m45s
Test / build (push) Failing after 16m25s

This commit is contained in:
Chuck Smith
2024-03-21 15:19:48 -04:00
parent 43362475f9
commit d3471af03d
7 changed files with 138 additions and 3 deletions

View File

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

View File

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

View File

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

View File

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