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 print_ir_after_modified: bool,
57 pub save_temps: bool,
59 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 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 #[inline(always)]
194 pub fn emit_source_locations(&self) -> bool {
195 matches!(self.debug, DebugInfo::Line | DebugInfo::Full)
196 }
197
198 #[inline(always)]
200 pub fn emit_debug_decorators(&self) -> bool {
201 matches!(self.debug, DebugInfo::Full)
202 }
203
204 #[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#[derive(Debug, Copy, Clone, Default)]
213#[cfg_attr(feature = "std", derive(clap::ValueEnum))]
214pub enum OptLevel {
215 None,
217 Basic,
219 #[default]
221 Balanced,
222 Max,
224 Size,
226 SizeMin,
228}
229
230#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
232#[cfg_attr(feature = "std", derive(clap::ValueEnum))]
233pub enum DebugInfo {
234 None,
236 #[default]
238 Line,
239 Full,
241}
242
243#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
245#[cfg_attr(feature = "std", derive(clap::ValueEnum))]
246pub enum Warnings {
247 None,
249 #[default]
251 All,
252 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#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
279#[cfg_attr(feature = "std", derive(clap::ValueEnum))]
280pub enum Verbosity {
281 Debug,
283 #[default]
285 Info,
286 Warning,
288 Error,
290 Silent,
292}