diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/MainWindow.h | 4 | ||||
| -rw-r--r-- | src/builtin.cc | 31 | ||||
| -rw-r--r-- | src/builtin.h | 8 | ||||
| -rw-r--r-- | src/cgaladv.cc | 21 | ||||
| -rw-r--r-- | src/color.cc | 15 | ||||
| -rw-r--r-- | src/context.cc | 150 | ||||
| -rw-r--r-- | src/context.h | 34 | ||||
| -rw-r--r-- | src/control.cc | 93 | ||||
| -rw-r--r-- | src/csgops.cc | 7 | ||||
| -rw-r--r-- | src/dxfdim.cc | 48 | ||||
| -rw-r--r-- | src/evalcontext.cc | 40 | ||||
| -rw-r--r-- | src/evalcontext.h | 24 | ||||
| -rw-r--r-- | src/expr.cc | 24 | ||||
| -rw-r--r-- | src/expression.h | 3 | ||||
| -rw-r--r-- | src/func.cc | 230 | ||||
| -rw-r--r-- | src/function.h | 12 | ||||
| -rw-r--r-- | src/import.cc | 36 | ||||
| -rw-r--r-- | src/lexer.l | 1 | ||||
| -rw-r--r-- | src/linearextrude.cc | 23 | ||||
| -rw-r--r-- | src/mainwin.cc | 8 | ||||
| -rw-r--r-- | src/modcontext.cc | 152 | ||||
| -rw-r--r-- | src/modcontext.h | 40 | ||||
| -rw-r--r-- | src/module.cc | 91 | ||||
| -rw-r--r-- | src/module.h | 30 | ||||
| -rw-r--r-- | src/openscad.cc | 15 | ||||
| -rw-r--r-- | src/parser.y | 795 | ||||
| -rw-r--r-- | src/primitives.cc | 26 | ||||
| -rw-r--r-- | src/printutils.cc | 2 | ||||
| -rw-r--r-- | src/printutils.h | 3 | ||||
| -rw-r--r-- | src/projection.cc | 15 | ||||
| -rw-r--r-- | src/render.cc | 15 | ||||
| -rw-r--r-- | src/rotateextrude.cc | 15 | ||||
| -rw-r--r-- | src/surface.cc | 13 | ||||
| -rw-r--r-- | src/transform.cc | 23 | ||||
| -rw-r--r-- | src/typedefs.h | 10 | 
35 files changed, 1150 insertions, 907 deletions
| diff --git a/src/MainWindow.h b/src/MainWindow.h index 8745b8b..65deb15 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -4,7 +4,7 @@  #include <QMainWindow>  #include "ui_MainWindow.h"  #include "openscad.h" -#include "context.h" +#include "modcontext.h"  #include "module.h"  #include "Tree.h"  #include "memory.h" @@ -29,7 +29,7 @@ public:  	QTimer *autoReloadTimer;  	std::string autoReloadId; -	Context root_ctx; +	ModuleContext root_ctx;  	Module *root_module;      // Result of parsing  	ModuleInstantiation root_inst;    // Top level instance  	AbstractNode *absolute_root_node; // Result of tree evaluation diff --git a/src/builtin.cc b/src/builtin.cc index 6eb32b6..bdd2d3b 100644 --- a/src/builtin.cc +++ b/src/builtin.cc @@ -1,6 +1,7 @@  #include "builtin.h"  #include "function.h"  #include "module.h" +#include "expression.h"  #include <boost/foreach.hpp>  Builtins *Builtins::instance(bool erase) @@ -15,12 +16,12 @@ Builtins *Builtins::instance(bool erase)  void Builtins::init(const char *name, class AbstractModule *module)  { -	Builtins::instance()->builtinmodules[name] = module; +	Builtins::instance()->rootmodule.modules[name] = module;  }  void Builtins::init(const char *name, class AbstractFunction *function)  { -	Builtins::instance()->builtinfunctions[name] = function; +	Builtins::instance()->rootmodule.functions[name] = function;  }  extern void register_builtin_functions(); @@ -77,10 +78,28 @@ std::string Builtins::isDeprecated(const std::string &name)  	return std::string();  } +Builtins::Builtins() +{ +	this->rootmodule.assignments_var.push_back("$fn"); +	this->rootmodule.assignments["$fn"] = new Expression(Value(0.0)); +	this->rootmodule.assignments_var.push_back("$fs"); +	this->rootmodule.assignments["$fs"] = new Expression(Value(2.0)); +	this->rootmodule.assignments_var.push_back("$fa"); +	this->rootmodule.assignments["$fa"] = new Expression(Value(12.0)); +	this->rootmodule.assignments_var.push_back("$t"); +	this->rootmodule.assignments["$t"] = new Expression(Value(0.0)); + +	Value::VectorType zero3; +	zero3.push_back(Value(0.0)); +	zero3.push_back(Value(0.0)); +	zero3.push_back(Value(0.0)); +	Value zero3val(zero3); +	this->rootmodule.assignments_var.push_back("$vpt"); +	this->rootmodule.assignments["$vpt"] = new Expression(zero3val); +	this->rootmodule.assignments_var.push_back("$vpr"); +	this->rootmodule.assignments["$vpr"] = new Expression(zero3val); +} +  Builtins::~Builtins()  { -	BOOST_FOREACH(FunctionContainer::value_type &f, this->builtinfunctions) delete f.second; -	this->builtinfunctions.clear(); -	BOOST_FOREACH(ModuleContainer::value_type &m, this->builtinmodules) delete m.second; -	this->builtinmodules.clear();  } diff --git a/src/builtin.h b/src/builtin.h index bc096e5..564c951 100644 --- a/src/builtin.h +++ b/src/builtin.h @@ -3,6 +3,7 @@  #include <string>  #include <boost/unordered_map.hpp> +#include "module.h"  class Builtins  { @@ -19,16 +20,17 @@ public:  	const FunctionContainer &functions() { return this->builtinfunctions; }  	const ModuleContainer &modules() { return this->builtinmodules; } +	const Module &getRootModule() { return this->rootmodule; } +  private: -	Builtins() { } +	Builtins();  	~Builtins(); +	Module rootmodule;  	FunctionContainer builtinfunctions;  	ModuleContainer builtinmodules;  	boost::unordered_map<std::string, std::string> deprecations;  }; -extern void register_builtin(class Context &ctx); -  #endif diff --git a/src/cgaladv.cc b/src/cgaladv.cc index a4cb5ec..aad3a95 100644 --- a/src/cgaladv.cc +++ b/src/cgaladv.cc @@ -26,7 +26,7 @@  #include "cgaladvnode.h"  #include "module.h" -#include "context.h" +#include "evalcontext.h"  #include "builtin.h"  #include "PolySetEvaluator.h"  #include <sstream> @@ -39,30 +39,29 @@ class CgaladvModule : public AbstractModule  public:  	cgaladv_type_e type;  	CgaladvModule(cgaladv_type_e type) : type(type) { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  }; -AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	CgaladvNode *node = new CgaladvNode(inst, type); -	std::vector<std::string> argnames; -	std::vector<Expression*> argexpr; +	AssignmentList args;  	if (type == MINKOWSKI) -		argnames += "convexity"; +		args += Assignment("convexity", NULL);  	if (type == GLIDE) -		argnames += "path", "convexity"; +		args += Assignment("path", NULL), Assignment("convexity", NULL);  	if (type == SUBDIV) -		argnames += "type", "level", "convexity"; +		args += Assignment("type", NULL), Assignment("level", NULL), Assignment("convexity", NULL);  	if (type == RESIZE) -		argnames += "newsize", "auto"; +		args += Assignment("newsize", NULL), Assignment("auto", NULL);  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	Value convexity, path, subdiv_type, level; @@ -111,7 +110,7 @@ AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiat  	if (node->level <= 1)  		node->level = 1; -	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); +	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);  	node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  	return node; diff --git a/src/color.cc b/src/color.cc index acca652..6c3aaef 100644 --- a/src/color.cc +++ b/src/color.cc @@ -26,7 +26,7 @@  #include "colornode.h"  #include "module.h" -#include "context.h" +#include "evalcontext.h"  #include "builtin.h"  #include "printutils.h"  #include <sstream> @@ -40,27 +40,26 @@ class ColorModule : public AbstractModule  {  public:  	ColorModule() { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  private:  	static boost::unordered_map<std::string, Color4f> colormap;  };  #include "colormap.h" -AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	ColorNode *node = new ColorNode(inst);  	node->color[0] = node->color[1] = node->color[2] = -1.0;  	node->color[3] = 1.0; -	std::vector<std::string> argnames; -	std::vector<Expression*> argexpr; +	AssignmentList args; -	argnames += "c", "alpha"; +	args += Assignment("c", NULL), Assignment("alpha", NULL);  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	Value v = c.lookup_variable("c");  	if (v.type() == Value::VECTOR) { @@ -88,7 +87,7 @@ AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiatio  		node->color[3] = alpha.toDouble();  	} -	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); +	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);  	node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  	return node; diff --git a/src/context.cc b/src/context.cc index 97ea5b9..706407c 100644 --- a/src/context.cc +++ b/src/context.cc @@ -25,6 +25,7 @@   */  #include "context.h" +#include "evalcontext.h"  #include "expression.h"  #include "function.h"  #include "module.h" @@ -40,26 +41,11 @@ std::vector<const Context*> Context::ctx_stack;  /*!  	Initializes this context. Optionally initializes a context for an external library  */ -Context::Context(const Context *parent, const Module *library) -	: parent(parent), inst_p(NULL) +Context::Context(const Context *parent) +	: parent(parent)  { -	if (parent) recursioncount = parent->recursioncount;  	ctx_stack.push_back(this);  	if (parent) document_path = parent->document_path; -	if (library) { -		// FIXME: Don't access module members directly -		this->functions_p = &library->functions; -		this->modules_p = &library->modules; -		this->usedlibs_p = &library->usedlibs; -		BOOST_FOREACH(const std::string &var, library->assignments_var) { -			this->set_variable(var, library->assignments.at(var)->evaluate(this)); -		} -	} -	else { -		functions_p = NULL; -		modules_p = NULL; -		usedlibs_p = NULL; -	}  }  Context::~Context() @@ -68,25 +54,26 @@ Context::~Context()  }  /*! -	Initialize context from argument lists (function call/module instantiation) - */ -void Context::args(const std::vector<std::string> &argnames,  -									 const std::vector<Expression*> &argexpr, -									 const std::vector<std::string> &call_argnames,  -									 const std::vector<Value> &call_argvalues) +	Initialize context from a module argument list and a evaluation context +	which may pass variables which will be preferred over default values. +*/ +void Context::setVariables(const AssignmentList &args, +													 const EvalContext *evalctx)  { -	for (size_t i=0; i<argnames.size(); i++) { -		set_variable(argnames[i], i < argexpr.size() && argexpr[i] ?  -								 argexpr[i]->evaluate(this->parent) : Value()); +	BOOST_FOREACH(const Assignment &arg, args) { +		set_variable(arg.first, arg.second ? arg.second->evaluate(this->parent) : Value());  	} -	size_t posarg = 0; -	for (size_t i=0; i<call_argnames.size(); i++) { -		if (call_argnames[i].empty()) { -			if (posarg < argnames.size()) -				set_variable(argnames[posarg++], call_argvalues[i]); -		} else { -			set_variable(call_argnames[i], call_argvalues[i]); +	if (evalctx) { +		size_t posarg = 0; +		for (size_t i=0; i<evalctx->eval_arguments.size(); i++) { +			const std::string &name = evalctx->eval_arguments[i].first; +			const Value &val = evalctx->eval_arguments[i].second; +			if (name.empty()) { +				if (posarg < args.size()) this->set_variable(args[posarg++].first, val); +			} else { +				this->set_variable(name, val); +			}  		}  	}  } @@ -130,61 +117,16 @@ Value Context::lookup_variable(const std::string &name, bool silent) const  	return Value();  } -class RecursionGuard -{ -public: -	RecursionGuard(const Context &c, const std::string &name) : c(c), name(name) { c.recursioncount[name]++; } -	~RecursionGuard() { if (--c.recursioncount[name] == 0) c.recursioncount.erase(name); } -	bool recursion_detected() const { return (c.recursioncount[name] > 100); } -private: -	const Context &c; -	const std::string &name; -}; - -Value Context::evaluate_function(const std::string &name,  -																 const std::vector<std::string> &argnames,  -																 const std::vector<Value> &argvalues) const +Value Context::evaluate_function(const std::string &name, const EvalContext *evalctx) const  { -	RecursionGuard g(*this, name); -	if (g.recursion_detected()) {  -		PRINTB("Recursion detected calling function '%s'", name); -		return Value(); -	} -	if (this->functions_p && this->functions_p->find(name) != this->functions_p->end()) -		return this->functions_p->find(name)->second->evaluate(this, argnames, argvalues); -	if (this->usedlibs_p) { -		BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { -			if (m.second->functions.find(name) != m.second->functions.end()) { -				Context ctx(this->parent, m.second); -				return m.second->functions[name]->evaluate(&ctx, argnames, argvalues); -			} -		} -	} -	if (this->parent) return this->parent->evaluate_function(name, argnames, argvalues); +	if (this->parent) return this->parent->evaluate_function(name, evalctx);  	PRINTB("WARNING: Ignoring unknown function '%s'.", name);  	return Value();  } -AbstractNode *Context::evaluate_module(const ModuleInstantiation &inst) const +AbstractNode *Context::evaluate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const  { -	if (this->modules_p && this->modules_p->find(inst.name()) != this->modules_p->end()) { -		AbstractModule *m = this->modules_p->find(inst.name())->second; -		std::string replacement = Builtins::instance()->isDeprecated(inst.name()); -		if (!replacement.empty()) { -			PRINTB("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", inst.name() % replacement); -		} -		return m->evaluate(this, &inst); -	} -	if (this->usedlibs_p) { -		BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { -			assert(m.second); -			if (m.second->modules.find(inst.name()) != m.second->modules.end()) { -				Context ctx(this->parent, m.second); -				return m.second->modules[inst.name()]->evaluate(&ctx, &inst); -			} -		} -	} -	if (this->parent) return this->parent->evaluate_module(inst); +	if (this->parent) return this->parent->evaluate_module(inst, evalctx);  	PRINTB("WARNING: Ignoring unknown module '%s'.", inst.name());  	return NULL;  } @@ -202,22 +144,34 @@ std::string Context::getAbsolutePath(const std::string &filename) const  	}  } -void register_builtin(Context &ctx) +#ifdef DEBUG +void Context::dump(const AbstractModule *mod, const ModuleInstantiation *inst)  { -	ctx.functions_p = &Builtins::instance()->functions(); -	ctx.modules_p = &Builtins::instance()->modules(); -	ctx.set_variable("$fn", Value(0.0)); -	ctx.set_variable("$fs", Value(2.0)); -	ctx.set_variable("$fa", Value(12.0)); -	ctx.set_variable("$t", Value(0.0)); -	 -	Value::VectorType zero3; -	zero3.push_back(Value(0.0)); -	zero3.push_back(Value(0.0)); -	zero3.push_back(Value(0.0)); -	Value zero3val(zero3); -	ctx.set_variable("$vpt", zero3val); -	ctx.set_variable("$vpr", zero3val); +	if (inst)  +		PRINTB("ModuleContext %p (%p) for %s inst (%p)", this % this->parent % inst->name() % inst); +	else  +		PRINTB("Context: %p (%p)", this % this->parent); +	PRINTB("  document path: %s", this->document_path); +	if (mod) { +		const Module *m = dynamic_cast<const Module*>(mod); +		if (m) { +			PRINT("  module args:"); +			BOOST_FOREACH(const Assignment &arg, m->definition_arguments) { +				PRINTB("    %s = %s", arg.first % variables[arg.first]); +			} +		} +	} +	typedef std::pair<std::string, Value> ValueMapType; +	PRINT("  vars:"); +  BOOST_FOREACH(const ValueMapType &v, constants) { +	  PRINTB("    %s = %s", v.first % v.second); +	}		 +  BOOST_FOREACH(const ValueMapType &v, variables) { +	  PRINTB("    %s = %s", v.first % v.second); +	}		 +  BOOST_FOREACH(const ValueMapType &v, config_variables) { +	  PRINTB("    %s = %s", v.first % v.second); +	}		 -	ctx.set_constant("PI",Value(M_PI));  } +#endif diff --git a/src/context.h b/src/context.h index eb9a175..51fc45c 100644 --- a/src/context.h +++ b/src/context.h @@ -5,48 +5,46 @@  #include <vector>  #include <boost/unordered_map.hpp>  #include "value.h" +#include "typedefs.h"  class Context  {  public: -	Context(const Context *parent = NULL, const class Module *library = NULL); -	~Context(); +	Context(const Context *parent = NULL); +	virtual ~Context(); -	void args(const std::vector<std::string> &argnames,  -						const std::vector<class Expression*> &argexpr,  -						const std::vector<std::string> &call_argnames,  -						const std::vector<Value> &call_argvalues); +	virtual Value evaluate_function(const std::string &name, const class EvalContext *evalctx) const; +	virtual class AbstractNode *evaluate_module(const class ModuleInstantiation &inst, const EvalContext *evalctx) const; + +	void setVariables(const AssignmentList &args, +										const class EvalContext *evalctx = NULL);  	void set_variable(const std::string &name, const Value &value);  	void set_constant(const std::string &name, const Value &value);  	Value lookup_variable(const std::string &name, bool silent = false) const; -	Value evaluate_function(const std::string &name,  -													const std::vector<std::string> &argnames,  -													const std::vector<Value> &argvalues) const; -	class AbstractNode *evaluate_module(const class ModuleInstantiation &inst) const;  	void setDocumentPath(const std::string &path) { this->document_path = path; } +	const std::string &documentPath() const { return this->document_path; }  	std::string getAbsolutePath(const std::string &filename) const;  public:  	const Context *parent; -	const boost::unordered_map<std::string, class AbstractFunction*> *functions_p; -	const boost::unordered_map<std::string, class AbstractModule*> *modules_p; -	typedef boost::unordered_map<std::string, class Module*> ModuleContainer; -	const ModuleContainer *usedlibs_p; -	const ModuleInstantiation *inst_p;  	static std::vector<const Context*> ctx_stack; -	mutable boost::unordered_map<std::string, int> recursioncount; - -private: +protected:  	typedef boost::unordered_map<std::string, Value> ValueMap;  	ValueMap constants;  	ValueMap variables;  	ValueMap config_variables; +  	std::string document_path; + +#ifdef DEBUG +public: +	virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst); +#endif  };  #endif diff --git a/src/control.cc b/src/control.cc index 44847f5..d47eec0 100644 --- a/src/control.cc +++ b/src/control.cc @@ -26,7 +26,8 @@  #include "module.h"  #include "node.h" -#include "context.h" +#include "evalcontext.h" +#include "modcontext.h"  #include "builtin.h"  #include "printutils.h"  #include <sstream> @@ -45,18 +46,16 @@ class ControlModule : public AbstractModule  public:  	control_type_e type;  	ControlModule(control_type_e type) : type(type) { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  };  void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l,  -							const std::vector<std::string> &call_argnames,  -							const std::vector<Value> &call_argvalues,  -							const Context *arg_context) +							const Context *ctx, const EvalContext *evalctx)  { -	if (call_argnames.size() > l) { -		const std::string &it_name = call_argnames[l]; -		const Value &it_values = call_argvalues[l]; -		Context c(arg_context); +	if (evalctx->eval_arguments.size() > l) { +		const std::string &it_name = evalctx->eval_arguments[l].first; +		const Value &it_values = evalctx->eval_arguments[l].second; +		Context c(ctx);  		if (it_values.type() == Value::RANGE) {  			Value::RangeType range = it_values.toRange();  			if (range.end < range.begin) { @@ -67,55 +66,69 @@ void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l,  			if (range.step > 0 && (range.begin-range.end)/range.step < 10000) {  				for (double i = range.begin; i <= range.end; i += range.step) {  					c.set_variable(it_name, Value(i)); -					for_eval(node, inst, l+1, call_argnames, call_argvalues, &c); +					for_eval(node, inst, l+1, &c, evalctx);  				}  			}  		}  		else if (it_values.type() == Value::VECTOR) {  			for (size_t i = 0; i < it_values.toVector().size(); i++) {  				c.set_variable(it_name, it_values.toVector()[i]); -				for_eval(node, inst, l+1, call_argnames, call_argvalues, &c); +				for_eval(node, inst, l+1, &c, evalctx);  			}  		}  		else if (it_values.type() != Value::UNDEFINED) {  			c.set_variable(it_name, it_values); -			for_eval(node, inst, l+1, call_argnames, call_argvalues, &c); +			for_eval(node, inst, l+1, &c, evalctx);  		}  	} else if (l > 0) { -		std::vector<AbstractNode *> evaluatednodes = inst.evaluateChildren(arg_context); +		std::vector<AbstractNode *> evaluatednodes = inst.evaluateChildren(ctx);  		node.children.insert(node.children.end(), evaluatednodes.begin(), evaluatednodes.end());  	}  } -AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation *inst) const +AbstractNode *ControlModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	AbstractNode *node = NULL;  	if (type == CHILD)  	{ -		size_t n = 0; -		if (inst->argvalues.size() > 0) { +		int n = 0; +		if (evalctx->eval_arguments.size() > 0) {  			double v; -			if (inst->argvalues[0].getDouble(v)) { -				if (v < 0) return NULL; // Disallow negative child indices +			if (evalctx->eval_arguments[0].second.getDouble(v)) {  				n = trunc(v); +				if (n < 0) { +					PRINTB("WARNING: Negative child index (%d) not allowed", n); +					return NULL; // Disallow negative child indices +				}  			}  		} -		for (int i = Context::ctx_stack.size()-1; i >= 0; i--) { -			const Context *c = Context::ctx_stack[i]; -			if (c->inst_p) { -				if (n < c->inst_p->children.size()) { -					node = c->inst_p->children[n]->evaluate(c->inst_p->ctx); -					// FIXME: We'd like to inherit any tags from the ModuleInstantiation -					// given as parameter to this method. However, the instantition which belongs -					// to the returned node cannot be changed. This causes the test -					// features/child-background.scad to fail. + +		// Find the last custom module invocation, which will contain +		// an eval context with the children of the module invokation +		const Context *tmpc = evalctx; +		while (tmpc->parent) { +			const ModuleContext *filectx = dynamic_cast<const ModuleContext*>(tmpc->parent); +			if (filectx) { +        // This will trigger if trying to invoke child from the root of any file +        // assert(filectx->evalctx); + +				if (filectx->evalctx) { +					if (n < filectx->evalctx->children.size()) { +						node = filectx->evalctx->children[n]->evaluate_instance(filectx->evalctx); +					} +					else { +						// How to deal with negative objects in this case? +            // (e.g. first child of difference is invalid) +						PRINTB("WARNING: Child index (%d) out of bounds (%d children)",  +									 n % filectx->evalctx->children.size()); +					}  				}  				return node;  			} -			c = c->parent; +			tmpc = tmpc->parent;  		} -		return NULL; +		return node;  	}  	if (type == INT_FOR) @@ -127,20 +140,20 @@ AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation  	{  		std::stringstream msg;  		msg << "ECHO: "; -		for (size_t i = 0; i < inst->argnames.size(); i++) { +		for (size_t i = 0; i < inst->arguments.size(); i++) {  			if (i > 0) msg << ", "; -			if (!inst->argnames[i].empty()) msg << inst->argnames[i] << " = "; -			msg << inst->argvalues[i]; +			if (!evalctx->eval_arguments[i].first.empty()) msg << evalctx->eval_arguments[i].first << " = "; +			msg << evalctx->eval_arguments[i].second;  		}  		PRINTB("%s", msg.str());  	}  	if (type == ASSIGN)  	{ -		Context c(inst->ctx); -		for (size_t i = 0; i < inst->argnames.size(); i++) { -			if (!inst->argnames[i].empty()) -				c.set_variable(inst->argnames[i], inst->argvalues[i]); +		Context c(evalctx); +		for (size_t i = 0; i < evalctx->eval_arguments.size(); i++) { +			if (!evalctx->eval_arguments[i].first.empty()) +				c.set_variable(evalctx->eval_arguments[i].first, evalctx->eval_arguments[i].second);  		}  		std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(&c);  		node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end()); @@ -148,18 +161,18 @@ AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation  	if (type == FOR || type == INT_FOR)  	{ -		for_eval(*node, *inst, 0, inst->argnames, inst->argvalues, inst->ctx); +		for_eval(*node, *inst, 0, evalctx, evalctx);  	}  	if (type == IF)  	{  		const IfElseModuleInstantiation *ifelse = dynamic_cast<const IfElseModuleInstantiation*>(inst); -		if (ifelse->argvalues.size() > 0 && ifelse->argvalues[0].toBool()) { -			std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateChildren(); +		if (evalctx->eval_arguments.size() > 0 && evalctx->eval_arguments[0].second.toBool()) { +			std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateChildren(evalctx);  			node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  		}  		else { -			std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateElseChildren(); +			std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateElseChildren(evalctx);  			node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  		}  	} diff --git a/src/csgops.cc b/src/csgops.cc index 7524559..425b747 100644 --- a/src/csgops.cc +++ b/src/csgops.cc @@ -26,6 +26,7 @@  #include "csgnode.h" +#include "evalcontext.h"  #include "module.h"  #include "csgterm.h"  #include "builtin.h" @@ -37,13 +38,13 @@ class CsgModule : public AbstractModule  public:  	csg_type_e type;  	CsgModule(csg_type_e type) : type(type) { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  }; -AbstractNode *CsgModule::evaluate(const Context*, const ModuleInstantiation *inst) const +AbstractNode *CsgModule::evaluate(const Context*, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	CsgNode *node = new CsgNode(inst, type); -	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); +	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);  	node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  	return node;  } diff --git a/src/dxfdim.cc b/src/dxfdim.cc index 53bc480..fbc24c4 100644 --- a/src/dxfdim.cc +++ b/src/dxfdim.cc @@ -30,7 +30,7 @@  #include "dxfdata.h"  #include "builtin.h"  #include "printutils.h" -#include "context.h" +#include "evalcontext.h"  #include "mathc99.h"  #include <sstream> @@ -40,7 +40,7 @@ boost::unordered_map<std::string,Value> dxf_dim_cache;  boost::unordered_map<std::string,Value> dxf_cross_cache;  namespace fs = boost::filesystem; -Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args) +Value builtin_dxf_dim(const Context *ctx, const EvalContext *evalctx)  {  	std::string filename;  	std::string layername; @@ -51,18 +51,18 @@ Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnam    // FIXME: We don't lookup the file relative to where this function was instantiated  	// since the path is only available for ModuleInstantiations, not function expressions. -	// See isse #217 -	for (size_t i = 0; i < argnames.size() && i < args.size(); i++) { -		if (argnames[i] == "file") -			filename = ctx->getAbsolutePath(args[i].toString()); -		if (argnames[i] == "layer") -			layername = args[i].toString(); -		if (argnames[i] == "origin") -			args[i].getVec2(xorigin, yorigin); -		if (argnames[i] == "scale") -			args[i].getDouble(scale); -		if (argnames[i] == "name") -			name = args[i].toString(); +	// See issue #217 +	for (size_t i = 0; i < evalctx->eval_arguments.size(); i++) { +		if (evalctx->eval_arguments[i].first == "file") +			filename = ctx->getAbsolutePath(evalctx->eval_arguments[i].second.toString()); +		if (evalctx->eval_arguments[i].first == "layer") +			layername = evalctx->eval_arguments[i].second.toString(); +		if (evalctx->eval_arguments[i].first == "origin") +			evalctx->eval_arguments[i].second.getVec2(xorigin, yorigin); +		if (evalctx->eval_arguments[i].first == "scale") +			evalctx->eval_arguments[i].second.getDouble(scale); +		if (evalctx->eval_arguments[i].first == "name") +			name = evalctx->eval_arguments[i].second.toString();  	}  	std::stringstream keystream; @@ -135,7 +135,7 @@ Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnam  	return Value();  } -Value builtin_dxf_cross(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args) +Value builtin_dxf_cross(const Context *ctx, const EvalContext *evalctx)  {  	std::string filename;  	std::string layername; @@ -146,15 +146,15 @@ Value builtin_dxf_cross(const Context *ctx, const std::vector<std::string> &argn    // FIXME: We don't lookup the file relative to where this function was instantiated  	// since the path is only available for ModuleInstantiations, not function expressions.  	// See isse #217 -	for (size_t i = 0; i < argnames.size() && i < args.size(); i++) { -		if (argnames[i] == "file") -			filename = ctx->getAbsolutePath(args[i].toString()); -		if (argnames[i] == "layer") -			layername = args[i].toString(); -		if (argnames[i] == "origin") -			args[i].getVec2(xorigin, yorigin); -		if (argnames[i] == "scale") -			args[i].getDouble(scale); +	for (size_t i = 0; i < evalctx->eval_arguments.size(); i++) { +		if (evalctx->eval_arguments[i].first == "file") +			filename = ctx->getAbsolutePath(evalctx->eval_arguments[i].second.toString()); +		if (evalctx->eval_arguments[i].first == "layer") +			layername = evalctx->eval_arguments[i].second.toString(); +		if (evalctx->eval_arguments[i].first == "origin") +			evalctx->eval_arguments[i].second.getVec2(xorigin, yorigin); +		if (evalctx->eval_arguments[i].first == "scale") +			evalctx->eval_arguments[i].second.getDouble(scale);  	}  	std::stringstream keystream; diff --git a/src/evalcontext.cc b/src/evalcontext.cc new file mode 100644 index 0000000..b7566e3 --- /dev/null +++ b/src/evalcontext.cc @@ -0,0 +1,40 @@ +#include "evalcontext.h" +#include "module.h" +#include "expression.h" +#include "function.h" +#include "printutils.h" +#include "builtin.h" + +#include <boost/foreach.hpp> + +#ifdef DEBUG +void EvalContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst) +{ +	if (inst)  +		PRINTB("EvalContext %p (%p) for %s inst (%p)", this % this->parent % inst->name() % inst); +	else  +		PRINTB("Context: %p (%p)", this % this->parent); +	PRINTB("  document path: %s", this->document_path); + +	PRINT("  eval args:"); +	for (int i=0;i<this->eval_arguments.size();i++) { +		PRINTB("    %s = %s", this->eval_arguments[i].first % this->eval_arguments[i].second); +	} +	if (this->children.size() > 0) { +		PRINT("    children:"); +		BOOST_FOREACH(const ModuleInstantiation *ch, this->children) { +			PRINTB("      %s", ch->name()); +		} +	} +		 +	if (mod) { +		const Module *m = dynamic_cast<const Module*>(mod); +		if (m) { +			PRINT("  module args:"); +			BOOST_FOREACH(const Assignment &arg, m->definition_arguments) { +				PRINTB("    %s = %s", arg.first % variables[arg.first]); +			} +		} +	} +} +#endif diff --git a/src/evalcontext.h b/src/evalcontext.h new file mode 100644 index 0000000..3d7d222 --- /dev/null +++ b/src/evalcontext.h @@ -0,0 +1,24 @@ +#ifndef EVALCONTEXT_H_ +#define EVALCONTEXT_H_ + +#include "context.h" + +/*! +  This hold the evaluation context (the parameters actually sent +	when calling a module or function, including the children). +*/ +class EvalContext : public Context +{ +public: +	EvalContext(const Context *parent = NULL) : Context(parent) {} +	virtual ~EvalContext() {} + +	std::vector<std::pair<std::string, Value> > eval_arguments; +	std::vector<class ModuleInstantiation *> children; + +#ifdef DEBUG +	virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst); +#endif +}; + +#endif diff --git a/src/expr.cc b/src/expr.cc index 75fc47a..7a8180f 100644 --- a/src/expr.cc +++ b/src/expr.cc @@ -26,7 +26,7 @@  #include "expression.h"  #include "value.h" -#include "context.h" +#include "evalcontext.h"  #include <assert.h>  #include <sstream>  #include <algorithm> @@ -127,13 +127,18 @@ Value Expression::evaluate(const Context *context) const  		return Value();  	}  	if (this->type == "F") { -		Value::VectorType argvalues; -		std::transform(this->children.begin(), this->children.end(),  -									 std::back_inserter(argvalues),  -									 boost::bind(&Expression::evaluate, _1, context)); +		EvalContext c(context); +		for (size_t i=0; i < this->call_arguments.size(); i++) { +			c.eval_arguments.push_back(std::make_pair(this->call_arguments[i].first,  +																								this->call_arguments[i].second->evaluate(context))); +		} +		// Value::VectorType argvalues; +		// std::transform(this->children.begin(), this->children.end(),  +		// 							 std::back_inserter(argvalues),  +		// 							 boost::bind(&Expression::evaluate, _1, context));  		// for (size_t i=0; i < this->children.size(); i++)  		// 	argvalues.push_back(this->children[i]->evaluate(context)); -		return context->evaluate_function(this->call_funcname, this->call_argnames, argvalues); +		return context->evaluate_function(this->call_funcname, &c);  	}  	abort();  } @@ -178,10 +183,11 @@ std::string Expression::toString() const  	}  	else if (this->type == "F") {  		stream << this->call_funcname << "("; -		for (size_t i=0; i < this->children.size(); i++) { +		for (size_t i=0; i < this->call_arguments.size(); i++) { +			const Assignment &arg = this->call_arguments[i];  			if (i > 0) stream << ", "; -			if (!this->call_argnames[i].empty()) stream << this->call_argnames[i]  << " = "; -			stream << *this->children[i]; +			if (!arg.first.empty()) stream << arg.first  << " = "; +			stream << *arg.second;  		}  		stream << ")";  	} diff --git a/src/expression.h b/src/expression.h index 2919b78..06becc0 100644 --- a/src/expression.h +++ b/src/expression.h @@ -4,6 +4,7 @@  #include <string>  #include <vector>  #include "value.h" +#include "typedefs.h"  class Expression  { @@ -14,7 +15,7 @@ public:  	std::string var_name;  	std::string call_funcname; -	std::vector<std::string> call_argnames; +	AssignmentList call_arguments;  	// Boolean: ! && ||  	// Operators: * / % + - diff --git a/src/func.cc b/src/func.cc index 26d7e69..88bf3c8 100644 --- a/src/func.cc +++ b/src/func.cc @@ -26,7 +26,7 @@  #include "function.h"  #include "expression.h" -#include "context.h" +#include "evalcontext.h"  #include "builtin.h"  #include <sstream>  #include <ctime> @@ -34,6 +34,7 @@  #include <algorithm>  #include "stl-utils.h"  #include "printutils.h" +#include <boost/foreach.hpp>  /*   Random numbers @@ -61,7 +62,7 @@ AbstractFunction::~AbstractFunction()  {  } -Value AbstractFunction::evaluate(const Context*, const std::vector<std::string>&, const std::vector<Value>&) const +Value AbstractFunction::evaluate(const Context*, const EvalContext *evalctx) const  {  	return Value();  } @@ -75,16 +76,14 @@ std::string AbstractFunction::dump(const std::string &indent, const std::string  Function::~Function()  { -	std::for_each(this->argexpr.begin(), this->argexpr.end(), del_fun<Expression>()); +	BOOST_FOREACH(const Assignment &arg, this->definition_arguments) delete arg.second;  	delete expr;  } -Value Function::evaluate(const Context *ctx,  -												 const std::vector<std::string> &call_argnames,  -												 const std::vector<Value> &call_argvalues) const +Value Function::evaluate(const Context *ctx, const EvalContext *evalctx) const  {  	Context c(ctx); -	c.args(argnames, argexpr, call_argnames, call_argvalues); +	c.setVariables(definition_arguments, evalctx);  	return expr ? expr->evaluate(&c) : Value();  } @@ -92,10 +91,11 @@ std::string Function::dump(const std::string &indent, const std::string &name) c  {  	std::stringstream dump;  	dump << indent << "function " << name << "("; -	for (size_t i=0; i < argnames.size(); i++) { +	for (size_t i=0; i < definition_arguments.size(); i++) { +		const Assignment &arg = definition_arguments[i];  		if (i > 0) dump << ", "; -		dump << argnames[i]; -		if (argexpr[i]) dump << " = " << *argexpr[i]; +		dump << arg.first; +		if (arg.second) dump << " = " << *arg.second;  	}  	dump << ") = " << *expr << ";\n";  	return dump.str(); @@ -105,9 +105,9 @@ BuiltinFunction::~BuiltinFunction()  {  } -Value BuiltinFunction::evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const +Value BuiltinFunction::evaluate(const Context *ctx, const EvalContext *evalctx) const  { -	return eval_func(ctx, call_argnames, call_argvalues); +	return eval_func(ctx, evalctx);  }  std::string BuiltinFunction::dump(const std::string &indent, const std::string &name) const @@ -127,37 +127,37 @@ static inline double rad2deg(double x)  	return x * 180.0 / M_PI;  } -Value builtin_abs(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_abs(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(fabs(args[0].toDouble())); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(fabs(evalctx->eval_arguments[0].second.toDouble()));  	return Value();  } -Value builtin_sign(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_sign(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value((args[0].toDouble()<0) ? -1.0 : ((args[0].toDouble()>0) ? 1.0 : 0.0)); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value((evalctx->eval_arguments[0].second.toDouble()<0) ? -1.0 : ((evalctx->eval_arguments[0].second.toDouble()>0) ? 1.0 : 0.0));  	return Value();  } -Value builtin_rands(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_rands(const Context *, const EvalContext *evalctx)  {  	bool deterministic = false; -	if (args.size() == 3 && -			args[0].type() == Value::NUMBER &&  -			args[1].type() == Value::NUMBER &&  -			args[2].type() == Value::NUMBER) +	if (evalctx->eval_arguments.size() == 3 && +			evalctx->eval_arguments[0].second.type() == Value::NUMBER &&  +			evalctx->eval_arguments[1].second.type() == Value::NUMBER &&  +			evalctx->eval_arguments[2].second.type() == Value::NUMBER)  	{  		deterministic = false;  	} -	else if (args.size() == 4 &&  -					 args[0].type() == Value::NUMBER &&  -					 args[1].type() == Value::NUMBER &&  -					 args[2].type() == Value::NUMBER &&  -					 args[3].type() == Value::NUMBER) +	else if (evalctx->eval_arguments.size() == 4 &&  +					 evalctx->eval_arguments[0].second.type() == Value::NUMBER &&  +					 evalctx->eval_arguments[1].second.type() == Value::NUMBER &&  +					 evalctx->eval_arguments[2].second.type() == Value::NUMBER &&  +					 evalctx->eval_arguments[3].second.type() == Value::NUMBER)  	{ -		deterministic_rng.seed( (unsigned int) args[3].toDouble() ); +		deterministic_rng.seed( (unsigned int) evalctx->eval_arguments[3].second.toDouble() );  		deterministic = true;  	}  	else @@ -165,11 +165,11 @@ Value builtin_rands(const Context *, const std::vector<std::string>&, const std:  		return Value();  	} -	double min = std::min( args[0].toDouble(), args[1].toDouble() ); -	double max = std::max( args[0].toDouble(), args[1].toDouble() ); +	double min = std::min( evalctx->eval_arguments[0].second.toDouble(), evalctx->eval_arguments[1].second.toDouble() ); +	double max = std::max( evalctx->eval_arguments[0].second.toDouble(), evalctx->eval_arguments[1].second.toDouble() );  	boost::uniform_real<> distributor( min, max );  	Value::VectorType vec; -	for (int i=0; i<args[2].toDouble(); i++) { +	for (int i=0; i<evalctx->eval_arguments[2].second.toDouble(); i++) {  		if ( deterministic ) {  			vec.push_back( Value( distributor( deterministic_rng ) ) );  		} else { @@ -181,169 +181,169 @@ Value builtin_rands(const Context *, const std::vector<std::string>&, const std:  } -Value builtin_min(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_min(const Context *, const EvalContext *evalctx)  { -	if (args.size() >= 1 && args[0].type() == Value::NUMBER) { -		double val = args[0].toDouble(); -		for (size_t i = 1; i < args.size(); i++) -			if (args[1].type() == Value::NUMBER) -				val = fmin(val, args[i].toDouble()); +	if (evalctx->eval_arguments.size() >= 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) { +		double val = evalctx->eval_arguments[0].second.toDouble(); +		for (size_t i = 1; i < evalctx->eval_arguments.size(); i++) +			if (evalctx->eval_arguments[1].second.type() == Value::NUMBER) +				val = fmin(val, evalctx->eval_arguments[i].second.toDouble());  		return Value(val);  	}  	return Value();  } -Value builtin_max(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_max(const Context *, const EvalContext *evalctx)  { -	if (args.size() >= 1 && args[0].type() == Value::NUMBER) { -		double val = args[0].toDouble(); -		for (size_t i = 1; i < args.size(); i++) -			if (args[1].type() == Value::NUMBER) -				val = fmax(val, args[i].toDouble()); +	if (evalctx->eval_arguments.size() >= 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) { +		double val = evalctx->eval_arguments[0].second.toDouble(); +		for (size_t i = 1; i < evalctx->eval_arguments.size(); i++) +			if (evalctx->eval_arguments[1].second.type() == Value::NUMBER) +				val = fmax(val, evalctx->eval_arguments[i].second.toDouble());  		return Value(val);  	}  	return Value();  } -Value builtin_sin(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_sin(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(sin(deg2rad(args[0].toDouble()))); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(sin(deg2rad(evalctx->eval_arguments[0].second.toDouble())));  	return Value();  } -Value builtin_cos(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_cos(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(cos(deg2rad(args[0].toDouble()))); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(cos(deg2rad(evalctx->eval_arguments[0].second.toDouble())));  	return Value();  } -Value builtin_asin(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_asin(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(rad2deg(asin(args[0].toDouble()))); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(rad2deg(asin(evalctx->eval_arguments[0].second.toDouble())));  	return Value();  } -Value builtin_acos(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_acos(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(rad2deg(acos(args[0].toDouble()))); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(rad2deg(acos(evalctx->eval_arguments[0].second.toDouble())));  	return Value();  } -Value builtin_tan(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_tan(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(tan(deg2rad(args[0].toDouble()))); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(tan(deg2rad(evalctx->eval_arguments[0].second.toDouble())));  	return Value();  } -Value builtin_atan(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_atan(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(rad2deg(atan(args[0].toDouble()))); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(rad2deg(atan(evalctx->eval_arguments[0].second.toDouble())));  	return Value();  } -Value builtin_atan2(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_atan2(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER) -		return Value(rad2deg(atan2(args[0].toDouble(), args[1].toDouble()))); +	if (evalctx->eval_arguments.size() == 2 && evalctx->eval_arguments[0].second.type() == Value::NUMBER && evalctx->eval_arguments[1].second.type() == Value::NUMBER) +		return Value(rad2deg(atan2(evalctx->eval_arguments[0].second.toDouble(), evalctx->eval_arguments[1].second.toDouble())));  	return Value();  } -Value builtin_pow(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_pow(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER) -		return Value(pow(args[0].toDouble(), args[1].toDouble())); +	if (evalctx->eval_arguments.size() == 2 && evalctx->eval_arguments[0].second.type() == Value::NUMBER && evalctx->eval_arguments[1].second.type() == Value::NUMBER) +		return Value(pow(evalctx->eval_arguments[0].second.toDouble(), evalctx->eval_arguments[1].second.toDouble()));  	return Value();  } -Value builtin_round(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_round(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(round(args[0].toDouble())); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(round(evalctx->eval_arguments[0].second.toDouble()));  	return Value();  } -Value builtin_ceil(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_ceil(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(ceil(args[0].toDouble())); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(ceil(evalctx->eval_arguments[0].second.toDouble()));  	return Value();  } -Value builtin_floor(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_floor(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(floor(args[0].toDouble())); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(floor(evalctx->eval_arguments[0].second.toDouble()));  	return Value();  } -Value builtin_sqrt(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_sqrt(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(sqrt(args[0].toDouble())); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(sqrt(evalctx->eval_arguments[0].second.toDouble()));  	return Value();  } -Value builtin_exp(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_exp(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(exp(args[0].toDouble())); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(exp(evalctx->eval_arguments[0].second.toDouble()));  	return Value();  } -Value builtin_length(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_length(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1) { -		if (args[0].type() == Value::VECTOR) return Value(int(args[0].toVector().size())); -		if (args[0].type() == Value::STRING) return Value(int(args[0].toString().size())); +	if (evalctx->eval_arguments.size() == 1) { +		if (evalctx->eval_arguments[0].second.type() == Value::VECTOR) return Value(int(evalctx->eval_arguments[0].second.toVector().size())); +		if (evalctx->eval_arguments[0].second.type() == Value::STRING) return Value(int(evalctx->eval_arguments[0].second.toString().size()));  	}  	return Value();  } -Value builtin_log(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_log(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER) -		return Value(log(args[1].toDouble()) / log(args[0].toDouble())); -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(log(args[0].toDouble()) / log(10.0)); +	if (evalctx->eval_arguments.size() == 2 && evalctx->eval_arguments[0].second.type() == Value::NUMBER && evalctx->eval_arguments[1].second.type() == Value::NUMBER) +		return Value(log(evalctx->eval_arguments[1].second.toDouble()) / log(evalctx->eval_arguments[0].second.toDouble())); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(log(evalctx->eval_arguments[0].second.toDouble()) / log(10.0));  	return Value();  } -Value builtin_ln(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_ln(const Context *, const EvalContext *evalctx)  { -	if (args.size() == 1 && args[0].type() == Value::NUMBER) -		return Value(log(args[0].toDouble())); +	if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) +		return Value(log(evalctx->eval_arguments[0].second.toDouble()));  	return Value();  } -Value builtin_str(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_str(const Context *, const EvalContext *evalctx)  {  	std::stringstream stream; -	for (size_t i = 0; i < args.size(); i++) { -		stream << args[i].toString(); +	for (size_t i = 0; i < evalctx->eval_arguments.size(); i++) { +		stream << evalctx->eval_arguments[i].second.toString();  	}  	return Value(stream.str());  } -Value builtin_lookup(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_lookup(const Context *, const EvalContext *evalctx)  {  	double p, low_p, low_v, high_p, high_v; -	if (args.size() < 2 ||                     // Needs two args -			!args[0].getDouble(p) ||                  // First must be a number -			args[1].toVector().size() < 2 ||       // Second must be a vector of vectors -			args[1].toVector()[0].toVector().size() < 2) +	if (evalctx->eval_arguments.size() < 2 ||                     // Needs two args +			!evalctx->eval_arguments[0].second.getDouble(p) ||                  // First must be a number +			evalctx->eval_arguments[1].second.toVector().size() < 2 ||       // Second must be a vector of vectors +			evalctx->eval_arguments[1].second.toVector()[0].toVector().size() < 2)  		return Value(); -	if (!args[1].toVector()[0].getVec2(low_p, low_v) || !args[1].toVector()[0].getVec2(high_p, high_v)) +	if (!evalctx->eval_arguments[1].second.toVector()[0].getVec2(low_p, low_v) || !evalctx->eval_arguments[1].second.toVector()[0].getVec2(high_p, high_v))  		return Value(); -	for (size_t i = 1; i < args[1].toVector().size(); i++) { +	for (size_t i = 1; i < evalctx->eval_arguments[1].second.toVector().size(); i++) {  		double this_p, this_v; -		if (args[1].toVector()[i].getVec2(this_p, this_v)) { +		if (evalctx->eval_arguments[1].second.toVector()[i].getVec2(this_p, this_v)) {  			if (this_p <= p && (this_p > low_p || low_p > p)) {  				low_p = this_p;  				low_v = this_v; @@ -404,14 +404,14 @@ Value builtin_lookup(const Context *, const std::vector<std::string>&, const std          - returns [[0,4],[1,5],[2,6],[8]]  */ -Value builtin_search(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_search(const Context *, const EvalContext *evalctx)  { -	if (args.size() < 2) return Value(); +	if (evalctx->eval_arguments.size() < 2) return Value(); -	const Value &findThis = args[0]; -	const Value &searchTable = args[1]; -	unsigned int num_returns_per_match = (args.size() > 2) ? args[2].toDouble() : 1; -	unsigned int index_col_num = (args.size() > 3) ? args[3].toDouble() : 0; +	const Value &findThis = evalctx->eval_arguments[0].second; +	const Value &searchTable = evalctx->eval_arguments[1].second; +	unsigned int num_returns_per_match = (evalctx->eval_arguments.size() > 2) ? evalctx->eval_arguments[2].second.toDouble() : 1; +	unsigned int index_col_num = (evalctx->eval_arguments.size() > 3) ? evalctx->eval_arguments[3].second.toDouble() : 0;  	Value::VectorType returnvec; @@ -499,7 +499,7 @@ Value builtin_search(const Context *, const std::vector<std::string>&, const std  #define QUOTE(x__) # x__  #define QUOTED(x__) QUOTE(x__) -Value builtin_version(const Context *, const std::vector<std::string>&, const std::vector<Value> &) +Value builtin_version(const Context *, const EvalContext *evalctx)  {  	Value::VectorType val;  	val.push_back(Value(double(OPENSCAD_YEAR))); @@ -510,9 +510,9 @@ Value builtin_version(const Context *, const std::vector<std::string>&, const st  	return Value(val);  } -Value builtin_version_num(const Context *ctx, const std::vector<std::string>& call_argnames, const std::vector<Value> &args) +Value builtin_version_num(const Context *ctx, const EvalContext *evalctx)  { -	Value val = (args.size() == 0) ? builtin_version(ctx, call_argnames, args) : args[0]; +	Value val = (evalctx->eval_arguments.size() == 0) ? builtin_version(ctx, evalctx) : evalctx->eval_arguments[0].second;  	double y, m, d = 0;  	if (!val.getVec3(y, m, d)) {  		if (!val.getVec2(y, m)) { diff --git a/src/function.h b/src/function.h index 623ef7e..a1fde3c 100644 --- a/src/function.h +++ b/src/function.h @@ -2,6 +2,7 @@  #define FUNCTION_H_  #include "value.h" +#include "typedefs.h"  #include <string>  #include <vector> @@ -9,35 +10,34 @@ class AbstractFunction  {  public:  	virtual ~AbstractFunction(); -	virtual Value evaluate(const class Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const; +	virtual Value evaluate(const class Context *ctx, const class EvalContext *evalctx) const;  	virtual std::string dump(const std::string &indent, const std::string &name) const;  };  class BuiltinFunction : public AbstractFunction  {  public: -	typedef Value (*eval_func_t)(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args); +	typedef Value (*eval_func_t)(const Context *ctx, const EvalContext *evalctx);  	eval_func_t eval_func;  	BuiltinFunction(eval_func_t f) : eval_func(f) { }  	virtual ~BuiltinFunction(); -	virtual Value evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const; +	virtual Value evaluate(const Context *ctx, const EvalContext *evalctx) const;  	virtual std::string dump(const std::string &indent, const std::string &name) const;  };  class Function : public AbstractFunction  {  public: -	std::vector<std::string> argnames; -	std::vector<class Expression*> argexpr; +	AssignmentList definition_arguments;  	Expression *expr;  	Function() { }  	virtual ~Function(); -	virtual Value evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const; +	virtual Value evaluate(const Context *ctx, const EvalContext *evalctx) const;  	virtual std::string dump(const std::string &indent, const std::string &name) const;  }; diff --git a/src/import.cc b/src/import.cc index 627fb56..927c9d8 100644 --- a/src/import.cc +++ b/src/import.cc @@ -28,7 +28,7 @@  #include "module.h"  #include "polyset.h" -#include "context.h" +#include "evalcontext.h"  #include "builtin.h"  #include "dxfdata.h"  #include "dxftess.h" @@ -60,26 +60,43 @@ class ImportModule : public AbstractModule  public:  	import_type_e type;  	ImportModule(import_type_e type = TYPE_UNKNOWN) : type(type) { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  }; -AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  { -	std::vector<std::string> argnames; -	argnames += "file", "layer", "convexity", "origin", "scale"; -	std::vector<Expression*> argexpr; +	AssignmentList args; +	args += Assignment("file", NULL), Assignment("layer", NULL), Assignment("convexity", NULL), Assignment("origin", NULL), Assignment("scale", NULL); +	args += Assignment("filename",NULL), Assignment("layername", NULL); +  // FIXME: This is broken. Tag as deprecated and fix  	// Map old argnames to new argnames for compatibility +	// To fix:  +  // o after c.setVariables() +	//   - if "filename" in evalctx: deprecated-warning && v.set_variable("file", value); +	//   - if "layername" in evalctx: deprecated-warning && v.set_variable("layer", value); +#if 0  	std::vector<std::string> inst_argnames = inst->argnames;  	for (size_t i=0; i<inst_argnames.size(); i++) {  		if (inst_argnames[i] == "filename") inst_argnames[i] = "file";  		if (inst_argnames[i] == "layername") inst_argnames[i] = "layer";  	} +#endif  	Context c(ctx); -	c.args(argnames, argexpr, inst_argnames, inst->argvalues); +	c.setDocumentPath(evalctx->documentPath()); +	c.setVariables(args, evalctx); +#if 0 && DEBUG +	c.dump(this, inst); +#endif  	Value v = c.lookup_variable("file"); +	if (v.isUndefined()) { +		v = c.lookup_variable("filename"); +		if (!v.isUndefined()) +			PRINT("WARNING: filename= is deprecated. Please use file="); +	} +  	std::string filename = inst->getAbsolutePath(v.isUndefined() ? "" : v.toString());  	import_type_e actualtype = this->type;  	if (actualtype == TYPE_UNKNOWN) { @@ -98,6 +115,11 @@ AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiati  	node->filename = filename;  	Value layerval = c.lookup_variable("layer", true); +	if (layerval.isUndefined()) { +		layerval = c.lookup_variable("layername",true); +		if (!layerval.isUndefined()) +			PRINT("WARNING: layername= is deprecated. Please use layer="); +	}  	node->layername = layerval.isUndefined() ? ""  : layerval.toString();  	node->convexity = c.lookup_variable("convexity", true).toDouble(); diff --git a/src/lexer.l b/src/lexer.l index 4dff654..6766abc 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -26,6 +26,7 @@  %{ +#include "typedefs.h"  #include "handle_dep.h"  #include "printutils.h"  #include "parsersettings.h" diff --git a/src/linearextrude.cc b/src/linearextrude.cc index ff9682e..f4c1112 100644 --- a/src/linearextrude.cc +++ b/src/linearextrude.cc @@ -27,7 +27,7 @@  #include "linearextrudenode.h"  #include "module.h" -#include "context.h" +#include "evalcontext.h"  #include "printutils.h"  #include "builtin.h"  #include "PolySetEvaluator.h" @@ -45,19 +45,18 @@ class LinearExtrudeModule : public AbstractModule  {  public:  	LinearExtrudeModule() { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  }; -AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	LinearExtrudeNode *node = new LinearExtrudeNode(inst); -	std::vector<std::string> argnames; -	argnames += "file", "layer", "height", "origin", "scale", "center", "twist", "slices"; -	std::vector<Expression*> argexpr; +	AssignmentList args; +	args += Assignment("file", NULL), Assignment("layer", NULL), Assignment("height", NULL), Assignment("origin", NULL), Assignment("scale", NULL), Assignment("center", NULL), Assignment("twist", NULL), Assignment("slices", NULL);  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	node->fn = c.lookup_variable("$fn").toDouble();  	node->fs = c.lookup_variable("$fs").toDouble(); @@ -81,10 +80,10 @@ AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInst  	// if height not given, and first argument is a number,  	// then assume it should be the height.  	if (c.lookup_variable("height").isUndefined() && -			inst->argnames.size() > 0 &&  -			inst->argnames[0] == "" && -			inst->argvalues[0].type() == Value::NUMBER) { -		height = Value(inst->argvalues[0]); +			evalctx->eval_arguments.size() > 0 &&  +			evalctx->eval_arguments[0].first == "" && +			evalctx->eval_arguments[0].second.type() == Value::NUMBER) { +		height = Value(evalctx->eval_arguments[0].second);  	}  	node->layername = layer.isUndefined() ? "" : layer.toString(); @@ -117,7 +116,7 @@ AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInst  	}  	if (node->filename.empty()) { -		std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); +		std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);  		node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  	} diff --git a/src/mainwin.cc b/src/mainwin.cc index dd855fb..2e69ec2 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -158,7 +158,7 @@ settings_valueList(const QString &key, const QList<int> &defaultList = QList<int  }  MainWindow::MainWindow(const QString &filename) -	: progresswidget(NULL) +	: root_inst("group"), progresswidget(NULL)  {  	setupUi(this); @@ -168,7 +168,7 @@ MainWindow::MainWindow(const QString &filename)  					this, SLOT(actionRenderCGALDone(CGAL_Nef_polyhedron *)));  #endif -	register_builtin(root_ctx); +	root_ctx.registerBuiltin();  	this->openglbox = NULL;  	root_module = NULL; @@ -643,8 +643,8 @@ bool MainWindow::compile(bool reload, bool procevents)  		if (procevents) QApplication::processEvents();  		AbstractNode::resetIndexCounter(); -		this->root_inst = ModuleInstantiation(); -		this->absolute_root_node = this->root_module->evaluate(&this->root_ctx, &this->root_inst); +		this->root_inst = ModuleInstantiation("group"); +		this->absolute_root_node = this->root_module->evaluate(&this->root_ctx, &this->root_inst, NULL);  		if (this->absolute_root_node) {  			// Do we have an explicit root node (! modifier)? diff --git a/src/modcontext.cc b/src/modcontext.cc new file mode 100644 index 0000000..7d123b8 --- /dev/null +++ b/src/modcontext.cc @@ -0,0 +1,152 @@ +#include "modcontext.h" +#include "module.h" +#include "expression.h" +#include "function.h" +#include "printutils.h" +#include "builtin.h" + +#include <boost/foreach.hpp> + +ModuleContext::ModuleContext(const class Module *module, const Context *parent, const EvalContext *evalctx) +	: Context(parent) +{ +	if (module) { +		setModule(*module, evalctx); +	} +	else { +		this->functions_p = NULL; +		this->modules_p = NULL; +		this->usedlibs_p = NULL; +	} +} + +ModuleContext::~ModuleContext() +{ +} + +void ModuleContext::setModule(const Module &module, const EvalContext *evalctx) +{ +	this->setVariables(module.definition_arguments, evalctx); +	this->evalctx = evalctx; + +	// FIXME: Don't access module members directly +	this->functions_p = &module.functions; +	this->modules_p = &module.modules; +	this->usedlibs_p = &module.usedlibs; +	BOOST_FOREACH(const std::string &var, module.assignments_var) { +		this->set_variable(var, module.assignments.at(var)->evaluate(this)); +	} +	 +	if (!module.modulePath().empty()) this->document_path = module.modulePath(); +} + +/*! +	Only used to initialize builtins for the top-level root context +*/ +void ModuleContext::registerBuiltin() +{ +	this->setModule(Builtins::instance()->getRootModule()); +	this->set_constant("PI",Value(M_PI)); +} + +class RecursionGuard +{ +public: +	RecursionGuard(const ModuleContext &c, const std::string &name) : c(c), name(name) {  +		c.recursioncount[name]++;  +	} +	~RecursionGuard() { if (--c.recursioncount[name] == 0) c.recursioncount.erase(name); } +	bool recursion_detected() const { return (c.recursioncount[name] > 100); } +private: +	const ModuleContext &c; +	const std::string &name; +}; + +Value ModuleContext::evaluate_function(const std::string &name, const EvalContext *evalctx) const +{ +	RecursionGuard g(*this, name); +	if (g.recursion_detected()) {  +		PRINTB("Recursion detected calling function '%s'", name); +		return Value(); +	} + +	if (this->functions_p && this->functions_p->find(name) != this->functions_p->end()) { +		return this->functions_p->find(name)->second->evaluate(this, evalctx); +	} +	 +	if (this->usedlibs_p) { +		BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { +			if (m.second->functions.find(name) != m.second->functions.end()) { +				ModuleContext ctx(m.second, this->parent); +				// FIXME: Set document path +#if 0 && DEBUG +				PRINTB("New lib Context for %s func:", name); +				ctx.dump(NULL, NULL); +#endif +				return m.second->functions[name]->evaluate(&ctx, evalctx); +			} +		} +	} +	return Context::evaluate_function(name, evalctx); +} + +AbstractNode *ModuleContext::evaluate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const +{ +	if (this->modules_p && this->modules_p->find(inst.name()) != this->modules_p->end()) { +		AbstractModule *m = this->modules_p->find(inst.name())->second; +		std::string replacement = Builtins::instance()->isDeprecated(inst.name()); +		if (!replacement.empty()) { +			PRINTB("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", inst.name() % replacement); +		} +		return m->evaluate(this, &inst, evalctx); +	} + +	if (this->usedlibs_p) { +		BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { +			assert(m.second); +			if (m.second->modules.find(inst.name()) != m.second->modules.end()) { +				ModuleContext ctx(m.second, this->parent); +				// FIXME: Set document path +#if 0 && DEBUG +				PRINT("New lib Context:"); +				ctx.dump(NULL, &inst); +#endif +				return m.second->modules[inst.name()]->evaluate(&ctx, &inst, evalctx); +			} +		} +	} + +	return Context::evaluate_module(inst, evalctx); +} + +#ifdef DEBUG +void ModuleContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst) +{ +	if (inst)  +		PRINTB("ModuleContext %p (%p) for %s inst (%p) ", this % this->parent % inst->name() % inst); +	else  +		PRINTB("ModuleContext: %p (%p)", this % this->parent); +	PRINTB("  document path: %s", this->document_path); +	if (mod) { +		const Module *m = dynamic_cast<const Module*>(mod); +		if (m) { +			PRINT("  module args:"); +			BOOST_FOREACH(const Assignment &arg, m->definition_arguments) { +				PRINTB("    %s = %s", arg.first % variables[arg.first]); +			} +		} +	} +	typedef std::pair<std::string, Value> ValueMapType; +	PRINT("  vars:"); +  BOOST_FOREACH(const ValueMapType &v, constants) { +	  PRINTB("    %s = %s", v.first % v.second); +	}		 +  BOOST_FOREACH(const ValueMapType &v, variables) { +	  PRINTB("    %s = %s", v.first % v.second); +	}		 +  BOOST_FOREACH(const ValueMapType &v, config_variables) { +	  PRINTB("    %s = %s", v.first % v.second); +	}		 + +} +#endif diff --git a/src/modcontext.h b/src/modcontext.h new file mode 100644 index 0000000..5fce88f --- /dev/null +++ b/src/modcontext.h @@ -0,0 +1,40 @@ +#ifndef FILECONTEXT_H_ +#define FILECONTEXT_H_ + +#include "context.h" +#include <boost/unordered_map.hpp> + +/*! +	This holds the context for a Module definition; keeps track of +	global variables, submodules and functions defined inside a module. + +	NB! every .scad file defines an implicit unnamed module holding the contents of the file. +*/ +class ModuleContext : public Context +{ +public: +	ModuleContext(const class Module *module = NULL, const Context *parent = NULL, const EvalContext *evalctx = NULL); +	virtual ~ModuleContext(); + +	void setModule(const Module &module, const EvalContext *evalctx = NULL); +	void registerBuiltin(); + +	virtual Value evaluate_function(const std::string &name, const EvalContext *evalctx) const; +	virtual AbstractNode *evaluate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const; + +	const boost::unordered_map<std::string, class AbstractFunction*> *functions_p; +	const boost::unordered_map<std::string, class AbstractModule*> *modules_p; +	typedef boost::unordered_map<std::string, class Module*> ModuleContainer; +	const ModuleContainer *usedlibs_p; + +  // FIXME: Points to the eval context for the call to this module. Not sure where it belongs +	const class EvalContext *evalctx; + +#ifdef DEBUG +	virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst); +#endif + +	mutable boost::unordered_map<std::string, int> recursioncount; +}; + +#endif diff --git a/src/module.cc b/src/module.cc index 322085b..7d83975 100644 --- a/src/module.cc +++ b/src/module.cc @@ -27,7 +27,8 @@  #include "module.h"  #include "ModuleCache.h"  #include "node.h" -#include "context.h" +#include "modcontext.h" +#include "evalcontext.h"  #include "expression.h"  #include "function.h"  #include "printutils.h" @@ -43,11 +44,11 @@ AbstractModule::~AbstractModule()  {  } -AbstractNode *AbstractModule::evaluate(const Context*, const ModuleInstantiation *inst) const +AbstractNode *AbstractModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	AbstractNode *node = new AbstractNode(inst); -	node->children = inst->evaluateChildren(); +	node->children = inst->evaluateChildren(evalctx);  	return node;  } @@ -61,8 +62,8 @@ std::string AbstractModule::dump(const std::string &indent, const std::string &n  ModuleInstantiation::~ModuleInstantiation()  { -	BOOST_FOREACH (Expression *v, argexpr) delete v; -	BOOST_FOREACH (ModuleInstantiation *v, children) delete v; +	BOOST_FOREACH(const Assignment &arg, this->arguments) delete arg.second; +	BOOST_FOREACH(ModuleInstantiation *v, children) delete v;  }  IfElseModuleInstantiation::~IfElseModuleInstantiation() @@ -88,10 +89,11 @@ std::string ModuleInstantiation::dump(const std::string &indent) const  	std::stringstream dump;  	dump << indent;  	dump << modname + "("; -	for (size_t i=0; i < argnames.size(); i++) { +	for (size_t i=0; i < this->arguments.size(); i++) { +		const Assignment &arg = this->arguments[i];  		if (i > 0) dump << ", "; -		if (!argnames[i].empty()) dump << argnames[i] << " = "; -		dump << *argexpr[i]; +		if (!arg.first.empty()) dump << arg.first << " = "; +		dump << *arg.second;  	}  	if (children.size() == 0) {  		dump << ");\n"; @@ -108,43 +110,40 @@ std::string ModuleInstantiation::dump(const std::string &indent) const  	return dump.str();  } -AbstractNode *ModuleInstantiation::evaluate(const Context *ctx) const +AbstractNode *ModuleInstantiation::evaluate_instance(const Context *ctx) const  { -	AbstractNode *node = NULL; -	if (this->ctx) { -		PRINTB("WARNING: Ignoring recursive module instantiation of '%s'.", modname); -	} else { -		// FIXME: Casting away const.. -		ModuleInstantiation *that = (ModuleInstantiation*)this; -		that->argvalues.clear(); -		BOOST_FOREACH (Expression *expr, that->argexpr) { -			that->argvalues.push_back(expr->evaluate(ctx)); -		} -		that->ctx = ctx; -		node = ctx->evaluate_module(*this); -		that->ctx = NULL; -		that->argvalues.clear(); +	EvalContext c(ctx); +	BOOST_FOREACH(const Assignment &arg, this->arguments) { +		c.eval_arguments.push_back(std::make_pair(arg.first, +																							arg.second ?  +																							arg.second->evaluate(ctx) :  +																							Value()));  	} +	c.children = this->children; + +#if 0 && DEBUG +	PRINT("New eval ctx:"); +	c.dump(NULL, this); +#endif +	AbstractNode *node = ctx->evaluate_module(*this, &c); // Passes c as evalctx  	return node;  } -std::vector<AbstractNode*> ModuleInstantiation::evaluateChildren(const Context *ctx) const +std::vector<AbstractNode*> ModuleInstantiation::evaluateChildren(const Context *evalctx) const  { -	if (!ctx) ctx = this->ctx;  	std::vector<AbstractNode*> childnodes;  	BOOST_FOREACH (ModuleInstantiation *modinst, this->children) { -		AbstractNode *node = modinst->evaluate(ctx); +		AbstractNode *node = modinst->evaluate_instance(evalctx);  		if (node) childnodes.push_back(node);  	}  	return childnodes;  } -std::vector<AbstractNode*> IfElseModuleInstantiation::evaluateElseChildren(const Context *ctx) const +std::vector<AbstractNode*> IfElseModuleInstantiation::evaluateElseChildren(const Context *evalctx) const  { -	if (!ctx) ctx = this->ctx;  	std::vector<AbstractNode*> childnodes;  	BOOST_FOREACH (ModuleInstantiation *modinst, this->else_children) { -		AbstractNode *node = modinst->evaluate(ctx); +		AbstractNode *node = modinst->evaluate_instance(evalctx);  		if (node != NULL) childnodes.push_back(node);  	}  	return childnodes; @@ -152,35 +151,24 @@ std::vector<AbstractNode*> IfElseModuleInstantiation::evaluateElseChildren(const  Module::~Module()  { -	BOOST_FOREACH (const AssignmentContainer::value_type &v, assignments) delete v.second; +	BOOST_FOREACH (const Assignment &v, assignments) delete v.second;  	BOOST_FOREACH (FunctionContainer::value_type &f, functions) delete f.second;  	BOOST_FOREACH (AbstractModuleContainer::value_type &m, modules) delete m.second;  	BOOST_FOREACH (ModuleInstantiation *v, children) delete v;  } -AbstractNode *Module::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *Module::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  { -	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); - -	c.inst_p = inst; +	ModuleContext c(this, ctx, evalctx); +	// FIXME: Set document path to the path of the module  	c.set_variable("$children", Value(double(inst->children.size()))); - -	c.functions_p = &functions; -	c.modules_p = &modules; -	 -	if (!usedlibs.empty()) -		c.usedlibs_p = &usedlibs; -	else -		c.usedlibs_p = NULL; -	 -	BOOST_FOREACH(const std::string &var, assignments_var) { -		c.set_variable(var, assignments.at(var)->evaluate(&c)); -  } +#if 0 && DEBUG +	c.dump(this, inst); +#endif  	AbstractNode *node = new AbstractNode(inst);  	for (size_t i = 0; i < children.size(); i++) { -		AbstractNode *n = children[i]->evaluate(&c); +		AbstractNode *n = children[i]->evaluate_instance(&c);  		if (n != NULL)  			node->children.push_back(n);  	} @@ -194,10 +182,11 @@ std::string Module::dump(const std::string &indent, const std::string &name) con  	std::string tab;  	if (!name.empty()) {  		dump << indent << "module " << name << "("; -		for (size_t i=0; i < argnames.size(); i++) { +		for (size_t i=0; i < this->definition_arguments.size(); i++) { +			const Assignment &arg = this->definition_arguments[i];  			if (i > 0) dump << ", "; -			dump << argnames[i]; -			if (argexpr[i]) dump << " = " << *argexpr[i]; +			dump << arg.first; +			if (arg.second) dump << " = " << *arg.second;  		}  		dump << ") {\n";  		tab = "\t"; diff --git a/src/module.h b/src/module.h index 1f9e303..ace3c1b 100644 --- a/src/module.h +++ b/src/module.h @@ -6,18 +6,18 @@  #include <list>  #include <boost/unordered_map.hpp>  #include "value.h" +#include "typedefs.h"  class ModuleInstantiation  {  public:  	ModuleInstantiation(const std::string &name = "") -	: ctx(NULL),  -		tag_root(false), tag_highlight(false), tag_background(false), modname(name) { } +	: tag_root(false), tag_highlight(false), tag_background(false), modname(name) { }  	virtual ~ModuleInstantiation();  	std::string dump(const std::string &indent) const; -	class AbstractNode *evaluate(const class Context *ctx) const; -	std::vector<AbstractNode*> evaluateChildren(const Context *ctx = NULL) const; +	class AbstractNode *evaluate_instance(const class Context *ctx) const; +	std::vector<AbstractNode*> evaluateChildren(const Context *evalctx) const;  	void setPath(const std::string &path) { this->modpath = path; }  	const std::string &path() const { return this->modpath; } @@ -28,11 +28,8 @@ public:  	bool isHighlight() const { return this->tag_highlight; }  	bool isRoot() const { return this->tag_root; } -	std::vector<std::string> argnames; -	std::vector<Value> argvalues; -	std::vector<class Expression*> argexpr; +	AssignmentList arguments;  	std::vector<ModuleInstantiation*> children; -	const Context *ctx;  	bool tag_root;  	bool tag_highlight; @@ -48,7 +45,7 @@ class IfElseModuleInstantiation : public ModuleInstantiation {  public:  	IfElseModuleInstantiation() : ModuleInstantiation("if") { }  	virtual ~IfElseModuleInstantiation(); -	std::vector<AbstractNode*> evaluateElseChildren(const Context *ctx = NULL) const; +	std::vector<AbstractNode*> evaluateElseChildren(const Context *evalctx) const;  	std::vector<ModuleInstantiation*> else_children;  }; @@ -57,7 +54,7 @@ class AbstractModule  {  public:  	virtual ~AbstractModule(); -	virtual class AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual class AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const class EvalContext *evalctx = NULL) const;  	virtual std::string dump(const std::string &indent, const std::string &name) const;  }; @@ -67,7 +64,10 @@ public:  	Module() : is_handling_dependencies(false) { }  	virtual ~Module(); -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	void setModulePath(const std::string &path) { this->path = path; } +	const std::string &modulePath() const { return this->path; } + +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  	virtual std::string dump(const std::string &indent, const std::string &name) const;  	void addChild(ModuleInstantiation *ch) { this->children.push_back(ch); } @@ -81,8 +81,8 @@ public:  	bool handleDependencies();  	std::list<std::string> assignments_var; -	typedef boost::unordered_map<std::string, Expression*> AssignmentContainer; -	AssignmentContainer assignments; +	typedef boost::unordered_map<std::string, Expression*> AssignmentMap; +	AssignmentMap assignments;  	typedef boost::unordered_map<std::string, class AbstractFunction*> FunctionContainer;  	FunctionContainer functions; @@ -91,12 +91,12 @@ public:  	std::vector<ModuleInstantiation*> children; -	std::vector<std::string> argnames; -	std::vector<Expression*> argexpr; +	std::vector<Assignment> definition_arguments;  protected:  private: +	std::string path;  };  #endif diff --git a/src/openscad.cc b/src/openscad.cc index 878c207..3b960f3 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -28,7 +28,7 @@  #include "MainWindow.h"  #include "node.h"  #include "module.h" -#include "context.h" +#include "modcontext.h"  #include "value.h"  #include "export.h"  #include "builtin.h" @@ -327,11 +327,8 @@ int main(int argc, char **argv)  		if (!filename) help(argv[0]); -		Context root_ctx; -		register_builtin(root_ctx); -  		Module *root_module; -		ModuleInstantiation root_inst; +		ModuleInstantiation root_inst("group");  		AbstractNode *root_node;  		AbstractNode *absolute_root_node;  		CGAL_Nef_polyhedron root_N; @@ -351,12 +348,18 @@ int main(int argc, char **argv)  		if (!root_module) exit(1);  		root_module->handleDependencies(); +		ModuleContext root_ctx; +		root_ctx.registerBuiltin(); +		PRINT("Root Context:"); +#if 0 && DEBUG +		root_ctx.dump(NULL, NULL); +#endif  		fs::path fpath = boosty::absolute(fs::path(filename));  		fs::path fparent = fpath.parent_path();  		fs::current_path(fparent);  		AbstractNode::resetIndexCounter(); -		absolute_root_node = root_module->evaluate(&root_ctx, &root_inst); +		absolute_root_node = root_module->evaluate(&root_ctx, &root_inst, NULL);  		// Do we have an explicit root node (! modifier)?  		if (!(root_node = find_root_tag(absolute_root_node))) diff --git a/src/parser.y b/src/parser.y index 70aebba..fd6b164 100644 --- a/src/parser.y +++ b/src/parser.y @@ -34,6 +34,7 @@  #include <unistd.h>  #endif +#include "typedefs.h"  #include "module.h"  #include "expression.h"  #include "value.h" @@ -43,50 +44,39 @@  #include <boost/foreach.hpp>  #include <boost/filesystem.hpp> -namespace fs = boost::filesystem; +  namespace fs = boost::filesystem;  #include "boosty.h" -int parser_error_pos = -1; +  int parser_error_pos = -1; -int parserlex(void); -void yyerror(char const *s); +  int parserlex(void); +  void yyerror(char const *s); -int lexerget_lineno(void); -int lexerlex_destroy(void); -int lexerlex(void); +  int lexerget_lineno(void); +  int lexerlex_destroy(void); +  int lexerlex(void); -std::vector<Module*> module_stack; -Module *currmodule; +  std::vector<Module*> module_stack; +  Module *currmodule; -extern void lexerdestroy(); -extern FILE *lexerin; -extern const char *parser_input_buffer; -const char *parser_input_buffer; -std::string parser_source_path; +  extern void lexerdestroy(); +  extern FILE *lexerin; +  extern const char *parser_input_buffer; +  const char *parser_input_buffer; +  std::string parser_source_path; -class ArgContainer { -public:  -	std::string argname; -	Expression *argexpr; -}; -class ArgsContainer { -public: -	std::vector<std::string> argnames; -	std::vector<Expression*> argexpr; -}; - -%} +  %}  %union { -	char *text; -	double number; -	class Value *value; -	class Expression *expr; -	class ModuleInstantiation *inst; -	std::vector<ModuleInstantiation*> *instvec; -	class IfElseModuleInstantiation *ifelse; -	class ArgContainer *arg; -	class ArgsContainer *args; +  char *text; +  double number; +  class Value *value; +  class Expression *expr; +  class ModuleInstantiation *inst; +  std::vector<ModuleInstantiation*> *instvec; +  class IfElseModuleInstantiation *ifelse; +  Assignment *arg; +  AssignmentList *args;  }  %token TOK_MODULE @@ -139,427 +129,412 @@ public:  %%  input:  -	/* empty */ | -	TOK_USE { currmodule->usedlibs[$1] = NULL; } input | -	statement input ; +/* empty */ | +TOK_USE { currmodule->usedlibs[$1] = NULL; } input | +statement input ;  inner_input:  -	/* empty */ | -	statement inner_input ; +/* empty */ | +statement inner_input ;  statement: -	';' | -	'{' inner_input '}' | -	module_instantiation { -		if ($1) { -			currmodule->addChild($1); -		} else { -			delete $1; -		} -	} | -	TOK_ID '=' expr ';' { -          std::list<std::string>::iterator found = std::find(currmodule->assignments_var.begin(), currmodule->assignments_var.end(),$1); -          if (found != currmodule->assignments_var.end()) currmodule->assignments_var.erase(found); -          currmodule->assignments_var.push_back($1); -          currmodule->assignments[$1] = $3; -	} | -	TOK_MODULE TOK_ID '(' arguments_decl optional_commas ')' { -		Module *p = currmodule; -		module_stack.push_back(currmodule); -		currmodule = new Module(); -		p->modules[$2] = currmodule; -		currmodule->argnames = $4->argnames; -		currmodule->argexpr = $4->argexpr; -		free($2); -		delete $4; -	} statement { -		currmodule = module_stack.back(); -		module_stack.pop_back(); -	} | -	TOK_FUNCTION TOK_ID '(' arguments_decl optional_commas ')' '=' expr { -		Function *func = new Function(); -		func->argnames = $4->argnames; -		func->argexpr = $4->argexpr; -		func->expr = $8; -		currmodule->functions[$2] = func; -		free($2); -		delete $4; -	} ';' ; +';' | +'{' inner_input '}' | +module_instantiation { +  if ($1) { +    currmodule->addChild($1); +  } else { +    delete $1; +  } +} | +TOK_ID '=' expr ';' { +  std::list<std::string>::iterator found = std::find(currmodule->assignments_var.begin(), currmodule->assignments_var.end(),$1); +  if (found != currmodule->assignments_var.end()) currmodule->assignments_var.erase(found); +  currmodule->assignments_var.push_back($1); +  currmodule->assignments[$1] = $3; +} | +TOK_MODULE TOK_ID '(' arguments_decl optional_commas ')' { +  Module *p = currmodule; +  module_stack.push_back(currmodule); +  currmodule = new Module(); +  p->modules[$2] = currmodule; +  currmodule->definition_arguments = *$4; +  free($2); +  delete $4; +} statement { +  currmodule = module_stack.back(); +  module_stack.pop_back(); +  } | +  TOK_FUNCTION TOK_ID '(' arguments_decl optional_commas ')' '=' expr { +    Function *func = new Function(); +    func->definition_arguments = *$4; +    func->expr = $8; +    currmodule->functions[$2] = func; +    free($2); +    delete $4; +  } ';' ;  /* Will return a dummy parent node with zero or more children */  children_instantiation: -	module_instantiation { -		$$ = new std::vector<ModuleInstantiation*>; -		if ($1) {  -			$$->push_back($1); -		} -	} | -	'{' module_instantiation_list '}' { -		$$ = $2; -	} ; +module_instantiation { +  $$ = new std::vector<ModuleInstantiation*>; +  if ($1) {  +    $$->push_back($1); +  } +} | +'{' module_instantiation_list '}' { +  $$ = $2; +} ;  if_statement: -	TOK_IF '(' expr ')' children_instantiation { -		$$ = new IfElseModuleInstantiation(); -		$$->argnames.push_back(""); -		$$->argexpr.push_back($3); -                $$->setPath(parser_source_path); - -		if ($$) { -                  $$->children = *$5; -		} else { -			for (size_t i = 0; i < $5->size(); i++) -                          delete (*$5)[i]; -		} -		delete $5; -	} ; +TOK_IF '(' expr ')' children_instantiation { +  $$ = new IfElseModuleInstantiation(); +  $$->arguments.push_back(Assignment("", $3)); +  $$->setPath(parser_source_path); + +  if ($$) { +    $$->children = *$5; +  } else { +    for (size_t i = 0; i < $5->size(); i++) +      delete (*$5)[i]; +  } +  delete $5; +} ;  ifelse_statement: -	if_statement { -		$$ = $1; -	} | -	if_statement TOK_ELSE children_instantiation { -		$$ = $1; -		if ($$) { -                  $$->else_children = *$3; -		} else { -			for (size_t i = 0; i < $3->size(); i++) -                          delete (*$3)[i]; -		} -		delete $3; -	} ; +if_statement { +  $$ = $1; +} | +if_statement TOK_ELSE children_instantiation { +  $$ = $1; +  if ($$) { +    $$->else_children = *$3; +  } else { +    for (size_t i = 0; i < $3->size(); i++) +      delete (*$3)[i]; +  } +  delete $3; +} ;  module_instantiation: -	'!' module_instantiation { -		$$ = $2; -		if ($$) $$->tag_root = true; -	} | -	'#' module_instantiation { -		$$ = $2; -		if ($$) $$->tag_highlight = true; -	} | -	'%' module_instantiation { -		$$ = $2; -		if ($$) $$->tag_background = true; -	} | -	'*' module_instantiation { -		delete $2; -		$$ = NULL; -	} | -	single_module_instantiation ';' { -		$$ = $1; -	} | -	single_module_instantiation children_instantiation { -		$$ = $1; -		if ($$) { -			$$->children = *$2; -		} else { -			for (size_t i = 0; i < $2->size(); i++) -                          delete (*$2)[i]; -		} -		delete $2; -	} | -	ifelse_statement { -		$$ = $1; -	} ; +'!' module_instantiation { +  $$ = $2; +  if ($$) $$->tag_root = true; +} | +'#' module_instantiation { +  $$ = $2; +  if ($$) $$->tag_highlight = true; +} | +'%' module_instantiation { +  $$ = $2; +  if ($$) $$->tag_background = true; +} | +'*' module_instantiation { +  delete $2; +  $$ = NULL; +} | +single_module_instantiation ';' { +  $$ = $1; +} | +single_module_instantiation children_instantiation { +  $$ = $1; +  if ($$) { +    $$->children = *$2; +  } else { +    for (size_t i = 0; i < $2->size(); i++) +      delete (*$2)[i]; +  } +  delete $2; +} | +ifelse_statement { +  $$ = $1; +} ;  module_instantiation_list: -	/* empty */ { -		$$ = new std::vector<ModuleInstantiation*>; -	} | -	module_instantiation_list module_instantiation { -		$$ = $1; -		if ($$) { -			if ($2) $$->push_back($2); -		} else { -			delete $2; -		} -	} ; +/* empty */ { +  $$ = new std::vector<ModuleInstantiation*>; +} | +module_instantiation_list module_instantiation { +  $$ = $1; +  if ($$) { +    if ($2) $$->push_back($2); +  } else { +    delete $2; +  } +} ;  single_module_instantiation: -	TOK_ID '(' arguments_call ')' { -		$$ = new ModuleInstantiation($1); -		$$->argnames = $3->argnames; -		$$->argexpr = $3->argexpr; -                $$->setPath(parser_source_path); -		free($1); -		delete $3; -	} +TOK_ID '(' arguments_call ')' { +  $$ = new ModuleInstantiation($1); +  $$->arguments = *$3; +  $$->setPath(parser_source_path); +  free($1); +  delete $3; +}  expr: -	TOK_TRUE { -          $$ = new Expression(Value(true)); -	} | -	TOK_FALSE { -          $$ = new Expression(Value(false)); -	} | -	TOK_UNDEF { -          $$ = new Expression(Value::undefined); -	} | -	TOK_ID { -		$$ = new Expression(); -		$$->type = "L"; -		$$->var_name = $1; -		free($1); -	} | -	expr '.' TOK_ID { -		$$ = new Expression(); -		$$->type = "N"; -		$$->children.push_back($1); -		$$->var_name = $3; -		free($3); -	} | -	TOK_STRING { -          $$ = new Expression(Value(std::string($1))); -          free($1); -	} | -	TOK_NUMBER { -          $$ = new Expression(Value($1)); -	} | -	'[' expr ':' expr ']' { -		Expression *e_one = new Expression(Value(1.0)); -		$$ = new Expression(); -		$$->type = "R"; -		$$->children.push_back($2); -		$$->children.push_back(e_one); -		$$->children.push_back($4); -	} | -	'[' expr ':' expr ':' expr ']' { -		$$ = new Expression(); -		$$->type = "R"; -		$$->children.push_back($2); -		$$->children.push_back($4); -		$$->children.push_back($6); -	} | -	'[' optional_commas ']' { -          $$ = new Expression(Value(Value::VectorType())); -	} | -	'[' vector_expr optional_commas ']' { -		$$ = $2; -	} | -	expr '*' expr { -		$$ = new Expression(); -		$$->type = "*"; -		$$->children.push_back($1); -		$$->children.push_back($3); -	} | -	expr '/' expr { -		$$ = new Expression(); -		$$->type = "/"; -		$$->children.push_back($1); -		$$->children.push_back($3); -	} | -	expr '%' expr { -		$$ = new Expression(); -		$$->type = "%"; -		$$->children.push_back($1); -		$$->children.push_back($3); -	} | -	expr '+' expr { -		$$ = new Expression(); -		$$->type = "+"; -		$$->children.push_back($1); -		$$->children.push_back($3); -	} | -	expr '-' expr { -		$$ = new Expression(); -		$$->type = "-"; -		$$->children.push_back($1); -		$$->children.push_back($3); -	} | -	expr '<' expr { -		$$ = new Expression(); -		$$->type = "<"; -		$$->children.push_back($1); -		$$->children.push_back($3); -	} | -	expr LE expr { -		$$ = new Expression(); -		$$->type = "<="; -		$$->children.push_back($1); -		$$->children.push_back($3); -	} | -	expr EQ expr { -		$$ = new Expression(); -		$$->type = "=="; -		$$->children.push_back($1); -		$$->children.push_back($3); -	} | -	expr NE expr { -		$$ = new Expression(); -		$$->type = "!="; -		$$->children.push_back($1); -		$$->children.push_back($3); -	} | -	expr GE expr { -		$$ = new Expression(); -		$$->type = ">="; -		$$->children.push_back($1); -		$$->children.push_back($3); -	} | -	expr '>' expr { -		$$ = new Expression(); -		$$->type = ">"; -		$$->children.push_back($1); -		$$->children.push_back($3); -	} | -	expr AND expr { -		$$ = new Expression(); -		$$->type = "&&"; -		$$->children.push_back($1); -		$$->children.push_back($3); -	} | -	expr OR expr { -		$$ = new Expression(); -		$$->type = "||"; -		$$->children.push_back($1); -		$$->children.push_back($3); -	} | -	'+' expr { -		$$ = $2; -	} | -	'-' expr { -		$$ = new Expression(); -		$$->type = "I"; -		$$->children.push_back($2); -	} | -	'!' expr { -		$$ = new Expression(); -		$$->type = "!"; -		$$->children.push_back($2); -	} | -	'(' expr ')' { -		$$ = $2; -	} | -	expr '?' expr ':' expr { -		$$ = new Expression(); -		$$->type = "?:"; -		$$->children.push_back($1); -		$$->children.push_back($3); -		$$->children.push_back($5); -	} | -	expr '[' expr ']' { -		$$ = new Expression(); -		$$->type = "[]"; -		$$->children.push_back($1); -		$$->children.push_back($3); -	} | -	TOK_ID '(' arguments_call ')' { -		$$ = new Expression(); -		$$->type = "F"; -		$$->call_funcname = $1; -		$$->call_argnames = $3->argnames; -		$$->children = $3->argexpr; -		free($1); -		delete $3; -	} ; +TOK_TRUE { +  $$ = new Expression(Value(true)); +} | +TOK_FALSE { +  $$ = new Expression(Value(false)); +} | +TOK_UNDEF { +  $$ = new Expression(Value::undefined); +} | +TOK_ID { +  $$ = new Expression(); +  $$->type = "L"; +  $$->var_name = $1; +  free($1); +} | +expr '.' TOK_ID { +  $$ = new Expression(); +  $$->type = "N"; +  $$->children.push_back($1); +  $$->var_name = $3; +  free($3); +} | +TOK_STRING { +  $$ = new Expression(Value(std::string($1))); +  free($1); +} | +TOK_NUMBER { +  $$ = new Expression(Value($1)); +} | +'[' expr ':' expr ']' { +  Expression *e_one = new Expression(Value(1.0)); +  $$ = new Expression(); +  $$->type = "R"; +  $$->children.push_back($2); +  $$->children.push_back(e_one); +  $$->children.push_back($4); +} | +'[' expr ':' expr ':' expr ']' { +  $$ = new Expression(); +  $$->type = "R"; +  $$->children.push_back($2); +  $$->children.push_back($4); +  $$->children.push_back($6); +} | +'[' optional_commas ']' { +  $$ = new Expression(Value(Value::VectorType())); +} | +'[' vector_expr optional_commas ']' { +  $$ = $2; +} | +expr '*' expr { +  $$ = new Expression(); +  $$->type = "*"; +  $$->children.push_back($1); +  $$->children.push_back($3); +} | +expr '/' expr { +  $$ = new Expression(); +  $$->type = "/"; +  $$->children.push_back($1); +  $$->children.push_back($3); +} | +expr '%' expr { +  $$ = new Expression(); +  $$->type = "%"; +  $$->children.push_back($1); +  $$->children.push_back($3); +} | +expr '+' expr { +  $$ = new Expression(); +  $$->type = "+"; +  $$->children.push_back($1); +  $$->children.push_back($3); +} | +expr '-' expr { +  $$ = new Expression(); +  $$->type = "-"; +  $$->children.push_back($1); +  $$->children.push_back($3); +} | +expr '<' expr { +  $$ = new Expression(); +  $$->type = "<"; +  $$->children.push_back($1); +  $$->children.push_back($3); +} | +expr LE expr { +  $$ = new Expression(); +  $$->type = "<="; +  $$->children.push_back($1); +  $$->children.push_back($3); +} | +expr EQ expr { +  $$ = new Expression(); +  $$->type = "=="; +  $$->children.push_back($1); +  $$->children.push_back($3); +} | +expr NE expr { +  $$ = new Expression(); +  $$->type = "!="; +  $$->children.push_back($1); +  $$->children.push_back($3); +} | +expr GE expr { +  $$ = new Expression(); +  $$->type = ">="; +  $$->children.push_back($1); +  $$->children.push_back($3); +} | +expr '>' expr { +  $$ = new Expression(); +  $$->type = ">"; +  $$->children.push_back($1); +  $$->children.push_back($3); +} | +expr AND expr { +  $$ = new Expression(); +  $$->type = "&&"; +  $$->children.push_back($1); +  $$->children.push_back($3); +} | +expr OR expr { +  $$ = new Expression(); +  $$->type = "||"; +  $$->children.push_back($1); +  $$->children.push_back($3); +} | +'+' expr { +  $$ = $2; +} | +'-' expr { +  $$ = new Expression(); +  $$->type = "I"; +  $$->children.push_back($2); +} | +'!' expr { +  $$ = new Expression(); +  $$->type = "!"; +  $$->children.push_back($2); +} | +'(' expr ')' { +  $$ = $2; +} | +expr '?' expr ':' expr { +  $$ = new Expression(); +  $$->type = "?:"; +  $$->children.push_back($1); +  $$->children.push_back($3); +  $$->children.push_back($5); +} | +expr '[' expr ']' { +  $$ = new Expression(); +  $$->type = "[]"; +  $$->children.push_back($1); +  $$->children.push_back($3); +} | +TOK_ID '(' arguments_call ')' { +  $$ = new Expression(); +  $$->type = "F"; +  $$->call_funcname = $1; +  $$->call_arguments = *$3; +  free($1); +  delete $3; +} ;  optional_commas: -	',' optional_commas | ; +',' optional_commas | ;  vector_expr: -	expr { -		$$ = new Expression(); -		$$->type = 'V'; -		$$->children.push_back($1); -	} | -	vector_expr ',' optional_commas expr { -		$$ = $1; -		$$->children.push_back($4); -	} ; +expr { +  $$ = new Expression(); +  $$->type = 'V'; +  $$->children.push_back($1); +} | +vector_expr ',' optional_commas expr { +  $$ = $1; +  $$->children.push_back($4); +} ;  arguments_decl: -	/* empty */ { -		$$ = new ArgsContainer(); -	} | -	argument_decl { -		$$ = new ArgsContainer(); -		$$->argnames.push_back($1->argname); -		$$->argexpr.push_back($1->argexpr); -		delete $1; -	} | -	arguments_decl ',' optional_commas argument_decl { -		$$ = $1; -		$$->argnames.push_back($4->argname); -		$$->argexpr.push_back($4->argexpr); -		delete $4; -	} ; +/* empty */ { +  $$ = new AssignmentList(); +} | +argument_decl { +  $$ = new AssignmentList(); +  $$->push_back(*$1); +  delete $1; +} | +arguments_decl ',' optional_commas argument_decl { +  $$ = $1; +  $$->push_back(*$4); +  delete $4; +} ;  argument_decl: -	TOK_ID { -		$$ = new ArgContainer(); -		$$->argname = $1; -		$$->argexpr = NULL; -		free($1); -	} | -	TOK_ID '=' expr { -		$$ = new ArgContainer(); -		$$->argname = $1; -		$$->argexpr = $3; -		free($1); -	} ; +TOK_ID { +  $$ = new Assignment($1, NULL); +  free($1); +} | +TOK_ID '=' expr { +  $$ = new Assignment($1, $3); +  free($1); +} ;  arguments_call: -	/* empty */ { -		$$ = new ArgsContainer(); -	} | -	argument_call { -		$$ = new ArgsContainer(); -		$$->argnames.push_back($1->argname); -		$$->argexpr.push_back($1->argexpr); -		delete $1; -	} | -	arguments_call ',' optional_commas argument_call { -		$$ = $1; -		$$->argnames.push_back($4->argname); -		$$->argexpr.push_back($4->argexpr); -		delete $4; -	} ; +/* empty */ { +  $$ = new AssignmentList(); +} | +argument_call { +  $$ = new AssignmentList(); +  $$->push_back(*$1); +  delete $1; +} | +arguments_call ',' optional_commas argument_call { +  $$ = $1; +  $$->push_back(*$4); +  delete $4; +} ;  argument_call: -	expr { -		$$ = new ArgContainer(); -		$$->argexpr = $1; -	} | -	TOK_ID '=' expr { -		$$ = new ArgContainer(); -		$$->argname = $1; -		$$->argexpr = $3; -		free($1); -	} ; +expr { +  $$ = new Assignment("", $1); +} | +TOK_ID '=' expr { +  $$ = new Assignment($1, $3); +  free($1); +} ;  %%  int parserlex(void)  { -	return lexerlex(); +  return lexerlex();  }  void yyerror (char const *s)  { -	// FIXME: We leak memory on parser errors... -	PRINTB("Parser error in line %d: %s\n", lexerget_lineno() % s); -	currmodule = NULL; +  // FIXME: We leak memory on parser errors... +  PRINTB("Parser error in line %d: %s\n", lexerget_lineno() % s); +  currmodule = NULL;  }  Module *parse(const char *text, const char *path, int debug)  { -	lexerin = NULL; -	parser_error_pos = -1; -	parser_input_buffer = text; -	parser_source_path = boosty::absolute(std::string(path)).string(); +  lexerin = NULL; +  parser_error_pos = -1; +  parser_input_buffer = text; +  parser_source_path = boosty::absolute(std::string(path)).string(); -	module_stack.clear(); -	Module *rootmodule = currmodule = new Module(); -        //        PRINTB_NOCACHE("New module: %s %p", "root" % rootmodule); +  module_stack.clear(); +  Module *rootmodule = currmodule = new Module(); +  rootmodule->setModulePath(path); +  //        PRINTB_NOCACHE("New module: %s %p", "root" % rootmodule); -	parserdebug = debug; -	int parserretval = parserparse(); -        lexerdestroy(); -	lexerlex_destroy(); +  parserdebug = debug; +  int parserretval = parserparse(); +  lexerdestroy(); +  lexerlex_destroy(); -	if (parserretval != 0) return NULL; +  if (parserretval != 0) return NULL; -	parser_error_pos = -1; -	return rootmodule; +  parser_error_pos = -1; +  return rootmodule;  } diff --git a/src/primitives.cc b/src/primitives.cc index e02df35..184b40c 100644 --- a/src/primitives.cc +++ b/src/primitives.cc @@ -27,12 +27,13 @@  #include "module.h"  #include "node.h"  #include "polyset.h" -#include "context.h" +#include "evalcontext.h"  #include "dxfdata.h"  #include "dxftess.h"  #include "builtin.h"  #include "printutils.h"  #include "visitor.h" +#include "context.h"  #include <sstream>  #include <assert.h>  #include <boost/assign/std/vector.hpp> @@ -55,7 +56,7 @@ class PrimitiveModule : public AbstractModule  public:  	primitive_type_e type;  	PrimitiveModule(primitive_type_e type) : type(type) { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  };  class PrimitiveNode : public AbstractPolyNode @@ -104,44 +105,43 @@ public:  	virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const;  }; -AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	PrimitiveNode *node = new PrimitiveNode(inst, this->type);  	node->center = false;  	node->x = node->y = node->z = node->h = node->r1 = node->r2 = 1; -	std::vector<std::string> argnames; -	std::vector<Expression*> argexpr; +	AssignmentList args;  	switch (this->type) {  	case CUBE: -		argnames += "size", "center"; +		args += Assignment("size", NULL), Assignment("center", NULL);  		break;  	case SPHERE: -		argnames += "r"; +		args += Assignment("r", NULL);  		break;  	case CYLINDER: -		argnames += "h", "r1", "r2", "center"; +		args += Assignment("h", NULL), Assignment("r1", NULL), Assignment("r2", NULL), Assignment("center", NULL);  		break;  	case POLYHEDRON: -		argnames += "points", "triangles", "convexity"; +		args += Assignment("points", NULL), Assignment("triangles", NULL), Assignment("convexity", NULL);  		break;  	case SQUARE: -		argnames += "size", "center"; +		args += Assignment("size", NULL), Assignment("center", NULL);  		break;  	case CIRCLE: -		argnames += "r"; +		args += Assignment("r", NULL);  		break;  	case POLYGON: -		argnames += "points", "paths", "convexity"; +		args += Assignment("points", NULL), Assignment("paths", NULL), Assignment("convexity", NULL);  		break;  	default:  		assert(false && "PrimitiveModule::evaluate(): Unknown node type");  	}  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	node->fn = c.lookup_variable("$fn").toDouble();  	node->fs = c.lookup_variable("$fs").toDouble(); diff --git a/src/printutils.cc b/src/printutils.cc index 698fffb..37092fa 100644 --- a/src/printutils.cc +++ b/src/printutils.cc @@ -69,5 +69,3 @@ std::string two_digit_exp_format( double x )  	s << x;  	return two_digit_exp_format( s.str() );  } - - diff --git a/src/printutils.h b/src/printutils.h index 439c884..18aadde 100644 --- a/src/printutils.h +++ b/src/printutils.h @@ -22,6 +22,9 @@ void PRINT(const std::string &msg);  void PRINT_NOCACHE(const std::string &msg);  #define PRINTB_NOCACHE(_fmt, _arg) do { PRINT_NOCACHE(str(boost::format(_fmt) % _arg)); } while (0) + +void PRINT_CONTEXT(const class Context *ctx, const class Module *mod, const class ModuleInstantiation *inst); +  std::string two_digit_exp_format( std::string doublestr );  std::string two_digit_exp_format( double x ); diff --git a/src/projection.cc b/src/projection.cc index 1fcf639..eeed411 100644 --- a/src/projection.cc +++ b/src/projection.cc @@ -26,7 +26,7 @@  #include "projectionnode.h"  #include "module.h" -#include "context.h" +#include "evalcontext.h"  #include "printutils.h"  #include "builtin.h"  #include "visitor.h" @@ -41,19 +41,18 @@ class ProjectionModule : public AbstractModule  {  public:  	ProjectionModule() { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  }; -AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	ProjectionNode *node = new ProjectionNode(inst); -	std::vector<std::string> argnames; -	argnames += "cut"; -	std::vector<Expression*> argexpr; +	AssignmentList args; +	args += Assignment("cut", NULL);  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	Value convexity = c.lookup_variable("convexity", true);  	Value cut = c.lookup_variable("cut", true); @@ -63,7 +62,7 @@ AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstant  	if (cut.type() == Value::BOOL)  		node->cut_mode = cut.toBool(); -	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); +	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);  	node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  	return node; diff --git a/src/render.cc b/src/render.cc index 81c3f7b..bb08c0c 100644 --- a/src/render.cc +++ b/src/render.cc @@ -26,7 +26,7 @@  #include "rendernode.h"  #include "module.h" -#include "context.h" +#include "evalcontext.h"  #include "builtin.h"  #include "PolySetEvaluator.h" @@ -38,25 +38,24 @@ class RenderModule : public AbstractModule  {  public:  	RenderModule() { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  }; -AbstractNode *RenderModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *RenderModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	RenderNode *node = new RenderNode(inst); -	std::vector<std::string> argnames; -	argnames += "convexity"; -	std::vector<Expression*> argexpr; +	AssignmentList args; +	args += Assignment("convexity", NULL);  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	Value v = c.lookup_variable("convexity");  	if (v.type() == Value::NUMBER)  		node->convexity = (int)v.toDouble(); -	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); +	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);  	node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  	return node; diff --git a/src/rotateextrude.cc b/src/rotateextrude.cc index c4d9342..b6edb8b 100644 --- a/src/rotateextrude.cc +++ b/src/rotateextrude.cc @@ -26,7 +26,7 @@  #include "rotateextrudenode.h"  #include "module.h" -#include "context.h" +#include "evalcontext.h"  #include "printutils.h"  #include "builtin.h"  #include "polyset.h" @@ -45,19 +45,18 @@ class RotateExtrudeModule : public AbstractModule  {  public:  	RotateExtrudeModule() { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  }; -AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	RotateExtrudeNode *node = new RotateExtrudeNode(inst); -	std::vector<std::string> argnames; -	argnames += "file", "layer", "origin", "scale"; -	std::vector<Expression*> argexpr; +	AssignmentList args; +	args += Assignment("file", NULL), Assignment("layer", NULL), Assignment("origin", NULL), Assignment("scale", NULL);  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	node->fn = c.lookup_variable("$fn").toDouble();  	node->fs = c.lookup_variable("$fs").toDouble(); @@ -86,7 +85,7 @@ AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInst  		node->scale = 1;  	if (node->filename.empty()) { -		std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); +		std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);  		node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  	} diff --git a/src/surface.cc b/src/surface.cc index ca5031e..d8fa422 100644 --- a/src/surface.cc +++ b/src/surface.cc @@ -27,7 +27,7 @@  #include "module.h"  #include "node.h"  #include "polyset.h" -#include "context.h" +#include "evalcontext.h"  #include "builtin.h"  #include "printutils.h"  #include "handle_dep.h" // handle_dep() @@ -50,7 +50,7 @@ class SurfaceModule : public AbstractModule  {  public:  	SurfaceModule() { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  };  class SurfaceNode : public AbstractPolyNode @@ -69,18 +69,17 @@ public:  	virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const;  }; -AbstractNode *SurfaceModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *SurfaceModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	SurfaceNode *node = new SurfaceNode(inst);  	node->center = false;  	node->convexity = 1; -	std::vector<std::string> argnames; -	argnames += "file", "center", "convexity"; -	std::vector<Expression*> argexpr; +	AssignmentList args; +	args += Assignment("file", NULL), Assignment("center", NULL), Assignment("convexity", NULL);  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	Value fileval = c.lookup_variable("file");  	node->filename = inst->getAbsolutePath(fileval.isUndefined() ? "" : fileval.toString()); diff --git a/src/transform.cc b/src/transform.cc index b01827f..cc026fb 100644 --- a/src/transform.cc +++ b/src/transform.cc @@ -26,7 +26,7 @@  #include "transformnode.h"  #include "module.h" -#include "context.h" +#include "evalcontext.h"  #include "polyset.h"  #include "builtin.h"  #include "value.h" @@ -50,40 +50,39 @@ class TransformModule : public AbstractModule  public:  	transform_type_e type;  	TransformModule(transform_type_e type) : type(type) { } -	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +	virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;  }; -AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	TransformNode *node = new TransformNode(inst);  	node->matrix = Transform3d::Identity(); -	std::vector<std::string> argnames; -	std::vector<Expression*> argexpr; +	AssignmentList args;  	switch (this->type) {  	case SCALE: -		argnames += "v"; +		args += Assignment("v", NULL);  		break;  	case ROTATE: -		argnames += "a", "v"; +		args += Assignment("a", NULL), Assignment("v", NULL);  		break;  	case MIRROR: -		argnames += "v"; +		args += Assignment("v", NULL);  		break;  	case TRANSLATE: -		argnames += "v"; +		args += Assignment("v", NULL);  		break;  	case MULTMATRIX: -		argnames += "m"; +		args += Assignment("m", NULL);  		break;  	default:  		assert(false);  	}  	Context c(ctx); -	c.args(argnames, argexpr, inst->argnames, inst->argvalues); +	c.setVariables(args, evalctx);  	if (this->type == SCALE)  	{ @@ -176,7 +175,7 @@ AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstanti  		}  	} -	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); +	std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx);  	node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end());  	return node; diff --git a/src/typedefs.h b/src/typedefs.h new file mode 100644 index 0000000..a6e9077 --- /dev/null +++ b/src/typedefs.h @@ -0,0 +1,10 @@ +#ifndef TYPEDEFS_H_ +#define TYPEDEFS_H_ + +#include <string> +#include <vector> + +typedef std::pair<std::string, class Expression*> Assignment; +typedef std::vector<Assignment> AssignmentList; + +#endif | 
