From 1eef6d35525514a8df4c07cd3fa1cc40783aa15a Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 21 Dec 2017 17:07:57 +0100 Subject: Improved error reporting of the PlaceholderParser. --- xs/src/libslic3r/PlaceholderParser.cpp | 59 ++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 9 deletions(-) (limited to 'xs/src/libslic3r') diff --git a/xs/src/libslic3r/PlaceholderParser.cpp b/xs/src/libslic3r/PlaceholderParser.cpp index bcd011da2..b91f4c99c 100644 --- a/xs/src/libslic3r/PlaceholderParser.cpp +++ b/xs/src/libslic3r/PlaceholderParser.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #ifdef _MSC_VER #include // provides **_environ #else @@ -520,6 +521,9 @@ namespace client bool just_boolean_expression = false; std::string error_message; + // Table to translate symbol tag to a human readable error message. + static std::map tag_to_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 @@ -707,9 +711,16 @@ namespace client 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; + auto it = tag_to_error_message.find(info.tag); + if (it == tag_to_error_message.end()) { + // A generic error report based on the nonterminal or terminal symbol name. + msg += ". Expecting tag "; + msg += info.tag; + } else { + // Use the human readable error message. + msg += ". "; + msg + it->second; + } } msg += '\n'; msg += error_line; @@ -720,6 +731,31 @@ namespace client } }; + // Table to translate symbol tag to a human readable error message. + std::map MyContext::tag_to_error_message = { + { "eoi", "Unknown syntax error" }, + { "start", "Unknown syntax error" }, + { "text", "Invalid text." }, + { "text_block", "Invalid text block." }, + { "macro", "Invalid macro." }, + { "if_else_output", "Not an {if}{else}{endif} macro." }, + { "switch_output", "Not a {switch} macro." }, + { "legacy_variable_expansion", "Expecting a legacy variable expansion format" }, + { "identifier", "Expecting an identifier." }, + { "conditional_expression", "Expecting a conditional expression." }, + { "logical_or_expression", "Expecting a boolean expression." }, + { "logical_and_expression", "Expecting a boolean expression." }, + { "equality_expression", "Expecting an expression." }, + { "bool_expr_eval", "Expecting a boolean expression."}, + { "relational_expression", "Expecting an expression." }, + { "additive_expression", "Expecting an expression." }, + { "multiplicative_expression", "Expecting an expression." }, + { "unary_expression", "Expecting an expression." }, + { "scalar_variable_reference", "Expecting a scalar variable reference."}, + { "variable_reference", "Expecting a variable reference."}, + { "regular_expression", "Expecting a regular expression."} + }; + // For debugging the boost::spirit parsers. Print out the string enclosed in it_range. template std::ostream& operator<<(std::ostream& os, const boost::iterator_range &it_range) @@ -822,7 +858,8 @@ namespace client spirit::int_type int_; spirit::double_type double_; spirit::ascii::string_type string; - spirit::repository::qi::iter_pos_type iter_pos; + spirit::eoi_type eoi; + spirit::repository::qi::iter_pos_type iter_pos; auto kw = spirit::repository::qi::distinct(qi::copy(alnum | '_')); qi::_val_type _val; @@ -843,7 +880,7 @@ namespace client start = eps[px::bind(&MyContext::evaluate_full_macro, _r1, _a)] > ( eps(_a==true) > text_block(_r1) [_val=_1] | conditional_expression(_r1) [ px::bind(&expr::evaluate_boolean_to_string, _1, _val) ] - ); + ) > eoi; start.name("start"); qi::on_error(start, px::bind(&MyContext::process_error_message, _r1, _4, _1, _2, _3)); @@ -866,7 +903,7 @@ namespace client // The macro expansion may contain numeric or string expressions, ifs and cases. macro = (kw["if"] > if_else_output(_r1) [_val = _1]) - | (kw["switch"] > switch_output(_r1) [_val = _1]) +// | (kw["switch"] > switch_output(_r1) [_val = _1]) | additive_expression(_r1) [ px::bind(&expr::to_string2, _1, _val) ]; macro.name("macro"); @@ -908,14 +945,17 @@ namespace client conditional_expression = logical_or_expression(_r1) [_val = _1] >> -('?' > conditional_expression(_r1) > ':' > conditional_expression(_r1)) [px::bind(&expr::ternary_op, _val, _1, _2)]; + conditional_expression.name("conditional_expression"); logical_or_expression = logical_and_expression(_r1) [_val = _1] >> *( ((kw["or"] | "||") > logical_and_expression(_r1) ) [px::bind(&expr::logical_or, _val, _1)] ); + logical_or_expression.name("logical_or_expression"); logical_and_expression = equality_expression(_r1) [_val = _1] >> *( ((kw["and"] | "&&") > equality_expression(_r1) ) [px::bind(&expr::logical_and, _val, _1)] ); + logical_and_expression.name("logical_and_expression"); equality_expression = relational_expression(_r1) [_val = _1] @@ -939,6 +979,7 @@ namespace client | ("<=" > additive_expression(_r1) ) [px::bind(&expr::leq, _val, _1)] | (">=" > additive_expression(_r1) ) [px::bind(&expr::geq, _val, _1)] ); + relational_expression.name("relational_expression"); additive_expression = multiplicative_expression(_r1) [_val = _1] @@ -1020,7 +1061,7 @@ namespace client debug(text_block); debug(macro); debug(if_else_output); - debug(switch_output); +// debug(switch_output); debug(legacy_variable_expansion); debug(identifier); debug(conditional_expression); @@ -1079,7 +1120,7 @@ namespace client qi::rule(const MyContext*), spirit::ascii::space_type> variable_reference; qi::rule, spirit::ascii::space_type> if_else_output; - qi::rule, bool, std::string>, spirit::ascii::space_type> switch_output; +// qi::rule, bool, std::string>, spirit::ascii::space_type> switch_output; qi::symbols keywords; }; @@ -1102,7 +1143,7 @@ static std::string process_macro(const std::string &templ, client::MyContext &co // Accumulator for the processed template. std::string output; bool res = phrase_parse(iter, end, macro_processor_instance(&context), space, output); - if (! context.error_message.empty()) { + 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); -- cgit v1.2.3