Skip to main content

scarf_parser/preprocessor/
error.rs

1// =======================================================================
2// error.rs
3// =======================================================================
4//! Warnings/errors that are thrown by the preprocessor
5
6use crate::{include::MAX_INCLUDE_DEPTH, *};
7use ariadne::ReportBuilder;
8use std::io;
9
10const NOTE_COLOR: Color = Color::Fixed(81);
11
12/// An error encountered during preprocessing
13///
14/// As preprocessing can affect the interpretation of later
15/// source code, these errors are often irrecoverable
16///
17/// Errors marked with **INTERNAL** are meant for use inside the
18/// preprocessor for passing information, and should not be returned
19#[derive(Debug)]
20pub enum PreprocessorError<'a> {
21    /// An `` `endif `` encountered outside a conditional preprocessor block
22    ///
23    /// ```rust
24    /// # use scarf_parser::*;
25    /// # let mut state = PreprocessorState::new(vec![], vec![]);
26    /// # let cache = PreprocessorCache::new();
27    /// let source = "
28    /// `endif
29    /// ";
30    /// let input = lex(source, "test.v").tokens();
31    /// let preprocess_result = preprocess(
32    ///     &mut TokenIterator::new(input.into_iter()),
33    ///     &mut state,
34    ///     &cache,
35    /// );
36    /// assert!(matches!(preprocess_result, Err(PreprocessorError::Endif(_))));
37    /// ```
38    Endif(Span<'a>),
39    /// No terminating `` `endif `` for a conditional preprocessor block
40    ///
41    /// ```rust
42    /// # use scarf_parser::*;
43    /// # let mut state = PreprocessorState::new(vec![], vec![]);
44    /// # let cache = PreprocessorCache::new();
45    /// let source = "
46    /// `ifdef TEST
47    /// ";
48    /// let input = lex(source, "test.v").tokens();
49    /// let preprocess_result = preprocess(
50    ///     &mut TokenIterator::new(input.into_iter()),
51    ///     &mut state,
52    ///     &cache,
53    /// );
54    /// assert!(matches!(preprocess_result, Err(PreprocessorError::NoEndif(Token::DirIfdef, _))));
55    /// ```
56    NoEndif(Token<'a>, Span<'a>),
57    /// An `` `elsif `` encountered outside a conditional preprocessor block
58    ///
59    /// ```rust
60    /// # use scarf_parser::*;
61    /// # let mut state = PreprocessorState::new(vec![], vec![]);
62    /// # let cache = PreprocessorCache::new();
63    /// let source = "
64    /// `elsif
65    /// ";
66    /// let input = lex(source, "test.v").tokens();
67    /// let preprocess_result = preprocess(
68    ///     &mut TokenIterator::new(input.into_iter()),
69    ///     &mut state,
70    ///     &cache,
71    /// );
72    /// assert!(matches!(preprocess_result, Err(PreprocessorError::Elsif(_))));
73    /// ```
74    Elsif(Span<'a>),
75    /// An `` `else `` encountered outside a conditional preprocessor block
76    ///
77    /// ```rust
78    /// # use scarf_parser::*;
79    /// # let mut state = PreprocessorState::new(vec![], vec![]);
80    /// # let cache = PreprocessorCache::new();
81    /// let source = "
82    /// `else
83    /// ";
84    /// let input = lex(source, "test.v").tokens();
85    /// let preprocess_result = preprocess(
86    ///     &mut TokenIterator::new(input.into_iter()),
87    ///     &mut state,
88    ///     &cache,
89    /// );
90    /// assert!(matches!(preprocess_result, Err(PreprocessorError::Else(_))));
91    /// ```
92    Else(Span<'a>),
93    /// An `` `end_keywords `` encountered outside a `` `begin_keywords `` block
94    ///
95    /// ```rust
96    /// # use scarf_parser::*;
97    /// # let mut state = PreprocessorState::new(vec![], vec![]);
98    /// # let cache = PreprocessorCache::new();
99    /// let source = "
100    /// `end_keywords
101    /// ";
102    /// let input = lex(source, "test.v").tokens();
103    /// let preprocess_result = preprocess(
104    ///     &mut TokenIterator::new(input.into_iter()),
105    ///     &mut state,
106    ///     &cache,
107    /// );
108    /// assert!(matches!(preprocess_result, Err(PreprocessorError::EndKeywords(_))));
109    /// ```
110    EndKeywords(Span<'a>),
111    /// No terminating `` `end_keywords `` for a `` `begin_keywords `` block
112    ///
113    /// ```rust
114    /// # use scarf_parser::*;
115    /// # let mut state = PreprocessorState::new(vec![], vec![]);
116    /// # let cache = PreprocessorCache::new();
117    /// let source = "
118    /// `begin_keywords \"1800-2009\"
119    /// ";
120    /// let input = lex(source, "test.v").tokens();
121    /// let preprocess_result = preprocess(
122    ///     &mut TokenIterator::new(input.into_iter()),
123    ///     &mut state,
124    ///     &cache,
125    /// );
126    /// assert!(matches!(preprocess_result, Err(PreprocessorError::NoEndKeywords(_))));
127    /// ```
128    NoEndKeywords(Span<'a>),
129    /// A missing parameter in a `` `define `` function declaration where one is expected
130    ///
131    /// ```rust
132    /// # use scarf_parser::*;
133    /// # let mut state = PreprocessorState::new(vec![], vec![]);
134    /// # let cache = PreprocessorCache::new();
135    /// let source = "
136    /// `define TEST()
137    /// ";
138    /// let input = lex(source, "test.v").tokens();
139    /// let preprocess_result = preprocess(
140    ///     &mut TokenIterator::new(input.into_iter()),
141    ///     &mut state,
142    ///     &cache,
143    /// );
144    /// assert!(matches!(preprocess_result, Err(PreprocessorError::InvalidDefineParameter(_))));
145    /// ```
146    InvalidDefineParameter(SpannedToken<'a>),
147    /// A missing or invalid argument specification in a `` `define `` function
148    ///
149    /// ```rust
150    /// # use scarf_parser::*;
151    /// # let mut state = PreprocessorState::new(vec![], vec![]);
152    /// # let cache = PreprocessorCache::new();
153    /// let source = "
154    /// `define TEST(a, b c)
155    /// ";
156    /// let input = lex(source, "test.v").tokens();
157    /// let preprocess_result = preprocess(
158    ///     &mut TokenIterator::new(input.into_iter()),
159    ///     &mut state,
160    ///     &cache,
161    /// );
162    /// assert!(matches!(preprocess_result, Err(PreprocessorError::InvalidDefineArgument(_))));
163    /// ```
164    InvalidDefineArgument(SpannedToken<'a>),
165    /// An invalid version specifier for a `` `begin_keywords `` directive
166    ///
167    /// ```rust
168    /// # use scarf_parser::*;
169    /// # let mut state = PreprocessorState::new(vec![], vec![]);
170    /// # let cache = PreprocessorCache::new();
171    /// let source = "
172    /// `begin_keywords \"MyVersion\"
173    /// ";
174    /// let input = lex(source, "test.v").tokens();
175    /// let preprocess_result = preprocess(
176    ///     &mut TokenIterator::new(input.into_iter()),
177    ///     &mut state,
178    ///     &cache,
179    /// );
180    /// assert!(matches!(preprocess_result, Err(PreprocessorError::InvalidVersionSpecifier(_))));
181    /// ```
182    InvalidVersionSpecifier((Option<&'a str>, Span<'a>)),
183    /// A directive that doesn't have all of the required components
184    ///
185    /// In general, [`PreprocessorError::VerboseError`] is preferred, but may
186    /// not be suitable due to a lack of subsequent tokens
187    ///
188    /// ```rust
189    /// # use scarf_parser::*;
190    /// # let mut state = PreprocessorState::new(vec![], vec![]);
191    /// # let cache = PreprocessorCache::new();
192    /// let source = "`line";
193    /// let input = lex(source, "test.v").tokens();
194    /// let preprocess_result = preprocess(
195    ///     &mut TokenIterator::new(input.into_iter()),
196    ///     &mut state,
197    ///     &cache,
198    /// );
199    /// assert!(matches!(preprocess_result, Err(PreprocessorError::IncompleteDirective(_))));
200    /// ```
201    IncompleteDirective(Span<'a>),
202    /// An incomplete preprocessor definition, specifically with function macro arguments
203    ///
204    /// ```rust
205    /// # use scarf_parser::*;
206    /// # let mut state = PreprocessorState::new(vec![], vec![]);
207    /// # let cache = PreprocessorCache::new();
208    /// let source = "
209    /// `define TEST(
210    /// ";
211    /// let input = lex(source, "test.v").tokens();
212    /// let preprocess_result = preprocess(
213    ///     &mut TokenIterator::new(input.into_iter()),
214    ///     &mut state,
215    ///     &cache,
216    /// );
217    /// assert!(matches!(preprocess_result, Err(PreprocessorError::IncompleteDefine(_))));
218    /// ```
219    IncompleteDefine(SpannedToken<'a>),
220    /// Use of a text macro that wasn't previously defined
221    ///
222    /// ```rust
223    /// # use scarf_parser::*;
224    /// # let mut state = PreprocessorState::new(vec![], vec![]);
225    /// # let cache = PreprocessorCache::new();
226    /// let source = "
227    /// `TEST
228    /// ";
229    /// let input = lex(source, "test.v").tokens();
230    /// let preprocess_result = preprocess(
231    ///     &mut TokenIterator::new(input.into_iter()),
232    ///     &mut state,
233    ///     &cache,
234    /// );
235    /// assert!(matches!(preprocess_result, Err(PreprocessorError::UndefinedMacro(_))));
236    /// ```
237    UndefinedMacro((&'a str, Span<'a>)),
238    /// Specifying a macro parameter that was already specified
239    ///
240    /// ```rust
241    /// # use scarf_parser::*;
242    /// # let mut state = PreprocessorState::new(vec![], vec![]);
243    /// # let cache = PreprocessorCache::new();
244    /// let source = "
245    /// `define TEST(a, b, a) a + b
246    /// ";
247    /// let input = lex(source, "test.v").tokens();
248    /// let preprocess_result = preprocess(
249    ///     &mut TokenIterator::new(input.into_iter()),
250    ///     &mut state,
251    ///     &cache,
252    /// );
253    /// assert!(matches!(preprocess_result, Err(PreprocessorError::DuplicateMacroParameter(_))));
254    /// ```
255    DuplicateMacroParameter((&'a str, &'a str, Span<'a>, Span<'a>)),
256    /// Attempting to have a macro parameter with no default value after one that does
257    ///
258    /// ```rust
259    /// # use scarf_parser::*;
260    /// # let mut state = PreprocessorState::new(vec![], vec![]);
261    /// # let cache = PreprocessorCache::new();
262    /// let source = "
263    /// `define TEST(a = 1, b) a + b
264    /// ";
265    /// let input = lex(source, "test.v").tokens();
266    /// let preprocess_result = preprocess(
267    ///     &mut TokenIterator::new(input.into_iter()),
268    ///     &mut state,
269    ///     &cache,
270    /// );
271    /// assert!(matches!(preprocess_result, Err(PreprocessorError::NoDefaultAfterDefault(_))));
272    /// ```
273    NoDefaultAfterDefault((SpannedString<'a>, SpannedString<'a>)),
274    /// Specifying no arguments for a macro function that takes arguments
275    ///
276    /// ```rust
277    /// # use scarf_parser::*;
278    /// # let mut state = PreprocessorState::new(vec![], vec![]);
279    /// # let cache = PreprocessorCache::new();
280    /// let source = "
281    /// `define TEST(a, b) a + b
282    /// `TEST
283    /// ";
284    /// let input = lex(source, "test.v").tokens();
285    /// let preprocess_result = preprocess(
286    ///     &mut TokenIterator::new(input.into_iter()),
287    ///     &mut state,
288    ///     &cache,
289    /// );
290    /// assert!(matches!(preprocess_result, Err(PreprocessorError::NoMacroArguments(_))));
291    /// ```
292    NoMacroArguments((Span<'a>, (&'a str, Span<'a>))),
293    /// Specifying too many arguments for a macro function
294    ///
295    /// ```rust
296    /// # use scarf_parser::*;
297    /// # let mut state = PreprocessorState::new(vec![], vec![]);
298    /// # let cache = PreprocessorCache::new();
299    /// let source = "
300    /// `define TEST(a, b) a + b
301    /// `TEST(1, 2, 3)
302    /// ";
303    /// let input = lex(source, "test.v").tokens();
304    /// let preprocess_result = preprocess(
305    ///     &mut TokenIterator::new(input.into_iter()),
306    ///     &mut state,
307    ///     &cache,
308    /// );
309    /// assert!(matches!(preprocess_result, Err(PreprocessorError::TooManyMacroArguments(_))));
310    /// ```
311    TooManyMacroArguments((Span<'a>, (&'a str, usize, usize, Span<'a>))),
312    /// Missing an argument in a macro function use
313    ///
314    /// ```rust
315    /// # use scarf_parser::*;
316    /// # let mut state = PreprocessorState::new(vec![], vec![]);
317    /// # let cache = PreprocessorCache::new();
318    /// let source = "
319    /// `define TEST(a, b) a + b
320    /// `TEST(1)
321    /// ";
322    /// let input = lex(source, "test.v").tokens();
323    /// let preprocess_result = preprocess(
324    ///     &mut TokenIterator::new(input.into_iter()),
325    ///     &mut state,
326    ///     &cache,
327    /// );
328    /// assert!(matches!(preprocess_result, Err(PreprocessorError::MissingMacroArgument(_))));
329    /// ```
330    MissingMacroArgument((Span<'a>, (&'a str, Span<'a>))),
331    /// An invalid preprocessor identifier specification
332    ///
333    /// ```rust
334    /// # use scarf_parser::*;
335    /// # let mut state = PreprocessorState::new(vec![], vec![]);
336    /// # let cache = PreprocessorCache::new();
337    /// let source = "
338    /// `define TEST(a, b) a``_with_``b
339    /// `TEST(\"one\", \"two\")
340    /// ";
341    /// let input = lex(source, "test.v").tokens();
342    /// let preprocess_result = preprocess(
343    ///     &mut TokenIterator::new(input.into_iter()),
344    ///     &mut state,
345    ///     &cache,
346    /// );
347    /// assert!(matches!(preprocess_result, Err(PreprocessorError::InvalidIdentifierFormation(_))));
348    /// ```
349    InvalidIdentifierFormation((&'a str, Span<'a>)),
350    /// A precision that is less precise than the unit in a `` `timescale `` directive
351    ///
352    /// ```rust
353    /// # use scarf_parser::*;
354    /// # let mut state = PreprocessorState::new(vec![], vec![]);
355    /// # let cache = PreprocessorCache::new();
356    /// let source = "
357    /// `timescale 100 fs / 1 s
358    /// ";
359    /// let input = lex(source, "test.v").tokens();
360    /// let preprocess_result = preprocess(
361    ///     &mut TokenIterator::new(input.into_iter()),
362    ///     &mut state,
363    ///     &cache,
364    /// );
365    /// assert!(matches!(preprocess_result, Err(PreprocessorError::InvalidRelativeTimescales(_))));
366    /// ```
367    InvalidRelativeTimescales(Span<'a>),
368    /// An incomplete macro due to mismatching grouping tokens (`[]`, `()`, or `{}`)
369    ///
370    /// ```rust
371    /// # use scarf_parser::*;
372    /// # let mut state = PreprocessorState::new(vec![], vec![]);
373    /// # let cache = PreprocessorCache::new();
374    /// let source = "
375    /// `define TEST(a, b) a + b
376    /// `TEST(a = 1, b = 2])
377    /// ";
378    /// let input = lex(source, "test.v").tokens();
379    /// let preprocess_result = preprocess(
380    ///     &mut TokenIterator::new(input.into_iter()),
381    ///     &mut state,
382    ///     &cache,
383    /// );
384    /// assert!(matches!(preprocess_result, Err(PreprocessorError::IncompleteMacroWithToken(_))));
385    /// ```
386    IncompleteMacroWithToken(SpannedToken<'a>),
387    /// An error reading a file specified by an  `` `include `` macro
388    ///
389    /// ```rust
390    /// # use scarf_parser::*;
391    /// # let mut state = PreprocessorState::new(vec![], vec![]);
392    /// # let cache = PreprocessorCache::new();
393    /// let source = "
394    /// `include \"other.v\"
395    /// ";
396    /// let input = lex(source, "test.v").tokens();
397    /// let preprocess_result = preprocess(
398    ///     &mut TokenIterator::new(input.into_iter()),
399    ///     &mut state,
400    ///     &cache,
401    /// );
402    /// assert!(matches!(preprocess_result, Err(PreprocessorError::Include(_, _, _))));
403    /// ```
404    Include(Span<'a>, String, io::Error),
405    /// The maximum include depth was hit, likely as a result of a self-referential
406    /// `` `include `` sequence
407    ///
408    /// ```rust
409    /// # use scarf_parser::*;
410    /// # let mut state = PreprocessorState::new(vec![], vec![]);
411    /// # let cache = PreprocessorCache::new();
412    /// let source = "
413    /// `include \"test.v\"
414    /// ";
415    /// state.retain_file(
416    ///     "test.v".to_string(),
417    ///     source.to_string(),
418    ///     &cache,
419    /// );
420    /// let input = lex(source, "test.v").tokens();
421    /// let preprocess_result = preprocess(
422    ///     &mut TokenIterator::new(input.into_iter()),
423    ///     &mut state,
424    ///     &cache,
425    /// );
426    /// assert!(matches!(preprocess_result, Err(PreprocessorError::IncludeDepth(_, _))));
427    /// ```
428    IncludeDepth(Span<'a>, Vec<Span<'a>>),
429    /// A [`VerboseError`] detailing the expected and found tokens, for a case not covered above
430    ///
431    /// This is most commonly used when we can provide the user with a bit more context
432    ///
433    /// ```rust
434    /// # use scarf_parser::*;
435    /// # let mut state = PreprocessorState::new(vec![], vec![]);
436    /// # let cache = PreprocessorCache::new();
437    /// let source = "
438    /// `line
439    /// ";
440    /// let input = lex(source, "test.v").tokens();
441    /// let preprocess_result = preprocess(
442    ///     &mut TokenIterator::new(input.into_iter()),
443    ///     &mut state,
444    ///     &cache,
445    /// );
446    /// // Expects a line number
447    /// assert!(matches!(preprocess_result, Err(PreprocessorError::VerboseError(_))));
448    /// ```
449    VerboseError(VerboseError<'a>),
450    // Internal "errors" used for communication
451    // - Should not be exposed outside of main preprocess function
452    /// **INTERNAL**: A newline encountered in a `` `define `` directive
453    NewlineInDefine(Span<'a>),
454    /// **INTERNAL**: The end of a function argument was encountered
455    EndOfFunctionArgument(SpannedToken<'a>),
456}
457
458fn make_report<'s>(
459    span: &Span<'s>,
460    code: &str,
461    reason: String,
462    code_label: String,
463    kind: ariadne::ReportKind<'s>,
464) -> ReportBuilder<'s, (String, std::ops::Range<usize>)> {
465    let report =
466        Report::build(kind, (span.file.to_string(), span.bytes.clone()))
467            .with_code(code)
468            .with_config(
469                ariadne::Config::new()
470                    .with_index_type(ariadne::IndexType::Byte),
471            )
472            .with_message(reason);
473    attach_span_label(span, kind_color(&kind), code_label, report)
474}
475
476impl<'s> From<&PreprocessorError<'s>>
477    for Report<'s, (String, std::ops::Range<usize>)>
478{
479    fn from(s: &PreprocessorError<'s>) -> Self {
480        match s {
481            PreprocessorError::Endif(endif_span) => make_report(
482                endif_span,
483                "PP1",
484                "Unexpected `endif".to_string(),
485                "Unexpected `endif".to_string(),
486                ReportKind::Error,
487            ).finish(),
488            PreprocessorError::NoEndif(token, ifdef_span) => make_report(
489                ifdef_span,
490                "PP2",
491                format!("No matching `endif for {token}"),
492                "No matching `endif".to_owned(),
493                ReportKind::Error,
494            ).finish(),
495            PreprocessorError::Elsif(elsif_span) => make_report(
496                elsif_span,
497                "PP3",
498                "Unexpected `elsif".to_string(),
499                "Unexpected `elsif".to_string(),
500                ReportKind::Error,
501            ).finish(),
502            PreprocessorError::Else(else_span) => make_report(
503                else_span,
504                "PP4",
505                "Unexpected `else".to_string(),
506                "Unexpected `else".to_string(),
507                ReportKind::Error,
508            ).finish(),
509            PreprocessorError::EndKeywords(end_keywords_span) => make_report(
510                end_keywords_span,
511                "PP5",
512                "`end_keywords with no previous `begin_keywords".to_string(),
513                "No matching `begin_keywords".to_string(),
514                ReportKind::Error,
515            ).finish(),
516            PreprocessorError::NoEndKeywords(begin_span) => make_report(
517                begin_span,
518                "PP6",
519                "`begin_keywords with no matching `end_keywords".to_string(),
520                "No matching `end_keywords".to_string(),
521                ReportKind::Error,
522            ).finish(),
523            PreprocessorError::InvalidDefineParameter(err_spanned_token) => {
524                make_report(
525                    &err_spanned_token.1,
526                    "PP7",
527                    format!(
528                        "Found {}, expected a preprocessor macro parameter/identifier",
529                        err_spanned_token.0
530                    ),
531                    format!("Unexpected {}", err_spanned_token.0),
532                    ReportKind::Error,
533                ).finish()
534            }
535            PreprocessorError::InvalidDefineArgument(err_spanned_token) => {
536                make_report(
537                    &err_spanned_token.1,
538                    "PP7",
539                    format!(
540                        "Found {}, expected a comma, ), or a preprocessor macro argument",
541                        err_spanned_token.0
542                    ),
543                    format!("Unexpected {}", err_spanned_token.0),
544                    ReportKind::Error,
545                ).finish()
546            }
547            PreprocessorError::InvalidVersionSpecifier((
548                spec_string,
549                spec_span,
550            )) => make_report(
551                spec_span,
552                "PP8",
553                match spec_string {
554                    Some(version_string) => format!("{version_string} is not a valid version specifier"),
555                    None => "Not a valid version specifier".to_string()
556                },
557                "Invalid version specifier".to_string(),
558                ReportKind::Error,
559            ).finish(),
560            PreprocessorError::IncompleteDirective(span) => make_report(
561                span,
562                "PP9",
563                "Incomplete directive".to_string(),
564                "Expected a complete directive".to_string(),
565                ReportKind::Error,
566            ).finish(),
567            PreprocessorError::IncompleteDefine(
568                err_spanned_token,
569            ) => make_report(
570                &err_spanned_token.1,
571                "PP10",
572                format!(
573                    "Found {}, expected more in the preprocessor definition",
574                    err_spanned_token.0
575                ),
576                "Expected more after".to_string(),
577                ReportKind::Error,
578            ).finish(),
579            PreprocessorError::UndefinedMacro((macro_name, macro_span)) => {
580                make_report(
581                    macro_span,
582                    "PP11",
583                    format!("{macro_name} has not been previously defined"),
584                    "Not previously defined".to_string(),
585                    ReportKind::Error,
586                ).finish()
587            }
588            PreprocessorError::DuplicateMacroParameter((define_name, arg_name, arg_span, prev_span)) => {
589                attach_span_label(prev_span, NOTE_COLOR, "Previously declared here", make_report(
590                    arg_span,
591                    "PP14",
592                    format!("'{arg_name}' was already declared as a macro parameter for {define_name}"),
593                    "Duplicate parameter declaration".to_string(),
594                    ReportKind::Error,
595                )).finish()
596            }
597            PreprocessorError::NoDefaultAfterDefault((last_default_arg, no_default_arg)) => {
598                attach_span_label(&last_default_arg.1, NOTE_COLOR, format!("{} had a default specified", last_default_arg.0), make_report(
599                    &no_default_arg.1,
600                    "PP15",
601                    format!("No default specified for argument after one with a default"),
602                    "No default specified".to_string(),
603                    ReportKind::Error,
604                )).finish()
605            }
606            PreprocessorError::NoMacroArguments((define_span, (macro_name, macro_span))) => {
607                attach_span_label(define_span, NOTE_COLOR, "Macro defined here", make_report(
608                    macro_span,
609                    "PP16",
610                    format!("Expected arguments when using {macro_name}"),
611                    "Expected arguments not present".to_string(),
612                    ReportKind::Error,
613                )).finish()
614            }
615            PreprocessorError::TooManyMacroArguments((define_span, (macro_name, expected, found, macro_span))) => {
616                attach_span_label(define_span, NOTE_COLOR, format!("Macro definition expects {expected} arguments"), make_report(
617                    macro_span,
618                    "PP17",
619                    format!("{} expected {} arguments, but {} were provided", macro_name, expected, found),
620                    format!("{found} arguments provided"),
621                    ReportKind::Error,
622                )).finish()
623            }
624            PreprocessorError::MissingMacroArgument((define_span, (arg_name, macro_span))) => {
625                attach_span_label(define_span, NOTE_COLOR, "Macro defined here", make_report(
626                    macro_span,
627                    "PP18",
628                    format!("'{arg_name}' wasn't specified and has no default"),
629                    "Missing argument".to_string(),
630                    ReportKind::Error,
631                )).finish()
632            }
633            PreprocessorError::InvalidIdentifierFormation((arg_name, arg_span)) => {
634                make_report(
635                    arg_span,
636                    "PP19",
637                    format!("The argument for '{arg_name}' cannot be concatenated into an identifier"),
638                    "No valid conversion to identifier".to_string(),
639                    ReportKind::Error,
640                ).finish()
641            }
642            PreprocessorError::InvalidRelativeTimescales(timescale_span) => {
643                make_report(
644                    timescale_span,
645                    "PP20",
646                    "Time precision is larger than the time unit".to_string(),
647                    "Cannot have delay unit be smaller than precision".to_string(),
648                    ReportKind::Error,
649                ).finish()
650            }
651            PreprocessorError::IncompleteMacroWithToken(err_spanned_token) => {
652                make_report(
653                  &err_spanned_token.1,
654                  "PP21",
655                  format!("Usage of {} is incomplete", err_spanned_token.0),
656                  "Expected a complete macro argument or escaped newline after".to_string(),
657                  ReportKind::Error,
658              ).finish()
659            }
660            PreprocessorError::Include(span, path, io_error) => {
661                make_report(
662                    span,
663                    "PP22",
664                    format!("Error when reading {}", path),
665                    io_error.to_string(),
666                    ReportKind::Error,
667                ).finish()
668            }
669            PreprocessorError::IncludeDepth(span, _prev_include_spans) => {
670                make_report(
671                    span,
672                    "PP23",
673                    format!("Include depth of {} reached", MAX_INCLUDE_DEPTH),
674                    "Check for an `include loop".to_string(),
675                    ReportKind::Error,
676                ).finish()
677            }
678            PreprocessorError::VerboseError(verbose_error) => {
679              verbose_error.report("PP24")
680            },
681            PreprocessorError::NewlineInDefine(newline_span) => make_report(
682              newline_span,
683              "PPX",
684              "(Internal Error) Newline in define not handled correctly".to_string(),
685              "(Internal Error) Newline in define not handled correctly".to_string(),
686              ReportKind::Error,
687          ).finish(),
688            PreprocessorError::EndOfFunctionArgument(err_spanned_token) => {
689              make_report(
690                &err_spanned_token.1,
691                "PPX",
692                "(Internal Error) End of function argument not handled correctly".to_string(),
693                "(Internal Error) End of function argument not handled correctly".to_string(),
694                ReportKind::Error,
695            ).finish()
696            }
697        }
698    }
699}
700
701/// A warning encountered during preprocessing
702///
703/// Warnings reflect an irregularity in the source code, but are
704/// still well-defined and allow preprocessing to continue
705#[derive(Debug, Clone, PartialEq)]
706pub enum PreprocessorWarning<'a> {
707    /// Attempted to `` `undef `` a macro that had no previous definition
708    ///
709    /// ```rust
710    /// # use scarf_parser::*;
711    /// # let mut state = PreprocessorState::new(vec![], vec![]);
712    /// # let cache = PreprocessorCache::new();
713    /// let source = "
714    /// `undef TEST
715    /// ";
716    /// let input = lex(source, "test.v").tokens();
717    /// let preprocess_result = preprocess(
718    ///     &mut TokenIterator::new(input.into_iter()),
719    ///     &mut state,
720    ///     &cache,
721    /// );
722    /// assert!(matches!(preprocess_result, Ok(_)));
723    /// assert!(matches!(state.warnings.first(), Some(PreprocessorWarning::NotPreviouslyDefinedMacro(_))))
724    /// ```
725    NotPreviouslyDefinedMacro((&'a str, Span<'a>)),
726    /// A redefinition of a text macro that was previously defined
727    ///
728    /// ```rust
729    /// # use scarf_parser::*;
730    /// # let mut state = PreprocessorState::new(vec![], vec![]);
731    /// # let cache = PreprocessorCache::new();
732    /// let source = "
733    /// `define TEST definition_one
734    /// `define TEST definition_two
735    /// ";
736    /// let input = lex(source, "test.v").tokens();
737    /// let preprocess_result = preprocess(
738    ///     &mut TokenIterator::new(input.into_iter()),
739    ///     &mut state,
740    ///     &cache,
741    /// );
742    /// assert!(matches!(preprocess_result, Ok(_)));
743    /// assert!(matches!(state.warnings.first(), Some(PreprocessorWarning::RedefinedMacro(_))))
744    /// ```
745    RedefinedMacro((&'a str, Span<'a>, Span<'a>)),
746}
747
748impl<'s> From<&PreprocessorWarning<'s>>
749    for Report<'s, (String, std::ops::Range<usize>)>
750{
751    fn from(s: &PreprocessorWarning<'s>) -> Self {
752        match s {
753            PreprocessorWarning::RedefinedMacro((macro_name, macro_span, prev_span)) => {
754                attach_span_label(prev_span, NOTE_COLOR, "Previously defined here", make_report(
755                    macro_span,
756                    "PP12",
757                    format!("Redefining {macro_name}"),
758                    "Redefined here".to_string(),
759                    ReportKind::Warning,
760                )).finish()
761            }
762            PreprocessorWarning::NotPreviouslyDefinedMacro((
763                macro_name,
764                macro_span,
765            )) => make_report(
766                macro_span,
767                "PP13",
768                format!("Undefining {macro_name}, which has not been previously defined"),
769                "Not previously defined".to_string(),
770                ReportKind::Warning,
771            ).finish(),
772        }
773    }
774}