=head1 NAME
-TOML::Tiny - a minimal TOML parser and serializer
+TOML::Tiny - a minimal, pure perl TOML parser and serializer
=head1 VERSION
-requires 'perl' => '>= 5.014';
-requires 'JSON::PP' => '0';
+requires 'perl' => '>= 5.014';
recommends 'Types::Serialiser' => 0;
on test => sub{
- requires 'Test::Pod' => '0';
- requires 'Test2::V0' => '0';
+ requires 'Data::Dumper' => '0';
+ requires 'DateTime::Format::ISO8601' => '0';
+ requires 'TOML::Parser' => '0';
+ requires 'Test2::V0' => '0';
+ requires 'Test::Pod' => '0';
};
package TOML::Tiny;
-# ABSTRACT: a minimal TOML parser and serializer
+# ABSTRACT: a minimal, pure perl TOML parser and serializer
use strict;
use warnings;
+use TOML::Tiny::Parser;
-use TOML::Tiny::Grammar;
+use parent 'Exporter';
-our $GRAMMAR_V5 = $TOML::Tiny::Grammar::GRAMMAR_V5;
+our @EXPORT = qw(
+ from_toml
+ to_toml
+);
+
+sub from_toml {
+ my $source = shift;
+ my $parser = TOML::Tiny::Parser->new(@_);
+ my $toml = eval{ $parser->parse($source) };
+ return ($toml, $@);
+}
+
+sub to_toml {
+ my $data = shift;
+}
1;
use strict;
use warnings;
-our $GRAMMAR_V5 = qr{
+use parent 'Exporter';
+
+our @EXPORT = qw(
+ $TOML
+);
+
+our $TOML = qr{
(?(DEFINE)
#-----------------------------------------------------------------------------
| (?&InlineTable)
)
- (?<NLSeq> (?: \x0A) | (?: \x0D \x0A))
+ (?<NLSeq> \x0A | (?: \x0D \x0A))
(?<NL> (?&NLSeq) | (?&Comment))
(?<WSChar> [ \x20 \x09 ]) # (space, tab)
)
(?<StringLiteral>
- (?: ' ([^']*) ') # single quoted string (no escaped chars allowed)
+ (?: ' [^']* ') # single quoted string (no escaped chars allowed)
)
(?<MultiLineStringLiteral>
(?m)
(?s)
''' # opening triple-quote
- (.)*? # capture
+ .*?
''' # closing triple-quote
(?-s)
(?-m)
(?<BasicString>
(?:
" # opening quote
- (?: # capture escape sequences or any char except " or \
+ (?: # escape sequences or any char except " or \
(?: (?&EscapeChar) )
| [^"\\]
)*
(?<MultiLineString>
(?s)
""" # opening triple-quote
- ( # capture:
+ (?:
(?: (?&EscapeChar) ) # escaped char
| .
)*?
use strict;
use warnings;
-use feature qw(switch);
+use feature qw(say switch);
no warnings qw(experimental);
-use Carp;
-use DDP;
-use Data::Dumper;
use TOML::Tiny::Tokenizer;
-our $TOML = $TOML::Tiny::Grammar::GRAMMAR_V5;
our $TRUE = 1;
our $FALSE = 0;
-BEGIN{
- eval{
- require Types::Serialiser;
- $TRUE = Types::Serialiser::true();
- $FALSE = Types::Serialiser::false();
- };
-}
+eval{
+ require Types::Serialiser;
+ $TRUE = Types::Serialiser::true();
+ $FALSE = Types::Serialiser::false();
+};
sub new {
my ($class, %param) = @_;
- return bless{
- inflate_datetime => $param{inflate_datetime},
- inflate_boolean => $param{inflate_boolean},
+ bless{
+ inflate_datetime => $param{inflate_datetime} || sub{ shift },
+ inflate_boolean => $param{inflate_boolean} || sub{ shift eq 'true' ? $TRUE : $FALSE },
}, $class;
}
+sub next_token {
+ my $self = shift;
+ return unless $self->{tokenizer};
+ $self->{tokenizer}->next_token;
+}
+
sub parse {
- my $self = shift;
- my $tokens = TOML::Tiny::Tokenizer::tokenize(@_);
- my $root = {};
- my $acc = { root => $root, node => $root };
- $self->parse_token($_, $acc) for @$tokens;
- return $root;
-}
-
-sub parse_token {
- my $self = shift;
- my $token = shift;
- my $acc = shift;
- my $type = shift @$token;
-
- for ($type) {
- # Table
- when ('table') {
- my $keys = $self->parse_key(shift @$token);
- $acc->{node} = $self->mkpath($keys, $acc->{root});
- }
+ my ($self, $toml) = @_;
- # Array of tables
- when ('array-of-tables') {
- my $keys = $self->parse_key(shift @$token);
- my $last = pop @$keys;
- $acc->{node} = $self->mkpath($keys, $acc->{root});
- $acc->{node}{$last} ||= [];
- push @{ $acc->{node}{$last} } => $acc->{node} = {};
- }
+ $self->{tokenizer} = TOML::Tiny::Tokenizer->new(source => $toml);
+ $self->{keys} = [];
+ $self->{root} = {};
+
+ $self->parse_table;
+ my $result = $self->{root};
+
+ delete $self->{tokenizer};
+ delete $self->{keys};
+ delete $self->{root};
+
+ return $result;
+}
+
+sub parse_error {
+ my ($self, $token, $msg) = @_;
+ my $line = $token ? $token->line : 'EOF';
+ die "toml parse error at line $line: $msg\n";
+}
+
+sub expect_type {
+ my ($self, $token, $expected) = @_;
+ my $actual = $token->type;
+ $self->parse_error($token, "expected $expected, but found $actual")
+ unless $actual eq $expected;
+}
- # Key-value pair
- when ('assignment') {
- my $keys = $self->parse_key(shift @$token);
- my $last = pop @$keys;
- my $value = $self->parse_value(shift @$token);
- my $node = $self->mkpath($keys, $acc->{node});
- $node->{$last} = $value;
- }
- }
- return $acc;
+sub push_keys {
+ my ($self, $token) = @_;
+ push @{ $self->{keys} }, $token->value;
+}
+
+sub pop_keys {
+ my $self = shift;
+ pop @{ $self->{keys} };
}
-sub mkpath {
+sub get_keys {
my $self = shift;
- my $keys = shift;
- my $node = shift;
+ return map{ @$_ } @{ $self->{keys} };
+}
+
+sub set_keys {
+ my $self = shift;
+ my $value = $self->parse_value;
+ my @keys = $self->get_keys;
+ my $key = pop @keys;
+ my $node = $self->scan_to_key(\@keys);
+ $node->{$key} = $value;
+}
+
+sub scan_to_key {
+ my ($self, $keys) = @_;
+ my $node = $self->{root};
for my $key (@$keys) {
if (exists $node->{$key}) {
for (ref $node->{$key}) {
- $node = $node->{$key}[-1] when 'ARRAY';
- $node = $node->{$key} when 'HASH';
+ $node = $node->{$key} when /HASH/;
+ $node = $node->{$key}[-1] when /ARRAY/;
+ default{
+ my $full_key = join '.', @$keys;
+ die "$full_key is already defined\n";
+ }
}
}
else {
- $node = $node->{$key} ||= {};
+ $node = $node->{$key} = {};
}
}
return $node;
}
-sub parse_key {
- my ($self, $key) = @_;
- my $type = shift @$key;
- for ($type) {
- return $self->dotted_key(shift @$key) when 'dotted-key';
- return $self->quoted_key(shift @$key) when 'quoted-key';
- return $self->bare_key(shift @$key) when 'bare-key';
- }
-}
-sub parse_value {
- my ($self, $token) = @_;
- my $type = shift @$token;
+sub parse_table {
+ my $self = shift;
+ my $token = shift // $self->next_token;
+ $self->expect_type($token, 'table');
+ $self->push_keys($token);
- for ($type) {
- return $self->datetime(@$token) when 'datetime';
- return $self->boolean(@$token) when 'boolean';
+ TOKEN: while (my $token = $self->next_token) {
+ for ($token->type) {
+ when (/key/) {
+ $self->expect_type($self->next_token, 'assign');
+ $self->push_keys($token);
+ $self->set_keys;
+ $self->pop_keys;
+ }
- when ('array') {
- my $contents = shift @$token;
- return [ map{ $self->parse_value($_) } @$contents ];
- }
+ when (/array_table/) {
+ $self->pop_keys;
+ $self->parse_array_table($token);
+ }
- when ('inline-table') {
- my $tokens = shift @$token;
- my $root = {};
- my $acc = {root => $root, node => $root};
- $self->parse_token($_, $acc) for @$tokens;
- return $root;
- }
+ when (/table/) {
+ $self->pop_keys;
+ $self->parse_table($token);
+ }
- default{
- return shift @$token;
+ default{
+ $self->parse_error($token, "expected key-value pair, table, or array of tables but got $_");
+ }
}
}
}
-sub bare_key {
- my ($self, $key) = @_;
- return [$key];
-}
+sub parse_array_table {
+ my $self = shift;
+ my $token = shift // $self->next_token;
+ $self->expect_type($token, 'array_table');
+ $self->push_keys($token);
+
+ my @keys = $self->get_keys;
+ my $key = pop @keys;
+ my $node = $self->scan_to_key(\@keys);
+ $node->{$key} //= [];
+ push @{ $node->{$key} }, {};
+
+ TOKEN: while (my $token = $self->next_token) {
+ for ($token->type) {
+ when (/key/) {
+ $self->expect_type($self->next_token, 'assign');
+ $self->push_keys($token);
+ $self->set_keys;
+ $self->pop_keys;
+ }
-sub quoted_key {
- my ($self, $key) = @_;
- $key =~ s/^"//;
- $key =~ s/"$//;
- return [$key];
-}
+ when (/array_table/) {
+ $self->pop_keys;
+ $self->parse_array_table($token);
+ }
+
+ when (/table/) {
+ $self->pop_keys;
+ $self->parse_table($token);
+ }
-sub dotted_key {
- my ($self, $key) = @_;
- my @parts = split /\./, $key;
- return \@parts;
+ default{
+ $self->parse_error($token, "expected key-value pair, table, or array of tables but got $_");
+ }
+ }
+ }
}
-sub number {
- my ($self, $n) = @_;
- defined $n ? 0 + $n : $n;
+sub parse_key {
+ my $self = shift;
+ my $token = shift // $self->next_token;
+ $self->expect_type($token, 'key');
+ return $token->value;
}
-sub datetime {
- my ($self, $dt) = @_;
+sub parse_value {
+ my $self = shift;
+ my $token = shift // $self->next_token;
- if ($self->{inflate_datetime}) {
- my ($year, $month, $day, $hour, $minute, $second, $fractional, $offset) = $dt =~ qr{
- (?:
- (\d\d\d\d) - (\d\d) - (\d\d) # yyyy-mm-dd
- )?
+ for ($token->type) {
+ return $token->value when /number/;
+ return $token->value when /string/;
+ return $self->{inflate_boolean}->($token->value) when /boolean/;
+ return $self->{inflate_datetime}->($token->value) when /datetime/;
+ return $self->parse_inline_table when /inline_table/;
+ return $self->parse_inline_array when /inline_array/;
- (?:
- [T ]
- (\d\d) : (\d\d) : (\d\d) # hh:mm:ss.fractional
- (?:[.] (\d+) )?
+ default{
+ $self->parse_error($token, "value expected (boolean, number, string, datetime, inline array, inline table), but found $_");
+ }
+ }
+}
- ((?&Offset)?)
- )?
+sub parse_inline_array {
+ my $self = shift;
+ my @array;
- $TOML::Tiny::Tokenizer::TOML
- }x;
+ TOKEN: while (my $token = $self->next_token) {
+ for ($token->type) {
+ next TOKEN when /comma/;
+ last TOKEN when /inline_array_close/;
- return {
- original => $dt,
- year => $self->number($year),
- month => $self->number($month),
- day => $self->number($day),
- hour => $self->number($hour),
- minute => $self->number($minute),
- second => $self->number($second),
- fractional => $self->number($fractional),
- offset => $offset,
- };
- } else {
- return $dt;
+ default{
+ push @array, $self->parse_value($token);
+ }
+ }
}
+
+ return \@array;
}
-sub boolean {
- my ($self, $bool) = @_;
- if ($self->{inflate_boolean}) {
- return $TRUE if $bool eq 'true';
- return $FALSE;
- } else {
- return $bool;
+sub parse_inline_table {
+ my $self = shift;
+
+ my @keys = $self->get_keys;
+ my $key = pop @keys;
+ my $node = $self->scan_to_key(\@keys);
+ $node->{$key} //= {};
+
+ TOKEN: while (my $token = $self->next_token) {
+ for ($token->type) {
+ next TOKEN when /comma/;
+ last TOKEN when /inline_table_close/;
+
+ when (/key/) {
+ $self->expect_type($self->next_token, 'assign');
+ $self->push_keys($token);
+ $self->set_keys;
+ $self->pop_keys;
+ }
+
+ default{
+ $self->parse_error($token, "inline table expected key-value pair, but found $_");
+ }
+ }
}
+
+ return $node->{$key};
}
1;
use strict;
use warnings;
-use feature qw(switch);
+use feature qw(say switch);
no warnings qw(experimental);
-use JSON::PP;
+use DDP;
+use Carp;
use TOML::Tiny::Grammar;
-our $TOML = $TOML::Tiny::Grammar::GRAMMAR_V5;
+use Class::Struct 'TOML::Tiny::Token' => {
+ type => '$',
+ line => '$',
+ pos => '$',
+ value => '$',
+};
+
+sub new {
+ my ($class, %param) = @_;
+
+ my $self = bless{
+ source => $param{source},
+ is_exhausted => 0,
+ position => 0,
+ line => 0,
+ tokens => [],
+ }, $class;
+
+ return $self;
+}
-sub tokenize {
- my $toml = shift;
- my @tokens;
+sub next_token {
+ my $self = shift;
- TOKEN: while ((pos($toml) // 0) < length($toml)) {
- for ($toml) {
- when (/\G ((?&Boolean)) $TOML/xgc) {
- push @tokens, ['boolean', $1];
- }
+ if (!defined($self->{source})) {
+ return;
+ }
- when (/\G ((?&DateTime)) $TOML/xgc) {
- push @tokens, ['datetime', $1];
- }
+ if ($self->{is_exhausted}) {
+ return;
+ }
- when (/\G ((?&Float)) $TOML/xgc) {
- push @tokens, ['float', tokenize_float($1)];
+ if (!@{ $self->{tokens} }) {
+ my $root = $self->_make_token('table', []);
+ $self->push_token($root);
+ return $root;
+ }
+
+ # Update the regex engine's position marker in case some other regex
+ # attempted to match against the source string and reset it.
+ pos($self->{source}) = $self->{position};
+
+ my $token;
+
+ while (!defined($token) && !$self->{is_exhausted}) {
+ for ($self->{source}) {
+ when (/\G (?&NL) $TOML/xgc) {
+ ++$self->{line};
}
- when (/\G ((?&Integer)) $TOML/xgc) {
- push @tokens, ['integer', tokenize_integer($1)];
+ when (/\G (?&WSChar)+ $TOML/xgc) {
+ ;
}
- when (/\G ((?&String)) $TOML/xgc) {
- push @tokens, ['string', tokenize_string($1)];
+ when (/\G ((?&Key)) (?= (?&WS) =) $TOML/xgc) {
+ $token = $self->_make_token('key', $1);
}
- when (/\G ((?&KeyValuePairDecl)) $TOML/xgc) {
- push @tokens, tokenize_assignment($1);
+ when (/\G ((?&Boolean)) $TOML/xgc) {
+ $token = $self->_make_token('boolean', $1);
}
- when (/\G ((?&Array)) $TOML/xgc) {
- push @tokens, tokenize_array($1);
+ when (/\G ((?&DateTime)) $TOML/xgc) {
+ $token = $self->_make_token('datetime', $1);
}
- when (/\G ((?&InlineTable)) $TOML/xgc) {
- push @tokens, tokenize_inline_table($1);
+ when (/\G ((?&Float) | (?&Integer)) $TOML/xgc) {
+ $token = $self->_make_token('number', $1);
}
- when (/\G \[ (?&WS) ((?&Key)) (?&WS) \] (?&WS) (?&NL) $TOML/xgc) {
- push @tokens, ['table', tokenize_key($1)];
+ when (/\G ((?&String)) $TOML/xgc) {
+ $token = $self->_make_token('string', $1);
}
- when (/\G \[\[ (?&WS) ((?&Key)) (?&WS) \]\] (?&WS) (?&NL) $TOML/xgc) {
- push @tokens, ['array-of-tables', tokenize_key($1)];
+ when (/\G = /xgc) {
+ $token = $self->_make_token('assign', $1);
}
- when (/\G (?: (?&WSChar) | (?&NLSeq) | (?&Comment) )+ $TOML/xgc) {
- next TOKEN;
+ when (/\G , /xgc) {
+ $token = $self->_make_token('comma', $1);
}
- default{
- my $pos = pos $toml;
- my $line = line_number($toml, $pos);
- my $substr = substr($toml, $pos, 30) // 'undef';
- die "toml syntax error on line $line:\n\t--> $substr\n";
+ when (/\G \[ (?&WS) ((?&Key)) (?&WS) \] $TOML/xgc) {
+ my $key = $self->tokenize_key($1);
+ $token = $self->_make_token('table', $key);
}
- }
- }
- return \@tokens;
-}
+ when (/\G \[\[ (?&WS) ((?&Key)) (?&WS) \]\] (?&WS) (?&NL) $TOML/xgc) {
+ my $key = $self->tokenize_key($1);
+ $token = $self->_make_token('array_table', $key);
+ }
-sub tokenize_inline_table {
- my $toml = shift;
- my @items;
+ when (/\G \[ /xgc) {
+ $token = $self->_make_token('inline_array', $1);
+ }
- $toml =~ s/^\s*\{\s*//;
- $toml =~ s/\s*\}\s*$//;
+ when (/\G \] /xgc) {
+ $token = $self->_make_token('inline_array_close', $1);
+ }
- ITEM: while ((pos($toml) // 0) < length($toml)) {
- for ($toml) {
- next ITEM when /\G\s*/gc;
- next ITEM when /\G\{/gc;
- next ITEM when /\G\}/gc;
+ when (/\G \{ /xgc) {
+ $token = $self->_make_token('inline_table', $1);
+ }
- when (/\G ((?&KeyValuePair)) (?&WS) ,? $TOML/xgc) {
- push @items, tokenize_assignment($1);
+ when (/\G \} /xgc) {
+ $token = $self->_make_token('inline_table_close', $1);
}
default{
- die "invalid inline table syntax: $toml";
+ my $substr = substr($self->{source}, $self->{position}, 30) // 'undef';
+ die "toml syntax error on line $self->{line}\n\t--> $substr\n";
}
}
+
+ $self->push_token($token);
+ $self->update_position;
}
- return ['inline-table', \@items];
+ return $token;
}
-sub tokenize_array {
- my $toml = shift;
- my @items;
+sub push_token {
+ my $self = shift;
+ my $token = shift // return;
+ push @{$self->{tokens}}, $token;
+}
+
+sub pop_token {
+ my $self = shift;
+ pop @{$self->{tokens}};
+}
- $toml =~ s/^\s*\[\s*//;
- $toml =~ s/\s*\]\s*$//;
+sub _make_token {
+ my ($self, $type, $value) = @_;
- ITEM: while ((pos($toml) // 0) < length($toml)) {
- my $pos = pos($toml) // 0;
- for ($toml) {
- when (/\G ((?&Value)) (?&WS) [,]? $TOML/xgc) {
- push @items, @{ tokenize($1) };
- }
+ my $token = TOML::Tiny::Token->new(
+ type => $type,
+ line => $self->{line},
+ pos => $self->{position},
+ );
- next ITEM when /\G\s*/gc;
- next ITEM when /\G\[/gc;
- next ITEM when /\G\]/gc;
+ $self->update_position;
- default{
- die "invalid array syntax: $toml";
- }
- }
+ if (my $tokenize = $self->can("tokenize_$type")) {
+ $value = $tokenize->($self, $value);
}
- return ['array', \@items];
+ $token->value($value);
+
+ return $token;
}
-sub tokenize_assignment {
- my $toml = shift;
+sub current_line {
+ my $self = shift;
+ my $rest = substr $self->{source}, $self->{position};
+ my $stop = index $rest, "\n";
+ substr $rest, 0, $stop;
+}
- for ($toml) {
- when (/\G(?&WS) ((?&Key)) (?&WS) = (?&WS) ((?&Value)) (?&NL)? $TOML/xgc) {
- my $key = tokenize_key($1);
- my $val = tokenize($2);
- return ['assignment', $key, @$val];
- }
+sub update_position {
+ my $self = shift;
+ $self->{position} = pos($self->{source}) // 0;
+ $self->{is_exhausted} = $self->{position} >= length($self->{source});
+}
- default{
- die "invalid assignment syntax: $toml";
- }
- }
+sub error {
+ my $self = shift;
+ my $token = shift;
+ my $msg = shift // 'unknown';
+ my $line = $token ? $token->line : $self->{line};
+ croak "toml: parse error at line $line: $msg\n";
}
sub tokenize_key {
+ my $self = shift;
my $toml = shift;
for ($toml) {
- return ['dotted-key', $1] when /^ ((?&DottedKey)) $TOML/x;
- return ['quoted-key', $1] when /^ ((?&QuotedKey)) $TOML/x;
- return ['bare-key', $1] when /^ ((?&BareKey)) $TOML/x;
-
- default{
- die "invalid key: syntax $toml";
+ my @parts;
+
+ $toml =~ qr{
+ (
+ (?:
+ ( (?&QuotedKey) | (?&BareKey) )
+ [.]?
+ (?{push @parts, $^N})
+ )+
+ )
+ $TOML
+ }x;
+
+ for (@parts) {
+ s/^["']//;
+ s/["']$//;
}
+
+ return \@parts;
}
}
sub tokenize_string {
+ my $self = shift;
my $toml = shift;
my $str = '';
for ($toml) {
when (/^ ((?&MultiLineString)) $TOML/x) {
$str = substr $1, 3, length($1) - 6;
+
+ my @newlines = $str =~ /((?&NL)) $TOML/xg;
+ $self->{line} += scalar( grep{ defined $_ } @newlines );
+
$str =~ s/^(?&WS) (?&NL) $TOML//x;
}
when (/^ ((?&MultiLineStringLiteral)) $TOML/x) {
$str = substr $1, 3, length($1) - 6;
+
+ my @newlines = $str =~ /(?&NL) $TOML/xg;
+ $self->{line} += scalar( grep{ defined $_ } @newlines );
+
$str =~ s/^(?&WS) (?&NL) $TOML//x;
}
when (/^ ((?&StringLiteral)) $TOML/x) {
$str = substr($1, 1, length($1) - 2);
}
-
- default{
- die "invalid string syntax: $toml";
- }
}
return ''.$str;
}
-sub tokenize_integer {
+sub tokenize_number {
+ my $self = shift;
my $toml = shift;
for ($toml) {
when (/(?&Hex) $TOML/x) {
return hex $toml;
}
-
- when (/(?&Dec) $TOML/x) {
- }
-
- default{
- die "invalid datetime syntax: $toml";
- }
}
return 0 + $toml;
}
-sub tokenize_float {
- my $toml = shift;
- return 0 + $toml;
-}
-
-sub line_number {
- my ($toml, $pos) = @_;
- my $substr = substr $toml, 0, $pos + 1;
- my @lines = $substr =~ /((?&NL)) $TOML/g;
- return scalar @lines;
-}
-
1;
# represented in the synopsis example
#-------------------------------------------------------------------------------
use Test2::V0;
+use Data::Dumper;
use TOML::Tiny::Parser;
-use TOML;
my $toml = do{ local $/; <DATA> };
-my $parser = TOML::Tiny::Parser->new(
- inflate_datetime => 0,
- inflate_boolean => 0,
-);
+subtest 'TOML::Parser' => sub{
+ use TOML::Parser;
+
+ subtest 'defaults' => sub{
+ my $exp = TOML::Parser->new->parse($toml);
+ my $got = TOML::Tiny::Parser->new->parse($toml);
+ is $got, $exp, 'equivalence'
+ or diag Dumper({got => $got, expected => $exp});
+ };
+
+ subtest 'inflate_boolean' => sub{
+ my $inflate = sub{ shift eq 'true' ? 'yes' : 'no' };
+ my $exp = TOML::Parser->new(inflate_boolean => $inflate)->parse($toml);
+ my $got = TOML::Tiny::Parser->new(inflate_boolean => $inflate)->parse($toml);
+ is $got, $exp, 'equivalence'
+ or diag Dumper({got => $got, expected => $exp});
+ };
+
+ subtest 'inflate_datetime' => sub{
+ require DateTime::Format::ISO8601;
+ my $inflate = sub{ DateTime::Format::ISO8601->parse_datetime(shift) };
+ my $exp = TOML::Parser->new(inflate_datetime => $inflate)->parse($toml);
+ my $got = TOML::Tiny::Parser->new(inflate_datetime => $inflate)->parse($toml);
+ is $got, $exp, 'equivalence'
+ or diag Dumper({got => $got, expected => $exp});
+ };
+};
-my $got = $parser->parse($toml);
-my $exp = from_toml($toml);
-
-is $got, $exp, 'parity with TOML module';
done_testing;
__DATA__
use Test2::V0;
-use TOML::Tiny;
+use TOML::Tiny::Grammar;
-my $re = qr{ ((?&ArrayOfTables)) $TOML::Tiny::GRAMMAR_V5 }x;
+my $re = qr{ ((?&ArrayOfTables)) $TOML }x;
my @valid = (
qq{[[foo]]\n},
use Test2::V0;
-use TOML::Tiny;
+use TOML::Tiny::Grammar;
-my $re = qr{ ((?&Array)) $TOML::Tiny::GRAMMAR_V5 }x;
+my $re = qr{ ((?&Array)) $TOML }x;
my @valid = (
q{[ 1, 2, 3 ]},
use Test2::V0;
-use TOML::Tiny;
+use TOML::Tiny::Grammar;
-my $re = qr{ ((?&Boolean)) $TOML::Tiny::GRAMMAR_V5 }x;
+my $re = qr{ ((?&Boolean)) $TOML }x;
like 'true', $re, 'true';
like 'false', $re, 'false';
use Test2::V0;
-use TOML::Tiny;
+use TOML::Tiny::Grammar;
-my $re = qr{ ((?&DateTime)) $TOML::Tiny::GRAMMAR_V5 }x;
+my $re = qr{ ((?&DateTime)) $TOML }x;
my @valid = (
'1979-05-27T07:32:00Z',
use Test2::V0;
-use TOML::Tiny;
+use TOML::Tiny::Grammar;
-my $re = qr{ ((?&Float)) $TOML::Tiny::GRAMMAR_V5 }x;
+my $re = qr{ ((?&Float)) $TOML }x;
my @valid = qw(
+1.0
use Test2::V0;
-use TOML::Tiny;
+use TOML::Tiny::Grammar;
-my $re = qr{ ((?&InlineTable)) $TOML::Tiny::GRAMMAR_V5 }x;
+my $re = qr{ ((?&InlineTable)) $TOML }x;
my @valid = (
q|{ first = "Tom", last = "Preston-Werner" }|,
use Test2::V0;
-use TOML::Tiny;
+use TOML::Tiny::Grammar;
-my $re = qr{ ((?&Integer)) $TOML::Tiny::GRAMMAR_V5 }x;
+my $re = qr{ ((?&Integer)) $TOML }x;
my @valid = qw(
+99
use Test2::V0;
-use TOML::Tiny;
+use TOML::Tiny::Grammar;
-my $re = qr{ ((?&KeyValuePair)) $TOML::Tiny::GRAMMAR_V5 }x;
+my $re = qr{ ((?&KeyValuePair)) $TOML }x;
my @valid = (
q{foo= "bar"},
use Test2::V0;
-use TOML::Tiny;
+use TOML::Tiny::Grammar;
-my $re = qr{ ((?&Key)) $TOML::Tiny::GRAMMAR_V5 }x;
+my $re = qr{ ((?&Key)) $TOML }x;
my @valid = qw(
key
use Test2::V0;
-use TOML::Tiny;
+use TOML::Tiny::Grammar;
sub test_simple_matches {
my ($re, @tests) = @_;
subtest 'escaped characters' => sub{
my $re = qr{
((?&EscapeChar))
- $TOML::Tiny::GRAMMAR_V5
+ $TOML
}x;
test_simple_matches($re,
subtest 'string literals' => sub{
my $re = qr{
((?&StringLiteral))
- $TOML::Tiny::GRAMMAR_V5
+ $TOML
}x;
test_simple_matches($re,
subtest 'basic strings' => sub{
my $re = qr{
((?&BasicString))
- $TOML::Tiny::GRAMMAR_V5
+ $TOML
}x;
test_simple_matches($re,
subtest 'multi-line strings' => sub{
my $re = qr{
((?&MultiLineString))
- $TOML::Tiny::GRAMMAR_V5
+ $TOML
}x;
test_simple_matches($re,
subtest 'multi-line string literals' => sub{
my $re = qr{
((?&MultiLineStringLiteral))
- $TOML::Tiny::GRAMMAR_V5
+ $TOML
}x;
test_simple_matches($re,
use Test2::V0;
-use TOML::Tiny;
+use TOML::Tiny::Grammar;
-my $re = qr{ (?&Table) $TOML::Tiny::GRAMMAR_V5 }x;
+my $re = qr{ (?&Table) $TOML }x;
my @valid = (
qq{[foo]\n},