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