1
0

Fix register-setting bug

This commit is contained in:
Jeff 2025-01-01 21:53:54 -05:00
parent 10c66b3f95
commit 56becbfacb
9 changed files with 104 additions and 56 deletions

View File

@ -1,18 +1,19 @@
use std::io::{self, stdout, Read};
use std::time::{Duration, Instant};
use std::{fs::read_to_string, path::PathBuf};
use clap::builder::StyledStr;
use clap::error::ErrorKind;
use clap::{
builder::{styling::AnsiColor, Styles},
crate_authors, crate_description, crate_version, ColorChoice, Parser, Subcommand, ValueHint,
use std::{
fs::read_to_string,
io::{self, stdout, Read},
path::PathBuf,
time::{Duration, Instant},
};
use clap::{
builder::{styling::AnsiColor, StyledStr, Styles},
crate_authors, crate_description, crate_version,
error::ErrorKind,
Args, ColorChoice, Error, Parser, Subcommand, ValueHint,
};
use clap::{Args, Error};
use color_print::cstr;
use dust_lang::{CompileError, Compiler, DustError, DustString, Lexer, Span, Token, Vm};
use tracing::subscriber::set_global_default;
use tracing::Level;
use tracing::{subscriber::set_global_default, Level};
use tracing_subscriber::FmtSubscriber;
const CLI_HELP_TEMPLATE: &str = cstr!(
@ -214,6 +215,7 @@ fn main() {
let subscriber = FmtSubscriber::builder()
.with_max_level(log_level)
.with_thread_names(true)
.with_file(false)
.finish();
set_global_default(subscriber).expect("Failed to set tracing subscriber");

View File

@ -197,7 +197,7 @@ impl<'src> Compiler<'src> {
/// [`CompileError`] if any are found. After calling this function, check its return value for
/// an error, then call [`Compiler::finish`] to get the compiled chunk.
pub fn compile(&mut self) -> Result<(), CompileError> {
let span = span!(Level::INFO, "Compiling");
let span = span!(Level::INFO, "Compile");
let _enter = span.enter();
info!(

View File

@ -1,10 +1,25 @@
use crate::{Instruction, Operation};
use super::InstructionData;
pub struct GetLocal {
pub destination: u8,
pub local_index: u8,
}
impl From<InstructionData> for GetLocal {
fn from(data: InstructionData) -> Self {
let InstructionData {
a_field, b_field, ..
} = data;
GetLocal {
destination: a_field,
local_index: b_field,
}
}
}
impl From<&Instruction> for GetLocal {
fn from(instruction: &Instruction) -> Self {
let destination = instruction.a_field();

View File

@ -26,6 +26,10 @@ impl CallStack {
self.calls.is_empty()
}
pub fn len(&self) -> usize {
self.calls.len()
}
pub fn push(&mut self, call: FunctionCall) {
self.calls.push(call);
}

View File

@ -41,7 +41,7 @@ impl Vm {
}
pub fn run(mut self) -> Option<Value> {
let span = span!(Level::INFO, "Running");
let span = span!(Level::INFO, "Run");
let _enter = span.enter();
if self.threads.len() == 1 {

View File

@ -7,6 +7,7 @@ use crate::{DustString, Function, FunctionType, Local, Span, Value};
use super::{run_action::RunAction, Pointer, Register};
#[derive(Debug)]
pub struct Record {
pub ip: usize,
pub actions: SmallVec<[RunAction; 32]>,
@ -113,6 +114,12 @@ impl Record {
self.stack[to_register] = register;
}
pub fn reserve_registers(&mut self, count: usize) {
for _ in 0..count {
self.stack.push(Register::Empty);
}
}
pub fn open_register(&self, register_index: u8) -> &Value {
trace!("Open register R{register_index}");
@ -151,7 +158,7 @@ impl Record {
}
}
pub fn replace_register_or_clone_constant(
pub fn empty_register_or_clone_constant(
&mut self,
register_index: u8,
new_register: Register,
@ -175,6 +182,24 @@ impl Record {
}
}
pub fn clone_register_value_or_constant(&self, register_index: u8) -> Value {
assert!(
(register_index as usize) < self.stack.len(),
"VM Error: Register index out of bounds"
);
let register = &self.stack[register_index as usize];
match register {
Register::Value(value) => value.clone(),
Register::Pointer(pointer) => match pointer {
Pointer::Stack(register_index) => self.open_register(*register_index).clone(),
Pointer::Constant(constant_index) => self.get_constant(*constant_index).clone(),
},
Register::Empty => panic!("VM Error: Register {register_index} is empty"),
}
}
/// DRY helper to get a value from an Argument
pub fn get_argument(&self, index: u8, is_constant: bool) -> &Value {
if is_constant {

View File

@ -2,7 +2,8 @@ use tracing::trace;
use crate::{
instruction::{
Call, CallNative, Close, LoadBoolean, LoadConstant, LoadFunction, LoadList, LoadSelf, Point,
Call, CallNative, Close, GetLocal, LoadBoolean, LoadConstant, LoadFunction, LoadList,
LoadSelf, Point,
},
vm::VmError,
AbstractList, ConcreteValue, Instruction, InstructionData, Type, Value,
@ -194,15 +195,14 @@ pub fn load_self(instruction_data: InstructionData, record: &mut Record) -> Thre
}
pub fn get_local(instruction_data: InstructionData, record: &mut Record) -> ThreadSignal {
let InstructionData {
a_field: a,
b_field: b,
..
} = instruction_data;
let local_register_index = record.get_local_register(b);
let GetLocal {
destination,
local_index,
} = instruction_data.into();
let local_register_index = record.get_local_register(local_index);
let register = Register::Pointer(Pointer::Stack(local_register_index));
record.set_register(a, register);
record.set_register(destination, register);
ThreadSignal::Continue
}

View File

@ -1,4 +1,4 @@
use tracing::{info, trace};
use tracing::{info, span, trace, Level};
use crate::{
vm::{FunctionCall, Register},
@ -26,6 +26,12 @@ impl Thread {
}
pub fn run(&mut self) -> Option<Value> {
let mut current_call = FunctionCall {
name: None,
record_index: 0,
return_register: 0,
ip: 0,
};
let mut active = &mut self.records[0];
info!(
@ -59,6 +65,8 @@ impl Thread {
let action = active.actions[active.ip];
let signal = (action.logic)(action.data, active);
trace!("Thread Signal: {:?}", signal);
active.ip += 1;
match signal {
@ -73,8 +81,7 @@ impl Thread {
let mut arguments = Vec::with_capacity(argument_count as usize);
for register_index in first_argument_register..return_register {
let value = active
.replace_register_or_clone_constant(register_index, Register::Empty);
let value = active.clone_register_value_or_constant(register_index);
arguments.push(value);
}
@ -89,20 +96,21 @@ impl Thread {
active.ip = 0;
}
self.call_stack.push(current_call);
active.reserve_registers(arguments.len());
current_call = FunctionCall {
name: active.name().cloned(),
record_index: active.index(),
return_register,
ip: active.ip,
};
active = &mut self.records[record_index];
for (index, argument) in arguments.into_iter().enumerate() {
active.set_register(index as u8, Register::Value(argument));
}
let function_call = FunctionCall {
name: active.name().cloned(),
record_index: active.index(),
return_register,
ip: 0,
};
self.call_stack.push(function_call);
}
ThreadSignal::LoadFunction {
from_record_index,
@ -121,47 +129,41 @@ impl Thread {
active.set_register(to_register_index, register);
}
ThreadSignal::Return(should_return_value) => {
let returning_call = match self.call_stack.pop() {
Some(function_call) => function_call,
None => {
if should_return_value {
return active.last_assigned_register().map(|register| {
active.replace_register_or_clone_constant(
register,
Register::Empty,
)
});
} else {
trace!("{:#?}", self.call_stack);
if self.call_stack.is_empty() {
return None;
}
}
};
let outer_call = self.call_stack.last();
let record_index = outer_call.map_or(0, |call| call.record_index as usize);
let outer_call = self.call_stack.pop().unwrap();
let record_index = outer_call.record_index as usize;
if should_return_value {
let return_register = active
.last_assigned_register()
.unwrap_or_else(|| panic!("Expected return value"));
let return_value = active
.replace_register_or_clone_constant(return_register, Register::Empty);
.empty_register_or_clone_constant(return_register, Register::Empty);
active = &mut self.records[record_index];
active.reserve_registers((current_call.return_register + 1) as usize);
active.set_register(
returning_call.return_register,
current_call.return_register,
Register::Value(return_value),
);
} else {
active = &mut self.records[record_index];
active.ip = record_index;
}
current_call = outer_call;
}
}
}
}
}
#[derive(Debug)]
pub enum ThreadSignal {
Continue,
Call {

View File

@ -5,4 +5,4 @@ fn fib (n: int) -> int {
fib(n - 1) + fib(n - 2)
}
write_line(fib(0))
write_line(fib(2))