Migrate parse_util_detect_errors to a free function

This commit is contained in:
ridiculousfish 2019-08-04 14:49:56 -07:00
parent 2c3bc1e857
commit 29dede8139
5 changed files with 39 additions and 43 deletions

View file

@ -303,11 +303,10 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
prefix.append(cmd);
prefix.append(L": ");
wcstring err_text;
if (parser.detect_errors_in_argument_list(comp, &err_text, prefix.c_str())) {
if (maybe_t<wcstring> err_text = parse_util_detect_errors_in_argument_list(comp, prefix)) {
streams.err.append_format(L"%ls: Completion '%ls' contained a syntax error\n", cmd,
comp);
streams.err.append(err_text);
streams.err.append(*err_text);
streams.err.push_back(L'\n');
return STATUS_CMD_ERROR;
}

View file

@ -1333,3 +1333,35 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src,
return res;
}
maybe_t<wcstring> parse_util_detect_errors_in_argument_list(const wcstring &arg_list_src,
const wcstring &prefix) {
// Helper to return a description of the first error.
auto get_error_text = [&](const parse_error_list_t &errors) {
assert(!errors.empty() && "Expected an error");
return errors.at(0).describe_with_prefix(arg_list_src, prefix, false /* not interactive */,
false /* don't skip caret */);
};
// Parse the string as an argument list.
parse_error_list_t errors;
parse_node_tree_t tree;
if (!parse_tree_from_string(arg_list_src, parse_flag_none, &tree, &errors,
symbol_freestanding_argument_list)) {
// Failed to parse.
return get_error_text(errors);
}
// Get the root argument list and extract arguments from it.
// Test each of these.
assert(!tree.empty() && "Should have parsed a tree");
tnode_t<grammar::freestanding_argument_list> arg_list(&tree, &tree.at(0));
while (auto arg = arg_list.next_in_list<grammar::argument>()) {
const wcstring arg_src = arg.get_source(arg_list_src);
if (parse_util_detect_errors_in_argument(arg, arg_src, &errors)) {
return get_error_text(errors);
}
}
return none();
}

View file

@ -132,6 +132,11 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src,
bool allow_incomplete = true,
parsed_source_ref_t *out_pstree = NULL);
/// Detect errors in the specified string when parsed as an argument list. Returns the text of an
/// error, or none if no error occurred.
maybe_t<wcstring> parse_util_detect_errors_in_argument_list(const wcstring &arg_list_src,
const wcstring &prefix = {});
/// Test if this argument contains any errors. Detected errors include syntax errors in command
/// substitutions, improperly escaped characters and improper use of the variable expansion
/// operator. This does NOT currently detect unterminated quotes.

View file

@ -680,41 +680,6 @@ template int parser_t::eval_node(parsed_source_ref_t, tnode_t<grammar::job_list>
const io_chain_t &, enum block_type_t,
std::shared_ptr<job_t> parent_job);
bool parser_t::detect_errors_in_argument_list(const wcstring &arg_list_src, wcstring *out,
const wchar_t *prefix) const {
bool errored = false;
parse_error_list_t errors;
// Use empty string for the prefix if it's NULL.
if (!prefix) prefix = L""; //!OCLINT(parameter reassignment)
// Parse the string as an argument list.
parse_node_tree_t tree;
if (!parse_tree_from_string(arg_list_src, parse_flag_none, &tree, &errors,
symbol_freestanding_argument_list)) {
// Failed to parse.
errored = true;
}
if (!errored) {
// Get the root argument list and extract arguments from it.
assert(!tree.empty()); //!OCLINT(multiple unary operator)
tnode_t<grammar::freestanding_argument_list> arg_list(&tree, &tree.at(0));
while (auto arg = arg_list.next_in_list<grammar::argument>()) {
const wcstring arg_src = arg.get_source(arg_list_src);
if (parse_util_detect_errors_in_argument(arg, arg_src, &errors)) {
errored = true;
}
}
}
if (!errors.empty() && out != NULL) {
out->assign(errors.at(0).describe_with_prefix(
arg_list_src, prefix, false /* not interactive */, false /* don't skip caret */));
}
return errored;
}
void parser_t::get_backtrace(const wcstring &src, const parse_error_list_t &errors,
wcstring &output) const {
if (!errors.empty()) {

View file

@ -335,11 +335,6 @@ class parser_t : public std::enable_shared_from_this<parser_t> {
void get_backtrace(const wcstring &src, const parse_error_list_t &errors,
wcstring &output) const;
/// Detect errors in the specified string when parsed as an argument list. Returns true if an
/// error occurred.
bool detect_errors_in_argument_list(const wcstring &arg_list_src, wcstring *out_err,
const wchar_t *prefix) const;
/// Tell the parser that the specified function may not be run if not inside of a conditional
/// block. This is to remove some possibilities of infinite recursion.
void forbid_function(const wcstring &function);