aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--parser.cpp719
-rw-r--r--parser.h1
2 files changed, 0 insertions, 720 deletions
diff --git a/parser.cpp b/parser.cpp
index 59d0f51b..0d47e5e1 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -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),
diff --git a/parser.h b/parser.h
index 90b6a1c4..cbd59bf5 100644
--- a/parser.h
+++ b/parser.h
@@ -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;
/**