miden_core/mast/node/
loop_node.rs1use alloc::vec::Vec;
2use core::fmt;
3
4use miden_crypto::{Felt, hash::rpo::RpoDigest};
5use miden_formatting::prettier::PrettyPrint;
6
7use super::MastNodeExt;
8use crate::{
9 OPCODE_LOOP,
10 chiplets::hasher,
11 mast::{DecoratorId, MastForest, MastForestError, MastNodeId, Remapping},
12};
13
14#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct LoopNode {
25 body: MastNodeId,
26 digest: RpoDigest,
27 before_enter: Vec<DecoratorId>,
28 after_exit: Vec<DecoratorId>,
29}
30
31impl LoopNode {
33 pub const DOMAIN: Felt = Felt::new(OPCODE_LOOP as u64);
35}
36
37impl LoopNode {
39 pub fn new(body: MastNodeId, mast_forest: &MastForest) -> Result<Self, MastForestError> {
41 if body.as_usize() >= mast_forest.nodes.len() {
42 return Err(MastForestError::NodeIdOverflow(body, mast_forest.nodes.len()));
43 }
44 let digest = {
45 let body_hash = mast_forest[body].digest();
46
47 hasher::merge_in_domain(&[body_hash, RpoDigest::default()], Self::DOMAIN)
48 };
49
50 Ok(Self {
51 body,
52 digest,
53 before_enter: Vec::new(),
54 after_exit: Vec::new(),
55 })
56 }
57
58 pub fn new_unsafe(body: MastNodeId, digest: RpoDigest) -> Self {
61 Self {
62 body,
63 digest,
64 before_enter: Vec::new(),
65 after_exit: Vec::new(),
66 }
67 }
68}
69
70impl LoopNode {
71 pub fn digest(&self) -> RpoDigest {
82 self.digest
83 }
84
85 pub fn body(&self) -> MastNodeId {
87 self.body
88 }
89
90 pub fn before_enter(&self) -> &[DecoratorId] {
92 &self.before_enter
93 }
94
95 pub fn after_exit(&self) -> &[DecoratorId] {
97 &self.after_exit
98 }
99}
100
101impl LoopNode {
103 pub fn remap_children(&self, remapping: &Remapping) -> Self {
104 let mut node = self.clone();
105 node.body = node.body.remap(remapping);
106 node
107 }
108
109 pub fn append_before_enter(&mut self, decorator_ids: &[DecoratorId]) {
111 self.before_enter.extend_from_slice(decorator_ids);
112 }
113
114 pub fn append_after_exit(&mut self, decorator_ids: &[DecoratorId]) {
116 self.after_exit.extend_from_slice(decorator_ids);
117 }
118}
119
120impl MastNodeExt for LoopNode {
121 fn decorators(&self) -> impl Iterator<Item = (usize, DecoratorId)> {
122 self.before_enter.iter().chain(&self.after_exit).copied().enumerate()
123 }
124}
125
126impl LoopNode {
130 pub(super) fn to_display<'a>(&'a self, mast_forest: &'a MastForest) -> impl fmt::Display + 'a {
131 LoopNodePrettyPrint { loop_node: self, mast_forest }
132 }
133
134 pub(super) fn to_pretty_print<'a>(
135 &'a self,
136 mast_forest: &'a MastForest,
137 ) -> impl PrettyPrint + 'a {
138 LoopNodePrettyPrint { loop_node: self, mast_forest }
139 }
140}
141
142struct LoopNodePrettyPrint<'a> {
143 loop_node: &'a LoopNode,
144 mast_forest: &'a MastForest,
145}
146
147impl crate::prettier::PrettyPrint for LoopNodePrettyPrint<'_> {
148 fn render(&self) -> crate::prettier::Document {
149 use crate::prettier::*;
150
151 let pre_decorators = {
152 let mut pre_decorators = self
153 .loop_node
154 .before_enter()
155 .iter()
156 .map(|&decorator_id| self.mast_forest[decorator_id].render())
157 .reduce(|acc, doc| acc + const_text(" ") + doc)
158 .unwrap_or_default();
159 if !pre_decorators.is_empty() {
160 pre_decorators += nl();
161 }
162
163 pre_decorators
164 };
165
166 let post_decorators = {
167 let mut post_decorators = self
168 .loop_node
169 .after_exit()
170 .iter()
171 .map(|&decorator_id| self.mast_forest[decorator_id].render())
172 .reduce(|acc, doc| acc + const_text(" ") + doc)
173 .unwrap_or_default();
174 if !post_decorators.is_empty() {
175 post_decorators = nl() + post_decorators;
176 }
177
178 post_decorators
179 };
180
181 let loop_body = self.mast_forest[self.loop_node.body].to_pretty_print(self.mast_forest);
182
183 pre_decorators
184 + indent(4, const_text("while.true") + nl() + loop_body.render())
185 + nl()
186 + const_text("end")
187 + post_decorators
188 }
189}
190
191impl fmt::Display for LoopNodePrettyPrint<'_> {
192 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193 use crate::prettier::PrettyPrint;
194 self.pretty_print(f)
195 }
196}