protected function op($op, $lhs, $rhs, Context $ctx) { // If there is a custom operator handler function defined in the context, call it instead if ($ctx->hasCustomOperatorHandler($op)) { $lhsValue = is_object($lhs) ? $lhs->value : null; $rhsValue = is_object($rhs) ? $rhs->value : null; return $ctx->execCustomOperatorHandler($op, $lhsValue, $rhsValue); } if ($lhs !== null) { $lhs = $lhs->value; $rhs = $rhs->value; switch ($op) { case Token::T_PLUS: return $lhs + $rhs; case Token::T_MINUS: return $lhs - $rhs; case Token::T_TIMES: return $lhs * $rhs; case Token::T_DIV: if ($rhs === 0.0) { throw new RuntimeError('run-time error: division by zero'); } return $lhs / $rhs; case Token::T_MOD: if ($rhs === 0.0) { throw new RuntimeError('run-time error: rest-division by zero'); } return (double) $lhs % $rhs; case Token::T_POW: return (double) pow($lhs, $rhs); } // throw? return 0; } switch ($op) { case Token::T_NOT: return is_null($rhs->value) ? null : (double) (!$rhs->value); case Token::T_UNARY_MINUS: return is_null($rhs->value) ? null : -$rhs->value; case Token::T_UNARY_PLUS: return is_null($rhs->value) ? null : +$rhs->value; } }
protected function op($op, $lhs, $rhs, Context $ctx) { // If there is a custom operator handler function defined in the context, call it instead if ($ctx->hasCustomOperatorHandler($op)) { $lhsValue = is_object($lhs) ? $lhs->value : null; $rhsValue = is_object($rhs) ? $rhs->value : null; return $ctx->execCustomOperatorHandler($op, $lhsValue, $rhsValue); } if ($lhs !== null) { $lhs = $lhs->value; $rhs = $rhs->value; switch ($op) { case Token::T_GREATER_EQUAL: case Token::T_LESS_EQUAL: case Token::T_GREATER: case Token::T_LESS: case Token::T_PLUS: case Token::T_MINUS: case Token::T_TIMES: case Token::T_DIV: case Token::T_MOD: case Token::T_POW: if (is_bool($lhs) && is_bool($rhs)) { throw new RuntimeError('run-time error: trying to do a number only operation over two booleans'); } else { if (is_bool($lhs) || is_bool($rhs)) { throw new RuntimeError('run-time error: trying to calculate a value out of a decimal and a boolean'); } } break; case Token::T_EQUAL: case Token::T_NOT_EQUAL: if (is_bool($lhs) ^ is_bool($rhs)) { throw new RuntimeError('run-time error: trying to calculate a value out of a decimal and a boolean'); } break; case Token::T_AND: case Token::T_OR: case Token::T_XOR: if (!is_bool($lhs) || !is_bool($rhs)) { throw new RuntimeError('run-time error: trying to do a boolean only operation over two numbers'); } break; } switch ($op) { case Token::T_AND: return $lhs && $rhs; case Token::T_OR: return $lhs || $rhs; case Token::T_XOR: return $lhs ^ $rhs; case Token::T_GREATER_EQUAL: return $lhs >= $rhs; case Token::T_LESS_EQUAL: return $lhs <= $rhs; case Token::T_GREATER: return $lhs > $rhs; case Token::T_LESS: return $lhs < $rhs; case Token::T_EQUAL: return $lhs == $rhs; case Token::T_NOT_EQUAL: return $lhs != $rhs; case Token::T_PLUS: return $lhs + $rhs; case Token::T_MINUS: return $lhs - $rhs; case Token::T_TIMES: return $lhs * $rhs; case Token::T_DIV: if ($rhs === 0.0) { throw new RuntimeError('run-time error: division by zero'); } return $lhs / $rhs; case Token::T_MOD: if ($rhs === 0.0) { throw new RuntimeError('run-time error: rest-division by zero'); } return (double) $lhs % $rhs; case Token::T_POW: return (double) pow($lhs, $rhs); } // throw? return 0; } switch ($op) { case Token::T_NOT: return is_null($rhs->value) ? null : (double) (!$rhs->value); case Token::T_UNARY_MINUS: return is_null($rhs->value) ? null : -$rhs->value; case Token::T_UNARY_PLUS: return is_null($rhs->value) ? null : +$rhs->value; } }