Remove detect_errors2

This commit is contained in:
ridiculousfish 2013-12-16 22:32:08 -08:00
parent af21dfd294
commit 384987cd5b
2 changed files with 0 additions and 720 deletions

View File

@ -2935,725 +2935,6 @@ void parser_t::get_backtrace(const wcstring &src, const parse_error_list_t &erro
}
}
parser_test_error_bits_t parser_t::detect_errors2(const wchar_t *buff, wcstring *out, const wchar_t *prefix)
{
ASSERT_IS_MAIN_THREAD();
/*
Set to one if a command name has been given for the currently
parsed process specification
*/
int had_cmd=0;
int err=0;
int unfinished = 0;
// This is very nearly a stack, but sometimes we have to inspect non-top elements (e.g. return)
std::vector<struct block_info_t> block_infos;
/*
Set to 1 if the current command is inside a pipeline
*/
int is_pipeline = 0;
/*
Set to one if the currently specified process can not be used inside a pipeline
*/
int forbid_pipeline = 0;
/*
Set to one if an additional process specification is needed
*/
bool needs_cmd = false;
/*
Counter on the number of arguments this function has encountered
so far. Is set to -1 when the count is unknown, i.e. after
encountering an argument that contains substitutions that can
expand to more/less arguemtns then 1.
*/
int arg_count=0;
/*
The currently validated command.
*/
wcstring command;
bool has_command = false;
CHECK(buff, 1);
tokenizer_t tok(buff, 0);
scoped_push<tokenizer_t*> tokenizer_push(&current_tokenizer, &tok);
scoped_push<int> tokenizer_pos_push(&current_tokenizer_pos);
for (;; tok_next(&tok))
{
current_tokenizer_pos = tok_get_pos(&tok);
int last_type = tok_last_type(&tok);
int end_of_cmd = 0;
switch (last_type)
{
case TOK_STRING:
{
if (!had_cmd)
{
int mark = tok_get_pos(&tok);
had_cmd = 1;
arg_count=0;
command = tok_last(&tok);
// Pass SKIP_HOME_DIRECTORIES for https://github.com/fish-shell/fish-shell/issues/512
has_command = expand_one(command, EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_VARIABLES | EXPAND_SKIP_HOME_DIRECTORIES);
if (! has_command)
{
command = L"";
err=1;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
ILLEGAL_CMD_ERR_MSG,
tok_last(&tok));
print_errors(*out, prefix);
}
break;
}
if (needs_cmd)
{
/*
end is not a valid command when a followup
command is needed, such as after 'and' or
'while'
*/
if (contains(command,
L"end"))
{
err=1;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
COND_ERR_MSG);
print_errors(*out, prefix);
}
}
needs_cmd = false;
}
/*
Decrement block count on end command
*/
if (command == L"end")
{
tok_next(&tok);
tok_set_pos(&tok, mark);
/* Test that end is not used when not inside any block */
if (block_infos.empty())
{
err = 1;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
INVALID_END_ERR_MSG);
print_errors(*out, prefix);
const wcstring h = builtin_help_get(*this, L"end");
if (! h.empty())
append_format(*out, L"%ls", h.c_str());
}
}
else
{
block_infos.pop_back();
}
}
/*
Handle block commands
*/
if (parser_keywords_is_block(command))
{
struct block_info_t info = {current_tokenizer_pos, parser_get_block_type(command)};
block_infos.push_back(info);
tok_next(&tok);
tok_set_pos(&tok, mark);
}
/*
If parser_keywords_is_subcommand is true, the command
accepts a second command as it's first
argument. If parser_skip_arguments is true, the
second argument is optional.
*/
if (parser_keywords_is_subcommand(command) && !parser_keywords_skip_arguments(command))
{
needs_cmd = true;
had_cmd = 0;
}
if (contains(command,
L"or",
L"and"))
{
/*
'or' and 'and' can not be used inside pipelines
*/
if (is_pipeline)
{
err=1;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
EXEC_ERR_MSG);
print_errors(*out, prefix);
}
}
}
/*
There are a lot of situations where pipelines
are forbidden, including when using the exec
builtin.
*/
if (parser_is_pipe_forbidden(command))
{
if (is_pipeline)
{
err=1;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
EXEC_ERR_MSG);
print_errors(*out, prefix);
}
}
forbid_pipeline = 1;
}
/*
Test that the case builtin is only used directly in a switch block
*/
if (command == L"case")
{
if (block_infos.empty() || block_infos.back().type != SWITCH)
{
err=1;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
INVALID_CASE_ERR_MSG);
print_errors(*out, prefix);
const wcstring h = builtin_help_get(*this, L"case");
if (h.size())
append_format(*out, L"%ls", h.c_str());
}
}
}
/*
Test that the return bultin is only used within function definitions
*/
if (command == L"return")
{
bool found_func = false;
size_t block_idx = block_infos.size();
while (block_idx--)
{
if (block_infos.at(block_idx).type == FUNCTION_DEF)
{
found_func = true;
break;
}
}
if (!found_func)
{
/*
Peek to see if the next argument is
--help, in which case we'll allow it to
show the help.
*/
int old_pos = tok_get_pos(&tok);
int is_help = 0;
tok_next(&tok);
if (tok_last_type(&tok) == TOK_STRING)
{
wcstring first_arg = tok_last(&tok);
if (expand_one(first_arg, EXPAND_SKIP_CMDSUBST) && parser_t::is_help(first_arg.c_str(), 3))
{
is_help = 1;
}
}
tok_set_pos(&tok, old_pos);
if (!is_help)
{
err=1;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
INVALID_RETURN_ERR_MSG);
print_errors(*out, prefix);
}
}
}
}
/*
Test that break and continue are only used within loop blocks
*/
if (contains(command, L"break", L"continue"))
{
bool found_loop = false;
size_t block_idx = block_infos.size();
while (block_idx--)
{
block_type_t type = block_infos.at(block_idx).type;
if (type == WHILE || type == FOR)
{
found_loop = true;
break;
}
}
if (!found_loop)
{
/*
Peek to see if the next argument is
--help, in which case we'll allow it to
show the help.
*/
int old_pos = tok_get_pos(&tok);
int is_help = 0;
tok_next(&tok);
if (tok_last_type(&tok) == TOK_STRING)
{
wcstring first_arg = tok_last(&tok);
if (expand_one(first_arg, EXPAND_SKIP_CMDSUBST) && parser_t::is_help(first_arg.c_str(), 3))
{
is_help = 1;
}
}
tok_set_pos(&tok, old_pos);
if (!is_help)
{
err=1;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
INVALID_LOOP_ERR_MSG);
print_errors(*out, prefix);
}
}
}
}
/*
Test that else and else-if are only used directly in an if-block
*/
if (command == L"else")
{
if (block_infos.empty() || block_infos.back().type != IF)
{
err=1;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
INVALID_ELSE_ERR_MSG,
command.c_str());
print_errors(*out, prefix);
}
}
}
}
else
{
err |= parser_test_argument(tok_last(&tok), out, prefix, tok_get_pos(&tok));
/* If possible, keep track of number of supplied arguments */
if (arg_count >= 0 && expand_is_clean(tok_last(&tok)))
{
arg_count++;
}
else
{
arg_count = -1;
}
if (has_command)
{
/*
Try to make sure the second argument to 'for' is 'in'
*/
if (command == L"for")
{
if (arg_count == 1)
{
if (wcsvarname(tok_last(&tok)))
{
err = 1;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
BUILTIN_FOR_ERR_NAME,
L"for",
tok_last(&tok));
print_errors(*out, prefix);
}
}
}
else if (arg_count == 2)
{
if (wcscmp(tok_last(&tok), L"in") != 0)
{
err = 1;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
BUILTIN_FOR_ERR_IN,
L"for");
print_errors(*out, prefix);
}
}
}
}
else if (command == L"else")
{
if (arg_count == 1)
{
/* Any second argument must be "if" */
if (wcscmp(tok_last(&tok), L"if") != 0)
{
err = 1;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
BUILTIN_ELSEIF_ERR_ARGUMENT,
L"else");
print_errors(*out, prefix);
}
}
else
{
/* Successfully detected "else if". Now we need a new command. */
needs_cmd = true;
had_cmd = false;
}
}
}
}
}
break;
}
case TOK_REDIRECT_OUT:
case TOK_REDIRECT_IN:
case TOK_REDIRECT_APPEND:
case TOK_REDIRECT_FD:
case TOK_REDIRECT_NOCLOB:
{
if (!had_cmd)
{
err = 1;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
INVALID_REDIRECTION_ERR_MSG);
print_errors(*out, prefix);
}
}
break;
}
case TOK_END:
{
if (needs_cmd && !had_cmd)
{
err = 1;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
CMD_ERR_MSG,
tok_get_desc(tok_last_type(&tok)));
print_errors(*out, prefix);
}
}
needs_cmd = false;
had_cmd = 0;
is_pipeline=0;
forbid_pipeline=0;
end_of_cmd = 1;
break;
}
case TOK_PIPE:
{
if (!had_cmd)
{
err=1;
if (out)
{
if (tok_get_pos(&tok)>0 && buff[tok_get_pos(&tok)-1] == L'|')
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
CMD_OR_ERR_MSG,
tok_get_desc(tok_last_type(&tok)));
}
else
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
CMD_ERR_MSG,
tok_get_desc(tok_last_type(&tok)));
}
print_errors(*out, prefix);
}
}
else if (forbid_pipeline)
{
err=1;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
EXEC_ERR_MSG);
print_errors(*out, prefix);
}
}
else
{
needs_cmd = true;
is_pipeline=1;
had_cmd=0;
end_of_cmd = 1;
}
break;
}
case TOK_BACKGROUND:
{
if (!had_cmd)
{
err = 1;
if (out)
{
if (tok_get_pos(&tok)>0 && buff[tok_get_pos(&tok)-1] == L'&')
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
CMD_AND_ERR_MSG,
tok_get_desc(tok_last_type(&tok)));
}
else
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
CMD_ERR_MSG,
tok_get_desc(tok_last_type(&tok)));
}
print_errors(*out, prefix);
}
}
had_cmd = 0;
end_of_cmd = 1;
break;
}
case TOK_ERROR:
default:
if (tok_get_error(&tok) == TOK_UNTERMINATED_QUOTE)
{
unfinished = 1;
}
else
{
// Only print errors once
if (out && ! err)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
TOK_ERR_MSG,
tok_last(&tok));
print_errors(*out, prefix);
}
err = 1;
}
break;
}
if (end_of_cmd)
{
if (has_command && command == L"for")
{
if (arg_count >= 0 && arg_count < 2)
{
/*
Not enough arguments to the for builtin
*/
err = 1;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
BUILTIN_FOR_ERR_COUNT,
L"for",
arg_count);
print_errors(*out, prefix);
}
}
}
else if (has_command && command == L"else")
{
if (arg_count == 1)
{
/* If we have any arguments, we must have at least two...either "else" or "else if foo..." */
err = true;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
BUILTIN_ELSEIF_ERR_COUNT,
L"else",
arg_count);
print_errors(*out, prefix);
}
}
}
}
if (!tok_has_next(&tok))
break;
}
if (needs_cmd)
{
err=1;
if (out)
{
error(SYNTAX_ERROR,
tok_get_pos(&tok),
COND_ERR_MSG);
print_errors(*out, prefix);
}
}
if (out != NULL && ! block_infos.empty())
{
const wchar_t *cmd;
int bad_pos = block_infos.back().position;
block_type_t bad_type = block_infos.back().type;
error(SYNTAX_ERROR, bad_pos, BLOCK_END_ERR_MSG);
print_errors(*out, prefix);
cmd = parser_get_block_command(bad_type);
if (cmd)
{
const wcstring h = builtin_help_get(*this, cmd);
if (h.size())
{
append_format(*out, L"%ls", h.c_str());
}
}
}
/*
Calculate exit status
*/
if (! block_infos.empty())
unfinished = 1;
parser_test_error_bits_t res = 0;
if (err)
res |= PARSER_TEST_ERROR;
if (unfinished)
res |= PARSER_TEST_INCOMPLETE;
/*
Cleanup
*/
error_code=0;
return res;
}
block_t::block_t(block_type_t t) :
block_type(t),
made_fake(false),

View File

@ -482,7 +482,6 @@ public:
\param out if non-null, any errors in the command will be filled out into this buffer
\param prefix the prefix string to prepend to each error message written to the \c out buffer
*/
parser_test_error_bits_t detect_errors2(const wchar_t *buff, wcstring *out_error_desc, const wchar_t *prefix);
void get_backtrace(const wcstring &src, const parse_error_list_t &errors, wcstring *output) const;
/**