midenc_session/options/
mod.rs

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