Continued adoption of tnode_t in parse_execution

Migrate boolean statements
This commit is contained in:
ridiculousfish 2018-01-15 11:45:47 -08:00
parent 7a3d5ddeae
commit 8a14a4a5ff
5 changed files with 25 additions and 30 deletions

View file

@ -1002,11 +1002,10 @@ bool parse_execution_context_t::determine_io_chain(const parse_node_t &statement
}
parse_execution_result_t parse_execution_context_t::populate_boolean_process(
job_t *job, process_t *proc, const parse_node_t &bool_statement) {
job_t *job, process_t *proc, tnode_t<g::boolean_statement> bool_statement) {
// Handle a boolean statement.
bool skip_job = false;
assert(bool_statement.type == symbol_boolean_statement);
switch (parse_node_tree_t::statement_boolean_type(bool_statement)) {
switch (bool_statement_type(bool_statement)) {
case parse_bool_and: {
// AND. Skip if the last job failed.
skip_job = (proc_get_last_status() != 0);
@ -1027,8 +1026,8 @@ parse_execution_result_t parse_execution_context_t::populate_boolean_process(
if (skip_job) {
return parse_execution_skipped;
}
const parse_node_t &subject = *tree().get_child(bool_statement, 1, symbol_statement);
return this->populate_job_process(job, proc, subject);
return this->populate_job_process(job, proc,
bool_statement.require_get_child<g::statement, 1>());
}
parse_execution_result_t parse_execution_context_t::populate_block_process(
@ -1051,20 +1050,16 @@ parse_execution_result_t parse_execution_context_t::populate_block_process(
return parse_execution_success;
}
// Returns a process_t allocated with new. It's the caller's responsibility to delete it (!).
parse_execution_result_t parse_execution_context_t::populate_job_process(
job_t *job, process_t *proc, const parse_node_t &statement_node) {
assert(statement_node.type == symbol_statement);
assert(statement_node.child_count == 1);
job_t *job, process_t *proc, tnode_t<grammar::statement> statement) {
// Get the "specific statement" which is boolean / block / if / switch / decorated.
const parse_node_t &specific_statement = *get_child(statement_node, 0);
const parse_node_t &specific_statement = *get_child(statement, 0);
parse_execution_result_t result = parse_execution_success;
switch (specific_statement.type) {
case symbol_boolean_statement: {
result = this->populate_boolean_process(job, proc, specific_statement);
result = this->populate_boolean_process(job, proc, {&tree(), &specific_statement});
break;
}
case symbol_block_statement:
@ -1100,15 +1095,15 @@ parse_execution_result_t parse_execution_context_t::populate_job_from_job_node(
// We are going to construct process_t structures for every statement in the job. Get the first
// statement.
tnode_t<g::statement> statement_node = job_node.child<0>();
assert(statement_node);
tnode_t<g::statement> statement = job_node.child<0>();
assert(statement);
parse_execution_result_t result = parse_execution_success;
// Create processes. Each one may fail.
process_list_t processes;
processes.emplace_back(new process_t());
result = this->populate_job_process(j, processes.back().get(), *statement_node);
result = this->populate_job_process(j, processes.back().get(), statement);
// Construct process_ts for job continuations (pipelines), by walking the list until we hit the
// terminal (empty) job continuation.

View file

@ -85,9 +85,9 @@ class parse_execution_context_t {
// These create process_t structures from statements.
parse_execution_result_t populate_job_process(job_t *job, process_t *proc,
const parse_node_t &statement_node);
parse_execution_result_t populate_boolean_process(job_t *job, process_t *proc,
const parse_node_t &bool_statement);
tnode_t<grammar::statement> statement);
parse_execution_result_t populate_boolean_process(
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,
const parse_node_t &statement);
parse_execution_result_t populate_block_process(job_t *job, process_t *proc,

View file

@ -1327,6 +1327,10 @@ enum parse_statement_decoration_t get_decoration(tnode_t<grammar::plain_statemen
return decoration;
}
enum parse_bool_statement_type_t bool_statement_type(tnode_t<grammar::boolean_statement> stmt) {
return static_cast<parse_bool_statement_type_t>(stmt.tag());
}
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.
@ -1429,12 +1433,6 @@ parse_node_tree_t::parse_node_list_t parse_node_tree_t::comment_nodes_for_node(
return result;
}
enum parse_bool_statement_type_t parse_node_tree_t::statement_boolean_type(
const parse_node_t &node) {
assert(node.type == symbol_boolean_statement);
return static_cast<parse_bool_statement_type_t>(node.tag);
}
bool parse_node_tree_t::job_should_be_backgrounded(const parse_node_t &job) const {
assert(job.type == symbol_job);
const parse_node_t *opt_background = get_child(job, 2, symbol_optional_background);

View file

@ -222,9 +222,6 @@ class parse_node_tree_t : public std::vector<parse_node_t> {
/// Given a node, return all of its comment nodes.
parse_node_list_t comment_nodes_for_node(const parse_node_t &node) const;
/// Returns the boolean type for a boolean node.
static enum parse_bool_statement_type_t statement_boolean_type(const parse_node_t &node);
/// Given a job, return whether it should be backgrounded, because it has a & specifier.
bool job_should_be_backgrounded(const parse_node_t &job) const;
@ -303,6 +300,9 @@ class tnode_t {
// return the tag, or 0 if missing.
parse_node_tag_t tag() const { return nodeptr ? nodeptr->tag : 0; }
// return the number of children, or 0 if missing.
uint8_t child_count() const { return nodeptr ? nodeptr->child_count : 0; }
maybe_t<source_range_t> source_range() const {
if (!has_source()) return none();
return source_range_t{nodeptr->source_start, nodeptr->source_length};
@ -416,6 +416,9 @@ maybe_t<wcstring> command_for_plain_statement(tnode_t<grammar::plain_statement>
/// Return the decoration for a plain statement.
parse_statement_decoration_t get_decoration(tnode_t<grammar::plain_statement> stmt);
/// Return the type for a boolean statement.
enum parse_bool_statement_type_t bool_statement_type(tnode_t<grammar::boolean_statement> stmt);
/// The big entry point. Parse a string, attempting to produce a tree for the given goal type.
bool parse_tree_from_string(const wcstring &str, parse_tree_flags_t flags,
parse_node_tree_t *output, parse_error_list_t *errors,

View file

@ -1068,8 +1068,7 @@ static bool detect_errors_in_backgrounded_job(const parse_node_tree_t &node_tree
tnode_t<grammar::statement> next_stmt = next_job.child<0>();
if (auto bool_stmt = next_stmt.try_get_child<grammar::boolean_statement, 0>()) {
// The next job is indeed a boolean statement.
parse_bool_statement_type_t bool_type =
parse_node_tree_t::statement_boolean_type(*bool_stmt.node());
parse_bool_statement_type_t bool_type = bool_statement_type(bool_stmt);
if (bool_type == parse_bool_and) { // this is not allowed
errored = append_syntax_error(parse_errors, bool_stmt.source_range()->start,
BOOL_AFTER_BACKGROUND_ERROR_MSG, L"and");
@ -1145,7 +1144,7 @@ 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 = parse_node_tree_t::statement_boolean_type(node);
parse_bool_statement_type_t type = bool_statement_type({&node_tree, &node});
if ((type == parse_bool_and || type == parse_bool_or) &&
node_tree.statement_is_in_pipeline(node, false /* don't count first */)) {
errored = append_syntax_error(&parse_errors, node.source_start, EXEC_ERR_MSG,