summaryrefslogtreecommitdiffstats
path: root/dom/xslt/xpath/txLocationStep.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/xslt/xpath/txLocationStep.cpp')
-rw-r--r--dom/xslt/xpath/txLocationStep.cpp308
1 files changed, 308 insertions, 0 deletions
diff --git a/dom/xslt/xpath/txLocationStep.cpp b/dom/xslt/xpath/txLocationStep.cpp
new file mode 100644
index 0000000000..c10d9e8cb1
--- /dev/null
+++ b/dom/xslt/xpath/txLocationStep.cpp
@@ -0,0 +1,308 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ Implementation of an XPath LocationStep
+*/
+
+#include "txExpr.h"
+#include "txIXPathContext.h"
+#include "txNodeSet.h"
+#include "txXPathTreeWalker.h"
+
+//-----------------------------/
+//- Virtual methods from Expr -/
+//-----------------------------/
+
+/**
+ * Evaluates this Expr based on the given context node and processor state
+ * @param context the context node for evaluation of this Expr
+ * @param ps the ProcessorState containing the stack information needed
+ * for evaluation
+ * @return the result of the evaluation
+ * @see Expr
+ **/
+nsresult LocationStep::evaluate(txIEvalContext* aContext,
+ txAExprResult** aResult) {
+ NS_ASSERTION(aContext, "internal error");
+ *aResult = nullptr;
+
+ RefPtr<txNodeSet> nodes;
+ nsresult rv = aContext->recycler()->getNodeSet(getter_AddRefs(nodes));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ txXPathTreeWalker walker(aContext->getContextNode());
+
+ switch (mAxisIdentifier) {
+ case ANCESTOR_AXIS: {
+ if (!walker.moveToParent()) {
+ break;
+ }
+ [[fallthrough]];
+ }
+ case ANCESTOR_OR_SELF_AXIS: {
+ nodes->setReverse();
+
+ do {
+ rv = appendIfMatching(walker, aContext, nodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } while (walker.moveToParent());
+
+ break;
+ }
+ case ATTRIBUTE_AXIS: {
+ if (!walker.moveToFirstAttribute()) {
+ break;
+ }
+
+ do {
+ rv = appendIfMatching(walker, aContext, nodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } while (walker.moveToNextAttribute());
+ break;
+ }
+ case DESCENDANT_OR_SELF_AXIS: {
+ rv = appendIfMatching(walker, aContext, nodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+ [[fallthrough]];
+ }
+ case DESCENDANT_AXIS: {
+ rv = appendMatchingDescendants(walker, aContext, nodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+ break;
+ }
+ case FOLLOWING_AXIS: {
+ if (txXPathNodeUtils::isAttribute(walker.getCurrentPosition())) {
+ walker.moveToParent();
+ rv = appendMatchingDescendants(walker, aContext, nodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ bool cont = true;
+ while (!walker.moveToNextSibling()) {
+ if (!walker.moveToParent()) {
+ cont = false;
+ break;
+ }
+ }
+ while (cont) {
+ rv = appendIfMatching(walker, aContext, nodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = appendMatchingDescendants(walker, aContext, nodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ while (!walker.moveToNextSibling()) {
+ if (!walker.moveToParent()) {
+ cont = false;
+ break;
+ }
+ }
+ }
+ break;
+ }
+ case FOLLOWING_SIBLING_AXIS: {
+ while (walker.moveToNextSibling()) {
+ rv = appendIfMatching(walker, aContext, nodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ break;
+ }
+ case NAMESPACE_AXIS: //-- not yet implemented
+#if 0
+ // XXX DEBUG OUTPUT
+ cout << "namespace axis not yet implemented"<<endl;
+#endif
+ break;
+ case PARENT_AXIS: {
+ if (walker.moveToParent()) {
+ rv = appendIfMatching(walker, aContext, nodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ break;
+ }
+ case PRECEDING_AXIS: {
+ nodes->setReverse();
+
+ bool cont = true;
+ while (!walker.moveToPreviousSibling()) {
+ if (!walker.moveToParent()) {
+ cont = false;
+ break;
+ }
+ }
+ while (cont) {
+ rv = appendMatchingDescendantsRev(walker, aContext, nodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = appendIfMatching(walker, aContext, nodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ while (!walker.moveToPreviousSibling()) {
+ if (!walker.moveToParent()) {
+ cont = false;
+ break;
+ }
+ }
+ }
+ break;
+ }
+ case PRECEDING_SIBLING_AXIS: {
+ nodes->setReverse();
+
+ while (walker.moveToPreviousSibling()) {
+ rv = appendIfMatching(walker, aContext, nodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ break;
+ }
+ case SELF_AXIS: {
+ rv = appendIfMatching(walker, aContext, nodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+ break;
+ }
+ default: // Children Axis
+ {
+ if (!walker.moveToFirstChild()) {
+ break;
+ }
+
+ do {
+ rv = appendIfMatching(walker, aContext, nodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } while (walker.moveToNextSibling());
+ break;
+ }
+ }
+
+ // Apply predicates
+ if (!isEmpty()) {
+ rv = evaluatePredicates(nodes, aContext);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ nodes->unsetReverse();
+
+ NS_ADDREF(*aResult = nodes);
+
+ return NS_OK;
+}
+
+nsresult LocationStep::appendIfMatching(const txXPathTreeWalker& aWalker,
+ txIMatchContext* aContext,
+ txNodeSet* aNodes) {
+ bool matched;
+ const txXPathNode& child = aWalker.getCurrentPosition();
+ nsresult rv = mNodeTest->matches(child, aContext, matched);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (matched) {
+ aNodes->append(child);
+ }
+ return NS_OK;
+}
+
+nsresult LocationStep::appendMatchingDescendants(
+ const txXPathTreeWalker& aWalker, txIMatchContext* aContext,
+ txNodeSet* aNodes) {
+ txXPathTreeWalker walker(aWalker);
+ if (!walker.moveToFirstChild()) {
+ return NS_OK;
+ }
+
+ do {
+ nsresult rv = appendIfMatching(walker, aContext, aNodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = appendMatchingDescendants(walker, aContext, aNodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } while (walker.moveToNextSibling());
+
+ return NS_OK;
+}
+
+nsresult LocationStep::appendMatchingDescendantsRev(
+ const txXPathTreeWalker& aWalker, txIMatchContext* aContext,
+ txNodeSet* aNodes) {
+ txXPathTreeWalker walker(aWalker);
+ if (!walker.moveToLastChild()) {
+ return NS_OK;
+ }
+
+ do {
+ nsresult rv = appendMatchingDescendantsRev(walker, aContext, aNodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = appendIfMatching(walker, aContext, aNodes);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } while (walker.moveToPreviousSibling());
+
+ return NS_OK;
+}
+
+Expr::ExprType LocationStep::getType() { return LOCATIONSTEP_EXPR; }
+
+TX_IMPL_EXPR_STUBS_BASE(LocationStep, NODESET_RESULT)
+
+Expr* LocationStep::getSubExprAt(uint32_t aPos) {
+ return PredicateList::getSubExprAt(aPos);
+}
+
+void LocationStep::setSubExprAt(uint32_t aPos, Expr* aExpr) {
+ PredicateList::setSubExprAt(aPos, aExpr);
+}
+
+bool LocationStep::isSensitiveTo(ContextSensitivity aContext) {
+ return (aContext & NODE_CONTEXT) || mNodeTest->isSensitiveTo(aContext) ||
+ PredicateList::isSensitiveTo(aContext);
+}
+
+#ifdef TX_TO_STRING
+void LocationStep::toString(nsAString& str) {
+ switch (mAxisIdentifier) {
+ case ANCESTOR_AXIS:
+ str.AppendLiteral("ancestor::");
+ break;
+ case ANCESTOR_OR_SELF_AXIS:
+ str.AppendLiteral("ancestor-or-self::");
+ break;
+ case ATTRIBUTE_AXIS:
+ str.Append(char16_t('@'));
+ break;
+ case DESCENDANT_AXIS:
+ str.AppendLiteral("descendant::");
+ break;
+ case DESCENDANT_OR_SELF_AXIS:
+ str.AppendLiteral("descendant-or-self::");
+ break;
+ case FOLLOWING_AXIS:
+ str.AppendLiteral("following::");
+ break;
+ case FOLLOWING_SIBLING_AXIS:
+ str.AppendLiteral("following-sibling::");
+ break;
+ case NAMESPACE_AXIS:
+ str.AppendLiteral("namespace::");
+ break;
+ case PARENT_AXIS:
+ str.AppendLiteral("parent::");
+ break;
+ case PRECEDING_AXIS:
+ str.AppendLiteral("preceding::");
+ break;
+ case PRECEDING_SIBLING_AXIS:
+ str.AppendLiteral("preceding-sibling::");
+ break;
+ case SELF_AXIS:
+ str.AppendLiteral("self::");
+ break;
+ default:
+ break;
+ }
+ NS_ASSERTION(mNodeTest, "mNodeTest is null, that's verboten");
+ mNodeTest->toString(str);
+
+ PredicateList::toString(str);
+}
+#endif