diff --git a/src/parse_fn.rs b/src/parse_fn.rs index 0e9f320..5accc1a 100644 --- a/src/parse_fn.rs +++ b/src/parse_fn.rs @@ -3,7 +3,10 @@ use crate::parse_type::{ }; use crate::parse_utils::{consume_attributes, consume_comma, consume_stuff_until, parse_ident}; use crate::punctuated::Punctuated; -use crate::types::{Function, FunctionParameter, FunctionQualifiers, GroupSpan, TyExpr}; +use crate::types::{ + Function, FunctionParameter, FunctionQualifiers, FunctionReceiverParameter, + FunctionTypedParameter, GroupSpan, TyExpr, +}; use crate::{Attribute, VisMarker}; use proc_macro2::{Delimiter, Ident, Punct, TokenStream, TokenTree}; use std::iter::Peekable; @@ -165,27 +168,58 @@ pub(crate) fn parse_fn_params(tokens: TokenStream) -> Punctuated punct.clone(), - _ => panic!("cannot parse fn params"), + let tk_ref = match tokens.peek() { + Some(TokenTree::Punct(punct)) if punct.as_char() == '&' => { + let ref_symbol = punct.clone(); + tokens.next(); + Some(ref_symbol) + } + _ => None, + }; + let tk_mut = match tokens.peek() { + Some(TokenTree::Ident(ident)) if ident == "mut" => { + let mut_ident = ident.clone(); + tokens.next(); + Some(mut_ident) + } + _ => None, + }; + let tk_self = match tokens.peek() { + Some(TokenTree::Ident(ident)) if ident == "self" => { + let self_ident = ident.clone(); + tokens.next(); + Some(self_ident) + } + _ => None, }; - let ty_tokens = consume_field_type(&mut tokens); - let comma = consume_comma(&mut tokens); - - fields.push( - FunctionParameter { + let param = if let Some(tk_self) = tk_self { + FunctionParameter::Receiver(FunctionReceiverParameter { attributes, + tk_ref, + tk_mut, + tk_self, + }) + } else { + // TODO - handle non-ident argument names + let ident = parse_ident(tokens.next().unwrap()).unwrap(); + let tk_colon = match tokens.next() { + Some(TokenTree::Punct(punct)) if punct.as_char() == ':' => punct.clone(), + _ => panic!("cannot parse fn params"), + }; + let ty_tokens = consume_field_type(&mut tokens); + FunctionParameter::Typed(FunctionTypedParameter { + attributes, + tk_mut, name: ident, tk_colon, ty: TyExpr { tokens: ty_tokens }, - }, - comma, - ); + }) + }; + + let comma = consume_comma(&mut tokens); + + fields.push(param, comma); } fields diff --git a/src/snapshots/venial__tests__parse_all_kw_fn.snap b/src/snapshots/venial__tests__parse_all_kw_fn.snap index 27b059c..082a178 100644 --- a/src/snapshots/venial__tests__parse_all_kw_fn.snap +++ b/src/snapshots/venial__tests__parse_all_kw_fn.snap @@ -46,19 +46,22 @@ Function( generic_params: None, tk_params_parens: (), params: [ - FunctionParameter { - attributes: [], - name: Ident( - b, - ), - tk_colon: Punct { - char: ':', - spacing: Alone, + Typed( + FunctionTypedParameter { + attributes: [], + tk_mut: None, + name: Ident( + b, + ), + tk_colon: Punct { + char: ':', + spacing: Alone, + }, + ty: [ + f32, + ], }, - ty: [ - f32, - ], - }, + ), ], where_clause: None, tk_return_arrow: None, diff --git a/src/snapshots/venial__tests__parse_async_fn.snap b/src/snapshots/venial__tests__parse_async_fn.snap index f4fc2d9..9c0fb2a 100644 --- a/src/snapshots/venial__tests__parse_async_fn.snap +++ b/src/snapshots/venial__tests__parse_async_fn.snap @@ -26,19 +26,22 @@ Function( generic_params: None, tk_params_parens: (), params: [ - FunctionParameter { - attributes: [], - name: Ident( - b, - ), - tk_colon: Punct { - char: ':', - spacing: Alone, + Typed( + FunctionTypedParameter { + attributes: [], + tk_mut: None, + name: Ident( + b, + ), + tk_colon: Punct { + char: ':', + spacing: Alone, + }, + ty: [ + f32, + ], }, - ty: [ - f32, - ], - }, + ), ], where_clause: None, tk_return_arrow: None, diff --git a/src/snapshots/venial__tests__parse_attr_fn.snap b/src/snapshots/venial__tests__parse_attr_fn.snap index a8c5936..c71a01c 100644 --- a/src/snapshots/venial__tests__parse_attr_fn.snap +++ b/src/snapshots/venial__tests__parse_attr_fn.snap @@ -32,19 +32,22 @@ Function( generic_params: None, tk_params_parens: (), params: [ - FunctionParameter { - attributes: [], - name: Ident( - a, - ), - tk_colon: Punct { - char: ':', - spacing: Alone, + Typed( + FunctionTypedParameter { + attributes: [], + tk_mut: None, + name: Ident( + a, + ), + tk_colon: Punct { + char: ':', + spacing: Alone, + }, + ty: [ + i32, + ], }, - ty: [ - i32, - ], - }, + ), ], where_clause: None, tk_return_arrow: None, diff --git a/src/snapshots/venial__tests__parse_const_fn.snap b/src/snapshots/venial__tests__parse_const_fn.snap index 6a9b761..be7c4f2 100644 --- a/src/snapshots/venial__tests__parse_const_fn.snap +++ b/src/snapshots/venial__tests__parse_const_fn.snap @@ -26,19 +26,22 @@ Function( generic_params: None, tk_params_parens: (), params: [ - FunctionParameter { - attributes: [], - name: Ident( - b, - ), - tk_colon: Punct { - char: ':', - spacing: Alone, + Typed( + FunctionTypedParameter { + attributes: [], + tk_mut: None, + name: Ident( + b, + ), + tk_colon: Punct { + char: ':', + spacing: Alone, + }, + ty: [ + f32, + ], }, - ty: [ - f32, - ], - }, + ), ], where_clause: None, tk_return_arrow: None, diff --git a/src/snapshots/venial__tests__parse_default_fn.snap b/src/snapshots/venial__tests__parse_default_fn.snap index 103e8af..a1caf2c 100644 --- a/src/snapshots/venial__tests__parse_default_fn.snap +++ b/src/snapshots/venial__tests__parse_default_fn.snap @@ -26,19 +26,22 @@ Function( generic_params: None, tk_params_parens: (), params: [ - FunctionParameter { - attributes: [], - name: Ident( - b, - ), - tk_colon: Punct { - char: ':', - spacing: Alone, + Typed( + FunctionTypedParameter { + attributes: [], + tk_mut: None, + name: Ident( + b, + ), + tk_colon: Punct { + char: ':', + spacing: Alone, + }, + ty: [ + f32, + ], }, - ty: [ - f32, - ], - }, + ), ], where_clause: None, tk_return_arrow: None, diff --git a/src/snapshots/venial__tests__parse_extern_abi_fn.snap b/src/snapshots/venial__tests__parse_extern_abi_fn.snap index ed1988c..ebf0763 100644 --- a/src/snapshots/venial__tests__parse_extern_abi_fn.snap +++ b/src/snapshots/venial__tests__parse_extern_abi_fn.snap @@ -30,19 +30,22 @@ Function( generic_params: None, tk_params_parens: (), params: [ - FunctionParameter { - attributes: [], - name: Ident( - b, - ), - tk_colon: Punct { - char: ':', - spacing: Alone, + Typed( + FunctionTypedParameter { + attributes: [], + tk_mut: None, + name: Ident( + b, + ), + tk_colon: Punct { + char: ':', + spacing: Alone, + }, + ty: [ + f32, + ], }, - ty: [ - f32, - ], - }, + ), ], where_clause: None, tk_return_arrow: None, diff --git a/src/snapshots/venial__tests__parse_extern_fn.snap b/src/snapshots/venial__tests__parse_extern_fn.snap index 611bc1b..15be776 100644 --- a/src/snapshots/venial__tests__parse_extern_fn.snap +++ b/src/snapshots/venial__tests__parse_extern_fn.snap @@ -26,19 +26,22 @@ Function( generic_params: None, tk_params_parens: (), params: [ - FunctionParameter { - attributes: [], - name: Ident( - b, - ), - tk_colon: Punct { - char: ':', - spacing: Alone, + Typed( + FunctionTypedParameter { + attributes: [], + tk_mut: None, + name: Ident( + b, + ), + tk_colon: Punct { + char: ':', + spacing: Alone, + }, + ty: [ + f32, + ], }, - ty: [ - f32, - ], - }, + ), ], where_clause: None, tk_return_arrow: None, diff --git a/src/snapshots/venial__tests__parse_fn.snap b/src/snapshots/venial__tests__parse_fn.snap index 1e9e645..3dc7ddd 100644 --- a/src/snapshots/venial__tests__parse_fn.snap +++ b/src/snapshots/venial__tests__parse_fn.snap @@ -20,32 +20,38 @@ Function( generic_params: None, tk_params_parens: (), params: [ - FunctionParameter { - attributes: [], - name: Ident( - a, - ), - tk_colon: Punct { - char: ':', - spacing: Alone, + Typed( + FunctionTypedParameter { + attributes: [], + tk_mut: None, + name: Ident( + a, + ), + tk_colon: Punct { + char: ':', + spacing: Alone, + }, + ty: [ + i32, + ], }, - ty: [ - i32, - ], - }, - FunctionParameter { - attributes: [], - name: Ident( - b, - ), - tk_colon: Punct { - char: ':', - spacing: Alone, + ), + Typed( + FunctionTypedParameter { + attributes: [], + tk_mut: None, + name: Ident( + b, + ), + tk_colon: Punct { + char: ':', + spacing: Alone, + }, + ty: [ + f32, + ], }, - ty: [ - f32, - ], - }, + ), ], where_clause: None, tk_return_arrow: Some( diff --git a/src/snapshots/venial__tests__parse_fn_body.snap b/src/snapshots/venial__tests__parse_fn_body.snap index c352647..180da7f 100644 --- a/src/snapshots/venial__tests__parse_fn_body.snap +++ b/src/snapshots/venial__tests__parse_fn_body.snap @@ -20,32 +20,38 @@ Function( generic_params: None, tk_params_parens: (), params: [ - FunctionParameter { - attributes: [], - name: Ident( - a, - ), - tk_colon: Punct { - char: ':', - spacing: Alone, + Typed( + FunctionTypedParameter { + attributes: [], + tk_mut: None, + name: Ident( + a, + ), + tk_colon: Punct { + char: ':', + spacing: Alone, + }, + ty: [ + i32, + ], }, - ty: [ - i32, - ], - }, - FunctionParameter { - attributes: [], - name: Ident( - b, - ), - tk_colon: Punct { - char: ':', - spacing: Alone, + ), + Typed( + FunctionTypedParameter { + attributes: [], + tk_mut: None, + name: Ident( + b, + ), + tk_colon: Punct { + char: ':', + spacing: Alone, + }, + ty: [ + f32, + ], }, - ty: [ - f32, - ], - }, + ), ], where_clause: None, tk_return_arrow: Some( diff --git a/src/snapshots/venial__tests__parse_fn_prototype.snap b/src/snapshots/venial__tests__parse_fn_prototype.snap index 00b9451..c2e5949 100644 --- a/src/snapshots/venial__tests__parse_fn_prototype.snap +++ b/src/snapshots/venial__tests__parse_fn_prototype.snap @@ -20,32 +20,38 @@ Function( generic_params: None, tk_params_parens: (), params: [ - FunctionParameter { - attributes: [], - name: Ident( - a, - ), - tk_colon: Punct { - char: ':', - spacing: Alone, + Typed( + FunctionTypedParameter { + attributes: [], + tk_mut: None, + name: Ident( + a, + ), + tk_colon: Punct { + char: ':', + spacing: Alone, + }, + ty: [ + i32, + ], }, - ty: [ - i32, - ], - }, - FunctionParameter { - attributes: [], - name: Ident( - b, - ), - tk_colon: Punct { - char: ':', - spacing: Alone, + ), + Typed( + FunctionTypedParameter { + attributes: [], + tk_mut: None, + name: Ident( + b, + ), + tk_colon: Punct { + char: ':', + spacing: Alone, + }, + ty: [ + f32, + ], }, - ty: [ - f32, - ], - }, + ), ], where_clause: None, tk_return_arrow: Some( diff --git a/src/snapshots/venial__tests__parse_fn_self_param-2.snap b/src/snapshots/venial__tests__parse_fn_self_param-2.snap new file mode 100644 index 0000000..e8f4524 --- /dev/null +++ b/src/snapshots/venial__tests__parse_fn_self_param-2.snap @@ -0,0 +1,51 @@ +--- +source: src/tests.rs +expression: func_ref_self +--- +Ok( + Function( + Function { + attributes: [], + vis_marker: None, + qualifiers: FunctionQualifiers { + tk_default: None, + tk_const: None, + tk_async: None, + tk_unsafe: None, + tk_extern: None, + extern_abi: None, + }, + name: Ident( + foobar, + ), + generic_params: None, + tk_params_parens: (), + params: [ + Receiver( + FunctionReceiverParameter { + attributes: [], + tk_ref: Some( + Punct { + char: '&', + spacing: Alone, + }, + ), + tk_mut: None, + tk_self: Ident( + self, + ), + }, + ), + ], + where_clause: None, + tk_return_arrow: None, + return_ty: None, + body: Some( + Group { + delimiter: Brace, + stream: TokenStream [], + }, + ), + }, + ), +) diff --git a/src/snapshots/venial__tests__parse_fn_self_param-3.snap b/src/snapshots/venial__tests__parse_fn_self_param-3.snap new file mode 100644 index 0000000..47c6c18 --- /dev/null +++ b/src/snapshots/venial__tests__parse_fn_self_param-3.snap @@ -0,0 +1,50 @@ +--- +source: src/tests.rs +expression: func_mut_self +--- +Ok( + Function( + Function { + attributes: [], + vis_marker: None, + qualifiers: FunctionQualifiers { + tk_default: None, + tk_const: None, + tk_async: None, + tk_unsafe: None, + tk_extern: None, + extern_abi: None, + }, + name: Ident( + foobar, + ), + generic_params: None, + tk_params_parens: (), + params: [ + Receiver( + FunctionReceiverParameter { + attributes: [], + tk_ref: None, + tk_mut: Some( + Ident( + mut, + ), + ), + tk_self: Ident( + self, + ), + }, + ), + ], + where_clause: None, + tk_return_arrow: None, + return_ty: None, + body: Some( + Group { + delimiter: Brace, + stream: TokenStream [], + }, + ), + }, + ), +) diff --git a/src/snapshots/venial__tests__parse_fn_self_param-4.snap b/src/snapshots/venial__tests__parse_fn_self_param-4.snap new file mode 100644 index 0000000..17163ec --- /dev/null +++ b/src/snapshots/venial__tests__parse_fn_self_param-4.snap @@ -0,0 +1,55 @@ +--- +source: src/tests.rs +expression: func_ref_mut_self +--- +Ok( + Function( + Function { + attributes: [], + vis_marker: None, + qualifiers: FunctionQualifiers { + tk_default: None, + tk_const: None, + tk_async: None, + tk_unsafe: None, + tk_extern: None, + extern_abi: None, + }, + name: Ident( + foobar, + ), + generic_params: None, + tk_params_parens: (), + params: [ + Receiver( + FunctionReceiverParameter { + attributes: [], + tk_ref: Some( + Punct { + char: '&', + spacing: Alone, + }, + ), + tk_mut: Some( + Ident( + mut, + ), + ), + tk_self: Ident( + self, + ), + }, + ), + ], + where_clause: None, + tk_return_arrow: None, + return_ty: None, + body: Some( + Group { + delimiter: Brace, + stream: TokenStream [], + }, + ), + }, + ), +) diff --git a/src/snapshots/venial__tests__parse_fn_self_param.snap b/src/snapshots/venial__tests__parse_fn_self_param.snap new file mode 100644 index 0000000..f9c1081 --- /dev/null +++ b/src/snapshots/venial__tests__parse_fn_self_param.snap @@ -0,0 +1,46 @@ +--- +source: src/tests.rs +expression: func_self +--- +Ok( + Function( + Function { + attributes: [], + vis_marker: None, + qualifiers: FunctionQualifiers { + tk_default: None, + tk_const: None, + tk_async: None, + tk_unsafe: None, + tk_extern: None, + extern_abi: None, + }, + name: Ident( + foobar, + ), + generic_params: None, + tk_params_parens: (), + params: [ + Receiver( + FunctionReceiverParameter { + attributes: [], + tk_ref: None, + tk_mut: None, + tk_self: Ident( + self, + ), + }, + ), + ], + where_clause: None, + tk_return_arrow: None, + return_ty: None, + body: Some( + Group { + delimiter: Brace, + stream: TokenStream [], + }, + ), + }, + ), +) diff --git a/src/snapshots/venial__tests__parse_generic_fn.snap b/src/snapshots/venial__tests__parse_generic_fn.snap index 4890c2a..8b685de 100644 --- a/src/snapshots/venial__tests__parse_generic_fn.snap +++ b/src/snapshots/venial__tests__parse_generic_fn.snap @@ -31,19 +31,22 @@ Function( ), tk_params_parens: (), params: [ - FunctionParameter { - attributes: [], - name: Ident( - a, - ), - tk_colon: Punct { - char: ':', - spacing: Alone, + Typed( + FunctionTypedParameter { + attributes: [], + tk_mut: None, + name: Ident( + a, + ), + tk_colon: Punct { + char: ':', + spacing: Alone, + }, + ty: [ + T, + ], }, - ty: [ - T, - ], - }, + ), ], where_clause: None, tk_return_arrow: Some( diff --git a/src/snapshots/venial__tests__parse_param_attr_fn.snap b/src/snapshots/venial__tests__parse_param_attr_fn.snap index efb2fa4..4694263 100644 --- a/src/snapshots/venial__tests__parse_param_attr_fn.snap +++ b/src/snapshots/venial__tests__parse_param_attr_fn.snap @@ -26,31 +26,34 @@ Function( generic_params: None, tk_params_parens: (), params: [ - FunctionParameter { - attributes: [ - Attribute { - tk_hashbang: Punct { - char: '#', - spacing: Alone, + Typed( + FunctionTypedParameter { + attributes: [ + Attribute { + tk_hashbang: Punct { + char: '#', + spacing: Alone, + }, + tk_brackets: [], + path: [ + my_attr, + ], + value: Empty, }, - tk_brackets: [], - path: [ - my_attr, - ], - value: Empty, + ], + tk_mut: None, + name: Ident( + b, + ), + tk_colon: Punct { + char: ':', + spacing: Alone, }, - ], - name: Ident( - b, - ), - tk_colon: Punct { - char: ':', - spacing: Alone, + ty: [ + f32, + ], }, - ty: [ - f32, - ], - }, + ), ], where_clause: None, tk_return_arrow: None, diff --git a/src/snapshots/venial__tests__parse_unsafe_fn.snap b/src/snapshots/venial__tests__parse_unsafe_fn.snap index 974d728..7776b52 100644 --- a/src/snapshots/venial__tests__parse_unsafe_fn.snap +++ b/src/snapshots/venial__tests__parse_unsafe_fn.snap @@ -26,19 +26,22 @@ Function( generic_params: None, tk_params_parens: (), params: [ - FunctionParameter { - attributes: [], - name: Ident( - b, - ), - tk_colon: Punct { - char: ':', - spacing: Alone, + Typed( + FunctionTypedParameter { + attributes: [], + tk_mut: None, + name: Ident( + b, + ), + tk_colon: Punct { + char: ':', + spacing: Alone, + }, + ty: [ + f32, + ], }, - ty: [ - f32, - ], - }, + ), ], where_clause: None, tk_return_arrow: None, diff --git a/src/snapshots/venial__tests__parse_visi_fn.snap b/src/snapshots/venial__tests__parse_visi_fn.snap index 8be78a9..457b403 100644 --- a/src/snapshots/venial__tests__parse_visi_fn.snap +++ b/src/snapshots/venial__tests__parse_visi_fn.snap @@ -22,19 +22,22 @@ Function( generic_params: None, tk_params_parens: (), params: [ - FunctionParameter { - attributes: [], - name: Ident( - b, - ), - tk_colon: Punct { - char: ':', - spacing: Alone, + Typed( + FunctionTypedParameter { + attributes: [], + tk_mut: None, + name: Ident( + b, + ), + tk_colon: Punct { + char: ':', + spacing: Alone, + }, + ty: [ + f32, + ], }, - ty: [ - f32, - ], - }, + ), ], where_clause: None, tk_return_arrow: None, diff --git a/src/tests.rs b/src/tests.rs index 4728520..7d030f7 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -814,27 +814,25 @@ fn parse_fn_no_pattern() { assert_debug_snapshot!(func); } -// FIXME #[test] -#[should_panic] fn parse_fn_self_param() { - let func_0 = parse_declaration(quote! { + let func_self = parse_declaration(quote! { fn foobar(self) {} }); - let func_1 = parse_declaration(quote! { + let func_ref_self = parse_declaration(quote! { fn foobar(&self) {} }); - let func_2 = parse_declaration(quote! { + let func_mut_self = parse_declaration(quote! { fn foobar(mut self) {} }); - let func_3 = parse_declaration(quote! { + let func_ref_mut_self = parse_declaration(quote! { fn foobar(&mut self) {} }); - assert_debug_snapshot!(func_0); - assert_debug_snapshot!(func_1); - assert_debug_snapshot!(func_2); - assert_debug_snapshot!(func_3); + assert_debug_snapshot!(func_self); + assert_debug_snapshot!(func_ref_self); + assert_debug_snapshot!(func_mut_self); + assert_debug_snapshot!(func_ref_mut_self); } // ============ diff --git a/src/types.rs b/src/types.rs index d2f9d8e..d410656 100644 --- a/src/types.rs +++ b/src/types.rs @@ -174,14 +174,46 @@ pub struct FunctionQualifiers { /// A parameter of a [`Function`] /// -/// In the following code, the function parameters captured are `a: i32` and `b: f32` +/// Function parameters can either be receivers (`self` variations) or typed parameters (`name: type` form). /// +/// In the following code, the parameters captured are `&self`, `a: i32` and `b: f32`: /// ```no_run -/// pub fn hello_world(a: i32, b: f32) {} +/// # struct S; impl S { +/// pub fn hello_world(&self, a: i32, b: f32) {} +/// # } /// ``` #[derive(Clone, Debug)] -pub struct FunctionParameter { +pub enum FunctionParameter { + Receiver(FunctionReceiverParameter), + Typed(FunctionTypedParameter), +} + +/// A [`Function`] parameter which refers to `self` in some way. +/// +/// Possible parameters captures by this are `self`, `mut self`, `&self` or `&mut self`. +/// Reference lifetimes are not yet supported. +/// +/// Parameters of the form `self: Pin<&mut Self>` are recognized as [`FunctionTypedParameter`]. +#[derive(Clone, Debug)] +pub struct FunctionReceiverParameter { + pub attributes: Vec, + pub tk_ref: Option, + // TODO ref lifetime (update doc) + pub tk_mut: Option, + pub tk_self: Ident, +} + +/// A parameter of a [`Function`] +/// +/// In the following code, the function parameters captured are `a: i32` and `mut b: f32` +/// +/// ```no_run +/// pub fn hello_world(a: i32, mut b: f32) {} +/// ``` +#[derive(Clone, Debug)] +pub struct FunctionTypedParameter { pub attributes: Vec, + pub tk_mut: Option, pub name: Ident, pub tk_colon: Punct, pub ty: TyExpr, @@ -694,10 +726,31 @@ impl ToTokens for FunctionQualifiers { } impl ToTokens for FunctionParameter { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + FunctionParameter::Receiver(param) => param.to_tokens(tokens), + FunctionParameter::Typed(param) => param.to_tokens(tokens), + } + } +} + +impl ToTokens for FunctionReceiverParameter { + fn to_tokens(&self, tokens: &mut TokenStream) { + for attribute in &self.attributes { + attribute.to_tokens(tokens); + } + self.tk_ref.to_tokens(tokens); + self.tk_mut.to_tokens(tokens); + self.tk_self.to_tokens(tokens); + } +} + +impl ToTokens for FunctionTypedParameter { fn to_tokens(&self, tokens: &mut TokenStream) { for attribute in &self.attributes { attribute.to_tokens(tokens); } + self.tk_mut.to_tokens(tokens); self.name.to_tokens(tokens); self.tk_colon.to_tokens(tokens); self.ty.to_tokens(tokens);