1use std::collections::{HashMap, HashSet};
9use std::fmt;
10use std::io::{BufRead, BufReader, Read};
11use string_interner::symbol::SymbolU32;
12use string_interner::{StringInterner, backend::StringBackend};
13use xlsynth::IrBits;
14
15pub type PortId = SymbolU32;
16pub type NetId = SymbolU32;
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19pub struct NetIndex(pub usize);
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23pub struct InstIndex(pub usize);
24
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct Net {
27 pub name: NetId,
28 pub width: Option<(u32, u32)>,
30}
31
32impl Net {
33 pub fn width_bits(&self) -> usize {
35 if let Some((msb, lsb)) = self.width {
36 (u32::abs_diff(msb, lsb) as usize) + 1
37 } else {
38 1
39 }
40 }
41
42 pub fn declared_lsb_number(&self) -> u32 {
44 self.width.map(|(_, lsb)| lsb).unwrap_or(0)
45 }
46
47 pub fn bit_offset(&self, bit_number: u32) -> Option<usize> {
50 match self.width {
51 Some((msb, lsb)) => {
52 let min_bit = msb.min(lsb);
53 let max_bit = msb.max(lsb);
54 if bit_number < min_bit || bit_number > max_bit {
55 None
56 } else {
57 Some(u32::abs_diff(bit_number, lsb) as usize)
58 }
59 }
60 None => {
61 if bit_number == 0 {
62 Some(0)
63 } else {
64 None
65 }
66 }
67 }
68 }
69
70 pub fn bit_number(&self, bit_offset: usize) -> Option<u32> {
72 if bit_offset >= self.width_bits() {
73 return None;
74 }
75 match self.width {
76 Some((msb, lsb)) => {
77 let offset = bit_offset as u32;
78 if msb >= lsb {
79 Some(lsb + offset)
80 } else {
81 Some(lsb - offset)
82 }
83 }
84 None => Some(0),
85 }
86 }
87}
88
89#[derive(Debug, Clone, PartialEq, Eq)]
90pub struct NetlistPort {
91 pub direction: PortDirection,
92 pub width: Option<(u32, u32)>, pub name: PortId,
94}
95
96#[derive(Debug, Clone, PartialEq, Eq)]
108pub struct NetlistModule {
109 pub name: PortId,
110 pub net_index_range: std::ops::Range<usize>,
112 pub ports: Vec<NetlistPort>,
113 pub wires: Vec<NetIndex>,
114 pub assigns: Vec<NetlistAssign>,
115 pub instances: Vec<NetlistInstance>,
116}
117
118impl NetlistModule {
119 pub fn find_net_index(&self, net_name: NetId, nets: &[Net]) -> Option<NetIndex> {
121 nets[self.net_index_range.clone()]
122 .iter()
123 .position(|net| net.name == net_name)
124 .map(|offset| NetIndex(self.net_index_range.start + offset))
125 }
126}
127
128#[derive(Debug, Clone, PartialEq, Eq)]
129pub enum NetRef {
130 Simple(NetIndex),
131 BitSelect(NetIndex, u32), PartSelect(NetIndex, u32, u32), Literal(IrBits),
134 UnknownLiteral(usize),
135 Unconnected,
136 Concat(Vec<NetRef>), }
138
139impl NetRef {
140 pub fn collect_net_indices(&self, out: &mut Vec<NetIndex>) {
142 match self {
143 NetRef::Simple(idx) | NetRef::BitSelect(idx, _) | NetRef::PartSelect(idx, _, _) => {
144 out.push(*idx);
145 }
146 NetRef::Concat(elems) => {
147 for e in elems {
148 e.collect_net_indices(out);
149 }
150 }
151 NetRef::Literal(_) | NetRef::UnknownLiteral(_) | NetRef::Unconnected => {}
152 }
153 }
154}
155
156#[derive(Debug, Clone, PartialEq, Eq)]
161pub enum AssignExpr {
162 Leaf(NetRef),
163 Not(Box<AssignExpr>),
164 And(Box<AssignExpr>, Box<AssignExpr>),
165 Or(Box<AssignExpr>, Box<AssignExpr>),
166 Xor(Box<AssignExpr>, Box<AssignExpr>),
167}
168
169impl AssignExpr {
170 pub fn collect_net_indices(&self, out: &mut Vec<NetIndex>) {
173 match self {
174 AssignExpr::Leaf(net_ref) => net_ref.collect_net_indices(out),
175 AssignExpr::Not(inner) => inner.collect_net_indices(out),
176 AssignExpr::And(lhs, rhs) | AssignExpr::Or(lhs, rhs) | AssignExpr::Xor(lhs, rhs) => {
177 lhs.collect_net_indices(out);
178 rhs.collect_net_indices(out);
179 }
180 }
181 }
182}
183
184#[derive(Debug, Clone, PartialEq, Eq)]
186pub struct NetlistAssign {
187 pub kind: NetlistAssignKind,
188 pub lhs: NetRef,
189 pub rhs: AssignExpr,
190 pub span: Span,
191}
192
193#[derive(Debug, Clone, Copy, PartialEq, Eq)]
195pub enum NetlistAssignKind {
196 Continuous,
197 Tran,
198}
199
200#[derive(Debug, Clone, PartialEq, Eq)]
201pub struct NetlistInstance {
202 pub type_name: PortId,
203 pub instance_name: PortId,
204 pub connections: Vec<(PortId, NetRef)>, pub inst_lineno: u32,
206 pub inst_colno: u32,
207}
208
209#[derive(Debug, Clone, PartialEq, Eq)]
210pub enum Keyword {
211 Wire,
212 Module,
213 Endmodule,
214 Input,
215 Output,
216 Inout,
217}
218
219#[derive(Debug, Clone, PartialEq, Eq)]
220pub enum PortDirection {
221 Input,
222 Output,
223 Inout,
224}
225
226#[derive(Debug, Clone, PartialEq, Eq)]
227pub enum AnnotationValue {
228 I64(i64),
229 String(String),
230 VerilogInt { width: Option<usize>, value: IrBits },
231}
232
233#[derive(Debug, Clone, PartialEq, Eq)]
234pub enum TokenPayload {
235 Identifier(String),
236 Keyword(Keyword),
237 OParen,
238 CParen,
239 OBrack,
240 CBrack,
241 OBrace,
242 CBrace,
243 Colon,
244 Semi,
245 Comma,
246 Dot,
247 Equals,
248 Tilde,
249 Ampersand,
250 Pipe,
251 Caret,
252 Comment(String),
253 Annotation { key: String, value: AnnotationValue },
254 VerilogInt { width: Option<usize>, value: IrBits },
255 VerilogUnknownInt { width: Option<usize> },
256}
257
258fn is_simple_identifier(s: &str) -> bool {
259 let mut chars = s.chars();
260 match chars.next() {
261 Some(c) if c.is_ascii_alphabetic() || c == '_' => {}
262 _ => return false,
263 }
264 chars.all(|c| c.is_ascii_alphanumeric() || c == '_')
265}
266
267impl fmt::Display for AnnotationValue {
268 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
269 match self {
270 AnnotationValue::I64(i) => write!(f, "{}", i),
271 AnnotationValue::String(s) => {
272 let s = s.replace('"', "");
274 write!(f, "\"{}\"", s)
275 }
276 AnnotationValue::VerilogInt { width, value } => {
277 let v = xlsynth::IrValue::from_bits(value).to_u32().unwrap();
278 match width {
279 Some(w) => write!(f, "{}'d{}", w, v),
280 None => write!(f, "{}", v),
281 }
282 }
283 }
284 }
285}
286
287impl fmt::Display for TokenPayload {
288 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289 match self {
290 TokenPayload::Identifier(s) => {
291 if is_simple_identifier(s) {
292 write!(f, "{}", s)
293 } else {
294 write!(f, "\\{} ", s)
296 }
297 }
298 TokenPayload::Keyword(Keyword::Module) => write!(f, "module"),
299 TokenPayload::Keyword(Keyword::Wire) => write!(f, "wire"),
300 TokenPayload::Keyword(Keyword::Endmodule) => write!(f, "endmodule"),
301 TokenPayload::Keyword(Keyword::Input) => write!(f, "input"),
302 TokenPayload::Keyword(Keyword::Output) => write!(f, "output"),
303 TokenPayload::Keyword(Keyword::Inout) => write!(f, "inout"),
304 TokenPayload::OParen => write!(f, "("),
305 TokenPayload::CParen => write!(f, ")"),
306 TokenPayload::OBrack => write!(f, "["),
307 TokenPayload::CBrack => write!(f, "]"),
308 TokenPayload::OBrace => write!(f, "{{"),
309 TokenPayload::CBrace => write!(f, "}}"),
310 TokenPayload::Colon => write!(f, ":"),
311 TokenPayload::Semi => write!(f, ";"),
312 TokenPayload::Comma => write!(f, ","),
313 TokenPayload::Dot => write!(f, "."),
314 TokenPayload::Equals => write!(f, "="),
315 TokenPayload::Tilde => write!(f, "~"),
316 TokenPayload::Ampersand => write!(f, "&"),
317 TokenPayload::Pipe => write!(f, "|"),
318 TokenPayload::Caret => write!(f, "^"),
319 TokenPayload::Comment(s) => write!(f, "//{}\n", s.replace('\n', " ")),
320 TokenPayload::Annotation { key, value } => {
321 write!(f, "(* {} = {} *)", key, value)
322 }
323 TokenPayload::VerilogInt { width, value } => {
324 let v = xlsynth::IrValue::from_bits(value).to_u32().unwrap();
325 match width {
326 Some(w) => write!(f, "{}'d{}", w, v),
327 None => write!(f, "{}", v),
328 }
329 }
330 TokenPayload::VerilogUnknownInt { width } => match width {
331 Some(w) => write!(f, "{}'hx", w),
332 None => write!(f, "'hx"),
333 },
334 }
335 }
336}
337
338#[derive(Debug, Clone, Copy, PartialEq, Eq)]
339pub struct Pos {
340 pub lineno: u32,
341 pub colno: u32,
342}
343
344#[derive(Debug, Clone, Copy, PartialEq, Eq)]
345pub struct Span {
346 pub start: Pos,
347 pub limit: Pos,
348}
349
350impl Span {
351 pub fn to_human_string(&self) -> String {
352 format!(
353 "{}:{}..{}:{}",
354 self.start.lineno, self.start.colno, self.limit.lineno, self.limit.colno
355 )
356 }
357}
358
359#[derive(Debug, Clone, PartialEq, Eq)]
360pub struct Token {
361 pub payload: TokenPayload,
362 pub span: Span,
363}
364
365#[derive(Debug)]
366pub struct ScanError {
367 pub message: String,
368 pub span: Span,
369}
370
371pub struct TokenScanner<R: Read + 'static> {
372 reader: BufReader<R>,
373 pub pos: Pos,
374 lookahead: Option<Token>,
375 done: bool,
376 line_lookup: Box<dyn Fn(u32) -> Option<String>>, }
378
379impl<R: Read + 'static> TokenScanner<R> {
380 pub fn with_line_lookup(reader: R, line_lookup: Box<dyn Fn(u32) -> Option<String>>) -> Self {
382 Self {
383 reader: BufReader::new(reader),
384 pos: Pos {
385 lineno: 1,
386 colno: 1,
387 },
388 lookahead: None,
389 done: false,
390 line_lookup,
391 }
392 }
393
394 pub fn from_file_with_path(reader: R, path: std::path::PathBuf) -> Self {
397 let path_clone = path.clone();
398 Self::with_line_lookup(
399 reader,
400 Box::new(move |lineno| {
401 use std::io::{BufRead, BufReader};
402 let file = std::fs::File::open(&path_clone).ok()?;
403 let reader = BufReader::new(file);
404 reader
405 .lines()
406 .nth((lineno - 1) as usize)
407 .and_then(Result::ok)
408 }),
409 )
410 }
411}
412
413impl<'a> TokenScanner<std::io::Cursor<&'a [u8]>> {
414 pub fn from_str(input: &'a str) -> Self {
417 let lines: Vec<String> = input.lines().map(|s| s.to_string()).collect();
418 let lookup = move |lineno: u32| lines.get((lineno - 1) as usize).cloned();
419 Self::with_line_lookup(std::io::Cursor::new(input.as_bytes()), Box::new(lookup))
420 }
421}
422
423impl<R: Read + 'static> TokenScanner<R> {
424 #[inline]
425 fn peekb(&mut self) -> Option<u8> {
426 if self.done {
427 return None;
428 }
429 match self.reader.fill_buf() {
430 Ok(buf) => buf.first().copied(),
431 Err(_) => {
432 self.done = true;
433 None
434 }
435 }
436 }
437
438 #[inline]
439 fn popb(&mut self) -> Option<u8> {
440 if self.done {
441 return None;
442 }
443 match self.reader.fill_buf() {
444 Ok(buf) => {
445 if let Some(&b) = buf.first() {
446 if b == b'\n' {
447 self.pos.lineno += 1;
448 self.pos.colno = 1;
449 } else {
450 self.pos.colno += 1;
451 }
452 self.reader.consume(1);
454 Some(b)
455 } else {
456 self.done = true;
457 None
458 }
459 }
460 Err(_) => {
461 self.done = true;
462 None
463 }
464 }
465 }
466
467 pub fn peekt(&mut self) -> Result<Option<&Token>, ScanError> {
468 if self.lookahead.is_none() && !self.done {
469 self.lookahead = self.next_token()?;
470 }
471 Ok(self.lookahead.as_ref())
472 }
473
474 pub fn popt(&mut self) -> Result<Option<Token>, ScanError> {
475 if self.lookahead.is_none() && !self.done {
476 self.lookahead = self.next_token()?;
477 }
478 Ok(self.lookahead.take())
479 }
480
481 pub fn pop_identifier_or_error(&mut self) -> Result<Token, ScanError> {
482 match self.popt()? {
483 Some(tok) => match &tok.payload {
484 TokenPayload::Identifier(_) => Ok(tok),
485 _ => Err(ScanError {
486 message: "Expected identifier".to_string(),
487 span: tok.span,
488 }),
489 },
490 None => Err(ScanError {
491 message: "Unexpected EOF, expected identifier".to_string(),
492 span: Span {
493 start: self.pos,
494 limit: self.pos,
495 },
496 }),
497 }
498 }
499
500 pub fn pop_i64_or_error(&mut self) -> Result<i64, ScanError> {
501 match self.popt()? {
502 Some(tok) => match &tok.payload {
503 TokenPayload::Annotation {
504 value: AnnotationValue::I64(i),
505 ..
506 } => Ok(*i),
507 _ => Err(ScanError {
508 message: "Expected integer value".to_string(),
509 span: tok.span,
510 }),
511 },
512 None => Err(ScanError {
513 message: "Unexpected EOF, expected integer value".to_string(),
514 span: Span {
515 start: self.pos,
516 limit: self.pos,
517 },
518 }),
519 }
520 }
521
522 fn error_with_context(&self, msg: &str, span: Span) -> ScanError {
523 let line = (self.line_lookup)(span.start.lineno)
524 .unwrap_or_else(|| "<line unavailable>".to_string());
525 let col = (span.start.colno as usize).saturating_sub(1);
526 log::error!("ScanError: {} @ {}", msg, span.to_human_string());
527 log::error!("{}", line);
528 log::error!("{}^", " ".repeat(col));
529 ScanError {
530 message: format!("{}", msg),
531 span,
532 }
533 }
534
535 fn pop_annotation(&mut self, start: Pos) -> Result<Token, ScanError> {
536 assert_eq!(self.popb(), Some(b'('));
538 assert_eq!(self.popb(), Some(b'*'));
539 while let Some(b) = self.peekb() {
541 let c = b as char;
542 if c.is_whitespace() {
543 self.popb();
544 } else {
545 break;
546 }
547 }
548 let mut key = String::new();
550 while let Some(b) = self.peekb() {
551 let c = b as char;
552 if c.is_alphanumeric() || c == '_' {
553 self.popb();
554 key.push(c);
555 } else {
556 break;
557 }
558 }
559 while let Some(b) = self.peekb() {
561 let c = b as char;
562 if c.is_whitespace() {
563 self.popb();
564 } else {
565 break;
566 }
567 }
568 assert_eq!(self.popb(), Some(b'='));
570 while let Some(b) = self.peekb() {
572 let c = b as char;
573 if c.is_whitespace() {
574 self.popb();
575 } else {
576 break;
577 }
578 }
579 let value: AnnotationValue = match self.peekb() {
581 Some(b'"') => {
582 self.popb(); let mut s = String::new();
584 while let Some(b) = self.popb() {
585 let c = b as char;
586 if c == '"' {
587 break;
588 }
589 s.push(c);
590 }
591 AnnotationValue::String(s)
592 }
593 Some(b) if (b as char).is_ascii_digit() => {
594 let mut num = String::new();
596 while let Some(b2) = self.peekb() {
597 if (b2 as char).is_ascii_digit() {
598 self.popb();
599 num.push(b2 as char);
600 } else {
601 break;
602 }
603 }
604 let width = if !num.is_empty() {
605 Some(num.parse::<usize>().unwrap())
606 } else {
607 None
608 };
609 if self.peekb() == Some(b'\'') {
610 self.popb(); let mut base_and_value = String::new();
613 while let Some(b2) = self.peekb() {
614 let c2 = b2 as char;
615 if c2.is_whitespace() || c2 == '*' || c2 == ')' {
616 break;
617 }
618 self.popb();
619 base_and_value.push(c2);
620 }
621 let base_and_value = if let Some((_base, _rest)) = base_and_value
623 .split_once(|c: char| c == 'b' || c == 'h' || c == 'o' || c == 'd')
624 {
625 let (base_char, _value_str) = base_and_value.split_at(1);
626 let prefix = match base_char {
627 "b" => "0b",
628 "h" => "0x",
629 "o" => "0o",
630 "d" => "",
631 _ => "",
632 };
633 format!("{}{}", prefix, &base_and_value[1..])
634 } else {
635 base_and_value.clone()
636 };
637 let irbits_str = if let Some(width) = width {
638 format!("bits[{}]:{}", width, base_and_value)
639 } else {
640 base_and_value.clone()
641 };
642 let value = xlsynth::IrValue::parse_typed(&irbits_str)
643 .unwrap()
644 .to_bits()
645 .unwrap();
646 while let Some(b2) = self.peekb() {
648 let c2 = b2 as char;
649 if c2.is_whitespace() {
650 self.popb();
651 } else {
652 break;
653 }
654 }
655 if self.popb() != Some(b'*') {
657 return Err(self.error_with_context(
658 "Expected '*' to close annotation",
659 Span {
660 start,
661 limit: self.pos,
662 },
663 ));
664 }
665 if self.popb() != Some(b')') {
666 return Err(self.error_with_context(
667 "Expected ')' to close annotation",
668 Span {
669 start,
670 limit: self.pos,
671 },
672 ));
673 }
674 let limit = self.pos;
675 return Ok(Token {
676 payload: TokenPayload::Annotation {
677 key,
678 value: AnnotationValue::VerilogInt { width, value },
679 },
680 span: Span { start, limit },
681 });
682 } else {
683 AnnotationValue::I64(num.parse().unwrap())
685 }
686 }
687 Some(b) if b == b'-' => {
688 let mut num = String::new();
689 num.push('-');
690 while let Some(b2) = self.peekb() {
691 if (b2 as char).is_ascii_digit() {
692 self.popb();
693 num.push(b2 as char);
694 } else {
695 break;
696 }
697 }
698 AnnotationValue::I64(num.parse().unwrap())
699 }
700 _ => {
701 return Err(self.error_with_context(
702 "Expected annotation value",
703 Span {
704 start,
705 limit: self.pos,
706 },
707 ));
708 }
709 };
710 while let Some(b) = self.peekb() {
712 let c = b as char;
713 if c.is_whitespace() {
714 self.popb();
715 } else {
716 break;
717 }
718 }
719 if self.popb() != Some(b'*') {
721 return Err(self.error_with_context(
722 "Expected '*' to close annotation",
723 Span {
724 start,
725 limit: self.pos,
726 },
727 ));
728 }
729 if self.popb() != Some(b')') {
730 return Err(self.error_with_context(
731 "Expected ')' to close annotation",
732 Span {
733 start,
734 limit: self.pos,
735 },
736 ));
737 }
738 let limit = self.pos;
739 Ok(Token {
740 payload: TokenPayload::Annotation { key, value },
741 span: Span { start, limit },
742 })
743 }
744
745 fn pop_identifier(&mut self, start: Pos) -> Token {
746 let mut ident = String::new();
747 let mut escaped = false;
748 if self.peekb() == Some(b'\\') {
750 escaped = true;
751 self.popb(); while let Some(b) = self.peekb() {
754 let c = b as char;
755 if c.is_whitespace() {
756 self.popb();
758 break;
759 }
760 self.popb();
761 ident.push(c);
762 }
763 } else {
764 loop {
768 if self.done {
769 break;
770 }
771 match self.reader.fill_buf() {
772 Ok(buf) => {
773 if buf.is_empty() {
774 self.done = true;
775 break;
776 }
777 let mut consumed = 0usize;
778 for &b in buf {
779 let c = b as char;
780 if c.is_alphanumeric() || c == '_' {
781 ident.push(c);
782 consumed += 1;
783 } else {
784 break;
785 }
786 }
787 if consumed == 0 {
788 break;
791 }
792 self.pos.colno += consumed as u32;
795 self.reader.consume(consumed);
796 }
797 Err(_) => {
798 self.done = true;
799 break;
800 }
801 }
802 }
803 }
804 let limit = self.pos;
805 if !escaped {
806 if let Some(kw) = Keyword::from_str(&ident) {
807 return Token {
808 payload: TokenPayload::Keyword(kw),
809 span: Span { start, limit },
810 };
811 }
812 }
813 Token {
814 payload: TokenPayload::Identifier(ident),
815 span: Span { start, limit },
816 }
817 }
818
819 pub fn next_token(&mut self) -> Result<Option<Token>, ScanError> {
820 loop {
822 match self.peekb() {
823 Some(b) if b.is_ascii_whitespace() && b != b'\n' => {
824 self.popb();
825 }
826 _ => break,
827 }
828 }
829 let start = self.pos;
830 let b = match self.peekb() {
831 Some(b) => b,
832 None => return Ok(None),
833 };
834 if b == b'`' {
839 let directive_start = start;
840 self.popb();
842 let mut word = String::new();
844 while let Some(b2) = self.peekb() {
845 let c2 = b2 as char;
846 if c2.is_ascii_alphabetic() || c2 == '_' {
847 self.popb();
848 word.push(c2);
849 } else {
850 break;
851 }
852 }
853 if word == "timescale" {
854 while let Some(b2) = self.popb() {
856 if b2 == b'\n' {
857 break;
858 }
859 }
860 log::trace!("TokenScanner: skipped `timescale directive line");
861 return match self.next_token()? {
863 Some(tok) => Ok(Some(tok)),
864 None => Ok(None),
865 };
866 } else {
867 return Err(self.error_with_context(
869 "Unexpected character '`'",
870 Span {
871 start: directive_start,
872 limit: directive_start,
873 },
874 ));
875 }
876 }
877 if b == b'(' {
879 if let Ok(buf) = self.reader.fill_buf() {
880 if buf.len() >= 2 && buf[0] == b'(' && buf[1] == b'*' {
881 return self.pop_annotation(start).map(Some);
882 }
883 }
884 }
885 if b.is_ascii_alphabetic() || b == b'_' || b == b'\\' {
889 return Ok(Some(self.pop_identifier(start)));
890 }
891 if b.is_ascii_digit() {
893 let mut num = String::new();
894 while let Some(b2) = self.peekb() {
895 if b2.is_ascii_digit() {
896 self.popb();
897 num.push(b2 as char);
898 } else {
899 break;
900 }
901 }
902 let width = if !num.is_empty() {
903 Some(num.parse::<usize>().unwrap())
904 } else {
905 None
906 };
907 if self.peekb() == Some(b'\'') {
908 self.popb(); let mut base_and_value = String::new();
915 while let Some(b2) = self.peekb() {
916 if b2.is_ascii_alphanumeric()
917 || b2 == b'_'
918 || b2 == b'x'
919 || b2 == b'X'
920 || b2 == b'z'
921 || b2 == b'Z'
922 || b2 == b'?'
923 {
924 self.popb();
925 base_and_value.push(b2 as char);
926 } else {
927 break;
928 }
929 }
930 let has_unknown_digit = base_and_value
931 .chars()
932 .skip(1)
933 .any(|ch| matches!(ch, 'x' | 'X' | 'z' | 'Z' | '?'));
934 let base_and_value = if let Some((_base, _rest)) = base_and_value
936 .split_once(|c: char| c == 'b' || c == 'h' || c == 'o' || c == 'd')
937 {
938 let (base_char, _value_str) = base_and_value.split_at(1);
939 let prefix = match base_char {
940 "b" => "0b",
941 "h" => "0x",
942 "o" => "0o",
943 "d" => "",
944 _ => "",
945 };
946 format!("{}{}", prefix, &base_and_value[1..])
947 } else {
948 base_and_value.clone()
949 };
950 let irbits_str = if let Some(width) = width {
951 format!("bits[{}]:{}", width, base_and_value)
952 } else {
953 base_and_value.clone()
954 };
955 let limit = self.pos;
956 if has_unknown_digit {
957 return Ok(Some(Token {
958 payload: TokenPayload::VerilogUnknownInt { width },
959 span: Span { start, limit },
960 }));
961 }
962 let value = xlsynth::IrValue::parse_typed(&irbits_str)
963 .unwrap()
964 .to_bits()
965 .unwrap();
966 return Ok(Some(Token {
967 payload: TokenPayload::VerilogInt { width, value },
968 span: Span { start, limit },
969 }));
970 } else {
971 let irbits_str = format!("bits[32]:{}", num);
973 let value = match xlsynth::IrValue::parse_typed(&irbits_str) {
974 Ok(v) => v.to_bits().unwrap(),
975 Err(e) => {
976 let line = (self.line_lookup)(start.lineno)
977 .unwrap_or_else(|| "<line unavailable>".to_string());
978 let col = (start.colno as usize).saturating_sub(1);
979 panic!(
980 "Failed to parse integer literal '{}': {}\nLine {}: {}\n{}^",
981 irbits_str,
982 e,
983 start.lineno,
984 line,
985 " ".repeat(col)
986 );
987 }
988 };
989 let limit = self.pos;
990 return Ok(Some(Token {
991 payload: TokenPayload::VerilogInt { width: None, value },
992 span: Span { start, limit },
993 }));
994 }
995 }
996 if b == b'/' {
998 self.popb();
999 match self.peekb() {
1000 Some(b'/') => {
1001 self.popb();
1002 let mut comment = String::new();
1003 while let Some(b2) = self.popb() {
1004 if b2 == b'\n' {
1005 break;
1006 }
1007 comment.push(b2 as char);
1008 }
1009 let limit = self.pos;
1010 return Ok(Some(Token {
1011 payload: TokenPayload::Comment(comment),
1012 span: Span { start, limit },
1013 }));
1014 }
1015 Some(b'*') => {
1016 self.popb(); let mut prev: Option<u8> = None;
1019 while let Some(b2) = self.popb() {
1020 if prev == Some(b'*') && b2 == b'/' {
1021 break;
1022 }
1023 prev = Some(b2);
1024 }
1025 return match self.next_token()? {
1027 Some(tok) => Ok(Some(tok)),
1028 None => Ok(None),
1029 };
1030 }
1031 _ => {
1032 let limit = self.pos;
1034 return Err(self.error_with_context("Unexpected '/'", Span { start, limit }));
1035 }
1036 }
1037 }
1038 let payload = match b {
1040 b'(' => {
1041 self.popb();
1042 TokenPayload::OParen
1043 }
1044 b')' => {
1045 self.popb();
1046 TokenPayload::CParen
1047 }
1048 b'[' => {
1049 self.popb();
1050 TokenPayload::OBrack
1051 }
1052 b']' => {
1053 self.popb();
1054 TokenPayload::CBrack
1055 }
1056 b'{' => {
1057 self.popb();
1058 TokenPayload::OBrace
1059 }
1060 b'}' => {
1061 self.popb();
1062 TokenPayload::CBrace
1063 }
1064 b':' => {
1065 self.popb();
1066 TokenPayload::Colon
1067 }
1068 b';' => {
1069 self.popb();
1070 TokenPayload::Semi
1071 }
1072 b',' => {
1073 self.popb();
1074 TokenPayload::Comma
1075 }
1076 b'.' => {
1077 self.popb();
1078 TokenPayload::Dot
1079 }
1080 b'=' => {
1081 self.popb();
1082 TokenPayload::Equals
1083 }
1084 b'~' => {
1085 self.popb();
1086 TokenPayload::Tilde
1087 }
1088 b'&' => {
1089 self.popb();
1090 TokenPayload::Ampersand
1091 }
1092 b'|' => {
1093 self.popb();
1094 TokenPayload::Pipe
1095 }
1096 b'^' => {
1097 self.popb();
1098 TokenPayload::Caret
1099 }
1100 b'\n' => {
1101 self.popb();
1102 return match self.next_token()? {
1103 Some(tok) => Ok(Some(tok)),
1104 None => Ok(None),
1105 };
1106 } _ => {
1108 let limit = self.pos;
1110 return Err(self.error_with_context(
1111 &format!("Unexpected character '{}'", b as char),
1112 Span { start, limit },
1113 ));
1114 }
1115 };
1116 let limit = self.pos;
1117 Ok(Some(Token {
1118 payload,
1119 span: Span { start, limit },
1120 }))
1121 }
1122}
1123
1124impl Keyword {
1125 fn from_str(s: &str) -> Option<Self> {
1126 match s {
1127 "module" => Some(Keyword::Module),
1128 "wire" => Some(Keyword::Wire),
1129 "endmodule" => Some(Keyword::Endmodule),
1130 "input" => Some(Keyword::Input),
1131 "output" => Some(Keyword::Output),
1132 "inout" => Some(Keyword::Inout),
1133 _ => None,
1134 }
1135 }
1136}
1137
1138pub struct Parser<R: Read + 'static> {
1140 scanner: TokenScanner<R>,
1141 pub interner: StringInterner<StringBackend<SymbolU32>>,
1142 pub nets: Vec<Net>,
1143 net_index_by_name: HashMap<NetId, NetIndex>,
1144 current_module_net_start: usize,
1148 net_width_span_by_name: HashMap<NetId, Span>,
1152 allow_implicit_nets: bool,
1155 implicit_net_by_name: HashSet<NetId>,
1159}
1160
1161impl<R: Read + 'static> Parser<R> {
1162 pub fn new_with_options(scanner: TokenScanner<R>, allow_implicit_nets: bool) -> Self {
1164 Self {
1165 scanner,
1166 interner: StringInterner::new(),
1167 nets: Vec::new(),
1168 net_index_by_name: HashMap::new(),
1169 current_module_net_start: 0,
1170 net_width_span_by_name: HashMap::new(),
1171 allow_implicit_nets,
1172 implicit_net_by_name: HashSet::new(),
1173 }
1174 }
1175
1176 pub fn new(scanner: TokenScanner<R>) -> Self {
1179 Self::new_with_options(scanner, true)
1180 }
1181
1182 fn skip_trivia(&mut self) -> Result<(), ScanError> {
1183 loop {
1184 let peek = self.scanner.peekt()?;
1185 match peek {
1186 Some(tok) => match &tok.payload {
1187 TokenPayload::Comment(_) | TokenPayload::Annotation { .. } => {
1188 self.scanner.popt()?;
1189 }
1190 _ => break,
1191 },
1192 None => break,
1193 }
1194 }
1195 Ok(())
1196 }
1197
1198 fn parse_non_concat_netref_from_token(&mut self, net_tok: Token) -> Result<NetRef, ScanError> {
1199 match net_tok.payload {
1200 TokenPayload::Identifier(s) => {
1201 let net_sym = self.interner.get_or_intern(s);
1202 let net_idx = if let Some(&idx) = self.net_index_by_name.get(&net_sym) {
1203 idx
1204 } else if let Some(pos) = self.nets[self.current_module_net_start..]
1205 .iter()
1206 .position(|n| n.name == net_sym)
1207 {
1208 let idx = NetIndex(self.current_module_net_start + pos);
1209 self.net_index_by_name.insert(net_sym, idx);
1210 idx
1211 } else if self.allow_implicit_nets {
1212 let idx = NetIndex(self.nets.len());
1213 self.nets.push(Net {
1214 name: net_sym,
1215 width: Some((0, 0)),
1216 });
1217 self.net_index_by_name.insert(net_sym, idx);
1218 self.net_width_span_by_name.insert(net_sym, net_tok.span);
1219 self.implicit_net_by_name.insert(net_sym);
1220 idx
1221 } else {
1222 return Err(ScanError {
1223 message: format!(
1224 "net '{}' not declared as wire",
1225 self.interner.resolve(net_sym).unwrap()
1226 ),
1227 span: net_tok.span,
1228 });
1229 };
1230
1231 self.skip_trivia()?;
1232 if let Some(next) = self.scanner.peekt()? {
1233 if matches!(next.payload, TokenPayload::OBrack) {
1234 self.scanner.popt()?; self.skip_trivia()?;
1236 let msb_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
1237 message: "expected msb or index in net reference".to_string(),
1238 span: Span {
1239 start: self.scanner.pos,
1240 limit: self.scanner.pos,
1241 },
1242 })?;
1243 let msb = match msb_tok.payload {
1244 TokenPayload::VerilogInt { value, .. } => {
1245 xlsynth::IrValue::from_bits(&value).to_u32().unwrap()
1246 }
1247 _ => {
1248 return Err(ScanError {
1249 message: "expected integer for msb/index in net reference"
1250 .to_string(),
1251 span: msb_tok.span,
1252 });
1253 }
1254 };
1255 self.skip_trivia()?;
1256 let next2 = self.scanner.popt()?.ok_or_else(|| ScanError {
1257 message: "expected ':' or ']' in net reference".to_string(),
1258 span: Span {
1259 start: self.scanner.pos,
1260 limit: self.scanner.pos,
1261 },
1262 })?;
1263 return match next2.payload {
1264 TokenPayload::Colon => {
1265 self.skip_trivia()?;
1266 let lsb_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
1267 message: "expected lsb in net reference".to_string(),
1268 span: Span {
1269 start: self.scanner.pos,
1270 limit: self.scanner.pos,
1271 },
1272 })?;
1273 let lsb = match lsb_tok.payload {
1274 TokenPayload::VerilogInt { value, .. } => {
1275 xlsynth::IrValue::from_bits(&value).to_u32().unwrap()
1276 }
1277 _ => {
1278 return Err(ScanError {
1279 message: "expected integer for lsb in net reference"
1280 .to_string(),
1281 span: lsb_tok.span,
1282 });
1283 }
1284 };
1285 self.skip_trivia()?;
1286 let cbrack_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
1287 message: "expected ']' after part-select".to_string(),
1288 span: Span {
1289 start: self.scanner.pos,
1290 limit: self.scanner.pos,
1291 },
1292 })?;
1293 if !matches!(cbrack_tok.payload, TokenPayload::CBrack) {
1294 return Err(ScanError {
1295 message: "expected ']' after part-select".to_string(),
1296 span: cbrack_tok.span,
1297 });
1298 }
1299 Ok(NetRef::PartSelect(net_idx, msb, lsb))
1300 }
1301 TokenPayload::CBrack => Ok(NetRef::BitSelect(net_idx, msb)),
1302 _ => Err(ScanError {
1303 message: "expected ':' or ']' in net reference".to_string(),
1304 span: next2.span,
1305 }),
1306 };
1307 }
1308 }
1309 Ok(NetRef::Simple(net_idx))
1310 }
1311 TokenPayload::VerilogInt { value, width: _ } => Ok(NetRef::Literal(value)),
1312 TokenPayload::VerilogUnknownInt { width } => {
1313 Ok(NetRef::UnknownLiteral(width.unwrap_or(32)))
1314 }
1315 other => Err(ScanError {
1316 message: format!("expected identifier for net name, got {:?}", other),
1317 span: net_tok.span,
1318 }),
1319 }
1320 }
1321
1322 fn parse_netref_expr(&mut self) -> Result<NetRef, ScanError> {
1323 self.skip_trivia()?;
1324 if let Some(tok) = self.scanner.peekt()? {
1325 if matches!(tok.payload, TokenPayload::OBrace) {
1326 self.scanner.popt()?; let mut elems: Vec<NetRef> = Vec::new();
1329 loop {
1330 self.skip_trivia()?;
1331 if let Some(tok2) = self.scanner.peekt()? {
1333 if matches!(tok2.payload, TokenPayload::CBrace) {
1334 self.scanner.popt()?; break;
1336 }
1337 }
1338 let elem = self.parse_netref_expr()?;
1341 elems.push(elem);
1342 if let Some(next) = self.scanner.peekt()? {
1344 if matches!(next.payload, TokenPayload::Comma) {
1345 self.scanner.popt()?; continue;
1347 }
1348 }
1349 let cbrace = self.scanner.popt()?.ok_or_else(|| ScanError {
1351 message: "expected '}' to close concatenation".to_string(),
1352 span: Span {
1353 start: self.scanner.pos,
1354 limit: self.scanner.pos,
1355 },
1356 })?;
1357 if !matches!(cbrace.payload, TokenPayload::CBrace) {
1358 return Err(ScanError {
1359 message: "expected '}' to close concatenation".to_string(),
1360 span: cbrace.span,
1361 });
1362 }
1363 break;
1364 }
1365 return Ok(NetRef::Concat(elems));
1366 }
1367 }
1368 let net_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
1369 message: "expected net name".to_string(),
1370 span: Span {
1371 start: self.scanner.pos,
1372 limit: self.scanner.pos,
1373 },
1374 })?;
1375 self.parse_non_concat_netref_from_token(net_tok)
1376 }
1377
1378 fn parse_assign_primary(&mut self) -> Result<AssignExpr, ScanError> {
1379 self.skip_trivia()?;
1380 if let Some(tok) = self.scanner.peekt()? {
1381 match tok.payload {
1382 TokenPayload::OParen => {
1383 self.scanner.popt()?;
1384 let expr = self.parse_assign_expr()?;
1385 self.skip_trivia()?;
1386 let cparen = self.scanner.popt()?.ok_or_else(|| ScanError {
1387 message: "expected ')' to close assign expression".to_string(),
1388 span: Span {
1389 start: self.scanner.pos,
1390 limit: self.scanner.pos,
1391 },
1392 })?;
1393 if !matches!(cparen.payload, TokenPayload::CParen) {
1394 return Err(ScanError {
1395 message: "expected ')' to close assign expression".to_string(),
1396 span: cparen.span,
1397 });
1398 }
1399 return Ok(expr);
1400 }
1401 TokenPayload::OBrace => {
1402 return Ok(AssignExpr::Leaf(self.parse_netref_expr()?));
1403 }
1404 _ => {}
1405 }
1406 }
1407 let tok = self.scanner.popt()?.ok_or_else(|| ScanError {
1408 message: "expected assign expression operand".to_string(),
1409 span: Span {
1410 start: self.scanner.pos,
1411 limit: self.scanner.pos,
1412 },
1413 })?;
1414 Ok(AssignExpr::Leaf(
1415 self.parse_non_concat_netref_from_token(tok)?,
1416 ))
1417 }
1418
1419 fn parse_assign_unary(&mut self) -> Result<AssignExpr, ScanError> {
1420 self.skip_trivia()?;
1421 if let Some(tok) = self.scanner.peekt()? {
1422 if matches!(tok.payload, TokenPayload::Tilde) {
1423 self.scanner.popt()?;
1424 let inner = self.parse_assign_unary()?;
1425 return Ok(AssignExpr::Not(Box::new(inner)));
1426 }
1427 }
1428 self.parse_assign_primary()
1429 }
1430
1431 fn parse_assign_and(&mut self) -> Result<AssignExpr, ScanError> {
1432 let mut lhs = self.parse_assign_unary()?;
1433 loop {
1434 self.skip_trivia()?;
1435 let Some(tok) = self.scanner.peekt()? else {
1436 break;
1437 };
1438 if !matches!(tok.payload, TokenPayload::Ampersand) {
1439 break;
1440 }
1441 self.scanner.popt()?;
1442 let rhs = self.parse_assign_unary()?;
1443 lhs = AssignExpr::And(Box::new(lhs), Box::new(rhs));
1444 }
1445 Ok(lhs)
1446 }
1447
1448 fn parse_assign_xor(&mut self) -> Result<AssignExpr, ScanError> {
1449 let mut lhs = self.parse_assign_and()?;
1450 loop {
1451 self.skip_trivia()?;
1452 let Some(tok) = self.scanner.peekt()? else {
1453 break;
1454 };
1455 if !matches!(tok.payload, TokenPayload::Caret) {
1456 break;
1457 }
1458 self.scanner.popt()?;
1459 let rhs = self.parse_assign_and()?;
1460 lhs = AssignExpr::Xor(Box::new(lhs), Box::new(rhs));
1461 }
1462 Ok(lhs)
1463 }
1464
1465 fn parse_assign_or(&mut self) -> Result<AssignExpr, ScanError> {
1466 let mut lhs = self.parse_assign_xor()?;
1467 loop {
1468 self.skip_trivia()?;
1469 let Some(tok) = self.scanner.peekt()? else {
1470 break;
1471 };
1472 if !matches!(tok.payload, TokenPayload::Pipe) {
1473 break;
1474 }
1475 self.scanner.popt()?;
1476 let rhs = self.parse_assign_xor()?;
1477 lhs = AssignExpr::Or(Box::new(lhs), Box::new(rhs));
1478 }
1479 Ok(lhs)
1480 }
1481
1482 fn parse_assign_expr(&mut self) -> Result<AssignExpr, ScanError> {
1483 self.parse_assign_or()
1484 }
1485
1486 fn ensure_net(
1493 &mut self,
1494 name: NetId,
1495 width: Option<(u32, u32)>,
1496 err_span: Span,
1497 ) -> Result<NetIndex, ScanError> {
1498 if let Some(&idx) = self.net_index_by_name.get(&name) {
1499 let implicit_scalar_placeholder =
1500 self.implicit_net_by_name.contains(&name) && self.nets[idx.0].width == Some((0, 0));
1501 let mut clear_implicit_marker = false;
1502 {
1503 let existing = &mut self.nets[idx.0];
1504 match (existing.width, width) {
1505 (None, None) => {}
1506 (None, Some(w)) => {
1507 existing.width = Some(w);
1508 self.net_width_span_by_name.insert(name, err_span);
1509 }
1510 (Some(_), None) => {
1511 if implicit_scalar_placeholder {
1512 self.net_width_span_by_name.insert(name, err_span);
1513 clear_implicit_marker = true;
1514 }
1515 }
1516 (Some(a), Some(b)) => {
1517 if a != b {
1518 if implicit_scalar_placeholder {
1519 existing.width = Some(b);
1520 self.net_width_span_by_name.insert(name, err_span);
1521 clear_implicit_marker = true;
1522 } else {
1523 debug_assert!(
1524 self.net_width_span_by_name.contains_key(&name),
1525 "Net with known width should carry a width span for diagnostics"
1526 );
1527 let prev_span = self
1528 .net_width_span_by_name
1529 .get(&name)
1530 .copied()
1531 .unwrap_or(err_span);
1532 return Err(ScanError {
1533 message: format!(
1534 "conflicting widths for net '{}': {:?} vs {:?}; previously determined width was {:?} @ {}",
1535 self.interner.resolve(name).unwrap_or("<unknown>"),
1536 a,
1537 b,
1538 a,
1539 prev_span.to_human_string()
1540 ),
1541 span: err_span,
1542 });
1543 }
1544 } else if implicit_scalar_placeholder {
1545 self.net_width_span_by_name.insert(name, err_span);
1546 clear_implicit_marker = true;
1547 }
1548 }
1549 }
1550 }
1551 if clear_implicit_marker {
1552 self.implicit_net_by_name.remove(&name);
1553 }
1554 Ok(idx)
1555 } else {
1556 let idx = NetIndex(self.nets.len());
1557 self.nets.push(Net { name, width });
1558 if width.is_some() {
1559 self.net_width_span_by_name.insert(name, err_span);
1560 }
1561 self.net_index_by_name.insert(name, idx);
1562 Ok(idx)
1563 }
1564 }
1565
1566 fn parse_assign(&mut self) -> Result<NetlistAssign, ScanError> {
1572 let t_assign = self.scanner.popt()?.ok_or_else(|| ScanError {
1573 message: "expected 'assign'".to_string(),
1574 span: Span {
1575 start: self.scanner.pos,
1576 limit: self.scanner.pos,
1577 },
1578 })?;
1579 match t_assign.payload {
1580 TokenPayload::Identifier(ref s) if s == "assign" => {}
1581 _ => {
1582 return Err(ScanError {
1583 message: "expected 'assign'".to_string(),
1584 span: t_assign.span,
1585 });
1586 }
1587 }
1588
1589 self.skip_trivia()?;
1590 let lhs = self.parse_netref_expr()?;
1591 if !matches!(
1592 lhs,
1593 NetRef::Simple(_)
1594 | NetRef::BitSelect(_, _)
1595 | NetRef::PartSelect(_, _, _)
1596 | NetRef::Concat(_)
1597 ) {
1598 return Err(ScanError {
1599 message: "left-hand side of assign must be an identifier, select, or concat"
1600 .to_string(),
1601 span: t_assign.span,
1602 });
1603 }
1604
1605 self.skip_trivia()?;
1606 let t_eq = self.scanner.popt()?.ok_or_else(|| ScanError {
1607 message: "expected '=' in assign".to_string(),
1608 span: Span {
1609 start: self.scanner.pos,
1610 limit: self.scanner.pos,
1611 },
1612 })?;
1613 if !matches!(t_eq.payload, TokenPayload::Equals) {
1614 return Err(ScanError {
1615 message: "expected '=' in assign".to_string(),
1616 span: t_eq.span,
1617 });
1618 }
1619
1620 let rhs = self.parse_assign_expr()?;
1621
1622 self.skip_trivia()?;
1623 let t_semi = self.scanner.popt()?.ok_or_else(|| ScanError {
1624 message: "expected ';' after assign".to_string(),
1625 span: Span {
1626 start: self.scanner.pos,
1627 limit: self.scanner.pos,
1628 },
1629 })?;
1630 if !matches!(t_semi.payload, TokenPayload::Semi) {
1631 return Err(ScanError {
1632 message: "expected ';' after assign".to_string(),
1633 span: t_semi.span,
1634 });
1635 }
1636 Ok(NetlistAssign {
1637 kind: NetlistAssignKind::Continuous,
1638 lhs,
1639 rhs,
1640 span: Span {
1641 start: t_assign.span.start,
1642 limit: t_semi.span.limit,
1643 },
1644 })
1645 }
1646
1647 fn parse_tran(&mut self) -> Result<NetlistAssign, ScanError> {
1649 let t_tran = self.scanner.popt()?.ok_or_else(|| ScanError {
1650 message: "expected 'tran'".to_string(),
1651 span: Span {
1652 start: self.scanner.pos,
1653 limit: self.scanner.pos,
1654 },
1655 })?;
1656 if !matches!(t_tran.payload, TokenPayload::Identifier(ref s) if s == "tran") {
1657 return Err(ScanError {
1658 message: "expected 'tran'".to_string(),
1659 span: t_tran.span,
1660 });
1661 }
1662
1663 self.skip_trivia()?;
1664 if let Some(tok) = self.scanner.peekt()? {
1665 if matches!(tok.payload, TokenPayload::Identifier(_)) {
1666 self.scanner.popt()?;
1667 self.skip_trivia()?;
1668 if let Some(range_tok) = self.scanner.peekt()? {
1669 if matches!(range_tok.payload, TokenPayload::OBrack) {
1670 self.scanner.popt()?;
1671 self.skip_trivia()?;
1672 let _msb = self.scanner.popt()?.ok_or_else(|| ScanError {
1673 message: "expected msb in tran instance range".to_string(),
1674 span: Span {
1675 start: self.scanner.pos,
1676 limit: self.scanner.pos,
1677 },
1678 })?;
1679 self.skip_trivia()?;
1680 let colon = self.scanner.popt()?.ok_or_else(|| ScanError {
1681 message: "expected ':' in tran instance range".to_string(),
1682 span: Span {
1683 start: self.scanner.pos,
1684 limit: self.scanner.pos,
1685 },
1686 })?;
1687 if !matches!(colon.payload, TokenPayload::Colon) {
1688 return Err(ScanError {
1689 message: "expected ':' in tran instance range".to_string(),
1690 span: colon.span,
1691 });
1692 }
1693 self.skip_trivia()?;
1694 let _lsb = self.scanner.popt()?.ok_or_else(|| ScanError {
1695 message: "expected lsb in tran instance range".to_string(),
1696 span: Span {
1697 start: self.scanner.pos,
1698 limit: self.scanner.pos,
1699 },
1700 })?;
1701 self.skip_trivia()?;
1702 let cbrack = self.scanner.popt()?.ok_or_else(|| ScanError {
1703 message: "expected ']' after tran instance range".to_string(),
1704 span: Span {
1705 start: self.scanner.pos,
1706 limit: self.scanner.pos,
1707 },
1708 })?;
1709 if !matches!(cbrack.payload, TokenPayload::CBrack) {
1710 return Err(ScanError {
1711 message: "expected ']' after tran instance range".to_string(),
1712 span: cbrack.span,
1713 });
1714 }
1715 }
1716 }
1717 }
1718 }
1719
1720 self.skip_trivia()?;
1721 let oparen = self.scanner.popt()?.ok_or_else(|| ScanError {
1722 message: "expected '(' after tran".to_string(),
1723 span: Span {
1724 start: self.scanner.pos,
1725 limit: self.scanner.pos,
1726 },
1727 })?;
1728 if !matches!(oparen.payload, TokenPayload::OParen) {
1729 return Err(ScanError {
1730 message: "expected '(' after tran".to_string(),
1731 span: oparen.span,
1732 });
1733 }
1734
1735 let lhs = self.parse_netref_expr()?;
1736 self.skip_trivia()?;
1737 let comma = self.scanner.popt()?.ok_or_else(|| ScanError {
1738 message: "expected ',' between tran terminals".to_string(),
1739 span: Span {
1740 start: self.scanner.pos,
1741 limit: self.scanner.pos,
1742 },
1743 })?;
1744 if !matches!(comma.payload, TokenPayload::Comma) {
1745 return Err(ScanError {
1746 message: "expected ',' between tran terminals".to_string(),
1747 span: comma.span,
1748 });
1749 }
1750 let rhs = self.parse_netref_expr()?;
1751 self.skip_trivia()?;
1752 let cparen = self.scanner.popt()?.ok_or_else(|| ScanError {
1753 message: "expected ')' after tran terminals".to_string(),
1754 span: Span {
1755 start: self.scanner.pos,
1756 limit: self.scanner.pos,
1757 },
1758 })?;
1759 if !matches!(cparen.payload, TokenPayload::CParen) {
1760 return Err(ScanError {
1761 message: "expected ')' after tran terminals".to_string(),
1762 span: cparen.span,
1763 });
1764 }
1765 self.skip_trivia()?;
1766 let t_semi = self.scanner.popt()?.ok_or_else(|| ScanError {
1767 message: "expected ';' after tran".to_string(),
1768 span: Span {
1769 start: self.scanner.pos,
1770 limit: self.scanner.pos,
1771 },
1772 })?;
1773 if !matches!(t_semi.payload, TokenPayload::Semi) {
1774 return Err(ScanError {
1775 message: "expected ';' after tran".to_string(),
1776 span: t_semi.span,
1777 });
1778 }
1779 Ok(NetlistAssign {
1780 kind: NetlistAssignKind::Tran,
1781 lhs,
1782 rhs: AssignExpr::Leaf(rhs),
1783 span: Span {
1784 start: t_tran.span.start,
1785 limit: t_semi.span.limit,
1786 },
1787 })
1788 }
1789 pub fn parse_file(&mut self) -> Result<Vec<NetlistModule>, ScanError> {
1790 log::trace!("parse_file: start");
1791 let mut modules = Vec::new();
1792 loop {
1793 match self.scanner.peekt()? {
1794 Some(tok) => {
1795 log::trace!(
1796 "parse_file: top-level token: {:?} at {:?}",
1797 tok.payload,
1798 tok.span
1799 );
1800 match &tok.payload {
1801 TokenPayload::Keyword(Keyword::Module) => {
1802 log::trace!("parse_file: found 'module', parsing module body");
1803 modules.push(self.parse_module()?);
1804 }
1805 TokenPayload::Comment(_) | TokenPayload::Annotation { .. } => {
1807 log::trace!("parse_file: skipping comment/annotation at top level");
1808 self.scanner.popt()?;
1809 }
1810 _ => {
1812 log::trace!(
1813 "parse_file: stopping on unexpected top-level token: {:?}",
1814 tok.payload
1815 );
1816 break;
1817 }
1818 }
1819 }
1820 None => break,
1821 }
1822 }
1823 log::trace!("parse_file: done; modules parsed: {}", modules.len());
1824 Ok(modules)
1825 }
1826
1827 pub fn parse_module(&mut self) -> Result<NetlistModule, ScanError> {
1828 self.current_module_net_start = self.nets.len();
1833 let module_net_start = self.current_module_net_start;
1834 self.net_index_by_name.clear();
1835 self.net_width_span_by_name.clear();
1836 self.implicit_net_by_name.clear();
1837
1838 let tok = self.scanner.popt()?.ok_or_else(|| ScanError {
1840 message: "expected 'module' keyword".to_string(),
1841 span: Span {
1842 start: self.scanner.pos,
1843 limit: self.scanner.pos,
1844 },
1845 })?;
1846 if !matches!(tok.payload, TokenPayload::Keyword(Keyword::Module)) {
1847 return Err(ScanError {
1848 message: "expected 'module' keyword".to_string(),
1849 span: tok.span,
1850 });
1851 }
1852 let name_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
1854 message: "expected module name".to_string(),
1855 span: Span {
1856 start: self.scanner.pos,
1857 limit: self.scanner.pos,
1858 },
1859 })?;
1860 let name = match name_tok.payload {
1861 TokenPayload::Identifier(s) => self.interner.get_or_intern(s),
1862 _ => {
1863 return Err(ScanError {
1864 message: "expected identifier for module name".to_string(),
1865 span: name_tok.span,
1866 });
1867 }
1868 };
1869 let oparen_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
1871 message: "expected '(' after module name".to_string(),
1872 span: Span {
1873 start: self.scanner.pos,
1874 limit: self.scanner.pos,
1875 },
1876 })?;
1877 if !matches!(oparen_tok.payload, TokenPayload::OParen) {
1878 return Err(ScanError {
1879 message: "expected '(' after module name".to_string(),
1880 span: oparen_tok.span,
1881 });
1882 }
1883 let mut port_names = Vec::new();
1885 loop {
1886 let t = self.scanner.popt()?.ok_or_else(|| ScanError {
1887 message: "expected token in port list".to_string(),
1888 span: Span {
1889 start: self.scanner.pos,
1890 limit: self.scanner.pos,
1891 },
1892 })?;
1893 match t.payload {
1894 TokenPayload::Identifier(s) => {
1895 let sym = self.interner.get_or_intern(s);
1896 port_names.push(sym);
1897 if let Some(next) = self.scanner.peekt()? {
1899 if matches!(next.payload, TokenPayload::Comma) {
1900 self.scanner.popt()?; continue;
1902 }
1903 }
1904 }
1905 TokenPayload::CParen => break,
1906 _ => {
1907 return Err(ScanError {
1908 message: format!("unexpected token in port list: {:?}", t.payload),
1909 span: t.span,
1910 });
1911 }
1912 }
1913 }
1914 let semi_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
1916 message: "expected ';' after port list".to_string(),
1917 span: Span {
1918 start: self.scanner.pos,
1919 limit: self.scanner.pos,
1920 },
1921 })?;
1922 if !matches!(semi_tok.payload, TokenPayload::Semi) {
1923 return Err(ScanError {
1924 message: "expected ';' after port list".to_string(),
1925 span: semi_tok.span,
1926 });
1927 }
1928 let mut ports = Vec::new();
1930 let mut wires = Vec::new();
1931 let mut assigns = Vec::new();
1932 let mut instances = Vec::new();
1933 let mut instance_names: HashSet<PortId> = HashSet::new();
1936 loop {
1937 match self.scanner.peekt()? {
1938 Some(tok) => match &tok.payload {
1939 TokenPayload::Keyword(Keyword::Input) => {
1940 let mut decls = self.parse_port_decl(PortDirection::Input)?;
1941 ports.append(&mut decls);
1942 }
1943 TokenPayload::Keyword(Keyword::Output) => {
1944 let mut decls = self.parse_port_decl(PortDirection::Output)?;
1945 ports.append(&mut decls);
1946 }
1947 TokenPayload::Keyword(Keyword::Inout) => {
1948 let mut decls = self.parse_port_decl(PortDirection::Inout)?;
1949 ports.append(&mut decls);
1950 }
1951 TokenPayload::Keyword(Keyword::Wire) => {
1952 let wire_indices = self.parse_wire_decl()?;
1953 wires.extend(wire_indices);
1954 }
1955 TokenPayload::Keyword(Keyword::Endmodule) => {
1956 self.scanner.popt()?; break;
1958 }
1959 TokenPayload::Identifier(s) if s == "assign" => {
1960 assigns.push(self.parse_assign()?);
1961 }
1962 TokenPayload::Identifier(s) if s == "tran" => {
1963 assigns.push(self.parse_tran()?);
1964 }
1965 TokenPayload::Identifier(_) => {
1966 let instance = self.parse_instance()?;
1967 if !instance_names.insert(instance.instance_name) {
1968 let instance_start_pos = Pos {
1969 lineno: instance.inst_lineno,
1970 colno: instance.inst_colno,
1971 };
1972 return Err(ScanError {
1973 message: format!(
1974 "duplicate instance name '{}' in module",
1975 self.interner.resolve(instance.instance_name).unwrap()
1976 ),
1977 span: Span {
1978 start: instance_start_pos,
1979 limit: instance_start_pos,
1980 },
1981 });
1982 }
1983 instances.push(instance);
1984 }
1985 TokenPayload::Comment(_) | TokenPayload::Annotation { .. } => {
1987 self.scanner.popt()?;
1988 }
1989 _ => {
1990 break;
1992 }
1993 },
1994 None => break,
1995 }
1996 }
1997 let mut header_port_index: HashMap<PortId, usize> = HashMap::new();
2002 for (i, port_name) in port_names.into_iter().enumerate() {
2003 header_port_index.entry(port_name).or_insert(i);
2004 }
2005 ports.sort_by_key(|port| {
2006 header_port_index
2007 .get(&port.name)
2008 .copied()
2009 .unwrap_or(usize::MAX)
2010 });
2011 Ok(NetlistModule {
2012 name,
2013 net_index_range: module_net_start..self.nets.len(),
2014 ports,
2015 wires,
2016 assigns,
2017 instances,
2018 })
2019 }
2020
2021 pub fn parse_port_decl(
2023 &mut self,
2024 direction: PortDirection,
2025 ) -> Result<Vec<NetlistPort>, ScanError> {
2026 let kw_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
2028 message: "expected port direction keyword".to_string(),
2029 span: Span {
2030 start: self.scanner.pos,
2031 limit: self.scanner.pos,
2032 },
2033 })?;
2034 if !matches!(
2035 kw_tok.payload,
2036 TokenPayload::Keyword(Keyword::Input)
2037 | TokenPayload::Keyword(Keyword::Output)
2038 | TokenPayload::Keyword(Keyword::Inout)
2039 ) {
2040 return Err(ScanError {
2041 message: "expected port direction keyword".to_string(),
2042 span: kw_tok.span,
2043 });
2044 }
2045 let mut width = None;
2047 if let Some(next) = self.scanner.peekt()? {
2048 if matches!(next.payload, TokenPayload::OBrack) {
2049 self.scanner.popt()?; let msb_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
2051 message: "expected msb in width".to_string(),
2052 span: Span {
2053 start: self.scanner.pos,
2054 limit: self.scanner.pos,
2055 },
2056 })?;
2057 let msb = match msb_tok.payload {
2058 TokenPayload::VerilogInt { value, .. } => {
2059 xlsynth::IrValue::from_bits(&value).to_u32().unwrap()
2060 }
2061 _ => {
2062 return Err(ScanError {
2063 message: "expected integer for msb".to_string(),
2064 span: msb_tok.span,
2065 });
2066 }
2067 };
2068 let colon_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
2069 message: "expected ':' in width".to_string(),
2070 span: Span {
2071 start: self.scanner.pos,
2072 limit: self.scanner.pos,
2073 },
2074 })?;
2075 if !matches!(colon_tok.payload, TokenPayload::Colon) {
2076 return Err(ScanError {
2077 message: "expected ':' in width".to_string(),
2078 span: colon_tok.span,
2079 });
2080 }
2081 let lsb_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
2082 message: "expected lsb in width".to_string(),
2083 span: Span {
2084 start: self.scanner.pos,
2085 limit: self.scanner.pos,
2086 },
2087 })?;
2088 let lsb = match lsb_tok.payload {
2089 TokenPayload::VerilogInt { value, .. } => {
2090 xlsynth::IrValue::from_bits(&value).to_u32().unwrap()
2091 }
2092 _ => {
2093 return Err(ScanError {
2094 message: "expected integer for lsb".to_string(),
2095 span: lsb_tok.span,
2096 });
2097 }
2098 };
2099 let cbrack_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
2100 message: "expected ']' after width".to_string(),
2101 span: Span {
2102 start: self.scanner.pos,
2103 limit: self.scanner.pos,
2104 },
2105 })?;
2106 if !matches!(cbrack_tok.payload, TokenPayload::CBrack) {
2107 return Err(ScanError {
2108 message: "expected ']' after width".to_string(),
2109 span: cbrack_tok.span,
2110 });
2111 }
2112 width = Some((msb, lsb));
2113 }
2114 }
2115 let mut ports = Vec::new();
2117 loop {
2118 let t = self.scanner.popt()?.ok_or_else(|| ScanError {
2119 message: "expected identifier in port decl".to_string(),
2120 span: Span {
2121 start: self.scanner.pos,
2122 limit: self.scanner.pos,
2123 },
2124 })?;
2125 let name = match t.payload {
2126 TokenPayload::Identifier(s) => self.interner.get_or_intern(s),
2127 _ => {
2128 return Err(ScanError {
2129 message: "expected identifier in port decl".to_string(),
2130 span: t.span,
2131 });
2132 }
2133 };
2134 let _net_index = self.ensure_net(name, width, t.span)?;
2138 ports.push(NetlistPort {
2139 direction: direction.clone(),
2140 width,
2141 name,
2142 });
2143 if let Some(next) = self.scanner.peekt()? {
2145 if matches!(next.payload, TokenPayload::Comma) {
2146 self.scanner.popt()?; continue;
2148 }
2149 }
2150 let semi = self.scanner.popt()?.ok_or_else(|| ScanError {
2152 message: "expected ';' after port decl".to_string(),
2153 span: Span {
2154 start: self.scanner.pos,
2155 limit: self.scanner.pos,
2156 },
2157 })?;
2158 if !matches!(semi.payload, TokenPayload::Semi) {
2159 return Err(ScanError {
2160 message: "expected ';' after port decl".to_string(),
2161 span: semi.span,
2162 });
2163 }
2164 break;
2165 }
2166 Ok(ports)
2167 }
2168
2169 pub fn parse_wire_decl(&mut self) -> Result<Vec<NetIndex>, ScanError> {
2171 let tok = self.scanner.popt()?.ok_or_else(|| ScanError {
2173 message: "expected 'wire' keyword".to_string(),
2174 span: Span {
2175 start: self.scanner.pos,
2176 limit: self.scanner.pos,
2177 },
2178 })?;
2179 if !matches!(tok.payload, TokenPayload::Keyword(Keyword::Wire)) {
2180 return Err(ScanError {
2181 message: "expected 'wire' keyword".to_string(),
2182 span: tok.span,
2183 });
2184 }
2185 let mut width = None;
2187 if let Some(next) = self.scanner.peekt()? {
2188 if matches!(next.payload, TokenPayload::OBrack) {
2189 self.scanner.popt()?; let msb_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
2191 message: "expected msb in width".to_string(),
2192 span: Span {
2193 start: self.scanner.pos,
2194 limit: self.scanner.pos,
2195 },
2196 })?;
2197 let msb = match msb_tok.payload {
2198 TokenPayload::VerilogInt { value, .. } => {
2199 xlsynth::IrValue::from_bits(&value).to_u32().unwrap()
2200 }
2201 _ => {
2202 return Err(ScanError {
2203 message: "expected integer for msb".to_string(),
2204 span: msb_tok.span,
2205 });
2206 }
2207 };
2208 let colon_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
2209 message: "expected ':' in width".to_string(),
2210 span: Span {
2211 start: self.scanner.pos,
2212 limit: self.scanner.pos,
2213 },
2214 })?;
2215 if !matches!(colon_tok.payload, TokenPayload::Colon) {
2216 return Err(ScanError {
2217 message: "expected ':' in width".to_string(),
2218 span: colon_tok.span,
2219 });
2220 }
2221 let lsb_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
2222 message: "expected lsb in width".to_string(),
2223 span: Span {
2224 start: self.scanner.pos,
2225 limit: self.scanner.pos,
2226 },
2227 })?;
2228 let lsb = match lsb_tok.payload {
2229 TokenPayload::VerilogInt { value, .. } => {
2230 xlsynth::IrValue::from_bits(&value).to_u32().unwrap()
2231 }
2232 _ => {
2233 return Err(ScanError {
2234 message: "expected integer for lsb".to_string(),
2235 span: lsb_tok.span,
2236 });
2237 }
2238 };
2239 let cbrack_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
2240 message: "expected ']' after width".to_string(),
2241 span: Span {
2242 start: self.scanner.pos,
2243 limit: self.scanner.pos,
2244 },
2245 })?;
2246 if !matches!(cbrack_tok.payload, TokenPayload::CBrack) {
2247 return Err(ScanError {
2248 message: "expected ']' after width".to_string(),
2249 span: cbrack_tok.span,
2250 });
2251 }
2252 width = Some((msb, lsb));
2253 }
2254 }
2255 let mut net_indices = Vec::new();
2256 loop {
2257 let t = self.scanner.popt()?.ok_or_else(|| ScanError {
2258 message: "expected identifier in wire decl".to_string(),
2259 span: Span {
2260 start: self.scanner.pos,
2261 limit: self.scanner.pos,
2262 },
2263 })?;
2264 let name = match t.payload {
2265 TokenPayload::Identifier(s) => self.interner.get_or_intern(s),
2266 ref other => {
2267 let line = (self.scanner.line_lookup)(t.span.start.lineno)
2268 .unwrap_or_else(|| "<line unavailable>".to_string());
2269 log::error!(
2270 "expected identifier in wire decl, got {:?} at {:?}\n{}\n{}^",
2271 other,
2272 t.span,
2273 line,
2274 " ".repeat((t.span.start.colno as usize).saturating_sub(1))
2275 );
2276 return Err(ScanError {
2277 message: "expected identifier in wire decl".to_string(),
2278 span: t.span,
2279 });
2280 }
2281 };
2282 let net_idx = self.ensure_net(name, width, t.span)?;
2284 net_indices.push(net_idx);
2285 if let Some(next) = self.scanner.peekt()? {
2287 if matches!(next.payload, TokenPayload::Comma) {
2288 self.scanner.popt()?; continue;
2290 }
2291 }
2292 let semi = self.scanner.popt()?.ok_or_else(|| ScanError {
2294 message: "expected ';' after wire decl".to_string(),
2295 span: Span {
2296 start: self.scanner.pos,
2297 limit: self.scanner.pos,
2298 },
2299 })?;
2300 if !matches!(semi.payload, TokenPayload::Semi) {
2301 return Err(ScanError {
2302 message: "expected ';' after wire decl".to_string(),
2303 span: semi.span,
2304 });
2305 }
2306 break;
2307 }
2308 Ok(net_indices)
2309 }
2310
2311 pub fn parse_instance(&mut self) -> Result<NetlistInstance, ScanError> {
2313 let type_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
2315 message: "expected type name".to_string(),
2316 span: Span {
2317 start: self.scanner.pos,
2318 limit: self.scanner.pos,
2319 },
2320 })?;
2321 let type_name = match type_tok.payload {
2322 TokenPayload::Identifier(s) => self.interner.get_or_intern(s),
2323 _ => {
2324 return Err(ScanError {
2325 message: "expected identifier for type name".to_string(),
2326 span: type_tok.span,
2327 });
2328 }
2329 };
2330 loop {
2332 let peek = self.scanner.peekt()?;
2333 match peek {
2334 Some(tok) => match &tok.payload {
2335 TokenPayload::Comment(_) | TokenPayload::Annotation { .. } => {
2336 self.scanner.popt()?;
2337 }
2338 _ => break,
2339 },
2340 None => break,
2341 }
2342 }
2343 let inst_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
2345 message: "expected instance name".to_string(),
2346 span: Span {
2347 start: self.scanner.pos,
2348 limit: self.scanner.pos,
2349 },
2350 })?;
2351 let instance_name = match inst_tok.payload {
2352 TokenPayload::Identifier(s) => self.interner.get_or_intern(s),
2353 ref other => {
2354 return Err(ScanError {
2355 message: format!("expected identifier for instance name; got {:?}", other),
2356 span: inst_tok.span,
2357 });
2358 }
2359 };
2360 let oparen = self.scanner.popt()?.ok_or_else(|| ScanError {
2362 message: "expected '(' after instance name".to_string(),
2363 span: Span {
2364 start: self.scanner.pos,
2365 limit: self.scanner.pos,
2366 },
2367 })?;
2368 if !matches!(oparen.payload, TokenPayload::OParen) {
2369 return Err(ScanError {
2370 message: "expected '(' after instance name".to_string(),
2371 span: oparen.span,
2372 });
2373 }
2374 loop {
2377 let peek = self.scanner.peekt()?;
2378 match peek {
2379 Some(tok) => match &tok.payload {
2380 TokenPayload::Comment(_) | TokenPayload::Annotation { .. } => {
2381 self.scanner.popt()?;
2382 }
2383 _ => break,
2384 },
2385 None => break,
2386 }
2387 }
2388 if let Some(tok) = self.scanner.peekt()? {
2389 if matches!(tok.payload, TokenPayload::CParen) {
2390 self.scanner.popt()?; let semi = self.scanner.popt()?.ok_or_else(|| ScanError {
2392 message: "expected ';' after instance".to_string(),
2393 span: Span {
2394 start: self.scanner.pos,
2395 limit: self.scanner.pos,
2396 },
2397 })?;
2398 if !matches!(semi.payload, TokenPayload::Semi) {
2399 return Err(ScanError {
2400 message: "expected ';' after instance".to_string(),
2401 span: semi.span,
2402 });
2403 }
2404 return Ok(NetlistInstance {
2405 type_name,
2406 instance_name,
2407 connections: Vec::new(),
2408 inst_lineno: inst_tok.span.start.lineno,
2409 inst_colno: inst_tok.span.start.colno,
2410 });
2411 }
2412 }
2413 let mut connections = Vec::new();
2414 loop {
2415 let dot = self.scanner.popt()?.ok_or_else(|| ScanError {
2417 message: "expected '.' before port name".to_string(),
2418 span: Span {
2419 start: self.scanner.pos,
2420 limit: self.scanner.pos,
2421 },
2422 })?;
2423 if !matches!(dot.payload, TokenPayload::Dot) {
2424 return Err(ScanError {
2425 message: "expected '.' before port name".to_string(),
2426 span: dot.span,
2427 });
2428 }
2429 let port_tok = self.scanner.popt()?.ok_or_else(|| ScanError {
2430 message: "expected port name".to_string(),
2431 span: Span {
2432 start: self.scanner.pos,
2433 limit: self.scanner.pos,
2434 },
2435 })?;
2436 let port = match port_tok.payload {
2437 TokenPayload::Identifier(s) => self.interner.get_or_intern(s),
2438 _ => {
2439 return Err(ScanError {
2440 message: "expected identifier for port name".to_string(),
2441 span: port_tok.span,
2442 });
2443 }
2444 };
2445 let oparen2 = self.scanner.popt()?.ok_or_else(|| ScanError {
2447 message: "expected '(' before net name".to_string(),
2448 span: Span {
2449 start: self.scanner.pos,
2450 limit: self.scanner.pos,
2451 },
2452 })?;
2453 if !matches!(oparen2.payload, TokenPayload::OParen) {
2454 return Err(ScanError {
2455 message: "expected '(' before net name".to_string(),
2456 span: oparen2.span,
2457 });
2458 }
2459 loop {
2462 let peek = self.scanner.peekt()?;
2463 match peek {
2464 Some(tok) => match &tok.payload {
2465 TokenPayload::Comment(_) | TokenPayload::Annotation { .. } => {
2466 self.scanner.popt()?;
2467 }
2468 _ => break,
2469 },
2470 None => break,
2471 }
2472 }
2473 let is_unconnected = matches!(self.scanner.peekt()?, Some(tok) if matches!(tok.payload, TokenPayload::CParen));
2475 let net_ref = if is_unconnected {
2476 NetRef::Unconnected
2477 } else {
2478 self.parse_netref_expr()?
2479 };
2480 let cparen2 = self.scanner.popt()?.ok_or_else(|| ScanError {
2482 message: "expected ')' after net name".to_string(),
2483 span: Span {
2484 start: self.scanner.pos,
2485 limit: self.scanner.pos,
2486 },
2487 })?;
2488 if !matches!(cparen2.payload, TokenPayload::CParen) {
2489 return Err(ScanError {
2490 message: "expected ')' after net name".to_string(),
2491 span: cparen2.span,
2492 });
2493 }
2494 connections.push((port, net_ref));
2495 if let Some(next) = self.scanner.peekt()? {
2497 if matches!(next.payload, TokenPayload::Comma) {
2498 self.scanner.popt()?; continue;
2500 }
2501 }
2502 let cparen = self.scanner.popt()?.ok_or_else(|| ScanError {
2504 message: "expected ')' after instance connections".to_string(),
2505 span: Span {
2506 start: self.scanner.pos,
2507 limit: self.scanner.pos,
2508 },
2509 })?;
2510 if !matches!(cparen.payload, TokenPayload::CParen) {
2511 return Err(ScanError {
2512 message: "expected ')' after instance connections".to_string(),
2513 span: cparen.span,
2514 });
2515 }
2516 break;
2517 }
2518 let semi = self.scanner.popt()?.ok_or_else(|| ScanError {
2520 message: "expected ';' after instance".to_string(),
2521 span: Span {
2522 start: self.scanner.pos,
2523 limit: self.scanner.pos,
2524 },
2525 })?;
2526 if !matches!(semi.payload, TokenPayload::Semi) {
2527 return Err(ScanError {
2528 message: "expected ';' after instance".to_string(),
2529 span: semi.span,
2530 });
2531 }
2532 Ok(NetlistInstance {
2533 type_name,
2534 instance_name,
2535 connections,
2536 inst_lineno: inst_tok.span.start.lineno,
2537 inst_colno: inst_tok.span.start.colno,
2538 })
2539 }
2540
2541 pub fn get_line(&self, lineno: u32) -> Option<String> {
2544 (self.scanner.line_lookup)(lineno)
2545 }
2546}
2547
2548#[cfg(test)]
2549mod tests {
2550 use super::*;
2551 #[test]
2554 fn test_token_scanner_oparen() {
2555 let input = "(";
2556 let mut scanner = TokenScanner::from_str(input);
2557 let t = scanner.popt().expect("no scan error").unwrap();
2558 assert!(matches!(t.payload, TokenPayload::OParen));
2559 assert!(scanner.popt().expect("no scan error").is_none());
2560 }
2561
2562 #[test]
2563 fn test_token_scanner_cparen() {
2564 let input = ")";
2565 let mut scanner = TokenScanner::from_str(input);
2566 let t = scanner.popt().expect("no scan error").unwrap();
2567 assert!(matches!(t.payload, TokenPayload::CParen));
2568 assert!(scanner.popt().expect("no scan error").is_none());
2569 }
2570
2571 #[test]
2572 fn test_token_scanner_semi() {
2573 let input = ";";
2574 let mut scanner = TokenScanner::from_str(input);
2575 let t = scanner.popt().expect("no scan error").unwrap();
2576 assert!(matches!(t.payload, TokenPayload::Semi));
2577 assert!(scanner.popt().expect("no scan error").is_none());
2578 }
2579
2580 #[test]
2581 fn test_token_scanner_line_comment() {
2582 let input = "// hello world\n";
2583 let mut scanner = TokenScanner::from_str(input);
2584 let t = scanner.popt().expect("no scan error").unwrap();
2585 assert!(matches!(t.payload, TokenPayload::Comment(ref s) if s == " hello world"));
2586 assert!(scanner.popt().expect("no scan error").is_none());
2587 }
2588
2589 #[test]
2590 fn test_parse_module_with_assign_literal_bit() {
2591 let src = r#"
2592module m(a, out);
2593 input a;
2594 output [3:0] out;
2595 assign out[1] = 1'b0;
2596endmodule
2597"#;
2598 let mut parser = Parser::new(TokenScanner::from_str(src));
2599 let modules = parser.parse_file().expect("parse ok");
2600 assert_eq!(modules.len(), 1);
2601 assert_eq!(modules[0].assigns.len(), 1);
2602 assert_eq!(modules[0].assigns[0].kind, NetlistAssignKind::Continuous);
2603 assert!(matches!(modules[0].assigns[0].lhs, NetRef::BitSelect(_, 1)));
2604 assert!(matches!(
2605 modules[0].assigns[0].rhs,
2606 AssignExpr::Leaf(NetRef::Literal(_))
2607 ));
2608 }
2609
2610 #[test]
2611 fn test_parse_module_accepts_unnamed_tran() {
2612 let src = r#"
2613module m(a, y);
2614 input a;
2615 output y;
2616 wire a;
2617 wire y;
2618 tran(y, a);
2619endmodule
2620"#;
2621 let mut parser = Parser::new(TokenScanner::from_str(src));
2622 let modules = parser.parse_file().expect("tran should parse");
2623 assert_eq!(modules[0].assigns.len(), 1);
2624 assert_eq!(modules[0].assigns[0].kind, NetlistAssignKind::Tran);
2625 assert!(matches!(modules[0].assigns[0].lhs, NetRef::Simple(_)));
2626 assert!(matches!(
2627 modules[0].assigns[0].rhs,
2628 AssignExpr::Leaf(NetRef::Simple(_))
2629 ));
2630 }
2631
2632 #[test]
2633 fn test_parse_module_accepts_named_arrayed_tran() {
2634 let src = r#"
2635module m(a, y);
2636 input [1:0] a;
2637 output [1:0] y;
2638 wire [1:0] a;
2639 wire [1:0] y;
2640 tran t[1:0]({y[1], y[0]}, {a[1], a[0]});
2641endmodule
2642"#;
2643 let mut parser = Parser::new(TokenScanner::from_str(src));
2644 let modules = parser.parse_file().expect("arrayed tran should parse");
2645 assert_eq!(modules[0].assigns.len(), 1);
2646 assert_eq!(modules[0].assigns[0].kind, NetlistAssignKind::Tran);
2647 assert!(matches!(modules[0].assigns[0].lhs, NetRef::Concat(_)));
2648 assert!(matches!(
2649 modules[0].assigns[0].rhs,
2650 AssignExpr::Leaf(NetRef::Concat(_))
2651 ));
2652 }
2653
2654 #[test]
2655 fn test_parse_module_with_assign_literal_partselect() {
2656 let src = r#"
2657module m(a, out);
2658 input a;
2659 output [7:0] out;
2660 assign out[7:4] = 4'h0;
2661endmodule
2662"#;
2663 let mut parser = Parser::new(TokenScanner::from_str(src));
2664 let modules = parser.parse_file().expect("parse ok");
2665 assert_eq!(modules.len(), 1);
2666 assert_eq!(modules[0].assigns.len(), 1);
2667 assert!(matches!(
2668 modules[0].assigns[0].lhs,
2669 NetRef::PartSelect(_, 7, 4)
2670 ));
2671 }
2672
2673 #[test]
2674 fn test_parse_module_with_unary_assign_expression() {
2675 let src = r#"
2676module m(a, y);
2677 input a;
2678 output y;
2679 assign y = ~a;
2680endmodule
2681"#;
2682 let mut parser = Parser::new(TokenScanner::from_str(src));
2683 let modules = parser.parse_file().expect("parse ok");
2684 assert_eq!(modules.len(), 1);
2685 assert_eq!(modules[0].assigns.len(), 1);
2686 match &modules[0].assigns[0].rhs {
2687 AssignExpr::Not(inner) => {
2688 assert!(matches!(
2689 inner.as_ref(),
2690 AssignExpr::Leaf(NetRef::Simple(_))
2691 ));
2692 }
2693 other => panic!("expected unary-not assign, got {:?}", other),
2694 }
2695 }
2696
2697 #[test]
2698 fn test_parse_module_with_operator_precedence_in_assign_expression() {
2699 let src = r#"
2700module m(a, b, c, d, y);
2701 input a;
2702 input b;
2703 input c;
2704 input d;
2705 output y;
2706 assign y = a | b ^ c & ~d;
2707endmodule
2708"#;
2709 let mut parser = Parser::new(TokenScanner::from_str(src));
2710 let modules = parser.parse_file().expect("parse ok");
2711 let rhs = &modules[0].assigns[0].rhs;
2712 match rhs {
2713 AssignExpr::Or(lhs, rhs) => {
2714 assert!(matches!(lhs.as_ref(), AssignExpr::Leaf(NetRef::Simple(_))));
2715 match rhs.as_ref() {
2716 AssignExpr::Xor(xor_lhs, xor_rhs) => {
2717 assert!(matches!(
2718 xor_lhs.as_ref(),
2719 AssignExpr::Leaf(NetRef::Simple(_))
2720 ));
2721 match xor_rhs.as_ref() {
2722 AssignExpr::And(and_lhs, and_rhs) => {
2723 assert!(matches!(
2724 and_lhs.as_ref(),
2725 AssignExpr::Leaf(NetRef::Simple(_))
2726 ));
2727 match and_rhs.as_ref() {
2728 AssignExpr::Not(not_inner) => {
2729 assert!(matches!(
2730 not_inner.as_ref(),
2731 AssignExpr::Leaf(NetRef::Simple(_))
2732 ));
2733 }
2734 other => panic!("expected unary-not, got {:?}", other),
2735 }
2736 }
2737 other => panic!("expected and-expression, got {:?}", other),
2738 }
2739 }
2740 other => panic!("expected xor-expression, got {:?}", other),
2741 }
2742 }
2743 other => panic!("expected top-level or-expression, got {:?}", other),
2744 }
2745 }
2746
2747 #[test]
2748 fn test_parse_module_with_parenthesized_assign_expression() {
2749 let src = r#"
2750module m(a, b, c, y);
2751 input a;
2752 input b;
2753 input c;
2754 output y;
2755 assign y = (a | b) ^ c;
2756endmodule
2757"#;
2758 let mut parser = Parser::new(TokenScanner::from_str(src));
2759 let modules = parser.parse_file().expect("parse ok");
2760 let rhs = &modules[0].assigns[0].rhs;
2761 match rhs {
2762 AssignExpr::Xor(lhs, rhs) => {
2763 match lhs.as_ref() {
2764 AssignExpr::Or(or_lhs, or_rhs) => {
2765 assert!(matches!(
2766 or_lhs.as_ref(),
2767 AssignExpr::Leaf(NetRef::Simple(_))
2768 ));
2769 assert!(matches!(
2770 or_rhs.as_ref(),
2771 AssignExpr::Leaf(NetRef::Simple(_))
2772 ));
2773 }
2774 other => panic!("expected parenthesized or-expression, got {:?}", other),
2775 }
2776 assert!(matches!(rhs.as_ref(), AssignExpr::Leaf(NetRef::Simple(_))));
2777 }
2778 other => panic!("expected top-level xor-expression, got {:?}", other),
2779 }
2780 }
2781
2782 #[test]
2783 fn test_parse_module_with_selects_in_assign_expression() {
2784 let src = r#"
2785module m(a, b, y);
2786 input [7:0] a;
2787 input [3:0] b;
2788 output [3:0] y;
2789 assign y[3:0] = a[7:4] & b[3:0];
2790endmodule
2791"#;
2792 let mut parser = Parser::new(TokenScanner::from_str(src));
2793 let modules = parser.parse_file().expect("parse ok");
2794 assert!(matches!(
2795 modules[0].assigns[0].lhs,
2796 NetRef::PartSelect(_, 3, 0)
2797 ));
2798 match &modules[0].assigns[0].rhs {
2799 AssignExpr::And(lhs, rhs) => {
2800 assert!(matches!(
2801 lhs.as_ref(),
2802 AssignExpr::Leaf(NetRef::PartSelect(_, 7, 4))
2803 ));
2804 assert!(matches!(
2805 rhs.as_ref(),
2806 AssignExpr::Leaf(NetRef::PartSelect(_, 3, 0))
2807 ));
2808 }
2809 other => panic!(
2810 "expected and-expression with part-select leaves, got {:?}",
2811 other
2812 ),
2813 }
2814 }
2815
2816 #[test]
2817 fn test_parse_module_accepts_concat_in_assign_expression() {
2818 let src = r#"
2819module m(a, b, y);
2820 input a;
2821 input b;
2822 output [1:0] y;
2823 assign y = {a, b};
2824endmodule
2825"#;
2826 let mut parser = Parser::new(TokenScanner::from_str(src));
2827 let modules = parser.parse_file().expect("concat assign should parse");
2828 match &modules[0].assigns[0].rhs {
2829 AssignExpr::Leaf(NetRef::Concat(elems)) => assert_eq!(elems.len(), 2),
2830 other => panic!("expected concat assign RHS, got {:?}", other),
2831 }
2832 }
2833
2834 #[test]
2835 fn test_parse_module_accepts_concat_on_assign_lhs() {
2836 let src = r#"
2837module m(a, b, y);
2838 input a;
2839 input b;
2840 output [1:0] y;
2841 assign {y[1], y[0]} = {a, b};
2842endmodule
2843"#;
2844 let mut parser = Parser::new(TokenScanner::from_str(src));
2845 let modules = parser.parse_file().expect("concat assign lhs should parse");
2846 match &modules[0].assigns[0].lhs {
2847 NetRef::Concat(elems) => assert_eq!(elems.len(), 2),
2848 other => panic!("expected concat assign LHS, got {:?}", other),
2849 }
2850 }
2851
2852 #[test]
2853 fn test_parse_module_accepts_unknown_literal_in_assign() {
2854 let src = r#"
2855module m(y);
2856 output y;
2857 assign y = 1'hx;
2858endmodule
2859"#;
2860 let mut parser = Parser::new(TokenScanner::from_str(src));
2861 let modules = parser
2862 .parse_file()
2863 .expect("unknown literal assign should parse");
2864 assert!(matches!(
2865 modules[0].assigns[0].rhs,
2866 AssignExpr::Leaf(NetRef::UnknownLiteral(1))
2867 ));
2868 }
2869
2870 #[test]
2871 fn test_instance_source_position_is_captured() {
2872 let src = r#"
2873module m(a, b);
2874 input a;
2875 output b;
2876 wire a, b;
2877 INV u1 (.A(a), .Y(b));
2878endmodule
2879"#;
2880 let mut parser = Parser::new(TokenScanner::from_str(src));
2881 let modules = parser.parse_file().expect("parse ok");
2882 assert_eq!(modules.len(), 1);
2883 let m = &modules[0];
2884 assert_eq!(m.instances.len(), 1);
2885 let inst = &m.instances[0];
2886 assert_eq!(inst.inst_lineno, 6);
2889 assert_eq!(inst.inst_colno, 7);
2890 }
2891
2892 #[test]
2893 fn test_parse_instance_with_empty_port_list() {
2894 let src = r#"
2895module top();
2896 DUMMY_CELL u0 ();
2897endmodule
2898"#;
2899 let mut parser = Parser::new(TokenScanner::from_str(src));
2900 let modules = parser.parse_file().expect("parse ok");
2901 assert_eq!(modules.len(), 1);
2902 let m = &modules[0];
2903 assert_eq!(m.instances.len(), 1);
2904 assert!(m.instances[0].connections.is_empty());
2905 }
2906
2907 #[test]
2908 fn test_parse_instance_with_concat_expr() {
2909 let src = r#"
2910module top(a, b, c);
2911 input a;
2912 input b;
2913 input c;
2914 wire a, b, c;
2915 TYPE u1 (.MY_PORT({a, b, c}));
2916endmodule
2917"#;
2918 let mut parser = Parser::new(TokenScanner::from_str(src));
2919 let modules = parser.parse_file().expect("parse ok");
2920 assert_eq!(modules.len(), 1);
2921 let insts = &modules[0].instances;
2922 assert_eq!(insts.len(), 1);
2923 let (_p, netref) = &insts[0].connections[0];
2924 match netref {
2925 NetRef::Concat(v) => {
2926 assert_eq!(v.len(), 3);
2927 for r in v {
2928 match r {
2929 NetRef::Simple(_) => {}
2930 other => panic!("expected Simple, got {:?}", other),
2931 }
2932 }
2933 }
2934 other => panic!("expected Concat, got {:?}", other),
2935 }
2936 }
2937
2938 #[test]
2939 fn test_token_scanner_block_comment_only() {
2940 let input = "/* block comment */";
2941 let mut scanner = TokenScanner::from_str(input);
2942 assert!(scanner.popt().expect("no scan error").is_none());
2943 }
2944
2945 #[test]
2946 fn test_token_scanner_block_comment_between_tokens() {
2947 let input = "( /* block comment */ )";
2948 let mut scanner = TokenScanner::from_str(input);
2949 let t1 = scanner.popt().expect("no scan error").unwrap();
2950 assert!(matches!(t1.payload, TokenPayload::OParen));
2951 let t2 = scanner.popt().expect("no scan error").unwrap();
2952 assert!(matches!(t2.payload, TokenPayload::CParen));
2953 assert!(scanner.popt().expect("no scan error").is_none());
2954 }
2955
2956 #[test]
2957 #[should_panic(expected = "ScanError")] fn test_token_scanner_error_on_unknown() {
2959 let input = "@";
2960 let mut scanner = TokenScanner::from_str(input);
2961 scanner.popt().unwrap();
2962 }
2963
2964 #[test]
2965 fn test_token_scanner_annotation() {
2966 let input = r#"(* src = "foo.sv" *)"#;
2967 let mut scanner = TokenScanner::from_str(input);
2968 let t = scanner.popt().expect("no scan error").unwrap();
2969 match t.payload {
2970 TokenPayload::Annotation { ref key, ref value } => {
2971 assert_eq!(key, "src");
2972 match value {
2973 AnnotationValue::String(s) => assert_eq!(s, "foo.sv"),
2974 _ => panic!("Expected string annotation value"),
2975 }
2976 }
2977 _ => panic!("Expected annotation token"),
2978 }
2979 assert!(scanner.popt().expect("no scan error").is_none());
2980 }
2981
2982 #[test]
2983 fn test_token_scanner_keyword() {
2984 let input = "module";
2985 let mut scanner = TokenScanner::from_str(input);
2986 let t = scanner.popt().expect("no scan error").unwrap();
2987 assert!(matches!(t.payload, TokenPayload::Keyword(Keyword::Module)));
2988 assert!(scanner.popt().expect("no scan error").is_none());
2989 }
2990
2991 #[test]
2992 fn test_token_scanner_identifier() {
2993 let input = "foo_bar123";
2994 let mut scanner = TokenScanner::from_str(input);
2995 let t = scanner.popt().expect("no scan error").unwrap();
2996 assert!(matches!(t.payload, TokenPayload::Identifier(ref s) if s == "foo_bar123"));
2997 assert!(scanner.popt().expect("no scan error").is_none());
2998 }
2999
3000 #[test]
3001 fn test_token_scanner_comma() {
3002 let input = ",";
3003 let mut scanner = TokenScanner::from_str(input);
3004 let t = scanner.popt().expect("no scan error").unwrap();
3005 assert!(matches!(t.payload, TokenPayload::Comma));
3006 assert!(scanner.popt().expect("no scan error").is_none());
3007 }
3008
3009 #[test]
3010 fn test_token_scanner_annotation_binary() {
3011 let input = r#"(* force_downto = 32'b00000000000000000000000000000001 *)"#;
3012 let mut scanner = TokenScanner::from_str(input);
3013 let t = scanner.popt().expect("no scan error").unwrap();
3014 match t.payload {
3015 TokenPayload::Annotation { ref key, ref value } => {
3016 assert_eq!(key, "force_downto");
3017 match value {
3018 AnnotationValue::VerilogInt { width, value } => {
3019 assert_eq!(*width, Some(32));
3020 assert_eq!(value.get_bit_count(), 32);
3021 assert_eq!(value.to_string(), "bits[32]:1");
3022 }
3023 _ => panic!("Expected VerilogInt annotation value"),
3024 }
3025 }
3026 _ => panic!("Expected annotation token"),
3027 }
3028 assert!(scanner.popt().expect("no scan error").is_none());
3029 }
3030
3031 #[test]
3032 fn test_token_scanner_verilog_int_annotation() {
3033 let input = r#"(* force_downto = 32'b00000000000000000000000000000001 *)"#;
3034 let mut scanner = TokenScanner::from_str(input);
3035 let t = scanner.popt().expect("no scan error").unwrap();
3036 match t.payload {
3037 TokenPayload::Annotation { ref key, ref value } => {
3038 assert_eq!(key, "force_downto");
3039 match value {
3040 AnnotationValue::VerilogInt { width, value } => {
3041 assert_eq!(*width, Some(32));
3042 assert_eq!(value.get_bit_count(), 32);
3043 assert_eq!(value.to_string(), "bits[32]:1");
3044 }
3045 _ => panic!("Expected VerilogInt annotation value"),
3046 }
3047 }
3048 _ => panic!("Expected annotation token"),
3049 }
3050 assert!(scanner.popt().expect("no scan error").is_none());
3051 }
3052
3053 #[test]
3054 fn test_token_scanner_stub() {
3055 let input = "( ) ; // comment\n)";
3056 let mut scanner = TokenScanner::from_str(input);
3057 let t1 = scanner.popt().expect("no scan error").unwrap();
3058 assert!(matches!(t1.payload, TokenPayload::OParen));
3059 let t2 = scanner.popt().expect("no scan error").unwrap();
3060 assert!(matches!(t2.payload, TokenPayload::CParen));
3061 let t3 = scanner.popt().expect("no scan error").unwrap();
3062 assert!(matches!(t3.payload, TokenPayload::Semi));
3063 let t4 = scanner.popt().expect("no scan error").unwrap();
3064 assert!(matches!(t4.payload, TokenPayload::Comment(ref s) if s == " comment"));
3065 let t5 = scanner.popt().expect("no scan error").unwrap();
3066 assert!(matches!(t5.payload, TokenPayload::CParen));
3067 assert!(scanner.popt().expect("no scan error").is_none());
3068 }
3069
3070 #[test]
3071 fn test_token_scanner_input_declaration() {
3072 let input = "input [255:0] a;";
3073 let mut scanner = TokenScanner::from_str(input);
3074 let t1 = scanner.popt().expect("no scan error").unwrap();
3076 match t1.payload {
3077 TokenPayload::Identifier(ref s) => assert_eq!(s, "input"),
3078 TokenPayload::Keyword(_) => assert_eq!(format!("{:?}", t1.payload), "Keyword(Input)"),
3079 _ => panic!("Expected identifier or keyword for 'input'"),
3080 }
3081 let t2 = scanner.popt().expect("no scan error").unwrap();
3082 assert!(matches!(t2.payload, TokenPayload::OBrack));
3083 let t3 = scanner.popt().expect("no scan error").unwrap();
3084 match t3.payload {
3085 TokenPayload::VerilogInt { width, ref value } => {
3086 assert_eq!(width, None);
3087 assert_eq!(value.get_bit_count(), 32); assert_eq!(value.to_string(), "bits[32]:255");
3089 }
3090 _ => panic!("Expected VerilogInt for 255"),
3091 }
3092 let t4 = scanner.popt().expect("no scan error").unwrap();
3094 assert!(matches!(t4.payload, TokenPayload::Colon));
3095 let t5 = scanner.popt().expect("no scan error").unwrap();
3096 match t5.payload {
3097 TokenPayload::VerilogInt { width, ref value } => {
3098 assert_eq!(width, None);
3099 assert_eq!(value.get_bit_count(), 32); assert_eq!(value.to_string(), "bits[32]:0");
3101 }
3102 _ => panic!("Expected VerilogInt for 0"),
3103 }
3104 let t6 = scanner.popt().expect("no scan error").unwrap();
3105 assert!(matches!(t6.payload, TokenPayload::CBrack));
3106 let t7 = scanner.popt().expect("no scan error").unwrap();
3107 assert!(matches!(t7.payload, TokenPayload::Identifier(ref s) if s == "a"));
3108 let t8 = scanner.popt().expect("no scan error").unwrap();
3109 assert!(matches!(t8.payload, TokenPayload::Semi));
3110 assert!(scanner.popt().expect("no scan error").is_none());
3111 }
3112
3113 #[test]
3114 fn test_token_scanner_annotation_tokenization() {
3115 let input = r#"(* foo = "bar" *)"#;
3116 let mut scanner = TokenScanner::from_str(input);
3117 let t = scanner.popt().expect("no scan error").unwrap();
3118 match t.payload {
3119 TokenPayload::Annotation { ref key, ref value } => {
3120 assert_eq!(key, "foo");
3121 match value {
3122 AnnotationValue::String(s) => assert_eq!(s, "bar"),
3123 _ => panic!("Expected string annotation value"),
3124 }
3125 }
3126 _ => panic!("Expected annotation token"),
3127 }
3128 assert!(scanner.popt().expect("no scan error").is_none());
3129 }
3130
3131 #[test]
3132 fn test_token_scanner_annotation_with_leading_whitespace() {
3133 let input = r#" (* foo = "bar" *)"#;
3134 let mut scanner = TokenScanner::from_str(input);
3135 let t = scanner.popt().expect("no scan error").unwrap();
3136 match t.payload {
3137 TokenPayload::Annotation { ref key, ref value } => {
3138 assert_eq!(key, "foo");
3139 match value {
3140 AnnotationValue::String(s) => assert_eq!(s, "bar"),
3141 _ => panic!("Expected string annotation value"),
3142 }
3143 }
3144 _ => panic!("Expected annotation token"),
3145 }
3146 assert!(scanner.popt().expect("no scan error").is_none());
3147 }
3148
3149 #[test]
3150 fn test_skip_timescale_at_top() {
3151 let src = "`timescale 10ps/10ps\nmodule m(); endmodule\n";
3152 let mut parser = Parser::new(TokenScanner::from_str(src));
3153 let modules = parser.parse_file().expect("parse ok");
3154 assert_eq!(modules.len(), 1);
3155 }
3156
3157 #[test]
3158 fn test_skip_timescale_with_leading_spaces() {
3159 let src = " `timescale 1ns/1ps\nmodule m(); endmodule\n";
3160 let mut parser = Parser::new(TokenScanner::from_str(src));
3161 let modules = parser.parse_file().expect("parse ok");
3162 assert_eq!(modules.len(), 1);
3163 }
3164
3165 #[test]
3166 fn test_skip_timescale_after_comment() {
3167 let src = "// comment\n`timescale 1ns/1ps\nmodule m(); endmodule\n";
3168 let mut parser = Parser::new(TokenScanner::from_str(src));
3169 let modules = parser.parse_file().expect("parse ok");
3170 assert_eq!(modules.len(), 1);
3171 }
3172
3173 #[test]
3174 fn test_skip_timescale_inside_module() {
3175 let src = "module m();\n`timescale 1ns/1ps\nendmodule\n";
3176 let mut parser = Parser::new(TokenScanner::from_str(src));
3177 let modules = parser.parse_file().expect("parse ok");
3178 assert_eq!(modules.len(), 1);
3179 }
3180
3181 #[test]
3182 fn test_token_scanner_endmodule_keyword() {
3183 let input = "endmodule";
3184 let mut scanner = TokenScanner::from_str(input);
3185 let t = scanner.popt().expect("no scan error").unwrap();
3186 assert!(matches!(
3187 t.payload,
3188 TokenPayload::Keyword(Keyword::Endmodule)
3189 ));
3190 assert!(scanner.popt().expect("no scan error").is_none());
3191 }
3192
3193 #[test]
3194 fn test_parse_wire_decl_with_width() {
3195 let input = "wire [7:0] foo, bar;";
3196 let mut parser = Parser::new(TokenScanner::from_str(input));
3197 let net_indices = parser.parse_wire_decl().expect("no error");
3198 assert_eq!(net_indices.len(), 2);
3199 let foo = &parser.nets[net_indices[0].0];
3200 let bar = &parser.nets[net_indices[1].0];
3201 assert_eq!(foo.width, Some((7, 0)));
3202 assert_eq!(bar.width, Some((7, 0)));
3203 }
3204
3205 #[test]
3206 fn test_parse_wire_decl_without_width() {
3207 let input = "wire foo, bar;";
3208 let mut parser = Parser::new(TokenScanner::from_str(input));
3209 let net_indices = parser.parse_wire_decl().expect("no error");
3210 assert_eq!(net_indices.len(), 2);
3211 let foo = &parser.nets[net_indices[0].0];
3212 let bar = &parser.nets[net_indices[1].0];
3213 assert_eq!(foo.width, None);
3214 assert_eq!(bar.width, None);
3215 }
3216
3217 #[test]
3218 fn test_parse_wire_decl_real_world_examples() {
3219 let input = "wire [255:0] a;";
3221 let mut parser = Parser::new(TokenScanner::from_str(input));
3222 let net_indices = parser.parse_wire_decl().expect("no error");
3223 assert_eq!(net_indices.len(), 1);
3224 let a = &parser.nets[net_indices[0].0];
3225 assert_eq!(a.width, Some((255, 0)));
3226
3227 let input = "wire clk;";
3229 let mut parser = Parser::new(TokenScanner::from_str(input));
3230 let net_indices = parser.parse_wire_decl().expect("no error");
3231 assert_eq!(net_indices.len(), 1);
3232 let clk = &parser.nets[net_indices[0].0];
3233 assert_eq!(clk.width, None);
3234
3235 let input = "wire [26:0] out;";
3237 let mut parser = Parser::new(TokenScanner::from_str(input));
3238 let net_indices = parser.parse_wire_decl().expect("no error");
3239 assert_eq!(net_indices.len(), 1);
3240 let out = &parser.nets[net_indices[0].0];
3241 assert_eq!(out.width, Some((26, 0)));
3242
3243 let input = "wire \\p0_umul_8[0] ;";
3245 let mut parser = Parser::new(TokenScanner::from_str(input));
3246 let net_indices = parser.parse_wire_decl().expect("no error");
3247 assert_eq!(net_indices.len(), 1);
3248 let p0_net = &parser.nets[net_indices[0].0];
3249 assert_eq!(
3250 parser.interner.resolve(p0_net.name).unwrap(),
3251 "p0_umul_8[0]"
3252 );
3253 assert_eq!(p0_net.width, None);
3254 }
3255
3256 #[test]
3257 fn test_parse_wire_decl_with_annotation_between() {
3258 let input = r#"(* src = "foo.sv:3.22-3.23" *)
3260wire [255:0] a;"#;
3261 let mut parser = Parser::new(TokenScanner::from_str(input));
3262 loop {
3264 let peek = parser.scanner.peekt().expect("no scan error");
3265 match peek {
3266 Some(tok) => match &tok.payload {
3267 TokenPayload::Annotation { .. } | TokenPayload::Comment(_) => {
3268 parser.scanner.popt().expect("no scan error");
3269 }
3270 TokenPayload::Keyword(Keyword::Wire) => break,
3271 _ => panic!("unexpected token before wire decl: {:?}", tok.payload),
3272 },
3273 None => panic!("unexpected EOF before wire decl"),
3274 }
3275 }
3276 let net_indices = parser.parse_wire_decl().expect("no error");
3278 assert_eq!(net_indices.len(), 1);
3279 let a = &parser.nets[net_indices[0].0];
3280 assert_eq!(a.width, Some((255, 0)));
3281 }
3282
3283 #[test]
3284 fn test_parse_instance_with_bit_and_part_select() {
3285 let mut parser = Parser::new(TokenScanner::from_str("wire [7:0] b;"));
3287 parser.parse_wire_decl().expect("no error");
3288 let input = "TypeName inst (.A(b));";
3290 let mut parser2 = Parser::new(TokenScanner::from_str(input));
3291 parser2.nets = parser.nets.clone();
3292 parser2.interner = parser.interner.clone();
3293 let inst = parser2.parse_instance().expect("no error");
3294 assert_eq!(inst.connections.len(), 1);
3295 match &inst.connections[0].1 {
3296 NetRef::Simple(_) => {}
3297 _ => panic!("Expected Simple net ref"),
3298 }
3299 let input = "TypeName inst (.A(b[5]));";
3301 let mut parser3 = Parser::new(TokenScanner::from_str(input));
3302 parser3.nets = parser.nets.clone();
3303 parser3.interner = parser.interner.clone();
3304 let inst = parser3.parse_instance().expect("no error");
3305 assert_eq!(inst.connections.len(), 1);
3306 match &inst.connections[0].1 {
3307 NetRef::BitSelect(_, idx) => assert_eq!(*idx, 5),
3308 _ => panic!("Expected BitSelect net ref"),
3309 }
3310 let input = "TypeName inst (.A(b[7:0]));";
3312 let mut parser4 = Parser::new(TokenScanner::from_str(input));
3313 parser4.nets = parser.nets.clone();
3314 parser4.interner = parser.interner.clone();
3315 let inst = parser4.parse_instance().expect("no error");
3316 assert_eq!(inst.connections.len(), 1);
3317 match &inst.connections[0].1 {
3318 NetRef::PartSelect(_, msb, lsb) => {
3319 assert_eq!((*msb, *lsb), (7, 0));
3320 }
3321 _ => panic!("Expected PartSelect net ref"),
3322 }
3323 }
3324
3325 #[test]
3326 fn test_token_scanner_escaped_identifier() {
3327 let input = "\\escaped-ident ;";
3328 let mut scanner = TokenScanner::from_str(input);
3329 let t1 = scanner.popt().expect("no scan error").unwrap();
3330 assert!(matches!(t1.payload, TokenPayload::Identifier(ref s) if s == "escaped-ident"));
3331 let t2 = scanner.popt().expect("no scan error").unwrap();
3332 assert!(matches!(t2.payload, TokenPayload::Semi));
3333 assert!(scanner.popt().expect("no scan error").is_none());
3334 }
3335
3336 #[test]
3337 fn test_token_scanner_escaped_identifier_with_special_chars() {
3338 let input = "\\!@#$%^&*()-+= ;";
3339 let mut scanner = TokenScanner::from_str(input);
3340 let t1 = scanner.popt().expect("no scan error").unwrap();
3341 assert!(matches!(t1.payload, TokenPayload::Identifier(ref s) if s == "!@#$%^&*()-+="));
3342 let t2 = scanner.popt().expect("no scan error").unwrap();
3343 assert!(matches!(t2.payload, TokenPayload::Semi));
3344 assert!(scanner.popt().expect("no scan error").is_none());
3345 }
3346
3347 #[test]
3348 fn test_token_scanner_escaped_identifier_named_like_keyword() {
3349 let input = "\\module ;";
3350 let mut scanner = TokenScanner::from_str(input);
3351 let t1 = scanner.popt().expect("no scan error").unwrap();
3352 assert!(matches!(t1.payload, TokenPayload::Identifier(ref s) if s == "module"));
3353 let t2 = scanner.popt().expect("no scan error").unwrap();
3354 assert!(matches!(t2.payload, TokenPayload::Semi));
3355 assert!(scanner.popt().expect("no scan error").is_none());
3356 }
3357
3358 #[test]
3359 fn test_token_scanner_escaped_identifier_leading_backslash_from_error() {
3360 let input = "\\p0_umul_8[0] ;";
3363 let mut scanner = TokenScanner::from_str(input);
3364 let t = scanner.popt().expect("no scan error").unwrap();
3365 assert!(matches!(t.payload, TokenPayload::Identifier(ref s) if s == "p0_umul_8[0]"));
3366 assert!(scanner.popt().expect("no scan error").unwrap().payload == TokenPayload::Semi);
3367 assert!(scanner.popt().expect("no scan error").is_none());
3368 }
3369
3370 #[test]
3371 fn test_parse_instance_with_literal_tieoff() {
3372 let mut parser = Parser::new(TokenScanner::from_str("wire b;"));
3374 parser.parse_wire_decl().expect("no error");
3375 let input = "TypeName inst (.A(1'b0));";
3377 let mut parser2 = Parser::new(TokenScanner::from_str(input));
3378 parser2.nets = parser.nets.clone();
3379 parser2.interner = parser.interner.clone();
3380 let inst = parser2
3381 .parse_instance()
3382 .expect("should parse instance with literal tie-off");
3383 assert_eq!(inst.connections.len(), 1);
3384 let (port, netref) = &inst.connections[0];
3385 let port_name = parser2.interner.resolve(*port).unwrap();
3386 assert_eq!(port_name, "A");
3387 match netref {
3388 NetRef::Literal(bits) => {
3389 assert_eq!(bits.get_bit_count(), 1);
3391 assert_eq!(bits.to_string(), "bits[1]:0");
3392 }
3393 _ => panic!("Expected Literal net ref, got {:?}", netref),
3394 }
3395 }
3396
3397 #[test]
3398 fn test_token_scanner_verilog_style_literal() {
3399 let input = "1'b0 8'hFF 16'd42";
3400 let mut scanner = TokenScanner::from_str(input);
3401 let t1 = scanner.popt().expect("no scan error").unwrap();
3402 match t1.payload {
3403 TokenPayload::VerilogInt { width, ref value } => {
3404 assert_eq!(width, Some(1));
3405 assert_eq!(value.get_bit_count(), 1);
3406 assert_eq!(value.to_string(), "bits[1]:0");
3407 }
3408 _ => panic!("Expected VerilogInt for 1'b0"),
3409 }
3410 let t2 = scanner.popt().expect("no scan error").unwrap();
3411 match t2.payload {
3412 TokenPayload::VerilogInt { width, ref value } => {
3413 assert_eq!(width, Some(8));
3414 assert_eq!(value.get_bit_count(), 8);
3415 assert_eq!(value.to_string(), "bits[8]:255");
3416 }
3417 _ => panic!("Expected VerilogInt for 8'hFF"),
3418 }
3419
3420 let t3 = scanner.popt().expect("no scan error").unwrap();
3421 match t3.payload {
3422 TokenPayload::VerilogInt { width, ref value } => {
3423 assert_eq!(width, Some(16));
3424 assert_eq!(value.get_bit_count(), 16);
3425 assert_eq!(value.to_string(), "bits[16]:42");
3426 }
3427 _ => panic!("Expected VerilogInt for 16'd42"),
3428 }
3429 assert!(scanner.popt().expect("no scan error").is_none());
3430 }
3431
3432 #[test]
3433 fn test_implicit_net_created_on_use_in_instance_connection() {
3434 let src = r#"
3438module m(a, y);
3439 input a;
3440 output y;
3441 DummyCell u0 (.in_valid(a), .in(a), .out_valid(data_valid_d));
3442 DummyCell u1 (.in_valid(data_valid_d), .in(a), .out_valid(y));
3443endmodule
3444"#;
3445 let mut parser = Parser::new(TokenScanner::from_str(src));
3446 let modules = parser.parse_file().expect("parse ok");
3447 assert_eq!(modules.len(), 1);
3448 let dv_nets: Vec<&Net> = parser
3450 .nets
3451 .iter()
3452 .filter(|n| parser.interner.resolve(n.name).unwrap() == "data_valid_d")
3453 .collect();
3454 assert_eq!(dv_nets.len(), 1);
3455 assert_eq!(dv_nets[0].width, Some((0, 0)));
3456 }
3457
3458 #[test]
3459 fn test_assign_use_before_vector_port_declaration_upgrades_implicit_widths() {
3460 let src = r#"
3461module m(a, y);
3462 assign y[3:0] = a;
3463 input [3:0] a;
3464 output [3:0] y;
3465endmodule
3466"#;
3467 let mut parser = Parser::new(TokenScanner::from_str(src));
3468 let modules = parser.parse_file().expect("parse ok");
3469 assert_eq!(modules.len(), 1);
3470
3471 let a_nets: Vec<&Net> = parser
3472 .nets
3473 .iter()
3474 .filter(|n| parser.interner.resolve(n.name).unwrap() == "a")
3475 .collect();
3476 let y_nets: Vec<&Net> = parser
3477 .nets
3478 .iter()
3479 .filter(|n| parser.interner.resolve(n.name).unwrap() == "y")
3480 .collect();
3481 assert_eq!(a_nets.len(), 1);
3482 assert_eq!(y_nets.len(), 1);
3483 assert_eq!(a_nets[0].width, Some((3, 0)));
3484 assert_eq!(y_nets[0].width, Some((3, 0)));
3485 }
3486
3487 #[test]
3488 fn test_assign_use_before_vector_wire_declaration_upgrades_implicit_widths() {
3489 let src = r#"
3490module m(y);
3491 assign y = tmp;
3492 wire [3:0] tmp;
3493 output [3:0] y;
3494endmodule
3495"#;
3496 let mut parser = Parser::new(TokenScanner::from_str(src));
3497 let modules = parser.parse_file().expect("parse ok");
3498 assert_eq!(modules.len(), 1);
3499
3500 let tmp_nets: Vec<&Net> = parser
3501 .nets
3502 .iter()
3503 .filter(|n| parser.interner.resolve(n.name).unwrap() == "tmp")
3504 .collect();
3505 let y_nets: Vec<&Net> = parser
3506 .nets
3507 .iter()
3508 .filter(|n| parser.interner.resolve(n.name).unwrap() == "y")
3509 .collect();
3510 assert_eq!(tmp_nets.len(), 1);
3511 assert_eq!(y_nets.len(), 1);
3512 assert_eq!(tmp_nets[0].width, Some((3, 0)));
3513 assert_eq!(y_nets[0].width, Some((3, 0)));
3514 }
3515
3516 #[test]
3517 fn test_concat_with_trailing_verilog_literal_and_close_brace() {
3518 let src = r#"
3522module m(a, y);
3523 input [1:0] a;
3524 output [3:0] y;
3525 MYCELL u1 (.Y({a, 3'b0}));
3526endmodule
3527"#;
3528 let mut parser = Parser::new(TokenScanner::from_str(src));
3529 let modules = parser.parse_file().expect("parse ok");
3530 assert_eq!(modules.len(), 1);
3531 let insts = &modules[0].instances;
3532 assert_eq!(insts.len(), 1);
3533 let (port_sym, netref) = &insts[0].connections[0];
3534 let port_name = parser.interner.resolve(*port_sym).unwrap();
3535 assert_eq!(port_name, "Y");
3536 match netref {
3537 NetRef::Concat(elems) => {
3538 assert_eq!(elems.len(), 2);
3539 }
3540 other => panic!("expected Concat for .Y connection, got {:?}", other),
3541 }
3542 }
3543
3544 #[test]
3545 fn test_unknown_net_errors_when_implicit_nets_disabled() {
3546 let src = r#"
3549module m(a, y);
3550 input a;
3551 output y;
3552 DummyCell u0 (.in_valid(a), .in(a), .out_valid(data_valid_d));
3553endmodule
3554"#;
3555 let mut parser = Parser::new_with_options(
3556 TokenScanner::from_str(src),
3557 false,
3558 );
3559 let err = parser
3560 .parse_file()
3561 .expect_err("should error on unknown net");
3562 assert!(
3563 err.message.contains("not declared as wire"),
3564 "unexpected error message: {}",
3565 err.message
3566 );
3567 }
3568
3569 #[test]
3570 fn test_parse_instance_unconnected_output() {
3571 let src = r#"
3572module m(a, y);
3573 input a;
3574 output y;
3575 wire a, y;
3576 INVX1 u1 (.A(a), .Y());
3577endmodule
3578"#;
3579 let mut parser = Parser::new(TokenScanner::from_str(src));
3580 let modules = parser.parse_file().expect("parse ok");
3581 assert_eq!(modules.len(), 1);
3582 let insts = &modules[0].instances;
3583 assert_eq!(insts.len(), 1);
3584 let conn = &insts[0].connections[1].1;
3585 match conn {
3586 NetRef::Unconnected => {}
3587 _ => panic!("expected Unconnected for .Y()"),
3588 }
3589 }
3590
3591 #[test]
3592 fn test_parse_instance_unconnected_input_and_comments() {
3593 let src = r#"
3594module m(y);
3595 output y;
3596 wire y;
3597 AND2 u1 (.A(/*c*/ ), .B( // c
3598 ), .Y(y));
3599endmodule
3600"#;
3601 let mut parser = Parser::new(TokenScanner::from_str(src));
3602 let modules = parser.parse_file().expect("parse ok");
3603 assert_eq!(modules.len(), 1);
3604 let insts = &modules[0].instances;
3605 assert_eq!(insts.len(), 1);
3606 match &insts[0].connections[0].1 {
3608 NetRef::Unconnected => {}
3609 other => panic!("expected Unconnected for .A(), got {:?}", other),
3610 }
3611 match &insts[0].connections[1].1 {
3613 NetRef::Unconnected => {}
3614 other => panic!("expected Unconnected for .B(), got {:?}", other),
3615 }
3616 }
3617
3618 #[test]
3619 fn test_non_ansi_body_ports_create_nets() {
3620 let src = r#"
3621module m(a, y);
3622 input a;
3623 output y;
3624 INVX1 u1 (.A(a), .Y(y));
3625endmodule
3626"#;
3627 let mut parser = Parser::new(TokenScanner::from_str(src));
3628 let modules = parser.parse_file().expect("parse ok");
3629 assert_eq!(modules.len(), 1);
3630 let a_net = parser
3632 .nets
3633 .iter()
3634 .find(|n| parser.interner.resolve(n.name).unwrap() == "a")
3635 .unwrap();
3636 let y_net = parser
3637 .nets
3638 .iter()
3639 .find(|n| parser.interner.resolve(n.name).unwrap() == "y")
3640 .unwrap();
3641 assert_eq!(a_net.width, None);
3642 assert_eq!(y_net.width, None);
3643 }
3644
3645 #[test]
3646 fn test_non_ansi_ports_are_ordered_by_header_list() {
3647 let src = r#"
3648module m(p0, p1, p2, p3, p4, p5, p6);
3649 input p0, p1, p3;
3650 input [57:0] p2;
3651 input [14:0] p4, p5;
3652 output [18:0] p6;
3653endmodule
3654"#;
3655 let mut parser = Parser::new(TokenScanner::from_str(src));
3656 let modules = parser.parse_file().expect("parse ok");
3657 assert_eq!(modules.len(), 1);
3658 let port_names: Vec<String> = modules[0]
3659 .ports
3660 .iter()
3661 .map(|p| parser.interner.resolve(p.name).unwrap().to_string())
3662 .collect();
3663 assert_eq!(port_names, vec!["p0", "p1", "p2", "p3", "p4", "p5", "p6",]);
3664 assert_eq!(modules[0].ports[2].width, Some((57, 0)));
3665 assert_eq!(modules[0].ports[6].width, Some((18, 0)));
3666 }
3667
3668 #[test]
3669 fn test_non_ansi_vector_output_and_bitselect() {
3670 let src = r#"
3671module m(a, out);
3672 input a;
3673 output [7:0] out;
3674 Type inst (.A(out[3]));
3675endmodule
3676"#;
3677 let mut parser = Parser::new(TokenScanner::from_str(src));
3678 let modules = parser.parse_file().expect("parse ok");
3679 assert_eq!(modules.len(), 1);
3680 let out_net = parser
3681 .nets
3682 .iter()
3683 .find(|n| parser.interner.resolve(n.name).unwrap() == "out")
3684 .unwrap();
3685 assert_eq!(out_net.width, Some((7, 0)));
3686 let inst = &modules[0].instances[0];
3688 match inst.connections[0].1 {
3689 NetRef::BitSelect(_, idx) => assert_eq!(idx, 3),
3690 ref other => panic!("expected BitSelect, got {:?}", other),
3691 }
3692 }
3693
3694 #[test]
3695 fn test_duplicate_wire_after_port_decl_same_width_ok() {
3696 let src = r#"
3697module m(a);
3698 input [3:0] a;
3699 wire [3:0] a;
3700endmodule
3701"#;
3702 let mut parser = Parser::new(TokenScanner::from_str(src));
3703 let modules = parser.parse_file().expect("parse ok");
3704 assert_eq!(modules.len(), 1);
3705 let a_nets: Vec<&Net> = parser
3706 .nets
3707 .iter()
3708 .filter(|n| parser.interner.resolve(n.name).unwrap() == "a")
3709 .collect();
3710 assert_eq!(a_nets.len(), 1);
3711 assert_eq!(a_nets[0].width, Some((3, 0)));
3712 }
3713
3714 #[test]
3715 fn test_conflicting_widths_error() {
3716 let src = r#"
3717module m(out);
3718 output [7:0] out;
3719 wire [3:0] out;
3720endmodule
3721"#;
3722 let mut parser = Parser::new(TokenScanner::from_str(src));
3723 let err = parser
3724 .parse_file()
3725 .expect_err("should error on width conflict");
3726 assert!(err.message.contains("conflicting widths for net 'out'"));
3727 assert!(
3728 err.message.contains("previously determined width was"),
3729 "error message should mention previous width location for diagnostics: {}",
3730 err.message
3731 );
3732 }
3733
3734 #[test]
3735 fn test_conflicting_widths_across_modules_are_ok() {
3736 let src = r#"
3740module m1(gen_in);
3741 input [7:0] gen_in;
3742endmodule
3743
3744module m2(gen_in);
3745 input [3:0] gen_in;
3746endmodule
3747"#;
3748 let mut parser = Parser::new(TokenScanner::from_str(src));
3749 let modules = parser.parse_file().expect("parse should succeed");
3750 assert_eq!(modules.len(), 2);
3751 let gen_in_nets: Vec<&Net> = parser
3754 .nets
3755 .iter()
3756 .filter(|n| parser.interner.resolve(n.name).unwrap() == "gen_in")
3757 .collect();
3758 assert_eq!(gen_in_nets.len(), 2);
3759 assert!(gen_in_nets.iter().any(|n| n.width == Some((7, 0))));
3760 assert!(gen_in_nets.iter().any(|n| n.width == Some((3, 0))));
3761 }
3762}