/** * This constructor initializes the class using the specified options. * * @access public * @param string $id the id given to the state * @param \Unicity\Automaton\StateType $type the type of state * @param mixed $value the value associated with the state * @param mixed $constraint a constraint on the state * @param double $priority the priority given to the state */ public function __construct($id, Automaton\StateType $type, $value = null, $constraint = null, $priority = 0.0) { $this->constraint = $constraint; $this->id = $id; $this->priority = $priority; $this->transitions = new Common\Mutable\HashSet(); $this->type = $type !== null ? $type : Automaton\StateType::normal(); $this->value = $value; }
/** * This method recursively traverses the machine. * * @access protected * @param \Unicity\Common\IList $sigma the sigma to be processed * @param integer $i the index to the input symbol * @param \Unicity\Automaton\IState $state the current a set of target states * @param \Unicity\Common\Mutable\Stack $stack the path through which the pattern * was found * @return boolean whether the machine finished in * a goal state * a goal state * @throws \Unicity\Throwable\Parse\Exception indicates that the machine failed * to parse */ protected function traverse(Common\IList $sigma, $i, Automaton\IState $state, Common\Mutable\Stack $stack) { if ($i >= $sigma->count()) { return Automaton\StateType::goal()->__equals($state->getType()); } $transitions = $this->transitions->getValues($state->getTransitions()); usort($transitions, function (Core\IComparable $c0, Core\IComparable $c1) { return $c0->compareTo($c1); }); $hasTransitioned = false; foreach ($transitions as $transition) { if ($transition->isTraversable($sigma, $i)) { $targets = $this->states->getValues($transition->getTargets()); usort($targets, function (Core\IComparable $c0, Core\IComparable $c1) { return $c0->compareTo($c1); }); foreach ($targets as $target) { $stack->push($target->getId()); if ($this->traverse($sigma, $i + 1, $target, $stack)) { return true; } $stack->pop(); } $hasTransitioned = true; break; } } if (!$hasTransitioned) { throw new Throwable\Parse\Exception('Machine failed. Unable to transition between states.'); } return false; }
/** * This method runs the machine using the specified sigma (i.e. the input alphabet/sequence). * * @access public * @param \Unicity\Common\IList $sigma the sigma to be processed * @param \Unicity\Common\Mutable\IList $path the path through which the pattern * was found * @return boolean whether the machine finished in * a goal state * @throws \Unicity\Throwable\InvalidArgument\Exception indicates that no sigma has been * specified * @throws \Unicity\Throwable\Parse\Exception indicates that the machine failed * to parse */ public function run(Common\IList $sigma, Common\Mutable\IList $path = null) { if ($sigma === null || $sigma->isEmpty()) { throw new Throwable\InvalidArgument\Exception('No sigma has been defined.'); } $count = $sigma->count(); if ($this->initials === null || $this->initials->isEmpty()) { throw new Throwable\Parse\Exception('Machine failed. No initial state has been defined.'); } $stack = new Common\Mutable\Stack($path); $states = $this->states->getValues($this->initials); usort($states, function (Core\IComparable $c0, Core\IComparable $c1) { return $c0->compareTo($c1); }); $state = $states[0]; $stack->push($state->getId()); $this->onStart($this, $state); for ($i = 0; $i < $count; $i++) { $transitions = $this->transitions->getValues($state->getTransitions()); usort($transitions, function (Core\IComparable $c0, Core\IComparable $c1) { return $c0->compareTo($c1); }); $hasTransitioned = false; foreach ($transitions as $transition) { if ($transition->isTraversable($sigma, $i)) { $this->onExit($this, $state); $this->onTransition($this, $transition); $targets = $this->states->getValues($transition->getTargets()); usort($targets, function (Core\IComparable $c0, Core\IComparable $c1) { return $c0->compareTo($c1); }); $state = $targets[0]; $stack->push($state->getId()); $this->onEntry($this, $state); $hasTransitioned = true; break; } } if (!$hasTransitioned) { $stack->clear(); throw new Throwable\Parse\Exception('Machine failed. Unable to transition between states.'); } } $this->onCompletion($this, $state); if (Automaton\StateType::goal()->__equals($state->getType())) { return true; } $stack->clear(); return false; }