Created
October 16, 2020 22:26
-
-
Save commander-trashdin/4b547fdfba08c1de0a795917b29698a3 to your computer and use it in GitHub Desktop.
Let's force people to write docs.
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
| (defparameter *type-policy* :docs) | |
| (defparameter *doc-info* (make-hash-table :test #'equal)) | |
| (defun validate-ftype (ftype) | |
| (labels ((check-symbols (list) | |
| (every (lambda (token) | |
| (if (atom token) | |
| (symbolp token) | |
| (check-symbols token))) | |
| list))) | |
| (when (and ftype (listp ftype)) | |
| (when (or (eql (car ftype) 'function) | |
| (eql (car ftype) '->)) | |
| (setf (car ftype) 'function) | |
| (when (check-symbols ftype) | |
| (when (listp (second ftype)) | |
| (when (= 3 (length ftype)) | |
| ftype))))))) | |
| (defun get-docs (name &optional (stream *standard-output*)) | |
| (if (gethash name *doc-info*) | |
| (destructuring-bind (_ type __ documentation) (gethash name *doc-info*) | |
| (declare (ignore _ __)) | |
| (format stream "Type:~%->~% ~a~% ~a~%" (second type) (third type)) | |
| (format stream "Documentation:~%~a~%" documentation) | |
| (values type documentation)) | |
| (error 'simple-error :format-control "Function is not known to defun/doc."))) | |
| (define-condition malformed-type (warning) | |
| ((function-name | |
| :initarg :name | |
| :reader name) | |
| (function-type | |
| :initarg :type | |
| :reader function-type)) | |
| (:report (lambda (condition stream) | |
| (format stream "The functional type ~a provided for ~a is not a valid ftype specifier." | |
| (function-type condition) (name condition))))) | |
| (define-condition no-type (style-warning) | |
| ((function-name | |
| :initarg :name | |
| :reader name)) | |
| (:report (lambda (condition stream) | |
| (format stream "No type was provided for function ~a. Please consider adding it for clarity." | |
| (name condition))))) | |
| (define-condition bad-docs (warning) | |
| ((function-docs | |
| :initarg :doc | |
| :reader function-doc)) | |
| (:report (lambda (condition stream) | |
| (if (function-doc condition) | |
| (cond ((not (stringp (function-doc condition))) | |
| (format stream "Only string documentation is allowed.")) | |
| ((>= 15 (length (function-doc condition))) | |
| (format stream "Such short documentation probably will not be enough for user. Consider a more detailed description."))) | |
| (format stream "No documentation is provided. Consider adding it."))))) | |
| (defmacro defun/doc (name lambda-list body &key type documentation) | |
| (if type | |
| (let ((transformed-type (validate-ftype type))) | |
| (if transformed-type | |
| (setf type transformed-type) | |
| (warn 'malformed-type :name name :type type))) | |
| (warn 'no-type :name name)) | |
| (unless (and documentation (stringp documentation) (< 15 (length documentation))) | |
| (warn 'bad-docs :doc documentation)) | |
| (unless documentation | |
| (setf documentation "No further documentation has been provided")) | |
| (setf (gethash name *doc-info*) (list :type type :documentation documentation)) | |
| (ecase *type-policy* | |
| (:declare | |
| `(progn | |
| (declaim ,type) | |
| (defun ,name ,lambda-list | |
| ,documentation | |
| ,@body))) | |
| (:docs | |
| `(defun ,name ,lambda-list | |
| ,documentation | |
| ,@body)))) | |
| (defun/doc add (a b) | |
| ((+ a b)) | |
| :documentation "Literally just adds two numbers, that's it" | |
| :type (-> (number number) (values number &optional))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment