aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYour Name <agrawalshagun07@gmail.com>2025-03-16 18:03:26 +0530
committerYour Name <agrawalshagun07@gmail.com>2025-03-16 18:03:26 +0530
commit32499638cef3c49ff686b19b5708d6b08712c526 (patch)
tree31f09287602d243b22660fe455e5174bdcc280b4
parent277319fa392f5ee9f21eedf2c4d224739f045690 (diff)
Refactor into cli and cljcc-compiler folders
Pass all tests. Fix babashka tasks and build setup. Repl is behaving in unexpected ways, otherwise working as expected.
-rw-r--r--bb.edn31
-rw-r--r--cli/build.clj9
-rw-r--r--cli/deps.edn7
-rw-r--r--cli/src/cli/cli.clj2
-rw-r--r--cli/src/cli/driver.clj154
-rw-r--r--cljcc-compiler/src/cljcc/analyze/core.clj (renamed from cljcc-compiler/src/cljcc/analyze/core.cljc)0
-rw-r--r--cljcc-compiler/src/cljcc/analyze/label_loops.clj (renamed from cljcc-compiler/src/cljcc/analyze/label_loops.cljc)2
-rw-r--r--cljcc-compiler/src/cljcc/analyze/resolve.clj (renamed from cljcc-compiler/src/cljcc/analyze/resolve.cljc)2
-rw-r--r--cljcc-compiler/src/cljcc/analyze/typecheck.clj (renamed from cljcc-compiler/src/cljcc/analyze/typecheck.cljc)2
-rw-r--r--cljcc-compiler/src/cljcc/cljcc.clj (renamed from cljcc-compiler/src/cljcc/cljcc.cljc)4
-rw-r--r--cljcc-compiler/src/cljcc/compiler.clj (renamed from cljcc-compiler/src/cljcc/compiler.cljc)2
-rw-r--r--cljcc-compiler/src/cljcc/config.clj9
-rw-r--r--cljcc-compiler/src/cljcc/core/exception.clj (renamed from cljcc-compiler/src/cljcc/exception.cljc)2
-rw-r--r--cljcc-compiler/src/cljcc/core/exception.cljc34
-rw-r--r--cljcc-compiler/src/cljcc/core/format.clj1
-rw-r--r--cljcc-compiler/src/cljcc/core/format.cljc10
-rw-r--r--cljcc-compiler/src/cljcc/core/log.clj (renamed from cljcc-compiler/src/cljcc/core/log.cljc)0
-rw-r--r--cljcc-compiler/src/cljcc/driver.cljc139
-rw-r--r--cljcc-compiler/src/cljcc/emit.clj (renamed from cljcc-compiler/src/cljcc/emit.cljc)17
-rw-r--r--cljcc-compiler/src/cljcc/lexer.clj (renamed from cljcc-compiler/src/cljcc/lexer.cljc)2
-rw-r--r--cljcc-compiler/src/cljcc/log.cljc28
-rw-r--r--cljcc-compiler/src/cljcc/parser.clj (renamed from cljcc-compiler/src/cljcc/parser.cljc)2
-rw-r--r--cljcc-compiler/src/cljcc/schema.clj (renamed from cljcc-compiler/src/cljcc/schema.cljc)0
-rw-r--r--cljcc-compiler/src/cljcc/symbol.clj (renamed from cljcc-compiler/src/cljcc/symbol.cljc)0
-rw-r--r--cljcc-compiler/src/cljcc/tacky.clj (renamed from cljcc-compiler/src/cljcc/tacky.cljc)2
-rw-r--r--cljcc-compiler/src/cljcc/token.clj (renamed from cljcc-compiler/src/cljcc/token.cljc)0
-rw-r--r--cljcc-compiler/src/cljcc/util.clj (renamed from cljcc-compiler/src/cljcc/util.cljc)41
-rw-r--r--deps.edn9
28 files changed, 210 insertions, 301 deletions
diff --git a/bb.edn b/bb.edn
index a995603..54f6027 100644
--- a/bb.edn
+++ b/bb.edn
@@ -10,33 +10,30 @@
clean {:doc "Removes target folder."
:task (fs/delete-tree "target")}
- run-main {:doc "Run main"
- :task (apply clojure "-M -m cljcc.cljcc" *command-line-args*)}
-
nrepl {:doc "Starts a nrepl session."
:task (apply clojure "-M:nrepl" *command-line-args*)}
storm {:doc "Starts a nrepl session with storm debugger."
:task (apply clojure "-M:storm" *command-line-args*)}
- build-uberjar {:doc "Builds uberjar"
- :task (when (seq (fs/modified-since "target/cljcc"
- ["src" "build.clj" "deps.edn" "test" "resources"]))
- (clojure "-T:build ci"))}
+ cli:run:main {:doc "Run's main CLI function."
+ :task (apply shell {:dir "cli"} "clojure -M -m cli.cli" *command-line-args*)}
+
+ cli:build:jar {:doc "Builds uberjar for CLI."
+ :task (shell {:dir "cli"} "clojure -T:build ci")}
- run-uberjar {:doc "Run uberjar"
- :depends [build-uberjar]
- :task (apply shell "java -jar target/cljcc/cljcc.jar" *command-line-args*)}
+ cli:run:jar {:doc "Runs CLI jar."
+ :depends [cli:build:jar]
+ :task (apply shell "java -jar target/cli/cljcc-cli.jar" *command-line-args*)}
- build-native {:doc "Builds native image"
- :depends [build-uberjar]
- :task
- (shell {:dir "target/cljcc"}
+ cli:build:native {:doc "Builds native image for CLI."
+ :depends [cli:build:jar]
+ :task
+ (shell {:dir "target/cli"}
"native-image"
- "-jar" "cljcc.jar"
- "-o" "cljcc"
+ "-jar" "cljcc-cli.jar"
+ "-o" "cljcc-cli"
"-Ob" ; quick compilation flag for development
- ; "-H:Name=cljcc"
"-H:+ReportExceptionStackTraces"
"--features=clj_easy.graal_build_time.InitClojureClasses"
"--initialize-at-build-time"
diff --git a/cli/build.clj b/cli/build.clj
index 47c8537..4bf6a82 100644
--- a/cli/build.clj
+++ b/cli/build.clj
@@ -2,14 +2,14 @@
(:refer-clojure :exclude [test])
(:require [clojure.tools.build.api :as b]))
-(def lib 'net.clojars.cljcc/cljcc)
-(def main 'cljcc.cljcc)
+(def lib 'net.clojars.cljcc-cli/cljcc-cli)
+(def main 'cli.cli)
(def class-dir "../target/classes")
(defn- uber-opts [opts]
(assoc opts
:lib lib :main main
- :uber-file "../target/cljcc/cljcc.jar"
+ :uber-file "../target/cli/cljcc-cli.jar"
:basis (b/create-basis {})
:class-dir class-dir
:src-dirs ["src"]
@@ -23,5 +23,6 @@
(println (str "\nCompiling " main "..."))
(b/compile-clj opts)
(println "\nBuilding JAR...")
- (b/uber opts))
+ (b/uber opts)
+ (println "\nJAR built."))
opts)
diff --git a/cli/deps.edn b/cli/deps.edn
index b0313f3..d074706 100644
--- a/cli/deps.edn
+++ b/cli/deps.edn
@@ -4,5 +4,8 @@
com.github.clj-easy/graal-build-time {:mvn/version "1.0.5"}
cljcc/cljcc {:local/root "../cljcc-compiler"}}
:aliases
- {:run
- {:main-opts ["-m" "cli.cli"]}}}
+ {:run {:main-opts ["-m" "cli.cli"]}
+ :build {:deps {io.github.clojure/tools.build
+ {:mvn/version "0.10.3"}}
+ :jvm-opts ["-Dclojure.compiler.direct-linking=true"]
+ :ns-default build}}}
diff --git a/cli/src/cli/cli.clj b/cli/src/cli/cli.clj
index 5f27187..e1ff5af 100644
--- a/cli/src/cli/cli.clj
+++ b/cli/src/cli/cli.clj
@@ -10,7 +10,7 @@
(defn usage [options-summary]
(->>
- ["Usage: ./cljcc path/to/file.c [options]"
+ ["Usage: ./cljcc-cli path/to/file.c [options]"
""
"Options:"
options-summary]
diff --git a/cli/src/cli/driver.clj b/cli/src/cli/driver.clj
index 76723f5..3e0a862 100644
--- a/cli/src/cli/driver.clj
+++ b/cli/src/cli/driver.clj
@@ -1,4 +1,154 @@
(ns cli.driver
- (:require [cljcc.cljcc :as cljcc]))
+ (:require [cljcc.cljcc :as cljcc]
+ [cli.core.log :as log]
+ [clojure.string :as str]
+ [clojure.pprint :as pp]
+ [clojure.java.shell :refer [sh]]
+ [clojure.java.io :as io]))
-(defn run [& args])
+(defn- remove-extension [^String filename]
+ (if (.contains filename ".")
+ (.substring filename 0 (.lastIndexOf filename "."))
+ filename))
+
+(defn- get-os []
+ (let [os-name (.toLowerCase (System/getProperty "os.name"))]
+ (cond
+ (.contains os-name "mac") :mac
+ (.contains os-name "linux") :linux
+ :else :unsupported)))
+
+(defn mac-aarch64? []
+ (and (= :mac (get-os)) (= (System/getProperty "os.arch") "aarch64")))
+
+(defn- validate-os []
+ (let [os (get-os)]
+ (condp = os
+ :linux (log/info "Running on Linux.")
+ :mac (if (mac-aarch64?)
+ (log/info "Running on Mac ARM64.")
+ (log/info "Running on Mac x86_64."))
+ :unsupported (throw (Exception. (str os " is not currently supported."))))))
+
+(defn- make-file-name
+ ([^String filename ^String ext]
+ (str filename "." ext))
+ ([directory filename ext]
+ (str directory "/" filename "." ext)))
+
+(defn- handle-sh
+ "Preprends arch -x86_64 if running under Mac M chips."
+ [command & args]
+ (let [args (filterv (comp not empty?) args)]
+ (if (mac-aarch64?)
+ (apply sh "arch" "-x86_64" command args)
+ (apply sh command args))))
+
+(defn- cleanup-step [directory filename]
+ (let [file-without-ext (remove-extension filename)]
+ (io/delete-file (make-file-name directory file-without-ext "i") true)
+ (io/delete-file (make-file-name directory file-without-ext "s") true)))
+
+(defn- preprocessor-step [directory filename]
+ (let [input-file-path (make-file-name directory (remove-extension filename) "c")
+ preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
+ output (handle-sh "gcc" "-E" "-P" input-file-path "-o" preprocessed-file-path)]
+ (if (= 1 (:exit output))
+ (throw (Exception. ^String (:err output)))
+ (log/info (str "Successfully preprocessed file: " preprocessed-file-path)))))
+
+(defn- lexer-step [directory filename]
+ (let [preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
+ file (io/file preprocessed-file-path)
+ source (slurp file)
+ output (cljcc/run source :options {:target {:os (get-os)}
+ :stage :lex})]
+ (log/info "Input file is succesfully lexed.")
+ (pp/pprint output)))
+
+(defn- parser-step [directory filename]
+ (let [preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
+ file (io/file preprocessed-file-path)
+ source (slurp file)
+ parsed-ast (cljcc/run source :options {:target {:os (get-os)}
+ :stage :parse})]
+ (log/info "Input file is succesfully parsed.")
+ (pp/pprint parsed-ast)))
+
+(defn- semantic-analyzer-step [directory filename]
+ (let [preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
+ file (io/file preprocessed-file-path)
+ source (slurp file)
+ validated-ast (cljcc/run source :options {:target {:os (get-os)}
+ :stage :validate})]
+ (log/info "Input file is succesfully validated.")
+ (pp/pprint validated-ast)))
+
+(defn- tacky-step [directory filename]
+ (let [preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
+ file (io/file preprocessed-file-path)
+ source (slurp file)
+ output (cljcc/run source :options {:target {:os (get-os)}
+ :stage :tacky})]
+ (log/info (str
+ "Successfully generated Tacky IR.\n"
+ (with-out-str (pp/pprint output))))))
+
+(defn- compiler-step [directory filename]
+ (let [preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
+ file (io/file preprocessed-file-path)
+ source (slurp file)
+ output (cljcc/run source :options {:target {:os (get-os)}
+ :stage :codegen})]
+ (log/info (str "Succesfully generated assembly ast.\n" output))))
+
+(defn- assemble-step [directory filename options]
+ (let [file-without-ext (remove-extension filename)
+ assembly-file (make-file-name directory file-without-ext "s")
+ preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
+ file (io/file preprocessed-file-path)
+ source (slurp file)
+ assembly-output (cljcc/run source :options {:target {:os (get-os)}
+ :stage :emit})
+ assembly-out-file-path (make-file-name directory (remove-extension filename) "s")
+ _ (spit assembly-out-file-path assembly-output)
+ output-file (if (:generate-object-file options)
+ (str directory "/" (str file-without-ext ".o"))
+ (str directory "/" file-without-ext))
+ libs (str/join " " (:libs options))
+ output (if (:generate-object-file options)
+ (handle-sh "gcc" "-c" assembly-file "-o" output-file libs)
+ (handle-sh "gcc" assembly-file "-o" output-file libs))]
+ (if (= 1 (:exit output))
+ (throw (Exception. ^String (:err output)))
+ (log/info (str "Successfully created executable at: " output-file)))))
+
+(defn- create-steps [options directory filename]
+ (let [steps [(partial validate-os)
+ (partial preprocessor-step directory filename)
+ (partial lexer-step directory filename)
+ (partial parser-step directory filename)
+ (partial semantic-analyzer-step directory filename)
+ (partial tacky-step directory filename)
+ (partial compiler-step directory filename)
+ (partial assemble-step directory filename options)]]
+ (cond
+ (:lex options) (subvec steps 0 3)
+ (:parse options) (subvec steps 0 4)
+ (:validate options) (subvec steps 0 5)
+ (:tacky options) (subvec steps 0 6)
+ (:codegen options) (subvec steps 0 7)
+ :else steps)))
+
+(defn- run-steps [options directory filename]
+ (let [steps (create-steps options directory filename)]
+ (run! #(apply % []) steps)))
+
+(defn run [^String file-path options]
+ (let [file (io/file ^String file-path)
+ filename (.getName file)
+ directory (.getParent file)]
+ (try
+ (run-steps options directory filename)
+ (finally
+ (cleanup-step directory filename)))))
diff --git a/cljcc-compiler/src/cljcc/analyze/core.cljc b/cljcc-compiler/src/cljcc/analyze/core.clj
index 793b667..793b667 100644
--- a/cljcc-compiler/src/cljcc/analyze/core.cljc
+++ b/cljcc-compiler/src/cljcc/analyze/core.clj
diff --git a/cljcc-compiler/src/cljcc/analyze/label_loops.cljc b/cljcc-compiler/src/cljcc/analyze/label_loops.clj
index 56fffc9..152e696 100644
--- a/cljcc-compiler/src/cljcc/analyze/label_loops.cljc
+++ b/cljcc-compiler/src/cljcc/analyze/label_loops.clj
@@ -1,6 +1,6 @@
(ns cljcc.analyze.label-loops
(:require [cljcc.parser :as p]
- [cljcc.exception :as exc]
+ [cljcc.core.exception :as exc]
[cljcc.analyze.resolve :as r]
[cljcc.schema :as s]
[cljcc.util :as util]
diff --git a/cljcc-compiler/src/cljcc/analyze/resolve.cljc b/cljcc-compiler/src/cljcc/analyze/resolve.clj
index 9f09333..7db16b6 100644
--- a/cljcc-compiler/src/cljcc/analyze/resolve.cljc
+++ b/cljcc-compiler/src/cljcc/analyze/resolve.clj
@@ -1,5 +1,5 @@
(ns cljcc.analyze.resolve
- (:require [cljcc.exception :as exc]
+ (:require [cljcc.core.exception :as exc]
[cljcc.parser :as p]
[malli.dev.pretty :as pretty]
[cljcc.schema :as s]
diff --git a/cljcc-compiler/src/cljcc/analyze/typecheck.cljc b/cljcc-compiler/src/cljcc/analyze/typecheck.clj
index d1e79dc..4d6843f 100644
--- a/cljcc-compiler/src/cljcc/analyze/typecheck.cljc
+++ b/cljcc-compiler/src/cljcc/analyze/typecheck.clj
@@ -8,7 +8,7 @@
[clojure.core.match :refer [match]]
[cljcc.analyze.resolve :as r]
[cljcc.analyze.label-loops :as l]
- [cljcc.exception :as exc]
+ [cljcc.core.exception :as exc]
[cljcc.util :as u]))
(declare typecheck-block typecheck-declaration to-static-init)
diff --git a/cljcc-compiler/src/cljcc/cljcc.cljc b/cljcc-compiler/src/cljcc/cljcc.clj
index 742c1c2..fc088fc 100644
--- a/cljcc-compiler/src/cljcc/cljcc.cljc
+++ b/cljcc-compiler/src/cljcc/cljcc.clj
@@ -3,13 +3,12 @@
[cljcc.lexer :as lexer]
[cljcc.parser :as parser]
[cljcc.tacky :as tacky]
+ [cljcc.config :as config]
[cljcc.analyze.core :as analyzer]
[cljcc.compiler :as codegen]
[cljcc.emit :as emit])
(:gen-class))
-#?(:clj (set! *warn-on-reflection* true))
-
(def valid-os-targets #{:mac :linux})
(def valid-stages #{:lex :parse :validate :tacky :codegen :emit})
@@ -34,6 +33,7 @@
target-os (:os (:target merged-options))
_ (assert (stage valid-stages) "Invalid stage for compilation.")
_ (assert (target-os valid-os-targets) "Invalid operating system.")
+ _ (config/set-os target-os)
stages [lexer/lex parser/parse
analyzer/validate tacky/tacky-generate
codegen/assembly emit/emit]
diff --git a/cljcc-compiler/src/cljcc/compiler.cljc b/cljcc-compiler/src/cljcc/compiler.clj
index 39b3506..19e1780 100644
--- a/cljcc-compiler/src/cljcc/compiler.cljc
+++ b/cljcc-compiler/src/cljcc/compiler.clj
@@ -8,7 +8,7 @@
[malli.core :as m]
[malli.dev.pretty :as pretty]
[cljcc.util :as util]
- [cljcc.exception :as exc]))
+ [cljcc.core.exception :as exc]))
(def registers #{:ax :dx :di :si :r8 :r9 :r10 :r11 :cx :cl :sp})
diff --git a/cljcc-compiler/src/cljcc/config.clj b/cljcc-compiler/src/cljcc/config.clj
new file mode 100644
index 0000000..d5a6dc2
--- /dev/null
+++ b/cljcc-compiler/src/cljcc/config.clj
@@ -0,0 +1,9 @@
+(ns cljcc.config)
+
+(def config (atom {}))
+
+(defn set-os [os]
+ (swap! config assoc :os os))
+
+(defn get-os []
+ (or (get @config :os) :linux))
diff --git a/cljcc-compiler/src/cljcc/exception.cljc b/cljcc-compiler/src/cljcc/core/exception.clj
index 40ea930..412dfff 100644
--- a/cljcc-compiler/src/cljcc/exception.cljc
+++ b/cljcc-compiler/src/cljcc/core/exception.clj
@@ -1,4 +1,4 @@
-(ns cljcc.exception)
+(ns cljcc.core.exception)
(defn lex-error [{line :line col :col :as data}]
(throw (ex-info
diff --git a/cljcc-compiler/src/cljcc/core/exception.cljc b/cljcc-compiler/src/cljcc/core/exception.cljc
deleted file mode 100644
index 19245aa..0000000
--- a/cljcc-compiler/src/cljcc/core/exception.cljc
+++ /dev/null
@@ -1,34 +0,0 @@
-(ns cljcc.core.exception
- (:require [cljcc.core.format :refer [safe-format]]))
-
-(defn try-catch-ex
- ([f]
- (try
- (f)
- (catch #?(:clj Throwable :cljs :default) e
- [:error e])))
- ([f default]
- (try
- (f)
- (catch #?(:clj Throwable :cljs :default) e
- default))))
-
-(defn lex-error [{line :line col :col :as data}]
- (throw (ex-info
- (safe-format "Invalid token at line: %s, col: %s." line col)
- (merge {:error/type :lexer} data))))
-
-(defn parser-error [msg data]
- (throw (ex-info msg (merge {:error/type :parser} data))))
-
-(defn analyzer-error [msg data]
- (throw (ex-info msg (merge {:error/type :analyzer} data))))
-
-(defn tacky-error [msg data]
- (throw (ex-info msg (merge {:error/type :tacky} data))))
-
-(defn compiler-error [msg data]
- (throw (ex-info msg (merge {:error/type :compiler} data))))
-
-(defn emit-error [msg data]
- (throw (ex-info msg (merge {:error/type :emit} data))))
diff --git a/cljcc-compiler/src/cljcc/core/format.clj b/cljcc-compiler/src/cljcc/core/format.clj
new file mode 100644
index 0000000..7b3fc48
--- /dev/null
+++ b/cljcc-compiler/src/cljcc/core/format.clj
@@ -0,0 +1 @@
+(ns cljcc.core.format)
diff --git a/cljcc-compiler/src/cljcc/core/format.cljc b/cljcc-compiler/src/cljcc/core/format.cljc
deleted file mode 100644
index 851b6a1..0000000
--- a/cljcc-compiler/src/cljcc/core/format.cljc
+++ /dev/null
@@ -1,10 +0,0 @@
-(ns cljcc.core.format
- #?(:clj (:require [clojure.core :refer [format]])
- :cljs (:require [goog.string :as gstring]
- [goog.string.format])))
-
-(defn safe-format
- "Cross platform format."
- [fmt & args]
- #?(:clj (apply format fmt args)
- :cljs (apply gstring/format fmt args)))
diff --git a/cljcc-compiler/src/cljcc/core/log.cljc b/cljcc-compiler/src/cljcc/core/log.clj
index bb92b02..bb92b02 100644
--- a/cljcc-compiler/src/cljcc/core/log.cljc
+++ b/cljcc-compiler/src/cljcc/core/log.clj
diff --git a/cljcc-compiler/src/cljcc/driver.cljc b/cljcc-compiler/src/cljcc/driver.cljc
deleted file mode 100644
index 20d2d22..0000000
--- a/cljcc-compiler/src/cljcc/driver.cljc
+++ /dev/null
@@ -1,139 +0,0 @@
-(ns cljcc.driver
- (:require
- [clojure.java.io :as io]
- [cljcc.compiler :as c]
- [cljcc.tacky :as t]
- [cljcc.lexer :as l]
- [cljcc.emit :as e]
- [cljcc.analyze.core :as a]
- [clojure.pprint :as pp]
- [cljcc.log :as log]
- [cljcc.util :refer [get-os handle-sh mac-aarch64? make-file-name]]
- [cljcc.parser :as p]
- [clojure.string :as str]))
-
-(defn- validate-os []
- (let [os (get-os)]
- (condp = os
- :linux (log/info "Running on Linux.")
- :mac (if (mac-aarch64?)
- (log/info "Running on Mac ARM64.")
- (log/info "Running on Mac x86_64."))
- :unsupported (throw (Exception. (str os " is not currently supported."))))))
-
-(defn- remove-extension [^String filename]
- (if (.contains filename ".")
- (.substring filename 0 (.lastIndexOf filename "."))
- filename))
-
-(defn- preprocessor-step [directory filename]
- (let [input-file-path (make-file-name directory (remove-extension filename) "c")
- preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
- output (handle-sh "gcc" "-E" "-P" input-file-path "-o" preprocessed-file-path)]
- (if (= 1 (:exit output))
- (throw (Exception. ^String (:err output)))
- (log/info (str "Successfully preprocessed file: " preprocessed-file-path)))))
-
-(defn- assemble-step [directory filename options]
- (let [file-without-ext (remove-extension filename)
- assembly-file (make-file-name directory file-without-ext "s")
- preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
- file (io/file preprocessed-file-path)
- source (slurp file)
- assembly-ast (c/assembly-from-src source)
- assembly-output (e/emit assembly-ast)
- assembly-out-file-path (make-file-name directory (remove-extension filename) "s")
- _ (spit assembly-out-file-path assembly-output)
- output-file (if (:generate-object-file options)
- (str directory "/" (str file-without-ext ".o"))
- (str directory "/" file-without-ext))
- libs (str/join " " (:libs options))
- output (if (:generate-object-file options)
- (handle-sh "gcc" "-c" assembly-file "-o" output-file libs)
- (handle-sh "gcc" assembly-file "-o" output-file libs))]
- (if (= 1 (:exit output))
- (throw (Exception. ^String (:err output)))
- (log/info (str "Successfully created executable at: " output-file)))))
-
-(defn- parser-step [directory filename]
- (let [preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
- file (io/file preprocessed-file-path)
- source (slurp file)
- ast (p/parse (l/lex source))]
- (log/info "Input file is succesfully parsed.")
- (pp/pprint ast)))
-
-(defn- semantic-analyzer-step [directory filename]
- (let [preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
- file (io/file preprocessed-file-path)
- source (slurp file)
- ast (a/validate (p/parse (l/lex source)))]
- (log/info "Input file is succesfully validated.")
- (pp/pprint ast)))
-
-(defn- lexer-step [directory filename]
- (let [preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
- file (io/file preprocessed-file-path)
- source (slurp file)
- output (l/lex source)]
- (log/info "Input file is succesfully lexed.")
- (pp/pprint output)))
-
-(defn- tacky-step [directory filename]
- (let [preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
- file (io/file preprocessed-file-path)
- source (slurp file)
- output (t/tacky-generate (a/validate (p/parse (l/lex source))))]
- (log/info (str
- "Successfully generated Tacky IR.\n"
- (with-out-str (pp/pprint output))))))
-
-(defn- compiler-step [directory filename]
- (let [preprocessed-file-path (make-file-name directory (remove-extension filename) "i")
- file (io/file preprocessed-file-path)
- source (slurp file)
- assembly-ast (c/assembly-from-src source)]
- (log/info (str "Succesfully generated assembly ast.\n" assembly-ast))))
-
-(defn- cleanup-step [directory filename]
- (let [file-without-ext (remove-extension filename)]
- (io/delete-file (make-file-name directory file-without-ext "i") true)
- (io/delete-file (make-file-name directory file-without-ext "s") true)))
-
-(defn- create-steps [options directory filename]
- (let [steps [(partial validate-os)
- (partial preprocessor-step directory filename)
- (partial lexer-step directory filename)
- (partial parser-step directory filename)
- (partial semantic-analyzer-step directory filename)
- (partial tacky-step directory filename)
- (partial compiler-step directory filename)
- (partial assemble-step directory filename options)]]
- (cond
- (:lex options) (subvec steps 0 3)
- (:parse options) (subvec steps 0 4)
- (:validate options) (subvec steps 0 5)
- (:tacky options) (subvec steps 0 6)
- (:codegen options) (subvec steps 0 7)
- :else steps)))
-
-(defn- run-steps [options directory filename]
- (let [steps (create-steps options directory filename)]
- (run! #(apply % []) steps)))
-
-(defn run
- "Runs the compiler driver with the given input source file."
- [^String file-path options]
- (let [file (io/file ^String file-path)
- filename (.getName file)
- directory (.getParent file)]
- (try
- (run-steps options directory filename)
- (finally
- (cleanup-step directory filename)))))
-
-(comment
-
- (run "./test-programs/ex1.c" {})
-
- ())
diff --git a/cljcc-compiler/src/cljcc/emit.cljc b/cljcc-compiler/src/cljcc/emit.clj
index b4fdc13..6c1566e 100644
--- a/cljcc-compiler/src/cljcc/emit.cljc
+++ b/cljcc-compiler/src/cljcc/emit.clj
@@ -1,24 +1,23 @@
(ns cljcc.emit
(:require
- [cljcc.util :refer [get-os]]
[cljcc.compiler :as c]
- [cljcc.core.format :refer [safe-format]]
+ [cljcc.config :as config]
[clojure.string :as str]
[cljcc.core.exception :as exc]))
(defn- handle-label [identifier]
- (condp = (get-os)
+ (condp = (config/get-os)
:mac (str "L" identifier)
:linux (str ".L" identifier)
(throw (ex-info "Error in generating label." {}))))
(defn- handle-symbol-name [name]
- (if (= :mac (get-os))
+ (if (= :mac (config/get-os))
(str "_" name)
name))
(defn- handle-current-translation-unit [name ident->asm-entry]
- (if (= :mac (get-os))
+ (if (= :mac (config/get-os))
(handle-symbol-name name)
(if (get-in ident->asm-entry [name :defined?])
name
@@ -27,13 +26,13 @@
;;;; Operand Emit
(defn- imm-opernad-emit [operand _opts]
- (safe-format "$%d" (:value operand)))
+ (format "$%d" (:value operand)))
(defn- stack-operand-emit [operand _opts]
- (safe-format "%d(%%rbp)" (:value operand)))
+ (format "%d(%%rbp)" (:value operand)))
(defn- data-operand-emit [operand _opts]
- (safe-format "%s(%%rip)" (handle-symbol-name (:identifier operand))))
+ (format "%s(%%rip)" (handle-symbol-name (:identifier operand))))
(defn- register-operand [{:keys [register] :as operand} {register-width :register-width :or {register-width :4-byte}}]
(let [register->width->output {:ax {:8-byte "%rax"
@@ -290,7 +289,7 @@
(defn emit [{:keys [program backend-symbol-table]}]
(let [handle-os (fn [ast]
- (if (= :linux (get-os))
+ (if (= :linux (config/get-os))
(conj (conj (conj (vec ast) linux-assembly-end) "\n"))
ast))]
(->> program
diff --git a/cljcc-compiler/src/cljcc/lexer.cljc b/cljcc-compiler/src/cljcc/lexer.clj
index b2854cf..0bfa12f 100644
--- a/cljcc-compiler/src/cljcc/lexer.cljc
+++ b/cljcc-compiler/src/cljcc/lexer.clj
@@ -1,7 +1,7 @@
(ns cljcc.lexer
(:require
[cljcc.util :refer [newline? whitespace? read-number digit? letter-digit? letter? letter-digit-period?]]
- [cljcc.exception :as exc]
+ [cljcc.core.exception :as exc]
[cljcc.token :as t]))
(defn- lexer-ctx []
diff --git a/cljcc-compiler/src/cljcc/log.cljc b/cljcc-compiler/src/cljcc/log.cljc
deleted file mode 100644
index 3dbc4fb..0000000
--- a/cljcc-compiler/src/cljcc/log.cljc
+++ /dev/null
@@ -1,28 +0,0 @@
-(ns cljcc.log
- (:require [clojure.string :as str]))
-
-(def ^:private log-colors
- {:debug "\u001b[36m" ; Cyan
- :info "\u001b[32m" ; Green
- :warn "\u001b[33m" ; Yellow
- :error "\u001b[31m" ; Red
- :reset "\u001b[0m"}) ; Reset color
-
-(def reset-color (get log-colors :reset))
-
-(defn- log-message [level message]
- (let [color (get log-colors level)
- formatted-message (str color "[" (str/upper-case (name level)) "] " message reset-color)]
- (println formatted-message)))
-
-(defn debug [msg]
- (log-message :debug msg))
-
-(defn info [msg]
- (log-message :info msg))
-
-(defn warn [msg]
- (log-message :warn msg))
-
-(defn error [msg]
- (log-message :error msg))
diff --git a/cljcc-compiler/src/cljcc/parser.cljc b/cljcc-compiler/src/cljcc/parser.clj
index e505aa3..a2067ed 100644
--- a/cljcc-compiler/src/cljcc/parser.cljc
+++ b/cljcc-compiler/src/cljcc/parser.clj
@@ -536,8 +536,6 @@
(def file-path "./test-programs/example.c")
- #?(:clj (slurp "./test-programs/example.c"))
-
(-> file-path
slurp
parse-from-src)
diff --git a/cljcc-compiler/src/cljcc/schema.cljc b/cljcc-compiler/src/cljcc/schema.clj
index bf216f9..bf216f9 100644
--- a/cljcc-compiler/src/cljcc/schema.cljc
+++ b/cljcc-compiler/src/cljcc/schema.clj
diff --git a/cljcc-compiler/src/cljcc/symbol.cljc b/cljcc-compiler/src/cljcc/symbol.clj
index c410dac..c410dac 100644
--- a/cljcc-compiler/src/cljcc/symbol.cljc
+++ b/cljcc-compiler/src/cljcc/symbol.clj
diff --git a/cljcc-compiler/src/cljcc/tacky.cljc b/cljcc-compiler/src/cljcc/tacky.clj
index be60841..a771117 100644
--- a/cljcc-compiler/src/cljcc/tacky.cljc
+++ b/cljcc-compiler/src/cljcc/tacky.clj
@@ -3,7 +3,7 @@
[cljcc.lexer :as l]
[cljcc.util :as u]
[cljcc.parser :as p]
- [cljcc.exception :as exc]
+ [cljcc.core.exception :as exc]
[cljcc.symbol :as sym]
[malli.core :as m]
[malli.dev.pretty :as pretty]
diff --git a/cljcc-compiler/src/cljcc/token.cljc b/cljcc-compiler/src/cljcc/token.clj
index 213588c..213588c 100644
--- a/cljcc-compiler/src/cljcc/token.cljc
+++ b/cljcc-compiler/src/cljcc/token.clj
diff --git a/cljcc-compiler/src/cljcc/util.cljc b/cljcc-compiler/src/cljcc/util.clj
index 00f11dc..dee99ad 100644
--- a/cljcc-compiler/src/cljcc/util.cljc
+++ b/cljcc-compiler/src/cljcc/util.clj
@@ -1,8 +1,7 @@
(ns cljcc.util
- (:require [clojure.java.shell :refer [sh]]
- [clojure.string :as str]
- [cljcc.log :as log]
- [cljcc.exception :as exc]))
+ (:require
+ [clojure.string :as str]
+ [cljcc.core.exception :as exc]))
(def ^:private counter "Global integer counter for generating unique identifier names." (atom 0))
@@ -24,40 +23,6 @@
(defn reset-counter! []
(reset! counter 0))
-(defn make-file-name
- ([^String filename ^String ext]
- (str filename "." ext))
- ([directory filename ext]
- (str directory "/" filename "." ext)))
-
-(defn get-os []
- (let [os-name (.toLowerCase (System/getProperty "os.name"))]
- (cond
- (.contains os-name "mac") :mac
- (.contains os-name "linux") :linux
- :else :unsupported)))
-
-(defn mac-aarch64? []
- (and (= :mac (get-os)) (= (System/getProperty "os.arch") "aarch64")))
-
-(defn handle-sh
- "Preprends arch -x86_64 if running under Mac M chips."
- [command & args]
- (let [args (filterv (comp not empty?) args)]
- (if (mac-aarch64?)
- (apply sh "arch" "-x86_64" command args)
- (apply sh command args))))
-
-(defn exit
- ([status msg]
- (if (= status 0)
- (log/info msg)
- (log/error msg))
- (System/exit status))
- ([status msg e]
- (log/error (ex-data e))
- (exit status msg)))
-
(defn letter? [^Character ch]
(or (= \_ ch)
(Character/isLetter ch)))
diff --git a/deps.edn b/deps.edn
index 1a50091..d4a889e 100644
--- a/deps.edn
+++ b/deps.edn
@@ -4,16 +4,12 @@
metosin/malli {:mvn/version "0.16.4"}
com.github.clj-easy/graal-build-time {:mvn/version "1.0.5"}}
:aliases
- {:cli
- {:extra-paths ["cli/src" "cljcc_compiler/src"]
- :main-opts ["-m" "cli.cli"]}
- :run-m {:main-opts ["-m" "cljcc.cljcc"]}
- :build {:deps {io.github.clojure/tools.build
+ {:build {:deps {io.github.clojure/tools.build
{:mvn/version "0.10.3"}}
:jvm-opts ["-Dclojure.compiler.direct-linking=true"]
:ns-default build}
:storm {;; for disabling the official compiler
- :extra-paths ["cljcc_compiler/src" "cli/src"]
+ :extra-paths ["cljcc-compiler/src" "cli/src"]
:classpath-overrides {org.clojure/clojure nil}
:extra-deps {io.github.clojure/tools.build {:mvn/version "0.10.3"}
nrepl/nrepl {:mvn/version "1.3.0"}
@@ -27,4 +23,5 @@
:nrepl {:extra-deps {nrepl/nrepl {:mvn/version "1.3.0"}
cider/cider-nrepl {:mvn/version "0.50.2"}
refactor-nrepl/refactor-nrepl {:mvn/version "3.10.0"}}
+ :extra-paths ["cljcc-compiler/src" "cli/src"]
:main-opts ["-m" "nrepl.cmdline" "--interactive" "--color" "--middleware" "[cider.nrepl/cider-middleware,refactor-nrepl.middleware/wrap-refactor]"]}}}