openscad/src/context.cc

180 lines
5.4 KiB
C++
Raw Normal View History

/*
2011-01-21 04:21:09 +03:00
* OpenSCAD (www.openscad.org)
* Copyright (C) 2009-2011 Clifford Wolf <clifford@clifford.at> and
* Marius Kintel <marius@kintel.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* As a special exception, you have permission to link this program
* with the CGAL library and distribute executables, as long as you
* follow the requirements of the GNU GPL in regard to all of the
* software in the executable aside from CGAL.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "context.h"
#include "evalcontext.h"
#include "expression.h"
#include "function.h"
#include "module.h"
#include "builtin.h"
#include "printutils.h"
2011-09-03 08:10:36 +04:00
#include <boost/foreach.hpp>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
#include "boosty.h"
2011-09-03 20:51:29 +04:00
std::vector<const Context*> Context::ctx_stack;
/*!
Initializes this context. Optionally initializes a context for an external library
*/
Context::Context(const Context *parent)
: parent(parent)
{
2011-09-03 08:10:36 +04:00
ctx_stack.push_back(this);
2011-09-03 20:51:29 +04:00
if (parent) document_path = parent->document_path;
}
Context::~Context()
{
ctx_stack.pop_back();
}
2011-09-03 20:51:29 +04:00
/*!
Initialize context from a module argument list and a evaluation context
which may pass variables which will be preferred over default values.
*/
void Context::setVariables(const std::vector<std::string> &argnames,
const std::vector<Expression*> &argexpr,
const EvalContext *evalctx)
{
2011-09-03 08:10:36 +04:00
for (size_t i=0; i<argnames.size(); i++) {
2011-09-03 20:51:29 +04:00
set_variable(argnames[i], i < argexpr.size() && argexpr[i] ?
argexpr[i]->evaluate(this->parent) : Value());
}
if (evalctx) {
size_t posarg = 0;
for (size_t i=0; i<evalctx->eval_arguments.size(); i++) {
const std::string &name = evalctx->eval_arguments[i].first;
const Value &val = evalctx->eval_arguments[i].second;
if (name.empty()) {
if (posarg < argnames.size()) this->set_variable(argnames[posarg++], val);
} else {
this->set_variable(name, val);
}
}
}
}
2011-09-03 20:51:29 +04:00
void Context::set_variable(const std::string &name, const Value &value)
{
2011-09-03 08:10:36 +04:00
if (name[0] == '$')
2011-09-03 20:51:29 +04:00
this->config_variables[name] = value;
else
this->variables[name] = value;
}
void Context::set_constant(const std::string &name, const Value &value)
{
2012-01-25 06:11:12 +04:00
if (this->constants.find(name) != this->constants.end()) {
PRINTB("WARNING: Attempt to modify constant '%s'.", name);
}
else {
2011-09-03 20:51:29 +04:00
this->constants[name] = value;
2012-01-25 06:11:12 +04:00
}
}
2011-09-03 08:10:36 +04:00
Value Context::lookup_variable(const std::string &name, bool silent) const
{
2011-09-03 08:10:36 +04:00
if (name[0] == '$') {
for (int i = ctx_stack.size()-1; i >= 0; i--) {
2011-09-03 08:10:36 +04:00
const ValueMap &confvars = ctx_stack[i]->config_variables;
if (confvars.find(name) != confvars.end())
return confvars.find(name)->second;
}
return Value();
}
2011-09-03 20:51:29 +04:00
if (!this->parent && this->constants.find(name) != this->constants.end())
return this->constants.find(name)->second;
if (this->variables.find(name) != this->variables.end())
return this->variables.find(name)->second;
if (this->parent)
return this->parent->lookup_variable(name, silent);
if (!silent)
2012-01-25 06:11:12 +04:00
PRINTB("WARNING: Ignoring unknown variable '%s'.", name);
return Value();
}
Value Context::evaluate_function(const std::string &name, const EvalContext *evalctx) const
{
if (this->parent) return this->parent->evaluate_function(name, evalctx);
2012-01-25 06:11:12 +04:00
PRINTB("WARNING: Ignoring unknown function '%s'.", name);
return Value();
}
AbstractNode *Context::evaluate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const
{
if (this->parent) return this->parent->evaluate_module(inst, evalctx);
2012-01-25 06:11:12 +04:00
PRINTB("WARNING: Ignoring unknown module '%s'.", inst.name());
return NULL;
}
/*!
Returns the absolute path to the given filename, unless it's empty.
*/
2011-09-03 20:51:29 +04:00
std::string Context::getAbsolutePath(const std::string &filename) const
{
if (!filename.empty() && !boosty::is_absolute(fs::path(filename))) {
return boosty::absolute(fs::path(this->document_path) / filename).string();
}
else {
return filename;
}
}
#ifdef DEBUG
void Context::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("Context: %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 std::string &arg, m->argnames) {
PRINTB(" %s = %s", arg % variables[arg]);
}
}
}
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