miden_assembly/
testing.rs1use alloc::{boxed::Box, sync::Arc, vec::Vec};
2
3#[cfg(any(test, feature = "testing"))]
4pub use miden_assembly_syntax::parser;
5use miden_assembly_syntax::{
6 Library, Parse, ParseOptions, Path, Word,
7 ast::{Module, ModuleKind},
8 debuginfo::{DefaultSourceManager, SourceManager},
9 diagnostics::{
10 Report,
11 reporting::{ReportHandlerOpts, set_hook},
12 },
13};
14pub use miden_assembly_syntax::{
15 assert_diagnostic, assert_diagnostic_lines, parse_module, regex, source_file, testing::Pattern,
16};
17#[cfg(feature = "testing")]
18use miden_assembly_syntax::{ast::Form, debuginfo::SourceFile};
19use miden_core::program::Program;
20
21use crate::assembler::Assembler;
22#[cfg(feature = "std")]
23use crate::diagnostics::reporting::set_panic_hook;
24
25pub struct TestContext {
33 source_manager: Arc<dyn SourceManager>,
34 assembler: Assembler,
35}
36
37impl Default for TestContext {
38 fn default() -> Self {
39 Self::new()
40 }
41}
42
43impl TestContext {
44 pub fn new() -> Self {
45 #[cfg(feature = "logging")]
46 {
47 let _ = env_logger::Builder::from_env("MIDEN_LOG").format_timestamp(None).try_init();
49 }
50
51 #[cfg(feature = "std")]
52 {
53 let result = set_hook(Box::new(|_| Box::new(ReportHandlerOpts::new().build())));
54 #[cfg(feature = "std")]
55 if result.is_ok() {
56 set_panic_hook();
57 }
58 }
59
60 #[cfg(not(feature = "std"))]
61 {
62 let _ = set_hook(Box::new(|_| Box::new(ReportHandlerOpts::new().build())));
63 }
64 let source_manager = Arc::new(DefaultSourceManager::default());
65 let assembler = Assembler::new(source_manager.clone()).with_warnings_as_errors(true);
66 Self { source_manager, assembler }
67 }
68
69 #[inline]
70 fn assembler(&self) -> Assembler {
71 self.assembler.clone()
72 }
73
74 #[inline(always)]
75 pub fn source_manager(&self) -> Arc<dyn SourceManager> {
76 self.source_manager.clone()
77 }
78
79 #[cfg(feature = "testing")]
84 #[track_caller]
85 pub fn parse_forms(&self, source: Arc<SourceFile>) -> Result<Vec<Form>, Report> {
86 parser::parse_forms(source.clone()).map_err(|err| Report::new(err).with_source_code(source))
87 }
88
89 #[track_caller]
94 pub fn parse_program(&self, source: impl Parse) -> Result<Box<Module>, Report> {
95 source.parse_with_options(
96 self.source_manager.clone(),
97 ParseOptions {
98 warnings_as_errors: self.assembler.warnings_as_errors(),
99 ..Default::default()
100 },
101 )
102 }
103
104 #[track_caller]
109 pub fn parse_kernel(&self, source: impl Parse) -> Result<Box<Module>, Report> {
110 source.parse_with_options(
111 self.source_manager.clone(),
112 ParseOptions {
113 warnings_as_errors: self.assembler.warnings_as_errors(),
114 ..ParseOptions::for_kernel()
115 },
116 )
117 }
118
119 #[track_caller]
124 pub fn parse_module(&self, source: impl Parse) -> Result<Box<Module>, Report> {
125 source.parse_with_options(
126 self.source_manager.clone(),
127 ParseOptions {
128 warnings_as_errors: self.assembler.warnings_as_errors(),
129 ..ParseOptions::for_library()
130 },
131 )
132 }
133
134 #[track_caller]
136 pub fn parse_module_with_path(
137 &self,
138 path: impl AsRef<Path>,
139 source: impl Parse,
140 ) -> Result<Box<Module>, Report> {
141 source.parse_with_options(
142 self.source_manager.clone(),
143 ParseOptions {
144 warnings_as_errors: self.assembler.warnings_as_errors(),
145 ..ParseOptions::new(ModuleKind::Library, path.as_ref().to_absolute())
146 },
147 )
148 }
149
150 #[track_caller]
153 pub fn add_module(&mut self, module: impl Parse) -> Result<(), Report> {
154 self.assembler.compile_and_statically_link(module).map(|_| ())
155 }
156
157 #[track_caller]
163 pub fn add_module_from_source(
164 &mut self,
165 path: impl AsRef<Path>,
166 source: impl Parse,
167 ) -> Result<(), Report> {
168 let module = source.parse_with_options(
169 self.source_manager.clone(),
170 ParseOptions {
171 path: Some(path.as_ref().to_absolute().into_owned().into()),
172 ..ParseOptions::for_library()
173 },
174 )?;
175 self.assembler.compile_and_statically_link(module).map(|_| ())
176 }
177
178 #[track_caller]
180 pub fn add_library(&mut self, library: impl AsRef<Library>) -> Result<(), Report> {
181 self.assembler.link_dynamic_library(library)
182 }
183
184 #[track_caller]
189 pub fn assemble(&self, source: impl Parse) -> Result<Program, Report> {
190 self.assembler().assemble_program(source)
191 }
192
193 #[track_caller]
198 pub fn assemble_library(
199 &self,
200 modules: impl IntoIterator<Item = Box<Module>>,
201 ) -> Result<Library, Report> {
202 self.assembler().assemble_library(modules)
203 }
204
205 #[track_caller]
208 pub fn assemble_module(
209 &self,
210 _path: impl AsRef<Path>,
211 _module: impl Parse,
212 ) -> Result<Vec<Word>, Report> {
213 unimplemented!()
215 }
216}