File Coverage

blib/lib/Soar/Production/Printer.pm
Criterion Covered Total %
statement 200 210 95.2
branch 50 58 86.2
condition n/a
subroutine 41 42 97.6
pod 1 1 100.0
total 292 311 93.8


line stmt bran cond sub pod time code
1             #
2             # This file is part of Soar-Production
3             #
4             # This software is copyright (c) 2012 by Nathan Glenn.
5             #
6             # This is free software; you can redistribute it and/or modify it under
7             # the same terms as the Perl 5 programming language system itself.
8             #
9             package Soar::Production::Printer;
10             # ABSTRACT: Print Soar productions
11 2     2   3139 use strict;
  2         6  
  2         113  
12 2     2   12 use warnings;
  2         5  
  2         110  
13              
14             our $VERSION = '0.03'; # VERSION
15              
16 2     2   867 use Soar::Production::Parser;
  2         4  
  2         81  
17 2     2   15 use Carp;
  2         3  
  2         143  
18             use Exporter::Easy (
19 2         18 OK => [qw(tree_to_text)]
20 2     2   12 );
  2         6  
21              
22             #default behavior is to read the input Soar file and output another one; worthless except for testing
23             _run(shift) unless caller;
24              
25             #pass in a Soar grammar file name. Parse the file, then reconstruct it and print to STDOUT.
26             sub _run {
27 0     0   0 my ($file) = @_;
28              
29 0         0 my $parser = Soar::Production::Parser->new();
30 0         0 my $trees = $parser->productions(file => $file, parse => 1);
31 0 0       0 croak "parse failure\n" if ( $#$trees == -1 );
32              
33 0         0 my $text = tree_to_text($$trees[0]);
34 0 0       0 my $tree = $parser->parse_text($text)
35             or croak 'illegal production printed';
36              
37 0         0 print $text;
38 0         0 return;
39             }
40              
41             sub tree_to_text{
42 822     822 1 128354877 my ($tree) = @_;
43              
44             #traverse tree and construct the Soar production text
45 822         2518 my $text = 'sp {';
46              
47 822         8374 $text .= _name( $tree->{name} );
48 822         3560 $text .= _doc( $tree->{doc} );
49 822         3441 $text .= _flags( $tree->{flags} );
50              
51 822         2713 $text .= _LHS( $tree->{LHS} );
52 822         2000 $text .= "\n-->\n\t";
53 822         2839 $text .= _RHS( $tree->{RHS} );
54 822         1683 $text .= "\n}";
55              
56 822         4933 return $text;
57             }
58              
59             sub _name {
60 822     822   2139 my $name = shift;
61 822         4259 return $name . "\n\t";;
62             }
63              
64             sub _doc {
65 822     822   1734 my $doc = shift;
66 822 100       3898 if(defined $doc){
67 48         226 return '"' . $doc . '"' . "\n\t";
68             }
69 774         2321 return '';
70             }
71              
72             sub _flags {
73 822     822   1861 my $flags = shift;
74 822         2273 my $text = '';
75 822         2411 for my $flag (@$flags){
76 104         541 $text .= ':' . $flag . "\n\t";
77             }
78 822         2071 return $text;
79             }
80              
81             sub _LHS {
82 822     822   1475 my $LHS = shift;
83 2226         4384 return join "\n\t",
84 822         1512 map { _condition($_) } @{ $LHS->{conditions} };
  822         3589  
85             }
86              
87             sub _condition {
88 2271     2271   3139 my $condition = shift;
89 2271         2857 my $text = '';
90              
91 2271 100       7729 $text .= '-'
92             if($condition->{negative} eq 'yes');
93              
94 2271         6153 $text .= _positive_condition( $condition->{condition} );
95              
96 2271         6998 return $text;
97             }
98              
99             sub _positive_condition {
100 2271     2271   3170 my $condition = shift;
101              
102 2271 100       6939 return _conjunction( $condition->{conjunction} )
103             if($condition->{conjunction});
104              
105 2249         7838 return _condsForOneId($condition);
106             }
107              
108             sub _condsForOneId {
109 2249     2249   3261 my $condsForOneId = shift;
110 2249         3522 my $text = '(';
111 2249         8062 my ($type, $idTest, $attrValueTests) =
112             (
113             $condsForOneId->{condType},
114             $condsForOneId->{idTest},
115             $condsForOneId->{attrValueTests}
116             );
117              
118 2249 100       6802 $text .= $type
119             if(defined $type);
120              
121 2249 50       7254 $text .= ' ' . _test($idTest)
122             if(defined $idTest);
123              
124 2249 50       6844 if($#$attrValueTests != -1){
125 2249         2781 $text .= ' ';
126 2249         4883 $text .= join ' ', map { _attrValueTests($_) } @$attrValueTests;
  4624         8310  
127             }
128              
129 2249         3457 $text .= ')';
130 2249         6089 return $text;
131             }
132              
133             sub _test {
134 12087     12087   15796 my $test = shift;
135              
136 12087 100       30899 if(exists $test->{conjunctiveTest}){
137 221         643 return _conjunctiveTest(
138             $test->{conjunctiveTest} );
139             }
140              
141 11866         29204 return _simpleTest( $test->{simpleTest} );
142             }
143              
144             sub _conjunctiveTest {
145 221     221   459 my $conjTest = shift;
146 221         494 my $text = '{';
147 498         996 $text .= join ' ',
148 221         597 map { _simpleTest($_) } @$conjTest;
149 221         453 $text .= '}';
150 221         597 return $text;
151             }
152              
153             sub _simpleTest {
154 12364     12364   14982 my $test = shift;
155 12364 100       30331 return _disjunctionTest($test->{disjunctionTest})
156             if( exists $test->{disjunctionTest} );
157 12281 100       27060 return _relationalTest($test->{relationTest} )
158             if( exists $test->{relationTest} );
159 11951         21008 return _singleTest($test);
160             }
161              
162             sub _disjunctionTest {
163 83     83   187 my $test = shift;
164 83         158 my $text = '<< ';
165 83         179 $text .= join ' ', map { _constant($_) } @$test;
  190         329  
166 83         216 $text .= ' >>';
167 83         252 return $text;
168             }
169              
170             sub _relationalTest {
171 330     330   598 my $test = shift;
172              
173 330         1079 my $text = _relation( $test->{relation} );
174 330         513 $text .= ' ';
175 330         952 $text .= _singleTest( $test->{test} );
176              
177 330         919 return $text;
178             }
179              
180             sub _relation {
181 330     330   754 my $relation = shift;
182 330         808 return $relation;
183             }
184              
185             sub _singleTest {
186 12281     12281   13612 my $test = shift;
187 12281 100       29716 return _variable($test->{variable})
188             if( exists $test->{variable} );
189 6537         10184 return _constant($test);
190             }
191              
192             sub _attrValueTests {
193 4624     4624   6117 my $attrValuetests = shift;
194 4624         17692 my ($negative, $attrs, $values) =
195             (
196             $attrValuetests->{negative},
197             $attrValuetests->{attrs},
198             $attrValuetests->{values}
199             );
200 4624         5114 my $text = '';
201 4624 100       9213 $text .= '-'
202             if($negative eq 'yes');
203 4624         8026 $text .= _attTest($attrs);
204              
205 4624 100       13866 if($#$values != -1){
206 4518         4797 $text .= ' ';
207 4518         7268 $text .= join ' ', map { _valueTest($_) } @$values;
  4732         7561  
208             }
209 4624         18762 return $text;
210             }
211              
212             sub _attTest {
213 4624     4624   4933 my $attTest = shift;
214 4624         6092 my $text = '^';
215 4624         8870 $text .= join '.', map { _test($_) } @$attTest;
  5106         8469  
216 4624         9883 return $text;
217             }
218              
219             sub _valueTest {
220 4732     4732   7004 my $valueTest = shift;
221 4732         5585 my $text = '';
222              
223 4732 50       13021 if(exists $valueTest->{test}){
224 4732         9043 $text = _test( $valueTest->{test} );
225             }else{
226             #condsForOneId
227 0         0 $text = _condsForOneId($valueTest->{conds});
228             }
229              
230 4732 100       13024 $text .= '+'
231             if($valueTest->{'+'} eq 'yes');
232              
233 4732         12261 return $text
234             }
235              
236             sub _conjunction {
237 22     22   56 my $conjunction = shift;
238 22         55 my $text = '{';
239 22         74 $text .= join "\n\t", map { _condition($_) } @$conjunction;
  45         119  
240 22         73 $text .= '}';
241 22         77 return $text;
242             }
243              
244             sub _RHS {
245 822     822   1349 my $RHS = shift;
246 822         1243 my $text = '';
247 822         1805 for my $action (@$RHS){
248 2472         7150 $text .= _action($action);
249 2472         5638 $text .= "\n\t";
250             }
251 822         5338 return $text;
252             }
253              
254             sub _action {
255 2472     2472   3313 my $action = shift;
256 2472 100       6703 if(exists $action->{funcCall}){
257 230         677 return _funcCall($action->{funcCall});
258             }
259              
260 2242         3151 my $text = '(';
261 2242         5037 $text .= _variable($action->{variable});
262 2242         3036 $text .= ' ';
263 5133         8918 $text .= join ' ',
264 2242         3512 map {_attrValueMake($_)} @{ $action->{attrValueMake} };
  2242         5962  
265 2242         3866 $text .= ')';
266 2242         4388 return $text;
267             }
268              
269             sub _attrValueMake {
270 5133     5133   6411 my $attrValueMake = shift;
271 5133         14378 my ($attr, $valueMake) =
272             ($attrValueMake->{attr}, $attrValueMake->{valueMake});
273              
274 5133         14464 my $text = _attr($$attr[0]);
275 5133 100       12894 if($#$attr != 0){
276 15         22 $text .= '.';
277 15         40 $text .= join '.',
278 15         71 map { _variableOrSymConstant($_) } @$attr[1..$#$attr];
279             }
280              
281 5133         6808 $text .= ' ';
282 5133         9103 $text .= join ' ', map{_valueMake($_)} @$valueMake;
  6257         10901  
283              
284 5133         12712 return $text;
285             }
286              
287             sub _attr {
288 5133     5133   6540 my $attr = shift;
289 5133         8338 return '^' . _variableOrSymConstant($attr);
290             }
291              
292             sub _variableOrSymConstant {
293 5148     5148   5533 my $vOs = shift;
294 5148 100       12983 return _variable($vOs->{variable})
295             if(exists $vOs->{variable});
296 5097         7532 return _symConstant($vOs);
297              
298             }
299              
300             sub _valueMake {
301 6257     6257   8225 my $valueMake = shift;
302 6257         17223 my ($rhsValue, $preferences) =
303             ($valueMake->{rhsValue}, $valueMake->{preferences});
304 6257         10689 my $text = _rhsValue($rhsValue);
305             #there will always be at least one preference; '+' is default
306 6257         8908 $text .= ' ';
307 6257         10401 $text .= join ',', map { _preference($_) } @$preferences;
  6369         10324  
308 6257         17233 return $text;
309             }
310              
311             sub _preference {
312 6369     6369   7896 my $preference = shift;
313 6369         13542 my $text = $preference->{value};
314 6369 100       15956 if($preference->{type} eq 'binary'){
315 13         84 $text .= ' ' . _rhsValue( $preference->{compareTo} );
316             }
317 6369         15696 return $text;
318             }
319              
320             #variable | constant | "(crlf)" | funcCall
321             sub _rhsValue {
322 7514     7514   8040 my $rhsValue = shift;
323              
324 7514 100       17569 return '(crlf)'
325             if($rhsValue eq '(crlf)');
326              
327 7319 100       17031 if(exists $rhsValue->{variable}){
328 3605         7758 return _variable($rhsValue->{variable});
329             }
330 3714 100       7575 if(exists $rhsValue->{constant}){
331 3609         5079 return _constant($rhsValue);
332             }
333 105 50       316 if(exists $rhsValue->{function}){
334 105         265 return _funcCall($rhsValue);
335             }
336 0         0 return $rhsValue;
337             }
338              
339             #(write |Hello World| |hello again|)
340             sub _funcCall {
341 335     335   424 my $funcCall = shift;
342              
343 335         897 my ($name, $args) =
344             (_funcName($funcCall->{function}), $funcCall->{args});
345 335         580 my $text = '(' . $name;
346 335 100       843 if($#$args != -1){
347 303         348 $text .= ' ';
348 303         533 $text .= join ' ', map {_rhsValue($_)} @$args;
  1244         1978  
349             }
350 335         1145 return $text . ')';
351             }
352              
353             # arithmetic operator (+ - * /) or a symConstant, being the name of some function
354             sub _funcName {
355 335     335   394 my $funcName = shift;
356              
357 335 100       858 if(ref $funcName eq 'HASH'){
358 233         365 return _symConstant($funcName);
359             }
360 102         290 return $funcName;
361             }
362              
363             sub _variable {
364 11642     11642   17605 my $variable = shift;
365 11642         33012 return '<' . $variable . '>'
366             }
367              
368             sub _constant {
369 10336     10336   10198 my $constant = shift;
370 10336         27176 my ($type, $value) = ($constant->{type}, $constant->{constant});
371              
372 10336 100       25902 return _symConstant($value) if($type eq 'sym');
373 2454 100       6405 return _int($value) if($type eq 'int');
374 49         81 return _float($value);#only other type is 'float'
375             }
376              
377             sub _float {
378 49     49   58 my $float = shift;
379 49         125 return $float;
380             }
381              
382             sub _int {
383 2405     2405   2837 my $int = shift;
384 2405         6267 return $int;
385             }
386              
387             #either string or quoted
388             sub _symConstant {
389 13212     13212   12499 my $symConstant = shift;
390 13212         38830 my ($type, $value) = ($symConstant->{type}, $symConstant->{value});
391 13212 100       33883 return _string($value) if($type eq 'string');
392 638         1104 return _quoted($value);
393             }
394              
395             sub _string {
396 12574     12574   48670 return shift;
397             }
398              
399             sub _quoted {
400 638     638   3466 my $text = shift;
401              
402             #escape vertical bars
403 638         963 $text =~ s/\|/\\|/g;
404 638         2428 return '|' . $text . '|';
405             }
406              
407             1;
408              
409             __END__