Earlier this year at Puppet Camp EU, Randall Hansen ran an open space session on improving the Puppet user experience.
Lots of sharp edges were identified, but one issue that I raised was the annoying need for trailing commas to break up parameters in resource declarations.
I chatted about this briefly with Luke and for a laugh I decided to write a Treetop Parsing Expression Grammar (PEG) for Puppet resources that supported newlines as the parameter delimeter:
# puppet.treetop
grammar Puppet
rule resource
whitespace
type
whitespace
open
whitespace
name
whitespace
parameters
whitespace
close
whitespace
{
def resource_type
type.text_value
end
def resource_name
name.word.text_value
end
}
end
rule type
word
end
rule open
"{"
end
rule close
"}"
end
rule name
quotes word quotes ":"
{
def name
word
end
}
end
rule word
[a-zA-Z]+
end
rule quotes
"'" / '"'
end
rule parameters
newline* (whitespace parameter comma_or_newline*)*
end
rule parameter
whitespace
word
whitespace
arrow
whitespace
word
whitespace
end
rule arrow
"=>"
end
rule comma_or_newline
comma / newline
end
rule comma
","
end
rule newline
"\n"
end
rule whitespace
"\s"* / "\n"+
end
end
It’s throwaway code, but as far as I’m aware it’s relatively idiomatic Treetop.
It came in handy earlier this week when explaining PEGs to a new recruit into the R&D team at work.
Said recruit suggested that I publish it, as there aren’t too many examples of Treetop PEGs floating around.
To run the PEG over an example snippet:
#!/usr/bin/env ruby
require 'rubygems'
require 'bundler/setup'
require 'polyglot'
require 'treetop'
Treetop.load "puppet"
snippet = <<-SNIPPET
package { "foobar":
ensure => present, another => bar, spoons => doom
foo => bar
}
SNIPPET
parser = PuppetParser.new
if @root = parser.parse(snippet.strip)
puts 'success'
p @root.resource_type
p @root.resource_name
else
puts 'failure'
puts parser.failure_reason
puts parser.failure_column
puts parser.failure_line
puts parser.failure_index
end
Gemfile for running it and all the above code is in a Gist.