/* * Copyright 2024 Luca Fulchir * * 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 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #![feature(proc_macro_span)] use ::proc_macro::TokenStream; mod collection; mod pkgs; mod repos; // // ####### Repository stuff ########## // /// Use as #[::bok::repository(MyBaseRepo)] /// Will setup a `base` field that is the given base repo /// and add `#[derive(::bok::Repository)]` /// /// e.g.: `#[::bok::repository(::bok::RepositoryEmpty)]` #[::macro_magic::import_tokens_attr] //#[with_custom_parsing(repos::BaseSet)] #[proc_macro_attribute] pub fn repository(attrs: TokenStream, input: TokenStream) -> TokenStream { crate::repos::repository(attrs, input) } /// Unless you know what you are doing, use `#[::bok::repository(MyBaseRepo)]` /// instead needs a `.base` field /// /// Use like: /// ``` /// #[derive(::bok::Repository)] /// pub struct MyRepo { /// base : BaseRepo, /// } /// ``` /// adds extension capabilities to a repo #[proc_macro_derive(Repository)] pub fn derive_repository(input: TokenStream) -> TokenStream { crate::repos::derive_repository(input) } /// Add multiple packages to a repo /// Usage: /// ``` /// #[::bok::repo_packages(Mypkg1, Mypkg2)] /// struct MyRepo{} /// ``` #[proc_macro_attribute] pub fn repo_packages(attrs: TokenStream, input: TokenStream) -> TokenStream { crate::repos::repo_packages(attrs, input) } /// Create the methods that will return the builders and packages /// /// will actually merely rewrite the macro to get the actual Repo name /// in `#[::bok_macro::repo_impl_methods(MyRepo)]` /// /// Usage: /// ``` /// #[::bok::repo_impl] /// impl MyRepo{} /// ``` //#[::macro_magic::import_tokens_attr] #[proc_macro_attribute] pub fn repo_impl(attrs: TokenStream, input: TokenStream) -> TokenStream { crate::repos::repo_impl(attrs, input) } /// **Internal. Do not use unless you know what you are doing** /// Create the methods that will return the builders and packages /// Usage: /// ``` /// #[::bok_macro::repo_impl_methods(MyRepo)] /// impl MyRepo{} /// ``` #[::macro_magic::import_tokens_attr] #[proc_macro_attribute] pub fn repo_impl_methods( attrs: TokenStream, input: TokenStream, ) -> TokenStream { crate::repos::repo_impl_methods(attrs, input, __source_path) } /// **Internal. Do not use unless you know what you are doing** /// given a Repository and a trait "BokDeps...", /// implement all the fn returning the dependencies needed by the package /// /// Usage: /// ``` /// #[::bok_macro::repo_impl_(MyRepo)] /// impl MyRepo{} /// ``` #[::macro_magic::import_tokens_attr] #[proc_macro_attribute] pub fn repo_impl_pkg_deps( attrs: TokenStream, input: TokenStream, ) -> TokenStream { crate::repos::repo_impl_pkg_deps(attrs, input) } /// **Internal** /// /// add implementation of a collection #[proc_macro_attribute] pub fn collection(attrs: TokenStream, input: TokenStream) -> TokenStream { crate::collection::collection(attrs, input) } /// **Internal** /// /// add implementation of a `BokBuilderDeps` trait #[::macro_magic::import_tokens_attr] #[proc_macro_attribute] pub fn collection_dep(attrs: TokenStream, input: TokenStream) -> TokenStream { crate::collection::collection_dep(attrs, input, __source_path) } // // ####### Package stuff ########## // /// Use on a function as `#[::bok::pkg_fn_to_code]` /// will create a new function, same name with `_code` that /// returns the ::proc_macro2::TokenStream of the function /// /// **Don't use this if you are using `#[::bok::package(...)]` /// it is already automatically added to all members of trait `::bok::Pkg`** /// /// e.g.: /// ``` /// impl MyPackage { /// #[::bok::pkg_fn_to_code] /// fn build() { /// ... /// } /// } /// let p = MyPackage::default(); /// let tokens : ::proc_macro2::TokenStream = p.build_code() /// ``` #[proc_macro_attribute] pub fn pkg_fn_to_code(attrs: TokenStream, input: TokenStream) -> TokenStream { crate::pkgs::pkg_fn_to_code(attrs, input) } /// Use as #[::bok::package(MyBasePackage)] /// Will setup a `base` field that is the given base package /// and add `#[derive(::bok::Package)]` /// /// e.g.: /// ``` /// #[::bok::package(::bok::PkgEmpty)] /// pub struct MyPkg {} /// ``` #[proc_macro_attribute] pub fn package(attrs: TokenStream, input: TokenStream) -> TokenStream { crate::pkgs::package(attrs, input) } /// **Internal**. try not to use /// Use as #[::bok::package(MyBasePackage)] /// Will setup a `base` field that is the given base package /// and add `#[derive(::bok::Package)]` /// needs generics /// /// e.g.: /// ``` /// #[::bok::package_path(::base::pkg)] /// pub struct MyPkg {} /// ``` #[::macro_magic::import_tokens_attr] #[proc_macro_attribute] pub fn package_path(attrs: TokenStream, input: TokenStream) -> TokenStream { crate::pkgs::package_path(attrs, input, __source_path) } /// Specify one or more dependencies /// /// e.g: /// ``` /// #[::bok::package(::bok::PkgEmpty)] /// #[::bok::deps(some::Package, other::Package)] /// pub struct MyPkg {} /// ``` #[proc_macro_attribute] pub fn deps(attrs: TokenStream, input: TokenStream) -> TokenStream { crate::pkgs::deps(attrs, input) } /* /// attribute for package optional feature fields /// marks a struct field as a package option /// the PkgBuilder will create apposite get/set and traits for the options /// /// e.g: /// ``` /// #[::bok::package(::bok::PkgEmpty)] /// pub struct MyPkg { /// #[::bok::option] /// with_ssl: bool, /// } /// ``` #[proc_macro_attribute] pub fn option(attrs: TokenStream, input: TokenStream) -> TokenStream { crate::pkgs::option(attrs, input) } */ /// Use as #[::bok::package_impl] /// adds the right generics to the package. /// /// extra calls and changes are added to `::bok::Pkg` and ::std::Default traits /// /// e.g.: /// ``` /// #[::bok::package_impl] /// impl Default for Mypackage { /// fn default() -> Self { ... } /// } /// #[::bok::package_impl] /// impl ::bok::Pkg for MyPackage { /// fn build(&self) -> Result<(),()> { /// ... /// } /// } /// ``` #[proc_macro_attribute] pub fn package_impl(attrs: TokenStream, input: TokenStream) -> TokenStream { crate::pkgs::package_impl(attrs, input) } /// ** Internal, don't use unless you know what you are doing.** /// Use as #[::bok::package_impl_base(::my::Package)] /// implements common ::bok::Pkg methods and takes the package methods /// not implemented by the user from the base package /// /// does not export symbols. /// /// should be called with the same path as the package that implements /// ::bok::Pkg /// /// will rewrite itself with the exported impl path of the base package /// so that macro_magic can import the base impl /// /// e.g.: /// ``` /// #[::bok::package_impl_base(MyPackage)] /// #[::macro_magic::export_tokens(_bok_pkg_mypackage)] /// impl ::bok::Pkg for MyPackage { /// fn build(&self) -> Result<(),()> { /// ... /// } /// } /// ``` #[::macro_magic::import_tokens_attr] #[proc_macro_attribute] pub fn package_impl_base( attrs: TokenStream, input: TokenStream, ) -> TokenStream { crate::pkgs::package_impl_base(attrs, input) } /// ** Internal, don't use unless you know what you are doing.** /// Use as #[::bok::package_impl_builder(::my::Package)] /// implements common ::bok::PkgBuilder methods and takes /// the package methods not implemented by the user from the base package /// /// does not export symbols. /// /// should be called with the same path as the package that implements /// ::bok::Pkg /// /// will rewrite itself with the exported impl path of the base package /// so that macro_magic can import the base impl /// /// e.g.: /// ``` /// #[::bok::package_impl_builder(MyPackage)] /// #[::macro_magic::export_tokens(_bok_pkgbuilder_mypackage)] /// impl ::bok::PkgBuilder for MyPackage { /// fn set_dependencies(&self, ...) -> Result<(),()> { /// ... /// } /// } /// ``` #[::macro_magic::import_tokens_attr] #[proc_macro_attribute] pub fn package_impl_builder( attrs: TokenStream, input: TokenStream, ) -> TokenStream { crate::pkgs::package_impl_builder(attrs, input, __source_path) } /// Unless you know what you are doing, use `#[::bok::package(MyBasePackage)]` /// instead needs a `.base` field /// /// ``` /// #[derive(::bok::Package)] /// pub struct MyPkg { /// base: OtherPkg /// } /// ``` /// adds: /// * Builder pattern to a package /// * getters/setters for all package fields /// * deref for package #[proc_macro_derive(Package, attributes(option))] pub fn derive_package(input: TokenStream) -> TokenStream { crate::pkgs::derive_package(input) } // ==== Common package stuff ==== pub(crate) struct PathList(Vec<::syn::Path>); impl ::syn::parse::Parse for PathList { fn parse(input: ::syn::parse::ParseStream) -> syn::Result { use ::syn::punctuated::Punctuated; let raw = Punctuated::<::syn::Path, ::syn::Token![,]>::parse_terminated( input, )?; let mut result = Vec::with_capacity(raw.len()); for r in raw.into_iter() { result.push(r) } Ok(PathList(result)) } }