src/wam/instructions.lisp @ 87afb11b9791
Add a function for extracting things from the heap
| author | Steve Losh <steve@stevelosh.com> |
|---|---|
| date | Sun, 27 Mar 2016 22:25:43 +0000 |
| parents | d80af96eaf15 |
| children | 0b1008a7fe76 |
(in-package #:bones.wam) ;;;; Utilities (defun* push-unbound-reference! ((wam wam)) (:returns (values heap-cell heap-index)) "Push a new unbound reference cell onto the heap." (wam-heap-push! wam (make-cell-reference (wam-heap-pointer wam)))) (defun* push-new-structure! ((wam wam)) (:returns (values heap-cell heap-index)) "Push a new structure cell onto the heap. The structure cell's value will point at the next address, so make sure you push something there too! " (wam-heap-push! wam (make-cell-structure (1+ (wam-heap-pointer wam))))) (defun* push-new-functor! ((wam wam) (functor symbol) (arity arity)) (:returns (values heap-cell heap-index)) "Push a new functor cell onto the heap. If the functor isn't already in the functor table it will be added. " (wam-heap-push! wam (make-cell-functor (wam-ensure-functor-index wam functor) arity))) (defun* bound-reference-p ((address heap-index) (cell heap-cell)) (:returns boolean) "Return whether `cell` is a bound reference, assuming it lives at `address`." (ensure-boolean (and (cell-reference-p cell) (not (= (cell-value cell) address))))) (defun* unbound-reference-p ((address heap-index) (cell heap-cell)) (:returns boolean) "Return whether `cell` is an unbound reference, assuming it lives at `address`." (ensure-boolean (and (cell-reference-p cell) (= (cell-value cell) address)))) (defun* matching-functor-p ((wam wam) (cell heap-cell) (functor symbol) (arity arity)) (:returns boolean) "Return whether `cell` is a functor cell of `functor`/`arity`." (ensure-boolean (and (cell-functor-p cell) (= arity (cell-functor-arity cell)) (eql functor (wam-functor-lookup wam (cell-functor-index cell)))))) (defun* deref ((wam wam) (address heap-index)) (:returns heap-index) "Dereference the address in the WAM to its eventual destination. If the address is a variable that's bound to something, that something will be looked up (recursively) and the address of whatever it's ultimately bound to will be returned. " (let ((cell (wam-heap-cell wam address))) (if (bound-reference-p address cell) (deref wam (cell-value cell)) address))) (defun* bind! ((wam wam) (address heap-index) (target heap-index)) "Bind the reference cell at `address` to `target`. The reference cell must be unbound to begin with. TODO: are we sure about this? `target` doesn't necessarily need to exist yet. TODO: this seems dangerous... " (assert (unbound-reference-p address (wam-heap-cell wam address)) () "Cannot bind address ~D because it is not an unbound reference." address) (setf (wam-heap-cell wam address) (make-cell-reference target))) (defun* fail! ((wam wam)) "Mark a failure in the WAM." (setf (wam-fail wam) t)) (defun* unify ((wam wam) (a1 heap-index) (a2 heap-index)) nil ) ;;;; Query Instructions (defun* %put-structure ((wam wam) (functor symbol) (arity arity) (register register-index)) (:returns :void) (setf (wam-register wam register) (nth-value 1 (push-new-structure! wam))) (push-new-functor! wam functor arity) (values)) (defun* %set-variable ((wam wam) (register register-index)) (:returns :void) (setf (wam-register wam register) (nth-value 1 (push-unbound-reference! wam))) (values)) (defun* %set-value ((wam wam) (register register-index)) (:returns :void) (wam-heap-push! wam (wam-register-cell wam register)) (values)) ;;;; Program Instructions (defun* %get-structure ((wam wam) (functor symbol) (arity arity) (register register-index)) (:returns :void) (let* ((addr (deref wam (wam-register wam register))) (cell (wam-heap-cell wam addr))) (cond ;; If the register points at a reference cell ((cell-reference-p cell) (bind! wam addr (wam-heap-pointer wam)) (push-new-structure! wam) (push-new-functor! wam functor arity) (setf (wam-mode wam) :write)) ;; If the register points at a structure cell ((cell-structure-p cell) (let* ((target-addr (cell-value cell)) (target (wam-heap-cell wam target-addr))) (if (matching-functor-p wam target functor arity) (progn (setf (wam-s wam) (1+ target-addr)) (setf (wam-mode wam) :read)) (fail! wam)))) (t (fail! wam)))) (values)) (defun* %unify-variable ((wam wam) (register register-index)) (:returns :void) (ecase (wam-mode wam) (:read (setf (wam-register wam register) (wam-s-cell wam))) (:write (setf (wam-register wam register) (nth-value 1 (push-unbound-reference! wam))))) (incf (wam-s wam)) (values)) (defun* %unify-value ((wam wam) (register register-index)) (:returns :void) (ecase (wam-mode wam) (:read (unify wam (cell-value (wam-register wam register)) (wam-s wam))) (:write (wam-heap-push! wam (wam-register wam register)))) (incf (wam-s wam)) (values))