rust-nix/src/parser/token/op_kw_ident.rs

165 lines
3.7 KiB
Rust

use nom::Parser;
use super::{
SpanRef,
PResult,
SpannedData,
Token,
SpanExt,
Identifier,
};
#[derive(Clone, Copy, Debug)]
/// Keywords / operators we tokenize as "standalone"
pub enum SimpleToken {
/// `=`
Assign,
/// `:`
Colon,
/// `;`
SemiColon,
/// `@` - lambda parameter alias
At,
/// `...` - accept unknown named parameters
Ellipsis,
/// `.` - attribute selection
Dot,
/// `?` - has attribute
QuestionMark,
/// `//` - attribute set update
DoubleSlash,
/// `++` - list concatenation
DoublePlus,
/// `*`
Multiplication,
/// `/`
Division,
/// `+`
Plus,
/// `-`
Minus,
/// `<`
LessThan,
/// `<=`
LessThanOrEqual,
/// `>`
GreaterThan,
/// `>=`
GreaterThanOrEqual,
/// `==`
Equal,
/// `!=`
NotEqual,
/// `!`
LogicNot,
/// `&&`
LogicAnd,
/// `||`
LogicOr,
/// `->` (`a -> b` == `!a || b`)
LogicImplication,
/// `or` - attribute selection fallback
KwOr,
/// `let`
KwLet,
/// `with`
KwWith,
/// `rec`
KwRec,
/// `inherit`
KwInherit,
/// `if`
KwIf,
/// `then`
KwThen,
/// `else`
KwElse,
/// `assert`
KwAssert,
}
// this also finds (some) path prefixes - path alternative should come before
fn ident_or_keyword(span: SpanRef) -> PResult<SpannedData<Token>> {
let (rem_span, ident_span) = nom::combinator::recognize(
nom::sequence::pair(
nom::branch::alt((
nom::character::complete::alpha1.map(|_| ()),
nom::bytes::complete::tag("_").map(|_| ()),
)),
nom::multi::many0_count(nom::branch::alt((
nom::character::complete::alphanumeric1.map(|_| ()),
nom::bytes::complete::tag("_").map(|_| ()),
nom::bytes::complete::tag("-").map(|_| ()),
)))
)
)(span)?;
let t = match ident_span.as_str() {
"or" => SimpleToken::KwOr,
"let" => SimpleToken::KwLet,
"with" => SimpleToken::KwWith,
"rec" => SimpleToken::KwRec,
"inherit" => SimpleToken::KwInherit,
"if" => SimpleToken::KwIf,
"then" => SimpleToken::KwThen,
"else" => SimpleToken::KwElse,
"assert" => SimpleToken::KwAssert,
ident => return Ok((
rem_span,
ident_span.data(Token::Identifier(Identifier::from_ref(ident))),
)),
};
Ok((rem_span, ident_span.data(Token::SimpleToken(t))))
}
fn simple_tagged(tag: &'static str, t: SimpleToken) -> impl Fn(SpanRef) -> PResult<SpannedData<Token>> {
move |span| {
let (rem_span, token_span) = nom::bytes::complete::tag(tag)(span)?;
Ok((rem_span, token_span.data(Token::SimpleToken(t))))
}
}
fn simple_op(span: SpanRef) -> PResult<SpannedData<Token>> {
nom::branch::alt((
nom::branch::alt((
simple_tagged(":", SimpleToken::Colon),
simple_tagged(";", SimpleToken::SemiColon),
simple_tagged("@", SimpleToken::At),
simple_tagged("...", SimpleToken::Ellipsis),
simple_tagged(".", SimpleToken::Dot),
simple_tagged("?", SimpleToken::QuestionMark),
simple_tagged("//", SimpleToken::DoubleSlash),
simple_tagged("++", SimpleToken::DoublePlus),
simple_tagged("*", SimpleToken::Multiplication),
simple_tagged("/", SimpleToken::Division),
simple_tagged("+", SimpleToken::Plus),
simple_tagged("-", SimpleToken::Minus),
)),
nom::branch::alt((
simple_tagged("<=", SimpleToken::LessThanOrEqual),
simple_tagged("<", SimpleToken::LessThan),
simple_tagged(">=", SimpleToken::GreaterThanOrEqual),
simple_tagged(">", SimpleToken::GreaterThan),
simple_tagged("==", SimpleToken::Equal),
simple_tagged("!=", SimpleToken::NotEqual),
simple_tagged("=", SimpleToken::Assign),
simple_tagged("!", SimpleToken::LogicNot),
simple_tagged("&&", SimpleToken::LogicAnd),
simple_tagged("||", SimpleToken::LogicOr),
simple_tagged("->", SimpleToken::LogicImplication),
)),
))(span)
}
pub(super) fn op_ident_or_keyword(span: SpanRef) -> PResult<SpannedData<Token>> {
nom::branch::alt((
simple_op,
ident_or_keyword,
))(span)
}