diff --git a/dust-lang/src/chunk.rs b/dust-lang/src/chunk.rs index 75bef76..3575b54 100644 --- a/dust-lang/src/chunk.rs +++ b/dust-lang/src/chunk.rs @@ -111,7 +111,15 @@ impl Chunk { .ok_or(ChunkError::ConstantIndexOutOfBounds { index, position }) } - pub fn push_constant(&mut self, value: Value, position: Span) -> Result { + pub fn push_or_get_constant(&mut self, value: Value, position: Span) -> Result { + if let Some(index) = self + .constants + .iter() + .position(|constant| constant == &value) + { + return Ok(index as u8); + } + let starting_length = self.constants.len(); if starting_length + 1 > (u8::MAX as usize) { diff --git a/dust-lang/src/native_function.rs b/dust-lang/src/native_function.rs index 6f60f64..fb0f5ba 100644 --- a/dust-lang/src/native_function.rs +++ b/dust-lang/src/native_function.rs @@ -79,7 +79,7 @@ impl_from_str_for_native_function! { (Assert, 0_u8, "assert", false), (AssertEqual, 1_u8, "assert_equal", false), (AssertNotEqual, 2_u8, "assert_not_equal", false), - (Panic, 3_u8, "panic", false), + (Panic, 3_u8, "panic", true), // Type conversion (Parse, 4_u8, "parse", true), diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 6443137..c9c55bf 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -236,7 +236,7 @@ impl<'src> Parser<'src> { } fn emit_constant(&mut self, value: Value, position: Span) -> Result<(), ParseError> { - let constant_index = self.chunk.push_constant(value, position)?; + let constant_index = self.chunk.push_or_get_constant(value, position)?; let register = self.next_register(); self.emit_instruction( @@ -960,7 +960,6 @@ impl<'src> Parser<'src> { let block_allowed = Allowed { assignment: allowed.assignment, explicit_return: allowed.explicit_return, - implicit_return: false, }; if let Token::LeftCurlyBrace = self.current_token { @@ -1093,7 +1092,6 @@ impl<'src> Parser<'src> { self.parse_block(Allowed { assignment: true, explicit_return: allowed.explicit_return, - implicit_return: false, })?; let block_end = self.chunk.len() as u8; @@ -1166,7 +1164,6 @@ impl<'src> Parser<'src> { self.parse_statement(Allowed { assignment: true, explicit_return: false, - implicit_return: true, })?; if self.is_eof() || self.allow(Token::RightCurlyBrace)? { @@ -1195,7 +1192,6 @@ impl<'src> Parser<'src> { Allowed { assignment: false, explicit_return: false, - implicit_return: false, }, ) } @@ -1206,7 +1202,6 @@ impl<'src> Parser<'src> { Allowed { assignment: false, explicit_return: false, - implicit_return: false, }, ) } @@ -1591,7 +1586,6 @@ pub enum Context { struct Allowed { pub assignment: bool, pub explicit_return: bool, - pub implicit_return: bool, } type PrefixFunction<'a> = fn(&mut Parser<'a>, Allowed) -> Result<(), ParseError>; diff --git a/dust-lang/tests/control_flow.rs b/dust-lang/tests/control_flow.rs index 3a41ce7..7b8e20f 100644 --- a/dust-lang/tests/control_flow.rs +++ b/dust-lang/tests/control_flow.rs @@ -10,7 +10,7 @@ fn equality_assignment_long() { None, vec![ ( - *Instruction::equal(true, 0, 1) + *Instruction::equal(true, 0, 0) .set_b_is_constant() .set_c_is_constant(), Span(13, 15) @@ -22,7 +22,7 @@ fn equality_assignment_long() { (Instruction::get_local(1, 0), Span(43, 44)), (Instruction::r#return(true), Span(44, 44)), ], - vec![Value::integer(4), Value::integer(4)], + vec![Value::integer(4)], vec![Local::new(Identifier::new("a"), None, false, 0, 0)] )), ); @@ -40,7 +40,7 @@ fn equality_assignment_short() { None, vec![ ( - *Instruction::equal(true, 0, 1) + *Instruction::equal(true, 0, 0) .set_b_is_constant() .set_c_is_constant(), Span(10, 12) @@ -52,7 +52,7 @@ fn equality_assignment_short() { (Instruction::get_local(1, 0), Span(15, 16)), (Instruction::r#return(true), Span(16, 16)), ], - vec![Value::integer(4), Value::integer(4)], + vec![Value::integer(4)], vec![Local::new(Identifier::new("a"), None, false, 0, 0)] )), ); @@ -78,23 +78,23 @@ fn if_else_assigment() { None, vec![ ( - *Instruction::equal(true, 0, 1) + *Instruction::equal(true, 0, 0) .set_b_is_constant() .set_c_is_constant(), Span(22, 24) ), (Instruction::jump(5, true), Span(22, 24)), - (Instruction::load_constant(0, 2, false), Span(41, 42)), - (Instruction::load_constant(1, 3, false), Span(44, 45)), - (Instruction::load_constant(2, 4, false), Span(47, 48)), - (Instruction::load_constant(3, 5, false), Span(50, 51)), - (Instruction::load_constant(4, 6, false), Span(65, 67)), + (Instruction::load_constant(0, 1, false), Span(41, 42)), + (Instruction::load_constant(1, 2, false), Span(44, 45)), + (Instruction::load_constant(2, 3, false), Span(47, 48)), + (Instruction::load_constant(3, 0, false), Span(50, 51)), + (Instruction::load_constant(4, 4, false), Span(65, 67)), (Instruction::jump(6, true), Span(138, 139)), (Instruction::jump(5, true), Span(138, 139)), - (Instruction::load_constant(5, 7, false), Span(97, 98)), - (Instruction::load_constant(6, 8, false), Span(100, 101)), - (Instruction::load_constant(7, 9, false), Span(103, 104)), - (Instruction::load_constant(8, 10, false), Span(106, 107)), + (Instruction::load_constant(5, 1, false), Span(97, 98)), + (Instruction::load_constant(6, 2, false), Span(100, 101)), + (Instruction::load_constant(7, 3, false), Span(103, 104)), + (Instruction::load_constant(8, 0, false), Span(106, 107)), ( Instruction::call_native(9, NativeFunction::Panic, 0), Span(121, 128) @@ -105,17 +105,11 @@ fn if_else_assigment() { (Instruction::r#return(true), Span(149, 149)), ], vec![ - Value::integer(4), Value::integer(4), Value::integer(1), Value::integer(2), Value::integer(3), - Value::integer(4), Value::integer(42), - Value::integer(1), - Value::integer(2), - Value::integer(3), - Value::integer(4), ], vec![Local::new(Identifier::new("a"), None, false, 0, 0)] )), @@ -139,36 +133,30 @@ fn if_else_complex() { None, vec![ ( - *Instruction::equal(true, 0, 1) + *Instruction::equal(true, 0, 0) .set_b_is_constant() .set_c_is_constant(), Span(14, 16) ), (Instruction::jump(5, true), Span(14, 16)), - (Instruction::load_constant(0, 2, false), Span(33, 34)), - (Instruction::load_constant(1, 3, false), Span(36, 37)), - (Instruction::load_constant(2, 4, false), Span(39, 40)), - (Instruction::load_constant(3, 5, false), Span(42, 43)), + (Instruction::load_constant(0, 0, false), Span(33, 34)), + (Instruction::load_constant(1, 1, false), Span(36, 37)), + (Instruction::load_constant(2, 2, false), Span(39, 40)), + (Instruction::load_constant(3, 3, false), Span(42, 43)), (Instruction::jump(5, true), Span(95, 95)), (Instruction::jump(4, true), Span(95, 95)), - (Instruction::load_constant(4, 6, false), Span(74, 75)), - (Instruction::load_constant(5, 7, false), Span(77, 78)), - (Instruction::load_constant(6, 8, false), Span(80, 81)), - (Instruction::load_constant(7, 9, false), Span(83, 84)), + (Instruction::load_constant(4, 0, false), Span(74, 75)), + (Instruction::load_constant(5, 1, false), Span(77, 78)), + (Instruction::load_constant(6, 2, false), Span(80, 81)), + (Instruction::load_constant(7, 3, false), Span(83, 84)), (Instruction::r#move(7, 3), Span(95, 95)), (Instruction::r#return(false), Span(95, 95)), ], vec![ - Value::integer(1), - Value::integer(1), Value::integer(1), Value::integer(2), Value::integer(3), Value::integer(4), - Value::integer(1), - Value::integer(2), - Value::integer(3), - Value::integer(4) ], vec![] )) @@ -289,13 +277,13 @@ fn if_else_true() { None, vec![ ( - *Instruction::equal(true, 0, 1) + *Instruction::equal(true, 0, 0) .set_b_is_constant() .set_c_is_constant(), Span(5, 7) ), (Instruction::jump(1, true), Span(5, 7)), - (Instruction::load_constant(0, 2, true), Span(12, 14)), + (Instruction::load_constant(0, 1, true), Span(12, 14)), ( Instruction::call_native(1, NativeFunction::Panic, 0), Span(24, 31) @@ -303,7 +291,7 @@ fn if_else_true() { (Instruction::r#move(1, 0), Span(33, 33)), (Instruction::r#return(true), Span(33, 33)) ], - vec![Value::integer(1), Value::integer(1), Value::integer(42)], + vec![Value::integer(1), Value::integer(42)], vec![] )), ); @@ -327,10 +315,10 @@ fn if_false() { Span(5, 7) ), (Instruction::jump(1, true), Span(5, 7)), - (Instruction::load_constant(0, 2, false), Span(12, 13)), + (Instruction::load_constant(0, 1, false), Span(12, 13)), (Instruction::r#return(false), Span(15, 15)) ], - vec![Value::integer(1), Value::integer(2), Value::integer(2)], + vec![Value::integer(1), Value::integer(2)], vec![] )), ); @@ -348,16 +336,16 @@ fn if_true() { None, vec![ ( - *Instruction::equal(true, 0, 1) + *Instruction::equal(true, 0, 0) .set_b_is_constant() .set_c_is_constant(), Span(5, 7) ), (Instruction::jump(1, true), Span(5, 7)), - (Instruction::load_constant(0, 2, false), Span(12, 13)), + (Instruction::load_constant(0, 1, false), Span(12, 13)), (Instruction::r#return(false), Span(15, 15)) ], - vec![Value::integer(1), Value::integer(1), Value::integer(2)], + vec![Value::integer(1), Value::integer(2)], vec![] )), ); diff --git a/dust-lang/tests/expressions.rs b/dust-lang/tests/expressions.rs index 5ea5c03..f3347f5 100644 --- a/dust-lang/tests/expressions.rs +++ b/dust-lang/tests/expressions.rs @@ -48,57 +48,6 @@ fn add_assign() { assert_eq!(run(source), Ok(Some(Value::integer(3)))); } -#[test] -fn block_scope() { - let source = " - let a = 0; - { - let b = 42; - { - let c = 1; - } - let d = 2; - } - let e = 1; - "; - - assert_eq!( - parse(source), - Ok(Chunk::with_data( - None, - vec![ - (Instruction::load_constant(0, 0, false), Span(17, 18)), - (Instruction::define_local(0, 0, false), Span(13, 14)), - (Instruction::load_constant(1, 1, false), Span(50, 52)), - (Instruction::define_local(1, 1, false), Span(46, 47)), - (Instruction::load_constant(2, 2, false), Span(92, 93)), - (Instruction::define_local(2, 2, false), Span(88, 89)), - (Instruction::load_constant(3, 3, false), Span(129, 130)), - (Instruction::define_local(3, 3, false), Span(125, 126)), - (Instruction::load_constant(4, 4, false), Span(158, 159)), - (Instruction::define_local(4, 4, false), Span(154, 155)), - (Instruction::r#return(false), Span(165, 165)) - ], - vec![ - Value::integer(0), - Value::integer(42), - Value::integer(1), - Value::integer(2), - Value::integer(1) - ], - vec![ - Local::new(Identifier::new("a"), None, false, 0, 0), - Local::new(Identifier::new("b"), None, false, 1, 1), - Local::new(Identifier::new("c"), None, false, 2, 2), - Local::new(Identifier::new("d"), None, false, 1, 3), - Local::new(Identifier::new("e"), None, false, 0, 4), - ] - )), - ); - - assert_eq!(run(source), Ok(None)); -} - #[test] fn constant() { let source = "42"; @@ -150,14 +99,14 @@ fn divide() { None, vec![ ( - *Instruction::divide(0, 0, 1) + *Instruction::divide(0, 0, 0) .set_b_is_constant() .set_c_is_constant(), Span(2, 3) ), (Instruction::r#return(true), Span(5, 5)) ], - vec![Value::integer(2), Value::integer(2)], + vec![Value::integer(2)], vec![] )) ); @@ -177,13 +126,13 @@ fn divide_assign() { (Instruction::load_constant(0, 0, false), Span(12, 13)), (Instruction::define_local(0, 0, true), Span(8, 9)), ( - *Instruction::divide(0, 0, 1).set_c_is_constant(), + *Instruction::divide(0, 0, 0).set_c_is_constant(), Span(17, 19) ), (Instruction::get_local(1, 0), Span(23, 24)), (Instruction::r#return(true), Span(24, 24)) ], - vec![Value::integer(2), Value::integer(2)], + vec![Value::integer(2)], vec![Local::new(Identifier::new("a"), None, true, 0, 0)] )) ); diff --git a/dust-lang/tests/scopes.rs b/dust-lang/tests/scopes.rs index dfada39..768c85c 100644 --- a/dust-lang/tests/scopes.rs +++ b/dust-lang/tests/scopes.rs @@ -12,6 +12,56 @@ fn allow_access_to_parent_scope() { assert_eq!(run(source), Ok(Some(Value::integer(1)))); } +#[test] +fn block_scope() { + let source = " + let a = 0; + { + let b = 42; + { + let c = 1; + } + let d = 2; + } + let e = 1; + "; + + assert_eq!( + parse(source), + Ok(Chunk::with_data( + None, + vec![ + (Instruction::load_constant(0, 0, false), Span(17, 18)), + (Instruction::define_local(0, 0, false), Span(13, 14)), + (Instruction::load_constant(1, 1, false), Span(50, 52)), + (Instruction::define_local(1, 1, false), Span(46, 47)), + (Instruction::load_constant(2, 2, false), Span(92, 93)), + (Instruction::define_local(2, 2, false), Span(88, 89)), + (Instruction::load_constant(3, 3, false), Span(129, 130)), + (Instruction::define_local(3, 3, false), Span(125, 126)), + (Instruction::load_constant(4, 2, false), Span(158, 159)), + (Instruction::define_local(4, 4, false), Span(154, 155)), + (Instruction::r#return(false), Span(165, 165)) + ], + vec![ + Value::integer(0), + Value::integer(42), + Value::integer(1), + Value::integer(2), + ], + vec![ + Local::new(Identifier::new("a"), None, false, 0, 0), + Local::new(Identifier::new("b"), None, false, 1, 1), + Local::new(Identifier::new("c"), None, false, 2, 2), + Local::new(Identifier::new("d"), None, false, 1, 3), + Local::new(Identifier::new("e"), None, false, 0, 4), + ] + )), + ); + + assert_eq!(run(source), Ok(None)); +} + // #[test] // fn disallow_access_to_child_scope() { // let source = r#"