1use super::{Box, Lit, SubDenomination, Type};
2use crate::BoxSlice;
3use either::Either;
4use solar_data_structures::trustme;
5use solar_interface::{Ident, Span, SpannedOption, diagnostics::ErrorGuaranteed};
6use std::fmt;
7
8pub type NamedArgList<'ast> = BoxSlice<'ast, NamedArg<'ast>>;
12
13#[derive(Debug)]
17pub struct Expr<'ast> {
18 pub span: Span,
19 pub kind: ExprKind<'ast>,
20}
21
22impl AsRef<Self> for Expr<'_> {
23 fn as_ref(&self) -> &Self {
24 self
25 }
26}
27
28impl<'ast> Expr<'ast> {
29 pub fn peel_parens(&self) -> &Self {
31 let mut expr = self;
32 while let ExprKind::Tuple(x) = &expr.kind
33 && let [SpannedOption::Some(inner)] = x.as_slice()
34 {
35 expr = inner;
36 }
37 expr
38 }
39
40 pub fn peel_parens_mut(&mut self) -> &mut Self {
42 let mut expr = self;
43 while let ExprKind::Tuple(x) = &mut unsafe { trustme::decouple_lt_mut(expr) }.kind
46 && let [SpannedOption::Some(inner)] = x.as_mut_slice()
47 {
48 expr = inner;
49 }
50 expr
51 }
52
53 pub fn from_ident(ident: Ident) -> Self {
55 Self { span: ident.span, kind: ExprKind::Ident(ident) }
56 }
57
58 pub fn from_ty(ty: Type<'ast>) -> Self {
60 Self { span: ty.span, kind: ExprKind::Type(ty) }
61 }
62}
63
64#[derive(Debug)]
66pub enum ExprKind<'ast> {
67 Array(BoxSlice<'ast, Box<'ast, Expr<'ast>>>),
69
70 Assign(Box<'ast, Expr<'ast>>, Option<BinOp>, Box<'ast, Expr<'ast>>),
72
73 Binary(Box<'ast, Expr<'ast>>, BinOp, Box<'ast, Expr<'ast>>),
75
76 Call(Box<'ast, Expr<'ast>>, CallArgs<'ast>),
78
79 CallOptions(Box<'ast, Expr<'ast>>, NamedArgList<'ast>),
81
82 Delete(Box<'ast, Expr<'ast>>),
84
85 Ident(Ident),
87
88 Index(Box<'ast, Expr<'ast>>, IndexKind<'ast>),
90
91 Lit(Box<'ast, Lit<'ast>>, Option<SubDenomination>),
96
97 Member(Box<'ast, Expr<'ast>>, Ident),
99
100 New(Type<'ast>),
102
103 Payable(CallArgs<'ast>),
105
106 Ternary(Box<'ast, Expr<'ast>>, Box<'ast, Expr<'ast>>, Box<'ast, Expr<'ast>>),
108
109 Tuple(BoxSlice<'ast, SpannedOption<Box<'ast, Expr<'ast>>>>),
111
112 TypeCall(Type<'ast>),
114
115 Type(Type<'ast>),
117
118 Unary(UnOp, Box<'ast, Expr<'ast>>),
120
121 Err(ErrorGuaranteed),
123}
124
125#[derive(Clone, Copy, Debug)]
127pub struct BinOp {
128 pub span: Span,
129 pub kind: BinOpKind,
130}
131
132#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
134pub enum BinOpKind {
135 Lt,
137 Le,
139 Gt,
141 Ge,
143 Eq,
145 Ne,
147 Or,
149 And,
151
152 Shr,
154 Shl,
156 Sar,
158 BitAnd,
160 BitOr,
162 BitXor,
164
165 Add,
167 Sub,
169 Pow,
171 Mul,
173 Div,
175 Rem,
177}
178
179impl fmt::Display for BinOp {
180 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 f.write_str(self.kind.to_str())
182 }
183}
184
185impl BinOpKind {
186 pub const fn to_str(self) -> &'static str {
188 match self {
189 Self::Lt => "<",
190 Self::Le => "<=",
191 Self::Gt => ">",
192 Self::Ge => ">=",
193 Self::Eq => "==",
194 Self::Ne => "!=",
195 Self::Or => "||",
196 Self::And => "&&",
197 Self::Sar => ">>>",
198 Self::Shr => ">>",
199 Self::Shl => "<<",
200 Self::BitAnd => "&",
201 Self::BitOr => "|",
202 Self::BitXor => "^",
203 Self::Add => "+",
204 Self::Sub => "-",
205 Self::Pow => "**",
206 Self::Mul => "*",
207 Self::Div => "/",
208 Self::Rem => "%",
209 }
210 }
211
212 pub const fn assignable(self) -> bool {
214 use BinOpKind::*;
216 matches!(self, BitOr | BitXor | BitAnd | Shl | Shr | Sar | Add | Sub | Mul | Div | Rem)
217 }
218
219 pub const fn is_cmp(self) -> bool {
221 use BinOpKind::*;
222 matches!(self, Lt | Le | Gt | Ge | Eq | Ne)
223 }
224
225 pub const fn is_shift(self) -> bool {
227 use BinOpKind::*;
228 matches!(self, Shl | Shr | Sar)
229 }
230}
231
232#[derive(Clone, Copy, Debug)]
234pub struct UnOp {
235 pub span: Span,
236 pub kind: UnOpKind,
237}
238
239#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
241pub enum UnOpKind {
242 PreInc,
244 PreDec,
246 Not,
248 Neg,
250 BitNot,
252
253 PostInc,
255 PostDec,
257}
258
259impl fmt::Display for UnOp {
260 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261 f.write_str(self.kind.to_str())
262 }
263}
264
265impl UnOpKind {
266 pub const fn to_str(self) -> &'static str {
268 match self {
269 Self::PreInc | Self::PostInc => "++",
270 Self::PreDec | Self::PostDec => "--",
271 Self::Not => "!",
272 Self::Neg => "-",
273 Self::BitNot => "~",
274 }
275 }
276
277 pub const fn is_prefix(self) -> bool {
279 match self {
280 Self::PreInc | Self::PreDec | Self::Not | Self::Neg | Self::BitNot => true,
281 Self::PostInc | Self::PostDec => false,
282 }
283 }
284
285 pub const fn is_postfix(self) -> bool {
287 !self.is_prefix()
288 }
289
290 pub const fn has_side_effects(self) -> bool {
292 match self {
293 Self::PreInc | Self::PreDec | Self::PostInc | Self::PostDec => true,
294 Self::Not | Self::Neg | Self::BitNot => false,
295 }
296 }
297}
298
299#[derive(Debug)]
301pub struct CallArgs<'ast> {
302 pub span: Span,
306 pub kind: CallArgsKind<'ast>,
307}
308
309impl<'ast> CallArgs<'ast> {
310 pub fn empty(span: Span) -> Self {
314 Self { span, kind: CallArgsKind::empty() }
315 }
316
317 pub fn is_dummy(&self) -> bool {
323 self.span.lo() == self.span.hi()
324 }
325
326 pub fn len(&self) -> usize {
328 self.kind.len()
329 }
330
331 pub fn is_empty(&self) -> bool {
333 self.kind.is_empty()
334 }
335
336 pub fn exprs(
338 &self,
339 ) -> impl ExactSizeIterator<Item = &Expr<'ast>> + DoubleEndedIterator + Clone {
340 self.kind.exprs()
341 }
342
343 pub fn exprs_mut(
345 &mut self,
346 ) -> impl ExactSizeIterator<Item = &mut Box<'ast, Expr<'ast>>> + DoubleEndedIterator {
347 self.kind.exprs_mut()
348 }
349}
350
351#[derive(Debug)]
353pub enum CallArgsKind<'ast> {
354 Unnamed(BoxSlice<'ast, Box<'ast, Expr<'ast>>>),
356
357 Named(NamedArgList<'ast>),
359}
360
361impl Default for CallArgsKind<'_> {
362 fn default() -> Self {
363 Self::empty()
364 }
365}
366
367impl<'ast> CallArgsKind<'ast> {
368 pub fn empty() -> Self {
370 Self::Unnamed(BoxSlice::default())
371 }
372
373 pub fn len(&self) -> usize {
375 match self {
376 Self::Unnamed(exprs) => exprs.len(),
377 Self::Named(args) => args.len(),
378 }
379 }
380
381 pub fn is_empty(&self) -> bool {
383 self.len() == 0
384 }
385
386 pub fn exprs(
388 &self,
389 ) -> impl ExactSizeIterator<Item = &Expr<'ast>> + DoubleEndedIterator + Clone {
390 match self {
391 Self::Unnamed(exprs) => Either::Left(exprs.iter().map(|expr| &**expr)),
392 Self::Named(args) => Either::Right(args.iter().map(|arg| &*arg.value)),
393 }
394 }
395
396 pub fn exprs_mut(
398 &mut self,
399 ) -> impl ExactSizeIterator<Item = &mut Box<'ast, Expr<'ast>>> + DoubleEndedIterator {
400 match self {
401 Self::Unnamed(exprs) => Either::Left(exprs.iter_mut()),
402 Self::Named(args) => Either::Right(args.iter_mut().map(|arg| &mut arg.value)),
403 }
404 }
405
406 pub fn span(&self) -> Option<Span> {
408 if self.is_empty() {
409 return None;
410 }
411 Some(Span::join_first_last(self.exprs().map(|e| e.span)))
412 }
413}
414
415#[derive(Debug)]
417pub struct NamedArg<'ast> {
418 pub name: Ident,
419 pub value: Box<'ast, Expr<'ast>>,
420}
421
422#[derive(Debug)]
424pub enum IndexKind<'ast> {
425 Index(Option<Box<'ast, Expr<'ast>>>),
427
428 Range(Option<Box<'ast, Expr<'ast>>>, Option<Box<'ast, Expr<'ast>>>),
430}