miden_core/mast/node/
dyn_node.rs1use alloc::vec::Vec;
2use core::fmt;
3
4use miden_crypto::{Felt, hash::rpo::RpoDigest};
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) -> RpoDigest {
79 if self.is_dyncall {
80 RpoDigest::new([
81 Felt::new(8751004906421739448),
82 Felt::new(13469709002495534233),
83 Felt::new(12584249374630430826),
84 Felt::new(7624899870831503004),
85 ])
86 } else {
87 RpoDigest::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 {
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 DynNode {
121 fn decorators(&self) -> impl Iterator<Item = (usize, DecoratorId)> {
122 self.before_enter.iter().chain(&self.after_exit).copied().enumerate()
123 }
124}
125
126impl DynNode {
130 pub(super) fn to_display<'a>(&'a self, mast_forest: &'a MastForest) -> impl fmt::Display + 'a {
131 DynNodePrettyPrint { 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 DynNodePrettyPrint { node: self, mast_forest }
139 }
140}
141
142struct DynNodePrettyPrint<'a> {
143 node: &'a DynNode,
144 mast_forest: &'a MastForest,
145}
146
147impl DynNodePrettyPrint<'_> {
148 fn concatenate_decorators(
151 &self,
152 decorator_ids: &[DecoratorId],
153 prepend: Document,
154 append: Document,
155 ) -> Document {
156 let decorators = decorator_ids
157 .iter()
158 .map(|&decorator_id| self.mast_forest[decorator_id].render())
159 .reduce(|acc, doc| acc + const_text(" ") + doc)
160 .unwrap_or_default();
161
162 if decorators.is_empty() {
163 decorators
164 } else {
165 prepend + decorators + append
166 }
167 }
168
169 fn single_line_pre_decorators(&self) -> Document {
170 self.concatenate_decorators(self.node.before_enter(), Document::Empty, const_text(" "))
171 }
172
173 fn single_line_post_decorators(&self) -> Document {
174 self.concatenate_decorators(self.node.after_exit(), const_text(" "), Document::Empty)
175 }
176
177 fn multi_line_pre_decorators(&self) -> Document {
178 self.concatenate_decorators(self.node.before_enter(), Document::Empty, nl())
179 }
180
181 fn multi_line_post_decorators(&self) -> Document {
182 self.concatenate_decorators(self.node.after_exit(), nl(), Document::Empty)
183 }
184}
185
186impl crate::prettier::PrettyPrint for DynNodePrettyPrint<'_> {
187 fn render(&self) -> crate::prettier::Document {
188 let dyn_text = if self.node.is_dyncall() {
189 const_text("dyncall")
190 } else {
191 const_text("dyn")
192 };
193
194 let single_line = self.single_line_pre_decorators()
195 + dyn_text.clone()
196 + self.single_line_post_decorators();
197 let multi_line =
198 self.multi_line_pre_decorators() + dyn_text + self.multi_line_post_decorators();
199
200 single_line | multi_line
201 }
202}
203
204impl fmt::Display for DynNodePrettyPrint<'_> {
205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206 self.pretty_print(f)
207 }
208}
209
210#[cfg(test)]
214mod tests {
215 use miden_crypto::hash::rpo::Rpo256;
216
217 use super::*;
218
219 #[test]
222 pub fn test_dyn_node_digest() {
223 assert_eq!(
224 DynNode::new_dyn().digest(),
225 Rpo256::merge_in_domain(
226 &[RpoDigest::default(), RpoDigest::default()],
227 DynNode::DYN_DOMAIN
228 )
229 );
230
231 assert_eq!(
232 DynNode::new_dyncall().digest(),
233 Rpo256::merge_in_domain(
234 &[RpoDigest::default(), RpoDigest::default()],
235 DynNode::DYNCALL_DOMAIN
236 )
237 );
238 }
239}