1use crate::prelude::*;
2use crate::ir::{Attributes, Constant, Function, Identifier, Type};
3use crate::proc_macro;
4use proc_macro2::TokenStream;
5use std::convert::{TryFrom, TryInto};
6use syn::{parse2, ItemImpl};
7use crate::ir::processing::ReplaceIdentifier;
8
9#[derive(Debug, PartialEq, Clone)]
10pub struct Implementation {
12 pub attributes: Attributes,
14 pub self_: Type,
16 pub items: Vec<ImplementationItem>,
18}
19
20#[derive(Debug, PartialEq, Clone)]
21pub enum ImplementationItem {
23 Constant(Constant),
25 Method(Function),
27}
28
29impl TryFrom<TokenStream> for Implementation {
30 type Error = Error;
31 fn try_from(tokenstream: TokenStream) -> Result<Self> {
32 parse2::<ItemImpl>(tokenstream)
33 .map_err(|_| "Failed to parse to Implementation.".into())
34 .and_then(|item| item.try_into())
35 }
36}
37
38impl TryFrom<proc_macro::TokenStream> for Implementation {
39 type Error = Error;
40 fn try_from(tokenstream: proc_macro::TokenStream) -> Result<Self> {
41 let tokenstream: TokenStream = tokenstream.into();
42 tokenstream.try_into()
43 }
44}
45
46impl TryFrom<syn::ImplItem> for ImplementationItem {
47 type Error = Error;
48 fn try_from(impl_item: syn::ImplItem) -> Result<Self> {
49 match impl_item {
50 syn::ImplItem::Const(impl_item_const) => Ok(Self::Constant(impl_item_const.into())),
51 syn::ImplItem::Method(impl_item_method) => Ok(Self::Method(impl_item_method.into())),
52 _ => Err("Only Const and Method Impl items are currently supported".into()),
53 }
54 }
55}
56
57impl TryFrom<ItemImpl> for Implementation {
58 type Error = Error;
59 fn try_from(item_impl: ItemImpl) -> Result<Self> {
60 if let syn::Type::Path(syn::TypePath { path, .. }) = *item_impl.self_ty {
61 Ok(Self {
62 attributes: Attributes {
63 attributes: item_impl
64 .attrs
65 .into_iter()
66 .map(|x| x.parse_meta().expect("Failed to parse Meta").into())
67 .collect(),
68 },
69 self_: path.into(),
70 items: item_impl
71 .items
72 .into_iter()
73 .map(|x| x.try_into().expect("Failed to convert from ImplItem"))
74 .collect(),
75 })
76 } else {
77 Err("Impl Block Identifier not found".into())
78 }
79 }
80}
81
82impl Implementation {
83 pub fn dependencies(&self) -> Vec<Type> {
85 let mut deps: Vec<Type> = vec![];
86 for item in &self.items {
87 if let ImplementationItem::Method(method) = item {
88 method.inputs.clone().into_iter().for_each(|parameter| {
89 if !deps.iter().any(|typ| typ == ¶meter.type_) {
90 deps.push(parameter.type_);
91 }
92 });
93 if let Some(type_) = method.output.clone() {
94 if !deps.iter().any(|typ| typ == &type_)
95 && type_ != Type::Compound(Identifier::new("Self").into())
96 {
97 deps.push(type_);
98 }
99 }
100 }
101 }
102 deps
103 }
104
105 pub fn replace_self_with_explicit_names(&mut self) {
119 let identifier = self.self_.path().last();
120 let mut lower_case_identifier = identifier.clone();
121 lower_case_identifier.name = lower_case_identifier.name.to_lowercase();
122 self.replace_identifier(&Identifier::from("Self"), &identifier);
123 }
124}
125
126
127
128#[cfg(test)]
129mod test {
130 use std::convert::TryFrom;
131
132 use super::{
133 Attributes, Constant, Function, Identifier, Implementation, ImplementationItem, ItemImpl,
134 };
135 use crate::ir::{
136 Atomic, Attribute, Integer, Literal, Reference, ReferenceKind, Type, Visibility,
137 };
138 use quote::quote;
139 use syn::parse_quote::parse;
140
141 #[test]
142 fn impl_block() {
143 assert_eq!(
144 Implementation::try_from(parse::<ItemImpl>(quote! {impl Test {}}))
145 .expect("Failed to convert from ItemImpl"),
146 Implementation {
147 attributes: Attributes { attributes: vec![] },
148 self_: Type::Compound(Identifier::new("Test").into()),
149 items: vec![]
150 }
151 );
152 }
153
154 #[test]
155 fn impl_block_attributes() {
156 assert_eq!(
157 Implementation::try_from(parse::<ItemImpl>(quote! {
158 #[test(a = "b")]
159 impl Test {}
160 }))
161 .expect("Failed to convert from ItemImpl"),
162 Implementation {
163 attributes: Attributes {
164 attributes: vec![Attribute::Group(
165 Identifier::new("test"),
166 Attributes {
167 attributes: vec![Attribute::Named(
168 Identifier::new("a"),
169 Literal::String(String::from("b"))
170 )]
171 }
172 )]
173 },
174 self_: Type::Compound(Identifier::new("Test").into()),
175 items: vec![]
176 }
177 );
178 }
179
180 #[test]
181 fn impl_block_items_const() {
182 assert_eq!(
183 Implementation::try_from(parse::<ItemImpl>(quote! {
184 impl Test {
185 const a: i32 = 2;
186 }
187 }))
188 .expect("Failed to convert from ItemImpl"),
189 Implementation {
190 attributes: Attributes { attributes: vec![] },
191 self_: Type::Compound(Identifier::new("Test").into()),
192 items: vec![ImplementationItem::Constant(Constant {
193 identifier: Identifier::new("a"),
194 type_: Type::Atomic(Atomic::Integer(Integer::I32)),
195 literal: Literal::Integer(2)
196 })]
197 }
198 );
199 }
200
201 #[test]
202 fn impl_block_items_method() {
203 assert_eq!(
204 Implementation::try_from(parse::<ItemImpl>(quote! {
205 impl Test {
206 fn a(){}
207 }
208 }))
209 .expect("Failed to convert from ItemImpl"),
210 Implementation {
211 attributes: Attributes { attributes: vec![] },
212 self_: Type::Compound(Identifier::new("Test").into()),
213 items: vec![ImplementationItem::Method(Function {
214 attributes: Attributes { attributes: vec![] },
215 visibility: Visibility::Inherited,
216 asyncness: None,
217 identifier: Identifier::new("a"),
218 inputs: vec![],
219 output: None
220 })]
221 }
222 );
223 }
224
225 #[test]
226 fn impl_block_items() {
227 assert_eq!(
228 Implementation::try_from(parse::<ItemImpl>(quote! {
229 impl Test {
230 const a: i32 = 2;
231 fn b(){}
232 }
233 }))
234 .expect("Failed to convert from ItemImpl"),
235 Implementation {
236 attributes: Attributes { attributes: vec![] },
237 self_: Type::Compound(Identifier::new("Test").into()),
238 items: vec![
239 ImplementationItem::Constant(Constant {
240 identifier: Identifier::new("a"),
241 type_: Type::Atomic(Atomic::Integer(Integer::I32)),
242 literal: Literal::Integer(2)
243 }),
244 ImplementationItem::Method(Function {
245 attributes: Attributes { attributes: vec![] },
246 visibility: Visibility::Inherited,
247 asyncness: None,
248 identifier: Identifier::new("b"),
249 inputs: vec![],
250 output: None
251 })
252 ]
253 }
254 );
255 }
256
257 #[test]
258 fn impl_block_dependencies() {
259 assert_eq!(
260 Implementation::try_from(parse::<ItemImpl>(quote! {
261 impl Person {
262 pub fn new(name: FullName, age: Age) -> Self { ... }
263 pub fn more_deps(age: Age, a: A, b: B, c: C) -> D;
264 pub fn builtin(&self, age: i32, name: String, name_str: &str, vec: Vec<String>) -> Box<Rc<Mutex<Arc<HashMap<String, Option<Result<String, Error>>>>>>>;
265 }
266 }))
267 .expect("Failed to build implementation from TokenStream")
268 .dependencies(),
269 vec![
270 Type::Compound(Identifier::new("FullName").into()),
271 Type::Compound(Identifier::new("Age").into()),
272 Type::Compound(Identifier::new("A").into()),
273 Type::Compound(Identifier::new("B").into()),
274 Type::Compound(Identifier::new("C").into()),
275 Type::Compound(Identifier::new("D").into()),
276 Type::Reference(Reference {kind: ReferenceKind::Borrow, is_constant: true, type_: Box::new(Type::Compound(Identifier::new("Self").into()))}),
277 Type::Atomic(Atomic::Integer(Integer::I32)),
278 Type::Compound(Identifier::new("String").into()),
279 Type::Reference(Reference {kind: ReferenceKind::Borrow, is_constant: true, type_: Box::new(Type::Compound(Identifier::new("str").into()))}),
280 Type::Compound(Identifier::new("Vec").into()),
281 Type::Compound(Identifier::new("Box").into()),
282 ]
283 );
284 }
285}