michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef TRANSFRMX_EXPR_H michael@0: #define TRANSFRMX_EXPR_H michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "txExprResult.h" michael@0: #include "txCore.h" michael@0: #include "nsString.h" michael@0: #include "txOwningArray.h" michael@0: #include "nsIAtom.h" michael@0: michael@0: #ifdef DEBUG michael@0: #define TX_TO_STRING michael@0: #endif michael@0: michael@0: /* michael@0: XPath class definitions. michael@0: Much of this code was ported from XSL:P. michael@0: */ michael@0: michael@0: class nsIAtom; michael@0: class txIParseContext; michael@0: class txIMatchContext; michael@0: class txIEvalContext; michael@0: class txNodeSet; michael@0: class txXPathNode; michael@0: michael@0: /** michael@0: * A Base Class for all XSL Expressions michael@0: **/ michael@0: class Expr michael@0: { michael@0: public: michael@0: Expr() michael@0: { michael@0: MOZ_COUNT_CTOR(Expr); michael@0: } michael@0: virtual ~Expr() michael@0: { michael@0: MOZ_COUNT_DTOR(Expr); michael@0: } michael@0: michael@0: /** michael@0: * Evaluates this Expr based on the given context node and processor state michael@0: * @param context the context node for evaluation of this Expr michael@0: * @param ps the ContextState containing the stack information needed michael@0: * for evaluation michael@0: * @return the result of the evaluation michael@0: **/ michael@0: virtual nsresult evaluate(txIEvalContext* aContext, michael@0: txAExprResult** aResult) = 0; michael@0: michael@0: michael@0: /** michael@0: * Returns the type of this expression. michael@0: */ michael@0: enum ExprType { michael@0: LOCATIONSTEP_EXPR, michael@0: PATH_EXPR, michael@0: UNION_EXPR, michael@0: LITERAL_EXPR, michael@0: OTHER_EXPR michael@0: }; michael@0: virtual ExprType getType() michael@0: { michael@0: return OTHER_EXPR; michael@0: } michael@0: michael@0: /** michael@0: * Returns the type or types of results this Expr return. michael@0: */ michael@0: typedef uint16_t ResultType; michael@0: enum { michael@0: NODESET_RESULT = 0x01, michael@0: BOOLEAN_RESULT = 0x02, michael@0: NUMBER_RESULT = 0x04, michael@0: STRING_RESULT = 0x08, michael@0: RTF_RESULT = 0x10, michael@0: ANY_RESULT = 0xFFFF michael@0: }; michael@0: virtual ResultType getReturnType() = 0; michael@0: bool canReturnType(ResultType aType) michael@0: { michael@0: return (getReturnType() & aType) != 0; michael@0: } michael@0: michael@0: typedef uint16_t ContextSensitivity; michael@0: enum { michael@0: NO_CONTEXT = 0x00, michael@0: NODE_CONTEXT = 0x01, michael@0: POSITION_CONTEXT = 0x02, michael@0: SIZE_CONTEXT = 0x04, michael@0: NODESET_CONTEXT = POSITION_CONTEXT | SIZE_CONTEXT, michael@0: VARIABLES_CONTEXT = 0x08, michael@0: PRIVATE_CONTEXT = 0x10, michael@0: ANY_CONTEXT = 0xFFFF michael@0: }; michael@0: michael@0: /** michael@0: * Returns true if this expression is sensitive to *any* of michael@0: * the requested contexts in aContexts. michael@0: */ michael@0: virtual bool isSensitiveTo(ContextSensitivity aContexts) = 0; michael@0: michael@0: /** michael@0: * Returns sub-expression at given position michael@0: */ michael@0: virtual Expr* getSubExprAt(uint32_t aPos) = 0; michael@0: michael@0: /** michael@0: * Replace sub-expression at given position. Does not delete the old michael@0: * expression, that is the responsibility of the caller. michael@0: */ michael@0: virtual void setSubExprAt(uint32_t aPos, Expr* aExpr) = 0; michael@0: michael@0: virtual nsresult evaluateToBool(txIEvalContext* aContext, michael@0: bool& aResult); michael@0: michael@0: virtual nsresult evaluateToString(txIEvalContext* aContext, michael@0: nsString& aResult); michael@0: michael@0: #ifdef TX_TO_STRING michael@0: /** michael@0: * Returns the String representation of this Expr. michael@0: * @param dest the String to use when creating the String michael@0: * representation. The String representation will be appended to michael@0: * any data in the destination String, to allow cascading calls to michael@0: * other #toString() methods for Expressions. michael@0: * @return the String representation of this Expr. michael@0: **/ michael@0: virtual void toString(nsAString& str) = 0; michael@0: #endif michael@0: }; //-- Expr michael@0: michael@0: #ifdef TX_TO_STRING michael@0: #define TX_DECL_TOSTRING \ michael@0: void toString(nsAString& aDest); michael@0: #define TX_DECL_GETNAMEATOM \ michael@0: nsresult getNameAtom(nsIAtom** aAtom); michael@0: #else michael@0: #define TX_DECL_TOSTRING michael@0: #define TX_DECL_GETNAMEATOM michael@0: #endif michael@0: michael@0: #define TX_DECL_EXPR_BASE \ michael@0: nsresult evaluate(txIEvalContext* aContext, txAExprResult** aResult); \ michael@0: ResultType getReturnType(); \ michael@0: bool isSensitiveTo(ContextSensitivity aContexts); michael@0: michael@0: #define TX_DECL_EXPR \ michael@0: TX_DECL_EXPR_BASE \ michael@0: TX_DECL_TOSTRING \ michael@0: Expr* getSubExprAt(uint32_t aPos); \ michael@0: void setSubExprAt(uint32_t aPos, Expr* aExpr); michael@0: michael@0: #define TX_DECL_OPTIMIZABLE_EXPR \ michael@0: TX_DECL_EXPR \ michael@0: ExprType getType(); michael@0: michael@0: michael@0: #define TX_DECL_FUNCTION \ michael@0: TX_DECL_GETNAMEATOM \ michael@0: TX_DECL_EXPR_BASE michael@0: michael@0: #define TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \ michael@0: Expr::ResultType \ michael@0: _class::getReturnType() \ michael@0: { \ michael@0: return _ReturnType; \ michael@0: } michael@0: michael@0: #define TX_IMPL_EXPR_STUBS_0(_class, _ReturnType) \ michael@0: TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \ michael@0: Expr* \ michael@0: _class::getSubExprAt(uint32_t aPos) \ michael@0: { \ michael@0: return nullptr; \ michael@0: } \ michael@0: void \ michael@0: _class::setSubExprAt(uint32_t aPos, Expr* aExpr) \ michael@0: { \ michael@0: NS_NOTREACHED("setting bad subexpression index"); \ michael@0: } michael@0: michael@0: #define TX_IMPL_EXPR_STUBS_1(_class, _ReturnType, _Expr1) \ michael@0: TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \ michael@0: Expr* \ michael@0: _class::getSubExprAt(uint32_t aPos) \ michael@0: { \ michael@0: if (aPos == 0) { \ michael@0: return _Expr1; \ michael@0: } \ michael@0: return nullptr; \ michael@0: } \ michael@0: void \ michael@0: _class::setSubExprAt(uint32_t aPos, Expr* aExpr) \ michael@0: { \ michael@0: NS_ASSERTION(aPos < 1, "setting bad subexpression index");\ michael@0: _Expr1.forget(); \ michael@0: _Expr1 = aExpr; \ michael@0: } michael@0: michael@0: #define TX_IMPL_EXPR_STUBS_2(_class, _ReturnType, _Expr1, _Expr2) \ michael@0: TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \ michael@0: Expr* \ michael@0: _class::getSubExprAt(uint32_t aPos) \ michael@0: { \ michael@0: switch(aPos) { \ michael@0: case 0: \ michael@0: return _Expr1; \ michael@0: case 1: \ michael@0: return _Expr2; \ michael@0: default: \ michael@0: break; \ michael@0: } \ michael@0: return nullptr; \ michael@0: } \ michael@0: void \ michael@0: _class::setSubExprAt(uint32_t aPos, Expr* aExpr) \ michael@0: { \ michael@0: NS_ASSERTION(aPos < 2, "setting bad subexpression index");\ michael@0: if (aPos == 0) { \ michael@0: _Expr1.forget(); \ michael@0: _Expr1 = aExpr; \ michael@0: } \ michael@0: else { \ michael@0: _Expr2.forget(); \ michael@0: _Expr2 = aExpr; \ michael@0: } \ michael@0: } michael@0: michael@0: #define TX_IMPL_EXPR_STUBS_LIST(_class, _ReturnType, _ExprList) \ michael@0: TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \ michael@0: Expr* \ michael@0: _class::getSubExprAt(uint32_t aPos) \ michael@0: { \ michael@0: return _ExprList.SafeElementAt(aPos); \ michael@0: } \ michael@0: void \ michael@0: _class::setSubExprAt(uint32_t aPos, Expr* aExpr) \ michael@0: { \ michael@0: NS_ASSERTION(aPos < _ExprList.Length(), \ michael@0: "setting bad subexpression index"); \ michael@0: _ExprList[aPos] = aExpr; \ michael@0: } michael@0: michael@0: michael@0: /** michael@0: * This class represents a FunctionCall as defined by the XPath 1.0 michael@0: * Recommendation. michael@0: **/ michael@0: class FunctionCall : public Expr michael@0: { michael@0: public: michael@0: /** michael@0: * Adds the given parameter to this FunctionCall's parameter list. michael@0: * The ownership of the given Expr is passed over to the FunctionCall, michael@0: * even on failure. michael@0: * @param aExpr the Expr to add to this FunctionCall's parameter list michael@0: * @return nsresult indicating out of memory michael@0: */ michael@0: nsresult addParam(Expr* aExpr) michael@0: { michael@0: return mParams.AppendElement(aExpr) ? michael@0: NS_OK : NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: /** michael@0: * Check if the number of parameters falls within a range. michael@0: * michael@0: * @param aParamCountMin minimum number of required parameters. michael@0: * @param aParamCountMax maximum number of parameters. If aParamCountMax michael@0: * is negative the maximum number is not checked. michael@0: * @return boolean representing whether the number of parameters falls michael@0: * within the expected range or not. michael@0: * michael@0: * XXX txIEvalContext should be txIParseContest, bug 143291 michael@0: */ michael@0: virtual bool requireParams(int32_t aParamCountMin, michael@0: int32_t aParamCountMax, michael@0: txIEvalContext* aContext); michael@0: michael@0: TX_DECL_TOSTRING michael@0: Expr* getSubExprAt(uint32_t aPos) MOZ_OVERRIDE; michael@0: void setSubExprAt(uint32_t aPos, Expr* aExpr) MOZ_OVERRIDE; michael@0: michael@0: protected: michael@0: michael@0: txOwningArray mParams; michael@0: michael@0: /* michael@0: * Evaluates the given Expression and converts its result to a number. michael@0: */ michael@0: static nsresult evaluateToNumber(Expr* aExpr, txIEvalContext* aContext, michael@0: double* aResult); michael@0: michael@0: /* michael@0: * Evaluates the given Expression and converts its result to a NodeSet. michael@0: * If the result is not a NodeSet an error is returned. michael@0: */ michael@0: static nsresult evaluateToNodeSet(Expr* aExpr, txIEvalContext* aContext, michael@0: txNodeSet** aResult); michael@0: michael@0: /** michael@0: * Returns true if any argument is sensitive to the given context. michael@0: */ michael@0: bool argsSensitiveTo(ContextSensitivity aContexts); michael@0: michael@0: michael@0: #ifdef TX_TO_STRING michael@0: /* michael@0: * Returns the name of the function as an atom. michael@0: */ michael@0: virtual nsresult getNameAtom(nsIAtom** aAtom) = 0; michael@0: #endif michael@0: }; michael@0: michael@0: class txCoreFunctionCall : public FunctionCall michael@0: { michael@0: public: michael@0: michael@0: // This must be ordered in the same order as descriptTable in michael@0: // txCoreFunctionCall.cpp. If you change one, change the other. michael@0: enum eType { michael@0: COUNT = 0, // count() michael@0: ID, // id() michael@0: LAST, // last() michael@0: LOCAL_NAME, // local-name() michael@0: NAMESPACE_URI, // namespace-uri() michael@0: NAME, // name() michael@0: POSITION, // position() michael@0: michael@0: CONCAT, // concat() michael@0: CONTAINS, // contains() michael@0: NORMALIZE_SPACE, // normalize-space() michael@0: STARTS_WITH, // starts-with() michael@0: STRING, // string() michael@0: STRING_LENGTH, // string-length() michael@0: SUBSTRING, // substring() michael@0: SUBSTRING_AFTER, // substring-after() michael@0: SUBSTRING_BEFORE, // substring-before() michael@0: TRANSLATE, // translate() michael@0: michael@0: NUMBER, // number() michael@0: ROUND, // round() michael@0: FLOOR, // floor() michael@0: CEILING, // ceiling() michael@0: SUM, // sum() michael@0: michael@0: BOOLEAN, // boolean() michael@0: _FALSE, // false() michael@0: LANG, // lang() michael@0: _NOT, // not() michael@0: _TRUE // true() michael@0: }; michael@0: michael@0: /* michael@0: * Creates a txCoreFunctionCall of the given type michael@0: */ michael@0: txCoreFunctionCall(eType aType) : mType(aType) michael@0: { michael@0: } michael@0: michael@0: TX_DECL_FUNCTION michael@0: michael@0: static bool getTypeFromAtom(nsIAtom* aName, eType& aType); michael@0: michael@0: private: michael@0: eType mType; michael@0: }; michael@0: michael@0: michael@0: /* michael@0: * This class represents a NodeTest as defined by the XPath spec michael@0: */ michael@0: class txNodeTest michael@0: { michael@0: public: michael@0: txNodeTest() michael@0: { michael@0: MOZ_COUNT_CTOR(txNodeTest); michael@0: } michael@0: virtual ~txNodeTest() michael@0: { michael@0: MOZ_COUNT_DTOR(txNodeTest); michael@0: } michael@0: michael@0: /* michael@0: * Virtual methods michael@0: * pretty much a txPattern, but not supposed to be used michael@0: * standalone. The NodeTest node() is different to the michael@0: * Pattern "node()" (document node isn't matched) michael@0: */ michael@0: virtual bool matches(const txXPathNode& aNode, michael@0: txIMatchContext* aContext) = 0; michael@0: virtual double getDefaultPriority() = 0; michael@0: michael@0: /** michael@0: * Returns the type of this nodetest. michael@0: */ michael@0: enum NodeTestType { michael@0: NAME_TEST, michael@0: NODETYPE_TEST, michael@0: OTHER_TEST michael@0: }; michael@0: virtual NodeTestType getType() michael@0: { michael@0: return OTHER_TEST; michael@0: } michael@0: michael@0: /** michael@0: * Returns true if this expression is sensitive to *any* of michael@0: * the requested flags. michael@0: */ michael@0: virtual bool isSensitiveTo(Expr::ContextSensitivity aContext) = 0; michael@0: michael@0: #ifdef TX_TO_STRING michael@0: virtual void toString(nsAString& aDest) = 0; michael@0: #endif michael@0: }; michael@0: michael@0: #define TX_DECL_NODE_TEST \ michael@0: TX_DECL_TOSTRING \ michael@0: bool matches(const txXPathNode& aNode, txIMatchContext* aContext); \ michael@0: double getDefaultPriority(); \ michael@0: bool isSensitiveTo(Expr::ContextSensitivity aContext); michael@0: michael@0: /* michael@0: * This class represents a NameTest as defined by the XPath spec michael@0: */ michael@0: class txNameTest : public txNodeTest michael@0: { michael@0: public: michael@0: /* michael@0: * Creates a new txNameTest with the given type and the given michael@0: * principal node type michael@0: */ michael@0: txNameTest(nsIAtom* aPrefix, nsIAtom* aLocalName, int32_t aNSID, michael@0: uint16_t aNodeType); michael@0: michael@0: NodeTestType getType() MOZ_OVERRIDE; michael@0: michael@0: TX_DECL_NODE_TEST michael@0: michael@0: nsCOMPtr mPrefix; michael@0: nsCOMPtr mLocalName; michael@0: int32_t mNamespace; michael@0: private: michael@0: uint16_t mNodeType; michael@0: }; michael@0: michael@0: /* michael@0: * This class represents a NodeType as defined by the XPath spec michael@0: */ michael@0: class txNodeTypeTest : public txNodeTest michael@0: { michael@0: public: michael@0: enum NodeType { michael@0: COMMENT_TYPE, michael@0: TEXT_TYPE, michael@0: PI_TYPE, michael@0: NODE_TYPE michael@0: }; michael@0: michael@0: /* michael@0: * Creates a new txNodeTypeTest of the given type michael@0: */ michael@0: txNodeTypeTest(NodeType aNodeType) michael@0: : mNodeType(aNodeType) michael@0: { michael@0: } michael@0: michael@0: /* michael@0: * Sets the name of the node to match. Only availible for pi nodes michael@0: */ michael@0: void setNodeName(const nsAString& aName) michael@0: { michael@0: mNodeName = do_GetAtom(aName); michael@0: } michael@0: michael@0: NodeType getNodeTestType() michael@0: { michael@0: return mNodeType; michael@0: } michael@0: michael@0: NodeTestType getType() MOZ_OVERRIDE; michael@0: michael@0: TX_DECL_NODE_TEST michael@0: michael@0: private: michael@0: NodeType mNodeType; michael@0: nsCOMPtr mNodeName; michael@0: }; michael@0: michael@0: /** michael@0: * Class representing a nodetest combined with a predicate. May only be used michael@0: * if the predicate is not sensitive to the context-nodelist. michael@0: */ michael@0: class txPredicatedNodeTest : public txNodeTest michael@0: { michael@0: public: michael@0: txPredicatedNodeTest(txNodeTest* aNodeTest, Expr* aPredicate); michael@0: TX_DECL_NODE_TEST michael@0: michael@0: private: michael@0: nsAutoPtr mNodeTest; michael@0: nsAutoPtr mPredicate; michael@0: }; michael@0: michael@0: /** michael@0: * Represents an ordered list of Predicates, michael@0: * for use with Step and Filter Expressions michael@0: **/ michael@0: class PredicateList { michael@0: public: michael@0: /** michael@0: * Adds the given Expr to the list. michael@0: * The ownership of the given Expr is passed over the PredicateList, michael@0: * even on failure. michael@0: * @param aExpr the Expr to add to the list michael@0: * @return nsresult indicating out of memory michael@0: */ michael@0: nsresult add(Expr* aExpr) michael@0: { michael@0: NS_ASSERTION(aExpr, "missing expression"); michael@0: return mPredicates.AppendElement(aExpr) ? michael@0: NS_OK : NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: nsresult evaluatePredicates(txNodeSet* aNodes, txIMatchContext* aContext); michael@0: michael@0: /** michael@0: * Drops the first predicate without deleting it. michael@0: */ michael@0: void dropFirst() michael@0: { michael@0: mPredicates.RemoveElementAt(0); michael@0: } michael@0: michael@0: /** michael@0: * returns true if this predicate list is empty michael@0: **/ michael@0: bool isEmpty() michael@0: { michael@0: return mPredicates.IsEmpty(); michael@0: } michael@0: michael@0: #ifdef TX_TO_STRING michael@0: /** michael@0: * Returns the String representation of this PredicateList. michael@0: * @param dest the String to use when creating the String michael@0: * representation. The String representation will be appended to michael@0: * any data in the destination String, to allow cascading calls to michael@0: * other #toString() methods for Expressions. michael@0: * @return the String representation of this PredicateList. michael@0: **/ michael@0: void toString(nsAString& dest); michael@0: #endif michael@0: michael@0: protected: michael@0: bool isSensitiveTo(Expr::ContextSensitivity aContext); michael@0: Expr* getSubExprAt(uint32_t aPos) michael@0: { michael@0: return mPredicates.SafeElementAt(aPos); michael@0: } michael@0: void setSubExprAt(uint32_t aPos, Expr* aExpr) michael@0: { michael@0: NS_ASSERTION(aPos < mPredicates.Length(), michael@0: "setting bad subexpression index"); michael@0: mPredicates[aPos] = aExpr; michael@0: } michael@0: michael@0: //-- list of predicates michael@0: txOwningArray mPredicates; michael@0: }; //-- PredicateList michael@0: michael@0: class LocationStep : public Expr, michael@0: public PredicateList michael@0: { michael@0: public: michael@0: enum LocationStepType { michael@0: ANCESTOR_AXIS = 0, michael@0: ANCESTOR_OR_SELF_AXIS, michael@0: ATTRIBUTE_AXIS, michael@0: CHILD_AXIS, michael@0: DESCENDANT_AXIS, michael@0: DESCENDANT_OR_SELF_AXIS, michael@0: FOLLOWING_AXIS, michael@0: FOLLOWING_SIBLING_AXIS, michael@0: NAMESPACE_AXIS, michael@0: PARENT_AXIS, michael@0: PRECEDING_AXIS, michael@0: PRECEDING_SIBLING_AXIS, michael@0: SELF_AXIS michael@0: }; michael@0: michael@0: /** michael@0: * Creates a new LocationStep using the given NodeExpr and Axis Identifier michael@0: * @param nodeExpr the NodeExpr to use when matching Nodes michael@0: * @param axisIdentifier the Axis Identifier in which to search for nodes michael@0: **/ michael@0: LocationStep(txNodeTest* aNodeTest, michael@0: LocationStepType aAxisIdentifier) michael@0: : mNodeTest(aNodeTest), michael@0: mAxisIdentifier(aAxisIdentifier) michael@0: { michael@0: } michael@0: michael@0: TX_DECL_OPTIMIZABLE_EXPR michael@0: michael@0: txNodeTest* getNodeTest() michael@0: { michael@0: return mNodeTest; michael@0: } michael@0: void setNodeTest(txNodeTest* aNodeTest) michael@0: { michael@0: mNodeTest.forget(); michael@0: mNodeTest = aNodeTest; michael@0: } michael@0: LocationStepType getAxisIdentifier() michael@0: { michael@0: return mAxisIdentifier; michael@0: } michael@0: void setAxisIdentifier(LocationStepType aAxisIdentifier) michael@0: { michael@0: mAxisIdentifier = aAxisIdentifier; michael@0: } michael@0: michael@0: private: michael@0: void fromDescendants(const txXPathNode& aNode, txIMatchContext* aCs, michael@0: txNodeSet* aNodes); michael@0: void fromDescendantsRev(const txXPathNode& aNode, txIMatchContext* aCs, michael@0: txNodeSet* aNodes); michael@0: michael@0: nsAutoPtr mNodeTest; michael@0: LocationStepType mAxisIdentifier; michael@0: }; michael@0: michael@0: class FilterExpr : public Expr, michael@0: public PredicateList michael@0: { michael@0: public: michael@0: michael@0: /** michael@0: * Creates a new FilterExpr using the given Expr michael@0: * @param expr the Expr to use for evaluation michael@0: */ michael@0: FilterExpr(Expr* aExpr) michael@0: : expr(aExpr) michael@0: { michael@0: } michael@0: michael@0: TX_DECL_EXPR michael@0: michael@0: private: michael@0: nsAutoPtr expr; michael@0: michael@0: }; //-- FilterExpr michael@0: michael@0: michael@0: class txLiteralExpr : public Expr { michael@0: public: michael@0: txLiteralExpr(double aDbl) michael@0: : mValue(new NumberResult(aDbl, nullptr)) michael@0: { michael@0: } michael@0: txLiteralExpr(const nsAString& aStr) michael@0: : mValue(new StringResult(aStr, nullptr)) michael@0: { michael@0: } michael@0: txLiteralExpr(txAExprResult* aValue) michael@0: : mValue(aValue) michael@0: { michael@0: } michael@0: michael@0: TX_DECL_EXPR michael@0: michael@0: private: michael@0: nsRefPtr mValue; michael@0: }; michael@0: michael@0: /** michael@0: * Represents an UnaryExpr. Returns the negative value of its expr. michael@0: **/ michael@0: class UnaryExpr : public Expr { michael@0: michael@0: public: michael@0: michael@0: UnaryExpr(Expr* aExpr) michael@0: : expr(aExpr) michael@0: { michael@0: } michael@0: michael@0: TX_DECL_EXPR michael@0: michael@0: private: michael@0: nsAutoPtr expr; michael@0: }; //-- UnaryExpr michael@0: michael@0: /** michael@0: * Represents a BooleanExpr, a binary expression that michael@0: * performs a boolean operation between its lvalue and rvalue. michael@0: **/ michael@0: class BooleanExpr : public Expr michael@0: { michael@0: public: michael@0: michael@0: //-- BooleanExpr Types michael@0: enum _BooleanExprType { AND = 1, OR }; michael@0: michael@0: BooleanExpr(Expr* aLeftExpr, Expr* aRightExpr, short aOp) michael@0: : leftExpr(aLeftExpr), michael@0: rightExpr(aRightExpr), michael@0: op(aOp) michael@0: { michael@0: } michael@0: michael@0: TX_DECL_EXPR michael@0: michael@0: private: michael@0: nsAutoPtr leftExpr, rightExpr; michael@0: short op; michael@0: }; //-- BooleanExpr michael@0: michael@0: /** michael@0: * Represents a MultiplicativeExpr, a binary expression that michael@0: * performs a multiplicative operation between its lvalue and rvalue: michael@0: * * : multiply michael@0: * mod : modulus michael@0: * div : divide michael@0: * michael@0: **/ michael@0: class txNumberExpr : public Expr michael@0: { michael@0: public: michael@0: michael@0: enum eOp { ADD, SUBTRACT, DIVIDE, MULTIPLY, MODULUS }; michael@0: michael@0: txNumberExpr(Expr* aLeftExpr, Expr* aRightExpr, eOp aOp) michael@0: : mLeftExpr(aLeftExpr), michael@0: mRightExpr(aRightExpr), michael@0: mOp(aOp) michael@0: { michael@0: } michael@0: michael@0: TX_DECL_EXPR michael@0: michael@0: private: michael@0: nsAutoPtr mLeftExpr, mRightExpr; michael@0: eOp mOp; michael@0: }; //-- MultiplicativeExpr michael@0: michael@0: /** michael@0: * Represents a RelationalExpr, an expression that compares its lvalue michael@0: * to its rvalue using: michael@0: * = : equal to michael@0: * < : less than michael@0: * > : greater than michael@0: * <= : less than or equal to michael@0: * >= : greater than or equal to michael@0: * michael@0: **/ michael@0: class RelationalExpr : public Expr michael@0: { michael@0: public: michael@0: enum RelationalExprType { michael@0: EQUAL, michael@0: NOT_EQUAL, michael@0: LESS_THAN, michael@0: GREATER_THAN, michael@0: LESS_OR_EQUAL, michael@0: GREATER_OR_EQUAL michael@0: }; michael@0: michael@0: RelationalExpr(Expr* aLeftExpr, Expr* aRightExpr, RelationalExprType aOp) michael@0: : mLeftExpr(aLeftExpr), michael@0: mRightExpr(aRightExpr), michael@0: mOp(aOp) michael@0: { michael@0: } michael@0: michael@0: michael@0: TX_DECL_EXPR michael@0: michael@0: private: michael@0: bool compareResults(txIEvalContext* aContext, txAExprResult* aLeft, michael@0: txAExprResult* aRight); michael@0: michael@0: nsAutoPtr mLeftExpr; michael@0: nsAutoPtr mRightExpr; michael@0: RelationalExprType mOp; michael@0: }; michael@0: michael@0: /** michael@0: * VariableRefExpr michael@0: * Represents a variable reference ($refname) michael@0: **/ michael@0: class VariableRefExpr : public Expr { michael@0: michael@0: public: michael@0: michael@0: VariableRefExpr(nsIAtom* aPrefix, nsIAtom* aLocalName, int32_t aNSID); michael@0: michael@0: TX_DECL_EXPR michael@0: michael@0: private: michael@0: nsCOMPtr mPrefix; michael@0: nsCOMPtr mLocalName; michael@0: int32_t mNamespace; michael@0: }; michael@0: michael@0: /** michael@0: * Represents a PathExpr michael@0: **/ michael@0: class PathExpr : public Expr { michael@0: michael@0: public: michael@0: michael@0: //-- Path Operators michael@0: //-- RELATIVE_OP is the default michael@0: //-- LF, changed from static const short to enum michael@0: enum PathOperator { RELATIVE_OP, DESCENDANT_OP }; michael@0: michael@0: /** michael@0: * Adds the Expr to this PathExpr michael@0: * The ownership of the given Expr is passed over the PathExpr, michael@0: * even on failure. michael@0: * @param aExpr the Expr to add to this PathExpr michael@0: * @return nsresult indicating out of memory michael@0: */ michael@0: nsresult addExpr(Expr* aExpr, PathOperator pathOp); michael@0: michael@0: /** michael@0: * Removes and deletes the expression at the given index. michael@0: */ michael@0: void deleteExprAt(uint32_t aPos) michael@0: { michael@0: NS_ASSERTION(aPos < mItems.Length(), michael@0: "killing bad expression index"); michael@0: mItems.RemoveElementAt(aPos); michael@0: } michael@0: michael@0: TX_DECL_OPTIMIZABLE_EXPR michael@0: michael@0: PathOperator getPathOpAt(uint32_t aPos) michael@0: { michael@0: NS_ASSERTION(aPos < mItems.Length(), "getting bad pathop index"); michael@0: return mItems[aPos].pathOp; michael@0: } michael@0: void setPathOpAt(uint32_t aPos, PathOperator aPathOp) michael@0: { michael@0: NS_ASSERTION(aPos < mItems.Length(), "setting bad pathop index"); michael@0: mItems[aPos].pathOp = aPathOp; michael@0: } michael@0: michael@0: private: michael@0: class PathExprItem { michael@0: public: michael@0: nsAutoPtr expr; michael@0: PathOperator pathOp; michael@0: }; michael@0: michael@0: nsTArray mItems; michael@0: michael@0: /* michael@0: * Selects from the descendants of the context node michael@0: * all nodes that match the Expr michael@0: */ michael@0: nsresult evalDescendants(Expr* aStep, const txXPathNode& aNode, michael@0: txIMatchContext* aContext, michael@0: txNodeSet* resNodes); michael@0: }; michael@0: michael@0: /** michael@0: * This class represents a RootExpr, which only matches the Document node michael@0: **/ michael@0: class RootExpr : public Expr { michael@0: public: michael@0: /** michael@0: * Creates a new RootExpr michael@0: */ michael@0: RootExpr() michael@0: #ifdef TX_TO_STRING michael@0: : mSerialize(true) michael@0: #endif michael@0: { michael@0: } michael@0: michael@0: TX_DECL_EXPR michael@0: michael@0: #ifdef TX_TO_STRING michael@0: public: michael@0: void setSerialize(bool aSerialize) michael@0: { michael@0: mSerialize = aSerialize; michael@0: } michael@0: michael@0: private: michael@0: // When a RootExpr is used in a PathExpr it shouldn't be serialized michael@0: bool mSerialize; michael@0: #endif michael@0: }; //-- RootExpr michael@0: michael@0: /** michael@0: * Represents a UnionExpr michael@0: **/ michael@0: class UnionExpr : public Expr { michael@0: public: michael@0: /** michael@0: * Adds the PathExpr to this UnionExpr michael@0: * The ownership of the given Expr is passed over the UnionExpr, michael@0: * even on failure. michael@0: * @param aExpr the Expr to add to this UnionExpr michael@0: * @return nsresult indicating out of memory michael@0: */ michael@0: nsresult addExpr(Expr* aExpr) michael@0: { michael@0: return mExpressions.AppendElement(aExpr) ? michael@0: NS_OK : NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: /** michael@0: * Removes and deletes the expression at the given index. michael@0: */ michael@0: void deleteExprAt(uint32_t aPos) michael@0: { michael@0: NS_ASSERTION(aPos < mExpressions.Length(), michael@0: "killing bad expression index"); michael@0: michael@0: delete mExpressions[aPos]; michael@0: mExpressions.RemoveElementAt(aPos); michael@0: } michael@0: michael@0: TX_DECL_OPTIMIZABLE_EXPR michael@0: michael@0: private: michael@0: michael@0: txOwningArray mExpressions; michael@0: michael@0: }; //-- UnionExpr michael@0: michael@0: /** michael@0: * Class specializing in executing expressions like "@foo" where we are michael@0: * interested in different result-types, and expressions like "@foo = 'hi'" michael@0: */ michael@0: class txNamedAttributeStep : public Expr michael@0: { michael@0: public: michael@0: txNamedAttributeStep(int32_t aNsID, nsIAtom* aPrefix, michael@0: nsIAtom* aLocalName); michael@0: michael@0: TX_DECL_EXPR michael@0: michael@0: private: michael@0: int32_t mNamespace; michael@0: nsCOMPtr mPrefix; michael@0: nsCOMPtr mLocalName; michael@0: }; michael@0: michael@0: /** michael@0: * michael@0: */ michael@0: class txUnionNodeTest : public txNodeTest michael@0: { michael@0: public: michael@0: nsresult addNodeTest(txNodeTest* aNodeTest) michael@0: { michael@0: return mNodeTests.AppendElement(aNodeTest) ? michael@0: NS_OK : NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: TX_DECL_NODE_TEST michael@0: michael@0: private: michael@0: txOwningArray mNodeTests; michael@0: }; michael@0: michael@0: /** michael@0: * Expression that failed to parse michael@0: */ michael@0: class txErrorExpr : public Expr michael@0: { michael@0: public: michael@0: #ifdef TX_TO_STRING michael@0: txErrorExpr(const nsAString& aStr) michael@0: : mStr(aStr) michael@0: { michael@0: } michael@0: #endif michael@0: michael@0: TX_DECL_EXPR michael@0: michael@0: #ifdef TX_TO_STRING michael@0: private: michael@0: nsString mStr; michael@0: #endif michael@0: }; michael@0: michael@0: #endif michael@0: michael@0: