sylvia_derive/parser/
mod.rs1pub mod attributes;
5pub mod check_generics;
6pub mod entry_point;
7pub mod variant_descs;
8
9pub use attributes::{
10 ContractErrorAttr, ContractMessageAttr, Custom, Customs, FilteredOverrideEntryPoints, MsgAttr,
11 MsgType, OverrideEntryPoint, ParsedSylviaAttributes, SylviaAttribute,
12};
13use check_generics::{CheckGenerics, GetPath};
14pub use entry_point::EntryPointArgs;
15
16use proc_macro_error::emit_error;
17use syn::punctuated::Punctuated;
18use syn::spanned::Spanned;
19use syn::{FnArg, GenericArgument, ImplItem, ItemImpl, Path, PathArguments, Signature, Token};
20
21use crate::types::msg_field::MsgField;
22
23fn extract_generics_from_path(module: &Path) -> Punctuated<GenericArgument, Token![,]> {
24 let generics = module
25 .segments
26 .last()
27 .map(|segment| match segment.arguments.clone() {
28 PathArguments::AngleBracketed(generics) => generics.args,
29 PathArguments::None => Default::default(),
30 PathArguments::Parenthesized(_) => Default::default(),
31 })
32 .unwrap_or_default();
33
34 generics
35}
36
37pub fn assert_new_method_defined(item: &ItemImpl) {
40 const ERROR_NOTE: &str = "`sylvia::contract` requires parameterless `new` method to be defined for dispatch to work correctly.";
41
42 let new = item.items.iter().find_map(|item| match item {
43 ImplItem::Fn(method) if method.sig.ident == "new" => Some(method),
44 _ => None,
45 });
46
47 match new {
48 Some(new) if !new.sig.inputs.is_empty() => emit_error!(
49 new.sig.inputs, "Parameters not allowed in `new` method.";
50 note = ERROR_NOTE;
51 ),
52 None => {
53 emit_error!(
54 item, "Missing `new` method in `impl` block.";
55 note = ERROR_NOTE;
56 )
57 }
58 _ => (),
59 }
60}
61
62pub fn process_fields<'s, Generic>(
64 sig: &'s Signature,
65 generics_checker: &mut CheckGenerics<Generic>,
66) -> Vec<MsgField<'s>>
67where
68 Generic: GetPath + PartialEq,
69{
70 assert_no_self_ctx_attributes(sig);
71
72 sig.inputs
73 .iter()
74 .skip(2)
75 .filter_map(|arg| match arg {
76 FnArg::Receiver(item) => {
77 emit_error!(item.span(), "Unexpected `self` argument");
78 None
79 }
80
81 FnArg::Typed(item) => MsgField::new(item, generics_checker),
82 })
83 .collect()
84}
85
86fn assert_no_self_ctx_attributes(sig: &Signature) {
88 sig.inputs.iter().take(2).for_each(|arg| match arg {
89 FnArg::Receiver(item) => {
90 item.attrs.iter().for_each(|attr| {
91 if SylviaAttribute::new(attr).is_none() {
92 return;
93 }
94 emit_error!(attr.span(),
95 "Invalid usage of Sylvia attribute.";
96 note = "First and second arguments of the method should be `self` and `ctx` respectively.";
97 note = "Unexpected attribute on `self` parameter."
98 );
99 });
100 }
101 FnArg::Typed(item) => {
102 item.attrs.iter().for_each(|attr| {
103 if SylviaAttribute::new(attr).is_none() {
104 return;
105 }
106 emit_error!(attr.span(),
107 "Invalid usage of Sylvia attribute.";
108 note = "First and second arguments of the method should be `self` and `ctx` respectively.";
109 note = "Unexpected attribute on `ctx` parameter."
110 );
111 });
112 }
113 });
114}