Created
December 13, 2019 16:19
-
-
Save JRaspass/bb1fdf4f43dca96f9c79cba1def9a0f9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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