Convert populate_block_process to tnode_t

This commit is contained in:
ridiculousfish 2018-01-15 15:37:13 -08:00
parent 2bf96493fc
commit fa0f552fe9
5 changed files with 53 additions and 50 deletions

View file

@ -839,7 +839,7 @@ void highlighter_t::color_redirection(tnode_t<g::redirection> redirection_node)
if (redir_prim) {
wcstring target;
const enum token_type redirect_type =
this->parse_tree.type_for_redirection(redirection_node, this->buff, NULL, &target);
redirection_type(redirection_node, this->buff, nullptr, &target);
// We may get a TOK_NONE redirection type, e.g. if the redirection is invalid.
auto hl = redirect_type == TOK_NONE ? highlight_spec_error : highlight_spec_redirection;

View file

@ -843,7 +843,7 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process(
argument_list.insert(argument_list.begin(), cmd);
// The set of IO redirections that we construct for the process.
if (!this->determine_io_chain(statement, &process_io_chain)) {
if (!this->determine_io_chain(statement.child<1>(), &process_io_chain)) {
return parse_execution_errored;
}
@ -912,26 +912,18 @@ parse_execution_result_t parse_execution_context_t::expand_arguments_from_nodes(
return parse_execution_success;
}
bool parse_execution_context_t::determine_io_chain(const parse_node_t &statement_node,
bool parse_execution_context_t::determine_io_chain(tnode_t<g::arguments_or_redirections_list> node,
io_chain_t *out_chain) {
io_chain_t result;
bool errored = false;
// We are called with a statement of varying types. We require that the statement have an
// arguments_or_redirections_list child.
const parse_node_t &args_and_redirections_list =
tree().find_child(statement_node, symbol_arguments_or_redirections_list);
// Get all redirection nodes underneath the statement.
const parse_node_tree_t::parse_node_list_t redirect_nodes =
tree().find_nodes(args_and_redirections_list, symbol_redirection);
for (size_t i = 0; i < redirect_nodes.size(); i++) {
const parse_node_t &redirect_node = *redirect_nodes.at(i);
auto redirect_nodes = node.descendants<g::redirection>();
for (tnode_t<g::redirection> redirect_node : redirect_nodes) {
int source_fd = -1; // source fd
wcstring target; // file path or target fd
enum token_type redirect_type =
tree().type_for_redirection(redirect_node, pstree->src, &source_fd, &target);
redirection_type(redirect_node, pstree->src, &source_fd, &target);
// PCA: I can't justify this EXPAND_SKIP_VARIABLES flag. It was like this when I got here.
bool target_expanded = expand_one(target, no_exec ? EXPAND_SKIP_VARIABLES : 0, NULL);
@ -1019,22 +1011,26 @@ parse_execution_result_t parse_execution_context_t::populate_boolean_process(
bool_statement.require_get_child<g::statement, 1>());
}
parse_execution_result_t parse_execution_context_t::populate_block_process(
job_t *job, process_t *proc, const parse_node_t &statement_node) {
template <typename Type>
parse_execution_result_t parse_execution_context_t::populate_block_process(job_t *job,
process_t *proc,
tnode_t<Type> node) {
// We handle block statements by creating INTERNAL_BLOCK_NODE, that will bounce back to us when
// it's time to execute them.
UNUSED(job);
assert(statement_node.type == symbol_block_statement ||
statement_node.type == symbol_if_statement ||
statement_node.type == symbol_switch_statement);
static_assert(Type::token == symbol_block_statement || Type::token == symbol_if_statement ||
Type::token == symbol_switch_statement,
"Invalid block process");
// The set of IO redirections that we construct for the process.
// TODO: fix this ugly find_child.
auto arguments = node.template find_child<g::arguments_or_redirections_list>();
io_chain_t process_io_chain;
bool errored = !this->determine_io_chain(statement_node, &process_io_chain);
bool errored = !this->determine_io_chain(arguments, &process_io_chain);
if (errored) return parse_execution_errored;
proc->type = INTERNAL_BLOCK_NODE;
proc->internal_block_node = this->get_offset(statement_node);
proc->internal_block_node = this->get_offset(node);
proc->set_io_chain(process_io_chain);
return parse_execution_success;
}
@ -1052,11 +1048,17 @@ parse_execution_result_t parse_execution_context_t::populate_job_process(
break;
}
case symbol_block_statement:
case symbol_if_statement:
case symbol_switch_statement: {
result = this->populate_block_process(job, proc, specific_statement);
result = this->populate_block_process(
job, proc, tnode_t<g::block_statement>(&tree(), &specific_statement));
break;
case symbol_if_statement:
result = this->populate_block_process(
job, proc, tnode_t<g::if_statement>(&tree(), &specific_statement));
break;
case symbol_switch_statement:
result = this->populate_block_process(
job, proc, tnode_t<g::switch_statement>(&tree(), &specific_statement));
break;
}
case symbol_decorated_statement: {
// Get the plain statement. It will pull out the decoration itself.
tnode_t<g::decorated_statement> dec_stat{&tree(), &specific_statement};

View file

@ -90,8 +90,10 @@ class parse_execution_context_t {
job_t *job, process_t *proc, tnode_t<grammar::boolean_statement> bool_statement);
parse_execution_result_t populate_plain_process(job_t *job, process_t *proc,
tnode_t<grammar::plain_statement> statement);
template <typename Type>
parse_execution_result_t populate_block_process(job_t *job, process_t *proc,
const parse_node_t &statement_node);
tnode_t<Type> statement_node);
// These encapsulate the actual logic of various (block) statements.
parse_execution_result_t run_block_statement(tnode_t<grammar::block_statement> statement);
@ -113,7 +115,8 @@ class parse_execution_context_t {
globspec_t glob_behavior);
// Determines the IO chain. Returns true on success, false on error.
bool determine_io_chain(const parse_node_t &statement, io_chain_t *out_chain);
bool determine_io_chain(tnode_t<grammar::arguments_or_redirections_list> node,
io_chain_t *out_chain);
parse_execution_result_t run_1_job(const parse_node_t &job_node,
const block_t *associated_block);

View file

@ -1331,6 +1331,23 @@ enum parse_bool_statement_type_t bool_statement_type(tnode_t<grammar::boolean_st
return static_cast<parse_bool_statement_type_t>(stmt.tag());
}
enum token_type redirection_type(tnode_t<grammar::redirection> redirection, const wcstring &src,
int *out_fd, wcstring *out_target) {
assert(redirection && "redirection is missing");
enum token_type result = TOK_NONE;
tnode_t<grammar::tok_redirection> prim = redirection.child<0>(); // like 2>
assert(prim && "expected to have primitive");
if (prim.has_source()) {
result = redirection_type_for_string(prim.get_source(src), out_fd);
}
if (out_target != NULL) {
tnode_t<grammar::tok_string> target = redirection.child<1>(); // like &1 or file path
*out_target = target ? target.get_source(src) : wcstring();
}
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.
@ -1360,25 +1377,6 @@ bool parse_node_tree_t::statement_is_in_pipeline(const parse_node_t &node,
return result;
}
enum token_type parse_node_tree_t::type_for_redirection(const parse_node_t &redirection_node,
const wcstring &src, int *out_fd,
wcstring *out_target) const {
assert(redirection_node.type == symbol_redirection);
enum token_type result = TOK_NONE;
const parse_node_t *redirection_primitive =
this->get_child(redirection_node, 0, parse_token_type_redirection); // like 2>
const parse_node_t *redirection_target =
this->get_child(redirection_node, 1, parse_token_type_string); // like &1 or file path
if (redirection_primitive != NULL && redirection_primitive->has_source()) {
result = redirection_type_for_string(redirection_primitive->get_source(src), out_fd);
}
if (out_target != NULL) {
*out_target = redirection_target ? redirection_target->get_source(src) : L"";
}
return result;
}
const parse_node_t *parse_node_tree_t::header_node_for_block_statement(
const parse_node_t &node) const {
const parse_node_t *result = NULL;

View file

@ -200,10 +200,6 @@ class parse_node_tree_t : public std::vector<parse_node_t> {
/// only the second or additional commands are.
bool statement_is_in_pipeline(const parse_node_t &node, bool include_first) const;
/// Given a redirection, get the redirection type (or TOK_NONE) and target (file path, or fd).
enum token_type type_for_redirection(const parse_node_t &node, const wcstring &src, int *out_fd,
wcstring *out_target) const;
/// If the given node is a block statement, returns the header node (for_header, while_header,
/// begin_header, or function_header). Otherwise returns NULL.
const parse_node_t *header_node_for_block_statement(const parse_node_t &node) const;
@ -428,6 +424,10 @@ parse_statement_decoration_t get_decoration(tnode_t<grammar::plain_statement> st
/// Return the type for a boolean statement.
enum parse_bool_statement_type_t bool_statement_type(tnode_t<grammar::boolean_statement> stmt);
/// Given a redirection, get the redirection type (or TOK_NONE) and target (file path, or fd).
enum token_type redirection_type(tnode_t<grammar::redirection> redirection, const wcstring &src,
int *out_fd, wcstring *out_target);
/// Return the arguments under an arguments_list or arguments_or_redirection_list
using arguments_node_list_t = std::vector<tnode_t<grammar::argument>>;
arguments_node_list_t get_argument_nodes(tnode_t<grammar::argument_list>);