Skip to content

Commit 6c49c8d

Browse files
committed
fix parser for Ternary
1 parent 21e835d commit 6c49c8d

3 files changed

Lines changed: 171 additions & 20 deletions

File tree

crates/emmylua_parser/src/grammar/lua/expr.rs

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ fn parse_sub_expr(p: &mut LuaParser, limit: i32) -> ParseResult {
4242
if p.current_token() == LuaTokenKind::TkTernary && TERNARY_LEFT > limit {
4343
let m = cm.precede(p, LuaSyntaxKind::TernaryExpr);
4444
p.bump(); // consume '?'
45+
p.enter_ternary();
4546
match parse_sub_expr(p, 0) {
4647
Ok(_) => {}
4748
Err(_) => {
@@ -51,6 +52,7 @@ fn parse_sub_expr(p: &mut LuaParser, limit: i32) -> ParseResult {
5152
));
5253
}
5354
}
55+
p.leave_ternary();
5456
match expect_token(p, LuaTokenKind::TkColon) {
5557
Ok(_) => {}
5658
Err(_) => {
@@ -524,17 +526,20 @@ fn parse_suffixed_expr(p: &mut LuaParser) -> ParseResult {
524526
let m = p.mark(LuaSyntaxKind::ParenExpr);
525527
let paren_range = p.current_token_range();
526528
p.bump();
529+
p.enter_paren();
527530
match parse_expr(p) {
528531
Ok(_) => {}
529532
Err(err) => {
530533
p.push_error(LuaParseError::syntax_error_from(
531534
&t!("expected expression inside parentheses"),
532535
paren_range,
533536
));
537+
p.leave_paren();
534538
m.complete(p);
535539
return Err(err);
536540
}
537541
}
542+
p.leave_paren();
538543
if p.current_token() == LuaTokenKind::TkRightParen {
539544
p.bump();
540545
} else {
@@ -565,7 +570,7 @@ fn parse_suffixed_expr(p: &mut LuaParser) -> ParseResult {
565570
cm = m.complete(p);
566571
}
567572
LuaTokenKind::TkColon => {
568-
if !is_colon_call_lookahead(p) {
573+
if p.inside_ternary_branch() && !p.inside_paren() {
569574
return Ok(cm);
570575
}
571576
let m = cm.precede(p, LuaSyntaxKind::IndexExpr);
@@ -652,25 +657,6 @@ fn parse_name_or_special_function(p: &mut LuaParser) -> ParseResult {
652657
Ok(cm)
653658
}
654659

655-
fn is_colon_call_lookahead(p: &LuaParser) -> bool {
656-
let name_token = p.peek_next_token();
657-
match name_token {
658-
LuaTokenKind::TkName => {
659-
let after_name = p.peek_nth_token(1);
660-
matches!(
661-
after_name,
662-
LuaTokenKind::TkLeftParen
663-
| LuaTokenKind::TkLeftBrace
664-
| LuaTokenKind::TkString
665-
| LuaTokenKind::TkLongString
666-
| LuaTokenKind::TkSafeNavigation
667-
)
668-
}
669-
LuaTokenKind::None | LuaTokenKind::TkEof => true,
670-
_ => false,
671-
}
672-
}
673-
674660
fn parse_index_struct(p: &mut LuaParser) -> Result<(), ParseFailReason> {
675661
let index_op_range = p.current_token_range();
676662
match p.current_token() {

crates/emmylua_parser/src/grammar/lua/test.rs

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,6 +1227,141 @@ Syntax(Chunk)@0..20
12271227
);
12281228
}
12291229

1230+
#[test]
1231+
fn test_ternary_right_assoc() {
1232+
let code = "local x = a ? b ? c : d : e\n";
1233+
let result = r#"
1234+
Syntax(Chunk)@0..28
1235+
Syntax(Block)@0..28
1236+
Syntax(LocalStat)@0..27
1237+
Token(TkLocal)@0..5 "local"
1238+
Token(TkWhitespace)@5..6 " "
1239+
Syntax(LocalName)@6..7
1240+
Token(TkName)@6..7 "x"
1241+
Token(TkWhitespace)@7..8 " "
1242+
Token(TkAssign)@8..9 "="
1243+
Token(TkWhitespace)@9..10 " "
1244+
Syntax(TernaryExpr)@10..27
1245+
Syntax(NameExpr)@10..11
1246+
Token(TkName)@10..11 "a"
1247+
Token(TkWhitespace)@11..12 " "
1248+
Token(TkTernary)@12..13 "?"
1249+
Token(TkWhitespace)@13..14 " "
1250+
Syntax(TernaryExpr)@14..23
1251+
Syntax(NameExpr)@14..15
1252+
Token(TkName)@14..15 "b"
1253+
Token(TkWhitespace)@15..16 " "
1254+
Token(TkTernary)@16..17 "?"
1255+
Token(TkWhitespace)@17..18 " "
1256+
Syntax(NameExpr)@18..19
1257+
Token(TkName)@18..19 "c"
1258+
Token(TkWhitespace)@19..20 " "
1259+
Token(TkColon)@20..21 ":"
1260+
Token(TkWhitespace)@21..22 " "
1261+
Syntax(NameExpr)@22..23
1262+
Token(TkName)@22..23 "d"
1263+
Token(TkWhitespace)@23..24 " "
1264+
Token(TkColon)@24..25 ":"
1265+
Token(TkWhitespace)@25..26 " "
1266+
Syntax(NameExpr)@26..27
1267+
Token(TkName)@26..27 "e"
1268+
Token(TkEndOfLine)@27..28 "\n"
1269+
"#;
1270+
1271+
assert_ast_eq!(
1272+
code,
1273+
result,
1274+
ParserConfig::with_level(LuaLanguageLevel::LuaJITExt)
1275+
);
1276+
}
1277+
1278+
#[test]
1279+
fn test_ternary_with_paren_method_call() {
1280+
let code = "local x = a ? (b:call()) : c\n";
1281+
let result = r#"
1282+
Syntax(Chunk)@0..29
1283+
Syntax(Block)@0..29
1284+
Syntax(LocalStat)@0..28
1285+
Token(TkLocal)@0..5 "local"
1286+
Token(TkWhitespace)@5..6 " "
1287+
Syntax(LocalName)@6..7
1288+
Token(TkName)@6..7 "x"
1289+
Token(TkWhitespace)@7..8 " "
1290+
Token(TkAssign)@8..9 "="
1291+
Token(TkWhitespace)@9..10 " "
1292+
Syntax(TernaryExpr)@10..28
1293+
Syntax(NameExpr)@10..11
1294+
Token(TkName)@10..11 "a"
1295+
Token(TkWhitespace)@11..12 " "
1296+
Token(TkTernary)@12..13 "?"
1297+
Token(TkWhitespace)@13..14 " "
1298+
Syntax(ParenExpr)@14..24
1299+
Token(TkLeftParen)@14..15 "("
1300+
Syntax(CallExpr)@15..23
1301+
Syntax(IndexExpr)@15..21
1302+
Syntax(NameExpr)@15..16
1303+
Token(TkName)@15..16 "b"
1304+
Token(TkColon)@16..17 ":"
1305+
Token(TkName)@17..21 "call"
1306+
Syntax(CallArgList)@21..23
1307+
Token(TkLeftParen)@21..22 "("
1308+
Token(TkRightParen)@22..23 ")"
1309+
Token(TkRightParen)@23..24 ")"
1310+
Token(TkWhitespace)@24..25 " "
1311+
Token(TkColon)@25..26 ":"
1312+
Token(TkWhitespace)@26..27 " "
1313+
Syntax(NameExpr)@27..28
1314+
Token(TkName)@27..28 "c"
1315+
Token(TkEndOfLine)@28..29 "\n"
1316+
"#;
1317+
1318+
assert_ast_eq!(
1319+
code,
1320+
result,
1321+
ParserConfig::with_level(LuaLanguageLevel::LuaJITExt)
1322+
);
1323+
}
1324+
1325+
#[test]
1326+
fn test_method_chain_no_ternary() {
1327+
let code = "local x = a:b():c()\n";
1328+
let result = r#"
1329+
Syntax(Chunk)@0..20
1330+
Syntax(Block)@0..20
1331+
Syntax(LocalStat)@0..19
1332+
Token(TkLocal)@0..5 "local"
1333+
Token(TkWhitespace)@5..6 " "
1334+
Syntax(LocalName)@6..7
1335+
Token(TkName)@6..7 "x"
1336+
Token(TkWhitespace)@7..8 " "
1337+
Token(TkAssign)@8..9 "="
1338+
Token(TkWhitespace)@9..10 " "
1339+
Syntax(CallExpr)@10..19
1340+
Syntax(IndexExpr)@10..17
1341+
Syntax(CallExpr)@10..15
1342+
Syntax(IndexExpr)@10..13
1343+
Syntax(NameExpr)@10..11
1344+
Token(TkName)@10..11 "a"
1345+
Token(TkColon)@11..12 ":"
1346+
Token(TkName)@12..13 "b"
1347+
Syntax(CallArgList)@13..15
1348+
Token(TkLeftParen)@13..14 "("
1349+
Token(TkRightParen)@14..15 ")"
1350+
Token(TkColon)@15..16 ":"
1351+
Token(TkName)@16..17 "c"
1352+
Syntax(CallArgList)@17..19
1353+
Token(TkLeftParen)@17..18 "("
1354+
Token(TkRightParen)@18..19 ")"
1355+
Token(TkEndOfLine)@19..20 "\n"
1356+
"#;
1357+
1358+
assert_ast_eq!(
1359+
code,
1360+
result,
1361+
ParserConfig::with_level(LuaLanguageLevel::LuaJITExt)
1362+
);
1363+
}
1364+
12301365
#[test]
12311366
fn test_const_stat() {
12321367
let code = "const x = 1\n";

crates/emmylua_parser/src/parser/lua_parser.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ pub struct LuaParser<'a> {
2323
mark_level: usize,
2424
pub parse_config: ParserConfig<'a>,
2525
pub(crate) errors: &'a mut Vec<LuaParseError>,
26+
ternary_depth: usize,
27+
paren_depth: usize,
2628
}
2729

2830
impl MarkerEventContainer for LuaParser<'_> {
@@ -61,6 +63,8 @@ impl<'a> LuaParser<'a> {
6163
parse_config: config,
6264
mark_level: 0,
6365
errors: &mut errors,
66+
ternary_depth: 0,
67+
paren_depth: 0,
6468
};
6569

6670
parse_chunk(&mut parser);
@@ -193,6 +197,30 @@ impl<'a> LuaParser<'a> {
193197
}
194198
}
195199

200+
pub fn enter_ternary(&mut self) {
201+
self.ternary_depth += 1;
202+
}
203+
204+
pub fn leave_ternary(&mut self) {
205+
self.ternary_depth = self.ternary_depth.saturating_sub(1);
206+
}
207+
208+
pub fn inside_ternary_branch(&self) -> bool {
209+
self.ternary_depth > 0
210+
}
211+
212+
pub fn enter_paren(&mut self) {
213+
self.paren_depth += 1;
214+
}
215+
216+
pub fn leave_paren(&mut self) {
217+
self.paren_depth = self.paren_depth.saturating_sub(1);
218+
}
219+
220+
pub fn inside_paren(&self) -> bool {
221+
self.paren_depth > 0
222+
}
223+
196224
fn skip_trivia(&self, index: &mut usize) {
197225
if index >= &mut self.tokens.len() {
198226
return;
@@ -399,6 +427,8 @@ mod tests {
399427
parse_config: config,
400428
mark_level: 0,
401429
errors,
430+
ternary_depth: 0,
431+
paren_depth: 0,
402432
};
403433
parser.init();
404434

0 commit comments

Comments
 (0)