summaryrefslogtreecommitdiffstats
path: root/share/txr/stdlib/txr-case.txr
blob: 4d0081b3a956122bd8756f097f5985cd7fb6e020 (plain)
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
@(do
   (macro-time
     (defun bindable (obj)
       (and obj
            (symbolp obj)
            (not (keywordp obj))
            (not (eq t obj)))))

   (defmacro txr-if (name args input : then else)
     (let ((syms [keep-if bindable args])
           (arg-exprs [mapcar [iffi symbolp (ret ^',@1)] args])
           (result (gensym "res-"))
           (bindings (gensym "bindings-"))
           (insym (gensym "input-")))
       ^(let* ((,insym ,input)
               (,result (match-fun ',name (list ,*arg-exprs)
                                   (if (stringp ,insym) (list ,insym) ,insym)
                                   nil)))
          (if ,result
            (let ((,bindings (car ,result)))
              (let (,*[mapcar (ret ^(,@1 (cdr (assoc ',@1 ,bindings))))
                              syms])
                ,then))
            ,else))))

   (defmacro txr-when (name args input . body)
     ^(txr-if ,name ,args ,input (progn ,*body)))

   (defmacro txr-case-impl (sym . clauses)
     (tree-case clauses
       (((name args . body) . other-clauses)
        (if (eq name t) :
          ^(txr-if ,name ,args ,sym
             (progn ,*body)
             (txr-case-impl ,sym ,*other-clauses))))
       (((sym . rest) . other-clauses)
        (if (eq sym t)
          (if other-clauses
            (error "txr-case: clauses after (t ...) clause ignored")
            ^(progn ,*rest))
          (error "txr-case: bad syntax: ~s" (car clauses))))
       (atom
          (error "txr-case: unexpected atom in syntax: ~s" atom))))

   (defmacro txr-case (input-expr . clauses)
     (let ((input (gensym "input-")))
       ^(let ((,input ,input-expr))
          (txr-case-impl ,input ,*clauses)))))