tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

txCoreFunctionCall.cpp (19630B)


      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/. */
      5 
      6 #include <math.h>
      7 
      8 #include "mozilla/FloatingPoint.h"
      9 #include "nsGkAtoms.h"
     10 #include "nsWhitespaceTokenizer.h"
     11 #include "txExpr.h"
     12 #include "txIXPathContext.h"
     13 #include "txNodeSet.h"
     14 #include "txStringUtils.h"
     15 #include "txXMLUtils.h"
     16 #include "txXPathTreeWalker.h"
     17 
     18 using namespace mozilla;
     19 
     20 struct txCoreFunctionDescriptor {
     21  const int8_t mMinParams;
     22  const int8_t mMaxParams;
     23  const Expr::ResultType mReturnType;
     24  const nsStaticAtom* const mName;
     25 };
     26 
     27 // This must be ordered in the same order as txCoreFunctionCall::eType.
     28 // If you change one, change the other.
     29 static const txCoreFunctionDescriptor descriptTable[] = {
     30    {1, 1, Expr::NUMBER_RESULT, nsGkAtoms::count},         // COUNT
     31    {1, 1, Expr::NODESET_RESULT, nsGkAtoms::id},           // ID
     32    {0, 0, Expr::NUMBER_RESULT, nsGkAtoms::last},          // LAST
     33    {0, 1, Expr::STRING_RESULT, nsGkAtoms::localName},     // LOCAL_NAME
     34    {0, 1, Expr::STRING_RESULT, nsGkAtoms::namespaceUri},  // NAMESPACE_URI
     35    {0, 1, Expr::STRING_RESULT, nsGkAtoms::name},          // NAME
     36    {0, 0, Expr::NUMBER_RESULT, nsGkAtoms::position},      // POSITION
     37 
     38    {2, -1, Expr::STRING_RESULT, nsGkAtoms::concat},         // CONCAT
     39    {2, 2, Expr::BOOLEAN_RESULT, nsGkAtoms::contains},       // CONTAINS
     40    {0, 1, Expr::STRING_RESULT, nsGkAtoms::normalizeSpace},  // NORMALIZE_SPACE
     41    {2, 2, Expr::BOOLEAN_RESULT, nsGkAtoms::startsWith},     // STARTS_WITH
     42    {0, 1, Expr::STRING_RESULT, nsGkAtoms::string},          // STRING
     43    {0, 1, Expr::NUMBER_RESULT, nsGkAtoms::stringLength},    // STRING_LENGTH
     44    {2, 3, Expr::STRING_RESULT, nsGkAtoms::substring},       // SUBSTRING
     45    {2, 2, Expr::STRING_RESULT, nsGkAtoms::substringAfter},  // SUBSTRING_AFTER
     46    {2, 2, Expr::STRING_RESULT,
     47     nsGkAtoms::substringBefore},                       // SUBSTRING_BEFORE
     48    {3, 3, Expr::STRING_RESULT, nsGkAtoms::translate},  // TRANSLATE
     49 
     50    {0, 1, Expr::NUMBER_RESULT, nsGkAtoms::number},   // NUMBER
     51    {1, 1, Expr::NUMBER_RESULT, nsGkAtoms::round},    // ROUND
     52    {1, 1, Expr::NUMBER_RESULT, nsGkAtoms::floor},    // FLOOR
     53    {1, 1, Expr::NUMBER_RESULT, nsGkAtoms::ceiling},  // CEILING
     54    {1, 1, Expr::NUMBER_RESULT, nsGkAtoms::sum},      // SUM
     55 
     56    {1, 1, Expr::BOOLEAN_RESULT, nsGkAtoms::boolean},  // BOOLEAN
     57    {0, 0, Expr::BOOLEAN_RESULT, nsGkAtoms::_false},   // _FALSE
     58    {1, 1, Expr::BOOLEAN_RESULT, nsGkAtoms::lang},     // LANG
     59    {1, 1, Expr::BOOLEAN_RESULT, nsGkAtoms::_not},     // _NOT
     60    {0, 0, Expr::BOOLEAN_RESULT, nsGkAtoms::_true}     // _TRUE
     61 };
     62 
     63 /*
     64 * Evaluates this Expr based on the given context node and processor state
     65 * @param context the context node for evaluation of this Expr
     66 * @param ps the ContextState containing the stack information needed
     67 * for evaluation
     68 * @return the result of the evaluation
     69 */
     70 nsresult txCoreFunctionCall::evaluate(txIEvalContext* aContext,
     71                                      txAExprResult** aResult) {
     72  *aResult = nullptr;
     73 
     74  if (!requireParams(descriptTable[mType].mMinParams,
     75                     descriptTable[mType].mMaxParams, aContext)) {
     76    return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
     77  }
     78 
     79  nsresult rv = NS_OK;
     80  switch (mType) {
     81    case COUNT: {
     82      RefPtr<txNodeSet> nodes;
     83      rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes));
     84      NS_ENSURE_SUCCESS(rv, rv);
     85 
     86      return aContext->recycler()->getNumberResult(nodes->size(), aResult);
     87    }
     88    case ID: {
     89      RefPtr<txAExprResult> exprResult;
     90      rv = mParams[0]->evaluate(aContext, getter_AddRefs(exprResult));
     91      NS_ENSURE_SUCCESS(rv, rv);
     92 
     93      RefPtr<txNodeSet> resultSet;
     94      rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
     95      NS_ENSURE_SUCCESS(rv, rv);
     96 
     97      txXPathTreeWalker walker(aContext->getContextNode());
     98 
     99      if (exprResult->getResultType() == txAExprResult::NODESET) {
    100        txNodeSet* nodes =
    101            static_cast<txNodeSet*>(static_cast<txAExprResult*>(exprResult));
    102        int32_t i;
    103        for (i = 0; i < nodes->size(); ++i) {
    104          nsAutoString idList;
    105          txXPathNodeUtils::appendNodeValue(nodes->get(i), idList);
    106          nsWhitespaceTokenizer tokenizer(idList);
    107          while (tokenizer.hasMoreTokens()) {
    108            if (walker.moveToElementById(tokenizer.nextToken())) {
    109              resultSet->add(walker.getCurrentPosition());
    110            }
    111          }
    112        }
    113      } else {
    114        nsAutoString idList;
    115        exprResult->stringValue(idList);
    116        nsWhitespaceTokenizer tokenizer(idList);
    117        while (tokenizer.hasMoreTokens()) {
    118          if (walker.moveToElementById(tokenizer.nextToken())) {
    119            resultSet->add(walker.getCurrentPosition());
    120          }
    121        }
    122      }
    123 
    124      *aResult = resultSet;
    125      NS_ADDREF(*aResult);
    126 
    127      return NS_OK;
    128    }
    129    case LAST: {
    130      return aContext->recycler()->getNumberResult(aContext->size(), aResult);
    131    }
    132    case LOCAL_NAME:
    133    case NAME:
    134    case NAMESPACE_URI: {
    135      // Check for optional arg
    136      RefPtr<txNodeSet> nodes;
    137      if (!mParams.IsEmpty()) {
    138        rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes));
    139        NS_ENSURE_SUCCESS(rv, rv);
    140 
    141        if (nodes->isEmpty()) {
    142          aContext->recycler()->getEmptyStringResult(aResult);
    143 
    144          return NS_OK;
    145        }
    146      }
    147 
    148      const txXPathNode& node =
    149          nodes ? nodes->get(0) : aContext->getContextNode();
    150      switch (mType) {
    151        case LOCAL_NAME: {
    152          StringResult* strRes = nullptr;
    153          rv = aContext->recycler()->getStringResult(&strRes);
    154          NS_ENSURE_SUCCESS(rv, rv);
    155 
    156          *aResult = strRes;
    157          txXPathNodeUtils::getLocalName(node, strRes->mValue);
    158 
    159          return NS_OK;
    160        }
    161        case NAMESPACE_URI: {
    162          StringResult* strRes = nullptr;
    163          rv = aContext->recycler()->getStringResult(&strRes);
    164          NS_ENSURE_SUCCESS(rv, rv);
    165 
    166          *aResult = strRes;
    167          txXPathNodeUtils::getNamespaceURI(node, strRes->mValue);
    168 
    169          return NS_OK;
    170        }
    171        case NAME: {
    172          // XXX Namespace: namespaces have a name
    173          if (txXPathNodeUtils::isAttribute(node) ||
    174              txXPathNodeUtils::isElement(node) ||
    175              txXPathNodeUtils::isProcessingInstruction(node)) {
    176            StringResult* strRes = nullptr;
    177            rv = aContext->recycler()->getStringResult(&strRes);
    178            NS_ENSURE_SUCCESS(rv, rv);
    179 
    180            *aResult = strRes;
    181            txXPathNodeUtils::getNodeName(node, strRes->mValue);
    182          } else {
    183            aContext->recycler()->getEmptyStringResult(aResult);
    184          }
    185 
    186          return NS_OK;
    187        }
    188        default: {
    189          MOZ_CRASH("Unexpected mType?!");
    190        }
    191      }
    192      MOZ_CRASH("Inner mType switch should have returned!");
    193    }
    194    case POSITION: {
    195      return aContext->recycler()->getNumberResult(aContext->position(),
    196                                                   aResult);
    197    }
    198 
    199      // String functions
    200 
    201    case CONCAT: {
    202      RefPtr<StringResult> strRes;
    203      rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
    204      NS_ENSURE_SUCCESS(rv, rv);
    205 
    206      uint32_t i, len = mParams.Length();
    207      for (i = 0; i < len; ++i) {
    208        rv = mParams[i]->evaluateToString(aContext, strRes->mValue);
    209        NS_ENSURE_SUCCESS(rv, rv);
    210      }
    211 
    212      NS_ADDREF(*aResult = strRes);
    213 
    214      return NS_OK;
    215    }
    216    case CONTAINS: {
    217      nsAutoString arg2;
    218      rv = mParams[1]->evaluateToString(aContext, arg2);
    219      NS_ENSURE_SUCCESS(rv, rv);
    220 
    221      if (arg2.IsEmpty()) {
    222        aContext->recycler()->getBoolResult(true, aResult);
    223      } else {
    224        nsAutoString arg1;
    225        rv = mParams[0]->evaluateToString(aContext, arg1);
    226        NS_ENSURE_SUCCESS(rv, rv);
    227 
    228        aContext->recycler()->getBoolResult(FindInReadable(arg2, arg1),
    229                                            aResult);
    230      }
    231 
    232      return NS_OK;
    233    }
    234    case NORMALIZE_SPACE: {
    235      nsAutoString resultStr;
    236      if (!mParams.IsEmpty()) {
    237        rv = mParams[0]->evaluateToString(aContext, resultStr);
    238        NS_ENSURE_SUCCESS(rv, rv);
    239      } else {
    240        txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
    241                                          resultStr);
    242      }
    243 
    244      RefPtr<StringResult> strRes;
    245      rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
    246      NS_ENSURE_SUCCESS(rv, rv);
    247 
    248      bool addSpace = false;
    249      bool first = true;
    250      strRes->mValue.SetCapacity(resultStr.Length());
    251      char16_t c;
    252      uint32_t src;
    253      for (src = 0; src < resultStr.Length(); src++) {
    254        c = resultStr.CharAt(src);
    255        if (XMLUtils::isWhitespace(c)) {
    256          addSpace = true;
    257        } else {
    258          if (addSpace && !first) strRes->mValue.Append(char16_t(' '));
    259 
    260          strRes->mValue.Append(c);
    261          addSpace = false;
    262          first = false;
    263        }
    264      }
    265      *aResult = strRes;
    266      NS_ADDREF(*aResult);
    267 
    268      return NS_OK;
    269    }
    270    case STARTS_WITH: {
    271      nsAutoString arg2;
    272      rv = mParams[1]->evaluateToString(aContext, arg2);
    273      NS_ENSURE_SUCCESS(rv, rv);
    274 
    275      bool result = false;
    276      if (arg2.IsEmpty()) {
    277        result = true;
    278      } else {
    279        nsAutoString arg1;
    280        rv = mParams[0]->evaluateToString(aContext, arg1);
    281        NS_ENSURE_SUCCESS(rv, rv);
    282 
    283        result = StringBeginsWith(arg1, arg2);
    284      }
    285 
    286      aContext->recycler()->getBoolResult(result, aResult);
    287 
    288      return NS_OK;
    289    }
    290    case STRING: {
    291      RefPtr<StringResult> strRes;
    292      rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
    293      NS_ENSURE_SUCCESS(rv, rv);
    294 
    295      if (!mParams.IsEmpty()) {
    296        rv = mParams[0]->evaluateToString(aContext, strRes->mValue);
    297        NS_ENSURE_SUCCESS(rv, rv);
    298      } else {
    299        txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
    300                                          strRes->mValue);
    301      }
    302 
    303      NS_ADDREF(*aResult = strRes);
    304 
    305      return NS_OK;
    306    }
    307    case STRING_LENGTH: {
    308      nsAutoString resultStr;
    309      if (!mParams.IsEmpty()) {
    310        rv = mParams[0]->evaluateToString(aContext, resultStr);
    311        NS_ENSURE_SUCCESS(rv, rv);
    312      } else {
    313        txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
    314                                          resultStr);
    315      }
    316      rv = aContext->recycler()->getNumberResult(resultStr.Length(), aResult);
    317      NS_ENSURE_SUCCESS(rv, rv);
    318 
    319      return NS_OK;
    320    }
    321    case SUBSTRING: {
    322      nsAutoString src;
    323      rv = mParams[0]->evaluateToString(aContext, src);
    324      NS_ENSURE_SUCCESS(rv, rv);
    325 
    326      double start;
    327      rv = evaluateToNumber(mParams[1], aContext, &start);
    328      NS_ENSURE_SUCCESS(rv, rv);
    329 
    330      // check for NaN or +/-Inf
    331      if (std::isnan(start) || std::isinf(start) ||
    332          start >= src.Length() + 0.5) {
    333        aContext->recycler()->getEmptyStringResult(aResult);
    334 
    335        return NS_OK;
    336      }
    337 
    338      start = floor(start + 0.5) - 1;
    339 
    340      double end;
    341      if (mParams.Length() == 3) {
    342        rv = evaluateToNumber(mParams[2], aContext, &end);
    343        NS_ENSURE_SUCCESS(rv, rv);
    344 
    345        end += start;
    346        if (std::isnan(end) || end < 0) {
    347          aContext->recycler()->getEmptyStringResult(aResult);
    348 
    349          return NS_OK;
    350        }
    351 
    352        if (end > src.Length())
    353          end = src.Length();
    354        else
    355          end = floor(end + 0.5);
    356      } else {
    357        end = src.Length();
    358      }
    359 
    360      if (start < 0) start = 0;
    361 
    362      if (start > end) {
    363        aContext->recycler()->getEmptyStringResult(aResult);
    364 
    365        return NS_OK;
    366      }
    367 
    368      return aContext->recycler()->getStringResult(
    369          Substring(src, (uint32_t)start, (uint32_t)(end - start)), aResult);
    370    }
    371    case SUBSTRING_AFTER: {
    372      nsAutoString arg1;
    373      rv = mParams[0]->evaluateToString(aContext, arg1);
    374      NS_ENSURE_SUCCESS(rv, rv);
    375 
    376      nsAutoString arg2;
    377      rv = mParams[1]->evaluateToString(aContext, arg2);
    378      NS_ENSURE_SUCCESS(rv, rv);
    379 
    380      if (arg2.IsEmpty()) {
    381        return aContext->recycler()->getStringResult(arg1, aResult);
    382      }
    383 
    384      int32_t idx = arg1.Find(arg2);
    385      if (idx == kNotFound) {
    386        aContext->recycler()->getEmptyStringResult(aResult);
    387 
    388        return NS_OK;
    389      }
    390 
    391      const nsAString& result = Substring(arg1, idx + arg2.Length());
    392      return aContext->recycler()->getStringResult(result, aResult);
    393    }
    394    case SUBSTRING_BEFORE: {
    395      nsAutoString arg2;
    396      rv = mParams[1]->evaluateToString(aContext, arg2);
    397      NS_ENSURE_SUCCESS(rv, rv);
    398 
    399      if (arg2.IsEmpty()) {
    400        aContext->recycler()->getEmptyStringResult(aResult);
    401 
    402        return NS_OK;
    403      }
    404 
    405      nsAutoString arg1;
    406      rv = mParams[0]->evaluateToString(aContext, arg1);
    407      NS_ENSURE_SUCCESS(rv, rv);
    408 
    409      int32_t idx = arg1.Find(arg2);
    410      if (idx == kNotFound) {
    411        aContext->recycler()->getEmptyStringResult(aResult);
    412 
    413        return NS_OK;
    414      }
    415 
    416      return aContext->recycler()->getStringResult(StringHead(arg1, idx),
    417                                                   aResult);
    418    }
    419    case TRANSLATE: {
    420      nsAutoString src;
    421      rv = mParams[0]->evaluateToString(aContext, src);
    422      NS_ENSURE_SUCCESS(rv, rv);
    423 
    424      if (src.IsEmpty()) {
    425        aContext->recycler()->getEmptyStringResult(aResult);
    426 
    427        return NS_OK;
    428      }
    429 
    430      RefPtr<StringResult> strRes;
    431      rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
    432      NS_ENSURE_SUCCESS(rv, rv);
    433 
    434      strRes->mValue.SetCapacity(src.Length());
    435 
    436      nsAutoString oldChars, newChars;
    437      rv = mParams[1]->evaluateToString(aContext, oldChars);
    438      NS_ENSURE_SUCCESS(rv, rv);
    439 
    440      rv = mParams[2]->evaluateToString(aContext, newChars);
    441      NS_ENSURE_SUCCESS(rv, rv);
    442 
    443      uint32_t i;
    444      int32_t newCharsLength = (int32_t)newChars.Length();
    445      for (i = 0; i < src.Length(); i++) {
    446        int32_t idx = oldChars.FindChar(src.CharAt(i));
    447        if (idx != kNotFound) {
    448          if (idx < newCharsLength)
    449            strRes->mValue.Append(newChars.CharAt((uint32_t)idx));
    450        } else {
    451          strRes->mValue.Append(src.CharAt(i));
    452        }
    453      }
    454 
    455      NS_ADDREF(*aResult = strRes);
    456 
    457      return NS_OK;
    458    }
    459 
    460      // Number functions
    461 
    462    case NUMBER: {
    463      double res;
    464      if (!mParams.IsEmpty()) {
    465        rv = evaluateToNumber(mParams[0], aContext, &res);
    466        NS_ENSURE_SUCCESS(rv, rv);
    467      } else {
    468        nsAutoString resultStr;
    469        txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
    470                                          resultStr);
    471        res = txDouble::toDouble(resultStr);
    472      }
    473      return aContext->recycler()->getNumberResult(res, aResult);
    474    }
    475    case ROUND: {
    476      double dbl;
    477      rv = evaluateToNumber(mParams[0], aContext, &dbl);
    478      NS_ENSURE_SUCCESS(rv, rv);
    479 
    480      if (std::isfinite(dbl)) {
    481        if (mozilla::IsNegative(dbl) && dbl >= -0.5) {
    482          dbl *= 0;
    483        } else {
    484          dbl = floor(dbl + 0.5);
    485        }
    486      }
    487 
    488      return aContext->recycler()->getNumberResult(dbl, aResult);
    489    }
    490    case FLOOR: {
    491      double dbl;
    492      rv = evaluateToNumber(mParams[0], aContext, &dbl);
    493      NS_ENSURE_SUCCESS(rv, rv);
    494 
    495      if (std::isfinite(dbl) && !mozilla::IsNegativeZero(dbl)) dbl = floor(dbl);
    496 
    497      return aContext->recycler()->getNumberResult(dbl, aResult);
    498    }
    499    case CEILING: {
    500      double dbl;
    501      rv = evaluateToNumber(mParams[0], aContext, &dbl);
    502      NS_ENSURE_SUCCESS(rv, rv);
    503 
    504      if (std::isfinite(dbl)) {
    505        if (mozilla::IsNegative(dbl) && dbl > -1)
    506          dbl *= 0;
    507        else
    508          dbl = ceil(dbl);
    509      }
    510 
    511      return aContext->recycler()->getNumberResult(dbl, aResult);
    512    }
    513    case SUM: {
    514      RefPtr<txNodeSet> nodes;
    515      nsresult rv =
    516          evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes));
    517      NS_ENSURE_SUCCESS(rv, rv);
    518 
    519      double res = 0;
    520      int32_t i;
    521      for (i = 0; i < nodes->size(); ++i) {
    522        nsAutoString resultStr;
    523        txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr);
    524        res += txDouble::toDouble(resultStr);
    525      }
    526      return aContext->recycler()->getNumberResult(res, aResult);
    527    }
    528 
    529      // Boolean functions
    530 
    531    case BOOLEAN: {
    532      bool result;
    533      nsresult rv = mParams[0]->evaluateToBool(aContext, result);
    534      NS_ENSURE_SUCCESS(rv, rv);
    535 
    536      aContext->recycler()->getBoolResult(result, aResult);
    537 
    538      return NS_OK;
    539    }
    540    case _FALSE: {
    541      aContext->recycler()->getBoolResult(false, aResult);
    542 
    543      return NS_OK;
    544    }
    545    case LANG: {
    546      txXPathTreeWalker walker(aContext->getContextNode());
    547 
    548      nsAutoString lang;
    549      bool found;
    550      do {
    551        found = walker.getAttr(nsGkAtoms::lang, kNameSpaceID_XML, lang);
    552      } while (!found && walker.moveToParent());
    553 
    554      if (!found) {
    555        aContext->recycler()->getBoolResult(false, aResult);
    556 
    557        return NS_OK;
    558      }
    559 
    560      nsAutoString arg;
    561      rv = mParams[0]->evaluateToString(aContext, arg);
    562      NS_ENSURE_SUCCESS(rv, rv);
    563 
    564      bool result =
    565          StringBeginsWith(lang, arg, nsCaseInsensitiveStringComparator) &&
    566          (lang.Length() == arg.Length() || lang.CharAt(arg.Length()) == '-');
    567 
    568      aContext->recycler()->getBoolResult(result, aResult);
    569 
    570      return NS_OK;
    571    }
    572    case _NOT: {
    573      bool result;
    574      rv = mParams[0]->evaluateToBool(aContext, result);
    575      NS_ENSURE_SUCCESS(rv, rv);
    576 
    577      aContext->recycler()->getBoolResult(!result, aResult);
    578 
    579      return NS_OK;
    580    }
    581    case _TRUE: {
    582      aContext->recycler()->getBoolResult(true, aResult);
    583 
    584      return NS_OK;
    585    }
    586  }
    587 
    588  aContext->receiveError(u"Internal error"_ns, NS_ERROR_UNEXPECTED);
    589  return NS_ERROR_UNEXPECTED;
    590 }
    591 
    592 Expr::ResultType txCoreFunctionCall::getReturnType() {
    593  return descriptTable[mType].mReturnType;
    594 }
    595 
    596 bool txCoreFunctionCall::isSensitiveTo(ContextSensitivity aContext) {
    597  switch (mType) {
    598    case COUNT:
    599    case CONCAT:
    600    case CONTAINS:
    601    case STARTS_WITH:
    602    case SUBSTRING:
    603    case SUBSTRING_AFTER:
    604    case SUBSTRING_BEFORE:
    605    case TRANSLATE:
    606    case ROUND:
    607    case FLOOR:
    608    case CEILING:
    609    case SUM:
    610    case BOOLEAN:
    611    case _NOT:
    612    case _FALSE:
    613    case _TRUE: {
    614      return argsSensitiveTo(aContext);
    615    }
    616    case ID: {
    617      return (aContext & NODE_CONTEXT) || argsSensitiveTo(aContext);
    618    }
    619    case LAST: {
    620      return !!(aContext & SIZE_CONTEXT);
    621    }
    622    case LOCAL_NAME:
    623    case NAME:
    624    case NAMESPACE_URI:
    625    case NORMALIZE_SPACE:
    626    case STRING:
    627    case STRING_LENGTH:
    628    case NUMBER: {
    629      if (mParams.IsEmpty()) {
    630        return !!(aContext & NODE_CONTEXT);
    631      }
    632      return argsSensitiveTo(aContext);
    633    }
    634    case POSITION: {
    635      return !!(aContext & POSITION_CONTEXT);
    636    }
    637    case LANG: {
    638      return (aContext & NODE_CONTEXT) || argsSensitiveTo(aContext);
    639    }
    640  }
    641 
    642  MOZ_ASSERT_UNREACHABLE("how'd we get here?");
    643  return true;
    644 }
    645 
    646 // static
    647 bool txCoreFunctionCall::getTypeFromAtom(nsAtom* aName, eType& aType) {
    648  uint32_t i;
    649  for (i = 0; i < std::size(descriptTable); ++i) {
    650    if (aName == descriptTable[i].mName) {
    651      aType = static_cast<eType>(i);
    652 
    653      return true;
    654    }
    655  }
    656 
    657  return false;
    658 }
    659 
    660 #ifdef TX_TO_STRING
    661 void txCoreFunctionCall::appendName(nsAString& aDest) {
    662  aDest.Append(descriptTable[mType].mName->GetUTF16String());
    663 }
    664 #endif