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
use failure::Fail;
use optimization;
use std::str::FromStr;
#[derive(Debug, Fail)]
pub enum ParseError {
#[fail(display = "unknown optimization level '{}'", name)]
UnknownLevel { name: String },
#[fail(display = "unknown optimization pass '{}'", name)]
UnknownOptimization { name: String },
#[fail(display = "unknown optimization flag ':{}'", name)]
UnknownFlag { name: String },
#[fail(display = "optimization flag can only contain a single separator")]
TooManySeparators,
#[fail(display = "a custom optimization sequence requires a non-empty list of optimizations")]
CustomWithoutList,
#[fail(
display = "this binary was compiled without visual debugger support. \
Flag `{}` cannot be used.",
flag
)]
NoDebuggerSupport { flag: String },
}
fn parse_flag(s: &str) -> Result<optimization::Flag, ParseError> {
match s.to_ascii_lowercase().as_str() {
"d" | "vcg" => Ok(optimization::Flag::DumpVcg),
"g" | "gui" => {
if cfg!(feature = "debugger_gui") {
Ok(optimization::Flag::Gui)
} else {
Err(ParseError::NoDebuggerSupport {
flag: s.to_string(),
})
}
}
_ => Err(ParseError::UnknownFlag {
name: s.to_string(),
}),
}
}
fn parse_level(arg: &str) -> Result<optimization::Level, ParseError> {
let mut parts = arg.split(':');
let level = parts.next().unwrap();
match (
level.to_ascii_lowercase().as_str(),
parts.next(),
parts.next(),
) {
(_, _, Some(_)) => Err(ParseError::TooManySeparators),
("custom", Some(sequence), _) => {
parse_custom_sequence(sequence).map(optimization::Level::Custom)
}
("custom", None, _) => Err(ParseError::CustomWithoutList),
("none", None, _) => Ok(optimization::Level::None),
("moderate", None, _) => Ok(optimization::Level::Moderate),
("aggressive", None, _) => Ok(optimization::Level::Aggressive),
(_, _, _) => Err(ParseError::UnknownLevel {
name: level.to_string(),
}),
}
}
fn parse_custom_sequence(s: &str) -> Result<Vec<optimization::Optimization>, ParseError> {
let mut list = Vec::new();
for opt in s.split(',').filter(|s| !s.is_empty()) {
let mut fields = opt.split('.');
let kind = optimization::Kind::from_str(fields.next().unwrap()).map_err(|_| {
ParseError::UnknownOptimization {
name: opt.to_string(),
}
})?;
let flags = fields
.map(parse_flag)
.collect::<Result<Vec<optimization::Flag>, _>>()?;
list.push(optimization::Optimization { kind, flags });
}
Ok(list)
}
#[derive(Debug, Clone, Default)]
pub struct Arg(optimization::Level);
impl Into<optimization::Level> for Arg {
fn into(self) -> optimization::Level {
self.0
}
}
impl FromStr for Arg {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
parse_level(s).map(Arg)
}
}