계속·경기 프로그래밍에 procedural macro를 반입

경기 프로그래밍에 procedural macro 가져오기

전회의 기사에서는 경기 프로그래밍에 수속형 매크로를 반입하고 싶은 동기와, 그것을 이루기 위한(별로 스마트라고는 할 수 없는) 방법을 소개했습니다. 그리고 요전날 "그렇다면 rust-analzyer (RA)는 어떻게 프로 시저 매크로를 다루고 있습니까?", rpc , msg 라는 단어가 눈에 들어왔습니다. 혹시 생각 아 r 지어 c 동반. MD 을 읽으면 이런 것이 쓰여져 있지 않습니까.

For proc macros, the client-server model are used. We pass an argument stdin to stdout binary to start a separate process ( --proc-macro ). And the client ( rust-analyzer ) provides an interface to server separately.

(지금은 proc_macro_srv 가 아닌 부속 명령 proc_macro_api 와 같습니다만) 시도에 쿼리 --proc-macro 의 JSON 을 던져 버렸는데 보통으로 결과를 돌려주었습니다.
$ echo '{"ListMacro":{"lib":"./target/debug/deps/libfastout-2dbcc333cc21dae5.so"}}' | rust-analyzer proc-macro
{"ListMacro":{"macros":[["fastout","Attr"]]}}

또 다른 쿼리 proc-macro 에 대해서도 ListMacro 에서 잘 JSON으로 직렬화하면 됩니다. 이제 ExpansionMacro 를 요청하지 않아도 됩니다. 이번 cargo-equip에 RA를 사용한 프로시저 매크로의 배포 기능 구현 하고, v0.10.0 로서 릴리스 했습니다. 본 기사에서는 그에 부딪힌 문제와 그 해결 방법을 써 가려고 합니다.

proc-macro2 다운로드



JSON 형식은 문서화되지 않았으며 사용자가 사용하는 것도 예상되지 않습니다. 따라서 앞으로 할 일은 hack이며 단순히 watt 안의 rust-analzyer(.exe)를 사용하면 RA 업데이트로 인해 작동하지 않을 가능성이 있습니다. 그래서 특정 버전의 바이너리를 GitHub Releases

메시지 스키마



상호 작용하는 메시지의 스키마는 $PATH에 정의되어 있습니다. rust-analzyer(.exe) 를 모방한 형태를 만들고 proc_macro_api::msg::{요청, Response}tt::SubtreeSerialize 의 상호 Deserialize 를 구현하면 나머지는 간단하게 취급할 수 있습니다.

proc_macro2::Group 크레이트의 DLL 위치


From 상자는 동적 링크 라이브러리로 컴파일됩니다. 이 위치이지만 proc-macro 의 출력을 cargo_metadata 크레이트 으로 파스하면 얻을 수 있습니다. 목표 proc-macro는 컴파일이 건너 뛴 경우에도 포함되므로 재 컴파일을 시도 할 필요가 없습니다.

cargo check --message-format json 크레이트를 컴파일하는 Rust 버전


compiler-artifact 상자는 1.47.0 이상의 Rust로 컴파일되어야합니다. 1.42.0으로 컴파일한 것을 RA에 건네주면 이렇게 됩니다.



이번에는 active toolchain이 1.47.0 미만이면 rustup에 있는 툴체인을 찾아 그것을 사용하는 형태로 했습니다.

동작 예



proconio-derivememoise 가 AtCoder 이외에서 사용할 수 있게 되었습니다.
#[macro_use]
extern crate memoise as _;
#[macro_use]
extern crate proconio_derive as _;

#[fastout]
fn main() {
    for i in 0..=100 {
        println!("{}", fib(i));
    }
}

#[memoise(n <= 100)]
fn fib(n: i64) -> i64 {
    if n == 0 || n == 1 {
        return n;
    }
    fib(n - 1) + fib(n - 2)
}



Output
//! # Procedural macros
//!
//! - `memoise 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)`         licensed under `BSD-3-Clause`
//! - `proconio-derive 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)` licensed under `MIT OR Apache-2.0`

/*#[macro_use]
extern crate memoise as _;*/
/*#[macro_use]
extern crate proconio_derive as _;*/

/*#[fastout]
fn main() {
    for i in 0..=100 {
        println!("{}", fib(i));
    }
}*/
fn main() {
    let __proconio_stdout = ::std::io::stdout();
    let mut __proconio_stdout = ::std::io::BufWriter::new(__proconio_stdout.lock());
    #[allow(unused_macros)]
    macro_rules ! print { ($ ($ tt : tt) *) => { { use std :: io :: Write as _ ; :: std :: write ! (__proconio_stdout , $ ($ tt) *) . unwrap () ; } } ; }
    #[allow(unused_macros)]
    macro_rules ! println { ($ ($ tt : tt) *) => { { use std :: io :: Write as _ ; :: std :: writeln ! (__proconio_stdout , $ ($ tt) *) . unwrap () ; } } ; }
    let __proconio_res = {
        for i in 0..=100 {
            println!("{}", fib(i));
        }
    };
    <::std::io::BufWriter<::std::io::StdoutLock> as ::std::io::Write>::flush(
        &mut __proconio_stdout,
    )
    .unwrap();
    return __proconio_res;
}

/*#[memoise(n <= 100)]
fn fib(n: i64) -> i64 {
    if n == 0 || n == 1 {
        return n;
    }
    fib(n - 1) + fib(n - 2)
}*/
thread_local ! (static FIB : std :: cell :: RefCell < Vec < Option < i64 > > > = std :: cell :: RefCell :: new (vec ! [None ; 101usize]));
fn fib_reset() {
    FIB.with(|cache| {
        let mut r = cache.borrow_mut();
        for r in r.iter_mut() {
            *r = None
        }
    });
}
fn fib(n: i64) -> i64 {
    if let Some(ret) = FIB.with(|cache| {
        let mut bm = cache.borrow_mut();
        bm[(n) as usize].clone()
    }) {
        return ret;
    }
    let ret: i64 = (|| {
        if n == 0 || n == 1 {
            return n;
        }
        fib(n - 1) + fib(n - 2)
    })();
    FIB.with(|cache| {
        let mut bm = cache.borrow_mut();
        bm[(n) as usize] = Some(ret.clone());
    });
    ret
}

// The following code was expanded by `cargo-equip`.

#[allow(clippy::deprecated_cfg_attr)]#[cfg_attr(rustfmt,rustfmt::skip)]#[allow(unused)]pub mod memoise{}
#[allow(clippy::deprecated_cfg_attr)]#[cfg_attr(rustfmt,rustfmt::skip)]#[allow(unused)]pub mod proconio_derive{}

좋은 웹페이지 즐겨찾기