Fork me on GitHub
#clj-kondo
<
2020-06-01
>
borkdude07:06:26

@didibus No, E.g. the weird-macro example is similar to jdbc’s with-connection while the clj-kondo macro just expands into constructs that are known but is much simpler

borkdude07:06:27

One other point is that clj-kondo has to deal with partial information. So it doesn’t go looking for namespaces elsewhere and find that macro for you

dominicm16:06:31

@borkdude have you tried core.match yet? I think that's the killer example for it.

borkdude16:06:45

I haven't yet, but that's a good one

dominicm16:06:46

@borkdude is it possible to mark a macro expansion as allowing unused variables? Consider an anaphoric macro like proxy(?) where this is bound, but possibly not used.

borkdude16:06:08

@dominicm Do you ask this in relation to the new macroexpand feature or in general?

dominicm16:06:44

The new macro expansion feature

borkdude16:06:20

I remember fixing something for proxy-super (https://github.com/borkdude/clj-kondo/commit/0cf0f2933d277c7986620bf31a8caca31c0e68af) But if you're implementing a stand-in macro, then you can just emit this so it will be linted as used.

dominicm16:06:44

Heh, that's true. Hmm. Might be an option then :)

snoe17:06:25

@borkdude that new macroexpansion feature looks great! I left some example macros that I've run across that might be useful to evaluate

seancorfield17:06:25

Catching up on this thread from yesterday/earlier... So the idea is that you provide, essentially, a dumbed-down version of arbitrary macros in the config so that clj-kondo is better able to parse code and issue correct warnings?

seancorfield17:06:38

The example shows it as text that is passed to SCI to evaluate -- would it be better to provide a (quoted) form instead so that folks writing these things can get code assist/syntax checking on the alternative macro definitions?

seancorfield17:06:19

(but, yeah, looks very interesting -- and certainly SCI has allowed Chlorine to do amazing stuff, in user-land, to extend the functionality so the overall approach is sound)

borkdude17:06:31

@seancorfield Yes, you provide dumbed down version to teach clj-kondo about the syntax. The reason the code is not quoted is that this is supposed to be part of your .clj-kondo/config.edn and in EDN you can't use arbitrary code (not even quotes).

borkdude17:06:46

I'm still thinking about a way to refer to another file in that config.

borkdude17:06:39

I've been considering reader tags to refer to other files, but I want something that can work in both .edn files and as metadata. Reader tags can break people's code.

seancorfield17:06:46

Ah, good point about EDN not being code-sufficient. What Chlorine did was to have the config be .cljs and treat the whole file as SCI-consumable.

seancorfield17:06:21

(that's harder for kondo which traffics in (unquoted) symbols tho')

borkdude17:06:09

That works, but I want the code for each macro to be readable separately, as to not eval all macro stuff if only some of it is needed for linting e.g. one file

borkdude17:06:07

right now I have this:

{:macroexpand {foo/bar "foo/bar.clj"}}
which looks in .clj-kondo/foo/bar.clj for the macro

4
borkdude18:06:04

@snoe Did one more test. better-cond, only tested the :let construction:

(ns foo
  {:clj-kondo/config '{:macroexpand {better.cond/cond
                                     "
(defn process-pairs [pairs]
  (loop [[[lhs rhs :as pair] & pairs] pairs
         new-body ['cond]]
    (if pair
      (cond
        (= 1 (count pair)) (seq (conj new-body lhs))
        (not (keyword? lhs))
        (recur pairs
               (conj new-body lhs rhs))
        (= :let lhs)
        (seq (conj new-body :else (list 'let rhs
                                       (process-pairs pairs)))))
      (seq new-body))))

(def f
  (fn [{:keys [:sexpr]}]
    (let [expr (let [args (rest sexpr)
                     pairs (partition-all 2 args)]
                 (process-pairs pairs))]
      {:sexpr (with-meta expr
                (meta sexpr))})))"}}}
  (:require [better.cond :as b]))

(let [x 10]
  (b/cond
    (= x 1) true
    :let [y (inc x)]      ;; binding is recognized
    (= 11 y) (subs y 0))) ;; yay, type error because y is not a string

borkdude18:06:58

I'm pretty sure more sophisticated things can be linted, as long as you're willing to provide the stand-in macro

snoe18:06:30

that's awesome stuff - I think my dsl approach worked for "regular" looking macros a bit better than the lint-as but this is clearer and more generally applicable.

borkdude18:06:22

I'll add this to the unit tests 🙂