EvalQuery evaluates a query top-down, according to mode and union-find-subst. The mode must consist only of ArgModeInput (+) and ArgModeOutput (-). For every input, query.Args[i] is either a constant or a variable that is in the domain of subst.
(query ast.Atom, mode []ast.ArgMode, uf unionfind.UnionFind, cb func(fact ast.Atom) error)
| 38 | // For every input, query.Args[i] is either a constant or a variable that |
| 39 | // is in the domain of subst. |
| 40 | func (q QueryContext) EvalQuery(query ast.Atom, mode []ast.ArgMode, uf unionfind.UnionFind, cb func(fact ast.Atom) error) error { |
| 41 | for _, clause := range q.PredToRules[query.Predicate] { |
| 42 | var vars []ast.BaseTerm |
| 43 | var values []ast.BaseTerm |
| 44 | for j, arg := range clause.Head.Args { |
| 45 | v, ok := arg.(ast.Variable) |
| 46 | if ok && mode[j] == ast.ArgModeInput { |
| 47 | vars = append(vars, v) |
| 48 | values = append(values, query.Args[j]) |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | subst, err := unionfind.UnifyTermsExtend(vars, values, uf) |
| 53 | if err != nil { |
| 54 | continue |
| 55 | } |
| 56 | sols := []unionfind.UnionFind{subst} |
| 57 | for _, premise := range clause.Premises { |
| 58 | var nsolsWorkList []unionfind.UnionFind |
| 59 | for _, s := range sols { |
| 60 | nsols, err := q.EvalPremise(premise, s) |
| 61 | if err != nil { |
| 62 | return err |
| 63 | } |
| 64 | nsolsWorkList = append(nsolsWorkList, nsols...) |
| 65 | } |
| 66 | sols = nsolsWorkList |
| 67 | } |
| 68 | if sols != nil { |
| 69 | for _, s := range sols { |
| 70 | result := clause.Head.ApplySubst(s).(ast.Atom) |
| 71 | if err := cb(result); err != nil { |
| 72 | return err |
| 73 | } |
| 74 | } |
| 75 | } |
| 76 | } |
| 77 | return nil |
| 78 | } |
| 79 | |
| 80 | // EvalExternalQuery evaluates an external query. |
| 81 | // See ExternalPredicateCallback for more details. |