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))))))))