diff options
| author | Marius Kintel <marius@kintel.net> | 2013-10-13 17:19:34 (GMT) | 
|---|---|---|
| committer | Marius Kintel <marius@kintel.net> | 2013-10-13 17:19:34 (GMT) | 
| commit | e77615be3027cfe365e3e52f3ed609dae9711028 (patch) | |
| tree | 21babea118b3bc59037e4e487a4c6bd6811b5412 /src | |
| parent | 0f22d6e9ad562e87ae484a82df56ddee30e87343 (diff) | |
| parent | 4401a136b9cbf01aa99cfdf5d9d67d62579dd853 (diff) | |
Merge branch 'children' of git://github.com/vicnet/openscad into vicnet-children
Conflicts:
	tests/CMakeLists.txt
Diffstat (limited to 'src')
| -rw-r--r-- | src/control.cc | 206 | ||||
| -rw-r--r-- | src/expr.cc | 3 | ||||
| -rw-r--r-- | src/highlighter.cc | 2 | ||||
| -rw-r--r-- | src/value.cc | 9 | ||||
| -rw-r--r-- | src/value.h | 17 | 
5 files changed, 183 insertions, 54 deletions
| diff --git a/src/control.cc b/src/control.cc index 50e5eae..10aadf0 100644 --- a/src/control.cc +++ b/src/control.cc @@ -24,6 +24,7 @@   *   */ +#include <boost/foreach.hpp>  #include "module.h"  #include "node.h"  #include "evalcontext.h" @@ -33,24 +34,42 @@  #include <sstream>  #include "mathc99.h" -enum control_type_e { -	CHILD, -	ECHO, -	ASSIGN, -	FOR, -	INT_FOR, -	IF -}; + +#define foreach BOOST_FOREACH +  class ControlModule : public AbstractModule  { -public: -	control_type_e type; -	ControlModule(control_type_e type) : type(type) { } +public: // types +	enum Type { +		CHILD, +		CHILDREN, +		ECHO, +		ASSIGN, +		FOR, +		INT_FOR, +		IF +    }; +public: // methods +	ControlModule(Type type) +		: type(type) +	{ } +  	virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; -}; -void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l,  +	static void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l,  +						 const Context *ctx, const EvalContext *evalctx); + +	static const EvalContext* getLastModuleCtx(const EvalContext *evalctx); +	 +	static AbstractNode* getChild(const Value& value, const EvalContext* modulectx); + +private: // data +	Type type; + +}; // class ControlModule + +void ControlModule::for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l,   							const Context *ctx, const EvalContext *evalctx)  {  	if (evalctx->numArgs() > l) { @@ -59,12 +78,8 @@ void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l,  		Context c(ctx);  		if (it_values.type() == Value::RANGE) {  			Value::RangeType range = it_values.toRange(); -			if (range.end < range.begin) { -				double t = range.begin; -				range.begin = range.end; -				range.end = t; -			} -			if (range.step > 0 && (range.begin-range.end)/range.step < 10000) { +			range.normalize(); +			if (range.nbsteps()<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, &c, evalctx); @@ -87,7 +102,58 @@ void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l,  	}  } -AbstractNode *ControlModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const +const EvalContext* ControlModule::getLastModuleCtx(const EvalContext *evalctx) +{ +	// 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 *modulectx = dynamic_cast<const ModuleContext*>(tmpc->parent); +		if (modulectx) { +			// This will trigger if trying to invoke child from the root of any file +			// assert(filectx->evalctx); +			if (modulectx->evalctx) { +				return modulectx->evalctx; +			} +			return NULL; +		} +		tmpc = tmpc->parent; +	} +	return NULL; +} + +// static +AbstractNode* ControlModule::getChild(const Value& value, const EvalContext* modulectx) +{ +	if (value.type()!=Value::NUMBER) { +		// Invalid parameter +		// (e.g. first child of difference is invalid) +		PRINTB("WARNING: Bad parameter type (%s) for children, only accept: empty, number, vector, range.", value.toString()); +		return NULL; +	} +	double v; +	if (!value.getDouble(v)) { +		PRINTB("WARNING: Bad parameter type (%s) for children, only accept: empty, number, vector, range.", value.toString()); +		return NULL; +	} +		 +	int n = trunc(v); +	if (n < 0) { +		PRINTB("WARNING: Negative children index (%d) not allowed", n); +		return NULL; // Disallow negative child indices +	} +	if (n>=(int)modulectx->numChildren()) { +		// How to deal with negative objects in this case? +		// (e.g. first child of difference is invalid) +		PRINTB("WARNING: Children index (%d) out of bounds (%d children)" +			, n % modulectx->numChildren()); +		return NULL; +	} +	// OK +	return modulectx->getChild(n)->evaluate(modulectx); +} + +AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleInstantiation *inst, const EvalContext *evalctx) const  {  	AbstractNode *node = NULL; @@ -107,29 +173,80 @@ AbstractNode *ControlModule::instantiate(const Context *ctx, const ModuleInstant  		// 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 < (int)filectx->evalctx->numChildren()) { -						node = filectx->evalctx->getChild(n)->evaluate(filectx->evalctx); -					} -					else { -						// How to deal with negative objects in this case? +		const EvalContext *modulectx = getLastModuleCtx(evalctx); +		if (modulectx==NULL) { +			return NULL; +		} +		// This will trigger if trying to invoke child from the root of any file +        if (n < (int)modulectx->numChildren()) { +			node = modulectx->getChild(n)->evaluate(modulectx); +		} +		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->numChildren()); -					} +			PRINTB("WARNING: Child index (%d) out of bounds (%d children)",  +				   n % modulectx->numChildren()); +		} +		return node; +	} + +	if (type == CHILDREN) +	{ +		const EvalContext *modulectx = getLastModuleCtx(evalctx); +		if (modulectx==NULL) { +			return NULL; +		} +		// This will trigger if trying to invoke child from the root of any file +		// assert(filectx->evalctx); +		if (evalctx->numArgs()<=0) { +			// no parameters => all children +			AbstractNode* node = new AbstractNode(inst); +			for (int n = 0; n < (int)modulectx->numChildren(); ++n) { +				AbstractNode* childnode = modulectx->getChild(n)->evaluate(modulectx); +				if (childnode==NULL) continue; // error +				node->children.push_back(childnode); +			} +			return node; +		} +		else if (evalctx->numArgs()>0) { +			// one (or more ignored) parameter +			const Value& value = evalctx->getArgValue(0); +			if (value.type() == Value::NUMBER) { +				return getChild(value,modulectx); +			} +			else if (value.type() == Value::VECTOR) { +				AbstractNode* node = new AbstractNode(inst); +				const Value::VectorType& vect = value.toVector(); +				foreach (const Value::VectorType::value_type& vectvalue, vect) { +					AbstractNode* childnode = getChild(vectvalue,modulectx); +					if (childnode==NULL) continue; // error +					node->children.push_back(childnode); +				} +				return node; +			} +			else if (value.type() == Value::RANGE) { +				AbstractNode* node = new AbstractNode(inst); +				Value::RangeType range = value.toRange(); +				range.normalize(); +				if (range.nbsteps()>=10000) { +					PRINTB("WARNING: Bad range parameter for children: too many elements (%d).", (int)((range.begin-range.end)/range.step)); +					return NULL; +				} +				for (double i = range.begin; i <= range.end; i += range.step) { +					AbstractNode* childnode = getChild(Value(i),modulectx); // with error cases +					if (childnode==NULL) continue; // error +					node->children.push_back(childnode);  				}  				return node;  			} -			tmpc = tmpc->parent; +			else { +				// Invalid parameter +				// (e.g. first child of difference is invalid) +				PRINTB("WARNING: Bad parameter type (%s) for children, only accept: empty, number, vector, range.", value.toString()); +				return NULL; +			}  		} -		return node; +		return NULL;  	}  	if (type == INT_FOR) @@ -183,10 +300,11 @@ AbstractNode *ControlModule::instantiate(const Context *ctx, const ModuleInstant  void register_builtin_control()  { -	Builtins::init("child", new ControlModule(CHILD)); -	Builtins::init("echo", new ControlModule(ECHO)); -	Builtins::init("assign", new ControlModule(ASSIGN)); -	Builtins::init("for", new ControlModule(FOR)); -	Builtins::init("intersection_for", new ControlModule(INT_FOR)); -	Builtins::init("if", new ControlModule(IF)); +	Builtins::init("child", new ControlModule(ControlModule::CHILD)); +	Builtins::init("children", new ControlModule(ControlModule::CHILDREN)); +	Builtins::init("echo", new ControlModule(ControlModule::ECHO)); +	Builtins::init("assign", new ControlModule(ControlModule::ASSIGN)); +	Builtins::init("for", new ControlModule(ControlModule::FOR)); +	Builtins::init("intersection_for", new ControlModule(ControlModule::INT_FOR)); +	Builtins::init("if", new ControlModule(ControlModule::IF));  } diff --git a/src/expr.cc b/src/expr.cc index 8500d13..594fccf 100644 --- a/src/expr.cc +++ b/src/expr.cc @@ -119,7 +119,8 @@ Value Expression::evaluate(const Context *context) const  		Value v2 = this->children[1]->evaluate(context);  		Value v3 = this->children[2]->evaluate(context);  		if (v1.type() == Value::NUMBER && v2.type() == Value::NUMBER && v3.type() == Value::NUMBER) { -			return Value(v1.toDouble(), v2.toDouble(), v3.toDouble()); +			Value::RangeType range(v1.toDouble(), v2.toDouble(), v3.toDouble()); +			return Value(range);  		}  		return Value();  	} diff --git a/src/highlighter.cc b/src/highlighter.cc index 4b4aa30..1da0e88 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -154,7 +154,7 @@ Highlighter::Highlighter(QTextDocument *parent)  	tokentypes["import"] << "include" << "use" << "import_stl" << "import" << "import_dxf" << "dxf_dim" << "dxf_cross" << "surface";  	typeformats["import"].setForeground(Qt::darkYellow); -	tokentypes["special"] << "$children" << "child" << "$fn" << "$fa" << "$fs" << "$t" << "$vpt" << "$vpr"; +	tokentypes["special"] << "$children" << "child" << "children" << "$fn" << "$fa" << "$fs" << "$t" << "$vpt" << "$vpr";  	typeformats["special"].setForeground(Qt::darkGreen);  	tokentypes["extrude"] << "linear_extrude" << "rotate_extrude"; diff --git a/src/value.cc b/src/value.cc index a281409..ac33a3b 100644 --- a/src/value.cc +++ b/src/value.cc @@ -117,11 +117,6 @@ Value::Value(const RangeType &v) : value(v)    //  std::cout << "creating range\n";  } -Value::Value(double begin, double step, double end) : value(RangeType(begin, step, end)) -{ -  //  std::cout << "creating range from numbers\n"; -} -  Value::ValueType Value::type() const  {    return static_cast<ValueType>(this->value.which()); @@ -590,7 +585,7 @@ public:    Value operator()(const std::string &str, const double &idx) const {      int i = int(idx);      Value v; -    if (i >= 0 && i < str.size()) { +    if ((i >= 0) && (i < (int)str.size())) {        v = Value(str[int(idx)]);        //      std::cout << "bracket_visitor: " <<  v << "\n";      } @@ -599,7 +594,7 @@ public:    Value operator()(const Value::VectorType &vec, const double &idx) const {      int i = int(idx); -    if (i >= 0 && i < vec.size()) return vec[int(idx)]; +    if ((i >= 0) && (i < (int)vec.size())) return vec[int(idx)];      return Value::undefined;    } diff --git a/src/value.h b/src/value.h index 24e1b45..388b721 100644 --- a/src/value.h +++ b/src/value.h @@ -3,6 +3,8 @@  #include <vector>  #include <string> +#include <algorithm> +#include <limits>  // Workaround for https://bugreports.qt-project.org/browse/QTBUG-22829  #ifndef Q_MOC_RUN @@ -39,6 +41,20 @@ public:          this->end == other.end;      } +    /// inverse begin/end if begin is upper than end +    void normalize() { +		if ((step>0) && (end < begin)) { +			std::swap(begin,end); +		} +	} +	/// return number of steps, max int value if step is null +	int nbsteps() const { +		if (step<=0) { +			return std::numeric_limits<int>::max(); +		} +		return (int)((begin-end)/step); +	} +      double begin;      double step;      double end; @@ -65,7 +81,6 @@ public:    Value(const char v);    Value(const VectorType &v);    Value(const RangeType &v); -  Value(double begin, double step, double end);    ~Value() {}    ValueType type() const; | 
