-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontrol.cl
76 lines (63 loc) · 2.46 KB
/
control.cl
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
65
66
67
68
69
70
71
72
73
74
75
(defparameter *commands* nil)
(defun defcommand (head &rest forms)
(push (list head forms) *commands*))
;; WARNING! psychotic code - approach with caution
(defun mushy-eval (command-str &optional caller)
(setf command-str (string-trim '(#\Space #\Tab #\Newline) command-str))
(let* ((command (find-head command-str))
(forms (cadr command))
(form nil) (matches nil) (symbols nil)
(matched-symbols (make-hash-table :test 'eq)))
(declare (special matched-symbols))
(block outer
(loop for f in forms do
(multiple-value-bind (a b)
(cl-ppcre:scan-to-strings (convert-form f) command-str)
(if a (progn
(setf matches b form f symbols (collect-symbols (car f)))
(return-from outer nil))))))
(if (not form) (return-from mushy-eval
"Can't match your command form."))
(if (and symbols (not (equalp matches #())))
(loop for s in symbols for m across matches do
(setf (gethash s matched-symbols) m)))
(let ((player caller))
(declare (special player))
(eval (cadr form)))))
(defun convert-head (head)
(format nil "^~a" head))
(defun find-head (command)
(loop for c in *commands* do
(if (cl-ppcre:all-matches (convert-head (car c)) command)
(return-from find-head c))))
(defun convert-form (form)
(setf form (car form))
(format nil "^~a$"
(build-regex form)))
(defun build-regex (elt)
(cond ((stringp elt) elt)
((symbolp elt) "(.+?)")
((eq (car elt) 'optional)
(format nil "~{(?:~a)?~}" (mapcar #'build-regex (cdr elt))))
((eq (car elt) 'switch)
(format nil "(?:~{~a~^|~})" (mapcar #'build-regex (cdr elt))))
((listp elt) (format nil "~{~a~}" (mapcar #'build-regex elt)))
(t (error "Invalid element in command declaration:~a" elt))))
(defun collect-symbols (form)
(let ((res nil))
(cond ((listp form)
(setf res (alexandria:flatten (mapcar #'collect-symbols form))))
((and (symbolp form) (not (eq form 'optional)) (not (eq form 'switch)))
(setf res (push form res)))
(t nil)) res))
(defmacro get- (sym) `(gethash ',sym matched-symbols))
(defun quote-list (lst)
(mapcar (lambda (x) (car `(',x))) lst))
;; (let ((name (resolve-object val player))) (if name progn "error"))
(defmacro with-object (name val &rest form)
`(let ((,name (resolve-object ,val player)))
(if (eql (list-length ,name) 1)
(progn (setf ,name (car ,name)) ,@form)
(format nil "Unable to resolve \"~a\".~{~% ~a~}" ,val ,name))))
(defmacro defcom (head &rest forms)
`(defcommand ,head ,@(quote-list forms)))