[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/parseedn e70ca8d03a 2/3: Merge pull request #11 from r0man
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/parseedn e70ca8d03a 2/3: Merge pull request #11 from r0man/default-data-reader |
Date: |
Mon, 7 Feb 2022 08:58:46 -0500 (EST) |
branch: elpa/parseedn
commit e70ca8d03a314f97e4f49b7d6098fa565742e217
Merge: e5ba280d1f c94ac06b53
Author: Arne Brasseur <arne@arnebrasseur.net>
Commit: GitHub <noreply@github.com>
Merge pull request #11 from r0man/default-data-reader
Default data reader function and tagged literals
---
parseedn.el | 32 ++++++++++++++++++++++++++++----
test/parseedn-test-data.el | 9 +++++++++
test/parseedn-test.el | 19 ++++++++++++++++++-
3 files changed, 55 insertions(+), 5 deletions(-)
diff --git a/parseedn.el b/parseedn.el
index a1cecbf99c..239f56a60c 100644
--- a/parseedn.el
+++ b/parseedn.el
@@ -65,6 +65,23 @@ is not recommended you change this variable, as this globally
changes the behavior of the EDN reader. Instead pass your own
handlers as an optional argument to the reader functions.")
+(defun parseedn-tagged-literal (tag form)
+ "Construct a data representation of a tagged literal from TAG and FORM."
+ (list 'edn-tagged-literal tag form))
+
+(defvar parseedn-default-data-reader-fn nil
+ "The default tagged literal reader function.
+
+When no data reader is found for a tag and
+`parseedn-default-data-reader-fn' is non-nil, it will be called
+with two arguments, the tag and the value. If
+`parseedn-default-data-reader-fn' is nil (the default), an
+exception will be thrown for the unknown tag.
+
+The default data reader can also be provided via the tagged
+reader options registered under the :default keyword when calling
+the reader functions.")
+
(defun parseedn-reduce-leaf (stack token _options)
"Put in the STACK an elisp value representing TOKEN.
@@ -101,10 +118,14 @@ on available options."
kvs)
hash-map))
((eq :tag token-type) (let* ((tag (intern (substring (alist-get :form
opening-token) 1)))
- (reader (alist-get tag tag-readers
:missing)))
- (when (eq :missing reader)
- (user-error "No reader for tag #%S in %S"
tag (map-keys tag-readers)))
- (funcall reader (car children)))))
+ (reader (alist-get tag tag-readers))
+ (default-reader (alist-get :default
tag-readers parseedn-default-data-reader-fn)))
+ (cond
+ ((functionp reader)
+ (funcall reader (car children)))
+ ((functionp default-reader)
+ (funcall default-reader tag (car children)))
+ (t (user-error "No reader for tag #%S in %S"
tag (map-keys tag-readers)))))))
stack))))
(defun parseedn-read (&optional tag-readers)
@@ -236,6 +257,9 @@ DATUM can be any Emacs Lisp value."
(insert "#uuid ") (parseedn-print-seq (cdr datum)))
((eq 'edn-inst (car datum))
(insert "#inst ") (parseedn-print-inst (cdr datum)))
+ ((eq 'edn-tagged-literal (car datum))
+ (insert "#" (symbol-name (cadr datum)) " ")
+ (parseedn-print (caddr datum)))
(t (insert "(") (parseedn-print-seq datum) (insert ")"))))
(t (error "Don't know how to print: %s" datum))))
diff --git a/test/parseedn-test-data.el b/test/parseedn-test-data.el
index 84da3c89f8..74b791574c 100644
--- a/test/parseedn-test-data.el
+++ b/test/parseedn-test-data.el
@@ -277,7 +277,10 @@
"tag-1"
(a-list
+ :tags '(:edn-roundtrip)
+ :tag-readers '((:default . parseedn-tagged-literal))
:source "#foo/bar [1]"
+ :edn '((edn-tagged-literal foo/bar [1]))
:ast '((:node-type . :root)
(:position . 1)
(:children . (((:node-type . :tag)
@@ -292,7 +295,10 @@
"tag-2"
(a-list
+ :tags '(:edn-roundtrip)
+ :tag-readers '((:default . parseedn-tagged-literal))
:source "(fn #param :param-name 1)"
+ :edn '((fn (edn-tagged-literal param :param-name) 1))
:ast '((:node-type . :root)
(:position . 1)
(:children . (((:node-type . :list)
@@ -315,6 +321,9 @@
"nested-tags"
(a-list
+ :tags '(:edn-roundtrip)
+ :tag-readers '((:default . parseedn-tagged-literal))
+ :edn (list (vector `(edn-tagged-literal lazy-error (edn-tagged-literal
error ,(a-hash-table :cause "Divide by zero")))))
:source "[#lazy-error #error {:cause \"Divide by zero\"}]"
:ast '((:node-type . :root)
(:position . 1)
diff --git a/test/parseedn-test.el b/test/parseedn-test.el
index 0c060b9924..49a3a66b2c 100644
--- a/test/parseedn-test.el
+++ b/test/parseedn-test.el
@@ -43,6 +43,8 @@
(should (equal (parseedn-print-str '((a . 1) (b . ((c . 3))))) "{a 1, b {c
3}}"))
(should (equal (parseedn-print-str '(:a 1 :b 2)) "{:a 1, :b 2}"))
(should (equal (parseedn-print-str '(:a 1 :b (:c 3))) "{:a 1, :b {:c 3}}"))
+ (should (equal (parseedn-print-str '(edn-tagged-literal unknown "data"))
"#unknown \"data\""))
+ (should (equal (parseedn-print-str '(edn-tagged-literal unknown
(edn-tagged-literal unknown "data"))) "#unknown #unknown \"data\""))
(should (listp (member (parseedn-print-str
(let ((ht (make-hash-table)))
(puthash :a 1 ht)
@@ -59,6 +61,20 @@
(ert-deftest parseedn-read-test ()
(should (equal (parseedn-read-str "true") t)))
+(ert-deftest parseedn-tagged-literal-test ()
+ (let ((data "#unknown \"data\"")
+ (expected '(edn-tagged-literal unknown "data")))
+ ;; Default reader can be passed as a function
+ (should (equal expected (parseedn-read-str data `((:default .
,#'parseedn-tagged-literal)))))
+ ;; Default reader can be passed as a symbol
+ (should (equal expected (parseedn-read-str data '((:default .
parseedn-tagged-literal)))))
+ ;; Default reader can be bound to a function
+ (let ((parseedn-default-data-reader-fn #'parseedn-tagged-literal))
+ (should (equal expected (parseedn-read-str data))))
+ ;; Default reader can be bound to a symbol
+ (let ((parseedn-default-data-reader-fn 'parseedn-tagged-literal))
+ (should (equal expected (parseedn-read-str data))))))
+
(defmacro define-parseedn-read-tests ()
`(progn
,@(mapcar
@@ -72,7 +88,8 @@
(with-temp-buffer
(insert ,(a-get data :source))
(goto-char 1)
- (should (a-equal (parseedn-read) ',(a-get data
:edn)))))))))
+ (should (a-equal (parseedn-read ',(a-get data
:tag-readers))
+ ',(a-get data :edn)))))))))
parseedn-test-data)))
(defmacro define-parseedn-roundtrip-tests ()