diff --git a/src/Parser.php b/src/Parser.php index eb264bce..f7e9043d 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -2142,19 +2142,19 @@ protected function propertyName(&$out) * * @return boolean */ - protected function selectors(&$out) + protected function selectors(&$out, $subSelector = false) { $s = $this->count; $selectors = []; - while ($this->selector($sel)) { + while ($this->selector($sel, $subSelector)) { $selectors[] = $sel; - if (! $this->matchChar(',')) { + if (! $this->matchChar(',', true)) { break; } - while ($this->matchChar(',')) { + while ($this->matchChar(',', true)) { ; // ignore extra } } @@ -2177,23 +2177,23 @@ protected function selectors(&$out) * * @return boolean */ - protected function selector(&$out) + protected function selector(&$out, $subSelector = false) { $selector = []; for (;;) { - if ($this->match('[>+~]+', $m)) { + if ($this->match('[>+~]+', $m, true)) { $selector[] = [$m[0]]; continue; } - if ($this->selectorSingle($part)) { + if ($this->selectorSingle($part, $subSelector)) { $selector[] = $part; $this->match('\s+', $m); continue; } - if ($this->match('\/[^\/]+\/', $m)) { + if ($this->match('\/[^\/]+\/', $m, true)) { $selector[] = [$m[0]]; continue; } @@ -2220,7 +2220,7 @@ protected function selector(&$out) * * @return boolean */ - protected function selectorSingle(&$out) + protected function selectorSingle(&$out, $subSelector = false) { $oldWhite = $this->eatWhiteDefault; $this->eatWhiteDefault = false; @@ -2244,6 +2244,11 @@ protected function selectorSingle(&$out) break; } + // parsing a sub selector in () stop with the closing ) + if ($subSelector && $char === ')') { + break; + } + //self switch ($char) { case '&': @@ -2307,21 +2312,46 @@ protected function selectorSingle(&$out) $ss = $this->count; - if ($this->matchChar('(') && - ($this->openString(')', $str, '(') || true) && - $this->matchChar(')') - ) { - $parts[] = '('; - - if (! empty($str)) { - $parts[] = $str; + if ($nameParts === ['not'] || $nameParts === ['is'] || $nameParts === ['has'] || $nameParts === ['where']) { + if ($this->matchChar('(') && + ($this->selectors($subs, true) || true) && + $this->matchChar(')') + ) { + $parts[] = '('; + + while ($sub = array_shift($subs)) { + while ($ps = array_shift($sub)) { + foreach ($ps as &$p) { + $parts[] = $p; + } + if (count($sub) && reset($sub)) { + $parts[] = ' '; + } + } + if (count($subs) && reset($subs)) { + $parts[] = ', '; + } + } + $parts[] = ')'; + } else { + $this->seek($ss); } - - $parts[] = ')'; } else { - $this->seek($ss); + if ($this->matchChar('(') && + ($this->openString(')', $str, '(') || true) && + $this->matchChar(')') + ) { + $parts[] = '('; + + if (! empty($str)) { + $parts[] = $str; + } + + $parts[] = ')'; + } else { + $this->seek($ss); + } } - continue; } }