Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/libslic3r/PlaceholderParser.cpp')
-rw-r--r--src/libslic3r/PlaceholderParser.cpp51
1 files changed, 44 insertions, 7 deletions
diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp
index 527d82b4c..6f2b7f3ea 100644
--- a/src/libslic3r/PlaceholderParser.cpp
+++ b/src/libslic3r/PlaceholderParser.cpp
@@ -1,4 +1,5 @@
#include "PlaceholderParser.hpp"
+#include "Exception.hpp"
#include "Flow.hpp"
#include <cstring>
#include <ctime>
@@ -24,6 +25,7 @@
#endif
#include <boost/algorithm/string.hpp>
+#include <boost/nowide/convert.hpp>
// Spirit v2.5 allows you to suppress automatic generation
// of predefined terminals to speed up complation. With
@@ -494,6 +496,12 @@ namespace client
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 throw_if_not_numeric(const expr &param)
+ {
+ const char *err_msg = "Not a numeric type.";
+ param.throw_if_not_numeric(err_msg);
+ }
+
enum Function2ParamsType {
FUNCTION_MIN,
FUNCTION_MAX,
@@ -501,9 +509,8 @@ namespace client
// Store the result into param1.
static void function_2params(expr &param1, expr &param2, Function2ParamsType fun)
{
- const char *err_msg = "Not a numeric type.";
- param1.throw_if_not_numeric(err_msg);
- param2.throw_if_not_numeric(err_msg);
+ throw_if_not_numeric(param1);
+ throw_if_not_numeric(param2);
if (param1.type == TYPE_DOUBLE || param2.type == TYPE_DOUBLE) {
double d = 0.;
switch (fun) {
@@ -528,6 +535,20 @@ namespace client
static void min(expr &param1, expr &param2) { function_2params(param1, param2, FUNCTION_MIN); }
static void max(expr &param1, expr &param2) { function_2params(param1, param2, FUNCTION_MAX); }
+ // Store the result into param1.
+ static void random(expr &param1, expr &param2, std::mt19937 &rng)
+ {
+ throw_if_not_numeric(param1);
+ throw_if_not_numeric(param2);
+ if (param1.type == TYPE_DOUBLE || param2.type == TYPE_DOUBLE) {
+ param1.data.d = std::uniform_real_distribution<>(param1.as_d(), param2.as_d())(rng);
+ param1.type = TYPE_DOUBLE;
+ } else {
+ param1.data.i = std::uniform_int_distribution<>(param1.as_i(), param2.as_i())(rng);
+ param1.type = TYPE_INT;
+ }
+ }
+
static void regex_op(expr &lhs, boost::iterator_range<Iterator> &rhs, char op)
{
const std::string *subject = nullptr;
@@ -622,6 +643,7 @@ namespace client
const DynamicConfig *config = nullptr;
const DynamicConfig *config_override = nullptr;
size_t current_extruder_id = 0;
+ PlaceholderParser::ContextData *context_data = nullptr;
// If false, the macro_processor will evaluate a full macro.
// If true, the macro processor will evaluate just a boolean condition using the full expressive power of the macro processor.
bool just_boolean_expression = false;
@@ -823,6 +845,15 @@ namespace client
}
template <typename Iterator>
+ static void random(const MyContext *ctx, expr<Iterator> &param1, expr<Iterator> &param2)
+ {
+ if (ctx->context_data == nullptr)
+ ctx->throw_exception("Random number generator not available in this context.",
+ boost::iterator_range<Iterator>(param1.it_range.begin(), param2.it_range.end()));
+ expr<Iterator>::random(param1, param2, ctx->context_data->rng);
+ }
+
+ template <typename Iterator>
static void throw_exception(const std::string &msg, const boost::iterator_range<Iterator> &it_range)
{
// An asterix is added to the start of the string to differentiate the boost::spirit::info::tag content
@@ -869,7 +900,9 @@ namespace client
}
}
msg += '\n';
- msg += error_line;
+ // This hack removes all non-UTF8 characters from the source line, so that the upstream wxWidgets conversions
+ // from UTF8 to UTF16 don't bail out.
+ msg += boost::nowide::narrow(boost::nowide::widen(error_line));
msg += '\n';
for (size_t i = 0; i < error_pos; ++ i)
msg += ' ';
@@ -1172,6 +1205,8 @@ namespace client
[ px::bind(&expr<Iterator>::min, _val, _2) ]
| (kw["max"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')')
[ px::bind(&expr<Iterator>::max, _val, _2) ]
+ | (kw["random"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')')
+ [ px::bind(&MyContext::random<Iterator>, _r1, _val, _2) ]
| (kw["int"] > '(' > unary_expression(_r1) > ')') [ px::bind(&FactorActions::to_int, _1, _val) ]
| (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _1, _2, _val) ]
| (int_ > iter_pos) [ px::bind(&FactorActions::int_, _1, _2, _val) ]
@@ -1208,6 +1243,7 @@ namespace client
("false")
("min")
("max")
+ ("random")
("not")
("or")
("true");
@@ -1303,23 +1339,24 @@ static std::string process_macro(const std::string &templ, client::MyContext &co
if (!context.error_message.empty()) {
if (context.error_message.back() != '\n' && context.error_message.back() != '\r')
context.error_message += '\n';
- throw std::runtime_error(context.error_message);
+ throw Slic3r::PlaceholderParserError(context.error_message);
}
return output;
}
-std::string PlaceholderParser::process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override) const
+std::string PlaceholderParser::process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override, ContextData *context_data) const
{
client::MyContext context;
context.external_config = this->external_config();
context.config = &this->config();
context.config_override = config_override;
context.current_extruder_id = current_extruder_id;
+ context.context_data = context_data;
return process_macro(templ, context);
}
// 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 Slic3r::RuntimeError on syntax or runtime error.
bool PlaceholderParser::evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config, const DynamicConfig *config_override)
{
client::MyContext context;