syn_solidity/stmt/
var_decl.rs1use crate::{utils::DebugPunctuated, Expr, Spanned, Stmt, VariableDeclaration};
2use proc_macro2::Span;
3use std::fmt;
4use syn::{
5 parenthesized,
6 parse::{discouraged::Speculative, Parse, ParseStream},
7 punctuated::Punctuated,
8 token::Paren,
9 Result, Token,
10};
11
12#[derive(Clone)]
17pub struct StmtVarDecl {
18 pub declaration: VarDeclDecl,
19 pub assignment: Option<(Token![=], Expr)>,
20 pub semi_token: Token![;],
21}
22
23impl fmt::Debug for StmtVarDecl {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 f.debug_struct("StmtVarDecl")
26 .field("declaration", &self.declaration)
27 .field("assignment", &self.assignment)
28 .finish()
29 }
30}
31
32impl Parse for StmtVarDecl {
33 fn parse(input: ParseStream<'_>) -> Result<Self> {
34 let declaration: VarDeclDecl = input.parse()?;
35
36 let assignment = if matches!(declaration, VarDeclDecl::Tuple(_)) || input.peek(Token![=]) {
38 Some((input.parse()?, input.parse()?))
39 } else {
40 None
41 };
42
43 let semi_token = input.parse()?;
44
45 Ok(Self { declaration, assignment, semi_token })
46 }
47}
48
49impl Spanned for StmtVarDecl {
50 fn span(&self) -> Span {
51 let span = self.declaration.span();
52 self.assignment.as_ref().and_then(|(_, expr)| expr.span().join(span)).unwrap_or(span)
53 }
54
55 fn set_span(&mut self, span: Span) {
56 self.declaration.set_span(span);
57 if let Some((eq, expr)) = &mut self.assignment {
58 eq.span = span;
59 expr.set_span(span);
60 }
61 self.semi_token.span = span;
62 }
63}
64
65impl StmtVarDecl {
66 pub fn parse_or_expr(input: ParseStream<'_>) -> Result<Stmt> {
67 let speculative_parse = || {
69 let fork = input.fork();
70 match fork.parse() {
71 Ok(var) => {
72 input.advance_to(&fork);
73 Ok(Stmt::VarDecl(var))
74 }
75 Err(_) => input.parse().map(Stmt::Expr),
76 }
77 };
78
79 if input.peek(Paren) {
80 if input.peek2(Token![=]) {
81 speculative_parse()
82 } else {
83 input.parse().map(Stmt::Expr)
84 }
85 } else {
86 speculative_parse()
87 }
88 }
89}
90
91#[derive(Clone, Debug)]
93pub enum VarDeclDecl {
94 VarDecl(VariableDeclaration),
95 Tuple(VarDeclTuple),
96}
97
98impl Parse for VarDeclDecl {
99 fn parse(input: ParseStream<'_>) -> Result<Self> {
100 if input.peek(Paren) {
101 input.parse().map(Self::Tuple)
102 } else {
103 VariableDeclaration::parse_with_name(input).map(Self::VarDecl)
104 }
105 }
106}
107
108impl Spanned for VarDeclDecl {
109 fn span(&self) -> Span {
110 match self {
111 Self::VarDecl(decl) => decl.span(),
112 Self::Tuple(decl) => decl.span(),
113 }
114 }
115
116 fn set_span(&mut self, span: Span) {
117 match self {
118 Self::VarDecl(decl) => decl.set_span(span),
119 Self::Tuple(decl) => decl.set_span(span),
120 }
121 }
122}
123
124#[derive(Clone)]
129pub struct VarDeclTuple {
130 pub paren_token: Paren,
131 pub vars: Punctuated<Option<VariableDeclaration>, Token![,]>,
134}
135
136impl fmt::Debug for VarDeclTuple {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 f.debug_struct("VarDeclTuple").field("vars", DebugPunctuated::new(&self.vars)).finish()
139 }
140}
141
142impl Parse for VarDeclTuple {
143 fn parse(input: ParseStream<'_>) -> Result<Self> {
144 let content;
145 Ok(Self {
146 paren_token: parenthesized!(content in input),
147 vars: content.parse_terminated(Self::parse_var_opt, Token![,])?,
148 })
149 }
150}
151
152impl Spanned for VarDeclTuple {
153 fn span(&self) -> Span {
154 self.paren_token.span.join()
155 }
156
157 fn set_span(&mut self, span: Span) {
158 self.paren_token = Paren(span);
159 }
160}
161
162impl VarDeclTuple {
163 fn parse_var_opt(input: ParseStream<'_>) -> Result<Option<VariableDeclaration>> {
164 if input.peek(Token![,]) {
165 Ok(None)
166 } else {
167 input.parse().map(Some)
168 }
169 }
170}