Skip to content

Commit aa4dbf6

Browse files
committed
Merge bugfix for nested function parsing
2 parents 3e23f70 + 6a321a7 commit aa4dbf6

File tree

4 files changed

+59
-8
lines changed

4 files changed

+59
-8
lines changed

docs/changelog.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ compatibility impact will be clearly marked as such in the changelog.
1414

1515
[semver]: https://semver.org/
1616

17+
## Next
18+
19+
Unreleased.
20+
21+
* Fix a bug that prevented parsing nested functions.
22+
23+
Thanks to matthieucx for contributing to this release.
24+
1725
## 0.12.0
1826

1927
Released 2025-12-17.

golden/rcl/function_nested.test

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// This is a regression test for a parser bug:
2+
// the former used to be accepted but not the latter,
3+
// even though they should be equivalent.
4+
let f = x => (y => 1);
5+
let g = x => ((y) => 1);
6+
7+
f(0)(0) == g(0)(0)
8+
9+
# output:
10+
true

grammar/tree-sitter-rcl/test/corpus/expr.txt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,38 @@ Function with 0 args and comment
368368
(comment))
369369
(string (string_double))))
370370

371+
============================================
372+
Nested function, inner arg not parenthesized
373+
============================================
374+
375+
x => (y => 1)
376+
377+
---
378+
379+
(source_file
380+
(expr_function
381+
(function_args (ident))
382+
(expr_term_parens
383+
(expr_function
384+
(function_args (ident))
385+
(number (num_decimal))))))
386+
387+
============================================
388+
Nested function with inner arg parenthesized
389+
============================================
390+
391+
x => ((y) => 1)
392+
393+
---
394+
395+
(source_file
396+
(expr_function
397+
(function_args (ident))
398+
(expr_term_parens
399+
(expr_function
400+
(function_args (ident))
401+
(number (num_decimal))))))
402+
371403
=====================================
372404
Not a function but parenthesized expr
373405
=====================================

src/parser.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -609,15 +609,14 @@ impl<'a> Parser<'a> {
609609
/// until we either see a `=>` and we know it's a lambda, or until we see
610610
/// some violation and we know it's not a lambda.
611611
///
612-
/// TODO: This is getting complex. I should consider using a prefix token
613-
/// to disambiguate lambdas after all.
614-
///
615-
/// TODO II: A better way to handle this: when closing a matching ), write
616-
/// to a side buffer the index of the token next to the opening (. That way,
617-
/// when we have a (, we can jump ahead to the closing ), and peek what
618-
/// comes after that closing ).
612+
/// TODO: An alternative way to handle this: when closing a matching ) in
613+
/// the lexer, write to a side buffer the index of the token next to the
614+
/// opening (. That way, when we have a (, we can jump ahead to the closing
615+
/// ), and peek what comes after it without having to do paren matching
616+
/// again here.
619617
fn look_ahead_is_function(&mut self) -> bool {
620618
let mut offset = 0;
619+
let mut paren_depth: u32 = 0;
621620
match self.peek() {
622621
Token::Ident => offset = 1,
623622
Token::LParen => {
@@ -632,10 +631,12 @@ impl<'a> Parser<'a> {
632631
// trying to parse an expression and failing on the `,`.
633632
for i in 1.. {
634633
match self.peek_n(i) {
635-
Token::RParen => {
634+
Token::LParen => paren_depth += 1,
635+
Token::RParen if paren_depth == 0 => {
636636
offset = i + 1;
637637
break;
638638
}
639+
Token::RParen => paren_depth -= 1,
639640
Token::Eof => unreachable!("The lexer returns balanced parens."),
640641
_ => continue,
641642
}

0 commit comments

Comments
 (0)