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