ra_proc_macro: cleanups here and there
This commit is contained in:
parent
36840bd6c7
commit
d3019164dc
@ -2,7 +2,7 @@
|
|||||||
//!
|
//!
|
||||||
//! We separate proc-macro expanding logic to an extern program to allow
|
//! We separate proc-macro expanding logic to an extern program to allow
|
||||||
//! different implementations (e.g. wasm or dylib loading). And this crate
|
//! different implementations (e.g. wasm or dylib loading). And this crate
|
||||||
//! is used to provide basic infrastructure for communication between two
|
//! is used to provide basic infrastructure for communication between two
|
||||||
//! processes: Client (RA itself), Server (the external program)
|
//! processes: Client (RA itself), Server (the external program)
|
||||||
|
|
||||||
mod rpc;
|
mod rpc;
|
||||||
@ -13,6 +13,7 @@ use process::{ProcMacroProcessSrv, ProcMacroProcessThread};
|
|||||||
use ra_tt::{SmolStr, Subtree};
|
use ra_tt::{SmolStr, Subtree};
|
||||||
use std::{
|
use std::{
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
|
io,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
@ -57,14 +58,10 @@ pub struct ProcMacroClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ProcMacroClient {
|
impl ProcMacroClient {
|
||||||
pub fn extern_process<I, S>(
|
pub fn extern_process(
|
||||||
process_path: &Path,
|
process_path: PathBuf,
|
||||||
args: I,
|
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
|
||||||
) -> Result<ProcMacroClient, std::io::Error>
|
) -> io::Result<ProcMacroClient> {
|
||||||
where
|
|
||||||
I: IntoIterator<Item = S>,
|
|
||||||
S: AsRef<OsStr>,
|
|
||||||
{
|
|
||||||
let (thread, process) = ProcMacroProcessSrv::run(process_path, args)?;
|
let (thread, process) = ProcMacroProcessSrv::run(process_path, args)?;
|
||||||
Ok(ProcMacroClient {
|
Ok(ProcMacroClient {
|
||||||
kind: ProcMacroClientKind::Process { process: Arc::new(process), thread },
|
kind: ProcMacroClientKind::Process { process: Arc::new(process), thread },
|
||||||
@ -84,7 +81,7 @@ impl ProcMacroClient {
|
|||||||
ProcMacroClientKind::Process { process, .. } => {
|
ProcMacroClientKind::Process { process, .. } => {
|
||||||
let macros = match process.find_proc_macros(dylib_path) {
|
let macros = match process.find_proc_macros(dylib_path) {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("Fail to find proc macro. Error: {:#?}", err);
|
eprintln!("Failed to find proc macros. Error: {:#?}", err);
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
Ok(macros) => macros,
|
Ok(macros) => macros,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! Defines messages for cross-process message based on `ndjson` wire protocol
|
//! Defines messages for cross-process message passing based on `ndjson` wire protocol
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
@ -31,7 +31,7 @@ macro_rules! impl_try_from_response {
|
|||||||
fn try_from(value: Response) -> Result<Self, Self::Error> {
|
fn try_from(value: Response) -> Result<Self, Self::Error> {
|
||||||
match value {
|
match value {
|
||||||
Response::$tag(res) => Ok(res),
|
Response::$tag(res) => Ok(res),
|
||||||
_ => Err("Fail to convert from response"),
|
_ => Err(concat!("Failed to convert response to ", stringify!($tag))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,18 +53,16 @@ pub enum ErrorCode {
|
|||||||
ExpansionError,
|
ExpansionError,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Message: Sized + Serialize + DeserializeOwned {
|
pub trait Message: Serialize + DeserializeOwned {
|
||||||
fn read(r: &mut impl BufRead) -> io::Result<Option<Self>> {
|
fn read(inp: &mut impl BufRead) -> io::Result<Option<Self>> {
|
||||||
let text = match read_json(r)? {
|
Ok(match read_json(inp)? {
|
||||||
None => return Ok(None),
|
None => None,
|
||||||
Some(text) => text,
|
Some(text) => Some(serde_json::from_str(&text)?),
|
||||||
};
|
})
|
||||||
let msg = serde_json::from_str(&text)?;
|
|
||||||
Ok(Some(msg))
|
|
||||||
}
|
}
|
||||||
fn write(self, w: &mut impl Write) -> io::Result<()> {
|
fn write(self, out: &mut impl Write) -> io::Result<()> {
|
||||||
let text = serde_json::to_string(&self)?;
|
let text = serde_json::to_string(&self)?;
|
||||||
write_json(w, &text)
|
write_json(out, &text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,15 +71,12 @@ impl Message for Response {}
|
|||||||
|
|
||||||
fn read_json(inp: &mut impl BufRead) -> io::Result<Option<String>> {
|
fn read_json(inp: &mut impl BufRead) -> io::Result<Option<String>> {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
if inp.read_line(&mut buf)? == 0 {
|
inp.read_line(&mut buf)?;
|
||||||
return Ok(None);
|
buf.pop(); // Remove traling '\n'
|
||||||
}
|
Ok(match buf.len() {
|
||||||
// Remove ending '\n'
|
0 => None,
|
||||||
let buf = &buf[..buf.len() - 1];
|
_ => Some(buf),
|
||||||
if buf.is_empty() {
|
})
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
Ok(Some(buf.to_string()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> {
|
fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> {
|
||||||
|
@ -45,24 +45,23 @@ impl Drop for Process {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Process {
|
impl Process {
|
||||||
fn run<I, S>(process_path: &Path, args: I) -> Result<Process, io::Error>
|
fn run(
|
||||||
where
|
process_path: PathBuf,
|
||||||
I: IntoIterator<Item = S>,
|
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
|
||||||
S: AsRef<OsStr>,
|
) -> Result<Process, io::Error> {
|
||||||
{
|
let child = Command::new(&process_path)
|
||||||
let child = Command::new(process_path.clone())
|
|
||||||
.args(args)
|
.args(args)
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::null())
|
.stderr(Stdio::null())
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
|
|
||||||
Ok(Process { path: process_path.into(), child })
|
Ok(Process { path: process_path, child })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restart(&mut self) -> Result<(), io::Error> {
|
fn restart(&mut self) -> Result<(), io::Error> {
|
||||||
let _ = self.child.kill();
|
let _ = self.child.kill();
|
||||||
self.child = Command::new(self.path.clone())
|
self.child = Command::new(&self.path)
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::null())
|
.stderr(Stdio::null())
|
||||||
@ -80,14 +79,10 @@ impl Process {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ProcMacroProcessSrv {
|
impl ProcMacroProcessSrv {
|
||||||
pub fn run<I, S>(
|
pub fn run(
|
||||||
process_path: &Path,
|
process_path: PathBuf,
|
||||||
args: I,
|
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
|
||||||
) -> Result<(ProcMacroProcessThread, ProcMacroProcessSrv), io::Error>
|
) -> io::Result<(ProcMacroProcessThread, ProcMacroProcessSrv)> {
|
||||||
where
|
|
||||||
I: IntoIterator<Item = S>,
|
|
||||||
S: AsRef<OsStr>,
|
|
||||||
{
|
|
||||||
let process = Process::run(process_path, args)?;
|
let process = Process::run(process_path, args)?;
|
||||||
|
|
||||||
let (task_tx, task_rx) = bounded(0);
|
let (task_tx, task_rx) = bounded(0);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
//! Data struture serialization related stuffs for RPC
|
//! Data struture serialization related stuff for RPC
|
||||||
//!
|
//!
|
||||||
//! Define all necessary rpc serialization data structure,
|
//! Defines all necessary rpc serialization data structures,
|
||||||
//! which include ra_tt related data and some task messages.
|
//! which includes `ra_tt` related data and some task messages.
|
||||||
//! Although adding Serialize and Deserialize trait to ra_tt directly seem to be much easier,
|
//! Although adding `Serialize` and `Deserialize` traits to `ra_tt` directly seems
|
||||||
//! we deliberately duplicate the ra_tt struct with #[serde(with = "XXDef")]
|
//! to be much easier, we deliberately duplicate `ra_tt` structs with `#[serde(with = "XXDef")]`
|
||||||
//! for separation of code responsibility.
|
//! for separation of code responsibility.
|
||||||
|
|
||||||
use ra_tt::{
|
use ra_tt::{
|
||||||
@ -34,15 +34,15 @@ pub struct ListMacrosResult {
|
|||||||
pub struct ExpansionTask {
|
pub struct ExpansionTask {
|
||||||
/// Argument of macro call.
|
/// Argument of macro call.
|
||||||
///
|
///
|
||||||
/// In custom derive that would be a struct or enum; in attribute-like macro - underlying
|
/// In custom derive this will be a struct or enum; in attribute-like macro - underlying
|
||||||
/// item; in function-like macro - the macro body.
|
/// item; in function-like macro - the macro body.
|
||||||
#[serde(with = "SubtreeDef")]
|
#[serde(with = "SubtreeDef")]
|
||||||
pub macro_body: Subtree,
|
pub macro_body: Subtree,
|
||||||
|
|
||||||
/// Names of macros to expand.
|
/// Names of macros to expand. // TODO: are they comma-separated?
|
||||||
///
|
///
|
||||||
/// In custom derive those are names of derived traits (`Serialize`, `Getters`, etc.). In
|
/// In custom derive those are names of derived traits (`Serialize`, `Getters`, etc.). In
|
||||||
/// attribute-like and functiona-like macros - single name of macro itself (`show_streams`).
|
/// attribute-like and function-like macros - single name of macro itself (`show_streams`).
|
||||||
pub macro_name: String,
|
pub macro_name: String,
|
||||||
|
|
||||||
/// Possible attributes for the attribute-like macros.
|
/// Possible attributes for the attribute-like macros.
|
||||||
|
@ -2,55 +2,43 @@
|
|||||||
|
|
||||||
use crate::{expand_task, list_macros};
|
use crate::{expand_task, list_macros};
|
||||||
use ra_proc_macro::msg::{self, Message};
|
use ra_proc_macro::msg::{self, Message};
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
fn read_request() -> Result<Option<msg::Request>, io::Error> {
|
|
||||||
let stdin = io::stdin();
|
|
||||||
let mut stdin = stdin.lock();
|
|
||||||
msg::Request::read(&mut stdin)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_response(res: Result<msg::Response, String>) -> Result<(), io::Error> {
|
|
||||||
let msg: msg::Response = match res {
|
|
||||||
Ok(res) => res,
|
|
||||||
Err(err) => msg::Response::Error(msg::ResponseError {
|
|
||||||
code: msg::ErrorCode::ExpansionError,
|
|
||||||
message: err,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
let stdout = io::stdout();
|
|
||||||
let mut stdout = stdout.lock();
|
|
||||||
msg.write(&mut stdout)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
loop {
|
loop {
|
||||||
let req = match read_request() {
|
let req = match read_request() {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("Read message error on ra_proc_macro_srv: {}", err.to_string());
|
eprintln!("Read message error on ra_proc_macro_srv: {}", err);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Ok(None) => continue,
|
Ok(None) => continue,
|
||||||
Ok(Some(req)) => req,
|
Ok(Some(req)) => req,
|
||||||
};
|
};
|
||||||
|
|
||||||
match req {
|
let res = match req {
|
||||||
msg::Request::ListMacro(task) => {
|
msg::Request::ListMacro(task) => Ok(msg::Response::ListMacro(list_macros(&task))),
|
||||||
if let Err(err) =
|
|
||||||
write_response(list_macros(&task).map(|it| msg::Response::ListMacro(it)))
|
|
||||||
{
|
|
||||||
eprintln!("Write message error on list macro: {}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
msg::Request::ExpansionMacro(task) => {
|
msg::Request::ExpansionMacro(task) => {
|
||||||
if let Err(err) =
|
expand_task(&task).map(msg::Response::ExpansionMacro)
|
||||||
write_response(expand_task(&task).map(|it| msg::Response::ExpansionMacro(it)))
|
|
||||||
{
|
|
||||||
eprintln!("Write message error on expansion macro: {}", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let msg = res.unwrap_or_else(|err| {
|
||||||
|
msg::Response::Error(msg::ResponseError {
|
||||||
|
code: msg::ErrorCode::ExpansionError,
|
||||||
|
message: err,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Err(err) = write_response(msg) {
|
||||||
|
eprintln!("Write message error: {}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_request() -> io::Result<Option<msg::Request>> {
|
||||||
|
msg::Request::read(&mut io::stdin().lock())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_response(msg: msg::Response) -> io::Result<()> {
|
||||||
|
msg.write(&mut io::stdout().lock())
|
||||||
|
}
|
||||||
|
@ -9,43 +9,37 @@ use libloading::Library;
|
|||||||
use memmap::Mmap;
|
use memmap::Mmap;
|
||||||
use ra_proc_macro::ProcMacroKind;
|
use ra_proc_macro::ProcMacroKind;
|
||||||
|
|
||||||
use std::io::Error as IoError;
|
use std::io;
|
||||||
use std::io::ErrorKind as IoErrorKind;
|
|
||||||
|
|
||||||
const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_";
|
const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_";
|
||||||
|
|
||||||
fn invalid_data_err(e: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> IoError {
|
fn invalid_data_err(e: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> io::Error {
|
||||||
IoError::new(IoErrorKind::InvalidData, e)
|
io::Error::new(io::ErrorKind::InvalidData, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_derive_registrar_symbol(symbol: &str) -> bool {
|
fn is_derive_registrar_symbol(symbol: &&str) -> bool {
|
||||||
symbol.contains(NEW_REGISTRAR_SYMBOL)
|
symbol.contains(NEW_REGISTRAR_SYMBOL)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_registrar_symbol(file: &Path) -> Result<Option<String>, IoError> {
|
fn find_registrar_symbol(file: &Path) -> io::Result<Option<String>> {
|
||||||
let file = File::open(file)?;
|
let file = File::open(file)?;
|
||||||
let buffer = unsafe { Mmap::map(&file)? };
|
let buffer = unsafe { Mmap::map(&file)? };
|
||||||
let object = Object::parse(&buffer).map_err(invalid_data_err)?;
|
let object = Object::parse(&buffer).map_err(invalid_data_err)?;
|
||||||
|
|
||||||
match object {
|
let name = match object {
|
||||||
Object::Elf(elf) => {
|
Object::Elf(elf) => {
|
||||||
let symbols = elf.dynstrtab.to_vec().map_err(invalid_data_err)?;
|
let symbols = elf.dynstrtab.to_vec().map_err(invalid_data_err)?;
|
||||||
let name =
|
symbols.into_iter().find(is_derive_registrar_symbol).map(&str::to_owned)
|
||||||
symbols.iter().find(|s| is_derive_registrar_symbol(s)).map(|s| s.to_string());
|
|
||||||
Ok(name)
|
|
||||||
}
|
|
||||||
Object::PE(pe) => {
|
|
||||||
let name = pe
|
|
||||||
.exports
|
|
||||||
.iter()
|
|
||||||
.flat_map(|s| s.name)
|
|
||||||
.find(|s| is_derive_registrar_symbol(s))
|
|
||||||
.map(|s| s.to_string());
|
|
||||||
Ok(name)
|
|
||||||
}
|
}
|
||||||
|
Object::PE(pe) => pe
|
||||||
|
.exports
|
||||||
|
.iter()
|
||||||
|
.flat_map(|s| s.name)
|
||||||
|
.find(is_derive_registrar_symbol)
|
||||||
|
.map(&str::to_owned),
|
||||||
Object::Mach(Mach::Binary(binary)) => {
|
Object::Mach(Mach::Binary(binary)) => {
|
||||||
let exports = binary.exports().map_err(invalid_data_err)?;
|
let exports = binary.exports().map_err(invalid_data_err)?;
|
||||||
let name = exports
|
exports
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| {
|
.map(|s| {
|
||||||
// In macos doc:
|
// In macos doc:
|
||||||
@ -58,12 +52,12 @@ fn find_registrar_symbol(file: &Path) -> Result<Option<String>, IoError> {
|
|||||||
&s.name
|
&s.name
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.find(|s| is_derive_registrar_symbol(s))
|
.find(is_derive_registrar_symbol)
|
||||||
.map(|s| s.to_string());
|
.map(&str::to_owned)
|
||||||
Ok(name)
|
|
||||||
}
|
}
|
||||||
_ => Ok(None),
|
_ => return Ok(None),
|
||||||
}
|
};
|
||||||
|
Ok(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads dynamic library in platform dependent manner.
|
/// Loads dynamic library in platform dependent manner.
|
||||||
@ -93,15 +87,16 @@ fn load_library(file: &Path) -> Result<Library, libloading::Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct ProcMacroLibraryLibloading {
|
struct ProcMacroLibraryLibloading {
|
||||||
// Hold the dylib to prevent it for unloadeding
|
// Hold the dylib to prevent it from unloading
|
||||||
_lib: Library,
|
_lib: Library,
|
||||||
exported_macros: Vec<bridge::client::ProcMacro>,
|
exported_macros: Vec<bridge::client::ProcMacro>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcMacroLibraryLibloading {
|
impl ProcMacroLibraryLibloading {
|
||||||
fn open(file: &Path) -> Result<Self, IoError> {
|
fn open(file: &Path) -> io::Result<Self> {
|
||||||
let symbol_name = find_registrar_symbol(file)?
|
let symbol_name = find_registrar_symbol(file)?.ok_or_else(|| {
|
||||||
.ok_or(invalid_data_err(format!("Cannot find registrar symbol in file {:?}", file)))?;
|
invalid_data_err(format!("Cannot find registrar symbol in file {:?}", file))
|
||||||
|
})?;
|
||||||
|
|
||||||
let lib = load_library(file).map_err(invalid_data_err)?;
|
let lib = load_library(file).map_err(invalid_data_err)?;
|
||||||
let exported_macros = {
|
let exported_macros = {
|
||||||
@ -121,18 +116,16 @@ pub struct Expander {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Expander {
|
impl Expander {
|
||||||
pub fn new<P: AsRef<Path>>(lib: &P) -> Result<Expander, String> {
|
pub fn new(lib: &Path) -> Result<Expander, String> {
|
||||||
let mut libs = vec![];
|
// Some libraries for dynamic loading require canonicalized path even when it is
|
||||||
/* Some libraries for dynamic loading require canonicalized path (even when it is
|
// already absolute
|
||||||
already absolute
|
let lib = lib
|
||||||
*/
|
.canonicalize()
|
||||||
let lib =
|
.unwrap_or_else(|err| panic!("Cannot canonicalize {:?}: {:?}", lib, err));
|
||||||
lib.as_ref().canonicalize().expect(&format!("Cannot canonicalize {:?}", lib.as_ref()));
|
|
||||||
|
|
||||||
let library = ProcMacroLibraryImpl::open(&lib).map_err(|e| e.to_string())?;
|
let library = ProcMacroLibraryImpl::open(&lib).map_err(|e| e.to_string())?;
|
||||||
libs.push(library);
|
|
||||||
|
|
||||||
Ok(Expander { libs })
|
Ok(Expander { libs: vec![library] })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expand(
|
pub fn expand(
|
||||||
@ -176,7 +169,6 @@ impl Expander {
|
|||||||
parsed_attributes,
|
parsed_attributes,
|
||||||
parsed_body,
|
parsed_body,
|
||||||
);
|
);
|
||||||
|
|
||||||
return res.map(|it| it.subtree);
|
return res.map(|it| it.subtree);
|
||||||
}
|
}
|
||||||
_ => continue,
|
_ => continue,
|
||||||
@ -187,26 +179,21 @@ impl Expander {
|
|||||||
Err(bridge::PanicMessage::String("Nothing to expand".to_string()))
|
Err(bridge::PanicMessage::String("Nothing to expand".to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_macros(&self) -> Result<Vec<(String, ProcMacroKind)>, bridge::PanicMessage> {
|
pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> {
|
||||||
let mut result = vec![];
|
self.libs
|
||||||
|
.iter()
|
||||||
for lib in &self.libs {
|
.flat_map(|it| &it.exported_macros)
|
||||||
for proc_macro in &lib.exported_macros {
|
.map(|proc_macro| match proc_macro {
|
||||||
let res = match proc_macro {
|
bridge::client::ProcMacro::CustomDerive { trait_name, .. } => {
|
||||||
bridge::client::ProcMacro::CustomDerive { trait_name, .. } => {
|
(trait_name.to_string(), ProcMacroKind::CustomDerive)
|
||||||
(trait_name.to_string(), ProcMacroKind::CustomDerive)
|
}
|
||||||
}
|
bridge::client::ProcMacro::Bang { name, .. } => {
|
||||||
bridge::client::ProcMacro::Bang { name, .. } => {
|
(name.to_string(), ProcMacroKind::FuncLike)
|
||||||
(name.to_string(), ProcMacroKind::FuncLike)
|
}
|
||||||
}
|
bridge::client::ProcMacro::Attr { name, .. } => {
|
||||||
bridge::client::ProcMacro::Attr { name, .. } => {
|
(name.to_string(), ProcMacroKind::Attr)
|
||||||
(name.to_string(), ProcMacroKind::Attr)
|
}
|
||||||
}
|
})
|
||||||
};
|
.collect()
|
||||||
result.push(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(result)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
//! This library is able to call compiled Rust custom derive dynamic libraries on arbitrary code.
|
//! This library is able to call compiled Rust custom derive dynamic libraries on arbitrary code.
|
||||||
//! The general idea here is based on https://github.com/fedochet/rust-proc-macro-expander.
|
//! The general idea here is based on https://github.com/fedochet/rust-proc-macro-expander.
|
||||||
//!
|
//!
|
||||||
//! But we change some several design for fitting RA needs:
|
//! But we adapt it to better fit RA needs:
|
||||||
//!
|
//!
|
||||||
//! * We use `ra_tt` for proc-macro `TokenStream` server, it is easy to manipute and interact with
|
//! * We use `ra_tt` for proc-macro `TokenStream` server, it is easy to manipulate and interact with
|
||||||
//! RA then proc-macro2 token stream.
|
//! RA than `proc-macro2` token stream.
|
||||||
//! * By **copying** the whole rustc `lib_proc_macro` code, we are able to build this with `stable`
|
//! * By **copying** the whole rustc `lib_proc_macro` code, we are able to build this with `stable`
|
||||||
//! rustc rather than `unstable`. (Although in gerenal ABI compatibility is still an issue)
|
//! rustc rather than `unstable`. (Although in gerenal ABI compatibility is still an issue)
|
||||||
|
|
||||||
@ -21,36 +21,28 @@ mod dylib;
|
|||||||
|
|
||||||
use proc_macro::bridge::client::TokenStream;
|
use proc_macro::bridge::client::TokenStream;
|
||||||
use ra_proc_macro::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask};
|
use ra_proc_macro::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
pub(crate) fn expand_task(task: &ExpansionTask) -> Result<ExpansionResult, String> {
|
pub(crate) fn expand_task(task: &ExpansionTask) -> Result<ExpansionResult, String> {
|
||||||
let expander = dylib::Expander::new(&task.lib)
|
let expander = create_expander(&task.lib);
|
||||||
.expect(&format!("Cannot expand with provided libraries: ${:?}", &task.lib));
|
|
||||||
|
|
||||||
match expander.expand(&task.macro_name, &task.macro_body, task.attributes.as_ref()) {
|
match expander.expand(&task.macro_name, &task.macro_body, task.attributes.as_ref()) {
|
||||||
Ok(expansion) => Ok(ExpansionResult { expansion }),
|
Ok(expansion) => Ok(ExpansionResult { expansion }),
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
let reason = format!(
|
Err(format!("Cannot perform expansion for {}: error {:?}", &task.macro_name, msg))
|
||||||
"Cannot perform expansion for {}: error {:?}!",
|
|
||||||
&task.macro_name,
|
|
||||||
msg.as_str()
|
|
||||||
);
|
|
||||||
Err(reason)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn list_macros(task: &ListMacrosTask) -> Result<ListMacrosResult, String> {
|
pub(crate) fn list_macros(task: &ListMacrosTask) -> ListMacrosResult {
|
||||||
let expander = dylib::Expander::new(&task.lib)
|
let expander = create_expander(&task.lib);
|
||||||
.expect(&format!("Cannot expand with provided libraries: ${:?}", &task.lib));
|
|
||||||
|
|
||||||
match expander.list_macros() {
|
ListMacrosResult { macros: expander.list_macros() }
|
||||||
Ok(macros) => Ok(ListMacrosResult { macros }),
|
}
|
||||||
Err(msg) => {
|
|
||||||
let reason =
|
fn create_expander(lib: &Path) -> dylib::Expander {
|
||||||
format!("Cannot perform expansion for {:?}: error {:?}!", &task.lib, msg.as_str());
|
dylib::Expander::new(lib)
|
||||||
Err(reason)
|
.unwrap_or_else(|err| panic!("Cannot create expander for {:?}: {:?}", lib, err))
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
//! The original idea from fedochet is using proc-macro2 as backend,
|
//! The original idea from fedochet is using proc-macro2 as backend,
|
||||||
//! we use ra_tt instead for better intergation with RA.
|
//! we use ra_tt instead for better intergation with RA.
|
||||||
//!
|
//!
|
||||||
//! FIXME: No span and source file informatin is implemented yet
|
//! FIXME: No span and source file information is implemented yet
|
||||||
|
|
||||||
use crate::proc_macro::bridge::{self, server};
|
use crate::proc_macro::bridge::{self, server};
|
||||||
use ra_tt as tt;
|
use ra_tt as tt;
|
||||||
|
@ -60,6 +60,6 @@ pub fn list(crate_name: &str, version: &str) -> Vec<String> {
|
|||||||
let path = fixtures::dylib_path(crate_name, version);
|
let path = fixtures::dylib_path(crate_name, version);
|
||||||
let task = ListMacrosTask { lib: path };
|
let task = ListMacrosTask { lib: path };
|
||||||
|
|
||||||
let res = list_macros(&task).unwrap();
|
let res = list_macros(&task);
|
||||||
res.macros.into_iter().map(|(name, kind)| format!("{} [{:?}]", name, kind)).collect()
|
res.macros.into_iter().map(|(name, kind)| format!("{} [{:?}]", name, kind)).collect()
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ fn main() -> Result<()> {
|
|||||||
cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro, all)?
|
cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro, all)?
|
||||||
}
|
}
|
||||||
|
|
||||||
args::Command::ProcMacro => run_proc_macro_sv()?,
|
args::Command::ProcMacro => run_proc_macro_srv()?,
|
||||||
args::Command::RunServer => run_server()?,
|
args::Command::RunServer => run_server()?,
|
||||||
args::Command::Version => println!("rust-analyzer {}", env!("REV")),
|
args::Command::Version => println!("rust-analyzer {}", env!("REV")),
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ fn setup_logging() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_proc_macro_sv() -> Result<()> {
|
fn run_proc_macro_srv() -> Result<()> {
|
||||||
ra_proc_macro_srv::cli::run();
|
ra_proc_macro_srv::cli::run();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ pub(crate) fn load_cargo(
|
|||||||
ProcMacroClient::dummy()
|
ProcMacroClient::dummy()
|
||||||
} else {
|
} else {
|
||||||
let path = std::env::current_exe()?;
|
let path = std::env::current_exe()?;
|
||||||
ProcMacroClient::extern_process(&path, &["proc-macro"]).unwrap()
|
ProcMacroClient::extern_process(path, &["proc-macro"]).unwrap()
|
||||||
};
|
};
|
||||||
let host = load(&source_roots, ws, &mut vfs, receiver, extern_dirs, &proc_macro_client);
|
let host = load(&source_roots, ws, &mut vfs, receiver, extern_dirs, &proc_macro_client);
|
||||||
Ok((host, source_roots))
|
Ok((host, source_roots))
|
||||||
|
@ -148,20 +148,17 @@ impl WorldState {
|
|||||||
|
|
||||||
let proc_macro_client = match &config.proc_macro_srv {
|
let proc_macro_client = match &config.proc_macro_srv {
|
||||||
None => ProcMacroClient::dummy(),
|
None => ProcMacroClient::dummy(),
|
||||||
Some((path, args)) => {
|
Some((path, args)) => match ProcMacroClient::extern_process(path.into(), args) {
|
||||||
let path = std::path::Path::new(path);
|
Ok(it) => it,
|
||||||
match ProcMacroClient::extern_process(path, args) {
|
Err(err) => {
|
||||||
Ok(it) => it,
|
log::error!(
|
||||||
Err(err) => {
|
"Fail to run ra_proc_macro_srv from path {}, error: {:?}",
|
||||||
log::error!(
|
path,
|
||||||
"Fail to run ra_proc_macro_srv from path {}, error : {}",
|
err
|
||||||
path.to_string_lossy(),
|
);
|
||||||
err
|
ProcMacroClient::dummy()
|
||||||
);
|
|
||||||
ProcMacroClient::dummy()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
workspaces
|
workspaces
|
||||||
|
Loading…
x
Reference in New Issue
Block a user