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) }