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
12use crate::types::ref_ty;
13
14/// Container struct for various identifiers used throughout the parser code.
15///
16/// This struct is passed around from the [`crate::compound::Compound`]
17/// downward to the code generators in order to ensure that everyone is on the
18/// same page about which identifiers are used for what.
19///
20/// The recommended usage is to bind the names which are needed into the local
21/// scope like this:
22///
23/// ```text
24/// # let scope = FromEventsScope::new();
25/// let FromEventsScope {
26/// ref attrs,
27/// ..
28/// } = scope;
29/// ```
30pub(crate) struct FromEventsScope {
31 /// Accesses the `AttrMap` from code in
32 /// [`crate::field::FieldBuilderPart::Init`].
33 pub(crate) attrs: Ident,
34
35 /// Accesses the `String` of a `rxml::Event::Text` event from code in
36 /// [`crate::field::FieldBuilderPart::Text`].
37 pub(crate) text: Ident,
38
39 /// Accesses the builder data during parsing.
40 ///
41 /// This should not be used directly outside [`crate::compound`]. Most of
42 /// the time, using [`Self::access_field`] is the correct way to access
43 /// the builder data.
44 pub(crate) builder_data_ident: Ident,
45
46 /// Accesses the result produced by a nested state's builder type.
47 ///
48 /// See [`crate::field::FieldBuilderPart::Nested`].
49 pub(crate) substate_data: Ident,
50
51 /// Accesses the result produced by a nested state's builder type.
52 ///
53 /// See [`crate::field::FieldBuilderPart::Nested`].
54 pub(crate) substate_result: Ident,
55}
56
57impl FromEventsScope {
58 /// Create a fresh scope with all necessary identifiers.
59 pub(crate) fn new() -> Self {
60 // Sadly, `Ident::new` is not `const`, so we have to create even the
61 // well-known identifiers from scratch all the time.
62 Self {
63 attrs: Ident::new("attrs", Span::call_site()),
64 text: Ident::new("__xso_proc_macro_text_data", Span::call_site()),
65 builder_data_ident: Ident::new("__xso_proc_macro_builder_data", Span::call_site()),
66 substate_data: Ident::new("__xso_proc_macro_substate_data", Span::call_site()),
67 substate_result: Ident::new("__xso_proc_macro_substate_result", Span::call_site()),
68 }
69 }
70
71 /// Generate an expression which accesses the temporary value for the
72 /// given `member` during parsing.
73 pub(crate) fn access_field(&self, member: &Member) -> Expr {
74 Expr::Field(ExprField {
75 attrs: Vec::new(),
76 base: Box::new(Expr::Path(ExprPath {
77 attrs: Vec::new(),
78 qself: None,
79 path: self.builder_data_ident.clone().into(),
80 })),
81 dot_token: syn::token::Dot {
82 spans: [Span::call_site()],
83 },
84 member: Member::Named(mangle_member(member)),
85 })
86 }
87}
88
89/// Container struct for various identifiers used throughout the generator
90/// code.
91///
92/// This struct is passed around from the [`crate::compound::Compound`]
93/// downward to the code generators in order to ensure that everyone is on the
94/// same page about which identifiers are used for what.
95///
96/// See [`FromEventsScope`] for recommendations on the usage.
97pub(crate) struct AsItemsScope {
98 /// Lifetime for data borrowed by the implementation.
99 pub(crate) lifetime: Lifetime,
100}
101
102impl AsItemsScope {
103 /// Create a fresh scope with all necessary identifiers.
104 pub(crate) fn new(lifetime: &Lifetime) -> Self {
105 Self {
106 lifetime: lifetime.clone(),
107 }
108 }
109
110 /// Create a reference to `ty`, borrowed for the lifetime of the AsXml
111 /// impl.
112 pub(crate) fn borrow(&self, ty: Type) -> Type {
113 ref_ty(ty, self.lifetime.clone())
114 }
115}
116
117pub(crate) fn mangle_member(member: &Member) -> Ident {
118 match member {
119 Member::Named(member) => quote::format_ident!("f{}", member),
120 Member::Unnamed(member) => quote::format_ident!("f_u{}", member.index),
121 }
122}