home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mitsch75.zip / scheme-7_5_17-src.zip / scheme-7.5.17 / src / sf / reduct.scm < prev    next >
Text File  |  1999-01-02  |  17KB  |  582 lines

  1. #| -*-Scheme-*-
  2.  
  3. $Id: reduct.scm,v 4.10 1999/01/02 06:19:10 cph Exp $
  4.  
  5. Copyright (c) 1988-1999 Massachusetts Institute of Technology
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful, but
  13. WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15. General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. |#
  21.  
  22. ;;;; SCode Optimizer: User defined reductions
  23. ;;; package: (scode-optimizer expansion)
  24.  
  25. (declare (usual-integrations)
  26.      (automagic-integrations)
  27.      (open-block-optimizations)
  28.      (eta-substitution)
  29.      (integrate-external "object"))
  30.  
  31. ;;;; Reductions and replacements
  32.  
  33. #|
  34.  
  35. REPLACE-OPERATOR declaration
  36.  
  37. Generates SF-time expanders (transformers for sf) for operations
  38. that act differently depending on the number of arguments.
  39.  
  40. (replace-operator (<name> (<nargs1> <value1>) (<nargs2> <value2>) ...))
  41.  
  42. <name> is a symbol
  43. <nargs1> is a non-negative integer or one of the symbols ANY, ELSE, OTHERWISE.
  44. <valueN> is a simple expression:
  45.   <symbol>                    ; means a variable
  46.   (QUOTE <constant>) = '<constant>        ; means a constant
  47.   (PRIMITIVE <primitive name> { <arity> })    ; means a primitive
  48.   (GLOBAL <variable>)                ; means a global variable
  49.  
  50. replaces non-shadowed calls to <name> with <nargsN> arguments
  51. with a call to <valueN> with the same arguments.
  52.  
  53. Examples:
  54.  
  55. (replace-operator (map (2 map-2) (3 map-3)))
  56.  
  57. replaces (map f l) with (map-2 f l)
  58. and (map (lambda (x) (car x)) frob l)
  59. with (map-3 (lambda (x) (car x)) frob l)
  60. |#
  61.  
  62. #|
  63. REDUCE-OPERATOR declaration
  64.  
  65. Generates SF-time expanders (transformers for sf) for operations
  66. obtained by REDUCEing a binary operator.
  67.  
  68. (reduce-operator (<name> <binop>
  69.           { (group <ordering>)
  70.             (null-value <value> <null-option>)
  71.             (singleton <unop>)
  72.             (wrapper <wrap> {<n>})
  73.             (maximum <m>)
  74.             }))
  75.  
  76. <name> is a symbol
  77.  
  78. <n> and <m> are non-negative integers.
  79.  
  80. <binop>, <value>, <unop>, and <wrap> are simple expressions as above.
  81.  
  82. <null-option> is a member of {ALWAYS, ANY, ONE, SINGLE, NONE, EMPTY}
  83.  
  84. <ordering> is a member of {LEFT, RIGHT, ASSOCIATIVE}
  85.  
  86. 1) <name> is the name of the generic operation to be reduced.
  87.  
  88. 2) <binop> is a binary operation which performs the reduction.
  89.  
  90. 3) The group option specifies whether <binop> associates to the right
  91. or to the left to produce <name>.
  92.  
  93. 4) The null-value option specifies a value to use in the following
  94. cases (each case is included in the following):
  95.  
  96. NONE, EMPTY: When no arguments are supplied to <name>, <value> is
  97. returned.
  98.  
  99. ONE, SINGLE: When a single argument is provided to <name>, <value>
  100. becomes the second argument to <binop>.
  101.  
  102. ANY, ALWAYS: <binop> is used on the "odd" argument, and <value>
  103. provides the remaining argument to <binop>.
  104.  
  105. In the above options, when <value> is supplied to <binop>, it is
  106. supplied on the left if grouping to the left, otherwise it is supplied
  107. on the right.
  108.  
  109. 5) The singleton option specifies a function, <unop>, to be invoked on
  110. the single argument left.  This option supersedes the null-value option,
  111. which can only take the value NONE.
  112.  
  113. 6) The wrapper option specifies a function, <wrap>, to be invoked on the
  114. result of the outermost call to <binop> after the expansion.
  115. If <n> is provided it must be a non-negative integer indicating a number
  116. of arguments that are transferred verbatim from the original call to
  117. the wrapper.  They are passed to the left of the reduction.
  118.  
  119. 7) The maximum option specifies that calls with more than <m> arguments
  120. should not be reduced.
  121.  
  122. Examples:
  123.  
  124. (declare (reduce-operator
  125.       (CONS* (PRIMITIVE cons))
  126.       (LIST (PRIMITIVE cons)
  127.         (NULL-VALUE '() ANY))
  128.       (+ %+ (NULL-VALUE 0 NONE) (GROUP RIGHT))
  129.       (- %- (NULL-VALUE 0 SINGLE) (GROUP LEFT))
  130.       (VECTOR (PRIMITIVE cons)
  131.           (GROUP RIGHT)
  132.           (NULL-VALUE '() ALWAYS)
  133.           (WRAPPER list->vector))
  134.       (APPLY (PRIMITIVE cons)
  135.          (GROUP RIGHT)
  136.          (WRAPPER (GLOBAL apply) 1))))
  137.  
  138. |#
  139.  
  140. ;;;; Syntax stubs
  141.  
  142. ;; Only the procedures under this heading need to be replaced to make
  143. ;; the code below work on s-expressions, scode, or other structure.
  144. ;; The only other assumption made below is that an expanders'
  145. ;; parameter list is
  146. ;;    (expr operands if-expanded if-not-expanded block)
  147. ;; Where
  148. ;;  - expr is the current expression
  149. ;;  - operands are the arguments to the "procedure" being reduced.
  150. ;;  - if-expanded is a procedure of 1 argument (the expanded expression)
  151. ;;  which must be invoked if the expansion (reduction) was succesful.
  152. ;;  - if-not-expanded is a procedure of no arguments to be invoked on
  153. ;;  failure.
  154. ;;  - block is the compile (syntax) time representation of the environment.
  155.  
  156. (define (lookup name block)
  157.   (reference/make
  158.    false
  159.    block
  160.    (or (block/lookup-name block name false)
  161.        (block/lookup-name (integrate/get-top-level-block) name true))))
  162.  
  163. (define-integrable (handle-variable object core)
  164.   (if (variable? object)
  165.       (let ((name (variable/name object)))
  166.     (core (lambda (block)
  167.         (declare (integrate block))
  168.         (lookup name block))))
  169.       (core (lambda (block)
  170.           block            ; ignore
  171.           object))))
  172.  
  173. (define (->expression procedure exp block)
  174.   (define (fail)
  175.     (error "Bad primitive expression" procedure exp))
  176.  
  177.   (define-integrable (constant value)
  178.     (constant/make false value))
  179.  
  180.   (cond ((symbol? exp)
  181.      (variable/make block exp '()))
  182.     ((not (pair? exp))
  183.      (constant exp))
  184.     ((eq? (car exp) 'PRIMITIVE)
  185.      (cond ((or (null? (cdr exp)) (not (list? exp)))
  186.         (fail))
  187.            ((null? (cddr exp))
  188.         (constant (make-primitive-procedure (cadr exp))))
  189.            ((null? (cdddr exp))
  190.         (constant
  191.          (make-primitive-procedure (cadr exp) (caddr exp))))
  192.            (else
  193.         (fail))))
  194.     ((eq? (car exp) 'QUOTE)
  195.      (if (or (not (pair? (cdr exp)))
  196.          (not (null? (cddr exp))))
  197.          (fail))
  198.      (constant (cadr exp)))
  199.     ((eq? (car exp) 'GLOBAL)
  200.      (if (or (not (pair? (cdr exp)))
  201.          (not (null? (cddr exp)))
  202.          (not (symbol? (cadr exp))))
  203.          (fail))
  204.      (global-ref/make (cadr exp)))
  205.     (else
  206.      (fail))))
  207.  
  208. ;; any-shadowed? prevents reductions in any environment where any of
  209. ;; the names introduced by the reduction has been shadowed.  The
  210. ;; search stops at the environment (block) where the declaration
  211. ;; appeared, since it is assumed that the binding is shared there.
  212.  
  213. (define (any-shadowed? var-list source target)
  214.   (let loop ((l var-list))
  215.     (and (not (null? l))
  216.      (or (block/limited-lookup target (variable/name (car l)) source)
  217.          (loop (cdr l))))))
  218.  
  219. (define (filter-vars expr-list)
  220.   (let loop ((l expr-list)
  221.          (done '()))
  222.     (cond ((null? l)
  223.        done)
  224.       ((variable? (car l))
  225.        (loop (cdr l) (cons (car l) done)))
  226.       (else
  227.        (loop (cdr l) done)))))
  228.  
  229. (define (combine-1 block unop x)
  230.   (combination/make false block unop (list x)))
  231.  
  232. (define (combine-2 block binop x y)
  233.   (combination/make false block binop (list x y)))
  234.  
  235. ;;;; Building blocks
  236.  
  237. ;; The arguments to the groupers below come from this set
  238.  
  239. (define (identity-combiner block value combiner)
  240.   block combiner            ; ignored
  241.   value)
  242.  
  243. (define (->singleton-combiner null)
  244.   (handle-variable null
  245.    (lambda (null)
  246.      (declare (integrate null))
  247.      (lambda (block value combiner)
  248.        (combiner block value (null block))))))
  249.   
  250. (define (->mapper-combiner mapper)
  251.   (handle-variable mapper
  252.    (lambda (mapper)
  253.      (declare (integrate mapper))
  254.      (lambda (block value combiner)
  255.        combiner                ; ignored
  256.        (combine-1 block (mapper block) value)))))
  257.  
  258. (define (->wrapper mapper)
  259.   (handle-variable mapper
  260.    (lambda (mapper)
  261.      (declare (integrate mapper))
  262.      (lambda (block not-reduced reduced)
  263.        (combination/make false
  264.              block
  265.              (mapper block)
  266.              (append not-reduced
  267.                  (list reduced)))))))
  268.  
  269. (define (identity-wrapper block not-reduced reduced)
  270.   block not-reduced            ; ignored
  271.   reduced)
  272.  
  273. (define (->error-thunk name)
  274.   (lambda (block)
  275.     block                ; ignored
  276.     (error "REDUCER: No supplied values" name)))
  277.  
  278. (define (->value-thunk val)
  279.   (handle-variable val
  280.    (lambda (val)
  281.      (declare (integrate val))
  282.      (lambda (block)
  283.        (val block)))))
  284.  
  285. (define (invert binop)
  286.   (lambda (block x y)
  287.     (binop block y x)))
  288.  
  289. ;;;; Groupers
  290.  
  291. (define (make-grouper spare-args min-args max-args
  292.               map1 map2
  293.               binop source-block exprs
  294.               wrap last single none)
  295.   (let ((expr (->expression 'REDUCE-OPERATOR binop source-block)))
  296.     (let ((vars (filter-vars (cons expr exprs)))
  297.       (binop (map1
  298.           (handle-variable
  299.            expr
  300.            (lambda (expr)
  301.              (declare (integrate expr))
  302.              (lambda (block x y)
  303.                (combine-2 block (expr block) x y)))))))
  304.  
  305.       (lambda (expr operands if-expanded if-not-expanded block)
  306.     (define (group l)
  307.       (if (null? (cdr l))
  308.           (last block (car l) binop)
  309.           (binop block
  310.              (car l)
  311.              (group (cdr l)))))
  312.  
  313.     (if (or (any-shadowed? vars source-block block)
  314.         (let ((l (length operands)))
  315.           (or (< l min-args)
  316.               (and max-args (> l max-args)))))
  317.         (if-not-expanded)
  318.         (if-expanded
  319.          (reassign
  320.           expr
  321.           (let ((l1 (list-head operands spare-args))
  322.             (l2 (map2 (list-tail operands spare-args))))
  323.         (cond ((null? l2)
  324.                (wrap block
  325.                  l1
  326.                  (none block)))
  327.               ((null? (cdr l2))
  328.                (wrap block
  329.                  l1
  330.                  (single block
  331.                      (car l2)
  332.                      (lambda (block x y)
  333.                        (binop block x y)))))
  334.               (else
  335.                (wrap block
  336.                  l1
  337.                  (binop block (car l2)
  338.                     (group (cdr l2))))))))))))))
  339.  
  340. (define (group-right spare-args min-args max-args
  341.              binop source-block exprs
  342.              wrap last single none)
  343.   (make-grouper spare-args min-args max-args
  344.         identity-procedure identity-procedure
  345.         binop source-block exprs
  346.         wrap last single none))
  347.  
  348. (define (group-left spare-args min-args max-args
  349.             binop source-block exprs
  350.             wrap last single none)
  351.   (make-grouper spare-args min-args max-args
  352.         invert reverse
  353.         binop source-block exprs
  354.         wrap last single none))
  355.  
  356. ;;;; Keyword and convenience utilities
  357.  
  358. (define-integrable (with-arguments-from list procedure)
  359.   (apply procedure list))
  360.  
  361. ;;; Keyword decoder
  362.  
  363. (define (decode-options keywords options receiver)
  364.   (define (collect keys)
  365.     (if (null? keys)
  366.     '()
  367.     (cons
  368.      (let ((place (assq (car keys) options)))
  369.        (and place
  370.         (cdr place)))
  371.      (collect (cdr keys)))))
  372.  
  373.   (define (check opts)
  374.     ;; options is guaranteed to be a list.  No need to check for pairness.
  375.     (cond ((null? opts)
  376.        'DONE)
  377.       ((or (not (pair? (car opts)))
  378.            (not (list? (car opts))))
  379.        (error "DECODE-OPTIONS: Bad option" (car opts)))
  380.       ((not (memq (caar opts) keywords))
  381.        (error "DECODE-OPTIONS: Unknown option" (car opts)))
  382.       (else
  383.        (check (cdr opts)))))
  384.  
  385.   (check options)
  386.   (apply receiver (collect keywords)))
  387.  
  388. ;;;; Error and indentation utilities
  389.  
  390. (define (fail name value)
  391.   (error "REDUCE-OPERATOR: Bad option" `(,name ,@value)))
  392.  
  393. (define (incompatible name1 val1 name2 val2)
  394.   (error "REDUCE-OPERATOR: Incompatible options"
  395.      `(,name1 ,val1) `(,name2 ,val2)))
  396.  
  397. (define (with-wrapper wrapper block receiver)
  398.   (cond ((not wrapper)
  399.      (receiver 0 identity-wrapper '()))
  400.     ((null? (cdr wrapper))
  401.      (let ((expr (->expression 'REDUCE-OPERATOR (car wrapper) block)))
  402.        (receiver 0 (->wrapper expr) (list expr))))
  403.     ((and (null? (cddr wrapper))
  404.           (exact-nonnegative-integer? (cadr wrapper)))
  405.      (let ((expr (->expression 'REDUCE-OPERATOR (car wrapper) block)))
  406.        (receiver (cadr wrapper) (->wrapper expr) (list expr))))
  407.     (else
  408.      (fail 'WRAPPER wrapper))))
  409.  
  410. (define (with-singleton singleton block receiver)
  411.   (cond ((not singleton)
  412.      (receiver identity-combiner '()))
  413.     ((null? (cdr singleton))
  414.      (let ((expr (->expression 'REDUCE-OPERATOR (car singleton) block)))
  415.        (receiver (->mapper-combiner expr)
  416.              (list expr))))
  417.     (else
  418.      (fail 'SINGLETON singleton))))
  419.  
  420. ;;;; Reduction top level
  421.  
  422. (define (reducer/make rule block)
  423.   (with-arguments-from rule
  424.     (lambda (name binop . options)
  425.       (decode-options '(NULL-VALUE GROUP SINGLETON WRAPPER MAXIMUM)
  426.       options
  427.     (lambda (null-value group singleton wrapper maximum)
  428.  
  429.       (define (make-reducer-internal grouper)
  430.         (with-wrapper wrapper block
  431.  
  432.           (lambda (spare-args wrap wrap-expr)
  433.         (with-singleton singleton block
  434.  
  435.           (lambda (single-combiner single-expr)
  436.  
  437.             (define (invoke min-args null-expr last single none)
  438.               (let ((max-args
  439.                  (and maximum
  440.                   (if (or (not (null? (cdr maximum)))
  441.                       (not (exact-nonnegative-integer?
  442.                         (car maximum))))
  443.                       (fail 'MAXIMUM maximum)
  444.                       (car maximum)))))
  445.             (grouper spare-args min-args max-args
  446.                  binop block
  447.                  (append null-expr wrap-expr single-expr)
  448.                  wrap last single none)))
  449.  
  450.             (cond ((not null-value)
  451.                (invoke (+ spare-args (if singleton 1 2))
  452.                    '() single-combiner
  453.                    single-combiner (->error-thunk name)))
  454.               ((not (= (length null-value) 2))
  455.                (fail 'NULL-VALUE null-value))
  456.               (else
  457.                (let* ((val (->expression 'REDUCE-OPERATOR
  458.                              (car null-value)
  459.                              block))
  460.                   (combiner (->singleton-combiner val))
  461.                   (null (->value-thunk val)))
  462.                  (case (cadr null-value)
  463.                    ((ANY ALWAYS)
  464.                 (if singleton
  465.                     (incompatible 'SINGLETON singleton
  466.                           'NULL-VALUE null-value))
  467.                 (invoke spare-args (list val) combiner
  468.                     combiner null))
  469.                    ((ONE SINGLE)
  470.                 (if singleton
  471.                     (incompatible 'SINGLETON singleton
  472.                           'NULL-VALUE null-value))
  473.                 (invoke (1+ spare-args) (list val)
  474.                     identity-combiner
  475.                     combiner null))
  476.                    ((NONE EMPTY)
  477.                 (invoke spare-args
  478.                     (list val) single-combiner
  479.                     single-combiner null))
  480.                    (else
  481.                 (fail 'NULL-VALUE null-value)))))))))))
  482.  
  483.       (cond ((not group)
  484.          (make-reducer-internal group-right))
  485.         ((not (null? (cdr group)))
  486.          (fail 'GROUP group))
  487.         (else
  488.          (case (car group)
  489.            ((RIGHT ASSOCIATIVE)
  490.             (make-reducer-internal group-right))
  491.            ((LEFT)
  492.             (make-reducer-internal group-left))
  493.            (else
  494.             (fail 'GROUP group))))))))))
  495.  
  496. ;;;; Replacement top level
  497.  
  498. (define (replacement/make replacement decl-block)
  499.   (call-with-values
  500.       (lambda ()
  501.     (parse-replacement (car replacement)
  502.                (cdr replacement)
  503.                decl-block))
  504.     (lambda (table default)
  505.       (lambda (expr operands if-expanded if-not-expanded block)
  506.     (let* ((len (length operands))
  507.            (candidate (or (and (< len (vector-length table))
  508.                    (vector-ref table len))
  509.                   default)))
  510.       (if (or (not (pair? candidate))
  511.           (and (car candidate)
  512.                (block/limited-lookup block
  513.                          (car candidate)
  514.                          decl-block)))
  515.           (if-not-expanded)
  516.           (if-expanded
  517.            (combination/make (and expr (object/scode expr))
  518.                  block
  519.                  (let ((frob (cdr candidate)))
  520.                    (if (variable? frob)
  521.                        (lookup (variable/name frob) block)
  522.                        frob))
  523.                  operands))))))))
  524.  
  525. (define (parse-replacement name ocases block)
  526.   (define (collect len cases default)
  527.     (let ((output (make-vector len false)))
  528.       (let loop ((cases cases))
  529.     (if (null? cases)
  530.         (values output default)
  531.         (let* ((a-case (car cases))
  532.            (index (car a-case)))
  533.           (if (vector-ref output index)
  534.           (error "REPLACE-OPERATOR: Duplicate arity" name ocases))
  535.           (vector-set! output index (cdr a-case))
  536.           (loop (cdr cases)))))))
  537.  
  538.   (define (fail a-case)
  539.     (error "REPLACE-OPERATOR: Bad replacement" name a-case))
  540.  
  541.   (define (expr->case expr)
  542.     (cons (and (symbol? expr) expr)
  543.       (->expression 'REPLACE-OPERATOR
  544.             expr
  545.             block)))
  546.  
  547.   (let parse ((cases ocases)
  548.           (parsed '())
  549.           (len 0)
  550.           (default false))
  551.     (if (null? cases)
  552.     (collect len parsed default)
  553.     (let ((a-case (car cases)))
  554.       (cond ((or (not (pair? a-case))
  555.              (not (pair? (cdr a-case)))
  556.              (not (null? (cddr a-case))))
  557.          (fail a-case))
  558.         ((exact-nonnegative-integer? (car a-case))
  559.          (let ((len* (car a-case))
  560.                (expr (cadr a-case)))
  561.            (parse (cdr cases)
  562.               (cons (cons len* (expr->case expr))
  563.                 parsed)
  564.               (max (1+ len*) len)
  565.               default)))
  566.         ((memq (car a-case) '(ANY ELSE OTHERWISE))
  567.          (if default
  568.              (error "REPLACE-OPERATOR: Duplicate default" ocases))
  569.          (parse (cdr cases)
  570.             parsed
  571.             len
  572.             (expr->case (cadr a-case))))
  573.         (else
  574.          (fail a-case)))))))
  575.  
  576. ;;; Local Variables:
  577. ;;; eval: (put 'decode-options 'scheme-indent-hook 2)
  578. ;;; eval: (put 'with-arguments-from 'scheme-indent-hook 1)
  579. ;;; eval: (put 'with-wrapper 'scheme-indent-hook 2)
  580. ;;; eval: (put 'with-singleton 'scheme-indent-hook 2)
  581. ;;; End:
  582.