syn_solidity/expr/
args.rs

1use crate::{
2    Expr, SolIdent, Spanned, kw,
3    utils::{DebugPunctuated, ParseNested},
4};
5use proc_macro2::Span;
6use std::fmt;
7use syn::{
8    Result, Token, braced, parenthesized,
9    parse::{Parse, ParseStream},
10    punctuated::Punctuated,
11    token::{Brace, Paren},
12};
13
14/// A function call expression: `foo(42)` or `foo({ bar: 42 })`.
15#[derive(Clone, Debug)]
16pub struct ExprCall {
17    pub expr: Box<Expr>,
18    pub args: ArgList,
19}
20
21impl ParseNested for ExprCall {
22    fn parse_nested(expr: Box<Expr>, input: ParseStream<'_>) -> Result<Self> {
23        Ok(Self { expr, args: input.parse()? })
24    }
25}
26
27derive_parse!(ExprCall);
28
29impl Spanned for ExprCall {
30    fn span(&self) -> Span {
31        let span = self.expr.span();
32        span.join(self.args.span()).unwrap_or(span)
33    }
34
35    fn set_span(&mut self, span: Span) {
36        self.expr.set_span(span);
37        self.args.set_span(span);
38    }
39}
40
41/// A `payable` expression: `payable(address(0x...))`.
42#[derive(Clone)]
43pub struct ExprPayable {
44    pub payable_token: kw::payable,
45    pub args: ArgList,
46}
47
48impl fmt::Debug for ExprPayable {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        f.debug_struct("ExprPayable").field("args", &self.args).finish()
51    }
52}
53
54impl From<ExprPayable> for ExprCall {
55    fn from(value: ExprPayable) -> Self {
56        Self {
57            expr: Box::new(Expr::Ident(SolIdent::new_spanned("payable", value.payable_token.span))),
58            args: value.args,
59        }
60    }
61}
62
63impl Parse for ExprPayable {
64    fn parse(input: ParseStream<'_>) -> Result<Self> {
65        Ok(Self { payable_token: input.parse()?, args: input.parse()? })
66    }
67}
68
69impl Spanned for ExprPayable {
70    fn span(&self) -> Span {
71        let span = self.payable_token.span;
72        span.join(self.args.span()).unwrap_or(span)
73    }
74
75    fn set_span(&mut self, span: Span) {
76        self.payable_token.span = span;
77        self.args.set_span(span);
78    }
79}
80
81/// A list of named or unnamed arguments: `{ foo: 42, bar: 64 }` or `(42, 64)`.
82///
83/// Solidity reference:
84/// <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.callArgumentList>
85#[derive(Clone)]
86pub struct ArgList {
87    pub paren_token: Paren,
88    /// The list of arguments. Can be named or unnamed.
89    ///
90    /// When empty, this is an empty unnamed list.
91    pub list: ArgListImpl,
92}
93
94impl fmt::Debug for ArgList {
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        f.debug_struct("ArgList").field("list", &self.list).finish()
97    }
98}
99
100impl Parse for ArgList {
101    fn parse(input: ParseStream<'_>) -> Result<Self> {
102        let content;
103        Ok(Self { paren_token: parenthesized!(content in input), list: content.parse()? })
104    }
105}
106
107impl Spanned for ArgList {
108    fn span(&self) -> Span {
109        self.paren_token.span.join()
110    }
111
112    fn set_span(&mut self, span: Span) {
113        self.paren_token = Paren(span);
114    }
115}
116
117/// A list of either unnamed or named arguments.
118#[derive(Clone)]
119pub enum ArgListImpl {
120    Unnamed(Punctuated<Expr, Token![,]>),
121    Named(NamedArgList),
122}
123
124impl fmt::Debug for ArgListImpl {
125    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126        match self {
127            Self::Unnamed(list) => {
128                f.debug_tuple("Unnamed").field(DebugPunctuated::new(list)).finish()
129            }
130            Self::Named(list) => f.debug_tuple("Named").field(list).finish(),
131        }
132    }
133}
134
135impl Parse for ArgListImpl {
136    fn parse(input: ParseStream<'_>) -> Result<Self> {
137        if input.peek(Brace) {
138            input.parse().map(Self::Named)
139        } else {
140            input.parse_terminated(Expr::parse, Token![,]).map(Self::Unnamed)
141        }
142    }
143}
144
145/// Function call options: `foo.bar{ value: 1, gas: 2 }`.
146#[derive(Clone, Debug)]
147pub struct ExprCallOptions {
148    pub expr: Box<Expr>,
149    pub args: NamedArgList,
150}
151
152impl ParseNested for ExprCallOptions {
153    fn parse_nested(expr: Box<Expr>, input: ParseStream<'_>) -> Result<Self> {
154        Ok(Self { expr, args: input.parse()? })
155    }
156}
157
158derive_parse!(ExprCallOptions);
159
160impl Spanned for ExprCallOptions {
161    fn span(&self) -> Span {
162        let span = self.expr.span();
163        span.join(self.args.span()).unwrap_or(span)
164    }
165
166    fn set_span(&mut self, span: Span) {
167        self.expr.set_span(span);
168        self.args.set_span(span);
169    }
170}
171
172/// A named argument list: `{ foo: uint256(42), bar: true }`.
173#[derive(Clone)]
174pub struct NamedArgList {
175    pub brace_token: Brace,
176    pub list: Punctuated<NamedArg, Token![,]>,
177}
178
179impl fmt::Debug for NamedArgList {
180    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181        f.debug_struct("NamedArgList").field("list", DebugPunctuated::new(&self.list)).finish()
182    }
183}
184
185impl Parse for NamedArgList {
186    fn parse(input: ParseStream<'_>) -> Result<Self> {
187        let content;
188        Ok(Self {
189            brace_token: braced!(content in input),
190            list: content.parse_terminated(NamedArg::parse, Token![,])?,
191        })
192    }
193}
194
195impl Spanned for NamedArgList {
196    fn span(&self) -> Span {
197        self.brace_token.span.join()
198    }
199
200    fn set_span(&mut self, span: Span) {
201        self.brace_token = Brace(span);
202    }
203}
204
205/// A named argument in an argument list: `foo: uint256(42)`.
206#[derive(Clone)]
207pub struct NamedArg {
208    pub name: SolIdent,
209    pub colon_token: Token![:],
210    pub arg: Expr,
211}
212
213impl fmt::Debug for NamedArg {
214    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215        f.debug_struct("NamedArg").field("name", &self.name).field("arg", &self.arg).finish()
216    }
217}
218
219impl Parse for NamedArg {
220    fn parse(input: ParseStream<'_>) -> Result<Self> {
221        Ok(Self { name: input.parse()?, colon_token: input.parse()?, arg: input.parse()? })
222    }
223}
224
225impl Spanned for NamedArg {
226    fn span(&self) -> Span {
227        let span = self.name.span();
228        span.join(self.arg.span()).unwrap_or(span)
229    }
230
231    fn set_span(&mut self, span: Span) {
232        self.name.set_span(span);
233        self.arg.set_span(span);
234    }
235}