Skip to main content

liberty_parser/
parser.rs

1use crate::ast::{GroupItem, Value};
2
3use gpoint::GPoint;
4
5use itertools::Itertools;
6use nom::{
7    branch::alt,
8    bytes::complete::{is_a, is_not, tag, take_until, take_while},
9    character::complete::{alpha1, char, line_ending, multispace0, one_of},
10    combinator::{all_consuming, cut, map, map_res, opt, peek, recognize},
11    error::{context, ParseError},
12    multi::{fold_many0, separated_list},
13    number::complete::double,
14    sequence::{delimited, preceded, terminated, tuple},
15    IResult,
16};
17
18fn underscore_tag<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, &'a str, E> {
19    context(
20        "underscore_tag",
21        recognize(preceded(
22            alpha1,
23            take_while(|c: char| c.is_alphanumeric() || c.eq_ignore_ascii_case(&'_')),
24        )),
25    )(input)
26}
27
28fn quoted_floats<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, Vec<f64>, E> {
29    context(
30        "quoted floats",
31        preceded(
32            char('\"'),
33            terminated(
34                separated_list(
35                    preceded(multispace0, char(',')),
36                    preceded(multispace0, double),
37                ),
38                char('\"'),
39            ),
40        ),
41    )(input)
42}
43
44fn expression<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, &'a str, E> {
45    context("expression", move |input| {
46        recognize(separated_list(
47            // operator
48            preceded(multispace0, is_a("+-*/")),
49            // operand
50            preceded(
51                multispace0,
52                preceded(
53                    opt(is_a("-")),
54                    alt((
55                        // sub expression
56                        preceded(char('('), cut(terminated(expression, char(')')))),
57                        // identifier
58                        underscore_tag,
59                        // constant
60                        recognize(double),
61                    )),
62                ),
63            ),
64        ))(input)
65    })(input)
66}
67
68fn quoted_string<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, &'a str, E> {
69    context(
70        "quoted string",
71        preceded(char('\"'), cut(terminated(is_not("\""), char('\"')))),
72    )(input)
73}
74
75fn boolean<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, bool, E> {
76    map_res(alpha1, |s: &str| s.parse::<bool>())(input)
77}
78
79fn simple_attr_value<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, Value, E> {
80    context(
81        "simple attr value",
82        preceded(
83            multispace0,
84            alt((
85                map(quoted_floats, Value::FloatGroup),
86                map(quoted_string, |s| Value::String(s.to_string())),
87                map(terminated(double, peek(one_of(",; \t)"))), Value::Float),
88                map(boolean, Value::Bool),
89                map(map(expression, String::from), Value::Expression),
90            )),
91        ),
92    )(input)
93}
94
95fn simple_attribute<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, GroupItem, E> {
96    context(
97        "simple attr",
98        map(
99            tuple((
100                preceded(multispace0, underscore_tag),
101                preceded(multispace0, char(':')),
102                cut(preceded(multispace0, simple_attr_value)),
103                preceded(multispace0, char(';')),
104            )),
105            |(name, _, value, _)| GroupItem::SimpleAttr(name.to_string(), value),
106        ),
107    )(input)
108}
109
110fn complex_attribute_values<'a, E: ParseError<&'a str>>(
111    input: &'a str,
112) -> IResult<&'a str, Vec<Value>, E> {
113    context(
114        "complex values",
115        delimited(
116            preceded(multispace0, tag("(")),
117            delimited(
118                opt(tuple((multispace0, tag("\\"), line_ending))),
119                separated_list(
120                    alt((
121                        map(
122                            tuple((multispace0, tag(","), multispace0, tag("\\"), line_ending)),
123                            |_| Some(1),
124                        ),
125                        map(tuple((multispace0, tag(","))), |_| Some(1)),
126                        map(
127                            tuple((multispace0, tag("\\"), line_ending, multispace0, tag(","))),
128                            |_| Some(1),
129                        ),
130                    )),
131                    preceded(multispace0, simple_attr_value),
132                ),
133                opt(tuple((multispace0, tag("\\"), line_ending))),
134            ),
135            preceded(multispace0, tag(")")),
136        ),
137    )(input)
138}
139
140fn complex_attribute<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, GroupItem, E> {
141    context(
142        "complex attr",
143        map(
144            tuple((
145                preceded(multispace0, underscore_tag),
146                preceded(multispace0, complex_attribute_values),
147                preceded(multispace0, char(';')),
148            )),
149            |(name, value, _)| GroupItem::ComplexAttr(name.to_string(), value),
150        ),
151    )(input)
152}
153
154fn comment<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, &'a str, E> {
155    context(
156        "comment",
157        recognize(delimited(tag("/*"), take_until("*/"), tag("*/"))),
158    )(input)
159}
160
161fn parse_group_body<'a, E: ParseError<&'a str>>(
162    input: &'a str,
163) -> IResult<&'a str, Vec<GroupItem>, E> {
164    context(
165        "group body",
166        fold_many0(
167            context(
168                "folding items",
169                alt((
170                    map(
171                        map(preceded(multispace0, comment), String::from),
172                        GroupItem::Comment,
173                    ),
174                    preceded(multispace0, parse_group),
175                    preceded(multispace0, simple_attribute),
176                    preceded(multispace0, complex_attribute),
177                )),
178            ),
179            Vec::new(),
180            |mut acc: Vec<_>, item| {
181                acc.push(item);
182                acc
183            },
184        ),
185    )(input)
186}
187fn parse_group<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, GroupItem, E> {
188    context(
189        "parsing group",
190        map(
191            tuple((
192                preceded(multispace0, underscore_tag),
193                preceded(
194                    preceded(multispace0, char('(')),
195                    terminated(
196                        map(
197                            separated_list(
198                                preceded(multispace0, char(',')),
199                                preceded(
200                                    multispace0,
201                                    alt((
202                                        map(quoted_string, |s| format!("\"{}\"", s)),
203                                        map(underscore_tag, |s| s.to_string()),
204                                        map(double, |s| format!("{}", GPoint(s))),
205                                        map(quoted_floats, |s| {
206                                            format!(
207                                                "\"{}\"",
208                                                s.into_iter()
209                                                    .map(|f| format!("{}", GPoint(f)))
210                                                    .format(",")
211                                            )
212                                        }),
213                                    )),
214                                ),
215                            ),
216                            |vals: Vec<String>| vals.join(", "),
217                        ),
218                        preceded(multispace0, char(')')),
219                    ),
220                ),
221                preceded(
222                    preceded(multispace0, char('{')),
223                    cut(terminated(
224                        parse_group_body,
225                        preceded(multispace0, char('}')),
226                    )),
227                ),
228            )),
229            |(gtype, name, body)| GroupItem::Group(gtype.to_string(), name, body),
230        ),
231    )(input)
232}
233
234pub fn parse_libs<'a, E: ParseError<&'a str>>(
235    input: &'a str,
236) -> IResult<&'a str, Vec<GroupItem>, E> {
237    context(
238        "parse_libs",
239        all_consuming(terminated(
240            fold_many0(
241                alt((
242                    context(
243                        "outer comment",
244                        map(
245                            map(delimited(multispace0, comment, multispace0), String::from),
246                            GroupItem::Comment,
247                        ),
248                    ),
249                    preceded(multispace0, context("parse_lib", parse_group)),
250                )),
251                Vec::new(),
252                |mut acc: Vec<_>, item| {
253                    match &item {
254                        GroupItem::Group(_, _, _) => acc.push(item),
255                        GroupItem::Comment(_) => {}
256                        GroupItem::SimpleAttr(_, _) => {}
257                        GroupItem::ComplexAttr(_, _) => {}
258                    }
259                    acc
260                },
261            ),
262            multispace0,
263        )),
264    )(input)
265}
266
267#[cfg(test)]
268mod tests {
269    use super::*;
270    use nom::{
271        error::{convert_error, ErrorKind, VerboseError},
272        Err,
273    };
274
275    #[test]
276    fn test_complex_attr_values() {
277        assert_eq!(
278            complex_attribute_values::<VerboseError<&str>>(
279                r#"( \
280    "0, 0.18, 0.33", \
281    "-0.555, -0.45, -0.225" \
282    )"#
283            ),
284            Ok((
285                "",
286                vec![
287                    Value::FloatGroup(vec![0.0, 0.18, 0.33]),
288                    Value::FloatGroup(vec![-0.555, -0.45, -0.225]),
289                ]
290            ))
291        );
292        assert_eq!(
293            complex_attribute_values::<VerboseError<&str>>(
294                r#"( \
295                 "a string(b)" \
296                 )"#
297            ),
298            Ok(("", vec![Value::String("a string(b)".to_string())]))
299        );
300        assert_eq!(
301            complex_attribute_values::<VerboseError<&str>>("(123,-456)"),
302            Ok(("", vec![Value::Float(123.0), Value::Float(-456.0),]))
303        );
304    }
305
306    #[test]
307    fn test_complex_attr() {
308        assert_eq!(
309            complex_attribute::<(&str, ErrorKind)>("capacitive_load_unit (1,pf);"),
310            Ok((
311                "",
312                GroupItem::ComplexAttr(
313                    "capacitive_load_unit".to_string(),
314                    vec![Value::Float(1.0), Value::Expression("pf".to_string()),],
315                )
316            ))
317        );
318    }
319
320    #[test]
321    fn test_complex_attr_multi_line() {
322        assert_eq!(
323            complex_attribute::<(&str, ErrorKind)>(
324                r#"values ( \
325    "0, 0.18, 0.33", \
326    "-0.555, -0.45, -0.225");"#
327            ),
328            Ok((
329                "",
330                GroupItem::ComplexAttr(
331                    "values".to_string(),
332                    vec![
333                        Value::FloatGroup(vec![0.0, 0.18, 0.33]),
334                        Value::FloatGroup(vec![-0.555, -0.45, -0.225]),
335                    ],
336                )
337            ))
338        );
339    }
340
341    #[test]
342    fn test_comment() {
343        assert_eq!(
344            comment::<(&str, ErrorKind)>("/*** abc **/def"),
345            Ok(("def", "/*** abc **/"))
346        );
347        assert_eq!(
348            comment::<(&str, ErrorKind)>(
349                "/* multi
350line
351**
352**/
353**/rest"
354            ),
355            Ok((
356                "
357**/rest",
358                "/* multi
359line
360**
361**/"
362            ))
363        );
364    }
365
366    #[test]
367    fn test_underscore_tag() {
368        assert_eq!(
369            underscore_tag::<(&str, ErrorKind)>("a_b__c"),
370            Ok(("", "a_b__c"))
371        );
372        assert_eq!(
373            underscore_tag::<(&str, ErrorKind)>("abc other"),
374            Ok((" other", "abc"))
375        );
376        assert_eq!(
377            underscore_tag::<(&str, ErrorKind)>("nand2"),
378            Ok(("", "nand2"))
379        );
380        assert_eq!(
381            underscore_tag::<(&str, ErrorKind)>("_"),
382            Err(Err::Error(("_", ErrorKind::Alpha)))
383        );
384        assert_eq!(
385            underscore_tag::<(&str, ErrorKind)>(" a_b"),
386            Err(Err::Error((" a_b", ErrorKind::Alpha)))
387        );
388        assert_eq!(
389            underscore_tag::<(&str, ErrorKind)>(",,"),
390            Err(Err::Error((",,", ErrorKind::Alpha)))
391        );
392    }
393
394    #[test]
395    fn test_simple_attribute_malformed() {
396        assert_eq!(
397            simple_attribute::<(&str, ErrorKind)>("attr_name : a b ; "),
398            Err(Err::Error(("b ; ", ErrorKind::Char))),
399        );
400    }
401    #[test]
402    fn test_simple_attribute_bool() {
403        assert_eq!(
404            simple_attribute::<(&str, ErrorKind)>("attr_name : true ; "),
405            Ok((
406                " ",
407                GroupItem::SimpleAttr(String::from("attr_name"), Value::Bool(true),)
408            ))
409        );
410        assert_eq!(
411            simple_attribute::<(&str, ErrorKind)>("attr_name : false ; "),
412            Ok((
413                " ",
414                GroupItem::SimpleAttr(String::from("attr_name"), Value::Bool(false),)
415            ))
416        );
417    }
418    #[test]
419    fn test_simple_attribute_float() {
420        assert_eq!(
421            simple_attribute::<(&str, ErrorKind)>("attr_name : 345.123 ; "),
422            Ok((
423                " ",
424                GroupItem::SimpleAttr(String::from("attr_name"), Value::Float(345.123),)
425            ))
426        );
427        assert_eq!(
428            simple_attribute::<(&str, ErrorKind)>("attr_name : -345.123 ; "),
429            Ok((
430                " ",
431                GroupItem::SimpleAttr(String::from("attr_name"), Value::Float(-345.123),)
432            ))
433        );
434    }
435    #[test]
436    fn test_simple_attribute_int() {
437        assert_eq!(
438            simple_attribute::<(&str, ErrorKind)>("attr_name : 345 ; "),
439            Ok((
440                " ",
441                GroupItem::SimpleAttr(String::from("attr_name"), Value::Float(345.0),)
442            ))
443        );
444        assert_eq!(
445            simple_attribute::<(&str, ErrorKind)>("attr_name : -345 ; "),
446            Ok((
447                " ",
448                GroupItem::SimpleAttr(String::from("attr_name"), Value::Float(-345.0),)
449            ))
450        );
451    }
452
453    #[test]
454    fn test_expression() {
455        let expressions = vec![
456            "A",
457            "-A",
458            "--A",
459            "A + B",
460            "A - B",
461            "A * B",
462            "A / B",
463            "(A + B)",
464            "((A + B))",
465            "(A / B) + C",
466            "(A / B) - (C * D)",
467            /****** with constants ******/
468            "A + 0.123",
469            "A - .123",
470            "A * 0",
471            "A / 1",
472            "(A + 0.5)",
473            "((1.23 + B))",
474            "(4.5 / B) + C",
475            "(7.8 / B) - (C * D)",
476        ];
477        for expr in expressions {
478            assert_eq!(expression::<(&str, ErrorKind)>(expr), Ok(("", expr)));
479        }
480    }
481
482    #[test]
483    fn test_simple_attribute_expression() {
484        assert_eq!(
485            simple_attribute::<(&str, ErrorKind)>("attr_name : nand2; "),
486            Ok((
487                " ",
488                GroupItem::SimpleAttr(
489                    String::from("attr_name"),
490                    Value::Expression(String::from("nand2")),
491                )
492            ))
493        );
494        assert_eq!(
495            simple_attribute::<(&str, ErrorKind)>("attr_name : table_lookup; "),
496            Ok((
497                " ",
498                GroupItem::SimpleAttr(
499                    String::from("attr_name"),
500                    Value::Expression(String::from("table_lookup")),
501                )
502            ))
503        );
504        let data = "attr_name : A +B; ";
505        match simple_attribute::<VerboseError<&str>>(data) {
506            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
507                println!("Error: {}", convert_error(data, err));
508                assert_eq!(true, false);
509            }
510            _ => {}
511        }
512        assert_eq!(
513            simple_attribute::<(&str, ErrorKind)>("attr_name : A + 1.2; "),
514            Ok((
515                " ",
516                GroupItem::SimpleAttr(
517                    String::from("attr_name"),
518                    Value::Expression(String::from("A + 1.2")),
519                )
520            ))
521        );
522    }
523
524    #[test]
525    fn test_simple_attribute_string() {
526        assert_eq!(
527            simple_attribute::<(&str, ErrorKind)>("attr_name : \"table_lookup\"; "),
528            Ok((
529                " ",
530                GroupItem::SimpleAttr(
531                    String::from("attr_name"),
532                    Value::String(String::from("table_lookup"))
533                )
534            ))
535        );
536    }
537
538    #[test]
539    fn test_parse_group() {
540        let data = "library ( foo ) {
541            abc ( 1, 2, 3 );
542        }";
543        match parse_group::<VerboseError<&str>>(data) {
544            Err(Err::Error(err)) | Err(Err::Failure(err)) => {
545                println!("Error: {}", convert_error(data, err));
546                assert_eq!(true, false);
547            }
548            _ => {}
549        };
550        assert_eq!(
551            parse_group::<(&str, ErrorKind)>(data),
552            Ok((
553                "",
554                GroupItem::Group(
555                    "library".to_string(),
556                    "foo".to_string(),
557                    vec![GroupItem::ComplexAttr(
558                        "abc".to_string(),
559                        vec![Value::Float(1.0), Value::Float(2.0), Value::Float(3.0),],
560                    ),],
561                ),
562            ))
563        );
564    }
565
566    #[test]
567    fn test_nested_group() {
568        assert_eq!(
569            parse_group::<(&str, ErrorKind)>(
570                r#"
571            outer( outer ) {
572                inner ( inner) {
573                    abc ( 1, 2, 3 );
574                }
575                inner(inner2 ) {
576                    abc ( 1, 2, 3 );
577                }
578            }"#
579            ),
580            Ok((
581                "",
582                GroupItem::Group(
583                    "outer".to_string(),
584                    "outer".to_string(),
585                    vec![
586                        GroupItem::Group(
587                            "inner".to_string(),
588                            "inner".to_string(),
589                            vec![GroupItem::ComplexAttr(
590                                "abc".to_string(),
591                                vec![Value::Float(1.0), Value::Float(2.0), Value::Float(3.0),],
592                            ),],
593                        ),
594                        GroupItem::Group(
595                            "inner".to_string(),
596                            "inner2".to_string(),
597                            vec![GroupItem::ComplexAttr(
598                                "abc".to_string(),
599                                vec![Value::Float(1.0), Value::Float(2.0), Value::Float(3.0),],
600                            ),],
601                        ),
602                    ]
603                )
604            ))
605        );
606    }
607
608    #[test]
609    fn test_lib_simple() {
610        assert_eq!(
611            parse_libs::<(&str, ErrorKind)>(
612                r#"
613/*
614 delay model :       typ
615 check model :       typ
616 power model :       typ
617 capacitance model : typ
618 other model :       typ
619*/
620library(foo) {
621
622  delay_model : table_lookup;
623  /* unit attributes */
624  time_unit : "1ns";
625  capacitive_load_unit (1, pf );
626  function: "A & B";
627
628  slew_upper_threshold_pct_rise : 80;
629  nom_temperature : 25.0;
630}
631"#
632            ),
633            Ok((
634                "",
635                vec![GroupItem::Group(
636                    "library".to_string(),
637                    "foo".to_string(),
638                    vec![
639                        GroupItem::SimpleAttr(
640                            "delay_model".to_string(),
641                            Value::Expression("table_lookup".to_string())
642                        ),
643                        GroupItem::Comment("/* unit attributes */".to_string()),
644                        GroupItem::SimpleAttr(
645                            "time_unit".to_string(),
646                            Value::String("1ns".to_string())
647                        ),
648                        GroupItem::ComplexAttr(
649                            "capacitive_load_unit".to_string(),
650                            vec![Value::Float(1.0), Value::Expression("pf".to_string()),],
651                        ),
652                        GroupItem::SimpleAttr(
653                            "function".to_string(),
654                            Value::String("A & B".to_string()),
655                        ),
656                        GroupItem::SimpleAttr(
657                            "slew_upper_threshold_pct_rise".to_string(),
658                            Value::Float(80.0)
659                        ),
660                        GroupItem::SimpleAttr("nom_temperature".to_string(), Value::Float(25.0)),
661                    ],
662                ),]
663            ))
664        );
665    }
666}