Remove the indentation part of parser_t::test(). Rename it to

detect_errors().
This commit is contained in:
ridiculousfish 2013-12-08 16:22:06 -08:00
parent 67b1f14a6f
commit 925fe65dd8
5 changed files with 23 additions and 125 deletions

View file

@ -497,14 +497,14 @@ static int builtin_complete(parser_t &parser, wchar_t **argv)
{ {
if (condition && wcslen(condition)) if (condition && wcslen(condition))
{ {
if (parser.test(condition)) if (parser.detect_errors(condition))
{ {
append_format(stderr_buffer, append_format(stderr_buffer,
L"%ls: Condition '%ls' contained a syntax error\n", L"%ls: Condition '%ls' contained a syntax error\n",
argv[0], argv[0],
condition); condition);
parser.test(condition, NULL, &stderr_buffer, argv[0]); parser.detect_errors(condition, &stderr_buffer, argv[0]);
res = true; res = true;
} }

View file

@ -585,52 +585,52 @@ static void test_parser()
parser_t parser(PARSER_TYPE_GENERAL, true); parser_t parser(PARSER_TYPE_GENERAL, true);
say(L"Testing null input to parser"); say(L"Testing null input to parser");
if (!parser.test(NULL)) if (!parser.detect_errors(NULL))
{ {
err(L"Null input to parser.test undetected"); err(L"Null input to parser.detect_errors undetected");
} }
say(L"Testing block nesting"); say(L"Testing block nesting");
if (!parser.test(L"if; end")) if (!parser.detect_errors(L"if; end"))
{ {
err(L"Incomplete if statement undetected"); err(L"Incomplete if statement undetected");
} }
if (!parser.test(L"if test; echo")) if (!parser.detect_errors(L"if test; echo"))
{ {
err(L"Missing end undetected"); err(L"Missing end undetected");
} }
if (!parser.test(L"if test; end; end")) if (!parser.detect_errors(L"if test; end; end"))
{ {
err(L"Unbalanced end undetected"); err(L"Unbalanced end undetected");
} }
say(L"Testing detection of invalid use of builtin commands"); say(L"Testing detection of invalid use of builtin commands");
if (!parser.test(L"case foo")) if (!parser.detect_errors(L"case foo"))
{ {
err(L"'case' command outside of block context undetected"); err(L"'case' command outside of block context undetected");
} }
if (!parser.test(L"switch ggg; if true; case foo;end;end")) if (!parser.detect_errors(L"switch ggg; if true; case foo;end;end"))
{ {
err(L"'case' command outside of switch block context undetected"); err(L"'case' command outside of switch block context undetected");
} }
if (!parser.test(L"else")) if (!parser.detect_errors(L"else"))
{ {
err(L"'else' command outside of conditional block context undetected"); err(L"'else' command outside of conditional block context undetected");
} }
if (!parser.test(L"else if")) if (!parser.detect_errors(L"else if"))
{ {
err(L"'else if' command outside of conditional block context undetected"); err(L"'else if' command outside of conditional block context undetected");
} }
if (!parser.test(L"if false; else if; end")) if (!parser.detect_errors(L"if false; else if; end"))
{ {
err(L"'else if' missing command undetected"); err(L"'else if' missing command undetected");
} }
if (!parser.test(L"break")) if (!parser.detect_errors(L"break"))
{ {
err(L"'break' command outside of loop block context undetected"); err(L"'break' command outside of loop block context undetected");
} }
if (!parser.test(L"exec ls|less") || !parser.test(L"echo|return")) if (!parser.detect_errors(L"exec ls|less") || !parser.detect_errors(L"echo|return"))
{ {
err(L"Invalid pipe command undetected"); err(L"Invalid pipe command undetected");
} }

View file

@ -2771,7 +2771,7 @@ int parser_t::parser_test_argument(const wchar_t *arg, wcstring *out, const wcha
// debug( 1, L"%ls -> %ls %ls", arg_cpy, subst, tmp.buff ); // debug( 1, L"%ls -> %ls %ls", arg_cpy, subst, tmp.buff );
err |= parser_t::test(subst, 0, out, prefix); err |= parser_t::detect_errors(subst, out, prefix);
free(subst); free(subst);
free(arg_cpy); free(arg_cpy);
@ -2906,12 +2906,9 @@ struct block_info_t
{ {
int position; //tokenizer position int position; //tokenizer position
block_type_t type; //type of the block block_type_t type; //type of the block
int indentation; //indentation associated with the block
bool has_had_case; //if we are a switch, whether we've encountered a case
}; };
parser_test_error_bits_t parser_t::test(const wchar_t *buff, int *block_level, wcstring *out, const wchar_t *prefix) parser_test_error_bits_t parser_t::detect_errors(const wchar_t *buff, wcstring *out, const wchar_t *prefix)
{ {
ASSERT_IS_MAIN_THREAD(); ASSERT_IS_MAIN_THREAD();
@ -2923,9 +2920,8 @@ parser_test_error_bits_t parser_t::test(const wchar_t *buff, int *block_level, w
int err=0; int err=0;
int unfinished = 0; int unfinished = 0;
// These are very nearly stacks, but sometimes we have to inspect non-top elements (e.g. return) // 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; std::vector<struct block_info_t> block_infos;
int indentation_sum = 0; //sum of indentation in block_infos
/* /*
Set to 1 if the current command is inside a pipeline Set to 1 if the current command is inside a pipeline
@ -2958,16 +2954,6 @@ parser_test_error_bits_t parser_t::test(const wchar_t *buff, int *block_level, w
CHECK(buff, 1); CHECK(buff, 1);
if (block_level)
{
size_t len = wcslen(buff);
for (size_t i=0; i<len; i++)
{
block_level[i] = -1;
}
}
tokenizer_t tok(buff, 0); tokenizer_t tok(buff, 0);
scoped_push<tokenizer_t*> tokenizer_push(&current_tokenizer, &tok); scoped_push<tokenizer_t*> tokenizer_push(&current_tokenizer, &tok);
@ -3059,53 +3045,18 @@ parser_test_error_bits_t parser_t::test(const wchar_t *buff, int *block_level, w
} }
else else
{ {
indentation_sum -= block_infos.back().indentation;
block_infos.pop_back(); block_infos.pop_back();
} }
} }
/*
Store the block level. This needs to be done
_after_ checking for end commands, but _before_
checking for block opening commands.
*/
if (block_level != NULL)
{
int indentation_adjust = 0;
if (command == L"else")
{
// if or else if goes back
indentation_adjust = -1;
}
else if (command == L"case")
{
if (! block_infos.empty() && block_infos.back().type == SWITCH)
{
// mark that we've encountered a case, and increase the indentation
// by doing this now, we avoid overly indenting the first case as the user types it
if (! block_infos.back().has_had_case)
{
block_infos.back().has_had_case = true;
block_infos.back().indentation += 1;
indentation_sum += 1;
}
// unindent this case
indentation_adjust = -1;
}
}
block_level[tok_get_pos(&tok)] = indentation_sum + indentation_adjust;
}
/* /*
Handle block commands Handle block commands
*/ */
if (parser_keywords_is_block(command)) if (parser_keywords_is_block(command))
{ {
struct block_info_t info = {current_tokenizer_pos, parser_get_block_type(command), 1 /* indent */}; struct block_info_t info = {current_tokenizer_pos, parser_get_block_type(command)};
block_infos.push_back(info); block_infos.push_back(info);
indentation_sum += info.indentation;
tok_next(&tok); tok_next(&tok);
tok_set_pos(&tok, mark); tok_set_pos(&tok, mark);
} }
@ -3651,52 +3602,6 @@ parser_test_error_bits_t parser_t::test(const wchar_t *buff, int *block_level, w
} }
/*
Fill in the unset block_level entries. Until now, only places
where the block level _changed_ have been filled out. This fills
in the rest.
*/
if (block_level)
{
int last_level = 0;
size_t i, len = wcslen(buff);
for (i=0; i<len; i++)
{
if (block_level[i] >= 0)
{
last_level = block_level[i];
/*
Make all whitespace before a token have the new
level. This avoid using the wrong indentation level
if a new line starts with whitespace.
*/
size_t prev_char_idx = i;
while (prev_char_idx--)
{
if (!wcschr(L" \n\t\r", buff[prev_char_idx]))
break;
block_level[prev_char_idx] = last_level;
}
}
block_level[i] = last_level;
}
/*
Make all trailing whitespace have the block level that the
validator had at exit. This makes sure a new line is
correctly indented even if it is empty.
*/
int last_indent = block_infos.empty() ? 0 : block_infos.back().indentation;
size_t suffix_idx = len;
while (suffix_idx--)
{
if (!wcschr(L" \n\t\r", buff[suffix_idx]))
break;
block_level[suffix_idx] = last_indent;
}
}
/* /*
Calculate exit status Calculate exit status
*/ */

View file

@ -487,7 +487,7 @@ public:
\param out if non-null, any errors in the command will be filled out into this buffer \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 \param prefix the prefix string to prepend to each error message written to the \c out buffer
*/ */
parser_test_error_bits_t test(const wchar_t * buff, int *block_level = NULL, wcstring *out = NULL, const wchar_t *prefix = NULL); parser_test_error_bits_t detect_errors(const wchar_t * buff, wcstring *out = NULL, const wchar_t *prefix = NULL);
/** /**
Test if the specified string can be parsed as an argument list, Test if the specified string can be parsed as an argument list,

View file

@ -519,14 +519,7 @@ wcstring combine_command_and_autosuggestion(const wcstring &cmdline, const wcstr
static void reader_repaint() static void reader_repaint()
{ {
// Update the indentation // Update the indentation
if (0) data->indents = parse_util_compute_indents(data->command_line);
{
parser_t::principal_parser().test(data->command_line.c_str(), &data->indents[0]);
}
else
{
data->indents = parse_util_compute_indents(data->command_line);
}
// Combine the command and autosuggestion into one string // Combine the command and autosuggestion into one string
wcstring full_line = combine_command_and_autosuggestion(data->command_line, data->autosuggestion); wcstring full_line = combine_command_and_autosuggestion(data->command_line, data->autosuggestion);
@ -2479,7 +2472,7 @@ void reader_run_command(parser_t &parser, const wcstring &cmd)
int reader_shell_test(const wchar_t *b) int reader_shell_test(const wchar_t *b)
{ {
int res = parser_t::principal_parser().test(b); int res = parser_t::principal_parser().detect_errors(b);
if (res & PARSER_TEST_ERROR) if (res & PARSER_TEST_ERROR)
{ {
@ -2499,7 +2492,7 @@ int reader_shell_test(const wchar_t *b)
0); 0);
parser_t::principal_parser().test(b, NULL, &sb, L"fish"); parser_t::principal_parser().detect_errors(b, &sb, L"fish");
fwprintf(stderr, L"%ls", sb.c_str()); fwprintf(stderr, L"%ls", sb.c_str());
} }
return res; return res;
@ -3911,7 +3904,7 @@ static int read_ni(int fd, const io_chain_t &io)
} }
wcstring sb; wcstring sb;
if (! parser.test(str.c_str(), 0, &sb, L"fish")) if (! parser.detect_errors(str.c_str(), &sb, L"fish"))
{ {
parser.eval(str, io, TOP); parser.eval(str, io, TOP);
} }