;;; -*-scheme-*-

;;; GNU Mes --- Maxwell Equations of Software
;;; Copyright © 2016,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
;;;
;;; This file is part of GNU Mes.
;;;
;;; GNU Mes is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Mes is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Mes.  If not, see <http://www.gnu.org/licenses/>.

;;; Commentary:

;;; Code:

(mes-use-module (mes scm))

(define-macro (make-fluid . default)
  ((lambda (fluid)
     `(begin
        (module-define!
         (initial-module)
        ',fluid
        ((lambda (v)
           (lambda ( . rest)
             (if (null? rest) v
                 (set! v (car rest)))))
         ,(and (pair? default) (car default))))
        ',fluid))
   (symbol-append 'fluid: (gensym))))

(define (fluid-ref fluid)
  (fluid))

(define (fluid-set! fluid value)
  (fluid value))

(define-macro (fluid? fluid)
  `(begin
     (and (symbol? ,fluid)
          (symbol-prefix? 'fluid: ,fluid))))

(define (with-fluid* fluid value thunk)
  (let ((v (fluid)))
    (fluid-set! fluid value)
    (let ((r (thunk)))
      (fluid-set! fluid v)
      r)))

;; (define-macro (with-fluids*-macro fluids values thunk)
;;   `(begin
;;      ,@(map (lambda (f v) (list 'set! f v)) fluids values)
;;      (,thunk)))

;; (define (with-fluids*-next fluids values thunk)
;;   `(with-fluids*-macro ,fluids ,values ,thunk))

;; (define (with-fluids* fluids values thunk)
;;   (primitive-eval (with-fluids*-next fluids values thunk)))

(define-macro (with-fluids bindings . bodies)
  (let ((syms (map gensym bindings)))
    `(let ,(map (lambda (b s) `(,s (,b))) (map car bindings) syms)
       ,@(map (lambda (o) `(fluid-set! ,(car o) ,(cadr o))) bindings)
       (let ((r (begin ,@bodies)))
         ,@(map (lambda (b s) `(fluid-set! ,b ,s)) (map car bindings) syms)
         r))))

(define (dynamic-wind in-guard thunk out-guard)
  (in-guard)
  (let ((r (thunk)))
    (out-guard)
    r))
