summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarius Kintel <marius@kintel.net>2013-04-09 04:28:16 (GMT)
committerMarius Kintel <marius@kintel.net>2013-04-09 04:28:16 (GMT)
commita37813a8999571f4b9235f33fdc7c22bcbe5fd17 (patch)
tree266d8c106100edab9f51b93cf229cf55cd083918 /src
parentb16c24fb2888d932ec035fff27cb29b4ffbc256b (diff)
Refactored context handling into using separate Module contexts and Eval contexts. This allows for recursive module calls, and cascading children. I believe this fixes issue #116
Diffstat (limited to 'src')
-rw-r--r--src/MainWindow.h4
-rw-r--r--src/builtin.cc31
-rw-r--r--src/builtin.h8
-rw-r--r--src/cgaladv.cc10
-rw-r--r--src/color.cc10
-rw-r--r--src/context.cc129
-rw-r--r--src/context.h32
-rw-r--r--src/control.cc73
-rw-r--r--src/csgops.cc7
-rw-r--r--src/dxfdim.cc48
-rw-r--r--src/evalcontext.cc40
-rw-r--r--src/evalcontext.h24
-rw-r--r--src/expr.cc17
-rw-r--r--src/func.cc220
-rw-r--r--src/function.h8
-rw-r--r--src/import.cc12
-rw-r--r--src/linearextrude.cc18
-rw-r--r--src/mainwin.cc8
-rw-r--r--src/modcontext.cc133
-rw-r--r--src/modcontext.h37
-rw-r--r--src/module.cc71
-rw-r--r--src/module.h19
-rw-r--r--src/openscad.cc14
-rw-r--r--src/parser.y1
-rw-r--r--src/primitives.cc9
-rw-r--r--src/printutils.cc2
-rw-r--r--src/printutils.h3
-rw-r--r--src/projection.cc10
-rw-r--r--src/render.cc10
-rw-r--r--src/rotateextrude.cc10
-rw-r--r--src/surface.cc8
-rw-r--r--src/transform.cc10
32 files changed, 632 insertions, 404 deletions
diff --git a/src/MainWindow.h b/src/MainWindow.h
index 8745b8b..65deb15 100644
--- a/src/MainWindow.h
+++ b/src/MainWindow.h
@@ -4,7 +4,7 @@
#include <QMainWindow>
#include "ui_MainWindow.h"
#include "openscad.h"
-#include "context.h"
+#include "modcontext.h"
#include "module.h"
#include "Tree.h"
#include "memory.h"
@@ -29,7 +29,7 @@ public:
QTimer *autoReloadTimer;
std::string autoReloadId;
- Context root_ctx;
+ ModuleContext root_ctx;
Module *root_module; // Result of parsing
ModuleInstantiation root_inst; // Top level instance
AbstractNode *absolute_root_node; // Result of tree evaluation
diff --git a/src/builtin.cc b/src/builtin.cc
index 6eb32b6..bdd2d3b 100644
--- a/src/builtin.cc
+++ b/src/builtin.cc
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "function.h"
#include "module.h"
+#include "expression.h"
#include <boost/foreach.hpp>
Builtins *Builtins::instance(bool erase)
@@ -15,12 +16,12 @@ Builtins *Builtins::instance(bool erase)
void Builtins::init(const char *name, class AbstractModule *module)
{
- Builtins::instance()->builtinmodules[name] = module;
+ Builtins::instance()->rootmodule.modules[name] = module;
}
void Builtins::init(const char *name, class AbstractFunction *function)
{
- Builtins::instance()->builtinfunctions[name] = function;
+ Builtins::instance()->rootmodule.functions[name] = function;
}
extern void register_builtin_functions();
@@ -77,10 +78,28 @@ std::string Builtins::isDeprecated(const std::string &name)
return std::string();
}
+Builtins::Builtins()
+{
+ this->rootmodule.assignments_var.push_back("$fn");
+ this->rootmodule.assignments["$fn"] = new Expression(Value(0.0));
+ this->rootmodule.assignments_var.push_back("$fs");
+ this->rootmodule.assignments["$fs"] = new Expression(Value(2.0));
+ this->rootmodule.assignments_var.push_back("$fa");
+ this->rootmodule.assignments["$fa"] = new Expression(Value(12.0));
+ this->rootmodule.assignments_var.push_back("$t");
+ this->rootmodule.assignments["$t"] = new Expression(Value(0.0));
+
+ Value::VectorType zero3;
+ zero3.push_back(Value(0.0));
+ zero3.push_back(Value(0.0));
+ zero3.push_back(Value(0.0));
+ Value zero3val(zero3);
+ this->rootmodule.assignments_var.push_back("$vpt");
+ this->rootmodule.assignments["$vpt"] = new Expression(zero3val);
+ this->rootmodule.assignments_var.push_back("$vpr");
+ this->rootmodule.assignments["$vpr"] = new Expression(zero3val);
+}
+
Builtins::~Builtins()
{
- BOOST_FOREACH(FunctionContainer::value_type &f, this->builtinfunctions) delete f.second;
- this->builtinfunctions.clear();
- BOOST_FOREACH(ModuleContainer::value_type &m, this->builtinmodules) delete m.second;
- this->builtinmodules.clear();
}
diff --git a/src/builtin.h b/src/builtin.h
index bc096e5..564c951 100644
--- a/src/builtin.h
+++ b/src/builtin.h
@@ -3,6 +3,7 @@
#include <string>
#include <boost/unordered_map.hpp>
+#include "module.h"
class Builtins
{
@@ -19,16 +20,17 @@ public:
const FunctionContainer &functions() { return this->builtinfunctions; }
const ModuleContainer &modules() { return this->builtinmodules; }
+ const Module &getRootModule() { return this->rootmodule; }
+
private:
- Builtins() { }
+ Builtins();
~Builtins();
+ Module rootmodule;
FunctionContainer builtinfunctions;
ModuleContainer builtinmodules;
boost::unordered_map<std::string, std::string> deprecations;
};
-extern void register_builtin(class Context &ctx);
-
#endif
diff --git a/src/cgaladv.cc b/src/cgaladv.cc
index a4cb5ec..8c98ae6 100644
--- a/src/cgaladv.cc
+++ b/src/cgaladv.cc
@@ -26,7 +26,7 @@
#include "cgaladvnode.h"
#include "module.h"
-#include "context.h"
+#include "evalcontext.h"
#include "builtin.h"
#include "PolySetEvaluator.h"
#include <sstream>
@@ -39,10 +39,10 @@ class CgaladvModule : public AbstractModule
public:
cgaladv_type_e type;
CgaladvModule(cgaladv_type_e type) : type(type) { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
CgaladvNode *node = new CgaladvNode(inst, type);
@@ -62,7 +62,7 @@ AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiat
argnames += "newsize", "auto";
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(argnames, argexpr, evalctx);
Value convexity, path, subdiv_type, level;
@@ -111,7 +111,7 @@ AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiat
if (node->level <= 1)
node->level = 1;
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
+ std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
return node;
diff --git a/src/color.cc b/src/color.cc
index acca652..4e9c55d 100644
--- a/src/color.cc
+++ b/src/color.cc
@@ -26,7 +26,7 @@
#include "colornode.h"
#include "module.h"
-#include "context.h"
+#include "evalcontext.h"
#include "builtin.h"
#include "printutils.h"
#include <sstream>
@@ -40,14 +40,14 @@ class ColorModule : public AbstractModule
{
public:
ColorModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
private:
static boost::unordered_map<std::string, Color4f> colormap;
};
#include "colormap.h"
-AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
ColorNode *node = new ColorNode(inst);
@@ -60,7 +60,7 @@ AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiatio
argnames += "c", "alpha";
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(argnames, argexpr, evalctx);
Value v = c.lookup_variable("c");
if (v.type() == Value::VECTOR) {
@@ -88,7 +88,7 @@ AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiatio
node->color[3] = alpha.toDouble();
}
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
+ std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
return node;
diff --git a/src/context.cc b/src/context.cc
index 97ea5b9..bc54b88 100644
--- a/src/context.cc
+++ b/src/context.cc
@@ -25,6 +25,7 @@
*/
#include "context.h"
+#include "evalcontext.h"
#include "expression.h"
#include "function.h"
#include "module.h"
@@ -40,26 +41,12 @@ std::vector<const Context*> Context::ctx_stack;
/*!
Initializes this context. Optionally initializes a context for an external library
*/
-Context::Context(const Context *parent, const Module *library)
- : parent(parent), inst_p(NULL)
+Context::Context(const Context *parent)
+ : parent(parent)
{
if (parent) recursioncount = parent->recursioncount;
ctx_stack.push_back(this);
if (parent) document_path = parent->document_path;
- if (library) {
- // FIXME: Don't access module members directly
- this->functions_p = &library->functions;
- this->modules_p = &library->modules;
- this->usedlibs_p = &library->usedlibs;
- BOOST_FOREACH(const std::string &var, library->assignments_var) {
- this->set_variable(var, library->assignments.at(var)->evaluate(this));
- }
- }
- else {
- functions_p = NULL;
- modules_p = NULL;
- usedlibs_p = NULL;
- }
}
Context::~Context()
@@ -68,25 +55,28 @@ Context::~Context()
}
/*!
- Initialize context from argument lists (function call/module instantiation)
- */
-void Context::args(const std::vector<std::string> &argnames,
- const std::vector<Expression*> &argexpr,
- const std::vector<std::string> &call_argnames,
- const std::vector<Value> &call_argvalues)
+ 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)
{
for (size_t i=0; i<argnames.size(); i++) {
set_variable(argnames[i], i < argexpr.size() && argexpr[i] ?
argexpr[i]->evaluate(this->parent) : Value());
}
- size_t posarg = 0;
- for (size_t i=0; i<call_argnames.size(); i++) {
- if (call_argnames[i].empty()) {
- if (posarg < argnames.size())
- set_variable(argnames[posarg++], call_argvalues[i]);
- } else {
- set_variable(call_argnames[i], call_argvalues[i]);
+ 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);
+ }
}
}
}
@@ -141,50 +131,21 @@ private:
const std::string &name;
};
-Value Context::evaluate_function(const std::string &name,
- const std::vector<std::string> &argnames,
- const std::vector<Value> &argvalues) const
+Value Context::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, argnames, argvalues);
- if (this->usedlibs_p) {
- BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) {
- if (m.second->functions.find(name) != m.second->functions.end()) {
- Context ctx(this->parent, m.second);
- return m.second->functions[name]->evaluate(&ctx, argnames, argvalues);
- }
- }
- }
- if (this->parent) return this->parent->evaluate_function(name, argnames, argvalues);
+ if (this->parent) return this->parent->evaluate_function(name, evalctx);
PRINTB("WARNING: Ignoring unknown function '%s'.", name);
return Value();
}
-AbstractNode *Context::evaluate_module(const ModuleInstantiation &inst) const
+AbstractNode *Context::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);
- }
- 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()) {
- Context ctx(this->parent, m.second);
- return m.second->modules[inst.name()]->evaluate(&ctx, &inst);
- }
- }
- }
- if (this->parent) return this->parent->evaluate_module(inst);
+ if (this->parent) return this->parent->evaluate_module(inst, evalctx);
PRINTB("WARNING: Ignoring unknown module '%s'.", inst.name());
return NULL;
}
@@ -202,22 +163,34 @@ std::string Context::getAbsolutePath(const std::string &filename) const
}
}
-void register_builtin(Context &ctx)
+#ifdef DEBUG
+void Context::dump(const AbstractModule *mod, const ModuleInstantiation *inst)
{
- ctx.functions_p = &Builtins::instance()->functions();
- ctx.modules_p = &Builtins::instance()->modules();
- ctx.set_variable("$fn", Value(0.0));
- ctx.set_variable("$fs", Value(2.0));
- ctx.set_variable("$fa", Value(12.0));
- ctx.set_variable("$t", Value(0.0));
-
- Value::VectorType zero3;
- zero3.push_back(Value(0.0));
- zero3.push_back(Value(0.0));
- zero3.push_back(Value(0.0));
- Value zero3val(zero3);
- ctx.set_variable("$vpt", zero3val);
- ctx.set_variable("$vpr", zero3val);
+ 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);
+ }
- ctx.set_constant("PI",Value(M_PI));
}
+#endif
diff --git a/src/context.h b/src/context.h
index eb9a175..5c75e48 100644
--- a/src/context.h
+++ b/src/context.h
@@ -9,44 +9,44 @@
class Context
{
public:
- Context(const Context *parent = NULL, const class Module *library = NULL);
- ~Context();
+ Context(const Context *parent = NULL);
+ virtual ~Context();
- void args(const std::vector<std::string> &argnames,
- const std::vector<class Expression*> &argexpr,
- const std::vector<std::string> &call_argnames,
- const std::vector<Value> &call_argvalues);
+ virtual Value evaluate_function(const std::string &name, const class EvalContext *evalctx) const;
+ virtual class AbstractNode *evaluate_module(const class ModuleInstantiation &inst, const EvalContext *evalctx) const;
+
+ void setVariables(const std::vector<std::string> &argnames,
+ const std::vector<class Expression*> &argexpr,
+ const class EvalContext *evalctx = NULL);
void set_variable(const std::string &name, const Value &value);
void set_constant(const std::string &name, const Value &value);
Value lookup_variable(const std::string &name, bool silent = false) const;
- Value evaluate_function(const std::string &name,
- const std::vector<std::string> &argnames,
- const std::vector<Value> &argvalues) const;
- class AbstractNode *evaluate_module(const class ModuleInstantiation &inst) const;
void setDocumentPath(const std::string &path) { this->document_path = path; }
+ const std::string &documentPath() const { return this->document_path; }
std::string getAbsolutePath(const std::string &filename) const;
public:
const Context *parent;
- const boost::unordered_map<std::string, class AbstractFunction*> *functions_p;
- const boost::unordered_map<std::string, class AbstractModule*> *modules_p;
- typedef boost::unordered_map<std::string, class Module*> ModuleContainer;
- const ModuleContainer *usedlibs_p;
- const ModuleInstantiation *inst_p;
static std::vector<const Context*> ctx_stack;
mutable boost::unordered_map<std::string, int> recursioncount;
-private:
+protected:
typedef boost::unordered_map<std::string, Value> ValueMap;
ValueMap constants;
ValueMap variables;
ValueMap config_variables;
+
std::string document_path;
+
+#ifdef DEBUG
+public:
+ virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst);
+#endif
};
#endif
diff --git a/src/control.cc b/src/control.cc
index 44847f5..9133f28 100644
--- a/src/control.cc
+++ b/src/control.cc
@@ -26,7 +26,8 @@
#include "module.h"
#include "node.h"
-#include "context.h"
+#include "evalcontext.h"
+#include "modcontext.h"
#include "builtin.h"
#include "printutils.h"
#include <sstream>
@@ -45,18 +46,16 @@ class ControlModule : public AbstractModule
public:
control_type_e type;
ControlModule(control_type_e type) : type(type) { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l,
- const std::vector<std::string> &call_argnames,
- const std::vector<Value> &call_argvalues,
- const Context *arg_context)
+ const Context *ctx, const EvalContext *evalctx)
{
- if (call_argnames.size() > l) {
- const std::string &it_name = call_argnames[l];
- const Value &it_values = call_argvalues[l];
- Context c(arg_context);
+ if (evalctx->eval_arguments.size() > l) {
+ const std::string &it_name = evalctx->eval_arguments[l].first;
+ const Value &it_values = evalctx->eval_arguments[l].second;
+ Context c(ctx);
if (it_values.type() == Value::RANGE) {
Value::RangeType range = it_values.toRange();
if (range.end < range.begin) {
@@ -67,55 +66,55 @@ void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l,
if (range.step > 0 && (range.begin-range.end)/range.step < 10000) {
for (double i = range.begin; i <= range.end; i += range.step) {
c.set_variable(it_name, Value(i));
- for_eval(node, inst, l+1, call_argnames, call_argvalues, &c);
+ for_eval(node, inst, l+1, &c, evalctx);
}
}
}
else if (it_values.type() == Value::VECTOR) {
for (size_t i = 0; i < it_values.toVector().size(); i++) {
c.set_variable(it_name, it_values.toVector()[i]);
- for_eval(node, inst, l+1, call_argnames, call_argvalues, &c);
+ for_eval(node, inst, l+1, &c, evalctx);
}
}
else if (it_values.type() != Value::UNDEFINED) {
c.set_variable(it_name, it_values);
- for_eval(node, inst, l+1, call_argnames, call_argvalues, &c);
+ for_eval(node, inst, l+1, &c, evalctx);
}
} else if (l > 0) {
- std::vector<AbstractNode *> evaluatednodes = inst.evaluateChildren(arg_context);
+ std::vector<AbstractNode *> evaluatednodes = inst.evaluateChildren(ctx);
node.children.insert(node.children.end(), evaluatednodes.begin(), evaluatednodes.end());
}
}
-AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation *inst) const
+AbstractNode *ControlModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
AbstractNode *node = NULL;
if (type == CHILD)
{
size_t n = 0;
- if (inst->argvalues.size() > 0) {
+ if (evalctx->eval_arguments.size() > 0) {
double v;
- if (inst->argvalues[0].getDouble(v)) {
+ if (evalctx->eval_arguments[0].second.getDouble(v)) {
if (v < 0) return NULL; // Disallow negative child indices
n = trunc(v);
}
}
- for (int i = Context::ctx_stack.size()-1; i >= 0; i--) {
- const Context *c = Context::ctx_stack[i];
- if (c->inst_p) {
- if (n < c->inst_p->children.size()) {
- node = c->inst_p->children[n]->evaluate(c->inst_p->ctx);
- // FIXME: We'd like to inherit any tags from the ModuleInstantiation
- // given as parameter to this method. However, the instantition which belongs
- // to the returned node cannot be changed. This causes the test
- // features/child-background.scad to fail.
+
+ // Find the last custom module invocation, which will contain
+ // an eval context with the children of the module invokation
+ const Context *tmpc = evalctx;
+ while (tmpc->parent) {
+ const ModuleContext *filectx = dynamic_cast<const ModuleContext*>(tmpc->parent);
+ if (filectx) {
+ if (filectx->evalctx && n < filectx->evalctx->children.size()) {
+ node = filectx->evalctx->children[n]->evaluate_instance(filectx->evalctx);
}
return node;
}
- c = c->parent;
+ tmpc = tmpc->parent;
}
- return NULL;
+ return node;
}
if (type == INT_FOR)
@@ -129,18 +128,18 @@ AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation
msg << "ECHO: ";
for (size_t i = 0; i < inst->argnames.size(); i++) {
if (i > 0) msg << ", ";
- if (!inst->argnames[i].empty()) msg << inst->argnames[i] << " = ";
- msg << inst->argvalues[i];
+ if (!evalctx->eval_arguments[i].first.empty()) msg << evalctx->eval_arguments[i].first << " = ";
+ msg << evalctx->eval_arguments[i].second;
}
PRINTB("%s", msg.str());
}
if (type == ASSIGN)
{
- Context c(inst->ctx);
- for (size_t i = 0; i < inst->argnames.size(); i++) {
- if (!inst->argnames[i].empty())
- c.set_variable(inst->argnames[i], inst->argvalues[i]);
+ Context c(evalctx);
+ for (size_t i = 0; i < evalctx->eval_arguments.size(); i++) {
+ if (!evalctx->eval_arguments[i].first.empty())
+ c.set_variable(evalctx->eval_arguments[i].first, evalctx->eval_arguments[i].second);
}
std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(&c);
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
@@ -148,18 +147,18 @@ AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation
if (type == FOR || type == INT_FOR)
{
- for_eval(*node, *inst, 0, inst->argnames, inst->argvalues, inst->ctx);
+ for_eval(*node, *inst, 0, evalctx, evalctx);
}
if (type == IF)
{
const IfElseModuleInstantiation *ifelse = dynamic_cast<const IfElseModuleInstantiation*>(inst);
- if (ifelse->argvalues.size() > 0 && ifelse->argvalues[0].toBool()) {
- std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateChildren();
+ if (evalctx->eval_arguments.size() > 0 && evalctx->eval_arguments[0].second.toBool()) {
+ std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateChildren(evalctx);
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
}
else {
- std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateElseChildren();
+ std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateElseChildren(evalctx);
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
}
}
diff --git a/src/csgops.cc b/src/csgops.cc
index 7524559..425b747 100644
--- a/src/csgops.cc
+++ b/src/csgops.cc
@@ -26,6 +26,7 @@
#include "csgnode.h"
+#include "evalcontext.h"
#include "module.h"
#include "csgterm.h"
#include "builtin.h"
@@ -37,13 +38,13 @@ class CsgModule : public AbstractModule
public:
csg_type_e type;
CsgModule(csg_type_e type) : type(type) { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *CsgModule::evaluate(const Context*, const ModuleInstantiation *inst) const
+AbstractNode *CsgModule::evaluate(const Context*, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
CsgNode *node = new CsgNode(inst, type);
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
+ std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
return node;
}
diff --git a/src/dxfdim.cc b/src/dxfdim.cc
index 53bc480..fbc24c4 100644
--- a/src/dxfdim.cc
+++ b/src/dxfdim.cc
@@ -30,7 +30,7 @@
#include "dxfdata.h"
#include "builtin.h"
#include "printutils.h"
-#include "context.h"
+#include "evalcontext.h"
#include "mathc99.h"
#include <sstream>
@@ -40,7 +40,7 @@ boost::unordered_map<std::string,Value> dxf_dim_cache;
boost::unordered_map<std::string,Value> dxf_cross_cache;
namespace fs = boost::filesystem;
-Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args)
+Value builtin_dxf_dim(const Context *ctx, const EvalContext *evalctx)
{
std::string filename;
std::string layername;
@@ -51,18 +51,18 @@ Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnam
// FIXME: We don't lookup the file relative to where this function was instantiated
// since the path is only available for ModuleInstantiations, not function expressions.
- // See isse #217
- for (size_t i = 0; i < argnames.size() && i < args.size(); i++) {
- if (argnames[i] == "file")
- filename = ctx->getAbsolutePath(args[i].toString());
- if (argnames[i] == "layer")
- layername = args[i].toString();
- if (argnames[i] == "origin")
- args[i].getVec2(xorigin, yorigin);
- if (argnames[i] == "scale")
- args[i].getDouble(scale);
- if (argnames[i] == "name")
- name = args[i].toString();
+ // See issue #217
+ for (size_t i = 0; i < evalctx->eval_arguments.size(); i++) {
+ if (evalctx->eval_arguments[i].first == "file")
+ filename = ctx->getAbsolutePath(evalctx->eval_arguments[i].second.toString());
+ if (evalctx->eval_arguments[i].first == "layer")
+ layername = evalctx->eval_arguments[i].second.toString();
+ if (evalctx->eval_arguments[i].first == "origin")
+ evalctx->eval_arguments[i].second.getVec2(xorigin, yorigin);
+ if (evalctx->eval_arguments[i].first == "scale")
+ evalctx->eval_arguments[i].second.getDouble(scale);
+ if (evalctx->eval_arguments[i].first == "name")
+ name = evalctx->eval_arguments[i].second.toString();
}
std::stringstream keystream;
@@ -135,7 +135,7 @@ Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnam
return Value();
}
-Value builtin_dxf_cross(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args)
+Value builtin_dxf_cross(const Context *ctx, const EvalContext *evalctx)
{
std::string filename;
std::string layername;
@@ -146,15 +146,15 @@ Value builtin_dxf_cross(const Context *ctx, const std::vector<std::string> &argn
// FIXME: We don't lookup the file relative to where this function was instantiated
// since the path is only available for ModuleInstantiations, not function expressions.
// See isse #217
- for (size_t i = 0; i < argnames.size() && i < args.size(); i++) {
- if (argnames[i] == "file")
- filename = ctx->getAbsolutePath(args[i].toString());
- if (argnames[i] == "layer")
- layername = args[i].toString();
- if (argnames[i] == "origin")
- args[i].getVec2(xorigin, yorigin);
- if (argnames[i] == "scale")
- args[i].getDouble(scale);
+ for (size_t i = 0; i < evalctx->eval_arguments.size(); i++) {
+ if (evalctx->eval_arguments[i].first == "file")
+ filename = ctx->getAbsolutePath(evalctx->eval_arguments[i].second.toString());
+ if (evalctx->eval_arguments[i].first == "layer")
+ layername = evalctx->eval_arguments[i].second.toString();
+ if (evalctx->eval_arguments[i].first == "origin")
+ evalctx->eval_arguments[i].second.getVec2(xorigin, yorigin);
+ if (evalctx->eval_arguments[i].first == "scale")
+ evalctx->eval_arguments[i].second.getDouble(scale);
}
std::stringstream keystream;
diff --git a/src/evalcontext.cc b/src/evalcontext.cc
new file mode 100644
index 0000000..39e5aae
--- /dev/null
+++ b/src/evalcontext.cc
@@ -0,0 +1,40 @@
+#include "evalcontext.h"
+#include "module.h"
+#include "expression.h"
+#include "function.h"
+#include "printutils.h"
+#include "builtin.h"
+
+#include <boost/foreach.hpp>
+
+#ifdef DEBUG
+void EvalContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst)
+{
+ if (inst)
+ PRINTB("EvalContext %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);
+
+ PRINT(" eval args:");
+ for (int i=0;i<this->eval_arguments.size();i++) {
+ PRINTB(" %s = %s", this->eval_arguments[i].first % this->eval_arguments[i].second);
+ }
+ if (this->children.size() > 0) {
+ PRINT(" children:");
+ BOOST_FOREACH(const ModuleInstantiation *ch, this->children) {
+ PRINTB(" %s", ch->name());
+ }
+ }
+
+ 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]);
+ }
+ }
+ }
+}
+#endif
diff --git a/src/evalcontext.h b/src/evalcontext.h
new file mode 100644
index 0000000..3d7d222
--- /dev/null
+++ b/src/evalcontext.h
@@ -0,0 +1,24 @@
+#ifndef EVALCONTEXT_H_
+#define EVALCONTEXT_H_
+
+#include "context.h"
+
+/*!
+ This hold the evaluation context (the parameters actually sent
+ when calling a module or function, including the children).
+*/
+class EvalContext : public Context
+{
+public:
+ EvalContext(const Context *parent = NULL) : Context(parent) {}
+ virtual ~EvalContext() {}
+
+ std::vector<std::pair<std::string, Value> > eval_arguments;
+ std::vector<class ModuleInstantiation *> children;
+
+#ifdef DEBUG
+ virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst);
+#endif
+};
+
+#endif
diff --git a/src/expr.cc b/src/expr.cc
index 75fc47a..1d7b440 100644
--- a/src/expr.cc
+++ b/src/expr.cc
@@ -26,7 +26,7 @@
#include "expression.h"
#include "value.h"
-#include "context.h"
+#include "evalcontext.h"
#include <assert.h>
#include <sstream>
#include <algorithm>
@@ -127,13 +127,18 @@ Value Expression::evaluate(const Context *context) const
return Value();
}
if (this->type == "F") {
- Value::VectorType argvalues;
- std::transform(this->children.begin(), this->children.end(),
- std::back_inserter(argvalues),
- boost::bind(&Expression::evaluate, _1, context));
+ EvalContext c(context);
+ for (size_t i=0; i < this->children.size(); i++) {
+ c.eval_arguments.push_back(std::make_pair(this->call_argnames[i],
+ this->children[i]->evaluate(context)));
+ }
+ // Value::VectorType argvalues;
+ // std::transform(this->children.begin(), this->children.end(),
+ // std::back_inserter(argvalues),
+ // boost::bind(&Expression::evaluate, _1, context));
// for (size_t i=0; i < this->children.size(); i++)
// argvalues.push_back(this->children[i]->evaluate(context));
- return context->evaluate_function(this->call_funcname, this->call_argnames, argvalues);
+ return context->evaluate_function(this->call_funcname, &c);
}
abort();
}
diff --git a/src/func.cc b/src/func.cc
index 791e957..ecd1f87 100644
--- a/src/func.cc
+++ b/src/func.cc
@@ -26,7 +26,7 @@
#include "function.h"
#include "expression.h"
-#include "context.h"
+#include "evalcontext.h"
#include "builtin.h"
#include <sstream>
#include <ctime>
@@ -61,7 +61,7 @@ AbstractFunction::~AbstractFunction()
{
}
-Value AbstractFunction::evaluate(const Context*, const std::vector<std::string>&, const std::vector<Value>&) const
+Value AbstractFunction::evaluate(const Context*, const EvalContext *evalctx) const
{
return Value();
}
@@ -79,12 +79,10 @@ Function::~Function()
delete expr;
}
-Value Function::evaluate(const Context *ctx,
- const std::vector<std::string> &call_argnames,
- const std::vector<Value> &call_argvalues) const
+Value Function::evaluate(const Context *ctx, const EvalContext *evalctx) const
{
Context c(ctx);
- c.args(argnames, argexpr, call_argnames, call_argvalues);
+ c.setVariables(argnames, argexpr, evalctx);
return expr ? expr->evaluate(&c) : Value();
}
@@ -105,9 +103,9 @@ BuiltinFunction::~BuiltinFunction()
{
}
-Value BuiltinFunction::evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const
+Value BuiltinFunction::evaluate(const Context *ctx, const EvalContext *evalctx) const
{
- return eval_func(ctx, call_argnames, call_argvalues);
+ return eval_func(ctx, evalctx);
}
std::string BuiltinFunction::dump(const std::string &indent, const std::string &name) const
@@ -127,37 +125,37 @@ static inline double rad2deg(double x)
return x * 180.0 / M_PI;
}
-Value builtin_abs(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_abs(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(fabs(args[0].toDouble()));
+ if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
+ return Value(fabs(evalctx->eval_arguments[0].second.toDouble()));
return Value();
}
-Value builtin_sign(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_sign(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value((args[0].toDouble()<0) ? -1.0 : ((args[0].toDouble()>0) ? 1.0 : 0.0));
+ if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
+ return Value((evalctx->eval_arguments[0].second.toDouble()<0) ? -1.0 : ((evalctx->eval_arguments[0].second.toDouble()>0) ? 1.0 : 0.0));
return Value();
}
-Value builtin_rands(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_rands(const Context *, const EvalContext *evalctx)
{
bool deterministic = false;
- if (args.size() == 3 &&
- args[0].type() == Value::NUMBER &&
- args[1].type() == Value::NUMBER &&
- args[2].type() == Value::NUMBER)
+ if (evalctx->eval_arguments.size() == 3 &&
+ evalctx->eval_arguments[0].second.type() == Value::NUMBER &&
+ evalctx->eval_arguments[1].second.type() == Value::NUMBER &&
+ evalctx->eval_arguments[2].second.type() == Value::NUMBER)
{
deterministic = false;
}
- else if (args.size() == 4 &&
- args[0].type() == Value::NUMBER &&
- args[1].type() == Value::NUMBER &&
- args[2].type() == Value::NUMBER &&
- args[3].type() == Value::NUMBER)
+ else if (evalctx->eval_arguments.size() == 4 &&
+ evalctx->eval_arguments[0].second.type() == Value::NUMBER &&
+ evalctx->eval_arguments[1].second.type() == Value::NUMBER &&
+ evalctx->eval_arguments[2].second.type() == Value::NUMBER &&
+ evalctx->eval_arguments[3].second.type() == Value::NUMBER)
{
- deterministic_rng.seed( (unsigned int) args[3].toDouble() );
+ deterministic_rng.seed( (unsigned int) evalctx->eval_arguments[3].second.toDouble() );
deterministic = true;
}
else
@@ -165,11 +163,11 @@ Value builtin_rands(const Context *, const std::vector<std::string>&, const std:
return Value();
}
- double min = std::min( args[0].toDouble(), args[1].toDouble() );
- double max = std::max( args[0].toDouble(), args[1].toDouble() );
+ double min = std::min( evalctx->eval_arguments[0].second.toDouble(), evalctx->eval_arguments[1].second.toDouble() );
+ double max = std::max( evalctx->eval_arguments[0].second.toDouble(), evalctx->eval_arguments[1].second.toDouble() );
boost::uniform_real<> distributor( min, max );
Value::VectorType vec;
- for (int i=0; i<args[2].toDouble(); i++) {
+ for (int i=0; i<evalctx->eval_arguments[2].second.toDouble(); i++) {
if ( deterministic ) {
vec.push_back( Value( distributor( deterministic_rng ) ) );
} else {
@@ -181,169 +179,169 @@ Value builtin_rands(const Context *, const std::vector<std::string>&, const std:
}
-Value builtin_min(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_min(const Context *, const EvalContext *evalctx)
{
- if (args.size() >= 1 && args[0].type() == Value::NUMBER) {
- double val = args[0].toDouble();
- for (size_t i = 1; i < args.size(); i++)
- if (args[1].type() == Value::NUMBER)
- val = fmin(val, args[i].toDouble());
+ if (evalctx->eval_arguments.size() >= 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) {
+ double val = evalctx->eval_arguments[0].second.toDouble();
+ for (size_t i = 1; i < evalctx->eval_arguments.size(); i++)
+ if (evalctx->eval_arguments[1].second.type() == Value::NUMBER)
+ val = fmin(val, evalctx->eval_arguments[i].second.toDouble());
return Value(val);
}
return Value();
}
-Value builtin_max(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_max(const Context *, const EvalContext *evalctx)
{
- if (args.size() >= 1 && args[0].type() == Value::NUMBER) {
- double val = args[0].toDouble();
- for (size_t i = 1; i < args.size(); i++)
- if (args[1].type() == Value::NUMBER)
- val = fmax(val, args[i].toDouble());
+ if (evalctx->eval_arguments.size() >= 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) {
+ double val = evalctx->eval_arguments[0].second.toDouble();
+ for (size_t i = 1; i < evalctx->eval_arguments.size(); i++)
+ if (evalctx->eval_arguments[1].second.type() == Value::NUMBER)
+ val = fmax(val, evalctx->eval_arguments[i].second.toDouble());
return Value(val);
}
return Value();
}
-Value builtin_sin(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_sin(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(sin(deg2rad(args[0].toDouble())));
+ if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
+ return Value(sin(deg2rad(evalctx->eval_arguments[0].second.toDouble())));
return Value();
}
-Value builtin_cos(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_cos(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(cos(deg2rad(args[0].toDouble())));
+ if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
+ return Value(cos(deg2rad(evalctx->eval_arguments[0].second.toDouble())));
return Value();
}
-Value builtin_asin(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_asin(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(rad2deg(asin(args[0].toDouble())));
+ if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
+ return Value(rad2deg(asin(evalctx->eval_arguments[0].second.toDouble())));
return Value();
}
-Value builtin_acos(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_acos(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(rad2deg(acos(args[0].toDouble())));
+ if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
+ return Value(rad2deg(acos(evalctx->eval_arguments[0].second.toDouble())));
return Value();
}
-Value builtin_tan(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_tan(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(tan(deg2rad(args[0].toDouble())));
+ if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
+ return Value(tan(deg2rad(evalctx->eval_arguments[0].second.toDouble())));
return Value();
}
-Value builtin_atan(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_atan(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(rad2deg(atan(args[0].toDouble())));
+ if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
+ return Value(rad2deg(atan(evalctx->eval_arguments[0].second.toDouble())));
return Value();
}
-Value builtin_atan2(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_atan2(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER)
- return Value(rad2deg(atan2(args[0].toDouble(), args[1].toDouble())));
+ if (evalctx->eval_arguments.size() == 2 && evalctx->eval_arguments[0].second.type() == Value::NUMBER && evalctx->eval_arguments[1].second.type() == Value::NUMBER)
+ return Value(rad2deg(atan2(evalctx->eval_arguments[0].second.toDouble(), evalctx->eval_arguments[1].second.toDouble())));
return Value();
}
-Value builtin_pow(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_pow(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER)
- return Value(pow(args[0].toDouble(), args[1].toDouble()));
+ if (evalctx->eval_arguments.size() == 2 && evalctx->eval_arguments[0].second.type() == Value::NUMBER && evalctx->eval_arguments[1].second.type() == Value::NUMBER)
+ return Value(pow(evalctx->eval_arguments[0].second.toDouble(), evalctx->eval_arguments[1].second.toDouble()));
return Value();
}
-Value builtin_round(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_round(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(round(args[0].toDouble()));
+ if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
+ return Value(round(evalctx->eval_arguments[0].second.toDouble()));
return Value();
}
-Value builtin_ceil(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_ceil(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(ceil(args[0].toDouble()));
+ if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
+ return Value(ceil(evalctx->eval_arguments[0].second.toDouble()));
return Value();
}
-Value builtin_floor(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_floor(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(floor(args[0].toDouble()));
+ if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
+ return Value(floor(evalctx->eval_arguments[0].second.toDouble()));
return Value();
}
-Value builtin_sqrt(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_sqrt(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(sqrt(args[0].toDouble()));
+ if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
+ return Value(sqrt(evalctx->eval_arguments[0].second.toDouble()));
return Value();
}
-Value builtin_exp(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_exp(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(exp(args[0].toDouble()));
+ if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
+ return Value(exp(evalctx->eval_arguments[0].second.toDouble()));
return Value();
}
-Value builtin_length(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_length(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1) {
- if (args[0].type() == Value::VECTOR) return Value(int(args[0].toVector().size()));
- if (args[0].type() == Value::STRING) return Value(int(args[0].toString().size()));
+ if (evalctx->eval_arguments.size() == 1) {
+ if (evalctx->eval_arguments[0].second.type() == Value::VECTOR) return Value(int(evalctx->eval_arguments[0].second.toVector().size()));
+ if (evalctx->eval_arguments[0].second.type() == Value::STRING) return Value(int(evalctx->eval_arguments[0].second.toString().size()));
}
return Value();
}
-Value builtin_log(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_log(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER)
- return Value(log(args[1].toDouble()) / log(args[0].toDouble()));
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(log(args[0].toDouble()) / log(10.0));
+ if (evalctx->eval_arguments.size() == 2 && evalctx->eval_arguments[0].second.type() == Value::NUMBER && evalctx->eval_arguments[1].second.type() == Value::NUMBER)
+ return Value(log(evalctx->eval_arguments[1].second.toDouble()) / log(evalctx->eval_arguments[0].second.toDouble()));
+ if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
+ return Value(log(evalctx->eval_arguments[0].second.toDouble()) / log(10.0));
return Value();
}
-Value builtin_ln(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_ln(const Context *, const EvalContext *evalctx)
{
- if (args.size() == 1 && args[0].type() == Value::NUMBER)
- return Value(log(args[0].toDouble()));
+ if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
+ return Value(log(evalctx->eval_arguments[0].second.toDouble()));
return Value();
}
-Value builtin_str(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_str(const Context *, const EvalContext *evalctx)
{
std::stringstream stream;
- for (size_t i = 0; i < args.size(); i++) {
- stream << args[i].toString();
+ for (size_t i = 0; i < evalctx->eval_arguments.size(); i++) {
+ stream << evalctx->eval_arguments[i].second.toString();
}
return Value(stream.str());
}
-Value builtin_lookup(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_lookup(const Context *, const EvalContext *evalctx)
{
double p, low_p, low_v, high_p, high_v;
- if (args.size() < 2 || // Needs two args
- !args[0].getDouble(p) || // First must be a number
- args[1].toVector().size() < 2 || // Second must be a vector of vectors
- args[1].toVector()[0].toVector().size() < 2)
+ if (evalctx->eval_arguments.size() < 2 || // Needs two args
+ !evalctx->eval_arguments[0].second.getDouble(p) || // First must be a number
+ evalctx->eval_arguments[1].second.toVector().size() < 2 || // Second must be a vector of vectors
+ evalctx->eval_arguments[1].second.toVector()[0].toVector().size() < 2)
return Value();
- if (!args[1].toVector()[0].getVec2(low_p, low_v) || !args[1].toVector()[0].getVec2(high_p, high_v))
+ if (!evalctx->eval_arguments[1].second.toVector()[0].getVec2(low_p, low_v) || !evalctx->eval_arguments[1].second.toVector()[0].getVec2(high_p, high_v))
return Value();
- for (size_t i = 1; i < args[1].toVector().size(); i++) {
+ for (size_t i = 1; i < evalctx->eval_arguments[1].second.toVector().size(); i++) {
double this_p, this_v;
- if (args[1].toVector()[i].getVec2(this_p, this_v)) {
+ if (evalctx->eval_arguments[1].second.toVector()[i].getVec2(this_p, this_v)) {
if (this_p <= p && (this_p > low_p || low_p > p)) {
low_p = this_p;
low_v = this_v;
@@ -404,14 +402,14 @@ Value builtin_lookup(const Context *, const std::vector<std::string>&, const std
- returns [[0,4],[1,5],[2,6],[8]]
*/
-Value builtin_search(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
+Value builtin_search(const Context *, const EvalContext *evalctx)
{
- if (args.size() < 2) return Value();
+ if (evalctx->eval_arguments.size() < 2) return Value();
- const Value &findThis = args[0];
- const Value &searchTable = args[1];
- unsigned int num_returns_per_match = (args.size() > 2) ? args[2].toDouble() : 1;
- unsigned int index_col_num = (args.size() > 3) ? args[3].toDouble() : 0;
+ const Value &findThis = evalctx->eval_arguments[0].second;
+ const Value &searchTable = evalctx->eval_arguments[1].second;
+ unsigned int num_returns_per_match = (evalctx->eval_arguments.size() > 2) ? evalctx->eval_arguments[2].second.toDouble() : 1;
+ unsigned int index_col_num = (evalctx->eval_arguments.size() > 3) ? evalctx->eval_arguments[3].second.toDouble() : 0;
Value::VectorType returnvec;
@@ -499,7 +497,7 @@ Value builtin_search(const Context *, const std::vector<std::string>&, const std
#define QUOTE(x__) # x__
#define QUOTED(x__) QUOTE(x__)
-Value builtin_version(const Context *, const std::vector<std::string>&, const std::vector<Value> &)
+Value builtin_version(const Context *, const EvalContext *evalctx)
{
Value::VectorType val;
val.push_back(Value(double(OPENSCAD_YEAR)));
@@ -510,9 +508,9 @@ Value builtin_version(const Context *, const std::vector<std::string>&, const st
return Value(val);
}
-Value builtin_version_num(const Context *ctx, const std::vector<std::string>& call_argnames, const std::vector<Value> &args)
+Value builtin_version_num(const Context *ctx, const EvalContext *evalctx)
{
- Value val = (args.size() == 0) ? builtin_version(ctx, call_argnames, args) : args[0];
+ Value val = (evalctx->eval_arguments.size() == 0) ? builtin_version(ctx, evalctx) : evalctx->eval_arguments[0].second;
double y, m, d = 0;
if (!val.getVec3(y, m, d)) {
if (!val.getVec2(y, m)) {
diff --git a/src/function.h b/src/function.h
index 623ef7e..bd7c329 100644
--- a/src/function.h
+++ b/src/function.h
@@ -9,20 +9,20 @@ class AbstractFunction
{
public:
virtual ~AbstractFunction();
- virtual Value evaluate(const class Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const;
+ virtual Value evaluate(const class Context *ctx, const class EvalContext *evalctx) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
};
class BuiltinFunction : public AbstractFunction
{
public:
- typedef Value (*eval_func_t)(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args);
+ typedef Value (*eval_func_t)(const Context *ctx, const EvalContext *evalctx);
eval_func_t eval_func;
BuiltinFunction(eval_func_t f) : eval_func(f) { }
virtual ~BuiltinFunction();
- virtual Value evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const;
+ virtual Value evaluate(const Context *ctx, const EvalContext *evalctx) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
};
@@ -37,7 +37,7 @@ public:
Function() { }
virtual ~Function();
- virtual Value evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const;
+ virtual Value evaluate(const Context *ctx, const EvalContext *evalctx) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
};
diff --git a/src/import.cc b/src/import.cc
index bbf5a6e..3d753fb 100644
--- a/src/import.cc
+++ b/src/import.cc
@@ -28,7 +28,7 @@
#include "module.h"
#include "polyset.h"
-#include "context.h"
+#include "evalcontext.h"
#include "builtin.h"
#include "dxfdata.h"
#include "dxftess.h"
@@ -60,10 +60,10 @@ class ImportModule : public AbstractModule
public:
import_type_e type;
ImportModule(import_type_e type = TYPE_UNKNOWN) : type(type) { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
std::vector<std::string> argnames;
argnames += "file", "layer", "convexity", "origin", "scale";
@@ -77,7 +77,11 @@ AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiati
}
Context c(ctx);
- c.args(argnames, argexpr, inst_argnames, inst->argvalues);
+ c.setDocumentPath(evalctx->documentPath());
+ c.setVariables(argnames, argexpr, evalctx);
+#ifdef DEBUG
+ c.dump(this, inst);
+#endif
Value v = c.lookup_variable("file");
std::string filename = inst->getAbsolutePath(v.isUndefined() ? "" : v.toString());
diff --git a/src/linearextrude.cc b/src/linearextrude.cc
index ff9682e..de728f7 100644
--- a/src/linearextrude.cc
+++ b/src/linearextrude.cc
@@ -27,7 +27,7 @@
#include "linearextrudenode.h"
#include "module.h"
-#include "context.h"
+#include "evalcontext.h"
#include "printutils.h"
#include "builtin.h"
#include "PolySetEvaluator.h"
@@ -45,10 +45,10 @@ class LinearExtrudeModule : public AbstractModule
{
public:
LinearExtrudeModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
LinearExtrudeNode *node = new LinearExtrudeNode(inst);
@@ -57,7 +57,7 @@ AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInst
std::vector<Expression*> argexpr;
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(argnames, argexpr, evalctx);
node->fn = c.lookup_variable("$fn").toDouble();
node->fs = c.lookup_variable("$fs").toDouble();
@@ -81,10 +81,10 @@ AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInst
// if height not given, and first argument is a number,
// then assume it should be the height.
if (c.lookup_variable("height").isUndefined() &&
- inst->argnames.size() > 0 &&
- inst->argnames[0] == "" &&
- inst->argvalues[0].type() == Value::NUMBER) {
- height = Value(inst->argvalues[0]);
+ evalctx->eval_arguments.size() > 0 &&
+ evalctx->eval_arguments[0].first == "" &&
+ evalctx->eval_arguments[0].second.type() == Value::NUMBER) {
+ height = Value(evalctx->eval_arguments[0].second);
}
node->layername = layer.isUndefined() ? "" : layer.toString();
@@ -117,7 +117,7 @@ AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInst
}
if (node->filename.empty()) {
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
+ std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
}
diff --git a/src/mainwin.cc b/src/mainwin.cc
index dd855fb..2e69ec2 100644
--- a/src/mainwin.cc
+++ b/src/mainwin.cc
@@ -158,7 +158,7 @@ settings_valueList(const QString &key, const QList<int> &defaultList = QList<int
}
MainWindow::MainWindow(const QString &filename)
- : progresswidget(NULL)
+ : root_inst("group"), progresswidget(NULL)
{
setupUi(this);
@@ -168,7 +168,7 @@ MainWindow::MainWindow(const QString &filename)
this, SLOT(actionRenderCGALDone(CGAL_Nef_polyhedron *)));
#endif
- register_builtin(root_ctx);
+ root_ctx.registerBuiltin();
this->openglbox = NULL;
root_module = NULL;
@@ -643,8 +643,8 @@ bool MainWindow::compile(bool reload, bool procevents)
if (procevents) QApplication::processEvents();
AbstractNode::resetIndexCounter();
- this->root_inst = ModuleInstantiation();
- this->absolute_root_node = this->root_module->evaluate(&this->root_ctx, &this->root_inst);
+ this->root_inst = ModuleInstantiation("group");
+ this->absolute_root_node = this->root_module->evaluate(&this->root_ctx, &this->root_inst, NULL);
if (this->absolute_root_node) {
// Do we have an explicit root node (! modifier)?
diff --git a/src/modcontext.cc b/src/modcontext.cc
new file mode 100644
index 0000000..34c6dbe
--- /dev/null
+++ b/src/modcontext.cc
@@ -0,0 +1,133 @@
+#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.argnames, module.argexpr, 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));
+}
+
+Value ModuleContext::evaluate_function(const std::string &name, const EvalContext *evalctx) const
+{
+ 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
+#ifdef 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
+#ifdef 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 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
diff --git a/src/modcontext.h b/src/modcontext.h
new file mode 100644
index 0000000..cecf91f
--- /dev/null
+++ b/src/modcontext.h
@@ -0,0 +1,37 @@
+#ifndef FILECONTEXT_H_
+#define FILECONTEXT_H_
+
+#include "context.h"
+
+/*!
+ This holds the context for a Module definition; keeps track of
+ global variables, submodules and functions defined inside a module.
+
+ NB! every .scad file defines an implicit unnamed module holding the contents of the file.
+*/
+class ModuleContext : public Context
+{
+public:
+ ModuleContext(const class Module *module = NULL, const Context *parent = NULL, const EvalContext *evalctx = NULL);
+ virtual ~ModuleContext();
+
+ void setModule(const Module &module, const EvalContext *evalctx = NULL);
+ void registerBuiltin();
+
+ virtual Value evaluate_function(const std::string &name, const EvalContext *evalctx) const;
+ virtual AbstractNode *evaluate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const;
+
+ const boost::unordered_map<std::string, class AbstractFunction*> *functions_p;
+ const boost::unordered_map<std::string, class AbstractModule*> *modules_p;
+ typedef boost::unordered_map<std::string, class Module*> ModuleContainer;
+ const ModuleContainer *usedlibs_p;
+
+ // FIXME: Points to the eval context for the call to this module. Not sure where it belongs
+ const class EvalContext *evalctx;
+
+#ifdef DEBUG
+ virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst);
+#endif
+};
+
+#endif
diff --git a/src/module.cc b/src/module.cc
index 322085b..120d07e 100644
--- a/src/module.cc
+++ b/src/module.cc
@@ -27,7 +27,8 @@
#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"
@@ -43,11 +44,11 @@ AbstractModule::~AbstractModule()
{
}
-AbstractNode *AbstractModule::evaluate(const Context*, const ModuleInstantiation *inst) const
+AbstractNode *AbstractModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
AbstractNode *node = new AbstractNode(inst);
- node->children = inst->evaluateChildren();
+ node->children = inst->evaluateChildren(evalctx);
return node;
}
@@ -108,43 +109,40 @@ std::string ModuleInstantiation::dump(const std::string &indent) const
return dump.str();
}
-AbstractNode *ModuleInstantiation::evaluate(const Context *ctx) const
+AbstractNode *ModuleInstantiation::evaluate_instance(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);
+ for (size_t i=0; i<argnames.size(); i++) {
+ c.eval_arguments.push_back(std::make_pair(argnames[i],
+ i < argexpr.size() && argexpr[i] ?
+ argexpr[i]->evaluate(ctx) :
+ Value()));
}
+ c.children = this->children;
+
+#ifdef DEBUG
+ PRINT("New eval ctx:");
+ c.dump(NULL, this);
+#endif
+ AbstractNode *node = ctx->evaluate_module(*this, &c); // Passes c as evalctx
return node;
}
-std::vector<AbstractNode*> ModuleInstantiation::evaluateChildren(const Context *ctx) const
+std::vector<AbstractNode*> ModuleInstantiation::evaluateChildren(const Context *evalctx) const
{
- if (!ctx) ctx = this->ctx;
std::vector<AbstractNode*> childnodes;
BOOST_FOREACH (ModuleInstantiation *modinst, this->children) {
- AbstractNode *node = modinst->evaluate(ctx);
+ AbstractNode *node = modinst->evaluate_instance(evalctx);
if (node) childnodes.push_back(node);
}
return childnodes;
}
-std::vector<AbstractNode*> IfElseModuleInstantiation::evaluateElseChildren(const Context *ctx) const
+std::vector<AbstractNode*> IfElseModuleInstantiation::evaluateElseChildren(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);
+ AbstractNode *node = modinst->evaluate_instance(evalctx);
if (node != NULL) childnodes.push_back(node);
}
return childnodes;
@@ -158,29 +156,18 @@ Module::~Module()
BOOST_FOREACH (ModuleInstantiation *v, children) delete v;
}
-AbstractNode *Module::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *Module::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
- Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
-
- c.inst_p = inst;
+ ModuleContext c(this, ctx, evalctx);
+ // FIXME: Set document path to the path of the module
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;
-
- BOOST_FOREACH(const std::string &var, assignments_var) {
- c.set_variable(var, assignments.at(var)->evaluate(&c));
- }
+#ifdef 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);
+ AbstractNode *n = children[i]->evaluate_instance(&c);
if (n != NULL)
node->children.push_back(n);
}
diff --git a/src/module.h b/src/module.h
index 1f9e303..17f0c59 100644
--- a/src/module.h
+++ b/src/module.h
@@ -11,13 +11,12 @@ class ModuleInstantiation
{
public:
ModuleInstantiation(const std::string &name = "")
- : ctx(NULL),
- tag_root(false), tag_highlight(false), tag_background(false), modname(name) { }
+ : tag_root(false), tag_highlight(false), tag_background(false), modname(name) { }
virtual ~ModuleInstantiation();
std::string dump(const std::string &indent) const;
- class AbstractNode *evaluate(const class Context *ctx) const;
- std::vector<AbstractNode*> evaluateChildren(const Context *ctx = NULL) const;
+ class AbstractNode *evaluate_instance(const class Context *ctx) const;
+ std::vector<AbstractNode*> evaluateChildren(const Context *evalctx) const;
void setPath(const std::string &path) { this->modpath = path; }
const std::string &path() const { return this->modpath; }
@@ -29,10 +28,8 @@ public:
bool isRoot() const { return this->tag_root; }
std::vector<std::string> argnames;
- std::vector<Value> argvalues;
std::vector<class Expression*> argexpr;
std::vector<ModuleInstantiation*> children;
- const Context *ctx;
bool tag_root;
bool tag_highlight;
@@ -48,7 +45,7 @@ class IfElseModuleInstantiation : public ModuleInstantiation {
public:
IfElseModuleInstantiation() : ModuleInstantiation("if") { }
virtual ~IfElseModuleInstantiation();
- std::vector<AbstractNode*> evaluateElseChildren(const Context *ctx = NULL) const;
+ std::vector<AbstractNode*> evaluateElseChildren(const Context *evalctx) const;
std::vector<ModuleInstantiation*> else_children;
};
@@ -57,7 +54,7 @@ class AbstractModule
{
public:
virtual ~AbstractModule();
- virtual class AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual class AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const class EvalContext *evalctx = NULL) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
};
@@ -67,7 +64,10 @@ public:
Module() : is_handling_dependencies(false) { }
virtual ~Module();
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ void setModulePath(const std::string &path) { this->path = path; }
+ const std::string &modulePath() const { return this->path; }
+
+ virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
void addChild(ModuleInstantiation *ch) { this->children.push_back(ch); }
@@ -97,6 +97,7 @@ public:
protected:
private:
+ std::string path;
};
#endif
diff --git a/src/openscad.cc b/src/openscad.cc
index 878c207..a345569 100644
--- a/src/openscad.cc
+++ b/src/openscad.cc
@@ -28,7 +28,7 @@
#include "MainWindow.h"
#include "node.h"
#include "module.h"
-#include "context.h"
+#include "modcontext.h"
#include "value.h"
#include "export.h"
#include "builtin.h"
@@ -327,11 +327,8 @@ int main(int argc, char **argv)
if (!filename) help(argv[0]);
- Context root_ctx;
- register_builtin(root_ctx);
-
Module *root_module;
- ModuleInstantiation root_inst;
+ ModuleInstantiation root_inst("group");
AbstractNode *root_node;
AbstractNode *absolute_root_node;
CGAL_Nef_polyhedron root_N;
@@ -351,12 +348,17 @@ int main(int argc, char **argv)
if (!root_module) exit(1);
root_module->handleDependencies();
+ ModuleContext root_ctx;
+ root_ctx.registerBuiltin();
+ PRINT("Root Context:");
+ root_ctx.dump(NULL, NULL);
+
fs::path fpath = boosty::absolute(fs::path(filename));
fs::path fparent = fpath.parent_path();
fs::current_path(fparent);
AbstractNode::resetIndexCounter();
- absolute_root_node = root_module->evaluate(&root_ctx, &root_inst);
+ absolute_root_node = root_module->evaluate(&root_ctx, &root_inst, NULL);
// Do we have an explicit root node (! modifier)?
if (!(root_node = find_root_tag(absolute_root_node)))
diff --git a/src/parser.y b/src/parser.y
index 70aebba..26bdba6 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -551,6 +551,7 @@ Module *parse(const char *text, const char *path, int debug)
module_stack.clear();
Module *rootmodule = currmodule = new Module();
+ rootmodule->setModulePath(path);
// PRINTB_NOCACHE("New module: %s %p", "root" % rootmodule);
parserdebug = debug;
diff --git a/src/primitives.cc b/src/primitives.cc
index e02df35..40e7e0b 100644
--- a/src/primitives.cc
+++ b/src/primitives.cc
@@ -27,12 +27,13 @@
#include "module.h"
#include "node.h"
#include "polyset.h"
-#include "context.h"
+#include "evalcontext.h"
#include "dxfdata.h"
#include "dxftess.h"
#include "builtin.h"
#include "printutils.h"
#include "visitor.h"
+#include "context.h"
#include <sstream>
#include <assert.h>
#include <boost/assign/std/vector.hpp>
@@ -55,7 +56,7 @@ class PrimitiveModule : public AbstractModule
public:
primitive_type_e type;
PrimitiveModule(primitive_type_e type) : type(type) { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
class PrimitiveNode : public AbstractPolyNode
@@ -104,7 +105,7 @@ public:
virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const;
};
-AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
PrimitiveNode *node = new PrimitiveNode(inst, this->type);
@@ -141,7 +142,7 @@ AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstanti
}
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(argnames, argexpr, evalctx);
node->fn = c.lookup_variable("$fn").toDouble();
node->fs = c.lookup_variable("$fs").toDouble();
diff --git a/src/printutils.cc b/src/printutils.cc
index 698fffb..37092fa 100644
--- a/src/printutils.cc
+++ b/src/printutils.cc
@@ -69,5 +69,3 @@ std::string two_digit_exp_format( double x )
s << x;
return two_digit_exp_format( s.str() );
}
-
-
diff --git a/src/printutils.h b/src/printutils.h
index 439c884..18aadde 100644
--- a/src/printutils.h
+++ b/src/printutils.h
@@ -22,6 +22,9 @@ void PRINT(const std::string &msg);
void PRINT_NOCACHE(const std::string &msg);
#define PRINTB_NOCACHE(_fmt, _arg) do { PRINT_NOCACHE(str(boost::format(_fmt) % _arg)); } while (0)
+
+void PRINT_CONTEXT(const class Context *ctx, const class Module *mod, const class ModuleInstantiation *inst);
+
std::string two_digit_exp_format( std::string doublestr );
std::string two_digit_exp_format( double x );
diff --git a/src/projection.cc b/src/projection.cc
index 1fcf639..46add48 100644
--- a/src/projection.cc
+++ b/src/projection.cc
@@ -26,7 +26,7 @@
#include "projectionnode.h"
#include "module.h"
-#include "context.h"
+#include "evalcontext.h"
#include "printutils.h"
#include "builtin.h"
#include "visitor.h"
@@ -41,10 +41,10 @@ class ProjectionModule : public AbstractModule
{
public:
ProjectionModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
ProjectionNode *node = new ProjectionNode(inst);
@@ -53,7 +53,7 @@ AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstant
std::vector<Expression*> argexpr;
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(argnames, argexpr, evalctx);
Value convexity = c.lookup_variable("convexity", true);
Value cut = c.lookup_variable("cut", true);
@@ -63,7 +63,7 @@ AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstant
if (cut.type() == Value::BOOL)
node->cut_mode = cut.toBool();
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
+ std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
return node;
diff --git a/src/render.cc b/src/render.cc
index 81c3f7b..855e5e3 100644
--- a/src/render.cc
+++ b/src/render.cc
@@ -26,7 +26,7 @@
#include "rendernode.h"
#include "module.h"
-#include "context.h"
+#include "evalcontext.h"
#include "builtin.h"
#include "PolySetEvaluator.h"
@@ -38,10 +38,10 @@ class RenderModule : public AbstractModule
{
public:
RenderModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *RenderModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *RenderModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
RenderNode *node = new RenderNode(inst);
@@ -50,13 +50,13 @@ AbstractNode *RenderModule::evaluate(const Context *ctx, const ModuleInstantiati
std::vector<Expression*> argexpr;
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(argnames, argexpr, evalctx);
Value v = c.lookup_variable("convexity");
if (v.type() == Value::NUMBER)
node->convexity = (int)v.toDouble();
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
+ std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
return node;
diff --git a/src/rotateextrude.cc b/src/rotateextrude.cc
index c4d9342..29a873f 100644
--- a/src/rotateextrude.cc
+++ b/src/rotateextrude.cc
@@ -26,7 +26,7 @@
#include "rotateextrudenode.h"
#include "module.h"
-#include "context.h"
+#include "evalcontext.h"
#include "printutils.h"
#include "builtin.h"
#include "polyset.h"
@@ -45,10 +45,10 @@ class RotateExtrudeModule : public AbstractModule
{
public:
RotateExtrudeModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
RotateExtrudeNode *node = new RotateExtrudeNode(inst);
@@ -57,7 +57,7 @@ AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInst
std::vector<Expression*> argexpr;
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(argnames, argexpr, evalctx);
node->fn = c.lookup_variable("$fn").toDouble();
node->fs = c.lookup_variable("$fs").toDouble();
@@ -86,7 +86,7 @@ AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInst
node->scale = 1;
if (node->filename.empty()) {
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
+ std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
}
diff --git a/src/surface.cc b/src/surface.cc
index ca5031e..22da93d 100644
--- a/src/surface.cc
+++ b/src/surface.cc
@@ -27,7 +27,7 @@
#include "module.h"
#include "node.h"
#include "polyset.h"
-#include "context.h"
+#include "evalcontext.h"
#include "builtin.h"
#include "printutils.h"
#include "handle_dep.h" // handle_dep()
@@ -50,7 +50,7 @@ class SurfaceModule : public AbstractModule
{
public:
SurfaceModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
class SurfaceNode : public AbstractPolyNode
@@ -69,7 +69,7 @@ public:
virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const;
};
-AbstractNode *SurfaceModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *SurfaceModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
SurfaceNode *node = new SurfaceNode(inst);
node->center = false;
@@ -80,7 +80,7 @@ AbstractNode *SurfaceModule::evaluate(const Context *ctx, const ModuleInstantiat
std::vector<Expression*> argexpr;
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(argnames, argexpr, evalctx);
Value fileval = c.lookup_variable("file");
node->filename = inst->getAbsolutePath(fileval.isUndefined() ? "" : fileval.toString());
diff --git a/src/transform.cc b/src/transform.cc
index b01827f..6246a59 100644
--- a/src/transform.cc
+++ b/src/transform.cc
@@ -26,7 +26,7 @@
#include "transformnode.h"
#include "module.h"
-#include "context.h"
+#include "evalcontext.h"
#include "polyset.h"
#include "builtin.h"
#include "value.h"
@@ -50,10 +50,10 @@ class TransformModule : public AbstractModule
public:
transform_type_e type;
TransformModule(transform_type_e type) : type(type) { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
+ virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
+AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
TransformNode *node = new TransformNode(inst);
@@ -83,7 +83,7 @@ AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstanti
}
Context c(ctx);
- c.args(argnames, argexpr, inst->argnames, inst->argvalues);
+ c.setVariables(argnames, argexpr, evalctx);
if (this->type == SCALE)
{
@@ -176,7 +176,7 @@ AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstanti
}
}
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren();
+ std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);
node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
return node;
contact: Jan Huwald // Impressum