Add done-thunk and use it for query interaction
Also adds `fact` convenience wrappers.
author |
Steve Losh <steve@stevelosh.com> |
date |
Fri, 22 Apr 2016 13:27:41 +0000 |
parents |
79abff72987d
|
children |
678ab674bd33
|
branches/tags |
(none) |
files |
src/wam/ui.lisp src/wam/vm.lisp |
Changes
--- a/src/wam/ui.lisp Fri Apr 22 12:39:36 2016 +0000
+++ b/src/wam/ui.lisp Fri Apr 22 13:27:41 2016 +0000
@@ -8,25 +8,63 @@
,@body))
-
(defun add-rules (rules)
(compile-rules *database* rules))
-(defun perform-query (query step)
- (run-query *database* query step))
-
(defmacro rule (&body body)
`(add-rules '(,body)))
+(defmacro fact (&body body)
+ `(add-rules '(,body)))
+
(defmacro rules (&body rules)
`(add-rules ',rules))
-(defmacro query (&body body)
- `(perform-query ',body nil))
+(defmacro facts (&body rules)
+ `(add-rules ',(mapcar #'list rules)))
+
+
+(defun display-results (results)
+ (format t "~%")
+ (loop :for (var . result) :in results :do
+ (format t "~S = ~S~%" var result)))
+
+(defun result-one (results)
+ (display-results results)
+ t)
+
+(defun result-all (results)
+ (display-results results)
+ nil)
-(defmacro query-step (&body body)
- `(perform-query ',body t))
+(defun result-interactive (results)
+ (display-results results)
+ (format t "~%More? [Yn] ")
+ (force-output)
+ (switch ((read-line) :test #'string=)
+ ("y" nil)
+ ("" nil)
+ ("n" t)
+ (t t)))
+
+
+(defun perform-query (query mode)
+ (run-query *database* query
+ (ecase mode
+ (:interactive #'result-interactive)
+ (:all #'result-all)
+ (:one #'result-one))))
+
+
+(defmacro query (&body body)
+ `(perform-query ',body :interactive))
+
+(defmacro query-all (&body body)
+ `(perform-query ',body :all))
+
+(defmacro query-one (&body body)
+ `(perform-query ',body :one))
(defun dump (&optional full-code)
--- a/src/wam/vm.lisp Fri Apr 22 12:39:36 2016 +0000
+++ b/src/wam/vm.lisp Fri Apr 22 13:27:41 2016 +0000
@@ -3,6 +3,7 @@
;;;; Config
(defparameter *break-on-fail* nil)
+(defparameter *step* nil)
;;;; Utilities
@@ -526,12 +527,8 @@
(results (extract-things wam addresses)))
(pairlis vars results)))
-(defun print-query-results (results)
- (loop :for (var . result) :in results :do
- (format t "~S = ~S~%" var result)))
-
-(defun run (wam &optional (step nil))
+(defun run (wam done-thunk)
(with-slots (code program-counter fail backtrack) wam
(macrolet ((instruction (inst args)
`(instruction-call wam ,inst code program-counter ,args)))
@@ -541,7 +538,7 @@
:for opcode = (aref code program-counter)
:do
(block op
- (when step
+ (when *step*
(dump) ; todo: make this saner
(break "About to execute instruction at ~4,'0X" program-counter))
(eswitch (opcode)
@@ -583,7 +580,9 @@
(instruction %call 1)
(return-from op))
(+opcode-done+
- (return-from run)))
+ (if (funcall done-thunk)
+ (return-from run)
+ (backtrack! wam "done-function returned false"))))
;; Only increment the PC when we didn't backtrack
(if (wam-backtracked wam)
(setf (wam-backtracked wam) nil)
@@ -592,12 +591,12 @@
(error "Fell off the end of the program code store!")))))
(values)))
-(defun run-query (wam term &optional (step nil))
+(defun run-query (wam term result-function)
"Compile query `term` and run the instructions on the `wam`.
Resets the heap, etc before running.
- When `step` is true, break into the debugger before calling the procedure and
+ When `*step*` is true, break into the debugger before calling the procedure and
after each instruction.
"
@@ -607,15 +606,15 @@
(wam-load-query-code! wam code)
(setf (wam-program-counter wam) 0
(wam-continuation-pointer wam) +code-sentinal+)
- (when step
+ (when *step*
(format *debug-io* "Built query code:~%")
(dump-code-store wam code))
- (run wam step)
+ (run wam (lambda ()
+ (funcall result-function
+ (extract-query-results wam vars))))
(if (wam-fail wam)
(princ "No.")
- (progn
- (print-query-results (extract-query-results wam vars))
- (princ "Yes."))))
+ (princ "Yes.")))
(values))