aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Grammar.pp11
-rw-r--r--Model/Throwable.php208
-rw-r--r--Visitor/Compiler.php105
-rw-r--r--Visitor/Interpreter.php63
-rw-r--r--Visitor/Praspel.php35
5 files changed, 340 insertions, 82 deletions
diff --git a/Grammar.pp b/Grammar.pp
index 4f4c6ba..9a18dab 100644
--- a/Grammar.pp
+++ b/Grammar.pp
@@ -172,9 +172,14 @@ exceptional_expression:
exception() ( ::and:: exception() )*
exception:
- classname() <identifier> ( ::or:: classname() <identifier> )* #exception_list
-// ( ::with:: declaration() #exception_with )?
-// NO
+ exception_identifier() ( ::or:: exception_identifier() )*
+ ( ::with:: exception_with() )?
+
+#exception_identifier:
+ classname() <identifier>
+
+#exception_with:
+ expression()
#declaration:
( ::let:: #local_declaration )?
diff --git a/Model/Throwable.php b/Model/Throwable.php
index 739edf7..53f81aa 100644
--- a/Model/Throwable.php
+++ b/Model/Throwable.php
@@ -44,6 +44,11 @@ from('Hoa')
-> import('Praspel.Model.Clause')
/**
+ * \Hoa\Praspel\Model\Ensures
+ */
+-> import('Praspel.Model.Ensures')
+
+/**
* \Hoa\Iterator\Aggregate
*/
-> import('Iterator.Aggregate')
@@ -78,14 +83,49 @@ class Throwable
*
* @const string
*/
- const NAME = 'throwable';
+ const NAME = 'throwable';
+
+ /**
+ * Identifier index.
+ *
+ * @const int
+ */
+ const IDENTIFIER = 0;
+
+ /**
+ * Instance of index.
+ *
+ * @const int
+ */
+ const INSTANCE_OF = 1;
+
+ /**
+ * With index.
+ *
+ * @const int
+ */
+ const WITH = 2;
+
+ /**
+ * Disjunction index.
+ *
+ * @const int
+ */
+ const DISJUNCTION = 3;
/**
* List of exception names.
*
* @var \Hoa\Praspel\Model\Throwable array
*/
- protected $_exceptions = array();
+ protected $_exceptions = array();
+
+ /**
+ * Current exception.
+ *
+ * @var \Hoa\Praspel\Model\Throwable array
+ */
+ protected $_currentException = null;
@@ -93,41 +133,49 @@ class Throwable
* Check if an exception identifier exists.
*
* @access public
- * @param string $offset Exception identifier.
+ * @param string $identifier Exception identifier.
* @return bool
*/
- public function offsetExists ( $offset ) {
+ public function offsetExists ( $identifier ) {
- return isset($this->_exceptions[$offset]);
+ return isset($this->_exceptions[$identifier]);
}
/**
- * Get an exception.
+ * Select an exception.
*
* @access public
- * @param string $offset Exception identifier.
- * @return \Hoa\Prasel\Model\Variable
+ * @param string $identifier Exception identifier.
+ * @return \Hoa\Praspel\Model\Throwable
*/
- public function offsetGet ( $offset ) {
+ public function offsetGet ( $identifier ) {
- if(false === $this->offsetExists($offset))
+ if(false === $this->offsetExists($identifier))
return null;
- return $this->_exceptions[$offset];
+ unset($this->_currentException);
+ $this->_currentException = &$this->_exceptions[$identifier];
+
+ return $this;
}
/**
* Add an exception.
*
* @access public
- * @param string $offset Exception identifier.
- * @param mixed $value Exception classname.
+ * @param string $identifier Exception identifier.
+ * @param mixed $instanceName Exception instance name.
* @return mixed
*/
- public function offsetSet ( $offset, $value ) {
+ public function offsetSet ( $identifier, $instanceName ) {
- $old = $this->offsetGet($offset);
- $this->_exceptions[$offset] = $value;
+ $old = $this->offsetGet($identifier);
+ $this->_exceptions[$identifier] = array(
+ static::IDENTIFIER => $identifier,
+ static::INSTANCE_OF => $instanceName,
+ static::WITH => null,
+ static::DISJUNCTION => null
+ );
return $old;
}
@@ -136,17 +184,137 @@ class Throwable
* Delete an exception.
*
* @access public
- * @param string $offset Exception identifier.
+ * @param string $identifier Exception identifier.
* @return void
*/
- public function offsetUnset ( $offset ) {
+ public function offsetUnset ( $identifier ) {
- unset($this->_exceptions[$offset]);
+ unset($this->_exceptions[$identifier]);
return;
}
/**
+ * Get instance name.
+ *
+ * @access public
+ * @return string
+ */
+ public function getInstanceName ( ) {
+
+ if(null === $this->_currentException)
+ return null;
+
+ return $this->_currentException[static::INSTANCE_OF];
+ }
+
+ /**
+ * Create a new with instance (an Hoa\Praspel\Model\Ensures instance with
+ * this instance as parent).
+ *
+ * @access public
+ * @return \Hoa\Praspel\Model\Ensures
+ */
+ public function newWith ( ) {
+
+ return new Ensures($this);
+ }
+
+ /**
+ * Set with declaration.
+ *
+ * @access public
+ * @param \Hoa\Praspel\Model\Ensures $with With.
+ * @return \Hoa\Praspel\Model\Throwable
+ */
+ public function setWith ( Ensures $with ) {
+
+ if(null === $this->_currentException)
+ return $this;
+
+ $this->_currentException[static::WITH] = $with;
+
+ return $this;
+ }
+
+ /**
+ * Get with declaration.
+ *
+ * @access public
+ * @return \Hoa\Praspel\Model\Ensures
+ */
+ public function getWith ( ) {
+
+ if(null === $this->_currentException)
+ return null;
+
+ return $this->_currentException[static::WITH];
+ }
+
+ /**
+ * Declare that this exception is disjointed with another one.
+ *
+ * @access public
+ * @param string $identifier Identifier.
+ * @return \Hoa\Praspel\Model\Throwable
+ */
+ public function disjunctionWith ( $identifier ) {
+
+ if(null === $this->_currentException)
+ return $this;
+
+ if(false === isset($this[$identifier]))
+ return $this;
+
+ $_identifier = &$this->_exceptions[$identifier];
+ $this->_currentException[static::WITH] = &$_identifier[static::WITH];
+
+ if(true === is_array($_identifier[static::DISJUNCTION]))
+ $_identifier[static::DISJUNCTION][] =
+ $this->_currentException[static::IDENTIFIER];
+ else
+ $_identifier[static::DISJUNCTION] = array(
+ $this->_currentException[static::IDENTIFIER]
+ );
+
+ $this->_currentException[static::DISJUNCTION] = $identifier;
+
+ return $this;
+ }
+
+ /**
+ * Check if an exception is disjointed with another one.
+ *
+ * @access public
+ * @return bool
+ */
+ public function isDisjointed ( ) {
+
+ return is_string($this->getDisjunction());
+ }
+
+ /**
+ * Get disjointed exceptions.
+ * Example:
+ * T1 t1 or T2 t2 or T3 t3
+ * For t1, this method will return an array containing t2 and t3.
+ * For t2, this method will return a string equals to t1.
+ * Same for t3.
+ * If this method returns null, it means that the exception is not in a
+ * disjunction.
+ *
+ * @access public
+ * @return mixed
+ */
+ public function getDisjunction ( ) {
+
+ if(null === $this->_currentException)
+ return null;
+
+ return $this->_currentException[static::DISJUNCTION];
+ }
+
+ /**
* Get exceptions list.
*
* @access public
@@ -165,7 +333,7 @@ class Throwable
*/
public function getIterator ( ) {
- return new \Hoa\Iterator\Map($this->getExceptions());
+ return new \Hoa\Iterator\Map(array_keys($this->getExceptions()));
}
/**
diff --git a/Visitor/Compiler.php b/Visitor/Compiler.php
index c14e6a3..d083572 100644
--- a/Visitor/Compiler.php
+++ b/Visitor/Compiler.php
@@ -110,58 +110,87 @@ class Compiler implements \Hoa\Visitor\Visit {
}
elseif($element instanceof \Hoa\Praspel\Model\Declaration) {
- $parent = '$' . $element->getParent()->getId();
- $variable = '$' . $element->getId();
- $clause = $element->getName();
+ $variable = '$' . ($eldnah ?: $element->getId());
$out = "\n" .
- $variable . ' = ' . $parent .
- '->getClause(\'' . $clause . '\');' . "\n";
+ $variable . ' = $' . $element->getParent()->getId() .
+ '->getClause(\'' . $element->getName() . '\');' . "\n";
- foreach($element as $name => $var) {
+ foreach($element as $var)
+ $out .= $var->accept($this, $handle, $eldnah);
- $start = $variable . '[\'' . $name . '\']';
+ foreach($element->getPredicates() as $predicate)
+ $out .= $variable . '->predicate(\'' . $predicate . '\');' . "\n";
+ }
+ elseif($element instanceof \Hoa\Praspel\Model\Variable) {
- if(true === $var->isLocal())
- $out .= $variable . '->let[\'' . $name . '\']';
- else
- $out .= $start;
+ $variable = '$' . ($eldnah ?: $element->getClause()->getId());
+ $name = $element->getName();
+ $start = $variable . '[\'' . $name . '\']';
- if(null === $alias = $var->getAlias())
- $out .= '->in = ' . $var->getDomains() . ';' . "\n";
- else
- $out .= '->domainof(\'' . $alias . '\');' . "\n";
+ if(true === $element->isLocal())
+ $out .= $variable . '->let[\'' . $name . '\']';
+ else
+ $out .= $start;
- $constraints = $var->getConstraints();
+ if(null === $alias = $element->getAlias())
+ $out .= '->in = ' . $element->getDomains() . ';' . "\n";
+ else
+ $out .= '->domainof(\'' . $alias . '\');' . "\n";
- if(isset($constraints['is']))
- $out .= $start . '->is(\'' .
- implode('\', \'', $constraints['is']) . '\');' .
- "\n";
+ $constraints = $element->getConstraints();
- if(isset($constraints['contains']))
- foreach($constraints['contains'] as $contains)
- $out .= $start . '->contains(' . $contains . ');' . "\n";
+ if(isset($constraints['is']))
+ $out .= $start . '->is(\'' .
+ implode('\', \'', $constraints['is']) . '\');' .
+ "\n";
- if(isset($constraints['key']))
- foreach($constraints['key'] as $pairs)
- $out .= $start . '->key(' . $pairs[0] . ')->in = ' .
- $pairs[1] . ';' . "\n";
- }
+ if(isset($constraints['contains']))
+ foreach($constraints['contains'] as $contains)
+ $out .= $start . '->contains(' . $contains . ');' . "\n";
- foreach($element->getPredicates() as $predicate)
- $out .= $variable . '->predicate(\'' . $predicate . '\');' . "\n";
+ if(isset($constraints['key']))
+ foreach($constraints['key'] as $pairs)
+ $out .= $start . '->key(' . $pairs[0] . ')->in = ' .
+ $pairs[1] . ';' . "\n";
}
elseif($element instanceof \Hoa\Praspel\Model\Throwable) {
- $parent = '$' . $element->getParent()->getId();
- $variable = '$' . $element->getId();
- $out = "\n" .
- $variable . ' = ' . $parent .
- '->getClause(\'throwable\');' . "\n";
+ $parent = '$' . $element->getParent()->getId();
+ $_variable = $element->getId();
+ $variable = '$' . $_variable;
+ $out = "\n" .
+ $variable . ' = ' . $parent .
+ '->getClause(\'throwable\');' . "\n";
- foreach($element->getExceptions() as $identifier => $class)
- $out .= $variable . '[\'' . $identifier . '\'] = \'' . $class .
- '\';' . "\n";
+ foreach($element as $identifier) {
+
+ $exception = $element[$identifier];
+ $start = $variable . '[\'' . $identifier . '\']';
+ $out .= $start . ' = \'' . $exception->getInstanceName() .
+ '\';' . "\n";
+
+ if(false === $element->isDisjointed()) {
+
+ if(null !== $with = $element->getWith()) {
+
+ $temp = $_variable . '_' . $identifier . '_with';
+ $out .= '$' . $temp . ' = ' .
+ $variable . '->newWith();' . "\n";
+
+ foreach($with as $var)
+ $out .= $var->accept($this, $handle, $temp);
+
+ foreach($with->getPredicates() as $predicate)
+ $out .= '$' . $temp . '->predicate(\'' . $predicate .
+ '\');' . "\n";
+
+ $out .= $start . '->setWith($' . $temp . ');' . "\n";
+ }
+ }
+ else
+ $out .= $start . '->disjunctionWith(\'' .
+ $exception->getDisjunction() . '\');' . "\n";
+ }
}
elseif($element instanceof \Hoa\Praspel\Model\Behavior) {
diff --git a/Visitor/Interpreter.php b/Visitor/Interpreter.php
index f0f6fc3..4337740 100644
--- a/Visitor/Interpreter.php
+++ b/Visitor/Interpreter.php
@@ -139,7 +139,6 @@ class Interpreter implements \Hoa\Visitor\Visit {
case '#requires':
case '#ensures':
case '#invariant':
- case '#throwable':
$this->_clause = $this->_current->getClause(substr($id, 1));
foreach($element->getChildren() as $child)
@@ -163,6 +162,50 @@ class Interpreter implements \Hoa\Visitor\Visit {
$this->_current = $previous;
break;
+ case '#throwable':
+ $this->_clause = $this->_current->getClause('throwable');
+ $identifier = null;
+
+ foreach($element->getChildren() as $child) {
+
+ switch($child->getId()) {
+
+ case '#exception_identifier':
+ $_identifier = $child->getChild(1)->accept(
+ $this,
+ $handle,
+ false
+ );
+ $_instanceof = $child->getChild(0)->accept(
+ $this,
+ $handle,
+ false
+ );
+
+ $this->_clause[$_identifier] = $_instanceof;
+
+ if(null === $identifier)
+ $identifier = $_identifier;
+ else
+ $this->_clause[$_identifier]->disjunctionWith(
+ $identifier
+ );
+ break;
+
+ case '#exception_with':
+ $old = $this->_clause;
+ $this->_clause = $old->newWith();
+
+ foreach($child->getChildren() as $_child)
+ $_child->accept($this, $handle, $eldnah);
+
+ $old[$identifier]->setWith($this->_clause);
+ $this->_clause = $old;
+ break;
+ }
+ }
+ break;
+
case '#description':
$this->_clause = $this->_root->getClause('description');
$this->_clause[] = $element->getChild(0)->accept(
@@ -172,24 +215,6 @@ class Interpreter implements \Hoa\Visitor\Visit {
);
break;
- case '#exception_list':
- for($i = 0, $max = $element->getChildrenNumber(); $i < $max; $i += 2) {
-
- $identifier = $element->getChild($i + 1)->accept(
- $this,
- $handle,
- false
- );
- $classname = $element->getChild($i)->accept(
- $this,
- $handle,
- false
- );
-
- $this->_clause[$identifier] = $classname;
- }
- break;
-
case '#declaration':
$variable = $element->getChild(0)
->accept($this, $handle, false);
diff --git a/Visitor/Praspel.php b/Visitor/Praspel.php
index b2c0da6..4ad2b07 100644
--- a/Visitor/Praspel.php
+++ b/Visitor/Praspel.php
@@ -154,8 +154,39 @@ class Praspel implements \Hoa\Visitor\Visit {
$oout = array();
- foreach($element->getExceptions() as $identifier => $class)
- $oout[] = ' ' . $class . ' ' . $identifier;
+ foreach($element as $identifier) {
+
+ $exception = $element[$identifier];
+
+ if(true === $exception->isDisjointed())
+ continue;
+
+ $line = ' ' . $exception->getInstanceName() . ' ' .
+ $identifier;
+
+ foreach((array) $exception->getDisjunction() as $_identifier) {
+
+ $_exception = $element[$_identifier];
+ $line .= ' or ' . $_exception->getInstanceName() . ' ' .
+ $_identifier;
+ }
+
+ if(null !== $with = $exception->getWith()) {
+
+ $line .= ' with ';
+ $liine = array();
+
+ foreach($with as $var)
+ $liine[] = $var->accept($this, $handle, $eldnah);
+
+ foreach($with->getPredicates() as $predicate)
+ $liine[] = '\pred(\'' . $predicate . '\')';
+
+ $line .= implode(' and ', $liine);
+ }
+
+ $oout[] = $line;
+ }
$out = '@throwable' . implode(' or', $oout) . ';';
}