shithub: pprolog

Download patch

ref: 85adea62d7e8eee9d0e3525d572325db4e58d21a
parent: fa83d3f1aba932e99833244ebb38b7415b142bd7
author: Peter Mikkelsen <peter@pmikkelsen.com>
date: Wed Jun 30 19:30:13 EDT 2021

Allow the repl to backtrack to give alternative results

--- a/TODO
+++ b/TODO
@@ -1,4 +1,3 @@
-* Add a repl
 * Stop comparing strings all the time
 * Stop copying the entire goal stack into every choicepoint
 * Stop creating choicepoints when it is not needed
--- a/eval.c
+++ b/eval.c
@@ -14,13 +14,12 @@
 static uvlong clausenr;
 
 int
-evalquery(Term *database, Term *query, Binding **resultbindings)
+evalquery(Term *database, Term *query, Binding **resultbindings, Choicepoint **resultchoicestack)
 {
 	Goal *goals;
-	Choicepoint *choicestack = nil;
+	Choicepoint *choicestack = *resultchoicestack;
 
-	clausenr = 2; /* Start at two since 0 is for the facts in the database, and 1 is for queries */
-
+	if(choicestack == 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
@@ -27,17 +26,21 @@
 		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;
 
-	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);
 
-	/* Now add the actual goals */
-	goals = addgoals(goals, query);
+		clausenr = 2; /* Start at two since 0 is for the facts in the database, and 1 is for queries */
+	}else{
+		goto Backtrack;
+	}
 
 	while(goals->goal != nil){
 		Term *dbstart;
@@ -76,7 +79,9 @@
 Backtrack:
 				if(choicestack == nil)
 					return 0;
-				print("Backtracking..\n");
+				if(debug)
+					print("Backtracking..\n");
+
 				Choicepoint *cp = choicestack;
 				choicestack = cp->next;
 				/* freegoals(goals) */
@@ -104,6 +109,7 @@
 	}
 	goals = goals->next;
 	unify(query, goals->goal, resultbindings);
+	*resultchoicestack = choicestack;
 	return 1;
 }
 
--- a/fns.h
+++ b/fns.h
@@ -15,7 +15,7 @@
 Term *mkstring(Rune *);
 
 /* eval.c */
-int evalquery(Term *, Term *, Binding **);
+int evalquery(Term *, Term *, Binding **, Choicepoint **);
 int unify(Term *, Term *, Binding **);
 
 /* repl.c */
--- a/main.c
+++ b/main.c
@@ -43,7 +43,8 @@
 		Term *goal;
 		for(goal = initgoals; goal != nil; goal = goal->next){
 			Binding *bindings = nil;
-			evalquery(database, goal, &bindings);
+			Choicepoint *choicestack = nil;
+			evalquery(database, goal, &bindings, &choicestack);
 		}
 	}
 
--- a/parser.c
+++ b/parser.c
@@ -81,6 +81,7 @@
 Term *
 parse(int fd, int querymode)
 {
+	fd = dup(fd, -1);
 	parsein = Bfdopen(fd, OREAD);
 	if(parsein == nil){
 		print("Could not open file\n");
@@ -95,6 +96,7 @@
 		uvlong id = 1;
 		result = copyterm(result, &id);
 	}
+	Bterm(parsein);
 	return result;
 }
 
--- a/repl.c
+++ b/repl.c
@@ -1,9 +1,12 @@
 #include <u.h>
 #include <libc.h>
+#include <bio.h>
 
 #include "dat.h"
 #include "fns.h"
 
+Rune parsefindmore(int);
+
 void
 repl(Term *database)
 {
@@ -12,7 +15,10 @@
 		print("?- ");
 		Term *query = parse(fd, 1);
 		Binding *bindings = nil;
-		int success = evalquery(database, query, &bindings);
+		Choicepoint *choicestack = nil;
+		int success;
+FindMore:
+		success = evalquery(database, query, &bindings, &choicestack);
 		if(success == 0)
 			print("false.\n");
 		else{
@@ -20,10 +26,46 @@
 				print("true.\n");
 			else{
 				while(bindings){
-					print("%S = %S\n", bindings->name, prettyprint(bindings->value));
+					print("  %S = %S%s", 
+						bindings->name, 
+						prettyprint(bindings->value), 
+						bindings->next ? " ,\n" : "");
 					bindings = bindings->next;
 				}
 			}
+			if(choicestack != nil){
+				print(" ");
+				if(parsefindmore(fd) == L';'){
+					print(";\n");
+					goto FindMore;
+				}else
+					print(".\n");
+			}else{
+				print(".\n");
+			}
 		}
 	}
+}
+
+Rune
+parsefindmore(int fd)
+{
+	int consctl = open("/dev/consctl", OWRITE);
+	if(consctl > 0)
+		write(consctl, "rawon", 5);
+	else{
+		print("Could not open /dev/consctl\n");
+		exits("open");
+	}
+
+	fd = dup(fd, -1);
+	Biobuf *input = Bfdopen(fd, OREAD);
+	Rune peek = Bgetrune(input);
+	Bterm(input);
+
+	if(consctl > 0){
+		write(consctl, "rawoff", 6);
+		close(consctl);
+	}
+	return peek;
 }
\ No newline at end of file
--- a/stdlib.pl
+++ b/stdlib.pl
@@ -16,10 +16,13 @@
 
 If -> Then ; _ :- 
 	If, !, Then.
+
 _ -> _ ; Else :-
 	!, Else.
+
 If ; _ :-
 	If.
+
 _ ; Else :-
 	Else.