aboutsummaryrefslogtreecommitdiff
path: root/cljcc-compiler/src/cljcc/util.clj
blob: 4c56ab93c9b1dd9c0feef72a6951485721a5cabe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
(ns cljcc.util
  (:require [clojure.java.shell :refer [sh]]
            [clojure.string :as str]
            [cljcc.log :as log]
            [cljcc.exception :as exc]))

(def ^:private counter "Global integer counter for generating unique identifier names." (atom 0))

(set! *warn-on-reflection* true)

(defn create-identifier!
  "Returns a unique identifier. Used for generating unique identifier.

  Removes : from keywords.
  Replaces all - with _ for generating valid assembly names."
  ([]
   (create-identifier! "tmp"))
  ([identifier]
   (let [n @counter
         _ (swap! counter inc)]
     (-> identifier
         (str "." n)
         (str/replace #":" "")
         (str/replace #"-" "_")))))

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

(defn letter-digit? [^Character ch]
  (or (= \_ ch)
      (Character/isLetterOrDigit ch)))

(defn letter-digit-period? [^Character ch]
  (or (= \_ ch)
      (= \. ch)
      (= \+ ch)
      (= \- ch)
      (Character/isLetterOrDigit ch)))

(defn digit? [^Character ch]
  (Character/isDigit ch))

(defn newline? [ch]
  (= \newline ch))

(defn whitespace? [^Character ch]
  (Character/isWhitespace ch))

(defn matches-regex [re s]
  (not (nil? (re-matches re s))))

(def unsigned-long-re-without-wordbreak #"[0-9]+([lL][uU]|[uU][lL])")
(def signed-long-re-without-wordbreak #"[0-9]+[lL]")
(def unsigned-int-re-without-wordbreak #"[0-9]+[uU]")
(def signed-int-re-without-wordbreak #"[0-9]+")
(def floating-point-constant-without-wordbreak #"([0-9]*\.[0-9]+|[0-9]+\.?)[Ee][+-]?[0-9]+|[0-9]*\.[0-9]+|[0-9]+\.")

(def unsigned-long-re #"([0-9]+([lL][uU]|[uU][lL]))[^\w.]")
(def signed-long-re #"([0-9]+[lL])[^\w.]")
(def unsigned-int-re #"([0-9]+[uU])[^\w.]")
(def signed-int-re #"([0-9]+)[^\w.]")
(def floating-point-constant #"(([0-9]*\.[0-9]+|[0-9]+\.?)[Ee][+-]?[0-9]+|[0-9]*\.[0-9]+|[0-9]+\.)[^\w.]")

(defn- re-find-indexed [re s]
  (let [matcher (re-matcher re s)]
    (when (.find matcher)
      [(.group matcher 1)
       (.start matcher 1)
       (.end matcher 1)])))

(defn match-regex
  "Returns matched string and remaining string tuple, otherwise returns nil.

  The first match by re-finds must be the starting subsequence, otherwise false."
  [re s]
  (when-let [[matched start-index _] (re-find-indexed re s)]
    (when (and (= 0 start-index) (str/starts-with? s matched))
      [matched (str/replace-first s matched "")])))

(defn read-number
  "Returns tuple of matched number and remaining string, otherwise nil."
  [s line col]
  (if-let [x (or
              (match-regex floating-point-constant s)
              (match-regex signed-int-re s)
              (match-regex signed-long-re s)
              (match-regex unsigned-int-re s)
              (match-regex unsigned-long-re s))]
    x
    (exc/lex-error {:line line
                    :col col})))

(defn round-away-from-zero [num div]
  (let [div (abs div)]
    (cond
      (= (mod num div) 0) num
      (< num 0) (- num (- div (mod num div)))
      :else (+ num (- div (mod num div))))))

(defn in-int-range?
  "Verifies whether -2^31 <= x <= 2^31."
  [v]
  (and (>= v Integer/MIN_VALUE)
       (<= v Integer/MAX_VALUE)))

(defn get-type-size [t]
  (condp = t
    {:type :int} 5
    {:type :uint} 5
    {:type :long} 10
    {:type :ulong} 10
    (exc/analyzer-error "Invalid type passed to get-type-size." {:type t})))

(defn type-double? [t]
  (= {:type :double} t))

(defn type-signed? [t]
  (condp = t
    {:type :int} true
    {:type :long} true
    {:type :uint} false
    {:type :ulong} false
    (exc/analyzer-error "Invalid type passed to type-signed?." {:type t})))