aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorW. Kosior <koszko@koszko.org>2025-03-04 13:56:26 +0100
committerW. Kosior <koszko@koszko.org>2025-03-04 17:02:31 +0100
commit9f336a25c5a49f5ce2e4ff5a9384f59ab56e487b (patch)
treeee186a828d25c28973f3c478e0f2b0899b3332c6
parent77472c6943378eed9f9b3ee6bf534407cfda9bd7 (diff)
downloadde-paul-records-9f336a25c5a49f5ce2e4ff5a9384f59ab56e487b.tar.gz
de-paul-records-9f336a25c5a49f5ce2e4ff5a9384f59ab56e487b.zip
Generate alist serializer and deserializer procedures.
-rw-r--r--README.md1
-rw-r--r--src/guile/de-paul-records.scm33
-rw-r--r--tests/guile/de-paul-records-test.scm29
3 files changed, 61 insertions, 2 deletions
diff --git a/README.md b/README.md
index 741e890..0d4dae5 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,7 @@ other tasks. Features include
- support for default field values,
- support for programmer-supplied record finalizer procedures,
- syntax for creation of a record object based on an existing one,
+- automatic generation of alist<->record (de)serialization procedures,
- optional automatic export of generated getters and other variables,
- and amended variants of `(ice-9 match)` forms with (unhygienic) record
matcher that allows fields to be matched **by name**.
diff --git a/src/guile/de-paul-records.scm b/src/guile/de-paul-records.scm
index 102ff87..7fcd3a0 100644
--- a/src/guile/de-paul-records.scm
+++ b/src/guile/de-paul-records.scm
@@ -205,7 +205,13 @@
(%null-record (format-identifiers "%null-~a" record-name))
(*record (format-identifiers "*~a" record-name))
(--finalize-record (format-identifiers "--finalize-~a"
- record-name)))
+ record-name))
+ (record->alist (format-identifiers "~a->alist"
+ record-name))
+ (*alist->record (format-identifiers "*alist->~a"
+ record-name))
+ (alist->record (format-identifiers "alist->~a"
+ record-name)))
#`(begin
(define-immutable-record-type <record> (--make-record) record?
#,@(map (match-lambda
@@ -235,9 +241,34 @@
(define-syntax-rule (#,record-name . body-rest)
(--finalize-record (*record . body-rest)))
+ (define (*alist->record alist)
+ (*record
+ #,@(map (match-lambda
+ ((= field-spec-name field-name)
+ #`(#,field-name
+ (or (and=> (assq '#,field-name alist)
+ cdr)
+ (#,(format-identifiers "~a-~a"
+ record-name field-name)
+ %null-record)))))
+ field-specs)))
+
+ (define (alist->record alist)
+ (--finalize-record (*alist->record alist)))
+
+ (define (record->alist record)
+ `(#,@(map (match-lambda
+ ((= field-spec-name field-name)
+ #`(#,field-name
+ . ,(#,(format-identifiers "~a-~a"
+ record-name field-name)
+ record))))
+ field-specs)))
+
#,@(if (eq? export? #t)
(list
#`(export <record> #,record-name record? %null-record
+ *alist->record alist->record record->alist
#,@(append-map
(match-lambda
((= field-spec-name field-name)
diff --git a/tests/guile/de-paul-records-test.scm b/tests/guile/de-paul-records-test.scm
index 275d1a3..011c438 100644
--- a/tests/guile/de-paul-records-test.scm
+++ b/tests/guile/de-paul-records-test.scm
@@ -20,7 +20,7 @@
(or (eval '(begin
(define-module (de-paul-records-test lisp)
#:use-module ((de-paul-records) #:select
- (deftype match set-field)))
+ (deftype match match-lambda set-field)))
(deftype lisp
(name)
@@ -131,6 +131,33 @@
(match %paren-3004
(($* lisp is-scheme? is-syntactically-scoped?)
(list is-scheme? is-syntactically-scoped?))))
+ (test-env 'lisp))))
+
+ (test-group "lisp paren-3005"
+ (tu:test-equal '((name . "paren-3005")
+ (is-scheme? . #f)
+ (is-syntactically-scoped? . #t))
+ (eval
+ '(lisp->alist (lisp (name "paren-3005")
+ (is-syntactically-scoped? #t)
+ (is-scheme? #f)))
+ (test-env 'lisp))))
+
+ (test-group "lisp paren-3006"
+ (tu:test-equal '((name "paren-3006" is? #t iss? #f)
+ (name "paren-3006" is? #t iss? #t))
+ (eval
+ '(map (compose
+ (match-lambda
+ (($* lisp name is-scheme? is-syntactically-scoped?)
+ (list 'name name
+ 'is? is-scheme?
+ 'iss? is-syntactically-scoped?)))
+ (lambda (proc)
+ (proc `((is-scheme? . #t)
+ (extra-key . 'dummy)
+ (name . "paren-3006")))))
+ (list *alist->lisp alist->lisp))
(test-env 'lisp)))))
(test-group "match behavior"