1use crate::cat::*;
8use moore_common::errors::{DiagBuilder2, DiagResult2};
9use moore_common::source::*;
10use std::{collections::HashMap, fmt, path::Path, rc::Rc};
11
12use once_cell::sync::Lazy;
13
14type TokenAndSpan = (CatTokenKind, Span);
15
16pub struct Preprocessor<'a> {
17 stack: Vec<Stream<'a>>,
21 contents: Vec<Rc<dyn SourceContent>>,
26 token: Option<TokenAndSpan>,
29 macro_defs: HashMap<String, Macro>,
31 macro_stack: Vec<TokenAndSpan>,
33 include_paths: &'a [&'a Path],
36 defcond_stack: Vec<Defcond>,
40 dirs: Directives,
42}
43
44impl<'a> Preprocessor<'a> {
45 pub fn new(
47 source: Source,
48 include_paths: &'a [&'a Path],
49 macro_defs: &'a [(&'a str, Option<&'a str>)],
50 ) -> Preprocessor<'a> {
51 let content = source.get_content();
52 let content_unbound = unsafe { &*(content.as_ref() as *const dyn SourceContent) };
53 let iter = content_unbound.iter();
54 let macro_defs = macro_defs
55 .into_iter()
56 .map(|(name, value)| {
57 let body = match value {
58 Some(value) => {
59 let src = get_source_manager().add_anonymous(*value);
61 let span = Span::new(src, 0, value.len());
62 Cat::new(Box::new(value.char_indices()))
63 .map(|x| (x.0, span))
64 .collect()
65 }
66 None => Vec::new(),
67 };
68 (
69 name.to_string(),
70 Macro {
71 name: name.to_string(),
72 span: INVALID_SPAN,
73 args: Vec::new(),
74 body: body,
75 },
76 )
77 })
78 .collect();
79 Preprocessor {
80 stack: vec![Stream {
81 source: source,
82 iter: Cat::new(iter),
83 }],
84 contents: vec![content],
85 token: None,
86 macro_defs,
87 macro_stack: Vec::new(),
88 include_paths: include_paths,
89 defcond_stack: Vec::new(),
90 dirs: Default::default(),
91 }
92 }
93
94 fn bump(&mut self) {
96 self.token = self.macro_stack.pop();
97 if self.token.is_some() {
98 return;
99 }
100 loop {
101 self.token = match self.stack.last_mut() {
102 Some(stream) => stream
103 .iter
104 .next()
105 .map(|tkn| (tkn.0, Span::new(stream.source, tkn.1, tkn.2))),
106 None => return,
107 };
108 if self.token.is_none() {
109 self.stack.pop();
110 } else {
111 break;
112 }
113 }
114 }
115
116 fn handle_directive<S: AsRef<str>>(&mut self, dir_name: S, span: Span) -> DiagResult2<()> {
120 let dir_name = dir_name.as_ref();
121 let dir = DIRECTIVES_TABLE
122 .get(dir_name)
123 .map(|x| *x)
124 .unwrap_or(Directive::Unknown);
125
126 match dir {
127 Directive::Include => {
128 if self.is_inactive() {
129 return Ok(());
130 }
131
132 match self.token {
134 Some((Whitespace, _)) => self.bump(),
135 _ => (),
136 }
137
138 let name_p;
140 let name_q;
141 let closing =
142 match self.token {
143 Some((Symbol('"'), sp)) => {
144 name_p = sp.end();
145 self.bump();
146 '"'
147 }
148 Some((Symbol('<'), sp)) => {
149 name_p = sp.end();
150 self.bump();
151 '>'
152 }
153 _ => return Err(DiagBuilder2::fatal(
154 "expected filename inside double quotes (\"...\") or angular brackets \
155 (<...>) after `include",
156 )
157 .span(span)),
158 };
159
160 let mut filename = String::new();
162 loop {
163 match self.token {
164 Some((Symbol(c), sp)) if c == closing => {
165 name_q = sp.begin();
166 break;
167 }
168 Some((Newline, sp)) => {
169 return Err(DiagBuilder2::fatal(
170 "expected end of included file's name before line break",
171 )
172 .span(sp));
173 }
174 Some((_, sp)) => {
175 filename.push_str(&sp.extract());
176 self.bump();
177 }
178 None => {
179 return Err(DiagBuilder2::fatal(
180 "expected filename after `include directive before the end of the \
181 input",
182 )
183 .span(span));
184 }
185 }
186 }
187
188 let included_source = match self.open_include(&filename, &span.source.get_path()) {
192 Some(src) => src,
193 None => {
194 return Err(DiagBuilder2::fatal(format!(
196 "cannot open included file \"{}\"",
197 filename
198 ))
199 .span(Span::union(name_p, name_q)));
200 }
201 };
202
203 let content = included_source.get_content();
204 let content_unbound = unsafe { &*(content.as_ref() as *const dyn SourceContent) };
205 let iter = content_unbound.iter();
206 self.contents.push(content);
207 self.stack.push(Stream {
208 source: included_source,
209 iter: Cat::new(iter),
210 });
211
212 self.bump();
213 return Ok(());
214 }
215
216 Directive::Define => {
217 if self.is_inactive() {
218 return Ok(());
219 }
220
221 match self.token {
223 Some((Whitespace, _)) => self.bump(),
224 _ => (),
225 }
226
227 let makro = self.handle_macro_definition(span)?;
228
229 self.macro_defs.insert(makro.name.clone(), makro);
230 return Ok(());
231 }
232
233 Directive::Undef => {
234 if self.is_inactive() {
235 return Ok(());
236 }
237
238 match self.token {
240 Some((Whitespace, _)) => self.bump(),
241 _ => (),
242 }
243
244 let (name, _) = match self.try_eat_name() {
246 Some(x) => x,
247 None => {
248 return Err(
249 DiagBuilder2::fatal("expected macro name after \"`undef\"").span(span)
250 );
251 }
252 };
253
254 self.macro_defs.remove(&name);
256 return Ok(());
257 }
258
259 Directive::Undefineall => {
260 if self.is_inactive() {
261 return Ok(());
262 }
263 self.macro_defs.clear();
264 }
265
266 Directive::Ifdef | Directive::Ifndef | Directive::Elsif => {
267 match self.token {
269 Some((Whitespace, _)) => self.bump(),
270 _ => (),
271 }
272
273 let name = match self.try_eat_name() {
275 Some((x, _)) => x,
276 _ => {
277 return Err(DiagBuilder2::fatal(format!(
278 "expected macro name after {}",
279 dir_name
280 ))
281 .span(span));
282 }
283 };
284 let exists = self.macro_defs.contains_key(&name);
285
286 match dir {
289 Directive::Ifdef => self.defcond_stack.push(if self.is_inactive() {
290 Defcond::Done
291 } else if exists {
292 Defcond::Enabled
293 } else {
294 Defcond::Disabled
295 }),
296 Directive::Ifndef => self.defcond_stack.push(if self.is_inactive() {
297 Defcond::Done
298 } else if exists {
299 Defcond::Disabled
300 } else {
301 Defcond::Enabled
302 }),
303 Directive::Elsif => {
304 match self.defcond_stack.pop() {
305 Some(Defcond::Done) | Some(Defcond::Enabled) => {
306 self.defcond_stack.push(Defcond::Done)
307 }
308 Some(Defcond::Disabled) => {
309 self.defcond_stack.push(if self.is_inactive() {
310 Defcond::Done
311 } else if exists {
312 Defcond::Enabled
313 } else {
314 Defcond::Disabled
315 })
316 }
317 None => {
318 return Err(DiagBuilder2::fatal(
319 "found `elsif without any preceeding `ifdef, `ifndef, or \
320 `elsif directive",
321 )
322 .span(span))
323 }
324 };
325 }
326 _ => unreachable!(),
327 }
328
329 return Ok(());
330 }
331
332 Directive::Else => {
333 match self.defcond_stack.pop() {
334 Some(Defcond::Disabled) => self.defcond_stack.push(Defcond::Enabled),
335 Some(Defcond::Enabled) | Some(Defcond::Done) => {
336 self.defcond_stack.push(Defcond::Done)
337 }
338 None => {
339 return Err(DiagBuilder2::fatal(
340 "found `else without any preceeding `ifdef, `ifndef, or `elsif \
341 directive",
342 )
343 .span(span))
344 }
345 }
346 return Ok(());
347 }
348
349 Directive::Endif => {
350 if self.defcond_stack.pop().is_none() {
351 return Err(DiagBuilder2::fatal(
352 "found `endif without any preceeding `ifdef, `ifndef, `else, or `elsif \
353 directive",
354 )
355 .span(span));
356 }
357 return Ok(());
358 }
359
360 Directive::Unknown => {
364 if self.is_inactive() {
365 return Ok(());
366 }
367 if let Some(ref makro) = unsafe { &*(self as *const Preprocessor) }
370 .macro_defs
371 .get(dir_name)
372 {
373 let args = self.handle_macro_expansion_args(makro, span)?;
374
375 match self.token {
386 Some((x, sp)) => self.macro_stack.push((x, sp)),
387 None => (),
388 }
389
390 if args.is_empty() {
393 self.macro_stack
394 .extend(makro.body.iter().rev().map(|&(tkn, sp)| (tkn, sp)));
395 } else {
396 let mut replacement = Vec::<TokenAndSpan>::new();
397 for tkn in &makro.body {
400 match *tkn {
401 (Text, sp) => match args.get(&sp.extract()) {
402 Some(substitute) => {
403 replacement.extend(substitute);
404 }
405 None => replacement.push(*tkn),
406 },
407 x => replacement.push(x),
408 }
409 }
410 self.macro_stack
411 .extend(replacement.iter().rev().map(|&(tkn, sp)| (tkn, sp)));
412 }
413
414 self.bump();
415 return Ok(());
416 }
417 }
418
419 Directive::Timescale => {
421 while let Some((tkn, _)) = self.token {
422 if tkn == Newline {
423 break;
424 }
425 self.bump();
426 }
427 return Ok(());
428 }
429
430 Directive::CurrentFile => {
431 if !self.is_inactive() {
432 self.macro_stack.push((CatTokenKind::Text, span));
433 }
434 return Ok(());
435 }
436
437 Directive::CurrentLine => {
438 if !self.is_inactive() {
439 self.macro_stack.push((CatTokenKind::Digits, span));
440 }
441 return Ok(());
442 }
443
444 Directive::Resetall => {
445 if !self.is_inactive() {
446 self.dirs = Default::default();
447 }
448 return Ok(());
449 }
450
451 Directive::Celldefine => {
452 if !self.is_inactive() {
453 self.dirs.celldefine = true;
454 }
455 return Ok(());
456 }
457
458 Directive::Endcelldefine => {
459 if !self.is_inactive() {
460 self.dirs.celldefine = false;
461 }
462 return Ok(());
463 }
464
465 Directive::DefaultNettype => {
466 if !self.is_inactive() {
467 match self.token {
469 Some((Whitespace, _)) => self.bump(),
470 _ => (),
471 }
472
473 let tkn = match self.token {
475 Some(tkn @ (Text, _)) => {
476 self.bump();
477 tkn
478 }
479 _ => {
480 return Err(DiagBuilder2::fatal(
481 "expected nettype after `default_nettype",
482 )
483 .span(span));
484 }
485 };
486
487 self.dirs.default_nettype = if tkn.1.extract() == "none" {
489 None
490 } else {
491 Some(tkn)
492 };
493 debug!(
494 "Set default_nettype to `{}`",
495 self.dirs
496 .default_nettype
497 .map(|(_, sp)| sp.extract())
498 .unwrap_or_else(|| "none".to_string())
499 );
500 }
501 return Ok(());
502 }
503
504 Directive::BeginKeywords => {
505 if !self.is_inactive() {
506 match self.token {
508 Some((Whitespace, _)) => self.bump(),
509 _ => (),
510 }
511
512 match self.token {
514 Some((Symbol('"'), _)) => self.bump(),
515 _ => {
516 return Err(DiagBuilder2::fatal("expected `\"` after `begin_keywords")
517 .span(span));
518 }
519 };
520
521 let mut spec = String::new();
523 while let Some(tkn) = self.token {
524 if tkn.0 == Symbol('"') {
525 break;
526 }
527 spec.push_str(&tkn.1.extract());
528 self.bump();
529 }
530
531 match self.token {
533 Some((Symbol('"'), _)) => self.bump(),
534 _ => {
535 return Err(DiagBuilder2::fatal(
536 "expected `\"` after version specifier",
537 )
538 .span(span));
539 }
540 };
541
542 let spec = match KeywordsDirective::from_str(&spec) {
544 Some(spec) => spec,
545 _ => {
546 return Err(DiagBuilder2::fatal(format!(
547 "unknown `begin_keywords version specifier `{}`",
548 spec
549 ))
550 .span(span));
551 }
552 };
553 self.dirs.keywords.push(spec);
554 debug!("Push keywords; now `{:?}`", self.dirs.keywords.last());
555 }
556 return Ok(());
557 }
558
559 Directive::EndKeywords => {
560 if !self.is_inactive() {
561 if self.dirs.keywords.pop().is_none() {
562 return Err(DiagBuilder2::fatal(
563 "`end_keywords without earlier `begin_keywords",
564 )
565 .span(span));
566 }
567 debug!("Pop keywords; now `{:?}`", self.dirs.keywords.last());
568 }
569 return Ok(());
570 }
571
572 Directive::Line => {
573 if !self.is_inactive() {
574 match self.token {
576 Some((Whitespace, _)) => self.bump(),
577 _ => (),
578 }
579
580 let _line = match self.token {
583 Some((Digits, sp)) => {
584 self.bump();
585 sp
586 }
587 _ => {
588 return Err(
589 DiagBuilder2::fatal("expected line number after `line").span(span)
590 );
591 }
592 };
593
594 match self.token {
596 Some((Whitespace, _)) => self.bump(),
597 _ => (),
598 }
599
600 match self.token {
602 Some((Symbol('"'), _)) => self.bump(),
603 _ => {
604 return Err(DiagBuilder2::fatal(
605 "expected `\"` after line number in `line",
606 )
607 .span(span));
608 }
609 };
610
611 let mut filename = String::new();
613 while let Some(tkn) = self.token {
614 if tkn.0 == Symbol('"') {
615 break;
616 }
617 filename.push_str(&tkn.1.extract());
618 self.bump();
619 }
620
621 match self.token {
623 Some((Symbol('"'), _)) => self.bump(),
624 _ => {
625 return Err(DiagBuilder2::fatal(
626 "expected `\"` after filename in `line",
627 )
628 .span(span));
629 }
630 };
631
632 match self.token {
634 Some((Whitespace, _)) => self.bump(),
635 _ => (),
636 }
637
638 let _level = match self.token {
641 Some((Digits, sp)) => {
642 self.bump();
643 sp
644 }
645 _ => {
646 return Err(
647 DiagBuilder2::fatal("expected level after `line").span(span)
648 );
649 }
650 };
651
652 debug!("Ignoring `line directive");
653 }
654 return Ok(());
655 }
656
657 Directive::UnconnectedDrive => {
658 if !self.is_inactive() {
659 match self.token {
661 Some((Whitespace, _)) => self.bump(),
662 _ => (),
663 }
664
665 let tkn = match self.token {
667 Some((Text, _)) => self.token,
668 _ => None,
669 };
670 let pull = match tkn.map(|(_, sp)| sp.extract()).as_ref().map(|s| s.as_str()) {
671 Some("pull0") => UnconnectedDrive::Pull0,
672 Some("pull1") => UnconnectedDrive::Pull1,
673 _ => {
674 return Err(DiagBuilder2::fatal(
675 "expected `pull0` or `pull1` after `unconnected_drive",
676 )
677 .span(span));
678 }
679 };
680 self.bump(); self.dirs.unconnected_drive = Some(pull);
684 debug!("Set unconnected_drive to {:?}", self.dirs.unconnected_drive);
685 }
686 return Ok(());
687 }
688
689 Directive::NoUnconnectedDrive => {
690 if !self.is_inactive() {
691 self.dirs.unconnected_drive = None;
692 debug!("Set unconnected_drive to {:?}", self.dirs.unconnected_drive);
693 }
694 return Ok(());
695 }
696 }
697
698 return Err(
699 DiagBuilder2::fatal(format!("unknown compiler directive '`{}'", dir_name)).span(span),
700 );
701 }
702
703 fn open_include(&mut self, filename: &str, current_file: &str) -> Option<Source> {
704 let first = [Path::new(current_file)
706 .parent()
707 .expect("current file path must have a valid parent")];
708 let prefices = first.iter().chain(self.include_paths.iter());
709 let sm = get_source_manager();
710 for prefix in prefices {
711 let mut buf = prefix.to_path_buf();
712 buf.push(filename);
713 let src = sm.open(buf.to_str().unwrap());
715 if src.is_some() {
716 return src;
717 }
718 }
719 return None;
720 }
721
722 fn is_inactive(&self) -> bool {
726 match self.defcond_stack.last() {
727 Some(&Defcond::Enabled) | None => false,
728 _ => true,
729 }
730 }
731
732 fn try_eat_name(&mut self) -> Option<(String, Span)> {
733 let (mut name, mut span) = match self.token {
736 Some((Text, sp)) | Some((Symbol('_'), sp)) => (sp.extract(), sp),
737 _ => return None,
738 };
739 self.bump();
740
741 loop {
744 match self.token {
745 Some((Text, sp)) | Some((Digits, sp)) | Some((Symbol('_'), sp)) => {
746 name.push_str(&sp.extract());
747 span.expand(sp);
748 self.bump();
749 }
750 _ => break,
751 }
752 }
753
754 Some((name, span))
755 }
756
757 fn skip_whitespace(&mut self) -> bool {
759 match self.token {
760 Some((Whitespace, _)) => {
761 self.bump();
762 true
763 }
764 _ => false,
765 }
766 }
767
768 fn handle_macro_definition(&mut self, define_span: Span) -> Result<Macro, DiagBuilder2> {
770 let mut all_span = define_span;
771
772 let (name, name_span) = match self.try_eat_name() {
774 Some(x) => x,
775 None => {
776 return Err(
777 DiagBuilder2::fatal("expected macro name after \"`define\"").span(define_span)
778 );
779 }
780 };
781 all_span.expand(define_span);
782 let mut makro = Macro::new(name, name_span);
783
784 makro.args = self.handle_macro_definition_args()?;
789
790 self.skip_whitespace();
792
793 loop {
796 match self.token {
797 Some((Newline, _)) => {
798 self.bump();
799 break;
800 }
801 Some((Symbol('\\'), _)) => {
804 self.bump();
805 match self.token {
806 Some((Newline, _)) => self.bump(),
807 _ => (),
808 };
809 }
810 Some(x) => {
811 makro.body.push(x);
812 self.bump();
813 }
814 None => break,
815 }
816 }
817 Ok(makro)
818 }
819
820 fn handle_macro_definition_args(&mut self) -> Result<Vec<MacroArg>, DiagBuilder2> {
821 let mut all_span = match self.token {
823 Some((Symbol('('), sp)) => {
824 self.bump();
825 sp
826 }
827 _ => return Ok(vec![]),
828 };
829
830 let mut args = vec![];
832 loop {
833 self.skip_whitespace();
835 match self.token {
836 Some((Symbol(')'), _)) => {
837 self.bump();
838 break;
839 }
840 None => {
841 return Err(
842 DiagBuilder2::fatal("expected `)` after macro arguments").span(all_span)
843 )
844 }
845 _ => (),
846 }
847
848 let (name, name_span) = match self.try_eat_name() {
850 Some(x) => x,
851 _ => {
852 return Err(
853 DiagBuilder2::fatal("expected macro argument name").span(all_span.end())
854 );
855 }
856 };
857 self.skip_whitespace();
858
859 let default = match self.token {
861 Some((Symbol('='), sp)) => {
862 all_span.expand(sp);
863 self.bump();
864 self.skip_whitespace();
865 let mut tokens = vec![];
866 let mut nesting = 0;
867 loop {
868 match self.token {
869 Some((Symbol(','), _)) | Some((Symbol(')'), _)) if nesting == 0 => {
870 match tokens.last() {
871 Some((Whitespace, _)) => {
872 tokens.pop();
873 }
874 _ => (),
875 }
876 break;
877 }
878 Some(x @ (Symbol('('), _))
879 | Some(x @ (Symbol('{'), _))
880 | Some(x @ (Symbol('['), _)) => {
881 nesting += 1;
882 all_span.expand(x.1);
883 tokens.push(x);
884 self.bump();
885 }
886 Some(x @ (Symbol(')'), _))
887 | Some(x @ (Symbol('}'), _))
888 | Some(x @ (Symbol(']'), _)) => {
889 nesting -= 1;
890 all_span.expand(x.1);
891 tokens.push(x);
892 self.bump();
893 }
894 Some(x) => {
895 all_span.expand(x.1);
896 tokens.push(x);
897 self.bump();
898 }
899 _ => break,
900 }
901 }
902 Some(tokens)
903 }
904 _ => None,
905 };
906
907 args.push(MacroArg {
908 name,
909 span: name_span,
910 default,
911 });
912
913 self.skip_whitespace();
915 match self.token {
916 Some((Symbol(','), _)) => self.bump(),
917 Some((Symbol(')'), _)) => (),
918 Some((_, sp)) => {
919 return Err(
920 DiagBuilder2::fatal("expected `,` or `)` after macro argument").span(sp),
921 )
922 }
923 None => (),
924 }
925 }
926 Ok(args)
927 }
928
929 fn handle_macro_expansion_args(
930 &mut self,
931 makro: &Macro,
932 span: Span,
933 ) -> Result<MacroExpansionParams, DiagBuilder2> {
934 if makro.args.is_empty() {
936 return Ok(Default::default());
937 }
938 let mut all_span = span;
939
940 self.skip_whitespace();
942
943 match self.token {
945 Some((Symbol('('), sp)) => {
946 self.bump();
947 all_span.expand(sp);
948 }
949 _ => {
950 return Err(DiagBuilder2::fatal(format!(
951 "expected macro arguments for `{}`",
952 makro.name
953 ))
954 .span(all_span)
955 .add_note(format!(
956 "At least parenthesis are needed: `{}()`",
957 makro.name
958 ))
959 .add_note(format!(
960 "Macro `{}` defines {} arguments:",
961 makro.name,
962 makro.args.len()
963 ))
964 .span(makro.span));
965 }
966 }
967 self.skip_whitespace();
968
969 let mut args = vec![];
976 'outer: loop {
977 let mut arg_tokens = Vec::<TokenAndSpan>::new();
978 let mut nesting = 0;
979 loop {
980 match self.token {
981 Some((Symbol(','), sp)) if nesting == 0 => {
982 args.push(arg_tokens);
983 all_span.expand(sp);
984 self.bump();
985 self.skip_whitespace();
986 break;
987 }
988 Some((Symbol(')'), sp)) if nesting == 0 => {
989 args.push(arg_tokens);
990 all_span.expand(sp);
991 self.bump();
992 break 'outer;
993 }
994 Some(x @ (Symbol('('), _))
995 | Some(x @ (Symbol('{'), _))
996 | Some(x @ (Symbol('['), _)) => {
997 arg_tokens.push(x);
998 nesting += 1;
999 self.bump();
1000 all_span.expand(x.1);
1001 }
1002 Some(x @ (Symbol(')'), _))
1003 | Some(x @ (Symbol('}'), _))
1004 | Some(x @ (Symbol(']'), _)) => {
1005 arg_tokens.push(x);
1006 nesting -= 1;
1007 self.bump();
1008 all_span.expand(x.1);
1009 }
1010 Some(x) => {
1011 arg_tokens.push(x);
1012 self.bump();
1013 all_span.expand(x.1);
1014 }
1015 None => {
1016 return Err(DiagBuilder2::fatal("expected `)` after macro arguments")
1017 .span(all_span));
1018 }
1019 }
1020 }
1021 }
1022
1023 for arg in &mut args {
1025 match arg.last() {
1026 Some((Whitespace, _)) => {
1027 arg.pop();
1028 }
1029 _ => (),
1030 }
1031 }
1032
1033 if makro.args.len() < args.len() {
1035 let d = DiagBuilder2::fatal(format!(
1036 "macro expansion with {} arguments, but `{}` expects {} arguments",
1037 args.len(),
1038 makro.name,
1039 makro.args.len()
1040 ))
1041 .span(all_span)
1042 .add_note(format!("Definition of `{}` was here:", makro.name))
1043 .span(makro.span);
1044 return Err(d);
1045 }
1046 let args = makro
1047 .args
1048 .iter()
1049 .zip(args.into_iter().map(Some).chain(std::iter::repeat(None)))
1050 .map(|(def, exp)| {
1051 let is_empty = !exp.iter().flatten().any(|(t, _)| match t {
1052 Whitespace => false,
1053 _ => true,
1054 });
1055 let value = match (exp, def.default.as_ref()) {
1056 (Some(ref _exp), Some(default)) if is_empty => default.clone(),
1059 (Some(ref _exp), None) if is_empty => vec![],
1060 (Some(exp), _) => exp,
1061
1062 (None, Some(default)) => default.clone(),
1064 (None, None) => {
1065 let d = DiagBuilder2::fatal(format!(
1066 "macro expansion missing value for `{}`",
1067 def.name
1068 ))
1069 .span(all_span)
1070 .add_note(format!(
1071 "Macro argument `{}` needs a value because it has no default:",
1072 def.name
1073 ))
1074 .span(def.span);
1075 return Err(d);
1076 }
1077 };
1078 Ok((def.name.clone(), value))
1079 })
1080 .collect::<Result<HashMap<_, _>, _>>()?;
1081
1082 Ok(args)
1083 }
1084}
1085
1086type MacroExpansionParams = HashMap<String, Vec<TokenAndSpan>>;
1087
1088impl<'a> Iterator for Preprocessor<'a> {
1089 type Item = DiagResult2<TokenAndSpan>;
1090
1091 fn next(&mut self) -> Option<DiagResult2<TokenAndSpan>> {
1092 if self.token.is_none() {
1095 self.bump();
1096 }
1097 loop {
1098 match self.token {
1104 Some((Symbol('`'), sp_backtick)) => {
1105 self.bump(); if let Some((name, sp)) = self.try_eat_name() {
1107 let dir_span = Span::union(sp_backtick, sp);
1112 match self.handle_directive(name, dir_span) {
1113 Err(x) => return Some(Err(x)),
1114 _ => (),
1115 }
1116 continue;
1117 } else if let Some(tkn @ (Symbol('"'), _)) = self.token {
1118 self.bump();
1120 if !self.is_inactive() {
1121 return Some(Ok(tkn));
1122 }
1123 } else if let Some(tkn @ (Symbol('\\'), _)) = self.token {
1124 self.bump();
1126 if !self.is_inactive() {
1127 return Some(Ok(tkn));
1128 }
1129 } else if let Some((Symbol('`'), _)) = self.token {
1130 self.bump(); } else {
1132 return Some(Err(DiagBuilder2::fatal(
1133 "expected compiler directive after '`', or '``', '`\"', or '`\\'",
1134 )
1135 .span(sp_backtick)));
1136 }
1137 }
1138 _ => {
1139 if self.is_inactive() {
1143 self.bump();
1144 } else {
1145 let tkn = self.token.map(|x| Ok(x));
1146 self.bump();
1147 return tkn;
1148 }
1149 }
1150 }
1151 }
1152 }
1153}
1154
1155struct Stream<'a> {
1156 source: Source,
1157 iter: Cat<'a>,
1158}
1159
1160#[derive(Debug, Clone, Copy)]
1162enum Directive {
1163 Include,
1164 Define,
1165 Undef,
1166 Undefineall,
1167 Ifdef,
1168 Ifndef,
1169 Else,
1170 Elsif,
1171 Endif,
1172 Timescale,
1173 CurrentFile,
1174 CurrentLine,
1175 Resetall,
1176 Celldefine,
1177 Endcelldefine,
1178 DefaultNettype,
1179 BeginKeywords,
1180 EndKeywords,
1181 Line,
1182 UnconnectedDrive,
1183 NoUnconnectedDrive,
1184 Unknown,
1185}
1186
1187impl fmt::Display for Directive {
1188 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1189 match self {
1190 Directive::Include => write!(f, "`include"),
1191 Directive::Define => write!(f, "`define"),
1192 Directive::Undef => write!(f, "`undef"),
1193 Directive::Undefineall => write!(f, "`undefineall"),
1194 Directive::Ifdef => write!(f, "`ifdef"),
1195 Directive::Ifndef => write!(f, "`ifndef"),
1196 Directive::Else => write!(f, "`else"),
1197 Directive::Elsif => write!(f, "`elsif"),
1198 Directive::Endif => write!(f, "`endif"),
1199 Directive::Timescale => write!(f, "`timescale"),
1200 Directive::CurrentFile => write!(f, "`__FILE__"),
1201 Directive::CurrentLine => write!(f, "`__LINE__"),
1202 Directive::Resetall => write!(f, "`resetall"),
1203 Directive::Celldefine => write!(f, "`celldefine"),
1204 Directive::Endcelldefine => write!(f, "`endcelldefine"),
1205 Directive::DefaultNettype => write!(f, "`default_nettype"),
1206 Directive::BeginKeywords => write!(f, "`begin_keywords"),
1207 Directive::EndKeywords => write!(f, "`end_keywords"),
1208 Directive::Line => write!(f, "`line"),
1209 Directive::UnconnectedDrive => write!(f, "`unconnected_drive"),
1210 Directive::NoUnconnectedDrive => write!(f, "`nounconnected_drive"),
1211 Directive::Unknown => write!(f, "unknown"),
1212 }
1213 }
1214}
1215
1216static DIRECTIVES_TABLE: Lazy<HashMap<&'static str, Directive>> = Lazy::new(|| {
1217 let mut table = HashMap::new();
1218 table.insert("include", Directive::Include);
1219 table.insert("define", Directive::Define);
1220 table.insert("undef", Directive::Undef);
1221 table.insert("undefineall", Directive::Undefineall);
1222 table.insert("ifdef", Directive::Ifdef);
1223 table.insert("ifndef", Directive::Ifndef);
1224 table.insert("else", Directive::Else);
1225 table.insert("elsif", Directive::Elsif);
1226 table.insert("endif", Directive::Endif);
1227 table.insert("__FILE__", Directive::CurrentFile);
1228 table.insert("__LINE__", Directive::CurrentLine);
1229 table.insert("resetall", Directive::Resetall);
1230 table.insert("celldefine", Directive::Celldefine);
1231 table.insert("endcelldefine", Directive::Endcelldefine);
1232 table.insert("default_nettype", Directive::DefaultNettype);
1233 table.insert("begin_keywords", Directive::BeginKeywords);
1234 table.insert("end_keywords", Directive::EndKeywords);
1235 table.insert("line", Directive::Line);
1236 table.insert("unconnected_drive", Directive::UnconnectedDrive);
1237 table.insert("nounconnected_drive", Directive::NoUnconnectedDrive);
1238 table.insert("timescale", Directive::Timescale);
1239 table
1240});
1241
1242#[derive(Debug)]
1243struct Macro {
1244 name: String,
1245 span: Span,
1246 args: Vec<MacroArg>,
1247 body: Vec<TokenAndSpan>,
1248}
1249
1250impl Macro {
1251 fn new(name: String, span: Span) -> Macro {
1252 Macro {
1253 name: name,
1254 span: span,
1255 args: Vec::new(),
1256 body: Vec::new(),
1257 }
1258 }
1259}
1260
1261#[derive(Debug)]
1262struct MacroArg {
1263 name: String,
1264 span: Span,
1265 default: Option<Vec<TokenAndSpan>>,
1266}
1267
1268enum Defcond {
1269 Done,
1270 Enabled,
1271 Disabled,
1272}
1273
1274#[derive(Default)]
1275struct Directives {
1276 celldefine: bool,
1277 default_nettype: Option<TokenAndSpan>,
1278 keywords: Vec<KeywordsDirective>,
1279 unconnected_drive: Option<UnconnectedDrive>,
1280}
1281
1282#[allow(non_camel_case_types)]
1283#[derive(Debug)]
1284enum KeywordsDirective {
1285 Ieee1800_2009,
1286 Ieee1800_2005,
1287 Ieee1364_2005,
1288 Ieee1364_2001,
1289 Ieee1364_2001_Noconfig,
1290 Ieee1364_1995,
1291}
1292
1293#[derive(Debug)]
1294enum UnconnectedDrive {
1295 Pull0,
1296 Pull1,
1297}
1298
1299impl KeywordsDirective {
1300 pub fn from_str(s: &str) -> Option<Self> {
1301 match s {
1302 "1800-2009" => Some(Self::Ieee1800_2009),
1303 "1800-2005" => Some(Self::Ieee1800_2005),
1304 "1364-2005" => Some(Self::Ieee1364_2005),
1305 "1364-2001" => Some(Self::Ieee1364_2001),
1306 "1364-2001-noconfig" => Some(Self::Ieee1364_2001_Noconfig),
1307 "1364-1995" => Some(Self::Ieee1364_1995),
1308 _ => None,
1309 }
1310 }
1311}
1312
1313#[cfg(test)]
1314mod tests {
1315 use super::*;
1316
1317 fn preproc(input: &str) -> Preprocessor {
1318 use std::cell::Cell;
1319 thread_local!(static INDEX: Cell<usize> = Cell::new(0));
1320 let sm = get_source_manager();
1321 let idx = INDEX.with(|i| {
1322 let v = i.get();
1323 i.set(v + 1);
1324 v
1325 });
1326 let source = sm.add(&format!("test_{}.sv", idx), input);
1327 Preprocessor::new(source, &[], &[])
1328 }
1329
1330 fn check_str(input: &str, expected: &str) {
1331 let pp = preproc(input);
1332 let actual: String = pp.map(|x| x.unwrap().1.extract()).collect();
1333 assert_eq!(actual, expected);
1334 }
1335
1336 #[test]
1337 fn include() {
1338 let sm = get_source_manager();
1339 sm.add("other.sv", "bar\n");
1340 sm.add("test.sv", "foo\n`include \"other.sv\"\nbaz");
1341 let pp = Preprocessor::new(sm.open("test.sv").unwrap(), &[], &[]);
1342 let actual: Vec<_> = pp.map(|x| x.unwrap().0).collect();
1343 assert_eq!(actual, &[Text, Newline, Text, Newline, Newline, Text,]);
1344 }
1345
1346 #[test]
1347 fn include_and_define() {
1348 let sm = get_source_manager();
1349 sm.add("other.sv", "/* World */\n`define foo 42\nbar");
1350 sm.add(
1351 "test.sv",
1352 "// Hello\n`include \"other.sv\"\n`foo something\n",
1353 );
1354 let pp = Preprocessor::new(sm.open("test.sv").unwrap(), &[], &[]);
1355 let actual: String = pp
1356 .map(|x| {
1357 let x = x.unwrap();
1358 println!("{:?}", x);
1359 x.1.extract()
1360 })
1361 .collect();
1362 assert_eq!(actual, "// Hello\n/* World */\nbar\n42 something\n");
1363 }
1364
1365 #[test]
1366 #[should_panic(expected = "unknown compiler directive")]
1367 fn conditional_define() {
1368 let sm = get_source_manager();
1369 let source = sm.add("test.sv", "`ifdef FOO\n`define BAR\n`endif\n`BAR");
1370 let mut pp = Preprocessor::new(source, &[], &[]);
1371 while let Some(tkn) = pp.next() {
1372 tkn.unwrap();
1373 }
1374 }
1375
1376 #[test]
1377 fn macro_args() {
1378 check_str(
1379 "`define foo(x,y) {x + y _bar}\n`foo(12, foo)\n",
1380 "{12 + foo _bar}\n",
1381 );
1382 }
1383
1384 #[test]
1387 fn macro_noargs_parentheses() {
1388 check_str(
1389 "`define FOO 4\n`define BAR (`FOO+$clog2(2))\n`BAR",
1390 "(4+$clog2(2))",
1391 );
1392 }
1393
1394 #[test]
1395 fn macro_name_with_digits_and_underscores() {
1396 check_str("`define AXI_BUS21_SV 42\n`AXI_BUS21_SV", "42");
1397 }
1398}