mod semantic;
use std::{collections::HashMap, path::Path};
use reda_lib_macro::model;
pub use semantic::{FromGroup, IntoGroup};
use crate::{ast::{self, Value}, error::LibError};
pub trait Model {
fn attrs(&self) -> &HashMap<String, Value>;
fn groups(&self) -> &[Group];
fn attr(&self, name: &str) -> Option<&Value> {
self.attrs().get(name)
}
fn kind_groups(&self, kind: &str) -> impl IntoIterator<Item = &Group> {
self.groups().into_iter().filter(move |g| g.kind == kind)
}
}
#[model]
#[derive(Debug, PartialEq, Clone, Default)]
pub struct Library {
pub name: String,
pub cells: Vec<Cell>,
}
impl Library {
pub fn new<S: Into<String>>(name: S) -> Self {
Self {
name: name.into(),
..Default::default()
}
}
pub fn load_file<P: AsRef<Path>>(path: P) -> Result<Self, LibError> {
let context = std::fs::read_to_string(path)?;
let ast = ast::parse_liberty(&context)?;
Self::from_ast(ast)
}
pub fn cell(&self, name: &str) -> Option<&Cell> {
self.cells.iter().find(|c| c.name == name)
}
}
#[model]
#[derive(Debug, PartialEq, Clone, Default)]
pub struct Cell {
pub name: String,
pub pins: Vec<Pin>,
}
impl Cell {
pub fn new<S: Into<String>>(name: S) -> Self {
Self {
name: name.into(),
..Default::default()
}
}
pub fn pin(&self, name: &str) -> Option<&Pin> {
self.pins.iter().find(|p| p.name == name)
}
}
#[model]
#[derive(Debug, PartialEq, Clone, Default)]
pub struct Pin {
pub name: String,
pub direction: PinDirection,
pub function: Option<String>,
}
#[derive(Debug, PartialEq, Clone, Default)]
pub enum PinDirection {
#[default]
Input,
Output,
Inout,
Internal,
}
impl Pin {
pub fn new<S: Into<String>>(name: S) -> Self {
Self {
name: name.into(),
..Default::default()
}
}
}
#[derive(Debug, PartialEq, Clone, Default)]
pub struct Group {
pub kind: String,
pub params: Vec<String>,
pub attrs: HashMap<String, Value>,
pub groups: Vec<Group>,
}
impl Group {
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 Group {
fn attrs(&self) -> &HashMap<String, Value> {
&self.attrs
}
fn groups(&self) -> &[Group] {
&self.groups
}
}
impl Group {
pub fn expect_name(&mut self) -> Result<String, LibError> {
if self.params.len() != 1 {
Err(LibError::LibraryParamLenUnmatch)?
}
Ok(self.params[0].clone())
}
pub fn expect_ident_attr(&mut self, attr_name: &str) -> Result<String, LibError> {
if let Some(value) = self.attrs.remove(attr_name) {
let s = value.into_ident()?;
Ok(s)
} else {
Err(LibError::MissAttr(attr_name.to_string()))
}
}
pub fn expect_ident_attr_opt(&mut self, attr_name: &str) -> Result<Option<String>, LibError> {
if let Some(value) = self.attrs.remove(attr_name) {
let s = value.into_ident()?;
Ok(Some(s))
} else {
Ok(None)
}
}
pub fn expect_string_attr_opt(&mut self, attr_name: &str) -> Result<Option<String>, LibError> {
if let Some(value) = self.attrs.remove(attr_name) {
let s = value.into_string()?;
Ok(Some(s))
} else {
Ok(None)
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_cells() {
let lib = Library::load_file("./data/cells.lib").unwrap();
let and2 = lib.cell("AND2").unwrap();
let pin = and2.pin("o").unwrap();
println!("{:#?}", pin.function);
}
}