summaryrefslogtreecommitdiff
path: root/src/modcontext.cc
blob: 7941cf5cc471253c921a8a0ef659bf0faad11f3a (plain)
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#include "modcontext.h"
#include "module.h"
#include "expression.h"
#include "function.h"
#include "printutils.h"
#include "builtin.h"
#include "ModuleCache.h"

#include <boost/foreach.hpp>

ModuleContext::ModuleContext(const Context *parent, const EvalContext *evalctx)
	: Context(parent), functions_p(NULL), modules_p(NULL), evalctx(evalctx)
{
}

ModuleContext::~ModuleContext()
{
}

// Experimental code. See issue #399
#if 0
void ModuleContext::evaluateAssignments(const AssignmentList &assignments)
{
	// First, assign all simple variables
	std::list<std::string> undefined_vars;
 	BOOST_FOREACH(const Assignment &ass, assignments) {
		Value tmpval = ass.second->evaluate(this);
		if (tmpval.isUndefined()) undefined_vars.push_back(ass.first);
 		else this->set_variable(ass.first, tmpval);
 	}

	// Variables which couldn't be evaluated in the first pass is attempted again,
  // to allow for initialization out of order

	boost::unordered_map<std::string, Expression *> tmpass;
	BOOST_FOREACH (const Assignment &ass, assignments) {
		tmpass[ass.first] = ass.second;
	}
		
	bool changed = true;
	while (changed) {
		changed = false;
		std::list<std::string>::iterator iter = undefined_vars.begin();
		while (iter != undefined_vars.end()) {
			std::list<std::string>::iterator curr = iter++;
			boost::unordered_map<std::string, Expression *>::iterator found = tmpass.find(*curr);
			if (found != tmpass.end()) {
				const Expression *expr = found->second;
				Value tmpval = expr->evaluate(this);
				// FIXME: it's not enough to check for undefined;
				// we need to check for any undefined variable in the subexpression
				// For now, ignore this and revisit the validity and order of variable
				// assignments later
				if (!tmpval.isUndefined()) {
					changed = true;
					this->set_variable(*curr, tmpval);
					undefined_vars.erase(curr);
				}
			}
		}
	}
}
#endif

void ModuleContext::initializeModule(const class Module &module)
{
	this->setVariables(module.definition_arguments, evalctx);
	// FIXME: Don't access module members directly
	this->functions_p = &module.scope.functions;
	this->modules_p = &module.scope.modules;
	BOOST_FOREACH(const Assignment &ass, module.scope.assignments) {
		this->set_variable(ass.first, ass.second->evaluate(this));
	}
// Experimental code. See issue #399
//	evaluateAssignments(module.scope.assignments);
}

/*!
	Only used to initialize builtins for the top-level root context
*/
void ModuleContext::registerBuiltin()
{
	const LocalScope &scope = Builtins::instance()->getGlobalScope();

	// FIXME: Don't access module members directly
	this->functions_p = &scope.functions;
	this->modules_p = &scope.modules;
	BOOST_FOREACH(const Assignment &ass, scope.assignments) {
		this->set_variable(ass.first, ass.second->evaluate(this));
	}

	this->set_constant("PI",Value(M_PI));
}

const AbstractFunction *ModuleContext::findLocalFunction(const std::string &name) const
{
	if (this->functions_p && this->functions_p->find(name) != this->functions_p->end()) {
		return this->functions_p->find(name)->second;
	}
	return NULL;
}

const AbstractModule *ModuleContext::findLocalModule(const std::string &name) const
{
	if (this->modules_p && this->modules_p->find(name) != this->modules_p->end()) {
		AbstractModule *m = this->modules_p->find(name)->second;
		std::string replacement = Builtins::instance()->isDeprecated(name);
		if (!replacement.empty()) {
			PRINTB("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", name % replacement);
		}
		return m;
	}
	return NULL;
}

Value ModuleContext::evaluate_function(const std::string &name, const EvalContext *evalctx) const
{
	const AbstractFunction *foundf = findLocalFunction(name);
	if (foundf) return foundf->evaluate(this, evalctx);

	return Context::evaluate_function(name, evalctx);
}

AbstractNode *ModuleContext::instantiate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const
{
	const AbstractModule *foundm = this->findLocalModule(inst.name());
	if (foundm) return foundm->instantiate(this, &inst, evalctx);

	return Context::instantiate_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

FileContext::FileContext(const class FileModule &module, const Context *parent)
	: ModuleContext(parent), usedlibs(module.usedlibs)
{
	if (!module.modulePath().empty()) this->document_path = module.modulePath();
}

Value FileContext::evaluate_function(const std::string &name, const EvalContext *evalctx) const
{
	const AbstractFunction *foundf = findLocalFunction(name);
	if (foundf) return foundf->evaluate(this, evalctx);
	
	BOOST_FOREACH(const FileModule::ModuleContainer::value_type &m, this->usedlibs) {
		// usedmod is NULL if the library wasn't be compiled (error or file-not-found)
		FileModule *usedmod = ModuleCache::instance()->lookup(m);
		if (usedmod && 
				usedmod->scope.functions.find(name) != usedmod->scope.functions.end()) {
			FileContext ctx(*usedmod, this->parent);
			ctx.initializeModule(*usedmod);
			// FIXME: Set document path
#if 0 && DEBUG
			PRINTB("New lib Context for %s func:", name);
			ctx.dump(NULL, NULL);
#endif
			return usedmod->scope.functions[name]->evaluate(&ctx, evalctx);
		}
	}

	return ModuleContext::evaluate_function(name, evalctx);
}

AbstractNode *FileContext::instantiate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const
{
	const AbstractModule *foundm = this->findLocalModule(inst.name());
	if (foundm) return foundm->instantiate(this, &inst, evalctx);

	BOOST_FOREACH(const FileModule::ModuleContainer::value_type &m, this->usedlibs) {
		FileModule *usedmod = ModuleCache::instance()->lookup(m);
		// usedmod is NULL if the library wasn't be compiled (error or file-not-found)
		if (usedmod && 
				usedmod->scope.modules.find(inst.name()) != usedmod->scope.modules.end()) {
			FileContext ctx(*usedmod, this->parent);
			ctx.initializeModule(*usedmod);
			// FIXME: Set document path
#if 0 && DEBUG
			PRINT("New file Context:");
			ctx.dump(NULL, &inst);
#endif
			return usedmod->scope.modules[inst.name()]->instantiate(&ctx, &inst, evalctx);
		}
	}

	return ModuleContext::instantiate_module(inst, evalctx);
}
contact: Jan Huwald // Impressum