Re-use the parse tree generated during error detection for execution

Prior to this fix, read_ni would use parse_util_detect_errors
to lint the script to run, and then parser_t::eval() to execute it.
Both functions would parse the script into a parse tree. This allows
us to re-use the parse tree, improving perfomance.
This commit is contained in:
ridiculousfish 2016-02-28 00:44:20 -08:00
parent e3970f9cbb
commit 3633c51ad8
3 changed files with 13 additions and 6 deletions

View file

@ -1287,7 +1287,7 @@ parser_test_error_bits_t parse_util_detect_errors_in_argument(const parse_node_t
return err; return err;
} }
parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, parse_error_list_t *out_errors, bool allow_incomplete) parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, parse_error_list_t *out_errors, bool allow_incomplete, parse_node_tree_t *out_tree)
{ {
parse_node_tree_t node_tree; parse_node_tree_t node_tree;
parse_error_list_t parse_errors; parse_error_list_t parse_errors;
@ -1546,11 +1546,16 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, pars
if (has_unclosed_block || has_unclosed_quote) if (has_unclosed_block || has_unclosed_quote)
res |= PARSER_TEST_INCOMPLETE; res |= PARSER_TEST_INCOMPLETE;
if (out_errors) if (out_errors != NULL)
{ {
out_errors->swap(parse_errors); out_errors->swap(parse_errors);
} }
if (out_tree != NULL)
{
out_tree->swap(node_tree);
}
return res; return res;
} }

View file

@ -171,8 +171,9 @@ wcstring parse_util_escape_string_with_quote(const wcstring &cmd, wchar_t quote)
/** Given a string, parse it as fish code and then return the indents. The return value has the same size as the string */ /** Given a string, parse it as fish code and then return the indents. The return value has the same size as the string */
std::vector<int> parse_util_compute_indents(const wcstring &src); std::vector<int> parse_util_compute_indents(const wcstring &src);
/** Given a string, detect parse errors in it. If allow_incomplete is set, then if the string is incomplete (e.g. an unclosed quote), an error is not returned and the PARSER_TEST_INCOMPLETE bit is set in the return value. If allow_incomplete is not set, then incomplete strings result in an error. */ /** Given a string, detect parse errors in it. If allow_incomplete is set, then if the string is incomplete (e.g. an unclosed quote), an error is not returned and the PARSER_TEST_INCOMPLETE bit is set in the return value. If allow_incomplete is not set, then incomplete strings result in an error. If out_tree is not NULL, the resulting tree is returned by reference. */
parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, parse_error_list_t *out_errors = NULL, bool allow_incomplete = true); class parse_node_tree_t;
parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, parse_error_list_t *out_errors = NULL, bool allow_incomplete = true, parse_node_tree_t *out_tree = NULL);
/** /**
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. 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.

View file

@ -4258,9 +4258,10 @@ static int read_ni(int fd, const io_chain_t &io)
} }
parse_error_list_t errors; parse_error_list_t errors;
if (! parse_util_detect_errors(str, &errors, false /* do not accept incomplete */)) parse_node_tree_t tree;
if (! parse_util_detect_errors(str, &errors, false /* do not accept incomplete */, &tree))
{ {
parser.eval(str, io, TOP); parser.eval_acquiring_tree(str, io, TOP, moved_ref<parse_node_tree_t>(tree));
} }
else else
{ {