;;;; sam-d.lisp
(defpackage sam-d (:use cl cl-user))
(in-package sam-d)

(defclass ext-proc ()
 ((2way :accessor 2way)
  (proc :accessor proc)))

(defclass sam-d (ext-proc)
 ((2sam :initform (list '|:-(|) :accessor 2sam)
  (fsam :initform (list '|:-)|) :accessor fsam)
  (dirty :initform nil :accessor dirty)))

(defmethod shared-initialize :after ((obj sam-d) names &rest args)
 (declare (ignore unused names args))
 (multiple-value-bind (2way unused proc)
                      (ext:run-program "9" '("sam" "-d") :wait nil)
                      (setf (slot-value obj '2way) 2way
                            (slot-value obj 'proc) proc)))
(defmethod wstrm ((obj sam-d))
 (two-way-stream-output-stream (2way obj)))
(defmethod rstrm ((obj sam-d))
 (two-way-stream-input-stream (2way obj)))

(defvar *sam-d* (make-instance 'sam-d))

(defun fin ()
 (format (wstrm *sam-d*) "=~%")
 (force-output (wstrm *sam-d*))
 (loop for line = (read-line (rstrm *sam-d*))
       do (format t "~a~%" line) while (not (search "; #" line)))
 (when (listen (rstrm *sam-d*))
   (loop for ch = (read-char-no-hang (rstrm *sam-d*))
         while ch do (princ ch))))
(define-symbol-macro % (fin))

(defun sam (say)
 (format (wstrm *sam-d*) "~a~%" say)
 (force-output (wstrm *sam-d*)))

(defun sam-reader (s c n)
 (declare (ignore c n))
 `(progn (sam (coerce
               ',(loop
                  for ch = (read-char s)
                  while (not (and (char= ch #\#)
                                  (char= (peek-char nil s) #\])))
                  collecting ch
                  finally (read-char-no-hang s))
               'string))
         (fin)))

(set-dispatch-macro-character #\# #\[ #'sam-reader)

(defmacro 2s (&body body)
 `(with-input-from-string (s (format nil "#[~@{~a~^ ~}#]" ,@body))
                          (eval (read s))))

(defun rs (start end)
 (with-output-to-string (*standard-output*)
                        (sam (format nil "~a,~a" start end))))