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) int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstring &contents, wcstring *out_err)
{ {
assert(out_err != NULL); assert(out_err != NULL);
@@ -2034,338 +2034,6 @@ int define_function(parser_t &parser, const wcstring_list_t &c_args, const wcstr
return res; 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. The random builtin. For generating random numbers.
*/ */
@@ -3713,195 +3381,6 @@ static int builtin_for(parser_t &parser, wchar_t **argv)
return res; 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 This function handles both the 'continue' and the 'break' builtins
that are used for loop control. that are used for loop control.
@@ -4037,90 +3516,6 @@ static int builtin_return(parser_t &parser, wchar_t **argv)
return status; 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 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"[", &builtin_test, N_(L"Test a condition") },
{ L"__fish_parse", &builtin_parse, N_(L"Try out the new parser") }, { 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"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"bg", &builtin_bg, N_(L"Send job to background") },
{ L"bind", &builtin_bind, N_(L"Handle fish key bindings") }, { L"bind", &builtin_bind, N_(L"Handle fish key bindings") },
{ L"block", &builtin_block, N_(L"Temporarily block delivery of events") }, { L"block", &builtin_block, N_(L"Temporarily block delivery of events") },
{ L"break", &builtin_break_continue, N_(L"Stop the innermost loop") }, { 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"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"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"cd", &builtin_cd, N_(L"Change working directory") },
{ L"command", &builtin_generic, N_(L"Run a program instead of a function or builtin") }, { 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") }, { 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"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"count", &builtin_count, N_(L"Count the number of arguments") },
{ L"echo", &builtin_echo, N_(L"Print 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"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"exec", &builtin_generic, N_(L"Run command in current process") },
{ L"exit", &builtin_exit, N_(L"Exit the shell") }, { L"exit", &builtin_exit, N_(L"Exit the shell") },
{ L"fg", &builtin_fg, N_(L"Send job to foreground") }, { L"fg", &builtin_fg, N_(L"Send job to foreground") },
{ L"for", &builtin_for, N_(L"Perform a set of commands multiple times") }, { 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"functions", &builtin_functions, N_(L"List or remove functions") },
{ L"history", &builtin_history, N_(L"History of commands executed by user") }, { L"history", &builtin_history, N_(L"History of commands executed by user") },
{ L"if", &builtin_generic, N_(L"Evaluate block if condition is true") }, { 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"set_color", &builtin_set_color, N_(L"Set the terminal color") },
{ L"source", &builtin_source, N_(L"Evaluate contents of file") }, { L"source", &builtin_source, N_(L"Evaluate contents of file") },
{ L"status", &builtin_status, N_(L"Return status information about fish") }, { 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"test", &builtin_test, N_(L"Test a condition") },
{ L"ulimit", &builtin_ulimit, N_(L"Set or get the shells resource usage limits") }, { 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") } { 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(); 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) void parser_t::forbid_function(const wcstring &function)
{ {
forbidden_function.push_back(function); forbidden_function.push_back(function);
@@ -826,29 +739,11 @@ const wchar_t *parser_t::is_function() const
int parser_t::get_lineno() const int parser_t::get_lineno() const
{ {
if (parser_use_ast()) int lineno = -1;
if (! execution_contexts.empty())
{ {
int lineno = -1; lineno = execution_contexts.back()->get_current_line_number();
if (! execution_contexts.empty())
{
lineno = execution_contexts.back()->get_current_line_number();
}
return lineno;
} }
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; return lineno;
} }