Advertisement
Guest User

Untitled

a guest
Dec 28th, 2017
262
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lisp 4.13 KB | None | 0 0
  1. (defun command-read-arguments ()
  2.   "Read the arguments following the expression that has just been read and that is being evaluated."
  3.   (flet ((read-arguments (stream)
  4.            (loop :for argument := (read stream nil stream)
  5.                  :until (eq argument stream)
  6.                  :collect argument)))
  7.     (if (and (member :swank *features*)
  8.              (find-package "SWANK")
  9.              (eq :external (nth-value 1 (find-symbol "*ARGUMENT-STREAM*" "SWANK")))
  10.              (streamp (symbol-value (intern "*ARGUMENT-STREAM*" "SWANK"))))
  11.         (read-arguments (symbol-value (intern "*ARGUMENT-STREAM*" "SWANK")))
  12.         (with-input-from-string (stream  (if (listen *standard-input*)
  13.                                              (read-line *standard-input*)
  14.                                              ""))
  15.           (read-arguments stream)))))
  16.  
  17. (defun call-command (command)
  18.   "
  19. DO:     Call the command with the arguments read from the following line.
  20. RETURN: No value.
  21. "
  22.   (apply command (command-read-arguments))
  23.   (values))
  24.  
  25. (defvar *commands* '()
  26.   "List of commands, with their lambda-list and docstring.")
  27.  
  28. (defmacro command-error-handling (&body body)
  29.   `(handler-case
  30.        (progn ,@body)
  31.      (error (err)
  32.        (format *error-output* "~&~A~%" err))))
  33.  
  34. (defmacro define-command (name (&rest lambda-list) &body docstring-declarations-and-body)
  35.   "
  36. DO:         Define a REPL command that can be invoked by name, without
  37.            surrounding it with parentheses.
  38.  
  39. NOTE:       Commands are defined as functions, associated with a
  40.            symbol-macro expanding to a call-command call.
  41.            Call-command will parse the rest of the line  as arguments
  42.            for the command.  Errors are handled and printed.  No
  43.            value is returned.  Commands must print their results.
  44.  
  45. EXAMPLE:
  46.            (define-command cmdt (&rest arguments)
  47.              (prin1 (append arguments arguments))
  48.              (terpri))
  49.  
  50.            cl-user> cmdt 1 2 3
  51.            (1 2 3 1 2 3)
  52.            ; No value
  53.            cl-user>
  54. "
  55.   (multiple-value-bind (docstrings declarations body)
  56.       (parse-body :lambda docstring-declarations-and-body)
  57.     `(progn
  58.        (setf *commands* (cons (list ',name ',lambda-list ',(car docstrings))
  59.                               (delete ',name *commands* :key (function first))))
  60.        (defun ,name ,lambda-list
  61.          ,@docstrings ,@declarations
  62.          (command-error-handling ,@body))
  63.        (define-symbol-macro ,name (call-command ',name)))))
  64.  
  65. (defun fmt-lambda-list (stream lambda-list at colon  &rest parameters)
  66.   "Formats a lambda list using [] for optional and parameters."
  67.   (declare (ignore at colon parameters))
  68.   (let ((lh (make-help (parse-lambda-list lambda-list :ordinary))))
  69.     (write-string
  70.      (mapconcat (lambda (p)
  71.                   (case (car p)
  72.                     (:key (let ((*print-circle* nil))  (format nil "[:~A ~:*~A]" (cdr p))))
  73.                     (otherwise (cdr p))))
  74.                 (if (and (find :key  lh :key (function car))
  75.                          (find :rest lh :key (function car)))
  76.                     (delete :rest lh :key (function car))
  77.                     lh)
  78.                 " ")
  79.      stream)))
  80.  
  81. (define-command help (&optional (command nil commandp))
  82.   "With a command argument, prints the docstring of the specified command.
  83. without, lists all the commands with their docstrings."
  84.   (flet ((format-help (help)
  85.            (format t "~%~S~@[ ~/com.informatimago.pjb:fmt-lambda-list/~]~%~@[~A~%~]"
  86.                    (first help) (second help)
  87.                    (mapconcat (lambda (line) (format nil "  ~A" line))
  88.                               (split-string (third help) #(#\newline))
  89.                               (coerce #(#\newline) 'string)))))
  90.     (if commandp
  91.         (let ((help (find command *commands* :key (function first) :test (function string-equal))))
  92.           (if help
  93.               (format-help help)
  94.               (format t "~%No help for ~S~%" command)))
  95.         (dolist (help (setf *commands* (sort *commands* (function string<) :key (function first))))
  96.           (format-help help))))
  97.   (terpri))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement