use rnix::ast;
use super::*;
pub fn downgrade_param(param: ast::Param, ctx: &mut DowngradeContext) -> Result {
match param {
ast::Param::IdentParam(ident) => Ok(Param::Ident(ident.to_string().into())),
ast::Param::Pattern(pattern) => downgrade_pattern(pattern, ctx),
}
}
pub fn downgrade_pattern(pattern: ast::Pattern, ctx: &mut DowngradeContext) -> Result {
let formals = pattern
.pat_entries()
.map(|entry| {
let ident = entry.ident().unwrap().to_string().into();
if entry.default().is_none() {
Ok((ident, None))
} else {
entry
.default()
.unwrap()
.downgrade(ctx)
.map(|ok| (ident, Some(ctx.new_thunk(ok))))
}
})
.collect::>>()?;
let ellipsis = pattern.ellipsis_token().is_some();
let alias = pattern
.pat_bind()
.map(|alias| alias.ident().unwrap().to_string().into());
Ok(Param::Formals {
formals,
ellipsis,
alias,
})
}
pub fn downgrade_attrs(has_entry: impl ast::HasEntry, ctx: &mut DowngradeContext) -> Result {
let entires = has_entry.entries();
let mut attrs = Attrs {
stcs: HashMap::new(),
dyns: Vec::new(),
};
for entry in entires {
match entry {
ast::Entry::Inherit(inherit) => downgrade_inherit(inherit, &mut attrs.stcs, ctx)?,
ast::Entry::AttrpathValue(value) => downgrade_attrpathvalue(value, &mut attrs, ctx)?,
}
}
Ok(attrs)
}
pub fn downgrade_inherit(
inherit: ast::Inherit,
stcs: &mut HashMap,
ctx: &mut DowngradeContext,
) -> Result<()> {
let from = if let Some(from) = inherit.from() {
let from = from.expr().unwrap().downgrade(ctx)?;
Some(ctx.new_thunk(from))
} else {
None
};
for attr in inherit.attrs() {
let ident = match downgrade_attr(attr, ctx)? {
Attr::Str(ident) => ident,
_ => {
return Err(Error::DowngradeError(
"dynamic attributes not allowed in inherit".to_string(),
));
}
};
let expr = from.map_or_else(
|| Var { sym: ident.clone() }.ir().ok(),
|from| {
Ok(Select {
expr: from.ir().boxed(),
attrpath: vec![Attr::Str(ident.clone())],
default: None,
}
.ir())
},
)?;
// TODO: Error Handling
assert!(stcs.insert(ident, expr).is_none());
}
Ok(())
}
pub fn downgrade_attr(attr: ast::Attr, ctx: &mut DowngradeContext) -> Result {
use ast::Attr::*;
use ast::InterpolPart::*;
match attr {
Ident(ident) => Ok(Attr::Str(ident.to_string().into())),
Str(string) => {
let parts = string.normalized_parts();
if parts.is_empty() {
Ok(Attr::Str("".into()))
} else if parts.len() == 1 {
match parts.into_iter().next().unwrap() {
Literal(ident) => Ok(Attr::Str(ident.into())),
Interpolation(interpol) => {
Ok(Attr::Dynamic(interpol.expr().unwrap().downgrade(ctx)?))
}
}
} else {
let parts = parts
.into_iter()
.map(|part| match part {
Literal(lit) => self::Str { val: lit.into() }.ir().ok(),
Interpolation(interpol) => interpol.expr().unwrap().downgrade(ctx),
})
.collect::>>()?;
Ok(Attr::Strs(ConcatStrings { parts }))
}
}
Dynamic(dynamic) => Ok(Attr::Dynamic(dynamic.expr().unwrap().downgrade(ctx)?)),
}
}
pub fn downgrade_attrpath(
attrpath: ast::Attrpath,
ctx: &mut DowngradeContext,
) -> Result> {
attrpath
.attrs()
.map(|attr| downgrade_attr(attr, ctx))
.collect::>>()
}
pub fn downgrade_attrpathvalue(
value: ast::AttrpathValue,
attrs: &mut Attrs,
ctx: &mut DowngradeContext,
) -> Result<()> {
let path = downgrade_attrpath(value.attrpath().unwrap(), ctx)?;
let value = value.value().unwrap().downgrade(ctx)?;
let value = match value {
x @ Ir::Const(_) => x,
x => ctx.new_thunk(x).ir(),
};
attrs.insert(path, value, ctx)
}