Parses command line arguments and performs the compilation process. | (ns mini-java.core
(:require [mini-java.parser :as parser]
[mini-java.static-semantics :as static-semantics]
[mini-java.code-gen :as code-gen]
[clojure.tools.cli :refer [parse-opts]])
(:gen-class)) |
(def cli-options
[["-d" "--directory DIR" "Destination directory for class files"
:validate [#(.exists (clojure.java.io/file %))
"Must be an existing directory"]
:default "."]
[nil "--syntax"
"Stop after syntax checking"]
[nil "--static-semantics"
"Stop after static semantics checking"]
["-h" "--help"]]) | |
Formats cli usage summary message. | (defn usage
[options-summary]
(->> ["Usage: mini-javac [options] filename"
""
"Options:"
options-summary]
(clojure.string/join \newline))) |
Formats cli parse error message. | (defn error-msg
[errors]
(str "The following errors occurred while parsing your command:\n\n"
(clojure.string/join \newline errors))) |
Exits the program, with an optional exit status and message. Default exit status is 0. | (defn exit
([]
(System/exit 0))
([status]
(System/exit status))
([status msg]
(println msg)
(System/exit status))) |
(defn errors-occured [n]
(str n " error"
(if (= 1 n) "s")
" occurred.")) | |
Parse the command line arguments and perform the compilation. | (defn -main
[& args]
(let [{:keys [options arguments errors summary]}
(parse-opts args cli-options)]
;; check for anything which might cause the program to exit before
;; parsing the source file
(cond
;; print help message
(:help options) (exit 0 (usage summary))
;; only one positional argument is expected
(not= (count arguments) 1) (exit 1 (usage summary))
;; errors in parsing command line options
errors (exit 1 (error-msg errors)))
;; begin compilation process
(let [source-file (first arguments)
;; parse AST from source file
[ast parser errors] (parser/mini-java source-file)]
;; exit if there are syntax errors
(when (pos? errors)
(exit 1 (errors-occured errors)))
;; exit if only syntax checking is requested
(when (:syntax options)
(exit 0))
;; perform static semantics checking
(let [[class-table errors]
(static-semantics/class-table ast parser)]
;; exit if there are semantic errors
(when-not (zero? errors)
(exit 1 (errors-occured errors)))
;; exit if only static semantics checking is requested
(when (:static-semantics options)
(exit 0))
;; generate bytecode and write to files in the given directory
(code-gen/write-classes class-table
(:directory options)))))
nil) |