Skip to content

Instantly share code, notes, and snippets.

@damncabbage
Created October 11, 2011 12:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save damncabbage/1278009 to your computer and use it in GitHub Desktop.
Save damncabbage/1278009 to your computer and use it in GitHub Desktop.
Parslet Woes
require 'parslet'
require 'pp'
def parse(input)
parser = SongParser.new
begin
tree = parser.parse(input)
rescue Parslet::ParseFailed => error
puts error, parser.root.error_tree
end
tree
end
class SongParser < Parslet::Parser
# Convenience: lyrics can have ignored characters after the
# last timecode on a line
rule(:junk) { (line_end.absent? >> any).repeat }
# Convenience: End of Line / Whitespace matchers
rule(:line_end) { match('[\r\n]').repeat(1) }
rule(:spaces) { match('\s').repeat(1) }
rule(:spaces?) { spaces.maybe }
# Elements
rule(:syllable) { (timecode.absent? >> any).repeat(1) }
rule(:timecode) {
str('[') >> match('\d').repeat(1).as(:min) >>
str(':') >> match('\d').repeat(1).as(:sec) >>
str(':') >> match('\d').repeat(1).as(:msec) >> str(']')
}
# Groups
rule(:pair) { timecode >> syllable.as(:syllable) }
rule(:line) { (pair.repeat >> timecode).as(:line) >> junk.maybe >> line_end }
rule(:song) { line.repeat.as(:lines) }
root :song
end
input = "[01:06:07]Beat[01:06:30]ing [01:06:56]up [01:06:83]the [01:07:09]wrong "
input << "[01:07:52]guy[01:08:03]\n[01:08:50]Oh [01:08:93]man![01:09:48]\n"
input_no_trailing_new_line = input.chomp
pp parse(input)
# Produces:
#
# Don't know what to do with [01:06:07]Beat[01:06:30]ing [01:06:56]up [01:06:83]the [01:07:09]wrong [01:07:52]guy[01:08:03]
# [01:0 at line 1 char 1.
# `- Failed to match sequence (line:(PAIR{0, } TIMECODE) JUNK? LINE_END) at line 1 char 1.
# `- Failed to match sequence (PAIR{0, } TIMECODE) at line 3 char 1.
# `- Failed to match sequence ('[' min:(\\d{1, }) ':' sec:(\\d{1, }) ':' msec:(\\d{1, }) ']') at line 3 char 1.
# `- Premature end of input at line 3 char 1.
pp parse(input_no_trailing_new_line)
# Produces:
#
# Don't know what to do with [01:06:07]Beat[01:06:30]ing [01:06:56]up [01:06:83]the [01:07:09]wrong [01:07:52]guy[01:08:03]
# [01:0 at line 1 char 1.
# `- Failed to match sequence (line:(PAIR{0, } TIMECODE) JUNK? LINE_END) at line 2 char 38.
# `- Expected at least 1 of [\\r\\n] at line 2 char 38.
# `- Failed to match [\\r\\n] at line 2 char 38.
require 'parslet'
require 'pp'
def parse(input)
parser = SongParser.new
begin
tree = parser.parse(input)
rescue Parslet::ParseFailed => error
puts error, parser.root.error_tree
end
tree
end
class SongParser < Parslet::Parser
rule(:line_end) { match('[\r\n]').repeat(1) }
rule(:junk) { (line_end.absent? >> any).repeat }
rule(:line) { junk.as(:line) >> line_end }
rule(:song) { line.repeat.as(:lines) }
root :song
end
input = "[01:06:07]Beat[01:06:30]ing [01:06:56]up [01:06:83]the [01:07:09]wrong "
input << "[01:07:52]guy[01:08:03]\n[01:08:50]Oh [01:08:93]man![01:09:48]\n"
input_no_trailing_new_line = input.chomp
pp parse(input) # Works fine
pp parse(input_no_trailing_new_line) # Explodes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment