Refactor VM, chunk and parser to pass tests
This commit is contained in:
parent
9b1dc6c55c
commit
9d0aa13e8a
@ -308,7 +308,7 @@ impl PartialEq for Chunk {
|
|||||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Local {
|
pub struct Local {
|
||||||
pub identifier: Identifier,
|
pub identifier: Identifier,
|
||||||
pub mutable: bool,
|
pub is_mutable: bool,
|
||||||
pub depth: usize,
|
pub depth: usize,
|
||||||
pub register_index: Option<u8>,
|
pub register_index: Option<u8>,
|
||||||
}
|
}
|
||||||
@ -322,7 +322,7 @@ impl Local {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
identifier,
|
identifier,
|
||||||
mutable,
|
is_mutable: mutable,
|
||||||
depth,
|
depth,
|
||||||
register_index,
|
register_index,
|
||||||
}
|
}
|
||||||
@ -481,7 +481,7 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
identifier,
|
identifier,
|
||||||
depth,
|
depth,
|
||||||
register_index,
|
register_index,
|
||||||
mutable,
|
is_mutable: mutable,
|
||||||
},
|
},
|
||||||
) in self.chunk.locals.iter().enumerate()
|
) in self.chunk.locals.iter().enumerate()
|
||||||
{
|
{
|
||||||
|
@ -206,13 +206,8 @@ impl Instruction {
|
|||||||
instruction
|
instruction
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn r#return(from_register: u8, to_register: u8) -> Instruction {
|
pub fn r#return() -> Instruction {
|
||||||
let mut instruction = Instruction(Operation::Return as u32);
|
Instruction(Operation::Return as u32)
|
||||||
|
|
||||||
instruction.set_a(from_register);
|
|
||||||
instruction.set_b(to_register);
|
|
||||||
|
|
||||||
instruction
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn operation(&self) -> Operation {
|
pub fn operation(&self) -> Operation {
|
||||||
@ -350,7 +345,14 @@ impl Instruction {
|
|||||||
Operation::LoadConstant => {
|
Operation::LoadConstant => {
|
||||||
let register_index = self.a();
|
let register_index = self.a();
|
||||||
let constant_index = self.b();
|
let constant_index = self.b();
|
||||||
let jump = if self.c_as_boolean() { "&& JUMP" } else { "" };
|
let jump = if self.c_as_boolean() {
|
||||||
|
jump_offset = Some(1);
|
||||||
|
|
||||||
|
"&& JUMP"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
|
||||||
let constant = if let Some(chunk) = chunk {
|
let constant = if let Some(chunk) = chunk {
|
||||||
match chunk.get_constant(constant_index, Span(0, 0)) {
|
match chunk.get_constant(constant_index, Span(0, 0)) {
|
||||||
Ok(constant) => constant.to_string(),
|
Ok(constant) => constant.to_string(),
|
||||||
@ -531,12 +533,7 @@ impl Instruction {
|
|||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Operation::Return => {
|
Operation::Return => None,
|
||||||
let from_register = self.a();
|
|
||||||
let to_register = self.b();
|
|
||||||
|
|
||||||
Some(format!("R{from_register}..=R{to_register}"))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
(info, jump_offset)
|
(info, jump_offset)
|
||||||
@ -745,10 +742,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn r#return() {
|
fn r#return() {
|
||||||
let instruction = Instruction::r#return(4, 8);
|
let instruction = Instruction::r#return();
|
||||||
|
|
||||||
assert_eq!(instruction.operation(), Operation::Return);
|
assert_eq!(instruction.operation(), Operation::Return);
|
||||||
assert_eq!(instruction.a(), 4);
|
|
||||||
assert_eq!(instruction.b(), 8);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -585,7 +585,10 @@ impl<'src> Parser<'src> {
|
|||||||
let local_index = self.parse_identifier_from(token, start_position)?;
|
let local_index = self.parse_identifier_from(token, start_position)?;
|
||||||
|
|
||||||
if allow_assignment && self.allow(TokenKind::Equal)? {
|
if allow_assignment && self.allow(TokenKind::Equal)? {
|
||||||
let is_mutable = self.chunk.get_local(local_index, start_position)?.mutable;
|
let is_mutable = self
|
||||||
|
.chunk
|
||||||
|
.get_local(local_index, start_position)?
|
||||||
|
.is_mutable;
|
||||||
|
|
||||||
if !is_mutable {
|
if !is_mutable {
|
||||||
return Err(ParseError::CannotMutateImmutableVariable {
|
return Err(ParseError::CannotMutateImmutableVariable {
|
||||||
@ -729,8 +732,10 @@ impl<'src> Parser<'src> {
|
|||||||
self.parse_block(allow_assignment, allow_return)?;
|
self.parse_block(allow_assignment, allow_return)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.chunk.get_last_operation()? == Operation::LoadConstant
|
let last_operation = self.chunk.get_last_operation()?;
|
||||||
&& self.current_token == Token::Else
|
|
||||||
|
if let (Operation::LoadConstant | Operation::LoadBoolean, Token::Else) =
|
||||||
|
(last_operation, self.current_token)
|
||||||
{
|
{
|
||||||
let (mut load_constant, load_constant_position) =
|
let (mut load_constant, load_constant_position) =
|
||||||
self.chunk.pop_instruction(self.current_position)?;
|
self.chunk.pop_instruction(self.current_position)?;
|
||||||
@ -803,7 +808,6 @@ impl<'src> Parser<'src> {
|
|||||||
Instruction::load_boolean(self.current_register, false, false),
|
Instruction::load_boolean(self.current_register, false, false),
|
||||||
comparison_position,
|
comparison_position,
|
||||||
);
|
);
|
||||||
self.increment_register()?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -824,12 +828,7 @@ impl<'src> Parser<'src> {
|
|||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
|
|
||||||
if !self.allow(TokenKind::Semicolon)? && self.is_eof() {
|
if !self.allow(TokenKind::Semicolon)? && self.is_eof() {
|
||||||
let register = self.current_register.saturating_sub(1);
|
self.emit_instruction(Instruction::r#return(), self.current_position);
|
||||||
|
|
||||||
self.emit_instruction(
|
|
||||||
Instruction::r#return(register, register),
|
|
||||||
self.current_position,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -146,14 +146,13 @@ impl Vm {
|
|||||||
let register_index = instruction.a();
|
let register_index = instruction.a();
|
||||||
let local_index = instruction.b();
|
let local_index = instruction.b();
|
||||||
let local = self.chunk.get_local(local_index, position)?;
|
let local = self.chunk.get_local(local_index, position)?;
|
||||||
let value = if let Some(index) = local.register_index {
|
|
||||||
self.take(index, position)?
|
if !local.is_mutable {
|
||||||
} else {
|
return Err(VmError::CannotMutateImmutableLocal {
|
||||||
return Err(VmError::UndefinedVariable {
|
|
||||||
identifier: local.identifier.clone(),
|
identifier: local.identifier.clone(),
|
||||||
position,
|
position,
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
let new_value = if instruction.b_is_constant() {
|
let new_value = if instruction.b_is_constant() {
|
||||||
self.chunk.take_constant(register_index, position)?
|
self.chunk.take_constant(register_index, position)?
|
||||||
@ -161,10 +160,9 @@ impl Vm {
|
|||||||
self.take(register_index, position)?
|
self.take(register_index, position)?
|
||||||
};
|
};
|
||||||
|
|
||||||
value
|
self.insert(new_value, register_index, position)?;
|
||||||
.mutate(new_value)
|
self.chunk
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
.define_local(local_index, register_index, position)?;
|
||||||
self.insert(value, register_index, position)?;
|
|
||||||
}
|
}
|
||||||
Operation::Add => {
|
Operation::Add => {
|
||||||
let (left, right) = get_arguments(self, instruction, position)?;
|
let (left, right) = get_arguments(self, instruction, position)?;
|
||||||
@ -469,7 +467,7 @@ impl Vm {
|
|||||||
position,
|
position,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
let clone_result = if local.mutable {
|
let clone_result = if local.is_mutable {
|
||||||
self._clone_mutable(index, position)
|
self._clone_mutable(index, position)
|
||||||
} else {
|
} else {
|
||||||
self.clone(index, position)
|
self.clone(index, position)
|
||||||
@ -508,6 +506,10 @@ impl Vm {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum VmError {
|
pub enum VmError {
|
||||||
|
CannotMutateImmutableLocal {
|
||||||
|
identifier: Identifier,
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
EmptyRegister {
|
EmptyRegister {
|
||||||
index: usize,
|
index: usize,
|
||||||
position: Span,
|
position: Span,
|
||||||
@ -555,6 +557,7 @@ impl AnnotatedError for VmError {
|
|||||||
|
|
||||||
fn description(&self) -> &'static str {
|
fn description(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
|
Self::CannotMutateImmutableLocal { .. } => "Cannot mutate immutable variable",
|
||||||
Self::EmptyRegister { .. } => "Empty register",
|
Self::EmptyRegister { .. } => "Empty register",
|
||||||
Self::ExpectedBoolean { .. } => "Expected boolean",
|
Self::ExpectedBoolean { .. } => "Expected boolean",
|
||||||
Self::RegisterIndexOutOfBounds { .. } => "Register index out of bounds",
|
Self::RegisterIndexOutOfBounds { .. } => "Register index out of bounds",
|
||||||
@ -581,6 +584,7 @@ impl AnnotatedError for VmError {
|
|||||||
|
|
||||||
fn position(&self) -> Span {
|
fn position(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
|
Self::CannotMutateImmutableLocal { position, .. } => *position,
|
||||||
Self::EmptyRegister { position, .. } => *position,
|
Self::EmptyRegister { position, .. } => *position,
|
||||||
Self::ExpectedBoolean { position, .. } => *position,
|
Self::ExpectedBoolean { position, .. } => *position,
|
||||||
Self::RegisterIndexOutOfBounds { position } => *position,
|
Self::RegisterIndexOutOfBounds { position } => *position,
|
||||||
|
@ -13,7 +13,7 @@ fn add() {
|
|||||||
.set_c_is_constant(),
|
.set_c_is_constant(),
|
||||||
Span(2, 3)
|
Span(2, 3)
|
||||||
),
|
),
|
||||||
(Instruction::r#return(0, 0), Span(5, 5))
|
(Instruction::r#return(), Span(5, 5))
|
||||||
],
|
],
|
||||||
vec![Value::integer(1), Value::integer(2)],
|
vec![Value::integer(1), Value::integer(2)],
|
||||||
vec![]
|
vec![]
|
||||||
@ -35,7 +35,7 @@ fn and() {
|
|||||||
(Instruction::test(0, false), Span(5, 7)),
|
(Instruction::test(0, false), Span(5, 7)),
|
||||||
(Instruction::jump(1, true), Span(5, 7)),
|
(Instruction::jump(1, true), Span(5, 7)),
|
||||||
(Instruction::load_boolean(1, false, false), Span(8, 13)),
|
(Instruction::load_boolean(1, false, false), Span(8, 13)),
|
||||||
(Instruction::r#return(0, 0), Span(13, 13)),
|
(Instruction::r#return(), Span(13, 13)),
|
||||||
],
|
],
|
||||||
vec![],
|
vec![],
|
||||||
vec![]
|
vec![]
|
||||||
@ -102,7 +102,7 @@ fn constant() {
|
|||||||
Ok(Chunk::with_data(
|
Ok(Chunk::with_data(
|
||||||
vec![
|
vec![
|
||||||
(Instruction::load_constant(0, 0, false), Span(0, 2)),
|
(Instruction::load_constant(0, 0, false), Span(0, 2)),
|
||||||
(Instruction::r#return(0, 0), Span(2, 2))
|
(Instruction::r#return(), Span(2, 2))
|
||||||
],
|
],
|
||||||
vec![Value::integer(42)],
|
vec![Value::integer(42)],
|
||||||
vec![]
|
vec![]
|
||||||
@ -143,7 +143,7 @@ fn divide() {
|
|||||||
.set_c_is_constant(),
|
.set_c_is_constant(),
|
||||||
Span(2, 3)
|
Span(2, 3)
|
||||||
),
|
),
|
||||||
(Instruction::r#return(0, 0), Span(5, 5))
|
(Instruction::r#return(), Span(5, 5))
|
||||||
],
|
],
|
||||||
vec![Value::integer(2), Value::integer(2)],
|
vec![Value::integer(2), Value::integer(2)],
|
||||||
vec![]
|
vec![]
|
||||||
@ -177,6 +177,7 @@ fn equal() {
|
|||||||
(Instruction::jump(1, true), Span(2, 4)),
|
(Instruction::jump(1, true), Span(2, 4)),
|
||||||
(Instruction::load_boolean(0, true, true), Span(2, 4)),
|
(Instruction::load_boolean(0, true, true), Span(2, 4)),
|
||||||
(Instruction::load_boolean(0, false, false), Span(2, 4)),
|
(Instruction::load_boolean(0, false, false), Span(2, 4)),
|
||||||
|
(Instruction::r#return(), Span(6, 6)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(1), Value::integer(2)],
|
vec![Value::integer(1), Value::integer(2)],
|
||||||
vec![]
|
vec![]
|
||||||
@ -188,7 +189,7 @@ fn equal() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn equality_assignment_long() {
|
fn equality_assignment_long() {
|
||||||
let source = "let a = if 4 == 4 { true } else { false };";
|
let source = "let a = if 4 == 4 { true } else { false }; a";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
@ -200,10 +201,12 @@ fn equality_assignment_long() {
|
|||||||
.set_c_is_constant(),
|
.set_c_is_constant(),
|
||||||
Span(13, 15)
|
Span(13, 15)
|
||||||
),
|
),
|
||||||
(Instruction::jump(1, true), Span(27, 31)),
|
(Instruction::jump(1, true), Span(13, 15)),
|
||||||
(Instruction::load_boolean(0, true, false), Span(20, 24)),
|
(Instruction::load_boolean(0, true, true), Span(20, 24)),
|
||||||
(Instruction::load_boolean(0, false, false), Span(34, 39)),
|
(Instruction::load_boolean(0, false, false), Span(34, 39)),
|
||||||
(Instruction::define_local(0, 0, false), Span(4, 5)),
|
(Instruction::define_local(0, 0, false), Span(4, 5)),
|
||||||
|
(Instruction::get_local(1, 0), Span(43, 44)),
|
||||||
|
(Instruction::r#return(), Span(44, 44)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(4), Value::integer(4)],
|
vec![Value::integer(4), Value::integer(4)],
|
||||||
vec![Local::new(Identifier::new("a"), false, 0, Some(0))]
|
vec![Local::new(Identifier::new("a"), false, 0, Some(0))]
|
||||||
@ -215,7 +218,7 @@ fn equality_assignment_long() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn equality_assignment_short() {
|
fn equality_assignment_short() {
|
||||||
let source = "let a = 4 == 4;";
|
let source = "let a = 4 == 4; a";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
@ -231,18 +234,20 @@ fn equality_assignment_short() {
|
|||||||
(Instruction::load_boolean(0, true, true), Span(10, 12)),
|
(Instruction::load_boolean(0, true, true), Span(10, 12)),
|
||||||
(Instruction::load_boolean(0, false, false), Span(10, 12)),
|
(Instruction::load_boolean(0, false, false), Span(10, 12)),
|
||||||
(Instruction::define_local(0, 0, false), Span(4, 5)),
|
(Instruction::define_local(0, 0, false), Span(4, 5)),
|
||||||
|
(Instruction::get_local(1, 0), Span(16, 17)),
|
||||||
|
(Instruction::r#return(), Span(17, 17)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(4), Value::integer(4)],
|
vec![Value::integer(4), Value::integer(4)],
|
||||||
vec![Local::new(Identifier::new("a"), false, 0, Some(0))]
|
vec![Local::new(Identifier::new("a"), false, 0, Some(0))]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(run(source), Ok(None));
|
assert_eq!(run(source), Ok(Some(Value::boolean(true))));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn greater() {
|
fn greater() {
|
||||||
let source = "1 > 2;";
|
let source = "1 > 2";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
@ -257,6 +262,7 @@ fn greater() {
|
|||||||
(Instruction::jump(1, true), Span(2, 3)),
|
(Instruction::jump(1, true), Span(2, 3)),
|
||||||
(Instruction::load_boolean(0, true, true), Span(2, 3)),
|
(Instruction::load_boolean(0, true, true), Span(2, 3)),
|
||||||
(Instruction::load_boolean(0, false, false), Span(2, 3)),
|
(Instruction::load_boolean(0, false, false), Span(2, 3)),
|
||||||
|
(Instruction::r#return(), Span(5, 5)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(1), Value::integer(2)],
|
vec![Value::integer(1), Value::integer(2)],
|
||||||
vec![]
|
vec![]
|
||||||
@ -268,7 +274,7 @@ fn greater() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn greater_than_or_equal() {
|
fn greater_than_or_equal() {
|
||||||
let source = "1 >= 2;";
|
let source = "1 >= 2";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
@ -283,6 +289,7 @@ fn greater_than_or_equal() {
|
|||||||
(Instruction::jump(1, true), Span(2, 4)),
|
(Instruction::jump(1, true), Span(2, 4)),
|
||||||
(Instruction::load_boolean(0, true, true), Span(2, 4)),
|
(Instruction::load_boolean(0, true, true), Span(2, 4)),
|
||||||
(Instruction::load_boolean(0, false, false), Span(2, 4)),
|
(Instruction::load_boolean(0, false, false), Span(2, 4)),
|
||||||
|
(Instruction::r#return(), Span(6, 6)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(1), Value::integer(2)],
|
vec![Value::integer(1), Value::integer(2)],
|
||||||
vec![]
|
vec![]
|
||||||
@ -306,9 +313,10 @@ fn if_else_expression() {
|
|||||||
.set_c_is_constant(),
|
.set_c_is_constant(),
|
||||||
Span(5, 7)
|
Span(5, 7)
|
||||||
),
|
),
|
||||||
(Instruction::jump(1, true), Span(16, 20)),
|
(Instruction::jump(1, true), Span(5, 7)),
|
||||||
(Instruction::load_constant(0, 2, true), Span(12, 13)),
|
(Instruction::load_constant(0, 2, true), Span(12, 13)),
|
||||||
(Instruction::load_constant(0, 3, false), Span(23, 24)),
|
(Instruction::load_constant(0, 3, false), Span(23, 24)),
|
||||||
|
(Instruction::r#return(), Span(26, 26)),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
Value::integer(1),
|
Value::integer(1),
|
||||||
@ -337,8 +345,9 @@ fn if_expression() {
|
|||||||
.set_c_is_constant(),
|
.set_c_is_constant(),
|
||||||
Span(5, 7)
|
Span(5, 7)
|
||||||
),
|
),
|
||||||
(Instruction::jump(1, true), Span(15, 15)),
|
(Instruction::jump(1, true), Span(5, 7)),
|
||||||
(Instruction::load_constant(0, 2, false), Span(12, 13)),
|
(Instruction::load_constant(0, 2, false), Span(12, 13)),
|
||||||
|
(Instruction::r#return(), Span(15, 15)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(1), Value::integer(1), Value::integer(2)],
|
vec![Value::integer(1), Value::integer(1), Value::integer(2)],
|
||||||
vec![]
|
vec![]
|
||||||
@ -350,7 +359,7 @@ fn if_expression() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn less_than() {
|
fn less_than() {
|
||||||
let source = "1 < 2;";
|
let source = "1 < 2";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
@ -365,6 +374,7 @@ fn less_than() {
|
|||||||
(Instruction::jump(1, true), Span(2, 3)),
|
(Instruction::jump(1, true), Span(2, 3)),
|
||||||
(Instruction::load_boolean(0, true, true), Span(2, 3)),
|
(Instruction::load_boolean(0, true, true), Span(2, 3)),
|
||||||
(Instruction::load_boolean(0, false, false), Span(2, 3)),
|
(Instruction::load_boolean(0, false, false), Span(2, 3)),
|
||||||
|
(Instruction::r#return(), Span(5, 5)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(1), Value::integer(2)],
|
vec![Value::integer(1), Value::integer(2)],
|
||||||
vec![]
|
vec![]
|
||||||
@ -376,7 +386,7 @@ fn less_than() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn less_than_or_equal() {
|
fn less_than_or_equal() {
|
||||||
let source = "1 <= 2;";
|
let source = "1 <= 2";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
@ -391,6 +401,7 @@ fn less_than_or_equal() {
|
|||||||
(Instruction::jump(1, true), Span(2, 4)),
|
(Instruction::jump(1, true), Span(2, 4)),
|
||||||
(Instruction::load_boolean(0, true, true), Span(2, 4)),
|
(Instruction::load_boolean(0, true, true), Span(2, 4)),
|
||||||
(Instruction::load_boolean(0, false, false), Span(2, 4)),
|
(Instruction::load_boolean(0, false, false), Span(2, 4)),
|
||||||
|
(Instruction::r#return(), Span(6, 6)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(1), Value::integer(2)],
|
vec![Value::integer(1), Value::integer(2)],
|
||||||
vec![]
|
vec![]
|
||||||
@ -412,6 +423,7 @@ fn list() {
|
|||||||
(Instruction::load_constant(1, 1, false), Span(4, 5)),
|
(Instruction::load_constant(1, 1, false), Span(4, 5)),
|
||||||
(Instruction::load_constant(2, 2, false), Span(7, 8)),
|
(Instruction::load_constant(2, 2, false), Span(7, 8)),
|
||||||
(Instruction::load_list(3, 0, 2), Span(0, 9)),
|
(Instruction::load_list(3, 0, 2), Span(0, 9)),
|
||||||
|
(Instruction::r#return(), Span(9, 9)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(1), Value::integer(2), Value::integer(3),],
|
vec![Value::integer(1), Value::integer(2), Value::integer(3),],
|
||||||
vec![]
|
vec![]
|
||||||
@ -452,6 +464,7 @@ fn list_with_complex_expression() {
|
|||||||
(Instruction::subtract(3, 1, 2), Span(10, 11)),
|
(Instruction::subtract(3, 1, 2), Span(10, 11)),
|
||||||
(Instruction::close(1, 3), Span(17, 18)),
|
(Instruction::close(1, 3), Span(17, 18)),
|
||||||
(Instruction::load_list(4, 0, 3), Span(0, 18)),
|
(Instruction::load_list(4, 0, 3), Span(0, 18)),
|
||||||
|
(Instruction::r#return(), Span(18, 18)),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
Value::integer(1),
|
Value::integer(1),
|
||||||
@ -468,7 +481,7 @@ fn list_with_complex_expression() {
|
|||||||
run(source),
|
run(source),
|
||||||
Ok(Some(Value::list(vec![
|
Ok(Some(Value::list(vec![
|
||||||
Value::integer(1),
|
Value::integer(1),
|
||||||
Value::integer(1)
|
Value::integer(-15)
|
||||||
])))
|
])))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -490,6 +503,7 @@ fn list_with_simple_expression() {
|
|||||||
),
|
),
|
||||||
(Instruction::load_constant(2, 3, false), Span(11, 12)),
|
(Instruction::load_constant(2, 3, false), Span(11, 12)),
|
||||||
(Instruction::load_list(3, 0, 2), Span(0, 13)),
|
(Instruction::load_list(3, 0, 2), Span(0, 13)),
|
||||||
|
(Instruction::r#return(), Span(13, 13)),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
Value::integer(1),
|
Value::integer(1),
|
||||||
@ -535,6 +549,7 @@ fn math_operator_precedence() {
|
|||||||
Span(14, 15)
|
Span(14, 15)
|
||||||
),
|
),
|
||||||
(Instruction::subtract(3, 0, 2), Span(6, 7)),
|
(Instruction::subtract(3, 0, 2), Span(6, 7)),
|
||||||
|
(Instruction::r#return(), Span(17, 17)),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
Value::integer(1),
|
Value::integer(1),
|
||||||
@ -556,12 +571,15 @@ fn multiply() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
Ok(Chunk::with_data(
|
Ok(Chunk::with_data(
|
||||||
vec![(
|
vec![
|
||||||
|
(
|
||||||
*Instruction::multiply(0, 0, 1)
|
*Instruction::multiply(0, 0, 1)
|
||||||
.set_b_is_constant()
|
.set_b_is_constant()
|
||||||
.set_c_is_constant(),
|
.set_c_is_constant(),
|
||||||
Span(2, 3)
|
Span(2, 3)
|
||||||
),],
|
),
|
||||||
|
(Instruction::r#return(), Span(5, 5)),
|
||||||
|
],
|
||||||
vec![Value::integer(1), Value::integer(2)],
|
vec![Value::integer(1), Value::integer(2)],
|
||||||
vec![]
|
vec![]
|
||||||
))
|
))
|
||||||
@ -577,7 +595,10 @@ fn negate() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
Ok(Chunk::with_data(
|
Ok(Chunk::with_data(
|
||||||
vec![(*Instruction::negate(0, 0).set_b_is_constant(), Span(0, 1)),],
|
vec![
|
||||||
|
(*Instruction::negate(0, 0).set_b_is_constant(), Span(0, 1)),
|
||||||
|
(Instruction::r#return(), Span(5, 5)),
|
||||||
|
],
|
||||||
vec![Value::integer(42)],
|
vec![Value::integer(42)],
|
||||||
vec![]
|
vec![]
|
||||||
)),
|
)),
|
||||||
@ -596,6 +617,7 @@ fn not() {
|
|||||||
vec![
|
vec![
|
||||||
(Instruction::load_boolean(0, true, false), Span(1, 5)),
|
(Instruction::load_boolean(0, true, false), Span(1, 5)),
|
||||||
(Instruction::not(1, 0), Span(0, 1)),
|
(Instruction::not(1, 0), Span(0, 1)),
|
||||||
|
(Instruction::r#return(), Span(5, 5)),
|
||||||
],
|
],
|
||||||
vec![],
|
vec![],
|
||||||
vec![]
|
vec![]
|
||||||
@ -607,7 +629,7 @@ fn not() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn not_equal() {
|
fn not_equal() {
|
||||||
let source = "1 != 2;";
|
let source = "1 != 2";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
@ -622,6 +644,7 @@ fn not_equal() {
|
|||||||
(Instruction::jump(1, true), Span(2, 4)),
|
(Instruction::jump(1, true), Span(2, 4)),
|
||||||
(Instruction::load_boolean(0, true, true), Span(2, 4)),
|
(Instruction::load_boolean(0, true, true), Span(2, 4)),
|
||||||
(Instruction::load_boolean(0, false, false), Span(2, 4)),
|
(Instruction::load_boolean(0, false, false), Span(2, 4)),
|
||||||
|
(Instruction::r#return(), Span(6, 6)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(1), Value::integer(2)],
|
vec![Value::integer(1), Value::integer(2)],
|
||||||
vec![]
|
vec![]
|
||||||
@ -642,6 +665,7 @@ fn or() {
|
|||||||
(Instruction::test(0, true), Span(5, 7)),
|
(Instruction::test(0, true), Span(5, 7)),
|
||||||
(Instruction::jump(1, true), Span(5, 7)),
|
(Instruction::jump(1, true), Span(5, 7)),
|
||||||
(Instruction::load_boolean(1, false, false), Span(8, 13)),
|
(Instruction::load_boolean(1, false, false), Span(8, 13)),
|
||||||
|
(Instruction::r#return(), Span(13, 13)),
|
||||||
],
|
],
|
||||||
vec![],
|
vec![],
|
||||||
vec![]
|
vec![]
|
||||||
@ -668,6 +692,7 @@ fn parentheses_precedence() {
|
|||||||
*Instruction::multiply(1, 0, 2).set_c_is_constant(),
|
*Instruction::multiply(1, 0, 2).set_c_is_constant(),
|
||||||
Span(8, 9)
|
Span(8, 9)
|
||||||
),
|
),
|
||||||
|
(Instruction::r#return(), Span(11, 11)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(1), Value::integer(2), Value::integer(3)],
|
vec![Value::integer(1), Value::integer(2), Value::integer(3)],
|
||||||
vec![]
|
vec![]
|
||||||
@ -679,7 +704,7 @@ fn parentheses_precedence() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn set_local() {
|
fn set_local() {
|
||||||
let source = "let mut x = 41; x = 42;";
|
let source = "let mut x = 41; x = 42; x";
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
Ok(Chunk::with_data(
|
Ok(Chunk::with_data(
|
||||||
@ -688,6 +713,8 @@ fn set_local() {
|
|||||||
(Instruction::define_local(0, 0, true), Span(8, 9)),
|
(Instruction::define_local(0, 0, true), Span(8, 9)),
|
||||||
(Instruction::load_constant(1, 1, false), Span(20, 22)),
|
(Instruction::load_constant(1, 1, false), Span(20, 22)),
|
||||||
(Instruction::set_local(1, 0), Span(16, 17)),
|
(Instruction::set_local(1, 0), Span(16, 17)),
|
||||||
|
(Instruction::get_local(1, 0), Span(24, 25)),
|
||||||
|
(Instruction::r#return(), Span(25, 25)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(41), Value::integer(42)],
|
vec![Value::integer(41), Value::integer(42)],
|
||||||
vec![Local::new(Identifier::new("x"), true, 0, Some(0)),]
|
vec![Local::new(Identifier::new("x"), true, 0, Some(0)),]
|
||||||
|
Loading…
Reference in New Issue
Block a user