1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
;; SPDX-License-Identifier: EUPL-1.2
;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs <perkontevs@gmail.com>
(defpackage :ukkoclot/bot/method-macros
(:use :c2cl :iterate :ukkoclot/bot/impl)
(:export :define-tg-method))
(in-package :ukkoclot/bot/method-macros)
(eval-when (:compile-toplevel :load-toplevel :execute)
(defstruct (param (:constructor make-param%)) name type default skip-if-default)
(defparameter +unique+ (gensym))
(defun make-param (name type &optional (default +unique+) &key (skip-if-default (not (eq default +unique+))))
(let ((default (if (eq default +unique+)
`(error ,(format nil "No value given for ~A" name))
default)))
(make-param% :name name
:type type
:default default
:skip-if-default skip-if-default)))
(defun parse-param-specs (param-specs)
(iter (for param-spec in param-specs)
(collect (apply #'make-param param-spec))))
(defun emit-append-to-args (param args)
`(setf ,args (acons ',(param-name param) ,(param-name param) ,args)))
(defun emit-arg-type (param)
`(,(intern (symbol-name (param-name param)) :keyword)
,(param-type param)))
(defun emit-defun-arg (param)
`(,(param-name param) ,(param-default param)))
(defun emit-defun (name return-type params method path)
(let ((revparams (reverse params))
(args (gensym "ARGS"))
(bot (gensym "BOT")))
`(defun ,name (,bot &key ,@(iter (for param in params)
(collect (emit-defun-arg param))))
(let (,args)
,@(iter (for param in revparams)
(collect (if (param-skip-if-default param)
`(unless (equal ,(param-name param)
,(param-default param))
,(emit-append-to-args param args))
(emit-append-to-args param args))))
(do-call ,bot ,method ,path ',return-type ,args)))))
(defun emit-ftype (name return-type params)
`(declaim (ftype (function (bot &key ,@(iter (for param in params)
(collect (emit-arg-type param))))
,return-type)
,name))))
;; TODO: Automatically derive path from name
(defmacro define-tg-method (
(name type path &optional (method :POST))
&body param-specs)
(let ((params (parse-param-specs param-specs)))
`(progn
,(emit-ftype name type params)
,(emit-defun name type params method path))))
|