From def51cf740555d7b6a6d89535abf91a266aa827c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tina=20M=C3=BCller?= Date: Sun, 26 Jan 2020 17:04:02 +0100 Subject: [PATCH] Improve emitter --- bin/yamlpp5-parse-emit | 2 +- lib/YAML/PP/Dumper.pm | 7 + lib/YAML/PP/Emitter.pm | 331 +++++++++++++++++++++-------------------- t/21.emit.t | 17 ++- t/39.emitter-alias.t | 6 +- t/40.representers.t | 2 +- t/lib/YAML/PP/Test.pm | 3 + 7 files changed, 194 insertions(+), 174 deletions(-) diff --git a/bin/yamlpp5-parse-emit b/bin/yamlpp5-parse-emit index 5884fa1c..152c50c4 100755 --- a/bin/yamlpp5-parse-emit +++ b/bin/yamlpp5-parse-emit @@ -48,7 +48,7 @@ for my $event (@events) { my $type = $event->{name}; my $str = YAML::PP::Common::event_to_test_suite($event); print "$str\n" if $verbose; - if ($type eq 'sequence_start_event' or $type eq 'mapping_end_event') { + if ($type eq 'sequence_start_event' or $type eq 'mapping_start_event') { delete $event->{style}; } $emitter->$type($event); diff --git a/lib/YAML/PP/Dumper.pm b/lib/YAML/PP/Dumper.pm index 8bb37730..33cd5674 100644 --- a/lib/YAML/PP/Dumper.pm +++ b/lib/YAML/PP/Dumper.pm @@ -138,6 +138,10 @@ sub emit_node { } if ($type eq 'mapping') { my $style = YAML_BLOCK_MAPPING_STYLE; + # TODO + if ($node->{items} and @{ $node->{items} } == 0) { +# $style = YAML_FLOW_MAPPING_STYLE; + } $self->emitter->mapping_start_event({ anchor => $node->{anchor}, style => $style, @@ -151,6 +155,9 @@ sub emit_node { } if ($type eq 'sequence') { my $style = YAML_BLOCK_SEQUENCE_STYLE; + if (@{ $node->{items} } == 0) { +# $style = YAML_FLOW_SEQUENCE_STYLE; + } $self->emitter->sequence_start_event({ anchor => $node->{anchor}, style => $style, diff --git a/lib/YAML/PP/Emitter.pm b/lib/YAML/PP/Emitter.pm index 08581e8d..0c75cb0a 100644 --- a/lib/YAML/PP/Emitter.pm +++ b/lib/YAML/PP/Emitter.pm @@ -3,6 +3,7 @@ use warnings; package YAML::PP::Emitter; our $VERSION = '0.000'; # VERSION +use Data::Dumper; use YAML::PP::Common qw/ YAML_PLAIN_SCALAR_STYLE YAML_SINGLE_QUOTED_SCALAR_STYLE @@ -69,59 +70,70 @@ sub mapping_start_event { $tag = $self->emit_tag('map', $tag); } $props = join ' ', grep defined, ($anchor, $tag); - my $append = $last->{append}; - my $new_append = 0; + my $column = $last->{column}; my $yaml = ''; + my $newline = 0; if ($last->{type} eq 'DOC') { - if ($append and $props) { - $yaml .= " $props"; - } - elsif ($props) { + if ($props) { + $newline = 1; + $yaml .= $last->{column} ? ' ' : $indent; $yaml .= "$props"; } - if ($append or $props) { - $yaml .= "\n"; + if ($last->{newline}) { + $newline = 1; } - } - elsif ($last->{type} eq 'MAPVALUE') { - if ($props) { - $yaml .= " $props"; + else { + if ($props) { + $newline = 1; + } } - $yaml .= "\n"; - $new_indent .= ' ' x $self->indent; } else { $new_indent .= ' ' x $self->indent; - if ($append) { - $yaml .= " "; - } - else { - $yaml .= $indent; - } - if ($last->{type} eq 'SEQ') { - $yaml .= '-'; + if ($last->{newline}) { + $yaml .= "\n"; + $last->{column} = 0; + $last->{newline} = 0; } - elsif ($last->{type} eq 'MAP') { - $yaml .= "?"; - $last->{type} = 'COMPLEX'; + if ($props) { + $newline = 1; } - elsif ($last->{type} eq 'COMPLEX') { - $yaml .= ":"; - $last->{type} = 'COMPLEXVALUE'; + if ($last->{type} eq 'MAPVALUE') { + $newline = 1; } else { - die "Unexpected"; + $yaml .= $last->{column} ? ' ' : $indent; + $last->{newline} = 0; + if ($last->{type} eq 'SEQ') { + $yaml .= '-'; + } + elsif ($last->{type} eq 'MAP') { + $yaml .= "?"; + $last->{type} = 'COMPLEX'; + } + elsif ($last->{type} eq 'COMPLEX') { + $yaml .= ":"; + $last->{type} = 'COMPLEXVALUE'; + } + else { + die "Unexpected"; + } } if ($props) { - $yaml .= " $props\n"; - } - else { - $new_append = 1; + $yaml .= " $props"; + $newline = 1; } } + if (length $yaml) { + $column = substr($yaml, -1) eq "\n" ? 0 : 1; + } $self->writer->write($yaml); - my $new_info = { index => 0, indent => $new_indent, info => $info, append => $new_append }; + my $new_info = { + index => 0, indent => $new_indent, info => $info, + newline => $newline, + column => $column, + }; if (($info->{style} || '') eq YAML_FLOW_MAPPING_STYLE) { # $new_info->{type} = 'FLOWMAP'; $new_info->{type} = 'MAP'; @@ -131,7 +143,6 @@ sub mapping_start_event { } push @{ $stack }, $new_info; $last->{index}++; - $last->{append} = 0; } sub mapping_end_event { @@ -140,20 +151,23 @@ sub mapping_end_event { my $stack = $self->event_stack; my $last = pop @{ $stack }; + my $column = $last->{column}; if ($last->{index} == 0) { my $indent = $last->{indent}; my $zero_indent = $last->{zero_indent}; if ($last->{zero_indent}) { $indent .= ' ' x $self->indent; } - if ($last->{append}) { + if ($last->{column}) { $self->writer->write(" {}\n"); } else { $self->writer->write("$indent\{}\n"); } + $column = 0; } $last = $stack->[-1]; + $last->{column} = $column; if ($last->{type} eq 'SEQ') { } elsif ($last->{type} eq 'MAP') { @@ -173,6 +187,7 @@ sub sequence_start_event { my $new_indent = $indent; my $yaml = ''; + my $writer = $self->writer; my $props = ''; my $anchor = $info->{anchor}; my $tag = $info->{tag}; @@ -184,62 +199,59 @@ sub sequence_start_event { } $props = join ' ', grep defined, ($anchor, $tag); - my $new_append = 0; + my $newline = 0; my $zero_indent = 0; - my $append = $last->{append}; if ($last->{type} eq 'DOC') { - if ($append and $props) { - $yaml .= " $props"; - } - elsif ($props) { - $yaml .= "$props"; - } - if ($append or $props) { - $yaml .= "\n"; - } + $newline = $last->{newline}; } else { + if ($last->{newline}) { + $yaml .= "\n"; + $last->{column} = 0; + $last->{newline} = 0; + } if ($last->{type} eq 'MAPVALUE') { $zero_indent = 1; + $newline = 1; } else { - if ($append) { - $yaml .= ' '; - } - else { - $yaml .= $indent; - } - $new_indent .= ' ' x $self->indent; - unless ($props) { - $new_append = 1; - } + $yaml .= $last->{column} ? ' ' : $indent; if ($last->{type} eq 'SEQ') { + $new_indent .= ' ' x $self->indent; $yaml .= "-"; } elsif ($last->{type} eq 'MAP') { + $new_indent .= ' ' x $self->indent; $yaml .= "?"; $last->{type} = 'COMPLEX'; + $zero_indent = 1; } elsif ($last->{type} eq 'COMPLEXVALUE') { + $new_indent .= ' ' x $self->indent; $yaml .= ":"; + $zero_indent = 1; } + $last->{column} = 1; } - if ($props) { - $yaml .= " $props"; - } - if (not $new_append) { - $yaml .= "\n"; - } + } + if ($props) { + $newline = 1; + $yaml .= $last->{column} ? ' ' : $indent; + $yaml .= $props; } $self->writer->write($yaml); $last->{index}++; - $last->{append} = 0; + my $column = $last->{column}; + if (length $yaml) { + $column = substr($yaml, -1) eq "\n" ? 0 : 1; + } my $new_info = { index => 0, indent => $new_indent, info => $info, - append => $new_append, zero_indent => $zero_indent, + newline => $newline, + column => $column, }; if (($info->{style} || '') eq YAML_FLOW_SEQUENCE_STYLE) { $new_info->{type} = 'FLOWSEQ'; @@ -256,20 +268,20 @@ sub sequence_end_event { my $stack = $self->event_stack; my $last = pop @{ $stack }; + my $column = $last->{column};; if ($last->{index} == 0) { my $indent = $last->{indent}; my $zero_indent = $last->{zero_indent}; if ($last->{zero_indent}) { $indent .= ' ' x $self->indent; } - if ($last->{append}) { - $self->writer->write(" []\n"); - } - else { - $self->writer->write("$indent\[]\n"); - } + my $yaml .= $last->{column} ? ' ' : $indent; + $yaml .= "[]\n"; + $self->writer->write("$yaml"); + $column = 0; } $last = $stack->[-1]; + $last->{column} = $column; if ($last->{type} eq 'MAP') { $last->{type} = 'MAPVALUE'; } @@ -364,7 +376,6 @@ sub scalar_event { } $props = join ' ', grep defined, ($anchor, $tag); - my $append = $last->{append}; my $style = $info->{style}; DEBUG and local $Data::Dumper::Useqq = 1; @@ -509,91 +520,74 @@ sub scalar_event { $pvalue .= $value; } my $multiline = ($style eq YAML_LITERAL_SCALAR_STYLE or $style eq YAML_FOLDED_SCALAR_STYLE); + my $newline = 0; + my $column = $last->{column}; + if ($last->{type} eq 'MAP' or $last->{type} eq 'SEQ') { + if ($last->{index} == 0 and $last->{newline}) { + $yaml .= "\n"; + $last->{column} = 0; + $last->{newline} = 0; + } + } if ($last->{type} eq 'MAP') { if ($props and not length $value) { $pvalue .= ' '; } my $new_event = 'MAPVALUE'; + $yaml .= $last->{column} ? ' ' : $indent; if ($multiline) { # oops, a complex key - if (not $append) { - $yaml .= $indent; - } - else { - $yaml .= " "; - } - $yaml .= "?"; - $append = 1; + $yaml .= "? "; $new_event = 'COMPLEXVALUE'; } - if ($append) { - $yaml .= " "; - } - else { - $yaml .= $indent; - } - $yaml .= $pvalue; if (not $multiline) { - $yaml .= ":"; + $pvalue .= ":"; } $last->{type} = $new_event; } - elsif ($last->{type} eq 'COMPLEXVALUE') { - if ($append) { - $yaml .= " "; - } - else { - $yaml .= $indent; - } - if (length $pvalue) { - $yaml .= ": $pvalue"; - } - else { - $yaml .= ":"; - } - if (not $multiline) { - $yaml .= "\n"; - } - $last->{type} = 'MAP'; - } else { if ($last->{type} eq 'MAPVALUE') { - if (length $pvalue) { - $yaml .= " $pvalue"; - } $last->{type} = 'MAP'; } - elsif ($last->{type} eq 'SEQ') { - if (not $append) { - $yaml .= $indent; + elsif ($last->{type} eq 'DOC') { + } + else { + $yaml .= $last->{column} ? ' ' : $indent; + if ($last->{type} eq 'COMPLEXVALUE') { + $last->{type} = 'MAP'; + $yaml .= ":"; } - else { - $yaml .= " "; + elsif ($last->{type} eq 'COMPLEX') { + $yaml .= ": "; } - $yaml .= "-"; - if (length $pvalue) { - $yaml .= " $pvalue"; + elsif ($last->{type} eq 'SEQ') { + $yaml .= "-"; } - } - elsif ($last->{type} eq 'DOC') { - if (length $pvalue) { - if ($append) { - $yaml .= " "; - } - $yaml .= $pvalue; + else { + die "Unexpected"; } + $last->{column} = 1; } - else { -# warn __PACKAGE__.':'.__LINE__.$".Data::Dumper->Dump([\$last], ['last']); - die "Unexpected"; + + if (length $pvalue) { + if ($last->{column}) { + $pvalue = " $pvalue"; + } } if (not $multiline) { - $yaml .= "\n"; + $pvalue .= "\n"; } } + $yaml .= $pvalue; + + $column = $last->{column}; $last->{index}++; - $last->{append} = 0; + $last->{newline} = $newline; + if (length $yaml) { + $column = substr($yaml, -1) eq "\n" ? 0 : 1; + } + $last->{column} = $column; $self->writer->write($yaml); } @@ -602,62 +596,75 @@ sub alias_event { my ($self, $info) = @_; my $stack = $self->event_stack; my $last = $stack->[-1]; - $last->{index}++; - my $append = $last->{append}; my $indent = $last->{indent}; my $alias = '*' . $info->{value}; - if ($last->{type} eq 'MAP') { - my $yaml = ''; - if ($append) { - $yaml .= " "; - } - else { - $yaml .= $indent; + my $yaml = ''; + if ($last->{type} eq 'MAP' or $last->{type} eq 'SEQ') { + if ($last->{index} == 0 and $last->{newline}) { + $yaml .= "\n"; + $last->{column} = 0; + $last->{newline} = 0; } - $self->writer->write("$yaml$alias :"); - $last->{type} = 'MAPVALUE'; } - elsif ($last->{type} eq 'MAPVALUE') { - $self->writer->write(" $alias\n"); - $last->{type} = 'MAP'; + $yaml .= $last->{column} ? ' ' : $indent; + if ($last->{type} eq 'MAP') { + $yaml .= "$alias :"; + $last->{type} = 'MAPVALUE'; } - elsif ($last->{type} eq 'SEQ') { - my $yaml = ''; - if (not $append) { - $yaml .= $indent; + else { + + if ($last->{type} eq 'MAPVALUE') { + $last->{type} = 'MAP'; + } + elsif ($last->{type} eq 'DOC') { + # TODO an alias at document level isn't actually valid } else { - $yaml .= " "; + if ($last->{type} eq 'COMPLEXVALUE') { + $last->{type} = 'MAP'; + $yaml .= ": "; + } + elsif ($last->{type} eq 'COMPLEX') { + $yaml .= ": "; + } + elsif ($last->{type} eq 'SEQ') { + $yaml .= "- "; + } + else { + die "Unexpected"; + } } - $yaml .= "- $alias\n"; - $self->writer->write($yaml); - } - elsif ($last->{type} eq 'DOC') { - # TODO an alias at document level isn't actually valid - $self->writer->write("$alias\n"); + $yaml .= "$alias\n"; } - else { - $self->writer->write("$indent: $alias\n"); - $last->{type} = 'MAP'; + + $self->writer->write("$yaml"); + $last->{index}++; + my $column = $last->{column}; + if (length $yaml) { + $column = substr($yaml, -1) eq "\n" ? 0 : 1; } - $last->{append} = 0; + $last->{column} = $column; } sub document_start_event { DEBUG and warn __PACKAGE__.':'.__LINE__.": +++ document_start_event\n"; my ($self, $info) = @_; - my $new_append = 0; + my $newline = 0; + my $column = 0; if ($info->{implicit}) { - $new_append = 0; } else { - $new_append = 1; + $newline = 1; $self->writer->write("---"); + $column = 1; } $self->set_event_stack([ - { type => 'DOC', index => 0, indent => '', info => $info, append => $new_append } + { + type => 'DOC', index => 0, indent => '', info => $info, + newline => $newline, column => $column, + } ]); } diff --git a/t/21.emit.t b/t/21.emit.t index f3dd71fb..68cfea97 100644 --- a/t/21.emit.t +++ b/t/21.emit.t @@ -56,6 +56,7 @@ push @skip, qw/ R4YG /; + # test push @skip, qw/ XLQ9 @@ -68,6 +69,10 @@ MJS9 /; +# TODO fix testsuite +# EXG3 +# 4QFQ + # unicode push @skip, qw/ H3Z8 @@ -82,20 +87,20 @@ my $testsuite = YAML::PP::Test->new( ); my %skip_yaml_equal = ( - '4MUZ' => 1, - '7ZZ5' => 1, + 'K858' => 1, 'X38W' => 1, - 'Q5MG' => 1, 'G4RS' => 1, - '9DXL' => 1, - '6ZKB' => 1, - '6SLA' => 1, '6CK3' => 1, '5TYM' => 1, '565N' => 1, + # fix testsuite + '4MUZ' => 1, '8KB6' => 1, '9BXH' => 1, + '6ZKB' => 1, + '6SLA' => 1, + '9DXL' => 1, ); my ($testcases) = $testsuite->read_tests( diff --git a/t/39.emitter-alias.t b/t/39.emitter-alias.t index e55d99e2..508f0ca5 100644 --- a/t/39.emitter-alias.t +++ b/t/39.emitter-alias.t @@ -68,11 +68,9 @@ my $exp = <<'EOM'; - *map - *map : foo *map : foo -- ? !!seq - [] +- ? !!seq [] : *map -- ? !!map - {} +- ? !!map {} : *map EOM cmp_ok($yaml, 'eq', $exp, "alias_event correct"); diff --git a/t/40.representers.t b/t/40.representers.t index d39275dc..ede5ffbb 100644 --- a/t/40.representers.t +++ b/t/40.representers.t @@ -25,7 +25,7 @@ use YAML::PP; my $yaml = $parser->dump_string($data); like($yaml, qr/o1: !Class1/, 'o1s\' class has a representer that converts it to a tag'); - like($yaml, qr/o2:\n \{\}/, 'o2s\' class doesn\'t have a representer. It gets converted to an empty hash'); + like($yaml, qr/o2: \{\}/, 'o2s\' class doesn\'t have a representer. It gets converted to an empty hash'); } { diff --git a/t/lib/YAML/PP/Test.pm b/t/lib/YAML/PP/Test.pm index 97f28da8..19ed9acf 100644 --- a/t/lib/YAML/PP/Test.pm +++ b/t/lib/YAML/PP/Test.pm @@ -698,6 +698,9 @@ sub compare_emit_yaml { push @{ $stats->{SAME_YAML} }, $id; } else { + local $Data::Dumper::Useqq = 1; + diag(' ' . Data::Dumper->Dump([$emit_yaml], ['emit_yaml'])); + diag(Data::Dumper->Dump([$exp_emit_yaml], ['exp_emit_yaml'])); push @{ $stats->{DIFF_YAML} }, $id; } }