1
- use crate :: core:: { Package , PackageId } ;
2
- use anyhow:: Result ;
1
+ use crate :: core:: { Config , Package , PackageId } ;
2
+ use anyhow:: { Context , Result } ;
3
3
use cairo_lang_defs:: patcher:: PatchBuilder ;
4
+ use cairo_lang_macro:: stable_abi:: { StableProcMacroResult , StableTokenStream } ;
4
5
use cairo_lang_macro:: { ProcMacroResult , TokenStream } ;
5
6
use cairo_lang_syntax:: node:: db:: SyntaxGroup ;
6
7
use cairo_lang_syntax:: node:: { ast, TypedSyntaxNode } ;
8
+ use camino:: Utf8PathBuf ;
9
+ use libloading:: { Library , Symbol } ;
7
10
use std:: fmt:: Debug ;
8
11
12
+ use crate :: compiler:: plugin:: proc_macro:: compilation:: SharedLibraryProvider ;
13
+ #[ cfg( not( windows) ) ]
14
+ use libloading:: os:: unix:: Symbol as RawSymbol ;
15
+ #[ cfg( windows) ]
16
+ use libloading:: os:: windows:: Symbol as RawSymbol ;
17
+
18
+ pub const PROC_MACRO_BUILD_PROFILE : & str = "release" ;
19
+
9
20
pub trait FromItemAst {
10
21
fn from_item_ast ( db : & dyn SyntaxGroup , item_ast : ast:: ModuleItem ) -> Self ;
11
22
}
@@ -22,31 +33,72 @@ impl FromItemAst for TokenStream {
22
33
///
23
34
/// This struct is a wrapper around a shared library containing the procedural macro implementation.
24
35
/// It is responsible for loading the shared library and providing a safe interface for code expansion.
25
- #[ derive( Debug , Clone ) ]
26
36
pub struct ProcMacroInstance {
27
37
package_id : PackageId ,
38
+ plugin : Plugin ,
39
+ }
40
+
41
+ impl Debug for ProcMacroInstance {
42
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
43
+ f. debug_struct ( "ProcMacroInstance" )
44
+ . field ( "package_id" , & self . package_id )
45
+ . finish ( )
46
+ }
28
47
}
29
48
30
49
impl ProcMacroInstance {
31
50
pub fn package_id ( & self ) -> PackageId {
32
51
self . package_id
33
52
}
34
53
35
- pub fn try_new ( package : Package ) -> Result < Self > {
36
- // Load shared library
37
- // TODO(maciektr): Implement
54
+ /// Load shared library
55
+ pub fn try_new ( package : Package , config : & Config ) -> Result < Self > {
56
+ let lib_path = package. shared_lib_path ( config) ;
57
+ let plugin = unsafe { Plugin :: try_new ( lib_path. to_path_buf ( ) ) ? } ;
38
58
Ok ( Self {
59
+ plugin,
39
60
package_id : package. id ,
40
61
} )
41
62
}
42
-
43
63
pub fn declared_attributes ( & self ) -> Vec < String > {
44
64
vec ! [ self . package_id. name. to_string( ) ]
45
65
}
46
66
47
- pub ( crate ) fn generate_code ( & self , _token_stream : TokenStream ) -> ProcMacroResult {
48
- // Apply expansion to token stream.
49
- // TODO(maciektr): Implement
50
- ProcMacroResult :: Leave
67
+ /// Apply expansion to token stream.
68
+ pub ( crate ) fn generate_code ( & self , token_stream : TokenStream ) -> ProcMacroResult {
69
+ let ffi_token_stream = unsafe { StableTokenStream :: from_token_stream ( token_stream) } ;
70
+ let result = ( self . plugin . vtable . expand ) ( ffi_token_stream) ;
71
+ unsafe { result. into_proc_macro_result ( ) }
72
+ }
73
+ }
74
+
75
+ type ExpandCode = extern "C" fn ( StableTokenStream ) -> StableProcMacroResult ;
76
+
77
+ struct VTableV0 {
78
+ expand : RawSymbol < ExpandCode > ,
79
+ }
80
+
81
+ impl VTableV0 {
82
+ unsafe fn try_new ( library : & Library ) -> Result < VTableV0 > {
83
+ let expand: Symbol < ' _ , ExpandCode > = library
84
+ . get ( b"expand\0 " )
85
+ . context ( "failed to load expand function for procedural macro" ) ?;
86
+ let expand = expand. into_raw ( ) ;
87
+ Ok ( VTableV0 { expand } )
88
+ }
89
+ }
90
+
91
+ struct Plugin {
92
+ #[ allow( dead_code) ]
93
+ library : Library ,
94
+ vtable : VTableV0 ,
95
+ }
96
+
97
+ impl Plugin {
98
+ unsafe fn try_new ( library_path : Utf8PathBuf ) -> Result < Plugin > {
99
+ let library = Library :: new ( library_path) ?;
100
+ let vtable = VTableV0 :: try_new ( & library) ?;
101
+
102
+ Ok ( Plugin { library, vtable } )
51
103
}
52
104
}
0 commit comments