1use crate::{kw, utils::DebugPunctuated, Item, Modifier, SolIdent, Spanned, Type};
2use proc_macro2::Span;
3use std::{cmp::Ordering, fmt};
4use syn::{
5 braced,
6 parse::{Lookahead1, Parse, ParseStream},
7 punctuated::Punctuated,
8 token::Brace,
9 Attribute, Error, Result, Token,
10};
11
12#[derive(Clone)]
18pub struct ItemContract {
19 pub attrs: Vec<Attribute>,
20 pub kind: ContractKind,
21 pub name: SolIdent,
22 pub inheritance: Option<Inheritance>,
23 pub brace_token: Brace,
24 pub body: Vec<Item>,
25}
26
27impl fmt::Display for ItemContract {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 write!(f, "{} {}", self.kind, self.name)?;
30 if let Some(inheritance) = &self.inheritance {
31 write!(f, " {inheritance}")?;
32 }
33 let s = self
34 .body
35 .iter()
36 .map(|item| item.to_string())
37 .collect::<Vec<_>>()
38 .join("\n")
39 .replace('\n', "\n ");
40 write!(f, " {{\n {s}\n}}")
41 }
42}
43
44impl fmt::Debug for ItemContract {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 f.debug_struct("ItemContract")
47 .field("attrs", &self.attrs)
48 .field("kind", &self.kind)
49 .field("name", &self.name)
50 .field("inheritance", &self.inheritance)
51 .field("body", &self.body)
52 .finish()
53 }
54}
55
56impl Parse for ItemContract {
57 fn parse(input: ParseStream<'_>) -> Result<Self> {
58 let kind;
59 let content;
60 Ok(Self {
61 attrs: input.call(Attribute::parse_outer)?,
62 kind: {
63 kind = input.parse()?;
64 kind
65 },
66 name: input.parse()?,
67 inheritance: {
68 if input.peek(kw::is) {
69 if kind.is_library() {
70 return Err(input.error("libraries are not allowed to inherit"));
71 }
72 Some(input.parse()?)
73 } else {
74 None
75 }
76 },
77 brace_token: braced!(content in input),
78 body: {
79 let mut body = Vec::new();
80 while !content.is_empty() {
81 let item: Item = content.parse()?;
82 if matches!(item, Item::Contract(_)) {
83 return Err(Error::new(item.span(), "cannot declare nested contracts"));
84 }
85 body.push(item);
86 }
87 body
88 },
89 })
90 }
91}
92
93impl Spanned for ItemContract {
94 fn span(&self) -> Span {
95 self.name.span()
96 }
97
98 fn set_span(&mut self, span: Span) {
99 self.name.set_span(span);
100 }
101}
102
103impl ItemContract {
104 pub fn as_type(&self) -> Type {
105 Type::Address(self.span(), None)
106 }
107
108 pub fn is_abstract_contract(&self) -> bool {
110 self.kind.is_abstract_contract()
111 }
112
113 pub fn is_contract(&self) -> bool {
115 self.kind.is_contract()
116 }
117
118 pub fn is_interface(&self) -> bool {
120 self.kind.is_interface()
121 }
122
123 pub fn is_library(&self) -> bool {
125 self.kind.is_library()
126 }
127}
128
129#[derive(Clone, Copy, PartialEq, Eq, Hash)]
131pub enum ContractKind {
132 AbstractContract(Token![abstract], kw::contract),
134 Contract(kw::contract),
136 Interface(kw::interface),
138 Library(kw::library),
140}
141
142impl fmt::Display for ContractKind {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 f.write_str(self.as_str())
145 }
146}
147
148impl fmt::Debug for ContractKind {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 f.write_str(self.as_debug_str())
151 }
152}
153
154impl PartialOrd for ContractKind {
155 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
156 Some(self.cmp(other))
157 }
158}
159
160impl Ord for ContractKind {
161 fn cmp(&self, other: &Self) -> Ordering {
162 self.idx().cmp(&other.idx())
163 }
164}
165
166impl Parse for ContractKind {
167 fn parse(input: ParseStream<'_>) -> Result<Self> {
168 let lookahead = input.lookahead1();
169 if lookahead.peek(Token![abstract]) {
170 Ok(Self::AbstractContract(input.parse()?, input.parse()?))
171 } else if lookahead.peek(kw::contract) {
172 input.parse().map(Self::Contract)
173 } else if lookahead.peek(kw::interface) {
174 input.parse().map(Self::Interface)
175 } else if lookahead.peek(kw::library) {
176 input.parse().map(Self::Library)
177 } else {
178 Err(lookahead.error())
179 }
180 }
181}
182
183impl Spanned for ContractKind {
184 fn span(&self) -> Span {
185 match self {
186 Self::AbstractContract(kw_abstract, kw_contract) => {
187 let span = kw_abstract.span;
188 span.join(kw_contract.span).unwrap_or(span)
189 }
190 Self::Contract(kw) => kw.span,
191 Self::Interface(kw) => kw.span,
192 Self::Library(kw) => kw.span,
193 }
194 }
195
196 fn set_span(&mut self, span: Span) {
197 match self {
198 Self::AbstractContract(kw_abstract, kw_contract) => {
199 kw_abstract.span = span;
200 kw_contract.span = span;
201 }
202 Self::Contract(kw) => kw.span = span,
203 Self::Interface(kw) => kw.span = span,
204 Self::Library(kw) => kw.span = span,
205 }
206 }
207}
208
209impl ContractKind {
210 pub fn peek(lookahead: &Lookahead1<'_>) -> bool {
211 lookahead.peek(Token![abstract])
212 || lookahead.peek(kw::contract)
213 || lookahead.peek(kw::interface)
214 || lookahead.peek(kw::library)
215 }
216
217 pub fn is_abstract_contract(self) -> bool {
219 matches!(self, Self::AbstractContract(..))
220 }
221
222 pub fn is_contract(self) -> bool {
224 matches!(self, Self::Contract(_))
225 }
226
227 pub fn is_interface(self) -> bool {
229 matches!(self, Self::Interface(_))
230 }
231
232 pub fn is_library(self) -> bool {
234 matches!(self, Self::Library(_))
235 }
236
237 pub const fn as_debug_str(self) -> &'static str {
238 match self {
239 Self::AbstractContract(..) => "AbstractContract",
240 Self::Contract(_) => "Contract",
241 Self::Interface(_) => "Interface",
242 Self::Library(_) => "Library",
243 }
244 }
245
246 pub const fn as_str(self) -> &'static str {
247 match self {
248 Self::AbstractContract(..) => "abstract contract",
249 Self::Contract(_) => "contract",
250 Self::Interface(_) => "interface",
251 Self::Library(_) => "library",
252 }
253 }
254
255 fn idx(&self) -> usize {
256 match self {
257 Self::AbstractContract(..) => 0,
258 Self::Contract(_) => 1,
259 Self::Interface(_) => 2,
260 Self::Library(_) => 3,
261 }
262 }
263}
264
265#[derive(Clone, PartialEq, Eq, Hash)]
271pub struct Inheritance {
272 pub is_token: kw::is,
273 pub inheritance: Punctuated<Modifier, Token![,]>,
274}
275
276impl fmt::Display for Inheritance {
277 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278 f.write_str("is ")?;
279 for (i, modifier) in self.inheritance.iter().enumerate() {
280 if i > 0 {
281 f.write_str(", ")?;
282 }
283 modifier.fmt(f)?;
284 }
285 Ok(())
286 }
287}
288
289impl fmt::Debug for Inheritance {
290 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291 f.debug_tuple("Inheritance").field(DebugPunctuated::new(&self.inheritance)).finish()
292 }
293}
294
295impl Parse for Inheritance {
296 fn parse(input: ParseStream<'_>) -> Result<Self> {
297 let is_token = input.parse()?;
298 let mut inheritance = Punctuated::new();
299 loop {
300 if input.is_empty() || input.peek(Brace) {
301 break;
302 }
303 inheritance.push_value(input.parse()?);
304 if input.is_empty() || input.peek(Brace) {
305 break;
306 }
307 inheritance.push_punct(input.parse()?);
308 }
309 if inheritance.is_empty() {
310 Err(input.parse::<SolIdent>().unwrap_err())
311 } else {
312 Ok(Self { is_token, inheritance })
313 }
314 }
315}
316
317impl Spanned for Inheritance {
318 fn span(&self) -> Span {
319 let span = self.is_token.span;
320 self.inheritance.last().and_then(|last| span.join(last.span())).unwrap_or(span)
321 }
322
323 fn set_span(&mut self, span: Span) {
324 self.is_token.span = span;
325 }
326}