miden_assembly/ast/
op.rs

1use core::fmt;
2
3use super::{Block, Instruction};
4use crate::{SourceSpan, Span, Spanned};
5
6/// Represents the Miden Assembly instruction set syntax
7///
8/// This is separate from [Instruction] in order to distinguish control flow instructions and
9/// instructions with block regions from the rest.
10#[derive(Clone)]
11#[repr(u8)]
12pub enum Op {
13    /// Represents a conditional branch
14    ///
15    /// Can be either `if`..`end`, or `if`..`else`..`end`.
16    If {
17        span: SourceSpan,
18        /// This block is always present and non-empty
19        then_blk: Block,
20        /// This block will be empty if no `else` branch was present
21        else_blk: Block,
22    } = 0,
23    /// Represents a condition-controlled loop
24    While { span: SourceSpan, body: Block } = 1,
25    /// Represents a counter-controlled loop.
26    ///
27    /// NOTE: The iteration count must be known at compile-time, so this is _not_ used for general
28    /// `for`-style loops where the iteration count is dynamic.
29    Repeat {
30        span: SourceSpan,
31        count: u32,
32        body: Block,
33    } = 2,
34    /// A primitive operation, e.g. `add`
35    Inst(Span<Instruction>) = 3,
36}
37
38impl crate::prettier::PrettyPrint for Op {
39    fn render(&self) -> crate::prettier::Document {
40        use crate::prettier::*;
41
42        match self {
43            Self::If { then_blk, else_blk, .. } => {
44                text("if.true")
45                    + nl()
46                    + then_blk.render()
47                    + nl()
48                    + text("else")
49                    + nl()
50                    + else_blk.render()
51                    + nl()
52                    + text("end")
53            },
54            Self::While { body, .. } => {
55                text("while.true") + nl() + body.render() + nl() + text("end")
56            },
57            Self::Repeat { count, body, .. } => {
58                display(format!("repeat.{count}")) + nl() + body.render() + nl() + text("end")
59            },
60            Self::Inst(inst) => inst.render(),
61        }
62    }
63}
64
65impl fmt::Debug for Op {
66    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67        match self {
68            Self::If { then_blk, else_blk, .. } => {
69                f.debug_struct("If").field("then", then_blk).field("else", else_blk).finish()
70            },
71            Self::While { body, .. } => f.debug_tuple("While").field(body).finish(),
72            Self::Repeat { count, body, .. } => {
73                f.debug_struct("Repeat").field("count", count).field("body", body).finish()
74            },
75            Self::Inst(inst) => fmt::Debug::fmt(&**inst, f),
76        }
77    }
78}
79
80impl Eq for Op {}
81
82impl PartialEq for Op {
83    fn eq(&self, other: &Self) -> bool {
84        match (self, other) {
85            (
86                Self::If { then_blk: lt, else_blk: le, .. },
87                Self::If { then_blk: rt, else_blk: re, .. },
88            ) => lt == rt && le == re,
89            (Self::While { body: lbody, .. }, Self::While { body: rbody, .. }) => lbody == rbody,
90            (
91                Self::Repeat { count: lcount, body: lbody, .. },
92                Self::Repeat { count: rcount, body: rbody, .. },
93            ) => lcount == rcount && lbody == rbody,
94            (Self::Inst(l), Self::Inst(r)) => l == r,
95            _ => false,
96        }
97    }
98}
99
100impl Spanned for Op {
101    fn span(&self) -> SourceSpan {
102        match self {
103            Self::If { span, .. } | Self::While { span, .. } | Self::Repeat { span, .. } => *span,
104            Self::Inst(spanned) => spanned.span(),
105        }
106    }
107}