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