Skip to main content

macroonz_compiler/host/
place.rs

1//! Placing one refusal as a `compile_error!` at the position it is a fact about.
2//!
3//! Both roads end in one composition, so a refusal the compiler established and one this host raised point at their token the same way and neither can drift into answering with the declaration's first span.
4
5use super::types::{CaptureError, Spans};
6use crate::diagnostic::Diagnostic;
7use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
8
9/// The `compile_error!` one diagnostic expands to, at the token its site names.
10///
11/// The line is the one the compiler composed and is only read here; this host builds no sentence.
12/// A diagnostic that names no token was established before any capture issued one, and is reported at the invocation — which is the only thing about the expansion such an observation is a fact about.
13#[must_use]
14pub fn place(diagnostic: &Diagnostic, spans: &Spans) -> TokenStream {
15    refused(diagnostic.summary(), sited(diagnostic, spans))
16}
17
18impl CaptureError {
19    /// The `compile_error!` this refusal expands to, at the position it is a fact about.
20    ///
21    /// A magnitude is a fact about the whole declaration and no one token overran it, so it is reported at the invocation.
22    /// A literal this crate could not read is a fact about exactly one token, and that token's handle was issued before its payload was read — so the span is held and the report goes there.
23    ///
24    /// # Nonclaims
25    ///
26    /// It is not a [`Diagnostic`]: composing one needs the door whose prefix, grammar, and callable entry the line carries, and a capture runs before any door is named.
27    #[must_use]
28    pub fn placed(self, spans: &Spans) -> TokenStream {
29        let at = match &self {
30            Self::Unbounded { .. } => Span::call_site(),
31            Self::Unread { at, .. } => spans.at(*at),
32        };
33        refused(&self.to_string(), at)
34    }
35}
36
37/// The compiler span one diagnostic points at.
38fn sited(diagnostic: &Diagnostic, spans: &Spans) -> Span {
39    diagnostic
40        .site()
41        .token()
42        .map_or_else(Span::call_site, |handle| spans.at(handle))
43}
44
45/// One `compile_error!` at one span, carrying a line composed elsewhere.
46fn refused(message: &str, span: Span) -> TokenStream {
47    let mut bang = Punct::new('!', Spacing::Alone);
48    bang.set_span(span);
49    let mut terminator = Punct::new(';', Spacing::Alone);
50    terminator.set_span(span);
51    let mut line = Literal::string(message);
52    line.set_span(span);
53    let mut argument = Group::new(
54        Delimiter::Parenthesis,
55        TokenStream::from(TokenTree::Literal(line)),
56    );
57    argument.set_span(span);
58    [
59        TokenTree::Ident(Ident::new("compile_error", span)),
60        TokenTree::Punct(bang),
61        TokenTree::Group(argument),
62        TokenTree::Punct(terminator),
63    ]
64    .into_iter()
65    .collect()
66}