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(self.try_into_element_access()?))
477 }
478 }
479
480 fn try_into_element_access(self) -> Result<ElementAccess, Expr> {
481 match self {
482 Expr::Path(path_expr) => match path_expr.try_into_ident() {
483 Ok(name) => Ok(ElementAccess::Var(name)),
484 Err(path_expr) => Err(Expr::Path(path_expr)),
485 },
486 Expr::Index { target, arg } => match target.try_into_element_access() {
487 Ok(target) => Ok(ElementAccess::Index {
488 target: Box::new(target),
489 arg,
490 }),
491 error => error,
492 },
493 Expr::FieldProjection {
494 target,
495 dot_token,
496 name,
497 } => match target.try_into_element_access() {
498 Ok(target) => Ok(ElementAccess::FieldProjection {
499 target: Box::new(target),
500 dot_token,
501 name,
502 }),
503 error => error,
504 },
505 Expr::TupleFieldProjection {
506 target,
507 dot_token,
508 field,
509 field_span,
510 } => match target.try_into_element_access() {
511 Ok(target) => Ok(ElementAccess::TupleFieldProjection {
512 target: Box::new(target),
513 dot_token,
514 field,
515 field_span,
516 }),
517 error => error,
518 },
519 expr => Err(expr),
520 }
521 }
522
523 pub fn is_control_flow(&self) -> bool {
524 match self {
525 Expr::Block(..)
526 | Expr::Asm(..)
527 | Expr::If(..)
528 | Expr::Match { .. }
529 | Expr::While { .. }
530 | Expr::For { .. } => true,
531 Expr::Error(..)
532 | Expr::Path(..)
533 | Expr::Literal(..)
534 | Expr::AbiCast { .. }
535 | Expr::Struct { .. }
536 | Expr::Tuple(..)
537 | Expr::Parens(..)
538 | Expr::Array(..)
539 | Expr::Return { .. }
540 | Expr::FuncApp { .. }
541 | Expr::Index { .. }
542 | Expr::MethodCall { .. }
543 | Expr::FieldProjection { .. }
544 | Expr::TupleFieldProjection { .. }
545 | Expr::Ref { .. }
546 | Expr::Deref { .. }
547 | Expr::Not { .. }
548 | Expr::Mul { .. }
549 | Expr::Div { .. }
550 | Expr::Pow { .. }
551 | Expr::Modulo { .. }
552 | Expr::Add { .. }
553 | Expr::Sub { .. }
554 | Expr::Shl { .. }
555 | Expr::Shr { .. }
556 | Expr::BitAnd { .. }
557 | Expr::BitXor { .. }
558 | Expr::BitOr { .. }
559 | Expr::Equal { .. }
560 | Expr::NotEqual { .. }
561 | Expr::LessThan { .. }
562 | Expr::GreaterThan { .. }
563 | Expr::LessThanEq { .. }
564 | Expr::GreaterThanEq { .. }
565 | Expr::LogicalAnd { .. }
566 | Expr::LogicalOr { .. }
567 | Expr::Reassignment { .. }
568 | Expr::Break { .. }
569 | Expr::Continue { .. } => false,
570 }
571 }
572
573 pub fn friendly_name(&self) -> &'static str {
575 match self {
576 Expr::Error(_, _) => "error",
577 Expr::Path(_) => "path",
578 Expr::Literal(_) => "literal",
579 Expr::AbiCast { .. } => "ABI cast",
580 Expr::Struct { .. } => "struct instantiation",
581 Expr::Tuple(_) => "tuple",
582 Expr::Parens(_) => "parentheses", Expr::Block(_) => "block",
584 Expr::Array(_) => "array",
585 Expr::Asm(_) => "assembly block",
586 Expr::Return { .. } => "return",
587 Expr::If(_) => "if expression",
588 Expr::Match { .. } => "match expression",
589 Expr::While { .. } => "while loop",
590 Expr::For { .. } => "for loop",
591 Expr::FuncApp { .. } => "function call",
592 Expr::Index { .. } => "array element access",
593 Expr::MethodCall { .. } => "method call",
594 Expr::FieldProjection { .. } => "struct field access",
595 Expr::TupleFieldProjection { .. } => "tuple element access",
596 Expr::Ref { .. } => "referencing",
597 Expr::Deref { .. } => "dereferencing",
598 Expr::Not { .. } => "negation",
599 Expr::Mul { .. } => "multiplication",
600 Expr::Div { .. } => "division",
601 Expr::Pow { .. } => "power operation",
602 Expr::Modulo { .. } => "modulo operation",
603 Expr::Add { .. } => "addition",
604 Expr::Sub { .. } => "subtraction",
605 Expr::Shl { .. } => "left shift",
606 Expr::Shr { .. } => "right shift",
607 Expr::BitAnd { .. } => "bitwise and",
608 Expr::BitXor { .. } => "bitwise xor",
609 Expr::BitOr { .. } => "bitwise or",
610 Expr::Equal { .. } => "equality",
611 Expr::NotEqual { .. } => "non equality",
612 Expr::LessThan { .. } => "less than operation",
613 Expr::GreaterThan { .. } => "greater than operation",
614 Expr::LessThanEq { .. } => "less than or equal operation",
615 Expr::GreaterThanEq { .. } => "greater than or equal operation",
616 Expr::LogicalAnd { .. } => "logical and",
617 Expr::LogicalOr { .. } => "logical or",
618 Expr::Reassignment { .. } => "reassignment",
619 Expr::Break { .. } => "break",
620 Expr::Continue { .. } => "continue",
621 }
622 }
623}