Mypal/dom/xslt/xslt/txStylesheetCompileHandlers.cpp
2019-03-11 13:26:37 +03:00

2945 lines
82 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 "mozilla/ArrayUtils.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/Move.h"
#include "txStylesheetCompiler.h"
#include "txStylesheetCompileHandlers.h"
#include "nsWhitespaceTokenizer.h"
#include "txInstructions.h"
#include "nsGkAtoms.h"
#include "txCore.h"
#include "txStringUtils.h"
#include "txStylesheet.h"
#include "txToplevelItems.h"
#include "txPatternParser.h"
#include "txNamespaceMap.h"
#include "txURIUtils.h"
#include "txXSLTFunctions.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,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState);
static nsresult
txFnEndLRE(txStylesheetCompilerState& aState);
#define TX_RETURN_IF_WHITESPACE(_str, _state) \
do { \
if (!_state.mElementContext->mPreserveWhitespace && \
XMLUtils::isWhitespace(PromiseFlatString(_str))) { \
return NS_OK; \
} \
} while(0)
static nsresult
getStyleAttr(txStylesheetAttr* aAttributes,
int32_t aAttrCount,
int32_t aNamespace,
nsIAtom* 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);
nsAutoPtr<txInstruction> instr(new txInsertAttrSet(name));
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
}
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,
nsIAtom* 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,
nsIAtom* aName,
bool aRequired,
txStylesheetCompilerState& aState,
nsAutoPtr<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 = new txErrorExpr(
#ifdef TX_TO_STRING
attr->mValue
#endif
);
}
else {
aExpr = nullptr;
}
return NS_OK;
}
return rv;
}
static nsresult
getAVTAttr(txStylesheetAttr* aAttributes,
int32_t aAttrCount,
nsIAtom* aName,
bool aRequired,
txStylesheetCompilerState& aState,
nsAutoPtr<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 = new txErrorExpr(
#ifdef TX_TO_STRING
attr->mValue
#endif
);
}
else {
aAVT = nullptr;
}
return NS_OK;
}
return rv;
}
static nsresult
getPatternAttr(txStylesheetAttr* aAttributes,
int32_t aAttrCount,
nsIAtom* aName,
bool aRequired,
txStylesheetCompilerState& aState,
nsAutoPtr<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,
nsIAtom* 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 (mozilla::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,
nsIAtom* aName,
bool aRequired,
txStylesheetCompilerState& aState,
nsIAtom** 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,
nsIAtom* aName,
bool aRequired,
txStylesheetCompilerState& aState,
txThreeState& aRes)
{
aRes = eNotSet;
nsCOMPtr<nsIAtom> 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,
nsIAtom* 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;
}
/**
* 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,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
if (!aState.fcp()) {
clearAttributes(aAttributes, aAttrCount);
}
return NS_OK;
}
static nsresult
txFnEndElementIgnore(txStylesheetCompilerState& aState)
{
return NS_OK;
}
static nsresult
txFnStartElementSetIgnore(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
if (!aState.fcp()) {
clearAttributes(aAttributes, aAttrCount);
}
return aState.pushHandlerTable(gTxIgnoreHandler);
}
static nsresult
txFnEndElementSetIgnore(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
return NS_OK;
}
static nsresult
txFnStartElementError(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
return NS_ERROR_XSLT_PARSE_FAILURE;
}
static nsresult
txFnEndElementError(txStylesheetCompilerState& aState)
{
NS_ERROR("txFnEndElementError shouldn't be called");
return NS_ERROR_XSLT_PARSE_FAILURE;
}
/**
* Root handlers
*/
static nsresult
txFnStartStylesheet(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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);
return aState.pushHandlerTable(gTxImportHandler);
}
static nsresult
txFnEndStylesheet(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
return NS_OK;
}
static nsresult
txFnStartElementContinueTopLevel(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
aState.mHandlerTable = gTxTopHandler;
return NS_XSLT_GET_NEW_HANDLER;
}
static nsresult
txFnStartLREStylesheet(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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>();
nsAutoPtr<txPattern> match(new txRootPattern());
nsAutoPtr<txTemplateItem> templ(new txTemplateItem(Move(match), nullExpr,
nullExpr, prio));
aState.openInstructionContainer(templ);
rv = aState.addToplevelItem(templ);
NS_ENSURE_SUCCESS(rv, rv);
templ.forget();
rv = aState.pushHandlerTable(gTxTemplateHandler);
NS_ENSURE_SUCCESS(rv, rv);
return txFnStartLRE(aNamespaceID, aLocalName, aPrefix, aAttributes,
aAttrCount, aState);
}
static nsresult
txFnEndLREStylesheet(txStylesheetCompilerState& aState)
{
nsresult rv = txFnEndLRE(aState);
NS_ENSURE_SUCCESS(rv, rv);
aState.popHandlerTable();
nsAutoPtr<txInstruction> instr(new txReturn());
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
aState.closeInstructionContainer();
return NS_OK;
}
static nsresult
txFnStartEmbed(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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 nsresult
txFnEndEmbed(txStylesheetCompilerState& aState)
{
if (!aState.handleEmbeddedSheet()) {
return NS_OK;
}
nsresult rv = txFnEndStylesheet(aState);
aState.doneEmbedding();
return rv;
}
/**
* Top handlers
*/
static nsresult
txFnStartOtherTop(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
if (aNamespaceID == kNameSpaceID_None ||
(aNamespaceID == kNameSpaceID_XSLT && !aState.fcp())) {
return NS_ERROR_XSLT_PARSE_FAILURE;
}
return aState.pushHandlerTable(gTxIgnoreHandler);
}
static nsresult
txFnEndOtherTop(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
return NS_OK;
}
// xsl:attribute-set
static nsresult
txFnStartAttributeSet(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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);
nsAutoPtr<txAttributeSetItem> attrSet(new txAttributeSetItem(name));
aState.openInstructionContainer(attrSet);
rv = aState.addToplevelItem(attrSet);
NS_ENSURE_SUCCESS(rv, rv);
attrSet.forget();
rv = parseUseAttrSets(aAttributes, aAttrCount, false, aState);
NS_ENSURE_SUCCESS(rv, rv);
return aState.pushHandlerTable(gTxAttributeSetHandler);
}
static nsresult
txFnEndAttributeSet(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
nsAutoPtr<txInstruction> instr(new txReturn());
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
aState.closeInstructionContainer();
return NS_OK;
}
// xsl:decimal-format
static nsresult
txFnStartDecimalFormat(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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);
nsAutoPtr<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, Move(format));
NS_ENSURE_SUCCESS(rv, rv);
return aState.pushHandlerTable(gTxIgnoreHandler);
}
static nsresult
txFnEndDecimalFormat(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
return NS_OK;
}
// xsl:import
static nsresult
txFnStartImport(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsAutoPtr<txImportItem> import(new txImportItem);
import->mFrame = new txStylesheet::ImportFrame;
nsresult rv = aState.addToplevelItem(import);
NS_ENSURE_SUCCESS(rv, rv);
txImportItem* importPtr = import.forget();
txStylesheetAttr* attr = nullptr;
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, importPtr->mFrame);
NS_ENSURE_SUCCESS(rv, rv);
return aState.pushHandlerTable(gTxIgnoreHandler);
}
static nsresult
txFnEndImport(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
return NS_OK;
}
// xsl:include
static nsresult
txFnStartInclude(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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);
return aState.pushHandlerTable(gTxIgnoreHandler);
}
static nsresult
txFnEndInclude(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
return NS_OK;
}
// xsl:key
static nsresult
txFnStartKey(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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;
nsAutoPtr<txPattern> match;
rv = getPatternAttr(aAttributes, aAttrCount, nsGkAtoms::match, true,
aState, match);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<Expr> use;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::use, true,
aState, use);
NS_ENSURE_SUCCESS(rv, rv);
aState.mDisAllowed = 0;
rv = aState.mStylesheet->addKey(name, Move(match), Move(use));
NS_ENSURE_SUCCESS(rv, rv);
return aState.pushHandlerTable(gTxIgnoreHandler);
}
static nsresult
txFnEndKey(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
return NS_OK;
}
// xsl:namespace-alias
static nsresult
txFnStartNamespaceAlias(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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.
return aState.pushHandlerTable(gTxIgnoreHandler);
}
static nsresult
txFnEndNamespaceAlias(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
return NS_OK;
}
// xsl:output
static nsresult
txFnStartOutput(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsresult rv = NS_OK;
nsAutoPtr<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()) {
nsAutoPtr<txExpandedName> qname(new txExpandedName());
rv = qname->init(tokens.nextToken(),
aState.mElementContext->mMappings, false);
NS_ENSURE_SUCCESS(rv, rv);
rv = item->mFormat.mCDATASectionElements.add(qname);
NS_ENSURE_SUCCESS(rv, rv);
qname.forget();
}
}
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 = attr->mValue;
}
rv = aState.addToplevelItem(item);
NS_ENSURE_SUCCESS(rv, rv);
item.forget();
return aState.pushHandlerTable(gTxIgnoreHandler);
}
static nsresult
txFnEndOutput(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
return NS_OK;
}
// xsl:strip-space/xsl:preserve-space
static nsresult
txFnStartStripSpace(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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;
nsAutoPtr<txStripSpaceItem> stripItem(new txStripSpaceItem);
nsWhitespaceTokenizer tokenizer(attr->mValue);
while (tokenizer.hasMoreTokens()) {
const nsASingleFragmentString& name = tokenizer.nextToken();
int32_t ns = kNameSpaceID_None;
nsCOMPtr<nsIAtom> 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);
}
nsAutoPtr<txStripSpaceTest> sst(new txStripSpaceTest(prefix, localName,
ns, strip));
rv = stripItem->addStripSpaceTest(sst);
NS_ENSURE_SUCCESS(rv, rv);
sst.forget();
}
rv = aState.addToplevelItem(stripItem);
NS_ENSURE_SUCCESS(rv, rv);
stripItem.forget();
return aState.pushHandlerTable(gTxIgnoreHandler);
}
static nsresult
txFnEndStripSpace(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
return NS_OK;
}
// xsl:template
static nsresult
txFnStartTemplate(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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);
nsAutoPtr<txPattern> match;
rv = getPatternAttr(aAttributes, aAttrCount, nsGkAtoms::match,
name.isNull(), aState, match);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txTemplateItem> templ(new txTemplateItem(Move(match), name, mode,
prio));
aState.openInstructionContainer(templ);
rv = aState.addToplevelItem(templ);
NS_ENSURE_SUCCESS(rv, rv);
templ.forget();
return aState.pushHandlerTable(gTxParamHandler);
}
static nsresult
txFnEndTemplate(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
nsAutoPtr<txInstruction> instr(new txReturn());
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
aState.closeInstructionContainer();
return NS_OK;
}
// xsl:variable, xsl:param
static nsresult
txFnStartTopVariable(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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);
nsAutoPtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select, false,
aState, select);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txVariableItem> var(
new txVariableItem(name, Move(select),
aLocalName == nsGkAtoms::param));
aState.openInstructionContainer(var);
rv = aState.pushPtr(var, aState.eVariableItem);
NS_ENSURE_SUCCESS(rv, rv);
if (var->mValue) {
// XXX should be gTxErrorHandler?
rv = aState.pushHandlerTable(gTxIgnoreHandler);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
rv = aState.pushHandlerTable(gTxTopVariableHandler);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = aState.addToplevelItem(var);
NS_ENSURE_SUCCESS(rv, rv);
var.forget();
return NS_OK;
}
static nsresult
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 = new txLiteralExpr(EmptyString());
}
else if (!var->mValue) {
// If we don't have a select-expression there mush be children.
nsAutoPtr<txInstruction> instr(new txReturn());
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
}
aState.closeInstructionContainer();
return NS_OK;
}
static nsresult
txFnStartElementStartTopVar(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsresult rv = NS_OK;
nsAutoPtr<txInstruction> instr(new txStartLREElement(aNamespaceID,
aLocalName, aPrefix));
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
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;
}
nsAutoPtr<Expr> avt;
rv = txExprParser::createAVT(attr->mValue, &aState,
getter_Transfers(avt));
NS_ENSURE_SUCCESS(rv, rv);
instr = new txLREAttribute(attr->mNamespaceID, attr->mLocalName,
attr->mPrefix, Move(avt));
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
static nsresult
txFnEndLRE(txStylesheetCompilerState& aState)
{
nsAutoPtr<txInstruction> instr(new txEndElement);
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
/*
"LRE text"
txText
*/
static nsresult
txFnText(const nsAString& aStr, txStylesheetCompilerState& aState)
{
TX_RETURN_IF_WHITESPACE(aStr, aState);
nsAutoPtr<txInstruction> instr(new txText(aStr, false));
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
/*
xsl:apply-imports
txApplyImports
*/
static nsresult
txFnStartApplyImports(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsresult rv = NS_OK;
nsAutoPtr<txInstruction> instr(new txApplyImports);
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return aState.pushHandlerTable(gTxIgnoreHandler);
}
static nsresult
txFnEndApplyImports(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
return NS_OK;
}
/*
xsl:apply-templates
txPushParams
[params]
txPushNewContext -+ (holds <xsl:sort>s)
txApplyTemplate <-+ |
txLoopNodeSet -+ |
txPopParams <-+
*/
static nsresult
txFnStartApplyTemplates(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsresult rv = NS_OK;
nsAutoPtr<txInstruction> instr(new txPushParams);
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
txExpandedName mode;
rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::mode, false,
aState, mode);
NS_ENSURE_SUCCESS(rv, rv);
instr = new txApplyTemplates(mode);
rv = aState.pushObject(instr);
NS_ENSURE_SUCCESS(rv, rv);
instr.forget();
nsAutoPtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select, false,
aState, select);
NS_ENSURE_SUCCESS(rv, rv);
if (!select) {
nsAutoPtr<txNodeTest> nt(
new txNodeTypeTest(txNodeTypeTest::NODE_TYPE));
select = new LocationStep(nt, LocationStep::CHILD_AXIS);
nt.forget();
}
nsAutoPtr<txPushNewContext> pushcontext( new txPushNewContext(Move(select)));
rv = aState.pushSorter(pushcontext);
NS_ENSURE_SUCCESS(rv, rv);
rv = aState.pushObject(pushcontext);
NS_ENSURE_SUCCESS(rv, rv);
pushcontext.forget();
return aState.pushHandlerTable(gTxApplyTemplatesHandler);
}
static nsresult
txFnEndApplyTemplates(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
txPushNewContext* pushcontext =
static_cast<txPushNewContext*>(aState.popObject());
nsAutoPtr<txInstruction> instr(pushcontext); // txPushNewContext
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
aState.popSorter();
instr = static_cast<txInstruction*>(aState.popObject()); // txApplyTemplates
nsAutoPtr<txLoopNodeSet> loop(new txLoopNodeSet(instr));
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
instr = loop.forget();
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
instr = new txPopParams;
pushcontext->mBailTarget = instr;
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
/*
xsl:attribute
txPushStringHandler
[children]
txAttribute
*/
static nsresult
txFnStartAttribute(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsresult rv = NS_OK;
nsAutoPtr<txInstruction> instr(new txPushStringHandler(true));
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<Expr> name;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::name, true,
aState, name);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<Expr> nspace;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::_namespace, false,
aState, nspace);
NS_ENSURE_SUCCESS(rv, rv);
instr = new txAttribute(Move(name), Move(nspace),
aState.mElementContext->mMappings);
rv = aState.pushObject(instr);
NS_ENSURE_SUCCESS(rv, rv);
instr.forget();
// We need to push the template-handler since the current might be
// the attributeset-handler
return aState.pushHandlerTable(gTxTemplateHandler);
}
static nsresult
txFnEndAttribute(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
nsAutoPtr<txInstruction> instr(static_cast<txInstruction*>
(aState.popObject()));
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
/*
xsl:call-template
txPushParams
[params]
txCallTemplate
txPopParams
*/
static nsresult
txFnStartCallTemplate(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsresult rv = NS_OK;
nsAutoPtr<txInstruction> instr(new txPushParams);
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
txExpandedName name;
rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::name, true,
aState, name);
NS_ENSURE_SUCCESS(rv, rv);
instr = new txCallTemplate(name);
rv = aState.pushObject(instr);
NS_ENSURE_SUCCESS(rv, rv);
instr.forget();
return aState.pushHandlerTable(gTxCallTemplateHandler);
}
static nsresult
txFnEndCallTemplate(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
// txCallTemplate
nsAutoPtr<txInstruction> instr(static_cast<txInstruction*>(aState.popObject()));
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
instr = new txPopParams;
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
/*
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,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsresult rv = aState.pushChooseGotoList();
NS_ENSURE_SUCCESS(rv, rv);
return aState.pushHandlerTable(gTxChooseHandler);
}
static nsresult
txFnEndChoose(txStylesheetCompilerState& aState)
{
nsresult rv = NS_OK;
aState.popHandlerTable();
txListIterator iter(aState.mChooseGotoList);
txGoTo* gotoinstr;
while ((gotoinstr = static_cast<txGoTo*>(iter.next()))) {
rv = aState.addGotoTarget(&gotoinstr->mTarget);
NS_ENSURE_SUCCESS(rv, rv);
}
aState.popChooseGotoList();
return NS_OK;
}
/*
xsl:comment
txPushStringHandler
[children]
txComment
*/
static nsresult
txFnStartComment(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsAutoPtr<txInstruction> instr(new txPushStringHandler(true));
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
static nsresult
txFnEndComment(txStylesheetCompilerState& aState)
{
nsAutoPtr<txInstruction> instr(new txComment);
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
/*
xsl:copy
txCopy -+
txInsertAttrSet | one for each qname in use-attribute-sets
[children] |
txEndElement |
<-+
*/
static nsresult
txFnStartCopy(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsAutoPtr<txCopy> copy(new txCopy);
nsresult rv = aState.pushPtr(copy, aState.eCopy);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txInstruction> instr(copy.forget());
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
rv = parseUseAttrSets(aAttributes, aAttrCount, false, aState);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
static nsresult
txFnEndCopy(txStylesheetCompilerState& aState)
{
nsAutoPtr<txInstruction> instr(new txEndElement);
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
txCopy* copy = static_cast<txCopy*>(aState.popPtr(aState.eCopy));
rv = aState.addGotoTarget(&copy->mBailTarget);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
/*
xsl:copy-of
txCopyOf
*/
static nsresult
txFnStartCopyOf(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsresult rv = NS_OK;
nsAutoPtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select, true,
aState, select);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txInstruction> instr(new txCopyOf(Move(select)));
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return aState.pushHandlerTable(gTxIgnoreHandler);
}
static nsresult
txFnEndCopyOf(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
return NS_OK;
}
/*
xsl:element
txStartElement
txInsertAttrSet one for each qname in use-attribute-sets
[children]
txEndElement
*/
static nsresult
txFnStartElement(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsresult rv = NS_OK;
nsAutoPtr<Expr> name;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::name, true,
aState, name);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<Expr> nspace;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::_namespace, false,
aState, nspace);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txInstruction> instr(
new txStartElement(Move(name), Move(nspace),
aState.mElementContext->mMappings));
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
rv = parseUseAttrSets(aAttributes, aAttrCount, false, aState);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
static nsresult
txFnEndElement(txStylesheetCompilerState& aState)
{
nsAutoPtr<txInstruction> instr(new txEndElement);
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
/*
xsl:fallback
[children]
*/
static nsresult
txFnStartFallback(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
aState.mSearchingForFallback = false;
return aState.pushHandlerTable(gTxTemplateHandler);
}
static nsresult
txFnEndFallback(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
NS_ASSERTION(!aState.mSearchingForFallback,
"bad nesting of unknown-instruction and fallback handlers");
return NS_OK;
}
/*
xsl:for-each
txPushNewContext -+ (holds <xsl:sort>s)
txPushNullTemplateRule <-+ |
[children] | |
txLoopNodeSet -+ |
<-+
*/
static nsresult
txFnStartForEach(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsresult rv = NS_OK;
nsAutoPtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select, true,
aState, select);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txPushNewContext> pushcontext(new txPushNewContext(Move(select)));
rv = aState.pushPtr(pushcontext, aState.ePushNewContext);
NS_ENSURE_SUCCESS(rv, rv);
rv = aState.pushSorter(pushcontext);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txInstruction> instr(pushcontext.forget());
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
instr = new txPushNullTemplateRule;
rv = aState.pushPtr(instr, aState.ePushNullTemplateRule);
NS_ENSURE_SUCCESS(rv, rv);
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return aState.pushHandlerTable(gTxForEachHandler);
}
static nsresult
txFnEndForEach(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
// This is a txPushNullTemplateRule
txInstruction* pnullrule =
static_cast<txInstruction*>(aState.popPtr(aState.ePushNullTemplateRule));
nsAutoPtr<txInstruction> instr(new txLoopNodeSet(pnullrule));
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
aState.popSorter();
txPushNewContext* pushcontext =
static_cast<txPushNewContext*>(aState.popPtr(aState.ePushNewContext));
aState.addGotoTarget(&pushcontext->mBailTarget);
return NS_OK;
}
static nsresult
txFnStartElementContinueTemplate(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsresult rv = NS_OK;
nsAutoPtr<Expr> test;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::test, true,
aState, test);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txConditionalGoto> condGoto(new txConditionalGoto(Move(test),
nullptr));
rv = aState.pushPtr(condGoto, aState.eConditionalGoto);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txInstruction> instr(condGoto.forget());
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
static nsresult
txFnEndIf(txStylesheetCompilerState& aState)
{
txConditionalGoto* condGoto =
static_cast<txConditionalGoto*>(aState.popPtr(aState.eConditionalGoto));
return aState.addGotoTarget(&condGoto->mTarget);
}
/*
xsl:message
txPushStringHandler
[children]
txMessage
*/
static nsresult
txFnStartMessage(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsAutoPtr<txInstruction> instr(new txPushStringHandler(false));
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
txThreeState term;
rv = getYesNoAttr(aAttributes, aAttrCount, nsGkAtoms::terminate,
false, aState, term);
NS_ENSURE_SUCCESS(rv, rv);
instr = new txMessage(term == eTrue);
rv = aState.pushObject(instr);
NS_ENSURE_SUCCESS(rv, rv);
instr.forget();
return NS_OK;
}
static nsresult
txFnEndMessage(txStylesheetCompilerState& aState)
{
nsAutoPtr<txInstruction> instr(static_cast<txInstruction*>(aState.popObject()));
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
/*
xsl:number
txNumber
*/
static nsresult
txFnStartNumber(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsresult rv = NS_OK;
nsCOMPtr<nsIAtom> 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;
}
nsAutoPtr<txPattern> count;
rv = getPatternAttr(aAttributes, aAttrCount, nsGkAtoms::count, false,
aState, count);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txPattern> from;
rv = getPatternAttr(aAttributes, aAttrCount, nsGkAtoms::from, false,
aState, from);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<Expr> value;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::value, false,
aState, value);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<Expr> format;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::format, false,
aState, format);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<Expr> lang;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::lang, false,
aState, lang);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<Expr> letterValue;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::letterValue, false,
aState, letterValue);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<Expr> groupingSeparator;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::groupingSeparator,
false, aState, groupingSeparator);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<Expr> groupingSize;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::groupingSize,
false, aState, groupingSize);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txInstruction> instr(new txNumber(level, Move(count), Move(from),
Move(value), Move(format),
Move(groupingSeparator),
Move(groupingSize)));
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return aState.pushHandlerTable(gTxIgnoreHandler);
}
static nsresult
txFnEndNumber(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
return NS_OK;
}
/*
xsl:otherwise
(see xsl:choose)
*/
static nsresult
txFnStartOtherwise(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
return aState.pushHandlerTable(gTxTemplateHandler);
}
static nsresult
txFnEndOtherwise(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
aState.mHandlerTable = gTxIgnoreHandler; // XXX should be gTxErrorHandler
return NS_OK;
}
/*
xsl:param
txCheckParam --+
txPushRTFHandler | --- (for RTF-parameters)
[children] | /
txSetVariable |
<-+
*/
static nsresult
txFnStartParam(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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);
nsAutoPtr<txCheckParam> checkParam(new txCheckParam(name));
NS_ENSURE_SUCCESS(rv, rv);
rv = aState.pushPtr(checkParam, aState.eCheckParam);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txInstruction> instr(checkParam.forget());
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select, false,
aState, select);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txSetVariable> var(new txSetVariable(name, Move(select)));
if (var->mValue) {
// XXX should be gTxErrorHandler?
rv = aState.pushHandlerTable(gTxIgnoreHandler);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
rv = aState.pushHandlerTable(gTxVariableHandler);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = aState.pushObject(var);
NS_ENSURE_SUCCESS(rv, rv);
var.forget();
return NS_OK;
}
static nsresult
txFnEndParam(txStylesheetCompilerState& aState)
{
nsAutoPtr<txSetVariable> var(static_cast<txSetVariable*>
(aState.popObject()));
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 = new txLiteralExpr(EmptyString());
}
nsresult rv = aState.addVariable(var->mName);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txInstruction> instr(var.forget());
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
txCheckParam* checkParam =
static_cast<txCheckParam*>(aState.popPtr(aState.eCheckParam));
aState.addGotoTarget(&checkParam->mBailTarget);
return NS_OK;
}
/*
xsl:processing-instruction
txPushStringHandler
[children]
txProcessingInstruction
*/
static nsresult
txFnStartPI(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsAutoPtr<txInstruction> instr(new txPushStringHandler(true));
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<Expr> name;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::name, true,
aState, name);
NS_ENSURE_SUCCESS(rv, rv);
instr = new txProcessingInstruction(Move(name));
rv = aState.pushObject(instr);
NS_ENSURE_SUCCESS(rv, rv);
instr.forget();
return NS_OK;
}
static nsresult
txFnEndPI(txStylesheetCompilerState& aState)
{
nsAutoPtr<txInstruction> instr(static_cast<txInstruction*>
(aState.popObject()));
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
/*
xsl:sort
(no instructions)
*/
static nsresult
txFnStartSort(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsresult rv = NS_OK;
nsAutoPtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select, false,
aState, select);
NS_ENSURE_SUCCESS(rv, rv);
if (!select) {
nsAutoPtr<txNodeTest> nt(
new txNodeTypeTest(txNodeTypeTest::NODE_TYPE));
select = new LocationStep(nt, LocationStep::SELF_AXIS);
nt.forget();
}
nsAutoPtr<Expr> lang;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::lang, false,
aState, lang);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<Expr> dataType;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::dataType, false,
aState, dataType);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<Expr> order;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::order, false,
aState, order);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<Expr> caseOrder;
rv = getAVTAttr(aAttributes, aAttrCount, nsGkAtoms::caseOrder, false,
aState, caseOrder);
NS_ENSURE_SUCCESS(rv, rv);
rv = aState.mSorter->addSort(Move(select), Move(lang), Move(dataType),
Move(order), Move(caseOrder));
NS_ENSURE_SUCCESS(rv, rv);
return aState.pushHandlerTable(gTxIgnoreHandler);
}
static nsresult
txFnEndSort(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
return NS_OK;
}
/*
xsl:text
[children] (only txText)
*/
static nsresult
txFnStartText(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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;
return aState.pushHandlerTable(gTxTextHandler);
}
static nsresult
txFnEndText(txStylesheetCompilerState& aState)
{
aState.mDOE = false;
aState.popHandlerTable();
return NS_OK;
}
static nsresult
txFnTextText(const nsAString& aStr, txStylesheetCompilerState& aState)
{
nsAutoPtr<txInstruction> instr(new txText(aStr, aState.mDOE));
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
/*
xsl:value-of
txValueOf
*/
static nsresult
txFnStartValueOf(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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);
nsAutoPtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select, true,
aState, select);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txInstruction> instr(new txValueOf(Move(select), doe == eTrue));
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return aState.pushHandlerTable(gTxIgnoreHandler);
}
static nsresult
txFnEndValueOf(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
return NS_OK;
}
/*
xsl:variable
txPushRTFHandler --- (for RTF-parameters)
[children] /
txSetVariable
*/
static nsresult
txFnStartVariable(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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);
nsAutoPtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select, false,
aState, select);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txSetVariable> var(new txSetVariable(name, Move(select)));
if (var->mValue) {
// XXX should be gTxErrorHandler?
rv = aState.pushHandlerTable(gTxIgnoreHandler);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
rv = aState.pushHandlerTable(gTxVariableHandler);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = aState.pushObject(var);
NS_ENSURE_SUCCESS(rv, rv);
var.forget();
return NS_OK;
}
static nsresult
txFnEndVariable(txStylesheetCompilerState& aState)
{
nsAutoPtr<txSetVariable> var(static_cast<txSetVariable*>
(aState.popObject()));
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 = new txLiteralExpr(EmptyString());
}
nsresult rv = aState.addVariable(var->mName);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txInstruction> instr(var.forget());
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
static nsresult
txFnStartElementStartRTF(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsAutoPtr<txInstruction> instr(new txPushRTFHandler);
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
aState.mHandlerTable = gTxTemplateHandler;
return NS_XSLT_GET_NEW_HANDLER;
}
static nsresult
txFnTextStartRTF(const nsAString& aStr, txStylesheetCompilerState& aState)
{
TX_RETURN_IF_WHITESPACE(aStr, aState);
nsAutoPtr<txInstruction> instr(new txPushRTFHandler);
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
aState.mHandlerTable = gTxTemplateHandler;
return NS_XSLT_GET_NEW_HANDLER;
}
/*
xsl:when
(see xsl:choose)
*/
static nsresult
txFnStartWhen(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* aPrefix,
txStylesheetAttr* aAttributes,
int32_t aAttrCount,
txStylesheetCompilerState& aState)
{
nsresult rv = NS_OK;
nsAutoPtr<Expr> test;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::test, true,
aState, test);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txConditionalGoto> condGoto(new txConditionalGoto(Move(test),
nullptr));
rv = aState.pushPtr(condGoto, aState.eConditionalGoto);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txInstruction> instr(condGoto.forget());
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return aState.pushHandlerTable(gTxTemplateHandler);
}
static nsresult
txFnEndWhen(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
nsAutoPtr<txGoTo> gotoinstr(new txGoTo(nullptr));
nsresult rv = aState.mChooseGotoList->add(gotoinstr);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txInstruction> instr(gotoinstr.forget());
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
txConditionalGoto* condGoto =
static_cast<txConditionalGoto*>(aState.popPtr(aState.eConditionalGoto));
rv = aState.addGotoTarget(&condGoto->mTarget);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
/*
xsl:with-param
txPushRTFHandler -- for RTF-parameters
[children] /
txSetParam
*/
static nsresult
txFnStartWithParam(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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);
nsAutoPtr<Expr> select;
rv = getExprAttr(aAttributes, aAttrCount, nsGkAtoms::select, false,
aState, select);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoPtr<txSetParam> var(new txSetParam(name, Move(select)));
if (var->mValue) {
// XXX should be gTxErrorHandler?
rv = aState.pushHandlerTable(gTxIgnoreHandler);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
rv = aState.pushHandlerTable(gTxVariableHandler);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = aState.pushObject(var);
NS_ENSURE_SUCCESS(rv, rv);
var.forget();
return NS_OK;
}
static nsresult
txFnEndWithParam(txStylesheetCompilerState& aState)
{
nsAutoPtr<txSetParam> var(static_cast<txSetParam*>(aState.popObject()));
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 = new txLiteralExpr(EmptyString());
}
nsAutoPtr<txInstruction> instr(var.forget());
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
/*
Unknown instruction
[fallbacks] if one or more xsl:fallbacks are found
or
txErrorInstruction otherwise
*/
static nsresult
txFnStartUnknownInstruction(int32_t aNamespaceID,
nsIAtom* aLocalName,
nsIAtom* 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;
return aState.pushHandlerTable(gTxFallbackHandler);
}
static nsresult
txFnEndUnknownInstruction(txStylesheetCompilerState& aState)
{
aState.popHandlerTable();
if (aState.mSearchingForFallback) {
nsAutoPtr<txInstruction> instr(new txErrorInstruction());
nsresult rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
}
aState.mSearchingForFallback = false;
return NS_OK;
}
/**
* 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
};
const txElementHandler gTxTopElementHandlers[] = {
{ kNameSpaceID_XSLT, "attribute-set", txFnStartAttributeSet, txFnEndAttributeSet },
{ kNameSpaceID_XSLT, "decimal-format", txFnStartDecimalFormat, txFnEndDecimalFormat },
{ kNameSpaceID_XSLT, "include", txFnStartInclude, txFnEndInclude },
{ kNameSpaceID_XSLT, "key", txFnStartKey, txFnEndKey },
{ kNameSpaceID_XSLT, "namespace-alias", txFnStartNamespaceAlias,
txFnEndNamespaceAlias },
{ kNameSpaceID_XSLT, "output", txFnStartOutput, txFnEndOutput },
{ kNameSpaceID_XSLT, "param", txFnStartTopVariable, txFnEndTopVariable },
{ kNameSpaceID_XSLT, "preserve-space", txFnStartStripSpace, txFnEndStripSpace },
{ kNameSpaceID_XSLT, "strip-space", txFnStartStripSpace, txFnEndStripSpace },
{ kNameSpaceID_XSLT, "template", txFnStartTemplate, txFnEndTemplate },
{ kNameSpaceID_XSLT, "variable", txFnStartTopVariable, txFnEndTopVariable }
};
const txHandlerTableData gTxTopTableData = {
// Other
{ 0, 0, txFnStartOtherTop, txFnEndOtherTop },
// LRE
{ 0, 0, txFnStartOtherTop, txFnEndOtherTop },
// Text
txFnTextIgnore
};
const txElementHandler gTxTemplateElementHandlers[] = {
{ kNameSpaceID_XSLT, "apply-imports", txFnStartApplyImports, txFnEndApplyImports },
{ kNameSpaceID_XSLT, "apply-templates", txFnStartApplyTemplates, txFnEndApplyTemplates },
{ kNameSpaceID_XSLT, "attribute", txFnStartAttribute, txFnEndAttribute },
{ kNameSpaceID_XSLT, "call-template", txFnStartCallTemplate, txFnEndCallTemplate },
{ kNameSpaceID_XSLT, "choose", txFnStartChoose, txFnEndChoose },
{ kNameSpaceID_XSLT, "comment", txFnStartComment, txFnEndComment },
{ kNameSpaceID_XSLT, "copy", txFnStartCopy, txFnEndCopy },
{ kNameSpaceID_XSLT, "copy-of", txFnStartCopyOf, txFnEndCopyOf },
{ kNameSpaceID_XSLT, "element", txFnStartElement, txFnEndElement },
{ kNameSpaceID_XSLT, "fallback", txFnStartElementSetIgnore, txFnEndElementSetIgnore },
{ kNameSpaceID_XSLT, "for-each", txFnStartForEach, txFnEndForEach },
{ kNameSpaceID_XSLT, "if", txFnStartIf, txFnEndIf },
{ kNameSpaceID_XSLT, "message", txFnStartMessage, txFnEndMessage },
{ kNameSpaceID_XSLT, "number", txFnStartNumber, txFnEndNumber },
{ kNameSpaceID_XSLT, "processing-instruction", txFnStartPI, txFnEndPI },
{ kNameSpaceID_XSLT, "text", txFnStartText, txFnEndText },
{ kNameSpaceID_XSLT, "value-of", txFnStartValueOf, txFnEndValueOf },
{ kNameSpaceID_XSLT, "variable", txFnStartVariable, txFnEndVariable }
};
const txHandlerTableData gTxTemplateTableData = {
// Other
{ 0, 0, txFnStartUnknownInstruction, txFnEndUnknownInstruction },
// LRE
{ 0, 0, txFnStartLRE, txFnEndLRE },
// Text
txFnText
};
const txHandlerTableData gTxTextTableData = {
// Other
{ 0, 0, txFnStartElementError, txFnEndElementError },
// LRE
{ 0, 0, txFnStartElementError, txFnEndElementError },
// Text
txFnTextText
};
const txElementHandler gTxApplyTemplatesElementHandlers[] = {
{ kNameSpaceID_XSLT, "sort", txFnStartSort, txFnEndSort },
{ kNameSpaceID_XSLT, "with-param", txFnStartWithParam, txFnEndWithParam }
};
const txHandlerTableData gTxApplyTemplatesTableData = {
// Other
{ 0, 0, txFnStartElementSetIgnore, txFnEndElementSetIgnore }, // should this be error?
// LRE
{ 0, 0, txFnStartElementSetIgnore, txFnEndElementSetIgnore },
// Text
txFnTextIgnore
};
const txElementHandler gTxCallTemplateElementHandlers[] = {
{ kNameSpaceID_XSLT, "with-param", txFnStartWithParam, txFnEndWithParam }
};
const txHandlerTableData gTxCallTemplateTableData = {
// Other
{ 0, 0, txFnStartElementSetIgnore, txFnEndElementSetIgnore }, // should this be error?
// LRE
{ 0, 0, txFnStartElementSetIgnore, txFnEndElementSetIgnore },
// Text
txFnTextIgnore
};
const txHandlerTableData gTxVariableTableData = {
// Other
{ 0, 0, txFnStartElementStartRTF, 0 },
// LRE
{ 0, 0, txFnStartElementStartRTF, 0 },
// Text
txFnTextStartRTF
};
const txElementHandler gTxForEachElementHandlers[] = {
{ kNameSpaceID_XSLT, "sort", txFnStartSort, txFnEndSort }
};
const txHandlerTableData gTxForEachTableData = {
// Other
{ 0, 0, txFnStartElementContinueTemplate, 0 },
// LRE
{ 0, 0, txFnStartElementContinueTemplate, 0 },
// Text
txFnTextContinueTemplate
};
const txHandlerTableData gTxTopVariableTableData = {
// Other
{ 0, 0, txFnStartElementStartTopVar, 0 },
// LRE
{ 0, 0, txFnStartElementStartTopVar, 0 },
// Text
txFnTextStartTopVar
};
const txElementHandler gTxChooseElementHandlers[] = {
{ kNameSpaceID_XSLT, "otherwise", txFnStartOtherwise, txFnEndOtherwise },
{ kNameSpaceID_XSLT, "when", txFnStartWhen, txFnEndWhen }
};
const txHandlerTableData gTxChooseTableData = {
// Other
{ 0, 0, txFnStartElementError, 0 },
// LRE
{ 0, 0, txFnStartElementError, 0 },
// Text
txFnTextError
};
const txElementHandler gTxParamElementHandlers[] = {
{ kNameSpaceID_XSLT, "param", txFnStartParam, txFnEndParam }
};
const txHandlerTableData gTxParamTableData = {
// Other
{ 0, 0, txFnStartElementContinueTemplate, 0 },
// LRE
{ 0, 0, txFnStartElementContinueTemplate, 0 },
// Text
txFnTextContinueTemplate
};
const txElementHandler gTxImportElementHandlers[] = {
{ kNameSpaceID_XSLT, "import", txFnStartImport, txFnEndImport }
};
const txHandlerTableData gTxImportTableData = {
// Other
{ 0, 0, txFnStartElementContinueTopLevel, 0 },
// LRE
{ 0, 0, txFnStartOtherTop, txFnEndOtherTop }, // XXX what should we do here?
// Text
txFnTextIgnore // XXX what should we do here?
};
const txElementHandler gTxAttributeSetElementHandlers[] = {
{ kNameSpaceID_XSLT, "attribute", txFnStartAttribute, txFnEndAttribute }
};
const txHandlerTableData gTxAttributeSetTableData = {
// Other
{ 0, 0, txFnStartElementError, 0 },
// LRE
{ 0, 0, txFnStartElementError, 0 },
// Text
txFnTextError
};
const txElementHandler gTxFallbackElementHandlers[] = {
{ kNameSpaceID_XSLT, "fallback", txFnStartFallback, txFnEndFallback }
};
const txHandlerTableData gTxFallbackTableData = {
// Other
{ 0, 0, txFnStartElementSetIgnore, txFnEndElementSetIgnore },
// LRE
{ 0, 0, txFnStartElementSetIgnore, txFnEndElementSetIgnore },
// Text
txFnTextIgnore
};
/**
* txHandlerTable
*/
txHandlerTable::txHandlerTable(const HandleTextFn aTextHandler,
const txElementHandler* aLREHandler,
const txElementHandler* aOtherHandler)
: mTextHandler(aTextHandler),
mLREHandler(aLREHandler),
mOtherHandler(aOtherHandler)
{
}
nsresult
txHandlerTable::init(const txElementHandler* aHandlers, uint32_t aCount)
{
nsresult rv = NS_OK;
uint32_t i;
for (i = 0; i < aCount; ++i) {
nsCOMPtr<nsIAtom> nameAtom = NS_Atomize(aHandlers->mLocalName);
txExpandedName name(aHandlers->mNamespaceID, nameAtom);
rv = mHandlers.add(name, aHandlers);
NS_ENSURE_SUCCESS(rv, rv);
++aHandlers;
}
return NS_OK;
}
const txElementHandler*
txHandlerTable::find(int32_t aNamespaceID, nsIAtom* aLocalName)
{
txExpandedName name(aNamespaceID, aLocalName);
const txElementHandler* handler = mHandlers.get(name);
if (!handler) {
handler = mOtherHandler;
}
return handler;
}
#define INIT_HANDLER(_name) \
gTx##_name##Handler = \
new txHandlerTable(gTx##_name##TableData.mTextHandler, \
&gTx##_name##TableData.mLREHandler, \
&gTx##_name##TableData.mOtherHandler); \
if (!gTx##_name##Handler) \
return false
#define INIT_HANDLER_WITH_ELEMENT_HANDLERS(_name) \
INIT_HANDLER(_name); \
\
rv = gTx##_name##Handler->init(gTx##_name##ElementHandlers, \
ArrayLength(gTx##_name##ElementHandlers)); \
if (NS_FAILED(rv)) \
return false
#define SHUTDOWN_HANDLER(_name) \
delete gTx##_name##Handler; \
gTx##_name##Handler = nullptr
// static
bool
txHandlerTable::init()
{
nsresult rv = NS_OK;
INIT_HANDLER_WITH_ELEMENT_HANDLERS(Root);
INIT_HANDLER(Embed);
INIT_HANDLER_WITH_ELEMENT_HANDLERS(Top);
INIT_HANDLER(Ignore);
INIT_HANDLER_WITH_ELEMENT_HANDLERS(Template);
INIT_HANDLER(Text);
INIT_HANDLER_WITH_ELEMENT_HANDLERS(ApplyTemplates);
INIT_HANDLER_WITH_ELEMENT_HANDLERS(CallTemplate);
INIT_HANDLER(Variable);
INIT_HANDLER_WITH_ELEMENT_HANDLERS(ForEach);
INIT_HANDLER(TopVariable);
INIT_HANDLER_WITH_ELEMENT_HANDLERS(Choose);
INIT_HANDLER_WITH_ELEMENT_HANDLERS(Param);
INIT_HANDLER_WITH_ELEMENT_HANDLERS(Import);
INIT_HANDLER_WITH_ELEMENT_HANDLERS(AttributeSet);
INIT_HANDLER_WITH_ELEMENT_HANDLERS(Fallback);
return true;
}
// static
void
txHandlerTable::shutdown()
{
SHUTDOWN_HANDLER(Root);
SHUTDOWN_HANDLER(Embed);
SHUTDOWN_HANDLER(Top);
SHUTDOWN_HANDLER(Ignore);
SHUTDOWN_HANDLER(Template);
SHUTDOWN_HANDLER(Text);
SHUTDOWN_HANDLER(ApplyTemplates);
SHUTDOWN_HANDLER(CallTemplate);
SHUTDOWN_HANDLER(Variable);
SHUTDOWN_HANDLER(ForEach);
SHUTDOWN_HANDLER(TopVariable);
SHUTDOWN_HANDLER(Choose);
SHUTDOWN_HANDLER(Param);
SHUTDOWN_HANDLER(Import);
SHUTDOWN_HANDLER(AttributeSet);
SHUTDOWN_HANDLER(Fallback);
}