1use sway_error::handler::ErrorEmitted;
2
3use crate::{assignable::ElementAccess, priv_prelude::*, PathExprSegment};
4
5pub mod asm;
6pub mod op_code;
7
8#[derive(Clone, Debug, Serialize)]
9pub enum Expr {
10 Error(Box<[Span]>, #[serde(skip_serializing)] ErrorEmitted),
14 Path(PathExpr),
15 Literal(Literal),
16 AbiCast {
17 abi_token: AbiToken,
18 args: Parens<AbiCastArgs>,
19 },
20 Struct {
21 path: PathExpr,
22 fields: Braces<Punctuated<ExprStructField, CommaToken>>,
23 },
24 Tuple(Parens<ExprTupleDescriptor>),
25 Parens(Parens<Box<Expr>>),
26 Block(Braces<CodeBlockContents>),
27 Array(SquareBrackets<ExprArrayDescriptor>),
28 Asm(AsmBlock),
29 Return {
30 return_token: ReturnToken,
31 expr_opt: Option<Box<Expr>>,
32 },
33 Panic {
34 panic_token: PanicToken,
35 expr_opt: Option<Box<Expr>>,
36 },
37 If(IfExpr),
38 Match {
39 match_token: MatchToken,
40 value: Box<Expr>,
41 branches: Braces<Vec<MatchBranch>>,
42 },
43 While {
44 while_token: WhileToken,
45 condition: Box<Expr>,
46 block: Braces<CodeBlockContents>,
47 },
48 For {
49 for_token: ForToken,
50 in_token: InToken,
51 value_pattern: Pattern,
52 iterator: Box<Expr>,
53 block: Braces<CodeBlockContents>,
54 },
55 FuncApp {
56 func: Box<Expr>,
57 args: Parens<Punctuated<Expr, CommaToken>>,
58 },
59 Index {
60 target: Box<Expr>,
61 arg: SquareBrackets<Box<Expr>>,
62 },
63 MethodCall {
64 target: Box<Expr>,
65 dot_token: DotToken,
66 path_seg: PathExprSegment,
67 contract_args_opt: Option<Braces<Punctuated<ExprStructField, CommaToken>>>,
68 args: Parens<Punctuated<Expr, CommaToken>>,
69 },
70 FieldProjection {
71 target: Box<Expr>,
72 dot_token: DotToken,
73 name: Ident,
74 },
75 TupleFieldProjection {
76 target: Box<Expr>,
77 dot_token: DotToken,
78 field: BigUint,
79 field_span: Span,
80 },
81 Ref {
82 ampersand_token: AmpersandToken,
83 mut_token: Option<MutToken>,
84 expr: Box<Expr>,
85 },
86 Deref {
87 star_token: StarToken,
88 expr: Box<Expr>,
89 },
90 Not {
91 bang_token: BangToken,
92 expr: Box<Expr>,
93 },
94 Mul {
95 lhs: Box<Expr>,
96 star_token: StarToken,
97 rhs: Box<Expr>,
98 },
99 Div {
100 lhs: Box<Expr>,
101 forward_slash_token: ForwardSlashToken,
102 rhs: Box<Expr>,
103 },
104 Pow {
105 lhs: Box<Expr>,
106 double_star_token: DoubleStarToken,
107 rhs: Box<Expr>,
108 },
109 Modulo {
110 lhs: Box<Expr>,
111 percent_token: PercentToken,
112 rhs: Box<Expr>,
113 },
114 Add {
115 lhs: Box<Expr>,
116 add_token: AddToken,
117 rhs: Box<Expr>,
118 },
119 Sub {
120 lhs: Box<Expr>,
121 sub_token: SubToken,
122 rhs: Box<Expr>,
123 },
124 Shl {
125 lhs: Box<Expr>,
126 shl_token: ShlToken,
127 rhs: Box<Expr>,
128 },
129 Shr {
130 lhs: Box<Expr>,
131 shr_token: ShrToken,
132 rhs: Box<Expr>,
133 },
134 BitAnd {
135 lhs: Box<Expr>,
136 ampersand_token: AmpersandToken,
137 rhs: Box<Expr>,
138 },
139 BitXor {
140 lhs: Box<Expr>,
141 caret_token: CaretToken,
142 rhs: Box<Expr>,
143 },
144 BitOr {
145 lhs: Box<Expr>,
146 pipe_token: PipeToken,
147 rhs: Box<Expr>,
148 },
149 Equal {
150 lhs: Box<Expr>,
151 double_eq_token: DoubleEqToken,
152 rhs: Box<Expr>,
153 },
154 NotEqual {
155 lhs: Box<Expr>,
156 bang_eq_token: BangEqToken,
157 rhs: Box<Expr>,
158 },
159 LessThan {
160 lhs: Box<Expr>,
161 less_than_token: LessThanToken,
162 rhs: Box<Expr>,
163 },
164 GreaterThan {
165 lhs: Box<Expr>,
166 greater_than_token: GreaterThanToken,
167 rhs: Box<Expr>,
168 },
169 LessThanEq {
170 lhs: Box<Expr>,
171 less_than_eq_token: LessThanEqToken,
172 rhs: Box<Expr>,
173 },
174 GreaterThanEq {
175 lhs: Box<Expr>,
176 greater_than_eq_token: GreaterThanEqToken,
177 rhs: Box<Expr>,
178 },
179 LogicalAnd {
180 lhs: Box<Expr>,
181 double_ampersand_token: DoubleAmpersandToken,
182 rhs: Box<Expr>,
183 },
184 LogicalOr {
185 lhs: Box<Expr>,
186 double_pipe_token: DoublePipeToken,
187 rhs: Box<Expr>,
188 },
189 Reassignment {
190 assignable: Assignable,
191 reassignment_op: ReassignmentOp,
192 expr: Box<Expr>,
193 },
194 Break {
195 break_token: BreakToken,
196 },
197 Continue {
198 continue_token: ContinueToken,
199 },
200}
201
202impl Spanned for Expr {
203 fn span(&self) -> Span {
204 match self {
205 Expr::Error(spans, _) => spans
206 .iter()
207 .cloned()
208 .reduce(|s1: Span, s2: Span| Span::join(s1, &s2))
209 .unwrap(),
210 Expr::Path(path_expr) => path_expr.span(),
211 Expr::Literal(literal) => literal.span(),
212 Expr::AbiCast { abi_token, args } => Span::join(abi_token.span(), &args.span()),
213 Expr::Struct { path, fields } => Span::join(path.span(), &fields.span()),
214 Expr::Tuple(tuple_expr) => tuple_expr.span(),
215 Expr::Parens(parens) => parens.span(),
216 Expr::Block(block_expr) => block_expr.span(),
217 Expr::Array(array_expr) => array_expr.span(),
218 Expr::Asm(asm_block) => asm_block.span(),
219 Expr::Return {
220 return_token,
221 expr_opt,
222 } => {
223 let start = return_token.span();
224 let end = match expr_opt {
225 Some(expr) => expr.span(),
226 None => return_token.span(),
227 };
228 Span::join(start, &end)
229 }
230 Expr::Panic {
231 panic_token,
232 expr_opt,
233 } => {
234 let start = panic_token.span();
235 let end = match expr_opt {
236 Some(expr) => expr.span(),
237 None => panic_token.span(),
238 };
239 Span::join(start, &end)
240 }
241 Expr::If(if_expr) => if_expr.span(),
242 Expr::Match {
243 match_token,
244 branches,
245 ..
246 } => Span::join(match_token.span(), &branches.span()),
247 Expr::While {
248 while_token, block, ..
249 } => Span::join(while_token.span(), &block.span()),
250 Expr::For {
251 for_token, block, ..
252 } => Span::join(for_token.span(), &block.span()),
253 Expr::FuncApp { func, args } => Span::join(func.span(), &args.span()),
254 Expr::Index { target, arg } => Span::join(target.span(), &arg.span()),
255 Expr::MethodCall { target, args, .. } => Span::join(target.span(), &args.span()),
256 Expr::FieldProjection { target, name, .. } => Span::join(target.span(), &name.span()),
257 Expr::TupleFieldProjection {
258 target, field_span, ..
259 } => Span::join(target.span(), field_span),
260 Expr::Ref {
261 ampersand_token,
262 expr,
263 ..
264 } => Span::join(ampersand_token.span(), &expr.span()),
265 Expr::Deref { star_token, expr } => Span::join(star_token.span(), &expr.span()),
266 Expr::Not { bang_token, expr } => Span::join(bang_token.span(), &expr.span()),
267 Expr::Pow { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
268 Expr::Mul { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
269 Expr::Div { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
270 Expr::Modulo { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
271 Expr::Add { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
272 Expr::Sub { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
273 Expr::Shl { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
274 Expr::Shr { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
275 Expr::BitAnd { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
276 Expr::BitXor { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
277 Expr::BitOr { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
278 Expr::Equal { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
279 Expr::NotEqual { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
280 Expr::LessThan { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
281 Expr::GreaterThan { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
282 Expr::LessThanEq { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
283 Expr::GreaterThanEq { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
284 Expr::LogicalAnd { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
285 Expr::LogicalOr { lhs, rhs, .. } => Span::join(lhs.span(), &rhs.span()),
286 Expr::Reassignment {
287 assignable, expr, ..
288 } => Span::join(assignable.span(), &expr.span()),
289 Expr::Break { break_token } => break_token.span(),
290 Expr::Continue { continue_token } => continue_token.span(),
291 }
292 }
293}
294
295#[derive(Clone, Debug, Serialize)]
296pub struct ReassignmentOp {
297 pub variant: ReassignmentOpVariant,
298 pub span: Span,
299}
300
301#[derive(Clone, Debug, Serialize)]
302pub enum ReassignmentOpVariant {
303 Equals,
304 AddEquals,
305 SubEquals,
306 MulEquals,
307 DivEquals,
308 ShlEquals,
309 ShrEquals,
310}
311
312impl ReassignmentOpVariant {
313 pub fn std_name(&self) -> &'static str {
314 match self {
315 ReassignmentOpVariant::Equals => "eq",
316 ReassignmentOpVariant::AddEquals => "add",
317 ReassignmentOpVariant::SubEquals => "subtract",
318 ReassignmentOpVariant::MulEquals => "multiply",
319 ReassignmentOpVariant::DivEquals => "divide",
320 ReassignmentOpVariant::ShlEquals => "lsh",
321 ReassignmentOpVariant::ShrEquals => "rsh",
322 }
323 }
324
325 pub fn as_str(&self) -> &'static str {
326 match self {
327 ReassignmentOpVariant::Equals => EqToken::AS_STR,
328 ReassignmentOpVariant::AddEquals => AddEqToken::AS_STR,
329 ReassignmentOpVariant::SubEquals => SubEqToken::AS_STR,
330 ReassignmentOpVariant::MulEquals => StarEqToken::AS_STR,
331 ReassignmentOpVariant::DivEquals => DivEqToken::AS_STR,
332 ReassignmentOpVariant::ShlEquals => ShlEqToken::AS_STR,
333 ReassignmentOpVariant::ShrEquals => ShrEqToken::AS_STR,
334 }
335 }
336}
337
338#[derive(Clone, Debug, Serialize)]
339pub struct AbiCastArgs {
340 pub name: PathType,
341 pub comma_token: CommaToken,
342 pub address: Box<Expr>,
343}
344
345#[allow(clippy::type_complexity)]
346#[derive(Clone, Debug, Serialize)]
347pub struct IfExpr {
348 pub if_token: IfToken,
349 pub condition: IfCondition,
350 pub then_block: Braces<CodeBlockContents>,
351 pub else_opt: Option<(
352 ElseToken,
353 LoopControlFlow<Braces<CodeBlockContents>, Box<IfExpr>>,
354 )>,
355}
356
357#[derive(Clone, Debug, Serialize)]
358pub enum IfCondition {
359 Expr(Box<Expr>),
360 Let {
361 let_token: LetToken,
362 lhs: Box<Pattern>,
363 eq_token: EqToken,
364 rhs: Box<Expr>,
365 },
366}
367
368#[derive(Clone, Debug, Serialize)]
369pub enum LoopControlFlow<B, C = ()> {
370 Continue(C),
371 Break(B),
372}
373
374impl Spanned for IfExpr {
375 fn span(&self) -> Span {
376 let start = self.if_token.span();
377 let end = match &self.else_opt {
378 Some((_else_token, tail)) => match tail {
379 LoopControlFlow::Break(block) => block.span(),
380 LoopControlFlow::Continue(if_expr) => if_expr.span(),
381 },
382 None => self.then_block.span(),
383 };
384 Span::join(start, &end)
385 }
386}
387
388#[derive(Clone, Debug, Serialize)]
389pub enum ExprTupleDescriptor {
390 Nil,
391 Cons {
392 head: Box<Expr>,
393 comma_token: CommaToken,
394 tail: Punctuated<Expr, CommaToken>,
395 },
396}
397
398#[derive(Clone, Debug, Serialize)]
399pub enum ExprArrayDescriptor {
400 Sequence(Punctuated<Expr, CommaToken>),
401 Repeat {
402 value: Box<Expr>,
403 semicolon_token: SemicolonToken,
404 length: Box<Expr>,
405 },
406}
407
408#[derive(Clone, Debug, Serialize)]
409pub struct MatchBranch {
410 pub pattern: Pattern,
411 pub fat_right_arrow_token: FatRightArrowToken,
412 pub kind: MatchBranchKind,
413}
414
415impl Spanned for MatchBranch {
416 fn span(&self) -> Span {
417 Span::join(self.pattern.span(), &self.kind.span())
418 }
419}
420
421#[allow(clippy::large_enum_variant)]
422#[derive(Debug, Clone, Serialize)]
423pub enum MatchBranchKind {
424 Block {
425 block: Braces<CodeBlockContents>,
426 comma_token_opt: Option<CommaToken>,
427 },
428 Expr {
429 expr: Expr,
430 comma_token: CommaToken,
431 },
432}
433
434impl Spanned for MatchBranchKind {
435 fn span(&self) -> Span {
436 match self {
437 MatchBranchKind::Block {
438 block,
439 comma_token_opt,
440 } => match comma_token_opt {
441 Some(comma_token) => Span::join(block.span(), &comma_token.span()),
442 None => block.span(),
443 },
444 MatchBranchKind::Expr { expr, comma_token } => {
445 Span::join(expr.span(), &comma_token.span())
446 }
447 }
448 }
449}
450
451#[derive(Clone, Debug, Serialize)]
452pub struct CodeBlockContents {
453 pub statements: Vec<Statement>,
454 pub final_expr_opt: Option<Box<Expr>>,
455 pub span: Span,
456}
457
458impl Spanned for CodeBlockContents {
459 fn span(&self) -> Span {
460 self.span.clone()
461 }
462}
463
464#[derive(Clone, Debug, Serialize)]
465pub struct ExprStructField {
466 pub field_name: Ident,
467 pub expr_opt: Option<(ColonToken, Box<Expr>)>,
468}
469
470impl Spanned for ExprStructField {
471 fn span(&self) -> Span {
472 match &self.expr_opt {
473 None => self.field_name.span(),
474 Some((_colon_token, expr)) => Span::join(self.field_name.span(), &expr.span()),
475 }
476 }
477}
478
479impl Expr {
480 pub fn try_into_assignable(self) -> Result<Assignable, Expr> {
488 if let Expr::Deref { star_token, expr } = self {
489 Ok(Assignable::Deref { star_token, expr })
490 } else {
491 Ok(Assignable::ElementAccess(
492 self.try_into_element_access(false)?,
493 ))
494 }
495 }
496
497 fn try_into_element_access(
498 self,
499 accept_deref_without_parens: bool,
500 ) -> Result<ElementAccess, Expr> {
501 match self.clone() {
502 Expr::Path(path_expr) => match path_expr.try_into_ident() {
503 Ok(name) => Ok(ElementAccess::Var(name)),
504 Err(path_expr) => Err(Expr::Path(path_expr)),
505 },
506 Expr::Index { target, arg } => match target.try_into_element_access(false) {
507 Ok(target) => Ok(ElementAccess::Index {
508 target: Box::new(target),
509 arg,
510 }),
511 error => error,
512 },
513 Expr::FieldProjection {
514 target,
515 dot_token,
516 name,
517 } => match target.try_into_element_access(false) {
518 Ok(target) => Ok(ElementAccess::FieldProjection {
519 target: Box::new(target),
520 dot_token,
521 name,
522 }),
523 error => error,
524 },
525 Expr::TupleFieldProjection {
526 target,
527 dot_token,
528 field,
529 field_span,
530 } => match target.try_into_element_access(false) {
531 Ok(target) => Ok(ElementAccess::TupleFieldProjection {
532 target: Box::new(target),
533 dot_token,
534 field,
535 field_span,
536 }),
537 error => error,
538 },
539 Expr::Parens(Parens { inner, .. }) => {
540 if let Expr::Deref { expr, star_token } = *inner {
541 match expr.try_into_element_access(true) {
542 Ok(target) => Ok(ElementAccess::Deref {
543 target: Box::new(target),
544 star_token,
545 is_root_element: true,
546 }),
547 error => error,
548 }
549 } else {
550 Err(self)
551 }
552 }
553 Expr::Deref { expr, star_token } if accept_deref_without_parens => {
554 match expr.try_into_element_access(true) {
555 Ok(target) => Ok(ElementAccess::Deref {
556 target: Box::new(target),
557 star_token,
558 is_root_element: false,
559 }),
560 error => error,
561 }
562 }
563 expr => Err(expr),
564 }
565 }
566
567 pub fn is_control_flow(&self) -> bool {
568 match self {
569 Expr::Block(..)
570 | Expr::Asm(..)
571 | Expr::If(..)
572 | Expr::Match { .. }
573 | Expr::While { .. }
574 | Expr::For { .. } => true,
575 Expr::Error(..)
576 | Expr::Path(..)
577 | Expr::Literal(..)
578 | Expr::AbiCast { .. }
579 | Expr::Struct { .. }
580 | Expr::Tuple(..)
581 | Expr::Parens(..)
582 | Expr::Array(..)
583 | Expr::Return { .. }
584 | Expr::Panic { .. }
585 | Expr::FuncApp { .. }
586 | Expr::Index { .. }
587 | Expr::MethodCall { .. }
588 | Expr::FieldProjection { .. }
589 | Expr::TupleFieldProjection { .. }
590 | Expr::Ref { .. }
591 | Expr::Deref { .. }
592 | Expr::Not { .. }
593 | Expr::Mul { .. }
594 | Expr::Div { .. }
595 | Expr::Pow { .. }
596 | Expr::Modulo { .. }
597 | Expr::Add { .. }
598 | Expr::Sub { .. }
599 | Expr::Shl { .. }
600 | Expr::Shr { .. }
601 | Expr::BitAnd { .. }
602 | Expr::BitXor { .. }
603 | Expr::BitOr { .. }
604 | Expr::Equal { .. }
605 | Expr::NotEqual { .. }
606 | Expr::LessThan { .. }
607 | Expr::GreaterThan { .. }
608 | Expr::LessThanEq { .. }
609 | Expr::GreaterThanEq { .. }
610 | Expr::LogicalAnd { .. }
611 | Expr::LogicalOr { .. }
612 | Expr::Reassignment { .. }
613 | Expr::Break { .. }
614 | Expr::Continue { .. } => false,
615 }
616 }
617
618 pub fn friendly_name(&self) -> &'static str {
620 match self {
621 Expr::Error(_, _) => "error",
622 Expr::Path(_) => "path",
623 Expr::Literal(_) => "literal",
624 Expr::AbiCast { .. } => "ABI cast",
625 Expr::Struct { .. } => "struct instantiation",
626 Expr::Tuple(_) => "tuple",
627 Expr::Parens(_) => "parentheses", Expr::Block(_) => "block",
629 Expr::Array(_) => "array",
630 Expr::Asm(_) => "assembly block",
631 Expr::Return { .. } => "return",
632 Expr::Panic { .. } => "panic",
633 Expr::If(_) => "if expression",
634 Expr::Match { .. } => "match expression",
635 Expr::While { .. } => "while loop",
636 Expr::For { .. } => "for loop",
637 Expr::FuncApp { .. } => "function call",
638 Expr::Index { .. } => "array element access",
639 Expr::MethodCall { .. } => "method call",
640 Expr::FieldProjection { .. } => "struct field access",
641 Expr::TupleFieldProjection { .. } => "tuple element access",
642 Expr::Ref { .. } => "referencing",
643 Expr::Deref { .. } => "dereferencing",
644 Expr::Not { .. } => "negation",
645 Expr::Mul { .. } => "multiplication",
646 Expr::Div { .. } => "division",
647 Expr::Pow { .. } => "power operation",
648 Expr::Modulo { .. } => "modulo operation",
649 Expr::Add { .. } => "addition",
650 Expr::Sub { .. } => "subtraction",
651 Expr::Shl { .. } => "left shift",
652 Expr::Shr { .. } => "right shift",
653 Expr::BitAnd { .. } => "bitwise and",
654 Expr::BitXor { .. } => "bitwise xor",
655 Expr::BitOr { .. } => "bitwise or",
656 Expr::Equal { .. } => "equality",
657 Expr::NotEqual { .. } => "non equality",
658 Expr::LessThan { .. } => "less than operation",
659 Expr::GreaterThan { .. } => "greater than operation",
660 Expr::LessThanEq { .. } => "less than or equal operation",
661 Expr::GreaterThanEq { .. } => "greater than or equal operation",
662 Expr::LogicalAnd { .. } => "logical and",
663 Expr::LogicalOr { .. } => "logical or",
664 Expr::Reassignment { .. } => "reassignment",
665 Expr::Break { .. } => "break",
666 Expr::Continue { .. } => "continue",
667 }
668 }
669}