ferment-sys 0.2.14

Syntax tree morphing of FFI-compatible stuff
Documentation
use std::cell::RefCell;
use std::fmt::Formatter;
use std::collections::HashSet;
use std::rc::Rc;
use indexmap::IndexMap;
use syn::{Attribute, Item, ItemMod, ItemUse};
use crate::context::{GlobalContext, ScopeChain, ScopeContext, ScopeContextLink};
use crate::ext::MaybeIdent;
use crate::formatter::{format_imported_set, format_tree_exported_dict};
use crate::tree::{ScopeTreeID, GetScopeTreeID};


#[allow(clippy::large_enum_variant)]
#[derive(Clone)]
pub enum ScopeTreeExportItem {
    Item(ScopeContextLink, Item),
    Tree(ScopeContextLink, HashSet<ItemUse>, IndexMap<ScopeTreeID, ScopeTreeExportItem>, Vec<Attribute>),
}

impl std::fmt::Debug for ScopeTreeExportItem {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            ScopeTreeExportItem::Item(_, item) =>
                f.write_str(&format!("ScopeTreeExportItem::Item({:?})", item.maybe_ident())),
            ScopeTreeExportItem::Tree(context, imported, exported, attrs) =>
                f.debug_struct("ScopeTreeExportItem::Tree")
                    .field("context", context)
                    .field("imported", &format_imported_set(imported))
                    .field("exported", &format_tree_exported_dict(exported))
                    .field("attrs", attrs)
                    .finish()
        }
    }
}

impl std::fmt::Display for ScopeTreeExportItem {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        std::fmt::Debug::fmt(self, f)
    }
}

impl ScopeTreeExportItem {
    pub fn scope(&self) -> ScopeChain {
        match self {
            ScopeTreeExportItem::Item(ctx, ..) => ctx.borrow().scope.clone(),
            ScopeTreeExportItem::Tree(ctx, ..) => ctx.borrow().scope.clone(),
        }
    }
    pub fn tree_with_context_and_exports(context: ScopeContextLink, attrs: &[Attribute]) -> Self {
        Self::Tree(context, HashSet::default(), IndexMap::default(), attrs.to_owned())
    }
    pub fn tree_with_context(scope: &ScopeChain, context: Rc<RefCell<GlobalContext>>, attrs: &[Attribute]) -> Self {
        Self::tree_with_context_and_exports(ScopeContext::cell_with(scope.clone(), context), attrs)
    }
    pub fn item_with_context(scope: &ScopeChain, item: &Item, context: Rc<RefCell<GlobalContext>>) -> Self {
        Self::Item(ScopeContext::cell_with(scope.clone(), context), item.clone())
    }
    pub fn add_item(&mut self, item: Item, scope: ScopeChain) {
        if let ScopeTreeExportItem::Tree(..) = self {
            match &item {
                Item::Use(..) => {},
                Item::Mod(item_mod) => self.add_mod_item(item_mod, &scope),
                Item::Trait(..) |
                Item::Fn(..) |
                Item::Struct(..) |
                Item::Enum(..) |
                Item::Type(..) |
                Item::Impl(..) => self.add_non_mod_item(&item, &scope),
                _ => {}
            };
        }
    }

    fn add_items(&mut self, items: &[Item], scope: &ScopeChain) {
        items.iter().for_each(|item|
            match item {
                Item::Mod(item_mod) =>
                    self.add_mod_item(item_mod, scope),
                Item::Const(_) |
                Item::Enum(_) |
                Item::Fn(_) |
                Item::Impl(_) |
                Item::Struct(_) |
                Item::Trait(_) |
                Item::Type(_) => self.add_non_mod_item(item, scope),
                _ => {}
            }
        );
    }
    fn add_non_mod_item(&mut self, item: &Item, scope: &ScopeChain) {
        if let Self::Tree(scope_context, _, exported, _attrs) = self {
            exported.insert(item.scope_tree_id(), Self::item_with_context(scope, item, scope_context.borrow().context.clone()));
        }
    }

    fn add_mod_item(&mut self, item_mod: &ItemMod, scope: &ScopeChain) {
        let ItemMod { attrs, ident, content, .. } = item_mod;
        let new_export_item = |context: &mut ScopeContextLink| Self::tree_with_context(scope, context.borrow().context.clone(), attrs);
        match content {
            Some((_, items)) => match self {
                Self::Item(context, _) => {
                    let mut inner_tree = new_export_item(context);
                    inner_tree.add_items(items, scope);
                },
                Self::Tree(context, _, exported, _) => {
                    let mut inner_tree = new_export_item(context);
                    inner_tree.add_items(items, scope);
                    exported.insert(ScopeTreeID::from_ident(ident), inner_tree);
                }
            },
            None => if let Self::Tree(context, _, exported, _) = self {
                exported.insert(ScopeTreeID::from_ident(ident), new_export_item(context));
            }
        }
    }
}