#lang racket/base

(require "private/command.rkt"
         "parameters.rkt"
         "whalesong-helpers.rkt"
         profile profile/render-text
         racket/path
         (for-syntax racket/base))

;; Command line for running Whalesong.


;; TODO: we may want to adopt this as a raco command, as described in:
;;
;;     http://docs.racket-lang.org/raco/command.html


;; Usage:
;;
;; * Build standalone .xhtml application.
;;
;;     $ whalesong build main-module-name.rkt
;;
;;
;; * Print out the runtime library to standard output.
;;
;;     $ whalesong get-runtime
;;
;;
;; * Print out the JavaScript for the program.
;;
;;     $ whalesong get-javascript main-module-name.rkt

(define as-standalone-html? (make-parameter #f))
(define with-profiling? (make-parameter #f))

(define-syntax (maybe-with-profiling stx)
  (syntax-case stx ()
    [(_ expr)
     (syntax/loc stx
       (if (with-profiling?)
           (profile expr
                    #:threads #t
                    #:delay 0.0001
                    #:render (lambda (profile)
                               (render profile
                                       #:truncate-source 500)))

           expr))]))


(define (set-root-path! root-path)
  (unless (directory-exists? root-path)
    (fprintf (current-report-port) "ERROR: root path ~a does not appear to exist.\n" root-path)
    (fprintf (current-report-port) "Aborting compilation.\n")
    (exit))
  (current-root-path (normalize-path root-path)))



(define (at-toplevel)
  (svn-style-command-line
   #:program "whalesong"
   #:argv (current-command-line-arguments)
   "The Whalesong command-line tool for compiling Racket to JavaScript"
   #;["version" "Print the current version"
    "Print the current version"
    #:args ()
    (print-version)]
   ["build" "build a standalone html and javascript package" 
            "Builds a Racket program and its required dependencies into a .html and .js file."
            #:once-each
            [("-v" "--verbose")
             ("Display verbose messages.")
             (current-verbose? #t)]
            [("--debug-show-timings")
             ("Display debug messages about compilation time.")
             (current-timing-port (current-output-port))]
            [("--enable-profiling")
             ("Enable profiling to standard output")
             (with-profiling? #t)]
            [("--without-ie")
             ("Disable IE legacy support")
             (current-with-legacy-ie-support? #f)]
            [("--with-cache")
             ("Turn on the internal compilation cache")
             (current-with-cache? #t)]
            [("--without-cache")
             ("Turn off the internal compilation cache")
             (current-with-cache? #f)]
            [("--compress-javascript")
             ("Compress JavaScript with Google Closure (requires Java)")
             (current-compress-javascript? #t)]
            [("--split-modules")
             ("Write one file per module")
             (current-one-module-per-file? #t)]
            [("--root-dir")
             root-path
             ("Set the root package path (default: current-directory)")
             (set-root-path! root-path)]
            [("--dest-dir")
             dest-dir
             ("Set destination directory (default: current-directory)")
             (current-output-dir dest-dir)]
            [("--as-standalone-xhtml")
             ("Write single standalone xhtml file")
             (as-standalone-html? #t)]
            #:multi
            [("--include-script")
             script-path
             ("Include a Javascript file in the header.")
             (current-header-scripts (cons (string->path script-path) (current-header-scripts)))]

            #:args (path)

            (maybe-with-profiling
             (if (as-standalone-html?)
                 (build-standalone-xhtml path)
                 (build-html-and-javascript path)))]

   ["print-il" "print the intermediate translation of a module"
               "Prints the intermediate translation of a module; used for debugging purposes."
               #:once-each
               [("-v" "--verbose")
                   ("Display verbose messages.")
                   (current-verbose? #t)]
                  [("--debug-show-timings")
                   ("Display debug messages about compilation time.")
                   (current-timing-port (current-output-port))]
                  [("--enable-profiling")
                   ("Enable profiling to standard output")
                   (with-profiling? #t)]
                  [("--root-dir")
                   root-path
                   ("Set the root package path (default: current-directory)")
                   (set-root-path! root-path)]
                  #:args (path)
                  (maybe-with-profiling
                   (print-il path))]

   ["print-bytecode" "print the bytecode of a module"
               "Prints the bytecode of a module; used for debugging purposes."
               #:once-each
               [("-v" "--verbose")
                   ("Display verbose messages.")
                   (current-verbose? #t)]
                  [("--debug-show-timings")
                   ("Display debug messages about compilation time.")
                   (current-timing-port (current-output-port))]
                  [("--enable-profiling")
                   ("Enable profiling to standard output")
                   (with-profiling? #t)]
                  [("--root-dir")
                   root-path
                   ("Set the root package path (default: current-directory)")
                   (set-root-path! root-path)]
                  #:args (path)
                  (maybe-with-profiling
                   (print-bytecode path))]


   
   ["get-runtime" "print the runtime library to standard output"
                  "Prints the runtime JavaScript library that's used by Whalesong programs."
                  #:once-each
                  [("-v" "--verbose")
                   ("Display verbose messages.")
                   (current-verbose? #t)]
                  [("--debug-show-timings")
                   ("Display debug messages about compilation time.")
                   (current-timing-port (current-output-port))]
                  [("--enable-profiling")
                   ("Enable profiling to standard output")
                   (with-profiling? #t)]
                  [("--without-ie")
                   ("Disable IE legacy support")
                   (current-with-legacy-ie-support? #f)]
                  [("--with-cache")
                   ("Turn on the internal compilation cache")
                   (current-with-cache? #t)]
                  [("--without-cache")
                   ("Turn off the internal compilation cache")
                   (current-with-cache? #f)]
                  [("--root-dir")
                   root-path
                   ("Set the root package path (default: current-directory)")
                   (set-root-path! root-path)]
                  [("--compress-javascript")
                   ("Compress JavaScript with Google Closure (requires Java)")
                   (current-compress-javascript? #t)]
                  
                  #:args ()
                  (maybe-with-profiling
                   (print-the-runtime))]
   ["get-javascript" "Gets just the JavaScript code and prints it to standard output"
                     "Builds a racket program into JavaScript.  The outputted file depends on the runtime."
                     #:once-each
                     [("-v" "--verbose")
                      ("Display verbose messages.")
                      (current-verbose? #t)]
                     [("--debug-show-timings")
                      ("Display debug messages about compilation time.")
                      (current-timing-port (current-output-port))]
                     [("--enable-profiling")
                      ("Enable profiling to standard output")
                      (with-profiling? #t)]
                     [("--without-ie")
                      ("Disable IE legacy support")
                      (current-with-legacy-ie-support? #f)]
                     [("--with-cache")
                      ("Turn on the internal compilation cache")
                      (current-with-cache? #t)]
                     [("--without-cache")
                      ("Turn off the internal compilation cache")
                      (current-with-cache? #f)]
                     [("--root-dir")
                      root-path
                      ("Set the root package path (default: current-directory)")
                      (set-root-path! root-path)]
                     
                     [("--compress-javascript")
                      ("Compress JavaScript with Google Closure (requires Java)")
                      (current-compress-javascript? #t)]
                     
                     
                     #:args (file)
                     (maybe-with-profiling
                      (get-javascript-code file))]))


(at-toplevel)
