Skip to content

Commit

Permalink
refactor(logic)!: remove @([]) empty list encoding in json_prolog/2
Browse files Browse the repository at this point in the history
Empty arrays in Prolog are now consistently encoded using the
empty-list atom [].
  • Loading branch information
ccamel committed Oct 12, 2024
1 parent 16f02d6 commit c3e5781
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 46 deletions.
39 changes: 16 additions & 23 deletions x/logic/predicate/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,32 +89,31 @@ func JSONProlog(_ *engine.VM, j, p engine.Term, cont engine.Cont, env *engine.En
}

func encodeTermToJSON(term engine.Term, buf *bytes.Buffer, env *engine.Env) (err error) {
switch t := term.(type) {
case engine.Atom:
bs, err := json.Marshal(t.String())
marshalToBuffer := func(data any) error {
bs, err := json.Marshal(data)
if err != nil {
return prologErrorToException(t, err, env)
return prologErrorToException(term, err, env)
}

buf.Write(bs)
case engine.Integer:
bs, err := json.Marshal(t)
if err != nil {
return prologErrorToException(t, err, env)
}

buf.Write(bs)
return nil
}

switch t := term.(type) {
case engine.Atom:
if term == prolog.AtomEmptyList {
buf.Write([]byte("[]"))
} else {
return marshalToBuffer(t.String())
}
case engine.Integer:
return marshalToBuffer(t)
case engine.Float:
float, err := strconv.ParseFloat(t.String(), 64)
if err != nil {
return prologErrorToException(t, err, env)
}
bs, err := json.Marshal(float)
if err != nil {
return prologErrorToException(t, err, env)
}

buf.Write(bs)
return marshalToBuffer(float)
case engine.Compound:
return encodeCompoundToJSON(t, buf, env)
default:
Expand All @@ -134,8 +133,6 @@ func encodeCompoundToJSON(term engine.Compound, buf *bytes.Buffer, env *engine.E
buf.Write([]byte("true"))
case prolog.JSONBool(false).Compare(term, env) == 0:
buf.Write([]byte("false"))
case prolog.JSONEmptyArray().Compare(term, env) == 0:
buf.Write([]byte("[]"))
case prolog.JSONNull().Compare(term, env) == 0:
buf.Write([]byte("null"))
default:
Expand Down Expand Up @@ -291,10 +288,6 @@ func decodeJSONArrayToTerm(decoder *json.Decoder, env *engine.Env) (engine.Term,
terms = append(terms, value)
}

if len(terms) == 0 {
return prolog.JSONEmptyArray(), nil
}

return engine.List(terms...), nil
}

Expand Down
14 changes: 3 additions & 11 deletions x/logic/predicate/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func TestJsonProlog(t *testing.T) {
description: "convert empty json array into prolog",
query: `json_prolog('[]', Term).`,
wantResult: []testutil.TermResults{{
"Term": "@([])",
"Term": "[]",
}},
wantSuccess: true,
},
Expand Down Expand Up @@ -271,14 +271,6 @@ func TestJsonProlog(t *testing.T) {
}},
wantSuccess: true,
},
{
description: "convert empty-list atom term to json",
query: `json_prolog(Json, []).`,
wantResult: []testutil.TermResults{{
"Json": "'\"[]\"'",
}},
wantSuccess: true,
},
// ** Prolog -> JSON **
// Object
{
Expand Down Expand Up @@ -411,7 +403,7 @@ func TestJsonProlog(t *testing.T) {
// Array
{
description: "convert empty json array from prolog",
query: `json_prolog(Json, @([])).`,
query: `json_prolog(Json, []).`,
wantResult: []testutil.TermResults{{
"Json": "[]",
}},
Expand Down Expand Up @@ -585,7 +577,7 @@ func TestJsonPrologWithMoreComplexStructBidirectional(t *testing.T) {
},
{
json: `'{"key1":null,"key2":[],"key3":{"nestedKey1":null,"nestedKey2":[],"nestedKey3":["a",null,null]}}'`,
term: `json([key1- @(null),key2- @([]),key3-json([nestedKey1- @(null),nestedKey2- @([]),nestedKey3-[a,@(null),@(null)]])])`,
term: `json([key1- @(null),key2-[],key3-json([nestedKey1- @(null),nestedKey2-[],nestedKey3-[a,@(null),@(null)]])])`,
wantSuccess: true,
},
}
Expand Down
2 changes: 0 additions & 2 deletions x/logic/prolog/atom.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ var (
AtomDot = engine.NewAtom(".")
// AtomEmpty is the term used to represent empty.
AtomEmpty = engine.NewAtom("")
// AtomEmptyArray is the term [].
AtomEmptyArray = engine.NewAtom("[]")
// AtomEmptyList is the term used to represent an empty list.
AtomEmptyList = engine.NewAtom("[]")
// AtomEncoding is the term used to indicate the encoding type option.
Expand Down
13 changes: 3 additions & 10 deletions x/logic/prolog/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import (
)

var (
nullTerm = AtomAt.Apply(AtomNull)
emptyArrayTerm = AtomAt.Apply(AtomEmptyArray)
trueTerm = AtomAt.Apply(AtomTrue)
falseTerm = AtomAt.Apply(AtomFalse)
nullTerm = AtomAt.Apply(AtomNull)
trueTerm = AtomAt.Apply(AtomTrue)
falseTerm = AtomAt.Apply(AtomFalse)
)

// JSONNull returns the compound term @(null).
Expand All @@ -26,12 +25,6 @@ func JSONBool(b bool) engine.Term {
return falseTerm
}

// JSONEmptyArray returns is the compound term @([]).
// It is used to represent the empty array in json objects.
func JSONEmptyArray() engine.Term {
return emptyArrayTerm
}

// AssertJSON resolves a term as a JSON object and returns it as engine.Compound.
// If conversion fails, the function returns nil and the error.
func AssertJSON(term engine.Term, env *engine.Env) (engine.Compound, error) {
Expand Down

0 comments on commit c3e5781

Please sign in to comment.