File Coverage

blib/lib/Language/Farnsworth/Evaluate.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package Language::Farnsworth::Evaluate;
4              
5 1     1   10 use strict;
  1         1  
  1         30  
6 1     1   5 use warnings;
  1         2  
  1         22  
7              
8 1     1   1214 use Data::Dumper;
  1         17882  
  1         93  
9              
10 1     1   691 use Language::Farnsworth::FunctionDispatch;
  0            
  0            
11             use Language::Farnsworth::Variables;
12             use Language::Farnsworth::Units;
13             use Language::Farnsworth::Parser;
14             use Language::Farnsworth::Value::Types;
15             use Language::Farnsworth::Value::Pari;
16             use Language::Farnsworth::Value::Date;
17             use Language::Farnsworth::Value::String;
18             use Language::Farnsworth::Value::Undef;
19             use Language::Farnsworth::Value::Lambda;
20             use Language::Farnsworth::Value::Array;
21             use Language::Farnsworth::Value::Boolean;
22             use Language::Farnsworth::Output;
23             use Language::Farnsworth::Error;
24              
25             use Math::Pari;# ':hex'; #why not? because it fucks up so fucking badly that fuck isn't a strong enough word
26              
27             sub new
28             {
29             my $class = shift;
30             my $self = {};
31             bless $self;
32              
33             my %opts = (@_);
34              
35             if (ref($opts{funcs}) eq "Language::Farnsworth::FunctionDispatch")
36             {
37             $self->{funcs} = $opts{funcs};
38             }
39             else
40             {
41             $self->{funcs} = new Language::Farnsworth::FunctionDispatch();
42             }
43              
44             if (ref($opts{vars}) eq "Language::Farnsworth::Variables")
45             {
46             $self->{vars} = $opts{vars};
47             }
48             else
49             {
50             $self->{vars} = new Language::Farnsworth::Variables();
51             }
52              
53             if (ref($opts{units}) eq "Language::Farnsworth::Units")
54             {
55             $self->{units} = $opts{units};
56             }
57             else
58             {
59             $self->{units} = new Language::Farnsworth::Units();
60             }
61              
62             if (ref($opts{parser}) eq "Language::Farnsworth::Parser")
63             {
64             $self->{parser} = $opts{parser};
65             }
66             else
67             {
68             $self->{parser} = new Language::Farnsworth::Parser();
69             }
70              
71             $self->{dumpbranches} = 0;
72              
73             return $self;
74             }
75              
76             sub DESTROY
77             {
78             debug 2,"SCOPE DIE: $_[0]";
79             }
80              
81             sub eval
82             {
83             my $self = shift;
84             my $code = shift; #i should probably take an array, so i can use arrays of things, but that'll be later
85              
86             $code =~ s/^\s*//;
87             $code =~ s/\s*$//;
88              
89             my $tree = $self->{parser}->parse($code); #should i catch the exceptions here? dunno
90              
91             debug 3, Dumper($tree);
92              
93             my $ret = eval{$self->evalbranch($tree)};
94            
95             #capture return[] at minimum level
96             if ($@ && $@->isa("Language::Farnsworth::Error")&&$@->isreturn())
97             {
98             return $@->getmsg();
99             }
100             elsif ($@ && $@->isa("Language::Farnsworth::Error"))
101             {
102             return $@;
103             }
104             elsif ($@)
105             {
106             error EPERL, $@;
107             }
108             else
109             {
110             return $ret;
111             }
112             }
113              
114             #evaluate a single branch
115             sub evalbranch
116             {
117             my $self = shift;
118              
119             my $branch = shift;
120             my $type = ref($branch); #this'll grab what kind from the bless on the tree
121              
122             my $return; #to make things simpler later on
123              
124             #print Data::Dumper->Dump([$branch],["BRANCH"]);
125              
126             if ($type eq "Add")
127             {
128             my $a = $self->makevalue($branch->[0]);
129             my $b = $self->makevalue($branch->[1]);
130             $return = $a + $b;
131             }
132             elsif ($type eq "Sub")
133             {
134             my $a = $self->makevalue($branch->[0]);
135             my $b = $self->makevalue($branch->[1]);
136             $return = $a - $b;
137             }
138             elsif ($type eq "Mul")
139             {
140             if ((ref($branch->[0]) eq "Fetch") && (ref($branch->[1]) eq "Array") && ($branch->[2] eq "imp"))
141             {
142             #we've got a new style function call!
143             my $a = $branch->[0][0]; #grab the function name
144             my $b = $self->makevalue($branch->[1]);
145              
146             # print STDERR "----------------FUNCCALL! $a\n";
147             # print STDERR "$self";
148             # print Dumper($a, $b);
149            
150             if ($self->{funcs}->isfunc($a)) #check if there is a func $a
151             { #$return = $self->{funcs}->callfunc($self, $name, $args, $branch);
152             $return = $self->{funcs}->callfunc($self, $a, $b, $branch);
153             }
154             else #otherwise we try to
155             {
156             $a = $self->makevalue($branch->[0]); #evaluate it, since it wasn't a function
157            
158             $return = $a * $b; #do the multiplication
159             }
160             }
161             else
162             {
163             my $a = $self->makevalue($branch->[0]);
164             my $b = $self->makevalue($branch->[1]);
165              
166             #print "-----------SUBMULT!\n";
167             #print Dumper($a,$b);
168              
169             $return = $a * $b;
170             }
171             }
172             elsif ($type eq "Div")
173             {
174             my $a = $self->makevalue($branch->[0]);
175             my $b = $self->makevalue($branch->[1]);
176             #print Dumper($a, $b);
177             $return = $a / $b;
178             }
179             elsif ($type eq "Conforms")
180             {
181             my $a = $self->makevalue($branch->[0]);
182             my $b = $self->makevalue($branch->[1]);
183             $return = new Language::Farnsworth::Value::Boolean($a->conforms($b));
184             }
185             elsif ($type eq "Mod")
186             {
187             my $a = $self->makevalue($branch->[0]);
188             my $b = $self->makevalue($branch->[1]);
189             $return = $a % $b;
190             }
191             elsif ($type eq "Pow")
192             {
193             my $a = $self->makevalue($branch->[0]);
194             my $b = $self->makevalue($branch->[1]);
195             $return = $a ** $b;
196             }
197             elsif ($type eq "And")
198             {
199             my $a = $self->makevalue($branch->[0]);
200              
201             if ($a->bool())
202             {
203             my $b = $self->makevalue($branch->[1]);
204             $return = $a && $b ? 1 : 0;
205             $return = Language::Farnsworth::Value::Boolean->new($return); #make sure its the right type
206             }
207             else
208             {
209             $return = Language::Farnsworth::Value::Boolean->new(0); #make sure its the right type
210             }
211             }
212             elsif ($type eq "Or")
213             {
214             my $a = $self->makevalue($branch->[0]);
215              
216             if ($a->bool())
217             {
218             $return = Language::Farnsworth::Value::Boolean->new(1); #make sure its the right type
219             }
220             else
221             {
222             my $b = $self->makevalue($branch->[1]);
223             $return = $a || $b ? 1 : 0;
224             $return = Language::Farnsworth::Value::Boolean->new($return); #make sure its the right type
225             }
226             }
227             elsif ($type eq "Xor")
228             {
229             my $a = $self->makevalue($branch->[0]);
230             my $b = $self->makevalue($branch->[1]);
231             $return = $a->bool() ^ $b->bool() ? 1 : 0;
232             $return = Language::Farnsworth::Value::Boolean->new($return); #make sure its the right type
233             }
234             elsif ($type eq "Not")
235             {
236             my $a = $self->makevalue($branch->[0]);
237             $return = $a->bool() ? 0 : 1;
238             $return = Language::Farnsworth::Value::Boolean->new($return); #make sure its the right type
239             }
240             elsif ($type eq "Gt")
241             {
242             my $a = $self->makevalue($branch->[0]);
243             my $b = $self->makevalue($branch->[1]);
244             $return = ($a > $b) ? 1 : 0;
245             $return = Language::Farnsworth::Value::Boolean->new($return); #make sure its the right type
246             }
247             elsif ($type eq "Lt")
248             {
249             my $a = $self->makevalue($branch->[0]);
250             my $b = $self->makevalue($branch->[1]);
251             $return = $a < $b ? 1 : 0;
252             $return = Language::Farnsworth::Value::Boolean->new($return); #make sure its the right type
253             }
254             elsif ($type eq "Ge")
255             {
256             my $a = $self->makevalue($branch->[0]);
257             my $b = $self->makevalue($branch->[1]);
258             $return = $a >= $b ? 1 : 0;
259             $return = Language::Farnsworth::Value::Boolean->new($return); #make sure its the right type
260             }
261             elsif ($type eq "Le")
262             {
263             my $a = $self->makevalue($branch->[0]);
264             my $b = $self->makevalue($branch->[1]);
265             $return = $a <= $b ? 1 : 0;
266             $return = Language::Farnsworth::Value::Boolean->new($return); #make sure its the right type
267             }
268             elsif ($type eq "Compare")
269             {
270             my $a = $self->makevalue($branch->[0]);
271             my $b = $self->makevalue($branch->[1]);
272             $return = $a <=> $b;
273             $return = Language::Farnsworth::Value::Pari->new($return); #make sure its the right type
274             }
275             elsif ($type eq "Eq")
276             {
277             my $a = $self->makevalue($branch->[0]);
278             my $b = $self->makevalue($branch->[1]);
279             $return = $a == $b ? 1 : 0;
280             $return = Language::Farnsworth::Value::Boolean->new($return); #make sure its the right type
281             }
282             elsif ($type eq "Ne")
283             {
284             my $a = $self->makevalue($branch->[0]);
285             my $b = $self->makevalue($branch->[1]);
286             $return = $a != $b ? 1 : 0;
287             $return = Language::Farnsworth::Value::Boolean->new($return); #make sure its the right type
288             }
289             elsif ($type eq "Ternary")
290             {
291             #turing completeness FTW
292             my $left = $self->makevalue($branch->[0]);
293             #$left = $left->bool() != new Language::Farnsworth::Value::Pari(0, $left->{dimen}); #shouldn't need it anymore, since i got ->bool working
294             $return = $left ? $self->makevalue($branch->[1]) : $self->makevalue($branch->[2]);
295             }
296             elsif ($type eq "If")
297             {
298             #turing completeness FTW
299             my $left = $self->makevalue($branch->[0]);
300             #$left = $left != new Language::Farnsworth::Value(0, $left->{dimen});
301            
302             if ($left)
303             {
304             $return = $self->makevalue($branch->[1]);
305             }
306             else
307             {
308             $return = $self->makevalue($branch->[2]);
309             }
310             }
311             elsif ($type eq "Store")
312             {
313             my $value = $self->makevalue($branch->[1]);
314             my $lvalue = $self->makevalue($branch->[0]);
315             $return = $value; #make stores evaluate to the value on the right
316             #$self->{vars}->setvar($name, $value);
317             $lvalue->{stored}++; #testing
318             my $cloned = $value->clone();
319             #warn "SETTING VALUES";
320             #warn Data::Dumper->Dump([$lvalue, $lvalue->getref(), $value, $cloned], [qw($lvalue \$ref $value $cloned)]);
321             $cloned->setref(\$cloned);
322             debug 6, "---STORE---\n",Data::Dumper->Dump([$lvalue, $value, $cloned, $lvalue->getref()],[qw(lvalue value cloned lvalref)]);
323             ${$lvalue->{_ref}} = $cloned;
324             debug 6, "---STORE---\n",Data::Dumper->Dump([$lvalue, $value, $cloned, $lvalue->getref()],[qw(lvalue value cloned lvalref)]);
325             # eval {
326             # my $rrval = $self->makevalue($branch->[0]);
327             # debug 2, Data::Dumper->Dump([$rrval, $lvalue, $cloned], [qw(rrval lvalue cloned)]);
328             # }; #keep it from killing things ahead of time
329             # undef $@;
330             }
331             elsif ($type eq "StoreAdd")
332             {
333             my $value = $self->makevalue($branch->[1]);
334             my $lvalue = $self->makevalue($branch->[0]);
335            
336             my $cloned = $value->clone();
337             $return = (${$lvalue->getref()} = $lvalue + $cloned);
338             }
339             elsif ($type eq "StoreSub")
340             {
341             my $value = $self->makevalue($branch->[1]);
342             my $lvalue = $self->makevalue($branch->[0]);
343            
344             my $cloned = $value->clone();
345             $return = (${$lvalue->getref()} = $lvalue - $cloned);
346             }
347             elsif ($type eq "StoreDiv")
348             {
349             my $value = $self->makevalue($branch->[1]);
350             my $lvalue = $self->makevalue($branch->[0]);
351            
352             my $cloned = $value->clone();
353             $return = (${$lvalue->getref()} = $lvalue / $cloned);
354             }
355             elsif ($type eq "StoreMul")
356             {
357             my $value = $self->makevalue($branch->[1]);
358             my $lvalue = $self->makevalue($branch->[0]);
359            
360             my $cloned = $value->clone();
361             $return = (${$lvalue->getref()} = $lvalue * $cloned);
362             }
363             elsif ($type eq "StoreMod")
364             {
365             my $value = $self->makevalue($branch->[1]);
366             my $lvalue = $self->makevalue($branch->[0]);
367            
368             my $cloned = $value->clone();
369             $return = (${$lvalue->getref()} = $lvalue % $cloned);
370             }
371             elsif ($type eq "StorePow")
372             {
373             my $value = $self->makevalue($branch->[1]);
374             my $lvalue = $self->makevalue($branch->[0]);
375            
376             my $cloned = $value->clone();
377             $return = (${$lvalue->getref()} = $lvalue ** $cloned);
378             }
379             elsif ($type eq "PreInc")
380             {
381             my $lvalue = $self->makevalue($branch->[0]);
382             $return = (${$lvalue->getref()} = $lvalue+VALUE_ONE());
383             }
384             elsif ($type eq "PostInc")
385             {
386             my $lvalue = $self->makevalue($branch->[0]);
387             my $val = $lvalue->clone();
388             ${$lvalue->getref()} = $val+VALUE_ONE();
389              
390             $return = $val;
391             }
392             elsif ($type eq "PreDec")
393             {
394             my $lvalue = $self->makevalue($branch->[0]);
395             $return = (${$lvalue->getref()} = $lvalue-VALUE_ONE());
396             }
397             elsif ($type eq "PostDec")
398             {
399             my $lvalue = $self->makevalue($branch->[0]);
400             my $val = $lvalue->clone();
401             ${$lvalue->getref()} = $val-VALUE_ONE();
402              
403             $return = $val;
404             }
405             elsif ($type eq "DeclareVar")
406             {
407             my $name = $branch->[0];
408             my $value;
409             #print "\n\n DECLARING $name\n";
410             #print Dumper($branch);
411              
412             if (defined($branch->[1]))
413             {
414             $value = $self->makevalue($branch->[1]);
415             }
416             else
417             {
418             $value = $self->makevalue(bless [0], 'Num');
419             }
420              
421             $return = $value; #make stores evaluate to the value on the right
422             $self->{vars}->declare($name, $value);
423             }
424             elsif ($type eq "DeclareFunc")
425             {
426             #print Dumper($branch);
427             my $name = $branch->[0];
428             my $lambda = $self->makevalue($branch->[1]);
429              
430             #should i allow constants? if i do i'll have to handle them differently, for now it'll be an error
431             error "Right side of function declaration for '$name' did not evaluate to a lambda" unless ($lambda->istype("Lambda"));
432              
433             $self->{funcs}->addfunclamb($name, $lambda);
434             $return = $lambda;
435             }
436             elsif ($type eq "FuncDef")
437             {
438             #print Dumper($branch);
439             my $name = $branch->[0];
440             my $args = $branch->[1];
441             my $value = $branch->[2]; #not really a value, but in fact the tree to run for the function
442              
443             my $nvars = new Language::Farnsworth::Variables($self->{vars}); #lamdbas get their own vars
444             my %nopts = (vars => $nvars, funcs => $self->{funcs}, units => $self->{units}, parser => $self->{parser});
445             my $scope = $self->new(%nopts);
446              
447             my $vargs;
448              
449             for my $arg (@$args)
450             {
451             my $reference = $arg->[3];
452             my $constraint = $arg->[2];
453             my $default = $arg->[1];
454             my $name = $arg->[0]; #name
455              
456             if (defined($default))
457             {
458             $default = $self->makevalue($default); #should be right
459             }
460              
461             if (defined($constraint))
462             {
463             #print Dumper($constraint);
464             $constraint = $self->makevalue($constraint); #should be right
465             #print Dumper($constraint);
466             }
467              
468             push @$vargs, [$name, $default, $constraint, $reference];
469             }
470              
471             $self->{funcs}->addfunc($name, $vargs, $value, $scope);
472             $return = undef; #cause an error should someone manage to make it parse other than the way i think it should be
473             }
474             elsif ($type eq "Lambda")
475             {
476             my $args = $branch->[0];
477             my $code = $branch->[1];
478              
479             #print "==========LAMBDA==========\n";
480             #print Data::Dumper->Dump([$args,$code], ["args", "code"]);
481              
482             my $nvars = new Language::Farnsworth::Variables($self->{vars}); #lamdbas get their own vars
483             my %nopts = (vars => $nvars, funcs => $self->{funcs}, units => $self->{units}, parser => $self->{parser});
484             my $scope = $self->new(%nopts);
485              
486             #this should probably get a function in Language::Farnsworth::FunctionDispatch
487             my $vargs;
488              
489             for my $arg (@$args)
490             {
491             my $reference = $arg->[3];
492             my $constraint = $arg->[2];
493             my $default = $arg->[1];
494             my $name = $arg->[0]; #name
495              
496             # if ($reference)
497             # {
498             # #we've got a reference for lambdas!
499             # error "Passing arguments by reference for lambdas is unsupported at this time";
500             # }
501              
502             if (defined($default))
503             {
504             $default = $self->makevalue($default); #should be right
505             }
506              
507             if (defined($constraint))
508             {
509             #print Dumper($constraint);
510             $constraint = $self->makevalue($constraint); #should be right
511             #print Dumper($constraint);
512             }
513              
514             push @$vargs, [$name, $default, $constraint, $reference];
515             }
516              
517             $return = new Language::Farnsworth::Value::Lambda($scope, $vargs, $code, $branch);
518             }
519             elsif ($type eq "LambdaCall") #still used in ONE place, sort[] in Standard.pm, i need to get the code to use mult but that's being a pita and i'm done trying to do it at the moment
520             {
521             my $left = $self->makevalue($branch->[0]);
522             my $right = $self->makevalue($branch->[1]);
523              
524             error "Right side of lamdbda call must evaluate to a Lambda\n" unless $right->istype("Lambda");
525              
526             #need $args to be an array
527             my $args = $left->istype("Array") ? $left : new Language::Farnsworth::Value::Array([$left]);
528              
529             $return = $self->{funcs}->calllambda($right, $args); #needs to be updated
530             }
531             elsif (($type eq "Array") || ($type eq "SubArray"))
532             {
533             my $array = []; #fixes bug with empty arrays
534             for my $bs (@$branch) #iterate over all the elements
535             {
536             my $type = ref($bs); #find out what kind of thing we are
537             my $value = $self->makevalue($bs);
538              
539             #print "ARRAY FILL -- $type\n";
540              
541             # if ($value->istype("Array"))
542             # {
543             #since we have an array, but its not in a SUBarray, we dereference it before the push
544             #push @$array, $value->getarray() unless ($type eq "SubArray");
545             #push @$array, $value;# if ($type eq "SubArray");
546             #}
547             #else
548             {
549             #print "ARRAY VALUE --- ".Dumper($value);
550             #its not an array or anything so we push it on
551             push @$array, $value; #we return an array ref! i need more error checking around for this later
552             }
553             }
554             $return = new Language::Farnsworth::Value::Array($array);
555             }
556             elsif ($type eq "ArgArray")
557             {
558             my $array = []; #autovivification wasn't working?
559             for my $bs (@$branch) #iterate over all the elements
560             {
561             my $type = ref($bs); #find out what kind of thing we are
562             my $value = $self->makevalue($bs);
563              
564             #even if it is an array we don't want to deref it here, because thats the wrong behavior, this will make things like push[a, 1,2,3] work properly
565             push @$array, $value; #we return an array ref! i need more error checking around for this later
566             }
567             $return = new Language::Farnsworth::Value::Array($array);
568             }
569             elsif ($type eq "ArrayFetch")
570             {
571             #print "\n\nAFETCH\n";
572             my $var = $self->makevalue($branch->[0]); #need to check if this is an array, and die if not
573             my $listval = $self->makevalue($branch->[1]);
574             my @rval;
575              
576             #print Data::Dumper->Dump([$branch, $var, $listval], ["branch","var","listval"]);
577              
578             for ($listval->getarray())
579             {
580             my $index = $_->getpari()*1.0;
581             #print STDERR "ARFET: ".$_->toperl()."\n";
582             #ok this line FOR WHATEVER REASON, makes Math::Pari.xs die in isnull(), WHY i don't know, there's something wrong here somewhere
583             #my $float = $_ * (Language::Farnsworth::Value::Pari->new(1.0)); #makes rationals work right
584            
585             my $input = $var->getarrayref()->[$index];
586            
587             #error "Array out of bounds\n" #old message, check is down below now;
588             $var->getarrayref()->[$index] = TYPE_UNDEF unless defined $input;
589             $input = $var->getarrayref()->[$index] unless defined $input; #reset the value if needed, this code should be redone but i don't feel like it right now XXX
590            
591             $input->setref(\$var->getarrayref()->[$index]);
592             push @rval, $input;
593             }
594              
595             #print Dumper(\@rval);
596              
597             if (@rval > 1)
598             {
599             my $pr = new Language::Farnsworth::Value::Array([@rval]);
600             $return = $pr;
601             $return->setref(\$return); #i think this should work fine
602             }
603             else
604             {
605             $return = $rval[0];
606             }
607             }
608             elsif ($type eq "ArrayStore")
609             {
610             my $var = $self->makevalue(bless [$branch->[0]], 'Fetch'); #need to check if this is an array, and die if not
611             my $listval = $self->makevalue($branch->[1]);
612             my $rval = $self->makevalue($branch->[2]);
613              
614             #print Dumper($branch, $var, $listval);
615              
616             if ($listval->getarray() > 1)
617             {
618             error "Assigning to slices not implemented yet\n";
619             }
620            
621             error "Only numerics may be given as array indexes!" unless ($listval->getarrayref()->[0]->istype("Pari"));
622              
623             my $num = $listval->getarrayref()->[0]->getpari() + 0; #the +0 makes sure its coerced into a number
624              
625             $var->getarrayref()->[$num] = $rval;
626              
627             for my $value ($var->getarray())
628             {
629             $value = $self->makevalue(bless [0], 'Num') if !defined($value);
630             }
631              
632             $return = $rval;
633             }
634             elsif ($type eq "While")
635             {
636             my $cond = $branch->[0]; #what to check each time
637             my $stmts = $branch->[1]; #what to run each time
638              
639             my $condval = $self->makevalue($cond);
640             while ($condval)
641             {
642             my $v = $self->makevalue($stmts);
643             $condval = $self->makevalue($cond);
644             }
645              
646             $return = undef; #cause errors
647             }
648             elsif ($type eq "Stmt")
649             {
650             for my $bs (@$branch) #iterate over all the statements
651             {
652             if (defined($bs))
653             {
654             my $r = $self->makevalue($bs);
655             $return = $r if defined $r; #this has interesting semantics!
656             }
657             }
658             }
659             elsif ($type eq "Paren")
660             {
661             $return = $self->makevalue($branch->[0]);
662             }
663             elsif ($type eq "SetDisplay")
664             {
665             #TODO make error checking
666             print Dumper($branch);
667             my $combo = $branch->[0][0]; #is a string?
668             my $right = $self->makevalue($branch->[1]);
669              
670             Language::Farnsworth::Output->setdisplay($combo, $right);
671             }
672             elsif ($type eq "UnitDef")
673             {
674             my $unitsize = $self->makevalue($branch->[1]);
675             my $name = $branch->[0];
676             $self->{units}->addunit($name, $unitsize);
677             $return = $unitsize;
678             }
679             elsif ($type eq "DefineDimen")
680             {
681             my $unit = $branch->[1];
682             my $dimen = $branch->[0];
683             $self->{units}->adddimen($dimen, $unit);
684             }
685             elsif ($type eq "DefineCombo")
686             {
687             my $combo = $branch->[1]; #should get me a string!
688             my $value = $self->makevalue($branch->[0]);
689             Language::Farnsworth::Output::addcombo($combo, $value);
690             }
691             elsif (($type eq "SetPrefix") || ($type eq "SetPrefixAbrv"))
692             {
693             my $name = $branch->[0];
694             my $value = $self->makevalue($branch->[1]);
695             #carp "SETTING PREFIX0: $name : $value : ".Dumper($branch->[1]) if ($name eq "m");
696             $self->{units}->setprefix($name, $value);
697             }
698             elsif ($type eq "Trans")
699             {
700             my $left = $self->makevalue($branch->[0]);
701             my $rights = eval {$self->makevalue($branch->[1])};
702             print "TRANS: right side eval\n";
703             #print Dumper($@);
704             my $right = $rights;
705              
706             if (!$@ && defined($rights) && $rights->istype("String")) #if its a string we do some fun stuff
707             {
708             print "STRINGED\n";
709             $right = $self->eval($rights->getstring()); #we need to set $right to the evaluation $rights
710             #print Dumper($rights, $right);
711             print "ERRORED: ".Dumper($@);
712             }
713              
714             if (!$@)
715             {
716             debug 1,"\n\nLEFT\n";
717             debug 1,ref($left);
718             debug 1,"RIGHT\n";
719             debug 1,ref($right);
720            
721             if ($left->conforms($right)) #only do this if they are the same
722             {
723             print "Got Conformity\n";
724             my $dispval = ($left / $right);
725              
726             #$return = $left;
727             %$return = %$left; #ok this makes NO SENSE as to WHY it would behave like it was...
728             bless $return, ref($left);
729            
730             if ($rights->istype("String"))
731             {
732             #right side was a string, use it
733             $return->{outmagic} = [$dispval, $rights];
734             }
735             else
736             {
737             $return->{outmagic} = [$dispval];
738             }
739             }
740             elsif ($right->istype("Lambda"))
741             {
742             print "Got a lambda";
743             $return = $right * $left; #simple enough, just use the overloaded operator
744             }
745             # this code isn't being used is it? fuck i need better docs and tests
746             # elsif ($self->{funcs}->isfunc($branch->[1][0]))
747             # {
748             # $left = $left->istype("Array") ? $left : new Language::Farnsworth::Value::Array([$left]);
749             # $return = $self->{funcs}->callfunc($self, $branch->[1][0], $left);
750             #
751             # if ($rights->istype("String"))
752             # {
753             # #right side was a string, use it
754             # my $nm = {%$return}; #do a shallow copy!
755             # bless $nm, ref($return); #rebless it
756             # $return->{outmagic} = [$nm, $rights];
757             # }
758             # }
759             else
760             {
761             error "Conformance error, can't convert from ".($left->type($self))." to ".($right->type($self))."\n";
762             }
763             }
764             else
765             {
766             #$right doesn't evaluate... so we check for a function?
767             $left = $left->istype("Array") ? $left : new Language::Farnsworth::Value::Array([$left]);
768             $return = $self->{funcs}->callfunc($self, $branch->[1][0], $left);
769              
770             if (defined($rights) && $rights->istype("String"))
771             {
772             #right side was a string, use it
773             my $nm = {%$return}; #do a shallow copy!
774             bless $nm, ref($return); #rebless it
775             $return->{outmagic} = [$nm, $rights];
776             }
777             }
778             }
779              
780             if (!defined($return))
781             {
782             #this creates a "true" undefined value for returning, this makes things funner! it also introduced a bug from naive coding above, which has been fixed
783             $return = new Language::Farnsworth::Value::Undef();
784             }
785            
786             return $return;
787             }
788              
789             sub makevalue
790             {
791             my $self = $_[0];
792             my $input = $_[1]; #switching from shift here, so that i can keep @_ intact for recursing
793              
794             # print "MAKEVALUE---------\n";
795             # print Dumper($input);
796              
797             if (ref($input) eq "Num")
798             {
799             #need to make a value here with Language::Farnsworth::Value!
800             my $val = new Language::Farnsworth::Value::Pari($input->[0]);
801             return $val;
802             }
803             if (ref($input) eq "HexNum")
804             {
805             #need to make a value here with Language::Farnsworth::Value!
806             #print "HEX VALUE: ".$input->[0]."\n";
807             #my $value = eval $input->[0]; #this SHOULD work, shouldn't be a security risk since its validated through the lexer and parser.
808             my $val = new Language::Farnsworth::Value::Pari($input->[0],undef,undef,1);
809             return $val;
810             }
811             elsif (ref($input) eq "Fetch")
812             {
813             #this needs to decide between variable and unit, but that'll come later
814             #esp since i also have to have this overridable for functions!
815              
816             my $name = $input->[0];
817             if ($self->{vars}->isvar($name))
818             {
819             return $self->{vars}->getvar($input->[0]);
820             }
821             elsif ($self->{units}->isunit($name))
822             {
823             #print "FETCH: $name\n" if ($name eq "milli");
824             return $self->{units}->getunit($name);
825             }
826            
827             error "Undefined symbol '$name'\n";
828             }
829             elsif (ref($input) eq "GetFunc")
830             {
831             my $name = $input->[0];
832             if ($self->{funcs}->isfunc($name))
833             {
834             return $self->{funcs}->getfunc($name)->{lambda};
835             }
836             else
837             {
838             error "Undefined function '$name'";
839             }
840             }
841             elsif (ref($input) eq "String") #we've got a string that should be a value!
842             {
843             my $value = $input->[0];
844             #here it comes in with quotes, so lets remove them
845             #$value =~ s/^"(.*)"$/$1/; #no longer needed
846             #$value =~ s/\\"/"/g; #i'm gonna move these into the constructor i think
847             #$value =~ s/\\\\/\\/g;
848             $value =~ s/\\(.)/qq("\\$1")/eeg;
849             my $ss = sub
850             {
851             my $var =shift;
852             $var =~ s/^[\$]//;
853             my $output = undef;
854             if ($var !~ /^{.*}$/)
855             {
856             $output = new Language::Farnsworth::Output($self->{units}, $self->{vars}->getvar($var), $self);
857             }
858             else
859             {
860             $var =~ s/[{}]//g;
861             $output = new Language::Farnsworth::Output($self->{units}, $self->eval($var), $self);
862             }
863              
864             "".$output;
865             };
866             $value =~ s/(?($1)/eg;
867             my $val = new Language::Farnsworth::Value::String($value);
868             return $val;
869             }
870             elsif (ref($input) eq "Date")
871             {
872             #print "\n\n\nMaking DATE!\n\n\n";
873             my $val = new Language::Farnsworth::Value::Date($input->[0]);
874             # print Dumper($val);
875             return $val;
876             }
877             elsif (ref($input) eq "VarArg")
878             {
879             #warn "Got a VarArg, code untested, want to mark when i get them\n"; #just so i can track down the inevitable crash
880             return "VarArg";
881             }
882             elsif (ref($input) =~ /Language::Farnsworth::Value/)
883             {
884             debug 5, "Got a Language::Farnsworth::Value::*, i PROBABLY shouldn't be getting these, i'm just going to let it fall through";
885             return $input;
886             }
887              
888             #return $self->evalbranch($input);
889             goto &evalbranch; #EVIL GOTO! but might save a stack frame! OMG!
890             }
891              
892             1;
893             __END__