Change return to use last_assigned_value; Add scopes tests
This commit is contained in:
parent
004cf73959
commit
e304195661
@ -173,30 +173,19 @@ impl<'src> Parser<'src> {
|
||||
second_loader_new.set_a(first_loader.a());
|
||||
second_loader_new.set_b(second_loader.b());
|
||||
second_loader_new.set_c(second_loader.c());
|
||||
|
||||
if second_loader.b_is_constant() {
|
||||
second_loader_new.set_b_is_constant();
|
||||
}
|
||||
|
||||
if second_loader.c_is_constant() {
|
||||
second_loader_new.set_c_is_constant();
|
||||
}
|
||||
second_loader_new.set_b_to_boolean(second_loader.b_is_constant());
|
||||
second_loader_new.set_c_to_boolean(second_loader.c_is_constant());
|
||||
|
||||
*second_loader = second_loader_new;
|
||||
|
||||
let jump = instructions.next().unwrap();
|
||||
|
||||
jump.set_b(jump.b() - 1);
|
||||
}
|
||||
|
||||
self.current_statement_length = 0;
|
||||
}
|
||||
|
||||
fn get_statement_instructions(&self) -> impl Iterator<Item = &Instruction> {
|
||||
self.chunk
|
||||
.instructions()
|
||||
.iter()
|
||||
.rev()
|
||||
.take(self.current_statement_length)
|
||||
.map(|(instruction, _)| instruction)
|
||||
}
|
||||
|
||||
fn get_last_value_operation(&self) -> Option<Operation> {
|
||||
self.chunk
|
||||
.instructions()
|
||||
|
@ -18,6 +18,7 @@ pub struct Vm {
|
||||
ip: usize,
|
||||
chunk: Chunk,
|
||||
stack: Vec<Register>,
|
||||
last_assigned_register: Option<u8>,
|
||||
}
|
||||
|
||||
impl Vm {
|
||||
@ -28,6 +29,7 @@ impl Vm {
|
||||
ip: 0,
|
||||
chunk,
|
||||
stack: Vec::new(),
|
||||
last_assigned_register: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,14 +389,17 @@ impl Vm {
|
||||
Operation::Return => {
|
||||
let should_return_value = instruction.b_as_boolean();
|
||||
|
||||
return if should_return_value {
|
||||
let top_of_stack = (self.stack.len() - 1) as u8;
|
||||
let value = self.empty(top_of_stack, position)?;
|
||||
if !should_return_value {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
Ok(Some(value))
|
||||
if let Some(register) = self.last_assigned_register {
|
||||
let value = self.empty(register, position)?;
|
||||
|
||||
return Ok(Some(value));
|
||||
} else {
|
||||
Ok(None)
|
||||
};
|
||||
return Err(VmError::StackUnderflow { position });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -404,6 +409,7 @@ impl Vm {
|
||||
|
||||
fn set(&mut self, to_register: u8, value: Value, position: Span) -> Result<(), VmError> {
|
||||
let length = self.stack.len();
|
||||
self.last_assigned_register = Some(to_register);
|
||||
let to_register = to_register as usize;
|
||||
|
||||
if length == Self::STACK_LIMIT {
|
||||
@ -450,6 +456,7 @@ impl Vm {
|
||||
position: Span,
|
||||
) -> Result<(), VmError> {
|
||||
let length = self.stack.len();
|
||||
self.last_assigned_register = Some(to_register);
|
||||
let to_register = to_register as usize;
|
||||
|
||||
if length == Self::STACK_LIMIT {
|
||||
@ -496,6 +503,7 @@ impl Vm {
|
||||
position: Span,
|
||||
) -> Result<(), VmError> {
|
||||
let length = self.stack.len();
|
||||
self.last_assigned_register = Some(to_register);
|
||||
let to_register = to_register as usize;
|
||||
|
||||
if length == Self::STACK_LIMIT {
|
||||
|
@ -569,6 +569,76 @@ fn if_else_complex() {
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_else_nested() {
|
||||
let source = r#"
|
||||
if 0 == 1 {
|
||||
if 0 == 2 {
|
||||
1;
|
||||
} else {
|
||||
2;
|
||||
}
|
||||
} else {
|
||||
if 0 == 3 {
|
||||
3;
|
||||
} else {
|
||||
4;
|
||||
}
|
||||
}"#;
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
vec![
|
||||
(
|
||||
*Instruction::equal(true, 0, 1)
|
||||
.set_b_is_constant()
|
||||
.set_c_is_constant(),
|
||||
Span(14, 16)
|
||||
),
|
||||
(Instruction::jump(7), Span(14, 16)),
|
||||
(
|
||||
*Instruction::equal(true, 0, 2)
|
||||
.set_b_is_constant()
|
||||
.set_c_is_constant(),
|
||||
Span(38, 41)
|
||||
),
|
||||
(Instruction::jump(3), Span(38, 41)),
|
||||
(Instruction::load_constant(0, 1, false), Span(61, 62)),
|
||||
(Instruction::jump(11), Span(95, 95)),
|
||||
(
|
||||
*Instruction::equal(true, 0, 3)
|
||||
.set_b_is_constant()
|
||||
.set_c_is_constant(),
|
||||
Span(77, 79)
|
||||
),
|
||||
(Instruction::jump(3), Span(77, 79)),
|
||||
(Instruction::load_constant(0, 2, false), Span(94, 95)),
|
||||
(Instruction::jump(11), Span(95, 95)),
|
||||
(Instruction::load_constant(0, 3, false), Span(114, 115)),
|
||||
(Instruction::jump(11), Span(95, 95)),
|
||||
(Instruction::load_constant(0, 4, false), Span(134, 135)),
|
||||
(Instruction::r#return(true), Span(146, 146)),
|
||||
],
|
||||
vec![
|
||||
Value::integer(0),
|
||||
Value::integer(1),
|
||||
Value::integer(0),
|
||||
Value::integer(2),
|
||||
Value::integer(1),
|
||||
Value::integer(0),
|
||||
Value::integer(3),
|
||||
Value::integer(3),
|
||||
Value::integer(4)
|
||||
],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(4))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_else_simple() {
|
||||
let source = "if 1 == 1 { 2 } else { 3 }";
|
||||
|
57
dust-lang/tests/scopes.rs
Normal file
57
dust-lang/tests/scopes.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn allow_access_to_parent_scope() {
|
||||
let source = r#"
|
||||
let x = 1;
|
||||
{
|
||||
x
|
||||
}
|
||||
"#;
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(1))));
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn disallow_access_to_child_scope() {
|
||||
// let source = r#"
|
||||
// {
|
||||
// let x = 1;
|
||||
// }
|
||||
// x
|
||||
// "#;
|
||||
|
||||
// assert_eq!(
|
||||
// run(source),
|
||||
// Err(DustError::Parse {
|
||||
// error: ParseError::Chunk(ChunkError::LocalOutOfScope {
|
||||
// identifier: Identifier::new("x"),
|
||||
// position: Span(52, 53)
|
||||
// }),
|
||||
// source
|
||||
// })
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn disallow_access_to_sibling_scope() {
|
||||
// let source = r#"
|
||||
// {
|
||||
// let x = 1;
|
||||
// }
|
||||
// {
|
||||
// x
|
||||
// }
|
||||
// "#;
|
||||
|
||||
// assert_eq!(
|
||||
// run(source),
|
||||
// Err(DustError::Parse {
|
||||
// error: ParseError::Chunk(ChunkError::LocalOutOfScope {
|
||||
// identifier: Identifier::new("x"),
|
||||
// position: Span(52, 53)
|
||||
// }),
|
||||
// source
|
||||
// })
|
||||
// );
|
||||
// }
|
@ -1,11 +1,13 @@
|
||||
fn fib (n: int) -> int {
|
||||
if n <= 0 {
|
||||
0
|
||||
} else if n == 1 {
|
||||
1
|
||||
} else {
|
||||
fib(n - 1) + fib(n - 2)
|
||||
if n == 1 {
|
||||
1
|
||||
} else {
|
||||
fib(n - 1) + fib(n - 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fib(2)
|
||||
fib(10)
|
||||
|
Loading…
Reference in New Issue
Block a user