diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index 34b637e30..56d3dd850 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -170,13 +170,12 @@ tnode_t parse_execution_context_t::infinite_recursive_statem } enum process_type_t parse_execution_context_t::process_type_for_command( - const parse_node_t &plain_statement, const wcstring &cmd) const { - assert(plain_statement.type == symbol_plain_statement); + tnode_t statement, const wcstring &cmd) const { enum process_type_t process_type = EXTERNAL; // Determine the process type, which depends on the statement decoration (command, builtin, // etc). - enum parse_statement_decoration_t decoration = get_decoration({&tree(), &plain_statement}); + enum parse_statement_decoration_t decoration = get_decoration(statement); if (decoration == parse_statement_decoration_exec) { // Always exec. @@ -342,8 +341,10 @@ parse_execution_result_t parse_execution_context_t::run_begin_statement( parse_execution_result_t parse_execution_context_t::run_function_statement( tnode_t header, tnode_t block_end_command) { // Get arguments. - wcstring_list_t argument_list; - parse_execution_result_t result = this->determine_arguments(header, &argument_list, failglob); + wcstring_list_t arguments; + argument_node_list_t arg_nodes = header.descendants(); + parse_execution_result_t result = + this->expand_arguments_from_nodes(arg_nodes, &arguments, failglob); if (result != parse_execution_success) { return result; @@ -371,8 +372,7 @@ parse_execution_result_t parse_execution_context_t::run_function_statement( wcstring(pstree->src, contents_start, contents_end - contents_start); int definition_line_offset = this->line_offset_of_character_at_offset(contents_start); io_streams_t streams(0); // no limit on the amount of output from builtin_function() - int err = - builtin_function(*parser, streams, argument_list, contents_str, definition_line_offset); + int err = builtin_function(*parser, streams, arguments, contents_str, definition_line_offset); proc_set_last_status(err); if (!streams.err.empty()) { @@ -426,8 +426,9 @@ parse_execution_result_t parse_execution_context_t::run_for_statement( } // Get the contents to iterate over. - wcstring_list_t argument_sequence; - parse_execution_result_t ret = this->determine_arguments(header, &argument_sequence, nullglob); + wcstring_list_t arguments; + 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; } @@ -446,14 +447,12 @@ parse_execution_result_t parse_execution_context_t::run_for_statement( for_block_t *fb = parser->push_block(); // Now drive the for loop. - const size_t arg_count = argument_sequence.size(); - for (size_t i = 0; i < arg_count; i++) { + for (const wcstring &val : arguments) { if (should_cancel_execution(fb)) { ret = parse_execution_cancelled; break; } - const wcstring &val = argument_sequence.at(i); int retval = env_set_one(for_var_name, ENV_DEFAULT | ENV_USER, val); assert(retval == ENV_OK && "for loop variable should have been successfully set"); (void)retval; @@ -534,15 +533,13 @@ parse_execution_result_t parse_execution_context_t::run_switch_statement( break; } - // Pull out the argument list. - auto arg_list = case_item.child<1>(); - // Expand arguments. A case item list may have a wildcard that fails to expand to // anything. We also report case errors, but don't stop execution; i.e. a case item that // 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; parse_execution_result_t case_result = - this->determine_arguments(arg_list, &case_args, failglob); + this->expand_arguments_from_nodes(arg_nodes, &case_args, failglob); if (case_result == parse_execution_success) { for (const wcstring &arg : case_args) { // Unescape wildcards so they can be expanded again. @@ -743,8 +740,9 @@ parse_execution_result_t parse_execution_context_t::handle_command_not_found( // error messages. wcstring_list_t event_args; { + auto args = get_argument_nodes(statement.child<1>()); parse_execution_result_t arg_result = - this->determine_arguments(statement, &event_args, failglob); + this->expand_arguments_from_nodes(args, &event_args, failglob); if (arg_result != parse_execution_success) { return arg_result; @@ -836,8 +834,9 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process( } else { const globspec_t glob_behavior = (cmd == L"set" || cmd == L"count") ? nullglob : failglob; // Form the list of arguments. The command is the first argument. + argument_node_list_t arg_nodes = statement.descendants(); parse_execution_result_t arg_result = - this->determine_arguments(statement, &argument_list, glob_behavior); + this->expand_arguments_from_nodes(arg_nodes, &argument_list, glob_behavior); if (arg_result != parse_execution_success) { return arg_result; } @@ -862,17 +861,14 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process( // 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. -parse_execution_result_t parse_execution_context_t::determine_arguments( - const parse_node_t &parent, wcstring_list_t *out_arguments, globspec_t glob_behavior) { +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 // may have more or fewer, if there are wildcards involved). - const parse_node_tree_t::parse_node_list_t argument_nodes = - tree().find_nodes(parent, symbol_argument); out_arguments->reserve(out_arguments->size() + argument_nodes.size()); std::vector arg_expanded; - for (size_t i = 0; i < argument_nodes.size(); i++) { - const parse_node_t &arg_node = *argument_nodes.at(i); - + for (const auto arg_node : argument_nodes) { // Expect all arguments to have source. assert(arg_node.has_source()); const wcstring arg_str = arg_node.get_source(pstree->src); @@ -881,7 +877,7 @@ parse_execution_result_t parse_execution_context_t::determine_arguments( parse_error_list_t errors; arg_expanded.clear(); int expand_ret = expand_string(arg_str, &arg_expanded, EXPAND_NO_DESCRIPTIONS, &errors); - parse_error_offset_source_start(&errors, arg_node.source_start); + parse_error_offset_source_start(&errors, arg_node.source_range()->start); switch (expand_ret) { case EXPAND_ERROR: { this->report_errors(errors); diff --git a/src/parse_execution.h b/src/parse_execution.h index 6fbbc7347..52d4f3b30 100644 --- a/src/parse_execution.h +++ b/src/parse_execution.h @@ -80,7 +80,7 @@ class parse_execution_context_t { /// Indicates whether a job is a simple block (one block, no redirections). bool job_is_simple_block(const parse_node_t &node) const; - enum process_type_t process_type_for_command(const parse_node_t &plain_statement, + enum process_type_t process_type_for_command(tnode_t statement, const wcstring &cmd) const; // These create process_t structures from statements. @@ -107,9 +107,10 @@ class parse_execution_context_t { tnode_t contents); enum globspec_t { failglob, nullglob }; - parse_execution_result_t determine_arguments(const parse_node_t &parent, - wcstring_list_t *out_arguments, - globspec_t glob_behavior); + using argument_node_list_t = std::vector>; + 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 IO chain. Returns true on success, false on error. bool determine_io_chain(const parse_node_t &statement, io_chain_t *out_chain); diff --git a/src/parse_tree.cpp b/src/parse_tree.cpp index 985aa4330..bb01aec7d 100644 --- a/src/parse_tree.cpp +++ b/src/parse_tree.cpp @@ -1485,3 +1485,11 @@ maybe_t command_for_plain_statement(tnode_t } return none(); } + +arguments_node_list_t get_argument_nodes(tnode_t list) { + return list.descendants(); +} + +arguments_node_list_t get_argument_nodes(tnode_t list) { + return list.descendants(); +} diff --git a/src/parse_tree.h b/src/parse_tree.h index 6b870c571..ab0b3a8ce 100644 --- a/src/parse_tree.h +++ b/src/parse_tree.h @@ -428,6 +428,11 @@ parse_statement_decoration_t get_decoration(tnode_t st /// Return the type for a boolean statement. enum parse_bool_statement_type_t bool_statement_type(tnode_t stmt); +/// Return the arguments under an arguments_list or arguments_or_redirection_list +using arguments_node_list_t = std::vector>; +arguments_node_list_t get_argument_nodes(tnode_t); +arguments_node_list_t get_argument_nodes(tnode_t); + /// 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,