summaryrefslogtreecommitdiff
path: root/src/tg/method-macros.lisp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tg/method-macros.lisp')
-rw-r--r--src/tg/method-macros.lisp72
1 files changed, 72 insertions, 0 deletions
diff --git a/src/tg/method-macros.lisp b/src/tg/method-macros.lisp
new file mode 100644
index 0000000..3599328
--- /dev/null
+++ b/src/tg/method-macros.lisp
@@ -0,0 +1,72 @@
1;; SPDX-License-Identifier: EUPL-1.2
2;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs <perkontevs@gmail.com>
3(defpackage :ukkoclot/tg/method-macros
4 (:use :c2cl :iterate)
5 (:import-from :ukkoclot/state :bot)
6 (:import-from :ukkoclot/strings :ends-with :lisp->camel-case)
7 (:import-from :ukkoclot/transport :do-call)
8 (:export :define-tg-method))
9(in-package :ukkoclot/tg/method-macros)
10
11(eval-when (:compile-toplevel :load-toplevel :execute)
12 (defstruct (param (:constructor make-param%)) name type default skip-if-default)
13
14 (defparameter +unique+ (gensym))
15
16 (defun make-param (name type &optional (default +unique+) &key (skip-if-default (not (eq default +unique+))))
17 (let ((default (if (eq default +unique+)
18 `(error ,(format nil "No value given for ~A" name))
19 default)))
20 (make-param% :name name
21 :type type
22 :default default
23 :skip-if-default skip-if-default)))
24
25 (defun parse-param-specs (param-specs)
26 (iter (for param-spec in param-specs)
27 (collect (apply #'make-param param-spec))))
28
29 (defun path-from-name (name)
30 (let ((str (lisp->camel-case (symbol-name name))))
31 (if (ends-with str "%")
32 (subseq str 0 (- (length str) 1))
33 str)))
34
35 (defun emit-append-to-args (param args)
36 `(setf ,args (acons ',(param-name param) ,(param-name param) ,args)))
37
38 (defun emit-arg-type (param)
39 `(,(intern (symbol-name (param-name param)) :keyword)
40 ,(param-type param)))
41
42 (defun emit-defun-arg (param)
43 `(,(param-name param) ,(param-default param)))
44
45 (defun emit-defun (name return-type params method)
46 (let ((revparams (reverse params))
47 (args (gensym "ARGS"))
48 (bot (gensym "BOT")))
49 `(defun ,name (,bot &key ,@(iter (for param in params)
50 (collect (emit-defun-arg param))))
51 (let (,args)
52 ,@(iter (for param in revparams)
53 (collect (if (param-skip-if-default param)
54 `(unless (equal ,(param-name param)
55 ,(param-default param))
56 ,(emit-append-to-args param args))
57 (emit-append-to-args param args))))
58 (do-call ,bot ,method ,(path-from-name name) ',return-type ,args)))))
59
60 (defun emit-ftype (name return-type params)
61 `(declaim (ftype (function (bot &key ,@(iter (for param in params)
62 (collect (emit-arg-type param))))
63 ,return-type)
64 ,name))))
65
66(defmacro define-tg-method (
67 (name type &optional (method :POST))
68 &body param-specs)
69 (let ((params (parse-param-specs param-specs)))
70 `(progn
71 ,(emit-ftype name type params)
72 ,(emit-defun name type params method))))