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}