@@ -93,6 +93,36 @@ def deconstruct_keys(keys)
9393 end
9494 end
9595
96+ # §15.1 https://www.w3.org/TR/selectors-4/#descendant-combinators
97+ class DescendantCombinator < Combinator
98+ TOKEN = WhitespaceToken
99+ PP_NAME = "descendant-combinator"
100+ end
101+
102+ # §15.2 https://www.w3.org/TR/selectors-4/#child-combinators
103+ class ChildCombinator < Combinator
104+ TOKEN = ">"
105+ PP_NAME = "child-combinator"
106+ end
107+
108+ # §15.3 https://www.w3.org/TR/selectors-4/#adjacent-sibling-combinators
109+ class NextSiblingCombinator < Combinator
110+ TOKEN = "+"
111+ PP_NAME = "next-sibling-combinator"
112+ end
113+
114+ # §15.4 https://www.w3.org/TR/selectors-4/#general-sibling-combinators
115+ class SubsequentSiblingCombinator < Combinator
116+ TOKEN = "~"
117+ PP_NAME = "subsequent-sibling-combinator"
118+ end
119+
120+ # §16.1 https://www.w3.org/TR/selectors-4/#the-column-combinator
121+ class ColumnSiblingCombinator < Combinator
122+ TOKEN = [ "|" , "|" ]
123+ PP_NAME = "column-sibling-combinator"
124+ end
125+
96126 class ComplexSelector < Node
97127 attr_reader :child_nodes
98128
@@ -333,12 +363,12 @@ def relative_selector_list
333363 def complex_selector
334364 child_nodes = [ compound_selector ]
335365
366+ combinator_ = nil
367+ compound_selector_ = nil
336368 loop do
337- if ( c = maybe { combinator } )
338- child_nodes << c
339- end
340- if ( s = maybe { compound_selector } )
341- child_nodes << s
369+ if maybe { ( combinator_ = combinator ) && ( compound_selector_ = compound_selector ) }
370+ child_nodes << combinator_
371+ child_nodes << compound_selector_
342372 else
343373 break
344374 end
@@ -363,8 +393,6 @@ def relative_selector
363393 # <compound-selector> = [ <type-selector>? <subclass-selector>*
364394 # [ <pseudo-element-selector> <pseudo-class-selector>* ]* ]!
365395 def compound_selector
366- consume_whitespace
367-
368396 type = maybe { type_selector }
369397 subclasses = [ ]
370398
@@ -401,17 +429,13 @@ def simple_selector
401429
402430 # <combinator> = '>' | '+' | '~' | [ '|' '|' ]
403431 def combinator
404- consume_whitespace
405-
406- value =
407- options do
408- maybe { consume ( ">" ) } ||
409- maybe { consume ( "+" ) } ||
410- maybe { consume ( "~" ) } ||
411- maybe { consume ( "|" , "|" ) }
412- end
413-
414- Combinator . new ( value : value )
432+ options do
433+ maybe { consume_combinator ( ChildCombinator ) } ||
434+ maybe { consume_combinator ( NextSiblingCombinator ) } ||
435+ maybe { consume_combinator ( SubsequentSiblingCombinator ) } ||
436+ maybe { consume_combinator ( ColumnSiblingCombinator ) } ||
437+ maybe { consume_combinator ( DescendantCombinator ) }
438+ end
415439 end
416440
417441 # <type-selector> = <wq-name> | <ns-prefix>? '*'
@@ -554,6 +578,16 @@ def one_or_more
554578 end
555579 end
556580
581+ def consume_combinator ( combinator_class )
582+ eat_whitespace = ( combinator_class ::TOKEN != WhitespaceToken )
583+
584+ consume_whitespace if eat_whitespace
585+ result = consume ( *combinator_class ::TOKEN )
586+ consume_whitespace if eat_whitespace
587+
588+ combinator_class . new ( value : result )
589+ end
590+
557591 def consume ( *values )
558592 result =
559593 values . map do |value |
0 commit comments