scope.rs

  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}