miden_core/mast/node/
dyn_node.rs1use alloc::vec::Vec;
2use core::fmt;
3
4use miden_crypto::{Felt, Word};
5use miden_formatting::prettier::{Document, PrettyPrint, const_text, nl};
6
7use super::MastNodeExt;
8use crate::{
9 OPCODE_DYN, OPCODE_DYNCALL,
10 mast::{DecoratorId, MastForest},
11};
12
13#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct DynNode {
19 is_dyncall: bool,
20 before_enter: Vec<DecoratorId>,
21 after_exit: Vec<DecoratorId>,
22}
23
24impl DynNode {
26 pub const DYN_DOMAIN: Felt = Felt::new(OPCODE_DYN as u64);
28
29 pub const DYNCALL_DOMAIN: Felt = Felt::new(OPCODE_DYNCALL as u64);
31}
32
33impl DynNode {
35 pub fn new_dyn() -> Self {
37 Self {
38 is_dyncall: false,
39 before_enter: Vec::new(),
40 after_exit: Vec::new(),
41 }
42 }
43
44 pub fn new_dyncall() -> Self {
46 Self {
47 is_dyncall: true,
48 before_enter: Vec::new(),
49 after_exit: Vec::new(),
50 }
51 }
52
53 pub fn is_dyncall(&self) -> bool {
55 self.is_dyncall
56 }
57
58 pub fn domain(&self) -> Felt {
60 if self.is_dyncall() {
61 Self::DYNCALL_DOMAIN
62 } else {
63 Self::DYN_DOMAIN
64 }
65 }
66
67 pub fn digest(&self) -> Word {
79 if self.is_dyncall {
80 Word::new([
81 Felt::new(8751004906421739448),
82 Felt::new(13469709002495534233),
83 Felt::new(12584249374630430826),
84 Felt::new(7624899870831503004),
85 ])
86 } else {
87 Word::new([
88 Felt::new(8115106948140260551),
89 Felt::new(13491227816952616836),
90 Felt::new(15015806788322198710),
91 Felt::new(16575543461540527115),
92 ])
93 }
94 }
95
96 pub fn before_enter(&self) -> &[DecoratorId] {
98 &self.before_enter
99 }
100
101 pub fn after_exit(&self) -> &[DecoratorId] {
103 &self.after_exit
104 }
105}
106
107impl DynNode {
110 pub fn append_before_enter(&mut self, decorator_ids: &[DecoratorId]) {
112 self.before_enter.extend_from_slice(decorator_ids);
113 }
114
115 pub fn append_after_exit(&mut self, decorator_ids: &[DecoratorId]) {
117 self.after_exit.extend_from_slice(decorator_ids);
118 }
119
120 pub fn remove_decorators(&mut self) {
122 self.before_enter.truncate(0);
123 self.after_exit.truncate(0);
124 }
125}
126
127impl MastNodeExt for DynNode {
128 fn decorators(&self) -> impl Iterator<Item = (usize, DecoratorId)> {
129 self.before_enter.iter().chain(&self.after_exit).copied().enumerate()
130 }
131}
132
133impl DynNode {
137 pub(super) fn to_display<'a>(&'a self, mast_forest: &'a MastForest) -> impl fmt::Display + 'a {
138 DynNodePrettyPrint { node: self, mast_forest }
139 }
140
141 pub(super) fn to_pretty_print<'a>(
142 &'a self,
143 mast_forest: &'a MastForest,
144 ) -> impl PrettyPrint + 'a {
145 DynNodePrettyPrint { node: self, mast_forest }
146 }
147}
148
149struct DynNodePrettyPrint<'a> {
150 node: &'a DynNode,
151 mast_forest: &'a MastForest,
152}
153
154impl DynNodePrettyPrint<'_> {
155 fn concatenate_decorators(
158 &self,
159 decorator_ids: &[DecoratorId],
160 prepend: Document,
161 append: Document,
162 ) -> Document {
163 let decorators = decorator_ids
164 .iter()
165 .map(|&decorator_id| self.mast_forest[decorator_id].render())
166 .reduce(|acc, doc| acc + const_text(" ") + doc)
167 .unwrap_or_default();
168
169 if decorators.is_empty() {
170 decorators
171 } else {
172 prepend + decorators + append
173 }
174 }
175
176 fn single_line_pre_decorators(&self) -> Document {
177 self.concatenate_decorators(self.node.before_enter(), Document::Empty, const_text(" "))
178 }
179
180 fn single_line_post_decorators(&self) -> Document {
181 self.concatenate_decorators(self.node.after_exit(), const_text(" "), Document::Empty)
182 }
183
184 fn multi_line_pre_decorators(&self) -> Document {
185 self.concatenate_decorators(self.node.before_enter(), Document::Empty, nl())
186 }
187
188 fn multi_line_post_decorators(&self) -> Document {
189 self.concatenate_decorators(self.node.after_exit(), nl(), Document::Empty)
190 }
191}
192
193impl crate::prettier::PrettyPrint for DynNodePrettyPrint<'_> {
194 fn render(&self) -> crate::prettier::Document {
195 let dyn_text = if self.node.is_dyncall() {
196 const_text("dyncall")
197 } else {
198 const_text("dyn")
199 };
200
201 let single_line = self.single_line_pre_decorators()
202 + dyn_text.clone()
203 + self.single_line_post_decorators();
204 let multi_line =
205 self.multi_line_pre_decorators() + dyn_text + self.multi_line_post_decorators();
206
207 single_line | multi_line
208 }
209}
210
211impl fmt::Display for DynNodePrettyPrint<'_> {
212 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213 self.pretty_print(f)
214 }
215}
216
217#[cfg(test)]
221mod tests {
222 use miden_crypto::hash::rpo::Rpo256;
223
224 use super::*;
225
226 #[test]
229 pub fn test_dyn_node_digest() {
230 assert_eq!(
231 DynNode::new_dyn().digest(),
232 Rpo256::merge_in_domain(&[Word::default(), Word::default()], DynNode::DYN_DOMAIN)
233 );
234
235 assert_eq!(
236 DynNode::new_dyncall().digest(),
237 Rpo256::merge_in_domain(&[Word::default(), Word::default()], DynNode::DYNCALL_DOMAIN)
238 );
239 }
240}