diff --git a/lib/oga/css/parser.y b/lib/oga/css/parser.y index db901a9..738787e 100644 --- a/lib/oga/css/parser.y +++ b/lib/oga/css/parser.y @@ -401,7 +401,7 @@ end count_call = s(:call, 'count', s(:axis, count_axis, s(:test, nil, '*'))) # literal 2, 4, etc - if arg.type == :int + if int_node?(arg) node = s(:eq, count_call, s(:int, arg.children[0] - 1)) else step, offset = *arg @@ -414,12 +414,22 @@ end end # -n-6, -n-4, etc - if !step and offset.children[0] <= 0 + if !step and non_positive_number?(offset) node = s(:eq, count_call, s(:int, -1)) # 2n+2, 2n-4, etc elsif offset - mod_val = step ? s(:int, 2) : s(:int, 1) + # -2n + if step and non_positive_number?(step) + mod_val = s(:int, -step.children[0]) + + # 2n + elsif step + mod_val = step + + else + mod_val = s(:int, 1) + end node = s( :and, @@ -436,4 +446,22 @@ end return node end + private + + ## + # @param [AST::Node] node + # @return [TrueClass|FalseClass] + # + def int_node?(node) + return node.type == :int + end + + ## + # @param [AST::Node] node + # @return [TrueClass|FalseClass] + # + def non_positive_number?(node) + return node.children[0] <= 0 + end + # vim: set ft=racc: diff --git a/spec/oga/css/parser/pseudo_classes/nth_child_spec.rb b/spec/oga/css/parser/pseudo_classes/nth_child_spec.rb index fdffa1a..e13ce3c 100644 --- a/spec/oga/css/parser/pseudo_classes/nth_child_spec.rb +++ b/spec/oga/css/parser/pseudo_classes/nth_child_spec.rb @@ -69,6 +69,13 @@ describe Oga::CSS::Parser do ) end + example 'parse the x:nth-child(3n+1) pseudo class' do + parse_css('x:nth-child(3n+1)').should == parse_xpath( + 'descendant-or-self::x[(count(preceding-sibling::*) + 1) >= 1 ' \ + 'and (((count(preceding-sibling::*) + 1) - 1) mod 3) = 0]' + ) + end + example 'parse the x:nth-child(2n-6) pseudo class' do parse_css('x:nth-child(2n-6)').should == parse_xpath( 'descendant-or-self::x[(count(preceding-sibling::*) + 1) >= 2 ' \