1use std::result;
6
7use crate::error::Error;
8use crate::liberty::Liberty;
9use crate::parser::parse_libs;
10
11use itertools::Itertools;
12use nom::error::VerboseError;
13
14pub type ParseResult<'a, T> = result::Result<T, Error<'a>>;
16
17#[derive(Debug)]
22pub struct LibertyAst(pub Vec<GroupItem>);
23
24impl LibertyAst {
25 pub fn new(libs: Vec<GroupItem>) -> Self {
27 Self(libs)
28 }
29
30 pub fn from_string(input: &str) -> ParseResult<Self> {
32 parse_libs::<VerboseError<&str>>(input)
33 .map_err(|e| Error::new(input, e))
34 .map(|(_, libs)| LibertyAst::new(libs))
35 }
36
37 pub fn to_string(&self) -> String {
39 items_to_string(&self.0)
40 }
41
42 pub fn into_liberty(self) -> Liberty {
44 Liberty::from_ast(self)
45 }
46
47 pub fn from_liberty(lib: Liberty) -> Self {
49 lib.to_ast()
50 }
51}
52
53fn items_to_string(items: &Vec<GroupItem>) -> String {
55 items
56 .iter()
57 .map(|item| match item {
58 GroupItem::SimpleAttr(name, value) => format!("{} : {};\n", name, value.to_string()),
59 GroupItem::ComplexAttr(name, values) => format!(
60 "{} (\n{}\n)\n",
61 name,
62 values.iter().map(|v| v.to_string()).join(", ")
63 ),
64 GroupItem::Comment(v) => format!("/*\n{}\n*/", v),
65 GroupItem::Group(type_, name, group_items) => format!(
66 "{} ( {} ) {{\n{}\n}}",
67 type_,
68 name,
69 items_to_string(group_items)
70 ),
71 })
72 .join("\n")
73}
74
75#[derive(Debug, PartialEq, Clone)]
77pub enum GroupItem {
78 Group(String, String, Vec<GroupItem>),
80 SimpleAttr(String, Value),
82 ComplexAttr(String, Vec<Value>),
83 Comment(String),
85}
86
87impl GroupItem {
88 pub fn group(&self) -> (String, String, Vec<GroupItem>) {
90 if let GroupItem::Group(type_, name, items) = self {
91 (String::from(type_), String::from(name), items.clone())
92 } else {
93 panic!("Not variant GroupItem::Group");
94 }
95 }
96}
97
98#[derive(Debug, PartialEq, Clone)]
104pub enum Value {
105 Bool(bool),
107 Float(f64),
112 FloatGroup(Vec<f64>),
125 String(String),
127 Expression(String),
132}
133
134impl Value {
135 pub fn to_string(&self) -> String {
137 match self {
138 Value::String(v) => format!("\"{}\"", v),
139 Value::Expression(v) => format!("{}", v),
140 Value::Bool(v) => {
141 if *v {
142 "true".to_string()
143 } else {
144 "false".to_string()
145 }
146 }
147 Value::Float(v) => format!("{:.6}", v),
148 Value::FloatGroup(v) => format!("\"{}\"", format!("{:.6}", v.iter().format(", "))),
149 }
150 }
151
152 pub fn float(&self) -> f64 {
154 if let Value::Float(v) = self {
155 v.clone()
156 } else {
157 panic!("Not a float")
158 }
159 }
160
161 pub fn string(&self) -> String {
163 if let Value::String(v) = self {
164 v.clone()
165 } else {
166 panic!("Not a string")
167 }
168 }
169
170 pub fn expr(&self) -> String {
172 if let Value::Expression(v) = self {
173 v.clone()
174 } else {
175 panic!("Not a string")
176 }
177 }
178
179 pub fn bool(&self) -> bool {
181 if let Value::Bool(v) = self {
182 v.clone()
183 } else {
184 panic!("Not a bool")
185 }
186 }
187
188 pub fn float_group(&self) -> Vec<f64> {
190 if let Value::FloatGroup(v) = self {
191 v.clone()
192 } else {
193 panic!("Not a float group")
194 }
195 }
196}
197
198#[cfg(test)]
199mod test {
200 use super::{LibertyAst, Value};
201
202 macro_rules! parse_file {
203 ($fname:ident) => {{
204 let data = include_str!(concat!("../data/", stringify!($fname), ".lib"));
205 LibertyAst::from_string(data).unwrap()
206 }};
207 }
208
209 #[test]
210 fn test_files() {
211 parse_file!(small);
212 parse_file!(cells);
213 parse_file!(cells_timing);
214 }
215
216 #[test]
217 fn test_values() {
218 assert_eq!(Value::Bool(false).bool(), false);
219 assert_eq!(Value::Float(-3.45).float(), -3.45f64);
220 assert_eq!(Value::Expression("A & B".to_string()).expr(), "A & B");
221 assert_eq!(
222 Value::FloatGroup(vec![1.2, 3.4]).float_group(),
223 vec![1.2, 3.4]
224 );
225 assert_eq!(Value::String("abc def".to_string()).string(), "abc def");
226 }
227}