def self.filter(nodes, expr, truth = true)
until expr.empty?
_, *m = *expr.match(/^(?:#{ATTR_RE}|#{BRACK_RE}|#{FUNC_RE}|#{CATCH_RE})/)
break unless _
expr = $'
m.compact!
if m[0] == '@'
m[0] = "@#{m.slice!(2,1)}"
end
if m[0] == '[' && m[1] =~ /^\d+$/
m = [":", "nth", m[1]]
end
if m[0] == ":" && m[1] == "not"
nodes, = Elements.filter(nodes, m[2], false)
else
meth = "filter[#{m[0]}]"
if Traverse.method_defined? meth
args = m[1..-1]
else
meth = "filter[#{m[0]}#{m[1]}]"
if Traverse.method_defined? meth
args = m[2..-1]
end
end
i = -1
nodes = Elements[*nodes.find_all do |x|
i += 1
x.send(meth, *([*args] + [i])) ? truth : !truth
end]
end
end
[nodes, expr]
end