/** * Sets up the finite state machine. */ private function setupFiniteStateMachine() { $this->fsm = new xfFiniteStateMachine(); $this->fsm->addStates(array(self::ST_QUERY, self::ST_RANGE_START, self::ST_RANGE_END, self::ST_RANGE_END_INDICATOR, self::ST_RANGE_SEPARATOR, self::ST_ERROR)); $this->fsm->setInitialState(self::ST_QUERY); $this->fsm->addTransitions(array(array(self::ST_QUERY, xfLexemeLucene::WORD, self::ST_QUERY), array(self::ST_QUERY, xfLexemeLucene::SYNTAX, self::ST_QUERY), array(self::ST_QUERY, xfLexemeLucene::PHRASE, self::ST_QUERY), array(self::ST_QUERY, xfLexemeLucene::NUMBER, self::ST_QUERY), array(self::ST_QUERY, xfLexemeLucene::FIELD, self::ST_QUERY), array(self::ST_QUERY, xfLexemeLucene::WILDCARD, self::ST_QUERY))); $this->fsm->addTransitions(array(array(self::ST_QUERY, xfLexemeLucene::RANGE_START_INCLUSIVE, self::ST_RANGE_START), array(self::ST_QUERY, xfLexemeLucene::RANGE_START_EXCLUSIVE, self::ST_RANGE_START), array(self::ST_RANGE_START, xfLexemeLucene::WORD, self::ST_RANGE_SEPARATOR), array(self::ST_RANGE_SEPARATOR, xfLexemeLucene::RANGE_SEPARATOR, self::ST_RANGE_END), array(self::ST_RANGE_END, xfLexemeLucene::WORD, self::ST_RANGE_END_INDICATOR), array(self::ST_RANGE_END_INDICATOR, xfLexemeLucene::RANGE_END_INCLUSIVE, self::ST_QUERY), array(self::ST_RANGE_END_INDICATOR, xfLexemeLucene::RANGE_END_EXCLUSIVE, self::ST_QUERY))); $addTerm = new xfCriterionBuilderAddTerm($this->builder); $addPhrase = new xfCriterionBuilderAddPhrase($this->builder, $this->phraseSlop); $addWildcard = new xfCriterionBuilderAddWildcard($this->builder); $addField = new xfCriterionBuilderSetField($this->builder); $handleSyntax = new xfCriterionBuilderLuceneHandleSyntax($this->builder); $handleRange = new xfCriterionBuilderLuceneHandleRange($this->builder); $this->fsm->addInputAction(self::ST_QUERY, xfLexemeLucene::WORD, $addTerm); $this->fsm->addInputAction(self::ST_QUERY, xfLexemeLucene::PHRASE, $addPhrase); $this->fsm->addInputAction(self::ST_QUERY, xfLexemeLucene::WILDCARD, $addWildcard); $this->fsm->addInputAction(self::ST_QUERY, xfLexemeLucene::FIELD, $addField); $this->fsm->addInputAction(self::ST_QUERY, xfLexemeLucene::SYNTAX, $handleSyntax); $this->fsm->addExitAction(self::ST_RANGE_END_INDICATOR, $handleRange); }
/** * Sets up the finite state machine according to rules for the Lucene query * syntax. * * This part of the algorithm is derived from the Zend Framework module, * Zend_Search_Lucene. Some modifications have been made. * * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ private function setupFiniteStateMachine() { $this->fsm = new xfFiniteStateMachine(); // These are our possible states. $this->fsm->addStates(array(self::ST_WHITE, self::ST_SYNTAX, self::ST_LEXEME, self::ST_QUOTED, self::ST_ESCAPED_CHAR, self::ST_ESCAPED_QCHAR, self::ST_MODIFIER, self::ST_NUMBER, self::ST_MANTISSA, self::ST_ERROR)); // Start at this state. $this->fsm->setInitialState(self::ST_WHITE); // These are the possible transitions. $this->fsm->addTransitions(array(array(self::ST_WHITE, self::IN_WHITE, self::ST_WHITE), array(self::ST_WHITE, self::IN_SYNTAX, self::ST_SYNTAX), array(self::ST_WHITE, self::IN_MODIFIER, self::ST_MODIFIER), array(self::ST_WHITE, self::IN_ESCAPE_CHAR, self::ST_ESCAPED_CHAR), array(self::ST_WHITE, self::IN_QUOTE, self::ST_QUOTED), array(self::ST_WHITE, self::IN_DECIMAL, self::ST_LEXEME), array(self::ST_WHITE, self::IN_NUMBER, self::ST_LEXEME), array(self::ST_WHITE, self::IN_CHAR, self::ST_LEXEME), array(self::ST_WHITE, self::IN_MUTABLE, self::ST_SYNTAX), array(self::ST_SYNTAX, self::IN_WHITE, self::ST_WHITE), array(self::ST_SYNTAX, self::IN_SYNTAX, self::ST_SYNTAX), array(self::ST_SYNTAX, self::IN_MODIFIER, self::ST_MODIFIER), array(self::ST_SYNTAX, self::IN_ESCAPE_CHAR, self::ST_ESCAPED_CHAR), array(self::ST_SYNTAX, self::IN_QUOTE, self::ST_QUOTED), array(self::ST_SYNTAX, self::IN_DECIMAL, self::ST_LEXEME), array(self::ST_SYNTAX, self::IN_NUMBER, self::ST_LEXEME), array(self::ST_SYNTAX, self::IN_CHAR, self::ST_LEXEME), array(self::ST_SYNTAX, self::IN_MUTABLE, self::ST_SYNTAX), array(self::ST_LEXEME, self::IN_WHITE, self::ST_WHITE), array(self::ST_LEXEME, self::IN_SYNTAX, self::ST_SYNTAX), array(self::ST_LEXEME, self::IN_MODIFIER, self::ST_MODIFIER), array(self::ST_LEXEME, self::IN_ESCAPE_CHAR, self::ST_ESCAPED_CHAR), array(self::ST_LEXEME, self::IN_QUOTE, self::ST_ERROR), array(self::ST_LEXEME, self::IN_DECIMAL, self::ST_LEXEME), array(self::ST_LEXEME, self::IN_NUMBER, self::ST_LEXEME), array(self::ST_LEXEME, self::IN_CHAR, self::ST_LEXEME), array(self::ST_LEXEME, self::IN_MUTABLE, self::ST_LEXEME), array(self::ST_QUOTED, self::IN_WHITE, self::ST_QUOTED), array(self::ST_QUOTED, self::IN_SYNTAX, self::ST_QUOTED), array(self::ST_QUOTED, self::IN_MODIFIER, self::ST_QUOTED), array(self::ST_QUOTED, self::IN_ESCAPE_CHAR, self::ST_ESCAPED_QCHAR), array(self::ST_QUOTED, self::IN_QUOTE, self::ST_WHITE), array(self::ST_QUOTED, self::IN_DECIMAL, self::ST_QUOTED), array(self::ST_QUOTED, self::IN_NUMBER, self::ST_QUOTED), array(self::ST_QUOTED, self::IN_CHAR, self::ST_QUOTED), array(self::ST_QUOTED, self::IN_MUTABLE, self::ST_QUOTED), array(self::ST_ESCAPED_CHAR, self::IN_WHITE, self::ST_LEXEME), array(self::ST_ESCAPED_CHAR, self::IN_SYNTAX, self::ST_LEXEME), array(self::ST_ESCAPED_CHAR, self::IN_MODIFIER, self::ST_LEXEME), array(self::ST_ESCAPED_CHAR, self::IN_ESCAPE_CHAR, self::ST_LEXEME), array(self::ST_ESCAPED_CHAR, self::IN_QUOTE, self::ST_LEXEME), array(self::ST_ESCAPED_CHAR, self::IN_DECIMAL, self::ST_LEXEME), array(self::ST_ESCAPED_CHAR, self::IN_NUMBER, self::ST_LEXEME), array(self::ST_ESCAPED_CHAR, self::IN_CHAR, self::ST_LEXEME), array(self::ST_ESCAPED_CHAR, self::IN_MUTABLE, self::ST_LEXEME), array(self::ST_ESCAPED_QCHAR, self::IN_WHITE, self::ST_QUOTED), array(self::ST_ESCAPED_QCHAR, self::IN_SYNTAX, self::ST_QUOTED), array(self::ST_ESCAPED_QCHAR, self::IN_MODIFIER, self::ST_QUOTED), array(self::ST_ESCAPED_QCHAR, self::IN_ESCAPE_CHAR, self::ST_QUOTED), array(self::ST_ESCAPED_QCHAR, self::IN_QUOTE, self::ST_QUOTED), array(self::ST_ESCAPED_QCHAR, self::IN_DECIMAL, self::ST_QUOTED), array(self::ST_ESCAPED_QCHAR, self::IN_NUMBER, self::ST_QUOTED), array(self::ST_ESCAPED_QCHAR, self::IN_CHAR, self::ST_QUOTED), array(self::ST_ESCAPED_QCHAR, self::IN_MUTABLE, self::ST_QUOTED), array(self::ST_MODIFIER, self::IN_WHITE, self::ST_WHITE), array(self::ST_MODIFIER, self::IN_SYNTAX, self::ST_SYNTAX), array(self::ST_MODIFIER, self::IN_MODIFIER, self::ST_MODIFIER), array(self::ST_MODIFIER, self::IN_ESCAPE_CHAR, self::ST_ERROR), array(self::ST_MODIFIER, self::IN_QUOTE, self::ST_ERROR), array(self::ST_MODIFIER, self::IN_DECIMAL, self::ST_MANTISSA), array(self::ST_MODIFIER, self::IN_NUMBER, self::ST_NUMBER), array(self::ST_MODIFIER, self::IN_CHAR, self::ST_ERROR), array(self::ST_MODIFIER, self::IN_MUTABLE, self::ST_SYNTAX), array(self::ST_NUMBER, self::IN_WHITE, self::ST_WHITE), array(self::ST_NUMBER, self::IN_SYNTAX, self::ST_SYNTAX), array(self::ST_NUMBER, self::IN_MODIFIER, self::ST_MODIFIER), array(self::ST_NUMBER, self::IN_ESCAPE_CHAR, self::ST_ERROR), array(self::ST_NUMBER, self::IN_QUOTE, self::ST_ERROR), array(self::ST_NUMBER, self::IN_DECIMAL, self::ST_MANTISSA), array(self::ST_NUMBER, self::IN_NUMBER, self::ST_NUMBER), array(self::ST_NUMBER, self::IN_CHAR, self::ST_ERROR), array(self::ST_NUMBER, self::IN_MUTABLE, self::ST_SYNTAX), array(self::ST_MANTISSA, self::IN_WHITE, self::ST_WHITE), array(self::ST_MANTISSA, self::IN_SYNTAX, self::ST_SYNTAX), array(self::ST_MANTISSA, self::IN_MODIFIER, self::ST_MODIFIER), array(self::ST_MANTISSA, self::IN_ESCAPE_CHAR, self::ST_ERROR), array(self::ST_MANTISSA, self::IN_QUOTE, self::ST_ERROR), array(self::ST_MANTISSA, self::IN_DECIMAL, self::ST_ERROR), array(self::ST_MANTISSA, self::IN_NUMBER, self::ST_MANTISSA), array(self::ST_MANTISSA, self::IN_CHAR, self::ST_ERROR), array(self::ST_MANTISSA, self::IN_MUTABLE, self::ST_SYNTAX))); // Actions for when an error occurs. $quoteWithinError = new xfParserFSMError('A quote within a lexeme is not allowed.'); $modifierError = new xfParserFSMError('Only a number, white space, or syntax can follow a modifier.'); $wrongNumberError = new xfParserFSMError('Invalid number syntax: make sure the number only has one decimal point and contains only digits.'); // Action for adding lexemes. $addChar = new xfLexemeBuilderAddChar($this->builder); $addLexeme = new xfLexemeBuilderAddLexeme($this->builder, xfLexemeLucene::WORD); $addModifier = new xfLexemeBuilderAddLexeme($this->builder, xfLexemeLucene::SYNTAX); $addQuoted = new xfLexemeBuilderAddLexeme($this->builder, xfLexemeLucene::PHRASE); $addNumber = new xfLexemeBuilderAddLexeme($this->builder, xfLexemeLucene::NUMBER); $addSyntax = new xfLexemeBuilderLuceneAddSyntax($this->builder); // Bind actions for when an error occurs. $this->fsm->addInputAction(self::ST_LEXEME, self::IN_QUOTE, $quoteWithinError); $this->fsm->addInputAction(self::ST_MODIFIER, self::IN_ESCAPE_CHAR, $modifierError); $this->fsm->addInputAction(self::ST_MODIFIER, self::IN_QUOTE, $modifierError); $this->fsm->addInputAction(self::ST_MODIFIER, self::IN_CHAR, $modifierError); $this->fsm->addInputAction(self::ST_NUMBER, self::IN_ESCAPE_CHAR, $wrongNumberError); $this->fsm->addInputAction(self::ST_NUMBER, self::IN_QUOTE, $wrongNumberError); $this->fsm->addInputAction(self::ST_NUMBER, self::IN_CHAR, $wrongNumberError); $this->fsm->addInputAction(self::ST_MANTISSA, self::IN_ESCAPE_CHAR, $wrongNumberError); $this->fsm->addInputAction(self::ST_MANTISSA, self::IN_QUOTE, $wrongNumberError); $this->fsm->addInputAction(self::ST_MANTISSA, self::IN_DECIMAL, $wrongNumberError); $this->fsm->addInputAction(self::ST_MANTISSA, self::IN_CHAR, $wrongNumberError); // Bind actions for adding a character. $this->fsm->addEntryAction(self::ST_LEXEME, $addChar); $this->fsm->addTransitionAction(self::ST_LEXEME, self::ST_LEXEME, $addChar); $this->fsm->addTransitionAction(self::ST_QUOTED, self::ST_QUOTED, $addChar); $this->fsm->addTransitionAction(self::ST_ESCAPED_QCHAR, self::ST_QUOTED, $addChar); $this->fsm->addEntryAction(self::ST_NUMBER, $addChar); $this->fsm->addEntryAction(self::ST_MANTISSA, $addChar); $this->fsm->addTransitionAction(self::ST_NUMBER, self::ST_NUMBER, $addChar); $this->fsm->addTransitionAction(self::ST_MANTISSA, self::ST_MANTISSA, $addChar); // Bind actions for adding a lexeme. $this->fsm->addTransitionAction(self::ST_LEXEME, self::ST_WHITE, $addLexeme); $this->fsm->addTransitionAction(self::ST_LEXEME, self::ST_SYNTAX, $addLexeme); $this->fsm->addTransitionAction(self::ST_LEXEME, self::ST_QUOTED, $addLexeme); $this->fsm->addTransitionAction(self::ST_LEXEME, self::ST_MODIFIER, $addLexeme); $this->fsm->addTransitionAction(self::ST_LEXEME, self::ST_NUMBER, $addLexeme); $this->fsm->addTransitionAction(self::ST_LEXEME, self::ST_MANTISSA, $addLexeme); // Bind actions for adding a quoted lexeme. $this->fsm->addTransitionAction(self::ST_QUOTED, self::ST_WHITE, $addQuoted); // Bind actions for adding a number. $this->fsm->addTransitionAction(self::ST_NUMBER, self::ST_WHITE, $addNumber); $this->fsm->addTransitionAction(self::ST_NUMBER, self::ST_SYNTAX, $addNumber); $this->fsm->addTransitionAction(self::ST_NUMBER, self::ST_MODIFIER, $addNumber); $this->fsm->addTransitionAction(self::ST_MANTISSA, self::ST_WHITE, $addNumber); $this->fsm->addTransitionAction(self::ST_MANTISSA, self::ST_SYNTAX, $addNumber); $this->fsm->addTransitionAction(self::ST_MANTISSA, self::ST_MODIFIER, $addNumber); // Bind actions for adding a modifier $this->fsm->addEntryAction(self::ST_MODIFIER, $addChar); $this->fsm->addEntryAction(self::ST_MODIFIER, $addModifier); // Bind actions for adding a syntax lexeme. $this->fsm->addEntryAction(self::ST_SYNTAX, $addSyntax); $this->fsm->addTransitionAction(self::ST_SYNTAX, self::ST_SYNTAX, $addSyntax); }
* file that was distributed with this source code. */ require dirname(__FILE__) . '/../../bootstrap/unit.php'; require 'fsm/xfFiniteStateMachine.class.php'; require 'fsm/xfFiniteStateMachineAction.interface.php'; require 'util/xfException.class.php'; $t = new lime_test(25, new lime_output_color()); class CounterAction implements xfFiniteStateMachineAction { public $counter = 0; public function execute() { $this->counter++; } } $fsm = new xfFiniteStateMachine(array('on', 'off', 'burned out', 'broken')); $fsm->setInitialState('off'); $fsm->addTransitions(array(array('on', 'push', 'off'), array('off', 'push', 'on'), array('on', 'smash', 'broken'), array('off', 'smash', 'broken'), array('off', 'wait', 'off'), array('broken', 'replace', 'off'), array('broken', 'wait', 'broken'), array('burned out', 'replace', 'off'), array('on', 'short out', 'burned out'))); $t->diag('->addTransitions(), ->addTransition()'); try { $msg = '->addTransitions() fails if array is not a two dimensional array with 3 items in the 2nd dimension'; $fsm->addTransitions(array('foo')); $t->fail($msg); } catch (Exception $e) { $t->pass($msg); } try { $msg = '->addTransition() fails if the source state does not exist.'; $fsm->addTransition('exploded', 'implode', 'on'); $t->fail($msg); } catch (Exception $e) {