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::{
|
||||||
use std::time::{Duration, Instant};
|
fs::read_to_string,
|
||||||
use std::{fs::read_to_string, path::PathBuf};
|
io::{self, stdout, Read},
|
||||||
|
path::PathBuf,
|
||||||
use clap::builder::StyledStr;
|
time::{Duration, Instant},
|
||||||
use clap::error::ErrorKind;
|
};
|
||||||
use clap::{
|
|
||||||
builder::{styling::AnsiColor, Styles},
|
use clap::{
|
||||||
crate_authors, crate_description, crate_version, ColorChoice, Parser, Subcommand, ValueHint,
|
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 color_print::cstr;
|
||||||
use dust_lang::{CompileError, Compiler, DustError, DustString, Lexer, Span, Token, Vm};
|
use dust_lang::{CompileError, Compiler, DustError, DustString, Lexer, Span, Token, Vm};
|
||||||
use tracing::subscriber::set_global_default;
|
use tracing::{subscriber::set_global_default, Level};
|
||||||
use tracing::Level;
|
|
||||||
use tracing_subscriber::FmtSubscriber;
|
use tracing_subscriber::FmtSubscriber;
|
||||||
|
|
||||||
const CLI_HELP_TEMPLATE: &str = cstr!(
|
const CLI_HELP_TEMPLATE: &str = cstr!(
|
||||||
@ -214,6 +215,7 @@ fn main() {
|
|||||||
let subscriber = FmtSubscriber::builder()
|
let subscriber = FmtSubscriber::builder()
|
||||||
.with_max_level(log_level)
|
.with_max_level(log_level)
|
||||||
.with_thread_names(true)
|
.with_thread_names(true)
|
||||||
|
.with_file(false)
|
||||||
.finish();
|
.finish();
|
||||||
|
|
||||||
set_global_default(subscriber).expect("Failed to set tracing subscriber");
|
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
|
/// [`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.
|
/// an error, then call [`Compiler::finish`] to get the compiled chunk.
|
||||||
pub fn compile(&mut self) -> Result<(), CompileError> {
|
pub fn compile(&mut self) -> Result<(), CompileError> {
|
||||||
let span = span!(Level::INFO, "Compiling");
|
let span = span!(Level::INFO, "Compile");
|
||||||
let _enter = span.enter();
|
let _enter = span.enter();
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
|
@ -1,10 +1,25 @@
|
|||||||
use crate::{Instruction, Operation};
|
use crate::{Instruction, Operation};
|
||||||
|
|
||||||
|
use super::InstructionData;
|
||||||
|
|
||||||
pub struct GetLocal {
|
pub struct GetLocal {
|
||||||
pub destination: u8,
|
pub destination: u8,
|
||||||
pub local_index: 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 {
|
impl From<&Instruction> for GetLocal {
|
||||||
fn from(instruction: &Instruction) -> Self {
|
fn from(instruction: &Instruction) -> Self {
|
||||||
let destination = instruction.a_field();
|
let destination = instruction.a_field();
|
||||||
|
@ -26,6 +26,10 @@ impl CallStack {
|
|||||||
self.calls.is_empty()
|
self.calls.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.calls.len()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, call: FunctionCall) {
|
pub fn push(&mut self, call: FunctionCall) {
|
||||||
self.calls.push(call);
|
self.calls.push(call);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(mut self) -> Option<Value> {
|
pub fn run(mut self) -> Option<Value> {
|
||||||
let span = span!(Level::INFO, "Running");
|
let span = span!(Level::INFO, "Run");
|
||||||
let _enter = span.enter();
|
let _enter = span.enter();
|
||||||
|
|
||||||
if self.threads.len() == 1 {
|
if self.threads.len() == 1 {
|
||||||
|
@ -7,6 +7,7 @@ use crate::{DustString, Function, FunctionType, Local, Span, Value};
|
|||||||
|
|
||||||
use super::{run_action::RunAction, Pointer, Register};
|
use super::{run_action::RunAction, Pointer, Register};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Record {
|
pub struct Record {
|
||||||
pub ip: usize,
|
pub ip: usize,
|
||||||
pub actions: SmallVec<[RunAction; 32]>,
|
pub actions: SmallVec<[RunAction; 32]>,
|
||||||
@ -113,6 +114,12 @@ impl Record {
|
|||||||
self.stack[to_register] = register;
|
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 {
|
pub fn open_register(&self, register_index: u8) -> &Value {
|
||||||
trace!("Open register R{register_index}");
|
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,
|
&mut self,
|
||||||
register_index: u8,
|
register_index: u8,
|
||||||
new_register: Register,
|
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
|
/// DRY helper to get a value from an Argument
|
||||||
pub fn get_argument(&self, index: u8, is_constant: bool) -> &Value {
|
pub fn get_argument(&self, index: u8, is_constant: bool) -> &Value {
|
||||||
if is_constant {
|
if is_constant {
|
||||||
|
@ -2,7 +2,8 @@ use tracing::trace;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
instruction::{
|
instruction::{
|
||||||
Call, CallNative, Close, LoadBoolean, LoadConstant, LoadFunction, LoadList, LoadSelf, Point,
|
Call, CallNative, Close, GetLocal, LoadBoolean, LoadConstant, LoadFunction, LoadList,
|
||||||
|
LoadSelf, Point,
|
||||||
},
|
},
|
||||||
vm::VmError,
|
vm::VmError,
|
||||||
AbstractList, ConcreteValue, Instruction, InstructionData, Type, Value,
|
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 {
|
pub fn get_local(instruction_data: InstructionData, record: &mut Record) -> ThreadSignal {
|
||||||
let InstructionData {
|
let GetLocal {
|
||||||
a_field: a,
|
destination,
|
||||||
b_field: b,
|
local_index,
|
||||||
..
|
} = instruction_data.into();
|
||||||
} = instruction_data;
|
let local_register_index = record.get_local_register(local_index);
|
||||||
let local_register_index = record.get_local_register(b);
|
|
||||||
let register = Register::Pointer(Pointer::Stack(local_register_index));
|
let register = Register::Pointer(Pointer::Stack(local_register_index));
|
||||||
|
|
||||||
record.set_register(a, register);
|
record.set_register(destination, register);
|
||||||
|
|
||||||
ThreadSignal::Continue
|
ThreadSignal::Continue
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use tracing::{info, trace};
|
use tracing::{info, span, trace, Level};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
vm::{FunctionCall, Register},
|
vm::{FunctionCall, Register},
|
||||||
@ -26,6 +26,12 @@ impl Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) -> Option<Value> {
|
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];
|
let mut active = &mut self.records[0];
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
@ -59,6 +65,8 @@ impl Thread {
|
|||||||
let action = active.actions[active.ip];
|
let action = active.actions[active.ip];
|
||||||
let signal = (action.logic)(action.data, active);
|
let signal = (action.logic)(action.data, active);
|
||||||
|
|
||||||
|
trace!("Thread Signal: {:?}", signal);
|
||||||
|
|
||||||
active.ip += 1;
|
active.ip += 1;
|
||||||
|
|
||||||
match signal {
|
match signal {
|
||||||
@ -73,8 +81,7 @@ impl Thread {
|
|||||||
let mut arguments = Vec::with_capacity(argument_count as usize);
|
let mut arguments = Vec::with_capacity(argument_count as usize);
|
||||||
|
|
||||||
for register_index in first_argument_register..return_register {
|
for register_index in first_argument_register..return_register {
|
||||||
let value = active
|
let value = active.clone_register_value_or_constant(register_index);
|
||||||
.replace_register_or_clone_constant(register_index, Register::Empty);
|
|
||||||
|
|
||||||
arguments.push(value);
|
arguments.push(value);
|
||||||
}
|
}
|
||||||
@ -89,20 +96,21 @@ impl Thread {
|
|||||||
active.ip = 0;
|
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];
|
active = &mut self.records[record_index];
|
||||||
|
|
||||||
for (index, argument) in arguments.into_iter().enumerate() {
|
for (index, argument) in arguments.into_iter().enumerate() {
|
||||||
active.set_register(index as u8, Register::Value(argument));
|
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 {
|
ThreadSignal::LoadFunction {
|
||||||
from_record_index,
|
from_record_index,
|
||||||
@ -121,47 +129,41 @@ impl Thread {
|
|||||||
active.set_register(to_register_index, register);
|
active.set_register(to_register_index, register);
|
||||||
}
|
}
|
||||||
ThreadSignal::Return(should_return_value) => {
|
ThreadSignal::Return(should_return_value) => {
|
||||||
let returning_call = match self.call_stack.pop() {
|
trace!("{:#?}", self.call_stack);
|
||||||
Some(function_call) => function_call,
|
|
||||||
None => {
|
if self.call_stack.is_empty() {
|
||||||
if should_return_value {
|
return None;
|
||||||
return active.last_assigned_register().map(|register| {
|
}
|
||||||
active.replace_register_or_clone_constant(
|
|
||||||
register,
|
let outer_call = self.call_stack.pop().unwrap();
|
||||||
Register::Empty,
|
let record_index = outer_call.record_index as usize;
|
||||||
)
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let outer_call = self.call_stack.last();
|
|
||||||
let record_index = outer_call.map_or(0, |call| call.record_index as usize);
|
|
||||||
|
|
||||||
if should_return_value {
|
if should_return_value {
|
||||||
let return_register = active
|
let return_register = active
|
||||||
.last_assigned_register()
|
.last_assigned_register()
|
||||||
.unwrap_or_else(|| panic!("Expected return value"));
|
.unwrap_or_else(|| panic!("Expected return value"));
|
||||||
let return_value = active
|
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 = &mut self.records[record_index];
|
||||||
|
|
||||||
|
active.reserve_registers((current_call.return_register + 1) as usize);
|
||||||
active.set_register(
|
active.set_register(
|
||||||
returning_call.return_register,
|
current_call.return_register,
|
||||||
Register::Value(return_value),
|
Register::Value(return_value),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
active = &mut self.records[record_index];
|
active = &mut self.records[record_index];
|
||||||
active.ip = record_index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
current_call = outer_call;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum ThreadSignal {
|
pub enum ThreadSignal {
|
||||||
Continue,
|
Continue,
|
||||||
Call {
|
Call {
|
||||||
|
@ -5,4 +5,4 @@ fn fib (n: int) -> int {
|
|||||||
fib(n - 1) + fib(n - 2)
|
fib(n - 1) + fib(n - 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
write_line(fib(0))
|
write_line(fib(2))
|
||||||
|
Loading…
Reference in New Issue
Block a user