Display a package

Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
Luca Fulchir 2024-03-27 11:34:09 +01:00
parent 1d9ea5a699
commit 11ecc75393
Signed by: luca.fulchir
GPG Key ID: 8F6440603D13A78E
5 changed files with 81 additions and 17 deletions

12
Cargo.lock generated
View File

@ -35,8 +35,10 @@ version = "0.1.0"
dependencies = [
"bok",
"bok-macro",
"prettyplease",
"proc-macro2",
"quote",
"syn",
]
[[package]]
@ -45,6 +47,16 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "prettyplease"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7"
dependencies = [
"proc-macro2",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.78"

View File

@ -101,7 +101,7 @@ pub fn derive_repository(input: TokenStream) -> TokenStream {
/// e.g.:
/// ```
/// impl MyPackage {
/// #[package(::bok_macro::to_code)]
/// #[::bok_macro::to_code]
/// fn build() {
/// ...
/// }
@ -216,6 +216,7 @@ pub fn package(attrs: TokenStream, input: TokenStream) -> TokenStream {
#[proc_macro_derive(Package)]
pub fn derive_package(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let input2 = input.clone();
let name = input.ident.clone();
let name_builder = quote::format_ident!("{name}Builder");
@ -355,20 +356,76 @@ pub fn derive_package(input: TokenStream) -> TokenStream {
let opt_types2 = opt_types.clone();
let non_opt_types2 = non_opt_types.clone();
let expanded = quote! {
let impl_base = quote! {
impl ::bok::Pkg for #name {
fn base(&self) -> Option<&impl ::bok::Pkg> {
Some(&self.base)
}
}
// FIXME: proper formatting of all functions
};
let pkg_struct = quote! {
#input2
};
let mut pkg_struct_str = String::new();
{
use ::core::fmt::Write;
write!(&mut pkg_struct_str, "{}", pkg_struct)
.expect("can't write package struct into string");
}
let expanded = quote! {
#impl_base
impl ::core::fmt::Display for #name {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>)
->::core::fmt::Result
{
// FIXME: this sounds convoluted.
// first we make everything into a string, then we
// parse the string into tokenstream again to format it
// reason: the `prettyplease` works on `::syn::File`
// and I can't find an easy translation
// `TokenStream2 -> TokenStream`
use ::bok::Pkg;
let pkg = self.package_code();
pkg.fmt(f)
// don't add a method if it is just the base Trait implementation
fn maybe_add_fn(out: &mut String, name: &str, fn_str: &str) -> ::core::fmt::Result {
let str_base = "self . base () . unwrap () . ".to_owned() + name + " ()";
if fn_str.trim() != str_base {
use ::core::fmt::Write;
write!(out,
"#[::bok_macro::to_code]\n\
fn {}(&self) -> Result<(), ()> {{\n{}\n}}\n",
name, fn_str)
} else {
::core::fmt::Result::Ok(())
}
};
// from the Pkg trait
use ::core::fmt::Write;
let pkg_empty = ::bok::PkgEmpty{};
let mut pkg_string = String::new();
write!(&mut pkg_string, "{}", #pkg_struct_str)?;
write!(&mut pkg_string,
"impl ::bok::Pkg for {} {{\n",
::std::stringify!(#name)
)?;
maybe_add_fn(&mut pkg_string, "prepare", &self.prepare_code().to_string())?;
maybe_add_fn(&mut pkg_string, "configure", &self.configure_code().to_string())?;
maybe_add_fn(&mut pkg_string, "build", &self.build_code().to_string())?;
maybe_add_fn(&mut pkg_string, "check", &self.check_code().to_string())?;
maybe_add_fn(&mut pkg_string, "install", &self.install_code().to_string())?;
write!(&mut pkg_string, "}}\n")?;
let re_parsed = ::syn::parse_file(&pkg_string).unwrap();
let formatted = prettyplease::unparse(&re_parsed);
f.write_str(&formatted)
}
}
impl #name {

View File

@ -16,3 +16,5 @@ bok = { path = "../bok" }
bok-macro = { path = "../bok-macro" }
proc-macro2 = "1.0"
quote = "1.0"
prettyplease = "0.2"
syn = { version = "2", features = [ "full", "parsing" ] }

View File

@ -1,9 +1,9 @@
/*
* Copyright 2024 Luca Fulchir <luca.fulchir@runesauth.com>
*
* Licensed under the Apache License, Version 2.0 with LLVM exception (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License and of the exception at
* Licensed under the Apache License, Version 2.0 with LLVM exception (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License and of the exception at
*
* http://www.apache.org/licenses/LICENSE-2.0
* https://spdx.org/licenses/LLVM-exception.html
@ -27,4 +27,6 @@ fn main() {
println!("pkgs2 - 1:{}", pkgs2.one().my_attr);
println!("pkgs2 - 2:{}", pkgs2.two().my_attr);
println!("pkgs2 - 3:{}", pkgs2.three().my_attr);
println!("pkgs1:\n{}", pkgs1.one());
}

View File

@ -131,15 +131,6 @@ pub trait Pkg: ::std::default::Default + ::core::fmt::Display {
self.check()?;
self.install()
}
fn package_code(&self) -> ::proc_macro2::TokenStream {
::quote::quote! {
self.prepare()?;
self.configure()?;
self.build()?;
self.check()?;
self.install()
}
}
}
#[derive(Default)]