pub type TokenText = compact_str::CompactString;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Span {
pub start: u32, pub end: u32, pub start_line: u32, pub end_line: u32, }
impl Span {
#[allow(clippy::cast_possible_truncation)] pub const fn new(start: usize, end: usize) -> Self {
Self {
start: start as u32,
end: end as u32,
start_line: 1,
end_line: 1,
}
}
#[allow(clippy::cast_possible_truncation)]
pub const fn with_lines(start: usize, end: usize, start_line: usize, end_line: usize) -> Self {
Self {
start: start as u32,
end: end as u32,
start_line: start_line as u32,
end_line: end_line as u32,
}
}
#[allow(clippy::cast_possible_truncation)]
pub const fn point(offset: usize) -> Self {
Self {
start: offset as u32,
end: offset as u32,
start_line: 1,
end_line: 1,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Trivium {
EmptyLine(),
LineComment(String),
BlockComment(bool, Vec<String>),
LanguageAnnotation(String),
}
#[derive(Debug, Clone, Default)]
#[allow(clippy::box_collection)] pub struct Trivia(Option<Box<Vec<Trivium>>>);
impl Trivia {
#[inline]
pub const fn new() -> Self {
Self(None)
}
pub fn one(t: Trivium) -> Self {
Self(Some(Box::new(vec![t])))
}
#[inline]
fn vec_mut(&mut self) -> &mut Vec<Trivium> {
self.0.get_or_insert_with(|| Box::new(Vec::new()))
}
#[inline]
pub fn push(&mut self, t: Trivium) {
self.vec_mut().push(t);
}
pub fn insert(&mut self, idx: usize, t: Trivium) {
self.vec_mut().insert(idx, t);
}
pub fn extend<I: IntoIterator<Item = Trivium>>(&mut self, iter: I) {
let mut iter = iter.into_iter();
if let Some(first) = iter.next() {
let v = self.vec_mut();
v.push(first);
v.extend(iter);
}
}
#[inline]
pub fn clear(&mut self) {
self.0 = None;
}
}
impl PartialEq for Trivia {
fn eq(&self, other: &Self) -> bool {
self[..] == other[..]
}
}
impl Eq for Trivia {}
impl std::ops::Deref for Trivia {
type Target = [Trivium];
#[inline]
fn deref(&self) -> &Self::Target {
match &self.0 {
Some(v) => v,
None => &[],
}
}
}
impl From<Vec<Trivium>> for Trivia {
fn from(value: Vec<Trivium>) -> Self {
if value.is_empty() {
Self(None)
} else {
Self(Some(Box::new(value)))
}
}
}
impl From<Trivia> for Vec<Trivium> {
fn from(val: Trivia) -> Self {
val.0.map(|b| *b).unwrap_or_default()
}
}
impl IntoIterator for Trivia {
type Item = Trivium;
type IntoIter = std::vec::IntoIter<Trivium>;
fn into_iter(self) -> Self::IntoIter {
Vec::from(self).into_iter()
}
}
impl<'a> IntoIterator for &'a Trivia {
type Item = &'a Trivium;
type IntoIter = std::slice::Iter<'a, Trivium>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TrailingComment(pub Box<str>);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Ann<T> {
pub pre_trivia: Trivia,
pub span: Span,
pub value: T,
pub trail_comment: Option<TrailingComment>,
}
impl<T: Clone> Ann<T> {
pub fn without_trail(&self) -> Self {
Self {
trail_comment: None,
..self.clone()
}
}
pub fn without_pre(&self) -> Self {
Self {
pre_trivia: Trivia::new(),
..self.clone()
}
}
}
pub struct AnnSlot<'a> {
pub pre_trivia: &'a Trivia,
pub trail_comment: &'a Option<TrailingComment>,
}
pub struct AnnSlotMut<'a> {
pub pre_trivia: &'a mut Trivia,
pub trail_comment: &'a mut Option<TrailingComment>,
}
impl<'a, T> From<&'a Ann<T>> for AnnSlot<'a> {
fn from(a: &'a Ann<T>) -> Self {
AnnSlot {
pre_trivia: &a.pre_trivia,
trail_comment: &a.trail_comment,
}
}
}
impl<'a, T> From<&'a mut Ann<T>> for AnnSlotMut<'a> {
fn from(a: &'a mut Ann<T>) -> Self {
AnnSlotMut {
pre_trivia: &mut a.pre_trivia,
trail_comment: &mut a.trail_comment,
}
}
}
pub trait FirstToken {
fn first_token(&self) -> AnnSlot<'_>;
fn first_token_mut(&mut self) -> AnnSlotMut<'_>;
}
impl FirstToken for Term {
fn first_token(&self) -> AnnSlot<'_> {
match self {
Self::Token(l) => l.into(),
Self::SimpleString(s) | Self::IndentedString(s) => s.into(),
Self::Path(p) => p.into(),
Self::List(open, _, _)
| Self::Set(None, open, _, _)
| Self::Parenthesized(open, _, _) => open.into(),
Self::Set(Some(rec), _, _, _) => rec.into(),
Self::Selection(inner, _, _) => inner.first_token(),
}
}
fn first_token_mut(&mut self) -> AnnSlotMut<'_> {
match self {
Self::Token(l) => l.into(),
Self::SimpleString(s) | Self::IndentedString(s) => s.into(),
Self::Path(p) => p.into(),
Self::List(open, _, _)
| Self::Set(None, open, _, _)
| Self::Parenthesized(open, _, _) => open.into(),
Self::Set(Some(rec), _, _, _) => rec.into(),
Self::Selection(inner, _, _) => inner.first_token_mut(),
}
}
}
impl FirstToken for Parameter {
fn first_token(&self) -> AnnSlot<'_> {
match self {
Self::ID(n) => n.into(),
Self::Set(open, _, _) => open.into(),
Self::Context(first, _, _) => first.first_token(),
}
}
fn first_token_mut(&mut self) -> AnnSlotMut<'_> {
match self {
Self::ID(n) => n.into(),
Self::Set(open, _, _) => open.into(),
Self::Context(first, _, _) => first.first_token_mut(),
}
}
}
impl FirstToken for Expression {
fn first_token(&self) -> AnnSlot<'_> {
match self {
Self::Term(t) => t.first_token(),
Self::With(kw, ..)
| Self::Let(kw, ..)
| Self::Assert(kw, ..)
| Self::If(kw, ..)
| Self::Negation(kw, _)
| Self::Inversion(kw, _) => kw.into(),
Self::Abstraction(p, _, _) => p.first_token(),
Self::Application(g, _) | Self::Operation(g, _, _) | Self::MemberCheck(g, _, _) => {
g.first_token()
}
}
}
fn first_token_mut(&mut self) -> AnnSlotMut<'_> {
match self {
Self::Term(t) => t.first_token_mut(),
Self::With(kw, ..)
| Self::Let(kw, ..)
| Self::Assert(kw, ..)
| Self::If(kw, ..)
| Self::Negation(kw, _)
| Self::Inversion(kw, _) => kw.into(),
Self::Abstraction(p, _, _) => p.first_token_mut(),
Self::Application(g, _) | Self::Operation(g, _, _) | Self::MemberCheck(g, _, _) => {
g.first_token_mut()
}
}
}
}
impl From<&TrailingComment> for Trivium {
fn from(tc: &TrailingComment) -> Self {
Self::LineComment(format!(" {}", tc.0))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Item<T> {
Item(T),
Comments(Trivia),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Items<T>(pub Vec<Item<T>>);
pub type Leaf = Ann<Token>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StringPart {
TextPart(String),
Interpolation(Box<Whole<Expression>>),
}
pub type Path = Ann<Vec<StringPart>>;
pub type NixString = Ann<Vec<Vec<StringPart>>>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SimpleSelector {
ID(Leaf),
Interpol(Ann<StringPart>),
String(NixString),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Selector {
pub dot: Option<Leaf>,
pub selector: SimpleSelector,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Binder {
Inherit(Leaf, Option<Term>, Vec<SimpleSelector>, Leaf),
Assignment(Vec<Selector>, Leaf, Expression, Leaf),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Term {
Token(Leaf),
SimpleString(NixString),
IndentedString(NixString),
Path(Path),
List(Leaf, Items<Self>, Leaf),
Set(Option<Leaf>, Leaf, Items<Binder>, Leaf),
Selection(Box<Self>, Vec<Selector>, Option<(Leaf, Box<Self>)>),
Parenthesized(Leaf, Box<Expression>, Leaf),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParamAttr {
ParamAttr(Leaf, Box<Option<(Leaf, Expression)>>, Option<Leaf>),
ParamEllipsis(Leaf),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Parameter {
ID(Leaf),
Set(Leaf, Vec<ParamAttr>, Leaf),
Context(Box<Self>, Leaf, Box<Self>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Expression {
Term(Term),
With(Leaf, Box<Self>, Leaf, Box<Self>),
Let(Leaf, Items<Binder>, Leaf, Box<Self>),
Assert(Leaf, Box<Self>, Leaf, Box<Self>),
If(Leaf, Box<Self>, Leaf, Box<Self>, Leaf, Box<Self>),
Abstraction(Parameter, Leaf, Box<Self>),
Application(Box<Self>, Box<Self>),
Operation(Box<Self>, Leaf, Box<Self>),
MemberCheck(Box<Self>, Leaf, Vec<Selector>),
Negation(Leaf, Box<Self>),
Inversion(Leaf, Box<Self>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Whole<T> {
pub value: T,
pub trailing_trivia: Trivia,
}
pub type File = Whole<Expression>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Token {
Integer(TokenText),
Float(TokenText),
Identifier(TokenText),
EnvPath(TokenText),
KAssert,
KElse,
KIf,
KIn,
KInherit,
KLet,
KOr,
KRec,
KThen,
KWith,
TBraceOpen,
TBraceClose,
TBrackOpen,
TBrackClose,
TInterOpen, TInterClose, TParenOpen,
TParenClose,
TAssign, TAt, TColon, TComma, TDot, TDoubleQuote, TDoubleSingleQuote, TEllipsis, TQuestion, TSemicolon, TConcat, TNegate, TUpdate, TPlus, TMinus, TMul, TDiv, TAnd, TOr, TEqual, TGreater, TGreaterEqual, TImplies, TLess, TLessEqual, TNot, TUnequal, TPipeForward, TPipeBackward,
Sof, TTilde, }
impl Token {
pub fn text(&self) -> &str {
match self {
Self::Identifier(s) | Self::Integer(s) | Self::Float(s) | Self::EnvPath(s) => {
s.as_str()
}
Self::KAssert => "assert",
Self::KElse => "else",
Self::KIf => "if",
Self::KIn => "in",
Self::KInherit => "inherit",
Self::KLet => "let",
Self::KOr => "or",
Self::KRec => "rec",
Self::KThen => "then",
Self::KWith => "with",
Self::TBraceOpen => "{",
Self::TBraceClose | Self::TInterClose => "}",
Self::TBrackOpen => "[",
Self::TBrackClose => "]",
Self::TInterOpen => "${",
Self::TParenOpen => "(",
Self::TParenClose => ")",
Self::TAssign => "=",
Self::TAt => "@",
Self::TColon => ":",
Self::TComma => ",",
Self::TDot => ".",
Self::TDoubleQuote => "\"",
Self::TDoubleSingleQuote => "''",
Self::TEllipsis => "...",
Self::TQuestion => "?",
Self::TSemicolon => ";",
Self::TPlus => "+",
Self::TMinus | Self::TNegate => "-",
Self::TMul => "*",
Self::TDiv => "/",
Self::TConcat => "++",
Self::TUpdate => "//",
Self::TAnd => "&&",
Self::TOr => "||",
Self::TEqual => "==",
Self::TGreater => ">",
Self::TGreaterEqual => ">=",
Self::TImplies => "->",
Self::TLess => "<",
Self::TLessEqual => "<=",
Self::TNot => "!",
Self::TUnequal => "!=",
Self::TPipeForward => "|>",
Self::TPipeBackward => "<|",
Self::Sof => "end of file",
Self::TTilde => "~",
}
}
}
impl Token {
pub const fn is_update_concat_plus(&self) -> bool {
matches!(self, Self::TUpdate | Self::TConcat | Self::TPlus)
}
}