syn_solidity/expr/
args.rs

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