diff options
author | Peter Mikkelsen <peter@pmikkelsen.com> | 2021-06-30 17:03:25 +0000 |
---|---|---|
committer | Peter Mikkelsen <peter@pmikkelsen.com> | 2021-06-30 17:03:25 +0000 |
commit | 50f83a91220940042962fdb55d07bb03991f52be (patch) | |
tree | c2d1046393d7c3f75becd7b2150afab46156baf0 /eval.c | |
parent | 347e5bc533070a5e988d82e7588a4e905c7096f3 (diff) |
Add support for builtins, and implement true/0, fail/0, call/1, and !/0 builtins
Diffstat (limited to 'eval.c')
-rw-r--r-- | eval.c | 95 |
1 files changed, 46 insertions, 49 deletions
@@ -4,28 +4,13 @@ #include "dat.h" #include "fns.h" -typedef struct Goal Goal; -typedef struct Choicepoint Choicepoint; - -struct Goal -{ - Term *goal; - Goal *next; -}; - -struct Choicepoint -{ - Goal *goalstack; - Term *retryclause; - Choicepoint *next; -}; - Goal *addgoals(Goal *, Term *); Term *findclause(Term *, Term *, Binding **); int unify(Term *, Term *, Binding **); int equalterms(Term *, Term *); void applybinding(Term *, Binding *); Goal *copygoals(Goal *); +Builtin findbuiltin(Term *); static uvlong clausenr; @@ -63,43 +48,55 @@ evalquery(Term *database, Term *query, Binding **resultbindings) Retry: goal = goals->goal; - /* Find a clause where the head unifies with the goal */ Binding *bindings = nil; - Term *clause = findclause(dbstart, 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(goals); - cp->next = choicestack; - cp->retryclause = clause->next; - choicestack = cp; - } - goals = goals->next; + Term *clause = nil; - /* Apply bindings to all goals on the stack. */ - Goal *g; - 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){ - Term *subgoal = copyterm(clause->children->next, nil); - applybinding(subgoal, bindings); - goals = addgoals(goals, subgoal); - } + /* Try to see if the goal can be solved using a builtin first */ + Builtin builtin = findbuiltin(goal); + if(builtin != nil){ + int success = builtin(database, goal, &goals->next, &choicestack, &bindings); + if(!success) + goto Backtrack; }else{ - if(choicestack == nil) - return 0; - Choicepoint *cp = choicestack; - choicestack = cp->next; - /* freegoals(goals) */ - goals = cp->goalstack; - dbstart = cp->retryclause; + /* Find a clause where the head unifies with the goal */ + clause = findclause(dbstart, 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(goals); + cp->next = choicestack; + cp->retryclause = clause->next; + cp->id = clause->clausenr; + choicestack = cp; + } + }else{ +Backtrack: + if(choicestack == nil) + return 0; + Choicepoint *cp = choicestack; + choicestack = cp->next; + /* freegoals(goals) */ + goals = cp->goalstack; + dbstart = cp->retryclause; + goto Retry; + } + } + + goals = goals->next; + + /* Apply bindings to all goals on the stack. */ + Goal *g; + for(g = goals; g != nil; g = g->next){ + if(g->goal != nil) + applybinding(g->goal, bindings); + } - goto Retry; + /* Add clause body as goals, with bindings applied */ + if(clause != nil && clause->tag == CompoundTerm && clause->arity == 2 && runestrcmp(clause->text, L":-") == 0){ + Term *subgoal = copyterm(clause->children->next, nil); + applybinding(subgoal, bindings); + goals = addgoals(goals, subgoal); } } goals = goals->next; |