Okay, sorry I don't have time/ability to create a minimal reproduction 
case, but here's my whole thing.

1) The whole grammar that reveals the problem. 2) the string input that 
will reveal the problem. 3) The rule change (adding an .as() ) that 
cures it.

As an aside, I have gotten the feeling writing this code that I'm not 
using .as() quite as you intended; but I couldn't quite wrap my head 
around how you intended with my use case, and the way I'm doing is 
working out well for my brain and use case.

And in fact I think the change I made _was_ neccesary for me to get 
output I could deal with properly; but perhaps the pre-change version 
still shouldn't have raised, or should have raised a more clear exception.

**
1. Original grammar revealing the problem
**
class AdvParser < Parslet::Parser
   root :query

   # query is actually a list of expressions.
   rule :query do
     (spacing? >>  (expression | paren_unit ) >> spacing?).repeat
   end

   rule :paren_list do
     (str('(') >> (spacing? >> unary_expression >> spacing?).repeat >> 
str(')'))
   end

   rule :paren_unit do
     (str('(') >> spacing? >> (expression ) >> spacing? >> str(')')) |
       paren_list
   end

   # Note well: It was tricky to parse the thing we want where you can
   # have a flat list with boolean operators, but where 'OR' takes 
precedence.
   # eg "A AND B OR C AND C" or "A OR B AND C OR D". Tricky to parse at all,
   # tricky to make precedence work. Important things that seem to make 
it work:
   # and_list comes BEFORE or_list in :expression.
   # and_list's operand can be an or_list, but NOT vice versa
   rule :expression do
     (and_list | or_list | unary_expression )
   end

   rule :and_list do
     ((or_list | unary_expression | paren_unit) >>
       (spacing >> str("AND") >> spacing >> (or_list | unary_expression 
| paren_unit)).repeat(1)).as(:and_list)
   end

   rule :or_list do
     ((unary_expression | paren_unit) >>
     (spacing >> str("OR") >> spacing >> (unary_expression | 
paren_unit)).repeat(1)).as(:or_list)
   end

   rule :unary_expression do
     (str('+') >> (phrase | token)).as(:mandatory) |
     (str('-') >> (phrase | token)).as(:excluded) |
     (str('NOT') >> spacing? >> (unary_expression | 
paren_unit)).as(:not_expression) |
     (phrase | token)
   end

   rule :token do
     match['^ ":)('].repeat(1).as(:token)
   end
   rule :phrase do
     match('"') >> match['^"'].repeat(1).as(:phrase) >> match('"')
   end


   rule :spacing do
     match[' '].repeat(1)
   end
   rule :spacing? do
     spacing.maybe
   end
end


**

2. Input string
**
(one two three) AND (four five six)
**

3. Change this rule adding an 'as', all is well again.
**
   rule :paren_list do
     (str('(') >> (spacing? >> unary_expression >> spacing?).repeat >> 
str(')')).as(:list)
   end
**


On 3/15/2011 5:11 AM, Kaspar Schiess wrote:
> On 15.03.11 00:37, Jonathan Rochkind wrote:
>> Hmm, weirdly that seemed to be caused not by the parse rules themselves,
>> but by the as(:label)s I added to them. Adding an _additional_
>> .as(:label) in a certain place somehow solved this, I can't explain it.
>> I could give you my entire complicated parser, but I don't expect anyone
>> else to try and understand it.
> Hei Jonathan,
>
> I would sure like to try and understand it ;). And I guess we might find
> the mindshare of others as well. Can you post a sample that exposes this
> error? Even if it is not minimal, there might be a bug lurking in there!
>
> kaspar
>
>
>

Reply via email to