yash_syntax/parser/lex/
raw_param.rsuse super::core::Lexer;
use crate::parser::core::Result;
use crate::syntax::Param;
use crate::syntax::ParamType;
use crate::syntax::SpecialParam;
use crate::syntax::TextUnit;
pub const fn is_portable_name_char(c: char) -> bool {
matches!(c, '0'..='9' | 'A'..='Z' | '_' | 'a'..='z')
}
pub const fn is_special_parameter_char(c: char) -> bool {
SpecialParam::from_char(c).is_some()
}
pub const fn is_single_char_name(c: char) -> bool {
c.is_ascii_digit() || is_special_parameter_char(c)
}
impl Lexer<'_> {
pub async fn raw_param(&mut self, start_index: usize) -> Result<Option<TextUnit>> {
let param = if let Some(c) = self.consume_char_if(is_special_parameter_char).await? {
Param {
id: c.value.to_string(),
r#type: SpecialParam::from_char(c.value).unwrap().into(),
}
} else if let Some(c) = self.consume_char_if(|c| c.is_ascii_digit()).await? {
Param {
id: c.value.to_string(),
r#type: ParamType::Positional(c.value.to_digit(10).unwrap() as usize),
}
} else if let Some(c) = self.consume_char_if(is_portable_name_char).await? {
let mut name = c.value.to_string();
while let Some(c) = self.consume_char_if(is_portable_name_char).await? {
name.push(c.value);
}
Param::variable(name)
} else {
return Ok(None);
};
let location = self.location_range(start_index..self.index());
Ok(Some(TextUnit::RawParam { param, location }))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::source::Source;
use crate::syntax::Param;
use assert_matches::assert_matches;
use futures_util::FutureExt;
#[test]
fn lexer_raw_param_special_parameter() {
let mut lexer = Lexer::from_memory("$@;", Source::Unknown);
lexer.peek_char().now_or_never().unwrap().unwrap();
lexer.consume_char();
let result = lexer.raw_param(0).now_or_never().unwrap().unwrap().unwrap();
assert_matches!(result, TextUnit::RawParam { param, location } => {
assert_eq!(param, Param::from(SpecialParam::At));
assert_eq!(*location.code.value.borrow(), "$@;");
assert_eq!(location.code.start_line_number.get(), 1);
assert_eq!(*location.code.source, Source::Unknown);
assert_eq!(location.range, 0..2);
});
assert_eq!(lexer.peek_char().now_or_never().unwrap(), Ok(Some(';')));
}
#[test]
fn lexer_raw_param_digit() {
let mut lexer = Lexer::from_memory("$12", Source::Unknown);
lexer.peek_char().now_or_never().unwrap().unwrap();
lexer.consume_char();
let result = lexer.raw_param(0).now_or_never().unwrap().unwrap().unwrap();
assert_matches!(result, TextUnit::RawParam { param, location } => {
assert_eq!(param, Param::from(1));
assert_eq!(*location.code.value.borrow(), "$12");
assert_eq!(location.code.start_line_number.get(), 1);
assert_eq!(*location.code.source, Source::Unknown);
assert_eq!(location.range, 0..2);
});
assert_eq!(lexer.peek_char().now_or_never().unwrap(), Ok(Some('2')));
}
#[test]
fn lexer_raw_param_posix_name() {
let mut lexer = Lexer::from_memory("$az_AZ_019<", Source::Unknown);
lexer.peek_char().now_or_never().unwrap().unwrap();
lexer.consume_char();
let result = lexer.raw_param(0).now_or_never().unwrap().unwrap().unwrap();
assert_matches!(result, TextUnit::RawParam { param, location } => {
assert_eq!(param, Param::variable("az_AZ_019"));
assert_eq!(*location.code.value.borrow(), "$az_AZ_019<");
assert_eq!(location.code.start_line_number.get(), 1);
assert_eq!(*location.code.source, Source::Unknown);
assert_eq!(location.range, 0..10);
});
assert_eq!(lexer.peek_char().now_or_never().unwrap(), Ok(Some('<')));
}
#[test]
fn lexer_raw_param_posix_name_line_continuations() {
let mut lexer = Lexer::from_memory("$a\\\n\\\nb\\\n\\\nc\\\n>", Source::Unknown);
lexer.peek_char().now_or_never().unwrap().unwrap();
lexer.consume_char();
let result = lexer.raw_param(0).now_or_never().unwrap().unwrap().unwrap();
assert_matches!(result, TextUnit::RawParam { param, location } => {
assert_eq!(param, Param::variable("abc"));
assert_eq!(*location.code.value.borrow(), "$a\\\n\\\nb\\\n\\\nc\\\n>");
assert_eq!(location.code.start_line_number.get(), 1);
assert_eq!(*location.code.source, Source::Unknown);
assert_eq!(location.range, 0..14);
});
assert_eq!(lexer.peek_char().now_or_never().unwrap(), Ok(Some('>')));
}
#[test]
fn lexer_raw_param_not_parameter() {
let mut lexer = Lexer::from_memory("$;", Source::Unknown);
lexer.peek_char().now_or_never().unwrap().unwrap();
lexer.consume_char();
assert_eq!(lexer.raw_param(0).now_or_never().unwrap(), Ok(None));
assert_eq!(lexer.peek_char().now_or_never().unwrap(), Ok(Some(';')));
}
}