use super::annotated::{Annotated, Trailed};
use super::items::Items;
use super::token::{Leaf, Token};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StringPart {
TextPart(Box<str>),
Interpolation(Box<Trailed<Expression>>),
}
pub type Path = Annotated<Vec<StringPart>>;
pub type NixString = Annotated<Vec<Vec<StringPart>>>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SimpleSelector {
ID(Leaf),
Interpol(Annotated<StringPart>),
String(NixString),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Selector {
pub dot: Option<Leaf>,
pub selector: SimpleSelector,
}
impl Selector {
pub const fn is_simple(&self) -> bool {
matches!(self.selector, SimpleSelector::ID(_))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Binder {
Inherit {
kw: Leaf,
from: Option<Term>,
attrs: Vec<SimpleSelector>,
semi: Leaf,
},
Assignment {
path: Vec<Selector>,
eq: Leaf,
value: Expression,
semi: Leaf,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SetDefault {
pub or_kw: Leaf,
pub value: Box<Term>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Term {
Token(Leaf),
SimpleString(NixString),
IndentedString(NixString),
Path(Path),
List {
open: Leaf,
items: Items<Self>,
close: Leaf,
},
Set {
rec: Option<Leaf>,
open: Leaf,
items: Items<Binder>,
close: Leaf,
},
Selection {
base: Box<Self>,
selectors: Vec<Selector>,
default: Option<SetDefault>,
},
Parenthesized {
open: Leaf,
expr: Box<Expression>,
close: Leaf,
},
}
impl Term {
pub fn is_simple(&self) -> bool {
match self {
Self::SimpleString(s) | Self::IndentedString(s) => !s.has_trivia(),
Self::Path(p) => !p.has_trivia(),
Self::Token(leaf)
if !leaf.has_trivia()
&& matches!(
leaf.value,
Token::Identifier(_)
| Token::Integer(_)
| Token::Float(_)
| Token::EnvPath(_)
) =>
{
true
}
Self::Selection {
base,
selectors,
default,
} => base.is_simple() && selectors.iter().all(Selector::is_simple) && default.is_none(),
Self::Parenthesized { open, expr, close } => {
!open.has_trivia() && !close.has_trivia() && expr.is_simple()
}
_ => false,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParamDefault {
pub question: Leaf,
pub value: Expression,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[allow(clippy::large_enum_variant)]
pub enum ParamAttr {
Attr {
name: Leaf,
default: Option<ParamDefault>,
comma: Option<Leaf>,
},
Ellipsis(Leaf),
}
impl ParamAttr {
pub const fn has_no_default(&self) -> bool {
matches!(self, Self::Attr { default, .. } if default.is_none())
}
pub const fn is_ellipsis(&self) -> bool {
matches!(self, Self::Ellipsis(_))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Parameter {
Id(Leaf),
Set {
open: Leaf,
attrs: Vec<ParamAttr>,
close: Leaf,
},
Context {
lhs: Box<Self>,
at: Leaf,
rhs: Box<Self>,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Expression {
Term(Term),
With {
kw_with: Leaf,
scope: Box<Self>,
semi: Leaf,
body: Box<Self>,
},
Let {
kw_let: Leaf,
bindings: Items<Binder>,
kw_in: Leaf,
body: Box<Self>,
},
Assert {
kw_assert: Leaf,
cond: Box<Self>,
semi: Leaf,
body: Box<Self>,
},
If {
kw_if: Leaf,
cond: Box<Self>,
kw_then: Leaf,
then_branch: Box<Self>,
kw_else: Leaf,
else_branch: Box<Self>,
},
Lambda {
param: Parameter,
colon: Leaf,
body: Box<Self>,
},
Apply {
func: Box<Self>,
arg: Box<Self>,
},
Operation {
lhs: Box<Self>,
op: Leaf,
rhs: Box<Self>,
},
HasAttr {
lhs: Box<Self>,
question: Leaf,
path: Vec<Selector>,
},
Negation {
minus: Leaf,
expr: Box<Self>,
},
Not {
bang: Leaf,
expr: Box<Self>,
},
}
impl Expression {
pub fn is_simple(&self) -> bool {
match self {
Self::Term(term) => term.is_simple(),
Self::Apply { func: f, arg: a } => Self::app_is_simple(f, a),
_ => false,
}
}
pub fn app_is_simple(f: &Self, a: &Self) -> bool {
if let Self::Apply { func: f2, .. } = f
&& matches!(**f2, Self::Apply { .. })
{
return false;
}
f.is_simple() && a.is_simple()
}
}
pub type File = Trailed<Expression>;
first_token_impl! { Term;
Self::Token(l) => leaf l,
Self::SimpleString(s) | Self::IndentedString(s) => leaf s,
Self::Path(p) => leaf p,
Self::List { open, .. }
| Self::Parenthesized { open, .. }
| Self::Set { rec: None, open, .. } => leaf open,
Self::Set { rec: Some(rec), .. } => leaf rec,
Self::Selection { base, .. } => recurse base,
}
first_token_impl! { Parameter;
Self::Id(n) => leaf n,
Self::Set { open, .. } => leaf open,
Self::Context { lhs, .. } => recurse lhs,
}
first_token_impl! { Expression;
Self::Term(t) => recurse t,
Self::With { kw_with: kw, .. }
| Self::Let { kw_let: kw, .. }
| Self::Assert { kw_assert: kw, .. }
| Self::If { kw_if: kw, .. }
| Self::Negation { minus: kw, .. }
| Self::Not { bang: kw, .. } => leaf kw,
Self::Lambda { param, .. } => recurse param,
Self::Apply { func: g, .. }
| Self::Operation { lhs: g, .. }
| Self::HasAttr { lhs: g, .. } => recurse g,
}