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#[derive(Debug)]
12pub struct Options {
13 pub name: Option<String>,
15 pub project_type: ProjectType,
17 pub entrypoint: Option<String>,
19 pub target: TargetEnv,
21 pub optimize: OptLevel,
23 pub debug: DebugInfo,
25 pub output_types: OutputTypes,
27 pub search_paths: Vec<PathBuf>,
29 pub link_libraries: Vec<LinkLibrary>,
31 pub sysroot: Option<PathBuf>,
33 pub color: ColorChoice,
35 pub diagnostics: DiagnosticsConfig,
37 pub current_dir: PathBuf,
39 pub parse_only: bool,
41 pub analyze_only: bool,
43 pub link_only: bool,
45 pub no_link: bool,
47 pub print_cfg_after_all: bool,
49 pub print_cfg_after_pass: Vec<String>,
51 pub print_ir_after_all: bool,
53 pub print_ir_after_pass: Vec<String>,
55 pub save_temps: bool,
57 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 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 #[inline(always)]
191 pub fn emit_source_locations(&self) -> bool {
192 matches!(self.debug, DebugInfo::Line | DebugInfo::Full)
193 }
194
195 #[inline(always)]
197 pub fn emit_debug_decorators(&self) -> bool {
198 matches!(self.debug, DebugInfo::Full)
199 }
200
201 #[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#[derive(Debug, Copy, Clone, Default)]
210#[cfg_attr(feature = "std", derive(clap::ValueEnum))]
211pub enum OptLevel {
212 None,
214 Basic,
216 #[default]
218 Balanced,
219 Max,
221 Size,
223 SizeMin,
225}
226
227#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
229#[cfg_attr(feature = "std", derive(clap::ValueEnum))]
230pub enum DebugInfo {
231 None,
233 #[default]
235 Line,
236 Full,
238}
239
240#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
242#[cfg_attr(feature = "std", derive(clap::ValueEnum))]
243pub enum Warnings {
244 None,
246 #[default]
248 All,
249 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#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
276#[cfg_attr(feature = "std", derive(clap::ValueEnum))]
277pub enum Verbosity {
278 Debug,
280 #[default]
282 Info,
283 Warning,
285 Error,
287 Silent,
289}