Support for parsing e.g. 'command --' as a plain statement, instead of

executing the command '--'.
This commit is contained in:
ridiculousfish 2013-10-12 01:46:22 -07:00
parent 5490f54d00
commit 77e358a001
4 changed files with 30 additions and 9 deletions

View file

@ -2002,6 +2002,8 @@ static void test_new_parser_ll2(void)
{L"command --help", L"command", L"--help", parse_statement_decoration_none}, {L"command --help", L"command", L"--help", parse_statement_decoration_none},
{L"command -h", L"command", L"-h", parse_statement_decoration_none}, {L"command -h", L"command", L"-h", parse_statement_decoration_none},
{L"command", L"command", L"", parse_statement_decoration_none}, {L"command", L"command", L"", parse_statement_decoration_none},
{L"command -", L"command", L"-", parse_statement_decoration_none},
{L"command --", L"command", L"--", parse_statement_decoration_none},
{L"function", L"function", L"", parse_statement_decoration_none}, {L"function", L"function", L"", parse_statement_decoration_none},
{L"function --help", L"function", L"--help", parse_statement_decoration_none} {L"function --help", L"function", L"--help", parse_statement_decoration_none}
}; };

View file

@ -26,19 +26,32 @@ static bool production_is_valid(const production_options_t production_list, prod
return nonempty_found; return nonempty_found;
} }
/* Helper function indicates whether a token (typically second token) means 'help'. This is so we can treat e.g. 'command --help' as "invoke the 'command' builtin with --help' instead of 'run the --help command'. /* Helper function indicates whether a token (typically second token) causes the preceding token to be treated as a command instead of giving it a special role. This is so we can treat e.g. 'command --help' as "invoke the 'command' builtin with --help' instead of 'run the --help command'.
if naked_invocation_invokes_help is true, then we treat an invalid type or something other than a string as indicating help; this means that the user ran e.g. 'command' with no arguments. if naked_invocation_invokes_help is true, then we treat an invalid type or something other than a string as indicating help; this means that the user ran e.g. 'command' with no arguments.
*/ */
static inline bool token_means_help(parse_token_type_t type, parse_keyword_t keyword, bool naked_invocation_invokes_help) static inline bool token_implies_previous_keyword_is_command(parse_token_type_t type, parse_keyword_t keyword, bool naked_invocation_invokes_help)
{ {
if (keyword == parse_keyword_dash_h || keyword == parse_keyword_dashdash_help) bool result = false;
return true; switch (keyword)
{
case parse_keyword_dash:
case parse_keyword_dashdash:
case parse_keyword_dash_h:
case parse_keyword_dashdash_help:
result = true;
break;
if (naked_invocation_invokes_help && type != parse_token_type_string) default:
return true; break;
}
return false; if (! result)
{
result = naked_invocation_invokes_help && type != parse_token_type_string;
}
return result;
} }
#define PRODUCTIONS(sym) static const production_options_t productions_##sym #define PRODUCTIONS(sym) static const production_options_t productions_##sym
@ -135,7 +148,7 @@ RESOLVE(statement)
if (token_type == parse_token_type_string) if (token_type == parse_token_type_string)
{ {
bool naked_invocation_invokes_help = (token_keyword != parse_keyword_begin && token_keyword != parse_keyword_end); bool naked_invocation_invokes_help = (token_keyword != parse_keyword_begin && token_keyword != parse_keyword_end);
if (token_means_help(token_type2, token_keyword2, naked_invocation_invokes_help)) if (token_implies_previous_keyword_is_command(token_type2, token_keyword2, naked_invocation_invokes_help))
{ {
return 4; //decorated statement return 4; //decorated statement
} }
@ -175,6 +188,8 @@ RESOLVE(statement)
case parse_keyword_command: case parse_keyword_command:
case parse_keyword_builtin: case parse_keyword_builtin:
case parse_keyword_case: case parse_keyword_case:
case parse_keyword_dash:
case parse_keyword_dashdash:
case parse_keyword_dash_h: case parse_keyword_dash_h:
case parse_keyword_dashdash_help: case parse_keyword_dashdash_help:
return 4; return 4;
@ -365,7 +380,7 @@ PRODUCTIONS(decorated_statement) =
RESOLVE(decorated_statement) RESOLVE(decorated_statement)
{ {
/* If this is e.g. 'command --help' then the command is 'command' and not a decoration */ /* If this is e.g. 'command --help' then the command is 'command' and not a decoration */
if (token_means_help(token_type2, token_keyword2, true /* naked_invocation_is_help */)) if (token_implies_previous_keyword_is_command(token_type2, token_keyword2, true /* naked_invocation_is_help */))
return 0; return 0;
switch (token_keyword) switch (token_keyword)

View file

@ -784,6 +784,8 @@ static parse_keyword_t keyword_for_token(token_type tok, const wchar_t *tok_txt)
{L"not", parse_keyword_not}, {L"not", parse_keyword_not},
{L"command", parse_keyword_command}, {L"command", parse_keyword_command},
{L"builtin", parse_keyword_builtin}, {L"builtin", parse_keyword_builtin},
{L"-", parse_keyword_dash},
{L"--", parse_keyword_dashdash},
{L"-h", parse_keyword_dash_h}, {L"-h", parse_keyword_dash_h},
{L"--help", parse_keyword_dashdash_help} {L"--help", parse_keyword_dashdash_help}
}; };

View file

@ -114,6 +114,8 @@ enum parse_keyword_t
parse_keyword_builtin, parse_keyword_builtin,
/* The following are not really keywords but are necessary for e.g. "command --help" to work */ /* The following are not really keywords but are necessary for e.g. "command --help" to work */
parse_keyword_dash,
parse_keyword_dashdash,
parse_keyword_dash_h, parse_keyword_dash_h,
parse_keyword_dashdash_help, parse_keyword_dashdash_help,