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

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