This file is indexed.

/usr/share/acl2-8.0dfsg/books/tools/pattern-match.lisp is in acl2-books-source 8.0dfsg-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
 ;; A scheme for pattern matching
;; written by Sol Swords, 6/01/2005
;; email: sswords@cs.utexas.edu


;; with code borrowed from the case-match function in basis.lisp,
;; by Matt Kaufmann and J Strother Moore.




;; There is quite a bit left to do with this especially for execution efficiency:
;; since we keep separate lists of tests and bindings for each clause, we may
;; call certain destructor functions many times where we could've used a binding
;; to improve the efficiency.  If destructors are expensive, you may wish to avoid
;; using this.  See the defdoc at the end of this file for usage and explanation.

(in-package "ACL2")
(include-book "xdoc/top" :dir :system)

(program)

(defxdoc pattern-match
  :parents (case-match)
  :short "User-definable pattern-matching."
  :long "<p>Examples:</p>

  @({
  (pattern-match
   x
   ((cons a b) ... body1 ... )
   ((three-elt-constructor a & c) ... body2 ...)
   (& default-value))
  })

<p>@('pm') is a convenient abbreviation for @('pattern-match').</p>

<p>Pattern-match is similar to @(see case-match), but the two macros interpret
patterns differently.  If the pattern is @('(a b c)'), @('case-match')
interprets this as a three-element list and, if the input is also a
three-element list, binds the first to @('a'), second to @('b'), and third to
@('c').  Pattern-match, on the other hand, interprets @('(a b c)') as the
application of a constructor @('a') to arguments @('b') and @('c').  Aside from
this difference, pattern-match contains much the same features as case-match.
See @(see case-match) for the significance of special characters such as @('&')
and @('!').  Also see @(see pattern-match-list), @(see pattern-matches), and
@(see pattern-matches-list).</p>

<h3>Usage</h3>

@({
  (pattern-match
     input
     (pattern1 declare-form condition11 condition12 ... declare-form body1)
     (pattern2 condition21 condition22 ... body2)
      ...)
})

<p>In the previous invocation, pattern-match first matches the input to
pattern1.  If it matches, condition11, condition12, ... are evaluated using any
variable bindings that pattern1 created, and using the declare form preceding
them if there is one.  (The declare form is primarily useful for declaring
ignored variables.)  If they all evaluate to non-nil, body1 is evaluated and
returned with the same variable bindings and with the declare form preceding
it, if any.  If pattern1 does not match or any of the conditions evaluate to
nil, body1 is not evaluated and pattern2 is tried, and so on.  The list of
patterns should be comprehensive or else end with a listing of the form @('(&
finalbody)'), so that finalbody serves as a default value.</p>

<p>In each pattern clause the declare forms and conditions are optional.
Conditions may be included without declare forms and vice versa.  To
distinguish declare forms from conditions we simply check whether the first
item following the pattern and/or the last item before the body are declare
forms; everything between the pattern and body that is not a declare form is
assumed to be a condition.</p>

<p>Each pattern may be a variable, to be bound to the value of the input; an
existing variable name prefixed by ! or a constant, the value of which is to be
compared with the input value; the special symbol @('&') which matches
anything, or an application of a constructor to a number of arguments.  Each
constructor must have an associated macro which allows pattern-match to process
it.  The macro defines what is acceptable syntax, i.e. the number and type of
arguments the constructor can take, the conditions under which the input
matches the constructor, and the significance of the arguments.  For example,
cons-pattern-matcher is defined so that in a pattern match statement, the
constructor cons is required to take exactly two arguments; it matches any
input satisfying (consp input), and its arguments are treated as subpatterns to
be matched to the car and cdr of the input, respectively.</p>

<h3>Extensions</h3>

<p>The pattern-match book includes built-in support for the constructors
@('cons'), @('list'), and @('list*').  Support may be added for user-defined
constructors.  Some ``special constructors'' are also supported, with less
obvious behavior. @('raw') takes one argument, which is matched to the input
using case-match syntax; that is, no constructors are recognized.  @('bind')
takes two arguments, one a variable symbol and one a pattern; if the pattern
matches the input, then the input is bound to the variable.  @('any') compares
the input to each of its arguments using equal; if any of the arguments are
equal to the input then it is considered a match. @('force') assumes that the
pattern matches and makes the specified bindings without checking.</p>

<p>For example, the following pattern-match statement returns @('(1 ((1 2
. 3)))'):</p>

 @({
  (pattern-match (list 1 (cons 1 (cons 2 3)))
    ((cons a (bind k (raw ((a b . c))))) (list a k)))
 })

<p>For documentation on enabling pattern-match to recognize new constructors,
see @(see def-pattern-match-constructor) and for more see @(see
constructor-pattern-match-macros).</p>

<p>Note 1: Currently pattern-match does not bind the input expression to an
internal variable, but simply copies it everywhere it is used.  Therefore it is
wise, if the input is from some expensive calculation, to bind it to a variable
before applying pattern-match.</p>

<p>Note 2: The default value of a pattern-match expression in case no patterns
match is nil.  Because of this, if the pattern-match expression is supposed to
evaluate to a special shape (an mv, or state, for instance), a default value of
the correct shape must be defined by including a final clause of the form @('(&
default-value-of-correct-shape)').</p>")

(defmacro pbl-tests-bindings (tests bindings)
  `(pattern-bindings-list (cdr lhses) (cdr rhses) ,tests ,bindings
                          pmstate))


(defmacro execute-patmatch (testclause bindings-and-body nextcall)
  (if testclause
      `(if ,testclause
           ,bindings-and-body
         ,nextcall)
    bindings-and-body))

(defmacro check-pattern-matches (testclause bindings-and-body nextcall)
  (declare (ignore bindings-and-body nextcall))
  (or testclause t))


(defun intern-check (str sym)
  (if (equal (symbol-package-name sym) "COMMON-LISP")
      (intern str "ACL2")
    (intern-in-package-of-symbol str sym)))


(defun pattern-bindings-list
  (lhses rhses tests bindings pmstate)
  (if (or (atom lhses) (atom rhses))
      (let* ((tests-declare (nth 0 pmstate))
             (final-tests (nth 1 pmstate))
             (declare (nth 2 pmstate))
             (body (nth 3 pmstate))
             (nextcall (nth 4 pmstate))
             (action (nth 5 pmstate))
             (final-test (if final-tests
                             `((let ,(reverse bindings)
                                 ,@tests-declare
                                 (and ,@final-tests)))
                           nil))
             (bindings-and-body
              (if (or (eq body t) (eq body nil))
                  body
                `(let ,(reverse bindings) ,@declare ,body)))
             (tests (revappend tests final-test))
             (testclause
              (if (< 1 (len tests))
                  `(and ,@tests)
                (if (consp tests)
                    (car tests)
                  nil))))
        `(,action ,testclause ,bindings-and-body ,nextcall))
    (let ((lhs (car lhses))
          (rhs (car rhses)))
      (cond
       ((symbolp lhs)
        (cond
         ((or (eq lhs t) (eq lhs nil))
          (pbl-tests-bindings (cons `(eq ,rhs ,lhs) tests) bindings))
         ((and (> (length (symbol-name lhs)) 0)
               (eql #\* (char (symbol-name lhs) 0)))
          (pbl-tests-bindings (cons `(equal ,rhs ,lhs) tests) bindings))
         ((and (> (length (symbol-name lhs)) 0)
               (eql #\! (char (symbol-name lhs) 0)))
          (pbl-tests-bindings
           (cons `(equal ,rhs ,(intern-check (coerce (cdr (coerce (symbol-name lhs) 'list))
                                               'string)
                                       lhs)) tests)
           bindings))
         ((eq lhs '&) (pbl-tests-bindings tests bindings))
         (t (let ((binding (assoc-eq lhs bindings)))
              (cond ((null binding)
                     (pbl-tests-bindings tests (cons `(,lhs ,rhs) bindings)))
                    (t (pbl-tests-bindings (cons `(equal ,rhs ,(cadr binding)) tests)
                                           bindings)))))))
       ((atom lhs)
        (pbl-tests-bindings (cons (equal-x-constant rhs (list 'quote lhs)) tests)
                            bindings))
       ((eq (car lhs) 'quote)
        (pbl-tests-bindings (cons (equal-x-constant rhs lhs) tests)
                            bindings))
       (t
        ;;lhs is aassumed to be a constructor application.  Return a call of
        ;;the pattern match macro for that constructor.
        (let* ((func (car lhs))
               (args (cdr lhs))
               (func-pm-macro (intern-check (concatenate 'string
                                                         (symbol-name func)
                                                         "-PATTERN-MATCHER")
                                            func)))
          (list func-pm-macro rhs args tests bindings (cdr lhses) (cdr rhses)
                pmstate)))))))


(defun test-declare (elt)
  (if (and (consp elt)
           (eq (car elt) 'declare))
      (list elt)
    nil))

(defun slice-clause (clause)
  (case (len clause)
    (0 (mv (er hard 'top-level "Empty clause") nil nil nil nil))
    (1 (mv (er hard 'top-level "Pattern needs a body") nil nil nil nil))
    (2 (mv (car clause) nil nil nil (cadr clause)))
    (3 (let ((decl (test-declare (cadr clause))))
         (if decl
             (mv (car clause) nil nil decl (caddr clause))
           (mv (car clause) nil (list (cadr clause)) nil (caddr clause)))))
    (otherwise
     (let* ((n (len clause))
            (pattern (car clause))
            (maybe-test-declare (test-declare (nth 1 clause)))
            (maybe-body-declare (test-declare (nth (- n 2) clause)))
            (body (nth (- n 1) clause))
            (tests (if maybe-test-declare
                       (if maybe-body-declare
                           (subseq clause 2 (- n 2))
                         (subseq clause 2 (- n 1)))
                     (if maybe-body-declare
                         (subseq clause 1 (- n 2))
                       (subseq clause 1 (- n 1))))))
       (mv pattern maybe-test-declare tests maybe-body-declare body)))))


(defun pattern-match-clauses (term clauses action)
  (if (atom clauses)
      nil
    (mv-let
     (pattern test-decl final-tests body-decl body)
     (slice-clause (car clauses))
     (cond ((and (eq pattern '&) (null final-tests))
            body)
           (t (pattern-bindings-list
               (list pattern) (list term) nil nil
               (list test-decl final-tests body-decl body
                     `(pattern-match ,term ,@(cdr clauses))
                     action)))))))


(defxdoc pattern-match-list
  :parents (pattern-match)
  :short "Pattern matching to a list of terms."
  :long "<p>Example:</p>

  @({
  (pattern-match-list
    (a b c d)
    (((cons !c x) 3 (list* !b y) x)
     (declare (ignore x))
     (foo y))
    (& default-value)))
  })

<p>@('pml') is a convenient abbreviaton of @('pattern-match-list').</p>

<p>Matches a list of terms to a list of pattern clauses.  See @(see
pattern-match) for more documentation of the pattern semantics.  The first
argument to pattern-match-list should be a list of input terms.  (For best
efficiency, these terms should be bound variables or simple constants, not
containing function calls.) Each subsequent argument should be a pattern
clause, consisting of a list of the following items:</p>

<ol>

<li>a list of patterns, the same length as the list of input terms</li>

<li>a declare form, used when evaluating the test forms (optional)</li>

<li>any number of test forms, which may use variables bound in the
pattern (optional)</li>

<li>a declare form whose scope is the body (optional)</li>

<li>the body, an expression to be evaluated if the pattern matches and all the
tests succeed.</li>

</ol>

<p>The final pattern clause may be of the form @('(& default-value)'); this is
an exception to the convention that the pattern list must be a list same length
as the input list, and it simply defines a default value for the pattern-match
clause, to be returned instead of nil when all patterns fail.</p>

<p>See also @(see pattern-matches-list), which simply tests whether or not a
certain pattern list matches the list of inputs.</p>")

(defun pattern-match-list-clauses (term-list clauses action)
  (if (atom clauses)
      nil
    (mv-let
     (patterns test-decl final-tests body-decl body)
     (slice-clause (car clauses))
     (cond ((and (eq patterns '&) (null final-tests))
            body)
           ((= (len patterns) (len term-list))
            (pattern-bindings-list
             patterns term-list nil nil
             (list test-decl final-tests body-decl  body
                   `(pattern-match-list ,term-list ,@(cdr clauses))
                   action)))
           (t (er hard 'top-level
                  "Lengths of term list ~x0 and pattern list ~x1 are unequal"
                  term-list patterns))))))

(defmacro pattern-match-list (term-list &rest clauses)
  (pattern-match-list-clauses term-list clauses 'execute-patmatch))

(defsection pml
  :parents (pattern-match)
  :short "@('pml') is an abbreviation for @('pattern-match-list')."
  :long "@(def pml)"

  (defmacro pml (term-list &rest clauses)
    `(pattern-match-list ,term-list . ,clauses)))

(defsection pattern-matches-list
  :parents (pattern-match)
  :short "Check that a list of terms matches a list of patterns."
  :long "<p>Example</p>

@({
  (pattern-matches-list
     (a b c)
     (x (cons x y) y))
})

<p>The example returns:</p>

<ul>
<li>@('t')  &mdash;  if @('b') equals the @(see cons) of @('a') and @('c'), or,</li>
<li>@('nil') &mdash; otherwise.</li>
</ul>

<p>See @(see pattern-match) and @(see pattern-match-list).</p>"

  (defmacro pattern-matches-list (term-list pattern-list)
    (pattern-match-list-clauses term-list `((,pattern-list t)) 'check-pattern-matches)))

(defmacro pattern-match (term &rest clauses)
  (pattern-match-clauses term clauses 'execute-patmatch))

(defsection pm
  :parents (pattern-match)
  :short "@('pm') is an abbreviation for @('pattern-match')."
  :long "@(def pm)"

  (defmacro pm (term &rest clauses)
    `(pattern-match ,term . ,clauses)))


(defsection pattern-matches
  :parents (pattern-match)
  :short "Check whether a term matches a pattern."
  :long "<p>Example:</p>

@({
    (pattern-matches x (cons a (cons b a)))
})

<p>The example is equivalent to the test</p>

@({
    (and (consp x)
         (consp (cdr x))
         (equal (car x) (cddr x)))
})

<p>See @(see pattern-match) and @(see pattern-match-list).</p>"

  (defmacro pattern-matches (term pattern)
    (pattern-match-clauses term `((,pattern t)) 'check-pattern-matches)))

(mutual-recursion
 (defun explode-term (term)
   (if (consp term)
       (if (eq (car term) 'quote)
           (list 'quote term)
         `(list ',(car term) ,@(explode-list (cdr term))))
     term))

 (defun explode-list (list)
   (if (atom list)
       nil
     (cons (explode-term (car list))
           (explode-list (cdr list))))))

(defmacro expl (tm)
  (explode-term tm))



(defun destructor-subst-list (term destructors)
  (if (atom destructors)
      nil
    (cons (if (consp (car destructors))
              (subst 'term term (explode-term (car destructors)))
            `(list ',(car destructors) term))
         (destructor-subst-list term (cdr destructors)))))

(defun destructor-list (destructors)
  (if (atom destructors)
      nil
    `((list ',(car destructors) term)
      ,@(destructor-list (cdr destructors)))))


(defsection def-pattern-match-constructor
  :parents (pattern-match)
  :short "Allow pattern-match to recognize a constructor."
  :long "<p>Example:</p>

@({
    (def-pattern-match-constructor cons consp (car cdr))
})

<p>For a constructor @('cname'), defines a macro named
@('cname-pattern-matcher') which will allow constructs using @('cname') to be
recognized by the pattern-match macro; see @(see pattern-match).  This macro
takes three arguments: the name of the constructor, which is the symbol that
pattern-match will recognize; the name of a recognizer function which returns
@('t') on objects produced by the constructor; and an ordered list of
destructor function names, which when applied to the constructed object return
the arguments to the constructor.</p>

<p>For example, say we define a function cons3 that combines three objects into
a triple.  We define a recognizer, cons3-p, for correctly-formed triples as
created by cons3, as well as three accessors, cons3-first, cons3-second,
cons3-third.  Now we'd like to have a pattern match expression like this</p>

@({
  (pattern-match x
         ((cons3 a b c) ... body ..)
         ... other clauses ...)
})

<p>resolve to this:</p>

@({
  (if (cons3-p x)
      (let ((a (cons3-first x))
            (b (cons3-second x))
            (c (cons3-third x)))
        ... body ...)
    ... other conditions ...)
})

<p>Therefore the pattern match macro must know that the recognizer for a cons3
object is cons3-p, and that the destructors are cons3-first, etc - we don't
want to have to write out those names anywhere in the untranslated body.  Our
solution is that when pattern-match sees a function symbol fun, it returns a
call to a macro named fun-pattern-matcher.  If this macro does not exist,
pattern-match will fail.  To easily define such macros, we provide
def-pattern-match-constructor, which takes as arguments the constructor name,
the recognizer name, and the ordered list of destructors.  For example, to
allow pattern-match to deal with cons3, we'd call</p>

@({
    (def-pattern-match-constructor cons3 cons3-p
      (cons3-first cons3-second cons3-third))
})

<p>Similarly for cons, the call would be</p>

@({
     (def-pattern-match-constructor cons consp (car cdr))
})

<p>but this is built into the pattern match book.</p>

<p>Pattern-matcher macros may be defined more flexibly without using
@('def-pattern-match-constructor') in order to support, for example, macros
with variable numbers of arguments; see @(see
constructor-pattern-match-macros).</p>")

(defmacro def-pattern-match-constructor (&rest args)
  (let* ((term (if (consp (car args)) (caar args) nil))
        (constructor (if term (cadr args) (car args)))
        (recognizer (if term
                        (if (eq (caddr args) :unconditional)
                            nil
                          (if (consp (caddr args))
                              (subst 'term term (explode-term (caddr args)))
                            `(list ',(caddr args) term)))
                      (if (eq (cadr args) :unconditional)
                          nil
                        `(list ',(cadr args) term))))
        (destructors (if term
                         (cons 'list (destructor-subst-list term (cadddr args)))
                       (cons 'list (destructor-list (caddr args)))))
        (err-string-nargs
         (concatenate 'string
                      "Wrong number of arguments to "
                      (symbol-name constructor)
                      " in pattern matching: ~x0~%"))
        (err-string-truelist
         (concatenate 'string "Badly formed expression: ~x0~%")))

    `(defmacro ,(intern-in-package-of-symbol
                 (concatenate 'string (symbol-name constructor)
                                     "-PATTERN-MATCHER")
                 (if (equal (symbol-package-name constructor) "COMMON-LISP")
                     'acl2::bla
                   constructor))
       (term args tests bindings lhses rhses pmstate)
       (cond ((not (true-listp args))
              (er hard 'top-level ,err-string-truelist (cons ',constructor args)))
             ((not (= (len args) ,(1- (len destructors))))
              (er hard 'top-level ,err-string-nargs (cons ',constructor args)))
             (t
              (let ((rhses
                     (append ,destructors
                             rhses))
                    ,@(if recognizer
                          `((tests (cons ,recognizer tests)))
                        nil)
                    (lhses (append args lhses)))
                (pattern-bindings-list lhses rhses tests bindings pmstate)))))))



(defsection constructor-pattern-match-macros
  :parents (pattern-match)
  :short "How to write pattern-match macros for custom constructors."
  :long "<p>Here we discuss how constructor @(see pattern-match) macros work in
conjunction with pattern-match.  In most cases the user does not need to be
concerned with the internals discussed here; see @(see
def-pattern-match-constructor) for an easy way to get pattern-match to
recognize a user-defined form.</p>

<p>The trick behind pattern-match is that whenever a constructor @('cname') is
seen in a pattern, a call to the macro named @('cname-pattern-matcher') is
returned and macro expansion continues by expanding that macro.  Because of
this, all the unprocessed parts of the original pattern-match call must be
passed through that macro.  By the design of the framework, the constructor
macro will only operate on a few of the arguments given to it, passing the rest
through to the main function that performs pattern matching,
@('pattern-bindings-list').</p>

<p>The arguments given to the constructor's macro are</p>

@({
    (term args tests bindings lhses rhses pmstate)
})

<p>The arguments that @('pattern-bindings-list') takes are</p>

@({
    (lhses rhses tests bindings pmstate)
})

<p>The argument list of @('pattern-bindings-list') is a subset of that of the
constructor's macro.  We will discuss how to form the arguments for
@('pattern-bindings-list') from those given to the constructor macro.</p>

<p>The constructor macro is responsible for error handling in the case of a
nonsensical invocation of the constructor (primarily, one with the wrong number
of arguments), adding appropriate tests to determine whether @('term') can
match the pattern, and ``lining up'' the arguments given to the constructor in
the pattern with the appropriate destructors applied to the term in
question.</p>

<p>We will go through the arguments given to the macro and outline what needs
to be done with them to fulfill the above obligations.</p>

<p>@('term') is a term which should evaluate to the current part of the input
that we are trying to match.  If the original term given as input to pattern
match was x, then term may be something like @('(car (nth 4 (cdr x)))').
Therefore we need to add tests to determine whether this is of the correct form
to be matched to something created by our constructor, and we need to apply the
correct destructors to it to break it down for further matching.</p>

<p>@('args') is the list of arguments given to the constructor in the pattern
that we're matching to.  The whole pattern that @('term') is supporsed to match
is our constructor @('cname') applied to @('args').  For error checking we need
to ensure that @('args') is the correct length for the call to our constructor
to make sense.  It is also helpful to ensure that @('args') is a true-list and
issue a helpful error message if not.  Each element of @('args') must also be
paired with an application of a destructor to @('term') to continue pattern
matching.  If, as is usually the case, the arguments we're expecting are to be
read as subpatterns, the best approach is not to examine them individually but
to let pattern-bindings-list do the real work.</p>

<p>@('tests') is an accumulated list of tests to be applied to the input to
determine whether it matches the pattern.  We need to prepend to this list any
necessary tests on @('term') so as to determine whether it could be formed by
our constructor.</p>

<p>@('bindings') is an accumulated list of variables that will be bound to
applications of destructors to the input term.  While the results of the
processing that our macro does will have a direct effect on this list, most of
the time it should be passed through to @('pattern-bindings-list') and we
should instead manipulate @('lhses') and @('rhses'):</p>

<p>@('lhses') and @('rhses') are lists of, respectively, subpatterns of the
top-level pattern that we're processing and corresponding subterms of the input
term that will be matched to the patterns.  In most cases what we'll do is
prepent @('args') to @('lhses') while prepending a list of each of our
destructors applied to @('term') to @('rhses').  @('pattern-bindings-list')
will then handle the details of variable bindings and recursive subpattern
matching as determined by the contents of @('lhses').  Each macro must maintain
the invariant that @('lhses') and @('rhses') are the same length; if this isn't
the case there are probably other things going wrong as well.  The intuition
behind these names is that eventually patterns in @('lhses') break down to
variables, which are bound to corresponding subterms broken down from elements
of @('rhses').  We're using LHS and RHS here as in an assignment statement in
some imperative language, as opposed to the sense used when talking about a
rewrite rule.</p>

<p>@('pmstate') contains the expression to be evaluated if the pattern matches,
the list of tests to be tried before confirming a match, declarations, the rest
of the clauses to match to in case this match fails, and the name of the macro
to pass the final results to.  These are grouped together specifically because
they don't have to do with the actual pattern-matching but must be kept intact
through the various iterations of macro expansion.  This argument should
*always* be passed through intact to pattern-bindings-list unless you're trying
to really confuse your users.</p>

<p>An example of a very typical constructor macro is the one for cons, which is
automatically generated by @('def-pattern-match-constructor'):</p>

 @({
 (defmacro
   cons-pattern-matcher
   (term args tests bindings lhses rhses pmstate)
   (cond
    ;; First check args for well-formedness: it should always be a true-list of
    ;; length 2, since any other argument list to cons is ill-formed.
    ((not (true-listp args))
     (er hard 'top-level ``badly formed expression: ~~x0~~%''
         (cons 'cons args)))
    ((not (= (len args) 2))
     (er hard 'top-level
         ``Wrong number of arguments to CONS in pattern matching: ~~x0~~%''
         (CONS 'CONS ARGS)))
    (t (let
        ;; Push destructor applications (car term) and (cdr term) onto rhses
        ((rhses (append (list (list 'car term) (list 'cdr term)) rhses))
         ;; Push the args onto lhses (they must occur in the order corresponding
         ;; to the order of the destructor calls pushed onto rhses.)
         (lhses (append args lhses))
         ;; Push a test that term is consp onto tests
         (tests (cons (list 'consp term) tests)))
        ;; Finally call pattern-bindings-list again.
        (pattern-bindings-list lhses rhses tests bindings pmstate)))))
 })

<p>If there are no errors, this simply makes three changes to the existing
arguments: it prepends the two subterms @('(car term)') and @('(cdr term)')
onto @('rhses') and the list of arguments to @('lhses') and adds the test
@('(consp term)') to tests.  It then calls pattern-bindings-list.</p>

<p>The macro for list works the same way, but could not have been generated by
@('def-pattern-match-constructor') because it handles variable length argument
lists.  It again simply prepends all arguments to @('lhses'), prepends a list
of applications of destructors to the input term to rhses (try evaluating
@('(list-of-nths 0 5 'x)') to see the resulting form), and tests whether the
input term is of a suitable form, in this case whether it is a true-list of the
same length as the argument list.</p>

 @({
 (defmacro list-pattern-matcher
   (term args tests bindings lhses rhses pmstate)
   ;; Ensure that args is a true-list; it may be any length.
   (if (not (true-listp args))
       (er hard 'top-level ``Badly formed expression: ~~x0~~%''
           (cons 'list args))
     (let
         ;; list-of-nths produces a list of calls to nth, from (nth 0 term) up
         ;; to (nth (- (length args) 1) term).
         ((rhses (append (list-of-nths 0 (length args) term) rhses))
          ;; push args onto lhses
          (lhses (append args lhses))
          ;; Require that term is a true-list with length corresponding to that
          ;; of args.
          (tests (append `((true-listp ,term)
                           (= (len ,term) ,(length args)))
                         tests)))
       (pattern-bindings-list lhses rhses tests bindings pmstate))))
 })

<p>A nonstandard, but still correct, example is the one for list*, which
instead of doing the processing itself replaces its pattern with an equivalent
cons structure so that the cons macro will do all the work: to illustrate what
is prepended to @('lhses'), try running @('(list*-macro (list 'a 'b 'c 'd))').
In this case no test needs to be added because the cons macro takes care of it.
Note that we could easily cause an infinite loop in macro expansion by abusing
this type of thing and, for example, pushing a new @('list*') pattern onto
lhses.</p>

 @({
 (defmacro list*-pattern-matcher
   (term args tests bindings lhses rhses pmstate)
   ;; Check that args is a true-listp.
   ;; If this is counterintuitive, consider that this would suggest syntax such
   ;; as (list* a b . c).
   (if (not (true-listp args))
       (er hard 'top-level ``Badly formed expression: ~~x0~~%''
           (cons 'list* args))
     (let
         ;; Just push term onto rhses
         ((rhses (cons term rhses))
          ;; list*-macro is the very function that list* uses to expand an
          ;; invocation into a nest of conses.  Since we have a cons pattern
          ;; matcher already, we just take advantage of this.
          (lhses (cons (list*-macro args) lhses)))
       ;; No additional tests are necessary - we trust in cons-pattern-matcher
       ;; to take care of that.
       (pattern-bindings-list lhses rhses tests bindings pmstate))))
 })

<p>Another nonstandard example is raw-pattern-matcher, which reverts the
behavior of pattern-match to that of case-match for the term inside; in fact,
it just calls the function that does the work for case-match -
@('match-tests-and-bindings') - and uses its results.  In this case, since the
argument to our constructor is not taken to be a subpattern of the form handled
by @('pattern-bindings-list'), we manipulate @('bindings') directly rather than
dealing with @('lhses') and @('rhses').  It is fortunate that the form of the
tests and bindings variables for @('match-tests-and-bindings') is the same as
ours or we would need to do more processing of them.</p>

 @({
 (defmacro raw-pattern-matcher
   (term args tests bindings lhses rhses pmstate)
   ;; Args should be a list of length 1 - just a pattern.
   (if (or (atom args)
           (cdr args))
       (er hard 'top-level ``Badly formed expression: ~~x0~~%''
           (cons 'raw args))
     ;; match-tests-and-bindings takes a term, a case-match pattern, and a list
     ;; of tests and bindings; it returns a new version of tests and bindings
     ;; including the ones necessary to match the term to the pattern.
     (mv-let (tests bindings)
             (match-tests-and-bindings term (car args) tests bindings)
             ;; We then pass the new tests and bindings to
             ;; pattern-bindings-list.
             (pattern-bindings-list lhses rhses tests bindings pmstate))))
  })

<p>Also try looking at the definitions for @('bind-pattern-matcher'),
@('any-pattern-matcher'), and both @('force-pattern-matcher') and
@('force-match-remove-tests-pattern-matcher') as further nonstandard
examples.</p>")

(def-pattern-match-constructor cons consp (car cdr))


(defun list-of-nths (n len term)
  (if (= n len)
      nil
    `((nth ,n ,term)
      ,@(list-of-nths (1+ n) len term))))

(defmacro list-pattern-matcher
  (term args tests bindings lhses rhses pmstate)
  ;; Ensure that args is a true-list; it may be any length.
  (if (not (true-listp args))
      (er hard 'top-level "Badly formed expression: ~x0~%"
          (cons 'list args))
    (let
        ;; list-of-nths produces a list of calls to nth, from (nth 0 term) up
        ;; to (nth (- (length args) 1) term).
        ((rhses (append (list-of-nths 0 (length args) term) rhses))
         ;; push args onto lhses
         (lhses (append args lhses))
         ;; Require that term is a true-list with length corresponding to that
         ;; of args.
         (tests (append `((true-listp ,term)
                          (= (len ,term) ,(length args)))
                        tests)))
      (pattern-bindings-list lhses rhses tests bindings pmstate))))


(defmacro list*-pattern-matcher
  (term args tests bindings lhses rhses pmstate)
  ;; Check that args is a true-listp.
  ;; If this is counterintuitive, consider that this would suggest syntax such
  ;; as (list* a b . c).
  (if (not (true-listp args))
      (er hard 'top-level "Badly formed expression: ~x0~%"
          (cons 'list* args))
    (let
        ;; Just push term onto rhses
        ((rhses (cons term rhses))
         ;; list*-macro is the very function that list* uses to expand an
         ;; invocation into a nest of conses.  Since we have a cons pattern
         ;; matcher already, we just take advantage of this.
         (lhses (cons (list*-macro args) lhses)))
      ;; No additional tests are necessary - we trust in cons-pattern-matcher
      ;; to take care of that.
      (pattern-bindings-list lhses rhses tests bindings pmstate))))




(defmacro raw-pattern-matcher
  (term args tests bindings lhses rhses pmstate)
  ;; Args should be a list of length 1 - just a pattern.
  (if (or (atom args)
          (cdr args))
      (er hard 'top-level "Badly formed expression: ~x0~%"
          (cons 'raw args))
    ;; match-tests-and-bindings takes a term, a case-match pattern, and a list
    ;; of tests and bindings; it returns a new version of tests and bindings
    ;; including the ones necessary to match the term to the pattern.
    (mv-let (tests bindings)
            (match-tests-and-bindings term (car args) tests bindings)
            ;; We then pass the new tests and bindings to
            ;; pattern-bindings-list.
            (pattern-bindings-list lhses rhses tests bindings pmstate))))


(defmacro bind-pattern-matcher
  (term args tests bindings lhses rhses pmstate)
  (if (not (and (true-listp args)
                (equal (len args) 2)
                (symbolp (car args))))
      (er hard 'top-level "Badly formed expression: ~x0~%"
          (cons 'bind args))
    (let ((rhses (cons term rhses))
          (lhses (cons (cadr args) lhses))
          (bindings (cons (list (car args) term) bindings)))
      (pattern-bindings-list lhses rhses tests bindings
                             pmstate))))


(defun equal-any-list (term args)
  (if (endp args)
      nil
    (cons `(equal ,term ,(car args))
          (equal-any-list term (cdr args)))))

(defmacro any-pattern-matcher
  (term args tests bindings lhses rhses pmstate)
  (if (not (true-listp args))
      (er hard 'top-level "Badly formed expression: ~x0~%"
          (cons 'any args))
    (let ((tests (cons `(or ,@(equal-any-list term args))
                       tests)))
      (pattern-bindings-list lhses rhses tests bindings
                             pmstate))))


(def-pattern-match-constructor (x) acons
  (and (consp x) (consp (car x)))
  (caar cdar cdr))


(defmacro force-pattern-matcher
  (term args tests bindings lhses rhses pmstate)
  (if (not (true-listp args))
      (er hard 'top-level "Badly formed expression: ~x0~%"
          (cons 'list args))
    (let ((lhses (cons (car args)
                       (cons '(force-match-remove-tests) lhses)))
          (rhses (cons term
                       (cons '(force-match-remove-tests) rhses)))
          (tests (cons '(nil . force-match-remove-tests) tests)))
      (pattern-bindings-list lhses rhses tests bindings pmstate))))


(defun remove-up-to (item list)
  (if (atom list)
      nil
    (if (equal (car list) item)
        (cdr list)
      (remove-up-to item (cdr list)))))

(defmacro force-match-remove-tests-pattern-matcher
  (term args tests bindings lhses rhses pmstate)
  (if (or args (not (equal term '(force-match-remove-tests))))
      (er hard 'top-level
          "Don't use force-match-remove-tests manually!~%")
    (let ((tests (remove-up-to '(nil . force-match-remove-tests) tests)))
      (pattern-bindings-list lhses rhses tests bindings pmstate))))