Implemented <,>,<=,>=,or,and,||,&& operators.
This commit is contained in:
parent
6b81f43206
commit
a402b1b83d
5 changed files with 178 additions and 58 deletions
|
@ -1,4 +1,4 @@
|
||||||
use Test::More tests => 55;
|
use Test::More tests => 71;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
@ -47,9 +47,13 @@ use Slic3r::Test;
|
||||||
|
|
||||||
{
|
{
|
||||||
my $parser = Slic3r::GCode::PlaceholderParser->new;
|
my $parser = Slic3r::GCode::PlaceholderParser->new;
|
||||||
$parser->apply_config(my $config = Slic3r::Config::new_from_defaults);
|
my $config = Slic3r::Config::new_from_defaults;
|
||||||
|
$config->set('printer_notes', ' PRINTER_VENDOR_PRUSA3D PRINTER_MODEL_MK2 ');
|
||||||
|
$config->set('nozzle_diameter', [0.6, 0.6, 0.6, 0.6]);
|
||||||
|
$parser->apply_config($config);
|
||||||
$parser->set('foo' => 0);
|
$parser->set('foo' => 0);
|
||||||
$parser->set('bar' => 2);
|
$parser->set('bar' => 2);
|
||||||
|
$parser->set('num_extruders' => 4);
|
||||||
is $parser->process('[temperature_[foo]]'),
|
is $parser->process('[temperature_[foo]]'),
|
||||||
$config->temperature->[0],
|
$config->temperature->[0],
|
||||||
"nested config options (legacy syntax)";
|
"nested config options (legacy syntax)";
|
||||||
|
@ -75,6 +79,24 @@ use Slic3r::Test;
|
||||||
is $parser->evaluate_boolean_expression('"has some PATTERN embedded" =~ /.*PTRN.*/'), 0, 'boolean expression parser: regex does not match';
|
is $parser->evaluate_boolean_expression('"has some PATTERN embedded" =~ /.*PTRN.*/'), 0, 'boolean expression parser: regex does not match';
|
||||||
is $parser->evaluate_boolean_expression('foo + 2 == bar'), 1, 'boolean expression parser: accessing variables, equal';
|
is $parser->evaluate_boolean_expression('foo + 2 == bar'), 1, 'boolean expression parser: accessing variables, equal';
|
||||||
is $parser->evaluate_boolean_expression('foo + 3 == bar'), 0, 'boolean expression parser: accessing variables, not equal';
|
is $parser->evaluate_boolean_expression('foo + 3 == bar'), 0, 'boolean expression parser: accessing variables, not equal';
|
||||||
|
|
||||||
|
is $parser->evaluate_boolean_expression('(12 == 12) and (13 != 14)'), 1, 'boolean expression parser: (12 == 12) and (13 != 14)';
|
||||||
|
is $parser->evaluate_boolean_expression('(12 == 12) && (13 != 14)'), 1, 'boolean expression parser: (12 == 12) && (13 != 14)';
|
||||||
|
is $parser->evaluate_boolean_expression('(12 == 12) or (13 == 14)'), 1, 'boolean expression parser: (12 == 12) or (13 == 14)';
|
||||||
|
is $parser->evaluate_boolean_expression('(12 == 12) || (13 == 14)'), 1, 'boolean expression parser: (12 == 12) || (13 == 14)';
|
||||||
|
is $parser->evaluate_boolean_expression('(12 == 12) and not (13 == 14)'), 1, 'boolean expression parser: (12 == 12) and not (13 == 14)';
|
||||||
|
is $parser->evaluate_boolean_expression('(12 == 12) ? (1 - 1 == 0) : (2 * 2 == 3)'), 1, 'boolean expression parser: ternary true';
|
||||||
|
is $parser->evaluate_boolean_expression('(12 == 21/2) ? (1 - 1 == 0) : (2 * 2 == 3)'), 0, 'boolean expression parser: ternary false';
|
||||||
|
is $parser->evaluate_boolean_expression('(12 == 13) ? (1 - 1 == 3) : (2 * 2 == 4)"'), 1, 'boolean expression parser: ternary false';
|
||||||
|
is $parser->evaluate_boolean_expression('(12 == 2 * 6) ? (1 - 1 == 3) : (2 * 2 == 4)"'), 0, 'boolean expression parser: ternary true';
|
||||||
|
is $parser->evaluate_boolean_expression('12 < 3'), 0, 'boolean expression parser: lower than - false';
|
||||||
|
is $parser->evaluate_boolean_expression('12 < 22'), 1, 'boolean expression parser: lower than - true';
|
||||||
|
is $parser->evaluate_boolean_expression('12 > 3'), 1, 'boolean expression parser: lower than - true';
|
||||||
|
is $parser->evaluate_boolean_expression('12 > 22'), 0, 'boolean expression parser: lower than - false';
|
||||||
|
|
||||||
|
is $parser->evaluate_boolean_expression('printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 and num_extruders>1'), 1, 'complex expression';
|
||||||
|
is $parser->evaluate_boolean_expression('printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.6 and num_extruders>1)'), 1, 'complex expression2';
|
||||||
|
is $parser->evaluate_boolean_expression('printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.3 and num_extruders>1)'), 0, 'complex expression3';
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -369,29 +369,50 @@ namespace client
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is lhs==rhs? Store the result into lhs.
|
// Is lhs==rhs? Store the result into lhs.
|
||||||
static void compare_op(expr &lhs, expr &rhs, char op)
|
static void compare_op(expr &lhs, expr &rhs, char op, bool invert)
|
||||||
{
|
{
|
||||||
bool value = false;
|
bool value = false;
|
||||||
if ((lhs.type == TYPE_INT || lhs.type == TYPE_DOUBLE) &&
|
if ((lhs.type == TYPE_INT || lhs.type == TYPE_DOUBLE) &&
|
||||||
(rhs.type == TYPE_INT || rhs.type == TYPE_DOUBLE)) {
|
(rhs.type == TYPE_INT || rhs.type == TYPE_DOUBLE)) {
|
||||||
// Both types are numeric.
|
// Both types are numeric.
|
||||||
value = (lhs.type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) ?
|
switch (op) {
|
||||||
(lhs.as_d() == rhs.as_d()) : (lhs.i() == rhs.i());
|
case '=':
|
||||||
|
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) ?
|
||||||
|
(lhs.as_d() < rhs.as_d()) : (lhs.i() < rhs.i());
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
default:
|
||||||
|
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.
|
// 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();
|
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.
|
// One type is string, the other could be converted to string.
|
||||||
value = lhs.to_string() == rhs.to_string();
|
value = (op == '=') ? (lhs.to_string() == rhs.to_string()) :
|
||||||
|
(op == '<') ? (lhs.to_string() < rhs.to_string()) : (lhs.to_string() > rhs.to_string());
|
||||||
} else {
|
} else {
|
||||||
boost::throw_exception(qi::expectation_failure<Iterator>(
|
boost::throw_exception(qi::expectation_failure<Iterator>(
|
||||||
lhs.it_range.begin(), rhs.it_range.end(), spirit::info("*Cannot compare the types.")));
|
lhs.it_range.begin(), rhs.it_range.end(), spirit::info("*Cannot compare the types.")));
|
||||||
}
|
}
|
||||||
lhs.type = TYPE_BOOL;
|
lhs.type = TYPE_BOOL;
|
||||||
lhs.data.b = (op == '=') ? value : !value;
|
lhs.data.b = invert ? ! value : value;
|
||||||
}
|
}
|
||||||
static void equal (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '='); }
|
static void equal (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '=', false); }
|
||||||
static void not_equal(expr &lhs, expr &rhs) { compare_op(lhs, rhs, '!'); }
|
static void not_equal(expr &lhs, expr &rhs) { compare_op(lhs, rhs, '=', true ); }
|
||||||
|
static void lower (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '<', false); }
|
||||||
|
static void greater (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '>', false); }
|
||||||
|
static void leq (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '>', true ); }
|
||||||
|
static void geq (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '<', true ); }
|
||||||
|
|
||||||
static void regex_op(expr &lhs, boost::iterator_range<Iterator> &rhs, char op)
|
static void regex_op(expr &lhs, boost::iterator_range<Iterator> &rhs, char op)
|
||||||
{
|
{
|
||||||
|
@ -421,6 +442,32 @@ namespace client
|
||||||
static void regex_matches (expr &lhs, boost::iterator_range<Iterator> &rhs) { return regex_op(lhs, rhs, '='); }
|
static void regex_matches (expr &lhs, boost::iterator_range<Iterator> &rhs) { return regex_op(lhs, rhs, '='); }
|
||||||
static void regex_doesnt_match(expr &lhs, boost::iterator_range<Iterator> &rhs) { return regex_op(lhs, rhs, '!'); }
|
static void regex_doesnt_match(expr &lhs, boost::iterator_range<Iterator> &rhs) { return regex_op(lhs, rhs, '!'); }
|
||||||
|
|
||||||
|
static void logical_op(expr &lhs, expr &rhs, char op)
|
||||||
|
{
|
||||||
|
bool value = false;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
bool value = false;
|
||||||
|
if (lhs.type != TYPE_BOOL)
|
||||||
|
lhs.throw_exception("Not a boolean expression");
|
||||||
|
if (lhs.b())
|
||||||
|
lhs = std::move(rhs1);
|
||||||
|
else
|
||||||
|
lhs = std::move(rhs2);
|
||||||
|
}
|
||||||
|
|
||||||
static void set_if(bool &cond, bool ¬_yet_consumed, std::string &str_in, std::string &str_out)
|
static void set_if(bool &cond, bool ¬_yet_consumed, std::string &str_in, std::string &str_out)
|
||||||
{
|
{
|
||||||
if (cond && not_yet_consumed) {
|
if (cond && not_yet_consumed) {
|
||||||
|
@ -789,7 +836,7 @@ namespace client
|
||||||
// could serve both purposes.
|
// could serve both purposes.
|
||||||
start = eps[px::bind(&MyContext::evaluate_full_macro, _r1, _a)] >
|
start = eps[px::bind(&MyContext::evaluate_full_macro, _r1, _a)] >
|
||||||
( eps(_a==true) > text_block(_r1) [_val=_1]
|
( eps(_a==true) > text_block(_r1) [_val=_1]
|
||||||
| bool_expr(_r1) [ px::bind(&expr<Iterator>::evaluate_boolean_to_string, _1, _val) ]
|
| conditional_expression(_r1) [ px::bind(&expr<Iterator>::evaluate_boolean_to_string, _1, _val) ]
|
||||||
);
|
);
|
||||||
start.name("start");
|
start.name("start");
|
||||||
qi::on_error<qi::fail>(start, px::bind(&MyContext::process_error_message<Iterator>, _r1, _4, _1, _2, _3));
|
qi::on_error<qi::fail>(start, px::bind(&MyContext::process_error_message<Iterator>, _r1, _4, _1, _2, _3));
|
||||||
|
@ -852,34 +899,54 @@ namespace client
|
||||||
raw[lexeme[(alpha | '_') >> *(alnum | '_')]];
|
raw[lexeme[(alpha | '_') >> *(alnum | '_')]];
|
||||||
identifier.name("identifier");
|
identifier.name("identifier");
|
||||||
|
|
||||||
bool_expr =
|
conditional_expression =
|
||||||
additive_expression(_r1) [_val = _1]
|
logical_or_expression(_r1) [_val = _1]
|
||||||
>> *( ("==" > additive_expression(_r1) ) [px::bind(&expr<Iterator>::equal, _val, _1)]
|
>> -('?' > conditional_expression(_r1) > ':' > conditional_expression(_r1)) [px::bind(&expr<Iterator>::ternary_op, _val, _1, _2)];
|
||||||
| ("!=" > additive_expression(_r1) ) [px::bind(&expr<Iterator>::not_equal, _val, _1)]
|
|
||||||
| ("<>" > additive_expression(_r1) ) [px::bind(&expr<Iterator>::not_equal, _val, _1)]
|
logical_or_expression =
|
||||||
| ("=~" > regular_expression ) [px::bind(&expr<Iterator>::regex_matches, _val, _1)]
|
logical_and_expression(_r1) [_val = _1]
|
||||||
| ("!~" > regular_expression ) [px::bind(&expr<Iterator>::regex_doesnt_match, _val, _1)]
|
>> *( ((kw["or"] | "||") > logical_and_expression(_r1) ) [px::bind(&expr<Iterator>::logical_or, _val, _1)] );
|
||||||
|
|
||||||
|
logical_and_expression =
|
||||||
|
equality_expression(_r1) [_val = _1]
|
||||||
|
>> *( ((kw["and"] | "&&") > equality_expression(_r1) ) [px::bind(&expr<Iterator>::logical_and, _val, _1)] );
|
||||||
|
|
||||||
|
equality_expression =
|
||||||
|
relational_expression(_r1) [_val = _1]
|
||||||
|
>> *( ("==" > relational_expression(_r1) ) [px::bind(&expr<Iterator>::equal, _val, _1)]
|
||||||
|
| ("!=" > relational_expression(_r1) ) [px::bind(&expr<Iterator>::not_equal, _val, _1)]
|
||||||
|
| ("<>" > relational_expression(_r1) ) [px::bind(&expr<Iterator>::not_equal, _val, _1)]
|
||||||
|
| ("=~" > regular_expression ) [px::bind(&expr<Iterator>::regex_matches, _val, _1)]
|
||||||
|
| ("!~" > regular_expression ) [px::bind(&expr<Iterator>::regex_doesnt_match, _val, _1)]
|
||||||
);
|
);
|
||||||
bool_expr.name("bool expression");
|
equality_expression.name("bool expression");
|
||||||
|
|
||||||
// Evaluate a boolean expression stored as expr into a boolean value.
|
// Evaluate a boolean expression stored as expr into a boolean value.
|
||||||
// Throw if the bool_expr does not produce a expr of boolean type.
|
// Throw if the equality_expression does not produce a expr of boolean type.
|
||||||
bool_expr_eval = bool_expr(_r1) [ px::bind(&expr<Iterator>::evaluate_boolean, _1, _val) ];
|
bool_expr_eval = conditional_expression(_r1) [ px::bind(&expr<Iterator>::evaluate_boolean, _1, _val) ];
|
||||||
bool_expr_eval.name("bool_expr_eval");
|
bool_expr_eval.name("bool_expr_eval");
|
||||||
|
|
||||||
|
relational_expression =
|
||||||
|
additive_expression(_r1) [_val = _1]
|
||||||
|
>> *( (lit('<') > additive_expression(_r1) ) [px::bind(&expr<Iterator>::lower, _val, _1)]
|
||||||
|
| (lit('>') > additive_expression(_r1) ) [px::bind(&expr<Iterator>::greater, _val, _1)]
|
||||||
|
| ("<=" > additive_expression(_r1) ) [px::bind(&expr<Iterator>::leq, _val, _1)]
|
||||||
|
| (">=" > additive_expression(_r1) ) [px::bind(&expr<Iterator>::geq, _val, _1)]
|
||||||
|
);
|
||||||
|
|
||||||
additive_expression =
|
additive_expression =
|
||||||
term(_r1) [_val = _1]
|
multiplicative_expression(_r1) [_val = _1]
|
||||||
>> *( (lit('+') > term(_r1) ) [_val += _1]
|
>> *( (lit('+') > multiplicative_expression(_r1) ) [_val += _1]
|
||||||
| (lit('-') > term(_r1) ) [_val -= _1]
|
| (lit('-') > multiplicative_expression(_r1) ) [_val -= _1]
|
||||||
);
|
);
|
||||||
additive_expression.name("additive_expression");
|
additive_expression.name("additive_expression");
|
||||||
|
|
||||||
term =
|
multiplicative_expression =
|
||||||
factor(_r1) [_val = _1]
|
unary_expression(_r1) [_val = _1]
|
||||||
>> *( (lit('*') > factor(_r1) ) [_val *= _1]
|
>> *( (lit('*') > unary_expression(_r1) ) [_val *= _1]
|
||||||
| (lit('/') > factor(_r1) ) [_val /= _1]
|
| (lit('/') > unary_expression(_r1) ) [_val /= _1]
|
||||||
);
|
);
|
||||||
term.name("term");
|
multiplicative_expression.name("multiplicative_expression");
|
||||||
|
|
||||||
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)
|
||||||
|
@ -899,19 +966,19 @@ namespace client
|
||||||
static void not_(expr<Iterator> &value, expr<Iterator> &out)
|
static void not_(expr<Iterator> &value, expr<Iterator> &out)
|
||||||
{ out = value.unary_not(out.it_range.begin()); }
|
{ out = value.unary_not(out.it_range.begin()); }
|
||||||
};
|
};
|
||||||
factor = 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 ]
|
||||||
| (lit('(') > additive_expression(_r1) > ')' > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ]
|
| (lit('(') > conditional_expression(_r1) > ')' > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ]
|
||||||
| (lit('-') > factor(_r1) ) [ px::bind(&FactorActions::minus_, _1, _val) ]
|
| (lit('-') > unary_expression(_r1) ) [ px::bind(&FactorActions::minus_, _1, _val) ]
|
||||||
| (lit('+') > factor(_r1) > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ]
|
| (lit('+') > unary_expression(_r1) > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ]
|
||||||
| ((kw["not"] | '!') > factor(_r1) > iter_pos) [ px::bind(&FactorActions::not_, _1, _val) ]
|
| ((kw["not"] | '!') > unary_expression(_r1) > iter_pos) [ px::bind(&FactorActions::not_, _1, _val) ]
|
||||||
| (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) ]
|
||||||
| raw[lexeme['"' > *((utf8char - char_('\\') - char_('"')) | ('\\' > char_)) > '"']]
|
| raw[lexeme['"' > *((utf8char - char_('\\') - char_('"')) | ('\\' > char_)) > '"']]
|
||||||
[ px::bind(&FactorActions::string_, _1, _val) ]
|
[ px::bind(&FactorActions::string_, _1, _val) ]
|
||||||
);
|
);
|
||||||
factor.name("factor");
|
unary_expression.name("unary_expression");
|
||||||
|
|
||||||
scalar_variable_reference =
|
scalar_variable_reference =
|
||||||
variable_reference(_r1)[_a=_1] >>
|
variable_reference(_r1)[_a=_1] >>
|
||||||
|
@ -950,17 +1017,24 @@ namespace client
|
||||||
debug(switch_output);
|
debug(switch_output);
|
||||||
debug(legacy_variable_expansion);
|
debug(legacy_variable_expansion);
|
||||||
debug(identifier);
|
debug(identifier);
|
||||||
debug(bool_expr);
|
debug(conditional_expression);
|
||||||
|
debug(logical_or_expression);
|
||||||
|
debug(logical_and_expression);
|
||||||
|
debug(equality_expression);
|
||||||
debug(bool_expr_eval);
|
debug(bool_expr_eval);
|
||||||
|
debug(relational_expression);
|
||||||
debug(additive_expression);
|
debug(additive_expression);
|
||||||
debug(term);
|
debug(multiplicative_expression);
|
||||||
debug(factor);
|
debug(unary_expression);
|
||||||
debug(scalar_variable_reference);
|
debug(scalar_variable_reference);
|
||||||
debug(variable_reference);
|
debug(variable_reference);
|
||||||
debug(regular_expression);
|
debug(regular_expression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generic expression over expr<Iterator>.
|
||||||
|
typedef qi::rule<Iterator, expr<Iterator>(const MyContext*), spirit::ascii::space_type> RuleExpression;
|
||||||
|
|
||||||
// The start of the grammar.
|
// The start of the grammar.
|
||||||
qi::rule<Iterator, std::string(const MyContext*), qi::locals<bool>, spirit::ascii::space_type> start;
|
qi::rule<Iterator, std::string(const MyContext*), qi::locals<bool>, spirit::ascii::space_type> start;
|
||||||
// A free-form text.
|
// A free-form text.
|
||||||
|
@ -973,18 +1047,26 @@ namespace client
|
||||||
qi::rule<Iterator, std::string(const MyContext*), spirit::ascii::space_type> legacy_variable_expansion;
|
qi::rule<Iterator, std::string(const MyContext*), spirit::ascii::space_type> legacy_variable_expansion;
|
||||||
// Parsed identifier name.
|
// Parsed identifier name.
|
||||||
qi::rule<Iterator, boost::iterator_range<Iterator>(), spirit::ascii::space_type> identifier;
|
qi::rule<Iterator, boost::iterator_range<Iterator>(), spirit::ascii::space_type> identifier;
|
||||||
// Math expression consisting of +- operators over terms.
|
// Ternary operator (?:) over logical_or_expression.
|
||||||
qi::rule<Iterator, expr<Iterator>(const MyContext*), spirit::ascii::space_type> additive_expression;
|
RuleExpression conditional_expression;
|
||||||
|
// Logical or over logical_and_expressions.
|
||||||
|
RuleExpression logical_or_expression;
|
||||||
|
// Logical and over relational_expressions.
|
||||||
|
RuleExpression logical_and_expression;
|
||||||
|
// <, >, <=, >=
|
||||||
|
RuleExpression relational_expression;
|
||||||
|
// Math expression consisting of +- operators over multiplicative_expressions.
|
||||||
|
RuleExpression additive_expression;
|
||||||
|
// Boolean expressions over expressions.
|
||||||
|
RuleExpression equality_expression;
|
||||||
|
// Math expression consisting of */ operators over factors.
|
||||||
|
RuleExpression multiplicative_expression;
|
||||||
|
// Number literals, functions, braced expressions, variable references, variable indexing references.
|
||||||
|
RuleExpression unary_expression;
|
||||||
// Rule to capture a regular expression enclosed in //.
|
// Rule to capture a regular expression enclosed in //.
|
||||||
qi::rule<Iterator, boost::iterator_range<Iterator>(), spirit::ascii::space_type> regular_expression;
|
qi::rule<Iterator, boost::iterator_range<Iterator>(), spirit::ascii::space_type> regular_expression;
|
||||||
// Boolean expressions over expressions.
|
|
||||||
qi::rule<Iterator, expr<Iterator>(const MyContext*), spirit::ascii::space_type> bool_expr;
|
|
||||||
// Evaluate boolean expression into bool.
|
// Evaluate boolean expression into bool.
|
||||||
qi::rule<Iterator, bool(const MyContext*), spirit::ascii::space_type> bool_expr_eval;
|
qi::rule<Iterator, bool(const MyContext*), spirit::ascii::space_type> bool_expr_eval;
|
||||||
// Math expression consisting of */ operators over factors.
|
|
||||||
qi::rule<Iterator, expr<Iterator>(const MyContext*), spirit::ascii::space_type> term;
|
|
||||||
// Number literals, functions, braced expressions, variable references, variable indexing references.
|
|
||||||
qi::rule<Iterator, expr<Iterator>(const MyContext*), spirit::ascii::space_type> factor;
|
|
||||||
// Reference of a scalar variable, or reference to a field of a vector variable.
|
// Reference of a scalar variable, or reference to a field of a vector variable.
|
||||||
qi::rule<Iterator, expr<Iterator>(const MyContext*), qi::locals<OptWithPos<Iterator>, int>, spirit::ascii::space_type> scalar_variable_reference;
|
qi::rule<Iterator, expr<Iterator>(const MyContext*), qi::locals<OptWithPos<Iterator>, int>, spirit::ascii::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.
|
||||||
|
@ -1033,10 +1115,11 @@ std::string PlaceholderParser::process(const std::string &templ, unsigned int cu
|
||||||
|
|
||||||
// Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax.
|
// Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax.
|
||||||
// Throws std::runtime_error on syntax or runtime error.
|
// Throws std::runtime_error on syntax or runtime error.
|
||||||
bool PlaceholderParser::evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config)
|
bool PlaceholderParser::evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config, const DynamicConfig *config_override)
|
||||||
{
|
{
|
||||||
client::MyContext context;
|
client::MyContext context;
|
||||||
context.config = &config;
|
context.config = &config;
|
||||||
|
context.config_override = config_override;
|
||||||
// Let the macro processor parse just a boolean expression, not the full macro language.
|
// Let the macro processor parse just a boolean expression, not the full macro language.
|
||||||
context.just_boolean_expression = true;
|
context.just_boolean_expression = true;
|
||||||
return process_macro(templ, context) == "true";
|
return process_macro(templ, context) == "true";
|
||||||
|
|
|
@ -35,7 +35,7 @@ public:
|
||||||
|
|
||||||
// Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax.
|
// Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax.
|
||||||
// Throws std::runtime_error on syntax or runtime error.
|
// Throws std::runtime_error on syntax or runtime error.
|
||||||
static bool evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config);
|
static bool evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config, const DynamicConfig *config_override = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DynamicConfig m_config;
|
DynamicConfig m_config;
|
||||||
|
|
|
@ -142,12 +142,12 @@ std::string Preset::label() const
|
||||||
return this->name + (this->is_dirty ? g_suffix_modified : "");
|
return this->name + (this->is_dirty ? g_suffix_modified : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Preset::is_compatible_with_printer(const Preset &active_printer) const
|
bool Preset::is_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config) const
|
||||||
{
|
{
|
||||||
auto *condition = dynamic_cast<const ConfigOptionString*>(this->config.option("compatible_printers_condition"));
|
auto *condition = dynamic_cast<const ConfigOptionString*>(this->config.option("compatible_printers_condition"));
|
||||||
if (condition != nullptr && ! condition->value.empty()) {
|
if (condition != nullptr && ! condition->value.empty()) {
|
||||||
try {
|
try {
|
||||||
return PlaceholderParser::evaluate_boolean_expression(condition->value, active_printer.config);
|
return PlaceholderParser::evaluate_boolean_expression(condition->value, active_printer.config, extra_config);
|
||||||
} catch (const std::runtime_error &err) {
|
} catch (const std::runtime_error &err) {
|
||||||
//FIXME in case of an error, return "compatible with everything".
|
//FIXME in case of an error, return "compatible with everything".
|
||||||
printf("Preset::is_compatible_with_printer - parsing error of compatible_printers_condition %s:\n%s\n", active_printer.name.c_str(), err.what());
|
printf("Preset::is_compatible_with_printer - parsing error of compatible_printers_condition %s:\n%s\n", active_printer.name.c_str(), err.what());
|
||||||
|
@ -161,9 +161,18 @@ bool Preset::is_compatible_with_printer(const Preset &active_printer) const
|
||||||
compatible_printers->values.end();
|
compatible_printers->values.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Preset::update_compatible_with_printer(const Preset &active_printer)
|
bool Preset::is_compatible_with_printer(const Preset &active_printer) const
|
||||||
{
|
{
|
||||||
return this->is_compatible = is_compatible_with_printer(active_printer);
|
DynamicPrintConfig config;
|
||||||
|
config.set_key_value("printer_preset", new ConfigOptionString(active_printer.name));
|
||||||
|
config.set_key_value("num_extruders", new ConfigOptionInt(
|
||||||
|
(int)static_cast<const ConfigOptionFloats*>(active_printer.config.option("nozzle_diameter"))->values.size()));
|
||||||
|
return this->is_compatible_with_printer(active_printer, &config);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Preset::update_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config)
|
||||||
|
{
|
||||||
|
return this->is_compatible = is_compatible_with_printer(active_printer, extra_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string>& Preset::print_options()
|
const std::vector<std::string>& Preset::print_options()
|
||||||
|
@ -408,11 +417,15 @@ void PresetCollection::set_default_suppressed(bool default_suppressed)
|
||||||
|
|
||||||
void PresetCollection::update_compatible_with_printer(const Preset &active_printer, bool select_other_if_incompatible)
|
void PresetCollection::update_compatible_with_printer(const Preset &active_printer, bool select_other_if_incompatible)
|
||||||
{
|
{
|
||||||
|
DynamicPrintConfig config;
|
||||||
|
config.set_key_value("printer_preset", new ConfigOptionString(active_printer.name));
|
||||||
|
config.set_key_value("num_extruders", new ConfigOptionInt(
|
||||||
|
(int)static_cast<const ConfigOptionFloats*>(active_printer.config.option("nozzle_diameter"))->values.size()));
|
||||||
for (size_t idx_preset = 1; idx_preset < m_presets.size(); ++ idx_preset) {
|
for (size_t idx_preset = 1; idx_preset < m_presets.size(); ++ idx_preset) {
|
||||||
bool selected = idx_preset == m_idx_selected;
|
bool selected = idx_preset == m_idx_selected;
|
||||||
Preset &preset_selected = m_presets[idx_preset];
|
Preset &preset_selected = m_presets[idx_preset];
|
||||||
Preset &preset_edited = selected ? m_edited_preset : preset_selected;
|
Preset &preset_edited = selected ? m_edited_preset : preset_selected;
|
||||||
if (! preset_edited.update_compatible_with_printer(active_printer) &&
|
if (! preset_edited.update_compatible_with_printer(active_printer, &config) &&
|
||||||
selected && select_other_if_incompatible)
|
selected && select_other_if_incompatible)
|
||||||
m_idx_selected = (size_t)-1;
|
m_idx_selected = (size_t)-1;
|
||||||
if (selected)
|
if (selected)
|
||||||
|
|
|
@ -79,9 +79,11 @@ public:
|
||||||
void set_dirty(bool dirty = true) { this->is_dirty = dirty; }
|
void set_dirty(bool dirty = true) { this->is_dirty = dirty; }
|
||||||
void reset_dirty() { this->is_dirty = false; }
|
void reset_dirty() { this->is_dirty = false; }
|
||||||
|
|
||||||
|
bool is_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config) const;
|
||||||
bool is_compatible_with_printer(const Preset &active_printer) const;
|
bool is_compatible_with_printer(const Preset &active_printer) const;
|
||||||
|
|
||||||
// Mark this preset as compatible if it is compatible with active_printer.
|
// Mark this preset as compatible if it is compatible with active_printer.
|
||||||
bool update_compatible_with_printer(const Preset &active_printer);
|
bool update_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config);
|
||||||
|
|
||||||
// Resize the extruder specific fields, initialize them with the content of the 1st extruder.
|
// Resize the extruder specific fields, initialize them with the content of the 1st extruder.
|
||||||
void set_num_extruders(unsigned int n) { set_num_extruders(this->config, n); }
|
void set_num_extruders(unsigned int n) { set_num_extruders(this->config, n); }
|
||||||
|
|
Loading…
Add table
Reference in a new issue