1
0

Begin refactoring to avoid mutating locals in the chunk

This commit is contained in:
Jeff 2024-11-09 13:49:02 -05:00
parent c343b82873
commit d82aed1a93
12 changed files with 113 additions and 208 deletions

View File

@ -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,
} }
} }
} }

View File

@ -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,

View File

@ -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);

View File

@ -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();

View File

@ -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,
} }
} }

View File

@ -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())]
)), )),
); );

View File

@ -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 )],
),],
)), )),
); );

View File

@ -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()),
] ]
)) ))
); );

View File

@ -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())]
)), )),
); );

View File

@ -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())]
)), )),
); );

View File

@ -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)),
] ]
)), )),
); );

View File

@ -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())]
)), )),
); );