aboutsummaryrefslogtreecommitdiff
path: root/cljcc-compiler/src/cljcc/util.clj
blob: dee99ad2d7e6cf1497162adc31b816ed1bc9a0fc (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
(ns cljcc.util
  (:require
   [clojure.string :as str]
   [cljcc.core.exception :as exc]))

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

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