PlaceholderParser: added size() and empty() functions over vector variables.

This commit is contained in:
Vojtech Bubnik 2023-03-23 17:51:37 +01:00
parent 929a0eba2c
commit 9cb50e6586
2 changed files with 42 additions and 5 deletions

View File

@ -1427,6 +1427,30 @@ namespace client
list.emplace_back(std::move(expr)); list.emplace_back(std::move(expr));
} }
template <typename Iterator>
static void is_vector_empty(
const MyContext *ctx,
OptWithPos<Iterator> &opt,
expr<Iterator> &out)
{
if (opt.has_index() || ! opt.opt->is_vector())
ctx->throw_exception("parameter of empty() is not a vector variable", opt.it_range);
out.set_b(static_cast<const ConfigOptionVectorBase*>(opt.opt)->size() == 0);
out.it_range = opt.it_range;
}
template <typename Iterator>
static void vector_size(
const MyContext *ctx,
OptWithPos<Iterator> &opt,
expr<Iterator> &out)
{
if (opt.has_index() || ! opt.opt->is_vector())
ctx->throw_exception("parameter of size() is not a vector variable", opt.it_range);
out.set_i(int(static_cast<const ConfigOptionVectorBase*>(opt.opt)->size()));
out.it_range = opt.it_range;
}
// 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>
@ -1843,8 +1867,7 @@ namespace client
assignment_statement = assignment_statement =
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('(') > initializer_list(_r1) > ')') initializer_list(_r1)[px::bind(&MyContext::vector_variable_assign_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.
| eps(px::bind(&MyContext::is_vector_variable_reference<Iterator>, _a)) >> | eps(px::bind(&MyContext::is_vector_variable_reference<Iterator>, _a)) >>
@ -1859,8 +1882,7 @@ namespace client
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('(') > initializer_list(_r1) > ')') initializer_list(_r1)[px::bind(&MyContext::vector_variable_new_from_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.
| eps(px::bind(&MyContext::could_be_vector_variable_reference<Iterator>, _b)) >> | eps(px::bind(&MyContext::could_be_vector_variable_reference<Iterator>, _b)) >>
@ -1871,7 +1893,13 @@ namespace client
| (kw["repeat"] > "(" > additive_expression(_r1) > "," > conditional_expression(_r1) > ")") | (kw["repeat"] > "(" > additive_expression(_r1) > "," > conditional_expression(_r1) > ")")
[px::bind(&MyContext::vector_variable_new_from_array<Iterator>, _r1, _a, _b, _1, _2)] [px::bind(&MyContext::vector_variable_new_from_array<Iterator>, _r1, _a, _b, _1, _2)]
); );
initializer_list = *(lit(',') > conditional_expression(_r1)[px::bind(&MyContext::initializer_list_append<Iterator>, _val, _1)]); initializer_list = lit('(') >
( lit(')') |
( conditional_expression(_r1)[px::bind(&MyContext::initializer_list_append<Iterator>, _val, _1)] >
*(lit(',') > conditional_expression(_r1)[px::bind(&MyContext::initializer_list_append<Iterator>, _val, _1)]) >
lit(')')
)
);
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)
@ -1917,6 +1945,8 @@ namespace client
| (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"] > '(' > variable_reference(_r1) > ')') [px::bind(&MyContext::is_nil_test<Iterator>, _r1, _1, _val)] | (kw["is_nil"] > '(' > variable_reference(_r1) > ')') [px::bind(&MyContext::is_nil_test<Iterator>, _r1, _1, _val)]
| (kw["one_of"] > '(' > one_of(_r1) > ')') [ _val = _1 ] | (kw["one_of"] > '(' > one_of(_r1) > ')') [ _val = _1 ]
| (kw["empty"] > '(' > variable_reference(_r1) > ')') [px::bind(&MyContext::is_vector_empty<Iterator>, _r1, _1, _val)]
| (kw["size"] > '(' > variable_reference(_r1) > ')') [px::bind(&MyContext::vector_size<Iterator>, _r1, _1, _val)]
| (kw["interpolate_table"] > '(' > interpolate_table(_r1) > ')') [ _val = _1 ] | (kw["interpolate_table"] > '(' > interpolate_table(_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) ]
@ -1975,6 +2005,7 @@ namespace client
("and") ("and")
("digits") ("digits")
("zdigits") ("zdigits")
("empty")
("if") ("if")
("int") ("int")
("is_nil") ("is_nil")
@ -1994,6 +2025,7 @@ namespace client
("not") ("not")
("one_of") ("one_of")
("or") ("or")
("size")
("true"); ("true");
if (0) { if (0) {

View File

@ -222,4 +222,9 @@ SCENARIO("Placeholder parser variables", "[PlaceholderParser]") {
REQUIRE(parser.process("{local mybool = enable_dynamic_fan_speeds}{mybool = (false, true)}{mybool[1]}", 0, &config, nullptr, nullptr) == "true"); REQUIRE(parser.process("{local mybool = enable_dynamic_fan_speeds}{mybool = (false, true)}{mybool[1]}", 0, &config, nullptr, nullptr) == "true");
REQUIRE(parser.process("{local mybool = enable_dynamic_fan_speeds}{mybool = (false, false)}{mybool = enable_dynamic_fan_speeds}{mybool[0]}", 0, &config, nullptr, nullptr) == "true"); REQUIRE(parser.process("{local mybool = enable_dynamic_fan_speeds}{mybool = (false, false)}{mybool = enable_dynamic_fan_speeds}{mybool[0]}", 0, &config, nullptr, nullptr) == "true");
} }
SECTION("size() of a non-empty vector returns the right size") { REQUIRE(parser.process("{local myint = (0, 1, 2, 3)}{size(myint)}", 0, nullptr, nullptr, nullptr) == "4"); }
SECTION("size() of a an empty vector returns the right size") { REQUIRE(parser.process("{local myint = (0);myint=();size(myint)}", 0, nullptr, nullptr, nullptr) == "0"); }
SECTION("empty() of a non-empty vector returns false") { REQUIRE(parser.process("{local myint = (0, 1, 2, 3)}{empty(myint)}", 0, nullptr, nullptr, nullptr) == "false"); }
SECTION("empty() of a an empty vector returns true") { REQUIRE(parser.process("{local myint = (0);myint=();empty(myint)}", 0, nullptr, nullptr, nullptr) == "true"); }
} }