mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 05:13:10 +00:00
Make statement_is_in_pipeline a free typesafe function
This commit is contained in:
parent
194f7f34d9
commit
1c2943bd8b
3 changed files with 38 additions and 44 deletions
|
@ -1315,35 +1315,6 @@ enum token_type redirection_type(tnode_t<grammar::redirection> redirection, cons
|
|||
return result;
|
||||
}
|
||||
|
||||
bool parse_node_tree_t::statement_is_in_pipeline(const parse_node_t &node,
|
||||
bool include_first) const {
|
||||
// Moderately nasty hack! Walk up our ancestor chain and see if we are in a job_continuation.
|
||||
// This checks if we are in the second or greater element in a pipeline; if we are the first
|
||||
// element we treat this as false. This accepts a few statement types.
|
||||
bool result = false;
|
||||
const parse_node_t *ancestor = &node;
|
||||
|
||||
// If we're given a plain statement, try to get its decorated statement parent.
|
||||
if (ancestor && ancestor->type == symbol_plain_statement)
|
||||
ancestor = this->get_parent(*ancestor, symbol_decorated_statement);
|
||||
if (ancestor) ancestor = this->get_parent(*ancestor, symbol_statement);
|
||||
if (ancestor) ancestor = this->get_parent(*ancestor);
|
||||
|
||||
if (ancestor) {
|
||||
if (ancestor->type == symbol_job_continuation) {
|
||||
// Second or more in a pipeline.
|
||||
result = true;
|
||||
} else if (ancestor->type == symbol_job && include_first) {
|
||||
// Check to see if we have a job continuation that's not empty.
|
||||
const parse_node_t *continuation =
|
||||
this->get_child(*ancestor, 1, symbol_job_continuation);
|
||||
result = (continuation != NULL && continuation->child_count > 0);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<tnode_t<grammar::comment>> parse_node_tree_t::comment_nodes_for_node(
|
||||
const parse_node_t &parent) const {
|
||||
std::vector<tnode_t<grammar::comment>> result;
|
||||
|
@ -1420,3 +1391,25 @@ bool job_node_is_background(tnode_t<grammar::job> job) {
|
|||
tnode_t<grammar::optional_background> bg = job.child<2>();
|
||||
return bg.tag() == parse_background;
|
||||
}
|
||||
|
||||
bool statement_is_in_pipeline(tnode_t<grammar::statement> st, bool include_first) {
|
||||
using namespace grammar;
|
||||
if (!st) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we're part of a job continuation, we're definitely in a pipeline.
|
||||
if (st.try_get_parent<job_continuation>()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If include_first is set, check if we're the beginning of a job, and if so, whether that job
|
||||
// has a non-empty continuation.
|
||||
if (include_first) {
|
||||
tnode_t<job_continuation> jc = st.try_get_parent<job>().child<1>();
|
||||
if (jc.try_get_child<statement, 1>()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -181,11 +181,6 @@ class parse_node_tree_t : public std::vector<parse_node_t> {
|
|||
const parse_node_t *parent) const;
|
||||
// Utilities
|
||||
|
||||
/// Given a plain statement, return true if the statement is part of a pipeline. If
|
||||
/// include_first is set, the first command in a pipeline is considered part of it; otherwise
|
||||
/// only the second or additional commands are.
|
||||
bool statement_is_in_pipeline(const parse_node_t &node, bool include_first) const;
|
||||
|
||||
/// Given a node, return all of its comment nodes.
|
||||
std::vector<tnode_t<grammar::comment>> comment_nodes_for_node(const parse_node_t &node) const;
|
||||
|
||||
|
@ -429,6 +424,10 @@ arguments_node_list_t get_argument_nodes(tnode_t<grammar::arguments_or_redirecti
|
|||
/// Return whether the given job is background because it has a & symbol.
|
||||
bool job_node_is_background(tnode_t<grammar::job>);
|
||||
|
||||
/// Return whether the statement is part of a pipeline. If include_first is set, the first command
|
||||
/// in a pipeline is considered part of it; otherwise only the second or additional commands are.
|
||||
bool statement_is_in_pipeline(tnode_t<grammar::statement> st, bool include_first);
|
||||
|
||||
/// Check whether an argument_list is a root list.
|
||||
inline bool argument_list_is_root(tnode_t<grammar::argument_list> list) {
|
||||
return !list.try_get_parent<grammar::argument_list>();
|
||||
|
|
|
@ -1142,9 +1142,11 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src,
|
|||
has_unclosed_block = true;
|
||||
} else if (node.type == symbol_boolean_statement) {
|
||||
// 'or' and 'and' can be in a pipeline, as long as they're first.
|
||||
parse_bool_statement_type_t type = bool_statement_type({&node_tree, &node});
|
||||
tnode_t<grammar::boolean_statement> gbs{&node_tree, &node};
|
||||
parse_bool_statement_type_t type = bool_statement_type(gbs);
|
||||
if ((type == parse_bool_and || type == parse_bool_or) &&
|
||||
node_tree.statement_is_in_pipeline(node, false /* don't count first */)) {
|
||||
statement_is_in_pipeline(gbs.try_get_parent<grammar::statement>(),
|
||||
false /* don't count first */)) {
|
||||
errored = append_syntax_error(&parse_errors, node.source_start, EXEC_ERR_MSG,
|
||||
(type == parse_bool_and) ? L"and" : L"or");
|
||||
}
|
||||
|
@ -1166,13 +1168,14 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src,
|
|||
}
|
||||
} else if (node.type == symbol_plain_statement) {
|
||||
using namespace grammar;
|
||||
tnode_t<plain_statement> statement{&node_tree, &node};
|
||||
tnode_t<plain_statement> pst{&node_tree, &node};
|
||||
// In a few places below, we want to know if we are in a pipeline.
|
||||
const bool is_in_pipeline =
|
||||
node_tree.statement_is_in_pipeline(statement, true /* count first */);
|
||||
tnode_t<statement> st =
|
||||
pst.try_get_parent<decorated_statement>().try_get_parent<statement>();
|
||||
const bool is_in_pipeline = statement_is_in_pipeline(st, true /* count first */);
|
||||
|
||||
// We need to know the decoration.
|
||||
const enum parse_statement_decoration_t decoration = get_decoration(statement);
|
||||
const enum parse_statement_decoration_t decoration = get_decoration(pst);
|
||||
|
||||
// Check that we don't try to pipe through exec.
|
||||
if (is_in_pipeline && decoration == parse_statement_decoration_exec) {
|
||||
|
@ -1180,8 +1183,7 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src,
|
|||
L"exec");
|
||||
}
|
||||
|
||||
if (maybe_t<wcstring> mcommand =
|
||||
command_for_plain_statement({&node_tree, &node}, buff_src)) {
|
||||
if (maybe_t<wcstring> mcommand = command_for_plain_statement(pst, buff_src)) {
|
||||
wcstring command = std::move(*mcommand);
|
||||
// Check that we can expand the command.
|
||||
if (!expand_one(command,
|
||||
|
@ -1212,7 +1214,7 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src,
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!found_function && !first_argument_is_help(statement, buff_src)) {
|
||||
if (!found_function && !first_argument_is_help(pst, buff_src)) {
|
||||
errored = append_syntax_error(&parse_errors, node.source_start,
|
||||
INVALID_RETURN_ERR_MSG);
|
||||
}
|
||||
|
@ -1244,7 +1246,7 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src,
|
|||
}
|
||||
}
|
||||
|
||||
if (!found_loop && !first_argument_is_help(statement, buff_src)) {
|
||||
if (!found_loop && !first_argument_is_help(pst, buff_src)) {
|
||||
errored = append_syntax_error(
|
||||
&parse_errors, node.source_start,
|
||||
(command == L"break" ? INVALID_BREAK_ERR_MSG
|
||||
|
|
Loading…
Reference in a new issue