From ae6d3d7a8261b2e4021f48141580f2ab4cd6aead Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 1 Nov 2024 09:55:15 -0400 Subject: [PATCH] Add new implicit return for end of file --- dust-lang/src/lib.rs | 2 +- dust-lang/src/parser.rs | 14 ++++++++++-- dust-lang/src/vm.rs | 35 +++++++++-------------------- dust-lang/tests/control_flow.rs | 6 +++-- dust-lang/tests/expressions.rs | 10 ++++++++- dust-lang/tests/native_functions.rs | 1 + 6 files changed, 37 insertions(+), 31 deletions(-) diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 9f6f99d..40ed6f1 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -20,7 +20,7 @@ pub use instruction::Instruction; pub use lexer::{lex, LexError, Lexer}; pub use native_function::{NativeFunction, NativeFunctionError}; pub use operation::Operation; -pub use parser::{parse, ParseError, Parser}; +pub use parser::{parse, ParseError}; pub use r#type::{EnumType, FunctionType, RangeableType, StructType, Type, TypeConflict}; pub use token::{Token, TokenKind, TokenOwned}; pub use value::{Function, Primitive, Value, ValueError}; diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 2fe67a2..7d17414 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -17,7 +17,7 @@ pub fn parse(source: &str) -> Result { let lexer = Lexer::new(source); let mut parser = Parser::new(lexer).map_err(|error| DustError::Parse { error, source })?; - while !parser.is_eof() { + loop { parser .parse_statement(Allowed { assignment: true, @@ -25,13 +25,17 @@ pub fn parse(source: &str) -> Result { implicit_return: true, }) .map_err(|error| DustError::Parse { error, source })?; + + if parser.is_eof() { + break; + } } Ok(parser.finish()) } #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize)] -pub struct Parser<'src> { +struct Parser<'src> { lexer: Lexer<'src>, chunk: Chunk, @@ -1256,6 +1260,10 @@ impl<'src> Parser<'src> { fn parse_implicit_return(&mut self) -> Result<(), ParseError> { if !self.current_is_expression { + if self.is_eof() { + self.emit_instruction(Instruction::r#return(false), self.current_position); + } + return Ok(()); } @@ -1273,6 +1281,8 @@ impl<'src> Parser<'src> { if end_of_statement && !has_semicolon && !returned { self.emit_instruction(Instruction::r#return(true), self.current_position); + } else if self.is_eof() { + self.emit_instruction(Instruction::r#return(false), self.current_position); } Ok(()) diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 4d3fe22..339fe49 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -92,7 +92,7 @@ impl Vm { self.set(to_register, value, position)?; if jump { - self.jump_to_ip(self.ip + 1); + self.ip += 1; } } Operation::LoadConstant => { @@ -103,7 +103,7 @@ impl Vm { self.set_constant(to_register, from_constant, position)?; if jump { - self.jump_to_ip(self.ip + 1); + self.ip += 1 } } Operation::LoadList => { @@ -252,7 +252,7 @@ impl Vm { self.ip - jump_distance as usize }; - self.jump_to_ip(new_ip); + self.ip = new_ip; } } Operation::Less => { @@ -288,7 +288,7 @@ impl Vm { self.ip - jump_distance as usize }; - self.jump_to_ip(new_ip); + self.ip = new_ip; } } Operation::LessEqual => { @@ -325,7 +325,7 @@ impl Vm { self.ip - jump_distance as usize }; - self.jump_to_ip(new_ip); + self.ip = new_ip; } } Operation::Negate => { @@ -360,8 +360,7 @@ impl Vm { } else { self.ip - jump_distance as usize - 1 }; - - self.jump_to_ip(new_ip); + self.ip = new_ip; } Operation::Call => { let to_register = instruction.a(); @@ -429,24 +428,6 @@ impl Vm { Ok(None) } - fn jump_to_ip(&mut self, new_ip: usize) { - let final_index = self.chunk.len() - 1; - - if new_ip > final_index { - let last_operation = self - .chunk - .instructions() - .last() - .map(|(instruction, _)| instruction.operation()); - - if let Some(Operation::Return) = last_operation { - self.ip = final_index; - } - } else { - self.ip = new_ip; - } - } - 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); @@ -632,6 +613,10 @@ impl Vm { } fn read(&mut self, position: Span) -> Result<&(Instruction, Span), VmError> { + if self.ip >= self.chunk.len() { + self.ip = self.chunk.len() - 1; + } + let current = self.chunk.get_instruction(self.ip, position)?; self.ip += 1; diff --git a/dust-lang/tests/control_flow.rs b/dust-lang/tests/control_flow.rs index 73313c6..02fe324 100644 --- a/dust-lang/tests/control_flow.rs +++ b/dust-lang/tests/control_flow.rs @@ -308,7 +308,7 @@ fn if_else_true() { } #[test] -fn if_expression_false() { +fn if_false() { let source = "if 1 == 2 { 2 }"; assert_eq!( @@ -324,6 +324,7 @@ fn if_expression_false() { ), (Instruction::jump(1, true), Span(5, 7)), (Instruction::load_constant(0, 2, false), Span(12, 13)), + (Instruction::r#return(false), Span(15, 15)) ], vec![Value::integer(1), Value::integer(2), Value::integer(2)], vec![] @@ -334,7 +335,7 @@ fn if_expression_false() { } #[test] -fn if_expression_true() { +fn if_true() { let source = "if 1 == 1 { 2 }"; assert_eq!( @@ -350,6 +351,7 @@ fn if_expression_true() { ), (Instruction::jump(1, true), Span(5, 7)), (Instruction::load_constant(0, 2, false), Span(12, 13)), + (Instruction::r#return(false), Span(15, 15)) ], vec![Value::integer(1), Value::integer(1), Value::integer(2)], vec![] diff --git a/dust-lang/tests/expressions.rs b/dust-lang/tests/expressions.rs index ffef606..942b44d 100644 --- a/dust-lang/tests/expressions.rs +++ b/dust-lang/tests/expressions.rs @@ -77,6 +77,7 @@ fn block_scope() { (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), @@ -129,6 +130,7 @@ fn define_local() { vec![ (Instruction::load_constant(0, 0, false), Span(8, 10)), (Instruction::define_local(0, 0, false), Span(4, 5)), + (Instruction::r#return(false), Span(11, 11)) ], vec![Value::integer(42)], vec![Local::new(Identifier::new("x"), None, false, 0, 0)] @@ -195,7 +197,12 @@ fn empty() { assert_eq!( parse(source), - Ok(Chunk::with_data(None, vec![], vec![], vec![])) + Ok(Chunk::with_data( + None, + vec![(Instruction::r#return(false), Span(0, 0))], + vec![], + vec![] + )) ); assert_eq!(run(source), Ok(None)); } @@ -262,6 +269,7 @@ fn function_declaration() { vec![ (Instruction::load_constant(0, 0, false), Span(0, 40)), (Instruction::define_local(0, 0, false), Span(3, 6)), + (Instruction::r#return(false), Span(40, 40)) ], vec![Value::function( Chunk::with_data( diff --git a/dust-lang/tests/native_functions.rs b/dust-lang/tests/native_functions.rs index 7921649..7a0aa56 100644 --- a/dust-lang/tests/native_functions.rs +++ b/dust-lang/tests/native_functions.rs @@ -15,6 +15,7 @@ fn panic() { Instruction::call_native(2, NativeFunction::Panic, 2), Span(0, 27) ), + (Instruction::r#return(false), Span(27, 27)) ], vec![Value::string("Goodbye world!"), Value::integer(42)], vec![]