Add implemenation of the hook for defcfn
This commit is contained in:
parent
463d35809b
commit
afdca6f5a4
6 changed files with 85 additions and 12 deletions
|
|
@ -1 +1 @@
|
|||
{:config-dirs ["org.suskalo/coffi"]}
|
||||
{:config-paths ["org.suskalo/coffi"]}
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
../../../../resources/clj-kondo.exports/org.suskalo/coffi/coffi/hooks.clj
|
||||
1
.clj-kondo/org.suskalo/coffi/hooks/coffi.clj
Symbolic link
1
.clj-kondo/org.suskalo/coffi/hooks/coffi.clj
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../../../resources/clj-kondo.exports/org.suskalo/coffi/hooks/coffi.clj
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
(ns ^:no-doc coffi.hooks
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as api]))
|
||||
|
||||
(defn defcfn
|
||||
[{:keys [node]}]
|
||||
(let [[] (rest (:children node))]
|
||||
;; TODO(Joshua): Add an implementation of this macro's hook
|
||||
))
|
||||
|
|
@ -1 +1,2 @@
|
|||
{:hooks {:analyze-call {coffi.ffi/defcfn coffi.hooks/defcfn}}}
|
||||
{:hooks {:analyze-call {coffi.ffi/defcfn hooks.coffi/defcfn}}
|
||||
:linters {:coffi.ffi/invalid-syntax {:level :error}}}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
(ns ^:no-doc hooks.coffi
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as api]))
|
||||
|
||||
(defn validate-type
|
||||
[node]
|
||||
(when-not (or (qualified-keyword? (api/sexpr node))
|
||||
(and (api/vector-node? node)
|
||||
(qualified-keyword? (api/sexpr (first (:children node))))))
|
||||
(api/reg-finding!
|
||||
{:row (:row (meta node))
|
||||
:col (:col (meta node))
|
||||
:message "A type must be a qualified keyword or a vector with one as the first element."
|
||||
:type :coffi.ffi/invalid-syntax})))
|
||||
|
||||
(defn defcfn
|
||||
[{:keys [node]}]
|
||||
(try
|
||||
(let [[var-name-node & more] (rest (:children node))
|
||||
[docstring-node & more] (if (and (api/string-node? (first more))
|
||||
(not (api/vector-node? (second more))))
|
||||
more
|
||||
(cons nil more))
|
||||
[attr-map-node & more] (if (api/map-node? (first more))
|
||||
more
|
||||
(cons nil more))
|
||||
[symbol-node native-arglist-node return-type-node & more] more
|
||||
_ (when-not (or (and (api/token-node? symbol-node)
|
||||
(simple-symbol? (api/sexpr symbol-node)))
|
||||
(api/string-node? symbol-node))
|
||||
(api/reg-finding! {:row (:row (meta symbol-node))
|
||||
:col (:col (meta symbol-node))
|
||||
:message "Native symbol must be a string or symbol."
|
||||
:type :coffi.ffi/invalid-syntax}))
|
||||
_ (run! validate-type (cons return-type-node (:children native-arglist-node)))
|
||||
wrapper-nodes (when (seq more)
|
||||
{:native-fn (first more)
|
||||
:fn-tail (rest more)})
|
||||
_ (when (and (:native-fn wrapper-nodes)
|
||||
(empty? (:fn-tail wrapper-nodes)))
|
||||
(api/reg-finding!
|
||||
{:row (:row (meta node))
|
||||
:col (:col (meta node))
|
||||
:message "A defcfn with a native-fn must have a function body."
|
||||
:type :coffi.ffi/invalid-syntax}))
|
||||
arglist-vec (api/vector-node
|
||||
(mapv api/token-node
|
||||
(repeatedly (count (:children native-arglist-node))
|
||||
#(gensym "arg"))))
|
||||
fn-body (if wrapper-nodes
|
||||
(:fn-tail wrapper-nodes)
|
||||
(list
|
||||
arglist-vec
|
||||
arglist-vec))
|
||||
defn-node (api/list-node
|
||||
(list*
|
||||
(api/token-node 'defn)
|
||||
var-name-node
|
||||
(concat
|
||||
(filter some? [docstring-node attr-map-node])
|
||||
fn-body)))
|
||||
let-node (api/list-node
|
||||
(list
|
||||
(api/token-node 'let)
|
||||
(api/vector-node
|
||||
(cond->> nil
|
||||
wrapper-nodes (concat [(:native-fn wrapper-nodes)
|
||||
(api/list-node
|
||||
(list
|
||||
(api/token-node 'fn)
|
||||
arglist-vec
|
||||
arglist-vec))])
|
||||
:always vec))
|
||||
defn-node))]
|
||||
{:node let-node})
|
||||
(catch Exception _
|
||||
(api/reg-finding!
|
||||
{:row (:row (meta node))
|
||||
:col (:col (meta node))
|
||||
:message "Invalid syntax"
|
||||
:type :coffi.ffi/invalid-syntax}))))
|
||||
Loading…
Reference in a new issue