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

github.com/supermerill/SuperSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'xs/src/libslic3r/PlaceholderParser.cpp')
-rw-r--r--xs/src/libslic3r/PlaceholderParser.cpp71
1 files changed, 54 insertions, 17 deletions
diff --git a/xs/src/libslic3r/PlaceholderParser.cpp b/xs/src/libslic3r/PlaceholderParser.cpp
index b9f6b803e..0b33304a8 100644
--- a/xs/src/libslic3r/PlaceholderParser.cpp
+++ b/xs/src/libslic3r/PlaceholderParser.cpp
@@ -361,6 +361,13 @@ namespace client
out = self.b();
}
+ static void evaluate_boolean_to_string(expr &self, std::string &out)
+ {
+ if (self.type != TYPE_BOOL)
+ self.throw_exception("Not a boolean expression");
+ out = self.b() ? "true" : "false";
+ }
+
// Is lhs==rhs? Store the result into lhs.
static void compare_op(expr &lhs, expr &rhs, char op)
{
@@ -452,18 +459,23 @@ namespace client
}
struct MyContext {
- const PlaceholderParser *pp = nullptr;
- const DynamicConfig *config_override = nullptr;
- const size_t current_extruder_id = 0;
+ const DynamicConfig *config = nullptr;
+ const DynamicConfig *config_override = nullptr;
+ size_t current_extruder_id = 0;
+ // 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;
std::string error_message;
+ static void evaluate_full_macro(const MyContext *ctx, bool &result) { result = ! ctx->just_boolean_expression; }
+
const ConfigOption* resolve_symbol(const std::string &opt_key) const
{
const ConfigOption *opt = nullptr;
if (config_override != nullptr)
opt = config_override->option(opt_key);
if (opt == nullptr)
- opt = pp->option(opt_key);
+ opt = config->option(opt_key);
return opt;
}
@@ -734,13 +746,13 @@ namespace client
};
///////////////////////////////////////////////////////////////////////////
- // Our calculator grammar
+ // Our macro_processor grammar
///////////////////////////////////////////////////////////////////////////
// Inspired by the C grammar rules https://www.lysator.liu.se/c/ANSI-C-grammar-y.html
template <typename Iterator>
- struct calculator : qi::grammar<Iterator, std::string(const MyContext*), spirit::ascii::space_type>
+ struct macro_processor : qi::grammar<Iterator, std::string(const MyContext*), qi::locals<bool>, spirit::ascii::space_type>
{
- calculator() : calculator::base_type(start)
+ macro_processor() : macro_processor::base_type(start)
{
using namespace qi::labels;
qi::alpha_type alpha;
@@ -772,7 +784,13 @@ namespace client
// Starting symbol of the grammer.
// The leading eps is required by the "expectation point" operator ">".
// Without it, some of the errors would not trigger the error handler.
- start = eps > text_block(_r1);
+ // Also the start symbol switches between the "full macro syntax" and a "boolean expression only",
+ // depending on the context->just_boolean_expression flag. This way a single static expression parser
+ // could serve both purposes.
+ start = eps[px::bind(&MyContext::evaluate_full_macro, _r1, _a)] >
+ ( eps(_a==true) > text_block(_r1) [_val=_1]
+ | bool_expr(_r1) [ px::bind(&expr<Iterator>::evaluate_boolean_to_string, _1, _val) ]
+ );
start.name("start");
qi::on_error<qi::fail>(start, px::bind(&MyContext::process_error_message<Iterator>, _r1, _4, _1, _2, _3));
@@ -944,7 +962,7 @@ namespace client
}
// The start of the grammar.
- qi::rule<Iterator, std::string(const MyContext*), spirit::ascii::space_type> start;
+ qi::rule<Iterator, std::string(const MyContext*), qi::locals<bool>, spirit::ascii::space_type> start;
// A free-form text.
qi::rule<Iterator, std::string(), spirit::ascii::space_type> text;
// A free-form text, possibly empty, possibly containing macro expansions.
@@ -979,24 +997,23 @@ namespace client
};
}
-std::string PlaceholderParser::process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override) const
+static std::string process_macro(const std::string &templ, client::MyContext &context)
{
typedef std::string::const_iterator iterator_type;
- typedef client::calculator<iterator_type> calculator;
+ typedef client::macro_processor<iterator_type> macro_processor;
// Our whitespace skipper.
spirit::ascii::space_type space;
- // Our grammar.
- calculator calc;
+ // Our grammar, statically allocated inside the method, meaning it will be allocated the first time
+ // PlaceholderParser::process() runs.
+ //FIXME this kind of initialization is not thread safe!
+ static macro_processor macro_processor_instance;
// Iterators over the source template.
std::string::const_iterator iter = templ.begin();
std::string::const_iterator end = templ.end();
// Accumulator for the processed template.
std::string output;
- client::MyContext context;
- context.pp = this;
- context.config_override = config_override;
- bool res = phrase_parse(iter, end, calc(&context), space, output);
+ bool res = phrase_parse(iter, end, macro_processor_instance(&context), space, output);
if (! context.error_message.empty()) {
if (context.error_message.back() != '\n' && context.error_message.back() != '\r')
context.error_message += '\n';
@@ -1005,4 +1022,24 @@ std::string PlaceholderParser::process(const std::string &templ, unsigned int cu
return output;
}
+std::string PlaceholderParser::process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override) const
+{
+ client::MyContext context;
+ context.config = &this->config();
+ context.config_override = config_override;
+ context.current_extruder_id = current_extruder_id;
+ 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.
+bool PlaceholderParser::evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config)
+{
+ client::MyContext context;
+ context.config = &config;
+ // Let the macro processor parse just a boolean expression, not the full macro language.
+ context.just_boolean_expression = true;
+ return process_macro(templ, context) == "true";
+}
+
}