PlaceholderParser:
1) Implemented access to coEnum values, they are returned as strings. 2) Fixed some possible memory leaks. 3) Fixed some possible union type punning issues.
This commit is contained in:
parent
9960c6e4ab
commit
1a5533d571
@ -301,7 +301,7 @@ template <class T>
|
||||
class ConfigOptionSingle : public ConfigOption {
|
||||
public:
|
||||
T value;
|
||||
explicit ConfigOptionSingle(T value) : value(value) {}
|
||||
explicit ConfigOptionSingle(T value) : value(std::move(value)) {}
|
||||
operator T() const { return this->value; }
|
||||
|
||||
void set(const ConfigOption *rhs) override
|
||||
@ -845,9 +845,9 @@ using ConfigOptionIntsNullable = ConfigOptionIntsTempl<true>;
|
||||
class ConfigOptionString : public ConfigOptionSingle<std::string>
|
||||
{
|
||||
public:
|
||||
ConfigOptionString() : ConfigOptionSingle<std::string>("") {}
|
||||
explicit ConfigOptionString(const std::string &value) : ConfigOptionSingle<std::string>(value) {}
|
||||
|
||||
ConfigOptionString() : ConfigOptionSingle<std::string>(std::string{}) {}
|
||||
explicit ConfigOptionString(std::string value) : ConfigOptionSingle<std::string>(std::move(value)) {}
|
||||
|
||||
static ConfigOptionType static_type() { return coString; }
|
||||
ConfigOptionType type() const override { return static_type(); }
|
||||
ConfigOption* clone() const override { return new ConfigOptionString(*this); }
|
||||
|
@ -185,75 +185,107 @@ namespace client
|
||||
template<typename Iterator>
|
||||
struct expr
|
||||
{
|
||||
expr() : type(TYPE_EMPTY) {}
|
||||
explicit expr(bool b) : type(TYPE_BOOL) { data.b = b; }
|
||||
explicit expr(bool b, const Iterator &it_begin, const Iterator &it_end) : type(TYPE_BOOL), it_range(it_begin, it_end) { data.b = b; }
|
||||
explicit expr(int i) : type(TYPE_INT) { data.i = i; }
|
||||
explicit expr(int i, const Iterator &it_begin, const Iterator &it_end) : type(TYPE_INT), it_range(it_begin, it_end) { data.i = i; }
|
||||
explicit expr(double d) : type(TYPE_DOUBLE) { data.d = d; }
|
||||
explicit expr(double d, const Iterator &it_begin, const Iterator &it_end) : type(TYPE_DOUBLE), it_range(it_begin, it_end) { data.d = d; }
|
||||
explicit expr(const char *s) : type(TYPE_STRING) { data.s = new std::string(s); }
|
||||
explicit expr(const std::string &s) : type(TYPE_STRING) { data.s = new std::string(s); }
|
||||
expr() {}
|
||||
explicit expr(bool b) : m_type(TYPE_BOOL) { m_data.b = b; }
|
||||
explicit expr(bool b, const Iterator &it_begin, const Iterator &it_end) : m_type(TYPE_BOOL), it_range(it_begin, it_end) { m_data.b = b; }
|
||||
explicit expr(int i) : m_type(TYPE_INT) { m_data.i = i; }
|
||||
explicit expr(int i, const Iterator &it_begin, const Iterator &it_end) : m_type(TYPE_INT), it_range(it_begin, it_end) { m_data.i = i; }
|
||||
explicit expr(double d) : m_type(TYPE_DOUBLE) { m_data.d = d; }
|
||||
explicit expr(double d, const Iterator &it_begin, const Iterator &it_end) : m_type(TYPE_DOUBLE), it_range(it_begin, it_end) { m_data.d = d; }
|
||||
explicit expr(const char *s) : m_type(TYPE_STRING) { m_data.s = new std::string(s); }
|
||||
explicit expr(const std::string &s) : m_type(TYPE_STRING) { m_data.s = new std::string(s); }
|
||||
explicit expr(const std::string &s, const Iterator &it_begin, const Iterator &it_end) :
|
||||
type(TYPE_STRING), it_range(it_begin, it_end) { data.s = new std::string(s); }
|
||||
expr(const expr &rhs) : type(rhs.type), it_range(rhs.it_range)
|
||||
{ if (rhs.type == TYPE_STRING) data.s = new std::string(*rhs.data.s); else data.set(rhs.data); }
|
||||
explicit expr(expr &&rhs) : type(rhs.type), it_range(rhs.it_range)
|
||||
{ data.set(rhs.data); rhs.type = TYPE_EMPTY; }
|
||||
explicit expr(expr &&rhs, const Iterator &it_begin, const Iterator &it_end) : type(rhs.type), it_range(it_begin, it_end)
|
||||
{ data.set(rhs.data); rhs.type = TYPE_EMPTY; }
|
||||
~expr() { this->reset(); }
|
||||
|
||||
expr &operator=(const expr &rhs)
|
||||
m_type(TYPE_STRING), it_range(it_begin, it_end) { m_data.s = new std::string(s); }
|
||||
expr(const expr &rhs) : m_type(rhs.type()), it_range(rhs.it_range)
|
||||
{ if (rhs.type() == TYPE_STRING) m_data.s = new std::string(*rhs.m_data.s); else m_data.set(rhs.m_data); }
|
||||
explicit expr(expr &&rhs) : expr(rhs, rhs.it_range.begin(), rhs.it_range.end()) {}
|
||||
explicit expr(expr &&rhs, const Iterator &it_begin, const Iterator &it_end) : m_type(rhs.type()), it_range{ it_begin, it_end }
|
||||
{
|
||||
m_data.set(rhs.m_data);
|
||||
rhs.m_type = TYPE_EMPTY;
|
||||
}
|
||||
expr &operator=(const expr &rhs)
|
||||
{
|
||||
this->type = rhs.type;
|
||||
this->it_range = rhs.it_range;
|
||||
if (rhs.type == TYPE_STRING)
|
||||
this->data.s = new std::string(*rhs.data.s);
|
||||
else
|
||||
this->data.set(rhs.data);
|
||||
return *this;
|
||||
if (rhs.type() == TYPE_STRING) {
|
||||
this->set_s(rhs.s());
|
||||
} else {
|
||||
m_type = rhs.type();
|
||||
m_data.set(rhs.m_data);
|
||||
}
|
||||
this->it_range = rhs.it_range;
|
||||
return *this;
|
||||
}
|
||||
|
||||
expr &operator=(expr &&rhs)
|
||||
{
|
||||
type = rhs.type;
|
||||
this->it_range = rhs.it_range;
|
||||
data.set(rhs.data);
|
||||
rhs.type = TYPE_EMPTY;
|
||||
if (this != &rhs) {
|
||||
this->reset();
|
||||
m_type = rhs.type();
|
||||
this->it_range = rhs.it_range;
|
||||
m_data.set(rhs.m_data);
|
||||
rhs.m_type = TYPE_EMPTY;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
if (this->type == TYPE_STRING)
|
||||
delete data.s;
|
||||
this->type = TYPE_EMPTY;
|
||||
if (this->type() == TYPE_STRING)
|
||||
delete m_data.s;
|
||||
m_type = TYPE_EMPTY;
|
||||
}
|
||||
|
||||
bool& b() { return data.b; }
|
||||
bool b() const { return data.b; }
|
||||
void set_b(bool v) { this->reset(); this->data.b = v; this->type = TYPE_BOOL; }
|
||||
int& i() { return data.i; }
|
||||
int i() const { return data.i; }
|
||||
void set_i(int v) { this->reset(); this->data.i = v; this->type = TYPE_INT; }
|
||||
int as_i() const { return (this->type == TYPE_INT) ? this->i() : int(this->d()); }
|
||||
int as_i_rounded() const { return (this->type == TYPE_INT) ? this->i() : int(std::round(this->d())); }
|
||||
double& d() { return data.d; }
|
||||
double d() const { return data.d; }
|
||||
void set_d(double v) { this->reset(); this->data.d = v; this->type = TYPE_DOUBLE; }
|
||||
double as_d() const { return (this->type == TYPE_DOUBLE) ? this->d() : double(this->i()); }
|
||||
std::string& s() { return *data.s; }
|
||||
const std::string& s() const { return *data.s; }
|
||||
void set_s(const std::string &s) { this->reset(); this->data.s = new std::string(s); this->type = TYPE_STRING; }
|
||||
void set_s(std::string &&s) { this->reset(); this->data.s = new std::string(std::move(s)); this->type = TYPE_STRING; }
|
||||
enum Type {
|
||||
TYPE_EMPTY = 0,
|
||||
TYPE_BOOL,
|
||||
TYPE_INT,
|
||||
TYPE_DOUBLE,
|
||||
TYPE_STRING,
|
||||
};
|
||||
Type type() const { return m_type; }
|
||||
|
||||
bool& b() { return m_data.b; }
|
||||
bool b() const { return m_data.b; }
|
||||
void set_b(bool v) { this->reset(); this->set_b_lite(v); }
|
||||
void set_b_lite(bool v) { assert(this->type() != TYPE_STRING); Data tmp; tmp.b = v; m_data.set(tmp); m_type = TYPE_BOOL; }
|
||||
int& i() { return m_data.i; }
|
||||
int i() const { return m_data.i; }
|
||||
void set_i(int v) { this->reset(); set_i_lite(v); }
|
||||
void set_i_lite(int v) { assert(this->type() != TYPE_STRING); Data tmp; tmp.i = v; m_data.set(tmp); m_type = TYPE_INT; }
|
||||
int as_i() const { return this->type() == TYPE_INT ? this->i() : int(this->d()); }
|
||||
int as_i_rounded() const { return this->type() == TYPE_INT ? this->i() : int(std::round(this->d())); }
|
||||
double& d() { return m_data.d; }
|
||||
double d() const { return m_data.d; }
|
||||
void set_d(double v) { this->reset(); this->set_d_lite(v); }
|
||||
void set_d_lite(double v) { assert(this->type() != TYPE_STRING); Data tmp; tmp.d = v; m_data.set(tmp); m_type = TYPE_DOUBLE; }
|
||||
double as_d() const { return this->type() == TYPE_DOUBLE ? this->d() : double(this->i()); }
|
||||
std::string& s() { return *m_data.s; }
|
||||
const std::string& s() const { return *m_data.s; }
|
||||
void set_s(const std::string &s) {
|
||||
if (this->type() == TYPE_STRING)
|
||||
*m_data.s = s;
|
||||
else
|
||||
this->set_s_take_ownership(new std::string(s));
|
||||
}
|
||||
void set_s(std::string &&s) {
|
||||
if (this->type() == TYPE_STRING)
|
||||
*m_data.s = std::move(s);
|
||||
else
|
||||
this->set_s_take_ownership(new std::string(std::move(s)));
|
||||
}
|
||||
void set_s(const char *s) {
|
||||
if (this->type() == TYPE_STRING)
|
||||
*m_data.s = s;
|
||||
else
|
||||
this->set_s_take_ownership(new std::string(s));
|
||||
}
|
||||
|
||||
std::string to_string() const
|
||||
{
|
||||
std::string out;
|
||||
switch (type) {
|
||||
case TYPE_BOOL: out = data.b ? "true" : "false"; break;
|
||||
case TYPE_INT: out = std::to_string(data.i); break;
|
||||
switch (this->type()) {
|
||||
case TYPE_BOOL: out = this->b() ? "true" : "false"; break;
|
||||
case TYPE_INT: out = std::to_string(this->i()); break;
|
||||
case TYPE_DOUBLE:
|
||||
#if 0
|
||||
// The default converter produces trailing zeros after the decimal point.
|
||||
@ -263,48 +295,24 @@ namespace client
|
||||
// It seems to be doing what the old boost::to_string() did.
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << data.d;
|
||||
ss << this->d();
|
||||
out = ss.str();
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case TYPE_STRING: out = *data.s; break;
|
||||
case TYPE_STRING: out = this->s(); break;
|
||||
default: break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
union Data {
|
||||
// Raw image of the other data members.
|
||||
// The C++ compiler will consider a possible aliasing of char* with any other union member,
|
||||
// therefore copying the raw data is safe.
|
||||
char raw[8];
|
||||
bool b;
|
||||
int i;
|
||||
double d;
|
||||
std::string *s;
|
||||
|
||||
// Copy the largest member variable through char*, which will alias with all other union members by default.
|
||||
void set(const Data &rhs) { memcpy(this->raw, rhs.raw, sizeof(rhs.raw)); }
|
||||
} data;
|
||||
|
||||
enum Type {
|
||||
TYPE_EMPTY = 0,
|
||||
TYPE_BOOL,
|
||||
TYPE_INT,
|
||||
TYPE_DOUBLE,
|
||||
TYPE_STRING,
|
||||
};
|
||||
|
||||
Type type;
|
||||
|
||||
// Range of input iterators covering this expression.
|
||||
// Used for throwing parse exceptions.
|
||||
boost::iterator_range<Iterator> it_range;
|
||||
|
||||
expr unary_minus(const Iterator start_pos) const
|
||||
{
|
||||
switch (this->type) {
|
||||
switch (this->type()) {
|
||||
case TYPE_INT :
|
||||
return expr<Iterator>(- this->i(), start_pos, this->it_range.end());
|
||||
case TYPE_DOUBLE:
|
||||
@ -319,7 +327,7 @@ namespace client
|
||||
|
||||
expr unary_integer(const Iterator start_pos) const
|
||||
{
|
||||
switch (this->type) {
|
||||
switch (this->type()) {
|
||||
case TYPE_INT:
|
||||
return expr<Iterator>(this->i(), start_pos, this->it_range.end());
|
||||
case TYPE_DOUBLE:
|
||||
@ -334,7 +342,7 @@ namespace client
|
||||
|
||||
expr round(const Iterator start_pos) const
|
||||
{
|
||||
switch (this->type) {
|
||||
switch (this->type()) {
|
||||
case TYPE_INT:
|
||||
return expr<Iterator>(this->i(), start_pos, this->it_range.end());
|
||||
case TYPE_DOUBLE:
|
||||
@ -349,7 +357,7 @@ namespace client
|
||||
|
||||
expr unary_not(const Iterator start_pos) const
|
||||
{
|
||||
switch (this->type) {
|
||||
switch (this->type()) {
|
||||
case TYPE_BOOL:
|
||||
return expr<Iterator>(! this->b(), start_pos, this->it_range.end());
|
||||
default:
|
||||
@ -362,23 +370,20 @@ namespace client
|
||||
|
||||
expr &operator+=(const expr &rhs)
|
||||
{
|
||||
if (this->type == TYPE_STRING) {
|
||||
if (this->type() == TYPE_STRING) {
|
||||
// Convert the right hand side to string and append.
|
||||
*this->data.s += rhs.to_string();
|
||||
} else if (rhs.type == TYPE_STRING) {
|
||||
*m_data.s += rhs.to_string();
|
||||
} else if (rhs.type() == TYPE_STRING) {
|
||||
// Conver the left hand side to string, append rhs.
|
||||
this->data.s = new std::string(this->to_string() + rhs.s());
|
||||
this->type = TYPE_STRING;
|
||||
this->set_s(this->to_string() + rhs.s());
|
||||
} else {
|
||||
const char *err_msg = "Cannot add non-numeric types.";
|
||||
this->throw_if_not_numeric(err_msg);
|
||||
rhs.throw_if_not_numeric(err_msg);
|
||||
if (this->type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) {
|
||||
double d = this->as_d() + rhs.as_d();
|
||||
this->data.d = d;
|
||||
this->type = TYPE_DOUBLE;
|
||||
} else
|
||||
this->data.i += rhs.i();
|
||||
if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE)
|
||||
this->set_d_lite(this->as_d() + rhs.as_d());
|
||||
else
|
||||
m_data.i += rhs.i();
|
||||
}
|
||||
this->it_range = boost::iterator_range<Iterator>(this->it_range.begin(), rhs.it_range.end());
|
||||
return *this;
|
||||
@ -389,12 +394,10 @@ namespace client
|
||||
const char *err_msg = "Cannot subtract non-numeric types.";
|
||||
this->throw_if_not_numeric(err_msg);
|
||||
rhs.throw_if_not_numeric(err_msg);
|
||||
if (this->type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) {
|
||||
double d = this->as_d() - rhs.as_d();
|
||||
this->data.d = d;
|
||||
this->type = TYPE_DOUBLE;
|
||||
} else
|
||||
this->data.i -= rhs.i();
|
||||
if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE)
|
||||
this->set_d_lite(this->as_d() - rhs.as_d());
|
||||
else
|
||||
m_data.i -= rhs.i();
|
||||
this->it_range = boost::iterator_range<Iterator>(this->it_range.begin(), rhs.it_range.end());
|
||||
return *this;
|
||||
}
|
||||
@ -404,12 +407,10 @@ namespace client
|
||||
const char *err_msg = "Cannot multiply with non-numeric type.";
|
||||
this->throw_if_not_numeric(err_msg);
|
||||
rhs.throw_if_not_numeric(err_msg);
|
||||
if (this->type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) {
|
||||
double d = this->as_d() * rhs.as_d();
|
||||
this->data.d = d;
|
||||
this->type = TYPE_DOUBLE;
|
||||
} else
|
||||
this->data.i *= rhs.i();
|
||||
if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE)
|
||||
this->set_d_lite(this->as_d() * rhs.as_d());
|
||||
else
|
||||
m_data.i *= rhs.i();
|
||||
this->it_range = boost::iterator_range<Iterator>(this->it_range.begin(), rhs.it_range.end());
|
||||
return *this;
|
||||
}
|
||||
@ -418,14 +419,12 @@ namespace client
|
||||
{
|
||||
this->throw_if_not_numeric("Cannot divide a non-numeric type.");
|
||||
rhs.throw_if_not_numeric("Cannot divide with a non-numeric type.");
|
||||
if ((rhs.type == TYPE_INT) ? (rhs.i() == 0) : (rhs.d() == 0.))
|
||||
if (rhs.type() == TYPE_INT ? (rhs.i() == 0) : (rhs.d() == 0.))
|
||||
rhs.throw_exception("Division by zero");
|
||||
if (this->type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) {
|
||||
double d = this->as_d() / rhs.as_d();
|
||||
this->data.d = d;
|
||||
this->type = TYPE_DOUBLE;
|
||||
} else
|
||||
this->data.i /= rhs.i();
|
||||
if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE)
|
||||
this->set_d_lite(this->as_d() / rhs.as_d());
|
||||
else
|
||||
m_data.i /= rhs.i();
|
||||
this->it_range = boost::iterator_range<Iterator>(this->it_range.begin(), rhs.it_range.end());
|
||||
return *this;
|
||||
}
|
||||
@ -434,14 +433,12 @@ namespace client
|
||||
{
|
||||
this->throw_if_not_numeric("Cannot divide a non-numeric type.");
|
||||
rhs.throw_if_not_numeric("Cannot divide with a non-numeric type.");
|
||||
if ((rhs.type == TYPE_INT) ? (rhs.i() == 0) : (rhs.d() == 0.))
|
||||
if (rhs.type() == TYPE_INT ? (rhs.i() == 0) : (rhs.d() == 0.))
|
||||
rhs.throw_exception("Division by zero");
|
||||
if (this->type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) {
|
||||
double d = std::fmod(this->as_d(), rhs.as_d());
|
||||
this->data.d = d;
|
||||
this->type = TYPE_DOUBLE;
|
||||
} else
|
||||
this->data.i %= rhs.i();
|
||||
if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE)
|
||||
this->set_d_lite(std::fmod(this->as_d(), rhs.as_d()));
|
||||
else
|
||||
m_data.i %= rhs.i();
|
||||
this->it_range = boost::iterator_range<Iterator>(this->it_range.begin(), rhs.it_range.end());
|
||||
return *this;
|
||||
}
|
||||
@ -453,14 +450,14 @@ namespace client
|
||||
|
||||
static void evaluate_boolean(expr &self, bool &out)
|
||||
{
|
||||
if (self.type != TYPE_BOOL)
|
||||
if (self.type() != TYPE_BOOL)
|
||||
self.throw_exception("Not a boolean expression");
|
||||
out = self.b();
|
||||
}
|
||||
|
||||
static void evaluate_boolean_to_string(expr &self, std::string &out)
|
||||
{
|
||||
if (self.type != TYPE_BOOL)
|
||||
if (self.type() != TYPE_BOOL)
|
||||
self.throw_exception("Not a boolean expression");
|
||||
out = self.b() ? "true" : "false";
|
||||
}
|
||||
@ -469,31 +466,31 @@ namespace client
|
||||
static void compare_op(expr &lhs, expr &rhs, char op, bool invert)
|
||||
{
|
||||
bool value = false;
|
||||
if ((lhs.type == TYPE_INT || lhs.type == TYPE_DOUBLE) &&
|
||||
(rhs.type == TYPE_INT || rhs.type == TYPE_DOUBLE)) {
|
||||
if ((lhs.type() == TYPE_INT || lhs.type() == TYPE_DOUBLE) &&
|
||||
(rhs.type() == TYPE_INT || rhs.type() == TYPE_DOUBLE)) {
|
||||
// Both types are numeric.
|
||||
switch (op) {
|
||||
case '=':
|
||||
value = (lhs.type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) ?
|
||||
value = (lhs.type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) ?
|
||||
(std::abs(lhs.as_d() - rhs.as_d()) < 1e-8) : (lhs.i() == rhs.i());
|
||||
break;
|
||||
case '<':
|
||||
value = (lhs.type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) ?
|
||||
value = (lhs.type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) ?
|
||||
(lhs.as_d() < rhs.as_d()) : (lhs.i() < rhs.i());
|
||||
break;
|
||||
case '>':
|
||||
default:
|
||||
value = (lhs.type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) ?
|
||||
value = (lhs.type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) ?
|
||||
(lhs.as_d() > rhs.as_d()) : (lhs.i() > rhs.i());
|
||||
break;
|
||||
}
|
||||
} else if (lhs.type == TYPE_BOOL && rhs.type == TYPE_BOOL) {
|
||||
} else if (lhs.type() == TYPE_BOOL && rhs.type() == TYPE_BOOL) {
|
||||
// Both type are bool.
|
||||
if (op != '=')
|
||||
boost::throw_exception(qi::expectation_failure<Iterator>(
|
||||
lhs.it_range.begin(), rhs.it_range.end(), spirit::info("*Cannot compare the types.")));
|
||||
value = lhs.b() == rhs.b();
|
||||
} else if (lhs.type == TYPE_STRING || rhs.type == TYPE_STRING) {
|
||||
} else if (lhs.type() == TYPE_STRING || rhs.type() == TYPE_STRING) {
|
||||
// One type is string, the other could be converted to string.
|
||||
value = (op == '=') ? (lhs.to_string() == rhs.to_string()) :
|
||||
(op == '<') ? (lhs.to_string() < rhs.to_string()) : (lhs.to_string() > rhs.to_string());
|
||||
@ -502,8 +499,7 @@ namespace client
|
||||
lhs.it_range.begin(), rhs.it_range.end(), spirit::info("*Cannot compare the types.")));
|
||||
}
|
||||
lhs.reset();
|
||||
lhs.type = TYPE_BOOL;
|
||||
lhs.data.b = invert ? ! value : value;
|
||||
lhs.set_b_lite(invert ? ! value : value);
|
||||
}
|
||||
// Compare operators, store the result into lhs.
|
||||
static void equal (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '=', false); }
|
||||
@ -528,15 +524,14 @@ namespace client
|
||||
{
|
||||
throw_if_not_numeric(param1);
|
||||
throw_if_not_numeric(param2);
|
||||
if (param1.type == TYPE_DOUBLE || param2.type == TYPE_DOUBLE) {
|
||||
if (param1.type() == TYPE_DOUBLE || param2.type() == TYPE_DOUBLE) {
|
||||
double d = 0.;
|
||||
switch (fun) {
|
||||
case FUNCTION_MIN: d = std::min(param1.as_d(), param2.as_d()); break;
|
||||
case FUNCTION_MAX: d = std::max(param1.as_d(), param2.as_d()); break;
|
||||
default: param1.throw_exception("Internal error: invalid function");
|
||||
}
|
||||
param1.data.d = d;
|
||||
param1.type = TYPE_DOUBLE;
|
||||
param1.set_d_lite(d);
|
||||
} else {
|
||||
int i = 0;
|
||||
switch (fun) {
|
||||
@ -544,8 +539,7 @@ namespace client
|
||||
case FUNCTION_MAX: i = std::max(param1.as_i(), param2.as_i()); break;
|
||||
default: param1.throw_exception("Internal error: invalid function");
|
||||
}
|
||||
param1.data.i = i;
|
||||
param1.type = TYPE_INT;
|
||||
param1.set_i_lite(i);
|
||||
}
|
||||
}
|
||||
// Store the result into param1.
|
||||
@ -557,13 +551,10 @@ namespace client
|
||||
{
|
||||
throw_if_not_numeric(param1);
|
||||
throw_if_not_numeric(param2);
|
||||
if (param1.type == TYPE_DOUBLE || param2.type == TYPE_DOUBLE) {
|
||||
param1.data.d = std::uniform_real_distribution<>(param1.as_d(), param2.as_d())(rng);
|
||||
param1.type = TYPE_DOUBLE;
|
||||
} else {
|
||||
param1.data.i = std::uniform_int_distribution<>(param1.as_i(), param2.as_i())(rng);
|
||||
param1.type = TYPE_INT;
|
||||
}
|
||||
if (param1.type() == TYPE_DOUBLE || param2.type() == TYPE_DOUBLE)
|
||||
param1.set_d_lite(std::uniform_real_distribution<>(param1.as_d(), param2.as_d())(rng));
|
||||
else
|
||||
param1.set_i_lite(std::uniform_int_distribution<>(param1.as_i(), param2.as_i())(rng));
|
||||
}
|
||||
|
||||
// Store the result into param1.
|
||||
@ -572,10 +563,10 @@ namespace client
|
||||
static void digits(expr ¶m1, expr ¶m2, expr ¶m3)
|
||||
{
|
||||
throw_if_not_numeric(param1);
|
||||
if (param2.type != TYPE_INT)
|
||||
if (param2.type() != TYPE_INT)
|
||||
param2.throw_exception("digits: second parameter must be integer");
|
||||
bool has_decimals = param3.type != TYPE_EMPTY;
|
||||
if (has_decimals && param3.type != TYPE_INT)
|
||||
bool has_decimals = param3.type() != TYPE_EMPTY;
|
||||
if (has_decimals && param3.type() != TYPE_INT)
|
||||
param3.throw_exception("digits: third parameter must be integer");
|
||||
|
||||
char buf[256];
|
||||
@ -593,7 +584,7 @@ namespace client
|
||||
static void regex_op(expr &lhs, boost::iterator_range<Iterator> &rhs, char op)
|
||||
{
|
||||
const std::string *subject = nullptr;
|
||||
if (lhs.type == TYPE_STRING) {
|
||||
if (lhs.type() == TYPE_STRING) {
|
||||
// One type is string, the other could be converted to string.
|
||||
subject = &lhs.s();
|
||||
} else {
|
||||
@ -604,9 +595,7 @@ namespace client
|
||||
bool result = SLIC3R_REGEX_NAMESPACE::regex_match(*subject, SLIC3R_REGEX_NAMESPACE::regex(pattern));
|
||||
if (op == '!')
|
||||
result = ! result;
|
||||
lhs.reset();
|
||||
lhs.type = TYPE_BOOL;
|
||||
lhs.data.b = result;
|
||||
lhs.set_b(result);
|
||||
} catch (SLIC3R_REGEX_NAMESPACE::regex_error &ex) {
|
||||
// Syntax error in the regular expression
|
||||
boost::throw_exception(qi::expectation_failure<Iterator>(
|
||||
@ -620,21 +609,20 @@ namespace client
|
||||
static void logical_op(expr &lhs, expr &rhs, char op)
|
||||
{
|
||||
bool value = false;
|
||||
if (lhs.type == TYPE_BOOL && rhs.type == TYPE_BOOL) {
|
||||
if (lhs.type() == TYPE_BOOL && rhs.type() == TYPE_BOOL) {
|
||||
value = (op == '|') ? (lhs.b() || rhs.b()) : (lhs.b() && rhs.b());
|
||||
} else {
|
||||
boost::throw_exception(qi::expectation_failure<Iterator>(
|
||||
lhs.it_range.begin(), rhs.it_range.end(), spirit::info("*Cannot apply logical operation to non-boolean operators.")));
|
||||
}
|
||||
lhs.type = TYPE_BOOL;
|
||||
lhs.data.b = value;
|
||||
lhs.set_b_lite(value);
|
||||
}
|
||||
static void logical_or (expr &lhs, expr &rhs) { logical_op(lhs, rhs, '|'); }
|
||||
static void logical_and(expr &lhs, expr &rhs) { logical_op(lhs, rhs, '&'); }
|
||||
|
||||
static void ternary_op(expr &lhs, expr &rhs1, expr &rhs2)
|
||||
{
|
||||
if (lhs.type != TYPE_BOOL)
|
||||
if (lhs.type() != TYPE_BOOL)
|
||||
lhs.throw_exception("Not a boolean expression");
|
||||
if (lhs.b())
|
||||
lhs = std::move(rhs1);
|
||||
@ -658,9 +646,25 @@ namespace client
|
||||
|
||||
void throw_if_not_numeric(const char *message) const
|
||||
{
|
||||
if (this->type != TYPE_INT && this->type != TYPE_DOUBLE)
|
||||
if (this->type() != TYPE_INT && this->type() != TYPE_DOUBLE)
|
||||
this->throw_exception(message);
|
||||
}
|
||||
|
||||
private:
|
||||
// This object will take ownership of the parameter string object "s".
|
||||
void set_s_take_ownership(std::string* s) { assert(this->type() != TYPE_STRING); Data tmp; tmp.s = s; m_data.set(tmp); m_type = TYPE_STRING; }
|
||||
|
||||
Type m_type = TYPE_EMPTY;
|
||||
|
||||
union Data {
|
||||
bool b;
|
||||
int i;
|
||||
double d;
|
||||
std::string *s;
|
||||
|
||||
// Copy the largest member variable through char*, which will alias with all other union members by default.
|
||||
void set(const Data &rhs) { memcpy(this, &rhs, sizeof(rhs)); }
|
||||
} m_data;
|
||||
};
|
||||
|
||||
template<typename ITERATOR>
|
||||
@ -668,7 +672,7 @@ namespace client
|
||||
{
|
||||
typedef expr<ITERATOR> Expr;
|
||||
os << std::string(expression.it_range.begin(), expression.it_range.end()) << " - ";
|
||||
switch (expression.type) {
|
||||
switch (expression.type()) {
|
||||
case Expr::TYPE_EMPTY: os << "empty"; break;
|
||||
case Expr::TYPE_BOOL: os << "bool (" << expression.b() << ")"; break;
|
||||
case Expr::TYPE_INT: os << "int (" << expression.i() << ")"; break;
|
||||
@ -802,6 +806,7 @@ namespace client
|
||||
case coInt: output.set_i(opt.opt->getInt()); break;
|
||||
case coString: output.set_s(static_cast<const ConfigOptionString*>(opt.opt)->value); break;
|
||||
case coPercent: output.set_d(opt.opt->getFloat()); break;
|
||||
case coEnum:
|
||||
case coPoint: output.set_s(opt.opt->serialize()); break;
|
||||
case coBool: output.set_b(opt.opt->getBool()); break;
|
||||
case coFloatOrPercent:
|
||||
@ -869,6 +874,7 @@ namespace client
|
||||
case coPercents: output.set_d(static_cast<const ConfigOptionPercents*>(opt.opt)->values[idx]); break;
|
||||
case coPoints: output.set_s(to_string(static_cast<const ConfigOptionPoints *>(opt.opt)->values[idx])); break;
|
||||
case coBools: output.set_b(static_cast<const ConfigOptionBools *>(opt.opt)->values[idx] != 0); break;
|
||||
//case coEnums: output.set_s(opt.opt->vserialize()[idx]); break;
|
||||
default:
|
||||
ctx->throw_exception("Unknown vector variable type", opt.it_range);
|
||||
}
|
||||
@ -880,7 +886,7 @@ namespace client
|
||||
template <typename Iterator>
|
||||
static void evaluate_index(expr<Iterator> &expr_index, int &output)
|
||||
{
|
||||
if (expr_index.type != expr<Iterator>::TYPE_INT)
|
||||
if (expr_index.type() != expr<Iterator>::TYPE_INT)
|
||||
expr_index.throw_exception("Non-integer index is not allowed to address a vector variable.");
|
||||
output = expr_index.i();
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <map>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include "PrintConfig.hpp"
|
||||
|
||||
@ -38,6 +39,8 @@ public:
|
||||
|
||||
// Add new ConfigOption values to m_config.
|
||||
void set(const std::string &key, const std::string &value) { this->set(key, new ConfigOptionString(value)); }
|
||||
void set(const std::string &key, std::string_view value) { this->set(key, new ConfigOptionString(std::string(value))); }
|
||||
void set(const std::string &key, const char *value) { this->set(key, new ConfigOptionString(value)); }
|
||||
void set(const std::string &key, int value) { this->set(key, new ConfigOptionInt(value)); }
|
||||
void set(const std::string &key, unsigned int value) { this->set(key, int(value)); }
|
||||
void set(const std::string &key, bool value) { this->set(key, new ConfigOptionBool(value)); }
|
||||
|
@ -29,6 +29,7 @@ SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") {
|
||||
parser.set("foo", 0);
|
||||
parser.set("bar", 2);
|
||||
parser.set("num_extruders", 4);
|
||||
parser.set("gcode_flavor", "marlin");
|
||||
|
||||
SECTION("nested config options (legacy syntax)") { REQUIRE(parser.process("[temperature_[foo]]") == "357"); }
|
||||
SECTION("array reference") { REQUIRE(parser.process("{temperature[foo]}") == "357"); }
|
||||
@ -110,4 +111,5 @@ SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") {
|
||||
SECTION("complex expression") { REQUIRE(boolean_expression("printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 and num_extruders>1")); }
|
||||
SECTION("complex expression2") { REQUIRE(boolean_expression("printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.6 and num_extruders>1)")); }
|
||||
SECTION("complex expression3") { REQUIRE(! boolean_expression("printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.3 and num_extruders>1)")); }
|
||||
SECTION("enum expression") { REQUIRE(boolean_expression("gcode_flavor == \"marlin\"")); }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user