/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "txStylesheetCompileHandlers.h"
#include <utility>
#include "mozilla/ArrayUtils.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/UniquePtrExtensions.h"
#include "nsGkAtoms.h"
#include "nsWhitespaceTokenizer.h"
#include "txCore.h"
#include "txInstructions.h"
#include "txNamespaceMap.h"
#include "txPatternParser.h"
#include "txStringUtils.h"
#include "txStylesheet.h"
#include "txStylesheetCompiler.h"
#include "txToplevelItems.h"
#include "txURIUtils.h"
#include "txXSLTFunctions.h"
#include "nsStringFlags.h"
#include "nsStyleUtil.h"
#include "nsStringIterator.h"
using namespace mozilla;
txHandlerTable* gTxIgnoreHandler = 0;
txHandlerTable* gTxRootHandler = 0;
txHandlerTable* gTxEmbedHandler = 0;
txHandlerTable* gTxTopHandler = 0;
txHandlerTable* gTxTemplateHandler = 0;
txHandlerTable* gTxTextHandler = 0;
txHandlerTable* gTxApplyTemplatesHandler = 0;
txHandlerTable* gTxCallTemplateHandler = 0;
txHandlerTable* gTxVariableHandler = 0;
txHandlerTable* gTxForEachHandler = 0;
txHandlerTable* gTxTopVariableHandler = 0;
txHandlerTable* gTxChooseHandler = 0;
txHandlerTable* gTxParamHandler = 0;
txHandlerTable* gTxImportHandler = 0;
txHandlerTable* gTxAttributeSetHandler = 0;
txHandlerTable* gTxFallbackHandler = 0;
static nsresult txFnStartLRE(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState);
static void txFnEndLRE(txStylesheetCompilerState& aState);
#define TX_RETURN_IF_WHITESPACE(_str, _state) \
do { \
if (!_state.mElementContext->mPreserveWhitespace && \
XMLUtils::isWhitespace(_str)) { \
return NS_OK; \
} \
}
while (0)
static nsresult getStyleAttr(txStylesheetAttr* aAttributes, int32_t aAttrCount,
int32_t aNamespace, nsAtom* aName,
bool aRequired,
txStylesheetAttr** aAttr) {
int32_t i;
for (i = 0; i < aAttrCount; ++i) {
txStylesheetAttr* attr = aAttributes + i;
if (attr->mNamespaceID == aNamespace && attr->mLocalName == aName) {
attr->mLocalName = nullptr;
*aAttr = attr;
return NS_OK;
}
}
*aAttr = nullptr;
if (aRequired) {
// XXX ErrorReport: missing required attribute
return NS_ERROR_XSLT_PARSE_FAILURE;
}
return NS_OK;
}
static nsresult parseUseAttrSets(txStylesheetAttr* aAttributes,
int32_t aAttrCount,
bool aInXSLTNS,
txStylesheetCompilerState& aState) {
txStylesheetAttr* attr = nullptr;
nsresult rv = getStyleAttr(aAttributes, aAttrCount,
aInXSLTNS ? kNameSpaceID_XSLT : kNameSpaceID_None,
nsGkAtoms::useAttributeSets,
false, &attr);
if (!attr) {
return rv;
}
nsWhitespaceTokenizer tok(attr->mValue);
while (tok.hasMoreTokens()) {
txExpandedName name;
rv = name.init(tok.nextToken(), aState.mElementContext->mMappings,
false);
NS_ENSURE_SUCCESS(rv, rv);
aState.addInstruction(MakeUnique<txInsertAttrSet>(name));
}
return NS_OK;
}
static nsresult parseExcludeResultPrefixes(txStylesheetAttr* aAttributes,
int32_t aAttrCount,
int32_t aNamespaceID) {
txStylesheetAttr* attr = nullptr;
nsresult rv = getStyleAttr(aAttributes, aAttrCount, aNamespaceID,
nsGkAtoms::excludeResultPrefixes,
false, &attr);
if (!attr) {
return rv;
}
// XXX Needs to be implemented.
return NS_OK;
}
static nsresult getQNameAttr(txStylesheetAttr* aAttributes, int32_t aAttrCount,
nsAtom* aName,
bool aRequired,
txStylesheetCompilerState& aState,
txExpandedName& aExpName) {
aExpName.reset();
txStylesheetAttr* attr = nullptr;
nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None, aName,
aRequired, &attr);
if (!attr) {
return rv;
}
rv = aExpName.init(attr->mValue, aState.mElementContext->mMappings,
false);
if (!aRequired && NS_FAILED(rv) && aState.fcp()) {
aExpName.reset();
rv = NS_OK;
}
return rv;
}
static nsresult getExprAttr(txStylesheetAttr* aAttributes, int32_t aAttrCount,
nsAtom* aName,
bool aRequired,
txStylesheetCompilerState& aState,
UniquePtr<Expr>& aExpr) {
aExpr = nullptr;
txStylesheetAttr* attr = nullptr;
nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None, aName,
aRequired, &attr);
if (!attr) {
return rv;
}
rv = txExprParser::createExpr(attr->mValue, &aState, getter_Transfers(aExpr));
if (NS_FAILED(rv) && aState.ignoreError(rv)) {
// use default value in fcp for not required exprs
if (aRequired) {
aExpr = MakeUnique<txErrorExpr>(
#ifdef TX_TO_STRING
attr->mValue
#endif
);
}
else {
aExpr = nullptr;
}
return NS_OK;
}
return rv;
}
static nsresult getAVTAttr(txStylesheetAttr* aAttributes, int32_t aAttrCount,
nsAtom* aName,
bool aRequired,
txStylesheetCompilerState& aState,
UniquePtr<Expr>& aAVT) {
aAVT = nullptr;
txStylesheetAttr* attr = nullptr;
nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None, aName,
aRequired, &attr);
if (!attr) {
return rv;
}
rv = txExprParser::createAVT(attr->mValue, &aState, getter_Transfers(aAVT));
if (NS_FAILED(rv) && aState.fcp()) {
// use default value in fcp for not required exprs
if (aRequired) {
aAVT = MakeUnique<txErrorExpr>(
#ifdef TX_TO_STRING
attr->mValue
#endif
);
}
else {
aAVT = nullptr;
}
return NS_OK;
}
return rv;
}
static nsresult getPatternAttr(txStylesheetAttr* aAttributes,
int32_t aAttrCount, nsAtom* aName,
bool aRequired,
txStylesheetCompilerState& aState,
UniquePtr<txPattern>& aPattern) {
aPattern = nullptr;
txStylesheetAttr* attr = nullptr;
nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None, aName,
aRequired, &attr);
if (!attr) {
return rv;
}
rv = txPatternParser::createPattern(attr->mValue, &aState,
getter_Transfers(aPattern));
if (NS_FAILED(rv) && (aRequired || !aState.ignoreError(rv))) {
// XXX ErrorReport: XSLT-Pattern parse failure
return rv;
}
return NS_OK;
}
static nsresult getNumberAttr(txStylesheetAttr* aAttributes, int32_t aAttrCount,
nsAtom* aName,
bool aRequired,
txStylesheetCompilerState& aState,
double& aNumber) {
aNumber = UnspecifiedNaN<
double>();
txStylesheetAttr* attr = nullptr;
nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None, aName,
aRequired, &attr);
if (!attr) {
return rv;
}
aNumber = txDouble::toDouble(attr->mValue);
if (std::isnan(aNumber) && (aRequired || !aState.fcp())) {
// XXX ErrorReport: number parse failure
return NS_ERROR_XSLT_PARSE_FAILURE;
}
return NS_OK;
}
static nsresult getAtomAttr(txStylesheetAttr* aAttributes, int32_t aAttrCount,
nsAtom* aName,
bool aRequired,
txStylesheetCompilerState& aState, nsAtom** aAtom) {
*aAtom = nullptr;
txStylesheetAttr* attr = nullptr;
nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None, aName,
aRequired, &attr);
if (!attr) {
return rv;
}
*aAtom = NS_Atomize(attr->mValue).take();
NS_ENSURE_TRUE(*aAtom, NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
}
static nsresult getYesNoAttr(txStylesheetAttr* aAttributes, int32_t aAttrCount,
nsAtom* aName,
bool aRequired,
txStylesheetCompilerState& aState,
txThreeState& aRes) {
aRes = eNotSet;
RefPtr<nsAtom> atom;
nsresult rv = getAtomAttr(aAttributes, aAttrCount, aName, aRequired, aState,
getter_AddRefs(atom));
if (!atom) {
return rv;
}
if (atom == nsGkAtoms::yes) {
aRes = eTrue;
}
else if (atom == nsGkAtoms::no) {
aRes = eFalse;
}
else if (aRequired || !aState.fcp()) {
// XXX ErrorReport: unknown values
return NS_ERROR_XSLT_PARSE_FAILURE;
}
return NS_OK;
}
static nsresult getCharAttr(txStylesheetAttr* aAttributes, int32_t aAttrCount,
nsAtom* aName,
bool aRequired,
txStylesheetCompilerState& aState,
char16_t& aChar) {
// Don't reset aChar since it contains the default value
txStylesheetAttr* attr = nullptr;
nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None, aName,
aRequired, &attr);
if (!attr) {
return rv;
}
if (attr->mValue.Length() == 1) {
aChar = attr->mValue.CharAt(0);
}
else if (aRequired || !aState.fcp()) {
// XXX ErrorReport: not a character
return NS_ERROR_XSLT_PARSE_FAILURE;
}
return NS_OK;
}
static void pushInstruction(txStylesheetCompilerState& aState,
UniquePtr<txInstruction> aInstruction) {
aState.pushObject(aInstruction.release());
}
template <
class T = txInstruction>
static UniquePtr<T> popInstruction(txStylesheetCompilerState& aState) {
return UniquePtr<T>(
static_cast<T*>(aState.popObject()));
}
/**
* Ignore and error handlers
*/
static nsresult txFnTextIgnore(
const nsAString& aStr,
txStylesheetCompilerState& aState) {
return NS_OK;
}
static nsresult txFnTextError(
const nsAString& aStr,
txStylesheetCompilerState& aState) {
TX_RETURN_IF_WHITESPACE(aStr, aState);
return NS_ERROR_XSLT_PARSE_FAILURE;
}
void clearAttributes(txStylesheetAttr* aAttributes, int32_t aAttrCount) {
int32_t i;
for (i = 0; i < aAttrCount; ++i) {
aAttributes[i].mLocalName = nullptr;
}
}
static nsresult txFnStartElementIgnore(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
if (!aState.fcp()) {
clearAttributes(aAttributes, aAttrCount);
}
return NS_OK;
}
static void txFnEndElementIgnore(txStylesheetCompilerState& aState) {}
static nsresult txFnStartElementSetIgnore(int32_t aNamespaceID,
nsAtom* aLocalName, nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
if (!aState.fcp()) {
clearAttributes(aAttributes, aAttrCount);
}
aState.pushHandlerTable(gTxIgnoreHandler);
return NS_OK;
}
static void txFnEndElementSetIgnore(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
}
static nsresult txFnStartElementError(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
return NS_ERROR_XSLT_PARSE_FAILURE;
}
static void txFnEndElementError(txStylesheetCompilerState& aState) {
MOZ_CRASH(
"txFnEndElementError shouldn't be called");
}
/**
* Root handlers
*/
static nsresult txFnStartStylesheet(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
// extension-element-prefixes is handled in
// txStylesheetCompiler::startElementInternal
txStylesheetAttr* attr;
nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
nsGkAtoms::id,
false, &attr);
NS_ENSURE_SUCCESS(rv, rv);
rv = parseExcludeResultPrefixes(aAttributes, aAttrCount, kNameSpaceID_None);
NS_ENSURE_SUCCESS(rv, rv);
rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
nsGkAtoms::version,
true, &attr);
NS_ENSURE_SUCCESS(rv, rv);
aState.pushHandlerTable(gTxImportHandler);
return NS_OK;
}
static void txFnEndStylesheet(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
}
static nsresult txFnStartElementContinueTopLevel(
int32_t aNamespaceID, nsAtom* aLocalName, nsAtom* aPrefix,
txStylesheetAttr* aAttributes, int32_t aAttrCount,
txStylesheetCompilerState& aState) {
aState.mHandlerTable = gTxTopHandler;
return NS_XSLT_GET_NEW_HANDLER;
}
static nsresult txFnStartLREStylesheet(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
txStylesheetAttr* attr;
nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_XSLT,
nsGkAtoms::version,
true, &attr);
NS_ENSURE_SUCCESS(rv, rv);
txExpandedName nullExpr;
double prio = UnspecifiedNaN<
double>();
UniquePtr<txPattern> match(
new txRootPattern());
UniquePtr<txTemplateItem> templ(
new txTemplateItem(std::move(match), nullExpr, nullExpr, prio));
aState.openInstructionContainer(templ.get());
aState.addToplevelItem(templ.release());
aState.pushHandlerTable(gTxTemplateHandler);
return txFnStartLRE(aNamespaceID, aLocalName, aPrefix, aAttributes,
aAttrCount, aState);
}
static void txFnEndLREStylesheet(txStylesheetCompilerState& aState) {
txFnEndLRE(aState);
aState.popHandlerTable();
aState.addInstruction(MakeUnique<txReturn>());
aState.closeInstructionContainer();
}
static nsresult txFnStartEmbed(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
if (!aState.handleEmbeddedSheet()) {
return NS_OK;
}
if (aNamespaceID != kNameSpaceID_XSLT ||
(aLocalName != nsGkAtoms::stylesheet &&
aLocalName != nsGkAtoms::transform)) {
return NS_ERROR_XSLT_PARSE_FAILURE;
}
return txFnStartStylesheet(aNamespaceID, aLocalName, aPrefix, aAttributes,
aAttrCount, aState);
}
static void txFnEndEmbed(txStylesheetCompilerState& aState) {
if (!aState.handleEmbeddedSheet()) {
return;
}
txFnEndStylesheet(aState);
aState.doneEmbedding();
}
/**
* Top handlers
*/
static nsresult txFnStartOtherTop(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
if (aNamespaceID == kNameSpaceID_None ||
(aNamespaceID == kNameSpaceID_XSLT && !aState.fcp())) {
return NS_ERROR_XSLT_PARSE_FAILURE;
}
aState.pushHandlerTable(gTxIgnoreHandler);
return NS_OK;
}
static void txFnEndOtherTop(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
}
// xsl:attribute-set
static nsresult txFnStartAttributeSet(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
txExpandedName name;
rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::name,
true, aState,
name);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<txAttributeSetItem> attrSet(
new txAttributeSetItem(name));
aState.openInstructionContainer(attrSet.get());
aState.addToplevelItem(attrSet.release());
rv = parseUseAttrSets(aAttributes, aAttrCount,
false, aState);
NS_ENSURE_SUCCESS(rv, rv);
aState.pushHandlerTable(gTxAttributeSetHandler);
return NS_OK;
}
static void txFnEndAttributeSet(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
aState.addInstruction(MakeUnique<txReturn>());
aState.closeInstructionContainer();
}
// xsl:decimal-format
static nsresult txFnStartDecimalFormat(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
txExpandedName name;
rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::name,
false, aState,
name);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<txDecimalFormat> format(
new txDecimalFormat);
rv = getCharAttr(aAttributes, aAttrCount, nsGkAtoms::decimalSeparator,
false,
aState, format->mDecimalSeparator);
NS_ENSURE_SUCCESS(rv, rv);
rv = getCharAttr(aAttributes, aAttrCount, nsGkAtoms::groupingSeparator,
false,
aState, format->mGroupingSeparator);
NS_ENSURE_SUCCESS(rv, rv);
txStylesheetAttr* attr = nullptr;
rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
nsGkAtoms::infinity,
false, &attr);
NS_ENSURE_SUCCESS(rv, rv);
if (attr) {
format->mInfinity = attr->mValue;
}
rv = getCharAttr(aAttributes, aAttrCount, nsGkAtoms::minusSign,
false, aState,
format->mMinusSign);
NS_ENSURE_SUCCESS(rv, rv);
rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None, nsGkAtoms::NaN,
false, &attr);
NS_ENSURE_SUCCESS(rv, rv);
if (attr) {
format->mNaN = attr->mValue;
}
rv = getCharAttr(aAttributes, aAttrCount, nsGkAtoms::percent,
false, aState,
format->mPercent);
NS_ENSURE_SUCCESS(rv, rv);
rv = getCharAttr(aAttributes, aAttrCount, nsGkAtoms::perMille,
false, aState,
format->mPerMille);
NS_ENSURE_SUCCESS(rv, rv);
rv = getCharAttr(aAttributes, aAttrCount, nsGkAtoms::zeroDigit,
false, aState,
format->mZeroDigit);
NS_ENSURE_SUCCESS(rv, rv);
rv = getCharAttr(aAttributes, aAttrCount, nsGkAtoms::digit,
false, aState,
format->mDigit);
NS_ENSURE_SUCCESS(rv, rv);
rv = getCharAttr(aAttributes, aAttrCount, nsGkAtoms::patternSeparator,
false,
aState, format->mPatternSeparator);
NS_ENSURE_SUCCESS(rv, rv);
rv = aState.mStylesheet->addDecimalFormat(name, std::move(format));
NS_ENSURE_SUCCESS(rv, rv);
aState.pushHandlerTable(gTxIgnoreHandler);
return NS_OK;
}
static void txFnEndDecimalFormat(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
}
// xsl:import
static nsresult txFnStartImport(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
UniquePtr<txImportItem> import(
new txImportItem);
import->mFrame = MakeUnique<txStylesheet::ImportFrame>();
txStylesheet::ImportFrame* frame = import->mFrame.get();
aState.addToplevelItem(import.release());
txStylesheetAttr* attr = nullptr;
nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
nsGkAtoms::href,
true, &attr);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString absUri;
URIUtils::resolveHref(attr->mValue, aState.mElementContext->mBaseURI, absUri);
rv = aState.loadImportedStylesheet(absUri, frame);
NS_ENSURE_SUCCESS(rv, rv);
aState.pushHandlerTable(gTxIgnoreHandler);
return NS_OK;
}
static void txFnEndImport(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
}
// xsl:include
static nsresult txFnStartInclude(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
txStylesheetAttr* attr = nullptr;
nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
nsGkAtoms::href,
true, &attr);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString absUri;
URIUtils::resolveHref(attr->mValue, aState.mElementContext->mBaseURI, absUri);
rv = aState.loadIncludedStylesheet(absUri);
NS_ENSURE_SUCCESS(rv, rv);
aState.pushHandlerTable(gTxIgnoreHandler);
return NS_OK;
}
static void txFnEndInclude(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
}
// xsl:key
static nsresult txFnStartKey(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
txExpandedName name;
rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::name,
true, aState,
name);
NS_ENSURE_SUCCESS(rv, rv);
aState.mDisAllowed = txIParseContext::KEY_FUNCTION;
UniquePtr<txPattern> match;
rv = getPatternAttr(aAttributes, aAttrCount, nsGkAtoms::match,
true, aState,
match);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<Expr> use;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::use,
true, aState, use);
NS_ENSURE_SUCCESS(rv, rv);
aState.mDisAllowed = 0;
rv = aState.mStylesheet->addKey(name, std::move(match), std::move(use));
NS_ENSURE_SUCCESS(rv, rv);
aState.pushHandlerTable(gTxIgnoreHandler);
return NS_OK;
}
static void txFnEndKey(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
}
// xsl:namespace-alias
static nsresult txFnStartNamespaceAlias(int32_t aNamespaceID,
nsAtom* aLocalName, nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
txStylesheetAttr* attr = nullptr;
nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
nsGkAtoms::stylesheetPrefix,
true, &attr);
NS_ENSURE_SUCCESS(rv, rv);
rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
nsGkAtoms::resultPrefix,
true, &attr);
NS_ENSURE_SUCCESS(rv, rv);
// XXX Needs to be implemented.
aState.pushHandlerTable(gTxIgnoreHandler);
return NS_OK;
}
static void txFnEndNamespaceAlias(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
}
// xsl:output
static nsresult txFnStartOutput(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
UniquePtr<txOutputItem> item(
new txOutputItem);
txExpandedName methodExpName;
rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::method,
false, aState,
methodExpName);
NS_ENSURE_SUCCESS(rv, rv);
if (!methodExpName.isNull()) {
if (methodExpName.mNamespaceID != kNameSpaceID_None) {
// The spec doesn't say what to do here so we'll just ignore the
// value. We could possibly warn.
}
else if (methodExpName.mLocalName == nsGkAtoms::html) {
item->mFormat.mMethod = eHTMLOutput;
}
else if (methodExpName.mLocalName == nsGkAtoms::text) {
item->mFormat.mMethod = eTextOutput;
}
else if (methodExpName.mLocalName == nsGkAtoms::xml) {
item->mFormat.mMethod = eXMLOutput;
}
else {
return NS_ERROR_XSLT_PARSE_FAILURE;
}
}
txStylesheetAttr* attr = nullptr;
getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None, nsGkAtoms::version,
false, &attr);
if (attr) {
item->mFormat.mVersion = attr->mValue;
}
getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None, nsGkAtoms::encoding,
false, &attr);
if (attr) {
item->mFormat.mEncoding = attr->mValue;
}
rv = getYesNoAttr(aAttributes, aAttrCount, nsGkAtoms::omitXmlDeclaration,
false, aState, item->mFormat.mOmitXMLDeclaration);
NS_ENSURE_SUCCESS(rv, rv);
rv = getYesNoAttr(aAttributes, aAttrCount, nsGkAtoms::standalone,
false,
aState, item->mFormat.mStandalone);
NS_ENSURE_SUCCESS(rv, rv);
getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
nsGkAtoms::doctypePublic,
false, &attr);
if (attr) {
item->mFormat.mPublicId = attr->mValue;
}
getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
nsGkAtoms::doctypeSystem,
false, &attr);
if (attr) {
item->mFormat.mSystemId = attr->mValue;
}
getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
nsGkAtoms::cdataSectionElements,
false, &attr);
if (attr) {
nsWhitespaceTokenizer tokens(attr->mValue);
while (tokens.hasMoreTokens()) {
UniquePtr<txExpandedName> qname(
new txExpandedName());
rv = qname->init(tokens.nextToken(), aState.mElementContext->mMappings,
false);
NS_ENSURE_SUCCESS(rv, rv);
item->mFormat.mCDATASectionElements.add(qname.release());
}
}
rv = getYesNoAttr(aAttributes, aAttrCount, nsGkAtoms::indent,
false, aState,
item->mFormat.mIndent);
NS_ENSURE_SUCCESS(rv, rv);
getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None, nsGkAtoms::mediaType,
false, &attr);
if (attr) {
item->mFormat.mMediaType = NS_ConvertUTF16toUTF8(attr->mValue);
}
aState.addToplevelItem(item.release());
aState.pushHandlerTable(gTxIgnoreHandler);
return NS_OK;
}
static void txFnEndOutput(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
}
// xsl:strip-space/xsl:preserve-space
static nsresult txFnStartStripSpace(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
txStylesheetAttr* attr = nullptr;
nsresult rv = getStyleAttr(aAttributes, aAttrCount, kNameSpaceID_None,
nsGkAtoms::elements,
true, &attr);
NS_ENSURE_SUCCESS(rv, rv);
bool strip = aLocalName == nsGkAtoms::stripSpace;
UniquePtr<txStripSpaceItem> stripItem(
new txStripSpaceItem);
nsWhitespaceTokenizer tokenizer(attr->mValue);
while (tokenizer.hasMoreTokens()) {
const nsAString& name = tokenizer.nextToken();
int32_t ns = kNameSpaceID_None;
RefPtr<nsAtom> prefix, localName;
rv = XMLUtils::splitQName(name, getter_AddRefs(prefix),
getter_AddRefs(localName));
if (NS_FAILED(rv)) {
// check for "*" or "prefix:*"
uint32_t length = name.Length();
const char16_t* c;
name.BeginReading(c);
if (length == 2 || c[length - 1] !=
'*') {
// these can't work
return NS_ERROR_XSLT_PARSE_FAILURE;
}
if (length > 1) {
// Check for a valid prefix, that is, the returned prefix
// should be empty and the real prefix is returned in
// localName.
if (c[length - 2] !=
':') {
return NS_ERROR_XSLT_PARSE_FAILURE;
}
rv = XMLUtils::splitQName(StringHead(name, length - 2),
getter_AddRefs(prefix),
getter_AddRefs(localName));
if (NS_FAILED(rv) || prefix) {
// bad chars or two ':'
return NS_ERROR_XSLT_PARSE_FAILURE;
}
prefix = localName;
}
localName = nsGkAtoms::_asterisk;
}
if (prefix) {
ns = aState.mElementContext->mMappings->lookupNamespace(prefix);
NS_ENSURE_TRUE(ns != kNameSpaceID_Unknown, NS_ERROR_FAILURE);
}
stripItem->addStripSpaceTest(
new txStripSpaceTest(prefix, localName, ns, strip));
}
aState.addToplevelItem(stripItem.release());
aState.pushHandlerTable(gTxIgnoreHandler);
return NS_OK;
}
static void txFnEndStripSpace(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
}
// xsl:template
static nsresult txFnStartTemplate(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
txExpandedName name;
rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::name,
false, aState,
name);
NS_ENSURE_SUCCESS(rv, rv);
txExpandedName mode;
rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::mode,
false, aState,
mode);
NS_ENSURE_SUCCESS(rv, rv);
double prio = UnspecifiedNaN<
double>();
rv = getNumberAttr(aAttributes, aAttrCount, nsGkAtoms::priority,
false,
aState, prio);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<txPattern> match;
rv = getPatternAttr(aAttributes, aAttrCount, nsGkAtoms::match, name.isNull(),
aState, match);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<txTemplateItem> templ(
new txTemplateItem(std::move(match), name, mode, prio));
aState.openInstructionContainer(templ.get());
aState.addToplevelItem(templ.release());
aState.pushHandlerTable(gTxParamHandler);
return NS_OK;
}
static void txFnEndTemplate(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
aState.addInstruction(MakeUnique<txReturn>());
aState.closeInstructionContainer();
}
// xsl:variable, xsl:param
static nsresult txFnStartTopVariable(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
txExpandedName name;
rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::name,
true, aState,
name);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select,
false, aState,
select);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<txVariableItem> var(
new txVariableItem(
name, std::move(select), aLocalName == nsGkAtoms::param));
aState.openInstructionContainer(var.get());
aState.pushPtr(var.get(), aState.eVariableItem);
if (var->mValue) {
// XXX should be gTxErrorHandler?
aState.pushHandlerTable(gTxIgnoreHandler);
}
else {
aState.pushHandlerTable(gTxTopVariableHandler);
}
aState.addToplevelItem(var.release());
return NS_OK;
}
static void txFnEndTopVariable(txStylesheetCompilerState& aState) {
txHandlerTable* prev = aState.mHandlerTable;
aState.popHandlerTable();
txVariableItem* var =
static_cast<txVariableItem*>(aState.popPtr(aState.eVariableItem));
if (prev == gTxTopVariableHandler) {
// No children were found.
NS_ASSERTION(!var->mValue,
"There shouldn't be a select-expression here");
var->mValue = MakeUnique<txLiteralExpr>(u
""_ns);
}
else if (!var->mValue) {
// If we don't have a select-expression there mush be children.
aState.addInstruction(MakeUnique<txReturn>());
}
aState.closeInstructionContainer();
}
static nsresult txFnStartElementStartTopVar(int32_t aNamespaceID,
nsAtom* aLocalName, nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
aState.mHandlerTable = gTxTemplateHandler;
return NS_XSLT_GET_NEW_HANDLER;
}
static nsresult txFnTextStartTopVar(
const nsAString& aStr,
txStylesheetCompilerState& aState) {
TX_RETURN_IF_WHITESPACE(aStr, aState);
aState.mHandlerTable = gTxTemplateHandler;
return NS_XSLT_GET_NEW_HANDLER;
}
/**
* Template Handlers
*/
/*
LRE
txStartLREElement
txInsertAttrSet one for each qname in xsl:use-attribute-sets
txLREAttribute one for each attribute
[children]
txEndElement
*/
static nsresult txFnStartLRE(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
aState.addInstruction(
MakeUnique<txStartLREElement>(aNamespaceID, aLocalName, aPrefix));
rv = parseExcludeResultPrefixes(aAttributes, aAttrCount, kNameSpaceID_XSLT);
NS_ENSURE_SUCCESS(rv, rv);
rv = parseUseAttrSets(aAttributes, aAttrCount,
true, aState);
NS_ENSURE_SUCCESS(rv, rv);
txStylesheetAttr* attr = nullptr;
int32_t i;
for (i = 0; i < aAttrCount; ++i) {
attr = aAttributes + i;
if (attr->mNamespaceID == kNameSpaceID_XSLT) {
if (attr->mLocalName == nsGkAtoms::version) {
attr->mLocalName = nullptr;
}
continue;
}
UniquePtr<Expr> avt;
rv = txExprParser::createAVT(attr->mValue, &aState, getter_Transfers(avt));
NS_ENSURE_SUCCESS(rv, rv);
aState.addInstruction(MakeUnique<txLREAttribute>(
attr->mNamespaceID, attr->mLocalName, attr->mPrefix, std::move(avt)));
}
return NS_OK;
}
static void txFnEndLRE(txStylesheetCompilerState& aState) {
aState.addInstruction(MakeUnique<txEndElement>());
}
/*
"LRE text"
txText
*/
static nsresult txFnText(
const nsAString& aStr,
txStylesheetCompilerState& aState) {
TX_RETURN_IF_WHITESPACE(aStr, aState);
aState.addInstruction(MakeUnique<txText>(aStr,
false));
return NS_OK;
}
/*
xsl:apply-imports
txApplyImportsStart
txApplyImportsEnd
*/
static nsresult txFnStartApplyImports(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
aState.addInstruction(MakeUnique<txApplyImportsStart>());
aState.addInstruction(MakeUnique<txApplyImportsEnd>());
aState.pushHandlerTable(gTxIgnoreHandler);
return NS_OK;
}
static void txFnEndApplyImports(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
}
/*
xsl:apply-templates
txPushParams
[params]
txPushNewContext -+ (holds <xsl:sort>s)
txApplyTemplate <-+ |
txLoopNodeSet -+ |
txPopParams <-+
*/
static nsresult txFnStartApplyTemplates(int32_t aNamespaceID,
nsAtom* aLocalName, nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
aState.addInstruction(MakeUnique<txPushParams>());
txExpandedName mode;
rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::mode,
false, aState,
mode);
NS_ENSURE_SUCCESS(rv, rv);
pushInstruction(aState, MakeUnique<txApplyTemplates>(mode));
UniquePtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select,
false, aState,
select);
NS_ENSURE_SUCCESS(rv, rv);
if (!select) {
UniquePtr<txNodeTest> nt(
new txNodeTypeTest(txNodeTypeTest::NODE_TYPE));
select = MakeUnique<LocationStep>(nt.release(), LocationStep::CHILD_AXIS);
}
UniquePtr<txPushNewContext> pushcontext(
new txPushNewContext(std::move(select)));
aState.pushSorter(pushcontext.get());
pushInstruction(aState, std::move(pushcontext));
aState.pushHandlerTable(gTxApplyTemplatesHandler);
return NS_OK;
}
static void txFnEndApplyTemplates(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
txPushNewContext* pushcontext =
aState.addInstruction(popInstruction<txPushNewContext>(aState));
aState.popSorter();
// txApplyTemplates
txInstruction* instr = aState.addInstruction(popInstruction(aState));
aState.addInstruction(MakeUnique<txLoopNodeSet>(instr));
pushcontext->mBailTarget = aState.addInstruction(MakeUnique<txPopParams>());
}
/*
xsl:attribute
txPushStringHandler
[children]
txAttribute
*/
static nsresult txFnStartAttribute(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
aState.addInstruction(MakeUnique<txPushStringHandler>(
true));
UniquePtr<Expr> name;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::name,
true, aState, name);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<Expr> nspace;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::_
namespace,
false, aState,
nspace);
NS_ENSURE_SUCCESS(rv, rv);
pushInstruction(aState,
MakeUnique<txAttribute>(std::move(name), std::move(nspace),
aState.mElementContext->mMappings));
// We need to push the template-handler since the current might be
// the attributeset-handler
aState.pushHandlerTable(gTxTemplateHandler);
return NS_OK;
}
static void txFnEndAttribute(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
aState.addInstruction(popInstruction(aState));
}
/*
xsl:call-template
txPushParams
[params]
txCallTemplate
txPopParams
*/
static nsresult txFnStartCallTemplate(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
aState.addInstruction(MakeUnique<txPushParams>());
txExpandedName name;
rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::name,
true, aState,
name);
NS_ENSURE_SUCCESS(rv, rv);
pushInstruction(aState, MakeUnique<txCallTemplate>(name));
aState.pushHandlerTable(gTxCallTemplateHandler);
return NS_OK;
}
static void txFnEndCallTemplate(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
// txCallTemplate
aState.addInstruction(popInstruction(aState));
aState.addInstruction(MakeUnique<txPopParams>());
}
/*
xsl:choose
txCondotionalGoto --+ \
[children] | | one for each xsl:when
txGoTo --+ | /
| |
txCondotionalGoto | <-+ --+
[children] | |
txGoTo --+ |
| |
[children] | <-+ for the xsl:otherwise, if there is one
<-+
*/
static nsresult txFnStartChoose(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
aState.pushChooseGotoList();
aState.pushHandlerTable(gTxChooseHandler);
return NS_OK;
}
static void txFnEndChoose(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
txListIterator iter(aState.mChooseGotoList.get());
txGoTo* gotoinstr;
while ((gotoinstr =
static_cast<txGoTo*>(iter.next()))) {
aState.addGotoTarget(&gotoinstr->mTarget);
}
aState.popChooseGotoList();
}
/*
xsl:comment
txPushStringHandler
[children]
txComment
*/
static nsresult txFnStartComment(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
aState.addInstruction(MakeUnique<txPushStringHandler>(
true));
return NS_OK;
}
static void txFnEndComment(txStylesheetCompilerState& aState) {
aState.addInstruction(MakeUnique<txComment>());
}
/*
xsl:copy
txCopy -+
txInsertAttrSet | one for each qname in use-attribute-sets
[children] |
txEndElement |
<-+
*/
static nsresult txFnStartCopy(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
aState.pushPtr(aState.addInstruction(MakeUnique<txCopy>()), aState.eCopy);
return parseUseAttrSets(aAttributes, aAttrCount,
false, aState);
}
static void txFnEndCopy(txStylesheetCompilerState& aState) {
aState.addInstruction(MakeUnique<txEndElement>());
txCopy* copy =
static_cast<txCopy*>(aState.popPtr(aState.eCopy));
aState.addGotoTarget(©->mBailTarget);
}
/*
xsl:copy-of
txCopyOf
*/
static nsresult txFnStartCopyOf(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
UniquePtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select,
true, aState,
select);
NS_ENSURE_SUCCESS(rv, rv);
aState.addInstruction(MakeUnique<txCopyOf>(std::move(select)));
aState.pushHandlerTable(gTxIgnoreHandler);
return NS_OK;
}
static void txFnEndCopyOf(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
}
/*
xsl:element
txStartElement
txInsertAttrSet one for each qname in use-attribute-sets
[children]
txEndElement
*/
static nsresult txFnStartElement(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
UniquePtr<Expr> name;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::name,
true, aState, name);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<Expr> nspace;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::_
namespace,
false, aState,
nspace);
NS_ENSURE_SUCCESS(rv, rv);
aState.addInstruction(MakeUnique<txStartElement>(
std::move(name), std::move(nspace), aState.mElementContext->mMappings));
rv = parseUseAttrSets(aAttributes, aAttrCount,
false, aState);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
static void txFnEndElement(txStylesheetCompilerState& aState) {
aState.addInstruction(MakeUnique<txEndElement>());
}
/*
xsl:fallback
[children]
*/
static nsresult txFnStartFallback(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
aState.mSearchingForFallback =
false;
aState.pushHandlerTable(gTxTemplateHandler);
return NS_OK;
}
static void txFnEndFallback(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
NS_ASSERTION(!aState.mSearchingForFallback,
"bad nesting of unknown-instruction and fallback handlers");
}
/*
xsl:for-each
txPushNewContext -+ (holds <xsl:sort>s)
txPushNullTemplateRule <-+ |
[children] | |
txLoopNodeSet -+ |
<-+
*/
static nsresult txFnStartForEach(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
UniquePtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select,
true, aState,
select);
NS_ENSURE_SUCCESS(rv, rv);
txPushNewContext* pushcontext =
aState.addInstruction(MakeUnique<txPushNewContext>(std::move(select)));
aState.pushPtr(pushcontext, aState.ePushNewContext);
aState.pushSorter(pushcontext);
aState.pushPtr(aState.addInstruction(MakeUnique<txPushNullTemplateRule>()),
aState.ePushNullTemplateRule);
aState.pushHandlerTable(gTxForEachHandler);
return NS_OK;
}
static void txFnEndForEach(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
// This is a txPushNullTemplateRule
txInstruction* pnullrule =
static_cast<txInstruction*>(aState.popPtr(aState.ePushNullTemplateRule));
aState.addInstruction(MakeUnique<txLoopNodeSet>(pnullrule));
aState.popSorter();
txPushNewContext* pushcontext =
static_cast<txPushNewContext*>(aState.popPtr(aState.ePushNewContext));
aState.addGotoTarget(&pushcontext->mBailTarget);
}
static nsresult txFnStartElementContinueTemplate(
int32_t aNamespaceID, nsAtom* aLocalName, nsAtom* aPrefix,
txStylesheetAttr* aAttributes, int32_t aAttrCount,
txStylesheetCompilerState& aState) {
aState.mHandlerTable = gTxTemplateHandler;
return NS_XSLT_GET_NEW_HANDLER;
}
static nsresult txFnTextContinueTemplate(
const nsAString& aStr,
txStylesheetCompilerState& aState) {
TX_RETURN_IF_WHITESPACE(aStr, aState);
aState.mHandlerTable = gTxTemplateHandler;
return NS_XSLT_GET_NEW_HANDLER;
}
/*
xsl:if
txConditionalGoto -+
[children] |
<-+
*/
static nsresult txFnStartIf(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
UniquePtr<Expr> test;
rv =
getExprAttr(aAttributes, aAttrCount, nsGkAtoms::test,
true, aState, test);
NS_ENSURE_SUCCESS(rv, rv);
aState.pushPtr(aState.addInstruction(
MakeUnique<txConditionalGoto>(std::move(test), nullptr)),
aState.eConditionalGoto);
return NS_OK;
}
static void txFnEndIf(txStylesheetCompilerState& aState) {
txConditionalGoto* condGoto =
static_cast<txConditionalGoto*>(aState.popPtr(aState.eConditionalGoto));
aState.addGotoTarget(&condGoto->mTarget);
}
/*
xsl:message
txPushStringHandler
[children]
txMessage
*/
static nsresult txFnStartMessage(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
aState.addInstruction(MakeUnique<txPushStringHandler>(
false));
txThreeState term;
nsresult rv = getYesNoAttr(aAttributes, aAttrCount, nsGkAtoms::terminate,
false, aState, term);
NS_ENSURE_SUCCESS(rv, rv);
pushInstruction(aState, MakeUnique<txMessage>(term == eTrue));
return NS_OK;
}
static void txFnEndMessage(txStylesheetCompilerState& aState) {
aState.addInstruction(popInstruction(aState));
}
/*
xsl:number
txNumber
*/
static nsresult txFnStartNumber(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
RefPtr<nsAtom> levelAtom;
rv = getAtomAttr(aAttributes, aAttrCount, nsGkAtoms::level,
false, aState,
getter_AddRefs(levelAtom));
NS_ENSURE_SUCCESS(rv, rv);
txXSLTNumber::LevelType level = txXSLTNumber::eLevelSingle;
if (levelAtom == nsGkAtoms::multiple) {
level = txXSLTNumber::eLevelMultiple;
}
else if (levelAtom == nsGkAtoms::any) {
level = txXSLTNumber::eLevelAny;
}
else if (levelAtom && levelAtom != nsGkAtoms::single && !aState.fcp()) {
return NS_ERROR_XSLT_PARSE_FAILURE;
}
UniquePtr<txPattern> count;
rv = getPatternAttr(aAttributes, aAttrCount, nsGkAtoms::count,
false, aState,
count);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<txPattern> from;
rv = getPatternAttr(aAttributes, aAttrCount, nsGkAtoms::from,
false, aState,
from);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<Expr> value;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::value,
false, aState,
value);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<Expr> format;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::format,
false, aState,
format);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<Expr> lang;
rv =
getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::lang,
false, aState, lang);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<Expr> letterValue;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::letterValue,
false,
aState, letterValue);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<Expr> groupingSeparator;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::groupingSeparator,
false,
aState, groupingSeparator);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<Expr> groupingSize;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::groupingSize,
false,
aState, groupingSize);
NS_ENSURE_SUCCESS(rv, rv);
aState.addInstruction(MakeUnique<txNumber>(
level, std::move(count), std::move(from), std::move(value),
std::move(format), std::move(groupingSeparator),
std::move(groupingSize)));
aState.pushHandlerTable(gTxIgnoreHandler);
return NS_OK;
}
static void txFnEndNumber(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
}
/*
xsl:otherwise
(see xsl:choose)
*/
static nsresult txFnStartOtherwise(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
aState.pushHandlerTable(gTxTemplateHandler);
return NS_OK;
}
static void txFnEndOtherwise(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
aState.mHandlerTable = gTxIgnoreHandler;
// XXX should be gTxErrorHandler
}
/*
xsl:param
txCheckParam --+
txPushRTFHandler | --- (for RTF-parameters)
[children] | /
txSetVariable |
<-+
*/
static nsresult txFnStartParam(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
txExpandedName name;
rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::name,
true, aState,
name);
NS_ENSURE_SUCCESS(rv, rv);
aState.pushPtr(aState.addInstruction(MakeUnique<txCheckParam>(name)),
aState.eCheckParam);
UniquePtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select,
false, aState,
select);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<txSetVariable> var =
MakeUnique<txSetVariable>(name, std::move(select));
if (var->mValue) {
// XXX should be gTxErrorHandler?
aState.pushHandlerTable(gTxIgnoreHandler);
}
else {
aState.pushHandlerTable(gTxVariableHandler);
}
pushInstruction(aState, std::move(var));
return NS_OK;
}
static void txFnEndParam(txStylesheetCompilerState& aState) {
UniquePtr<txSetVariable> var = popInstruction<txSetVariable>(aState);
txHandlerTable* prev = aState.mHandlerTable;
aState.popHandlerTable();
if (prev == gTxVariableHandler) {
// No children were found.
NS_ASSERTION(!var->mValue,
"There shouldn't be a select-expression here");
var->mValue = MakeUnique<txLiteralExpr>(u
""_ns);
}
aState.addVariable(var->mName);
aState.addInstruction(std::move(var));
txCheckParam* checkParam =
static_cast<txCheckParam*>(aState.popPtr(aState.eCheckParam));
aState.addGotoTarget(&checkParam->mBailTarget);
}
/*
xsl:processing-instruction
txPushStringHandler
[children]
txProcessingInstruction
*/
static nsresult txFnStartPI(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
aState.addInstruction(MakeUnique<txPushStringHandler>(
true));
UniquePtr<Expr> name;
nsresult rv =
getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::name,
true, aState, name);
NS_ENSURE_SUCCESS(rv, rv);
pushInstruction(aState, MakeUnique<txProcessingInstruction>(std::move(name)));
return NS_OK;
}
static void txFnEndPI(txStylesheetCompilerState& aState) {
aState.addInstruction(popInstruction(aState));
}
/*
xsl:sort
(no instructions)
*/
static nsresult txFnStartSort(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
UniquePtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select,
false, aState,
select);
NS_ENSURE_SUCCESS(rv, rv);
if (!select) {
UniquePtr<txNodeTest> nt(
new txNodeTypeTest(txNodeTypeTest::NODE_TYPE));
select = MakeUnique<LocationStep>(nt.release(), LocationStep::SELF_AXIS);
}
UniquePtr<Expr> lang;
rv =
getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::lang,
false, aState, lang);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<Expr> dataType;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::dataType,
false, aState,
dataType);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<Expr> order;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::order,
false, aState,
order);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<Expr> caseOrder;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::caseOrder,
false, aState,
caseOrder);
NS_ENSURE_SUCCESS(rv, rv);
aState.mSorter->addSort(std::move(select), std::move(lang),
std::move(dataType), std::move(order),
std::move(caseOrder));
aState.pushHandlerTable(gTxIgnoreHandler);
return NS_OK;
}
static void txFnEndSort(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
}
/*
xsl:text
[children] (only txText)
*/
static nsresult txFnStartText(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
NS_ASSERTION(!aState.mDOE,
"nested d-o-e elements should not happen");
nsresult rv = NS_OK;
txThreeState doe;
rv = getYesNoAttr(aAttributes, aAttrCount, nsGkAtoms::disableOutputEscaping,
false, aState, doe);
NS_ENSURE_SUCCESS(rv, rv);
aState.mDOE = doe == eTrue;
aState.pushHandlerTable(gTxTextHandler);
return NS_OK;
}
static void txFnEndText(txStylesheetCompilerState& aState) {
aState.mDOE =
false;
aState.popHandlerTable();
}
static nsresult txFnTextText(
const nsAString& aStr,
txStylesheetCompilerState& aState) {
aState.addInstruction(MakeUnique<txText>(aStr, aState.mDOE));
return NS_OK;
}
/*
xsl:value-of
txValueOf
*/
static nsresult txFnStartValueOf(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
txThreeState doe;
rv = getYesNoAttr(aAttributes, aAttrCount, nsGkAtoms::disableOutputEscaping,
false, aState, doe);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select,
true, aState,
select);
NS_ENSURE_SUCCESS(rv, rv);
aState.addInstruction(MakeUnique<txValueOf>(std::move(select), doe == eTrue));
aState.pushHandlerTable(gTxIgnoreHandler);
return NS_OK;
}
static void txFnEndValueOf(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
}
/*
xsl:variable
txPushRTFHandler --- (for RTF-parameters)
[children] /
txSetVariable
*/
static nsresult txFnStartVariable(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
txExpandedName name;
rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::name,
true, aState,
name);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select,
false, aState,
select);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<txSetVariable> var =
MakeUnique<txSetVariable>(name, std::move(select));
if (var->mValue) {
// XXX should be gTxErrorHandler?
aState.pushHandlerTable(gTxIgnoreHandler);
}
else {
aState.pushHandlerTable(gTxVariableHandler);
}
pushInstruction(aState, std::move(var));
return NS_OK;
}
static void txFnEndVariable(txStylesheetCompilerState& aState) {
UniquePtr<txSetVariable> var = popInstruction<txSetVariable>(aState);
txHandlerTable* prev = aState.mHandlerTable;
aState.popHandlerTable();
if (prev == gTxVariableHandler) {
// No children were found.
NS_ASSERTION(!var->mValue,
"There shouldn't be a select-expression here");
var->mValue = MakeUnique<txLiteralExpr>(u
""_ns);
}
aState.addVariable(var->mName);
aState.addInstruction(std::move(var));
}
static nsresult txFnStartElementStartRTF(int32_t aNamespaceID,
nsAtom* aLocalName, nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
aState.addInstruction(MakeUnique<txPushRTFHandler>());
aState.mHandlerTable = gTxTemplateHandler;
return NS_XSLT_GET_NEW_HANDLER;
}
static nsresult txFnTextStartRTF(
const nsAString& aStr,
txStylesheetCompilerState& aState) {
TX_RETURN_IF_WHITESPACE(aStr, aState);
aState.addInstruction(MakeUnique<txPushRTFHandler>());
aState.mHandlerTable = gTxTemplateHandler;
return NS_XSLT_GET_NEW_HANDLER;
}
/*
xsl:when
(see xsl:choose)
*/
static nsresult txFnStartWhen(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix, txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
UniquePtr<Expr> test;
rv =
getExprAttr(aAttributes, aAttrCount, nsGkAtoms::test,
true, aState, test);
NS_ENSURE_SUCCESS(rv, rv);
aState.pushPtr(aState.addInstruction(
MakeUnique<txConditionalGoto>(std::move(test), nullptr)),
aState.eConditionalGoto);
aState.pushHandlerTable(gTxTemplateHandler);
return NS_OK;
}
static void txFnEndWhen(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
aState.mChooseGotoList->add(
aState.addInstruction(MakeUnique<txGoTo>(nullptr)));
txConditionalGoto* condGoto =
static_cast<txConditionalGoto*>(aState.popPtr(aState.eConditionalGoto));
aState.addGotoTarget(&condGoto->mTarget);
}
/*
xsl:with-param
txPushRTFHandler -- for RTF-parameters
[children] /
txSetParam
*/
static nsresult txFnStartWithParam(int32_t aNamespaceID, nsAtom* aLocalName,
nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
nsresult rv = NS_OK;
txExpandedName name;
rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::name,
true, aState,
name);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select,
false, aState,
select);
NS_ENSURE_SUCCESS(rv, rv);
UniquePtr<txSetParam> var = MakeUnique<txSetParam>(name, std::move(select));
if (var->mValue) {
// XXX should be gTxErrorHandler?
aState.pushHandlerTable(gTxIgnoreHandler);
}
else {
aState.pushHandlerTable(gTxVariableHandler);
}
pushInstruction(aState, std::move(var));
return NS_OK;
}
static void txFnEndWithParam(txStylesheetCompilerState& aState) {
UniquePtr<txSetParam> var = popInstruction<txSetParam>(aState);
txHandlerTable* prev = aState.mHandlerTable;
aState.popHandlerTable();
if (prev == gTxVariableHandler) {
// No children were found.
NS_ASSERTION(!var->mValue,
"There shouldn't be a select-expression here");
var->mValue = MakeUnique<txLiteralExpr>(u
""_ns);
}
aState.addInstruction(std::move(var));
}
/*
Unknown instruction
[fallbacks] if one or more xsl:fallbacks are found
or
txErrorInstruction otherwise
*/
static nsresult txFnStartUnknownInstruction(int32_t aNamespaceID,
nsAtom* aLocalName, nsAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState) {
NS_ASSERTION(!aState.mSearchingForFallback,
"bad nesting of unknown-instruction and fallback handlers");
if (aNamespaceID == kNameSpaceID_XSLT && !aState.fcp()) {
return NS_ERROR_XSLT_PARSE_FAILURE;
}
aState.mSearchingForFallback =
true;
aState.pushHandlerTable(gTxFallbackHandler);
return NS_OK;
}
static void txFnEndUnknownInstruction(txStylesheetCompilerState& aState) {
aState.popHandlerTable();
if (aState.mSearchingForFallback) {
aState.addInstruction(MakeUnique<txErrorInstruction>());
}
aState.mSearchingForFallback =
false;
}
/**
* Table Datas
*/
struct txHandlerTableData {
txElementHandler mOtherHandler;
txElementHandler mLREHandler;
HandleTextFn mTextHandler;
};
const txHandlerTableData gTxIgnoreTableData = {
// Other
{0, 0, txFnStartElementIgnore, txFnEndElementIgnore},
// LRE
{0, 0, txFnStartElementIgnore, txFnEndElementIgnore},
// Text
txFnTextIgnore};
const txElementHandler gTxRootElementHandlers[] = {
{kNameSpaceID_XSLT,
"stylesheet", txFnStartStylesheet, txFnEndStylesheet},
{kNameSpaceID_XSLT,
"transform", txFnStartStylesheet, txFnEndStylesheet}};
const txHandlerTableData gTxRootTableData = {
// Other
{0, 0, txFnStartElementError, txFnEndElementError},
// LRE
{0, 0, txFnStartLREStylesheet, txFnEndLREStylesheet},
// Text
txFnTextError};
const txHandlerTableData gTxEmbedTableData = {
// Other
{0, 0, txFnStartEmbed, txFnEndEmbed},
// LRE
{0, 0, txFnStartEmbed, txFnEndEmbed},
// Text
txFnTextIgnore};
--> --------------------
--> maximum size reached
--> --------------------