TL;DR; - As a rule Parslet's as
applied to repeat
captures an array of matches; except in the special case where all the matches are raw strings, in which case it joins them and returns the resulting string.
In your code, the repeat
doesn't know the types it would capture as there aren't any, so it returns the empty array.
In this example... the empty array seems like the right choice.
require 'parslet'
class Parser < Parslet::Parser
rule(:quote) { str('"') }
rule(:escape_char) { str('\\') }
def quoted(term)
quote >> term >> quote
end
rule(:string) {
quoted( (escape_char >> any | quote.absent? >> any).as(:char).repeat.as(:string) )
}
end
puts Parser.new.string.parse('""').inspect # => {:string=>[]}
puts Parser.new.string.parse('"test"').inspect
# => {:string=>[{:char=>"t"@1}, {:char=>"e"@2}, {:char=>"s"@3}, {:char=>"t"@4}]}
When the child nodes are just strings Parslet concatenates then into a single string. When there are no elements in the collection it defaults to empty collection instead of empty string.
maybe
is different.
From http://kschiess.github.io/parslet/parser.html # Repetition and its Special Cases
These all map to Parslet::Atoms::Repetition. Please note this little
twist to #maybe:
str('foo').maybe.as(:f).parse('') # => {:f=>nil}
str('foo').repeat(0,1).as(:f).parse('') # => {:f=>[]} The
‘nil’-value of #maybe is nil. This is catering to the intuition that
foo.maybe either gives me foo or nothing at all, not an empty array.
But have it your way!