Fix register-setting bug
This commit is contained in:
parent
10c66b3f95
commit
56becbfacb
@ -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");
|
||||
|
@ -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!(
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
};
|
||||
let outer_call = self.call_stack.last();
|
||||
let record_index = outer_call.map_or(0, |call| call.record_index as usize);
|
||||
trace!("{:#?}", self.call_stack);
|
||||
|
||||
if self.call_stack.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -5,4 +5,4 @@ fn fib (n: int) -> int {
|
||||
fib(n - 1) + fib(n - 2)
|
||||
}
|
||||
|
||||
write_line(fib(0))
|
||||
write_line(fib(2))
|
||||
|
Loading…
Reference in New Issue
Block a user