mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-13 21:44:16 +00:00
Make block_type_t an enum class
This commit is contained in:
parent
4529e7d183
commit
a59f35a378
13 changed files with 129 additions and 124 deletions
|
@ -165,7 +165,7 @@ void builtin_print_help(parser_t &parser, io_streams_t &streams, const wchar_t *
|
|||
// If it's an error, redirect the output of __fish_print_help to stderr
|
||||
ios.push_back(std::make_shared<io_fd_t>(STDOUT_FILENO, STDERR_FILENO));
|
||||
}
|
||||
parser.eval(cmd, ios, TOP);
|
||||
parser.eval(cmd, ios, block_type_t::top);
|
||||
// ignore the exit status of __fish_print_help
|
||||
}
|
||||
|
||||
|
@ -265,11 +265,11 @@ static int builtin_break_continue(parser_t &parser, io_streams_t &streams, wchar
|
|||
// Paranoia: ensure we have a real loop.
|
||||
bool has_loop = false;
|
||||
for (const auto &b : parser.blocks()) {
|
||||
if (b.type() == WHILE || b.type() == FOR) {
|
||||
if (b.type() == block_type_t::while_block || b.type() == block_type_t::for_block) {
|
||||
has_loop = true;
|
||||
break;
|
||||
}
|
||||
if (b.is_function()) break;
|
||||
if (b.is_function_call()) break;
|
||||
}
|
||||
if (!has_loop) {
|
||||
wcstring error_message = format_string(_(L"%ls: Not inside of loop\n"), argv[0]);
|
||||
|
@ -298,7 +298,7 @@ static int builtin_breakpoint(parser_t &parser, io_streams_t &streams, wchar_t *
|
|||
// Ensure we don't allow creating a breakpoint at an interactive prompt. There may be a simpler
|
||||
// or clearer way to do this but this works.
|
||||
const block_t *block1 = parser.block_at_index(1);
|
||||
if (!block1 || block1->type() == BREAKPOINT) {
|
||||
if (!block1 || block1->type() == block_type_t::breakpoint) {
|
||||
streams.err.append_format(_(L"%ls: Command not valid at an interactive prompt\n"), cmd);
|
||||
return STATUS_ILLEGAL_CMD;
|
||||
}
|
||||
|
|
|
@ -117,8 +117,7 @@ int builtin_block(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
break;
|
||||
}
|
||||
case UNSET: {
|
||||
while (block != nullptr && block->type() != FUNCTION_CALL &&
|
||||
block->type() != FUNCTION_CALL_NO_SHADOW) {
|
||||
while (block && !block->is_function_call()) {
|
||||
// Set it in function scope
|
||||
block = parser.block_at_index(++block_idx);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ int builtin_eval(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
const auto cached_exec_count = parser.libdata().exec_count;
|
||||
int status = STATUS_CMD_OK;
|
||||
if (argc > 1) {
|
||||
if (parser.eval(std::move(new_cmd), *streams.io_chain, block_type_t::TOP) !=
|
||||
if (parser.eval(std::move(new_cmd), *streams.io_chain, block_type_t::top) !=
|
||||
eval_result_t::ok) {
|
||||
status = STATUS_CMD_ERROR;
|
||||
} else if (cached_exec_count == parser.libdata().exec_count) {
|
||||
|
|
|
@ -93,7 +93,7 @@ int builtin_return(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
// Find the function block.
|
||||
bool has_function_block = false;
|
||||
for (const auto &b : parser.blocks()) {
|
||||
if (b.is_function()) {
|
||||
if (b.is_function_call()) {
|
||||
has_function_block = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -286,7 +286,7 @@ static void event_fire_internal(parser_t &parser, const event_t &event) {
|
|||
auto prev_statuses = parser.get_last_statuses();
|
||||
|
||||
block_t *b = parser.push_block(block_t::event_block(event));
|
||||
parser.eval(buffer, io_chain_t(), TOP);
|
||||
parser.eval(buffer, io_chain_t(), block_type_t::top);
|
||||
parser.pop_block(b);
|
||||
parser.set_last_statuses(std::move(prev_statuses));
|
||||
}
|
||||
|
|
|
@ -733,7 +733,7 @@ static proc_performer_t get_performer_for_process(process_t *p, const job_t *job
|
|||
tnode_t<grammar::statement> node = p->internal_block_node;
|
||||
assert(source && node && "Process is missing node info");
|
||||
return [=](parser_t &parser) {
|
||||
eval_result_t res = parser.eval_node(source, node, TOP, lineage);
|
||||
eval_result_t res = parser.eval_node(source, node, block_type_t::top, lineage);
|
||||
switch (res) {
|
||||
case eval_result_t::ok:
|
||||
case eval_result_t::error:
|
||||
|
@ -758,7 +758,8 @@ static proc_performer_t get_performer_for_process(process_t *p, const job_t *job
|
|||
const auto &ld = parser.libdata();
|
||||
auto saved_exec_count = ld.exec_count;
|
||||
const block_t *fb = function_prepare_environment(parser, *argv, *props);
|
||||
auto res = parser.eval_node(props->parsed_source, props->body_node, TOP, lineage);
|
||||
auto res = parser.eval_node(props->parsed_source, props->body_node, block_type_t::top,
|
||||
lineage);
|
||||
function_restore_environment(parser, fb);
|
||||
|
||||
switch (res) {
|
||||
|
@ -1175,7 +1176,7 @@ static int exec_subshell_internal(const wcstring &cmd, parser_t &parser, wcstrin
|
|||
// be null.
|
||||
std::shared_ptr<io_buffer_t> buffer;
|
||||
if (auto bufferfill = io_bufferfill_t::create(fd_set_t{}, ld.read_limit)) {
|
||||
if (parser.eval(cmd, io_chain_t{bufferfill}, SUBST) == eval_result_t::ok) {
|
||||
if (parser.eval(cmd, io_chain_t{bufferfill}, block_type_t::subst) == eval_result_t::ok) {
|
||||
subcommand_statuses = parser.get_last_statuses();
|
||||
}
|
||||
buffer = io_bufferfill_t::finish(std::move(bufferfill));
|
||||
|
|
|
@ -228,7 +228,7 @@ static void source_config_in_directory(const wcstring &dir) {
|
|||
const wcstring cmd = L"builtin source " + escaped_pathname;
|
||||
parser_t &parser = parser_t::principal_parser();
|
||||
set_is_within_fish_initialization(true);
|
||||
parser.eval(cmd, io_chain_t(), TOP);
|
||||
parser.eval(cmd, io_chain_t(), block_type_t::top);
|
||||
set_is_within_fish_initialization(false);
|
||||
}
|
||||
|
||||
|
@ -254,7 +254,7 @@ int run_command_list(std::vector<std::string> *cmds, const io_chain_t &io) {
|
|||
|
||||
for (const auto &cmd : *cmds) {
|
||||
const wcstring cmd_wcs = str2wcstring(cmd);
|
||||
eval_result_t eval_res = parser.eval(cmd_wcs, io, TOP);
|
||||
eval_result_t eval_res = parser.eval(cmd_wcs, io, block_type_t::top);
|
||||
res = (eval_res == eval_result_t::ok ? 0 : 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -1003,16 +1003,17 @@ static void test_parser() {
|
|||
// Ensure that we don't crash on infinite self recursion and mutual recursion. These must use
|
||||
// the principal parser because we cannot yet execute jobs on other parsers.
|
||||
say(L"Testing recursion detection");
|
||||
parser->eval(L"function recursive ; recursive ; end ; recursive; ", io_chain_t(), TOP);
|
||||
parser->eval(L"function recursive ; recursive ; end ; recursive; ", io_chain_t(),
|
||||
block_type_t::top);
|
||||
#if 0
|
||||
// This is disabled since it produces a long backtrace. We should find a way to either visually
|
||||
// compress the backtrace, or disable error spewing.
|
||||
parser->.eval(L"function recursive1 ; recursive2 ; end ; "
|
||||
L"function recursive2 ; recursive1 ; end ; recursive1; ", io_chain_t(), TOP);
|
||||
L"function recursive2 ; recursive1 ; end ; recursive1; ", io_chain_t(), block_type_t::top);
|
||||
#endif
|
||||
|
||||
say(L"Testing empty function name");
|
||||
parser->eval(L"function '' ; echo fail; exit 42 ; end ; ''", io_chain_t(), TOP);
|
||||
parser->eval(L"function '' ; echo fail; exit 42 ; end ; ''", io_chain_t(), block_type_t::top);
|
||||
|
||||
say(L"Testing eval_args");
|
||||
completion_list_t comps = parser_t::expand_argument_list(
|
||||
|
@ -1032,7 +1033,8 @@ static void test_1_cancellation(const wchar_t *src) {
|
|||
usleep(delay * 1E6);
|
||||
pthread_kill(thread, SIGINT);
|
||||
});
|
||||
eval_result_t ret = parser_t::principal_parser().eval(src, io_chain_t{filler}, TOP);
|
||||
eval_result_t ret =
|
||||
parser_t::principal_parser().eval(src, io_chain_t{filler}, block_type_t::top);
|
||||
auto buffer = io_bufferfill_t::finish(std::move(filler));
|
||||
if (buffer->buffer().size() != 0) {
|
||||
err(L"Expected 0 bytes in out_buff, but instead found %lu bytes, for command %ls\n",
|
||||
|
@ -1074,7 +1076,7 @@ static void test_cancellation() {
|
|||
bool iis = is_interactive_session();
|
||||
set_interactive_session(true);
|
||||
const wchar_t *child_self_destructor = L"while true ; sh -c 'sleep .25; kill -s INT $$' ; end";
|
||||
parser_t::principal_parser().eval(child_self_destructor, io_chain_t(), TOP);
|
||||
parser_t::principal_parser().eval(child_self_destructor, io_chain_t(), block_type_t::top);
|
||||
set_interactive_session(iis);
|
||||
|
||||
// Restore signal handling.
|
||||
|
@ -5198,7 +5200,7 @@ static void test_illegal_command_exit_code() {
|
|||
parser_t &parser = parser_t::principal_parser();
|
||||
|
||||
for (const auto &test : tests) {
|
||||
parser.eval(test.txt, empty_ios, TOP);
|
||||
parser.eval(test.txt, empty_ios, block_type_t::top);
|
||||
|
||||
int exit_status = parser.get_last_status();
|
||||
if (exit_status != test.result) {
|
||||
|
|
|
@ -389,7 +389,7 @@ void inputter_t::mapping_execute(const input_mapping_t &m, bool allow_commands)
|
|||
// see that until all other commands have also been run.
|
||||
auto last_statuses = parser_->get_last_statuses();
|
||||
for (const wcstring &cmd : m.commands) {
|
||||
parser_->eval(cmd, io_chain_t(), TOP);
|
||||
parser_->eval(cmd, io_chain_t(), block_type_t::top);
|
||||
}
|
||||
parser_->set_last_statuses(std::move(last_statuses));
|
||||
event_queue_.push_front(char_event_type_t::check_exit);
|
||||
|
|
|
@ -105,7 +105,7 @@ tnode_t<g::plain_statement> parse_execution_context_t::infinite_recursive_statem
|
|||
// on function invocation changes, then this check will break.
|
||||
const block_t *current = parser->block_at_index(0), *parent = parser->block_at_index(1);
|
||||
bool is_within_function_call =
|
||||
(current && parent && current->type() == TOP && parent->type() == FUNCTION_CALL);
|
||||
(current && parent && current->type() == block_type_t::top && parent->is_function_call());
|
||||
if (!is_within_function_call) {
|
||||
return {};
|
||||
}
|
||||
|
@ -322,7 +322,7 @@ eval_result_t parse_execution_context_t::run_if_statement(tnode_t<g::if_statemen
|
|||
eval_result_t parse_execution_context_t::run_begin_statement(tnode_t<g::job_list> 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));
|
||||
block_t *sb = parser->push_block(block_t::scope_block(block_type_t::begin));
|
||||
eval_result_t ret = run_job_list(contents, sb);
|
||||
parser->pop_block(sb);
|
||||
trace_if_enabled(*parser, L"end begin");
|
||||
|
@ -380,7 +380,7 @@ bool parse_execution_context_t::is_function_context() const {
|
|||
const block_t *current = parser->block_at_index(0);
|
||||
const block_t *parent = parser->block_at_index(1);
|
||||
bool is_within_function_call =
|
||||
(current && parent && current->type() == TOP && parent->type() == FUNCTION_CALL);
|
||||
(current && parent && current->type() == block_type_t::top && parent->is_function_call());
|
||||
return is_within_function_call;
|
||||
}
|
||||
|
||||
|
@ -1461,7 +1461,7 @@ eval_result_t parse_execution_context_t::eval_node(tnode_t<g::job_list> job_list
|
|||
}
|
||||
|
||||
// Check for stack overflow. The TOP check ensures we only do this for function calls.
|
||||
if (associated_block->type() == TOP && parser->function_stack_is_overflowing()) {
|
||||
if (associated_block->type() == block_type_t::top && parser->function_stack_is_overflowing()) {
|
||||
return this->report_error(job_list, CALL_STACK_LIMIT_EXCEEDED_ERR_MSG);
|
||||
}
|
||||
return this->run_job_list(job_list, associated_block);
|
||||
|
|
160
src/parser.cpp
160
src/parser.cpp
|
@ -75,33 +75,6 @@ class io_chain_t;
|
|||
/// Unknown block description.
|
||||
#define UNKNOWN_BLOCK N_(L"unknown/invalid block")
|
||||
|
||||
/// Data structure to describe a block type, like while blocks, command substitution blocks, etc.
|
||||
struct block_lookup_entry {
|
||||
// The block type id. The legal values are defined in parser.h.
|
||||
block_type_t type;
|
||||
// The name of the builtin that creates this type of block, if any.
|
||||
const wchar_t *name;
|
||||
// A description of this block type.
|
||||
const wchar_t *desc;
|
||||
};
|
||||
|
||||
/// List of all legal block types.
|
||||
static const struct block_lookup_entry block_lookup[] = {
|
||||
{WHILE, L"while", WHILE_BLOCK},
|
||||
{FOR, L"for", FOR_BLOCK},
|
||||
{IF, L"if", IF_BLOCK},
|
||||
{FUNCTION_CALL, nullptr, FUNCTION_CALL_BLOCK},
|
||||
{FUNCTION_CALL_NO_SHADOW, nullptr, FUNCTION_CALL_NO_SHADOW_BLOCK},
|
||||
{SWITCH, L"switch", SWITCH_BLOCK},
|
||||
{TOP, nullptr, TOP_BLOCK},
|
||||
{SUBST, nullptr, SUBST_BLOCK},
|
||||
{BEGIN, L"begin", BEGIN_BLOCK},
|
||||
{SOURCE, L"source", SOURCE_BLOCK},
|
||||
{EVENT, nullptr, EVENT_BLOCK},
|
||||
{BREAKPOINT, L"breakpoint", BREAKPOINT_BLOCK},
|
||||
{VARIABLE_ASSIGNMENT, L"variable assignment", VARIABLE_ASSIGNMENT_BLOCK},
|
||||
{static_cast<block_type_t>(0), nullptr, nullptr}};
|
||||
|
||||
// Given a file path, return something nicer. Currently we just "unexpand" tildes.
|
||||
wcstring parser_t::user_presentable_path(const wcstring &path) const {
|
||||
return replace_home_directory_with_tilde(path, vars());
|
||||
|
@ -148,17 +121,18 @@ block_t *parser_t::push_block(block_t &&block) {
|
|||
new_current.src_filename = intern(filename);
|
||||
}
|
||||
|
||||
// Types TOP and SUBST are not considered blocks for the purposes of `status is-block`.
|
||||
if (type != TOP && type != SUBST) {
|
||||
// Types top and subst are not considered blocks for the purposes of `status is-block`.
|
||||
if (type != block_type_t::top && type != block_type_t::subst) {
|
||||
libdata().is_block = true;
|
||||
}
|
||||
|
||||
if (type == BREAKPOINT) {
|
||||
if (type == block_type_t::breakpoint) {
|
||||
libdata().is_breakpoint = true;
|
||||
}
|
||||
|
||||
if (new_current.type() != TOP) {
|
||||
vars().push(type == FUNCTION_CALL);
|
||||
if (new_current.type() != block_type_t::top) {
|
||||
bool shadow = (type == block_type_t::function_call);
|
||||
vars().push(shadow);
|
||||
new_current.wants_pop_env = true;
|
||||
}
|
||||
|
||||
|
@ -181,7 +155,7 @@ void parser_t::pop_block(const block_t *expected) {
|
|||
// Figure out if `status is-block` should consider us to be in a block now.
|
||||
bool new_is_block = false;
|
||||
for (const auto &b : block_list) {
|
||||
if (b.type() != TOP && b.type() != SUBST) {
|
||||
if (b.type() != block_type_t::top && b.type() != block_type_t::subst) {
|
||||
new_is_block = true;
|
||||
break;
|
||||
}
|
||||
|
@ -191,7 +165,7 @@ void parser_t::pop_block(const block_t *expected) {
|
|||
// Are we still in a breakpoint?
|
||||
bool new_is_breakpoint = false;
|
||||
for (const auto &b : block_list) {
|
||||
if (b.type() == BREAKPOINT) {
|
||||
if (b.type() == block_type_t::breakpoint) {
|
||||
new_is_breakpoint = true;
|
||||
break;
|
||||
}
|
||||
|
@ -199,11 +173,35 @@ void parser_t::pop_block(const block_t *expected) {
|
|||
libdata().is_breakpoint = new_is_breakpoint;
|
||||
}
|
||||
|
||||
const wchar_t *parser_t::get_block_desc(int block) const {
|
||||
for (size_t i = 0; block_lookup[i].desc; i++) {
|
||||
if (block_lookup[i].type == block) {
|
||||
return _(block_lookup[i].desc);
|
||||
}
|
||||
const wchar_t *parser_t::get_block_desc(block_type_t block) {
|
||||
switch (block) {
|
||||
case block_type_t::while_block:
|
||||
return WHILE_BLOCK;
|
||||
case block_type_t::for_block:
|
||||
return FOR_BLOCK;
|
||||
case block_type_t::if_block:
|
||||
return IF_BLOCK;
|
||||
case block_type_t::function_call:
|
||||
return FUNCTION_CALL_BLOCK;
|
||||
|
||||
case block_type_t::function_call_no_shadow:
|
||||
return FUNCTION_CALL_NO_SHADOW_BLOCK;
|
||||
case block_type_t::switch_block:
|
||||
return SWITCH_BLOCK;
|
||||
case block_type_t::subst:
|
||||
return SUBST_BLOCK;
|
||||
case block_type_t::top:
|
||||
return TOP_BLOCK;
|
||||
case block_type_t::begin:
|
||||
return BEGIN_BLOCK;
|
||||
case block_type_t::source:
|
||||
return SOURCE_BLOCK;
|
||||
case block_type_t::event:
|
||||
return EVENT_BLOCK;
|
||||
case block_type_t::breakpoint:
|
||||
return BREAKPOINT_BLOCK;
|
||||
case block_type_t::variable_assignment:
|
||||
return VARIABLE_ASSIGNMENT_BLOCK;
|
||||
}
|
||||
return _(UNKNOWN_BLOCK);
|
||||
}
|
||||
|
@ -339,7 +337,7 @@ std::shared_ptr<parser_t> parser_t::shared() { return shared_from_this(); }
|
|||
wcstring parser_t::stack_trace() const {
|
||||
wcstring trace;
|
||||
for (const auto &b : blocks()) {
|
||||
if (b.type() == EVENT) {
|
||||
if (b.type() == block_type_t::event) {
|
||||
// This is an event handler.
|
||||
assert(b.event && "Should have an event");
|
||||
wcstring description = event_get_desc(*b.event);
|
||||
|
@ -353,18 +351,19 @@ wcstring parser_t::stack_trace() const {
|
|||
break;
|
||||
}
|
||||
|
||||
if (b.type() == FUNCTION_CALL || b.type() == FUNCTION_CALL_NO_SHADOW ||
|
||||
b.type() == SOURCE || b.type() == SUBST) {
|
||||
if (b.type() == block_type_t::function_call ||
|
||||
b.type() == block_type_t::function_call_no_shadow || b.type() == block_type_t::source ||
|
||||
b.type() == block_type_t::subst) {
|
||||
// These types of blocks should be printed.
|
||||
switch (b.type()) {
|
||||
case SOURCE: {
|
||||
case block_type_t::source: {
|
||||
const wchar_t *source_dest = b.sourced_file;
|
||||
append_format(trace, _(L"from sourcing file %ls\n"),
|
||||
user_presentable_path(source_dest).c_str());
|
||||
break;
|
||||
}
|
||||
case FUNCTION_CALL:
|
||||
case FUNCTION_CALL_NO_SHADOW: {
|
||||
case block_type_t::function_call:
|
||||
case block_type_t::function_call_no_shadow: {
|
||||
append_format(trace, _(L"in function '%ls'"), b.function_name.c_str());
|
||||
// Print arguments on the same line.
|
||||
wcstring args_str;
|
||||
|
@ -385,7 +384,7 @@ wcstring parser_t::stack_trace() const {
|
|||
trace.push_back('\n');
|
||||
break;
|
||||
}
|
||||
case SUBST: {
|
||||
case block_type_t::subst: {
|
||||
append_format(trace, _(L"in command substitution\n"));
|
||||
break;
|
||||
}
|
||||
|
@ -422,9 +421,9 @@ const wchar_t *parser_t::is_function(size_t idx) const {
|
|||
|
||||
for (size_t block_idx = idx; block_idx < block_list.size(); block_idx++) {
|
||||
const block_t &b = block_list[block_idx];
|
||||
if (b.is_function()) {
|
||||
if (b.is_function_call()) {
|
||||
return b.function_name.c_str();
|
||||
} else if (b.type() == SOURCE) {
|
||||
} else if (b.type() == block_type_t::source) {
|
||||
// If a function sources a file, obviously that function's offset doesn't
|
||||
// contribute.
|
||||
break;
|
||||
|
@ -442,9 +441,9 @@ const wchar_t *parser_t::get_function_name(int level) {
|
|||
// Walk until we find a breakpoint, then take the next function.
|
||||
bool found_breakpoint = false;
|
||||
for (const auto &b : block_list) {
|
||||
if (b.type() == BREAKPOINT) {
|
||||
if (b.type() == block_type_t::breakpoint) {
|
||||
found_breakpoint = true;
|
||||
} else if (found_breakpoint && b.is_function()) {
|
||||
} else if (found_breakpoint && b.is_function_call()) {
|
||||
return b.function_name.c_str();
|
||||
}
|
||||
}
|
||||
|
@ -457,7 +456,7 @@ const wchar_t *parser_t::get_function_name(int level) {
|
|||
// Level 1 is the topmost function call. Level 2 is its caller. Etc.
|
||||
int funcs_seen = 0;
|
||||
for (const auto &b : block_list) {
|
||||
if (b.is_function()) {
|
||||
if (b.is_function_call()) {
|
||||
funcs_seen++;
|
||||
if (funcs_seen == level) {
|
||||
return b.function_name.c_str();
|
||||
|
@ -479,9 +478,9 @@ const wchar_t *parser_t::current_filename() const {
|
|||
ASSERT_IS_MAIN_THREAD();
|
||||
|
||||
for (const auto &b : block_list) {
|
||||
if (b.is_function()) {
|
||||
if (b.is_function_call()) {
|
||||
return function_get_definition_file(b.function_name);
|
||||
} else if (b.type() == SOURCE) {
|
||||
} else if (b.type() == block_type_t::source) {
|
||||
return b.sourced_file;
|
||||
}
|
||||
}
|
||||
|
@ -499,7 +498,7 @@ bool parser_t::function_stack_is_overflowing() const {
|
|||
// Count the functions.
|
||||
int depth = 0;
|
||||
for (const auto &b : block_list) {
|
||||
depth += b.is_function();
|
||||
depth += b.is_function_call();
|
||||
}
|
||||
return depth > FISH_MAX_STACK_DEPTH;
|
||||
}
|
||||
|
@ -620,7 +619,7 @@ eval_result_t parser_t::eval(const wcstring &cmd, const io_chain_t &io,
|
|||
|
||||
eval_result_t parser_t::eval(parsed_source_ref_t ps, const io_chain_t &io,
|
||||
enum block_type_t block_type) {
|
||||
assert(block_type == TOP || block_type == SUBST);
|
||||
assert(block_type == block_type_t::top || block_type == block_type_t::subst);
|
||||
if (!ps->tree.empty()) {
|
||||
job_lineage_t lineage;
|
||||
lineage.block_io = io;
|
||||
|
@ -648,7 +647,8 @@ eval_result_t parser_t::eval_node(parsed_source_ref_t ps, tnode_t<T> node, block
|
|||
}
|
||||
|
||||
// Only certain blocks are allowed.
|
||||
assert((block_type == TOP || block_type == SUBST) && "Invalid block type");
|
||||
assert((block_type == block_type_t::top || block_type == block_type_t::subst) &&
|
||||
"Invalid block type");
|
||||
|
||||
job_reap(*this, false); // not sure why we reap jobs here
|
||||
|
||||
|
@ -728,55 +728,55 @@ block_t::~block_t() = default;
|
|||
wcstring block_t::description() const {
|
||||
wcstring result;
|
||||
switch (this->type()) {
|
||||
case WHILE: {
|
||||
case block_type_t::while_block: {
|
||||
result.append(L"while");
|
||||
break;
|
||||
}
|
||||
case FOR: {
|
||||
case block_type_t::for_block: {
|
||||
result.append(L"for");
|
||||
break;
|
||||
}
|
||||
case IF: {
|
||||
case block_type_t::if_block: {
|
||||
result.append(L"if");
|
||||
break;
|
||||
}
|
||||
case FUNCTION_CALL: {
|
||||
case block_type_t::function_call: {
|
||||
result.append(L"function_call");
|
||||
break;
|
||||
}
|
||||
case FUNCTION_CALL_NO_SHADOW: {
|
||||
case block_type_t::function_call_no_shadow: {
|
||||
result.append(L"function_call_no_shadow");
|
||||
break;
|
||||
}
|
||||
case SWITCH: {
|
||||
case block_type_t::switch_block: {
|
||||
result.append(L"switch");
|
||||
break;
|
||||
}
|
||||
case SUBST: {
|
||||
case block_type_t::subst: {
|
||||
result.append(L"substitution");
|
||||
break;
|
||||
}
|
||||
case TOP: {
|
||||
case block_type_t::top: {
|
||||
result.append(L"top");
|
||||
break;
|
||||
}
|
||||
case BEGIN: {
|
||||
case block_type_t::begin: {
|
||||
result.append(L"begin");
|
||||
break;
|
||||
}
|
||||
case SOURCE: {
|
||||
case block_type_t::source: {
|
||||
result.append(L"source");
|
||||
break;
|
||||
}
|
||||
case EVENT: {
|
||||
case block_type_t::event: {
|
||||
result.append(L"event");
|
||||
break;
|
||||
}
|
||||
case BREAKPOINT: {
|
||||
case block_type_t::breakpoint: {
|
||||
result.append(L"breakpoint");
|
||||
break;
|
||||
}
|
||||
case VARIABLE_ASSIGNMENT: {
|
||||
case block_type_t::variable_assignment: {
|
||||
result.append(L"variable_assignment");
|
||||
break;
|
||||
}
|
||||
|
@ -793,33 +793,35 @@ wcstring block_t::description() const {
|
|||
|
||||
// Various block constructors.
|
||||
|
||||
block_t block_t::if_block() { return block_t(IF); }
|
||||
block_t block_t::if_block() { return block_t(block_type_t::if_block); }
|
||||
|
||||
block_t block_t::event_block(event_t evt) {
|
||||
block_t b{EVENT};
|
||||
block_t b{block_type_t::event};
|
||||
b.event = std::move(evt);
|
||||
return b;
|
||||
}
|
||||
|
||||
block_t block_t::function_block(wcstring name, wcstring_list_t args, bool shadows) {
|
||||
block_t b{shadows ? FUNCTION_CALL : FUNCTION_CALL_NO_SHADOW};
|
||||
block_t b{shadows ? block_type_t::function_call : block_type_t::function_call_no_shadow};
|
||||
b.function_name = std::move(name);
|
||||
b.function_args = std::move(args);
|
||||
return b;
|
||||
}
|
||||
|
||||
block_t block_t::source_block(const wchar_t *src) {
|
||||
block_t b{SOURCE};
|
||||
block_t b{block_type_t::source};
|
||||
b.sourced_file = src;
|
||||
return b;
|
||||
}
|
||||
|
||||
block_t block_t::for_block() { return block_t{FOR}; }
|
||||
block_t block_t::while_block() { return block_t{WHILE}; }
|
||||
block_t block_t::switch_block() { return block_t{SWITCH}; }
|
||||
block_t block_t::for_block() { return block_t{block_type_t::for_block}; }
|
||||
block_t block_t::while_block() { return block_t{block_type_t::while_block}; }
|
||||
block_t block_t::switch_block() { return block_t{block_type_t::switch_block}; }
|
||||
block_t block_t::scope_block(block_type_t type) {
|
||||
assert((type == BEGIN || type == TOP || type == SUBST) && "Invalid scope type");
|
||||
assert(
|
||||
(type == block_type_t::begin || type == block_type_t::top || type == block_type_t::subst) &&
|
||||
"Invalid scope type");
|
||||
return block_t(type);
|
||||
}
|
||||
block_t block_t::breakpoint_block() { return block_t(BREAKPOINT); }
|
||||
block_t block_t::variable_assignment_block() { return block_t(VARIABLE_ASSIGNMENT); }
|
||||
block_t block_t::breakpoint_block() { return block_t(block_type_t::breakpoint); }
|
||||
block_t block_t::variable_assignment_block() { return block_t(block_type_t::variable_assignment); }
|
||||
|
|
35
src/parser.h
35
src/parser.h
|
@ -31,20 +31,20 @@ inline bool event_block_list_blocks_type(const event_blockage_list_t &ebls) {
|
|||
}
|
||||
|
||||
/// Types of blocks.
|
||||
enum block_type_t {
|
||||
WHILE, /// While loop block
|
||||
FOR, /// For loop block
|
||||
IF, /// If block
|
||||
FUNCTION_CALL, /// Function invocation block
|
||||
FUNCTION_CALL_NO_SHADOW, /// Function invocation block with no variable shadowing
|
||||
SWITCH, /// Switch block
|
||||
SUBST, /// Command substitution scope
|
||||
TOP, /// Outermost block
|
||||
BEGIN, /// Unconditional block
|
||||
SOURCE, /// Block created by the . (source) builtin
|
||||
EVENT, /// Block created on event notifier invocation
|
||||
BREAKPOINT, /// Breakpoint block
|
||||
VARIABLE_ASSIGNMENT, /// Variable assignment before a command
|
||||
enum class block_type_t {
|
||||
while_block, /// While loop block
|
||||
for_block, /// For loop block
|
||||
if_block, /// If block
|
||||
function_call, /// Function invocation block
|
||||
function_call_no_shadow, /// Function invocation block with no variable shadowing
|
||||
switch_block, /// Switch block
|
||||
subst, /// Command substitution scope
|
||||
top, /// Outermost block
|
||||
begin, /// Unconditional block
|
||||
source, /// Block created by the . (source) builtin
|
||||
event, /// Block created on event notifier invocation
|
||||
breakpoint, /// Breakpoint block
|
||||
variable_assignment, /// Variable assignment before a command
|
||||
};
|
||||
|
||||
/// Possible states for a loop.
|
||||
|
@ -91,8 +91,9 @@ class block_t {
|
|||
wcstring description() const;
|
||||
|
||||
/// \return if we are a function call (with or without shadowing).
|
||||
bool is_function() const {
|
||||
return type() == FUNCTION_CALL || type() == FUNCTION_CALL_NO_SHADOW;
|
||||
bool is_function_call() const {
|
||||
return type() == block_type_t::function_call ||
|
||||
type() == block_type_t::function_call_no_shadow;
|
||||
}
|
||||
|
||||
/// Entry points for creating blocks.
|
||||
|
@ -329,7 +330,7 @@ class parser_t : public std::enable_shared_from_this<parser_t> {
|
|||
void pop_block(const block_t *expected);
|
||||
|
||||
/// Return a description of the given blocktype.
|
||||
const wchar_t *get_block_desc(int block) const;
|
||||
static const wchar_t *get_block_desc(block_type_t block);
|
||||
|
||||
/// Return the function name for the specified stack frame. Default is one (current frame).
|
||||
const wchar_t *get_function_name(int level = 1);
|
||||
|
|
|
@ -1952,7 +1952,7 @@ void reader_run_command(parser_t &parser, const wcstring &cmd) {
|
|||
|
||||
gettimeofday(&time_before, nullptr);
|
||||
|
||||
parser.eval(cmd, io_chain_t(), TOP);
|
||||
parser.eval(cmd, io_chain_t(), block_type_t::top);
|
||||
job_reap(parser, true);
|
||||
|
||||
gettimeofday(&time_after, nullptr);
|
||||
|
@ -2205,7 +2205,7 @@ void reader_bg_job_warning(const parser_t &parser) {
|
|||
static void handle_end_loop(const parser_t &parser) {
|
||||
if (!reader_exit_forced()) {
|
||||
for (const auto &b : parser.blocks()) {
|
||||
if (b.type() == BREAKPOINT) {
|
||||
if (b.type() == block_type_t::breakpoint) {
|
||||
// We're executing within a breakpoint so we do not want to terminate the shell and
|
||||
// kill background jobs.
|
||||
return;
|
||||
|
@ -3551,7 +3551,7 @@ static int read_ni(parser_t &parser, int fd, const io_chain_t &io) {
|
|||
parsed_source_ref_t pstree;
|
||||
if (!parse_util_detect_errors(str, &errors, false /* do not accept incomplete */,
|
||||
&pstree)) {
|
||||
parser.eval(pstree, io, TOP);
|
||||
parser.eval(pstree, io, block_type_t::top);
|
||||
} else {
|
||||
wcstring sb;
|
||||
parser.get_backtrace(str, errors, sb);
|
||||
|
|
Loading…
Reference in a new issue