diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index b5f1866309..131693b4ef 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -814,10 +814,10 @@ std::string GCode::placeholder_parser_process(const std::string &name, const std // Collect the names of failed template substitutions for error reporting. this->m_placeholder_parser_failed_templates.insert(name); // Insert the macro error message into the G-code. - return - std::string("!!!!! Failed to process the custom G-code template ") + name + "\n" + + return + std::string("\n!!!!! Failed to process the custom G-code template ") + name + "\n" + err.what() + - "!!!!! End of an error report for the custom G-code template " + name + "\n"; + "!!!!! End of an error report for the custom G-code template " + name + "\n\n"; } } diff --git a/xs/src/libslic3r/PlaceholderParser.cpp b/xs/src/libslic3r/PlaceholderParser.cpp index f9f72a9e9b..ed75508ace 100644 --- a/xs/src/libslic3r/PlaceholderParser.cpp +++ b/xs/src/libslic3r/PlaceholderParser.cpp @@ -280,22 +280,31 @@ namespace client expr &operator+=(const expr &rhs) { - const char *err_msg = "Cannot multiply with non-numeric type."; - this->throw_if_not_numeric(err_msg); - rhs.throw_if_not_numeric(err_msg); - if (this->type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) { - double d = this->as_d() + rhs.as_d(); - this->data.d = d; - this->type = TYPE_DOUBLE; - } else - this->data.i += rhs.i(); + if (this->type == TYPE_STRING) { + // Convert the right hand side to string and append. + *this->data.s += rhs.to_string(); + } else if (rhs.type == TYPE_STRING) { + // Conver the left hand side to string, append rhs. + this->data.s = new std::string(this->to_string() + rhs.s()); + this->type = TYPE_STRING; + } else { + const char *err_msg = "Cannot add non-numeric types."; + this->throw_if_not_numeric(err_msg); + rhs.throw_if_not_numeric(err_msg); + if (this->type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) { + double d = this->as_d() + rhs.as_d(); + this->data.d = d; + this->type = TYPE_DOUBLE; + } else + this->data.i += rhs.i(); + } this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); return *this; } expr &operator-=(const expr &rhs) { - const char *err_msg = "Cannot multiply with non-numeric type."; + const char *err_msg = "Cannot subtract non-numeric types."; this->throw_if_not_numeric(err_msg); rhs.throw_if_not_numeric(err_msg); if (this->type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) { @@ -578,39 +587,42 @@ namespace client } template - static void process_error_message(const MyContext *context, const boost::spirit::info &info, const Iterator &it_begin, const Iterator &it_end) + static void process_error_message(const MyContext *context, const boost::spirit::info &info, const Iterator &it_begin, const Iterator &it_end, const Iterator &it_error) { - struct expectation_printer - { - expectation_printer(std::string &msg) : result(msg) {} - std::string &result; - void element(std::string const& tag, std::string const& value, int depth) - { - // Indent to depth. - for (int i = 0; i < depth * 4; ++ i) - result += ' '; - if (tag.empty() || tag.front() != '*') { - if (depth == 0) - this->result += "Expecting "; - this->result += "tag: "; - this->result += tag; - } else - this->result += tag.substr(1); - if (! value.empty()) { - this->result += ", value: "; - this->result += value; - } - this->result += '\n'; - } - }; - std::string &msg = const_cast(context)->error_message; - msg += "Error! "; - expectation_printer ep(msg); - spirit::basic_info_walker walker(ep, info.tag, 0); - boost::apply_visitor(walker, info.value); - msg += " got: \""; - msg += std::string(it_begin, it_end) + "\"\n"; + std::string first(it_begin, it_error); + std::string last(it_error, it_end); + auto first_pos = first.rfind('\n'); + auto last_pos = last.find('\n'); + int line_nr = 1; + if (first_pos == std::string::npos) + first_pos = 0; + else { + // Calculate the current line number. + for (size_t i = 0; i <= first_pos; ++ i) + if (first[i] == '\n') + ++ line_nr; + ++ first_pos; + } + auto error_line = std::string(first, first_pos) + std::string(last, 0, last_pos); + // Position of the it_error from the start of its line. + auto error_pos = (it_error - it_begin) - first_pos; + msg += "Parsing error at line " + std::to_string(line_nr); + if (! info.tag.empty() && info.tag.front() == '*') { + // The gat contains an explanatory string. + msg += ": "; + msg += info.tag.substr(1); + } else { + // A generic error report based on the nonterminal or terminal symbol name. + msg += ". Expecting tag "; + msg += info.tag; + } + msg += '\n'; + msg += error_line; + msg += '\n'; + for (size_t i = 0; i < error_pos; ++ i) + msg += ' '; + msg += "^\n"; } }; @@ -733,7 +745,7 @@ namespace client // Without it, some of the errors would not trigger the error handler. start = eps > text_block(_r1); start.name("start"); - qi::on_error(start, px::bind(&MyContext::process_error_message, _r1, _4, _3, _2)); + qi::on_error(start, px::bind(&MyContext::process_error_message, _r1, _4, _1, _2, _3)); text_block = *( text [_val+=_1]