precompile_utils_macro/precompile/
attr.rs

1// This file is part of Frontier.
2
3// Copyright (c) Moonsong Labs.
4// Copyright (C) Parity Technologies (UK) Ltd.
5// SPDX-License-Identifier: Apache-2.0
6
7// Licensed under the Apache License, Version 2.0 (the "License");
8// you may not use this file except in compliance with the License.
9// You may obtain a copy of the License at
10//
11// 	http://www.apache.org/licenses/LICENSE-2.0
12//
13// Unless required by applicable law or agreed to in writing, software
14// distributed under the License is distributed on an "AS IS" BASIS,
15// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16// See the License for the specific language governing permissions and
17// limitations under the License.
18
19use proc_macro2::Span;
20use quote::ToTokens;
21use syn::spanned::Spanned;
22
23pub fn take_attributes<A>(attributes: &mut Vec<syn::Attribute>) -> syn::Result<Vec<A>>
24where
25	A: syn::parse::Parse,
26{
27	let mut output = vec![];
28	let pred = |attr: &syn::Attribute| {
29		attr.path()
30			.segments
31			.first()
32			.is_some_and(|segment| segment.ident == "precompile")
33	};
34
35	while let Some(index) = attributes.iter().position(pred) {
36		let attr = attributes.remove(index);
37		let attr = syn::parse2(attr.into_token_stream())?;
38		output.push(attr)
39	}
40	Ok(output)
41}
42
43/// List of additional token to be used for parsing.
44pub mod keyword {
45	syn::custom_keyword!(precompile);
46	syn::custom_keyword!(public);
47	syn::custom_keyword!(fallback);
48	syn::custom_keyword!(payable);
49	syn::custom_keyword!(view);
50	syn::custom_keyword!(discriminant);
51	syn::custom_keyword!(precompile_set);
52	syn::custom_keyword!(test_concrete_types);
53	syn::custom_keyword!(pre_check);
54}
55
56/// Attributes for methods
57#[allow(dead_code)]
58pub enum MethodAttr {
59	Public(Span, syn::LitStr),
60	Fallback(Span),
61	Payable(Span),
62	View(Span),
63	Discriminant(Span),
64	PreCheck(Span),
65}
66
67impl syn::parse::Parse for MethodAttr {
68	fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
69		input.parse::<syn::Token![#]>()?;
70		let content;
71		syn::bracketed!(content in input);
72		content.parse::<keyword::precompile>()?;
73		content.parse::<syn::Token![::]>()?;
74
75		let lookahead = content.lookahead1();
76
77		if lookahead.peek(keyword::public) {
78			let span = content.parse::<keyword::public>()?.span();
79
80			let inner;
81			syn::parenthesized!(inner in content);
82			let signature = inner.parse::<syn::LitStr>()?;
83
84			Ok(MethodAttr::Public(span, signature))
85		} else if lookahead.peek(keyword::fallback) {
86			Ok(MethodAttr::Fallback(
87				content.parse::<keyword::fallback>()?.span(),
88			))
89		} else if lookahead.peek(keyword::payable) {
90			Ok(MethodAttr::Payable(
91				content.parse::<keyword::payable>()?.span(),
92			))
93		} else if lookahead.peek(keyword::view) {
94			Ok(MethodAttr::View(content.parse::<keyword::view>()?.span()))
95		} else if lookahead.peek(keyword::discriminant) {
96			Ok(MethodAttr::Discriminant(
97				content.parse::<keyword::discriminant>()?.span(),
98			))
99		} else if lookahead.peek(keyword::pre_check) {
100			Ok(MethodAttr::PreCheck(
101				content.parse::<keyword::pre_check>()?.span(),
102			))
103		} else {
104			Err(lookahead.error())
105		}
106	}
107}
108
109/// Attributes for the main impl Block.
110#[allow(dead_code)]
111pub enum ImplAttr {
112	PrecompileSet(Span),
113	TestConcreteTypes(Span, Vec<syn::Type>),
114}
115
116impl syn::parse::Parse for ImplAttr {
117	fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
118		input.parse::<syn::Token![#]>()?;
119		let content;
120		syn::bracketed!(content in input);
121		content.parse::<keyword::precompile>()?;
122		content.parse::<syn::Token![::]>()?;
123
124		let lookahead = content.lookahead1();
125
126		if lookahead.peek(keyword::precompile_set) {
127			Ok(ImplAttr::PrecompileSet(
128				content.parse::<keyword::precompile_set>()?.span(),
129			))
130		} else if lookahead.peek(keyword::test_concrete_types) {
131			let span = content.parse::<keyword::test_concrete_types>()?.span();
132
133			let inner;
134			syn::parenthesized!(inner in content);
135			let types = inner.parse_terminated(syn::Type::parse, syn::Token![,])?;
136
137			Ok(ImplAttr::TestConcreteTypes(
138				span,
139				types.into_iter().collect(),
140			))
141		} else {
142			Err(lookahead.error())
143		}
144	}
145}