diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 43cd652..b69ff4a 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -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 { - self.chunk - .instructions() - .iter() - .rev() - .take(self.current_statement_length) - .map(|(instruction, _)| instruction) - } - fn get_last_value_operation(&self) -> Option { self.chunk .instructions() diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index f9244d8..9b2e81b 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -18,6 +18,7 @@ pub struct Vm { ip: usize, chunk: Chunk, stack: Vec, + last_assigned_register: Option, } 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 { diff --git a/dust-lang/tests/expressions.rs b/dust-lang/tests/expressions.rs index 71547e4..d1ae53c 100644 --- a/dust-lang/tests/expressions.rs +++ b/dust-lang/tests/expressions.rs @@ -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 }"; diff --git a/dust-lang/tests/scopes.rs b/dust-lang/tests/scopes.rs new file mode 100644 index 0000000..dfada39 --- /dev/null +++ b/dust-lang/tests/scopes.rs @@ -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 +// }) +// ); +// } diff --git a/examples/fibonacci.ds b/examples/fibonacci.ds index c624338..3abfe23 100644 --- a/examples/fibonacci.ds +++ b/examples/fibonacci.ds @@ -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)