diff options
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 | 21 | ||||
-rw-r--r-- | src/color.cc | 15 | ||||
-rw-r--r-- | src/context.cc | 150 | ||||
-rw-r--r-- | src/context.h | 34 | ||||
-rw-r--r-- | src/control.cc | 93 | ||||
-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 | 24 | ||||
-rw-r--r-- | src/expression.h | 3 | ||||
-rw-r--r-- | src/func.cc | 230 | ||||
-rw-r--r-- | src/function.h | 12 | ||||
-rw-r--r-- | src/import.cc | 36 | ||||
-rw-r--r-- | src/lexer.l | 1 | ||||
-rw-r--r-- | src/linearextrude.cc | 23 | ||||
-rw-r--r-- | src/mainwin.cc | 8 | ||||
-rw-r--r-- | src/modcontext.cc | 152 | ||||
-rw-r--r-- | src/modcontext.h | 40 | ||||
-rw-r--r-- | src/module.cc | 91 | ||||
-rw-r--r-- | src/module.h | 30 | ||||
-rw-r--r-- | src/openscad.cc | 15 | ||||
-rw-r--r-- | src/parser.y | 795 | ||||
-rw-r--r-- | src/primitives.cc | 26 | ||||
-rw-r--r-- | src/printutils.cc | 2 | ||||
-rw-r--r-- | src/printutils.h | 3 | ||||
-rw-r--r-- | src/projection.cc | 15 | ||||
-rw-r--r-- | src/render.cc | 15 | ||||
-rw-r--r-- | src/rotateextrude.cc | 15 | ||||
-rw-r--r-- | src/surface.cc | 13 | ||||
-rw-r--r-- | src/transform.cc | 23 | ||||
-rw-r--r-- | src/typedefs.h | 10 |
35 files changed, 1150 insertions, 907 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..aad3a95 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,30 +39,29 @@ 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); - std::vector<std::string> argnames; - std::vector<Expression*> argexpr; + AssignmentList args; if (type == MINKOWSKI) - argnames += "convexity"; + args += Assignment("convexity", NULL); if (type == GLIDE) - argnames += "path", "convexity"; + args += Assignment("path", NULL), Assignment("convexity", NULL); if (type == SUBDIV) - argnames += "type", "level", "convexity"; + args += Assignment("type", NULL), Assignment("level", NULL), Assignment("convexity", NULL); if (type == RESIZE) - argnames += "newsize", "auto"; + args += Assignment("newsize", NULL), Assignment("auto", NULL); Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); + c.setVariables(args, evalctx); Value convexity, path, subdiv_type, level; @@ -111,7 +110,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..6c3aaef 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,27 +40,26 @@ 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); node->color[0] = node->color[1] = node->color[2] = -1.0; node->color[3] = 1.0; - std::vector<std::string> argnames; - std::vector<Expression*> argexpr; + AssignmentList args; - argnames += "c", "alpha"; + args += Assignment("c", NULL), Assignment("alpha", NULL); Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); + c.setVariables(args, evalctx); Value v = c.lookup_variable("c"); if (v.type() == Value::VECTOR) { @@ -88,7 +87,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..706407c 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,11 @@ 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 +54,26 @@ 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 AssignmentList &args, + 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()); + BOOST_FOREACH(const Assignment &arg, args) { + set_variable(arg.first, arg.second ? arg.second->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 < args.size()) this->set_variable(args[posarg++].first, val); + } else { + this->set_variable(name, val); + } } } } @@ -130,61 +117,16 @@ Value Context::lookup_variable(const std::string &name, bool silent) const return Value(); } -class RecursionGuard -{ -public: - RecursionGuard(const Context &c, const std::string &name) : c(c), name(name) { c.recursioncount[name]++; } - ~RecursionGuard() { if (--c.recursioncount[name] == 0) c.recursioncount.erase(name); } - bool recursion_detected() const { return (c.recursioncount[name] > 100); } -private: - const Context &c; - 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 +144,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 Assignment &arg, m->definition_arguments) { + PRINTB(" %s = %s", arg.first % variables[arg.first]); + } + } + } + typedef std::pair<std::string, Value> ValueMapType; + PRINT(" vars:"); + BOOST_FOREACH(const ValueMapType &v, constants) { + PRINTB(" %s = %s", v.first % v.second); + } + BOOST_FOREACH(const ValueMapType &v, variables) { + PRINTB(" %s = %s", v.first % v.second); + } + BOOST_FOREACH(const ValueMapType &v, config_variables) { + PRINTB(" %s = %s", v.first % v.second); + } - ctx.set_constant("PI",Value(M_PI)); } +#endif diff --git a/src/context.h b/src/context.h index eb9a175..51fc45c 100644 --- a/src/context.h +++ b/src/context.h @@ -5,48 +5,46 @@ #include <vector> #include <boost/unordered_map.hpp> #include "value.h" +#include "typedefs.h" 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 AssignmentList &args, + 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..d47eec0 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,69 @@ 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) { + int n = 0; + if (evalctx->eval_arguments.size() > 0) { double v; - if (inst->argvalues[0].getDouble(v)) { - if (v < 0) return NULL; // Disallow negative child indices + if (evalctx->eval_arguments[0].second.getDouble(v)) { n = trunc(v); + if (n < 0) { + PRINTB("WARNING: Negative child index (%d) not allowed", n); + return NULL; // Disallow negative child indices + } } } - 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) { + // This will trigger if trying to invoke child from the root of any file + // assert(filectx->evalctx); + + if (filectx->evalctx) { + if (n < filectx->evalctx->children.size()) { + node = filectx->evalctx->children[n]->evaluate_instance(filectx->evalctx); + } + else { + // How to deal with negative objects in this case? + // (e.g. first child of difference is invalid) + PRINTB("WARNING: Child index (%d) out of bounds (%d children)", + n % filectx->evalctx->children.size()); + } } return node; } - c = c->parent; + tmpc = tmpc->parent; } - return NULL; + return node; } if (type == INT_FOR) @@ -127,20 +140,20 @@ AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation { std::stringstream msg; msg << "ECHO: "; - for (size_t i = 0; i < inst->argnames.size(); i++) { + for (size_t i = 0; i < inst->arguments.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 +161,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..b7566e3 --- /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 Assignment &arg, m->definition_arguments) { + PRINTB(" %s = %s", arg.first % variables[arg.first]); + } + } + } +} +#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..7a8180f 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->call_arguments.size(); i++) { + c.eval_arguments.push_back(std::make_pair(this->call_arguments[i].first, + this->call_arguments[i].second->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(); } @@ -178,10 +183,11 @@ std::string Expression::toString() const } else if (this->type == "F") { stream << this->call_funcname << "("; - for (size_t i=0; i < this->children.size(); i++) { + for (size_t i=0; i < this->call_arguments.size(); i++) { + const Assignment &arg = this->call_arguments[i]; if (i > 0) stream << ", "; - if (!this->call_argnames[i].empty()) stream << this->call_argnames[i] << " = "; - stream << *this->children[i]; + if (!arg.first.empty()) stream << arg.first << " = "; + stream << *arg.second; } stream << ")"; } diff --git a/src/expression.h b/src/expression.h index 2919b78..06becc0 100644 --- a/src/expression.h +++ b/src/expression.h @@ -4,6 +4,7 @@ #include <string> #include <vector> #include "value.h" +#include "typedefs.h" class Expression { @@ -14,7 +15,7 @@ public: std::string var_name; std::string call_funcname; - std::vector<std::string> call_argnames; + AssignmentList call_arguments; // Boolean: ! && || // Operators: * / % + - diff --git a/src/func.cc b/src/func.cc index 26d7e69..88bf3c8 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> @@ -34,6 +34,7 @@ #include <algorithm> #include "stl-utils.h" #include "printutils.h" +#include <boost/foreach.hpp> /* Random numbers @@ -61,7 +62,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(); } @@ -75,16 +76,14 @@ std::string AbstractFunction::dump(const std::string &indent, const std::string Function::~Function() { - std::for_each(this->argexpr.begin(), this->argexpr.end(), del_fun<Expression>()); + BOOST_FOREACH(const Assignment &arg, this->definition_arguments) delete arg.second; 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(definition_arguments, evalctx); return expr ? expr->evaluate(&c) : Value(); } @@ -92,10 +91,11 @@ std::string Function::dump(const std::string &indent, const std::string &name) c { std::stringstream dump; dump << indent << "function " << name << "("; - for (size_t i=0; i < argnames.size(); i++) { + for (size_t i=0; i < definition_arguments.size(); i++) { + const Assignment &arg = definition_arguments[i]; if (i > 0) dump << ", "; - dump << argnames[i]; - if (argexpr[i]) dump << " = " << *argexpr[i]; + dump << arg.first; + if (arg.second) dump << " = " << *arg.second; } dump << ") = " << *expr << ";\n"; return dump.str(); @@ -105,9 +105,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 +127,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 +165,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 +181,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 +404,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 +499,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 +510,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..a1fde3c 100644 --- a/src/function.h +++ b/src/function.h @@ -2,6 +2,7 @@ #define FUNCTION_H_ #include "value.h" +#include "typedefs.h" #include <string> #include <vector> @@ -9,35 +10,34 @@ 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; }; class Function : public AbstractFunction { public: - std::vector<std::string> argnames; - std::vector<class Expression*> argexpr; + AssignmentList definition_arguments; Expression *expr; 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 627fb56..927c9d8 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,26 +60,43 @@ 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"; - std::vector<Expression*> argexpr; + AssignmentList args; + args += Assignment("file", NULL), Assignment("layer", NULL), Assignment("convexity", NULL), Assignment("origin", NULL), Assignment("scale", NULL); + args += Assignment("filename",NULL), Assignment("layername", NULL); + // FIXME: This is broken. Tag as deprecated and fix // Map old argnames to new argnames for compatibility + // To fix: + // o after c.setVariables() + // - if "filename" in evalctx: deprecated-warning && v.set_variable("file", value); + // - if "layername" in evalctx: deprecated-warning && v.set_variable("layer", value); +#if 0 std::vector<std::string> inst_argnames = inst->argnames; for (size_t i=0; i<inst_argnames.size(); i++) { if (inst_argnames[i] == "filename") inst_argnames[i] = "file"; if (inst_argnames[i] == "layername") inst_argnames[i] = "layer"; } +#endif Context c(ctx); - c.args(argnames, argexpr, inst_argnames, inst->argvalues); + c.setDocumentPath(evalctx->documentPath()); + c.setVariables(args, evalctx); +#if 0 && DEBUG + c.dump(this, inst); +#endif Value v = c.lookup_variable("file"); + if (v.isUndefined()) { + v = c.lookup_variable("filename"); + if (!v.isUndefined()) + PRINT("WARNING: filename= is deprecated. Please use file="); + } + std::string filename = inst->getAbsolutePath(v.isUndefined() ? "" : v.toString()); import_type_e actualtype = this->type; if (actualtype == TYPE_UNKNOWN) { @@ -98,6 +115,11 @@ AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiati node->filename = filename; Value layerval = c.lookup_variable("layer", true); + if (layerval.isUndefined()) { + layerval = c.lookup_variable("layername",true); + if (!layerval.isUndefined()) + PRINT("WARNING: layername= is deprecated. Please use layer="); + } node->layername = layerval.isUndefined() ? "" : layerval.toString(); node->convexity = c.lookup_variable("convexity", true).toDouble(); diff --git a/src/lexer.l b/src/lexer.l index 4dff654..6766abc 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -26,6 +26,7 @@ %{ +#include "typedefs.h" #include "handle_dep.h" #include "printutils.h" #include "parsersettings.h" diff --git a/src/linearextrude.cc b/src/linearextrude.cc index ff9682e..f4c1112 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,19 +45,18 @@ 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); - std::vector<std::string> argnames; - argnames += "file", "layer", "height", "origin", "scale", "center", "twist", "slices"; - std::vector<Expression*> argexpr; + AssignmentList args; + args += Assignment("file", NULL), Assignment("layer", NULL), Assignment("height", NULL), Assignment("origin", NULL), Assignment("scale", NULL), Assignment("center", NULL), Assignment("twist", NULL), Assignment("slices", NULL); Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); + c.setVariables(args, evalctx); node->fn = c.lookup_variable("$fn").toDouble(); node->fs = c.lookup_variable("$fs").toDouble(); @@ -81,10 +80,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 +116,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..7d123b8 --- /dev/null +++ b/src/modcontext.cc @@ -0,0 +1,152 @@ +#include "modcontext.h" +#include "module.h" +#include "expression.h" +#include "function.h" +#include "printutils.h" +#include "builtin.h" + +#include <boost/foreach.hpp> + +ModuleContext::ModuleContext(const class Module *module, const Context *parent, const EvalContext *evalctx) + : Context(parent) +{ + if (module) { + setModule(*module, evalctx); + } + else { + this->functions_p = NULL; + this->modules_p = NULL; + this->usedlibs_p = NULL; + } +} + +ModuleContext::~ModuleContext() +{ +} + +void ModuleContext::setModule(const Module &module, const EvalContext *evalctx) +{ + this->setVariables(module.definition_arguments, evalctx); + this->evalctx = evalctx; + + // FIXME: Don't access module members directly + this->functions_p = &module.functions; + this->modules_p = &module.modules; + this->usedlibs_p = &module.usedlibs; + BOOST_FOREACH(const std::string &var, module.assignments_var) { + this->set_variable(var, module.assignments.at(var)->evaluate(this)); + } + + if (!module.modulePath().empty()) this->document_path = module.modulePath(); +} + +/*! + Only used to initialize builtins for the top-level root context +*/ +void ModuleContext::registerBuiltin() +{ + this->setModule(Builtins::instance()->getRootModule()); + this->set_constant("PI",Value(M_PI)); +} + +class RecursionGuard +{ +public: + RecursionGuard(const ModuleContext &c, const std::string &name) : c(c), name(name) { + c.recursioncount[name]++; + } + ~RecursionGuard() { if (--c.recursioncount[name] == 0) c.recursioncount.erase(name); } + bool recursion_detected() const { return (c.recursioncount[name] > 100); } +private: + const ModuleContext &c; + const std::string &name; +}; + +Value ModuleContext::evaluate_function(const std::string &name, const EvalContext *evalctx) const +{ + RecursionGuard g(*this, name); + if (g.recursion_detected()) { + PRINTB("Recursion detected calling function '%s'", name); + return Value(); + } + + if (this->functions_p && this->functions_p->find(name) != this->functions_p->end()) { + return this->functions_p->find(name)->second->evaluate(this, evalctx); + } + + if (this->usedlibs_p) { + BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { + if (m.second->functions.find(name) != m.second->functions.end()) { + ModuleContext ctx(m.second, this->parent); + // FIXME: Set document path +#if 0 && DEBUG + PRINTB("New lib Context for %s func:", name); + ctx.dump(NULL, NULL); +#endif + return m.second->functions[name]->evaluate(&ctx, evalctx); + } + } + } + return Context::evaluate_function(name, evalctx); +} + +AbstractNode *ModuleContext::evaluate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const +{ + if (this->modules_p && this->modules_p->find(inst.name()) != this->modules_p->end()) { + AbstractModule *m = this->modules_p->find(inst.name())->second; + std::string replacement = Builtins::instance()->isDeprecated(inst.name()); + if (!replacement.empty()) { + PRINTB("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", inst.name() % replacement); + } + return m->evaluate(this, &inst, evalctx); + } + + if (this->usedlibs_p) { + BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { + assert(m.second); + if (m.second->modules.find(inst.name()) != m.second->modules.end()) { + ModuleContext ctx(m.second, this->parent); + // FIXME: Set document path +#if 0 && DEBUG + PRINT("New lib Context:"); + ctx.dump(NULL, &inst); +#endif + return m.second->modules[inst.name()]->evaluate(&ctx, &inst, evalctx); + } + } + } + + return Context::evaluate_module(inst, evalctx); +} + +#ifdef DEBUG +void ModuleContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst) +{ + if (inst) + PRINTB("ModuleContext %p (%p) for %s inst (%p) ", this % this->parent % inst->name() % inst); + else + PRINTB("ModuleContext: %p (%p)", this % this->parent); + PRINTB(" document path: %s", this->document_path); + if (mod) { + const Module *m = dynamic_cast<const Module*>(mod); + if (m) { + PRINT(" module args:"); + BOOST_FOREACH(const Assignment &arg, m->definition_arguments) { + PRINTB(" %s = %s", arg.first % variables[arg.first]); + } + } + } + typedef std::pair<std::string, Value> ValueMapType; + PRINT(" vars:"); + BOOST_FOREACH(const ValueMapType &v, constants) { + PRINTB(" %s = %s", v.first % v.second); + } + BOOST_FOREACH(const ValueMapType &v, variables) { + PRINTB(" %s = %s", v.first % v.second); + } + BOOST_FOREACH(const ValueMapType &v, config_variables) { + PRINTB(" %s = %s", v.first % v.second); + } + +} +#endif diff --git a/src/modcontext.h b/src/modcontext.h new file mode 100644 index 0000000..5fce88f --- /dev/null +++ b/src/modcontext.h @@ -0,0 +1,40 @@ +#ifndef FILECONTEXT_H_ +#define FILECONTEXT_H_ + +#include "context.h" +#include <boost/unordered_map.hpp> + +/*! + 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 + + mutable boost::unordered_map<std::string, int> recursioncount; +}; + +#endif diff --git a/src/module.cc b/src/module.cc index 322085b..7d83975 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; } @@ -61,8 +62,8 @@ std::string AbstractModule::dump(const std::string &indent, const std::string &n ModuleInstantiation::~ModuleInstantiation() { - BOOST_FOREACH (Expression *v, argexpr) delete v; - BOOST_FOREACH (ModuleInstantiation *v, children) delete v; + BOOST_FOREACH(const Assignment &arg, this->arguments) delete arg.second; + BOOST_FOREACH(ModuleInstantiation *v, children) delete v; } IfElseModuleInstantiation::~IfElseModuleInstantiation() @@ -88,10 +89,11 @@ std::string ModuleInstantiation::dump(const std::string &indent) const std::stringstream dump; dump << indent; dump << modname + "("; - for (size_t i=0; i < argnames.size(); i++) { + for (size_t i=0; i < this->arguments.size(); i++) { + const Assignment &arg = this->arguments[i]; if (i > 0) dump << ", "; - if (!argnames[i].empty()) dump << argnames[i] << " = "; - dump << *argexpr[i]; + if (!arg.first.empty()) dump << arg.first << " = "; + dump << *arg.second; } if (children.size() == 0) { dump << ");\n"; @@ -108,43 +110,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); + BOOST_FOREACH(const Assignment &arg, this->arguments) { + c.eval_arguments.push_back(std::make_pair(arg.first, + arg.second ? + arg.second->evaluate(ctx) : + Value())); } + c.children = this->children; + +#if 0 && 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; @@ -152,35 +151,24 @@ std::vector<AbstractNode*> IfElseModuleInstantiation::evaluateElseChildren(const Module::~Module() { - BOOST_FOREACH (const AssignmentContainer::value_type &v, assignments) delete v.second; + BOOST_FOREACH (const Assignment &v, assignments) delete v.second; BOOST_FOREACH (FunctionContainer::value_type &f, functions) delete f.second; BOOST_FOREACH (AbstractModuleContainer::value_type &m, modules) delete m.second; 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)); - } +#if 0 && 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); } @@ -194,10 +182,11 @@ std::string Module::dump(const std::string &indent, const std::string &name) con std::string tab; if (!name.empty()) { dump << indent << "module " << name << "("; - for (size_t i=0; i < argnames.size(); i++) { + for (size_t i=0; i < this->definition_arguments.size(); i++) { + const Assignment &arg = this->definition_arguments[i]; if (i > 0) dump << ", "; - dump << argnames[i]; - if (argexpr[i]) dump << " = " << *argexpr[i]; + dump << arg.first; + if (arg.second) dump << " = " << *arg.second; } dump << ") {\n"; tab = "\t"; diff --git a/src/module.h b/src/module.h index 1f9e303..ace3c1b 100644 --- a/src/module.h +++ b/src/module.h @@ -6,18 +6,18 @@ #include <list> #include <boost/unordered_map.hpp> #include "value.h" +#include "typedefs.h" 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; } @@ -28,11 +28,8 @@ public: bool isHighlight() const { return this->tag_highlight; } bool isRoot() const { return this->tag_root; } - std::vector<std::string> argnames; - std::vector<Value> argvalues; - std::vector<class Expression*> argexpr; + AssignmentList arguments; 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); } @@ -81,8 +81,8 @@ public: bool handleDependencies(); std::list<std::string> assignments_var; - typedef boost::unordered_map<std::string, Expression*> AssignmentContainer; - AssignmentContainer assignments; + typedef boost::unordered_map<std::string, Expression*> AssignmentMap; + AssignmentMap assignments; typedef boost::unordered_map<std::string, class AbstractFunction*> FunctionContainer; FunctionContainer functions; @@ -91,12 +91,12 @@ public: std::vector<ModuleInstantiation*> children; - std::vector<std::string> argnames; - std::vector<Expression*> argexpr; + std::vector<Assignment> definition_arguments; protected: private: + std::string path; }; #endif diff --git a/src/openscad.cc b/src/openscad.cc index 878c207..3b960f3 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,18 @@ int main(int argc, char **argv) if (!root_module) exit(1); root_module->handleDependencies(); + ModuleContext root_ctx; + root_ctx.registerBuiltin(); + PRINT("Root Context:"); +#if 0 && DEBUG + root_ctx.dump(NULL, NULL); +#endif 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..fd6b164 100644 --- a/src/parser.y +++ b/src/parser.y @@ -34,6 +34,7 @@ #include <unistd.h> #endif +#include "typedefs.h" #include "module.h" #include "expression.h" #include "value.h" @@ -43,50 +44,39 @@ #include <boost/foreach.hpp> #include <boost/filesystem.hpp> -namespace fs = boost::filesystem; + namespace fs = boost::filesystem; #include "boosty.h" -int parser_error_pos = -1; + int parser_error_pos = -1; -int parserlex(void); -void yyerror(char const *s); + int parserlex(void); + void yyerror(char const *s); -int lexerget_lineno(void); -int lexerlex_destroy(void); -int lexerlex(void); + int lexerget_lineno(void); + int lexerlex_destroy(void); + int lexerlex(void); -std::vector<Module*> module_stack; -Module *currmodule; + std::vector<Module*> module_stack; + Module *currmodule; -extern void lexerdestroy(); -extern FILE *lexerin; -extern const char *parser_input_buffer; -const char *parser_input_buffer; -std::string parser_source_path; + extern void lexerdestroy(); + extern FILE *lexerin; + extern const char *parser_input_buffer; + const char *parser_input_buffer; + std::string parser_source_path; -class ArgContainer { -public: - std::string argname; - Expression *argexpr; -}; -class ArgsContainer { -public: - std::vector<std::string> argnames; - std::vector<Expression*> argexpr; -}; - -%} + %} %union { - char *text; - double number; - class Value *value; - class Expression *expr; - class ModuleInstantiation *inst; - std::vector<ModuleInstantiation*> *instvec; - class IfElseModuleInstantiation *ifelse; - class ArgContainer *arg; - class ArgsContainer *args; + char *text; + double number; + class Value *value; + class Expression *expr; + class ModuleInstantiation *inst; + std::vector<ModuleInstantiation*> *instvec; + class IfElseModuleInstantiation *ifelse; + Assignment *arg; + AssignmentList *args; } %token TOK_MODULE @@ -139,427 +129,412 @@ public: %% input: - /* empty */ | - TOK_USE { currmodule->usedlibs[$1] = NULL; } input | - statement input ; +/* empty */ | +TOK_USE { currmodule->usedlibs[$1] = NULL; } input | +statement input ; inner_input: - /* empty */ | - statement inner_input ; +/* empty */ | +statement inner_input ; statement: - ';' | - '{' inner_input '}' | - module_instantiation { - if ($1) { - currmodule->addChild($1); - } else { - delete $1; - } - } | - TOK_ID '=' expr ';' { - std::list<std::string>::iterator found = std::find(currmodule->assignments_var.begin(), currmodule->assignments_var.end(),$1); - if (found != currmodule->assignments_var.end()) currmodule->assignments_var.erase(found); - currmodule->assignments_var.push_back($1); - currmodule->assignments[$1] = $3; - } | - TOK_MODULE TOK_ID '(' arguments_decl optional_commas ')' { - Module *p = currmodule; - module_stack.push_back(currmodule); - currmodule = new Module(); - p->modules[$2] = currmodule; - currmodule->argnames = $4->argnames; - currmodule->argexpr = $4->argexpr; - free($2); - delete $4; - } statement { - currmodule = module_stack.back(); - module_stack.pop_back(); - } | - TOK_FUNCTION TOK_ID '(' arguments_decl optional_commas ')' '=' expr { - Function *func = new Function(); - func->argnames = $4->argnames; - func->argexpr = $4->argexpr; - func->expr = $8; - currmodule->functions[$2] = func; - free($2); - delete $4; - } ';' ; +';' | +'{' inner_input '}' | +module_instantiation { + if ($1) { + currmodule->addChild($1); + } else { + delete $1; + } +} | +TOK_ID '=' expr ';' { + std::list<std::string>::iterator found = std::find(currmodule->assignments_var.begin(), currmodule->assignments_var.end(),$1); + if (found != currmodule->assignments_var.end()) currmodule->assignments_var.erase(found); + currmodule->assignments_var.push_back($1); + currmodule->assignments[$1] = $3; +} | +TOK_MODULE TOK_ID '(' arguments_decl optional_commas ')' { + Module *p = currmodule; + module_stack.push_back(currmodule); + currmodule = new Module(); + p->modules[$2] = currmodule; + currmodule->definition_arguments = *$4; + free($2); + delete $4; +} statement { + currmodule = module_stack.back(); + module_stack.pop_back(); + } | + TOK_FUNCTION TOK_ID '(' arguments_decl optional_commas ')' '=' expr { + Function *func = new Function(); + func->definition_arguments = *$4; + func->expr = $8; + currmodule->functions[$2] = func; + free($2); + delete $4; + } ';' ; /* Will return a dummy parent node with zero or more children */ children_instantiation: - module_instantiation { - $$ = new std::vector<ModuleInstantiation*>; - if ($1) { - $$->push_back($1); - } - } | - '{' module_instantiation_list '}' { - $$ = $2; - } ; +module_instantiation { + $$ = new std::vector<ModuleInstantiation*>; + if ($1) { + $$->push_back($1); + } +} | +'{' module_instantiation_list '}' { + $$ = $2; +} ; if_statement: - TOK_IF '(' expr ')' children_instantiation { - $$ = new IfElseModuleInstantiation(); - $$->argnames.push_back(""); - $$->argexpr.push_back($3); - $$->setPath(parser_source_path); - - if ($$) { - $$->children = *$5; - } else { - for (size_t i = 0; i < $5->size(); i++) - delete (*$5)[i]; - } - delete $5; - } ; +TOK_IF '(' expr ')' children_instantiation { + $$ = new IfElseModuleInstantiation(); + $$->arguments.push_back(Assignment("", $3)); + $$->setPath(parser_source_path); + + if ($$) { + $$->children = *$5; + } else { + for (size_t i = 0; i < $5->size(); i++) + delete (*$5)[i]; + } + delete $5; +} ; ifelse_statement: - if_statement { - $$ = $1; - } | - if_statement TOK_ELSE children_instantiation { - $$ = $1; - if ($$) { - $$->else_children = *$3; - } else { - for (size_t i = 0; i < $3->size(); i++) - delete (*$3)[i]; - } - delete $3; - } ; +if_statement { + $$ = $1; +} | +if_statement TOK_ELSE children_instantiation { + $$ = $1; + if ($$) { + $$->else_children = *$3; + } else { + for (size_t i = 0; i < $3->size(); i++) + delete (*$3)[i]; + } + delete $3; +} ; module_instantiation: - '!' module_instantiation { - $$ = $2; - if ($$) $$->tag_root = true; - } | - '#' module_instantiation { - $$ = $2; - if ($$) $$->tag_highlight = true; - } | - '%' module_instantiation { - $$ = $2; - if ($$) $$->tag_background = true; - } | - '*' module_instantiation { - delete $2; - $$ = NULL; - } | - single_module_instantiation ';' { - $$ = $1; - } | - single_module_instantiation children_instantiation { - $$ = $1; - if ($$) { - $$->children = *$2; - } else { - for (size_t i = 0; i < $2->size(); i++) - delete (*$2)[i]; - } - delete $2; - } | - ifelse_statement { - $$ = $1; - } ; +'!' module_instantiation { + $$ = $2; + if ($$) $$->tag_root = true; +} | +'#' module_instantiation { + $$ = $2; + if ($$) $$->tag_highlight = true; +} | +'%' module_instantiation { + $$ = $2; + if ($$) $$->tag_background = true; +} | +'*' module_instantiation { + delete $2; + $$ = NULL; +} | +single_module_instantiation ';' { + $$ = $1; +} | +single_module_instantiation children_instantiation { + $$ = $1; + if ($$) { + $$->children = *$2; + } else { + for (size_t i = 0; i < $2->size(); i++) + delete (*$2)[i]; + } + delete $2; +} | +ifelse_statement { + $$ = $1; +} ; module_instantiation_list: - /* empty */ { - $$ = new std::vector<ModuleInstantiation*>; - } | - module_instantiation_list module_instantiation { - $$ = $1; - if ($$) { - if ($2) $$->push_back($2); - } else { - delete $2; - } - } ; +/* empty */ { + $$ = new std::vector<ModuleInstantiation*>; +} | +module_instantiation_list module_instantiation { + $$ = $1; + if ($$) { + if ($2) $$->push_back($2); + } else { + delete $2; + } +} ; single_module_instantiation: - TOK_ID '(' arguments_call ')' { - $$ = new ModuleInstantiation($1); - $$->argnames = $3->argnames; - $$->argexpr = $3->argexpr; - $$->setPath(parser_source_path); - free($1); - delete $3; - } +TOK_ID '(' arguments_call ')' { + $$ = new ModuleInstantiation($1); + $$->arguments = *$3; + $$->setPath(parser_source_path); + free($1); + delete $3; +} expr: - TOK_TRUE { - $$ = new Expression(Value(true)); - } | - TOK_FALSE { - $$ = new Expression(Value(false)); - } | - TOK_UNDEF { - $$ = new Expression(Value::undefined); - } | - TOK_ID { - $$ = new Expression(); - $$->type = "L"; - $$->var_name = $1; - free($1); - } | - expr '.' TOK_ID { - $$ = new Expression(); - $$->type = "N"; - $$->children.push_back($1); - $$->var_name = $3; - free($3); - } | - TOK_STRING { - $$ = new Expression(Value(std::string($1))); - free($1); - } | - TOK_NUMBER { - $$ = new Expression(Value($1)); - } | - '[' expr ':' expr ']' { - Expression *e_one = new Expression(Value(1.0)); - $$ = new Expression(); - $$->type = "R"; - $$->children.push_back($2); - $$->children.push_back(e_one); - $$->children.push_back($4); - } | - '[' expr ':' expr ':' expr ']' { - $$ = new Expression(); - $$->type = "R"; - $$->children.push_back($2); - $$->children.push_back($4); - $$->children.push_back($6); - } | - '[' optional_commas ']' { - $$ = new Expression(Value(Value::VectorType())); - } | - '[' vector_expr optional_commas ']' { - $$ = $2; - } | - expr '*' expr { - $$ = new Expression(); - $$->type = "*"; - $$->children.push_back($1); - $$->children.push_back($3); - } | - expr '/' expr { - $$ = new Expression(); - $$->type = "/"; - $$->children.push_back($1); - $$->children.push_back($3); - } | - expr '%' expr { - $$ = new Expression(); - $$->type = "%"; - $$->children.push_back($1); - $$->children.push_back($3); - } | - expr '+' expr { - $$ = new Expression(); - $$->type = "+"; - $$->children.push_back($1); - $$->children.push_back($3); - } | - expr '-' expr { - $$ = new Expression(); - $$->type = "-"; - $$->children.push_back($1); - $$->children.push_back($3); - } | - expr '<' expr { - $$ = new Expression(); - $$->type = "<"; - $$->children.push_back($1); - $$->children.push_back($3); - } | - expr LE expr { - $$ = new Expression(); - $$->type = "<="; - $$->children.push_back($1); - $$->children.push_back($3); - } | - expr EQ expr { - $$ = new Expression(); - $$->type = "=="; - $$->children.push_back($1); - $$->children.push_back($3); - } | - expr NE expr { - $$ = new Expression(); - $$->type = "!="; - $$->children.push_back($1); - $$->children.push_back($3); - } | - expr GE expr { - $$ = new Expression(); - $$->type = ">="; - $$->children.push_back($1); - $$->children.push_back($3); - } | - expr '>' expr { - $$ = new Expression(); - $$->type = ">"; - $$->children.push_back($1); - $$->children.push_back($3); - } | - expr AND expr { - $$ = new Expression(); - $$->type = "&&"; - $$->children.push_back($1); - $$->children.push_back($3); - } | - expr OR expr { - $$ = new Expression(); - $$->type = "||"; - $$->children.push_back($1); - $$->children.push_back($3); - } | - '+' expr { - $$ = $2; - } | - '-' expr { - $$ = new Expression(); - $$->type = "I"; - $$->children.push_back($2); - } | - '!' expr { - $$ = new Expression(); - $$->type = "!"; - $$->children.push_back($2); - } | - '(' expr ')' { - $$ = $2; - } | - expr '?' expr ':' expr { - $$ = new Expression(); - $$->type = "?:"; - $$->children.push_back($1); - $$->children.push_back($3); - $$->children.push_back($5); - } | - expr '[' expr ']' { - $$ = new Expression(); - $$->type = "[]"; - $$->children.push_back($1); - $$->children.push_back($3); - } | - TOK_ID '(' arguments_call ')' { - $$ = new Expression(); - $$->type = "F"; - $$->call_funcname = $1; - $$->call_argnames = $3->argnames; - $$->children = $3->argexpr; - free($1); - delete $3; - } ; +TOK_TRUE { + $$ = new Expression(Value(true)); +} | +TOK_FALSE { + $$ = new Expression(Value(false)); +} | +TOK_UNDEF { + $$ = new Expression(Value::undefined); +} | +TOK_ID { + $$ = new Expression(); + $$->type = "L"; + $$->var_name = $1; + free($1); +} | +expr '.' TOK_ID { + $$ = new Expression(); + $$->type = "N"; + $$->children.push_back($1); + $$->var_name = $3; + free($3); +} | +TOK_STRING { + $$ = new Expression(Value(std::string($1))); + free($1); +} | +TOK_NUMBER { + $$ = new Expression(Value($1)); +} | +'[' expr ':' expr ']' { + Expression *e_one = new Expression(Value(1.0)); + $$ = new Expression(); + $$->type = "R"; + $$->children.push_back($2); + $$->children.push_back(e_one); + $$->children.push_back($4); +} | +'[' expr ':' expr ':' expr ']' { + $$ = new Expression(); + $$->type = "R"; + $$->children.push_back($2); + $$->children.push_back($4); + $$->children.push_back($6); +} | +'[' optional_commas ']' { + $$ = new Expression(Value(Value::VectorType())); +} | +'[' vector_expr optional_commas ']' { + $$ = $2; +} | +expr '*' expr { + $$ = new Expression(); + $$->type = "*"; + $$->children.push_back($1); + $$->children.push_back($3); +} | +expr '/' expr { + $$ = new Expression(); + $$->type = "/"; + $$->children.push_back($1); + $$->children.push_back($3); +} | +expr '%' expr { + $$ = new Expression(); + $$->type = "%"; + $$->children.push_back($1); + $$->children.push_back($3); +} | +expr '+' expr { + $$ = new Expression(); + $$->type = "+"; + $$->children.push_back($1); + $$->children.push_back($3); +} | +expr '-' expr { + $$ = new Expression(); + $$->type = "-"; + $$->children.push_back($1); + $$->children.push_back($3); +} | +expr '<' expr { + $$ = new Expression(); + $$->type = "<"; + $$->children.push_back($1); + $$->children.push_back($3); +} | +expr LE expr { + $$ = new Expression(); + $$->type = "<="; + $$->children.push_back($1); + $$->children.push_back($3); +} | +expr EQ expr { + $$ = new Expression(); + $$->type = "=="; + $$->children.push_back($1); + $$->children.push_back($3); +} | +expr NE expr { + $$ = new Expression(); + $$->type = "!="; + $$->children.push_back($1); + $$->children.push_back($3); +} | +expr GE expr { + $$ = new Expression(); + $$->type = ">="; + $$->children.push_back($1); + $$->children.push_back($3); +} | +expr '>' expr { + $$ = new Expression(); + $$->type = ">"; + $$->children.push_back($1); + $$->children.push_back($3); +} | +expr AND expr { + $$ = new Expression(); + $$->type = "&&"; + $$->children.push_back($1); + $$->children.push_back($3); +} | +expr OR expr { + $$ = new Expression(); + $$->type = "||"; + $$->children.push_back($1); + $$->children.push_back($3); +} | +'+' expr { + $$ = $2; +} | +'-' expr { + $$ = new Expression(); + $$->type = "I"; + $$->children.push_back($2); +} | +'!' expr { + $$ = new Expression(); + $$->type = "!"; + $$->children.push_back($2); +} | +'(' expr ')' { + $$ = $2; +} | +expr '?' expr ':' expr { + $$ = new Expression(); + $$->type = "?:"; + $$->children.push_back($1); + $$->children.push_back($3); + $$->children.push_back($5); +} | +expr '[' expr ']' { + $$ = new Expression(); + $$->type = "[]"; + $$->children.push_back($1); + $$->children.push_back($3); +} | +TOK_ID '(' arguments_call ')' { + $$ = new Expression(); + $$->type = "F"; + $$->call_funcname = $1; + $$->call_arguments = *$3; + free($1); + delete $3; +} ; optional_commas: - ',' optional_commas | ; +',' optional_commas | ; vector_expr: - expr { - $$ = new Expression(); - $$->type = 'V'; - $$->children.push_back($1); - } | - vector_expr ',' optional_commas expr { - $$ = $1; - $$->children.push_back($4); - } ; +expr { + $$ = new Expression(); + $$->type = 'V'; + $$->children.push_back($1); +} | +vector_expr ',' optional_commas expr { + $$ = $1; + $$->children.push_back($4); +} ; arguments_decl: - /* empty */ { - $$ = new ArgsContainer(); - } | - argument_decl { - $$ = new ArgsContainer(); - $$->argnames.push_back($1->argname); - $$->argexpr.push_back($1->argexpr); - delete $1; - } | - arguments_decl ',' optional_commas argument_decl { - $$ = $1; - $$->argnames.push_back($4->argname); - $$->argexpr.push_back($4->argexpr); - delete $4; - } ; +/* empty */ { + $$ = new AssignmentList(); +} | +argument_decl { + $$ = new AssignmentList(); + $$->push_back(*$1); + delete $1; +} | +arguments_decl ',' optional_commas argument_decl { + $$ = $1; + $$->push_back(*$4); + delete $4; +} ; argument_decl: - TOK_ID { - $$ = new ArgContainer(); - $$->argname = $1; - $$->argexpr = NULL; - free($1); - } | - TOK_ID '=' expr { - $$ = new ArgContainer(); - $$->argname = $1; - $$->argexpr = $3; - free($1); - } ; +TOK_ID { + $$ = new Assignment($1, NULL); + free($1); +} | +TOK_ID '=' expr { + $$ = new Assignment($1, $3); + free($1); +} ; arguments_call: - /* empty */ { - $$ = new ArgsContainer(); - } | - argument_call { - $$ = new ArgsContainer(); - $$->argnames.push_back($1->argname); - $$->argexpr.push_back($1->argexpr); - delete $1; - } | - arguments_call ',' optional_commas argument_call { - $$ = $1; - $$->argnames.push_back($4->argname); - $$->argexpr.push_back($4->argexpr); - delete $4; - } ; +/* empty */ { + $$ = new AssignmentList(); +} | +argument_call { + $$ = new AssignmentList(); + $$->push_back(*$1); + delete $1; +} | +arguments_call ',' optional_commas argument_call { + $$ = $1; + $$->push_back(*$4); + delete $4; +} ; argument_call: - expr { - $$ = new ArgContainer(); - $$->argexpr = $1; - } | - TOK_ID '=' expr { - $$ = new ArgContainer(); - $$->argname = $1; - $$->argexpr = $3; - free($1); - } ; +expr { + $$ = new Assignment("", $1); +} | +TOK_ID '=' expr { + $$ = new Assignment($1, $3); + free($1); +} ; %% int parserlex(void) { - return lexerlex(); + return lexerlex(); } void yyerror (char const *s) { - // FIXME: We leak memory on parser errors... - PRINTB("Parser error in line %d: %s\n", lexerget_lineno() % s); - currmodule = NULL; + // FIXME: We leak memory on parser errors... + PRINTB("Parser error in line %d: %s\n", lexerget_lineno() % s); + currmodule = NULL; } Module *parse(const char *text, const char *path, int debug) { - lexerin = NULL; - parser_error_pos = -1; - parser_input_buffer = text; - parser_source_path = boosty::absolute(std::string(path)).string(); + lexerin = NULL; + parser_error_pos = -1; + parser_input_buffer = text; + parser_source_path = boosty::absolute(std::string(path)).string(); - module_stack.clear(); - Module *rootmodule = currmodule = new Module(); - // PRINTB_NOCACHE("New module: %s %p", "root" % rootmodule); + module_stack.clear(); + Module *rootmodule = currmodule = new Module(); + rootmodule->setModulePath(path); + // PRINTB_NOCACHE("New module: %s %p", "root" % rootmodule); - parserdebug = debug; - int parserretval = parserparse(); - lexerdestroy(); - lexerlex_destroy(); + parserdebug = debug; + int parserretval = parserparse(); + lexerdestroy(); + lexerlex_destroy(); - if (parserretval != 0) return NULL; + if (parserretval != 0) return NULL; - parser_error_pos = -1; - return rootmodule; + parser_error_pos = -1; + return rootmodule; } diff --git a/src/primitives.cc b/src/primitives.cc index e02df35..184b40c 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,44 +105,43 @@ 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); node->center = false; node->x = node->y = node->z = node->h = node->r1 = node->r2 = 1; - std::vector<std::string> argnames; - std::vector<Expression*> argexpr; + AssignmentList args; switch (this->type) { case CUBE: - argnames += "size", "center"; + args += Assignment("size", NULL), Assignment("center", NULL); break; case SPHERE: - argnames += "r"; + args += Assignment("r", NULL); break; case CYLINDER: - argnames += "h", "r1", "r2", "center"; + args += Assignment("h", NULL), Assignment("r1", NULL), Assignment("r2", NULL), Assignment("center", NULL); break; case POLYHEDRON: - argnames += "points", "triangles", "convexity"; + args += Assignment("points", NULL), Assignment("triangles", NULL), Assignment("convexity", NULL); break; case SQUARE: - argnames += "size", "center"; + args += Assignment("size", NULL), Assignment("center", NULL); break; case CIRCLE: - argnames += "r"; + args += Assignment("r", NULL); break; case POLYGON: - argnames += "points", "paths", "convexity"; + args += Assignment("points", NULL), Assignment("paths", NULL), Assignment("convexity", NULL); break; default: assert(false && "PrimitiveModule::evaluate(): Unknown node type"); } Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); + c.setVariables(args, 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..eeed411 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,19 +41,18 @@ 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); - std::vector<std::string> argnames; - argnames += "cut"; - std::vector<Expression*> argexpr; + AssignmentList args; + args += Assignment("cut", NULL); Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); + c.setVariables(args, evalctx); Value convexity = c.lookup_variable("convexity", true); Value cut = c.lookup_variable("cut", true); @@ -63,7 +62,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..bb08c0c 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,25 +38,24 @@ 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); - std::vector<std::string> argnames; - argnames += "convexity"; - std::vector<Expression*> argexpr; + AssignmentList args; + args += Assignment("convexity", NULL); Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); + c.setVariables(args, 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..b6edb8b 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,19 +45,18 @@ 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); - std::vector<std::string> argnames; - argnames += "file", "layer", "origin", "scale"; - std::vector<Expression*> argexpr; + AssignmentList args; + args += Assignment("file", NULL), Assignment("layer", NULL), Assignment("origin", NULL), Assignment("scale", NULL); Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); + c.setVariables(args, evalctx); node->fn = c.lookup_variable("$fn").toDouble(); node->fs = c.lookup_variable("$fs").toDouble(); @@ -86,7 +85,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..d8fa422 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,18 +69,17 @@ 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; node->convexity = 1; - std::vector<std::string> argnames; - argnames += "file", "center", "convexity"; - std::vector<Expression*> argexpr; + AssignmentList args; + args += Assignment("file", NULL), Assignment("center", NULL), Assignment("convexity", NULL); Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); + c.setVariables(args, 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..cc026fb 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,40 +50,39 @@ 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); node->matrix = Transform3d::Identity(); - std::vector<std::string> argnames; - std::vector<Expression*> argexpr; + AssignmentList args; switch (this->type) { case SCALE: - argnames += "v"; + args += Assignment("v", NULL); break; case ROTATE: - argnames += "a", "v"; + args += Assignment("a", NULL), Assignment("v", NULL); break; case MIRROR: - argnames += "v"; + args += Assignment("v", NULL); break; case TRANSLATE: - argnames += "v"; + args += Assignment("v", NULL); break; case MULTMATRIX: - argnames += "m"; + args += Assignment("m", NULL); break; default: assert(false); } Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); + c.setVariables(args, evalctx); if (this->type == SCALE) { @@ -176,7 +175,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; diff --git a/src/typedefs.h b/src/typedefs.h new file mode 100644 index 0000000..a6e9077 --- /dev/null +++ b/src/typedefs.h @@ -0,0 +1,10 @@ +#ifndef TYPEDEFS_H_ +#define TYPEDEFS_H_ + +#include <string> +#include <vector> + +typedef std::pair<std::string, class Expression*> Assignment; +typedef std::vector<Assignment> AssignmentList; + +#endif |