Created
August 30, 2018 17:40
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;;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