diff options
author | Edwin Cheng <[email protected]> | 2020-03-26 20:26:34 +0000 |
---|---|---|
committer | Edwin Cheng <[email protected]> | 2020-03-31 15:20:18 +0100 |
commit | 503cbd3f4b54f3be224d7a4221fa023f0e35d228 (patch) | |
tree | 101dcec6de8da790766a6e76d8f983242d8fcbfd /crates | |
parent | fa3c7742af9fbfe5146f4158a6119fa727dcc87a (diff) |
Implement ra_proc_macro client logic
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir_expand/src/proc_macro.rs | 27 | ||||
-rw-r--r-- | crates/ra_proc_macro/Cargo.toml | 5 | ||||
-rw-r--r-- | crates/ra_proc_macro/src/lib.rs | 83 | ||||
-rw-r--r-- | crates/ra_proc_macro/src/msg.rs | 218 | ||||
-rw-r--r-- | crates/ra_proc_macro/src/process.rs | 202 | ||||
-rw-r--r-- | crates/ra_proc_macro/src/rpc.rs | 260 | ||||
-rw-r--r-- | crates/ra_project_model/src/cargo_workspace.rs | 22 | ||||
-rw-r--r-- | crates/ra_tt/src/lib.rs | 7 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 1 | ||||
-rw-r--r-- | crates/rust-analyzer/src/world.rs | 20 |
10 files changed, 822 insertions, 23 deletions
diff --git a/crates/ra_hir_expand/src/proc_macro.rs b/crates/ra_hir_expand/src/proc_macro.rs index 4d270e0de..97d1208ec 100644 --- a/crates/ra_hir_expand/src/proc_macro.rs +++ b/crates/ra_hir_expand/src/proc_macro.rs | |||
@@ -9,6 +9,15 @@ pub struct ProcMacroExpander { | |||
9 | proc_macro_id: ProcMacroId, | 9 | proc_macro_id: ProcMacroId, |
10 | } | 10 | } |
11 | 11 | ||
12 | macro_rules! err { | ||
13 | ($fmt:literal, $($tt:tt),*) => { | ||
14 | mbe::ExpandError::ProcMacroError(tt::ExpansionError::Unknown(format!($fmt, $($tt),*))) | ||
15 | }; | ||
16 | ($fmt:literal) => { | ||
17 | mbe::ExpandError::ProcMacroError(tt::ExpansionError::Unknown($fmt.to_string())) | ||
18 | } | ||
19 | } | ||
20 | |||
12 | impl ProcMacroExpander { | 21 | impl ProcMacroExpander { |
13 | pub fn new(krate: CrateId, proc_macro_id: ProcMacroId) -> ProcMacroExpander { | 22 | pub fn new(krate: CrateId, proc_macro_id: ProcMacroId) -> ProcMacroExpander { |
14 | ProcMacroExpander { krate, proc_macro_id } | 23 | ProcMacroExpander { krate, proc_macro_id } |
@@ -25,8 +34,24 @@ impl ProcMacroExpander { | |||
25 | .proc_macro | 34 | .proc_macro |
26 | .get(self.proc_macro_id.0 as usize) | 35 | .get(self.proc_macro_id.0 as usize) |
27 | .clone() | 36 | .clone() |
28 | .ok_or_else(|| mbe::ExpandError::ConversionError)?; | 37 | .ok_or_else(|| err!("No derive macro found."))?; |
38 | |||
39 | let tt = remove_derive_atr(tt, &proc_macro.name) | ||
40 | .ok_or_else(|| err!("Fail to remove derive for custom derive"))?; | ||
29 | 41 | ||
30 | proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from) | 42 | proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from) |
31 | } | 43 | } |
32 | } | 44 | } |
45 | |||
46 | fn remove_derive_atr(tt: &tt::Subtree, _name: &str) -> Option<tt::Subtree> { | ||
47 | // FIXME: proper handle the remove derive | ||
48 | // We assume the first 2 tokens are #[derive(name)] | ||
49 | if tt.token_trees.len() > 2 { | ||
50 | let mut tt = tt.clone(); | ||
51 | tt.token_trees.remove(0); | ||
52 | tt.token_trees.remove(0); | ||
53 | return Some(tt); | ||
54 | } | ||
55 | |||
56 | None | ||
57 | } | ||
diff --git a/crates/ra_proc_macro/Cargo.toml b/crates/ra_proc_macro/Cargo.toml index bc2c37296..7b4ff993f 100644 --- a/crates/ra_proc_macro/Cargo.toml +++ b/crates/ra_proc_macro/Cargo.toml | |||
@@ -10,3 +10,8 @@ doctest = false | |||
10 | 10 | ||
11 | [dependencies] | 11 | [dependencies] |
12 | ra_tt = { path = "../ra_tt" } | 12 | ra_tt = { path = "../ra_tt" } |
13 | serde_derive = "1.0.104" | ||
14 | serde = "1.0.104" | ||
15 | serde_json = "1.0.48" | ||
16 | log = "0.4.8" | ||
17 | crossbeam-channel = "0.4.0" | ||
diff --git a/crates/ra_proc_macro/src/lib.rs b/crates/ra_proc_macro/src/lib.rs index 5e21dd487..a0a478dc8 100644 --- a/crates/ra_proc_macro/src/lib.rs +++ b/crates/ra_proc_macro/src/lib.rs | |||
@@ -5,55 +5,102 @@ | |||
5 | //! is used to provide basic infrastructure for communication between two | 5 | //! is used to provide basic infrastructure for communication between two |
6 | //! processes: Client (RA itself), Server (the external program) | 6 | //! processes: Client (RA itself), Server (the external program) |
7 | 7 | ||
8 | mod rpc; | ||
9 | mod process; | ||
10 | pub mod msg; | ||
11 | |||
12 | use process::ProcMacroProcessSrv; | ||
8 | use ra_tt::{SmolStr, Subtree}; | 13 | use ra_tt::{SmolStr, Subtree}; |
14 | use rpc::ProcMacroKind; | ||
9 | use std::{ | 15 | use std::{ |
10 | path::{Path, PathBuf}, | 16 | path::{Path, PathBuf}, |
11 | sync::Arc, | 17 | sync::Arc, |
12 | }; | 18 | }; |
13 | 19 | ||
14 | #[derive(Debug, Clone, PartialEq, Eq)] | 20 | pub use rpc::{ExpansionResult, ExpansionTask}; |
21 | |||
22 | #[derive(Debug, Clone)] | ||
15 | pub struct ProcMacroProcessExpander { | 23 | pub struct ProcMacroProcessExpander { |
16 | process: Arc<ProcMacroProcessSrv>, | 24 | process: Arc<ProcMacroProcessSrv>, |
25 | dylib_path: PathBuf, | ||
17 | name: SmolStr, | 26 | name: SmolStr, |
18 | } | 27 | } |
19 | 28 | ||
29 | impl Eq for ProcMacroProcessExpander {} | ||
30 | impl PartialEq for ProcMacroProcessExpander { | ||
31 | fn eq(&self, other: &Self) -> bool { | ||
32 | self.name == other.name | ||
33 | && self.dylib_path == other.dylib_path | ||
34 | && Arc::ptr_eq(&self.process, &other.process) | ||
35 | } | ||
36 | } | ||
37 | |||
20 | impl ra_tt::TokenExpander for ProcMacroProcessExpander { | 38 | impl ra_tt::TokenExpander for ProcMacroProcessExpander { |
21 | fn expand( | 39 | fn expand( |
22 | &self, | 40 | &self, |
23 | _subtree: &Subtree, | 41 | subtree: &Subtree, |
24 | _attr: Option<&Subtree>, | 42 | _attr: Option<&Subtree>, |
25 | ) -> Result<Subtree, ra_tt::ExpansionError> { | 43 | ) -> Result<Subtree, ra_tt::ExpansionError> { |
26 | // FIXME: do nothing for now | 44 | self.process.custom_derive(&self.dylib_path, subtree, &self.name) |
27 | Ok(Subtree::default()) | ||
28 | } | 45 | } |
29 | } | 46 | } |
30 | 47 | ||
31 | #[derive(Debug, Clone, PartialEq, Eq)] | 48 | #[derive(Debug, Clone)] |
32 | pub struct ProcMacroProcessSrv { | 49 | enum ProcMacroClientKind { |
33 | path: PathBuf, | ||
34 | } | ||
35 | |||
36 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
37 | pub enum ProcMacroClient { | ||
38 | Process { process: Arc<ProcMacroProcessSrv> }, | 50 | Process { process: Arc<ProcMacroProcessSrv> }, |
39 | Dummy, | 51 | Dummy, |
40 | } | 52 | } |
41 | 53 | ||
54 | #[derive(Debug, Clone)] | ||
55 | pub struct ProcMacroClient { | ||
56 | kind: ProcMacroClientKind, | ||
57 | } | ||
58 | |||
42 | impl ProcMacroClient { | 59 | impl ProcMacroClient { |
43 | pub fn extern_process(process_path: &Path) -> ProcMacroClient { | 60 | pub fn extern_process(process_path: &Path) -> Result<ProcMacroClient, std::io::Error> { |
44 | let process = ProcMacroProcessSrv { path: process_path.into() }; | 61 | let process = ProcMacroProcessSrv::run(process_path)?; |
45 | ProcMacroClient::Process { process: Arc::new(process) } | 62 | Ok(ProcMacroClient { kind: ProcMacroClientKind::Process { process: Arc::new(process) } }) |
46 | } | 63 | } |
47 | 64 | ||
48 | pub fn dummy() -> ProcMacroClient { | 65 | pub fn dummy() -> ProcMacroClient { |
49 | ProcMacroClient::Dummy | 66 | ProcMacroClient { kind: ProcMacroClientKind::Dummy } |
50 | } | 67 | } |
51 | 68 | ||
52 | pub fn by_dylib_path( | 69 | pub fn by_dylib_path( |
53 | &self, | 70 | &self, |
54 | _dylib_path: &Path, | 71 | dylib_path: &Path, |
55 | ) -> Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)> { | 72 | ) -> Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)> { |
56 | // FIXME: return empty for now | 73 | match &self.kind { |
57 | vec![] | 74 | ProcMacroClientKind::Dummy => vec![], |
75 | ProcMacroClientKind::Process { process } => { | ||
76 | let macros = match process.find_proc_macros(dylib_path) { | ||
77 | Err(err) => { | ||
78 | eprintln!("Fail to find proc macro. Error: {:#?}", err); | ||
79 | return vec![]; | ||
80 | } | ||
81 | Ok(macros) => macros, | ||
82 | }; | ||
83 | |||
84 | macros | ||
85 | .into_iter() | ||
86 | .filter_map(|(name, kind)| { | ||
87 | // FIXME: Support custom derive only for now. | ||
88 | match kind { | ||
89 | ProcMacroKind::CustomDerive => { | ||
90 | let name = SmolStr::new(&name); | ||
91 | let expander: Arc<dyn ra_tt::TokenExpander> = | ||
92 | Arc::new(ProcMacroProcessExpander { | ||
93 | process: process.clone(), | ||
94 | name: name.clone(), | ||
95 | dylib_path: dylib_path.into(), | ||
96 | }); | ||
97 | Some((name, expander)) | ||
98 | } | ||
99 | _ => None, | ||
100 | } | ||
101 | }) | ||
102 | .collect() | ||
103 | } | ||
104 | } | ||
58 | } | 105 | } |
59 | } | 106 | } |
diff --git a/crates/ra_proc_macro/src/msg.rs b/crates/ra_proc_macro/src/msg.rs new file mode 100644 index 000000000..2fb065d32 --- /dev/null +++ b/crates/ra_proc_macro/src/msg.rs | |||
@@ -0,0 +1,218 @@ | |||
1 | //! A simplified version of lsp base protocol for rpc | ||
2 | |||
3 | use std::{ | ||
4 | fmt, | ||
5 | io::{self, BufRead, Write}, | ||
6 | }; | ||
7 | |||
8 | use serde::{de::DeserializeOwned, Deserialize, Serialize}; | ||
9 | |||
10 | #[derive(Serialize, Deserialize, Debug, Clone)] | ||
11 | #[serde(untagged)] | ||
12 | pub enum Message { | ||
13 | Request(Request), | ||
14 | Response(Response), | ||
15 | } | ||
16 | |||
17 | impl From<Request> for Message { | ||
18 | fn from(request: Request) -> Message { | ||
19 | Message::Request(request) | ||
20 | } | ||
21 | } | ||
22 | |||
23 | impl From<Response> for Message { | ||
24 | fn from(response: Response) -> Message { | ||
25 | Message::Response(response) | ||
26 | } | ||
27 | } | ||
28 | |||
29 | #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
30 | #[serde(transparent)] | ||
31 | pub struct RequestId(IdRepr); | ||
32 | |||
33 | #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
34 | #[serde(untagged)] | ||
35 | enum IdRepr { | ||
36 | U64(u64), | ||
37 | String(String), | ||
38 | } | ||
39 | |||
40 | impl From<u64> for RequestId { | ||
41 | fn from(id: u64) -> RequestId { | ||
42 | RequestId(IdRepr::U64(id)) | ||
43 | } | ||
44 | } | ||
45 | |||
46 | impl From<String> for RequestId { | ||
47 | fn from(id: String) -> RequestId { | ||
48 | RequestId(IdRepr::String(id)) | ||
49 | } | ||
50 | } | ||
51 | |||
52 | impl fmt::Display for RequestId { | ||
53 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
54 | match &self.0 { | ||
55 | IdRepr::U64(it) => fmt::Display::fmt(it, f), | ||
56 | IdRepr::String(it) => fmt::Display::fmt(it, f), | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
61 | #[derive(Debug, Serialize, Deserialize, Clone)] | ||
62 | pub struct Request { | ||
63 | pub id: RequestId, | ||
64 | pub method: String, | ||
65 | pub params: serde_json::Value, | ||
66 | } | ||
67 | |||
68 | #[derive(Debug, Serialize, Deserialize, Clone)] | ||
69 | pub struct Response { | ||
70 | // JSON RPC allows this to be null if it was impossible | ||
71 | // to decode the request's id. Ignore this special case | ||
72 | // and just die horribly. | ||
73 | pub id: RequestId, | ||
74 | #[serde(skip_serializing_if = "Option::is_none")] | ||
75 | pub result: Option<serde_json::Value>, | ||
76 | #[serde(skip_serializing_if = "Option::is_none")] | ||
77 | pub error: Option<ResponseError>, | ||
78 | } | ||
79 | |||
80 | #[derive(Debug, Serialize, Deserialize, Clone)] | ||
81 | pub struct ResponseError { | ||
82 | pub code: i32, | ||
83 | pub message: String, | ||
84 | #[serde(skip_serializing_if = "Option::is_none")] | ||
85 | pub data: Option<serde_json::Value>, | ||
86 | } | ||
87 | |||
88 | #[derive(Clone, Copy, Debug)] | ||
89 | #[allow(unused)] | ||
90 | pub enum ErrorCode { | ||
91 | // Defined by JSON RPC | ||
92 | ParseError = -32700, | ||
93 | InvalidRequest = -32600, | ||
94 | MethodNotFound = -32601, | ||
95 | InvalidParams = -32602, | ||
96 | InternalError = -32603, | ||
97 | ServerErrorStart = -32099, | ||
98 | ServerErrorEnd = -32000, | ||
99 | ServerNotInitialized = -32002, | ||
100 | UnknownErrorCode = -32001, | ||
101 | |||
102 | // Defined by protocol | ||
103 | ExpansionError = -32900, | ||
104 | } | ||
105 | |||
106 | #[derive(Debug, Serialize, Deserialize, Clone)] | ||
107 | pub struct Notification { | ||
108 | pub method: String, | ||
109 | pub params: serde_json::Value, | ||
110 | } | ||
111 | |||
112 | impl Message { | ||
113 | pub fn read(r: &mut impl BufRead) -> io::Result<Option<Message>> { | ||
114 | let text = match read_msg_text(r)? { | ||
115 | None => return Ok(None), | ||
116 | Some(text) => text, | ||
117 | }; | ||
118 | let msg = serde_json::from_str(&text)?; | ||
119 | Ok(Some(msg)) | ||
120 | } | ||
121 | pub fn write(self, w: &mut impl Write) -> io::Result<()> { | ||
122 | #[derive(Serialize)] | ||
123 | struct JsonRpc { | ||
124 | jsonrpc: &'static str, | ||
125 | #[serde(flatten)] | ||
126 | msg: Message, | ||
127 | } | ||
128 | let text = serde_json::to_string(&JsonRpc { jsonrpc: "2.0", msg: self })?; | ||
129 | write_msg_text(w, &text) | ||
130 | } | ||
131 | } | ||
132 | |||
133 | impl Response { | ||
134 | pub fn new_ok<R: Serialize>(id: RequestId, result: R) -> Response { | ||
135 | Response { id, result: Some(serde_json::to_value(result).unwrap()), error: None } | ||
136 | } | ||
137 | pub fn new_err(id: RequestId, code: i32, message: String) -> Response { | ||
138 | let error = ResponseError { code, message, data: None }; | ||
139 | Response { id, result: None, error: Some(error) } | ||
140 | } | ||
141 | } | ||
142 | |||
143 | impl Request { | ||
144 | pub fn new<P: Serialize>(id: RequestId, method: String, params: P) -> Request { | ||
145 | Request { id, method, params: serde_json::to_value(params).unwrap() } | ||
146 | } | ||
147 | pub fn extract<P: DeserializeOwned>(self, method: &str) -> Result<(RequestId, P), Request> { | ||
148 | if self.method == method { | ||
149 | let params = serde_json::from_value(self.params).unwrap_or_else(|err| { | ||
150 | panic!("Invalid request\nMethod: {}\n error: {}", method, err) | ||
151 | }); | ||
152 | Ok((self.id, params)) | ||
153 | } else { | ||
154 | Err(self) | ||
155 | } | ||
156 | } | ||
157 | } | ||
158 | |||
159 | impl Notification { | ||
160 | pub fn new(method: String, params: impl Serialize) -> Notification { | ||
161 | Notification { method, params: serde_json::to_value(params).unwrap() } | ||
162 | } | ||
163 | pub fn extract<P: DeserializeOwned>(self, method: &str) -> Result<P, Notification> { | ||
164 | if self.method == method { | ||
165 | let params = serde_json::from_value(self.params).unwrap(); | ||
166 | Ok(params) | ||
167 | } else { | ||
168 | Err(self) | ||
169 | } | ||
170 | } | ||
171 | } | ||
172 | |||
173 | fn read_msg_text(inp: &mut impl BufRead) -> io::Result<Option<String>> { | ||
174 | fn invalid_data(error: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> io::Error { | ||
175 | io::Error::new(io::ErrorKind::InvalidData, error) | ||
176 | } | ||
177 | macro_rules! invalid_data { | ||
178 | ($($tt:tt)*) => (invalid_data(format!($($tt)*))) | ||
179 | } | ||
180 | |||
181 | let mut size = None; | ||
182 | let mut buf = String::new(); | ||
183 | loop { | ||
184 | buf.clear(); | ||
185 | if inp.read_line(&mut buf)? == 0 { | ||
186 | return Ok(None); | ||
187 | } | ||
188 | if !buf.ends_with("\r\n") { | ||
189 | return Err(invalid_data!("malformed header: {:?}", buf)); | ||
190 | } | ||
191 | let buf = &buf[..buf.len() - 2]; | ||
192 | if buf.is_empty() { | ||
193 | break; | ||
194 | } | ||
195 | let mut parts = buf.splitn(2, ": "); | ||
196 | let header_name = parts.next().unwrap(); | ||
197 | let header_value = | ||
198 | parts.next().ok_or_else(|| invalid_data!("malformed header: {:?}", buf))?; | ||
199 | if header_name == "Content-Length" { | ||
200 | size = Some(header_value.parse::<usize>().map_err(invalid_data)?); | ||
201 | } | ||
202 | } | ||
203 | let size: usize = size.ok_or_else(|| invalid_data!("no Content-Length"))?; | ||
204 | let mut buf = buf.into_bytes(); | ||
205 | buf.resize(size, 0); | ||
206 | inp.read_exact(&mut buf)?; | ||
207 | let buf = String::from_utf8(buf).map_err(invalid_data)?; | ||
208 | log::debug!("< {}", buf); | ||
209 | Ok(Some(buf)) | ||
210 | } | ||
211 | |||
212 | fn write_msg_text(out: &mut impl Write, msg: &str) -> io::Result<()> { | ||
213 | log::debug!("> {}", msg); | ||
214 | write!(out, "Content-Length: {}\r\n\r\n", msg.len())?; | ||
215 | out.write_all(msg.as_bytes())?; | ||
216 | out.flush()?; | ||
217 | Ok(()) | ||
218 | } | ||
diff --git a/crates/ra_proc_macro/src/process.rs b/crates/ra_proc_macro/src/process.rs new file mode 100644 index 000000000..a9095af11 --- /dev/null +++ b/crates/ra_proc_macro/src/process.rs | |||
@@ -0,0 +1,202 @@ | |||
1 | use crossbeam_channel::{bounded, Receiver, Sender}; | ||
2 | use ra_tt::Subtree; | ||
3 | |||
4 | use crate::msg::{ErrorCode, Message, Request, Response, ResponseError}; | ||
5 | use crate::rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask, ProcMacroKind}; | ||
6 | |||
7 | use io::{BufRead, BufReader}; | ||
8 | use std::{ | ||
9 | io::{self, Write}, | ||
10 | path::{Path, PathBuf}, | ||
11 | process::{Child, Command, Stdio}, | ||
12 | thread::spawn, | ||
13 | }; | ||
14 | |||
15 | #[derive(Debug, Default)] | ||
16 | pub(crate) struct ProcMacroProcessSrv { | ||
17 | inner: Option<Handle>, | ||
18 | } | ||
19 | |||
20 | struct Task { | ||
21 | req: Message, | ||
22 | result_tx: Sender<Message>, | ||
23 | } | ||
24 | |||
25 | #[derive(Debug)] | ||
26 | struct Handle { | ||
27 | sender: Sender<Task>, | ||
28 | } | ||
29 | |||
30 | struct Process { | ||
31 | path: PathBuf, | ||
32 | child: Child, | ||
33 | } | ||
34 | |||
35 | impl Process { | ||
36 | fn run(process_path: &Path) -> Result<Process, io::Error> { | ||
37 | let child = Command::new(process_path.clone()) | ||
38 | .stdin(Stdio::piped()) | ||
39 | .stdout(Stdio::piped()) | ||
40 | .spawn()?; | ||
41 | |||
42 | Ok(Process { path: process_path.into(), child }) | ||
43 | } | ||
44 | |||
45 | fn restart(&mut self) -> Result<(), io::Error> { | ||
46 | let _ = self.child.kill(); | ||
47 | self.child = | ||
48 | Command::new(self.path.clone()).stdin(Stdio::piped()).stdout(Stdio::piped()).spawn()?; | ||
49 | Ok(()) | ||
50 | } | ||
51 | |||
52 | fn stdio(&mut self) -> Option<(impl Write, impl BufRead)> { | ||
53 | let stdin = self.child.stdin.take()?; | ||
54 | let stdout = self.child.stdout.take()?; | ||
55 | let read = BufReader::new(stdout); | ||
56 | |||
57 | Some((stdin, read)) | ||
58 | } | ||
59 | } | ||
60 | |||
61 | impl ProcMacroProcessSrv { | ||
62 | pub fn run(process_path: &Path) -> Result<ProcMacroProcessSrv, io::Error> { | ||
63 | let process = Process::run(process_path)?; | ||
64 | |||
65 | let (task_tx, task_rx) = bounded(0); | ||
66 | |||
67 | let _ = spawn(move || { | ||
68 | client_loop(task_rx, process); | ||
69 | }); | ||
70 | Ok(ProcMacroProcessSrv { inner: Some(Handle { sender: task_tx }) }) | ||
71 | } | ||
72 | |||
73 | pub fn find_proc_macros( | ||
74 | &self, | ||
75 | dylib_path: &Path, | ||
76 | ) -> Result<Vec<(String, ProcMacroKind)>, ra_tt::ExpansionError> { | ||
77 | let task = ListMacrosTask { lib: dylib_path.to_path_buf() }; | ||
78 | |||
79 | let result: ListMacrosResult = self.send_task("list_macros", task)?; | ||
80 | Ok(result.macros) | ||
81 | } | ||
82 | |||
83 | pub fn custom_derive( | ||
84 | &self, | ||
85 | dylib_path: &Path, | ||
86 | subtree: &Subtree, | ||
87 | derive_name: &str, | ||
88 | ) -> Result<Subtree, ra_tt::ExpansionError> { | ||
89 | let task = ExpansionTask { | ||
90 | macro_body: subtree.clone(), | ||
91 | macro_name: derive_name.to_string(), | ||
92 | attributes: None, | ||
93 | lib: dylib_path.to_path_buf(), | ||
94 | }; | ||
95 | |||
96 | let result: ExpansionResult = self.send_task("custom_derive", task)?; | ||
97 | Ok(result.expansion) | ||
98 | } | ||
99 | |||
100 | pub fn send_task<'a, T, R>(&self, method: &str, task: T) -> Result<R, ra_tt::ExpansionError> | ||
101 | where | ||
102 | T: serde::Serialize, | ||
103 | R: serde::de::DeserializeOwned + Default, | ||
104 | { | ||
105 | let handle = match &self.inner { | ||
106 | None => return Err(ra_tt::ExpansionError::Unknown("No handle is found.".to_string())), | ||
107 | Some(it) => it, | ||
108 | }; | ||
109 | |||
110 | let msg = serde_json::to_value(task).unwrap(); | ||
111 | |||
112 | // FIXME: use a proper request id | ||
113 | let id = 0; | ||
114 | let req = Request { id: id.into(), method: method.into(), params: msg }; | ||
115 | |||
116 | let (result_tx, result_rx) = bounded(0); | ||
117 | |||
118 | handle.sender.send(Task { req: req.into(), result_tx }).unwrap(); | ||
119 | let response = result_rx.recv().unwrap(); | ||
120 | |||
121 | match response { | ||
122 | Message::Request(_) => { | ||
123 | return Err(ra_tt::ExpansionError::Unknown( | ||
124 | "Return request from ra_proc_srv".into(), | ||
125 | )) | ||
126 | } | ||
127 | Message::Response(res) => { | ||
128 | if let Some(err) = res.error { | ||
129 | return Err(ra_tt::ExpansionError::ExpansionError(err.message)); | ||
130 | } | ||
131 | match res.result { | ||
132 | None => Ok(R::default()), | ||
133 | Some(res) => { | ||
134 | let result: R = serde_json::from_value(res) | ||
135 | .map_err(|err| ra_tt::ExpansionError::JsonError(err.to_string()))?; | ||
136 | Ok(result) | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | |||
144 | fn client_loop(task_rx: Receiver<Task>, mut process: Process) { | ||
145 | let (mut stdin, mut stdout) = match process.stdio() { | ||
146 | None => return, | ||
147 | Some(it) => it, | ||
148 | }; | ||
149 | |||
150 | loop { | ||
151 | let task = match task_rx.recv() { | ||
152 | Ok(task) => task, | ||
153 | Err(_) => break, | ||
154 | }; | ||
155 | |||
156 | let res = match send_message(&mut stdin, &mut stdout, task.req) { | ||
157 | Ok(res) => res, | ||
158 | Err(_err) => { | ||
159 | let res = Response { | ||
160 | id: 0.into(), | ||
161 | result: None, | ||
162 | error: Some(ResponseError { | ||
163 | code: ErrorCode::ServerErrorEnd as i32, | ||
164 | message: "Server closed".into(), | ||
165 | data: None, | ||
166 | }), | ||
167 | }; | ||
168 | if task.result_tx.send(res.into()).is_err() { | ||
169 | break; | ||
170 | } | ||
171 | // Restart the process | ||
172 | if process.restart().is_err() { | ||
173 | break; | ||
174 | } | ||
175 | let stdio = match process.stdio() { | ||
176 | None => break, | ||
177 | Some(it) => it, | ||
178 | }; | ||
179 | stdin = stdio.0; | ||
180 | stdout = stdio.1; | ||
181 | continue; | ||
182 | } | ||
183 | }; | ||
184 | |||
185 | if let Some(res) = res { | ||
186 | if task.result_tx.send(res).is_err() { | ||
187 | break; | ||
188 | } | ||
189 | } | ||
190 | } | ||
191 | |||
192 | let _ = process.child.kill(); | ||
193 | } | ||
194 | |||
195 | fn send_message( | ||
196 | mut writer: &mut impl Write, | ||
197 | mut reader: &mut impl BufRead, | ||
198 | msg: Message, | ||
199 | ) -> Result<Option<Message>, io::Error> { | ||
200 | msg.write(&mut writer)?; | ||
201 | Ok(Message::read(&mut reader)?) | ||
202 | } | ||
diff --git a/crates/ra_proc_macro/src/rpc.rs b/crates/ra_proc_macro/src/rpc.rs new file mode 100644 index 000000000..e7eaf7c15 --- /dev/null +++ b/crates/ra_proc_macro/src/rpc.rs | |||
@@ -0,0 +1,260 @@ | |||
1 | //! Data struture serialization related stuffs for RPC | ||
2 | |||
3 | use ra_tt::{ | ||
4 | Delimiter, DelimiterKind, Ident, Leaf, Literal, Punct, SmolStr, Spacing, Subtree, TokenId, | ||
5 | TokenTree, | ||
6 | }; | ||
7 | use serde::{Deserialize, Serialize}; | ||
8 | use std::path::PathBuf; | ||
9 | |||
10 | #[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] | ||
11 | pub struct ListMacrosTask { | ||
12 | pub lib: PathBuf, | ||
13 | } | ||
14 | |||
15 | #[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] | ||
16 | pub enum ProcMacroKind { | ||
17 | CustomDerive, | ||
18 | FuncLike, | ||
19 | Attr, | ||
20 | } | ||
21 | |||
22 | #[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)] | ||
23 | pub struct ListMacrosResult { | ||
24 | pub macros: Vec<(String, ProcMacroKind)>, | ||
25 | } | ||
26 | |||
27 | #[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] | ||
28 | pub struct ExpansionTask { | ||
29 | /// Argument of macro call. | ||
30 | /// | ||
31 | /// In custom derive that would be a struct or enum; in attribute-like macro - underlying | ||
32 | /// item; in function-like macro - the macro body. | ||
33 | #[serde(with = "SubtreeDef")] | ||
34 | pub macro_body: Subtree, | ||
35 | |||
36 | /// Names of macros to expand. | ||
37 | /// | ||
38 | /// In custom derive those are names of derived traits (`Serialize`, `Getters`, etc.). In | ||
39 | /// attribute-like and functiona-like macros - single name of macro itself (`show_streams`). | ||
40 | pub macro_name: String, | ||
41 | |||
42 | /// Possible attributes for the attribute-like macros. | ||
43 | #[serde(with = "opt_subtree_def")] | ||
44 | pub attributes: Option<Subtree>, | ||
45 | |||
46 | pub lib: PathBuf, | ||
47 | } | ||
48 | |||
49 | #[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)] | ||
50 | pub struct ExpansionResult { | ||
51 | #[serde(with = "SubtreeDef")] | ||
52 | pub expansion: Subtree, | ||
53 | } | ||
54 | |||
55 | #[derive(Serialize, Deserialize)] | ||
56 | #[serde(remote = "DelimiterKind")] | ||
57 | enum DelimiterKindDef { | ||
58 | Parenthesis, | ||
59 | Brace, | ||
60 | Bracket, | ||
61 | } | ||
62 | |||
63 | #[derive(Serialize, Deserialize)] | ||
64 | #[serde(remote = "TokenId")] | ||
65 | struct TokenIdDef(u32); | ||
66 | |||
67 | #[derive(Serialize, Deserialize)] | ||
68 | #[serde(remote = "Delimiter")] | ||
69 | struct DelimiterDef { | ||
70 | #[serde(with = "TokenIdDef")] | ||
71 | pub id: TokenId, | ||
72 | #[serde(with = "DelimiterKindDef")] | ||
73 | pub kind: DelimiterKind, | ||
74 | } | ||
75 | |||
76 | #[derive(Serialize, Deserialize)] | ||
77 | #[serde(remote = "Subtree")] | ||
78 | struct SubtreeDef { | ||
79 | #[serde(default, with = "opt_delimiter_def")] | ||
80 | pub delimiter: Option<Delimiter>, | ||
81 | #[serde(with = "vec_token_tree")] | ||
82 | pub token_trees: Vec<TokenTree>, | ||
83 | } | ||
84 | |||
85 | #[derive(Serialize, Deserialize)] | ||
86 | #[serde(remote = "TokenTree")] | ||
87 | enum TokenTreeDef { | ||
88 | #[serde(with = "LeafDef")] | ||
89 | Leaf(Leaf), | ||
90 | #[serde(with = "SubtreeDef")] | ||
91 | Subtree(Subtree), | ||
92 | } | ||
93 | |||
94 | #[derive(Serialize, Deserialize)] | ||
95 | #[serde(remote = "Leaf")] | ||
96 | enum LeafDef { | ||
97 | #[serde(with = "LiteralDef")] | ||
98 | Literal(Literal), | ||
99 | #[serde(with = "PunctDef")] | ||
100 | Punct(Punct), | ||
101 | #[serde(with = "IdentDef")] | ||
102 | Ident(Ident), | ||
103 | } | ||
104 | |||
105 | #[derive(Serialize, Deserialize)] | ||
106 | #[serde(remote = "Literal")] | ||
107 | struct LiteralDef { | ||
108 | pub text: SmolStr, | ||
109 | #[serde(with = "TokenIdDef")] | ||
110 | pub id: TokenId, | ||
111 | } | ||
112 | |||
113 | #[derive(Serialize, Deserialize)] | ||
114 | #[serde(remote = "Punct")] | ||
115 | struct PunctDef { | ||
116 | pub char: char, | ||
117 | #[serde(with = "SpacingDef")] | ||
118 | pub spacing: Spacing, | ||
119 | #[serde(with = "TokenIdDef")] | ||
120 | pub id: TokenId, | ||
121 | } | ||
122 | |||
123 | #[derive(Serialize, Deserialize)] | ||
124 | #[serde(remote = "Spacing")] | ||
125 | enum SpacingDef { | ||
126 | Alone, | ||
127 | Joint, | ||
128 | } | ||
129 | |||
130 | #[derive(Serialize, Deserialize)] | ||
131 | #[serde(remote = "Ident")] | ||
132 | struct IdentDef { | ||
133 | pub text: SmolStr, | ||
134 | #[serde(with = "TokenIdDef")] | ||
135 | pub id: TokenId, | ||
136 | } | ||
137 | |||
138 | mod opt_delimiter_def { | ||
139 | use super::{Delimiter, DelimiterDef}; | ||
140 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; | ||
141 | |||
142 | pub fn serialize<S>(value: &Option<Delimiter>, serializer: S) -> Result<S::Ok, S::Error> | ||
143 | where | ||
144 | S: Serializer, | ||
145 | { | ||
146 | #[derive(Serialize)] | ||
147 | struct Helper<'a>(#[serde(with = "DelimiterDef")] &'a Delimiter); | ||
148 | value.as_ref().map(Helper).serialize(serializer) | ||
149 | } | ||
150 | |||
151 | pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Delimiter>, D::Error> | ||
152 | where | ||
153 | D: Deserializer<'de>, | ||
154 | { | ||
155 | #[derive(Deserialize)] | ||
156 | struct Helper(#[serde(with = "DelimiterDef")] Delimiter); | ||
157 | let helper = Option::deserialize(deserializer)?; | ||
158 | Ok(helper.map(|Helper(external)| external)) | ||
159 | } | ||
160 | } | ||
161 | |||
162 | mod opt_subtree_def { | ||
163 | use super::{Subtree, SubtreeDef}; | ||
164 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; | ||
165 | |||
166 | pub fn serialize<S>(value: &Option<Subtree>, serializer: S) -> Result<S::Ok, S::Error> | ||
167 | where | ||
168 | S: Serializer, | ||
169 | { | ||
170 | #[derive(Serialize)] | ||
171 | struct Helper<'a>(#[serde(with = "SubtreeDef")] &'a Subtree); | ||
172 | value.as_ref().map(Helper).serialize(serializer) | ||
173 | } | ||
174 | |||
175 | pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Subtree>, D::Error> | ||
176 | where | ||
177 | D: Deserializer<'de>, | ||
178 | { | ||
179 | #[derive(Deserialize)] | ||
180 | struct Helper(#[serde(with = "SubtreeDef")] Subtree); | ||
181 | let helper = Option::deserialize(deserializer)?; | ||
182 | Ok(helper.map(|Helper(external)| external)) | ||
183 | } | ||
184 | } | ||
185 | |||
186 | mod vec_token_tree { | ||
187 | use super::{TokenTree, TokenTreeDef}; | ||
188 | use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer}; | ||
189 | |||
190 | pub fn serialize<S>(value: &Vec<TokenTree>, serializer: S) -> Result<S::Ok, S::Error> | ||
191 | where | ||
192 | S: Serializer, | ||
193 | { | ||
194 | #[derive(Serialize)] | ||
195 | struct Helper<'a>(#[serde(with = "TokenTreeDef")] &'a TokenTree); | ||
196 | |||
197 | let items: Vec<_> = value.iter().map(Helper).collect(); | ||
198 | let mut seq = serializer.serialize_seq(Some(items.len()))?; | ||
199 | for element in items { | ||
200 | seq.serialize_element(&element)?; | ||
201 | } | ||
202 | seq.end() | ||
203 | } | ||
204 | |||
205 | pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<TokenTree>, D::Error> | ||
206 | where | ||
207 | D: Deserializer<'de>, | ||
208 | { | ||
209 | #[derive(Deserialize)] | ||
210 | struct Helper(#[serde(with = "TokenTreeDef")] TokenTree); | ||
211 | |||
212 | let helper = Vec::deserialize(deserializer)?; | ||
213 | Ok(helper.into_iter().map(|Helper(external)| external).collect()) | ||
214 | } | ||
215 | } | ||
216 | |||
217 | #[cfg(test)] | ||
218 | mod tests { | ||
219 | use super::*; | ||
220 | |||
221 | fn fixture_token_tree() -> Subtree { | ||
222 | let mut subtree = Subtree::default(); | ||
223 | subtree | ||
224 | .token_trees | ||
225 | .push(TokenTree::Leaf(Ident { text: "struct".into(), id: TokenId(0) }.into())); | ||
226 | subtree | ||
227 | .token_trees | ||
228 | .push(TokenTree::Leaf(Ident { text: "Foo".into(), id: TokenId(1) }.into())); | ||
229 | subtree.token_trees.push(TokenTree::Subtree( | ||
230 | Subtree { | ||
231 | delimiter: Some(Delimiter { id: TokenId(2), kind: DelimiterKind::Brace }), | ||
232 | token_trees: vec![], | ||
233 | } | ||
234 | .into(), | ||
235 | )); | ||
236 | subtree | ||
237 | } | ||
238 | |||
239 | #[test] | ||
240 | fn test_proc_macro_rpc_works() { | ||
241 | let tt = fixture_token_tree(); | ||
242 | let task = ExpansionTask { | ||
243 | macro_body: tt.clone(), | ||
244 | macro_name: Default::default(), | ||
245 | attributes: None, | ||
246 | lib: Default::default(), | ||
247 | }; | ||
248 | |||
249 | let json = serde_json::to_string(&task).unwrap(); | ||
250 | let back: ExpansionTask = serde_json::from_str(&json).unwrap(); | ||
251 | |||
252 | assert_eq!(task.macro_body, back.macro_body); | ||
253 | |||
254 | let result = ExpansionResult { expansion: tt.clone() }; | ||
255 | let json = serde_json::to_string(&task).unwrap(); | ||
256 | let back: ExpansionResult = serde_json::from_str(&json).unwrap(); | ||
257 | |||
258 | assert_eq!(result, back); | ||
259 | } | ||
260 | } | ||
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 738fd6f61..32592e660 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::{ | 3 | use std::{ |
4 | ffi::OsStr, | ||
4 | ops, | 5 | ops, |
5 | path::{Path, PathBuf}, | 6 | path::{Path, PathBuf}, |
6 | }; | 7 | }; |
@@ -299,7 +300,10 @@ pub fn load_extern_resources(cargo_toml: &Path, cargo_features: &CargoFeatures) | |||
299 | Message::CompilerArtifact(message) => { | 300 | Message::CompilerArtifact(message) => { |
300 | if message.target.kind.contains(&"proc-macro".to_string()) { | 301 | if message.target.kind.contains(&"proc-macro".to_string()) { |
301 | let package_id = message.package_id; | 302 | let package_id = message.package_id; |
302 | if let Some(filename) = message.filenames.get(0) { | 303 | // Skip rmeta file |
304 | if let Some(filename) = | ||
305 | message.filenames.iter().filter(|name| is_dylib(name)).next() | ||
306 | { | ||
303 | acc.proc_dylib_paths.insert(package_id, filename.clone()); | 307 | acc.proc_dylib_paths.insert(package_id, filename.clone()); |
304 | } | 308 | } |
305 | } | 309 | } |
@@ -316,3 +320,19 @@ pub fn load_extern_resources(cargo_toml: &Path, cargo_features: &CargoFeatures) | |||
316 | 320 | ||
317 | acc | 321 | acc |
318 | } | 322 | } |
323 | |||
324 | // FIXME: File a better way to know if it is a dylib | ||
325 | fn is_dylib(path: &Path) -> bool { | ||
326 | let ext = match path.extension().and_then(OsStr::to_str).map(|it| it.to_string().to_lowercase()) | ||
327 | { | ||
328 | None => return false, | ||
329 | Some(ext) => ext, | ||
330 | }; | ||
331 | |||
332 | match ext.as_str() { | ||
333 | "dll" => true, | ||
334 | "dylib" => true, | ||
335 | "so" => true, | ||
336 | _ => false, | ||
337 | } | ||
338 | } | ||
diff --git a/crates/ra_tt/src/lib.rs b/crates/ra_tt/src/lib.rs index 1015ce0a6..bd484aa30 100644 --- a/crates/ra_tt/src/lib.rs +++ b/crates/ra_tt/src/lib.rs | |||
@@ -189,7 +189,12 @@ impl Subtree { | |||
189 | pub mod buffer; | 189 | pub mod buffer; |
190 | 190 | ||
191 | #[derive(Debug, PartialEq, Eq)] | 191 | #[derive(Debug, PartialEq, Eq)] |
192 | pub enum ExpansionError {} | 192 | pub enum ExpansionError { |
193 | IOError(String), | ||
194 | JsonError(String), | ||
195 | Unknown(String), | ||
196 | ExpansionError(String), | ||
197 | } | ||
193 | 198 | ||
194 | pub trait TokenExpander: Debug + Send + Sync + RefUnwindSafe { | 199 | pub trait TokenExpander: Debug + Send + Sync + RefUnwindSafe { |
195 | fn expand(&self, subtree: &Subtree, attrs: Option<&Subtree>) | 200 | fn expand(&self, subtree: &Subtree, attrs: Option<&Subtree>) |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index c233f72ff..9fd568601 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -109,6 +109,7 @@ fn get_config( | |||
109 | }, | 109 | }, |
110 | rustfmt_args: config.rustfmt_args.clone(), | 110 | rustfmt_args: config.rustfmt_args.clone(), |
111 | vscode_lldb: config.vscode_lldb, | 111 | vscode_lldb: config.vscode_lldb, |
112 | proc_macro_srv: None, // FIXME: get this from config | ||
112 | } | 113 | } |
113 | } | 114 | } |
114 | 115 | ||
diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs index a15a7085f..b97fc7c53 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs | |||
@@ -58,6 +58,7 @@ pub struct Config { | |||
58 | pub rustfmt_args: Vec<String>, | 58 | pub rustfmt_args: Vec<String>, |
59 | pub check: CheckConfig, | 59 | pub check: CheckConfig, |
60 | pub vscode_lldb: bool, | 60 | pub vscode_lldb: bool, |
61 | pub proc_macro_srv: Option<String>, | ||
61 | } | 62 | } |
62 | 63 | ||
63 | /// `WorldState` is the primary mutable state of the language server | 64 | /// `WorldState` is the primary mutable state of the language server |
@@ -167,8 +168,23 @@ impl WorldState { | |||
167 | vfs_file.map(|f| FileId(f.0)) | 168 | vfs_file.map(|f| FileId(f.0)) |
168 | }; | 169 | }; |
169 | 170 | ||
170 | let proc_macro_client = | 171 | let proc_macro_client = match &options.proc_macro_srv { |
171 | ProcMacroClient::extern_process(std::path::Path::new("ra_proc_macro_srv")); | 172 | None => ProcMacroClient::dummy(), |
173 | Some(srv) => { | ||
174 | let path = Path::new(&srv); | ||
175 | match ProcMacroClient::extern_process(path) { | ||
176 | Ok(it) => it, | ||
177 | Err(err) => { | ||
178 | log::error!( | ||
179 | "Fail to run ra_proc_macro_srv from path {}, error : {}", | ||
180 | path.to_string_lossy(), | ||
181 | err | ||
182 | ); | ||
183 | ProcMacroClient::dummy() | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | }; | ||
172 | 188 | ||
173 | workspaces | 189 | workspaces |
174 | .iter() | 190 | .iter() |