Skip to main content

cairo_vm/
utils.rs

1use crate::types::relocatable::Relocatable;
2use lazy_static::lazy_static;
3use num_bigint::BigUint;
4use num_traits::Num;
5
6pub const PRIME_STR: &str = "0x800000000000011000000000000000000000000000000000000000000000001";
7
8#[macro_export]
9macro_rules! relocatable {
10    ($val1 : expr, $val2 : expr) => {
11        Relocatable {
12            segment_index: $val1,
13            offset: $val2,
14        }
15    };
16}
17
18lazy_static! {
19    pub static ref CAIRO_PRIME: BigUint = BigUint::from_str_radix(&PRIME_STR[2..], 16).unwrap();
20}
21
22#[macro_export]
23macro_rules! any_box {
24    ($val : expr) => {
25        Box::new($val) as Box<dyn core::any::Any>
26    };
27}
28
29pub fn is_subsequence<T: PartialEq>(subsequence: &[T], mut sequence: &[T]) -> bool {
30    for search in subsequence {
31        if let Some(index) = sequence.iter().position(|element| search == element) {
32            sequence = &sequence[index + 1..];
33        } else {
34            return false;
35        }
36    }
37    true
38}
39
40pub fn from_relocatable_to_indexes(relocatable: Relocatable) -> (usize, usize) {
41    if relocatable.segment_index.is_negative() {
42        (
43            -(relocatable.segment_index + 1) as usize,
44            relocatable.offset,
45        )
46    } else {
47        (relocatable.segment_index as usize, relocatable.offset)
48    }
49}
50
51#[cfg(test)]
52#[macro_use]
53pub mod test_utils {
54    use crate::types::exec_scope::ExecutionScopes;
55    use crate::types::relocatable::MaybeRelocatable;
56    use crate::vm::trace::trace_entry::TraceEntry;
57
58    #[macro_export]
59    macro_rules! felt_hex {
60        ($val: expr) => {
61            $crate::Felt252::from_hex($val).expect("Couldn't parse bytes")
62        };
63    }
64
65    #[macro_export]
66    macro_rules! felt_str {
67        ($val: expr) => {
68            $crate::Felt252::from_dec_str($val).expect("Couldn't parse bytes")
69        };
70    }
71
72    #[macro_export]
73    macro_rules! bigint {
74        ($val : expr) => {
75            Into::<num_bigint::BigInt>::into($val)
76        };
77    }
78    pub(crate) use bigint;
79
80    #[macro_export]
81    macro_rules! bigint_str {
82        ($val: expr) => {
83            num_bigint::BigInt::parse_bytes($val.as_bytes(), 10).expect("Couldn't parse bytes")
84        };
85        ($val: expr, $opt: expr) => {
86            num_bigint::BigInt::parse_bytes($val.as_bytes(), $opt).expect("Couldn't parse bytes")
87        };
88    }
89    pub(crate) use bigint_str;
90
91    #[macro_export]
92    macro_rules! biguint {
93        ($val : expr) => {
94            Into::<num_bigint::BigUint>::into($val as u128)
95        };
96    }
97    pub(crate) use biguint;
98
99    #[macro_export]
100    macro_rules! biguint_str {
101        ($val: expr) => {
102            num_bigint::BigUint::parse_bytes($val.as_bytes(), 10).expect("Couldn't parse bytes")
103        };
104        ($val: expr, $opt: expr) => {
105            num_bigint::BigUint::parse_bytes($val.as_bytes(), $opt).expect("Couldn't parse bytes")
106        };
107    }
108    pub(crate) use biguint_str;
109
110    impl From<(&str, u8)> for MaybeRelocatable {
111        fn from((string, radix): (&str, u8)) -> Self {
112            match radix {
113                16 => MaybeRelocatable::Int(crate::felt_hex!(string)),
114                10 => MaybeRelocatable::Int(crate::felt_str!(string)),
115                _ => panic!(" Invalid radix"),
116            }
117        }
118    }
119
120    macro_rules! segments {
121        ($( (($si:expr, $off:expr), $val:tt) ),* $(,)? ) => {
122            {
123                let mut segments = $crate::vm::vm_memory::memory_segments::MemorySegmentManager::new();
124                segments.memory = memory!($( (($si, $off), $val) ),*);
125                segments
126            }
127
128        };
129    }
130    pub(crate) use segments;
131
132    macro_rules! memory {
133        ( $( (($si:expr, $off:expr), $val:tt) ),* ) => {
134            {
135                let mut memory = $crate::vm::vm_memory::memory::Memory::new();
136                memory_from_memory!(memory, ( $( (($si, $off), $val) ),* ));
137                memory
138            }
139        };
140    }
141    pub(crate) use memory;
142
143    macro_rules! memory_from_memory {
144        ($mem: expr, ( $( (($si:expr, $off:expr), $val:tt) ),* )) => {
145            {
146                $(
147                    memory_inner!($mem, ($si, $off), $val);
148                )*
149            }
150        };
151    }
152    pub(crate) use memory_from_memory;
153
154    macro_rules! memory_inner {
155        ($mem:expr, ($si:expr, $off:expr), ($sival:expr, $offval: expr)) => {
156            let (k, v) = (($si, $off).into(), &mayberelocatable!($sival, $offval));
157            let mut res = $mem.insert(k, v);
158            while matches!(
159                res,
160                Err($crate::vm::errors::memory_errors::MemoryError::UnallocatedSegment(_))
161            ) {
162                if $si < 0 {
163                    $mem.temp_data.push(Vec::new())
164                } else {
165                    $mem.data.push(Vec::new());
166                }
167                res = $mem.insert(k, v);
168            }
169        };
170        ($mem:expr, ($si:expr, $off:expr), $val:expr) => {
171            let (k, v) = (($si, $off).into(), &mayberelocatable!($val));
172            let mut res = $mem.insert(k, v);
173            while matches!(
174                res,
175                Err($crate::vm::errors::memory_errors::MemoryError::UnallocatedSegment(_))
176            ) {
177                if $si < 0 {
178                    $mem.temp_data.push(Vec::new())
179                } else {
180                    $mem.data.push(Vec::new());
181                }
182                res = $mem.insert(k, v);
183            }
184        };
185    }
186    pub(crate) use memory_inner;
187
188    macro_rules! check_memory {
189        ( $mem: expr, $( (($si:expr, $off:expr), $val:tt) ),* $(,)? ) => {
190            $(
191                check_memory_address!($mem, ($si, $off), $val);
192            )*
193        };
194    }
195    pub(crate) use check_memory;
196
197    macro_rules! check_memory_address {
198        ($mem:expr, ($si:expr, $off:expr), ($sival:expr, $offval: expr)) => {
199            assert_eq!(
200                $mem.get(&mayberelocatable!($si, $off)).unwrap().as_ref(),
201                &mayberelocatable!($sival, $offval)
202            )
203        };
204        ($mem:expr, ($si:expr, $off:expr), $val:expr) => {
205            assert_eq!(
206                $mem.get(&mayberelocatable!($si, $off)).unwrap().as_ref(),
207                &mayberelocatable!($val)
208            )
209        };
210    }
211    pub(crate) use check_memory_address;
212
213    macro_rules! mayberelocatable {
214        ($val1 : expr, $val2 : expr) => {
215            $crate::types::relocatable::MaybeRelocatable::from(($val1, $val2))
216        };
217        ($val1 : expr) => {
218            $crate::types::relocatable::MaybeRelocatable::from(crate::Felt252::from($val1 as i128))
219        };
220    }
221    pub(crate) use mayberelocatable;
222
223    macro_rules! references {
224        ($num: expr) => {{
225            let mut references = std::collections::HashMap::<usize, HintReference>::new();
226            for i in 0..$num {
227                references.insert(i as usize, HintReference::new_simple((i as i32 - $num)));
228            }
229            references
230        }};
231    }
232    pub(crate) use references;
233
234    macro_rules! vm_with_range_check {
235        () => {{
236            let mut vm = VirtualMachine::new(false, false);
237            vm.builtin_runners = vec![
238                $crate::vm::runners::builtin_runner::RangeCheckBuiltinRunner::<8>::new(
239                    Some(8),
240                    true,
241                )
242                .into(),
243            ];
244            vm
245        }};
246    }
247    pub(crate) use vm_with_range_check;
248
249    macro_rules! cairo_runner {
250        ($program:expr) => {
251            crate::vm::runners::cairo_runner::CairoRunner::new(
252                &$program,
253                crate::types::layout_name::LayoutName::all_cairo,
254                None,
255                false,
256                false,
257                false,
258            )
259            .unwrap()
260        };
261        ($program:expr, $layout:expr) => {
262            crate::vm::runners::cairo_runner::CairoRunner::new(
263                &$program, $layout, None, false, false, false,
264            )
265            .unwrap()
266        };
267        ($program:expr, $layout:expr, $proof_mode:expr) => {
268            crate::vm::runners::cairo_runner::CairoRunner::new(
269                &$program,
270                $layout,
271                None,
272                $proof_mode,
273                false,
274                false,
275            )
276            .unwrap()
277        };
278        ($program:expr, $layout:expr, $proof_mode:expr, $trace_enabled:expr) => {
279            crate::vm::runners::cairo_runner::CairoRunner::new(
280                &$program,
281                $layout,
282                None,
283                $proof_mode,
284                $trace_enabled,
285                false,
286            )
287            .unwrap()
288        };
289    }
290    pub(crate) use cairo_runner;
291
292    pub(crate) use crate::types::program::HintsCollection;
293    pub(crate) use crate::types::program::Program;
294    pub(crate) use crate::types::program::SharedProgramData;
295    pub(crate) use std::{collections::BTreeMap, sync::Arc};
296    macro_rules! program {
297        //Empty program
298        () => {
299            Program::default()
300        };
301        //Program with builtins
302        ( $( $builtin_name: expr ),* ) => {{
303            let shared_program_data = SharedProgramData {
304                data: Vec::new(),
305                hints_collection: HintsCollection::new(&BTreeMap::new(), 0).unwrap(),
306                main: None,
307                start: None,
308                end: None,
309                error_message_attributes: Vec::new(),
310                instruction_locations: None,
311                identifiers: HashMap::new(),
312                reference_manager: Program::get_reference_list(&ReferenceManager {
313                    references: Vec::new(),
314                }),
315            };
316            Program {
317                shared_program_data: Arc::new(shared_program_data),
318                constants: HashMap::new().into(),
319                builtins: vec![$( $builtin_name ),*],
320            }
321        }};
322        ($($field:ident = $value:expr),* $(,)?) => {{
323
324            let program_flat = crate::utils::test_utils::ProgramFlat {
325                $(
326                    $field: $value,
327                )*
328                ..Default::default()
329            };
330
331            Into::<Program>::into(program_flat)
332        }};
333    }
334
335    pub(crate) use program;
336
337    pub(crate) struct ProgramFlat {
338        pub(crate) data: Vec<MaybeRelocatable>,
339        pub(crate) hints:
340            std::collections::BTreeMap<usize, Vec<crate::serde::deserialize_program::HintParams>>,
341        pub(crate) main: Option<usize>,
342        //start and end labels will only be used in proof-mode
343        pub(crate) start: Option<usize>,
344        pub(crate) end: Option<usize>,
345        pub(crate) error_message_attributes: Vec<crate::serde::deserialize_program::Attribute>,
346        pub(crate) instruction_locations: Option<
347            std::collections::HashMap<
348                usize,
349                crate::serde::deserialize_program::InstructionLocation,
350            >,
351        >,
352        pub(crate) identifiers:
353            std::collections::HashMap<String, crate::serde::deserialize_program::Identifier>,
354        pub(crate) constants: std::collections::HashMap<String, crate::Felt252>,
355        pub(crate) builtins: Vec<crate::types::builtin_name::BuiltinName>,
356        pub(crate) reference_manager: crate::serde::deserialize_program::ReferenceManager,
357    }
358
359    impl Default for ProgramFlat {
360        fn default() -> Self {
361            Self {
362                data: Default::default(),
363                hints: Default::default(),
364                main: Default::default(),
365                start: Default::default(),
366                end: Default::default(),
367                error_message_attributes: Default::default(),
368                instruction_locations: Default::default(),
369                identifiers: Default::default(),
370                constants: Default::default(),
371                builtins: Default::default(),
372                reference_manager: crate::serde::deserialize_program::ReferenceManager {
373                    references: Vec::new(),
374                },
375            }
376        }
377    }
378
379    impl From<ProgramFlat> for Program {
380        fn from(val: ProgramFlat) -> Self {
381            // NOTE: panics if hints have PCs higher than the program length
382            let hints_collection =
383                HintsCollection::new(&val.hints, val.data.len()).expect("hints are valid");
384            Program {
385                shared_program_data: Arc::new(SharedProgramData {
386                    data: val.data,
387                    hints_collection,
388                    main: val.main,
389                    start: val.start,
390                    end: val.end,
391                    error_message_attributes: val.error_message_attributes,
392                    instruction_locations: val.instruction_locations,
393                    identifiers: val.identifiers,
394                    reference_manager: Program::get_reference_list(&val.reference_manager),
395                }),
396                constants: val.constants.into(),
397                builtins: val.builtins,
398            }
399        }
400    }
401
402    macro_rules! vm {
403        () => {{
404            crate::vm::vm_core::VirtualMachine::new(false, false)
405        }};
406
407        ($use_trace:expr) => {{
408            crate::vm::vm_core::VirtualMachine::new($use_trace, false)
409        }};
410    }
411    pub(crate) use vm;
412
413    macro_rules! run_context {
414        ( $vm: expr, $pc: expr, $ap: expr, $fp: expr ) => {
415            $vm.run_context.pc = Relocatable::from((0, $pc));
416            $vm.run_context.ap = $ap;
417            $vm.run_context.fp = $fp;
418        };
419    }
420    pub(crate) use run_context;
421
422    macro_rules! ids_data {
423        ( $( $name: expr ),* ) => {
424            {
425                let ids_names = vec![$( $name ),*];
426                let references = references!(ids_names.len() as i32);
427                let mut ids_data = std::collections::HashMap::<String, HintReference>::new();
428                for (i, name) in ids_names.iter().enumerate() {
429                    ids_data.insert(ToString::to_string(name), references.get(&i).unwrap().clone());
430                }
431                ids_data
432            }
433        };
434    }
435    pub(crate) use ids_data;
436
437    macro_rules! non_continuous_ids_data {
438        ( $( ($name: expr, $offset:expr) ),* $(,)? ) => {
439            {
440                let mut ids_data = std::collections::HashMap::<String, HintReference>::new();
441                $(
442                    ids_data.insert(String::from($name), HintReference::new_simple($offset));
443                )*
444                ids_data
445            }
446        };
447    }
448    pub(crate) use non_continuous_ids_data;
449
450    #[track_caller]
451    pub(crate) fn trace_check(
452        actual: &[TraceEntry],
453        expected: &[(crate::utils::Relocatable, usize, usize)],
454    ) {
455        assert_eq!(actual.len(), expected.len());
456        for (entry, expected) in actual.iter().zip(expected.iter()) {
457            assert_eq!(&(entry.pc, entry.ap, entry.fp), expected);
458        }
459    }
460
461    macro_rules! exec_scopes_ref {
462        () => {
463            &mut crate::types::exec_scope::ExecutionScopes::new()
464        };
465    }
466    pub(crate) use exec_scopes_ref;
467
468    macro_rules! run_hint {
469        ($vm:expr, $ids_data:expr, $hint_code:expr, $exec_scopes:expr, $constants:expr) => {{
470            let mut hint_data = HintProcessorData::new_default($hint_code.to_string(), $ids_data);
471            let constants: &HashMap<String, Felt252> = $constants;
472            hint_data.constants = constants.clone().into();
473            let mut hint_processor = BuiltinHintProcessor::new_empty();
474            hint_processor.execute_hint(&mut $vm, $exec_scopes, &any_box!(hint_data))
475        }};
476        ($vm:expr, $ids_data:expr, $hint_code:expr, $exec_scopes:expr) => {{
477            let hint_data =
478                HintProcessorData::new_default(ToString::to_string($hint_code), $ids_data);
479            let mut hint_processor = BuiltinHintProcessor::new_empty();
480            hint_processor.execute_hint(&mut $vm, $exec_scopes, &any_box!(hint_data))
481        }};
482        ($vm:expr, $ids_data:expr, $hint_code:expr) => {{
483            let hint_data =
484                HintProcessorData::new_default(ToString::to_string($hint_code), $ids_data);
485            let mut hint_processor = BuiltinHintProcessor::new_empty();
486            hint_processor.execute_hint(&mut $vm, exec_scopes_ref!(), &any_box!(hint_data))
487        }};
488    }
489    pub(crate) use run_hint;
490
491    macro_rules! add_segments {
492        ($vm:expr, $n:expr) => {
493            for _ in 0..$n {
494                $vm.segments.add();
495            }
496        };
497    }
498    pub(crate) use add_segments;
499
500    macro_rules! check_scope {
501        ( $exec_scope: expr, [ $( ($name: expr, $val: expr)),*$(,)? ] $(,)? ) => {
502            $(
503                check_scope_value($exec_scope, $name, $val);
504            )*
505        };
506    }
507    pub(crate) use check_scope;
508
509    macro_rules! scope {
510        () => { ExecutionScopes::new() };
511        (  $( ($name: expr, $val: expr)),* $(,)?  ) => {
512            {
513                let mut exec_scopes = ExecutionScopes::new();
514                $(
515                    exec_scopes.assign_or_update_variable(
516                        $name,
517                        any_box!($val),
518                    );
519                )*
520                exec_scopes
521            }
522        };
523    }
524    pub(crate) use scope;
525
526    macro_rules! check_dictionary {
527        ( $exec_scopes: expr, $tracker_num:expr, $( ($key:expr, $val:expr )),* ) => {
528            $(
529                assert_matches::assert_matches!(
530                    $exec_scopes
531                        .get_dict_manager()
532                        .unwrap()
533                        .borrow_mut()
534                        .trackers
535                        .get_mut(&$tracker_num)
536                        .unwrap()
537                        .get_value(&MaybeRelocatable::from($key)),
538                    Ok(x) if x == &MaybeRelocatable::from($val)
539                ));
540            *
541        };
542    }
543    pub(crate) use check_dictionary;
544
545    macro_rules! check_dict_ptr {
546        ($exec_scopes: expr, $tracker_num: expr, ($i:expr, $off:expr)) => {
547            assert_eq!(
548                $exec_scopes
549                    .get_dict_manager()
550                    .unwrap()
551                    .borrow()
552                    .trackers
553                    .get(&$tracker_num)
554                    .unwrap()
555                    .current_ptr,
556                relocatable!($i, $off)
557            );
558        };
559    }
560    pub(crate) use check_dict_ptr;
561
562    macro_rules! dict_manager {
563        ($exec_scopes:expr, $tracker_num:expr, $( ($key:expr, $val:expr )),* ) => {
564            let mut tracker = DictTracker::new_empty(relocatable!($tracker_num, 0));
565            $(
566            tracker.insert_value(&MaybeRelocatable::from($key), &MaybeRelocatable::from($val));
567            )*
568            let mut dict_manager = DictManager::new();
569            dict_manager.trackers.insert(2, tracker);
570            $exec_scopes.insert_value("dict_manager", std::rc::Rc::new(core::cell::RefCell::new(dict_manager)))
571        };
572        ($exec_scopes:expr, $tracker_num:expr) => {
573            let  tracker = DictTracker::new_empty(relocatable!($tracker_num, 0));
574            let mut dict_manager = DictManager::new();
575            dict_manager.trackers.insert(2, tracker);
576            $exec_scopes.insert_value("dict_manager", std::rc::Rc::new(core::cell::RefCell::new(dict_manager)))
577        };
578
579    }
580    pub(crate) use dict_manager;
581
582    macro_rules! dict_manager_default {
583        ($exec_scopes:expr, $tracker_num:expr,$default:expr, $( ($key:expr, $val:expr )),* ) => {
584            let mut tracker = DictTracker::new_default_dict(relocatable!($tracker_num, 0), &MaybeRelocatable::from($default), None);
585            $(
586            tracker.insert_value(&MaybeRelocatable::from($key), &MaybeRelocatable::from($val));
587            )*
588            let mut dict_manager = DictManager::new();
589            dict_manager.trackers.insert(2, tracker);
590            $exec_scopes.insert_value("dict_manager", std::rc::Rc::new(core::cell::RefCell::new(dict_manager)))
591        };
592        ($exec_scopes:expr, $tracker_num:expr,$default:expr) => {
593            let tracker = DictTracker::new_default_dict(relocatable!($tracker_num, 0), &MaybeRelocatable::from($default), None);
594            let mut dict_manager = DictManager::new();
595            dict_manager.trackers.insert(2, tracker);
596            $exec_scopes.insert_value("dict_manager", std::rc::Rc::new(core::cell::RefCell::new(dict_manager)))
597        };
598    }
599    pub(crate) use dict_manager_default;
600
601    macro_rules! vec_data {
602        ( $( ($val:tt) ),* ) => {
603            vec![$( vec_data_inner!($val) ),*]
604        };
605    }
606    pub(crate) use vec_data;
607
608    macro_rules! vec_data_inner {
609        (( $val1:expr, $val2:expr )) => {
610            mayberelocatable!($val1, $val2)
611        };
612        ( $val:expr ) => {
613            mayberelocatable!($val)
614        };
615    }
616    pub(crate) use vec_data_inner;
617
618    pub fn check_scope_value<T: core::fmt::Debug + core::cmp::PartialEq + 'static>(
619        scopes: &ExecutionScopes,
620        name: &str,
621        value: T,
622    ) {
623        let scope_value = scopes.get_any_boxed_ref(name).unwrap();
624        assert_eq!(scope_value.downcast_ref::<T>(), Some(&value));
625    }
626}
627
628#[cfg(test)]
629mod test {
630    use crate::hint_processor::hint_processor_definition::HintProcessorLogic;
631    use crate::types::builtin_name::BuiltinName;
632    use crate::types::program::HintsCollection;
633    use crate::{
634        hint_processor::{
635            builtin_hint_processor::{
636                builtin_hint_processor_definition::{BuiltinHintProcessor, HintProcessorData},
637                dict_manager::{DictManager, DictTracker},
638            },
639            hint_processor_definition::HintReference,
640        },
641        serde::deserialize_program::ReferenceManager,
642        types::{exec_scope::ExecutionScopes, program::Program, relocatable::MaybeRelocatable},
643        utils::test_utils::*,
644        vm::{trace::trace_entry::TraceEntry, vm_memory::memory::Memory},
645    };
646    use std::{cell::RefCell, collections::HashMap, rc::Rc};
647
648    use super::*;
649
650    #[test]
651    fn memory_macro_test() {
652        let mut memory = Memory::new();
653        for _ in 0..2 {
654            memory.data.push(Vec::new());
655        }
656        memory
657            .insert(
658                Relocatable::from((1, 2)),
659                &MaybeRelocatable::from(crate::Felt252::ONE),
660            )
661            .unwrap();
662        memory
663            .insert(Relocatable::from((1, 1)), &MaybeRelocatable::from((1, 0)))
664            .unwrap();
665        let mem = memory![((1, 2), 1), ((1, 1), (1, 0))];
666        assert_eq!(memory.data, mem.data);
667    }
668
669    #[test]
670    fn check_memory_macro_test() {
671        let mut memory = Memory::new();
672        for _ in 0..2 {
673            memory.data.push(Vec::new());
674        }
675        memory
676            .insert(Relocatable::from((1, 1)), &MaybeRelocatable::from((1, 0)))
677            .unwrap();
678
679        memory
680            .insert(
681                Relocatable::from((1, 2)),
682                &MaybeRelocatable::from(crate::Felt252::ONE),
683            )
684            .unwrap();
685
686        check_memory![memory, ((1, 1), (1, 0)), ((1, 2), 1)];
687    }
688
689    #[test]
690    fn check_memory_address_macro_test() {
691        let mut memory = Memory::new();
692        for _ in 0..2 {
693            memory.data.push(Vec::new());
694        }
695        memory
696            .insert(Relocatable::from((1, 1)), &MaybeRelocatable::from((1, 0)))
697            .unwrap();
698
699        memory
700            .insert(
701                Relocatable::from((1, 2)),
702                &MaybeRelocatable::from(crate::Felt252::ONE),
703            )
704            .unwrap();
705
706        check_memory_address!(memory, (1, 1), (1, 0));
707        check_memory_address!(memory, (1, 2), 1);
708    }
709
710    #[test]
711    fn create_run_context() {
712        let mut vm = vm!();
713        run_context!(vm, 2, 6, 10);
714
715        assert_eq!(vm.run_context.pc, Relocatable::from((0, 2)));
716        assert_eq!(vm.run_context.ap, 6);
717        assert_eq!(vm.run_context.fp, 10);
718    }
719
720    #[test]
721    fn assert_trace() {
722        let trace = vec![
723            TraceEntry {
724                pc: (0, 2).into(),
725                ap: 7,
726                fp: 1,
727            },
728            TraceEntry {
729                pc: (0, 5).into(),
730                ap: 1,
731                fp: 0,
732            },
733            TraceEntry {
734                pc: (0, 9).into(),
735                ap: 5,
736                fp: 7,
737            },
738        ];
739        trace_check(
740            &trace,
741            &[
742                ((0, 2).into(), 7, 1),
743                ((0, 5).into(), 1, 0),
744                ((0, 9).into(), 5, 7),
745            ],
746        );
747    }
748
749    #[test]
750    fn test_non_continuous_ids_data() {
751        let ids_data_macro = non_continuous_ids_data![("a", -2), ("", -6)];
752        let ids_data_verbose = HashMap::from([
753            ("a".to_string(), HintReference::new_simple(-2)),
754            ("".to_string(), HintReference::new_simple(-6)),
755        ]);
756        assert_eq!(ids_data_macro, ids_data_verbose);
757    }
758
759    #[test]
760    fn run_hint_alloc() {
761        let hint_code = "memory[ap] = segments.add()";
762        let mut vm = vm!();
763        add_segments!(vm, 1);
764        assert_matches::assert_matches!(run_hint!(vm, HashMap::new(), hint_code), Ok(()));
765        //A segment is added
766        assert_eq!(vm.segments.memory.data.len(), 2);
767    }
768
769    #[test]
770    fn check_scope_test_pass() {
771        let mut exec_scopes = ExecutionScopes::new();
772        exec_scopes.assign_or_update_variable("a", any_box!(String::from("Hello")));
773        exec_scopes.assign_or_update_variable(
774            "",
775            any_box!(Rc::new(RefCell::new(HashMap::<usize, Vec<usize>>::new()))),
776        );
777        exec_scopes.assign_or_update_variable("c", any_box!(vec![1, 2, 3, 4]));
778        check_scope!(
779            &exec_scopes,
780            [
781                ("a", String::from("Hello")),
782                (
783                    "",
784                    Rc::new(RefCell::new(HashMap::<usize, Vec<usize>>::new()))
785                ),
786                ("c", vec![1, 2, 3, 4])
787            ]
788        );
789    }
790
791    #[test]
792    #[should_panic]
793    fn check_scope_test_fail() {
794        let mut exec_scopes = ExecutionScopes::new();
795        exec_scopes.assign_or_update_variable("a", any_box!(String::from("Hello")));
796        exec_scopes.assign_or_update_variable(
797            "",
798            any_box!(Rc::new(RefCell::new(HashMap::<usize, Vec<usize>>::new()))),
799        );
800        exec_scopes.assign_or_update_variable("c", any_box!(vec![1, 2, 3, 4]));
801        check_scope!(
802            &exec_scopes,
803            [
804                ("a", String::from("Hello")),
805                (
806                    "",
807                    Rc::new(RefCell::new(HashMap::<usize, Vec<usize>>::new()))
808                ),
809                ("c", vec![1, 2, 3, 5])
810            ]
811        );
812    }
813
814    #[test]
815    fn scope_macro_test() {
816        let scope_from_macro = scope![("a", crate::Felt252::ONE)];
817        let mut scope_verbose = ExecutionScopes::new();
818        scope_verbose.assign_or_update_variable("a", any_box!(crate::Felt252::ONE));
819        assert_eq!(scope_from_macro.data.len(), scope_verbose.data.len());
820        assert_eq!(scope_from_macro.data[0].len(), scope_verbose.data[0].len());
821        assert_eq!(
822            scope_from_macro.data[0].get("a").unwrap().downcast_ref(),
823            Some(&crate::Felt252::ONE)
824        );
825    }
826
827    #[test]
828    fn check_dictionary_pass() {
829        let mut tracker = DictTracker::new_empty(relocatable!(2, 0));
830        tracker.insert_value(
831            &MaybeRelocatable::from(crate::Felt252::from(5)),
832            &MaybeRelocatable::from(crate::Felt252::from(10)),
833        );
834        let mut dict_manager = DictManager::new();
835        dict_manager.trackers.insert(2, tracker);
836        let mut exec_scopes = ExecutionScopes::new();
837        exec_scopes.assign_or_update_variable(
838            "dict_manager",
839            any_box!(Rc::new(RefCell::new(dict_manager))),
840        );
841        check_dictionary!(&exec_scopes, 2, (5, 10));
842    }
843
844    #[test]
845    #[should_panic]
846    fn check_dictionary_fail() {
847        let mut tracker = DictTracker::new_empty(relocatable!(2, 0));
848        tracker.insert_value(&MaybeRelocatable::from(5), &MaybeRelocatable::from(10));
849        let mut dict_manager = DictManager::new();
850        dict_manager.trackers.insert(2, tracker);
851        let mut exec_scopes = ExecutionScopes::new();
852        exec_scopes.assign_or_update_variable(
853            "dict_manager",
854            any_box!(Rc::new(RefCell::new(dict_manager))),
855        );
856        check_dictionary!(&exec_scopes, 2, (5, 11));
857    }
858
859    #[test]
860    fn check_dict_ptr_pass() {
861        let tracker = DictTracker::new_empty(relocatable!(2, 0));
862        let mut dict_manager = DictManager::new();
863        dict_manager.trackers.insert(2, tracker);
864        let mut exec_scopes = ExecutionScopes::new();
865        exec_scopes.assign_or_update_variable(
866            "dict_manager",
867            any_box!(Rc::new(RefCell::new(dict_manager))),
868        );
869        check_dict_ptr!(&exec_scopes, 2, (2, 0));
870    }
871
872    #[test]
873    #[should_panic]
874    fn check_dict_ptr_fail() {
875        let tracker = DictTracker::new_empty(relocatable!(2, 0));
876        let mut dict_manager = DictManager::new();
877        dict_manager.trackers.insert(2, tracker);
878        let mut exec_scopes = ExecutionScopes::new();
879        exec_scopes.assign_or_update_variable(
880            "dict_manager",
881            any_box!(Rc::new(RefCell::new(dict_manager))),
882        );
883        check_dict_ptr!(&exec_scopes, 2, (3, 0));
884    }
885
886    #[test]
887    fn dict_manager_macro() {
888        let tracker = DictTracker::new_empty(relocatable!(2, 0));
889        let mut dict_manager = DictManager::new();
890        dict_manager.trackers.insert(2, tracker);
891        let mut exec_scopes = ExecutionScopes::new();
892        dict_manager!(exec_scopes, 2);
893        assert_matches::assert_matches!(
894            exec_scopes.get_dict_manager(),
895            Ok(x) if x == Rc::new(RefCell::new(dict_manager))
896        );
897    }
898
899    #[test]
900    fn dict_manager_default_macro() {
901        let tracker = DictTracker::new_default_dict(
902            relocatable!(2, 0),
903            &MaybeRelocatable::from(crate::Felt252::from(17)),
904            None,
905        );
906        let mut dict_manager = DictManager::new();
907        dict_manager.trackers.insert(2, tracker);
908        let mut exec_scopes = ExecutionScopes::new();
909        dict_manager_default!(exec_scopes, 2, 17);
910        assert_matches::assert_matches!(
911            exec_scopes.get_dict_manager(),
912            Ok(x) if x == Rc::new(RefCell::new(dict_manager))
913        );
914    }
915
916    #[test]
917    fn data_vec_test() {
918        let data = vec_data!((1), ((2, 2)), (("49128305", 10)), (("3b6f00a9", 16)));
919        assert_eq!(data[0], mayberelocatable!(1));
920        assert_eq!(data[1], mayberelocatable!(2, 2));
921        assert_eq!(data[2], mayberelocatable!(49128305));
922        assert_eq!(data[3], mayberelocatable!(997130409));
923    }
924    #[test]
925    fn from_relocatable_to_indexes_test() {
926        let reloc_1 = relocatable!(1, 5);
927        let reloc_2 = relocatable!(0, 5);
928        let reloc_3 = relocatable!(-1, 5);
929        assert_eq!((1, 5), from_relocatable_to_indexes(reloc_1));
930        assert_eq!((0, 5), from_relocatable_to_indexes(reloc_2));
931        assert_eq!((0, 5), from_relocatable_to_indexes(reloc_3));
932    }
933
934    #[test]
935    fn program_macro() {
936        let shared_data = SharedProgramData {
937            data: Vec::new(),
938            hints_collection: HintsCollection::new(&BTreeMap::new(), 0).unwrap(),
939            main: None,
940            start: None,
941            end: None,
942            error_message_attributes: Vec::new(),
943            instruction_locations: None,
944            identifiers: HashMap::new(),
945            reference_manager: Program::get_reference_list(&ReferenceManager {
946                references: Vec::new(),
947            }),
948        };
949        let program = Program {
950            shared_program_data: Arc::new(shared_data),
951            constants: HashMap::new().into(),
952            builtins: Vec::new(),
953        };
954        assert_eq!(program, program!())
955    }
956
957    #[test]
958    fn program_macro_with_builtin() {
959        let shared_data = SharedProgramData {
960            data: Vec::new(),
961            hints_collection: HintsCollection::new(&BTreeMap::new(), 0).unwrap(),
962            main: None,
963            start: None,
964            end: None,
965            error_message_attributes: Vec::new(),
966            instruction_locations: None,
967            identifiers: HashMap::new(),
968            reference_manager: Program::get_reference_list(&ReferenceManager {
969                references: Vec::new(),
970            }),
971        };
972        let program = Program {
973            shared_program_data: Arc::new(shared_data),
974            constants: HashMap::new().into(),
975            builtins: vec![BuiltinName::range_check],
976        };
977
978        assert_eq!(program, program![BuiltinName::range_check])
979    }
980
981    #[test]
982    fn program_macro_custom_definition() {
983        let shared_data = SharedProgramData {
984            data: Vec::new(),
985            hints_collection: HintsCollection::new(&BTreeMap::new(), 0).unwrap(),
986            main: Some(2),
987            start: None,
988            end: None,
989            error_message_attributes: Vec::new(),
990            instruction_locations: None,
991            identifiers: HashMap::new(),
992            reference_manager: Program::get_reference_list(&ReferenceManager {
993                references: Vec::new(),
994            }),
995        };
996        let program = Program {
997            shared_program_data: Arc::new(shared_data),
998            constants: HashMap::new().into(),
999            builtins: vec![BuiltinName::range_check],
1000        };
1001
1002        assert_eq!(
1003            program,
1004            program!(builtins = vec![BuiltinName::range_check], main = Some(2),)
1005        )
1006    }
1007}