diff --git a/.bzrignore b/.bzrignore index c72c1ba3..4be526c7 100644 --- a/.bzrignore +++ b/.bzrignore @@ -34,3 +34,4 @@ vs9/mangle.sln *.stackdump *.lnk spec +gmon.out diff --git a/include/XPath/impl/xpath_arithmetic.hpp b/include/XPath/impl/xpath_arithmetic.hpp index d81614e3..a03e55b0 100644 --- a/include/XPath/impl/xpath_arithmetic.hpp +++ b/include/XPath/impl/xpath_arithmetic.hpp @@ -1,6 +1,7 @@ #ifndef ARABICA_XPATHIC_XPATH_ARITHMETIC_HPP #define ARABICA_XPATHIC_XPATH_ARITHMETIC_HPP +#include #include "xpath_value.hpp" namespace Arabica @@ -10,12 +11,12 @@ namespace XPath namespace impl { -template -class PlusOperator : public BinaryExpression +template +class ArithmeticOperator : public BinaryExpression { typedef BinaryExpression baseT; public: - PlusOperator(XPathExpression_impl* lhs, XPathExpression_impl* rhs) : + ArithmeticOperator(XPathExpression_impl* lhs, XPathExpression_impl* rhs) : BinaryExpression(lhs, rhs) { } virtual ValueType type() const { return NUMBER; } @@ -23,81 +24,67 @@ public: virtual XPathValue evaluate(const DOM::Node& context, const ExecutionContext& executionContext) const { - return NumericValue::createValue(baseT::lhs()->evaluateAsNumber(context, executionContext) + baseT::rhs()->evaluateAsNumber(context, executionContext)); + return NumericValue::createValue(evaluateAsNumber(context, executionContext)); } // evaluate + + virtual double evaluateAsNumber(const DOM::Node& context, + const ExecutionContext& executionContext) const + { + return Op()(baseT::lhs()->evaluateAsNumber(context, executionContext), + baseT::rhs()->evaluateAsNumber(context, executionContext)); + } // evaluateAsNumber +}; // class ArithmeticOperator + +template +class PlusOperator : public ArithmeticOperator > +{ +public: + PlusOperator(XPathExpression_impl* lhs, XPathExpression_impl* rhs) : + ArithmeticOperator >(lhs, rhs) { } }; // class PlusOperator template -class MinusOperator : public BinaryExpression +class MinusOperator : public ArithmeticOperator > { - typedef BinaryExpression baseT; public: MinusOperator(XPathExpression_impl* lhs, XPathExpression_impl* rhs) : - BinaryExpression(lhs, rhs) { } - - virtual ValueType type() const { return NUMBER; } - - virtual XPathValue evaluate(const DOM::Node& context, - const ExecutionContext& executionContext) const - { - return NumericValue::createValue(baseT::lhs()->evaluateAsNumber(context, executionContext) - baseT::rhs()->evaluateAsNumber(context, executionContext)); - } // evaluate + ArithmeticOperator >(lhs, rhs) { } }; // class MinusOperator template -class MultiplyOperator : public BinaryExpression +class MultiplyOperator : public ArithmeticOperator > { - typedef BinaryExpression baseT; public: MultiplyOperator(XPathExpression_impl* lhs, XPathExpression_impl* rhs) : - BinaryExpression(lhs, rhs) { } - - virtual ValueType type() const { return NUMBER; } - - virtual XPathValue evaluate(const DOM::Node& context, - const ExecutionContext& executionContext) const - { - return NumericValue::createValue(baseT::lhs()->evaluateAsNumber(context, executionContext) * baseT::rhs()->evaluateAsNumber(context, executionContext)); - } // evaluate + ArithmeticOperator >(lhs, rhs) { } }; // class MultiplyOperator template -class DivideOperator : public BinaryExpression +class DivideOperator : public ArithmeticOperator > { - typedef BinaryExpression baseT; public: DivideOperator(XPathExpression_impl* lhs, XPathExpression_impl* rhs) : - BinaryExpression(lhs, rhs) { } - - virtual ValueType type() const { return NUMBER; } - - virtual XPathValue evaluate(const DOM::Node& context, - const ExecutionContext& executionContext) const - { - return NumericValue::createValue(baseT::lhs()->evaluateAsNumber(context, executionContext) / baseT::rhs()->evaluateAsNumber(context, executionContext)); - } // evaluate + ArithmeticOperator >(lhs, rhs) { } }; // class DivideOperator + +struct NaN_aware_modulus +{ + double operator()(const double& lhs, const double& rhs) const + { // apply operator% to operands + if(isNaN(lhs) || isNaN(rhs)) + return NaN; + return (static_cast(lhs) % static_cast(rhs)); + } +}; // NaN_aware_modulus + template -class ModOperator : public BinaryExpression +class ModOperator : public ArithmeticOperator { typedef BinaryExpression baseT; public: ModOperator(XPathExpression_impl* lhs, XPathExpression_impl* rhs) : - BinaryExpression(lhs, rhs) { } - - virtual ValueType type() const { return NUMBER; } - - virtual XPathValue evaluate(const DOM::Node& context, - const ExecutionContext& executionContext) const - { - double l = baseT::lhs()->evaluateAsNumber(context, executionContext); - double r = baseT::rhs()->evaluateAsNumber(context, executionContext); - - if(isNaN(l) || isNaN(r)) - return NumericValue::createValue(NaN); - return NumericValue::createValue(static_cast(l) % static_cast(r)); - } // evaluate + ArithmeticOperator(lhs, rhs) { } }; // class ModOperator template @@ -113,8 +100,13 @@ public: virtual XPathValue evaluate(const DOM::Node& context, const ExecutionContext& executionContext) const { - return NumericValue::createValue(-baseT::expr()->evaluate(context, executionContext).asNumber()); + return NumericValue::createValue(evaluateAsNumber(context, executionContext)); } // evaluate + virtual double evaluateAsNumber(const DOM::Node& context, + const ExecutionContext& executionContext) const + { + return -baseT::expr()->evaluateAsNumber(context, executionContext); + } // evaluateAsNumber }; // class UnaryNegative } // namespace impl diff --git a/include/XPath/impl/xpath_expression.hpp b/include/XPath/impl/xpath_expression.hpp index 897dfe9c..389ed03f 100644 --- a/include/XPath/impl/xpath_expression.hpp +++ b/include/XPath/impl/xpath_expression.hpp @@ -48,30 +48,58 @@ public: XPathValue evaluate(const DOM::Node& context) const { - ExecutionContext executionContext; - return evaluate(context, executionContext); + return evaluate(context, StaticExecutionContext()); } // evaluate + virtual bool evaluateAsBool(const DOM::Node& context) const + { + return evaluateAsBool(context, StaticExecutionContext()); + } + virtual double evaluateAsNumber(const DOM::Node& context) const + { + return evaluateAsNumber(context, StaticExecutionContext()); + } + virtual string_type evaluateAsString(const DOM::Node& context) const + { + return evaluateAsString(context, StaticExecutionContext()); + } + virtual NodeSet evaluateAsNodeSet(const DOM::Node& context) const + { + return evaluateAsNodeSet(context, StaticExecutionContext()); + } - virtual bool evaluateAsBool(const DOM::Node& context) const { return evaluate(context).asBool(); } - virtual double evaluateAsNumber(const DOM::Node& context) const { return evaluate(context).asNumber(); } - virtual string_type evaluateAsString(const DOM::Node& context) const { return evaluate(context).asString(); } - virtual NodeSet evaluateAsNodeSet(const DOM::Node& context) const { return evaluate(context).asNodeSet(); } - - virtual XPathValue evaluate(const DOM::Node& context, + virtual XPathValue evaluate(const DOM::Node& context, const ExecutionContext& executionContext) const = 0; virtual bool evaluateAsBool(const DOM::Node& context, - const ExecutionContext& executionContext) const { return evaluate(context, executionContext).asBool(); } + const ExecutionContext& executionContext) const + { + return evaluate(context, executionContext).asBool(); + } virtual double evaluateAsNumber(const DOM::Node& context, - const ExecutionContext& executionContext) const { return evaluate(context, executionContext).asNumber(); } + const ExecutionContext& executionContext) const + { + return evaluate(context, executionContext).asNumber(); + } virtual string_type evaluateAsString(const DOM::Node& context, - const ExecutionContext& executionContext) const { return evaluate(context, executionContext).asString(); } + const ExecutionContext& executionContext) const + { + return evaluate(context, executionContext).asString(); + } virtual NodeSet evaluateAsNodeSet(const DOM::Node& context, - const ExecutionContext& executionContext) const { return evaluate(context, executionContext).asNodeSet(); } + const ExecutionContext& executionContext) const + { + return evaluate(context, executionContext).asNodeSet(); + } virtual void scan(impl::Expression_scanner& scanner) const { scanner.scan(this); } private: + static const ExecutionContext& StaticExecutionContext() + { + static ExecutionContext executionContext; + return executionContext; + } // StaticExecutionContext + XPathExpression_impl(const XPathExpression_impl&); bool operator==(const XPathExpression_impl&); XPathExpression_impl& operator=(const XPathExpression_impl&); diff --git a/include/XPath/impl/xpath_logical.hpp b/include/XPath/impl/xpath_logical.hpp index aa14d481..773d4212 100644 --- a/include/XPath/impl/xpath_logical.hpp +++ b/include/XPath/impl/xpath_logical.hpp @@ -1,66 +1,81 @@ -#ifndef ARABICA_XPATHIC_XPATH_LOGICAL_HPP -#define ARABICA_XPATHIC_XPATH_LOGICAL_HPP - -#include "xpath_value.hpp" - -namespace Arabica -{ -namespace XPath -{ -namespace impl -{ - -template -class OrOperator : public BinaryExpression -{ - typedef BinaryExpression baseT; -public: - OrOperator(XPathExpression_impl* lhs, - XPathExpression_impl* rhs) : - BinaryExpression(lhs, rhs) { } - - virtual ValueType type() const { return BOOL; } - - virtual XPathValue evaluate(const DOM::Node& context, - const ExecutionContext& executionContext) const - { - // From XPath 1.0 Rec, section 3.4 - // An or expression is evaluated by evaluating each operand and converting its value - // to a boolean as if by a call to the boolean function. The result is true if either - // value is true and false otherwise. The right operand is not evaluated if the - // left operand evaluates to true. - if(baseT::lhs()->evaluate(context, executionContext).asBool()) - return BoolValue::createValue(true); - return BoolValue::createValue(baseT::rhs()->evaluate(context, executionContext).asBool()); - } // evaluate -}; // class OrOperator - -template -class AndOperator : public BinaryExpression -{ - typedef BinaryExpression baseT; -public: - AndOperator(XPathExpression_impl* lhs, - XPathExpression_impl* rhs) : - BinaryExpression(lhs, rhs) { } - - virtual ValueType type() const { return BOOL; } - - virtual XPathValue evaluate(const DOM::Node& context, - const ExecutionContext& executionContext) const - { - // From XPath 1.0 Rec, section 3.4 - // An and expression is evaluated by evaluating each operand and converting its value - // to a boolean as if by a call to the boolean function. The result is true if both - // values are true and false otherwise. The right operand is not evaluated if the left - // operand evaluates to false. - if(!baseT::lhs()->evaluate(context, executionContext).asBool()) - return BoolValue::createValue(false); - return BoolValue::createValue(baseT::rhs()->evaluate(context, executionContext).asBool()); - } // evaluate -}; // class AndOperator - -} // namespace impl -} // namespace XPath -} // namespace Arabica -#endif +#ifndef ARABICA_XPATHIC_XPATH_LOGICAL_HPP +#define ARABICA_XPATHIC_XPATH_LOGICAL_HPP + +#include "xpath_value.hpp" + +namespace Arabica +{ +namespace XPath +{ +namespace impl +{ + + +template +class LogicalOperator : public BinaryExpression +{ +public: + LogicalOperator(XPathExpression_impl* lhs, XPathExpression_impl* rhs) : + BinaryExpression(lhs, rhs) { } + + virtual ValueType type() const { return BOOL; } + + virtual XPathValue evaluate(const DOM::Node& context, + const ExecutionContext& executionContext) const + { + return BoolValue::createValue(evaluateAsBool(context, executionContext)); + } // evaluate +}; // class LogicalOperator + +template +class OrOperator : public LogicalOperator +{ + typedef LogicalOperator LogicalOperatorT; + using LogicalOperatorT::lhs; + using LogicalOperatorT::rhs; +public: + OrOperator(XPathExpression_impl* lhs, + XPathExpression_impl* rhs) : + LogicalOperator(lhs, rhs) { } + + virtual bool evaluateAsBool(const DOM::Node& context, + const ExecutionContext& executionContext) const + { + // From XPath 1.0 Rec, section 3.4 + // An or expression is evaluated by evaluating each operand and converting its value + // to a boolean as if by a call to the boolean function. The result is true if either + // value is true and false otherwise. The right operand is not evaluated if the + // left operand evaluates to true. + return lhs()->evaluate(context, executionContext).asBool() || + rhs()->evaluate(context, executionContext).asBool(); + } // evaluateAsBool +}; // class OrOperator + +template +class AndOperator : public LogicalOperator +{ + typedef LogicalOperator LogicalOperatorT; + using LogicalOperatorT::lhs; + using LogicalOperatorT::rhs; +public: + AndOperator(XPathExpression_impl* lhs, + XPathExpression_impl* rhs) : + LogicalOperator(lhs, rhs) { } + + virtual bool evaluateAsBool(const DOM::Node& context, + const ExecutionContext& executionContext) const + { + // From XPath 1.0 Rec, section 3.4 + // An and expression is evaluated by evaluating each operand and converting its value + // to a boolean as if by a call to the boolean function. The result is true if both + // values are true and false otherwise. The right operand is not evaluated if the left + // operand evaluates to false. + return lhs()->evaluate(context, executionContext).asBool() && + rhs()->evaluate(context, executionContext).asBool(); + } // evaluateAsBool +}; // class AndOperator + +} // namespace impl +} // namespace XPath +} // namespace Arabica +#endif diff --git a/include/XPath/impl/xpath_value.hpp b/include/XPath/impl/xpath_value.hpp index a2101314..63eac5d2 100644 --- a/include/XPath/impl/xpath_value.hpp +++ b/include/XPath/impl/xpath_value.hpp @@ -14,8 +14,49 @@ namespace Arabica namespace XPath { +template +class Value_base : public XPathValue_impl, public XPathExpression_impl +{ + typedef XPathValue_impl XPathValue_implT; + using XPathValue_implT::asBool; + using XPathValue_implT::asNumber; + using XPathValue_implT::asString; + using XPathValue_implT::asNodeSet; + +protected: + Value_base() { } + ~Value_base() { } + +public: + virtual bool evaluateAsBool(const DOM::Node& context) { return asBool(); } + virtual double evaluateAsNumber(const DOM::Node& context) { return asNumber(); } + virtual string_type evaluateAsString(const DOM::Node& context) { return asString(); } + virtual NodeSet evaluateAsNodeSet(const DOM::Node& context) { return asNodeSet(); } + + virtual bool evaluateAsBool(const DOM::Node& context, + const ExecutionContext& executionContext) const + { + return asBool(); + } + virtual double evaluateAsNumber(const DOM::Node& context, + const ExecutionContext& executionContext) const + { + return asNumber(); + } + virtual string_type evaluateAsString(const DOM::Node& context, + const ExecutionContext& executionContext) const + { + return asString(); + } + virtual NodeSet evaluateAsNodeSet(const DOM::Node& context, + const ExecutionContext& executionContext) const + { + return asNodeSet(); + } +}; // class Value_base + template > -class BoolValue : public XPathValue_impl, public XPathExpression_impl +class BoolValue : public Value_base { public: BoolValue(bool value) : @@ -28,10 +69,6 @@ public: { return XPathValue(new BoolValue(value_)); } // evaluate - virtual bool evaluateAsBool(const DOM::Node& context) { return asBool(); } - virtual double evaluateAsNumber(const DOM::Node& context) { return asNumber(); } - virtual string_type evaluateAsString(const DOM::Node& context) { return asString(); } - virtual NodeSet evaluateAsNodeSet(const DOM::Node& context) { return asNodeSet(); } virtual bool asBool() const { return value_; } virtual double asNumber() const { return value_ ? 1 : 0; } @@ -45,7 +82,7 @@ private: }; // class BoolValue template > -class NumericValue : public XPathValue_impl, public XPathExpression_impl +class NumericValue : public Value_base { public: NumericValue(double value) : @@ -58,10 +95,6 @@ public: { return createValue(value_); } // evaluate - virtual bool evaluateAsBool(const DOM::Node& context) { return asBool(); } - virtual double evaluateAsNumber(const DOM::Node& context) { return asNumber(); } - virtual string_type evaluateAsString(const DOM::Node& context) { return asString(); } - virtual NodeSet evaluateAsNodeSet(const DOM::Node& context) { return asNodeSet(); } virtual bool asBool() const { @@ -89,7 +122,7 @@ private: }; // class NumberValue template > -class StringValue : public XPathValue_impl, public XPathExpression_impl +class StringValue : public Value_base { public: StringValue(const char* value) : @@ -104,10 +137,6 @@ public: { return XPathValue(new StringValue(value_)); } // evaluate - virtual bool evaluateAsBool(const DOM::Node& context) { return asBool(); } - virtual double evaluateAsNumber(const DOM::Node& context) { return asNumber(); } - virtual string_type evaluateAsString(const DOM::Node& context) { return asString(); } - virtual NodeSet evaluateAsNodeSet() const { return asNodeSet(); } virtual bool asBool() const { return !string_adaptor::empty(value_); } virtual double asNumber() const @@ -124,7 +153,7 @@ private: }; // class StringValue template > -class NodeSetValue : public XPathValue_impl, public XPathExpression_impl +class NodeSetValue : public Value_base { public: NodeSetValue(const NodeSet& set) : set_(set) { } @@ -139,10 +168,6 @@ public: { return XPathValue(this); } // evaluate - virtual bool evaluateAsBool(const DOM::Node& context) const{ return asBool(); } - virtual double evaluateAsNumber(const DOM::Node& context) const { return asNumber(); } - virtual string_type evaluateAsString(const DOM::Node& context) const { return asString(); } - virtual const NodeSet& evaluateAsNodeSet() const { return asNodeSet(); } virtual bool asBool() const { diff --git a/include/XSLT/impl/handler/xslt_inline_element_handler.hpp b/include/XSLT/impl/handler/xslt_inline_element_handler.hpp old mode 100644 new mode 100755 diff --git a/tests/XSLT/TO-DO b/tests/XSLT/TO-DO index b25ada98..2ff38a3a 100644 --- a/tests/XSLT/TO-DO +++ b/tests/XSLT/TO-DO @@ -19,3 +19,10 @@ output combining (partially done for cdata-section-elements) Performance + variable pool + string pool? + use underlying_impl in XPath axis walker + use underlying_impl in XPath functions + short circuit evaluation in functions + only convert to full NodeSet at boundary + use a proxy to return propagate values out of functions \ No newline at end of file