syn_solidity/yul/stmt/
var_decl.rs

1use crate::{utils::DebugPunctuated, Spanned, WalrusToken, YulExpr, YulIdent};
2use proc_macro2::Span;
3use std::fmt;
4use syn::{
5    parse::{Parse, ParseStream},
6    punctuated::Punctuated,
7    Result, Token,
8};
9
10/// Declares Yul variables, which may or may not have initial values. E.x.
11/// `let x := 0`
12/// `let x`
13/// `let x, y := foo()`
14/// `let x, y, z`
15///
16/// Multiple variables can only be initialized via a function call.
17///
18/// Solidity Reference:
19/// <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.yulVariableDeclaration>
20#[derive(Clone)]
21pub struct YulVarDecl {
22    pub let_token: Token![let],
23    pub vars: Punctuated<YulIdent, Token![,]>,
24    pub init_value: Option<(WalrusToken, YulExpr)>,
25}
26
27impl Parse for YulVarDecl {
28    fn parse(input: ParseStream<'_>) -> Result<Self> {
29        let let_token = input.parse()?;
30        let vars = Punctuated::parse_separated_nonempty(input)?;
31        let init_value = if input.peek(Token![:]) && input.peek2(Token![=]) {
32            Some((input.parse()?, input.parse()?))
33        } else {
34            None
35        };
36
37        if vars.len() > 1
38            && init_value.as_ref().is_some_and(|(_, expr)| !matches!(expr, YulExpr::Call(_)))
39        {
40            return Err(
41                input.error("Multiple variables can only be initialized by a function call")
42            );
43        }
44
45        Ok(Self { let_token, vars, init_value })
46    }
47}
48
49impl Spanned for YulVarDecl {
50    fn span(&self) -> Span {
51        let span = self.let_token.span();
52        if let Some((_, expr)) = &self.init_value {
53            span.join(expr.span()).unwrap_or(span)
54        } else {
55            span.join(self.vars.span()).unwrap_or(span)
56        }
57    }
58
59    fn set_span(&mut self, span: Span) {
60        self.let_token.set_span(span);
61        self.vars.set_span(span);
62        if let Some((walrus_token, init_value)) = &mut self.init_value {
63            walrus_token.set_span(span);
64            init_value.set_span(span);
65        }
66    }
67}
68
69impl fmt::Debug for YulVarDecl {
70    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71        f.debug_struct("YulVarDecl")
72            .field("vars", DebugPunctuated::new(&self.vars))
73            .field("init_value", &self.init_value.as_ref().map(|(_, expr)| expr))
74            .finish()
75    }
76}