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