use crate::ast::{
Annotated, Binder, Expression, File, Item, Items, Leaf, NixString, ParamAttr, Parameter,
Selector, SimpleSelector, Span, StringPart, Term, Trailed, Trivia,
};
const ZERO_SPAN: Span = Span::with_lines(0, 0, 1, 1);
pub fn normalize_file(file: &mut File) {
normalize_whole_expr(file);
}
fn normalize_whole_expr(w: &mut Trailed<Expression>) {
w.trailing_trivia = Trivia::new();
normalize_expr(&mut w.value);
}
fn normalize_ann<T>(a: &mut Annotated<T>, f: impl FnOnce(&mut T)) {
a.pre_trivia = Trivia::new();
a.span = ZERO_SPAN;
a.trail_comment = None;
f(&mut a.value);
}
fn normalize_leaf(l: &mut Leaf) {
normalize_ann(l, |_| {});
}
fn normalize_items<T>(items: &mut Items<T>, mut f: impl FnMut(&mut T)) {
items.0.retain_mut(|it| match it {
Item::Item(v) => {
f(v);
true
}
Item::Comments(_) => false,
});
}
fn normalize_string_parts(parts: &mut [StringPart]) {
for p in parts {
if let StringPart::Interpolation(w) = p {
normalize_whole_expr(w);
}
}
}
fn normalize_nix_string(s: &mut NixString) {
normalize_ann(s, |lines| {
for line in lines {
normalize_string_parts(line);
}
});
}
fn normalize_simple_selector(s: &mut SimpleSelector) {
match s {
SimpleSelector::ID(l) => normalize_leaf(l),
SimpleSelector::Interpol(a) => normalize_ann(a, |sp| {
if let StringPart::Interpolation(w) = sp {
normalize_whole_expr(w);
}
}),
SimpleSelector::String(s) => normalize_nix_string(s),
}
}
fn normalize_selector(s: &mut Selector) {
if let Some(dot) = &mut s.dot {
normalize_leaf(dot);
}
normalize_simple_selector(&mut s.selector);
}
fn normalize_binder(b: &mut Binder) {
match b {
Binder::Inherit {
kw,
from,
attrs,
semi,
} => {
normalize_leaf(kw);
if let Some(t) = from {
normalize_term(t);
}
for s in attrs {
normalize_simple_selector(s);
}
normalize_leaf(semi);
}
Binder::Assignment {
path,
eq,
value,
semi,
} => {
for s in path {
normalize_selector(s);
}
normalize_leaf(eq);
normalize_expr(value);
normalize_leaf(semi);
}
}
}
fn normalize_term(t: &mut Term) {
match t {
Term::Token(l) => normalize_leaf(l),
Term::SimpleString(s) | Term::IndentedString(s) => normalize_nix_string(s),
Term::Path(p) => normalize_ann(p, |parts| normalize_string_parts(parts)),
Term::List { open, items, close } => {
normalize_leaf(open);
normalize_items(items, normalize_term);
normalize_leaf(close);
}
Term::Set {
rec,
open,
items,
close,
} => {
if let Some(r) = rec {
normalize_leaf(r);
}
normalize_leaf(open);
normalize_items(items, normalize_binder);
normalize_leaf(close);
}
Term::Selection {
base,
selectors,
default,
} => {
normalize_term(base);
for s in selectors {
normalize_selector(s);
}
if let Some(d) = default {
normalize_leaf(&mut d.or_kw);
normalize_term(&mut d.value);
}
}
Term::Parenthesized { open, expr, close } => {
normalize_leaf(open);
normalize_expr(expr);
normalize_leaf(close);
}
}
}
fn normalize_param_attr(p: &mut ParamAttr) {
match p {
ParamAttr::Attr {
name,
default,
comma,
} => {
normalize_leaf(name);
if let Some(d) = default.as_mut() {
normalize_leaf(&mut d.question);
normalize_expr(&mut d.value);
}
*comma = None;
}
ParamAttr::Ellipsis(l) => normalize_leaf(l),
}
}
fn normalize_parameter(p: &mut Parameter) {
match p {
Parameter::Id(l) => normalize_leaf(l),
Parameter::Set { open, attrs, close } => {
normalize_leaf(open);
for a in attrs {
normalize_param_attr(a);
}
normalize_leaf(close);
}
Parameter::Context { lhs, at, rhs } => {
normalize_parameter(lhs);
normalize_leaf(at);
normalize_parameter(rhs);
}
}
}
#[allow(clippy::many_single_char_names)] fn normalize_expr(e: &mut Expression) {
match e {
Expression::Term(t) => normalize_term(t),
Expression::With {
kw_with: kw,
scope: a,
semi,
body: b,
}
| Expression::Assert {
kw_assert: kw,
cond: a,
semi,
body: b,
} => {
normalize_leaf(kw);
normalize_expr(a);
normalize_leaf(semi);
normalize_expr(b);
}
Expression::Let {
kw_let,
bindings,
kw_in,
body,
} => {
normalize_leaf(kw_let);
normalize_items(bindings, normalize_binder);
normalize_leaf(kw_in);
normalize_expr(body);
}
Expression::If {
kw_if,
cond,
kw_then,
then_branch,
kw_else,
else_branch,
} => {
normalize_leaf(kw_if);
normalize_expr(cond);
normalize_leaf(kw_then);
normalize_expr(then_branch);
normalize_leaf(kw_else);
normalize_expr(else_branch);
}
Expression::Lambda { param, colon, body } => {
normalize_parameter(param);
normalize_leaf(colon);
normalize_expr(body);
}
Expression::Apply { func, arg } => {
normalize_expr(func);
normalize_expr(arg);
}
Expression::Operation { lhs, op, rhs } => {
normalize_expr(lhs);
normalize_leaf(op);
normalize_expr(rhs);
}
Expression::HasAttr {
lhs,
question,
path,
} => {
normalize_expr(lhs);
normalize_leaf(question);
for s in path {
normalize_selector(s);
}
}
Expression::Negation { minus: op, expr: a } | Expression::Not { bang: op, expr: a } => {
normalize_leaf(op);
normalize_expr(a);
}
}
}