🎨 Make cargo clippy happy

main
Shad Amethyst 1 year ago
parent 790da1870b
commit 5949174cdb

@ -19,7 +19,7 @@ impl std::fmt::Display for Operand {
match self {
Operand::Variable(name) => write!(f, "{}", name),
Operand::String(string) => {
let escaped = string.replace('\\', r#"\\"#).replace('"', r#"\""#);
let escaped = string.replace('\\', r"\\").replace('"', r#"\""#);
write!(f, "\"{}\"", escaped)
}
Operand::Integer(int) => write!(f, "{}", int),
@ -50,7 +50,7 @@ pub enum MindustryOperation {
}
impl MindustryOperation {
fn operands<'a>(&'a self) -> Box<[&'a Operand]> {
fn operands(&self) -> Box<[&Operand]> {
match self {
Self::JumpIf(_label, _operator, lhs, rhs) => Box::new([lhs, rhs]),
Self::Operator(_target, _operator, lhs, rhs) => Box::new([lhs, rhs]),
@ -65,7 +65,7 @@ impl MindustryOperation {
}
}
fn operands_mut<'a>(&'a mut self) -> Vec<&'a mut Operand> {
fn operands_mut(&mut self) -> Vec<&mut Operand> {
match self {
Self::JumpIf(_label, _operator, lhs, rhs) => vec![lhs, rhs],
Self::Operator(_target, _operator, lhs, rhs) => vec![lhs, rhs],
@ -91,7 +91,7 @@ impl MindustryOperation {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default)]
pub struct MindustryProgram(pub Vec<MindustryOperation>);
impl MindustryProgram {
@ -225,7 +225,7 @@ pub fn translate_ast(
condition_name.clone(),
));
if false_branch.instructions.len() > 0 {
if !false_branch.instructions.is_empty() {
let else_label = namer.label("else");
let end_label = namer.label("endif");
res.push(MindustryOperation::JumpIf(
@ -301,18 +301,12 @@ pub fn translate_ast(
res.push(MindustryOperation::GenericMut(
target_name.clone(),
out_name,
argument_names
.into_iter()
.map(|name| Operand::Variable(name))
.collect(),
argument_names.into_iter().map(Operand::Variable).collect(),
));
} else {
res.push(MindustryOperation::Generic(
target_name.clone(),
argument_names
.into_iter()
.map(|name| Operand::Variable(name))
.collect(),
argument_names.into_iter().map(Operand::Variable).collect(),
));
}
}
@ -403,7 +397,7 @@ impl std::fmt::Display for MindustryProgram {
for operand in operands {
write!(f, " {}", operand)?;
}
write!(f, "\n")?;
writeln!(f)?;
}
MindustryOperation::GenericMut(name, out_name, operands) => {
write!(f, "{}", name)?;
@ -411,7 +405,7 @@ impl std::fmt::Display for MindustryProgram {
for operand in operands {
write!(f, " {}", operand)?;
}
write!(f, "\n")?;
writeln!(f)?;
}
}
}

@ -10,11 +10,7 @@ pub fn optimize_constant(program: MindustryProgram) -> MindustryProgram {
return true;
}
if name.starts_with('@') {
false
} else {
true
}
!name.starts_with('@')
};
let res = replace_if(program, |instructions, instruction, use_index| {
@ -67,12 +63,12 @@ pub fn optimize_constant(program: MindustryProgram) -> MindustryProgram {
.filter(|(_name, value, set_index)| {
// Don't optimize operands that refer to a mutating variable (either mutable @-variables or instructions that get updated in-between)
if let Operand::Variable(assigned_var) = value {
if !is_safe_variable(&assigned_var) {
if !is_safe_variable(assigned_var) {
return false;
}
for instr_between in &instructions[*set_index..use_index] {
if instr_between.mutates(&assigned_var) {
if instr_between.mutates(assigned_var) {
return false;
}
}
@ -85,8 +81,8 @@ pub fn optimize_constant(program: MindustryProgram) -> MindustryProgram {
.map(|(name, value, _index)| (name, value))
.collect::<Vec<_>>();
if optimizable_operands.len() == 0 {
return None
if optimizable_operands.is_empty() {
return None;
}
let mut instruction = instruction.clone();

@ -6,11 +6,10 @@ pub(crate) fn optimize_dead_code(program: MindustryProgram) -> MindustryProgram
let mut needed_vars = HashSet::new();
let mut needed_labels = HashSet::new();
let mut push_var = |operand: &Operand| match operand {
Operand::Variable(name) => {
let mut push_var = |operand: &Operand| {
if let Operand::Variable(name) = operand {
needed_vars.insert(name.clone());
}
_ => {}
};
for instruction in program.0.iter() {
@ -44,31 +43,32 @@ pub(crate) fn optimize_dead_code(program: MindustryProgram) -> MindustryProgram
}
// Remove unneeded `set`s and `op`s
replace_if(program, |_instructions, instruction, _index| {
match instruction {
replace_if(
program,
|_instructions, instruction, _index| match instruction {
MindustryOperation::Set(name, _) | MindustryOperation::Operator(name, _, _, _) => {
if !tmp_regex.is_match(name) {
return None
return None;
}
if needed_vars.contains(name) {
return None
return None;
}
return Some(vec![])
Some(vec![])
}
MindustryOperation::JumpLabel(label) => {
if !label_regex.is_match(label) {
return None
return None;
}
if needed_labels.contains(label) {
return None
return None;
}
return Some(vec![])
Some(vec![])
}
_ => None
}
})
_ => None,
},
)
}

@ -1,9 +1,12 @@
use super::*;
pub(crate) fn replace_if<F>(program: MindustryProgram, callback: F) -> MindustryProgram
where
F: for<'c> Fn(&'c Vec<MindustryOperation>, &'c MindustryOperation, usize) -> Option<Vec<MindustryOperation>>
F: for<'c> Fn(
&'c Vec<MindustryOperation>,
&'c MindustryOperation,
usize,
) -> Option<Vec<MindustryOperation>>,
{
let mut res = MindustryProgram::new();

@ -103,6 +103,10 @@ impl<'a, T> Cursor<'a, T> {
self.data.len().saturating_sub(self.offset)
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn range<R: std::slice::SliceIndex<[T], Output = [T]>>(&self, range: R) -> Self {
Self {
data: &self.data[self.offset..][range],

@ -46,7 +46,7 @@ pub fn build_ast(tokens: &[BasicToken], config: &Config) -> Result<BasicAstBlock
let mut context_stack: Vec<(Vec<BasicAstInstruction>, Context)> =
vec![(Vec::new(), Context::Main)];
while tokens.len() > 0 {
while !tokens.is_empty() {
let Some((ref mut instructions, _context)) = context_stack.last_mut() else {
unreachable!("Context stack got emptied!");
};
@ -225,7 +225,7 @@ pub fn build_ast(tokens: &[BasicToken], config: &Config) -> Result<BasicAstBlock
}
}
if context_stack.len() == 0 {
if context_stack.is_empty() {
unreachable!("Empty context stack");
} else if context_stack.len() > 1 {
match &context_stack.last().unwrap().1 {
@ -277,7 +277,7 @@ pub(crate) fn parse_expression(
tokens: &mut Cursor<'_, BasicToken>,
) -> Result<BasicAstExpression, ParseError> {
/// Returns the first non-newline token in `tokens`
fn peek<'a>(tokens: &'a [BasicToken]) -> Option<&'a BasicToken> {
fn peek(tokens: &[BasicToken]) -> Option<&BasicToken> {
tokens.iter().find(|t| !matches!(t, BasicToken::NewLine))
}

@ -86,10 +86,10 @@ pub fn tokenize(raw: &str) -> Result<Vec<BasicToken>, ParseError> {
// TODO: handle labels
for mut line in raw.lines() {
if line.len() > 0 {
if !line.is_empty() {
res.push(BasicToken::NewLine);
}
while line.len() > 0 {
while !line.is_empty() {
// Main match clause for tokens
match_token!(line, res;
match_space => (),

@ -3,30 +3,35 @@
use std::path::{Path, PathBuf};
use basic_to_mindustry::common::Config;
use basic_to_mindustry::compile::{optimize_constant, translate_ast, optimize_jump_op, optimize_jump_always};
use basic_to_mindustry::compile::{
optimize_constant, optimize_jump_always, optimize_jump_op, translate_ast,
};
use basic_to_mindustry::parse::{build_ast, tokenize};
fn read_basic_examples() -> impl Iterator<Item=(String, String)> {
Path::new("./examples/").read_dir().unwrap().filter_map(|entry| {
let Ok(entry) = entry else {
return None;
};
if entry
.file_name()
.into_string()
.map(|name| name.ends_with(".basic"))
.unwrap_or(false)
{
let file_name = entry.file_name().into_string().unwrap();
let file = std::fs::read_to_string(entry.path()).unwrap_or_else(|e| {
panic!("Error opening {:?}: {:?}", file_name, e);
});
Some((file_name, file))
} else {
None
}
})
fn read_basic_examples() -> impl Iterator<Item = (String, String)> {
Path::new("./examples/")
.read_dir()
.unwrap()
.filter_map(|entry| {
let Ok(entry) = entry else {
return None;
};
if entry
.file_name()
.into_string()
.map(|name| name.ends_with(".basic"))
.unwrap_or(false)
{
let file_name = entry.file_name().into_string().unwrap();
let file = std::fs::read_to_string(entry.path()).unwrap_or_else(|e| {
panic!("Error opening {:?}: {:?}", file_name, e);
});
Some((file_name, file))
} else {
None
}
})
}
#[test]
@ -53,17 +58,27 @@ fn test_examples_opt() {
let config = Config::default();
for (file_name, file) in read_basic_examples() {
let Some(program_name) = PathBuf::from(file_name.clone()).file_stem().and_then(|stem| stem.to_str()).map(|s| s.to_string()) else {
panic!("Basic program in examples/ has an invalid filename: {}", file_name);
let Some(program_name) = PathBuf::from(file_name.clone())
.file_stem()
.and_then(|stem| stem.to_str())
.map(|s| s.to_string())
else {
panic!(
"Basic program in examples/ has an invalid filename: {}",
file_name
);
};
let opt_0 = format!("tests/examples/{}.0.mlog", program_name);
if !std::fs::try_exists(&opt_0).unwrap() {
continue
continue;
}
let opt_0 = std::fs::read_to_string(opt_0).unwrap_or_else(|e| {
panic!("Couldn't open tests/examples/{}.0.mlog: {:?}", program_name, e);
panic!(
"Couldn't open tests/examples/{}.0.mlog: {:?}",
program_name, e
);
});
let tokenized = tokenize(&file).unwrap_or_else(|e| {
@ -74,14 +89,17 @@ fn test_examples_opt() {
});
let translated = translate_ast(&parsed, &mut Default::default(), &config);
pretty_assertions::assert_eq!(opt_0.trim(), format!("{}", translated).trim());
let optimized = optimize_jump_always(optimize_jump_op(optimize_constant(translated)));
let opt_1 = std::fs::read_to_string(format!("tests/examples/{}.1.mlog", program_name)).unwrap_or_else(|e| {
panic!("Couldn't open tests/examples/{}.1.mlog: {:?}", program_name, e);
});
let opt_1 = std::fs::read_to_string(format!("tests/examples/{}.1.mlog", program_name))
.unwrap_or_else(|e| {
panic!(
"Couldn't open tests/examples/{}.1.mlog: {:?}",
program_name, e
);
});
pretty_assertions::assert_eq!(opt_1.trim(), format!("{}", optimized).trim());
}

Loading…
Cancel
Save