
The eopl language is now racket-based rather than mzscheme-based. This test-suite, which was originally distributed on the book's web-site has been re-written in the new language. Changes include dropping all drscheme-init.scm and top.scm files. Remaining files were renamed to use the .rkt extension and edited to use the #lang syntax (instead of modulue). Require and provide forms were changed to reflect racket's syntax instead of mzscheme's (eg, only-in vs. only). Several occurrences of one-armed ifs were changed to use when and unless. All tests have been run successfully.
208 lines
6.5 KiB
Racket
Executable File
208 lines
6.5 KiB
Racket
Executable File
#lang eopl
|
|
|
|
(require "lang.rkt")
|
|
(require "data-structures.rkt")
|
|
(require "environments.rkt")
|
|
|
|
(provide value-of-program value-of/k)
|
|
(provide trace-apply-procedure)
|
|
|
|
(define trace-apply-procedure (make-parameter #f))
|
|
|
|
;;;;;;;;;;;;;;;; continuations ;;;;;;;;;;;;;;;;
|
|
|
|
|
|
(define-datatype continuation continuation?
|
|
(end-cont) ; []
|
|
(diff1-cont ; cont[(- [] (value-of e2 env))]
|
|
(exp2 expression?)
|
|
(env environment?)
|
|
(cont continuation?))
|
|
(diff2-cont ; cont[(- val1 [])]
|
|
(val1 expval?)
|
|
(cont continuation?))
|
|
(unop-arg-cont
|
|
(unop unary-op?)
|
|
(cont continuation?))
|
|
(if-test-cont
|
|
(exp2 expression?)
|
|
(exp3 expression?)
|
|
(env environment?)
|
|
(cont continuation?))
|
|
(rator-cont ; cont[(apply-proc [] (value-of rand env))]
|
|
(rand expression?)
|
|
(env environment?)
|
|
(cont continuation?))
|
|
(rand-cont ; cont[(apply-proc val1 [])]
|
|
(val1 expval?)
|
|
(cont continuation?))
|
|
(try-cont
|
|
(var symbol?)
|
|
(handler-exp expression?)
|
|
(env environment?)
|
|
(cont continuation?))
|
|
(raise1-cont
|
|
(saved-cont continuation?))
|
|
)
|
|
|
|
;;;;;;;;;;;;;;;; the interpreter ;;;;;;;;;;;;;;;;
|
|
|
|
;; value-of-program : Program -> ExpVal
|
|
(define value-of-program
|
|
(lambda (pgm)
|
|
(cases program pgm
|
|
(a-program (body)
|
|
(value-of/k body (init-env) (end-cont))))))
|
|
|
|
;; value-of/k : Exp * Env * Cont -> FinalAnswer
|
|
;; Page: 173
|
|
(define value-of/k
|
|
(lambda (exp env cont)
|
|
(cases expression exp
|
|
|
|
(const-exp (num) (apply-cont cont (num-val num)))
|
|
|
|
(const-list-exp (nums)
|
|
(apply-cont cont
|
|
(list-val (map num-val nums))))
|
|
|
|
(var-exp (var) (apply-cont cont (apply-env env var)))
|
|
|
|
(diff-exp (exp1 exp2)
|
|
(value-of/k exp1 env
|
|
(diff1-cont exp2 env cont)))
|
|
|
|
(unop-exp (unop exp1)
|
|
(value-of/k exp1 env
|
|
(unop-arg-cont unop cont)))
|
|
|
|
(if-exp (exp1 exp2 exp3)
|
|
(value-of/k exp1 env
|
|
(if-test-cont exp2 exp3 env cont)))
|
|
|
|
(proc-exp (var body)
|
|
(apply-cont cont
|
|
(proc-val
|
|
(procedure var body env))))
|
|
|
|
(call-exp (rator rand)
|
|
(value-of/k rator env
|
|
(rator-cont rand env cont)))
|
|
|
|
;; make let a macro, because I'm too lazy to add the extra
|
|
;; continuation
|
|
(let-exp (var exp1 body)
|
|
(value-of/k
|
|
(call-exp (proc-exp var body) exp1)
|
|
env
|
|
cont))
|
|
|
|
(letrec-exp (p-name b-var p-body letrec-body)
|
|
(value-of/k
|
|
letrec-body
|
|
(extend-env-rec p-name b-var p-body env)
|
|
cont))
|
|
|
|
(try-exp (exp1 var handler-exp)
|
|
(value-of/k exp1 env
|
|
(try-cont var handler-exp env cont)))
|
|
|
|
(raise-exp (exp1)
|
|
(value-of/k exp1 env
|
|
(raise1-cont cont))))))
|
|
|
|
;; apply-cont : continuation * expval -> final-expval
|
|
|
|
(define apply-cont
|
|
(lambda (cont val)
|
|
(cases continuation cont
|
|
(end-cont () val)
|
|
(diff1-cont (exp2 saved-env saved-cont)
|
|
(value-of/k exp2 saved-env (diff2-cont val saved-cont)))
|
|
(diff2-cont (val1 saved-cont)
|
|
(let ((n1 (expval->num val1))
|
|
(n2 (expval->num val)))
|
|
(apply-cont saved-cont
|
|
(num-val (- n1 n2)))))
|
|
(unop-arg-cont (unop cont)
|
|
(apply-cont cont
|
|
(apply-unop unop val)))
|
|
(if-test-cont (exp2 exp3 env cont)
|
|
(if (expval->bool val)
|
|
(value-of/k exp2 env cont)
|
|
(value-of/k exp3 env cont)))
|
|
(rator-cont (rand saved-env saved-cont)
|
|
(value-of/k rand saved-env
|
|
(rand-cont val saved-cont)))
|
|
(rand-cont (val1 saved-cont)
|
|
(let ((proc (expval->proc val1)))
|
|
(apply-procedure proc val saved-cont)))
|
|
;; the body of the try finished normally-- don't evaluate the handler
|
|
(try-cont (var handler-exp saved-env saved-cont)
|
|
(apply-cont saved-cont val))
|
|
;; val is the value of the argument to raise
|
|
(raise1-cont (saved-cont)
|
|
;; we put the short argument first to make the trace more readable.
|
|
(apply-handler val saved-cont))
|
|
)))
|
|
|
|
;; apply-handler : ExpVal * Cont -> FinalAnswer
|
|
(define apply-handler
|
|
(lambda (val cont)
|
|
(cases continuation cont
|
|
;; interesting cases
|
|
(try-cont (var handler-exp saved-env saved-cont)
|
|
(value-of/k handler-exp
|
|
(extend-env var val saved-env)
|
|
saved-cont))
|
|
|
|
(end-cont () (eopl:error 'apply-handler "uncaught exception!"))
|
|
|
|
;; otherwise, just look for the handler...
|
|
(diff1-cont (exp2 saved-env saved-cont)
|
|
(apply-handler val saved-cont))
|
|
(diff2-cont (val1 saved-cont)
|
|
(apply-handler val saved-cont))
|
|
(if-test-cont (exp2 exp3 env saved-cont)
|
|
(apply-handler val saved-cont))
|
|
(unop-arg-cont (unop saved-cont)
|
|
(apply-handler val saved-cont))
|
|
(rator-cont (rand saved-env saved-cont)
|
|
(apply-handler val saved-cont))
|
|
(rand-cont (val1 saved-cont)
|
|
(apply-handler val saved-cont))
|
|
(raise1-cont (cont)
|
|
(apply-handler val cont))
|
|
)))
|
|
|
|
|
|
;; apply-procedure : procedure * expval * cont -> final-expval
|
|
|
|
(define apply-procedure
|
|
(lambda (proc1 arg cont)
|
|
(cases proc proc1
|
|
(procedure (var body saved-env)
|
|
(value-of/k body
|
|
(extend-env var arg saved-env)
|
|
cont)))))
|
|
|
|
|
|
(define apply-unop
|
|
(lambda (unop val)
|
|
(cases unary-op unop
|
|
(null?-unop ()
|
|
(bool-val
|
|
(null? (expval->list val))))
|
|
(car-unop ()
|
|
(car (expval->list val)))
|
|
(cdr-unop ()
|
|
(list-val (cdr (expval->list val))))
|
|
(zero?-unop ()
|
|
(bool-val
|
|
(zero? (expval->num val)))))))
|
|
|
|
|
|
;; to get the detailed trace:
|
|
;; (trace value-of/k apply-cont apply-handler)
|
|
|