Config::INI in Perl 6
What better way to learn Perl 6 than to write software in it? I thought a nice, small project would be to write an INI file parser. Unfortunately, it turns out there there is no standard INI format. Or if there is, there it's pretty much ignored. As a result, I tried to write something which would handle something which is the least surprising to people. Thus, I trim whitespace, I allow comment lines starting with ';' and '#' and I ignore blank lines. It does not yet handle quoted strings, but I want to add that later.
I finally have a (clumsy) grammar which matches, but turning it into an AST and transforming it into a useful object has failed miserably. Tips? The code below runs on the latest version of Rakudo and the first parse shows that we match, but the second match generates errors such as:
Use of uninitialized value Use of uninitialized value Null PMC access in find_method('new') in Main (file <unknown>, line <unknown>)
And the Perl 6:
grammar Config::INI::Grammar {
token TOP {
<config>
{*}
}
token config {
<root_section>?
<section>+
{*}
}
token root_section {
[ <property> | <ignore> ]*
{*}
}
regex section {
^^ '[' <.ws> $<name>=<-[\n\]]>*? <.ws> ']' \h* \n
[ <property> | <ignore> ]*
{*}
}
regex property {
^^ <.ws> $<name>=[<.print>+?] <.ws> '=' <.ws> $<value>=[\N*?] \h* \n
}
token ignore {
| ^^ <.ws> [';'|'#'] [\N*] \n
| ^^ \h* \n
}
}
class Config::INI {
class Config::INI::Section {
has $.name is rw;
has %.properties is rw;
}
has $.root_section is rw;
has Config::INI::Section @.sections is rw;
}
class Config::INI::Actions {
method TOP ($/) {
say 'TOP';
make ($<config>).ast;
}
method config ($/) {
say 'config';
make Config::INI.new(
root_section => ($<root_section>).ast,
sections => ($<section>)>>.ast,
);
}
method root_section ($/) {
my %property;
for $<property> -> $p {
%property{$<name>} = $<value>;
}
make Config::INI::Section.new(
name => '_',
properties => %property,
);
}
method section ($/) {
my %property;
for $<property> -> $p {
%property{$<name>} = $<value>;
}
make Config::INI::Section.new(
name => $<name>,
properties => %property
{*}
);
}
}
my $text = Q{
uno=dos
tres = quatro
[ foo bar ]
this=that
one = two
# ignore this
; and this
};
my $config = Config::INI::Grammar.parse($text);
say $config ?? 'yes' !! 'no';
say $config.perl;
my $actions = Config::INI::Actions.new();
$config = Config::INI::Grammar.parse($text, :action($actions)).ast;
say $config ?? 'yes' !! 'no';
say $config.perl;
Clearly the Config::INI classes are clumsy right now, but they're just a first pass for me trying to generate the AST.
In the RSS feed, your nicely formatted grammar shows up as a code blob.
@coke: bummer. I'll file a bug report.