
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.
222 lines
5.5 KiB
Racket
Executable File
222 lines
5.5 KiB
Racket
Executable File
#lang eopl
|
|
(require "lang.rkt") ; for expression?
|
|
(require "store.rkt")
|
|
;; (provide (all-from "lang.rkt"))
|
|
(provide (all-defined-out)) ; too many things to list
|
|
|
|
|
|
;;;;;;;;;;;;;;;; expressed values ;;;;;;;;;;;;;;;;
|
|
|
|
(define-datatype expval expval?
|
|
(num-val
|
|
(value number?))
|
|
(bool-val
|
|
(boolean boolean?))
|
|
(proc-val
|
|
(proc proc?))
|
|
(list-val
|
|
(lst (list-of expval?)))
|
|
(mutex-val
|
|
(mutex mutex?))
|
|
)
|
|
|
|
;;; extractors:
|
|
|
|
(define expval->num
|
|
(lambda (v)
|
|
(cases expval v
|
|
(num-val (num) num)
|
|
(else (expval-extractor-error 'num v)))))
|
|
|
|
(define expval->bool
|
|
(lambda (v)
|
|
(cases expval v
|
|
(bool-val (bool) bool)
|
|
(else (expval-extractor-error 'bool v)))))
|
|
|
|
(define expval->proc
|
|
(lambda (v)
|
|
(cases expval v
|
|
(proc-val (proc) proc)
|
|
(else (expval-extractor-error 'proc v)))))
|
|
|
|
(define expval->list
|
|
(lambda (v)
|
|
(cases expval v
|
|
(list-val (lst) lst)
|
|
(else (expval-extractor-error 'list v)))))
|
|
|
|
(define expval->mutex
|
|
(lambda (v)
|
|
(cases expval v
|
|
(mutex-val (l) l)
|
|
(else (expval-extractor-error 'mutex v)))))
|
|
|
|
(define expval-extractor-error
|
|
(lambda (variant value)
|
|
(eopl:error 'expval-extractors "Looking for a ~s, found ~s"
|
|
variant value)))
|
|
|
|
;;;;;;;;;;;;;;;; mutexes ;;;;;;;;;;;;;;;;
|
|
|
|
(define-datatype mutex mutex?
|
|
(a-mutex
|
|
(ref-to-closed? reference?) ; ref to bool
|
|
(ref-to-wait-queue reference?))) ; ref to (listof thread)
|
|
|
|
;;;;;;;;;;;;;;;; procedures ;;;;;;;;;;;;;;;;
|
|
|
|
(define-datatype proc proc?
|
|
(procedure
|
|
(bvar symbol?)
|
|
(body expression?)
|
|
(env environment?)))
|
|
|
|
;; used by begin-exp
|
|
(define fresh-identifier
|
|
(let ((sn 0))
|
|
(lambda (identifier)
|
|
(set! sn (+ sn 1))
|
|
(string->symbol
|
|
(string-append
|
|
(symbol->string identifier)
|
|
"%" ; this can't appear in an input identifier
|
|
(number->string sn))))))
|
|
|
|
;;;;;;;;;;;;;;;; continuations ;;;;;;;;;;;;;;;;
|
|
|
|
|
|
(define-datatype continuation continuation?
|
|
|
|
(end-main-thread-cont)
|
|
(end-subthread-cont)
|
|
|
|
(diff1-cont ; cont[(- [] (value-of e2 env))]
|
|
(exp2 expression?)
|
|
(env environment?)
|
|
(cont continuation?))
|
|
(diff2-cont ; cont[(- val1 [])]
|
|
(val1 expval?)
|
|
(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?))
|
|
(set-rhs-cont
|
|
(loc reference?)
|
|
(cont continuation?))
|
|
|
|
(spawn-cont
|
|
(saved-cont continuation?))
|
|
(wait-cont
|
|
(saved-cont continuation?))
|
|
(signal-cont
|
|
(saved-cont continuation?))
|
|
|
|
(unop-arg-cont
|
|
(unop1 unop?)
|
|
(cont continuation?))
|
|
)
|
|
|
|
;;;;;;;;;;;;;;;; environments ;;;;;;;;;;;;;;;;
|
|
|
|
;;; represent environment as a list of bindings.
|
|
;;; binding ::= (id expval)
|
|
;;; | ((list-of id) (list-of bvar) (list-of expression))
|
|
|
|
;;; The first binding for extend-env, the second is for
|
|
;;; extend-env-rec.
|
|
|
|
;;; this representation is designed to make the printed representation
|
|
;;; of the environment more readable.
|
|
|
|
;;; This should probably be factored out into a module called
|
|
;;; environments.scm, like it is in most of the other interpreters.
|
|
|
|
(define empty-env
|
|
(lambda ()
|
|
'()))
|
|
|
|
(define empty-env?
|
|
(lambda (x) (null? x)))
|
|
|
|
(define extend-env
|
|
(lambda (sym val old-env)
|
|
(cons (list sym val) old-env)))
|
|
|
|
(define extend-env-rec*
|
|
(lambda (p-names b-vars p-bodies saved-env)
|
|
(cons
|
|
(list p-names b-vars p-bodies)
|
|
saved-env)))
|
|
|
|
(define apply-env
|
|
(lambda (env search-sym)
|
|
(if (null? env)
|
|
(eopl:error 'apply-env "No binding for ~s" search-sym)
|
|
(let* ((binding (car env))
|
|
(saved-env (cdr env)))
|
|
(if (symbol? (car binding))
|
|
;; ok, this is an extend-env
|
|
(if (eqv? search-sym (car binding))
|
|
(cadr binding)
|
|
(apply-env saved-env search-sym))
|
|
;; no, this is an extend-env-rec
|
|
(let ((pos (locate search-sym (car binding)))
|
|
(b-vars (cadr binding))
|
|
(p-bodies (caddr binding)))
|
|
(if pos
|
|
(newref
|
|
(proc-val
|
|
(procedure
|
|
(list-ref b-vars pos)
|
|
(list-ref p-bodies pos)
|
|
env)))
|
|
(apply-env saved-env search-sym))))))))
|
|
|
|
;; returns position of sym in los, else #f
|
|
(define locate
|
|
(lambda (sym los)
|
|
(let loop ((pos 0) (los los))
|
|
;; los is at position pos of the original los
|
|
(cond
|
|
((null? los) #f)
|
|
((eqv? sym (car los)) pos)
|
|
(else (loop (+ pos 1) (cdr los)))))))
|
|
|
|
(define init-env
|
|
(lambda ()
|
|
(letrec
|
|
((make-init-env
|
|
;; entry ::= (id expval)
|
|
(lambda (entries)
|
|
(if (null? entries)
|
|
(empty-env)
|
|
(extend-env
|
|
(car (car entries))
|
|
(newref (cadr (car entries)))
|
|
(make-init-env (cdr entries)))))))
|
|
(make-init-env
|
|
(list
|
|
(list 'i (num-val 1))
|
|
(list 'v (num-val 5))
|
|
(list 'x (num-val 10)))))))
|
|
|
|
;; not precise, but will do.
|
|
(define environment?
|
|
(list-of
|
|
(lambda (p)
|
|
(and
|
|
(pair? p)
|
|
(or
|
|
(symbol? (car p))
|
|
((list-of symbol?) (car p)))))))
|