Skip to content

Instantly share code, notes, and snippets.

@joinr
Created August 30, 2018 17:40
Show Gist options
  • Save joinr/68ba0f0e9a690f69c3e23404c8815a7a to your computer and use it in GitHub Desktop.
Save joinr/68ba0f0e9a690f69c3e23404c8815a7a to your computer and use it in GitHub Desktop.
A simple example of providing reader and macro support for custom data structures, to include allowing them as binding forms.
;;util function to help with bindings
(defun partition (n l)
(do ((remaining l (setf remaining (subseq remaining 2)))
(acc (list)))
((null remaining) (nreverse acc))
(let ((nxt (subseq remaining 0 2)))
(if (= (length nxt) n)
(push nxt acc)
(setf remaining nil)))))
;;a dumb struct to wrap a list. solely for custom
;;read/print
(defstruct custom-list (contents))
;;custom printing for {the list contents}
(defmethod print-object ((obj custom-list) stream)
(format stream "{~{~s~^ ~}}" (custom-list-contents obj)))
;;dumb constructor for our magic lists.
(defun magic-list (&rest args)
(make-custom-list :contents args))
;;a variant of let* that expects bindings in the form
;;of (magic-list ....) that doesn't do any checking but should.
(defmacro magic-let* (mexpr &rest body)
(let ((binds (rest mexpr)))
`(let* (,@ (partition 2 binds)) ,@body)))
(defun |magic-reader| (stream char)
"A reader macro that allows us to define magic lists."
(declare (ignore char))
`(magic-list ,@(read-delimited-list #\} stream t)))
;;reader support, will mutate the read-table.
(progn (pprint "I'm about to jack up the read table for {, apologies!")
(set-macro-character #\{ #'|magic-reader|)
(set-syntax-from-char #\} #\) ))
;;supported quoted magic lists, needs to be extended
;;for quoting children. that's an exercise for the reader.
(defun lame-quoted-read (stream char)
(declare (ignore char))
(let ((res (read stream t nil t)))
(cond ((atom res) `(quote ,res))
((eq (first res) 'magic-list)
(apply #'magic-list `,(rest res)))
(t `(quote ,res)))))
;;reader support for new quote, mutates the read-table.
(progn (pprint
"I'm about to jack up the read-table to handle '{}, apologies!")
(set-macro-character #\'
#'lame-quoted-read))
;;demos.
;;CL-USER>(magic-let*
;; {x 2
;; y '{x x}}
;; {x y})
;;{2 {X X}}
;;CL-USER> (magic-let* {x 2
;; y (list 1 2 x)}
;; {x y})
;;{2 (1 2 2)}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment