summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bison.pri2
-rw-r--r--flex.pri2
-rw-r--r--openscad.pro11
-rw-r--r--src/MainWindow.h4
-rw-r--r--src/ModuleCache.cc10
-rw-r--r--src/ModuleCache.h7
-rw-r--r--src/builtin.cc22
-rw-r--r--src/builtin.h10
-rw-r--r--src/cgaladv.cc8
-rw-r--r--src/color.cc8
-rw-r--r--src/context.cc10
-rw-r--r--src/context.h4
-rw-r--r--src/control.cc48
-rw-r--r--src/csgops.cc8
-rw-r--r--src/dxfdim.cc40
-rw-r--r--src/evalcontext.cc28
-rw-r--r--src/evalcontext.h19
-rw-r--r--src/expr.cc26
-rw-r--r--src/expression.h2
-rw-r--r--src/func.cc154
-rw-r--r--src/import.cc17
-rw-r--r--src/lexer.l4
-rw-r--r--src/linearextrude.cc16
-rw-r--r--src/localscope.cc73
-rw-r--r--src/localscope.h26
-rw-r--r--src/mainwin.cc16
-rw-r--r--src/modcontext.cc177
-rw-r--r--src/modcontext.h34
-rw-r--r--src/module.cc105
-rw-r--r--src/module.h60
-rw-r--r--src/openscad.cc18
-rw-r--r--src/openscad.h2
-rw-r--r--src/parser.y238
-rw-r--r--src/primitives.cc6
-rw-r--r--src/projection.cc8
-rw-r--r--src/render.cc8
-rw-r--r--src/rotateextrude.cc8
-rw-r--r--src/surface.cc4
-rw-r--r--src/transform.cc8
-rw-r--r--src/typedefs.h1
-rw-r--r--testdata/scad/features/child-tests.scad7
-rw-r--r--testdata/scad/misc/localfiles_dir/localfiles_module.scad3
-rw-r--r--testdata/scad/misc/variable-scope-sub.scad24
-rw-r--r--testdata/scad/misc/variable-scope-tests.scad53
-rw-r--r--tests/CMakeLists.txt13
-rw-r--r--tests/cgalcachetest.cc8
-rw-r--r--tests/cgalpngtest.cc8
-rw-r--r--tests/cgalstlsanitytest.cc8
-rw-r--r--tests/cgaltest.cc8
-rw-r--r--tests/csgtermtest.cc8
-rw-r--r--tests/csgtestcore.cc8
-rw-r--r--tests/csgtexttest.cc8
-rw-r--r--tests/dumptest.cc18
-rw-r--r--tests/echotest.cc8
-rw-r--r--tests/modulecachetest.cc11
-rw-r--r--tests/regression/cgalpngtest/child-tests-expected.pngbin13034 -> 13394 bytes
-rw-r--r--tests/regression/cgalpngtest/localfiles-test-expected.pngbin8454 -> 11732 bytes
-rw-r--r--tests/regression/dumptest/child-tests-expected.txt12
-rw-r--r--tests/regression/dumptest/localfiles-test-expected.txt3
-rw-r--r--tests/regression/echotest/variable-scope-tests-expected.txt16
-rw-r--r--tests/regression/opencsgtest/child-tests-expected.pngbin13600 -> 14187 bytes
-rw-r--r--tests/regression/opencsgtest/localfiles-test-expected.pngbin8844 -> 12657 bytes
-rw-r--r--tests/regression/throwntogethertest/child-tests-expected.pngbin9234 -> 14187 bytes
-rw-r--r--tests/regression/throwntogethertest/localfiles-test-expected.pngbin8844 -> 12657 bytes
-rw-r--r--tests/tests-common.cc4
-rw-r--r--tests/tests-common.h2
66 files changed, 845 insertions, 637 deletions
diff --git a/bison.pri b/bison.pri
index 7a63f0e..d2972d6 100644
--- a/bison.pri
+++ b/bison.pri
@@ -1,4 +1,4 @@
-win32 {
+{
bison.name = Bison ${QMAKE_FILE_IN}
bison.input = BISONSOURCES
bison.output = ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}_yacc.cpp
diff --git a/flex.pri b/flex.pri
index 203d90d..0813300 100644
--- a/flex.pri
+++ b/flex.pri
@@ -1,4 +1,4 @@
-win32 {
+{
flex.name = Flex ${QMAKE_FILE_IN}
flex.input = FLEXSOURCES
flex.output = ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.lexer.cpp
diff --git a/openscad.pro b/openscad.pro
index 0f3394e..81f5e6f 100644
--- a/openscad.pro
+++ b/openscad.pro
@@ -171,13 +171,8 @@ CONFIG(mingw-cross-env) {
include(mingw-cross-env.pri)
}
-win32 {
- FLEXSOURCES = src/lexer.l
- BISONSOURCES = src/parser.y
-} else {
- LEXSOURCES += src/lexer.l
- YACCSOURCES += src/parser.y
-}
+FLEXSOURCES = src/lexer.l
+BISONSOURCES = src/parser.y
RESOURCES = openscad.qrc
@@ -216,6 +211,7 @@ HEADERS += src/typedefs.h \
src/function.h \
src/grid.h \
src/highlighter.h \
+ src/localscope.h \
src/module.h \
src/node.h \
src/csgnode.h \
@@ -272,6 +268,7 @@ SOURCES += src/version_check.cc \
src/value.cc \
src/expr.cc \
src/func.cc \
+ src/localscope.cc \
src/module.cc \
src/node.cc \
src/context.cc \
diff --git a/src/MainWindow.h b/src/MainWindow.h
index 65deb15..378705e 100644
--- a/src/MainWindow.h
+++ b/src/MainWindow.h
@@ -29,8 +29,8 @@ public:
QTimer *autoReloadTimer;
std::string autoReloadId;
- ModuleContext root_ctx;
- Module *root_module; // Result of parsing
+ ModuleContext top_ctx;
+ FileModule *root_module; // Result of parsing
ModuleInstantiation root_inst; // Top level instance
AbstractNode *absolute_root_node; // Result of tree evaluation
AbstractNode *root_node; // Root if the root modifier (!) is used
diff --git a/src/ModuleCache.cc b/src/ModuleCache.cc
index 19a3f84..4944495 100644
--- a/src/ModuleCache.cc
+++ b/src/ModuleCache.cc
@@ -28,9 +28,9 @@ static bool is_modified(const std::string &filename, const time_t &mtime)
return (st.st_mtime > mtime);
}
-Module *ModuleCache::evaluate(const std::string &filename)
+FileModule *ModuleCache::evaluate(const std::string &filename)
{
- Module *lib_mod = NULL;
+ FileModule *lib_mod = NULL;
// Create cache ID
struct stat st;
@@ -48,7 +48,7 @@ Module *ModuleCache::evaluate(const std::string &filename)
#endif
lib_mod = &(*this->entries[filename].module);
- BOOST_FOREACH(const Module::IncludeContainer::value_type &item, lib_mod->includes) {
+ BOOST_FOREACH(const FileModule::IncludeContainer::value_type &item, lib_mod->includes) {
if (is_modified(item.first, item.second)) {
lib_mod = NULL;
break;
@@ -78,7 +78,7 @@ Module *ModuleCache::evaluate(const std::string &filename)
print_messages_push();
- Module *oldmodule = NULL;
+ FileModule *oldmodule = NULL;
cache_entry e = { NULL, cache_id };
if (this->entries.find(filename) != this->entries.end()) {
oldmodule = this->entries[filename].module;
@@ -86,7 +86,7 @@ Module *ModuleCache::evaluate(const std::string &filename)
this->entries[filename] = e;
std::string pathname = boosty::stringy(fs::path(filename).parent_path());
- lib_mod = dynamic_cast<Module*>(parse(textbuf.str().c_str(), pathname.c_str(), false));
+ lib_mod = dynamic_cast<FileModule*>(parse(textbuf.str().c_str(), pathname.c_str(), false));
PRINTB_NOCACHE(" compiled module: %p", lib_mod);
if (lib_mod) {
diff --git a/src/ModuleCache.h b/src/ModuleCache.h
index 1e6373d..b8ded38 100644
--- a/src/ModuleCache.h
+++ b/src/ModuleCache.h
@@ -1,11 +1,14 @@
#include <string>
#include <boost/unordered_map.hpp>
+/*!
+ Caches FileModules based on their filenames
+*/
class ModuleCache
{
public:
static ModuleCache *instance() { if (!inst) inst = new ModuleCache; return inst; }
- class Module *evaluate(const std::string &filename);
+ class FileModule *evaluate(const std::string &filename);
size_t size() { return this->entries.size(); }
void clear();
@@ -16,7 +19,7 @@ private:
static ModuleCache *inst;
struct cache_entry {
- class Module *module;
+ class FileModule *module;
std::string cache_id;
};
boost::unordered_map<std::string, cache_entry> entries;
diff --git a/src/builtin.cc b/src/builtin.cc
index bdd2d3b..e116f17 100644
--- a/src/builtin.cc
+++ b/src/builtin.cc
@@ -16,12 +16,12 @@ Builtins *Builtins::instance(bool erase)
void Builtins::init(const char *name, class AbstractModule *module)
{
- Builtins::instance()->rootmodule.modules[name] = module;
+ Builtins::instance()->globalscope.modules[name] = module;
}
void Builtins::init(const char *name, class AbstractFunction *function)
{
- Builtins::instance()->rootmodule.functions[name] = function;
+ Builtins::instance()->globalscope.functions[name] = function;
}
extern void register_builtin_functions();
@@ -80,24 +80,18 @@ std::string Builtins::isDeprecated(const std::string &name)
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));
+ this->globalscope.assignments.push_back(Assignment("$fn", new Expression(Value(0.0))));
+ this->globalscope.assignments.push_back(Assignment("$fs", new Expression(Value(2.0))));
+ this->globalscope.assignments.push_back(Assignment("$fa", new Expression(Value(12.0))));
+ this->globalscope.assignments.push_back(Assignment("$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);
+ this->globalscope.assignments.push_back(Assignment("$vpt", new Expression(zero3val)));
+ this->globalscope.assignments.push_back(Assignment("$vpr", new Expression(zero3val)));
}
Builtins::~Builtins()
diff --git a/src/builtin.h b/src/builtin.h
index 564c951..9397aa9 100644
--- a/src/builtin.h
+++ b/src/builtin.h
@@ -4,6 +4,7 @@
#include <string>
#include <boost/unordered_map.hpp>
#include "module.h"
+#include "localscope.h"
class Builtins
{
@@ -17,18 +18,13 @@ public:
void initialize();
std::string isDeprecated(const std::string &name);
- const FunctionContainer &functions() { return this->builtinfunctions; }
- const ModuleContainer &modules() { return this->builtinmodules; }
-
- const Module &getRootModule() { return this->rootmodule; }
+ const LocalScope &getGlobalScope() { return this->globalscope; }
private:
Builtins();
~Builtins();
- Module rootmodule;
- FunctionContainer builtinfunctions;
- ModuleContainer builtinmodules;
+ LocalScope globalscope;
boost::unordered_map<std::string, std::string> deprecations;
};
diff --git a/src/cgaladv.cc b/src/cgaladv.cc
index aad3a95..70590f7 100644
--- a/src/cgaladv.cc
+++ b/src/cgaladv.cc
@@ -39,10 +39,10 @@ class CgaladvModule : public AbstractModule
public:
cgaladv_type_e type;
CgaladvModule(cgaladv_type_e type) : type(type) { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+AbstractNode *CgaladvModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
CgaladvNode *node = new CgaladvNode(inst, type);
@@ -110,8 +110,8 @@ AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiat
if (node->level <= 1)
node->level = 1;
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
return node;
}
diff --git a/src/color.cc b/src/color.cc
index 6c3aaef..7fef030 100644
--- a/src/color.cc
+++ b/src/color.cc
@@ -40,14 +40,14 @@ class ColorModule : public AbstractModule
{
public:
ColorModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
+ virtual AbstractNode *instantiate(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 EvalContext *evalctx) const
+AbstractNode *ColorModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
ColorNode *node = new ColorNode(inst);
@@ -87,8 +87,8 @@ AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiatio
node->color[3] = alpha.toDouble();
}
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
return node;
}
diff --git a/src/context.cc b/src/context.cc
index 706407c..a7273a4 100644
--- a/src/context.cc
+++ b/src/context.cc
@@ -66,9 +66,9 @@ void Context::setVariables(const AssignmentList &args,
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;
+ for (size_t i=0; i<evalctx->numArgs(); i++) {
+ const std::string &name = evalctx->getArgName(i);
+ const Value &val = evalctx->getArgValue(i);
if (name.empty()) {
if (posarg < args.size()) this->set_variable(args[posarg++].first, val);
} else {
@@ -124,9 +124,9 @@ Value Context::evaluate_function(const std::string &name, const EvalContext *eva
return Value();
}
-AbstractNode *Context::evaluate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const
+AbstractNode *Context::instantiate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const
{
- if (this->parent) return this->parent->evaluate_module(inst, evalctx);
+ if (this->parent) return this->parent->instantiate_module(inst, evalctx);
PRINTB("WARNING: Ignoring unknown module '%s'.", inst.name());
return NULL;
}
diff --git a/src/context.h b/src/context.h
index 51fc45c..9817df3 100644
--- a/src/context.h
+++ b/src/context.h
@@ -14,7 +14,7 @@ public:
virtual ~Context();
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;
+ virtual class AbstractNode *instantiate_module(const class ModuleInstantiation &inst, const EvalContext *evalctx) const;
void setVariables(const AssignmentList &args,
const class EvalContext *evalctx = NULL);
@@ -39,7 +39,7 @@ protected:
ValueMap variables;
ValueMap config_variables;
- std::string document_path;
+ std::string document_path; // FIXME: This is a remnant only needed by dxfdim
#ifdef DEBUG
public:
diff --git a/src/control.cc b/src/control.cc
index d47eec0..7786e36 100644
--- a/src/control.cc
+++ b/src/control.cc
@@ -46,15 +46,15 @@ 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 EvalContext *evalctx) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l,
const Context *ctx, const EvalContext *evalctx)
{
- 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;
+ if (evalctx->numArgs() > l) {
+ const std::string &it_name = evalctx->getArgName(l);
+ const Value &it_values = evalctx->getArgValue(l, ctx);
Context c(ctx);
if (it_values.type() == Value::RANGE) {
Value::RangeType range = it_values.toRange();
@@ -81,21 +81,21 @@ void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l,
for_eval(node, inst, l+1, &c, evalctx);
}
} else if (l > 0) {
- std::vector<AbstractNode *> evaluatednodes = inst.evaluateChildren(ctx);
- node.children.insert(node.children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst.instantiateChildren(ctx);
+ node.children.insert(node.children.end(), instantiatednodes.begin(), instantiatednodes.end());
}
}
-AbstractNode *ControlModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+AbstractNode *ControlModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
AbstractNode *node = NULL;
if (type == CHILD)
{
int n = 0;
- if (evalctx->eval_arguments.size() > 0) {
+ if (evalctx->numArgs() > 0) {
double v;
- if (evalctx->eval_arguments[0].second.getDouble(v)) {
+ if (evalctx->getArgValue(0).getDouble(v)) {
n = trunc(v);
if (n < 0) {
PRINTB("WARNING: Negative child index (%d) not allowed", n);
@@ -114,14 +114,14 @@ AbstractNode *ControlModule::evaluate(const Context *ctx, const ModuleInstantiat
// assert(filectx->evalctx);
if (filectx->evalctx) {
- if (n < filectx->evalctx->children.size()) {
- node = filectx->evalctx->children[n]->evaluate_instance(filectx->evalctx);
+ if (n < filectx->evalctx->numChildren()) {
+ node = filectx->evalctx->getChild(n)->evaluate(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());
+ n % filectx->evalctx->numChildren());
}
}
return node;
@@ -142,8 +142,8 @@ AbstractNode *ControlModule::evaluate(const Context *ctx, const ModuleInstantiat
msg << "ECHO: ";
for (size_t i = 0; i < inst->arguments.size(); i++) {
if (i > 0) msg << ", ";
- if (!evalctx->eval_arguments[i].first.empty()) msg << evalctx->eval_arguments[i].first << " = ";
- msg << evalctx->eval_arguments[i].second;
+ if (!evalctx->getArgName(i).empty()) msg << evalctx->getArgName(i) << " = ";
+ msg << evalctx->getArgValue(i);
}
PRINTB("%s", msg.str());
}
@@ -151,12 +151,12 @@ AbstractNode *ControlModule::evaluate(const Context *ctx, const ModuleInstantiat
if (type == ASSIGN)
{
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);
+ for (size_t i = 0; i < evalctx->numArgs(); i++) {
+ if (!evalctx->getArgName(i).empty())
+ c.set_variable(evalctx->getArgName(i), evalctx->getArgValue(i));
}
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(&c);
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(&c);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
}
if (type == FOR || type == INT_FOR)
@@ -167,13 +167,13 @@ AbstractNode *ControlModule::evaluate(const Context *ctx, const ModuleInstantiat
if (type == IF)
{
const IfElseModuleInstantiation *ifelse = dynamic_cast<const IfElseModuleInstantiation*>(inst);
- 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());
+ if (evalctx->numArgs() > 0 && evalctx->getArgValue(0).toBool()) {
+ std::vector<AbstractNode *> instantiatednodes = ifelse->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
}
else {
- std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateElseChildren(evalctx);
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = ifelse->instantiateElseChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
}
}
diff --git a/src/csgops.cc b/src/csgops.cc
index 425b747..92b97e7 100644
--- a/src/csgops.cc
+++ b/src/csgops.cc
@@ -38,14 +38,14 @@ 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 EvalContext *evalctx) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *CsgModule::evaluate(const Context*, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+AbstractNode *CsgModule::instantiate(const Context*, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
CsgNode *node = new CsgNode(inst, type);
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
return node;
}
diff --git a/src/dxfdim.cc b/src/dxfdim.cc
index fbc24c4..555ed49 100644
--- a/src/dxfdim.cc
+++ b/src/dxfdim.cc
@@ -52,17 +52,17 @@ Value builtin_dxf_dim(const Context *ctx, const EvalContext *evalctx)
// 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 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();
+ for (size_t i = 0; i < evalctx->numArgs(); i++) {
+ if (evalctx->getArgName(i) == "file")
+ filename = evalctx->getAbsolutePath(evalctx->getArgValue(i).toString());
+ if (evalctx->getArgName(i) == "layer")
+ layername = evalctx->getArgValue(i).toString();
+ if (evalctx->getArgName(i) == "origin")
+ evalctx->getArgValue(i).getVec2(xorigin, yorigin);
+ if (evalctx->getArgName(i) == "scale")
+ evalctx->getArgValue(i).getDouble(scale);
+ if (evalctx->getArgName(i) == "name")
+ name = evalctx->getArgValue(i).toString();
}
std::stringstream keystream;
@@ -146,15 +146,15 @@ Value builtin_dxf_cross(const Context *ctx, const EvalContext *evalctx)
// 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 < 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);
+ for (size_t i = 0; i < evalctx->numArgs(); i++) {
+ if (evalctx->getArgName(i) == "file")
+ filename = ctx->getAbsolutePath(evalctx->getArgValue(i).toString());
+ if (evalctx->getArgName(i) == "layer")
+ layername = evalctx->getArgValue(i).toString();
+ if (evalctx->getArgName(i) == "origin")
+ evalctx->getArgValue(i).getVec2(xorigin, yorigin);
+ if (evalctx->getArgName(i) == "scale")
+ evalctx->getArgValue(i).getDouble(scale);
}
std::stringstream keystream;
diff --git a/src/evalcontext.cc b/src/evalcontext.cc
index b7566e3..57c206f 100644
--- a/src/evalcontext.cc
+++ b/src/evalcontext.cc
@@ -4,9 +4,33 @@
#include "function.h"
#include "printutils.h"
#include "builtin.h"
+#include "localscope.h"
#include <boost/foreach.hpp>
+const std::string &EvalContext::getArgName(size_t i) const
+{
+ assert(i < this->eval_arguments.size());
+ return this->eval_arguments[i].first;
+}
+
+Value EvalContext::getArgValue(size_t i, const Context *ctx) const
+{
+ assert(i < this->eval_arguments.size());
+ const Assignment &arg = this->eval_arguments[i];
+ return arg.second ? arg.second->evaluate(ctx ? ctx : this) : Value();
+}
+
+size_t EvalContext::numChildren() const
+{
+ return this->scope ? this->scope->children.size() : 0;
+}
+
+ModuleInstantiation *EvalContext::getChild(size_t i) const
+{
+ return this->scope ? this->scope->children[i] : NULL;
+}
+
#ifdef DEBUG
void EvalContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst)
{
@@ -20,9 +44,9 @@ void EvalContext::dump(const AbstractModule *mod, const ModuleInstantiation *ins
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) {
+ if (this->scope && this->scope->children.size() > 0) {
PRINT(" children:");
- BOOST_FOREACH(const ModuleInstantiation *ch, this->children) {
+ BOOST_FOREACH(const ModuleInstantiation *ch, this->scope->children) {
PRINTB(" %s", ch->name());
}
}
diff --git a/src/evalcontext.h b/src/evalcontext.h
index 3d7d222..34f339a 100644
--- a/src/evalcontext.h
+++ b/src/evalcontext.h
@@ -10,15 +10,28 @@
class EvalContext : public Context
{
public:
- EvalContext(const Context *parent = NULL) : Context(parent) {}
+ 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) {}
virtual ~EvalContext() {}
- std::vector<std::pair<std::string, Value> > eval_arguments;
- std::vector<class ModuleInstantiation *> children;
+ size_t numArgs() const { return this->eval_arguments.size(); }
+ const std::string &getArgName(size_t i) const;
+ Value getArgValue(size_t i, const Context *ctx = NULL) const;
+
+ size_t numChildren() const;
+ ModuleInstantiation *getChild(size_t i) const;
#ifdef DEBUG
virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst);
#endif
+
+private:
+ const AssignmentList &eval_arguments;
+ std::vector<std::pair<std::string, Value> > eval_values;
+ const LocalScope *const scope;
};
#endif
diff --git a/src/expr.cc b/src/expr.cc
index 7a8180f..746c0e3 100644
--- a/src/expr.cc
+++ b/src/expr.cc
@@ -38,6 +38,20 @@ Expression::Expression()
{
}
+Expression::Expression(const std::string &type,
+ Expression *left, Expression *right)
+ : type(type)
+{
+ this->children.push_back(left);
+ this->children.push_back(right);
+}
+
+Expression::Expression(const std::string &type, Expression *expr)
+ : type(type)
+{
+ this->children.push_back(expr);
+}
+
Expression::Expression(const Value &val) : const_value(val), type("C")
{
}
@@ -127,17 +141,7 @@ Value Expression::evaluate(const Context *context) const
return Value();
}
if (this->type == "F") {
- 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));
+ EvalContext c(context, this->call_arguments);
return context->evaluate_function(this->call_funcname, &c);
}
abort();
diff --git a/src/expression.h b/src/expression.h
index 06becc0..6c03f52 100644
--- a/src/expression.h
+++ b/src/expression.h
@@ -34,6 +34,8 @@ public:
Expression();
Expression(const Value &val);
+ Expression(const std::string &type, Expression *left, Expression *right);
+ Expression(const std::string &type, Expression *expr);
~Expression();
Value evaluate(const class Context *context) const;
diff --git a/src/func.cc b/src/func.cc
index 88bf3c8..4377a90 100644
--- a/src/func.cc
+++ b/src/func.cc
@@ -129,35 +129,35 @@ static inline double rad2deg(double x)
Value builtin_abs(const Context *, const EvalContext *evalctx)
{
- if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
- return Value(fabs(evalctx->eval_arguments[0].second.toDouble()));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(fabs(evalctx->getArgValue(0).toDouble()));
return Value();
}
Value builtin_sign(const Context *, const EvalContext *evalctx)
{
- 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));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value((evalctx->getArgValue(0).toDouble()<0) ? -1.0 : ((evalctx->getArgValue(0).toDouble()>0) ? 1.0 : 0.0));
return Value();
}
Value builtin_rands(const Context *, const EvalContext *evalctx)
{
bool deterministic = false;
- 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)
+ if (evalctx->numArgs() == 3 &&
+ evalctx->getArgValue(0).type() == Value::NUMBER &&
+ evalctx->getArgValue(1).type() == Value::NUMBER &&
+ evalctx->getArgValue(2).type() == Value::NUMBER)
{
deterministic = false;
}
- 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)
+ else if (evalctx->numArgs() == 4 &&
+ evalctx->getArgValue(0).type() == Value::NUMBER &&
+ evalctx->getArgValue(1).type() == Value::NUMBER &&
+ evalctx->getArgValue(2).type() == Value::NUMBER &&
+ evalctx->getArgValue(3).type() == Value::NUMBER)
{
- deterministic_rng.seed( (unsigned int) evalctx->eval_arguments[3].second.toDouble() );
+ deterministic_rng.seed( (unsigned int) evalctx->getArgValue(3).toDouble() );
deterministic = true;
}
else
@@ -165,11 +165,11 @@ Value builtin_rands(const Context *, const EvalContext *evalctx)
return Value();
}
- 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() );
+ double min = std::min( evalctx->getArgValue(0).toDouble(), evalctx->getArgValue(1).toDouble() );
+ double max = std::max( evalctx->getArgValue(0).toDouble(), evalctx->getArgValue(1).toDouble() );
boost::uniform_real<> distributor( min, max );
Value::VectorType vec;
- for (int i=0; i<evalctx->eval_arguments[2].second.toDouble(); i++) {
+ for (int i=0; i<evalctx->getArgValue(2).toDouble(); i++) {
if ( deterministic ) {
vec.push_back( Value( distributor( deterministic_rng ) ) );
} else {
@@ -183,11 +183,11 @@ Value builtin_rands(const Context *, const EvalContext *evalctx)
Value builtin_min(const Context *, const EvalContext *evalctx)
{
- 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());
+ if (evalctx->numArgs() >= 1 && evalctx->getArgValue(0).type() == Value::NUMBER) {
+ double val = evalctx->getArgValue(0).toDouble();
+ for (size_t i = 1; i < evalctx->numArgs(); i++)
+ if (evalctx->getArgValue(1).type() == Value::NUMBER)
+ val = fmin(val, evalctx->getArgValue(i).toDouble());
return Value(val);
}
return Value();
@@ -195,11 +195,11 @@ Value builtin_min(const Context *, const EvalContext *evalctx)
Value builtin_max(const Context *, const EvalContext *evalctx)
{
- 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());
+ if (evalctx->numArgs() >= 1 && evalctx->getArgValue(0).type() == Value::NUMBER) {
+ double val = evalctx->getArgValue(0).toDouble();
+ for (size_t i = 1; i < evalctx->numArgs(); i++)
+ if (evalctx->getArgValue(1).type() == Value::NUMBER)
+ val = fmax(val, evalctx->getArgValue(i).toDouble());
return Value(val);
}
return Value();
@@ -207,117 +207,117 @@ Value builtin_max(const Context *, const EvalContext *evalctx)
Value builtin_sin(const Context *, const EvalContext *evalctx)
{
- if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
- return Value(sin(deg2rad(evalctx->eval_arguments[0].second.toDouble())));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(sin(deg2rad(evalctx->getArgValue(0).toDouble())));
return Value();
}
Value builtin_cos(const Context *, const EvalContext *evalctx)
{
- if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
- return Value(cos(deg2rad(evalctx->eval_arguments[0].second.toDouble())));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(cos(deg2rad(evalctx->getArgValue(0).toDouble())));
return Value();
}
Value builtin_asin(const Context *, const EvalContext *evalctx)
{
- if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
- return Value(rad2deg(asin(evalctx->eval_arguments[0].second.toDouble())));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(rad2deg(asin(evalctx->getArgValue(0).toDouble())));
return Value();
}
Value builtin_acos(const Context *, const EvalContext *evalctx)
{
- if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
- return Value(rad2deg(acos(evalctx->eval_arguments[0].second.toDouble())));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(rad2deg(acos(evalctx->getArgValue(0).toDouble())));
return Value();
}
Value builtin_tan(const Context *, const EvalContext *evalctx)
{
- if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
- return Value(tan(deg2rad(evalctx->eval_arguments[0].second.toDouble())));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(tan(deg2rad(evalctx->getArgValue(0).toDouble())));
return Value();
}
Value builtin_atan(const Context *, const EvalContext *evalctx)
{
- if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
- return Value(rad2deg(atan(evalctx->eval_arguments[0].second.toDouble())));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(rad2deg(atan(evalctx->getArgValue(0).toDouble())));
return Value();
}
Value builtin_atan2(const Context *, const EvalContext *evalctx)
{
- 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())));
+ if (evalctx->numArgs() == 2 && evalctx->getArgValue(0).type() == Value::NUMBER && evalctx->getArgValue(1).type() == Value::NUMBER)
+ return Value(rad2deg(atan2(evalctx->getArgValue(0).toDouble(), evalctx->getArgValue(1).toDouble())));
return Value();
}
Value builtin_pow(const Context *, const EvalContext *evalctx)
{
- 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()));
+ if (evalctx->numArgs() == 2 && evalctx->getArgValue(0).type() == Value::NUMBER && evalctx->getArgValue(1).type() == Value::NUMBER)
+ return Value(pow(evalctx->getArgValue(0).toDouble(), evalctx->getArgValue(1).toDouble()));
return Value();
}
Value builtin_round(const Context *, const EvalContext *evalctx)
{
- if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
- return Value(round(evalctx->eval_arguments[0].second.toDouble()));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(round(evalctx->getArgValue(0).toDouble()));
return Value();
}
Value builtin_ceil(const Context *, const EvalContext *evalctx)
{
- if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
- return Value(ceil(evalctx->eval_arguments[0].second.toDouble()));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(ceil(evalctx->getArgValue(0).toDouble()));
return Value();
}
Value builtin_floor(const Context *, const EvalContext *evalctx)
{
- if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
- return Value(floor(evalctx->eval_arguments[0].second.toDouble()));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(floor(evalctx->getArgValue(0).toDouble()));
return Value();
}
Value builtin_sqrt(const Context *, const EvalContext *evalctx)
{
- if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
- return Value(sqrt(evalctx->eval_arguments[0].second.toDouble()));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(sqrt(evalctx->getArgValue(0).toDouble()));
return Value();
}
Value builtin_exp(const Context *, const EvalContext *evalctx)
{
- if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
- return Value(exp(evalctx->eval_arguments[0].second.toDouble()));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(exp(evalctx->getArgValue(0).toDouble()));
return Value();
}
Value builtin_length(const Context *, const EvalContext *evalctx)
{
- 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()));
+ if (evalctx->numArgs() == 1) {
+ if (evalctx->getArgValue(0).type() == Value::VECTOR) return Value(int(evalctx->getArgValue(0).toVector().size()));
+ if (evalctx->getArgValue(0).type() == Value::STRING) return Value(int(evalctx->getArgValue(0).toString().size()));
}
return Value();
}
Value builtin_log(const Context *, const EvalContext *evalctx)
{
- 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));
+ if (evalctx->numArgs() == 2 && evalctx->getArgValue(0).type() == Value::NUMBER && evalctx->getArgValue(1).type() == Value::NUMBER)
+ return Value(log(evalctx->getArgValue(1).toDouble()) / log(evalctx->getArgValue(0).toDouble()));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(log(evalctx->getArgValue(0).toDouble()) / log(10.0));
return Value();
}
Value builtin_ln(const Context *, const EvalContext *evalctx)
{
- if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER)
- return Value(log(evalctx->eval_arguments[0].second.toDouble()));
+ if (evalctx->numArgs() == 1 && evalctx->getArgValue(0).type() == Value::NUMBER)
+ return Value(log(evalctx->getArgValue(0).toDouble()));
return Value();
}
@@ -325,8 +325,8 @@ Value builtin_str(const Context *, const EvalContext *evalctx)
{
std::stringstream stream;
- for (size_t i = 0; i < evalctx->eval_arguments.size(); i++) {
- stream << evalctx->eval_arguments[i].second.toString();
+ for (size_t i = 0; i < evalctx->numArgs(); i++) {
+ stream << evalctx->getArgValue(i).toString();
}
return Value(stream.str());
}
@@ -334,16 +334,16 @@ Value builtin_str(const Context *, const EvalContext *evalctx)
Value builtin_lookup(const Context *, const EvalContext *evalctx)
{
double p, low_p, low_v, high_p, high_v;
- 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)
+ if (evalctx->numArgs() < 2 || // Needs two args
+ !evalctx->getArgValue(0).getDouble(p) || // First must be a number
+ evalctx->getArgValue(1).toVector().size() < 2 || // Second must be a vector of vectors
+ evalctx->getArgValue(1).toVector()[0].toVector().size() < 2)
return Value();
- 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))
+ if (!evalctx->getArgValue(1).toVector()[0].getVec2(low_p, low_v) || !evalctx->getArgValue(1).toVector()[0].getVec2(high_p, high_v))
return Value();
- for (size_t i = 1; i < evalctx->eval_arguments[1].second.toVector().size(); i++) {
+ for (size_t i = 1; i < evalctx->getArgValue(1).toVector().size(); i++) {
double this_p, this_v;
- if (evalctx->eval_arguments[1].second.toVector()[i].getVec2(this_p, this_v)) {
+ if (evalctx->getArgValue(1).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;
@@ -406,12 +406,12 @@ Value builtin_lookup(const Context *, const EvalContext *evalctx)
*/
Value builtin_search(const Context *, const EvalContext *evalctx)
{
- if (evalctx->eval_arguments.size() < 2) return Value();
+ if (evalctx->numArgs() < 2) return Value();
- 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;
+ const Value &findThis = evalctx->getArgValue(0);
+ const Value &searchTable = evalctx->getArgValue(1);
+ unsigned int num_returns_per_match = (evalctx->numArgs() > 2) ? evalctx->getArgValue(2).toDouble() : 1;
+ unsigned int index_col_num = (evalctx->numArgs() > 3) ? evalctx->getArgValue(3).toDouble() : 0;
Value::VectorType returnvec;
@@ -512,7 +512,7 @@ Value builtin_version(const Context *, const EvalContext *evalctx)
Value builtin_version_num(const Context *ctx, const EvalContext *evalctx)
{
- Value val = (evalctx->eval_arguments.size() == 0) ? builtin_version(ctx, evalctx) : evalctx->eval_arguments[0].second;
+ Value val = (evalctx->numArgs() == 0) ? builtin_version(ctx, evalctx) : evalctx->getArgValue(0);
double y, m, d = 0;
if (!val.getVec3(y, m, d)) {
if (!val.getVec2(y, m)) {
diff --git a/src/import.cc b/src/import.cc
index 927c9d8..bd8f830 100644
--- a/src/import.cc
+++ b/src/import.cc
@@ -60,10 +60,10 @@ class ImportModule : public AbstractModule
public:
import_type_e type;
ImportModule(import_type_e type = TYPE_UNKNOWN) : type(type) { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+AbstractNode *ImportModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
AssignmentList args;
args += Assignment("file", NULL), Assignment("layer", NULL), Assignment("convexity", NULL), Assignment("origin", NULL), Assignment("scale", NULL);
@@ -93,10 +93,10 @@ AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiati
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=");
+ if (!v.isUndefined()) {
+ PRINT("DEPRECATED: 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) {
@@ -116,9 +116,10 @@ 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=");
+ layerval = c.lookup_variable("layername");
+ if (!layerval.isUndefined()) {
+ PRINT("DEPRECATED: 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 6766abc..6dfe9bc 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -55,7 +55,7 @@ static void yyunput(int, char*) __attribute__((unused));
#endif
extern const char *parser_input_buffer;
extern std::string parser_source_path;
-extern Module *currmodule;
+extern FileModule *rootmodule;
#define YY_INPUT(buf,result,max_size) { \
if (yyin && yyin != stdin) { \
@@ -248,7 +248,7 @@ void includefile()
path_stack.push_back(finfo.parent_path());
handle_dep(fullname);
- currmodule->registerInclude(fullname);
+ rootmodule->registerInclude(fullname);
yyin = fopen(fullname.c_str(), "r");
if (!yyin) {
PRINTB("WARNING: Can't open 'include' file '%s'.", filename);
diff --git a/src/linearextrude.cc b/src/linearextrude.cc
index f4c1112..c64a235 100644
--- a/src/linearextrude.cc
+++ b/src/linearextrude.cc
@@ -45,10 +45,10 @@ class LinearExtrudeModule : public AbstractModule
{
public:
LinearExtrudeModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+AbstractNode *LinearExtrudeModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
LinearExtrudeNode *node = new LinearExtrudeNode(inst);
@@ -80,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() &&
- 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);
+ evalctx->numArgs() > 0 &&
+ evalctx->getArgName(0) == "" &&
+ evalctx->getArgValue(0).type() == Value::NUMBER) {
+ height = evalctx->getArgValue(0);
}
node->layername = layer.isUndefined() ? "" : layer.toString();
@@ -116,8 +116,8 @@ AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInst
}
if (node->filename.empty()) {
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
}
return node;
diff --git a/src/localscope.cc b/src/localscope.cc
new file mode 100644
index 0000000..eecff91
--- /dev/null
+++ b/src/localscope.cc
@@ -0,0 +1,73 @@
+#include "localscope.h"
+#include "modcontext.h"
+#include "module.h"
+#include "typedefs.h"
+#include "expression.h"
+#include "function.h"
+
+#include <boost/foreach.hpp>
+
+LocalScope::LocalScope()
+{
+}
+
+LocalScope::~LocalScope()
+{
+ BOOST_FOREACH (ModuleInstantiation *v, children) delete v;
+ 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;
+}
+
+void LocalScope::addChild(ModuleInstantiation *ch)
+{
+ assert(ch != NULL);
+ this->children.push_back(ch);
+}
+
+std::string LocalScope::dump(const std::string &indent) const
+{
+ std::stringstream dump;
+ BOOST_FOREACH(const FunctionContainer::value_type &f, this->functions) {
+ dump << f.second->dump(indent, f.first);
+ }
+ BOOST_FOREACH(const AbstractModuleContainer::value_type &m, this->modules) {
+ dump << m.second->dump(indent, m.first);
+ }
+ BOOST_FOREACH(const Assignment &ass, this->assignments) {
+ dump << indent << ass.first << " = " << *ass.second << ";\n";
+ }
+ BOOST_FOREACH(const ModuleInstantiation *inst, this->children) {
+ dump << inst->dump(indent);
+ }
+ return dump.str();
+}
+
+// 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
+{
+ 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;
+
+ 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);
+ if (node) childnodes.push_back(node);
+ }
+
+ if (c != filectx) delete c;
+
+ return childnodes;
+}
+
diff --git a/src/localscope.h b/src/localscope.h
new file mode 100644
index 0000000..d81a27c
--- /dev/null
+++ b/src/localscope.h
@@ -0,0 +1,26 @@
+#ifndef LOCALSCOPE_H_
+#define LOCALSCOPE_H_
+
+#include "typedefs.h"
+#include <boost/unordered_map.hpp>
+
+class LocalScope
+{
+public:
+ LocalScope();
+ ~LocalScope();
+
+ 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;
+ void addChild(ModuleInstantiation *ch);
+
+ AssignmentList assignments;
+ ModuleInstantiationList children;
+ typedef boost::unordered_map<std::string, class AbstractFunction*> FunctionContainer;
+ FunctionContainer functions;
+ typedef boost::unordered_map<std::string, class AbstractModule*> AbstractModuleContainer;
+ AbstractModuleContainer modules;
+};
+
+#endif
diff --git a/src/mainwin.cc b/src/mainwin.cc
index 2e69ec2..027f72a 100644
--- a/src/mainwin.cc
+++ b/src/mainwin.cc
@@ -168,7 +168,7 @@ MainWindow::MainWindow(const QString &filename)
this, SLOT(actionRenderCGALDone(CGAL_Nef_polyhedron *)));
#endif
- root_ctx.registerBuiltin();
+ top_ctx.registerBuiltin();
this->openglbox = NULL;
root_module = NULL;
@@ -506,7 +506,7 @@ MainWindow::setFileName(const QString &filename)
{
if (filename.isEmpty()) {
this->fileName.clear();
- this->root_ctx.setDocumentPath(currentdir);
+ this->top_ctx.setDocumentPath(currentdir);
setWindowTitle("OpenSCAD - New Document[*]");
}
else {
@@ -522,7 +522,7 @@ MainWindow::setFileName(const QString &filename)
this->fileName = fileinfo.fileName();
}
- this->root_ctx.setDocumentPath(fileinfo.dir().absolutePath().toLocal8Bit().constData());
+ this->top_ctx.setDocumentPath(fileinfo.dir().absolutePath().toLocal8Bit().constData());
QDir::setCurrent(fileinfo.dir().absolutePath());
}
@@ -644,7 +644,7 @@ bool MainWindow::compile(bool reload, bool procevents)
AbstractNode::resetIndexCounter();
this->root_inst = ModuleInstantiation("group");
- this->absolute_root_node = this->root_module->evaluate(&this->root_ctx, &this->root_inst, NULL);
+ this->absolute_root_node = this->root_module->instantiate(&top_ctx, &this->root_inst, NULL);
if (this->absolute_root_node) {
// Do we have an explicit root node (! modifier)?
@@ -979,19 +979,19 @@ void MainWindow::pasteViewportRotation()
void MainWindow::updateTemporalVariables()
{
- this->root_ctx.set_variable("$t", Value(this->e_tval->text().toDouble()));
+ this->top_ctx.set_variable("$t", Value(this->e_tval->text().toDouble()));
Value::VectorType vpt;
vpt.push_back(Value(-qglview->cam.object_trans.x()));
vpt.push_back(Value(-qglview->cam.object_trans.y()));
vpt.push_back(Value(-qglview->cam.object_trans.z()));
- this->root_ctx.set_variable("$vpt", Value(vpt));
+ this->top_ctx.set_variable("$vpt", Value(vpt));
Value::VectorType vpr;
vpr.push_back(Value(fmodf(360 - qglview->cam.object_rot.x() + 90, 360)));
vpr.push_back(Value(fmodf(360 - qglview->cam.object_rot.y(), 360)));
vpr.push_back(Value(fmodf(360 - qglview->cam.object_rot.z(), 360)));
- root_ctx.set_variable("$vpr", Value(vpr));
+ top_ctx.set_variable("$vpr", Value(vpr));
}
bool MainWindow::fileChangedOnDisk()
@@ -1022,7 +1022,7 @@ static bool is_modified(const std::string &filename, const time_t &mtime)
bool MainWindow::includesChanged()
{
if (this->root_module) {
- BOOST_FOREACH(const Module::IncludeContainer::value_type &item, this->root_module->includes) {
+ BOOST_FOREACH(const FileModule::IncludeContainer::value_type &item, this->root_module->includes) {
if (is_modified(item.first, item.second)) return true;
}
}
diff --git a/src/modcontext.cc b/src/modcontext.cc
index 7d123b8..44c2002 100644
--- a/src/modcontext.cc
+++ b/src/modcontext.cc
@@ -7,46 +7,24 @@
#include <boost/foreach.hpp>
-ModuleContext::ModuleContext(const class Module *module, const Context *parent, const EvalContext *evalctx)
- : Context(parent)
+ModuleContext::ModuleContext(const Context *parent, const EvalContext *evalctx)
+ : Context(parent), functions_p(NULL), modules_p(NULL), evalctx(evalctx)
{
- 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)
+void ModuleContext::initializeModule(const class Module &module)
{
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));
+ this->functions_p = &module.scope.functions;
+ this->modules_p = &module.scope.modules;
+ BOOST_FOREACH(const Assignment &ass, module.scope.assignments) {
+ this->set_variable(ass.first, ass.second->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
@@ -62,61 +40,65 @@ private:
const std::string &name;
};
-Value ModuleContext::evaluate_function(const std::string &name, const EvalContext *evalctx) const
+
+/*!
+ Only used to initialize builtins for the top-level root context
+*/
+void ModuleContext::registerBuiltin()
{
- RecursionGuard g(*this, name);
- if (g.recursion_detected()) {
- PRINTB("Recursion detected calling function '%s'", name);
- return Value();
+ const LocalScope &scope = Builtins::instance()->getGlobalScope();
+
+ // FIXME: Don't access module members directly
+ this->functions_p = &scope.functions;
+ this->modules_p = &scope.modules;
+ BOOST_FOREACH(const Assignment &ass, scope.assignments) {
+ this->set_variable(ass.first, ass.second->evaluate(this));
}
+ this->set_constant("PI",Value(M_PI));
+}
+
+const AbstractFunction *ModuleContext::findLocalFunction(const std::string &name) const
+{
if (this->functions_p && this->functions_p->find(name) != this->functions_p->end()) {
- return this->functions_p->find(name)->second->evaluate(this, evalctx);
- }
-
- if (this->usedlibs_p) {
- BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) {
- if (m.second->functions.find(name) != m.second->functions.end()) {
- ModuleContext ctx(m.second, this->parent);
- // FIXME: Set document path
-#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 this->functions_p->find(name)->second;
}
- return Context::evaluate_function(name, evalctx);
+ return NULL;
}
-AbstractNode *ModuleContext::evaluate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const
+const AbstractModule *ModuleContext::findLocalModule(const std::string &name) 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 (this->modules_p && this->modules_p->find(name) != this->modules_p->end()) {
+ AbstractModule *m = this->modules_p->find(name)->second;
+ std::string replacement = Builtins::instance()->isDeprecated(name);
if (!replacement.empty()) {
- PRINTB("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", inst.name() % replacement);
+ PRINTB("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", name % replacement);
}
- return m->evaluate(this, &inst, evalctx);
+ return m;
}
+ return NULL;
+}
- 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);
- }
- }
+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();
}
- return Context::evaluate_module(inst, evalctx);
+ const AbstractFunction *foundf = findLocalFunction(name);
+ if (foundf) return foundf->evaluate(this, evalctx);
+
+ return Context::evaluate_function(name, evalctx);
+}
+
+AbstractNode *ModuleContext::instantiate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const
+{
+ const AbstractModule *foundm = this->findLocalModule(inst.name());
+ if (foundm) return foundm->instantiate(this, &inst, evalctx);
+
+ return Context::instantiate_module(inst, evalctx);
}
#ifdef DEBUG
@@ -150,3 +132,58 @@ void ModuleContext::dump(const AbstractModule *mod, const ModuleInstantiation *i
}
#endif
+
+FileContext::FileContext(const class FileModule &module, const Context *parent)
+ : usedlibs(module.usedlibs), ModuleContext(parent)
+{
+ if (!module.modulePath().empty()) this->document_path = module.modulePath();
+}
+
+Value FileContext::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();
+ }
+
+ const AbstractFunction *foundf = findLocalFunction(name);
+ if (foundf) return foundf->evaluate(this, evalctx);
+
+ BOOST_FOREACH(const FileModule::ModuleContainer::value_type &m, this->usedlibs) {
+ if (m.second->scope.functions.find(name) != m.second->scope.functions.end()) {
+ FileContext ctx(*m.second, this->parent);
+ ctx.initializeModule(*m.second);
+ // FIXME: Set document path
+#if 0 && DEBUG
+ PRINTB("New lib Context for %s func:", name);
+ ctx.dump(NULL, NULL);
+#endif
+ return m.second->scope.functions[name]->evaluate(&ctx, evalctx);
+ }
+ }
+
+ return ModuleContext::evaluate_function(name, evalctx);
+}
+
+AbstractNode *FileContext::instantiate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const
+{
+ const AbstractModule *foundm = this->findLocalModule(inst.name());
+ if (foundm) return foundm->instantiate(this, &inst, evalctx);
+
+ BOOST_FOREACH(const FileModule::ModuleContainer::value_type &m, this->usedlibs) {
+ assert(m.second);
+ if (m.second->scope.modules.find(inst.name()) != m.second->scope.modules.end()) {
+ FileContext ctx(*m.second, this->parent);
+ ctx.initializeModule(*m.second);
+ // FIXME: Set document path
+#if 0 && DEBUG
+ PRINT("New file Context:");
+ ctx.dump(NULL, &inst);
+#endif
+ return m.second->scope.modules[inst.name()]->instantiate(&ctx, &inst, evalctx);
+ }
+ }
+
+ return ModuleContext::instantiate_module(inst, evalctx);
+}
diff --git a/src/modcontext.h b/src/modcontext.h
index 5fce88f..4479051 100644
--- a/src/modcontext.h
+++ b/src/modcontext.h
@@ -2,30 +2,33 @@
#define FILECONTEXT_H_
#include "context.h"
+#include "module.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.
+ NB! every .scad file defines a FileModule 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);
+ ModuleContext(const Context *parent = NULL, const EvalContext *evalctx = NULL);
virtual ~ModuleContext();
- void setModule(const Module &module, const EvalContext *evalctx = NULL);
+ void initializeModule(const Module &m);
void registerBuiltin();
+ virtual Value evaluate_function(const std::string &name,
+ const EvalContext *evalctx) const;
+ virtual AbstractNode *instantiate_module(const ModuleInstantiation &inst,
+ const EvalContext *evalctx) const;
- virtual Value evaluate_function(const std::string &name, const EvalContext *evalctx) const;
- virtual AbstractNode *evaluate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const;
+ const AbstractModule *findLocalModule(const std::string &name) const;
+ const AbstractFunction *findLocalFunction(const std::string &name) 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;
+ const LocalScope::FunctionContainer *functions_p;
+ const LocalScope::AbstractModuleContainer *modules_p;
// FIXME: Points to the eval context for the call to this module. Not sure where it belongs
const class EvalContext *evalctx;
@@ -37,4 +40,17 @@ public:
mutable boost::unordered_map<std::string, int> recursioncount;
};
+class FileContext : public ModuleContext
+{
+public:
+ FileContext(const class FileModule &module, const Context *parent);
+ 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;
+
+private:
+ const FileModule::ModuleContainer &usedlibs;
+};
+
#endif
diff --git a/src/module.cc b/src/module.cc
index 7d83975..9503f05 100644
--- a/src/module.cc
+++ b/src/module.cc
@@ -44,11 +44,11 @@ AbstractModule::~AbstractModule()
{
}
-AbstractNode *AbstractModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+AbstractNode *AbstractModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
AbstractNode *node = new AbstractNode(inst);
- node->children = inst->evaluateChildren(evalctx);
+ node->children = inst->instantiateChildren(evalctx);
return node;
}
@@ -63,12 +63,10 @@ std::string AbstractModule::dump(const std::string &indent, const std::string &n
ModuleInstantiation::~ModuleInstantiation()
{
BOOST_FOREACH(const Assignment &arg, this->arguments) delete arg.second;
- BOOST_FOREACH(ModuleInstantiation *v, children) delete v;
}
IfElseModuleInstantiation::~IfElseModuleInstantiation()
{
- BOOST_FOREACH (ModuleInstantiation *v, else_children) delete v;
}
/*!
@@ -95,83 +93,58 @@ std::string ModuleInstantiation::dump(const std::string &indent) const
if (!arg.first.empty()) dump << arg.first << " = ";
dump << *arg.second;
}
- if (children.size() == 0) {
+ if (scope.numElements() == 0) {
dump << ");\n";
- } else if (children.size() == 1) {
+ } else if (scope.numElements() == 1) {
dump << ")\n";
- dump << children[0]->dump(indent + "\t");
+ dump << scope.dump(indent + "\t");
} else {
dump << ") {\n";
- for (size_t i = 0; i < children.size(); i++) {
- dump << children[i]->dump(indent + "\t");
- }
+ scope.dump(indent + "\t");
dump << indent << "}\n";
}
return dump.str();
}
-AbstractNode *ModuleInstantiation::evaluate_instance(const Context *ctx) const
+AbstractNode *ModuleInstantiation::evaluate(const Context *ctx) const
{
- 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;
+ EvalContext c(ctx, this->arguments, &this->scope);
#if 0 && DEBUG
PRINT("New eval ctx:");
c.dump(NULL, this);
#endif
- AbstractNode *node = ctx->evaluate_module(*this, &c); // Passes c as evalctx
+ AbstractNode *node = ctx->instantiate_module(*this, &c); // Passes c as evalctx
return node;
}
-std::vector<AbstractNode*> ModuleInstantiation::evaluateChildren(const Context *evalctx) const
+std::vector<AbstractNode*> ModuleInstantiation::instantiateChildren(const Context *evalctx) const
{
- std::vector<AbstractNode*> childnodes;
- BOOST_FOREACH (ModuleInstantiation *modinst, this->children) {
- AbstractNode *node = modinst->evaluate_instance(evalctx);
- if (node) childnodes.push_back(node);
- }
- return childnodes;
+ return this->scope.instantiateChildren(evalctx);
}
-std::vector<AbstractNode*> IfElseModuleInstantiation::evaluateElseChildren(const Context *evalctx) const
+std::vector<AbstractNode*> IfElseModuleInstantiation::instantiateElseChildren(const Context *evalctx) const
{
- std::vector<AbstractNode*> childnodes;
- BOOST_FOREACH (ModuleInstantiation *modinst, this->else_children) {
- AbstractNode *node = modinst->evaluate_instance(evalctx);
- if (node != NULL) childnodes.push_back(node);
- }
- return childnodes;
+ return this->else_scope.instantiateChildren(evalctx);
}
Module::~Module()
{
- 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 EvalContext *evalctx) const
+AbstractNode *Module::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
- ModuleContext c(this, ctx, evalctx);
+ ModuleContext c(ctx, evalctx);
+ c.initializeModule(*this);
+ c.set_variable("$children", Value(double(inst->scope.children.size())));
// FIXME: Set document path to the path of the module
- c.set_variable("$children", Value(double(inst->children.size())));
#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_instance(&c);
- if (n != NULL)
- node->children.push_back(n);
- }
+ std::vector<AbstractNode *> instantiatednodes = this->scope.instantiateChildren(&c);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
return node;
}
@@ -191,25 +164,14 @@ std::string Module::dump(const std::string &indent, const std::string &name) con
dump << ") {\n";
tab = "\t";
}
- BOOST_FOREACH(const FunctionContainer::value_type &f, functions) {
- dump << f.second->dump(indent + tab, f.first);
- }
- BOOST_FOREACH(const AbstractModuleContainer::value_type &m, modules) {
- dump << m.second->dump(indent + tab, m.first);
- }
- BOOST_FOREACH(const std::string &var, assignments_var) {
- dump << indent << tab << var << " = " << *assignments.at(var) << ";\n";
- }
- for (size_t i = 0; i < children.size(); i++) {
- dump << children[i]->dump(indent + tab);
- }
+ dump << scope.dump(indent + tab);
if (!name.empty()) {
dump << indent << "}\n";
}
return dump.str();
}
-void Module::registerInclude(const std::string &filename)
+void FileModule::registerInclude(const std::string &filename)
{
struct stat st;
memset(&st, 0, sizeof(struct stat));
@@ -221,17 +183,17 @@ void Module::registerInclude(const std::string &filename)
Check if any dependencies have been modified and recompile them.
Returns true if anything was recompiled.
*/
-bool Module::handleDependencies()
+bool FileModule::handleDependencies()
{
if (this->is_handling_dependencies) return false;
this->is_handling_dependencies = true;
bool changed = false;
// Iterating manually since we want to modify the container while iterating
- Module::ModuleContainer::iterator iter = this->usedlibs.begin();
+ FileModule::ModuleContainer::iterator iter = this->usedlibs.begin();
while (iter != this->usedlibs.end()) {
- Module::ModuleContainer::iterator curr = iter++;
- Module *oldmodule = curr->second;
+ FileModule::ModuleContainer::iterator curr = iter++;
+ FileModule *oldmodule = curr->second;
curr->second = ModuleCache::instance()->evaluate(curr->first);
if (curr->second != oldmodule) {
changed = true;
@@ -248,3 +210,20 @@ bool Module::handleDependencies()
this->is_handling_dependencies = false;
return changed;
}
+
+AbstractNode *FileModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+{
+ assert(evalctx == NULL);
+ FileContext c(*this, ctx);
+ c.initializeModule(*this);
+ // FIXME: Set document path to the path of the module
+#if 0 && DEBUG
+ c.dump(this, inst);
+#endif
+
+ AbstractNode *node = new AbstractNode(inst);
+ std::vector<AbstractNode *> instantiatednodes = this->scope.instantiateChildren(ctx, &c);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
+
+ return node;
+}
diff --git a/src/module.h b/src/module.h
index ace3c1b..8f1ccb7 100644
--- a/src/module.h
+++ b/src/module.h
@@ -7,6 +7,7 @@
#include <boost/unordered_map.hpp>
#include "value.h"
#include "typedefs.h"
+#include "localscope.h"
class ModuleInstantiation
{
@@ -16,8 +17,8 @@ public:
virtual ~ModuleInstantiation();
std::string dump(const std::string &indent) const;
- class AbstractNode *evaluate_instance(const class Context *ctx) const;
- std::vector<AbstractNode*> evaluateChildren(const Context *evalctx) const;
+ class AbstractNode *evaluate(const class Context *ctx) const;
+ std::vector<AbstractNode*> instantiateChildren(const Context *evalctx) const;
void setPath(const std::string &path) { this->modpath = path; }
const std::string &path() const { return this->modpath; }
@@ -29,7 +30,7 @@ public:
bool isRoot() const { return this->tag_root; }
AssignmentList arguments;
- std::vector<ModuleInstantiation*> children;
+ LocalScope scope;
bool tag_root;
bool tag_highlight;
@@ -45,57 +46,54 @@ class IfElseModuleInstantiation : public ModuleInstantiation {
public:
IfElseModuleInstantiation() : ModuleInstantiation("if") { }
virtual ~IfElseModuleInstantiation();
- std::vector<AbstractNode*> evaluateElseChildren(const Context *evalctx) const;
+ std::vector<AbstractNode*> instantiateElseChildren(const Context *evalctx) const;
- std::vector<ModuleInstantiation*> else_children;
+ LocalScope else_scope;
};
class AbstractModule
{
public:
virtual ~AbstractModule();
- virtual class AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const class EvalContext *evalctx = NULL) const;
+ virtual class AbstractNode *instantiate(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;
};
class Module : public AbstractModule
{
public:
- Module() : is_handling_dependencies(false) { }
+ Module() { }
virtual ~Module();
- 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 AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx = NULL) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
- void addChild(ModuleInstantiation *ch) { this->children.push_back(ch); }
-
- typedef boost::unordered_map<std::string, class Module*> ModuleContainer;
- ModuleContainer usedlibs;
- void registerInclude(const std::string &filename);
- typedef boost::unordered_map<std::string, time_t> IncludeContainer;
- IncludeContainer includes;
- bool is_handling_dependencies;
- bool handleDependencies();
-
- std::list<std::string> assignments_var;
- typedef boost::unordered_map<std::string, Expression*> AssignmentMap;
- AssignmentMap assignments;
+ AssignmentList definition_arguments;
- typedef boost::unordered_map<std::string, class AbstractFunction*> FunctionContainer;
- FunctionContainer functions;
- typedef boost::unordered_map<std::string, AbstractModule*> AbstractModuleContainer;
- AbstractModuleContainer modules;
+ LocalScope scope;
+};
- std::vector<ModuleInstantiation*> children;
+// FIXME: A FileModule doesn't have definition arguments, so we shouldn't really
+// inherit from a Module
+class FileModule : public Module
+{
+public:
+ FileModule() : is_handling_dependencies(false) {}
+ virtual ~FileModule() {}
- std::vector<Assignment> definition_arguments;
+ void setModulePath(const std::string &path) { this->path = path; }
+ const std::string &modulePath() const { return this->path; }
+ void registerInclude(const std::string &filename);
+ bool handleDependencies();
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx = NULL) const;
-protected:
+ typedef boost::unordered_map<std::string, class FileModule*> ModuleContainer;
+ ModuleContainer usedlibs;
+ typedef boost::unordered_map<std::string, time_t> IncludeContainer;
+ IncludeContainer includes;
private:
+ bool is_handling_dependencies;
std::string path;
};
diff --git a/src/openscad.cc b/src/openscad.cc
index 3b960f3..6a0d057 100644
--- a/src/openscad.cc
+++ b/src/openscad.cc
@@ -327,7 +327,15 @@ int main(int argc, char **argv)
if (!filename) help(argv[0]);
- Module *root_module;
+ // Top context - this context only holds builtins
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
+ PRINT("Root Context:");
+#if 0 && DEBUG
+ top_ctx.dump(NULL, NULL);
+#endif
+
+ FileModule *root_module;
ModuleInstantiation root_inst("group");
AbstractNode *root_node;
AbstractNode *absolute_root_node;
@@ -348,18 +356,12 @@ 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, NULL);
+ absolute_root_node = root_module->instantiate(&top_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/openscad.h b/src/openscad.h
index 8d9a01e..dd379a9 100644
--- a/src/openscad.h
+++ b/src/openscad.h
@@ -27,7 +27,7 @@
#ifndef OPENSCAD_H
#define OPENSCAD_H
-extern class Module *parse(const char *text, const char *path, int debug);
+extern class FileModule *parse(const char *text, const char *path, int debug);
extern int get_fragments_from_r(double r, double fn, double fs, double fa);
#include <string>
diff --git a/src/parser.y b/src/parser.y
index fd6b164..272f801 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -56,8 +56,8 @@
int lexerlex_destroy(void);
int lexerlex(void);
- std::vector<Module*> module_stack;
- Module *currmodule;
+ std::stack<LocalScope *> scope_stack;
+ FileModule *rootmodule;
extern void lexerdestroy();
extern FILE *lexerin;
@@ -73,7 +73,6 @@
class Value *value;
class Expression *expr;
class ModuleInstantiation *inst;
- std::vector<ModuleInstantiation*> *instvec;
class IfElseModuleInstantiation *ifelse;
Assignment *arg;
AssignmentList *args;
@@ -114,8 +113,6 @@
%type <inst> module_instantiation
%type <ifelse> if_statement
%type <ifelse> ifelse_statement
-%type <instvec> children_instantiation
-%type <instvec> module_instantiation_list
%type <inst> single_module_instantiation
%type <args> arguments_call
@@ -130,91 +127,73 @@
input:
/* empty */ |
-TOK_USE { currmodule->usedlibs[$1] = NULL; } input |
+TOK_USE { rootmodule->usedlibs[$1] = NULL; } input |
statement input ;
inner_input:
/* empty */ |
statement inner_input ;
+assignment:
+TOK_ID '=' expr ';' {
+ for (AssignmentList::iterator iter = scope_stack.top()->assignments.begin();
+ iter != scope_stack.top()->assignments.end();
+ iter++) {
+ if (iter->first == $1) {
+ scope_stack.top()->assignments.erase(iter);
+ break;
+ }
+ }
+ scope_stack.top()->assignments.push_back(Assignment($1, $3));
+} ;
+
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;
+ if ($1) scope_stack.top()->addChild($1);
} |
+assignment |
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;
+ Module *newmodule = new Module();
+ newmodule->definition_arguments = *$4;
+ scope_stack.top()->modules[$2] = newmodule;
+ scope_stack.push(&newmodule->scope);
free($2);
delete $4;
} statement {
- currmodule = module_stack.back();
- module_stack.pop_back();
+ scope_stack.pop();
} |
TOK_FUNCTION TOK_ID '(' arguments_decl optional_commas ')' '=' expr {
Function *func = new Function();
func->definition_arguments = *$4;
func->expr = $8;
- currmodule->functions[$2] = func;
+ scope_stack.top()->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;
-} ;
-
if_statement:
-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;
-} ;
+TOK_IF '(' expr ')' {
+ $<ifelse>if = new IfElseModuleInstantiation();
+ $<ifelse>if->arguments.push_back(Assignment("", $3));
+ $<ifelse>if->setPath(parser_source_path);
+ scope_stack.push(&$<ifelse>if->scope);
+}[if] child_statement {
+ scope_stack.pop();
+ $$ = $<ifelse>if;
+ } ;
ifelse_statement:
if_statement {
$$ = $1;
} |
-if_statement TOK_ELSE children_instantiation {
+if_statement TOK_ELSE {
+ scope_stack.push(&$1->else_scope);
+}[else] child_statement {
+ scope_stack.pop();
$$ = $1;
- if ($$) {
- $$->else_children = *$3;
- } else {
- for (size_t i = 0; i < $3->size(); i++)
- delete (*$3)[i];
- }
- delete $3;
-} ;
+ } ;
module_instantiation:
'!' module_instantiation {
@@ -233,35 +212,28 @@ 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;
+single_module_instantiation {
+ $<inst>inst = $1;
+ scope_stack.push(&$<inst>inst->scope);
+}[inst] child_statement {
+ scope_stack.pop();
+ $$ = $<inst>inst;
+ } |
+ ifelse_statement {
+ $$ = $1;
+ } ;
+
+child_statement:
+';' |
+'{' child_statements '}' |
+module_instantiation {
+ if ($1) scope_stack.top()->addChild($1);
} |
-ifelse_statement {
- $$ = $1;
-} ;
+assignment ;
-module_instantiation_list:
-/* empty */ {
- $$ = new std::vector<ModuleInstantiation*>;
-} |
-module_instantiation_list module_instantiation {
- $$ = $1;
- if ($$) {
- if ($2) $$->push_back($2);
- } else {
- delete $2;
- }
-} ;
+child_statements:
+/* empty */ |
+child_statements child_statement ;
single_module_instantiation:
TOK_ID '(' arguments_call ')' {
@@ -289,9 +261,7 @@ TOK_ID {
free($1);
} |
expr '.' TOK_ID {
- $$ = new Expression();
- $$->type = "N";
- $$->children.push_back($1);
+ $$ = new Expression("N", $1);
$$->var_name = $3;
free($3);
} |
@@ -324,95 +294,52 @@ TOK_NUMBER {
$$ = $2;
} |
expr '*' expr {
- $$ = new Expression();
- $$->type = "*";
- $$->children.push_back($1);
- $$->children.push_back($3);
+ $$ = new Expression("*", $1, $3);
} |
expr '/' expr {
- $$ = new Expression();
- $$->type = "/";
- $$->children.push_back($1);
- $$->children.push_back($3);
+ $$ = new Expression("/", $1, $3);
} |
expr '%' expr {
- $$ = new Expression();
- $$->type = "%";
- $$->children.push_back($1);
- $$->children.push_back($3);
+ $$ = new Expression("%", $1, $3);
} |
expr '+' expr {
- $$ = new Expression();
- $$->type = "+";
- $$->children.push_back($1);
- $$->children.push_back($3);
+ $$ = new Expression("+", $1, $3);
} |
expr '-' expr {
- $$ = new Expression();
- $$->type = "-";
- $$->children.push_back($1);
- $$->children.push_back($3);
+ $$ = new Expression("-", $1, $3);
} |
expr '<' expr {
- $$ = new Expression();
- $$->type = "<";
- $$->children.push_back($1);
- $$->children.push_back($3);
+ $$ = new Expression("<", $1, $3);
} |
expr LE expr {
- $$ = new Expression();
- $$->type = "<=";
- $$->children.push_back($1);
- $$->children.push_back($3);
+ $$ = new Expression("<=", $1, $3);
} |
expr EQ expr {
- $$ = new Expression();
- $$->type = "==";
- $$->children.push_back($1);
- $$->children.push_back($3);
+ $$ = new Expression("==", $1, $3);
} |
expr NE expr {
- $$ = new Expression();
- $$->type = "!=";
- $$->children.push_back($1);
- $$->children.push_back($3);
+ $$ = new Expression("!=", $1, $3);
} |
expr GE expr {
- $$ = new Expression();
- $$->type = ">=";
- $$->children.push_back($1);
- $$->children.push_back($3);
+ $$ = new Expression(">=", $1, $3);
} |
expr '>' expr {
- $$ = new Expression();
- $$->type = ">";
- $$->children.push_back($1);
- $$->children.push_back($3);
+ $$ = new Expression(">", $1, $3);
} |
expr AND expr {
- $$ = new Expression();
- $$->type = "&&";
- $$->children.push_back($1);
- $$->children.push_back($3);
+ $$ = new Expression("&&", $1, $3);
} |
expr OR expr {
- $$ = new Expression();
- $$->type = "||";
- $$->children.push_back($1);
- $$->children.push_back($3);
+ $$ = new Expression("||", $1, $3);
} |
'+' expr {
$$ = $2;
} |
'-' expr {
- $$ = new Expression();
- $$->type = "I";
- $$->children.push_back($2);
+ $$ = new Expression("I", $2);
} |
'!' expr {
- $$ = new Expression();
- $$->type = "!";
- $$->children.push_back($2);
+ $$ = new Expression("!", $2);
} |
'(' expr ')' {
$$ = $2;
@@ -425,10 +352,7 @@ expr '?' expr ':' expr {
$$->children.push_back($5);
} |
expr '[' expr ']' {
- $$ = new Expression();
- $$->type = "[]";
- $$->children.push_back($1);
- $$->children.push_back($3);
+ $$ = new Expression("[]", $1, $3);
} |
TOK_ID '(' arguments_call ')' {
$$ = new Expression();
@@ -444,9 +368,7 @@ optional_commas:
vector_expr:
expr {
- $$ = new Expression();
- $$->type = 'V';
- $$->children.push_back($1);
+ $$ = new Expression("V", $1);
} |
vector_expr ',' optional_commas expr {
$$ = $1;
@@ -513,19 +435,18 @@ 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;
}
-Module *parse(const char *text, const char *path, int debug)
+FileModule *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();
- module_stack.clear();
- Module *rootmodule = currmodule = new Module();
+ rootmodule = new FileModule();
rootmodule->setModulePath(path);
+ scope_stack.push(&rootmodule->scope);
// PRINTB_NOCACHE("New module: %s %p", "root" % rootmodule);
parserdebug = debug;
@@ -536,5 +457,6 @@ Module *parse(const char *text, const char *path, int debug)
if (parserretval != 0) return NULL;
parser_error_pos = -1;
+ scope_stack.pop();
return rootmodule;
}
diff --git a/src/primitives.cc b/src/primitives.cc
index 184b40c..be1ec6f 100644
--- a/src/primitives.cc
+++ b/src/primitives.cc
@@ -56,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 EvalContext *evalctx) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
class PrimitiveNode : public AbstractPolyNode
@@ -105,7 +105,7 @@ public:
virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const;
};
-AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+AbstractNode *PrimitiveModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
PrimitiveNode *node = new PrimitiveNode(inst, this->type);
@@ -137,7 +137,7 @@ AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstanti
args += Assignment("points", NULL), Assignment("paths", NULL), Assignment("convexity", NULL);
break;
default:
- assert(false && "PrimitiveModule::evaluate(): Unknown node type");
+ assert(false && "PrimitiveModule::instantiate(): Unknown node type");
}
Context c(ctx);
diff --git a/src/projection.cc b/src/projection.cc
index eeed411..8d8cee6 100644
--- a/src/projection.cc
+++ b/src/projection.cc
@@ -41,10 +41,10 @@ class ProjectionModule : public AbstractModule
{
public:
ProjectionModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+AbstractNode *ProjectionModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
ProjectionNode *node = new ProjectionNode(inst);
@@ -62,8 +62,8 @@ AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstant
if (cut.type() == Value::BOOL)
node->cut_mode = cut.toBool();
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
return node;
}
diff --git a/src/render.cc b/src/render.cc
index bb08c0c..5097661 100644
--- a/src/render.cc
+++ b/src/render.cc
@@ -38,10 +38,10 @@ class RenderModule : public AbstractModule
{
public:
RenderModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *RenderModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+AbstractNode *RenderModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
RenderNode *node = new RenderNode(inst);
@@ -55,8 +55,8 @@ AbstractNode *RenderModule::evaluate(const Context *ctx, const ModuleInstantiati
if (v.type() == Value::NUMBER)
node->convexity = (int)v.toDouble();
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
return node;
}
diff --git a/src/rotateextrude.cc b/src/rotateextrude.cc
index b6edb8b..2f9a28b 100644
--- a/src/rotateextrude.cc
+++ b/src/rotateextrude.cc
@@ -45,10 +45,10 @@ class RotateExtrudeModule : public AbstractModule
{
public:
RotateExtrudeModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+AbstractNode *RotateExtrudeModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
RotateExtrudeNode *node = new RotateExtrudeNode(inst);
@@ -85,8 +85,8 @@ AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInst
node->scale = 1;
if (node->filename.empty()) {
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
}
return node;
diff --git a/src/surface.cc b/src/surface.cc
index d8fa422..b3246c1 100644
--- a/src/surface.cc
+++ b/src/surface.cc
@@ -50,7 +50,7 @@ class SurfaceModule : public AbstractModule
{
public:
SurfaceModule() { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
class SurfaceNode : public AbstractPolyNode
@@ -69,7 +69,7 @@ public:
virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const;
};
-AbstractNode *SurfaceModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+AbstractNode *SurfaceModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
SurfaceNode *node = new SurfaceNode(inst);
node->center = false;
diff --git a/src/transform.cc b/src/transform.cc
index cc026fb..ddf222a 100644
--- a/src/transform.cc
+++ b/src/transform.cc
@@ -50,10 +50,10 @@ class TransformModule : public AbstractModule
public:
transform_type_e type;
TransformModule(transform_type_e type) : type(type) { }
- virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
+ virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
};
-AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+AbstractNode *TransformModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
{
TransformNode *node = new TransformNode(inst);
@@ -175,8 +175,8 @@ AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstanti
}
}
- std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);
- node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());
+ std::vector<AbstractNode *> instantiatednodes = inst->instantiateChildren(evalctx);
+ node->children.insert(node->children.end(), instantiatednodes.begin(), instantiatednodes.end());
return node;
}
diff --git a/src/typedefs.h b/src/typedefs.h
index a6e9077..fd676e2 100644
--- a/src/typedefs.h
+++ b/src/typedefs.h
@@ -6,5 +6,6 @@
typedef std::pair<std::string, class Expression*> Assignment;
typedef std::vector<Assignment> AssignmentList;
+typedef std::vector<class ModuleInstantiation*> ModuleInstantiationList;
#endif
diff --git a/testdata/scad/features/child-tests.scad b/testdata/scad/features/child-tests.scad
index e4e3572..cf983b4 100644
--- a/testdata/scad/features/child-tests.scad
+++ b/testdata/scad/features/child-tests.scad
@@ -1,7 +1,7 @@
$fn=16;
-module parent() {
- for (i=[0:2]) {
+module parent(range=[0:2]) {
+ for (i=range) {
translate([2.5*i,0,0]) child(i);
}
}
@@ -32,3 +32,6 @@ module parent3() {
}
translate([5,3,0]) parent3() { cube(); sphere(); }
+
+// Leaking variables to child list is not allowed
+translate([0,6,0]) parent(range=[0:1], testvar=10) { sphere(); cube(testvar, center=true);}
diff --git a/testdata/scad/misc/localfiles_dir/localfiles_module.scad b/testdata/scad/misc/localfiles_dir/localfiles_module.scad
index b98a49b..2611e71 100644
--- a/testdata/scad/misc/localfiles_dir/localfiles_module.scad
+++ b/testdata/scad/misc/localfiles_dir/localfiles_module.scad
@@ -5,6 +5,5 @@ module localfiles_module()
translate([0,350,0]) rotate_extrude(file="localfile.dxf");
translate([250,0,0]) scale([200,200,50]) surface("localfile.dat");
- // This is not supported:
- // echo(dxf_dim(file="localfile.dxf", name="localfile"));
+ translate([0,-200,0]) sphere(r=dxf_dim(file="localfile.dxf", name="localfile")/2);
}
diff --git a/testdata/scad/misc/variable-scope-sub.scad b/testdata/scad/misc/variable-scope-sub.scad
new file mode 100644
index 0000000..fda9520
--- /dev/null
+++ b/testdata/scad/misc/variable-scope-sub.scad
@@ -0,0 +1,24 @@
+sub_global = 15;
+
+module submodule() {
+ echo($children);
+ echo(submodule_var);
+ submodule_var = 16;
+ module subsubmodule() {
+ echo($children);
+ subsubmodule_var = 17;
+ echo(subsubmodule_var);
+ child(0);
+ }
+ subsubmodule() {child(0); sphere();}
+}
+
+module submodule2() {
+ echo(sub_global);
+ echo($children);
+}
+
+module submain() {
+ echo(global_var); // Undefined global var
+ submodule() {submodule2() sphere(); cube();}
+}
diff --git a/testdata/scad/misc/variable-scope-tests.scad b/testdata/scad/misc/variable-scope-tests.scad
new file mode 100644
index 0000000..8426fbb
--- /dev/null
+++ b/testdata/scad/misc/variable-scope-tests.scad
@@ -0,0 +1,53 @@
+echo("special variable inheritance");
+module special_module(a) {
+ echo(a, $fn);
+ special_module2(a);
+}
+
+module special_module2(b) {
+ echo(a);
+ echo(b, $fn);
+}
+
+special_module(23, $fn=5);
+
+echo("inner variables shadows parameter");
+module inner_variables(a, b) {
+ b = 24;
+ echo(a, b);
+}
+
+inner_variables(5, 6);
+
+echo("user-defined special variables as parameter");
+module user_defined_special($b) {
+ echo($b);
+ user_defined_special2();
+}
+
+module user_defined_special2() {
+ echo($b);
+}
+
+user_defined_special(7);
+
+echo("assign only visible in children's scope");
+module assigning() {
+ echo(c);
+}
+
+module assigning2(c) {
+ echo(c);
+}
+
+assign(c=5) {
+ assigning();
+ assigning2(c);
+}
+
+echo("undeclared variable can still be passed and used");
+module undeclared_var() {
+ echo(d);
+}
+
+undeclared_var(d=6);
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index de4bab7..51abd06 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -13,7 +13,11 @@ include(CMakeParseArguments.cmake)
# Detect Lion and force gcc
IF (APPLE)
EXECUTE_PROCESS(COMMAND sw_vers -productVersion OUTPUT_VARIABLE MACOSX_VERSION)
- IF (NOT ${MACOSX_VERSION} VERSION_LESS "10.7.0")
+ IF (NOT ${MACOSX_VERSION} VERSION_LESS "10.8.0")
+ message("Detected Mountain Lion or later")
+ set(CMAKE_C_COMPILER "gcc")
+ set(CMAKE_CXX_COMPILER "g++")
+ ELSEIF (NOT ${MACOSX_VERSION} VERSION_LESS "10.7.0")
message("Detected Lion or later")
set(CMAKE_C_COMPILER "gcc")
set(CMAKE_CXX_COMPILER "g++")
@@ -325,9 +329,8 @@ if (WIN32)
set(FLEX_UNISTD_FLAG "-DYY_NO_UNISTD_H")
endif()
FLEX_TARGET(OpenSCADlexer ../src/lexer.l ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp COMPILE_FLAGS "-Plexer ${FLEX_UNISTD_FLAG}")
-BISON_TARGET(OpenSCADparser ../src/parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser_yacc.c COMPILE_FLAGS "-p parser")
+BISON_TARGET(OpenSCADparser ../src/parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp COMPILE_FLAGS "-p parser")
ADD_FLEX_BISON_DEPENDENCY(OpenSCADlexer OpenSCADparser)
-set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/parser_yacc.c PROPERTIES LANGUAGE "CXX")
# CGAL
@@ -402,6 +405,7 @@ set(CORE_SOURCES
../src/value.cc
../src/expr.cc
../src/func.cc
+ ../src/localscope.cc
../src/module.cc
../src/ModuleCache.cc
../src/node.cc
@@ -751,7 +755,8 @@ list(APPEND ECHO_FILES ${FUNCTION_FILES}
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/vector-values.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/search-tests.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/recursion-tests.scad
- ${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/variable-scope-tests.scad)
list(APPEND DUMPTEST_FILES ${MINIMAL_FILES} ${FEATURES_FILES} ${EXAMPLE_FILES})
list(APPEND DUMPTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/escape-test.scad
diff --git a/tests/cgalcachetest.cc b/tests/cgalcachetest.cc
index b65a2c8..67d3313 100644
--- a/tests/cgalcachetest.cc
+++ b/tests/cgalcachetest.cc
@@ -129,10 +129,10 @@ int main(int argc, char **argv)
parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- ModuleContext root_ctx;
- root_ctx.registerBuiltin();
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
+ FileModule *root_module;
ModuleInstantiation root_inst("group");
root_module = parsefile(filename);
@@ -145,7 +145,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- AbstractNode *absolute_root_node = root_module->evaluate(&root_ctx, &root_inst);
+ AbstractNode *absolute_root_node = root_module->instantiate(&top_ctx, &root_inst);
AbstractNode *root_node;
// Do we have an explicit root node (! modifier)?
if (!(root_node = find_root_tag(absolute_root_node))) root_node = absolute_root_node;
diff --git a/tests/cgalpngtest.cc b/tests/cgalpngtest.cc
index afc3128..81fc6b4 100644
--- a/tests/cgalpngtest.cc
+++ b/tests/cgalpngtest.cc
@@ -102,10 +102,10 @@ int main(int argc, char **argv)
parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- ModuleContext root_ctx;
- root_ctx.registerBuiltin();
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
+ FileModule *root_module;
ModuleInstantiation root_inst("group");
root_module = parsefile(filename);
@@ -118,7 +118,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- AbstractNode *absolute_root_node = root_module->evaluate(&root_ctx, &root_inst);
+ AbstractNode *absolute_root_node = root_module->instantiate(&top_ctx, &root_inst);
AbstractNode *root_node;
// Do we have an explicit root node (! modifier)?
if (!(root_node = find_root_tag(absolute_root_node))) root_node = absolute_root_node;
diff --git a/tests/cgalstlsanitytest.cc b/tests/cgalstlsanitytest.cc
index 49a3f8e..4be7767 100644
--- a/tests/cgalstlsanitytest.cc
+++ b/tests/cgalstlsanitytest.cc
@@ -84,10 +84,10 @@ int main(int argc, char **argv)
parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- ModuleContext root_ctx;
- root_ctx.registerBuiltin();
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
+ FileModule *root_module;
ModuleInstantiation root_inst("group");
root_module = parsefile(filename);
@@ -100,7 +100,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- AbstractNode *absolute_root_node = root_module->evaluate(&root_ctx, &root_inst);
+ AbstractNode *absolute_root_node = root_module->instantiate(&top_ctx, &root_inst);
AbstractNode *root_node;
// Do we have an explicit root node (! modifier)?
if (!(root_node = find_root_tag(absolute_root_node))) root_node = absolute_root_node;
diff --git a/tests/cgaltest.cc b/tests/cgaltest.cc
index b7ae669..d750da9 100644
--- a/tests/cgaltest.cc
+++ b/tests/cgaltest.cc
@@ -81,10 +81,10 @@ int main(int argc, char **argv)
parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- ModuleContext root_ctx;
- root_ctx.registerBuiltin();
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
+ FileModule *root_module;
ModuleInstantiation root_inst("group");
root_module = parsefile(filename);
@@ -97,7 +97,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- AbstractNode *absolute_root_node = root_module->evaluate(&root_ctx, &root_inst);
+ AbstractNode *absolute_root_node = root_module->instantiate(&top_ctx, &root_inst);
AbstractNode *root_node;
// Do we have an explicit root node (! modifier)?
if (!(root_node = find_root_tag(absolute_root_node))) root_node = absolute_root_node;
diff --git a/tests/csgtermtest.cc b/tests/csgtermtest.cc
index f4a88e0..1460bbd 100644
--- a/tests/csgtermtest.cc
+++ b/tests/csgtermtest.cc
@@ -76,10 +76,10 @@ int main(int argc, char **argv)
parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- ModuleContext root_ctx;
- root_ctx.registerBuiltin();
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
+ FileModule *root_module;
ModuleInstantiation root_inst("group");
const AbstractNode *root_node;
@@ -93,7 +93,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- root_node = root_module->evaluate(&root_ctx, &root_inst);
+ root_node = root_module->instantiate(&top_ctx, &root_inst);
Tree tree(root_node);
diff --git a/tests/csgtestcore.cc b/tests/csgtestcore.cc
index 6da6411..320b533 100644
--- a/tests/csgtestcore.cc
+++ b/tests/csgtestcore.cc
@@ -132,10 +132,10 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type)
parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- ModuleContext root_ctx;
- root_ctx.registerBuiltin();
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
+ FileModule *root_module;
ModuleInstantiation root_inst("group");
if (sysinfo_dump)
@@ -154,7 +154,7 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type)
}
AbstractNode::resetIndexCounter();
- AbstractNode *absolute_root_node = root_module->evaluate(&root_ctx, &root_inst);
+ AbstractNode *absolute_root_node = root_module->instantiate(&top_ctx, &root_inst);
AbstractNode *root_node;
// Do we have an explicit root node (! modifier)?
if (!(root_node = find_root_tag(absolute_root_node))) root_node = absolute_root_node;
diff --git a/tests/csgtexttest.cc b/tests/csgtexttest.cc
index 3e26814..97902f6 100644
--- a/tests/csgtexttest.cc
+++ b/tests/csgtexttest.cc
@@ -80,10 +80,10 @@ int main(int argc, char **argv)
parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- ModuleContext root_ctx;
- root_ctx.registerBuiltin();
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
+ FileModule *root_module;
ModuleInstantiation root_inst("group");
AbstractNode *root_node;
@@ -97,7 +97,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- root_node = root_module->evaluate(&root_ctx, &root_inst);
+ root_node = root_module->instantiate(&top_ctx, &root_inst);
Tree tree;
tree.setRoot(root_node);
diff --git a/tests/dumptest.cc b/tests/dumptest.cc
index e0d2776..e4876fa 100644
--- a/tests/dumptest.cc
+++ b/tests/dumptest.cc
@@ -74,7 +74,6 @@ int main(int argc, char **argv)
const char *filename = argv[1];
const char *outfilename = argv[2];
-
int rc = 0;
Builtins::instance()->initialize();
@@ -86,10 +85,10 @@ int main(int argc, char **argv)
parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- ModuleContext root_ctx;
- root_ctx.registerBuiltin();
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
+ FileModule *root_module;
ModuleInstantiation root_inst("group");
AbstractNode *root_node;
@@ -103,7 +102,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- root_node = root_module->evaluate(&root_ctx, &root_inst);
+ root_node = root_module->instantiate(&top_ctx, &root_inst);
Tree tree;
tree.setRoot(root_node);
@@ -115,10 +114,17 @@ int main(int argc, char **argv)
exit(1);
}
+ fs::current_path(original_path);
std::ofstream outfile;
outfile.open(outfilename);
+ if (!outfile.is_open()) {
+ fprintf(stderr, "Error: Unable to open output file %s\n", outfilename);
+ exit(1);
+ }
+ std::cout << "Opened " << outfilename << "\n";
outfile << dumpstdstr << "\n";
outfile.close();
+ if (outfile.fail()) fprintf(stderr, "Failed to close file\n");
delete root_node;
delete root_module;
@@ -131,7 +137,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- root_node = root_module->evaluate(&root_ctx, &root_inst);
+ root_node = root_module->instantiate(&top_ctx, &root_inst);
tree.setRoot(root_node);
diff --git a/tests/echotest.cc b/tests/echotest.cc
index 9924d11..3051751 100644
--- a/tests/echotest.cc
+++ b/tests/echotest.cc
@@ -88,10 +88,10 @@ int main(int argc, char **argv)
parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- ModuleContext root_ctx;
- root_ctx.registerBuiltin();
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
+ FileModule *root_module;
ModuleInstantiation root_inst("group");
AbstractNode *root_node;
@@ -105,7 +105,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- root_node = root_module->evaluate(&root_ctx, &root_inst);
+ root_node = root_module->instantiate(&top_ctx, &root_inst);
delete root_node;
delete root_module;
diff --git a/tests/modulecachetest.cc b/tests/modulecachetest.cc
index 62f9543..5531461 100644
--- a/tests/modulecachetest.cc
+++ b/tests/modulecachetest.cc
@@ -76,14 +76,13 @@ int main(int argc, char **argv)
parser_init(boosty::stringy(fs::path(argv[0]).branch_path()));
add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries"));
- ModuleContext root_ctx;
- root_ctx.registerBuiltin();
+ ModuleContext top_ctx;
+ top_ctx.registerBuiltin();
- AbstractModule *root_module;
ModuleInstantiation root_inst("group");
AbstractNode *root_node;
- root_module = parsefile(filename);
+ FileModule *root_module = parsefile(filename);
if (!root_module) {
fprintf(stderr, "Error: Unable to parse input file\n");
exit(1);
@@ -94,7 +93,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- root_node = root_module->evaluate(&root_ctx, &root_inst);
+ root_node = root_module->instantiate(&top_ctx, &root_inst);
delete root_node;
delete root_module;
@@ -109,7 +108,7 @@ int main(int argc, char **argv)
}
AbstractNode::resetIndexCounter();
- root_node = root_module->evaluate(&root_ctx, &root_inst);
+ root_node = root_module->instantiate(&top_ctx, &root_inst);
delete root_node;
delete root_module;
diff --git a/tests/regression/cgalpngtest/child-tests-expected.png b/tests/regression/cgalpngtest/child-tests-expected.png
index ed6207c..eb34f18 100644
--- a/tests/regression/cgalpngtest/child-tests-expected.png
+++ b/tests/regression/cgalpngtest/child-tests-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/localfiles-test-expected.png b/tests/regression/cgalpngtest/localfiles-test-expected.png
index 3ad3d96..d0cfd50 100644
--- a/tests/regression/cgalpngtest/localfiles-test-expected.png
+++ b/tests/regression/cgalpngtest/localfiles-test-expected.png
Binary files differ
diff --git a/tests/regression/dumptest/child-tests-expected.txt b/tests/regression/dumptest/child-tests-expected.txt
index 9a886fe..e1a7557 100644
--- a/tests/regression/dumptest/child-tests-expected.txt
+++ b/tests/regression/dumptest/child-tests-expected.txt
@@ -37,4 +37,16 @@
multmatrix([[1, 0, 0, 5], [0, 1, 0, 3], [0, 0, 1, 0], [0, 0, 0, 1]]) {
group();
}
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 6], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ group() {
+ group() {
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ sphere($fn = 16, $fa = 12, $fs = 2, r = 1);
+ }
+ multmatrix([[1, 0, 0, 2.5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ cube(size = [1, 1, 1], center = true);
+ }
+ }
+ }
+ }
diff --git a/tests/regression/dumptest/localfiles-test-expected.txt b/tests/regression/dumptest/localfiles-test-expected.txt
index acdf7e7..7a84e88 100644
--- a/tests/regression/dumptest/localfiles-test-expected.txt
+++ b/tests/regression/dumptest/localfiles-test-expected.txt
@@ -13,5 +13,8 @@
surface(file = "localfiles_dir/localfile.dat", center = false);
}
}
+ multmatrix([[1, 0, 0, 0], [0, 1, 0, -200], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ sphere($fn = 0, $fa = 12, $fs = 2, r = 100);
+ }
}
diff --git a/tests/regression/echotest/variable-scope-tests-expected.txt b/tests/regression/echotest/variable-scope-tests-expected.txt
new file mode 100644
index 0000000..92db05d
--- /dev/null
+++ b/tests/regression/echotest/variable-scope-tests-expected.txt
@@ -0,0 +1,16 @@
+ECHO: "special variable inheritance"
+ECHO: 23, 5
+WARNING: Ignoring unknown variable 'a'.
+ECHO: undef
+ECHO: 23, 5
+ECHO: "inner variables shadows parameter"
+ECHO: 5, 24
+ECHO: "user-defined special variables as parameter"
+ECHO: 7
+ECHO: 7
+ECHO: "assign only visible in children's scope"
+WARNING: Ignoring unknown variable 'c'.
+ECHO: undef
+ECHO: 5
+ECHO: "undeclared variable can still be passed and used"
+ECHO: 6
diff --git a/tests/regression/opencsgtest/child-tests-expected.png b/tests/regression/opencsgtest/child-tests-expected.png
index e8ea39b..2ff902c 100644
--- a/tests/regression/opencsgtest/child-tests-expected.png
+++ b/tests/regression/opencsgtest/child-tests-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/localfiles-test-expected.png b/tests/regression/opencsgtest/localfiles-test-expected.png
index 7bc7909..f280efd 100644
--- a/tests/regression/opencsgtest/localfiles-test-expected.png
+++ b/tests/regression/opencsgtest/localfiles-test-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/child-tests-expected.png b/tests/regression/throwntogethertest/child-tests-expected.png
index 561334e..2ff902c 100644
--- a/tests/regression/throwntogethertest/child-tests-expected.png
+++ b/tests/regression/throwntogethertest/child-tests-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/localfiles-test-expected.png b/tests/regression/throwntogethertest/localfiles-test-expected.png
index 7bc7909..f280efd 100644
--- a/tests/regression/throwntogethertest/localfiles-test-expected.png
+++ b/tests/regression/throwntogethertest/localfiles-test-expected.png
Binary files differ
diff --git a/tests/tests-common.cc b/tests/tests-common.cc
index 703e1c5..ac85e37 100644
--- a/tests/tests-common.cc
+++ b/tests/tests-common.cc
@@ -7,9 +7,9 @@
#include <sstream>
#include <fstream>
-Module *parsefile(const char *filename)
+FileModule *parsefile(const char *filename)
{
- Module *root_module = NULL;
+ FileModule *root_module = NULL;
handle_dep(filename);
std::ifstream ifs(filename);
diff --git a/tests/tests-common.h b/tests/tests-common.h
index 0047562..3393884 100644
--- a/tests/tests-common.h
+++ b/tests/tests-common.h
@@ -1,6 +1,6 @@
#ifndef TESTS_COMMON_H_
#define TESTS_COMMON_H_
-class Module *parsefile(const char *filename);
+class FileModule *parsefile(const char *filename);
#endif
contact: Jan Huwald // Impressum