Remove obviated builtins and additional cleanup of old parser

This commit is contained in:
ridiculousfish 2014-03-02 13:11:17 -08:00
parent b187125b63
commit 6b3a37c597
2 changed files with 10 additions and 720 deletions

View file

@ -1728,7 +1728,7 @@ static int builtin_pwd(parser_t &parser, wchar_t **argv)
}
}
/* This is nearly identical to builtin_function, and is intended to be the successor (with no block manipulation, no function/end split) */
/** Adds a function to the function set. It calls into function.cpp to perform any heavy lifting. */
int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstring &contents, wcstring *out_err)
{
assert(out_err != NULL);
@ -2034,338 +2034,6 @@ int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstr
return res;
}
/**
The function builtin, used for providing subroutines.
It calls various functions from function.c to perform any heavy lifting.
*/
static int builtin_function(parser_t &parser, wchar_t **argv)
{
/* Hack hack hack - with the new parser, this is only invoked for help */
if (parser_use_ast())
{
builtin_print_help(parser, argv[0], stdout_buffer);
return STATUS_BUILTIN_OK;
}
int argc = builtin_count_args(argv);
int res=STATUS_BUILTIN_OK;
wchar_t *desc=0;
std::vector<event_t> events;
std::auto_ptr<wcstring_list_t> named_arguments(NULL);
wchar_t *name = 0;
bool shadows = true;
woptind=0;
function_def_block_t * const fdb = new function_def_block_t();
parser.push_block(fdb);
const struct woption long_options[] =
{
{ L"description", required_argument, 0, 'd' },
{ L"on-signal", required_argument, 0, 's' },
{ L"on-job-exit", required_argument, 0, 'j' },
{ L"on-process-exit", required_argument, 0, 'p' },
{ L"on-variable", required_argument, 0, 'v' },
{ L"on-event", required_argument, 0, 'e' },
{ L"help", no_argument, 0, 'h' },
{ L"argument-names", no_argument, 0, 'a' },
{ L"no-scope-shadowing", no_argument, 0, 'S' },
{ 0, 0, 0, 0 }
};
while (1 && (!res))
{
int opt_index = 0;
int opt = wgetopt_long(argc,
argv,
L"d:s:j:p:v:e:haS",
long_options,
&opt_index);
if (opt == -1)
break;
switch (opt)
{
case 0:
if (long_options[opt_index].flag != 0)
break;
append_format(stderr_buffer,
BUILTIN_ERR_UNKNOWN,
argv[0],
long_options[opt_index].name);
res = 1;
break;
case 'd':
desc=woptarg;
break;
case 's':
{
int sig = wcs2sig(woptarg);
if (sig < 0)
{
append_format(stderr_buffer,
_(L"%ls: Unknown signal '%ls'\n"),
argv[0],
woptarg);
res=1;
break;
}
events.push_back(event_t::signal_event(sig));
break;
}
case 'v':
{
if (wcsvarname(woptarg))
{
append_format(stderr_buffer,
_(L"%ls: Invalid variable name '%ls'\n"),
argv[0],
woptarg);
res=STATUS_BUILTIN_ERROR;
break;
}
events.push_back(event_t::variable_event(woptarg));
break;
}
case 'e':
{
events.push_back(event_t::generic_event(woptarg));
break;
}
case 'j':
case 'p':
{
pid_t pid;
wchar_t *end;
event_t e(EVENT_ANY);
if ((opt == 'j') &&
(wcscasecmp(woptarg, L"caller") == 0))
{
int job_id = -1;
if (is_subshell)
{
size_t block_idx = 0;
/* Find the outermost substitution block */
for (block_idx = 0; ; block_idx++)
{
const block_t *b = parser.block_at_index(block_idx);
if (b == NULL || b->type() == SUBST)
break;
}
/* 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 = caller_block->job->job_id;
}
}
if (job_id == -1)
{
append_format(stderr_buffer,
_(L"%ls: Cannot find calling job for event handler\n"),
argv[0]);
res=1;
}
else
{
e.type = EVENT_JOB_ID;
e.param1.job_id = job_id;
}
}
else
{
errno = 0;
pid = fish_wcstoi(woptarg, &end, 10);
if (errno || !end || *end)
{
append_format(stderr_buffer,
_(L"%ls: Invalid process id %ls\n"),
argv[0],
woptarg);
res=1;
break;
}
e.type = EVENT_EXIT;
e.param1.pid = (opt=='j'?-1:1)*abs(pid);
}
if (res)
{
/* nothing */
}
else
{
events.push_back(e);
}
break;
}
case 'a':
if (named_arguments.get() == NULL)
named_arguments.reset(new wcstring_list_t);
break;
case 'S':
shadows = 0;
break;
case 'h':
parser.pop_block();
parser.push_block(new fake_block_t());
builtin_print_help(parser, argv[0], stdout_buffer);
return STATUS_BUILTIN_OK;
case '?':
builtin_unknown_option(parser, argv[0], argv[woptind-1]);
res = 1;
break;
}
}
if (!res)
{
if (argc == woptind)
{
append_format(stderr_buffer,
_(L"%ls: Expected function name\n"),
argv[0]);
res=1;
}
else if (wcsfuncname(argv[woptind]))
{
append_format(stderr_buffer,
_(L"%ls: Illegal function name '%ls'\n"),
argv[0],
argv[woptind]);
res=1;
}
else if (parser_keywords_is_reserved(argv[woptind]))
{
append_format(stderr_buffer,
_(L"%ls: The name '%ls' is reserved,\nand can not be used as a function name\n"),
argv[0],
argv[woptind]);
res=1;
}
else if (! wcslen(argv[woptind]))
{
append_format(stderr_buffer, _(L"%ls: No function name given\n"), argv[0]);
}
else
{
name = argv[woptind++];
if (named_arguments.get())
{
while (woptind < argc)
{
if (wcsvarname(argv[woptind]))
{
append_format(stderr_buffer,
_(L"%ls: Invalid variable name '%ls'\n"),
argv[0],
argv[woptind]);
res = STATUS_BUILTIN_ERROR;
break;
}
named_arguments->push_back(argv[woptind++]);
}
}
else if (woptind != argc)
{
append_format(stderr_buffer,
_(L"%ls: Expected one argument, got %d\n"),
argv[0],
argc);
res=1;
}
}
}
if (res)
{
size_t i;
size_t chars=0;
builtin_print_help(parser, argv[0], stderr_buffer);
const wchar_t *cfa = _(L"Current functions are: ");
stderr_buffer.append(cfa);
chars += wcslen(cfa);
wcstring_list_t names = function_get_names(0);
sort(names.begin(), names.end());
for (i=0; i<names.size(); i++)
{
const wchar_t *nxt = names.at(i).c_str();
size_t l = wcslen(nxt + 2);
if (chars+l > (size_t)common_get_width())
{
chars = 0;
stderr_buffer.push_back(L'\n');
}
stderr_buffer.append(nxt);
stderr_buffer.append(L" ");
}
stderr_buffer.push_back(L'\n');
parser.pop_block();
parser.push_block(new fake_block_t());
}
else
{
function_data_t &d = fdb->function_data;
d.name = name;
if (desc)
d.description = desc;
d.events.swap(events);
d.shadows = shadows;
if (named_arguments.get())
d.named_arguments.swap(*named_arguments);
for (size_t i=0; i<d.events.size(); i++)
{
event_t &e = d.events.at(i);
e.function_name = d.name;
}
}
parser.current_block()->tok_pos = parser.get_pos();
parser.current_block()->skip = 1;
return STATUS_BUILTIN_OK;
}
/**
The random builtin. For generating random numbers.
*/
@ -3713,195 +3381,6 @@ static int builtin_for(parser_t &parser, wchar_t **argv)
return res;
}
/**
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();
return proc_get_last_status();
}
/**
Builtin for ending a block of code, such as a for-loop or an if statement.
The end command is whare a lot of the block-level magic happens.
*/
static int builtin_end(parser_t &parser, wchar_t **argv)
{
if (! parser.block_at_index(1))
{
append_format(stderr_buffer,
_(L"%ls: Not inside of block\n"),
argv[0]);
builtin_print_help(parser, argv[0], stderr_buffer);
return STATUS_BUILTIN_ERROR;
}
else
{
/**
By default, 'end' kills the current block scope. But if we
are rewinding a loop, this should be set to false, so that
variables in the current loop scope won't die between laps.
*/
bool kill_block = true;
block_t * const current_block = parser.current_block();
switch (current_block->type())
{
case WHILE:
{
/*
If this is a while loop, we rewind the loop unless
it's the last lap, in which case we continue.
*/
if (!(current_block->skip && (current_block->loop_status != LOOP_CONTINUE)))
{
current_block->loop_status = LOOP_NORMAL;
current_block->skip = 0;
kill_block = false;
parser.set_pos(current_block->tok_pos);
while_block_t *blk = static_cast<while_block_t *>(current_block);
blk->status = WHILE_TEST_AGAIN;
}
break;
}
case IF:
/* Always return success (#1061) */
proc_set_last_status(0);
break;
case SUBST:
case BEGIN:
case SWITCH:
case FAKE:
/*
Nothing special happens at the end of these commands. The scope just ends.
*/
break;
case FOR:
{
/*
set loop variable to next element, and rewind to the beginning of the block.
*/
for_block_t *fb = static_cast<for_block_t *>(current_block);
wcstring_list_t &for_vars = fb->sequence;
if (current_block->loop_status == LOOP_BREAK)
{
for_vars.clear();
}
if (! for_vars.empty())
{
const wcstring val = for_vars.back();
for_vars.pop_back();
const wcstring &for_variable = fb->variable;
env_set(for_variable, val.c_str(), ENV_LOCAL);
current_block->loop_status = LOOP_NORMAL;
current_block->skip = 0;
kill_block = false;
parser.set_pos(current_block->tok_pos);
}
break;
}
case FUNCTION_DEF:
{
function_def_block_t *fdb = static_cast<function_def_block_t *>(current_block);
function_data_t &d = fdb->function_data;
if (d.name.empty())
{
/* Disallow empty function names */
append_format(stderr_buffer, _(L"%ls: No function name given\n"), argv[0]);
/* Return an error via a crummy way. Don't just return here, since we need to pop the block. */
proc_set_last_status(STATUS_BUILTIN_ERROR);
}
else
{
/**
Copy the text from the beginning of the function
until the end command and use as the new definition
for the specified function
*/
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);
free(def);
}
}
break;
default:
assert(false); //should never get here
break;
}
if (kill_block)
{
parser.pop_block();
}
/*
If everything goes ok, return status of last command to execute.
*/
return proc_get_last_status();
}
}
/**
Builtin for executing commands if an if statement is false
*/
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_block = static_cast<if_block_t *>(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)
{
block_ok = true;
}
}
if (! block_ok)
{
append_format(stderr_buffer,
_(L"%ls: Not inside of 'if' block\n"),
argv[0]);
builtin_print_help(parser, argv[0], stderr_buffer);
return STATUS_BUILTIN_ERROR;
}
else
{
/* Run the else block if the IF expression was false and so were all the ELSEIF expressions (if any) */
bool run_else = ! if_block->any_branch_taken;
if_block->skip = ! run_else;
if_block->else_evaluated = true;
env_pop();
env_push(false);
}
/*
If everything goes ok, return status of last command to execute.
*/
return proc_get_last_status();
}
/**
This function handles both the 'continue' and the 'break' builtins
that are used for loop control.
@ -4037,90 +3516,6 @@ static int builtin_return(parser_t &parser, wchar_t **argv)
return status;
}
/**
Builtin for executing one of several blocks of commands depending
on the value of an argument.
*/
static int builtin_switch(parser_t &parser, wchar_t **argv)
{
int res=STATUS_BUILTIN_OK;
int argc = builtin_count_args(argv);
/* Hackish - if we have no arguments other than the command, we are a "naked invocation" and we just print help */
if (argc == 1)
{
builtin_print_help(parser, argv[0], stdout_buffer);
return STATUS_BUILTIN_ERROR;
}
if (argc != 2)
{
append_format(stderr_buffer,
_(L"%ls: Expected exactly one argument, got %d\n"),
argv[0],
argc-1);
builtin_print_help(parser, argv[0], stderr_buffer);
res=1;
parser.push_block(new fake_block_t());
}
else
{
parser.push_block(new switch_block_t(argv[1]));
parser.current_block()->skip=1;
res = proc_get_last_status();
}
return res;
}
/**
Builtin used together with the switch builtin for conditional
execution
*/
static int builtin_case(parser_t &parser, wchar_t **argv)
{
int argc = builtin_count_args(argv);
int i;
wchar_t *unescaped=0;
if (parser.current_block()->type() != SWITCH)
{
append_format(stderr_buffer,
_(L"%ls: 'case' command while not in switch block\n"),
argv[0]);
builtin_print_help(parser, argv[0], stderr_buffer);
return STATUS_BUILTIN_ERROR;
}
parser.current_block()->skip = 1;
switch_block_t *sb = static_cast<switch_block_t *>(parser.current_block());
if (sb->switch_taken)
{
return proc_get_last_status();
}
const wcstring &switch_value = sb->switch_value;
for (i=1; i<argc; i++)
{
int match;
unescaped = parse_util_unescape_wildcards(argv[i]);
match = wildcard_match(switch_value, unescaped);
free(unescaped);
if (match)
{
parser.current_block()->skip = 0;
sb->switch_taken = true;
break;
}
}
return proc_get_last_status();
}
/**
History of commands executed by user
*/
@ -4317,14 +3712,14 @@ static const builtin_data_t builtin_datas[]=
{ L"[", &builtin_test, N_(L"Test a condition") },
{ L"__fish_parse", &builtin_parse, N_(L"Try out the new parser") },
{ L"and", &builtin_generic, N_(L"Execute command if previous command suceeded") },
{ L"begin", &builtin_begin, N_(L"Create a block of code") },
{ L"begin", &builtin_generic, N_(L"Create a block of code") },
{ L"bg", &builtin_bg, N_(L"Send job to background") },
{ L"bind", &builtin_bind, N_(L"Handle fish key bindings") },
{ L"block", &builtin_block, N_(L"Temporarily block delivery of events") },
{ L"break", &builtin_break_continue, N_(L"Stop the innermost loop") },
{ L"breakpoint", &builtin_breakpoint, N_(L"Temporarily halt execution of a script and launch an interactive debug prompt") },
{ L"builtin", &builtin_builtin, N_(L"Run a builtin command instead of a function") },
{ L"case", &builtin_case, N_(L"Conditionally execute a block of commands") },
{ L"case", &builtin_generic, N_(L"Conditionally execute a block of commands") },
{ L"cd", &builtin_cd, N_(L"Change working directory") },
{ L"command", &builtin_generic, N_(L"Run a program instead of a function or builtin") },
{ L"commandline", &builtin_commandline, N_(L"Set or get the commandline") },
@ -4333,14 +3728,14 @@ static const builtin_data_t builtin_datas[]=
{ L"continue", &builtin_break_continue, N_(L"Skip the rest of the current lap of the innermost loop") },
{ L"count", &builtin_count, N_(L"Count the number of arguments") },
{ L"echo", &builtin_echo, N_(L"Print arguments") },
{ L"else", &builtin_else, N_(L"Evaluate block if condition is false") },
{ L"else", &builtin_generic, N_(L"Evaluate block if condition is false") },
{ L"emit", &builtin_emit, N_(L"Emit an event") },
{ L"end", &builtin_end, N_(L"End a block of commands") },
{ L"end", &builtin_generic, N_(L"End a block of commands") },
{ L"exec", &builtin_generic, N_(L"Run command in current process") },
{ L"exit", &builtin_exit, N_(L"Exit the shell") },
{ L"fg", &builtin_fg, N_(L"Send job to foreground") },
{ L"for", &builtin_for, N_(L"Perform a set of commands multiple times") },
{ L"function", &builtin_function, N_(L"Define a new function") },
{ L"function", &builtin_generic, N_(L"Define a new function") },
{ L"functions", &builtin_functions, N_(L"List or remove functions") },
{ L"history", &builtin_history, N_(L"History of commands executed by user") },
{ L"if", &builtin_generic, N_(L"Evaluate block if condition is true") },
@ -4356,7 +3751,7 @@ static const builtin_data_t builtin_datas[]=
{ L"set_color", &builtin_set_color, N_(L"Set the terminal color") },
{ L"source", &builtin_source, N_(L"Evaluate contents of file") },
{ L"status", &builtin_status, N_(L"Return status information about fish") },
{ L"switch", &builtin_switch, N_(L"Conditionally execute a block of commands") },
{ L"switch", &builtin_generic, N_(L"Conditionally execute a block of commands") },
{ L"test", &builtin_test, N_(L"Test a condition") },
{ L"ulimit", &builtin_ulimit, N_(L"Set or get the shells resource usage limits") },
{ L"while", &builtin_generic, N_(L"Perform a command multiple times") }

View file

@ -349,93 +349,6 @@ block_t *parser_t::current_block()
return block_stack.empty() ? NULL : block_stack.back();
}
/**
Search the text for the end of the current block
*/
static const wchar_t *parser_find_end(const wchar_t * buff)
{
int had_cmd=0;
int count = 0;
int error=0;
int mark=0;
CHECK(buff, 0);
tokenizer_t tok(buff, 0);
for (; tok_has_next(&tok) && !error; tok_next(&tok))
{
int last_type = tok_last_type(&tok);
switch (last_type)
{
case TOK_STRING:
{
if (!had_cmd)
{
if (wcscmp(tok_last(&tok), L"end")==0)
{
count--;
}
else if (parser_keywords_is_block(tok_last(&tok)))
{
count++;
}
if (count < 0)
{
error = 1;
}
had_cmd = 1;
}
break;
}
case TOK_END:
{
had_cmd = 0;
break;
}
case TOK_PIPE:
case TOK_BACKGROUND:
{
if (had_cmd)
{
had_cmd = 0;
}
else
{
error = 1;
}
break;
}
case TOK_ERROR:
error = 1;
break;
default:
break;
}
if (!count)
{
tok_next(&tok);
mark = tok_get_pos(&tok);
break;
}
}
if (!count && !error)
{
return buff+mark;
}
return 0;
}
void parser_t::forbid_function(const wcstring &function)
{
forbidden_function.push_back(function);
@ -826,29 +739,11 @@ const wchar_t *parser_t::is_function() const
int parser_t::get_lineno() const
{
if (parser_use_ast())
int lineno = -1;
if (! execution_contexts.empty())
{
int lineno = -1;
if (! execution_contexts.empty())
{
lineno = execution_contexts.back()->get_current_line_number();
}
return lineno;
lineno = execution_contexts.back()->get_current_line_number();
}
int lineno;
if (! current_tokenizer || ! tok_string(current_tokenizer))
return -1;
lineno = current_tokenizer->line_number_of_character_at_offset(current_tokenizer_pos);
const wchar_t *function_name;
if ((function_name = is_function()))
{
lineno += function_get_definition_offset(function_name);
}
return lineno;
}