diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index c1af96268..de5007b17 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -240,9 +240,9 @@ bool parse_execution_context_t::job_is_simple_block(tnode_t job_node) co } } -eval_result_t parse_execution_context_t::run_if_statement(tnode_t statement, - const block_t *associated_block) { - eval_result_t result = eval_result_t::ok; +parse_execution_result_t parse_execution_context_t::run_if_statement( + tnode_t statement, const block_t *associated_block) { + parse_execution_result_t result = parse_execution_success; // We have a sequence of if clauses, with a final else, resulting in a single job list that we // execute. @@ -255,7 +255,7 @@ eval_result_t parse_execution_context_t::run_if_statement(tnode_t condition_head = if_clause.child<1>(); tnode_t condition_boolean_tail = if_clause.child<3>(); - // Check the condition and the tail. We treat eval_result_t::error here as failure, in + // Check the condition and the tail. We treat parse_execution_errored here as failure, in // accordance with historic behavior. - eval_result_t cond_ret = run_job_conjunction(condition_head, associated_block); - if (cond_ret == eval_result_t::ok) { + parse_execution_result_t cond_ret = run_job_conjunction(condition_head, associated_block); + if (cond_ret == parse_execution_success) { cond_ret = run_job_list(condition_boolean_tail, associated_block); } const bool take_branch = - (cond_ret == eval_result_t::ok) && parser->get_last_status() == EXIT_SUCCESS; + (cond_ret == parse_execution_success) && parser->get_last_status() == EXIT_SUCCESS; if (take_branch) { // Condition succeeded. @@ -305,7 +305,7 @@ eval_result_t parse_execution_context_t::run_if_statement(tnode_tpush_block(block_t::if_block()); run_job_list(job_list_to_execute, ib); if (should_cancel_execution(ib)) { - result = eval_result_t::cancelled; + result = parse_execution_cancelled; } parser->pop_block(ib); } else { @@ -317,32 +317,34 @@ eval_result_t parse_execution_context_t::run_if_statement(tnode_t contents) { +parse_execution_result_t parse_execution_context_t::run_begin_statement( + tnode_t contents) { // Basic begin/end block. Push a scope block, run jobs, pop it trace_if_enabled(*parser, L"begin"); block_t *sb = parser->push_block(block_t::scope_block(BEGIN)); - eval_result_t ret = run_job_list(contents, sb); + parse_execution_result_t ret = run_job_list(contents, sb); parser->pop_block(sb); trace_if_enabled(*parser, L"end begin"); return ret; } // Define a function. -eval_result_t parse_execution_context_t::run_function_statement(tnode_t header, - tnode_t body) { +parse_execution_result_t parse_execution_context_t::run_function_statement( + tnode_t header, tnode_t body) { // Get arguments. wcstring_list_t arguments; argument_node_list_t arg_nodes = header.descendants(); - eval_result_t result = this->expand_arguments_from_nodes(arg_nodes, &arguments, failglob); + parse_execution_result_t result = + this->expand_arguments_from_nodes(arg_nodes, &arguments, failglob); - if (result != eval_result_t::ok) { + if (result != parse_execution_success) { return result; } trace_if_enabled(*parser, L"function", arguments); @@ -353,18 +355,18 @@ eval_result_t parse_execution_context_t::run_function_statement(tnode_treport_error(header, L"%ls", errtext.c_str()); - result = eval_result_t::error; + result = parse_execution_errored; } return result; } -eval_result_t parse_execution_context_t::run_block_statement(tnode_t statement, - const block_t *associated_block) { +parse_execution_result_t parse_execution_context_t::run_block_statement( + tnode_t statement, const block_t *associated_block) { tnode_t bheader = statement.child<0>(); tnode_t contents = statement.child<1>(); - eval_result_t ret = eval_result_t::ok; + parse_execution_result_t ret = parse_execution_success; if (auto header = bheader.try_get_child()) { ret = run_for_statement(header, contents); } else if (auto header = bheader.try_get_child()) { @@ -389,7 +391,7 @@ bool parse_execution_context_t::is_function_context() const { return is_within_function_call; } -eval_result_t parse_execution_context_t::run_for_statement( +parse_execution_result_t parse_execution_context_t::run_for_statement( tnode_t header, tnode_t block_contents) { // Get the variable name: `for var_name in ...`. We expand the variable name. It better result // in just one. @@ -397,14 +399,14 @@ eval_result_t parse_execution_context_t::run_for_statement( wcstring for_var_name = get_source(var_name_node); if (!expand_one(for_var_name, expand_flags_t{}, parser->vars(), parser->shared())) { report_error(var_name_node, FAILED_EXPANSION_VARIABLE_NAME_ERR_MSG, for_var_name.c_str()); - return eval_result_t::error; + return parse_execution_errored; } // Get the contents to iterate over. wcstring_list_t arguments; - eval_result_t ret = this->expand_arguments_from_nodes(get_argument_nodes(header.child<3>()), - &arguments, nullglob); - if (ret != eval_result_t::ok) { + parse_execution_result_t ret = this->expand_arguments_from_nodes( + get_argument_nodes(header.child<3>()), &arguments, nullglob); + if (ret != parse_execution_success) { return ret; } @@ -416,13 +418,13 @@ eval_result_t parse_execution_context_t::run_for_statement( if (retval != ENV_OK) { report_error(var_name_node, L"You cannot use read-only variable '%ls' in a for loop", for_var_name.c_str()); - return eval_result_t::error; + return parse_execution_errored; } } if (!valid_var_name(for_var_name)) { report_error(var_name_node, BUILTIN_ERR_VARNAME, L"for", for_var_name.c_str()); - return eval_result_t::error; + return parse_execution_errored; } trace_if_enabled(*parser, L"for", arguments); @@ -431,7 +433,7 @@ eval_result_t parse_execution_context_t::run_for_statement( // Now drive the for loop. for (const wcstring &val : arguments) { if (should_cancel_execution(fb)) { - ret = eval_result_t::cancelled; + ret = parse_execution_cancelled; break; } @@ -458,9 +460,9 @@ eval_result_t parse_execution_context_t::run_for_statement( return ret; } -eval_result_t parse_execution_context_t::run_switch_statement( +parse_execution_result_t parse_execution_context_t::run_switch_statement( tnode_t statement) { - eval_result_t result = eval_result_t::ok; + parse_execution_result_t result = parse_execution_success; // Get the switch variable. tnode_t switch_value_n = statement.child<1>(); @@ -493,13 +495,13 @@ eval_result_t parse_execution_context_t::run_switch_statement( } } - if (result == eval_result_t::ok && switch_values_expanded.size() > 1) { + if (result == parse_execution_success && switch_values_expanded.size() > 1) { result = report_error(switch_value_n, _(L"switch: Expected at most one argument, got %lu\n"), switch_values_expanded.size()); } - if (result != eval_result_t::ok) { + if (result != parse_execution_success) { return result; } @@ -513,7 +515,7 @@ eval_result_t parse_execution_context_t::run_switch_statement( tnode_t matching_case_item{}; while (auto case_item = case_item_list.next_in_list()) { if (should_cancel_execution(sb)) { - result = eval_result_t::cancelled; + result = parse_execution_cancelled; break; } @@ -522,9 +524,9 @@ eval_result_t parse_execution_context_t::run_switch_statement( // contains an unexpandable process will report and then fail to match. auto arg_nodes = get_argument_nodes(case_item.child<1>()); wcstring_list_t case_args; - eval_result_t case_result = + parse_execution_result_t case_result = this->expand_arguments_from_nodes(arg_nodes, &case_args, failglob); - if (case_result == eval_result_t::ok) { + if (case_result == parse_execution_success) { for (const wcstring &arg : case_args) { // Unescape wildcards so they can be expanded again. wcstring unescaped_arg = parse_util_unescape_wildcards(arg); @@ -542,7 +544,7 @@ eval_result_t parse_execution_context_t::run_switch_statement( if (matching_case_item) { // Success, evaluate the job list. - assert(result == eval_result_t::ok && "Expected success"); + assert(result == parse_execution_success && "Expected success"); auto job_list = matching_case_item.child<3>(); result = this->run_job_list(job_list, sb); } @@ -551,10 +553,10 @@ eval_result_t parse_execution_context_t::run_switch_statement( return result; } -eval_result_t parse_execution_context_t::run_while_statement(tnode_t header, - tnode_t contents, - const block_t *associated_block) { - eval_result_t ret = eval_result_t::ok; +parse_execution_result_t parse_execution_context_t::run_while_statement( + tnode_t header, tnode_t contents, + const block_t *associated_block) { + parse_execution_result_t ret = parse_execution_success; // "The exit status of the while loop shall be the exit status of the last compound-list-2 // executed, or zero if none was executed." @@ -582,15 +584,16 @@ eval_result_t parse_execution_context_t::run_while_statement(tnode_trun_job_conjunction(condition_head, associated_block); - if (cond_ret == eval_result_t::ok) { + parse_execution_result_t cond_ret = + this->run_job_conjunction(condition_head, associated_block); + if (cond_ret == parse_execution_success) { cond_ret = run_job_list(condition_boolean_tail, associated_block); } // If the loop condition failed to execute, then exit the loop without modifying the exit // status. If the loop condition executed with a failure status, restore the status and then // exit the loop. - if (cond_ret != eval_result_t::ok) { + if (cond_ret != parse_execution_success) { break; } else if (parser->get_last_status() != EXIT_SUCCESS) { parser->set_last_statuses(cond_saved_status); @@ -599,7 +602,7 @@ eval_result_t parse_execution_context_t::run_while_statement(tnode_tshould_cancel_execution(associated_block)) { - ret = eval_result_t::cancelled; + ret = parse_execution_cancelled; break; } @@ -633,10 +636,10 @@ eval_result_t parse_execution_context_t::run_while_statement(tnode_treport_errors(error_list); - return eval_result_t::error; + return parse_execution_errored; } -eval_result_t parse_execution_context_t::report_errors(const parse_error_list_t &error_list) const { +parse_execution_result_t parse_execution_context_t::report_errors( + const parse_error_list_t &error_list) const { if (!parser->cancellation_requested) { if (error_list.empty()) { FLOG(error, L"Error reported but no error text found."); @@ -668,19 +672,19 @@ eval_result_t parse_execution_context_t::report_errors(const parse_error_list_t std::fwprintf(stderr, L"%ls", backtrace_and_desc.c_str()); } } - return eval_result_t::error; + return parse_execution_errored; } -/// Reports an unmatched wildcard error and returns eval_result_t::error. -eval_result_t parse_execution_context_t::report_unmatched_wildcard_error( +/// Reports an unmatched wildcard error and returns parse_execution_errored. +parse_execution_result_t parse_execution_context_t::report_unmatched_wildcard_error( const parse_node_t &unmatched_wildcard) const { parser->set_last_statuses(statuses_t::just(STATUS_UNMATCHED_WILDCARD)); report_error(unmatched_wildcard, WILDCARD_ERR_MSG, get_source(unmatched_wildcard).c_str()); - return eval_result_t::error; + return parse_execution_errored; } /// Handle the case of command not found. -eval_result_t parse_execution_context_t::handle_command_not_found( +parse_execution_result_t parse_execution_context_t::handle_command_not_found( const wcstring &cmd_str, tnode_t statement, int err_code) { // We couldn't find the specified command. This is a non-fatal error. We want to set the exit // status to 127, which is the standard number used by other shells like bash and zsh. @@ -694,10 +698,10 @@ eval_result_t parse_execution_context_t::handle_command_not_found( wcstring_list_t event_args; { auto args = get_argument_nodes(statement.child<1>()); - eval_result_t arg_result = + parse_execution_result_t arg_result = this->expand_arguments_from_nodes(args, &event_args, failglob); - if (arg_result != eval_result_t::ok) { + if (arg_result != parse_execution_success) { return arg_result; } @@ -714,12 +718,12 @@ eval_result_t parse_execution_context_t::handle_command_not_found( int status = err_code == ENOENT ? STATUS_CMD_UNKNOWN : STATUS_NOT_EXECUTABLE; parser->set_last_statuses(statuses_t::just(status)); - return eval_result_t::error; + return parse_execution_errored; } -eval_result_t parse_execution_context_t::expand_command(tnode_t statement, - wcstring *out_cmd, - wcstring_list_t *out_args) const { +parse_execution_result_t parse_execution_context_t::expand_command( + tnode_t statement, wcstring *out_cmd, + wcstring_list_t *out_args) const { // Here we're expanding a command, for example $HOME/bin/stuff or $randomthing. The first // completion becomes the command itself, everything after becomes arguments. Command // substitutions are not supported. @@ -749,11 +753,11 @@ eval_result_t parse_execution_context_t::expand_command(tnode_tempty()) { return this->report_error(statement, _(L"The expanded command was empty.")); } - return eval_result_t::ok; + return parse_execution_success; } /// Creates a 'normal' (non-block) process. -eval_result_t parse_execution_context_t::populate_plain_process( +parse_execution_result_t parse_execution_context_t::populate_plain_process( job_t *job, process_t *proc, tnode_t statement) { assert(job != nullptr); assert(proc != nullptr); @@ -765,7 +769,7 @@ eval_result_t parse_execution_context_t::populate_plain_process( wcstring cmd; wcstring_list_t args_from_cmd_expansion; auto ret = expand_command(statement, &cmd, &args_from_cmd_expansion); - if (ret != eval_result_t::ok) { + if (ret != parse_execution_success) { return ret; } assert(!cmd.empty() && "expand_command should not produce an empty command"); @@ -792,7 +796,7 @@ eval_result_t parse_execution_context_t::populate_plain_process( if (isatty(STDIN_FILENO) && current_run_count - 1 != last_exec_run_count) { reader_bg_job_warning(*parser); last_exec_run_count = current_run_count; - return eval_result_t::error; + return parse_execution_errored; } else { hup_background_jobs(*parser); } @@ -848,15 +852,15 @@ eval_result_t parse_execution_context_t::populate_plain_process( cmd_args.insert(cmd_args.end(), args_from_cmd_expansion.begin(), args_from_cmd_expansion.end()); argument_node_list_t arg_nodes = statement.descendants(); - eval_result_t arg_result = + parse_execution_result_t arg_result = this->expand_arguments_from_nodes(arg_nodes, &cmd_args, glob_behavior); - if (arg_result != eval_result_t::ok) { + if (arg_result != parse_execution_success) { return arg_result; } // The set of IO redirections that we construct for the process. if (!this->determine_redirections(statement.child<1>(), &redirections)) { - return eval_result_t::error; + return parse_execution_errored; } // Determine the process type. @@ -868,12 +872,12 @@ eval_result_t parse_execution_context_t::populate_plain_process( proc->set_argv(cmd_args); proc->set_redirection_specs(std::move(redirections)); proc->actual_cmd = std::move(path_to_external_command); - return eval_result_t::ok; + return parse_execution_success; } // Determine the list of arguments, expanding stuff. Reports any errors caused by expansion. If we // have a wildcard that could not be expanded, report the error and continue. -eval_result_t parse_execution_context_t::expand_arguments_from_nodes( +parse_execution_result_t parse_execution_context_t::expand_arguments_from_nodes( const argument_node_list_t &argument_nodes, wcstring_list_t *out_arguments, globspec_t glob_behavior) { // Get all argument nodes underneath the statement. We guess we'll have that many arguments (but @@ -894,13 +898,13 @@ eval_result_t parse_execution_context_t::expand_arguments_from_nodes( switch (expand_ret) { case expand_result_t::error: { this->report_errors(errors); - return eval_result_t::error; + return parse_execution_errored; } case expand_result_t::wildcard_no_match: { if (glob_behavior == failglob) { // Report the unmatched wildcard error and stop processing. report_unmatched_wildcard_error(arg_node); - return eval_result_t::error; + return parse_execution_errored; } break; } @@ -924,10 +928,10 @@ eval_result_t parse_execution_context_t::expand_arguments_from_nodes( // We may have received a cancellation during this expansion. if (parser->cancellation_requested) { - return eval_result_t::cancelled; + return parse_execution_cancelled; } - return eval_result_t::ok; + return parse_execution_success; } bool parse_execution_context_t::determine_redirections( @@ -977,7 +981,7 @@ bool parse_execution_context_t::determine_redirections( return true; } -eval_result_t parse_execution_context_t::populate_not_process( +parse_execution_result_t parse_execution_context_t::populate_not_process( job_t *job, process_t *proc, tnode_t not_statement) { auto &flags = job->mut_flags(); flags.negate = !flags.negate; @@ -987,9 +991,9 @@ eval_result_t parse_execution_context_t::populate_not_process( } template -eval_result_t parse_execution_context_t::populate_block_process(job_t *job, process_t *proc, - tnode_t statement, - tnode_t specific_statement) { +parse_execution_result_t parse_execution_context_t::populate_block_process( + job_t *job, process_t *proc, tnode_t statement, + tnode_t specific_statement) { // We handle block statements by creating process_type_t::block_node, that will bounce back to // us when it's time to execute them. UNUSED(job); @@ -1004,22 +1008,22 @@ eval_result_t parse_execution_context_t::populate_block_process(job_t *job, proc auto arguments = specific_statement.template find_child(); redirection_spec_list_t redirections; if (!this->determine_redirections(arguments, &redirections)) { - return eval_result_t::error; + return parse_execution_errored; } proc->type = process_type_t::block_node; proc->block_node_source = pstree; proc->internal_block_node = statement; proc->set_redirection_specs(std::move(redirections)); - return eval_result_t::ok; + return parse_execution_success; } -eval_result_t parse_execution_context_t::apply_variable_assignments( +parse_execution_result_t parse_execution_context_t::apply_variable_assignments( process_t *proc, tnode_t variable_assignments, const block_t **block) { variable_assignment_node_list_t assignment_list = get_variable_assignment_nodes(variable_assignments); - if (assignment_list.empty()) return eval_result_t::ok; + if (assignment_list.empty()) return parse_execution_success; *block = parser->push_block(block_t::variable_assignment_block()); for (const auto &variable_assignment : assignment_list) { const wcstring &source = variable_assignment.get_source(pstree->src); @@ -1038,7 +1042,7 @@ eval_result_t parse_execution_context_t::apply_variable_assignments( switch (expand_ret) { case expand_result_t::error: { this->report_errors(errors); - return eval_result_t::error; + return parse_execution_errored; } case expand_result_t::wildcard_no_match: // nullglob (equivalent to set) case expand_result_t::wildcard_match: @@ -1057,21 +1061,22 @@ eval_result_t parse_execution_context_t::apply_variable_assignments( if (proc) proc->variable_assignments.push_back({variable_name, vals}); parser->vars().set(std::move(variable_name), ENV_LOCAL | ENV_EXPORT, std::move(vals)); } - return eval_result_t::ok; + return parse_execution_success; } -eval_result_t parse_execution_context_t::populate_job_process( +parse_execution_result_t parse_execution_context_t::populate_job_process( job_t *job, process_t *proc, tnode_t statement, tnode_t variable_assignments) { // Get the "specific statement" which is boolean / block / if / switch / decorated. const parse_node_t &specific_statement = statement.get_child_node<0>(); const block_t *block = nullptr; - eval_result_t result = this->apply_variable_assignments(proc, variable_assignments, &block); + parse_execution_result_t result = + this->apply_variable_assignments(proc, variable_assignments, &block); cleanup_t scope([&]() { if (block) parser->pop_block(block); }); - if (result != eval_result_t::ok) return eval_result_t::error; + if (result != parse_execution_success) return parse_execution_errored; switch (specific_statement.type) { case symbol_not_statement: { @@ -1108,7 +1113,7 @@ eval_result_t parse_execution_context_t::populate_job_process( return result; } -eval_result_t parse_execution_context_t::populate_job_from_job_node( +parse_execution_result_t parse_execution_context_t::populate_job_from_job_node( job_t *j, tnode_t job_node, const block_t *associated_block) { UNUSED(associated_block); @@ -1123,7 +1128,7 @@ eval_result_t parse_execution_context_t::populate_job_from_job_node( // Create processes. Each one may fail. process_list_t processes; processes.emplace_back(new process_t()); - eval_result_t result = + parse_execution_result_t result = this->populate_job_process(j, processes.back().get(), statement, variable_assignments); // Construct process_ts for job continuations (pipelines), by walking the list until we hit the @@ -1131,7 +1136,7 @@ eval_result_t parse_execution_context_t::populate_job_from_job_node( tnode_t job_cont = job_node.child<2>(); assert(job_cont); while (auto pipe = job_cont.try_get_child()) { - if (result != eval_result_t::ok) { + if (result != parse_execution_success) { break; } auto variable_assignments = job_cont.require_get_child(); @@ -1168,7 +1173,7 @@ eval_result_t parse_execution_context_t::populate_job_from_job_node( processes.back()->is_last_in_job = true; // Return what happened. - if (result == eval_result_t::ok) { + if (result == parse_execution_success) { // Link up the processes. assert(!processes.empty()); //!OCLINT(multiple unary operator) j->processes = std::move(processes); @@ -1186,10 +1191,10 @@ static bool remove_job(parser_t &parser, job_t *job) { return false; } -eval_result_t parse_execution_context_t::run_1_job(tnode_t job_node, - const block_t *associated_block) { +parse_execution_result_t parse_execution_context_t::run_1_job(tnode_t job_node, + const block_t *associated_block) { if (should_cancel_execution(associated_block)) { - return eval_result_t::cancelled; + return parse_execution_cancelled; } // Get terminal modes. @@ -1197,7 +1202,7 @@ eval_result_t parse_execution_context_t::run_1_job(tnode_t job_node, if (parser->is_interactive() && tcgetattr(STDIN_FILENO, &tmodes)) { // Need real error handling here. wperror(L"tcgetattr"); - return eval_result_t::error; + return parse_execution_errored; } // Increment the eval_level for the duration of this command. @@ -1220,7 +1225,7 @@ eval_result_t parse_execution_context_t::run_1_job(tnode_t job_node, if (job_is_simple_block(job_node)) { tnode_t variable_assignments = job_node.child<0>(); const block_t *block = nullptr; - eval_result_t result = + parse_execution_result_t result = this->apply_variable_assignments(nullptr, variable_assignments, &block); cleanup_t scope([&]() { if (block) parser->pop_block(block); @@ -1229,7 +1234,7 @@ eval_result_t parse_execution_context_t::run_1_job(tnode_t job_node, tnode_t statement = job_node.child<1>(); const parse_node_t &specific_statement = statement.get_child_node<0>(); assert(specific_statement_type_is_redirectable_block(specific_statement)); - if (result == eval_result_t::ok) { + if (result == parse_execution_success) { switch (specific_statement.type) { case symbol_block_statement: { result = @@ -1297,7 +1302,7 @@ eval_result_t parse_execution_context_t::run_1_job(tnode_t job_node, // Populate the job. This may fail for reasons like command_not_found. If this fails, an error // will have been printed. - eval_result_t pop_result = + parse_execution_result_t pop_result = this->populate_job_from_job_node(job.get(), job_node, associated_block); assert(libdata.caller_job_id == job->job_id && "Caller job ID unexpectedly changed"); @@ -1309,7 +1314,7 @@ eval_result_t parse_execution_context_t::run_1_job(tnode_t job_node, } // Clean up the job on failure or cancellation. - bool populated_job = (pop_result == eval_result_t::ok); + bool populated_job = (pop_result == parse_execution_success); if (populated_job) { // Success. Give the job to the parser - it will clean it up. parser->job_add(job); @@ -1345,12 +1350,12 @@ eval_result_t parse_execution_context_t::run_1_job(tnode_t job_node, } job_reap(*parser, false); // clean up jobs - return populated_job ? eval_result_t::ok : eval_result_t::error; + return populated_job ? parse_execution_success : parse_execution_errored; } -eval_result_t parse_execution_context_t::run_job_conjunction( +parse_execution_result_t parse_execution_context_t::run_job_conjunction( tnode_t job_expr, const block_t *associated_block) { - eval_result_t result = eval_result_t::ok; + parse_execution_result_t result = parse_execution_success; tnode_t cursor = job_expr; // continuation is the parent of the cursor tnode_t continuation; @@ -1386,20 +1391,20 @@ bool parse_execution_context_t::should_skip(parse_bool_statement_type_t type) co } template -eval_result_t parse_execution_context_t::run_job_list(tnode_t job_list, - const block_t *associated_block) { +parse_execution_result_t parse_execution_context_t::run_job_list(tnode_t job_list, + const block_t *associated_block) { // We handle both job_list and andor_job_list uniformly. static_assert(Type::token == symbol_job_list || Type::token == symbol_andor_job_list, "Not a job list"); - eval_result_t result = eval_result_t::ok; + parse_execution_result_t result = parse_execution_success; while (auto job_conj = job_list.template next_in_list()) { if (should_cancel_execution(associated_block)) break; // Maybe skip the job if it has a leading and/or. // Skipping is treated as success. if (should_skip(get_decorator(job_conj))) { - result = eval_result_t::ok; + result = parse_execution_success; } else { result = this->run_job_conjunction(job_conj, associated_block); } @@ -1409,11 +1414,11 @@ eval_result_t parse_execution_context_t::run_job_list(tnode_t job_list, return result; } -eval_result_t parse_execution_context_t::eval_node(tnode_t statement, - const block_t *associated_block) { +parse_execution_result_t parse_execution_context_t::eval_node(tnode_t statement, + const block_t *associated_block) { assert(statement && "Empty node in eval_node"); assert(statement.matches_node_tree(tree()) && "statement has unexpected tree"); - enum eval_result_t status = eval_result_t::ok; + enum parse_execution_result_t status = parse_execution_success; if (auto block = statement.try_get_child()) { status = this->run_block_statement(block, associated_block); } else if (auto ifstat = statement.try_get_child()) { @@ -1428,8 +1433,8 @@ eval_result_t parse_execution_context_t::eval_node(tnode_t stateme return status; } -eval_result_t parse_execution_context_t::eval_node(tnode_t job_list, - const block_t *associated_block) { +parse_execution_result_t parse_execution_context_t::eval_node(tnode_t job_list, + const block_t *associated_block) { // Apply this block IO for the duration of this function. assert(job_list && "Empty node in eval_node"); assert(job_list.matches_node_tree(tree()) && "job_list has unexpected tree"); diff --git a/src/parse_execution.h b/src/parse_execution.h index 4c577663e..b9018f8ff 100644 --- a/src/parse_execution.h +++ b/src/parse_execution.h @@ -13,18 +13,14 @@ class block_t; class parser_t; -/// An eval_result represents evaluation errors including wildcards which failed to match, syntax -/// errors, or other expansion errors. It also tracks when evaluation was skipped due to signal -/// cancellation. Note it does not track the exit status of commands. -enum class eval_result_t { - /// Evaluation was successfull. - ok, - - /// Evaluation was cancelled, e.g. because of a signal. - cancelled, - - /// A parse error or failed expansion (but not an error exit status from a command). - error, +enum parse_execution_result_t { + /// The job was successfully executed (though it have failed on its own). + parse_execution_success, + /// The job did not execute due to some error (e.g. failed to wildcard expand). An error will + /// have been printed and proc_last_status will have been set. + parse_execution_errored, + /// The job was cancelled (e.g. Ctrl-C). + parse_execution_cancelled, }; class parse_execution_context_t { @@ -55,17 +51,18 @@ class parse_execution_context_t { }; execution_cancellation_reason_t cancellation_reason(const block_t *block) const; - // Report an error. Always returns 'eval_result_t::error'. - eval_result_t report_error(const parse_node_t &node, const wchar_t *fmt, ...) const; - eval_result_t report_errors(const parse_error_list_t &error_list) const; + // Report an error. Always returns true. + parse_execution_result_t report_error(const parse_node_t &node, const wchar_t *fmt, ...) const; + parse_execution_result_t report_errors(const parse_error_list_t &error_list) const; // Wildcard error helper. - eval_result_t report_unmatched_wildcard_error(const parse_node_t &unmatched_wildcard) const; + parse_execution_result_t report_unmatched_wildcard_error( + const parse_node_t &unmatched_wildcard) const; /// Command not found support. - eval_result_t handle_command_not_found(const wcstring &cmd, - tnode_t statement, - int err_code); + parse_execution_result_t handle_command_not_found(const wcstring &cmd, + tnode_t statement, + int err_code); // Utilities wcstring get_source(const parse_node_t &node) const; @@ -75,8 +72,8 @@ class parse_execution_context_t { // Expand a command which may contain variables, producing an expand command and possibly // arguments. Prints an error message on error. - eval_result_t expand_command(tnode_t statement, wcstring *out_cmd, - wcstring_list_t *out_args) const; + parse_execution_result_t expand_command(tnode_t statement, + wcstring *out_cmd, wcstring_list_t *out_args) const; /// Return whether we should skip a job with the given bool statement type. bool should_skip(parse_bool_statement_type_t type) const; @@ -86,57 +83,58 @@ class parse_execution_context_t { enum process_type_t process_type_for_command(tnode_t statement, const wcstring &cmd) const; - eval_result_t apply_variable_assignments( + parse_execution_result_t apply_variable_assignments( process_t *proc, tnode_t variable_assignments, const block_t **block); // These create process_t structures from statements. - eval_result_t populate_job_process(job_t *job, process_t *proc, - tnode_t statement, - tnode_t variable_assignments); - eval_result_t populate_not_process(job_t *job, process_t *proc, - tnode_t not_statement); - eval_result_t populate_plain_process(job_t *job, process_t *proc, - tnode_t statement); + parse_execution_result_t populate_job_process( + job_t *job, process_t *proc, tnode_t statement, + tnode_t variable_assignments); + parse_execution_result_t populate_not_process(job_t *job, process_t *proc, + tnode_t not_statement); + parse_execution_result_t populate_plain_process(job_t *job, process_t *proc, + tnode_t statement); template - eval_result_t populate_block_process(job_t *job, process_t *proc, - tnode_t statement, - tnode_t specific_statement); + parse_execution_result_t populate_block_process(job_t *job, process_t *proc, + tnode_t statement, + tnode_t specific_statement); // These encapsulate the actual logic of various (block) statements. - eval_result_t run_block_statement(tnode_t statement, - const block_t *associated_block); - eval_result_t run_for_statement(tnode_t header, - tnode_t contents); - eval_result_t run_if_statement(tnode_t statement, - const block_t *associated_block); - eval_result_t run_switch_statement(tnode_t statement); - eval_result_t run_while_statement(tnode_t header, - tnode_t contents, - const block_t *associated_block); - eval_result_t run_function_statement(tnode_t header, - tnode_t body); - eval_result_t run_begin_statement(tnode_t contents); + parse_execution_result_t run_block_statement(tnode_t statement, + const block_t *associated_block); + parse_execution_result_t run_for_statement(tnode_t header, + tnode_t contents); + parse_execution_result_t run_if_statement(tnode_t statement, + const block_t *associated_block); + parse_execution_result_t run_switch_statement(tnode_t statement); + parse_execution_result_t run_while_statement(tnode_t header, + tnode_t contents, + const block_t *associated_block); + parse_execution_result_t run_function_statement(tnode_t header, + tnode_t body); + parse_execution_result_t run_begin_statement(tnode_t contents); enum globspec_t { failglob, nullglob }; using argument_node_list_t = std::vector>; - eval_result_t expand_arguments_from_nodes(const argument_node_list_t &argument_nodes, - wcstring_list_t *out_arguments, - globspec_t glob_behavior); + parse_execution_result_t expand_arguments_from_nodes(const argument_node_list_t &argument_nodes, + wcstring_list_t *out_arguments, + globspec_t glob_behavior); // Determines the list of redirections for a node. Returns none() on failure, for example, an // invalid fd. bool determine_redirections(tnode_t node, redirection_spec_list_t *out_redirs); - eval_result_t run_1_job(tnode_t job, const block_t *associated_block); - eval_result_t run_job_conjunction(tnode_t job_expr, - const block_t *associated_block); + parse_execution_result_t run_1_job(tnode_t job, const block_t *associated_block); + parse_execution_result_t run_job_conjunction(tnode_t job_expr, + const block_t *associated_block); template - eval_result_t run_job_list(tnode_t job_list_node, const block_t *associated_block); - eval_result_t populate_job_from_job_node(job_t *j, tnode_t job_node, - const block_t *associated_block); + parse_execution_result_t run_job_list(tnode_t job_list_node, + const block_t *associated_block); + parse_execution_result_t populate_job_from_job_node(job_t *j, tnode_t job_node, + const block_t *associated_block); // Returns the line number of the node. Not const since it touches cached_lineno_offset. int line_offset_of_node(tnode_t node); @@ -160,8 +158,10 @@ class parse_execution_context_t { /// Start executing at the given node. Returns 0 if there was no error, 1 if there was an /// error. - eval_result_t eval_node(tnode_t statement, const block_t *associated_block); - eval_result_t eval_node(tnode_t job_list, const block_t *associated_block); + parse_execution_result_t eval_node(tnode_t statement, + const block_t *associated_block); + parse_execution_result_t eval_node(tnode_t job_list, + const block_t *associated_block); }; #endif diff --git a/src/parser.cpp b/src/parser.cpp index b457718f4..1146fe1a3 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -674,12 +674,19 @@ eval_result_t parser_t::eval_node(parsed_source_ref_t ps, tnode_t node, block using exc_ctx_ref_t = std::unique_ptr; scoped_push exc( &execution_context, make_unique(ps, this, std::move(lineage))); - eval_result_t res = execution_context->eval_node(node, scope_block); + parse_execution_result_t res = execution_context->eval_node(node, scope_block); exc.restore(); this->pop_block(scope_block); job_reap(*this, false); // reap again - return res; + switch (res) { + case parse_execution_success: + return eval_result_t::ok; + case parse_execution_errored: + return eval_result_t::error; + case parse_execution_cancelled: + return eval_result_t::cancelled; + } } // Explicit instantiations. TODO: use overloads instead? diff --git a/src/parser.h b/src/parser.h index 41aff1176..bbe1c1eff 100644 --- a/src/parser.h +++ b/src/parser.h @@ -15,7 +15,6 @@ #include "event.h" #include "expand.h" #include "parse_constants.h" -#include "parse_execution.h" #include "parse_tree.h" #include "proc.h" @@ -54,6 +53,18 @@ enum class loop_status_t { continues, /// current loop block should be skipped }; +/// Result of the source code form of eval. +enum class eval_result_t { + /// eval was able to evaluate the source or tree. + ok, + + /// Evaluation was cancelled, e.g. because of a signal. + cancelled, + + /// Parse or execution error (but not simply a failed command). + error, +}; + /// block_t represents a block of commands. class block_t { /// Construct from a block type.