1
0

Add chunk names

This commit is contained in:
Jeff 2024-10-20 00:46:59 -04:00
parent f15cf84c4d
commit 6caae6c952
6 changed files with 91 additions and 61 deletions

View File

@ -1,6 +1,6 @@
use std::{
env::current_exe,
fmt::{self, Debug, Display},
path::PathBuf,
};
use colored::Colorize;
@ -10,6 +10,7 @@ use crate::{AnnotatedError, Identifier, Instruction, Span, Type, Value};
#[derive(Clone, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Chunk {
name: Option<Identifier>,
instructions: Vec<(Instruction, Span)>,
constants: Vec<Value>,
locals: Vec<Local>,
@ -17,8 +18,9 @@ pub struct Chunk {
}
impl Chunk {
pub fn new() -> Self {
pub fn new(name: Option<Identifier>) -> Self {
Self {
name,
instructions: Vec::new(),
constants: Vec::new(),
locals: Vec::new(),
@ -27,11 +29,13 @@ impl Chunk {
}
pub fn with_data(
name: Option<Identifier>,
instructions: Vec<(Instruction, Span)>,
constants: Vec<Value>,
locals: Vec<Local>,
) -> Self {
Self {
name,
instructions,
constants,
locals,
@ -39,6 +43,14 @@ impl Chunk {
}
}
pub fn name(&self) -> Option<&Identifier> {
self.name.as_ref()
}
pub fn set_name(&mut self, name: Identifier) {
self.name = Some(name);
}
pub fn len(&self) -> usize {
self.instructions.len()
}
@ -202,34 +214,20 @@ impl Chunk {
self.scope_depth -= 1;
}
pub fn disassembler<'a>(&'a self, name: &'a str) -> ChunkDisassembler<'a> {
ChunkDisassembler::new(name, self)
}
}
impl Default for Chunk {
fn default() -> Self {
Self::new()
pub fn disassembler(&self) -> ChunkDisassembler {
ChunkDisassembler::new(self)
}
}
impl Display for Chunk {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
self.disassembler("Dust Program").styled(true).disassemble()
)
write!(f, "{}", self.disassembler().styled(true).disassemble())
}
}
impl Debug for Chunk {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let executable = std::env::current_exe().unwrap_or_else(|_| PathBuf::new());
let disassembly = self
.disassembler(&executable.to_string_lossy())
.styled(false)
.disassemble();
let disassembly = self.disassembler().styled(false).disassemble();
if cfg!(debug_assertions) {
write!(f, "\n{}", disassembly)
@ -277,7 +275,6 @@ impl Local {
}
pub struct ChunkDisassembler<'a> {
name: &'a str,
chunk: &'a Chunk,
source: Option<&'a str>,
width: usize,
@ -311,9 +308,8 @@ impl<'a> ChunkDisassembler<'a> {
longest_line.chars().count().max(80)
}
pub fn new(name: &'a str, chunk: &'a Chunk) -> Self {
pub fn new(chunk: &'a Chunk) -> Self {
Self {
name,
chunk,
source: None,
width: Self::default_width(),
@ -465,9 +461,18 @@ impl<'a> ChunkDisassembler<'a> {
let top_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 name_display = self
.chunk
.name()
.map(|identifier| identifier.to_string())
.unwrap_or_else(|| {
current_exe()
.map(|path| path.to_string_lossy().to_string())
.unwrap_or("Chunk Disassembly".to_string())
});
push_border(&top_border, &mut disassembly);
push_header(self.name, &mut disassembly);
push_header(&name_display, &mut disassembly);
let info_line = format!(
"{} instructions, {} constants, {} locals",
@ -564,7 +569,7 @@ impl<'a> ChunkDisassembler<'a> {
if let Some(function_disassembly) = match value {
Value::Function(function) => Some({
let mut disassembler = function.chunk().disassembler("function");
let mut disassembler = function.chunk().disassembler();
disassembler.indent = self.indent + 1;
disassembler.styled(self.styled);

View File

@ -9,8 +9,8 @@ use colored::Colorize;
use serde::{Deserialize, Serialize};
use crate::{
instruction, operation, AnnotatedError, Chunk, ChunkError, DustError, FunctionType, Identifier,
Instruction, LexError, Lexer, Operation, Span, Token, TokenKind, TokenOwned, Type, Value,
AnnotatedError, Chunk, ChunkError, DustError, FunctionType, Identifier, Instruction, LexError,
Lexer, Operation, Span, Token, TokenKind, TokenOwned, Type, Value,
};
pub fn parse(source: &str) -> Result<Chunk, DustError> {
@ -59,7 +59,7 @@ impl<'src> Parser<'src> {
Ok(Parser {
lexer,
chunk: Chunk::new(),
chunk: Chunk::new(None),
current_statement: Vec::new(),
minimum_register: 0,
current_token,
@ -171,36 +171,6 @@ impl<'src> Parser<'src> {
Some(operations)
}
fn get_previous_jump_mut(&mut self) -> Option<&mut Instruction> {
let staged_jump = self
.current_statement
.iter_mut()
.rev()
.find_map(|(instruction, _)| {
if matches!(instruction.operation(), Operation::Jump) {
Some(instruction)
} else {
None
}
});
if staged_jump.is_some() {
staged_jump
} else {
self.chunk
.instructions_mut()
.iter_mut()
.rev()
.find_map(|(instruction, _)| {
if matches!(instruction.operation(), Operation::Jump) {
Some(instruction)
} else {
None
}
})
}
}
fn emit_constant(&mut self, value: Value, position: Span) -> Result<(), ParseError> {
let constant_index = self.chunk.push_constant(value, position)?;
let register = self.next_register();
@ -1104,10 +1074,12 @@ impl<'src> Parser<'src> {
let mut function_parser = Parser::new(self.lexer)?;
let identifier = if let Token::Identifier(text) = function_parser.current_token {
let position = function_parser.current_position;
let identifier = Identifier::new(text);
function_parser.advance()?;
function_parser.chunk.set_name(identifier.clone());
Some((Identifier::new(text), position))
Some((identifier, position))
} else {
None
};

View File

@ -7,6 +7,7 @@ fn add() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::add(0, 0, 1)
@ -31,6 +32,7 @@ fn add_assign() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_constant(0, 0, false), Span(12, 13)),
(Instruction::define_local(0, 0, true), Span(8, 9)),
@ -53,6 +55,7 @@ fn and() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_boolean(0, true, false), Span(0, 4)),
(Instruction::test(0, false), Span(5, 7)),
@ -85,6 +88,7 @@ fn block_scope() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_constant(0, 0, false), Span(17, 18)),
(Instruction::define_local(0, 0, false), Span(13, 14)),
@ -124,6 +128,7 @@ fn constant() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_constant(0, 0, false), Span(0, 2)),
(Instruction::r#return(true), Span(2, 2))
@ -143,6 +148,7 @@ fn define_local() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_constant(0, 0, false), Span(8, 10)),
(Instruction::define_local(0, 0, false), Span(4, 5)),
@ -162,6 +168,7 @@ fn divide() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::divide(0, 0, 1)
@ -186,6 +193,7 @@ fn divide_assign() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_constant(0, 0, false), Span(12, 13)),
(Instruction::define_local(0, 0, true), Span(8, 9)),
@ -208,7 +216,10 @@ fn divide_assign() {
fn empty() {
let source = "";
assert_eq!(parse(source), Ok(Chunk::with_data(vec![], vec![], vec![])),);
assert_eq!(
parse(source),
Ok(Chunk::with_data(None, vec![], vec![], vec![]))
);
assert_eq!(run(source), Ok(None));
}
@ -219,6 +230,7 @@ fn empty_list() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_list(0, 0, 0), Span(0, 2)),
(Instruction::r#return(true), Span(2, 2)),
@ -238,6 +250,7 @@ fn equal() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
@ -265,6 +278,7 @@ fn equality_assignment_long() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
@ -294,6 +308,7 @@ fn equality_assignment_short() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
@ -324,6 +339,7 @@ fn function() {
run(source),
Ok(Some(Value::function(
Chunk::with_data(
None,
vec![
(Instruction::add(2, 0, 1), Span(30, 31)),
(Instruction::r#return(true), Span(34, 35)),
@ -353,12 +369,14 @@ fn function_declaration() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_constant(0, 0, false), Span(0, 40)),
(Instruction::define_local(0, 0, false), Span(3, 6)),
],
vec![Value::function(
Chunk::with_data(
None,
vec![
(Instruction::add(2, 0, 1), Span(35, 36)),
(Instruction::r#return(true), Span(39, 40)),
@ -405,6 +423,7 @@ fn function_call() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_constant(0, 0, false), Span(0, 36)),
(Instruction::load_constant(1, 1, false), Span(36, 37)),
@ -415,6 +434,7 @@ fn function_call() {
vec![
Value::function(
Chunk::with_data(
None,
vec![
(Instruction::add(2, 0, 1), Span(30, 31)),
(Instruction::r#return(true), Span(34, 35)),
@ -451,6 +471,7 @@ fn greater() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::less_equal(false, 0, 1)
@ -478,6 +499,7 @@ fn greater_than_or_equal() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::less(false, 0, 1)
@ -505,6 +527,7 @@ fn if_else_expression() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
@ -537,6 +560,7 @@ fn if_expression_false() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
@ -562,6 +586,7 @@ fn if_expression_true() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
@ -587,6 +612,7 @@ fn less_than() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::less(true, 0, 1)
@ -614,6 +640,7 @@ fn less_than_or_equal() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::less_equal(true, 0, 1)
@ -641,6 +668,7 @@ fn list() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_constant(0, 0, false), Span(1, 2)),
(Instruction::load_constant(1, 1, false), Span(4, 5)),
@ -663,6 +691,7 @@ fn list_with_complex_expression() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_constant(0, 0, false), Span(1, 2)),
(
@ -703,6 +732,7 @@ fn list_with_simple_expression() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_constant(0, 0, false), Span(1, 2)),
(
@ -735,6 +765,7 @@ fn math_operator_precedence() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::add(0, 0, 1)
@ -776,6 +807,7 @@ fn multiply() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::multiply(0, 0, 1)
@ -800,6 +832,7 @@ fn multiply_assign() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_constant(0, 0, false), Span(12, 13)),
(Instruction::define_local(0, 0, true), Span(8, 9)),
@ -825,6 +858,7 @@ fn negate() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(*Instruction::negate(0, 0).set_b_is_constant(), Span(0, 1)),
(Instruction::r#return(true), Span(5, 5)),
@ -844,6 +878,7 @@ fn not() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_boolean(0, true, false), Span(1, 5)),
(Instruction::not(1, 0), Span(0, 1)),
@ -864,6 +899,7 @@ fn not_equal() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(false, 0, 1)
@ -891,6 +927,7 @@ fn or() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_boolean(0, true, false), Span(0, 4)),
(Instruction::test(0, true), Span(5, 7)),
@ -913,6 +950,7 @@ fn parentheses_precedence() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::add(0, 0, 1)
@ -941,6 +979,7 @@ fn set_local() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_constant(0, 0, false), Span(12, 14)),
(Instruction::define_local(0, 0, true), Span(8, 9)),
@ -964,6 +1003,7 @@ fn subtract() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::subtract(0, 0, 1)
@ -988,6 +1028,7 @@ fn subtract_assign() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_constant(0, 0, false), Span(12, 14)),
(Instruction::define_local(0, 0, true), Span(8, 9)),
@ -1013,6 +1054,7 @@ fn variable_and() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_boolean(0, true, false), Span(8, 12)),
(Instruction::define_local(0, 0, false), Span(4, 5)),
@ -1042,6 +1084,7 @@ fn r#while() {
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_constant(0, 0, false), Span(12, 13)),
(Instruction::define_local(0, 0, true), Span(8, 9)),

View File

@ -111,7 +111,7 @@ fn parse_source(source: &str, styled: bool) {
match parse(source) {
Ok(chunk) => {
let disassembly = chunk
.disassembler("Dust CLI Input")
.disassembler()
.source(source)
.styled(styled)
.disassemble();

5
examples/assets/count.js Normal file
View File

@ -0,0 +1,5 @@
var i = 0;
while (i < 10000) {
i++;
}

5
examples/count.ds Normal file
View File

@ -0,0 +1,5 @@
let mut i = 0;
while i < 10000 {
i += 1;
}