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 })
}
pub fn get_last_instruction(&self) -> Option<&(Instruction, Span)> {
self.instructions.last()
pub fn get_last_instruction(&self) -> Result<(&Instruction, &Span), ChunkError> {
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()
.map(|(instruction, _)| instruction.operation())
}

View File

@ -1,17 +1,15 @@
//! Key used to identify a value or type.
//!
//! Identifiers are used to uniquely identify values and types in Dust programs. They are
//! cached to avoid duplication. This means that two identifiers with the same text are the same
//! object in memory.
//! Identifiers are used to uniquely identify values and types in Dust programs.
//!
//! # Examples
//! ```
//! # use dust_lang::Identifier;
//! let foo = Identifier::new("foo");
//! let also_foo = Identifier::new("foo");
//! let another_foo = Identifier::new("foo");
//! let also_foo = foo.clone();
//! 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::{
fmt::{self, Display, Formatter},
@ -27,7 +25,6 @@ use serde::{de::Visitor, Deserialize, Serialize};
pub struct Identifier(Arc<String>);
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 {
let string = text.to_string();

View File

@ -41,12 +41,12 @@ impl 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);
instruction.set_a(to_register);
instruction.set_b(start_register);
instruction.set_c(list_length);
instruction.set_c(end_register);
instruction
}
@ -371,12 +371,9 @@ impl Instruction {
Operation::LoadList => {
let destination = self.a();
let first_index = self.b();
let last_index = destination.saturating_sub(1);
let last_index = self.c();
Some(format!(
"R{} = [R{}..=R{}]",
destination, first_index, last_index
))
Some(format!("R{destination} = [R{first_index}..=R{last_index}]",))
}
Operation::DefineLocal => {
let destination = self.a();

View File

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

View File

@ -321,7 +321,7 @@ fn list_with_complex_expression() {
),
(Instruction::subtract(3, 1, 2), Span(10, 11)),
(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)),
],
vec![
@ -352,7 +352,7 @@ fn list_with_simple_expression() {
Span(6, 7)
),
(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)),
],
vec![
@ -377,7 +377,7 @@ fn list() {
(Instruction::load_constant(0, 0), Span(1, 2)),
(Instruction::load_constant(1, 1), Span(4, 5)),
(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)),
],
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() {
log::trace!(
log::info!(
"Running IP {} {} at {position}",
self.ip - 1,
instruction.operation()
@ -68,6 +68,8 @@ impl Vm {
let to = instruction.a();
let value = self.take(from, position)?;
log::debug!("R{from} -{{{value}}}-> R{to}");
self.insert(value, to, position)?;
}
Operation::Close => {
@ -100,13 +102,14 @@ impl Vm {
Operation::LoadList => {
let to_register = instruction.a();
let first_register = instruction.b();
let length = instruction.c();
let last_register = first_register + length + 1;
let last_register = instruction.c();
let length = last_register - first_register + 1;
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 {
let value = match self.clone(register_index, position) {
let value = match self.take(register_index, position) {
Ok(value) => value,
Err(VmError::EmptyRegister { .. }) => continue,
Err(error) => return Err(error),
@ -126,81 +129,91 @@ impl Vm {
Operation::GetLocal => {
let register_index = instruction.a();
let local_index = instruction.b();
let local = self.chunk.get_local(local_index, position)?.clone();
let value = self.clone_as_variable(local, position)?;
let local = self.chunk.get_local(local_index, 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)?;
}
Operation::SetLocal => {
let register_index = instruction.a();
let local_index = instruction.b();
let local = self.chunk.get_local(local_index, position)?.clone();
let value = self.clone_as_variable(local, position)?;
let local = self.chunk.get_local(local_index, 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() {
self.chunk.take_constant(register_index, position)?
} else {
self.clone(register_index, position)?
self.take(register_index, position)?
};
value
.mutate(new_value)
.map_err(|error| VmError::Value { error, position })?;
self.insert(value, register_index, position)?;
}
Operation::Add => {
let (left, right) = get_arguments(self, instruction, position)?;
log::debug!("{left} + {right}");
let sum = left
.add(right)
.map_err(|error| VmError::Value { error, position })?;
log::debug!("{left} + {right} = {sum}");
self.insert(sum, instruction.a(), position)?;
}
Operation::Subtract => {
let (left, right) = get_arguments(self, instruction, position)?;
log::debug!("{left} - {right}");
let difference = left
.subtract(right)
.map_err(|error| VmError::Value { error, position })?;
log::debug!("{left} - {right} = {difference}");
self.insert(difference, instruction.a(), position)?;
}
Operation::Multiply => {
let (left, right) = get_arguments(self, instruction, position)?;
log::debug!("{left} * {right}");
let product = left
.multiply(right)
.map_err(|error| VmError::Value { error, position })?;
log::debug!("{position} {left} * {right}");
self.insert(product, instruction.a(), position)?;
}
Operation::Divide => {
let (left, right) = get_arguments(self, instruction, position)?;
log::debug!("{left} / {right}");
let quotient = left
.divide(right)
.map_err(|error| VmError::Value { error, position })?;
log::debug!("{left} / {right} = {quotient}");
self.insert(quotient, instruction.a(), position)?;
}
Operation::Modulo => {
let (left, right) = get_arguments(self, instruction, position)?;
log::debug!("{left} % {right}");
let remainder = left
.modulo(right)
.map_err(|error| VmError::Value { error, position })?;
log::debug!("{left} % {right} = {remainder}");
self.insert(remainder, instruction.a(), position)?;
}
Operation::Test => {
@ -238,6 +251,7 @@ impl Vm {
debug_assert_eq!(jump.operation(), Operation::Jump);
let (left, right) = get_arguments(self, instruction, position)?;
let boolean = left
.equal(right)
.map_err(|error| VmError::Value { error, position })?
@ -248,6 +262,8 @@ impl Vm {
})?;
let compare_to = instruction.a_as_boolean();
log::debug!("{left} == {right} = {boolean} == {compare_to}");
if boolean == compare_to {
self.ip += 1;
} else {
@ -263,11 +279,12 @@ impl Vm {
}
}
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);
let (left, right) = get_arguments(self, instruction, position)?;
let boolean = left
.less_than(right)
.map_err(|error| VmError::Value { error, position })?
@ -278,6 +295,8 @@ impl Vm {
})?;
let compare_to = instruction.a_as_boolean();
log::debug!("{left} < {right} = {boolean} == {compare_to}");
if boolean == compare_to {
self.ip += 1;
} else {
@ -293,7 +312,7 @@ impl Vm {
}
}
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);
@ -308,6 +327,8 @@ impl Vm {
})?;
let compare_to = instruction.a_as_boolean();
log::debug!("{left} <= {right} = {boolean} == {compare_to}");
if boolean == compare_to {
self.ip += 1;
} else {
@ -332,6 +353,8 @@ impl Vm {
.negate()
.map_err(|error| VmError::Value { error, position })?;
log::debug!("-({value}) = {negated}");
self.insert(negated, instruction.a(), position)?;
}
Operation::Not => {
@ -344,6 +367,8 @@ impl Vm {
.not()
.map_err(|error| VmError::Value { error, position })?;
log::debug!("!{value} = {not}");
self.insert(not, instruction.a(), position)?;
}
Operation::Jump => {

View File

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