Skip to content

Instantly share code, notes, and snippets.

@dwarring
Created March 27, 2014 23:06
Show Gist options
  • Save dwarring/9821113 to your computer and use it in GitHub Desktop.
Save dwarring/9821113 to your computer and use it in GitHub Desktop.
advent 2013 day 14 - config combiner
our %TestFiles = (
'config1.ini' => q:to"END1",
[fruit]
apples = 0.50
oranges = 0.70
[veges]
broccoli = 0.25
END1
'config2.ini' => q:to"END2",
[fruit]
kiwis = 0.75
[veges]
cabbage = 0.20
END2
);
my @files = %TestFiles.keys;
diag "files: {@files}";
read_all(@files);
sub read_all(@files) {
my $read = Channel.new;
my $parsed = Channel.new;
read_worker(@files, $read);
parse_worker($read, $parsed) for 1..2;
my %all_config = await config_combiner($parsed);
diag %all_config.perl;
}
sub read_worker(@files, $dest) {
start {
for @files -> $file {
sleep .1;
die "no such file: $file"
unless %TestFiles{$file}:exists;
$dest.send(%TestFiles{$file});
}
$dest.close();
CATCH { $dest.fail($_) }
}
}
sub parse_worker($source, $dest) {
my grammar INIFile {
token TOP {
^
<entries>
<section>+
$
}
token section {
'[' ~ ']' <key> \n
<entries>
}
token entries {
[
| <entry> \n
| \n
]*
}
rule entry { <key> '=' <value> }
token key { \w+ }
token value { \N+ }
token ws { \h* }
}
my class INIFileActions {
method TOP($/) {
my %result;
%result<_> = $<entries>.ast;
for $<section> -> $sec {
%result{$sec<key>} = $sec<entries>.ast;
}
make %result;
}
method entries($/) {
my %entries;
for $<entry> -> $e {
%entries{$e<key>} = ~$e<value>;
}
make %entries;
}
}
start {
loop {
winner $source {
more $source {
diag "parsing: {$_}";
if INIFile.parse($_, :actions(INIFileActions)) -> $parsed {
diag "parsed: {$parsed}";
diag "ast: {$parsed.ast}";
$dest.send($parsed.ast);
}
else {
diag "unable to parse";
$dest.fail("Could not parse INI file");
last;
}
}
done $source { last }
}
}
$dest.close();
CATCH { $dest.fail($_) }
}
}
sub config_combiner($source) {
my $p = Promise.new;
my $v = $p.vow;
warn "combiner...";
start {
my %result;
loop {
winner $source {
more $source {
for %^content.kv -> $sec, %kvs {
warn "sec: $sec";
for %kvs.kv -> $k, $v {
warn "\tcombining: k={$k} v={$v}";
%result{$sec}{$k} = $v;
}
}
}
done $source { last }
}
}
$v.keep(%result);
CATCH { $v.break($_) }
}
return $p;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment