(define-structure conditionals
  (export (define-simple-syntax :syntax)
	  (when    :syntax)
	  (unless  :syntax)
	  (?       :syntax)
	  (switchq :syntax)
	  (switch  :syntax)
	  (prog0   :syntax)
	  (land*   :syntax))
  (open scheme)
  (begin

;;; (define-simple-syntax (name subforms ...) expansion)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define-syntax define-simple-syntax
  (syntax-rules ()
    ((define-simple-syntax (name subforms ...) expansion)
     (define-syntax name (syntax-rules () ((name subforms ...) expansion))))))


;;; ? = COND
;;; (WHEN test body ...)		(SWITCHQ = key clause ...)
;;; (UNLESS test body ...)		(SWITCH  = key clause ...)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Handy conditional forms. ? is so short that it renders WHEN pretty
;;; much useless.

(define-simple-syntax (when test body ...)
  (if test (begin body ...)))

(define-simple-syntax (unless test body ...)
  (if (not test) (begin body ...)))

;;; ? is synonym for COND.
(define-simple-syntax (? clause ...) (cond clause ...))


;;; (PROG0 val-exp exp ...)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define-simple-syntax (prog0 val-exp exp ...)
  (let ((v val-exp)) exp ... v))


;;; (land* (clause ...) body ...)				-*- Scheme -*-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Evaluate each clause. If any clause returns false, land* stops and
;;; returns false. If all the clauses evaluate to a true value, return
;;; the value of the body.
;;;
;;; The difference between LAND* and AND is that LAND* binds names to
;;; the values of its clauses, which may be used by subsequent clauses.
;;; Clauses are of the form
;;;     (var exp)	; binds VAR to the value of EXP.
;;;     (exp)		; No binding.
;;;     var		; Reference -- no binding. 
;;;
;;; Example:
;;; (land* ((probe (assq key alist)))
;;;   (cdr probe))
;;;
;;; LAND* is due to Oleg Kiselyov (http://pobox.com/~oleg); I wrote this
;;; simple implementation as a high-level R5RS DEFINE-SYNTAX macro.
;;;     Olin 98/9/29

(define-syntax land*
  (syntax-rules ()
    ((land* () body ...) (begin body ...))

    ((land* ((var exp) clause ...) body ...)
     (let ((var exp)) (and var (land* (clause ...) body ...))))

    ((land* ((#f exp) clause ...) body ...)
     (and exp (land* (clause ...) body ...)))

    ((land* ((exp) clause ...) body ...)
     (and exp (land* (clause ...) body ...)))

    ((land* (var clause ...) body ...)
     (and var (land* (clause ...) body ...)))))



;;; Like CASE, but you specify the key-comparison procedure.
;;; SWITCH evaluates its keys each time through the conditional.
;;; SWITCHQ keys are not evaluated -- are simply constants.
;;; (switchq string=? (vector-ref vec i)
;;;   (("plus" "minus") ...)
;;;   (("times" "div")  ...)
;;;   (else ...))

(define-simple-syntax (switchq compare key clause ...)
  (let ((k key)				; Eval KEY and COMPARE
	(c compare))			; just once, then call %switch.
    (%switchq c k clause ...)))		; C, K are vars, hence replicable.

(define-syntax %switchq
  (syntax-rules (else)
    ((%switchq compare key ((key1 ...) body1 body2 ...) rest ...)
     (if (or (compare key 'key1) ...)
	 (begin body1 body2 ...)
	 (%switchq compare key rest ...)))

    ((%switchq compare key ((key1 ...)) rest ...)	; Null body.
     (if (not (or (compare key 'key1) ...))
	 (%switchq compare key rest ...)))
    
    ((%switchq compare key (else body ...))
     (begin body ...))

    ((%switchq compare key) '#f)))


(define-simple-syntax (switch compare key clause ...)
  (let ((k key)				; Eval KEY and COMPARE
	(c compare))			; just once, then call %switch.
    (%switch c k clause ...)))		; C, K are vars, hence replicable.

(define-syntax %switch
  (syntax-rules (else)
    ((%switch compare key ((key1 ...) body1 body2 ...) rest ...)
     (if (or (compare key key1) ...)
	 (begin body1 body2 ...)
	 (%switch compare key rest ...)))

    ((%switch compare key ((key1 ...)) rest ...)	; Null body.
     (if (not (or (compare key key1) ...))
	 (%switch compare key rest ...)))
    
    ((%switch compare key (else body ...))
     (begin body ...))

    ((%switch compare key) '#f)))

;;; I can't get this to work -- S48 complains "too many ...'s".
;(define-syntax switchq
;  (syntax-rules (else)
;    ((switchq compare key clause ...)
;     (letrec-syntax ((%switchq (syntax-rules (else)
;			         ((%switchq compare key
;					   ((key1 ...) body1 body2 ...) rest ...)
;				  (if (or (compare key 'key1) ...)
;				      (begin body1 body2 ...)
;				      (%switchq compare key rest ...)))
;
;				 ; Null body.
;				 ((%switchq compare key ((key1 ...)) rest ...)
;				  (if (not (or (compare key 'key1) ...))
;				      (%switchq compare key rest ...)))
;    
;			         ((%switchq compare key (else body ...))
;				  (begin body ...))
;
;				 ((%switchq compare key) '#f))))
;
;        (let ((k key)			 ; Eval KEY and COMPARE
;	      (c compare))		 ; just once, then call %switch.
;	   (%switchq c k clause ...)))))); C, K are vars, hence replicable.
))
