Search code examples
rubyparslet

Simple parslet parser for comma-delimited list does not work


Why does the following Parslet parser not work for parsing comma-delimited lists? When I parse, it gets stuck and does not provide an error message:

class TestParser < Parslet::Parser

  rule(:name) { match['a-z'].repeat >> str(',').maybe }
  rule(:names) { name.repeat }

  root(:names)

end

TestParser.new.parse_with_debug('tom,samantha,ricardo')  # hangs here

I am aware of "Parslet word until delimeter present", and I know how to parse the list in other ways, but I don't understand why the above does not work.


Solution

  • Explanation:

    An infinite loops mean you have a rule in your parser that you are looping over, but it can match against an empty string. If it consumed anything, you wouldn't get an infinite loop.

    In your case: Repeat defaults to Repeat(0) which can match zero characters. The Maybe makes the comma optional, so name can match without consuming anything, so it does... Repeatedly.

    Solution:

    • Make name call repeat(1) instead.

    Diagnosis:

    Checkout my fork of Parslet that detects these infinite loops.

    Its on github. ( https://github.com/NigelThorne/parslet )

    My branch complains when it's going through a loop a second time, and it hasn't consumed anything since the last iteration. (Only use this for development... as there is a check inside a time critical loop, so performs slower)