@sova Once your query has been parsed from a string into data (that's usually the hard part), you can use whatever strategy you want to actually evaluate it. insta/transform
is meant to be just one tool in your toolbelt to serve the most common case.
I think this is the transform example you were referring to:
=> (->> (arithmetic "1-2/(3-4)+5*6")
(insta/transform
{:add +, :sub -, :mul *, :div /,
:number clojure.edn/read-string :expr identity}))
33
In this case it isn't replacing :add
with +
, it's actually calling +
on all of the elements that come after :add
. So as the transformer works its way up the tree, it ends up evaluating the whole expression.
Does that explanation help?
wow! that is very cool, it's calling +
... this explanation is very helpful, it gives me a really strong starting point,
but i'm still not sure how i can end up with a thing i can test logicals on.
since i could replace different nodes with whatever function i see fit, there's a lot of power there,
but i gotta end up with something that i could pour "lemon juice" through and if the internal
query expression was ("lemon" | "momo") & "juice" ... it would work.
do you have any ideas on transforming nodes into logic gates?
okay, you mention that it works its way up the tree so presumably it starts at the leaves... so if on matching leaves we write down "true" and non matching leaves we write "false" and then eventually do an eval on the whole thing, it'll be like getting a truth statement back.
Thanks for taking the time to explain that, by the way.
Found this channel in #beginners and I just wanna say: @aengelberg thank you for the great library, it saved me multiple times from DSL hell 😊
thanks @akiroz, glad you are finding it useful
@sova yeah your true/false strategy should work. insta/transform
is a recursive function, and whenever it's processing a node it transforms all of the children first, hence the "leaves first" approach.
you can take a look at the source code of insta/transform
. It has some boilerplate to make sure it works on instaparse's various output formats, but at its core it's a fairly simple depth-first iterator.
https://github.com/Engelberg/instaparse/blob/master/src/instaparse/transform.cljc#L33-L46
the super-simplified version of the logic looks like this:
(defn- hiccup-transform
[transform-map parse-tree]
(if (not (empty? parse-tree))
(let [transform (transform-map (first parse-tree))]
(apply transform (map (partial hiccup-transform transform-map)
(next parse-tree))))
parse-tree))
Cool! Thanks very much for providing source and also zooming in on the vital part.
So the (partial ..) function ... could you tell me more about how that comes into play?
partial
is a function built-in to Clojure that helps curry arguments in anonymous functions http://clojuredocs.org/clojure.core/partial