Teach builtin_test about the special precedence rules in IEEE 1003.1

https://github.com/fish-shell/fish-shell/issues/601
This commit is contained in:
ridiculousfish 2013-03-03 13:22:00 -08:00
parent cbcc439e03
commit 1d75c232ff
2 changed files with 139 additions and 42 deletions

View file

@ -177,6 +177,8 @@ public:
{ }
expression *parse_expression(unsigned int start, unsigned int end);
expression *parse_3_arg_expression(unsigned int start, unsigned int end);
expression *parse_4_arg_expression(unsigned int start, unsigned int end);
expression *parse_combining_expression(unsigned int start, unsigned int end);
expression *parse_unary_expression(unsigned int start, unsigned int end);
@ -539,6 +541,64 @@ expression *test_parser::parse_primary(unsigned int start, unsigned int end)
return expr;
}
// See IEEE 1003.1 breakdown of the behavior for different parameter counts
expression *test_parser::parse_3_arg_expression(unsigned int start, unsigned int end)
{
assert(end - start == 3);
expression *result = NULL;
const token_info_t *center_token = token_for_string(arg(start + 1));
if (center_token->flags & BINARY_PRIMARY)
{
result = parse_binary_primary(start, end);
}
else if (center_token->tok == test_combine_and || center_token->tok == test_combine_or)
{
expr_ref_t left(parse_unary_expression(start, start + 1));
expr_ref_t right(parse_unary_expression(start + 2, start + 3));
if (left.get() && right.get())
{
// Transfer ownership to the vector of subjects
std::vector<token_t> combiners(1, center_token->tok);
std::vector<expression *> subjects;
subjects.push_back(left.release());
subjects.push_back(right.release());
result = new combining_expression(center_token->tok, range_t(start, end), subjects, combiners);
}
}
else
{
result = parse_unary_expression(start, end);
}
return result;
}
expression *test_parser::parse_4_arg_expression(unsigned int start, unsigned int end)
{
assert(end - start == 4);
expression *result = NULL;
token_t first_token = token_for_string(arg(start))->tok;
if (first_token == test_bang)
{
expr_ref_t subject(parse_3_arg_expression(start + 1, end));
if (subject.get())
{
result = new unary_operator(first_token, range_t(start, subject->range.end), subject);
}
}
else if (first_token == test_paren_open)
{
result = parse_parenthentical(start, end);
}
else
{
result = parse_combining_expression(start, end);
}
return result;
}
expression *test_parser::parse_expression(unsigned int start, unsigned int end)
{
if (start >= end)
@ -546,8 +606,38 @@ expression *test_parser::parse_expression(unsigned int start, unsigned int end)
return error(L"Missing argument at index %u", start);
}
unsigned int argc = end - start;
switch (argc)
{
case 0:
assert(0); //should have been caught by the above test
return NULL;
case 1:
{
return error(L"Missing argument at index %u", start + 1);
}
case 2:
{
return parse_unary_expression(start, end);
}
case 3:
{
return parse_3_arg_expression(start, end);
}
case 4:
{
return parse_4_arg_expression(start, end);
}
default:
{
return parse_combining_expression(start, end);
}
}
}
expression *test_parser::parse_args(const wcstring_list_t &args, wcstring &err)
{
@ -829,17 +919,19 @@ int builtin_test(parser_t &parser, wchar_t **argv)
/* Collect the arguments into a list */
const wcstring_list_t args(argv + 1, argv + 1 + argc);
if (argc == 0)
switch (argc)
{
case 0:
{
// Per 1003.1, exit false
return BUILTIN_TEST_FAIL;
}
else if (argc == 1)
case 1:
{
// Per 1003.1, exit true if the arg is non-empty
return args.at(0).empty() ? BUILTIN_TEST_FAIL : BUILTIN_TEST_SUCCESS;
}
else
default:
{
// Try parsing. If expr is not nil, we are responsible for deleting it.
wcstring err;
@ -873,5 +965,6 @@ int builtin_test(parser_t &parser, wchar_t **argv)
return result ? BUILTIN_TEST_SUCCESS : BUILTIN_TEST_FAIL;
}
}
}
return 1;
}

View file

@ -936,6 +936,10 @@ static void test_test()
/* This crashed */
assert(run_test_test(1, L"1 = 1 -a = 1"));
/* Make sure we can treat -S as a parameter instead of an operator. https://github.com/fish-shell/fish-shell/issues/601 */
assert(run_test_test(0, L"-S = -S"));
assert(run_test_test(1, L"! ! ! A"));
}
/** Testing colors */