Revamp CSS parser for better axis support
This makes it possible to parse expressions such as "foo>bar", "> .bar", "> foo.bar", and similar expressions. This fixes #126 and fixes #131.
This commit is contained in:
parent
c713f6250f
commit
f753f08f18
|
@ -28,13 +28,13 @@ css
|
|||
selectors
|
||||
= selector selectors_follow*
|
||||
{
|
||||
node = val[0]
|
||||
query = val[0]
|
||||
|
||||
val[1].each do |chunk|
|
||||
node = s(:pipe, node, chunk)
|
||||
query = s(:pipe, query, chunk)
|
||||
end
|
||||
|
||||
node
|
||||
query
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -43,88 +43,95 @@ selectors_follow
|
|||
;
|
||||
|
||||
selector
|
||||
= axis_or_descendant_or_self predicates? selector_follow?
|
||||
# foo, foo.bar, foo[bar], etc
|
||||
= node_test predicates? selector_follow?
|
||||
{
|
||||
node = val[0]
|
||||
pred = val[1]
|
||||
more = val[2]
|
||||
node = s(:axis, 'descendant', val[0])
|
||||
preds = val[1]
|
||||
more = val[2]
|
||||
|
||||
if pred
|
||||
node = s(:predicate, node, pred)
|
||||
if preds
|
||||
node = s(:predicate, node, preds)
|
||||
end
|
||||
|
||||
if more
|
||||
node = node.updated(nil, node.children + [more])
|
||||
end
|
||||
node = add_child(node, more) if more
|
||||
|
||||
node
|
||||
}
|
||||
|
||||
# > foo, + foo, etc
|
||||
| axis
|
||||
|
||||
# .foo, :nth-child(2n), etc
|
||||
| predicates selector_follow?
|
||||
{
|
||||
node = s(:axis, 'descendant', on_test(nil, '*'))
|
||||
preds = val[0]
|
||||
more = val[1]
|
||||
|
||||
if more
|
||||
s(:predicate, node, preds, more)
|
||||
if preds
|
||||
node = s(:predicate, node, preds)
|
||||
else
|
||||
s(:predicate, node, preds)
|
||||
end
|
||||
}
|
||||
# + foo
|
||||
#
|
||||
# This branch is not part of the "axis" rule because we need more fine grained
|
||||
# control over what to do with any selec
|
||||
| T_PLUS axis_selector selector_follow?
|
||||
{
|
||||
selector = val[1]
|
||||
more = val[2]
|
||||
|
||||
if more
|
||||
child = s(:axis, 'self', selector, more)
|
||||
else
|
||||
child = s(:axis, 'self', selector)
|
||||
node = s(:predicate, node)
|
||||
end
|
||||
|
||||
s(
|
||||
:predicate,
|
||||
s(:axis, 'following-sibling', on_test(nil, '*')),
|
||||
s(:int, 1),
|
||||
child
|
||||
)
|
||||
node = add_child(node, more) if more
|
||||
|
||||
node
|
||||
}
|
||||
;
|
||||
|
||||
selector_follow
|
||||
= T_SPACE selector { val[1] }
|
||||
;
|
||||
|
||||
descendant_or_self
|
||||
= node_test { s(:axis, 'descendant', val[0]) }
|
||||
| axis
|
||||
;
|
||||
|
||||
axis
|
||||
# > foo
|
||||
= T_GREATER axis_selector
|
||||
= T_GREATER axis_selector selector_follow?
|
||||
{
|
||||
s(:axis, 'child', val[1])
|
||||
test, preds = val[1]
|
||||
more = val[2]
|
||||
|
||||
generate_axis('child', test, preds, more)
|
||||
}
|
||||
|
||||
# + foo
|
||||
| T_PLUS axis_selector selector_follow?
|
||||
{
|
||||
test, preds = val[1]
|
||||
more = val[2]
|
||||
|
||||
s(
|
||||
:predicate,
|
||||
s(:axis, 'following-sibling', on_test(nil, '*')),
|
||||
s(:int, 1),
|
||||
generate_axis('self', test, preds, more)
|
||||
)
|
||||
}
|
||||
|
||||
# ~ foo
|
||||
| T_TILDE axis_selector
|
||||
| T_TILDE axis_selector selector_follow?
|
||||
{
|
||||
s(:axis, 'following-sibling', val[1])
|
||||
test, preds = val[1]
|
||||
more = val[2]
|
||||
|
||||
generate_axis('following-sibling', test, preds, more)
|
||||
}
|
||||
;
|
||||
|
||||
axis_or_descendant_or_self
|
||||
= descendant_or_self
|
||||
| axis
|
||||
axis_selector
|
||||
# foo.bar
|
||||
= node_test predicates?
|
||||
|
||||
# .foo
|
||||
| predicates { [nil, val[0]] }
|
||||
;
|
||||
|
||||
axis_selector
|
||||
= node_test
|
||||
| axis
|
||||
id_class_pseudo_class
|
||||
= id
|
||||
| class
|
||||
| pseudo_class
|
||||
;
|
||||
|
||||
node_test
|
||||
|
@ -153,9 +160,7 @@ predicates
|
|||
;
|
||||
|
||||
predicate
|
||||
= class
|
||||
| id
|
||||
| pseudo_class
|
||||
= id_class_pseudo_class
|
||||
| attribute_predicate
|
||||
;
|
||||
|
||||
|
@ -678,4 +683,32 @@ even
|
|||
|
||||
mod_val
|
||||
end
|
||||
|
||||
# @param [String] name
|
||||
# @param [AST::Node] test
|
||||
# @param [AST::Node] predicates
|
||||
# @param [AST::Node] more
|
||||
# @return [AST::Node]
|
||||
def generate_axis(name, test = nil, predicates = nil, more = nil)
|
||||
if test
|
||||
node = s(:axis, name, test)
|
||||
else
|
||||
node = s(:axis, name, on_test(nil, '*'))
|
||||
end
|
||||
|
||||
if predicates
|
||||
node = s(:predicate, node, predicates)
|
||||
end
|
||||
|
||||
node = add_child(node, more) if more
|
||||
|
||||
node
|
||||
end
|
||||
|
||||
# @param [AST::Node] node
|
||||
# @param [AST::Node] child
|
||||
# @return [AST::Node]
|
||||
def add_child(node, child)
|
||||
node.updated(nil, node.children + [child])
|
||||
end
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue