use super::*;
use pest::Parser;
use pest_derive::Parser;
use std::collections::HashMap;
use std::str::FromStr;
use parsing_utils::PairsHelper;
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()); 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()); 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> {
let p = match SPEFParser::parse(Rule::main, s) {
Ok(mut r) => r.next().unwrap(),
Err(e) => return Err(format!("{}", e)),
};
let mut p = PairsHelper(p.into_inner());
let header = parse_header(p.next());
let name_map = p.next_rule_opt(Rule::name_map)
.map(|p| parse_name_map(p))
.unwrap_or(Default::default());
let top_ports = p.next_rule_opt(Rule::top_ports)
.map(|p| parse_top_ports(&name_map, p))
.unwrap_or(Default::default());
let nets = p.iter_while(Rule::parasitic_net)
.map(|p| parse_parasitic_net(&name_map, p))
.collect();
Ok(SPEF{ header, top_ports, nets })
}