protected function evaluate($exp)
{
list(, $op, $left, $right, $whiteBefore, $whiteAfter) = $exp;
$left = $this->reduce($left, true);
$right = $this->reduce($right, true);
if ($leftColor = $this->coerceColor($left)) {
$left = $leftColor;
}
if ($rightColor = $this->coerceColor($right)) {
$right = $rightColor;
}
$ltype = $left[0];
$rtype = $right[0];
// operators that work on all types
if ($op == "and") {
return $this->toBool($left == self::$TRUE && $right == self::$TRUE);
}
if ($op == "=") {
return $this->toBool($this->eq($left, $right));
}
if ($op == "+" && !is_null($str = $this->stringConcatenate($left, $right))) {
return $str;
}
// type based operators
$fname = "op_{$ltype}_{$rtype}";
if (is_callable(array($this, $fname))) {
$out = $this->{$fname}($op, $left, $right);
if (!is_null($out)) {
return $out;
}
}
// make the expression look it did before being parsed
$paddedOp = $op;
if ($whiteBefore) {
$paddedOp = " " . $paddedOp;
}
if ($whiteAfter) {
$paddedOp .= " ";
}
return array("string", "", array($left, $paddedOp, $right));
}