/// Unpack the units of a physical type declaration.
Unpack the units of a physical type declaration.
Unpack the units of a physical type declaration .
fn unpack_units<'t>(
    units: &[(ast::Ident, Option<Box<ast::Expr>>)],
    type_name: Spanned<Name>,
    ctx: AllocContext<'t>,
) -> Result<(Vec<PhysicalUnit>, usize)> {
    // Determine the primary unit.
    let mut prim_iter = units
        .iter()
        .enumerate()
        .filter(|&(_, &(_, ref expr))| expr.is_none())
        .map(|(index, &(name, _))| (index, name));
    let primary = match prim_iter.next() {
        Some(u) => u,
        None => {
            ctx.emit(
                DiagBuilder2::error(format!(
                    "physical type `{}` has no primary unit",
                    type_name.value
                ))
                .span(type_name.span)
                .add_note(
                    "A physical type must have a primary unit of the form `<name>;`. See IEEE \
                     1076-2008 section 5.2.4.",
                ),
            );
            return Err(());
        }
    };
    let mut had_fails = false;
    for (_, n) in prim_iter {
        ctx.emit(
            DiagBuilder2::error(format!(
                "physical type `{}` has multiple primary units",
                type_name.value
            ))
            .span(n.span)
            .add_note(
                "A physical type cannot have multiple primary units. See IEEE 1076-2008 section \
                 5.2.4.",
            ),
        );
        had_fails = true;
    }
    if had_fails {
        return Err(());
    }
    // Determine the units and how they are defined with respect
    // to each other.
    let term_ctx = TermContext::new2(ctx);
    let table = units
        .iter()
        .map(|&(unit_name, ref expr)| {
            let rel = if let Some(ref expr) = *expr {
                let term = term_ctx.termify_expr(expr)?;
                let (value, unit) = match term.value {
                    Term::PhysLit(value, unit) => (value, unit),
                    _ => {
                        ctx.emit(
                            DiagBuilder2::error(format!(
                                "`{}` is not a valid secondary unit",
                                term.span.extract()
                            ))
                            .span(term.span),
                        );
                        debugln!("It is a {:#?}", term.value);
                        return Err(());
                    }
                };
                // TODO: Find a way to enable this again!
                // if unit.value.0 != id {
                //     ctx.emit(
                //         DiagBuilder2::error(format!(
                //             "`{}` is not a unit in the physical type `{}`",
                //             term.span.extract(),
                //             type_name.value
                //         )).span(term.span)
                //             .add_note(format!("`{}` has been declared here:", term.span.extract()
                // ))
                //             .span(unit.span),
                //     );
                // }
                Some((value, unit.value.unwrap_new().1))
            } else {
                None
            };
            Ok((Spanned::new(unit_name.name, unit_name.span), rel))
        })
        .collect::<Vec<Result<_>>>()
        .into_iter()
        .collect::<Result<Vec<_>>>()?;
    // Determine the scale of each unit with respect to the primary unit.
    Ok((
        table
            .iter()
            .map(|&(name, ref rel)| {
                let mut abs = BigInt::from(1);
                let mut rel_to = rel.as_ref();
                while let Some(&(ref scale, index)) = rel_to {
                    abs = abs * scale;
                    rel_to = table[index].1.as_ref();
                }
                PhysicalUnit::new(name.value, abs, rel.clone())
            })
            .collect::<Vec<_>>(),
        primary.0,
    ))
}
fn unpack_units < ' t > ( units : & [ ( ast :: Ident , Option < Box < ast :: Expr > > ) ] , type_name : Spanned < Name > , ctx : AllocContext < ' t > , ) -> Result < ( Vec < PhysicalUnit > , usize ) > { // Determine the primary unit. let mut prim_iter = units . iter ( ) . enumerate ( ) . filter ( | & ( _ , & ( _ , ref expr ) ) | expr . is_none ( ) ) . map ( | ( index , & ( name , _ ) ) | ( index , name ) ) ; let primary = match prim_iter . next ( ) { Some ( u ) => u , None => { ctx . emit ( DiagBuilder2 :: error ( format ! ( " " type_name value ) ) . span ( type_name . span ) . add_note ( " \
 " , ) , ) ; return Err ( ( ) ) ; } } ; let mut had_fails = false ; for ( _ , n ) in prim_iter { ctx . emit ( DiagBuilder2 :: error ( format ! ( " " type_name value ) ) . span ( n . span ) . add_note ( " \
 " , ) , ) ; had_fails = true ; } if had_fails { return Err ( ( ) ) ; } // Determine the units and how they are defined with respect // to each other. let term_ctx = TermContext :: new2 ( ctx ) ; let table = units . iter ( ) . map ( | & ( unit_name , ref expr ) | { let rel = if let Some ( ref expr ) = * expr { let term = term_ctx . termify_expr ( expr ) ? ; let ( value , unit ) = match term . value { Term :: PhysLit ( value , unit ) => ( value , unit ) , _ => { ctx . emit ( DiagBuilder2 :: error ( format ! ( " " term span extract ( ) ) ) . span ( term . span ) , ) ; debugln ! ( " " term value ) ; return Err ( ( ) ) ; } } ; // TODO: Find a way to enable this again! // if unit.value.0 != id { //     ctx.emit( //         DiagBuilder2::error(format!( //             "`{}` is not a unit in the physical type `{}`", //             term.span.extract(), //             type_name.value //         )).span(term.span) //             .add_note(format!("`{}` has been declared here:", term.span.extract() // )) //             .span(unit.span), //     ); // } Some ( ( value , unit . value . unwrap_new ( ) . 1 ) ) } else { None } ; Ok ( ( Spanned :: new ( unit_name . name , unit_name . span ) , rel ) ) } ) . collect :: < Vec < Result < _ > > > ( ) . into_iter ( ) . collect :: < Result < Vec < _ > > > ( ) ? ; // Determine the scale of each unit with respect to the primary unit. Ok ( ( table . iter ( ) . map ( | & ( name , ref rel ) | { let mut abs = BigInt :: from ( 1 ) ; let mut rel_to = rel . as_ref ( ) ; while let Some ( & ( ref scale , index ) ) = rel_to { abs = abs * scale ; rel_to = table [ index ] . 1 . as_ref ( ) ; } PhysicalUnit :: new ( name . value , abs , rel . clone ( ) ) } ) . collect :: < Vec < _ > > ( ) , primary . 0 , ) ) }
Unpack the units of a physical type declaration.
Unpack the units of a physical type declaration .
units
&[(ast::Ident, Option<Box<ast::Expr>>)]
type_name
Spanned<Name>
ctx
AllocContext<'t>