-port

               read
               read-char
               peek-char
               eof-object?
               char-ready?

               write
               display
               newline
               write-char

               ;;transcript-on
               ;;transcript-off
               )

  #:export (null-environment
            syntax-rules cond case))

;;; These definitions of `cond', `case', and `syntax-rules' differ from
;;; the ones in Guile in that they expect their auxiliary syntax (`_',
;;; `...', `else', and `=>') to be unbound.  They also don't support
;;; some extensions from Guile (e.g. `=>' in `case'.).

(define-syntax syntax-rules
  (lambda (x)
    (define (replace-underscores pattern)
      (syntax-case pattern (_)
        (_ #'^_)
        ((x . y)
         (with-syntax ((x (replace-underscores #'x))
                       (y (replace-underscores #'y)))
           #'(x . y)))
        ((x . y)
         (with-syntax ((x (replace-underscores #'x))
                       (y (replace-underscores #'y)))
           #'(x . y)))
        (#(x ^...)
         (with-syntax (((x ^...) (map replace-underscores #'(x ^...))))
           #'#(x ^...)))
        (x #'x)))
    (syntax-case x ()
      ((^_ dots (k ^...) . clauses)
       (identifier? #'dots)
       #'(with-ellipsis dots (syntax-rules (k ^...) . clauses)))
      ((^_ (k ^...) ((keyword . pattern) template) ^...)
       (with-syntax (((pattern ^...) (replace-underscores #'(pattern ^...))))
         #`(lambda (x)
             (syntax-case x (k ^...)
               ((dummy . pattern) #'template)
               ^...)))))))

(define-syntax case
  (lambda (stx)
    (let lp ((stx stx))
      (syntax-case stx (else)
        (("case" x)
         #'(if #f #f))
        (("case" x ((y ^...) expr ^...) clause ^...)
         #`(if (memv x '(y ^...))
               (begin expr ^...)
               #,(lp #'("case" x clause ^...))))
        (("case" x (else expr ^...))
         #'(begin expr ^...))
        (("case" x clause . ^_)
         (syntax-violation 'case "bad 'case' clause" #'clause))
        ((^_ x clause clause* ^...)
         #`(let ((t x))
             #,(lp #'("case" t clause clause* ^...))))))))

(define-syntax cond
  (lambda (stx)
    (let lp ((stx stx))
      (syntax-case stx (else =>)
        (("cond")
         #'(if #f #f))
        (("cond" (else expr ^...))
         #'(begin expr ^...))
        (("cond" (test => expr) clause ^...)
         #`(let ((t test))
             (if t
                 (expr t)
                 #,(lp #'("cond" clause ^...)))))
        (("cond" (test) clause ^...)
         #`(or test #,(lp #'("cond" clause ^...))))
        (("cond" (test expr ^...) clause ^...)
         #`(if test
               (begin expr ^...)
               #,(lp #'("cond" clause ^...))))
        (("cond" clause . ^_)
         (syntax-violation 'cond "bad 'cond' clause" #'clause))
        ((^_ clause clause* ^...)
         (lp #'("cond" clause clause* ^...)))))))

(define (null-environment n)
  (unless (eqv? n 5)
    (scm-error 'misc-error 'null-environment
               "~A is not a valid version" (list n) '()))
  ;; Note that we need to create a *fresh* interface
  (let ((interface (make-module)))
    (set-module-kind! interface 'interface)
    (define bindings
      '(define quote lambda if set! cond case and or let let* letrec
	 begin do delay quasiquote unquote
         define-syntax let-syntax letrec-syntax syntax-rules))
    (module-use! interface
                 (resolve-interface '(ice-9 safe-r5rs) #:select bindings))
    interface))
