Back to index

lightning-sunbird  0.9+nobinonly
txPatternParser.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is TransforMiiX XSLT processor code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Axel Hecht.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Axel Hecht <axel@pike.org>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "txPatternParser.h"
00040 #include "ExprLexer.h"
00041 #include "txAtoms.h"
00042 #include "txError.h"
00043 #include "txStringUtils.h"
00044 #include "txXSLTPatterns.h"
00045 #include "txIXPathContext.h"
00046 
00047 txPattern* txPatternParser::createPattern(const nsAFlatString& aPattern,
00048                                           txIParseContext* aContext)
00049 {
00050     txPattern* pattern = 0;
00051     txExprLexer lexer;
00052     nsresult rv = lexer.parse(aPattern);
00053     if (NS_FAILED(rv)) {
00054         // XXX error report parsing error
00055         return 0;
00056     }
00057     rv = createUnionPattern(lexer, aContext, pattern);
00058     if (NS_FAILED(rv)) {
00059         // XXX error report parsing error
00060         return 0;
00061     }
00062     return pattern;
00063 }
00064 
00065 nsresult txPatternParser::createUnionPattern(txExprLexer& aLexer,
00066                                              txIParseContext* aContext,
00067                                              txPattern*& aPattern)
00068 {
00069     nsresult rv = NS_OK;
00070     txPattern* locPath = 0;
00071 
00072     rv = createLocPathPattern(aLexer, aContext, locPath);
00073     if (NS_FAILED(rv))
00074         return rv;
00075 
00076     Token::Type type = aLexer.peek()->mType;
00077     if (type == Token::END) {
00078         aPattern = locPath;
00079         return NS_OK;
00080     }
00081 
00082     if (type != Token::UNION_OP) {
00083         delete locPath;
00084         return NS_ERROR_XPATH_PARSE_FAILURE;
00085     }
00086 
00087     txUnionPattern* unionPattern = new txUnionPattern();
00088     if (!unionPattern) {
00089         delete locPath;
00090         return NS_ERROR_OUT_OF_MEMORY;
00091     }
00092     rv = unionPattern->addPattern(locPath);
00093 #if 0 // XXX addPattern can't fail yet, it doesn't check for mem
00094     if (NS_FAILED(rv)) {
00095         delete unionPattern;
00096         delete locPath;
00097         return rv;
00098     }
00099 #endif
00100 
00101     aLexer.nextToken();
00102     do {
00103         rv = createLocPathPattern(aLexer, aContext, locPath);
00104         if (NS_FAILED(rv)) {
00105             delete unionPattern;
00106             return rv;
00107         }
00108         rv = unionPattern->addPattern(locPath);
00109 #if 0 // XXX addPattern can't fail yet, it doesn't check for mem
00110         if (NS_FAILED(rv)) {
00111             delete unionPattern;
00112             delete locPath;
00113             return rv;
00114         }
00115 #endif
00116         type = aLexer.nextToken()->mType;
00117     } while (type == Token::UNION_OP);
00118 
00119     if (type != Token::END) {
00120         delete unionPattern;
00121         return NS_ERROR_XPATH_PARSE_FAILURE;
00122     }
00123 
00124     aPattern = unionPattern;
00125     return NS_OK;
00126 }
00127 
00128 nsresult txPatternParser::createLocPathPattern(txExprLexer& aLexer,
00129                                                txIParseContext* aContext,
00130                                                txPattern*& aPattern)
00131 {
00132     nsresult rv = NS_OK;
00133 
00134     MBool isChild = MB_TRUE;
00135     MBool isAbsolute = MB_FALSE;
00136     txPattern* stepPattern = 0;
00137     txLocPathPattern* pathPattern = 0;
00138 
00139     Token::Type type = aLexer.peek()->mType;
00140     switch (type) {
00141         case Token::ANCESTOR_OP:
00142             isChild = MB_FALSE;
00143             isAbsolute = MB_TRUE;
00144             aLexer.nextToken();
00145             break;
00146         case Token::PARENT_OP:
00147             aLexer.nextToken();
00148             isAbsolute = MB_TRUE;
00149             if (aLexer.peek()->mType == Token::END || 
00150                 aLexer.peek()->mType == Token::UNION_OP) {
00151                 aPattern = new txRootPattern();
00152 
00153                 return aPattern ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00154             }
00155             break;
00156         case Token::FUNCTION_NAME:
00157             // id(Literal) or key(Literal, Literal)
00158             {
00159                 nsCOMPtr<nsIAtom> nameAtom =
00160                     do_GetAtom(aLexer.nextToken()->Value());
00161                 if (nameAtom == txXPathAtoms::id) {
00162                     rv = createIdPattern(aLexer, stepPattern);
00163                 }
00164                 else if (nameAtom == txXSLTAtoms::key) {
00165                     rv = createKeyPattern(aLexer, aContext, stepPattern);
00166                 }
00167                 if (NS_FAILED(rv))
00168                     return rv;
00169             }
00170             break;
00171         default:
00172             break;
00173     }
00174     if (!stepPattern) {
00175         rv = createStepPattern(aLexer, aContext, stepPattern);
00176         if (NS_FAILED(rv))
00177             return rv;
00178     }
00179 
00180     type = aLexer.peek()->mType;
00181     if (!isAbsolute && type != Token::PARENT_OP
00182         && type != Token::ANCESTOR_OP) {
00183         aPattern = stepPattern;
00184         return NS_OK;
00185     }
00186 
00187     pathPattern = new txLocPathPattern();
00188     if (!pathPattern) {
00189         delete stepPattern;
00190         return NS_ERROR_OUT_OF_MEMORY;
00191     }
00192 
00193     if (isAbsolute) {
00194         txRootPattern* root = new txRootPattern();
00195         if (!root) {
00196             delete stepPattern;
00197             delete pathPattern;
00198             return NS_ERROR_OUT_OF_MEMORY;
00199         }
00200 
00201 #ifdef TX_TO_STRING
00202         root->setSerialize(PR_FALSE);
00203 #endif
00204 
00205         rv = pathPattern->addStep(root, isChild);
00206         if (NS_FAILED(rv)) {
00207             delete stepPattern;
00208             delete pathPattern;
00209             delete root;
00210             return NS_ERROR_OUT_OF_MEMORY;
00211         }
00212     }
00213 
00214     rv = pathPattern->addStep(stepPattern, isChild);
00215     if (NS_FAILED(rv)) {
00216         delete stepPattern;
00217         delete pathPattern;
00218         return NS_ERROR_OUT_OF_MEMORY;
00219     }
00220     stepPattern = 0; // stepPattern is part of pathPattern now
00221 
00222     while (type == Token::PARENT_OP || type == Token::ANCESTOR_OP) {
00223         isChild = type == Token::PARENT_OP;
00224         aLexer.nextToken();
00225         rv = createStepPattern(aLexer, aContext, stepPattern);
00226         if (NS_FAILED(rv)) {
00227             delete pathPattern;
00228             return rv;
00229         }
00230         rv = pathPattern->addStep(stepPattern, isChild);
00231         if (NS_FAILED(rv)) {
00232             delete stepPattern;
00233             delete pathPattern;
00234             return NS_ERROR_OUT_OF_MEMORY;
00235         }
00236         stepPattern = 0; // stepPattern is part of pathPattern now
00237         type = aLexer.peek()->mType;
00238     }
00239     aPattern = pathPattern;
00240     return rv;
00241 }
00242 
00243 nsresult txPatternParser::createIdPattern(txExprLexer& aLexer,
00244                                           txPattern*& aPattern)
00245 {
00246     // check for '(' Literal ')'
00247     if (aLexer.nextToken()->mType != Token::L_PAREN && 
00248         aLexer.peek()->mType != Token::LITERAL)
00249         return NS_ERROR_XPATH_PARSE_FAILURE;
00250     const nsDependentSubstring& value =
00251         aLexer.nextToken()->Value();
00252     if (aLexer.nextToken()->mType != Token::R_PAREN)
00253         return NS_ERROR_XPATH_PARSE_FAILURE;
00254     aPattern  = new txIdPattern(value);
00255     return aPattern ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00256 }
00257 
00258 nsresult txPatternParser::createKeyPattern(txExprLexer& aLexer,
00259                                            txIParseContext* aContext,
00260                                            txPattern*& aPattern)
00261 {
00262     // check for '(' Literal, Literal ')'
00263     if (aLexer.nextToken()->mType != Token::L_PAREN && 
00264         aLexer.peek()->mType != Token::LITERAL)
00265         return NS_ERROR_XPATH_PARSE_FAILURE;
00266     const nsDependentSubstring& key =
00267         aLexer.nextToken()->Value();
00268     if (aLexer.nextToken()->mType != Token::COMMA && 
00269         aLexer.peek()->mType != Token::LITERAL)
00270         return NS_ERROR_XPATH_PARSE_FAILURE;
00271     const nsDependentSubstring& value =
00272         aLexer.nextToken()->Value();
00273     if (aLexer.nextToken()->mType != Token::R_PAREN)
00274         return NS_ERROR_XPATH_PARSE_FAILURE;
00275 
00276     const PRUnichar* colon;
00277     if (!XMLUtils::isValidQName(PromiseFlatString(key), &colon))
00278         return NS_ERROR_XPATH_PARSE_FAILURE;
00279     nsCOMPtr<nsIAtom> prefix, localName;
00280     PRInt32 namespaceID;
00281     nsresult rv = resolveQName(key, getter_AddRefs(prefix), aContext,
00282                                getter_AddRefs(localName), namespaceID);
00283     if (NS_FAILED(rv))
00284         return rv;
00285 
00286     aPattern  = new txKeyPattern(prefix, localName, namespaceID, value);
00287 
00288     return aPattern ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00289 }
00290 
00291 nsresult txPatternParser::createStepPattern(txExprLexer& aLexer,
00292                                             txIParseContext* aContext,
00293                                             txPattern*& aPattern)
00294 {
00295     nsresult rv = NS_OK;
00296     MBool isAttr = MB_FALSE;
00297     Token* tok = aLexer.peek();
00298     if (tok->mType == Token::AXIS_IDENTIFIER) {
00299         if (TX_StringEqualsAtom(tok->Value(), txXPathAtoms::attribute)) {
00300             isAttr = MB_TRUE;
00301         }
00302         else if (!TX_StringEqualsAtom(tok->Value(), txXPathAtoms::child)) {
00303             // all done already for CHILD_AXIS, for all others
00304             // XXX report unexpected axis error
00305             return NS_ERROR_XPATH_PARSE_FAILURE;
00306         }
00307         aLexer.nextToken();
00308     }
00309     else if (tok->mType == Token::AT_SIGN) {
00310         aLexer.nextToken();
00311         isAttr = MB_TRUE;
00312     }
00313     tok = aLexer.nextToken();
00314 
00315     txNodeTest* nodeTest = 0;
00316     if (tok->mType == Token::CNAME) {
00317         // resolve QName
00318         nsCOMPtr<nsIAtom> prefix, lName;
00319         PRInt32 nspace;
00320         rv = resolveQName(tok->Value(), getter_AddRefs(prefix), aContext,
00321                           getter_AddRefs(lName), nspace, PR_TRUE);
00322         if (NS_FAILED(rv)) {
00323             // XXX error report namespace resolve failed
00324             return rv;
00325         }
00326         if (isAttr) {
00327             nodeTest = new txNameTest(prefix, lName, nspace,
00328                                       txXPathNodeType::ATTRIBUTE_NODE);
00329         }
00330         else {
00331             nodeTest = new txNameTest(prefix, lName, nspace,
00332                                       txXPathNodeType::ELEMENT_NODE);
00333         }
00334         if (!nodeTest) {
00335             return NS_ERROR_OUT_OF_MEMORY;
00336         }
00337     }
00338     else {
00339         aLexer.pushBack();
00340         rv = createNodeTypeTest(aLexer, &nodeTest);
00341         NS_ENSURE_SUCCESS(rv, rv);
00342     }
00343 
00344     txStepPattern* step = new txStepPattern(nodeTest, isAttr);
00345     if (!step) {
00346         delete nodeTest;
00347         return NS_ERROR_OUT_OF_MEMORY;
00348     }
00349     nodeTest = 0;
00350     rv = parsePredicates(step, aLexer, aContext);
00351     if (NS_FAILED(rv)) {
00352         delete step;
00353         return rv;
00354     }
00355 
00356     aPattern = step;
00357     return NS_OK;
00358 }