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"
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
) {
23 nsresult rv
= lexer
.parse(aPattern
);
25 // XXX error report parsing error
28 UniquePtr
<txPattern
> pattern
;
29 rv
= createUnionPattern(lexer
, aContext
, *getter_Transfers(pattern
));
31 // XXX error report parsing error
35 txPatternOptimizer optimizer
;
36 txPattern
* newPattern
= nullptr;
37 optimizer
.optimize(pattern
.get(), &newPattern
);
39 *aResult
= newPattern
? newPattern
: pattern
.release();
44 nsresult
txPatternParser::createUnionPattern(txExprLexer
& aLexer
,
45 txIParseContext
* aContext
,
46 txPattern
*& aPattern
) {
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
) {
59 if (type
!= Token::UNION_OP
) {
61 return NS_ERROR_XPATH_PARSE_FAILURE
;
64 txUnionPattern
* unionPattern
= new txUnionPattern();
65 unionPattern
->addPattern(locPath
);
69 rv
= createLocPathPattern(aLexer
, aContext
, locPath
);
74 unionPattern
->addPattern(locPath
);
75 type
= aLexer
.nextToken()->mType
;
76 } while (type
== Token::UNION_OP
);
78 if (type
!= Token::END
) {
80 return NS_ERROR_XPATH_PARSE_FAILURE
;
83 aPattern
= unionPattern
;
87 nsresult
txPatternParser::createLocPathPattern(txExprLexer
& aLexer
,
88 txIParseContext
* aContext
,
89 txPattern
*& aPattern
) {
93 bool isAbsolute
= false;
94 txPattern
* stepPattern
= 0;
95 txLocPathPattern
* pathPattern
= 0;
97 Token::Type type
= aLexer
.peek()->mType
;
99 case Token::ANCESTOR_OP
:
104 case Token::PARENT_OP
:
107 if (aLexer
.peek()->mType
== Token::END
||
108 aLexer
.peek()->mType
== Token::UNION_OP
) {
109 aPattern
= new txRootPattern();
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
;
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
;
139 pathPattern
= new txLocPathPattern();
141 txRootPattern
* root
= new txRootPattern();
143 root
->setSerialize(false);
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
;
155 rv
= createStepPattern(aLexer
, aContext
, stepPattern
);
160 pathPattern
->addStep(stepPattern
, isChild
);
161 stepPattern
= 0; // stepPattern is part of pathPattern now
162 type
= aLexer
.peek()->mType
;
164 aPattern
= pathPattern
;
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
);
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
;
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
);
211 nsresult
txPatternParser::createStepPattern(txExprLexer
& aLexer
,
212 txIParseContext
* aContext
,
213 txPattern
*& aPattern
) {
216 Token
* tok
= aLexer
.peek();
217 if (tok
->mType
== Token::AXIS_IDENTIFIER
) {
218 if (TX_StringEqualsAtom(tok
->Value(), nsGkAtoms::attribute
)) {
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
;
226 } else if (tok
->mType
== Token::AT_SIGN
) {
231 txNodeTest
* nodeTest
;
232 if (aLexer
.peek()->mType
== Token::CNAME
) {
233 tok
= aLexer
.nextToken();
236 RefPtr
<nsAtom
> prefix
, lName
;
238 rv
= resolveQName(tok
->Value(), getter_AddRefs(prefix
), aContext
,
239 getter_AddRefs(lName
), nspace
, true);
241 // XXX error report namespace resolve failed
245 uint16_t nodeType
= isAttr
? (uint16_t)txXPathNodeType::ATTRIBUTE_NODE
246 : (uint16_t)txXPathNodeType::ELEMENT_NODE
;
247 nodeTest
= new txNameTest(prefix
, lName
, nspace
, nodeType
);
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();