slightly less incomplete deparse output
[scpubgit/DX.git] / lib / DX / Deparse.pm
1 package DX::Deparse;
2
3 use DX::Class;
4
5 sub indent_by { '    ' }
6
7 sub max_width { 78 }
8
9 sub _inner_meta {
10   my ($self, $ometa) = @_;
11   +{ %$ometa, width_left => $ometa->{width_left} - length $self->indent_by };
12 }
13
14 sub _indent_one {
15   my ($self, $to_indent) = @_;
16   $to_indent =~ s/^/${\$self->indent_by}/mg;
17   $to_indent;
18 }
19
20 sub fmt {
21   my ($self, $thing) = @_;
22   $self->_fmt($thing, { width_left => $self->max_width })."\n";
23 }
24
25 sub _fmt {
26   my ($self, $thing, $meta) = @_;
27   return $thing unless ref($thing);
28   my $type = join'_', split '::', lc +(ref($thing) =~ /^(?:DX::)?(.*)/)[0];
29   $self->${\"_fmt_${type}"}($thing, $meta);
30 }
31
32 sub _fmt_value_dict {
33   my ($self, $dict, $meta) = @_;
34   my $chunks = $self->_fmt_pairs([
35     map [ $_, $dict->get_member_at($_) ], $dict->index_list
36   ], $meta);
37   return '{{ }}' unless $chunks =~ /\S/;
38   "{{\n${chunks}\n}}";
39 }
40
41 sub _fmt_pairs {
42   my ($self, $pairs, $ometa) = @_;
43   my $imeta = $self->_inner_meta($ometa);
44   $self->_indent_one(join "\n", map {
45     join ' ', map $self->_fmt($_, $imeta), @$_
46   } @$pairs);
47 }
48
49 sub _fmt_value_string {
50   my ($self, $string) = @_;
51   # TODO: multiline handling
52   my $val = $string->string_value;
53   if ($val =~ /^\w+$/) {
54     qq{'${val}'}
55   } else {
56     qq{{'${val}'}}
57   }
58 }
59
60 sub _fmt_value_number { $_[1]->number_value }
61
62 sub _fmt_value_true { 'true' }
63
64 sub _fmt_value_false { 'false' }
65
66 sub _fmt_value_unset { 'unset' }
67
68 sub _fmt_object {
69   my ($self, $pairs, $meta) = @_;
70   my $chunks = $self->_fmt_pairs($pairs, $meta);
71   return '{ }' unless $chunks =~ /\S/;
72   "{\n${chunks}\n}"
73 }
74
75 sub _fmt_hypothesis {
76   my ($self, $hyp, $meta) = @_;
77   $self->_fmt_object([
78     map [ $_ => $hyp->$_ ],
79       qw(actions outstanding_propositions resolved_propositions scope)
80   ], $meta);
81 }
82
83 sub _fmt_array {
84   my ($self, $ary, $ometa) = @_;
85   my $imeta = $self->_inner_meta($ometa);
86   my $chunks = $self->_indent_one(
87     join "\n", map $self->_fmt($_, $imeta), @$ary
88   );
89   return '{ }' unless $chunks =~ /\S/;
90   "{\n${chunks}\n}";
91 }
92
93 sub _fmt_glob {
94   my ($self, $glob, $meta) = @_;
95   return ((''.*$glob) =~ /::([A-Z_]+)$/)[0];
96 }
97
98 sub _fmt_action_setvalue {
99   my ($self, $action, $meta) = @_;
100   $self->_fmt_action_generic(SetValue => $action, $meta);
101 }
102
103 sub _fmt_action_addvalue {
104   my ($self, $action, $meta) = @_;
105   $self->_fmt_action_generic(AddValue => $action, $meta);
106 }
107
108 sub _fmt_action_generic {
109   my ($self, $name, $action, $meta) = @_;
110   my $path = join '.', map $self->_fmt($_, $meta), @{$action->target_path};
111   join ' ', $name, $path, $self->_fmt($action->new_value, $meta);
112 }
113
114 sub _fmt_resolvedpropositionset {
115   my ($self, $rps, $meta) = @_;
116   $self->_fmt_object([
117     map {
118       [ $_, $rps->dependencies_for($_) ]
119     } @{$rps->propositions},
120   ], $meta);
121 }
122
123 sub _fmt_proposition {
124   my ($self, $prop, $meta) = @_;
125   join ' ',
126     $prop->predicate,
127     map $self->_fmt($_, $meta), @{$prop->args};
128 }
129
130 sub _fmt_scope {
131   my ($self, $scope, $meta) = @_;
132   $self->_fmt_object([
133     [ W => $scope->globals ],
134     map [ $_ => $scope->locals->[$_] ], 0..$#{$scope->locals}
135   ], $meta);
136 }
137
138 sub _fmt_searchstate {
139   my ($self, $ss, $meta) = @_;
140   $self->_fmt_object([
141     [ alternatives => '{...}' ],
142     [ current_hypothesis => $ss->current_hypothesis ],
143   ], $meta);
144 }
145
146 1;