midenc_session/options/
mod.rs

1use alloc::{fmt, str::FromStr, string::String, sync::Arc, vec, vec::Vec};
2
3#[cfg(feature = "std")]
4use crate::Path;
5use crate::{
6    ColorChoice, CompileFlags, LinkLibrary, OutputTypes, PathBuf, ProjectType, TargetEnv,
7    diagnostics::{DiagnosticsConfig, Emitter},
8};
9
10/// This struct contains all of the configuration options for the compiler
11#[derive(Debug)]
12pub struct Options {
13    /// The name of the program being compiled
14    pub name: Option<String>,
15    /// The type of project we're compiling this session
16    pub project_type: ProjectType,
17    /// The name of the function to call as the entrypoint
18    pub entrypoint: Option<String>,
19    /// The current target environment for this session
20    pub target: TargetEnv,
21    /// The optimization level for the current program
22    pub optimize: OptLevel,
23    /// The level of debugging info for the current program
24    pub debug: DebugInfo,
25    /// The type of outputs to emit
26    pub output_types: OutputTypes,
27    /// The paths in which to search for Miden Assembly libraries to link against
28    pub search_paths: Vec<PathBuf>,
29    /// The set of Miden libraries to link against
30    pub link_libraries: Vec<LinkLibrary>,
31    /// The location of the libraries which are shipped with the compiler
32    pub sysroot: Option<PathBuf>,
33    /// Whether, and how, to color terminal output
34    pub color: ColorChoice,
35    /// The current diagnostics configuration
36    pub diagnostics: DiagnosticsConfig,
37    /// The current working directory of the compiler
38    pub current_dir: PathBuf,
39    /// Path prefixes to try when resolving relative paths in DWARF debug info
40    pub trim_path_prefixes: Vec<PathBuf>,
41    /// Print source location information in HIR output
42    pub print_hir_source_locations: bool,
43    /// Only parse inputs
44    pub parse_only: bool,
45    /// Only perform semantic analysis on the input
46    pub analyze_only: bool,
47    /// Run the linker on the inputs, but do not generate Miden Assembly
48    pub link_only: bool,
49    /// Generate Miden Assembly from the inputs without the linker
50    pub no_link: bool,
51    /// Print CFG to stdout after each pass
52    pub print_cfg_after_all: bool,
53    /// Print CFG to stdout each time the named passes are applied
54    pub print_cfg_after_pass: Vec<String>,
55    /// Print IR to stdout after each pass
56    pub print_ir_after_all: bool,
57    /// Print IR to stdout each time the named passes are applied
58    pub print_ir_after_pass: Vec<String>,
59    /// Only print the IR if the pass modified the IR structure.
60    pub print_ir_after_modified: bool,
61    /// Save intermediate artifacts in memory during compilation
62    pub save_temps: bool,
63    /// We store any leftover argument matches in the session options for use
64    /// by any downstream crates that register custom flags
65    pub flags: CompileFlags,
66}
67
68impl Default for Options {
69    fn default() -> Self {
70        let current_dir = current_dir();
71        let target = TargetEnv::default();
72        let project_type = ProjectType::default_for_target(target);
73        Self::new(None, target, project_type, current_dir, None)
74    }
75}
76
77#[cfg(feature = "std")]
78fn current_dir() -> PathBuf {
79    std::env::current_dir().expect("could not get working directory")
80}
81
82#[cfg(not(feature = "std"))]
83fn current_dir() -> PathBuf {
84    PathBuf::from(".")
85}
86
87#[cfg(feature = "std")]
88fn current_sysroot() -> Option<PathBuf> {
89    std::env::var("HOME").ok().map(|home| {
90        Path::new(&home)
91            .join(".miden")
92            .join("toolchains")
93            .join(crate::MIDENC_BUILD_VERSION)
94    })
95}
96
97#[cfg(not(feature = "std"))]
98fn current_sysroot() -> Option<PathBuf> {
99    None
100}
101
102impl Options {
103    pub fn new(
104        name: Option<String>,
105        target: TargetEnv,
106        project_type: ProjectType,
107        current_dir: PathBuf,
108        sysroot: Option<PathBuf>,
109    ) -> Self {
110        let sysroot = sysroot.or_else(current_sysroot);
111
112        Self {
113            name,
114            target,
115            project_type,
116            entrypoint: None,
117            optimize: OptLevel::None,
118            debug: DebugInfo::None,
119            output_types: Default::default(),
120            search_paths: vec![],
121            link_libraries: vec![],
122            sysroot,
123            color: Default::default(),
124            diagnostics: Default::default(),
125            current_dir,
126            trim_path_prefixes: vec![],
127            print_hir_source_locations: false,
128            parse_only: false,
129            analyze_only: false,
130            link_only: false,
131            no_link: false,
132            save_temps: false,
133            print_cfg_after_all: false,
134            print_cfg_after_pass: vec![],
135            print_ir_after_all: false,
136            print_ir_after_pass: vec![],
137            print_ir_after_modified: false,
138            flags: CompileFlags::default(),
139        }
140    }
141
142    #[inline(always)]
143    pub fn with_color(mut self, color: ColorChoice) -> Self {
144        self.color = color;
145        self
146    }
147
148    #[inline(always)]
149    pub fn with_verbosity(mut self, verbosity: Verbosity) -> Self {
150        self.diagnostics.verbosity = verbosity;
151        self
152    }
153
154    #[inline(always)]
155    pub fn with_debug_info(mut self, debug: DebugInfo) -> Self {
156        self.debug = debug;
157        self
158    }
159
160    #[inline(always)]
161    pub fn with_optimization(mut self, level: OptLevel) -> Self {
162        self.optimize = level;
163        self
164    }
165
166    pub fn with_warnings(mut self, warnings: Warnings) -> Self {
167        self.diagnostics.warnings = warnings;
168        self
169    }
170
171    #[inline(always)]
172    pub fn with_output_types(mut self, output_types: OutputTypes) -> Self {
173        self.output_types = output_types;
174        self
175    }
176
177    #[doc(hidden)]
178    pub fn with_extra_flags(mut self, flags: CompileFlags) -> Self {
179        self.flags = flags;
180        self
181    }
182
183    #[doc(hidden)]
184    pub fn set_extra_flags(&mut self, flags: CompileFlags) {
185        self.flags = flags;
186    }
187
188    /// Get a new [Emitter] based on the current options.
189    pub fn default_emitter(&self) -> Arc<dyn Emitter> {
190        use crate::diagnostics::{DefaultEmitter, NullEmitter};
191
192        match self.diagnostics.verbosity {
193            Verbosity::Silent => Arc::new(NullEmitter::new(self.color)),
194            _ => Arc::new(DefaultEmitter::new(self.color)),
195        }
196    }
197
198    /// Returns true if source location information should be emitted by the compiler
199    #[inline(always)]
200    pub fn emit_source_locations(&self) -> bool {
201        matches!(self.debug, DebugInfo::Line | DebugInfo::Full)
202    }
203
204    /// Returns true if rich debugging information should be emitted by the compiler
205    #[inline(always)]
206    pub fn emit_debug_decorators(&self) -> bool {
207        matches!(self.debug, DebugInfo::Full)
208    }
209
210    /// Returns true if debug assertions are enabled
211    #[inline(always)]
212    pub fn emit_debug_assertions(&self) -> bool {
213        self.debug != DebugInfo::None && matches!(self.optimize, OptLevel::None | OptLevel::Basic)
214    }
215}
216
217/// This enum describes the degree to which compiled programs will be optimized
218#[derive(Debug, Copy, Clone, Default)]
219#[cfg_attr(feature = "std", derive(clap::ValueEnum))]
220pub enum OptLevel {
221    /// No optimizations at all
222    None,
223    /// Only basic optimizations are applied, e.g. constant propagation
224    Basic,
225    /// Most optimizations are applied, except when the cost is particularly high.
226    #[default]
227    Balanced,
228    /// All optimizations are applied, with all tradeoffs in favor of runtime performance
229    Max,
230    /// Most optimizations are applied, but tuned to trade runtime performance for code size
231    Size,
232    /// Only optimizations which reduce code size are applied
233    SizeMin,
234}
235
236/// This enum describes what type of debugging information to emit in compiled programs
237#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
238#[cfg_attr(feature = "std", derive(clap::ValueEnum))]
239pub enum DebugInfo {
240    /// Do not emit debug info in the final output
241    None,
242    /// Emit source location information in the final output
243    #[default]
244    Line,
245    /// Emit all available debug information in the final output
246    Full,
247}
248
249/// This enum represents the behavior of the compiler with regard to warnings
250#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
251#[cfg_attr(feature = "std", derive(clap::ValueEnum))]
252pub enum Warnings {
253    /// Disable all warnings
254    None,
255    /// Enable all warnings
256    #[default]
257    All,
258    /// Promotes warnings to errors
259    Error,
260}
261impl fmt::Display for Warnings {
262    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
263        match self {
264            Self::None => f.write_str("none"),
265            Self::All => f.write_str("auto"),
266            Self::Error => f.write_str("error"),
267        }
268    }
269}
270impl FromStr for Warnings {
271    type Err = ();
272
273    fn from_str(s: &str) -> Result<Self, Self::Err> {
274        match s {
275            "none" => Ok(Self::None),
276            "all" => Ok(Self::All),
277            "error" => Ok(Self::Error),
278            _ => Err(()),
279        }
280    }
281}
282
283/// This enum represents the type of messages produced by the compiler during execution
284#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
285#[cfg_attr(feature = "std", derive(clap::ValueEnum))]
286pub enum Verbosity {
287    /// Emit additional debug/trace information during compilation
288    Debug,
289    /// Emit the standard informational, warning, and error messages
290    #[default]
291    Info,
292    /// Only emit warnings and errors
293    Warning,
294    /// Only emit errors
295    Error,
296    /// Do not emit anything to stdout/stderr
297    Silent,
298}