Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

More work

  • Loading branch information...
commit 2d0f22c99173f536000e674319399831e29fe99e 1 parent 26649b8
@relaxnow authored
Showing with 1,207 additions and 258 deletions.
  1. +4 −0 .gitignore
  2. +1 −1  phpunit.xml.dist
  3. +0 −17 preload.php
  4. +23 −2 src/QueryLang/v1/Parser.php
  5. +11 −5 src/QueryLang/v1/Peg/Parser.php
  6. +11 −5 src/QueryLang/v1/Peg/grammar.peg.inc
  7. +7 −0 src/QueryLang/v1/SyntaxException.php
  8. +23 −2 src/QueryLang/v2/Parser.php
  9. +23 −32 src/QueryLang/v2/Peg/Parser.php
  10. +4 −7 src/QueryLang/v2/Peg/grammar.peg.inc
  11. +7 −0 src/QueryLang/v2/SyntaxException.php
  12. +70 −0 src/QueryLang/v3/Lexer.php
  13. +17 −3 src/QueryLang/v3/Node/Query.php
  14. +0 −11 src/QueryLang/v3/Node/Term.php
  15. +68 −12 src/QueryLang/v3/Parser.php
  16. +178 −78 src/QueryLang/v3/Peg/Parser.php
  17. +65 −19 src/QueryLang/v3/Peg/grammar.peg.inc
  18. +7 −0 src/QueryLang/v3/SyntaxException.php
  19. +32 −0 src/QueryLang/v3/Token.php
  20. +8 −0 src/QueryLang/v4/Node/LiteralTerm.php
  21. +49 −1 src/QueryLang/v4/Parser.php
  22. +325 −0 src/QueryLang/v4/Peg/Parser.php
  23. +97 −5 src/QueryLang/v4/Peg/grammar.peg.inc
  24. +23 −0 tests/QueryLang/v1/ParserTest.php
  25. +0 −19 tests/QueryLang/v1/ParserTests.php
  26. +8 −0 tests/QueryLang/v1/Peg/ParserTest.php
  27. +31 −0 tests/QueryLang/v2/ParserTest.php
  28. +0 −17 tests/QueryLang/v2/ParserTests.php
  29. +8 −0 tests/QueryLang/v2/Peg/ParserTest.php
  30. +73 −8 tests/QueryLang/v3/ParserTest.php
  31. +8 −0 tests/QueryLang/v3/Peg/ParserTest.php
  32. +14 −14 tests/QueryLang/v4/ParserTest.php
  33. +8 −0 tests/QueryLang/v4/Peg/ParserTest.php
  34. +4 −0 tests/bootstrap.php
View
4 .gitignore
@@ -0,0 +1,4 @@
+autoload.php
+composer.lock
+composer.phar
+bin
View
2  phpunit.xml.dist
@@ -9,7 +9,7 @@
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
- bootstrap="preload.php"
+ bootstrap="tests/bootstrap.php"
>
<testsuites>
<testsuite name="QueryLang test suite">
View
17 preload.php
@@ -1,17 +0,0 @@
-<?php
-
-// Find all PHP files in ./src/
-$files = new RegexIterator(
- new RecursiveIteratorIterator(
- new RecursiveDirectoryIterator(__DIR__ . '/src/')
- ),
- '/^.+\.php$/i',
- RecursiveRegexIterator::GET_MATCH
-);
-
-// and require them
-foreach ($files as $file) {
- $file = $file[0];
- echo "Preloading: $file" . PHP_EOL;
- require $file;
-}
View
25 src/QueryLang/v1/Parser.php
@@ -13,8 +13,29 @@ public function __construct($string)
public function parse()
{
+ // Match a term
+ $token = $this->_match('[\w\d]+');
+
+ // Anything left after matching?
+ if (!empty($this->_string)) {
+ throw new SyntaxException('Unrecognized input: ' . $this->_string);
+ }
+
+ return $token;
+ }
+
+ protected function _match($regex)
+ {
$matches = array();
- preg_match('/(?<term>[\w\d]+)/', $this->_string, $matches);
- return $matches['term'];
+ $matched = preg_match("/^$regex/", $this->_string, $matches);
+ if (!$matched) {
+ return '';
+ }
+ $token = $matches[0];
+
+ // consume the token from the input
+ $this->_string = substr($this->_string, strlen($token));
+
+ return $token;
}
}
View
16 src/QueryLang/v1/Peg/Parser.php
@@ -2,9 +2,9 @@
namespace QueryLang\v1\Peg;
-require __DIR__ . '/../../../../vendor/hafriedlander/php-peg/Parser.php';
+require_once __DIR__ . '/../../../../vendor/hafriedlander/php-peg/Parser.php';
-class QueryLangV1 extends \Parser {
+class Parser extends \Parser {
/* Term: /[\w\d]+/ */
protected $match_Term_typestack = array('Term');
@@ -19,7 +19,13 @@ function match_Term ($stack = array()) {
-}
-$parser = new QueryLangV1('slipping');
-var_dump($parser->match_Term());
+ public function parse()
+ {
+ $match = $this->match_Term();
+ if (!$match) {
+ return '';
+ }
+ return $match['text'];
+ }
+}
View
16 src/QueryLang/v1/Peg/grammar.peg.inc
@@ -2,16 +2,22 @@
namespace QueryLang\v1\Peg;
-require __DIR__ . '/../../../../vendor/hafriedlander/php-peg/Parser.php';
+require_once __DIR__ . '/../../../../vendor/hafriedlander/php-peg/Parser.php';
-class QueryLangV1 extends \Parser {
+class Parser extends \Parser {
/*!* QueryLangV1
Term: /[\w\d]+/
*/
-}
-$parser = new QueryLangV1('slipping');
-var_dump($parser->match_Term());
+ public function parse()
+ {
+ $match = $this->match_Term();
+ if (!$match) {
+ return '';
+ }
+ return $match['text'];
+ }
+}
View
7 src/QueryLang/v1/SyntaxException.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace QueryLang\v1;
+
+class SyntaxException extends \RuntimeException
+{
+}
View
25 src/QueryLang/v2/Parser.php
@@ -13,8 +13,29 @@ public function __construct($string)
public function parse()
{
+ // Match a term
+ $token = $this->_match('[\w\d]+');
+
+ // Anything left after matching?
+ if (!empty($this->_string)) {
+ throw new SyntaxException('Unrecognized input: ' . $this->_string);
+ }
+
+ return $token;
+ }
+
+ protected function _match($regex)
+ {
$matches = array();
- preg_match_all('/(?<term>[\w\d]+)/', $this->_string, $matches);
- return $matches['term'];
+ $matched = preg_match("/^$regex/", $this->_string, $matches);
+ if (!$matched) {
+ return '';
+ }
+ $token = $matches[0];
+
+ // consume the token from the input
+ $this->_string = substr($this->_string, strlen($token));
+
+ return $token;
}
}
View
55 src/QueryLang/v2/Peg/Parser.php
@@ -1,44 +1,38 @@
<?php
-namespace QueryLang\v1\Peg;
+namespace QueryLang\v2\Peg;
-require __DIR__ . '/../../../../vendor/hafriedlander/php-peg/Parser.php';
+require_once __DIR__ . '/../../../../vendor/hafriedlander/php-peg/Parser.php';
-class QueryLangV2 extends \Parser {
- /* Query: Term > Query* */
+class Parser extends \Parser {
+ /* Query: (Term >)* */
protected $match_Query_typestack = array('Query');
function match_Query ($stack = array()) {
$matchrule = "Query"; $result = $this->construct($matchrule, $matchrule, null);
- $_3 = NULL;
- do {
- $matcher = 'match_'.'Term'; $key = $matcher; $pos = $this->pos;
- $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
- if ($subres !== FALSE) {
- $this->store( $result, $subres );
- }
- else { $_3 = FALSE; break; }
- if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; }
- while (true) {
- $res_2 = $result;
- $pos_2 = $this->pos;
- $matcher = 'match_'.'Query'; $key = $matcher; $pos = $this->pos;
+ while (true) {
+ $res_3 = $result;
+ $pos_3 = $this->pos;
+ $_2 = NULL;
+ do {
+ $matcher = 'match_'.'Term'; $key = $matcher; $pos = $this->pos;
$subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
if ($subres !== FALSE) {
$this->store( $result, $subres );
}
- else {
- $result = $res_2;
- $this->pos = $pos_2;
- unset( $res_2 );
- unset( $pos_2 );
- break;
- }
+ else { $_2 = FALSE; break; }
+ if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; }
+ $_2 = TRUE; break;
+ }
+ while(0);
+ if( $_2 === FALSE) {
+ $result = $res_3;
+ $this->pos = $pos_3;
+ unset( $res_3 );
+ unset( $pos_3 );
+ break;
}
- $_3 = TRUE; break;
}
- while(0);
- if( $_3 === TRUE ) { return $this->finalise($result); }
- if( $_3 === FALSE) { return FALSE; }
+ return $this->finalise($result);
}
@@ -68,7 +62,4 @@ public function Query_Term($result, $sub)
{
$this->_terms[] = $sub['text'];
}
-}
-
-$parser = new QueryLangV2('slipping angels devils');
-var_dump($parser->parse());
+}
View
11 src/QueryLang/v2/Peg/grammar.peg.inc
@@ -2,12 +2,12 @@
namespace QueryLang\v2\Peg;
-require __DIR__ . '/../../../../vendor/hafriedlander/php-peg/Parser.php';
+require_once __DIR__ . '/../../../../vendor/hafriedlander/php-peg/Parser.php';
-class QueryLangV2 extends \Parser {
+class Parser extends \Parser {
/*!* QueryLangV2
- Query: Term > Query*
+ Query: (Term >)*
Term: /[\w\d]+/
*/
@@ -24,7 +24,4 @@ class QueryLangV2 extends \Parser {
{
$this->_terms[] = $sub['text'];
}
-}
-
-$parser = new QueryLangV2('slipping angels devils');
-var_dump($parser->parse());
+}
View
7 src/QueryLang/v2/SyntaxException.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace QueryLang\v2;
+
+class SyntaxException extends \RuntimeException
+{
+}
View
70 src/QueryLang/v3/Lexer.php
@@ -0,0 +1,70 @@
+<?php
+
+namespace QueryLang\v3;
+
+class Lexer
+{
+ private $_input;
+ private $_pos = 0;
+ private $_tokens;
+
+ /**
+ * @param string $input
+ */
+ public function __construct($input)
+ {
+ $this->_input = $input;
+ }
+
+ /**
+ * @param int $pos
+ * @return Token
+ */
+ public function lookAhead($pos = 0)
+ {
+ return $this->_tokens[$pos];
+ }
+
+ /**
+ * @return Token
+ */
+ public function nextToken()
+ {
+ return array_shift($this->_tokens);
+ }
+
+ public function lex()
+ {
+ while (!empty($this->_input)) {
+ if ($this->_match('LeftParen' , '/^(\()/')) {continue;}
+ if ($this->_match('RightParen' , '/^(\))/')) {continue;}
+ if ($this->_match('OR' , '/^(OR)/i')) {continue;}
+ if ($this->_match('AND' , '/^(AND)/i')) {continue;}
+ if ($this->_match('TermValue' , '/^([\w\d]+)/i')) {continue;}
+ if ($this->_match('WS' , '/^\s+/i', true)) {continue;}
+
+ throw new SyntaxException(
+ "Unrecognized character in input stream: '{$this->_input[0]}' at position " . $this->_pos
+ );
+ }
+ $this->_tokens[] = new Token('EOS', '', $this->_pos);
+ }
+
+ protected function _match($type, $regex, $skip = false)
+ {
+ $matches = array();
+ if (!preg_match($regex, $this->_input, $matches)) {
+ return false;
+ }
+
+ if (!$skip) {
+ $this->_tokens[] = new Token($type, $matches[0], $this->_pos);
+ }
+
+ $tokenLength = strlen($matches[0]);
+ $this->_input = substr($this->_input, strlen($matches[0]));
+ $this->_pos += $tokenLength;
+
+ return true;
+ }
+}
View
20 src/QueryLang/v3/Node/Query.php
@@ -4,15 +4,29 @@
class Query
{
- protected $_terms = array();
+ private $_operator;
+ private $_terms = array();
+ private $_subQueries = array();
+
+ public function __construct($operator = 'OR')
+ {
+ $this->_operator = $operator;
+ }
+
+ public function getOperator()
+ {
+ return $this->_operator;
+ }
public function addTerm(Term $term)
{
$this->_terms[] = $term;
+ return $term;
}
- public function getTerms()
+ public function addSubQuery(Query $query)
{
- return $this->_terms;
+ $this->_subQueries[] = $query;
+ return $query;
}
}
View
11 src/QueryLang/v3/Node/Term.php
@@ -5,20 +5,9 @@
class Term
{
private $_value;
- private $_modifier;
public function __construct($value)
{
$this->_value = $value;
}
-
- public function setModifier($modifier)
- {
- $this->_modifier = $modifier;
- }
-
- public function getModifier()
- {
- return $this->_modifier;
- }
}
View
80 src/QueryLang/v3/Parser.php
@@ -2,32 +2,88 @@
namespace QueryLang\v3;
+/**
+ * Query: OrQuery
+ * OrQuery: AndQuery ([ OR ] AndQuery)*
+ * AndQuery: Term ([ AND ] Term)*
+ * Term: ParenLeft Query ParenRight | TermValue
+ */
class Parser
{
- private $_string;
+ protected $_lexer;
public function __construct($string)
{
- $this->_string = $string;
+ $this->_lexer = new Lexer($string);
}
public function parse()
{
- $matches = array();
- preg_match_all('/(?<modifier>[+-]*)(?<term>[\w\d]+)/', $this->_string, $matches);
+ $this->_lexer->lex();
+ $query = $this->_query();
+
+ return $query;
+ }
+
+ protected function _query()
+ {
$query = new \QueryLang\v3\Node\Query();
- foreach ($matches['term'] as $index => $term) {
- $term = new \QueryLang\v3\Node\Term($term);
+ $this->_orQuery($query);
+ return $query;
+ }
+
+ protected function _orQuery(\QueryLang\v3\Node\Query $query)
+ {
+ $this->_andQuery($query);
+ // As long as we have input...
+ while ($this->_predict()->getType() === 'OR') {
+ $this->_accept('OR');
+ $this->_andQuery($query);
+ }
+ }
- $termModifier = $matches['modifier'][$index];
- if ($termModifier) {
- $term->setModifier($termModifier);
- }
+ protected function _andQuery(\QueryLang\v3\Node\Query $query)
+ {
+ $this->_term($query);
+ while ($this->_predict()->getType() === 'AND') {
+ $this->_accept('AND');
+ $this->_term($query);
+ }
+ }
- $query->addTerm($term);
+ protected function _term(\QueryLang\v3\Node\Query $query)
+ {
+ $nextTokenType = $this->_predict()->getType();
+ if ($nextTokenType === 'LeftParen') {
+ $this->_accept('LeftParen');
+ $query->addSubQuery($this->_query());
+ $this->_accept('RightParen');
}
+ else if ($nextTokenType === 'TermValue') {
+ $termValue = $this->_accept('TermValue');
+ $query->addTerm(new \QueryLang\v3\Node\Term($termValue));
+ }
+ else {
+ throw new SyntaxException(
+ "Unexpected token '{$nextTokenType}', expecting a term or a subquery!"
+ );
+ }
+ }
- return $query;
+ protected function _predict()
+ {
+ return $this->_lexer->lookAhead();
+ }
+
+ protected function _accept($tokenType)
+ {
+ $token = $this->_lexer->nextToken();
+ if ($token->getType() !== $tokenType) {
+ throw new SyntaxException(
+ "Unexpected token at " . $this->getPos() . ", expecting: $tokenType"
+ );
+ }
+ return $token->getValue();
}
}
View
256 src/QueryLang/v3/Peg/Parser.php
@@ -2,105 +2,164 @@
namespace QueryLang\v3\Peg;
-require __DIR__ . '/../Node/Query.php';
-require __DIR__ . '/../Node/Term.php';
-require __DIR__ . '/../../../../vendor/hafriedlander/php-peg/Parser.php';
+require_once __DIR__ . '/../Node/Query.php';
+require_once __DIR__ . '/../Node/Term.php';
+require_once __DIR__ . '/../../../../vendor/hafriedlander/php-peg/Parser.php';
-class QueryLangV3 extends \Parser {
- /* Query: Term > Query* */
+class Parser extends \Parser {
+ /* Query: OrQuery */
protected $match_Query_typestack = array('Query');
function match_Query ($stack = array()) {
$matchrule = "Query"; $result = $this->construct($matchrule, $matchrule, null);
- $_3 = NULL;
+ $matcher = 'match_'.'OrQuery'; $key = $matcher; $pos = $this->pos;
+ $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
+ if ($subres !== FALSE) {
+ $this->store( $result, $subres );
+ return $this->finalise($result);
+ }
+ else { return FALSE; }
+ }
+
+
+ /* OrQuery: AndQuery ([ "OR" ] AndQuery)* */
+ protected $match_OrQuery_typestack = array('OrQuery');
+ function match_OrQuery ($stack = array()) {
+ $matchrule = "OrQuery"; $result = $this->construct($matchrule, $matchrule, null);
+ $_8 = NULL;
+ do {
+ $matcher = 'match_'.'AndQuery'; $key = $matcher; $pos = $this->pos;
+ $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
+ if ($subres !== FALSE) {
+ $this->store( $result, $subres );
+ }
+ else { $_8 = FALSE; break; }
+ while (true) {
+ $res_7 = $result;
+ $pos_7 = $this->pos;
+ $_6 = NULL;
+ do {
+ if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; }
+ else { $_6 = FALSE; break; }
+ if (( $subres = $this->literal( 'OR' ) ) !== FALSE) { $result["text"] .= $subres; }
+ else { $_6 = FALSE; break; }
+ if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; }
+ else { $_6 = FALSE; break; }
+ $matcher = 'match_'.'AndQuery'; $key = $matcher; $pos = $this->pos;
+ $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
+ if ($subres !== FALSE) {
+ $this->store( $result, $subres );
+ }
+ else { $_6 = FALSE; break; }
+ $_6 = TRUE; break;
+ }
+ while(0);
+ if( $_6 === FALSE) {
+ $result = $res_7;
+ $this->pos = $pos_7;
+ unset( $res_7 );
+ unset( $pos_7 );
+ break;
+ }
+ }
+ $_8 = TRUE; break;
+ }
+ while(0);
+ if( $_8 === TRUE ) { return $this->finalise($result); }
+ if( $_8 === FALSE) { return FALSE; }
+ }
+
+
+ /* AndQuery: Term ([ "AND" ] Term)* */
+ protected $match_AndQuery_typestack = array('AndQuery');
+ function match_AndQuery ($stack = array()) {
+ $matchrule = "AndQuery"; $result = $this->construct($matchrule, $matchrule, null);
+ $_17 = NULL;
do {
$matcher = 'match_'.'Term'; $key = $matcher; $pos = $this->pos;
$subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
if ($subres !== FALSE) {
$this->store( $result, $subres );
}
- else { $_3 = FALSE; break; }
- if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; }
+ else { $_17 = FALSE; break; }
while (true) {
- $res_2 = $result;
- $pos_2 = $this->pos;
- $matcher = 'match_'.'Query'; $key = $matcher; $pos = $this->pos;
- $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
- if ($subres !== FALSE) {
- $this->store( $result, $subres );
+ $res_16 = $result;
+ $pos_16 = $this->pos;
+ $_15 = NULL;
+ do {
+ if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; }
+ else { $_15 = FALSE; break; }
+ if (( $subres = $this->literal( 'AND' ) ) !== FALSE) { $result["text"] .= $subres; }
+ else { $_15 = FALSE; break; }
+ if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; }
+ else { $_15 = FALSE; break; }
+ $matcher = 'match_'.'Term'; $key = $matcher; $pos = $this->pos;
+ $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
+ if ($subres !== FALSE) {
+ $this->store( $result, $subres );
+ }
+ else { $_15 = FALSE; break; }
+ $_15 = TRUE; break;
}
- else {
- $result = $res_2;
- $this->pos = $pos_2;
- unset( $res_2 );
- unset( $pos_2 );
+ while(0);
+ if( $_15 === FALSE) {
+ $result = $res_16;
+ $this->pos = $pos_16;
+ unset( $res_16 );
+ unset( $pos_16 );
break;
}
}
- $_3 = TRUE; break;
+ $_17 = TRUE; break;
}
while(0);
- if( $_3 === TRUE ) { return $this->finalise($result); }
- if( $_3 === FALSE) { return FALSE; }
+ if( $_17 === TRUE ) { return $this->finalise($result); }
+ if( $_17 === FALSE) { return FALSE; }
}
- /* Term: Modifier* TermValue */
+ /* Term: "(" Query ")" | /[\w\d]+/ */
protected $match_Term_typestack = array('Term');
function match_Term ($stack = array()) {
$matchrule = "Term"; $result = $this->construct($matchrule, $matchrule, null);
- $_7 = NULL;
+ $_26 = NULL;
do {
- while (true) {
- $res_5 = $result;
- $pos_5 = $this->pos;
- $matcher = 'match_'.'Modifier'; $key = $matcher; $pos = $this->pos;
+ $res_19 = $result;
+ $pos_19 = $this->pos;
+ $_23 = NULL;
+ do {
+ if (substr($this->string,$this->pos,1) == '(') {
+ $this->pos += 1;
+ $result["text"] .= '(';
+ }
+ else { $_23 = FALSE; break; }
+ $matcher = 'match_'.'Query'; $key = $matcher; $pos = $this->pos;
$subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
if ($subres !== FALSE) {
$this->store( $result, $subres );
}
- else {
- $result = $res_5;
- $this->pos = $pos_5;
- unset( $res_5 );
- unset( $pos_5 );
- break;
+ else { $_23 = FALSE; break; }
+ if (substr($this->string,$this->pos,1) == ')') {
+ $this->pos += 1;
+ $result["text"] .= ')';
}
+ else { $_23 = FALSE; break; }
+ $_23 = TRUE; break;
}
- $matcher = 'match_'.'TermValue'; $key = $matcher; $pos = $this->pos;
- $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
- if ($subres !== FALSE) {
- $this->store( $result, $subres );
+ while(0);
+ if( $_23 === TRUE ) { $_26 = TRUE; break; }
+ $result = $res_19;
+ $this->pos = $pos_19;
+ if (( $subres = $this->rx( '/[\w\d]+/' ) ) !== FALSE) {
+ $result["text"] .= $subres;
+ $_26 = TRUE; break;
}
- else { $_7 = FALSE; break; }
- $_7 = TRUE; break;
+ $result = $res_19;
+ $this->pos = $pos_19;
+ $_26 = FALSE; break;
}
while(0);
- if( $_7 === TRUE ) { return $this->finalise($result); }
- if( $_7 === FALSE) { return FALSE; }
- }
-
-
- /* Modifier: /[+-]/ */
- protected $match_Modifier_typestack = array('Modifier');
- function match_Modifier ($stack = array()) {
- $matchrule = "Modifier"; $result = $this->construct($matchrule, $matchrule, null);
- if (( $subres = $this->rx( '/[+-]/' ) ) !== FALSE) {
- $result["text"] .= $subres;
- return $this->finalise($result);
- }
- else { return FALSE; }
- }
-
-
- /* TermValue: /[\w\d]+/ */
- protected $match_TermValue_typestack = array('TermValue');
- function match_TermValue ($stack = array()) {
- $matchrule = "TermValue"; $result = $this->construct($matchrule, $matchrule, null);
- if (( $subres = $this->rx( '/[\w\d]+/' ) ) !== FALSE) {
- $result["text"] .= $subres;
- return $this->finalise($result);
- }
- else { return FALSE; }
+ if( $_26 === TRUE ) { return $this->finalise($result); }
+ if( $_26 === FALSE) { return FALSE; }
}
@@ -113,29 +172,70 @@ function match_TermValue ($stack = array()) {
public function parse()
{
- $this->_query = new \QueryLang\v3\Node\Query();
+ $node = $this->match_Query();
+ return $node['query'];
+ }
- $this->match_Query();
+ public function Query__construct(&$result)
+ {
+ $result['query'] = new \QueryLang\v3\Node\Query();
+ var_dump(__METHOD__); var_dump(func_get_args());
+ }
+
+ public function Query_OrQuery(&$result, $sub)
+ {
+ var_dump(__METHOD__); var_dump(func_get_args());
+ $result['query']->addSubQuery($sub['query']);
+ }
- return $this->_query;
+ public function OrQuery__construct(&$result)
+ {
+ $result['query'] = new \QueryLang\v3\Node\Query();
+ var_dump(__METHOD__); var_dump(func_get_args());
}
- public function Query_Term(&$result, $sub)
+ public function OrQuery_AndQuery(&$result, $sub)
{
- $term = new \QueryLang\v3\Node\Term($sub['value']);
- if (isset($sub['modifier'])) {
- $term->setModifier($sub['modifier']);
+ if (isset($sub['query'])) {
+ $result['query']->addSubQuery($sub['query']);
+ }
+ else if (isset($sub['firstTerm'])) {
+ $result['query']->addTerm($sub['firstTerm']);
+ unset($sub['firstTerm']);
}
- $this->_query->addTerm($term);
+ var_dump(__METHOD__); var_dump(func_get_args());
}
- public function Term_TermValue(&$result, $sub)
+ public function AndQuery_Term(&$result, $sub)
{
- $result['value'] = $sub['text'];
+ $term = new \QueryLang\v3\Node\Term($sub['text']);
+ if (isset($result['query'])) {
+ $result['query']->addTerm($term);
+ }
+ // Second term, we can be sure this is a subquery now, so create it...
+ else if (isset($result['firstTerm'])) {
+ $query = new \QueryLang\v3\Node\Query('AND');
+ $query->addTerm($result['firstTerm']);
+ $query->addTerm($term);
+ $result['query'] = $query;
+ }
+ // May contain a subquery
+ else if (isset($sub['query'])) {
+ $query = new \QueryLang\v3\Node\Query('AND');
+ $query->addSubQuery($sub['query']);
+ $result['query'];
+ }
+ // May just be a single term...
+ else {
+ $result['firstTerm'] = $term;
+ }
+
+ var_dump(__METHOD__); var_dump(func_get_args());
}
- public function Term_Modifier(&$result, $sub)
+ public function Term_Query(&$result, $sub)
{
- $result['modifier'] = $sub['text'];
+ $result['query'] = $sub['query'];
+ var_dump(__METHOD__); var_dump(func_get_args());
}
}
View
84 src/QueryLang/v3/Peg/grammar.peg.inc
@@ -2,16 +2,21 @@
namespace QueryLang\v3\Peg;
-require __DIR__ . '/../Node/Query.php';
-require __DIR__ . '/../Node/Term.php';
-require __DIR__ . '/../../../../vendor/hafriedlander/php-peg/Parser.php';
+require_once __DIR__ . '/../Node/Query.php';
+require_once __DIR__ . '/../Node/Term.php';
+require_once __DIR__ . '/../../../../vendor/hafriedlander/php-peg/Parser.php';
-class QueryLangV3 extends \Parser {
+class Parser extends \Parser {
/*!* QueryLangV3
- Query: Term > Query*
- Term: Modifier* TermValue
- Modifier: /[+-]/
+ Query: OrQuery
+ OrQuery: AndQuery ([ OR ] AndQuery)*
+ AndQuery: Term ([ AND ] Term)*
+ Term: ParenLeft Query ParenRight | TermValue
+ OR: "OR"
+ AND: "AND"
+ ParenLeft: "("
+ ParenRight: ")"
TermValue: /[\w\d]+/
*/
@@ -23,29 +28,70 @@ class QueryLangV3 extends \Parser {
public function parse()
{
- $this->_query = new \QueryLang\v3\Node\Query();
+ $node = $this->match_Query();
+ return $node['query'];
+ }
- $this->match_Query();
+ public function Query__construct(&$result)
+ {
+ $result['query'] = new \QueryLang\v3\Node\Query();
+ var_dump(__METHOD__); var_dump(func_get_args());
+ }
- return $this->_query;
+ public function Query_OrQuery(&$result, $sub)
+ {
+ var_dump(__METHOD__); var_dump(func_get_args());
+ $result['query']->addSubQuery($sub['query']);
+ }
+
+ public function OrQuery__construct(&$result)
+ {
+ $result['query'] = new \QueryLang\v3\Node\Query();
+ var_dump(__METHOD__); var_dump(func_get_args());
}
- public function Query_Term(&$result, $sub)
+ public function OrQuery_AndQuery(&$result, $sub)
{
- $term = new \QueryLang\v3\Node\Term($sub['value']);
- if (isset($sub['modifier'])) {
- $term->setModifier($sub['modifier']);
+ if (isset($sub['query'])) {
+ $result['query']->addSubQuery($sub['query']);
}
- $this->_query->addTerm($term);
+ else if (isset($sub['firstTerm'])) {
+ $result['query']->addTerm($sub['firstTerm']);
+ unset($sub['firstTerm']);
+ }
+ var_dump(__METHOD__); var_dump(func_get_args());
}
- public function Term_TermValue(&$result, $sub)
+ public function AndQuery_Term(&$result, $sub)
{
- $result['value'] = $sub['text'];
+ $term = new \QueryLang\v3\Node\Term($sub['text']);
+ if (isset($result['query'])) {
+ $result['query']->addTerm($term);
+ }
+ // Second term, we can be sure this is a subquery now, so create it...
+ else if (isset($result['firstTerm'])) {
+ $query = new \QueryLang\v3\Node\Query('AND');
+ $query->addTerm($result['firstTerm']);
+ $query->addTerm($term);
+ $result['query'] = $query;
+ }
+ // May contain a subquery
+ else if (isset($sub['query'])) {
+ $query = new \QueryLang\v3\Node\Query('AND');
+ $query->addSubQuery($sub['query']);
+ $result['query'];
+ }
+ // May just be a single term...
+ else {
+ $result['firstTerm'] = $term;
+ }
+
+ var_dump(__METHOD__); var_dump(func_get_args());
}
- public function Term_Modifier(&$result, $sub)
+ public function Term_Query(&$result, $sub)
{
- $result['modifier'] = $sub['text'];
+ $result['query'] = $sub['query'];
+ var_dump(__METHOD__); var_dump(func_get_args());
}
}
View
7 src/QueryLang/v3/SyntaxException.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace QueryLang\v3;
+
+class SyntaxException extends \RuntimeException
+{
+}
View
32 src/QueryLang/v3/Token.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace QueryLang\v3;
+
+class Token
+{
+ private $_type;
+ private $_value;
+ private $_pos;
+
+ public function __construct($type, $value, $pos)
+ {
+ $this->_type = $type;
+ $this->_value = $value;
+ $this->_pos = $pos;
+ }
+
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ public function getValue()
+ {
+ return $this->_value;
+ }
+
+ public function getPos()
+ {
+ return $this->_pos;
+ }
+}
View
8 src/QueryLang/v4/Node/LiteralTerm.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace QueryLang\v4\Node;
+
+class LiteralTerm extends Term
+{
+
+}
View
50 src/QueryLang/v4/Parser.php
@@ -15,6 +15,54 @@ public function __construct($string)
public function parse()
{
+ if ($term = $this->_parseSingleQuotedTerm()) {
+ $this->_query->addTerm($term);
+ }
+ else if ($term = $this->_parseDoubleQuotedTerm()) {
+ $this->_query->addTerm($term);
+ }
+ else if ($term = $this->_parseTerm()) {
+ $this->_query->addTerm($term);
+ }
+ $this->parse();
}
-}
+
+ protected function _parseTerm()
+ {
+ if ($term = $this->_consume('/^([\w\d])/')) {
+
+ }
+ }
+
+ protected function _parseSingleQuotedTerm()
+ {
+ $this->_consume("/^'([^']+)'/");
+ }
+
+ protected function _parseDoubleQuotedTerm()
+ {
+ $this->_consume('/^"([^"]+)"/');
+ }
+
+ protected function _parseTermValue()
+ {
+ $this->_consume('/^([\w\d]+)/');
+ }
+
+ protected function _consume($regex)
+ {
+ $matches = array();
+ if (preg_match($regex, $this->_string, $matches) === 0) {
+ return false;
+ }
+ else {
+ $match = $matches[0];
+ $this->_string = substr($this->_string, strlen($match));
+ return $match;
+ }
+ }
+}
+
+$parser = new Parser('a badass -"motherf*cking crazy" +parser');
+var_dump($parser->parse());
View
325 src/QueryLang/v4/Peg/Parser.php
@@ -0,0 +1,325 @@
+<?php
+
+namespace QueryLang\v4\Peg;
+
+require_once __DIR__ . '/../Node/Query.php';
+require_once __DIR__ . '/../Node/Term.php';
+require_once __DIR__ . '/../Node/LiteralTerm.php';
+require_once __DIR__ . '/../../../../vendor/hafriedlander/php-peg/Parser.php';
+
+class QueryLangv4 extends \Parser {
+ /* Query: ( SingleQuotedTerm | DoubleQuotedTerm | Term ) > Query* */
+ protected $match_Query_typestack = array('Query');
+ function match_Query ($stack = array()) {
+ $matchrule = "Query"; $result = $this->construct($matchrule, $matchrule, null);
+ $_13 = NULL;
+ do {
+ $_9 = NULL;
+ do {
+ $_7 = NULL;
+ do {
+ $res_0 = $result;
+ $pos_0 = $this->pos;
+ $matcher = 'match_'.'SingleQuotedTerm'; $key = $matcher; $pos = $this->pos;
+ $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
+ if ($subres !== FALSE) {
+ $this->store( $result, $subres );
+ $_7 = TRUE; break;
+ }
+ $result = $res_0;
+ $this->pos = $pos_0;
+ $_5 = NULL;
+ do {
+ $res_2 = $result;
+ $pos_2 = $this->pos;
+ $matcher = 'match_'.'DoubleQuotedTerm'; $key = $matcher; $pos = $this->pos;
+ $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
+ if ($subres !== FALSE) {
+ $this->store( $result, $subres );
+ $_5 = TRUE; break;
+ }
+ $result = $res_2;
+ $this->pos = $pos_2;
+ $matcher = 'match_'.'Term'; $key = $matcher; $pos = $this->pos;
+ $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
+ if ($subres !== FALSE) {
+ $this->store( $result, $subres );
+ $_5 = TRUE; break;
+ }
+ $result = $res_2;
+ $this->pos = $pos_2;
+ $_5 = FALSE; break;
+ }
+ while(0);
+ if( $_5 === TRUE ) { $_7 = TRUE; break; }
+ $result = $res_0;
+ $this->pos = $pos_0;
+ $_7 = FALSE; break;
+ }
+ while(0);
+ if( $_7 === FALSE) { $_9 = FALSE; break; }
+ $_9 = TRUE; break;
+ }
+ while(0);
+ if( $_9 === FALSE) { $_13 = FALSE; break; }
+ if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; }
+ while (true) {
+ $res_12 = $result;
+ $pos_12 = $this->pos;
+ $matcher = 'match_'.'Query'; $key = $matcher; $pos = $this->pos;
+ $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
+ if ($subres !== FALSE) {
+ $this->store( $result, $subres );
+ }
+ else {
+ $result = $res_12;
+ $this->pos = $pos_12;
+ unset( $res_12 );
+ unset( $pos_12 );
+ break;
+ }
+ }
+ $_13 = TRUE; break;
+ }
+ while(0);
+ if( $_13 === TRUE ) { return $this->finalise($result); }
+ if( $_13 === FALSE) { return FALSE; }
+ }
+
+
+ /* SingleQuotedTerm: Modifier* "'" term:/[^']+/ "'" */
+ protected $match_SingleQuotedTerm_typestack = array('SingleQuotedTerm');
+ function match_SingleQuotedTerm ($stack = array()) {
+ $matchrule = "SingleQuotedTerm"; $result = $this->construct($matchrule, $matchrule, null);
+ $_19 = NULL;
+ do {
+ while (true) {
+ $res_15 = $result;
+ $pos_15 = $this->pos;
+ $matcher = 'match_'.'Modifier'; $key = $matcher; $pos = $this->pos;
+ $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
+ if ($subres !== FALSE) {
+ $this->store( $result, $subres );
+ }
+ else {
+ $result = $res_15;
+ $this->pos = $pos_15;
+ unset( $res_15 );
+ unset( $pos_15 );
+ break;
+ }
+ }
+ if (substr($this->string,$this->pos,1) == '\'') {
+ $this->pos += 1;
+ $result["text"] .= '\'';
+ }
+ else { $_19 = FALSE; break; }
+ $stack[] = $result; $result = $this->construct( $matchrule, "term" );
+ if (( $subres = $this->rx( '/[^\']+/' ) ) !== FALSE) {
+ $result["text"] .= $subres;
+ $subres = $result; $result = array_pop($stack);
+ $this->store( $result, $subres, 'term' );
+ }
+ else {
+ $result = array_pop($stack);
+ $_19 = FALSE; break;
+ }
+ if (substr($this->string,$this->pos,1) == '\'') {
+ $this->pos += 1;
+ $result["text"] .= '\'';
+ }
+ else { $_19 = FALSE; break; }
+ $_19 = TRUE; break;
+ }
+ while(0);
+ if( $_19 === TRUE ) { return $this->finalise($result); }
+ if( $_19 === FALSE) { return FALSE; }
+ }
+
+
+ /* DoubleQuotedTerm: Modifier* '"' term:/[^"]+/ '"' */
+ protected $match_DoubleQuotedTerm_typestack = array('DoubleQuotedTerm');
+ function match_DoubleQuotedTerm ($stack = array()) {
+ $matchrule = "DoubleQuotedTerm"; $result = $this->construct($matchrule, $matchrule, null);
+ $_25 = NULL;
+ do {
+ while (true) {
+ $res_21 = $result;
+ $pos_21 = $this->pos;
+ $matcher = 'match_'.'Modifier'; $key = $matcher; $pos = $this->pos;
+ $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
+ if ($subres !== FALSE) {
+ $this->store( $result, $subres );
+ }
+ else {
+ $result = $res_21;
+ $this->pos = $pos_21;
+ unset( $res_21 );
+ unset( $pos_21 );
+ break;
+ }
+ }
+ if (substr($this->string,$this->pos,1) == '"') {
+ $this->pos += 1;
+ $result["text"] .= '"';
+ }
+ else { $_25 = FALSE; break; }
+ $stack[] = $result; $result = $this->construct( $matchrule, "term" );
+ if (( $subres = $this->rx( '/[^"]+/' ) ) !== FALSE) {
+ $result["text"] .= $subres;
+ $subres = $result; $result = array_pop($stack);
+ $this->store( $result, $subres, 'term' );
+ }
+ else {
+ $result = array_pop($stack);
+ $_25 = FALSE; break;
+ }
+ if (substr($this->string,$this->pos,1) == '"') {
+ $this->pos += 1;
+ $result["text"] .= '"';
+ }
+ else { $_25 = FALSE; break; }
+ $_25 = TRUE; break;
+ }
+ while(0);
+ if( $_25 === TRUE ) { return $this->finalise($result); }
+ if( $_25 === FALSE) { return FALSE; }
+ }
+
+
+ /* Term: Modifier* TermValue */
+ protected $match_Term_typestack = array('Term');
+ function match_Term ($stack = array()) {
+ $matchrule = "Term"; $result = $this->construct($matchrule, $matchrule, null);
+ $_29 = NULL;
+ do {
+ while (true) {
+ $res_27 = $result;
+ $pos_27 = $this->pos;
+ $matcher = 'match_'.'Modifier'; $key = $matcher; $pos = $this->pos;
+ $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
+ if ($subres !== FALSE) {
+ $this->store( $result, $subres );
+ }
+ else {
+ $result = $res_27;
+ $this->pos = $pos_27;
+ unset( $res_27 );
+ unset( $pos_27 );
+ break;
+ }
+ }
+ $matcher = 'match_'.'TermValue'; $key = $matcher; $pos = $this->pos;
+ $subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
+ if ($subres !== FALSE) {
+ $this->store( $result, $subres );
+ }
+ else { $_29 = FALSE; break; }
+ $_29 = TRUE; break;
+ }
+ while(0);
+ if( $_29 === TRUE ) { return $this->finalise($result); }
+ if( $_29 === FALSE) { return FALSE; }
+ }
+
+
+ /* Modifier: /[+-]/ */
+ protected $match_Modifier_typestack = array('Modifier');
+ function match_Modifier ($stack = array()) {
+ $matchrule = "Modifier"; $result = $this->construct($matchrule, $matchrule, null);
+ if (( $subres = $this->rx( '/[+-]/' ) ) !== FALSE) {
+ $result["text"] .= $subres;
+ return $this->finalise($result);
+ }
+ else { return FALSE; }
+ }
+
+
+ /* TermValue: /[\w\d]+/ */
+ protected $match_TermValue_typestack = array('TermValue');
+ function match_TermValue ($stack = array()) {
+ $matchrule = "TermValue"; $result = $this->construct($matchrule, $matchrule, null);
+ if (( $subres = $this->rx( '/[\w\d]+/' ) ) !== FALSE) {
+ $result["text"] .= $subres;
+ return $this->finalise($result);
+ }
+ else { return FALSE; }
+ }
+
+
+
+
+ /**
+ * @var \QueryLang\v4\Node\Query
+ */
+ private $_query;
+
+ public function parse()
+ {
+ $this->_query = new \QueryLang\v4\Node\Query();
+
+ $this->match_Query();
+
+ return $this->_query;
+ }
+
+ public function Query_Term(&$result, $sub)
+ {
+ $term = new \QueryLang\v4\Node\Term($sub['value']);
+ if (isset($sub['modifier'])) {
+ $term->setModifier($sub['modifier']);
+ }
+ $this->_query->addTerm($term);
+ }
+
+ public function Query_SingleQuotedTerm(&$result, $sub)
+ {
+ $term = new \QueryLang\v4\Node\LiteralTerm($sub['value']);
+ if (isset($sub['modifier'])) {
+ $term->setModifier($sub['modifier']);
+ }
+ $this->_query->addTerm($term);
+ }
+
+ public function Query_DoubleQuotedTerm(&$result, $sub)
+ {
+ $term = new \QueryLang\v4\Node\LiteralTerm($sub['value']);
+ if (isset($sub['modifier'])) {
+ $term->setModifier($sub['modifier']);
+ }
+ $this->_query->addTerm($term);
+ }
+
+ public function Term_TermValue(&$result, $sub)
+ {
+ $result['value'] = $sub['text'];
+ }
+
+ public function Term_Modifier(&$result, $sub)
+ {
+ $result['modifier'] = $sub['text'];
+ }
+
+ public function SingleQuotedTerm_Modifier(&$result, $sub)
+ {
+ $result['modifier'] = $sub['text'];
+ }
+
+ public function SingleQuotedTerm_term(&$result, $sub)
+ {
+ $result['value'] = $sub['text'];
+ }
+
+ public function DoubleQuotedTerm_Modifier(&$result, $sub)
+ {
+ $result['modifier'] = $sub['text'];
+ }
+
+ public function DoubleQuotedTerm_term(&$result, $sub)
+ {
+ $result['value'] = $sub['text'];
+ }
+}
+
+$parser = new QueryLangv4('a +bloody -"motherf*cking badass" query');
+var_dump($parser->parse());
View
102 src/QueryLang/v4/Peg/grammar.peg.inc
@@ -1,5 +1,97 @@
-Query: (Term | QuotedTerm) > Query*
-QuotedTerm: Modifier* " TermValue+ "
-Term: Modifier* TermValue
-Modifier: /[+-]/
-TermValue: /[\w\d]+/
+<?php
+
+namespace QueryLang\v4\Peg;
+
+require_once __DIR__ . '/../Node/Query.php';
+require_once __DIR__ . '/../Node/Term.php';
+require_once __DIR__ . '/../../../../vendor/hafriedlander/php-peg/Parser.php';
+
+class QueryLangv4 extends \Parser {
+ /*!* QueryLangv4
+
+ Query : ( SingleQuotedTerm | DoubleQuotedTerm | Term ) > Query*
+ SingleQuotedTerm: Modifier* "'" term:/[^']+/ "'"
+ DoubleQuotedTerm: Modifier* '"' term:/[^"]+/ '"'
+ Term : Modifier* TermValue
+ Modifier : /[+-]/
+ TermValue : /[\w\d]+/
+
+ */
+
+ /**
+ * @var \QueryLang\v4\Node\Query
+ */
+ private $_query;
+
+ public function parse()
+ {
+ $this->_query = new \QueryLang\v4\Node\Query();
+
+ $this->match_Query();
+
+ return $this->_query;
+ }
+
+ public function Query_Term(&$result, $sub)
+ {
+ $term = new \QueryLang\v4\Node\Term($sub['value']);
+ if (isset($sub['modifier'])) {
+ $term->setModifier($sub['modifier']);
+ }
+ $this->_query->addTerm($term);
+ }
+
+ public function Query_SingleQuotedTerm(&$result, $sub)
+ {
+ $term = new \QueryLang\v4\Node\LiteralTerm($sub['value']);
+ if (isset($sub['modifier'])) {
+ $term->setModifier($sub['modifier']);
+ }
+ $this->_query->addTerm($term);
+ }
+
+ public function Query_DoubleQuotedTerm(&$result, $sub)
+ {
+ $term = new \QueryLang\v4\Node\LiteralTerm($sub['value']);
+ if (isset($sub['modifier'])) {
+ $term->setModifier($sub['modifier']);
+ }
+ $this->_query->addTerm($term);
+ }
+
+ public function Term_TermValue(&$result, $sub)
+ {
+ $result['value'] = $sub['text'];
+ }
+
+ public function Term_Modifier(&$result, $sub)
+ {
+ $result['modifier'] = $sub['text'];
+ }
+
+ public function SingleQuotedTerm_Modifier(&$result, $sub)
+ {
+ $result['modifier'] = $sub['text'];
+ }
+
+ public function SingleQuotedTerm_term(&$result, $sub)
+ {
+ $result['value'] = $sub['text'];
+ }
+
+ public function DoubleQuotedTerm_Modifier(&$result, $sub)
+ {
+ $result['modifier'] = $sub['text'];
+ }
+
+ public function DoubleQuotedTerm_term(&$result, $sub)
+ {
+ $result['value'] = $sub['text'];
+ }
+}
+
+$parser = new QueryLangv4('a +bloody -"motherf*cking badass" query');
+var_dump($parser->parse());
+
+"a OR b AND c";
+"";
View
23 tests/QueryLang/v1/ParserTest.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Tests\QueryLang\v1;
+
+class ParserTest extends \PHPUnit_Framework_TestCase
+{
+ const PARSER_CLASS = '\QueryLang\v1\Parser';
+
+ public function testNoQuery()
+ {
+ $parserClass = static::PARSER_CLASS;
+ $parser = new $parserClass('');
+ $this->assertEmpty($parser->parse());
+ }
+
+ public function testParseSingleWord()
+ {
+ $parserClass = static::PARSER_CLASS;
+ $parser = new $parserClass('parser');
+ $query = $parser->parse();
+ $this->assertEquals('parser', $query);
+ }
+}
View
19 tests/QueryLang/v1/ParserTests.php
@@ -1,19 +0,0 @@
-<?php
-
-namespace Tests\QueryLang\v1;
-
-use QueryLang\v1;
-
-class ParserTest extends \PHPUnit_Framework_TestCase
-{
- public function testTerm()
- {
- $parser = new \QueryLang\v1\Parser('parser');
- $query = $parser->parse();
- $this->assertEquals(array('parser'), $query);
- }
-
- public function testEmpty()
- {
- }
-}
View
8 tests/QueryLang/v1/Peg/ParserTest.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace Tests\QueryLang\v1\Peg;
+
+class ParserTest extends \Tests\QueryLang\v1\ParserTest
+{
+ const PARSER_CLASS = '\QueryLang\v1\Peg\Parser';
+}
View
31 tests/QueryLang/v2/ParserTest.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Tests\QueryLang\v2;
+
+class ParserTest extends \PHPUnit_Framework_TestCase
+{
+ const PARSER_CLASS = '\QueryLang\v2\Parser';
+
+ public function testNoQuery()
+ {
+ $parserClass = static::PARSER_CLASS;
+ $parser = new $parserClass('');
+ $this->assertEmpty($parser->parse());
+ }
+
+ public function testParseSingleWord()
+ {
+ $parserClass = static::PARSER_CLASS;
+ $parser = new $parserClass('parser');
+ $query = $parser->parse();
+ $this->assertEquals(array('parser'), $query);
+ }
+
+ public function testMultiTerm()
+ {
+ $parserClass = static::PARSER_CLASS;
+ $parser = new $parserClass('parser mult1 word');
+ $query = $parser->parse();
+ $this->assertEquals(array('parser', 'mult1', 'word'), $query);
+ }
+}
View
17 tests/QueryLang/v2/ParserTests.php
@@ -1,17 +0,0 @@
-<?php
-
-namespace Tests\QueryLang\v2;
-
-class ParserTest extends \PHPUnit_Framework_TestCase
-{
- public function testMultiTerm()
- {
- $parser = new \QueryLang\v2\Parser('parser mult1 word');
- $query = $parser->parse();
- $this->assertEquals(array('parser', 'mult1', 'word'), $query);
- }
-
- public function testEmpty()
- {
- }
-}
View
8 tests/QueryLang/v2/Peg/ParserTest.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace Tests\QueryLang\v2\Peg;
+
+class ParserTest extends \Tests\QueryLang\v2\ParserTest
+{
+ const PARSER_CLASS = '\QueryLang\v2\Peg\Parser';
+}
View
81 tests/QueryLang/v3/ParserTest.php
@@ -6,21 +6,86 @@
class ParserTest extends \PHPUnit_Framework_TestCase
{
- public function testModifiers()
+ const PARSER_CLASS = '\QueryLang\v3\Parser';
+
+ public function testNoQuery()
+ {
+ $parserClass = static::PARSER_CLASS;
+ $parser = new $parserClass('');
+ $query = $parser->parse();
+ $this->assertEquals(new \QueryLang\v3\Node\Query(), $query);
+ }
+
+ public function testParseSingleWord()
{
- $parser = new \QueryLang\v3\Parser('c +programming');
+ $parserClass = static::PARSER_CLASS;
+ $parser = new $parserClass('parser');
$query = $parser->parse();
$expectedQuery = new \QueryLang\v3\Node\Query();
+ $expectedQuery->addTerm(new \QueryLang\v3\Node\Term('parser'));
+ $this->assertEquals($expectedQuery, $query);
+ }
- $firstTerm = new \QueryLang\v3\Node\Term('c');
- $expectedQuery->addTerm($firstTerm);
+ public function testMultiTerm()
+ {
+ $parserClass = static::PARSER_CLASS;
+ $parser = new $parserClass('parser OR mult1 OR word');
+ $query = $parser->parse();
- $secondTerm = new \QueryLang\v3\Node\Term('programming');
- $secondTerm->setModifier('+');
- $expectedQuery->addTerm($secondTerm);
+ $expectedQuery = new \QueryLang\v3\Node\Query();
+ $expectedQuery->addTerm(new \QueryLang\v3\Node\Term('parser'));
+ $expectedQuery->addTerm(new \QueryLang\v3\Node\Term('mult1'));
+ $expectedQuery->addTerm(new \QueryLang\v3\Node\Term('word'));
+ $this->assertEquals($expectedQuery, $query, 'Parser knows to parse multiple terms');
+ }
- $this->assertEquals($expectedQuery, $query);
+ public function testPrecedence()
+ {
+ $parserClass = static::PARSER_CLASS;
+
+ $implicitPrecedenceQuery = 'c OR a AND b';
+ $explicitPrecedenceQuery = 'c OR (a AND b)';
+
+ $parser = new $parserClass($implicitPrecedenceQuery);
+ $query = $parser->parse();
+
+ $parser = new $parserClass($explicitPrecedenceQuery);
+ $expectedQuery = $parser->parse();
+
+ echo 'Query: ' . $implicitPrecedenceQuery . PHP_EOL;
+ echo "Expected:" . PHP_EOL;
+ var_dump($expectedQuery);
+ echo "Actual:" . PHP_EOL;
+ var_dump($query);
+ $this->assertEquals($expectedQuery, $query, $implicitPrecedenceQuery . '===' . $explicitPrecedenceQuery);
+
+ $implicitPrecedenceQuery = 'a AND b OR c';
+ $explicitPrecedenceQuery = '(a AND b) OR c';
+
+ $parser = new $parserClass($implicitPrecedenceQuery);
+ $query = $parser->parse();
+
+ echo "=================================" . PHP_EOL;
+ echo "=============EXPLICIT============" . PHP_EOL;
+ echo "=================================" . PHP_EOL;
+ $parser = new $parserClass($explicitPrecedenceQuery);
+ $expectedQuery = $parser->parse();
+
+ $this->assertEquals($expectedQuery, $query, $implicitPrecedenceQuery . '===' . $explicitPrecedenceQuery);
+ }
+
+ public function testSubQueries()
+ {
+ $query = 'a OR (b AND c OR (e AND (f)))';
+
+ $parserClass = static::PARSER_CLASS;
+ $parser = new $parserClass($query);
+ $query = $parser->parse();
+
+ $expectedQuery = new \QueryLang\v3\Node\Query();
+ $expectedQuery->addTerm(new \QueryLang\v3\Node\Term('a'));
+// $expectedQuery->addSubQuery()
}
public function testEmpty()
View
8 tests/QueryLang/v3/Peg/ParserTest.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace Tests\QueryLang\v3\Peg;
+
+class ParserTest extends \Tests\QueryLang\v3\ParserTest
+{
+ const PARSER_CLASS = '\QueryLang\v3\Peg\Parser';
+}
View
28 tests/QueryLang/v4/ParserTest.php
@@ -2,25 +2,25 @@
namespace Tests\QueryLang\v4;
-use QueryLang\v3;
+use QueryLang\v4;
class ParserTest extends \PHPUnit_Framework_TestCase
{
public function testModifiers()
{
- $parser = new \QueryLang\v3\Parser('c +programming');
- $query = $parser->parse();
-
- $expectedQuery = new \QueryLang\v3\Node\Query();
-
- $firstTerm = new \QueryLang\v3\Node\Term('c');
- $expectedQuery->addTerm($firstTerm);
-
- $secondTerm = new \QueryLang\v3\Node\Term('programming');
- $secondTerm->setModifier('+');
- $expectedQuery->addTerm($secondTerm);
-
- $this->assertEquals($expectedQuery, $query);
+// $parser = new \QueryLang\v4\Parser('c +programming');
+// $query = $parser->parse();
+//
+// $expectedQuery = new \QueryLang\v4\Node\Query();
+//
+// $firstTerm = new \QueryLang\v4\Node\Term('c');
+// $expectedQuery->addTerm($firstTerm);
+//
+// $secondTerm = new \QueryLang\v4\Node\Term('programming');
+// $secondTerm->setModifier('+');
+// $expectedQuery->addTerm($secondTerm);
+//
+// $this->assertEquals($expectedQuery, $query);
}
public function testEmpty()
View
8 tests/QueryLang/v4/Peg/ParserTest.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace Tests\QueryLang\v4\Peg;
+
+class ParserTest extends \Tests\QueryLang\v4\ParserTest
+{
+ const PARSER_CLASS = '\QueryLang\v4\Peg\Parser';
+}
View
4 tests/bootstrap.php
@@ -0,0 +1,4 @@
+<?php
+
+// Use Composer autoloading
+require __DIR__ . '/../vendor/autoload.php';
Please sign in to comment.
Something went wrong with that request. Please try again.