shithub: pprolog

Download patch

ref: 44ab8a339c78bcc3460d44b2f435116f21faa60a
parent: 3f26a0f2a1f699e628136ec5be6178b5ab40fc44
author: Peter Mikkelsen <peter@pmikkelsen.com>
date: Mon Jul 5 12:27:38 EDT 2021

First step on modules. Still very very rough.

--- a/TODO
+++ b/TODO
@@ -5,4 +5,4 @@
 * Right now we copy and allocate a lot, but almost never free stuff.
 * Many builtins should really throw an error, but they just fail for now.
 * Exceptions (throw, catch)
-* Modules
+* Modules (I try to do something like SWI prolog for now, but I know there is also an iso standard)
\ No newline at end of file
--- a/builtins.c
+++ b/builtins.c
@@ -5,7 +5,7 @@
 #include "dat.h"
 #include "fns.h"
 
-#define BuiltinProto(name) int name(Term *, Term *, Binding **)
+#define BuiltinProto(name) int name(Term *, Binding **)
 #define Match(X, Y) (runestrcmp(name, X) == 0 && arity == Y)
 #define Throw(What) do{\
 	Goal *g = malloc(sizeof(Goal)); \
@@ -128,9 +128,8 @@
 }
 
 int
-builtinfail(Term *database, Term *goal, Binding **bindings)
+builtinfail(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(goal);
 	USED(bindings);
 	return 0;
@@ -137,9 +136,8 @@
 }
 
 int
-builtincall(Term *database, Term *goal, Binding **bindings)
+builtincall(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 
 	Goal *g = malloc(sizeof(Goal));
@@ -152,9 +150,8 @@
 }
 
 int
-builtincut(Term *database, Term *goal, Binding **bindings)
+builtincut(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 
 	Choicepoint *cp = choicestack;
@@ -169,9 +166,8 @@
 }
 
 int
-builtinvar(Term *database, Term *goal, Binding **bindings)
+builtinvar(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 	Term *arg = goal->children;
 	return (arg->tag == VariableTerm);
@@ -178,9 +174,8 @@
 }
 
 int
-builtinatom(Term *database, Term *goal, Binding **bindings)
+builtinatom(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 	Term *arg = goal->children;
 	return (arg->tag == AtomTerm);
@@ -187,9 +182,8 @@
 }
 
 int
-builtininteger(Term *database, Term *goal, Binding **bindings)
+builtininteger(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 	Term *arg = goal->children;
 	return (arg->tag == NumberTerm && arg->numbertype == NumberInt);
@@ -196,9 +190,8 @@
 }
 
 int
-builtinfloat(Term *database, Term *goal, Binding **bindings)
+builtinfloat(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 	Term *arg = goal->children;
 	return (arg->tag == NumberTerm && arg->numbertype == NumberFloat);
@@ -205,9 +198,8 @@
 }
 
 int
-builtinatomic(Term *database, Term *goal, Binding **bindings)
+builtinatomic(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 	Term *arg = goal->children;
 	return (arg->tag == AtomTerm || arg->tag == NumberTerm);
@@ -214,9 +206,8 @@
 }
 
 int
-builtincompound(Term *database, Term *goal, Binding **bindings)
+builtincompound(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 	Term *arg = goal->children;
 	return (arg->tag == CompoundTerm);
@@ -223,9 +214,8 @@
 }
 
 int
-builtinnonvar(Term *database, Term *goal, Binding **bindings)
+builtinnonvar(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 	Term *arg = goal->children;
 	return (arg->tag != VariableTerm);
@@ -232,9 +222,8 @@
 }
 
 int
-builtinnumber(Term *database, Term *goal, Binding **bindings)
+builtinnumber(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 	Term *arg = goal->children;
 	return (arg->tag == NumberTerm);
@@ -296,9 +285,8 @@
 }
 
 int
-builtincompare(Term *database, Term *goal, Binding **bindings)
+builtincompare(Term *goal, Binding **bindings)
 {
-	USED(database);
 	Term *order = goal->children;
 	Term *t1 = order->next;
 	Term *t2 = t1->next;
@@ -317,9 +305,8 @@
 }
 
 int
-builtinfunctor(Term *database, Term *goal, Binding **bindings)
+builtinfunctor(Term *goal, Binding **bindings)
 {
-	USED(database);
 
 	Term *term = goal->children;
 	Term *name = term->next;
@@ -354,9 +341,8 @@
 }
 
 int
-builtinarg(Term *database, Term *goal, Binding **bindings)
+builtinarg(Term *goal, Binding **bindings)
 {
-	USED(database);
 
 	Term *n = goal->children;
 	Term *term = n->next;
@@ -390,9 +376,8 @@
 }
 
 int
-builtinuniv(Term *database, Term *goal, Binding **bindings)
+builtinuniv(Term *goal, Binding **bindings)
 {
-	USED(database);
 	Term *term = goal->children;
 	Term *list = term->next;
 
@@ -463,9 +448,8 @@
 }
 
 int
-builtinis(Term *database, Term *goal, Binding **bindings)
+builtinis(Term *goal, Binding **bindings)
 {
-	USED(database);
 	Term *result = goal->children;
 	Term *expr = result->next;
 
@@ -478,9 +462,8 @@
 }
 
 int
-builtincatch(Term *database, Term *goal, Binding **bindings)
+builtincatch(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 
 	Term *catchgoal = goal->children;
@@ -503,9 +486,8 @@
 }
 
 int
-builtinthrow(Term *database, Term *goal, Binding **bindings)
+builtinthrow(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 
 	Term *ball = goal->children;
@@ -543,9 +525,8 @@
 }
 
 int
-builtincurrentprologflag(Term *database, Term *goal, Binding **bindings)
+builtincurrentprologflag(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(goal);
 	USED(bindings);
 	return 0;
@@ -552,9 +533,8 @@
 }
 
 int
-builtinsetprologflag(Term *database, Term *goal, Binding **bindings)
+builtinsetprologflag(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 	Term *key = goal->children;
 	Term *value = key->next;
@@ -572,9 +552,8 @@
 }
 
 int
-builtinopen(Term *database, Term *goal, Binding **bindings)
+builtinopen(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 
 	Term *sourcesink = goal->children;
@@ -608,9 +587,8 @@
 }
 
 int
-builtinclose(Term *database, Term *goal, Binding **bindings)
+builtinclose(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 	
 	Term *stream = goal->children;
@@ -634,9 +612,8 @@
 }
 
 int
-builtincurrentinput(Term *database, Term *goal, Binding **bindings)
+builtincurrentinput(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 
 	Term *stream = goal->children;
@@ -648,9 +625,8 @@
 }
 
 int
-builtincurrentoutput(Term *database, Term *goal, Binding **bindings)
+builtincurrentoutput(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 
 	Term *stream = goal->children;
@@ -662,9 +638,8 @@
 }
 
 int
-builtinsetinput(Term *database, Term *goal, Binding **bindings)
+builtinsetinput(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 
 	Term *stream = goal->children;
@@ -685,9 +660,8 @@
 }
 
 int
-builtinsetoutput(Term *database, Term *goal, Binding **bindings)
+builtinsetoutput(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 
 	Term *stream = goal->children;
@@ -708,9 +682,8 @@
 }
 
 int
-builtinreadterm(Term *database, Term *goal, Binding **bindings)
+builtinreadterm(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
 
 	Term *stream = goal->children;
@@ -739,11 +712,10 @@
 }
 
 int
-builtinwriteterm(Term *database, Term *goal, Binding **bindings)
+builtinwriteterm(Term *goal, Binding **bindings)
 {
-	USED(database);
 	USED(bindings);
-	
+
 	Term *stream = goal->children;
 	Term *term = stream->next;
 	Term *options = term->next;
@@ -763,4 +735,3 @@
 	writeterm(stream, options, term);
 	return 1;
 }
-
--- a/dat.h
+++ b/dat.h
@@ -2,7 +2,9 @@
 typedef struct Binding Binding;
 typedef struct Goal Goal;
 typedef struct Choicepoint Choicepoint;
-typedef int (*Builtin)(Term *, Term *, Binding **);
+typedef struct Clause Clause;
+typedef struct Module Module;
+typedef int (*Builtin)(Term *, Binding **);
 
 struct Term
 {
@@ -36,11 +38,29 @@
 struct Choicepoint
 {
 	Goal *goalstack;
-	Term *retryclause;
+	Clause *retryclause;
 	uvlong id; /* Unique number for each clause. Used to know where to cut to. */
+	Module *currentmodule;
 	Choicepoint *next;
 };
 
+struct Clause
+{
+	Term *head;
+	Term *body;
+	uvlong clausenr;
+	int public;
+	Clause *next;
+};
+
+struct Module
+{
+	/* What about imports */
+	Rune *name;
+	Clause *clauses;
+	Module *next;
+};
+
 /* Sorted so that a lower value means it comes earlier in the standard ordering */
 enum {
 	VariableTerm,
@@ -55,7 +75,6 @@
 };
 
 int debug;
-Term *initgoals;
 
 /* Flags */
 enum {
@@ -66,6 +85,9 @@
 
 int flagdoublequotes;
 
-/* Staate of the running system */
+/* State of the running system */
 Choicepoint *choicestack;
-Goal *goalstack;
\ No newline at end of file
+Goal *goalstack;
+Module *modules;
+Module *systemmodule; /* The module for the builtins. Everything has access to those */
+Module *usermodule; /* The default module for user defined predicates */
--- a/eval.c
+++ b/eval.c
@@ -6,7 +6,7 @@
 #include "fns.h"
 
 Goal *addgoals(Goal *, Term *);
-Term *findclause(Term *, Term *, Binding **);
+Clause *findclause(Clause *, Term *, Binding **);
 int equalterms(Term *, Term *);
 Goal *copygoals(Goal *);
 Builtin findbuiltin(Term *);
@@ -14,8 +14,9 @@
 static uvlong clausenr;
 
 int
-evalquery(Term *database, Term *query, Binding **resultbindings)
+evalquery(Term *query, Binding **resultbindings)
 {
+	static Module *currentmodule = nil;
 	if(choicestack == nil){
 	/*
 		The goal stack has the original query at the very bottom, protected by a catch frame where the ->goal field is nil.
@@ -37,42 +38,60 @@
 		goalstack = addgoals(goalstack, query);
 
 		clausenr = 2; /* Start at two since 0 is for the facts in the database, and 1 is for queries */
+
+		currentmodule = usermodule;
 	}else{
 		goto Backtrack;
 	}
 
 	while(goalstack->goal != nil){
-		Term *dbstart;
+		Clause *startclause;
 		Term *goal;
 		Goal *oldgoalstack;
 
-		dbstart = database;
+		startclause = nil; /* Where to start looking for a matching clause. Used by backtracking */
 Retry:
-		print("Loop run\n");
 		goal = goalstack->goal;
 		oldgoalstack = goalstack;
 		goalstack = goalstack->next;
 
-		if(oldgoalstack->catcher){
-			print("Was catchframe\n");
+		if(oldgoalstack->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){
+			Term *module = goal->children;
+			if(module->tag == AtomTerm){
+				Module *m = getmodule(module->text);
+				if(m == nil)
+					goal = existenceerror(L"module", module);
+				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;
-		Term *clause = nil;
+		Clause *clause = nil;
 		
 		/* 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, &bindings);
+			int success = builtin(goal, &bindings);
 			if(!success)
 				goto Backtrack;
 		}else{
 			/* Find a clause where the head unifies with the goal */
-			clause = findclause(dbstart, goal, &bindings);
+			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. */
@@ -81,6 +100,7 @@
 					cp->next = choicestack;
 					cp->retryclause = clause->next;
 					cp->id = clause->clausenr;
+					cp->currentmodule = currentmodule;
 					choicestack = cp;
 				}
 			}else{
@@ -93,7 +113,8 @@
 				choicestack = cp->next;
 				/* freegoals(goals) */
 				goalstack = cp->goalstack;
-				dbstart = cp->retryclause;
+				currentmodule = cp->currentmodule;
+				startclause = cp->retryclause;
 				goto Retry;
 			}
 		}
@@ -106,8 +127,8 @@
 		}
 
 		/* 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);
+		if(clause != nil && clause->body != nil){
+			Term *subgoal = copyterm(clause->body, nil);
 			applybinding(subgoal, bindings);
 			goalstack = addgoals(goalstack, subgoal);
 		}
@@ -133,21 +154,18 @@
 	return goals;
 }
 
-Term *
-findclause(Term *database, Term *goal, Binding **bindings)
+Clause *
+findclause(Clause *clauses, Term *goal, Binding **bindings)
 {
-	Term *clause;
-	Term *head;
-	for(; database != nil; database = database->next){
-		clause = copyterm(database, &clausenr);
-		clausenr++;
-		clause->next = database->next;
-		if(clause->tag == CompoundTerm && runestrcmp(clause->text, L":-") == 0 && clause->arity == 2)
-			head = clause->children;
-		else
-			head = clause;
+	Clause *clause;
+	for(; clauses != nil; clauses = clauses->next){
+		if(!clauses->public)
+			continue;
 
-		if(unify(head, goal, bindings))
+		clause = copyclause(clauses, &clausenr);
+		clausenr++;
+		clause->next = clauses->next;
+		if(unify(clause->head, goal, bindings))
 			return clause;
 	}
 	return nil;
--- a/example.pl
+++ b/example.pl
@@ -1,3 +1,5 @@
+:- module(example, []).
+
 math(A,B,C,D) :- D is A + B + C * A.
 
 parentest :-
--- a/fns.h
+++ b/fns.h
@@ -14,14 +14,15 @@
 Term *mknumber(int, vlong, double);
 Term *mkstring(Rune *);
 Term *mklist(Term *);
+Clause *copyclause(Clause *, uvlong *);
 
 /* eval.c */
-int evalquery(Term *, Term *, Binding **);
+int evalquery(Term *, Binding **);
 int unify(Term *, Term *, Binding **);
 void applybinding(Term *, Binding *);
 
 /* repl.c */
-void repl(Term *);
+void repl(void);
 
 /* builtins.c */
 Builtin findbuiltin(Term *);
@@ -55,4 +56,9 @@
 int istextstream(Term *);
 int isbinarystream(Term *);
 int readterm(Term *, Term *, Term **);
-void writeterm(Term *, Term *, Term *);
\ No newline at end of file
+void writeterm(Term *, Term *, Term *);
+
+/* module.c */
+void initmodules(void);
+Module *parsemodule(char *);
+Module *getmodule(Rune *);
\ No newline at end of file
--- a/main.c
+++ b/main.c
@@ -10,50 +10,25 @@
 void
 main(int argc, char *argv[])
 {
-	char *parsetestfile = nil;
-
 	ARGBEGIN{
 	case 'd':
 		debug = 1;
 		break;
-	case 'f':
-		parsetestfile = EARGF(usage());
-		break;
 	default:
 		usage();
 	}ARGEND
 
-	if(argc != 0)
-		usage();
-
 	initflags();
 	initstreams();
+	initmodules();
 
-	int fd = open("./stdlib.pl", OREAD);
-	if(fd < 0){
-		print("Can't open ./stdlib.pl\n");
-		exits("open");
+	while(argc != 0){
+		parsemodule(argv[0]);
+		argc--;
+		argv++;
 	}
 
-	Term *database = parse(fd, nil, 0);
-	close(fd);
-
-	if(parsetestfile){
-		int fd = open(parsetestfile, OREAD);
-		if(fd < 0)
-			exits("open");
-		Term *clauses = parse(fd, nil, 0);
-		database = appendterm(database, clauses);
-
-		Term *goal;
-		for(goal = initgoals; goal != nil; goal = goal->next){
-			Binding *bindings = nil;
-			evalquery(database, goal, &bindings);
-		}
-	}
-
-	repl(database);
-
+	repl();
 	exits(nil);
 }
 
@@ -60,6 +35,6 @@
 void
 usage(void)
 {
-	fprint(2, "Usage: pprolog [-d]\n");
+	fprint(2, "Usage: pprolog [-d] modulefiles\n");
 	exits("Usage");
 }
\ No newline at end of file
--- a/misc.c
+++ b/misc.c
@@ -132,3 +132,21 @@
 		return mkcompound(L".", 2, t);
 	}
 }
+
+Clause *
+copyclause(Clause *orig, uvlong *clausenr)
+{
+	Clause *new = malloc(sizeof(Clause));
+	new->head = copyterm(orig->head, clausenr);
+	if(orig->body)
+		new->body = copyterm(orig->body, clausenr);
+	else
+		new->body = nil;
+	if(clausenr)
+		new->clausenr = *clausenr;
+	else
+		new->clausenr = orig->clausenr;
+	new->public = orig->public;
+	new->next = nil;
+	return new;
+}
\ No newline at end of file
--- a/mkfile
+++ b/mkfile
@@ -12,7 +12,8 @@
 	repl.$O\
 	flags.$O\
 	error.$O\
-	streams.$O
+	streams.$O\
+	module.$O
 
 HFILES=dat.h fns.h
 
--- /dev/null
+++ b/module.c
@@ -1,0 +1,116 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+#include "dat.h"
+#include "fns.h"
+
+Module *addemptymodule(Rune *);
+Clause *appendclause(Clause *, Clause *);
+
+void
+initmodules(void)
+{
+	systemmodule = parsemodule("./stdlib.pl");
+	if(systemmodule == nil){
+		print("Can't load ./stdlib.pl\n");
+		exits(nil);
+	}
+
+	usermodule = addemptymodule(L"user");
+}
+
+Module *
+parsemodule(char *file)
+{
+	Module *m = nil;
+
+	int fd = open(file, OREAD);
+	if(fd < 0)
+		return nil;
+	Term *terms = parse(fd, nil, 0);
+
+	if(terms == nil)
+		return nil;
+
+	/* Actually look at the terms and convert ':-'/2 terms into clauses.
+	   The only directives (terms of type ':-'/1 there should be in the list are
+	   the module specific ones, as the other are handled by parse itself.
+	*/
+	if(terms->tag == CompoundTerm && runestrcmp(terms->text, L":-") == 0 && terms->arity == 1){
+		Term *directive = terms->children;
+		if(directive->tag == CompoundTerm && runestrcmp(directive->text, L"module") == 0 && directive->arity == 2){
+			Term *modulename = directive->children;
+			Term *publiclist = modulename->next;
+			if(modulename->tag != AtomTerm){
+				print("Module name should be an atom in: %S\n", prettyprint(directive, 0, 0, 0));
+				return nil;
+			}
+			print("Public list for module '%S': %S\n", modulename->text, prettyprint(publiclist, 0, 0, 0));
+			m = addemptymodule(modulename->text);
+		}
+		terms = terms->next;
+	}
+
+	Term *t;
+	for(t = terms; t != nil; t = t->next){
+		Clause *cl = malloc(sizeof(Clause));
+		cl->clausenr = 0;
+		cl->public = 1; /* everything is public for now */
+		cl->next = nil;
+		if(t->tag == CompoundTerm && runestrcmp(t->text, L":-") == 0 && t->arity == 2){
+			cl->head = t->children;
+			cl->body = t->children->next;
+		}else{
+			cl->head = t;
+			cl->body = nil;
+		}
+
+		if(m == nil)
+			usermodule->clauses = appendclause(usermodule->clauses, cl);
+		else
+			m->clauses = appendclause(m->clauses, cl);
+	}
+
+	return m;
+}
+
+Module *
+getmodule(Rune *name)
+{
+	Module *m;
+	for(m = modules; m != nil; m = m->next){
+		if(runestrcmp(m->name, name) == 0)
+			return m;
+	}
+	return nil;
+}
+
+Module *
+addemptymodule(Rune *name)
+{
+	Module *m = malloc(sizeof(Module));
+	m->name = name;
+	m->next = modules;
+
+	if(systemmodule == nil)
+		m->clauses = nil;
+	else
+		m->clauses = systemmodule->clauses; /* Direct access to system clauses for now, but when I figure out imports this will change */
+	modules = m;
+	return m;
+}
+
+Clause *
+appendclause(Clause *clauses, Clause *new)
+{
+	Clause *tmp;
+
+	if(clauses == nil)
+		return new;
+
+	for(tmp = clauses; tmp->next != nil; tmp = tmp->next);
+
+	tmp->next = new;
+	return clauses;
+}
\ No newline at end of file
--- a/parser.c
+++ b/parser.c
@@ -91,7 +91,6 @@
 	}else
 		parsein = bio;
 
-	initgoals = nil;
 	initoperators();
 	nexttoken();
 
@@ -125,12 +124,10 @@
 	if(t->tag == CompoundTerm && runestrcmp(t->text, L":-") == 0 && t->arity == 1){
 		Term *body = t->children;
 		print("Got directive: %S\n", prettyprint(body, 0, 0, 0));
-		if(body->tag == CompoundTerm && body->arity == 1 && runestrcmp(body->text, L"initialization") == 0){
-			Term *tmp = initgoals;
-			initgoals = body->children;
-			initgoals->next = tmp;
-		}
-		t = prologtext(querymode);
+		if(runestrcmp(body->text, L"module") == 0 && body->arity == 2)
+			t->next = prologtext(querymode);
+		else
+			t = prologtext(querymode);
 	}else if(t->tag == CompoundTerm && runestrcmp(t->text, L":-") == 0 && t->arity == 2){
 		t->next = prologtext(querymode);
 	}else if(t->tag == AtomTerm || t->tag == CompoundTerm){
@@ -391,6 +388,7 @@
 	addoperator(700,  Xfx, L">");
 	addoperator(700,  Xfx, L">=");
 	addoperator(700,  Xfx, L"=..");
+	addoperator(600,  Xfy, L":");
 	addoperator(500,  Yfx, L"+");
 	addoperator(400,  Yfx, L"*");
 	addoperator(400,  Yfx, L"/");
--- a/repl.c
+++ b/repl.c
@@ -8,7 +8,7 @@
 Rune parsefindmore(int);
 
 void
-repl(Term *database)
+repl(void)
 {
 	int fd = 0; /* Standard input */
 	while(1){
@@ -19,7 +19,7 @@
 		goalstack = nil; /* should free old choicestack and goalstack */
 		int success;
 FindMore:
-		success = evalquery(database, query, &bindings);
+		success = evalquery(query, &bindings);
 		if(success == 0)
 			print("false.\n");
 		else{
--- a/stdlib.pl
+++ b/stdlib.pl
@@ -1,3 +1,5 @@
+:- module(system, []).
+
 % Logic and control predicates
 \+ Goal :- call(Goal), !, fail.
 \+ Goal.
@@ -57,17 +59,6 @@
 	A == B.
 A @>= B :-
 	A @> B.
-
-% List predicates
-
-length([], 0).
-length([_|Tail], Length) :-
-	length(Tail, Length0),
-	Length is Length0 + 1.
-
-member(X, [X|_]).
-member(X, [_|Tail]) :-
-	member(X, Tail).
 
 % Input output