Skip to content

Commit

Permalink
add .to_json() (#82)
Browse files Browse the repository at this point in the history
* add .to_json()

Signed-off-by: Flipez <code@brauser.io>

* add marshal error test

Signed-off-by: Flipez <code@brauser.io>

* add not serializable test

Signed-off-by: Flipez <code@brauser.io>

* remove empty line

Signed-off-by: Flipez <code@brauser.io>
  • Loading branch information
Flipez authored Mar 14, 2022
1 parent e84f176 commit a1ad606
Show file tree
Hide file tree
Showing 14 changed files with 84 additions and 0 deletions.
5 changes: 5 additions & 0 deletions object/array.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package object

import (
"bytes"
"encoding/json"
"hash/fnv"
"strings"
)
Expand Down Expand Up @@ -214,3 +215,7 @@ func (ao *Array) Next() (Object, Object, bool) {

return nil, NewInteger(0), false
}

func (ao *Array) MarshalJSON() ([]byte, error) {
return json.Marshal(ao.Elements)
}
2 changes: 2 additions & 0 deletions object/array_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ func TestArrayObjectMethods(t *testing.T) {
{"[1,2,3].first()", 1},
{"[].last()", "NULL"},
{"[1,2,3].last()", 3},
{"[1,2,3].to_json()", "[1,2,3]"},
{`["test",true,3].to_json()`, `["test",true,3]`},
}

testInput(t, tests)
Expand Down
5 changes: 5 additions & 0 deletions object/boolean.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package object

import (
"encoding/json"
"fmt"
"strconv"
)
Expand Down Expand Up @@ -49,3 +50,7 @@ func (b *Boolean) InvokeMethod(method string, env Environment, args ...Object) O
return objectMethodLookup(b, method, env, args)

}

func (b *Boolean) MarshalJSON() ([]byte, error) {
return json.Marshal(b.Value)
}
3 changes: 3 additions & 0 deletions object/boolean_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ func TestBooleanObjectMethods(t *testing.T) {
{"(true.wat().lines().size() == true.methods().size() + 1).plz_s()", "true"},
{"true == true", true},
{"true == false", false},

{"true.to_json()", "true"},
{"false.to_json()", "false"},
}

testInput(t, tests)
Expand Down
5 changes: 5 additions & 0 deletions object/float.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package object

import (
"encoding/json"
"fmt"
"hash/fnv"
"strconv"
Expand Down Expand Up @@ -82,3 +83,7 @@ func (f *Float) toString() string {
}
return strconv.FormatFloat(f.Value, 'f', -1, 64)
}

func (f *Float) MarshalJSON() ([]byte, error) {
return json.Marshal(f.Value)
}
2 changes: 2 additions & 0 deletions object/float_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ func TestFloatObjectMethods(t *testing.T) {
{`10.0.type()`, "FLOAT"},
{`2.2.nope()`, "undefined method `.nope()` for FLOAT"},
{`(2.0.wat().lines().size() == 2.0.methods().size() + 1).plz_s()`, "true"},
{"1.1.to_json()", "1.1"},
{"3.123456.to_json()", "3.123456"},
}

testInput(t, tests)
Expand Down
23 changes: 23 additions & 0 deletions object/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package object

import (
"bytes"
"encoding/json"
"fmt"
"hash/fnv"
"strings"
Expand Down Expand Up @@ -126,3 +127,25 @@ func (h *Hash) Next() (Object, Object, bool) {

return nil, NewInteger(0), false
}

func (h *Hash) MarshalJSON() ([]byte, error) {
tempHash := make(map[string]Serializable)
for _, pair := range h.Pairs {
_, ok := pair.Key.(Serializable)
if !ok {
return nil, fmt.Errorf("unable to serialize key: %s", pair.Key.Inspect())
}
serializableValue, ok := pair.Value.(Serializable)
if !ok {
return nil, fmt.Errorf("unable to serialize value: %s", pair.Key.Inspect())
}

if str, ok := pair.Key.(*String); ok {
tempHash[str.Value] = serializableValue
} else {
tempHash[pair.Key.Inspect()] = serializableValue
}
}

return json.Marshal(tempHash)
}
3 changes: 3 additions & 0 deletions object/hash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ func TestHashObjectMethods(t *testing.T) {
{`{"a": 1, "b": 2}["a"]`, 1},
{`{"a": 1, "b": 2}.keys().size()`, 2},
{`{"a": 1, "b": 2}.values().size()`, 2},
{`{"a": "b"}.to_json()`, `{"a":"b"}`},
{`{1: "b"}.to_json()`, `{"1":"b"}`},
{`{true: "b"}.to_json()`, `{"true":"b"}`},
}

testInput(t, tests)
Expand Down
1 change: 1 addition & 0 deletions object/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func TestHTTPObjectMethods(t *testing.T) {
{`def test(){};HTTP.handle("/", test)`, "Invalid handler. Call only supported on instance."},
{`a = HTTP.new(); a.listen(-1)`, "listening on port -1: listen tcp: address -1: invalid port"},
{`a = HTTP.new(); a.listen(80)`, "listening on port 80: listen tcp :80: bind: permission denied"},
{"HTTP.new().to_json()", "HTTP is not serializable"},
}

testInput(t, tests)
Expand Down
5 changes: 5 additions & 0 deletions object/integer.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package object

import (
"encoding/json"
"fmt"
"strconv"
)
Expand Down Expand Up @@ -102,3 +103,7 @@ func (i *Integer) Next() (Object, Object, bool) {
}
return nil, NewInteger(0), false
}

func (i *Integer) MarshalJSON() ([]byte, error) {
return json.Marshal(i.Value)
}
1 change: 1 addition & 0 deletions object/integer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func TestIntegerObjectMethods(t *testing.T) {
{`10.type()`, "INTEGER"},
{`2.nope()`, "undefined method `.nope()` for INTEGER"},
{`(2.wat().lines().size() == 2.methods().size() + 1).plz_s()`, "true"},
{"1.to_json()", "1"},
}

testInput(t, tests)
Expand Down
22 changes: 22 additions & 0 deletions object/object.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package object

import (
"encoding/json"
"fmt"
"strings"

Expand All @@ -26,6 +27,10 @@ type Hashable interface {
HashKey() HashKey
}

type Serializable interface {
MarshalJSON() ([]byte, error)
}

const (
INTEGER_OBJ = "INTEGER"
FLOAT_OBJ = "FLOAT"
Expand Down Expand Up @@ -147,6 +152,23 @@ func ListObjectMethods() map[ObjectType]map[string]ObjectMethod {

func init() {
objectMethods["*"] = map[string]ObjectMethod{
"to_json": ObjectMethod{
description: "Returns the object as json notation.",
returnPattern: [][]string{
[]string{STRING_OBJ, ERROR_OBJ},
},
method: func(o Object, _ []Object, _ Environment) Object {
if serializeableObject, ok := o.(Serializable); ok {
j, err := json.Marshal(serializeableObject)
if err != nil {
return NewErrorFormat("Error while marshal value: %s", err.Error())
}
return NewString(string(j))
}

return NewErrorFormat("%s is not serializable", o.Type())
},
},
"methods": ObjectMethod{
description: "Returns an array of all supported methods names.",
example: `🚀 > "test".methods()
Expand Down
5 changes: 5 additions & 0 deletions object/string.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package object

import (
"encoding/json"
"hash/fnv"
"strconv"
"strings"
Expand Down Expand Up @@ -344,3 +345,7 @@ func (s *String) Next() (Object, Object, bool) {

return nil, NewInteger(0), false
}

func (s *String) MarshalJSON() ([]byte, error) {
return json.Marshal(s.Value)
}
2 changes: 2 additions & 0 deletions object/string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ func TestStringObjectMethods(t *testing.T) {
{`a = "test"; b = []; foreach char in a { b.yoink(char) }; b.size()`, 4},
{`"test" * 2`, "testtest"},
{`2 * "test"`, "testtest"},
{`"test".to_json()`, `"test"`},
{`{"test": HTTP.new()}.to_json()`, `Error while marshal value: json: error calling MarshalJSON for type *object.Hash: unable to serialize value: "test"`},
}

testInput(t, tests)
Expand Down

1 comment on commit a1ad606

@vercel
Copy link

@vercel vercel bot commented on a1ad606 Mar 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.