1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef TRANSFRMX_EXPR_H
7 #define TRANSFRMX_EXPR_H
9 #include "mozilla/Attributes.h"
10 #include "mozilla/UniquePtr.h"
11 #include "txExprResult.h"
14 #include "txOwningArray.h"
22 XPath class definitions.
23 Much of this code was ported from XSL:P.
27 class txIMatchContext
;
31 class txXPathTreeWalker
;
34 * A Base Class for all XSL Expressions
38 MOZ_COUNTED_DEFAULT_CTOR(Expr
)
39 MOZ_COUNTED_DTOR_VIRTUAL(Expr
)
42 * Evaluates this Expr based on the given context node and processor state
43 * @param context the context node for evaluation of this Expr
44 * @param ps the ContextState containing the stack information needed
46 * @return the result of the evaluation
48 virtual nsresult
evaluate(txIEvalContext
* aContext
,
49 txAExprResult
** aResult
) = 0;
52 * Returns the type of this expression.
61 virtual ExprType
getType() { return OTHER_EXPR
; }
64 * Returns the type or types of results this Expr return.
66 using ResultType
= uint16_t;
68 NODESET_RESULT
= 0x01,
69 BOOLEAN_RESULT
= 0x02,
75 virtual ResultType
getReturnType() = 0;
76 bool canReturnType(ResultType aType
) {
77 return (getReturnType() & aType
) != 0;
80 using ContextSensitivity
= uint16_t;
84 POSITION_CONTEXT
= 0x02,
86 NODESET_CONTEXT
= POSITION_CONTEXT
| SIZE_CONTEXT
,
87 VARIABLES_CONTEXT
= 0x08,
88 PRIVATE_CONTEXT
= 0x10,
93 * Returns true if this expression is sensitive to *any* of
94 * the requested contexts in aContexts.
96 virtual bool isSensitiveTo(ContextSensitivity aContexts
) = 0;
99 * Returns sub-expression at given position
101 virtual Expr
* getSubExprAt(uint32_t aPos
) = 0;
104 * Replace sub-expression at given position. Does not delete the old
105 * expression, that is the responsibility of the caller.
107 virtual void setSubExprAt(uint32_t aPos
, Expr
* aExpr
) = 0;
109 virtual nsresult
evaluateToBool(txIEvalContext
* aContext
, bool& aResult
);
111 virtual nsresult
evaluateToString(txIEvalContext
* aContext
,
116 * Returns the String representation of this Expr.
117 * @param dest the String to use when creating the String
118 * representation. The String representation will be appended to
119 * any data in the destination String, to allow cascading calls to
120 * other #toString() methods for Expressions.
121 * @return the String representation of this Expr.
123 virtual void toString(nsAString
& str
) = 0;
128 # define TX_DECL_TOSTRING void toString(nsAString& aDest) override;
129 # define TX_DECL_APPENDNAME void appendName(nsAString& aDest) override;
131 # define TX_DECL_TOSTRING
132 # define TX_DECL_APPENDNAME
135 #define TX_DECL_EXPR_BASE \
136 nsresult evaluate(txIEvalContext* aContext, txAExprResult** aResult) \
138 ResultType getReturnType() override; \
139 bool isSensitiveTo(ContextSensitivity aContexts) override;
141 #define TX_DECL_EXPR \
144 Expr* getSubExprAt(uint32_t aPos) override; \
145 void setSubExprAt(uint32_t aPos, Expr* aExpr) override;
147 #define TX_DECL_OPTIMIZABLE_EXPR \
149 ExprType getType() override;
151 #define TX_DECL_FUNCTION \
155 #define TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \
156 Expr::ResultType _class::getReturnType() { return _ReturnType; }
158 #define TX_IMPL_EXPR_STUBS_0(_class, _ReturnType) \
159 TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \
160 Expr* _class::getSubExprAt(uint32_t aPos) { return nullptr; } \
161 void _class::setSubExprAt(uint32_t aPos, Expr* aExpr) { \
162 MOZ_ASSERT_UNREACHABLE("setting bad subexpression index"); \
165 #define TX_IMPL_EXPR_STUBS_1(_class, _ReturnType, _Expr1) \
166 TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \
167 Expr* _class::getSubExprAt(uint32_t aPos) { \
169 return _Expr1.get(); \
173 void _class::setSubExprAt(uint32_t aPos, Expr* aExpr) { \
174 NS_ASSERTION(aPos < 1, "setting bad subexpression index"); \
175 mozilla::Unused << _Expr1.release(); \
176 _Expr1 = mozilla::WrapUnique(aExpr); \
179 #define TX_IMPL_EXPR_STUBS_2(_class, _ReturnType, _Expr1, _Expr2) \
180 TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \
181 Expr* _class::getSubExprAt(uint32_t aPos) { \
184 return _Expr1.get(); \
186 return _Expr2.get(); \
192 void _class::setSubExprAt(uint32_t aPos, Expr* aExpr) { \
193 NS_ASSERTION(aPos < 2, "setting bad subexpression index"); \
195 mozilla::Unused << _Expr1.release(); \
196 _Expr1 = mozilla::WrapUnique(aExpr); \
198 mozilla::Unused << _Expr2.release(); \
199 _Expr2 = mozilla::WrapUnique(aExpr); \
203 #define TX_IMPL_EXPR_STUBS_LIST(_class, _ReturnType, _ExprList) \
204 TX_IMPL_EXPR_STUBS_BASE(_class, _ReturnType) \
205 Expr* _class::getSubExprAt(uint32_t aPos) { \
206 return _ExprList.SafeElementAt(aPos); \
208 void _class::setSubExprAt(uint32_t aPos, Expr* aExpr) { \
209 NS_ASSERTION(aPos < _ExprList.Length(), \
210 "setting bad subexpression index"); \
211 _ExprList[aPos] = aExpr; \
215 * This class represents a FunctionCall as defined by the XPath 1.0
218 class FunctionCall
: public Expr
{
221 * Adds the given parameter to this FunctionCall's parameter list.
222 * The ownership of the given Expr is passed over to the FunctionCall,
224 * @param aExpr the Expr to add to this FunctionCall's parameter list
226 void addParam(Expr
* aExpr
) { mParams
.AppendElement(aExpr
); }
229 * Check if the number of parameters falls within a range.
231 * @param aParamCountMin minimum number of required parameters.
232 * @param aParamCountMax maximum number of parameters. If aParamCountMax
233 * is negative the maximum number is not checked.
234 * @return boolean representing whether the number of parameters falls
235 * within the expected range or not.
237 * XXX txIEvalContext should be txIParseContest, bug 143291
239 virtual bool requireParams(int32_t aParamCountMin
, int32_t aParamCountMax
,
240 txIEvalContext
* aContext
);
243 Expr
* getSubExprAt(uint32_t aPos
) override
;
244 void setSubExprAt(uint32_t aPos
, Expr
* aExpr
) override
;
247 txOwningArray
<Expr
> mParams
;
250 * Evaluates the given Expression and converts its result to a number.
252 static nsresult
evaluateToNumber(Expr
* aExpr
, txIEvalContext
* aContext
,
256 * Evaluates the given Expression and converts its result to a NodeSet.
257 * If the result is not a NodeSet an error is returned.
259 static nsresult
evaluateToNodeSet(Expr
* aExpr
, txIEvalContext
* aContext
,
260 txNodeSet
** aResult
);
263 * Returns true if any argument is sensitive to the given context.
265 bool argsSensitiveTo(ContextSensitivity aContexts
);
269 * Appends the name of the function to `aStr`.
271 virtual void appendName(nsAString
& aStr
) = 0;
275 class txCoreFunctionCall
: public FunctionCall
{
277 // This must be ordered in the same order as descriptTable in
278 // txCoreFunctionCall.cpp. If you change one, change the other.
280 COUNT
= 0, // count()
283 LOCAL_NAME
, // local-name()
284 NAMESPACE_URI
, // namespace-uri()
286 POSITION
, // position()
289 CONTAINS
, // contains()
290 NORMALIZE_SPACE
, // normalize-space()
291 STARTS_WITH
, // starts-with()
293 STRING_LENGTH
, // string-length()
294 SUBSTRING
, // substring()
295 SUBSTRING_AFTER
, // substring-after()
296 SUBSTRING_BEFORE
, // substring-before()
297 TRANSLATE
, // translate()
302 CEILING
, // ceiling()
305 BOOLEAN
, // boolean()
313 * Creates a txCoreFunctionCall of the given type
315 explicit txCoreFunctionCall(eType aType
) : mType(aType
) {}
319 static bool getTypeFromAtom(nsAtom
* aName
, eType
& aType
);
326 * This class represents a NodeTest as defined by the XPath spec
330 MOZ_COUNTED_DEFAULT_CTOR(txNodeTest
)
331 MOZ_COUNTED_DTOR_VIRTUAL(txNodeTest
)
335 * pretty much a txPattern, but not supposed to be used
336 * standalone. The NodeTest node() is different to the
337 * Pattern "node()" (document node isn't matched)
339 virtual nsresult
matches(const txXPathNode
& aNode
, txIMatchContext
* aContext
,
341 virtual double getDefaultPriority() = 0;
344 * Returns the type of this nodetest.
346 enum NodeTestType
{ NAME_TEST
, NODETYPE_TEST
, OTHER_TEST
};
347 virtual NodeTestType
getType() { return OTHER_TEST
; }
350 * Returns true if this expression is sensitive to *any* of
351 * the requested flags.
353 virtual bool isSensitiveTo(Expr::ContextSensitivity aContext
) = 0;
356 virtual void toString(nsAString
& aDest
) = 0;
360 #define TX_DECL_NODE_TEST \
362 nsresult matches(const txXPathNode& aNode, txIMatchContext* aContext, \
363 bool& aMatched) override; \
364 double getDefaultPriority() override; \
365 bool isSensitiveTo(Expr::ContextSensitivity aContext) override;
368 * This class represents a NameTest as defined by the XPath spec
370 class txNameTest
: public txNodeTest
{
373 * Creates a new txNameTest with the given type and the given
374 * principal node type
376 txNameTest(nsAtom
* aPrefix
, nsAtom
* aLocalName
, int32_t aNSID
,
379 NodeTestType
getType() override
;
383 RefPtr
<nsAtom
> mPrefix
;
384 RefPtr
<nsAtom
> mLocalName
;
392 * This class represents a NodeType as defined by the XPath spec
394 class txNodeTypeTest
: public txNodeTest
{
396 enum NodeType
{ COMMENT_TYPE
, TEXT_TYPE
, PI_TYPE
, NODE_TYPE
};
399 * Creates a new txNodeTypeTest of the given type
401 explicit txNodeTypeTest(NodeType aNodeType
) : mNodeType(aNodeType
) {}
404 * Sets the name of the node to match. Only availible for pi nodes
406 void setNodeName(const nsAString
& aName
) { mNodeName
= NS_Atomize(aName
); }
408 NodeType
getNodeTestType() { return mNodeType
; }
410 NodeTestType
getType() override
;
416 RefPtr
<nsAtom
> mNodeName
;
420 * Class representing a nodetest combined with a predicate. May only be used
421 * if the predicate is not sensitive to the context-nodelist.
423 class txPredicatedNodeTest
: public txNodeTest
{
425 txPredicatedNodeTest(txNodeTest
* aNodeTest
, Expr
* aPredicate
);
429 mozilla::UniquePtr
<txNodeTest
> mNodeTest
;
430 mozilla::UniquePtr
<Expr
> mPredicate
;
434 * Represents an ordered list of Predicates,
435 * for use with Step and Filter Expressions
437 class PredicateList
{
440 * Adds the given Expr to the list.
441 * The ownership of the given Expr is passed over the PredicateList,
443 * @param aExpr the Expr to add to the list
445 void add(Expr
* aExpr
) {
446 NS_ASSERTION(aExpr
, "missing expression");
447 mPredicates
.AppendElement(aExpr
);
450 nsresult
evaluatePredicates(txNodeSet
* aNodes
, txIMatchContext
* aContext
);
453 * Drops the first predicate without deleting it.
455 void dropFirst() { mPredicates
.RemoveElementAt(0); }
458 * returns true if this predicate list is empty
460 bool isEmpty() { return mPredicates
.IsEmpty(); }
464 * Returns the String representation of this PredicateList.
465 * @param dest the String to use when creating the String
466 * representation. The String representation will be appended to
467 * any data in the destination String, to allow cascading calls to
468 * other #toString() methods for Expressions.
469 * @return the String representation of this PredicateList.
471 void toString(nsAString
& dest
);
475 bool isSensitiveTo(Expr::ContextSensitivity aContext
);
476 Expr
* getSubExprAt(uint32_t aPos
) { return mPredicates
.SafeElementAt(aPos
); }
477 void setSubExprAt(uint32_t aPos
, Expr
* aExpr
) {
478 NS_ASSERTION(aPos
< mPredicates
.Length(),
479 "setting bad subexpression index");
480 mPredicates
[aPos
] = aExpr
;
483 //-- list of predicates
484 txOwningArray
<Expr
> mPredicates
;
485 }; //-- PredicateList
487 class LocationStep
: public Expr
, public PredicateList
{
489 enum LocationStepType
{
491 ANCESTOR_OR_SELF_AXIS
,
495 DESCENDANT_OR_SELF_AXIS
,
497 FOLLOWING_SIBLING_AXIS
,
501 PRECEDING_SIBLING_AXIS
,
506 * Creates a new LocationStep using the given NodeExpr and Axis Identifier
507 * @param nodeExpr the NodeExpr to use when matching Nodes
508 * @param axisIdentifier the Axis Identifier in which to search for nodes
510 LocationStep(txNodeTest
* aNodeTest
, LocationStepType aAxisIdentifier
)
511 : mNodeTest(aNodeTest
), mAxisIdentifier(aAxisIdentifier
) {}
513 TX_DECL_OPTIMIZABLE_EXPR
515 txNodeTest
* getNodeTest() { return mNodeTest
.get(); }
516 void setNodeTest(txNodeTest
* aNodeTest
) {
517 mozilla::Unused
<< mNodeTest
.release();
518 mNodeTest
= mozilla::WrapUnique(aNodeTest
);
520 LocationStepType
getAxisIdentifier() { return mAxisIdentifier
; }
521 void setAxisIdentifier(LocationStepType aAxisIdentifier
) {
522 mAxisIdentifier
= aAxisIdentifier
;
527 * Append the current position of aWalker to aNodes if it matches mNodeTest,
528 * using aContext as the context for matching.
530 nsresult
appendIfMatching(const txXPathTreeWalker
& aWalker
,
531 txIMatchContext
* aContext
, txNodeSet
* aNodes
);
534 * Append the descendants of the current position of aWalker to aNodes if
535 * they match mNodeTest, using aContext as the context for matching.
537 nsresult
appendMatchingDescendants(const txXPathTreeWalker
& aWalker
,
538 txIMatchContext
* aContext
,
542 * Append the descendants of the current position of aWalker to aNodes in
543 * reverse order if they match mNodeTest, using aContext as the context for
546 nsresult
appendMatchingDescendantsRev(const txXPathTreeWalker
& aWalker
,
547 txIMatchContext
* aContext
,
550 mozilla::UniquePtr
<txNodeTest
> mNodeTest
;
551 LocationStepType mAxisIdentifier
;
554 class FilterExpr
: public Expr
, public PredicateList
{
557 * Creates a new FilterExpr using the given Expr
558 * @param expr the Expr to use for evaluation
560 explicit FilterExpr(Expr
* aExpr
) : expr(aExpr
) {}
565 mozilla::UniquePtr
<Expr
> expr
;
569 class txLiteralExpr
: public Expr
{
571 explicit txLiteralExpr(double aDbl
)
572 : mValue(new NumberResult(aDbl
, nullptr)) {}
573 explicit txLiteralExpr(const nsAString
& aStr
)
574 : mValue(new StringResult(aStr
, nullptr)) {}
575 explicit txLiteralExpr(txAExprResult
* aValue
) : mValue(aValue
) {}
580 RefPtr
<txAExprResult
> mValue
;
584 * Represents an UnaryExpr. Returns the negative value of its expr.
586 class UnaryExpr
: public Expr
{
588 explicit UnaryExpr(Expr
* aExpr
) : expr(aExpr
) {}
593 mozilla::UniquePtr
<Expr
> expr
;
597 * Represents a BooleanExpr, a binary expression that
598 * performs a boolean operation between its lvalue and rvalue.
600 class BooleanExpr
: public Expr
{
602 //-- BooleanExpr Types
603 enum _BooleanExprType
{ AND
= 1, OR
};
605 BooleanExpr(Expr
* aLeftExpr
, Expr
* aRightExpr
, short aOp
)
606 : leftExpr(aLeftExpr
), rightExpr(aRightExpr
), op(aOp
) {}
611 mozilla::UniquePtr
<Expr
> leftExpr
, rightExpr
;
616 * Represents a MultiplicativeExpr, a binary expression that
617 * performs a multiplicative operation between its lvalue and rvalue:
623 class txNumberExpr
: public Expr
{
625 enum eOp
{ ADD
, SUBTRACT
, DIVIDE
, MULTIPLY
, MODULUS
};
627 txNumberExpr(Expr
* aLeftExpr
, Expr
* aRightExpr
, eOp aOp
)
628 : mLeftExpr(aLeftExpr
), mRightExpr(aRightExpr
), mOp(aOp
) {}
633 mozilla::UniquePtr
<Expr
> mLeftExpr
, mRightExpr
;
635 }; //-- MultiplicativeExpr
638 * Represents a RelationalExpr, an expression that compares its lvalue
639 * to its rvalue using:
643 * <= : less than or equal to
644 * >= : greater than or equal to
647 class RelationalExpr
: public Expr
{
649 enum RelationalExprType
{
658 RelationalExpr(Expr
* aLeftExpr
, Expr
* aRightExpr
, RelationalExprType aOp
)
659 : mLeftExpr(aLeftExpr
), mRightExpr(aRightExpr
), mOp(aOp
) {}
664 bool compareResults(txIEvalContext
* aContext
, txAExprResult
* aLeft
,
665 txAExprResult
* aRight
);
667 mozilla::UniquePtr
<Expr
> mLeftExpr
;
668 mozilla::UniquePtr
<Expr
> mRightExpr
;
669 RelationalExprType mOp
;
674 * Represents a variable reference ($refname)
676 class VariableRefExpr
: public Expr
{
678 VariableRefExpr(nsAtom
* aPrefix
, nsAtom
* aLocalName
, int32_t aNSID
);
683 RefPtr
<nsAtom
> mPrefix
;
684 RefPtr
<nsAtom
> mLocalName
;
689 * Represents a PathExpr
691 class PathExpr
: public Expr
{
694 //-- RELATIVE_OP is the default
695 //-- LF, changed from static const short to enum
696 enum PathOperator
{ RELATIVE_OP
, DESCENDANT_OP
};
699 * Adds the Expr to this PathExpr
700 * The ownership of the given Expr is passed over the PathExpr,
702 * @param aExpr the Expr to add to this PathExpr
704 void addExpr(Expr
* aExpr
, PathOperator pathOp
);
707 * Removes and deletes the expression at the given index.
709 void deleteExprAt(uint32_t aPos
) {
710 NS_ASSERTION(aPos
< mItems
.Length(), "killing bad expression index");
711 mItems
.RemoveElementAt(aPos
);
714 TX_DECL_OPTIMIZABLE_EXPR
716 PathOperator
getPathOpAt(uint32_t aPos
) {
717 NS_ASSERTION(aPos
< mItems
.Length(), "getting bad pathop index");
718 return mItems
[aPos
].pathOp
;
720 void setPathOpAt(uint32_t aPos
, PathOperator aPathOp
) {
721 NS_ASSERTION(aPos
< mItems
.Length(), "setting bad pathop index");
722 mItems
[aPos
].pathOp
= aPathOp
;
728 mozilla::UniquePtr
<Expr
> expr
;
732 nsTArray
<PathExprItem
> mItems
;
735 * Selects from the descendants of the context node
736 * all nodes that match the Expr
738 nsresult
evalDescendants(Expr
* aStep
, const txXPathNode
& aNode
,
739 txIMatchContext
* aContext
, txNodeSet
* resNodes
);
743 * This class represents a RootExpr, which only matches the Document node
745 class RootExpr
: public Expr
{
748 * Creates a new RootExpr
761 void setSerialize(bool aSerialize
) { mSerialize
= aSerialize
; }
764 // When a RootExpr is used in a PathExpr it shouldn't be serialized
770 * Represents a UnionExpr
772 class UnionExpr
: public Expr
{
775 * Adds the PathExpr to this UnionExpr
776 * The ownership of the given Expr is passed over the UnionExpr,
778 * @param aExpr the Expr to add to this UnionExpr
780 void addExpr(Expr
* aExpr
) { mExpressions
.AppendElement(aExpr
); }
783 * Removes and deletes the expression at the given index.
785 void deleteExprAt(uint32_t aPos
) {
786 NS_ASSERTION(aPos
< mExpressions
.Length(), "killing bad expression index");
788 delete mExpressions
[aPos
];
789 mExpressions
.RemoveElementAt(aPos
);
792 TX_DECL_OPTIMIZABLE_EXPR
795 txOwningArray
<Expr
> mExpressions
;
800 * Class specializing in executing expressions like "@foo" where we are
801 * interested in different result-types, and expressions like "@foo = 'hi'"
803 class txNamedAttributeStep
: public Expr
{
805 txNamedAttributeStep(int32_t aNsID
, nsAtom
* aPrefix
, nsAtom
* aLocalName
);
811 RefPtr
<nsAtom
> mPrefix
;
812 RefPtr
<nsAtom
> mLocalName
;
818 class txUnionNodeTest
: public txNodeTest
{
820 void addNodeTest(txNodeTest
* aNodeTest
) {
821 mNodeTests
.AppendElement(aNodeTest
);
827 txOwningArray
<txNodeTest
> mNodeTests
;
831 * Expression that failed to parse
833 class txErrorExpr
: public Expr
{
836 explicit txErrorExpr(const nsAString
& aStr
) : mStr(aStr
) {}