#ifndef ARABICA_XSLT_EXECUTION_CONTEXT_HPP #define ARABICA_XSLT_EXECUTION_CONTEXT_HPP #include #include "xslt_sink.hpp" #include "xslt_variable_stack.hpp" namespace Arabica { namespace XSLT { template class CompiledStylesheet; template class ExecutionContext; template class StackFrame; template class ChainStackFrame; template class Variable_declaration { protected: Variable_declaration() { } public: virtual const string_type& name() const = 0; virtual Arabica::XPath::XPathValue value(const DOM::Node& node, ExecutionContext& context, DOMSink& sink) const = 0; virtual const Precedence& precedence() const = 0; private: Variable_declaration(const Variable_declaration&); Variable_declaration& operator=(const Variable_declaration&); bool operator==(const Variable_declaration&) const; }; // class Variable_declaration template class ExecutionContext { public: ExecutionContext(const CompiledStylesheet& stylesheet, Sink& output, std::basic_ostream& error_output) : stylesheet_(stylesheet), sink_(output.asOutput()), message_sink_(error_output), to_msg_(0) { xpathContext_.setVariableResolver(stack_); sink_.set_warning_sink(message_sink_.asOutput()); message_sink_.asOutput().set_warning_sink(message_sink_.asOutput()); } // ExecutionContext ExecutionContext(Sink& output, ExecutionContext& rhs) : stylesheet_(rhs.stylesheet_), stack_(rhs.stack_), sink_(output.asOutput()), message_sink_(rhs.message_sink_), to_msg_(false) { xpathContext_.setVariableResolver(stack_); xpathContext_.setCurrentNode(rhs.xpathContext().currentNode()); xpathContext_.setPosition(rhs.xpathContext().position()); xpathContext_.setLast(rhs.xpathContext().last()); } // ExecutionContext const CompiledStylesheet& stylesheet() const { return stylesheet_; } Output& sink() { return !to_msg_ ? sink_ : message_sink_.asOutput(); } // sink void redirectToMessageSink() { ++to_msg_; } void revertFromMessageSink() { --to_msg_; if (to_msg_ == 0) message_sink_.flush(); } const Arabica::XPath::ExecutionContext& xpathContext() const { return xpathContext_; } void topLevelParam(const DOM::Node& node, const Variable_declaration& param); string_type passParam(const DOM::Node& node, const Variable_declaration& param); void unpassParam(const string_type& name); void declareParam(const DOM::Node& node, const Variable_declaration& param); void declareVariable(const DOM::Node& node, const Variable_declaration& variable); void freezeTopLevel(); void injectGlobalScope(const typename ScopeType::Scope& scope); void setPosition(const DOM::Node& current, size_t pos) { setPosition(current, static_cast(pos)); } void setPosition(const DOM::Node& current, int pos) { xpathContext_.setCurrentNode(current); xpathContext_.setPosition(pos); } // setPosition int setLast(int last) { int old = xpathContext_.last(); xpathContext_.setLast(last); return old; } // setLast private: void pushStackFrame() { stack_.pushScope(); } void chainStackFrame() { stack_.chainScope(); } void popStackFrame() { stack_.popScope(); } private: const CompiledStylesheet& stylesheet_; VariableStack stack_; Arabica::XPath::ExecutionContext xpathContext_; Output& sink_; StreamSink message_sink_; int to_msg_; friend class StackFrame ; friend class ChainStackFrame ; }; // class ExecutionContext /////////////////////////// template class VariableClosure : public Variable_instance { public: typedef typename ScopeType::Variable_instance_ptr Variable_instance_ptr; typedef typename ScopeType::Scope Scope; static Variable_instance_ptr create(const Variable_declaration& var, const DOM::Node& node, ExecutionContext& context) { return Variable_instance_ptr(new VariableClosure(var, node, context)); } // create virtual const string_type& name() const { return var_.name(); } virtual const Precedence& precedence() const { return var_.precedence(); } virtual Arabica::XPath::XPathValue value() const { if(!value_) value_ = var_.value(node_, context_, sink_); return value_; } // value virtual void injectGlobalScope(const Scope& scope) const { context_.injectGlobalScope(scope); } // globalScope private: VariableClosure(const Variable_declaration& var, const DOM::Node& node, ExecutionContext& context) : var_(var), sink_(), node_(node), context_(sink_, context) { } // VariableClosure const Variable_declaration& var_; mutable DOMSink sink_; const DOM::Node node_; mutable ExecutionContext context_; mutable Arabica::XPath::XPathValue value_; VariableClosure(); VariableClosure(const VariableClosure&); VariableClosure& operator=(const VariableClosure&); const VariableClosure& operator==(const VariableClosure&) const; }; // class VariableClosure /////////////////////////// template void ExecutionContext::topLevelParam(const DOM::Node& node, const Variable_declaration& param) { stack_.topLevelParam(VariableClosure::create(param, node, *this)); } // topLevelParam template string_type ExecutionContext::passParam(const DOM::Node& node, const Variable_declaration& param) { return stack_.passParam(VariableClosure::create(param, node, *this)); } // passParam template void ExecutionContext::unpassParam(const string_type& name) { stack_.unpassParam(name); } // unpassParam template void ExecutionContext::declareParam(const DOM::Node& node, const Variable_declaration& param) { if(!stack_.findPassedParam(param.name())) stack_.declareParam(VariableClosure::create(param, node, *this)); } // declareParam template void ExecutionContext::declareVariable(const DOM::Node& node, const Variable_declaration& variable) { stack_.declareVariable(VariableClosure::create(variable, node, *this)); } // declareVariable template void ExecutionContext::freezeTopLevel() { stack_.freezeTopLevel(); } // freezeTopLevel template void ExecutionContext::injectGlobalScope(const typename ScopeType::Scope& scope) { stack_.injectGlobalScope(scope); } // injectGlobalScope /////////////////////////// template class StackFrame { public: StackFrame(ExecutionContext& context) : context_(context) { context_.pushStackFrame(); } ~StackFrame() { context_.popStackFrame(); } private: ExecutionContext& context_; StackFrame(const StackFrame&); StackFrame& operator=(const StackFrame&); bool operator==(const StackFrame&) const; }; // class StackFrame template class ChainStackFrame { public: ChainStackFrame(ExecutionContext& context) : context_(context) { context_.chainStackFrame(); } ~ChainStackFrame() { context_.popStackFrame(); } private: ExecutionContext& context_; ChainStackFrame(const ChainStackFrame&); ChainStackFrame& operator=(const ChainStackFrame&); bool operator==(const ChainStackFrame&) const; }; // class ChainStackFrame /////////////////////////// template class LastFrame { public: LastFrame(ExecutionContext& context, int last) : context_(context) { oldLast_ = context_.setLast(last); } // LastFrame LastFrame(ExecutionContext& context, size_t last) : context_(context) { oldLast_ = context_.setLast(static_cast(last)); } // LastFrame ~LastFrame() { context_.setLast(oldLast_); } // ~LastFrame private: ExecutionContext& context_; int oldLast_; LastFrame(const LastFrame&); LastFrame& operator=(const LastFrame&); bool operator==(const LastFrame&) const; }; // class LastFrame } // namespace XSLT } // namespace Arabica #endif // ARABICA_XSLT_EXECUTION_CONTEXT_HPP