Randomized tests for the delimited control model.
Tests in randomized-tests.rkt are deliberately not run by DrDr at the moment because they fail too consistently.
This commit is contained in:
parent
8ff358b559
commit
1ccd6e7a2c
|
@ -1198,6 +1198,8 @@ path/s is either such a string or a list of them.
|
||||||
"collects/redex/examples/church.rkt" drdr:command-line (mzc *)
|
"collects/redex/examples/church.rkt" drdr:command-line (mzc *)
|
||||||
"collects/redex/examples/combinators.rkt" drdr:command-line (mzc *)
|
"collects/redex/examples/combinators.rkt" drdr:command-line (mzc *)
|
||||||
"collects/redex/examples/compatible-closure.rkt" drdr:command-line (mzc *)
|
"collects/redex/examples/compatible-closure.rkt" drdr:command-line (mzc *)
|
||||||
|
"collects/redex/examples/delim-cont/randomized-tests-test.rkt" drdr:timeout 120 drdr:random #t
|
||||||
|
"collects/redex/examples/delim-cont/randomized-tests.rkt" drdr:random #t
|
||||||
"collects/redex/examples/delim-cont/test.rkt" drdr:command-line (mzc *)
|
"collects/redex/examples/delim-cont/test.rkt" drdr:command-line (mzc *)
|
||||||
"collects/redex/examples/letrec.rkt" drdr:command-line (mzc *)
|
"collects/redex/examples/letrec.rkt" drdr:command-line (mzc *)
|
||||||
"collects/redex/examples/omega.rkt" drdr:command-line (mzc *)
|
"collects/redex/examples/omega.rkt" drdr:command-line (mzc *)
|
||||||
|
|
76
collects/redex/examples/delim-cont/model-impl.rkt
Normal file
76
collects/redex/examples/delim-cont/model-impl.rkt
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
#lang racket
|
||||||
|
|
||||||
|
(provide % abort call/comp call/cm current-marks
|
||||||
|
(rename-out [_call/cc call/cc]
|
||||||
|
[_if if]
|
||||||
|
[_+ +]
|
||||||
|
[_print print]
|
||||||
|
[_cons cons]
|
||||||
|
[_set! set!]
|
||||||
|
[_zero? zero?]))
|
||||||
|
|
||||||
|
(define tag
|
||||||
|
(let ([tags (make-hash)])
|
||||||
|
(λ (v)
|
||||||
|
(hash-ref tags v
|
||||||
|
(λ ()
|
||||||
|
(let ([t (make-continuation-prompt-tag)])
|
||||||
|
(hash-set! tags v t)
|
||||||
|
t))))))
|
||||||
|
|
||||||
|
(define-syntax-rule (% tag-val expr handler)
|
||||||
|
(call-with-continuation-prompt
|
||||||
|
(λ () expr)
|
||||||
|
(let ([v tag-val])
|
||||||
|
(if (let comparable? ([v v])
|
||||||
|
(cond [(procedure? v) #f]
|
||||||
|
[(list? v) (andmap comparable? v)]
|
||||||
|
[else #t]))
|
||||||
|
(tag v)
|
||||||
|
(raise-type-error '% "non-procedure" v)))
|
||||||
|
(let ([h handler])
|
||||||
|
(λ (x) (h x)))))
|
||||||
|
|
||||||
|
(define (abort tag-val result)
|
||||||
|
(abort-current-continuation (tag tag-val) result))
|
||||||
|
|
||||||
|
(define ((force-unary f) x) (f x))
|
||||||
|
|
||||||
|
(define (_call/cc proc tag-val)
|
||||||
|
(call/cc (compose proc force-unary) (tag tag-val)))
|
||||||
|
|
||||||
|
(define (call/comp proc tag-val)
|
||||||
|
(call-with-composable-continuation (compose proc force-unary) (tag tag-val)))
|
||||||
|
|
||||||
|
(define (call/cm key val thunk)
|
||||||
|
(with-continuation-mark key val (thunk)))
|
||||||
|
|
||||||
|
(define (current-marks key tag-val)
|
||||||
|
(continuation-mark-set->list
|
||||||
|
(current-continuation-marks (tag tag-val))
|
||||||
|
key))
|
||||||
|
|
||||||
|
(define-syntax-rule (_if e1 e2 e3)
|
||||||
|
(let ([v1 e1])
|
||||||
|
(case v1
|
||||||
|
[(#t) e2]
|
||||||
|
[(#f) e3]
|
||||||
|
[else (raise-type-error 'if "#t or #f" v1)])))
|
||||||
|
|
||||||
|
(define (_+ x y) (+ x y))
|
||||||
|
|
||||||
|
(define (_print n)
|
||||||
|
(if (number? n)
|
||||||
|
(begin (print n) #f)
|
||||||
|
(raise-type-error 'print "number" n)))
|
||||||
|
|
||||||
|
(define (_cons x xs)
|
||||||
|
(if (list? xs)
|
||||||
|
(cons x xs)
|
||||||
|
(raise-type-error 'cons "list?" 1 x xs)))
|
||||||
|
|
||||||
|
(define-syntax-rule (_set! x e)
|
||||||
|
(begin (set! x e) #f))
|
||||||
|
|
||||||
|
(define (_zero? x)
|
||||||
|
(equal? 0 x))
|
147
collects/redex/examples/delim-cont/randomized-tests-test.rkt
Normal file
147
collects/redex/examples/delim-cont/randomized-tests-test.rkt
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
#lang racket
|
||||||
|
|
||||||
|
(require "randomized-tests.rkt"
|
||||||
|
"reduce.rkt"
|
||||||
|
"grammar.rkt"
|
||||||
|
rackunit
|
||||||
|
(except-in redex/reduction-semantics plug))
|
||||||
|
|
||||||
|
(define-syntax (test-transformation stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ program expected-output expected-result)
|
||||||
|
#`(match-let ([(answer actual-output actual-result)
|
||||||
|
(model-eval (transform-intermediate (term program)))])
|
||||||
|
(begin
|
||||||
|
#,(syntax/loc #'expected-output
|
||||||
|
(check-equal? actual-output expected-output))
|
||||||
|
#,(syntax/loc #'expected-result
|
||||||
|
(check-equal? actual-result 'expected-result))))]))
|
||||||
|
|
||||||
|
(test-transformation
|
||||||
|
(<> ()
|
||||||
|
()
|
||||||
|
(% 0
|
||||||
|
(wcm ()
|
||||||
|
((λ (k)
|
||||||
|
(begin (k 7) (print 1)))
|
||||||
|
(cont 0 hole)))
|
||||||
|
(λ (x) x)))
|
||||||
|
"" 7)
|
||||||
|
|
||||||
|
(test-transformation
|
||||||
|
(<> ()
|
||||||
|
()
|
||||||
|
(cont 1 (begin hole (print 3))))
|
||||||
|
"" procedure)
|
||||||
|
|
||||||
|
(test-transformation
|
||||||
|
(<> ()
|
||||||
|
()
|
||||||
|
(% 0
|
||||||
|
(print
|
||||||
|
(wcm ()
|
||||||
|
((λ (k) (begin (k 1) 2))
|
||||||
|
(comp (print hole)))))
|
||||||
|
(λ (x) x)))
|
||||||
|
"12" #f)
|
||||||
|
|
||||||
|
(test-transformation
|
||||||
|
(<> ()
|
||||||
|
(1)
|
||||||
|
(% 1
|
||||||
|
(dw
|
||||||
|
x_1
|
||||||
|
(print 1)
|
||||||
|
(wcm ()
|
||||||
|
((λ (k) (k 3))
|
||||||
|
(cont 1 (dw x_1 (print 1) hole (print 2)))))
|
||||||
|
(print 2))
|
||||||
|
(λ (x) x)))
|
||||||
|
"12" 3)
|
||||||
|
|
||||||
|
(test-transformation
|
||||||
|
(<> ()
|
||||||
|
(1)
|
||||||
|
(% 0
|
||||||
|
((% 0
|
||||||
|
(dw
|
||||||
|
x_1
|
||||||
|
(print 1)
|
||||||
|
(wcm ()
|
||||||
|
((λ (k) k)
|
||||||
|
(cont 0 (dw x_1 (print 1) hole (print 2)))))
|
||||||
|
(print 2))
|
||||||
|
(λ (x) x))
|
||||||
|
3)
|
||||||
|
(λ (x) x)))
|
||||||
|
"1212" 3)
|
||||||
|
|
||||||
|
(test-transformation
|
||||||
|
(<> () []
|
||||||
|
(% 0
|
||||||
|
(wcm ([1 2] [3 4])
|
||||||
|
((λ (x) x)
|
||||||
|
(wcm ([1 5] [3 6])
|
||||||
|
(cons (current-marks 1 0)
|
||||||
|
(cons (current-marks 3 0)
|
||||||
|
(list))))))
|
||||||
|
(λ (x) x)))
|
||||||
|
"" ((5 2) (6 4)))
|
||||||
|
|
||||||
|
(test-transformation
|
||||||
|
(<>
|
||||||
|
()
|
||||||
|
()
|
||||||
|
(dw
|
||||||
|
ra
|
||||||
|
(print 1)
|
||||||
|
(print 2)
|
||||||
|
(print 3)))
|
||||||
|
"23" #f)
|
||||||
|
|
||||||
|
(test-transformation
|
||||||
|
(<> ()
|
||||||
|
()
|
||||||
|
(%
|
||||||
|
1
|
||||||
|
(dw x_1
|
||||||
|
(print 1)
|
||||||
|
(abort 1 (cont 1 (dw x_1 (print 1) hole (print 3))))
|
||||||
|
(print 3))
|
||||||
|
(λ (k) (% 1 (k 4) (λ (x) x)))))
|
||||||
|
"313" 4)
|
||||||
|
|
||||||
|
(test-transformation
|
||||||
|
(<>
|
||||||
|
()
|
||||||
|
()
|
||||||
|
((comp
|
||||||
|
(dw
|
||||||
|
ra
|
||||||
|
(print 1)
|
||||||
|
hole
|
||||||
|
(dw q (print 2) (print 3) (print 4))))
|
||||||
|
5))
|
||||||
|
"134" 5)
|
||||||
|
|
||||||
|
(define (transformation-preserves-meaning? p)
|
||||||
|
(let ([original-result (parameterize ([model-eval-steps 1000]) (model-eval p))]
|
||||||
|
[transformed (transform-intermediate p)]
|
||||||
|
[warn (λ () (eprintf "Long test:\n") (pretty-write p (current-error-port)))]
|
||||||
|
[threshold (* 60 2)])
|
||||||
|
(or (timeout? original-result)
|
||||||
|
(let ([transformed-result
|
||||||
|
(timeout-warn threshold (model-eval transformed) (warn))])
|
||||||
|
(if (answer? original-result)
|
||||||
|
(equal? original-result transformed-result)
|
||||||
|
(not (answer? transformed-result))))
|
||||||
|
; filters bad tests
|
||||||
|
(bad-test? (timeout-warn threshold (impl-eval (impl-program transformed)) (warn))))))
|
||||||
|
|
||||||
|
(define-syntax-rule (test-transformation/randomized . kw-args)
|
||||||
|
(let ([test-number 1])
|
||||||
|
(redex-check grammar p (transformation-preserves-meaning? (term p))
|
||||||
|
#:prepare fix-prog
|
||||||
|
#:source :-> . kw-args)))
|
||||||
|
|
||||||
|
(time (test-transformation/randomized #:attempts 1 #:attempt-size (const 3)))
|
385
collects/redex/examples/delim-cont/randomized-tests.rkt
Normal file
385
collects/redex/examples/delim-cont/randomized-tests.rkt
Normal file
|
@ -0,0 +1,385 @@
|
||||||
|
#lang racket
|
||||||
|
|
||||||
|
(require "grammar.ss"
|
||||||
|
"reduce.rkt"
|
||||||
|
(except-in redex/reduction-semantics plug)
|
||||||
|
racket/runtime-path)
|
||||||
|
|
||||||
|
(provide (all-defined-out))
|
||||||
|
|
||||||
|
(define (main [seed-arg #f])
|
||||||
|
(define seed
|
||||||
|
(if seed-arg
|
||||||
|
(string->number seed-arg)
|
||||||
|
(add1 (random (sub1 (expt 2 31))))))
|
||||||
|
(printf "Test seed: ~s\n" seed)
|
||||||
|
(parameterize ([current-pseudo-random-generator test-prg])
|
||||||
|
(random-seed seed))
|
||||||
|
(parameterize ([redex-pseudo-random-generator test-prg])
|
||||||
|
(time (test #:attempts 3000))
|
||||||
|
(time (test #:source :-> #:attempts 3000))))
|
||||||
|
|
||||||
|
(define-syntax-rule (test . kw-args)
|
||||||
|
(redex-check grammar p (same-behavior? (term p))
|
||||||
|
#:prepare fix-prog . kw-args))
|
||||||
|
|
||||||
|
(define fix-prog
|
||||||
|
(match-lambda
|
||||||
|
[`(<> ,s ,_ ,e)
|
||||||
|
(match-let ([`([,xs ,vs] ...) (remove-duplicates s #:key first)])
|
||||||
|
`(<> ,(map list xs (map (fix-expr xs) vs)) [] ,((fix-expr xs) e)))]))
|
||||||
|
|
||||||
|
(define (fix-expr top-vars)
|
||||||
|
(compose drop-duplicate-binders
|
||||||
|
proper-wcms
|
||||||
|
consistent-dws
|
||||||
|
(curry close top-vars '())))
|
||||||
|
|
||||||
|
(struct error (cause) #:transparent)
|
||||||
|
(struct answer (output result) #:transparent)
|
||||||
|
(struct bad-test (reason) #:transparent)
|
||||||
|
(struct timeout ())
|
||||||
|
|
||||||
|
(define (same-behavior? prog)
|
||||||
|
(let ([impl-behavior (timeout-kill 15 (impl-eval (impl-program (transform-intermediate prog))))])
|
||||||
|
(or (bad-test? impl-behavior)
|
||||||
|
(timeout? impl-behavior)
|
||||||
|
(let ([model-behavior (timeout-warn 30 (model-eval prog) (pretty-write prog))])
|
||||||
|
(or (timeout? model-behavior)
|
||||||
|
(if (error? impl-behavior)
|
||||||
|
(error? model-behavior)
|
||||||
|
(and (answer? model-behavior)
|
||||||
|
(equal? impl-behavior model-behavior))))))))
|
||||||
|
|
||||||
|
(define impl-program
|
||||||
|
(match-lambda
|
||||||
|
[`(<> ,s [] ,e)
|
||||||
|
`(letrec ,s ,e)]
|
||||||
|
[e e]))
|
||||||
|
|
||||||
|
(define-runtime-module-path model-impl "model-impl.rkt")
|
||||||
|
|
||||||
|
(define impl-eval
|
||||||
|
(let ([ns (make-base-empty-namespace)])
|
||||||
|
(parameterize ([current-namespace ns])
|
||||||
|
(namespace-require 'racket)
|
||||||
|
(namespace-require (resolved-module-path-name model-impl)))
|
||||||
|
(define show
|
||||||
|
(match-lambda
|
||||||
|
[(? procedure?) 'procedure]
|
||||||
|
[(? list? vs) (map show vs)]
|
||||||
|
[v v]))
|
||||||
|
(λ (test)
|
||||||
|
(define output (open-output-string))
|
||||||
|
(define result
|
||||||
|
(with-handlers ([exn:fail?
|
||||||
|
(λ (e)
|
||||||
|
(match (exn-message e)
|
||||||
|
[(regexp #rx"%: expected argument of type <non-procedure>")
|
||||||
|
(bad-test "procedure as tag")]
|
||||||
|
[_ (error e)]))])
|
||||||
|
(parameterize ([current-output-port output])
|
||||||
|
(eval test ns))))
|
||||||
|
(if (or (error? result) (bad-test? result))
|
||||||
|
result
|
||||||
|
(answer (get-output-string output)
|
||||||
|
(show result))))))
|
||||||
|
|
||||||
|
(define model-eval-steps (make-parameter +inf.0))
|
||||||
|
|
||||||
|
(define (model-eval prog)
|
||||||
|
(let/ec return
|
||||||
|
(define show
|
||||||
|
(match-lambda
|
||||||
|
[(? number? n) n]
|
||||||
|
[(? boolean? b) b]
|
||||||
|
[`(list . ,vs) (map show vs)]
|
||||||
|
[v 'procedure]))
|
||||||
|
(define (eval prog steps)
|
||||||
|
(define ns (set))
|
||||||
|
(let recur ([p prog] [d steps] [s (set)])
|
||||||
|
(define qs (apply-reduction-relation :-> p))
|
||||||
|
(if (empty? qs)
|
||||||
|
(set! ns (set-add ns p))
|
||||||
|
(if (< d 0)
|
||||||
|
(return (timeout))
|
||||||
|
(for ([q qs])
|
||||||
|
(if (set-member? s q)
|
||||||
|
(return (timeout))
|
||||||
|
(recur q (sub1 d) (set-add s p)))))))
|
||||||
|
(set-map ns values))
|
||||||
|
(match (eval prog (model-eval-steps))
|
||||||
|
[(list (and p `(<> ,_ ,output ,result)))
|
||||||
|
(if (v? result)
|
||||||
|
(answer
|
||||||
|
(apply string-append (map (curry format "~v") output))
|
||||||
|
(show result))
|
||||||
|
(error p))])))
|
||||||
|
|
||||||
|
(define (with-timeout thunk timeout on-timeout)
|
||||||
|
(let ([c (make-channel)])
|
||||||
|
(struct raised (value))
|
||||||
|
(let ([t (thread
|
||||||
|
(λ ()
|
||||||
|
(channel-put
|
||||||
|
c (with-handlers ([exn:fail? raised])
|
||||||
|
(thunk)))))])
|
||||||
|
(match (sync/timeout timeout c)
|
||||||
|
[#f (on-timeout t c)]
|
||||||
|
[(raised v) (raise v)]
|
||||||
|
[x x]))))
|
||||||
|
|
||||||
|
(define-syntax-rule (timeout-kill time expr)
|
||||||
|
(with-timeout (λ () expr) time
|
||||||
|
(λ (t _)
|
||||||
|
(kill-thread t)
|
||||||
|
(timeout))))
|
||||||
|
(define-syntax-rule (timeout-warn time expr warn)
|
||||||
|
(with-timeout (λ () expr) time
|
||||||
|
(λ (_ c)
|
||||||
|
warn
|
||||||
|
(sync c))))
|
||||||
|
|
||||||
|
(define (close top-vars loc-vars expr)
|
||||||
|
(match expr
|
||||||
|
[(? x? x)
|
||||||
|
(let ([bound (append top-vars loc-vars)])
|
||||||
|
(cond [(memq x bound) x]
|
||||||
|
[(not (empty? bound))
|
||||||
|
(random-member bound)]
|
||||||
|
[else (random-literal)]))]
|
||||||
|
[`(set! ,x ,e)
|
||||||
|
(if (empty? top-vars)
|
||||||
|
(close top-vars loc-vars e)
|
||||||
|
`(set! ,(random-member top-vars)
|
||||||
|
,(close top-vars loc-vars e)))]
|
||||||
|
[`(λ ,xs ,e)
|
||||||
|
`(λ ,xs
|
||||||
|
,(close (filter (negate (curryr member xs)) top-vars)
|
||||||
|
(append xs loc-vars)
|
||||||
|
e))]
|
||||||
|
[`(dw ,x ,e_1 ,e_2 ,e_3)
|
||||||
|
`(dw ,x
|
||||||
|
,(close top-vars loc-vars e_1)
|
||||||
|
,(close top-vars loc-vars e_2)
|
||||||
|
,(close top-vars loc-vars e_3))]
|
||||||
|
; substitution does not recur inside continuation values
|
||||||
|
; (not sure why it bothers to recur within dw expression)
|
||||||
|
[`(cont ,v ,E)
|
||||||
|
`(cont ,(close top-vars '() v)
|
||||||
|
,(close top-vars '() E))]
|
||||||
|
[`(cont ,E)
|
||||||
|
`(comp ,(close top-vars '() E))]
|
||||||
|
[(? list?)
|
||||||
|
(map (curry close top-vars loc-vars) expr)]
|
||||||
|
[_ expr]))
|
||||||
|
|
||||||
|
(define drop-duplicate-binders
|
||||||
|
(match-lambda
|
||||||
|
[`(λ ,xs ,e)
|
||||||
|
`(λ ,(remove-duplicates xs) ,(drop-duplicate-binders e))]
|
||||||
|
[(? list? es)
|
||||||
|
(map drop-duplicate-binders es)]
|
||||||
|
[e e]))
|
||||||
|
|
||||||
|
(define (consistent-dws p)
|
||||||
|
(define pre-post
|
||||||
|
(let ([h (make-hash)])
|
||||||
|
(λ (id pre post)
|
||||||
|
(match (hash-ref h id #f)
|
||||||
|
[#f
|
||||||
|
(hash-set! h id (list pre post))
|
||||||
|
(list pre post)]
|
||||||
|
[x x]))))
|
||||||
|
(let recur ([x p] [excluded '()])
|
||||||
|
(match x
|
||||||
|
[`(dw ,x ,e1 ,e2 ,e3)
|
||||||
|
(if (member x excluded)
|
||||||
|
(recur e2 excluded)
|
||||||
|
(match-let ([(list e1’ e3’) (pre-post x e1 e3)])
|
||||||
|
`(dw ,x
|
||||||
|
,(recur e1’ (cons x excluded))
|
||||||
|
,(recur e2 excluded)
|
||||||
|
,(recur e3’ (cons x excluded)))))]
|
||||||
|
[(? list?) (map (curryr recur excluded) x)]
|
||||||
|
[_ x])))
|
||||||
|
|
||||||
|
(define (proper-wcms e)
|
||||||
|
(let fix ([ok? #t] [e e])
|
||||||
|
(match e
|
||||||
|
[`(wcm ,w ,e)
|
||||||
|
(if ok?
|
||||||
|
`(wcm ,(remove-duplicates (fix #t w) #:key first)
|
||||||
|
,(fix #f e))
|
||||||
|
(fix #f e))]
|
||||||
|
[`(list . ,vs)
|
||||||
|
`(list . ,(map (curry fix #t) vs))]
|
||||||
|
[`(λ ,xs ,e)
|
||||||
|
; #f in case applied with a continuation that's already marked
|
||||||
|
`(λ ,xs ,(fix #f e))]
|
||||||
|
[`(cont ,v ,E)
|
||||||
|
`(cont ,(fix #t v) ,(fix #t E))]
|
||||||
|
[`(comp ,E)
|
||||||
|
`(comp ,(fix #t E))]
|
||||||
|
[`(begin ,e1 ,e2)
|
||||||
|
`(begin ,(fix #t e1)
|
||||||
|
,(fix ok? e2))]
|
||||||
|
[`(% ,e1 ,e2 ,e3)
|
||||||
|
`(% ,(fix #t e1) ,(fix ok? e2) ,(fix #t e3))]
|
||||||
|
[`(dw ,x ,e1 ,e2 ,e3)
|
||||||
|
`(dw ,x ,(fix #t e1) ,(fix ok? e2) ,(fix #t e3))]
|
||||||
|
[`(if ,e1 ,e2 ,e3)
|
||||||
|
`(if ,(fix #t e1)
|
||||||
|
,(fix ok? e2)
|
||||||
|
,(fix ok? e3))]
|
||||||
|
[`(set! ,x ,e)
|
||||||
|
`(set! ,x ,(fix #t e))]
|
||||||
|
[(? list?)
|
||||||
|
(map (curry fix #t) e)]
|
||||||
|
[_ e])))
|
||||||
|
|
||||||
|
(define transform-intermediate
|
||||||
|
(match-lambda
|
||||||
|
[(and p `(<> ,s ,o ,e))
|
||||||
|
(define fresh (make-fresh p))
|
||||||
|
(define allocated (map first s))
|
||||||
|
(define (alloc-cell prefix)
|
||||||
|
(define cell (fresh prefix))
|
||||||
|
(set! allocated (cons cell allocated))
|
||||||
|
cell)
|
||||||
|
(define no-dw? (alloc-cell "handlers-disabled?"))
|
||||||
|
(define dw-frame-locs
|
||||||
|
(let ([locs (make-hash)])
|
||||||
|
(λ (x)
|
||||||
|
(hash-ref
|
||||||
|
locs x
|
||||||
|
(λ () (let ([ys (list (alloc-cell (format "~s-allocated?" x))
|
||||||
|
(alloc-cell (format "~s-skip-pre?" x))
|
||||||
|
(alloc-cell (format "~s-comp-cont" x)))])
|
||||||
|
(hash-set! locs x ys)
|
||||||
|
ys))))))
|
||||||
|
(define transform
|
||||||
|
(match-lambda
|
||||||
|
[`(wcm () ,m)
|
||||||
|
(transform m)]
|
||||||
|
[`(wcm ([,k ,v] . ,w) ,m)
|
||||||
|
`(call/cm ,(transform k) ,(transform v)
|
||||||
|
(λ () ,(transform `(wcm ,w ,m))))]
|
||||||
|
[(and e `(dw ,x ,e1 ,e2 ,e3))
|
||||||
|
(match-let ([(list a? s? c) (dw-frame-locs x)]
|
||||||
|
[t (fresh "t")])
|
||||||
|
`((λ (,t)
|
||||||
|
(if ,a?
|
||||||
|
(begin (if ,no-dw? #f (set! ,s? #t)) (,c ,t))
|
||||||
|
(% 1
|
||||||
|
(dynamic-wind
|
||||||
|
(λ ()
|
||||||
|
(if ,no-dw?
|
||||||
|
#f
|
||||||
|
(if ,a?
|
||||||
|
(if ,s? (set! ,s? #f) ,(transform e1))
|
||||||
|
#f)))
|
||||||
|
(λ ()
|
||||||
|
((call/comp
|
||||||
|
(λ (k)
|
||||||
|
(begin
|
||||||
|
(set! ,c k)
|
||||||
|
(abort 1 k)))
|
||||||
|
1)))
|
||||||
|
(λ ()
|
||||||
|
(if ,no-dw?
|
||||||
|
(set! ,a? #t)
|
||||||
|
(if ,a?
|
||||||
|
,(transform e3)
|
||||||
|
(set! ,a? #t)))))
|
||||||
|
(λ (k) (begin (if ,no-dw? #f (set! ,s? #t)) (k ,t))))))
|
||||||
|
(λ () ,(transform e2))))]
|
||||||
|
[`(cont ,v ,E)
|
||||||
|
(let ([x (fresh "v")])
|
||||||
|
`(begin
|
||||||
|
(set! ,no-dw? #t)
|
||||||
|
((λ (,x)
|
||||||
|
(% ,x
|
||||||
|
,(transform
|
||||||
|
(term (plug ,E (call/cc (λ (k) (abort ,x k)) ,x))))
|
||||||
|
(λ (x) (begin (set! ,no-dw? #f) x))))
|
||||||
|
,(transform v))))]
|
||||||
|
[`(comp ,E)
|
||||||
|
(define numbers
|
||||||
|
(match-lambda
|
||||||
|
[(? integer? n) (list n)]
|
||||||
|
[(? list? l) (append-map numbers l)]
|
||||||
|
[_ (list)]))
|
||||||
|
(define t (add1 (apply max 0 (numbers E))))
|
||||||
|
`(begin
|
||||||
|
(set! ,no-dw? #t)
|
||||||
|
(% ,t
|
||||||
|
,(transform
|
||||||
|
(term (plug ,E (call/comp (λ (k) (abort ,t k)) ,t))))
|
||||||
|
(λ (x) (begin (set! ,no-dw? #f) x))))]
|
||||||
|
[`(list ,vs ...)
|
||||||
|
`(list ,@(map transform-value vs))]
|
||||||
|
[(? list? xs)
|
||||||
|
(map transform xs)]
|
||||||
|
[e e]))
|
||||||
|
(define transform-value
|
||||||
|
(match-lambda
|
||||||
|
[(and e (or `(cont ,_ ,_) `(comp ,_)))
|
||||||
|
`(λ (x) (,(transform e) x))]
|
||||||
|
[e (transform e)]))
|
||||||
|
(define e’ (transform e))
|
||||||
|
(define s’ (map (match-lambda [(list x v) (list x (transform-value v))]) s))
|
||||||
|
`(<> ,(map (λ (x) (match (assoc x s’)
|
||||||
|
[#f (list x #f)]
|
||||||
|
[(list _ v’) (list x v’)]))
|
||||||
|
allocated)
|
||||||
|
,o
|
||||||
|
,e’)]))
|
||||||
|
|
||||||
|
;; The built-in `plug' sometimes chooses the wrong hole.
|
||||||
|
(define-metafunction grammar
|
||||||
|
[(plug hole any) any]
|
||||||
|
[(plug (in-hole W (dw x e_1 E e_2)) any)
|
||||||
|
(in-hole W (dw x e_1 (plug E any) e_2))]
|
||||||
|
[(plug (wcm w M) any)
|
||||||
|
(wcm w (plug M any))]
|
||||||
|
[(plug (v ... W e ...) any)
|
||||||
|
(v ... (plug W any) e ...)]
|
||||||
|
[(plug (begin W e) any)
|
||||||
|
(begin (plug W any) e)]
|
||||||
|
[(plug (% W e_1 e_2) any)
|
||||||
|
(% (plug W any) e_1 e_2)]
|
||||||
|
[(plug (% v e W) any)
|
||||||
|
(% v e (plug W any))]
|
||||||
|
[(plug (% v_1 W v_2) any)
|
||||||
|
(% v_1 (plug W any) v_2)]
|
||||||
|
[(plug (set! x W) any)
|
||||||
|
(set! x (plug W any))]
|
||||||
|
[(plug (if W e_1 e_2) any)
|
||||||
|
(if (plug W any) e_1 e_2)])
|
||||||
|
|
||||||
|
(define (make-fresh p)
|
||||||
|
(define suffix
|
||||||
|
(let recur ([x p] [s 0])
|
||||||
|
(cond [(symbol? x)
|
||||||
|
(match (regexp-match #rx"_(.+)$" (symbol->string x))
|
||||||
|
[(list _ n) (max s (add1 (string->number n)))]
|
||||||
|
[#f s])]
|
||||||
|
[(pair? x) (recur (cdr x) (recur (car x) s))]
|
||||||
|
[else s])))
|
||||||
|
(λ (prefix)
|
||||||
|
(begin0 (string->symbol (format "~a_~a" prefix suffix))
|
||||||
|
(set! suffix (add1 suffix)))))
|
||||||
|
|
||||||
|
(define (random-literal)
|
||||||
|
(random-member
|
||||||
|
'(dynamic-wind abort current-marks cons
|
||||||
|
-inf.0 +inf.0 -1 0 1 1/3 -1/4 .33 -.25 4-3i 3+4i
|
||||||
|
call/cc call/comp call/cm
|
||||||
|
#f #t zero? print + first rest)))
|
||||||
|
|
||||||
|
(define (random-member xs)
|
||||||
|
(parameterize ([current-pseudo-random-generator test-prg])
|
||||||
|
(list-ref xs (random (length xs)))))
|
||||||
|
|
||||||
|
(define test-prg (make-pseudo-random-generator))
|
Loading…
Reference in New Issue
Block a user