001  (ns beowulf.core
002    "Essentially, the `-main` function and the bootstrap read-eval-print loop."
003    (:require [beowulf.bootstrap :refer [EVAL oblist *options*]]
004              [beowulf.read :refer [READ]]
005              [clojure.java.io :as io]
006              [clojure.pprint :refer [pprint]]
007              [clojure.tools.cli :refer [parse-opts]]
008              [environ.core :refer [env]])
009    (:gen-class))
010  
011  (def cli-options
012    [["-h" "--help"]
013     ["-p PROMPT" "--prompt PROMPT" "Set the REPL prompt to PROMPT"
014      :default "Sprecan::"]
015     ["-r INITFILE" "--read INITFILE" "Read Lisp functions from the file INITFILE"
016      :validate [#(and
017                    (.exists (io/file %))
018                    (.canRead (io/file %)))
019                 "Could not find initfile"]]
020     ["-s" "--strict" "Strictly interpret the Lisp 1.5 language, without extensions."]
021     ["-t" "--trace" "Trace Lisp evaluation."]])
022  
023  (defn repl
024    "Read/eval/print loop."
025    [prompt]
026    (loop []
027      (print prompt)
028      (flush)
029      (try
030        (let [input (read-line)]
031          (cond
032            (= input "quit") (throw (ex-info "\nFærwell!" {:cause :quit}))
033            input (println (str ">  " (print-str (EVAL (READ input) @oblist))))
034            :else (println)))
035        (catch
036          Exception
037          e
038          (let [data (ex-data e)]
039            (println (.getMessage e))
040            (if
041              data
042              (case (:cause data)
043                :parse-failure (println (:failure data))
044                :strict nil ;; the message, which has already been printed, is enough.
045                :quit (throw e)
046                ;; default
047                (pprint data))))))
048      (recur)))
049  
050  (defn -main
051    "Parse options, print the banner, read the init file if any, and enter the
052    read/eval/print loop."
053    [& opts]
054    (let [args (parse-opts opts cli-options)]
055      (println
056        (str
057          "\nHider wilcuman. Béowulf is mín nama.\n"
058          (if
059            (System/getProperty "beowulf.version")
060            (str "Síðe " (System/getProperty "beowulf.version") "\n"))
061          (if
062            (:help (:options args))
063            (:summary args))
064          (if (:errors args)
065            (apply str (interpose "; " (:errors args))))
066          "\nSprecan 'quit' tó laéfan\n"))
067      (binding [*options* (:options args)]
068        (try
069          (repl (str (:prompt (:options args)) " "))
070          (catch
071            Exception
072            e
073            (let [data (ex-data e)]
074              (if
075                data
076                (case (:cause data)
077                  :quit nil
078                  ;; default
079                  (pprint data))
080                (println e))))))))