diff --git a/Cargo.toml b/Cargo.toml index 9c198fed..102c6904 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,7 +56,7 @@ shrinkwraprs = "0.3" derive_more = "0.99" lazy_static = "1.4.0" pretty_assertions = "1.4.0" -syn = { version = "1.0.73", features = [ "full" ] } +syn = { version = "2.0.76", features = [ "full" ] } regex = "1" # If you want to use the bleeding edge version of egui and eframe: diff --git a/ecosystem/rust/parser/src/function/method.rs b/ecosystem/rust/parser/src/function/method.rs index 5f0efca5..03391dff 100644 --- a/ecosystem/rust/parser/src/function/method.rs +++ b/ecosystem/rust/parser/src/function/method.rs @@ -12,22 +12,13 @@ use crate::visibility::VisibilityParser; pub struct MethodParser; -impl Parser for MethodParser { +impl Parser for MethodParser { type Output = Method; - fn parse(&self, method: syn::ImplItemMethod, config: &ParserConfig) -> Result { - let mutability = method.sig.receiver().map(|arg| { - match arg { - syn::FnArg::Receiver(receiver) => if receiver.mutability.is_some() { Mutability::Mutable } else { Mutability::Constant }, - syn::FnArg::Typed(_pat) => Mutability::Constant // FIXME: This needs better treatment. - } + 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 syn::Signature { asyncness, ident, inputs, output, .. } = method.sig; let inputs: Vec = inputs .clone() .into_iter() diff --git a/ecosystem/rust/parser/src/function/mod.rs b/ecosystem/rust/parser/src/function/mod.rs index fe15c130..e2d9f8a4 100644 --- a/ecosystem/rust/parser/src/function/mod.rs +++ b/ecosystem/rust/parser/src/function/mod.rs @@ -31,9 +31,9 @@ impl Parser for FunctionParser { } } -impl Parser for FunctionParser { +impl Parser for FunctionParser { type Output = Function; - fn parse(&self, method: syn::ImplItemMethod, config: &ParserConfig) -> Result { + 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)?; diff --git a/ecosystem/rust/parser/src/literal.rs b/ecosystem/rust/parser/src/literal.rs index df6c43d9..86dea8d5 100644 --- a/ecosystem/rust/parser/src/literal.rs +++ b/ecosystem/rust/parser/src/literal.rs @@ -19,6 +19,8 @@ impl Parser for LiteralParser { syn::Lit::Int(litint) => Self::Output::Integer(litint.base10_parse().unwrap()), syn::Lit::Float(litfloat) => Self::Output::Float(litfloat.base10_parse().unwrap()), syn::Lit::Bool(litbool) => Self::Output::Boolean(litbool.value), + syn::Lit::CStr(litcstr) => Self::Output::String(litcstr.value().to_str().unwrap().to_string()), + _ => return Err(Error::Message("Failed to parse literal".into())), }) } } @@ -73,9 +75,11 @@ impl Parser for LiteralParser { impl Parser<&str> for LiteralParser { type Output = Literal; fn parse(&self, input: &str, config: &ParserConfig) -> Result { - syn::parse_str::(input) - .map_err(|e| Error::Message(format!("Failed to parse literal: {:?}", e))) - .and_then(|literal| self.parse(literal, config)) + if let Ok(lit) = syn::parse_str::(input) { + Ok(self.parse(lit, config)?) + } else { + Ok(Literal::Unknown(input.to_string())) + } } } @@ -125,4 +129,9 @@ mod test { fn literal_float() -> Result<()> { assert_eq(LiteralParser, mock::literal_float(), "3.5") } + + #[test] + fn literal_unknown() -> Result<()> { + assert_eq(LiteralParser, mock::literal_unknown(), ".0") // FIXME: This is actually an expression. + } } diff --git a/ecosystem/rust/parser/src/module/mod.rs b/ecosystem/rust/parser/src/module/mod.rs index 9e56b6c4..7a557196 100644 --- a/ecosystem/rust/parser/src/module/mod.rs +++ b/ecosystem/rust/parser/src/module/mod.rs @@ -58,8 +58,9 @@ impl Parser<&std::path::Path> for ModuleParser { let semi = Default::default(); let mod_token = Default::default(); let content = Some((Default::default(), module.items)); - let vis = syn::Visibility::Public(syn::VisPublic { pub_token }); - let module = syn::ItemMod { attrs, vis, mod_token, ident, semi, content }; + let vis = syn::Visibility::Public(pub_token); + let unsafety = Default::default(); + let module = syn::ItemMod { unsafety, attrs, vis, mod_token, ident, semi, content }; self.parse(module, config) } } diff --git a/ecosystem/rust/parser/src/path.rs b/ecosystem/rust/parser/src/path.rs index b2fa0c5f..060c1316 100644 --- a/ecosystem/rust/parser/src/path.rs +++ b/ecosystem/rust/parser/src/path.rs @@ -19,7 +19,7 @@ impl Parser for PathParser { .segments .iter() // FIXME: This isn't parsing generics, just the identifiers. - .map(|segment| IdentifierParser::new().parse(segment.ident.clone(), config).expect("Failed to parse segment.")) + .map(|segment| IdentifierParser::new().parse(segment.ident.clone(), config).expect("Failed to parse segment.")) // FIXME: Remove this expect. .map(PathSegment::from) .collect(); Ok(Self::Output { segments }) @@ -34,6 +34,15 @@ impl Parser for PathParser { } } +impl Parser<&str> for PathParser { + type Output = Path; + fn parse(&self, input: &str, config: &ParserConfig) -> Result { + syn::parse_str::(input) + .map_err(|e| Error::Message(format!("Failed to parse path: {:?}", e))) + .and_then(|path| self.parse(path, config)) + } +} + impl Parser for PathParser { type Output = Path; fn parse(&self, input: proc_macro::TokenStream, config: &ParserConfig) -> Result { @@ -60,15 +69,11 @@ mod test { #[test] fn identifier_as_path() -> Result<()> { - assert_eq(PathParser::default(), mock::identifier_as_path(), quote! { - u8 - }) + assert_eq(PathParser::default(), mock::identifier_as_path(), "u8") } #[test] fn path() -> Result<()> { - assert_eq(PathParser::default(), mock::path(), quote! { - std::convert::TryFrom - }) + assert_eq(PathParser::default(), mock::path(), "std::convert::TryFrom") } } \ No newline at end of file diff --git a/ecosystem/rust/parser/src/types/type_definition/enumeration/variant.rs b/ecosystem/rust/parser/src/types/type_definition/enumeration/variant.rs index 002f5c38..4aad7f8e 100644 --- a/ecosystem/rust/parser/src/types/type_definition/enumeration/variant.rs +++ b/ecosystem/rust/parser/src/types/type_definition/enumeration/variant.rs @@ -30,19 +30,18 @@ impl Parser> for Va #[cfg(test)] mod tests { - use quote::quote; - use syn::parse_quote::parse; + use syn::parse_quote; use ligen::ir::Variant; use ligen::parser::Parser; use crate::types::type_definition::enumeration::variant::VariantParser; #[test] fn parameter_primitive() { - let enumeration = parse::(quote! { + let enumeration: syn::ItemEnum = parse_quote! { enum Enumeration { Integer } - }); + }; let variant = enumeration.variants.into_iter().next().expect("Couldn't get field."); assert_eq!( VariantParser.parse(variant, &Default::default()).expect("Failed to convert field."), diff --git a/ecosystem/rust/parser/src/types/type_definition/structure/field.rs b/ecosystem/rust/parser/src/types/type_definition/structure/field.rs index 05294906..2a8dbda8 100644 --- a/ecosystem/rust/parser/src/types/type_definition/structure/field.rs +++ b/ecosystem/rust/parser/src/types/type_definition/structure/field.rs @@ -34,18 +34,18 @@ impl Parser for FieldParser { #[cfg(test)] mod tests { - use syn::parse_quote::parse; + use syn::parse_quote; use ligen::ir::{Field, Visibility, Path}; use crate::types::structure::FieldParser; use crate::prelude::*; #[test] fn field() -> Result<()> { - let structure = parse::(quote! { + let structure: syn::ItemStruct = parse_quote! { struct Structure { instant: std::time::Instant } - }); + }; let field = structure.fields.into_iter().next().expect("Couldn't get field."); assert_eq!( FieldParser.parse(field, &Default::default())?, diff --git a/ligen/ir/src/literal/mock.rs b/ligen/ir/src/literal/mock.rs index 2a11dbb9..ef5a2398 100644 --- a/ligen/ir/src/literal/mock.rs +++ b/ligen/ir/src/literal/mock.rs @@ -26,4 +26,8 @@ pub fn literal_integer() -> Literal { pub fn literal_float() -> Literal { Literal::Float(3.5) +} + +pub fn literal_unknown() -> Literal { + Literal::Unknown(".0".into()) } \ No newline at end of file diff --git a/ligen/ir/src/macro_attributes/attributes/mock.rs b/ligen/ir/src/macro_attributes/attributes/mock.rs index f99ce18d..07d9ce77 100644 --- a/ligen/ir/src/macro_attributes/attributes/mock.rs +++ b/ligen/ir/src/macro_attributes/attributes/mock.rs @@ -28,9 +28,9 @@ pub fn parse_expressions() -> Attributes { "error", vec![ Attribute::Literal("the {} field name: '{}' is invalid, path: {:?}".into()), - Attribute::Group(".0.field_type".into()), - Attribute::Group(".0.field_name".into()), - Attribute::Group(".0.path".into()) + Attribute::from(Literal::Unknown("self.0.field_type".into())), + Attribute::from(Literal::Unknown("self.0.field_name".into())), + Attribute::from(Literal::Unknown("self.0.path".into())) ] ).into() } diff --git a/ligen/parser/src/parser/universal/attributes/attribute/intermediary_attribute/mod.rs b/ligen/parser/src/parser/universal/attributes/attribute/intermediary_attribute/mod.rs new file mode 100644 index 00000000..4850902e --- /dev/null +++ b/ligen/parser/src/parser/universal/attributes/attribute/intermediary_attribute/mod.rs @@ -0,0 +1,21 @@ +pub(crate) enum IntermediaryAttribute { + Meta(syn::Meta), + Lit(syn::Lit), + Expr(syn::Expr), + Unknown(String) +} + +impl syn::parse::Parse for IntermediaryAttribute { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + println!("{}", input); + if input.peek(syn::Lit) { + input.parse().map(IntermediaryAttribute::Lit) + } else { + if let Ok(attribute) = input.parse().map(IntermediaryAttribute::Expr) { + Ok(attribute) + } else { + Ok(input.parse().map(IntermediaryAttribute::Meta).unwrap_or(IntermediaryAttribute::Unknown(input.to_string()))) + } + } + } +} diff --git a/ligen/parser/src/parser/universal/attributes/attribute.rs b/ligen/parser/src/parser/universal/attributes/attribute/mod.rs similarity index 51% rename from ligen/parser/src/parser/universal/attributes/attribute.rs rename to ligen/parser/src/parser/universal/attributes/attribute/mod.rs index 32dd55d6..4a4e617e 100644 --- a/ligen/parser/src/parser/universal/attributes/attribute.rs +++ b/ligen/parser/src/parser/universal/attributes/attribute/mod.rs @@ -1,14 +1,18 @@ //! Attribute enumeration. +use intermediary_attribute::IntermediaryAttribute; use ligen_ir::macro_attributes::{Named, Group}; use syn::__private::ToTokens; use crate::prelude::*; -use ligen_ir::{Attribute, Path, PathSegment}; +use crate::universal::parser::PathParser; +use ligen_ir::{Attribute, Literal}; use crate::parser::{Parser, ParserConfig}; use crate::parser::universal::identifier::IdentifierParser; use crate::parser::universal::attributes::AttributesParser; use crate::parser::universal::literal::LiteralParser; +pub(crate) mod intermediary_attribute; + #[derive(Default)] pub struct AttributeParser { literal_parser: T @@ -35,16 +39,11 @@ impl Parser for AttributeParser { impl Parser for AttributeParser { type Output = Attribute; fn parse(&self, meta_list: syn::MetaList, config: &ParserConfig) -> Result { - let identifier = meta_list - .path - .segments - .first() - .ok_or(Error::Message("Failed to get identifier from syn::MetaList".to_string()))? - .ident - .clone(); - let identifier = IdentifierParser::new().parse(identifier, config)?; - let attributes = AttributesParser::::default().parse(meta_list, config)?; - let group = Group::new(identifier, attributes); + println!("4"); + let path = PathParser::default().parse(meta_list.path.clone(), config)?; + let inner = meta_list.tokens.into_iter().map(|token| token.to_string()).collect::>().join(""); + let attributes = AttributesParser::::default().parse(inner.as_str(), config)?; + let group = Group::new(path, attributes); Ok(group.into()) } } @@ -92,31 +91,7 @@ impl Parser for AttributeParser { syn::Expr::Lit(expr) => self.literal_parser.parse(expr.to_token_stream().to_string(), config).map(Attribute::Literal), syn::Expr::Call(expr) => self.parse(expr, config), syn::Expr::Assign(expr) => self.parse(expr, config), - syn::Expr::Field(_) => Err(Error::Message(format!("Failed to parse attributes: Field is not supported"))), - syn::Expr::Array(_) => Err(Error::Message(format!("Failed to parse attributes: Array is not supported"))), - syn::Expr::Tuple(_) => Err(Error::Message(format!("Failed to parse attributes: Tuple is not supported"))), - syn::Expr::Paren(_) => Err(Error::Message(format!("Failed to parse attributes: Paren is not supported"))), - syn::Expr::Group(_) => Err(Error::Message(format!("Failed to parse attributes: Group is not supported"))), - syn::Expr::AssignOp(_) => Err(Error::Message(format!("Failed to parse attributes: AssignOp is not supported"))), - syn::Expr::Index(_) => Err(Error::Message(format!("Failed to parse attributes: Index is not supported"))), - syn::Expr::Range(_) => Err(Error::Message(format!("Failed to parse attributes: Range is not supported"))), - syn::Expr::Async(_) => Err(Error::Message(format!("Failed to parse attributes: Async is not supported"))), - syn::Expr::Try(_) => Err(Error::Message(format!("Failed to parse attributes: Try is not supported"))), - syn::Expr::TryBlock(_) => Err(Error::Message(format!("Failed to parse attributes: TryBlock is not supported"))), - syn::Expr::Yield(_) => Err(Error::Message(format!("Failed to parse attributes: Yield is not supported"))), - syn::Expr::Verbatim(_) => Err(Error::Message(format!("Failed to parse attributes: Verbatim is not supported"))), - syn::Expr::Await(_) => Err(Error::Message(format!("Failed to parse attributes: Await is not supported"))), - syn::Expr::Closure(_) => Err(Error::Message(format!("Failed to parse attributes: Closure is not supported"))), - syn::Expr::Unsafe(_) => Err(Error::Message(format!("Failed to parse attributes: Unsafe is not supported"))), - syn::Expr::Block(_) => Err(Error::Message(format!("Failed to parse attributes: Block is not supported"))), - syn::Expr::If(_) => Err(Error::Message(format!("Failed to parse attributes: If is not supported"))), - syn::Expr::Binary(_) => Err(Error::Message(format!("Failed to parse attributes: Binary is not supported"))), - syn::Expr::Cast(_) => Err(Error::Message(format!("Failed to parse attributes: Cast is not supported"))), - syn::Expr::Type(_) => Err(Error::Message(format!("Failed to parse attributes: Type is not supported"))), - syn::Expr::Repeat(_) => Err(Error::Message(format!("Failed to parse attributes: Repeat is not supported"))), - syn::Expr::Struct(_) => Err(Error::Message(format!("Failed to parse attributes: Struct is not supported"))), - syn::Expr::MethodCall(_) => Err(Error::Message(format!("Failed to parse attributes: MethodCall is not supported"))), - _ => Err(Error::Message("Failed to parse attribute: Unsupported expression type".to_string())), + _ => Ok(Attribute::Literal(Literal::Unknown(expr.to_token_stream().into_iter().map(|token| token.to_string()).collect::>().join("")))), } } } @@ -131,15 +106,7 @@ impl Parser for AttributeParser { impl Parser for AttributeParser { type Output = Attribute; fn parse(&self, path: syn::Path, config: &ParserConfig) -> Result { - // TODO: This is duplicated from PathParser. - let segments = path - .segments - .iter() - // FIXME: This isn't parsing generics, just the identifiers. - .map(|segment| IdentifierParser::new().parse(segment.ident.clone(), config).expect("Failed to parse segment.")) - .map(PathSegment::from) - .collect(); - let path = Path { segments }; + let path = PathParser::default().parse(path, config)?; let attribute = Group::from(path).into(); Ok(attribute) } @@ -149,14 +116,9 @@ impl Parser for AttributeParser { impl Parser for AttributeParser { type Output = Attribute; fn parse(&self, meta_name_value: syn::MetaNameValue, config: &ParserConfig) -> Result { - let identifier = meta_name_value - .path - .segments - .first() - .ok_or(Error::Message("Failed to get identifier from syn::MetaNameValue".to_string()))? - .ident - .clone(); - let attribute = Named::new(IdentifierParser::new().parse(identifier, config)?, self.literal_parser.parse(meta_name_value.lit.to_token_stream().to_string(), config)?).into(); + let path = PathParser::default().parse(meta_name_value.path, config)?; + let literal = self.literal_parser.parse(meta_name_value.value.to_token_stream().to_string(), config)?; + let attribute = Named::new(path, literal).into(); Ok(attribute) } } @@ -164,6 +126,7 @@ impl Parser for AttributeParser { impl Parser for AttributeParser { type Output = Attribute; fn parse(&self, meta: syn::Meta, config: &ParserConfig) -> Result { + println!("3"); match meta { syn::Meta::Path(path) => self.parse(path, config), syn::Meta::List(list) => self.parse(list, config), @@ -172,23 +135,10 @@ impl Parser for AttributeParser { } } -impl Parser for AttributeParser { - type Output = Attribute; - fn parse(&self, nested_meta: syn::NestedMeta, config: &ParserConfig) -> Result { - match nested_meta { - syn::NestedMeta::Meta(meta) => self.parse(meta, config), - syn::NestedMeta::Lit(lit) => Ok(Self::Output::Literal(self.literal_parser.parse(lit.to_token_stream().to_string(), config)?)), - } - } -} - impl Parser for AttributeParser { type Output = Attribute; fn parse(&self, attribute: syn::Attribute, config: &ParserConfig) -> Result { - attribute - .parse_meta() - .map_err(|e| Error::Message(format!("Failed to parse attribute: {:?} - {}", e, attribute.to_token_stream().to_string()))) - .and_then(|attribute| self.parse(attribute, config)) + self.parse(attribute.meta, config) } } @@ -199,11 +149,24 @@ impl Parser for AttributeParser { } } +impl Parser for AttributeParser { + type Output = Attribute; + fn parse(&self, input: IntermediaryAttribute, config: &ParserConfig) -> Result { + println!("2", ); + match input { + IntermediaryAttribute::Meta(meta) => self.parse(meta, config), + IntermediaryAttribute::Lit(lit) => self.parse(lit, config), + IntermediaryAttribute::Expr(expr) => self.parse(expr, config), + IntermediaryAttribute::Unknown(unknown) => Ok(Attribute::Literal(Literal::Unknown(unknown))), + } + } +} + impl Parser<&str> for AttributeParser { type Output = Attribute; fn parse(&self, input: &str, config: &ParserConfig) -> Result { - syn::parse_str::(input) - .map_err(|e| Error::Message(format!("Failed to parse attribute: {:?} - {}", e, input))) - .and_then(|attribute| self.parse(attribute, config)) + let attribute = syn::parse_str::(input) + .map_err(|e| Error::Message(format!("Failed to parse attribute: {:?} - {}", e, input)))?; + self.parse(attribute, config) } -} \ No newline at end of file +} diff --git a/ligen/parser/src/parser/universal/attributes/mod.rs b/ligen/parser/src/parser/universal/attributes/mod.rs index 3a08d7dc..bbcd1c81 100644 --- a/ligen/parser/src/parser/universal/attributes/mod.rs +++ b/ligen/parser/src/parser/universal/attributes/mod.rs @@ -2,6 +2,7 @@ pub mod attribute; use crate::prelude::*; use crate::parser::{Parser, ParserConfig}; +use attribute::intermediary_attribute::IntermediaryAttribute; use ligen_ir::Attributes; use attribute::AttributeParser; use crate::parser::universal::literal::LiteralParser; @@ -28,8 +29,9 @@ impl Parser<&str> for AttributesParser { type Output = Attributes; fn parse(&self, input: &str, config: &ParserConfig) -> Result { - syn::parse_str::>(input) - .map_err(|e| Error::Message(format!("Failed to parse attributes: {:?}. Input: {}", e, input))) + println!("{}", input); + syn::parse_str::>(input) + .map_err(|e| Error::Message(format!("Failed to parse attributes: {}. Input: {}", e, input))) .and_then(|input| self.parse(input.0, config)) } } @@ -45,6 +47,19 @@ impl Parser> for AttributesParser { } } +impl Parser> for AttributesParser +{ + type Output = Attributes; + fn parse(&self, input: syn::punctuated::Punctuated, config: &ParserConfig) -> Result { + println!("??"); + let mut attributes = Vec::new(); + for attribute in input { + attributes.push(self.attribute_parser.parse(attribute, config)?); + } + Ok(Self::Output { attributes }) + } +} + impl Parser> for AttributesParser { type Output = Attributes; @@ -57,10 +72,9 @@ impl Parser Parser> for AttributesParser { +impl Parser> for AttributesParser { type Output = Attributes; - fn parse(&self, input: syn::punctuated::Punctuated, config: &ParserConfig) -> Result { + fn parse(&self, input: syn::punctuated::Punctuated, config: &ParserConfig) -> Result { let attributes = input .into_iter() .map(|nested_meta| self.attribute_parser.parse(nested_meta, config).expect("Failed to parse nested meta.")) @@ -68,25 +82,3 @@ impl Parser Parser for AttributesParser { - type Output = Attributes; - fn parse(&self, attribute_args: syn::AttributeArgs, config: &ParserConfig) -> Result { - let attributes = attribute_args - .iter() - .map(|nested_meta| self.attribute_parser.parse(nested_meta.clone(), config).expect("Failed to parse nested meta.")) - .collect(); - Ok(Self::Output { attributes }) - } -} - -impl Parser for AttributesParser { - type Output = Attributes; - fn parse(&self, input: syn::MetaList, config: &ParserConfig) -> Result { - let mut attributes = Vec::new(); - for nested_meta in input.nested { - attributes.push(self.attribute_parser.parse(nested_meta, config)?); - } - Ok(Self::Output { attributes }) - } -} diff --git a/ligen/parser/src/parser/universal/mod.rs b/ligen/parser/src/parser/universal/mod.rs index 5145cd52..7dc5d4ed 100644 --- a/ligen/parser/src/parser/universal/mod.rs +++ b/ligen/parser/src/parser/universal/mod.rs @@ -1,3 +1,4 @@ pub mod attributes; pub mod identifier; -pub mod literal; \ No newline at end of file +pub mod literal; +pub mod parser; \ No newline at end of file diff --git a/ligen/parser/src/parser/universal/parser/mod.rs b/ligen/parser/src/parser/universal/parser/mod.rs new file mode 100644 index 00000000..4f89be7c --- /dev/null +++ b/ligen/parser/src/parser/universal/parser/mod.rs @@ -0,0 +1,65 @@ +// FIXME: This is duplicated from Rust's parser. + +use ligen_ir::{Path, PathSegment}; +use crate::{Parser, ParserConfig}; +use crate::universal::identifier::IdentifierParser; +use crate::prelude::*; + +#[derive(Default)] +pub struct PathParser {} + +impl PathParser { + pub fn new() -> Self { + Default::default() + } +} + +impl Parser for PathParser { + type Output = Path; + fn parse(&self, path: syn::Path, config: &ParserConfig) -> Result { + let segments = path + .segments + .iter() + // FIXME: This isn't parsing generics, just the identifiers. + .map(|segment| IdentifierParser::new().parse(segment.ident.clone(), config).expect("Failed to parse segment.")) // FIXME: Remove this expect. + .map(PathSegment::from) + .collect(); + Ok(Self::Output { segments }) + } +} + +impl Parser for PathParser { + type Output = Path; + fn parse(&self, identifier: syn::Ident, config: &ParserConfig) -> Result { + let segments = vec![IdentifierParser::new().parse(identifier, config)?.into()]; + Ok(Self::Output { segments }) + } +} + +impl Parser<&str> for PathParser { + type Output = Path; + fn parse(&self, input: &str, config: &ParserConfig) -> Result { + syn::parse_str::(input) + .map_err(|e| Error::Message(format!("Failed to parse path: {:?}", e))) + .and_then(|path| self.parse(path, config)) + } +} + +#[cfg(test)] +mod test { + use super::PathParser; + use crate::prelude::*; + + use crate::assert::*; + use ligen_ir::path::mock; + + #[test] + fn identifier_as_path() -> Result<()> { + assert_eq(PathParser::default(), mock::identifier_as_path(), "u8") + } + + #[test] + fn path() -> Result<()> { + assert_eq(PathParser::default(), mock::path(), "std::convert::TryFrom") + } +} \ No newline at end of file diff --git a/ligen/parser/src/prelude/syn2/punctuated.rs b/ligen/parser/src/prelude/syn2/punctuated.rs index 17641230..ce7d2b9b 100644 --- a/ligen/parser/src/prelude/syn2/punctuated.rs +++ b/ligen/parser/src/prelude/syn2/punctuated.rs @@ -4,5 +4,6 @@ impl syn::parse::Parse for Punctuate fn parse(input: syn::parse::ParseStream) -> syn::Result { syn::punctuated::Punctuated::::parse_terminated(input) .map(|punctuated| Self(punctuated)) + } }