use super::*;
#[derive(Clone, Serialize)]
struct Rust {
line: String,
path: ::std::path::PathBuf,
loc: asm::ast::Loc,
}
impl Rust {
fn new(
line: String, path: ::std::path::PathBuf, loc: asm::ast::Loc,
) -> Self {
Self { line, path, loc }
}
}
#[derive(Serialize)]
enum Kind {
Asm(asm::ast::Statement),
Rust(Rust),
}
#[cfg_attr(feature = "cargo-clippy", allow(items_after_statements))]
fn write_output(kind: &Kind, function: &asm::ast::Function) {
match kind {
&Kind::Asm(ref a) => {
use asm::ast::Statement::*;
match a {
&Comment(_) if !opts.print_comments() => return,
&Directive(_) if !opts.print_directives() => return,
&Label(ref l) => {
if l.id.contains("Lcfi")
|| l.id.contains("Ltmp")
|| l.id.contains("Lfunc_end")
{
return;
}
}
_ => {}
}
}
&Kind::Rust(_) => {
if !opts.rust() {
return;
}
}
}
let part_of_main_function = match kind {
&Kind::Asm(ref a) => is_stmt_in_function(function, a),
&Kind::Rust(ref r) => is_rust_in_function(function, r),
};
let indent = match kind {
&Kind::Asm(ref a) => {
use asm::ast::Statement::*;
match *a {
Comment(_) | Directive(_) | Instruction(_) => {
if !opts.rust() || part_of_main_function {
1
} else {
5
}
}
Label(_) => 0,
}
}
&Kind::Rust(_) => {
if part_of_main_function {
1
} else {
5
}
}
};
let indent = (0..indent).map(|_| " ").collect::<String>();
use std::io::Write;
use termcolor::{
Buffer, BufferWriter, Color, ColorChoice, ColorSpec, WriteColor,
};
let bufwtr = if opts.use_colors() {
BufferWriter::stdout(ColorChoice::Auto)
} else {
BufferWriter::stdout(ColorChoice::Never)
};
let mut buffer = bufwtr.buffer();
buffer.set_color(&ColorSpec::new()).unwrap();
write!(&mut buffer, "{}", indent).unwrap();
let mut instr_color = ColorSpec::new();
instr_color
.set_intense(true)
.set_fg(Some(Color::Blue))
.set_bold(true);
let mut label_color = ColorSpec::new();
label_color
.set_intense(true)
.set_fg(Some(Color::Green))
.set_bold(true);
let comment_color = ColorSpec::new();
let instr_arg_color = ColorSpec::new();
let mut rust_color = ColorSpec::new();
rust_color
.set_intense(true)
.set_fg(Some(Color::Red))
.set_bold(true);
let instr_call_arg_color = rust_color.clone();
fn debug_mode_format(mut buffer: &mut Buffer, loc: Option<asm::ast::Loc>) {
if let Some(loc) = loc {
write!(&mut buffer, " [{}:{}]", loc.file_index, loc.file_line)
.unwrap();
} else {
write!(&mut buffer, " [{0}:{0}]", "-").unwrap();
}
}
match kind {
&Kind::Asm(ref a) => {
use asm::ast::Statement::*;
match a {
&Label(ref l) => {
buffer.set_color(&label_color).unwrap();
write!(&mut buffer, "{}", l.id).unwrap();
write!(&mut buffer, ":").unwrap();
if opts.debug_mode() {
debug_mode_format(&mut buffer, l.rust_loc());
}
}
&Directive(ref d) => match d {
&asm::ast::Directive::File(ref f) => {
write!(
&mut buffer,
".file {} \"{}\"",
f.index,
f.path.display(),
).unwrap();
}
&asm::ast::Directive::Loc(ref l) => {
write!(
&mut buffer,
".loc {} {} {}",
l.file_index, l.file_line, l.file_column
).unwrap();
}
&asm::ast::Directive::Generic(ref g) => {
write!(&mut buffer, "{}", g.string).unwrap();
}
},
&Comment(ref c) => {
buffer.set_color(&comment_color).unwrap();
write!(&mut buffer, "{}", c.string).unwrap();
if opts.debug_mode() {
debug_mode_format(&mut buffer, c.rust_loc());
}
}
&Instruction(ref i) => {
buffer.set_color(&instr_color).unwrap();
if i.args.is_empty() {
write!(&mut buffer, "{}", i.instr).unwrap();
} else {
write!(&mut buffer, "{: <7}", i.instr).unwrap();
}
if i.is_jump() {
buffer.set_color(&label_color).unwrap();
} else if i.is_call() {
buffer.set_color(&instr_call_arg_color).unwrap();
} else {
buffer.set_color(&instr_arg_color).unwrap();
}
if !i.args.is_empty() {
write!(&mut buffer, " {}", i.args.join(", ")).unwrap();
}
if opts.debug_mode() {
debug_mode_format(&mut buffer, i.rust_loc());
}
}
}
}
&Kind::Rust(ref r) => {
buffer.set_color(&rust_color).unwrap();
if part_of_main_function {
write!(&mut buffer, "{}", r.line).unwrap();
if opts.debug_mode() {
debug_mode_format(&mut buffer, Some(r.loc));
}
} else {
write!(
&mut buffer,
"{} ({}:{})",
r.line,
r.path.display(),
r.loc.file_line
).unwrap();
}
}
}
write!(&mut buffer, "\n").unwrap();
bufwtr.print(&buffer).unwrap();
}
fn format_function_name(function: &asm::ast::Function) -> String {
if function.file.is_some() && function.loc.is_some() {
if let &Some(ref file) = &function.file {
if let &Some(ref loc) = &function.loc {
return format!(
"{} ({}:{})",
function.id,
file.path.display(),
loc.file_line
);
}
}
unreachable!()
} else {
assert!(function.file.is_none());
assert!(function.loc.is_none());
format!("{}", function.id)
}
}
fn is_stmt_in_function(
f: &asm::ast::Function, stmt: &asm::ast::Statement,
) -> bool {
let function_file_index = if let Some(loc) = f.loc {
Some(loc.file_index)
} else {
None
};
if let Some(function_file_index) = function_file_index {
if let Some(loc) = stmt.rust_loc() {
return loc.file_index == function_file_index;
}
}
true
}
fn is_rust_in_function(f: &asm::ast::Function, rust: &Rust) -> bool {
let function_file_index = if let Some(loc) = f.loc {
Some(loc.file_index)
} else {
None
};
if let Some(function_file_index) = function_file_index {
return rust.loc.file_index == function_file_index;
}
true
}
fn make_path_relative(path: &mut ::std::path::PathBuf) {
if !path.is_absolute() {
return;
}
let rust_src_path = ::target::rust_src_path_component();
let current_dir_path =
::std::env::current_dir().expect("cannot read the current dir");
debug!("making paths relative: {}", path.display());
debug!(" * std lib paths contain: {}", rust_src_path.display());
debug!(" * local paths contain: {}", current_dir_path.display());
if ::path::contains(&path, &rust_src_path) {
let new_path = ::path::after(&path, &rust_src_path);
debug!(" * rel path std: {}", new_path.display());
*path = new_path;
} else if ::path::contains(&path, ¤t_dir_path) {
let new_path = ::path::after(&path, ¤t_dir_path);
debug!(" * rel path loc: {}", new_path.display());
*path = new_path;
return;
} else {
debug!(" * path is neither local nor to std lib");
}
}
fn make_paths_relative(
function: &mut asm::ast::Function, rust: &mut rust::Files,
) {
if let &mut Some(ref mut file) = &mut function.file {
make_path_relative(&mut file.path)
}
for f in rust.files.values_mut() {
make_path_relative(&mut f.ast.path)
}
}
pub fn print(function: &mut asm::ast::Function, mut rust: rust::Files) {
make_paths_relative(function, &mut rust);
if !opts.rust() {
use std::io::Write;
use termcolor::{
BufferWriter, Color, ColorChoice, ColorSpec, WriteColor,
};
let mut rust_color = ColorSpec::new();
rust_color
.set_intense(true)
.set_fg(Some(Color::Red))
.set_bold(true);
let bufwtr = if opts.use_colors() {
BufferWriter::stdout(ColorChoice::Auto)
} else {
BufferWriter::stdout(ColorChoice::Never)
};
let mut buffer = bufwtr.buffer();
buffer.set_color(&rust_color).unwrap();
writeln!(&mut buffer, "{}:", format_function_name(function)).unwrap();
bufwtr.print(&buffer).unwrap();
}
let output = merge_rust_and_asm(function, &rust);
for o in &output {
write_output(o, function);
}
return;
}
fn merge_rust_and_asm(
function: &asm::ast::Function, rust_files: &rust::Files,
) -> Vec<Kind> {
let mut output = Vec::<Kind>::new();
for stmt in &function.statements {
if let Some(rust_loc) = stmt.rust_loc() {
if let Some(rust_line) = rust_files.line(rust_loc).map(|line| {
let path = rust_files.file_path(rust_loc).unwrap();
Rust::new(line, path, rust_loc)
}) {
let rl = rust_line.line.trim().to_string();
if !rl.starts_with("//") {
output.push(Kind::Rust(rust_line))
}
} else {
}
}
let asm = Kind::Asm(stmt.clone());
output.push(asm);
}
{
let mut last_rust: Option<Rust> = None;
output.retain(|v| {
let r = match v {
&Kind::Rust(ref r) => r,
_ => return true,
};
if let &Some(ref last_rust) = &last_rust {
if last_rust.loc == r.loc {
return false;
}
}
last_rust = Some(r.clone());
true
});
}
output
}
pub fn write_error(msg: &str) {
use std::io::Write;
use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};
let mut error_color = ColorSpec::new();
error_color
.set_intense(true)
.set_fg(Some(Color::Red))
.set_bold(true);
let bufwtr = if opts.use_colors() {
BufferWriter::stderr(ColorChoice::Auto)
} else {
BufferWriter::stderr(ColorChoice::Never)
};
let mut buffer = bufwtr.buffer();
buffer.set_color(&error_color).unwrap();
write!(&mut buffer, "[ERROR]: ").unwrap();
buffer.set_color(&ColorSpec::new()).unwrap();
write!(&mut buffer, "{}", msg).unwrap();
bufwtr.print(&buffer).unwrap();
}
pub fn to_json(
function: &asm::ast::Function, rust_files: &rust::Files,
) -> Option<String> {
let r = merge_rust_and_asm(&function, rust_files);
match ::serde_json::to_string_pretty(&r) {
Ok(s) => Some(s),
Err(e) => {
error!("{}", e);
None
}
}
}