summaryrefslogtreecommitdiffstats
path: root/dom/xslt/xslt/txPatternParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/xslt/xslt/txPatternParser.cpp')
-rw-r--r--dom/xslt/xslt/txPatternParser.cpp260
1 files changed, 260 insertions, 0 deletions
diff --git a/dom/xslt/xslt/txPatternParser.cpp b/dom/xslt/xslt/txPatternParser.cpp
new file mode 100644
index 0000000000..d012c8d549
--- /dev/null
+++ b/dom/xslt/xslt/txPatternParser.cpp
@@ -0,0 +1,260 @@
+/* -*- 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/. */
+
+#include "txPatternParser.h"
+#include "txExprLexer.h"
+#include "nsGkAtoms.h"
+#include "nsError.h"
+#include "txStringUtils.h"
+#include "txXSLTPatterns.h"
+#include "txStylesheetCompiler.h"
+#include "txPatternOptimizer.h"
+
+#include "mozilla/UniquePtrExtensions.h"
+
+using mozilla::UniquePtr;
+
+nsresult txPatternParser::createPattern(const nsString& aPattern,
+ txIParseContext* aContext,
+ txPattern** aResult) {
+ txExprLexer lexer;
+ nsresult rv = lexer.parse(aPattern);
+ if (NS_FAILED(rv)) {
+ // XXX error report parsing error
+ return rv;
+ }
+ UniquePtr<txPattern> pattern;
+ rv = createUnionPattern(lexer, aContext, *getter_Transfers(pattern));
+ if (NS_FAILED(rv)) {
+ // XXX error report parsing error
+ return rv;
+ }
+
+ txPatternOptimizer optimizer;
+ txPattern* newPattern = nullptr;
+ optimizer.optimize(pattern.get(), &newPattern);
+
+ *aResult = newPattern ? newPattern : pattern.release();
+
+ return NS_OK;
+}
+
+nsresult txPatternParser::createUnionPattern(txExprLexer& aLexer,
+ txIParseContext* aContext,
+ txPattern*& aPattern) {
+ nsresult rv = NS_OK;
+ txPattern* locPath = 0;
+
+ rv = createLocPathPattern(aLexer, aContext, locPath);
+ if (NS_FAILED(rv)) return rv;
+
+ Token::Type type = aLexer.peek()->mType;
+ if (type == Token::END) {
+ aPattern = locPath;
+ return NS_OK;
+ }
+
+ if (type != Token::UNION_OP) {
+ delete locPath;
+ return NS_ERROR_XPATH_PARSE_FAILURE;
+ }
+
+ txUnionPattern* unionPattern = new txUnionPattern();
+ unionPattern->addPattern(locPath);
+
+ aLexer.nextToken();
+ do {
+ rv = createLocPathPattern(aLexer, aContext, locPath);
+ if (NS_FAILED(rv)) {
+ delete unionPattern;
+ return rv;
+ }
+ unionPattern->addPattern(locPath);
+ type = aLexer.nextToken()->mType;
+ } while (type == Token::UNION_OP);
+
+ if (type != Token::END) {
+ delete unionPattern;
+ return NS_ERROR_XPATH_PARSE_FAILURE;
+ }
+
+ aPattern = unionPattern;
+ return NS_OK;
+}
+
+nsresult txPatternParser::createLocPathPattern(txExprLexer& aLexer,
+ txIParseContext* aContext,
+ txPattern*& aPattern) {
+ nsresult rv = NS_OK;
+
+ bool isChild = true;
+ bool isAbsolute = false;
+ txPattern* stepPattern = 0;
+ txLocPathPattern* pathPattern = 0;
+
+ Token::Type type = aLexer.peek()->mType;
+ switch (type) {
+ case Token::ANCESTOR_OP:
+ isChild = false;
+ isAbsolute = true;
+ aLexer.nextToken();
+ break;
+ case Token::PARENT_OP:
+ aLexer.nextToken();
+ isAbsolute = true;
+ if (aLexer.peek()->mType == Token::END ||
+ aLexer.peek()->mType == Token::UNION_OP) {
+ aPattern = new txRootPattern();
+ return NS_OK;
+ }
+ break;
+ case Token::FUNCTION_NAME_AND_PAREN:
+ // id(Literal) or key(Literal, Literal)
+ {
+ RefPtr<nsAtom> nameAtom = NS_Atomize(aLexer.nextToken()->Value());
+ if (nameAtom == nsGkAtoms::id) {
+ rv = createIdPattern(aLexer, stepPattern);
+ } else if (nameAtom == nsGkAtoms::key) {
+ rv = createKeyPattern(aLexer, aContext, stepPattern);
+ }
+ if (NS_FAILED(rv)) return rv;
+ }
+ break;
+ default:
+ break;
+ }
+ if (!stepPattern) {
+ rv = createStepPattern(aLexer, aContext, stepPattern);
+ if (NS_FAILED(rv)) return rv;
+ }
+
+ type = aLexer.peek()->mType;
+ if (!isAbsolute && type != Token::PARENT_OP && type != Token::ANCESTOR_OP) {
+ aPattern = stepPattern;
+ return NS_OK;
+ }
+
+ pathPattern = new txLocPathPattern();
+ if (isAbsolute) {
+ txRootPattern* root = new txRootPattern();
+#ifdef TX_TO_STRING
+ root->setSerialize(false);
+#endif
+
+ pathPattern->addStep(root, isChild);
+ }
+
+ pathPattern->addStep(stepPattern, isChild);
+ stepPattern = 0; // stepPattern is part of pathPattern now
+
+ while (type == Token::PARENT_OP || type == Token::ANCESTOR_OP) {
+ isChild = type == Token::PARENT_OP;
+ aLexer.nextToken();
+ rv = createStepPattern(aLexer, aContext, stepPattern);
+ if (NS_FAILED(rv)) {
+ delete pathPattern;
+ return rv;
+ }
+ pathPattern->addStep(stepPattern, isChild);
+ stepPattern = 0; // stepPattern is part of pathPattern now
+ type = aLexer.peek()->mType;
+ }
+ aPattern = pathPattern;
+ return rv;
+}
+
+nsresult txPatternParser::createIdPattern(txExprLexer& aLexer,
+ txPattern*& aPattern) {
+ // check for '(' Literal ')'
+ if (aLexer.peek()->mType != Token::LITERAL)
+ return NS_ERROR_XPATH_PARSE_FAILURE;
+ const nsDependentSubstring& value = aLexer.nextToken()->Value();
+ if (aLexer.nextToken()->mType != Token::R_PAREN)
+ return NS_ERROR_XPATH_PARSE_FAILURE;
+ aPattern = new txIdPattern(value);
+ return NS_OK;
+}
+
+nsresult txPatternParser::createKeyPattern(txExprLexer& aLexer,
+ txIParseContext* aContext,
+ txPattern*& aPattern) {
+ // check for '(' Literal, Literal ')'
+ if (aLexer.peek()->mType != Token::LITERAL)
+ return NS_ERROR_XPATH_PARSE_FAILURE;
+ const nsDependentSubstring& key = aLexer.nextToken()->Value();
+ if (aLexer.nextToken()->mType != Token::COMMA &&
+ aLexer.peek()->mType != Token::LITERAL)
+ return NS_ERROR_XPATH_PARSE_FAILURE;
+ const nsDependentSubstring& value = aLexer.nextToken()->Value();
+ if (aLexer.nextToken()->mType != Token::R_PAREN)
+ return NS_ERROR_XPATH_PARSE_FAILURE;
+
+ if (!aContext->allowed(txIParseContext::KEY_FUNCTION))
+ return NS_ERROR_XSLT_CALL_TO_KEY_NOT_ALLOWED;
+
+ const char16_t* colon;
+ if (!XMLUtils::isValidQName(key, &colon)) {
+ return NS_ERROR_XPATH_PARSE_FAILURE;
+ }
+ RefPtr<nsAtom> prefix, localName;
+ int32_t namespaceID;
+ nsresult rv = resolveQName(key, getter_AddRefs(prefix), aContext,
+ getter_AddRefs(localName), namespaceID);
+ if (NS_FAILED(rv)) return rv;
+
+ aPattern = new txKeyPattern(prefix, localName, namespaceID, value);
+ return NS_OK;
+}
+
+nsresult txPatternParser::createStepPattern(txExprLexer& aLexer,
+ txIParseContext* aContext,
+ txPattern*& aPattern) {
+ nsresult rv = NS_OK;
+ bool isAttr = false;
+ Token* tok = aLexer.peek();
+ if (tok->mType == Token::AXIS_IDENTIFIER) {
+ if (TX_StringEqualsAtom(tok->Value(), nsGkAtoms::attribute)) {
+ isAttr = true;
+ } else if (!TX_StringEqualsAtom(tok->Value(), nsGkAtoms::child)) {
+ // all done already for CHILD_AXIS, for all others
+ // XXX report unexpected axis error
+ return NS_ERROR_XPATH_PARSE_FAILURE;
+ }
+ aLexer.nextToken();
+ } else if (tok->mType == Token::AT_SIGN) {
+ aLexer.nextToken();
+ isAttr = true;
+ }
+
+ txNodeTest* nodeTest;
+ if (aLexer.peek()->mType == Token::CNAME) {
+ tok = aLexer.nextToken();
+
+ // resolve QName
+ RefPtr<nsAtom> prefix, lName;
+ int32_t nspace;
+ rv = resolveQName(tok->Value(), getter_AddRefs(prefix), aContext,
+ getter_AddRefs(lName), nspace, true);
+ if (NS_FAILED(rv)) {
+ // XXX error report namespace resolve failed
+ return rv;
+ }
+
+ uint16_t nodeType = isAttr ? (uint16_t)txXPathNodeType::ATTRIBUTE_NODE
+ : (uint16_t)txXPathNodeType::ELEMENT_NODE;
+ nodeTest = new txNameTest(prefix, lName, nspace, nodeType);
+ } else {
+ rv = createNodeTypeTest(aLexer, &nodeTest);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ UniquePtr<txStepPattern> step(new txStepPattern(nodeTest, isAttr));
+ rv = parsePredicates(step.get(), aLexer, aContext);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ aPattern = step.release();
+
+ return NS_OK;
+}