cairo_lang_defs/
plugin.rs

1use std::any::Any;
2use std::ops::Deref;
3use std::sync::Arc;
4
5use cairo_lang_diagnostics::Severity;
6use cairo_lang_filesystem::cfg::CfgSet;
7use cairo_lang_filesystem::db::Edition;
8use cairo_lang_filesystem::ids::CodeMapping;
9use cairo_lang_syntax::node::ast;
10use cairo_lang_syntax::node::db::SyntaxGroup;
11use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
12use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
13use smol_str::SmolStr;
14
15/// A trait for arbitrary data that a macro generates along with a generated file.
16pub trait GeneratedFileAuxData: std::fmt::Debug + Sync + Send {
17    fn as_any(&self) -> &dyn Any;
18    fn eq(&self, other: &dyn GeneratedFileAuxData) -> bool;
19}
20
21#[derive(Clone, Debug)]
22pub struct DynGeneratedFileAuxData(pub Arc<dyn GeneratedFileAuxData>);
23impl DynGeneratedFileAuxData {
24    pub fn new<T: GeneratedFileAuxData + 'static>(aux_data: T) -> Self {
25        DynGeneratedFileAuxData(Arc::new(aux_data))
26    }
27}
28impl Deref for DynGeneratedFileAuxData {
29    type Target = Arc<dyn GeneratedFileAuxData>;
30
31    fn deref(&self) -> &Self::Target {
32        &self.0
33    }
34}
35impl PartialEq for DynGeneratedFileAuxData {
36    fn eq(&self, that: &DynGeneratedFileAuxData) -> bool {
37        GeneratedFileAuxData::eq(&*self.0, &*that.0)
38    }
39}
40impl Eq for DynGeneratedFileAuxData {}
41
42/// Virtual code file generated by a plugin.
43pub struct PluginGeneratedFile {
44    /// Name for the virtual file. Will appear in diagnostics.
45    pub name: SmolStr,
46    /// Code content for the file.
47    pub content: String,
48    /// A code mapper, to allow more readable diagnostics that originate in plugin generated
49    /// virtual files.
50    pub code_mappings: Vec<CodeMapping>,
51    /// Arbitrary data that the plugin generates along with the file.
52    pub aux_data: Option<DynGeneratedFileAuxData>,
53    /// Diagnostic note for the plugin generated file.
54    /// This will be used as [`cairo_lang_diagnostics::DiagnosticNote`] on diagnostics originating
55    /// from this file.
56    pub diagnostics_note: Option<String>,
57}
58
59/// Result of plugin code generation.
60#[derive(Default)]
61pub struct PluginResult {
62    /// Filename, content.
63    pub code: Option<PluginGeneratedFile>,
64    /// Diagnostics.
65    pub diagnostics: Vec<PluginDiagnostic>,
66    /// If true - the original item should be removed, if false - it should remain as is.
67    pub remove_original_item: bool,
68}
69
70#[derive(Clone, Debug, Eq, Hash, PartialEq)]
71pub struct PluginDiagnostic {
72    pub stable_ptr: SyntaxStablePtrId,
73    pub message: String,
74    pub severity: Severity,
75}
76impl PluginDiagnostic {
77    pub fn error(stable_ptr: impl Into<SyntaxStablePtrId>, message: String) -> PluginDiagnostic {
78        PluginDiagnostic { stable_ptr: stable_ptr.into(), message, severity: Severity::Error }
79    }
80    pub fn warning(stable_ptr: impl Into<SyntaxStablePtrId>, message: String) -> PluginDiagnostic {
81        PluginDiagnostic { stable_ptr: stable_ptr.into(), message, severity: Severity::Warning }
82    }
83}
84
85/// A structure containing additional info about the current module item on which macro plugin
86/// operates.
87pub struct MacroPluginMetadata<'a> {
88    /// Config set of the crate to which the current item belongs.
89    pub cfg_set: &'a CfgSet,
90    /// The possible derives declared by any plugin.
91    pub declared_derives: &'a OrderedHashSet<String>,
92    /// The allowed features at the macro activation site.
93    pub allowed_features: &'a OrderedHashSet<SmolStr>,
94    /// The edition of the crate to which the current item belongs.
95    pub edition: Edition,
96}
97
98// TOD(spapini): Move to another place.
99/// A trait for a macro plugin: external plugin that generates additional code for items.
100pub trait MacroPlugin: std::fmt::Debug + Sync + Send {
101    /// Generates code for an item. If no code should be generated returns None.
102    /// Otherwise, returns (virtual_module_name, module_content), and a virtual submodule
103    /// with that name and content should be created.
104    fn generate_code(
105        &self,
106        db: &dyn SyntaxGroup,
107        item_ast: ast::ModuleItem,
108        metadata: &MacroPluginMetadata<'_>,
109    ) -> PluginResult;
110
111    /// Attributes this plugin uses.
112    /// Attributes the plugin uses without declaring here are likely to cause a compilation error
113    /// for unknown attribute.
114    /// Note: They may not cause a diagnostic if some other plugin declares such attribute, but
115    /// plugin writers should not rely on that.
116    fn declared_attributes(&self) -> Vec<String>;
117
118    /// Derives this plugin supplies.
119    /// Any derived classes the plugin supplies without declaring here are likely to cause a
120    /// compilation error for unknown derive.
121    /// Note: They may not cause a diagnostic if some other plugin declares such derive, but
122    /// plugin writers should not rely on that.
123    fn declared_derives(&self) -> Vec<String> {
124        Vec::new()
125    }
126
127    /// Attributes that should mark the function as an executable.
128    /// Functions marked with executable attributes will be listed
129    /// in a dedicated field in the generated program.
130    /// Must return a subset of `declared_attributes`.
131    /// This mechanism is optional.
132    fn executable_attributes(&self) -> Vec<String> {
133        Vec::new()
134    }
135
136    /// Attributes that mark a type as a phantom type. Must return a subset of
137    /// `declared_attributes`.
138    /// This mechanism is optional.
139    fn phantom_type_attributes(&self) -> Vec<String> {
140        Vec::new()
141    }
142}
143
144/// Result of plugin code generation.
145#[derive(Default)]
146pub struct InlinePluginResult {
147    pub code: Option<PluginGeneratedFile>,
148    /// Diagnostics.
149    pub diagnostics: Vec<PluginDiagnostic>,
150}
151
152pub trait InlineMacroExprPlugin: std::fmt::Debug + Sync + Send {
153    /// Generates code for an item. If no code should be generated returns None.
154    /// Otherwise, returns (virtual_module_name, module_content), and a virtual submodule
155    /// with that name and content should be created.
156    fn generate_code(
157        &self,
158        db: &dyn SyntaxGroup,
159        item_ast: &ast::ExprInlineMacro,
160        metadata: &MacroPluginMetadata<'_>,
161    ) -> InlinePluginResult;
162
163    /// Allows for the plugin to provide documentation for an inline macro.
164    fn documentation(&self) -> Option<String> {
165        None
166    }
167}
168
169/// A trait for easier addition of macro plugins.
170pub trait NamedPlugin: Default + 'static {
171    const NAME: &'static str;
172}