Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/proc-macro-srv-cli/src/main_loop.rs')
| -rw-r--r-- | crates/proc-macro-srv-cli/src/main_loop.rs | 332 |
1 files changed, 286 insertions, 46 deletions
diff --git a/crates/proc-macro-srv-cli/src/main_loop.rs b/crates/proc-macro-srv-cli/src/main_loop.rs index 703bc965db..25a5104c5d 100644 --- a/crates/proc-macro-srv-cli/src/main_loop.rs +++ b/crates/proc-macro-srv-cli/src/main_loop.rs @@ -1,23 +1,21 @@ //! The main loop of the proc-macro server. -use std::io; - use proc_macro_api::{ - legacy_protocol::{ - json::{read_json, write_json}, - msg::{ - self, ExpandMacroData, ExpnGlobals, Message, SpanMode, SpanTransformer, - deserialize_span_data_index_map, serialize_span_data_index_map, - }, - }, + Codec, + bidirectional_protocol::msg as bidirectional, + legacy_protocol::msg as legacy, + transport::codec::{json::JsonProtocol, postcard::PostcardProtocol}, version::CURRENT_API_VERSION, }; +use std::io; + +use legacy::Message; + use proc_macro_srv::{EnvSnapshot, SpanId}; use crate::ProtocolFormat; - struct SpanTrans; -impl SpanTransformer for SpanTrans { +impl legacy::SpanTransformer for SpanTrans { type Table = (); type Span = SpanId; fn token_id_of( @@ -36,13 +34,13 @@ impl SpanTransformer for SpanTrans { pub(crate) fn run(format: ProtocolFormat) -> io::Result<()> { match format { - ProtocolFormat::Json => run_json(), - #[cfg(feature = "postcard")] - ProtocolFormat::Postcard => unimplemented!(), + ProtocolFormat::JsonLegacy => run_::<JsonProtocol>(), + ProtocolFormat::PostcardLegacy => run_::<PostcardProtocol>(), + ProtocolFormat::BidirectionalPostcardPrototype => run_new::<PostcardProtocol>(), } } -fn run_json() -> io::Result<()> { +fn run_new<C: Codec>() -> io::Result<()> { fn macro_kind_to_api(kind: proc_macro_srv::ProcMacroKind) -> proc_macro_api::ProcMacroKind { match kind { proc_macro_srv::ProcMacroKind::CustomDerive => { @@ -53,47 +51,270 @@ fn run_json() -> io::Result<()> { } } - let mut buf = String::new(); - let mut read_request = || msg::Request::read(read_json, &mut io::stdin().lock(), &mut buf); - let write_response = |msg: msg::Response| msg.write(write_json, &mut io::stdout().lock()); + let mut buf = C::Buf::default(); + let mut stdin = io::stdin(); + let mut stdout = io::stdout(); + + let env_snapshot = EnvSnapshot::default(); + let srv = proc_macro_srv::ProcMacroSrv::new(&env_snapshot); + + let mut span_mode = legacy::SpanMode::Id; + + 'outer: loop { + let req_opt = + bidirectional::BidirectionalMessage::read::<_, C>(&mut stdin.lock(), &mut buf)?; + let Some(req) = req_opt else { + break 'outer; + }; + + match req { + bidirectional::BidirectionalMessage::Request(request) => match request { + bidirectional::Request::ListMacros { dylib_path } => { + let res = srv.list_macros(&dylib_path).map(|macros| { + macros + .into_iter() + .map(|(name, kind)| (name, macro_kind_to_api(kind))) + .collect() + }); + + send_response::<C>(&stdout, bidirectional::Response::ListMacros(res))?; + } + + bidirectional::Request::ApiVersionCheck {} => { + // bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION).write::<_, C>(stdout) + send_response::<C>( + &stdout, + bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION), + )?; + } + + bidirectional::Request::SetConfig(config) => { + span_mode = config.span_mode; + send_response::<C>(&stdout, bidirectional::Response::SetConfig(config))?; + } + bidirectional::Request::ExpandMacro(task) => { + handle_expand::<C>(&srv, &mut stdin, &mut stdout, &mut buf, span_mode, *task)?; + } + }, + _ => continue, + } + } + + Ok(()) +} + +fn handle_expand<C: Codec>( + srv: &proc_macro_srv::ProcMacroSrv<'_>, + stdin: &io::Stdin, + stdout: &io::Stdout, + buf: &mut C::Buf, + span_mode: legacy::SpanMode, + task: bidirectional::ExpandMacro, +) -> io::Result<()> { + match span_mode { + legacy::SpanMode::Id => handle_expand_id::<C>(srv, stdout, task), + legacy::SpanMode::RustAnalyzer => handle_expand_ra::<C>(srv, stdin, stdout, buf, task), + } +} + +fn handle_expand_id<C: Codec>( + srv: &proc_macro_srv::ProcMacroSrv<'_>, + stdout: &io::Stdout, + task: bidirectional::ExpandMacro, +) -> io::Result<()> { + let bidirectional::ExpandMacro { lib, env, current_dir, data } = task; + let bidirectional::ExpandMacroData { + macro_body, + macro_name, + attributes, + has_global_spans: bidirectional::ExpnGlobals { def_site, call_site, mixed_site, .. }, + .. + } = data; + + let def_site = SpanId(def_site as u32); + let call_site = SpanId(call_site as u32); + let mixed_site = SpanId(mixed_site as u32); + + let macro_body = + macro_body.to_tokenstream_unresolved::<SpanTrans>(CURRENT_API_VERSION, |_, b| b); + let attributes = attributes + .map(|it| it.to_tokenstream_unresolved::<SpanTrans>(CURRENT_API_VERSION, |_, b| b)); + + let res = srv + .expand( + lib, + &env, + current_dir, + ¯o_name, + macro_body, + attributes, + def_site, + call_site, + mixed_site, + None, + ) + .map(|it| { + legacy::FlatTree::from_tokenstream_raw::<SpanTrans>(it, call_site, CURRENT_API_VERSION) + }) + .map_err(|e| legacy::PanicMessage(e.into_string().unwrap_or_default())); + + send_response::<C>(&stdout, bidirectional::Response::ExpandMacro(res)) +} + +struct ProcMacroClientHandle<'a, C: Codec> { + stdin: &'a io::Stdin, + stdout: &'a io::Stdout, + buf: &'a mut C::Buf, +} + +impl<C: Codec> proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> { + fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option<String> { + let req = bidirectional::BidirectionalMessage::SubRequest( + bidirectional::SubRequest::SourceText { file_id, start, end }, + ); + + if req.write::<_, C>(&mut self.stdout.lock()).is_err() { + return None; + } + + let msg = match bidirectional::BidirectionalMessage::read::<_, C>( + &mut self.stdin.lock(), + self.buf, + ) { + Ok(Some(msg)) => msg, + _ => return None, + }; + + match msg { + bidirectional::BidirectionalMessage::SubResponse( + bidirectional::SubResponse::SourceTextResult { text }, + ) => text, + _ => None, + } + } +} + +fn handle_expand_ra<C: Codec>( + srv: &proc_macro_srv::ProcMacroSrv<'_>, + stdin: &io::Stdin, + stdout: &io::Stdout, + buf: &mut C::Buf, + task: bidirectional::ExpandMacro, +) -> io::Result<()> { + let bidirectional::ExpandMacro { + lib, + env, + current_dir, + data: + bidirectional::ExpandMacroData { + macro_body, + macro_name, + attributes, + has_global_spans: bidirectional::ExpnGlobals { def_site, call_site, mixed_site, .. }, + span_data_table, + }, + } = task; + + let mut span_data_table = legacy::deserialize_span_data_index_map(&span_data_table); + + let def_site = span_data_table[def_site]; + let call_site = span_data_table[call_site]; + let mixed_site = span_data_table[mixed_site]; + + let macro_body = + macro_body.to_tokenstream_resolved(CURRENT_API_VERSION, &span_data_table, |a, b| { + srv.join_spans(a, b).unwrap_or(b) + }); + + let attributes = attributes.map(|it| { + it.to_tokenstream_resolved(CURRENT_API_VERSION, &span_data_table, |a, b| { + srv.join_spans(a, b).unwrap_or(b) + }) + }); + + let res = srv + .expand( + lib, + &env, + current_dir, + ¯o_name, + macro_body, + attributes, + def_site, + call_site, + mixed_site, + Some(&mut ProcMacroClientHandle::<C> { stdin, stdout, buf }), + ) + .map(|it| { + ( + legacy::FlatTree::from_tokenstream( + it, + CURRENT_API_VERSION, + call_site, + &mut span_data_table, + ), + legacy::serialize_span_data_index_map(&span_data_table), + ) + }) + .map(|(tree, span_data_table)| bidirectional::ExpandMacroExtended { tree, span_data_table }) + .map_err(|e| legacy::PanicMessage(e.into_string().unwrap_or_default())); + + send_response::<C>(&stdout, bidirectional::Response::ExpandMacroExtended(res)) +} + +fn run_<C: Codec>() -> io::Result<()> { + fn macro_kind_to_api(kind: proc_macro_srv::ProcMacroKind) -> proc_macro_api::ProcMacroKind { + match kind { + proc_macro_srv::ProcMacroKind::CustomDerive => { + proc_macro_api::ProcMacroKind::CustomDerive + } + proc_macro_srv::ProcMacroKind::Bang => proc_macro_api::ProcMacroKind::Bang, + proc_macro_srv::ProcMacroKind::Attr => proc_macro_api::ProcMacroKind::Attr, + } + } + + let mut buf = C::Buf::default(); + let mut read_request = || legacy::Request::read::<_, C>(&mut io::stdin().lock(), &mut buf); + let write_response = |msg: legacy::Response| msg.write::<_, C>(&mut io::stdout().lock()); let env = EnvSnapshot::default(); let srv = proc_macro_srv::ProcMacroSrv::new(&env); - let mut span_mode = SpanMode::Id; + let mut span_mode = legacy::SpanMode::Id; while let Some(req) = read_request()? { let res = match req { - msg::Request::ListMacros { dylib_path } => { - msg::Response::ListMacros(srv.list_macros(&dylib_path).map(|macros| { + legacy::Request::ListMacros { dylib_path } => { + legacy::Response::ListMacros(srv.list_macros(&dylib_path).map(|macros| { macros.into_iter().map(|(name, kind)| (name, macro_kind_to_api(kind))).collect() })) } - msg::Request::ExpandMacro(task) => { - let msg::ExpandMacro { + legacy::Request::ExpandMacro(task) => { + let legacy::ExpandMacro { lib, env, current_dir, data: - ExpandMacroData { + legacy::ExpandMacroData { macro_body, macro_name, attributes, has_global_spans: - ExpnGlobals { serialize: _, def_site, call_site, mixed_site }, + legacy::ExpnGlobals { serialize: _, def_site, call_site, mixed_site }, span_data_table, }, } = *task; match span_mode { - SpanMode::Id => msg::Response::ExpandMacro({ + legacy::SpanMode::Id => legacy::Response::ExpandMacro({ let def_site = SpanId(def_site as u32); let call_site = SpanId(call_site as u32); let mixed_site = SpanId(mixed_site as u32); - let macro_body = - macro_body.to_subtree_unresolved::<SpanTrans>(CURRENT_API_VERSION); - let attributes = attributes - .map(|it| it.to_subtree_unresolved::<SpanTrans>(CURRENT_API_VERSION)); + let macro_body = macro_body + .to_tokenstream_unresolved::<SpanTrans>(CURRENT_API_VERSION, |_, b| b); + let attributes = attributes.map(|it| { + it.to_tokenstream_unresolved::<SpanTrans>(CURRENT_API_VERSION, |_, b| b) + }); srv.expand( lib, @@ -105,27 +326,37 @@ fn run_json() -> io::Result<()> { def_site, call_site, mixed_site, + None, ) .map(|it| { - msg::FlatTree::new_raw::<SpanTrans>( - tt::SubtreeView::new(&it), + legacy::FlatTree::from_tokenstream_raw::<SpanTrans>( + it, + call_site, CURRENT_API_VERSION, ) }) .map_err(|e| e.into_string().unwrap_or_default()) - .map_err(msg::PanicMessage) + .map_err(legacy::PanicMessage) }), - SpanMode::RustAnalyzer => msg::Response::ExpandMacroExtended({ - let mut span_data_table = deserialize_span_data_index_map(&span_data_table); + legacy::SpanMode::RustAnalyzer => legacy::Response::ExpandMacroExtended({ + let mut span_data_table = + legacy::deserialize_span_data_index_map(&span_data_table); let def_site = span_data_table[def_site]; let call_site = span_data_table[call_site]; let mixed_site = span_data_table[mixed_site]; - let macro_body = - macro_body.to_subtree_resolved(CURRENT_API_VERSION, &span_data_table); + let macro_body = macro_body.to_tokenstream_resolved( + CURRENT_API_VERSION, + &span_data_table, + |a, b| srv.join_spans(a, b).unwrap_or(b), + ); let attributes = attributes.map(|it| { - it.to_subtree_resolved(CURRENT_API_VERSION, &span_data_table) + it.to_tokenstream_resolved( + CURRENT_API_VERSION, + &span_data_table, + |a, b| srv.join_spans(a, b).unwrap_or(b), + ) }); srv.expand( lib, @@ -137,30 +368,34 @@ fn run_json() -> io::Result<()> { def_site, call_site, mixed_site, + None, ) .map(|it| { ( - msg::FlatTree::new( - tt::SubtreeView::new(&it), + legacy::FlatTree::from_tokenstream( + it, CURRENT_API_VERSION, + call_site, &mut span_data_table, ), - serialize_span_data_index_map(&span_data_table), + legacy::serialize_span_data_index_map(&span_data_table), ) }) - .map(|(tree, span_data_table)| msg::ExpandMacroExtended { + .map(|(tree, span_data_table)| legacy::ExpandMacroExtended { tree, span_data_table, }) .map_err(|e| e.into_string().unwrap_or_default()) - .map_err(msg::PanicMessage) + .map_err(legacy::PanicMessage) }), } } - msg::Request::ApiVersionCheck {} => msg::Response::ApiVersionCheck(CURRENT_API_VERSION), - msg::Request::SetConfig(config) => { + legacy::Request::ApiVersionCheck {} => { + legacy::Response::ApiVersionCheck(CURRENT_API_VERSION) + } + legacy::Request::SetConfig(config) => { span_mode = config.span_mode; - msg::Response::SetConfig(config) + legacy::Response::SetConfig(config) } }; write_response(res)? @@ -168,3 +403,8 @@ fn run_json() -> io::Result<()> { Ok(()) } + +fn send_response<C: Codec>(stdout: &io::Stdout, resp: bidirectional::Response) -> io::Result<()> { + let resp = bidirectional::BidirectionalMessage::Response(resp); + resp.write::<_, C>(&mut stdout.lock()) +} |