Begin refactoring to avoid mutating locals in the chunk
This commit is contained in:
parent
c343b82873
commit
d82aed1a93
@ -19,7 +19,6 @@ use crate::{Disassembler, Instruction, Operation, Span, Type, Value};
|
|||||||
#[derive(Clone, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct Chunk {
|
pub struct Chunk {
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
pub is_poisoned: bool,
|
|
||||||
|
|
||||||
instructions: Vec<(Instruction, Span)>,
|
instructions: Vec<(Instruction, Span)>,
|
||||||
constants: Vec<Value>,
|
constants: Vec<Value>,
|
||||||
@ -33,7 +32,6 @@ impl Chunk {
|
|||||||
pub fn new(name: Option<String>) -> Self {
|
pub fn new(name: Option<String>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
is_poisoned: false,
|
|
||||||
instructions: Vec::new(),
|
instructions: Vec::new(),
|
||||||
constants: Vec::new(),
|
constants: Vec::new(),
|
||||||
locals: Vec::new(),
|
locals: Vec::new(),
|
||||||
@ -50,7 +48,6 @@ impl Chunk {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
is_poisoned: false,
|
|
||||||
instructions,
|
instructions,
|
||||||
constants,
|
constants,
|
||||||
locals,
|
locals,
|
||||||
@ -175,14 +172,6 @@ impl Chunk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_not_poisoned(&self) -> Result<(), ChunkError> {
|
|
||||||
if self.is_poisoned {
|
|
||||||
Err(ChunkError::PoisonedChunk)
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_constant_type(&self, constant_index: u8) -> Option<Type> {
|
pub fn get_constant_type(&self, constant_index: u8) -> Option<Type> {
|
||||||
self.constants
|
self.constants
|
||||||
.get(constant_index as usize)
|
.get(constant_index as usize)
|
||||||
@ -194,16 +183,6 @@ impl Chunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_register_type(&self, register_index: u8) -> Option<Type> {
|
pub fn get_register_type(&self, register_index: u8) -> Option<Type> {
|
||||||
let local_type_option = self
|
|
||||||
.locals
|
|
||||||
.iter()
|
|
||||||
.find(|local| local.register_index == register_index)
|
|
||||||
.map(|local| local.r#type.clone());
|
|
||||||
|
|
||||||
if let Some(local_type) = local_type_option {
|
|
||||||
return local_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.instructions
|
self.instructions
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
@ -316,26 +295,16 @@ pub struct Local {
|
|||||||
|
|
||||||
/// Scope where the variable was declared.
|
/// Scope where the variable was declared.
|
||||||
pub scope: Scope,
|
pub scope: Scope,
|
||||||
|
|
||||||
/// Expected location of a local's value.
|
|
||||||
pub register_index: u8,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Local {
|
impl Local {
|
||||||
/// Creates a new Local instance.
|
/// Creates a new Local instance.
|
||||||
pub fn new(
|
pub fn new(identifier_index: u8, r#type: Option<Type>, mutable: bool, scope: Scope) -> Self {
|
||||||
identifier_index: u8,
|
|
||||||
r#type: Option<Type>,
|
|
||||||
mutable: bool,
|
|
||||||
scope: Scope,
|
|
||||||
register_index: u8,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
identifier_index,
|
identifier_index,
|
||||||
r#type,
|
r#type,
|
||||||
is_mutable: mutable,
|
is_mutable: mutable,
|
||||||
scope,
|
scope,
|
||||||
register_index,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,8 +48,9 @@ pub fn compile(source: &str) -> Result<Chunk, DustError> {
|
|||||||
pub struct Compiler<'src> {
|
pub struct Compiler<'src> {
|
||||||
chunk: Chunk,
|
chunk: Chunk,
|
||||||
lexer: Lexer<'src>,
|
lexer: Lexer<'src>,
|
||||||
optimization_count: usize,
|
|
||||||
|
|
||||||
|
local_definitions: Vec<u8>,
|
||||||
|
optimization_count: usize,
|
||||||
previous_is_expression: bool,
|
previous_is_expression: bool,
|
||||||
minimum_register: u8,
|
minimum_register: u8,
|
||||||
|
|
||||||
@ -74,6 +75,7 @@ impl<'src> Compiler<'src> {
|
|||||||
Ok(Compiler {
|
Ok(Compiler {
|
||||||
chunk,
|
chunk,
|
||||||
lexer,
|
lexer,
|
||||||
|
local_definitions: Vec::new(),
|
||||||
optimization_count: 0,
|
optimization_count: 0,
|
||||||
previous_is_expression: false,
|
previous_is_expression: false,
|
||||||
minimum_register: 0,
|
minimum_register: 0,
|
||||||
@ -178,13 +180,10 @@ impl<'src> Compiler<'src> {
|
|||||||
let identifier = Value::string(identifier);
|
let identifier = Value::string(identifier);
|
||||||
let identifier_index = self.chunk.push_or_get_constant(identifier);
|
let identifier_index = self.chunk.push_or_get_constant(identifier);
|
||||||
|
|
||||||
self.chunk.locals_mut().push(Local::new(
|
self.chunk
|
||||||
identifier_index,
|
.locals_mut()
|
||||||
r#type,
|
.push(Local::new(identifier_index, r#type, is_mutable, scope));
|
||||||
is_mutable,
|
self.local_definitions.push(register_index);
|
||||||
scope,
|
|
||||||
register_index,
|
|
||||||
));
|
|
||||||
|
|
||||||
(self.chunk.locals().len() as u8 - 1, identifier_index)
|
(self.chunk.locals().len() as u8 - 1, identifier_index)
|
||||||
}
|
}
|
||||||
@ -505,7 +504,22 @@ impl<'src> Compiler<'src> {
|
|||||||
let local = self.get_local(local_index)?;
|
let local = self.get_local(local_index)?;
|
||||||
is_mutable_local = local.is_mutable;
|
is_mutable_local = local.is_mutable;
|
||||||
|
|
||||||
local.register_index
|
*self
|
||||||
|
.local_definitions
|
||||||
|
.get(local_index as usize)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
let identifier = self
|
||||||
|
.chunk
|
||||||
|
.constants()
|
||||||
|
.get(local.identifier_index as usize)
|
||||||
|
.unwrap()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
CompileError::UndeclaredVariable {
|
||||||
|
identifier,
|
||||||
|
position: self.current_position,
|
||||||
|
}
|
||||||
|
})?
|
||||||
}
|
}
|
||||||
Operation::LoadConstant => {
|
Operation::LoadConstant => {
|
||||||
is_constant = true;
|
is_constant = true;
|
||||||
@ -821,28 +835,8 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
|
|
||||||
let (mut previous_instruction, previous_position) =
|
let register = self.next_register() - 1;
|
||||||
self.chunk.instructions_mut().pop().ok_or_else(|| {
|
|
||||||
CompileError::ExpectedExpression {
|
|
||||||
found: self.previous_token.to_owned(),
|
|
||||||
position: self.previous_position,
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if previous_instruction.operation().is_math() {
|
|
||||||
let register_index = self.get_local(local_index)?.register_index;
|
|
||||||
|
|
||||||
log::trace!("Condensing SET_LOCAL to binary math expression");
|
|
||||||
|
|
||||||
previous_instruction.set_a(register_index);
|
|
||||||
self.emit_instruction(previous_instruction, self.current_position);
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let register = self.next_register();
|
|
||||||
|
|
||||||
self.emit_instruction(previous_instruction, previous_position);
|
|
||||||
self.emit_instruction(
|
self.emit_instruction(
|
||||||
Instruction::set_local(register, local_index),
|
Instruction::set_local(register, local_index),
|
||||||
start_position,
|
start_position,
|
||||||
@ -1235,13 +1229,12 @@ impl<'src> Compiler<'src> {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let register = self.next_register();
|
|
||||||
|
|
||||||
self.expect(Token::Equal)?;
|
self.expect(Token::Equal)?;
|
||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
|
|
||||||
let (local_index, _) = self.declare_local(identifier, r#type, is_mutable, scope, register);
|
|
||||||
let register = self.next_register().saturating_sub(1);
|
let register = self.next_register().saturating_sub(1);
|
||||||
|
let (local_index, _) = self.declare_local(identifier, r#type, is_mutable, scope, register);
|
||||||
|
|
||||||
self.emit_instruction(
|
self.emit_instruction(
|
||||||
Instruction::define_local(register, local_index, is_mutable),
|
Instruction::define_local(register, local_index, is_mutable),
|
||||||
@ -1294,10 +1287,8 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
function_compiler.advance()?;
|
function_compiler.advance()?;
|
||||||
|
|
||||||
let register = value_parameters
|
let register = function_compiler.next_register();
|
||||||
.as_ref()
|
|
||||||
.map(|values| values.len() as u8)
|
|
||||||
.unwrap_or(0);
|
|
||||||
let scope = function_compiler.chunk.current_scope();
|
let scope = function_compiler.chunk.current_scope();
|
||||||
let (_, identifier_index) = function_compiler.declare_local(
|
let (_, identifier_index) = function_compiler.declare_local(
|
||||||
parameter,
|
parameter,
|
||||||
|
@ -295,7 +295,6 @@ impl<'a> Disassembler<'a> {
|
|||||||
identifier_index,
|
identifier_index,
|
||||||
r#type,
|
r#type,
|
||||||
scope,
|
scope,
|
||||||
register_index,
|
|
||||||
is_mutable: mutable,
|
is_mutable: mutable,
|
||||||
},
|
},
|
||||||
) in self.chunk.locals().iter().enumerate()
|
) in self.chunk.locals().iter().enumerate()
|
||||||
@ -319,7 +318,7 @@ impl<'a> Disassembler<'a> {
|
|||||||
})
|
})
|
||||||
.unwrap_or("unknown".to_string());
|
.unwrap_or("unknown".to_string());
|
||||||
let local_display = format!(
|
let local_display = format!(
|
||||||
"{index:^3} {identifier_display:10} {type_display:16} {mutable:7} {scope:7} {register_index:8}"
|
"{index:^3} {identifier_display:10} {type_display:16} {mutable:7} {scope:7}"
|
||||||
);
|
);
|
||||||
|
|
||||||
self.push_details(&local_display);
|
self.push_details(&local_display);
|
||||||
|
@ -324,13 +324,14 @@ impl NativeFunction {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let first_index = to_register.saturating_sub(argument_count);
|
let first_index = to_register.saturating_sub(argument_count);
|
||||||
let arguments = vm.open_nonempty_registers(first_index..to_register, position)?;
|
|
||||||
|
|
||||||
for (index, argument) in arguments.into_iter().enumerate() {
|
for (index, register) in (first_index..to_register).enumerate() {
|
||||||
if index != 0 {
|
if index != 0 {
|
||||||
stdout.write(b" ").map_err(map_err)?;
|
stdout.write(b" ").map_err(map_err)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let argument = vm.open_register(register, position)?;
|
||||||
|
|
||||||
if let Value::Concrete(ConcreteValue::String(string)) = argument {
|
if let Value::Concrete(ConcreteValue::String(string)) = argument {
|
||||||
let bytes = string.as_bytes();
|
let bytes = string.as_bytes();
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
//! Virtual machine and errors
|
//! Virtual machine and errors
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
|
collections::HashMap,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
ops::Range,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -12,8 +12,8 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
||||||
let mut chunk = compile(source)?;
|
let chunk = compile(source)?;
|
||||||
let mut vm = Vm::new(&mut chunk, None);
|
let mut vm = Vm::new(&chunk, None);
|
||||||
|
|
||||||
vm.run()
|
vm.run()
|
||||||
.map(|option| option.cloned())
|
.map(|option| option.cloned())
|
||||||
@ -34,8 +34,9 @@ pub fn run_and_display_output(source: &str) {
|
|||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub struct Vm<'chunk, 'parent> {
|
pub struct Vm<'chunk, 'parent> {
|
||||||
ip: usize,
|
ip: usize,
|
||||||
chunk: &'chunk mut Chunk,
|
chunk: &'chunk Chunk,
|
||||||
stack: Vec<Register>,
|
stack: Vec<Register>,
|
||||||
|
local_definitions: HashMap<u8, u8>,
|
||||||
last_assigned_register: Option<u8>,
|
last_assigned_register: Option<u8>,
|
||||||
parent: Option<&'parent Vm<'chunk, 'parent>>,
|
parent: Option<&'parent Vm<'chunk, 'parent>>,
|
||||||
}
|
}
|
||||||
@ -43,11 +44,12 @@ pub struct Vm<'chunk, 'parent> {
|
|||||||
impl<'chunk, 'parent> Vm<'chunk, 'parent> {
|
impl<'chunk, 'parent> Vm<'chunk, 'parent> {
|
||||||
const STACK_LIMIT: usize = u16::MAX as usize;
|
const STACK_LIMIT: usize = u16::MAX as usize;
|
||||||
|
|
||||||
pub fn new(chunk: &'chunk mut Chunk, parent: Option<&'parent Vm<'chunk, 'parent>>) -> Self {
|
pub fn new(chunk: &'chunk Chunk, parent: Option<&'parent Vm<'chunk, 'parent>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ip: 0,
|
ip: 0,
|
||||||
chunk,
|
chunk,
|
||||||
stack: Vec::new(),
|
stack: Vec::new(),
|
||||||
|
local_definitions: HashMap::new(),
|
||||||
last_assigned_register: None,
|
last_assigned_register: None,
|
||||||
parent,
|
parent,
|
||||||
}
|
}
|
||||||
@ -172,24 +174,39 @@ impl<'chunk, 'parent> Vm<'chunk, 'parent> {
|
|||||||
let from_register = instruction.a();
|
let from_register = instruction.a();
|
||||||
let to_local = instruction.b();
|
let to_local = instruction.b();
|
||||||
|
|
||||||
self.define_local(to_local, from_register, position)?;
|
self.define_local(to_local, from_register)?;
|
||||||
}
|
}
|
||||||
Operation::GetLocal => {
|
Operation::GetLocal => {
|
||||||
let to_register = instruction.a();
|
let to_register = instruction.a();
|
||||||
let local_index = instruction.b();
|
let local_index = instruction.b();
|
||||||
let local = self.get_local(local_index, position)?;
|
let local_register = self.local_definitions.get(&local_index).copied().ok_or(
|
||||||
|
VmError::UndefinedLocal {
|
||||||
|
local_index,
|
||||||
|
position,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
self.set_register(
|
self.set_register(
|
||||||
to_register,
|
to_register,
|
||||||
Register::StackPointer(local.register_index),
|
Register::StackPointer(local_register),
|
||||||
position,
|
position,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Operation::SetLocal => {
|
Operation::SetLocal => {
|
||||||
let register = instruction.a();
|
let from_register = instruction.a();
|
||||||
let local_index = instruction.b();
|
let to_local = instruction.b();
|
||||||
|
let local_register = self.local_definitions.get(&to_local).copied().ok_or(
|
||||||
|
VmError::UndefinedLocal {
|
||||||
|
local_index: to_local,
|
||||||
|
position,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
self.define_local(local_index, register, position)?;
|
self.set_register(
|
||||||
|
local_register,
|
||||||
|
Register::StackPointer(from_register),
|
||||||
|
position,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
Operation::Add => {
|
Operation::Add => {
|
||||||
let to_register = instruction.a();
|
let to_register = instruction.a();
|
||||||
@ -401,17 +418,17 @@ impl<'chunk, 'parent> Vm<'chunk, 'parent> {
|
|||||||
let to_register = instruction.a();
|
let to_register = instruction.a();
|
||||||
let function_register = instruction.b();
|
let function_register = instruction.b();
|
||||||
let argument_count = instruction.c();
|
let argument_count = instruction.c();
|
||||||
let value = self.open_register(function_register, position)?.clone();
|
let value = self.open_register(function_register, position)?;
|
||||||
let mut function =
|
let function = if let Value::Concrete(ConcreteValue::Function(function)) = value
|
||||||
if let Value::Concrete(ConcreteValue::Function(function)) = value {
|
{
|
||||||
function
|
function
|
||||||
} else {
|
} else {
|
||||||
return Err(VmError::ExpectedFunction {
|
return Err(VmError::ExpectedFunction {
|
||||||
found: value,
|
found: value.clone(),
|
||||||
position,
|
position,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
let mut function_vm = Vm::new(function.chunk_mut(), Some(self));
|
let mut function_vm = Vm::new(function.chunk(), Some(self));
|
||||||
let first_argument_index = function_register + 1;
|
let first_argument_index = function_register + 1;
|
||||||
|
|
||||||
for argument_index in
|
for argument_index in
|
||||||
@ -527,6 +544,8 @@ impl<'chunk, 'parent> Vm<'chunk, 'parent> {
|
|||||||
position,
|
position,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
log::trace!("Open R{register_index} to {register}");
|
||||||
|
|
||||||
match register {
|
match register {
|
||||||
Register::Value(value) => Ok(value),
|
Register::Value(value) => Ok(value),
|
||||||
Register::StackPointer(register_index) => self.open_register(*register_index, position),
|
Register::StackPointer(register_index) => self.open_register(*register_index, position),
|
||||||
@ -556,67 +575,7 @@ impl<'chunk, 'parent> Vm<'chunk, 'parent> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_nonempty_registers(
|
|
||||||
&self,
|
|
||||||
register_index_range: Range<u8>,
|
|
||||||
position: Span,
|
|
||||||
) -> Result<Vec<&Value>, VmError> {
|
|
||||||
let mut values = Vec::with_capacity(register_index_range.len());
|
|
||||||
|
|
||||||
for register_index in register_index_range.clone() {
|
|
||||||
let register_index = register_index as usize;
|
|
||||||
let register = self.stack.get(register_index).ok_or_else(|| {
|
|
||||||
VmError::RegisterIndexOutOfBounds {
|
|
||||||
index: register_index,
|
|
||||||
position,
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let value = match register {
|
|
||||||
Register::Value(value) => value,
|
|
||||||
Register::StackPointer(register_index) => {
|
|
||||||
self.open_register(*register_index, position)?
|
|
||||||
}
|
|
||||||
Register::ConstantPointer(constant_index) => {
|
|
||||||
self.get_constant(*constant_index, position)?
|
|
||||||
}
|
|
||||||
Register::ParentStackPointer(register_index) => {
|
|
||||||
let parent = self
|
|
||||||
.parent
|
|
||||||
.as_ref()
|
|
||||||
.ok_or(VmError::ExpectedParent { position })?;
|
|
||||||
|
|
||||||
parent.open_register(*register_index, position)?
|
|
||||||
}
|
|
||||||
Register::ParentConstantPointer(constant_index) => {
|
|
||||||
let parent = self
|
|
||||||
.parent
|
|
||||||
.as_ref()
|
|
||||||
.ok_or(VmError::ExpectedParent { position })?;
|
|
||||||
|
|
||||||
parent.get_constant(*constant_index, position)?
|
|
||||||
}
|
|
||||||
Register::Empty => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
values.push(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if values.is_empty() {
|
|
||||||
Err(VmError::EmptyRegisters {
|
|
||||||
indexes: register_index_range,
|
|
||||||
position,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Ok(values)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&mut self, position: Span) -> Result<&(Instruction, Span), VmError> {
|
fn read(&mut self, position: Span) -> Result<&(Instruction, Span), VmError> {
|
||||||
self.chunk
|
|
||||||
.expect_not_poisoned()
|
|
||||||
.map_err(|error| VmError::Chunk { error, position })?;
|
|
||||||
|
|
||||||
let max_ip = self.chunk.len() - 1;
|
let max_ip = self.chunk.len() - 1;
|
||||||
|
|
||||||
if self.ip > max_ip {
|
if self.ip > max_ip {
|
||||||
@ -628,20 +587,10 @@ impl<'chunk, 'parent> Vm<'chunk, 'parent> {
|
|||||||
self.get_instruction(self.ip - 1, position)
|
self.get_instruction(self.ip - 1, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn define_local(
|
fn define_local(&mut self, local_index: u8, register_index: u8) -> Result<(), VmError> {
|
||||||
&mut self,
|
|
||||||
local_index: u8,
|
|
||||||
register_index: u8,
|
|
||||||
position: Span,
|
|
||||||
) -> Result<(), VmError> {
|
|
||||||
let local = self
|
|
||||||
.chunk
|
|
||||||
.get_local_mut(local_index)
|
|
||||||
.map_err(|error| VmError::Chunk { error, position })?;
|
|
||||||
|
|
||||||
log::debug!("Define local L{}", local_index);
|
log::debug!("Define local L{}", local_index);
|
||||||
|
|
||||||
local.register_index = register_index;
|
self.local_definitions.insert(local_index, register_index);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -694,9 +643,11 @@ pub enum VmError {
|
|||||||
|
|
||||||
// Register errors
|
// Register errors
|
||||||
EmptyRegister { index: usize, position: Span },
|
EmptyRegister { index: usize, position: Span },
|
||||||
EmptyRegisters { indexes: Range<u8>, position: Span },
|
|
||||||
RegisterIndexOutOfBounds { index: usize, position: Span },
|
RegisterIndexOutOfBounds { index: usize, position: Span },
|
||||||
|
|
||||||
|
// Local errors
|
||||||
|
UndefinedLocal { local_index: u8, position: Span },
|
||||||
|
|
||||||
// Execution errors
|
// Execution errors
|
||||||
ExpectedBoolean { found: Value, position: Span },
|
ExpectedBoolean { found: Value, position: Span },
|
||||||
ExpectedFunction { found: Value, position: Span },
|
ExpectedFunction { found: Value, position: Span },
|
||||||
@ -717,7 +668,6 @@ impl AnnotatedError for VmError {
|
|||||||
match self {
|
match self {
|
||||||
Self::Chunk { .. } => "Chunk error",
|
Self::Chunk { .. } => "Chunk error",
|
||||||
Self::EmptyRegister { .. } => "Empty register",
|
Self::EmptyRegister { .. } => "Empty register",
|
||||||
Self::EmptyRegisters { .. } => "Empty registers",
|
|
||||||
Self::ExpectedBoolean { .. } => "Expected boolean",
|
Self::ExpectedBoolean { .. } => "Expected boolean",
|
||||||
Self::ExpectedFunction { .. } => "Expected function",
|
Self::ExpectedFunction { .. } => "Expected function",
|
||||||
Self::ExpectedParent { .. } => "Expected parent",
|
Self::ExpectedParent { .. } => "Expected parent",
|
||||||
@ -725,6 +675,7 @@ impl AnnotatedError for VmError {
|
|||||||
Self::RegisterIndexOutOfBounds { .. } => "Register index out of bounds",
|
Self::RegisterIndexOutOfBounds { .. } => "Register index out of bounds",
|
||||||
Self::StackOverflow { .. } => "Stack overflow",
|
Self::StackOverflow { .. } => "Stack overflow",
|
||||||
Self::StackUnderflow { .. } => "Stack underflow",
|
Self::StackUnderflow { .. } => "Stack underflow",
|
||||||
|
Self::UndefinedLocal { .. } => "Undefined local",
|
||||||
Self::Value { .. } => "Value error",
|
Self::Value { .. } => "Value error",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -733,10 +684,6 @@ impl AnnotatedError for VmError {
|
|||||||
match self {
|
match self {
|
||||||
Self::Chunk { error, .. } => Some(error.to_string()),
|
Self::Chunk { error, .. } => Some(error.to_string()),
|
||||||
Self::EmptyRegister { index, .. } => Some(format!("Register R{index} is empty")),
|
Self::EmptyRegister { index, .. } => Some(format!("Register R{index} is empty")),
|
||||||
Self::EmptyRegisters { indexes: range, .. } => Some(format!(
|
|
||||||
"Registers R{} to R{} are empty",
|
|
||||||
range.start, range.end
|
|
||||||
)),
|
|
||||||
Self::ExpectedFunction { found, .. } => Some(format!("{found} is not a function")),
|
Self::ExpectedFunction { found, .. } => Some(format!("{found} is not a function")),
|
||||||
Self::RegisterIndexOutOfBounds { index, .. } => {
|
Self::RegisterIndexOutOfBounds { index, .. } => {
|
||||||
Some(format!("Register {index} does not exist"))
|
Some(format!("Register {index} does not exist"))
|
||||||
@ -751,7 +698,6 @@ impl AnnotatedError for VmError {
|
|||||||
match self {
|
match self {
|
||||||
Self::Chunk { position, .. } => *position,
|
Self::Chunk { position, .. } => *position,
|
||||||
Self::EmptyRegister { position, .. } => *position,
|
Self::EmptyRegister { position, .. } => *position,
|
||||||
Self::EmptyRegisters { position, .. } => *position,
|
|
||||||
Self::ExpectedBoolean { position, .. } => *position,
|
Self::ExpectedBoolean { position, .. } => *position,
|
||||||
Self::ExpectedFunction { position, .. } => *position,
|
Self::ExpectedFunction { position, .. } => *position,
|
||||||
Self::ExpectedParent { position } => *position,
|
Self::ExpectedParent { position } => *position,
|
||||||
@ -759,6 +705,7 @@ impl AnnotatedError for VmError {
|
|||||||
Self::RegisterIndexOutOfBounds { position, .. } => *position,
|
Self::RegisterIndexOutOfBounds { position, .. } => *position,
|
||||||
Self::StackOverflow { position } => *position,
|
Self::StackOverflow { position } => *position,
|
||||||
Self::StackUnderflow { position } => *position,
|
Self::StackUnderflow { position } => *position,
|
||||||
|
Self::UndefinedLocal { position, .. } => *position,
|
||||||
Self::Value { position, .. } => *position,
|
Self::Value { position, .. } => *position,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,6 @@ fn equality_assignment_long() {
|
|||||||
depth: 0,
|
depth: 0,
|
||||||
block_index: 0
|
block_index: 0
|
||||||
},
|
},
|
||||||
0
|
|
||||||
)]
|
)]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
@ -62,7 +61,7 @@ fn equality_assignment_short() {
|
|||||||
(Instruction::r#return(true), Span(16, 16)),
|
(Instruction::r#return(true), Span(16, 16)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(4), Value::string("a")],
|
vec![Value::integer(4), Value::string("a")],
|
||||||
vec![Local::new(1, None, false, Scope::default(), 0)]
|
vec![Local::new(1, None, false, Scope::default())]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -120,7 +119,7 @@ fn if_else_assigment_false() {
|
|||||||
Value::integer(42),
|
Value::integer(42),
|
||||||
Value::string("a")
|
Value::string("a")
|
||||||
],
|
],
|
||||||
vec![Local::new(5, None, false, Scope::default(), 0)]
|
vec![Local::new(5, None, false, Scope::default())]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -178,7 +177,7 @@ fn if_else_assigment_true() {
|
|||||||
Value::integer(42),
|
Value::integer(42),
|
||||||
Value::string("a")
|
Value::string("a")
|
||||||
],
|
],
|
||||||
vec![Local::new(5, None, false, Scope::default(), 0)]
|
vec![Local::new(5, None, false, Scope::default())]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -15,8 +15,8 @@ fn function() {
|
|||||||
],
|
],
|
||||||
vec![Value::string("a"), Value::string("b"),],
|
vec![Value::string("a"), Value::string("b"),],
|
||||||
vec![
|
vec![
|
||||||
Local::new(0, Some(Type::Integer), false, Scope::default(), 0),
|
Local::new(0, Some(Type::Integer), false, Scope::default()),
|
||||||
Local::new(1, Some(Type::Integer), false, Scope::default(), 1)
|
Local::new(1, Some(Type::Integer), false, Scope::default())
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
FunctionType {
|
FunctionType {
|
||||||
@ -53,8 +53,8 @@ fn function_call() {
|
|||||||
],
|
],
|
||||||
vec![Value::string("a"), Value::string("b"),],
|
vec![Value::string("a"), Value::string("b"),],
|
||||||
vec![
|
vec![
|
||||||
Local::new(0, Some(Type::Integer), false, Scope::default(), 0),
|
Local::new(0, Some(Type::Integer), false, Scope::default()),
|
||||||
Local::new(1, Some(Type::Integer), false, Scope::default(), 1)
|
Local::new(1, Some(Type::Integer), false, Scope::default())
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
FunctionType {
|
FunctionType {
|
||||||
@ -97,8 +97,8 @@ fn function_declaration() {
|
|||||||
],
|
],
|
||||||
vec![Value::string("a"), Value::string("b")],
|
vec![Value::string("a"), Value::string("b")],
|
||||||
vec![
|
vec![
|
||||||
Local::new(0, Some(Type::Integer), false, Scope::default(), 0),
|
Local::new(0, Some(Type::Integer), false, Scope::default()),
|
||||||
Local::new(1, Some(Type::Integer), false, Scope::default(), 1)
|
Local::new(1, Some(Type::Integer), false, Scope::default())
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
FunctionType {
|
FunctionType {
|
||||||
@ -117,8 +117,7 @@ fn function_declaration() {
|
|||||||
})),
|
})),
|
||||||
false,
|
false,
|
||||||
Scope::default(),
|
Scope::default(),
|
||||||
0
|
)],
|
||||||
),],
|
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -67,8 +67,8 @@ fn variable_and() {
|
|||||||
],
|
],
|
||||||
vec![Value::string("a"), Value::string("b"),],
|
vec![Value::string("a"), Value::string("b"),],
|
||||||
vec![
|
vec![
|
||||||
Local::new(0, None, false, Scope::default(), 0),
|
Local::new(0, None, false, Scope::default()),
|
||||||
Local::new(1, None, false, Scope::default(), 1),
|
Local::new(1, None, false, Scope::default()),
|
||||||
]
|
]
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
@ -27,7 +27,7 @@ fn r#while() {
|
|||||||
Value::integer(5),
|
Value::integer(5),
|
||||||
Value::integer(1),
|
Value::integer(1),
|
||||||
],
|
],
|
||||||
vec![Local::new(1, None, true, Scope::default(), 0),]
|
vec![Local::new(1, None, true, Scope::default())]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ fn add_assign() {
|
|||||||
(Instruction::r#return(true), Span(24, 24))
|
(Instruction::r#return(true), Span(24, 24))
|
||||||
],
|
],
|
||||||
vec![Value::integer(1), Value::string("a"), Value::integer(2)],
|
vec![Value::integer(1), Value::string("a"), Value::integer(2)],
|
||||||
vec![Local::new(1, None, true, Scope::default(), 0)]
|
vec![Local::new(1, None, true, Scope::default())]
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ fn divide_assign() {
|
|||||||
(Instruction::r#return(true), Span(24, 24))
|
(Instruction::r#return(true), Span(24, 24))
|
||||||
],
|
],
|
||||||
vec![Value::integer(2), Value::string("a")],
|
vec![Value::integer(2), Value::string("a")],
|
||||||
vec![Local::new(1, None, true, Scope::default(), 0)]
|
vec![Local::new(1, None, true, Scope::default())]
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -233,7 +233,7 @@ fn multiply_assign() {
|
|||||||
(Instruction::r#return(true), Span(23, 23))
|
(Instruction::r#return(true), Span(23, 23))
|
||||||
],
|
],
|
||||||
vec![Value::integer(2), Value::string("a"), Value::integer(3)],
|
vec![Value::integer(2), Value::string("a"), Value::integer(3)],
|
||||||
vec![Local::new(1, None, true, Scope::default(), 0),]
|
vec![Local::new(1, None, true, Scope::default())]
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -300,7 +300,7 @@ fn subtract_assign() {
|
|||||||
(Instruction::r#return(true), Span(25, 25)),
|
(Instruction::r#return(true), Span(25, 25)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(42), Value::string("x"), Value::integer(2)],
|
vec![Value::integer(42), Value::string("x"), Value::integer(2)],
|
||||||
vec![Local::new(1, None, true, Scope::default(), 0)]
|
vec![Local::new(1, None, true, Scope::default())]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -55,11 +55,11 @@ fn block_scope() {
|
|||||||
Value::string("e"),
|
Value::string("e"),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
Local::new(1, None, false, Scope::new(0, 0), 0),
|
Local::new(1, None, false, Scope::new(0, 0)),
|
||||||
Local::new(3, None, false, Scope::new(1, 1), 1),
|
Local::new(3, None, false, Scope::new(1, 1)),
|
||||||
Local::new(5, None, false, Scope::new(2, 2), 2),
|
Local::new(5, None, false, Scope::new(2, 2)),
|
||||||
Local::new(7, None, false, Scope::new(1, 1), 3),
|
Local::new(7, None, false, Scope::new(1, 1)),
|
||||||
Local::new(8, None, false, Scope::new(0, 0), 4),
|
Local::new(8, None, false, Scope::new(0, 0)),
|
||||||
]
|
]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
@ -127,15 +127,15 @@ fn multiple_block_scopes() {
|
|||||||
Value::string("e"),
|
Value::string("e"),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
Local::new(1, None, false, Scope::new(0, 0), 0),
|
Local::new(1, None, false, Scope::new(0, 0)),
|
||||||
Local::new(3, None, false, Scope::new(1, 1), 1),
|
Local::new(3, None, false, Scope::new(1, 1)),
|
||||||
Local::new(5, None, false, Scope::new(2, 2), 2),
|
Local::new(5, None, false, Scope::new(2, 2)),
|
||||||
Local::new(7, None, false, Scope::new(1, 1), 3),
|
Local::new(7, None, false, Scope::new(1, 1)),
|
||||||
Local::new(8, None, false, Scope::new(0, 0), 4),
|
Local::new(8, None, false, Scope::new(0, 0)),
|
||||||
Local::new(3, None, false, Scope::new(1, 3), 5),
|
Local::new(3, None, false, Scope::new(1, 3)),
|
||||||
Local::new(5, None, false, Scope::new(2, 4), 6),
|
Local::new(5, None, false, Scope::new(2, 4)),
|
||||||
Local::new(7, None, false, Scope::new(1, 3), 7),
|
Local::new(7, None, false, Scope::new(1, 3)),
|
||||||
Local::new(9, None, false, Scope::new(0, 0), 8),
|
Local::new(9, None, false, Scope::new(0, 0)),
|
||||||
]
|
]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
@ -14,7 +14,7 @@ fn define_local() {
|
|||||||
(Instruction::r#return(false), Span(11, 11))
|
(Instruction::r#return(false), Span(11, 11))
|
||||||
],
|
],
|
||||||
vec![Value::integer(42), Value::string("x")],
|
vec![Value::integer(42), Value::string("x")],
|
||||||
vec![Local::new(1, None, false, Scope::default(), 0)]
|
vec![Local::new(1, None, false, Scope::default())]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ fn set_local() {
|
|||||||
(Instruction::r#return(true), Span(25, 25)),
|
(Instruction::r#return(true), Span(25, 25)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(41), Value::string("x"), Value::integer(42)],
|
vec![Value::integer(41), Value::string("x"), Value::integer(42)],
|
||||||
vec![Local::new(1, None, true, Scope::default(), 0)]
|
vec![Local::new(1, None, true, Scope::default())]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user