rewrite deparse system
Matt S Trout [Wed, 28 Feb 2018 21:24:10 +0000 (21:24 +0000)]
lib/DX/Action/BindValue.pm
lib/DX/Deparse.pm
lib/DX/Proposition.pm
lib/DX/Role/BooleanValue.pm
lib/DX/Role/BoundValueAction.pm
lib/DX/Role/SimpleAction.pm
lib/DX/Utils.pm
lib/DX/Value/Dict.pm
lib/DX/Value/Number.pm
lib/DX/Value/String.pm
lib/DX/Value/Unset.pm

index a355935..c8f43d1 100644 (file)
@@ -8,6 +8,18 @@ with 'DX::Role::SimpleAction';
 
 has new_value => (is => 'ro', required => 1);
 
+sub for_deparse {
+  my ($self) = @_;
+  [ statement => [
+    [ symbol => 'BindValue' ],
+    [ value_path => $self->target_path ],
+    [ value_path => $self->new_value
+                         ->action_builder
+                         ->inner_action_builder
+                         ->target_path ],
+  ] ];
+}
+
 sub _build__updates {
   my ($self) = @_;
   DX::Update::SetValue->new(
index 0b01d2b..74d8eb3 100644 (file)
@@ -1,62 +1,34 @@
 package DX::Deparse;
 
+use Scalar::Util qw(blessed);
 use DX::Class;
 
 sub indent_by { '    ' }
 
-sub max_width { 78 }
-
-sub _inner_meta {
-  my ($self, $ometa) = @_;
-  +{ %$ometa, width_left => $ometa->{width_left} - length $self->indent_by };
-}
-
-sub _indent_one {
-  my ($self, $to_indent) = @_;
-  $to_indent =~ s/^/${\$self->indent_by}/mg;
-  $to_indent;
-}
-
-sub fmt {
+sub format {
   my ($self, $thing) = @_;
-  $self->_fmt($thing, { width_left => $self->max_width })."\n";
-}
-
-sub _fmt {
-  my ($self, $thing, $meta) = @_;
-  return '{}' unless defined($thing);
-  return $thing unless ref($thing);
-  my $type = join'_', split '::', lc +(ref($thing) =~ /^(?:DX::)?(.*)/)[0];
-  $self->${\"_fmt_${type}"}($thing, $meta);
-}
-
-sub _fmt_error_typetiny_assertion {
-  $_[1]->to_string;
+  local our $Indent_Level = 0;
+  $self->_format($thing);
 }
 
-sub _fmt_value_dict {
-  my ($self, $dict, $meta) = @_;
-  my $chunks = $self->_fmt_pairs([
-    map [ $_, $dict->get_member_at($_) ], $dict->index_list
-  ], $meta);
-  return '{{ }}' unless $chunks =~ /\S/;
-  s/^\s+//, s/\n\s+/ /g for (my $maybe = $chunks);
-  return "{{ ${maybe} }}" if length($maybe) < $meta->{width_left};
-  "{{\n${chunks}\n}}";
+sub _format {
+  my ($self, $thing) = @_;
+  my ($as, $data) = @{blessed($thing) ? $thing->for_deparse : $thing};
+  $self->${\"_format_as_${as}"}($data);
 }
 
-sub _fmt_pairs {
-  my ($self, $pairs, $ometa) = @_;
-  my $imeta = $self->_inner_meta($ometa);
-  $self->_indent_one(join "\n", map {
-    join ' ', map $self->_fmt($_, $imeta), @$_
-  } @$pairs);
+sub _format_indented {
+  my ($self, $cb) = @_;
+  our $Indent_Level;
+  local $Indent_Level = $Indent_Level + 1;
+  my $unindented = $cb->();
+  (my $indented = $unindented) =~ s/^/${\$self->indent_by}/mg;
+  return $indented;
 }
 
-sub _fmt_value_string {
-  my ($self, $string) = @_;
+sub _format_as_string {
+  my ($self, $val) = @_;
   # TODO: multiline handling
-  my $val = $string->string_value;
   if ($val =~ /^\w+$/) {
     qq{'${val}'}
   } else {
@@ -64,158 +36,67 @@ sub _fmt_value_string {
   }
 }
 
-sub _fmt_value_number { $_[1]->number_value }
-
-sub _fmt_value_true { 'true' }
-
-sub _fmt_value_false { 'false' }
-
-sub _fmt_value_unset { 'unset' }
-
-sub _fmt_object {
-  my ($self, $pairs, $meta) = @_;
-  my $chunks = $self->_fmt_pairs($pairs, $meta);
-  return '{ }' unless $chunks =~ /\S/;
-  s/^\s+//, s/\n\s+/ /g for (my $maybe = $chunks);
-  return "{ ${maybe} }" if length($maybe) < $meta->{width_left};
-  "{\n${chunks}\n}"
-}
-
-sub _fmt_hypothesis {
-  my ($self, $hyp, $meta) = @_;
-  $self->_fmt_object([
-    map [ $_ => $hyp->$_ ],
-      qw(actions resolved_propositions scope)
-  ], $meta);
-}
-
-sub _fmt_array {
-  my ($self, $ary, $ometa) = @_;
-  my $imeta = $self->_inner_meta($ometa);
-  my $chunks = $self->_indent_one(
-    join "\n", map $self->_fmt($_, $imeta), @$ary
-  );
-  return '{ }' unless $chunks =~ /\S/;
-  "{\n${chunks}\n}";
-}
+sub _format_as_symbol { $_[1] }
 
-sub _fmt_glob {
-  my ($self, $glob, $meta) = @_;
-  return ((''.*$glob) =~ /::([A-Z_]+)$/)[0];
+sub _format_as_maybe_bareword {
+  my ($self, $maybe_bareword) = @_;
+  # should stringify if required
+  return $maybe_bareword;
 }
 
-sub _fmt_action_setvalue {
-  my ($self, $action, $meta) = @_;
-  $self->_fmt_action_generic(SetValue => $action, $meta);
-}
+sub _format_as_number { $_[1] }
 
-sub _fmt_action_addvalue {
-  my ($self, $action, $meta) = @_;
-  $self->_fmt_action_generic(AddValue => $action, $meta);
-}
+sub _format_as_boolean { $_[1] ? 'true' : 'false' }
 
-sub _fmt_action_bindvalue {
-  my ($self, $action, $meta) = @_;
-  my $path = join '.', map $self->_fmt($_, $meta), @{$action->target_path};
-  my $bound_path = join '.',
-                     map $self->_fmt($_, $meta),
-                       @{$action->new_value
-                                ->action_builder
-                                ->inner_action_builder
-                                ->target_path};
-  join ' ', BindValue => $path, $bound_path;
-}
-
-sub _fmt_action_addboundvalue {
-  my ($self, $action, $meta) = @_;
-  $self->_fmt_action_generic(AddBoundValue => $action, $meta);
-}
-
-sub _fmt_action_setboundvalue {
-  my ($self, $action, $meta) = @_;
-  $self->_fmt_action_generic(SetBoundValue => $action, $meta);
-}
+sub _format_as_unset { 'unset' }
 
-sub _fmt_action_generic {
-  my ($self, $name, $action, $meta) = @_;
-  my $path = join '.', map $self->_fmt($_, $meta), @{$action->target_path};
-  join ' ', $name, $path, $self->_fmt($action->new_value, $meta);
+sub _format_as_array {
+  my ($self, $members) = @_;
+  join ' ', '{[', (map $self->_format($_), @$members), ']}';
 }
 
-sub _fmt_resolvedpropositionset {
-  my ($self, $rps, $meta) = @_;
-  $self->_fmt_object([
-    map {
-      [ $_, [
-        map bless([ @$_ ], 'DX::Dependency'),
-          map @{$_}[1..$#$_],
-            @{$rps->dependencies_for($_)}
-      ] ]
-    } @{$rps->propositions},
-  ], $meta);
+sub _format_as_dict {
+  my ($self, $members) = @_;
+  join ' ', '{{', (
+    map +(
+      $self->_format_as_maybe_bareword($_),
+      $self->_format($members->{$_}),
+    ), sort keys %$members
+  ), '}}';
 }
 
-sub _fmt_dependency {
-  my ($self, $dep, $meta) = @_;
-  '{ '.join(' ', map $self->_fmt($_, $meta), @$dep).' }'
+sub _format_as_statement {
+  my ($self, $parts) = @_;
+  join ' ', map $self->_format($_), @$parts;
 }
 
-sub _fmt_proposition {
-  my ($self, $prop, $meta) = @_;
-  join ' ',
-    $prop->predicate,
-    map $self->_fmt($_, $meta),
-      map +((!ref($_) and $prop->introduced_names->{$_}) ? "?$_" : $_),
-        @{$prop->args};
+sub _format_as_value_path {
+  my ($self, $parts) = @_;
+  join '.', map $self->_format_as_maybe_bareword($_), @$parts;
 }
 
-sub _fmt_scope {
-  my ($self, $scope, $meta) = @_;
-  $self->_fmt_object([
-    [ W => $scope->globals ],
-    map [ $_ => $scope->locals->[$_] ], 0..$#{$scope->locals}
-  ], $meta);
+sub _format_as_list {
+  my ($self, $members) = @_;
+  join "\n", '{', (
+    map $self->_format_indented($self->curry::_format($_)), @$members
+  ), '}';
 }
 
-sub _fmt_searchstate {
-  my ($self, $ss, $meta) = @_;
-  $self->_fmt_object([
-    [ adjustments_made => '{...}' ],
-    [ current_hypothesis => $ss->current_hypothesis ],
-  ], $meta);
+sub _format_as_pairs {
+  my ($self, $members) = @_;
+  join "\n", '{', (
+    map $self->_format_indented(sub {
+          $self->_format_as_maybe_bareword($_->[0])
+            .' '.$self->_format($_->[1])
+        }), @$members
+  ), '}';
 }
 
-sub _fmt_step_considerproposition {
-  my ($self, $step, $meta) = @_;
-  'consider '.$self->_fmt($step->proposition, $meta);
+sub _format_as_block {
+  my ($self, $members) = @_;
+  join "\n", '{', (
+    map $self->_format_indented($self->curry::_format($_)), @$members
+  ), '}';
 }
 
-sub _fmt_step_resolveproposition {
-  my ($self, $step, $meta) = @_;
-  'resolve '.$self->_fmt_object([
-    [ actions => $step->actions ],
-    ($step->alternative_step
-      ? [ alternative_step => '...' ]
-      : ()),
-    [ depends_on => [
-      map bless([ @$_ ], 'DX::Dependency'),
-        map @{$_}[1..$#$_],
-          @{$step->depends_on}
-    ] ],
-  ], $meta);
-}
-
-sub _fmt_step_backtrack { 'backtrack' }
-
-sub _fmt_step_markassolution { 'mark as solution' }
-
-sub _fmt_step_enterrecheck {
-  my ($self, $step, $meta) = @_;
-  'recheck '.$self->_fmt($step->proposition_list->[0], $meta);
-}
-
-sub _fmt_step_completerecheck { 'complete recheck' }
-
-sub _fmt_step_failrecheck { 'fail recheck' }
-
 1;
index 1415276..b173ca8 100644 (file)
@@ -11,6 +11,18 @@ has introduced_names => (is => 'ro', isa => HashRef[One], required => 1);
 
 has required_names => (is => 'ro', isa => HashRef[One], required => 1);
 
+sub for_deparse {
+  my ($self) = @_;
+  [ statement => [
+    [ symbol => $self->predicate ],
+    map {
+      ref($_)
+        ? $_
+        : [ symbol => $self->introduced_names->{$_} ? "?$_" : $_ ]
+    } @{$self->args}
+  ] ];
+}
+
 sub resolve_for {
   my ($self, $scope) = @_;
   my $predicate = $scope->lookup_predicate($self->predicate);
index 336e545..37f3097 100644 (file)
@@ -4,6 +4,8 @@ use DX::Role;
 
 with 'DX::Role::Value';
 
+sub for_deparse { [ boolean => $_[0]->is_true ] }
+
 requires 'is_true';
 
 1;
index 37b317b..3bd125e 100644 (file)
@@ -16,6 +16,15 @@ has inner_action => (is => 'ro', required => 1);
 
 requires 'update_class';
 
+sub for_deparse {
+  my ($self) = @_;
+  [ statement => [
+    [ symbol => (split('::',ref($self)))[-1] ],
+    [ value_path => $self->target_path ],
+    $self->new_value,
+  ] ];
+}
+
 sub dry_run {
   my ($self, $hyp) = @_;
   my ($outer_hyp, @inner_events) = $self->inner_action->dry_run(
index 9b6086f..62bf837 100644 (file)
@@ -10,6 +10,15 @@ has _updates => (is => 'lazy');
 
 requires '_build__updates';
 
+sub for_deparse {
+  my ($self) = @_;
+  [ statement => [
+    [ symbol => (split('::',ref($self)))[-1] ],
+    [ value_path => $self->target_path ],
+    $self->new_value,
+  ] ];
+}
+
 sub dry_run {
   my ($self, $hyp) = @_;
   my ($scope, @events) = $hyp->scope->apply_updates($self->_updates);
index 37a0829..4c9f0b8 100644 (file)
@@ -115,7 +115,7 @@ sub proposition {
       DX::Deparse->new;
     };
     my ($thing) = @_;
-    $dp->fmt($thing);
+    $dp->format($thing);
   }
 }
 
index 13cec8d..8c61afe 100644 (file)
@@ -14,6 +14,10 @@ has '+action_builder' => (
 
 has members => (is => 'ro', required => 1);
 
+sub for_deparse {
+  [ dict => $_[0]->members ]
+}
+
 sub index_list { sort keys %{$_[0]->members} }
 
 sub get_member_at {
index 74e30ac..10500df 100644 (file)
@@ -6,6 +6,8 @@ with 'DX::Role::Value';
 
 has number_value => (is => 'ro', required => 1);
 
+sub for_deparse { [ number => $_[0]->number_value ] }
+
 sub to_data { 0+$_[0]->number_value }
 
 1;
index e1a55b6..33b110a 100644 (file)
@@ -6,6 +6,8 @@ with 'DX::Role::Value';
 
 has string_value => (is => 'ro', required => 1);
 
+sub for_deparse { [ string => $_[0]->string_value ] }
+
 sub to_data { ''.$_[0]->string_value }
 
 1;
index 507bd4f..84d3b58 100644 (file)
@@ -4,6 +4,8 @@ use DX::Class;
 
 with 'DX::Role::Value';
 
+sub for_deparse { [ 'unset' ] }
+
 sub is_set { 0 }
 
 sub to_data { undef }