#lang scheme

(require scheme/private/for)

(require (for-syntax scheme/match/parse
                     scheme/match/patterns))

(define-raw-sequence-syntax :match
  (lambda (stx) (raise-syntax-error #f "cannot be used in expression position" stx))
  (lambda (stx)
    (syntax-case stx ()
      [(pat (_ seq-expr))
       #'[(pat) (:match* seq-expr)]])))  

(define-raw-sequence-syntax :match*
  (lambda (stx) (raise-syntax-error #f "cannot be used in expression position" stx))
  (lambda (stx)
    (syntax-case stx ()
      [((pat ...) (_ seq-expr))
       (let ([ps 
              (for/list ([pat1 (syntax->list #'(pat ...))])
                        (parse/cert pat1 (syntax-local-certifier)))])
         (with-syntax ([((vars ...) ...) (map bound-vars ps)])
           #'[(vars ... ...)
              (:do-in ([(more? get) (sequence-generate seq-expr)])
                      (void)
                      ()
                      (more?)
                      ([(vars ... ...) 
                        (call-with-values get 
                                          (match-lambda**
                                           [(pat ...) (values vars ... ...)]))])
                      #t
                      #t
                      ())]))])))

(for/and ([((app add1 x) (app sub1 y))
            (:match* (in-parallel (list 1 2 3) (list 4 5 6)))])
          (< x 3))

(for/and ([((app add1 x) (app sub1 y))
            (:match* (in-parallel (list 1 2 3) (list 4 5 6)))])
          (< x 30))

(for/or ([((app add1 x) (app sub1 y))
          (:match* (in-parallel (list 1 2 3) (list 4 5 6)))])
        (< x -30))

(for/or ([((app add1 x) (app sub1 y))
          (:match* (in-parallel (list 1 2 3) (list 4 5 6)))])
        (< x 30))

(for/first ([((app add1 x) (app sub1 y))
             (:match* (in-parallel (list 1 2 3) (list 4 5 6)))]
            #:when (> x y))
        (list x y))

(for/last ([((app add1 x) (app sub1 y))
            (:match* (in-parallel (list 1 2 3) (list 4 5 6)))])
          (+ x y))

(for/list ([q (in-naturals)]
           [(list x y z)
            (:match (list (list 1 2 3) (list 4 5 6)))])
          (list x q))