diff options
Diffstat (limited to 'eval.c')
-rw-r--r-- | eval.c | 106 |
1 files changed, 75 insertions, 31 deletions
@@ -6,10 +6,12 @@ #include "fns.h" Goal *addgoals(Goal *, Term *); +Predicate *findpredicate(Predicate *, Term *); Clause *findclause(Clause *, Term *, Binding **); int equalterms(Term *, Term *); Goal *copygoals(Goal *); Builtin findbuiltin(Term *); +void addchoicepoints(Clause *, Term *, Goal *, Module *); static uvlong clausenr; @@ -45,23 +47,17 @@ evalquery(Term *query, Binding **resultbindings) } while(goalstack->goal != nil){ - Clause *startclause; - Term *goal; - Goal *oldgoalstack; - - startclause = nil; /* Where to start looking for a matching clause. Used by backtracking */ -Retry: - goal = goalstack->goal; - oldgoalstack = goalstack; + Term *goal = goalstack->goal; + Term *catcher = goalstack->catcher; goalstack = goalstack->next; - if(oldgoalstack->catcher) + if(catcher) continue; if(debug) print("Working goal: %S\n", prettyprint(goal, 0, 0, 0)); - if(startclause == nil && goal->tag == CompoundTerm && goal->arity == 2 && runestrcmp(goal->text, L":") == 0){ + if(goal->tag == CompoundTerm && goal->arity == 2 && runestrcmp(goal->text, L":") == 0){ Term *module = goal->children; if(module->tag == AtomTerm){ Module *m = getmodule(module->text); @@ -70,16 +66,11 @@ Retry: else{ goal = module->next; currentmodule = m; - startclause = m->clauses; - oldgoalstack->goal = goal; } }else goal = typeerror(L"module", module); } - if(startclause == nil) - startclause = currentmodule->clauses; - Binding *bindings = nil; Clause *clause = nil; @@ -90,20 +81,17 @@ Retry: if(!success) goto Backtrack; }else{ + Predicate *pred = findpredicate(currentmodule->predicates, goal); + if(pred == nil){ + print("No predicate matches: %S\n", prettyprint(goal, 0, 0, 0)); + goto Backtrack; + } + /* Find a clause where the head unifies with the goal */ - clause = findclause(startclause, goal, &bindings); - if(clause != nil){ - if(clause->next != nil){ - /* Add a choicepoint. Note we create a choicepoint every time, so there is room for improvement. */ - Choicepoint *cp = malloc(sizeof(Choicepoint)); - cp->goalstack = copygoals(oldgoalstack); - cp->next = choicestack; - cp->retryclause = clause->next; - cp->id = clause->clausenr; - cp->currentmodule = currentmodule; - choicestack = cp; - } - }else{ + clause = findclause(pred->clauses, goal, &bindings); + if(clause != nil) + addchoicepoints(clause, goal, goalstack, currentmodule); + else{ Backtrack: if(choicestack == nil) return 0; @@ -111,11 +99,10 @@ Backtrack: print("Backtracking..\n"); Choicepoint *cp = choicestack; choicestack = cp->next; - /* freegoals(goals) */ goalstack = cp->goalstack; currentmodule = cp->currentmodule; - startclause = cp->retryclause; - goto Retry; + clause = cp->alternative; + bindings = cp->altbindings; } } @@ -171,6 +158,26 @@ findclause(Clause *clauses, Term *goal, Binding **bindings) return nil; } +Predicate * +findpredicate(Predicate *preds, Term *goal) +{ + Rune *name; + int arity; + + name = goal->text; + if(goal->tag == AtomTerm) + arity = 0; + else + arity = goal->arity; + + Predicate *p; + for(p = preds; p != nil; p = p->next){ + if(runestrcmp(p->name, name) == 0 && p->arity == arity) + return p; + } + return nil; +} + int unify(Term *a, Term *b, Binding **bindings) { @@ -293,3 +300,40 @@ copygoals(Goal *goals) }else return nil; } + +void +addchoicepoints(Clause *clause, Term *goal, Goal *goals, Module *mod){ + /* Find all alternative clauses that would have matched, and create a choicepoint for them */ + Choicepoint *cps = nil; + Choicepoint *last = nil; + + Clause *alt = clause->next; + while(alt != nil){ + Binding *altbindings = nil; + clause = findclause(alt, goal, &altbindings); + if(clause){ + /* Add choicepoint here */ + Choicepoint *cp = malloc(sizeof(Choicepoint)); + cp->goalstack = copygoals(goals); + cp->next = nil; + cp->alternative = clause; + cp->altbindings = altbindings; + cp->id = clause->clausenr; + cp->currentmodule = mod; + if(cps == nil){ + cps = cp; + last = cp; + }else{ + last->next = cp; + last = cp; + } + alt = clause->next; + }else + alt = nil; + } + + if(last){ + last->next = choicestack; + choicestack = cps; + } +}
\ No newline at end of file |