Skip to content

Commit 3589ae5

Browse files
committed
Parser improvement to parse the content of :not() :has() :where() :is() itself as subselector - supporting all the selector syntax
At the moment the subselector is re-flatten after the parsing because the compiler not know how to deal with nested selector structure leafo#368
1 parent 67d535d commit 3589ae5

File tree

1 file changed

+51
-21
lines changed

1 file changed

+51
-21
lines changed

src/Parser.php

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2142,19 +2142,19 @@ protected function propertyName(&$out)
21422142
*
21432143
* @return boolean
21442144
*/
2145-
protected function selectors(&$out)
2145+
protected function selectors(&$out, $subSelector = false)
21462146
{
21472147
$s = $this->count;
21482148
$selectors = [];
21492149

2150-
while ($this->selector($sel)) {
2150+
while ($this->selector($sel, $subSelector)) {
21512151
$selectors[] = $sel;
21522152

2153-
if (! $this->matchChar(',')) {
2153+
if (! $this->matchChar(',', true)) {
21542154
break;
21552155
}
21562156

2157-
while ($this->matchChar(',')) {
2157+
while ($this->matchChar(',', true)) {
21582158
; // ignore extra
21592159
}
21602160
}
@@ -2177,23 +2177,23 @@ protected function selectors(&$out)
21772177
*
21782178
* @return boolean
21792179
*/
2180-
protected function selector(&$out)
2180+
protected function selector(&$out, $subSelector = false)
21812181
{
21822182
$selector = [];
21832183

21842184
for (;;) {
2185-
if ($this->match('[>+~]+', $m)) {
2185+
if ($this->match('[>+~]+', $m, true)) {
21862186
$selector[] = [$m[0]];
21872187
continue;
21882188
}
21892189

2190-
if ($this->selectorSingle($part)) {
2190+
if ($this->selectorSingle($part, $subSelector)) {
21912191
$selector[] = $part;
21922192
$this->match('\s+', $m);
21932193
continue;
21942194
}
21952195

2196-
if ($this->match('\/[^\/]+\/', $m)) {
2196+
if ($this->match('\/[^\/]+\/', $m, true)) {
21972197
$selector[] = [$m[0]];
21982198
continue;
21992199
}
@@ -2220,7 +2220,7 @@ protected function selector(&$out)
22202220
*
22212221
* @return boolean
22222222
*/
2223-
protected function selectorSingle(&$out)
2223+
protected function selectorSingle(&$out, $subSelector = false)
22242224
{
22252225
$oldWhite = $this->eatWhiteDefault;
22262226
$this->eatWhiteDefault = false;
@@ -2244,6 +2244,11 @@ protected function selectorSingle(&$out)
22442244
break;
22452245
}
22462246

2247+
// parsing a sub selector in () stop with the closing )
2248+
if ($subSelector && $char === ')') {
2249+
break;
2250+
}
2251+
22472252
//self
22482253
switch ($char) {
22492254
case '&':
@@ -2307,21 +2312,46 @@ protected function selectorSingle(&$out)
23072312

23082313
$ss = $this->count;
23092314

2310-
if ($this->matchChar('(') &&
2311-
($this->openString(')', $str, '(') || true) &&
2312-
$this->matchChar(')')
2313-
) {
2314-
$parts[] = '(';
2315-
2316-
if (! empty($str)) {
2317-
$parts[] = $str;
2315+
if ($nameParts === ['not'] || $nameParts === ['is'] || $nameParts === ['has'] || $nameParts === ['where']) {
2316+
if ($this->matchChar('(') &&
2317+
($this->selectors($subs, true) || true) &&
2318+
$this->matchChar(')')
2319+
) {
2320+
$parts[] = '(';
2321+
2322+
while ($sub = array_shift($subs)) {
2323+
while ($ps = array_shift($sub)) {
2324+
foreach ($ps as &$p) {
2325+
$parts[] = $p;
2326+
}
2327+
if (count($sub) && reset($sub)) {
2328+
$parts[] = ' ';
2329+
}
2330+
}
2331+
if (count($subs) && reset($subs)) {
2332+
$parts[] = ', ';
2333+
}
2334+
}
2335+
$parts[] = ')';
2336+
} else {
2337+
$this->seek($ss);
23182338
}
2319-
2320-
$parts[] = ')';
23212339
} else {
2322-
$this->seek($ss);
2340+
if ($this->matchChar('(') &&
2341+
($this->openString(')', $str, '(') || true) &&
2342+
$this->matchChar(')')
2343+
) {
2344+
$parts[] = '(';
2345+
2346+
if (! empty($str)) {
2347+
$parts[] = $str;
2348+
}
2349+
2350+
$parts[] = ')';
2351+
} else {
2352+
$this->seek($ss);
2353+
}
23232354
}
2324-
23252355
continue;
23262356
}
23272357
}

0 commit comments

Comments
 (0)