From 779a04002dd02801b1ad3df8171eb637dbd5933b Mon Sep 17 00:00:00 2001 From: PennyJim Date: Sun, 19 Jul 2026 01:23:42 -0600 Subject: [PATCH 1/2] fix: error on statement after return While it would have been better to specify the expected keyword to ends that particular block like actual Lua does, I do not see that being possible in the given structure. fix #1163 --- crates/emmylua_parser/locales/app.yml | 2 ++ crates/emmylua_parser/src/grammar/doc/test.rs | 22 +++++++++++++++++++ crates/emmylua_parser/src/grammar/lua/stat.rs | 9 ++++++++ 3 files changed, 33 insertions(+) diff --git a/crates/emmylua_parser/locales/app.yml b/crates/emmylua_parser/locales/app.yml index 27a4bb8a3..3d0159490 100644 --- a/crates/emmylua_parser/locales/app.yml +++ b/crates/emmylua_parser/locales/app.yml @@ -255,6 +255,8 @@ expected 'end' to close while statement: en: expected 'end' to close while statement zh_CN: 期望 'end' 来关闭while语句 zh_HK: 期望 'end' 來關閉while語句 +expected end of block after return: + en: expected end of block after return expected 'function', variable name, or attribute after 'local': en: expected 'function', variable name, or attribute after 'local' zh_CN: 期望在 'local' 后有 'function'、变量名或属性 diff --git a/crates/emmylua_parser/src/grammar/doc/test.rs b/crates/emmylua_parser/src/grammar/doc/test.rs index b6e176eae..021b805df 100644 --- a/crates/emmylua_parser/src/grammar/doc/test.rs +++ b/crates/emmylua_parser/src/grammar/doc/test.rs @@ -3724,4 +3724,26 @@ Syntax(Chunk)@0..47 assert!(errors[0].range.is_empty()); assert_eq!(u32::from(errors[0].range.start()) as usize, code.len()); } + + #[test] + fn test_statement_after_return() { + let code = "return 1, 2 x = 1"; + let tree = LuaParser::parse(code, ParserConfig::default()); + let errors = tree.get_errors(); + + assert_eq!(errors.len(), 1); + assert_eq!(errors[0].kind, LuaParseErrorKind::SyntaxError); + assert_eq!(errors[0].message, "expected end of block after return") + } + + #[test] + fn test_statement_after_blank_return() { + let code = "return; x = 1"; + let tree = LuaParser::parse(code, ParserConfig::default()); + let errors = tree.get_errors(); + + assert_eq!(errors.len(), 1); + assert_eq!(errors[0].kind, LuaParseErrorKind::SyntaxError); + assert_eq!(errors[0].message, "expected end of block after return") + } } diff --git a/crates/emmylua_parser/src/grammar/lua/stat.rs b/crates/emmylua_parser/src/grammar/lua/stat.rs index f066df848..9af319dea 100644 --- a/crates/emmylua_parser/src/grammar/lua/stat.rs +++ b/crates/emmylua_parser/src/grammar/lua/stat.rs @@ -752,6 +752,7 @@ fn parse_attrib(p: &mut LuaParser) -> ParseResult { fn parse_return(p: &mut LuaParser) -> ParseResult { let m = p.mark(LuaSyntaxKind::ReturnStat); + let return_start_range = p.current_token_range(); p.bump(); if !block_follow(p) && p.current_token() != LuaTokenKind::TkSemicolon @@ -761,6 +762,14 @@ fn parse_return(p: &mut LuaParser) -> ParseResult { } if_token_bump(p, LuaTokenKind::TkSemicolon); + + if !block_follow(p) { + p.push_error(LuaParseError::syntax_error_from( + &t!("expected end of block after return"), + return_start_range, + )); + }; + Ok(m.complete(p)) } From 48e829cbf65ea7196f1a6aea91f56f86c46c8f54 Mon Sep 17 00:00:00 2001 From: PennyJim Date: Sun, 19 Jul 2026 01:44:37 -0600 Subject: [PATCH 2/2] Add working test and change error range I was putting the error on the `return` to match how it's on the `if` when missing the `end`. But the code review made me realize that where the `end` can be is arbitrary with an if statement, but not with a return statement. --- crates/emmylua_parser/src/grammar/doc/test.rs | 15 +++++++++++++-- crates/emmylua_parser/src/grammar/lua/stat.rs | 5 ++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/crates/emmylua_parser/src/grammar/doc/test.rs b/crates/emmylua_parser/src/grammar/doc/test.rs index 021b805df..eb1c1baaf 100644 --- a/crates/emmylua_parser/src/grammar/doc/test.rs +++ b/crates/emmylua_parser/src/grammar/doc/test.rs @@ -3733,7 +3733,8 @@ Syntax(Chunk)@0..47 assert_eq!(errors.len(), 1); assert_eq!(errors[0].kind, LuaParseErrorKind::SyntaxError); - assert_eq!(errors[0].message, "expected end of block after return") + assert_eq!(errors[0].message, "expected end of block after return"); + assert_eq!(u32::from(errors[0].range.start()) as usize, 12); } #[test] @@ -3744,6 +3745,16 @@ Syntax(Chunk)@0..47 assert_eq!(errors.len(), 1); assert_eq!(errors[0].kind, LuaParseErrorKind::SyntaxError); - assert_eq!(errors[0].message, "expected end of block after return") + assert_eq!(errors[0].message, "expected end of block after return"); + assert_eq!(u32::from(errors[0].range.start()) as usize, 8); + } + + #[test] + fn test_do_return_end() { + let code = "do return end"; + let tree = LuaParser::parse(code, ParserConfig::default()); + let errors = tree.get_errors(); + + assert!(errors.is_empty()); } } diff --git a/crates/emmylua_parser/src/grammar/lua/stat.rs b/crates/emmylua_parser/src/grammar/lua/stat.rs index 9af319dea..eb9fb5b0e 100644 --- a/crates/emmylua_parser/src/grammar/lua/stat.rs +++ b/crates/emmylua_parser/src/grammar/lua/stat.rs @@ -752,7 +752,6 @@ fn parse_attrib(p: &mut LuaParser) -> ParseResult { fn parse_return(p: &mut LuaParser) -> ParseResult { let m = p.mark(LuaSyntaxKind::ReturnStat); - let return_start_range = p.current_token_range(); p.bump(); if !block_follow(p) && p.current_token() != LuaTokenKind::TkSemicolon @@ -766,9 +765,9 @@ fn parse_return(p: &mut LuaParser) -> ParseResult { if !block_follow(p) { p.push_error(LuaParseError::syntax_error_from( &t!("expected end of block after return"), - return_start_range, + p.current_token_range(), )); - }; + } Ok(m.complete(p)) }