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
|
selectors
|
||||||
= selector selectors_follow*
|
= selector selectors_follow*
|
||||||
{
|
{
|
||||||
node = val[0]
|
query = val[0]
|
||||||
|
|
||||||
val[1].each do |chunk|
|
val[1].each do |chunk|
|
||||||
node = s(:pipe, node, chunk)
|
query = s(:pipe, query, chunk)
|
||||||
end
|
end
|
||||||
|
|
||||||
node
|
query
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -43,88 +43,95 @@ selectors_follow
|
||||||
;
|
;
|
||||||
|
|
||||||
selector
|
selector
|
||||||
= axis_or_descendant_or_self predicates? selector_follow?
|
# foo, foo.bar, foo[bar], etc
|
||||||
|
= node_test predicates? selector_follow?
|
||||||
{
|
{
|
||||||
node = val[0]
|
node = s(:axis, 'descendant', val[0])
|
||||||
pred = val[1]
|
preds = val[1]
|
||||||
more = val[2]
|
more = val[2]
|
||||||
|
|
||||||
if pred
|
if preds
|
||||||
node = s(:predicate, node, pred)
|
node = s(:predicate, node, preds)
|
||||||
end
|
end
|
||||||
|
|
||||||
if more
|
node = add_child(node, more) if more
|
||||||
node = node.updated(nil, node.children + [more])
|
|
||||||
end
|
|
||||||
|
|
||||||
node
|
node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# > foo, + foo, etc
|
||||||
|
| axis
|
||||||
|
|
||||||
|
# .foo, :nth-child(2n), etc
|
||||||
| predicates selector_follow?
|
| predicates selector_follow?
|
||||||
{
|
{
|
||||||
node = s(:axis, 'descendant', on_test(nil, '*'))
|
node = s(:axis, 'descendant', on_test(nil, '*'))
|
||||||
preds = val[0]
|
preds = val[0]
|
||||||
more = val[1]
|
more = val[1]
|
||||||
|
|
||||||
if more
|
if preds
|
||||||
s(:predicate, node, preds, more)
|
node = s(:predicate, node, preds)
|
||||||
else
|
else
|
||||||
s(:predicate, node, preds)
|
node = s(:predicate, node)
|
||||||
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)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
s(
|
node = add_child(node, more) if more
|
||||||
:predicate,
|
|
||||||
s(:axis, 'following-sibling', on_test(nil, '*')),
|
node
|
||||||
s(:int, 1),
|
|
||||||
child
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
selector_follow
|
selector_follow
|
||||||
= T_SPACE selector { val[1] }
|
= T_SPACE selector { val[1] }
|
||||||
;
|
| axis
|
||||||
|
|
||||||
descendant_or_self
|
|
||||||
= node_test { s(:axis, 'descendant', val[0]) }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
axis
|
axis
|
||||||
# > foo
|
# > 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
|
# ~ 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
|
axis_selector
|
||||||
= descendant_or_self
|
# foo.bar
|
||||||
| axis
|
= node_test predicates?
|
||||||
|
|
||||||
|
# .foo
|
||||||
|
| predicates { [nil, val[0]] }
|
||||||
;
|
;
|
||||||
|
|
||||||
axis_selector
|
id_class_pseudo_class
|
||||||
= node_test
|
= id
|
||||||
| axis
|
| class
|
||||||
|
| pseudo_class
|
||||||
;
|
;
|
||||||
|
|
||||||
node_test
|
node_test
|
||||||
|
@ -153,9 +160,7 @@ predicates
|
||||||
;
|
;
|
||||||
|
|
||||||
predicate
|
predicate
|
||||||
= class
|
= id_class_pseudo_class
|
||||||
| id
|
|
||||||
| pseudo_class
|
|
||||||
| attribute_predicate
|
| attribute_predicate
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -678,4 +683,32 @@ even
|
||||||
|
|
||||||
mod_val
|
mod_val
|
||||||
end
|
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