Skip to content

Commit

Permalink
add json.encode method
Browse files Browse the repository at this point in the history
  • Loading branch information
kaidesu committed Oct 27, 2023
1 parent 9da4d4d commit 74b0cec
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 17 deletions.
17 changes: 1 addition & 16 deletions examples/hello.ghost
Original file line number Diff line number Diff line change
@@ -1,16 +1 @@
test = '{ "name": "Kai", "age": 34, "is_admin": true, "hobbies": ["programming", "gaming", "reading"], "address": { "street": "1234 Main St", "city": "Anytown", "state": "CA", "zip": 12345 } }'

foo = json.parse(test)

console.log(foo.name)
console.log(foo.age)
console.log(foo.is_admin)
console.log(foo.hobbies)
console.log(foo.address)
console.log(foo.address.street)
console.log(foo.address.city)
console.log(foo.address.state)
console.log(foo.address.zip)
console.log(foo.hobbies[0])
console.log(foo.hobbies[1])
console.log(foo.hobbies[2])
print("hello world!")
51 changes: 50 additions & 1 deletion library/modules/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package modules

import (
"encoding/json"
"fmt"

"ghostlang.org/x/ghost/object"
"ghostlang.org/x/ghost/token"
Expand All @@ -12,7 +13,7 @@ var JsonProperties = map[string]*object.LibraryProperty{}

func init() {
RegisterMethod(JsonMethods, "decode", jsonDecode)
// RegisterMethod(JsonMethods, "encode", jsonEncode)
RegisterMethod(JsonMethods, "encode", jsonEncode)
}

// jsonDecode decodes the JSON-encoded data and returns a new list or map object.
Expand Down Expand Up @@ -59,3 +60,51 @@ func jsonDecode(scope *object.Scope, tok token.Token, args ...object.Object) obj

return object.NewError("failed to decode JSON: %s", err.Error())
}

// jsonEncode returns the JSON encoding of either a list or map object.
func jsonEncode(scope *object.Scope, tok token.Token, args ...object.Object) object.Object {
if len(args) != 1 {
return object.NewError("wrong number of arguments. got=%d, want=1", len(args))
}

switch arg := args[0].(type) {
case *object.List:
var elements []interface{}

for _, val := range arg.Elements {
elements = append(elements, object.ObjectToAnyValue(val))
}

data, err := json.Marshal(elements)

if err != nil {
return object.NewError("failed to encode JSON: %s", err.Error())
}

return &object.String{Value: string(data)}
case *object.Map:
pairs := make(map[string]interface{})

for _, pair := range arg.Pairs {
// map keys can be numbers, strings, or booleans
switch pair.Key.(type) {
case *object.String:
pairs[pair.Key.(*object.String).Value] = object.ObjectToAnyValue(pair.Value)
case *object.Number:
pairs[fmt.Sprintf("%d", object.ObjectToAnyValue(pair.Key.(*object.Number)))] = object.ObjectToAnyValue(pair.Value)
case *object.Boolean:
pairs[fmt.Sprintf("%t", pair.Key.(*object.Boolean).Value)] = object.ObjectToAnyValue(pair.Value)
}
}

data, err := json.Marshal(pairs)

if err != nil {
return object.NewError("failed to encode JSON: %s", err.Error())
}

return &object.String{Value: string(data)}
}

return object.NewError("argument to `encode` must be LIST or MAP, got %s", args[0].Type())
}
38 changes: 38 additions & 0 deletions object/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,41 @@ func AnyValueToObject(val any) Object {

return nil
}

func ObjectToAnyValue(val Object) any {
switch v := val.(type) {
case *Boolean:
return bool(v.Value)
case *String:
return string(v.Value)
case *Number:
// Determine if value is an integer or float.
if v.Value.Exponent() <= 0 {
return int(v.Value.IntPart())
}

num, _ := v.Value.Float64()

return num
case *Null:
return nil
case *List:
var collection []any

for _, val := range v.Elements {
collection = append(collection, ObjectToAnyValue(val))
}

return collection
case *Map:
collection := make(map[string]any)

for _, pair := range v.Pairs {
collection[pair.Key.(*String).Value] = ObjectToAnyValue(pair.Value)
}

return collection
}

return nil
}

0 comments on commit 74b0cec

Please sign in to comment.