Clean up code and docs
This commit is contained in:
parent
85e1b5cff2
commit
215601707b
@ -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;
|
||||||
|
@ -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(§ion_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(§ion_border);
|
if !self.chunk.constants().is_empty() {
|
||||||
|
self.push_border(§ion_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(§ion_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);
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user