mod ast;
mod library;
mod cell;
mod pin;
mod expr;
pub use ast::*;
pub use library::*;
pub use cell::*;
pub use pin::*;
pub use expr::*;
use std::{collections::HashMap, error::Error, str::FromStr};
use crate::error::{LibError, LibErrorContext};
pub trait Model {
fn attrs(&self) -> &HashMap<String, LibValue>;
fn groups(&self) -> &[LibGroup];
fn attr(&self, name: &str) -> Option<&LibValue> {
self.attrs().get(name)
}
fn attr_must(&self, name: &str) -> Result<&LibValue, LibError> {
self.attr(name).ok_or_else(|| LibError::MissAttr(name.to_string()))
}
fn kind_groups(&self, kind: &str) -> impl IntoIterator<Item = &LibGroup> {
self.groups().into_iter().filter(move |g| g.kind == kind)
}
}
#[derive(Debug, PartialEq, Clone, Default)]
pub struct LibGroup {
pub kind: String,
pub params: Vec<String>,
pub attrs: HashMap<String, LibValue>,
pub groups: Vec<LibGroup>,
}
impl LibGroup {
pub fn new<S: Into<String>, P: Into<Vec<String>>>(kind: S, params: P) -> Self {
Self {
kind: kind.into(),
params: params.into(),
..Default::default()
}
}
}
impl Model for LibGroup {
fn attrs(&self) -> &HashMap<String, LibValue> {
&self.attrs
}
fn groups(&self) -> &[LibGroup] {
&self.groups
}
}
impl LibGroup {
pub fn expect_name(&mut self) -> Result<String, LibError> {
if self.params.len() != 1 {
Err(LibError::LibraryParamLenUnmatch)?
}
Ok(self.params[0].clone())
}
pub fn attr_bool_opt<S: Into<String>>(&self, attr_name: &str, ctx: impl Fn() -> S) -> Result<Option<bool>, LibError> {
match self.attr(attr_name) {
Some(v) => Ok(Some(v.bool().context(ctx)?)),
None => Ok(None),
}
}
pub fn attr_float_opt<S: Into<String>>(&self, attr_name: &str, ctx: impl Fn() -> S) -> Result<Option<f64>, LibError> {
match self.attr(attr_name) {
Some(v) => Ok(Some(v.float().context(ctx)?)),
None => Ok(None),
}
}
pub fn attr_string_opt<S: Into<String>>(&self, attr_name: &str, ctx: impl Fn() -> S) -> Result<Option<&str>, LibError> {
match self.attr(attr_name) {
Some(v) => Ok(Some(v.string().context(ctx)?)),
None => Ok(None),
}
}
pub fn attr_ident_opt<S: Into<String>>(&self, attr_name: &str, ctx: impl Fn() -> S) -> Result<Option<&str>, LibError> {
match self.attr(attr_name) {
Some(v) => Ok(Some(v.ident().context(ctx)?)),
None => Ok(None),
}
}
pub fn attr_iteral_opt<S: Into<String>>(&self, attr_name: &str, ctx: impl Fn() -> S) -> Result<Option<&str>, LibError> {
match self.attr(attr_name) {
Some(v) => Ok(Some(v.iteral().context(ctx)?)),
None => Ok(None),
}
}
pub fn attr_expr_opt<S: Into<String>>(&self, attr_name: &str, ctx: &impl Fn() -> S) -> Result<Option<LibExpr>, LibError> {
match self.attr(attr_name) {
Some(v) => {
let s = v.string().context(ctx)?;
let expr = LibExpr::from_str(s).context(ctx)?;
Ok(Some(expr))
}
None => Ok(None),
}
}
pub fn attr_floats_opt<const N: usize, S: Into<String>>(&self, attr_name: &str, ctx: &impl Fn() -> S) -> Result<Option<[f64; N]>, LibError> {
match self.attr(attr_name) {
Some(v) => {
let vs = v.vector().context(ctx)?;
if vs.len() != N {
Err(LibError::Parse(format!("expect float len {}, got {}", N, vs.len())))?;
}
let mut fs = [0.0; N];
for i in 0..N {
let v = &vs[i];
let f = v.float().context(ctx)?;
fs[i] = f;
}
Ok(Some(fs))
}
None => Ok(None),
}
}
pub fn attr_parse_opt<T, S, F>(&self, attr_name: &str, ctx: &F) -> Result<Option<T>, LibError>
where
T: FromStr,
T::Err: Error,
S: Into<String>,
F: Fn() -> S
{
match self.attr(attr_name) {
Some(v) => {
let s = v.ident().context(ctx)?;
let v = T::from_str(s).map_err(|e| LibError::Parse(e.to_string())).context(ctx)?;
Ok(Some(v))
}
None => Ok(None),
}
}
pub fn attr_bool<S: Into<String>>(&self, attr_name: &str, ctx: impl Fn() -> S) -> Result<bool, LibError> {
let v = self.attr_bool_opt(attr_name, ctx)?;
v.ok_or_else(|| LibError::MissAttr(attr_name.into()))
}
pub fn attr_float<S: Into<String>>(&self, attr_name: &str, ctx: impl Fn() -> S) -> Result<f64, LibError> {
let v = self.attr_float_opt(attr_name, ctx)?;
v.ok_or_else(|| LibError::MissAttr(attr_name.into()))
}
pub fn attr_string<S: Into<String>>(&self, attr_name: &str, ctx: impl Fn() -> S) -> Result<&str, LibError> {
let v = self.attr_string_opt(attr_name, ctx)?;
v.ok_or_else(|| LibError::MissAttr(attr_name.into()))
}
pub fn attr_ident<S: Into<String>>(&self, attr_name: &str, ctx: impl Fn() -> S) -> Result<&str, LibError> {
let v = self.attr_ident_opt(attr_name, ctx)?;
v.ok_or_else(|| LibError::MissAttr(attr_name.into()))
}
pub fn attr_literal<S: Into<String>>(&self, attr_name: &str, ctx: impl Fn() -> S) -> Result<&str, LibError> {
let v = self.attr_ident_opt(attr_name, ctx)?;
v.ok_or_else(|| LibError::MissAttr(attr_name.into()))
}
pub fn attr_expr<S: Into<String>>(&self, attr_name: &str, ctx: &impl Fn() -> S) -> Result<LibExpr, LibError> {
let v = self.attr_expr_opt(attr_name, ctx)?;
v.ok_or_else(|| LibError::MissAttr(attr_name.into()))
}
pub fn attr_parse<T, S, F>(&self, attr_name: &str, ctx: &F) -> Result<T, LibError>
where
T: FromStr,
T::Err: Error,
S: Into<String>,
F: Fn() -> S
{
let v = self.attr_parse_opt(attr_name, ctx)?;
v.ok_or_else(|| LibError::MissAttr(attr_name.into()))
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_cells() {
let lib = LibLibrary::load_file("./data/cells.lib").unwrap();
let and2 = lib.cell("AND2").unwrap();
let pin = and2.pin("o").unwrap();
println!("{:#?}", pin.function);
}
}