// Functions having to do with parser keywords, like testing if a function is a block command. #include "config.h" // IWYU pragma: keep #include #include #include "common.h" #include "fallback.h" // IWYU pragma: keep #include "parser_keywords.h" typedef std::unordered_set string_set_t; static const wcstring skip_keywords[]{ L"else", L"begin", }; static const wcstring subcommand_keywords[]{L"command", L"builtin", L"while", L"exec", L"if", L"and", L"or", L"not"}; static const string_set_t block_keywords = {L"for", L"while", L"if", L"function", L"switch", L"begin"}; static const wcstring reserved_keywords[] = {L"end", L"case", L"else", L"return", L"continue", L"break", L"argparse", L"read", L"set", L"status", L"test", L"["}; // The lists above are purposely implemented separately from the logic below, so that future // maintainers may assume the contents of the list based off their names, and not off what the // functions below require them to contain. static size_t list_max_length(const string_set_t &list) { size_t result = 0; for (const auto &w : list) { if (w.length() > result) { result = w.length(); } } return result; } bool parser_keywords_skip_arguments(const wcstring &cmd) { return cmd == skip_keywords[0] || cmd == skip_keywords[1]; } bool parser_keywords_is_subcommand(const wcstring &cmd) { const static string_set_t search_list = ([]() { string_set_t results; results.insert(std::begin(subcommand_keywords), std::end(subcommand_keywords)); results.insert(std::begin(skip_keywords), std::end(skip_keywords)); return results; })(); const static auto max_len = list_max_length(search_list); const static auto not_found = search_list.end(); // Everything above is executed only at startup, this is the actual optimized search routine: return cmd.length() <= max_len && search_list.find(cmd) != not_found; } bool parser_keywords_is_block(const wcstring &word) { const static auto max_len = list_max_length(block_keywords); const static auto not_found = block_keywords.end(); // Everything above is executed only at startup, this is the actual optimized search routine: return word.length() <= max_len && block_keywords.find(word) != not_found; } bool parser_keywords_is_reserved(const wcstring &word) { const static string_set_t search_list = ([]() { string_set_t results; results.insert(std::begin(subcommand_keywords), std::end(subcommand_keywords)); results.insert(std::begin(skip_keywords), std::end(skip_keywords)); results.insert(std::begin(block_keywords), std::end(block_keywords)); results.insert(std::begin(reserved_keywords), std::end(reserved_keywords)); return results; })(); const static auto max_len = list_max_length(search_list); const static auto not_found = search_list.end(); // Everything above is executed only at startup, this is the actual optimized search routine: return word.length() <= max_len && search_list.find(word) != not_found; }