Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: lambdas and parens, multiple indents #347

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 1 addition & 11 deletions gdtoolkit/parser/gdscript.lark
Original file line number Diff line number Diff line change
Expand Up @@ -255,18 +255,8 @@ _lambda_suite: _lambda_body
| _standalone_lambda_stmt
_lambda_body: _NL _INDENT _func_stmt+ _DEDENT
_standalone_lambda_stmt: _simple_func_stmt
// | annotation* compound_lambda_stmt
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opinionated, but I think fixing compound func stmt is the way to go and this works some of the time. could def revert this part tho

// | annotation* compound_func_stmt
| annotation* compound_func_stmt
| annotation*
// ?compound_lambda_stmt: lambda_if_stmt
// | while_stmt
// | for_stmt
// | for_stmt_typed
// | match_stmt
// lambda_if_stmt: lambda_if_branch (_NL? lambda_elif_branch)* [_NL? lambda_else_branch]
// lambda_if_branch: "if" expr ":" _lambda_suite
// lambda_elif_branch: "elif" expr ":" _lambda_suite
// lambda_else_branch: "else" ":" _lambda_suite
?literal: NUMBER
| string
| rstring
Expand Down
28 changes: 17 additions & 11 deletions gdtoolkit/parser/gdscript_indenter.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class GDScriptIndenter(Indenter):
NL_type = "_NL"
OPEN_PAREN_types = ["LPAR", "LSQB", "LBRACE"]
CLOSE_PAREN_types = ["RPAR", "RSQB", "RBRACE"]
LAMBDA_LINE_EXTENSION_types = ["IF", "WHILE", "FOR", "MATCH"]
LAMBDA_SEPARATOR_types = ["COMMA"]
INDENT_type = "_INDENT"
DEDENT_type = "_DEDENT"
Expand Down Expand Up @@ -57,31 +58,36 @@ def _record_stream(self, stream):
self.processed_tokens.append(token)
yield token

def _in_multiline_lambda(self):
return self.undedented_lambdas_at_paren_level[self.paren_level] > 0

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

if (
if indent > self.indent_level[-1] and (
self._current_token_is_just_after_lambda_header()
and indent > self.indent_level[-1]
or self._in_multiline_lambda()
):
self.indent_level.append(indent)
self.undedented_lambdas_at_paren_level[self.paren_level] += 1
yield token
yield Token.new_borrow_pos(self.INDENT_type, indent_str, token)
elif (
indent <= self.indent_level[-1]
and self.undedented_lambdas_at_paren_level[self.paren_level] > 0
):
elif indent <= self.indent_level[-1] and self._in_multiline_lambda():
yield token

while indent < self.indent_level[-1]:
while indent < self.indent_level[-1] and self._in_multiline_lambda():
self.indent_level.pop()
self.undedented_lambdas_at_paren_level[self.paren_level] -= 1
yield Token.new_borrow_pos(self.DEDENT_type, indent_str, token)

# never raising DedentError here as it doesn't make sense in parens
yield Token(self.DEDENT_type, None, None, token.line, None, token.line)
# If we are still in a situation that can handle newlines, emit an extra
# one with the same rationale as above
if self._in_multiline_lambda():
yield token
# Otherwise do nothing as other expressions don't handle newlines

def _dedent_lambda_at_token(self, token: Token):
self.indent_level.pop()
Expand Down
245 changes: 234 additions & 11 deletions tests/valid-gd-scripts/lambdas.gd
Original file line number Diff line number Diff line change
@@ -1,11 +1,234 @@
extends Node

func _ready():
var l1 = func(x): pass;print('l1', x)
l1.call('foo')
var ls = [func(): print('l3'), func(): print('l4')]
ls[1].call()
var lss = [
func(): print('l6')]
lss[1].call()
get_tree().process_frame.connect(func(): pass;print('x'))
func parened1():
stack(func():
source.owner.remove_card(source)
if source == 1:
var x: = 1
pass)

func parened2():
stack(func():
if true:
pass
if false:
pass)

func foo(x):
pass
func bar(x,y):
pass
func actual_params():
foo(func():
var x = 1
return x)

foo(func():
var x = 1
if x > 1:
print(x))

foo(func():
var x = 1
if x > 1:
print(x)
)

bar(func():
var x = 1
return x, func():
var y = 1
return y)

bar(func():
var x = 1
return x,
func():
var y = 1
return y)

bar(func():
var x = 1
return x,

func():
var y = 1
return y)

bar(func():
var x = 1
if x > 0:
print(x), func():
var y = 1
return y)

bar(func():
var x = 1
if x > 0:
print(x),
func():
var y = 1
return y)

func arrays():
var x1 = [func():
var x = 1
return x]
var x2 = [func():
var x = 1
return x
]
var x3 = [func():
var x = 1
return x,func():
var x = 1
return x
]
var x4 = [func():
var x = 1
return x,
func():
var x = 1
return x
]
var x5 = [func():
var x = 1
return x,

func():
var x = 1
return x
]
var x6 = [func():
var x = 1
if x > 0:
print(x),
func():
var x = 1
return x
]
var x7 = [func():
var x = 1
if x > 0:
print(x),

func():
var x = 1
return x
]

func dicts():
var x1 = {'a':func():
var x = 1
return x}
var x2 = {'a':func():
var x = 1
return x
}
var x3 = {'a':func():
var x = 1
return x,'b':func():
var x = 1
return x
}
var x4 = {'a':func():
var x = 1
return x,
'b':func():
var x = 1
return x
}
var x5 = {'a':func():
var x = 1
return x,'b':
func():
var x = 1
return x
}
var x6 = {'a':func():
var x = 1
return x,

'b':func():
var x = 1
return x
}
var x7 = {'a':func():
var x = 1
if x > 0:
print(x),'b':func():
var x = 1
return x
}
var x8 = {'a':func():
var x = 1
if x > 0:
print(x),
'b':func():
var x = 1
return x
}
var x9 = {'a':func():
var x = 1
if x > 0:
print(x),

'b':func():
var x = 1
return x
}

func nested():
var x1 = func():
var x1r = func():
var x = 1
return x
return x1r

var x2 = func():
var x2r = func():
pass
pass
pass

var x3 = func():
var x3r = func():
var x3rr = func():
pass
pass
pass
pass

var x4 = func():
if true:
var x4r = func():
pass
pass
pass
pass

var x5 = func():
if true:
var x5r = func():
if true:
pass
pass
pass
pass
pass

var x6 = func():
if true:
var x6r = func():
if true:
var x6rr = func():
pass
pass
pass
pass
pass
pass

var x7 = [func():
pass
var x = func():
pass
pass,]
72 changes: 36 additions & 36 deletions tests/valid-gd-scripts/multiline_lambdas.gd
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
func foo():
var f0 = func bar():
pass
var f1 = func():
pass
var f11 = func():
var f11r = func():
pass
var f12 = func():
var f12r = func():
return func(): pass
var f13 = func():
pass
var f13r = func():
pass
return func(): pass
var f14 = func():
pass
var f14r = func():
if true:
pass
var f15 = func():
pass
var f15r = func():
if true:
pass
pass
pass
var f16 = func():
@warning_ignore("unused_variable")
var f17 = func():
@warning_ignore("unused_variable")
var x
var f18 = func():
@warning_ignore("unused_variable") var x
var f19 = func():
@warning_ignore("unused_variable") @warning_ignore("unused_variable") var x
# var f0 = func bar():
# pass
# var f1 = func():
# pass
# var f11 = func():
# var f11r = func():
# pass
# var f12 = func():
# var f12r = func():
# return func(): pass
# var f13 = func():
# pass
# var f13r = func():
# pass
# return func(): pass
# var f14 = func():
# pass
# var f14r = func():
# if true:
# pass
# var f15 = func():
# pass
# var f15r = func():
# if true:
# pass
# pass
# pass
# var f16 = func():
# @warning_ignore("unused_variable")
# var f17 = func():
# @warning_ignore("unused_variable")
# var x
# var f18 = func():
# @warning_ignore("unused_variable") var x
# var f19 = func():
# @warning_ignore("unused_variable") @warning_ignore("unused_variable") var x
var f2s = [func():
pass
]
Expand Down