miden_core/mast/node/
dyn_node.rs1use alloc::vec::Vec;
2use core::fmt;
3
4use miden_crypto::{hash::rpo::RpoDigest, Felt};
5use miden_formatting::prettier::{const_text, nl, Document, PrettyPrint};
6
7use crate::{
8 mast::{DecoratorId, MastForest},
9 OPCODE_DYN, OPCODE_DYNCALL,
10};
11
12#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct DynNode {
18 is_dyncall: bool,
19 before_enter: Vec<DecoratorId>,
20 after_exit: Vec<DecoratorId>,
21}
22
23impl DynNode {
25 pub const DYN_DOMAIN: Felt = Felt::new(OPCODE_DYN as u64);
27
28 pub const DYNCALL_DOMAIN: Felt = Felt::new(OPCODE_DYNCALL as u64);
30}
31
32impl DynNode {
34 pub fn new_dyn() -> Self {
36 Self {
37 is_dyncall: false,
38 before_enter: Vec::new(),
39 after_exit: Vec::new(),
40 }
41 }
42
43 pub fn new_dyncall() -> Self {
45 Self {
46 is_dyncall: true,
47 before_enter: Vec::new(),
48 after_exit: Vec::new(),
49 }
50 }
51
52 pub fn is_dyncall(&self) -> bool {
54 self.is_dyncall
55 }
56
57 pub fn domain(&self) -> Felt {
59 if self.is_dyncall() {
60 Self::DYNCALL_DOMAIN
61 } else {
62 Self::DYN_DOMAIN
63 }
64 }
65
66 pub fn digest(&self) -> RpoDigest {
78 if self.is_dyncall {
79 RpoDigest::new([
80 Felt::new(8751004906421739448),
81 Felt::new(13469709002495534233),
82 Felt::new(12584249374630430826),
83 Felt::new(7624899870831503004),
84 ])
85 } else {
86 RpoDigest::new([
87 Felt::new(8115106948140260551),
88 Felt::new(13491227816952616836),
89 Felt::new(15015806788322198710),
90 Felt::new(16575543461540527115),
91 ])
92 }
93 }
94
95 pub fn before_enter(&self) -> &[DecoratorId] {
97 &self.before_enter
98 }
99
100 pub fn after_exit(&self) -> &[DecoratorId] {
102 &self.after_exit
103 }
104}
105
106impl DynNode {
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 DynNode {
123 pub(super) fn to_display<'a>(&'a self, mast_forest: &'a MastForest) -> impl fmt::Display + 'a {
124 DynNodePrettyPrint { 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 DynNodePrettyPrint { node: self, mast_forest }
132 }
133}
134
135struct DynNodePrettyPrint<'a> {
136 node: &'a DynNode,
137 mast_forest: &'a MastForest,
138}
139
140impl DynNodePrettyPrint<'_> {
141 fn concatenate_decorators(
144 &self,
145 decorator_ids: &[DecoratorId],
146 prepend: Document,
147 append: Document,
148 ) -> Document {
149 let decorators = decorator_ids
150 .iter()
151 .map(|&decorator_id| self.mast_forest[decorator_id].render())
152 .reduce(|acc, doc| acc + const_text(" ") + doc)
153 .unwrap_or_default();
154
155 if decorators.is_empty() {
156 decorators
157 } else {
158 prepend + decorators + append
159 }
160 }
161
162 fn single_line_pre_decorators(&self) -> Document {
163 self.concatenate_decorators(self.node.before_enter(), Document::Empty, const_text(" "))
164 }
165
166 fn single_line_post_decorators(&self) -> Document {
167 self.concatenate_decorators(self.node.after_exit(), const_text(" "), Document::Empty)
168 }
169
170 fn multi_line_pre_decorators(&self) -> Document {
171 self.concatenate_decorators(self.node.before_enter(), Document::Empty, nl())
172 }
173
174 fn multi_line_post_decorators(&self) -> Document {
175 self.concatenate_decorators(self.node.after_exit(), nl(), Document::Empty)
176 }
177}
178
179impl crate::prettier::PrettyPrint for DynNodePrettyPrint<'_> {
180 fn render(&self) -> crate::prettier::Document {
181 let dyn_text = if self.node.is_dyncall() {
182 const_text("dyncall")
183 } else {
184 const_text("dyn")
185 };
186
187 let single_line = self.single_line_pre_decorators()
188 + dyn_text.clone()
189 + self.single_line_post_decorators();
190 let multi_line =
191 self.multi_line_pre_decorators() + dyn_text + self.multi_line_post_decorators();
192
193 single_line | multi_line
194 }
195}
196
197impl fmt::Display for DynNodePrettyPrint<'_> {
198 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 self.pretty_print(f)
200 }
201}
202
203#[cfg(test)]
207mod tests {
208 use miden_crypto::hash::rpo::Rpo256;
209
210 use super::*;
211
212 #[test]
215 pub fn test_dyn_node_digest() {
216 assert_eq!(
217 DynNode::new_dyn().digest(),
218 Rpo256::merge_in_domain(
219 &[RpoDigest::default(), RpoDigest::default()],
220 DynNode::DYN_DOMAIN
221 )
222 );
223
224 assert_eq!(
225 DynNode::new_dyncall().digest(),
226 Rpo256::merge_in_domain(
227 &[RpoDigest::default(), RpoDigest::default()],
228 DynNode::DYNCALL_DOMAIN
229 )
230 );
231 }
232}