Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/. */
5 :
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"
14 :
15 :
16 0 : nsresult txPatternParser::createPattern(const nsString& aPattern,
17 : txIParseContext* aContext,
18 : txPattern** aResult)
19 : {
20 0 : txExprLexer lexer;
21 0 : nsresult rv = lexer.parse(aPattern);
22 0 : if (NS_FAILED(rv)) {
23 : // XXX error report parsing error
24 0 : return rv;
25 : }
26 0 : nsAutoPtr<txPattern> pattern;
27 0 : rv = createUnionPattern(lexer, aContext, *getter_Transfers(pattern));
28 0 : if (NS_FAILED(rv)) {
29 : // XXX error report parsing error
30 0 : return rv;
31 : }
32 :
33 : txPatternOptimizer optimizer;
34 0 : txPattern* newPattern = nullptr;
35 0 : rv = optimizer.optimize(pattern, &newPattern);
36 0 : NS_ENSURE_SUCCESS(rv, rv);
37 :
38 0 : *aResult = newPattern ? newPattern : pattern.forget();
39 :
40 0 : return NS_OK;
41 : }
42 :
43 0 : nsresult txPatternParser::createUnionPattern(txExprLexer& aLexer,
44 : txIParseContext* aContext,
45 : txPattern*& aPattern)
46 : {
47 0 : nsresult rv = NS_OK;
48 0 : txPattern* locPath = 0;
49 :
50 0 : rv = createLocPathPattern(aLexer, aContext, locPath);
51 0 : if (NS_FAILED(rv))
52 0 : return rv;
53 :
54 0 : Token::Type type = aLexer.peek()->mType;
55 0 : if (type == Token::END) {
56 0 : aPattern = locPath;
57 0 : return NS_OK;
58 : }
59 :
60 0 : if (type != Token::UNION_OP) {
61 0 : delete locPath;
62 0 : return NS_ERROR_XPATH_PARSE_FAILURE;
63 : }
64 :
65 0 : txUnionPattern* unionPattern = new txUnionPattern();
66 0 : rv = unionPattern->addPattern(locPath);
67 : #if 0 // XXX addPattern can't fail yet, it doesn't check for mem
68 : if (NS_FAILED(rv)) {
69 : delete unionPattern;
70 : delete locPath;
71 : return rv;
72 : }
73 : #endif
74 :
75 0 : aLexer.nextToken();
76 0 : do {
77 0 : rv = createLocPathPattern(aLexer, aContext, locPath);
78 0 : if (NS_FAILED(rv)) {
79 0 : delete unionPattern;
80 0 : return rv;
81 : }
82 0 : rv = unionPattern->addPattern(locPath);
83 : #if 0 // XXX addPattern can't fail yet, it doesn't check for mem
84 : if (NS_FAILED(rv)) {
85 : delete unionPattern;
86 : delete locPath;
87 : return rv;
88 : }
89 : #endif
90 0 : type = aLexer.nextToken()->mType;
91 0 : } while (type == Token::UNION_OP);
92 :
93 0 : if (type != Token::END) {
94 0 : delete unionPattern;
95 0 : return NS_ERROR_XPATH_PARSE_FAILURE;
96 : }
97 :
98 0 : aPattern = unionPattern;
99 0 : return NS_OK;
100 : }
101 :
102 0 : nsresult txPatternParser::createLocPathPattern(txExprLexer& aLexer,
103 : txIParseContext* aContext,
104 : txPattern*& aPattern)
105 : {
106 0 : nsresult rv = NS_OK;
107 :
108 0 : bool isChild = true;
109 0 : bool isAbsolute = false;
110 0 : txPattern* stepPattern = 0;
111 0 : txLocPathPattern* pathPattern = 0;
112 :
113 0 : Token::Type type = aLexer.peek()->mType;
114 0 : switch (type) {
115 : case Token::ANCESTOR_OP:
116 0 : isChild = false;
117 0 : isAbsolute = true;
118 0 : aLexer.nextToken();
119 0 : break;
120 : case Token::PARENT_OP:
121 0 : aLexer.nextToken();
122 0 : isAbsolute = true;
123 0 : if (aLexer.peek()->mType == Token::END ||
124 0 : aLexer.peek()->mType == Token::UNION_OP) {
125 0 : aPattern = new txRootPattern();
126 0 : return NS_OK;
127 : }
128 0 : break;
129 : case Token::FUNCTION_NAME_AND_PAREN:
130 : // id(Literal) or key(Literal, Literal)
131 : {
132 : nsCOMPtr<nsIAtom> nameAtom =
133 0 : NS_Atomize(aLexer.nextToken()->Value());
134 0 : if (nameAtom == nsGkAtoms::id) {
135 0 : rv = createIdPattern(aLexer, stepPattern);
136 : }
137 0 : else if (nameAtom == nsGkAtoms::key) {
138 0 : rv = createKeyPattern(aLexer, aContext, stepPattern);
139 : }
140 0 : if (NS_FAILED(rv))
141 0 : return rv;
142 : }
143 0 : break;
144 : default:
145 0 : break;
146 : }
147 0 : if (!stepPattern) {
148 0 : rv = createStepPattern(aLexer, aContext, stepPattern);
149 0 : if (NS_FAILED(rv))
150 0 : return rv;
151 : }
152 :
153 0 : type = aLexer.peek()->mType;
154 0 : if (!isAbsolute && type != Token::PARENT_OP
155 0 : && type != Token::ANCESTOR_OP) {
156 0 : aPattern = stepPattern;
157 0 : return NS_OK;
158 : }
159 :
160 0 : pathPattern = new txLocPathPattern();
161 0 : if (isAbsolute) {
162 0 : txRootPattern* root = new txRootPattern();
163 : #ifdef TX_TO_STRING
164 0 : root->setSerialize(false);
165 : #endif
166 :
167 0 : rv = pathPattern->addStep(root, isChild);
168 0 : if (NS_FAILED(rv)) {
169 0 : delete stepPattern;
170 0 : delete pathPattern;
171 0 : delete root;
172 0 : return NS_ERROR_OUT_OF_MEMORY;
173 : }
174 : }
175 :
176 0 : rv = pathPattern->addStep(stepPattern, isChild);
177 0 : if (NS_FAILED(rv)) {
178 0 : delete stepPattern;
179 0 : delete pathPattern;
180 0 : return NS_ERROR_OUT_OF_MEMORY;
181 : }
182 0 : stepPattern = 0; // stepPattern is part of pathPattern now
183 :
184 0 : while (type == Token::PARENT_OP || type == Token::ANCESTOR_OP) {
185 0 : isChild = type == Token::PARENT_OP;
186 0 : aLexer.nextToken();
187 0 : rv = createStepPattern(aLexer, aContext, stepPattern);
188 0 : if (NS_FAILED(rv)) {
189 0 : delete pathPattern;
190 0 : return rv;
191 : }
192 0 : rv = pathPattern->addStep(stepPattern, isChild);
193 0 : if (NS_FAILED(rv)) {
194 0 : delete stepPattern;
195 0 : delete pathPattern;
196 0 : return NS_ERROR_OUT_OF_MEMORY;
197 : }
198 0 : stepPattern = 0; // stepPattern is part of pathPattern now
199 0 : type = aLexer.peek()->mType;
200 : }
201 0 : aPattern = pathPattern;
202 0 : return rv;
203 : }
204 :
205 0 : nsresult txPatternParser::createIdPattern(txExprLexer& aLexer,
206 : txPattern*& aPattern)
207 : {
208 : // check for '(' Literal ')'
209 0 : if (aLexer.peek()->mType != Token::LITERAL)
210 0 : return NS_ERROR_XPATH_PARSE_FAILURE;
211 : const nsDependentSubstring& value =
212 0 : aLexer.nextToken()->Value();
213 0 : if (aLexer.nextToken()->mType != Token::R_PAREN)
214 0 : return NS_ERROR_XPATH_PARSE_FAILURE;
215 0 : aPattern = new txIdPattern(value);
216 0 : return NS_OK;
217 : }
218 :
219 0 : nsresult txPatternParser::createKeyPattern(txExprLexer& aLexer,
220 : txIParseContext* aContext,
221 : txPattern*& aPattern)
222 : {
223 : // check for '(' Literal, Literal ')'
224 0 : if (aLexer.peek()->mType != Token::LITERAL)
225 0 : return NS_ERROR_XPATH_PARSE_FAILURE;
226 : const nsDependentSubstring& key =
227 0 : aLexer.nextToken()->Value();
228 0 : if (aLexer.nextToken()->mType != Token::COMMA &&
229 0 : aLexer.peek()->mType != Token::LITERAL)
230 0 : return NS_ERROR_XPATH_PARSE_FAILURE;
231 : const nsDependentSubstring& value =
232 0 : aLexer.nextToken()->Value();
233 0 : if (aLexer.nextToken()->mType != Token::R_PAREN)
234 0 : return NS_ERROR_XPATH_PARSE_FAILURE;
235 :
236 0 : if (!aContext->allowed(txIParseContext::KEY_FUNCTION))
237 0 : return NS_ERROR_XSLT_CALL_TO_KEY_NOT_ALLOWED;
238 :
239 : const char16_t* colon;
240 0 : if (!XMLUtils::isValidQName(PromiseFlatString(key), &colon))
241 0 : return NS_ERROR_XPATH_PARSE_FAILURE;
242 0 : nsCOMPtr<nsIAtom> prefix, localName;
243 : int32_t namespaceID;
244 0 : nsresult rv = resolveQName(key, getter_AddRefs(prefix), aContext,
245 0 : getter_AddRefs(localName), namespaceID);
246 0 : if (NS_FAILED(rv))
247 0 : return rv;
248 :
249 0 : aPattern = new txKeyPattern(prefix, localName, namespaceID, value);
250 0 : return NS_OK;
251 : }
252 :
253 0 : nsresult txPatternParser::createStepPattern(txExprLexer& aLexer,
254 : txIParseContext* aContext,
255 : txPattern*& aPattern)
256 : {
257 0 : nsresult rv = NS_OK;
258 0 : bool isAttr = false;
259 0 : Token* tok = aLexer.peek();
260 0 : if (tok->mType == Token::AXIS_IDENTIFIER) {
261 0 : if (TX_StringEqualsAtom(tok->Value(), nsGkAtoms::attribute)) {
262 0 : isAttr = true;
263 : }
264 0 : else if (!TX_StringEqualsAtom(tok->Value(), nsGkAtoms::child)) {
265 : // all done already for CHILD_AXIS, for all others
266 : // XXX report unexpected axis error
267 0 : return NS_ERROR_XPATH_PARSE_FAILURE;
268 : }
269 0 : aLexer.nextToken();
270 : }
271 0 : else if (tok->mType == Token::AT_SIGN) {
272 0 : aLexer.nextToken();
273 0 : isAttr = true;
274 : }
275 :
276 : txNodeTest* nodeTest;
277 0 : if (aLexer.peek()->mType == Token::CNAME) {
278 0 : tok = aLexer.nextToken();
279 :
280 : // resolve QName
281 0 : nsCOMPtr<nsIAtom> prefix, lName;
282 : int32_t nspace;
283 0 : rv = resolveQName(tok->Value(), getter_AddRefs(prefix), aContext,
284 0 : getter_AddRefs(lName), nspace, true);
285 0 : if (NS_FAILED(rv)) {
286 : // XXX error report namespace resolve failed
287 0 : return rv;
288 : }
289 :
290 0 : uint16_t nodeType = isAttr ?
291 : (uint16_t)txXPathNodeType::ATTRIBUTE_NODE :
292 0 : (uint16_t)txXPathNodeType::ELEMENT_NODE;
293 0 : nodeTest = new txNameTest(prefix, lName, nspace, nodeType);
294 : }
295 : else {
296 0 : rv = createNodeTypeTest(aLexer, &nodeTest);
297 0 : NS_ENSURE_SUCCESS(rv, rv);
298 : }
299 :
300 0 : nsAutoPtr<txStepPattern> step(new txStepPattern(nodeTest, isAttr));
301 0 : rv = parsePredicates(step, aLexer, aContext);
302 0 : NS_ENSURE_SUCCESS(rv, rv);
303 :
304 0 : aPattern = step.forget();
305 :
306 0 : return NS_OK;
307 : }
|