miden_core/mast/node/
loop_node.rs1use alloc::{boxed::Box, vec::Vec};
2use core::fmt;
3
4use miden_crypto::{Felt, Word};
5use miden_formatting::prettier::PrettyPrint;
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9use super::{MastNodeErrorContext, MastNodeExt};
10use crate::{
11 Idx, OPCODE_LOOP,
12 chiplets::hasher,
13 mast::{DecoratedOpLink, DecoratorId, MastForest, MastForestError, MastNodeId, Remapping},
14};
15
16#[derive(Debug, Clone, PartialEq, Eq)]
26#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
27pub struct LoopNode {
28 body: MastNodeId,
29 digest: Word,
30 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Vec::is_empty"))]
31 before_enter: Vec<DecoratorId>,
32 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Vec::is_empty"))]
33 after_exit: Vec<DecoratorId>,
34}
35
36impl LoopNode {
38 pub const DOMAIN: Felt = Felt::new(OPCODE_LOOP as u64);
40}
41
42impl LoopNode {
44 pub fn new(body: MastNodeId, mast_forest: &MastForest) -> Result<Self, MastForestError> {
46 if body.to_usize() >= mast_forest.nodes.len() {
47 return Err(MastForestError::NodeIdOverflow(body, mast_forest.nodes.len()));
48 }
49 let digest = {
50 let body_hash = mast_forest[body].digest();
51
52 hasher::merge_in_domain(&[body_hash, Word::default()], Self::DOMAIN)
53 };
54
55 Ok(Self {
56 body,
57 digest,
58 before_enter: Vec::new(),
59 after_exit: Vec::new(),
60 })
61 }
62
63 pub fn new_unsafe(body: MastNodeId, digest: Word) -> Self {
66 Self {
67 body,
68 digest,
69 before_enter: Vec::new(),
70 after_exit: Vec::new(),
71 }
72 }
73}
74
75impl LoopNode {
76 pub fn body(&self) -> MastNodeId {
78 self.body
79 }
80}
81
82impl MastNodeErrorContext for LoopNode {
83 fn decorators(&self) -> impl Iterator<Item = DecoratedOpLink> {
84 self.before_enter.iter().chain(&self.after_exit).copied().enumerate()
85 }
86}
87
88impl LoopNode {
92 pub(super) fn to_display<'a>(&'a self, mast_forest: &'a MastForest) -> impl fmt::Display + 'a {
93 LoopNodePrettyPrint { loop_node: self, mast_forest }
94 }
95
96 pub(super) fn to_pretty_print<'a>(
97 &'a self,
98 mast_forest: &'a MastForest,
99 ) -> impl PrettyPrint + 'a {
100 LoopNodePrettyPrint { loop_node: self, mast_forest }
101 }
102}
103
104struct LoopNodePrettyPrint<'a> {
105 loop_node: &'a LoopNode,
106 mast_forest: &'a MastForest,
107}
108
109impl crate::prettier::PrettyPrint for LoopNodePrettyPrint<'_> {
110 fn render(&self) -> crate::prettier::Document {
111 use crate::prettier::*;
112
113 let pre_decorators = {
114 let mut pre_decorators = self
115 .loop_node
116 .before_enter()
117 .iter()
118 .map(|&decorator_id| self.mast_forest[decorator_id].render())
119 .reduce(|acc, doc| acc + const_text(" ") + doc)
120 .unwrap_or_default();
121 if !pre_decorators.is_empty() {
122 pre_decorators += nl();
123 }
124
125 pre_decorators
126 };
127
128 let post_decorators = {
129 let mut post_decorators = self
130 .loop_node
131 .after_exit()
132 .iter()
133 .map(|&decorator_id| self.mast_forest[decorator_id].render())
134 .reduce(|acc, doc| acc + const_text(" ") + doc)
135 .unwrap_or_default();
136 if !post_decorators.is_empty() {
137 post_decorators = nl() + post_decorators;
138 }
139
140 post_decorators
141 };
142
143 let loop_body = self.mast_forest[self.loop_node.body].to_pretty_print(self.mast_forest);
144
145 pre_decorators
146 + indent(4, const_text("while.true") + nl() + loop_body.render())
147 + nl()
148 + const_text("end")
149 + post_decorators
150 }
151}
152
153impl fmt::Display for LoopNodePrettyPrint<'_> {
154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 use crate::prettier::PrettyPrint;
156 self.pretty_print(f)
157 }
158}
159
160impl MastNodeExt for LoopNode {
164 fn digest(&self) -> Word {
175 self.digest
176 }
177
178 fn before_enter(&self) -> &[DecoratorId] {
180 &self.before_enter
181 }
182
183 fn after_exit(&self) -> &[DecoratorId] {
185 &self.after_exit
186 }
187 fn append_before_enter(&mut self, decorator_ids: &[DecoratorId]) {
189 self.before_enter.extend_from_slice(decorator_ids);
190 }
191
192 fn append_after_exit(&mut self, decorator_ids: &[DecoratorId]) {
194 self.after_exit.extend_from_slice(decorator_ids);
195 }
196
197 fn remove_decorators(&mut self) {
199 self.before_enter.truncate(0);
200 self.after_exit.truncate(0);
201 }
202
203 fn to_display<'a>(&'a self, mast_forest: &'a MastForest) -> Box<dyn fmt::Display + 'a> {
204 Box::new(LoopNode::to_display(self, mast_forest))
205 }
206
207 fn to_pretty_print<'a>(&'a self, mast_forest: &'a MastForest) -> Box<dyn PrettyPrint + 'a> {
208 Box::new(LoopNode::to_pretty_print(self, mast_forest))
209 }
210
211 fn remap_children(&self, remapping: &Remapping) -> Self {
212 let mut node = self.clone();
213 node.body = node.body.remap(remapping);
214 node
215 }
216
217 fn has_children(&self) -> bool {
218 true
219 }
220
221 fn append_children_to(&self, target: &mut Vec<MastNodeId>) {
222 target.push(self.body());
223 }
224
225 fn for_each_child<F>(&self, mut f: F)
226 where
227 F: FnMut(MastNodeId),
228 {
229 f(self.body());
230 }
231
232 fn domain(&self) -> Felt {
233 Self::DOMAIN
234 }
235}