diff options
| author | Your Name <agrawalshagun07@gmail.com> | 2025-03-16 18:03:26 +0530 |
|---|---|---|
| committer | Your Name <agrawalshagun07@gmail.com> | 2025-03-16 18:03:26 +0530 |
| commit | 32499638cef3c49ff686b19b5708d6b08712c526 (patch) | |
| tree | 31f09287602d243b22660fe455e5174bdcc280b4 /cljcc-compiler/src | |
| parent | 277319fa392f5ee9f21eedf2c4d224739f045690 (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.
Diffstat (limited to 'cljcc-compiler/src')
| -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.clj | 9 | ||||
| -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.cljc | 34 | ||||
| -rw-r--r-- | cljcc-compiler/src/cljcc/core/format.clj | 1 | ||||
| -rw-r--r-- | cljcc-compiler/src/cljcc/core/format.cljc | 10 | ||||
| -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.cljc | 139 | ||||
| -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.cljc | 28 | ||||
| -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 |
22 files changed, 30 insertions, 269 deletions
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))) |
