diff options
74 files changed, 3247 insertions, 628 deletions
| @@ -84,15 +84,15 @@ libraries from aptitude. If you're using Mac, or an older Linux/BSD, there  are build scripts that download and compile the libraries from source.   Follow the instructions for the platform you're compiling on below. -* [Qt4 (4.4 - 4.7)](http://www.qt.nokia.com/) -* [CGAL (3.6 - 4.0.2)](http://www.cgal.org/) - * [GMP (5.0.x)](http://www.gmplib.org/) - * [cmake (2.6 - 2.8, required by CGAL and the test framework)](http://www.cmake.org/) +* [Qt4 (4.4 - 4.8)](http://www.qt.nokia.com/) +* [CGAL (3.6 - 4.1)](http://www.cgal.org/) + * [GMP (5.x)](http://www.gmplib.org/) + * [cmake (2.8, required by CGAL and the test framework)](http://www.cmake.org/)   * [MPFR (3.x)](http://www.mpfr.org/) - * [boost (1.35 - 1.47)](http://www.boost.org/) + * [boost (1.35 - 1.53)](http://www.boost.org/)  * [OpenCSG (1.3.2)](http://www.opencsg.org/)  * [GLEW (1.5.4 ->)](http://glew.sourceforge.net/) -* [Eigen (2.0.13->3.1.1)](http://eigen.tuxfamily.org/) +* [Eigen (2.0.x->3.x)](http://eigen.tuxfamily.org/)  * [GCC C++ Compiler (4.2 ->)](http://gcc.gnu.org/)  * [Bison (2.4)](http://www.gnu.org/software/bison/)  * [Flex (2.5.35)](http://flex.sourceforge.net/) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 252b38b..65ff3a3 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -2,6 +2,7 @@ OpenSCAD 2013.XX  ================  Features: +o Recursive modules and functions is now supported (including cascading child() operations)  o Console output is now enabled on Windows through the openscad.com executable  o Added basic syntax highlighting in the editor  o Mac: Added document icon @@ -12,6 +13,7 @@ o Regression test now creates single monolithic .html file for easier uploading  o value reassignment is now less strict  Bugfixes: +o Importing files is now always relative to the importing script, also for libraries  o OpenCSG rendering sometimes crashed when rendering large models  o We didn't always print a warning when CSG normalization created too many elements  o Binary STLs can now be read on big endian architectures diff --git a/doc/OpenSCAD-polygons.graffle b/doc/OpenSCAD-polygons.graffleBinary files differ index 758d575..63985dc 100644 --- a/doc/OpenSCAD-polygons.graffle +++ b/doc/OpenSCAD-polygons.graffle diff --git a/openscad.pro b/openscad.pro index 42b8ef0..0f3394e 100644 --- a/openscad.pro +++ b/openscad.pro @@ -187,7 +187,8 @@ FORMS   += src/MainWindow.ui \             src/AboutDialog.ui \             src/ProgressWidget.ui -HEADERS += src/version_check.h \ +HEADERS += src/typedefs.h \ +           src/version_check.h \             src/ProgressWidget.h \             src/parsersettings.h \             src/renderer.h \ @@ -203,6 +204,8 @@ HEADERS += src/version_check.h \             src/AboutDialog.h \             src/builtin.h \             src/context.h \ +           src/modcontext.h \ +           src/evalcontext.h \             src/csgterm.h \             src/csgtermnormalizer.h \             src/dxfdata.h \ @@ -272,6 +275,8 @@ SOURCES += src/version_check.cc \             src/module.cc \             src/node.cc \             src/context.cc \ +           src/modcontext.cc \ +           src/evalcontext.cc \             src/csgterm.cc \             src/csgtermnormalizer.cc \             src/polyset.cc \ diff --git a/scripts/macosx-build-dependencies.sh b/scripts/macosx-build-dependencies.sh index 3687041..fa8bb05 100755 --- a/scripts/macosx-build-dependencies.sh +++ b/scripts/macosx-build-dependencies.sh @@ -416,7 +416,7 @@ mkdir -p $SRCDIR $DEPLOYDIR  build_qt 4.8.4  build_eigen 3.1.2  build_gmp 5.1.1 -build_mpfr 3.1.1 +build_mpfr 3.1.2  build_boost 1.53.0  # NB! For CGAL, also update the actual download URL in the function  build_cgal 4.1 diff --git a/src/MainWindow.h b/src/MainWindow.h index 8745b8b..65deb15 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -4,7 +4,7 @@  #include <QMainWindow>  #include "ui_MainWindow.h"  #include "openscad.h" -#include "context.h" +#include "modcontext.h"  #include "module.h"  #include "Tree.h"  #include "memory.h" @@ -29,7 +29,7 @@ public:  	QTimer *autoReloadTimer;  	std::string autoReloadId; -	Context root_ctx; +	ModuleContext root_ctx;  	Module *root_module;      // Result of parsing  	ModuleInstantiation root_inst;    // Top level instance  	AbstractNode *absolute_root_node; // Result of tree evaluation diff --git a/src/builtin.cc b/src/builtin.cc index 6eb32b6..bdd2d3b 100644 --- a/src/builtin.cc +++ b/src/builtin.cc @@ -1,6 +1,7 @@  #include "builtin.h"  #include "function.h"  #include "module.h" +#include "expression.h"  #include <boost/foreach.hpp>  Builtins *Builtins::instance(bool erase) @@ -15,12 +16,12 @@ Builtins *Builtins::instance(bool erase)  void Builtins::init(const char *name, class AbstractModule *module)  { -	Builtins::instance()->builtinmodules[name] = module; +	Builtins::instance()->rootmodule.modules[name] = module;  }  void Builtins::init(const char *name, class AbstractFunction *function)  { -	Builtins::instance()->builtinfunctions[name] = function; +	Builtins::instance()->rootmodule.functions[name] = function;  }  extern void register_builtin_functions(); @@ -77,10 +78,28 @@ std::string Builtins::isDeprecated(const std::string &name)  	return std::string();  } +Builtins::Builtins() +{ +	this->rootmodule.assignments_var.push_back("$fn"); +	this->rootmodule.assignments["$fn"] = new Expression(Value(0.0)); +	this->rootmodule.assignments_var.push_back("$fs"); +	this->rootmodule.assignments["$fs"] = new Expression(Value(2.0)); +	this->rootmodule.assignments_var.push_back("$fa"); +	this->rootmodule.assignments["$fa"] = new Expression(Value(12.0)); +	this->rootmodule.assignments_var.push_back("$t"); +	this->rootmodule.assignments["$t"] = new Expression(Value(0.0)); + +	Value::VectorType zero3; +	zero3.push_back(Value(0.0)); +	zero3.push_back(Value(0.0)); +	zero3.push_back(Value(0.0)); +	Value zero3val(zero3); +	this->rootmodule.assignments_var.push_back("$vpt"); +	this->rootmodule.assignments["$vpt"] = new Expression(zero3val); +	this->rootmodule.assignments_var.push_back("$vpr"); +	this->rootmodule.assignments["$vpr"] = new Expression(zero3val); +} +  Builtins::~Builtins()  { -	BOOST_FOREACH(FunctionContainer::value_type &f, this->builtinfunctions) delete f.second; -	this->builtinfunctions.clear(); -	BOOST_FOREACH(ModuleContainer::value_type &m, this->builtinmodules) delete m.second; -	this->builtinmodules.clear();  } diff --git a/src/builtin.h b/src/builtin.h index bc096e5..564c951 100644 --- a/src/builtin.h +++ b/src/builtin.h @@ -3,6 +3,7 @@  #include <string>  #include <boost/unordered_map.hpp> +#include "module.h"  class Builtins  { @@ -19,16 +20,17 @@ public:  	const FunctionContainer &functions() { return this->builtinfunctions; }  	const ModuleContainer &modules() { return this->builtinmodules; } +	const Module &getRootModule() { return this->rootmodule; } +  private: -	Builtins() { } +	Builtins();  	~Builtins(); +	Module rootmodule;  	FunctionContainer builtinfunctions;  	ModuleContainer builtinmodules;  	boost::unordered_map<std::string, std::string> deprecations;  }; -extern void register_builtin(class Context &ctx); -  #endif diff --git a/src/cgaladv.cc b/src/cgaladv.cc index a4cb5ec..aad3a95 100644 --- a/src/cgaladv.cc +++ b/src/cgaladv.cc @@ -26,7 +26,7 @@  #include "cgaladvnode.h"  #include "module.h" -#include "context.h" +#include "evalcontext.h"  #include "builtin.h"  #include "PolySetEvaluator.h"  #include <sstream> @@ -39,30 +39,29 @@ class CgaladvModule : public AbstractModule  public:  	cgaladv_type_e type;  	CgaladvModule(cgaladv_type_e type) : type(type) { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  }; -AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	CgaladvNode *node = new CgaladvNode(inst, type); -	std::vector<std::string> argnames; -	std::vector<Expression*> argexpr; +	AssignmentList args;  	if (type == MINKOWSKI) -		argnames += "convexity"; +		args += Assignment("convexity", NULL);  	if (type == GLIDE) -		argnames += "path", "convexity"; +		args += Assignment("path", NULL), Assignment("convexity", NULL);  	if (type == SUBDIV) -		argnames += "type", "level", "convexity"; +		args += Assignment("type", NULL), Assignment("level", NULL), Assignment("convexity", NULL);  	if (type == RESIZE) -		argnames += "newsize", "auto"; +		args += Assignment("newsize", NULL), Assignment("auto", NULL);  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	Value convexity, path, subdiv_type, level; @@ -111,7 +110,7 @@ AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiat  	if (node->level <= 1)  		node->level = 1; -	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); +	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);  	node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  	return node; diff --git a/src/color.cc b/src/color.cc index acca652..6c3aaef 100644 --- a/src/color.cc +++ b/src/color.cc @@ -26,7 +26,7 @@  #include "colornode.h"  #include "module.h" -#include "context.h" +#include "evalcontext.h"  #include "builtin.h"  #include "printutils.h"  #include <sstream> @@ -40,27 +40,26 @@ class ColorModule : public AbstractModule  {  public:  	ColorModule() { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  private:  	static boost::unordered_map<std::string, Color4f> colormap;  };  #include "colormap.h" -AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	ColorNode *node = new ColorNode(inst);  	node->color[0] = node->color[1] = node->color[2] = -1.0;  	node->color[3] = 1.0; -	std::vector<std::string> argnames; -	std::vector<Expression*> argexpr; +	AssignmentList args; -	argnames += "c", "alpha"; +	args += Assignment("c", NULL), Assignment("alpha", NULL);  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	Value v = c.lookup_variable("c");  	if (v.type() == Value::VECTOR) { @@ -88,7 +87,7 @@ AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiatio  		node->color[3] = alpha.toDouble();  	} -	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); +	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);  	node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  	return node; diff --git a/src/context.cc b/src/context.cc index 97ea5b9..706407c 100644 --- a/src/context.cc +++ b/src/context.cc @@ -25,6 +25,7 @@   */  #include "context.h" +#include "evalcontext.h"  #include "expression.h"  #include "function.h"  #include "module.h" @@ -40,26 +41,11 @@ std::vector<const Context*> Context::ctx_stack;  /*!  	Initializes this context. Optionally initializes a context for an external library  */ -Context::Context(const Context *parent, const Module *library) -	: parent(parent), inst_p(NULL) +Context::Context(const Context *parent) +	: parent(parent)  { -	if (parent) recursioncount = parent->recursioncount;  	ctx_stack.push_back(this);  	if (parent) document_path = parent->document_path; -	if (library) { -		// FIXME: Don't access module members directly -		this->functions_p = &library->functions; -		this->modules_p = &library->modules; -		this->usedlibs_p = &library->usedlibs; -		BOOST_FOREACH(const std::string &var, library->assignments_var) { -			this->set_variable(var, library->assignments.at(var)->evaluate(this)); -		} -	} -	else { -		functions_p = NULL; -		modules_p = NULL; -		usedlibs_p = NULL; -	}  }  Context::~Context() @@ -68,25 +54,26 @@ Context::~Context()  }  /*! -	Initialize context from argument lists (function call/module instantiation) - */ -void Context::args(const std::vector<std::string> &argnames,  -									 const std::vector<Expression*> &argexpr, -									 const std::vector<std::string> &call_argnames,  -									 const std::vector<Value> &call_argvalues) +	Initialize context from a module argument list and a evaluation context +	which may pass variables which will be preferred over default values. +*/ +void Context::setVariables(const AssignmentList &args, +													 const EvalContext *evalctx)  { -	for (size_t i=0; i<argnames.size(); i++) { -		set_variable(argnames[i], i < argexpr.size() && argexpr[i] ?  -								 argexpr[i]->evaluate(this->parent) : Value()); +	BOOST_FOREACH(const Assignment &arg, args) { +		set_variable(arg.first, arg.second ? arg.second->evaluate(this->parent) : Value());  	} -	size_t posarg = 0; -	for (size_t i=0; i<call_argnames.size(); i++) { -		if (call_argnames[i].empty()) { -			if (posarg < argnames.size()) -				set_variable(argnames[posarg++], call_argvalues[i]); -		} else { -			set_variable(call_argnames[i], call_argvalues[i]); +	if (evalctx) { +		size_t posarg = 0; +		for (size_t i=0; i<evalctx->eval_arguments.size(); i++) { +			const std::string &name = evalctx->eval_arguments[i].first; +			const Value &val = evalctx->eval_arguments[i].second; +			if (name.empty()) { +				if (posarg < args.size()) this->set_variable(args[posarg++].first, val); +			} else { +				this->set_variable(name, val); +			}  		}  	}  } @@ -130,61 +117,16 @@ Value Context::lookup_variable(const std::string &name, bool silent) const  	return Value();  } -class RecursionGuard -{ -public: -	RecursionGuard(const Context &c, const std::string &name) : c(c), name(name) { c.recursioncount[name]++; } -	~RecursionGuard() { if (--c.recursioncount[name] == 0) c.recursioncount.erase(name); } -	bool recursion_detected() const { return (c.recursioncount[name] > 100); } -private: -	const Context &c; -	const std::string &name; -}; - -Value Context::evaluate_function(const std::string &name,  -																 const std::vector<std::string> &argnames,  -																 const std::vector<Value> &argvalues) const +Value Context::evaluate_function(const std::string &name, const EvalContext *evalctx) const  { -	RecursionGuard g(*this, name); -	if (g.recursion_detected()) {  -		PRINTB("Recursion detected calling function '%s'", name); -		return Value(); -	} -	if (this->functions_p && this->functions_p->find(name) != this->functions_p->end()) -		return this->functions_p->find(name)->second->evaluate(this, argnames, argvalues); -	if (this->usedlibs_p) { -		BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { -			if (m.second->functions.find(name) != m.second->functions.end()) { -				Context ctx(this->parent, m.second); -				return m.second->functions[name]->evaluate(&ctx, argnames, argvalues); -			} -		} -	} -	if (this->parent) return this->parent->evaluate_function(name, argnames, argvalues); +	if (this->parent) return this->parent->evaluate_function(name, evalctx);  	PRINTB("WARNING: Ignoring unknown function '%s'.", name);  	return Value();  } -AbstractNode *Context::evaluate_module(const ModuleInstantiation &inst) const +AbstractNode *Context::evaluate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const  { -	if (this->modules_p && this->modules_p->find(inst.name()) != this->modules_p->end()) { -		AbstractModule *m = this->modules_p->find(inst.name())->second; -		std::string replacement = Builtins::instance()->isDeprecated(inst.name()); -		if (!replacement.empty()) { -			PRINTB("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", inst.name() % replacement); -		} -		return m->evaluate(this, &inst); -	} -	if (this->usedlibs_p) { -		BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { -			assert(m.second); -			if (m.second->modules.find(inst.name()) != m.second->modules.end()) { -				Context ctx(this->parent, m.second); -				return m.second->modules[inst.name()]->evaluate(&ctx, &inst); -			} -		} -	} -	if (this->parent) return this->parent->evaluate_module(inst); +	if (this->parent) return this->parent->evaluate_module(inst, evalctx);  	PRINTB("WARNING: Ignoring unknown module '%s'.", inst.name());  	return NULL;  } @@ -202,22 +144,34 @@ std::string Context::getAbsolutePath(const std::string &filename) const  	}  } -void register_builtin(Context &ctx) +#ifdef DEBUG +void Context::dump(const AbstractModule *mod, const ModuleInstantiation *inst)  { -	ctx.functions_p = &Builtins::instance()->functions(); -	ctx.modules_p = &Builtins::instance()->modules(); -	ctx.set_variable("$fn", Value(0.0)); -	ctx.set_variable("$fs", Value(2.0)); -	ctx.set_variable("$fa", Value(12.0)); -	ctx.set_variable("$t", Value(0.0)); -	 -	Value::VectorType zero3; -	zero3.push_back(Value(0.0)); -	zero3.push_back(Value(0.0)); -	zero3.push_back(Value(0.0)); -	Value zero3val(zero3); -	ctx.set_variable("$vpt", zero3val); -	ctx.set_variable("$vpr", zero3val); +	if (inst)  +		PRINTB("ModuleContext %p (%p) for %s inst (%p)", this % this->parent % inst->name() % inst); +	else  +		PRINTB("Context: %p (%p)", this % this->parent); +	PRINTB("  document path: %s", this->document_path); +	if (mod) { +		const Module *m = dynamic_cast<const Module*>(mod); +		if (m) { +			PRINT("  module args:"); +			BOOST_FOREACH(const Assignment &arg, m->definition_arguments) { +				PRINTB("    %s = %s", arg.first % variables[arg.first]); +			} +		} +	} +	typedef std::pair<std::string, Value> ValueMapType; +	PRINT("  vars:"); +  BOOST_FOREACH(const ValueMapType &v, constants) { +	  PRINTB("    %s = %s", v.first % v.second); +	}		 +  BOOST_FOREACH(const ValueMapType &v, variables) { +	  PRINTB("    %s = %s", v.first % v.second); +	}		 +  BOOST_FOREACH(const ValueMapType &v, config_variables) { +	  PRINTB("    %s = %s", v.first % v.second); +	}		 -	ctx.set_constant("PI",Value(M_PI));  } +#endif diff --git a/src/context.h b/src/context.h index eb9a175..51fc45c 100644 --- a/src/context.h +++ b/src/context.h @@ -5,48 +5,46 @@  #include <vector>  #include <boost/unordered_map.hpp>  #include "value.h" +#include "typedefs.h"  class Context  {  public: -	Context(const Context *parent = NULL, const class Module *library = NULL); -	~Context(); +	Context(const Context *parent = NULL); +	virtual ~Context(); -	void args(const std::vector<std::string> &argnames,  -						const std::vector<class Expression*> &argexpr,  -						const std::vector<std::string> &call_argnames,  -						const std::vector<Value> &call_argvalues); +	virtual Value evaluate_function(const std::string &name, const class EvalContext *evalctx) const; +	virtual class AbstractNode *evaluate_module(const class ModuleInstantiation &inst, const EvalContext *evalctx) const; + +	void setVariables(const AssignmentList &args, +										const class EvalContext *evalctx = NULL);  	void set_variable(const std::string &name, const Value &value);  	void set_constant(const std::string &name, const Value &value);  	Value lookup_variable(const std::string &name, bool silent = false) const; -	Value evaluate_function(const std::string &name,  -													const std::vector<std::string> &argnames,  -													const std::vector<Value> &argvalues) const; -	class AbstractNode *evaluate_module(const class ModuleInstantiation &inst) const;  	void setDocumentPath(const std::string &path) { this->document_path = path; } +	const std::string &documentPath() const { return this->document_path; }  	std::string getAbsolutePath(const std::string &filename) const;  public:  	const Context *parent; -	const boost::unordered_map<std::string, class AbstractFunction*> *functions_p; -	const boost::unordered_map<std::string, class AbstractModule*> *modules_p; -	typedef boost::unordered_map<std::string, class Module*> ModuleContainer; -	const ModuleContainer *usedlibs_p; -	const ModuleInstantiation *inst_p;  	static std::vector<const Context*> ctx_stack; -	mutable boost::unordered_map<std::string, int> recursioncount; - -private: +protected:  	typedef boost::unordered_map<std::string, Value> ValueMap;  	ValueMap constants;  	ValueMap variables;  	ValueMap config_variables; +  	std::string document_path; + +#ifdef DEBUG +public: +	virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst); +#endif  };  #endif diff --git a/src/control.cc b/src/control.cc index 44847f5..d47eec0 100644 --- a/src/control.cc +++ b/src/control.cc @@ -26,7 +26,8 @@  #include "module.h"  #include "node.h" -#include "context.h" +#include "evalcontext.h" +#include "modcontext.h"  #include "builtin.h"  #include "printutils.h"  #include <sstream> @@ -45,18 +46,16 @@ class ControlModule : public AbstractModule  public:  	control_type_e type;  	ControlModule(control_type_e type) : type(type) { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  };  void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l,  -							const std::vector<std::string> &call_argnames,  -							const std::vector<Value> &call_argvalues,  -							const Context *arg_context) +							const Context *ctx, const EvalContext *evalctx)  { -	if (call_argnames.size() > l) { -		const std::string &it_name = call_argnames[l]; -		const Value &it_values = call_argvalues[l]; -		Context c(arg_context); +	if (evalctx->eval_arguments.size() > l) { +		const std::string &it_name = evalctx->eval_arguments[l].first; +		const Value &it_values = evalctx->eval_arguments[l].second; +		Context c(ctx);  		if (it_values.type() == Value::RANGE) {  			Value::RangeType range = it_values.toRange();  			if (range.end < range.begin) { @@ -67,55 +66,69 @@ void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l,  			if (range.step > 0 && (range.begin-range.end)/range.step < 10000) {  				for (double i = range.begin; i <= range.end; i += range.step) {  					c.set_variable(it_name, Value(i)); -					for_eval(node, inst, l+1, call_argnames, call_argvalues, &c); +					for_eval(node, inst, l+1, &c, evalctx);  				}  			}  		}  		else if (it_values.type() == Value::VECTOR) {  			for (size_t i = 0; i < it_values.toVector().size(); i++) {  				c.set_variable(it_name, it_values.toVector()[i]); -				for_eval(node, inst, l+1, call_argnames, call_argvalues, &c); +				for_eval(node, inst, l+1, &c, evalctx);  			}  		}  		else if (it_values.type() != Value::UNDEFINED) {  			c.set_variable(it_name, it_values); -			for_eval(node, inst, l+1, call_argnames, call_argvalues, &c); +			for_eval(node, inst, l+1, &c, evalctx);  		}  	} else if (l > 0) { -		std::vector<AbstractNode *> evaluatednodes = inst.evaluateChildren(arg_context); +		std::vector<AbstractNode *> evaluatednodes = inst.evaluateChildren(ctx);  		node.children.insert(node.children.end(), evaluatednodes.begin(), evaluatednodes.end());  	}  } -AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation *inst) const +AbstractNode *ControlModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	AbstractNode *node = NULL;  	if (type == CHILD)  	{ -		size_t n = 0; -		if (inst->argvalues.size() > 0) { +		int n = 0; +		if (evalctx->eval_arguments.size() > 0) {  			double v; -			if (inst->argvalues[0].getDouble(v)) { -				if (v < 0) return NULL; // Disallow negative child indices +			if (evalctx->eval_arguments[0].second.getDouble(v)) {  				n = trunc(v); +				if (n < 0) { +					PRINTB("WARNING: Negative child index (%d) not allowed", n); +					return NULL; // Disallow negative child indices +				}  			}  		} -		for (int i = Context::ctx_stack.size()-1; i >= 0; i--) { -			const Context *c = Context::ctx_stack[i]; -			if (c->inst_p) { -				if (n < c->inst_p->children.size()) { -					node = c->inst_p->children[n]->evaluate(c->inst_p->ctx); -					// FIXME: We'd like to inherit any tags from the ModuleInstantiation -					// given as parameter to this method. However, the instantition which belongs -					// to the returned node cannot be changed. This causes the test -					// features/child-background.scad to fail. + +		// Find the last custom module invocation, which will contain +		// an eval context with the children of the module invokation +		const Context *tmpc = evalctx; +		while (tmpc->parent) { +			const ModuleContext *filectx = dynamic_cast<const ModuleContext*>(tmpc->parent); +			if (filectx) { +        // This will trigger if trying to invoke child from the root of any file +        // assert(filectx->evalctx); + +				if (filectx->evalctx) { +					if (n < filectx->evalctx->children.size()) { +						node = filectx->evalctx->children[n]->evaluate_instance(filectx->evalctx); +					} +					else { +						// How to deal with negative objects in this case? +            // (e.g. first child of difference is invalid) +						PRINTB("WARNING: Child index (%d) out of bounds (%d children)",  +									 n % filectx->evalctx->children.size()); +					}  				}  				return node;  			} -			c = c->parent; +			tmpc = tmpc->parent;  		} -		return NULL; +		return node;  	}  	if (type == INT_FOR) @@ -127,20 +140,20 @@ AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation  	{  		std::stringstream msg;  		msg << "ECHO: "; -		for (size_t i = 0; i < inst->argnames.size(); i++) { +		for (size_t i = 0; i < inst->arguments.size(); i++) {  			if (i > 0) msg << ", "; -			if (!inst->argnames[i].empty()) msg << inst->argnames[i] << " = "; -			msg << inst->argvalues[i]; +			if (!evalctx->eval_arguments[i].first.empty()) msg << evalctx->eval_arguments[i].first << " = "; +			msg << evalctx->eval_arguments[i].second;  		}  		PRINTB("%s", msg.str());  	}  	if (type == ASSIGN)  	{ -		Context c(inst->ctx); -		for (size_t i = 0; i < inst->argnames.size(); i++) { -			if (!inst->argnames[i].empty()) -				c.set_variable(inst->argnames[i], inst->argvalues[i]); +		Context c(evalctx); +		for (size_t i = 0; i < evalctx->eval_arguments.size(); i++) { +			if (!evalctx->eval_arguments[i].first.empty()) +				c.set_variable(evalctx->eval_arguments[i].first, evalctx->eval_arguments[i].second);  		}  		std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(&c);  		node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end()); @@ -148,18 +161,18 @@ AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation  	if (type == FOR || type == INT_FOR)  	{ -		for_eval(*node, *inst, 0, inst->argnames, inst->argvalues, inst->ctx); +		for_eval(*node, *inst, 0, evalctx, evalctx);  	}  	if (type == IF)  	{  		const IfElseModuleInstantiation *ifelse = dynamic_cast<const IfElseModuleInstantiation*>(inst); -		if (ifelse->argvalues.size() > 0 && ifelse->argvalues[0].toBool()) { -			std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateChildren(); +		if (evalctx->eval_arguments.size() > 0 && evalctx->eval_arguments[0].second.toBool()) { +			std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateChildren(evalctx);  			node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  		}  		else { -			std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateElseChildren(); +			std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateElseChildren(evalctx);  			node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  		}  	} diff --git a/src/csgops.cc b/src/csgops.cc index 7524559..425b747 100644 --- a/src/csgops.cc +++ b/src/csgops.cc @@ -26,6 +26,7 @@  #include "csgnode.h" +#include "evalcontext.h"  #include "module.h"  #include "csgterm.h"  #include "builtin.h" @@ -37,13 +38,13 @@ class CsgModule : public AbstractModule  public:  	csg_type_e type;  	CsgModule(csg_type_e type) : type(type) { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  }; -AbstractNode *CsgModule::evaluate(const Context*, const ModuleInstantiation *inst) const +AbstractNode *CsgModule::evaluate(const Context*, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	CsgNode *node = new CsgNode(inst, type); -	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); +	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);  	node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  	return node;  } diff --git a/src/dxfdim.cc b/src/dxfdim.cc index 1ed37fa..fbc24c4 100644 --- a/src/dxfdim.cc +++ b/src/dxfdim.cc @@ -30,7 +30,7 @@  #include "dxfdata.h"  #include "builtin.h"  #include "printutils.h" -#include "context.h" +#include "evalcontext.h"  #include "mathc99.h"  #include <sstream> @@ -40,7 +40,7 @@ boost::unordered_map<std::string,Value> dxf_dim_cache;  boost::unordered_map<std::string,Value> dxf_cross_cache;  namespace fs = boost::filesystem; -Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args) +Value builtin_dxf_dim(const Context *ctx, const EvalContext *evalctx)  {  	std::string filename;  	std::string layername; @@ -49,23 +49,33 @@ Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnam  	double yorigin = 0;  	double scale = 1; -	for (size_t i = 0; i < argnames.size() && i < args.size(); i++) { -		if (argnames[i] == "file") -			filename = ctx->getAbsolutePath(args[i].toString()); -		if (argnames[i] == "layer") -			layername = args[i].toString(); -		if (argnames[i] == "origin") -			args[i].getVec2(xorigin, yorigin); -		if (argnames[i] == "scale") -			args[i].getDouble(scale); -		if (argnames[i] == "name") -			name = args[i].toString(); +  // 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();  	}  	std::stringstream keystream; +	fs::path filepath(filename); +	uintmax_t filesize = -1; +	time_t lastwritetime = -1; +	if (fs::exists(filepath) && fs::is_regular_file(filepath)) { +		filesize = fs::file_size(filepath); +		lastwritetime = fs::last_write_time(filepath); +	}  	keystream << filename << "|" << layername << "|" << name << "|" << xorigin -						<< "|" << yorigin <<"|" << scale << "|" << fs::last_write_time(filename) -						<< "|" << fs::file_size(filename); +						<< "|" << yorigin <<"|" << scale << "|" << lastwritetime +						<< "|" << filesize;  	std::string key = keystream.str();  	if (dxf_dim_cache.find(key) != dxf_dim_cache.end())  		return dxf_dim_cache.find(key)->second; @@ -125,7 +135,7 @@ Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnam  	return Value();  } -Value builtin_dxf_cross(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args) +Value builtin_dxf_cross(const Context *ctx, const EvalContext *evalctx)  {  	std::string filename;  	std::string layername; @@ -133,15 +143,18 @@ Value builtin_dxf_cross(const Context *ctx, const std::vector<std::string> &argn  	double yorigin = 0;  	double scale = 1; -	for (size_t i = 0; i < argnames.size() && i < args.size(); i++) { -		if (argnames[i] == "file") -			filename = ctx->getAbsolutePath(args[i].toString()); -		if (argnames[i] == "layer") -			layername = args[i].toString(); -		if (argnames[i] == "origin") -			args[i].getVec2(xorigin, yorigin); -		if (argnames[i] == "scale") -			args[i].getDouble(scale); +  // 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);  	}  	std::stringstream keystream; diff --git a/src/evalcontext.cc b/src/evalcontext.cc new file mode 100644 index 0000000..b7566e3 --- /dev/null +++ b/src/evalcontext.cc @@ -0,0 +1,40 @@ +#include "evalcontext.h" +#include "module.h" +#include "expression.h" +#include "function.h" +#include "printutils.h" +#include "builtin.h" + +#include <boost/foreach.hpp> + +#ifdef DEBUG +void EvalContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst) +{ +	if (inst)  +		PRINTB("EvalContext %p (%p) for %s inst (%p)", this % this->parent % inst->name() % inst); +	else  +		PRINTB("Context: %p (%p)", this % this->parent); +	PRINTB("  document path: %s", this->document_path); + +	PRINT("  eval args:"); +	for (int i=0;i<this->eval_arguments.size();i++) { +		PRINTB("    %s = %s", this->eval_arguments[i].first % this->eval_arguments[i].second); +	} +	if (this->children.size() > 0) { +		PRINT("    children:"); +		BOOST_FOREACH(const ModuleInstantiation *ch, this->children) { +			PRINTB("      %s", ch->name()); +		} +	} +		 +	if (mod) { +		const Module *m = dynamic_cast<const Module*>(mod); +		if (m) { +			PRINT("  module args:"); +			BOOST_FOREACH(const Assignment &arg, m->definition_arguments) { +				PRINTB("    %s = %s", arg.first % variables[arg.first]); +			} +		} +	} +} +#endif diff --git a/src/evalcontext.h b/src/evalcontext.h new file mode 100644 index 0000000..3d7d222 --- /dev/null +++ b/src/evalcontext.h @@ -0,0 +1,24 @@ +#ifndef EVALCONTEXT_H_ +#define EVALCONTEXT_H_ + +#include "context.h" + +/*! +  This hold the evaluation context (the parameters actually sent +	when calling a module or function, including the children). +*/ +class EvalContext : public Context +{ +public: +	EvalContext(const Context *parent = NULL) : Context(parent) {} +	virtual ~EvalContext() {} + +	std::vector<std::pair<std::string, Value> > eval_arguments; +	std::vector<class ModuleInstantiation *> children; + +#ifdef DEBUG +	virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst); +#endif +}; + +#endif diff --git a/src/expr.cc b/src/expr.cc index 75fc47a..7a8180f 100644 --- a/src/expr.cc +++ b/src/expr.cc @@ -26,7 +26,7 @@  #include "expression.h"  #include "value.h" -#include "context.h" +#include "evalcontext.h"  #include <assert.h>  #include <sstream>  #include <algorithm> @@ -127,13 +127,18 @@ Value Expression::evaluate(const Context *context) const  		return Value();  	}  	if (this->type == "F") { -		Value::VectorType argvalues; -		std::transform(this->children.begin(), this->children.end(),  -									 std::back_inserter(argvalues),  -									 boost::bind(&Expression::evaluate, _1, context)); +		EvalContext c(context); +		for (size_t i=0; i < this->call_arguments.size(); i++) { +			c.eval_arguments.push_back(std::make_pair(this->call_arguments[i].first,  +																								this->call_arguments[i].second->evaluate(context))); +		} +		// Value::VectorType argvalues; +		// std::transform(this->children.begin(), this->children.end(),  +		// 							 std::back_inserter(argvalues),  +		// 							 boost::bind(&Expression::evaluate, _1, context));  		// for (size_t i=0; i < this->children.size(); i++)  		// 	argvalues.push_back(this->children[i]->evaluate(context)); -		return context->evaluate_function(this->call_funcname, this->call_argnames, argvalues); +		return context->evaluate_function(this->call_funcname, &c);  	}  	abort();  } @@ -178,10 +183,11 @@ std::string Expression::toString() const  	}  	else if (this->type == "F") {  		stream << this->call_funcname << "("; -		for (size_t i=0; i < this->children.size(); i++) { +		for (size_t i=0; i < this->call_arguments.size(); i++) { +			const Assignment &arg = this->call_arguments[i];  			if (i > 0) stream << ", "; -			if (!this->call_argnames[i].empty()) stream << this->call_argnames[i]  << " = "; -			stream << *this->children[i]; +			if (!arg.first.empty()) stream << arg.first  << " = "; +			stream << *arg.second;  		}  		stream << ")";  	} diff --git a/src/expression.h b/src/expression.h index 2919b78..06becc0 100644 --- a/src/expression.h +++ b/src/expression.h @@ -4,6 +4,7 @@  #include <string>  #include <vector>  #include "value.h" +#include "typedefs.h"  class Expression  { @@ -14,7 +15,7 @@ public:  	std::string var_name;  	std::string call_funcname; -	std::vector<std::string> call_argnames; +	AssignmentList call_arguments;  	// Boolean: ! && ||  	// Operators: * / % + - diff --git a/src/func.cc b/src/func.cc index 791e957..f2c9835 100644 --- a/src/func.cc +++ b/src/func.cc @@ -26,7 +26,7 @@  #include "function.h"  #include "expression.h" -#include "context.h" +#include "evalcontext.h"  #include "builtin.h"  #include <sstream>  #include <ctime> @@ -34,6 +34,7 @@  #include <algorithm>  #include "stl-utils.h"  #include "printutils.h" +#include <boost/foreach.hpp>  /*   Random numbers @@ -61,7 +62,7 @@ AbstractFunction::~AbstractFunction()  {  } -Value AbstractFunction::evaluate(const Context*, const std::vector<std::string>&, const std::vector<Value>&) const +Value AbstractFunction::evaluate(const Context*, const EvalContext *evalctx) const  {  	return Value();  } @@ -75,16 +76,14 @@ std::string AbstractFunction::dump(const std::string &indent, const std::string  Function::~Function()  { -	std::for_each(this->argexpr.begin(), this->argexpr.end(), del_fun<Expression>()); +	BOOST_FOREACH(const Assignment &arg, this->definition_arguments) delete arg.second;  	delete expr;  } -Value Function::evaluate(const Context *ctx,  -												 const std::vector<std::string> &call_argnames,  -												 const std::vector<Value> &call_argvalues) const +Value Function::evaluate(const Context *ctx, const EvalContext *evalctx) const  {  	Context c(ctx); -	c.args(argnames, argexpr, call_argnames, call_argvalues); +	c.setVariables(definition_arguments, evalctx);  	return expr ? expr->evaluate(&c) : Value();  } @@ -92,10 +91,11 @@ std::string Function::dump(const std::string &indent, const std::string &name) c  {  	std::stringstream dump;  	dump << indent << "function " << name << "("; -	for (size_t i=0; i < argnames.size(); i++) { +	for (size_t i=0; i < definition_arguments.size(); i++) { +		const Assignment &arg = definition_arguments[i];  		if (i > 0) dump << ", "; -		dump << argnames[i]; -		if (argexpr[i]) dump << " = " << *argexpr[i]; +		dump << arg.first; +		if (arg.second) dump << " = " << *arg.second;  	}  	dump << ") = " << *expr << ";\n";  	return dump.str(); @@ -105,9 +105,9 @@ BuiltinFunction::~BuiltinFunction()  {  } -Value BuiltinFunction::evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const +Value BuiltinFunction::evaluate(const Context *ctx, const EvalContext *evalctx) const  { -	return eval_func(ctx, call_argnames, call_argvalues); +	return eval_func(ctx, evalctx);  }  std::string BuiltinFunction::dump(const std::string &indent, const std::string &name) const @@ -127,37 +127,37 @@ static inline double rad2deg(double x)  	return x * 180.0 / M_PI;  } -Value builtin_abs(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_abs(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(fabs(args[0].toDouble())); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(fabs(evalctx->eval_arguments[0].second.toDouble()));  	return Value();  } -Value builtin_sign(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_sign(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value((args[0].toDouble()<0) ? -1.0 : ((args[0].toDouble()>0) ? 1.0 : 0.0)); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value((evalctx->eval_arguments[0].second.toDouble()<0) ? -1.0 : ((evalctx->eval_arguments[0].second.toDouble()>0) ? 1.0 : 0.0));  	return Value();  } -Value builtin_rands(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_rands(const Context *, const EvalContext *evalctx)  {  	bool deterministic = false; -	if (args.size() == 3 && -			args[0].type() == Value::NUMBER &&  -			args[1].type() == Value::NUMBER &&  -			args[2].type() == Value::NUMBER) +	if (evalctx->eval_arguments.size() == 3 && +			evalctx->eval_arguments[0].second.type() == Value::NUMBER &&  +			evalctx->eval_arguments[1].second.type() == Value::NUMBER &&  +			evalctx->eval_arguments[2].second.type() == Value::NUMBER)  	{  		deterministic = false;  	} -	else if (args.size() == 4 &&  -					 args[0].type() == Value::NUMBER &&  -					 args[1].type() == Value::NUMBER &&  -					 args[2].type() == Value::NUMBER &&  -					 args[3].type() == Value::NUMBER) +	else if (evalctx->eval_arguments.size() == 4 &&  +					 evalctx->eval_arguments[0].second.type() == Value::NUMBER &&  +					 evalctx->eval_arguments[1].second.type() == Value::NUMBER &&  +					 evalctx->eval_arguments[2].second.type() == Value::NUMBER &&  +					 evalctx->eval_arguments[3].second.type() == Value::NUMBER)  	{ -		deterministic_rng.seed( (unsigned int) args[3].toDouble() ); +		deterministic_rng.seed( (unsigned int) evalctx->eval_arguments[3].second.toDouble() );  		deterministic = true;  	}  	else @@ -165,11 +165,11 @@ Value builtin_rands(const Context *, const std::vector<std::string>&, const std:  		return Value();  	} -	double min = std::min( args[0].toDouble(), args[1].toDouble() ); -	double max = std::max( args[0].toDouble(), args[1].toDouble() ); +	double min = std::min( evalctx->eval_arguments[0].second.toDouble(), evalctx->eval_arguments[1].second.toDouble() ); +	double max = std::max( evalctx->eval_arguments[0].second.toDouble(), evalctx->eval_arguments[1].second.toDouble() );  	boost::uniform_real<> distributor( min, max );  	Value::VectorType vec; -	for (int i=0; i<args[2].toDouble(); i++) { +	for (int i=0; i<evalctx->eval_arguments[2].second.toDouble(); i++) {  		if ( deterministic ) {  			vec.push_back( Value( distributor( deterministic_rng ) ) );  		} else { @@ -181,169 +181,169 @@ Value builtin_rands(const Context *, const std::vector<std::string>&, const std:  } -Value builtin_min(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_min(const Context *, const EvalContext *evalctx)  { -	if (args.size() >= 1 && args[0].type() == Value::NUMBER) { -		double val = args[0].toDouble(); -		for (size_t i = 1; i < args.size(); i++) -			if (args[1].type() == Value::NUMBER) -				val = fmin(val, args[i].toDouble()); +	if (evalctx->eval_arguments.size() >= 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) { +		double val = evalctx->eval_arguments[0].second.toDouble(); +		for (size_t i = 1; i < evalctx->eval_arguments.size(); i++) +			if (evalctx->eval_arguments[1].second.type() == Value::NUMBER) +				val = fmin(val, evalctx->eval_arguments[i].second.toDouble());  		return Value(val);  	}  	return Value();  } -Value builtin_max(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_max(const Context *, const EvalContext *evalctx)  { -	if (args.size() >= 1 && args[0].type() == Value::NUMBER) { -		double val = args[0].toDouble(); -		for (size_t i = 1; i < args.size(); i++) -			if (args[1].type() == Value::NUMBER) -				val = fmax(val, args[i].toDouble()); +	if (evalctx->eval_arguments.size() >= 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) { +		double val = evalctx->eval_arguments[0].second.toDouble(); +		for (size_t i = 1; i < evalctx->eval_arguments.size(); i++) +			if (evalctx->eval_arguments[1].second.type() == Value::NUMBER) +				val = fmax(val, evalctx->eval_arguments[i].second.toDouble());  		return Value(val);  	}  	return Value();  } -Value builtin_sin(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_sin(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(sin(deg2rad(args[0].toDouble()))); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(sin(deg2rad(evalctx->eval_arguments[0].second.toDouble())));  	return Value();  } -Value builtin_cos(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_cos(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(cos(deg2rad(args[0].toDouble()))); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(cos(deg2rad(evalctx->eval_arguments[0].second.toDouble())));  	return Value();  } -Value builtin_asin(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_asin(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(rad2deg(asin(args[0].toDouble()))); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(rad2deg(asin(evalctx->eval_arguments[0].second.toDouble())));  	return Value();  } -Value builtin_acos(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_acos(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(rad2deg(acos(args[0].toDouble()))); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(rad2deg(acos(evalctx->eval_arguments[0].second.toDouble())));  	return Value();  } -Value builtin_tan(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_tan(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(tan(deg2rad(args[0].toDouble()))); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(tan(deg2rad(evalctx->eval_arguments[0].second.toDouble())));  	return Value();  } -Value builtin_atan(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_atan(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(rad2deg(atan(args[0].toDouble()))); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(rad2deg(atan(evalctx->eval_arguments[0].second.toDouble())));  	return Value();  } -Value builtin_atan2(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_atan2(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER) -		return Value(rad2deg(atan2(args[0].toDouble(), args[1].toDouble()))); +	if (evalctx->eval_arguments.size() == 2 && evalctx->eval_arguments[0].second.type() == Value::NUMBER && evalctx->eval_arguments[1].second.type() == Value::NUMBER) +		return Value(rad2deg(atan2(evalctx->eval_arguments[0].second.toDouble(), evalctx->eval_arguments[1].second.toDouble())));  	return Value();  } -Value builtin_pow(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_pow(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER) -		return Value(pow(args[0].toDouble(), args[1].toDouble())); +	if (evalctx->eval_arguments.size() == 2 && evalctx->eval_arguments[0].second.type() == Value::NUMBER && evalctx->eval_arguments[1].second.type() == Value::NUMBER) +		return Value(pow(evalctx->eval_arguments[0].second.toDouble(), evalctx->eval_arguments[1].second.toDouble()));  	return Value();  } -Value builtin_round(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_round(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(round(args[0].toDouble())); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(round(evalctx->eval_arguments[0].second.toDouble()));  	return Value();  } -Value builtin_ceil(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_ceil(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(ceil(args[0].toDouble())); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(ceil(evalctx->eval_arguments[0].second.toDouble()));  	return Value();  } -Value builtin_floor(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_floor(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(floor(args[0].toDouble())); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(floor(evalctx->eval_arguments[0].second.toDouble()));  	return Value();  } -Value builtin_sqrt(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_sqrt(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(sqrt(args[0].toDouble())); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(sqrt(evalctx->eval_arguments[0].second.toDouble()));  	return Value();  } -Value builtin_exp(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_exp(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(exp(args[0].toDouble())); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(exp(evalctx->eval_arguments[0].second.toDouble()));  	return Value();  } -Value builtin_length(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_length(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1) { -		if (args[0].type() == Value::VECTOR) return Value(int(args[0].toVector().size())); -		if (args[0].type() == Value::STRING) return Value(int(args[0].toString().size())); +	if (evalctx->eval_arguments.size() == 1) { +		if (evalctx->eval_arguments[0].second.type() == Value::VECTOR) return Value(int(evalctx->eval_arguments[0].second.toVector().size())); +		if (evalctx->eval_arguments[0].second.type() == Value::STRING) return Value(int(evalctx->eval_arguments[0].second.toString().size()));  	}  	return Value();  } -Value builtin_log(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_log(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER) -		return Value(log(args[1].toDouble()) / log(args[0].toDouble())); -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(log(args[0].toDouble()) / log(10.0)); +	if (evalctx->eval_arguments.size() == 2 && evalctx->eval_arguments[0].second.type() == Value::NUMBER && evalctx->eval_arguments[1].second.type() == Value::NUMBER) +		return Value(log(evalctx->eval_arguments[1].second.toDouble()) / log(evalctx->eval_arguments[0].second.toDouble())); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(log(evalctx->eval_arguments[0].second.toDouble()) / log(10.0));  	return Value();  } -Value builtin_ln(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_ln(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(log(args[0].toDouble())); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(log(evalctx->eval_arguments[0].second.toDouble()));  	return Value();  } -Value builtin_str(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_str(const Context *, const EvalContext *evalctx)  {  	std::stringstream stream; -	for (size_t i = 0; i < args.size(); i++) { -		stream << args[i].toString(); +	for (size_t i = 0; i < evalctx->eval_arguments.size(); i++) { +		stream << evalctx->eval_arguments[i].second.toString();  	}  	return Value(stream.str());  } -Value builtin_lookup(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_lookup(const Context *, const EvalContext *evalctx)  {  	double p, low_p, low_v, high_p, high_v; -	if (args.size() < 2 ||                     // Needs two args -			!args[0].getDouble(p) ||                  // First must be a number -			args[1].toVector().size() < 2 ||       // Second must be a vector of vectors -			args[1].toVector()[0].toVector().size() < 2) +	if (evalctx->eval_arguments.size() < 2 ||                     // Needs two args +			!evalctx->eval_arguments[0].second.getDouble(p) ||                  // First must be a number +			evalctx->eval_arguments[1].second.toVector().size() < 2 ||       // Second must be a vector of vectors +			evalctx->eval_arguments[1].second.toVector()[0].toVector().size() < 2)  		return Value(); -	if (!args[1].toVector()[0].getVec2(low_p, low_v) || !args[1].toVector()[0].getVec2(high_p, high_v)) +	if (!evalctx->eval_arguments[1].second.toVector()[0].getVec2(low_p, low_v) || !evalctx->eval_arguments[1].second.toVector()[0].getVec2(high_p, high_v))  		return Value(); -	for (size_t i = 1; i < args[1].toVector().size(); i++) { +	for (size_t i = 1; i < evalctx->eval_arguments[1].second.toVector().size(); i++) {  		double this_p, this_v; -		if (args[1].toVector()[i].getVec2(this_p, this_v)) { +		if (evalctx->eval_arguments[1].second.toVector()[i].getVec2(this_p, this_v)) {  			if (this_p <= p && (this_p > low_p || low_p > p)) {  				low_p = this_p;  				low_v = this_v; @@ -404,14 +404,14 @@ Value builtin_lookup(const Context *, const std::vector<std::string>&, const std          - returns [[0,4],[1,5],[2,6],[8]]  */ -Value builtin_search(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_search(const Context *, const EvalContext *evalctx)  { -	if (args.size() < 2) return Value(); +	if (evalctx->eval_arguments.size() < 2) return Value(); -	const Value &findThis = args[0]; -	const Value &searchTable = args[1]; -	unsigned int num_returns_per_match = (args.size() > 2) ? args[2].toDouble() : 1; -	unsigned int index_col_num = (args.size() > 3) ? args[3].toDouble() : 0; +	const Value &findThis = evalctx->eval_arguments[0].second; +	const Value &searchTable = evalctx->eval_arguments[1].second; +	unsigned int num_returns_per_match = (evalctx->eval_arguments.size() > 2) ? evalctx->eval_arguments[2].second.toDouble() : 1; +	unsigned int index_col_num = (evalctx->eval_arguments.size() > 3) ? evalctx->eval_arguments[3].second.toDouble() : 0;  	Value::VectorType returnvec; @@ -499,7 +499,7 @@ Value builtin_search(const Context *, const std::vector<std::string>&, const std  #define QUOTE(x__) # x__  #define QUOTED(x__) QUOTE(x__) -Value builtin_version(const Context *, const std::vector<std::string>&, const std::vector<Value> &) +Value builtin_version(const Context *, const EvalContext *evalctx)  {  	Value::VectorType val;  	val.push_back(Value(double(OPENSCAD_YEAR))); @@ -510,9 +510,9 @@ Value builtin_version(const Context *, const std::vector<std::string>&, const st  	return Value(val);  } -Value builtin_version_num(const Context *ctx, const std::vector<std::string>& call_argnames, const std::vector<Value> &args) +Value builtin_version_num(const Context *ctx, const EvalContext *evalctx)  { -	Value val = (args.size() == 0) ? builtin_version(ctx, call_argnames, args) : args[0]; +	Value val = (evalctx->eval_arguments.size() == 0) ? builtin_version(ctx, evalctx) : evalctx->eval_arguments[0].second;  	double y, m, d = 0;  	if (!val.getVec3(y, m, d)) {  		if (!val.getVec2(y, m)) { diff --git a/src/function.h b/src/function.h index 623ef7e..a1fde3c 100644 --- a/src/function.h +++ b/src/function.h @@ -2,6 +2,7 @@  #define FUNCTION_H_  #include "value.h" +#include "typedefs.h"  #include <string>  #include <vector> @@ -9,35 +10,34 @@ class AbstractFunction  {  public:  	virtual ~AbstractFunction(); -	virtual Value evaluate(const class Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const; +	virtual Value evaluate(const class Context *ctx, const class EvalContext *evalctx) const;  	virtual std::string dump(const std::string &indent, const std::string &name) const;  };  class BuiltinFunction : public AbstractFunction  {  public: -	typedef Value (*eval_func_t)(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args); +	typedef Value (*eval_func_t)(const Context *ctx, const EvalContext *evalctx);  	eval_func_t eval_func;  	BuiltinFunction(eval_func_t f) : eval_func(f) { }  	virtual ~BuiltinFunction(); -	virtual Value evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const; +	virtual Value evaluate(const Context *ctx, const EvalContext *evalctx) const;  	virtual std::string dump(const std::string &indent, const std::string &name) const;  };  class Function : public AbstractFunction  {  public: -	std::vector<std::string> argnames; -	std::vector<class Expression*> argexpr; +	AssignmentList definition_arguments;  	Expression *expr;  	Function() { }  	virtual ~Function(); -	virtual Value evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const; +	virtual Value evaluate(const Context *ctx, const EvalContext *evalctx) const;  	virtual std::string dump(const std::string &indent, const std::string &name) const;  }; diff --git a/src/import.cc b/src/import.cc index e693401..c9a2b91 100644 --- a/src/import.cc +++ b/src/import.cc @@ -28,7 +28,7 @@  #include "module.h"  #include "polyset.h" -#include "context.h" +#include "evalcontext.h"  #include "builtin.h"  #include "dxfdata.h"  #include "dxftess.h" @@ -60,27 +60,37 @@ class ImportModule : public AbstractModule  public:  	import_type_e type;  	ImportModule(import_type_e type = TYPE_UNKNOWN) : type(type) { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  }; -AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  { -	std::vector<std::string> argnames; -	argnames += "file", "layer", "convexity", "origin", "scale"; -	std::vector<Expression*> argexpr; +	AssignmentList args; +	args += Assignment("file", NULL), Assignment("layer", NULL), Assignment("convexity", NULL), Assignment("origin", NULL), Assignment("scale", NULL); +  // FIXME: This is broken. Tag as deprecated and fix  	// Map old argnames to new argnames for compatibility +	// To fix:  +  // o after c.setVariables() +	//   - if "filename" in evalctx: deprecated-warning && v.set_variable("file", value); +	//   - if "layername" in evalctx: deprecated-warning && v.set_variable("layer", value); +#if 0  	std::vector<std::string> inst_argnames = inst->argnames;  	for (size_t i=0; i<inst_argnames.size(); i++) {  		if (inst_argnames[i] == "filename") inst_argnames[i] = "file";  		if (inst_argnames[i] == "layername") inst_argnames[i] = "layer";  	} +#endif  	Context c(ctx); -	c.args(argnames, argexpr, inst_argnames, inst->argvalues); +	c.setDocumentPath(evalctx->documentPath()); +	c.setVariables(args, evalctx); +#if 0 && DEBUG +	c.dump(this, inst); +#endif  	Value v = c.lookup_variable("file"); -	std::string filename = c.getAbsolutePath(v.isUndefined() ? "" : v.toString()); +	std::string filename = inst->getAbsolutePath(v.isUndefined() ? "" : v.toString());  	import_type_e actualtype = this->type;  	if (actualtype == TYPE_UNKNOWN) {  		std::string extraw = boosty::extension_str( fs::path(filename) ); diff --git a/src/lexer.l b/src/lexer.l index 4dff654..6766abc 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -26,6 +26,7 @@  %{ +#include "typedefs.h"  #include "handle_dep.h"  #include "printutils.h"  #include "parsersettings.h" diff --git a/src/linearextrude.cc b/src/linearextrude.cc index 43db907..f4c1112 100644 --- a/src/linearextrude.cc +++ b/src/linearextrude.cc @@ -27,7 +27,7 @@  #include "linearextrudenode.h"  #include "module.h" -#include "context.h" +#include "evalcontext.h"  #include "printutils.h"  #include "builtin.h"  #include "PolySetEvaluator.h" @@ -45,19 +45,18 @@ class LinearExtrudeModule : public AbstractModule  {  public:  	LinearExtrudeModule() { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  }; -AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	LinearExtrudeNode *node = new LinearExtrudeNode(inst); -	std::vector<std::string> argnames; -	argnames += "file", "layer", "height", "origin", "scale", "center", "twist", "slices"; -	std::vector<Expression*> argexpr; +	AssignmentList args; +	args += Assignment("file", NULL), Assignment("layer", NULL), Assignment("height", NULL), Assignment("origin", NULL), Assignment("scale", NULL), Assignment("center", NULL), Assignment("twist", NULL), Assignment("slices", NULL);  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	node->fn = c.lookup_variable("$fn").toDouble();  	node->fs = c.lookup_variable("$fs").toDouble(); @@ -75,16 +74,16 @@ AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInst  	if (!file.isUndefined()) {  		PRINT("DEPRECATED: Support for reading files in linear_extrude will be removed in future releases. Use a child import() instead."); -		node->filename = c.getAbsolutePath(file.toString()); +		node->filename = inst->getAbsolutePath(file.toString());  	}  	// if height not given, and first argument is a number,  	// then assume it should be the height.  	if (c.lookup_variable("height").isUndefined() && -			inst->argnames.size() > 0 &&  -			inst->argnames[0] == "" && -			inst->argvalues[0].type() == Value::NUMBER) { -		height = Value(inst->argvalues[0]); +			evalctx->eval_arguments.size() > 0 &&  +			evalctx->eval_arguments[0].first == "" && +			evalctx->eval_arguments[0].second.type() == Value::NUMBER) { +		height = Value(evalctx->eval_arguments[0].second);  	}  	node->layername = layer.isUndefined() ? "" : layer.toString(); @@ -117,7 +116,7 @@ AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInst  	}  	if (node->filename.empty()) { -		std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); +		std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);  		node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  	} diff --git a/src/mainwin.cc b/src/mainwin.cc index dd855fb..2e69ec2 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -158,7 +158,7 @@ settings_valueList(const QString &key, const QList<int> &defaultList = QList<int  }  MainWindow::MainWindow(const QString &filename) -	: progresswidget(NULL) +	: root_inst("group"), progresswidget(NULL)  {  	setupUi(this); @@ -168,7 +168,7 @@ MainWindow::MainWindow(const QString &filename)  					this, SLOT(actionRenderCGALDone(CGAL_Nef_polyhedron *)));  #endif -	register_builtin(root_ctx); +	root_ctx.registerBuiltin();  	this->openglbox = NULL;  	root_module = NULL; @@ -643,8 +643,8 @@ bool MainWindow::compile(bool reload, bool procevents)  		if (procevents) QApplication::processEvents();  		AbstractNode::resetIndexCounter(); -		this->root_inst = ModuleInstantiation(); -		this->absolute_root_node = this->root_module->evaluate(&this->root_ctx, &this->root_inst); +		this->root_inst = ModuleInstantiation("group"); +		this->absolute_root_node = this->root_module->evaluate(&this->root_ctx, &this->root_inst, NULL);  		if (this->absolute_root_node) {  			// Do we have an explicit root node (! modifier)? diff --git a/src/modcontext.cc b/src/modcontext.cc new file mode 100644 index 0000000..7d123b8 --- /dev/null +++ b/src/modcontext.cc @@ -0,0 +1,152 @@ +#include "modcontext.h" +#include "module.h" +#include "expression.h" +#include "function.h" +#include "printutils.h" +#include "builtin.h" + +#include <boost/foreach.hpp> + +ModuleContext::ModuleContext(const class Module *module, const Context *parent, const EvalContext *evalctx) +	: Context(parent) +{ +	if (module) { +		setModule(*module, evalctx); +	} +	else { +		this->functions_p = NULL; +		this->modules_p = NULL; +		this->usedlibs_p = NULL; +	} +} + +ModuleContext::~ModuleContext() +{ +} + +void ModuleContext::setModule(const Module &module, const EvalContext *evalctx) +{ +	this->setVariables(module.definition_arguments, evalctx); +	this->evalctx = evalctx; + +	// FIXME: Don't access module members directly +	this->functions_p = &module.functions; +	this->modules_p = &module.modules; +	this->usedlibs_p = &module.usedlibs; +	BOOST_FOREACH(const std::string &var, module.assignments_var) { +		this->set_variable(var, module.assignments.at(var)->evaluate(this)); +	} +	 +	if (!module.modulePath().empty()) this->document_path = module.modulePath(); +} + +/*! +	Only used to initialize builtins for the top-level root context +*/ +void ModuleContext::registerBuiltin() +{ +	this->setModule(Builtins::instance()->getRootModule()); +	this->set_constant("PI",Value(M_PI)); +} + +class RecursionGuard +{ +public: +	RecursionGuard(const ModuleContext &c, const std::string &name) : c(c), name(name) {  +		c.recursioncount[name]++;  +	} +	~RecursionGuard() { if (--c.recursioncount[name] == 0) c.recursioncount.erase(name); } +	bool recursion_detected() const { return (c.recursioncount[name] > 100); } +private: +	const ModuleContext &c; +	const std::string &name; +}; + +Value ModuleContext::evaluate_function(const std::string &name, const EvalContext *evalctx) const +{ +	RecursionGuard g(*this, name); +	if (g.recursion_detected()) {  +		PRINTB("Recursion detected calling function '%s'", name); +		return Value(); +	} + +	if (this->functions_p && this->functions_p->find(name) != this->functions_p->end()) { +		return this->functions_p->find(name)->second->evaluate(this, evalctx); +	} +	 +	if (this->usedlibs_p) { +		BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { +			if (m.second->functions.find(name) != m.second->functions.end()) { +				ModuleContext ctx(m.second, this->parent); +				// FIXME: Set document path +#if 0 && DEBUG +				PRINTB("New lib Context for %s func:", name); +				ctx.dump(NULL, NULL); +#endif +				return m.second->functions[name]->evaluate(&ctx, evalctx); +			} +		} +	} +	return Context::evaluate_function(name, evalctx); +} + +AbstractNode *ModuleContext::evaluate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const +{ +	if (this->modules_p && this->modules_p->find(inst.name()) != this->modules_p->end()) { +		AbstractModule *m = this->modules_p->find(inst.name())->second; +		std::string replacement = Builtins::instance()->isDeprecated(inst.name()); +		if (!replacement.empty()) { +			PRINTB("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", inst.name() % replacement); +		} +		return m->evaluate(this, &inst, evalctx); +	} + +	if (this->usedlibs_p) { +		BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { +			assert(m.second); +			if (m.second->modules.find(inst.name()) != m.second->modules.end()) { +				ModuleContext ctx(m.second, this->parent); +				// FIXME: Set document path +#if 0 && DEBUG +				PRINT("New lib Context:"); +				ctx.dump(NULL, &inst); +#endif +				return m.second->modules[inst.name()]->evaluate(&ctx, &inst, evalctx); +			} +		} +	} + +	return Context::evaluate_module(inst, evalctx); +} + +#ifdef DEBUG +void ModuleContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst) +{ +	if (inst)  +		PRINTB("ModuleContext %p (%p) for %s inst (%p) ", this % this->parent % inst->name() % inst); +	else  +		PRINTB("ModuleContext: %p (%p)", this % this->parent); +	PRINTB("  document path: %s", this->document_path); +	if (mod) { +		const Module *m = dynamic_cast<const Module*>(mod); +		if (m) { +			PRINT("  module args:"); +			BOOST_FOREACH(const Assignment &arg, m->definition_arguments) { +				PRINTB("    %s = %s", arg.first % variables[arg.first]); +			} +		} +	} +	typedef std::pair<std::string, Value> ValueMapType; +	PRINT("  vars:"); +  BOOST_FOREACH(const ValueMapType &v, constants) { +	  PRINTB("    %s = %s", v.first % v.second); +	}		 +  BOOST_FOREACH(const ValueMapType &v, variables) { +	  PRINTB("    %s = %s", v.first % v.second); +	}		 +  BOOST_FOREACH(const ValueMapType &v, config_variables) { +	  PRINTB("    %s = %s", v.first % v.second); +	}		 + +} +#endif diff --git a/src/modcontext.h b/src/modcontext.h new file mode 100644 index 0000000..5fce88f --- /dev/null +++ b/src/modcontext.h @@ -0,0 +1,40 @@ +#ifndef FILECONTEXT_H_ +#define FILECONTEXT_H_ + +#include "context.h" +#include <boost/unordered_map.hpp> + +/*! +	This holds the context for a Module definition; keeps track of +	global variables, submodules and functions defined inside a module. + +	NB! every .scad file defines an implicit unnamed module holding the contents of the file. +*/ +class ModuleContext : public Context +{ +public: +	ModuleContext(const class Module *module = NULL, const Context *parent = NULL, const EvalContext *evalctx = NULL); +	virtual ~ModuleContext(); + +	void setModule(const Module &module, const EvalContext *evalctx = NULL); +	void registerBuiltin(); + +	virtual Value evaluate_function(const std::string &name, const EvalContext *evalctx) const; +	virtual AbstractNode *evaluate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const; + +	const boost::unordered_map<std::string, class AbstractFunction*> *functions_p; +	const boost::unordered_map<std::string, class AbstractModule*> *modules_p; +	typedef boost::unordered_map<std::string, class Module*> ModuleContainer; +	const ModuleContainer *usedlibs_p; + +  // FIXME: Points to the eval context for the call to this module. Not sure where it belongs +	const class EvalContext *evalctx; + +#ifdef DEBUG +	virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst); +#endif + +	mutable boost::unordered_map<std::string, int> recursioncount; +}; + +#endif diff --git a/src/module.cc b/src/module.cc index e6dcb57..7d83975 100644 --- a/src/module.cc +++ b/src/module.cc @@ -27,11 +27,15 @@  #include "module.h"  #include "ModuleCache.h"  #include "node.h" -#include "context.h" +#include "modcontext.h" +#include "evalcontext.h"  #include "expression.h"  #include "function.h"  #include "printutils.h" +#include <boost/filesystem.hpp> +namespace fs = boost::filesystem; +#include "boosty.h"  #include <boost/foreach.hpp>  #include <sstream>  #include <sys/stat.h> @@ -40,11 +44,11 @@ AbstractModule::~AbstractModule()  {  } -AbstractNode *AbstractModule::evaluate(const Context*, const ModuleInstantiation *inst) const +AbstractNode *AbstractModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	AbstractNode *node = new AbstractNode(inst); -	node->children = inst->evaluateChildren(); +	node->children = inst->evaluateChildren(evalctx);  	return node;  } @@ -58,8 +62,8 @@ std::string AbstractModule::dump(const std::string &indent, const std::string &n  ModuleInstantiation::~ModuleInstantiation()  { -	BOOST_FOREACH (Expression *v, argexpr) delete v; -	BOOST_FOREACH (ModuleInstantiation *v, children) delete v; +	BOOST_FOREACH(const Assignment &arg, this->arguments) delete arg.second; +	BOOST_FOREACH(ModuleInstantiation *v, children) delete v;  }  IfElseModuleInstantiation::~IfElseModuleInstantiation() @@ -67,15 +71,29 @@ IfElseModuleInstantiation::~IfElseModuleInstantiation()  	BOOST_FOREACH (ModuleInstantiation *v, else_children) delete v;  } +/*! +	Returns the absolute path to the given filename, unless it's empty. + */ +std::string ModuleInstantiation::getAbsolutePath(const std::string &filename) const +{ +	if (!filename.empty() && !boosty::is_absolute(fs::path(filename))) { +		return boosty::absolute(fs::path(this->modpath) / filename).string(); +	} +	else { +		return filename; +	} +} +  std::string ModuleInstantiation::dump(const std::string &indent) const  {  	std::stringstream dump;  	dump << indent;  	dump << modname + "("; -	for (size_t i=0; i < argnames.size(); i++) { +	for (size_t i=0; i < this->arguments.size(); i++) { +		const Assignment &arg = this->arguments[i];  		if (i > 0) dump << ", "; -		if (!argnames[i].empty()) dump << argnames[i] << " = "; -		dump << *argexpr[i]; +		if (!arg.first.empty()) dump << arg.first << " = "; +		dump << *arg.second;  	}  	if (children.size() == 0) {  		dump << ");\n"; @@ -92,43 +110,40 @@ std::string ModuleInstantiation::dump(const std::string &indent) const  	return dump.str();  } -AbstractNode *ModuleInstantiation::evaluate(const Context *ctx) const +AbstractNode *ModuleInstantiation::evaluate_instance(const Context *ctx) const  { -	AbstractNode *node = NULL; -	if (this->ctx) { -		PRINTB("WARNING: Ignoring recursive module instantiation of '%s'.", modname); -	} else { -		// FIXME: Casting away const.. -		ModuleInstantiation *that = (ModuleInstantiation*)this; -		that->argvalues.clear(); -		BOOST_FOREACH (Expression *expr, that->argexpr) { -			that->argvalues.push_back(expr->evaluate(ctx)); -		} -		that->ctx = ctx; -		node = ctx->evaluate_module(*this); -		that->ctx = NULL; -		that->argvalues.clear(); +	EvalContext c(ctx); +	BOOST_FOREACH(const Assignment &arg, this->arguments) { +		c.eval_arguments.push_back(std::make_pair(arg.first, +																							arg.second ?  +																							arg.second->evaluate(ctx) :  +																							Value()));  	} +	c.children = this->children; + +#if 0 && DEBUG +	PRINT("New eval ctx:"); +	c.dump(NULL, this); +#endif +	AbstractNode *node = ctx->evaluate_module(*this, &c); // Passes c as evalctx  	return node;  } -std::vector<AbstractNode*> ModuleInstantiation::evaluateChildren(const Context *ctx) const +std::vector<AbstractNode*> ModuleInstantiation::evaluateChildren(const Context *evalctx) const  { -	if (!ctx) ctx = this->ctx;  	std::vector<AbstractNode*> childnodes;  	BOOST_FOREACH (ModuleInstantiation *modinst, this->children) { -		AbstractNode *node = modinst->evaluate(ctx); +		AbstractNode *node = modinst->evaluate_instance(evalctx);  		if (node) childnodes.push_back(node);  	}  	return childnodes;  } -std::vector<AbstractNode*> IfElseModuleInstantiation::evaluateElseChildren(const Context *ctx) const +std::vector<AbstractNode*> IfElseModuleInstantiation::evaluateElseChildren(const Context *evalctx) const  { -	if (!ctx) ctx = this->ctx;  	std::vector<AbstractNode*> childnodes;  	BOOST_FOREACH (ModuleInstantiation *modinst, this->else_children) { -		AbstractNode *node = modinst->evaluate(ctx); +		AbstractNode *node = modinst->evaluate_instance(evalctx);  		if (node != NULL) childnodes.push_back(node);  	}  	return childnodes; @@ -136,35 +151,24 @@ std::vector<AbstractNode*> IfElseModuleInstantiation::evaluateElseChildren(const  Module::~Module()  { -	BOOST_FOREACH (const AssignmentContainer::value_type &v, assignments) delete v.second; +	BOOST_FOREACH (const Assignment &v, assignments) delete v.second;  	BOOST_FOREACH (FunctionContainer::value_type &f, functions) delete f.second;  	BOOST_FOREACH (AbstractModuleContainer::value_type &m, modules) delete m.second;  	BOOST_FOREACH (ModuleInstantiation *v, children) delete v;  } -AbstractNode *Module::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *Module::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  { -	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); - -	c.inst_p = inst; +	ModuleContext c(this, ctx, evalctx); +	// FIXME: Set document path to the path of the module  	c.set_variable("$children", Value(double(inst->children.size()))); - -	c.functions_p = &functions; -	c.modules_p = &modules; - -	if (!usedlibs.empty()) -		c.usedlibs_p = &usedlibs; -	else -		c.usedlibs_p = NULL; - -	BOOST_FOREACH(const std::string &var, assignments_var) { -		c.set_variable(var, assignments.at(var)->evaluate(&c)); -	} +#if 0 && DEBUG +	c.dump(this, inst); +#endif  	AbstractNode *node = new AbstractNode(inst);  	for (size_t i = 0; i < children.size(); i++) { -		AbstractNode *n = children[i]->evaluate(&c); +		AbstractNode *n = children[i]->evaluate_instance(&c);  		if (n != NULL)  			node->children.push_back(n);  	} @@ -178,10 +182,11 @@ std::string Module::dump(const std::string &indent, const std::string &name) con  	std::string tab;  	if (!name.empty()) {  		dump << indent << "module " << name << "("; -		for (size_t i=0; i < argnames.size(); i++) { +		for (size_t i=0; i < this->definition_arguments.size(); i++) { +			const Assignment &arg = this->definition_arguments[i];  			if (i > 0) dump << ", "; -			dump << argnames[i]; -			if (argexpr[i]) dump << " = " << *argexpr[i]; +			dump << arg.first; +			if (arg.second) dump << " = " << *arg.second;  		}  		dump << ") {\n";  		tab = "\t"; diff --git a/src/module.h b/src/module.h index cc82f81..ace3c1b 100644 --- a/src/module.h +++ b/src/module.h @@ -6,35 +6,37 @@  #include <list>  #include <boost/unordered_map.hpp>  #include "value.h" +#include "typedefs.h"  class ModuleInstantiation  {  public: -	ModuleInstantiation(const std::string &name = "")  -	: ctx(NULL),  -		tag_root(false), tag_highlight(false), tag_background(false), modname(name) { } +	ModuleInstantiation(const std::string &name = "") +	: tag_root(false), tag_highlight(false), tag_background(false), modname(name) { }  	virtual ~ModuleInstantiation();  	std::string dump(const std::string &indent) const; -	class AbstractNode *evaluate(const class Context *ctx) const; -	std::vector<AbstractNode*> evaluateChildren(const Context *ctx = NULL) const; +	class AbstractNode *evaluate_instance(const class Context *ctx) const; +	std::vector<AbstractNode*> evaluateChildren(const Context *evalctx) const; + +	void setPath(const std::string &path) { this->modpath = path; } +	const std::string &path() const { return this->modpath; } +	std::string getAbsolutePath(const std::string &filename) const;  	const std::string &name() const { return this->modname; }  	bool isBackground() const { return this->tag_background; }  	bool isHighlight() const { return this->tag_highlight; }  	bool isRoot() const { return this->tag_root; } -	std::vector<std::string> argnames; -	std::vector<Value> argvalues; -	std::vector<class Expression*> argexpr; +	AssignmentList arguments;  	std::vector<ModuleInstantiation*> children; -	const Context *ctx;  	bool tag_root;  	bool tag_highlight;  	bool tag_background;  protected:  	std::string modname; +	std::string modpath;  	friend class Module;  }; @@ -43,7 +45,7 @@ class IfElseModuleInstantiation : public ModuleInstantiation {  public:  	IfElseModuleInstantiation() : ModuleInstantiation("if") { }  	virtual ~IfElseModuleInstantiation(); -	std::vector<AbstractNode*> evaluateElseChildren(const Context *ctx = NULL) const; +	std::vector<AbstractNode*> evaluateElseChildren(const Context *evalctx) const;  	std::vector<ModuleInstantiation*> else_children;  }; @@ -52,7 +54,7 @@ class AbstractModule  {  public:  	virtual ~AbstractModule(); -	virtual class AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual class AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const class EvalContext *evalctx = NULL) const;  	virtual std::string dump(const std::string &indent, const std::string &name) const;  }; @@ -61,7 +63,11 @@ class Module : public AbstractModule  public:  	Module() : is_handling_dependencies(false) { }  	virtual ~Module(); -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; + +	void setModulePath(const std::string &path) { this->path = path; } +	const std::string &modulePath() const { return this->path; } + +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  	virtual std::string dump(const std::string &indent, const std::string &name) const;  	void addChild(ModuleInstantiation *ch) { this->children.push_back(ch); } @@ -75,8 +81,8 @@ public:  	bool handleDependencies();  	std::list<std::string> assignments_var; -	typedef boost::unordered_map<std::string, Expression*> AssignmentContainer; -	AssignmentContainer assignments; +	typedef boost::unordered_map<std::string, Expression*> AssignmentMap; +	AssignmentMap assignments;  	typedef boost::unordered_map<std::string, class AbstractFunction*> FunctionContainer;  	FunctionContainer functions; @@ -85,12 +91,12 @@ public:  	std::vector<ModuleInstantiation*> children; -	std::vector<std::string> argnames; -	std::vector<Expression*> argexpr; +	std::vector<Assignment> definition_arguments;  protected:  private: +	std::string path;  };  #endif diff --git a/src/openscad.cc b/src/openscad.cc index 878c207..3b960f3 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -28,7 +28,7 @@  #include "MainWindow.h"  #include "node.h"  #include "module.h" -#include "context.h" +#include "modcontext.h"  #include "value.h"  #include "export.h"  #include "builtin.h" @@ -327,11 +327,8 @@ int main(int argc, char **argv)  		if (!filename) help(argv[0]); -		Context root_ctx; -		register_builtin(root_ctx); -  		Module *root_module; -		ModuleInstantiation root_inst; +		ModuleInstantiation root_inst("group");  		AbstractNode *root_node;  		AbstractNode *absolute_root_node;  		CGAL_Nef_polyhedron root_N; @@ -351,12 +348,18 @@ int main(int argc, char **argv)  		if (!root_module) exit(1);  		root_module->handleDependencies(); +		ModuleContext root_ctx; +		root_ctx.registerBuiltin(); +		PRINT("Root Context:"); +#if 0 && DEBUG +		root_ctx.dump(NULL, NULL); +#endif  		fs::path fpath = boosty::absolute(fs::path(filename));  		fs::path fparent = fpath.parent_path();  		fs::current_path(fparent);  		AbstractNode::resetIndexCounter(); -		absolute_root_node = root_module->evaluate(&root_ctx, &root_inst); +		absolute_root_node = root_module->evaluate(&root_ctx, &root_inst, NULL);  		// Do we have an explicit root node (! modifier)?  		if (!(root_node = find_root_tag(absolute_root_node))) diff --git a/src/parser.y b/src/parser.y index 536f4ef..9b4f888 100644 --- a/src/parser.y +++ b/src/parser.y @@ -34,6 +34,7 @@  #include <unistd.h>  #endif +#include "typedefs.h"  #include "module.h"  #include "expression.h"  #include "value.h" @@ -58,16 +59,11 @@ int lexerlex(void);  std::vector<Module*> module_stack;  Module *currmodule; -class ArgContainer { -public:  -	std::string argname; -	Expression *argexpr; -}; -class ArgsContainer { -public: -	std::vector<std::string> argnames; -	std::vector<Expression*> argexpr; -}; +extern void lexerdestroy(); +extern FILE *lexerin; +extern const char *parser_input_buffer; +const char *parser_input_buffer; +std::string parser_source_path;  %} @@ -77,9 +73,10 @@ public:  	class Value *value;  	class Expression *expr;  	class ModuleInstantiation *inst; +	std::vector<ModuleInstantiation*> *instvec;  	class IfElseModuleInstantiation *ifelse; -	class ArgContainer *arg; -	class ArgsContainer *args; +	Assignment *arg; +	AssignmentList *args;  }  %token TOK_MODULE @@ -117,8 +114,8 @@ public:  %type <inst> module_instantiation  %type <ifelse> if_statement  %type <ifelse> ifelse_statement -%type <inst> children_instantiation -%type <inst> module_instantiation_list +%type <instvec> children_instantiation +%type <instvec> module_instantiation_list  %type <inst> single_module_instantiation  %type <args> arguments_call @@ -161,8 +158,7 @@ statement:  		module_stack.push_back(currmodule);  		currmodule = new Module();  		p->modules[$2] = currmodule; -		currmodule->argnames = $4->argnames; -		currmodule->argexpr = $4->argexpr; +		currmodule->definition_arguments = *$4;  		free($2);  		delete $4;  	} statement { @@ -171,8 +167,7 @@ statement:  	} |  	TOK_FUNCTION TOK_ID '(' arguments_decl optional_commas ')' '=' expr {  		Function *func = new Function(); -		func->argnames = $4->argnames; -		func->argexpr = $4->argexpr; +		func->definition_arguments = *$4;  		func->expr = $8;  		currmodule->functions[$2] = func;  		free($2); @@ -182,9 +177,9 @@ statement:  /* Will return a dummy parent node with zero or more children */  children_instantiation:  	module_instantiation { -		$$ = new ModuleInstantiation(); +		$$ = new std::vector<ModuleInstantiation*>;  		if ($1) {  -			$$->children.push_back($1); +			$$->push_back($1);  		}  	} |  	'{' module_instantiation_list '}' { @@ -194,16 +189,15 @@ children_instantiation:  if_statement:  	TOK_IF '(' expr ')' children_instantiation {  		$$ = new IfElseModuleInstantiation(); -		$$->argnames.push_back(""); -		$$->argexpr.push_back($3); +		$$->arguments.push_back(Assignment("", $3)); +                $$->setPath(parser_source_path);  		if ($$) { -			$$->children = $5->children; +                  $$->children = *$5;  		} else { -			for (size_t i = 0; i < $5->children.size(); i++) -				delete $5->children[i]; +			for (size_t i = 0; i < $5->size(); i++) +                          delete (*$5)[i];  		} -		$5->children.clear();  		delete $5;  	} ; @@ -214,12 +208,11 @@ ifelse_statement:  	if_statement TOK_ELSE children_instantiation {  		$$ = $1;  		if ($$) { -			$$->else_children = $3->children; +                  $$->else_children = *$3;  		} else { -			for (size_t i = 0; i < $3->children.size(); i++) -				delete $3->children[i]; +			for (size_t i = 0; i < $3->size(); i++) +                          delete (*$3)[i];  		} -		$3->children.clear();  		delete $3;  	} ; @@ -246,12 +239,11 @@ module_instantiation:  	single_module_instantiation children_instantiation {  		$$ = $1;  		if ($$) { -			$$->children = $2->children; +			$$->children = *$2;  		} else { -			for (size_t i = 0; i < $2->children.size(); i++) -				delete $2->children[i]; +			for (size_t i = 0; i < $2->size(); i++) +                          delete (*$2)[i];  		} -		$2->children.clear();  		delete $2;  	} |  	ifelse_statement { @@ -260,12 +252,12 @@ module_instantiation:  module_instantiation_list:  	/* empty */ { -		$$ = new ModuleInstantiation(); +		$$ = new std::vector<ModuleInstantiation*>;  	} |  	module_instantiation_list module_instantiation {  		$$ = $1;  		if ($$) { -			if ($2) $$->children.push_back($2); +			if ($2) $$->push_back($2);  		} else {  			delete $2;  		} @@ -274,8 +266,8 @@ module_instantiation_list:  single_module_instantiation:  	TOK_ID '(' arguments_call ')' {  		$$ = new ModuleInstantiation($1); -		$$->argnames = $3->argnames; -		$$->argexpr = $3->argexpr; +		$$->arguments = *$3; +                $$->setPath(parser_source_path);  		free($1);  		delete $3;  	} @@ -442,8 +434,7 @@ expr:  		$$ = new Expression();  		$$->type = "F";  		$$->call_funcname = $1; -		$$->call_argnames = $3->argnames; -		$$->children = $3->argexpr; +		$$->call_arguments = *$3;  		free($1);  		delete $3;  	} ; @@ -464,61 +455,50 @@ vector_expr:  arguments_decl:  	/* empty */ { -		$$ = new ArgsContainer(); +		$$ = new AssignmentList();  	} |  	argument_decl { -		$$ = new ArgsContainer(); -		$$->argnames.push_back($1->argname); -		$$->argexpr.push_back($1->argexpr); +		$$ = new AssignmentList(); +		$$->push_back(*$1);  		delete $1;  	} |  	arguments_decl ',' optional_commas argument_decl {  		$$ = $1; -		$$->argnames.push_back($4->argname); -		$$->argexpr.push_back($4->argexpr); +		$$->push_back(*$4);  		delete $4;  	} ;  argument_decl:  	TOK_ID { -		$$ = new ArgContainer(); -		$$->argname = $1; -		$$->argexpr = NULL; +		$$ = new Assignment($1, NULL);  		free($1);  	} |  	TOK_ID '=' expr { -		$$ = new ArgContainer(); -		$$->argname = $1; -		$$->argexpr = $3; +		$$ = new Assignment($1, $3);  		free($1);  	} ;  arguments_call:  	/* empty */ { -		$$ = new ArgsContainer(); +		$$ = new AssignmentList();  	} |  	argument_call { -		$$ = new ArgsContainer(); -		$$->argnames.push_back($1->argname); -		$$->argexpr.push_back($1->argexpr); +		$$ = new AssignmentList(); +		$$->push_back(*$1);  		delete $1;  	} |  	arguments_call ',' optional_commas argument_call {  		$$ = $1; -		$$->argnames.push_back($4->argname); -		$$->argexpr.push_back($4->argexpr); +		$$->push_back(*$4);  		delete $4;  	} ;  argument_call:  	expr { -		$$ = new ArgContainer(); -		$$->argexpr = $1; +		$$ = new Assignment("", $1);  	} |  	TOK_ID '=' expr { -		$$ = new ArgContainer(); -		$$->argname = $1; -		$$->argexpr = $3; +		$$ = new Assignment($1, $3);  		free($1);  	} ; @@ -536,21 +516,16 @@ void yyerror (char const *s)  	currmodule = NULL;  } -extern void lexerdestroy(); -extern FILE *lexerin; -extern const char *parser_input_buffer; -const char *parser_input_buffer; -std::string parser_source_path; -  Module *parse(const char *text, const char *path, int debug)  {  	lexerin = NULL;  	parser_error_pos = -1;  	parser_input_buffer = text; -	parser_source_path = std::string(path); +	parser_source_path = boosty::absolute(std::string(path)).string();  	module_stack.clear();  	Module *rootmodule = currmodule = new Module(); +        rootmodule->setModulePath(path);          //        PRINTB_NOCACHE("New module: %s %p", "root" % rootmodule);  	parserdebug = debug; diff --git a/src/primitives.cc b/src/primitives.cc index e02df35..184b40c 100644 --- a/src/primitives.cc +++ b/src/primitives.cc @@ -27,12 +27,13 @@  #include "module.h"  #include "node.h"  #include "polyset.h" -#include "context.h" +#include "evalcontext.h"  #include "dxfdata.h"  #include "dxftess.h"  #include "builtin.h"  #include "printutils.h"  #include "visitor.h" +#include "context.h"  #include <sstream>  #include <assert.h>  #include <boost/assign/std/vector.hpp> @@ -55,7 +56,7 @@ class PrimitiveModule : public AbstractModule  public:  	primitive_type_e type;  	PrimitiveModule(primitive_type_e type) : type(type) { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  };  class PrimitiveNode : public AbstractPolyNode @@ -104,44 +105,43 @@ public:  	virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const;  }; -AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	PrimitiveNode *node = new PrimitiveNode(inst, this->type);  	node->center = false;  	node->x = node->y = node->z = node->h = node->r1 = node->r2 = 1; -	std::vector<std::string> argnames; -	std::vector<Expression*> argexpr; +	AssignmentList args;  	switch (this->type) {  	case CUBE: -		argnames += "size", "center"; +		args += Assignment("size", NULL), Assignment("center", NULL);  		break;  	case SPHERE: -		argnames += "r"; +		args += Assignment("r", NULL);  		break;  	case CYLINDER: -		argnames += "h", "r1", "r2", "center"; +		args += Assignment("h", NULL), Assignment("r1", NULL), Assignment("r2", NULL), Assignment("center", NULL);  		break;  	case POLYHEDRON: -		argnames += "points", "triangles", "convexity"; +		args += Assignment("points", NULL), Assignment("triangles", NULL), Assignment("convexity", NULL);  		break;  	case SQUARE: -		argnames += "size", "center"; +		args += Assignment("size", NULL), Assignment("center", NULL);  		break;  	case CIRCLE: -		argnames += "r"; +		args += Assignment("r", NULL);  		break;  	case POLYGON: -		argnames += "points", "paths", "convexity"; +		args += Assignment("points", NULL), Assignment("paths", NULL), Assignment("convexity", NULL);  		break;  	default:  		assert(false && "PrimitiveModule::evaluate(): Unknown node type");  	}  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	node->fn = c.lookup_variable("$fn").toDouble();  	node->fs = c.lookup_variable("$fs").toDouble(); diff --git a/src/printutils.cc b/src/printutils.cc index 698fffb..37092fa 100644 --- a/src/printutils.cc +++ b/src/printutils.cc @@ -69,5 +69,3 @@ std::string two_digit_exp_format( double x )  	s << x;  	return two_digit_exp_format( s.str() );  } - - diff --git a/src/printutils.h b/src/printutils.h index 439c884..18aadde 100644 --- a/src/printutils.h +++ b/src/printutils.h @@ -22,6 +22,9 @@ void PRINT(const std::string &msg);  void PRINT_NOCACHE(const std::string &msg);  #define PRINTB_NOCACHE(_fmt, _arg) do { PRINT_NOCACHE(str(boost::format(_fmt) % _arg)); } while (0) + +void PRINT_CONTEXT(const class Context *ctx, const class Module *mod, const class ModuleInstantiation *inst); +  std::string two_digit_exp_format( std::string doublestr );  std::string two_digit_exp_format( double x ); diff --git a/src/projection.cc b/src/projection.cc index 1fcf639..eeed411 100644 --- a/src/projection.cc +++ b/src/projection.cc @@ -26,7 +26,7 @@  #include "projectionnode.h"  #include "module.h" -#include "context.h" +#include "evalcontext.h"  #include "printutils.h"  #include "builtin.h"  #include "visitor.h" @@ -41,19 +41,18 @@ class ProjectionModule : public AbstractModule  {  public:  	ProjectionModule() { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  }; -AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	ProjectionNode *node = new ProjectionNode(inst); -	std::vector<std::string> argnames; -	argnames += "cut"; -	std::vector<Expression*> argexpr; +	AssignmentList args; +	args += Assignment("cut", NULL);  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	Value convexity = c.lookup_variable("convexity", true);  	Value cut = c.lookup_variable("cut", true); @@ -63,7 +62,7 @@ AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstant  	if (cut.type() == Value::BOOL)  		node->cut_mode = cut.toBool(); -	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); +	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);  	node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  	return node; diff --git a/src/render.cc b/src/render.cc index 81c3f7b..bb08c0c 100644 --- a/src/render.cc +++ b/src/render.cc @@ -26,7 +26,7 @@  #include "rendernode.h"  #include "module.h" -#include "context.h" +#include "evalcontext.h"  #include "builtin.h"  #include "PolySetEvaluator.h" @@ -38,25 +38,24 @@ class RenderModule : public AbstractModule  {  public:  	RenderModule() { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  }; -AbstractNode *RenderModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *RenderModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	RenderNode *node = new RenderNode(inst); -	std::vector<std::string> argnames; -	argnames += "convexity"; -	std::vector<Expression*> argexpr; +	AssignmentList args; +	args += Assignment("convexity", NULL);  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	Value v = c.lookup_variable("convexity");  	if (v.type() == Value::NUMBER)  		node->convexity = (int)v.toDouble(); -	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); +	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);  	node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  	return node; diff --git a/src/rotateextrude.cc b/src/rotateextrude.cc index dc8ea34..b6edb8b 100644 --- a/src/rotateextrude.cc +++ b/src/rotateextrude.cc @@ -26,7 +26,7 @@  #include "rotateextrudenode.h"  #include "module.h" -#include "context.h" +#include "evalcontext.h"  #include "printutils.h"  #include "builtin.h"  #include "polyset.h" @@ -45,19 +45,18 @@ class RotateExtrudeModule : public AbstractModule  {  public:  	RotateExtrudeModule() { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  }; -AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	RotateExtrudeNode *node = new RotateExtrudeNode(inst); -	std::vector<std::string> argnames; -	argnames += "file", "layer", "origin", "scale"; -	std::vector<Expression*> argexpr; +	AssignmentList args; +	args += Assignment("file", NULL), Assignment("layer", NULL), Assignment("origin", NULL), Assignment("scale", NULL);  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	node->fn = c.lookup_variable("$fn").toDouble();  	node->fs = c.lookup_variable("$fs").toDouble(); @@ -71,7 +70,7 @@ AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInst  	if (!file.isUndefined()) {  		PRINT("DEPRECATED: Support for reading files in rotate_extrude will be removed in future releases. Use a child import() instead."); -		node->filename = c.getAbsolutePath(file.toString()); +		node->filename = inst->getAbsolutePath(file.toString());  	}  	node->layername = layer.isUndefined() ? "" : layer.toString(); @@ -86,7 +85,7 @@ AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInst  		node->scale = 1;  	if (node->filename.empty()) { -		std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); +		std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);  		node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  	} diff --git a/src/surface.cc b/src/surface.cc index 4339ead..d8fa422 100644 --- a/src/surface.cc +++ b/src/surface.cc @@ -27,7 +27,7 @@  #include "module.h"  #include "node.h"  #include "polyset.h" -#include "context.h" +#include "evalcontext.h"  #include "builtin.h"  #include "printutils.h"  #include "handle_dep.h" // handle_dep() @@ -50,7 +50,7 @@ class SurfaceModule : public AbstractModule  {  public:  	SurfaceModule() { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  };  class SurfaceNode : public AbstractPolyNode @@ -69,21 +69,20 @@ public:  	virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const;  }; -AbstractNode *SurfaceModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *SurfaceModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	SurfaceNode *node = new SurfaceNode(inst);  	node->center = false;  	node->convexity = 1; -	std::vector<std::string> argnames; -	argnames += "file", "center", "convexity"; -	std::vector<Expression*> argexpr; +	AssignmentList args; +	args += Assignment("file", NULL), Assignment("center", NULL), Assignment("convexity", NULL);  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	Value fileval = c.lookup_variable("file"); -	node->filename = c.getAbsolutePath(fileval.isUndefined() ? "" : fileval.toString()); +	node->filename = inst->getAbsolutePath(fileval.isUndefined() ? "" : fileval.toString());  	Value center = c.lookup_variable("center", true);  	if (center.type() == Value::BOOL) { diff --git a/src/transform.cc b/src/transform.cc index b01827f..cc026fb 100644 --- a/src/transform.cc +++ b/src/transform.cc @@ -26,7 +26,7 @@  #include "transformnode.h"  #include "module.h" -#include "context.h" +#include "evalcontext.h"  #include "polyset.h"  #include "builtin.h"  #include "value.h" @@ -50,40 +50,39 @@ class TransformModule : public AbstractModule  public:  	transform_type_e type;  	TransformModule(transform_type_e type) : type(type) { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  }; -AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	TransformNode *node = new TransformNode(inst);  	node->matrix = Transform3d::Identity(); -	std::vector<std::string> argnames; -	std::vector<Expression*> argexpr; +	AssignmentList args;  	switch (this->type) {  	case SCALE: -		argnames += "v"; +		args += Assignment("v", NULL);  		break;  	case ROTATE: -		argnames += "a", "v"; +		args += Assignment("a", NULL), Assignment("v", NULL);  		break;  	case MIRROR: -		argnames += "v"; +		args += Assignment("v", NULL);  		break;  	case TRANSLATE: -		argnames += "v"; +		args += Assignment("v", NULL);  		break;  	case MULTMATRIX: -		argnames += "m"; +		args += Assignment("m", NULL);  		break;  	default:  		assert(false);  	}  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	if (this->type == SCALE)  	{ @@ -176,7 +175,7 @@ AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstanti  		}  	} -	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); +	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);  	node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  	return node; diff --git a/src/typedefs.h b/src/typedefs.h new file mode 100644 index 0000000..a6e9077 --- /dev/null +++ b/src/typedefs.h @@ -0,0 +1,10 @@ +#ifndef TYPEDEFS_H_ +#define TYPEDEFS_H_ + +#include <string> +#include <vector> + +typedef std::pair<std::string, class Expression*> Assignment; +typedef std::vector<Assignment> AssignmentList; + +#endif diff --git a/testdata/scad/features/child-child-test.scad b/testdata/scad/features/child-child-test.scad new file mode 100644 index 0000000..e5e6d93 --- /dev/null +++ b/testdata/scad/features/child-child-test.scad @@ -0,0 +1,12 @@ +module up() { +  translate([0,0,1]) child(0); +} + +module red() { +  color("Red") child(0); +} + +up() cylinder(r=5); +translate([5,0,0]) up() up() cylinder(r=5); +translate([10,0,0]) up() up() up() red() cylinder(r=5); +translate([15,0,0]) red() up() up() up() up() cylinder(r=5); diff --git a/testdata/scad/features/module-recursion.scad b/testdata/scad/features/module-recursion.scad new file mode 100644 index 0000000..f67a1d0 --- /dev/null +++ b/testdata/scad/features/module-recursion.scad @@ -0,0 +1,15 @@ +module tree(currentScale, levels) +{ +  h = currentScale; +  w = currentScale/5; +  childScale = currentScale * 0.7; +   +  if (levels > 0) { +    cylinder(r=w, h=h); +    translate([0,0,h]) for (i = [1:2]) { +      rotate([40, 0, i * 180]) tree(childScale, levels-1); +    } +  } +} + +tree(1, 4); diff --git a/testdata/scad/features/modulevariables.scad b/testdata/scad/features/modulevariables.scad new file mode 100644 index 0000000..fc7a183 --- /dev/null +++ b/testdata/scad/features/modulevariables.scad @@ -0,0 +1,7 @@ +module mymodule(modparam) { +  inner_variable = 23; +  inner_variable2 = modparam * 2; +  cylinder(r1=inner_variable, r2=inner_variable2, h=10); +} + +mymodule(5); diff --git a/testdata/scad/misc/localfiles-test.scad b/testdata/scad/misc/localfiles-test.scad new file mode 100644 index 0000000..31efe96 --- /dev/null +++ b/testdata/scad/misc/localfiles-test.scad @@ -0,0 +1,3 @@ +use <localfiles_dir/localfiles_module.scad> + +localfiles_module(); diff --git a/testdata/scad/misc/localfiles_dir/localfile.dat b/testdata/scad/misc/localfiles_dir/localfile.dat new file mode 100644 index 0000000..32eba08 --- /dev/null +++ b/testdata/scad/misc/localfiles_dir/localfile.dat @@ -0,0 +1,2 @@ +0 1 +2 3 diff --git a/testdata/scad/misc/localfiles_dir/localfile.dxf b/testdata/scad/misc/localfiles_dir/localfile.dxf new file mode 100644 index 0000000..933e263 --- /dev/null +++ b/testdata/scad/misc/localfiles_dir/localfile.dxf @@ -0,0 +1,1968 @@ +999 +dxflib 2.2.0.0 +  0 +SECTION +  2 +HEADER +  9 +$ACADVER +  1 +AC1015 +  9 +$HANDSEED +  5 +FFFF +  9 +$DIMASZ + 40 +2.5 +  9 +$PLIMMIN + 10 +0.0 + 20 +0.0 +  9 +$DIMEXE + 40 +1.25 +  9 +$DIMGAP + 40 +0.625 +  9 +$PLIMMAX + 10 +210.0 + 20 +297.0 +  9 +$INSUNITS + 70 +4 +  9 +$DIMSTYLE +  2 +Standard +  9 +$CLAYER +  8 +0 +  9 +$DIMEXO + 40 +0.625 +  9 +$DIMTXT + 40 +2.5 +  9 +$CLAYER +  8 +0 +  0 +ENDSEC +  0 +SECTION +  2 +TABLES +  0 +TABLE +  2 +VPORT +  5 +8 +100 +AcDbSymbolTable + 70 +1 +  0 +VPORT +  5 +30 +100 +AcDbSymbolTableRecord +100 +AcDbViewportTableRecord +  2 +*Active + 70 +0 + 10 +0.0 + 20 +0.0 + 11 +1.0 + 21 +1.0 + 12 +286.3055555555554861 + 22 +148.5 + 13 +0.0 + 23 +0.0 + 14 +10.0 + 24 +10.0 + 15 +10.0 + 25 +10.0 + 16 +0.0 + 26 +0.0 + 36 +1.0 + 17 +0.0 + 27 +0.0 + 37 +0.0 + 40 +297.0 + 41 +1.92798353909465 + 42 +50.0 + 43 +0.0 + 44 +0.0 + 50 +0.0 + 51 +0.0 + 71 +0 + 72 +100 + 73 +1 + 74 +3 + 75 +1 + 76 +1 + 77 +0 + 78 +0 +281 +0 + 65 +1 +110 +0.0 +120 +0.0 +130 +0.0 +111 +1.0 +121 +0.0 +131 +0.0 +112 +0.0 +122 +1.0 +132 +0.0 + 79 +0 +146 +0.0 +  0 +ENDTAB +  0 +TABLE +  2 +LTYPE +  5 +5 +100 +AcDbSymbolTable + 70 +21 +  0 +LTYPE +  5 +14 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +ByBlock + 70 +0 +  3 + + 72 +65 + 73 +0 + 40 +0.0 +  0 +LTYPE +  5 +15 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +ByLayer + 70 +0 +  3 + + 72 +65 + 73 +0 + 40 +0.0 +  0 +LTYPE +  5 +16 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +CONTINUOUS + 70 +0 +  3 +Solid line + 72 +65 + 73 +0 + 40 +0.0 +  0 +LTYPE +  5 +31 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +DOT + 70 +0 +  3 +Dot . . . . . . . . . . . . . . . . . . . . . . + 72 +65 + 73 +2 + 40 +6.3499999999999996 + 49 +0.0 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 +  0 +LTYPE +  5 +32 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +DOT2 + 70 +0 +  3 +Dot (.5x) ..................................... + 72 +65 + 73 +2 + 40 +3.1749999999999998 + 49 +0.0 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 +  0 +LTYPE +  5 +33 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +DOTX2 + 70 +0 +  3 +Dot (2x) .  .  .  .  .  .  .  .  .  .  .  .  . + 72 +65 + 73 +2 + 40 +12.6999999999999993 + 49 +0.0 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 +  0 +LTYPE +  5 +34 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +DASHED + 70 +0 +  3 +Dashed __ __ __ __ __ __ __ __ __ __ __ __ __ _ + 72 +65 + 73 +2 + 40 +19.0500000000000007 + 49 +12.6999999999999993 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 +  0 +LTYPE +  5 +35 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +DASHED2 + 70 +0 +  3 +Dashed (.5x) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + 72 +65 + 73 +2 + 40 +9.5250000000000004 + 49 +6.3499999999999996 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 +  0 +LTYPE +  5 +36 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +DASHEDX2 + 70 +0 +  3 +Dashed (2x) ____  ____  ____  ____  ____  ___ + 72 +65 + 73 +2 + 40 +38.1000000000000014 + 49 +25.3999999999999986 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 +  0 +LTYPE +  5 +37 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +DASHDOT + 70 +0 +  3 +Dash dot __ . __ . __ . __ . __ . __ . __ . __ + 72 +65 + 73 +4 + 40 +25.3999999999999986 + 49 +12.6999999999999993 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 +  0 +LTYPE +  5 +38 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +DASHDOT2 + 70 +0 +  3 +Dash dot (.5x) _._._._._._._._._._._._._._._. + 72 +65 + 73 +4 + 40 +12.6999999999999993 + 49 +6.3499999999999996 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 +  0 +LTYPE +  5 +39 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +DASHDOTX2 + 70 +0 +  3 +Dash dot (2x) ____  .  ____  .  ____  .  ___ + 72 +65 + 73 +4 + 40 +50.7999999999999972 + 49 +25.3999999999999986 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 +  0 +LTYPE +  5 +3A +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +DIVIDE + 70 +0 +  3 +Divide ____ . . ____ . . ____ . . ____ . . ____ + 72 +65 + 73 +6 + 40 +31.75 + 49 +12.6999999999999993 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 +  0 +LTYPE +  5 +3B +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +DIVIDE2 + 70 +0 +  3 +Divide (.5x) __..__..__..__..__..__..__..__.._ + 72 +65 + 73 +6 + 40 +15.875 + 49 +6.3499999999999996 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 +  0 +LTYPE +  5 +3C +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +DIVIDEX2 + 70 +0 +  3 +Divide (2x) ________  .  .  ________  .  .  _ + 72 +65 + 73 +6 + 40 +63.5 + 49 +25.3999999999999986 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 +  0 +LTYPE +  5 +3D +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +CENTER + 70 +0 +  3 +Center ____ _ ____ _ ____ _ ____ _ ____ _ ____ + 72 +65 + 73 +4 + 40 +50.7999999999999972 + 49 +31.75 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 49 +6.3499999999999996 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 +  0 +LTYPE +  5 +3E +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +CENTER2 + 70 +0 +  3 +Center (.5x) ___ _ ___ _ ___ _ ___ _ ___ _ ___ + 72 +65 + 73 +4 + 40 +28.5749999999999993 + 49 +19.0500000000000007 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 49 +3.1749999999999998 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 +  0 +LTYPE +  5 +3F +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +CENTERX2 + 70 +0 +  3 +Center (2x) ________  __  ________  __  _____ + 72 +65 + 73 +4 + 40 +101.5999999999999943 + 49 +63.5 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 49 +12.6999999999999993 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 +  0 +LTYPE +  5 +40 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +BORDER + 70 +0 +  3 +Border __ __ . __ __ . __ __ . __ __ . __ __ . + 72 +65 + 73 +6 + 40 +44.4500000000000028 + 49 +12.6999999999999993 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 49 +12.6999999999999993 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 +  0 +LTYPE +  5 +41 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +BORDER2 + 70 +0 +  3 +Border (.5x) __.__.__.__.__.__.__.__.__.__.__. + 72 +65 + 73 +6 + 40 +22.2250000000000014 + 49 +6.3499999999999996 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 49 +6.3499999999999996 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 +  0 +LTYPE +  5 +42 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +  2 +BORDERX2 + 70 +0 +  3 +Border (2x) ____  ____  .  ____  ____  .  ___ + 72 +65 + 73 +6 + 40 +88.9000000000000057 + 49 +25.3999999999999986 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 49 +25.3999999999999986 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 +  0 +ENDTAB +  0 +TABLE +  2 +LAYER +  5 +2 +100 +AcDbSymbolTable + 70 +1 +  0 +LAYER +  5 +10 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord +  2 +0 + 70 +0 + 62 +7 +420 +0 +  6 +CONTINUOUS +370 +25 +390 +F +  0 +ENDTAB +  0 +TABLE +  2 +STYLE +  5 +3 +100 +AcDbSymbolTable + 70 +1 +  0 +STYLE +  5 +11 +100 +AcDbSymbolTableRecord +100 +AcDbTextStyleTableRecord +  2 +Standard + 70 +0 + 40 +0.0 + 41 +0.75 + 50 +0.0 + 71 +0 + 42 +2.5 +  3 +txt +  4 + +  0 +ENDTAB +  0 +TABLE +  2 +VIEW +  5 +6 +100 +AcDbSymbolTable + 70 +0 +  0 +ENDTAB +  0 +TABLE +  2 +UCS +  5 +7 +100 +AcDbSymbolTable + 70 +0 +  0 +ENDTAB +  0 +TABLE +  2 +APPID +  5 +9 +100 +AcDbSymbolTable + 70 +1 +  0 +APPID +  5 +12 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord +  2 +ACAD + 70 +0 +  0 +ENDTAB +  0 +TABLE +  2 +DIMSTYLE +  5 +A +100 +AcDbSymbolTable + 70 +1 +100 +AcDbDimStyleTable + 71 +0 +  0 +DIMSTYLE +105 +27 +100 +AcDbSymbolTableRecord +100 +AcDbDimStyleTableRecord +  2 +Standard + 41 +2.5 + 42 +0.625 + 43 +3.75 + 44 +1.25 + 70 +0 + 73 +0 + 74 +0 + 77 +1 + 78 +8 +140 +2.5 +141 +2.5 +143 +0.03937007874016 +147 +0.625 +171 +3 +172 +1 +271 +2 +272 +2 +274 +3 +278 +44 +283 +0 +284 +8 +340 +11 +  0 +ENDTAB +  0 +TABLE +  2 +BLOCK_RECORD +  5 +1 +100 +AcDbSymbolTable + 70 +1 +  0 +BLOCK_RECORD +  5 +1F +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord +  2 +*Model_Space +340 +22 +  0 +BLOCK_RECORD +  5 +1B +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord +  2 +*Paper_Space +340 +1E +  0 +BLOCK_RECORD +  5 +23 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord +  2 +*Paper_Space0 +340 +26 +  0 +ENDTAB +  0 +ENDSEC +  0 +SECTION +  2 +BLOCKS +  0 +BLOCK +  5 +20 +100 +AcDbEntity +  8 +0 +100 +AcDbBlockBegin +  2 +*Model_Space + 70 +0 + 10 +0.0 + 20 +0.0 + 30 +0.0 +  3 +*Model_Space +  1 + +  0 +ENDBLK +  5 +21 +100 +AcDbEntity +  8 +0 +100 +AcDbBlockEnd +  0 +BLOCK +  5 +1C +100 +AcDbEntity + 67 +1 +  8 +0 +100 +AcDbBlockBegin +  2 +*Paper_Space + 70 +0 + 10 +0.0 + 20 +0.0 + 30 +0.0 +  3 +*Paper_Space +  1 + +  0 +ENDBLK +  5 +1D +100 +AcDbEntity + 67 +1 +  8 +0 +100 +AcDbBlockEnd +  0 +BLOCK +  5 +24 +100 +AcDbEntity +  8 +0 +100 +AcDbBlockBegin +  2 +*Paper_Space0 + 70 +0 + 10 +0.0 + 20 +0.0 + 30 +0.0 +  3 +*Paper_Space0 +  1 + +  0 +ENDBLK +  5 +25 +100 +AcDbEntity +  8 +0 +100 +AcDbBlockEnd +  0 +ENDSEC +  0 +SECTION +  2 +ENTITIES +  0 +LINE +  5 +43 +100 +AcDbEntity +100 +AcDbLine +  8 +0 + 62 +256 +370 +-1 +  6 +ByLayer + 10 +10.0 + 20 +100.0 + 30 +0.0 + 11 +210.0 + 21 +100.0 + 31 +0.0 +  0 +LINE +  5 +44 +100 +AcDbEntity +100 +AcDbLine +  8 +0 + 62 +256 +370 +-1 +  6 +ByLayer + 10 +210.0 + 20 +100.0 + 30 +0.0 + 11 +210.0 + 21 +-100.0 + 31 +0.0 +  0 +LINE +  5 +45 +100 +AcDbEntity +100 +AcDbLine +  8 +0 + 62 +256 +370 +-1 +  6 +ByLayer + 10 +210.0 + 20 +-100.0 + 30 +0.0 + 11 +10.0 + 21 +-100.0 + 31 +0.0 +  0 +LINE +  5 +46 +100 +AcDbEntity +100 +AcDbLine +  8 +0 + 62 +256 +370 +-1 +  6 +ByLayer + 10 +10.0 + 20 +-100.0 + 30 +0.0 + 11 +10.0 + 21 +100.0 + 31 +0.0 +  0 +DIMENSION +  5 +47 +100 +AcDbEntity +  8 +0 + 62 +256 +370 +-1 +  6 +ByLayer +100 +AcDbDimension + 10 +10.0000000000000018 + 20 +150.0 + 30 +0.0 + 11 +110.0 + 21 +151.875 + 31 +0.0 + 70 +1 + 71 +5 + 72 +1 + 41 +1.0 + 42 +0.0 +  1 +localfile +  3 +Standard +100 +AcDbAlignedDimension + 13 +10.0 + 23 +130.0 + 33 +0.0 + 14 +210.0 + 24 +130.0 + 34 +0.0 +  0 +ENDSEC +  0 +SECTION +  2 +OBJECTS +  0 +DICTIONARY +  5 +C +100 +AcDbDictionary +280 +0 +281 +1 +  3 +ACAD_GROUP +350 +D +  3 +ACAD_LAYOUT +350 +1A +  3 +ACAD_MLINESTYLE +350 +17 +  3 +ACAD_PLOTSETTINGS +350 +19 +  3 +ACAD_PLOTSTYLENAME +350 +E +  3 +AcDbVariableDictionary +350 +48 +  0 +DICTIONARY +  5 +D +100 +AcDbDictionary +280 +0 +281 +1 +  0 +ACDBDICTIONARYWDFLT +  5 +E +100 +AcDbDictionary +281 +1 +  3 +Normal +350 +F +100 +AcDbDictionaryWithDefault +340 +F +  0 +ACDBPLACEHOLDER +  5 +F +  0 +DICTIONARY +  5 +17 +100 +AcDbDictionary +280 +0 +281 +1 +  3 +Standard +350 +18 +  0 +MLINESTYLE +  5 +18 +100 +AcDbMlineStyle +  2 +STANDARD + 70 +0 +  3 + + 62 +256 + 51 +90.0 + 52 +90.0 + 71 +2 + 49 +0.5 + 62 +256 +  6 +BYLAYER + 49 +-0.5 + 62 +256 +  6 +BYLAYER +  0 +DICTIONARY +  5 +19 +100 +AcDbDictionary +280 +0 +281 +1 +  0 +DICTIONARY +  5 +1A +100 +AcDbDictionary +281 +1 +  3 +Layout1 +350 +1E +  3 +Layout2 +350 +26 +  3 +Model +350 +22 +  0 +LAYOUT +  5 +1E +100 +AcDbPlotSettings +  1 + +  2 +C:\Program Files\AutoCAD 2002\plotters\DWF ePlot (optimized for plotting).pc3 +  4 + +  6 + + 40 +0.0 + 41 +0.0 + 42 +0.0 + 43 +0.0 + 44 +0.0 + 45 +0.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +0.0 +140 +0.0 +141 +0.0 +142 +1.0 +143 +1.0 + 70 +688 + 72 +0 + 73 +0 + 74 +5 +  7 + + 75 +16 +147 +1.0 +148 +0.0 +149 +0.0 +100 +AcDbLayout +  1 +Layout1 + 70 +1 + 71 +1 + 10 +0.0 + 20 +0.0 + 11 +420.0 + 21 +297.0 + 12 +0.0 + 22 +0.0 + 32 +0.0 + 14 +100000000000000000000.0 + 24 +100000000000000000000.0 + 34 +100000000000000000000.0 + 15 +-100000000000000000000.0 + 25 +-100000000000000000000.0 + 35 +-100000000000000000000.0 +146 +0.0 + 13 +0.0 + 23 +0.0 + 33 +0.0 + 16 +1.0 + 26 +0.0 + 36 +0.0 + 17 +0.0 + 27 +1.0 + 37 +0.0 + 76 +0 +330 +1B +  0 +LAYOUT +  5 +22 +100 +AcDbPlotSettings +  1 + +  2 +C:\Program Files\AutoCAD 2002\plotters\DWF ePlot (optimized for plotting).pc3 +  4 + +  6 + + 40 +0.0 + 41 +0.0 + 42 +0.0 + 43 +0.0 + 44 +0.0 + 45 +0.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +0.0 +140 +0.0 +141 +0.0 +142 +1.0 +143 +1.0 + 70 +1712 + 72 +0 + 73 +0 + 74 +0 +  7 + + 75 +0 +147 +1.0 +148 +0.0 +149 +0.0 +100 +AcDbLayout +  1 +Model + 70 +1 + 71 +0 + 10 +0.0 + 20 +0.0 + 11 +12.0 + 21 +9.0 + 12 +0.0 + 22 +0.0 + 32 +0.0 + 14 +0.0 + 24 +0.0 + 34 +0.0 + 15 +0.0 + 25 +0.0 + 35 +0.0 +146 +0.0 + 13 +0.0 + 23 +0.0 + 33 +0.0 + 16 +1.0 + 26 +0.0 + 36 +0.0 + 17 +0.0 + 27 +1.0 + 37 +0.0 + 76 +0 +330 +1F +  0 +LAYOUT +  5 +26 +100 +AcDbPlotSettings +  1 + +  2 +C:\Program Files\AutoCAD 2002\plotters\DWF ePlot (optimized for plotting).pc3 +  4 + +  6 + + 40 +0.0 + 41 +0.0 + 42 +0.0 + 43 +0.0 + 44 +0.0 + 45 +0.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +0.0 +140 +0.0 +141 +0.0 +142 +1.0 +143 +1.0 + 70 +688 + 72 +0 + 73 +0 + 74 +5 +  7 + + 75 +16 +147 +1.0 +148 +0.0 +149 +0.0 +100 +AcDbLayout +  1 +Layout2 + 70 +1 + 71 +2 + 10 +0.0 + 20 +0.0 + 11 +12.0 + 21 +9.0 + 12 +0.0 + 22 +0.0 + 32 +0.0 + 14 +0.0 + 24 +0.0 + 34 +0.0 + 15 +0.0 + 25 +0.0 + 35 +0.0 +146 +0.0 + 13 +0.0 + 23 +0.0 + 33 +0.0 + 16 +1.0 + 26 +0.0 + 36 +0.0 + 17 +0.0 + 27 +1.0 + 37 +0.0 + 76 +0 +330 +23 +  0 +DICTIONARY +  5 +48 +100 +AcDbDictionary +281 +1 +  3 +DIMASSOC +350 +4A +  3 +HIDETEXT +350 +49 +  0 +DICTIONARYVAR +  5 +49 +100 +DictionaryVariables +280 +0 +  1 +2 +  0 +DICTIONARYVAR +  5 +4A +100 +DictionaryVariables +280 +0 +  1 +1 +  0 +ENDSEC +  0 +EOF diff --git a/testdata/scad/misc/localfiles_dir/localfiles_module.scad b/testdata/scad/misc/localfiles_dir/localfiles_module.scad new file mode 100644 index 0000000..b98a49b --- /dev/null +++ b/testdata/scad/misc/localfiles_dir/localfiles_module.scad @@ -0,0 +1,10 @@ +module localfiles_module() +{ +  linear_extrude(h=100) import("localfile.dxf"); +  translate([-250,0,0]) linear_extrude(file="localfile.dxf"); +  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")); +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d178f0f..de4bab7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -406,6 +406,8 @@ set(CORE_SOURCES    ../src/ModuleCache.cc     ../src/node.cc     ../src/context.cc  +  ../src/modcontext.cc  +  ../src/evalcontext.cc     ../src/csgterm.cc     ../src/csgtermnormalizer.cc     ../src/polyset.cc  @@ -754,12 +756,15 @@ list(APPEND ECHO_FILES ${FUNCTION_FILES}  list(APPEND DUMPTEST_FILES ${MINIMAL_FILES} ${FEATURES_FILES} ${EXAMPLE_FILES})  list(APPEND DUMPTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/escape-test.scad                             ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/include-tests.scad -                           ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests.scad) +                           ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests.scad +                           ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles-test.scad)  list(APPEND CGALPNGTEST_FILES ${FEATURES_FILES} ${SCAD_DXF_FILES} ${EXAMPLE_FILES})  list(APPEND CGALPNGTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/include-tests.scad                             ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests.scad -                           ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/transform-nan-inf-tests.scad) +                           ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/transform-nan-inf-tests.scad +                           ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles-test.scad) +  list(APPEND OPENCSGTEST_FILES ${CGALPNGTEST_FILES})  list(APPEND OPENCSGTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/bbox-transform-bug.scad)  list(APPEND OPENCSGTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/intersection-prune-test.scad) diff --git a/tests/cgalcachetest.cc b/tests/cgalcachetest.cc index b7e51b5..b65a2c8 100644 --- a/tests/cgalcachetest.cc +++ b/tests/cgalcachetest.cc @@ -30,7 +30,7 @@  #include "parsersettings.h"  #include "node.h"  #include "module.h" -#include "context.h" +#include "modcontext.h"  #include "value.h"  #include "export.h"  #include "builtin.h" @@ -129,11 +129,11 @@ 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")); -	Context root_ctx; -	register_builtin(root_ctx); +	ModuleContext root_ctx; +	root_ctx.registerBuiltin();  	AbstractModule *root_module; -	ModuleInstantiation root_inst; +	ModuleInstantiation root_inst("group");  	root_module = parsefile(filename);  	if (!root_module) { diff --git a/tests/cgalpngtest.cc b/tests/cgalpngtest.cc index 947a231..afc3128 100644 --- a/tests/cgalpngtest.cc +++ b/tests/cgalpngtest.cc @@ -30,7 +30,7 @@  #include "node.h"  #include "module.h"  #include "polyset.h" -#include "context.h" +#include "modcontext.h"  #include "value.h"  #include "export.h"  #include "builtin.h" @@ -102,11 +102,11 @@ 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")); -	Context root_ctx; -	register_builtin(root_ctx); +	ModuleContext root_ctx; +	root_ctx.registerBuiltin();  	AbstractModule *root_module; -	ModuleInstantiation root_inst; +	ModuleInstantiation root_inst("group");  	root_module = parsefile(filename);  	if (!root_module) { diff --git a/tests/cgalstlsanitytest.cc b/tests/cgalstlsanitytest.cc index 228bfde..49a3f8e 100644 --- a/tests/cgalstlsanitytest.cc +++ b/tests/cgalstlsanitytest.cc @@ -29,7 +29,7 @@  #include "parsersettings.h"  #include "node.h"  #include "module.h" -#include "context.h" +#include "modcontext.h"  #include "value.h"  #include "export.h"  #include "builtin.h" @@ -84,11 +84,11 @@ 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")); -	Context root_ctx; -	register_builtin(root_ctx); +	ModuleContext root_ctx; +	root_ctx.registerBuiltin();  	AbstractModule *root_module; -	ModuleInstantiation root_inst; +	ModuleInstantiation root_inst("group");  	root_module = parsefile(filename);  	if (!root_module) { diff --git a/tests/cgaltest.cc b/tests/cgaltest.cc index 9c8c090..b7ae669 100644 --- a/tests/cgaltest.cc +++ b/tests/cgaltest.cc @@ -29,7 +29,7 @@  #include "parsersettings.h"  #include "node.h"  #include "module.h" -#include "context.h" +#include "modcontext.h"  #include "value.h"  #include "export.h"  #include "builtin.h" @@ -81,11 +81,11 @@ 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")); -	Context root_ctx; -	register_builtin(root_ctx); +	ModuleContext root_ctx; +	root_ctx.registerBuiltin();  	AbstractModule *root_module; -	ModuleInstantiation root_inst; +	ModuleInstantiation root_inst("group");  	root_module = parsefile(filename);  	if (!root_module) { diff --git a/tests/csgtermtest.cc b/tests/csgtermtest.cc index 864ba5d..f4a88e0 100644 --- a/tests/csgtermtest.cc +++ b/tests/csgtermtest.cc @@ -31,7 +31,7 @@  #include "parsersettings.h"  #include "node.h"  #include "module.h" -#include "context.h" +#include "modcontext.h"  #include "value.h"  #include "export.h"  #include "builtin.h" @@ -76,11 +76,11 @@ 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")); -	Context root_ctx; -	register_builtin(root_ctx); +	ModuleContext root_ctx; +	root_ctx.registerBuiltin();  	AbstractModule *root_module; -	ModuleInstantiation root_inst; +	ModuleInstantiation root_inst("group");  	const AbstractNode *root_node;  	root_module = parsefile(filename); diff --git a/tests/csgtestcore.cc b/tests/csgtestcore.cc index 1e518e2..6da6411 100644 --- a/tests/csgtestcore.cc +++ b/tests/csgtestcore.cc @@ -6,7 +6,7 @@  #include "openscad.h"  #include "parsersettings.h"  #include "builtin.h" -#include "context.h" +#include "modcontext.h"  #include "node.h"  #include "module.h"  #include "polyset.h" @@ -132,11 +132,11 @@ 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")); -	Context root_ctx; -	register_builtin(root_ctx); +	ModuleContext root_ctx; +	root_ctx.registerBuiltin();  	AbstractModule *root_module; -	ModuleInstantiation root_inst; +	ModuleInstantiation root_inst("group");  	if (sysinfo_dump)  		root_module = parse("sphere();","",false); diff --git a/tests/csgtexttest.cc b/tests/csgtexttest.cc index 6a72dff..3e26814 100644 --- a/tests/csgtexttest.cc +++ b/tests/csgtexttest.cc @@ -31,7 +31,7 @@  #include "parsersettings.h"  #include "node.h"  #include "module.h" -#include "context.h" +#include "modcontext.h"  #include "value.h"  #include "export.h"  #include "builtin.h" @@ -80,11 +80,11 @@ 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")); -	Context root_ctx; -	register_builtin(root_ctx); +	ModuleContext root_ctx; +	root_ctx.registerBuiltin();  	AbstractModule *root_module; -	ModuleInstantiation root_inst; +	ModuleInstantiation root_inst("group");  	AbstractNode *root_node;  	root_module = parsefile(filename); diff --git a/tests/dumptest.cc b/tests/dumptest.cc index 4ddefe2..e0d2776 100644 --- a/tests/dumptest.cc +++ b/tests/dumptest.cc @@ -29,7 +29,7 @@  #include "parsersettings.h"  #include "node.h"  #include "module.h" -#include "context.h" +#include "modcontext.h"  #include "value.h"  #include "export.h"  #include "builtin.h" @@ -86,11 +86,11 @@ 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")); -	Context root_ctx; -	register_builtin(root_ctx); +	ModuleContext root_ctx; +	root_ctx.registerBuiltin();  	AbstractModule *root_module; -	ModuleInstantiation root_inst; +	ModuleInstantiation root_inst("group");  	AbstractNode *root_node;  	root_module = parsefile(filename); @@ -115,7 +115,6 @@ int main(int argc, char **argv)  		exit(1);  	} -	fs::current_path(original_path);  	std::ofstream outfile;  	outfile.open(outfilename);  	outfile << dumpstdstr << "\n"; @@ -124,21 +123,22 @@ int main(int argc, char **argv)  	delete root_node;  	delete root_module; +	fs::current_path(original_path);  	root_module = parsefile(outfilename);  	if (!root_module) {  		fprintf(stderr, "Error: Unable to read back dumped file\n");  		exit(1);  	} -	if (fs::path(filename).has_parent_path()) { -		fs::current_path(fs::path(filename).parent_path()); -	} -  	AbstractNode::resetIndexCounter();  	root_node = root_module->evaluate(&root_ctx, &root_inst);  	tree.setRoot(root_node); +	if (fs::path(outfilename).has_parent_path()) { +		fs::current_path(fs::path(outfilename).parent_path()); +	} +  	string readbackstr = dumptree(tree, *root_node);  	if (dumpstdstr != readbackstr) {  		fprintf(stderr, "Error: Readback is different from original dump:\n"); diff --git a/tests/echotest.cc b/tests/echotest.cc index af4942b..9924d11 100644 --- a/tests/echotest.cc +++ b/tests/echotest.cc @@ -29,7 +29,7 @@  #include "parsersettings.h"  #include "node.h"  #include "module.h" -#include "context.h" +#include "modcontext.h"  #include "value.h"  #include "builtin.h"  #include "printutils.h" @@ -88,11 +88,11 @@ 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")); -	Context root_ctx; -	register_builtin(root_ctx); +	ModuleContext root_ctx; +	root_ctx.registerBuiltin();  	AbstractModule *root_module; -	ModuleInstantiation root_inst; +	ModuleInstantiation root_inst("group");  	AbstractNode *root_node;  	root_module = parsefile(filename); diff --git a/tests/modulecachetest.cc b/tests/modulecachetest.cc index 1103720..62f9543 100644 --- a/tests/modulecachetest.cc +++ b/tests/modulecachetest.cc @@ -29,7 +29,7 @@  #include "parsersettings.h"  #include "node.h"  #include "module.h" -#include "context.h" +#include "modcontext.h"  #include "value.h"  #include "export.h"  #include "builtin.h" @@ -76,11 +76,11 @@ 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")); -	Context root_ctx; -	register_builtin(root_ctx); +	ModuleContext root_ctx; +	root_ctx.registerBuiltin();  	AbstractModule *root_module; -	ModuleInstantiation root_inst; +	ModuleInstantiation root_inst("group");  	AbstractNode *root_node;  	root_module = parsefile(filename); diff --git a/tests/regression/cgalpngtest/child-child-test-expected.png b/tests/regression/cgalpngtest/child-child-test-expected.pngBinary files differ new file mode 100644 index 0000000..80b70ba --- /dev/null +++ b/tests/regression/cgalpngtest/child-child-test-expected.png diff --git a/tests/regression/cgalpngtest/localfiles-test-expected.png b/tests/regression/cgalpngtest/localfiles-test-expected.pngBinary files differ new file mode 100644 index 0000000..3ad3d96 --- /dev/null +++ b/tests/regression/cgalpngtest/localfiles-test-expected.png diff --git a/tests/regression/cgalpngtest/module-recursion-expected.png b/tests/regression/cgalpngtest/module-recursion-expected.pngBinary files differ new file mode 100644 index 0000000..3012a12 --- /dev/null +++ b/tests/regression/cgalpngtest/module-recursion-expected.png diff --git a/tests/regression/cgalpngtest/modulevariables-expected.png b/tests/regression/cgalpngtest/modulevariables-expected.pngBinary files differ new file mode 100644 index 0000000..0dc18e8 --- /dev/null +++ b/tests/regression/cgalpngtest/modulevariables-expected.png diff --git a/tests/regression/dumptest/child-child-test-expected.txt b/tests/regression/dumptest/child-child-test-expected.txt new file mode 100644 index 0000000..13f098d --- /dev/null +++ b/tests/regression/dumptest/child-child-test-expected.txt @@ -0,0 +1,59 @@ +	group() { +		multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { +			cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 5, r2 = 5, center = false); +		} +	} +	multmatrix([[1, 0, 0, 5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { +		group() { +			multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { +				group() { +					multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { +						cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 5, r2 = 5, center = false); +					} +				} +			} +		} +	} +	multmatrix([[1, 0, 0, 10], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { +		group() { +			multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { +				group() { +					multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { +						group() { +							multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { +								group() { +									color([1, 0, 0, 1]) { +										cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 5, r2 = 5, center = false); +									} +								} +							} +						} +					} +				} +			} +		} +	} +	multmatrix([[1, 0, 0, 15], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { +		group() { +			color([1, 0, 0, 1]) { +				group() { +					multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { +						group() { +							multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { +								group() { +									multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { +										group() { +											multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { +												cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 5, r2 = 5, center = false); +											} +										} +									} +								} +							} +						} +					} +				} +			} +		} +	} + diff --git a/tests/regression/dumptest/localfiles-test-expected.txt b/tests/regression/dumptest/localfiles-test-expected.txt new file mode 100644 index 0000000..acdf7e7 --- /dev/null +++ b/tests/regression/dumptest/localfiles-test-expected.txt @@ -0,0 +1,17 @@ +	group() { +		linear_extrude(height = 100, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2) { +			import(file = "localfiles_dir/localfile.dxf", layer = "", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2); +		} +		multmatrix([[1, 0, 0, -250], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { +			linear_extrude(file = "localfiles_dir/localfile.dxf", layer = "", origin = [0, 0], scale = 1, height = 100, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2); +		} +		multmatrix([[1, 0, 0, 0], [0, 1, 0, 350], [0, 0, 1, 0], [0, 0, 0, 1]]) { +			rotate_extrude(file = "localfiles_dir/localfile.dxf", layer = "", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2); +		} +		multmatrix([[1, 0, 0, 250], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { +			multmatrix([[200, 0, 0, 0], [0, 200, 0, 0], [0, 0, 50, 0], [0, 0, 0, 1]]) { +				surface(file = "localfiles_dir/localfile.dat", center = false); +			} +		} +	} + diff --git a/tests/regression/dumptest/module-recursion-expected.txt b/tests/regression/dumptest/module-recursion-expected.txt new file mode 100644 index 0000000..9ad8877 --- /dev/null +++ b/tests/regression/dumptest/module-recursion-expected.txt @@ -0,0 +1,244 @@ +	group() { +		group() { +			cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 0.2, r2 = 0.2, center = false); +			multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { +				group() { +					multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +						group() { +							group() { +								cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.7, r1 = 0.14, r2 = 0.14, center = false); +								multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.7], [0, 0, 0, 1]]) { +									group() { +										multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +											group() { +												group() { +													cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.49, r1 = 0.098, r2 = 0.098, center = false); +													multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.49], [0, 0, 0, 1]]) { +														group() { +															multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																group() { +																	group() { +																		cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false); +																		multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) { +																			group() { +																				multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																					group() { +																						group(); +																					} +																				} +																				multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																					group() { +																						group(); +																					} +																				} +																			} +																		} +																	} +																} +															} +															multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																group() { +																	group() { +																		cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false); +																		multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) { +																			group() { +																				multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																					group() { +																						group(); +																					} +																				} +																				multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																					group() { +																						group(); +																					} +																				} +																			} +																		} +																	} +																} +															} +														} +													} +												} +											} +										} +										multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +											group() { +												group() { +													cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.49, r1 = 0.098, r2 = 0.098, center = false); +													multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.49], [0, 0, 0, 1]]) { +														group() { +															multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																group() { +																	group() { +																		cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false); +																		multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) { +																			group() { +																				multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																					group() { +																						group(); +																					} +																				} +																				multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																					group() { +																						group(); +																					} +																				} +																			} +																		} +																	} +																} +															} +															multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																group() { +																	group() { +																		cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false); +																		multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) { +																			group() { +																				multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																					group() { +																						group(); +																					} +																				} +																				multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																					group() { +																						group(); +																					} +																				} +																			} +																		} +																	} +																} +															} +														} +													} +												} +											} +										} +									} +								} +							} +						} +					} +					multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +						group() { +							group() { +								cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.7, r1 = 0.14, r2 = 0.14, center = false); +								multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.7], [0, 0, 0, 1]]) { +									group() { +										multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +											group() { +												group() { +													cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.49, r1 = 0.098, r2 = 0.098, center = false); +													multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.49], [0, 0, 0, 1]]) { +														group() { +															multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																group() { +																	group() { +																		cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false); +																		multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) { +																			group() { +																				multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																					group() { +																						group(); +																					} +																				} +																				multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																					group() { +																						group(); +																					} +																				} +																			} +																		} +																	} +																} +															} +															multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																group() { +																	group() { +																		cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false); +																		multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) { +																			group() { +																				multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																					group() { +																						group(); +																					} +																				} +																				multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																					group() { +																						group(); +																					} +																				} +																			} +																		} +																	} +																} +															} +														} +													} +												} +											} +										} +										multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +											group() { +												group() { +													cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.49, r1 = 0.098, r2 = 0.098, center = false); +													multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.49], [0, 0, 0, 1]]) { +														group() { +															multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																group() { +																	group() { +																		cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false); +																		multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) { +																			group() { +																				multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																					group() { +																						group(); +																					} +																				} +																				multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																					group() { +																						group(); +																					} +																				} +																			} +																		} +																	} +																} +															} +															multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																group() { +																	group() { +																		cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false); +																		multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) { +																			group() { +																				multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																					group() { +																						group(); +																					} +																				} +																				multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { +																					group() { +																						group(); +																					} +																				} +																			} +																		} +																	} +																} +															} +														} +													} +												} +											} +										} +									} +								} +							} +						} +					} +				} +			} +		} +	} + diff --git a/tests/regression/dumptest/modulevariables-expected.txt b/tests/regression/dumptest/modulevariables-expected.txt new file mode 100644 index 0000000..fed4bbc --- /dev/null +++ b/tests/regression/dumptest/modulevariables-expected.txt @@ -0,0 +1,4 @@ +	group() { +		cylinder($fn = 0, $fa = 12, $fs = 2, h = 10, r1 = 23, r2 = 10, center = false); +	} + diff --git a/tests/regression/opencsgtest/child-child-test-expected.png b/tests/regression/opencsgtest/child-child-test-expected.pngBinary files differ new file mode 100644 index 0000000..07d61c0 --- /dev/null +++ b/tests/regression/opencsgtest/child-child-test-expected.png diff --git a/tests/regression/opencsgtest/localfiles-test-expected.png b/tests/regression/opencsgtest/localfiles-test-expected.pngBinary files differ new file mode 100644 index 0000000..7bc7909 --- /dev/null +++ b/tests/regression/opencsgtest/localfiles-test-expected.png diff --git a/tests/regression/opencsgtest/module-recursion-expected.png b/tests/regression/opencsgtest/module-recursion-expected.pngBinary files differ new file mode 100644 index 0000000..324c260 --- /dev/null +++ b/tests/regression/opencsgtest/module-recursion-expected.png diff --git a/tests/regression/opencsgtest/modulevariables-expected.png b/tests/regression/opencsgtest/modulevariables-expected.pngBinary files differ new file mode 100644 index 0000000..bf23265 --- /dev/null +++ b/tests/regression/opencsgtest/modulevariables-expected.png diff --git a/tests/regression/throwntogethertest/child-child-test-expected.png b/tests/regression/throwntogethertest/child-child-test-expected.pngBinary files differ new file mode 100644 index 0000000..07d61c0 --- /dev/null +++ b/tests/regression/throwntogethertest/child-child-test-expected.png diff --git a/tests/regression/throwntogethertest/localfiles-test-expected.png b/tests/regression/throwntogethertest/localfiles-test-expected.pngBinary files differ new file mode 100644 index 0000000..7bc7909 --- /dev/null +++ b/tests/regression/throwntogethertest/localfiles-test-expected.png diff --git a/tests/regression/throwntogethertest/module-recursion-expected.png b/tests/regression/throwntogethertest/module-recursion-expected.pngBinary files differ new file mode 100644 index 0000000..324c260 --- /dev/null +++ b/tests/regression/throwntogethertest/module-recursion-expected.png diff --git a/tests/regression/throwntogethertest/modulevariables-expected.png b/tests/regression/throwntogethertest/modulevariables-expected.pngBinary files differ new file mode 100644 index 0000000..bf23265 --- /dev/null +++ b/tests/regression/throwntogethertest/modulevariables-expected.png | 
