cairo_lang_defs/plugin.rs
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 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
use std::any::Any;
use std::ops::Deref;
use std::sync::Arc;
use cairo_lang_diagnostics::Severity;
use cairo_lang_filesystem::cfg::CfgSet;
use cairo_lang_filesystem::db::Edition;
use cairo_lang_filesystem::ids::CodeMapping;
use cairo_lang_syntax::node::ast;
use cairo_lang_syntax::node::db::SyntaxGroup;
use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
use smol_str::SmolStr;
/// A trait for arbitrary data that a macro generates along with a generated file.
pub trait GeneratedFileAuxData: std::fmt::Debug + Sync + Send {
fn as_any(&self) -> &dyn Any;
fn eq(&self, other: &dyn GeneratedFileAuxData) -> bool;
}
#[derive(Clone, Debug)]
pub struct DynGeneratedFileAuxData(pub Arc<dyn GeneratedFileAuxData>);
impl DynGeneratedFileAuxData {
pub fn new<T: GeneratedFileAuxData + 'static>(aux_data: T) -> Self {
DynGeneratedFileAuxData(Arc::new(aux_data))
}
}
impl Deref for DynGeneratedFileAuxData {
type Target = Arc<dyn GeneratedFileAuxData>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl PartialEq for DynGeneratedFileAuxData {
fn eq(&self, that: &DynGeneratedFileAuxData) -> bool {
GeneratedFileAuxData::eq(&*self.0, &*that.0)
}
}
impl Eq for DynGeneratedFileAuxData {}
/// Virtual code file generated by a plugin.
pub struct PluginGeneratedFile {
/// Name for the virtual file. Will appear in diagnostics.
pub name: SmolStr,
/// Code content for the file.
pub content: String,
/// A code mapper, to allow more readable diagnostics that originate in plugin generated
/// virtual files.
pub code_mappings: Vec<CodeMapping>,
/// Arbitrary data that the plugin generates along with the file.
pub aux_data: Option<DynGeneratedFileAuxData>,
/// Diagnostic note for the plugin generated file.
/// This will be used as [`cairo_lang_diagnostics::DiagnosticNote`] on diagnostics originating
/// from this file.
pub diagnostics_note: Option<String>,
}
/// Result of plugin code generation.
#[derive(Default)]
pub struct PluginResult {
/// Filename, content.
pub code: Option<PluginGeneratedFile>,
/// Diagnostics.
pub diagnostics: Vec<PluginDiagnostic>,
/// If true - the original item should be removed, if false - it should remain as is.
pub remove_original_item: bool,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct PluginDiagnostic {
pub stable_ptr: SyntaxStablePtrId,
pub message: String,
pub severity: Severity,
}
impl PluginDiagnostic {
pub fn error(stable_ptr: impl Into<SyntaxStablePtrId>, message: String) -> PluginDiagnostic {
PluginDiagnostic { stable_ptr: stable_ptr.into(), message, severity: Severity::Error }
}
pub fn warning(stable_ptr: impl Into<SyntaxStablePtrId>, message: String) -> PluginDiagnostic {
PluginDiagnostic { stable_ptr: stable_ptr.into(), message, severity: Severity::Warning }
}
}
/// A structure containing additional info about the current module item on which macro plugin
/// operates.
pub struct MacroPluginMetadata<'a> {
/// Config set of the crate to which the current item belongs.
pub cfg_set: &'a CfgSet,
/// The possible derives declared by any plugin.
pub declared_derives: &'a OrderedHashSet<String>,
/// The allowed features at the macro activation site.
pub allowed_features: &'a OrderedHashSet<SmolStr>,
/// The edition of the crate to which the current item belongs.
pub edition: Edition,
}
// TOD(spapini): Move to another place.
/// A trait for a macro plugin: external plugin that generates additional code for items.
pub trait MacroPlugin: std::fmt::Debug + Sync + Send {
/// Generates code for an item. If no code should be generated returns None.
/// Otherwise, returns (virtual_module_name, module_content), and a virtual submodule
/// with that name and content should be created.
fn generate_code(
&self,
db: &dyn SyntaxGroup,
item_ast: ast::ModuleItem,
metadata: &MacroPluginMetadata<'_>,
) -> PluginResult;
/// Attributes this plugin uses.
/// Attributes the plugin uses without declaring here are likely to cause a compilation error
/// for unknown attribute.
/// Note: They may not cause a diagnostic if some other plugin declares such attribute, but
/// plugin writers should not rely on that.
fn declared_attributes(&self) -> Vec<String>;
/// Derives this plugin supplies.
/// Any derived classes the plugin supplies without declaring here are likely to cause a
/// compilation error for unknown derive.
/// Note: They may not cause a diagnostic if some other plugin declares such derive, but
/// plugin writers should not rely on that.
fn declared_derives(&self) -> Vec<String> {
Vec::new()
}
/// Attributes that should mark the function as an executable.
/// Functions marked with executable attributes will be listed
/// in a dedicated field in the generated program.
/// Must return a subset of `declared_attributes`.
/// This mechanism is optional.
fn executable_attributes(&self) -> Vec<String> {
Vec::new()
}
/// Attributes that mark a type as a phantom type. Must return a subset of
/// `declared_attributes`.
/// This mechanism is optional.
fn phantom_type_attributes(&self) -> Vec<String> {
Vec::new()
}
}
/// Result of plugin code generation.
#[derive(Default)]
pub struct InlinePluginResult {
pub code: Option<PluginGeneratedFile>,
/// Diagnostics.
pub diagnostics: Vec<PluginDiagnostic>,
}
pub trait InlineMacroExprPlugin: std::fmt::Debug + Sync + Send {
/// Generates code for an item. If no code should be generated returns None.
/// Otherwise, returns (virtual_module_name, module_content), and a virtual submodule
/// with that name and content should be created.
fn generate_code(
&self,
db: &dyn SyntaxGroup,
item_ast: &ast::ExprInlineMacro,
metadata: &MacroPluginMetadata<'_>,
) -> InlinePluginResult;
/// Allows for the plugin to provide documentation for an inline macro.
fn documentation(&self) -> Option<String> {
None
}
}
/// A trait for easier addition of macro plugins.
pub trait NamedPlugin: Default + 'static {
const NAME: &'static str;
}