Fork me on GitHub
#clj-kondo
<
2023-01-17
>
Alexis Schad11:01:13

Hi there, I wanted to write a hook for defun (https://github.com/killme2008/defun) but it is actually a macro that produces valid clojure code (like all macros I guess?). Is there any way to expand the macro to tell clj-kondo the underlying syntax? How does clj-kondo handle the differences between the original syntax and the transformed one?

borkdude11:01:44

clj-kondo transforms code using the hook and then lints the expanded code

borkdude11:01:01

you can provide a way simpler expansion than the original macro using :analyze-call or :macroexpand just something that clj-kondo understands, e.g. transform the keyword arguments into symbols

borkdude11:01:05

or just one argument _x or so

Alexis Schad14:01:41

Thanks! I don't really care if the transformed version is more complex if I don't have to write it, it seems easier to just use the macro itself but nvm. I did try to figure out how to do this manually, but I'm having a little trouble with recur. Here's the initial syntax:

(defun accum-defun
  ([0 ret] ret)
  ([n ret] (recur (dec n) (+ n ret)))
  ([n] (recur n 0)))
Here is what I produce:
(defn accum-defun [& args#]
  (let [ret (nth args# 1)]
    ret)
  (let [n (nth args# 0)
        ret (nth args# 1)]
    (recur (dec n) (+ n ret)))
  (let [n (nth args# 0)]
    (recur n 0)))
So I got a recur error: recur argument count mismatch (expected 1, got 2)" I can replace all underlying recur to the function name but I have to manage nested loop/fn in recursion. Is there an easier way or am I doing it right?

Alexis Schad14:01:51

It seems to work like that, just checked for 'fn or 'loop to stop recursion if it is the value of the first child of a list node

borkdude15:01:14

if you have a varargs function, recur only takes 1 argument

escherize19:01:45

Is there a kondo hook for schema.core/defn? I’m looking through https://github.com/metosin/malli/blob/master/resources/clj-kondo/clj-kondo.exports/metosin/malli/config.edn#L1, and I can’t figure out where the schema.core/defn hook comes from. I thought they’d be in https://github.com/plumatic/schema/blob/master/resources/clj-kondo.exports/prismatic/schema/config.edn but it isnt there

borkdude19:01:17

This is built into clj-kondo

borkdude19:01:33

This predates hooks

escherize19:01:45

How hard would it be to adapt this for malli.experimental/defn ?

borkdude19:01:00

you can use :lint-as right?

borkdude19:01:54

I see. Are you working at metabase?

escherize19:01:05

mu/defn has same shape as malli.experimental/defn. I am

borkdude19:01:26

I think it might be better if malli got dedicated hooks if the lint-as no longer works

escherize19:01:18

I think that’d be awesome

escherize19:01:04

as it is, malli is linting mx/defn as schema.core/defn. I am not sure but that may break too. https://github.com/metosin/malli/blob/master/resources/clj-kondo/clj-kondo.exports/metosin/malli/config.edn#L1

borkdude19:01:18

So this will be a PR to metosin/malli then in their exported hooks. I think opening an issue with them would be best and I can help where needed. I also work for metabase on clj-kondo issues sometimes, so if this is a priority I can also do this under "their" time as well. cc @U11BV7MTK

👍 2
Sam Ritchie20:01:16

odd… I tried to put a println in my macro hook so bb lint would kick out some info (just (prn "cake")` ) and triggered this

[sritchie@wintermute ~/code/clj/mafs.cljs (main)]$ bb lint
#error {
 :cause "long overflow"
 :via
 [{:type java.lang.ArithmeticException
   :message "long overflow"
   :at [java.lang.Math multiplyExact "Math.java" 949]}]
 :trace
 [[java.lang.Math multiplyExact "Math.java" 949]
  [clojure.lang.Numbers multiply "Numbers.java" 1971]
  [bencode.core$read_long invokeStatic "core.clj" 128]
  [bencode.core$read_netstring_STAR_ invokeStatic "core.clj" 153]
  [bencode.core$read_token invokeStatic "core.clj" 245]
  [bencode.core$read_bencode invokeStatic "core.clj" 253]
  [babashka.pods.impl$read invokeStatic "impl.clj" 25]
  [babashka.pods.impl$processor$fn__30883 invoke "impl.clj" 169]
  [babashka.pods.impl$processor invokeStatic "impl.clj" 169]
  [babashka.pods.sci$load_pod$fn__31056 invoke "sci.clj" 121]
  [sci.impl.vars$binding_conveyor_fn$fn__337 invoke "vars.cljc" 129]
  [clojure.core$binding_conveyor_fn$fn__5823 invoke "core.clj" 2047]
  [clojure.lang.AFn call "AFn.java" 18]
  [java.util.concurrent.FutureTask run "FutureTask.java" 264]
  [java.util.concurrent.ThreadPoolExecutor runWorker "ThreadPoolExecutor.java" 1128]
  [java.util.concurrent.ThreadPoolExecutor$Worker run "ThreadPoolExecutor.java" 628]
  [java.lang.Thread run "Thread.java" 829]
  [com.oracle.svm.core.thread.PlatformThreads threadStartRoutine "PlatformThreads.java" 704]
  [com.oracle.svm.core.posix.thread.PosixPlatformThreads pthreadStartRoutine "PosixPlatformThreads.java" 202]]}

Sam Ritchie20:01:37

here’s my lint task

borkdude20:01:38

try printing to stderr instead

Sam Ritchie20:01:49

like this?

(binding [*out* *err*]
      (println "cake"))

Sam Ritchie20:01:56

that can’t be right since I get

src/mafs/plot.cljs:45:1: error: sci.impl.vars.SciUnbound cannot be cast to java.io.Writer

Sam Ritchie20:01:16

anyway it works fine if I don’t use the babashka version, but use the cli clj-kondo … for now I will just debug that way

borkdude20:01:20

Feel free to post an issue about this.

borkdude20:01:33

One should be able to print to stderr in hooks :)

borkdude19:01:11

@U017QJZ9M7W I found a workaround that works with the current clj-kondo:

(def err *err*)

(defn new [{:keys [node]}]
  (binding [*out* err]
    (prn "ERRRRR"))
  (api/reg-finding! (assoc (meta node)
                           :message (str "Interop is no good! " (api/generated-node? (first (:children node))))
                           :type :interop)))
So capture *err* in the top level and then use it at "run time"

❤️ 2
borkdude19:01:24

I'll fix it the proper way though