shithub: pprolog

Download patch

ref: 7db38904537603dabe960f32fa505e27db89e27b
parent: d81447526cde6fa98dfa792a65f71acb78ef1398
author: Peter Mikkelsen <peter@pmikkelsen.com>
date: Sat Jul 3 14:58:07 EDT 2021

Start adding support for read_term and write_term

--- a/builtins.c
+++ b/builtins.c
@@ -1,5 +1,6 @@
 #include <u.h>
 #include <libc.h>
+#include <bio.h>
 
 #include "dat.h"
 #include "fns.h"
@@ -41,6 +42,8 @@
 BuiltinProto(builtincurrentoutput);
 BuiltinProto(builtinsetinput);
 BuiltinProto(builtinsetoutput);
+BuiltinProto(builtinreadterm);
+BuiltinProto(builtinwriteterm);
 
 int compareterms(Term *, Term *);
 
@@ -116,6 +119,10 @@
 		return builtinsetinput;
 	if(Match(L"set_output", 1))
 		return builtinsetoutput;
+	if(Match(L"read_term", 3))
+		return builtinreadterm;
+	if(Match(L"write_term", 3))
+		return builtinwriteterm;
 
 	return nil;
 }
@@ -536,7 +543,7 @@
 
 	Term *ball = goal->children;
 
-	print("Throwing: %S\n", prettyprint(ball));
+	print("Throwing: %S\n", prettyprint(ball, 0, 0, 0));
 	Goal *g;
 	for(g = *goals; g != nil; g = g->next){
 		if(g->catcher == nil)
@@ -545,7 +552,7 @@
 		if(unify(g->catcher, ball, bindings)){
 			if(g->goal == nil){
 				/* As soon as we have print facilities as builtins, we can avoid this by having the protector frame have a unhandled exception handler*/
-				print("Unhandled exception: %S\n", prettyprint(ball));
+				print("Unhandled exception: %S\n", prettyprint(ball, 0, 0, 0));
 				exits("exception");
 				return 0;
 			}else{
@@ -727,7 +734,6 @@
 builtinsetoutput(Term *database, Term *goal, Goal **goals, Choicepoint **choicestack, Binding **bindings)
 {
 	USED(database);
-	USED(goal);
 	USED(goals);
 	USED(choicestack);
 	USED(bindings);
@@ -747,4 +753,66 @@
 
 	setcurrentoutputstream(stream);
 	return 1;
-}
\ No newline at end of file
+}
+
+int
+builtinreadterm(Term *database, Term *goal, Goal **goals, Choicepoint **choicestack, Binding **bindings)
+{
+	USED(database);
+	USED(goals);
+	USED(choicestack);
+	USED(bindings);
+
+	Term *stream = goal->children;
+	Term *term = stream->next;
+	Term *options = term->next;
+
+	if(stream->tag == VariableTerm)
+		Throw(instantiationerror());
+	if(options->tag != AtomTerm || runestrcmp(options->text, L"[]") != 0)
+		Throw(typeerror(L"empty_list", options));
+	if((stream->tag != NumberTerm || stream->numbertype != NumberInt) && stream->tag != AtomTerm)
+		Throw(domainerror(L"stream_or_alias", stream));
+	if(!isopenstream(stream))
+		Throw(existenceerror(L"stream", stream));
+	if(isoutputstream(stream))
+		Throw(permissionerror(L"input", L"stream", stream));
+	if(isbinarystream(stream))
+		Throw(permissionerror(L"input", L"binary_stream", stream));
+
+	Term *realterm;
+	int error = readterm(stream, options, &realterm);
+	if(error)
+		Throw(realterm);
+
+	return unify(term, realterm, bindings);
+}
+
+int
+builtinwriteterm(Term *database, Term *goal, Goal **goals, Choicepoint **choicestack, Binding **bindings)
+{
+	USED(database);
+	USED(goals);
+	USED(choicestack);
+	USED(bindings);
+	
+	Term *stream = goal->children;
+	Term *term = stream->next;
+	Term *options = term->next;
+
+	if(stream->tag == VariableTerm)
+		Throw(instantiationerror());
+	if(options->tag != AtomTerm || runestrcmp(options->text, L"[]") != 0)
+		Throw(typeerror(L"empty_list", options));
+	if((stream->tag != NumberTerm || stream->numbertype != NumberInt) && stream->tag != AtomTerm)
+		Throw(domainerror(L"stream_or_alias", stream));
+	if(!isopenstream(stream))
+		Throw(existenceerror(L"stream", stream));
+	if(isinputstream(stream))
+		Throw(permissionerror(L"output", L"stream", stream));
+	if(isbinarystream(stream))
+		Throw(permissionerror(L"output", L"binary_stream", stream));
+	writeterm(stream, options, term);
+	return 1;
+}
+
--- a/error.c
+++ b/error.c
@@ -1,5 +1,6 @@
 #include <u.h>
 #include <libc.h>
+#include <bio.h>
 
 #include "dat.h"
 #include "fns.h"
--- a/eval.c
+++ b/eval.c
@@ -1,5 +1,6 @@
 #include <u.h>
 #include <libc.h>
+#include <bio.h>
 
 #include "dat.h"
 #include "fns.h"
@@ -57,7 +58,7 @@
 		}
 
 		if(debug)
-			print("Working goal: %S\n", prettyprint(goal));
+			print("Working goal: %S\n", prettyprint(goal, 0, 0, 0));
 
 		Binding *bindings = nil;
 		Term *clause = nil;
@@ -226,6 +227,7 @@
 
 	switch(a->tag){
 	case AtomTerm:
+		return runestrcmp(a->text, b->text) == 0;
 	case VariableTerm:
 		return (runestrcmp(a->text, b->text) == 0 && a->clausenr == b->clausenr);
 	case NumberTerm:
--- a/flags.c
+++ b/flags.c
@@ -1,5 +1,6 @@
 #include <u.h>
 #include <libc.h>
+#include <bio.h>
 
 #include "dat.h"
 #include "fns.h"
--- a/fns.h
+++ b/fns.h
@@ -1,8 +1,8 @@
 /* parser.c */
-Term *parse(int, int);
+Term *parse(int, Biobuf *, int);
 
 /* prettyprint.c */
-Rune *prettyprint(Term *);
+Rune *prettyprint(Term *, int, int, int);
 
 /* misc.c */
 Term *copyterm(Term *, uvlong *);
@@ -51,4 +51,8 @@
 void setcurrentoutputstream(Term *);
 int isopenstream(Term *);
 int isinputstream(Term *);
-int isoutputstream(Term *);
\ No newline at end of file
+int isoutputstream(Term *);
+int istextstream(Term *);
+int isbinarystream(Term *);
+int readterm(Term *, Term *, Term **);
+void writeterm(Term *, Term *, Term *);
\ No newline at end of file
--- a/main.c
+++ b/main.c
@@ -1,5 +1,6 @@
 #include <u.h>
 #include <libc.h>
+#include <bio.h>
 
 #include "dat.h"
 #include "fns.h"
@@ -34,7 +35,7 @@
 		exits("open");
 	}
 
-	Term *database = parse(fd, 0);
+	Term *database = parse(fd, nil, 0);
 	close(fd);
 
 	if(parsetestfile){
@@ -41,7 +42,7 @@
 		int fd = open(parsetestfile, OREAD);
 		if(fd < 0)
 			exits("open");
-		Term *clauses = parse(fd, 0);
+		Term *clauses = parse(fd, nil, 0);
 		database = appendterm(database, clauses);
 
 		Term *goal;
--- a/misc.c
+++ b/misc.c
@@ -1,5 +1,6 @@
 #include <u.h>
 #include <libc.h>
+#include <bio.h>
 
 #include "dat.h"
 #include "fns.h"
--- a/parser.c
+++ b/parser.c
@@ -79,14 +79,18 @@
 Term *prologtext(int);
 
 Term *
-parse(int fd, int querymode)
+parse(int fd, Biobuf *bio, int querymode)
 {
-	fd = dup(fd, -1);
-	parsein = Bfdopen(fd, OREAD);
-	if(parsein == nil){
-		print("Could not open file\n");
-		return nil;
-	}
+	if(bio == nil){
+		fd = dup(fd, -1);
+		parsein = Bfdopen(fd, OREAD);
+		if(parsein == nil){
+			print("Could not open file\n");
+			return nil;
+		}
+	}else
+		parsein = bio;
+
 	initgoals = nil;
 	initoperators();
 	nexttoken();
@@ -96,7 +100,9 @@
 		uvlong id = 1;
 		result = copyterm(result, &id);
 	}
-	Bterm(parsein);
+	if(!bio)
+		Bterm(parsein);
+
 	return result;
 }
 
@@ -118,7 +124,7 @@
 	
 	if(t->tag == CompoundTerm && runestrcmp(t->text, L":-") == 0 && t->arity == 1){
 		Term *body = t->children;
-		print("Got directive: %S\n", prettyprint(body));
+		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;
@@ -296,7 +302,7 @@
 		if(index == -1){
 			print("Can't parse, list of length %d contains no operators: ", length);
 			for(i = 0; i < length; i++)
-				print("%S(%d) ", prettyprint(terms[i]), infos[i].level);
+				print("%S(%d) ", prettyprint(terms[i], 0, 0, 0), infos[i].level);
 			print("\n");
 			syntaxerror_parser("parseoperators");
 		}
@@ -337,7 +343,7 @@
 				terms[i] = terms[i+1];
 			}
 		}else{
-			print("Parse error when parsing operator %S (prefix=%d, postfix=%d, infix=%d level=%d)\n", prettyprint(terms[index]), prefixlevel, postfixlevel, infixlevel, infos[index].level);
+			print("Parse error when parsing operator %S (prefix=%d, postfix=%d, infix=%d level=%d)\n", prettyprint(terms[index], 0, 0, 0), prefixlevel, postfixlevel, infixlevel, infos[index].level);
 			syntaxerror_parser("parseoperators");
 		}
 	}
--- a/prettyprint.c
+++ b/prettyprint.c
@@ -1,15 +1,16 @@
 #include <u.h>
 #include <libc.h>
+#include <bio.h>
 
 #include "dat.h"
 #include "fns.h"
 
-Rune *prettyprintlist(Term *, Rune *, int);
-Rune *printlist(Term *);
+Rune *prettyprintlist(Term *, Rune *, int, int, int, int);
+Rune *printlist(Term *, int, int, int);
 int islist(Term *);
 
 Rune *
-prettyprint(Term *t)
+prettyprint(Term *t, int quoted, int ignoreops, int numbervars)
 {
 	Rune *result;
 	Rune *args;
@@ -16,9 +17,9 @@
 
 	switch(t->tag){
 	case CompoundTerm:
-		args = printlist(t);
+		args = printlist(t, quoted, ignoreops, numbervars);
 		if(args == nil){
-			args = prettyprintlist(t->children, L", ", 0);
+			args = prettyprintlist(t->children, L", ", 0, quoted, ignoreops, numbervars);
 			result = runesmprint("%S(%S)", t->text, args);
 			free(args);
 		}else
@@ -45,7 +46,7 @@
 }
 
 Rune *
-prettyprintlist(Term *t, Rune *sep, int end)
+prettyprintlist(Term *t, Rune *sep, int end, int quoted, int ignoreops, int numbervars)
 {
 	if(t == nil){
 		if(end)
@@ -54,8 +55,8 @@
 			return runesmprint("");
 	}
 
-	Rune *str = prettyprint(t);
-	Rune *rest = prettyprintlist(t->next, sep, end);
+	Rune *str = prettyprint(t, quoted, ignoreops, numbervars);
+	Rune *rest = prettyprintlist(t->next, sep, end, quoted, ignoreops, numbervars);
 	Rune *result;
 
 	if(t->next != nil)
@@ -70,7 +71,7 @@
 
 /* printlist prints a list's elements but not the surrounding [ and ] */
 Rune *
-printlist(Term *list)
+printlist(Term *list, int quoted, int ignoreops, int numbervars)
 {
 	if(list->tag != CompoundTerm || list->arity != 2 || runestrcmp(L".", list->text) != 0)
 		return nil;
@@ -78,20 +79,20 @@
 	Term *head = list->children;
 	Term *tail = head->next;
 
-	Rune *headstr = prettyprint(head);
+	Rune *headstr = prettyprint(head, quoted, ignoreops, numbervars);
 	Rune *tailstr = nil;
 	Rune *result;
 
 	if(tail->tag == CompoundTerm && tail->arity == 2 && runestrcmp(L".", tail->text) == 0){
-		tailstr = printlist(tail);
+		tailstr = printlist(tail, quoted, ignoreops, numbervars);
 		result = runesmprint("%S, %S", headstr, tailstr);
 	}else if(tail->tag == AtomTerm && runestrcmp(L"[]", tail->text) == 0){
 		result = runesmprint("%S", headstr);
 	}else{
-		tailstr = prettyprint(tail);
+		tailstr = prettyprint(tail, quoted, ignoreops, numbervars);
 		result = runesmprint("%S | %S", headstr, tailstr);
 	}
 	free(headstr);
 	free(tailstr);
 	return result;
-}
\ No newline at end of file
+}
--- a/repl.c
+++ b/repl.c
@@ -13,7 +13,7 @@
 	int fd = 0; /* Standard input */
 	while(1){
 		print("?- ");
-		Term *query = parse(fd, 1);
+		Term *query = parse(fd, nil, 1);
 		Binding *bindings = nil;
 		Choicepoint *choicestack = nil;
 		int success;
@@ -28,7 +28,7 @@
 				while(bindings){
 					print("  %S = %S%s", 
 						bindings->name, 
-						prettyprint(bindings->value), 
+						prettyprint(bindings->value, 0, 0, 0), 
 						bindings->next ? " ,\n" : "");
 					bindings = bindings->next;
 				}
--- a/stdlib.pl
+++ b/stdlib.pl
@@ -105,3 +105,35 @@
 
 syntax_error(Error) :-
 	throw(error(syntax_error(Error), _)).
+
+% Input and output
+
+read_term(Term, Options) :-
+	current_input(S),
+	read_term(S, Term, Options).
+
+read(Term) :-
+	current_input(S),
+	read_term(S, Term, []).
+
+write_term(Term, Options) :-
+	current_output(S),
+	write_term(S, Term, Options).
+
+write(Term) :-
+	current_output(S),
+	write_term(S, Term, [numbervars(true)]).
+
+writeq(Term) :-
+	current_output(S),
+	write_term(S, Term, [quoted(true), numbervars(true)]).
+
+writeq(S, Term) :-
+	write_term(S, Term, [quoted(true), numbervars(true)]).
+
+write_canonical(Term) :-
+	current_output(S),
+	write_term(S, Term, [quoted(true), ignore_ops(true)]).
+
+write_canonical(S, Term) :-
+	write_term(S, Term, [quoted(true), ignore_ops(true)]).
--- a/streams.c
+++ b/streams.c
@@ -1,5 +1,6 @@
 #include <u.h>
 #include <libc.h>
+#include <bio.h>
 
 #include "dat.h"
 #include "fns.h"
@@ -9,6 +10,7 @@
 struct Stream
 {
 	ulong fd;
+	Biobuf *bio;
 	int type;
 	int mode;
 	int nalias;
@@ -31,7 +33,7 @@
 static Stream *currentinput;
 static Stream *currentoutput;
 
-Stream *openstreamfd(int, int, int);
+Stream *openstreamfd(int, Biobuf *, int, int);
 Stream *getstreambyfd(int);
 Stream *getstreambyalias(Rune *);
 Stream *getstream(Term *);
@@ -39,8 +41,14 @@
 void
 initstreams(void)
 {
-	currentinput = openstreamfd(0, TextStream, ReadStream);
-	currentoutput = openstreamfd(1, TextStream, WriteStream);
+	int infd = dup(0, -1);
+	int outfd = dup(1, -1);
+
+	Biobuf *bioin = Bfdopen(infd, OREAD);
+	Biobuf *bioout = Bfdopen(outfd, OWRITE);
+	
+	currentinput = openstreamfd(infd, bioin, TextStream, ReadStream);
+	currentoutput = openstreamfd(outfd, bioout, TextStream, WriteStream);
 }
 
 int
@@ -69,7 +77,13 @@
 		*stream = permissionerror(L"open", L"source_sink", mkatom(sourcesink));
 		return 1;
 	}
-	Stream *s = openstreamfd(fd, TextStream, smode);
+	Biobuf *bio = Bfdopen(fd, omode);
+	if(bio == nil){
+		*stream = permissionerror(L"open", L"source_sink", mkatom(sourcesink));
+		return 1;
+	}
+
+	Stream *s = openstreamfd(fd, bio, TextStream, smode);
 	*stream = mknumber(NumberInt, s->fd, 0);
 	return 0;
 }
@@ -81,6 +95,9 @@
 	if(s == nil)
 		return;
 
+	Bterm(s->bio);
+	close(s->fd);
+
 	Stream *tmp;
 	Stream *prev = nil;
 	for(tmp = streams; tmp != nil; tmp = tmp->next){
@@ -154,11 +171,66 @@
 		return 0;
 }
 
+int
+istextstream(Term *t)
+{
+	Stream *s = getstream(t);
+	if(s && s->type == TextStream)
+		return 1;
+	else
+		return 0;
+}
+
+int
+isbinarystream(Term *t)
+{
+	Stream *s = getstream(t);
+	if(s && s->type == BinaryStream)
+		return 1;
+	else
+		return 0;
+}
+
+int
+readterm(Term *stream, Term *options, Term **term)
+{
+	USED(options);
+
+	Stream *s = getstream(stream);
+	if(s == nil){
+		*term = existenceerror(L"stream", stream);
+		return 1;
+	}
+	print(": ");
+	*term = parse(0, s->bio, 1);
+
+	return 0;
+}
+
+void
+writeterm(Term *stream, Term *options, Term *term)
+{
+	USED(options);
+	
+	Stream *s = getstream(stream);
+	if(s == nil)
+		return;
+
+	int quoted = 0;
+	int ignoreops = 0;
+	int numbervars = 0;
+
+	Rune *output = prettyprint(term, quoted, ignoreops, numbervars);
+	Bprint(s->bio, "%S", output);
+	Bflush(s->bio);
+}
+
 Stream *
-openstreamfd(int fd, int type, int mode)
+openstreamfd(int fd, Biobuf *bio, int type, int mode)
 {
 	Stream *s = malloc(sizeof(Stream));
 	s->fd = fd;
+	s->bio = bio;
 	s->type = type;
 	s->mode = mode;
 	s->nalias = 0;
@@ -201,4 +273,5 @@
 	else if(t->tag == AtomTerm)
 		s = getstreambyalias(t->text);
 	return s;
-}
\ No newline at end of file
+}
+