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, EmissionError, 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
18/// Place one host emission contradiction at the invocation boundary.
19pub(super) fn emission_refused(refusal: &EmissionError) -> TokenStream {
20    refused(&refusal.to_string(), Span::call_site())
21}
22
23impl CaptureError {
24    /// The `compile_error!` this refusal expands to, at the position it is a fact about.
25    ///
26    /// A magnitude is a fact about the whole declaration and no one token overran it, so it is reported at the invocation.
27    /// 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.
28    ///
29    /// # Nonclaims
30    ///
31    /// 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.
32    #[must_use]
33    pub fn placed(self, spans: &Spans) -> TokenStream {
34        let at = match &self {
35            Self::Unbounded { .. } => Span::call_site(),
36            Self::Unread { at, .. } => spans.at(*at),
37        };
38        refused(&self.to_string(), at)
39    }
40}
41
42/// The compiler span one diagnostic points at.
43fn sited(diagnostic: &Diagnostic, spans: &Spans) -> Span {
44    diagnostic
45        .site()
46        .token()
47        .map_or_else(Span::call_site, |handle| spans.at(handle))
48}
49
50/// One `compile_error!` at one span, carrying a line composed elsewhere.
51fn refused(message: &str, span: Span) -> TokenStream {
52    let mut bang = Punct::new('!', Spacing::Alone);
53    bang.set_span(span);
54    let mut terminator = Punct::new(';', Spacing::Alone);
55    terminator.set_span(span);
56    let mut line = Literal::string(message);
57    line.set_span(span);
58    let mut argument = Group::new(
59        Delimiter::Parenthesis,
60        TokenStream::from(TokenTree::Literal(line)),
61    );
62    argument.set_span(span);
63    [
64        TokenTree::Ident(Ident::new("compile_error", span)),
65        TokenTree::Punct(bang),
66        TokenTree::Group(argument),
67        TokenTree::Punct(terminator),
68    ]
69    .into_iter()
70    .collect()
71}