From 8a14a4a5ffdba28544f2e695a5233cf406c7ded0 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Mon, 15 Jan 2018 11:45:47 -0800 Subject: [PATCH] Continued adoption of tnode_t in parse_execution Migrate boolean statements --- src/parse_execution.cpp | 25 ++++++++++--------------- src/parse_execution.h | 6 +++--- src/parse_tree.cpp | 10 ++++------ src/parse_tree.h | 9 ++++++--- src/parse_util.cpp | 5 ++--- 5 files changed, 25 insertions(+), 30 deletions(-) diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index f05b6cecf..31d2782be 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -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 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()); } 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 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 statement_node = job_node.child<0>(); - assert(statement_node); + tnode_t 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. diff --git a/src/parse_execution.h b/src/parse_execution.h index ea0ce0791..b0632e10e 100644 --- a/src/parse_execution.h +++ b/src/parse_execution.h @@ -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 statement); + parse_execution_result_t populate_boolean_process( + job_t *job, process_t *proc, tnode_t 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, diff --git a/src/parse_tree.cpp b/src/parse_tree.cpp index f103b9060..985aa4330 100644 --- a/src/parse_tree.cpp +++ b/src/parse_tree.cpp @@ -1327,6 +1327,10 @@ enum parse_statement_decoration_t get_decoration(tnode_t stmt) { + return static_cast(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(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); diff --git a/src/parse_tree.h b/src/parse_tree.h index 1c7ffc130..e6d39a6e0 100644 --- a/src/parse_tree.h +++ b/src/parse_tree.h @@ -222,9 +222,6 @@ class parse_node_tree_t : public std::vector { /// 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() const { if (!has_source()) return none(); return source_range_t{nodeptr->source_start, nodeptr->source_length}; @@ -416,6 +416,9 @@ maybe_t command_for_plain_statement(tnode_t /// Return the decoration for a plain statement. parse_statement_decoration_t get_decoration(tnode_t stmt); +/// Return the type for a boolean statement. +enum parse_bool_statement_type_t bool_statement_type(tnode_t 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, diff --git a/src/parse_util.cpp b/src/parse_util.cpp index 9f46902ab..c2c341b06 100644 --- a/src/parse_util.cpp +++ b/src/parse_util.cpp @@ -1068,8 +1068,7 @@ static bool detect_errors_in_backgrounded_job(const parse_node_tree_t &node_tree tnode_t next_stmt = next_job.child<0>(); if (auto bool_stmt = next_stmt.try_get_child()) { // 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,