diff options
Diffstat (limited to 'src/enum.lisp')
| -rw-r--r-- | src/enum.lisp | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/src/enum.lisp b/src/enum.lisp new file mode 100644 index 0000000..c678ec7 --- /dev/null +++ b/src/enum.lisp | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | ;; SPDX-License-Identifier: EUPL-1.2 | ||
| 2 | ;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs <perkontevs@gmail.com> | ||
| 3 | (defpackage :ukkoclot/enum | ||
| 4 | (:use :c2cl :iterate) | ||
| 5 | (:import-from :ukkoclot/bot/impl :fixup-value :parse-value) | ||
| 6 | (:import-from :string-case :string-case) | ||
| 7 | (:local-nicknames | ||
| 8 | (:jzon :com.inuoe.jzon)) | ||
| 9 | (:export :define-enum)) | ||
| 10 | (in-package :ukkoclot/enum) | ||
| 11 | |||
| 12 | (eval-when (:compile-toplevel :load-toplevel :execute) | ||
| 13 | (defstruct (field (:constructor make-field%)) name string) | ||
| 14 | |||
| 15 | (defun make-field (name string) | ||
| 16 | (make-field% :name name :string string)) | ||
| 17 | |||
| 18 | (defun parse-field-specs (field-specs) | ||
| 19 | (iter (for field-spec in field-specs) | ||
| 20 | (collect (apply #'make-field field-spec)))) | ||
| 21 | |||
| 22 | (defun emit-defconst (field) | ||
| 23 | `(defconstant ,(field-name field) ',(field-name field))) | ||
| 24 | |||
| 25 | (defun emit-deftype (name fields) | ||
| 26 | `(deftype ,name () | ||
| 27 | '(member ,@(iter (for field in fields) (collect (field-name field)))))) | ||
| 28 | |||
| 29 | (defun emit-fixup-method (field) | ||
| 30 | (let ((arg (gensym "ARG"))) | ||
| 31 | `(defmethod fixup-value ((,arg (eql ',(field-name field)))) | ||
| 32 | ,(field-string field)))) | ||
| 33 | |||
| 34 | (defun emit-jzon-write-method (field) | ||
| 35 | (let ((writer (gensym "WRITER")) | ||
| 36 | (arg (gensym "ARG"))) | ||
| 37 | `(defmethod jzon:write-value (,writer (,arg (eql ',(field-name field)))) | ||
| 38 | (jzon::write-string ,(field-string field) ,writer)))) | ||
| 39 | |||
| 40 | (defun emit-parse-value (name fields) | ||
| 41 | (let ((type (gensym "TYPE")) | ||
| 42 | (source (gensym "SOURCE"))) | ||
| 43 | `(defmethod parse-value ((,type (eql ',name)) ,source) | ||
| 44 | ;; nil in, nil out | ||
| 45 | (when ,source | ||
| 46 | (string-case (,source) | ||
| 47 | ,@(iter (for field in fields) | ||
| 48 | (collect `(,(field-string field) ,(field-name field)))))))))) | ||
| 49 | |||
| 50 | (defmacro define-enum (name &body field-specs) | ||
| 51 | (let ((fields (parse-field-specs field-specs))) | ||
| 52 | `(progn | ||
| 53 | ,(emit-deftype name fields) | ||
| 54 | ,(emit-parse-value name fields) | ||
| 55 | ,@(iter (for field in fields) | ||
| 56 | (collect `(progn | ||
| 57 | ,(emit-defconst field) | ||
| 58 | ,(emit-fixup-method field) | ||
| 59 | ,(emit-jzon-write-method field))))))) | ||