aboutsummaryrefslogtreecommitdiff
path: root/src/cljcc/analyze/resolve.clj
diff options
context:
space:
mode:
authorYour Name <agrawalshagun07@gmail.com>2025-03-16 02:00:40 +0530
committerYour Name <agrawalshagun07@gmail.com>2025-03-16 02:00:40 +0530
commit0321df3708cfa4d1440faf3f407611df85484b4b (patch)
tree8c23154afaf1afd78363eb0fa639edd5d8a32821 /src/cljcc/analyze/resolve.clj
parente458b2fadee1eaf0a6cf4ed4881da6f3f25acc21 (diff)
Refactor files to cljcc-compiler and cli tool.
Diffstat (limited to 'src/cljcc/analyze/resolve.clj')
-rw-r--r--src/cljcc/analyze/resolve.clj300
1 files changed, 0 insertions, 300 deletions
diff --git a/src/cljcc/analyze/resolve.clj b/src/cljcc/analyze/resolve.clj
deleted file mode 100644
index 9f09333..0000000
--- a/src/cljcc/analyze/resolve.clj
+++ /dev/null
@@ -1,300 +0,0 @@
-(ns cljcc.analyze.resolve
- (:require [cljcc.exception :as exc]
- [cljcc.parser :as p]
- [malli.dev.pretty :as pretty]
- [cljcc.schema :as s]
- [cljcc.util :as util]
- [malli.core :as m]))
-
-(defn- unique-identifier [identifier]
- (util/create-identifier! identifier))
-
-(defn- copy-identifier-map
- "Returns a copy of the identifier -> symbol map.
-
- Sets :at-top-level false, as it's going inside a scope. ( Could be fn definition, compound statement ).
- Sets :from-current-scope as false for every symbol. Used when going into a inner scope."
- [ident->symbol]
- (let [set-from-current-scope-as-false (fn [i->s]
- (zipmap (keys i->s)
- (map (fn [s]
- (assoc s :from-current-scope false))
- (vals i->s))))]
- (-> ident->symbol
- (dissoc :at-top-level)
- set-from-current-scope-as-false
- (assoc :at-top-level false))))
-
-(declare resolve-block resolve-declaration resolve-optional-exp)
-
-(defn- resolve-exp [e ident->symbol]
- (condp = (:exp-type e)
- :constant-exp e
- :variable-exp (if (contains? ident->symbol (:identifier e))
- (p/variable-exp-node (:name (get ident->symbol (:identifier e))))
- (exc/analyzer-error "Undeclared variable seen." {:variable e}))
- :assignment-exp (let [left (:left e)
- right (:right e)
- op (:assignment-operator e)
- left-var? (= :variable-exp (:exp-type left))]
- (if left-var?
- (p/assignment-exp-node (resolve-exp left ident->symbol)
- (resolve-exp right ident->symbol)
- op)
- (exc/analyzer-error "Invalid lvalue in assignment expression." {:lvalue e})))
- :binary-exp (p/binary-exp-node (resolve-exp (:left e) ident->symbol)
- (resolve-exp (:right e) ident->symbol)
- (:binary-operator e))
- :unary-exp (p/unary-exp-node (:unary-operator e) (resolve-exp (:value e) ident->symbol))
- :conditional-exp (p/conditional-exp-node (resolve-exp (:left e) ident->symbol)
- (resolve-exp (:middle e) ident->symbol)
- (resolve-exp (:right e) ident->symbol))
- :cast-exp (p/cast-exp-node (:target-type e)
- (resolve-exp (:value e) ident->symbol))
- :function-call-exp (let [fn-name (:identifier e)
- args (:arguments e)]
- (if (contains? ident->symbol fn-name)
- (p/function-call-exp-node (:new-name (get ident->symbol fn-name))
- (mapv #(resolve-exp % ident->symbol) args))
- (exc/analyzer-error "Undeclared function." {:function-name fn-name})))
- (exc/analyzer-error "Invalid expression." {:exp e})))
-
-(defn- resolve-optional-exp [e ident->symbol]
- (if (nil? e)
- e
- (resolve-exp e ident->symbol)))
-
-(defn- resolve-file-scope-variable-declaration
- "Adds file scope variable declaration to scope.
-
- Directly adds variable declaration to map as it is top level."
- [{:keys [identifier] :as declaration} ident->symbol]
- {:declaration declaration
- :ident->symbol (assoc ident->symbol identifier {:new-name identifier
- :name identifier
- :from-current-scope true
- :has-linkage true})})
-
-(defn- resolve-local-variable-declaration
- "Add local variable declaration.
-
- Validates for variables declared with same name.
- Validates for variables declared from different scope, but with conflicting storage class."
- [{:keys [identifier initial variable-type storage-class] :as declaration} ident->symbol]
- (let [prev-entry (get ident->symbol identifier)
- extern? (= storage-class :extern)
- _ (when (and prev-entry (:from-current-scope prev-entry))
- (when (not (and (:has-linkage prev-entry) extern?))
- (exc/analyzer-error "Conflicting local declaration." {:declaration declaration})))]
- (if extern?
- {:declaration declaration
- :ident->symbol (assoc ident->symbol identifier {:new-name identifier
- :name identifier
- :from-current-scope true
- :has-linkage true})}
- (let [unique-name (unique-identifier identifier)
- updated-symbols (assoc ident->symbol identifier {:new-name unique-name
- :name unique-name
- :from-current-scope true
- :has-linkage false})
- init-value (when initial (resolve-exp initial updated-symbols))]
- {:declaration (p/variable-declaration-node unique-name storage-class variable-type init-value)
- :ident->symbol updated-symbols}))))
-
-(defn- resolve-variable-declaration
- "Resolves variable declarations.
-
- Ensures variable not declared twice in the current scope."
- [decl {:keys [at-top-level] :as ident->symbol}]
- (if at-top-level
- (resolve-file-scope-variable-declaration decl ident->symbol)
- (resolve-local-variable-declaration decl ident->symbol)))
-
-(defn- resolve-parameter [parameter ident->symbol]
- (if (and (contains? ident->symbol parameter)
- (:from-current-scope (get ident->symbol parameter)))
- (exc/analyzer-error "Parameter name duplicated." {:parameter parameter})
- (let [unique-name (unique-identifier parameter)
- updated-identifier-map (assoc ident->symbol parameter {:name unique-name
- :from-current-scope true
- :has-linkage false})]
- {:parameter unique-name
- :ident->symbol updated-identifier-map})))
-
-(defn- resolve-parameters [params ident->symbol]
- (reduce (fn [acc p]
- (let [{:keys [parameter ident->symbol]} (resolve-parameter p (:ident->symbol acc))]
- {:parameters (conj (:parameters acc) parameter)
- :ident->symbol ident->symbol}))
- {:parameters [] :ident->symbol ident->symbol}
- params))
-
-(defn- resolve-function-declaration
- "Resolve function declaration.
-
- Ensures functions not declared twice in current scope with incorrect linkage."
- [{:keys [identifier storage-class parameters function-type body] :as d} ident->symbol]
- (let [prev-entry (get ident->symbol identifier)
- already-declared-var? (and (contains? ident->symbol identifier)
- (:from-current-scope (get ident->symbol identifier))
- (not (:has-linkage prev-entry)))
- illegally-redeclared? (and (contains? ident->symbol identifier)
- (:from-current-scope prev-entry)
- (not (:has-linkage prev-entry)))
- static? (= :static storage-class)
- inside-function-definition? (not (:at-top-level ident->symbol))
- _ (when already-declared-var?
- (exc/analyzer-error "Variable already declared in same scope." {:declaration d}))
- _ (when illegally-redeclared?
- (exc/analyzer-error "Function duplicate declaration." {:declaration d}))
- updated-identifier-map (assoc ident->symbol identifier {:new-name identifier
- :name identifier
- :from-current-scope true
- :has-linkage true})
- inner-map (copy-identifier-map updated-identifier-map)
- {new-params :parameters, inner-map :ident->symbol} (resolve-parameters parameters inner-map)
- _ (when (and body inside-function-definition?)
- (exc/analyzer-error "Nested function definition not allowed." {:declaration d
- :ident->symbol ident->symbol}))
- _ (when (and inside-function-definition? static?)
- (exc/analyzer-error "Nested static function declarations cannot exist." {:declaration d}))
- new-body (when body (resolve-block body inner-map))]
- {:declaration (p/function-declaration-node function-type storage-class identifier new-params (:block new-body))
- :ident->symbol updated-identifier-map}))
-
-(defn- resolve-declaration [{:keys [declaration-type] :as d} ident->symbol]
- (condp = declaration-type
- :variable (resolve-variable-declaration d ident->symbol)
- :function (resolve-function-declaration d ident->symbol)
- (exc/analyzer-error "Invalid declaration type" {:declaration d})))
-
-(defn- resolve-for-init [for-init ident->symbol]
- (if (= (:type for-init) :declaration)
- (resolve-declaration for-init ident->symbol)
- (resolve-optional-exp for-init ident->symbol)))
-
-(defmulti resolve-statement
- "Resolves statements in a given scope.
-
- Scope here refers to the ident->symbol map, which holds declarations
- visisble to statement at this time.
-
- Dispatches based on the type of statement.
-
- Returns statement after recursively resolving all expressions and statements.
- "
- (fn [statement _ident->symbol]
- (:statement-type statement)))
-
-(defmethod resolve-statement :default [statement _]
- (exc/analyzer-error "Invalid statement." {:statement statement}))
-
-(defmethod resolve-statement :return [{:keys [value]} ident->symbol]
- (p/return-statement-node (resolve-exp value ident->symbol)))
-
-(defmethod resolve-statement :break [statement _]
- statement)
-
-(defmethod resolve-statement :continue [statement _]
- statement)
-
-(defmethod resolve-statement :empty [statement _]
- statement)
-
-(defmethod resolve-statement :expression [{:keys [value]} ident->symbol]
- (p/expression-statement-node (resolve-exp value ident->symbol)))
-
-(defmethod resolve-statement :if [{:keys [condition then-statement else-statement]} ident->symbol]
- (if else-statement
- (p/if-statement-node (resolve-exp condition ident->symbol)
- (resolve-statement then-statement ident->symbol)
- (resolve-statement else-statement ident->symbol))
- (p/if-statement-node (resolve-exp condition ident->symbol)
- (resolve-statement then-statement ident->symbol))))
-
-(defmethod resolve-statement :while [{:keys [condition body]} ident->symbol]
- (p/while-statement-node (resolve-exp condition ident->symbol)
- (resolve-statement body ident->symbol)))
-
-(defmethod resolve-statement :do-while [{:keys [condition body]} ident->symbol]
- (p/do-while-statement-node (resolve-exp condition ident->symbol)
- (resolve-statement body ident->symbol)))
-
-(defmethod resolve-statement :for [{:keys [init condition post body]} ident->symbol]
- (let [for-scope-identifier-map (copy-identifier-map ident->symbol)
- resolved-for-init (resolve-for-init init for-scope-identifier-map)
- for-scope-identifier-map (if (:declaration resolved-for-init) ; updates symbol map if for initializer is declaration
- (:ident->symbol resolved-for-init)
- for-scope-identifier-map)
- resolved-for-init (if (:declaration resolved-for-init) ; getting the underlying declaration, if it is
- (:declaration resolved-for-init)
- resolved-for-init)
- condition (resolve-optional-exp condition for-scope-identifier-map)
- post (resolve-optional-exp post for-scope-identifier-map)
- body (resolve-statement body for-scope-identifier-map)]
- (p/for-statement-node resolved-for-init condition post body)))
-
-(defmethod resolve-statement :compound [{:keys [block]} ident->symbol]
- (p/compound-statement-node (:block (resolve-block block (copy-identifier-map ident->symbol)))))
-
-(defn- resolve-block-item [{:keys [type] :as item} ident->symbol]
- (condp = type
- :declaration (let [{d :declaration
- i->s :ident->symbol} (resolve-declaration item ident->symbol)]
- {:block-item d
- :ident->symbol i->s})
- :statement {:block-item (resolve-statement item ident->symbol)
- :ident->symbol ident->symbol}))
-
-(defn- resolve-block
- "Resolves a block under a given symbol table.
-
- Block is list of block items.
-
- ident->symbol holds identifier to symbol mapping.
- Symbol contains the type information, generated variable name etc.
-
- | key | description |
- |----------------|-------------|
- |`:at-top-level` | Is current level top or not ( default true)|"
- ([block]
- (resolve-block block {:at-top-level true}))
- ([block ident->symbol]
- (let [reduce-f (fn [acc block-item]
- (let [res (resolve-block-item block-item (:ident->symbol acc))]
- {:block (conj (:block acc) (:block-item res))
- :ident->symbol (:ident->symbol res)}))]
- (reduce reduce-f
- {:block []
- :ident->symbol ident->symbol}
- block))))
-
-;; Program is list of block items, which are themselves just blocks.
-(defn resolve-program [program]
- (let [res (:block (resolve-block program))]
- ; _ (m/coerce s/Program res)]
- res))
-
-(comment
-
- (def file-path "./test-programs/example.c")
-
- (slurp "./test-programs/example.c")
-
- (-> file-path
- slurp
- p/parse-from-src)
-
- (-> file-path
- slurp
- p/parse-from-src
- resolve-program)
-
- (pretty/explain
- s/Program
- (-> file-path
- slurp
- p/parse-from-src
- resolve-program))
-
- ())