but this isn't a DSL in the "in the language" sense, it's just a string. I like EBNF a lot too, I think writing (| A B) is not that much worse than writing "A | B" in clojure, but that you get the advanatages of manipulating a language-level object instead of an opaque string.
Let's not forget that string-based programming is the source of many many bugs
I also think this string format is the right default choice, since most of the time I'm building parsers that don't change or need to be built programmatically.
But Instaparse has exposed all the functionality as an "in the language" DSL as well using parser combinators in a map structure (near the bottom of the README).
You can also turn a string specification into a grammar map/combinator specification, which I have used when a part of my parser was generated at run time.
> Let's not forget that string-based programming is the source of many many bugs
Since the parser generator compiles the EBNF into an executable function at runtime. The solution is the same as writing code in Ruby, JavaScript, or any other dynamic language. Write a unit test.
The name you want for "in the language" is EDSL: Embedded DSL. DSL is quite often used for library-level constructs but really, any concrete syntax (e.g. graphviz's dot format) is a DSL.
EBNF is a DSL.
I happen to like it more than many apis because of it's history, stability, and my experience with it. But, that's an opinion.