1// Copyright (c) 2024 Jonas Schäfer <jonas@zombofant.net>
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7//! Identifiers used within generated code.
8
9use proc_macro2::Span;
10use syn::*;
11
12/// Container struct for various identifiers used throughout the parser code.
13///
14/// This struct is passed around from the [`crate::compound::Compound`]
15/// downward to the code generators in order to ensure that everyone is on the
16/// same page about which identifiers are used for what.
17///
18/// The recommended usage is to bind the names which are needed into the local
19/// scope like this:
20///
21/// ```text
22/// # let scope = FromEventsScope::new();
23/// let FromEventsScope {
24/// ref attrs,
25/// ..
26/// } = scope;
27/// ```
28pub(crate) struct FromEventsScope {
29 /// Accesses the `AttrMap` from code in
30 /// [`crate::field::FieldBuilderPart::Init`].
31 pub(crate) attrs: Ident,
32
33 /// Accesses the `String` of a `rxml::Event::Text` event from code in
34 /// [`crate::field::FieldBuilderPart::Text`].
35 pub(crate) text: Ident,
36
37 /// Accesses the builder data during parsing.
38 ///
39 /// This should not be used directly outside [`crate::compound`]. Most of
40 /// the time, using [`Self::access_field`] is the correct way to access
41 /// the builder data.
42 pub(crate) builder_data_ident: Ident,
43}
44
45impl FromEventsScope {
46 /// Create a fresh scope with all necessary identifiers.
47 pub(crate) fn new() -> Self {
48 // Sadly, `Ident::new` is not `const`, so we have to create even the
49 // well-known identifiers from scratch all the time.
50 Self {
51 attrs: Ident::new("attrs", Span::call_site()),
52 text: Ident::new("__xso_proc_macro_text_data", Span::call_site()),
53 builder_data_ident: Ident::new("__xso_proc_macro_builder_data", Span::call_site()),
54 }
55 }
56
57 /// Generate an expression which accesses the temporary value for the
58 /// given `member` during parsing.
59 pub(crate) fn access_field(&self, member: &Member) -> Expr {
60 Expr::Field(ExprField {
61 attrs: Vec::new(),
62 base: Box::new(Expr::Path(ExprPath {
63 attrs: Vec::new(),
64 qself: None,
65 path: self.builder_data_ident.clone().into(),
66 })),
67 dot_token: syn::token::Dot {
68 spans: [Span::call_site()],
69 },
70 member: Member::Named(mangle_member(member)),
71 })
72 }
73}
74
75/// Container struct for various identifiers used throughout the generator
76/// code.
77///
78/// This struct is passed around from the [`crate::compound::Compound`]
79/// downward to the code generators in order to ensure that everyone is on the
80/// same page about which identifiers are used for what.
81///
82/// See [`FromEventsScope`] for recommendations on the usage.
83pub(crate) struct IntoEventsScope {
84 /// Accesses the `AttrMap` from code in
85 /// [`crate::field::FieldIteratorPart::Header`].
86 pub(crate) attrs: Ident,
87}
88
89impl IntoEventsScope {
90 /// Create a fresh scope with all necessary identifiers.
91 pub(crate) fn new() -> Self {
92 Self {
93 attrs: Ident::new("attrs", Span::call_site()),
94 }
95 }
96}
97
98pub(crate) fn mangle_member(member: &Member) -> Ident {
99 match member {
100 Member::Named(member) => quote::format_ident!("f{}", member),
101 Member::Unnamed(member) => quote::format_ident!("f_u{}", member.index),
102 }
103}