Improve chunk disassembly code
This commit is contained in:
parent
80b6380255
commit
b0af1609f0
@ -146,7 +146,9 @@ impl Chunk {
|
|||||||
|
|
||||||
impl Display for Chunk {
|
impl Display for Chunk {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", self.disassembler().styled(true).disassemble())
|
let disassembler = self.disassembler().styled(false);
|
||||||
|
|
||||||
|
write!(f, "{}", disassembler.disassemble())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +205,7 @@ impl Local {
|
|||||||
pub struct Scope {
|
pub struct Scope {
|
||||||
/// The level of block nesting.
|
/// The level of block nesting.
|
||||||
pub depth: u8,
|
pub depth: u8,
|
||||||
/// The nth scope in the block.
|
/// The nth scope in the chunk.
|
||||||
pub width: u8,
|
pub width: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,6 +230,7 @@ impl Display for Scope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct ChunkDisassembler<'a> {
|
pub struct ChunkDisassembler<'a> {
|
||||||
|
output: String,
|
||||||
chunk: &'a Chunk,
|
chunk: &'a Chunk,
|
||||||
source: Option<&'a str>,
|
source: Option<&'a str>,
|
||||||
width: usize,
|
width: usize,
|
||||||
@ -249,8 +252,8 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
const LOCAL_HEADER: [&'static str; 4] = [
|
const LOCAL_HEADER: [&'static str; 4] = [
|
||||||
"Locals",
|
"Locals",
|
||||||
"------",
|
"------",
|
||||||
"INDEX IDENTIFIER TYPE MUTABLE SCOPE REGISTER",
|
"INDEX IDENTIFIER TYPE MUTABLE SCOPE REGISTER",
|
||||||
"----- ---------- -------- ------- ----- --------",
|
"----- ---------- -------- ------- ------- --------",
|
||||||
];
|
];
|
||||||
|
|
||||||
/// The default width of the disassembly output. To correctly align the output, this should
|
/// The default width of the disassembly output. To correctly align the output, this should
|
||||||
@ -263,6 +266,7 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
|
|
||||||
pub fn new(chunk: &'a Chunk) -> Self {
|
pub fn new(chunk: &'a Chunk) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
output: String::new(),
|
||||||
chunk,
|
chunk,
|
||||||
source: None,
|
source: None,
|
||||||
width: Self::default_width(),
|
width: Self::default_width(),
|
||||||
@ -271,152 +275,130 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn source(&mut self, source: &'a str) -> &mut Self {
|
pub fn source(mut self, source: &'a str) -> Self {
|
||||||
self.source = Some(source);
|
self.source = Some(source);
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn width(&mut self, width: usize) -> &mut Self {
|
pub fn width(mut self, width: usize) -> Self {
|
||||||
self.width = width;
|
self.width = width;
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn styled(&mut self, styled: bool) -> &mut Self {
|
pub fn styled(mut self, styled: bool) -> Self {
|
||||||
self.styled = styled;
|
self.styled = styled;
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disassemble(&self) -> String {
|
pub fn indent(mut self, indent: usize) -> Self {
|
||||||
#[allow(clippy::too_many_arguments)]
|
self.indent = indent;
|
||||||
fn push(
|
|
||||||
text: &str,
|
|
||||||
disassembly: &mut String,
|
|
||||||
width: usize,
|
|
||||||
indent: usize,
|
|
||||||
center: bool,
|
|
||||||
style_bold: bool,
|
|
||||||
style_dim: bool,
|
|
||||||
add_border: bool,
|
|
||||||
) {
|
|
||||||
let characters = text.chars().collect::<Vec<char>>();
|
|
||||||
let content_width = if add_border { width - 2 } else { width };
|
|
||||||
let (line_characters, remainder) = characters
|
|
||||||
.split_at_checked(content_width)
|
|
||||||
.unwrap_or((characters.as_slice(), &[]));
|
|
||||||
let (left_pad_length, right_pad_length) = {
|
|
||||||
let extra_space = content_width.saturating_sub(characters.len());
|
|
||||||
|
|
||||||
if center {
|
self
|
||||||
(extra_space / 2, extra_space / 2 + extra_space % 2)
|
}
|
||||||
} else {
|
|
||||||
(0, extra_space)
|
fn push(
|
||||||
}
|
&mut self,
|
||||||
};
|
text: &str,
|
||||||
let content = if style_bold {
|
center: bool,
|
||||||
line_characters
|
style_bold: bool,
|
||||||
.iter()
|
style_dim: bool,
|
||||||
.collect::<String>()
|
add_border: bool,
|
||||||
.bold()
|
) {
|
||||||
.to_string()
|
let characters = text.chars().collect::<Vec<char>>();
|
||||||
} else if style_dim {
|
let content_width = if add_border {
|
||||||
line_characters
|
self.width - 2
|
||||||
.iter()
|
} else {
|
||||||
.collect::<String>()
|
self.width
|
||||||
.dimmed()
|
};
|
||||||
.to_string()
|
let (line_characters, remainder) = characters
|
||||||
|
.split_at_checked(content_width)
|
||||||
|
.unwrap_or((characters.as_slice(), &[]));
|
||||||
|
let (left_pad_length, right_pad_length) = {
|
||||||
|
let extra_space = content_width.saturating_sub(characters.len());
|
||||||
|
|
||||||
|
if center {
|
||||||
|
(extra_space / 2, extra_space / 2 + extra_space % 2)
|
||||||
} else {
|
} else {
|
||||||
line_characters.iter().collect::<String>()
|
(0, extra_space)
|
||||||
};
|
|
||||||
let length_before_content = disassembly.chars().count();
|
|
||||||
|
|
||||||
for _ in 0..indent {
|
|
||||||
disassembly.push_str("│ ");
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
let content = if style_bold {
|
||||||
|
line_characters
|
||||||
|
.iter()
|
||||||
|
.collect::<String>()
|
||||||
|
.bold()
|
||||||
|
.to_string()
|
||||||
|
} else if style_dim {
|
||||||
|
line_characters
|
||||||
|
.iter()
|
||||||
|
.collect::<String>()
|
||||||
|
.dimmed()
|
||||||
|
.to_string()
|
||||||
|
} else {
|
||||||
|
line_characters.iter().collect::<String>()
|
||||||
|
};
|
||||||
|
let length_before_content = self.output.chars().count();
|
||||||
|
|
||||||
if add_border {
|
for _ in 0..self.indent {
|
||||||
disassembly.push('│');
|
self.output.push_str("│ ");
|
||||||
}
|
|
||||||
|
|
||||||
disassembly.push_str(&" ".repeat(left_pad_length));
|
|
||||||
disassembly.push_str(&content);
|
|
||||||
disassembly.push_str(&" ".repeat(right_pad_length));
|
|
||||||
|
|
||||||
let length_after_content = disassembly.chars().count();
|
|
||||||
let line_length = length_after_content - length_before_content;
|
|
||||||
|
|
||||||
if line_length < content_width - 1 {
|
|
||||||
disassembly.push_str(&" ".repeat(content_width - line_length));
|
|
||||||
}
|
|
||||||
|
|
||||||
if add_border {
|
|
||||||
disassembly.push('│');
|
|
||||||
}
|
|
||||||
|
|
||||||
disassembly.push('\n');
|
|
||||||
|
|
||||||
if !remainder.is_empty() {
|
|
||||||
push(
|
|
||||||
remainder.iter().collect::<String>().as_str(),
|
|
||||||
disassembly,
|
|
||||||
width,
|
|
||||||
indent,
|
|
||||||
center,
|
|
||||||
style_bold,
|
|
||||||
style_dim,
|
|
||||||
add_border,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let push_header = |header: &str, disassembly: &mut String| {
|
if add_border {
|
||||||
push(
|
self.output.push('│');
|
||||||
header,
|
}
|
||||||
disassembly,
|
|
||||||
self.width,
|
self.output.push_str(&" ".repeat(left_pad_length));
|
||||||
self.indent,
|
self.output.push_str(&content);
|
||||||
true,
|
self.output.push_str(&" ".repeat(right_pad_length));
|
||||||
self.styled,
|
|
||||||
false,
|
let length_after_content = self.output.chars().count();
|
||||||
true,
|
let line_length = length_after_content - length_before_content;
|
||||||
|
|
||||||
|
if line_length < content_width - 1 {
|
||||||
|
self.output
|
||||||
|
.push_str(&" ".repeat(content_width - line_length));
|
||||||
|
}
|
||||||
|
|
||||||
|
if add_border {
|
||||||
|
self.output.push('│');
|
||||||
|
}
|
||||||
|
|
||||||
|
self.output.push('\n');
|
||||||
|
|
||||||
|
if !remainder.is_empty() {
|
||||||
|
self.push(
|
||||||
|
remainder.iter().collect::<String>().as_str(),
|
||||||
|
center,
|
||||||
|
style_bold,
|
||||||
|
style_dim,
|
||||||
|
add_border,
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
let push_details = |details: &str, disassembly: &mut String| {
|
}
|
||||||
push(
|
|
||||||
details,
|
fn push_header(&mut self, header: &str) {
|
||||||
disassembly,
|
self.push(header, true, self.styled, false, true);
|
||||||
self.width,
|
}
|
||||||
self.indent,
|
|
||||||
true,
|
fn push_details(&mut self, details: &str) {
|
||||||
false,
|
self.push(details, true, false, false, true);
|
||||||
false,
|
}
|
||||||
true,
|
|
||||||
);
|
fn push_border(&mut self, border: &str) {
|
||||||
};
|
self.push(border, false, false, false, false);
|
||||||
let push_border = |border: &str, disassembly: &mut String| {
|
}
|
||||||
push(
|
|
||||||
border,
|
pub fn disassemble(mut self) -> String {
|
||||||
disassembly,
|
|
||||||
self.width,
|
|
||||||
self.indent,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let push_function_disassembly = |function_disassembly: &str, disassembly: &mut String| {
|
|
||||||
disassembly.push_str(function_disassembly);
|
|
||||||
};
|
|
||||||
let mut disassembly = String::new();
|
|
||||||
let top_border = "┌".to_string() + &"─".repeat(self.width - 2) + "┐";
|
let top_border = "┌".to_string() + &"─".repeat(self.width - 2) + "┐";
|
||||||
let section_border = "│".to_string() + &"┈".repeat(self.width - 2) + "│";
|
let section_border = "│".to_string() + &"┈".repeat(self.width - 2) + "│";
|
||||||
let bottom_border = "└".to_string() + &"─".repeat(self.width - 2) + "┘";
|
let bottom_border = "└".to_string() + &"─".repeat(self.width - 2) + "┘";
|
||||||
let name_display = self
|
let name_display = self
|
||||||
.chunk
|
.chunk
|
||||||
.name()
|
.name
|
||||||
|
.as_ref()
|
||||||
.map(|identifier| identifier.to_string())
|
.map(|identifier| identifier.to_string())
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
current_exe()
|
current_exe()
|
||||||
@ -424,8 +406,8 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
.unwrap_or("Chunk Disassembly".to_string())
|
.unwrap_or("Chunk Disassembly".to_string())
|
||||||
});
|
});
|
||||||
|
|
||||||
push_border(&top_border, &mut disassembly);
|
self.push_border(&top_border);
|
||||||
push_header(&name_display, &mut disassembly);
|
self.push_header(&name_display);
|
||||||
|
|
||||||
let info_line = format!(
|
let info_line = format!(
|
||||||
"{} instructions, {} constants, {} locals",
|
"{} instructions, {} constants, {} locals",
|
||||||
@ -434,19 +416,10 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
self.chunk.locals.len()
|
self.chunk.locals.len()
|
||||||
);
|
);
|
||||||
|
|
||||||
push(
|
self.push(&info_line, true, false, false, true);
|
||||||
&info_line,
|
|
||||||
&mut disassembly,
|
|
||||||
self.width,
|
|
||||||
self.indent,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
for line in &Self::INSTRUCTION_HEADER {
|
for line in &Self::INSTRUCTION_HEADER {
|
||||||
push_header(line, &mut disassembly);
|
self.push_header(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index, (instruction, position)) in self.chunk.instructions.iter().enumerate() {
|
for (index, (instruction, position)) in self.chunk.instructions.iter().enumerate() {
|
||||||
@ -457,13 +430,13 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
let instruction_display =
|
let instruction_display =
|
||||||
format!("{index:<5} {bytecode:<08X} {operation:15} {info:25} {position:13}");
|
format!("{index:<5} {bytecode:<08X} {operation:15} {info:25} {position:13}");
|
||||||
|
|
||||||
push_details(&instruction_display, &mut disassembly);
|
self.push_details(&instruction_display);
|
||||||
}
|
}
|
||||||
|
|
||||||
push_border(§ion_border, &mut disassembly);
|
self.push_border(§ion_border);
|
||||||
|
|
||||||
for line in &Self::LOCAL_HEADER {
|
for line in &Self::LOCAL_HEADER {
|
||||||
push_header(line, &mut disassembly);
|
self.push_header(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (
|
for (
|
||||||
@ -471,7 +444,7 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
Local {
|
Local {
|
||||||
identifier_index,
|
identifier_index,
|
||||||
r#type,
|
r#type,
|
||||||
scope: depth,
|
scope,
|
||||||
register_index,
|
register_index,
|
||||||
is_mutable: mutable,
|
is_mutable: mutable,
|
||||||
},
|
},
|
||||||
@ -488,42 +461,43 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
.map(|r#type| r#type.to_string())
|
.map(|r#type| r#type.to_string())
|
||||||
.unwrap_or("unknown".to_string());
|
.unwrap_or("unknown".to_string());
|
||||||
let local_display = format!(
|
let local_display = format!(
|
||||||
"{index:<5} {identifier_display:10} {type_display:8} {mutable:7} {depth:<5} {register_index:8}"
|
"{index:<5} {identifier_display:10} {type_display:8} {mutable:7} {scope:7} {register_index:8}"
|
||||||
);
|
);
|
||||||
|
|
||||||
push_details(&local_display, &mut disassembly);
|
self.push_details(&local_display);
|
||||||
}
|
}
|
||||||
|
|
||||||
push_border(§ion_border, &mut disassembly);
|
self.push_border(§ion_border);
|
||||||
|
|
||||||
for line in &Self::CONSTANT_HEADER {
|
for line in &Self::CONSTANT_HEADER {
|
||||||
push_header(line, &mut disassembly);
|
self.push_header(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index, value) in self.chunk.constants.iter().enumerate() {
|
for (index, value) in self.chunk.constants.iter().enumerate() {
|
||||||
let constant_display = format!("{index:<5} {value:<5}");
|
let constant_display = format!("{index:<5} {value:<5}");
|
||||||
|
|
||||||
push_details(&constant_display, &mut disassembly);
|
self.push_details(&constant_display);
|
||||||
|
|
||||||
if let Some(function_disassembly) = match value {
|
if let Some(function_disassembly) = match value {
|
||||||
Value::Function(function) => Some({
|
Value::Function(function) => Some({
|
||||||
let mut disassembler = function.chunk().disassembler();
|
function
|
||||||
disassembler.indent = self.indent + 1;
|
.chunk()
|
||||||
|
.disassembler()
|
||||||
disassembler.styled(self.styled);
|
.styled(self.styled)
|
||||||
disassembler.disassemble()
|
.indent(self.indent + 1)
|
||||||
|
.disassemble()
|
||||||
}),
|
}),
|
||||||
Value::Primitive(_) => None,
|
Value::Primitive(_) => None,
|
||||||
Value::Object(_) => None,
|
Value::Object(_) => None,
|
||||||
} {
|
} {
|
||||||
push_function_disassembly(&function_disassembly, &mut disassembly);
|
self.output.push_str(&function_disassembly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
push_border(&bottom_border, &mut disassembly);
|
self.push_border(&bottom_border);
|
||||||
|
|
||||||
let _ = disassembly.trim_end_matches('\n');
|
let _ = self.output.trim_end_matches('\n');
|
||||||
|
|
||||||
disassembly
|
self.output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user