public function testParserWithStringConstants() { $context = new Context(); $const = 'string constant'; $context->def('const', $const, 'string'); $actual = Parser::parse('const', $context); $this->assertEquals($const, $actual); }
public function testFunctionDefinitionWithOptionalParams() { $context = new Context(); $context->defFunction('func', function ($param1, $param2 = 100) { return $param1 + $param2; }); $actual = $context->fn('func', array(3)); $this->assertEquals(103.0, $actual); $actual = $context->fn('func', array(3, 200)); $this->assertEquals(203.0, $actual); }
/** * @param $op * @param $lhs * @param $rhs * @param Context $ctx * @return float|int|null * @throws RuntimeError */ 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; } }
/** * @expectedException \Shunt\Exception\ParseError */ public function testParserExceptionSurplusClosingBracket() { $context = new Context(); $context->defFunction('pi'); $equation = 'pi())'; $actual = Parser::parse($equation, $context); }
/** * @expectedException \Shunt\Exception\RuntimeError */ public function testCallNotSetConstantCausesException() { $context = new Context(); $context->cs('notdefinedfunction'); }