1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
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
|