From 9250bda2ddca9119c9cb18014f3e2008f30c4e0c Mon Sep 17 00:00:00 2001 From: ccamel Date: Wed, 20 Mar 2024 16:49:25 +0100 Subject: [PATCH 1/2] fix(logic): prevent non-bound substitution variables to be returned --- x/logic/util/prolog.go | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/x/logic/util/prolog.go b/x/logic/util/prolog.go index 82dafcd2..aac9bcce 100644 --- a/x/logic/util/prolog.go +++ b/x/logic/util/prolog.go @@ -73,14 +73,14 @@ func envsToResults(envs []*engine.Env, vars []engine.ParsedVariable, i *prolog.I for _, rEnv := range envs { substitutions := make([]types.Substitution, 0, len(vars)) for _, v := range vars { - var expression prolog.TermString - err := expression.Scan(&i.VM, v.Variable, rEnv) - if err != nil { - return nil, err + if !isBound(v, rEnv) { + // skip parsed variables that are not bound (singletons variables or other) + continue } - substitution := types.Substitution{ - Variable: v.Name.String(), - Expression: string(expression), + + substitution, err := scanExpression(i, v, rEnv) + if err != nil { + return results, err } substitutions = append(substitutions, substitution) } @@ -88,3 +88,24 @@ func envsToResults(envs []*engine.Env, vars []engine.ParsedVariable, i *prolog.I } return results, nil } + +func scanExpression(i *prolog.Interpreter, v engine.ParsedVariable, rEnv *engine.Env) (types.Substitution, error) { + var expression prolog.TermString + err := expression.Scan(&i.VM, v.Variable, rEnv) + if err != nil { + return types.Substitution{}, err + } + substitution := types.Substitution{ + Variable: v.Name.String(), + Expression: string(expression), + } + + return substitution, nil +} + +// isBound returns true if the given parsed variable is bound in the given environment. +func isBound(v engine.ParsedVariable, env *engine.Env) bool { + _, ok := env.Resolve(v.Variable).(engine.Variable) + + return !ok +} From f327463f8320493c314c5ce37af49812aedb9750 Mon Sep 17 00:00:00 2001 From: ccamel Date: Wed, 20 Mar 2024 16:50:01 +0100 Subject: [PATCH 2/2] test(logic): add test case for non-bound substitution variables --- x/logic/keeper/grpc_query_ask_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/x/logic/keeper/grpc_query_ask_test.go b/x/logic/keeper/grpc_query_ask_test.go index ba353780..7a04b6e1 100644 --- a/x/logic/keeper/grpc_query_ask_test.go +++ b/x/logic/keeper/grpc_query_ask_test.go @@ -192,6 +192,16 @@ func TestGRPCAsk(t *testing.T) { }}}}, }, }, + { + program: "father(bob, X) :- true.", + query: "father(B, X).", + expectedAnswer: &types.Answer{ + Variables: []string{"B", "X"}, + Results: []types.Result{{Substitutions: []types.Substitution{{ + Variable: "B", Expression: "bob", + }}}}, + }, + }, { program: "father(bob, alice).", query: "father(bob, X, O).",