LCOV - code coverage report
Current view: top level - xpcom/ds - Tokenizer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 197 374 52.7 %
Date: 2017-07-14 16:53:18 Functions: 31 49 63.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "Tokenizer.h"
       8             : 
       9             : #include "nsUnicharUtils.h"
      10             : #include <algorithm>
      11             : 
      12             : namespace mozilla {
      13             : 
      14             : static const char sWhitespaces[] = " \t";
      15             : 
      16        7105 : Tokenizer::Tokenizer(const nsACString& aSource,
      17             :                      const char* aWhitespaces,
      18        7105 :                      const char* aAdditionalWordChars)
      19        7105 :   : TokenizerBase(aWhitespaces, aAdditionalWordChars)
      20             : {
      21        7105 :   mInputFinished = true;
      22        7105 :   aSource.BeginReading(mCursor);
      23        7105 :   mRecord = mRollback = mCursor;
      24        7105 :   aSource.EndReading(mEnd);
      25        7105 : }
      26             : 
      27           2 : Tokenizer::Tokenizer(const char* aSource,
      28             :                      const char* aWhitespaces,
      29           2 :                      const char* aAdditionalWordChars)
      30           2 :   : Tokenizer(nsDependentCString(aSource), aWhitespaces, aAdditionalWordChars)
      31             : {
      32           2 : }
      33             : 
      34             : bool
      35          22 : Tokenizer::Next(Token& aToken)
      36             : {
      37          22 :   if (!HasInput()) {
      38           0 :     mHasFailed = true;
      39           0 :     return false;
      40             :   }
      41             : 
      42          22 :   mRollback = mCursor;
      43          22 :   mCursor = Parse(aToken);
      44             : 
      45          22 :   AssignFragment(aToken, mRollback, mCursor);
      46             : 
      47          22 :   mPastEof = aToken.Type() == TOKEN_EOF;
      48          22 :   mHasFailed = false;
      49          22 :   return true;
      50             : }
      51             : 
      52             : bool
      53          16 : Tokenizer::Check(const TokenType aTokenType, Token& aResult)
      54             : {
      55          16 :   if (!HasInput()) {
      56           0 :     mHasFailed = true;
      57           0 :     return false;
      58             :   }
      59             : 
      60          16 :   nsACString::const_char_iterator next = Parse(aResult);
      61          16 :   if (aTokenType != aResult.Type()) {
      62          16 :     mHasFailed = true;
      63          16 :     return false;
      64             :   }
      65             : 
      66           0 :   mRollback = mCursor;
      67           0 :   mCursor = next;
      68             : 
      69           0 :   AssignFragment(aResult, mRollback, mCursor);
      70             : 
      71           0 :   mPastEof = aResult.Type() == TOKEN_EOF;
      72           0 :   mHasFailed = false;
      73           0 :   return true;
      74             : }
      75             : 
      76             : bool
      77       15018 : Tokenizer::Check(const Token& aToken)
      78             : {
      79       15018 :   if (!HasInput()) {
      80           0 :     mHasFailed = true;
      81           0 :     return false;
      82             :   }
      83             : 
      84       30036 :   Token parsed;
      85       15018 :   nsACString::const_char_iterator next = Parse(parsed);
      86       15018 :   if (!aToken.Equals(parsed)) {
      87        8071 :     mHasFailed = true;
      88        8071 :     return false;
      89             :   }
      90             : 
      91        6947 :   mRollback = mCursor;
      92        6947 :   mCursor = next;
      93        6947 :   mPastEof = parsed.Type() == TOKEN_EOF;
      94        6947 :   mHasFailed = false;
      95        6947 :   return true;
      96             : }
      97             : 
      98             : void
      99         472 : Tokenizer::SkipWhites(WhiteSkipping aIncludeNewLines)
     100             : {
     101         472 :   if (!CheckWhite() && (aIncludeNewLines == DONT_INCLUDE_NEW_LINE || !CheckEOL())) {
     102         471 :     return;
     103             :   }
     104             : 
     105           1 :   nsACString::const_char_iterator rollback = mRollback;
     106           1 :   while (CheckWhite() || (aIncludeNewLines == INCLUDE_NEW_LINE && CheckEOL())) {
     107             :   }
     108             : 
     109           1 :   mHasFailed = false;
     110           1 :   mRollback = rollback;
     111             : }
     112             : 
     113             : void
     114           0 : Tokenizer::SkipUntil(Token const& aToken)
     115             : {
     116           0 :   nsACString::const_char_iterator rollback = mCursor;
     117           0 :   const Token eof = Token::EndOfFile();
     118             : 
     119           0 :   Token t;
     120           0 :   while (Next(t)) {
     121           0 :     if (aToken.Equals(t) || eof.Equals(t)) {
     122           0 :       Rollback();
     123           0 :       break;
     124             :     }
     125             :   }
     126             : 
     127           0 :   mRollback = rollback;
     128           0 : }
     129             : 
     130             : bool
     131       45747 : Tokenizer::CheckChar(bool (*aClassifier)(const char aChar))
     132             : {
     133       45747 :   if (!aClassifier) {
     134           0 :     MOZ_ASSERT(false);
     135             :     return false;
     136             :   }
     137             : 
     138       45747 :   if (!HasInput() || mCursor == mEnd) {
     139         258 :     mHasFailed = true;
     140         258 :     return false;
     141             :   }
     142             : 
     143       45489 :   if (!aClassifier(*mCursor)) {
     144        6806 :     mHasFailed = true;
     145        6806 :     return false;
     146             :   }
     147             : 
     148       38683 :   mRollback = mCursor;
     149       38683 :   ++mCursor;
     150       38683 :   mHasFailed = false;
     151       38683 :   return true;
     152             : }
     153             : 
     154             : bool
     155           0 : Tokenizer::ReadChar(char* aValue)
     156             : {
     157           0 :   MOZ_RELEASE_ASSERT(aValue);
     158             : 
     159           0 :   Token t;
     160           0 :   if (!Check(TOKEN_CHAR, t)) {
     161           0 :     return false;
     162             :   }
     163             : 
     164           0 :   *aValue = t.AsChar();
     165           0 :   return true;
     166             : }
     167             : 
     168             : bool
     169           6 : Tokenizer::ReadChar(bool (*aClassifier)(const char aChar), char* aValue)
     170             : {
     171           6 :   MOZ_RELEASE_ASSERT(aValue);
     172             : 
     173           6 :   if (!CheckChar(aClassifier)) {
     174           0 :     return false;
     175             :   }
     176             : 
     177           6 :   *aValue = *mRollback;
     178           6 :   return true;
     179             : }
     180             : 
     181             : bool
     182           0 : Tokenizer::ReadWord(nsACString& aValue)
     183             : {
     184           0 :   Token t;
     185           0 :   if (!Check(TOKEN_WORD, t)) {
     186           0 :     return false;
     187             :   }
     188             : 
     189           0 :   aValue.Assign(t.AsString());
     190           0 :   return true;
     191             : }
     192             : 
     193             : bool
     194           0 : Tokenizer::ReadWord(nsDependentCSubstring& aValue)
     195             : {
     196           0 :   Token t;
     197           0 :   if (!Check(TOKEN_WORD, t)) {
     198           0 :     return false;
     199             :   }
     200             : 
     201           0 :   aValue.Rebind(t.AsString().BeginReading(), t.AsString().Length());
     202           0 :   return true;
     203             : }
     204             : 
     205             : bool
     206           0 : Tokenizer::ReadUntil(Token const& aToken, nsACString& aResult, ClaimInclusion aInclude)
     207             : {
     208           0 :   nsDependentCSubstring substring;
     209           0 :   bool rv = ReadUntil(aToken, substring, aInclude);
     210           0 :   aResult.Assign(substring);
     211           0 :   return rv;
     212             : }
     213             : 
     214             : bool
     215           0 : Tokenizer::ReadUntil(Token const& aToken, nsDependentCSubstring& aResult, ClaimInclusion aInclude)
     216             : {
     217           0 :   nsACString::const_char_iterator record = mRecord;
     218           0 :   Record();
     219           0 :   nsACString::const_char_iterator rollback = mRollback = mCursor;
     220             : 
     221           0 :   bool found = false;
     222           0 :   Token t;
     223           0 :   while (Next(t)) {
     224           0 :     if (aToken.Equals(t)) {
     225           0 :       found = true;
     226           0 :       break;
     227             :     }
     228           0 :     if (t.Equals(Token::EndOfFile())) {
     229             :       // We don't want to eat it.
     230           0 :       Rollback();
     231           0 :       break;
     232             :     }
     233             :   }
     234             : 
     235           0 :   Claim(aResult, aInclude);
     236           0 :   mRollback = rollback;
     237           0 :   mRecord = record;
     238           0 :   return found;
     239             : }
     240             : 
     241             : void
     242           1 : Tokenizer::Rollback()
     243             : {
     244           1 :   MOZ_ASSERT(mCursor > mRollback || mPastEof,
     245             :              "Tokenizer::Rollback() cannot use twice or before any parsing");
     246             : 
     247           1 :   mPastEof = false;
     248           1 :   mHasFailed = false;
     249           1 :   mCursor = mRollback;
     250           1 : }
     251             : 
     252             : void
     253        6553 : Tokenizer::Record(ClaimInclusion aInclude)
     254             : {
     255        6553 :   mRecord = aInclude == INCLUDE_LAST
     256        6553 :     ? mRollback
     257             :     : mCursor;
     258        6553 : }
     259             : 
     260             : void
     261        6245 : Tokenizer::Claim(nsACString& aResult, ClaimInclusion aInclusion)
     262             : {
     263             :   nsACString::const_char_iterator close = aInclusion == EXCLUDE_LAST
     264        6245 :     ? mRollback
     265        6245 :     : mCursor;
     266        6245 :   aResult.Assign(Substring(mRecord, close));
     267        6245 : }
     268             : 
     269             : void
     270           0 : Tokenizer::Claim(nsDependentCSubstring& aResult, ClaimInclusion aInclusion)
     271             : {
     272             :   nsACString::const_char_iterator close = aInclusion == EXCLUDE_LAST
     273           0 :     ? mRollback
     274           0 :     : mCursor;
     275             : 
     276           0 :   MOZ_RELEASE_ASSERT(close >= mRecord, "Overflow!");
     277           0 :   aResult.Rebind(mRecord, close - mRecord);
     278           0 : }
     279             : 
     280             : // TokenizerBase
     281             : 
     282        7105 : TokenizerBase::TokenizerBase(const char* aWhitespaces,
     283        7105 :                              const char* aAdditionalWordChars)
     284             :   : mPastEof(false)
     285             :   , mHasFailed(false)
     286             :   , mInputFinished(true)
     287             :   , mMode(Mode::FULL)
     288             :   , mMinRawDelivery(1024)
     289        7105 :   , mWhitespaces(aWhitespaces ? aWhitespaces : sWhitespaces)
     290             :   , mAdditionalWordChars(aAdditionalWordChars)
     291             :   , mCursor(nullptr)
     292             :   , mEnd(nullptr)
     293       14210 :   , mNextCustomTokenID(TOKEN_CUSTOM0)
     294             : {
     295        7105 : }
     296             : 
     297             : TokenizerBase::Token
     298           0 : TokenizerBase::AddCustomToken(const nsACString & aValue,
     299             :                               ECaseSensitivity aCaseInsensitivity, bool aEnabled)
     300             : {
     301           0 :   MOZ_ASSERT(!aValue.IsEmpty());
     302             : 
     303           0 :   UniquePtr<Token>& t = *mCustomTokens.AppendElement();
     304           0 :   t = MakeUnique<Token>();
     305             : 
     306           0 :   t->mType = static_cast<TokenType>(++mNextCustomTokenID);
     307           0 :   t->mCustomCaseInsensitivity = aCaseInsensitivity;
     308           0 :   t->mCustomEnabled = aEnabled;
     309           0 :   t->mCustom.Assign(aValue);
     310           0 :   return *t;
     311             : }
     312             : 
     313             : void
     314           0 : TokenizerBase::RemoveCustomToken(Token& aToken)
     315             : {
     316           0 :   if (aToken.mType == TOKEN_UNKNOWN) {
     317             :     // Already removed
     318           0 :     return;
     319             :   }
     320             : 
     321           0 :   for (UniquePtr<Token> const& custom : mCustomTokens) {
     322           0 :     if (custom->mType == aToken.mType) {
     323           0 :       mCustomTokens.RemoveElement(custom);
     324           0 :       aToken.mType = TOKEN_UNKNOWN;
     325           0 :       return;
     326             :     }
     327             :   }
     328             : 
     329           0 :   MOZ_ASSERT(false, "Token to remove not found");
     330             : }
     331             : 
     332             : void
     333           0 : TokenizerBase::EnableCustomToken(Token const& aToken, bool aEnabled)
     334             : {
     335           0 :   if (aToken.mType == TOKEN_UNKNOWN) {
     336             :     // Already removed
     337           0 :     return;
     338             :   }
     339             : 
     340           0 :   for (UniquePtr<Token> const& custom : mCustomTokens) {
     341           0 :     if (custom->Type() == aToken.Type()) {
     342             :       // This effectively destroys the token instance.
     343           0 :       custom->mCustomEnabled = aEnabled;
     344           0 :       return;
     345             :     }
     346             :   }
     347             : 
     348           0 :   MOZ_ASSERT(false, "Token to change not found");
     349             : }
     350             : 
     351             : void
     352           0 : TokenizerBase::SetTokenizingMode(Mode aMode)
     353             : {
     354           0 :   mMode = aMode;
     355           0 : }
     356             : 
     357             : bool
     358           0 : TokenizerBase::HasFailed() const
     359             : {
     360           0 :   return mHasFailed;
     361             : }
     362             : 
     363             : bool
     364       60803 : TokenizerBase::HasInput() const
     365             : {
     366       60803 :   return !mPastEof;
     367             : }
     368             : 
     369             : nsACString::const_char_iterator
     370       15056 : TokenizerBase::Parse(Token& aToken) const
     371             : {
     372       15056 :   if (mCursor == mEnd) {
     373         555 :     if (!mInputFinished) {
     374           0 :       return mCursor;
     375             :     }
     376             : 
     377         555 :     aToken = Token::EndOfFile();
     378         555 :     return mEnd;
     379             :   }
     380             : 
     381       14501 :   MOZ_RELEASE_ASSERT(mEnd >= mCursor, "Overflow!");
     382       14501 :   nsACString::size_type available = mEnd - mCursor;
     383             : 
     384       14501 :   uint32_t longestCustom = 0;
     385       14501 :   for (UniquePtr<Token> const& custom : mCustomTokens) {
     386           0 :     if (IsCustom(mCursor, *custom, &longestCustom)) {
     387           0 :       aToken = *custom;
     388           0 :       return mCursor + custom->mCustom.Length();
     389             :     }
     390             :   }
     391             : 
     392       14501 :   if (!mInputFinished && available < longestCustom) {
     393             :     // Not enough data to deterministically decide.
     394           0 :     return mCursor;
     395             :   }
     396             : 
     397       14501 :   nsACString::const_char_iterator next = mCursor;
     398             : 
     399       14501 :   if (mMode == Mode::CUSTOM_ONLY) {
     400             :     // We have to do a brute-force search for all of the enabled custom
     401             :     // tokens.
     402           0 :     while (next < mEnd) {
     403           0 :       ++next;
     404           0 :       for (UniquePtr<Token> const& custom : mCustomTokens) {
     405           0 :         if (IsCustom(next, *custom)) {
     406           0 :           aToken = Token::Raw();
     407           0 :           return next;
     408             :         }
     409             :       }
     410             :     }
     411             : 
     412           0 :     if (mInputFinished) {
     413             :       // End of the data reached.
     414           0 :       aToken = Token::Raw();
     415           0 :       return next;
     416             :     }
     417             : 
     418           0 :     if (longestCustom < available && available > mMinRawDelivery) {
     419             :       // We can return some data w/o waiting for either a custom token
     420             :       // or call to FinishData() when we leave the tail where all the
     421             :       // custom tokens potentially fit, so we can't lose only partially
     422             :       // delivered tokens.  This preserves reasonable granularity.
     423           0 :       aToken = Token::Raw();
     424           0 :       return mEnd - longestCustom + 1;
     425             :     }
     426             : 
     427             :     // Not enough data to deterministically decide.
     428           0 :     return mCursor;
     429             :   }
     430             : 
     431             :   enum State {
     432             :     PARSE_INTEGER,
     433             :     PARSE_WORD,
     434             :     PARSE_CRLF,
     435             :     PARSE_LF,
     436             :     PARSE_WS,
     437             :     PARSE_CHAR,
     438             :   } state;
     439             : 
     440       14501 :   if (IsWordFirst(*next)) {
     441           6 :     state = PARSE_WORD;
     442       14495 :   } else if (IsNumber(*next)) {
     443          13 :     state = PARSE_INTEGER;
     444       14482 :   } else if (strchr(mWhitespaces, *next)) { // not UTF-8 friendly?
     445           2 :     state = PARSE_WS;
     446       14480 :   } else if (*next == '\r') {
     447           0 :     state = PARSE_CRLF;
     448       14480 :   } else if (*next == '\n') {
     449           0 :     state = PARSE_LF;
     450             :   } else {
     451       14480 :     state = PARSE_CHAR;
     452             :   }
     453             : 
     454       14501 :   mozilla::CheckedUint64 resultingNumber = 0;
     455             : 
     456       14627 :   while (next < mEnd) {
     457       14564 :     switch (state) {
     458             :     case PARSE_INTEGER:
     459             :       // Keep it simple for now
     460          31 :       resultingNumber *= 10;
     461          31 :       resultingNumber += static_cast<uint64_t>(*next - '0');
     462             : 
     463          31 :       ++next;
     464          31 :       if (IsPending(next)) {
     465           0 :         break;
     466             :       }
     467          31 :       if (IsEnd(next) || !IsNumber(*next)) {
     468          13 :         if (!resultingNumber.isValid()) {
     469           0 :           aToken = Token::Error();
     470             :         } else {
     471          13 :           aToken = Token::Number(resultingNumber.value());
     472             :         }
     473          13 :         return next;
     474             :       }
     475          18 :       break;
     476             : 
     477             :     case PARSE_WORD:
     478          51 :       ++next;
     479          51 :       if (IsPending(next)) {
     480           0 :         break;
     481             :       }
     482          51 :       if (IsEnd(next) || !IsWord(*next)) {
     483           6 :         aToken = Token::Word(Substring(mCursor, next));
     484           6 :         return next;
     485             :       }
     486          45 :       break;
     487             : 
     488             :     case PARSE_CRLF:
     489           0 :       ++next;
     490           0 :       if (IsPending(next)) {
     491           0 :         break;
     492             :       }
     493           0 :       if (!IsEnd(next) && *next == '\n') { // LF is optional
     494           0 :         ++next;
     495             :       }
     496           0 :       aToken = Token::NewLine();
     497           0 :       return next;
     498             : 
     499             :     case PARSE_LF:
     500           0 :       ++next;
     501           0 :       aToken = Token::NewLine();
     502           0 :       return next;
     503             : 
     504             :     case PARSE_WS:
     505           2 :       ++next;
     506           2 :       aToken = Token::Whitespace();
     507           2 :       return next;
     508             : 
     509             :     case PARSE_CHAR:
     510       14480 :       ++next;
     511       14480 :       aToken = Token::Char(*mCursor);
     512       14480 :       return next;
     513             :     } // switch (state)
     514             :   } // while (next < end)
     515             : 
     516           0 :   MOZ_ASSERT(!mInputFinished);
     517           0 :   return mCursor;
     518             : }
     519             : 
     520             : bool
     521         164 : TokenizerBase::IsEnd(const nsACString::const_char_iterator& caret) const
     522             : {
     523         164 :   return caret == mEnd;
     524             : }
     525             : 
     526             : bool
     527          82 : TokenizerBase::IsPending(const nsACString::const_char_iterator& caret) const
     528             : {
     529          82 :   return IsEnd(caret) && !mInputFinished;
     530             : }
     531             : 
     532             : bool
     533       14552 : TokenizerBase::IsWordFirst(const char aInput) const
     534             : {
     535             :   // TODO: make this fully work with unicode
     536       14552 :   return (ToLowerCase(static_cast<uint32_t>(aInput)) !=
     537       29053 :           ToUpperCase(static_cast<uint32_t>(aInput))) ||
     538       29104 :           '_' == aInput ||
     539       29054 :           (mAdditionalWordChars ? !!strchr(mAdditionalWordChars, aInput) : false);
     540             : }
     541             : 
     542             : bool
     543          51 : TokenizerBase::IsWord(const char aInput) const
     544             : {
     545          51 :   return IsWordFirst(aInput) || IsNumber(aInput);
     546             : }
     547             : 
     548             : bool
     549       14526 : TokenizerBase::IsNumber(const char aInput) const
     550             : {
     551             :   // TODO: are there unicode numbers?
     552       14526 :   return aInput >= '0' && aInput <= '9';
     553             : }
     554             : 
     555             : bool
     556           0 : TokenizerBase::IsCustom(const nsACString::const_char_iterator & caret,
     557             :                         const Token & aCustomToken,
     558             :                         uint32_t * aLongest) const
     559             : {
     560           0 :   MOZ_ASSERT(aCustomToken.mType > TOKEN_CUSTOM0);
     561           0 :   if (!aCustomToken.mCustomEnabled) {
     562           0 :     return false;
     563             :   }
     564             : 
     565           0 :   if (aLongest) {
     566           0 :     *aLongest = std::max(*aLongest, aCustomToken.mCustom.Length());
     567             :   }
     568             : 
     569             :   // This is not very likely to happen according to how we call this method
     570             :   // and since it's on a hot path, it's just a diagnostic assert,
     571             :   // not a release assert.
     572           0 :   MOZ_DIAGNOSTIC_ASSERT(mEnd >= caret, "Overflow?");
     573           0 :   uint32_t inputLength = mEnd - caret;
     574           0 :   if (aCustomToken.mCustom.Length() > inputLength) {
     575           0 :     return false;
     576             :   }
     577             : 
     578           0 :   nsDependentCSubstring inputFragment(caret, aCustomToken.mCustom.Length());
     579           0 :   if (aCustomToken.mCustomCaseInsensitivity == CASE_INSENSITIVE) {
     580           0 :     return inputFragment.Equals(aCustomToken.mCustom, nsCaseInsensitiveUTF8StringComparator());
     581             :   }
     582           0 :   return inputFragment.Equals(aCustomToken.mCustom);
     583             : }
     584             : 
     585          22 : void TokenizerBase::AssignFragment(Token& aToken,
     586             :                                    nsACString::const_char_iterator begin,
     587             :                                    nsACString::const_char_iterator end)
     588             : {
     589          22 :   aToken.AssignFragment(begin, end);
     590          22 : }
     591             : 
     592             : // TokenizerBase::Token
     593             : 
     594       45172 : TokenizerBase::Token::Token()
     595             :   : mType(TOKEN_UNKNOWN)
     596             :   , mChar(0)
     597             :   , mInteger(0)
     598             :   , mCustomCaseInsensitivity(CASE_SENSITIVE)
     599       45172 :   , mCustomEnabled(false)
     600             : {
     601       45172 : }
     602             : 
     603           0 : TokenizerBase::Token::Token(const Token& aOther)
     604           0 :   : mType(aOther.mType)
     605             :   , mCustom(aOther.mCustom)
     606           0 :   , mChar(aOther.mChar)
     607           0 :   , mInteger(aOther.mInteger)
     608           0 :   , mCustomCaseInsensitivity(aOther.mCustomCaseInsensitivity)
     609           0 :   , mCustomEnabled(aOther.mCustomEnabled)
     610             : {
     611           0 :   if (mType == TOKEN_WORD || mType > TOKEN_CUSTOM0) {
     612           0 :     mWord.Rebind(aOther.mWord.BeginReading(), aOther.mWord.Length());
     613             :   }
     614           0 : }
     615             : 
     616             : TokenizerBase::Token&
     617       15056 : TokenizerBase::Token::operator=(const Token& aOther)
     618             : {
     619       15056 :   mType = aOther.mType;
     620       15056 :   mCustom = aOther.mCustom;
     621       15056 :   mChar = aOther.mChar;
     622       15056 :   mWord.Rebind(aOther.mWord.BeginReading(), aOther.mWord.Length());
     623       15056 :   mInteger = aOther.mInteger;
     624       15056 :   mCustomCaseInsensitivity = aOther.mCustomCaseInsensitivity;
     625       15056 :   mCustomEnabled = aOther.mCustomEnabled;
     626       15056 :   return *this;
     627             : }
     628             : 
     629             : void
     630          22 : TokenizerBase::Token::AssignFragment(nsACString::const_char_iterator begin,
     631             :                                      nsACString::const_char_iterator end)
     632             : {
     633          22 :   MOZ_RELEASE_ASSERT(end >= begin, "Overflow!");
     634          22 :   mFragment.Rebind(begin, end - begin);
     635          22 : }
     636             : 
     637             : // static
     638             : TokenizerBase::Token
     639           0 : TokenizerBase::Token::Raw()
     640             : {
     641           0 :   Token t;
     642           0 :   t.mType = TOKEN_RAW;
     643           0 :   return t;
     644             : }
     645             : 
     646             : // static
     647             : TokenizerBase::Token
     648           6 : TokenizerBase::Token::Word(const nsACString& aValue)
     649             : {
     650           6 :   Token t;
     651           6 :   t.mType = TOKEN_WORD;
     652           6 :   t.mWord.Rebind(aValue.BeginReading(), aValue.Length());
     653           6 :   return t;
     654             : }
     655             : 
     656             : // static
     657             : TokenizerBase::Token
     658       22020 : TokenizerBase::Token::Char(const char aValue)
     659             : {
     660       22020 :   Token t;
     661       22020 :   t.mType = TOKEN_CHAR;
     662       22020 :   t.mChar = aValue;
     663       22020 :   return t;
     664             : }
     665             : 
     666             : // static
     667             : TokenizerBase::Token
     668          13 : TokenizerBase::Token::Number(const uint64_t aValue)
     669             : {
     670          13 :   Token t;
     671          13 :   t.mType = TOKEN_INTEGER;
     672          13 :   t.mInteger = aValue;
     673          13 :   return t;
     674             : }
     675             : 
     676             : // static
     677             : TokenizerBase::Token
     678        7506 : TokenizerBase::Token::Whitespace()
     679             : {
     680        7506 :   Token t;
     681        7506 :   t.mType = TOKEN_WS;
     682        7506 :   t.mChar = '\0';
     683        7506 :   return t;
     684             : }
     685             : 
     686             : // static
     687             : TokenizerBase::Token
     688           0 : TokenizerBase::Token::NewLine()
     689             : {
     690           0 :   Token t;
     691           0 :   t.mType = TOKEN_EOL;
     692           0 :   return t;
     693             : }
     694             : 
     695             : // static
     696             : TokenizerBase::Token
     697         584 : TokenizerBase::Token::EndOfFile()
     698             : {
     699         584 :   Token t;
     700         584 :   t.mType = TOKEN_EOF;
     701         584 :   return t;
     702             : }
     703             : 
     704             : // static
     705             : TokenizerBase::Token
     706           0 : TokenizerBase::Token::Error()
     707             : {
     708           0 :   Token t;
     709           0 :   t.mType = TOKEN_ERROR;
     710           0 :   return t;
     711             : }
     712             : 
     713             : bool
     714       15073 : TokenizerBase::Token::Equals(const Token& aOther) const
     715             : {
     716       15073 :   if (mType != aOther.mType) {
     717        7806 :     return false;
     718             :   }
     719             : 
     720        7267 :   switch (mType) {
     721             :   case TOKEN_INTEGER:
     722           0 :     return AsInteger() == aOther.AsInteger();
     723             :   case TOKEN_WORD:
     724           0 :     return AsString() == aOther.AsString();
     725             :   case TOKEN_CHAR:
     726        7253 :     return AsChar() == aOther.AsChar();
     727             :   default:
     728          14 :     return true;
     729             :   }
     730             : }
     731             : 
     732             : char
     733       14506 : TokenizerBase::Token::AsChar() const
     734             : {
     735       14506 :   MOZ_ASSERT(mType == TOKEN_CHAR || mType == TOKEN_WS);
     736       14506 :   return mChar;
     737             : }
     738             : 
     739             : nsDependentCSubstring
     740           0 : TokenizerBase::Token::AsString() const
     741             : {
     742           0 :   MOZ_ASSERT(mType == TOKEN_WORD);
     743           0 :   return mWord;
     744             : }
     745             : 
     746             : uint64_t
     747          14 : TokenizerBase::Token::AsInteger() const
     748             : {
     749          14 :   MOZ_ASSERT(mType == TOKEN_INTEGER);
     750          14 :   return mInteger;
     751             : }
     752             : 
     753             : } // mozilla

Generated by: LCOV version 1.13