Skip to content

Instantly share code, notes, and snippets.

@JRaspass
Created December 13, 2019 16:19
Show Gist options
  • Save JRaspass/bb1fdf4f43dca96f9c79cba1def9a0f9 to your computer and use it in GitHub Desktop.
Save JRaspass/bb1fdf4f43dca96f9c79cba1def9a0f9 to your computer and use it in GitHub Desktop.
unit module TOML::Tiny;
# FIXME Raku needs a Time.
class Time does Dateish {
has $.hour;
has $.minute;
has $.second;
method !formatter() {
sprintf '%02d:%02d:%s', $!hour, $!minute, $!second.floor == $!second
?? $!second.Int.fmt('%02d') !! $!second.fmt('%09.6f');
}
multi method new($hour, $minute, $second) {
self.bless(:$hour :$minute :$second);
}
multi method new(Str $time) {
Time.new(|($time ~~ /(\d\d) ':' (\d\d) ':' (\d\d[\.\d ** 1..6]?)/)».Num);
}
}
grammar Grammar {
rule TOP { [ <comment> | <key-value> | <table> ]* }
token basic-str { '"' <basic-chr>* '"' }
proto token basic-chr { * }
token basic-chr:common { <+[\N] -[ \" \\ ] -[\x00..\x1F] -[\x7F]> } # "
token basic-chr:backspace { 「\b」 }
token basic-chr:tab { 「\t」 }
token basic-chr:line-feed { 「\n」 }
token basic-chr:form-feed { 「\f」 }
token basic-chr:carriage-return { 「\r」 }
token basic-chr:quotation-mark { 「\"」 } # "
token basic-chr:reverse-solidus { 「\\」 }
token basic-chr:unicode { 「\u」 <(<xdigit> ** 4)>
| 「\U」 <(<xdigit> ** 8)> }
token literal-str { "'" <(\d+)> "'" }
token comment { '#' \N* }
token digits { \d+ | \d+ '_' <digits> }
token key { ''"'? <(<[ A .. Z a .. z 0 .. 9 . _ + # - ]>+)> '"'?' }
rule key-value { <key> '=' <value> <comment>? }
rule table { '[' <key> ']' <comment>? <key-value>* }
proto token value {*}
# FIXME Why doesn't <value:date> in datetime work?
rule value:sym<array> { '[' <value>* %% [ ',' <comment>? ] ']' }
token value:sym<datetime> { \d\d [\d\d] ** 3 % '-' T <value:time> [ Z | <[+-]> \d+ ':' \d+ ] }
token value:sym<date> { \d\d [\d\d] ** 3 % '-' }
token value:sym<false> { <sym> }
token value:sym<inf> { <[+-]>? <sym> }
token value:sym<nan> { <[+-]>? <sym> }
token value:sym<string> { <basic-str> | <literal-str> }
rule value:sym<table> { '{' <key-value>* % ',' '}' }
token value:sym<time> { \d\d ':' \d\d ':' \d\d [ '.' \d+ ]? }
token value:sym<true> { <sym> }
token value:sym<number> {
<[+-]>?
# Leading zeros are not allowed.
[ 0 | <[1..9]> [ '_'? <digits> ]? ]
[ '.' <digits>+ ]?
[ <[Ee]> <[+-]>? <digits>+ ]?
}
}
class Actions {
method TOP ($/) { make %( |$<key-value>».made, $<table>».made.Hash ) }
method basic-str ($/) { make $<basic-chr>».made.join }
method basic-chr:common ($/) { make ~$/ }
method basic-chr:backspace ($/) { make "\b" }
method basic-chr:tab ($/) { make "\t" }
method basic-chr:line-feed ($/) { make "\n" }
method basic-chr:form-feed ($/) { make "\f" }
method basic-chr:carriage-return ($/) { make "\r" }
method basic-chr:quotation-mark ($/) { make "\"" }
method basic-chr:reverse-solidus ($/) { make "\\" }
method basic-chr:unicode ($/) { make chr :16(~$/) }
method literal-str ($/) { dd ~$/; make ~$/ }
method key ($/) { make ~$/ }
method key-value ($/) { make $<key>.made => $<value>.made }
method table ($/) { make $<key>.made => $<key-value>».made.Hash }
method value:sym<array> ($/) { make $<value>».made }
method value:sym<datetime> ($/) { make DateTime.new(~$/) }
method value:sym<date> ($/) { make Date.new(~$/) }
method value:sym<false> ($/) { make False }
method value:sym<inf> ($/) { make $/.starts-with('-') ?? -Inf !! Inf }
method value:sym<nan> ($/) { make NaN }
method value:sym<number> ($/) { make +$/ }
method value:sym<string> ($/) { make ( $<basic-str> // $<literal-str> ).made }
method value:sym<table> ($/) { make $<key-value>».made.Hash }
method value:sym<time> ($/) { make Time.new(~$/) }
method value:sym<true> ($/) { make True }
}
sub from-toml(Str $toml) is export {
dd $toml;
Grammar.parse($toml, :actions(Actions)).made;
}
# FIXME Assumes we have a hash of hashes.
sub to-toml(%hash) is export {
my $toml;
for %hash.sort {
# Quote complicated keys.
my $key = .key ~~ /<[.+]>/ ?? '"' ~ .key ~ '"' !! .key;
$toml ~= "[$key]\n";
$toml ~= "{.key} = {toml(.value)}\n" for .value.sort;
$toml ~= "\n";
}
$toml.chomp;
}
multi sub toml(Bool $value) { $value.lc }
multi sub toml(Dateish $value) { ~$value }
multi sub toml(Int $value) { ~$value }
multi sub toml(Iterable $value) { '[ ' ~ $value».&toml.join(', ') ~ ' ]' }
multi sub toml(Str $value) { qq{"$value"} }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment