diff options
author | Marius Kintel <marius@kintel.net> | 2013-04-09 04:28:16 (GMT) |
---|---|---|
committer | Marius Kintel <marius@kintel.net> | 2013-04-09 04:28:16 (GMT) |
commit | a37813a8999571f4b9235f33fdc7c22bcbe5fd17 (patch) | |
tree | 266d8c106100edab9f51b93cf229cf55cd083918 /src | |
parent | b16c24fb2888d932ec035fff27cb29b4ffbc256b (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.h | 4 | ||||
-rw-r--r-- | src/builtin.cc | 31 | ||||
-rw-r--r-- | src/builtin.h | 8 | ||||
-rw-r--r-- | src/cgaladv.cc | 10 | ||||
-rw-r--r-- | src/color.cc | 10 | ||||
-rw-r--r-- | src/context.cc | 129 | ||||
-rw-r--r-- | src/context.h | 32 | ||||
-rw-r--r-- | src/control.cc | 73 | ||||
-rw-r--r-- | src/csgops.cc | 7 | ||||
-rw-r--r-- | src/dxfdim.cc | 48 | ||||
-rw-r--r-- | src/evalcontext.cc | 40 | ||||
-rw-r--r-- | src/evalcontext.h | 24 | ||||
-rw-r--r-- | src/expr.cc | 17 | ||||
-rw-r--r-- | src/func.cc | 220 | ||||
-rw-r--r-- | src/function.h | 8 | ||||
-rw-r--r-- | src/import.cc | 12 | ||||
-rw-r--r-- | src/linearextrude.cc | 18 | ||||
-rw-r--r-- | src/mainwin.cc | 8 | ||||
-rw-r--r-- | src/modcontext.cc | 133 | ||||
-rw-r--r-- | src/modcontext.h | 37 | ||||
-rw-r--r-- | src/module.cc | 71 | ||||
-rw-r--r-- | src/module.h | 19 | ||||
-rw-r--r-- | src/openscad.cc | 14 | ||||
-rw-r--r-- | src/parser.y | 1 | ||||
-rw-r--r-- | src/primitives.cc | 9 | ||||
-rw-r--r-- | src/printutils.cc | 2 | ||||
-rw-r--r-- | src/printutils.h | 3 | ||||
-rw-r--r-- | src/projection.cc | 10 | ||||
-rw-r--r-- | src/render.cc | 10 | ||||
-rw-r--r-- | src/rotateextrude.cc | 10 | ||||
-rw-r--r-- | src/surface.cc | 8 | ||||
-rw-r--r-- | src/transform.cc | 10 |
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; |