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 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 "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}