diff options
Diffstat (limited to 'src/tg/macros.lisp')
| -rw-r--r-- | src/tg/macros.lisp | 118 |
1 files changed, 0 insertions, 118 deletions
diff --git a/src/tg/macros.lisp b/src/tg/macros.lisp deleted file mode 100644 index 9577d94..0000000 --- a/src/tg/macros.lisp +++ /dev/null | |||
| @@ -1,118 +0,0 @@ | |||
| 1 | ;; SPDX-License-Identifier: EUPL-1.2 | ||
| 2 | ;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs <perkontevs@gmail.com> | ||
| 3 | (defpackage :ukkoclot/tg/macros | ||
| 4 | (:use :c2cl) | ||
| 5 | (:import-from :ukkoclot/bot/impl :bot :do-call :parse-value) | ||
| 6 | (:import-from :ukkoclot/hash-tables :gethash-lazy) | ||
| 7 | (:import-from :ukkoclot/strings :lisp->snake-case) | ||
| 8 | (:local-nicknames | ||
| 9 | (:jzon :com.inuoe.jzon)) | ||
| 10 | (:export :define-tg-type)) | ||
| 11 | (in-package :ukkoclot/tg/macros) | ||
| 12 | |||
| 13 | (eval-when (:compile-toplevel :load-toplevel :execute) | ||
| 14 | (defstruct (field (:constructor make-field%)) name type default skip-if-default) | ||
| 15 | |||
| 16 | (defparameter +unique+ (gensym)) | ||
| 17 | |||
| 18 | (defun make-field (name type &optional (default +unique+) &key (skip-if-default (not (eq default +unique+)))) | ||
| 19 | (let ((default (if (eq default +unique+) | ||
| 20 | (list 'error (format nil "No value given for ~A" name)) | ||
| 21 | default))) | ||
| 22 | (make-field% :name name | ||
| 23 | :type type | ||
| 24 | :default default | ||
| 25 | :skip-if-default skip-if-default))) | ||
| 26 | |||
| 27 | (defun parse-field-specs (field-specs) | ||
| 28 | (loop for field-spec in field-specs | ||
| 29 | collect (apply #'make-field field-spec))) | ||
| 30 | |||
| 31 | (defun field-hash-key (field) | ||
| 32 | (string-downcase (lisp->snake-case (symbol-name (field-name field))))) | ||
| 33 | |||
| 34 | (defun field-accessor (struc-name field) | ||
| 35 | (intern (concatenate 'string (symbol-name struc-name) "-" (symbol-name (field-name field))))) | ||
| 36 | |||
| 37 | (defun field->coerced-field-spec (field struc-name obj-name) | ||
| 38 | `(list ,(string-downcase (lisp->snake-case (symbol-name (field-name field)))) | ||
| 39 | (,(field-accessor struc-name field) ,obj-name) | ||
| 40 | ',(field-type field))) | ||
| 41 | |||
| 42 | (defun field->defun-spec (field) | ||
| 43 | (list (field-name field) (field-default field))) | ||
| 44 | |||
| 45 | (defun field->format-arg (field name struc) | ||
| 46 | `(',(field-name field) (,(field-accessor name field) ,struc))) | ||
| 47 | |||
| 48 | (defun field->ftype-spec (field) | ||
| 49 | (list (intern (symbol-name (field-name field)) :keyword) (field-type field))) | ||
| 50 | |||
| 51 | (defun field->gethash-spec (field hash-table-sym) | ||
| 52 | (let ((hash-key (field-hash-key field))) | ||
| 53 | (list 'gethash-lazy hash-key hash-table-sym (field-default field)))) | ||
| 54 | |||
| 55 | (defun field->sethash-spec (field name struc hash-table-sym) | ||
| 56 | (let ((hash-key (field-hash-key field)) | ||
| 57 | (skip-if-default (field-skip-if-default field)) | ||
| 58 | (default (field-default field))) | ||
| 59 | (if skip-if-default | ||
| 60 | (let ((tmpsym (gensym "TMP"))) | ||
| 61 | `(let ((,tmpsym (,(field-accessor name field) ,struc))) | ||
| 62 | (unless (equal ,tmpsym ,default) | ||
| 63 | (setf (gethash ,hash-key ,hash-table-sym) ,tmpsym)))) | ||
| 64 | `(setf (gethash ,hash-key ,hash-table-sym) (,(field-accessor name field) ,struc))))) | ||
| 65 | |||
| 66 | (defun field->let-gethash-spec (field hash-table-sym) | ||
| 67 | `(,(field-name field) | ||
| 68 | (parse-value ',(field-type field) ,(field->gethash-spec field hash-table-sym)))) | ||
| 69 | |||
| 70 | (defun field->make-spec (field) | ||
| 71 | (list (intern (symbol-name (field-name field)) :keyword) | ||
| 72 | (field-name field))) | ||
| 73 | |||
| 74 | (defun field->struct-spec (field) | ||
| 75 | (list (field-name field) (field-default field) :type (field-type field)))) | ||
| 76 | |||
| 77 | (defmacro define-tg-type (name &body field-specs) | ||
| 78 | (let* ((fields (parse-field-specs field-specs)) | ||
| 79 | (revfields (reverse fields)) | ||
| 80 | (make-name (intern (concatenate 'string "MAKE-" (symbol-name name)))) | ||
| 81 | (printer (gensym (concatenate 'string "PRINT-" (symbol-name name)))) | ||
| 82 | (hash (gensym "HASH-")) | ||
| 83 | (struc (gensym (symbol-name name))) | ||
| 84 | (stream (gensym "STREAM")) | ||
| 85 | (depth (gensym "DEPTH")) | ||
| 86 | (pprint-args (gensym "PPRINT-ARGS")) | ||
| 87 | (res (gensym "RES")) | ||
| 88 | (type (gensym "TYPE"))) | ||
| 89 | `(progn | ||
| 90 | (defstruct (,name (:print-function ,printer)) | ||
| 91 | ,@(loop for field in fields | ||
| 92 | collect (field->struct-spec field))) | ||
| 93 | (defun ,printer (,struc ,stream ,depth) | ||
| 94 | (declare (ignore ,depth)) | ||
| 95 | (let (,pprint-args) | ||
| 96 | ,@(loop for field in revfields | ||
| 97 | collecting | ||
| 98 | (if (field-skip-if-default field) | ||
| 99 | `(let ((value (,(field-accessor name field) ,struc))) | ||
| 100 | (unless (equal value ,(field-default field)) | ||
| 101 | (setf ,pprint-args (list* ',(field-name field) value ,pprint-args)))) | ||
| 102 | `(setf ,pprint-args (list* ',(field-name field) (,(field-accessor name field) ,struc) ,pprint-args)))) | ||
| 103 | (format ,stream "~A~<[~;~@{~_~1I~W = ~W~^, ~}~;]~:>" ',name ,pprint-args))) | ||
| 104 | (defmethod parse-value ((,type (eql ',name)) ,hash) | ||
| 105 | (let ,(loop for field in fields | ||
| 106 | collect (field->let-gethash-spec field hash)) | ||
| 107 | (,make-name ,@(loop for field in fields | ||
| 108 | append (field->make-spec field))))) | ||
| 109 | (defmethod jzon:coerced-fields ((,struc ,name)) | ||
| 110 | (let (,res) | ||
| 111 | ,@(loop for field in revfields | ||
| 112 | collecting | ||
| 113 | (if (field-skip-if-default field) | ||
| 114 | `(let ((value (,(field-accessor name field) ,struc))) | ||
| 115 | (unless (equal value ,(field-default field)) | ||
| 116 | (setf ,res (cons ,(field->coerced-field-spec field name struc) ,res)))) | ||
| 117 | `(setf ,res (cons ,(field->coerced-field-spec field name struc) ,res)))) | ||
| 118 | ,res))))) | ||