PlaceholderParser: Reduced code duplicity.
This commit is contained in:
parent
11e22b7950
commit
3045884640
@ -170,7 +170,7 @@ namespace client
|
|||||||
template<typename Iterator>
|
template<typename Iterator>
|
||||||
struct OptWithPos {
|
struct OptWithPos {
|
||||||
OptWithPos() {}
|
OptWithPos() {}
|
||||||
OptWithPos(ConfigOptionConstPtr opt, boost::iterator_range<Iterator> it_range) : opt(opt), it_range(it_range) {}
|
OptWithPos(ConfigOptionConstPtr opt, boost::iterator_range<Iterator> it_range, bool writable = false) : opt(opt), it_range(it_range), writable(writable) {}
|
||||||
ConfigOptionConstPtr opt { nullptr };
|
ConfigOptionConstPtr opt { nullptr };
|
||||||
bool writable { false };
|
bool writable { false };
|
||||||
// -1 means it is a scalar variable, or it is a vector variable and index was not assigned yet or the whole vector is considered.
|
// -1 means it is a scalar variable, or it is a vector variable and index was not assigned yet or the whole vector is considered.
|
||||||
@ -720,9 +720,14 @@ namespace client
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct MyContext : public ConfigOptionResolver {
|
struct MyContext : public ConfigOptionResolver {
|
||||||
|
// Config provided as a parameter to PlaceholderParser invocation, overriding PlaceholderParser stored config.
|
||||||
const DynamicConfig *external_config = nullptr;
|
const DynamicConfig *external_config = nullptr;
|
||||||
|
// Config stored inside PlaceholderParser.
|
||||||
const DynamicConfig *config = nullptr;
|
const DynamicConfig *config = nullptr;
|
||||||
|
// Config provided as a parameter to PlaceholderParser invocation, evaluated after the two configs above.
|
||||||
const DynamicConfig *config_override = nullptr;
|
const DynamicConfig *config_override = nullptr;
|
||||||
|
// Config provided as a parameter to PlaceholderParser invocation, containing variables that will be read out
|
||||||
|
// and processed by the PlaceholderParser callee.
|
||||||
mutable DynamicConfig *config_outputs = nullptr;
|
mutable DynamicConfig *config_outputs = nullptr;
|
||||||
// Local variables, read / write
|
// Local variables, read / write
|
||||||
mutable DynamicConfig config_local;
|
mutable DynamicConfig config_local;
|
||||||
@ -737,6 +742,7 @@ namespace client
|
|||||||
// Table to translate symbol tag to a human readable error message.
|
// Table to translate symbol tag to a human readable error message.
|
||||||
static std::map<std::string, std::string> tag_to_error_message;
|
static std::map<std::string, std::string> tag_to_error_message;
|
||||||
|
|
||||||
|
// Should the parser consider the parsed string to be a macro or a boolean expression?
|
||||||
static bool evaluate_full_macro(const MyContext *ctx) { return ! ctx->just_boolean_expression; }
|
static bool evaluate_full_macro(const MyContext *ctx) { return ! ctx->just_boolean_expression; }
|
||||||
|
|
||||||
const ConfigOption* optptr(const t_config_option_key &opt_key) const override
|
const ConfigOption* optptr(const t_config_option_key &opt_key) const override
|
||||||
@ -762,13 +768,13 @@ namespace client
|
|||||||
out = this->config_local.optptr(opt_key);
|
out = this->config_local.optptr(opt_key);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
void store_new_variable(const std::string &opt_key, ConfigOption *opt, bool global_variable) {
|
void store_new_variable(const std::string &opt_key, std::unique_ptr<ConfigOption> &&opt, bool global_variable) {
|
||||||
assert(opt != nullptr);
|
assert(opt);
|
||||||
if (global_variable) {
|
if (global_variable) {
|
||||||
assert(this->context_data != nullptr && this->context_data->global_config);
|
assert(this->context_data != nullptr && this->context_data->global_config);
|
||||||
this->context_data->global_config->set_key_value(opt_key, opt);
|
this->context_data->global_config->set_key_value(opt_key, opt.release());
|
||||||
} else
|
} else
|
||||||
this->config_local.set_key_value(opt_key ,opt);
|
this->config_local.set_key_value(opt_key, opt.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
@ -844,9 +850,10 @@ namespace client
|
|||||||
boost::iterator_range<Iterator> &opt_key,
|
boost::iterator_range<Iterator> &opt_key,
|
||||||
OptWithPos<Iterator> &output)
|
OptWithPos<Iterator> &output)
|
||||||
{
|
{
|
||||||
const ConfigOption *opt = ctx->resolve_symbol(std::string(opt_key.begin(), opt_key.end()));
|
const std::string key{ opt_key.begin(), opt_key.end() };
|
||||||
|
const ConfigOption *opt = ctx->resolve_symbol(key);
|
||||||
if (opt == nullptr) {
|
if (opt == nullptr) {
|
||||||
opt = ctx->resolve_output_symbol(std::string(opt_key.begin(), opt_key.end()));
|
opt = ctx->resolve_output_symbol(key);
|
||||||
if (opt == nullptr)
|
if (opt == nullptr)
|
||||||
ctx->throw_exception("Not a variable name", opt_key);
|
ctx->throw_exception("Not a variable name", opt_key);
|
||||||
output.writable = true;
|
output.writable = true;
|
||||||
@ -872,32 +879,16 @@ namespace client
|
|||||||
output.it_range.end() = it_end;
|
output.it_range.end() = it_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Evaluating a scalar variable into expr,
|
||||||
|
// all possible ConfigOption types are supported.
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
static void variable_value(
|
static void scalar_variable_to_expr(
|
||||||
const MyContext *ctx,
|
const MyContext *ctx,
|
||||||
OptWithPos<Iterator> &opt,
|
OptWithPos<Iterator> &opt,
|
||||||
expr<Iterator> &output)
|
expr<Iterator> &output)
|
||||||
{
|
{
|
||||||
if (opt.opt->is_vector()) {
|
|
||||||
if (! opt.has_index())
|
|
||||||
ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range);
|
|
||||||
const ConfigOptionVectorBase *vec = static_cast<const ConfigOptionVectorBase*>(opt.opt);
|
|
||||||
if (vec->empty())
|
|
||||||
ctx->throw_exception("Indexing an empty vector variable", opt.it_range);
|
|
||||||
size_t idx = (opt.index < 0) ? 0 : (opt.index >= int(vec->size())) ? 0 : size_t(opt.index);
|
|
||||||
switch (opt.opt->type()) {
|
|
||||||
case coFloats: output.set_d(static_cast<const ConfigOptionFloats *>(opt.opt)->values[idx]); break;
|
|
||||||
case coInts: output.set_i(static_cast<const ConfigOptionInts *>(opt.opt)->values[idx]); break;
|
|
||||||
case coStrings: output.set_s(static_cast<const ConfigOptionStrings *>(opt.opt)->values[idx]); break;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert(opt.opt->is_scalar());
|
assert(opt.opt->is_scalar());
|
||||||
|
|
||||||
switch (opt.opt->type()) {
|
switch (opt.opt->type()) {
|
||||||
case coFloat: output.set_d(opt.opt->getFloat()); break;
|
case coFloat: output.set_d(opt.opt->getFloat()); break;
|
||||||
case coInt: output.set_i(opt.opt->getInt()); break;
|
case coInt: output.set_i(opt.opt->getInt()); break;
|
||||||
@ -945,10 +936,176 @@ namespace client
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
ctx->throw_exception("Unknown scalar variable type", opt.it_range);
|
ctx->throw_exception("Unsupported scalar variable type", opt.it_range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Evaluating one element of a vector variable.
|
||||||
|
// all possible ConfigOption types are supported.
|
||||||
|
template <typename Iterator>
|
||||||
|
static void vector_element_to_expr(
|
||||||
|
const MyContext *ctx,
|
||||||
|
OptWithPos<Iterator> &opt,
|
||||||
|
expr<Iterator> &output)
|
||||||
|
{
|
||||||
|
assert(opt.opt->is_vector());
|
||||||
|
if (! opt.has_index())
|
||||||
|
ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range);
|
||||||
|
const ConfigOptionVectorBase* vec = static_cast<const ConfigOptionVectorBase*>(opt.opt);
|
||||||
|
if (vec->empty())
|
||||||
|
ctx->throw_exception("Indexing an empty vector variable", opt.it_range);
|
||||||
|
size_t idx = (opt.index < 0) ? 0 : (opt.index >= int(vec->size())) ? 0 : size_t(opt.index);
|
||||||
|
switch (opt.opt->type()) {
|
||||||
|
case coFloats: output.set_d(static_cast<const ConfigOptionFloats*>(opt.opt)->values[idx]); break;
|
||||||
|
case coInts: output.set_i(static_cast<const ConfigOptionInts*>(opt.opt)->values[idx]); break;
|
||||||
|
case coStrings: output.set_s(static_cast<const ConfigOptionStrings*>(opt.opt)->values[idx]); break;
|
||||||
|
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("Unsupported vector variable type", opt.it_range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Iterator>
|
||||||
|
static void check_writable(const MyContext *ctx, OptWithPos<Iterator> &opt) {
|
||||||
|
if (! opt.writable)
|
||||||
|
ctx->throw_exception("Cannot modify a read-only variable", opt.it_range);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Iterator>
|
||||||
|
static void check_numeric(const expr<Iterator> ¶m) {
|
||||||
|
if (! param.numeric_type())
|
||||||
|
param.throw_exception("Right side is not a numeric expression");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Iterator>
|
||||||
|
static size_t evaluate_count(const expr<Iterator> &expr_count) {
|
||||||
|
if (expr_count.type() != expr<Iterator>::TYPE_INT)
|
||||||
|
expr_count.throw_exception("Expected number of elements to fill a vector with.");
|
||||||
|
int count = expr_count.i();
|
||||||
|
if (count < 0)
|
||||||
|
expr_count.throw_exception("Negative number of elements specified.");
|
||||||
|
return size_t(count);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Iterator>
|
||||||
|
static void scalar_variable_assign_scalar(
|
||||||
|
const MyContext *ctx,
|
||||||
|
OptWithPos<Iterator> &lhs,
|
||||||
|
const expr<Iterator> &rhs)
|
||||||
|
{
|
||||||
|
assert(lhs.opt->is_scalar());
|
||||||
|
check_writable(ctx, lhs);
|
||||||
|
ConfigOption *wropt = const_cast<ConfigOption*>(lhs.opt);
|
||||||
|
switch (wropt->type()) {
|
||||||
|
case coFloat:
|
||||||
|
check_numeric(rhs);
|
||||||
|
static_cast<ConfigOptionFloat*>(wropt)->value = rhs.as_d();
|
||||||
|
break;
|
||||||
|
case coInt:
|
||||||
|
check_numeric(rhs);
|
||||||
|
static_cast<ConfigOptionInt*>(wropt)->value = rhs.as_i();
|
||||||
|
break;
|
||||||
|
case coString:
|
||||||
|
static_cast<ConfigOptionString*>(wropt)->value = rhs.to_string();
|
||||||
|
break;
|
||||||
|
case coPercent:
|
||||||
|
check_numeric(rhs);
|
||||||
|
static_cast<ConfigOptionPercent*>(wropt)->value = rhs.as_d();
|
||||||
|
break;
|
||||||
|
case coBool:
|
||||||
|
if (rhs.type() != expr<Iterator>::TYPE_BOOL)
|
||||||
|
ctx->throw_exception("Right side is not a boolean expression", rhs.it_range);
|
||||||
|
static_cast<ConfigOptionBool*>(wropt)->value = rhs.b();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ctx->throw_exception("Unsupported output scalar variable type", lhs.it_range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Iterator>
|
||||||
|
static void vector_variable_element_assign_scalar(
|
||||||
|
const MyContext *ctx,
|
||||||
|
OptWithPos<Iterator> &lhs,
|
||||||
|
const expr<Iterator> &rhs)
|
||||||
|
{
|
||||||
|
assert(lhs.opt->is_vector());
|
||||||
|
check_writable(ctx, lhs);
|
||||||
|
if (! lhs.has_index())
|
||||||
|
ctx->throw_exception("Referencing an output vector variable when scalar is expected", lhs.it_range);
|
||||||
|
ConfigOptionVectorBase *vec = const_cast<ConfigOptionVectorBase*>(static_cast<const ConfigOptionVectorBase*>(lhs.opt));
|
||||||
|
if (vec->empty())
|
||||||
|
ctx->throw_exception("Indexing an empty vector variable", lhs.it_range);
|
||||||
|
if (lhs.index >= int(vec->size()))
|
||||||
|
ctx->throw_exception("Index out of range", lhs.it_range);
|
||||||
|
switch (lhs.opt->type()) {
|
||||||
|
case coFloats:
|
||||||
|
check_numeric(rhs);
|
||||||
|
static_cast<ConfigOptionFloats*>(vec)->values[lhs.index] = rhs.as_d();
|
||||||
|
break;
|
||||||
|
case coInts:
|
||||||
|
check_numeric(rhs);
|
||||||
|
static_cast<ConfigOptionInts*>(vec)->values[lhs.index] = rhs.as_i();
|
||||||
|
break;
|
||||||
|
case coStrings:
|
||||||
|
static_cast<ConfigOptionStrings*>(vec)->values[lhs.index] = rhs.to_string();
|
||||||
|
break;
|
||||||
|
case coPercents:
|
||||||
|
check_numeric(rhs);
|
||||||
|
static_cast<ConfigOptionPercents*>(vec)->values[lhs.index] = rhs.as_d();
|
||||||
|
break;
|
||||||
|
case coBools:
|
||||||
|
if (rhs.type() != expr<Iterator>::TYPE_BOOL)
|
||||||
|
ctx->throw_exception("Right side is not a boolean expression", rhs.it_range);
|
||||||
|
static_cast<ConfigOptionBools*>(vec)->values[lhs.index] = rhs.b();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ctx->throw_exception("Unsupported output vector variable type", lhs.it_range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Iterator>
|
||||||
|
static void vector_variable_assign_expr_with_count(
|
||||||
|
const MyContext *ctx,
|
||||||
|
OptWithPos<Iterator> &lhs,
|
||||||
|
const expr<Iterator> &rhs_count,
|
||||||
|
const expr<Iterator> &rhs_value)
|
||||||
|
{
|
||||||
|
size_t count = evaluate_count(rhs_count);
|
||||||
|
auto *opt = const_cast<ConfigOption*>(lhs.opt);
|
||||||
|
switch (lhs.opt->type()) {
|
||||||
|
case coFloats:
|
||||||
|
check_numeric(rhs_value);
|
||||||
|
static_cast<ConfigOptionFloats*>(opt)->values.assign(count, rhs_value.as_d());
|
||||||
|
break;
|
||||||
|
case coInts:
|
||||||
|
check_numeric(rhs_value);
|
||||||
|
static_cast<ConfigOptionInts*>(opt)->values.assign(count, rhs_value.as_i());
|
||||||
|
break;
|
||||||
|
case coStrings:
|
||||||
|
static_cast<ConfigOptionStrings*>(opt)->values.assign(count, rhs_value.to_string());
|
||||||
|
break;
|
||||||
|
case coBools:
|
||||||
|
if (rhs_value.type() != expr<Iterator>::TYPE_BOOL)
|
||||||
|
rhs_value.throw_exception("Right side is not a boolean expression");
|
||||||
|
static_cast<ConfigOptionBools*>(opt)->values.assign(count, rhs_value.b());
|
||||||
|
break;
|
||||||
|
default: assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Iterator>
|
||||||
|
static void variable_value(
|
||||||
|
const MyContext *ctx,
|
||||||
|
OptWithPos<Iterator> &opt,
|
||||||
|
expr<Iterator> &output)
|
||||||
|
{
|
||||||
|
if (opt.opt->is_vector())
|
||||||
|
vector_element_to_expr(ctx, opt, output);
|
||||||
|
else
|
||||||
|
scalar_variable_to_expr(ctx, opt, output);
|
||||||
output.it_range = opt.it_range;
|
output.it_range = opt.it_range;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -974,6 +1131,7 @@ namespace client
|
|||||||
output.it_range = opt.it_range;
|
output.it_range = opt.it_range;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reference to an existing symbol, or a name of a new symbol.
|
||||||
template<typename Iterator>
|
template<typename Iterator>
|
||||||
struct NewOldVariable {
|
struct NewOldVariable {
|
||||||
std::string name;
|
std::string name;
|
||||||
@ -1010,240 +1168,148 @@ namespace client
|
|||||||
out.it_range = it_range;
|
out.it_range = it_range;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Iterator>
|
|
||||||
static void new_scalar_variable(
|
|
||||||
const MyContext *ctx,
|
|
||||||
bool global_variable,
|
|
||||||
NewOldVariable<Iterator> &output_variable,
|
|
||||||
const expr<Iterator> ¶m)
|
|
||||||
{
|
|
||||||
auto check_numeric = [](const expr<Iterator> ¶m) {
|
|
||||||
if (! param.numeric_type())
|
|
||||||
param.throw_exception("Right side is not a numeric expression");
|
|
||||||
};
|
|
||||||
if (output_variable.opt) {
|
|
||||||
if (output_variable.opt->is_vector())
|
|
||||||
param.throw_exception("Cannot assign a scalar value to a vector variable.");
|
|
||||||
switch (output_variable.opt->type()) {
|
|
||||||
case coFloat:
|
|
||||||
check_numeric(param);
|
|
||||||
static_cast<ConfigOptionFloat*>(output_variable.opt)->value = param.as_d();
|
|
||||||
break;
|
|
||||||
case coInt:
|
|
||||||
check_numeric(param);
|
|
||||||
static_cast<ConfigOptionInt*>(output_variable.opt)->value = param.as_i();
|
|
||||||
break;
|
|
||||||
case coString:
|
|
||||||
static_cast<ConfigOptionString*>(output_variable.opt)->value = param.to_string();
|
|
||||||
break;
|
|
||||||
case coBool:
|
|
||||||
if (param.type() != expr<Iterator>::TYPE_BOOL)
|
|
||||||
param.throw_exception("Right side is not a boolean expression");
|
|
||||||
static_cast<ConfigOptionBool*>(output_variable.opt)->value = param.b();
|
|
||||||
break;
|
|
||||||
default: assert(false);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (param.type()) {
|
|
||||||
case expr<Iterator>::TYPE_BOOL: output_variable.opt = new ConfigOptionBool(param.b()); break;
|
|
||||||
case expr<Iterator>::TYPE_INT: output_variable.opt = new ConfigOptionInt(param.i()); break;
|
|
||||||
case expr<Iterator>::TYPE_DOUBLE: output_variable.opt = new ConfigOptionFloat(param.d()); break;
|
|
||||||
case expr<Iterator>::TYPE_STRING: output_variable.opt = new ConfigOptionString(param.s()); break;
|
|
||||||
default: assert(false);
|
|
||||||
}
|
|
||||||
const_cast<MyContext*>(ctx)->store_new_variable(output_variable.name, output_variable.opt, global_variable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Iterator>
|
|
||||||
static void check_writable(const MyContext *ctx, OptWithPos<Iterator> &opt) {
|
|
||||||
if (! opt.writable)
|
|
||||||
ctx->throw_exception("Cannot modify a read-only variable", opt.it_range);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decoding a scalar variable symbol "opt", assigning it a value of "param".
|
// Decoding a scalar variable symbol "opt", assigning it a value of "param".
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
static void assign_scalar_variable(
|
static void scalar_variable_assign_scalar_expression(
|
||||||
const MyContext *ctx,
|
const MyContext *ctx,
|
||||||
OptWithPos<Iterator> &opt,
|
OptWithPos<Iterator> &opt,
|
||||||
expr<Iterator> ¶m)
|
const expr<Iterator> ¶m)
|
||||||
{
|
{
|
||||||
check_writable(ctx, opt);
|
check_writable(ctx, opt);
|
||||||
auto check_numeric = [](const expr<Iterator> ¶m) {
|
if (opt.opt->is_vector())
|
||||||
if (! param.numeric_type())
|
vector_variable_element_assign_scalar(ctx, opt, param);
|
||||||
param.throw_exception("Right side is not a numeric expression");
|
else
|
||||||
};
|
scalar_variable_assign_scalar(ctx, opt, param);
|
||||||
if (opt.opt->is_vector()) {
|
|
||||||
if (! opt.has_index())
|
|
||||||
ctx->throw_exception("Referencing an output vector variable when scalar is expected", opt.it_range);
|
|
||||||
ConfigOptionVectorBase *vec = const_cast<ConfigOptionVectorBase*>(static_cast<const ConfigOptionVectorBase*>(opt.opt));
|
|
||||||
if (vec->empty())
|
|
||||||
ctx->throw_exception("Indexing an empty vector variable", opt.it_range);
|
|
||||||
if (opt.index >= int(vec->size()))
|
|
||||||
ctx->throw_exception("Index out of range", opt.it_range);
|
|
||||||
switch (opt.opt->type()) {
|
|
||||||
case coFloats:
|
|
||||||
check_numeric(param);
|
|
||||||
static_cast<ConfigOptionFloats*>(vec)->values[opt.index] = param.as_d();
|
|
||||||
break;
|
|
||||||
case coInts:
|
|
||||||
check_numeric(param);
|
|
||||||
static_cast<ConfigOptionInts*>(vec)->values[opt.index] = param.as_i();
|
|
||||||
break;
|
|
||||||
case coStrings:
|
|
||||||
static_cast<ConfigOptionStrings*>(vec)->values[opt.index] = param.to_string();
|
|
||||||
break;
|
|
||||||
case coPercents:
|
|
||||||
check_numeric(param);
|
|
||||||
static_cast<ConfigOptionPercents*>(vec)->values[opt.index] = param.as_d();
|
|
||||||
break;
|
|
||||||
case coBools:
|
|
||||||
if (param.type() != expr<Iterator>::TYPE_BOOL)
|
|
||||||
ctx->throw_exception("Right side is not a boolean expression", param.it_range);
|
|
||||||
static_cast<ConfigOptionBools*>(vec)->values[opt.index] = param.b();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ctx->throw_exception("Unsupported output vector variable type", opt.it_range);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert(opt.opt->is_scalar());
|
|
||||||
ConfigOption *wropt = const_cast<ConfigOption*>(opt.opt);
|
|
||||||
switch (wropt->type()) {
|
|
||||||
case coFloat:
|
|
||||||
check_numeric(param);
|
|
||||||
static_cast<ConfigOptionFloat*>(wropt)->value = param.as_d();
|
|
||||||
break;
|
|
||||||
case coInt:
|
|
||||||
check_numeric(param);
|
|
||||||
static_cast<ConfigOptionInt*>(wropt)->value = param.as_i();
|
|
||||||
break;
|
|
||||||
case coString:
|
|
||||||
static_cast<ConfigOptionString*>(wropt)->value = param.to_string();
|
|
||||||
break;
|
|
||||||
case coPercent:
|
|
||||||
check_numeric(param);
|
|
||||||
static_cast<ConfigOptionPercent*>(wropt)->value = param.as_d();
|
|
||||||
break;
|
|
||||||
case coBool:
|
|
||||||
if (param.type() != expr<Iterator>::TYPE_BOOL)
|
|
||||||
ctx->throw_exception("Right side is not a boolean expression", param.it_range);
|
|
||||||
static_cast<ConfigOptionBool*>(wropt)->value = param.b();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ctx->throw_exception("Unsupported output scalar variable type", opt.it_range);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
static void new_vector_variable_array(
|
static void scalar_variable_new_from_scalar_expression(
|
||||||
const MyContext *ctx,
|
const MyContext *ctx,
|
||||||
bool global_variable,
|
bool global_variable,
|
||||||
NewOldVariable<Iterator> &output_variable,
|
NewOldVariable<Iterator> &lhs,
|
||||||
const expr<Iterator> &expr_count,
|
const expr<Iterator> &rhs)
|
||||||
const expr<Iterator> &expr_value)
|
|
||||||
{
|
{
|
||||||
auto check_numeric = [](const expr<Iterator> ¶m) {
|
if (lhs.opt) {
|
||||||
if (! param.numeric_type())
|
if (lhs.opt->is_vector())
|
||||||
param.throw_exception("Right side is not a numeric expression");
|
rhs.throw_exception("Cannot assign a scalar value to a vector variable.");
|
||||||
};
|
OptWithPos lhs_opt{ lhs.opt, lhs.it_range, true };
|
||||||
auto evaluate_count = [](const expr<Iterator> &expr_count) -> size_t {
|
scalar_variable_assign_scalar(ctx, lhs_opt, rhs);
|
||||||
if (expr_count.type() != expr<Iterator>::TYPE_INT)
|
|
||||||
expr_count.throw_exception("Expected number of elements to fill a vector with.");
|
|
||||||
int count = expr_count.i();
|
|
||||||
if (count < 0)
|
|
||||||
expr_count.throw_exception("Negative number of elements specified.");
|
|
||||||
return size_t(count);
|
|
||||||
};
|
|
||||||
if (output_variable.opt) {
|
|
||||||
if (output_variable.opt->is_scalar())
|
|
||||||
expr_value.throw_exception("Cannot assign a vector value to a scalar variable.");
|
|
||||||
size_t count = evaluate_count(expr_count);
|
|
||||||
switch (output_variable.opt->type()) {
|
|
||||||
case coFloats:
|
|
||||||
check_numeric(expr_value);
|
|
||||||
static_cast<ConfigOptionFloats*>(output_variable.opt)->values.assign(count, expr_value.as_d());
|
|
||||||
break;
|
|
||||||
case coInts:
|
|
||||||
check_numeric(expr_value);
|
|
||||||
static_cast<ConfigOptionInts*>(output_variable.opt)->values.assign(count, expr_value.as_i());
|
|
||||||
break;
|
|
||||||
case coStrings:
|
|
||||||
static_cast<ConfigOptionStrings*>(output_variable.opt)->values.assign(count, expr_value.to_string());
|
|
||||||
break;
|
|
||||||
case coBools:
|
|
||||||
if (expr_value.type() != expr<Iterator>::TYPE_BOOL)
|
|
||||||
expr_value.throw_exception("Right side is not a boolean expression");
|
|
||||||
static_cast<ConfigOptionBools*>(output_variable.opt)->values.assign(count, expr_value.b());
|
|
||||||
break;
|
|
||||||
default: assert(false);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
size_t count = evaluate_count(expr_count);
|
std::unique_ptr<ConfigOption> opt_new;
|
||||||
switch (expr_value.type()) {
|
switch (rhs.type()) {
|
||||||
case expr<Iterator>::TYPE_BOOL: output_variable.opt = new ConfigOptionBools(count, expr_value.b()); break;
|
case expr<Iterator>::TYPE_BOOL: opt_new = std::make_unique<ConfigOptionBool>(rhs.b()); break;
|
||||||
case expr<Iterator>::TYPE_INT: output_variable.opt = new ConfigOptionInts(count, expr_value.i()); break;
|
case expr<Iterator>::TYPE_INT: opt_new = std::make_unique<ConfigOptionInt>(rhs.i()); break;
|
||||||
case expr<Iterator>::TYPE_DOUBLE: output_variable.opt = new ConfigOptionFloats(count, expr_value.d()); break;
|
case expr<Iterator>::TYPE_DOUBLE: opt_new = std::make_unique<ConfigOptionFloat>(rhs.d()); break;
|
||||||
case expr<Iterator>::TYPE_STRING: output_variable.opt = new ConfigOptionStrings(count, expr_value.s()); break;
|
case expr<Iterator>::TYPE_STRING: opt_new = std::make_unique<ConfigOptionString>(rhs.s()); break;
|
||||||
default: assert(false);
|
default: assert(false);
|
||||||
}
|
}
|
||||||
const_cast<MyContext*>(ctx)->store_new_variable(output_variable.name, output_variable.opt, global_variable);
|
const_cast<MyContext*>(ctx)->store_new_variable(lhs.name, std::move(opt_new), global_variable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
static void assign_vector_variable_array(
|
static void vector_variable_new_from_array(
|
||||||
|
const MyContext *ctx,
|
||||||
|
bool global_variable,
|
||||||
|
NewOldVariable<Iterator> &lhs,
|
||||||
|
const expr<Iterator> &rhs_count,
|
||||||
|
const expr<Iterator> &rhs_value)
|
||||||
|
{
|
||||||
|
if (lhs.opt) {
|
||||||
|
if (lhs.opt->is_scalar())
|
||||||
|
rhs_value.throw_exception("Cannot assign a vector value to a scalar variable.");
|
||||||
|
OptWithPos lhs_opt{ lhs.opt, lhs.it_range, true };
|
||||||
|
vector_variable_assign_expr_with_count(ctx, lhs_opt, rhs_count, rhs_value);
|
||||||
|
} else {
|
||||||
|
size_t count = evaluate_count(rhs_count);
|
||||||
|
std::unique_ptr<ConfigOption> opt_new;
|
||||||
|
switch (rhs_value.type()) {
|
||||||
|
case expr<Iterator>::TYPE_BOOL: opt_new = std::make_unique<ConfigOptionBools>(count, rhs_value.b()); break;
|
||||||
|
case expr<Iterator>::TYPE_INT: opt_new = std::make_unique<ConfigOptionInts>(count, rhs_value.i()); break;
|
||||||
|
case expr<Iterator>::TYPE_DOUBLE: opt_new = std::make_unique<ConfigOptionFloats>(count, rhs_value.d()); break;
|
||||||
|
case expr<Iterator>::TYPE_STRING: opt_new = std::make_unique<ConfigOptionStrings>(count, rhs_value.s()); break;
|
||||||
|
default: assert(false);
|
||||||
|
}
|
||||||
|
const_cast<MyContext*>(ctx)->store_new_variable(lhs.name, std::move(opt_new), global_variable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Iterator>
|
||||||
|
static void vector_variable_assign_array(
|
||||||
const MyContext *ctx,
|
const MyContext *ctx,
|
||||||
OptWithPos<Iterator> &lhs,
|
OptWithPos<Iterator> &lhs,
|
||||||
const expr<Iterator> &expr_count,
|
const expr<Iterator> &rhs_count,
|
||||||
const expr<Iterator> &expr_value)
|
const expr<Iterator> &rhs_value)
|
||||||
{
|
{
|
||||||
check_writable(ctx, lhs);
|
check_writable(ctx, lhs);
|
||||||
auto check_numeric = [](const expr<Iterator> ¶m) {
|
|
||||||
if (! param.numeric_type())
|
|
||||||
param.throw_exception("Right side is not a numeric expression");
|
|
||||||
};
|
|
||||||
auto evaluate_count = [](const expr<Iterator> &expr_count) -> size_t {
|
|
||||||
if (expr_count.type() != expr<Iterator>::TYPE_INT)
|
|
||||||
expr_count.throw_exception("Expected number of elements to fill a vector with.");
|
|
||||||
int count = expr_count.i();
|
|
||||||
if (count < 0)
|
|
||||||
expr_count.throw_exception("Negative number of elements specified.");
|
|
||||||
return size_t(count);
|
|
||||||
};
|
|
||||||
if (lhs.opt->is_scalar())
|
if (lhs.opt->is_scalar())
|
||||||
expr_value.throw_exception("Cannot assign a vector value to a scalar variable.");
|
rhs_value.throw_exception("Cannot assign a vector value to a scalar variable.");
|
||||||
auto *opt = const_cast<ConfigOption*>(lhs.opt);
|
vector_variable_assign_expr_with_count(ctx, lhs, rhs_count, rhs_value);
|
||||||
size_t count = evaluate_count(expr_count);
|
}
|
||||||
|
|
||||||
|
template<typename ConfigOptionType, typename Iterator, typename RightValueEvaluate>
|
||||||
|
static void fill_vector_from_initializer_list(ConfigOption *opt, const std::vector<expr<Iterator>> &il, RightValueEvaluate rv_eval) {
|
||||||
|
auto& out = static_cast<ConfigOptionType*>(opt)->values;
|
||||||
|
out.clear();
|
||||||
|
out.reserve(il.size());
|
||||||
|
for (const expr<Iterator>& i : il)
|
||||||
|
out.emplace_back(rv_eval(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Iterator>
|
||||||
|
static void vector_variable_assign_initializer_list(
|
||||||
|
const MyContext *ctx,
|
||||||
|
OptWithPos<Iterator> &lhs,
|
||||||
|
const std::vector<expr<Iterator>> &il)
|
||||||
|
{
|
||||||
|
check_writable(ctx, lhs);
|
||||||
|
auto check_numeric_vector = [](const std::vector<expr<Iterator>> &il) {
|
||||||
|
for (auto &i : il)
|
||||||
|
if (! i.numeric_type())
|
||||||
|
i.throw_exception("Right side is not a numeric expression");
|
||||||
|
};
|
||||||
|
|
||||||
|
if (lhs.opt->is_scalar())
|
||||||
|
ctx->throw_exception("Cannot assign a vector value to a scalar variable.", lhs.it_range);
|
||||||
|
|
||||||
|
ConfigOption *opt = const_cast<ConfigOption*>(lhs.opt);
|
||||||
switch (lhs.opt->type()) {
|
switch (lhs.opt->type()) {
|
||||||
case coFloats:
|
case coFloats:
|
||||||
check_numeric(expr_value);
|
check_numeric_vector(il);
|
||||||
static_cast<ConfigOptionFloats*>(opt)->values.assign(count, expr_value.as_d());
|
fill_vector_from_initializer_list<ConfigOptionFloats>(opt, il, [](auto &v){ return v.as_d(); });
|
||||||
break;
|
break;
|
||||||
case coInts:
|
case coInts:
|
||||||
check_numeric(expr_value);
|
check_numeric_vector(il);
|
||||||
static_cast<ConfigOptionInts*>(opt)->values.assign(count, expr_value.as_i());
|
fill_vector_from_initializer_list<ConfigOptionInts>(opt, il, [](auto &v){ return v.as_i(); });
|
||||||
break;
|
break;
|
||||||
case coStrings:
|
case coStrings:
|
||||||
static_cast<ConfigOptionStrings*>(opt)->values.assign(count, expr_value.to_string());
|
fill_vector_from_initializer_list<ConfigOptionStrings>(opt, il, [](auto &v){ return v.to_string(); });
|
||||||
break;
|
break;
|
||||||
case coBools:
|
case coBools:
|
||||||
if (expr_value.type() != expr<Iterator>::TYPE_BOOL)
|
for (auto &i : il)
|
||||||
expr_value.throw_exception("Right side is not a boolean expression");
|
if (i.type() != expr<Iterator>::TYPE_BOOL)
|
||||||
static_cast<ConfigOptionBools*>(opt)->values.assign(count, expr_value.b());
|
i.throw_exception("Right side is not a boolean expression");
|
||||||
|
fill_vector_from_initializer_list<ConfigOptionBools>(opt, il, [](auto &v){ return v.b(); });
|
||||||
break;
|
break;
|
||||||
default: assert(false);
|
default: assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
static void new_vector_variable_initializer_list(
|
static void vector_variable_new_from_initializer_list(
|
||||||
const MyContext *ctx,
|
const MyContext *ctx,
|
||||||
bool global_variable,
|
bool global_variable,
|
||||||
NewOldVariable<Iterator> &output_variable,
|
NewOldVariable<Iterator> &lhs,
|
||||||
const std::vector<expr<Iterator>> &il)
|
const std::vector<expr<Iterator>> &il)
|
||||||
{
|
{
|
||||||
if (! output_variable.opt) {
|
if (lhs.opt) {
|
||||||
|
// Assign to an existing vector variable.
|
||||||
|
if (lhs.opt->is_scalar())
|
||||||
|
ctx->throw_exception("Cannot assign a vector value to a scalar variable.", lhs.it_range);
|
||||||
|
OptWithPos lhs_opt{ lhs.opt, lhs.it_range, true };
|
||||||
|
vector_variable_assign_initializer_list(ctx, lhs_opt, il);
|
||||||
|
} else {
|
||||||
|
// Allocate a new vector variable.
|
||||||
// First guesstimate type of the output vector.
|
// First guesstimate type of the output vector.
|
||||||
size_t num_bool = 0;
|
size_t num_bool = 0;
|
||||||
size_t num_int = 0;
|
size_t num_int = 0;
|
||||||
@ -1257,186 +1323,53 @@ namespace client
|
|||||||
case expr<Iterator>::TYPE_STRING: ++ num_string; break;
|
case expr<Iterator>::TYPE_STRING: ++ num_string; break;
|
||||||
default: assert(false);
|
default: assert(false);
|
||||||
}
|
}
|
||||||
|
std::unique_ptr<ConfigOption> opt_new;
|
||||||
if (num_string > 0)
|
if (num_string > 0)
|
||||||
// Convert everything to strings.
|
// Convert everything to strings.
|
||||||
output_variable.opt = new ConfigOptionStrings();
|
opt_new = std::make_unique<ConfigOptionStrings>();
|
||||||
else if (num_bool > 0) {
|
else if (num_bool > 0) {
|
||||||
if (num_double + num_int > 0)
|
if (num_double + num_int > 0)
|
||||||
ctx->throw_exception("Right side is not valid: Mixing numeric and boolean types.", boost::iterator_range<Iterator>{ il.front().it_range.begin(), il.back().it_range.end() });
|
ctx->throw_exception("Right side is not valid: Mixing numeric and boolean types.", boost::iterator_range<Iterator>{ il.front().it_range.begin(), il.back().it_range.end() });
|
||||||
output_variable.opt = new ConfigOptionBools();
|
opt_new = std::make_unique<ConfigOptionBools>();
|
||||||
} else
|
} else {
|
||||||
// Output is numeric.
|
// Output is numeric.
|
||||||
output_variable.opt = num_double == 0 ? static_cast<ConfigOption*>(new ConfigOptionInts()) : static_cast<ConfigOption*>(new ConfigOptionFloats());
|
if (num_double == 0)
|
||||||
const_cast<MyContext*>(ctx)->store_new_variable(output_variable.name, output_variable.opt, global_variable);
|
opt_new = std::make_unique<ConfigOptionInts>();
|
||||||
}
|
|
||||||
|
|
||||||
auto check_numeric = [](const std::vector<expr<Iterator>> &il) {
|
|
||||||
for (auto& i : il)
|
|
||||||
if (!i.numeric_type())
|
|
||||||
i.throw_exception("Right side is not a numeric expression");
|
|
||||||
};
|
|
||||||
|
|
||||||
if (output_variable.opt->is_scalar())
|
|
||||||
ctx->throw_exception("Cannot assign a vector value to a scalar variable.", output_variable.it_range);
|
|
||||||
|
|
||||||
switch (output_variable.opt->type()) {
|
|
||||||
case coFloats:
|
|
||||||
{
|
|
||||||
check_numeric(il);
|
|
||||||
auto &out = static_cast<ConfigOptionFloats*>(output_variable.opt)->values;
|
|
||||||
out.clear();
|
|
||||||
out.reserve(il.size());
|
|
||||||
for (auto &i : il)
|
|
||||||
out.emplace_back(i.as_d());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case coInts:
|
|
||||||
{
|
|
||||||
check_numeric(il);
|
|
||||||
auto &out = static_cast<ConfigOptionInts*>(output_variable.opt)->values;
|
|
||||||
out.clear();
|
|
||||||
out.reserve(il.size());
|
|
||||||
for (auto& i : il)
|
|
||||||
out.emplace_back(i.as_i());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case coStrings:
|
|
||||||
{
|
|
||||||
auto &out = static_cast<ConfigOptionStrings*>(output_variable.opt)->values;
|
|
||||||
out.clear();
|
|
||||||
out.reserve(il.size());
|
|
||||||
for (auto &i : il)
|
|
||||||
out.emplace_back(i.to_string());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case coBools:
|
|
||||||
{
|
|
||||||
auto &out = static_cast<ConfigOptionBools*>(output_variable.opt)->values;
|
|
||||||
out.clear();
|
|
||||||
out.reserve(il.size());
|
|
||||||
for (auto &i : il)
|
|
||||||
if (i.type() == expr<Iterator>::TYPE_BOOL)
|
|
||||||
out.emplace_back(i.b());
|
|
||||||
else
|
else
|
||||||
i.throw_exception("Right side is not a boolean expression");
|
opt_new = std::make_unique<ConfigOptionFloats>();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
default:
|
OptWithPos lhs_opt{ opt_new.get(), lhs.it_range, true };
|
||||||
assert(false);
|
vector_variable_assign_initializer_list(ctx, lhs_opt, il);
|
||||||
|
const_cast<MyContext*>(ctx)->store_new_variable(lhs.name, std::move(opt_new), global_variable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
static void assign_vector_variable_initializer_list(
|
static void copy_vector_variable_to_vector_variable(
|
||||||
const MyContext *ctx,
|
const MyContext *ctx,
|
||||||
OptWithPos<Iterator> &lhs,
|
OptWithPos<Iterator> &lhs,
|
||||||
const std::vector<expr<Iterator>> &il)
|
const OptWithPos<Iterator> &rhs)
|
||||||
{
|
{
|
||||||
check_writable(ctx, lhs);
|
check_writable(ctx, lhs);
|
||||||
auto check_numeric = [](const std::vector<expr<Iterator>> &il) {
|
assert(rhs.opt->is_vector());
|
||||||
for (auto &i : il)
|
if (! lhs.opt->is_vector())
|
||||||
if (! i.numeric_type())
|
ctx->throw_exception("Cannot assign vector to a scalar", lhs.it_range);
|
||||||
i.throw_exception("Right side is not a numeric expression");
|
if (lhs.opt->type() != rhs.opt->type()) {
|
||||||
};
|
// Vector types are not compatible.
|
||||||
|
|
||||||
if (lhs.opt->is_scalar())
|
|
||||||
ctx->throw_exception("Cannot assign a vector value to a scalar variable.", lhs.it_range);
|
|
||||||
|
|
||||||
ConfigOption *opt = const_cast<ConfigOption*>(lhs.opt);
|
|
||||||
switch (lhs.opt->type()) {
|
switch (lhs.opt->type()) {
|
||||||
case coFloats:
|
case coFloats:
|
||||||
{
|
ctx->throw_exception("Left hand side is a float vector, while the right hand side is not.", lhs.it_range);
|
||||||
check_numeric(il);
|
|
||||||
auto &out = static_cast<ConfigOptionFloats*>(opt)->values;
|
|
||||||
out.clear();
|
|
||||||
out.reserve(il.size());
|
|
||||||
for (auto &i : il)
|
|
||||||
out.emplace_back(i.as_d());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case coInts:
|
case coInts:
|
||||||
{
|
ctx->throw_exception("Left hand side is an int vector, while the right hand side is not.", lhs.it_range);
|
||||||
check_numeric(il);
|
|
||||||
auto &out = static_cast<ConfigOptionInts*>(opt)->values;
|
|
||||||
out.clear();
|
|
||||||
out.reserve(il.size());
|
|
||||||
for (auto& i : il)
|
|
||||||
out.emplace_back(i.as_i());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case coStrings:
|
case coStrings:
|
||||||
{
|
ctx->throw_exception("Left hand side is a string vector, while the right hand side is not.", lhs.it_range);
|
||||||
auto &out = static_cast<ConfigOptionStrings*>(opt)->values;
|
|
||||||
out.clear();
|
|
||||||
out.reserve(il.size());
|
|
||||||
for (auto &i : il)
|
|
||||||
out.emplace_back(i.to_string());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case coBools:
|
case coBools:
|
||||||
{
|
ctx->throw_exception("Left hand side is a bool vector, while the right hand side is not.", lhs.it_range);
|
||||||
auto &out = static_cast<ConfigOptionBools*>(opt)->values;
|
|
||||||
out.clear();
|
|
||||||
out.reserve(il.size());
|
|
||||||
for (auto &i : il)
|
|
||||||
if (i.type() == expr<Iterator>::TYPE_BOOL)
|
|
||||||
out.emplace_back(i.b());
|
|
||||||
else
|
|
||||||
i.throw_exception("Right side is not a boolean expression");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
assert(false);
|
ctx->throw_exception("Left hand side / right hand side vectors are not compatible.", lhs.it_range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const_cast<ConfigOption*>(lhs.opt)->set(rhs.opt);
|
||||||
template <typename Iterator>
|
|
||||||
static bool new_vector_variable_copy(
|
|
||||||
const MyContext *ctx,
|
|
||||||
bool global_variable,
|
|
||||||
NewOldVariable<Iterator> &output_variable,
|
|
||||||
const OptWithPos<Iterator> &src_variable)
|
|
||||||
{
|
|
||||||
if (! is_vector_variable_reference(src_variable))
|
|
||||||
// Skip parsing this branch, bactrack.
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (! output_variable.opt) {
|
|
||||||
if (one_of(src_variable.opt->type(), { coFloats, coInts, coStrings, coBools }))
|
|
||||||
output_variable.opt = src_variable.opt->clone();
|
|
||||||
else if (src_variable.opt->type() == coPercents)
|
|
||||||
output_variable.opt = new ConfigOptionFloats(static_cast<const ConfigOptionPercents*>(src_variable.opt)->values);
|
|
||||||
else
|
|
||||||
ctx->throw_exception("Duplicating this vector variable is not supported", src_variable.it_range);
|
|
||||||
const_cast<MyContext*>(ctx)->store_new_variable(output_variable.name, output_variable.opt, global_variable);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (output_variable.opt->type()) {
|
|
||||||
case coFloats:
|
|
||||||
if (output_variable.opt->type() != coFloats)
|
|
||||||
ctx->throw_exception("Left hand side is a float vector, while the right hand side is not.", boost::iterator_range<Iterator>{ output_variable.it_range.begin(), src_variable.it_range.end() });
|
|
||||||
static_cast<ConfigOptionFloats*>(output_variable.opt)->values = static_cast<const ConfigOptionFloats*>(src_variable.opt)->values;
|
|
||||||
break;
|
|
||||||
case coInts:
|
|
||||||
if (output_variable.opt->type() != coInts)
|
|
||||||
ctx->throw_exception("Left hand side is an int vector, while the right hand side is not.", boost::iterator_range<Iterator>{ output_variable.it_range.begin(), src_variable.it_range.end() });
|
|
||||||
static_cast<ConfigOptionInts*>(output_variable.opt)->values = static_cast<const ConfigOptionInts*>(src_variable.opt)->values;
|
|
||||||
break;
|
|
||||||
case coStrings:
|
|
||||||
if (output_variable.opt->type() != coStrings)
|
|
||||||
ctx->throw_exception("Left hand side is a string vector, while the right hand side is not.", boost::iterator_range<Iterator>{ output_variable.it_range.begin(), src_variable.it_range.end() });
|
|
||||||
static_cast<ConfigOptionStrings*>(output_variable.opt)->values = static_cast<const ConfigOptionStrings*>(src_variable.opt)->values;
|
|
||||||
break;
|
|
||||||
case coBools:
|
|
||||||
if (output_variable.opt->type() != coBools)
|
|
||||||
ctx->throw_exception("Left hand side is a bool vector, while the right hand side is not.", boost::iterator_range<Iterator>{ output_variable.it_range.begin(), src_variable.it_range.end() });
|
|
||||||
static_cast<ConfigOptionBools*>(output_variable.opt)->values = static_cast<const ConfigOptionBools*>(src_variable.opt)->values;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
// Continue parsing.
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
@ -1445,49 +1378,53 @@ namespace client
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
static bool assign_vector_variable_copy(
|
static bool vector_variable_new_from_copy(
|
||||||
const MyContext *ctx,
|
const MyContext *ctx,
|
||||||
OptWithPos<Iterator> &lhs,
|
bool global_variable,
|
||||||
const OptWithPos<Iterator> &src_variable)
|
NewOldVariable<Iterator> &lhs,
|
||||||
|
const OptWithPos<Iterator> &rhs)
|
||||||
{
|
{
|
||||||
if (! is_vector_variable_reference(src_variable))
|
if (is_vector_variable_reference(rhs)) {
|
||||||
// Skip parsing this branch, bactrack.
|
if (lhs.opt) {
|
||||||
return false;
|
OptWithPos lhs_opt{ lhs.opt, lhs.it_range, true };
|
||||||
|
copy_vector_variable_to_vector_variable(ctx, lhs_opt, rhs);
|
||||||
check_writable(ctx, lhs);
|
} else {
|
||||||
|
// Clone the vector variable.
|
||||||
auto *opt = const_cast<ConfigOption*>(lhs.opt);
|
std::unique_ptr<ConfigOption> opt_new;
|
||||||
switch (lhs.opt->type()) {
|
if (one_of(rhs.opt->type(), { coFloats, coInts, coStrings, coBools }))
|
||||||
case coFloats:
|
opt_new = std::unique_ptr<ConfigOption>(rhs.opt->clone());
|
||||||
if (lhs.opt->type() != coFloats)
|
else if (rhs.opt->type() == coPercents)
|
||||||
ctx->throw_exception("Left hand side is a float vector, while the right hand side is not.", lhs.it_range);
|
opt_new = std::make_unique<ConfigOptionFloats>(static_cast<const ConfigOptionPercents*>(rhs.opt)->values);
|
||||||
static_cast<ConfigOptionFloats*>(opt)->values = static_cast<const ConfigOptionFloats*>(src_variable.opt)->values;
|
else
|
||||||
break;
|
ctx->throw_exception("Duplicating this type of vector variable is not supported", rhs.it_range);
|
||||||
case coInts:
|
const_cast<MyContext*>(ctx)->store_new_variable(lhs.name, std::move(opt_new), global_variable);
|
||||||
if (lhs.opt->type() != coInts)
|
|
||||||
ctx->throw_exception("Left hand side is an int vector, while the right hand side is not.", lhs.it_range);
|
|
||||||
static_cast<ConfigOptionInts*>(opt)->values = static_cast<const ConfigOptionInts*>(src_variable.opt)->values;
|
|
||||||
break;
|
|
||||||
case coStrings:
|
|
||||||
if (lhs.opt->type() != coStrings)
|
|
||||||
ctx->throw_exception("Left hand side is a string vector, while the right hand side is not.", lhs.it_range);
|
|
||||||
static_cast<ConfigOptionStrings*>(opt)->values = static_cast<const ConfigOptionStrings*>(src_variable.opt)->values;
|
|
||||||
break;
|
|
||||||
case coBools:
|
|
||||||
if (lhs.opt->type() != coBools)
|
|
||||||
ctx->throw_exception("Left hand side is a bool vector, while the right hand side is not.", lhs.it_range);
|
|
||||||
static_cast<ConfigOptionBools*>(opt)->values = static_cast<const ConfigOptionBools*>(src_variable.opt)->values;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Continue parsing.
|
// Continue parsing.
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
// Skip parsing this branch, bactrack.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
static void new_vector_variable_initializer_list_append(std::vector<expr<Iterator>> &list, expr<Iterator> &expr)
|
static bool vector_variable_assign_copy(
|
||||||
|
const MyContext *ctx,
|
||||||
|
OptWithPos<Iterator> &lhs,
|
||||||
|
const OptWithPos<Iterator> &rhs)
|
||||||
|
{
|
||||||
|
if (is_vector_variable_reference(rhs)) {
|
||||||
|
copy_vector_variable_to_vector_variable(ctx, lhs, rhs);
|
||||||
|
// Continue parsing.
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// Skip parsing this branch, bactrack.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Iterator>
|
||||||
|
static void initializer_list_append(std::vector<expr<Iterator>> &list, expr<Iterator> &expr)
|
||||||
{
|
{
|
||||||
list.emplace_back(std::move(expr));
|
list.emplace_back(std::move(expr));
|
||||||
}
|
}
|
||||||
@ -1910,36 +1847,36 @@ namespace client
|
|||||||
variable_reference(_r1)[_a = _1] >> '=' >
|
variable_reference(_r1)[_a = _1] >> '=' >
|
||||||
( // Consumes also '(' conditional_expression ')', that means enclosing an expression into braces makes it a single value vector initializer.
|
( // Consumes also '(' conditional_expression ')', that means enclosing an expression into braces makes it a single value vector initializer.
|
||||||
(lit('(') > new_variable_initializer_list(_r1) > ')')
|
(lit('(') > new_variable_initializer_list(_r1) > ')')
|
||||||
[px::bind(&MyContext::assign_vector_variable_initializer_list<Iterator>, _r1, _a, _1)]
|
[px::bind(&MyContext::vector_variable_assign_initializer_list<Iterator>, _r1, _a, _1)]
|
||||||
// Process it before conditional_expression, as conditional_expression requires a vector reference to be augmented with an index.
|
// Process it before conditional_expression, as conditional_expression requires a vector reference to be augmented with an index.
|
||||||
// Only process such variable references, which return a naked vector variable.
|
// Only process such variable references, which return a naked vector variable.
|
||||||
| variable_reference(_r1)
|
| variable_reference(_r1)
|
||||||
[px::ref(qi::_pass) = px::bind(&MyContext::assign_vector_variable_copy<Iterator>, _r1, _a, _1)]
|
[px::ref(qi::_pass) = px::bind(&MyContext::vector_variable_assign_copy<Iterator>, _r1, _a, _1)]
|
||||||
// Would NOT consume '(' conditional_expression ')' because such value was consumed with the expression above.
|
// Would NOT consume '(' conditional_expression ')' because such value was consumed with the expression above.
|
||||||
| conditional_expression(_r1)
|
| conditional_expression(_r1)
|
||||||
[px::bind(&MyContext::assign_scalar_variable<Iterator>, _r1, _a, _1)]
|
[px::bind(&MyContext::scalar_variable_assign_scalar_expression<Iterator>, _r1, _a, _1)]
|
||||||
| (kw["array"] > "(" > additive_expression(_r1) > "," > conditional_expression(_r1) > ")")
|
| (kw["array"] > "(" > additive_expression(_r1) > "," > conditional_expression(_r1) > ")")
|
||||||
[px::bind(&MyContext::assign_vector_variable_array<Iterator>, _r1, _a, _1, _2)]
|
[px::bind(&MyContext::vector_variable_assign_array<Iterator>, _r1, _a, _1, _2)]
|
||||||
);
|
);
|
||||||
|
|
||||||
new_variable_statement =
|
new_variable_statement =
|
||||||
(kw["local"][_a = false] | kw["global"][_a = true]) > identifier[px::bind(&MyContext::new_old_variable<Iterator>, _r1, _a, _1, _b)] > lit('=') >
|
(kw["local"][_a = false] | kw["global"][_a = true]) > identifier[px::bind(&MyContext::new_old_variable<Iterator>, _r1, _a, _1, _b)] > lit('=') >
|
||||||
( // Consumes also '(' conditional_expression ')', that means enclosing an expression into braces makes it a single value vector initializer.
|
( // Consumes also '(' conditional_expression ')', that means enclosing an expression into braces makes it a single value vector initializer.
|
||||||
(lit('(') > new_variable_initializer_list(_r1) > ')')
|
(lit('(') > new_variable_initializer_list(_r1) > ')')
|
||||||
[px::bind(&MyContext::new_vector_variable_initializer_list<Iterator>, _r1, _a, _b, _1)]
|
[px::bind(&MyContext::vector_variable_new_from_initializer_list<Iterator>, _r1, _a, _b, _1)]
|
||||||
// Process it before conditional_expression, as conditional_expression requires a vector reference to be augmented with an index.
|
// Process it before conditional_expression, as conditional_expression requires a vector reference to be augmented with an index.
|
||||||
// Only process such variable references, which return a naked vector variable.
|
// Only process such variable references, which return a naked vector variable.
|
||||||
| variable_reference(_r1)
|
| variable_reference(_r1)
|
||||||
[px::ref(qi::_pass) = px::bind(&MyContext::new_vector_variable_copy<Iterator>, _r1, _a, _b, _1)]
|
[px::ref(qi::_pass) = px::bind(&MyContext::vector_variable_new_from_copy<Iterator>, _r1, _a, _b, _1)]
|
||||||
// Would NOT consume '(' conditional_expression ')' because such value was consumed with the expression above.
|
// Would NOT consume '(' conditional_expression ')' because such value was consumed with the expression above.
|
||||||
| conditional_expression(_r1)
|
| conditional_expression(_r1)
|
||||||
[px::bind(&MyContext::new_scalar_variable<Iterator>, _r1, _a, _b, _1)]
|
[px::bind(&MyContext::scalar_variable_new_from_scalar_expression<Iterator>, _r1, _a, _b, _1)]
|
||||||
| (kw["array"] > "(" > additive_expression(_r1) > "," > conditional_expression(_r1) > ")")
|
| (kw["array"] > "(" > additive_expression(_r1) > "," > conditional_expression(_r1) > ")")
|
||||||
[px::bind(&MyContext::new_vector_variable_array<Iterator>, _r1, _a, _b, _1, _2)]
|
[px::bind(&MyContext::vector_variable_new_from_array<Iterator>, _r1, _a, _b, _1, _2)]
|
||||||
);
|
);
|
||||||
new_variable_initializer_list =
|
new_variable_initializer_list =
|
||||||
conditional_expression(_r1)[px::bind(&MyContext::new_vector_variable_initializer_list_append<Iterator>, _val, _1)] >>
|
conditional_expression(_r1)[px::bind(&MyContext::initializer_list_append<Iterator>, _val, _1)] >>
|
||||||
*(lit(',') > conditional_expression(_r1)[px::bind(&MyContext::new_vector_variable_initializer_list_append<Iterator>, _val, _1)]);
|
*(lit(',') > conditional_expression(_r1)[px::bind(&MyContext::initializer_list_append<Iterator>, _val, _1)]);
|
||||||
|
|
||||||
struct FactorActions {
|
struct FactorActions {
|
||||||
static void set_start_pos(Iterator &start_pos, expr<Iterator> &out)
|
static void set_start_pos(Iterator &start_pos, expr<Iterator> &out)
|
||||||
|
Loading…
Reference in New Issue
Block a user