Support variable assignment in local blocks. This should fix #347 but more testing is needed

master
Marius Kintel 2014-11-17 00:57:36 -05:00
parent 1263042fc9
commit ea1d561c46
28 changed files with 208 additions and 90 deletions

View File

@ -39,10 +39,10 @@ class CgaladvModule : public AbstractModule
public: public:
cgaladv_type_e type; cgaladv_type_e type;
CgaladvModule(cgaladv_type_e type) : type(type) { } CgaladvModule(cgaladv_type_e type) : type(type) { }
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const;
}; };
AbstractNode *CgaladvModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const AbstractNode *CgaladvModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const
{ {
CgaladvNode *node = new CgaladvNode(inst, type); CgaladvNode *node = new CgaladvNode(inst, type);
@ -62,6 +62,7 @@ AbstractNode *CgaladvModule::instantiate(const Context *ctx, const ModuleInstant
Context c(ctx); Context c(ctx);
c.setVariables(args, evalctx); c.setVariables(args, evalctx);
evalctx->applyScope();
Value convexity, path, subdiv_type, level; Value convexity, path, subdiv_type, level;

View File

@ -42,7 +42,7 @@ class ColorModule : public AbstractModule
public: public:
ColorModule(); ColorModule();
virtual ~ColorModule(); virtual ~ColorModule();
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const;
private: private:
boost::unordered_map<std::string, Color4f> webcolors; boost::unordered_map<std::string, Color4f> webcolors;
@ -205,7 +205,7 @@ ColorModule::~ColorModule()
{ {
} }
AbstractNode *ColorModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const AbstractNode *ColorModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const
{ {
ColorNode *node = new ColorNode(inst); ColorNode *node = new ColorNode(inst);
@ -218,6 +218,7 @@ AbstractNode *ColorModule::instantiate(const Context *ctx, const ModuleInstantia
Context c(ctx); Context c(ctx);
c.setVariables(args, evalctx); c.setVariables(args, evalctx);
evalctx->applyScope();
Value v = c.lookup_variable("c"); Value v = c.lookup_variable("c");
if (v.type() == Value::VECTOR) { if (v.type() == Value::VECTOR) {

View File

@ -152,7 +152,7 @@ Value Context::evaluate_function(const std::string &name, const EvalContext *eva
return Value(); return Value();
} }
AbstractNode *Context::instantiate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const AbstractNode *Context::instantiate_module(const ModuleInstantiation &inst, EvalContext *evalctx) const
{ {
if (this->parent) return this->parent->instantiate_module(inst, evalctx); if (this->parent) return this->parent->instantiate_module(inst, evalctx);
PRINTB("WARNING: Ignoring unknown module '%s'.", inst.name()); PRINTB("WARNING: Ignoring unknown module '%s'.", inst.name());

View File

@ -15,7 +15,7 @@ public:
const Context *getParent() const { return this->parent; } const Context *getParent() const { return this->parent; }
virtual Value evaluate_function(const std::string &name, const class EvalContext *evalctx) const; virtual Value evaluate_function(const std::string &name, const class EvalContext *evalctx) const;
virtual class AbstractNode *instantiate_module(const class ModuleInstantiation &inst, const EvalContext *evalctx) const; virtual class AbstractNode *instantiate_module(const class ModuleInstantiation &inst, EvalContext *evalctx) const;
void setVariables(const AssignmentList &args, void setVariables(const AssignmentList &args,
const class EvalContext *evalctx = NULL); const class EvalContext *evalctx = NULL);

View File

@ -29,6 +29,7 @@
#include "node.h" #include "node.h"
#include "evalcontext.h" #include "evalcontext.h"
#include "modcontext.h" #include "modcontext.h"
#include "expression.h"
#include "builtin.h" #include "builtin.h"
#include "printutils.h" #include "printutils.h"
#include <sstream> #include <sstream>
@ -55,7 +56,7 @@ public: // methods
: type(type) : type(type)
{ } { }
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const;
static void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l, static void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l,
const Context *ctx, const EvalContext *evalctx); const Context *ctx, const EvalContext *evalctx);
@ -99,7 +100,14 @@ void ControlModule::for_eval(AbstractNode &node, const ModuleInstantiation &inst
for_eval(node, inst, l+1, &c, evalctx); for_eval(node, inst, l+1, &c, evalctx);
} }
} else if (l > 0) { } else if (l > 0) {
std::vector<AbstractNode *> instantiatednodes = inst.instantiateChildren(ctx); // At this point, the for loop variables have been set and we can initialize
// the local scope (as they may depend on the for loop variables
Context c(ctx);
BOOST_FOREACH(const Assignment &ass, inst.scope.assignments) {
c.set_variable(ass.first, ass.second->evaluate(&c));
}
std::vector<AbstractNode *> instantiatednodes = inst.instantiateChildren(&c);
node.children.insert(node.children.end(), instantiatednodes.begin(), instantiatednodes.end()); node.children.insert(node.children.end(), instantiatednodes.begin(), instantiatednodes.end());
} }
} }
@ -155,12 +163,16 @@ AbstractNode* ControlModule::getChild(const Value& value, const EvalContext* mod
return modulectx->getChild(n)->evaluate(modulectx); return modulectx->getChild(n)->evaluate(modulectx);
} }
AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleInstantiation *inst, const EvalContext *evalctx) const AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleInstantiation *inst, EvalContext *evalctx) const
{ {
AbstractNode *node = NULL; AbstractNode *node = NULL;
if (type == CHILD) if (this->type != FOR && this->type != INT_FOR) {
{ evalctx->applyScope();
}
switch (this->type) {
case CHILD: {
printDeprecation("DEPRECATED: child() will be removed in future releases. Use children() instead."); printDeprecation("DEPRECATED: child() will be removed in future releases. Use children() instead.");
int n = 0; int n = 0;
if (evalctx->numArgs() > 0) { if (evalctx->numArgs() > 0) {
@ -192,9 +204,9 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns
} }
return node; return node;
} }
break;
if (type == CHILDREN) case CHILDREN: {
{
const EvalContext *modulectx = getLastModuleCtx(evalctx); const EvalContext *modulectx = getLastModuleCtx(evalctx);
if (modulectx==NULL) { if (modulectx==NULL) {
return NULL; return NULL;
@ -251,14 +263,10 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns
} }
return NULL; return NULL;
} }
break;
if (type == INT_FOR) case ECHO: {
node = new AbstractIntersectionNode(inst);
else
node = new AbstractNode(inst); node = new AbstractNode(inst);
if (type == ECHO)
{
std::stringstream msg; std::stringstream msg;
msg << "ECHO: "; msg << "ECHO: ";
for (size_t i = 0; i < inst->arguments.size(); i++) { for (size_t i = 0; i < inst->arguments.size(); i++) {
@ -273,9 +281,10 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns
} }
PRINTB("%s", msg.str()); PRINTB("%s", msg.str());
} }
break;
if (type == ASSIGN) case ASSIGN: {
{ node = new AbstractNode(inst);
Context c(evalctx); Context c(evalctx);
for (size_t i = 0; i < evalctx->numArgs(); i++) { for (size_t i = 0; i < evalctx->numArgs(); i++) {
if (!evalctx->getArgName(i).empty()) if (!evalctx->getArgName(i).empty())
@ -284,14 +293,20 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns
std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(&c); std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(&c);
node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end()); node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
} }
break;
if (type == FOR || type == INT_FOR) case FOR:
{ node = new AbstractNode(inst);
for_eval(*node, *inst, 0, evalctx, evalctx); for_eval(*node, *inst, 0, evalctx, evalctx);
} break;
if (type == IF) case INT_FOR:
{ node = new AbstractIntersectionNode(inst);
for_eval(*node, *inst, 0, evalctx, evalctx);
break;
case IF: {
node = new AbstractNode(inst);
const IfElseModuleInstantiation *ifelse = dynamic_cast<const IfElseModuleInstantiation*>(inst); const IfElseModuleInstantiation *ifelse = dynamic_cast<const IfElseModuleInstantiation*>(inst);
if (evalctx->numArgs() > 0 && evalctx->getArgValue(0).toBool()) { if (evalctx->numArgs() > 0 && evalctx->getArgValue(0).toBool()) {
std::vector<AbstractNode *> instantiatednodes = ifelse->instantiateChildren(evalctx); std::vector<AbstractNode *> instantiatednodes = ifelse->instantiateChildren(evalctx);
@ -302,7 +317,8 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns
node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end()); node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
} }
} }
break;
}
return node; return node;
} }

View File

@ -38,11 +38,12 @@ class CsgModule : public AbstractModule
public: public:
OpenSCADOperator type; OpenSCADOperator type;
CsgModule(OpenSCADOperator type) : type(type) { } CsgModule(OpenSCADOperator type) : type(type) { }
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const;
}; };
AbstractNode *CsgModule::instantiate(const Context*, const ModuleInstantiation *inst, const EvalContext *evalctx) const AbstractNode *CsgModule::instantiate(const Context*, const ModuleInstantiation *inst, EvalContext *evalctx) const
{ {
evalctx->applyScope();
CsgNode *node = new CsgNode(inst, type); CsgNode *node = new CsgNode(inst, type);
std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx); std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end()); node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());

View File

@ -8,6 +8,12 @@
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
EvalContext::EvalContext(const Context *parent,
const AssignmentList &args, const class LocalScope *const scope)
: Context(parent), eval_arguments(args), scope(scope)
{
}
const std::string &EvalContext::getArgName(size_t i) const const std::string &EvalContext::getArgName(size_t i) const
{ {
assert(i < this->eval_arguments.size()); assert(i < this->eval_arguments.size());
@ -31,6 +37,22 @@ ModuleInstantiation *EvalContext::getChild(size_t i) const
return this->scope ? this->scope->children[i] : NULL; return this->scope ? this->scope->children[i] : NULL;
} }
/*!
When instantiating a module which can take a scope as parameter (i.e. non-leaf nodes),
use this method to apply the local scope definitions to the evaluation context.
This will enable variables defined in local blocks.
NB! for loops are special as the local block may depend on variables evaluated by the
for loop parameters. The for loop code will handle this specially.
*/
void EvalContext::applyScope()
{
if (this->scope) {
BOOST_FOREACH(const Assignment &ass, this->scope->assignments) {
this->set_variable(ass.first, ass.second->evaluate(this));
}
}
}
#ifdef DEBUG #ifdef DEBUG
std::string EvalContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst) std::string EvalContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst)
{ {

View File

@ -12,8 +12,7 @@ public:
typedef std::vector<class ModuleInstantiation *> InstanceList; typedef std::vector<class ModuleInstantiation *> InstanceList;
EvalContext(const Context *parent, EvalContext(const Context *parent,
const AssignmentList &args, const class LocalScope *const scope = NULL) const AssignmentList &args, const class LocalScope *const scope = NULL);
: Context(parent), eval_arguments(args), scope(scope) {}
virtual ~EvalContext() {} virtual ~EvalContext() {}
size_t numArgs() const { return this->eval_arguments.size(); } size_t numArgs() const { return this->eval_arguments.size(); }
@ -23,6 +22,8 @@ public:
size_t numChildren() const; size_t numChildren() const;
ModuleInstantiation *getChild(size_t i) const; ModuleInstantiation *getChild(size_t i) const;
void applyScope();
#ifdef DEBUG #ifdef DEBUG
virtual std::string dump(const class AbstractModule *mod, const ModuleInstantiation *inst); virtual std::string dump(const class AbstractModule *mod, const ModuleInstantiation *inst);
#endif #endif

View File

@ -61,10 +61,10 @@ class ImportModule : public AbstractModule
public: public:
import_type_e type; import_type_e type;
ImportModule(import_type_e type = TYPE_UNKNOWN) : type(type) { } ImportModule(import_type_e type = TYPE_UNKNOWN) : type(type) { }
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const;
}; };
AbstractNode *ImportModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const AbstractNode *ImportModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const
{ {
AssignmentList args; AssignmentList args;
args += Assignment("file"), Assignment("layer"), Assignment("convexity"), Assignment("origin"), Assignment("scale"); args += Assignment("file"), Assignment("layer"), Assignment("convexity"), Assignment("origin"), Assignment("scale");

View File

@ -46,10 +46,10 @@ class LinearExtrudeModule : public AbstractModule
{ {
public: public:
LinearExtrudeModule() { } LinearExtrudeModule() { }
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const;
}; };
AbstractNode *LinearExtrudeModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const AbstractNode *LinearExtrudeModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const
{ {
LinearExtrudeNode *node = new LinearExtrudeNode(inst); LinearExtrudeNode *node = new LinearExtrudeNode(inst);
@ -58,6 +58,7 @@ AbstractNode *LinearExtrudeModule::instantiate(const Context *ctx, const ModuleI
Context c(ctx); Context c(ctx);
c.setVariables(args, evalctx); c.setVariables(args, evalctx);
evalctx->applyScope();
node->fn = c.lookup_variable("$fn").toDouble(); node->fn = c.lookup_variable("$fn").toDouble();
node->fs = c.lookup_variable("$fs").toDouble(); node->fs = c.lookup_variable("$fs").toDouble();

View File

@ -43,32 +43,14 @@ std::string LocalScope::dump(const std::string &indent) const
} }
// FIXME: Two parameters here is a hack. Rather have separate types of scopes, or check the type of the first parameter. Note const vs. non-const // FIXME: Two parameters here is a hack. Rather have separate types of scopes, or check the type of the first parameter. Note const vs. non-const
std::vector<AbstractNode*> LocalScope::instantiateChildren(const Context *evalctx, FileContext *filectx) const std::vector<AbstractNode*> LocalScope::instantiateChildren(const Context *evalctx) const
{ {
Context *c = filectx;
if (!c) {
c = new Context(evalctx);
// FIXME: If we make c a ModuleContext, child() doesn't work anymore
// c->functions_p = &this->functions;
// c->modules_p = &this->modules;
// Uncommenting the following would allow assignments in local scopes,
// but would cause duplicate evaluation of module scopes
// BOOST_FOREACH (const Assignment &ass, this->assignments) {
// c->set_variable(ass.first, ass.second->evaluate(c));
// }
}
std::vector<AbstractNode*> childnodes; std::vector<AbstractNode*> childnodes;
BOOST_FOREACH (ModuleInstantiation *modinst, this->children) { BOOST_FOREACH (ModuleInstantiation *modinst, this->children) {
AbstractNode *node = modinst->evaluate(c); AbstractNode *node = modinst->evaluate(evalctx);
if (node) childnodes.push_back(node); if (node) childnodes.push_back(node);
} }
if (c != filectx) delete c;
return childnodes; return childnodes;
} }

View File

@ -11,7 +11,7 @@ public:
size_t numElements() const { return assignments.size() + children.size(); } size_t numElements() const { return assignments.size() + children.size(); }
std::string dump(const std::string &indent) const; std::string dump(const std::string &indent) const;
std::vector<class AbstractNode*> instantiateChildren(const class Context *evalctx, class FileContext *filectx = NULL) const; std::vector<class AbstractNode*> instantiateChildren(const class Context *evalctx) const;
void addChild(ModuleInstantiation *ch); void addChild(ModuleInstantiation *ch);
AssignmentList assignments; AssignmentList assignments;

View File

@ -71,6 +71,7 @@ void ModuleContext::initializeModule(const class Module &module)
BOOST_FOREACH(const Assignment &ass, module.scope.assignments) { BOOST_FOREACH(const Assignment &ass, module.scope.assignments) {
this->set_variable(ass.first, ass.second->evaluate(this)); this->set_variable(ass.first, ass.second->evaluate(this));
} }
// Experimental code. See issue #399 // Experimental code. See issue #399
// evaluateAssignments(module.scope.assignments); // evaluateAssignments(module.scope.assignments);
} }
@ -130,7 +131,7 @@ Value ModuleContext::evaluate_function(const std::string &name, const EvalContex
return Context::evaluate_function(name, evalctx); return Context::evaluate_function(name, evalctx);
} }
AbstractNode *ModuleContext::instantiate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const AbstractNode *ModuleContext::instantiate_module(const ModuleInstantiation &inst, EvalContext *evalctx) const
{ {
const AbstractModule *foundm = this->findLocalModule(inst.name()); const AbstractModule *foundm = this->findLocalModule(inst.name());
if (foundm) return foundm->instantiate(this, &inst, evalctx); if (foundm) return foundm->instantiate(this, &inst, evalctx);
@ -207,7 +208,7 @@ Value FileContext::evaluate_function(const std::string &name, const EvalContext
return ModuleContext::evaluate_function(name, evalctx); return ModuleContext::evaluate_function(name, evalctx);
} }
AbstractNode *FileContext::instantiate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const AbstractNode *FileContext::instantiate_module(const ModuleInstantiation &inst, EvalContext *evalctx) const
{ {
const AbstractModule *foundm = this->findLocalModule(inst.name()); const AbstractModule *foundm = this->findLocalModule(inst.name());
if (foundm) return foundm->instantiate(this, &inst, evalctx); if (foundm) return foundm->instantiate(this, &inst, evalctx);

View File

@ -21,7 +21,7 @@ public:
virtual Value evaluate_function(const std::string &name, virtual Value evaluate_function(const std::string &name,
const EvalContext *evalctx) const; const EvalContext *evalctx) const;
virtual AbstractNode *instantiate_module(const ModuleInstantiation &inst, virtual AbstractNode *instantiate_module(const ModuleInstantiation &inst,
const EvalContext *evalctx) const; EvalContext *evalctx) const;
const AbstractModule *findLocalModule(const std::string &name) const; const AbstractModule *findLocalModule(const std::string &name) const;
const AbstractFunction *findLocalFunction(const std::string &name) const; const AbstractFunction *findLocalFunction(const std::string &name) const;
@ -47,7 +47,7 @@ public:
virtual ~FileContext() {} virtual ~FileContext() {}
virtual Value evaluate_function(const std::string &name, const EvalContext *evalctx) const; virtual Value evaluate_function(const std::string &name, const EvalContext *evalctx) const;
virtual AbstractNode *instantiate_module(const ModuleInstantiation &inst, virtual AbstractNode *instantiate_module(const ModuleInstantiation &inst,
const EvalContext *evalctx) const; EvalContext *evalctx) const;
private: private:
const FileModule::ModuleContainer &usedlibs; const FileModule::ModuleContainer &usedlibs;

View File

@ -46,7 +46,7 @@ AbstractModule::~AbstractModule()
{ {
} }
AbstractNode *AbstractModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const AbstractNode *AbstractModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const
{ {
(void)ctx; // avoid unusued parameter warning (void)ctx; // avoid unusued parameter warning
@ -185,7 +185,7 @@ private:
const ModuleInstantiation &inst; const ModuleInstantiation &inst;
}; };
AbstractNode *Module::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const AbstractNode *Module::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const
{ {
ModRecursionGuard g(*inst); ModRecursionGuard g(*inst);
if (g.recursion_detected()) { if (g.recursion_detected()) {
@ -193,6 +193,10 @@ AbstractNode *Module::instantiate(const Context *ctx, const ModuleInstantiation
return NULL; return NULL;
} }
// At this point we know that nobody will modify the dependencies of the local scope
// passed to this instance, so we can populate the context
evalctx->applyScope();
ModuleContext c(ctx, evalctx); ModuleContext c(ctx, evalctx);
// set $children first since we might have variables depending on it // set $children first since we might have variables depending on it
c.set_variable("$children", Value(double(inst->scope.children.size()))); c.set_variable("$children", Value(double(inst->scope.children.size())));
@ -342,7 +346,7 @@ bool FileModule::handleDependencies()
return somethingchanged; return somethingchanged;
} }
AbstractNode *FileModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const AbstractNode *FileModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const
{ {
assert(evalctx == NULL); assert(evalctx == NULL);
FileContext c(*this, ctx); FileContext c(*this, ctx);
@ -353,7 +357,7 @@ AbstractNode *FileModule::instantiate(const Context *ctx, const ModuleInstantiat
#endif #endif
AbstractNode *node = new AbstractNode(inst); AbstractNode *node = new AbstractNode(inst);
std::vector<AbstractNode *> instantiatednodes = this->scope.instantiateChildren(ctx, &c); std::vector<AbstractNode *> instantiatednodes = this->scope.instantiateChildren(&c);
node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end()); node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
return node; return node;

View File

@ -68,7 +68,7 @@ public:
virtual ~AbstractModule(); virtual ~AbstractModule();
virtual bool is_experimental() const { return feature != NULL; } virtual bool is_experimental() const { return feature != NULL; }
virtual bool is_enabled() const { return (feature == NULL) || feature->is_enabled(); } virtual bool is_enabled() const { return (feature == NULL) || feature->is_enabled(); }
virtual class AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const class EvalContext *evalctx = NULL) const; virtual class AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, class EvalContext *evalctx = NULL) const;
virtual std::string dump(const std::string &indent, const std::string &name) const; virtual std::string dump(const std::string &indent, const std::string &name) const;
virtual double lookup_double_variable_with_default(Context &c, std::string variable, double def) const; virtual double lookup_double_variable_with_default(Context &c, std::string variable, double def) const;
virtual std::string lookup_string_variable_with_default(Context &c, std::string variable, std::string def) const; virtual std::string lookup_string_variable_with_default(Context &c, std::string variable, std::string def) const;
@ -81,7 +81,7 @@ public:
Module(const Feature& feature) : AbstractModule(feature) { } Module(const Feature& feature) : AbstractModule(feature) { }
virtual ~Module(); virtual ~Module();
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx = NULL) const; virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx = NULL) const;
virtual std::string dump(const std::string &indent, const std::string &name) const; virtual std::string dump(const std::string &indent, const std::string &name) const;
static const std::string& stack_element(int n) { return module_stack[n]; }; static const std::string& stack_element(int n) { return module_stack[n]; };
static int stack_size() { return module_stack.size(); }; static int stack_size() { return module_stack.size(); };
@ -108,7 +108,7 @@ public:
void registerInclude(const std::string &localpath, const std::string &fullpath); void registerInclude(const std::string &localpath, const std::string &fullpath);
bool includesChanged() const; bool includesChanged() const;
bool handleDependencies(); bool handleDependencies();
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx = NULL) const; virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx = NULL) const;
bool hasIncludes() const { return !this->includes.empty(); } bool hasIncludes() const { return !this->includes.empty(); }
bool usesLibraries() const { return !this->usedlibs.empty(); } bool usesLibraries() const { return !this->usedlibs.empty(); }
bool isHandlingDependencies() const { return this->is_handling_dependencies; } bool isHandlingDependencies() const { return this->is_handling_dependencies; }

View File

@ -46,10 +46,10 @@ class OffsetModule : public AbstractModule
{ {
public: public:
OffsetModule() { } OffsetModule() { }
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const;
}; };
AbstractNode *OffsetModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const AbstractNode *OffsetModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const
{ {
OffsetNode *node = new OffsetNode(inst); OffsetNode *node = new OffsetNode(inst);
@ -58,6 +58,7 @@ AbstractNode *OffsetModule::instantiate(const Context *ctx, const ModuleInstanti
Context c(ctx); Context c(ctx);
c.setVariables(args, evalctx); c.setVariables(args, evalctx);
evalctx->applyScope();
node->fn = c.lookup_variable("$fn").toDouble(); node->fn = c.lookup_variable("$fn").toDouble();
node->fs = c.lookup_variable("$fs").toDouble(); node->fs = c.lookup_variable("$fs").toDouble();

View File

@ -270,6 +270,7 @@ if_statement:
child_statements: child_statements:
/* empty */ /* empty */
| child_statements child_statement | child_statements child_statement
| child_statements assignment
; ;
child_statement: child_statement:
@ -281,13 +282,6 @@ child_statement:
} }
; ;
/*
FIXME: This allows for variable declaration in child blocks, not activated yet
|
assignment ;
*/
// "for" is a valid module identifier // "for" is a valid module identifier
module_id: module_id:
TOK_ID { $$ = $1; } TOK_ID { $$ = $1; }

View File

@ -61,7 +61,7 @@ class PrimitiveModule : public AbstractModule
public: public:
primitive_type_e type; primitive_type_e type;
PrimitiveModule(primitive_type_e type) : type(type) { } PrimitiveModule(primitive_type_e type) : type(type) { }
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const;
private: private:
Value lookup_radius(const Context &ctx, const std::string &radius_var, const std::string &diameter_var) const; Value lookup_radius(const Context &ctx, const std::string &radius_var, const std::string &diameter_var) const;
}; };
@ -141,7 +141,7 @@ Value PrimitiveModule::lookup_radius(const Context &ctx, const std::string &diam
} }
} }
AbstractNode *PrimitiveModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const AbstractNode *PrimitiveModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const
{ {
PrimitiveNode *node = new PrimitiveNode(inst, this->type); PrimitiveNode *node = new PrimitiveNode(inst, this->type);

View File

@ -41,10 +41,10 @@ class ProjectionModule : public AbstractModule
{ {
public: public:
ProjectionModule() { } ProjectionModule() { }
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const;
}; };
AbstractNode *ProjectionModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const AbstractNode *ProjectionModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const
{ {
ProjectionNode *node = new ProjectionNode(inst); ProjectionNode *node = new ProjectionNode(inst);
@ -53,6 +53,7 @@ AbstractNode *ProjectionModule::instantiate(const Context *ctx, const ModuleInst
Context c(ctx); Context c(ctx);
c.setVariables(args, evalctx); c.setVariables(args, evalctx);
evalctx->applyScope();
Value convexity = c.lookup_variable("convexity", true); Value convexity = c.lookup_variable("convexity", true);
Value cut = c.lookup_variable("cut", true); Value cut = c.lookup_variable("cut", true);

View File

@ -38,10 +38,10 @@ class RenderModule : public AbstractModule
{ {
public: public:
RenderModule() { } RenderModule() { }
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const;
}; };
AbstractNode *RenderModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const AbstractNode *RenderModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const
{ {
RenderNode *node = new RenderNode(inst); RenderNode *node = new RenderNode(inst);
@ -50,6 +50,7 @@ AbstractNode *RenderModule::instantiate(const Context *ctx, const ModuleInstanti
Context c(ctx); Context c(ctx);
c.setVariables(args, evalctx); c.setVariables(args, evalctx);
evalctx->applyScope();
Value v = c.lookup_variable("convexity"); Value v = c.lookup_variable("convexity");
if (v.type() == Value::NUMBER) if (v.type() == Value::NUMBER)

View File

@ -44,10 +44,10 @@ class RotateExtrudeModule : public AbstractModule
{ {
public: public:
RotateExtrudeModule() { } RotateExtrudeModule() { }
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const;
}; };
AbstractNode *RotateExtrudeModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const AbstractNode *RotateExtrudeModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const
{ {
RotateExtrudeNode *node = new RotateExtrudeNode(inst); RotateExtrudeNode *node = new RotateExtrudeNode(inst);
@ -56,6 +56,7 @@ AbstractNode *RotateExtrudeModule::instantiate(const Context *ctx, const ModuleI
Context c(ctx); Context c(ctx);
c.setVariables(args, evalctx); c.setVariables(args, evalctx);
evalctx->applyScope();
node->fn = c.lookup_variable("$fn").toDouble(); node->fn = c.lookup_variable("$fn").toDouble();
node->fs = c.lookup_variable("$fs").toDouble(); node->fs = c.lookup_variable("$fs").toDouble();

View File

@ -52,7 +52,7 @@ class SurfaceModule : public AbstractModule
{ {
public: public:
SurfaceModule() { } SurfaceModule() { }
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const;
}; };
typedef boost::unordered_map<std::pair<int,int>,double> img_data_t; typedef boost::unordered_map<std::pair<int,int>,double> img_data_t;
@ -80,7 +80,7 @@ private:
img_data_t read_png_or_dat(std::string filename) const; img_data_t read_png_or_dat(std::string filename) const;
}; };
AbstractNode *SurfaceModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const AbstractNode *SurfaceModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const
{ {
SurfaceNode *node = new SurfaceNode(inst); SurfaceNode *node = new SurfaceNode(inst);
node->center = false; node->center = false;

View File

@ -41,10 +41,10 @@ class TextModule : public AbstractModule
{ {
public: public:
TextModule() : AbstractModule(Feature::ExperimentalTextModule) { } TextModule() : AbstractModule(Feature::ExperimentalTextModule) { }
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const;
}; };
AbstractNode *TextModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const AbstractNode *TextModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const
{ {
TextNode *node = new TextNode(inst); TextNode *node = new TextNode(inst);

View File

@ -50,10 +50,10 @@ class TransformModule : public AbstractModule
public: public:
transform_type_e type; transform_type_e type;
TransformModule(transform_type_e type) : type(type) { } TransformModule(transform_type_e type) : type(type) { }
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const;
}; };
AbstractNode *TransformModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const AbstractNode *TransformModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, EvalContext *evalctx) const
{ {
TransformNode *node = new TransformNode(inst); TransformNode *node = new TransformNode(inst);
@ -83,6 +83,7 @@ AbstractNode *TransformModule::instantiate(const Context *ctx, const ModuleInsta
Context c(ctx); Context c(ctx);
c.setVariables(args, evalctx); c.setVariables(args, evalctx);
evalctx->applyScope();
if (this->type == SCALE) if (this->type == SCALE)
{ {

View File

@ -0,0 +1,65 @@
echo("union scope");
a = 4;
union() {
a = 5;
echo("local a (5):", a);
}
echo("global a (4):", a);
echo("module scope:");
module mymodule(b=6) {
b = 7;
echo("local b (7)", b);
}
mymodule();
mymodule(8);
echo("module children scope:");
module mymodule2(b2=6) {
b2 = 2;
children(0);
}
mymodule2(b2=7) {
b2 = 3;
echo("b2 (3)", b2);
}
echo("for loop (c = 0,1,25):");
for (i=[0:2]) {
c = (i > 1) ? i + 23 : i;
echo("c", c);
}
echo("anonymous inner scope (scope ignored):");
union() {
e = 2;
echo("outer e (3)", e);
{
e = 3;
echo("inner e (3)", e);
}
}
echo("anonymous scope (scope ignored):");
f=1;
echo("outer f (2)", f);
{
f=2;
echo("inner f (2)", f);
}
echo("anonymous scope reassign:");
{
g=1;
echo("g (2)", g);
g=2;
}
echo("anonymous reassign using outer (scope ignored)", h);
h=5;
{
h=h*2; // Not allowed
echo("h (undef)", h);
}

View File

@ -1046,6 +1046,7 @@ list(APPEND ECHO_FILES ${FUNCTION_FILES}
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/value-reassignment-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/value-reassignment-tests.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/value-reassignment-tests2.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/value-reassignment-tests2.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/variable-scope-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/variable-scope-tests.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/scope-assignment-tests.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/lookup-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/lookup-tests.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/expression-shortcircuit-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/expression-shortcircuit-tests.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/parent_module-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/parent_module-tests.scad

View File

@ -0,0 +1,23 @@
WARNING: Ignoring unknown variable 'h'.
ECHO: "union scope"
ECHO: "local a (5):", 5
ECHO: "global a (4):", 4
ECHO: "module scope:"
ECHO: "local b (7)", 7
ECHO: "local b (7)", 7
ECHO: "module children scope:"
ECHO: "b2 (3)", 3
ECHO: "for loop (c = 0,1,25):"
ECHO: "c", 0
ECHO: "c", 1
ECHO: "c", 25
ECHO: "anonymous inner scope (scope ignored):"
ECHO: "outer e (3)", 3
ECHO: "inner e (3)", 3
ECHO: "anonymous scope (scope ignored):"
ECHO: "outer f (2)", 2
ECHO: "inner f (2)", 2
ECHO: "anonymous scope reassign:"
ECHO: "g (2)", 2
ECHO: "anonymous reassign using outer (scope ignored)", undef
ECHO: "h (undef)", undef