1#| -*-Scheme-*-
2
3Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
4    1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5    2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Massachusetts
6    Institute of Technology
7
8This file is part of MIT/GNU Scheme.
9
10MIT/GNU Scheme is free software; you can redistribute it and/or modify
11it under the terms of the GNU General Public License as published by
12the Free Software Foundation; either version 2 of the License, or (at
13your option) any later version.
14
15MIT/GNU Scheme is distributed in the hope that it will be useful, but
16WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with MIT/GNU Scheme; if not, write to the Free Software
22Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
23USA.
24
25|#
26
27;;;; SCode Optimizer: Expression analysis
28;;; package: (scode-optimizer analyze)
29
30(declare (usual-integrations)
31         (integrate-external "object"))
32
33;;; EXPRESSION/ALWAYS-FALSE?
34
35;; True iff expression can be shown to always return #F.
36;; That is, the expression counts as #f to a conditional.
37;; Expression is not shown to be side-effect free.
38(declare (integrate-operator expression/always-false?))
39(define (expression/always-false? expression)
40  ((expression/method always-false?-dispatch-vector expression) expression))
41
42(define always-false?-dispatch-vector
43  (expression/make-dispatch-vector))
44
45(define define-method/always-false?
46  (expression/make-method-definer always-false?-dispatch-vector))
47
48(define-method/always-false? 'ACCESS false-procedure)
49
50(define-method/always-false? 'ASSIGNMENT false-procedure)
51
52(define-method/always-false? 'COMBINATION
53  (lambda (expression)
54    (cond ((expression/call-to-not? expression)
55           (expression/never-false? (first (combination/operands expression))))
56          ((procedure? (combination/operator expression))
57           (expression/always-false? (procedure/body (combination/operator expression))))
58          (else #f))))
59
60(define-method/always-false? 'CONDITIONAL
61  (lambda (expression)
62    (and (or (expression/always-false? (conditional/predicate expression))
63             (expression/always-false? (conditional/consequent expression)))
64         (or (expression/never-false? (conditional/predicate expression))
65             (expression/always-false? (conditional/alternative expression))))))
66
67(define-method/always-false? 'CONSTANT
68  (lambda (expression)
69    (not (constant/value expression))))
70
71(define-method/always-false? 'DECLARATION
72  (lambda (expression)
73    (expression/always-false?
74     (declaration/expression expression))))
75
76;; A promise is not a false value.
77(define-method/always-false? 'DELAY false-procedure)
78
79(define-method/always-false? 'DISJUNCTION
80  (lambda (expression)
81    (and (expression/always-false? (disjunction/predicate expression))
82         (expression/always-false? (disjunction/alternative expression)))))
83
84(define-method/always-false? 'OPEN-BLOCK
85  (lambda (expression)
86    (expression/always-false?
87     (last (open-block/actions expression)))))
88
89;; A closure is not a false value.
90(define-method/always-false? 'PROCEDURE false-procedure)
91
92(define-method/always-false? 'QUOTATION false-procedure)
93
94(define-method/always-false? 'REFERENCE false-procedure)
95
96(define-method/always-false? 'SEQUENCE
97  (lambda (expression)
98    (expression/always-false?
99     (last (sequence/actions expression)))))
100
101(define-method/always-false? 'THE-ENVIRONMENT false-procedure)
102
103;;; EXPRESSION/BOOLEAN?
104;;
105;; T if expression can be shown to return only #T or #F.
106;;
107(declare (integrate-operator expression/boolean?))
108(define (expression/boolean? expression)
109  ((expression/method boolean?-dispatch-vector expression) expression))
110
111(define boolean?-dispatch-vector
112  (expression/make-dispatch-vector))
113
114(define define-method/boolean?
115  (expression/make-method-definer boolean?-dispatch-vector))
116
117(define-method/boolean? 'ACCESS false-procedure)
118
119(define-method/boolean? 'ASSIGNMENT false-procedure)
120
121(define-method/boolean? 'COMBINATION
122  (lambda (expression)
123    (or (expression/call-to-boolean-predicate? expression)
124        (and (procedure? (combination/operator expression))
125             (boolean? (procedure/body (combination/operator expression)))))))
126
127(define-method/boolean? 'CONDITIONAL
128  (lambda (expression)
129    (and (or (expression/always-false? (conditional/predicate expression))
130             (expression/boolean? (conditional/consequent expression)))
131         (or (expression/never-false? (conditional/predicate expression))
132             (expression/boolean? (conditional/alternative expression))))))
133
134(define-method/boolean? 'CONSTANT
135  (lambda (expression)
136    ;; jrm:  do not accept unspecific here.
137    (or (not (constant/value expression))
138        (eq? (constant/value expression) #t))))
139
140(define-method/boolean? 'DECLARATION
141  (lambda (expression)
142    (expression/boolean? (declaration/expression expression))))
143
144(define-method/boolean? 'DELAY  false-procedure)
145
146(define-method/boolean? 'DISJUNCTION
147  (lambda (expression)
148    (and (expression/boolean? (disjunction/predicate expression))
149         (or (expression/never-false? (disjunction/predicate expression))
150             (expression/boolean? (disjunction/alternative expression))))))
151
152(define-method/boolean? 'OPEN-BLOCK
153  (lambda (expression)
154    (expression/boolean?
155     (last (open-block/actions expression)))))
156
157(define-method/boolean? 'PROCEDURE false-procedure)
158
159(define-method/boolean? 'QUOTATION false-procedure)
160
161(define-method/boolean? 'REFERENCE false-procedure)
162
163(define-method/boolean? 'SEQUENCE
164  (lambda (expression)
165    (expression/boolean? (last (sequence/actions expression)))))
166
167(define-method/boolean? 'THE-ENVIRONMENT false-procedure)
168
169;;; EXPRESSION/EFFECT-FREE?
170;;
171;; True iff evaluation of expression has no side effects.
172(declare (integrate-operator expression/effect-free?))
173(define (expression/effect-free? expression)
174  ((expression/method effect-free?-dispatch-vector expression) expression))
175
176(define effect-free?-dispatch-vector
177  (expression/make-dispatch-vector))
178
179(define define-method/effect-free?
180  (expression/make-method-definer effect-free?-dispatch-vector))
181
182(define-method/effect-free? 'ACCESS
183  (lambda (expression)
184    (expression/effect-free? (access/environment expression))))
185
186(define-method/effect-free? 'ASSIGNMENT false-procedure)
187
188(define-method/effect-free? 'COMBINATION
189  (lambda (expression)
190    (and (for-all? (combination/operands expression) expression/effect-free?)
191         (or (expression/call-to-effect-free-primitive? expression)
192             (and (procedure? (combination/operator expression))
193                  (expression/effect-free? (procedure/body (combination/operator expression))))))))
194
195(define-method/effect-free? 'CONDITIONAL
196  (lambda (expression)
197    (and (expression/effect-free? (conditional/predicate expression))
198         (or (expression/always-false? (conditional/predicate expression))
199             (expression/effect-free? (conditional/consequent expression)))
200         (or (expression/never-false? (conditional/predicate expression))
201             (expression/effect-free? (conditional/alternative expression))))))
202
203(define-method/effect-free? 'CONSTANT true-procedure)
204
205(define-method/effect-free? 'DECLARATION
206  (lambda (expression)
207    (expression/effect-free? (declaration/expression expression))))
208
209;; Consing a promise is not considered an effect.
210(define-method/effect-free? 'DELAY true-procedure)
211
212(define-method/effect-free? 'DISJUNCTION
213  (lambda (expression)
214    (and (expression/effect-free? (disjunction/predicate expression))
215         (or (expression/never-false? (disjunction/predicate expression))
216             (expression/effect-free? (disjunction/alternative expression))))))
217
218;; This could be smarter and skip the assignments
219;; done for the letrec, but it is easier to just
220;; assume it causes effects.
221(define-method/effect-free? 'OPEN-BLOCK
222  (lambda (expression)
223    (declare (ignore expression))
224    #f))
225
226;; Just consing a closure is not considered a side-effect.
227(define-method/effect-free? 'PROCEDURE true-procedure)
228
229(define-method/effect-free? 'QUOTATION false-procedure)
230
231(define-method/effect-free? 'REFERENCE true-procedure)
232
233(define-method/effect-free? 'SEQUENCE
234  (lambda (expression)
235    (for-all? (sequence/actions expression) expression/effect-free?)))
236
237(define-method/effect-free? 'THE-ENVIRONMENT true-procedure)
238
239;;; EXPRESSION/FREE-VARIABLES
240;;
241;; Returns an EQ? LSET of the free variables in an expression.
242
243(declare (integrate-operator expression/free-variables))
244
245(define (expression/free-variables expression)
246  ((expression/method free-variables-dispatch-vector expression) expression))
247
248(define (expressions/free-variables expressions)
249  (fold-left (lambda (answer expression)
250               (lset-union eq? answer (expression/free-variables expression)))
251             (no-free-variables)
252             expressions))
253
254(define free-variables-dispatch-vector
255  (expression/make-dispatch-vector))
256
257(define define-method/free-variables
258  (expression/make-method-definer free-variables-dispatch-vector))
259
260(define-method/free-variables 'ACCESS
261  (lambda (expression)
262    (expression/free-variables (access/environment expression))))
263
264(define-method/free-variables 'ASSIGNMENT
265  (lambda (expression)
266    (lset-adjoin eq?
267                 (expression/free-variables (assignment/value expression))
268                 (assignment/variable expression))))
269
270(define-method/free-variables 'COMBINATION
271  (lambda (expression)
272    (lset-union eq?
273                (expression/free-variables (combination/operator expression))
274                (expressions/free-variables (combination/operands expression)))))
275
276(define-method/free-variables 'CONDITIONAL
277  (lambda (expression)
278    (lset-union eq?
279                (expression/free-variables (conditional/predicate expression))
280                (if (expression/always-false? (conditional/predicate expression))
281                    (no-free-variables)
282                    (expression/free-variables (conditional/consequent expression)))
283                (if (expression/never-false? (conditional/predicate expression))
284                    (no-free-variables)
285                    (expression/free-variables (conditional/alternative expression))))))
286
287(define-method/free-variables 'CONSTANT
288  (lambda (expression)
289    expression
290    (no-free-variables)))
291
292(define-method/free-variables 'DECLARATION
293  (lambda (expression)
294    (expression/free-variables (declaration/expression expression))))
295
296(define-method/free-variables 'DELAY
297  (lambda (expression)
298    (expression/free-variables (delay/expression expression))))
299
300(define-method/free-variables 'DISJUNCTION
301  (lambda (expression)
302    (lset-union eq?
303                (expression/free-variables (disjunction/predicate expression))
304                (if (expression/never-false? (disjunction/predicate expression))
305                    (no-free-variables)
306                    (expression/free-variables (disjunction/alternative expression))))))
307
308(define-method/free-variables 'OPEN-BLOCK
309  (lambda (expression)
310    (let ((omit (block/bound-variables (open-block/block expression))))
311     (fold-left (lambda (variables action)
312                  (if (eq? action open-block/value-marker)
313                      variables
314                      (lset-union eq? variables (lset-difference eq? (expression/free-variables action) omit))))
315                (lset-difference eq? (expressions/free-variables (open-block/values expression)) omit)
316                (open-block/actions expression)))))
317
318(define-method/free-variables 'PROCEDURE
319  (lambda (expression)
320    (lset-difference eq?
321     (expression/free-variables (procedure/body expression))
322     (block/bound-variables (procedure/block expression)))))
323
324(define-method/free-variables 'QUOTATION
325  (lambda (expression)
326    (declare (ignore expression))
327    (no-free-variables)))
328
329(define-method/free-variables 'REFERENCE
330  (lambda (expression)
331    (singleton-variable (reference/variable expression))))
332
333(define-method/free-variables 'SEQUENCE
334  (lambda (expression)
335    (expressions/free-variables (sequence/actions expression))))
336
337(define-method/free-variables 'THE-ENVIRONMENT
338  (lambda (expression)
339    (declare (ignore expression))
340    (no-free-variables)))
341
342(define-integrable (no-free-variables)
343  '())
344
345(define-integrable (singleton-variable variable)
346  (list variable))
347
348;;; EXPRESSION/FREE-VARIABLE? <expression> <variable>
349;;
350;; Test if a particular <variable> occurs free in <expression>.  Faster
351;; and cheaper than collecting the entire free variable set and then
352;; using memq.
353
354(define (expression/free-variable? expression variable)
355  ((expression/method is-free-dispatch-vector expression) expression variable))
356
357(define (expressions/free-variable? expressions variable)
358  (fold-left (lambda (answer expression)
359               (or answer
360                   (expression/free-variable? expression variable)))
361             #f
362             expressions))
363
364(define is-free-dispatch-vector
365  (expression/make-dispatch-vector))
366
367(define define-method/free-variable?
368  (expression/make-method-definer is-free-dispatch-vector))
369
370(define-method/free-variable? 'ACCESS
371  (lambda (expression variable)
372    (expression/free-variable? (access/environment expression) variable)))
373
374(define-method/free-variable? 'ASSIGNMENT
375  (lambda (expression variable)
376    (or (eq? variable (assignment/variable expression))
377        (expression/free-variable? (assignment/value expression) variable))))
378
379(define-method/free-variable? 'COMBINATION
380  (lambda (expression variable)
381    (or (expression/free-variable? (combination/operator expression) variable)
382        (expressions/free-variable? (combination/operands expression) variable))))
383
384(define-method/free-variable? 'CONDITIONAL
385  (lambda (expression variable)
386    (or (expression/free-variable? (conditional/predicate expression) variable)
387        (cond ((expression/always-false? (conditional/predicate expression))
388               (expression/free-variable? (conditional/alternative expression) variable))
389              ((expression/never-false? (conditional/predicate expression))
390               (expression/free-variable? (conditional/consequent expression) variable))
391              ((expression/free-variable? (conditional/consequent expression) variable))
392              (else (expression/free-variable? (conditional/alternative expression) variable))))))
393
394(define-method/free-variable? 'CONSTANT false-procedure)
395
396(define-method/free-variable? 'DECLARATION
397  (lambda (expression variable)
398    (expression/free-variable? (declaration/expression expression) variable)))
399
400(define-method/free-variable? 'DELAY
401  (lambda (expression variable)
402    (expression/free-variable? (delay/expression expression) variable)))
403
404(define-method/free-variable? 'DISJUNCTION
405  (lambda (expression variable)
406    (or (expression/free-variable? (disjunction/predicate expression) variable)
407        (if (expression/never-false? (disjunction/predicate expression))
408            #f
409            (expression/free-variable? (disjunction/alternative expression) variable)))))
410
411(define-method/free-variable? 'OPEN-BLOCK
412  (lambda (expression variable)
413    (fold-left (lambda (answer action)
414                 (or answer
415                     (if (eq? action open-block/value-marker)
416                         #f
417                         (expression/free-variable? action variable))))
418               #f
419               (open-block/actions expression))))
420
421(define-method/free-variable? 'PROCEDURE
422  (lambda (expression variable)
423    (expression/free-variable? (procedure/body expression) variable)))
424
425(define-method/free-variable? 'QUOTATION false-procedure)
426
427(define-method/free-variable? 'REFERENCE
428  (lambda (expression variable)
429    (eq? (reference/variable expression) variable)))
430
431(define-method/free-variable? 'SEQUENCE
432  (lambda (expression variable)
433  (fold-left (lambda (answer action)
434               (or answer
435                   (if (eq? action open-block/value-marker)
436                       #f
437                       (expression/free-variable? action variable))))
438             #f
439             (sequence/actions expression))))
440
441(define-method/free-variable? 'THE-ENVIRONMENT false-procedure)
442
443;;; EXPRESSION/FREE-VARIABLE-INFO <expression> <variable>
444;;
445;; Returns a PAIR, the car of which contains a count of the number
446;; of times the variable appears as an operator, the cdr contains
447;; the number of times the variable appears as an argument.
448;; Used to determine if adding an INTEGRATE-OPERATOR declaration
449;; is a good idea.
450
451(define (expression/free-variable-info expression variable)
452  (expression/free-variable-info-dispatch expression variable (cons 0 0)))
453
454(define (expression/free-variable-info-dispatch expression variable info)
455  ((expression/method free-info-dispatch-vector expression) expression variable info))
456
457(define (expressions/free-variable-info expressions variable info)
458  (fold-left (lambda (answer expression)
459               (expression/free-variable-info-dispatch expression variable answer))
460             info
461             expressions))
462
463(define free-info-dispatch-vector
464  (expression/make-dispatch-vector))
465
466(define define-method/free-variable-info
467  (expression/make-method-definer free-info-dispatch-vector))
468
469(define-method/free-variable-info 'ACCESS
470  (lambda (expression variable info)
471    (expression/free-variable-info-dispatch (access/environment expression) variable info)))
472
473(define-method/free-variable-info 'ASSIGNMENT
474  (lambda (expression variable info)
475    (or (eq? variable (assignment/variable expression))
476        (expression/free-variable-info-dispatch (assignment/value expression) variable info))))
477
478(define-method/free-variable-info 'COMBINATION
479  (lambda (expression variable info)
480    (let ((operator (combination/operator expression))
481          (inner-info (expressions/free-variable-info (combination/operands expression) variable info)))
482      (if (and (reference? operator)
483               (eq? (reference/variable operator) variable))
484          (cons (fix:1+ (car inner-info)) (cdr inner-info))
485          (expression/free-variable-info-dispatch operator variable inner-info)))))
486
487(define-method/free-variable-info 'CONDITIONAL
488  (lambda (expression variable info)
489    (expression/free-variable-info-dispatch
490     (conditional/predicate expression) variable
491     (expression/free-variable-info-dispatch
492      (conditional/consequent expression) variable
493      (expression/free-variable-info-dispatch (conditional/alternative expression) variable info)))))
494
495(define-method/free-variable-info 'CONSTANT
496  (lambda (expression variable info) (declare (ignore expression variable)) info))
497
498(define-method/free-variable-info 'DECLARATION
499  (lambda (expression variable info)
500    (expression/free-variable-info-dispatch (declaration/expression expression) variable info)))
501
502(define-method/free-variable-info 'DELAY
503  (lambda (expression variable info)
504    (expression/free-variable-info-dispatch (delay/expression expression) variable info)))
505
506(define-method/free-variable-info 'DISJUNCTION
507  (lambda (expression variable info)
508    (expression/free-variable-info-dispatch
509     (disjunction/predicate expression) variable
510     (expression/free-variable-info-dispatch
511      (disjunction/alternative expression) variable
512      info))))
513
514(define-method/free-variable-info 'OPEN-BLOCK
515  (lambda (expression variable info)
516    (fold-left (lambda (info action)
517                 (if (eq? action open-block/value-marker)
518                     info
519                     (expression/free-variable-info-dispatch action variable info)))
520               info
521               (open-block/actions expression))))
522
523(define-method/free-variable-info 'PROCEDURE
524  (lambda (expression variable info)
525    (expression/free-variable-info-dispatch (procedure/body expression) variable info)))
526
527(define-method/free-variable-info 'QUOTATION
528  (lambda (expression variable info)
529    (declare (ignore expression variable))
530    info))
531
532(define-method/free-variable-info 'REFERENCE
533  (lambda (expression variable info)
534    (if (eq? (reference/variable expression) variable)
535        (cons (car info) (fix:1+ (cdr info)))
536        info)))
537
538(define-method/free-variable-info 'SEQUENCE
539  (lambda (expression variable info)
540    (expressions/free-variable-info (sequence/actions expression) variable info)))
541
542(define-method/free-variable-info 'THE-ENVIRONMENT
543  (lambda (expression variable info)
544    (declare (ignore expression variable))
545    info))
546
547;;; EXPRESSION/NEVER-FALSE?
548;;
549;; True iff expression can be shown to never return #F.
550;; That is, the expression counts as #t to a conditional.
551;; Expression is not shown to be side-effect free.
552(declare (integrate-operator expression/never-false?))
553(define (expression/never-false? expression)
554  ((expression/method never-false?-dispatch-vector expression) expression))
555
556(define never-false?-dispatch-vector
557  (expression/make-dispatch-vector))
558
559(define define-method/never-false?
560  (expression/make-method-definer never-false?-dispatch-vector))
561
562(define-method/never-false? 'ACCESS false-procedure)
563
564(define-method/never-false? 'ASSIGNMENT false-procedure)
565
566(define-method/never-false? 'COMBINATION
567  (lambda (expression)
568    (cond ((expression/call-to-not? expression)
569           (expression/always-false? (first (combination/operands expression))))
570          ((procedure? (combination/operator expression))
571           (expression/never-false? (procedure/body (combination/operator expression))))
572          (else #f))))
573
574(define-method/never-false? 'CONDITIONAL
575  (lambda (expression)
576    (and (or (expression/always-false? (conditional/predicate expression))
577             (expression/never-false? (conditional/consequent expression)))
578         (or (expression/never-false? (conditional/predicate expression))
579             (expression/never-false? (conditional/alternative expression))))))
580
581(define-method/never-false? 'CONSTANT        constant/value)
582
583(define-method/never-false? 'DECLARATION
584  (lambda (expression)
585    (expression/never-false? (declaration/expression expression))))
586
587(define-method/never-false? 'DELAY true-procedure)
588
589(define-method/never-false? 'DISJUNCTION
590  (lambda (expression)
591    (or (expression/never-false? (disjunction/predicate expression))
592        (expression/never-false? (disjunction/alternative expression)))))
593
594(define-method/never-false? 'OPEN-BLOCK
595  (lambda (expression)
596    (expression/never-false?
597     (last (open-block/actions expression)))))
598
599(define-method/never-false? 'PROCEDURE true-procedure)
600
601(define-method/never-false? 'QUOTATION false-procedure)
602
603(define-method/never-false? 'REFERENCE false-procedure)
604
605(define-method/never-false? 'SEQUENCE
606  (lambda (expression)
607    (expression/never-false? (last (sequence/actions expression)))))
608
609(define-method/never-false? 'THE-ENVIRONMENT true-procedure)
610
611;;; EXPRESSION/PURE-FALSE?
612
613;; True iff all paths through expression end in returning
614;; exactly #F or unspecified, and no path has side effects.
615;; Expression is observationally equivalent to #F.
616(define (expression/pure-false? expression)
617  ((expression/method pure-false?-dispatch-vector expression) expression))
618
619(define pure-false?-dispatch-vector
620  (expression/make-dispatch-vector))
621
622(define define-method/pure-false?
623  (expression/make-method-definer pure-false?-dispatch-vector))
624
625(define-method/pure-false? 'ACCESS false-procedure)
626
627(define-method/pure-false? 'ASSIGNMENT false-procedure)
628
629(define-method/pure-false? 'COMBINATION
630  (lambda (expression)
631    (cond ((expression/call-to-not? expression)
632           (expression/pure-true? (first (combination/operands expression))))
633          ((procedure? (combination/operator expression))
634           (and (for-all? (combination/operands expression) expression/effect-free?)
635                (expression/pure-false? (procedure/body (combination/operator expression)))))
636          (else #f))))
637
638(define-method/pure-false? 'CONDITIONAL
639  (lambda (expression)
640    (and (expression/effect-free? (conditional/predicate expression))
641         (or (expression/always-false? (conditional/predicate expression))
642             (expression/pure-false? (conditional/consequent expression)))
643         (or (expression/never-false? (conditional/predicate expression))
644             (expression/pure-false? (conditional/alternative expression))))))
645
646(define-method/pure-false? 'CONSTANT
647  (lambda (expression)
648    (not (constant/value expression))))
649
650(define-method/pure-false? 'DECLARATION
651  (lambda (expression)
652    (expression/pure-false?
653     (declaration/expression expression))))
654
655(define-method/pure-false? 'DELAY false-procedure)
656
657(define-method/pure-false? 'DISJUNCTION
658  (lambda (expression)
659    (and (expression/pure-false? (disjunction/predicate expression))
660         (expression/pure-false? (disjunction/alternative expression)))))
661
662;; Could be smarter
663(define-method/pure-false? 'OPEN-BLOCK false-procedure)
664
665(define-method/pure-false? 'PROCEDURE false-procedure)
666
667(define-method/pure-false? 'QUOTATION false-procedure)
668
669(define-method/pure-false? 'REFERENCE false-procedure)
670
671(define-method/pure-false? 'SEQUENCE
672  (lambda (expression)
673    (and (for-all? (except-last-pair (sequence/actions expression))
674                   expression/effect-free?) ;; unlikely
675         (expression/pure-false? (last (sequence/actions expression))))))
676
677(define-method/pure-false? 'THE-ENVIRONMENT false-procedure)
678
679;;; EXPRESSION/PURE-TRUE?
680;;
681;; True iff all paths through expression end in returning
682;; exactly #T or unspecified, and no path has side effects.
683;; Expression is observationally equivalent to #T.
684(declare (integrate-operator expression/pure-true?))
685(define (expression/pure-true? expression)
686  ((expression/method pure-true?-dispatch-vector expression) expression))
687
688(define pure-true?-dispatch-vector
689  (expression/make-dispatch-vector))
690
691(define define-method/pure-true?
692  (expression/make-method-definer pure-true?-dispatch-vector))
693
694(define-method/pure-true? 'ACCESS false-procedure)
695
696(define-method/pure-true? 'ASSIGNMENT false-procedure)
697
698(define-method/pure-true? 'COMBINATION
699  (lambda (expression)
700    (cond ((expression/call-to-not? expression)
701           (expression/pure-false? (first (combination/operands expression))))
702          ((procedure? (combination/operator expression))
703           (and (for-all? (combination/operands expression) expression/effect-free?)
704                (expression/pure-true? (procedure/body (combination/operator expression)))))
705          (else #f))))
706
707(define-method/pure-true? 'CONDITIONAL
708  (lambda (expression)
709    (and (expression/effect-free? (conditional/predicate expression))
710         (or (expression/always-false? (conditional/predicate expression))
711             (expression/pure-true? (conditional/consequent expression)))
712         (or (expression/never-false? (conditional/predicate expression))
713             (expression/pure-true? (conditional/alternative expression))))))
714
715(define-method/pure-true? 'CONSTANT
716  (lambda (expression)
717    (eq? (constant/value expression) #t)))
718
719(define-method/pure-true? 'DECLARATION
720  (lambda (expression)
721    (expression/pure-true? (declaration/expression expression))))
722
723(define-method/pure-true? 'DELAY false-procedure)
724
725(define-method/pure-true? 'DISJUNCTION
726  (lambda (expression)
727    (and (expression/effect-free? (disjunction/predicate expression))
728         (expression/boolean? (disjunction/predicate expression))
729         (expression/pure-true? (disjunction/alternative expression)))))
730
731(define-method/pure-true? 'OPEN-BLOCK false-procedure)
732
733(define-method/pure-true? 'PROCEDURE false-procedure)
734
735(define-method/pure-true? 'QUOTATION false-procedure)
736
737(define-method/pure-true? 'REFERENCE false-procedure)
738
739(define-method/pure-true? 'SEQUENCE
740  (lambda (expression)
741    (and (for-all? (except-last-pair (sequence/actions expression))
742                   expression/effect-free?)
743         (expression/pure-true? (last (sequence/actions expression))))))
744
745(define-method/pure-true? 'THE-ENVIRONMENT false-procedure)
746
747;;; EXPRESSION/SIZE <expr>
748;;
749;; Returns an integer count of the number of SCode nodes in the expression.
750;; Used to avoid exponential code bloat when adding INTEGRATE-OPERATOR
751;; declarations.
752(declare (integrate-operator expression/size))
753
754(define (expression/size expression)
755  ((expression/method size-dispatch-vector expression) expression))
756
757(define size-dispatch-vector
758  (expression/make-dispatch-vector))
759
760(define define-method/size
761  (expression/make-method-definer size-dispatch-vector))
762
763(define-method/size 'ACCESS
764  (lambda (expression)
765    (fix:1+ (expression/size (access/environment expression)))))
766
767(define-method/size 'ASSIGNMENT
768  (lambda (expression)
769    (fix:1+ (expression/size (assignment/value expression)))))
770
771(define-method/size 'COMBINATION
772  (lambda (expression)
773    (fold-left (lambda (total operand)
774                 (fix:+ total (expression/size operand)))
775               (fix:1+ (expression/size (combination/operator expression)))
776               (combination/operands expression))))
777
778(define-method/size 'CONDITIONAL
779  (lambda (expression)
780    (fix:+
781     (expression/size (conditional/predicate expression))
782     (fix:+
783      (expression/size (conditional/consequent expression))
784      (fix:1+ (expression/size (conditional/alternative expression)))))))
785
786(define-method/size 'CONSTANT
787  (lambda (expression) (declare (ignore expression)) 1))
788
789(define-method/size 'DECLARATION
790  (lambda (expression)
791    (fix:1+ (expression/size (declaration/expression expression)))))
792
793(define-method/size 'DELAY
794  (lambda (expression)
795    (fix:1+ (expression/size (delay/expression expression)))))
796
797(define-method/size 'DISJUNCTION
798  (lambda (expression)
799    (fix:+ (expression/size (disjunction/predicate expression))
800           (fix:1+ (expression/size (disjunction/alternative expression))))))
801
802(define-method/size 'OPEN-BLOCK
803  (lambda (expression)
804    (fold-left (lambda (total action)
805                (if (eq? action open-block/value-marker)
806                    total
807                    (fix:+ total (expression/size action))))
808              1
809              (open-block/actions expression))))
810
811(define-method/size 'PROCEDURE
812  (lambda (expression)
813    (fix:1+ (expression/size (procedure/body expression)))))
814
815(define-method/size 'QUOTATION
816  (lambda (expression)
817    (fix:1+ (expression/size (quotation/expression expression)))))
818
819(define-method/size 'REFERENCE
820  (lambda (expression)
821    (declare (ignore expression))
822    1))
823
824(define-method/size 'SEQUENCE
825  (lambda (expression)
826    (fold-left (lambda (total action)
827                 (fix:+ total (expression/size action)))
828               1
829               (sequence/actions expression))))
830
831;;; EXPRESSION->list <expr>
832;;
833;; Returns an list representation of the SCode nodes in the expression.
834;; Used for debugging sf.
835
836(define (expression->list expression)
837  ((expression/method expression->list-dispatch-vector expression) expression))
838
839(define expression->list-dispatch-vector
840  (expression/make-dispatch-vector))
841
842(define define-method/expression->list
843  (expression/make-method-definer expression->list-dispatch-vector))
844
845(define-method/expression->list 'ACCESS
846  (lambda (expression)
847    `(ACCESS ,(access/name expression)
848	     ,(expression->list (access/environment expression)))))
849
850(define-method/expression->list 'ASSIGNMENT
851  (lambda (expression)
852    `(SET! ,(assignment/variable expression)
853	   ,(expression->list (assignment/value expression)))))
854
855(define-method/expression->list 'COMBINATION
856  (lambda (expression)
857    (cons (expression->list (combination/operator expression))
858	  (map expression->list (combination/operands expression)))))
859
860(define-method/expression->list 'CONDITIONAL
861  (lambda (expression)
862    `(IF ,(expression->list (conditional/predicate expression))
863	 ,(expression->list (conditional/consequent expression))
864	 ,(expression->list (conditional/alternative expression)))))
865
866(define-method/expression->list 'CONSTANT
867  (lambda (expression) (constant/value expression)))
868
869(define-method/expression->list 'DECLARATION
870  (lambda (expression)
871    `(DECLARE ,(declaration/declarations expression)
872	      ,(expression->list (declaration/expression expression)))))
873
874(define-method/expression->list 'DELAY
875  (lambda (expression)
876    `(DELAY ,(expression->list (delay/expression expression)))))
877
878(define-method/expression->list 'DISJUNCTION
879  (lambda (expression)
880    `(OR ,(expression->list (disjunction/predicate expression))
881	 ,(expression->list (disjunction/alternative expression)))))
882
883(define-method/expression->list 'OPEN-BLOCK
884  (lambda (expression)
885    `(OPEN-BLOCK
886      ',(map variable/name (open-block/variables expression))
887      ,@(map (lambda (action)
888	       (if (eq? action open-block/value-marker)
889		   `(QUOTE ,action)
890		   (expression->list action)))
891	     (open-block/actions expression)))))
892
893(define-method/expression->list 'PROCEDURE
894  (lambda (expression)
895    (let ((name (procedure/name expression))
896	  (required (map variable/name (procedure/required expression)))
897	  (optional (map variable/name (procedure/optional expression)))
898	  (rest     (let ((rest-arg (procedure/rest expression)))
899		      (and rest-arg
900			   (variable/name rest-arg)))))
901      `(PROCEDURE ,name
902		  ,(make-lambda-list required optional rest '())
903		  ,(expression->list (procedure/body expression))))))
904
905(define-method/expression->list 'QUOTATION
906  (lambda (expression)
907    `(QUOTE ,(quotation/expression expression))))
908
909(define-method/expression->list 'REFERENCE
910  (lambda (expression)
911    (variable/name (reference/variable expression))))
912
913(define-method/expression->list 'SEQUENCE
914  (lambda (expression)
915    `(BEGIN ,@(map expression->list (sequence/actions expression)))))
916