Skip to content

Commit 0c9611c

Browse files
authored
fix: lambdas and parens, multiple indents (#347)
Fix compound statements of lambdas, fixes #346
1 parent c9b3bd4 commit 0c9611c

File tree

3 files changed

+35
-25
lines changed

3 files changed

+35
-25
lines changed

gdtoolkit/parser/gdscript.lark

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -255,18 +255,8 @@ _lambda_suite: _lambda_body
255255
| _standalone_lambda_stmt
256256
_lambda_body: _NL _INDENT _func_stmt+ _DEDENT
257257
_standalone_lambda_stmt: _simple_func_stmt
258-
// | annotation* compound_lambda_stmt
259-
// | annotation* compound_func_stmt
258+
| annotation* compound_func_stmt
260259
| annotation*
261-
// ?compound_lambda_stmt: lambda_if_stmt
262-
// | while_stmt
263-
// | for_stmt
264-
// | for_stmt_typed
265-
// | match_stmt
266-
// lambda_if_stmt: lambda_if_branch (_NL? lambda_elif_branch)* [_NL? lambda_else_branch]
267-
// lambda_if_branch: "if" expr ":" _lambda_suite
268-
// lambda_elif_branch: "elif" expr ":" _lambda_suite
269-
// lambda_else_branch: "else" ":" _lambda_suite
270260
?literal: NUMBER
271261
| string
272262
| rstring

gdtoolkit/parser/gdscript_indenter.py

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class GDScriptIndenter(Indenter):
99
NL_type = "_NL"
1010
OPEN_PAREN_types = ["LPAR", "LSQB", "LBRACE"]
1111
CLOSE_PAREN_types = ["RPAR", "RSQB", "RBRACE"]
12+
LAMBDA_LINE_EXTENSION_types = ["IF", "WHILE", "FOR", "MATCH"]
1213
LAMBDA_SEPARATOR_types = ["COMMA"]
1314
INDENT_type = "_INDENT"
1415
DEDENT_type = "_DEDENT"
@@ -42,51 +43,60 @@ def _process(self, stream):
4243
self.processed_tokens = []
4344
self.undedented_lambdas_at_paren_level = defaultdict(int)
4445

46+
had_newline = False
4547
for produced_token in super()._process(self._record_stream(stream)):
4648
if (
4749
produced_token.type in self.CLOSE_PAREN_types
4850
or produced_token.type in self.LAMBDA_SEPARATOR_types
4951
):
5052
# dedenting all undedented lambas (more than one if nested) at current paren level
5153
while self.undedented_lambdas_at_paren_level[self.paren_level] > 0:
52-
yield from self._dedent_lambda_at_token(produced_token)
54+
yield from self._dedent_lambda_at_token(had_newline, produced_token)
55+
had_newline = False
56+
had_newline = produced_token.type == self.NL_type
5357
yield produced_token
5458

5559
def _record_stream(self, stream):
5660
for token in stream:
5761
self.processed_tokens.append(token)
5862
yield token
5963

64+
def _in_multiline_lambda(self):
65+
return self.undedented_lambdas_at_paren_level[self.paren_level] > 0
66+
6067
# pylint: disable=invalid-name
6168
def _handle_NL_in_parens(self, token: Token):
69+
# Adapted from lark/indendeter.py as that normally disables line handling
70+
# when paren_level > 0.
71+
# NOTE: we never raise DedentError here as it doesn't make sense in parens
6272
indent_str = token.rsplit("\n", 1)[1] # tabs and spaces
6373
indent = indent_str.count(" ") + indent_str.count("\t") * self.tab_len
6474

65-
if (
75+
if indent > self.indent_level[-1] and (
6676
self._current_token_is_just_after_lambda_header()
67-
and indent > self.indent_level[-1]
77+
or self._in_multiline_lambda()
6878
):
6979
self.indent_level.append(indent)
7080
self.undedented_lambdas_at_paren_level[self.paren_level] += 1
7181
yield token
7282
yield Token.new_borrow_pos(self.INDENT_type, indent_str, token)
73-
elif (
74-
indent <= self.indent_level[-1]
75-
and self.undedented_lambdas_at_paren_level[self.paren_level] > 0
76-
):
83+
elif indent <= self.indent_level[-1] and self._in_multiline_lambda():
7784
yield token
78-
79-
while indent < self.indent_level[-1]:
85+
while indent < self.indent_level[-1] and self._in_multiline_lambda():
8086
self.indent_level.pop()
8187
self.undedented_lambdas_at_paren_level[self.paren_level] -= 1
82-
yield Token.new_borrow_pos(self.DEDENT_type, indent_str, token)
83-
84-
# never raising DedentError here as it doesn't make sense in parens
88+
yield Token(self.DEDENT_type, None, None, token.line, None, token.line)
89+
# If we are still in a situation that can handle newlines, emit an extra
90+
# one with the same rationale as above
91+
if self._in_multiline_lambda():
92+
yield token
93+
# Otherwise do nothing as other expressions don't handle newlines
8594

86-
def _dedent_lambda_at_token(self, token: Token):
95+
def _dedent_lambda_at_token(self, had_newline: bool, token: Token):
8796
self.indent_level.pop()
8897
self.undedented_lambdas_at_paren_level[self.paren_level] -= 1
89-
yield Token.new_borrow_pos(self.NL_type, "N/A", token)
98+
if not had_newline:
99+
yield Token.new_borrow_pos(self.NL_type, "N/A", token)
90100
yield Token.new_borrow_pos(self.DEDENT_type, "N/A", token)
91101

92102
def _current_token_is_just_after_lambda_header(self):

tests/valid-gd-scripts/multiline_lambdas.gd

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
func foo():
2+
stack(func():
3+
print("foo")
4+
if source == 1:
5+
var x: = 1
6+
pass)
7+
stack(func():
8+
if true:
9+
pass
10+
if false:
11+
pass)
212
var f0 = func bar():
313
pass
414
var f1 = func():

0 commit comments

Comments
 (0)