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 crate::{
8 OPCODE_LOOP,
9 chiplets::hasher,
10 mast::{DecoratorId, MastForest, MastForestError, MastNodeId, Remapping},
11};
12
13#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct LoopNode {
24 body: MastNodeId,
25 digest: RpoDigest,
26 before_enter: Vec<DecoratorId>,
27 after_exit: Vec<DecoratorId>,
28}
29
30impl LoopNode {
32 pub const DOMAIN: Felt = Felt::new(OPCODE_LOOP as u64);
34}
35
36impl LoopNode {
38 pub fn new(body: MastNodeId, mast_forest: &MastForest) -> Result<Self, MastForestError> {
40 if body.as_usize() >= mast_forest.nodes.len() {
41 return Err(MastForestError::NodeIdOverflow(body, mast_forest.nodes.len()));
42 }
43 let digest = {
44 let body_hash = mast_forest[body].digest();
45
46 hasher::merge_in_domain(&[body_hash, RpoDigest::default()], Self::DOMAIN)
47 };
48
49 Ok(Self {
50 body,
51 digest,
52 before_enter: Vec::new(),
53 after_exit: Vec::new(),
54 })
55 }
56
57 pub fn new_unsafe(body: MastNodeId, digest: RpoDigest) -> Self {
60 Self {
61 body,
62 digest,
63 before_enter: Vec::new(),
64 after_exit: Vec::new(),
65 }
66 }
67}
68
69impl LoopNode {
70 pub fn digest(&self) -> RpoDigest {
81 self.digest
82 }
83
84 pub fn body(&self) -> MastNodeId {
86 self.body
87 }
88
89 pub fn before_enter(&self) -> &[DecoratorId] {
91 &self.before_enter
92 }
93
94 pub fn after_exit(&self) -> &[DecoratorId] {
96 &self.after_exit
97 }
98}
99
100impl LoopNode {
102 pub fn remap_children(&self, remapping: &Remapping) -> Self {
103 let mut node = self.clone();
104 node.body = node.body.remap(remapping);
105 node
106 }
107
108 pub fn set_before_enter(&mut self, decorator_ids: Vec<DecoratorId>) {
110 self.before_enter = decorator_ids;
111 }
112
113 pub fn set_after_exit(&mut self, decorator_ids: Vec<DecoratorId>) {
115 self.after_exit = decorator_ids;
116 }
117}
118
119impl LoopNode {
123 pub(super) fn to_display<'a>(&'a self, mast_forest: &'a MastForest) -> impl fmt::Display + 'a {
124 LoopNodePrettyPrint { loop_node: self, mast_forest }
125 }
126
127 pub(super) fn to_pretty_print<'a>(
128 &'a self,
129 mast_forest: &'a MastForest,
130 ) -> impl PrettyPrint + 'a {
131 LoopNodePrettyPrint { loop_node: self, mast_forest }
132 }
133}
134
135struct LoopNodePrettyPrint<'a> {
136 loop_node: &'a LoopNode,
137 mast_forest: &'a MastForest,
138}
139
140impl crate::prettier::PrettyPrint for LoopNodePrettyPrint<'_> {
141 fn render(&self) -> crate::prettier::Document {
142 use crate::prettier::*;
143
144 let pre_decorators = {
145 let mut pre_decorators = self
146 .loop_node
147 .before_enter()
148 .iter()
149 .map(|&decorator_id| self.mast_forest[decorator_id].render())
150 .reduce(|acc, doc| acc + const_text(" ") + doc)
151 .unwrap_or_default();
152 if !pre_decorators.is_empty() {
153 pre_decorators += nl();
154 }
155
156 pre_decorators
157 };
158
159 let post_decorators = {
160 let mut post_decorators = self
161 .loop_node
162 .after_exit()
163 .iter()
164 .map(|&decorator_id| self.mast_forest[decorator_id].render())
165 .reduce(|acc, doc| acc + const_text(" ") + doc)
166 .unwrap_or_default();
167 if !post_decorators.is_empty() {
168 post_decorators = nl() + post_decorators;
169 }
170
171 post_decorators
172 };
173
174 let loop_body = self.mast_forest[self.loop_node.body].to_pretty_print(self.mast_forest);
175
176 pre_decorators
177 + indent(4, const_text("while.true") + nl() + loop_body.render())
178 + nl()
179 + const_text("end")
180 + post_decorators
181 }
182}
183
184impl fmt::Display for LoopNodePrettyPrint<'_> {
185 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186 use crate::prettier::PrettyPrint;
187 self.pretty_print(f)
188 }
189}