reda_lib/io/read/
semantic.rs1use std::fmt::Display;
2use std::{collections::HashMap, str::FromStr};
3use crate::error::{LibErrorContext, LibError};
4use crate::model::{LibAst, LibCell, LibGroup, LibLibrary, LibPin, LibPinDirection};
5
6pub trait FromLibGroup: Sized {
7 type Error: Sized;
8 fn from_group(group: LibGroup) -> Result<Self, Self::Error>;
9}
10
11impl LibLibrary {
12 pub fn from_ast(ast: LibAst) -> Result<Self, LibError> {
13 let group = LibGroup::from_ast(ast).context(|| "semantic root ast to group")?;
14 Self::from_group(group)
15 }
16}
17
18impl FromLibGroup for LibLibrary {
19 type Error = LibError;
20 fn from_group(group: LibGroup) -> Result<Self, LibError> {
21 let mut group = group;
22 let name = group.expect_name().context(|| "group name")?;
23 let (cell_groups, groups) = group.groups.into_iter().partition(|g| g.kind == "cell");
24
25 let mut cells = Vec::new();
27 for cell_group in cell_groups {
28 cells.push(LibCell::from_group(cell_group).context(|| "semantic cell")?);
29 }
30
31 Ok(Self {
32 name,
33 attrs: group.attrs,
34 groups,
35 cells,
36 })
37 }
38}
39
40impl FromLibGroup for LibCell {
41 type Error = LibError;
42 fn from_group(group: LibGroup) -> Result<Self, LibError> {
43 let mut group = group;
44 let name = group.expect_name().context(|| "cell name")?;
45 let err_context = |msg: &str| {
46 format!("{} in {} cell", msg, &name)
47 };
48
49 let (pin_groups, groups) = group.groups.into_iter().partition(|g| g.kind == "pin");
50
51 let mut pins = Vec::new();
53 for cell_group in pin_groups {
54 pins.push(LibPin::from_group(cell_group).context(|| err_context("semantic pin"))?);
55 }
56
57 Ok(Self {
58 name,
59 pins,
60 attrs: group.attrs,
61 groups,
62 })
63 }
64}
65
66impl FromLibGroup for LibPin {
67 type Error = LibError;
68 fn from_group(group: LibGroup) -> Result<Self, LibError> {
69 let mut group = group;
70 let name = group.expect_name().context(|| "pin name")?;
71 let err_context = |msg: &str| {
72 format!("{} in `{}` pin", msg, &name)
73 };
74
75 let direction = match group.expect_ident_attr_opt("direction")
76 .context(|| err_context("semantic `direction` attr"))?
77 {
78 Some(s) => LibPinDirection::from_str(&s)?,
79 None => LibPinDirection::default(),
80 };
81 let function = group.expect_string_attr_opt("function")
82 .context(|| err_context("semantic `function` attr"))?;
83
84 Ok(Self {
85 name,
86 direction,
87 function,
88 attrs: group.attrs,
89 groups: group.groups,
90 })
91 }
92}
93
94impl FromStr for LibPinDirection {
95 type Err = LibError;
96 fn from_str(s: &str) -> Result<Self, Self::Err> {
97 match s {
98 "input" => Ok(Self::Input),
99 "output" => Ok(Self::Output),
100 "inout" => Ok(Self::Inout),
101 "internal" => Ok(Self::Internal),
102 s => Err(LibError::UnsupportDirection(s.to_string()))
103 }
104 }
105}
106
107impl Display for LibPinDirection {
108 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109 match self {
110 Self::Input => write!(f, "input"),
111 Self::Output => write!(f, "output"),
112 Self::Inout => write!(f, "inout"),
113 Self::Internal => write!(f, "internal"),
114 }
115 }
116}
117
118impl LibGroup {
119 pub fn from_ast(ast: LibAst) -> Result<Self, LibError> {
120 match ast {
121 LibAst::LibGroup { kind, params, items } => {
122 let mut attrs = HashMap::new();
123 let mut groups = Vec::new();
124
125 for item_ast in items {
126 if let LibAst::Attr { key, value } = item_ast {
127 attrs.insert(key, value);
128 } else {
129 groups.push(LibGroup::from_ast(item_ast)?);
130 }
131 }
132
133 Ok(Self {
134 kind,
135 params,
136 attrs,
137 groups
138 })
139 }
140 LibAst::Attr { key:_, value:_ } => Err(LibError::ExceptLibGroup),
141 }
142 }
143}
144
145#[cfg(test)]
146mod test {
147 use super::*;
148
149 #[test]
150 fn test_pin_into_group() {
151 let mut pin = LibPin::new("my_pin");
152 pin.groups.push(LibGroup::new("gtype", vec!["gname".to_string()]));
153 }
158
159 #[test]
160 fn test_pin_from_group() {
161 let mut group = LibGroup::new("pin", vec!["a".to_string()]);
162 group.groups.push(LibGroup::new("gtype", vec!["gname".to_string()]));
163 let pin = LibPin::from_group(group).unwrap();
164 assert_eq!(pin.name, "a");
165 assert_eq!(pin.groups.len(), 1);
166 }
167
168 #[test]
169 fn test_cell_into_group() {
170 let mut cell = LibCell::new("my_cell");
171 cell.groups.push(LibGroup::new("gtype", vec!["gname".to_string()]));
172 cell.pins.push(LibPin::new("a"));
173 cell.pins.push(LibPin::new("b"));
174 }
179
180 #[test]
181 fn test_cell_from_group() {
182 let mut group = LibGroup::new("cell", vec!["AND2".to_string()]);
183 group.groups.push(LibGroup::new("gtype", vec!["gname".to_string()]));
184 group.groups.push(LibGroup::new("pin", vec!["a".to_string()]));
185 group.groups.push(LibGroup::new("pin", vec!["b".to_string()]));
186 let cell = LibCell::from_group(group).unwrap();
187 assert_eq!(cell.name, "AND2");
188 assert_eq!(cell.groups.len(), 1);
189 assert_eq!(cell.pins.len(), 2);
190 }
191
192 #[test]
193 fn test_library_into_group() {
194 let mut lib = LibLibrary::new("my_lib");
195 lib.groups.push(LibGroup::new("gtype", vec!["gname".to_string()]));
196 lib.cells.push(LibCell::new("AND2"));
197 lib.cells.push(LibCell::new("NAND2"));
198 }
203
204 #[test]
205 fn test_lib_from_group() {
206 let mut group = LibGroup::new("library", vec!["mylib".to_string()]);
207 group.groups.push(LibGroup::new("gtype", vec!["gname".to_string()]));
208 let mut cell = LibGroup::new("cell", vec!["AND2".to_string()]);
209 cell.groups.push(LibGroup::new("pin", vec!["a".to_string()]));
210 cell.groups.push(LibGroup::new("pin", vec!["b".to_string()]));
211 group.groups.push(cell);
212 let lib = LibLibrary::from_group(group).unwrap();
213 assert_eq!(lib.name, "mylib");
214 assert_eq!(lib.groups.len(), 1);
215 assert_eq!(lib.cells.len(), 1);
216 let converted_cell = lib.cell("AND2").unwrap();
217 assert_eq!(converted_cell.name, "AND2");
218 assert_eq!(converted_cell.groups.len(), 0);
219 assert_eq!(converted_cell.pins.len(), 2);
220 }
221}