diff --git a/ecosystem/rust/cargo/src/parser/library.rs b/ecosystem/rust/cargo/src/parser/library.rs index 7071898b..5f286c2a 100644 --- a/ecosystem/rust/cargo/src/parser/library.rs +++ b/ecosystem/rust/cargo/src/parser/library.rs @@ -28,7 +28,7 @@ impl Parser<&std::path::Path> for LibraryParser { let library_path = directory.join(library.path.unwrap_or("src/lib.rs".into())); let identifier = Identifier::from(package.name.as_str()); - let mut root_module = ModuleParser.parse(library_path.as_path(), config)?; + let mut root_module = ModuleParser::new().parse(library_path.as_path(), config)?; root_module.identifier = identifier.clone(); let metadata = Default::default(); Ok(Self::Output { identifier, metadata, root_module }) diff --git a/ecosystem/rust/parser/src/function/method.rs b/ecosystem/rust/parser/src/function/method.rs index 03391dff..a9be18b1 100644 --- a/ecosystem/rust/parser/src/function/method.rs +++ b/ecosystem/rust/parser/src/function/method.rs @@ -10,41 +10,50 @@ use crate::macro_attributes::attributes::AttributeParser; use crate::types::TypeParser; use crate::visibility::VisibilityParser; +#[derive(Default)] pub struct MethodParser; +impl MethodParser { + pub fn new() -> Self { + Default::default() + } +} + impl Parser for MethodParser { type Output = Method; fn parse(&self, method: syn::ImplItemFn, config: &ParserConfig) -> Result { - let mutability = method.sig.receiver().map(|receiver| { - if receiver.mutability.is_some() { Mutability::Mutable } else { Mutability::Constant } - }).unwrap_or(Mutability::Constant); - let syn::Signature { asyncness, ident, inputs, output, .. } = method.sig; - let inputs: Vec = inputs - .clone() - .into_iter() - .filter(|input| matches!(input, syn::FnArg::Receiver(_))) - .map(|x| ParameterParser.parse(x, config).expect("Failed to convert Parameter")) - .collect(); - let output: Option = match output { - syn::ReturnType::Default => None, - syn::ReturnType::Type(_x, y) => { - Some(TypeParser::new().parse(*y, config)?) - } - }; - Ok(Self::Output { - mutability, - attributes: Attributes { - attributes: method - .attrs - .into_iter() - .map(|attribute| AttributeParser::default().parse(attribute, config).expect("Failed to parse meta.")) - .collect(), - }, - visibility: VisibilityParser.parse(method.vis, config)?, - synchrony: SynchronyParser.parse(asyncness, config)?, - identifier: IdentifierParser::new().parse(ident, config)?, - inputs, - output, - }) + if let Some(receiver) = method.sig.receiver() { + let mutability = if receiver.mutability.is_some() { Mutability::Mutable } else { Mutability::Constant }; + let syn::Signature { asyncness, ident, inputs, output, .. } = method.sig; + let inputs: Vec = inputs + .clone() + .into_iter() + .filter(|input| matches!(input, syn::FnArg::Receiver(_))) + .map(|x| ParameterParser.parse(x, config).expect("Failed to convert Parameter")) + .collect(); + let output: Option = match output { + syn::ReturnType::Default => None, + syn::ReturnType::Type(_x, y) => { + Some(TypeParser::new().parse(*y, config)?) + } + }; + Ok(Self::Output { + mutability, + attributes: Attributes { + attributes: method + .attrs + .into_iter() + .map(|attribute| AttributeParser::default().parse(attribute, config).expect("Failed to parse meta.")) + .collect(), + }, + visibility: VisibilityParser.parse(method.vis, config)?, + synchrony: SynchronyParser.parse(asyncness, config)?, + identifier: IdentifierParser::new().parse(ident, config)?, + inputs, + output, + }) + } else { + Err(Error::Message("Function is not a method.".to_string())) + } } } \ No newline at end of file diff --git a/ecosystem/rust/parser/src/function/mod.rs b/ecosystem/rust/parser/src/function/mod.rs index e2d9f8a4..fc24d55f 100644 --- a/ecosystem/rust/parser/src/function/mod.rs +++ b/ecosystem/rust/parser/src/function/mod.rs @@ -18,6 +18,12 @@ use crate::visibility::VisibilityParser; #[derive(Default)] pub struct FunctionParser; +impl FunctionParser { + pub fn new() -> Self { + Default::default() + } +} + impl Parser for FunctionParser { type Output = Function; fn parse(&self, item_fn: syn::ItemFn, config: &ParserConfig) -> Result { @@ -33,14 +39,18 @@ impl Parser for FunctionParser { impl Parser for FunctionParser { type Output = Function; - fn parse(&self, method: syn::ImplItemFn, config: &ParserConfig) -> Result { - let attributes = AttributesParser::default().parse(method.attrs, config)?; - let visibility = VisibilityParser.parse(method.vis, config)?; - let synchrony = SynchronyParser.parse(method.sig.asyncness, config)?; - let identifier = IdentifierParser::new().parse(method.sig.ident, config)?; - let inputs = self.parse_inputs(method.sig.inputs, config)?; - let output = self.parse_output(method.sig.output, config)?; - Ok(Self::Output { attributes, visibility, synchrony, identifier, inputs, output }) + fn parse(&self, function: syn::ImplItemFn, config: &ParserConfig) -> Result { + if function.sig.receiver().is_some() { + Err(Error::Message("Function is not a method.".to_string())) + } else { + let attributes = AttributesParser::default().parse(function.attrs, config)?; + let visibility = VisibilityParser.parse(function.vis, config)?; + let synchrony = SynchronyParser.parse(function.sig.asyncness, config)?; + let identifier = IdentifierParser::new().parse(function.sig.ident, config)?; + let inputs = self.parse_inputs(function.sig.inputs, config)?; + let output = self.parse_output(function.sig.output, config)?; + Ok(Self::Output { attributes, visibility, synchrony, identifier, inputs, output }) + } } } diff --git a/ecosystem/rust/parser/src/interface/mod.rs b/ecosystem/rust/parser/src/interface/mod.rs new file mode 100644 index 00000000..8aaed578 --- /dev/null +++ b/ecosystem/rust/parser/src/interface/mod.rs @@ -0,0 +1,76 @@ +use crate::function::{FunctionParser, MethodParser}; +use crate::macro_attributes::attributes::AttributesParser; +use crate::object::ObjectParser; +use crate::prelude::*; +use crate::types::TypeParser; + +use ligen::parser::{Parser, ParserConfig}; +use ligen::ir::{Path, Interface, Visibility, Function, Method, Object}; + + +#[derive(Default)] +pub struct InterfaceParser {} + +impl InterfaceParser { + pub fn new() -> Self { + Default::default() + } +} + +impl Parser for InterfaceParser { + type Output = Interface; + fn parse(&self, input: syn::ItemImpl, config: &ParserConfig) -> Result { + let attributes = AttributesParser::default().parse(input.attrs, config)?; + let visibility = Visibility::Public; + + // TODO: What should we do with the self type? + let type_ = TypeParser::new().parse(*input.self_ty, config)?; + let identifier = type_.path.last().clone().into(); // TODO: Fix this + + let functions = self.extract_functions(input.items.as_slice(), config)?; + let methods = self.extract_methods(input.items.as_slice(), config)?; + let objects = self.extract_objects(input.items.as_slice(), config)?; + let interfaces = self.extract_interfaces(input.items.as_slice(), config)?; + Ok(Interface { attributes, visibility, identifier, methods, objects, functions, interfaces }) + } +} + +impl InterfaceParser { + fn extract_interfaces(&self, _items: &[syn::ImplItem], _config: &ParserConfig) -> Result> { + Ok(Default::default()) + } + + fn extract_methods(&self, items: &[syn::ImplItem], config: &ParserConfig) -> Result> { + let mut methods = Vec::new(); + for item in items { + if let syn::ImplItem::Fn(method) = item { + if let Ok(method) = MethodParser::new().parse(method.clone(), config) { + methods.push(method); + } + } + } + Ok(methods) + } + + fn extract_objects(&self, items: &[syn::ImplItem], config: &ParserConfig) -> Result> { + let mut objects = Vec::new(); + for item in items { + if let syn::ImplItem::Const(object) = item { + objects.push(ObjectParser::new().parse(object.clone(), config)?); + } + } + Ok(objects) + } + + fn extract_functions(&self, items: &[syn::ImplItem], config: &ParserConfig) -> Result> { + let mut functions = Vec::new(); + for item in items { + if let syn::ImplItem::Fn(function) = item { + if let Ok(function) = FunctionParser::new().parse(function.clone(), config) { + functions.push(function); + } + } + } + Ok(functions) + } +} \ No newline at end of file diff --git a/ecosystem/rust/parser/src/lib.rs b/ecosystem/rust/parser/src/lib.rs index 267a0fd0..848f5118 100644 --- a/ecosystem/rust/parser/src/lib.rs +++ b/ecosystem/rust/parser/src/lib.rs @@ -10,6 +10,7 @@ pub mod literal; pub mod identifier; pub mod module; pub mod object; +pub mod interface; pub mod parser; diff --git a/ecosystem/rust/parser/src/module/import.rs b/ecosystem/rust/parser/src/module/import.rs index 28911e44..1c511da9 100644 --- a/ecosystem/rust/parser/src/module/import.rs +++ b/ecosystem/rust/parser/src/module/import.rs @@ -15,13 +15,18 @@ struct ImportsBuilder { pub tree: syn::UseTree } -pub struct ImportsParser; +#[derive(Default)] +pub struct ImportsParser { + attributes_parser: AttributesParser, + visibility_parser: VisibilityParser +} + impl Parser for ImportsParser { type Output = Vec; fn parse(&self, import: syn::ItemUse, config: &ParserConfig) -> Result { - let attributes = AttributesParser::default().parse(import.attrs, config)?; - let visibility = VisibilityParser.parse(import.vis, config)?; + let attributes = self.attributes_parser.parse(import.attrs, config)?; + let visibility = self.visibility_parser.parse(import.vis, config)?; let path = Path::default(); let tree = import.tree; self.parse(ImportsBuilder { attributes, visibility, path, tree }, config) @@ -103,7 +108,7 @@ mod tests { #[test] fn import() -> Result<()> { - assert_eq(ImportsParser, mock::import(), quote! { + assert_eq(ImportsParser::default(), mock::import(), quote! { #[custom(attribute)] pub use std::collections::HashMap; }) @@ -111,7 +116,7 @@ mod tests { #[test] fn glob_import() -> Result<()> { - assert_eq(ImportsParser, mock::glob_import(), quote! { + assert_eq(ImportsParser::default(), mock::glob_import(), quote! { #[custom(attribute)] pub use std::collections::*; }) @@ -119,7 +124,7 @@ mod tests { #[test] fn renamed_import() -> Result<()> { - assert_eq(ImportsParser, mock::renamed_import(), quote !{ + assert_eq(ImportsParser::default(), mock::renamed_import(), quote !{ #[custom(attribute)] pub use std::collections::HashMap as Map; }) @@ -127,7 +132,7 @@ mod tests { #[test] fn group_import() -> Result<()> { - assert_eq(ImportsParser, mock::group_import(), quote! { + assert_eq(ImportsParser::default(), mock::group_import(), quote! { #[custom(attribute)] pub use std::{ collections::{ diff --git a/ecosystem/rust/parser/src/module/mod.rs b/ecosystem/rust/parser/src/module/mod.rs index 2f2e4c79..b4ded418 100644 --- a/ecosystem/rust/parser/src/module/mod.rs +++ b/ecosystem/rust/parser/src/module/mod.rs @@ -5,6 +5,7 @@ mod import; use syn::spanned::Spanned; use ligen::ir::Object; use ligen::parser::{Parser, ParserConfig}; +use crate::interface::InterfaceParser; use crate::prelude::*; use crate::types::type_alias::TypeAliasParser; use ligen::ir::{Function, Module, Import, TypeDefinition, Interface}; @@ -17,7 +18,34 @@ use crate::types::enumeration::EnumerationParser; use crate::types::structure::StructureParser; use crate::visibility::VisibilityParser; -pub struct ModuleParser; +#[derive(Default)] +pub struct ModuleParser { + interface_parser: InterfaceParser, + object_parser: ObjectParser, + visibility_parser: VisibilityParser, + function_parser: FunctionParser, + identifier_parser: IdentifierParser, + attributes_parser: AttributesParser, + type_alias_parser: TypeAliasParser, + enumeration_parser: EnumerationParser, + structure_parser: StructureParser, + imports_parser: ImportsParser, +} + +impl ModuleParser { + pub fn new() -> Self { + Default::default() + } +} + +impl Parser<&str> for ModuleParser { + type Output = Module; + fn parse(&self, input: &str, config: &ParserConfig) -> Result { + syn::parse_str::(input) + .map_err(|e| Error::Message(format!("Failed to parse module: {:?}", e))) + .and_then(|module| self.parse(module, config)) + } +} impl Parser for ModuleParser { type Output = Module; @@ -35,9 +63,9 @@ impl Parser for ModuleParser { .content .map(|(_, items)| items) .ok_or("Module file isn't loaded.")?; - let attributes = AttributesParser::default().parse(module.attrs, config)?; - let visibility = VisibilityParser.parse(module.vis, config)?; - let identifier = IdentifierParser::new().parse(module.ident, config)?; + let attributes = self.attributes_parser.parse(module.attrs, config)?; + let visibility = self.visibility_parser.parse(module.vis, config)?; + let identifier = self.identifier_parser.parse(module.ident, config)?; let imports = self.extract_imports(items.as_slice(), config)?; let functions = self.extract_functions(items.as_slice(), config)?; @@ -67,19 +95,27 @@ impl Parser<&std::path::Path> for ModuleParser { } impl ModuleParser { - fn extract_interfaces(&self, _items: &[syn::Item]) -> Result> { - Ok(Default::default()) + fn extract_interfaces(&self, items: &[syn::Item]) -> Result> { + let mut interfaces = Vec::new(); + for item in items { + if let syn::Item::Impl(impl_) = item { + if let Ok(interface) = self.interface_parser.parse(impl_.clone(), &ParserConfig::default()) { + interfaces.push(interface); + } + } + } + Ok(interfaces) } fn extract_types(&self, items: &[syn::Item], config: &ParserConfig) -> Result> { let mut types = Vec::new(); for item in items { match item { syn::Item::Enum(enumeration) => - types.push(EnumerationParser::new().parse(enumeration.clone(), config)?), + types.push(self.enumeration_parser.parse(enumeration.clone(), config)?), syn::Item::Struct(structure) => - types.push(StructureParser::new().parse(structure.clone(), config)?), + types.push(self.structure_parser.parse(structure.clone(), config)?), syn::Item::Type(type_) => { - types.push(TypeAliasParser::new().parse(type_.clone(), config)?); + types.push(self.type_alias_parser.parse(type_.clone(), config)?); }, syn::Item::Union(_union) => { todo!("Union object isn't implemented yet.") @@ -94,7 +130,7 @@ impl ModuleParser { let mut imports: Vec = Default::default(); for item in items { if let syn::Item::Use(import) = item { - imports.append(&mut ImportsParser.parse(import.clone(), config)?); + imports.append(&mut self.imports_parser.parse(import.clone(), config)?); } } Ok(imports) @@ -103,7 +139,7 @@ impl ModuleParser { let mut functions = Vec::new(); for item in items { if let syn::Item::Fn(function) = item { - functions.push(FunctionParser.parse(function.clone(), config)?); + functions.push(self.function_parser.parse(function.clone(), config)?); } } Ok(functions) @@ -130,7 +166,7 @@ impl ModuleParser { let mut objects = Vec::new(); for item in items { if let syn::Item::Const(constant) = item { - objects.push(ObjectParser.parse(constant.clone(), config)?); + objects.push(self.object_parser.parse(constant.clone(), config)?); } } Ok(objects) @@ -148,12 +184,12 @@ mod tests { #[test] fn module_file() -> Result<()> { - assert_failure(ModuleParser, quote! { mod module; }) + assert_failure(ModuleParser::default(), "mod module;") } #[test] fn sub_modules() -> Result<()> { - assert_eq(ModuleParser, mock::sub_modules(), quote! { + assert_eq(ModuleParser::default(), mock::sub_modules(), quote! { pub mod root { pub mod branch { pub mod leaf {} @@ -164,7 +200,7 @@ mod tests { #[test] fn module_types() -> Result<()> { - assert_eq(ModuleParser, mock::module_types(), quote! { + assert_eq(ModuleParser::default(), mock::module_types(), quote! { pub mod types { pub struct Structure; pub enum Enumeration {} diff --git a/ecosystem/rust/parser/src/object.rs b/ecosystem/rust/parser/src/object.rs index 58bb101c..49b97883 100644 --- a/ecosystem/rust/parser/src/object.rs +++ b/ecosystem/rust/parser/src/object.rs @@ -5,8 +5,15 @@ use crate::literal::LiteralParser; use crate::prelude::*; use crate::types::TypeParser; +#[derive(Default)] pub struct ObjectParser; +impl ObjectParser { + pub fn new() -> Self { + Default::default() + } +} + impl Parser for ObjectParser { type Output = Object; fn parse(&self, item_const: syn::ImplItemConst, config: &ParserConfig) -> Result { diff --git a/ecosystem/rust/parser/src/types/type_.rs b/ecosystem/rust/parser/src/types/type_.rs index 10046cc5..8a9992f5 100644 --- a/ecosystem/rust/parser/src/types/type_.rs +++ b/ecosystem/rust/parser/src/types/type_.rs @@ -1,4 +1,5 @@ use ligen::{ir::Type, parser::ParserConfig}; +use quote::ToTokens; use syn::{TypeArray, TypeSlice}; use crate::{literal::LiteralParser, mutability::MutabilityParser, prelude::*}; use ligen::parser::Parser; @@ -59,7 +60,7 @@ impl Parser for TypeParser { } else { match syn_type { syn::Type::Reference(syn::TypeReference { elem, mutability, .. }) | - syn::Type::Ptr(syn::TypePtr { elem, mutability, .. }) => { + syn::Type::Ptr(syn::TypePtr { elem, mutability, .. }) => { let mutability = self.mutability_parser.parse(mutability, config)?; let type_ = TypeParser::new().parse(*elem, config)?; Ok(Type::reference(mutability, type_)) @@ -74,7 +75,7 @@ impl Parser for TypeParser { let type_ = TypeParser::new().parse(*elem, config)?; Ok(Type::array(type_, len)) }, - _ => Err(Error::Message("Only Path, Reference and Ptr Types are currently supported".into())), + _ => Err(Error::Message(format!("\"{}\" not supported. Only Path, Reference and Ptr Types are currently supported", syn_type.to_token_stream()))), } } } diff --git a/ecosystem/rust/parser/tests/lib.rs b/ecosystem/rust/parser/tests/lib.rs index d877d100..f1a606ab 100644 --- a/ecosystem/rust/parser/tests/lib.rs +++ b/ecosystem/rust/parser/tests/lib.rs @@ -32,5 +32,5 @@ pub fn module_file() { }; let project_root = project_root::get_project_root().expect("Failed to get library root."); let path = project_root.join(file!()); - assert_eq(ModuleParser, module, path.as_path()).unwrap() + assert_eq(ModuleParser::default(), module, path.as_path()).unwrap() } \ No newline at end of file