summaryrefslogtreecommitdiff
path: root/src/control.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/control.cc')
-rw-r--r--src/control.cc101
1 files changed, 89 insertions, 12 deletions
diff --git a/src/control.cc b/src/control.cc
index ec13650..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,6 +34,10 @@
#include <sstream>
#include "mathc99.h"
+
+#define foreach BOOST_FOREACH
+
+
class ControlModule : public AbstractModule
{
public: // types
@@ -56,6 +61,8 @@ public: // methods
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;
@@ -71,12 +78,8 @@ void ControlModule::for_eval(AbstractNode &node, const ModuleInstantiation &inst
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);
@@ -119,7 +122,38 @@ const EvalContext* ControlModule::getLastModuleCtx(const EvalContext *evalctx)
return NULL;
}
-AbstractNode *ControlModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const
+// 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;
@@ -162,14 +196,57 @@ AbstractNode *ControlModule::instantiate(const Context *ctx, const ModuleInstant
if (modulectx==NULL) {
return NULL;
}
- AbstractNode* node = new AbstractNode(inst);
// This will trigger if trying to invoke child from the root of any file
// assert(filectx->evalctx);
- for (int n = 0; n < (int)modulectx->numChildren(); ++n) {
- AbstractNode* childnode = modulectx->getChild(n)->evaluate(modulectx);
- node->children.push_back(childnode);
+ 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;
}
- 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;
+ }
+ 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 NULL;
}
if (type == INT_FOR)
contact: Jan Huwald // Impressum