How can I execute custom tag readers in different order in Clojure EDN

417 Views Asked by At

I have a following EDN file

:abc #request/builder/abc {
    "def" #request/builder/def {
          "someVector" ["sample1", "sample2"]
    }
}

I have defined custom tag reader in Clojure, which internally calls java code

(defn custom-readers []
    {
        #request/builder/def defBuilder
        #request/builder/abc abcBuilder
    }
)

(defn defBuilder [params]
    (.defBuilder (someJavaUtilityClass.) params)
)

(defn abcBuilder [params]
    (.abcBuilder (someJavaUtilityClass.) params)
)

When I read EDN using edn/read-string, defBuilder executes first and its value gets passed to abcBuilder.

I want to reverse the order of execution without modifying EDN. I want to modify abcBuilder code such that if java call in abcBuilder returns some value then only execute defBuilder. How can I achieve this.

I tried by modifying code as below

(defn defBuilder [params]
    '(.defBuilder (someJavaUtilityClass.) params)
)

(defn abcBuilder [params]
    if((.abcBuilder (someJavaUtilityClass.) params)
       (eval (get params "def"))
    )
)

But this throws error like it "Unable to resolve someJavaUtilityClass and params". Is there a better way to solve this?

1

There are 1 best solutions below

0
On

I'm afraid that's not possible. That isn't how EDN's tagged literals work. The tag handler is called after reading the form, which includes calling the tag handlers for any tagged literals in the form. In other words, the tag handlers are called inside-out.

If this weren't the case, then what a tag means will depend on where that tagged literal is situated, which is needlessly context dependent.

Check out: https://github.com/edn-format/edn#tagged-elements

Here's the relevant part:

Upon encountering a tag, the reader will first read the next element (which may itself be or comprise other tagged elements), then pass the result to the corresponding handler for further interpretation, and the result of the handler will be the data value yielded by the tag + tagged element, i.e. reading a tag and tagged element yields one value.

Also check out: https://clojure.org/reference/reader#tagged_literals

This is about the Clojure reader. And again, here is the relevant bit:

by invoking the Var #'my.project.foo/bar on the vector [1 2 3]. The data reader function is invoked on the form AFTER it has been read as a normal Clojure data structure by the reader.

Also, symbols can only contain one /, delimiting the namespace and the name. Check out: https://github.com/edn-format/edn#symbols