diff --git a/src/sf/subst.scm b/src/sf/subst.scm index 6fa6ac5..dcea1ed 100644 --- a/src/sf/subst.scm +++ b/src/sf/subst.scm @@ -453,15 +453,23 @@ you ask for. (combination/optimizing-make expression block - (if (procedure? operator) - (integrate/procedure-operator operations environment - block operator operands) - (let ((operator - (integrate/expression operations environment operator))) - (if (procedure? operator) + (let* ((integrate-procedure + (lambda (operator) (integrate/procedure-operator operations environment - block operator operands) - operator))) + block operator operands))) + (operator + (if (procedure? operator) + (integrate-procedure operator) + (let ((operator + (integrate/expression operations + environment + operator))) + (if (procedure? operator) + (integrate-procedure operator) + operator))))) + (cond ((integrate/compound-operator operator) + => integrate-procedure) + (else operator))) operands)))) (define (integrate/procedure-operator operations environment @@ -490,6 +498,88 @@ you ask for. (else (error "Unknown operation" operation)))) integration-failure))) +;;; ((begin (frob) +;;; (let ((a (foo)) (b (bar))) +;;; (declare (zork a)) +;;; (lambda (zot) +;;; ...body...))) +;;; (mumble frotz)) +;;; => +;;; (let ((zot (mumble frotz))) +;;; (frob) +;;; (let ((a (foo)) (b (bar))) +;;; (declare (zork a)) +;;; ...body...)) +;;; +;;; This improves the code generated by CALL-WITH-VALUES and VALUES, +;;; for which ZOT is RECEIVER and (MUMBLE FROTZ) is the continuation. +;;; It has the consequence of committing to a particular order of +;;; evaluation, though, when the operands of the outermost combination +;;; have side effects. + +(define (integrate/compound-operator operator) + (define (scan-body body encloser) + (if (procedure? body) + (procedure-with-body body (encloser (procedure/body body))) + (scan-operator body encloser))) + (define (scan-operator operator encloser) + (cond ((sequence? operator) + (let ((reversed-actions (reverse (sequence/actions operator)))) + (scan-body (car reversed-actions) + (let ((commands (cdr reversed-actions))) + (lambda (expression) + (encloser + (sequence-with-actions + operator + (reverse (cons expression commands))))))))) + ((combination? operator) + (let ((descend + (lambda (operator*) + (scan-body (procedure/body operator*) + (lambda (body*) + (encloser + (combination-with-operator + operator + (procedure-with-body operator* body*))))))) + (operator* (combination/operator operator))) + (cond ((procedure? operator*) (descend operator*)) + ((integrate/compound-operator operator*) => descend) + (else #f)))) + ((declaration? operator) + (scan-body (declaration/expression operator) + (lambda (expression) + (encloser + (declaration-with-expression operator expression))))) + (else #f))) + (scan-operator operator (lambda (body) body))) + +(define (combination-with-operator combination operator) + (combination/make (combination/scode combination) + (combination/block combination) + operator + (combination/operands combination))) + +(define (procedure-with-body procedure body) + (procedure/make (procedure/scode procedure) + (procedure/block procedure) + (procedure/name procedure) + (procedure/required procedure) + (procedure/optional procedure) + (procedure/rest procedure) + body)) + +(define (sequence-with-actions sequence actions) + (sequence/make (sequence/scode sequence) actions)) + +(define (declaration-with-expression declaration expression) + (declaration/make (declaration/scode declaration) + (declaration/declarations declaration) + expression)) + +(define (non-side-effecting? expression) + (or (reference? expression) + (non-side-effecting-in-sequence? expression))) + (define-method/integrate 'DECLARATION (lambda (operations environment declaration) (let ((declarations (declaration/declarations declaration)) diff --git a/src/sf/usiexp.scm b/src/sf/usiexp.scm index 5d50463..d596073 100644 --- a/src/sf/usiexp.scm +++ b/src/sf/usiexp.scm @@ -351,7 +351,7 @@ USA. (make-combination expr block (ucode-primitive cons) (list (car rest) (list-expansion-loop #f block (cdr rest)))))) - + (define (values-expansion expr operands if-expanded if-not-expanded block) if-not-expanded (if-expanded @@ -373,12 +373,18 @@ USA. (let ((variable (variable/make&bind! block 'RECEIVER))) (procedure/make #f block lambda-tag:unnamed (list variable) '() #f - (combination/make #f - block - (reference/make #f block variable) - (map (lambda (variable) - (reference/make #f block variable)) - variables)))))) + (declaration/make + #f + ;; The receiver is used only once, and all its operand + ;; expressions are effect-free, so integrating here is + ;; safe. + (declarations/parse block '((INTEGRATE-OPERATOR RECEIVER))) + (combination/make #f + block + (reference/make #f block variable) + (map (lambda (variable) + (reference/make #f block variable)) + variables))))))) operands))))) (define (call-with-values-expansion expr operands