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
17pub 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 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
93fn line_comment(input: &str) -> NomResult<()> {
95 value(
96 (),
97 preceded(tag("//"), alt((not_line_ending, eof))),
98 )(input)
99}
100
101fn 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
114fn ws0(input: &str) -> NomResult<()> {
116 value(
117 (),
118 many0(value((), multispace1)),
119 )(input)
120}
121
122fn unused0(input: &str) -> NomResult<()> {
124 value(
125 (),
126 many0(alt((
127 value((), multispace1), line_comment,
129 block_comment,
130 ))),
131 )(input)
132}
133
134#[allow(unused)]
135fn 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
148fn 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
160fn 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
173fn 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
185pub 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
197pub fn integer(input: &str) -> NomResult<i32> {
199 context(
200 "integer",
201 map_res(
202 tuple((
203 opt(one_of("+-")), digit1, )),
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
216pub 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 let res = unused0(input);
394 assert!(res.is_ok());
395 let (remaining, _) = res.unwrap();
396
397 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}