commit 890ea7f6c2894ae370964aff70f3a1549fe5e87b Spenser Truex <truex@equwal.com> 2023-05-27 18:31:25 -0300 blah v1
blah.lisp | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+)
diff --git a/blah.lisp b/blah.lisp new file mode 100644 index 0000000..787b0ff --- /dev/null +++ b/blah.lisp @@ -0,0 +1,63 @@ +(defun blah (stream template &rest args) + (multiple-value-bind (format keys) (parse-blah template) + (apply #'format stream format (loop for key in keys + collect (getf args key))))) + +(define-compiler-macro blah (&whole whole stream template &rest args) + (cond ((stringp template) ;constantp? + `(funcall (blaher ,template) ,stream ,@args)) + (t + whole))) + +(defmacro blaher (template) + (multiple-value-bind (format keys) (parse-blah template) + (let ((stream (gensym "STREAM.")) + (args (gensym "ARGS.")) + (params (mapcar #'(lambda (x) (list x (gensym))) + (remove-duplicates keys)))) + `(lambda (,stream &key ,@(mapcar #'list params)) + (format ,stream ,format ,@(mapcar #'(lambda (key) + (cadr (assoc key params))) + keys)))))) + +(defun parse-blah (string &optional (start 0) (end (length string))) + (labels ((format-escape (string) + (with-output-to-string (bag) + (loop for c across string do + (when (eql c #\~) (write-char c bag)) + (write-char c bag))))) + (let* ((p1 (search "{{" string :start2 start :end2 end)) + (p2 (and p1 (search "}}" string :start2 p1 :end2 end)))) + (cond ((and p1 p2) + (multiple-value-bind (format args) + (parse-blah string (+ p2 2) end) + (values (format nil "~A~~A~A" + (format-escape (subseq string start p1)) + format) + (cons (intern (string-upcase + (subseq string (+ p1 2) p2)) + :keyword) + args)))) + (t + (values (format-escape (subseq string start end)) nil)))))) + +;; (blah nil "Hi {{person}}!" :person "Joe") => "Hi Joe!" + +;; (blah nil "Hi {{person}}! I am {{computer-assistant}}, here to help you, {{person}}, with all of your problems." +;; :person "Fred" +;; :computer-assistant "Eliza") + +;; => "Hi Fred! I am Eliza, here to help you, Fred, with all of your problems." + +;; (blaher "Hi {{person}}! I am {{computer-assistant}}, here to help you, {{person}}, with all of your problems.") + +;; macro expands to: + +;; (LAMBDA (#:STREAM.5900 &KEY ((:COMPUTER-ASSISTANT #:G5902)) +;; ((:PERSON #:G5903))) +;; (FORMAT #:STREAM.5900 +;; "Hi ~A! I am ~A, here to help you, ~A, with all of your problems." +;; #:G5903 +;; #:G5902 +;; #:G5903)) +