Fix custom var exists() function

Fix regression on legacy placeholder syntax
supermerill/SuperSlicer#2359
This commit is contained in:
remi durand 2022-02-10 23:17:42 +01:00 committed by supermerill
parent 34ff5c0304
commit f8180803da
4 changed files with 48 additions and 49 deletions

View File

@ -695,6 +695,7 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re
throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n"); throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
try { try {
m_placeholder_parser.reset();
m_placeholder_parser_failed_templates.clear(); m_placeholder_parser_failed_templates.clear();
this->_do_export(*print, file, thumbnail_cb); this->_do_export(*print, file, thumbnail_cb);
fflush(file); fflush(file);

View File

@ -730,7 +730,7 @@ namespace client
if (vector_opt->is_extruder_size()) { if (vector_opt->is_extruder_size()) {
if (raw_opt->type() == coFloats || raw_opt->type() == coInts || raw_opt->type() == coBools) if (raw_opt->type() == coFloats || raw_opt->type() == coInts || raw_opt->type() == coBools)
return vector_opt->getFloat(current_extruder_id); return vector_opt->getFloat(int(current_extruder_id));
if (raw_opt->type() == coFloatsOrPercents) { if (raw_opt->type() == coFloatsOrPercents) {
const ConfigOptionFloatsOrPercents* opt_fl_per = static_cast<const ConfigOptionFloatsOrPercents*>(raw_opt); const ConfigOptionFloatsOrPercents* opt_fl_per = static_cast<const ConfigOptionFloatsOrPercents*>(raw_opt);
if (!opt_fl_per->values[current_extruder_id].percent) if (!opt_fl_per->values[current_extruder_id].percent)
@ -856,8 +856,9 @@ namespace client
boost::iterator_range<Iterator>& opt_key, boost::iterator_range<Iterator>& opt_key,
Iterator& end_pos, Iterator& end_pos,
expr<Iterator>& out, expr<Iterator>& out,
ConfigOption* default_val = nullptr) std::unique_ptr<ConfigOption>&& default_val)
{ {
bool has_default_value = default_val.get() != nullptr;
t_config_option_key key = std::string(opt_key.begin(), opt_key.end()); t_config_option_key key = std::string(opt_key.begin(), opt_key.end());
const ConfigOption* opt = nullptr; const ConfigOption* opt = nullptr;
if (ctx->config_override != nullptr) if (ctx->config_override != nullptr)
@ -866,26 +867,18 @@ namespace client
opt = ctx->config->option(key); opt = ctx->config->option(key);
if (opt == nullptr && ctx->external_config != nullptr) if (opt == nullptr && ctx->external_config != nullptr)
opt = ctx->external_config->option(key); opt = ctx->external_config->option(key);
if (opt == nullptr) { if (opt == nullptr && (has_default_value || MyContext::checked_vars.find(key) == MyContext::checked_vars.end()) ) {
std::unique_ptr<ConfigOption> ppt; // set stub bool value only if a default() hasn't been called yet.
if(default_val == nullptr) if (!has_default_value) {
ppt = std::unique_ptr<ConfigOption>(new ConfigOptionBool(false)); default_val.reset(new ConfigOptionBool(false));
else
ppt = std::unique_ptr<ConfigOption>(default_val);
// set flag to say "it's a var that isn't here, please ignore it"
ppt->flags |= ConfigOption::FCO_PLACEHOLDER_TEMP;
if (MyContext::checked_vars.find(key) != MyContext::checked_vars.end()) {
if (default_val != nullptr) {
// erase previous value
MyContext::checked_vars[key] = std::move(ppt);
}
} else {
// put the var
MyContext::checked_vars.emplace(std::move(key), std::move(ppt));
} }
// set flag to say "it's a var that isn't here, please ignore it"
default_val->flags |= ConfigOption::FCO_PLACEHOLDER_TEMP;
MyContext::checked_vars[key] = std::move(default_val);
} }
//return // return (wanted for exists() but not for default())
//out = expr<Iterator>(opt != nullptr, out.it_range.begin(), end_pos); if(!has_default_value)
out = expr<Iterator>(opt != nullptr, out.it_range.begin(), end_pos);
} }
template <typename Iterator> template <typename Iterator>
@ -952,7 +945,7 @@ namespace client
case coInts: case coInts:
opt_def = print_config_def.get(opt_key); opt_def = print_config_def.get(opt_key);
if (opt_def->is_vector_extruder) { if (opt_def->is_vector_extruder) {
output.set_i((int)((ConfigOptionVectorBase*)opt.opt)->getFloat(ctx->current_extruder_id)); output.set_i(int(((ConfigOptionVectorBase*)opt.opt)->getFloat(int(ctx->current_extruder_id))));
break; break;
} else } else
ctx->throw_exception("Unknown scalar variable type", opt.it_range); ctx->throw_exception("Unknown scalar variable type", opt.it_range);
@ -960,7 +953,7 @@ namespace client
case coPercents: case coPercents:
vector_opt = static_cast<const ConfigOptionVectorBase*>(opt.opt); vector_opt = static_cast<const ConfigOptionVectorBase*>(opt.opt);
if (vector_opt->is_extruder_size()) { if (vector_opt->is_extruder_size()) {
output.set_d(((ConfigOptionVectorBase*)opt.opt)->getFloat(ctx->current_extruder_id)); output.set_d(((ConfigOptionVectorBase*)opt.opt)->getFloat(int(ctx->current_extruder_id)));
break; break;
} else } else
ctx->throw_exception("Unknown scalar variable type", opt.it_range); ctx->throw_exception("Unknown scalar variable type", opt.it_range);
@ -1301,13 +1294,11 @@ namespace client
"endif"; "endif";
*/ */
// Legacy variable expansion of the original Slic3r, in the form of [scalar_variable] or [vector_variable_index]. // Legacy variable expansion of the original Slic3r, in the form of [scalar_variable] or [vector_variable_index] or [vector_variable_[index_variable]].
// note: should use 'identifier' instead of 'raw[lexeme[*((utf8char - char_('\\') - char_(']')) | ('\\' > char_))]]'
// but it's that way to allow to ignore the legacy_variable_expansion is disabled, witout outputting an exception
legacy_variable_expansion = legacy_variable_expansion =
((raw[lexeme[*((utf8char - char_('\\') - char_(']')) | ('\\' > char_))]] >> &lit(']')) >> &lit(']')) (identifier >> &lit(']'))
[ px::bind(&MyContext::legacy_variable_expansion<Iterator>, _r1, _1, _val) ] [ px::bind(&MyContext::legacy_variable_expansion<Iterator>, _r1, _1, _val) ]
| ((raw[lexeme[*((utf8char - char_('\\') - char_(']')) | ('\\' > char_))]] >> &lit(']')) > lit('[') > (raw[lexeme[*((utf8char - char_('\\') - char_(']')) | ('\\' > char_))]] >> &lit(']')) > ']') | (identifier > lit('[') > identifier > ']')
[ px::bind(&MyContext::legacy_variable_expansion2<Iterator>, _r1, _1, _2, _val) ] [ px::bind(&MyContext::legacy_variable_expansion2<Iterator>, _r1, _1, _2, _val) ]
; ;
legacy_variable_expansion.name("legacy_variable_expansion"); legacy_variable_expansion.name("legacy_variable_expansion");
@ -1392,17 +1383,17 @@ namespace client
{ out = value.unary_integer(out.it_range.begin()); } { out = value.unary_integer(out.it_range.begin()); }
//function for default keyword //function for default keyword
static void default_bool_(bool &value, const MyContext* ctx, boost::iterator_range<Iterator>& opt_key, Iterator& end_pos, expr<Iterator>& out) static void default_bool_(bool &value, const MyContext* ctx, boost::iterator_range<Iterator>& opt_key, Iterator& end_pos, expr<Iterator>& out)
{ MyContext::check_variable<Iterator>(ctx, opt_key, end_pos, out, new ConfigOptionBool(value)); } { MyContext::check_variable<Iterator>(ctx, opt_key, end_pos, out, std::make_unique<ConfigOptionBool>(value)); }
static void default_int_(int &value, const MyContext* ctx, boost::iterator_range<Iterator>& opt_key, Iterator& end_pos, expr<Iterator>& out) static void default_int_(int &value, const MyContext* ctx, boost::iterator_range<Iterator>& opt_key, Iterator& end_pos, expr<Iterator>& out)
{ MyContext::check_variable<Iterator>(ctx, opt_key, end_pos, out, new ConfigOptionInt(value)); } { MyContext::check_variable<Iterator>(ctx, opt_key, end_pos, out, std::make_unique<ConfigOptionInt>(value)); }
static void default_double_(double &value, const MyContext* ctx, boost::iterator_range<Iterator>& opt_key, Iterator& end_pos, expr<Iterator>& out) static void default_double_(double &value, const MyContext* ctx, boost::iterator_range<Iterator>& opt_key, Iterator& end_pos, expr<Iterator>& out)
{ MyContext::check_variable<Iterator>(ctx, opt_key, end_pos, out, new ConfigOptionFloat(value)); } { MyContext::check_variable<Iterator>(ctx, opt_key, end_pos, out, std::make_unique<ConfigOptionFloat>(value)); }
static void default_string_(boost::iterator_range<Iterator>& it_range, const MyContext* ctx, boost::iterator_range<Iterator>& opt_key, Iterator& end_pos, expr<Iterator>& out) static void default_string_(boost::iterator_range<Iterator>& it_range, const MyContext* ctx, boost::iterator_range<Iterator>& opt_key, Iterator& end_pos, expr<Iterator>& out)
{ MyContext::check_variable<Iterator>(ctx, opt_key, end_pos, out, new ConfigOptionString(std::string(it_range.begin() + 1, it_range.end() - 1))); } { MyContext::check_variable<Iterator>(ctx, opt_key, end_pos, out, std::make_unique<ConfigOptionString>(std::string(it_range.begin() + 1, it_range.end() - 1))); }
static void exists_(const MyContext* ctx, boost::iterator_range<Iterator>& opt_key, Iterator& end_pos, expr<Iterator>& out)
{ MyContext::check_variable<Iterator>(ctx, opt_key, end_pos, out, std::unique_ptr<ConfigOption>{nullptr}); }
static void set_ignore_legacy_(bool& value) static void set_ignore_legacy_(bool& value)
{ { MyContext::ignore_legacy = value; }
MyContext::ignore_legacy = value;
}
}; };
unary_expression = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> ( unary_expression = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> (
scalar_variable_reference(_r1) [ _val = _1 ] scalar_variable_reference(_r1) [ _val = _1 ]
@ -1417,7 +1408,7 @@ namespace client
| (kw["random"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')') | (kw["random"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')')
[ px::bind(&MyContext::random<Iterator>, _r1, _val, _2) ] [ px::bind(&MyContext::random<Iterator>, _r1, _val, _2) ]
| (kw["int"] > '(' > unary_expression(_r1) > ')') [ px::bind(&FactorActions::to_int, _1, _val) ] | (kw["int"] > '(' > unary_expression(_r1) > ')') [ px::bind(&FactorActions::to_int, _1, _val) ]
| (kw["exists"] > '(' > identifier > ')' > iter_pos) [ px::bind(&MyContext::check_variable<Iterator>, _r1, _1, _2, _val, nullptr) ] | (kw["exists"] > '(' > identifier > ')' > iter_pos) [ px::bind(&FactorActions::exists_, _r1, _1, _2, _val) ]
| (kw["default_double"] > '(' > identifier > ',' > strict_double > ')' > iter_pos) | (kw["default_double"] > '(' > identifier > ',' > strict_double > ')' > iter_pos)
[px::bind(&FactorActions::default_double_, _2, _r1, _1, _3, _val)] [px::bind(&FactorActions::default_double_, _2, _r1, _1, _3, _val)]
| (kw["default_int"] > '(' > identifier > ',' > int_ > ')' > iter_pos) | (kw["default_int"] > '(' > identifier > ',' > int_ > ')' > iter_pos)
@ -1593,7 +1584,7 @@ bool PlaceholderParser::evaluate_boolean_expression(const std::string &templ, co
} }
void PlaceholderParser::append_custom_variables(std::map<std::string, std::vector<std::string>> name2var_array, int nb_extruders) { void PlaceholderParser::append_custom_variables(std::map<std::string, std::vector<std::string>> name2var_array, uint16_t nb_extruders) {
bool is_array = nb_extruders > 0; bool is_array = nb_extruders > 0;
if (!is_array) nb_extruders = 1; if (!is_array) nb_extruders = 1;
@ -1606,7 +1597,7 @@ void PlaceholderParser::append_custom_variables(std::map<std::string, std::vecto
const std::vector<std::string>& values = entry.second; const std::vector<std::string>& values = entry.second;
//check if all values are empty //check if all values are empty
bool is_not_string = false; bool is_not_string = false;
for (int extruder_id = 0; extruder_id < nb_extruders; ++extruder_id) { for (uint16_t extruder_id = 0; extruder_id < nb_extruders; ++extruder_id) {
if (!values[extruder_id].empty()) { if (!values[extruder_id].empty()) {
is_not_string = true; is_not_string = true;
break; break;
@ -1616,7 +1607,7 @@ void PlaceholderParser::append_custom_variables(std::map<std::string, std::vecto
//check if all values are strings //check if all values are strings
if (is_not_string) { if (is_not_string) {
is_not_string = false; is_not_string = false;
for (int extruder_id = 0; extruder_id < nb_extruders; ++extruder_id) { for (uint16_t extruder_id = 0; extruder_id < nb_extruders; ++extruder_id) {
if (!values[extruder_id].empty()) { if (!values[extruder_id].empty()) {
if (values[extruder_id].front() != '\"' && values[extruder_id].back() != '\"') { if (values[extruder_id].front() != '\"' && values[extruder_id].back() != '\"') {
is_not_string = true; is_not_string = true;
@ -1632,7 +1623,7 @@ void PlaceholderParser::append_custom_variables(std::map<std::string, std::vecto
bool is_not_bool = !is_not_string; bool is_not_bool = !is_not_string;
std::vector<unsigned char> bool_values; std::vector<unsigned char> bool_values;
if (!is_not_bool) { if (!is_not_bool) {
for (int extruder_id = 0; extruder_id < nb_extruders; ++extruder_id) { for (uint16_t extruder_id = 0; extruder_id < nb_extruders; ++extruder_id) {
if (!values[extruder_id].empty()) { if (!values[extruder_id].empty()) {
if (boost::algorithm::to_lower_copy(values[extruder_id]) == "true") { if (boost::algorithm::to_lower_copy(values[extruder_id]) == "true") {
bool_values.push_back(true); bool_values.push_back(true);
@ -1652,7 +1643,7 @@ void PlaceholderParser::append_custom_variables(std::map<std::string, std::vecto
std::vector<double> double_values; std::vector<double> double_values;
//SLIC3R_REGEX_NAMESPACE::regex("\\s*[+-]?([0-9]+\\.[0-9]*([Ee][+-]?[0-9]+)?|\\.[0-9]+([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)"); //SLIC3R_REGEX_NAMESPACE::regex("\\s*[+-]?([0-9]+\\.[0-9]*([Ee][+-]?[0-9]+)?|\\.[0-9]+([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)");
if (!is_not_numeric) { if (!is_not_numeric) {
for (int extruder_id = 0; extruder_id < nb_extruders; ++extruder_id) { for (uint16_t extruder_id = 0; extruder_id < nb_extruders; ++extruder_id) {
if (!values[extruder_id].empty()) { if (!values[extruder_id].empty()) {
try { try {
double_values.push_back(boost::lexical_cast<float>(values[extruder_id])); double_values.push_back(boost::lexical_cast<float>(values[extruder_id]));
@ -1717,8 +1708,14 @@ void PlaceholderParser::append_custom_variables(std::map<std::string, std::vecto
} }
void PlaceholderParser::parse_custom_variables(const ConfigOptionString& custom_variables) { void PlaceholderParser::reset()
{
client::MyContext::checked_vars.clear();
m_config.clear();
}
void PlaceholderParser::parse_custom_variables(const ConfigOptionString& custom_variables)
{
std::map<std::string, std::vector<std::string>> name2var_array; std::map<std::string, std::vector<std::string>> name2var_array;
std::string raw_text = custom_variables.value; std::string raw_text = custom_variables.value;
@ -1726,7 +1723,7 @@ void PlaceholderParser::parse_custom_variables(const ConfigOptionString& custom_
std::vector<std::string> lines; std::vector<std::string> lines;
boost::algorithm::split(lines, raw_text, boost::is_any_of("\n")); boost::algorithm::split(lines, raw_text, boost::is_any_of("\n"));
for (const std::string& line : lines) { for (const std::string& line : lines) {
int equal_pos = line.find_first_of('='); size_t equal_pos = line.find_first_of('=');
if (equal_pos != std::string::npos) { if (equal_pos != std::string::npos) {
std::string name = line.substr(0, equal_pos); std::string name = line.substr(0, equal_pos);
std::string value = line.substr(equal_pos + 1); std::string value = line.substr(equal_pos + 1);
@ -1754,7 +1751,7 @@ void PlaceholderParser::parse_custom_variables(const ConfigOptionStrings& filame
std::vector<std::string> lines; std::vector<std::string> lines;
boost::algorithm::split(lines, raw_text, boost::is_any_of("\n")); boost::algorithm::split(lines, raw_text, boost::is_any_of("\n"));
for (const std::string& line : lines) { for (const std::string& line : lines) {
int equal_pos = line.find_first_of('='); size_t equal_pos = line.find_first_of('=');
if (equal_pos != std::string::npos) { if (equal_pos != std::string::npos) {
std::string name = line.substr(0, equal_pos); std::string name = line.substr(0, equal_pos);
std::string value = line.substr(equal_pos + 1); std::string value = line.substr(equal_pos + 1);
@ -1768,8 +1765,7 @@ void PlaceholderParser::parse_custom_variables(const ConfigOptionStrings& filame
} }
} }
} }
append_custom_variables(name2var_array, filament_custom_variables.values.size()); append_custom_variables(name2var_array, uint16_t(filament_custom_variables.values.size()));
} }
} }

View File

@ -66,9 +66,11 @@ public:
void parse_custom_variables(const ConfigOptionString& custom_variables); void parse_custom_variables(const ConfigOptionString& custom_variables);
void parse_custom_variables(const ConfigOptionStrings& filament_custom_variables); void parse_custom_variables(const ConfigOptionStrings& filament_custom_variables);
//remove custom vars and stored config
void reset();
private: private:
void append_custom_variables(std::map<std::string, std::vector<std::string>> name2var_array, int nb_extruders); void append_custom_variables(std::map<std::string, std::vector<std::string>> name2var_array, uint16_t nb_extruders);
// config has a higher priority than external_config when looking up a symbol. // config has a higher priority than external_config when looking up a symbol.
DynamicConfig m_config; DynamicConfig m_config;

View File

@ -19,7 +19,7 @@ uint16_t PrintRegion::extruder(FlowRole role, const PrintObject& object) const
extruder = object.config().support_material_interface_extruder; extruder = object.config().support_material_interface_extruder;
else else
throw Slic3r::InvalidArgument("Unknown role"); throw Slic3r::InvalidArgument("Unknown role");
return extruder; return (uint16_t)extruder;
} }
Flow PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) const Flow PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) const
@ -56,7 +56,7 @@ Flow PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool fir
// Here this->extruder(role) - 1 may underflow to MAX_INT, but then the get_at() will follback to zero'th element, so everything is all right. // Here this->extruder(role) - 1 may underflow to MAX_INT, but then the get_at() will follback to zero'th element, so everything is all right.
double nozzle_diameter = m_print->config().nozzle_diameter.get_at(this->extruder(role, object) - 1); double nozzle_diameter = m_print->config().nozzle_diameter.get_at(this->extruder(role, object) - 1);
return Flow::new_from_config_width(role, config_width, (float)nozzle_diameter, (float)layer_height, return Flow::new_from_config_width(role, config_width, (float)nozzle_diameter, (float)layer_height,
this->config().get_computed_value("filament_max_overlap", this->extruder(role, object) - 1), (float)this->config().get_computed_value("filament_max_overlap", this->extruder(role, object) - 1),
bridge ? (float)m_config.bridge_flow_ratio.get_abs_value(1) : 0.0f); bridge ? (float)m_config.bridge_flow_ratio.get_abs_value(1) : 0.0f);
} }
@ -91,7 +91,7 @@ float PrintRegion::width(FlowRole role, bool first_layer, const PrintObject& ob
double nozzle_diameter = m_print->config().nozzle_diameter.get_at(this->extruder(role, object) - 1); double nozzle_diameter = m_print->config().nozzle_diameter.get_at(this->extruder(role, object) - 1);
if (config_width->value <= 0.) { if (config_width->value <= 0.) {
// If user left option to 0, calculate a sane default width. // If user left option to 0, calculate a sane default width.
return Flow::auto_extrusion_width(role, nozzle_diameter); return float(Flow::auto_extrusion_width(role, nozzle_diameter));
} else { } else {
// If user set a manual value, use it. // If user set a manual value, use it.
return float(config_width->get_abs_value(nozzle_diameter)); return float(config_width->get_abs_value(nozzle_diameter));