How to match a string literal? #8

Closed
mikebridge opened this Issue Jun 5, 2012 · 4 comments

Comments

Projects
None yet
3 participants

Sorry for the dumb question in the Issues, but I'm not sure how to match a string literal using parsatron---or more generally, how do I easily run an ordered list of parsers against some input?

The let->> macro will allow me to bind a series of parsers if want to explicitly define vars for each of the parsers, and the >> macro will allow me to bind a value to the last of a series of parsers, but I don't see a simple way to create a single value that combines the result of an arbitrary list of parsers (e.g. chars).

I can easily create the ordered token list from the chars, but I don't see how I can run them against a string:

   (map char (seq "mytoken")) 

I must be missing a simple solution....

Cheers!

-Mike

Owner

youngnh commented Jun 14, 2012

Hi! I apologize for the embarrassingly late reply to your question,
but here goes

You are right that you could use let->> combinator to do something
like:

(let->> [s (char \s)
         e (char \e)
         l (char \l)
         e (char \e)
         c (char \c)
         t (char \t)]
  (always (str s e l e c t)))

but if the parser succeeds, we already know what it should return (if
it needs to return anything at all) so there's no real need to bind
the individual characters as we match them. You noted that you could
use >> as well, and here's how I imagine you might do that:

(>> (char \s)
    (char \e)
    (char \l)
    (char \e)
    (char \c)
    (char \t)
    (always "select"))

But those are highly un-reusable.

It looks like you've already figured out how to go from a string to a
seq of char parsers:

(map char "select")

the tricky part is combining them into a single parser that we could
run. It seems like its the job of >> to do that, but its less than
helpful being a macro:

(apply >> (map char "select"))
;; => java.lang.Exception: Can't take value of a macro: #'the.parsatron/>>

But >> is built on a proper fn, nxt. Its only limitation is that
it is not a varargs function. It only takes 2 arguments at a time, so
to combine a bunch of parsers together using it, we have to use
reduce:

(defn kword [s]
  (reduce nxt (map char s)))

And you can verify that it works:

(run (kword "select") "select * from tbl")
;; => "select"

and if you want it to return a semi-useful value:

(defn kword [s]
  (reduce nxt (concat (map char s) (list (always s)))))

Hope that helps!

Contributor

sjl commented Sep 12, 2012

This seems like something that would be handy to have in the core library. Would you take a patch that added it? Perhaps under the name string since that's not used in core Clojure anyway.

Owner

youngnh commented Sep 13, 2012

I would indeed. string would be a good name.

I also apologize for my embarrassingly late response, but thanks for the help!

We all fooled around with parsatron at the local Functional Programming group (hence my question) and it was a good exercise to figure out how to do it. But I agree that in practical terms it would be nice to have this as part of the core.

youngnh closed this in f7e769f Sep 13, 2012

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment