Skip to content

Commit c872c51

Browse files
authored
add json object (#95)
* add json object Signed-off-by: Flipez <code@brauser.io> * implement json to object conversion Signed-off-by: Flipez <code@brauser.io> * add json tests Signed-off-by: Flipez <code@brauser.io> * more tests Signed-off-by: Flipez <code@brauser.io> * move content Signed-off-by: Flipez <code@brauser.io> * fix test Signed-off-by: Flipez <code@brauser.io> * improve tests Signed-off-by: Flipez <code@brauser.io> * start docs for json Signed-off-by: Flipez <code@brauser.io> * add and generate first docs Signed-off-by: Flipez <code@brauser.io> * go tidy Signed-off-by: Flipez <code@brauser.io> * enhance docs Signed-off-by: Flipez <code@brauser.io>
1 parent 321f478 commit c872c51

9 files changed

Lines changed: 208 additions & 6 deletions

File tree

docs/content/docs/literals/json.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
---
2+
title: "JSON"
3+
menu:
4+
docs:
5+
parent: "literals"
6+
---
7+
# JSON
8+
9+
10+
11+
12+
```js
13+
🚀 > JSON.parse('{"test": 123}')
14+
=> {"test": 123.0}
15+
```
16+
17+
## Literal Specific Methods
18+
19+
### parse(STRING)
20+
> Returns `HASH`
21+
22+
Takes a STRING and parses it to a HASH or ARRAY. Numbers are always FLOAT.
23+
24+
25+
```js
26+
🚀 > JSON.parse('{"test": 123}')
27+
=> {"test": 123.0}
28+
🚀 > JSON.parse('["test", 123]')
29+
=> ["test", 123.0]
30+
```
31+
32+
33+
34+
## Generic Literal Methods
35+
36+
### methods()
37+
> Returns `ARRAY`
38+
39+
Returns an array of all supported methods names.
40+
41+
```js
42+
🚀 > "test".methods()
43+
=> [count, downcase, find, reverse!, split, lines, upcase!, strip!, downcase!, size, plz_i, replace, reverse, strip, upcase]
44+
```
45+
46+
### to_json()
47+
> Returns `STRING|ERROR`
48+
49+
Returns the object as json notation.
50+
51+
```js
52+
🚀 > a = {"test": 1234}
53+
=> {"test": 1234}
54+
🚀 > a.to_json()
55+
=> "{"test":1234}"
56+
```
57+
58+
### type()
59+
> Returns `STRING`
60+
61+
Returns the type of the object.
62+
63+
```js
64+
🚀 > "test".type()
65+
=> "STRING"
66+
```
67+
68+
### wat()
69+
> Returns `STRING`
70+
71+
Returns the supported methods with usage information.
72+
73+
```js
74+
🚀 > true.wat()
75+
=> BOOLEAN supports the following methods:
76+
plz_s()
77+
```

docs/generate.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package main
22

33
import (
4-
"github.com/flipez/rocket-lang/object"
54
"os"
65
"text/template"
6+
7+
"github.com/flipez/rocket-lang/object"
78
)
89

910
type templateData struct {
@@ -26,6 +27,7 @@ func main() {
2627
nil_methods := object.ListObjectMethods()[object.NIL_OBJ]
2728
float_methods := object.ListObjectMethods()[object.FLOAT_OBJ]
2829
http_methods := object.ListObjectMethods()[object.HTTP_OBJ]
30+
json_methods := object.ListObjectMethods()[object.JSON_OBJ]
2931

3032
tempData := templateData{
3133
Title: "String",
@@ -190,6 +192,13 @@ HTTP.listen(3000)
190192
DefaultMethods: default_methods}
191193
create_doc("docs/templates/literal.md", "docs/content/docs/literals/http.md", tempData)
192194

195+
tempData = templateData{
196+
Title: "JSON",
197+
Example: `🚀 > JSON.parse('{"test": 123}')
198+
=> {"test": 123.0}`,
199+
LiteralMethods: json_methods,
200+
DefaultMethods: default_methods}
201+
create_doc("docs/templates/literal.md", "docs/content/docs/literals/json.md", tempData)
193202
}
194203

195204
func create_doc(path string, target string, data templateData) bool {

fixtures/data.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"string": "Kadeem Sawyer",
3+
"float": 12.3,
4+
"array": ["11137", 1234],
5+
"bool": true
6+
}

go.mod

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
module github.com/flipez/rocket-lang
22

3-
go 1.17
3+
go 1.18
44

5-
require github.com/abiosoft/ishell/v2 v2.0.2
5+
require (
6+
github.com/abiosoft/ishell/v2 v2.0.2
7+
github.com/spf13/pflag v1.0.5
8+
)
69

710
require (
11+
github.com/abiosoft/ishell v2.0.0+incompatible // indirect
812
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db // indirect
913
github.com/fatih/color v1.12.0 // indirect
1014
github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
1115
github.com/mattn/go-colorable v0.1.8 // indirect
1216
github.com/mattn/go-isatty v0.0.12 // indirect
13-
github.com/spf13/pflag v1.0.5 // indirect
14-
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae // indirect
17+
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
1518
)

go.sum

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1+
github.com/abiosoft/ishell v2.0.0+incompatible h1:zpwIuEHc37EzrsIYah3cpevrIc8Oma7oZPxr03tlmmw=
2+
github.com/abiosoft/ishell v2.0.0+incompatible/go.mod h1:HQR9AqF2R3P4XXpMpI0NAzgHf/aS6+zVXRj14cVk9qg=
13
github.com/abiosoft/ishell/v2 v2.0.2 h1:5qVfGiQISaYM8TkbBl7RFO6MddABoXpATrsFbVI+SNo=
24
github.com/abiosoft/ishell/v2 v2.0.2/go.mod h1:E4oTCXfo6QjoCart0QYa5m9w4S+deXs/P/9jA77A9Bs=
35
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db h1:CjPUSXOiYptLbTdr1RceuZgSFDQ7U15ITERUGrUORx8=
46
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db/go.mod h1:rB3B4rKii8V21ydCbIzH5hZiCQE7f5E9SzUb/ZZx530=
7+
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
58
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
9+
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
610
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
11+
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
712
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
813
github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
914
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
@@ -13,13 +18,17 @@ github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ
1318
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
1419
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
1520
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
21+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
1622
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
1723
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
1824
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
1925
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
26+
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
2027
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
2128
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
22-
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
2329
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
30+
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
31+
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
2432
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
33+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
2534
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

object/json.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package object
2+
3+
import (
4+
"encoding/json"
5+
)
6+
7+
type JSON struct{}
8+
9+
func (j *JSON) Type() ObjectType { return JSON_OBJ }
10+
func (j *JSON) Inspect() string { return "JSON" }
11+
func (j *JSON) InvokeMethod(method string, env Environment, args ...Object) Object {
12+
return objectMethodLookup(j, method, env, args)
13+
}
14+
15+
func init() {
16+
objectMethods[JSON_OBJ] = map[string]ObjectMethod{
17+
"parse": ObjectMethod{
18+
description: "Takes a STRING and parses it to a HASH or ARRAY. Numbers are always FLOAT.",
19+
example: `🚀 > JSON.parse('{"test": 123}')
20+
=> {"test": 123.0}
21+
🚀 > JSON.parse('["test", 123]')
22+
=> ["test", 123.0]`,
23+
returnPattern: [][]string{
24+
[]string{HASH_OBJ},
25+
},
26+
argPattern: [][]string{
27+
[]string{STRING_OBJ},
28+
},
29+
method: func(_ Object, args []Object, _ Environment) Object {
30+
var i interface{}
31+
input := args[0].(*String).Value
32+
33+
err := json.Unmarshal([]byte(input), &i)
34+
35+
if err != nil {
36+
return NewErrorFormat("Error while parsing json: %s", err)
37+
}
38+
39+
return interfaceToObject(i)
40+
},
41+
},
42+
}
43+
}
44+
45+
func interfaceToObject(i interface{}) Object {
46+
switch v := i.(type) {
47+
case map[string]interface{}:
48+
jsonObject := NewHash(nil)
49+
for key, val := range v {
50+
hp := HashPair{
51+
Key: NewString(key),
52+
Value: interfaceToObject(val),
53+
}
54+
55+
jsonObject.Pairs[hp.Key.(Hashable).HashKey()] = hp
56+
}
57+
58+
return jsonObject
59+
case []interface{}:
60+
jsonArray := NewArray(nil)
61+
for _, element := range v {
62+
jsonArray.Elements = append(jsonArray.Elements, interfaceToObject(element))
63+
}
64+
return jsonArray
65+
case string:
66+
return NewString(v)
67+
case float64:
68+
return NewFloat(v)
69+
case bool:
70+
if v {
71+
return TRUE
72+
}
73+
return FALSE
74+
}
75+
return NIL
76+
}

object/json_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package object_test
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestJSONObjectMethods(t *testing.T) {
8+
tests := []inputTestCase{
9+
{`JSON.nope()`, "undefined method `.nope()` for JSON"},
10+
{`JSON.parse("{a}")`, "Error while parsing json: invalid character 'a' looking for beginning of object key string"},
11+
{`JSON.parse("{}").type()`, "HASH"},
12+
{`JSON.parse("[]").type()`, "ARRAY"},
13+
{`a = open("../fixtures/data.json").content(); JSON.parse(a)["string"]`, "Kadeem Sawyer"},
14+
{`a = open("../fixtures/data.json").content(); JSON.parse(a)["bool"]`, true},
15+
{`a = open("../fixtures/data.json").content(); JSON.parse(a)["float"]`, 12.3},
16+
{`a = open("../fixtures/data.json").content(); JSON.parse(a)["array"][1]`, 1234.0},
17+
}
18+
19+
testInput(t, tests)
20+
}

object/object.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ const (
4848
FILE_OBJ = "FILE"
4949
MODULE_OBJ = "MODULE"
5050
HTTP_OBJ = "HTTP"
51+
JSON_OBJ = "JSON"
5152
)
5253

5354
type ObjectMethod struct {

stdlib/std.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ func init() {
1414
RegisterFunction("open", openFunction)
1515

1616
RegisterClass("HTTP", &object.HTTP{})
17+
RegisterClass("JSON", &object.JSON{})
1718
}
1819

1920
func RegisterFunction(name string, function object.BuiltinFunction) {

0 commit comments

Comments
 (0)