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
use std::any::Any;
use std::ops::Deref;
use std::sync::Arc;

use cairo_lang_syntax::node::ast;
use cairo_lang_syntax::node::db::SyntaxGroup;
use cairo_lang_syntax::node::ids::SyntaxStablePtrId;
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 diagnostics mapper, to allow more readable diagnostics that originate in plugin generated
    /// virtual files.
    pub aux_data: 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,
}

// 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::Item) -> PluginResult;
}