Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Some clj-kondo support #9

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions src/clj/new/clj_template.clj
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,31 @@

(with-bindings {#'clj.new.templates/*force?* force
#'clj.new.templates/*dir* dir}
(file-map->files
data
{"deps.edn" (render "deps.edn" data)
(format "src/%s/%s.clj" (:base data) (:suffix data)) (render "core.clj" data)
(format "src/%s/python.clj" (:base data)) (render "python.clj" data)}))))
(let [lpc-path ".clj-kondo/configs/libpython-clj"
tp-path ".clj-kondo/configs/tech.parallel"]
(file-map->files
data
{"deps.edn" (render "deps.edn" data)
(format "src/%s/%s.clj" (:base data) (:suffix data)) (render "core.clj" data)
(format "src/%s/python.clj" (:base data)) (render "python.clj" data)
;; clj-kondo hooks related
".clj-kondo/config.edn"
(render ".clj-kondo/config.edn" data)
;; libpython_clj
(str lpc-path "/config.edn")
(render (str lpc-path "/config.edn") data)
(str lpc-path "/hooks/libpython_clj/jna/base/def_pylib_fn.clj")
(render (str lpc-path "/hooks/libpython_clj/jna/base/def_pylib_fn.clj") data)
(str lpc-path "/hooks/libpython_clj/require/import_python.clj")
(render (str lpc-path "/hooks/libpython_clj/require/import_python.clj") data)
;; tech.parallel
(str tp-path "/config.edn")
(render (str tp-path "/config.edn") data)
(str tp-path "/hooks/tech/parallel/utils/export_symbols.clj")
(render (str tp-path "/hooks/tech/parallel/utils/export_symbols.clj") data)})))))


(defn clj-template
(defn clj-template
([name] (libpython-clj-template! name))
([name & args] (clj-template name)))

Expand Down
3 changes: 3 additions & 0 deletions src/clj/new/libpython_clj/.clj-kondo/config.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
:config-paths ["configs/libpython-clj" "configs/tech.parallel"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
:hooks
{:analyze-call {libpython-clj.jna.base/def-pylib-fn
hooks.libpython-clj.jna.base.def-pylib-fn/def-pylib-fn
libpython-clj.require/import-python
hooks.libpython-clj.require.import-python/import-python}}
:linters {:unused-namespace {:exclude [builtins.list
builtins.dict
builtins.set
builtins.tuple
builtins.frozenset
builtins.str
builtins]}}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
;; XXX: work on export-symbols from tech.parallel.utils?
(ns hooks.libpython-clj.jna.base.def-pylib-fn
"The def-pylib-fn macro from libpython-clj/jna/base.clj"
(:require [clj-kondo.hooks-api :as api]))

;; from: libpython-clj/jna/base.clj

;; (defmacro def-pylib-fn
;; [fn-name docstring rettype & argpairs]
;; `(defn ~fn-name
;; ~docstring
;; ~(mapv first argpairs)
;; (when-not (== (current-thread-id) (.get ^AtomicLong gil-thread-id))
;; (throw (Exception. "Failure to capture gil when calling into libpython")))
;; (let [~'tvm-fn (jna/find-function ~(str fn-name) *python-library*)
;; ~'fn-args (object-array
;; ~(mapv (fn [[arg-symbol arg-coersion]]
;; (when (= arg-symbol arg-coersion)
;; (throw (ex-info (format "Argument symbol (%s) cannot match coersion (%s)"
;; arg-symbol arg-coersion)
;; {})))
;; `(~arg-coersion ~arg-symbol))
;; argpairs))]
;; ~(if rettype
;; `(.invoke (jna-base/to-typed-fn ~'tvm-fn) ~rettype ~'fn-args)
;; `(.invoke (jna-base/to-typed-fn ~'tvm-fn) ~'fn-args)))))

;; called like:

;; (def-pylib-fn PyImport_AddModule
;; "Return value: Borrowed reference.
;;
;; Similar to PyImport_AddModuleObject(), but the name is a UTF-8 encoded string instead
;; of a Unicode object."
;; Pointer
;; [name str])

(defn def-pylib-fn
"Macro in libpython-clj/jna/base.clj.

Example call:

(def-pylib-fn PyImport_AddModule
\"Return value: Borrowed reference.

Similar to PyImport_AddModuleObject(), but the name is a UTF-8 ...
of a Unicode object.\"
Pointer
[name str])

This has the form:

(def-pylib-fn fn-name docstring rettype & argpairs)

May be treating it as:

(defn fn-name
[arg1 arg2 ,,, argn]
[arg1 arg2 ,,, argn]) ; fake usage of args?

where arg1, ..., argn are extracted from argpairs is acceptable.

XXX: using the second elements of argpairs might be worth doing
to avoid unused warnings.

"
[{:keys [:node]}]
(let [[_ fn-name _ _ & argpairs] (:children node)
pairs (map (fn [vec-node]
(let [[an-arg a-type] (:children vec-node)]
[an-arg a-type]))
argpairs)
new-node (with-meta (api/list-node
(apply concat
[(api/token-node 'defn)
fn-name
(api/vector-node (map first pairs))]
pairs))
(meta node))]
;; XXX: uncomment following and run clj-kondo on cl_format.clj to debug
;;(prn (api/sexpr node))
;;(prn (api/sexpr new-node))
{:node new-node}))
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
(ns hooks.libpython-clj.require.import-python
"The import-python macro from libpython-clj/require.clj"
(:require [clj-kondo.hooks-api :as api]))

;; from: libpython-clj/require.clj

;; (defn import-python
;; "Loads python, python.list, python.dict, python.set, python.tuple,
;; and python.frozenset."
;; []
;; (require-python
;; '(builtins
;; [list :as python.list]
;; [dict :as python.dict]
;; [set :as python.set]
;; [tuple :as python.tuple]
;; [frozenset :as python.frozenset]
;; [str :as python.str])
;; '[builtins :as python])
;; :ok)

;; alternative:
;;
;; (require
;; (quote [builtins.list :as python.list])
;; (quote [builtins.dict :as python.dict])
;; (quote [builtins.set :as python.set])
;; (quote [builtins.tuple :as python.tuple])
;; (quote [builtins.frozenset :as python.frozenset])
;; (quote [builtins.str :as python.str])
;; (quote [builtins :as python]))

(defn make-require
[ns-sym alias-sym]
(api/list-node
[(api/token-node 'require)
(api/list-node
[(api/token-node 'quote)
(api/vector-node
[(api/token-node ns-sym)
(api/keyword-node :as)
(api/token-node alias-sym)])])]))

(defn import-python
"Macro in libpython-clj/require.clj.

Example call:

(import-python)

May be treating it as:

(do
(require (quote [builtins.list :as python.list]))
(require (quote [builtins.dict :as python.dict]))
,,,
)

"
[{:keys [:node]}]
(let [new-node
(with-meta (api/list-node
[(api/token-node 'do)
(make-require 'builtins.list 'python.list)
(make-require 'builtins.dict 'python.dict)
(make-require 'builtins.set 'python.set)
(make-require 'builtins.tuple 'python.tuple)
(make-require 'builtins.frozenset 'python.frozenset)
(make-require 'builtins.str 'python.str)
(make-require 'builtins 'python)])
(meta node))]
;; XXX: uncomment following and run clj-kondo on cl_format.clj to debug
;;(prn (api/sexpr node))
;;(prn (api/sexpr new-node))
{:node new-node}))
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
:hooks {:analyze-call {tech.parallel.utils/export-symbols
hooks.tech.parallel.utils.export-symbols/export-symbols}}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
(ns hooks.tech.parallel.utils.export-symbols
"The export-symbols macro from tech/parallel/utils.clj"
(:require [clj-kondo.hooks-api :as api]))

;; from: tech/parallel/utils.clj

;; (defmacro export-symbols
;; [src-ns & symbol-list]
;; `(do
;; (require '~src-ns)
;; ~@(->> symbol-list
;; (mapv
;; (fn [sym-name]
;; `(let [varval# (requiring-resolve (symbol ~(name src-ns)
;; ~(name sym-name)))
;; var-meta# (meta varval#)]
;; (when (:macro var-meta#)
;; (throw
;; (ex-info
;; (format "Cannot export macros as this breaks aot: %s"
;; '~sym-name)
;; {:symbol '~sym-name})))
;; (def ~(symbol (name sym-name)) @varval#)
;; (alter-meta! #'~(symbol (name sym-name))
;; merge
;; (select-keys var-meta#
;; [:file :line :column
;; :doc
;; :column :tag
;; :arglists]))))))))

(defn export-symbols
"Macro in tech/parallel/utils.clj.

Example call:

(export-symbols libpython-clj.jna.base
find-pylib-symbol
as-pyobj
ensure-pyobj)

This has the form:

(export-symbols ns-name var-name-1 var-name-2 ... var-name-n)

May be treating it as:

(do
(def var-name-1 ns-name/var-name-1)
(def var-name-2 ns-name/var-name-2)
,,,
(def var-name-n ns-name/var-name-n))

is acceptable.

Thanks lread :)

"
[{:keys [:node]}]
(let [[_ ns-node & var-nodes] (:children node)
new-node (api/list-node
(conj
(doall
(for [var-node var-nodes
:let [var-sym (api/sexpr var-node)
var-fq (str (api/sexpr ns-node) "/" var-sym)]]
(with-meta
(api/list-node
[(api/token-node 'def)
(api/token-node (symbol var-sym))
(api/token-node (symbol var-fq))])
(meta var-node))))
(api/token-node 'do)))]
;; XXX: uncomment following and run clj-kondo on cl_format.clj to debug
;;(prn (api/sexpr node))
;;(prn (api/sexpr new-node))
{:node new-node}))