instaparse

If you're not trampolining your parser, why bother getting up in the morning?
aengelberg 2018-05-22T14:49:47.000256Z

aengelberg 2018-05-22T14:50:55.000801Z

@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.

aengelberg 2018-05-22T14:52:55.000211Z

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

aengelberg 2018-05-22T14:54:06.000222Z

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.

aengelberg 2018-05-22T14:56:17.000141Z

Does that explanation help?

sova-soars-the-sora 2018-05-22T14:59:56.000676Z

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?

sova-soars-the-sora 2018-05-22T15:01:40.000132Z

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.

sova-soars-the-sora 2018-05-22T15:02:58.000598Z

Thanks for taking the time to explain that, by the way.

2018-05-22T21:07:56.000621Z

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 😊

aengelberg 2018-05-22T21:09:25.000166Z

thanks @akiroz, glad you are finding it useful

aengelberg 2018-05-22T21:12:24.000225Z

@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.

aengelberg 2018-05-22T21:13:12.000445Z

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.

aengelberg 2018-05-22T21:18:18.000028Z

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))

sova-soars-the-sora 2018-05-22T21:32:53.000138Z

Cool! Thanks very much for providing source and also zooming in on the vital part.

sova-soars-the-sora 2018-05-22T21:34:39.000561Z

So the (partial ..) function ... could you tell me more about how that comes into play?

aengelberg 2018-05-22T21:45:32.000616Z

partial is a function built-in to Clojure that helps curry arguments in anonymous functions http://clojuredocs.org/clojure.core/partial