Hi Camillo,
I quickly hacked (with a lot of tests) support for
omit in PetitParser.
This should simplify some parsing efforts as an additional filtering step could be
avoided.
parser := ($" asParser omit, $" asParser negate star flatten, $"
asParser omit)
parser parse: '"asdfsd"' "yields directly #('asdfsd')
"
vs
parser := ($" asParser, $" asParser negate star flatten, $" asParser)
parser parse: '"asdfsd"'
which yields #($" 'asdfsd' $")
I don't really see use of #omit. The element is still in a collection
and you need to extract it from there. What is the benefit other than
it is now at index 1 instead of 2?
Also the implementation has some problems:
1. #omit makes it really hard to compose grammars, because parsers
suddenly get very asymmetric and start to affect each others behavior
depending on how you compose them.
2. For the same reason grammar transformation becomes impossible, one
of the design goals of PetitParser.
3. #omit makes a typical grammar (the smalltalk one) roughly 15%
slower without even using the new feature.
4. There are various methods (#-, #match..., #copy..., ...) that need
to be fixed when you add state to a parser.
5. There is no need for eager (#initialize) as well as lazy
initialization (kills the possibility for a quick invocation).
6. Please do not remove PPParser class>>new and do not change how
initialization works, otherwise you break GemStone, VisualWorks, and
GNU Smalltalk. The Seaside wiki has some nice documentation of how to
correctly initialize objects (basically following the pattern of
Objective-C).
I think, problems 1, 3 (!), 4, 5 and to some extent also 2 could be
solved if the implementation was a bit more object-oriented. That is,
if you added a PPOmitParser that would dispatch from #parseOn: to some
other parsing method #parseOmittedOn: you wouldn't need all those
#ifTrue:ifFalse:.
I pushed my solution to the petitparser repos. I
didn't add full support for flatten.
Did you see #map: and #permutation:? Both allow you do the same in a
less invasive way:
parser := ($" asParser , $" asParser negate star flatten, $" asParser).
parser map: [ :begin :inner :end | inner ]
or
parser := ($" asParser , $" asParser negate star flatten, $" asParser).
parser permutation: #(2)
Additionally, did you see the experimental binding/capturing
functionality in PetitBeta? This kind of provides something much more
general and (I believe) much more powerful without the above
drawbacks. Bind-Capture allows you to bind certain parse results
anywhere down the tree to names and directly access them later on in a
capture block. It also deals with unpacking and reshuffling
collections automatically, check the tests for that.
Your example would look like:
parser := ($" asParser , ($" asParser negate star flatten bind:
#inner) , $" asParser).
parser capture: [ :inner | inner ]
Cheers,
Lukas
--
Lukas Renggli
www.lukas-renggli.ch