reda_lib/ast/
parse.rs

1use nom::branch::alt;
2use nom::bytes::complete::{is_not, tag, take_until};
3use nom::character::complete::{alpha1, alphanumeric1, char, digit1, line_ending, multispace0, multispace1, not_line_ending, one_of};
4use nom::combinator::{map, cut, eof, map_res, opt, recognize, value};
5use nom::error::{context, VerboseError, VerboseErrorKind};
6use nom::multi::{many0, many1, separated_list0, separated_list1};
7use nom::number::streaming::double;
8use nom::sequence::{delimited, pair, preceded, terminated, tuple};
9use nom::IResult;
10use std::str;
11use std::str::FromStr;
12use crate::ast::{Ast, Value};
13use crate::error::{LibError, LibResult};
14
15pub type NomResult<'a, O> = IResult<&'a str, O, VerboseError<&'a str>>; 
16
17/// Convert Error to Failure
18pub trait ToFailure<T, E> {
19    fn to_failure(self) -> Result<T, nom::Err<E>>;
20}
21
22impl<T, E> ToFailure<T, E> for Result<T, nom::Err<E>> {
23    fn to_failure(self) -> Result<T, nom::Err<E>> {
24        self.map_err(|e| match e {
25            nom::Err::Error(e) => nom::Err::Failure(e),
26            other => other,
27        })
28    }
29}
30
31pub fn parse_liberty(input: &str) -> LibResult<Ast> {
32    match wrap_unused(group)(input) {
33        Ok((_, ast)) => Ok(ast),
34        Err(e) => {
35            match e {
36                nom::Err::Error(err) | nom::Err::Failure(err) => {
37                    let msg = pretty_print_error(input, err);
38                    Err(LibError::Parse(msg))
39                }
40                nom::Err::Incomplete(_) => Err(LibError::Parse("incomplete input".into())),
41            }
42        }
43    }
44}
45
46pub fn pretty_print_error(input: &str, e: VerboseError<&str>) -> String {
47    use std::fmt::Write;
48    let mut out = String::new();
49
50    for (i, (substr, kind)) in e.errors.iter().enumerate() {
51        // 计算出行号和列号
52        let prefix = &input[..(input.len() - substr.len()).min(input.len())];
53        let line_num = prefix.lines().count();
54        let last_line = prefix.lines().last().unwrap_or("");
55        let col_num = last_line.len() + 1;
56
57        match kind {
58            VerboseErrorKind::Context(ctx) => {
59                writeln!(
60                    &mut out,
61                    "{i:02}: at line {line_num}, column {col_num}: in context `{ctx}`"
62                ).unwrap();
63            }
64            VerboseErrorKind::Char(c) => {
65                writeln!(
66                    &mut out,
67                    "{i:02}: at line {line_num}, column {col_num}: expected char `{c}`"
68                ).unwrap();
69            }
70            VerboseErrorKind::Nom(kind) => {
71                writeln!(
72                    &mut out,
73                    "{i:02}: at line {line_num}, column {col_num}: nom error: {:?}",
74                    kind
75                ).unwrap();
76            }
77        }
78    }
79
80    out
81}
82
83pub fn ast(input: &str) -> NomResult<Ast> {
84    context(
85        "ast",
86        alt((
87            attr,
88            group,
89        ))
90    )(input)
91}
92
93/// 单行注释: // ...
94fn line_comment(input: &str) -> NomResult<()> {
95    value(
96        (),
97        preceded(tag("//"), alt((not_line_ending, eof))),
98    )(input)
99}
100
101/// 多行注释: /* ... */
102fn block_comment(input: &str) -> NomResult<()> {
103    value((), delimited(tag("/*"), take_until("*/"), tag("*/")))(input)
104}
105
106#[allow(unused)]
107fn comment(input: &str) -> NomResult<&str> {
108    context(
109        "comment",
110        recognize(delimited(tag("/*"), take_until("*/"), tag("*/"))),
111    )(input)
112}
113
114/// 跳过空白
115fn ws0(input: &str) -> NomResult<()> {
116    value(
117        (),
118        many0(value((), multispace1)),
119    )(input)
120}
121
122/// 跳过空白或注释
123fn unused0(input: &str) -> NomResult<()> {
124    value(
125        (),
126        many0(alt((
127            value((), multispace1), // 至少一个空白,包括换行
128            line_comment,
129            block_comment,
130        ))),
131    )(input)
132}
133
134#[allow(unused)]
135/// 包装 parser,自动跳过两边空白
136fn wrap_ws<'a, F: 'a, O>(mut inner: F) -> impl FnMut(&'a str) -> NomResult<'a, O>
137where
138    F: FnMut(&'a str) -> NomResult<'a, O>,
139{
140    move |input: &'a str| {
141        let (input, _) = ws0(input)?;
142        let (input, res) = inner(input)?;
143        let (input, _) = ws0(input)?;
144        Ok((input, res))
145    }
146}
147
148/// 包装 parser,自动跳过前方的空白
149fn pre_ws<'a, F: 'a, O>(mut inner: F) -> impl FnMut(&'a str) -> NomResult<'a, O>
150where
151    F: FnMut(&'a str) -> NomResult<'a, O>,
152{
153    move |input: &'a str| {
154        let (input, _) = ws0(input)?;
155        let (input, res) = inner(input)?;
156        Ok((input, res))
157    }
158}
159
160/// 包装 parser,自动跳过两边空白或注释
161fn wrap_unused<'a, F: 'a, O>(mut inner: F) -> impl FnMut(&'a str) -> NomResult<'a, O>
162where
163    F: FnMut(&'a str) -> NomResult<'a, O>,
164{
165    move |input: &'a str| {
166        let (input, _) = unused0(input)?;
167        let (input, res) = inner(input)?;
168        let (input, _) = unused0(input)?;
169        Ok((input, res))
170    }
171}
172
173/// 包装 parser,自动跳过前方的空白或注释
174fn pre_unused<'a, F: 'a, O>(mut inner: F) -> impl FnMut(&'a str) -> NomResult<'a, O>
175where
176    F: FnMut(&'a str) -> NomResult<'a, O>,
177{
178    move |input: &'a str| {
179        let (input, _) = unused0(input)?;
180        let (input, res) = inner(input)?;
181        Ok((input, res))
182    }
183}
184
185// typical string
186// ie. abcdef, de234, jkl_mn, ...
187pub fn identifier(input: &str) -> NomResult<&str> {
188    context(
189        "identifier",
190        recognize(pair(
191            alt((alpha1, tag("_"))),
192            many0(alt((alphanumeric1, tag("_"), tag(".")))),
193        ))
194    )(input)
195}
196
197/// integer parser, supports sign like +42 or -3
198pub fn integer(input: &str) -> NomResult<i32> {
199    context(
200        "integer",
201        map_res(
202            tuple((
203                opt(one_of("+-")), // optional sign
204                digit1,            // digits
205            )),
206            |(sign, digits): (Option<char>, &str)| {
207                i32::from_str(digits).map(|n| match sign {
208                    Some('-') => -n,
209                    _ => n,
210                })
211            },
212        ),
213    )(input)
214}
215
216/// signed floating-point number parser
217pub fn float(input: &str) -> NomResult<f64> {
218    context(
219        "float",
220        double
221    )(input)
222}
223
224pub fn boolean(input: &str) -> NomResult<bool> {
225    map_res(alpha1, |s: &str| s.parse::<bool>())(input)
226}
227
228pub fn quoted_string(input: &str) -> NomResult<&str> {
229    context(
230        "quoted string",
231        preceded(char('\"'), cut(terminated(is_not("\""), char('\"')))),
232    )(input)
233}
234
235pub fn quoted_floats(input: &str) -> NomResult<Vec<f64>> {
236    context(
237        "quoted floats",
238        delimited(
239            pre_unused(char('"')), 
240            separated_list1(
241                pre_ws(char(',')),
242                pre_ws(float)
243            ),
244            pre_ws(char('"')), 
245        )
246    )(input)
247}
248
249pub fn ast_value(input: &str) -> NomResult<Value> {
250    context(
251        "ast value", 
252        alt((
253            map(boolean, Value::Bool),
254            map(float, Value::Float),
255            map(quoted_floats, Value::FloatGroup),
256            map(quoted_string, |s| Value::String(s.to_string())),
257            map(identifier, |s| Value::Ident(s.to_string())),
258        ))
259    )(input)
260}
261
262pub fn ast_values(input: &str) -> NomResult<Vec<Value>> {
263    context(
264        "ast values", 
265        delimited(
266            pre_unused(char('(')),
267            delimited(
268                opt(tuple((multispace0, char('\\'), line_ending))),
269                separated_list1(
270                    alt((
271                        map(
272                            tuple((multispace0, char(','), multispace0, char('\\'), line_ending)),
273                            |_| Some(1),
274                        ),
275                        map(tuple((multispace0, char(','))), |_| Some(1)),
276                        map(
277                            tuple((multispace0, char('\\'), line_ending, multispace0, char(','))),
278                            |_| Some(1),
279                        ),
280                    )),
281                    preceded(multispace0, ast_value),
282                ),
283                opt(tuple((multispace0, tag("\\"), line_ending))),
284            ),
285            pre_unused(char(')')),
286        )
287    )(input)
288}
289
290pub fn simple_attr(input: &str) -> NomResult<Ast> {
291    context(
292        "simple attr",
293        move |input| {
294            let (input, key) = pre_unused(identifier)(input)?;
295            let (input, _) = pre_unused(char(':'))(input)?;
296            let (input, value) = pre_unused(ast_value)(input).to_failure()?;
297            let (input, _) = pre_unused(char(';'))(input)?;
298
299            Ok((input, Ast::attr(key, value)))
300        }
301    )(input)
302}
303
304pub fn complex_attr(input: &str) -> NomResult<Ast> {
305    context(
306        "complex attr",
307        map(
308            tuple((
309                pre_unused(identifier),
310                pre_unused(ast_values),
311                pre_unused(char(';')),
312            )),
313
314            |(name, values, _)| Ast::attr(name, Value::Vec(values))
315        )
316    )(input)
317}
318
319pub fn attr(input: &str) -> NomResult<Ast> {
320    context(
321        "attr", 
322        alt((simple_attr, complex_attr))
323    )(input)
324}
325
326pub fn group(input: &str) -> NomResult<Ast> {
327    context(
328        "group",
329        move |input| {
330            let (input, kind) = pre_unused(identifier)(input)?;
331
332            let (input, params) = pre_unused(delimited(
333                pre_unused(char('(')),
334                separated_list0(
335                    pre_unused(tuple((multispace0, char(','), multispace0))),
336                    pre_unused(map(alt((identifier, quoted_string)), String::from)),
337                ),
338                pre_unused(char(')')),
339            ))(input)?;
340
341            let (input, _) = pre_unused(char('{'))(input)?;
342            let (input, items) = pre_unused(group_items0)(input).to_failure()?;
343            let (input, _) = pre_unused(char('}'))(input).to_failure()?;
344
345            Ok((input, Ast::group(kind, params, items)))
346        }
347    )(input)
348}
349
350pub fn group_items1(input: &str) -> NomResult<Vec<Ast>> {
351    context(
352        "group items1",
353        many1(pre_unused(ast))
354    )(input)
355}
356
357pub fn group_items0(input: &str) -> NomResult<Vec<Ast>> {
358    context(
359        "group items0",
360        many0(pre_unused(ast))
361    )(input)
362}
363
364#[allow(unused)]
365#[cfg(test)]
366mod tests {
367    use super::*;
368
369    #[test]
370    fn test_int() {
371        let res = integer("-1231 hhh").unwrap();
372        assert_eq!(res.0, " hhh");
373        assert_eq!(res.1, -1231);
374    }
375
376    #[test]
377    fn test_tstring() {
378        let res = identifier("hello world!").unwrap();
379        assert_eq!(res.0, " world!");
380        assert_eq!(res.1, "hello");
381    }
382
383    #[test]
384    fn test_ws0() {
385        let input = r#"
386            // 这是单行注释
387            /* 这是
388               多行注释 */
389            abc
390        "#;
391
392        // 我们用 ws0 跳过开头空白和注释,然后看看剩余输入
393        let res = unused0(input);
394        assert!(res.is_ok());
395        let (remaining, _) = res.unwrap();
396
397        // 剩下的应该是 "abc\n"
398        assert!(remaining.trim_start().starts_with("abc"));
399        println!("left: {:?}", remaining);
400    }
401
402    #[test]
403    fn test_hws_with_identifier() {
404        let input = r#"
405            // 注释
406            /* 多行
407               注释 */
408            my_var
409        "#;
410
411        let mut parser = pre_unused(identifier);
412        let res = parser(input);
413        assert!(res.is_ok());
414        let (remaining, id) = res.unwrap();
415        assert_eq!(id, "my_var");
416        println!("identifier: {:?}", id);
417        println!("left {:?}", remaining);
418    }
419
420    #[test]
421    fn test_quoted_floats() {
422        let input = r#"
423            "1.0, 2.0,    3.0"
424        "#;
425        let mut parser = wrap_unused(quoted_floats);
426        let res = parser(input);
427        assert!(res.is_ok());
428        let (remaining, values) = res.unwrap();
429        assert_eq!(values, vec![1.0, 2.0, 3.0]);
430    }
431
432    #[test]
433    fn test_quoted_string() {
434        let input = r#"
435            "hhh???"
436        "#;
437        let mut parser = wrap_unused(quoted_string);
438        let res = parser(input);
439        assert!(res.is_ok());
440        let (remaining, values) = res.unwrap();
441        assert_eq!(values, "hhh???");
442    }
443
444
445    #[test]
446    fn test_ast_values() {
447        assert_eq!(
448            ast_values(
449                r#"( \
450    "0, 0.18, 0.33", \
451    "-0.555, -0.45, -0.225" \
452    )"#
453            ),
454            Ok((
455                "",
456                vec![
457                    Value::FloatGroup(vec![0.0, 0.18, 0.33]),
458                    Value::FloatGroup(vec![-0.555, -0.45, -0.225]),
459                ]
460            ))
461        );
462        assert_eq!(
463            ast_values(
464                r#"( \
465                 "a string(b)" \
466                 )"#
467            ),
468            Ok(("", vec![Value::String("a string(b)".to_string())]))
469        );
470        assert_eq!(
471            ast_values("(123,-456)"),
472            Ok(("", vec![Value::Float(123.), Value::Float(-456.),]))
473        );
474    }
475
476
477    #[test]
478    fn test_attr() {
479        assert_eq!(
480            attr("capacitive_load_unit (1,pf);"),
481            Ok((
482                "",
483                Ast::Attr {
484                    key: "capacitive_load_unit".to_string(),
485                    value: Value::Vec(vec![Value::Float(1.), Value::Ident("pf".to_string()),]),
486                }
487            ))
488        );
489    }
490
491    #[test]
492    fn test_attr_multi_line() {
493        assert_eq!(
494            complex_attr(
495                r#"values ( \
496    "0, 0.18, 0.33", \
497    "-0.555, -0.45, -0.225");"#
498            ),
499            Ok((
500                "",
501                Ast::Attr {
502                    key: "values".to_string(),
503                    value: Value::Vec(vec![
504                        Value::FloatGroup(vec![0.0, 0.18, 0.33]),
505                        Value::FloatGroup(vec![-0.555, -0.45, -0.225]),
506                    ]),
507                }
508            ))
509        );
510    }
511
512    #[test]
513    fn test_comment() {
514        assert_eq!(
515            comment("/*** abc **/def"),
516            Ok(("def", "/*** abc **/"))
517        );
518        assert_eq!(
519            comment(
520                "/* multi
521line
522**
523**/
524**/rest"
525            ),
526            Ok((
527                "
528**/rest",
529                "/* multi
530line
531**
532**/"
533            ))
534        );
535    }
536
537    #[test]
538    fn test_attribute_malformed() {
539        assert!(attr("attr_name : a b ; ").is_err());
540    }
541
542    #[test]
543    fn test_attribute_bool() {
544        assert_eq!(
545            attr("attr_name : true ; "),
546            Ok((
547                " ",
548                Ast::Attr { key: String::from("attr_name"), value: Value::Bool(true), }
549            ))
550        );
551        assert_eq!(
552            attr("attr_name : false ; "),
553            Ok((
554                " ",
555                Ast::Attr { key: String::from("attr_name"), value: Value::Bool(false), }
556            ))
557        );
558    }
559
560    #[test]
561    fn test_attribute_float() {
562        assert_eq!(
563            attr("attr_name : 345.123 ; "),
564            Ok((
565                " ",
566                Ast::Attr{ key: String::from("attr_name"), value: Value::Float(345.123), }
567            ))
568        );
569        assert_eq!(
570            attr("attr_name : -345.123 ; "),
571            Ok((
572                " ",
573                Ast::Attr{ key: String::from("attr_name"), value: Value::Float(-345.123),}
574            ))
575        );
576    }
577
578
579    #[test]
580    fn test_parse_group() {
581        let data = "library ( foo ) {
582            abc ( 1, 2, 3 );
583        }";
584        match group(data) {
585            Err(_) => {
586                eprint!("e");
587            }
588            _ => {}
589        };
590        assert_eq!(
591            group(data),
592            Ok((
593                "",
594                Ast::Group {
595                    kind: "library".to_string(),
596                    params: vec!["foo".to_string()],
597                    items: vec![Ast::Attr {
598                        key: "abc".to_string(),
599                        value: Value::Vec(vec![
600                            Value::Float(1.0), Value::Float(2.0), Value::Float(3.0),
601                        ]),
602                    },],
603                },
604            ))
605        );
606    }
607
608
609    #[test]
610    fn test_nested_group() {
611        assert_eq!(
612            group(
613                r#"
614            outer( outer ) {
615                inner ( inner) {
616                    abc ( 1, 2, 3 );
617                }
618                inner(inner2 ) {
619                    abc ( 1, 2, 3 );
620                }
621            }"#
622            ),
623            Ok((
624                "",
625                Ast::group(
626                    "outer".to_string(),
627                    vec!["outer".to_string()],
628                    vec![
629                        Ast::group(
630                            "inner".to_string(),
631                            vec!["inner".to_string()],
632                            vec![Ast::attr(
633                                "abc".to_string(),
634                                Value::Vec(vec![Value::Float(1.0), Value::Float(2.0), Value::Float(3.0),]),
635                            ),],
636                        ),
637                        Ast::group(
638                            "inner".to_string(),
639                            vec!["inner2".to_string()],
640                            vec![Ast::attr(
641                                "abc".to_string(),
642                                Value::Vec(vec![Value::Float(1.0), Value::Float(2.0), Value::Float(3.0),]),
643                            ),],
644                        ),
645                    ]
646                )
647            ))
648        );
649    }
650
651    #[test]
652    fn test_lib_simple() {
653        let asts = parse_liberty(
654                r#"
655/*
656 delay model :       typ
657 check model :       typ
658 power model :       typ
659 capacitance model : typ
660 other model :       typ
661*/
662library(foo) {
663
664  delay_model : table_lookup;
665  /* unit attributes */
666  time_unit : "1ns";
667  capacitive_load_unit (1, pf );
668  function: "A & B";
669
670  slew_upper_threshold_pct_rise : 80;
671  nom_temperature : 25.0;
672}
673"#
674        ).unwrap();
675        assert_eq!(
676            asts,
677            Ast::group(
678                "library".to_string(),
679                vec!["foo".to_string()],
680                vec![
681                    Ast::attr(
682                        "delay_model".to_string(),
683                        Value::Ident("table_lookup".to_string())
684                    ),
685                    Ast::attr(
686                        "time_unit".to_string(),
687                        Value::String("1ns".to_string())
688                    ),
689                    Ast::attr(
690                        "capacitive_load_unit".to_string(),
691                        Value::Vec(vec![Value::Float(1.0), Value::Ident("pf".to_string()),]),
692                    ),
693                    Ast::attr(
694                        "function".to_string(),
695                        Value::String("A & B".to_string()),
696                    ),
697                    Ast::attr(
698                        "slew_upper_threshold_pct_rise".to_string(),
699                        Value::Float(80.0)
700                    ),
701                    Ast::attr("nom_temperature".to_string(), Value::Float(25.0)),
702                ],
703            ),
704        );
705    }
706}