home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-386-Vol-2of3.iso / c / cr-macro.zip / INTERP.SCM < prev    next >
Text File  |  1990-02-09  |  11KB  |  412 lines

  1. ; Abstract interpreter for macro proposal
  2.  
  3. ;  interpret : exp * env -> result
  4. ;
  5. ;  syntax = special + macro
  6. ;  special = {'macro, 'let, 'letrec, 'define, 'begin, 'lambda, 'if, 'set!, 'quote}
  7. ;  macro = transformer * env
  8. ;  definitions = (name * result)*
  9. ;  value = boolean + number + pair + procedure + ...
  10. ;
  11. ;  env = name -> binding
  12. ;  binding = syntax + variable
  13.  
  14. (define (interpret exp env model)
  15.   (cond ((literal? exp)
  16.      ((model 'literal) exp env model))
  17.     ((name? exp)
  18.      (interpret-name exp env model))
  19.     ((compound? exp)
  20.      (interpret-compound exp env model))
  21.     (else (error "unknown expression type" exp))))
  22.  
  23. (define (interpret-compound exp env model)
  24.   (let ((op (interpret (operator exp) env model)))
  25.     (cond ((special-operator? op)
  26.        (interpret-special-form op exp env model))
  27.       ((macro-result? op)
  28.        (interpret-macro-application op exp env model))
  29.       (else
  30.        (interpret-combination op exp env model)))))
  31.  
  32. (define (interpret-special-form op exp env model)
  33.   (let ((type (special-operator-type op)))
  34.     (case type
  35.       ((macro)         (interpret-macro         exp env model))
  36.       ((let-syntax)    (interpret-let-syntax    exp env model))
  37.       ((letrec-syntax) (interpret-letrec-syntax exp env model))
  38.       (else (model type exp env)))))
  39.  
  40. (define (interpret-name exp env model)
  41.   (let ((binding (lookup exp env)))
  42.     (cond ((syntax-result? binding) binding)
  43.       (else (model 'variable binding env)))))
  44.  
  45. ; Macro application
  46.  
  47. (define (interpret-macro exp env model)
  48.   (let ((transformer (macro-transformer exp)))
  49.     (make-macro-result (if (procedure? transformer)
  50.                transformer
  51.                (eval-transformer transformer))
  52.                env)))
  53.  
  54. (define (interpret-macro-application op exp env model)
  55.   (with-new-color
  56.     (lambda (rename alist-promise)
  57.       (let* ((macro-env (macro-result-environment op))
  58.          (compare (lambda (client-name macro-name)
  59.             (same-binding? (lookup client-name env)
  60.                        (lookup macro-name macro-env))))
  61.          (new-exp ((macro-result-transformer op) exp rename same-binding?)))
  62.     (model 'macro-application
  63.            (make-macro-application
  64.            new-exp
  65.            (force alist-promise)
  66.            macro-env)        ;???
  67.            env)))))
  68.  
  69. ; let-syntax and letrec-syntax
  70.  
  71. (define (interpret-let-syntax exp env model)
  72.   (interpret-body (let-syntax-body exp)
  73.           (bind ... env)
  74.           model))
  75.  
  76. (define (interpret-letrec-syntax exp outer-env)
  77.   (interpret-body (letrec-syntax-body exp)
  78.           (bind ... env)
  79.           model))
  80.  
  81. ; Process internal definitions
  82.  
  83. (define (with-body-environment env cont)
  84.   (let* ((seen '())
  85.      (env (lambda (request name)
  86.         (if (eq? request 'lookup)
  87.             (set! seen (cons name seen)))
  88.         (env request name))))
  89.     (cont env (lambda () seen))))
  90.  
  91. (define (interpret-body forms env model)
  92.   (with-body-environment env
  93.     (lambda (env seen-thunk)
  94.       (let ((done (lambda (ds forms seen)
  95.             (let ((names (map definition-name ds)))
  96.               (for-each (lambda (name)
  97.                   (if (memq name seen)
  98.                       (error "defined name was used in expanding definition"
  99.                          name)))
  100.                 names)
  101.               (model 'body
  102.                  (make-body names (map definition-rhs-proc ds) forms)
  103.                  env)))))
  104.     (let loop ((forms forms)
  105.            (ds '())
  106.            (seen '()))
  107.       (if (null? (cdr forms))
  108.           ;; Body must contain at least one statement
  109.           (done ds forms seen)
  110.           (let ((first (interpret (car forms) env body-model)))
  111.         (if (eq? first 'expression)
  112.             (done ds forms seen)
  113.             (loop (cdr forms)
  114.               (append first ds)
  115.               (seen-thunk))))))))))
  116.  
  117. (define (body-model operator exp env)
  118.   (case operator
  119.     ((define)
  120.      (make-definitions
  121.       (list (make-definition (define-name exp)
  122.                  (lambda (env model)
  123.                    (interpret (define-rhs exp) env model))))))
  124.     ((begin)
  125.      (let ((forms (begin-statements exp)))
  126.        (cond ((null? forms) ds)
  127.          ((null? (cdr forms)) (interpret (car forms) env body-model))
  128.          (else (let ((first (interpret (car forms) env)))
  129.              (if (eq? first 'expression)
  130.              'expression
  131.              (apply append
  132.                 (cons first
  133.                       (map (lambda (form)
  134.                          (let ((ds (interpret form env body-model)))
  135.                            (if (eq? ds 'expression)
  136.                            (error "intermixed expressions and definitions"
  137.                               exp)
  138.                            ds)))
  139.                        (cdr forms))))))))))
  140.     ((macro-application)
  141.      (let ((result (interpret new-exp (rename alist macro-env env) body-model)))
  142.        (if (definitions? result)
  143.        (make-definitions (map (lambda (d)
  144.                     (make-definition (definition-name d)
  145.                              (lambda (env model)
  146.                                (interpret-definition-rhs d
  147.                                          (rename alist macro-env env)
  148.                                          model))))
  149.                   (definitions-list result)))
  150.        'expression)))
  151.     (else 'expression)))
  152.  
  153. ; Environment operations
  154.  
  155. (define (lookup name env)
  156.   (env 'lookup name))
  157.  
  158. (define (obtain-bindings ds)    ; returns list of (name . binding)
  159.   (let ((names (map definition-name ds)))
  160.     (map cons
  161.      names
  162.      (make-bindings names
  163.             (map force-definition-rhs ds)))))
  164.  
  165. ; Bind takes list of definitions (name . result-promise)
  166.  
  167. (define (bind ds env)
  168.   (really-bind (lambda () ds)
  169.            (delay (obtain-bindings ds))
  170.            env))
  171.  
  172. (define (really-bind current-ds alist-promise env)
  173.   (lambda (name)
  174.     (if (assq name (current-ds))
  175.     (cdr (assq name (force alist-promise)))
  176.     (lookup name env))))
  177.  
  178. ; For internal definitions: it must be possible to expand all of the
  179. ; definitions without knowing the binding of any of them.  The
  180. ; bookkeeping is a pain.
  181.  
  182. (define (make-body-environment outer-env cont)
  183.   (let ((ds '())
  184.     (seen '())
  185.     (more? #t))
  186.     (letrec ((env (really-bind (lambda () ds)
  187.                    (delay (begin (set! more? #f)
  188.                          (obtain-bindings ds)))
  189.                    outer-env)))
  190.       (cont (lambda (name)
  191.           (if more? (set! seen (cons name seen)))
  192.           (lookup name env))
  193.         (lambda (new-ds)
  194.           (if more?
  195.           (if (any (lambda (name)
  196.                  (assq name new-ds))
  197.                seen)
  198.               (error "invalid forward definition reference" ds)
  199.               (set! ds (merge-alists new-ds ds)))
  200.           (error "definition occurs too late" ds)))))))
  201.  
  202. ; This is used by macro application.
  203. ; Compare with filter-syntactic-environment and extend-syntactic-environment
  204. ; in Bawden's implementation.
  205.  
  206. (define (rename name+new-list new-env else-env)
  207.   (lambda (name)
  208.     (let ((probe (right-assq name name+new-list)))
  209.       (if probe
  210.       (lookup (car probe) new-env)
  211.       (lookup name else-env)))))
  212.  
  213. (define same-binding? equal?)
  214.  
  215. ; Syntax
  216.  
  217. (define (syntax-result? result)
  218.   (or (special-operator? result)
  219.       (macro-result? result)))
  220.  
  221. ; Special operators
  222.  
  223. (define (make-special-operator type)
  224.   (vector 'special type))
  225. (define special-operator?
  226.   (vector-predicate 'special))
  227. (define special-operator-type
  228.   (vector-accessor 'special 1))
  229.  
  230. (define (bind-special-operators env)
  231.   (bind (map (lambda (name)
  232.            (make-definition name (delay (make-special-operator name))))
  233.          '(macro let letrec define begin lambda quote if set!))
  234.     env))
  235.  
  236. ; Macros
  237.  
  238. (define (make-macro-result transformer env)
  239.   (vector 'macro transformer env))
  240. (define macro-result?
  241.   (vector-predicate 'macro))
  242. (define macro-result-transformer
  243.   (vector-accessor 'macro 1))
  244. (define macro-result-environment
  245.   (vector-accessor 'macro 2))
  246.  
  247. ; Names, colors, painting
  248.  
  249. (define (make-painted name color)
  250.   (vector 'painted name color))
  251. (define painted? (vector-predicate 'painted))
  252. (define painted-name (vector-accessor 'painted 1))
  253. (define painted-color (vector-accessor 'painted 2))
  254.  
  255. (define (unpaint thing)
  256.   (cond ((painted? thing) (unpaint (painted-name thing)))
  257.     ((pair? thing)
  258.      (let ((x (unpaint (car thing)))
  259.            (y (unpaint (cdr thing))))
  260.        (if (and (eq? x (car thing))
  261.             (eq? y (cdr thing)))
  262.            thing
  263.            (cons x y))))
  264.     ((vector? thing) ...)
  265.     (else thing)))
  266.  
  267. (define (name? thing)
  268.   (or (symbol? thing) (painted? thing)))
  269.  
  270. (define (name->symbol name)
  271.   (if (symbol? name)
  272.       name
  273.       (string->symbol (string-append "."
  274.                      (number->string (painted-color name) '(heur))
  275.                      "."
  276.                      (symbol->string (name->symbol (painted-name name)))))))
  277.  
  278. (define *counter* 0)
  279.  
  280. (define (make-name-generator)
  281.   ;; Don't bump counter if no names are generated
  282.   (let ((color (delay (begin (set! *counter* (+ *counter* 1))
  283.                  *counter*))))
  284.     (lambda (name)
  285.       (make-painted name (force color)))))
  286.  
  287. (define (with-new-color cont)
  288.   (let ((alist '())            ;list of name * painted
  289.     (more? #t)
  290.     (gen (make-name-generator)))
  291.     (cont (lambda (name)
  292.         (let ((probe (assq name alist)))
  293.           (if probe
  294.           (cdr probe)
  295.           (if more?
  296.               (let ((new-name (gen name)))
  297.             (set! alist (cons (cons name new-name)
  298.                       alist))
  299.             new-name)
  300.               (error "this color has expired" name)))))
  301.       (delay (begin (set! more? #f)
  302.             alist)))))
  303.  
  304. ; Expressions
  305.  
  306. (define (literal? x)
  307.   (or (number? x) (string? x) (boolean? x) (char? x)))
  308.  
  309. (define compound? pair?)
  310. (define operator car)
  311. (define operands cdr)
  312.  
  313. ; (macro <transformer>)
  314.  
  315. (define macro-transformer cadr)
  316.  
  317. ; (let-syntax ((<name> <exp>)) <body>)
  318. ; (letrec-syntax ((<name> <exp>)) <body>)
  319.  
  320. (define let-syntax-bspecs cadr)
  321. (define let-syntax-body cddr)
  322.  
  323. (define letrec-syntax-bspecs cadr)
  324. (define letrec-syntax-body cddr)
  325.  
  326. (define bspec-name car)
  327. (define bspec-rhs cadr)
  328.  
  329. ; (define <name> <rhs>)     [rhs = right-hand side]
  330.  
  331. (define define-name cadr)
  332. (define define-rhs caddr)
  333.  
  334. ; (begin <statement>*)
  335.  
  336. (define begin-statements cdr)
  337.  
  338. ; Test routine
  339.  
  340. (define (run exp . maybe-env)
  341.   (set! *counter* 0)
  342.   (result->output
  343.    (interpret exp (if (null? maybe-env)
  344.               (top-env)
  345.               (car maybe-env)))))
  346.  
  347. (define (top-env)
  348.   (bind-special-operators 
  349.    (bind-primitive-values empty-environment)))
  350.  
  351. (define (defs->env defs . maybe-env)
  352.   (make-body-environment (if (null? maybe-env)
  353.                  (top-env)
  354.                  (car maybe-env))
  355.     (lambda (env define!)
  356.       (let ((res (interpret `(begin ,@defs) env)))  ;kludge
  357.     (if (definitions? res)
  358.         (let ((ds (definitions-list res)))
  359.           (define! ds)
  360.           (for-each force-definition-rhs ds)
  361.           env))))))
  362.  
  363.  
  364. ; Test cases
  365.  
  366. #||
  367.  
  368. (run '((macro (lambda (exp c) 1))))
  369.  
  370. (run '((macro (lambda (exp c) '+))))
  371.  
  372. (run '((macro (lambda (exp c) (c '+)))))
  373.  
  374. (run '((lambda () 2 1)))
  375.  
  376. (run '(begin (define x 1) (define y 2)))
  377.  
  378. (run '((lambda () (define x 1) x)))
  379.  
  380. (run '(let ((x 'outer))
  381.     (let ((m (macro (lambda (exp paint) 'x))))
  382.       (let ((x 'inner))
  383.         (m)))))
  384.  
  385. (run '(let ((x 'outer))
  386.     (let ((m (macro (lambda (exp paint) (paint 'x)))))
  387.       (let ((x 'inner))
  388.         (m)))))
  389.  
  390. (run '(letrec ((x (lambda () x)))
  391.     (let ((y x))
  392.       (set! x 2)
  393.       (y))))
  394.  
  395. (run '(let ((x 'outer))
  396.       (letrec ((m (macro (lambda (exp paint) (paint 'x))))
  397.            (x 'inner))
  398.           (m))))
  399.  
  400. (run '(let ((foo (lambda (x) (+ x 1))))
  401.     (let ((m (macro (lambda (exp paint)
  402.               `(,(paint 'foo) ,(cadr exp))))))
  403.       (list (m 3)            ; => 4
  404.         (let ((foo 97))
  405.           (m foo)        ; => 98
  406.           )))))
  407.  
  408. ||#
  409.  
  410. ; (put 'make-body-environment 'scheme-indent-hook 1)
  411. ; (put 'bind 'scheme-indent-hook nil)
  412.