1
0

Refine LoadList instruction; Improve logs; Refactor

This commit is contained in:
Jeff 2024-09-24 22:58:14 -04:00
parent 60df8b4d64
commit daca836db1
7 changed files with 93 additions and 77 deletions

View File

@ -76,11 +76,18 @@ impl Chunk {
.ok_or(ChunkError::InstructionUnderflow { position }) .ok_or(ChunkError::InstructionUnderflow { position })
} }
pub fn get_last_instruction(&self) -> Option<&(Instruction, Span)> { pub fn get_last_instruction(&self) -> Result<(&Instruction, &Span), ChunkError> {
self.instructions.last() let (instruction, position) =
self.instructions
.last()
.ok_or_else(|| ChunkError::InstructionUnderflow {
position: Span(0, 0),
})?;
Ok((instruction, position))
} }
pub fn get_last_operation(&self) -> Option<Operation> { pub fn get_last_operation(&self) -> Result<Operation, ChunkError> {
self.get_last_instruction() self.get_last_instruction()
.map(|(instruction, _)| instruction.operation()) .map(|(instruction, _)| instruction.operation())
} }

View File

@ -1,17 +1,15 @@
//! Key used to identify a value or type. //! Key used to identify a value or type.
//! //!
//! Identifiers are used to uniquely identify values and types in Dust programs. They are //! Identifiers are used to uniquely identify values and types in Dust programs.
//! cached to avoid duplication. This means that two identifiers with the same text are the same
//! object in memory.
//! //!
//! # Examples //! # Examples
//! ``` //! ```
//! # use dust_lang::Identifier; //! # use dust_lang::Identifier;
//! let foo = Identifier::new("foo"); //! let foo = Identifier::new("foo");
//! let also_foo = Identifier::new("foo"); //! let also_foo = foo.clone();
//! let another_foo = Identifier::new("foo"); //! let another_foo = also_foo.clone();
//! //!
//! assert_eq!(foo.strong_count(), 4); // One for each of the above and one for the cache. //! assert_eq!(foo.strong_count(), 3); // One for each of the above.
//! ``` //! ```
use std::{ use std::{
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
@ -27,7 +25,6 @@ use serde::{de::Visitor, Deserialize, Serialize};
pub struct Identifier(Arc<String>); pub struct Identifier(Arc<String>);
impl Identifier { impl Identifier {
/// Creates a new identifier or returns a clone of an existing one from a cache.
pub fn new<T: ToString>(text: T) -> Self { pub fn new<T: ToString>(text: T) -> Self {
let string = text.to_string(); let string = text.to_string();

View File

@ -41,12 +41,12 @@ impl Instruction {
instruction instruction
} }
pub fn load_list(to_register: u8, start_register: u8, list_length: u8) -> Instruction { pub fn load_list(to_register: u8, start_register: u8, end_register: u8) -> Instruction {
let mut instruction = Instruction(Operation::LoadList as u32); let mut instruction = Instruction(Operation::LoadList as u32);
instruction.set_a(to_register); instruction.set_a(to_register);
instruction.set_b(start_register); instruction.set_b(start_register);
instruction.set_c(list_length); instruction.set_c(end_register);
instruction instruction
} }
@ -371,12 +371,9 @@ impl Instruction {
Operation::LoadList => { Operation::LoadList => {
let destination = self.a(); let destination = self.a();
let first_index = self.b(); let first_index = self.b();
let last_index = destination.saturating_sub(1); let last_index = self.c();
Some(format!( Some(format!("R{destination} = [R{first_index}..=R{last_index}]",))
"R{} = [R{}..=R{}]",
destination, first_index, last_index
))
} }
Operation::DefineLocal => { Operation::DefineLocal => {
let destination = self.a(); let destination = self.a();

View File

@ -40,7 +40,7 @@ impl<'src> Parser<'src> {
pub fn new(mut lexer: Lexer<'src>) -> Result<Self, ParseError> { pub fn new(mut lexer: Lexer<'src>) -> Result<Self, ParseError> {
let (current_token, current_position) = lexer.next_token()?; let (current_token, current_position) = lexer.next_token()?;
log::trace!("Starting parser with token \"{current_token}\" at {current_position}"); log::info!("Starting parser with token \"{current_token}\" at {current_position}");
Ok(Parser { Ok(Parser {
lexer, lexer,
@ -96,7 +96,7 @@ impl<'src> Parser<'src> {
let (new_token, position) = self.lexer.next_token()?; let (new_token, position) = self.lexer.next_token()?;
log::trace!("Parsing \"{new_token}\" at {position}"); log::info!("Parsing \"{new_token}\" at {position}");
self.previous_token = replace(&mut self.current_token, new_token); self.previous_token = replace(&mut self.current_token, new_token);
self.previous_position = replace(&mut self.current_position, position); self.previous_position = replace(&mut self.current_position, position);
@ -438,7 +438,7 @@ impl<'src> Parser<'src> {
] ]
}; };
while let Some(operation) = self.chunk.get_last_operation() { while let Ok(operation) = self.chunk.get_last_operation() {
if operation.is_math() { if operation.is_math() {
let (instruction, position) = self.chunk.pop_instruction(self.current_position)?; let (instruction, position) = self.chunk.pop_instruction(self.current_position)?;
@ -688,14 +688,13 @@ impl<'src> Parser<'src> {
self.advance()?; self.advance()?;
let start_register = self.current_register; let start_register = self.current_register;
let mut length = 0;
while !self.allow(TokenKind::RightSquareBrace)? && !self.is_eof() { while !self.allow(TokenKind::RightSquareBrace)? && !self.is_eof() {
let next_register = self.current_register; let next_register = self.current_register;
self.parse(Precedence::Assignment)?; // Do not allow assignment self.parse(Precedence::Assignment)?; // Do not allow assignment
if let Some(Operation::LoadConstant) = self.chunk.get_last_operation() { if let Operation::LoadConstant = self.chunk.get_last_operation()? {
self.increment_register()?; self.increment_register()?;
} }
@ -706,19 +705,16 @@ impl<'src> Parser<'src> {
); );
} }
length += 1;
if !self.allow(TokenKind::Comma)? { if !self.allow(TokenKind::Comma)? {
self.expect(TokenKind::RightSquareBrace)?; self.expect(TokenKind::RightSquareBrace)?;
break;
} }
} }
let end_register = self.current_register - 1;
let end = self.current_position.1; let end = self.current_position.1;
self.emit_instruction( self.emit_instruction(
Instruction::load_list(self.current_register, start_register, length), Instruction::load_list(self.current_register, start_register, end_register),
Span(start, end), Span(start, end),
); );
self.increment_register()?; self.increment_register()?;
@ -864,17 +860,11 @@ impl<'src> Parser<'src> {
self.parse_expression()?; self.parse_expression()?;
self.increment_register()?; self.increment_register()?;
let (previous_instruction, previous_position) = *self let (previous_instruction, previous_position) = self.chunk.get_last_instruction()?;
.chunk
.get_last_instruction()
.ok_or_else(|| ParseError::ExpectedExpression {
found: self.current_token.to_owned(),
position,
})?;
let register = previous_instruction.a(); let register = previous_instruction.a();
let local_index = let local_index =
self.chunk self.chunk
.declare_local(identifier, is_mutable, register, previous_position)?; .declare_local(identifier, is_mutable, register, *previous_position)?;
// Optimize for assignment to a comparison // Optimize for assignment to a comparison
// if let Operation::Jump = previous_instruction.operation() { // if let Operation::Jump = previous_instruction.operation() {
@ -909,8 +899,8 @@ impl<'src> Parser<'src> {
let allow_return = precedence == Precedence::None; let allow_return = precedence == Precedence::None;
if let Some(prefix_parser) = ParseRule::from(&self.current_token.kind()).prefix { if let Some(prefix_parser) = ParseRule::from(&self.current_token.kind()).prefix {
log::trace!( log::debug!(
"Parsing \"{}\" as prefix at precedence {precedence}", "Prefix \"{}\" has precedence {precedence}",
self.current_token, self.current_token,
); );
@ -921,8 +911,8 @@ impl<'src> Parser<'src> {
while precedence <= infix_rule.precedence { while precedence <= infix_rule.precedence {
if let Some(infix_parser) = infix_rule.infix { if let Some(infix_parser) = infix_rule.infix {
log::trace!( log::debug!(
"Parsing \"{}\" as infix at precedence {precedence}", "Infix \"{}\" has precedence {precedence}",
self.current_token, self.current_token,
); );

View File

@ -321,7 +321,7 @@ fn list_with_complex_expression() {
), ),
(Instruction::subtract(3, 1, 2), Span(10, 11)), (Instruction::subtract(3, 1, 2), Span(10, 11)),
(Instruction::close(1, 3), Span(17, 18)), (Instruction::close(1, 3), Span(17, 18)),
(Instruction::load_list(4, 0, 2), Span(0, 18)), (Instruction::load_list(4, 0, 3), Span(0, 18)),
(Instruction::end(true), Span(18, 18)), (Instruction::end(true), Span(18, 18)),
], ],
vec![ vec![
@ -352,7 +352,7 @@ fn list_with_simple_expression() {
Span(6, 7) Span(6, 7)
), ),
(Instruction::load_constant(2, 3), Span(11, 12)), (Instruction::load_constant(2, 3), Span(11, 12)),
(Instruction::load_list(3, 0, 3), Span(0, 13)), (Instruction::load_list(3, 0, 2), Span(0, 13)),
(Instruction::end(true), Span(13, 13)), (Instruction::end(true), Span(13, 13)),
], ],
vec![ vec![
@ -377,7 +377,7 @@ fn list() {
(Instruction::load_constant(0, 0), Span(1, 2)), (Instruction::load_constant(0, 0), Span(1, 2)),
(Instruction::load_constant(1, 1), Span(4, 5)), (Instruction::load_constant(1, 1), Span(4, 5)),
(Instruction::load_constant(2, 2), Span(7, 8)), (Instruction::load_constant(2, 2), Span(7, 8)),
(Instruction::load_list(3, 0, 3), Span(0, 9)), (Instruction::load_list(3, 0, 2), Span(0, 9)),
(Instruction::end(true), Span(9, 9)), (Instruction::end(true), Span(9, 9)),
], ],
vec![Value::integer(1), Value::integer(2), Value::integer(3),], vec![Value::integer(1), Value::integer(2), Value::integer(3),],

View File

@ -56,7 +56,7 @@ impl Vm {
} }
while let Ok((instruction, position)) = self.read(Span(0, 0)).copied() { while let Ok((instruction, position)) = self.read(Span(0, 0)).copied() {
log::trace!( log::info!(
"Running IP {} {} at {position}", "Running IP {} {} at {position}",
self.ip - 1, self.ip - 1,
instruction.operation() instruction.operation()
@ -68,6 +68,8 @@ impl Vm {
let to = instruction.a(); let to = instruction.a();
let value = self.take(from, position)?; let value = self.take(from, position)?;
log::debug!("R{from} -{{{value}}}-> R{to}");
self.insert(value, to, position)?; self.insert(value, to, position)?;
} }
Operation::Close => { Operation::Close => {
@ -100,13 +102,14 @@ impl Vm {
Operation::LoadList => { Operation::LoadList => {
let to_register = instruction.a(); let to_register = instruction.a();
let first_register = instruction.b(); let first_register = instruction.b();
let length = instruction.c(); let last_register = instruction.c();
let last_register = first_register + length + 1; let length = last_register - first_register + 1;
let mut list = Vec::with_capacity(length as usize); let mut list = Vec::with_capacity(length as usize);
log::debug!("R{to_register} = [R{first_register}..=R{last_register}]");
for register_index in first_register..=last_register { for register_index in first_register..=last_register {
let value = match self.clone(register_index, position) { let value = match self.take(register_index, position) {
Ok(value) => value, Ok(value) => value,
Err(VmError::EmptyRegister { .. }) => continue, Err(VmError::EmptyRegister { .. }) => continue,
Err(error) => return Err(error), Err(error) => return Err(error),
@ -126,81 +129,91 @@ impl Vm {
Operation::GetLocal => { Operation::GetLocal => {
let register_index = instruction.a(); let register_index = instruction.a();
let local_index = instruction.b(); let local_index = instruction.b();
let local = self.chunk.get_local(local_index, position)?.clone(); let local = self.chunk.get_local(local_index, position)?;
let value = self.clone_as_variable(local, position)?; let value = if let Some(index) = local.register_index {
self.take(index, position)?
} else {
return Err(VmError::UndefinedVariable {
identifier: local.identifier.clone(),
position,
});
};
self.insert(value, register_index, position)?; self.insert(value, register_index, position)?;
} }
Operation::SetLocal => { Operation::SetLocal => {
let register_index = instruction.a(); let register_index = instruction.a();
let local_index = instruction.b(); let local_index = instruction.b();
let local = self.chunk.get_local(local_index, position)?.clone(); let local = self.chunk.get_local(local_index, position)?;
let value = self.clone_as_variable(local, position)?; let value = if let Some(index) = local.register_index {
self.take(index, position)?
} else {
return Err(VmError::UndefinedVariable {
identifier: local.identifier.clone(),
position,
});
};
let new_value = if instruction.b_is_constant() { let new_value = if instruction.b_is_constant() {
self.chunk.take_constant(register_index, position)? self.chunk.take_constant(register_index, position)?
} else { } else {
self.clone(register_index, position)? self.take(register_index, position)?
}; };
value value
.mutate(new_value) .mutate(new_value)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
self.insert(value, register_index, position)?; self.insert(value, register_index, position)?;
} }
Operation::Add => { Operation::Add => {
let (left, right) = get_arguments(self, instruction, position)?; let (left, right) = get_arguments(self, instruction, position)?;
log::debug!("{left} + {right}");
let sum = left let sum = left
.add(right) .add(right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
log::debug!("{left} + {right} = {sum}");
self.insert(sum, instruction.a(), position)?; self.insert(sum, instruction.a(), position)?;
} }
Operation::Subtract => { Operation::Subtract => {
let (left, right) = get_arguments(self, instruction, position)?; let (left, right) = get_arguments(self, instruction, position)?;
log::debug!("{left} - {right}");
let difference = left let difference = left
.subtract(right) .subtract(right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
log::debug!("{left} - {right} = {difference}");
self.insert(difference, instruction.a(), position)?; self.insert(difference, instruction.a(), position)?;
} }
Operation::Multiply => { Operation::Multiply => {
let (left, right) = get_arguments(self, instruction, position)?; let (left, right) = get_arguments(self, instruction, position)?;
log::debug!("{left} * {right}");
let product = left let product = left
.multiply(right) .multiply(right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
log::debug!("{position} {left} * {right}");
self.insert(product, instruction.a(), position)?; self.insert(product, instruction.a(), position)?;
} }
Operation::Divide => { Operation::Divide => {
let (left, right) = get_arguments(self, instruction, position)?; let (left, right) = get_arguments(self, instruction, position)?;
log::debug!("{left} / {right}");
let quotient = left let quotient = left
.divide(right) .divide(right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
log::debug!("{left} / {right} = {quotient}");
self.insert(quotient, instruction.a(), position)?; self.insert(quotient, instruction.a(), position)?;
} }
Operation::Modulo => { Operation::Modulo => {
let (left, right) = get_arguments(self, instruction, position)?; let (left, right) = get_arguments(self, instruction, position)?;
log::debug!("{left} % {right}");
let remainder = left let remainder = left
.modulo(right) .modulo(right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
log::debug!("{left} % {right} = {remainder}");
self.insert(remainder, instruction.a(), position)?; self.insert(remainder, instruction.a(), position)?;
} }
Operation::Test => { Operation::Test => {
@ -238,6 +251,7 @@ impl Vm {
debug_assert_eq!(jump.operation(), Operation::Jump); debug_assert_eq!(jump.operation(), Operation::Jump);
let (left, right) = get_arguments(self, instruction, position)?; let (left, right) = get_arguments(self, instruction, position)?;
let boolean = left let boolean = left
.equal(right) .equal(right)
.map_err(|error| VmError::Value { error, position })? .map_err(|error| VmError::Value { error, position })?
@ -248,6 +262,8 @@ impl Vm {
})?; })?;
let compare_to = instruction.a_as_boolean(); let compare_to = instruction.a_as_boolean();
log::debug!("{left} == {right} = {boolean} == {compare_to}");
if boolean == compare_to { if boolean == compare_to {
self.ip += 1; self.ip += 1;
} else { } else {
@ -263,11 +279,12 @@ impl Vm {
} }
} }
Operation::Less => { Operation::Less => {
let (jump, _) = *self.chunk.get_instruction(self.ip, position)?; let jump = self.chunk.get_instruction(self.ip, position)?.0;
debug_assert_eq!(jump.operation(), Operation::Jump); debug_assert_eq!(jump.operation(), Operation::Jump);
let (left, right) = get_arguments(self, instruction, position)?; let (left, right) = get_arguments(self, instruction, position)?;
let boolean = left let boolean = left
.less_than(right) .less_than(right)
.map_err(|error| VmError::Value { error, position })? .map_err(|error| VmError::Value { error, position })?
@ -278,6 +295,8 @@ impl Vm {
})?; })?;
let compare_to = instruction.a_as_boolean(); let compare_to = instruction.a_as_boolean();
log::debug!("{left} < {right} = {boolean} == {compare_to}");
if boolean == compare_to { if boolean == compare_to {
self.ip += 1; self.ip += 1;
} else { } else {
@ -293,7 +312,7 @@ impl Vm {
} }
} }
Operation::LessEqual => { Operation::LessEqual => {
let (jump, _) = *self.chunk.get_instruction(self.ip, position)?; let jump = self.chunk.get_instruction(self.ip, position)?.0;
debug_assert_eq!(jump.operation(), Operation::Jump); debug_assert_eq!(jump.operation(), Operation::Jump);
@ -308,6 +327,8 @@ impl Vm {
})?; })?;
let compare_to = instruction.a_as_boolean(); let compare_to = instruction.a_as_boolean();
log::debug!("{left} <= {right} = {boolean} == {compare_to}");
if boolean == compare_to { if boolean == compare_to {
self.ip += 1; self.ip += 1;
} else { } else {
@ -332,6 +353,8 @@ impl Vm {
.negate() .negate()
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
log::debug!("-({value}) = {negated}");
self.insert(negated, instruction.a(), position)?; self.insert(negated, instruction.a(), position)?;
} }
Operation::Not => { Operation::Not => {
@ -344,6 +367,8 @@ impl Vm {
.not() .not()
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
log::debug!("!{value} = {not}");
self.insert(not, instruction.a(), position)?; self.insert(not, instruction.a(), position)?;
} }
Operation::Jump => { Operation::Jump => {

View File

@ -24,21 +24,21 @@ fn main() {
.parse_env("DUST_LOG") .parse_env("DUST_LOG")
.format(|buf, record| { .format(|buf, record| {
let level = match record.level() { let level = match record.level() {
Level::Error => "ERROR".red(), Level::Info => "INFO".white().bold(),
Level::Warn => "WARN".yellow(), Level::Debug => "DEBUG".blue().bold(),
Level::Info => "INFO".white(), Level::Warn => "WARN".yellow().bold(),
Level::Debug => "DEBUG".blue(), Level::Error => "ERROR".red().bold(),
Level::Trace => "TRACE".purple(), Level::Trace => "TRACE".purple().bold(),
} }
.bold(); .bold();
let level_display = format!("[{level:^5}]").white().on_black(); let level_display = format!("{level:<5}");
let module = record let module = record
.module_path() .module_path()
.map(|path| path.split("::").last().unwrap_or("unknown")) .map(|path| path.split("::").last().unwrap_or(path))
.unwrap_or("unknown") .unwrap_or("unknown")
.dimmed(); .dimmed();
writeln!(buf, "{level_display} {module:^6} {}", record.args()) writeln!(buf, "{level_display:^10} {module:^6} {}", record.args())
}) })
.init(); .init();