diff --git a/CMakeLists.txt b/CMakeLists.txt index 99c24f516..0179915f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,7 +77,7 @@ SET(FISH_SRCS src/builtin_random.cpp src/builtin_read.cpp src/builtin_realpath.cpp src/builtin_return.cpp src/builtin_set.cpp src/builtin_set_color.cpp src/builtin_source.cpp src/builtin_status.cpp src/builtin_string.cpp - src/builtin_test.cpp src/builtin_ulimit.cpp src/builtin_wait.cpp + src/builtin_test.cpp src/builtin_ulimit.cpp src/builtin_wait.cpp src/builtin_eval.cpp src/color.cpp src/common.cpp src/complete.cpp src/env.cpp src/env_dispatch.cpp src/env_universal_common.cpp src/event.cpp src/exec.cpp src/expand.cpp src/fallback.cpp src/fish_version.cpp src/function.cpp src/highlight.cpp diff --git a/share/functions/eval.fish b/share/functions/eval.fish deleted file mode 100644 index 42013f764..000000000 --- a/share/functions/eval.fish +++ /dev/null @@ -1,12 +0,0 @@ -# This empty function is required as while `eval` is implemented internally as -# a decorator, unlike other decorators such as `command` or `builtin`, it is -# *not* stripped from the statement by the parser before execution to internal -# quirks in how statements are handled; the presence of this function allows -# constructs such as command substitution to be used in the head of an -# evaluated statement. -# -# The function defined below is only executed if a bare `eval` is executed (with -# no arguments), in all other cases it is bypassed entirely. - -function eval -end diff --git a/src/builtin.cpp b/src/builtin.cpp index d2b545536..4179e0f63 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -41,6 +41,7 @@ #include "builtin_disown.h" #include "builtin_echo.h" #include "builtin_emit.h" +#include "builtin_eval.h" #include "builtin_exit.h" #include "builtin_fg.h" #include "builtin_functions.h" @@ -381,6 +382,7 @@ static const builtin_data_t builtin_datas[] = { {L"else", &builtin_generic, N_(L"Evaluate block if condition is false")}, {L"emit", &builtin_emit, N_(L"Emit an event")}, {L"end", &builtin_generic, N_(L"End a block of commands")}, + {L"eval", &builtin_eval, N_(L"Evaluate a string as a statement")}, {L"exec", &builtin_generic, N_(L"Run command in current process")}, {L"exit", &builtin_exit, N_(L"Exit the shell")}, {L"false", &builtin_false, N_(L"Return an unsuccessful result")}, diff --git a/src/builtin_eval.cpp b/src/builtin_eval.cpp new file mode 100644 index 000000000..7beb1e9a8 --- /dev/null +++ b/src/builtin_eval.cpp @@ -0,0 +1,45 @@ +// Functions for executing the jobs builtin. +#include "config.h" // IWYU pragma: keep + +#include +#include +#ifdef HAVE__PROC_SELF_STAT +#include +#endif + +#include "builtin.h" +#include "common.h" +#include "fallback.h" // IWYU pragma: keep +#include "io.h" +#include "parser.h" +#include "proc.h" +#include "wgetopt.h" +#include "wutil.h" // IWYU pragma: keep + +class parser_t; + +/// The jobs builtin. Used for printing running jobs. Defined in builtin_jobs.c. +int builtin_eval(parser_t &parser, io_streams_t &streams, wchar_t **argv) { + wchar_t *cmd = argv[0]; + int argc = builtin_count_args(argv); + + wcstring new_cmd; + for (size_t i = 1; i < argc; ++i) { + new_cmd += L' '; + new_cmd += argv[i]; + } + + // debug(1, "new_cmd: %ls", new_cmd.c_str()); + + auto status = proc_get_last_status(); + if (argc > 1) { + if (parser.eval(new_cmd.c_str(), *streams.io_chain, block_type_t::TOP) != 0) { + return STATUS_CMD_ERROR; + } + status = proc_get_last_status(); + } else { + status = STATUS_CMD_OK; + } + + return status; +} diff --git a/src/builtin_eval.h b/src/builtin_eval.h new file mode 100644 index 000000000..6cceaacc3 --- /dev/null +++ b/src/builtin_eval.h @@ -0,0 +1,9 @@ +// Prototypes for executing builtin_eval function. +#ifndef FISH_BUILTIN_EVAL_H +#define FISH_BUILTIN_EVAL_H + +class parser_t; +struct io_streams_t; + +int builtin_eval(parser_t &parser, io_streams_t &streams, wchar_t **argv); +#endif diff --git a/src/complete.cpp b/src/complete.cpp index ddec89ca2..d4091855d 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -1465,14 +1465,6 @@ void completer_t::perform() { use_abbr = false; break; } - case parse_statement_decoration_eval: { - use_command = true; - use_function = true; - use_builtin = true; - use_implicit_cd = true; - use_abbr = true; - break; - } } if (cmd_node.location_in_or_at_end_of_source_range(pos)) { diff --git a/src/exec.cpp b/src/exec.cpp index 6a99cf225..4e01dbca3 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -982,29 +982,6 @@ static bool exec_process_in_job(parser_t &parser, process_t *p, std::shared_ptr< "Aborting."); break; } - - case process_type_t::eval: { - // int eval(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type); - bool has_args = false; - wcstring new_cmd; - for (const wchar_t * const* arg = p->get_argv() + 1; *arg != nullptr; ++arg) { - has_args = true; - new_cmd += L' '; - new_cmd += *arg; - } - - // `eval` is not supposed to error or do anything at all if no arguments are provided, - // or if it is used to execute a function that wouldn't have changed the status code - // (e.g. an empty function) if it were executed normally. - j->processes[0]->completed = true; - p->status = proc_status_t::from_exit_code(cached_status); - - if (has_args) { - parser.eval(new_cmd.c_str(), process_net_io_chain, block_type_t::TOP); - p->status = proc_status_t::from_exit_code(proc_get_last_status()); - } - break; - } } return true; } diff --git a/src/parse_constants.h b/src/parse_constants.h index 2f86f05fd..2879bc251 100644 --- a/src/parse_constants.h +++ b/src/parse_constants.h @@ -104,7 +104,6 @@ enum parse_keyword_t { parse_keyword_command, parse_keyword_else, parse_keyword_end, - parse_keyword_eval, parse_keyword_exclam, parse_keyword_exec, parse_keyword_for, @@ -126,7 +125,6 @@ const enum_map keyword_enum_map[] = {{parse_keyword_exclam, L"! {parse_keyword_command, L"command"}, {parse_keyword_else, L"else"}, {parse_keyword_end, L"end"}, - {parse_keyword_eval, L"eval"}, {parse_keyword_exec, L"exec"}, {parse_keyword_for, L"for"}, {parse_keyword_function, L"function"}, @@ -147,7 +145,6 @@ enum parse_statement_decoration_t { parse_statement_decoration_command, parse_statement_decoration_builtin, parse_statement_decoration_exec, - parse_statement_decoration_eval, }; // Boolean statement types, stored in node tag. diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index 51bf0f3cf..694c50fb3 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -161,9 +161,6 @@ process_type_t parse_execution_context_t::process_type_for_command( case parse_statement_decoration_builtin: process_type = process_type_t::builtin; break; - case parse_statement_decoration_eval: - process_type = process_type_t::eval; - break; case parse_statement_decoration_none: if (function_exists(cmd)) { process_type = process_type_t::function; diff --git a/src/parse_grammar.h b/src/parse_grammar.h index 5a3c5f0ce..b6b1cb2ee 100644 --- a/src/parse_grammar.h +++ b/src/parse_grammar.h @@ -334,16 +334,7 @@ DEF_ALT(decorated_statement) { using cmds = seq, plain_statement>; using builtins = seq, plain_statement>; using execs = seq, plain_statement>; - // Ideally, `evals` should be defined as `seq, - // arguments_or_redirections_list`, but other parts of the code have the logic hard coded to - // search for a process at the head of a statement, and bug out if we do that. - // We also can't define `evals` as a `seq, plain_statement>` because - // `expand.cpp` hard-codes its "command substitution at the head of a statement is not allowed" - // check without any way of telling it to perform the substitution anyway. Our solution is to - // create an empty function called `eval` that never actually gets executed and convert a - // decorated statement `eval ...` into a plain statement `eval ...` - using evals = seq; - ALT_BODY(decorated_statement, plains, cmds, builtins, execs, evals); + ALT_BODY(decorated_statement, plains, cmds, builtins, execs); }; DEF(plain_statement) diff --git a/src/parse_productions.cpp b/src/parse_productions.cpp index 2e60f3b46..4718d826a 100644 --- a/src/parse_productions.cpp +++ b/src/parse_productions.cpp @@ -314,10 +314,6 @@ RESOLVE(decorated_statement) { *out_tag = parse_statement_decoration_exec; return production_for(); } - case parse_keyword_eval: { - *out_tag = parse_statement_decoration_eval; - return production_for(); - } default: { *out_tag = parse_statement_decoration_none; return production_for(); diff --git a/src/proc.h b/src/proc.h index abca58465..c39e1a123 100644 --- a/src/proc.h +++ b/src/proc.h @@ -36,8 +36,6 @@ enum class process_type_t { block_node, /// The exec builtin. exec, - /// A literal evaluation - eval, }; enum class job_control_t {