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:
cgaladv_type_e 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);
@ -62,6 +62,7 @@ AbstractNode *CgaladvModule::instantiate(const Context *ctx, const ModuleInstant
Context c(ctx);
c.setVariables(args, evalctx);
evalctx->applyScope();
Value convexity, path, subdiv_type, level;

View File

@ -42,7 +42,7 @@ class ColorModule : public AbstractModule
public:
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:
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);
@ -218,6 +218,7 @@ AbstractNode *ColorModule::instantiate(const Context *ctx, const ModuleInstantia
Context c(ctx);
c.setVariables(args, evalctx);
evalctx->applyScope();
Value v = c.lookup_variable("c");
if (v.type() == Value::VECTOR) {

View File

@ -152,7 +152,7 @@ Value Context::evaluate_function(const std::string &name, const EvalContext *eva
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);
PRINTB("WARNING: Ignoring unknown module '%s'.", inst.name());

View File

@ -15,7 +15,7 @@ public:
const Context *getParent() const { return this->parent; }
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,
const class EvalContext *evalctx = NULL);

View File

@ -29,6 +29,7 @@
#include "node.h"
#include "evalcontext.h"
#include "modcontext.h"
#include "expression.h"
#include "builtin.h"
#include "printutils.h"
#include <sstream>
@ -55,7 +56,7 @@ public: // methods
: 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,
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);
}
} 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());
}
}
@ -155,12 +163,16 @@ AbstractNode* ControlModule::getChild(const Value& value, const EvalContext* mod
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;
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.");
int n = 0;
if (evalctx->numArgs() > 0) {
@ -192,9 +204,9 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns
}
return node;
}
break;
if (type == CHILDREN)
{
case CHILDREN: {
const EvalContext *modulectx = getLastModuleCtx(evalctx);
if (modulectx==NULL) {
return NULL;
@ -251,14 +263,10 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns
}
return NULL;
}
break;
if (type == INT_FOR)
node = new AbstractIntersectionNode(inst);
else
case ECHO: {
node = new AbstractNode(inst);
if (type == ECHO)
{
std::stringstream msg;
msg << "ECHO: ";
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());
}
break;
if (type == ASSIGN)
{
case ASSIGN: {
node = new AbstractNode(inst);
Context c(evalctx);
for (size_t i = 0; i < evalctx->numArgs(); i++) {
if (!evalctx->getArgName(i).empty())
@ -284,14 +293,20 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns
std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(&c);
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);
}
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);
if (evalctx->numArgs() > 0 && evalctx->getArgValue(0).toBool()) {
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());
}
}
break;
}
return node;
}

View File

@ -38,11 +38,12 @@ class CsgModule : public AbstractModule
public:
OpenSCADOperator 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);
std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());

View File

@ -8,6 +8,12 @@
#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
{
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;
}
/*!
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
std::string EvalContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst)
{

View File

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

View File

@ -61,10 +61,10 @@ class ImportModule : public AbstractModule
public:
import_type_e 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;
args += Assignment("file"), Assignment("layer"), Assignment("convexity"), Assignment("origin"), Assignment("scale");

View File

@ -46,10 +46,10 @@ class LinearExtrudeModule : public AbstractModule
{
public:
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);
@ -58,6 +58,7 @@ AbstractNode *LinearExtrudeModule::instantiate(const Context *ctx, const ModuleI
Context c(ctx);
c.setVariables(args, evalctx);
evalctx->applyScope();
node->fn = c.lookup_variable("$fn").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
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;
BOOST_FOREACH (ModuleInstantiation *modinst, this->children) {
AbstractNode *node = modinst->evaluate(c);
AbstractNode *node = modinst->evaluate(evalctx);
if (node) childnodes.push_back(node);
}
if (c != filectx) delete c;
return childnodes;
}

View File

@ -11,7 +11,7 @@ public:
size_t numElements() const { return assignments.size() + children.size(); }
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);
AssignmentList assignments;

View File

@ -71,6 +71,7 @@ void ModuleContext::initializeModule(const class Module &module)
BOOST_FOREACH(const Assignment &ass, module.scope.assignments) {
this->set_variable(ass.first, ass.second->evaluate(this));
}
// Experimental code. See issue #399
// evaluateAssignments(module.scope.assignments);
}
@ -130,7 +131,7 @@ Value ModuleContext::evaluate_function(const std::string &name, const EvalContex
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());
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);
}
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());
if (foundm) return foundm->instantiate(this, &inst, evalctx);

View File

@ -21,7 +21,7 @@ public:
virtual Value evaluate_function(const std::string &name,
const EvalContext *evalctx) const;
virtual AbstractNode *instantiate_module(const ModuleInstantiation &inst,
const EvalContext *evalctx) const;
EvalContext *evalctx) const;
const AbstractModule *findLocalModule(const std::string &name) const;
const AbstractFunction *findLocalFunction(const std::string &name) const;
@ -47,7 +47,7 @@ public:
virtual ~FileContext() {}
virtual Value evaluate_function(const std::string &name, const EvalContext *evalctx) const;
virtual AbstractNode *instantiate_module(const ModuleInstantiation &inst,
const EvalContext *evalctx) const;
EvalContext *evalctx) const;
private:
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
@ -185,7 +185,7 @@ private:
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);
if (g.recursion_detected()) {
@ -193,6 +193,10 @@ AbstractNode *Module::instantiate(const Context *ctx, const ModuleInstantiation
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);
// set $children first since we might have variables depending on it
c.set_variable("$children", Value(double(inst->scope.children.size())));
@ -342,7 +346,7 @@ bool FileModule::handleDependencies()
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);
FileContext c(*this, ctx);
@ -353,7 +357,7 @@ AbstractNode *FileModule::instantiate(const Context *ctx, const ModuleInstantiat
#endif
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());
return node;

View File

@ -68,7 +68,7 @@ public:
virtual ~AbstractModule();
virtual bool is_experimental() const { return feature != NULL; }
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 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;
@ -81,7 +81,7 @@ public:
Module(const Feature& feature) : AbstractModule(feature) { }
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;
static const std::string& stack_element(int n) { return module_stack[n]; };
static int stack_size() { return module_stack.size(); };
@ -108,7 +108,7 @@ public:
void registerInclude(const std::string &localpath, const std::string &fullpath);
bool includesChanged() const;
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 usesLibraries() const { return !this->usedlibs.empty(); }
bool isHandlingDependencies() const { return this->is_handling_dependencies; }

View File

@ -46,10 +46,10 @@ class OffsetModule : public AbstractModule
{
public:
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);
@ -58,6 +58,7 @@ AbstractNode *OffsetModule::instantiate(const Context *ctx, const ModuleInstanti
Context c(ctx);
c.setVariables(args, evalctx);
evalctx->applyScope();
node->fn = c.lookup_variable("$fn").toDouble();
node->fs = c.lookup_variable("$fs").toDouble();

View File

@ -270,6 +270,7 @@ if_statement:
child_statements:
/* empty */
| child_statements child_statement
| child_statements assignment
;
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
module_id:
TOK_ID { $$ = $1; }

View File

@ -61,7 +61,7 @@ class PrimitiveModule : public AbstractModule
public:
primitive_type_e 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:
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);

View File

@ -41,10 +41,10 @@ class ProjectionModule : public AbstractModule
{
public:
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);
@ -53,6 +53,7 @@ AbstractNode *ProjectionModule::instantiate(const Context *ctx, const ModuleInst
Context c(ctx);
c.setVariables(args, evalctx);
evalctx->applyScope();
Value convexity = c.lookup_variable("convexity", true);
Value cut = c.lookup_variable("cut", true);

View File

@ -38,10 +38,10 @@ class RenderModule : public AbstractModule
{
public:
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);
@ -50,6 +50,7 @@ AbstractNode *RenderModule::instantiate(const Context *ctx, const ModuleInstanti
Context c(ctx);
c.setVariables(args, evalctx);
evalctx->applyScope();
Value v = c.lookup_variable("convexity");
if (v.type() == Value::NUMBER)

View File

@ -44,10 +44,10 @@ class RotateExtrudeModule : public AbstractModule
{
public:
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);
@ -56,6 +56,7 @@ AbstractNode *RotateExtrudeModule::instantiate(const Context *ctx, const ModuleI
Context c(ctx);
c.setVariables(args, evalctx);
evalctx->applyScope();
node->fn = c.lookup_variable("$fn").toDouble();
node->fs = c.lookup_variable("$fs").toDouble();

View File

@ -52,7 +52,7 @@ class SurfaceModule : public AbstractModule
{
public:
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;
@ -80,7 +80,7 @@ private:
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);
node->center = false;

View File

@ -41,10 +41,10 @@ class TextModule : public AbstractModule
{
public:
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);

View File

@ -50,10 +50,10 @@ class TransformModule : public AbstractModule
public:
transform_type_e 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);
@ -83,6 +83,7 @@ AbstractNode *TransformModule::instantiate(const Context *ctx, const ModuleInsta
Context c(ctx);
c.setVariables(args, evalctx);
evalctx->applyScope();
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-tests2.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/expression-shortcircuit-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