Proper parsing support for all CSS operators.

This commit is contained in:
Yorick Peterse 2014-10-26 12:45:43 +01:00
parent 24ae791f00
commit 32764c9a14
2 changed files with 83 additions and 31 deletions

View File

@ -138,8 +138,76 @@ rule
: node_name { s(:axis, 'attribute', s(:test, *val[0])) }
;
# The AST of these operators is mostly based on what
# `Nokogiri::CSS.xpath_for('...')` returns.
operator
: attribute T_EQ string { s(:eq, val[0], val[2]) }
# a="b"
: attribute T_EQ string
{
s(:eq, val[0], val[2])
}
# a~="b"
| attribute T_SPACE_IN string
{
s(
:call,
'contains',
s(:call, 'concat', s(:string, ' '), val[0], s(:string, ' ')),
s(:call, 'concat', s(:string, ' '), val[2], s(:string, ' '))
)
}
# a^="b"
| attribute T_STARTS_WITH string
{
s(:call, 'starts-with', val[0], val[2])
}
# a$="b"
| attribute T_ENDS_WITH string
{
s(
:eq,
s(
:call,
'substring',
val[0],
s(
:add,
s(
:sub,
s(:call, 'string-length', val[0]),
s(:call, 'string-length', val[2])
),
s(:int, 1)
),
s(:call, 'string-length', val[2])
),
val[2]
)
}
# a*="b"
| attribute T_IN string
{
s(:call, 'contains', val[0], val[2])
}
# a|="b"
| attribute T_HYPHEN_IN string
{
s(
:or,
s(:eq, val[0], val[2]),
s(
:call,
'starts-with',
val[0],
s(:call, 'concat', val[2], s(:string, '-'))
)
)
}
;
class

View File

@ -3,56 +3,40 @@ require 'spec_helper'
describe Oga::CSS::Parser do
context 'operators' do
example 'parse the = operator' do
parse_css('x[a="b"]').should == s(
:test,
nil,
'x',
s(:eq, s(:test, nil, 'a'), s(:string, 'b'))
parse_css('x[a="b"]').should == parse_xpath(
'descendant-or-self::x[@a="b"]'
)
end
example 'parse the ~= operator' do
parse_css('x[a~="b"]').should == s(
:test,
nil,
'x',
s(:space_in, s(:test, nil, 'a'), s(:string, 'b'))
parse_css('x[a~="b"]').should == parse_xpath(
'descendant-or-self::x[contains(concat(" ", @a, " "), ' \
'concat(" ", "b", " "))]'
)
end
example 'parse the ^= operator' do
parse_css('x[a^="b"]').should == s(
:test,
nil,
'x',
s(:starts_with, s(:test, nil, 'a'), s(:string, 'b'))
parse_css('x[a^="b"]').should == parse_xpath(
'descendant-or-self::x[starts-with(@a, "b")]'
)
end
example 'parse the $= operator' do
parse_css('x[a$="b"]').should == s(
:test,
nil,
'x',
s(:ends_with, s(:test, nil, 'a'), s(:string, 'b'))
parse_css('x[a$="b"]').should == parse_xpath(
'descendant-or-self::x[substring(@a, string-length(@a) - ' \
'string-length("b") + 1, string-length("b")) = "b"]'
)
end
example 'parse the *= operator' do
parse_css('x[a*="b"]').should == s(
:test,
nil,
'x',
s(:in, s(:test, nil, 'a'), s(:string, 'b'))
parse_css('x[a*="b"]').should == parse_xpath(
'descendant-or-self::x[contains(@a, "b")]'
)
end
example 'parse the |= operator' do
parse_css('x[a|="b"]').should == s(
:test,
nil,
'x',
s(:hyphen_in, s(:test, nil, 'a'), s(:string, 'b'))
parse_css('x[a|="b"]').should == parse_xpath(
'descendant-or-self::x[@a = "b" or starts-with(@a, concat("b", "-"))]'
)
end
end