(uiop:define-package ambrevar/syntax (:documentation "Syntax table.") (:use #:common-lisp) (:use #:trivia) (:import-from #:ambrevar/shell) (:import-from #:ambrevar/file) (:import-from #:serapeum #:export-always)) (in-package ambrevar/syntax) (eval-when (:compile-toplevel :load-toplevel :execute) (trivial-package-local-nicknames:add-package-local-nickname :alex :alexandria) (trivial-package-local-nicknames:add-package-local-nickname :sera :serapeum)) (defun read-until (stream delimiter) "Return the string read until DELIMITER." (concatenate 'string (loop :for char = (read-char stream nil :eof) :while (and (not (eq char :eof)) (not (char= char delimiter))) :collect char))) (defun cmd-reader (stream char1 char2) (declare (ignore char1 char2)) (cmd:cmd (read-until stream #\newline))) (defun $cmd-reader (stream char1 char2) (declare (ignore char1 char2)) (cmd:$cmd (read-until stream #\newline))) (defun sh-reader (stream char1 char2) (declare (ignore char1 char2)) (let ((next-char (read-char stream nil :eof))) (str:string-case (string next-char) ("#" (ambrevar/shell:sh (read-until stream #\newline))) ("!" (ambrevar/shell:sh (read-until stream #\newline))) ("$" (ambrevar/shell:$sh (read-until stream #\newline))) (otherwise (ambrevar/shell:sh (str:concat (string next-char) (read-until stream #\newline))))))) (defun file-reader (stream char1 char2) (declare (ignore char1 char2)) (read-until stream #\") (ambrevar/file:file (read-until stream #\"))) (export-always 'syntax) (named-readtables:defreadtable syntax (:merge :standard) (:dispatch-macro-char #\# #\# #'sh-reader) (:dispatch-macro-char #\# #\$ #'$cmd-reader) (:dispatch-macro-char #\# #\! #'cmd-reader) (:dispatch-macro-char #\# #\? #'interpol:interpol-reader) (:dispatch-macro-char #\# #\f #'file-reader))