spefparse 0.2.0

SPEF parasitics parser
Documentation
use super::*;
use pest::Parser;
use pest_derive::Parser;
use std::collections::HashMap;
use std::str::FromStr;
use parsing_utils::PairsHelper;

/// Name mapping.
/// It is used in parsing, but hidden from
/// the parsed SPEF object.
type NameMap = HashMap<isize, (Arc<HierName>, Option<isize>)>;

#[derive(Parser)]
#[grammar = "spef.pest"]
struct SPEFParser;

type Pair<'i> = pest::iterators::Pair<'i, Rule>;

#[inline]
fn unescape(s: &str) -> CompactString {
    if s.chars().all(|c| c != '\\') {
        return s.into();
    }
    let mut cs = CompactString::with_capacity(s.len());
    let mut s = s.chars();
    while let Some(c) = s.next() {
        if c == '\\' { cs.push(s.next().unwrap()); }
        else { cs.push(c); }
    }
    cs
}

#[inline]
fn parse_str(p: Pair) -> CompactString {
    assert_eq!(p.as_rule(), Rule::str);
    let substr = p.as_str();
    let substr = &substr[1..substr.len() - 1];
    unescape(substr)
}

#[inline]
fn parse_ident(p: Pair) -> CompactString {
    assert_eq!(p.as_rule(), Rule::ident);
    let substr = p.as_str();
    unescape(substr)
}

#[inline]
fn parse_int(p: Pair) -> isize {
    assert_eq!(p.as_rule(), Rule::int);
    isize::from_str(p.as_str()).unwrap()
}

#[inline]
fn parse_float(p: Pair) -> f32 {
    assert_eq!(p.as_rule(), Rule::float);
    f32::from_str(p.as_str()).unwrap()
}

#[inline]
fn parse_char(p: Pair) -> char {
    assert!(p.as_rule() == Rule::hchar ||
            p.as_rule() == Rule::prefix_bus_delim_char ||
            p.as_rule() == Rule::suffix_bus_delim_char);
    let s = p.as_str();
    assert_eq!(s.len(), 1);
    s.chars().next().unwrap()
}

#[inline]
fn parse_header(p: Pair) -> SPEFHeader {
    assert_eq!(p.as_rule(), Rule::header);
    let mut p = PairsHelper(p.into_inner());
    macro_rules! unit_match {
        ($($map:tt)+) => {
            parse_float(p.next()) *
                match p.next().as_str().to_ascii_uppercase().as_str() {
                    $($map)+,
                    _ => unreachable!()
                }
        }
    }
    SPEFHeader {
        edition: parse_str(p.next()),
        design: parse_str(p.next()),
        date: parse_str(p.next()),
        vendor: parse_str(p.next()),
        program: parse_str(p.next()),
        version: parse_str(p.next()),
        design_flow: p.next_rule(Rule::header_design_flow).into_inner()
            .map(|p| parse_str(p)).collect(),
        divider: parse_char(p.next_rule(Rule::hchar)),
        delimiter: parse_char(p.next_rule(Rule::hchar)),
        bus_delimiter_left: parse_char(
            p.next_rule(Rule::prefix_bus_delim_char)),
        bus_delimiter_right: parse_char(
            p.next_rule(Rule::suffix_bus_delim_char)),
        time_unit: unit_match!("NS" => 1e-9, "PS" => 1e-12),
        cap_unit: unit_match!("PF" => 1e-12, "FF" => 1e-15),
        res_unit: unit_match!("OHM" => 1., "KOHM" => 1e3),
        induct_unit: unit_match!("HENRY" => 1., "MH" => 1e-3, "UH" => 1e-6)
    }
}

#[inline]
fn parse_ident_path(p: Pair) -> (Arc<HierName>, Option<isize>) {
    assert_eq!(p.as_rule(), Rule::ident_path);
    let mut p = PairsHelper(p.into_inner());
    (Arc::from(HierName(p.iter_while(Rule::ident)
                        .map(|p| parse_ident(p)).collect())),
     p.next_rule_opt(Rule::int).map(|p| parse_int(p)))
}

#[inline]
fn parse_name_map(p: Pair) -> NameMap {
    assert_eq!(p.as_rule(), Rule::name_map);
    p.into_inner().map(|p| {
        let mut p = PairsHelper(p.into_inner());
        (parse_int(p.next()), parse_ident_path(p.next()))
    }).collect()
}

#[inline]
fn parse_ident_path_m(nm: &NameMap, p: Pair) -> (Arc<HierName>, Option<isize>) {
    assert_eq!(p.as_rule(), Rule::ident_path_m);
    let p = PairsHelper(p.into_inner()).next();
    match p.as_rule() {
        Rule::ident_path => parse_ident_path(p),
        Rule::int => nm.get(&parse_int(p)).expect("bad map id").clone(),
        _ => unreachable!()
    }
}

#[inline]
fn parse_direction(p: Pair) -> Direction {
    assert_eq!(p.as_rule(), Rule::direction);
    use Direction::*;
    match p.as_str() {
        "O" => O, "I" => I, "B" => B,
        _ => unreachable!()
    }
}

#[inline]
fn parse_par_value(p: Pair) -> ParValue {
    assert_eq!(p.as_rule(), Rule::par_value);
    let mut p = PairsHelper(p.into_inner());
    let v0 = parse_float(p.next());
    let v1 = p.next_rule_opt(Rule::float);
    use ParValue::*;
    match v1 {
        Some(v1) => Three(v0, parse_float(v1),
                          parse_float(p.next())),
        None => Single(v0)
    }
}

#[inline]
fn parse_conn_attr(p: Pair) -> SPEFConnAttr {
    assert_eq!(p.as_rule(), Rule::conn_attr);
    let mut coords = None;
    let mut cap_load = None;
    let mut slew = None;
    let mut driving_cell = None;
    for p in p.into_inner() {
        let rule = p.as_rule();
        let mut p = PairsHelper(p.into_inner());
        match rule {
            Rule::ca_coords => {
                assert_eq!(coords, None, "multiple coords");
                coords = Some((parse_float(p.next()),
                               parse_float(p.next())));
            }
            Rule::ca_cap_load => {
                assert_eq!(cap_load, None, "multiple caps");
                cap_load = Some(parse_par_value(p.next()));
            }
            Rule::ca_slew => {
                assert_eq!(slew, None, "multiple slews");
                slew = Some((parse_par_value(p.next()),
                             parse_par_value(p.next())));
            }
            Rule::ca_driving_cell => {
                assert_eq!(driving_cell, None, "multiple driving cells");
                driving_cell = Some(parse_ident(p.next()))
            }
            _ => unreachable!()
        }
    }
    SPEFConnAttr { coords, cap_load, slew, driving_cell }
}

#[inline]
fn parse_top_ports(nm: &NameMap, p: Pair) -> Vec<SPEFPort> {
    assert_eq!(p.as_rule(), Rule::top_ports);
    p.into_inner().map(|p| {
        let mut p = PairsHelper(p.into_inner());
        SPEFPort {
            name: {
                let (ident, id) = parse_ident_path_m(nm, p.next());
                SPEFHierPortPinRef( ident, None, id )
            },
            direction: parse_direction(p.next()),
            conn_attr: parse_conn_attr(p.next())
        }
    }).collect()
}

#[inline]
fn parse_net_name_ref(nm: &NameMap, p: Pair) -> SPEFHierPortPinRef {
    assert!(p.as_rule() == Rule::net_conn_port ||
            p.as_rule() == Rule::net_conn_intr ||
            p.as_rule() == Rule::net_name_ref,
            "unexpected net name ref rule: {:?}", p.as_rule());
    let mut p = PairsHelper(p.into_inner());
    
    let (ident, bit_id_m) = parse_ident_path_m(nm, p.next());
    let pin_ident = p.next_rule_opt(Rule::ident).map(parse_ident);
    let bit_id = p.next_rule_opt(Rule::int).map(parse_int);
    
    if bit_id_m.is_some() && bit_id.is_some() {
        panic!("duplicate bit id. first in name map: {:?} ({}), \
then in net ref ({}).", ident, bit_id_m.unwrap(), bit_id.unwrap());
    }
    let bit_id = bit_id_m.or(bit_id);
    
    SPEFHierPortPinRef( ident, pin_ident, bit_id )
}

#[inline]
fn parse_parasitic_net(nm: &NameMap, p: Pair) -> SPEFNet {
    assert_eq!(p.as_rule(), Rule::parasitic_net);
    let mut p = PairsHelper(p.into_inner());
    
    let (ident, id) = parse_ident_path_m(nm, p.next());
    let name = SPEFHierPortPinRef( ident, None, id );
    let total_cap = parse_float(p.next());
    
    let conns = p.iter_while(Rule::net_conn)
        .map(|p| {
            let mut p = PairsHelper(p.into_inner());
            SPEFNetConn { name: parse_net_name_ref(nm, p.next()),
                          direction: parse_direction(p.next()),
                          conn_attr: parse_conn_attr(p.next()) }
        }).collect();
    
    let caps = p.iter_while(Rule::net_cap)
        .map(|p| {
            let mut p = PairsHelper(p.into_inner());
            drop(p.next());  // int
            SPEFNetCap { a: parse_net_name_ref(nm, p.next()),
                         b: p.next_rule_opt(Rule::net_name_ref)
                         .map(|p| parse_net_name_ref(nm, p)),
                         val: parse_par_value(p.next()) }
        }).collect();
    
    let ress = p.iter_while(Rule::net_res)
        .map(|p| {
            let mut p = PairsHelper(p.into_inner());
            drop(p.next());  // int
            SPEFNetRes { a: parse_net_name_ref(nm, p.next()),
                         b: parse_net_name_ref(nm, p.next()),
                         val: parse_par_value(p.next()) }
        }).collect();
    
    SPEFNet { name, total_cap, conns, caps, ress }
}

pub fn parse_spef(s: &str) -> Result<SPEF, String> {
    // clilog::info!("begin parse");
    let p = match SPEFParser::parse(Rule::main, s) {
        Ok(mut r) => r.next().unwrap(),
        Err(e) => return Err(format!("{}", e)),
    };
    // clilog::info!("pest done");
    let mut p = PairsHelper(p.into_inner());

    let header = parse_header(p.next());
    // clilog::info!("header done");
    let name_map = p.next_rule_opt(Rule::name_map)
        .map(|p| parse_name_map(p))
        .unwrap_or(Default::default());
    // clilog::info!("name map done");
    let top_ports = p.next_rule_opt(Rule::top_ports)
        .map(|p| parse_top_ports(&name_map, p))
        .unwrap_or(Default::default());
    // clilog::info!("top ports done");
    let nets = p.iter_while(Rule::parasitic_net)
        .map(|p| parse_parasitic_net(&name_map, p))
        .collect();
    // clilog::info!("nets done");
    
    Ok(SPEF{ header, top_ports, nets })
}