Skip to content

Commit

Permalink
refactor(logic)!: standardize error messages for some predicates
Browse files Browse the repository at this point in the history
  • Loading branch information
ccamel committed Jan 7, 2024
1 parent 5df389e commit 864b059
Show file tree
Hide file tree
Showing 23 changed files with 313 additions and 178 deletions.
7 changes: 4 additions & 3 deletions x/logic/predicate/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import (
"fmt"

"github.com/ichiban/prolog/engine"
"github.com/okp4/okp4d/x/logic/prolog"

bech322 "github.com/cosmos/cosmos-sdk/types/bech32"

"github.com/okp4/okp4d/x/logic/prolog"
)

// Bech32Address is a predicate that convert a [bech32] encoded string into [base64] bytes and give the address prefix,
Expand Down Expand Up @@ -44,7 +45,7 @@ func Bech32Address(vm *engine.VM, address, bech32 engine.Term, cont engine.Cont,
if err != nil {
return engine.Error(fmt.Errorf("bech32_address/2: failed to decode Bech32: %w", err))
}
pair := prolog.AtomPair.Apply(prolog.StringToTerm(h), prolog.BytesToCodepointListTermWithDefault(a))
pair := prolog.AtomPair.Apply(prolog.StringToTerm(h), prolog.BytesToCodepointListTermWithDefault(a, env))
return engine.Unify(vm, address, pair, cont, env)
default:
return engine.Error(fmt.Errorf("bech32_address/2: invalid Bech32 type: %T, should be Atom or Variable", b))
Expand All @@ -70,7 +71,7 @@ func addressPairToBech32(addressPair engine.Compound, env *engine.Env) (string,

switch a := env.Resolve(addressPair.Arg(1)).(type) {
case engine.Compound:
data, err := prolog.StringTermToBytes(a, "", env)
data, err := prolog.StringTermToBytes(a, prolog.AtomEmpty, env)
if err != nil {
return "", fmt.Errorf("failed to convert term to bytes list: %w", err)
}
Expand Down
4 changes: 2 additions & 2 deletions x/logic/predicate/address_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func TestBech32(t *testing.T) {
},
{
query: `bech32_address(-('okp4', ['8956',167,23,244,162,175,49,162,170,15,181,141,68,134,141,168,18,56,247,30]), Bech32).`,
wantError: fmt.Errorf("bech32_address/2: failed to convert term to bytes list: invalid character_code '8956' value in list at position 1: should be a single character"),
wantError: fmt.Errorf("bech32_address/2: failed to convert term to bytes list: error(domain_error(valid_character_code(8956),[8956,167,23,244,162,175,49,162,170,15,181,141,68,134,141,168,18,56,247,30]),bech32_address/2)"),
wantSuccess: false,
},
{
Expand All @@ -99,7 +99,7 @@ func TestBech32(t *testing.T) {
},
{
query: `bech32_address(-('okp4', hey(2)), Bech32).`,
wantError: fmt.Errorf("bech32_address/2: failed to convert term to bytes list: invalid compound term: expected a list of character_code or integer"),
wantError: fmt.Errorf("bech32_address/2: failed to convert term to bytes list: error(type_error(character_code,hey(2)),bech32_address/2)"),
wantSuccess: false,
},
{
Expand Down
2 changes: 1 addition & 1 deletion x/logic/predicate/bank.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import (
"fmt"

"github.com/ichiban/prolog/engine"
"github.com/okp4/okp4d/x/logic/prolog"

sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/okp4/okp4d/x/logic/prolog"
"github.com/okp4/okp4d/x/logic/types"
"github.com/okp4/okp4d/x/logic/util"
)
Expand Down
6 changes: 3 additions & 3 deletions x/logic/predicate/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
"strings"

"github.com/ichiban/prolog/engine"
"github.com/okp4/okp4d/x/logic/prolog"

"github.com/okp4/okp4d/x/logic/prolog"
"github.com/okp4/okp4d/x/logic/util"
)

Expand Down Expand Up @@ -79,7 +79,7 @@ func CryptoDataHash(
return engine.Error(fmt.Errorf("%s: failed to hash data: %w", functor, err))
}

return engine.Unify(vm, hash, prolog.BytesToCodepointListTermWithDefault(result), cont, env)
return engine.Unify(vm, hash, prolog.BytesToCodepointListTermWithDefault(result, env), cont, env)
})
}

Expand Down Expand Up @@ -226,7 +226,7 @@ func termToBytes(term, options, defaultEncoding engine.Term, env *engine.Env) ([
case prolog.AtomHex:
return prolog.TermHexToBytes(term, env)
case prolog.AtomOctet, prolog.AtomUtf8:
return prolog.StringTermToBytes(term, "", env)
return prolog.StringTermToBytes(term, prolog.AtomEmpty, env)
default:
return nil, fmt.Errorf("invalid encoding: %s. Possible values: hex, octet", encodingAtom.String())
}
Expand Down
1 change: 1 addition & 0 deletions x/logic/predicate/did.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/ichiban/prolog/engine"
godid "github.com/nuts-foundation/go-did/did"

"github.com/okp4/okp4d/x/logic/prolog"
)

Expand Down
2 changes: 1 addition & 1 deletion x/logic/predicate/did_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func TestDID(t *testing.T) {
query: `did_components(X,did(example,'123456','path with/space',5,test)).`,
wantResult: []types.TermResults{},
wantError: fmt.Errorf(
"did_components/2: failed to resolve atom at segment 3: invalid term '%%!s(engine.Integer=5)' - expected engine.Atom but got engine.Integer"), //nolint:lll
"did_components/2: failed to resolve atom at segment 3: error(type_error(atom,5),did_components/2)"),
},
{
query: `did_components('did:example:123456',foo(X)).`,
Expand Down
5 changes: 3 additions & 2 deletions x/logic/predicate/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"

"github.com/ichiban/prolog/engine"

"github.com/okp4/okp4d/x/logic/prolog"
)

Expand Down Expand Up @@ -45,9 +46,9 @@ func HexBytes(vm *engine.VM, hexa, bts engine.Term, cont engine.Cont, env *engin
if result == nil {
return engine.Error(fmt.Errorf("hex_bytes/2: nil hexadecimal conversion in input"))
}
return engine.Unify(vm, bts, prolog.BytesToCodepointListTermWithDefault(result), cont, env)
return engine.Unify(vm, bts, prolog.BytesToCodepointListTermWithDefault(result, env), cont, env)
case engine.Compound:
src, err := prolog.StringTermToBytes(b, "", env)
src, err := prolog.StringTermToBytes(b, prolog.AtomEmpty, env)
if err != nil {
return engine.Error(fmt.Errorf("hex_bytes/2: %w", err))
}
Expand Down
2 changes: 1 addition & 1 deletion x/logic/predicate/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func TestHexBytesPredicate(t *testing.T) {
query: `hex_bytes('2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae',
[345,38,'hey',107,104,255,198,143,249,155,69,60,29,48,65,52,19,66,45,112,100,131,191,160,249,138,94,136,98,102,231,174]).`,
wantSuccess: false,
wantError: fmt.Errorf("hex_bytes/2: invalid integer value '345' in list at position 1: out of byte range (0-255)"),
wantError: fmt.Errorf("hex_bytes/2: error(domain_error(valid_byte(345),[345,38,hey,107,104,255,198,143,249,155,69,60,29,48,65,52,19,66,45,112,100,131,191,160,249,138,94,136,98,102,231,174]),hex_bytes/2)"), //nolint:lll
},
}
for nc, tc := range cases {
Expand Down
17 changes: 9 additions & 8 deletions x/logic/predicate/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import (
"strings"

"github.com/ichiban/prolog/engine"
"github.com/okp4/okp4d/x/logic/prolog"
"github.com/samber/lo"

"cosmossdk.io/math"

sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/okp4/okp4d/x/logic/prolog"
)

// JSONProlog is a predicate that will unify a JSON string into prolog terms and vice versa.
Expand Down Expand Up @@ -123,13 +124,13 @@ func termsToJSON(term engine.Term, env *engine.Env) ([]byte, error) {
}

switch {
case prolog.JsonBool(true).Compare(t, env) == 0:
case prolog.JSONBool(true).Compare(t, env) == 0:
return json.Marshal(true)
case prolog.JsonBool(false).Compare(t, env) == 0:
case prolog.JSONBool(false).Compare(t, env) == 0:
return json.Marshal(false)
case prolog.JsonEmptyArray().Compare(t, env) == 0:
case prolog.JSONEmptyArray().Compare(t, env) == 0:
return json.Marshal([]json.RawMessage{})
case prolog.JsonNull().Compare(t, env) == 0:
case prolog.JSONNull().Compare(t, env) == 0:
return json.Marshal(nil)
}

Expand All @@ -153,9 +154,9 @@ func jsonToTerms(value any) (engine.Term, error) {
}
return engine.Integer(r.Int64()), nil
case bool:
return prolog.JsonBool(v), nil
return prolog.JSONBool(v), nil
case nil:
return prolog.JsonNull(), nil
return prolog.JSONNull(), nil
case map[string]any:
keys := lo.Keys(v)
sort.Strings(keys)
Expand All @@ -172,7 +173,7 @@ func jsonToTerms(value any) (engine.Term, error) {
case []any:
elements := make([]engine.Term, 0, len(v))
if len(v) == 0 {
return prolog.JsonEmptyArray(), nil
return prolog.JSONEmptyArray(), nil
}

for _, element := range v {
Expand Down
9 changes: 5 additions & 4 deletions x/logic/predicate/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"

"github.com/ichiban/prolog/engine"

"github.com/okp4/okp4d/x/logic/prolog"
)

Expand Down Expand Up @@ -114,11 +115,11 @@ func StringBytes(
return engine.Error(err)
}
forwardConverter := func(value []engine.Term, options engine.Term, env *engine.Env) ([]engine.Term, error) {
bs, err := prolog.StringTermToBytes(value[0], encodingAtom.String(), env)
bs, err := prolog.StringTermToBytes(value[0], encodingAtom, env)
if err != nil {
return nil, err
}
result, err := prolog.BytesToCodepointListTerm(bs, "text")
result, err := prolog.BytesToCodepointListTerm(bs, prolog.AtomText, env)
if err != nil {
return nil, err
}
Expand All @@ -128,11 +129,11 @@ func StringBytes(
if _, err := prolog.AssertList(env, value[0]); err != nil {
return nil, err
}
bs, err := prolog.StringTermToBytes(value[0], "text", env)
bs, err := prolog.StringTermToBytes(value[0], prolog.AtomText, env)
if err != nil {
return nil, err
}
result, err := prolog.BytesToAtomListTerm(bs, encodingAtom.String())
result, err := prolog.BytesToAtomListTerm(bs, encodingAtom, env)
if err != nil {
return nil, err
}
Expand Down
1 change: 1 addition & 0 deletions x/logic/predicate/uri.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net/url"

"github.com/ichiban/prolog/engine"

"github.com/okp4/okp4d/x/logic/prolog"
)

Expand Down
5 changes: 3 additions & 2 deletions x/logic/predicate/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package predicate
import (
"sort"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ichiban/prolog/engine"
"github.com/okp4/okp4d/x/logic/prolog"

sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/okp4/okp4d/x/logic/prolog"
"github.com/okp4/okp4d/x/logic/types"
)

Expand Down
18 changes: 18 additions & 0 deletions x/logic/prolog/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,24 @@ func AssertAtom(env *engine.Env, t engine.Term) (engine.Atom, error) {
return AtomEmpty, engine.TypeError(AtomAtom, t, env)
}

// AssertCharacterCode resolves a term and attempts to convert it into an engine.Integer if possible.
// If conversion fails, the function returns the zero value and the error.
func AssertCharacterCode(env *engine.Env, t engine.Term) (engine.Integer, error) {
if t, ok := env.Resolve(t).(engine.Integer); ok {
return t, nil
}
return 0, engine.TypeError(AtomCharacterCode, t, env)
}

// AssertCharacter resolves a term and attempts to convert it into an engine.Atom if possible.
// If conversion fails, the function returns the empty atom and the error.
func AssertCharacter(env *engine.Env, t engine.Term) (engine.Atom, error) {
if t, ok := env.Resolve(t).(engine.Atom); ok {
return t, nil
}
return AtomEmpty, engine.TypeError(AtomCharacter, t, env)
}

// AssertList resolves a term as a list and returns it as a engine.Compound.
// If conversion fails, the function returns nil and the error.
func AssertList(env *engine.Env, t engine.Term) (engine.Compound, error) {
Expand Down
3 changes: 2 additions & 1 deletion x/logic/prolog/assert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import (
"fmt"
"testing"

"github.com/okp4/okp4d/x/logic/util"
"github.com/samber/lo"

. "github.com/smartystreets/goconvey/convey"

"github.com/okp4/okp4d/x/logic/util"
)

var (
Expand Down
71 changes: 49 additions & 22 deletions x/logic/prolog/atom.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,54 @@ package prolog

import "github.com/ichiban/prolog/engine"

// Common atoms.
var (
AtomAs = engine.NewAtom("as") // AtomAs is the term used to indicate the as encoding type option.
AtomAt = engine.NewAtom("@") // AtomAt are terms with principal functor (@)/1. It is used to represent special values in json objects.
AtomAtom = engine.NewAtom("atom") // AtomAtom is the term used to indicate the atom atom,
AtomCharset = engine.NewAtom("charset") // AtomCharset is the term used to indicate the charset encoding type option.
AtomCompound = engine.NewAtom("compound") // AtomCompound is the term used to indicate the atom compound,
AtomDot = engine.NewAtom(".") // AtomDot is the term used to represent the dot in a list.
AtomEmpty = engine.NewAtom("") // AtomEmpty is the term used to represent empty.
AtomEmptyArray = engine.NewAtom("[]") // AtomEmptyArray is the term [].
AtomEmptyList = engine.NewAtom("[]") // AtomEmptyList is the term used to represent an empty list.
AtomEncoding = engine.NewAtom("encoding") // AtomEncoding is the term used to indicate the encoding type option.
AtomError = engine.NewAtom("error") // AtomError is the term used to indicate the error.
AtomFalse = engine.NewAtom("false") // AtomFalse is the term false.
AtomHex = engine.NewAtom("hex") // AtomHex is the term used to indicate the hexadecimal encoding type option.
AtomJSON = engine.NewAtom("json") // AtomJSON are terms with principal functor json/1. // It is used to represent json objects.
AtomList = engine.NewAtom("list") // AtomList is the term used to indicate the atom list,
AtomNull = engine.NewAtom("null") // AtomNull is the term null.
AtomOctet = engine.NewAtom("octet") // AtomOctet is the term used to indicate the byte encoding type option.
AtomPadding = engine.NewAtom("padding") // AtomPadding is the term used to indicate the padding encoding type option.
AtomPair = engine.NewAtom("-") // AtomPair are terms with principal functor (-)/2. For example, the term -(A, B) denotes the pair of elements A and B.
AtomTrue = engine.NewAtom("true") // AtomTrue is the term true.
AtomUtf8 = engine.NewAtom("utf8") // AtomUtf8 is the term used to indicate the UTF-8 encoding type option.
// AtomAs is the term used to indicate the as encoding type option.
AtomAs = engine.NewAtom("as")
// AtomAt are terms with principal functor (@)/1 used to represent special values in json objects.
AtomAt = engine.NewAtom("@")
// AtomAtom is the term used to indicate the atom atom.
AtomAtom = engine.NewAtom("atom")
// AtomCharacter is the term used to indicate the character type.
AtomCharacter = engine.NewAtom("character")
// AtomCharacterCode is the term used to indicate the character code type.
AtomCharacterCode = engine.NewAtom("character_code")
// AtomCharset is the term used to indicate the charset encoding type option.
AtomCharset = engine.NewAtom("charset")
// AtomCompound is the term used to indicate the atom compound.
AtomCompound = engine.NewAtom("compound")
// AtomDot is the term used to represent the dot in a list.
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.
AtomEncoding = engine.NewAtom("encoding")
// AtomError is the term used to indicate the error.
AtomError = engine.NewAtom("error")
// AtomFalse is the term false.
AtomFalse = engine.NewAtom("false")
// AtomHex is the term used to indicate the hexadecimal encoding type option.
AtomHex = engine.NewAtom("hex")
// AtomJSON are terms with principal functor json/1 used to represent json objects.
AtomJSON = engine.NewAtom("json")
// AtomList is the term used to indicate the atom list.
AtomList = engine.NewAtom("list")
// AtomNull is the term null.
AtomNull = engine.NewAtom("null")
// AtomOctet is the term used to indicate the byte encoding type option.
AtomOctet = engine.NewAtom("octet")
// AtomPadding is the term used to indicate the padding encoding type option.
AtomPadding = engine.NewAtom("padding")
// AtomPair are terms with principal functor (-)/2.
// For example, the term -(A, B) denotes the pair of elements A and B.
AtomPair = engine.NewAtom("-")
// AtomText is the term used to indicate the atom text.
AtomText = engine.NewAtom("text")
// AtomTrue is the term true.
AtomTrue = engine.NewAtom("true")
// AtomUtf8 is the term used to indicate the UTF-8 encoding type option.
AtomUtf8 = engine.NewAtom("utf8")
)
Loading

0 comments on commit 864b059

Please sign in to comment.