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