aboutsummaryrefslogtreecommitdiffhomepage
path: root/parser.cpp
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2013-12-20 17:44:37 -0800
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2013-12-20 17:44:37 -0800
commited70195c7eda1040e596c3f7a1a417d4ec888242 (patch)
tree9bcbcddd51fde2a75aaa3aa5cb1cb61a5a5fc4e5 /parser.cpp
parent739e529416c3917d1e75d1a41850762a327e6ea9 (diff)
parente38217683c65f53fcaa3b6a5daedb6b23b408a90 (diff)
Merge branch 'master' into ast
Conflicts: function.cpp parser.cpp parser.h
Diffstat (limited to 'parser.cpp')
-rw-r--r--parser.cpp198
1 files changed, 106 insertions, 92 deletions
diff --git a/parser.cpp b/parser.cpp
index cd43b41a..c93ae071 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -328,7 +328,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<io_data_t>())
{
}
@@ -354,39 +353,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;
-
- newv->outer = current_block;
- if (current_block && current_block->skip)
- newv->mark_as_fake();
+ 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;
+
+ 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;
}
/*
@@ -394,27 +390,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;
-
- current_block = newv;
+ new_current->job = 0;
+ new_current->loop_status=LOOP_NORMAL;
+
+ this->block_stack.push_back(new_current);
- 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.",
@@ -423,7 +418,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();
@@ -443,6 +439,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 @@ void parser_t::eval_args(const wchar_t *line, std::vector<completion_t> &args)
proc_pop_interactive();
}
-void parser_t::stack_trace(block_t *b, wcstring &buff) const
+void parser_t::stack_trace(size_t block_idx, wcstring &buff) const
{
/*
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) const
/*
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<const function_block_t *>(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<const function_block_t *>(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,
@@ -1337,7 +1352,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
@@ -1345,12 +1360,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;
}
@@ -1358,7 +1373,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;
}
@@ -1441,7 +1456,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)
@@ -1756,7 +1771,7 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
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<int> tokenizer_pos_push(&current_tokenizer_pos, tok_get_pos(tok));
while (args.empty())
@@ -1909,11 +1924,11 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
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<while_block_t*>(current_block))->status == WHILE_TEST_AGAIN)
+ else if ((wb = static_cast<while_block_t*>(current_block()))->status == WHILE_TEST_AGAIN)
{
wb->status = WHILE_TEST_FIRST;
}
@@ -1951,9 +1966,9 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
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<const if_block_t *>(current_block);
+ const if_block_t *ib = static_cast<const if_block_t *>(current_block());
/* If we've already encountered an else, complain */
if (ib->else_evaluated)
@@ -1994,7 +2009,7 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
continue;
}
- if (use_function && (unskip || ! current_block->skip))
+ if (use_function && (unskip || ! current_block()->skip))
{
bool nxt_forbidden=false;
wcstring forbid;
@@ -2008,9 +2023,8 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
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;
/*
@@ -2019,7 +2033,7 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
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)
@@ -2066,7 +2080,7 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
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)
@@ -2311,7 +2325,7 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
tok_set_pos(tok, (int)end_pos);
- while (prev_block != current_block)
+ while (prev_block != this->current_block())
{
parser_t::pop_block();
}
@@ -2340,7 +2354,7 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
{
if (!is_new_block)
{
- current_block->had_command = true;
+ current_block()->had_command = true;
}
}
@@ -2349,7 +2363,7 @@ int parser_t::parse_job(process_t *p, job_t *j, tokenizer_t *tok)
/*
Make sure the block stack is consistent
*/
- while (prev_block != current_block)
+ while (prev_block != current_block())
{
parser_t::pop_block();
}
@@ -2383,7 +2397,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;
@@ -2392,10 +2407,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<const if_block_t*>(current_block);
+ const if_block_t *ib = static_cast<const if_block_t*>(current_block());
if (ib->if_expr_evaluated && ! ib->any_branch_taken)
{
exec_job(*this, j);
@@ -2405,7 +2420,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;
@@ -2679,7 +2694,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())
{
@@ -2714,27 +2729,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<if_block_t *>(current_block)->is_elseif_entry = true;
+ assert(current_block()->type() == IF);
+ static_cast<if_block_t *>(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);
@@ -2763,9 +2778,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<while_block_t *>(current_block);
+ while_block_t *wb = static_cast<while_block_t *>(current_block());
switch (wb->status)
{
case WHILE_TEST_FIRST:
@@ -2779,9 +2794,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<if_block_t *>(current_block);
+ if_block_t *ib = static_cast<if_block_t *>(current_block());
if (ib->skip)
{
@@ -2794,7 +2809,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)
@@ -2802,7 +2817,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;
}
}
@@ -2820,7 +2835,7 @@ void parser_t::eval_job(tokenizer_t *tok)
proc_set_last_status(1);
}
- current_block->job = 0;
+ current_block()->job = 0;
break;
}
@@ -3014,7 +3029,7 @@ int parser_t::eval(const wcstring &cmd_str, const io_chain_t &io, enum block_typ
const wchar_t * const cmd = cmd_str.c_str();
size_t forbid_count;
int code;
- const 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<io_chain_t> block_io_push(&block_io, io);
@@ -3068,9 +3083,9 @@ int parser_t::eval(const wcstring &cmd_str, const io_chain_t &io, enum block_typ
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."));
@@ -3085,7 +3100,7 @@ int parser_t::eval(const wcstring &cmd_str, const io_chain_t &io, enum block_typ
//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());
@@ -3380,8 +3395,7 @@ block_t::block_t(block_type_t t) :
src_filename(),
src_lineno(),
wants_pop_env(false),
- event_blocks(),
- outer(NULL)
+ event_blocks()
{
}