Bug 1874684 - Part 4: Prefer const references instead of copying Instant values....
[gecko.git] / dom / xslt / xslt / txEXSLTFunctions.cpp
blobcb4f2040196296b5115d99b2997664db8ee6bfea
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/. */
6 #include "mozilla/ArrayUtils.h"
7 #include "mozilla/EnumeratedArray.h"
8 #include "mozilla/EnumeratedRange.h"
9 #include "mozilla/FloatingPoint.h"
10 #include "mozilla/MacroArgs.h"
11 #include "mozilla/MacroForEach.h"
13 #include "nsAtom.h"
14 #include "nsGkAtoms.h"
15 #include "txExecutionState.h"
16 #include "txExpr.h"
17 #include "txIXPathContext.h"
18 #include "txIEXSLTFunctions.h"
19 #include "txNodeSet.h"
20 #include "txOutputFormat.h"
21 #include "txRtfHandler.h"
22 #include "txXPathTreeWalker.h"
23 #include "nsImportModule.h"
24 #include "nsPrintfCString.h"
25 #include "nsComponentManagerUtils.h"
26 #include "nsContentCreatorFunctions.h"
27 #include "nsIContent.h"
28 #include "txMozillaXMLOutput.h"
29 #include "nsTextNode.h"
30 #include "mozilla/dom/DocumentFragmentBinding.h"
31 #include "prtime.h"
32 #include "xpcprivate.h"
34 using namespace mozilla;
35 using namespace mozilla::dom;
37 class txStylesheetCompilerState;
39 // ------------------------------------------------------------------
40 // Utility functions
41 // ------------------------------------------------------------------
43 static Document* getSourceDocument(txIEvalContext* aContext) {
44 txExecutionState* es =
45 static_cast<txExecutionState*>(aContext->getPrivateContext());
46 if (!es) {
47 NS_ERROR("Need txExecutionState!");
49 return nullptr;
52 const txXPathNode& document = es->getSourceDocument();
53 return txXPathNativeNode::getDocument(document);
56 static nsresult convertRtfToNode(txIEvalContext* aContext,
57 txResultTreeFragment* aRtf) {
58 Document* doc = getSourceDocument(aContext);
59 if (!doc) {
60 return NS_ERROR_UNEXPECTED;
63 RefPtr<DocumentFragment> domFragment =
64 new (doc->NodeInfoManager()) DocumentFragment(doc->NodeInfoManager());
66 txOutputFormat format;
67 txMozillaXMLOutput mozHandler(&format, domFragment, true);
69 nsresult rv = aRtf->flushToHandler(&mozHandler);
70 NS_ENSURE_SUCCESS(rv, rv);
72 rv = mozHandler.closePrevious(true);
73 NS_ENSURE_SUCCESS(rv, rv);
75 // The txResultTreeFragment will own this.
76 const txXPathNode* node =
77 txXPathNativeNode::createXPathNode(domFragment, true);
78 NS_ENSURE_TRUE(node, NS_ERROR_OUT_OF_MEMORY);
80 aRtf->setNode(node);
82 return NS_OK;
85 static nsresult createTextNode(txIEvalContext* aContext, nsString& aValue,
86 txXPathNode** aResult) {
87 Document* doc = getSourceDocument(aContext);
88 if (!doc) {
89 return NS_ERROR_UNEXPECTED;
92 RefPtr<nsTextNode> text =
93 new (doc->NodeInfoManager()) nsTextNode(doc->NodeInfoManager());
95 nsresult rv = text->SetText(aValue, false);
96 NS_ENSURE_SUCCESS(rv, rv);
98 *aResult = txXPathNativeNode::createXPathNode(text, true);
99 NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
101 return NS_OK;
104 static nsresult createAndAddToResult(nsAtom* aName, const nsAString& aValue,
105 txNodeSet* aResultSet,
106 DocumentFragment* aResultHolder) {
107 Document* doc = aResultHolder->OwnerDoc();
108 nsCOMPtr<Element> elem =
109 doc->CreateElem(nsDependentAtomString(aName), nullptr, kNameSpaceID_None);
110 NS_ENSURE_TRUE(elem, NS_ERROR_NULL_POINTER);
112 RefPtr<nsTextNode> text =
113 new (doc->NodeInfoManager()) nsTextNode(doc->NodeInfoManager());
115 nsresult rv = text->SetText(aValue, false);
116 NS_ENSURE_SUCCESS(rv, rv);
118 ErrorResult error;
119 elem->AppendChildTo(text, false, error);
120 if (error.Failed()) {
121 return error.StealNSResult();
124 aResultHolder->AppendChildTo(elem, false, error);
125 if (error.Failed()) {
126 return error.StealNSResult();
129 UniquePtr<txXPathNode> xpathNode(
130 txXPathNativeNode::createXPathNode(elem, true));
131 NS_ENSURE_TRUE(xpathNode, NS_ERROR_OUT_OF_MEMORY);
133 aResultSet->append(*xpathNode);
135 return NS_OK;
138 // Need to update this array if types are added to the ResultType enum in
139 // txAExprResult.
140 static const char* const sTypes[] = {"node-set", "boolean", "number", "string",
141 "RTF"};
143 // ------------------------------------------------------------------
144 // Function implementations
145 // ------------------------------------------------------------------
147 enum class txEXSLTType {
148 // http://exslt.org/common
149 NODE_SET,
150 OBJECT_TYPE,
152 // http://exslt.org/dates-and-times
153 DATE_TIME,
155 // http://exslt.org/math
156 MAX,
157 MIN,
158 HIGHEST,
159 LOWEST,
161 // http://exslt.org/regular-expressions
162 MATCH,
163 REPLACE,
164 TEST,
166 // http://exslt.org/sets
167 DIFFERENCE_, // not DIFFERENCE to avoid a conflict with a winuser.h macro
168 DISTINCT,
169 HAS_SAME_NODE,
170 INTERSECTION,
171 LEADING,
172 TRAILING,
174 // http://exslt.org/strings
175 CONCAT,
176 SPLIT,
177 TOKENIZE,
179 _LIMIT,
182 struct txEXSLTFunctionDescriptor {
183 int8_t mMinParams;
184 int8_t mMaxParams;
185 Expr::ResultType mReturnType;
186 nsStaticAtom* mName;
187 bool (*mCreator)(txEXSLTType, FunctionCall**);
188 int32_t mNamespaceID;
191 static EnumeratedArray<txEXSLTType, txEXSLTFunctionDescriptor,
192 size_t(txEXSLTType::_LIMIT)>
193 descriptTable;
195 class txEXSLTFunctionCall : public FunctionCall {
196 public:
197 explicit txEXSLTFunctionCall(txEXSLTType aType) : mType(aType) {}
199 static bool Create(txEXSLTType aType, FunctionCall** aFunction) {
200 *aFunction = new txEXSLTFunctionCall(aType);
201 return true;
204 TX_DECL_FUNCTION
206 private:
207 txEXSLTType mType;
210 class txEXSLTRegExFunctionCall : public FunctionCall {
211 public:
212 explicit txEXSLTRegExFunctionCall(txEXSLTType aType) : mType(aType) {}
214 static bool Create(txEXSLTType aType, FunctionCall** aFunction) {
215 *aFunction = new txEXSLTRegExFunctionCall(aType);
216 return true;
219 TX_DECL_FUNCTION
221 private:
222 txEXSLTType mType;
225 nsresult txEXSLTFunctionCall::evaluate(txIEvalContext* aContext,
226 txAExprResult** aResult) {
227 *aResult = nullptr;
228 if (!requireParams(descriptTable[mType].mMinParams,
229 descriptTable[mType].mMaxParams, aContext)) {
230 return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
233 nsresult rv = NS_OK;
234 switch (mType) {
235 case txEXSLTType::NODE_SET: {
236 RefPtr<txAExprResult> exprResult;
237 rv = mParams[0]->evaluate(aContext, getter_AddRefs(exprResult));
238 NS_ENSURE_SUCCESS(rv, rv);
240 if (exprResult->getResultType() == txAExprResult::NODESET) {
241 exprResult.forget(aResult);
242 } else {
243 RefPtr<txNodeSet> resultSet;
244 rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
245 NS_ENSURE_SUCCESS(rv, rv);
247 if (exprResult->getResultType() ==
248 txAExprResult::RESULT_TREE_FRAGMENT) {
249 txResultTreeFragment* rtf =
250 static_cast<txResultTreeFragment*>(exprResult.get());
252 const txXPathNode* node = rtf->getNode();
253 if (!node) {
254 rv = convertRtfToNode(aContext, rtf);
255 NS_ENSURE_SUCCESS(rv, rv);
257 node = rtf->getNode();
260 resultSet->append(*node);
261 } else {
262 nsAutoString value;
263 exprResult->stringValue(value);
265 UniquePtr<txXPathNode> node;
266 rv = createTextNode(aContext, value, getter_Transfers(node));
267 NS_ENSURE_SUCCESS(rv, rv);
269 resultSet->append(*node);
272 NS_ADDREF(*aResult = resultSet);
275 return NS_OK;
277 case txEXSLTType::OBJECT_TYPE: {
278 RefPtr<txAExprResult> exprResult;
279 nsresult rv = mParams[0]->evaluate(aContext, getter_AddRefs(exprResult));
280 NS_ENSURE_SUCCESS(rv, rv);
282 RefPtr<StringResult> strRes;
283 rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
284 NS_ENSURE_SUCCESS(rv, rv);
286 AppendASCIItoUTF16(MakeStringSpan(sTypes[exprResult->getResultType()]),
287 strRes->mValue);
289 NS_ADDREF(*aResult = strRes);
291 return NS_OK;
293 case txEXSLTType::DIFFERENCE_:
294 case txEXSLTType::INTERSECTION: {
295 RefPtr<txNodeSet> nodes1;
296 rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes1));
297 NS_ENSURE_SUCCESS(rv, rv);
299 RefPtr<txNodeSet> nodes2;
300 rv = evaluateToNodeSet(mParams[1], aContext, getter_AddRefs(nodes2));
301 NS_ENSURE_SUCCESS(rv, rv);
303 RefPtr<txNodeSet> resultSet;
304 rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
305 NS_ENSURE_SUCCESS(rv, rv);
307 bool insertOnFound = mType == txEXSLTType::INTERSECTION;
309 int32_t searchPos = 0;
310 int32_t i, len = nodes1->size();
311 for (i = 0; i < len; ++i) {
312 const txXPathNode& node = nodes1->get(i);
313 int32_t foundPos = nodes2->indexOf(node, searchPos);
314 if (foundPos >= 0) {
315 searchPos = foundPos + 1;
318 if ((foundPos >= 0) == insertOnFound) {
319 rv = resultSet->append(node);
320 NS_ENSURE_SUCCESS(rv, rv);
324 NS_ADDREF(*aResult = resultSet);
326 return NS_OK;
328 case txEXSLTType::DISTINCT: {
329 RefPtr<txNodeSet> nodes;
330 rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes));
331 NS_ENSURE_SUCCESS(rv, rv);
333 RefPtr<txNodeSet> resultSet;
334 rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
335 NS_ENSURE_SUCCESS(rv, rv);
337 nsTHashSet<nsString> hash;
339 int32_t i, len = nodes->size();
340 for (i = 0; i < len; ++i) {
341 nsAutoString str;
342 const txXPathNode& node = nodes->get(i);
343 txXPathNodeUtils::appendNodeValue(node, str);
344 if (hash.EnsureInserted(str)) {
345 rv = resultSet->append(node);
346 NS_ENSURE_SUCCESS(rv, rv);
350 NS_ADDREF(*aResult = resultSet);
352 return NS_OK;
354 case txEXSLTType::HAS_SAME_NODE: {
355 RefPtr<txNodeSet> nodes1;
356 rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes1));
357 NS_ENSURE_SUCCESS(rv, rv);
359 RefPtr<txNodeSet> nodes2;
360 rv = evaluateToNodeSet(mParams[1], aContext, getter_AddRefs(nodes2));
361 NS_ENSURE_SUCCESS(rv, rv);
363 bool found = false;
364 int32_t i, len = nodes1->size();
365 for (i = 0; i < len; ++i) {
366 if (nodes2->contains(nodes1->get(i))) {
367 found = true;
368 break;
372 aContext->recycler()->getBoolResult(found, aResult);
374 return NS_OK;
376 case txEXSLTType::LEADING:
377 case txEXSLTType::TRAILING: {
378 RefPtr<txNodeSet> nodes1;
379 rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes1));
380 NS_ENSURE_SUCCESS(rv, rv);
382 RefPtr<txNodeSet> nodes2;
383 rv = evaluateToNodeSet(mParams[1], aContext, getter_AddRefs(nodes2));
384 NS_ENSURE_SUCCESS(rv, rv);
386 if (nodes2->isEmpty()) {
387 *aResult = nodes1;
388 NS_ADDREF(*aResult);
390 return NS_OK;
393 RefPtr<txNodeSet> resultSet;
394 rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
395 NS_ENSURE_SUCCESS(rv, rv);
397 int32_t end = nodes1->indexOf(nodes2->get(0));
398 if (end >= 0) {
399 int32_t i = 0;
400 if (mType == txEXSLTType::TRAILING) {
401 i = end + 1;
402 end = nodes1->size();
404 for (; i < end; ++i) {
405 rv = resultSet->append(nodes1->get(i));
406 NS_ENSURE_SUCCESS(rv, rv);
410 NS_ADDREF(*aResult = resultSet);
412 return NS_OK;
414 case txEXSLTType::CONCAT: {
415 RefPtr<txNodeSet> nodes;
416 rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes));
417 NS_ENSURE_SUCCESS(rv, rv);
419 nsAutoString str;
420 int32_t i, len = nodes->size();
421 for (i = 0; i < len; ++i) {
422 txXPathNodeUtils::appendNodeValue(nodes->get(i), str);
425 return aContext->recycler()->getStringResult(str, aResult);
427 case txEXSLTType::SPLIT:
428 case txEXSLTType::TOKENIZE: {
429 // Evaluate parameters
430 nsAutoString string;
431 rv = mParams[0]->evaluateToString(aContext, string);
432 NS_ENSURE_SUCCESS(rv, rv);
434 nsAutoString pattern;
435 if (mParams.Length() == 2) {
436 rv = mParams[1]->evaluateToString(aContext, pattern);
437 NS_ENSURE_SUCCESS(rv, rv);
438 } else if (mType == txEXSLTType::SPLIT) {
439 pattern.Assign(' ');
440 } else {
441 pattern.AssignLiteral("\t\r\n ");
444 // Set up holders for the result
445 Document* sourceDoc = getSourceDocument(aContext);
446 NS_ENSURE_STATE(sourceDoc);
448 RefPtr<DocumentFragment> docFrag = new (sourceDoc->NodeInfoManager())
449 DocumentFragment(sourceDoc->NodeInfoManager());
451 RefPtr<txNodeSet> resultSet;
452 rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
453 NS_ENSURE_SUCCESS(rv, rv);
455 uint32_t tailIndex;
457 // Start splitting
458 if (pattern.IsEmpty()) {
459 nsString::const_char_iterator start = string.BeginReading();
460 nsString::const_char_iterator end = string.EndReading();
461 for (; start < end; ++start) {
462 rv = createAndAddToResult(nsGkAtoms::token,
463 Substring(start, start + 1), resultSet,
464 docFrag);
465 NS_ENSURE_SUCCESS(rv, rv);
468 tailIndex = string.Length();
469 } else if (mType == txEXSLTType::SPLIT) {
470 nsAString::const_iterator strStart, strEnd;
471 string.BeginReading(strStart);
472 string.EndReading(strEnd);
473 nsAString::const_iterator start = strStart, end = strEnd;
475 while (FindInReadable(pattern, start, end)) {
476 if (start != strStart) {
477 rv = createAndAddToResult(nsGkAtoms::token,
478 Substring(strStart, start), resultSet,
479 docFrag);
480 NS_ENSURE_SUCCESS(rv, rv);
482 strStart = start = end;
483 end = strEnd;
486 tailIndex = strStart.get() - string.get();
487 } else {
488 int32_t found, start = 0;
489 while ((found = string.FindCharInSet(pattern, start)) != kNotFound) {
490 if (found != start) {
491 rv = createAndAddToResult(nsGkAtoms::token,
492 Substring(string, start, found - start),
493 resultSet, docFrag);
494 NS_ENSURE_SUCCESS(rv, rv);
496 start = found + 1;
499 tailIndex = start;
502 // Add tail if needed
503 if (tailIndex != (uint32_t)string.Length()) {
504 rv = createAndAddToResult(
505 nsGkAtoms::token, Substring(string, tailIndex), resultSet, docFrag);
506 NS_ENSURE_SUCCESS(rv, rv);
509 NS_ADDREF(*aResult = resultSet);
511 return NS_OK;
513 case txEXSLTType::MAX:
514 case txEXSLTType::MIN: {
515 RefPtr<txNodeSet> nodes;
516 rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes));
517 NS_ENSURE_SUCCESS(rv, rv);
519 if (nodes->isEmpty()) {
520 return aContext->recycler()->getNumberResult(UnspecifiedNaN<double>(),
521 aResult);
524 bool findMax = mType == txEXSLTType::MAX;
526 double res = findMax ? mozilla::NegativeInfinity<double>()
527 : mozilla::PositiveInfinity<double>();
528 int32_t i, len = nodes->size();
529 for (i = 0; i < len; ++i) {
530 nsAutoString str;
531 txXPathNodeUtils::appendNodeValue(nodes->get(i), str);
532 double val = txDouble::toDouble(str);
533 if (std::isnan(val)) {
534 res = UnspecifiedNaN<double>();
535 break;
538 if (findMax ? (val > res) : (val < res)) {
539 res = val;
543 return aContext->recycler()->getNumberResult(res, aResult);
545 case txEXSLTType::HIGHEST:
546 case txEXSLTType::LOWEST: {
547 RefPtr<txNodeSet> nodes;
548 rv = evaluateToNodeSet(mParams[0], aContext, getter_AddRefs(nodes));
549 NS_ENSURE_SUCCESS(rv, rv);
551 if (nodes->isEmpty()) {
552 NS_ADDREF(*aResult = nodes);
554 return NS_OK;
557 RefPtr<txNodeSet> resultSet;
558 rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
559 NS_ENSURE_SUCCESS(rv, rv);
561 bool findMax = mType == txEXSLTType::HIGHEST;
562 double res = findMax ? mozilla::NegativeInfinity<double>()
563 : mozilla::PositiveInfinity<double>();
564 int32_t i, len = nodes->size();
565 for (i = 0; i < len; ++i) {
566 nsAutoString str;
567 const txXPathNode& node = nodes->get(i);
568 txXPathNodeUtils::appendNodeValue(node, str);
569 double val = txDouble::toDouble(str);
570 if (std::isnan(val)) {
571 resultSet->clear();
572 break;
574 if (findMax ? (val > res) : (val < res)) {
575 resultSet->clear();
576 res = val;
579 if (res == val) {
580 rv = resultSet->append(node);
581 NS_ENSURE_SUCCESS(rv, rv);
585 NS_ADDREF(*aResult = resultSet);
587 return NS_OK;
589 case txEXSLTType::DATE_TIME: {
590 // http://exslt.org/date/functions/date-time/
592 PRExplodedTime prtime;
593 PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prtime);
595 int32_t offset =
596 (prtime.tm_params.tp_gmt_offset + prtime.tm_params.tp_dst_offset) /
599 bool isneg = offset < 0;
600 if (isneg) offset = -offset;
602 StringResult* strRes;
603 rv = aContext->recycler()->getStringResult(&strRes);
604 NS_ENSURE_SUCCESS(rv, rv);
606 // format: YYYY-MM-DDTTHH:MM:SS.sss+00:00
607 CopyASCIItoUTF16(
608 nsPrintfCString("%04hd-%02" PRId32 "-%02" PRId32 "T%02" PRId32
609 ":%02" PRId32 ":%02" PRId32 ".%03" PRId32
610 "%c%02" PRId32 ":%02" PRId32,
611 prtime.tm_year, prtime.tm_month + 1, prtime.tm_mday,
612 prtime.tm_hour, prtime.tm_min, prtime.tm_sec,
613 prtime.tm_usec / 10000, isneg ? '-' : '+',
614 offset / 60, offset % 60),
615 strRes->mValue);
617 *aResult = strRes;
619 return NS_OK;
621 default: {
622 aContext->receiveError(u"Internal error"_ns, NS_ERROR_UNEXPECTED);
623 return NS_ERROR_UNEXPECTED;
627 MOZ_ASSERT_UNREACHABLE("Missing return?");
628 return NS_ERROR_UNEXPECTED;
631 Expr::ResultType txEXSLTFunctionCall::getReturnType() {
632 return descriptTable[mType].mReturnType;
635 bool txEXSLTFunctionCall::isSensitiveTo(ContextSensitivity aContext) {
636 if (mType == txEXSLTType::NODE_SET || mType == txEXSLTType::SPLIT ||
637 mType == txEXSLTType::TOKENIZE) {
638 return (aContext & PRIVATE_CONTEXT) || argsSensitiveTo(aContext);
640 return argsSensitiveTo(aContext);
643 #ifdef TX_TO_STRING
644 void txEXSLTFunctionCall::appendName(nsAString& aDest) {
645 aDest.Append(descriptTable[mType].mName->GetUTF16String());
647 #endif
649 nsresult txEXSLTRegExFunctionCall::evaluate(txIEvalContext* aContext,
650 txAExprResult** aResult) {
651 *aResult = nullptr;
652 if (!requireParams(descriptTable[mType].mMinParams,
653 descriptTable[mType].mMaxParams, aContext)) {
654 return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
657 nsAutoString string;
658 nsresult rv = mParams[0]->evaluateToString(aContext, string);
659 NS_ENSURE_SUCCESS(rv, rv);
661 nsAutoString regex;
662 rv = mParams[1]->evaluateToString(aContext, regex);
663 NS_ENSURE_SUCCESS(rv, rv);
665 nsAutoString flags;
666 if (mParams.Length() >= 3) {
667 rv = mParams[2]->evaluateToString(aContext, flags);
668 NS_ENSURE_SUCCESS(rv, rv);
671 nsCOMPtr<txIEXSLTFunctions> funcs =
672 do_ImportESModule("resource://gre/modules/txEXSLTRegExFunctions.sys.mjs");
673 MOZ_ALWAYS_TRUE(funcs);
675 switch (mType) {
676 case txEXSLTType::MATCH: {
677 nsCOMPtr<Document> sourceDoc = getSourceDocument(aContext);
678 NS_ENSURE_STATE(sourceDoc);
680 RefPtr<DocumentFragment> docFrag;
681 rv = funcs->Match(string, regex, flags, sourceDoc,
682 getter_AddRefs(docFrag));
683 NS_ENSURE_SUCCESS(rv, rv);
684 NS_ENSURE_STATE(docFrag);
686 RefPtr<txNodeSet> resultSet;
687 rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
688 NS_ENSURE_SUCCESS(rv, rv);
690 UniquePtr<txXPathNode> node;
691 for (nsIContent* result = docFrag->GetFirstChild(); result;
692 result = result->GetNextSibling()) {
693 node = WrapUnique(txXPathNativeNode::createXPathNode(result, true));
694 rv = resultSet->add(*node);
695 NS_ENSURE_SUCCESS(rv, rv);
698 resultSet.forget(aResult);
700 return NS_OK;
702 case txEXSLTType::REPLACE: {
703 nsAutoString replace;
704 rv = mParams[3]->evaluateToString(aContext, replace);
705 NS_ENSURE_SUCCESS(rv, rv);
707 nsAutoString result;
708 rv = funcs->Replace(string, regex, flags, replace, result);
709 NS_ENSURE_SUCCESS(rv, rv);
711 rv = aContext->recycler()->getStringResult(result, aResult);
712 NS_ENSURE_SUCCESS(rv, rv);
714 return NS_OK;
716 case txEXSLTType::TEST: {
717 bool result;
718 rv = funcs->Test(string, regex, flags, &result);
719 NS_ENSURE_SUCCESS(rv, rv);
721 aContext->recycler()->getBoolResult(result, aResult);
723 return NS_OK;
725 default: {
726 aContext->receiveError(u"Internal error"_ns, NS_ERROR_UNEXPECTED);
727 return NS_ERROR_UNEXPECTED;
731 MOZ_ASSERT_UNREACHABLE("Missing return?");
732 return NS_ERROR_UNEXPECTED;
735 Expr::ResultType txEXSLTRegExFunctionCall::getReturnType() {
736 return descriptTable[mType].mReturnType;
739 bool txEXSLTRegExFunctionCall::isSensitiveTo(ContextSensitivity aContext) {
740 if (mType == txEXSLTType::MATCH) {
741 return (aContext & PRIVATE_CONTEXT) || argsSensitiveTo(aContext);
743 return argsSensitiveTo(aContext);
746 #ifdef TX_TO_STRING
747 void txEXSLTRegExFunctionCall::appendName(nsAString& aDest) {
748 aDest.Append(descriptTable[mType].mName->GetUTF16String());
750 #endif
752 extern nsresult TX_ConstructEXSLTFunction(nsAtom* aName, int32_t aNamespaceID,
753 txStylesheetCompilerState* aState,
754 FunctionCall** aResult) {
755 for (auto i : MakeEnumeratedRange(txEXSLTType::_LIMIT)) {
756 const txEXSLTFunctionDescriptor& desc = descriptTable[i];
757 if (aName == desc.mName && aNamespaceID == desc.mNamespaceID) {
758 return desc.mCreator(i, aResult) ? NS_OK : NS_ERROR_FAILURE;
762 return NS_ERROR_XPATH_UNKNOWN_FUNCTION;
765 extern bool TX_InitEXSLTFunction() {
766 #define EXSLT_FUNCS(NS, CLASS, ...) \
768 int32_t nsid = txNamespaceManager::getNamespaceID(nsLiteralString(NS)); \
769 if (nsid == kNameSpaceID_Unknown) { \
770 return false; \
772 MOZ_FOR_EACH(EXSLT_FUNC, (nsid, CLASS, ), (__VA_ARGS__)) \
775 #define EXSLT_FUNC(NS, CLASS, ...) \
776 descriptTable[txEXSLTType::MOZ_ARG_1 __VA_ARGS__] = { \
777 MOZ_ARGS_AFTER_1 __VA_ARGS__, CLASS::Create, NS};
779 EXSLT_FUNCS(u"http://exslt.org/common", txEXSLTFunctionCall,
780 (NODE_SET, 1, 1, Expr::NODESET_RESULT, nsGkAtoms::nodeSet),
781 (OBJECT_TYPE, 1, 1, Expr::STRING_RESULT, nsGkAtoms::objectType))
783 EXSLT_FUNCS(u"http://exslt.org/dates-and-times", txEXSLTFunctionCall,
784 (DATE_TIME, 0, 0, Expr::STRING_RESULT, nsGkAtoms::dateTime))
786 EXSLT_FUNCS(u"http://exslt.org/math", txEXSLTFunctionCall,
787 (MAX, 1, 1, Expr::NUMBER_RESULT, nsGkAtoms::max),
788 (MIN, 1, 1, Expr::NUMBER_RESULT, nsGkAtoms::min),
789 (HIGHEST, 1, 1, Expr::NODESET_RESULT, nsGkAtoms::highest),
790 (LOWEST, 1, 1, Expr::NODESET_RESULT, nsGkAtoms::lowest))
792 EXSLT_FUNCS(u"http://exslt.org/regular-expressions", txEXSLTRegExFunctionCall,
793 (MATCH, 2, 3, Expr::NODESET_RESULT, nsGkAtoms::match),
794 (REPLACE, 4, 4, Expr::STRING_RESULT, nsGkAtoms::replace),
795 (TEST, 2, 3, Expr::BOOLEAN_RESULT, nsGkAtoms::test))
797 EXSLT_FUNCS(
798 u"http://exslt.org/sets", txEXSLTFunctionCall,
799 (DIFFERENCE_, 2, 2, Expr::NODESET_RESULT, nsGkAtoms::difference),
800 (DISTINCT, 1, 1, Expr::NODESET_RESULT, nsGkAtoms::distinct),
801 (HAS_SAME_NODE, 2, 2, Expr::BOOLEAN_RESULT, nsGkAtoms::hasSameNode),
802 (INTERSECTION, 2, 2, Expr::NODESET_RESULT, nsGkAtoms::intersection),
803 (LEADING, 2, 2, Expr::NODESET_RESULT, nsGkAtoms::leading),
804 (TRAILING, 2, 2, Expr::NODESET_RESULT, nsGkAtoms::trailing))
806 EXSLT_FUNCS(u"http://exslt.org/strings", txEXSLTFunctionCall,
807 (CONCAT, 1, 1, Expr::STRING_RESULT, nsGkAtoms::concat),
808 (SPLIT, 1, 2, Expr::STRING_RESULT, nsGkAtoms::split),
809 (TOKENIZE, 1, 2, Expr::STRING_RESULT, nsGkAtoms::tokenize))
811 #undef EXSLT_FUNCS
812 #undef EXSLT_FUNC
813 #undef EXSLT_FUNC_HELPER
814 #undef EXSLT_FUNC_HELPER2
816 return true;