aboutsummaryrefslogtreecommitdiffstats
path: root/Praspel.php
diff options
context:
space:
mode:
authorIvan Enderlin <ivan.enderlin@hoa-project.net>2013-06-07 16:44:13 +0200
committerIvan Enderlin <ivan.enderlin@hoa-project.net>2013-06-07 16:44:13 +0200
commitaf0ab4b0397a2745d8c143d4dce3826c1e6119d9 (patch)
treea5191b8bde18bb311ba00928121536403f56f456 /Praspel.php
parentdeb81e7b382857c9b155c8122558696a69e045ba (diff)
downloadPraspel-af0ab4b0397a2745d8c143d4dce3826c1e6119d9.zip
Praspel-af0ab4b0397a2745d8c143d4dce3826c1e6119d9.tar.gz
Praspel-af0ab4b0397a2745d8c143d4dce3826c1e6119d9.tar.bz2
New RAC for Praspel: cleaner and faster.
Diffstat (limited to 'Praspel.php')
-rw-r--r--Praspel.php177
1 files changed, 143 insertions, 34 deletions
diff --git a/Praspel.php b/Praspel.php
index cc58bb9..7556ecb 100644
--- a/Praspel.php
+++ b/Praspel.php
@@ -39,9 +39,39 @@ namespace {
from('Hoa')
/**
- * \Hoa\Praspel\Exception
+ * \Hoa\Praspel\Exception\Generic
*/
--> import('Praspel.Exception.~')
+-> import('Praspel.Exception.Generic')
+
+/**
+ * \Hoa\Praspel\Exception\Group
+ */
+-> import('Praspel.Exception.Group')
+
+/**
+ * \Hoa\Praspel\Exception\Failure\Precondition
+ */
+-> import('Praspel.Exception.Failure.Precondition')
+
+/**
+ * \Hoa\Praspel\Exception\Failure\Postcondition
+ */
+-> import('Praspel.Exception.Failure.Postcondition')
+
+/**
+ * \Hoa\Praspel\Exception\Failure\Exceptional
+ */
+-> import('Praspel.Exception.Failure.Exceptional')
+
+/**
+ * \Hoa\Praspel\Exception\Failure\Invariant
+ */
+-> import('Praspel.Exception.Failure.Invariant')
+
+/**
+ * \Hoa\Praspel\Exception\Failure\InternalPrecondition
+ */
+-> import('Praspel.Exception.Failure.InternalPrecondition')
/**
* \Hoa\Praspel\Visitor\Interpreter
@@ -123,13 +153,21 @@ class Praspel {
*/
public function evaluate ( ) {
- $callable = $this->getCallable();
- $reflection = $callable->getReflection();
- $arguments = array();
- $data = $this->getData();
+ // Start.
+ $callable = $this->getCallable();
+ $reflection = $callable->getReflection();
+ $specification = $this->getSpecification();
+ $exceptions = new \Hoa\Praspel\Exception\Group(
+ 'The Runtime Assertion Checker has detected errors for %s.',
+ 0, $callable);
+
+ if($reflection instanceof \ReflectionMethod)
+ $reflection->setAccessible(true);
+
- if(null === $data)
- $data = $this->generateData();
+ // Prepare data.
+ $data = $this->getData() ?: $this->generateData();
+ $arguments = array();
foreach($reflection->getParameters() as $parameter) {
@@ -142,47 +180,106 @@ class Praspel {
}
if(false === $parameter->isOptional())
- throw new Exception(
- 'The evaluated callable needs a data for the argument $%s.',
- 0, $name);
+ // Let the error be caught by the @requires clause.
+ continue;
$arguments[$name] = $parameter->getDefaultValue();
}
- $specification = $this->getSpecification();
- $requires = $specification->getClause('requires');
- $precondition = true;
- foreach($arguments as $name => $value) {
+ // Check precondition.
+ $precondition = true;
- if(!isset($requires[$name]))
- $variable = $requires[$name]->in = realdom()->undefined();
+ if(true === $specification->clauseExists('requires')) {
- $variable = &$requires[$name];
- $variable->setValue($value);
-
- $precondition = $variable->predicate()
- && $precondition;
+ $requires = $specification->getClause('requires');
+ $precondition = $this->checkClause(
+ $requires,
+ $arguments,
+ $exceptions,
+ __NAMESPACE__ . '\Exception\Failure\Precondition'
+ );
}
- $return = $callable->distributeArguments($arguments);
- $ensures = $specification->getClause('ensures');
+ if(0 < count($exceptions))
+ throw $exceptions;
- if(isset($ensures['\result']))
- $ensures['\result'] = $return;
+ // Invoke.
+ if($reflection instanceof \ReflectionFunction)
+ $return = $reflection->invokeArgs($arguments);
+ else {
+
+ $_callback = $callable->getValidCallback();
+ $_object = $_callback[0];
+ $return = $reflection->invokeArgs($_object, $arguments);
+ }
+
+
+ // Check postcondition.
$postcondition = true;
- foreach($ensures as $name => $variable) {
+ if(true === $specification->clauseExists('ensures')) {
- $postcondition = $variable->predicate()
- && $postcondition;
+ $ensures = $specification->getClause('ensures');
+ $arguments['\result'] = $return;
+ $postcondition = $this->checkClause(
+ $ensures,
+ $arguments,
+ $exceptions,
+ __NAMESPACE__ . '\Exception\Failure\Postcondition'
+ );
}
+ if(0 < count($exceptions))
+ throw $exceptions;
+
+
+ // Verdict.
return $precondition && $postcondition;
}
/**
+ * Check a clause.
+ *
+ * @access protected
+ * @param \Hoa\Praspel\Model\Declaration $clause Clause.
+ * @param array &$data Data.
+ * @param \Hoa\Praspel\Exception\Group $exceptions Exceptions group.
+ * @param string $exception Exception to
+ * throw.
+ * @return bool
+ * @throw \Hoa\Praspel\Exception
+ */
+ protected function checkClause ( Model\Declaration $clause, Array &$data,
+ Exception\Group $exceptions, $exception ) {
+
+ $verdict = true;
+
+ foreach($clause as $name => $variable) {
+
+ if(false === array_key_exists($name, $data)) {
+
+ $exceptions[] = new $exception(
+ 'Variable %s has no value and is required.', 0, $name);
+
+ continue;
+ }
+
+ $_verdict = $variable->predicate($data[$name]);
+
+ if(false === $_verdict)
+ $exceptions[] = new $exception(
+ 'Variable %s does not verify the constraint %s.',
+ 0, array($name, $variable->getDomains()->toPraspel()));
+
+ $verdict = $_verdict && $verdict;
+ }
+
+ return $verdict;
+ }
+
+ /**
* Set specification.
*
* @access protected
@@ -208,14 +305,26 @@ class Praspel {
return $this->_specification;
}
+ /**
+ * Generate data from the @requires clause.
+ *
+ * @access public
+ * @return array
+ */
public function generateData ( ) {
- $data = array();
+ $data = array();
+ $specification = $this->getSpecification();
+
+ if(false === $specification->clauseExists('requires'))
+ return $data;
- foreach($this->_specification->getClause('requires') as $name => $variable)
+ foreach($specification->getClause('requires') as $name => $variable)
$data[$name] = $variable->sample();
- return $this->_data = $data;
+ $this->setData($data);
+
+ return $data;
}
/**
@@ -308,14 +417,14 @@ class Praspel {
$i = preg_match('#/\*(.*?)\*/#s', $comment, $matches);
if(0 === $i)
- throw new Exception(
+ throw new Exception\Generic(
'Not able to extract Praspel from the following ' .
'comment:' . "\n" . '%s', 1, $comment);
$i = preg_match_all('#^[\s\*]*\s*\*\s?([^\n]*)$#m', $matches[1], $maatches);
if(0 === $i)
- throw new Exception(
+ throw new Exception\Generic(
'Not able to extract Praspel from the following ' .
'comment:' . "\n" . '%s', 2, $comment);