PlaceholderPareser: new is_null() function to test whether a variable
has a "nil" value or not. Implements SPE-1539
This commit is contained in:
parent
2959de40ae
commit
55533397f9
2 changed files with 52 additions and 0 deletions
|
@ -875,6 +875,38 @@ namespace client
|
||||||
output.it_range = boost::iterator_range<Iterator>(opt.it_range.begin(), it_end);
|
output.it_range = boost::iterator_range<Iterator>(opt.it_range.begin(), it_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return a boolean value, true if the scalar variable referenced by "opt" is nullable and it has a nil value.
|
||||||
|
template <typename Iterator>
|
||||||
|
static void is_nil_test_scalar(
|
||||||
|
const MyContext *ctx,
|
||||||
|
OptWithPos<Iterator> &opt,
|
||||||
|
expr<Iterator> &output)
|
||||||
|
{
|
||||||
|
if (opt.opt->is_vector())
|
||||||
|
ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range);
|
||||||
|
output.set_b(opt.opt->is_nil());
|
||||||
|
output.it_range = opt.it_range;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a boolean value, true if an element of a vector variable referenced by "opt[index]" is nullable and it has a nil value.
|
||||||
|
template <typename Iterator>
|
||||||
|
static void is_nil_test_vector(
|
||||||
|
const MyContext *ctx,
|
||||||
|
OptWithPos<Iterator> &opt,
|
||||||
|
int &index,
|
||||||
|
Iterator it_end,
|
||||||
|
expr<Iterator> &output)
|
||||||
|
{
|
||||||
|
if (opt.opt->is_scalar())
|
||||||
|
ctx->throw_exception("Referencing a scalar variable when vector 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 = (index < 0) ? 0 : (index >= int(vec->size())) ? 0 : size_t(index);
|
||||||
|
output.set_b(static_cast<const ConfigOptionVectorBase*>(opt.opt)->is_nil(idx));
|
||||||
|
output.it_range = boost::iterator_range<Iterator>(opt.it_range.begin(), it_end);
|
||||||
|
}
|
||||||
|
|
||||||
// Verify that the expression returns an integer, which may be used
|
// Verify that the expression returns an integer, which may be used
|
||||||
// to address a vector.
|
// to address a vector.
|
||||||
template <typename Iterator>
|
template <typename Iterator>
|
||||||
|
@ -973,6 +1005,7 @@ namespace client
|
||||||
{ "unary_expression", "Expecting an expression." },
|
{ "unary_expression", "Expecting an expression." },
|
||||||
{ "optional_parameter", "Expecting a closing brace or an optional parameter." },
|
{ "optional_parameter", "Expecting a closing brace or an optional parameter." },
|
||||||
{ "scalar_variable_reference", "Expecting a scalar variable reference."},
|
{ "scalar_variable_reference", "Expecting a scalar variable reference."},
|
||||||
|
{ "is_nil_test", "Expecting a scalar variable reference."},
|
||||||
{ "variable_reference", "Expecting a variable reference."},
|
{ "variable_reference", "Expecting a variable reference."},
|
||||||
{ "regular_expression", "Expecting a regular expression."}
|
{ "regular_expression", "Expecting a regular expression."}
|
||||||
};
|
};
|
||||||
|
@ -1259,6 +1292,7 @@ namespace client
|
||||||
[ px::bind(&expr<Iterator>::template digits<true>, _val, _2, _3) ]
|
[ px::bind(&expr<Iterator>::template digits<true>, _val, _2, _3) ]
|
||||||
| (kw["int"] > '(' > conditional_expression(_r1) > ')') [ px::bind(&FactorActions::to_int, _1, _val) ]
|
| (kw["int"] > '(' > conditional_expression(_r1) > ')') [ px::bind(&FactorActions::to_int, _1, _val) ]
|
||||||
| (kw["round"] > '(' > conditional_expression(_r1) > ')') [ px::bind(&FactorActions::round, _1, _val) ]
|
| (kw["round"] > '(' > conditional_expression(_r1) > ')') [ px::bind(&FactorActions::round, _1, _val) ]
|
||||||
|
| (kw["is_nil"] > '(' > is_nil_test(_r1) > ')') [_val = _1]
|
||||||
| (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _1, _2, _val) ]
|
| (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _1, _2, _val) ]
|
||||||
| (int_ > iter_pos) [ px::bind(&FactorActions::int_, _1, _2, _val) ]
|
| (int_ > iter_pos) [ px::bind(&FactorActions::int_, _1, _2, _val) ]
|
||||||
| (kw[bool_] > iter_pos) [ px::bind(&FactorActions::bool_, _1, _2, _val) ]
|
| (kw[bool_] > iter_pos) [ px::bind(&FactorActions::bool_, _1, _2, _val) ]
|
||||||
|
@ -1286,6 +1320,15 @@ namespace client
|
||||||
[ px::bind(&MyContext::resolve_variable<Iterator>, _r1, _1, _val) ];
|
[ px::bind(&MyContext::resolve_variable<Iterator>, _r1, _1, _val) ];
|
||||||
variable_reference.name("variable reference");
|
variable_reference.name("variable reference");
|
||||||
|
|
||||||
|
is_nil_test =
|
||||||
|
variable_reference(_r1)[_a=_1] >>
|
||||||
|
(
|
||||||
|
('[' > additive_expression(_r1)[px::bind(&MyContext::evaluate_index<Iterator>, _1, _b)] > ']' >
|
||||||
|
iter_pos[px::bind(&MyContext::is_nil_test_vector<Iterator>, _r1, _a, _b, _1, _val)])
|
||||||
|
| eps[px::bind(&MyContext::is_nil_test_scalar<Iterator>, _r1, _a, _val)]
|
||||||
|
);
|
||||||
|
is_nil_test.name("is_nil test");
|
||||||
|
|
||||||
regular_expression = raw[lexeme['/' > *((utf8char - char_('\\') - char_('/')) | ('\\' > char_)) > '/']];
|
regular_expression = raw[lexeme['/' > *((utf8char - char_('\\') - char_('/')) | ('\\' > char_)) > '/']];
|
||||||
regular_expression.name("regular_expression");
|
regular_expression.name("regular_expression");
|
||||||
|
|
||||||
|
@ -1295,6 +1338,7 @@ namespace client
|
||||||
("zdigits")
|
("zdigits")
|
||||||
("if")
|
("if")
|
||||||
("int")
|
("int")
|
||||||
|
("is_nil")
|
||||||
//("inf")
|
//("inf")
|
||||||
("else")
|
("else")
|
||||||
("elsif")
|
("elsif")
|
||||||
|
@ -1329,6 +1373,7 @@ namespace client
|
||||||
debug(optional_parameter);
|
debug(optional_parameter);
|
||||||
debug(scalar_variable_reference);
|
debug(scalar_variable_reference);
|
||||||
debug(variable_reference);
|
debug(variable_reference);
|
||||||
|
debug(is_nil_test);
|
||||||
debug(regular_expression);
|
debug(regular_expression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1374,6 +1419,8 @@ namespace client
|
||||||
qi::rule<Iterator, expr<Iterator>(const MyContext*), qi::locals<OptWithPos<Iterator>, int>, spirit_encoding::space_type> scalar_variable_reference;
|
qi::rule<Iterator, expr<Iterator>(const MyContext*), qi::locals<OptWithPos<Iterator>, int>, spirit_encoding::space_type> scalar_variable_reference;
|
||||||
// Rule to translate an identifier to a ConfigOption, or to fail.
|
// Rule to translate an identifier to a ConfigOption, or to fail.
|
||||||
qi::rule<Iterator, OptWithPos<Iterator>(const MyContext*), spirit_encoding::space_type> variable_reference;
|
qi::rule<Iterator, OptWithPos<Iterator>(const MyContext*), spirit_encoding::space_type> variable_reference;
|
||||||
|
// Evaluating whether a nullable variable is nil.
|
||||||
|
qi::rule<Iterator, expr<Iterator>(const MyContext*), qi::locals<OptWithPos<Iterator>, int>, spirit_encoding::space_type> is_nil_test;
|
||||||
|
|
||||||
qi::rule<Iterator, std::string(const MyContext*), qi::locals<bool, bool>, spirit_encoding::space_type> if_else_output;
|
qi::rule<Iterator, std::string(const MyContext*), qi::locals<bool, bool>, spirit_encoding::space_type> if_else_output;
|
||||||
// qi::rule<Iterator, std::string(const MyContext*), qi::locals<expr<Iterator>, bool, std::string>, spirit_encoding::space_type> switch_output;
|
// qi::rule<Iterator, std::string(const MyContext*), qi::locals<expr<Iterator>, bool, std::string>, spirit_encoding::space_type> switch_output;
|
||||||
|
|
|
@ -24,6 +24,8 @@ SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") {
|
||||||
// a percent to what.
|
// a percent to what.
|
||||||
config.option<ConfigOptionFloatOrPercent>("first_layer_speed")->value = 50.;
|
config.option<ConfigOptionFloatOrPercent>("first_layer_speed")->value = 50.;
|
||||||
config.option<ConfigOptionFloatOrPercent>("first_layer_speed")->percent = true;
|
config.option<ConfigOptionFloatOrPercent>("first_layer_speed")->percent = true;
|
||||||
|
ConfigOptionFloatsNullable *opt_filament_retract_length = config.option<ConfigOptionFloatsNullable>("filament_retract_length", true);
|
||||||
|
opt_filament_retract_length->values = { 5., ConfigOptionFloatsNullable::nil_value(), 3. };
|
||||||
|
|
||||||
parser.apply_config(config);
|
parser.apply_config(config);
|
||||||
parser.set("foo", 0);
|
parser.set("foo", 0);
|
||||||
|
@ -33,6 +35,9 @@ SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") {
|
||||||
SECTION("nested config options (legacy syntax)") { REQUIRE(parser.process("[temperature_[foo]]") == "357"); }
|
SECTION("nested config options (legacy syntax)") { REQUIRE(parser.process("[temperature_[foo]]") == "357"); }
|
||||||
SECTION("array reference") { REQUIRE(parser.process("{temperature[foo]}") == "357"); }
|
SECTION("array reference") { REQUIRE(parser.process("{temperature[foo]}") == "357"); }
|
||||||
SECTION("whitespaces and newlines are maintained") { REQUIRE(parser.process("test [ temperature_ [foo] ] \n hu") == "test 357 \n hu"); }
|
SECTION("whitespaces and newlines are maintained") { REQUIRE(parser.process("test [ temperature_ [foo] ] \n hu") == "test 357 \n hu"); }
|
||||||
|
SECTION("nullable is not null") { REQUIRE(parser.process("{is_nil(filament_retract_length[0])}") == "false"); }
|
||||||
|
SECTION("nullable is null") { REQUIRE(parser.process("{is_nil(filament_retract_length[1])}") == "true"); }
|
||||||
|
SECTION("nullable is not null 2") { REQUIRE(parser.process("{is_nil(filament_retract_length[2])}") == "false"); }
|
||||||
|
|
||||||
// Test the math expressions.
|
// Test the math expressions.
|
||||||
SECTION("math: 2*3") { REQUIRE(parser.process("{2*3}") == "6"); }
|
SECTION("math: 2*3") { REQUIRE(parser.process("{2*3}") == "6"); }
|
||||||
|
|
Loading…
Reference in a new issue