forked from acl2/acl2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
basis-b.lisp
4307 lines (3712 loc) · 166 KB
/
basis-b.lisp
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
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
; ACL2 Version 8.1 -- A Computational Logic for Applicative Common Lisp
; Copyright (C) 2018, Regents of the University of Texas
; This version of ACL2 is a descendent of ACL2 Version 1.9, Copyright
; (C) 1997 Computational Logic, Inc. See the documentation topic NOTE-2-0.
; This program is free software; you can redistribute it and/or modify
; it under the terms of the LICENSE file distributed with ACL2.
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; LICENSE for more details.
; Written by: Matt Kaufmann and J Strother Moore
; email: [email protected] and [email protected]
; Department of Computer Science
; University of Texas at Austin
; Austin, TX 78712 U.S.A.
; When we are ready to verify termination in this and later files, we should
; consider changing null to endp in a number of functions.
(in-package "ACL2")
(defun enforce-redundancy-er-args (event-form-var wrld-var)
(list "Enforce-redundancy is active; see :DOC set-enforce-redundancy and ~
see :DOC redundant-events. However, the following event ~@0:~|~%~x1"
`(if (and (symbolp (cadr ,event-form-var))
(decode-logical-name (cadr ,event-form-var) ,wrld-var))
"conflicts with an existing event of the same name"
"is not redundant")
event-form-var))
(defmacro enforce-redundancy (event-form ctx wrld form)
(let ((var 'redun-check-var))
`(let ((,var (and (not (eq (ld-skip-proofsp state)
'include-book))
(cdr (assoc-eq :enforce-redundancy
(table-alist 'acl2-defaults-table
,wrld))))))
(cond ((eq ,var t)
(check-vars-not-free
(,var)
(er soft ,ctx
,@(enforce-redundancy-er-args
event-form wrld))))
(t (pprogn (cond (,var (check-vars-not-free
(,var)
(warning$ ,ctx "Enforce-redundancy"
,@(enforce-redundancy-er-args
event-form wrld))))
(t state))
(check-vars-not-free
(,var)
,form)))))))
(defun global-set (var val wrld)
(declare (xargs :guard (and (symbolp var)
(plist-worldp wrld))))
(putprop var 'global-value val wrld))
(defun tilde-@-illegal-variable-or-constant-name-phrase (name)
; Assume that legal-variable-or-constant-namep has failed on name.
; We return a phrase that when printed with ~@0 will complete the
; sentence "Variable names must ...". Observe that the sentence
; could be "Constant names must ...".
(cond ((not (symbolp name)) "be symbols")
((keywordp name) "not be in the KEYWORD package")
((and (legal-constantp1 name)
(equal (symbol-package-name name) *main-lisp-package-name*))
(cons "not be in the main Lisp package, ~x0"
(list (cons #\0 *main-lisp-package-name*))))
((and (> (length (symbol-name name)) 0)
(eql (char (symbol-name name) 0) #\&))
"not start with ampersands")
((and (not (legal-constantp1 name))
(member-eq name *common-lisp-specials-and-constants*))
"not be among certain symbols from the main Lisp package, namely, the ~
value of the list *common-lisp-specials-and-constants*")
((and (not (legal-constantp1 name))
(equal (symbol-package-name name) *main-lisp-package-name*)
(not (member-eq name *common-lisp-symbols-from-main-lisp-package*)))
"either not be in the main Lisp package, or else must be among the ~
imports into ACL2 from that package, namely, the list ~
*common-lisp-symbols-from-main-lisp-package*")
(t "be approved by LEGAL-VARIABLE-OR-CONSTANT-NAMEP and this ~
one wasn't, even though it passes all the checks known to ~
the diagnostic function ~
TILDE-@-ILLEGAL-VARIABLE-OR-CONSTANT-NAME-PHRASE")))
(defun legal-constantp (name)
; A name may be declared as a constant if it has the syntax of a
; variable or constant (see legal-variable-or-constant-namep) and
; starts and ends with a *.
; WARNING: Do not confuse this function with defined-constant.
(eq (legal-variable-or-constant-namep name) 'constant))
(defun genvar1 (pkg-witness char-lst avoid-lst cnt)
; This function generates a symbol in the same package as the symbol
; pkg-witness that is guaranteed to be a legal-variablep and not in avoid-lst.
; We form a symbol by concatenating char-lst and the decimal representation of
; the natural number cnt. Observe the guard below. Since guards are not
; checked in :program code, the user must ensure upon calling this
; function that pkg-witness is a symbol in some package other than the main
; lisp package or the keyword package and that char-lst is a list of characters
; not beginning with * or &. Given that guard, there must exist a sufficiently
; large cnt to make our generated symbol be in the package of pkg-witness (a
; finite number of generated symbols might have been interned in one of the
; non-variable packages).
(declare (xargs :guard (and (let ((p (symbol-package-name pkg-witness)))
(and (not (equal p "KEYWORD"))
(not (equal p *main-lisp-package-name*))))
(consp char-lst)
(not (eql (car char-lst) #\*))
(not (eql (car char-lst) #\&)))))
(let ((sym (intern-in-package-of-symbol
(coerce
(append char-lst
(explode-nonnegative-integer cnt 10 nil))
'string)
pkg-witness)))
(cond ((or (member sym avoid-lst)
; The following call of legal-variablep could soundly be replaced by
; legal-variable-or-constant-namep, given the guard above, but we keep it
; as is for robustness.
(not (legal-variablep sym)))
(genvar1 pkg-witness char-lst avoid-lst (1+ cnt)))
(t sym))))
(defun genvar (pkg-witness prefix n avoid-lst)
; This is THE function that ACL2 uses to generate new variable names.
; Prefix is a string and n is either nil or a natural number. Together we
; call prefix and n the "root" of the variable we generate.
; We generate from prefix a legal variable symbol in the same package as
; pkg-witness that does not occur in avoid-lst. If n is nil, we first try the
; symbol with symbol-name prefix first and otherwise suffix prefix with
; increasingly large naturals (starting from 0) to find a suitable variable.
; If n is non-nil it had better be a natural and we immediately begin trying
; suffixes from there. Since no legal variable begins with #\* or #\&, we tack
; a #\V on the front of our prefix if prefix starts with one of those chars.
; If prefix is empty, we use "V".
; Note: This system will eventually contain a lot of code to generate
; "suggestive" variable names. However, we make the convention that
; in the end every variable name generated is generated by this
; function. Thus, all other code associated with variable name
; generation is heuristic if this one is correct.
(let* ((pkg-witness (cond ((let ((p (symbol-package-name pkg-witness)))
(or (equal p "KEYWORD")
(equal p *main-lisp-package-name*)))
; If pkg-witness is in an inappropriate package, we default it to the
; "ACL2" package.
'genvar)
(t pkg-witness)))
(sym (if (null n) (intern-in-package-of-symbol prefix pkg-witness) nil))
(cnt (if n n 0)))
(cond ((and (null n)
(legal-variablep sym)
(not (member sym avoid-lst)))
sym)
(t (let ((prefix (coerce prefix 'list)))
(cond ((null prefix) (genvar1 pkg-witness '(#\V) avoid-lst cnt))
((and (consp prefix)
(or (eql (car prefix) #\*)
(eql (car prefix) #\&)))
(genvar1 pkg-witness (cons #\V prefix) avoid-lst cnt))
(t (genvar1 pkg-witness prefix avoid-lst cnt))))))))
(defun gen-formals-from-pretty-flags1 (pretty-flags i avoid)
(cond ((endp pretty-flags) nil)
((eq (car pretty-flags) '*)
(let ((xi (pack2 'x i)))
(cond ((member-eq xi avoid)
(let ((new-var (genvar 'genvar ;;; ACL2 package
"GENSYM"
1
avoid)))
(cons new-var
(gen-formals-from-pretty-flags1
(cdr pretty-flags)
(+ i 1)
(cons new-var avoid)))))
(t (cons xi
(gen-formals-from-pretty-flags1
(cdr pretty-flags)
(+ i 1)
avoid))))))
(t (cons (car pretty-flags)
(gen-formals-from-pretty-flags1
(cdr pretty-flags)
(+ i 1)
avoid)))))
(defun gen-formals-from-pretty-flags (pretty-flags)
; Given a list of prettyified stobj flags, e.g., '(* * $S * STATE) we
; generate a proposed list of formals, e.g., '(X1 X2 $S X4 STATE). We
; guarantee that the result is a list of symbols as long as
; pretty-flags. Furthermore, a non-* in pretty-flags is preserved in
; the same slot in the output. Furthermore, the symbol generated for
; each * in pretty-flags is unique and not among the symbols in
; pretty-flags. Finally, STATE is not among the symbols we generate.
(gen-formals-from-pretty-flags1 pretty-flags 1 pretty-flags))
(defun defstub-body (output)
; This strange little function is used to turn an output signature
; spec (in either the old or new style) into a term. It never causes
; an error, even if output is ill-formed! What it returns in that
; case is irrelevant. If output is well-formed, i.e., is one of:
; output result
; * nil
; x x
; state state
; (mv * state *) (mv nil state nil)
; (mv x state y) (mv x state y)
; it replaces the *'s by nil and otherwise doesn't do anything.
(cond ((atom output)
(cond ((equal output '*) nil)
(t output)))
((equal (car output) '*)
(cons nil (defstub-body (cdr output))))
(t (cons (car output) (defstub-body (cdr output))))))
(defun collect-non-x (x lst)
; This function preserves possible duplications of non-x elements in lst.
; We use this fact when we check the legality of signatures.
(declare (xargs :guard (true-listp lst)))
(cond ((endp lst) nil)
((equal (car lst) x)
(collect-non-x x (cdr lst)))
(t (cons (car lst) (collect-non-x x (cdr lst))))))
#+acl2-loop-only
(defmacro defproxy (name args-sig arrow body-sig)
(cond
((not (and (symbol-listp args-sig)
(symbolp arrow)
(equal (symbol-name arrow) "=>")))
(er hard 'defproxy
"Defproxy must be of the form (proxy name args-sig => body-sig), ~
where args-sig is a true-list of symbols. See :DOC defproxy."))
(t
(let ((formals (gen-formals-from-pretty-flags args-sig))
(body (defstub-body body-sig))
(stobjs (collect-non-x '* args-sig)))
`(defun ,name ,formals
(declare (xargs :non-executable :program
:mode :program
,@(and stobjs `(:stobjs ,stobjs)))
(ignorable ,@formals))
; The form of the body below is dictated by function throw-nonexec-error-p.
; Notice that we do not pass the formals to throw-nonexec-error as we do in
; defun-nx-fn, because if the formals contain a stobj then we would violate
; stobj restrictions, which are checked for non-executable :program mode
; functions.
(prog2$ (throw-nonexec-error ',name nil)
,body))))))
#-acl2-loop-only
(defmacro defproxy (name args-sig arrow body-sig)
; Note that a defproxy redefined using encapsulate can generate a warning in
; CLISP (see comment about CLISP in with-redefinition-suppressed), because
; indeed there are two definitions being made for the same name. However, the
; definition generated for a function by encapsulate depends only on the
; function's signature, up to renaming of formals; see the #-acl2-loop-only
; definition of encapsulate. So this redefinition is as benign as the
; redefinition that occurs in raw Lisp with a redundant defun.
`(defstub ,name ,args-sig ,arrow ,body-sig))
; We now use encapsulate to implement defstub. It is handy to do so here,
; rather than in other-events.lisp, since the raw Lisp definition of defproxy
; uses defstub.
(defun defstub-ignores (formals body)
; The test below is sufficient to ensure that the set-difference-equal
; used to compute the ignored vars will not cause an error. We return
; a true list. The formals and body will be checked thoroughly by the
; encapsulate, provided we generate it! Provided they check out, the
; result returned is the list of ignored formals.
(if (and (symbol-listp formals)
(or (symbolp body)
(and (consp body)
(symbol-listp (cdr body)))))
(set-difference-equal
formals
(if (symbolp body)
(list body)
(cdr body)))
nil))
(defun defstub-fn (name args)
(let ((len-args (length args)))
(cond
((not (or (eql len-args 2)
(and (eql len-args 3)
(symbolp (cadr args))
(equal (symbol-name (cadr args)) "=>"))))
`(er soft 'defstub
"Defstub must be of the form (defstub name formals args-sig) or ~
(defstub name args-sig => body-sig). See :DOC defstub."))
((and (eql len-args 2)
(not (and (symbol-listp (car args))
(or (symbolp (cadr args))
(symbol-listp (cadr args))))))
`(er soft 'defstub
"For calls of the form (defstub name formals args-sig), formals ~
must be a true-list of symbols and args-sig must be a symbol or a ~
true-list of symbols. See :DOC defstub."))
((and (eql len-args 3)
(not (symbol-listp (car args))))
`(er soft 'defstub
"For calls of the form (defstub name args-sig => body-sig), ~
args-sig must be a true-list of symbols. See :DOC defstub."))
((eql len-args 2) ; old style
(let* ((formals (car args))
(body (cadr args))
(mv-p (and (consp body)
(eq (car body) 'mv))))
`(encapsulate
((,name ,formals ,body))
(logic)
(local
(defun ,name ,formals
(declare (ignorable ,@formals))
,(if mv-p
(let* ((output-vars (cdr body))
(posn (position-eq 'state output-vars))
(lst
(if posn
(append (make-list posn :initial-element t)
(cons 'state
(make-list (- (length output-vars)
(1+ posn)))))
(make-list (length output-vars)
:initial-element t))))
`(mv ,@lst))
(if (eq body 'state)
'state
t))))
,@(and mv-p
`((defthm ,(packn-pos (list "TRUE-LISTP-" name)
name)
(true-listp (,name ,@formals))
:rule-classes :type-prescription))))))
(t (let* ((args-sig (car args))
(body-sig (caddr args))
(formals (gen-formals-from-pretty-flags args-sig))
(body (defstub-body body-sig))
(ignores (defstub-ignores formals body))
(stobjs (collect-non-x '* args-sig)))
`(encapsulate
(((,name ,@args-sig) => ,body-sig))
(logic)
(local
(defun ,name ,formals
(declare (ignore ,@ignores)
(xargs :stobjs ,stobjs))
,body))
,@(and (consp body-sig)
(eq (car body-sig) 'mv)
`((defthm ,(packn-pos (list "TRUE-LISTP-" name)
name)
(true-listp (,name ,@formals))
:rule-classes :type-prescription)))))))))
(defmacro defstub (name &rest args)
(defstub-fn name args))
;; Historical Comment from Ruben Gamboa:
;; I changed the primitive guard for the < function, and the
;; complex function. Added the functions complexp, realp, and floor1.
;; Historical Comment from Ruben Gamboa:
;; I subsequently changed this to add the non-standard functions
;; standardp, standard-part and i-large-integer. I had some
;; questions as to whether these functions should appear on this list
;; or not. After considering carefully, I decided that was the right
;; course of action. In addition to adding them to the list below, I
;; also add them to *non-standard-primitives* which is a special list
;; of non-standard primitives. Functions in this list are considered
;; to be constrained. Moreover, they are given the value t for the
;; property 'unsafe-induction so that recursion and induction are
;; turned off for terms built from these functions.
(defconst *primitive-formals-and-guards*
; Keep this in sync with ev-fncall-rec-logical and type-set-primitive, and with
; the documentation and "-completion" axioms of the primitives. Also be sure
; to define a *1* function for each function in this list that is not a member
; of *oneify-primitives*.
; WARNING: for each primitive below, primordial-world puts a 'stobjs-in that is
; a list of nils of the same length as its formals, and a 'stobjs-out of
; '(nil). Revisit that code if you add a primitive that involves stobjs!
; WARNING: Just below you will find another list, *primitive-monadic-booleans*
; that lists the function names from this list that are monadic booleans. The
; names must appear in the same order as here!
'((acl2-numberp (x) 't)
(bad-atom<= (x y) (if (bad-atom x) (bad-atom y) 'nil))
(binary-* (x y) (if (acl2-numberp x) (acl2-numberp y) 'nil))
(binary-+ (x y) (if (acl2-numberp x) (acl2-numberp y) 'nil))
(unary-- (x) (acl2-numberp x))
(unary-/ (x) (if (acl2-numberp x) (not (equal x '0)) 'nil))
(< (x y)
; We avoid the temptation to use real/rationalp below, since it is a macro.
(if #+:non-standard-analysis (realp x)
#-:non-standard-analysis (rationalp x)
#+:non-standard-analysis (realp y)
#-:non-standard-analysis (rationalp y)
'nil))
(car (x) (if (consp x) 't (equal x 'nil)))
(cdr (x) (if (consp x) 't (equal x 'nil)))
(char-code (x) (characterp x))
(characterp (x) 't)
(code-char (x) (if (integerp x) (if (< x '0) 'nil (< x '256)) 'nil))
(complex (x y)
(if #+:non-standard-analysis (realp x)
#-:non-standard-analysis (rationalp x)
#+:non-standard-analysis (realp y)
#-:non-standard-analysis (rationalp y)
'nil))
(complex-rationalp (x) 't)
#+:non-standard-analysis
(complexp (x) 't)
(coerce (x y)
(if (equal y 'list)
(stringp x)
(if (equal y 'string)
(character-listp x)
'nil)))
(cons (x y) 't)
(consp (x) 't)
(denominator (x) (rationalp x))
(equal (x y) 't)
#+:non-standard-analysis
(floor1 (x) (realp x))
(if (x y z) 't)
(imagpart (x) (acl2-numberp x))
(integerp (x) 't)
(intern-in-package-of-symbol (str sym) (if (stringp str) (symbolp sym) 'nil))
(numerator (x) (rationalp x))
(pkg-imports (pkg) (stringp pkg))
(pkg-witness (pkg) (if (stringp pkg) (not (equal pkg '"")) 'nil))
(rationalp (x) 't)
#+:non-standard-analysis
(realp (x) 't)
(realpart (x) (acl2-numberp x))
(stringp (x) 't)
(symbol-name (x) (symbolp x))
(symbol-package-name (x) (symbolp x))
(symbolp (x) 't)
#+:non-standard-analysis
(standardp (x) 't)
#+:non-standard-analysis
(standard-part (x) ; If (x) is changed here, change cons-term1-cases.
(acl2-numberp x))
#+:non-standard-analysis
(i-large-integer () 't)))
(defconst *primitive-monadic-booleans*
; This is the list of primitive monadic boolean function symbols. Each
; function must be listed in *primitive-formals-and-guards* and they should
; appear in the same order. (The reason order matters is simply to make it
; easier to check at the end of boot-strap that we have included all the
; monadic booleans.)
'(acl2-numberp
characterp
complex-rationalp
#+:non-standard-analysis
complexp
consp
integerp
rationalp
#+:non-standard-analysis
realp
stringp
symbolp
#+:non-standard-analysis
standardp))
#+:non-standard-analysis
(defconst *non-standard-primitives*
'(standardp
standard-part
i-large-integer))
(defun cons-term1-cases (alist)
; Initially, alist is *primitive-formals-and-guards*.
(cond ((endp alist) nil)
((member-eq (caar alist)
'(if ; IF is handled directly in cons-term1-body.
bad-atom<= pkg-imports pkg-witness))
(cons-term1-cases (cdr alist)))
(t (cons (let* ((trip (car alist))
(fn (car trip))
(formals (cadr trip))
(guard (caddr trip)))
(list
fn
(cond #+:non-standard-analysis
((eq fn 'i-large-integer)
nil) ; fall through in cons-term1-body
#+:non-standard-analysis
((eq fn 'standardp)
'(kwote t))
#+:non-standard-analysis
((eq fn 'standard-part)
(assert$
(eq (car formals) 'x)
`(and ,guard ; a term in variable x
(kwote ,@formals))))
((equal guard *t*)
`(kwote (,fn ,@formals)))
((or (equal formals '(x))
(equal formals '(x y)))
`(and ,guard
(kwote (,fn ,@formals))))
(t (case-match formals
((f1)
`(let ((,f1 x))
(and ,guard
(kwote (,fn ,@formals)))))
((f1 f2)
`(let ((,f1 x)
(,f2 y))
(and ,guard
(kwote (,fn ,@formals)))))
(& (er hard! 'cons-term1-cases
"Unexpected formals, ~x0"
formals)))))))
(cons-term1-cases (cdr alist))))))
(defconst *cons-term1-alist*
(cons-term1-cases *primitive-formals-and-guards*))
(defmacro cons-term1-body ()
`(let ((x (unquote (car args)))
(y (unquote (cadr args))))
(or (case fn
,@*cons-term1-alist*
(if (kwote (if x y (unquote (caddr args)))))
(not (kwote (not x))))
(cons fn args))))
(defun quote-listp (l)
(declare (xargs :guard (true-listp l)))
(cond ((null l) t)
(t (and (quotep (car l))
(quote-listp (cdr l))))))
(defun cons-term1 (fn args)
(declare (xargs :guard (and (pseudo-term-listp args)
(quote-listp args))))
(cons-term1-body))
(defun cons-term (fn args)
(declare (xargs :guard (pseudo-term-listp args)))
(cond ((quote-listp args)
(cons-term1 fn args))
(t (cons fn args))))
(defmacro cons-term* (fn &rest args)
`(cons-term ,fn (list ,@args)))
(defmacro mcons-term (fn args)
; The "m" in "mcons-term" is for "maybe fast". Some calls of this macro can
; probably be replaced with fcons-term.
`(cons-term ,fn ,args))
(defmacro mcons-term* (fn &rest args)
; The "m" in "mcons-term*" is for "maybe fast". Some of calls of this macro
; can probably be replaced with fcons-term*.
`(cons-term* ,fn ,@args))
(defmacro fcons-term (fn args)
; ; Start experimental code mod, to check that calls of fcons-term are legitimate
; ; shortcuts in place of the corresponding known-correct calls of cons-term.
; #-acl2-loop-only
; `(let* ((fn-used-only-in-fcons-term ,fn)
; (args-used-only-in-fcons-term ,args)
; (result (cons fn-used-only-in-fcons-term
; args-used-only-in-fcons-term)))
; (assert$ (equal result (cons-term fn-used-only-in-fcons-term
; args-used-only-in-fcons-term))
; result))
; #+acl2-loop-only
; ; End experimental code mod.
(list 'cons fn args))
(defun fargn1 (x n)
(declare (xargs :guard (and (integerp n)
(> n 0))))
(cond ((eql n 1) (list 'cdr x))
(t (list 'cdr (fargn1 x (- n 1))))))
(defmacro fargn (x n)
(list 'car (fargn1 x n)))
(defun cdr-nest (n v)
(cond ((equal n 0) v)
(t (fargn1 v n))))
(defun stobj-print-name (name)
(coerce
(cons #\<
(append (string-downcase1 (coerce (symbol-name name) 'list))
'(#\>)))
'string))
(defun evisceration-stobj-mark (name inputp)
; NAME is a stobj name. We return an evisceration mark that prints as
; ``<name>''. We make a special case out of STATE.
(cond
(inputp name)
((eq name 'STATE)
*evisceration-state-mark*)
(t
(cons *evisceration-mark* (stobj-print-name name)))))
(defun evisceration-stobj-marks1 (stobjs-flags inputp)
; See the comment in eviscerate-stobjs, below.
(cond ((null stobjs-flags) nil)
((car stobjs-flags)
(cons (evisceration-stobj-mark (car stobjs-flags) inputp)
(evisceration-stobj-marks1 (cdr stobjs-flags) inputp)))
(t
(cons nil
(evisceration-stobj-marks1 (cdr stobjs-flags) inputp)))))
(defconst *error-triple-sig*
'(nil nil state))
(defconst *cmp-sig*
'(nil nil))
(defun evisceration-stobj-marks (stobjs-flags inputp)
(cond ((equal stobjs-flags *error-triple-sig*)
(if inputp
*error-triple-sig*
*evisceration-error-triple-marks*))
((equal stobjs-flags '(nil)) '(nil))
(t (evisceration-stobj-marks1 stobjs-flags inputp))))
(defun eviscerate-stobjs1 (estobjs-out lst print-level print-length
alist evisc-table hiding-cars
iprint-alist
iprint-fal-new iprint-fal-old eager-p)
(cond
((null estobjs-out) (mv nil iprint-alist iprint-fal-new))
((car estobjs-out)
(mv-let (rest iprint-alist iprint-fal-new)
(eviscerate-stobjs1 (cdr estobjs-out) (cdr lst)
print-level print-length
alist evisc-table hiding-cars
iprint-alist iprint-fal-new iprint-fal-old eager-p)
(mv (cons (car estobjs-out) rest)
iprint-alist
iprint-fal-new)))
(t (mv-let (first iprint-alist iprint-fal-new)
(eviscerate (car lst) print-level print-length
alist evisc-table hiding-cars iprint-alist
iprint-fal-new iprint-fal-old eager-p)
(mv-let (rest iprint-alist iprint-fal-new)
(eviscerate-stobjs1 (cdr estobjs-out) (cdr lst)
print-level print-length alist
evisc-table hiding-cars iprint-alist
iprint-fal-new iprint-fal-old eager-p)
(mv (cons first rest) iprint-alist iprint-fal-new))))))
(defun eviscerate-stobjs (estobjs-out lst print-level print-length
alist evisc-table hiding-cars
iprint-alist iprint-fal-old eager-p)
; See also eviscerate-stobjs-top, which takes iprint-ar from the state and
; installs a new iprint-ar in the state.
; Warning: Right now, we abbreviate all stobjs with the <name> convention. I
; have toyed with the idea of allowing the user to specify how a stobj is to be
; abbreviated on output. This is awkward. See the Essay on Abbreviating Live
; Stobjs below.
; We wish to eviscerate lst with the given print-level, etc., but respecting
; stobjs that we may find in lst. Estobjs-out describes the shape of lst as a
; multiple value vector: if estobjs-out is of length 1, then lst is the single
; result; otherwise, lst is a list of as many elements as estobjs-out is long.
; The non-nil elements of stobjs name the stobjs in lst -- EXCEPT that unlike
; an ordinary ``stobjs-out'', the elements of estobjs-out are evisceration
; marks we are to ``print!'' For example corresponding to the stobjs-out
; setting of '(NIL $MY-STOBJ NIL STATE) is the estobjs-out
; '(NIL
; (:EVISCERATION-MARK . "<$my-stobj>")
; NIL
; (:EVISCERATION-MARK . "<state>"))
; Here, we assume *evisceration-mark* is :EVISCERATION-MARK.
(cond
((null estobjs-out)
; Lst is either a single non-stobj output or a list of n non-stobj outputs. We
; eviscerate it without regard for stobjs.
(eviscerate lst print-level print-length alist evisc-table hiding-cars
iprint-alist nil iprint-fal-old eager-p))
((null (cdr estobjs-out))
; Lst is a single output, which is either a stobj or not depending on whether
; (car stobjs-out) is non-nil.
(cond
((car estobjs-out)
(mv (car estobjs-out) iprint-alist nil))
(t (eviscerate lst print-level print-length alist evisc-table
hiding-cars iprint-alist nil iprint-fal-old eager-p))))
(t (eviscerate-stobjs1 estobjs-out lst print-level print-length
alist evisc-table hiding-cars iprint-alist
nil iprint-fal-old eager-p))))
(defun eviscerate-stobjs-top (estobjs-out lst print-level print-length
alist evisc-table hiding-cars
state)
; See eviscerate-stobjs.
(let ((iprint-fal-old (f-get-global 'iprint-fal state)))
(mv-let (result iprint-alist iprint-fal-new)
(eviscerate-stobjs estobjs-out lst print-level print-length alist
evisc-table hiding-cars
(and (iprint-enabledp state)
(iprint-last-index state))
iprint-fal-old
(iprint-eager-p iprint-fal-old))
(fast-alist-free-on-exit
iprint-fal-new
(let ((state
(cond
((eq iprint-alist t)
(f-put-global 'evisc-hitp-without-iprint t state))
((atom iprint-alist) state)
(t (update-iprint-ar-fal iprint-alist
iprint-fal-new
iprint-fal-old
state)))))
(mv result state))))))
; Essay on Abbreviating Live Stobjs
; Right now the live state is abbreviated as <state> when it is printed, and
; the user's live stobj $s is abbreviated as <$s>. It would be cool if the
; user could specify how he or she wants a stobj displayed, e.g., by selecting
; key components for printing or by providing a function which maps the stobj
; to some non-stobj ``stand-in'' or eviscerated object for printing.
; I have given this matter several hours' thought and abandoned it for the
; moment. I am not convinced it is worth the trouble. It IS a lot of trouble.
; We eviscerate stobjs in the read-eval-print loop. (Through Version_4.3, we
; also eviscerated stobjs in a very low-level place: ev-fncall-msg (and its
; more pervasive friend, ev-fncall-guard-er), used to print stobjs involved in
; calls of functions on args that violate a guard.)
; Every stobj must have some ``stand-in transformer'' function, fn. We will
; typically be holding a stobj name, e.g., $S, and a live value, val, e.g.,
; (#(777) #(1 2 3 ...)), and wish to obtain some ACL2 object to print in place
; of the value. This value is obtained by applying fn to val. The two main
; issues I see are
; (a) where do we find fn? The candidate places are state, world, and val
; itself. But we do not have state available in the low-level code.
; (b) how do we apply fn to val? The obvious thing is to call trans-eval or do
; an ev-fncall. Again, we need state. Furthermore, depending on how we do it,
; we have to fight a syntactic battle of ``casting'' an arbitrary object, val,
; to a stobj of type name, to apply a function which has a STOBJS-IN of (name).
; A more important problem is the one of order-of-definition. Which is defined
; first: how to eviscerate a stobj or how to evaluate a form? Stobj
; evisceration calls evaluation to apply fn, but evaluation calls stobj
; evisceration to report guard errors.
; Is user-specified stobj abbreviation really worth the trouble?
; One idea that presents itself is that val ``knows how to abbreviate itself.''
; I think this is akin to the idea of having a :program mode function, say
; stobj-standin, which syntactically takes a non-stobj and returns a non-stobj.
; Actually, stobj-standin would be called on val. It is clear that I could
; define this function in raw lisp: look in *the-live-state* to determine how
; to abbreviate val and then just do it. But what would be the logical
; definition of it? We could leave it undefined, or defined to be an undefined
; function. Until we admit the whole ACL2 system :logically, we could even
; define it in the logic to be t even though it really returned something else,
; since as a :program its logical definition is irrelevant. But at the moment
; I don't think ACL2 has a precedent for such a function and I don't think
; user-specified stobj abbreviation is justification enough for doing it.
; End of Essay on Abbreviating Live Stobjs
(defmacro flambda-applicationp (term)
; Term is assumed to be nvariablep.
`(consp (car ,term)))
(defabbrev lambda-applicationp (term)
(and (consp term)
(flambda-applicationp term)))
(defmacro flambdap (fn)
; Fn is assumed to be the fn-symb of some term.
`(consp ,fn))
(defmacro lambda-formals (x) `(cadr ,x))
(defmacro lambda-body (x) `(caddr ,x))
(defmacro make-lambda (args body)
`(list 'lambda ,args ,body))
(defmacro make-let (bindings body)
`(list 'let ,bindings ,body))
(defun doublet-listp (x)
(declare (xargs :guard t))
(cond ((atom x) (equal x nil))
(t (and (true-listp (car x))
(eql (length (car x)) 2)
(doublet-listp (cdr x))))))
(defmacro er-let* (alist body)
; This macro introduces the variable er-let-star-use-nowhere-else.
; The user who uses that variable in his forms is likely to be
; disappointed by the fact that we rebind it.
; Keep in sync with er-let*@par.
(declare (xargs :guard (and (doublet-listp alist)
(symbol-alistp alist))))
(cond ((null alist)
(list 'check-vars-not-free
'(er-let-star-use-nowhere-else)
body))
(t (list 'mv-let
(list 'er-let-star-use-nowhere-else
(caar alist)
'state)
(cadar alist)
(list 'cond
(list 'er-let-star-use-nowhere-else
(list 'mv
'er-let-star-use-nowhere-else
(caar alist)
'state))
(list t (list 'er-let* (cdr alist) body)))))))
#+acl2-par
(defmacro er-let*@par (alist body)
; Keep in sync with er-let*.
; This macro introduces the variable er-let-star-use-nowhere-else.
; The user who uses that variable in his forms is likely to be
; disappointed by the fact that we rebind it.
(declare (xargs :guard (and (doublet-listp alist)
(symbol-alistp alist))))
(cond ((null alist)
(list 'check-vars-not-free
'(er-let-star-use-nowhere-else)
body))
(t (list 'mv-let
(list 'er-let-star-use-nowhere-else
(caar alist))
(cadar alist)
(list 'cond
(list 'er-let-star-use-nowhere-else
(list 'mv
'er-let-star-use-nowhere-else
(caar alist)))
(list t (list 'er-let*@par (cdr alist) body)))))))
(defmacro match (x pat)
(list 'case-match x (list pat t)))
(defmacro match! (x pat)
(list 'or (list 'case-match x
(list pat '(value nil)))
(list 'er 'soft nil
"The form ~x0 was supposed to match the pattern ~x1."
x (kwote pat))))
(defun def-basic-type-sets1 (lst i)
(declare (xargs :guard (and (integerp i)
(true-listp lst))))
(cond ((null lst) nil)
(t (cons (list 'defconst (car lst) (list 'the-type-set (expt 2 i)))
(def-basic-type-sets1 (cdr lst) (+ i 1))))))
(defmacro def-basic-type-sets (&rest lst)
(let ((n (length lst)))
`(progn
(defconst *actual-primitive-types* ',lst)
(defconst *min-type-set* (- (expt 2 ,n)))
(defconst *max-type-set* (- (expt 2 ,n) 1))
(defmacro the-type-set (x)
; Warning: Keep this definition in sync with the type declaration in
; ts-subsetp0 and ts-subsetp.
`(the (integer ,*min-type-set* ,*max-type-set*) ,x))
,@(def-basic-type-sets1 lst 0))))
(defun list-of-the-type-set (x)
(cond ((consp x)
(cons (list 'the-type-set (car x))
(list-of-the-type-set (cdr x))))
(t nil)))
(defmacro ts= (a b)
(list '= (list 'the-type-set a) (list 'the-type-set b)))
; We'll create fancier versions of ts-complement0, ts-union0, and
; ts-intersection0 once we have defined the basic type sets.
(defmacro ts-complement0 (x)
(list 'the-type-set (list 'lognot (list 'the-type-set x))))
(defmacro ts-complementp (x)
(list 'minusp x))
(defun ts-union0-fn (x)
(list 'the-type-set
(cond ((null x) '*ts-empty*)
((null (cdr x)) (car x))
(t (xxxjoin 'logior
(list-of-the-type-set x))))))
(defmacro ts-union0 (&rest x)
(declare (xargs :guard (true-listp x)))
(ts-union0-fn x))
(defmacro ts-intersection0 (&rest x)
(list 'the-type-set
(cons 'logand (list-of-the-type-set x))))
(defmacro ts-disjointp (&rest x)
(list 'ts= (cons 'ts-intersection x) '*ts-empty*))
(defmacro ts-intersectp (&rest x)
(list 'not (list 'ts= (cons 'ts-intersection x) '*ts-empty*)))
; We do not define ts-subsetp0, both because we don't need it and because if we
; do define it, we will be tempted to add the declaration found in ts-subsetp,
; yet we have not yet defined *min-type-set* or *max-type-set*.