;; Examples from some papers, and from Oleg Kiselyov's:
;;  Generic implementation of all four delimited control operators
;;     shift/reset, prompt/control, shift0/reset0 and prompt0/control0
;;                    aka. -F- through +F+   
;;  $Id: delim-control-n.scm 815 2005-09-05 23:02:12Z oleg $

(load-relative "loadtest.ss")

(Section 'control)

(require mzlib/control
         (only-in mzlib/etc rec))

;-----------------------------------------------------------------------

(define-syntax ctest
  (syntax-rules ()
    [(_ expr expect)
     (test expect 'expr expr)]))

;-----------------------------------------------------------------------
;			Shift tests

(ctest (+ 10 (reset (+ 2 (shift k (+ 100 (k (k 3)))))))
      117)

(ctest (* 10 (reset (* 2 (shift g (reset 
				   (* 5 (shift f (+ (f 1) 1))))))))
      60)

(ctest (let ((f (lambda (x) (shift k (k (k x))))))
	   (+ 1 (reset (+ 10 (f 100)))))
      121)

(ctest (reset
       (let ((x (shift f (cons 'a (f '())))))
         (shift g x)))
      '(a))

(define (shift* p) (shift f (p f)))
(ctest (reset (let ((x 'abcde)) (eq? x ((shift* shift*) x))))
      #t)

(define traverse
  (lambda (xs)
    (letrec ((visit
	       (lambda (xs)
		 (if (null? xs)
		   '()
		   (visit (shift k
                                 (cons (car xs)
                                       (k (cdr xs)))))))))
      (reset
       (visit xs)))))

(ctest (traverse '(1 2 3 4 5))
      '(1 2 3 4 5))

;-----------------------------------------------------------------------
;			Control tests
; Example from Sitaram, Felleisen

(define (abort v) (control k v))

(ctest (let ((g (prompt (* 2 (control k k)))))
        (* 3 (prompt (* 5 (abort (g 7))))))
      42)

; Olivier Danvy's puzzle

(define traverse
  (lambda (xs)
    (letrec ((visit
	       (lambda (xs)
		 (if (null? xs)
		   '()
		   (visit (control k
                                   (cons (car xs) 
                                         (k (cdr xs)))))))))
      (prompt
       (visit xs)))))

(ctest (traverse '(1 2 3 4 5))
      '(5 4 3 2 1))

(ctest (+ 10 (prompt (+ 2 (control k (+ 100 (k (k 3)))))))
      117)

(ctest (prompt (let ((x (control f (cons 'a (f '()))))) (control g x)))
      '())

(ctest (prompt ((lambda (x) (control l 2))
               (control l (+ 1 (l 0)))))
      2)
(ctest (prompt (control f (cons 'a (f '()))))
      '(a))
(ctest (prompt (let ((x (control f (cons 'a (f '()))))) 
                (control g (g x))))
      '(a))

(define (control* f) (control k (f k)))
(ctest (prompt (let ((x 'abcde)) (eq? x ((control* control*) x))))
      #t)

;------------------------------------------------------------------------
;			shift0/control0 tests

(ctest (+ 10 (prompt0 (+ 2 (control k (+ 100 (k (k 3)))))))
      117)

(ctest (prompt0 (prompt0 
                (let ((x (control f (cons 'a (f '()))))) 
                  (control g x))))
      '())

(ctest (+ 10 (prompt0 (+ 2 (shift0 k (+ 100 (k (k 3)))))))
      117)

(ctest (prompt0 (cons 'a (prompt0 (shift0 f (shift0 g '())))))
      '())

(ctest (prompt (cons 'a (prompt (shift0 f (shift0 g '())))))
      '(a))


;; ----------------------------------------
;; Examples from Dorai Sitaram's dissertation

(define make-fringe
  (lambda (tree)
    (lambda (any)
      (let loop ([tree tree])
        (cond
         [(pair? tree) 
          (loop (car tree))
          (loop (cdr tree))]
         [(null? tree) '*]
         [else (fcontrol tree)]))
      (fcontrol '()))))

(define same-fringe?
  (lambda (tree1 tree2)
    (let loop ([fringe1 (make-fringe tree1)]
               [fringe2 (make-fringe tree2)])
      (% (fringe1 '*)
         (lambda (leaf1 rest-of-fringe1)
           (% (fringe2 '*)
              (lambda (leaf2 rest-of-fringe2)
                (cond
                 [(and (null? leaf1) (null? leaf2)) #t]
                 [(or (null? leaf1) (null? leaf2)) #f]
                 [(eqv? leaf1 leaf2) (loop rest-of-fringe1
                                           rest-of-fringe2)]
                 [else #f]))))))))

(ctest (same-fringe? '(1 . (2 . (3 . 4)))
                    '(1 . ((2 . 3) . 4)))
      #t)
(ctest (same-fringe? '(1 . (2 . (3 . 4)))
                    '(1 . ((2 . 5) . 4)))
      #f)

(define all-prefixes
  (lambda (l)
    (letrec ([loop (lambda (l)
                     (if (null? l)
                         (fcontrol 'done)
                         (cons (car l)
                               (fcontrol (cdr l)))))])
      (% (loop l)
         (rec h
              (lambda (r k)
                (if (eq? r 'done)
                    '()
                    (cons (k '())
                          (% (k (loop r)) h)))))))))

(ctest (all-prefixes '(1 2 3 4))
      '((1) (1 2) (1 2 3) (1 2 3 4)))

;; ------------------------------------------------------------
;; spawn
;;  example from Queinnec & Serpete, POPL'91

(ctest (spawn (lambda (f) 
               (let ([v (f (lambda (c2) 
                             (cons 2 (c2 3))))])
                 (cons (f (lambda (cl) 
                            (cons 1 (cl 4)))) 
                       v))))
      '(2 1 4 . 3))

(ctest (spawn (lambda (f) 
               (cons (f (lambda (cl) 
                          (cons 1 (cl 4)))) 
                     (f (lambda (c2) 
                          (cons 2 (c2 3)))))))
      '(1 2 4 . 3))

;; ------------------------------------------------------------
;; splitter
;;  example from Queinnec & Serpete, POPL'91

(define (visit tree fn) 
  (if (pair? tree) 
      (begin (visit (car tree) fn) 
             (visit (cdr tree) fn)) 
      (fn tree)))

(define (make-tree-walker visit) 
  (lambda (tree) 
    (splitter 
     (lambda (exit grab) 
       (visit 
        tree 
        (lambda (leaf) 
          (grab 
           (lambda (c) 
             (exit (lambda () 
                     (cons 
                      leaf 
                      (lambda (v) 
                        (splitter 
                         (lambda (k j ) 
                           (set! grab j) 
                           (set! exit k) 
                           (c v)))))))))))))))

(define (compare-fringes walk trees) 
  (let ((end (list 'end)))
    (define (end? leaf) (eq? leaf end)) 
    (define (loop leafs) 
      (define (same-leaf? leaf) 
        (eq? (car leaf) (caar leafs)))
      (or ; all trees are finished ? 
       (andmap end? leafs) 
       ;; some trees are jinished ? 
       (if (ormap end? leafs)
           #f
           (and (andmap same-leaf? 
                        (cdr leafs)) 
                ;; all leaves are equal ! 
                (loop (map
                       (lambda (leaf) 
                         ((cdr leaf) end) ) 
                       leafs )) ) ) ) ) 
    (loop (map walk trees)) ) )

(define (same-fringe trees) 
  (compare-fringes (make-tree-walker visit) 
                   trees))

(ctest (same-fringe (list '(1 . (2 . (3 . 4)))
                         '(1 . ((2 . 3) . 4))))
      #t)
(ctest (same-fringe (list '(1 . (2 . (3 . 4)))
                         '(1 . ((2 . 5) . 4))))
      #f)

;; ----------------------------------------
;; cupto

(ctest (let ([p (new-prompt)])
         (set p
              (+ 1
                 (cupto p k (+ 3 (k 2) (k 5))))))
       12)

;; ----------------------------------------

(report-errs)
