Bug 1874684 - Part 4: Prefer const references instead of copying Instant values....
[gecko.git] / dom / xslt / xslt / txPatternParser.cpp
blobd012c8d5495c7972115ca7df743644afe09aebca
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "txPatternParser.h"
7 #include "txExprLexer.h"
8 #include "nsGkAtoms.h"
9 #include "nsError.h"
10 #include "txStringUtils.h"
11 #include "txXSLTPatterns.h"
12 #include "txStylesheetCompiler.h"
13 #include "txPatternOptimizer.h"
15 #include "mozilla/UniquePtrExtensions.h"
17 using mozilla::UniquePtr;
19 nsresult txPatternParser::createPattern(const nsString& aPattern,
20 txIParseContext* aContext,
21 txPattern** aResult) {
22 txExprLexer lexer;
23 nsresult rv = lexer.parse(aPattern);
24 if (NS_FAILED(rv)) {
25 // XXX error report parsing error
26 return rv;
28 UniquePtr<txPattern> pattern;
29 rv = createUnionPattern(lexer, aContext, *getter_Transfers(pattern));
30 if (NS_FAILED(rv)) {
31 // XXX error report parsing error
32 return rv;
35 txPatternOptimizer optimizer;
36 txPattern* newPattern = nullptr;
37 optimizer.optimize(pattern.get(), &newPattern);
39 *aResult = newPattern ? newPattern : pattern.release();
41 return NS_OK;
44 nsresult txPatternParser::createUnionPattern(txExprLexer& aLexer,
45 txIParseContext* aContext,
46 txPattern*& aPattern) {
47 nsresult rv = NS_OK;
48 txPattern* locPath = 0;
50 rv = createLocPathPattern(aLexer, aContext, locPath);
51 if (NS_FAILED(rv)) return rv;
53 Token::Type type = aLexer.peek()->mType;
54 if (type == Token::END) {
55 aPattern = locPath;
56 return NS_OK;
59 if (type != Token::UNION_OP) {
60 delete locPath;
61 return NS_ERROR_XPATH_PARSE_FAILURE;
64 txUnionPattern* unionPattern = new txUnionPattern();
65 unionPattern->addPattern(locPath);
67 aLexer.nextToken();
68 do {
69 rv = createLocPathPattern(aLexer, aContext, locPath);
70 if (NS_FAILED(rv)) {
71 delete unionPattern;
72 return rv;
74 unionPattern->addPattern(locPath);
75 type = aLexer.nextToken()->mType;
76 } while (type == Token::UNION_OP);
78 if (type != Token::END) {
79 delete unionPattern;
80 return NS_ERROR_XPATH_PARSE_FAILURE;
83 aPattern = unionPattern;
84 return NS_OK;
87 nsresult txPatternParser::createLocPathPattern(txExprLexer& aLexer,
88 txIParseContext* aContext,
89 txPattern*& aPattern) {
90 nsresult rv = NS_OK;
92 bool isChild = true;
93 bool isAbsolute = false;
94 txPattern* stepPattern = 0;
95 txLocPathPattern* pathPattern = 0;
97 Token::Type type = aLexer.peek()->mType;
98 switch (type) {
99 case Token::ANCESTOR_OP:
100 isChild = false;
101 isAbsolute = true;
102 aLexer.nextToken();
103 break;
104 case Token::PARENT_OP:
105 aLexer.nextToken();
106 isAbsolute = true;
107 if (aLexer.peek()->mType == Token::END ||
108 aLexer.peek()->mType == Token::UNION_OP) {
109 aPattern = new txRootPattern();
110 return NS_OK;
112 break;
113 case Token::FUNCTION_NAME_AND_PAREN:
114 // id(Literal) or key(Literal, Literal)
116 RefPtr<nsAtom> nameAtom = NS_Atomize(aLexer.nextToken()->Value());
117 if (nameAtom == nsGkAtoms::id) {
118 rv = createIdPattern(aLexer, stepPattern);
119 } else if (nameAtom == nsGkAtoms::key) {
120 rv = createKeyPattern(aLexer, aContext, stepPattern);
122 if (NS_FAILED(rv)) return rv;
124 break;
125 default:
126 break;
128 if (!stepPattern) {
129 rv = createStepPattern(aLexer, aContext, stepPattern);
130 if (NS_FAILED(rv)) return rv;
133 type = aLexer.peek()->mType;
134 if (!isAbsolute && type != Token::PARENT_OP && type != Token::ANCESTOR_OP) {
135 aPattern = stepPattern;
136 return NS_OK;
139 pathPattern = new txLocPathPattern();
140 if (isAbsolute) {
141 txRootPattern* root = new txRootPattern();
142 #ifdef TX_TO_STRING
143 root->setSerialize(false);
144 #endif
146 pathPattern->addStep(root, isChild);
149 pathPattern->addStep(stepPattern, isChild);
150 stepPattern = 0; // stepPattern is part of pathPattern now
152 while (type == Token::PARENT_OP || type == Token::ANCESTOR_OP) {
153 isChild = type == Token::PARENT_OP;
154 aLexer.nextToken();
155 rv = createStepPattern(aLexer, aContext, stepPattern);
156 if (NS_FAILED(rv)) {
157 delete pathPattern;
158 return rv;
160 pathPattern->addStep(stepPattern, isChild);
161 stepPattern = 0; // stepPattern is part of pathPattern now
162 type = aLexer.peek()->mType;
164 aPattern = pathPattern;
165 return rv;
168 nsresult txPatternParser::createIdPattern(txExprLexer& aLexer,
169 txPattern*& aPattern) {
170 // check for '(' Literal ')'
171 if (aLexer.peek()->mType != Token::LITERAL)
172 return NS_ERROR_XPATH_PARSE_FAILURE;
173 const nsDependentSubstring& value = aLexer.nextToken()->Value();
174 if (aLexer.nextToken()->mType != Token::R_PAREN)
175 return NS_ERROR_XPATH_PARSE_FAILURE;
176 aPattern = new txIdPattern(value);
177 return NS_OK;
180 nsresult txPatternParser::createKeyPattern(txExprLexer& aLexer,
181 txIParseContext* aContext,
182 txPattern*& aPattern) {
183 // check for '(' Literal, Literal ')'
184 if (aLexer.peek()->mType != Token::LITERAL)
185 return NS_ERROR_XPATH_PARSE_FAILURE;
186 const nsDependentSubstring& key = aLexer.nextToken()->Value();
187 if (aLexer.nextToken()->mType != Token::COMMA &&
188 aLexer.peek()->mType != Token::LITERAL)
189 return NS_ERROR_XPATH_PARSE_FAILURE;
190 const nsDependentSubstring& value = aLexer.nextToken()->Value();
191 if (aLexer.nextToken()->mType != Token::R_PAREN)
192 return NS_ERROR_XPATH_PARSE_FAILURE;
194 if (!aContext->allowed(txIParseContext::KEY_FUNCTION))
195 return NS_ERROR_XSLT_CALL_TO_KEY_NOT_ALLOWED;
197 const char16_t* colon;
198 if (!XMLUtils::isValidQName(key, &colon)) {
199 return NS_ERROR_XPATH_PARSE_FAILURE;
201 RefPtr<nsAtom> prefix, localName;
202 int32_t namespaceID;
203 nsresult rv = resolveQName(key, getter_AddRefs(prefix), aContext,
204 getter_AddRefs(localName), namespaceID);
205 if (NS_FAILED(rv)) return rv;
207 aPattern = new txKeyPattern(prefix, localName, namespaceID, value);
208 return NS_OK;
211 nsresult txPatternParser::createStepPattern(txExprLexer& aLexer,
212 txIParseContext* aContext,
213 txPattern*& aPattern) {
214 nsresult rv = NS_OK;
215 bool isAttr = false;
216 Token* tok = aLexer.peek();
217 if (tok->mType == Token::AXIS_IDENTIFIER) {
218 if (TX_StringEqualsAtom(tok->Value(), nsGkAtoms::attribute)) {
219 isAttr = true;
220 } else if (!TX_StringEqualsAtom(tok->Value(), nsGkAtoms::child)) {
221 // all done already for CHILD_AXIS, for all others
222 // XXX report unexpected axis error
223 return NS_ERROR_XPATH_PARSE_FAILURE;
225 aLexer.nextToken();
226 } else if (tok->mType == Token::AT_SIGN) {
227 aLexer.nextToken();
228 isAttr = true;
231 txNodeTest* nodeTest;
232 if (aLexer.peek()->mType == Token::CNAME) {
233 tok = aLexer.nextToken();
235 // resolve QName
236 RefPtr<nsAtom> prefix, lName;
237 int32_t nspace;
238 rv = resolveQName(tok->Value(), getter_AddRefs(prefix), aContext,
239 getter_AddRefs(lName), nspace, true);
240 if (NS_FAILED(rv)) {
241 // XXX error report namespace resolve failed
242 return rv;
245 uint16_t nodeType = isAttr ? (uint16_t)txXPathNodeType::ATTRIBUTE_NODE
246 : (uint16_t)txXPathNodeType::ELEMENT_NODE;
247 nodeTest = new txNameTest(prefix, lName, nspace, nodeType);
248 } else {
249 rv = createNodeTypeTest(aLexer, &nodeTest);
250 NS_ENSURE_SUCCESS(rv, rv);
253 UniquePtr<txStepPattern> step(new txStepPattern(nodeTest, isAttr));
254 rv = parsePredicates(step.get(), aLexer, aContext);
255 NS_ENSURE_SUCCESS(rv, rv);
257 aPattern = step.release();
259 return NS_OK;