Initial revision
authorGuillermo J. Rozas <edu/mit/csail/zurich/gjr>
Wed, 11 May 1988 04:20:07 +0000 (04:20 +0000)
committerGuillermo J. Rozas <edu/mit/csail/zurich/gjr>
Wed, 11 May 1988 04:20:07 +0000 (04:20 +0000)
v7/src/sf/reduct.scm [new file with mode: 0644]

diff --git a/v7/src/sf/reduct.scm b/v7/src/sf/reduct.scm
new file mode 100644 (file)
index 0000000..c150bf1
--- /dev/null
@@ -0,0 +1,427 @@
+#| -*-Scheme-*-
+
+$Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/sf/reduct.scm,v 1.1 1988/05/11 04:20:07 jinx Exp $
+
+Copyright (c) 1988 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science.  Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. |#
+
+;;;; SCode Optimizer: User defined reductions
+
+(declare (usual-integrations)
+        (automagic-integrations)
+        (open-block-optimizations)
+        (eta-substitution)
+        (integrate-external "object"))
+\f
+;;;; Reductions
+
+#|
+
+REDUCE-OPERATOR declaration
+
+Generates syntax time expanders (transformers for sf) for operations
+obtained by REDUCEing a binary operator.
+
+(reduce-operator (<name> <binop>
+                 { (group <ordering>)
+                   (null-value <value> <null-option>)
+                   (singleton <unop>)
+                   (wrapper <wrap>)
+                   }))
+
+<name> is a symbol
+
+<binop>, <value>, <unop>, and <wrap> are simple expressions
+(currently not checked):
+  '<constant>
+  <variable>
+  (primitive <primitive name> { <arity> })
+
+<null-option> is a member of {ALWAYS, ANY, ONE, SINGLE, NONE, EMPTY}
+
+<ordering> is a member of {LEFT, RIGHT, ASSOCIATIVE}
+
+1) <name> is the name of the generic operation to be reduced.
+
+2) <binop> is a binary operation which performs the reduction.
+
+3) The group option specifies whether <binop> associates to the right
+or to the left to produce <name>.
+
+4) The null-value option specifies a value to use in the following
+cases (each case is included in the following):
+
+NONE, EMPTY: When no arguments are supplied to <name>, <value> is
+returned.
+
+ONE, SINGLE: When a single argument is provided to <name>, <value>
+becomes the second argument to <binop>.
+
+ANY, ALWAYS: <binop> is used on the "odd" argument, and <value>
+provides the remaining argument to <binop>.
+
+In the above options, when <value> is supplied to <binop>, it is
+supplied on the left if grouping to the left, otherwise it is supplied
+on the right.
+
+5) The singleton option specifies a function, <unop>, to be invoked on
+the single argument left.  This option supersedes the null-value option,
+which can only take the value NONE.
+
+6) The wrapper option specifies a function, <wrap>, to be invoked on the
+result of the outermost call to <binop> after the expansion.
+
+Examples:
+
+(declare (reduce-operator
+         (CONS* (primitive cons))
+         (LIST (primitive cons) (NULL-VALUE '() ANY))
+         (+ %+ (NULL-VALUE 0 NONE) (GROUP RIGHT))
+         (- %- (NULL-VALUE 0 SINGLE) (GROUP LEFT))))
+
+|#
+\f
+;;;; Syntax stubs
+
+;; Only the procedures under this heading need to be replaced to make
+;; the code below work on s-expressions, scode, or other structure.
+;; The only other assumption made below is that an expanders'
+;; parameter list is
+;;     (operands if-expanded if-not-expanded block)
+;; Where
+;;  - operands are the arguments to the "procedure" being reduced.
+;;  - if-expanded is a procedure of 1 argument (the expanded expression)
+;;  which must be invoked if the expansion (reduction) was succesful.
+;;  - if-not-expanded is a procedure of no arguments to be invoked on
+;;  failure.
+;;  - block is the compile (syntax) time representation of the environment.
+
+(define (lookup name block)
+  (reference/make
+   block
+   (or (block/lookup-name block name false)
+       (block/lookup-name global-block name true))))
+
+(declare (integrate-operator handle-variable))
+
+(define (handle-variable object core)
+  (declare (integrate object core))
+  (if (variable? object)
+      (let ((name (variable/name object)))
+       (core (lambda (block)
+               (declare (integrate block))
+               (lookup name block))))
+      (core (lambda (block)
+             block                     ; ignore
+             object))))
+
+(define (->expression exp block)
+  (cond ((symbol? exp)
+        (variable/make block exp '()))
+       ((not (pair? exp))
+        (constant/make exp))
+       ((eq? (car exp) 'PRIMITIVE)
+        (cond ((or (null? (cdr exp)) (not (list? exp)))
+               (error "MAKE-REDUCER: Bad PRIMITIVE expression" exp))
+              ((null? (cddr exp))
+               (constant/make (make-primitive-procedure (cadr exp))))
+              ((null? (cdddr exp))
+               (constant/make
+                (make-primitive-procedure (cadr exp) (caddr exp))))
+              (else
+               (error "MAKE-REDUCER: Bad PRIMITIVE expression" exp))))
+       ((eq? (car exp) 'QUOTE)
+        (cadr exp))
+       (else
+        (error "MAKE-REDUCER: Bad expression" exp))))
+\f
+;; any-shadowed? prevents reductions in any environment where any of
+;; the names introduced by the reduction has been shadowed.  The
+;; search stops at the environment (block) where the declaration
+;; appeared, since it is assumed that the binding is shared there.
+
+(define (any-shadowed? var-list source target)
+  (let loop ((l var-list))
+    (and (not (null? l))
+        (or (shadowed? (variable/name (car l)) source target)
+            (loop (cdr l))))))
+
+(define (shadowed? name source target)
+  (let search ((block target))
+    (and (not (eq? block source))
+        (or (variable/assoc name (block/bound-variables block))
+            (let ((parent (block/parent block)))
+              (and (not (null? parent))
+                   (search parent)))))))
+
+(define (filter-vars expr-list)
+  (let loop ((l expr-list)
+            (done '()))
+    (cond ((null? l)
+          done)
+         ((variable? (car l))
+          (loop (cdr l) (cons (car l) done)))
+         (else
+          (loop (cdr l) done)))))
+
+(define (combine-1 unop x)
+  (combination/make unop (list x)))
+
+(define (combine-2 binop x y)
+  (combination/make binop (list x y)))
+\f
+;;;; Building blocks
+
+;; The arguments to the groupers below come from this set
+
+(define (identity-combiner block value combiner)
+  block combiner                       ; ignored
+  value)
+
+(define (->singleton-combiner null)
+  (handle-variable null
+   (lambda (null)
+     (declare (integrate null))
+     (lambda (block value combiner)
+       (combiner value (null block))))))
+  
+(define (->mapper-combiner mapper)
+  (handle-variable mapper
+   (lambda (mapper)
+     (declare (integrate mapper))
+     (lambda (block value combiner)
+       combiner                                ; ignored
+       (combine-1 (mapper block) value)))))
+
+(define (->wrapper mapper)
+  (handle-variable mapper
+   (lambda (mapper)
+     (declare (integrate mapper))
+     (lambda (block reduced)
+       (combine-1 (mapper block) reduced)))))
+
+(define (identity-wrapper block reduced)
+  block                                        ; ignored
+  reduced)
+
+(define (->error-thunk name)
+  (lambda (block)
+    block                              ; ignored
+    (error "REDUCER: No supplied values" name)))
+
+(define (->value-thunk val)
+  (handle-variable val
+   (lambda (val)
+     (declare (integrate val))
+     (lambda (block)
+       (val block)))))
+
+(define (invert binop)
+  (lambda (block x y)
+    (binop block y x)))
+\f
+;;;; Groupers
+
+(define (make-grouper map1 map2 binop source-block exprs
+                     wrap last single none)
+  (let ((expr (->expression binop source-block)))
+    (let ((vars (filter-vars (cons expr exprs)))
+         (binop (map1
+                 (handle-variable
+                  expr
+                  (lambda (expr)
+                    (declare (integrate expr))
+                    (lambda (block x y)
+                      (combine-2 (expr block) x y)))))))
+
+      (lambda (operands if-expanded if-not-expanded block)
+       (define (group l)
+         (if (null? (cdr l))
+             (last block (car l) binop)
+             (binop block
+                    (car l)
+                    (group (cdr l)))))
+
+       (if (any-shadowed? vars source-block block)
+           (if-not-expanded)
+           (if-expanded
+            (let ((l (map2 operands)))
+              (cond ((null? l)
+                     (none block))
+                    ((null? (cdr l))
+                     (wrap block (single (car l) binop)))
+                    (else
+                     (wrap block (binop block (car l)
+                                        (group (cdr l)))))))))))))
+
+(define (group-right binop source-block exprs wrap last single none)
+  (make-grouper identity-procedure identity-procedure binop
+               source-block exprs wrap
+               last single none))
+
+(define (group-left binop source-block exprs wrap last single none)
+  (make-grouper invert reverse binop
+               source-block exprs wrap
+               last single none))
+\f
+;;;; Keyword and convenience utilities
+
+(declare (integrate-operator with-arguments-from))
+
+(define (with-arguments-from list procedure)
+  (declare (integrate list procedure))
+  (apply procedure list))
+
+;;; Keyword decoder
+
+(define (decode-options keywords options receiver)
+  (define (collect keys)
+    (if (null? keys)
+       '()
+       (cons
+        (let ((place (assq (car keys) options)))
+          (if (null? place)
+              '()
+              (cdr place)))
+        (collect (cdr keys)))))
+
+  (define (check opts)
+    ;; options is guaranteed to be a list.  No need to check for pairness.
+    (cond ((null? opts)
+          'DONE)
+         ((or (not (pair? (car opts)))
+              (not (list? (car opts))))
+          (error "DECODE-OPTIONS: Bad option" (car opts)))
+         ((not (memq (caar opts) keywords))
+          (error "DECODE-OPTIONS: Unknown option" (car opts)))
+         (else
+          (check (cdr opts)))))
+
+  (check options)
+  (apply receiver (collect keywords)))
+\f
+;;;; Error and indentation utilities
+
+(define (fail name value)
+  (error "MAKE-REDUCER: Bad option" `(,name ,@value)))
+
+(define (incompatible name1 val1 name2 val2)
+  (error "MAKE-REDUCER: Incompatible options"
+        `(,name1 ,val1) `(,name2 ,val2)))
+
+(define (with-wrapper wrapper block receiver)
+  (cond ((not wrapper)
+        (receiver identity-wrapper '()))
+       ((null? (cdr wrapper))
+        (let ((expr (->expression (car wrapper) block)))
+          (receiver (->wrapper expr) (list expr))))
+       (else
+        (fail 'WRAPPER wrapper))))
+
+(define (with-singleton singleton block receiver)
+  (cond ((not singleton)
+        (receiver identity-combiner '()))
+       ((null? (cdr singleton))
+        (let ((expr (->expression (car singleton) block)))
+          (receiver (->mapper-combiner expr)
+                    (list expr))))
+       (else
+        (fail 'SINGLETON singleton))))
+\f
+;;;; Top level
+
+(define (reducer/make rule block)
+  (with-arguments-from rule
+    (lambda (name binop . options)
+      (decode-options
+         '(NULL-VALUE GROUP SINGLETON WRAPPER)
+         options
+       (lambda (null-value group singleton wrapper)
+
+         (define (make-reducer-internal grouper)
+           (with-wrapper wrapper block
+
+             (lambda (wrap wrap-expr)
+               (with-singleton singleton block
+
+                 (lambda (single-combiner single-expr)
+
+                   (define (invoke null-expr last single none)
+                     (grouper binop block
+                              (append null-expr wrap-expr single-expr)
+                              wrap last single none))
+
+                   (cond ((not null-value)
+                          (invoke '() single-combiner
+                                  single-combiner (->error-thunk name)))
+                         ((not (= (length null-value) 2))
+                          (fail 'NULL-VALUE null-value))
+                         (else
+                          (let* ((val (->expression (car null-value) block))
+                                 (combiner (->singleton-combiner val))
+                                 (null (->value-thunk val)))
+                            (case (cadr null-value)
+                              ((ANY ALWAYS)
+                               (if singleton
+                                   (incompatible 'SINGLETON singleton
+                                                 'NULL-VALUE null-value))
+                               (invoke (list val) combiner
+                                       combiner null))
+                              ((ONE SINGLE)
+                               (if singleton
+                                   (incompatible 'SINGLETON singleton
+                                                 'NULL-VALUE null-value))
+                               (invoke (list val) identity-combiner
+                                       combiner null))
+                              ((NONE EMPTY)
+                               (invoke (list val) single-combiner
+                                       single-combiner null))
+                              (else
+                               (fail 'NULL-VALUE null-value)))))))))))
+\f
+         (cond ((not group)
+                (make-reducer-internal group-right))
+               ((not (null? (cdr group)))
+                (fail 'GROUP group))
+               (else
+                (case (car group)
+                  ((RIGHT ASSOCIATIVE)
+                   (make-reducer-internal group-right))
+                  ((LEFT)
+                   (make-reducer-internal group-left))
+                  (else
+                   (fail 'GROUP group))))))))))
+\f
+;;; Local Variables:
+;;; eval: (put 'decode-options 'scheme-indent-hook 2)
+;;; eval: (put 'with-arguments-from 'scheme-indent-hook 1)
+;;; eval: (put 'with-wrapper 'scheme-indent-hook 2)
+;;; eval: (put 'with-singleton 'scheme-indent-hook 2)
+;;; End: