1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
use std::{collections::BTreeMap, sync::Arc}; use crate::{ ast::Argument, symbol::{Symbol, SymbolRef}, }; pub trait MetadataEnv { fn get_metadata(&self, id: &SymbolRef) -> Option<&Arc<Metadata>>; } impl<'a, T: ?Sized + MetadataEnv> MetadataEnv for &'a T { fn get_metadata(&self, id: &SymbolRef) -> Option<&Arc<Metadata>> { (**self).get_metadata(id) } } impl MetadataEnv for () { fn get_metadata(&self, _id: &SymbolRef) -> Option<&Arc<Metadata>> { None } } #[derive(Clone, Copy, Eq, PartialEq, Debug)] #[cfg_attr(feature = "serde_derive", derive(Deserialize, Serialize))] pub enum CommentType { Block, Line, } #[derive(Clone, Eq, PartialEq, Debug)] #[cfg_attr(feature = "serde_derive", derive(Deserialize, Serialize))] pub struct Comment { pub typ: CommentType, pub content: String, } #[derive(Clone, Debug, Default, Eq, PartialEq)] #[cfg_attr(feature = "serde_derive", derive(Deserialize, Serialize))] pub struct Attribute { pub name: String, pub arguments: Option<String>, } #[derive(Clone, Debug, Default, Eq, PartialEq)] #[cfg_attr(feature = "serde_derive", derive(Deserialize, Serialize))] pub struct Metadata { pub definition: Option<Symbol>, pub comment: Option<Comment>, pub attributes: Vec<Attribute>, pub args: Vec<Argument<Symbol>>, pub module: BTreeMap<String, Arc<Metadata>>, } impl Metadata { pub fn has_data(&self) -> bool { self.definition.is_some() || self.comment.is_some() || !self.module.is_empty() || !self.attributes.is_empty() } pub fn merge(mut self, other: Metadata) -> Metadata { self.merge_with(other); self } pub fn merge_with(&mut self, other: Metadata) { if other.definition.is_some() { self.definition = other.definition; } if self.comment.is_none() { self.comment = other.comment; } for (key, value) in other.module { use std::collections::btree_map::Entry; match self.module.entry(key) { Entry::Vacant(entry) => { entry.insert(value); } Entry::Occupied(entry) => Arc::make_mut(entry.into_mut()).merge_with_ref(&value), } } self.attributes.extend(other.attributes); if self.args.is_empty() { self.args = other.args; } } pub fn merge_ref(mut self, other: &Metadata) -> Self { self.merge_with_ref(other); self } pub fn merge_with_ref(&mut self, other: &Metadata) { if other.definition.is_some() { self.definition = other.definition.clone(); } if self.comment.is_none() { self.comment = other.comment.clone(); } for (key, value) in &other.module { use std::collections::btree_map::Entry; match self.module.entry(key.clone()) { Entry::Vacant(entry) => { entry.insert(value.clone()); } Entry::Occupied(entry) => Arc::make_mut(entry.into_mut()).merge_with_ref(&value), } } self.attributes.extend(other.attributes.iter().cloned()); if self.args.is_empty() { self.args = other.args.clone(); } } pub fn get_attribute(&self, name: &str) -> Option<&str> { self.attributes() .find(|attribute| attribute.name == name) .map(|t| t.arguments.as_ref().map_or("", |s| s)) } pub fn attributes(&self) -> impl Iterator<Item = &Attribute> { self.attributes.iter() } }