This updates the CSS parser to make it compatible with the XPath AST
changes introduced in commit 365a9e9fa9.
This also, finally, means I can get rid of some of the hacks that were
used for "+ foo" selectors and building (path) nodes.
This changes the XPath AST so that every segment in a path (e.g.
foo/bar) is parsed as a child node of the node that precedes it. For
example, take the following expression:
foo/bar
This used to be parsed into the following AST:
(path
(axis "child" (test nil "foo"))
(axis "child" (test nil "bar")))
This is now parsed into the following AST:
(axis "child"
(test nil "foo")
(axis "child"
(test nil "bar")))
This new AST is much easier to deal with in the XPath::Compiler class,
especially when trying to ensure that each segment operates on the
correct input.
This commit also fixes parsing of type tests with predicates, such as:
comment()[10]
This used to throw a parser error.
Handling of predicates is delegated to 3 different methods:
* on_predicate_direct: for predicates such as foo[bar] and foo[x < y].
* on_predicate_temporary: for predicates that use the last() function
somewhere.
* on_predicate_index: for predicates that only contain a literal index,
foo[10] being an example.
This enables the compiler to use more optimized code depending on the
type of predicate while still being able to support last() and
position().
The code is currently still quite rough on the edges, this will be taken
care of in following commits.
This was a hack that never should've made it into the code in the first
place. This breaks some of the CSS specs, but this should be taken care
of when I refactor predicate support.
I can't quite recall why this throw was present in the Evaluator in the
first place, but removing it doesn't seem to break anything (in the
Evaluator). In fact, removing it actually fixes some of the CSS specs
that were broken when using the Compiler.
This is a shortcut for "!foo". Using this method one doesn't have to
worry about how the "!" operator binds. For example, this:
!foo.or(bar)
would be parsed/evaluated as this:
!(foo.or(bar))
when instead we want it to be this:
(!foo).or(bar)
Using explicit parenthesis leads to ugly code, so now we can do this
instead:
foo.not.or(bar)
This is a direct port of the same handler used in the Evaluator class.
The code is a bit rough on the edges but this will be cleaned up in
upcoming commits.