mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-30 19:41:15 -03:00
Refactor subcommand keyword detection
This file has bitrotted; for example commitbc66921ac9(Optimize keyword detection, 2019-04-03) removed use of SKIP_KEYWORDS but confusingly it's still around (even after0118eafee1(Remove unused functions, members (and a variable), 2022-04-09). Also some keywords appear in multiple lists; the separate lists are not really used today; there is a comment stating they may be useful in future. It would be great to add an optimization back but either way we should present the set of reserved words in source code as a contiguous list, to make it easy for humans to see all relevant information.
This commit is contained in:
@@ -2,64 +2,77 @@
|
||||
|
||||
use crate::wchar::prelude::*;
|
||||
|
||||
const SKIP_KEYWORDS: &[&wstr] = &[L!("else"), L!("begin")];
|
||||
const SUBCOMMAND_KEYWORDS: &[&wstr] = &[
|
||||
L!("and"),
|
||||
L!("begin"),
|
||||
L!("builtin"),
|
||||
L!("command"),
|
||||
L!("exec"),
|
||||
L!("if"),
|
||||
L!("not"),
|
||||
L!("or"),
|
||||
L!("time"),
|
||||
L!("while"),
|
||||
];
|
||||
const BLOCK_KEYWORDS: &[&wstr] = &[
|
||||
L!("begin"),
|
||||
L!("for"),
|
||||
L!("function"),
|
||||
L!("if"),
|
||||
L!("switch"),
|
||||
L!("while"),
|
||||
];
|
||||
struct ReservedWord {
|
||||
text: &'static wstr,
|
||||
is_super_command: bool,
|
||||
}
|
||||
|
||||
macro_rules! rw {
|
||||
( ( $text:literal ) ) => {
|
||||
ReservedWord {
|
||||
text: L!($text),
|
||||
is_super_command: false,
|
||||
}
|
||||
};
|
||||
( ( $text:literal, [subcommand] ) ) => {
|
||||
ReservedWord {
|
||||
text: L!($text),
|
||||
is_super_command: true,
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! reserved_words {
|
||||
( $( $reserved_word:tt , ) * ) => {
|
||||
&[ $( rw!($reserved_word), )* ]
|
||||
}
|
||||
}
|
||||
|
||||
// Don't forget to add any new reserved keywords to the documentation
|
||||
const RESERVED_KEYWORDS: &[&wstr] = &[
|
||||
L!("["),
|
||||
L!("_"),
|
||||
L!("argparse"),
|
||||
L!("break"),
|
||||
L!("case"),
|
||||
L!("continue"),
|
||||
L!("else"),
|
||||
L!("end"),
|
||||
L!("eval"),
|
||||
L!("read"),
|
||||
L!("return"),
|
||||
L!("set"),
|
||||
L!("status"),
|
||||
L!("string"),
|
||||
L!("test"),
|
||||
];
|
||||
const RESERVED_WORDS: &[ReservedWord] = reserved_words!(
|
||||
("["),
|
||||
("_"),
|
||||
("and", [subcommand]),
|
||||
("argparse"),
|
||||
("begin", [subcommand]),
|
||||
("break"),
|
||||
("builtin", [subcommand]),
|
||||
("case"),
|
||||
("command", [subcommand]),
|
||||
("continue"),
|
||||
("else"),
|
||||
("end"),
|
||||
("eval"),
|
||||
("exec", [subcommand]),
|
||||
("for"),
|
||||
("function"),
|
||||
("if", [subcommand]),
|
||||
("not", [subcommand]),
|
||||
("or", [subcommand]),
|
||||
("read"),
|
||||
("return"),
|
||||
("set"),
|
||||
("status"),
|
||||
("string"),
|
||||
("switch"),
|
||||
("test"),
|
||||
("time", [subcommand]),
|
||||
("while", [subcommand]),
|
||||
);
|
||||
|
||||
// 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.
|
||||
fn reserved_word(cmd: &wstr) -> Option<&'static ReservedWord> {
|
||||
RESERVED_WORDS
|
||||
.iter()
|
||||
.find(|reserved_word| reserved_word.text == cmd)
|
||||
}
|
||||
|
||||
/// Tests if the specified commands parameters should be interpreted as another command, which will
|
||||
/// be true if the command is either 'command', 'exec', 'if', 'while', or 'builtin'. This does not
|
||||
/// handle "else if" which is more complicated.
|
||||
/// Tests if the specified command's parameters should be interpreted as another command.
|
||||
pub fn parser_keywords_is_subcommand(cmd: &wstr) -> bool {
|
||||
SUBCOMMAND_KEYWORDS.contains(&cmd) || SKIP_KEYWORDS.contains(&cmd)
|
||||
reserved_word(cmd).is_some_and(|reserved_word| reserved_word.is_super_command)
|
||||
}
|
||||
|
||||
/// Tests if the specified command is a reserved word, i.e. if it is the name of one of the builtin
|
||||
/// functions that change the block or command scope, like 'for', 'end' or 'command' or 'exec'.
|
||||
/// These functions may not be overloaded, so their names are reserved.
|
||||
pub fn parser_keywords_is_reserved(word: &wstr) -> bool {
|
||||
SUBCOMMAND_KEYWORDS.contains(&word)
|
||||
|| SKIP_KEYWORDS.contains(&word)
|
||||
|| BLOCK_KEYWORDS.contains(&word)
|
||||
|| RESERVED_KEYWORDS.contains(&word)
|
||||
reserved_word(word).is_some()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user