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
 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}