Skip to content

Commit

Permalink
Rust interface parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
notdanilo committed Sep 1, 2024
1 parent 105098c commit 6f26491
Show file tree
Hide file tree
Showing 10 changed files with 210 additions and 65 deletions.
2 changes: 1 addition & 1 deletion ecosystem/rust/cargo/src/parser/library.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
Expand Down
71 changes: 40 additions & 31 deletions ecosystem/rust/parser/src/function/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<syn::ImplItemFn> for MethodParser {
type Output = Method;
fn parse(&self, method: syn::ImplItemFn, config: &ParserConfig) -> Result<Self::Output> {
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<Parameter> = 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<Type> = 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<Parameter> = 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<Type> = 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()))
}
}
}
26 changes: 18 additions & 8 deletions ecosystem/rust/parser/src/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ use crate::visibility::VisibilityParser;
#[derive(Default)]
pub struct FunctionParser;

impl FunctionParser {
pub fn new() -> Self {
Default::default()
}
}

impl Parser<syn::ItemFn> for FunctionParser {
type Output = Function;
fn parse(&self, item_fn: syn::ItemFn, config: &ParserConfig) -> Result<Self::Output> {
Expand All @@ -33,14 +39,18 @@ impl Parser<syn::ItemFn> for FunctionParser {

impl Parser<syn::ImplItemFn> for FunctionParser {
type Output = Function;
fn parse(&self, method: syn::ImplItemFn, config: &ParserConfig) -> Result<Self::Output> {
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<Self::Output> {
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 })
}
}
}

Expand Down
76 changes: 76 additions & 0 deletions ecosystem/rust/parser/src/interface/mod.rs
Original file line number Diff line number Diff line change
@@ -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<syn::ItemImpl> for InterfaceParser {
type Output = Interface;
fn parse(&self, input: syn::ItemImpl, config: &ParserConfig) -> Result<Self::Output> {
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<Vec<Path>> {
Ok(Default::default())
}

fn extract_methods(&self, items: &[syn::ImplItem], config: &ParserConfig) -> Result<Vec<Method>> {
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<Vec<Object>> {
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<Vec<Function>> {
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)
}
}
1 change: 1 addition & 0 deletions ecosystem/rust/parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod literal;
pub mod identifier;
pub mod module;
pub mod object;
pub mod interface;

pub mod parser;

Expand Down
19 changes: 12 additions & 7 deletions ecosystem/rust/parser/src/module/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<syn::ItemUse> for ImportsParser {
type Output = Vec<Import>;
fn parse(&self, import: syn::ItemUse, config: &ParserConfig) -> Result<Self::Output> {
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)
Expand Down Expand Up @@ -103,31 +108,31 @@ 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;
})
}

#[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::*;
})
}

#[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;
})
}

#[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::{
Expand Down
Loading

0 comments on commit 6f26491

Please sign in to comment.