зеркало из https://github.com/mozilla/pjs.git
Bug 324775. Merge some classes to reduce binary and source size. r/sr=peterv
This commit is contained in:
Родитель
d1a93b96b9
Коммит
991e5e3fbe
|
@ -64,26 +64,23 @@ REQUIRES += dom \
|
|||
$(NULL)
|
||||
endif
|
||||
|
||||
CPPSRCS = txAdditiveExpr.cpp \
|
||||
CPPSRCS = \
|
||||
txBooleanExpr.cpp \
|
||||
txBooleanFunctionCall.cpp \
|
||||
txBooleanResult.cpp \
|
||||
txCoreFunctionCall.cpp \
|
||||
txExpr.cpp \
|
||||
txExprLexer.cpp \
|
||||
txExprParser.cpp \
|
||||
txFilterExpr.cpp \
|
||||
txFunctionCall.cpp \
|
||||
txLocationStep.cpp \
|
||||
txMultiplicativeExpr.cpp \
|
||||
txNodeSetFunctionCall.cpp \
|
||||
txNumberFunctionCall.cpp \
|
||||
txNumberExpr.cpp \
|
||||
txNumberResult.cpp \
|
||||
txPathExpr.cpp \
|
||||
txPredicatedNodeTest.cpp \
|
||||
txPredicateList.cpp \
|
||||
txRelationalExpr.cpp \
|
||||
txRootExpr.cpp \
|
||||
txStringFunctionCall.cpp \
|
||||
txStringResult.cpp \
|
||||
txErrorExpr.cpp \
|
||||
txLiteralExpr.cpp \
|
||||
|
|
|
@ -0,0 +1,787 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is TransforMiiX XSLT processor code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The MITRE Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Keith Visco <kvisco@ziplink.net> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "txExpr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "txNodeSet.h"
|
||||
#include "txAtoms.h"
|
||||
#include "txIXPathContext.h"
|
||||
#include "txTokenizer.h"
|
||||
#include "txXPathTreeWalker.h"
|
||||
#include <math.h>
|
||||
#include "txStringUtils.h"
|
||||
|
||||
struct txFunctionDescriptor
|
||||
{
|
||||
PRInt8 mMinParams;
|
||||
PRInt8 mMaxParams;
|
||||
Expr::ResultType mReturnType;
|
||||
nsIAtom** mName;
|
||||
};
|
||||
|
||||
// This must be ordered in the same order as txCoreFunctionCall::eType.
|
||||
// If you change one, change the other.
|
||||
static const txFunctionDescriptor const descriptTable[] =
|
||||
{
|
||||
{ 1, 1, Expr::NUMBER_RESULT, &txXPathAtoms::count }, // COUNT
|
||||
{ 1, 1, Expr::NODESET_RESULT, &txXPathAtoms::id }, // ID
|
||||
{ 0, 0, Expr::NUMBER_RESULT, &txXPathAtoms::last }, // LAST
|
||||
{ 0, 1, Expr::STRING_RESULT, &txXPathAtoms::localName }, // LOCAL_NAME
|
||||
{ 0, 1, Expr::STRING_RESULT, &txXPathAtoms::namespaceUri }, // NAMESPACE_URI
|
||||
{ 0, 1, Expr::STRING_RESULT, &txXPathAtoms::name }, // NAME
|
||||
{ 0, 0, Expr::NUMBER_RESULT, &txXPathAtoms::position }, // POSITION
|
||||
|
||||
{ 2, -1, Expr::STRING_RESULT, &txXPathAtoms::concat }, // CONCAT
|
||||
{ 2, 2, Expr::BOOLEAN_RESULT, &txXPathAtoms::contains }, // CONTAINS
|
||||
{ 0, 1, Expr::STRING_RESULT, &txXPathAtoms::normalizeSpace }, // NORMALIZE_SPACE
|
||||
{ 2, 2, Expr::BOOLEAN_RESULT, &txXPathAtoms::startsWith }, // STARTS_WITH
|
||||
{ 0, 1, Expr::STRING_RESULT, &txXPathAtoms::string }, // STRING
|
||||
{ 0, 1, Expr::NUMBER_RESULT, &txXPathAtoms::stringLength }, // STRING_LENGTH
|
||||
{ 2, 3, Expr::STRING_RESULT, &txXPathAtoms::substring }, // SUBSTRING
|
||||
{ 2, 2, Expr::STRING_RESULT, &txXPathAtoms::substringAfter }, // SUBSTRING_AFTER
|
||||
{ 2, 2, Expr::STRING_RESULT, &txXPathAtoms::substringBefore }, // SUBSTRING_BEFORE
|
||||
{ 3, 3, Expr::STRING_RESULT, &txXPathAtoms::translate }, // TRANSLATE
|
||||
|
||||
{ 0, 1, Expr::NUMBER_RESULT, &txXPathAtoms::number }, // NUMBER
|
||||
{ 1, 1, Expr::NUMBER_RESULT, &txXPathAtoms::round }, // ROUND
|
||||
{ 1, 1, Expr::NUMBER_RESULT, &txXPathAtoms::floor }, // FLOOR
|
||||
{ 1, 1, Expr::NUMBER_RESULT, &txXPathAtoms::ceiling }, // CEILING
|
||||
{ 1, 1, Expr::NUMBER_RESULT, &txXPathAtoms::sum }, // SUM
|
||||
|
||||
{ 1, 1, Expr::BOOLEAN_RESULT, &txXPathAtoms::boolean }, // BOOLEAN
|
||||
{ 0, 0, Expr::BOOLEAN_RESULT, &txXPathAtoms::_false }, // _FALSE
|
||||
{ 1, 1, Expr::BOOLEAN_RESULT, &txXPathAtoms::lang }, // LANG
|
||||
{ 1, 1, Expr::BOOLEAN_RESULT, &txXPathAtoms::_not }, // _NOT
|
||||
{ 0, 0, Expr::BOOLEAN_RESULT, &txXPathAtoms::_true } // _TRUE
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Evaluates this Expr based on the given context node and processor state
|
||||
* @param context the context node for evaluation of this Expr
|
||||
* @param ps the ContextState containing the stack information needed
|
||||
* for evaluation
|
||||
* @return the result of the evaluation
|
||||
*/
|
||||
nsresult
|
||||
txCoreFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
|
||||
if (!requireParams(descriptTable[mType].mMinParams,
|
||||
descriptTable[mType].mMaxParams,
|
||||
aContext)) {
|
||||
return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
txListIterator iter(¶ms);
|
||||
|
||||
switch (mType) {
|
||||
case COUNT:
|
||||
{
|
||||
nsRefPtr<txNodeSet> nodes;
|
||||
rv = evaluateToNodeSet((Expr*)iter.next(), aContext,
|
||||
getter_AddRefs(nodes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return aContext->recycler()->getNumberResult(nodes->size(),
|
||||
aResult);
|
||||
}
|
||||
case ID:
|
||||
{
|
||||
nsRefPtr<txAExprResult> exprResult;
|
||||
rv = ((Expr*)iter.next())->evaluate(aContext,
|
||||
getter_AddRefs(exprResult));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsRefPtr<txNodeSet> resultSet;
|
||||
rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
txXPathTreeWalker walker(aContext->getContextNode());
|
||||
|
||||
if (exprResult->getResultType() == txAExprResult::NODESET) {
|
||||
txNodeSet* nodes = NS_STATIC_CAST(txNodeSet*,
|
||||
NS_STATIC_CAST(txAExprResult*,
|
||||
exprResult));
|
||||
PRInt32 i;
|
||||
for (i = 0; i < nodes->size(); ++i) {
|
||||
nsAutoString idList;
|
||||
txXPathNodeUtils::appendNodeValue(nodes->get(i), idList);
|
||||
txTokenizer tokenizer(idList);
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
if (walker.moveToElementById(tokenizer.nextToken())) {
|
||||
resultSet->add(walker.getCurrentPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
nsAutoString idList;
|
||||
exprResult->stringValue(idList);
|
||||
txTokenizer tokenizer(idList);
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
if (walker.moveToElementById(tokenizer.nextToken())) {
|
||||
resultSet->add(walker.getCurrentPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*aResult = resultSet;
|
||||
NS_ADDREF(*aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
case LAST:
|
||||
{
|
||||
return aContext->recycler()->getNumberResult(aContext->size(),
|
||||
aResult);
|
||||
}
|
||||
case LOCAL_NAME:
|
||||
case NAME:
|
||||
case NAMESPACE_URI:
|
||||
{
|
||||
// Check for optional arg
|
||||
nsRefPtr<txNodeSet> nodes;
|
||||
if (iter.hasNext()) {
|
||||
rv = evaluateToNodeSet((Expr*)iter.next(), aContext,
|
||||
getter_AddRefs(nodes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (nodes->isEmpty()) {
|
||||
aContext->recycler()->getEmptyStringResult(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
const txXPathNode& node = nodes ? nodes->get(0) :
|
||||
aContext->getContextNode();
|
||||
switch (mType) {
|
||||
case LOCAL_NAME:
|
||||
{
|
||||
StringResult* strRes = nsnull;
|
||||
rv = aContext->recycler()->getStringResult(&strRes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aResult = strRes;
|
||||
txXPathNodeUtils::getLocalName(node, strRes->mValue);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
case NAMESPACE_URI:
|
||||
{
|
||||
StringResult* strRes = nsnull;
|
||||
rv = aContext->recycler()->getStringResult(&strRes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aResult = strRes;
|
||||
txXPathNodeUtils::getNamespaceURI(node, strRes->mValue);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
case NAME:
|
||||
{
|
||||
// XXX Namespace: namespaces have a name
|
||||
if (txXPathNodeUtils::isAttribute(node) ||
|
||||
txXPathNodeUtils::isElement(node) ||
|
||||
txXPathNodeUtils::isProcessingInstruction(node)) {
|
||||
StringResult* strRes = nsnull;
|
||||
rv = aContext->recycler()->getStringResult(&strRes);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aResult = strRes;
|
||||
txXPathNodeUtils::getNodeName(node, strRes->mValue);
|
||||
}
|
||||
else {
|
||||
aContext->recycler()->getEmptyStringResult(aResult);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
case POSITION:
|
||||
{
|
||||
return aContext->recycler()->getNumberResult(aContext->position(),
|
||||
aResult);
|
||||
}
|
||||
|
||||
// String functions
|
||||
|
||||
case CONCAT:
|
||||
{
|
||||
nsRefPtr<StringResult> strRes;
|
||||
rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
while (iter.hasNext()) {
|
||||
Expr* param = NS_STATIC_CAST(Expr*, iter.next());
|
||||
rv = param->evaluateToString(aContext, strRes->mValue);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
NS_ADDREF(*aResult = strRes);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
case CONTAINS:
|
||||
{
|
||||
Expr* arg1Expr = NS_STATIC_CAST(Expr*, iter.next());
|
||||
Expr* arg2Expr = NS_STATIC_CAST(Expr*, iter.next());
|
||||
|
||||
nsAutoString arg2;
|
||||
rv = arg2Expr->evaluateToString(aContext, arg2);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (arg2.IsEmpty()) {
|
||||
aContext->recycler()->getBoolResult(PR_TRUE, aResult);
|
||||
}
|
||||
else {
|
||||
nsAutoString arg1;
|
||||
rv = arg1Expr->evaluateToString(aContext, arg1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aContext->recycler()->getBoolResult(FindInReadable(arg2, arg1),
|
||||
aResult);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
case NORMALIZE_SPACE:
|
||||
{
|
||||
nsAutoString resultStr;
|
||||
if (iter.hasNext()) {
|
||||
Expr* param = NS_STATIC_CAST(Expr*, iter.next());
|
||||
rv = param->evaluateToString(aContext, resultStr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else {
|
||||
txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
|
||||
resultStr);
|
||||
}
|
||||
|
||||
nsRefPtr<StringResult> strRes;
|
||||
rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
MBool addSpace = MB_FALSE;
|
||||
MBool first = MB_TRUE;
|
||||
strRes->mValue.SetCapacity(resultStr.Length());
|
||||
PRUnichar c;
|
||||
PRUint32 src;
|
||||
for (src = 0; src < resultStr.Length(); src++) {
|
||||
c = resultStr.CharAt(src);
|
||||
if (XMLUtils::isWhitespace(c)) {
|
||||
addSpace = MB_TRUE;
|
||||
}
|
||||
else {
|
||||
if (addSpace && !first)
|
||||
strRes->mValue.Append(PRUnichar(' '));
|
||||
|
||||
strRes->mValue.Append(c);
|
||||
addSpace = MB_FALSE;
|
||||
first = MB_FALSE;
|
||||
}
|
||||
}
|
||||
*aResult = strRes;
|
||||
NS_ADDREF(*aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
case STARTS_WITH:
|
||||
{
|
||||
Expr* arg1Expr = NS_STATIC_CAST(Expr*, iter.next());
|
||||
Expr* arg2Expr = NS_STATIC_CAST(Expr*, iter.next());
|
||||
|
||||
nsAutoString arg2;
|
||||
rv = arg2Expr->evaluateToString(aContext, arg2);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRBool result;
|
||||
if (arg2.IsEmpty()) {
|
||||
result = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
nsAutoString arg1;
|
||||
rv = arg1Expr->evaluateToString(aContext, arg1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
result = StringBeginsWith(arg1, arg2);
|
||||
}
|
||||
|
||||
aContext->recycler()->getBoolResult(result, aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
case STRING:
|
||||
{
|
||||
nsRefPtr<StringResult> strRes;
|
||||
rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (iter.hasNext()) {
|
||||
Expr* param = NS_STATIC_CAST(Expr*, iter.next());
|
||||
rv = param->evaluateToString(aContext, strRes->mValue);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else {
|
||||
txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
|
||||
strRes->mValue);
|
||||
}
|
||||
|
||||
NS_ADDREF(*aResult = strRes);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
case STRING_LENGTH:
|
||||
{
|
||||
nsAutoString resultStr;
|
||||
if (iter.hasNext()) {
|
||||
Expr* arg1Expr = NS_STATIC_CAST(Expr*, iter.next());
|
||||
rv = arg1Expr->evaluateToString(aContext, resultStr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else {
|
||||
txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
|
||||
resultStr);
|
||||
}
|
||||
rv = aContext->recycler()->getNumberResult(resultStr.Length(),
|
||||
aResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
case SUBSTRING:
|
||||
{
|
||||
Expr* param = NS_STATIC_CAST(Expr*, iter.next());
|
||||
|
||||
nsAutoString src;
|
||||
rv = param->evaluateToString(aContext, src);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
double start = evaluateToNumber(NS_STATIC_CAST(Expr*, iter.next()),
|
||||
aContext);
|
||||
|
||||
// check for NaN or +/-Inf
|
||||
if (Double::isNaN(start) ||
|
||||
Double::isInfinite(start) ||
|
||||
start >= src.Length() + 0.5) {
|
||||
aContext->recycler()->getEmptyStringResult(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
start = floor(start + 0.5) - 1;
|
||||
|
||||
double end;
|
||||
if (iter.hasNext()) {
|
||||
end = start + evaluateToNumber((Expr*)iter.next(),
|
||||
aContext);
|
||||
if (Double::isNaN(end) || end < 0) {
|
||||
aContext->recycler()->getEmptyStringResult(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (end > src.Length())
|
||||
end = src.Length();
|
||||
else
|
||||
end = floor(end + 0.5);
|
||||
}
|
||||
else {
|
||||
end = src.Length();
|
||||
}
|
||||
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
|
||||
if (start > end) {
|
||||
aContext->recycler()->getEmptyStringResult(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return aContext->recycler()->getStringResult(
|
||||
Substring(src, (PRUint32)start, (PRUint32)(end - start)),
|
||||
aResult);
|
||||
}
|
||||
case SUBSTRING_AFTER:
|
||||
{
|
||||
Expr* arg1Expr = NS_STATIC_CAST(Expr*, iter.next());
|
||||
nsAutoString arg1;
|
||||
rv = arg1Expr->evaluateToString(aContext, arg1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
Expr* arg2Expr = NS_STATIC_CAST(Expr*, iter.next());
|
||||
nsAutoString arg2;
|
||||
rv = arg2Expr->evaluateToString(aContext, arg2);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (arg2.IsEmpty()) {
|
||||
return aContext->recycler()->getStringResult(arg1, aResult);
|
||||
}
|
||||
|
||||
PRInt32 idx = arg1.Find(arg2);
|
||||
if (idx == kNotFound) {
|
||||
aContext->recycler()->getEmptyStringResult(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const nsSubstring& result = Substring(arg1, idx + arg2.Length());
|
||||
return aContext->recycler()->getStringResult(result, aResult);
|
||||
}
|
||||
case SUBSTRING_BEFORE:
|
||||
{
|
||||
Expr* arg1Expr = NS_STATIC_CAST(Expr*, iter.next());
|
||||
Expr* arg2Expr = NS_STATIC_CAST(Expr*, iter.next());
|
||||
|
||||
nsAutoString arg2;
|
||||
rv = arg2Expr->evaluateToString(aContext, arg2);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (arg2.IsEmpty()) {
|
||||
aContext->recycler()->getEmptyStringResult(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoString arg1;
|
||||
rv = arg1Expr->evaluateToString(aContext, arg1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRInt32 idx = arg1.Find(arg2);
|
||||
if (idx == kNotFound) {
|
||||
aContext->recycler()->getEmptyStringResult(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return aContext->recycler()->getStringResult(StringHead(arg1, idx),
|
||||
aResult);
|
||||
}
|
||||
case TRANSLATE:
|
||||
{
|
||||
Expr* arg1Expr = NS_STATIC_CAST(Expr*, iter.next());
|
||||
|
||||
nsAutoString src;
|
||||
rv = arg1Expr->evaluateToString(aContext, src);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (src.IsEmpty()) {
|
||||
aContext->recycler()->getEmptyStringResult(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<StringResult> strRes;
|
||||
rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
strRes->mValue.SetCapacity(src.Length());
|
||||
|
||||
Expr* arg2Expr = NS_STATIC_CAST(Expr*, iter.next());
|
||||
Expr* arg3Expr = NS_STATIC_CAST(Expr*, iter.next());
|
||||
|
||||
nsAutoString oldChars, newChars;
|
||||
rv = arg2Expr->evaluateToString(aContext, oldChars);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = arg3Expr->evaluateToString(aContext, newChars);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 i;
|
||||
PRInt32 newCharsLength = (PRInt32)newChars.Length();
|
||||
for (i = 0; i < src.Length(); i++) {
|
||||
PRInt32 idx = oldChars.FindChar(src.CharAt(i));
|
||||
if (idx != kNotFound) {
|
||||
if (idx < newCharsLength)
|
||||
strRes->mValue.Append(newChars.CharAt((PRUint32)idx));
|
||||
}
|
||||
else {
|
||||
strRes->mValue.Append(src.CharAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
NS_ADDREF(*aResult = strRes);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Number functions
|
||||
|
||||
case NUMBER:
|
||||
{
|
||||
double res;
|
||||
if (iter.hasNext()) {
|
||||
res = evaluateToNumber((Expr*)iter.next(), aContext);
|
||||
}
|
||||
else {
|
||||
nsAutoString resultStr;
|
||||
txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
|
||||
resultStr);
|
||||
res = Double::toDouble(resultStr);
|
||||
}
|
||||
return aContext->recycler()->getNumberResult(res, aResult);
|
||||
}
|
||||
case ROUND:
|
||||
{
|
||||
double dbl = evaluateToNumber((Expr*)iter.next(), aContext);
|
||||
if (!Double::isNaN(dbl) && !Double::isInfinite(dbl)) {
|
||||
if (Double::isNeg(dbl) && dbl >= -0.5) {
|
||||
dbl *= 0;
|
||||
}
|
||||
else {
|
||||
dbl = floor(dbl + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
return aContext->recycler()->getNumberResult(dbl, aResult);
|
||||
}
|
||||
case FLOOR:
|
||||
{
|
||||
double dbl = evaluateToNumber((Expr*)iter.next(), aContext);
|
||||
if (!Double::isNaN(dbl) &&
|
||||
!Double::isInfinite(dbl) &&
|
||||
!(dbl == 0 && Double::isNeg(dbl))) {
|
||||
dbl = floor(dbl);
|
||||
}
|
||||
|
||||
return aContext->recycler()->getNumberResult(dbl, aResult);
|
||||
}
|
||||
case CEILING:
|
||||
{
|
||||
double dbl = evaluateToNumber((Expr*)iter.next(), aContext);
|
||||
if (!Double::isNaN(dbl) && !Double::isInfinite(dbl)) {
|
||||
if (Double::isNeg(dbl) && dbl > -1) {
|
||||
dbl *= 0;
|
||||
}
|
||||
else {
|
||||
dbl = ceil(dbl);
|
||||
}
|
||||
}
|
||||
|
||||
return aContext->recycler()->getNumberResult(dbl, aResult);
|
||||
}
|
||||
case SUM:
|
||||
{
|
||||
nsRefPtr<txNodeSet> nodes;
|
||||
nsresult rv = evaluateToNodeSet((Expr*)iter.next(), aContext,
|
||||
getter_AddRefs(nodes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
double res = 0;
|
||||
PRInt32 i;
|
||||
for (i = 0; i < nodes->size(); ++i) {
|
||||
nsAutoString resultStr;
|
||||
txXPathNodeUtils::appendNodeValue(nodes->get(i), resultStr);
|
||||
res += Double::toDouble(resultStr);
|
||||
}
|
||||
return aContext->recycler()->getNumberResult(res, aResult);
|
||||
}
|
||||
|
||||
// Boolean functions
|
||||
|
||||
case BOOLEAN:
|
||||
{
|
||||
Expr* param = NS_STATIC_CAST(Expr*, iter.next());
|
||||
PRBool result;
|
||||
nsresult rv = param->evaluateToBool(aContext, result);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aContext->recycler()->getBoolResult(result, aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
case _FALSE:
|
||||
{
|
||||
aContext->recycler()->getBoolResult(PR_FALSE, aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
case LANG:
|
||||
{
|
||||
txXPathTreeWalker walker(aContext->getContextNode());
|
||||
|
||||
nsAutoString lang;
|
||||
PRBool found;
|
||||
do {
|
||||
found = walker.getAttr(txXMLAtoms::lang, kNameSpaceID_XML,
|
||||
lang);
|
||||
} while (!found && walker.moveToParent());
|
||||
|
||||
if (!found) {
|
||||
aContext->recycler()->getBoolResult(PR_FALSE, aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoString arg;
|
||||
Expr* param = NS_STATIC_CAST(Expr*, iter.next());
|
||||
nsresult rv = param->evaluateToString(aContext, arg);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRBool result = arg.Equals(Substring(lang, 0, arg.Length()),
|
||||
txCaseInsensitiveStringComparator()) &&
|
||||
(lang.Length() == arg.Length() ||
|
||||
lang.CharAt(arg.Length()) == '-');
|
||||
|
||||
aContext->recycler()->getBoolResult(result, aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
case _NOT:
|
||||
{
|
||||
Expr* param = NS_STATIC_CAST(Expr*, iter.next());
|
||||
PRBool result;
|
||||
nsresult rv = param->evaluateToBool(aContext, result);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aContext->recycler()->getBoolResult(!result, aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
case _TRUE:
|
||||
{
|
||||
aContext->recycler()->getBoolResult(PR_TRUE, aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
aContext->receiveError(NS_LITERAL_STRING("Internal error"),
|
||||
NS_ERROR_UNEXPECTED);
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
Expr::ResultType
|
||||
txCoreFunctionCall::getReturnType()
|
||||
{
|
||||
return descriptTable[mType].mReturnType;
|
||||
}
|
||||
|
||||
PRBool
|
||||
txCoreFunctionCall::isSensitiveTo(ContextSensitivity aContext)
|
||||
{
|
||||
switch (mType) {
|
||||
case COUNT:
|
||||
case CONCAT:
|
||||
case CONTAINS:
|
||||
case STARTS_WITH:
|
||||
case SUBSTRING:
|
||||
case SUBSTRING_AFTER:
|
||||
case SUBSTRING_BEFORE:
|
||||
case TRANSLATE:
|
||||
case ROUND:
|
||||
case FLOOR:
|
||||
case CEILING:
|
||||
case SUM:
|
||||
case BOOLEAN:
|
||||
case _NOT:
|
||||
case _FALSE:
|
||||
case _TRUE:
|
||||
{
|
||||
return argsSensitiveTo(aContext);
|
||||
}
|
||||
case ID:
|
||||
{
|
||||
return (aContext & DOCUMENT_CONTEXT) ||
|
||||
argsSensitiveTo(aContext);
|
||||
}
|
||||
case LAST:
|
||||
{
|
||||
return !!(aContext & SIZE_CONTEXT);
|
||||
}
|
||||
case LOCAL_NAME:
|
||||
case NAME:
|
||||
case NAMESPACE_URI:
|
||||
case NORMALIZE_SPACE:
|
||||
case STRING:
|
||||
case STRING_LENGTH:
|
||||
case NUMBER:
|
||||
{
|
||||
if (params.isEmpty()) {
|
||||
return !!(aContext & NODE_CONTEXT);
|
||||
}
|
||||
return argsSensitiveTo(aContext);
|
||||
}
|
||||
case POSITION:
|
||||
{
|
||||
return !!(aContext & POSITION_CONTEXT);
|
||||
}
|
||||
case LANG:
|
||||
{
|
||||
return (aContext & NODE_CONTEXT) ||
|
||||
argsSensitiveTo(aContext);
|
||||
}
|
||||
}
|
||||
|
||||
NS_NOTREACHED("how'd we get here?");
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// static
|
||||
PRBool
|
||||
txCoreFunctionCall::getTypeFromAtom(nsIAtom* aName, eType& aType)
|
||||
{
|
||||
PRUint32 i;
|
||||
for (i = 0; i < NS_ARRAY_LENGTH(descriptTable); ++i) {
|
||||
if (aName == *descriptTable[i].mName) {
|
||||
aType = NS_STATIC_CAST(eType, i);
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
#ifdef TX_TO_STRING
|
||||
nsresult
|
||||
txCoreFunctionCall::getNameAtom(nsIAtom** aAtom)
|
||||
{
|
||||
NS_ADDREF(*aAtom = *descriptTable[mType].mName);
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
|
@ -323,8 +323,6 @@ protected:
|
|||
|
||||
txList params;
|
||||
|
||||
FunctionCall();
|
||||
|
||||
/*
|
||||
* Evaluates the given Expression and converts its result to a number.
|
||||
*/
|
||||
|
@ -351,27 +349,58 @@ protected:
|
|||
#endif
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Represents an AttributeValueTemplate
|
||||
**/
|
||||
class AttributeValueTemplate: public Expr {
|
||||
|
||||
class txCoreFunctionCall : public FunctionCall
|
||||
{
|
||||
public:
|
||||
|
||||
AttributeValueTemplate();
|
||||
// This must be ordered in the same order as descriptTable in
|
||||
// txCoreFunctionCall.cpp. If you change one, change the other.
|
||||
enum eType {
|
||||
COUNT = 0, // count()
|
||||
ID, // id()
|
||||
LAST, // last()
|
||||
LOCAL_NAME, // local-name()
|
||||
NAMESPACE_URI, // namespace-uri()
|
||||
NAME, // name()
|
||||
POSITION, // position()
|
||||
|
||||
virtual ~AttributeValueTemplate();
|
||||
CONCAT, // concat()
|
||||
CONTAINS, // contains()
|
||||
NORMALIZE_SPACE, // normalize-space()
|
||||
STARTS_WITH, // starts-with()
|
||||
STRING, // string()
|
||||
STRING_LENGTH, // string-length()
|
||||
SUBSTRING, // substring()
|
||||
SUBSTRING_AFTER, // substring-after()
|
||||
SUBSTRING_BEFORE, // substring-before()
|
||||
TRANSLATE, // translate()
|
||||
|
||||
/**
|
||||
* Adds the given Expr to this AttributeValueTemplate
|
||||
**/
|
||||
void addExpr(Expr* expr);
|
||||
NUMBER, // number()
|
||||
ROUND, // round()
|
||||
FLOOR, // floor()
|
||||
CEILING, // ceiling()
|
||||
SUM, // sum()
|
||||
|
||||
TX_DECL_EXPR;
|
||||
BOOLEAN, // boolean()
|
||||
_FALSE, // false()
|
||||
LANG, // lang()
|
||||
_NOT, // not()
|
||||
_TRUE // true()
|
||||
};
|
||||
|
||||
/*
|
||||
* Creates a txCoreFunctionCall of the given type
|
||||
*/
|
||||
txCoreFunctionCall(eType aType) : mType(aType)
|
||||
{
|
||||
}
|
||||
|
||||
TX_DECL_FUNCTION;
|
||||
|
||||
static PRBool getTypeFromAtom(nsIAtom* aName, eType& aType);
|
||||
|
||||
private:
|
||||
List expressions;
|
||||
eType mType;
|
||||
};
|
||||
|
||||
|
||||
|
@ -705,8 +734,8 @@ public:
|
|||
TX_DECL_EXPR;
|
||||
|
||||
private:
|
||||
short op;
|
||||
nsAutoPtr<Expr> leftExpr, rightExpr;
|
||||
short op;
|
||||
}; //-- BooleanExpr
|
||||
|
||||
/**
|
||||
|
@ -717,28 +746,26 @@ private:
|
|||
* div : divide
|
||||
*
|
||||
**/
|
||||
class MultiplicativeExpr : public Expr {
|
||||
class txNumberExpr : public Expr {
|
||||
|
||||
public:
|
||||
|
||||
//-- MultiplicativeExpr Types
|
||||
//-- LF, changed from static const short to enum
|
||||
enum _MultiplicativeExprType { DIVIDE = 1, MULTIPLY, MODULUS };
|
||||
enum eOp { ADD, SUBTRACT, DIVIDE, MULTIPLY, MODULUS };
|
||||
|
||||
MultiplicativeExpr(nsAutoPtr<Expr>& aLeftExpr,
|
||||
nsAutoPtr<Expr>& aRightExpr,
|
||||
short aOp)
|
||||
: op(aOp),
|
||||
leftExpr(aLeftExpr),
|
||||
rightExpr(aRightExpr)
|
||||
txNumberExpr(nsAutoPtr<Expr>& aLeftExpr,
|
||||
nsAutoPtr<Expr>& aRightExpr,
|
||||
eOp aOp)
|
||||
: mLeftExpr(aLeftExpr),
|
||||
mRightExpr(aRightExpr),
|
||||
mOp(aOp)
|
||||
{
|
||||
}
|
||||
|
||||
TX_DECL_EXPR;
|
||||
|
||||
private:
|
||||
short op;
|
||||
nsAutoPtr<Expr> leftExpr, rightExpr;
|
||||
nsAutoPtr<Expr> mLeftExpr, mRightExpr;
|
||||
eOp mOp;
|
||||
}; //-- MultiplicativeExpr
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
|
||||
#include "txExprParser.h"
|
||||
#include "txExprLexer.h"
|
||||
#include "txFunctionLib.h"
|
||||
#include "txExpr.h"
|
||||
#include "txStack.h"
|
||||
#include "txAtoms.h"
|
||||
#include "txError.h"
|
||||
|
@ -151,7 +151,7 @@ txExprParser::createAVT(const nsSubstring& aAttrValue,
|
|||
}
|
||||
else {
|
||||
if (!concat) {
|
||||
concat = new StringFunctionCall(StringFunctionCall::CONCAT);
|
||||
concat = new txCoreFunctionCall(txCoreFunctionCall::CONCAT);
|
||||
NS_ENSURE_TRUE(concat, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = concat->addParam(expr.forget());
|
||||
|
@ -233,12 +233,21 @@ txExprParser::createBinaryExpr(nsAutoPtr<Expr>& left, nsAutoPtr<Expr>& right,
|
|||
|
||||
Expr* expr = nsnull;
|
||||
switch (op->mType) {
|
||||
//-- additive ops
|
||||
//-- math ops
|
||||
case Token::ADDITION_OP :
|
||||
expr = new AdditiveExpr(left, right, AdditiveExpr::ADDITION);
|
||||
expr = new txNumberExpr(left, right, txNumberExpr::ADD);
|
||||
break;
|
||||
case Token::SUBTRACTION_OP:
|
||||
expr = new AdditiveExpr(left, right, AdditiveExpr::SUBTRACTION);
|
||||
expr = new txNumberExpr(left, right, txNumberExpr::SUBTRACT);
|
||||
break;
|
||||
case Token::DIVIDE_OP :
|
||||
expr = new txNumberExpr(left, right, txNumberExpr::DIVIDE);
|
||||
break;
|
||||
case Token::MODULUS_OP :
|
||||
expr = new txNumberExpr(left, right, txNumberExpr::MODULUS);
|
||||
break;
|
||||
case Token::MULTIPLY_OP :
|
||||
expr = new txNumberExpr(left, right, txNumberExpr::MULTIPLY);
|
||||
break;
|
||||
|
||||
//-- case boolean ops
|
||||
|
@ -274,19 +283,6 @@ txExprParser::createBinaryExpr(nsAutoPtr<Expr>& left, nsAutoPtr<Expr>& right,
|
|||
RelationalExpr::GREATER_OR_EQUAL);
|
||||
break;
|
||||
|
||||
//-- multiplicative ops
|
||||
case Token::DIVIDE_OP :
|
||||
expr = new MultiplicativeExpr(left, right,
|
||||
MultiplicativeExpr::DIVIDE);
|
||||
break;
|
||||
case Token::MODULUS_OP :
|
||||
expr = new MultiplicativeExpr(left, right,
|
||||
MultiplicativeExpr::MODULUS);
|
||||
break;
|
||||
case Token::MULTIPLY_OP :
|
||||
expr = new MultiplicativeExpr(left, right,
|
||||
MultiplicativeExpr::MULTIPLY);
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("operator tokens should be already checked");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
@ -459,97 +455,12 @@ txExprParser::createFunctionCall(txExprLexer& lexer, txIParseContext* aContext,
|
|||
getter_AddRefs(lName), namespaceID);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (namespaceID == kNameSpaceID_None) {
|
||||
PRBool isOutOfMem = PR_TRUE;
|
||||
if (lName == txXPathAtoms::boolean) {
|
||||
fnCall = new BooleanFunctionCall(BooleanFunctionCall::TX_BOOLEAN);
|
||||
}
|
||||
else if (lName == txXPathAtoms::concat) {
|
||||
fnCall = new StringFunctionCall(StringFunctionCall::CONCAT);
|
||||
}
|
||||
else if (lName == txXPathAtoms::contains) {
|
||||
fnCall = new StringFunctionCall(StringFunctionCall::CONTAINS);
|
||||
}
|
||||
else if (lName == txXPathAtoms::count) {
|
||||
fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::COUNT);
|
||||
}
|
||||
else if (lName == txXPathAtoms::_false) {
|
||||
fnCall = new BooleanFunctionCall(BooleanFunctionCall::TX_FALSE);
|
||||
}
|
||||
else if (lName == txXPathAtoms::id) {
|
||||
fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::ID);
|
||||
}
|
||||
else if (lName == txXPathAtoms::lang) {
|
||||
fnCall = new BooleanFunctionCall(BooleanFunctionCall::TX_LANG);
|
||||
}
|
||||
else if (lName == txXPathAtoms::last) {
|
||||
fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::LAST);
|
||||
}
|
||||
else if (lName == txXPathAtoms::localName) {
|
||||
fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::LOCAL_NAME);
|
||||
}
|
||||
else if (lName == txXPathAtoms::name) {
|
||||
fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::NAME);
|
||||
}
|
||||
else if (lName == txXPathAtoms::namespaceUri) {
|
||||
fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::NAMESPACE_URI);
|
||||
}
|
||||
else if (lName == txXPathAtoms::normalizeSpace) {
|
||||
fnCall = new StringFunctionCall(StringFunctionCall::NORMALIZE_SPACE);
|
||||
}
|
||||
else if (lName == txXPathAtoms::_not) {
|
||||
fnCall = new BooleanFunctionCall(BooleanFunctionCall::TX_NOT);
|
||||
}
|
||||
else if (lName == txXPathAtoms::position) {
|
||||
fnCall = new NodeSetFunctionCall(NodeSetFunctionCall::POSITION);
|
||||
}
|
||||
else if (lName == txXPathAtoms::startsWith) {
|
||||
fnCall = new StringFunctionCall(StringFunctionCall::STARTS_WITH);
|
||||
}
|
||||
else if (lName == txXPathAtoms::string) {
|
||||
fnCall = new StringFunctionCall(StringFunctionCall::STRING);
|
||||
}
|
||||
else if (lName == txXPathAtoms::stringLength) {
|
||||
fnCall = new StringFunctionCall(StringFunctionCall::STRING_LENGTH);
|
||||
}
|
||||
else if (lName == txXPathAtoms::substring) {
|
||||
fnCall = new StringFunctionCall(StringFunctionCall::SUBSTRING);
|
||||
}
|
||||
else if (lName == txXPathAtoms::substringAfter) {
|
||||
fnCall = new StringFunctionCall(StringFunctionCall::SUBSTRING_AFTER);
|
||||
}
|
||||
else if (lName == txXPathAtoms::substringBefore) {
|
||||
fnCall = new StringFunctionCall(StringFunctionCall::SUBSTRING_BEFORE);
|
||||
}
|
||||
else if (lName == txXPathAtoms::sum) {
|
||||
fnCall = new NumberFunctionCall(NumberFunctionCall::SUM);
|
||||
}
|
||||
else if (lName == txXPathAtoms::translate) {
|
||||
fnCall = new StringFunctionCall(StringFunctionCall::TRANSLATE);
|
||||
}
|
||||
else if (lName == txXPathAtoms::_true) {
|
||||
fnCall = new BooleanFunctionCall(BooleanFunctionCall::TX_TRUE);
|
||||
}
|
||||
else if (lName == txXPathAtoms::number) {
|
||||
fnCall = new NumberFunctionCall(NumberFunctionCall::NUMBER);
|
||||
}
|
||||
else if (lName == txXPathAtoms::round) {
|
||||
fnCall = new NumberFunctionCall(NumberFunctionCall::ROUND);
|
||||
}
|
||||
else if (lName == txXPathAtoms::ceiling) {
|
||||
fnCall = new NumberFunctionCall(NumberFunctionCall::CEILING);
|
||||
}
|
||||
else if (lName == txXPathAtoms::floor) {
|
||||
fnCall = new NumberFunctionCall(NumberFunctionCall::FLOOR);
|
||||
}
|
||||
else {
|
||||
// didn't find functioncall here, fnCall should be null
|
||||
isOutOfMem = PR_FALSE;
|
||||
}
|
||||
if (!fnCall && isOutOfMem) {
|
||||
NS_ERROR("XPath FunctionLib failed on out-of-memory");
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
txCoreFunctionCall::eType type;
|
||||
if (namespaceID == kNameSpaceID_None &&
|
||||
txCoreFunctionCall::getTypeFromAtom(lName, type)) {
|
||||
// It is a known built-in function.
|
||||
fnCall = new txCoreFunctionCall(type);
|
||||
NS_ENSURE_TRUE(fnCall, NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
// check extension functions and xslt
|
||||
if (!fnCall) {
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "txFunctionLib.h"
|
||||
#include "txExpr.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "txIXPathContext.h"
|
||||
#include "txNodeSet.h"
|
||||
|
@ -45,10 +45,6 @@
|
|||
* This class represents a FunctionCall as defined by the XSL Working Draft
|
||||
**/
|
||||
|
||||
FunctionCall::FunctionCall()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
**/
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is TransforMiiX XSLT processor code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The MITRE Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Keith Visco <kvisco@ziplink.net> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "txExpr.h"
|
||||
#include <math.h>
|
||||
#include "txIXPathContext.h"
|
||||
|
||||
nsresult
|
||||
txNumberExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
|
||||
nsRefPtr<txAExprResult> exprRes;
|
||||
nsresult rv = mRightExpr->evaluate(aContext, getter_AddRefs(exprRes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
double rightDbl = exprRes->numberValue();
|
||||
|
||||
rv = mLeftExpr->evaluate(aContext, getter_AddRefs(exprRes));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
double leftDbl = exprRes->numberValue();
|
||||
double result = 0;
|
||||
|
||||
switch (mOp) {
|
||||
case ADD:
|
||||
result = leftDbl + rightDbl;
|
||||
break;
|
||||
|
||||
case SUBTRACT:
|
||||
result = leftDbl - rightDbl;
|
||||
break;
|
||||
|
||||
case DIVIDE:
|
||||
if (rightDbl == 0) {
|
||||
#if defined(XP_WIN)
|
||||
/* XXX MSVC miscompiles such that (NaN == 0) */
|
||||
if (Double::isNaN(rightDbl))
|
||||
result = Double::NaN;
|
||||
else
|
||||
#endif
|
||||
if (leftDbl == 0 || Double::isNaN(leftDbl))
|
||||
result = Double::NaN;
|
||||
else if (Double::isNeg(leftDbl) ^ Double::isNeg(rightDbl))
|
||||
result = Double::NEGATIVE_INFINITY;
|
||||
else
|
||||
result = Double::POSITIVE_INFINITY;
|
||||
}
|
||||
else
|
||||
result = leftDbl / rightDbl;
|
||||
break;
|
||||
|
||||
case MODULUS:
|
||||
if (rightDbl == 0) {
|
||||
result = Double::NaN;
|
||||
}
|
||||
else {
|
||||
#if defined(XP_WIN)
|
||||
/* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
|
||||
if (!Double::isInfinite(leftDbl) && Double::isInfinite(rightDbl))
|
||||
result = leftDbl;
|
||||
else
|
||||
#endif
|
||||
result = fmod(leftDbl, rightDbl);
|
||||
}
|
||||
break;
|
||||
|
||||
case MULTIPLY:
|
||||
result = leftDbl * rightDbl;
|
||||
break;
|
||||
}
|
||||
|
||||
return aContext->recycler()->getNumberResult(result, aResult);
|
||||
} //-- evaluate
|
||||
|
||||
TX_IMPL_EXPR_STUBS_2(txNumberExpr, NUMBER_RESULT, mLeftExpr, mRightExpr)
|
||||
|
||||
PRBool
|
||||
txNumberExpr::isSensitiveTo(ContextSensitivity aContext)
|
||||
{
|
||||
return mLeftExpr->isSensitiveTo(aContext) ||
|
||||
mRightExpr->isSensitiveTo(aContext);
|
||||
}
|
||||
|
||||
#ifdef TX_TO_STRING
|
||||
void
|
||||
txNumberExpr::toString(nsAString& str)
|
||||
{
|
||||
mLeftExpr->toString(str);
|
||||
|
||||
switch (mOp) {
|
||||
case ADD:
|
||||
str.AppendLiteral(" + ");
|
||||
break;
|
||||
case SUBTRACT:
|
||||
str.AppendLiteral(" - ");
|
||||
break;
|
||||
case DIVIDE:
|
||||
str.AppendLiteral(" div ");
|
||||
break;
|
||||
case MODULUS:
|
||||
str.AppendLiteral(" mod ");
|
||||
break;
|
||||
case MULTIPLY:
|
||||
str.AppendLiteral(" * ");
|
||||
break;
|
||||
}
|
||||
|
||||
mRightExpr->toString(str);
|
||||
|
||||
}
|
||||
#endif
|
|
@ -41,7 +41,7 @@
|
|||
* A representation of the XPath NodeSet funtions
|
||||
*/
|
||||
|
||||
#include "txFunctionLib.h"
|
||||
#include "txExpr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "txNodeSet.h"
|
||||
#include "txAtoms.h"
|
||||
|
|
|
@ -101,12 +101,10 @@ CPPSRCS = \
|
|||
txUnknownHandler.cpp \
|
||||
txCurrentFunctionCall.cpp \
|
||||
txDocumentFunctionCall.cpp \
|
||||
txElementAvailableFnCall.cpp \
|
||||
txFormatNumberFunctionCall.cpp \
|
||||
txFunctionAvailableFnCall.cpp \
|
||||
txGenerateIdFunctionCall.cpp \
|
||||
txKeyFunctionCall.cpp \
|
||||
txSystemPropertyFunctionCall.cpp
|
||||
txXSLTEnvironmentFunctionCall.cpp
|
||||
|
||||
ifdef MOZ_XSLT_STANDALONE
|
||||
CPPSRCS += txHTMLOutput.cpp \
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
#include "txExpandedNameMap.h"
|
||||
#include "txList.h"
|
||||
#include "txXSLTPatterns.h"
|
||||
#include "txXSLTFunctions.h"
|
||||
#include "nsVoidArray.h"
|
||||
|
||||
class txInstruction;
|
||||
|
@ -52,6 +51,7 @@ class txTemplateItem;
|
|||
class txVariableItem;
|
||||
class txStripSpaceItem;
|
||||
class txAttributeSetItem;
|
||||
class txDecimalFormat;
|
||||
|
||||
class txStylesheet
|
||||
{
|
||||
|
|
|
@ -966,21 +966,25 @@ txStylesheetCompilerState::resolveFunctionCall(nsIAtom* aName, PRInt32 aID,
|
|||
return NS_OK;
|
||||
}
|
||||
if (aName == txXSLTAtoms::systemProperty) {
|
||||
aFunction = new SystemPropertyFunctionCall(mElementContext->mMappings);
|
||||
aFunction = new txXSLTEnvironmentFunctionCall(
|
||||
txXSLTEnvironmentFunctionCall::SYSTEM_PROPERTY,
|
||||
mElementContext->mMappings);
|
||||
NS_ENSURE_TRUE(aFunction, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
if (aName == txXSLTAtoms::elementAvailable) {
|
||||
aFunction =
|
||||
new ElementAvailableFunctionCall(mElementContext->mMappings);
|
||||
aFunction = new txXSLTEnvironmentFunctionCall(
|
||||
txXSLTEnvironmentFunctionCall::ELEMENT_AVAILABLE,
|
||||
mElementContext->mMappings);
|
||||
NS_ENSURE_TRUE(aFunction, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
if (aName == txXSLTAtoms::functionAvailable) {
|
||||
aFunction =
|
||||
new FunctionAvailableFunctionCall(mElementContext->mMappings);
|
||||
aFunction = new txXSLTEnvironmentFunctionCall(
|
||||
txXSLTEnvironmentFunctionCall::FUNCTION_AVAILABLE,
|
||||
mElementContext->mMappings);
|
||||
NS_ENSURE_TRUE(aFunction, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is TransforMiiX XSLT processor code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Axel Hecht.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Axel Hecht <axel@pike.org>
|
||||
*
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "txIXPathContext.h"
|
||||
#include "txAtoms.h"
|
||||
#include "txError.h"
|
||||
#include "txXMLUtils.h"
|
||||
#include "txXSLTFunctions.h"
|
||||
#include "txNamespaceMap.h"
|
||||
|
||||
nsresult
|
||||
txXSLTEnvironmentFunctionCall::evaluate(txIEvalContext* aContext,
|
||||
txAExprResult** aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
|
||||
if (!requireParams(1, 1, aContext)) {
|
||||
return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
|
||||
}
|
||||
|
||||
txListIterator iter(¶ms);
|
||||
Expr* param = (Expr*)iter.next();
|
||||
|
||||
nsAutoString property;
|
||||
nsresult rv = param->evaluateToString(aContext, property);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
txExpandedName qname;
|
||||
rv = qname.init(property, mMappings, mType != FUNCTION_AVAILABLE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
switch (mType) {
|
||||
case SYSTEM_PROPERTY:
|
||||
{
|
||||
if (qname.mNamespaceID == kNameSpaceID_XSLT) {
|
||||
if (qname.mLocalName == txXSLTAtoms::version) {
|
||||
return aContext->recycler()->getNumberResult(1.0, aResult);
|
||||
}
|
||||
if (qname.mLocalName == txXSLTAtoms::vendor) {
|
||||
return aContext->recycler()->getStringResult(
|
||||
NS_LITERAL_STRING("Transformiix"), aResult);
|
||||
}
|
||||
if (qname.mLocalName == txXSLTAtoms::vendorUrl) {
|
||||
return aContext->recycler()->getStringResult(
|
||||
NS_LITERAL_STRING("http://www.mozilla.org/projects/xslt/"),
|
||||
aResult);
|
||||
}
|
||||
}
|
||||
aContext->recycler()->getEmptyStringResult(aResult);
|
||||
break;
|
||||
}
|
||||
case ELEMENT_AVAILABLE:
|
||||
{
|
||||
PRBool val = qname.mNamespaceID == kNameSpaceID_XSLT &&
|
||||
(qname.mLocalName == txXSLTAtoms::applyImports ||
|
||||
qname.mLocalName == txXSLTAtoms::applyTemplates ||
|
||||
qname.mLocalName == txXSLTAtoms::attribute ||
|
||||
qname.mLocalName == txXSLTAtoms::attributeSet ||
|
||||
qname.mLocalName == txXSLTAtoms::callTemplate ||
|
||||
qname.mLocalName == txXSLTAtoms::choose ||
|
||||
qname.mLocalName == txXSLTAtoms::comment ||
|
||||
qname.mLocalName == txXSLTAtoms::copy ||
|
||||
qname.mLocalName == txXSLTAtoms::copyOf ||
|
||||
qname.mLocalName == txXSLTAtoms::decimalFormat ||
|
||||
qname.mLocalName == txXSLTAtoms::element ||
|
||||
qname.mLocalName == txXSLTAtoms::fallback ||
|
||||
qname.mLocalName == txXSLTAtoms::forEach ||
|
||||
qname.mLocalName == txXSLTAtoms::_if ||
|
||||
qname.mLocalName == txXSLTAtoms::import ||
|
||||
qname.mLocalName == txXSLTAtoms::include ||
|
||||
qname.mLocalName == txXSLTAtoms::key ||
|
||||
qname.mLocalName == txXSLTAtoms::message ||
|
||||
//qname.mLocalName == txXSLTAtoms::namespaceAlias ||
|
||||
qname.mLocalName == txXSLTAtoms::number ||
|
||||
qname.mLocalName == txXSLTAtoms::otherwise ||
|
||||
qname.mLocalName == txXSLTAtoms::output ||
|
||||
qname.mLocalName == txXSLTAtoms::param ||
|
||||
qname.mLocalName == txXSLTAtoms::preserveSpace ||
|
||||
qname.mLocalName == txXSLTAtoms::processingInstruction ||
|
||||
qname.mLocalName == txXSLTAtoms::sort ||
|
||||
qname.mLocalName == txXSLTAtoms::stripSpace ||
|
||||
qname.mLocalName == txXSLTAtoms::stylesheet ||
|
||||
qname.mLocalName == txXSLTAtoms::_template ||
|
||||
qname.mLocalName == txXSLTAtoms::text ||
|
||||
qname.mLocalName == txXSLTAtoms::transform ||
|
||||
qname.mLocalName == txXSLTAtoms::valueOf ||
|
||||
qname.mLocalName == txXSLTAtoms::variable ||
|
||||
qname.mLocalName == txXSLTAtoms::when ||
|
||||
qname.mLocalName == txXSLTAtoms::withParam);
|
||||
|
||||
aContext->recycler()->getBoolResult(val, aResult);
|
||||
break;
|
||||
}
|
||||
case FUNCTION_AVAILABLE:
|
||||
{
|
||||
txCoreFunctionCall::eType type;
|
||||
PRBool val = qname.mNamespaceID == kNameSpaceID_None &&
|
||||
(txCoreFunctionCall::getTypeFromAtom(qname.mLocalName, type) ||
|
||||
qname.mLocalName == txXSLTAtoms::current ||
|
||||
qname.mLocalName == txXSLTAtoms::document ||
|
||||
qname.mLocalName == txXSLTAtoms::elementAvailable ||
|
||||
qname.mLocalName == txXSLTAtoms::formatNumber ||
|
||||
qname.mLocalName == txXSLTAtoms::functionAvailable ||
|
||||
qname.mLocalName == txXSLTAtoms::generateId ||
|
||||
qname.mLocalName == txXSLTAtoms::key ||
|
||||
//qname.mLocalName == txXSLTAtoms::unparsedEntityUri ||
|
||||
qname.mLocalName == txXSLTAtoms::systemProperty);
|
||||
|
||||
aContext->recycler()->getBoolResult(val, aResult);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
Expr::ResultType
|
||||
txXSLTEnvironmentFunctionCall::getReturnType()
|
||||
{
|
||||
return mType == SYSTEM_PROPERTY ? (STRING_RESULT | NUMBER_RESULT) :
|
||||
BOOLEAN_RESULT;
|
||||
}
|
||||
|
||||
PRBool
|
||||
txXSLTEnvironmentFunctionCall::isSensitiveTo(ContextSensitivity aContext)
|
||||
{
|
||||
return argsSensitiveTo(aContext);
|
||||
}
|
||||
|
||||
#ifdef TX_TO_STRING
|
||||
nsresult
|
||||
txXSLTEnvironmentFunctionCall::getNameAtom(nsIAtom** aAtom)
|
||||
{
|
||||
*aAtom = mType == SYSTEM_PROPERTY ? txXSLTAtoms::systemProperty :
|
||||
mType == ELEMENT_AVAILABLE ? txXSLTAtoms::elementAvailable :
|
||||
txXSLTAtoms::functionAvailable;
|
||||
NS_ADDREF(*aAtom);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
|
@ -41,12 +41,12 @@
|
|||
#include "txExpr.h"
|
||||
#include "txXMLUtils.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "txNamespaceMap.h"
|
||||
|
||||
class txPattern;
|
||||
class txStylesheet;
|
||||
class txKeyValueHashKey;
|
||||
class txExecutionState;
|
||||
class txNamespaceMap;
|
||||
|
||||
/**
|
||||
* The definition for the XSLT document() function
|
||||
|
@ -156,23 +156,6 @@ public:
|
|||
TX_DECL_FUNCTION;
|
||||
};
|
||||
|
||||
/**
|
||||
* The definition for the XSLT unparsed-entity-uri() function
|
||||
**/
|
||||
class UnparsedEntityUriFunctionCall : public FunctionCall {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a new unparsed-entity-uri() function call
|
||||
**/
|
||||
UnparsedEntityUriFunctionCall();
|
||||
|
||||
TX_DECL_FUNCTION;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
/**
|
||||
* The definition for the XSLT generate-id() function
|
||||
**/
|
||||
|
@ -188,71 +171,26 @@ public:
|
|||
TX_DECL_FUNCTION;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The definition for the XSLT system-property() function
|
||||
**/
|
||||
class SystemPropertyFunctionCall : public FunctionCall {
|
||||
|
||||
* A system-property(), element-available() or function-available() function.
|
||||
*/
|
||||
class txXSLTEnvironmentFunctionCall : public FunctionCall
|
||||
{
|
||||
public:
|
||||
enum eType { SYSTEM_PROPERTY, ELEMENT_AVAILABLE, FUNCTION_AVAILABLE };
|
||||
|
||||
/**
|
||||
* Creates a new system-property() function call
|
||||
* aNode is the Element in the stylesheet containing the
|
||||
* Expr and is used for namespaceID resolution
|
||||
**/
|
||||
SystemPropertyFunctionCall(txNamespaceMap* aMappings);
|
||||
txXSLTEnvironmentFunctionCall(eType aType, txNamespaceMap* aMappings)
|
||||
: mType(aType),
|
||||
mMappings(aMappings)
|
||||
{
|
||||
}
|
||||
|
||||
TX_DECL_FUNCTION;
|
||||
|
||||
private:
|
||||
/*
|
||||
* resolve namespaceIDs with this node
|
||||
*/
|
||||
nsRefPtr<txNamespaceMap> mMappings;
|
||||
};
|
||||
|
||||
/**
|
||||
* The definition for the XSLT element-available() function
|
||||
**/
|
||||
class ElementAvailableFunctionCall : public FunctionCall {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a new element-available() function call
|
||||
* aNode is the Element in the stylesheet containing the
|
||||
* Expr and is used for namespaceID resolution
|
||||
**/
|
||||
ElementAvailableFunctionCall(txNamespaceMap* aMappings);
|
||||
|
||||
TX_DECL_FUNCTION;
|
||||
|
||||
private:
|
||||
/*
|
||||
* resolve namespaceIDs with this node
|
||||
*/
|
||||
nsRefPtr<txNamespaceMap> mMappings;
|
||||
};
|
||||
|
||||
/**
|
||||
* The definition for the XSLT function-available() function
|
||||
**/
|
||||
class FunctionAvailableFunctionCall : public FunctionCall {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a new function-available() function call
|
||||
**/
|
||||
FunctionAvailableFunctionCall(txNamespaceMap* aMappings);
|
||||
|
||||
TX_DECL_FUNCTION;
|
||||
|
||||
private:
|
||||
/*
|
||||
* resolve namespaceIDs with this node
|
||||
*/
|
||||
nsRefPtr<txNamespaceMap> mMappings;
|
||||
eType mType;
|
||||
nsRefPtr<txNamespaceMap> mMappings; // Used to resolve prefixes
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче