#lang scheme/base
(provide
 let-ns-tx           define-ns-tx
 redefine!-ns-tx
 definitions-ns-tx
 parameterize-words-ns-tx
 parameterize/super-words-ns-tx
 ns-prefixed
 make-ns-ref    make-ns-bind
 name->identifier
)
(require
 (lib "pretty.ss")
 scheme/stxparam
 syntax/modcode
 syntax/modresolve
 scheme/pretty
 mzlib/pregexp
 "../tools-tx.ss"
 (for-template
  "../tools.ss"
  "rep.ss"   scheme/base
  )
 )
(define (make-ns-ref ns)
  (lambda (stx)
    (syntax-case stx ()
      ((_ id)
       (ns-prefixed ns #'id)))))
(define (make-ns-bind let ns)
  (lambda (stx)
    (syntax-case stx ()
      ((_ ((name/names expr) ...) body ...)
       #`(#,let
             #,(map
                (lambda (n/ns e)
                  #`(#,(syntax-case n/ns ()
                         ((name ...)
                          (map (lambda (n) (ns-prefixed ns n))
                               (syntax->list #'(name ...))))
                         (name
                          (ns-prefixed ns #'name)))
                     #,e))
                (syntax->list #'(name/names ...))
                (syntax->list #'(expr ...)))
           body ...)))))
(define ns-separator "/")
(define (ns->prefix-string ns-lst)
  (apply string-append
         (map (lambda (x) (format "~a~a" x ns-separator))
              ns-lst)))
(define (ns->prefix ns-stx)
  (->syntax ns-stx
            (string->symbol
             (ns->prefix-string
              (->datum ns-stx)))))
(define (name->identifier stx)
  (let ((name (syntax->datum stx)))
    (cond
     ((symbol? name) stx)  
     ((string? name) (datum->syntax stx (string->symbol name)))
     (else #f))))
(define (ns-prefixed ns name)  (prefix (ns->prefix ns)
          (name->identifier name)))
(define (let-ns-tx stx)
  (syntax-case stx ()
    ((let ns . args)
     #`(let-syntax
           ((let/ns (make-ns-bind #'let #'ns)))
         (let/ns . args)))))
(define (define-ns-tx stx)
  (syntax-case stx ()
            ((define ns name val)
     (let ((mapped (ns-prefixed #'ns #'name)))
       #`(define #,mapped val)))))
(define (redefine!-ns-tx stx)      
  (syntax-case stx ()
                                ((define ns name val)
     (let ((id (ns-prefixed #'ns #'name)))
       (if (identifier-binding id)
           (let ((super
                  (ns-prefixed
                   #'ns (datum->syntax #'name 'super))))
             #`(letrec ((#,super val))
                 (log:                        "~a ~a\n" 'ns 'name)
                 (word-swap! #,super #,id)))
           #`(define #,id val))))))
(define (definitions-ns-tx stx)
  (syntax-case stx ()
    ((define-ns ns (name val) ...)
     #`(begin (define-ns ns name val) ...))))
(define (suffix-temp stx-lst suffix)
  (generate-temporaries
   (map (lambda (id)
          (format "~a~a" id suffix))
        (syntax->datum stx-lst))))
(define (parameterize-words-ns-tx stx)
  (syntax-case stx ()
    ((word->param ns ((name expr) ...) body ...)
     #`(let-syntax
           ((id  (make-ns-ref #'ns)))
         (parameterize
             (((word->param (id name)) expr) ...)
           body ...)))))
(define (parameterize/super-words-ns-tx stx)
  (syntax-case stx ()
    ((_ _ () body ...) #`(let () body ...))     ((word->param ns ((name expr) ...) body ...)
     (syntax-case
         (list
          (ns-prefixed #'ns
                       (datum->syntax
                        (stx-car #'(name ...))
                        'super))
          (suffix-temp #'(name ...) "-param-")             (suffix-temp #'(name ...) "-value-"))           ()
       ((super (pname ...) (pvalue ...))
        #`(let-syntax
              ((_ns (make-ns-ref #'ns)))
            (let ((pname (word->param (_ns name))) ...)
              (let ((pvalue (pname)) ...)
                (parameterize
                    ((pname (let ((super pvalue)) expr)) ...)
                  body ...)))))))))