diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/control.cc | 24 | ||||
| -rw-r--r-- | src/expr.cc | 17 | ||||
| -rw-r--r-- | src/parser.y | 2 | ||||
| -rw-r--r-- | src/value.cc | 102 | ||||
| -rw-r--r-- | src/value.h | 75 | 
5 files changed, 176 insertions, 44 deletions
| diff --git a/src/control.cc b/src/control.cc index 10aadf0..6b10a28 100644 --- a/src/control.cc +++ b/src/control.cc @@ -78,12 +78,14 @@ void ControlModule::for_eval(AbstractNode &node, const ModuleInstantiation &inst  		Context c(ctx);  		if (it_values.type() == Value::RANGE) {  			Value::RangeType range = it_values.toRange(); -			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); -				} +                        unsigned long steps = range.nbsteps(); +                        if (steps >= 10000) { +                                PRINTB("WARNING: Bad range parameter in for statement: too many elements (%lu).", steps); +                        } else { +                            for (Value::RangeType::iterator it = range.begin();it != range.end();it++) { +                                c.set_variable(it_name, Value(*it)); +                                for_eval(node, inst, l+1, &c, evalctx); +                            }  			}  		}  		else if (it_values.type() == Value::VECTOR) { @@ -227,13 +229,13 @@ AbstractNode *ControlModule::instantiate(const Context* /*ctx*/, const ModuleIns  			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)); +                                unsigned long steps = range.nbsteps(); +				if (steps >= 10000) { +					PRINTB("WARNING: Bad range parameter for children: too many elements (%lu).", steps);  					return NULL;  				} -				for (double i = range.begin; i <= range.end; i += range.step) { -					AbstractNode* childnode = getChild(Value(i),modulectx); // with error cases +                                for (Value::RangeType::iterator it = range.begin();it != range.end();it++) { +					AbstractNode* childnode = getChild(Value(*it),modulectx); // with error cases  					if (childnode==NULL) continue; // error  					node->children.push_back(childnode);  				} diff --git a/src/expr.cc b/src/expr.cc index 594fccf..51accf3 100644 --- a/src/expr.cc +++ b/src/expr.cc @@ -117,11 +117,18 @@ Value Expression::evaluate(const Context *context) const  	if (this->type == "R") {  		Value v1 = this->children[0]->evaluate(context);  		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) { -			Value::RangeType range(v1.toDouble(), v2.toDouble(), v3.toDouble()); -			return Value(range); -		} +                if (this->children.size() == 2) { +                        if (v1.type() == Value::NUMBER && v2.type() == Value::NUMBER) { +                                Value::RangeType range(v1.toDouble(), v2.toDouble()); +                                return Value(range); +                        } +                } else { +        		Value v3 = this->children[2]->evaluate(context); +                        if (v1.type() == Value::NUMBER && v2.type() == Value::NUMBER && v3.type() == Value::NUMBER) { +                                Value::RangeType range(v1.toDouble(), v2.toDouble(), v3.toDouble()); +                                return Value(range); +                        } +                }  		return Value();  	}  	if (this->type == "V") { diff --git a/src/parser.y b/src/parser.y index 5645104..6446e82 100644 --- a/src/parser.y +++ b/src/parser.y @@ -325,11 +325,9 @@ expr:              }          | '[' 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 ']' diff --git a/src/value.cc b/src/value.cc index ac33a3b..931c616 100644 --- a/src/value.cc +++ b/src/value.cc @@ -232,7 +232,7 @@ public:    }    std::string operator()(const Value::RangeType &v) const { -    return (boost::format("[%1% : %2% : %3%]") % v.begin % v.step % v.end).str(); +    return (boost::format("[%1% : %2% : %3%]") % v.begin_val % v.step_val % v.end_val).str();    }  }; @@ -600,9 +600,9 @@ public:    Value operator()(const Value::RangeType &range, const double &idx) const {      switch(int(idx)) { -    case 0: return Value(range.begin); -    case 1: return Value(range.step); -    case 2: return Value(range.end); +    case 0: return Value(range.begin_val); +    case 1: return Value(range.step_val); +    case 2: return Value(range.end_val);      }      return Value::undefined;    } @@ -617,3 +617,97 @@ Value Value::operator[](const Value &v)  {    return boost::apply_visitor(bracket_visitor(), this->value, v.value);  } + +void Value::RangeType::normalize() { +  if ((step_val>0) && (end_val < begin_val)) { +    std::swap(begin_val,end_val); +    PRINT("DEPRECATED: Using ranges of the form [begin:end] with begin value greater than the end value is deprecated."); +  } +} + +unsigned long Value::RangeType::nbsteps() const { +  if (begin_val == end_val) { +    return 0; +  } +   +  if (step_val == 0) {  +    return std::numeric_limits<unsigned long>::max(); +  } + +  double steps; +  if (step_val < 0) { +    if (begin_val < end_val) { +      return 0; +    } +    steps = (begin_val - end_val) / (-step_val); +  } else { +    if (begin_val > end_val) { +      return 0; +    } +    steps = (end_val - begin_val) / step_val; +  } +   +  return steps; +} + +Value::RangeType::iterator::iterator(Value::RangeType &range, type_t type) : range(range), val(range.begin_val) +{ +    this->type = type; +    update_type(); +} + +void Value::RangeType::iterator::update_type() +{ +    if (range.step_val == 0) { +        type = RANGE_TYPE_END; +    } else if (range.step_val < 0) { +        if (val < range.end_val) { +            type = RANGE_TYPE_END; +        } +    } else { +        if (val > range.end_val) { +            type = RANGE_TYPE_END; +        } +    } +} + +Value::RangeType::iterator::reference Value::RangeType::iterator::operator*() +{ +    return val; +} + +Value::RangeType::iterator::pointer Value::RangeType::iterator::operator->() +{ +    return &(operator*()); +} + +Value::RangeType::iterator::self_type Value::RangeType::iterator::operator++() +{ +    if (type < 0) { +        type = RANGE_TYPE_RUNNING; +    } +    val += range.step_val; +    update_type(); +    return *this; +} + +Value::RangeType::iterator::self_type Value::RangeType::iterator::operator++(int) +{ +    self_type tmp(*this); +    operator++(); +    return tmp; +} + +bool Value::RangeType::iterator::operator==(const self_type &other) const +{ +    if (type == RANGE_TYPE_RUNNING) { +        return (type == other.type) && (val == other.val) && (range == other.range); +    } else { +        return (type == other.type) && (range == other.range); +    } +} + +bool Value::RangeType::iterator::operator!=(const self_type &other) const +{ +    return !(*this == other); +} diff --git a/src/value.h b/src/value.h index 388b721..4671cdc 100644 --- a/src/value.h +++ b/src/value.h @@ -31,33 +31,64 @@ std::ostream &operator<<(std::ostream &stream, const Filename &filename);  class Value  {  public: -  struct RangeType { +  class RangeType { +  private: +    double begin_val; +    double step_val; +    double end_val; +  +    /// inverse begin/end if begin is upper than end +    void normalize(); + +  public: +    typedef enum { RANGE_TYPE_BEGIN, RANGE_TYPE_RUNNING, RANGE_TYPE_END } type_t; +     +    class iterator { +    public: +        typedef iterator self_type; +        typedef double value_type; +        typedef double& reference; +        typedef double* pointer; +        typedef std::forward_iterator_tag iterator_category; +        typedef double difference_type; +        iterator(RangeType &range, type_t type); +        self_type operator++(); +        self_type operator++(int junk); +        reference operator*(); +        pointer operator->(); +        bool operator==(const self_type& other) const; +        bool operator!=(const self_type& other) const; +    private: +      RangeType ⦥ +      double val; +      type_t type; +       +      void update_type(); +    }; +         +    RangeType(double begin, double end) +      : begin_val(begin), step_val(1.0), end_val(end) +    { +      normalize(); +    } +      RangeType(double begin, double step, double end) -      : begin(begin), step(step), end(end) {} +      : begin_val(begin), step_val(step), end_val(end) {}      bool operator==(const RangeType &other) const { -      return this->begin == other.begin && -        this->step == other.step && -        this->end == other.end; +      return this->begin_val == other.begin_val && +        this->step_val == other.step_val && +        this->end_val == other.end_val;      } -    /// 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; +    iterator begin() { return iterator(*this, RANGE_TYPE_BEGIN); } +    iterator end() { return iterator(*this, RANGE_TYPE_END); } + +    /// return number of steps, max int value if step is null +    unsigned long nbsteps() const; +     +    friend class tostring_visitor; +    friend class bracket_visitor;    };    typedef std::vector<Value> VectorType; | 
