From d357f70405e31f19a69658dc510e2a24e1f57d06 Mon Sep 17 00:00:00 2001 From: jez <> Date: Sat, 2 Aug 2008 21:41:44 +0000 Subject: [PATCH] detect circular references and throw exception --- include/XSLT/impl/xslt_variable_stack.hpp | 97 ++++++++++++----------- 1 file changed, 52 insertions(+), 45 deletions(-) diff --git a/include/XSLT/impl/xslt_variable_stack.hpp b/include/XSLT/impl/xslt_variable_stack.hpp index a59545f7..7b8a1d76 100755 --- a/include/XSLT/impl/xslt_variable_stack.hpp +++ b/include/XSLT/impl/xslt_variable_stack.hpp @@ -35,14 +35,14 @@ private: class VariableStack : public Arabica::XPath::VariableResolver { public: - VariableStack() - { + VariableStack() + { stack_.push_back(Scope()); - + params_.push_back(Scope()); params_.push_back(Scope()); - } // VariableStack - + } // VariableStack + VariableStack(const VariableStack& rhs) : stack_(rhs.stack_), params_(rhs.params_) @@ -50,10 +50,10 @@ public: } // VariableStack void pushScope() - { - stack_.push_back(Scope()); + { + stack_.push_back(Scope()); params_.push_back(Scope()); - } // pushScope + } // pushScope void chainScope() { @@ -61,12 +61,12 @@ public: params_.push_back(Scope(params_.back())); } // chainsScope - void popScope() - { + void popScope() + { params_.pop_back(); - stack_.pop_back(); - } // popScope - + stack_.pop_back(); + } // popScope + void topLevelParam(Variable_instance_ptr param) { params_.front()[clarkName(param)] = param; @@ -91,69 +91,76 @@ public: void declareParam(Variable_instance_ptr param) { ScopeStack::reverse_iterator p = params_.rbegin()+1; - Scope::iterator i = p->find(clarkName(param)); - if(i == p->end()) + Scope::iterator i = p->find(clarkName(param)); + if(i == p->end()) declareVariable(param); else declareVariable(i->second); } // declareParam - void declareVariable(Variable_instance_ptr var) - { + void declareVariable(Variable_instance_ptr var) + { std::string name = clarkName(var); Scope& stack = stack_.back(); - + if(stack.find(name) != stack.end()) throw std::runtime_error("Duplicate variable name : " + name); - stack[clarkName(var)] = var; - } // declareVariable - + stack[clarkName(var)] = var; + } // declareVariable + void freezeTopLevel() { const Scope& top = stack_.front(); for(Scope::const_iterator v = top.begin(), ve = top.end(); v != ve; ++v) v->second->injectGlobalScope(top); } // freezeTopLevel - + void injectGlobalScope(const Scope& scope) { stack_.front() = scope; } // injectGlobalScope - + virtual Arabica::XPath::XPathValue resolveVariable(const std::string& namespace_uri, const std::string& name) const { std::string clarkName = "{" + namespace_uri + "}" + name; - Arabica::XPath::XPathValue val = lookup(stack_.back(), clarkName); - if(val != 0) - return val; + if(std::find(resolutionStack_.begin(), resolutionStack_.end(), clarkName) != resolutionStack_.end()) + throw std::runtime_error("Circular dependency: " + clarkName + " refers to itself directly or indirectly."); - val = lookup(stack_.front(), clarkName); // try our "global" scope - if(val == 0) - throw Arabica::XPath::UnboundVariableException(clarkName); - - return val; + resolutionStack_.push_back(clarkName); + Arabica::XPath::XPathValue val = lookup(stack_.back(), clarkName); + resolutionStack_.pop_back(); + + if(val != 0) + return val; + + val = lookup(stack_.front(), clarkName); // try our "global" scope + if(val == 0) + throw Arabica::XPath::UnboundVariableException(clarkName); + + return val; } // resolveVariable - + private: - typedef std::vector ScopeStack; - + typedef std::vector ScopeStack; + std::string clarkName(Variable_instance_ptr var) { return "{" + var->namespace_uri() + "}" + var->name(); } // clarkName - - Arabica::XPath::XPathValue lookup(const Scope& scope, const std::string& name) const - { - Scope::const_iterator i = scope.find(name); - if(i == scope.end()) - return Arabica::XPath::XPathValue(0); - - return i->second->value(); - } // lookup - - ScopeStack stack_; + + Arabica::XPath::XPathValue lookup(const Scope& scope, const std::string& name) const + { + Scope::const_iterator i = scope.find(name); + if(i == scope.end()) + return Arabica::XPath::XPathValue(0); + + return i->second->value(); + } // lookup + + ScopeStack stack_; ScopeStack params_; + mutable std::vector resolutionStack_; }; // class VariableStack } // namespace XSLT