From 611d5ce2a7125e4d76dc95c619b10dbc2b544d7f Mon Sep 17 00:00:00 2001 From: Vicnet Date: Tue, 24 Sep 2013 07:06:44 +0200 Subject: add children primitive, and refactor control.cc a little diff --git a/contrib/scad-mode.el b/contrib/scad-mode.el index 68a47e6..070caaf 100644 --- a/contrib/scad-mode.el +++ b/contrib/scad-mode.el @@ -74,7 +74,7 @@ :group 'scad-font-lock) (defcustom scad-modules - '("child" "echo" "assign" "for" "intersection_for" "if" "else" ;;control.cc + '("child" "children" "echo" "assign" "for" "intersection_for" "if" "else" ;;control.cc "cube" "sphere" "cylinder" "polyhedron" "square" "circle" "polygon" ;;primitives.cc "scale" "rotate" "translate" "mirror" "multmatrix" ;;transform.cc "union" "difference" "intersection" ;;csgops.cc diff --git a/src/control.cc b/src/control.cc index 50e5eae..ec13650 100644 --- a/src/control.cc +++ b/src/control.cc @@ -33,24 +33,36 @@ #include #include "mathc99.h" -enum control_type_e { - CHILD, - ECHO, - ASSIGN, - FOR, - INT_FOR, - IF -}; - 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); + +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) { @@ -87,6 +99,26 @@ void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l, } } +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(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; +} + AbstractNode *ControlModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const { AbstractNode *node = NULL; @@ -107,27 +139,35 @@ 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(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()); - } - } - return node; - } - tmpc = tmpc->parent; + 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; + } + 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); } return node; } @@ -183,10 +223,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/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"; -- cgit v0.10.1 From 8f1081a27dedf336b1e03d9f69a995156a027646 Mon Sep 17 00:00:00 2001 From: Vicnet Date: Tue, 24 Sep 2013 07:06:44 +0200 Subject: add children primitive, and refactor control.cc a little diff --git a/contrib/scad-mode.el b/contrib/scad-mode.el index 68a47e6..070caaf 100644 --- a/contrib/scad-mode.el +++ b/contrib/scad-mode.el @@ -74,7 +74,7 @@ :group 'scad-font-lock) (defcustom scad-modules - '("child" "echo" "assign" "for" "intersection_for" "if" "else" ;;control.cc + '("child" "children" "echo" "assign" "for" "intersection_for" "if" "else" ;;control.cc "cube" "sphere" "cylinder" "polyhedron" "square" "circle" "polygon" ;;primitives.cc "scale" "rotate" "translate" "mirror" "multmatrix" ;;transform.cc "union" "difference" "intersection" ;;csgops.cc diff --git a/src/control.cc b/src/control.cc index 50e5eae..ec13650 100644 --- a/src/control.cc +++ b/src/control.cc @@ -33,24 +33,36 @@ #include #include "mathc99.h" -enum control_type_e { - CHILD, - ECHO, - ASSIGN, - FOR, - INT_FOR, - IF -}; - 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); + +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) { @@ -87,6 +99,26 @@ void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l, } } +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(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; +} + AbstractNode *ControlModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const { AbstractNode *node = NULL; @@ -107,27 +139,35 @@ 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(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()); - } - } - return node; - } - tmpc = tmpc->parent; + 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; + } + 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); } return node; } @@ -183,10 +223,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/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"; -- cgit v0.10.1 From 119bf37cb343ec9873698a76150bca77b4d8e0b4 Mon Sep 17 00:00:00 2001 From: Vicnet Date: Tue, 24 Sep 2013 07:06:44 +0200 Subject: add children primitive, and refactor control.cc a little diff --git a/contrib/scad-mode.el b/contrib/scad-mode.el index 68a47e6..070caaf 100644 --- a/contrib/scad-mode.el +++ b/contrib/scad-mode.el @@ -74,7 +74,7 @@ :group 'scad-font-lock) (defcustom scad-modules - '("child" "echo" "assign" "for" "intersection_for" "if" "else" ;;control.cc + '("child" "children" "echo" "assign" "for" "intersection_for" "if" "else" ;;control.cc "cube" "sphere" "cylinder" "polyhedron" "square" "circle" "polygon" ;;primitives.cc "scale" "rotate" "translate" "mirror" "multmatrix" ;;transform.cc "union" "difference" "intersection" ;;csgops.cc diff --git a/src/control.cc b/src/control.cc index 50e5eae..ec13650 100644 --- a/src/control.cc +++ b/src/control.cc @@ -33,24 +33,36 @@ #include #include "mathc99.h" -enum control_type_e { - CHILD, - ECHO, - ASSIGN, - FOR, - INT_FOR, - IF -}; - 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); + +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) { @@ -87,6 +99,26 @@ void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l, } } +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(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; +} + AbstractNode *ControlModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const { AbstractNode *node = NULL; @@ -107,27 +139,35 @@ 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(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()); - } - } - return node; - } - tmpc = tmpc->parent; + 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; + } + 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); } return node; } @@ -183,10 +223,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/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"; -- cgit v0.10.1 From ce27757712c7621cbd81676b6d399976412d7ca0 Mon Sep 17 00:00:00 2001 From: Vicnet Date: Mon, 7 Oct 2013 10:23:09 +0200 Subject: use explicit Value::RangeType for clarity 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/value.cc b/src/value.cc index a281409..414975d 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(this->value.which()); diff --git a/src/value.h b/src/value.h index 24e1b45..f9bd99b 100644 --- a/src/value.h +++ b/src/value.h @@ -65,7 +65,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; -- cgit v0.10.1 From 014f48c1e8a5daa600a89635d3998ee2feb08a84 Mon Sep 17 00:00:00 2001 From: Vicnet Date: Mon, 7 Oct 2013 11:18:16 +0200 Subject: allow one number parameter on children(): select this child only diff --git a/src/control.cc b/src/control.cc index ec13650..0887cc7 100644 --- a/src/control.cc +++ b/src/control.cc @@ -119,7 +119,7 @@ const EvalContext* ControlModule::getLastModuleCtx(const EvalContext *evalctx) return NULL; } -AbstractNode *ControlModule::instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const +AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleInstantiation *inst, const EvalContext *evalctx) const { AbstractNode *node = NULL; @@ -150,8 +150,7 @@ AbstractNode *ControlModule::instantiate(const Context *ctx, const ModuleInstant 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 % modulectx->numChildren()); + PRINTB("WARNING: Child index (%d) out of bounds (%d children)", n % modulectx->numChildren()); } return node; } @@ -162,14 +161,47 @@ 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); + 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) { + double v; + if (!value.getDouble(v)) { + PRINTB("WARNING: Bad parameter type (%s) for children, only accept: empty, number.", 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 modulectx->getChild(n)->evaluate(modulectx); + } + else { + // Invalid parameter + // (e.g. first child of difference is invalid) + PRINTB("WARNING: Bad parameter type (%s) for children, only accept: empty, number.", value.toString()); + return NULL; + } + } + return NULL; } if (type == INT_FOR) -- cgit v0.10.1 From 3dfb76a56d2cc38bda988eeb2cdf51ccbfb4df15 Mon Sep 17 00:00:00 2001 From: Vicnet Date: Mon, 7 Oct 2013 12:34:30 +0200 Subject: add vector parameter to children() diff --git a/src/control.cc b/src/control.cc index 0887cc7..7293963 100644 --- a/src/control.cc +++ b/src/control.cc @@ -24,6 +24,7 @@ * */ +#include #include "module.h" #include "node.h" #include "evalcontext.h" @@ -33,6 +34,10 @@ #include #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; @@ -119,6 +126,36 @@ const EvalContext* ControlModule::getLastModuleCtx(const EvalContext *evalctx) 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.", value.toString()); + return NULL; + } + double v; + if (!value.getDouble(v)) { + PRINTB("WARNING: Bad parameter type (%s) for children, only accept: empty, number.", 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()); + } + // OK + return modulectx->getChild(n)->evaluate(modulectx); +} + AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleInstantiation *inst, const EvalContext *evalctx) const { AbstractNode *node = NULL; @@ -176,23 +213,17 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns // one (or more ignored) parameter const Value& value = evalctx->getArgValue(0); if (value.type() == Value::NUMBER) { - double v; - if (!value.getDouble(v)) { - PRINTB("WARNING: Bad parameter type (%s) for children, only accept: empty, number.", 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 getChild(value,modulectx); + } + 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 modulectx->getChild(n)->evaluate(modulectx); + return node; } else { // Invalid parameter -- cgit v0.10.1 From 2452aa8e88a67f448040563eb890d624ce8c101c Mon Sep 17 00:00:00 2001 From: Vicnet Date: Mon, 7 Oct 2013 13:03:00 +0200 Subject: factorize Value::RangeType method diff --git a/src/value.h b/src/value.h index f9bd99b..4d8346f 100644 --- a/src/value.h +++ b/src/value.h @@ -3,6 +3,7 @@ #include #include +#include // Workaround for https://bugreports.qt-project.org/browse/QTBUG-22829 #ifndef Q_MOC_RUN @@ -39,6 +40,13 @@ public: this->end == other.end; } + /// inverse begin/end if begin is upper than end + void normalize() { + if (end < begin) { + std::swap(begin,end); + } + } + double begin; double step; double end; -- cgit v0.10.1 From e5484b1081c9a75a23b47491e0c6485c71bfdaea Mon Sep 17 00:00:00 2001 From: Vicnet Date: Mon, 7 Oct 2013 13:03:35 +0200 Subject: remove compliation warnings diff --git a/src/value.cc b/src/value.cc index 414975d..ac33a3b 100644 --- a/src/value.cc +++ b/src/value.cc @@ -585,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"; } @@ -594,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; } -- cgit v0.10.1 From 9bc73ac106a78398b744c2cd6c997055d8d2de9d Mon Sep 17 00:00:00 2001 From: Vicnet Date: Mon, 7 Oct 2013 13:04:28 +0200 Subject: add range on children() diff --git a/src/control.cc b/src/control.cc index 7293963..db12f71 100644 --- a/src/control.cc +++ b/src/control.cc @@ -78,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.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, &c, evalctx); @@ -132,12 +128,12 @@ AbstractNode* ControlModule::getChild(const Value& value, const EvalContext* mod 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.", value.toString()); + 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.", value.toString()); + PRINTB("WARNING: Bad parameter type (%s) for children, only accept: empty, number, vector, range.", value.toString()); return NULL; } @@ -205,6 +201,7 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns 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; @@ -215,7 +212,7 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns if (value.type() == Value::NUMBER) { return getChild(value,modulectx); } - if (value.type() == Value::VECTOR) { + 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) { @@ -225,10 +222,25 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns } return node; } + else if (value.type() == Value::RANGE) { + AbstractNode* node = new AbstractNode(inst); + Value::RangeType range = value.toRange(); + range.normalize(); + if ((range.step>0) && ((range.begin-range.end)/range.step>=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.", value.toString()); + PRINTB("WARNING: Bad parameter type (%s) for children, only accept: empty, number, vector, range.", value.toString()); return NULL; } } -- cgit v0.10.1 From eb27a0277f1eb08e947f5d4e4036f5fe13dfe086 Mon Sep 17 00:00:00 2001 From: Vicnet Date: Mon, 7 Oct 2013 16:02:43 +0200 Subject: factorize Value::RangeType calculation and correct error diff --git a/src/control.cc b/src/control.cc index db12f71..c50402f 100644 --- a/src/control.cc +++ b/src/control.cc @@ -79,7 +79,7 @@ void ControlModule::for_eval(AbstractNode &node, const ModuleInstantiation &inst if (it_values.type() == Value::RANGE) { Value::RangeType range = it_values.toRange(); range.normalize(); - if ((range.step > 0) && (range.begin-range.end)/range.step < 10000) { + 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); @@ -147,6 +147,7 @@ AbstractNode* ControlModule::getChild(const Value& value, const EvalContext* mod // (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); @@ -226,7 +227,7 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns AbstractNode* node = new AbstractNode(inst); Value::RangeType range = value.toRange(); range.normalize(); - if ((range.step>0) && ((range.begin-range.end)/range.step>=10000)) { + if (range.nbsteps()>=10000) { PRINTB("WARNING: Bad range parameter for children: too many elements (%d).", (int)((range.begin-range.end)/range.step)); return NULL; } diff --git a/src/value.h b/src/value.h index 4d8346f..388b721 100644 --- a/src/value.h +++ b/src/value.h @@ -4,6 +4,7 @@ #include #include #include +#include // Workaround for https://bugreports.qt-project.org/browse/QTBUG-22829 #ifndef Q_MOC_RUN @@ -42,10 +43,17 @@ public: /// inverse begin/end if begin is upper than end void normalize() { - if (end < begin) { + 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::max(); + } + return (int)((begin-end)/step); + } double begin; double step; -- cgit v0.10.1 From 4401a136b9cbf01aa99cfdf5d9d67d62579dd853 Mon Sep 17 00:00:00 2001 From: Vicnet Date: Tue, 8 Oct 2013 15:35:47 +0200 Subject: add children tests diff --git a/testdata/scad/misc/children-tests.scad b/testdata/scad/misc/children-tests.scad new file mode 100644 index 0000000..a9a3cf9 --- /dev/null +++ b/testdata/scad/misc/children-tests.scad @@ -0,0 +1,64 @@ + +module child1() { + echo("child1"); +} +module child2() { + echo("child2"); +} +module child3() { + echo("child3"); +} +module child4() { + echo("child4"); +} +module child5() { + echo("child5"); +} + +module test_children_empty() { + echo("Children empty: begin"); + children(); + echo("Children empty: end"); +} +test_children_empty() { + child1();child2();child3();child4();child5(); +} + +module test_children_scalar() { + echo("Children scalar: begin"); + children(0); // child1 + children(4); // child5 + children(2); // child3 + children(5); // out + children(-1); // out + echo("Children scalar: end"); +} +test_children_scalar() { + child1();child2();child3();child4();child5(); +} + +module test_children_vector() { + echo("Children vector: begin"); + children([4]); // child5 last + children([0,3,1]); // child1, child4, child2 + children([5,-1]); // out, out + echo("Children vector: end"); +} +test_children_vector() { + child1();child2();child3();child4();child5(); +} + +module test_children_range() { + echo("Children range: begin"); + children([0:4]); // all + children([1:2]); // child2, child3 + children([0:2:4]); // child1, child3, child5 + children([4:-1:0]); // out, out + echo("Children range: end"); +} +test_children_range() { + child1();child2();child3();child4();child5(); +} + +// to avoid no object error +cube(1.0); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ab94e64..d9aef2e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -772,7 +772,8 @@ list(APPEND ECHO_FILES ${FUNCTION_FILES} ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/value-reassignment-tests2.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/variable-scope-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/lookup-tests.scad - ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/expression-shortcircuit-tests.scad) + ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/expression-shortcircuit-tests.scad + ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/children-tests.scad) list(APPEND DUMPTEST_FILES ${FEATURES_FILES} ${EXAMPLE_FILES}) list(APPEND DUMPTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/escape-test.scad diff --git a/tests/regression/echotest/children-tests-expected.echo b/tests/regression/echotest/children-tests-expected.echo new file mode 100644 index 0000000..7b8278a --- /dev/null +++ b/tests/regression/echotest/children-tests-expected.echo @@ -0,0 +1,35 @@ +ECHO: "Children empty: begin" +ECHO: "child1" +ECHO: "child2" +ECHO: "child3" +ECHO: "child4" +ECHO: "child5" +ECHO: "Children empty: end" +ECHO: "Children scalar: begin" +ECHO: "child1" +ECHO: "child5" +ECHO: "child3" +WARNING: Children index (5) out of bounds (5 children) +WARNING: Negative children index (-1) not allowed +ECHO: "Children scalar: end" +ECHO: "Children vector: begin" +ECHO: "child5" +ECHO: "child1" +ECHO: "child4" +ECHO: "child2" +WARNING: Children index (5) out of bounds (5 children) +WARNING: Negative children index (-1) not allowed +ECHO: "Children vector: end" +ECHO: "Children range: begin" +ECHO: "child1" +ECHO: "child2" +ECHO: "child3" +ECHO: "child4" +ECHO: "child5" +ECHO: "child2" +ECHO: "child3" +ECHO: "child1" +ECHO: "child3" +ECHO: "child5" +WARNING: Bad range parameter for children: too many elements (-4). +ECHO: "Children range: end" -- cgit v0.10.1