git.fiddlerwoaroof.com
Raw Blame History
(in-package :edn)

(defgeneric synthesize (implementation args))
(defgeneric synthesize-compound (implementation discriminator args))
(defgeneric synthesize-tag (implementation tag args))

(defun parse (input &optional (realizer 'fset))
  (synthesize realizer
              (read-edn input)))


(defmethod synthesize ((implementation symbol) discriminator)
  (synthesize (make-instance implementation) discriminator))

(defmethod synthesize (implementation thing)
  (typecase thing
    (list (synthesize-compound implementation (car thing) (cdr thing)))
    (t thing)))

(defmethod synthesize-compound (implementation (discriminator (eql :keyword)) args)
  (destructuring-bind (ns name) args
    (alexandria:make-keyword (if ns
                                 (format nil "~a/~a" ns name)
                                 (format nil "~a" name)))))

(defmethod synthesize-compound (implementation (discriminator (eql :string)) args)
  (car args))

(defmethod synthesize-compound (implementation (discriminator (eql :symbol)) args)
  (destructuring-bind (ns name) args
    (make-symbol (if ns
                     (format nil "~a/~a" ns name)
                     (format nil "~a" name)))))

(defmethod synthesize-compound (implementation (discriminator (eql :tagged)) args)
  (destructuring-bind (sym obj) args
    (list :tagged
          (synthesize-compound implementation (car sym) (cdr sym))
          (synthesize implementation obj))))

(defmethod synthesize-compound (implementation (discriminator (eql :character)) args)
  (car args))

(defmethod synthesize-compound (implementation (discriminator (eql :tagged)) args)
  (destructuring-bind (sym obj) args
    (let ((tag (synthesize-compound implementation (car sym) (cdr sym))))
      (alexandria:switch ((symbol-name tag) :test 'string-equal)
        ("inst" (local-time:parse-rfc3339-timestring (synthesize implementation obj)))
        ("uuid" (uuid:make-uuid-from-string (synthesize implementation obj)))
        (t (let ((synthesized-object (synthesize implementation obj)))
             (fw.lu:if-let* ((tag-keyword (alexandria:make-keyword
                                           (string-upcase
                                            (symbol-name tag))))
                             (methods (compute-applicable-methods
                                       #'synthesize-tag
                                       (list implementation tag-keyword synthesized-object))))
               
               (synthesize-tag implementation tag-keyword synthesized-object)
               (list :tagged tag
                     synthesized-object))))))))