1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use alloc::vec::Vec;
use core::fmt;

use super::Op;
use crate::{SourceSpan, Spanned};

// BASIC BLOCK
// ================================================================================================

/// Represents a basic block in Miden Assembly syntax.
///
/// Blocks can be nested, see [Op] for details.
#[derive(Clone, Default)]
pub struct Block {
    span: SourceSpan,
    body: Vec<Op>,
}

impl Block {
    /// Creates a new [Block].
    pub fn new(span: SourceSpan, body: Vec<Op>) -> Self {
        Self { span, body }
    }

    /// Appends `op` to this block.
    pub fn push(&mut self, op: Op) {
        self.body.push(op);
    }

    /// Returns the number of ops in this block.
    ///
    /// NOTE: The count does not include nested ops,
    /// only those at the root of the block.
    pub fn len(&self) -> usize {
        self.body.len()
    }

    /// Returns true if this block is empty
    pub fn is_empty(&self) -> bool {
        self.body.is_empty()
    }

    /// Returns an iterator for the operations in this block.
    pub fn iter(&self) -> core::slice::Iter<'_, Op> {
        self.body.iter()
    }

    /// Returns a mutable iterator for the operations in this block.
    pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, Op> {
        self.body.iter_mut()
    }
}

impl fmt::Debug for Block {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_list().entries(&self.body).finish()
    }
}

impl crate::prettier::PrettyPrint for Block {
    fn render(&self) -> crate::prettier::Document {
        use crate::{ast::Instruction, prettier::*, Span};

        // If a block is empty, pretty-print it with a `nop` instruction
        let default_body = [Op::Inst(Span::new(self.span, Instruction::Nop))];
        let body = match self.body.as_slice() {
            [] => default_body.as_slice().iter(),
            body => body.iter(),
        }
        .map(PrettyPrint::render)
        .reduce(|acc, doc| acc + nl() + doc);

        body.map(|body| indent(4, body)).unwrap_or(Document::Empty)
    }
}

impl Spanned for Block {
    fn span(&self) -> SourceSpan {
        self.span
    }
}

impl Eq for Block {}

impl PartialEq for Block {
    fn eq(&self, other: &Self) -> bool {
        self.body == other.body
    }
}