diff options
author | Zac Pullar-Strecker <[email protected]> | 2020-08-24 10:19:53 +0100 |
---|---|---|
committer | Zac Pullar-Strecker <[email protected]> | 2020-08-24 10:20:13 +0100 |
commit | 7bbca7a1b3f9293d2f5cc5745199bc5f8396f2f0 (patch) | |
tree | bdb47765991cb973b2cd5481a088fac636bd326c /crates/proc_macro_api/src/lib.rs | |
parent | ca464650eeaca6195891199a93f4f76cf3e7e697 (diff) | |
parent | e65d48d1fb3d4d91d9dc1148a7a836ff5c9a3c87 (diff) |
Merge remote-tracking branch 'upstream/master' into 503-hover-doc-links
Diffstat (limited to 'crates/proc_macro_api/src/lib.rs')
-rw-r--r-- | crates/proc_macro_api/src/lib.rs | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/crates/proc_macro_api/src/lib.rs b/crates/proc_macro_api/src/lib.rs new file mode 100644 index 000000000..d5e87cf7d --- /dev/null +++ b/crates/proc_macro_api/src/lib.rs | |||
@@ -0,0 +1,111 @@ | |||
1 | //! Client-side Proc-Macro crate | ||
2 | //! | ||
3 | //! We separate proc-macro expanding logic to an extern program to allow | ||
4 | //! different implementations (e.g. wasm or dylib loading). And this crate | ||
5 | //! is used to provide basic infrastructure for communication between two | ||
6 | //! processes: Client (RA itself), Server (the external program) | ||
7 | |||
8 | mod rpc; | ||
9 | mod process; | ||
10 | pub mod msg; | ||
11 | |||
12 | use std::{ | ||
13 | ffi::OsStr, | ||
14 | io, | ||
15 | path::{Path, PathBuf}, | ||
16 | sync::Arc, | ||
17 | }; | ||
18 | |||
19 | use tt::{SmolStr, Subtree}; | ||
20 | |||
21 | use crate::process::{ProcMacroProcessSrv, ProcMacroProcessThread}; | ||
22 | |||
23 | pub use rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask, ProcMacroKind}; | ||
24 | |||
25 | #[derive(Debug, Clone)] | ||
26 | pub struct ProcMacroProcessExpander { | ||
27 | process: Arc<ProcMacroProcessSrv>, | ||
28 | dylib_path: PathBuf, | ||
29 | name: SmolStr, | ||
30 | } | ||
31 | |||
32 | impl Eq for ProcMacroProcessExpander {} | ||
33 | impl PartialEq for ProcMacroProcessExpander { | ||
34 | fn eq(&self, other: &Self) -> bool { | ||
35 | self.name == other.name | ||
36 | && self.dylib_path == other.dylib_path | ||
37 | && Arc::ptr_eq(&self.process, &other.process) | ||
38 | } | ||
39 | } | ||
40 | |||
41 | impl tt::TokenExpander for ProcMacroProcessExpander { | ||
42 | fn expand( | ||
43 | &self, | ||
44 | subtree: &Subtree, | ||
45 | _attr: Option<&Subtree>, | ||
46 | ) -> Result<Subtree, tt::ExpansionError> { | ||
47 | self.process.custom_derive(&self.dylib_path, subtree, &self.name) | ||
48 | } | ||
49 | } | ||
50 | |||
51 | #[derive(Debug)] | ||
52 | enum ProcMacroClientKind { | ||
53 | Process { process: Arc<ProcMacroProcessSrv>, thread: ProcMacroProcessThread }, | ||
54 | Dummy, | ||
55 | } | ||
56 | |||
57 | #[derive(Debug)] | ||
58 | pub struct ProcMacroClient { | ||
59 | kind: ProcMacroClientKind, | ||
60 | } | ||
61 | |||
62 | impl ProcMacroClient { | ||
63 | pub fn extern_process( | ||
64 | process_path: PathBuf, | ||
65 | args: impl IntoIterator<Item = impl AsRef<OsStr>>, | ||
66 | ) -> io::Result<ProcMacroClient> { | ||
67 | let (thread, process) = ProcMacroProcessSrv::run(process_path, args)?; | ||
68 | Ok(ProcMacroClient { | ||
69 | kind: ProcMacroClientKind::Process { process: Arc::new(process), thread }, | ||
70 | }) | ||
71 | } | ||
72 | |||
73 | pub fn dummy() -> ProcMacroClient { | ||
74 | ProcMacroClient { kind: ProcMacroClientKind::Dummy } | ||
75 | } | ||
76 | |||
77 | pub fn by_dylib_path(&self, dylib_path: &Path) -> Vec<(SmolStr, Arc<dyn tt::TokenExpander>)> { | ||
78 | match &self.kind { | ||
79 | ProcMacroClientKind::Dummy => vec![], | ||
80 | ProcMacroClientKind::Process { process, .. } => { | ||
81 | let macros = match process.find_proc_macros(dylib_path) { | ||
82 | Err(err) => { | ||
83 | eprintln!("Failed to find proc macros. Error: {:#?}", err); | ||
84 | return vec![]; | ||
85 | } | ||
86 | Ok(macros) => macros, | ||
87 | }; | ||
88 | |||
89 | macros | ||
90 | .into_iter() | ||
91 | .filter_map(|(name, kind)| { | ||
92 | match kind { | ||
93 | ProcMacroKind::CustomDerive | ProcMacroKind::FuncLike => { | ||
94 | let name = SmolStr::new(&name); | ||
95 | let expander: Arc<dyn tt::TokenExpander> = | ||
96 | Arc::new(ProcMacroProcessExpander { | ||
97 | process: process.clone(), | ||
98 | name: name.clone(), | ||
99 | dylib_path: dylib_path.into(), | ||
100 | }); | ||
101 | Some((name, expander)) | ||
102 | } | ||
103 | // FIXME: Attribute macro are currently unsupported. | ||
104 | ProcMacroKind::Attr => None, | ||
105 | } | ||
106 | }) | ||
107 | .collect() | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | } | ||