better-monad-parse.el to my github repository. This is
a refactoring of
monad-parse, principally to make its interface more
regular and grokable. It also is more intellegently polymorphic over
different kinds of parseable objects, principally by making use of my
implementation of multimethods instead of EIEIO, which, as far as I'm
able to ascertain, doesn't allow method dispatch on built-in classes.
Unfortunately, its a bit slow, even compiled. I'd love to have advice on how it might be sped up, although I'm thinking its a lost cause - this kind of programming might be too taxing for Emacs Lisp.
This library follows the following conventions.
- Parsers are functions which accept a generic input state and
return a list of cons cells, where the
caris the monadic return value and the
cdris the unparsed input.
- All parsers defined by the library start with the symbol
- Parsers are often parameterized, that is, a parser will be
created based on some value passed to a function. Functions
which produce parsers begin with the symbol
=>, eg: =>string, =>items, =>or, =>and and so forth.
New parsers should be most easily created with the
form, which introduces a monadic expression context for parser
(parser (n <- =number) (letters <- (=>zero-plus-more =alpha)) (m-return (list n letters)))
Produces a parser which binds n to a number parsed from the input, and then binds letters to a list of zero or more letters parsed from the input. All the parses defined by the library are generic, so they can parse buffers, strings or lists. There is a rich vocabulary of parsers to combine in the library, but if you wish to write your own generic parsers, you'll need to create a multimethod to cover all input types.
Understanding mulitmethods is also critical if you want to extend the parser library to cover additional input types.
This library is all about defining parsers, so there are special forms for that purpose:
(defparser =number-then-letters (n <- =number) (letters <- (=>zero-plus-more =alpha)) (m-return (list n letters)))
=number-then-letters symbol and function value to the parser
produced by the body expression evaluated in the parser monad. This
allows you to call the parser as a function and also refer to it as a
variable, since both actions are common.
defparser allows the creation of parametric parsers too:
(defparser (=>specific-number-then-letters n) (n-parsed <- =number) (if (= n n-parsed) (parser (letters <- (=>zero-plus-more =alpha)) (m-return n letters)) =nil))
defun's a function which produces the indicated parser. Arguments
are automatically lexically closed over. This version doesn't set the
symbol-value of the name.
As stated above, the library performance is a bit slow still - I haven't determined to what that slowness owes, but I recommend byte-compiling everything.
I'm almost certainly going to port this whole thing to Common Lisp at some point, so I can call out to it via slime. That should help with performance, as I have a nagging feeling that the bottleneck is my ad-hoc multimethod dispatch.