From e38217683c65f53fcaa3b6a5daedb6b23b408a90 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Fri, 20 Dec 2013 17:41:21 -0800 Subject: [PATCH] Refactor block_t storage in parser_t from a linked list to a vector --- builtin.cpp | 160 +++++++++++++++++++++-------------------- event.cpp | 7 +- exec.cpp | 3 +- function.cpp | 2 +- parser.cpp | 196 +++++++++++++++++++++++++++------------------------ parser.h | 28 +++++--- reader.cpp | 9 +-- 7 files changed, 218 insertions(+), 187 deletions(-) diff --git a/builtin.cpp b/builtin.cpp index c1281a529..a57218900 100644 --- a/builtin.cpp +++ b/builtin.cpp @@ -831,7 +831,8 @@ static int builtin_block(parser_t &parser, wchar_t **argv) } else { - block_t *block=parser.current_block; + size_t block_idx = 0; + block_t *block = parser.block_at_index(block_idx); event_blockage_t eb = {}; eb.typemask = type; @@ -840,20 +841,24 @@ static int builtin_block(parser_t &parser, wchar_t **argv) { case LOCAL: { - if (!block->outer) - block=0; + // If this is the outermost block, then we're global + if (block_idx + 1 >= parser.block_count()) + { + block = NULL; + } break; } case GLOBAL: { - block=0; + block=NULL; } case UNSET: { - while (block && - block->type() != FUNCTION_CALL && - block->type() != FUNCTION_CALL_NO_SHADOW) - block = block->outer; + while (block != NULL && block->type() != FUNCTION_CALL && block->type() != FUNCTION_CALL_NO_SHADOW) + { + // Set it in function scope + block = parser.block_at_index(++block_idx); + } } } if (block) @@ -1863,18 +1868,21 @@ static int builtin_function(parser_t &parser, wchar_t **argv) if (is_subshell) { - block_t *b = parser.current_block; - - while (b && (b->type() != SUBST)) - b = b->outer; - - if (b) + size_t block_idx = 0; + + /* Find the outermost substitution block */ + for (block_idx = 0; ; block_idx++) { - b=b->outer; + const block_t *b = parser.block_at_index(block_idx); + if (b == NULL || b->type() == SUBST) + break; } - if (b->job) + + /* Go one step beyond that, to get to the caller */ + const block_t *caller_block = parser.block_at_index(block_idx + 1); + if (caller_block != NULL && caller_block->job != NULL) { - job_id = b->job->job_id; + job_id = caller_block->job->job_id; } } @@ -2058,8 +2066,8 @@ static int builtin_function(parser_t &parser, wchar_t **argv) } } - parser.current_block->tok_pos = parser.get_pos(); - parser.current_block->skip = 1; + parser.current_block()->tok_pos = parser.get_pos(); + parser.current_block()->skip = 1; return STATUS_BUILTIN_OK; } @@ -2712,7 +2720,7 @@ static int builtin_status(parser_t &parser, wchar_t **argv) case STACK_TRACE: { - parser.stack_trace(parser.current_block, stdout_buffer); + parser.stack_trace(0, stdout_buffer); break; } @@ -2727,7 +2735,7 @@ static int builtin_status(parser_t &parser, wchar_t **argv) job_control_mode==JOB_CONTROL_INTERACTIVE?_(L"Only on interactive jobs"): (job_control_mode==JOB_CONTROL_NONE ? _(L"Never") : _(L"Always"))); - parser.stack_trace(parser.current_block, stdout_buffer); + parser.stack_trace(0, stdout_buffer); break; } } @@ -3413,19 +3421,19 @@ static int builtin_for(parser_t &parser, wchar_t **argv) } else { - parser.current_block->skip=1; + parser.current_block()->skip=1; } } return res; } /** - The begin builtin. Creates a nex block. + The begin builtin. Creates a new block. */ static int builtin_begin(parser_t &parser, wchar_t **argv) { parser.push_block(new scope_block_t(BEGIN)); - parser.current_block->tok_pos = parser.get_pos(); + parser.current_block()->tok_pos = parser.get_pos(); return proc_get_last_status(); } @@ -3437,7 +3445,7 @@ static int builtin_begin(parser_t &parser, wchar_t **argv) */ static int builtin_end(parser_t &parser, wchar_t **argv) { - if (!parser.current_block->outer) + if (! parser.block_at_index(1)) { append_format(stderr_buffer, _(L"%ls: Not inside of block\n"), @@ -3455,7 +3463,8 @@ static int builtin_end(parser_t &parser, wchar_t **argv) */ bool kill_block = true; - switch (parser.current_block->type()) + block_t * const current_block = parser.current_block(); + switch (current_block->type()) { case WHILE: { @@ -3463,13 +3472,13 @@ static int builtin_end(parser_t &parser, wchar_t **argv) If this is a while loop, we rewind the loop unless it's the last lap, in which case we continue. */ - if (!(parser.current_block->skip && (parser.current_block->loop_status != LOOP_CONTINUE))) + if (!(current_block->skip && (current_block->loop_status != LOOP_CONTINUE))) { - parser.current_block->loop_status = LOOP_NORMAL; - parser.current_block->skip = 0; + current_block->loop_status = LOOP_NORMAL; + current_block->skip = 0; kill_block = false; - parser.set_pos(parser.current_block->tok_pos); - while_block_t *blk = static_cast(parser.current_block); + parser.set_pos(current_block->tok_pos); + while_block_t *blk = static_cast(current_block); blk->status = WHILE_TEST_AGAIN; } @@ -3492,9 +3501,9 @@ static int builtin_end(parser_t &parser, wchar_t **argv) /* set loop variable to next element, and rewind to the beginning of the block. */ - for_block_t *fb = static_cast(parser.current_block); + for_block_t *fb = static_cast(current_block); wcstring_list_t &for_vars = fb->sequence; - if (parser.current_block->loop_status == LOOP_BREAK) + if (current_block->loop_status == LOOP_BREAK) { for_vars.clear(); } @@ -3505,18 +3514,18 @@ static int builtin_end(parser_t &parser, wchar_t **argv) for_vars.pop_back(); const wcstring &for_variable = fb->variable; env_set(for_variable, val.c_str(), ENV_LOCAL); - parser.current_block->loop_status = LOOP_NORMAL; - parser.current_block->skip = 0; + current_block->loop_status = LOOP_NORMAL; + current_block->skip = 0; kill_block = false; - parser.set_pos(parser.current_block->tok_pos); + parser.set_pos(current_block->tok_pos); } break; } case FUNCTION_DEF: { - function_def_block_t *fdb = static_cast(parser.current_block); + function_def_block_t *fdb = static_cast(current_block); function_data_t &d = fdb->function_data; if (d.name.empty()) @@ -3535,8 +3544,8 @@ static int builtin_end(parser_t &parser, wchar_t **argv) for the specified function */ - wchar_t *def = wcsndup(parser.get_buffer()+parser.current_block->tok_pos, - parser.get_job_pos()-parser.current_block->tok_pos); + wchar_t *def = wcsndup(parser.get_buffer()+current_block->tok_pos, + parser.get_job_pos()-current_block->tok_pos); d.definition = def; function_add(d, parser); @@ -3569,9 +3578,9 @@ static int builtin_else(parser_t &parser, wchar_t **argv) { bool block_ok = false; if_block_t *if_block = NULL; - if (parser.current_block != NULL && parser.current_block->type() == IF) + if (parser.current_block() != NULL && parser.current_block()->type() == IF) { - if_block = static_cast(parser.current_block); + if_block = static_cast(parser.current_block()); /* Ensure that we're past IF but not up to an ELSE */ if (if_block->if_expr_evaluated && ! if_block->else_evaluated) { @@ -3612,7 +3621,6 @@ static int builtin_break_continue(parser_t &parser, wchar_t **argv) int is_break = (wcscmp(argv[0],L"break")==0); int argc = builtin_count_args(argv); - block_t *b = parser.current_block; if (argc != 1) { @@ -3625,15 +3633,16 @@ static int builtin_break_continue(parser_t &parser, wchar_t **argv) return STATUS_BUILTIN_ERROR; } - - while ((b != 0) && - (b->type() != WHILE) && - (b->type() != FOR)) + /* Find the index of the enclosing for or while loop. Recall that incrementing loop_idx goes 'up' to outer blocks */ + size_t loop_idx; + for (loop_idx = 0; loop_idx < parser.block_count(); loop_idx++) { - b = b->outer; + const block_t *b = parser.block_at_index(loop_idx); + if (b->type() == WHILE || b->type() == FOR) + break; } - if (b == 0) + if (loop_idx >= parser.block_count()) { append_format(stderr_buffer, _(L"%ls: Not inside of loop\n"), @@ -3642,15 +3651,17 @@ static int builtin_break_continue(parser_t &parser, wchar_t **argv) return STATUS_BUILTIN_ERROR; } - b = parser.current_block; - while ((b->type() != WHILE) && - (b->type() != FOR)) + /* Skip blocks interior to the loop */ + size_t block_idx = loop_idx; + while (block_idx--) { - b->skip=1; - b = b->outer; + parser.block_at_index(block_idx)->skip = true; } - b->skip=1; - b->loop_status = is_break?LOOP_BREAK:LOOP_CONTINUE; + + /* Skip the loop itself */ + block_t *loop_block = parser.block_at_index(loop_idx); + loop_block->skip = true; + loop_block->loop_status = is_break ? LOOP_BREAK : LOOP_CONTINUE; return STATUS_BUILTIN_OK; } @@ -3679,8 +3690,6 @@ static int builtin_return(parser_t &parser, wchar_t **argv) int argc = builtin_count_args(argv); int status = proc_get_last_status(); - block_t *b = parser.current_block; - switch (argc) { case 1: @@ -3709,15 +3718,16 @@ static int builtin_return(parser_t &parser, wchar_t **argv) return STATUS_BUILTIN_ERROR; } - - while ((b != 0) && - (b->type() != FUNCTION_CALL && - b->type() != FUNCTION_CALL_NO_SHADOW)) + /* Find the function block */ + size_t function_block_idx; + for (function_block_idx = 0; function_block_idx < parser.block_count(); function_block_idx++) { - b = b->outer; + const block_t *b = parser.block_at_index(function_block_idx); + if (b->type() == FUNCTION_CALL || b->type() == FUNCTION_CALL_NO_SHADOW) + break; } - if (b == 0) + if (function_block_idx >= parser.block_count()) { append_format(stderr_buffer, _(L"%ls: Not inside of function\n"), @@ -3725,17 +3735,15 @@ static int builtin_return(parser_t &parser, wchar_t **argv) builtin_print_help(parser, argv[0], stderr_buffer); return STATUS_BUILTIN_ERROR; } - - b = parser.current_block; - while ((b->type() != FUNCTION_CALL && - b->type() != FUNCTION_CALL_NO_SHADOW)) + + /* Skip everything up to (and then including) the function block */ + for (size_t i=0; i < function_block_idx; i++) { + block_t *b = parser.block_at_index(i); b->mark_as_fake(); - b->skip=1; - b = b->outer; + b->skip = true; } - b->skip=1; - + parser.block_at_index(function_block_idx)->skip = true; return status; } @@ -3762,7 +3770,7 @@ static int builtin_switch(parser_t &parser, wchar_t **argv) else { parser.push_block(new switch_block_t(argv[1])); - parser.current_block->skip=1; + parser.current_block()->skip=1; res = proc_get_last_status(); } @@ -3779,7 +3787,7 @@ static int builtin_case(parser_t &parser, wchar_t **argv) int i; wchar_t *unescaped=0; - if (parser.current_block->type() != SWITCH) + if (parser.current_block()->type() != SWITCH) { append_format(stderr_buffer, _(L"%ls: 'case' command while not in switch block\n"), @@ -3788,8 +3796,8 @@ static int builtin_case(parser_t &parser, wchar_t **argv) return STATUS_BUILTIN_ERROR; } - parser.current_block->skip = 1; - switch_block_t *sb = static_cast(parser.current_block); + parser.current_block()->skip = 1; + switch_block_t *sb = static_cast(parser.current_block()); if (sb->switch_taken) { return proc_get_last_status(); @@ -3806,7 +3814,7 @@ static int builtin_case(parser_t &parser, wchar_t **argv) if (match) { - parser.current_block->skip = 0; + parser.current_block()->skip = 0; sb->switch_taken = true; break; } diff --git a/event.cpp b/event.cpp index f6313fb0c..d2b219e7d 100644 --- a/event.cpp +++ b/event.cpp @@ -144,12 +144,15 @@ static int event_match(const event_t &classv, const event_t &instance) */ static int event_is_blocked(const event_t &e) { - block_t *block; + const block_t *block; parser_t &parser = parser_t::principal_parser(); - for (block = parser.current_block; block; block = block->outer) + + size_t idx = 0; + while ((block = parser.block_at_index(idx++))) { if (event_block_list_blocks_type(block->event_blocks, e.type)) return true; + } return event_block_list_blocks_type(parser.global_event_blocks, e.type); } diff --git a/exec.cpp b/exec.cpp index b894ce690..6d7a19e88 100644 --- a/exec.cpp +++ b/exec.cpp @@ -580,7 +580,8 @@ static void exec_no_exec(parser_t &parser, const job_t *job) } else if (builtin_name == L"end") { - if (parser.current_block == NULL || parser.current_block->type() == TOP) + const block_t *block = parser.current_block(); + if (block == NULL || block->type() == TOP) { fprintf(stderr, "Warning: not popping the root block\n"); } diff --git a/function.cpp b/function.cpp index da7574d39..c559a686a 100644 --- a/function.cpp +++ b/function.cpp @@ -189,7 +189,7 @@ void function_add(const function_data_t &data, const parser_t &parser) /* Create and store a new function */ const wchar_t *filename = reader_current_filename(); - int def_offset = parser.line_number_of_character_at_offset(parser.current_block->tok_pos) - 1; + int def_offset = parser.line_number_of_character_at_offset(parser.current_block()->tok_pos) - 1; const function_map_t::value_type new_pair(data.name, function_info_t(data, filename, def_offset, is_autoload)); loaded_functions.insert(new_pair); diff --git a/parser.cpp b/parser.cpp index 328e331a9..62b45dcc3 100644 --- a/parser.cpp +++ b/parser.cpp @@ -325,7 +325,6 @@ parser_t::parser_t(enum parser_type_t type, bool errors) : current_tokenizer_pos(0), job_start_pos(0), eval_level(-1), - current_block(NULL), block_io(shared_ptr()) { @@ -352,39 +351,36 @@ void parser_t::skip_all_blocks(void) if (s_principal_parser) { //write(2, "Cancelling blocks\n", strlen("Cancelling blocks\n")); - block_t *c = s_principal_parser->current_block; - while (c) + for (size_t i=0; i < s_principal_parser->block_count(); i++) { - c->skip = true; - //fprintf(stderr, " Cancelled %p\n", c); - c = c->outer; + s_principal_parser->block_at_index(i)->skip = true; } } } -void parser_t::push_block(block_t *newv) +void parser_t::push_block(block_t *new_current) { - const enum block_type_t type = newv->type(); - newv->src_lineno = parser_t::get_lineno(); - newv->src_filename = parser_t::current_filename()?intern(parser_t::current_filename()):0; + const enum block_type_t type = new_current->type(); + new_current->src_lineno = parser_t::get_lineno(); + new_current->src_filename = parser_t::current_filename()?intern(parser_t::current_filename()):0; - newv->outer = current_block; - if (current_block && current_block->skip) - newv->mark_as_fake(); + const block_t *old_current = this->current_block(); + if (old_current && old_current->skip) + new_current->mark_as_fake(); /* New blocks should be skipped if the outer block is skipped, except TOP ans SUBST block, which open up new environments. Fake blocks should always be skipped. Rather complicated... :-( */ - newv->skip=current_block?current_block->skip:0; + new_current->skip = old_current ? old_current->skip : 0; /* Type TOP and SUBST are never skipped */ if (type == TOP || type == SUBST) { - newv->skip = 0; + new_current->skip = 0; } /* @@ -392,27 +388,26 @@ void parser_t::push_block(block_t *newv) */ if (type == FAKE || type == FUNCTION_DEF) { - newv->skip = 1; + new_current->skip = 1; } - newv->job = 0; - newv->loop_status=LOOP_NORMAL; + new_current->job = 0; + new_current->loop_status=LOOP_NORMAL; + + this->block_stack.push_back(new_current); - current_block = newv; - - if ((newv->type() != FUNCTION_DEF) && - (newv->type() != FAKE) && - (newv->type() != TOP)) + if ((new_current->type() != FUNCTION_DEF) && + (new_current->type() != FAKE) && + (new_current->type() != TOP)) { env_push(type == FUNCTION_CALL); - newv->wants_pop_env = true; + new_current->wants_pop_env = true; } } void parser_t::pop_block() { - block_t *old = current_block; - if (!current_block) + if (block_stack.empty()) { debug(1, L"function %s called on empty block stack.", @@ -421,7 +416,8 @@ void parser_t::pop_block() return; } - current_block = current_block->outer; + block_t *old = block_stack.back(); + block_stack.pop_back(); if (old->wants_pop_env) env_pop(); @@ -441,6 +437,30 @@ const wchar_t *parser_t::get_block_desc(int block) const return _(UNKNOWN_BLOCK); } +const block_t *parser_t::block_at_index(size_t idx) const +{ + /* 0 corresponds to the last element in our vector */ + size_t count = block_stack.size(); + return idx < count ? block_stack.at(count - idx - 1) : NULL; +} + +block_t *parser_t::block_at_index(size_t idx) +{ + size_t count = block_stack.size(); + return idx < count ? block_stack.at(count - idx - 1) : NULL; +} + +const block_t *parser_t::current_block() const +{ + return block_stack.empty() ? NULL : block_stack.back(); +} + +block_t *parser_t::current_block() +{ + return block_stack.empty() ? NULL : block_stack.back(); +} + + /** Returns 1 if the specified command is a builtin that may not be used in a pipeline */ @@ -807,13 +827,15 @@ int parser_t::eval_args(const wchar_t *line, std::vector &args) return 1; } -void parser_t::stack_trace(block_t *b, wcstring &buff) +void parser_t::stack_trace(size_t block_idx, wcstring &buff) { /* Check if we should end the recursion */ - if (!b) + if (block_idx >= this->block_count()) return; + + const block_t *b = this->block_at_index(block_idx); if (b->type()==EVENT) { @@ -908,7 +930,7 @@ void parser_t::stack_trace(block_t *b, wcstring &buff) /* Recursively print the next block */ - parser_t::stack_trace(b->outer, buff); + parser_t::stack_trace(block_idx + 1, buff); } /** @@ -921,22 +943,19 @@ const wchar_t *parser_t::is_function() const { // PCA: Have to make this a string somehow ASSERT_IS_MAIN_THREAD(); - wcstring result; - block_t *b = current_block; - while (1) + const wchar_t *result = NULL; + for (size_t block_idx = 0; block_idx < this->block_count(); block_idx++) { - if (!b) - { - return NULL; - } + const block_t *b = this->block_at_index(block_idx); if (b->type() == FUNCTION_CALL) { const function_block_t *fb = static_cast(b); - return fb->name.c_str(); + result = fb->name.c_str(); + break; } - b=b->outer; } + return result; } @@ -974,21 +993,17 @@ const wchar_t *parser_t::current_filename() const ASSERT_IS_MAIN_THREAD(); assert(this == &principal_parser()); - block_t *b = current_block; - while (1) + for (size_t i=0; i < this->block_count(); i++) { - if (!b) - { - return reader_current_filename(); - } + const block_t *b = this->block_at_index(i); if (b->type() == FUNCTION_CALL) { const function_block_t *fb = static_cast(b); return function_get_definition_file(fb->name); } - b=b->outer; } + return reader_current_filename(); } /** @@ -1129,7 +1144,7 @@ const wchar_t *parser_t::current_line() } free((void *)line); - parser_t::stack_trace(current_block, lineinfo); + parser_t::stack_trace(0, lineinfo); return lineinfo.c_str(); } @@ -1239,7 +1254,7 @@ job_t *parser_t::job_get_from_pid(int pid) \param j the job to which the process belongs to \param tok the tokenizer to read options from \param args the argument list to insert options into - \param args unskip whether we should ignore current_block->skip. Big hack because of our dumb handling of if statements. + \param args unskip whether we should ignore current_block()->skip. Big hack because of our dumb handling of if statements. */ void parser_t::parse_job_argument_list(process_t *p, job_t *j, @@ -1336,7 +1351,7 @@ void parser_t::parse_job_argument_list(process_t *p, { skip = 1; } - else if (current_block->skip && ! unskip) + else if (current_block()->skip && ! unskip) { /* If this command should be skipped, we do not expand the arguments @@ -1344,12 +1359,12 @@ void parser_t::parse_job_argument_list(process_t *p, skip=1; /* But if this is in fact a case statement or an elseif statement, then it should be evaluated */ - block_type_t type = current_block->type(); + block_type_t type = current_block()->type(); if (type == SWITCH && args.at(0).completion == L"case" && p->type == INTERNAL_BUILTIN) { skip=0; } - else if (job_get_flag(j, JOB_ELSEIF) && ! job_should_skip_elseif(j, current_block)) + else if (job_get_flag(j, JOB_ELSEIF) && ! job_should_skip_elseif(j, current_block())) { skip=0; } @@ -1357,7 +1372,7 @@ void parser_t::parse_job_argument_list(process_t *p, else { /* If this is an else if, and we should skip it, then don't expand any arguments */ - if (job_get_flag(j, JOB_ELSEIF) && job_should_skip_elseif(j, current_block)) + if (job_get_flag(j, JOB_ELSEIF) && job_should_skip_elseif(j, current_block())) { skip = 1; } @@ -1440,7 +1455,7 @@ void parser_t::parse_job_argument_list(process_t *p, Otherwise, bogus errors may be the result. (Do check that token is string, though) */ - if (current_block->skip && ! unskip) + if (current_block()->skip && ! unskip) { tok_next(tok); if (tok_last_type(tok) != TOK_STRING) @@ -1653,7 +1668,7 @@ int parser_t::parse_job(process_t *p, bool unskip = false; // Maybe we are an elseif inside an if block; if so we may want to evaluate this even if the if block is currently set to skip bool allow_bogus_command = false; // If we are an elseif that will not be executed, or an AND or OR that will have been short circuited, don't complain about non-existent commands - block_t *prev_block = current_block; + const block_t *prev_block = current_block(); scoped_push tokenizer_pos_push(¤t_tokenizer_pos, tok_get_pos(tok)); while (args.empty()) @@ -1806,11 +1821,11 @@ int parser_t::parse_job(process_t *p, tok_next(tok); while_block_t *wb = NULL; - if ((current_block->type() != WHILE)) + if ((current_block()->type() != WHILE)) { new_block = true; } - else if ((wb = static_cast(current_block))->status == WHILE_TEST_AGAIN) + else if ((wb = static_cast(current_block()))->status == WHILE_TEST_AGAIN) { wb->status = WHILE_TEST_FIRST; } @@ -1848,9 +1863,9 @@ int parser_t::parse_job(process_t *p, const int else_pos = tok_get_pos(tok); /* See if we have any more arguments, that is, whether we're ELSE IF ... or just ELSE. */ tok_next(tok); - if (tok_last_type(tok) == TOK_STRING && current_block->type() == IF) + if (tok_last_type(tok) == TOK_STRING && current_block()->type() == IF) { - const if_block_t *ib = static_cast(current_block); + const if_block_t *ib = static_cast(current_block()); /* If we've already encountered an else, complain */ if (ib->else_evaluated) @@ -1891,7 +1906,7 @@ int parser_t::parse_job(process_t *p, continue; } - if (use_function && (unskip || ! current_block->skip)) + if (use_function && (unskip || ! current_block()->skip)) { bool nxt_forbidden=false; wcstring forbid; @@ -1905,9 +1920,8 @@ int parser_t::parse_job(process_t *p, block scopes are pushed on function invocation changes, then this check will break. */ - if ((current_block->type() == TOP) && - (current_block->outer) && - (current_block->outer->type() == FUNCTION_CALL)) + const block_t *current = this->block_at_index(0), *parent = this->block_at_index(1); + if (current && parent && current->type() == TOP && parent->type() == FUNCTION_CALL) is_function_call = 1; /* @@ -1916,7 +1930,7 @@ int parser_t::parse_job(process_t *p, may not be called, since that would mean an infinite recursion. */ - if (is_function_call && !current_block->had_command) + if (is_function_call && !current->had_command) { forbid = forbidden_function.empty() ? wcstring(L"") : forbidden_function.back(); if (forbid == nxt) @@ -1963,7 +1977,7 @@ int parser_t::parse_job(process_t *p, If we are not executing the current block, allow non-existent commands. */ - if (current_block->skip && ! unskip) + if (current_block()->skip && ! unskip) allow_bogus_command = true; //note this may already be true for other reasons if (allow_bogus_command) @@ -2208,7 +2222,7 @@ int parser_t::parse_job(process_t *p, tok_set_pos(tok, (int)end_pos); - while (prev_block != current_block) + while (prev_block != this->current_block()) { parser_t::pop_block(); } @@ -2237,7 +2251,7 @@ int parser_t::parse_job(process_t *p, { if (!is_new_block) { - current_block->had_command = true; + current_block()->had_command = true; } } @@ -2246,7 +2260,7 @@ int parser_t::parse_job(process_t *p, /* Make sure the block stack is consistent */ - while (prev_block != current_block) + while (prev_block != current_block()) { parser_t::pop_block(); } @@ -2280,7 +2294,8 @@ void parser_t::skipped_exec(job_t * j) } else if (wcscmp(p->argv0(), L"end")==0) { - if (!current_block->outer->skip) + const block_t *parent = this->block_at_index(1); + if (parent && ! parent->skip) { exec_job(*this, j); return; @@ -2289,10 +2304,10 @@ void parser_t::skipped_exec(job_t * j) } else if (wcscmp(p->argv0(), L"else")==0) { - if (current_block->type() == IF) + if (current_block()->type() == IF) { /* Evaluate this ELSE if the IF expression failed, and so has every ELSEIF (if any) expression thus far */ - const if_block_t *ib = static_cast(current_block); + const if_block_t *ib = static_cast(current_block()); if (ib->if_expr_evaluated && ! ib->any_branch_taken) { exec_job(*this, j); @@ -2302,7 +2317,7 @@ void parser_t::skipped_exec(job_t * j) } else if (wcscmp(p->argv0(), L"case")==0) { - if (current_block->type() == SWITCH) + if (current_block()->type() == SWITCH) { exec_job(*this, j); return; @@ -2376,7 +2391,7 @@ void parser_t::eval_job(tokenizer_t *tok) || is_event \ || (!get_is_interactive())); - current_block->job = j; + current_block()->job = j; if (get_is_interactive()) { @@ -2411,27 +2426,27 @@ void parser_t::eval_job(tokenizer_t *tok) { t2 = get_time(); profile_item->cmd = j->command(); - profile_item->skipped=current_block->skip; + profile_item->skipped=current_block()->skip; } /* If we're an ELSEIF, then we may want to unskip, if we're skipping because of an IF */ if (job_get_flag(j, JOB_ELSEIF)) { - bool skip_elseif = job_should_skip_elseif(j, current_block); + bool skip_elseif = job_should_skip_elseif(j, current_block()); /* Record that we're entering an elseif */ if (! skip_elseif) { /* We must be an IF block here */ - assert(current_block->type() == IF); - static_cast(current_block)->is_elseif_entry = true; + assert(current_block()->type() == IF); + static_cast(current_block())->is_elseif_entry = true; } /* Record that in the block too. This is similar to what builtin_else does. */ - current_block->skip = skip_elseif; + current_block()->skip = skip_elseif; } - skip = skip || current_block->skip; + skip = skip || current_block()->skip; skip = skip || job_get_flag(j, JOB_WILDCARD_ERROR); skip = skip || job_get_flag(j, JOB_SKIP); @@ -2460,9 +2475,9 @@ void parser_t::eval_job(tokenizer_t *tok) profile_item->exec=(int)(t3-t2); } - if (current_block->type() == WHILE) + if (current_block()->type() == WHILE) { - while_block_t *wb = static_cast(current_block); + while_block_t *wb = static_cast(current_block()); switch (wb->status) { case WHILE_TEST_FIRST: @@ -2476,9 +2491,9 @@ void parser_t::eval_job(tokenizer_t *tok) } } - if (current_block->type() == IF) + if (current_block()->type() == IF) { - if_block_t *ib = static_cast(current_block); + if_block_t *ib = static_cast(current_block()); if (ib->skip) { @@ -2491,7 +2506,7 @@ void parser_t::eval_job(tokenizer_t *tok) ib->any_branch_taken = if_result; /* Don't execute if the expression failed */ - current_block->skip = ! if_result; + current_block()->skip = ! if_result; ib->if_expr_evaluated = true; } else if (ib->is_elseif_entry && ! ib->any_branch_taken) @@ -2499,7 +2514,7 @@ void parser_t::eval_job(tokenizer_t *tok) /* Maybe mark an ELSEIF branch as taken */ bool elseif_taken = (proc_get_last_status() == 0); ib->any_branch_taken = elseif_taken; - current_block->skip = ! elseif_taken; + current_block()->skip = ! elseif_taken; ib->is_elseif_entry = false; } } @@ -2517,7 +2532,7 @@ void parser_t::eval_job(tokenizer_t *tok) proc_set_last_status(1); } - current_block->job = 0; + current_block()->job = 0; break; } @@ -2579,7 +2594,7 @@ int parser_t::eval(const wcstring &cmdStr, const io_chain_t &io, enum block_type const wchar_t * const cmd = cmdStr.c_str(); size_t forbid_count; int code; - block_t *start_current_block = current_block; + const block_t *start_current_block = current_block(); /* Record the current chain so we can put it back later */ scoped_push block_io_push(&block_io, io); @@ -2639,9 +2654,9 @@ int parser_t::eval(const wcstring &cmdStr, const io_chain_t &io, enum block_type parser_t::pop_block(); - while (start_current_block != current_block) + while (start_current_block != current_block()) { - if (current_block == 0) + if (current_block() == NULL) { debug(0, _(L"End of block mismatch. Program terminating.")); @@ -2656,7 +2671,7 @@ int parser_t::eval(const wcstring &cmdStr, const io_chain_t &io, enum block_type //debug( 2, L"Status %d\n", proc_get_last_status() ); debug(1, - L"%ls", parser_t::get_block_desc(current_block->type())); + L"%ls", parser_t::get_block_desc(current_block()->type())); debug(1, BLOCK_END_ERR_MSG); fwprintf(stderr, L"%ls", parser_t::current_line()); @@ -3734,8 +3749,7 @@ block_t::block_t(block_type_t t) : src_filename(), src_lineno(), wants_pop_env(false), - event_blocks(), - outer(NULL) + event_blocks() { } diff --git a/parser.h b/parser.h index fa49fcfb7..9b613d3c8 100644 --- a/parser.h +++ b/parser.h @@ -137,11 +137,6 @@ public: /** List of event blocks. */ event_blockage_list_t event_blocks; - /** - Next outer block - */ - block_t *outer; - /** Destructor */ virtual ~block_t(); }; @@ -301,7 +296,6 @@ class parser_t { private: enum parser_type_t parser_type; - std::vector blocks; /** Whether or not we output errors */ const bool show_errors; @@ -332,6 +326,9 @@ private: /** The jobs associated with this parser */ job_list_t my_job_list; + + /** The list of blocks, allocated with new. It's our responsibility to delete these */ + std::vector block_stack; /** Keeps track of how many recursive eval calls have been made. Eval @@ -377,9 +374,6 @@ public: /** Create a parser of the given type */ parser_t(enum parser_type_t type, bool show_errors); - /** The current innermost block, allocated with new */ - block_t *current_block; - /** Global event blocks */ event_blockage_list_t global_event_blocks; @@ -441,6 +435,20 @@ public: /** Set the current position in the latest string of the tokenizer. */ void set_pos(int p); + + /** Returns the block at the given index. 0 corresponds to the innermost block. Returns NULL when idx is at or equal to the number of blocks. */ + const block_t *block_at_index(size_t idx) const; + block_t *block_at_index(size_t idx); + + /** Returns the current (innermost) block */ + const block_t *current_block() const; + block_t *current_block(); + + /** Count of blocks */ + size_t block_count() const + { + return block_stack.size(); + } /** Get the string currently parsed */ const wchar_t *get_buffer() const; @@ -533,7 +541,7 @@ public: /** Write a stack trace starting at the specified block to the specified wcstring */ - void stack_trace(block_t *b, wcstring &buff); + void stack_trace(size_t block_idx, wcstring &buff); int get_block_type(const wchar_t *cmd) const; const wchar_t *get_block_command(int type) const; diff --git a/reader.cpp b/reader.cpp index 5660ff268..b0cbd8a35 100644 --- a/reader.cpp +++ b/reader.cpp @@ -2823,14 +2823,11 @@ static void handle_end_loop() job_t *j; int stopped_jobs_count=0; int is_breakpoint=0; - block_t *b; - parser_t &parser = parser_t::principal_parser(); + const parser_t &parser = parser_t::principal_parser(); - for (b = parser.current_block; - b; - b = b->outer) + for (size_t i = 0; i < parser.block_count(); i++) { - if (b->type() == BREAKPOINT) + if (parser.block_at_index(i)->type() == BREAKPOINT) { is_breakpoint = 1; break;