Math-Expression
view release on metacpan or search on metacpan
Expression.pm view on Meta::CPAN
return;
}
$right = 0; # Monadics are all numeric
}
unless($right =~ /^([-+]?)0*([\d.]+)([ef][-+]?\d*|)$/i) {
$self->PrintError("Operand to monadic '%s' is not numeric '%s'", $oper, $right);
return;
}
$right = "$1$2$3";
return -$right if($oper eq '-');
return $right if($oper eq '+');
return !$right if($oper eq '!');
return ~$right if($oper eq '~');
$self->PrintError("Unknown monadic operator when evaluating: '%s'", $oper);
return;
}
# This is complicated by multiple assignment: (a, b, c) := (1, 2, 3, 4). 'c' is given '(3, 4)'.
# Assign the right value to the left node
# Where the values list is shorter, leave vars alone: (a, b, c) := (1, 2) does not change c.
if($oper eq ':=') {
my @left = $self->EvalTree($tree->{left}, 1);
my @right = $self->EvalTree($tree->{right}, $wantlv);
# Easy case, assigning to one variable, assign the whole array:
return $self->{VarSetFun}($self, @left, @right) if($#right <= 0);
# Assign conseq values to conseq variables. The last var gets the rest of the values.
# Ignore too many vars.
for(my $i = 0; $i <= $#left; $i++) {
last if($i > $#right);
if($i == $#left and $i != $#right) {
$self->{VarSetFun}($self, $left[$i], @right[$i ... $#right]);
last;
}
$self->{VarSetFun}($self, $left[$i], $right[$i]);
}
return @right;
}
# Flow control: if/while
if($oper eq 'flow') {
if($tree->{flow} eq 'if') {
# left is condition, right is body when true
my @left = $self->EvalTree($tree->{left}, 0);
return ($left[-1]) ? ($self->EvalTree($tree->{right}, 0))[-1] : 0;
}
if($tree->{flow} eq 'while') {
my $ret = 0; # Return val, until get something better
if( !$self->{PermitLoops}) {
$self->PrintError("Loops not enabled, set property PermitLoops to do so");
return;
}
while(1) {
if($self->{MaxLoopCount} && ++$self->{LoopCount} > $self->{MaxLoopCount}) {
$self->PrintError("Loop exceeded maximum iterations: MaxLoopCount = $self->{MaxLoopCount}");
return;
}
# left is loop condition, right is body:
my @left = $self->EvalTree($tree->{left}, 0);
return $ret unless($left[-1]);
$ret = ($self->EvalTree($tree->{right}, 0))[-1];
}
return $ret;
}
}
# Evaluate left - may be able to avoid evaluating right.
# Take care to avoid evaluating a tree twice, not just inefficient but nasty side effects with ++ & -- operators
my @left = $self->EvalTree($tree->{left}, $wantlv);
my $left = $left[$#left];
if(!defined($left) and $oper ne ',' and $oper ne '.' and $oper ne ';') {
unless($self->{AutoInit}) {
$self->PrintError("Left value to operator '%s' is not defined", $oper);
return;
}
$left = ''; # Set to the empty string
}
# Lazy evaluation:
return $left ? $self->EvalTree($tree->{right}{left}, $wantlv) :
$self->EvalTree($tree->{right}{right}, $wantlv) if($oper eq '?');
# Constructing a list of variable names (for assignment):
return (@left, $self->EvalTree($tree->{right}, 1)) if($oper eq ',' and $wantlv);
# More lazy evaluation:
if($oper eq '&&' or $oper eq '||') {
return 0 if($oper eq '&&' and !$left);
return 1 if($oper eq '||' and $left);
my @right = $self->EvalTree($tree->{right}, 0);
return($right[$#right] ? 1 : 0);
}
# Everything else is a binary operator, get right side - value(s):
my @right = $self->EvalTree($tree->{right}, 0);
my $right = $right[-1];
return (@left, @right) if($oper eq ',');
return @right if($oper eq ';');
# Array index. Beware: works differently depending on $wantlv.
# Because when $wantlv it is the array name, not its contents
if($oper eq '[') {
return undef # Check if the array member could exist; ie have index
if($right !~ /^-?\d+$/);
@left = $self->{VarGetFun}($self, $left[0]) if($wantlv);
my $index = $right[-1];
$index += @left if($index < 0); # Convert -ve index to a +ve one
return "$left\[$index]" # Return var[index] for assignment
if($wantlv);
( run in 0.727 second using v1.01-cache-2.11-cpan-71847e10f99 )