diff options
author | Peter Mikkelsen <peter@pmikkelsen.com> | 2021-06-30 14:04:15 +0000 |
---|---|---|
committer | Peter Mikkelsen <peter@pmikkelsen.com> | 2021-06-30 14:04:15 +0000 |
commit | ee4298a2cfbbd9e015cfc775d9d714a9f5035846 (patch) | |
tree | 8d6f4b139abf1a645e9e4fe0fba811f64b03839f /eval.c | |
parent | 79d1fe1cf2eb6748e2c12ffe9c36a678655302b1 (diff) |
Add a basic repl
Diffstat (limited to 'eval.c')
-rw-r--r-- | eval.c | 67 |
1 files changed, 33 insertions, 34 deletions
@@ -4,18 +4,9 @@ #include "dat.h" #include "fns.h" -typedef struct Binding Binding; typedef struct Goal Goal; typedef struct Choicepoint Choicepoint; -struct Binding -{ - Rune *name; - uvlong nr; /* Unique number for each clause. Every time a clause is used, it gets a new number. */ - Term *value; - Binding *next; -}; - struct Goal { Term *goal; @@ -38,15 +29,33 @@ Goal *copygoals(Goal *); static uvlong clausenr; -void -evalquery(Term *database, Term *query) +int +evalquery(Term *database, Term *query, Binding **resultbindings) { - Goal *goals = addgoals(nil, query); + Goal *goals; Choicepoint *choicestack = nil; clausenr = 0; - while(goals != nil){ + /* + The goal stack has the original query at the very bottom, protected by a goal there the ->goal field is nil. + This makes it so that we can continue until we hit the protective goal, at which point we have solved everything + and to get the result we can unify the original query with the one at the bottom of the stack, to get the bindings + applied. + */ + + goals = malloc(sizeof(Goal)); + goals->goal = copyterm(query, nil); + goals->next = nil; + Goal *protector = malloc(sizeof(Goal)); + protector->goal = nil; + protector->next = goals; + goals = protector; + + /* Now add the actual goals */ + goals = addgoals(goals, query); + + while(goals->goal != nil){ Term *dbstart; Term *goal; @@ -54,13 +63,6 @@ evalquery(Term *database, Term *query) Retry: goal = goals->goal; - if(goal == nil){ - goals = goals->next; - continue; - } - - print("Solving goal %S\n", prettyprint(goal)); - /* Find a clause where the head unifies with the goal */ Binding *bindings = nil; Term *clause = findclause(dbstart, goal, &bindings); @@ -74,28 +76,23 @@ Retry: choicestack = cp; } goals = goals->next; - /* Apply bindings to all goals on the top of the stack, down to the "bodystart" goal */ + + /* Apply bindings to all goals on the stack. */ Goal *g; - for(g = goals; g != nil && g->goal != nil; g = g->next) - applybinding(g->goal, bindings); + for(g = goals; g != nil; g = g->next){ + if(g->goal != nil) + applybinding(g->goal, bindings); + } /* Add clause body as goals, with bindings applied */ if(clause->tag == CompoundTerm && clause->arity == 2 && runestrcmp(clause->text, L":-") == 0){ - Goal *bodystart = malloc(sizeof(Goal)); - bodystart->goal = nil; - bodystart->next = goals; - goals = bodystart; - Term *subgoal = copyterm(clause->children->next, nil); applybinding(subgoal, bindings); goals = addgoals(goals, subgoal); } }else{ - if(choicestack == nil){ - print("Fail\n"); - return; - } - print("Backtracking...\n"); + if(choicestack == nil) + return 0; Choicepoint *cp = choicestack; choicestack = cp->next; /* freegoals(goals) */ @@ -105,7 +102,9 @@ Retry: goto Retry; } } - print("Success.\n"); + goals = goals->next; + unify(query, goals->goal, resultbindings); + return 1; } Goal * |