diff --git a/flake.nix b/flake.nix index 8efe1a5..12fbd4b 100644 --- a/flake.nix +++ b/flake.nix @@ -158,7 +158,7 @@ overlays = [(import rust-overlay)]; }; - nightly = true; + nightly = false; rust = if nightly then pkgs.rust-bin.selectLatestNightlyWith (toolchain: toolchain.default) diff --git a/language_macros/src/command_enum_parsing/mod.rs b/language_macros/src/command_enum_parsing/mod.rs new file mode 100644 index 0000000..c64a5ed --- /dev/null +++ b/language_macros/src/command_enum_parsing/mod.rs @@ -0,0 +1,110 @@ +use syn::{braced, parse::Parse, punctuated::Punctuated, token, Attribute, Ident, Token, Type}; + +pub type NamespacePath = Punctuated; + +mod kw { + syn::custom_keyword!(commands); + syn::custom_keyword!(namespace); + syn::custom_keyword!(declare); +} + +#[derive(Debug)] +pub struct DataCommandEnum { + #[allow(dead_code)] + commands_token: kw::commands, + + #[allow(dead_code)] + brace_token: token::Brace, + + pub fields: Punctuated, +} + +#[derive(Debug)] +pub enum Field { + Function(FunctionDeclaration), + Namespace(Namespace), +} +#[derive(Debug)] +pub struct Namespace { + #[allow(dead_code)] + namespace_token: kw::namespace, + + pub path: NamespacePath, + + #[allow(dead_code)] + brace_token: token::Brace, + + pub fields: Punctuated, +} +#[derive(Debug)] +pub struct FunctionDeclaration { + #[allow(dead_code)] + function_token: kw::declare, + + pub name: Ident, + + #[allow(dead_code)] + colon_token: Token![:], + + pub ty: Type, +} + +impl Parse for DataCommandEnum { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let content; + Ok(DataCommandEnum { + commands_token: input.parse()?, + brace_token: braced!(content in input), + fields: content.parse_terminated(Field::parse, Token![,])?, + }) + } +} +impl Parse for Field { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let lookahead = input.lookahead1(); + if input.peek(Token![#]) { + // FIXME(@soispha): We ignore doc comments, which should probably be replaced by adding + // them to the output <2023-09-19> + let _output = input.call(Attribute::parse_outer).unwrap_or(vec![]); + let lookahead = input.lookahead1(); + + if lookahead.peek(kw::namespace) { + input.parse().map(Field::Namespace) + } else if lookahead.peek(kw::declare) { + input.parse().map(Field::Function) + } else { + Err(lookahead.error()) + } + } else { + if lookahead.peek(kw::declare) { + input.parse().map(Field::Function) + } else if lookahead.peek(kw::namespace) { + input.parse().map(Field::Namespace) + } else { + Err(lookahead.error()) + } + } + } +} + +impl Parse for FunctionDeclaration { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + Ok(FunctionDeclaration { + function_token: input.parse()?, + name: input.parse()?, + colon_token: input.parse()?, + ty: input.parse()?, + }) + } +} +impl Parse for Namespace { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let content; + Ok(Namespace { + namespace_token: input.parse()?, + path: NamespacePath::parse_separated_nonempty(input)?, + brace_token: braced!(content in input), + fields: content.parse_terminated(Field::parse, Token![,])?, + }) + } +} diff --git a/language_macros/src/generate/command_enum/mod.rs b/language_macros/src/generate/command_enum/mod.rs index fe51685..61f0b7b 100644 --- a/language_macros/src/generate/command_enum/mod.rs +++ b/language_macros/src/generate/command_enum/mod.rs @@ -1,9 +1,9 @@ use convert_case::{Case, Casing}; use proc_macro2::TokenStream as TokenStream2; use quote::{format_ident, quote, ToTokens}; -use syn::{punctuated::Punctuated, Token, Type, Ident}; +use syn::{punctuated::Punctuated, Ident, Token, Type}; -use crate::{DataCommandEnum, Field}; +use crate::{DataCommandEnum, command_enum_parsing::Field}; use super::get_input_type_of_bare_fn_field; @@ -71,12 +71,19 @@ fn turn_struct_field_to_enum(field: &Field) -> (TokenStream2, TokenStream2) { turn_fields_to_enum(&namespace.fields); let namespace_name: Ident = format_ident!( "{}", - namespace.path.iter().map(|name| name.to_string()).collect::() + namespace + .path + .iter() + .map(|name| name.to_string()) + .collect::() ); let new_namespace_name: Ident = format_ident!( "{}", - namespace_name.to_string().from_case(Case::Snake).to_case(Case::Pascal) + namespace_name + .to_string() + .from_case(Case::Snake) + .to_case(Case::Pascal) ); ( diff --git a/language_macros/src/generate/lua_wrapper/lua_functions_to_globals/mod.rs b/language_macros/src/generate/lua_wrapper/lua_functions_to_globals/mod.rs index a301e2e..124817a 100644 --- a/language_macros/src/generate/lua_wrapper/lua_functions_to_globals/mod.rs +++ b/language_macros/src/generate/lua_wrapper/lua_functions_to_globals/mod.rs @@ -2,7 +2,10 @@ use proc_macro2::TokenStream as TokenStream2; use quote::{format_ident, quote}; use syn::{punctuated::Punctuated, Token}; -use crate::{DataCommandEnum, Field, FunctionDeclaration, NamespacePath}; +use crate::{ + command_enum_parsing::{Field, NamespacePath, FunctionDeclaration}, + DataCommandEnum, +}; pub fn generate_add_lua_functions_to_globals(input: &DataCommandEnum) -> TokenStream2 { fn turn_field_to_functions( @@ -12,10 +15,8 @@ pub fn generate_add_lua_functions_to_globals(input: &DataCommandEnum) -> TokenSt input .iter() .map(|field| match field { - crate::Field::Function(function) => { - generate_function_adder(function, namespace_path) - } - crate::Field::Namespace(namespace) => { + Field::Function(function) => generate_function_adder(function, namespace_path), + Field::Namespace(namespace) => { let mut passed_namespace = namespace_path.unwrap_or(&Default::default()).clone(); namespace diff --git a/language_macros/src/generate/lua_wrapper/rust_wrapper_functions/mod.rs b/language_macros/src/generate/lua_wrapper/rust_wrapper_functions/mod.rs index 57f45c6..0f16dd5 100644 --- a/language_macros/src/generate/lua_wrapper/rust_wrapper_functions/mod.rs +++ b/language_macros/src/generate/lua_wrapper/rust_wrapper_functions/mod.rs @@ -5,7 +5,7 @@ use syn::{punctuated::Punctuated, token::Comma, GenericArgument, Lifetime, Token use crate::{ generate::{get_input_type_of_bare_fn_field, get_return_type_of_bare_fn_field}, - DataCommandEnum, Field, FunctionDeclaration, NamespacePath, + DataCommandEnum, command_enum_parsing::{NamespacePath, Field, FunctionDeclaration}, }; pub fn generate_rust_wrapper_functions( diff --git a/language_macros/src/generate/mod.rs b/language_macros/src/generate/mod.rs index 4bc329c..103b3f1 100644 --- a/language_macros/src/generate/mod.rs +++ b/language_macros/src/generate/mod.rs @@ -5,7 +5,7 @@ pub use command_enum::command_enum; pub use lua_wrapper::lua_wrapper; use syn::{ReturnType, Type, TypeBareFn}; -use crate::FunctionDeclaration; +use crate::command_enum_parsing::FunctionDeclaration; pub fn get_bare_fn_input_type(function: &TypeBareFn) -> Option { if function.inputs.len() == 1 { diff --git a/language_macros/src/lib.rs b/language_macros/src/lib.rs index 708cc6f..be1e4b3 100644 --- a/language_macros/src/lib.rs +++ b/language_macros/src/lib.rs @@ -1,12 +1,12 @@ +use command_enum_parsing::DataCommandEnum; use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use quote::quote; -use syn::{ - braced, parse::Parse, parse_macro_input, punctuated::Punctuated, token, Attribute, Ident, - Token, Type, -}; +use syn::parse_macro_input; + mod generate; +mod command_enum_parsing; /// This is the heart of the command api /// It mainly does two things: @@ -73,115 +73,6 @@ mod generate; /// }; /// } /// ``` -#[derive(Debug)] -struct DataCommandEnum { - #[allow(dead_code)] - commands_token: kw::commands, - - #[allow(dead_code)] - brace_token: token::Brace, - - fields: Punctuated, -} - -mod kw { - syn::custom_keyword!(commands); - syn::custom_keyword!(namespace); - syn::custom_keyword!(declare); -} - -#[derive(Debug)] -enum Field { - Function(FunctionDeclaration), - Namespace(Namespace), -} -#[derive(Debug)] -struct Namespace { - #[allow(dead_code)] - namespace_token: kw::namespace, - - path: NamespacePath, - - #[allow(dead_code)] - brace_token: token::Brace, - - fields: Punctuated, -} -type NamespacePath = Punctuated; - -#[derive(Debug)] -struct FunctionDeclaration { - #[allow(dead_code)] - function_token: kw::declare, - - name: Ident, - - #[allow(dead_code)] - colon_token: Token![:], - - ty: Type, -} - -impl Parse for DataCommandEnum { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let content; - Ok(DataCommandEnum { - commands_token: input.parse()?, - brace_token: braced!(content in input), - fields: content.parse_terminated(Field::parse, Token![,])?, - }) - } -} -impl Parse for Field { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let lookahead = input.lookahead1(); - if input.peek(Token![#]) { - // FIXME(@soispha): We ignore doc comments, which should probably be replaced by adding - // them to the output <2023-09-19> - let _output = input.call(Attribute::parse_outer).unwrap_or(vec![]); - let lookahead = input.lookahead1(); - - if lookahead.peek(kw::namespace) { - input.parse().map(Field::Namespace) - } else if lookahead.peek(kw::declare) { - input.parse().map(Field::Function) - } else { - Err(lookahead.error()) - } - } else { - if lookahead.peek(kw::declare) { - input.parse().map(Field::Function) - } else if lookahead.peek(kw::namespace) { - input.parse().map(Field::Namespace) - } else { - Err(lookahead.error()) - } - } - } -} - -impl Parse for FunctionDeclaration { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - Ok(FunctionDeclaration { - function_token: input.parse()?, - name: input.parse()?, - colon_token: input.parse()?, - ty: input.parse()?, - }) - } -} -impl Parse for Namespace { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let content; - Ok(Namespace { - namespace_token: input.parse()?, - path: NamespacePath::parse_separated_nonempty(input)?, - brace_token: braced!(content in input), - fields: content.parse_terminated(Field::parse, Token![,])?, - }) - } -} - #[proc_macro] pub fn parse_command_enum(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DataCommandEnum);