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 preceded(multispace0, is_a("+-*/")),
49 preceded(
51 multispace0,
52 preceded(
53 opt(is_a("-")),
54 alt((
55 preceded(char('('), cut(terminated(expression, char(')')))),
57 underscore_tag,
59 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 unescape_line_continuations(s: &str) -> String {
89 if !s.contains('\\') {
90 return s.to_string();
91 }
92 let mut out = String::with_capacity(s.len());
93 let mut chars = s.chars().peekable();
94 while let Some(c) = chars.next() {
95 if c == '\\' {
96 let is_continuation = match chars.peek() {
99 Some('\n') => {
100 chars.next();
101 true
102 }
103 Some('\r') => {
104 let mut lookahead = chars.clone();
106 lookahead.next();
107 if lookahead.peek() == Some(&'\n') {
108 chars.next(); chars.next(); true
111 } else {
112 false
113 }
114 }
115 _ => false,
116 };
117 if is_continuation {
118 if out.ends_with(' ') {
120 out.pop();
121 }
122 out.push('\n');
123 while matches!(chars.peek(), Some(' ') | Some('\t')) {
125 chars.next();
126 }
127 } else {
128 out.push('\\');
131 }
132 } else {
133 out.push(c);
134 }
135 }
136 out
137}
138
139fn boolean<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, bool, E> {
140 map_res(alpha1, |s: &str| s.parse::<bool>())(input)
141}
142
143fn simple_attr_value<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, Value, E> {
144 context(
145 "simple attr value",
146 preceded(
147 multispace0,
148 alt((
149 map(quoted_floats, Value::FloatGroup),
150 map(quoted_string, |s| {
151 Value::String(unescape_line_continuations(s))
152 }),
153 map(terminated(double, peek(one_of(",; \t)"))), Value::Float),
154 map(boolean, Value::Bool),
155 map(map(expression, String::from), Value::Expression),
156 )),
157 ),
158 )(input)
159}
160
161fn simple_attribute<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, GroupItem, E> {
162 context(
163 "simple attr",
164 map(
165 tuple((
166 preceded(multispace0, underscore_tag),
167 preceded(multispace0, char(':')),
168 cut(preceded(multispace0, simple_attr_value)),
169 preceded(multispace0, char(';')),
170 )),
171 |(name, _, value, _)| GroupItem::SimpleAttr(name.to_string(), value),
172 ),
173 )(input)
174}
175
176fn complex_attribute_values<'a, E: ParseError<&'a str>>(
177 input: &'a str,
178) -> IResult<&'a str, Vec<Value>, E> {
179 context(
180 "complex values",
181 delimited(
182 preceded(multispace0, tag("(")),
183 delimited(
184 opt(tuple((multispace0, tag("\\"), line_ending))),
185 separated_list(
186 alt((
187 map(
188 tuple((multispace0, tag(","), multispace0, tag("\\"), line_ending)),
189 |_| Some(1),
190 ),
191 map(tuple((multispace0, tag(","))), |_| Some(1)),
192 map(
193 tuple((multispace0, tag("\\"), line_ending, multispace0, tag(","))),
194 |_| Some(1),
195 ),
196 )),
197 preceded(multispace0, simple_attr_value),
198 ),
199 opt(tuple((multispace0, tag("\\"), line_ending))),
200 ),
201 preceded(multispace0, tag(")")),
202 ),
203 )(input)
204}
205
206fn complex_attribute<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, GroupItem, E> {
207 context(
208 "complex attr",
209 map(
210 tuple((
211 preceded(multispace0, underscore_tag),
212 preceded(multispace0, complex_attribute_values),
213 preceded(multispace0, char(';')),
214 )),
215 |(name, value, _)| GroupItem::ComplexAttr(name.to_string(), value),
216 ),
217 )(input)
218}
219
220fn comment<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, &'a str, E> {
221 context(
222 "comment",
223 recognize(delimited(tag("/*"), take_until("*/"), tag("*/"))),
224 )(input)
225}
226
227fn parse_group_body<'a, E: ParseError<&'a str>>(
228 input: &'a str,
229) -> IResult<&'a str, Vec<GroupItem>, E> {
230 context(
231 "group body",
232 fold_many0(
233 context(
234 "folding items",
235 alt((
236 map(
237 map(preceded(multispace0, comment), String::from),
238 GroupItem::Comment,
239 ),
240 preceded(multispace0, parse_group),
241 preceded(multispace0, simple_attribute),
242 preceded(multispace0, complex_attribute),
243 )),
244 ),
245 Vec::new(),
246 |mut acc: Vec<_>, item| {
247 acc.push(item);
248 acc
249 },
250 ),
251 )(input)
252}
253fn parse_group<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, GroupItem, E> {
254 context(
255 "parsing group",
256 map(
257 tuple((
258 preceded(multispace0, underscore_tag),
259 preceded(
260 preceded(multispace0, char('(')),
261 terminated(
262 map(
263 separated_list(
264 preceded(multispace0, char(',')),
265 preceded(
266 multispace0,
267 alt((
268 map(quoted_string, |s| format!("\"{}\"", s)),
269 map(underscore_tag, |s| s.to_string()),
270 map(double, |s| format!("{}", GPoint(s))),
271 map(quoted_floats, |s| {
272 format!(
273 "\"{}\"",
274 s.into_iter()
275 .map(|f| format!("{}", GPoint(f)))
276 .format(",")
277 )
278 }),
279 )),
280 ),
281 ),
282 |vals: Vec<String>| vals.join(", "),
283 ),
284 preceded(multispace0, char(')')),
285 ),
286 ),
287 preceded(
288 preceded(multispace0, char('{')),
289 cut(terminated(
290 parse_group_body,
291 preceded(multispace0, char('}')),
292 )),
293 ),
294 )),
295 |(gtype, name, body)| GroupItem::Group(gtype.to_string(), name, body),
296 ),
297 )(input)
298}
299
300pub fn parse_libs<'a, E: ParseError<&'a str>>(
301 input: &'a str,
302) -> IResult<&'a str, Vec<GroupItem>, E> {
303 context(
304 "parse_libs",
305 all_consuming(terminated(
306 fold_many0(
307 alt((
308 context(
309 "outer comment",
310 map(
311 map(delimited(multispace0, comment, multispace0), String::from),
312 GroupItem::Comment,
313 ),
314 ),
315 preceded(multispace0, context("parse_lib", parse_group)),
316 )),
317 Vec::new(),
318 |mut acc: Vec<_>, item| {
319 match &item {
320 GroupItem::Group(_, _, _) => acc.push(item),
321 GroupItem::Comment(_) => {}
322 GroupItem::SimpleAttr(_, _) => {}
323 GroupItem::ComplexAttr(_, _) => {}
324 }
325 acc
326 },
327 ),
328 multispace0,
329 )),
330 )(input)
331}
332
333#[cfg(test)]
334mod tests {
335 use super::*;
336 use nom::{
337 error::{convert_error, ErrorKind, VerboseError},
338 Err,
339 };
340
341 #[test]
342 fn test_unescape_no_backslash_identity() {
343 assert_eq!(unescape_line_continuations("A , B , C"), "A , B , C");
344 assert_eq!(unescape_line_continuations(""), "");
345 }
346
347 #[test]
348 fn test_unescape_continuation_drops_indent() {
349 assert_eq!(
353 unescape_line_continuations("A , \\\n B"),
354 "A ,\nB"
355 );
356 }
357
358 #[test]
359 fn test_unescape_trailing_space_pops_at_most_one() {
360 assert_eq!(unescape_line_continuations("A , \\\n"), "A , \n");
363 }
364
365 #[test]
366 fn test_unescape_crlf_normalised() {
367 assert_eq!(
368 unescape_line_continuations("A , \\\r\n B"),
369 "A ,\nB"
370 );
371 }
372
373 #[test]
374 fn test_unescape_literal_backslash_mid_string_preserved() {
375 assert_eq!(unescape_line_continuations("a\\b"), "a\\b");
376 assert_eq!(unescape_line_continuations("a\\\rb"), "a\\\rb");
378 }
379
380 #[test]
381 fn test_unescape_backslash_at_end_preserved() {
382 assert_eq!(unescape_line_continuations("abc\\"), "abc\\");
383 }
384
385 #[test]
386 fn test_complex_attr_values() {
387 assert_eq!(
388 complex_attribute_values::<VerboseError<&str>>(
389 r#"( \
390 "0, 0.18, 0.33", \
391 "-0.555, -0.45, -0.225" \
392 )"#
393 ),
394 Ok((
395 "",
396 vec![
397 Value::FloatGroup(vec![0.0, 0.18, 0.33]),
398 Value::FloatGroup(vec![-0.555, -0.45, -0.225]),
399 ]
400 ))
401 );
402 assert_eq!(
403 complex_attribute_values::<VerboseError<&str>>(
404 r#"( \
405 "a string(b)" \
406 )"#
407 ),
408 Ok(("", vec![Value::String("a string(b)".to_string())]))
409 );
410 assert_eq!(
411 complex_attribute_values::<VerboseError<&str>>("(123,-456)"),
412 Ok(("", vec![Value::Float(123.0), Value::Float(-456.0),]))
413 );
414 }
415
416 #[test]
417 fn test_complex_attr() {
418 assert_eq!(
419 complex_attribute::<(&str, ErrorKind)>("capacitive_load_unit (1,pf);"),
420 Ok((
421 "",
422 GroupItem::ComplexAttr(
423 "capacitive_load_unit".to_string(),
424 vec![Value::Float(1.0), Value::Expression("pf".to_string()),],
425 )
426 ))
427 );
428 }
429
430 #[test]
431 fn test_complex_attr_multi_line() {
432 assert_eq!(
433 complex_attribute::<(&str, ErrorKind)>(
434 r#"values ( \
435 "0, 0.18, 0.33", \
436 "-0.555, -0.45, -0.225");"#
437 ),
438 Ok((
439 "",
440 GroupItem::ComplexAttr(
441 "values".to_string(),
442 vec![
443 Value::FloatGroup(vec![0.0, 0.18, 0.33]),
444 Value::FloatGroup(vec![-0.555, -0.45, -0.225]),
445 ],
446 )
447 ))
448 );
449 }
450
451 #[test]
452 fn test_comment() {
453 assert_eq!(
454 comment::<(&str, ErrorKind)>("/*** abc **/def"),
455 Ok(("def", "/*** abc **/"))
456 );
457 assert_eq!(
458 comment::<(&str, ErrorKind)>(
459 "/* multi
460line
461**
462**/
463**/rest"
464 ),
465 Ok((
466 "
467**/rest",
468 "/* multi
469line
470**
471**/"
472 ))
473 );
474 }
475
476 #[test]
477 fn test_underscore_tag() {
478 assert_eq!(
479 underscore_tag::<(&str, ErrorKind)>("a_b__c"),
480 Ok(("", "a_b__c"))
481 );
482 assert_eq!(
483 underscore_tag::<(&str, ErrorKind)>("abc other"),
484 Ok((" other", "abc"))
485 );
486 assert_eq!(
487 underscore_tag::<(&str, ErrorKind)>("nand2"),
488 Ok(("", "nand2"))
489 );
490 assert_eq!(
491 underscore_tag::<(&str, ErrorKind)>("_"),
492 Err(Err::Error(("_", ErrorKind::Alpha)))
493 );
494 assert_eq!(
495 underscore_tag::<(&str, ErrorKind)>(" a_b"),
496 Err(Err::Error((" a_b", ErrorKind::Alpha)))
497 );
498 assert_eq!(
499 underscore_tag::<(&str, ErrorKind)>(",,"),
500 Err(Err::Error((",,", ErrorKind::Alpha)))
501 );
502 }
503
504 #[test]
505 fn test_simple_attribute_malformed() {
506 assert_eq!(
507 simple_attribute::<(&str, ErrorKind)>("attr_name : a b ; "),
508 Err(Err::Error(("b ; ", ErrorKind::Char))),
509 );
510 }
511 #[test]
512 fn test_simple_attribute_bool() {
513 assert_eq!(
514 simple_attribute::<(&str, ErrorKind)>("attr_name : true ; "),
515 Ok((
516 " ",
517 GroupItem::SimpleAttr(String::from("attr_name"), Value::Bool(true),)
518 ))
519 );
520 assert_eq!(
521 simple_attribute::<(&str, ErrorKind)>("attr_name : false ; "),
522 Ok((
523 " ",
524 GroupItem::SimpleAttr(String::from("attr_name"), Value::Bool(false),)
525 ))
526 );
527 }
528 #[test]
529 fn test_simple_attribute_float() {
530 assert_eq!(
531 simple_attribute::<(&str, ErrorKind)>("attr_name : 345.123 ; "),
532 Ok((
533 " ",
534 GroupItem::SimpleAttr(String::from("attr_name"), Value::Float(345.123),)
535 ))
536 );
537 assert_eq!(
538 simple_attribute::<(&str, ErrorKind)>("attr_name : -345.123 ; "),
539 Ok((
540 " ",
541 GroupItem::SimpleAttr(String::from("attr_name"), Value::Float(-345.123),)
542 ))
543 );
544 }
545 #[test]
546 fn test_simple_attribute_int() {
547 assert_eq!(
548 simple_attribute::<(&str, ErrorKind)>("attr_name : 345 ; "),
549 Ok((
550 " ",
551 GroupItem::SimpleAttr(String::from("attr_name"), Value::Float(345.0),)
552 ))
553 );
554 assert_eq!(
555 simple_attribute::<(&str, ErrorKind)>("attr_name : -345 ; "),
556 Ok((
557 " ",
558 GroupItem::SimpleAttr(String::from("attr_name"), Value::Float(-345.0),)
559 ))
560 );
561 }
562
563 #[test]
564 fn test_expression() {
565 let expressions = vec![
566 "A",
567 "-A",
568 "--A",
569 "A + B",
570 "A - B",
571 "A * B",
572 "A / B",
573 "(A + B)",
574 "((A + B))",
575 "(A / B) + C",
576 "(A / B) - (C * D)",
577 "A + 0.123",
579 "A - .123",
580 "A * 0",
581 "A / 1",
582 "(A + 0.5)",
583 "((1.23 + B))",
584 "(4.5 / B) + C",
585 "(7.8 / B) - (C * D)",
586 ];
587 for expr in expressions {
588 assert_eq!(expression::<(&str, ErrorKind)>(expr), Ok(("", expr)));
589 }
590 }
591
592 #[test]
593 fn test_simple_attribute_expression() {
594 assert_eq!(
595 simple_attribute::<(&str, ErrorKind)>("attr_name : nand2; "),
596 Ok((
597 " ",
598 GroupItem::SimpleAttr(
599 String::from("attr_name"),
600 Value::Expression(String::from("nand2")),
601 )
602 ))
603 );
604 assert_eq!(
605 simple_attribute::<(&str, ErrorKind)>("attr_name : table_lookup; "),
606 Ok((
607 " ",
608 GroupItem::SimpleAttr(
609 String::from("attr_name"),
610 Value::Expression(String::from("table_lookup")),
611 )
612 ))
613 );
614 let data = "attr_name : A +B; ";
615 match simple_attribute::<VerboseError<&str>>(data) {
616 Err(Err::Error(err)) | Err(Err::Failure(err)) => {
617 println!("Error: {}", convert_error(data, err));
618 assert_eq!(true, false);
619 }
620 _ => {}
621 }
622 assert_eq!(
623 simple_attribute::<(&str, ErrorKind)>("attr_name : A + 1.2; "),
624 Ok((
625 " ",
626 GroupItem::SimpleAttr(
627 String::from("attr_name"),
628 Value::Expression(String::from("A + 1.2")),
629 )
630 ))
631 );
632 }
633
634 #[test]
635 fn test_simple_attribute_string() {
636 assert_eq!(
637 simple_attribute::<(&str, ErrorKind)>("attr_name : \"table_lookup\"; "),
638 Ok((
639 " ",
640 GroupItem::SimpleAttr(
641 String::from("attr_name"),
642 Value::String(String::from("table_lookup"))
643 )
644 ))
645 );
646 }
647
648 #[test]
649 fn test_parse_group() {
650 let data = "library ( foo ) {
651 abc ( 1, 2, 3 );
652 }";
653 match parse_group::<VerboseError<&str>>(data) {
654 Err(Err::Error(err)) | Err(Err::Failure(err)) => {
655 println!("Error: {}", convert_error(data, err));
656 assert_eq!(true, false);
657 }
658 _ => {}
659 };
660 assert_eq!(
661 parse_group::<(&str, ErrorKind)>(data),
662 Ok((
663 "",
664 GroupItem::Group(
665 "library".to_string(),
666 "foo".to_string(),
667 vec![GroupItem::ComplexAttr(
668 "abc".to_string(),
669 vec![Value::Float(1.0), Value::Float(2.0), Value::Float(3.0),],
670 ),],
671 ),
672 ))
673 );
674 }
675
676 #[test]
677 fn test_nested_group() {
678 assert_eq!(
679 parse_group::<(&str, ErrorKind)>(
680 r#"
681 outer( outer ) {
682 inner ( inner) {
683 abc ( 1, 2, 3 );
684 }
685 inner(inner2 ) {
686 abc ( 1, 2, 3 );
687 }
688 }"#
689 ),
690 Ok((
691 "",
692 GroupItem::Group(
693 "outer".to_string(),
694 "outer".to_string(),
695 vec![
696 GroupItem::Group(
697 "inner".to_string(),
698 "inner".to_string(),
699 vec![GroupItem::ComplexAttr(
700 "abc".to_string(),
701 vec![Value::Float(1.0), Value::Float(2.0), Value::Float(3.0),],
702 ),],
703 ),
704 GroupItem::Group(
705 "inner".to_string(),
706 "inner2".to_string(),
707 vec![GroupItem::ComplexAttr(
708 "abc".to_string(),
709 vec![Value::Float(1.0), Value::Float(2.0), Value::Float(3.0),],
710 ),],
711 ),
712 ]
713 )
714 ))
715 );
716 }
717
718 #[test]
719 fn test_lib_simple() {
720 assert_eq!(
721 parse_libs::<(&str, ErrorKind)>(
722 r#"
723/*
724 delay model : typ
725 check model : typ
726 power model : typ
727 capacitance model : typ
728 other model : typ
729*/
730library(foo) {
731
732 delay_model : table_lookup;
733 /* unit attributes */
734 time_unit : "1ns";
735 capacitive_load_unit (1, pf );
736 function: "A & B";
737
738 slew_upper_threshold_pct_rise : 80;
739 nom_temperature : 25.0;
740}
741"#
742 ),
743 Ok((
744 "",
745 vec![GroupItem::Group(
746 "library".to_string(),
747 "foo".to_string(),
748 vec![
749 GroupItem::SimpleAttr(
750 "delay_model".to_string(),
751 Value::Expression("table_lookup".to_string())
752 ),
753 GroupItem::Comment("/* unit attributes */".to_string()),
754 GroupItem::SimpleAttr(
755 "time_unit".to_string(),
756 Value::String("1ns".to_string())
757 ),
758 GroupItem::ComplexAttr(
759 "capacitive_load_unit".to_string(),
760 vec![Value::Float(1.0), Value::Expression("pf".to_string()),],
761 ),
762 GroupItem::SimpleAttr(
763 "function".to_string(),
764 Value::String("A & B".to_string()),
765 ),
766 GroupItem::SimpleAttr(
767 "slew_upper_threshold_pct_rise".to_string(),
768 Value::Float(80.0)
769 ),
770 GroupItem::SimpleAttr("nom_temperature".to_string(), Value::Float(25.0)),
771 ],
772 ),]
773 ))
774 );
775 }
776}