librelist archives

« back to archive

.repeat(0,1) != .maybe

.repeat(0,1) != .maybe

From:
David Jenkins
Date:
2011-10-17 @ 18:55
Hi,

First, just want to say thank you for writing "Parslet", I don't know what
I'd do without it!
Now, on to the grim business at hand... ;)

According to the doc,

Matching something once or not at all can be achieved by repeat(0,1), but
also through the prettier:
        str('foo').maybe          # same as str('foo').repeat(0,1)

(http://kschiess.github.com/parslet/parser.html)

But the following yields different results depending on whether I use
".repeat(0,1)" or ".maybe".  In the line with the comment " #### THIS LINE
####, using ".repeat(0,1)" exits the code (maybe_test.rb, at bottom) without
an error; but if the ".repeat(0,1)" is changed to ".maybe", I get

/home/jenko/Ruby/query_engine/maybe_test.rb:9:in `<top (required)>': private
method `eval' called for #<Hash:0x00000001f75bb0> (NoMethodError)
 from -e:1:in `load'
from -e:1:in `<main>'

I chopped this down from my original project as much as I could.

Thank you!

PS, Here are the repro files:

#myparser.rb:
require 'parslet'

class MiniP < Parslet::Parser
  rule(:comma)      { str(',') >> space? }
  rule(:space)      { match('\s').repeat(1) }
  rule(:space?)     { space.repeat(0,1) }
  rule(:digit) { match("[0-9]") }
  rule(:integer) {
      ((str('+') | str('-')).repeat(0,1) >> digit.repeat(1)).as(:int) >>
space? #### THIS LINE ####
    }

  rule(:offset_params) { (integer >> (comma >>
expression).repeat(0,1).as(:offset_params) }
  rule(:expression){
  offset_params
}
  root :expression
end
========================================================
#mytransform.rb
require 'parslet'
require './myparser.rb'

class IntExp < Struct.new(:int)
def eval; int.to_i; end
end

class OffsetParamsExp  < Struct.new(:offset_params)
 def eval
offset_params.map do |s|
if s.class == Parslet::Slice
 s.to_s.to_i
      else
s.eval
end
 end
end
end

class MiniT < Parslet::Transform
 rule(:int => simple(:int))                                          {
IntExp.new(int) }
rule(:offset_params => sequence(:offset_params)) {
OffsetParamsExp.new(offset_params) }
 rule(:offset_params => simple(:offset_params)) {
OffsetParamsExp.new(offset_params) }
end
========================================================
#maybe_test.rb
require 'parslet'
require './myparser.rb'
require './mytransform.rb'

  @minip = MiniP.new
  @transf = MiniT.new
  tree = @minip.parse("-3,1")
  ast = @transf.apply(tree)
  result = ast.eval

Re: .repeat(0,1) != .maybe

From:
Kaspar Schiess
Date:
2011-10-18 @ 07:41
Hi David,

> First, just want to say thank you for writing "Parslet", I don't know what
> I'd do without it!
Appreciated ;)

> But the following yields different results depending on whether I use
> ".repeat(0,1)" or ".maybe".

Yes. I've now documented this for the first time. #repeat will mostly 
produce strings and arrays, also in the case where it doesn't match at 
all. #maybe on the other hand produces strings or nils. This is on purpose.

Does this help make sense out of the error messages you get? (The #eval 
isn't mine, it's yours ;))

regards,
kaspar

Re: [ruby.parslet] Re: .repeat(0,1) != .maybe

From:
David Jenkins
Date:
2011-10-18 @ 15:21
>Does this help make sense out of the error messages you get?

Indeed!

Thanks again.

David


On Tue, Oct 18, 2011 at 3:41 AM, Kaspar Schiess <eule@space.ch> wrote:

> Does this help make sense out of the error messages you get? (The #eval
> isn't mine, it's yours ;))
>