diff --git a/objects/builtin_json.go b/objects/builtin_json.go index b341365..d792212 100644 --- a/objects/builtin_json.go +++ b/objects/builtin_json.go @@ -12,7 +12,12 @@ func builtinToJSON(args ...Object) (Object, error) { return nil, ErrWrongNumArguments } - res, err := json.Marshal(objectToInterface(args[0])) + v := objectToInterface(args[0]) + if vErr, isErr := v.(error); isErr { + v = vErr.Error() + } + + res, err := json.Marshal(v) if err != nil { return &Error{Value: &String{Value: err.Error()}}, nil } diff --git a/objects/conversion.go b/objects/conversion.go index 714f261..306fdb1 100644 --- a/objects/conversion.go +++ b/objects/conversion.go @@ -1,6 +1,7 @@ package objects import ( + "errors" "fmt" "strconv" "time" @@ -178,11 +179,25 @@ func objectToInterface(o Object) (res interface{}) { for i, val := range o.Value { res.([]interface{})[i] = objectToInterface(val) } + case *ImmutableArray: + res = make([]interface{}, len(o.Value)) + for i, val := range o.Value { + res.([]interface{})[i] = objectToInterface(val) + } case *Map: res = make(map[string]interface{}) for key, v := range o.Value { res.(map[string]interface{})[key] = objectToInterface(v) } + case *ImmutableMap: + res = make(map[string]interface{}) + for key, v := range o.Value { + res.(map[string]interface{})[key] = objectToInterface(v) + } + case *Time: + res = o.Value + case *Error: + res = errors.New(o.String()) case Object: return o } diff --git a/runtime/vm_builtin_test.go b/runtime/vm_builtin_test.go index b5198b2..1ae3311 100644 --- a/runtime/vm_builtin_test.go +++ b/runtime/vm_builtin_test.go @@ -127,17 +127,24 @@ func TestBuiltinFunction(t *testing.T) { // to_json expect(t, `out = to_json(5)`, []byte("5")) + expect(t, `out = to_json("foobar")`, []byte(`"foobar"`)) expect(t, `out = to_json({foo: 5})`, []byte("{\"foo\":5}")) + expect(t, `out = to_json(immutable({foo: 5}))`, []byte("{\"foo\":5}")) + expect(t, `out = to_json([1,2,3])`, []byte("[1,2,3]")) + expect(t, `out = to_json(immutable([1,2,3]))`, []byte("[1,2,3]")) expect(t, `out = to_json({foo: "bar"})`, []byte("{\"foo\":\"bar\"}")) expect(t, `out = to_json({foo: 1.8})`, []byte("{\"foo\":1.8}")) expect(t, `out = to_json({foo: true})`, []byte("{\"foo\":true}")) expect(t, `out = to_json({foo: '8'})`, []byte("{\"foo\":56}")) expect(t, `out = to_json({foo: bytes("foo")})`, []byte("{\"foo\":\"Zm9v\"}")) // json encoding returns []byte as base64 encoded string expect(t, `out = to_json({foo: ["bar", 1, 1.8, '8', true]})`, []byte("{\"foo\":[\"bar\",1,1.8,56,true]}")) + expect(t, `out = to_json({foo: immutable(["bar", 1, 1.8, '8', true])})`, []byte("{\"foo\":[\"bar\",1,1.8,56,true]}")) expect(t, `out = to_json({foo: [["bar", 1], ["bar", 1]]})`, []byte("{\"foo\":[[\"bar\",1],[\"bar\",1]]}")) expect(t, `out = to_json({foo: {string: "bar", int: 1, float: 1.8, char: '8', bool: true}})`, []byte("{\"foo\":{\"bool\":true,\"char\":56,\"float\":1.8,\"int\":1,\"string\":\"bar\"}}")) + expect(t, `out = to_json({foo: immutable({string: "bar", int: 1, float: 1.8, char: '8', bool: true})})`, []byte("{\"foo\":{\"bool\":true,\"char\":56,\"float\":1.8,\"int\":1,\"string\":\"bar\"}}")) expect(t, `out = to_json({foo: {map1: {string: "bar"}, map2: {int: "1"}}})`, []byte("{\"foo\":{\"map1\":{\"string\":\"bar\"},\"map2\":{\"int\":\"1\"}}}")) expect(t, `out = to_json([["bar", 1], ["bar", 1]])`, []byte("[[\"bar\",1],[\"bar\",1]]")) + expect(t, `out = to_json(error("my error"))`, []byte(`"error: \"my error\""`)) // from_json expect(t, `out = from_json("{\"foo\":5}").foo`, 5.0) @@ -148,8 +155,8 @@ func TestBuiltinFunction(t *testing.T) { expect(t, `out = from_json("{\"foo\":[[\"bar\",1],[\"bar\",1]]}").foo[0]`, ARR{"bar", 1.0}) expect(t, `out = from_json("{\"foo\":{\"bool\":true,\"char\":56,\"float\":1.8,\"int\":1,\"string\":\"bar\"}}").foo.bool`, true) expect(t, `out = from_json("{\"foo\":{\"map1\":{\"string\":\"bar\"},\"map2\":{\"int\":\"1\"}}}").foo.map1.string`, "bar") - expect(t, `out = from_json("5")`, 5.0) + expect(t, `out = from_json("\"foobar\"")`, "foobar") expect(t, `out = from_json("[\"bar\",1,1.8,56,true]")`, ARR{"bar", 1.0, 1.8, 56.0, true}) // sprintf