summaryrefslogtreecommitdiff
path: root/src/module.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/module.cc')
-rw-r--r--src/module.cc189
1 files changed, 98 insertions, 91 deletions
diff --git a/src/module.cc b/src/module.cc
index e6dcb57..e853457 100644
--- a/src/module.cc
+++ b/src/module.cc
@@ -27,11 +27,15 @@
#include "module.h"
#include "ModuleCache.h"
#include "node.h"
-#include "context.h"
+#include "modcontext.h"
+#include "evalcontext.h"
#include "expression.h"
#include "function.h"
#include "printutils.h"
+#include <boost/filesystem.hpp>
+namespace fs = boost::filesystem;
+#include "boosty.h"
#include <boost/foreach.hpp>
#include <sstream>
#include <sys/stat.h>
@@ -40,11 +44,11 @@ AbstractModule::~AbstractModule()
{
}
-AbstractNode *AbstractModule::evaluate(const Context*, const ModuleInstantiation *inst) const
+AbstractNode *AbstractModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
AbstractNode *node = new AbstractNode(inst);
- node->children = inst->evaluateChildren();
+ node->children = inst->instantiateChildren(evalctx);
return node;
}
@@ -58,13 +62,27 @@ std::string AbstractModule::dump(const std::string &indent, const std::string &n
ModuleInstantiation::~ModuleInstantiation()
{
- BOOST_FOREACH (Expression *v, argexpr) delete v;
- BOOST_FOREACH (ModuleInstantiation *v, children) delete v;
+ BOOST_FOREACH(const Assignment &arg, this->arguments) delete arg.second;
}
IfElseModuleInstantiation::~IfElseModuleInstantiation()
{
- BOOST_FOREACH (ModuleInstantiation *v, else_children) delete v;
+}
+
+/*!
+ Returns the absolute path to the given filename, unless it's empty.
+
+ NB! This will actually search for the file, to be backwards compatible with <= 2013.01
+ (see issue #217)
+*/
+std::string ModuleInstantiation::getAbsolutePath(const std::string &filename) const
+{
+ if (!filename.empty() && !boosty::is_absolute(fs::path(filename))) {
+ return boosty::absolute(fs::path(this->modpath) / filename).string();
+ }
+ else {
+ return filename;
+ }
}
std::string ModuleInstantiation::dump(const std::string &indent) const
@@ -72,21 +90,20 @@ std::string ModuleInstantiation::dump(const std::string &indent) const
std::stringstream dump;
dump << indent;
dump << modname + "(";
- for (size_t i=0; i < argnames.size(); i++) {
+ for (size_t i=0; i < this->arguments.size(); i++) {
+ const Assignment &arg = this->arguments[i];
if (i > 0) dump << ", ";
- if (!argnames[i].empty()) dump << argnames[i] << " = ";
- dump << *argexpr[i];
+ if (!arg.first.empty()) dump << arg.first << " = ";
+ dump << *arg.second;
}
- if (children.size() == 0) {
+ if (scope.numElements() == 0) {
dump << ");\n";
- } else if (children.size() == 1) {
+ } else if (scope.numElements() == 1) {
dump << ")\n";
- dump << children[0]->dump(indent + "\t");
+ dump << scope.dump(indent + "\t");
} else {
dump << ") {\n";
- for (size_t i = 0; i < children.size(); i++) {
- dump << children[i]->dump(indent + "\t");
- }
+ scope.dump(indent + "\t");
dump << indent << "}\n";
}
return dump.str();
@@ -94,80 +111,63 @@ std::string ModuleInstantiation::dump(const std::string &indent) const
AbstractNode *ModuleInstantiation::evaluate(const Context *ctx) const
{
- AbstractNode *node = NULL;
- if (this->ctx) {
- PRINTB("WARNING: Ignoring recursive module instantiation of '%s'.", modname);
- } else {
- // FIXME: Casting away const..
- ModuleInstantiation *that = (ModuleInstantiation*)this;
- that->argvalues.clear();
- BOOST_FOREACH (Expression *expr, that->argexpr) {
- that->argvalues.push_back(expr->evaluate(ctx));
- }
- that->ctx = ctx;
- node = ctx->evaluate_module(*this);
- that->ctx = NULL;
- that->argvalues.clear();
- }
+ EvalContext c(ctx, this->arguments, &this->scope);
+
+#if 0 && DEBUG
+ PRINT("New eval ctx:");
+ c.dump(NULL, this);
+#endif
+ AbstractNode *node = ctx->instantiate_module(*this, &c); // Passes c as evalctx
return node;
}
-std::vector<AbstractNode*> ModuleInstantiation::evaluateChildren(const Context *ctx) const
+std::vector<AbstractNode*> ModuleInstantiation::instantiateChildren(const Context *evalctx) const
{
- if (!ctx) ctx = this->ctx;
- std::vector<AbstractNode*> childnodes;
- BOOST_FOREACH (ModuleInstantiation *modinst, this->children) {
- AbstractNode *node = modinst->evaluate(ctx);
- if (node) childnodes.push_back(node);
- }
- return childnodes;
+ return this->scope.instantiateChildren(evalctx);
}
-std::vector<AbstractNode*> IfElseModuleInstantiation::evaluateElseChildren(const Context *ctx) const
+std::vector<AbstractNode*> IfElseModuleInstantiation::instantiateElseChildren(const Context *evalctx) const
{
- if (!ctx) ctx = this->ctx;
- std::vector<AbstractNode*> childnodes;
- BOOST_FOREACH (ModuleInstantiation *modinst, this->else_children) {
- AbstractNode *node = modinst->evaluate(ctx);
- if (node != NULL) childnodes.push_back(node);
- }
- return childnodes;
+ return this->else_scope.instantiateChildren(evalctx);
}
Module::~Module()
{
- BOOST_FOREACH (const AssignmentContainer::value_type &v, assignments) delete v.second;
- BOOST_FOREACH (FunctionContainer::value_type &f, functions) delete f.second;
- BOOST_FOREACH (AbstractModuleContainer::value_type &m, modules) delete m.second;
- BOOST_FOREACH (ModuleInstantiation *v, children) delete v;
}
-AbstractNode *Module::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+class ModRecursionGuard
{
- Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
-
- c.inst_p = inst;
- c.set_variable("$children", Value(double(inst->children.size())));
-
- c.functions_p = &functions;
- c.modules_p = &modules;
-
- if (!usedlibs.empty())
- c.usedlibs_p = &usedlibs;
- else
- c.usedlibs_p = NULL;
+public:
+ ModRecursionGuard(const ModuleInstantiation &inst) : inst(inst) {
+ inst.recursioncount++;
+ }
+ ~ModRecursionGuard() {
+ inst.recursioncount--;
+ }
+ bool recursion_detected() const { return (inst.recursioncount > 100); }
+private:
+ const ModuleInstantiation &inst;
+};
- BOOST_FOREACH(const std::string &var, assignments_var) {
- c.set_variable(var, assignments.at(var)->evaluate(&c));
+AbstractNode *Module::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+{
+ ModRecursionGuard g(*inst);
+ if (g.recursion_detected()) {
+ PRINTB("ERROR: Recursion detected calling module '%s'", inst->name());
+ return NULL;
}
+ ModuleContext c(ctx, evalctx);
+ c.initializeModule(*this);
+ c.set_variable("$children", Value(double(inst->scope.children.size())));
+ // FIXME: Set document path to the path of the module
+#if 0 && DEBUG
+ c.dump(this, inst);
+#endif
+
AbstractNode *node = new AbstractNode(inst);
- for (size_t i = 0; i < children.size(); i++) {
- AbstractNode *n = children[i]->evaluate(&c);
- if (n != NULL)
- node->children.push_back(n);
- }
+ std::vector<AbstractNode *> instantiatednodes = this->scope.instantiateChildren(&c);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
return node;
}
@@ -178,33 +178,23 @@ std::string Module::dump(const std::string &indent, const std::string &name) con
std::string tab;
if (!name.empty()) {
dump << indent << "module " << name << "(";
- for (size_t i=0; i < argnames.size(); i++) {
+ for (size_t i=0; i < this->definition_arguments.size(); i++) {
+ const Assignment &arg = this->definition_arguments[i];
if (i > 0) dump << ", ";
- dump << argnames[i];
- if (argexpr[i]) dump << " = " << *argexpr[i];
+ dump << arg.first;
+ if (arg.second) dump << " = " << *arg.second;
}
dump << ") {\n";
tab = "\t";
}
- BOOST_FOREACH(const FunctionContainer::value_type &f, functions) {
- dump << f.second->dump(indent + tab, f.first);
- }
- BOOST_FOREACH(const AbstractModuleContainer::value_type &m, modules) {
- dump << m.second->dump(indent + tab, m.first);
- }
- BOOST_FOREACH(const std::string &var, assignments_var) {
- dump << indent << tab << var << " = " << *assignments.at(var) << ";\n";
- }
- for (size_t i = 0; i < children.size(); i++) {
- dump << children[i]->dump(indent + tab);
- }
+ dump << scope.dump(indent + tab);
if (!name.empty()) {
dump << indent << "}\n";
}
return dump.str();
}
-void Module::registerInclude(const std::string &filename)
+void FileModule::registerInclude(const std::string &filename)
{
struct stat st;
memset(&st, 0, sizeof(struct stat));
@@ -216,17 +206,17 @@ void Module::registerInclude(const std::string &filename)
Check if any dependencies have been modified and recompile them.
Returns true if anything was recompiled.
*/
-bool Module::handleDependencies()
+bool FileModule::handleDependencies()
{
if (this->is_handling_dependencies) return false;
this->is_handling_dependencies = true;
bool changed = false;
// Iterating manually since we want to modify the container while iterating
- Module::ModuleContainer::iterator iter = this->usedlibs.begin();
+ FileModule::ModuleContainer::iterator iter = this->usedlibs.begin();
while (iter != this->usedlibs.end()) {
- Module::ModuleContainer::iterator curr = iter++;
- Module *oldmodule = curr->second;
+ FileModule::ModuleContainer::iterator curr = iter++;
+ FileModule *oldmodule = curr->second;
curr->second = ModuleCache::instance()->evaluate(curr->first);
if (curr->second != oldmodule) {
changed = true;
@@ -243,3 +233,20 @@ bool Module::handleDependencies()
this->is_handling_dependencies = false;
return changed;
}
+
+AbstractNode *FileModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+{
+ assert(evalctx == NULL);
+ FileContext c(*this, ctx);
+ c.initializeModule(*this);
+ // FIXME: Set document path to the path of the module
+#if 0 && DEBUG
+ c.dump(this, inst);
+#endif
+
+ AbstractNode *node = new AbstractNode(inst);
+ std::vector<AbstractNode *> instantiatednodes = this->scope.instantiateChildren(ctx, &c);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
+
+ return node;
+}
contact: Jan Huwald // Impressum