(module eval mzscheme
  (require (lib "contract.ss")
           (lib "etc.ss")
           (lib "mred.ss" "mred")

  ;; TODO: remove the mred dependency and move all that stuff into tool.ss

  (define (require-spec module-name . path)
    `(file ,(path->string (apply build-path (this-expression-source-directory) (append path (list module-name))))))

  ;; make-javascript-namespace : -> javascript-namespace
  (define (make-javascript-namespace)
    (let ([ns (make-namespace-with-mred)]
          [runtime (require-spec "runtime.ss" "runtime")]
          [debug (require-spec "debug.ss")])
      (parameterize ([current-namespace ns])
        (dynamic-require runtime #f)
        (dynamic-require debug #f)
        (let ([path1 ((current-module-name-resolver) runtime #f #f)]
              [path2 ((current-module-name-resolver) debug #f #f)])
          (namespace-attach-module ns path1)
          (namespace-require path1)
          (namespace-attach-module ns path2))
        (eval '(initialize-runtime!)))

  ;; reset-javascript-namespace! : javascript-namespace -> any
  (define (reset-javascript-namespace! ns)
    (parameterize ([current-namespace ns])
      (eval '(initialize-runtime!))))

  ;; eval-compiled-javascript : syntax * [javascript-namespace] -> any
  (define eval-compiled-javascript
    (opt-lambda (stx [ns (make-javascript-namespace)])
      (parameterize ([current-namespace ns])
        (eval stx))))

  ;; eval-javascript-string : input-source * [javascript-namespace] -> any
  (define eval-javascript-string
    (opt-lambda (src [ns (make-javascript-namespace)])
      (eval-compiled-javascript (compile-script (parse-script src)) ns)))

  ;; TODO: get this to work with all of the missing source location information

  ;; eval-javascript : sexp * [javascript-namespace] -> any
  (define eval-javascript
    (opt-lambda (src [ns (make-javascript-namespace)])
      (eval-compiled-javascript (compile-script (list (sexp->SourceElement src))) ns)))

  (provide/contract [make-javascript-namespace (-> namespace?)]
                    [reset-javascript-namespace! (namespace? . -> . any)]
                    [eval-compiled-javascript ((syntax?) (namespace?) . opt-> . any)]
                    [eval-javascript-string ((input-source?) (namespace?) . opt-> . any)])
  (provide eval-javascript))