LCOV - code coverage report
Current view: directory - content/xslt/src/xpath - txExprLexer.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 185 53 28.6 %
Date: 2012-06-02 Functions: 7 6 85.7 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is TransforMiiX XSLT processor code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * The MITRE Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1999
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Keith Visco <kvisco@ziplink.net> (Original Author)
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : /**
      40                 :  * Lexical analyzer for XPath expressions
      41                 :  */
      42                 : 
      43                 : #include "txExprLexer.h"
      44                 : #include "nsGkAtoms.h"
      45                 : #include "nsString.h"
      46                 : #include "txError.h"
      47                 : #include "txXMLUtils.h"
      48                 : 
      49                 : /**
      50                 :  * Creates a new ExprLexer
      51                 :  */
      52              42 : txExprLexer::txExprLexer()
      53                 :   : mCurrentItem(nsnull),
      54                 :     mFirstItem(nsnull),
      55                 :     mLastItem(nsnull),
      56              42 :     mTokenCount(0)
      57                 : {
      58              42 : }
      59                 : 
      60                 : /**
      61                 :  * Destroys this instance of an txExprLexer
      62                 :  */
      63              42 : txExprLexer::~txExprLexer()
      64                 : {
      65                 :   //-- delete tokens
      66              42 :   Token* tok = mFirstItem;
      67             168 :   while (tok) {
      68              84 :     Token* temp = tok->mNext;
      69                 :     delete tok;
      70              84 :     tok = temp;
      71                 :   }
      72              42 :   mCurrentItem = nsnull;
      73              42 : }
      74                 : 
      75                 : Token*
      76             126 : txExprLexer::nextToken()
      77                 : {
      78             126 :   NS_ASSERTION(mCurrentItem, "nextToken called beyoned the end");
      79             126 :   Token* token = mCurrentItem;
      80             126 :   mCurrentItem = mCurrentItem->mNext;
      81             126 :   return token;
      82                 : }
      83                 : 
      84                 : void
      85              84 : txExprLexer::pushBack()
      86                 : {
      87              84 :   mCurrentItem = mCurrentItem ? mCurrentItem->mPrevious : mLastItem;
      88              84 : }
      89                 : 
      90                 : void
      91              84 : txExprLexer::addToken(Token* aToken)
      92                 : {
      93              84 :   if (mLastItem) {
      94              42 :     aToken->mPrevious = mLastItem;
      95              42 :     mLastItem->mNext = aToken;
      96                 :   }
      97              84 :   if (!mFirstItem) {
      98              42 :     mFirstItem = aToken;
      99              42 :     mCurrentItem = aToken;
     100                 :   }
     101              84 :   mLastItem = aToken;
     102              84 :   ++mTokenCount;
     103              84 : }
     104                 : 
     105                 : /**
     106                 :  * Returns true if the following Token should be an operator.
     107                 :  * This is a helper for the first bullet of [XPath 3.7]
     108                 :  *  Lexical Structure
     109                 :  */
     110                 : bool
     111               0 : txExprLexer::nextIsOperatorToken(Token* aToken)
     112                 : {
     113               0 :   if (!aToken || aToken->mType == Token::NULL_TOKEN) {
     114               0 :     return false;
     115                 :   }
     116                 :   /* This relies on the tokens having the right order in txExprLexer.h */
     117                 :   return aToken->mType < Token::COMMA ||
     118               0 :     aToken->mType > Token::UNION_OP;
     119                 : 
     120                 : }
     121                 : 
     122                 : /**
     123                 :  * Parses the given string into a sequence of Tokens
     124                 :  */
     125                 : nsresult
     126              42 : txExprLexer::parse(const nsASingleFragmentString& aPattern)
     127                 : {
     128                 :   iterator start, end;
     129              42 :   start = aPattern.BeginReading(mPosition);
     130              42 :   aPattern.EndReading(end);
     131                 : 
     132                 :   //-- initialize previous token, this will automatically get
     133                 :   //-- deleted when it goes out of scope
     134              42 :   Token nullToken(nsnull, nsnull, Token::NULL_TOKEN);
     135                 : 
     136                 :   Token::Type defType;
     137              42 :   Token* newToken = nsnull;
     138              42 :   Token* prevToken = &nullToken;
     139                 :   bool isToken;
     140                 : 
     141             126 :   while (mPosition < end) {
     142                 : 
     143              42 :     defType = Token::CNAME;
     144              42 :     isToken = true;
     145                 : 
     146              42 :     if (*mPosition == DOLLAR_SIGN) {
     147               0 :       if (++mPosition == end || !XMLUtils::isLetter(*mPosition)) {
     148               0 :         return NS_ERROR_XPATH_INVALID_VAR_NAME;
     149                 :       }
     150               0 :       defType = Token::VAR_REFERENCE;
     151                 :     } 
     152                 :     // just reuse the QName parsing, which will use defType 
     153                 :     // the token to construct
     154                 : 
     155              42 :     if (XMLUtils::isLetter(*mPosition)) {
     156                 :       // NCName, can get QName or OperatorName;
     157                 :       //  FunctionName, NodeName, and AxisSpecifier may want whitespace,
     158                 :       //  and are dealt with below
     159               0 :       start = mPosition;
     160               0 :       while (++mPosition < end && XMLUtils::isNCNameChar(*mPosition)) {
     161                 :         /* just go */
     162                 :       }
     163               0 :       if (mPosition < end && *mPosition == COLON) {
     164                 :         // try QName or wildcard, might need to step back for axis
     165               0 :         if (++mPosition == end) {
     166               0 :           return NS_ERROR_XPATH_UNEXPECTED_END;
     167                 :         }
     168               0 :         if (XMLUtils::isLetter(*mPosition)) {
     169               0 :           while (++mPosition < end && XMLUtils::isNCNameChar(*mPosition)) {
     170                 :             /* just go */
     171                 :           }
     172                 :         }
     173               0 :         else if (*mPosition == '*' && defType != Token::VAR_REFERENCE) {
     174                 :           // eat wildcard for NameTest, bail for var ref at COLON
     175               0 :           ++mPosition;
     176                 :         }
     177                 :         else {
     178               0 :           --mPosition; // step back
     179                 :         }
     180                 :       }
     181               0 :       if (nextIsOperatorToken(prevToken)) {
     182               0 :         nsDependentSubstring op(Substring(start, mPosition));
     183               0 :         if (nsGkAtoms::_and->Equals(op)) {
     184               0 :           defType = Token::AND_OP;
     185                 :         }
     186               0 :         else if (nsGkAtoms::_or->Equals(op)) {
     187               0 :           defType = Token::OR_OP;
     188                 :         }
     189               0 :         else if (nsGkAtoms::mod->Equals(op)) {
     190               0 :           defType = Token::MODULUS_OP;
     191                 :         }
     192               0 :         else if (nsGkAtoms::div->Equals(op)) {
     193               0 :           defType = Token::DIVIDE_OP;
     194                 :         }
     195                 :         else {
     196                 :           // XXX QUESTION: spec is not too precise
     197                 :           // badops is sure an error, but is bad:ops, too? We say yes!
     198               0 :           return NS_ERROR_XPATH_OPERATOR_EXPECTED;
     199                 :         }
     200                 :       }
     201               0 :       newToken = new Token(start, mPosition, defType);
     202                 :     }
     203              42 :     else if (isXPathDigit(*mPosition)) {
     204               0 :       start = mPosition;
     205               0 :       while (++mPosition < end && isXPathDigit(*mPosition)) {
     206                 :         /* just go */
     207                 :       }
     208               0 :       if (mPosition < end && *mPosition == '.') {
     209               0 :         while (++mPosition < end && isXPathDigit(*mPosition)) {
     210                 :           /* just go */
     211                 :         }
     212                 :       }
     213               0 :       newToken = new Token(start, mPosition, Token::NUMBER);
     214                 :     }
     215                 :     else {
     216              42 :       switch (*mPosition) {
     217                 :         //-- ignore whitespace
     218                 :       case SPACE:
     219                 :       case TX_TAB:
     220                 :       case TX_CR:
     221                 :       case TX_LF:
     222               0 :         ++mPosition;
     223               0 :         isToken = false;
     224               0 :         break;
     225                 :       case S_QUOTE :
     226                 :       case D_QUOTE :
     227               0 :         start = mPosition;
     228               0 :         while (++mPosition < end && *mPosition != *start) {
     229                 :           // eat literal
     230                 :         }
     231               0 :         if (mPosition == end) {
     232               0 :           mPosition = start;
     233               0 :           return NS_ERROR_XPATH_UNCLOSED_LITERAL;
     234                 :         }
     235               0 :         newToken = new Token(start + 1, mPosition, Token::LITERAL);
     236               0 :         ++mPosition;
     237               0 :         break;
     238                 :       case PERIOD:
     239                 :         // period can be .., .(DIGITS)+ or ., check next
     240              42 :         if (++mPosition == end) {
     241              42 :           newToken = new Token(mPosition - 1, Token::SELF_NODE);
     242                 :         }
     243               0 :         else if (isXPathDigit(*mPosition)) {
     244               0 :           start = mPosition - 1;
     245               0 :           while (++mPosition < end && isXPathDigit(*mPosition)) {
     246                 :             /* just go */
     247                 :           }
     248               0 :           newToken = new Token(start, mPosition, Token::NUMBER);
     249                 :         }
     250               0 :         else if (*mPosition == PERIOD) {
     251               0 :           ++mPosition;
     252               0 :           newToken = new Token(mPosition - 2, mPosition, Token::PARENT_NODE);
     253                 :         }
     254                 :         else {
     255               0 :           newToken = new Token(mPosition - 1, Token::SELF_NODE);
     256                 :         }
     257              42 :         break;
     258                 :       case COLON: // QNames are dealt above, must be axis ident
     259               0 :         if (++mPosition >= end || *mPosition != COLON ||
     260                 :             prevToken->mType != Token::CNAME) {
     261               0 :           return NS_ERROR_XPATH_BAD_COLON;
     262                 :         }
     263               0 :         prevToken->mType = Token::AXIS_IDENTIFIER;
     264               0 :         ++mPosition;
     265               0 :         isToken = false;
     266               0 :         break;
     267                 :       case FORWARD_SLASH :
     268               0 :         if (++mPosition < end && *mPosition == FORWARD_SLASH) {
     269               0 :           ++mPosition;
     270               0 :           newToken = new Token(mPosition - 2, mPosition, Token::ANCESTOR_OP);
     271                 :         }
     272                 :         else {
     273               0 :           newToken = new Token(mPosition - 1, Token::PARENT_OP);
     274                 :         }
     275               0 :         break;
     276                 :       case BANG : // can only be !=
     277               0 :         if (++mPosition < end && *mPosition == EQUAL) {
     278               0 :           ++mPosition;
     279               0 :           newToken = new Token(mPosition - 2, mPosition, Token::NOT_EQUAL_OP);
     280               0 :           break;
     281                 :         }
     282                 :         // Error ! is not not()
     283               0 :         return NS_ERROR_XPATH_BAD_BANG;
     284                 :       case EQUAL:
     285               0 :         newToken = new Token(mPosition, Token::EQUAL_OP);
     286               0 :         ++mPosition;
     287               0 :         break;
     288                 :       case L_ANGLE:
     289               0 :         if (++mPosition == end) {
     290               0 :           return NS_ERROR_XPATH_UNEXPECTED_END;
     291                 :         }
     292               0 :         if (*mPosition == EQUAL) {
     293               0 :           ++mPosition;
     294                 :           newToken = new Token(mPosition - 2, mPosition,
     295               0 :                                Token::LESS_OR_EQUAL_OP);
     296                 :         }
     297                 :         else {
     298               0 :           newToken = new Token(mPosition - 1, Token::LESS_THAN_OP);
     299                 :         }
     300               0 :         break;
     301                 :       case R_ANGLE:
     302               0 :         if (++mPosition == end) {
     303               0 :           return NS_ERROR_XPATH_UNEXPECTED_END;
     304                 :         }
     305               0 :         if (*mPosition == EQUAL) {
     306               0 :           ++mPosition;
     307                 :           newToken = new Token(mPosition - 2, mPosition,
     308               0 :                                Token::GREATER_OR_EQUAL_OP);
     309                 :         }
     310                 :         else {
     311               0 :           newToken = new Token(mPosition - 1, Token::GREATER_THAN_OP);
     312                 :         }
     313               0 :         break;
     314                 :       case HYPHEN :
     315               0 :         newToken = new Token(mPosition, Token::SUBTRACTION_OP);
     316               0 :         ++mPosition;
     317               0 :         break;
     318                 :       case ASTERIX:
     319               0 :         if (nextIsOperatorToken(prevToken)) {
     320               0 :           newToken = new Token(mPosition, Token::MULTIPLY_OP);
     321                 :         }
     322                 :         else {
     323               0 :           newToken = new Token(mPosition, Token::CNAME);
     324                 :         }
     325               0 :         ++mPosition;
     326               0 :         break;
     327                 :       case L_PAREN:
     328               0 :         if (prevToken->mType == Token::CNAME) {
     329               0 :           const nsDependentSubstring& val = prevToken->Value();
     330               0 :           if (val.EqualsLiteral("comment")) {
     331               0 :             prevToken->mType = Token::COMMENT_AND_PAREN;
     332                 :           }
     333               0 :           else if (val.EqualsLiteral("node")) {
     334               0 :             prevToken->mType = Token::NODE_AND_PAREN;
     335                 :           }
     336               0 :           else if (val.EqualsLiteral("processing-instruction")) {
     337               0 :             prevToken->mType = Token::PROC_INST_AND_PAREN;
     338                 :           }
     339               0 :           else if (val.EqualsLiteral("text")) {
     340               0 :             prevToken->mType = Token::TEXT_AND_PAREN;
     341                 :           }
     342                 :           else {
     343               0 :             prevToken->mType = Token::FUNCTION_NAME_AND_PAREN;
     344                 :           }
     345               0 :           isToken = false;
     346                 :         }
     347                 :         else {
     348               0 :           newToken = new Token(mPosition, Token::L_PAREN);
     349                 :         }
     350               0 :         ++mPosition;
     351               0 :         break;
     352                 :       case R_PAREN:
     353               0 :         newToken = new Token(mPosition, Token::R_PAREN);
     354               0 :         ++mPosition;
     355               0 :         break;
     356                 :       case L_BRACKET:
     357               0 :         newToken = new Token(mPosition, Token::L_BRACKET);
     358               0 :         ++mPosition;
     359               0 :         break;
     360                 :       case R_BRACKET:
     361               0 :         newToken = new Token(mPosition, Token::R_BRACKET);
     362               0 :         ++mPosition;
     363               0 :         break;
     364                 :       case COMMA:
     365               0 :         newToken = new Token(mPosition, Token::COMMA);
     366               0 :         ++mPosition;
     367               0 :         break;
     368                 :       case AT_SIGN :
     369               0 :         newToken = new Token(mPosition, Token::AT_SIGN);
     370               0 :         ++mPosition;
     371               0 :         break;
     372                 :       case PLUS:
     373               0 :         newToken = new Token(mPosition, Token::ADDITION_OP);
     374               0 :         ++mPosition;
     375               0 :         break;
     376                 :       case VERT_BAR:
     377               0 :         newToken = new Token(mPosition, Token::UNION_OP);
     378               0 :         ++mPosition;
     379               0 :         break;
     380                 :       default:
     381                 :         // Error, don't grok character :-(
     382               0 :         return NS_ERROR_XPATH_ILLEGAL_CHAR;
     383                 :       }
     384                 :     }
     385              42 :     if (isToken) {
     386              42 :       NS_ENSURE_TRUE(newToken, NS_ERROR_OUT_OF_MEMORY);
     387              42 :       NS_ENSURE_TRUE(newToken != mLastItem, NS_ERROR_FAILURE);
     388              42 :       prevToken = newToken;
     389              42 :       addToken(newToken);
     390                 :     }
     391                 :   }
     392                 : 
     393                 :   // add a endToken to the list
     394              42 :   newToken = new Token(end, end, Token::END);
     395              42 :   if (!newToken) {
     396               0 :     return NS_ERROR_OUT_OF_MEMORY;
     397                 :   }
     398              42 :   addToken(newToken);
     399                 : 
     400              42 :   return NS_OK;
     401                 : }

Generated by: LCOV version 1.7