racket/collects/tests/eopl/chapter5/thread-lang/data-structures.rkt
David Van Horn 7491e172ea EOPL test suite re-written in Racket-based #lang eopl and rackunit
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.
2012-02-24 14:46:18 -05:00

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)))))))