File: defun.lisp

package info (click to toggle)
acl2 8.5dfsg-5
  • links: PTS
  • area: main
  • in suites: bookworm
  • size: 991,452 kB
  • sloc: lisp: 15,567,759; javascript: 22,820; cpp: 13,929; ansic: 12,092; perl: 7,150; java: 4,405; xml: 3,884; makefile: 3,507; sh: 3,187; ruby: 2,633; ml: 763; python: 746; yacc: 723; awk: 295; csh: 186; php: 171; lex: 154; tcl: 49; asm: 23; haskell: 17
file content (399 lines) | stat: -rw-r--r-- 16,086 bytes parent folder | download | duplicates (8)
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
; Milawa - A Reflective Theorem Prover
; Copyright (C) 2005-2009 Kookamara LLC
;
; Contact:
;
;   Kookamara LLC
;   11410 Windermere Meadows
;   Austin, TX 78759, USA
;   http://www.kookamara.com/
;
; License: (An MIT/X11-style license)
;
;   Permission is hereby granted, free of charge, to any person obtaining a
;   copy of this software and associated documentation files (the "Software"),
;   to deal in the Software without restriction, including without limitation
;   the rights to use, copy, modify, merge, publish, distribute, sublicense,
;   and/or sell copies of the Software, and to permit persons to whom the
;   Software is furnished to do so, subject to the following conditions:
;
;   The above copyright notice and this permission notice shall be included in
;   all copies or substantial portions of the Software.
;
;   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
;   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
;   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
;   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
;   DEALINGS IN THE SOFTWARE.
;
; Original author: Jared Davis <jared@kookamara.com>

(in-package "ACL2")
(include-book "misc/hons-help2" :dir :system)

;; WHY WE NO LONGER INLINE
;;
;; Until inlining support was added to ACL2 proper, we used the misc/definline
;; book to which supported it via a ttag.  But now that inlining is "properly"
;; supported, ACL2 changes the names of functions into things like foo$inline.
;;
;; I got this mostly working for the ACL2 side of things, e.g., by using the
;; new :e instead of :executable-counterpart, and by patching verify-guards to
;; do a macro dereference.  So as far as the ACL2 stuff goes, this isn't too
;; horrible, although it's still pretty ugly to have to think about this.
;;
;; But when it comes to bootstrapping, the whole $inline versus not $inline
;; thing is a real pain in the ass, because we want to just take the ACL2
;; definitions and turn them into Milawa definitions, but then suddenly our
;; function bodies are no longer calling the "right" functions, etc.
;;
;; Rather than make Milawa's functions have ugly names like nfix$inline, it
;; seems best to just not bother with inlining in ACL2.  This is a somewhat
;; significant speed hit to bootstrapping, but, well, it's ACL2's fault for
;; implementing inlining in this terrible way.
;;
;; (include-book "misc/definline" :dir :system :ttags '(definline))

(include-book "io" :ttags :all)
(include-book "half-translate")


;; Our defun macro.
;;
;; We implement several features not found in the regular defun event.
;;
;;   - If :skip-guards is on the features-list, we strip out all the guards
;;     specified by any function and set verify-guards to nil.
;;
;;   - We disable any :type-prescription rules that are generated.
;;
;;   - We write out a LaTeX file in autodoc/defun-foo.tex which includes
;;     the definition of foo.
;;
;;   - We add an entry to the syntax-defuns table, which is used as part of
;;     the bootstrapping phase.

(defun aux-get-xarg (key x)
  ;; X should be a list of keywords and values given to xargs.  We return the
  ;; pair (key . value), unless key does not occur in xargs in which case we
  ;; return nil.
  (declare (xargs :guard t))
  (if (and (consp x)
           (consp (cdr x)))
      (if (equal (car x) key)
          (cons (first x) (second x))
        (aux-get-xarg key (cddr x)))
    nil))

(defun get-xarg (key x)
  ;; We look for any occurrences of (xargs ...) within x, then look up the key
  ;; in the first occurrence we find.  We return the (key . value) pair if key
  ;; occurs among the xargs, or nil otherwise.
  (declare (xargs :guard t))
  (cond ((atom x)
         nil)
        ((equal (car x) 'quote)
         nil)
        ((equal (car x) 'xargs)
         (aux-get-xarg key (cdr x)))
        (t
         (or (get-xarg key (car x))
             (get-xarg key (cdr x))))))

(defun aux-remove-xarg (key x)
  ;; X should be a list of keywords and values given to xargs.  We remove any
  ;; instances of the specified key and its value.
  (declare (xargs :guard t))
  (if (and (consp x)
           (consp (cdr x)))
      (if (equal (car x) key)
          (aux-remove-xarg key (cddr x))
        (cons (first x)
              (cons (second x)
                    (aux-remove-xarg key (cddr x)))))
    nil))

(defun remove-xarg (key x)
  ;; We look for any occurrences of (xargs ...) within x, then remove the
  ;; specified key and its value from these xargs.
  (declare (xargs :guard t))
  (cond ((atom x)
         x)
        ((equal (car x) 'quote)
         x)
        ((equal (car x) 'xargs)
         (cons 'xargs (aux-remove-xarg key (cdr x))))
        (t
         (cons (remove-xarg key (car x))
               (remove-xarg key (cdr x))))))

(defun set-xarg (key value x)
  ;; We look for any occurrences of (xargs ...) within x.  If key occurs among
  ;; these xargs, we erase it.  Then, we add the new key and value.
  (declare (xargs :guard t))
  (cond ((atom x)
         x)
        ((equal (car x) 'quote)
         x)
        ((equal (car x) 'xargs)
         (cons 'xargs (list* key value (aux-remove-xarg key (cdr x)))))
        (t
         (cons (set-xarg key value (car x))
               (set-xarg key value (cdr x))))))

(defun remove-milawa-xargs (x)
  ;; We look for occurrences of (xargs ...) within x and remove any occurrences
  ;; of milawa-specific xargs.
  (declare (xargs :guard t))
  (remove-xarg :export x))

(defun remove-guards (x)
  ;; X should be the arguments given to a defun.  We erase any :guard xargs and
  ;; set :verify-guards to nil.
  (declare (xargs :guard t))
  (set-xarg :verify-guards nil (remove-xarg :guard x)))

(defmacro MILAWA::verify-guards (name &rest args)
  ;; In guard-skipping mode, we ignore any verify-guards events and turn them
  ;; into value-triples (i.e., no-ops).  Otherwise, we just turn them into
  ;; ACL2::verify-guards commands.
  #+skip-guards
  `(value-triple '(ignoring-guards ,name . ,args))
  #-skip-guards
  ;; Fancy make-event stuff to deal with new $inline crap in ACL2 6.2,
  ;; suggested by Matt Kaufmann
  `(make-event
    (let ((fn (deref-macro-name ',name (macro-aliases (w state)))))
      (list* 'verify-guards fn ',args))))



(defun defun-to-latex (defun-args state)
  ;; We write autodoc/defun-foo.tex, so that the definition of foo can be kept
  ;; current in latex documentation.
  (declare (xargs :mode :program :stobjs state))
  (let* ((name     (first defun-args))
         (args     (second defun-args))
         (body     (car (last defun-args)))
         (filename (concatenate 'string "autodoc/defun-"
                                (mangle-filename (string-downcase (symbol-name name)))
                                ".tex")))
    ;; This command changed in v3-5.  We still want to support 3-4, so we check
    ;; for it explicitly.
    (let* ((state #+v3-4 (set-acl2-print-case :downcase)
                  #-v3-4 (set-print-case :downcase state))
           (state (set-fmt-hard-right-margin 80 state))
           (state (set-fmt-soft-right-margin 75 state)))
      (mv-let
       (channel state)
       (open-output-channel$ filename :character state)
       (let ((state (fms "\\begin{acl2}~%~q0~t1$=$~%~q2\\end{acl2}"
                         (list (cons #\0 (cons name args))
                               (cons #\1 2)
                               (cons #\2 body))
                         channel state nil)))
         (close-output-channel channel state))))))

(table milawa 'syntax-defun-entries nil)
(table milawa 'acl2-defun-entries nil)

(defun get-syntax-defun-entries (world)
  (cdr (assoc 'syntax-defun-entries (table-alist 'milawa world))))

(defun get-acl2-defun-entries (world)
  (cdr (assoc 'acl2-defun-entries (table-alist 'milawa world))))

(defun clean-up-body (x)
  ;; When we "export" definitions to Milawa, we strip away a custom ACL2
  ;; things.
  (if (consp x)
      (cond ((and (equal (car x) 'quote)
                  (equal (len x) 2))
             ;; Do not descend into quoted constants
             x)
            ((and (equal (car x) 'ACL2::time$)
                  (equal (len x) 2))
             ;; Simplify (ACL2::time$ x) to x
             (clean-up-body (second x)))
            ((and (equal (car x) 'ACL2::prog2$)
                  (equal (len x) 3))
             ;; Simplify (ACL2::prog2$ x y) to y
             (clean-up-body (third x)))
            ((and (equal (car x) 'ACL2::prog1$)
                  (equal (len x) 3))
             ;; Simplify (ACL2::prog1$ x y) to x
             (clean-up-body (second x)))
            ((equal (car x) 'ACL2::ec-call)
             ;; Simplify (ACL2::ec-call x) to x
             (clean-up-body (second x)))
            ((or (equal (car x) 'ACL2::cw)
                 (equal (car x) 'ACL2::cw!))
             ;; Simplify (ACL2::cw ...) and (ACL2::cw! ...) to nil
             nil)
            ((equal (car x) 'ACL2::hist)
             ;; Simplify (ACL2::hist x y ...) to (ACL2::list x y ...)
             (cons 'ACL2::list
                   (clean-up-body (cdr x))))
            ((and (equal (car x) 'ACL2::hons)
                  (equal (len x) 3))
             ;; Simplify (ACL2::hons x y) to (ACL2::cons x y)
             (list 'ACL2::cons
                   (clean-up-body (second x))
                   (clean-up-body (third x))))
            ((and (or (equal (car x) 'let)
                      (equal (car x) 'let*))
                  (equal (len x) 4)
                  (consp (third x))
                  (equal (car (third x)) 'declare))
             ;; Simplify (let ((blah)) (declare ...) body) to (let ((blah)) body)
             (list (first x)
                   (clean-up-body (second x))
                   (clean-up-body (fourth x))))
            (t
             (cons (clean-up-body (car x))
                   (clean-up-body (cdr x)))))
    x))

(defun defun-to-syntax-table-entry (defun-args state)
  (declare (xargs :mode :program :stobjs state))
  (let ((export (get-xarg :export defun-args))
        (mode   (get-xarg :mode defun-args)))
    (cond ((and (consp export)
                (not (cdr export)))
           ;; Found (:export nil) -- We are to skip this %SYNTAX-DEFUN.
           (mv nil `(value-triple :invisible) state))
          ((and (consp mode)
                (equal (cdr mode) :program))
           ;; Program mode function -- We are to skip this %SYNTAX-DEFUN
           (mv nil `(value-triple :invisible) state))
          (t
           (let* ((name (first defun-args))
                  (args (second defun-args)))
             (mv-let (erp body state)
                     (if (consp export)
                         ;; Found (:export ...) -- We pretend that the
                         ;; function's body is "..." and don't do any cleaning
                         (mv nil (cdr export) state)
                       ;; No (:export ...) -- We use the real body, half-translated
                       ;; and cleaned up.
                       (half-translate (clean-up-body (car (last defun-args))) state))
                     (if erp
                         (mv erp body state)
                       (mv nil
                           `(table milawa 'syntax-defun-entries
                                   (cons '(MILAWA::%syntax-defun ,name ,args ,body)
                                         (get-syntax-defun-entries ACL2::world)))
                           state))))))))

(defun MILAWA::defun-fn (type args)
  (declare (xargs :mode :program))
  ;; In guard-skipping mode, we strip out guards from the xargs and insert an
  ;; explicit :verify-guards nil command.  Otherwise, we just turn them into
  ;; ACL2::defun's and disable any type prescription generated.
  `(encapsulate
    ()
    ;; Submit the defun with or without guards as necessary
    #+skip-guards
    (,type ,@(remove-guards (remove-milawa-xargs args)))
    #-skip-guards
    (,type ,@(remove-milawa-xargs args))
    ;; Disable the type prescription, if one exists
    (make-event
     (let* ((fn ',(car args))
            (props (getprops fn 'current-acl2-world (w state)))
            (symbol-class (cdr (assoc 'symbol-class props))))
       (if (equal symbol-class :program)
           `(value-triple :invisible)
         (prog2$
          (cw "~%Note: Disabling type prescription for ~s0.~%" fn)
          `(in-theory (disable (:t ,fn)))))))
    ;; Write out a LaTeX file for the function
    ;; BOZO disabling this because of stupid fucking OpenMCL .tem file bug ruining all my builds
    (local (make-event ;; (let ((state (defun-to-latex ',args state)))
                         (ACL2::mv nil `(value-triple :invisible) state))) ;; )
    ;; Add the syntax-defun if necessary
    (make-event (defun-to-syntax-table-entry ',args state))
    ;; Add the acl2-defun entry
    (table milawa 'acl2-defun-entries
           (cons ',args (get-acl2-defun-entries world)))))

(defmacro MILAWA::defun (&rest args)
  (MILAWA::defun-fn 'ACL2::defun args))

(defmacro MILAWA::defund (&rest args)
  (MILAWA::defun-fn 'ACL2::defund args))



(ACL2::table milawa 'functions-to-inline nil)

(defun get-functions-to-inline (world)
  (cdr (assoc 'functions-to-inline (ACL2::table-alist 'milawa world))))

(defmacro MILAWA::definline (&rest args)
  ;; Same as defun, but also indicates that the introduced function should be
  ;; inlined.  We haven't yet implemented inlining in ACL2 yet.
  `(ACL2::progn
    ,(MILAWA::defun-fn
      ;; This was formerly 'acl2::definline, but see WHY WE NO LONGER INLINE,
      ;; above.
      'ACL2::defun
      args)
    (ACL2::table milawa 'functions-to-inline
                 (cons ',(first args)
                       (get-functions-to-inline ACL2::world)))))

(defmacro MILAWA::definlined (&rest args)
  ;; Same as defund, but also indicates that the introduced function should be
  ;; inlined.  We haven't implemented inlining in ACL2 yet.
  `(ACL2::progn
    ,(MILAWA::defun-fn
      ;; This was formerly 'acl2::definline, but see WHY WE NO LONGER INLINE,
      ;; above.
      'ACL2::defund
      args)
    (ACL2::table milawa 'functions-to-inline
                 (cons ',(first args)
                       (get-functions-to-inline ACL2::world)))))


(defun create-type-prescriptions (x)
  ;; Given a list of names, we produce a list of (:type-prescription name1),
  ;; ..., (:type-prescription nameN).
  (declare (xargs :guard t))
  (if (consp x)
      (cons (list :t (car x))
            (create-type-prescriptions (cdr x)))
    nil))

(defmacro MILAWA::mutual-recursion (&rest args)
  ;; ACL2::mutual-recursion is messy because ACL2 insists only ACL2::defun(d)s
  ;; appear within it.  We change any MILAWA::defun(d)s to ACL2::defun(d)s.  If
  ;; we are in guard-skipping mode, we also strip out guards and insert
  ;; ":verify-guards nil" as appropriate.
  `(ACL2::progn
    (ACL2::mutual-recursion
     ,@(subst 'ACL2::defun 'MILAWA::defun
              (subst 'ACL2::defund 'MILAWA::defund
                     #+skip-guards
                     (remove-guards args)
                     #-skip-guards
                     args)))
    (make-event
     (if (not ',args)
         `(value-triple :invisible)
       (let* ((names (strip-cadrs ',args))
              (props1 (getprops (car names) 'current-acl2-world (w state)))
              (class1 (cdr (assoc 'symbol-class props1))))
         (if (equal class1 :program)
             ;; ALL functions are program mode.  Nothing to disable.
             `(value-triple :invisible)
           ;; ALL functions are logic mode.  Disable all type prescriptions.
           ;; Defund's are handled by acl2's defund.
           (prog2$
            (cw "~%Note: Disabling type prescriptions for ~&0.~%" names)
            (let ((disables (create-type-prescriptions names)))
              `(in-theory (disable ,@disables))))))))))