Skip to content

Commit 7a54649

Browse files
Merge #3738
3738: Implement ra_proc_macro client logic r=matklad a=edwin0cheng This PR add the actual client logic for `ra_proc_macro` crate: 1. Define all necessary rpc serialization data structure, which include `ra_tt` related data and some task messages. Although adding `Serialize` and `Deserialize` trait to ra_tt directly seem to be much easier, we deliberately duplicate the `ra_tt` struct with `#[serde(with = "XXDef")]` for separation of code responsibility. 2. Define a simplified version of lsp base protocol for rpc, which basically copy from lsp-server code base. 3. Implement the actual `IO` for the client side progress spawning and message passing. Co-authored-by: Edwin Cheng <[email protected]>
2 parents fa3c774 + 207903a commit 7a54649

File tree

11 files changed

+696
-23
lines changed

11 files changed

+696
-23
lines changed

Cargo.lock

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ra_hir_expand/src/proc_macro.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@ pub struct ProcMacroExpander {
99
proc_macro_id: ProcMacroId,
1010
}
1111

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+
1221
impl ProcMacroExpander {
1322
pub fn new(krate: CrateId, proc_macro_id: ProcMacroId) -> ProcMacroExpander {
1423
ProcMacroExpander { krate, proc_macro_id }
@@ -25,8 +34,24 @@ impl ProcMacroExpander {
2534
.proc_macro
2635
.get(self.proc_macro_id.0 as usize)
2736
.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"))?;
2941

3042
proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from)
3143
}
3244
}
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+
}

crates/ra_proc_macro/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,8 @@ doctest = false
1010

1111
[dependencies]
1212
ra_tt = { path = "../ra_tt" }
13+
serde = { version = "1.0", features = ["derive"] }
14+
serde_json = "1.0"
15+
log = "0.4.8"
16+
crossbeam-channel = "0.4.0"
17+
jod-thread = "0.1.1"

crates/ra_proc_macro/src/lib.rs

Lines changed: 67 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,55 +5,104 @@
55
//! is used to provide basic infrastructure for communication between two
66
//! processes: Client (RA itself), Server (the external program)
77
8+
mod rpc;
9+
mod process;
10+
pub mod msg;
11+
12+
use process::{ProcMacroProcessSrv, ProcMacroProcessThread};
813
use ra_tt::{SmolStr, Subtree};
14+
use rpc::ProcMacroKind;
915
use std::{
1016
path::{Path, PathBuf},
1117
sync::Arc,
1218
};
1319

14-
#[derive(Debug, Clone, PartialEq, Eq)]
20+
pub use rpc::{ExpansionResult, ExpansionTask};
21+
22+
#[derive(Debug, Clone)]
1523
pub struct ProcMacroProcessExpander {
1624
process: Arc<ProcMacroProcessSrv>,
25+
dylib_path: PathBuf,
1726
name: SmolStr,
1827
}
1928

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+
2038
impl ra_tt::TokenExpander for ProcMacroProcessExpander {
2139
fn expand(
2240
&self,
23-
_subtree: &Subtree,
41+
subtree: &Subtree,
2442
_attr: Option<&Subtree>,
2543
) -> Result<Subtree, ra_tt::ExpansionError> {
26-
// FIXME: do nothing for now
27-
Ok(Subtree::default())
44+
self.process.custom_derive(&self.dylib_path, subtree, &self.name)
2845
}
2946
}
3047

31-
#[derive(Debug, Clone, PartialEq, Eq)]
32-
pub struct ProcMacroProcessSrv {
33-
path: PathBuf,
48+
#[derive(Debug)]
49+
enum ProcMacroClientKind {
50+
Process { process: Arc<ProcMacroProcessSrv>, thread: ProcMacroProcessThread },
51+
Dummy,
3452
}
3553

36-
#[derive(Debug, Clone, PartialEq, Eq)]
37-
pub enum ProcMacroClient {
38-
Process { process: Arc<ProcMacroProcessSrv> },
39-
Dummy,
54+
#[derive(Debug)]
55+
pub struct ProcMacroClient {
56+
kind: ProcMacroClientKind,
4057
}
4158

4259
impl ProcMacroClient {
43-
pub fn extern_process(process_path: &Path) -> ProcMacroClient {
44-
let process = ProcMacroProcessSrv { path: process_path.into() };
45-
ProcMacroClient::Process { process: Arc::new(process) }
60+
pub fn extern_process(process_path: &Path) -> Result<ProcMacroClient, std::io::Error> {
61+
let (thread, process) = ProcMacroProcessSrv::run(process_path)?;
62+
Ok(ProcMacroClient {
63+
kind: ProcMacroClientKind::Process { process: Arc::new(process), thread },
64+
})
4665
}
4766

4867
pub fn dummy() -> ProcMacroClient {
49-
ProcMacroClient::Dummy
68+
ProcMacroClient { kind: ProcMacroClientKind::Dummy }
5069
}
5170

5271
pub fn by_dylib_path(
5372
&self,
54-
_dylib_path: &Path,
73+
dylib_path: &Path,
5574
) -> Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)> {
56-
// FIXME: return empty for now
57-
vec![]
75+
match &self.kind {
76+
ProcMacroClientKind::Dummy => vec![],
77+
ProcMacroClientKind::Process { process, .. } => {
78+
let macros = match process.find_proc_macros(dylib_path) {
79+
Err(err) => {
80+
eprintln!("Fail to find proc macro. Error: {:#?}", err);
81+
return vec![];
82+
}
83+
Ok(macros) => macros,
84+
};
85+
86+
macros
87+
.into_iter()
88+
.filter_map(|(name, kind)| {
89+
// FIXME: Support custom derive only for now.
90+
match kind {
91+
ProcMacroKind::CustomDerive => {
92+
let name = SmolStr::new(&name);
93+
let expander: Arc<dyn ra_tt::TokenExpander> =
94+
Arc::new(ProcMacroProcessExpander {
95+
process: process.clone(),
96+
name: name.clone(),
97+
dylib_path: dylib_path.into(),
98+
});
99+
Some((name, expander))
100+
}
101+
_ => None,
102+
}
103+
})
104+
.collect()
105+
}
106+
}
58107
}
59108
}

crates/ra_proc_macro/src/msg.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//! Defines messages for cross-process message based on `ndjson` wire protocol
2+
3+
use std::{
4+
convert::TryFrom,
5+
io::{self, BufRead, Write},
6+
};
7+
8+
use crate::{
9+
rpc::{ListMacrosResult, ListMacrosTask},
10+
ExpansionResult, ExpansionTask,
11+
};
12+
use serde::{de::DeserializeOwned, Deserialize, Serialize};
13+
14+
#[derive(Debug, Serialize, Deserialize, Clone)]
15+
pub enum Request {
16+
ListMacro(ListMacrosTask),
17+
ExpansionMacro(ExpansionTask),
18+
}
19+
20+
#[derive(Debug, Serialize, Deserialize, Clone)]
21+
pub enum Response {
22+
Error(ResponseError),
23+
ListMacro(ListMacrosResult),
24+
ExpansionMacro(ExpansionResult),
25+
}
26+
27+
macro_rules! impl_try_from_response {
28+
($ty:ty, $tag:ident) => {
29+
impl TryFrom<Response> for $ty {
30+
type Error = &'static str;
31+
fn try_from(value: Response) -> Result<Self, Self::Error> {
32+
match value {
33+
Response::$tag(res) => Ok(res),
34+
_ => Err("Fail to convert from response"),
35+
}
36+
}
37+
}
38+
};
39+
}
40+
41+
impl_try_from_response!(ListMacrosResult, ListMacro);
42+
impl_try_from_response!(ExpansionResult, ExpansionMacro);
43+
44+
#[derive(Debug, Serialize, Deserialize, Clone)]
45+
pub struct ResponseError {
46+
pub code: ErrorCode,
47+
pub message: String,
48+
}
49+
50+
#[derive(Debug, Serialize, Deserialize, Clone)]
51+
pub enum ErrorCode {
52+
ServerErrorEnd,
53+
ExpansionError,
54+
}
55+
56+
pub trait Message: Sized + Serialize + DeserializeOwned {
57+
fn read(r: &mut impl BufRead) -> io::Result<Option<Self>> {
58+
let text = match read_json(r)? {
59+
None => return Ok(None),
60+
Some(text) => text,
61+
};
62+
let msg = serde_json::from_str(&text)?;
63+
Ok(Some(msg))
64+
}
65+
fn write(self, w: &mut impl Write) -> io::Result<()> {
66+
let text = serde_json::to_string(&self)?;
67+
write_json(w, &text)
68+
}
69+
}
70+
71+
impl Message for Request {}
72+
impl Message for Response {}
73+
74+
fn read_json(inp: &mut impl BufRead) -> io::Result<Option<String>> {
75+
let mut buf = String::new();
76+
if inp.read_line(&mut buf)? == 0 {
77+
return Ok(None);
78+
}
79+
// Remove ending '\n'
80+
let buf = &buf[..buf.len() - 1];
81+
if buf.is_empty() {
82+
return Ok(None);
83+
}
84+
Ok(Some(buf.to_string()))
85+
}
86+
87+
fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> {
88+
log::debug!("> {}", msg);
89+
out.write_all(msg.as_bytes())?;
90+
out.write_all(b"\n")?;
91+
out.flush()?;
92+
Ok(())
93+
}

0 commit comments

Comments
 (0)