1
0

Clean up code and docs

This commit is contained in:
Jeff 2024-12-02 01:08:41 -05:00
parent 85e1b5cff2
commit 215601707b
3 changed files with 135 additions and 120 deletions

View File

@ -1,8 +1,9 @@
//! Compilation tools and errors //! Compilation tools and errors
//! //!
//! This module provides two compilation options: //! This module provides two compilation options:
//! - [`compile`], which compiles the entire input and returns a chunk //! - [`compile`] borrows a string and returns a chunk, handling the entire compilation process and
//! - [`Compiler`], which compiles the input a token at a time while assembling a chunk //! turning any resulting [`ComplileError`] into a [`DustError`].
//! - [`Compiler`] uses a lexer to get tokens and assembles a chunk.
use std::{ use std::{
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
mem::replace, mem::replace,
@ -41,10 +42,12 @@ pub fn compile(source: &str) -> Result<Chunk, DustError> {
Compiler::new(lexer).map_err(|error| DustError::Compile { error, source })?; Compiler::new(lexer).map_err(|error| DustError::Compile { error, source })?;
compiler compiler
.parse_top_level() .compile()
.map_err(|error| DustError::Compile { error, source })?; .map_err(|error| DustError::Compile { error, source })?;
Ok(compiler.finish(None, None)) let chunk = compiler.finish(None, None);
Ok(chunk)
} }
/// Tool for compiling the input a token at a time while assembling a chunk. /// Tool for compiling the input a token at a time while assembling a chunk.
@ -119,6 +122,20 @@ impl<'src> Compiler<'src> {
) )
} }
pub fn compile(&mut self) -> Result<(), CompileError> {
loop {
self.parse(Precedence::None)?;
if self.is_eof() || self.allow(Token::RightBrace)? {
self.parse_implicit_return()?;
break;
}
}
Ok(())
}
fn is_eof(&self) -> bool { fn is_eof(&self) -> bool {
matches!(self.current_token, Token::Eof) matches!(self.current_token, Token::Eof)
} }
@ -1199,20 +1216,6 @@ impl<'src> Compiler<'src> {
Ok(()) Ok(())
} }
fn parse_top_level(&mut self) -> Result<(), CompileError> {
loop {
self.parse(Precedence::None)?;
if self.is_eof() || self.allow(Token::RightBrace)? {
self.parse_implicit_return()?;
break;
}
}
Ok(())
}
fn parse_expression(&mut self) -> Result<(), CompileError> { fn parse_expression(&mut self) -> Result<(), CompileError> {
self.parse(Precedence::None)?; self.parse(Precedence::None)?;
@ -1408,7 +1411,7 @@ impl<'src> Compiler<'src> {
function_compiler.return_type = Some((*return_type).clone()); function_compiler.return_type = Some((*return_type).clone());
function_compiler.expect(Token::LeftBrace)?; function_compiler.expect(Token::LeftBrace)?;
function_compiler.parse_top_level()?; function_compiler.compile()?;
self.previous_token = function_compiler.previous_token; self.previous_token = function_compiler.previous_token;
self.previous_position = function_compiler.previous_position; self.previous_position = function_compiler.previous_position;

View File

@ -15,30 +15,22 @@
//! //!
//! ```text //! ```text
//! ┌──────────────────────────────────────────────────────────────────────────────┐ //! ┌──────────────────────────────────────────────────────────────────────────────┐
//! │ <file name omitted> │ //! │ dust │
//! │ │
//! │ write_line("Hello, world!") │
//! │ │
//! │ 3 instructions, 1 constants, 0 locals, returns none │ //! │ 3 instructions, 1 constants, 0 locals, returns none │
//! │ │ //! │ │
//! │ Instructions │ //! │ Instructions │
//! │ ------------ │ //! │ ------------ │
//! │ i BYTECODE OPERATION INFO TYPE POSITION │ //! │ i POSITION OPERATION TYPE INFO │
//! │--- -------- ------------- -------------------- ---------------- ------------ │ //! │ --- ---------- ------------- -------------- -------------------------------- │
//! │ 0 03 LOAD_CONSTANT R0 = C0 str (11, 26) │ //! │ 0 (11, 24) LOAD_CONSTANT str R0 = C0 │
//! │ 1 1390117 CALL_NATIVE write_line(R0) (0, 27) │ //! │ 1 (0, 25) CALL_NATIVE none write_line(R0..R1) │
//! │ 2 18 RETURN (27, 27) │ //! │ 2 (25, 25) RETURN none │
//! │┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈│
//! │ Locals │
//! │ ------ │
//! │ i IDENTIFIER TYPE MUTABLE SCOPE REGISTER │
//! │ --- ---------- ---------------- ------- ------- -------- │
//! │┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈│ //! │┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈│
//! │ Constants │ //! │ Constants │
//! │ --------- │ //! │ --------- │
//! │ i VALUE //! │ i TYPE VALUE │
//! │ --- --------------- //! │ --- ---------------- ----------------- │
//! │ 0 Hello, world! //! │ 0 str Hello, world!
//! └──────────────────────────────────────────────────────────────────────────────┘ //! └──────────────────────────────────────────────────────────────────────────────┘
//! ``` //! ```
use std::env::current_exe; use std::env::current_exe;
@ -207,6 +199,97 @@ impl<'a> Disassembler<'a> {
self.push("", false, false, false, true); self.push("", false, false, false, true);
} }
fn push_instruction_section(&mut self) {
for line in INSTRUCTION_HEADER {
self.push_header(line);
}
for (index, (instruction, r#type, position)) in self.chunk.instructions().iter().enumerate()
{
let position = position.to_string();
let operation = instruction.operation().to_string();
let type_display = {
let mut type_string = r#type.to_string();
if type_string.len() > 14 {
type_string = format!("{type_string:.11}...");
}
type_string
};
let info = instruction.disassembly_info();
let instruction_display =
format!("{index:^3} {position:^10} {operation:13} {type_display:^14} {info:^32}");
self.push_details(&instruction_display);
}
}
fn push_local_section(&mut self) {
for line in LOCAL_HEADER {
self.push_header(line);
}
for (
index,
Local {
identifier_index,
r#type,
scope,
is_mutable,
},
) in self.chunk.locals().iter().enumerate()
{
let identifier_display = self
.chunk
.constants()
.get(*identifier_index as usize)
.map(|value| value.to_string())
.unwrap_or_else(|| "unknown".to_string());
let type_display = r#type.to_string();
let scope = scope.to_string();
let local_display = format!(
"{index:^3} {scope:^7} {is_mutable:^7} {type_display:^32} {identifier_display:^16}"
);
self.push_details(&local_display);
}
}
fn push_constant_section(&mut self) {
for line in CONSTANT_HEADER {
self.push_header(line);
}
for (index, value) in self.chunk.constants().iter().enumerate() {
if let ConcreteValue::Function(chunk) = value {
let mut function_disassembler = chunk.disassembler().style(self.style);
function_disassembler.indent = self.indent + 1;
let function_disassembly = function_disassembler.disassemble();
self.output.push_str(&function_disassembly);
continue;
}
let type_display = value.r#type().to_string();
let value_display = {
let mut value_string = value.to_string();
if value_string.len() > 15 {
value_string = format!("{value_string:.12}...");
}
value_string
};
let constant_display = format!("{index:^3} {type_display:^16} {value_display:^17}");
self.push_details(&constant_display);
}
}
pub fn disassemble(mut self) -> String { pub fn disassemble(mut self) -> String {
let width = Disassembler::default_width(); let width = Disassembler::default_width();
let top_border = "".to_string() + &"".repeat(width - 2) + ""; let top_border = "".to_string() + &"".repeat(width - 2) + "";
@ -251,93 +334,18 @@ impl<'a> Disassembler<'a> {
self.push_chunk_info(&info_line); self.push_chunk_info(&info_line);
self.push_empty(); self.push_empty();
for line in INSTRUCTION_HEADER { if !self.chunk.is_empty() {
self.push_header(line); self.push_instruction_section();
} }
for (index, (instruction, r#type, position)) in self.chunk.instructions().iter().enumerate() if !self.chunk.locals().is_empty() {
{ self.push_border(&section_border);
let position = position.to_string(); self.push_local_section();
let operation = instruction.operation().to_string();
let type_display = {
let mut type_string = r#type.to_string();
if type_string.len() > 14 {
type_string = format!("{type_string:.11}...");
}
type_string
};
let info = instruction.disassembly_info();
let instruction_display =
format!("{index:^3} {position:^10} {operation:13} {type_display:^14} {info:^32}");
self.push_details(&instruction_display);
} }
self.push_border(&section_border); if !self.chunk.constants().is_empty() {
self.push_border(&section_border);
for line in LOCAL_HEADER { self.push_constant_section();
self.push_header(line);
}
for (
index,
Local {
identifier_index,
r#type,
scope,
is_mutable,
},
) in self.chunk.locals().iter().enumerate()
{
let identifier_display = self
.chunk
.constants()
.get(*identifier_index as usize)
.map(|value| value.to_string())
.unwrap_or_else(|| "unknown".to_string());
let type_display = r#type.to_string();
let scope = scope.to_string();
let local_display = format!(
"{index:^3} {scope:^7} {is_mutable:^7} {type_display:^32} {identifier_display:^16}"
);
self.push_details(&local_display);
}
self.push_border(&section_border);
for line in CONSTANT_HEADER {
self.push_header(line);
}
for (index, value) in self.chunk.constants().iter().enumerate() {
if let ConcreteValue::Function(chunk) = value {
let mut function_disassembler = chunk.disassembler().style(self.style);
function_disassembler.indent = self.indent + 1;
let function_disassembly = function_disassembler.disassemble();
self.output.push_str(&function_disassembly);
continue;
}
let type_display = value.r#type().to_string();
let value_display = {
let mut value_string = value.to_string();
if value_string.len() > 15 {
value_string = format!("{value_string:.12}...");
}
value_string
};
let constant_display = format!("{index:^3} {type_display:^16} {value_display:^17}");
self.push_details(&constant_display);
} }
self.push_border(&bottom_border); self.push_border(&bottom_border);

View File

@ -703,7 +703,11 @@ impl Instruction {
let arguments_start = destination.index().saturating_sub(argument_count); let arguments_start = destination.index().saturating_sub(argument_count);
let arguments_end = arguments_start + argument_count; let arguments_end = arguments_start + argument_count;
format!("{destination} = {function}(R{arguments_start}..R{arguments_end})") if function.returns_value() {
format!("{destination} = {function}(R{arguments_start}..R{arguments_end})")
} else {
format!("{function}(R{arguments_start}..R{arguments_end})")
}
} }
Operation::Return => { Operation::Return => {
let Return { let Return {