changelog shortlog graph tags branches files raw help

Mercurial > core / changeset: add skel/core/print.lisp, wrap up obj/query init

changeset 574: 9e7d4393eac6
parent 573: f8b76ced5e2d
child 575: efb4a19ff530
author: Richard Westhaver <ellis@rwest.io>
date: Sat, 03 Aug 2024 00:59:36 -0400
files: lisp/lib/dat/dat.asd lisp/lib/obj/hash/chash.lisp lisp/lib/obj/hash/map.lisp lisp/lib/obj/hash/set.lisp lisp/lib/obj/list/clist.lisp lisp/lib/obj/pkg.lisp lisp/lib/obj/query.lisp lisp/lib/obj/tests.lisp lisp/lib/q/dql.lisp lisp/lib/skel/core/print.lisp lisp/lib/skel/skel.lisp
description: add skel/core/print.lisp, wrap up obj/query init
     1.1--- a/lisp/lib/dat/dat.asd	Thu Aug 01 21:21:07 2024 -0400
     1.2+++ b/lisp/lib/dat/dat.asd	Sat Aug 03 00:59:36 2024 -0400
     1.3@@ -1,6 +1,6 @@
     1.4 (defsystem :dat
     1.5   :description "Data formats"
     1.6-  :depends-on (:cl-ppcre :std :obj #+png :png :flexi-streams :io)
     1.7+  :depends-on (:cl-ppcre :std :obj #+png :png :flexi-streams :io :log)
     1.8   :version "0.1.0"
     1.9   :serial t
    1.10   :components ((:file "pkg")
     2.1--- a/lisp/lib/obj/hash/chash.lisp	Thu Aug 01 21:21:07 2024 -0400
     2.2+++ b/lisp/lib/obj/hash/chash.lisp	Sat Aug 03 00:59:36 2024 -0400
     2.3@@ -51,3 +51,70 @@
     2.4 
     2.5 ;;; Code:
     2.6 (in-package :obj/hash)
     2.7+
     2.8+(deftype solist-element-designator () `(member ,@(list :addr :fixnum :string)))
     2.9+
    2.10+(defun show-list (solist)
    2.11+  (let ((node (so-head solist)))
    2.12+    (loop (format t "~s~%" node)
    2.13+          (when (endp node) (return))
    2.14+          (setq node (%node-next node)))))
    2.15+
    2.16+(defun show-bin (solist i)
    2.17+  (let ((node (aref (car (so-bins solist)) i))
    2.18+        (bin-nbits (- +hash-nbits+ (cdr (so-bins solist))))
    2.19+        (count 0))
    2.20+    (flet ((bit-string (hash)
    2.21+             (let ((s (format nil " ~v,'0b" +hash-nbits+ hash)))
    2.22+               (replace s s :end1 bin-nbits :start2 1)
    2.23+               (setf (char s bin-nbits) #\.)
    2.24+               s)))
    2.25+      (cond
    2.26+        ((unbound-marker-p node)
    2.27+         (values 0 0))
    2.28+        (t
    2.29+         (let ((node node))
    2.30+           (loop (let ((next (get-next node)))
    2.31+                   (when (or (endp next) (evenp (node-hash next)))
    2.32+                     (return))
    2.33+                   (incf count)
    2.34+                   (setq node next))))
    2.35+         (format t " ~5d [~2d] = ~a" i count (bit-string (node-hash node)))
    2.36+         (loop (let ((next (get-next node)))
    2.37+                 (when (or (endp next) (evenp (node-hash next)))
    2.38+                   (return))
    2.39+                 (setq node next)
    2.40+                 (if (= count 1)
    2.41+                     (format t " ~a=~s"
    2.42+                             (bit-string (node-hash node)) (so-key node))
    2.43+                     (format t "~%              ~a=~s"
    2.44+                             (bit-string (node-hash node)) (so-key node)))))
    2.45+         (terpri)
    2.46+         (values 1 count))))))
    2.47+
    2.48+(defun show-bins (solist)
    2.49+  (let ((bins (car (so-bins solist)))
    2.50+        (bin-nbits (- +hash-nbits+ (cdr (so-bins solist))))
    2.51+        (n-occupied-bins 0)
    2.52+        (sum-chainlengths 0)
    2.53+        (max-chainlength 0))
    2.54+    (assert (= (length bins) (ash 1 bin-nbits)))
    2.55+    (format t "Bins (~d total, ~d leading bits):~%"
    2.56+            (length bins) bin-nbits)
    2.57+    (dotimes (i (length bins))
    2.58+      (multiple-value-bind (occupied count) (show-bin solist i)
    2.59+        (incf n-occupied-bins occupied)
    2.60+        (incf sum-chainlengths count)
    2.61+        (setq max-chainlength (max count max-chainlength))))
    2.62+    (let ((avg-chainlength (/ sum-chainlengths n-occupied-bins)))
    2.63+      (format t "~&Total ~D items, avg ~F items/bin~%"
    2.64+              (so-count solist) avg-chainlength)
    2.65+      (values max-chainlength (float avg-chainlength)))))
    2.66+
    2.67+(defun print-hashes (solist)
    2.68+  (do ((node (%node-next (so-head solist)) (%node-next node)))
    2.69+      ((endp node))
    2.70+    (format t "~16x~@[ ~s~]~%"
    2.71+            (node-hash node)
    2.72+            (if (so-key-node-p node) (type-of (so-key node))))))
    2.73+(sb-lockless:lfl-insert (sb-lockless:make-ordered-list :key-type 'fixnum) 5 'five)
     3.1--- a/lisp/lib/obj/hash/map.lisp	Thu Aug 01 21:21:07 2024 -0400
     3.2+++ b/lisp/lib/obj/hash/map.lisp	Sat Aug 03 00:59:36 2024 -0400
     3.3@@ -4,3 +4,15 @@
     3.4 
     3.5 ;;; Code:
     3.6 (in-package :obj/hash)
     3.7+
     3.8+;;; SOLIST
     3.9+
    3.10+;; Lockfree Maps
    3.11+
    3.12+(defmacro make-so-map (&optional (type :addr))
    3.13+  "Return a SOLIST map. Type may be either FIXNUM or STRING."
    3.14+  (declare (solist-element-designator type))
    3.15+  `(case ,type
    3.16+     (:fixnum ,(make-so-map/fixnum))
    3.17+     (:string ,(make-so-map/string))
    3.18+     (:addr ,(make-so-map/addr))))
     4.1--- a/lisp/lib/obj/hash/set.lisp	Thu Aug 01 21:21:07 2024 -0400
     4.2+++ b/lisp/lib/obj/hash/set.lisp	Sat Aug 03 00:59:36 2024 -0400
     4.3@@ -7,6 +7,14 @@
     4.4 
     4.5 ;;; SOLIST
     4.6 
     4.7-;; Split-Ordered Lists
     4.8+;; Lockfree hashsets
     4.9 
    4.10 ;; see file src/code/solist.lisp
    4.11+
    4.12+(defmacro make-so-set (&optional (type :addr))
    4.13+  "Return a SOLIST set. Type is of type SOLIST-ELEMENT-DESIGNATOR."
    4.14+  (declare (solist-element-designator type))
    4.15+  `(case ,type
    4.16+     (:fixnum ,(make-so-set/fixnum))
    4.17+     (:string ,(make-so-map/string))
    4.18+     (:addr ,(make-so-set/addr))))
     5.1--- a/lisp/lib/obj/list/clist.lisp	Thu Aug 01 21:21:07 2024 -0400
     5.2+++ b/lisp/lib/obj/list/clist.lisp	Sat Aug 03 00:59:36 2024 -0400
     5.3@@ -1,7 +1,7 @@
     5.4 ;;; obj/list/clist.lisp --- Concurrent Lists
     5.5 
     5.6 ;; https://timharris.uk/papers/2001-disc.pdf
     5.7-;; see sb-lockless - lfl=lockfree-list solist=splitorder-lists
     5.8+;; see sb-lockless - lfl=lockfree-list
     5.9 
    5.10 ;;; Code:
    5.11 (in-package :obj/list)
     6.1--- a/lisp/lib/obj/pkg.lisp	Thu Aug 01 21:21:07 2024 -0400
     6.2+++ b/lisp/lib/obj/pkg.lisp	Sat Aug 03 00:59:36 2024 -0400
     6.3@@ -23,8 +23,11 @@
     6.4 (defpackage :obj/hash
     6.5   (:nicknames :hash)
     6.6   (:use :cl :std)
     6.7+  (:shadowing-import-from :sb-lockless :endp)
     6.8   (:import-from :sb-lockless
     6.9    :make-so-map/fixnum :+hash-nbits+
    6.10+   :node-hash :%node-next
    6.11+   :unbound-marker-p
    6.12    :get-next :node-hash
    6.13    :so-head :so-bins
    6.14    :so-key :so-data
    6.15@@ -32,7 +35,8 @@
    6.16    :so-insert :so-delete
    6.17    :so-find :so-find/string
    6.18    :so-maplist :make-so-map/string
    6.19-   :make-so-set/string :make-so-map/addr :make-marked-ref)
    6.20+   :make-so-set/string :make-so-set/fixnum :make-so-map/addr :make-marked-ref
    6.21+   :make-so-set/addr)
    6.22   (:export 
    6.23    :*global-hasher*
    6.24    :*global-hash*
     7.1--- a/lisp/lib/obj/query.lisp	Thu Aug 01 21:21:07 2024 -0400
     7.2+++ b/lisp/lib/obj/query.lisp	Sat Aug 03 00:59:36 2024 -0400
     7.3@@ -21,6 +21,14 @@
     7.4 ;; - Backends :: The interface exposed to the underlying data sources -
     7.5 ;;   RocksDB, SQLite, etc.
     7.6 
     7.7+;;;; Refs
     7.8+
     7.9+;; https://gist.github.com/twitu/221c8349887cec0a83b395e4cbb492a7
    7.10+
    7.11+;; https://www1.columbia.edu/sec/acis/db2/db2d0/db2d0103.htm
    7.12+
    7.13+;; https://howqueryengineswork.com/
    7.14+
    7.15 ;;; Code:
    7.16 (in-package :obj/query)
    7.17 
    7.18@@ -353,9 +361,9 @@
    7.19 
    7.20 ;;;;; Scan
    7.21 (defclass scan-data (logical-plan)
    7.22-  ((path :type string)
    7.23-   (data-source :type data-source)
    7.24-   (projection :type (vector string))))
    7.25+  ((path :type string :initarg :path)
    7.26+   (data-source :type data-source :initarg :data-source)
    7.27+   (projection :type (vector string) :initarg :projection)))
    7.28 
    7.29 (defmethod derive-schema ((self scan-data))
    7.30   (let ((proj (slot-value self 'projection)))
    7.31@@ -368,25 +376,25 @@
    7.32 
    7.33 ;;;;; Projection
    7.34 (defclass projection (logical-plan)
    7.35-  ((input :type logical-plan)
    7.36-   (expr :type (vector logical-expression))))
    7.37+  ((input :type logical-plan :initarg :input)
    7.38+   (expr :type (vector logical-expression) :initarg :expr)))
    7.39 
    7.40 (defmethod schema ((self projection))
    7.41   (schema (slot-value self 'input)))
    7.42 
    7.43 ;;;;; Selection
    7.44 (defclass selection (logical-plan)
    7.45-  ((input :type logical-plan)
    7.46-   (expr :type logical-expression)))
    7.47+  ((input :type logical-plan :initarg :input)
    7.48+   (expr :type logical-expression :initarg :expr)))
    7.49 
    7.50 (defmethod schema ((self selection))
    7.51   (schema (slot-value self 'input)))
    7.52 
    7.53 ;;;;; Aggregate
    7.54 (defclass aggregate (logical-plan)
    7.55-  ((input :type logical-plan)
    7.56-   (group-expr :type (vector logical-expression))
    7.57-   (agg-expr :type (vector aggregate-expression))))
    7.58+  ((input :type logical-plan :initarg :input)
    7.59+   (group-expr :type (vector logical-expression) :initarg :group-expr)
    7.60+   (agg-expr :type (vector aggregate-expression) :initarg :agg-expr)))
    7.61 
    7.62 (defmethod schema ((self aggregate))
    7.63   (let ((input (slot-value self 'input))
    7.64@@ -398,7 +406,6 @@
    7.65     (make-schema :fields (coerce ret 'field-vector))))
    7.66 
    7.67 ;;; Physical Expression
    7.68-
    7.69 (defclass physical-expression (query-expression) ())
    7.70 
    7.71 (defclass literal-physical-expression (physical-expression) ())
    7.72@@ -439,6 +446,24 @@
    7.73   (declare (ignore self))
    7.74   (equal lhs rhs))
    7.75 
    7.76+(defclass neq-physical-expression (binary-physical-expression) ())
    7.77+
    7.78+(defmethod evaluate2 ((self neq-physical-expression) lhs rhs)
    7.79+  (declare (ignore self))
    7.80+  (equal lhs rhs))
    7.81+
    7.82+(defclass lt-physical-expression (binary-physical-expression) ())
    7.83+
    7.84+(defclass gt-physical-expression (binary-physical-expression) ())
    7.85+
    7.86+(defclass lteq-physical-expression (binary-physical-expression) ())
    7.87+
    7.88+(defclass gteq-physical-expression (binary-physical-expression) ())
    7.89+
    7.90+(defclass and-physical-expression (binary-physical-expression) ())
    7.91+
    7.92+(defclass or-physical-expression (binary-physical-expression) ())
    7.93+
    7.94 (defclass math-physical-expression (binary-physical-expression) ())
    7.95 
    7.96 (defmethod evaluate2 ((self math-physical-expression) (lhs column-vector) (rhs column-vector))
    7.97@@ -452,6 +477,24 @@
    7.98   (declare (ignore self))
    7.99   (+ lhs rhs))
   7.100 
   7.101+(defclass sub-physical-expression (math-expression) ())
   7.102+
   7.103+(defmethod evaluate2 ((self sub-physical-expression) lhs rhs)
   7.104+  (declare (ignore self))
   7.105+  (- lhs rhs))
   7.106+
   7.107+(defclass mult-physical-expression (math-expression) ())
   7.108+
   7.109+(defmethod evaluate2 ((self mult-physical-expression) lhs rhs)
   7.110+  (declare (ignore self))
   7.111+  (* lhs rhs))
   7.112+
   7.113+(defclass div-physical-expression (math-expression) ())
   7.114+
   7.115+(defmethod evaluate2 ((self div-physical-expression) lhs rhs)
   7.116+  (declare (ignore self))
   7.117+  (/ lhs rhs))
   7.118+
   7.119 (defclass accumulator ()
   7.120   ((value :initarg :value :accessor accumulator-value)))
   7.121 
   7.122@@ -523,7 +566,6 @@
   7.123          collect (make-record-batch :schema schema :fields (coerce filtered 'field-vector)))
   7.124    '(vector record-batch)))
   7.125 
   7.126-;; NOTE 2024-07-10: 
   7.127 (defgeneric filter (self columns selection)
   7.128   (:method ((self selection-exec) (columns column-vector) (selection simple-bit-vector))
   7.129     (coerce
   7.130@@ -533,9 +575,9 @@
   7.131      'field-vector)))
   7.132 
   7.133 (defclass hash-aggregate-exec (physical-plan)
   7.134-  ((input :type physical-plan)
   7.135-   (group-expr :type (vector physical-plan))
   7.136-   (agg-expr :type (vector aggregate-physical-expression))))
   7.137+  ((input :type physical-plan :initarg :input)
   7.138+   (group-expr :type (vector physical-plan) :initarg :group-expr)
   7.139+   (agg-expr :type (vector aggregate-physical-expression) :initarg :agg-expr)))
   7.140 
   7.141 (defmethod execute ((self hash-aggregate-exec))
   7.142   (coerce 
   7.143@@ -589,7 +631,6 @@
   7.144 
   7.145 (defclass query-planner () ())
   7.146 
   7.147-;; these generics 
   7.148 (defgeneric make-physical-expression (expr input)
   7.149   (:documentation "Translate logical expression EXPR and logical plan INPUT
   7.150   into a physical expression.")
   7.151@@ -607,18 +648,17 @@
   7.152           (r (make-physical-expression (rhs expr) input)))
   7.153       (etypecase expr
   7.154         (eq-expression (make-instance 'eq-physical-expression :lhs l :rhs r))
   7.155-        ;; (neq-expression (make-instance 'neq-physical-expression :lhs l :rhs r))
   7.156-        ;; (gt-expression)
   7.157-        ;; (gteq-expression)
   7.158-        ;; (lt-expression)
   7.159-        ;; (lteq-expression)
   7.160-        ;; (and-expression)
   7.161-        ;; (or-expression)
   7.162+        (neq-expression (make-instance 'neq-physical-expression :lhs l :rhs r))
   7.163+        (gt-expression (make-instance 'gt-physical-expression :lhs l :rhs r))
   7.164+        (gteq-expression (make-instance 'gteq-physical-expression :lhs l :rhs r))
   7.165+        (lt-expression (make-instance 'lt-physical-expression :lhs l :rhs r))
   7.166+        (lteq-expression (make-instance 'lteq-physical-expression :lhs l :rhs r))
   7.167+        (and-expression (make-instance 'and-physical-expression :lhs l :rhs r))
   7.168+        (or-expression (make-instance 'or-physical-expression :lhs l :rhs r))
   7.169         (add-expression (make-instance 'add-physical-expresion :lhs l :rhs r))
   7.170-        ;; (sub-expression)
   7.171-        ;; (mult-expression)
   7.172-        ;; (div-expression)
   7.173-        ))))
   7.174+        (sub-expression (make-instance 'sub-physical-expression :lhs l :rhs r))
   7.175+        (mult-expression (make-instance 'mult-physical-expression :lhs l :rhs r))
   7.176+        (div-expression (make-instance 'div-physical-expression :lhs l :rhs r))))))
   7.177 
   7.178 (defgeneric make-physical-plan (plan)
   7.179   (:documentation "Create a physical plan from logical PLAN.")
   7.180@@ -639,8 +679,42 @@
   7.181       (selection (make-instance 'selection-exec
   7.182                    :input (make-physical-plan (slot-value plan 'input))
   7.183                    :expr (make-physical-expression (slot-value plan 'expr) (slot-value plan 'input))))
   7.184-      ;; TODO 2024-07-10: 
   7.185-      (aggregate (make-instance 'hash-aggregate-exec)))))
   7.186+      (aggregate (make-instance 'hash-aggregate-exec
   7.187+                   :input (make-physical-plan (slot-value plan 'input))
   7.188+                   :group-expr (make-physical-expression (slot-value plan 'group-expr) (slot-value plan 'input))
   7.189+                   :agg-expr (make-physical-expression (slot-value plan 'agg-expr) (slot-value plan 'input)))))))
   7.190+
   7.191+;;; Joins
   7.192+
   7.193+;;  TODO 2024-08-02: 
   7.194+
   7.195+;; inner-join
   7.196+
   7.197+;; outer-join left-outer-join right-outer-join
   7.198+
   7.199+;; semi-join
   7.200+
   7.201+;; anti-join
   7.202+
   7.203+;; cross-join
   7.204+
   7.205+;;; Subqueries
   7.206+
   7.207+;;  TODO 2024-08-02: 
   7.208+
   7.209+;; subquery
   7.210+
   7.211+;; correlated-subquery
   7.212+
   7.213+;; SELECT id, name, (SELECT count(*) FROM orders WHERE customer_id = customer.id) AS num_orders FROM customers
   7.214+
   7.215+;; uncorrelated-subquery
   7.216+
   7.217+;; scalar-subquery
   7.218+
   7.219+;; SELECT * FROM orders WHERE total > (SELECT avg(total) FROM sales WHERE customer_state = 'CA')
   7.220+
   7.221+;; NOTE 2024-08-02: EXISTS, IN, NOT EXISTS, and NOT IN are also subqueries
   7.222 
   7.223 ;;; Optimizer
   7.224 
   7.225@@ -654,7 +728,56 @@
   7.226 ;; TODO 2024-07-10: 
   7.227 (defclass query-optimizer () ())
   7.228 
   7.229-(defgeneric optimize-query (self &key &allow-other-keys))
   7.230+(defstruct (query-vop (:constructor make-query-vop (info)))
   7.231+  (info nil))
   7.232+
   7.233+(defgeneric optimize-query (self plan))
   7.234+
   7.235+;; Projection Pushdown
   7.236+(defun extract-columns (expr input &optional accum)
   7.237+  (etypecase expr
   7.238+    (array-index (accumulate accum (field (fields (schema input)) expr)))
   7.239+    (column-expression (accumulate accum (column-name expr)))
   7.240+    (binary-expression
   7.241+     (extract-columns (lhs expr) input accum)
   7.242+     (extract-columns (rhs expr) input accum))
   7.243+    (alias-expression (extract-columns (slot-value expr 'expr) input accum))
   7.244+    ;; cast-expression
   7.245+    (literal-expression nil)))
   7.246+
   7.247+(defun extract-columns* (exprs input &optional accum)
   7.248+  (mapcar (lambda (x) (extract-columns x input accum)) exprs))
   7.249+
   7.250+(defclass projection-pushdown-optimizer (query-optimizer) ())
   7.251+
   7.252+(defun %pushdown (plan &optional column-names)
   7.253+  (declare (logical-plan plan))
   7.254+  (etypecase plan
   7.255+    (projection
   7.256+     (extract-columns (slot-value plan 'expr) column-names)
   7.257+     (let ((input (%pushdown (slot-value plan 'input) column-names)))
   7.258+       (make-instance 'projection :input input :expr (slot-value plan 'expr))))
   7.259+    (selection
   7.260+     (extract-columns (slot-value plan 'expr) column-names)
   7.261+     (let ((input (%pushdown (slot-value plan 'input) column-names)))
   7.262+       (make-instance 'selection :input input :expr (slot-value plan 'expr))))
   7.263+    (aggregate
   7.264+     (extract-columns (slot-value plan 'group-expr) column-names)
   7.265+     (extract-columns*
   7.266+      (loop for x across (slot-value plan 'agg-expr) collect (slot-value x 'input))
   7.267+      column-names)
   7.268+     (let ((input (%pushdown (slot-value plan 'input) column-names)))
   7.269+       (make-instance 'aggregate
   7.270+         :input input
   7.271+         :group-expr (slot-value plan 'group-expr)
   7.272+         :agg-expr (slot-value plan 'agg-expr))))
   7.273+    (scan-data (make-instance 'scan-data
   7.274+                 :path (slot-value plan 'name)
   7.275+                 :data-source (slot-value plan 'data-source)
   7.276+                 :projection column-names)))) ;; maybe sort here?
   7.277+
   7.278+(defmethod optimize-query ((self projection-pushdown-optimizer) (plan logical-plan))
   7.279+  (%pushdown plan))
   7.280 
   7.281 ;;; Query
   7.282 (defclass query () ())
     8.1--- a/lisp/lib/obj/tests.lisp	Thu Aug 01 21:21:07 2024 -0400
     8.2+++ b/lisp/lib/obj/tests.lisp	Sat Aug 03 00:59:36 2024 -0400
     8.3@@ -250,6 +250,9 @@
     8.4 
     8.5 (defclass bogus-data-source (data-source) ((db :initform nil :initarg :db)))
     8.6 
     8.7-(deftest query-simple-hard ()
     8.8+(defvar *basic-query* "SELECT * FROM employee WHERE state = 'CT'")
     8.9+
    8.10+(deftest query-basic ()
    8.11   "Test the simple query `SELECT * FROM employee WHERE state = 'CT'` by manually
    8.12-building a query-plan.")
    8.13+building a query-plan."
    8.14+  (make-query *basic-query*))
     9.1--- a/lisp/lib/q/dql.lisp	Thu Aug 01 21:21:07 2024 -0400
     9.2+++ b/lisp/lib/q/dql.lisp	Sat Aug 03 00:59:36 2024 -0400
     9.3@@ -23,13 +23,42 @@
     9.4 
     9.5 ;; The WAM compiler is a bit too much to understand let alone implement at
     9.6 ;; this stage. The design of this package will be much simpler and optimized
     9.7-;; for compatibility with Lisp.
     9.8+;; for compatibility with Lisp Objects.
     9.9+
    9.10+;; I think we can get quite far, with a bit of clever hacking and some good
    9.11+;; macros.
    9.12+
    9.13+;;;; Refs
    9.14 
    9.15-;; I think we can get quite far 
    9.16+;; https://franz.com/support/documentation/11.0/prolog.html
    9.17+
    9.18+;; https://github.com/wmannis/cl-gambol
    9.19+
    9.20+;; https://norvig.com/paip/README.html
    9.21+
    9.22+;; https://en.wikipedia.org/wiki/Negation_as_failure
    9.23 
    9.24 ;;; Code:
    9.25 (in-package :q/dql)
    9.26 
    9.27+;;; Vars
    9.28+
    9.29+(declaim (fixnum *lips*))
    9.30+(defvar *lips* 0
    9.31+  "Count of logical inferences performed.")
    9.32+
    9.33+;; from GAMBOL
    9.34+(defvar *interactive*           t "true iff interacting with user")
    9.35+(defvar *auto-backtrack*      nil "return all solutions if true")
    9.36+(defvar *last-continuation*   nil "saved state of the system")
    9.37+(defvar *trail*               nil "the trail, for backtracking")
    9.38+(defvar *x-env*               nil "env for goals")
    9.39+(defvar *y-env*               nil "env for rules")
    9.40+(defvar *top-level-envs*      nil "saves top-level environments")
    9.41+(defvar *top-level-vars*      nil "saves top-level variable names")
    9.42+(defvar *num-slots*            -1 "number of logical variables in a query")
    9.43+(defvar *rules*  (make-hash-table) "hash table for prolog rule heads")
    9.44+
    9.45 ;;; Conditions
    9.46 (define-condition dql-error (error) ())
    9.47 
    9.48@@ -38,8 +67,21 @@
    9.49 (defun simple-dql-error (ctrl &rest args)
    9.50   (error 'simpl-dql-error :format-control ctrl :format-arguments args))
    9.51 
    9.52+;;; CLOS
    9.53 (defclass dql-query (query) ())
    9.54 
    9.55 (defclass dql-data-source (data-source) ()
    9.56   (:documentation "Data source which can be used withing DQL expressions."))
    9.57 
    9.58+;;; Prolog Semantics
    9.59+
    9.60+;; NOTE 2024-08-03: we're loosely following along with CL-GAMBOL, but sticking
    9.61+;; with defstructs instead of vectors for the most part. I'm willing to pay
    9.62+;; the immediate cost of not vectorizing in hopes that the fact that structs
    9.63+;; are vector-backed and multi-threaded contexts exist will minimize the
    9.64+;; effect.
    9.65+
    9.66+;;; Macros
    9.67+(defmacro ?- (&body clauses))
    9.68+
    9.69+(defmacro *- (head &body body))
    10.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2+++ b/lisp/lib/skel/core/print.lisp	Sat Aug 03 00:59:36 2024 -0400
    10.3@@ -0,0 +1,28 @@
    10.4+;;; print.lisp --- Skel Printer
    10.5+
    10.6+;; SK-PRINT
    10.7+
    10.8+;;; Commentary:
    10.9+
   10.10+;; SK-PRINT is the top-level interface, and dispatches on all sorts of SKEL
   10.11+;; objects. The output is different than the PRINT-OBJECT methods, which are
   10.12+;; implemented in the SKEL/CORE/OBJ package.
   10.13+
   10.14+;; SK-PRINT is the 'external print' representation, which is structured, akin
   10.15+;; to PPRINT - while PRINT-OBJECT is the 'internal print' and unstructured
   10.16+;; representation.
   10.17+
   10.18+;; All printer parameters are dynamic and dispatch occurs in the same manner
   10.19+;; as the standard Lisp Printer. Additional parameters may be provided in the
   10.20+;; future.
   10.21+
   10.22+;;; Code:
   10.23+(in-package :skel/core/print)
   10.24+
   10.25+;; sb-pretty::*standard-pprint-dispatch-table*
   10.26+;; *readtable*
   10.27+
   10.28+(sb-ext:defglobal *sk-print-dispatch-table* (sb-pretty::make-pprint-dispatch-table #() nil nil))
   10.29+
   10.30+(defmethod sk-print ((self skel))
   10.31+  (pprint (cons (keywordicate (class-name (class-of self))) (format-sxhash (obj/id:id self)))))