Rewrite the compiler
A few days ago I found a bug in the compiler that I decided merited basically an
entire rewrite of it.
This was long overdue. The compiler kind of grew organically and unhealthily
over time as I wrapped my head around how the whole WAM is structured, and now
that I understand a lot more I can do things right.
This new implementation is a lot "flatter" than the old one. It makes use of
CLOS classes and generic methods to un-nest a lot of the crap that was
previously happening in bigass `labels` blocks. This is a lot easier to read
and understand because you can take things a piece at a time.
Unfortunately, it's currently a lot slower than the old one. But at least it's
*correct*, and now I can start taking a look at optimizing the performance with
a cleaner base to start from.
Notes/ideas for the near future:
* Switch to structs instead of CLOS classes for all the bits and bobs in the
compilation process.
* Inline hot functions in the compilation process.
* Type hint the fucking compiler already. I've put this off for far too long.
* Move the compiler to its own package for easier profiling and to maintain my
shreds of sanity.
* Look into that generic-function-inlining library thing I saw on Reddit...
* Remove the last vestiges of `match` and kill the dependency on optima.
author |
Steve Losh <steve@stevelosh.com> |
date |
Tue, 07 Jun 2016 14:49:20 +0000 |
parents |
4d33f11b074f |
children |
410acaae0c14 |
(in-package #:bones.wam)
(defparameter *database* nil)
(defvar *results* nil)
(defun make-database ()
(make-wam))
(defmacro with-database (database &body body)
`(let ((*database* ,database))
,@body))
(defmacro with-fresh-database (&body body)
`(with-database (make-database) ,@body))
(defun add-rules (rules)
(compile-rules *database* rules))
(defmacro rule (&body body)
`(add-rules '(,body)))
(defmacro fact (&body body)
`(add-rules '(,body)))
(defmacro rules (&body rules)
`(add-rules ',rules))
(defmacro facts (&body rules)
`(add-rules ',(mapcar #'list rules)))
(defun display-results (results)
(format t "~%")
(loop :for (var result . more) :on results :by #'cddr :do
(format t "~S = ~S~%" var result)))
(defun display-results-one (results)
(display-results results)
t)
(defun display-results-all (results)
(display-results results)
nil)
(defun display-results-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
:result-function
(ecase mode
(:interactive #'display-results-interactive)
(:all #'display-results-all)
(:one #'display-results-one))
:status-function
(lambda (failp)
(if failp
(princ "No.")
(princ "Yes."))))
(values))
(defun return-results-one (results)
(setf *results* results)
t)
(defun return-results-all (results)
(push results *results*)
nil)
(defun perform-return (query mode)
(ecase mode
(:all (let ((*results* nil))
(run-query *database* query
:result-function
#'return-results-all)
(values *results* (ensure-boolean *results*))))
(:one (let* ((no-results (gensym))
(*results* no-results))
(run-query *database* query
:result-function
#'return-results-one)
(if (eql *results* no-results)
(values nil nil)
(values *results* t))))))
(defun perform-prove (query)
(nth-value 1 (perform-return query :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))
(defmacro return-all (&body body)
`(perform-return ',body :all))
(defmacro return-one (&body body)
`(perform-return ',body :one))
(defmacro prove (&body body)
`(perform-prove ',body))
(defun dump (&optional full-code)
(dump-wam-full *database*)
(when full-code
(dump-wam-code *database*)))