Hoa central
Structural.php
Go to the documentation of this file.
1 <?php
2 
38 
39 use Hoa\Iterator;
40 use Hoa\Praspel;
41 
50 class Structural implements Iterator\Recursive
51 {
57  const STATE_REQUIRES = 0;
58 
64  const STATE_BEHAVIOR = 1;
65 
71  const STATE_ENSURES = 2;
72 
78  const STATE_THROWABLE = 3;
79 
85  protected $_specification = null;
86 
92  protected $_criteria = 3; // Coverage::CRITERIA_NORMAL
93  // | Coverage::CRITERIA_EXCEPTIONAL
94 
100  protected $_path = null;
101 
107  protected $_stack = null;
108 
114  protected $_pop = null;
115 
121  protected $_key = -1;
122 
129  protected $_current = null;
130 
131 
132 
139  public function __construct(Praspel\Model\Specification $specification)
140  {
141  $this->_specification = $specification;
142  $this->setCriteria(
144  );
145 
146  return;
147  }
148 
154  public function current()
155  {
156  $out = ['pre' => [], 'post' => []];
157 
158  foreach ($this->_path as $element) {
159  if ($element instanceof Praspel\Model\Requires) {
160  $out['pre'][] = $element;
161  } else {
162  $out['post'][] = $element;
163  }
164  }
165 
166  return $out;
167  }
168 
174  public function key()
175  {
176  return $this->_key;
177  }
178 
184  public function next()
185  {
186  $this->_current = null;
187 
188  if (0 === count($this->_stack)) {
189  return;
190  }
191 
192  while (0 === $this->_pop->top()) {
193  $this->_pop->pop();
194  $this->_path->pop();
195  $this->_pop->push($this->_pop->pop() - 1);
196  }
197 
198  list($behavior, $state) = array_values($this->_stack->pop());
199 
200  switch ($state) {
201  case static::STATE_REQUIRES:
202  ++$this->_key;
203 
204  if (true === $behavior->clauseExists('requires')) {
205  $this->_current = $behavior->getClause('requires');
206  $this->_path->push($this->_current);
207  } else {
208  $this->_current = true;
209  $this->_path->push(null);
210  }
211 
212  if (true === $behavior->clauseExists('behavior')) {
213  $behaviors = $behavior->getClause('behavior')->getIterator();
214  $this->_stack->push([
215  'behavior' => $behavior,
216  'state' => static::STATE_BEHAVIOR
217  ]);
218  $this->_stack->push([
219  'behavior' => $behaviors,
220  'state' => static::STATE_BEHAVIOR
221  ]);
222 
223  $this->_pop->push(
224  count($behaviors)
225  + (2 * $behavior->clauseExists('default'))
226  );
227  } else {
228  $this->_stack->push([
229  'behavior' => $behavior,
230  'state' => static::STATE_ENSURES
231  ]);
232  $this->_pop->push(2);
233  $this->next();
234  }
235 
236  break;
237 
238  case static::STATE_BEHAVIOR:
239  if (true === $behavior->valid()) {
240  $this->_stack->push([
241  'behavior' => $behavior,
242  'state' => static::STATE_BEHAVIOR
243  ]);
244  $this->_stack->push([
245  'behavior' => $behavior->current(),
246  'state' => static::STATE_REQUIRES
247  ]);
248  $behavior->next();
249  $this->next();
250 
251  break;
252  }
253 
254  list($parentBehavior, ) = array_values($this->_stack->pop());
255 
256  if (true === $parentBehavior->clauseExists('default')) {
257  $this->_stack->push([
258  'behavior' => $parentBehavior->getClause('default'),
259  'state' => static::STATE_ENSURES
260  ]);
261  }
262 
263  $this->next();
264 
265  break;
266 
267  case static::STATE_ENSURES:
268  $this->_stack->push([
269  'behavior' => $behavior,
270  'state' => static::STATE_THROWABLE
271  ]);
272 
273  if (false === $behavior->clauseExists('ensures') ||
274  0 === (Coverage::CRITERIA_NORMAL & $this->getCriteria())) {
275  $this->_pop->push($this->_pop->pop() - 1);
276  $this->next();
277 
278  break;
279  }
280 
281  ++$this->_key;
282  $this->_current = $behavior->getClause('ensures');
283  $this->_path->push($this->_current);
284  $this->_pop->push(0);
285 
286  break;
287 
288  case static::STATE_THROWABLE:
289  if (false === $behavior->clauseExists('throwable') ||
290  0 === (Coverage::CRITERIA_EXCEPTIONAL & $this->getCriteria())) {
291  $this->_pop->push($this->_pop->pop() - 1);
292  $this->next();
293 
294  break;
295  }
296 
297  ++$this->_key;
298  $this->_current = $behavior->getClause('throwable');
299 
300  $this->_path->push($this->_current);
301  $this->_pop->push(0);
302 
303  break;
304  }
305 
306  return;
307  }
308 
314  public function rewind()
315  {
316  $this->_key = -1;
317 
318  unset($this->_path);
319  $this->_path = new Praspel\Iterator\WeakStack();
320 
321  unset($this->_stack);
322  $this->_stack = new \SplStack();
323  $this->_stack->push([
324  'behavior' => $this->_specification,
325  'state' => static::STATE_REQUIRES
326  ]);
327 
328  unset($this->_pop);
329  $this->_pop = new \SplQueue();
330  $this->_pop->push(-1);
331 
332  $this->next();
333 
334  return $this->current();
335  }
336 
343  public function valid()
344  {
345  return null !== $this->_current;
346  }
347 
355  public function setCriteria($criteria)
356  {
357  if (0 !== (Coverage::CRITERIA_DOMAIN & $criteria) &&
358  0 !== (Coverage::CRITERIA_EXCEPTIONAL & $criteria)) {
359  throw new Praspel\Exception\Generic(
360  'Mixing CRITERIA_EXCEPTIONAL and CRITERIA_DOMAIN is not ' .
361  'supported yet. Sorry.',
362  0
363  );
364  }
365 
366  $old = $this->_criteria;
367  $this->_criteria = $criteria;
368 
369  return $old;
370  }
371 
377  public function getCriteria()
378  {
379  return $this->_criteria;
380  }
381 
387  public function hasChildren()
388  {
389  return 0 !== (Coverage::CRITERIA_DOMAIN & $this->getCriteria());
390  }
391 
398  public function getChildren()
399  {
400  $variables = [];
401  $current = $this->current();
402 
403  foreach ($current['pre'] as $clause) {
404  foreach ($clause->getLocalVariables() as $variable) {
405  $variables[] = $variable;
406  }
407  }
408 
409  foreach ($current['post'] as $clause) {
410  foreach ($clause->getLocalVariables() as $variable) {
411  $variables[] = $variable;
412  }
413  }
414 
415  return new Iterator\Recursive\Mock(
417  new Domain($variables),
418  function ($current) {
419  $out = ['pre' => [], 'post' => []];
420 
421  foreach ($current as $name => $variable) {
422  $clause = $variable->getHolder()->getClause();
423 
424  if ($clause instanceof Praspel\Model\Requires) {
425  $out['pre'][$name] = $variable;
426  } else {
427  $out['post'][$name] = $variable;
428  }
429  }
430 
431  return $out;
432  }
433  )
434  );
435  }
436 }
__construct(Praspel\Model\Specification $specification)
Definition: Structural.php:139