diff options
Diffstat (limited to 'src/modcontext.cc')
-rw-r--r-- | src/modcontext.cc | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/src/modcontext.cc b/src/modcontext.cc new file mode 100644 index 0000000..7d123b8 --- /dev/null +++ b/src/modcontext.cc @@ -0,0 +1,152 @@ +#include "modcontext.h" +#include "module.h" +#include "expression.h" +#include "function.h" +#include "printutils.h" +#include "builtin.h" + +#include <boost/foreach.hpp> + +ModuleContext::ModuleContext(const class Module *module, const Context *parent, const EvalContext *evalctx) + : Context(parent) +{ + if (module) { + setModule(*module, evalctx); + } + else { + this->functions_p = NULL; + this->modules_p = NULL; + this->usedlibs_p = NULL; + } +} + +ModuleContext::~ModuleContext() +{ +} + +void ModuleContext::setModule(const Module &module, const EvalContext *evalctx) +{ + this->setVariables(module.definition_arguments, evalctx); + this->evalctx = evalctx; + + // FIXME: Don't access module members directly + this->functions_p = &module.functions; + this->modules_p = &module.modules; + this->usedlibs_p = &module.usedlibs; + BOOST_FOREACH(const std::string &var, module.assignments_var) { + this->set_variable(var, module.assignments.at(var)->evaluate(this)); + } + + if (!module.modulePath().empty()) this->document_path = module.modulePath(); +} + +/*! + Only used to initialize builtins for the top-level root context +*/ +void ModuleContext::registerBuiltin() +{ + this->setModule(Builtins::instance()->getRootModule()); + this->set_constant("PI",Value(M_PI)); +} + +class RecursionGuard +{ +public: + RecursionGuard(const ModuleContext &c, const std::string &name) : c(c), name(name) { + c.recursioncount[name]++; + } + ~RecursionGuard() { if (--c.recursioncount[name] == 0) c.recursioncount.erase(name); } + bool recursion_detected() const { return (c.recursioncount[name] > 100); } +private: + const ModuleContext &c; + const std::string &name; +}; + +Value ModuleContext::evaluate_function(const std::string &name, const EvalContext *evalctx) const +{ + RecursionGuard g(*this, name); + if (g.recursion_detected()) { + PRINTB("Recursion detected calling function '%s'", name); + return Value(); + } + + if (this->functions_p && this->functions_p->find(name) != this->functions_p->end()) { + return this->functions_p->find(name)->second->evaluate(this, evalctx); + } + + if (this->usedlibs_p) { + BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { + if (m.second->functions.find(name) != m.second->functions.end()) { + ModuleContext ctx(m.second, this->parent); + // FIXME: Set document path +#if 0 && DEBUG + PRINTB("New lib Context for %s func:", name); + ctx.dump(NULL, NULL); +#endif + return m.second->functions[name]->evaluate(&ctx, evalctx); + } + } + } + return Context::evaluate_function(name, evalctx); +} + +AbstractNode *ModuleContext::evaluate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const +{ + if (this->modules_p && this->modules_p->find(inst.name()) != this->modules_p->end()) { + AbstractModule *m = this->modules_p->find(inst.name())->second; + std::string replacement = Builtins::instance()->isDeprecated(inst.name()); + if (!replacement.empty()) { + PRINTB("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", inst.name() % replacement); + } + return m->evaluate(this, &inst, evalctx); + } + + if (this->usedlibs_p) { + BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { + assert(m.second); + if (m.second->modules.find(inst.name()) != m.second->modules.end()) { + ModuleContext ctx(m.second, this->parent); + // FIXME: Set document path +#if 0 && DEBUG + PRINT("New lib Context:"); + ctx.dump(NULL, &inst); +#endif + return m.second->modules[inst.name()]->evaluate(&ctx, &inst, evalctx); + } + } + } + + return Context::evaluate_module(inst, evalctx); +} + +#ifdef DEBUG +void ModuleContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst) +{ + if (inst) + PRINTB("ModuleContext %p (%p) for %s inst (%p) ", this % this->parent % inst->name() % inst); + else + PRINTB("ModuleContext: %p (%p)", this % this->parent); + PRINTB(" document path: %s", this->document_path); + if (mod) { + const Module *m = dynamic_cast<const Module*>(mod); + if (m) { + PRINT(" module args:"); + BOOST_FOREACH(const Assignment &arg, m->definition_arguments) { + PRINTB(" %s = %s", arg.first % variables[arg.first]); + } + } + } + typedef std::pair<std::string, Value> ValueMapType; + PRINT(" vars:"); + BOOST_FOREACH(const ValueMapType &v, constants) { + PRINTB(" %s = %s", v.first % v.second); + } + BOOST_FOREACH(const ValueMapType &v, variables) { + PRINTB(" %s = %s", v.first % v.second); + } + BOOST_FOREACH(const ValueMapType &v, config_variables) { + PRINTB(" %s = %s", v.first % v.second); + } + +} +#endif |