cairo_lang_defs/
plugin.rs1use std::any::{self, Any};
2use std::hash::{Hash, Hasher};
3use std::ops::Deref;
4use std::sync::Arc;
5
6use cairo_lang_diagnostics::{ErrorCode, Severity};
7use cairo_lang_filesystem::cfg::CfgSet;
8use cairo_lang_filesystem::db::Edition;
9use cairo_lang_filesystem::ids::{CodeMapping, SmolStrId};
10use cairo_lang_filesystem::span::TextWidth;
11use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
12use cairo_lang_syntax::node::{SyntaxNode, ast};
13use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
14use salsa::Database;
15use serde::{Deserialize, Serialize};
16
17#[typetag::serde]
19pub trait GeneratedFileAuxData: std::fmt::Debug + Sync + Send {
20 fn as_any(&self) -> &dyn Any;
21 fn eq(&self, other: &dyn GeneratedFileAuxData) -> bool;
22 fn hash_value(&self) -> u64;
25}
26
27#[derive(Clone, Debug, Serialize, Deserialize)]
28pub struct DynGeneratedFileAuxData(pub Arc<dyn GeneratedFileAuxData>);
29unsafe impl salsa::SalsaValue for DynGeneratedFileAuxData {}
30impl DynGeneratedFileAuxData {
31 pub fn new<T: GeneratedFileAuxData + 'static>(aux_data: T) -> Self {
32 DynGeneratedFileAuxData(Arc::new(aux_data))
33 }
34}
35impl Deref for DynGeneratedFileAuxData {
36 type Target = Arc<dyn GeneratedFileAuxData>;
37
38 fn deref(&self) -> &Self::Target {
39 &self.0
40 }
41}
42impl PartialEq for DynGeneratedFileAuxData {
43 fn eq(&self, that: &DynGeneratedFileAuxData) -> bool {
44 self.0.eq(&*that.0)
45 }
46}
47impl Eq for DynGeneratedFileAuxData {}
48impl Hash for DynGeneratedFileAuxData {
49 fn hash<H: Hasher>(&self, state: &mut H) {
50 self.0.hash_value().hash(state);
51 }
52}
53
54pub struct PluginGeneratedFile {
56 pub name: String,
58 pub content: String,
60 pub code_mappings: Vec<CodeMapping>,
63 pub aux_data: Option<DynGeneratedFileAuxData>,
65 pub diagnostics_note: Option<String>,
69 pub is_unhygienic: bool,
72}
73
74#[derive(Default)]
76pub struct PluginResult<'db> {
77 pub code: Option<PluginGeneratedFile>,
79 pub diagnostics: Vec<PluginDiagnostic<'db>>,
81 pub remove_original_item: bool,
83}
84
85#[derive(Clone, Debug, Eq, Hash, PartialEq, salsa::SalsaValue)]
87pub struct PluginDiagnostic<'db> {
88 pub stable_ptr: SyntaxStablePtrId<'db>,
90 pub message: String,
91 pub severity: Severity,
93 pub inner_span: Option<(TextWidth, TextWidth)>,
98 pub error_code: Option<ErrorCode>,
100}
101impl<'db> PluginDiagnostic<'db> {
102 pub fn error(
103 stable_ptr: impl Into<SyntaxStablePtrId<'db>>,
104 message: String,
105 ) -> PluginDiagnostic<'db> {
106 PluginDiagnostic {
107 stable_ptr: stable_ptr.into(),
108 message,
109 severity: Severity::Error,
110 inner_span: None,
111 error_code: None,
112 }
113 }
114
115 pub fn error_with_inner_span(
117 db: &dyn Database,
118 stable_ptr: impl Into<SyntaxStablePtrId<'db>>,
119 inner_span: SyntaxNode<'_>,
120 message: String,
121 ) -> PluginDiagnostic<'db> {
122 let stable_ptr = stable_ptr.into();
123 let offset = inner_span.offset(db) - stable_ptr.lookup(db).offset(db);
124 let width = inner_span.width(db);
125 PluginDiagnostic {
126 stable_ptr,
127 message,
128 severity: Severity::Error,
129 inner_span: Some((offset, width)),
130 error_code: None,
131 }
132 }
133
134 pub fn warning(
135 stable_ptr: impl Into<SyntaxStablePtrId<'db>>,
136 message: String,
137 ) -> PluginDiagnostic<'db> {
138 PluginDiagnostic {
139 stable_ptr: stable_ptr.into(),
140 message,
141 severity: Severity::Warning,
142 inner_span: None,
143 error_code: None,
144 }
145 }
146
147 pub fn with_error_code(self, error_code: ErrorCode) -> PluginDiagnostic<'db> {
149 PluginDiagnostic { error_code: Some(error_code), ..self }
150 }
151}
152
153pub struct MacroPluginMetadata<'a> {
156 pub cfg_set: &'a CfgSet,
158 pub declared_derives: &'a OrderedHashSet<SmolStrId<'a>>,
160 pub allowed_features: &'a OrderedHashSet<SmolStrId<'a>>,
162 pub edition: Edition,
164}
165
166pub trait MacroPlugin: std::fmt::Debug + Sync + Send + Any {
168 fn generate_code<'db>(
171 &self,
172 db: &'db dyn Database,
173 item_ast: ast::ModuleItem<'db>,
174 metadata: &MacroPluginMetadata<'_>,
175 ) -> PluginResult<'db>;
176
177 fn declared_attributes<'db>(&self, db: &'db dyn Database) -> Vec<SmolStrId<'db>>;
183
184 fn declared_derives<'db>(&self, _db: &'db dyn Database) -> Vec<SmolStrId<'db>> {
190 Vec::new()
191 }
192
193 fn executable_attributes<'db>(&self, _db: &'db dyn Database) -> Vec<SmolStrId<'db>> {
199 Vec::new()
200 }
201
202 fn phantom_type_attributes<'db>(&self, _db: &'db dyn Database) -> Vec<SmolStrId<'db>> {
206 Vec::new()
207 }
208
209 fn plugin_type_id(&self) -> any::TypeId {
212 self.type_id()
213 }
214}
215
216#[derive(Default)]
218pub struct InlinePluginResult<'db> {
219 pub code: Option<PluginGeneratedFile>,
220 pub diagnostics: Vec<PluginDiagnostic<'db>>,
222}
223
224pub trait InlineMacroExprPlugin: std::fmt::Debug + Sync + Send + Any {
225 fn generate_code<'db>(
229 &self,
230 db: &'db dyn Database,
231 item_ast: &ast::ExprInlineMacro<'db>,
232 metadata: &MacroPluginMetadata<'_>,
233 ) -> InlinePluginResult<'db>;
234
235 fn documentation(&self) -> Option<String> {
237 None
238 }
239
240 fn plugin_type_id(&self) -> any::TypeId {
243 self.type_id()
244 }
245}
246
247pub trait NamedPlugin: Default + 'static {
249 const NAME: &'static str;
250}