From 3bd3c31210c07c81dbd0d9c954b4b5989132b012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Mon, 2 Jan 2023 20:29:32 +0100 Subject: [PATCH] Parser - Prevent return from being used outside of functions --- src/parser.rs | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 51d8fd2..91cf5c1 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -440,15 +440,22 @@ impl Parser { /// return_statement := "return" expression? ";" /// ``` fn parse_return_statement(&mut self, ret_token: &Token) -> ParserResult { - let value = if self.check(&TokenType::Semicolon) { - None + if self.can_use_return() { + let value = if self.check(&TokenType::Semicolon) { + None + } else { + Some(self.parse_expression()?) + }; + Ok(ast::StmtNode::Return { + token: ret_token.clone(), + value, + }) } else { - Some(self.parse_expression()?) - }; - Ok(ast::StmtNode::Return { - token: ret_token.clone(), - value, - }) + Err(ParserError::new( + ret_token, + "'return' found outside of function", + )) + } } /// Parse the following rule: @@ -758,4 +765,17 @@ impl Parser { } false } + + /// Check whether the `return` keyword can be used. This is true whenever + /// the first `LoopParsingState::None` found in the loop parsing state is + /// not the one at position 0. + fn can_use_return(&self) -> bool { + let mut pos = self.loop_state.len() - 1; + loop { + if self.loop_state[pos] == LoopParsingState::None { + return pos == 0; + } + pos -= 1; + } + } }