Clojure: How do I get the file/line number on which a map was defined?

1.6k views Asked by At

I know I can get the :line and :file from the metadata on a var; however, I'm building a system where the user can pass me raw maps and I will end up "linking" the data together at a later time. When this linkage fails, I'd like to report the file/line in which they specified the map. E.g.:

 (defn generate-stuff []
    (make-thing { :k (make-thing { :k v }) }))

 (link (generate-stuff) (other-generator))
 ;; outputs file/line of the map containing the errant :k/v pair

I assume that writing a macro to associate file/line with the collection's metadata is almost certainly the way to go, but since there isn't any "var" to look at, I'm not sure where to get the line number. I see the definition of get-line-number, but it requires a reader, and while I can find all of the special readers and the *default-data-reader-fn* data reader (which is nil), I cannot seem to figure out how to access the "code" reader.

1

There are 1 answers

0
Tony K. On

OK, it looks like using &form in a macro is the answer. I wrote the following bit of generic test code, and it seems to work:

(defmacro make-thing [obj]
  (let [f *file*]
    (with-meta obj (assoc (meta &form) :file f))))

The &form refers to the form that invoked the macro, and it has metadata for line/column. The special var file has the relative path of the source file. So, combining the two into the metadata onto the object results in the desired result.