         '(java.text ParseException))
 
 (s/defn type-conversion-atom? :- s/Bool [node :- IASTNode] false)
-
-(s/defrecord CoercionType
-    [datatype :- s/Keyword modifiers :- #{s/Keyword} size :- s/Int])
-(s/defrecord CoercionContext
-    ;[node-type :- s/Keyword context-type :- CoercionType arg-type :- CoercionType])
-    [node-type :- s/Keyword context-type arg-type])
 
 (s/defrecord TD ;TypeDescription
     [number-type :- s/Keyword bits :- s/Int])

       (map #(- % (first signed-range)) signed-range)
       signed-range))))

(s/defn td-range :- [(s/one s/Int "lower") (s/one s/Int "upper")] [type]
  (bit-range (:unsigned? type) (:bits type)))

;(s/defn type-conversion-declaration? :- s/Bool
;  [node :- IASTSimpleDeclaration]
;  (let [context-type (->> node unify-type)]
;    (if (nil? context-type)
;      false
;      (let [[context-lower context-upper] (bit-range node)
;            arg-exprs (keep #(some->> % .getInitializer .getInitializerClause) (.getDeclarators node))
;            simple-arg-exprs (filter #(not (instance? IASTInitializerList %)) arg-exprs)
;            arg-types (keep #(->> % .getExpressionType .getKind basic-type) simple-arg-exprs)]
;
;        (or
;         ; real -> int
;         (and (#{:int} (:number-type context-type))
;              (any-pred? #(#{:real} (:number-type %)) arg-types))
;
;         ; large -> small
;         ; signed -> unsigned (and the reverse)
;         (any-pred? (fn [[type expr]]
;                      (and (numeric-literal? expr)
;                           (#{:int} (:number-type type))
;                           (not (<= context-lower (parse-numeric-literal expr) context-upper))))
;                    (map vector arg-types arg-exprs))
;         )))))

(defmulti unify-arg-types class)
(s/defmethod unify-arg-types IASTBinaryExpression [node]
  (map unify-type [(.getOperand2 node)]))
(s/defmethod unify-arg-types IASTSimpleDeclaration [node]
  (keep #(some->> % .getInitializer .getInitializerClause unify-type) (.getDeclarators node)))


;(s/defn type-conversion-assignment? :- s/Bool
;  [node :- IASTBinaryExpression]
;  (let [context-type (->> node unify-type)]
;    (if (nil? context-type)
;      false
;      (let [[context-lower context-upper] (bit-range node)
;            arg-expr (->> node .getOperand2)
;            arg-type (->> arg-expr unify-type)]
;
;        (boolean
;         (or
;                                        ; real -> int
;          (and (#{:int}  (:number-type context-type))
;               (#{:real} (:number-type arg-type)))
;
;                                        ; large -> small
;                                        ; signed -> unsigned (and the reverse)
;          (and (numeric-literal? arg-expr)
;               (#{:int} (:number-type arg-type))
;               (not (<= context-lower (parse-numeric-literal arg-expr) context-upper)))))
;        ))))

{:unsigned :val}
(s/defn type-conversion? :- s/Bool
  [node]
  (try
    (let [context-type (->> node unify-type)
          arg-types (->> node unify-arg-types)] ; merge unsigned in
      (boolean (when (and context-type (not-empty arg-types))
                 (let [[context-lower context-upper] (td-range context-type)]
                   (or
                                        ; real -> int
                    (and (#{:int} (:number-type context-type))


(def decl-type (into {} (map #(into [] (vals (select-keys % [1 2]))) type-components)))
(def basic-type (into {} (map #(into [] (vals (select-keys % [0 2]))) type-components)))

(defmulti unsigned? class)
(s/defmethod unsigned? IASTSimpleDeclaration [node] (->> node .getDeclSpecifier unsigned?))
