LCOV - code coverage report
Current view: top level - dom/xslt/xpath - txExprLexer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 187 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 6 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; 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/. */
       5             : 
       6             : /**
       7             :  * Lexical analyzer for XPath expressions
       8             :  */
       9             : 
      10             : #include "txExprLexer.h"
      11             : #include "nsGkAtoms.h"
      12             : #include "nsString.h"
      13             : #include "nsError.h"
      14             : #include "txXMLUtils.h"
      15             : 
      16             : /**
      17             :  * Creates a new ExprLexer
      18             :  */
      19           0 : txExprLexer::txExprLexer()
      20             :   : mCurrentItem(nullptr),
      21             :     mFirstItem(nullptr),
      22             :     mLastItem(nullptr),
      23           0 :     mTokenCount(0)
      24             : {
      25           0 : }
      26             : 
      27             : /**
      28             :  * Destroys this instance of an txExprLexer
      29             :  */
      30           0 : txExprLexer::~txExprLexer()
      31             : {
      32             :   //-- delete tokens
      33           0 :   Token* tok = mFirstItem;
      34           0 :   while (tok) {
      35           0 :     Token* temp = tok->mNext;
      36             :     delete tok;
      37           0 :     tok = temp;
      38             :   }
      39           0 :   mCurrentItem = nullptr;
      40           0 : }
      41             : 
      42             : Token*
      43           0 : txExprLexer::nextToken()
      44             : {
      45           0 :   if (!mCurrentItem) {
      46           0 :     NS_NOTREACHED("nextToken called on uninitialized lexer");
      47           0 :     return nullptr;
      48             :   }
      49             : 
      50           0 :   if (mCurrentItem->mType == Token::END) {
      51             :     // Do not progress beyond the end token
      52           0 :     return mCurrentItem;
      53             :   }
      54             : 
      55           0 :   Token* token = mCurrentItem;
      56           0 :   mCurrentItem = mCurrentItem->mNext;
      57           0 :   return token;
      58             : }
      59             : 
      60             : void
      61           0 : txExprLexer::addToken(Token* aToken)
      62             : {
      63           0 :   if (mLastItem) {
      64           0 :     mLastItem->mNext = aToken;
      65             :   }
      66           0 :   if (!mFirstItem) {
      67           0 :     mFirstItem = aToken;
      68           0 :     mCurrentItem = aToken;
      69             :   }
      70           0 :   mLastItem = aToken;
      71           0 :   ++mTokenCount;
      72           0 : }
      73             : 
      74             : /**
      75             :  * Returns true if the following Token should be an operator.
      76             :  * This is a helper for the first bullet of [XPath 3.7]
      77             :  *  Lexical Structure
      78             :  */
      79             : bool
      80           0 : txExprLexer::nextIsOperatorToken(Token* aToken)
      81             : {
      82           0 :   if (!aToken || aToken->mType == Token::NULL_TOKEN) {
      83           0 :     return false;
      84             :   }
      85             :   /* This relies on the tokens having the right order in txExprLexer.h */
      86           0 :   return aToken->mType < Token::COMMA ||
      87           0 :     aToken->mType > Token::UNION_OP;
      88             : 
      89             : }
      90             : 
      91             : /**
      92             :  * Parses the given string into a sequence of Tokens
      93             :  */
      94             : nsresult
      95           0 : txExprLexer::parse(const nsAString& aPattern)
      96             : {
      97             :   iterator start, end;
      98           0 :   start = aPattern.BeginReading(mPosition);
      99           0 :   aPattern.EndReading(end);
     100             : 
     101             :   //-- initialize previous token, this will automatically get
     102             :   //-- deleted when it goes out of scope
     103           0 :   Token nullToken(nullptr, nullptr, Token::NULL_TOKEN);
     104             : 
     105             :   Token::Type defType;
     106           0 :   Token* newToken = nullptr;
     107           0 :   Token* prevToken = &nullToken;
     108             :   bool isToken;
     109             : 
     110           0 :   while (mPosition < end) {
     111             : 
     112           0 :     defType = Token::CNAME;
     113           0 :     isToken = true;
     114             : 
     115           0 :     if (*mPosition == DOLLAR_SIGN) {
     116           0 :       if (++mPosition == end || !XMLUtils::isLetter(*mPosition)) {
     117           0 :         return NS_ERROR_XPATH_INVALID_VAR_NAME;
     118             :       }
     119           0 :       defType = Token::VAR_REFERENCE;
     120             :     }
     121             :     // just reuse the QName parsing, which will use defType
     122             :     // the token to construct
     123             : 
     124           0 :     if (XMLUtils::isLetter(*mPosition)) {
     125             :       // NCName, can get QName or OperatorName;
     126             :       //  FunctionName, NodeName, and AxisSpecifier may want whitespace,
     127             :       //  and are dealt with below
     128           0 :       start = mPosition;
     129           0 :       while (++mPosition < end && XMLUtils::isNCNameChar(*mPosition)) {
     130             :         /* just go */
     131             :       }
     132           0 :       if (mPosition < end && *mPosition == COLON) {
     133             :         // try QName or wildcard, might need to step back for axis
     134           0 :         if (++mPosition == end) {
     135           0 :           return NS_ERROR_XPATH_UNEXPECTED_END;
     136             :         }
     137           0 :         if (XMLUtils::isLetter(*mPosition)) {
     138           0 :           while (++mPosition < end && XMLUtils::isNCNameChar(*mPosition)) {
     139             :             /* just go */
     140             :           }
     141             :         }
     142           0 :         else if (*mPosition == '*' && defType != Token::VAR_REFERENCE) {
     143             :           // eat wildcard for NameTest, bail for var ref at COLON
     144           0 :           ++mPosition;
     145             :         }
     146             :         else {
     147           0 :           --mPosition; // step back
     148             :         }
     149             :       }
     150           0 :       if (nextIsOperatorToken(prevToken)) {
     151           0 :         nsDependentSubstring op(Substring(start, mPosition));
     152           0 :         if (nsGkAtoms::_and->Equals(op)) {
     153           0 :           defType = Token::AND_OP;
     154             :         }
     155           0 :         else if (nsGkAtoms::_or->Equals(op)) {
     156           0 :           defType = Token::OR_OP;
     157             :         }
     158           0 :         else if (nsGkAtoms::mod->Equals(op)) {
     159           0 :           defType = Token::MODULUS_OP;
     160             :         }
     161           0 :         else if (nsGkAtoms::div->Equals(op)) {
     162           0 :           defType = Token::DIVIDE_OP;
     163             :         }
     164             :         else {
     165             :           // XXX QUESTION: spec is not too precise
     166             :           // badops is sure an error, but is bad:ops, too? We say yes!
     167           0 :           return NS_ERROR_XPATH_OPERATOR_EXPECTED;
     168             :         }
     169             :       }
     170           0 :       newToken = new Token(start, mPosition, defType);
     171             :     }
     172           0 :     else if (isXPathDigit(*mPosition)) {
     173           0 :       start = mPosition;
     174           0 :       while (++mPosition < end && isXPathDigit(*mPosition)) {
     175             :         /* just go */
     176             :       }
     177           0 :       if (mPosition < end && *mPosition == '.') {
     178           0 :         while (++mPosition < end && isXPathDigit(*mPosition)) {
     179             :           /* just go */
     180             :         }
     181             :       }
     182           0 :       newToken = new Token(start, mPosition, Token::NUMBER);
     183             :     }
     184             :     else {
     185           0 :       switch (*mPosition) {
     186             :         //-- ignore whitespace
     187             :       case SPACE:
     188             :       case TX_TAB:
     189             :       case TX_CR:
     190             :       case TX_LF:
     191           0 :         ++mPosition;
     192           0 :         isToken = false;
     193           0 :         break;
     194             :       case S_QUOTE :
     195             :       case D_QUOTE :
     196           0 :         start = mPosition;
     197           0 :         while (++mPosition < end && *mPosition != *start) {
     198             :           // eat literal
     199             :         }
     200           0 :         if (mPosition == end) {
     201           0 :           mPosition = start;
     202           0 :           return NS_ERROR_XPATH_UNCLOSED_LITERAL;
     203             :         }
     204           0 :         newToken = new Token(start + 1, mPosition, Token::LITERAL);
     205           0 :         ++mPosition;
     206           0 :         break;
     207             :       case PERIOD:
     208             :         // period can be .., .(DIGITS)+ or ., check next
     209           0 :         if (++mPosition == end) {
     210           0 :           newToken = new Token(mPosition - 1, Token::SELF_NODE);
     211             :         }
     212           0 :         else if (isXPathDigit(*mPosition)) {
     213           0 :           start = mPosition - 1;
     214           0 :           while (++mPosition < end && isXPathDigit(*mPosition)) {
     215             :             /* just go */
     216             :           }
     217           0 :           newToken = new Token(start, mPosition, Token::NUMBER);
     218             :         }
     219           0 :         else if (*mPosition == PERIOD) {
     220           0 :           ++mPosition;
     221           0 :           newToken = new Token(mPosition - 2, mPosition, Token::PARENT_NODE);
     222             :         }
     223             :         else {
     224           0 :           newToken = new Token(mPosition - 1, Token::SELF_NODE);
     225             :         }
     226           0 :         break;
     227             :       case COLON: // QNames are dealt above, must be axis ident
     228           0 :         if (++mPosition >= end || *mPosition != COLON ||
     229           0 :             prevToken->mType != Token::CNAME) {
     230           0 :           return NS_ERROR_XPATH_BAD_COLON;
     231             :         }
     232           0 :         prevToken->mType = Token::AXIS_IDENTIFIER;
     233           0 :         ++mPosition;
     234           0 :         isToken = false;
     235           0 :         break;
     236             :       case FORWARD_SLASH :
     237           0 :         if (++mPosition < end && *mPosition == FORWARD_SLASH) {
     238           0 :           ++mPosition;
     239           0 :           newToken = new Token(mPosition - 2, mPosition, Token::ANCESTOR_OP);
     240             :         }
     241             :         else {
     242           0 :           newToken = new Token(mPosition - 1, Token::PARENT_OP);
     243             :         }
     244           0 :         break;
     245             :       case BANG : // can only be !=
     246           0 :         if (++mPosition < end && *mPosition == EQUAL) {
     247           0 :           ++mPosition;
     248           0 :           newToken = new Token(mPosition - 2, mPosition, Token::NOT_EQUAL_OP);
     249           0 :           break;
     250             :         }
     251             :         // Error ! is not not()
     252           0 :         return NS_ERROR_XPATH_BAD_BANG;
     253             :       case EQUAL:
     254           0 :         newToken = new Token(mPosition, Token::EQUAL_OP);
     255           0 :         ++mPosition;
     256           0 :         break;
     257             :       case L_ANGLE:
     258           0 :         if (++mPosition == end) {
     259           0 :           return NS_ERROR_XPATH_UNEXPECTED_END;
     260             :         }
     261           0 :         if (*mPosition == EQUAL) {
     262           0 :           ++mPosition;
     263           0 :           newToken = new Token(mPosition - 2, mPosition,
     264           0 :                                Token::LESS_OR_EQUAL_OP);
     265             :         }
     266             :         else {
     267           0 :           newToken = new Token(mPosition - 1, Token::LESS_THAN_OP);
     268             :         }
     269           0 :         break;
     270             :       case R_ANGLE:
     271           0 :         if (++mPosition == end) {
     272           0 :           return NS_ERROR_XPATH_UNEXPECTED_END;
     273             :         }
     274           0 :         if (*mPosition == EQUAL) {
     275           0 :           ++mPosition;
     276           0 :           newToken = new Token(mPosition - 2, mPosition,
     277           0 :                                Token::GREATER_OR_EQUAL_OP);
     278             :         }
     279             :         else {
     280           0 :           newToken = new Token(mPosition - 1, Token::GREATER_THAN_OP);
     281             :         }
     282           0 :         break;
     283             :       case HYPHEN :
     284           0 :         newToken = new Token(mPosition, Token::SUBTRACTION_OP);
     285           0 :         ++mPosition;
     286           0 :         break;
     287             :       case ASTERISK:
     288           0 :         if (nextIsOperatorToken(prevToken)) {
     289           0 :           newToken = new Token(mPosition, Token::MULTIPLY_OP);
     290             :         }
     291             :         else {
     292           0 :           newToken = new Token(mPosition, Token::CNAME);
     293             :         }
     294           0 :         ++mPosition;
     295           0 :         break;
     296             :       case L_PAREN:
     297           0 :         if (prevToken->mType == Token::CNAME) {
     298           0 :           const nsDependentSubstring& val = prevToken->Value();
     299           0 :           if (val.EqualsLiteral("comment")) {
     300           0 :             prevToken->mType = Token::COMMENT_AND_PAREN;
     301             :           }
     302           0 :           else if (val.EqualsLiteral("node")) {
     303           0 :             prevToken->mType = Token::NODE_AND_PAREN;
     304             :           }
     305           0 :           else if (val.EqualsLiteral("processing-instruction")) {
     306           0 :             prevToken->mType = Token::PROC_INST_AND_PAREN;
     307             :           }
     308           0 :           else if (val.EqualsLiteral("text")) {
     309           0 :             prevToken->mType = Token::TEXT_AND_PAREN;
     310             :           }
     311             :           else {
     312           0 :             prevToken->mType = Token::FUNCTION_NAME_AND_PAREN;
     313             :           }
     314           0 :           isToken = false;
     315             :         }
     316             :         else {
     317           0 :           newToken = new Token(mPosition, Token::L_PAREN);
     318             :         }
     319           0 :         ++mPosition;
     320           0 :         break;
     321             :       case R_PAREN:
     322           0 :         newToken = new Token(mPosition, Token::R_PAREN);
     323           0 :         ++mPosition;
     324           0 :         break;
     325             :       case L_BRACKET:
     326           0 :         newToken = new Token(mPosition, Token::L_BRACKET);
     327           0 :         ++mPosition;
     328           0 :         break;
     329             :       case R_BRACKET:
     330           0 :         newToken = new Token(mPosition, Token::R_BRACKET);
     331           0 :         ++mPosition;
     332           0 :         break;
     333             :       case COMMA:
     334           0 :         newToken = new Token(mPosition, Token::COMMA);
     335           0 :         ++mPosition;
     336           0 :         break;
     337             :       case AT_SIGN :
     338           0 :         newToken = new Token(mPosition, Token::AT_SIGN);
     339           0 :         ++mPosition;
     340           0 :         break;
     341             :       case PLUS:
     342           0 :         newToken = new Token(mPosition, Token::ADDITION_OP);
     343           0 :         ++mPosition;
     344           0 :         break;
     345             :       case VERT_BAR:
     346           0 :         newToken = new Token(mPosition, Token::UNION_OP);
     347           0 :         ++mPosition;
     348           0 :         break;
     349             :       default:
     350             :         // Error, don't grok character :-(
     351           0 :         return NS_ERROR_XPATH_ILLEGAL_CHAR;
     352             :       }
     353             :     }
     354           0 :     if (isToken) {
     355           0 :       NS_ENSURE_TRUE(newToken, NS_ERROR_OUT_OF_MEMORY);
     356           0 :       NS_ENSURE_TRUE(newToken != mLastItem, NS_ERROR_FAILURE);
     357           0 :       prevToken = newToken;
     358           0 :       addToken(newToken);
     359             :     }
     360             :   }
     361             : 
     362             :   // add a endToken to the list
     363           0 :   newToken = new Token(end, end, Token::END);
     364           0 :   addToken(newToken);
     365             : 
     366           0 :   return NS_OK;
     367             : }

Generated by: LCOV version 1.13