File Coverage

blib/lib/Language/Farnsworth/Output.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Language::Farnsworth::Output;
2              
3 1     1   1345 use strict;
  1         2  
  1         31  
4 1     1   5 use warnings;
  1         2  
  1         45  
5              
6 1     1   5 use overload '""' => \&tostring, "eq" => \&eq;
  1         2  
  1         11  
7              
8              
9 1     1   71 use Data::Dumper;
  1         1  
  1         50  
10 1     1   42 use Language::Farnsworth::Error;
  0            
  0            
11              
12             our %combos;
13             our %displays;
14              
15             #these primarily are used for display purposes
16             sub addcombo
17             {
18             my $name = shift;
19             my $value = shift; #this is a valueless list of dimensions
20              
21             $combos{$name} = $value;
22             }
23              
24             #this returns the name of the combo that matches the current dimensions of a Language::Farnsworth::Value::Pari
25             sub findcombo
26             {
27             my $self = shift;
28             my $value = shift;
29              
30             for my $combo (keys %combos)
31             {
32             #print "TRY COMBO: $combo\n";
33             my $cv = $combos{$combo}; #grab the value
34             return $combo if ($value->getdimen()->compare($cv->getdimen()));
35             }
36              
37             return undef; #none found
38             }
39              
40             #this sets a display for a combo first, then for a dimension
41             sub setdisplay
42             {
43             my $self = shift;
44             my $name = shift; #this only works on things created by =!= or |||, i might try to extend that later but i don't think i need to, since you can just create a name with ||| when you need it
45             my $branch = shift;
46              
47             #I SHOULD CHECK FOR THE NAME!!!!!
48             #print Dumper($name, $branch);
49              
50             if (exists($combos{$name}))
51             {
52             $displays{$name} = $branch;
53             }
54             else
55             {
56             error "No such dimension/combination as $name\n";
57             }
58             }
59              
60             sub getdisplay
61             {
62             my $self = shift;
63             my $name = shift;
64              
65             debug 2, "GETDISP: ",$name, "\n";
66              
67             if (defined($name) && exists($displays{$name}))
68             {
69             debug 4, "GETDISP:", (Dumper($displays{$name})), "\n";
70             if (ref($displays{$name}) eq "Fetch" && $displays{$name}[0] eq "undef")
71             {
72             return undef;
73             }
74              
75             return $displays{$name}; #guess i'll just do the rest in there?
76             }
77              
78             return undef;
79             }
80              
81             sub new
82             {
83             shift; #remove the class
84             my $self = {};
85             $self->{units} = shift;
86             $self->{obj} = shift;
87             $self->{eval} = shift;
88              
89             #warn Dumper($self->{obj});
90              
91             #when we get an error, pass it through, HACK, this is a HACK! the code needs to handle these directly but i need to rewrite the code for output anyway
92             error $self->{obj} if ref($self->{obj}) =~ /Language::Farnsworth::Error/;
93            
94             #warn Dumper($self->{obj});
95             error "Attempting to make output class of non Language::Farnsworth::Value" unless ref($self->{obj}) =~ /Language::Farnsworth::Value/;
96             error "Forgot to add \$eval to params!" unless ref($self->{eval}) eq "Language::Farnsworth::Evaluate";
97              
98            
99             bless $self;
100             }
101              
102             sub tostring
103             {
104             my $self = shift;
105             my $value = $self->{obj};
106              
107             return $self->getoutstring($value);
108             }
109              
110             sub eq
111             {
112             my $one = shift;
113             my $two = shift;
114             my $order = shift;
115              
116             my $string = $one->tostring();
117             return $string eq $two;
118             }
119              
120             #this takes a set of dimensions and returns what to display
121             sub getoutstring
122             {
123             my $self = shift; #i'll implement this later too
124             # my $dimen = shift; #i take a Language::Farnsworth::Dimension object!
125             my $value = shift; #the value so we can stringify it
126              
127             my @returns;
128              
129             if (defined($value->{outmagic}))
130             {
131             if (ref($value->{outmagic}[1]) eq "Language::Farnsworth::Value::String")
132             {
133             #ok we were given a string!
134             my $number = $value->{outmagic}[0];
135             my $string = $value->{outmagic}[1];
136             return $self->getoutstring($number) . " ".$string->getstring();
137             }
138             elsif (exists($value->{outmagic}[0]) && (ref($value->{outmagic}[0]) ne "Language::Farnsworth::Value::Array"))
139             {
140             #ok we were given a value without the string
141             my $number = $value->{outmagic}[0];
142             return $self->getoutstring($number);
143             }
144             else
145             {
146             print Dumper($value);
147             error "Unhandled output magic, this IS A BUG!";
148             }
149             }
150             elsif (ref($value) eq "Language::Farnsworth::Value::Boolean")
151             {
152             return $value ? "True" : "False"
153             #these should do something!
154             }
155             elsif (ref($value) eq "Language::Farnsworth::Value::String")
156             {
157             #I NEED FUNCTIONS TO HANDLE ESCAPING AND UNESCAPING!!!!
158             my $val = $value->getstring();
159             $val =~ s/\\/\\\\/g;
160             $val =~ s/"/\\"/g;
161             return '"'.$val.'"';
162             }
163             elsif (ref($value) eq "Language::Farnsworth::Value::Array")
164             {
165             my @array; #this will be used to build the output
166             for my $v ($value->getarray())
167             {
168             #print Dumper($v);
169             push @array, $self->getoutstring($v);
170             }
171              
172             return '['.(join ' , ', @array).']';
173             }
174             elsif (ref($value) eq "Language::Farnsworth::Value::Date")
175             {
176             return $value->getdate()->strftime("# %F %H:%M:%S.%3N %Z #");#UnixDate($value->{pari}, "# %C #"); #output in ISO format for now
177             }
178             elsif (ref($value) eq "Language::Farnsworth::Value::Lambda")
179             {
180             return $value->tostring();
181             }
182             elsif (ref($value) eq "Language::Farnsworth::Value::Undef")
183             {
184             return "undef";
185             }
186             elsif (ref($value) eq "HASH")
187             {
188             warn "RED ALERT!!!! WE've got a BAD CASE HERE. We've got an UNBLESSED HASH";
189             warn Dumper($value);
190              
191             return "undef";
192             }
193             elsif (my $disp = $self->getdisplay($self->findcombo($value)))
194             {
195             #$disp should now contain the branches to be used on the RIGHT side of the ->
196             #wtf do i put on the left? i'm going to send over the Language::Farnsworth::Value, this generates a warning but i can remove that after i decide that its correct
197              
198             print "SUPERDISPLAY:\n";
199             my $branch = bless [$value, $disp], 'Trans';
200             #print Dumper($branch);
201             my $newvalue = eval {$self->{eval}->evalbranch($branch);};
202             return $self->getoutstring($newvalue);
203             }
204             else
205             {
206             my $dimen = $value->getdimen();
207             #added a sort so its stable, i'll need this...
208             for my $d (sort {$a cmp $b} keys %{$dimen->{dimen}})
209             {
210             my $exp = "";
211             #print Dumper($dimen->{dimen}, $exp);
212             my $dv = "".($dimen->{dimen}{$d});
213             my $realdv = "".(0.0+$dimen->{dimen}{$d}); #use this for comparing below, that way i can keep rational exponents when possible
214              
215             $dv =~ s/([.]\d+?)0+$/$1/;
216             $dv =~ s/E/e/; #make floating points clearer
217              
218             $exp = "^".($dv =~ /^[\d\.]+$/? $dv :"(".$dv.")") unless ($realdv eq "1");
219            
220             push @returns, $self->{units}->getdimen($d).$exp;
221             }
222            
223             if (my $combo = $self->findcombo($value)) #this should be a method?
224             {
225             push @returns, "/* $combo */";
226             }
227              
228              
229             my $prec = Math::Pari::setprecision();
230             Math::Pari::setprecision(15); #set it to 15?
231             my $pv = "".(Math::Pari::pari_print($value->getpari()));
232             my $parenflag = $pv =~ /^[\d\.e]+$/i;
233             my $rational = $pv =~ m|/|;
234              
235             $pv =~ s/E/e/; #make floating points clearer
236              
237             if ($pv =~ m|/|) #check for rationality
238             {
239             my $nv = "".Math::Pari::pari_print($value->getpari() * 1.0); #attempt to force a floating value
240             $nv =~ s/([.]\d+?)0+$/$1/ ;
241             $pv .= " /* apx ($nv) */";
242             }
243              
244             $pv = ($parenflag? $pv :"(".$pv.")"); #check if its a simple value, or complex, if it is complex, add parens
245             $pv =~ s/([.]\d+?)0+$/$1/ ;
246              
247             Math::Pari::setprecision($prec); #restore it before calcs
248             return $pv." ".join " ", @returns;
249             }
250             }
251              
252             sub makevalue
253             {
254             error "MAKEVALUE WAS CALLED!\n";
255             }
256              
257             1;
258             __END__