Scony / godot-gdscript-toolkit

Independent set of GDScript tools - parser, linter, formatter, and more
MIT License
944 stars 65 forks source link

GDFormat 4.2.2 is Unable to parse lambda expressions #297

Closed jamie-pate closed 4 months ago

jamie-pate commented 4 months ago

gdformat 4.2.2 fails to parse the following code and the linter crashes with an unhandled exception.

var race := {complete = null}
race.complete = func (promise: Promise): # this creates an unhandled exception in the lexer
    promise.completed.disconnect(race.complete)
Traceback (most recent call last):
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/lexer.py", line 590, in lex
    yield lexer.next_token(lexer_state, parser_state)
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/lexer.py", line 528, in next_token
    raise UnexpectedCharacters(lex_state.text, line_ctr.char_pos, line_ctr.line, line_ctr.column,
lark.exceptions.UnexpectedCharacters: <exception str() failed>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/gdtoolkit/formatter/__main__.py", line 209, in _format_code
    code_parse_tree = parser.parse(code, gather_metadata=True)
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/gdtoolkit/parser/parser.py", line 62, in parse
    self._parser_with_metadata.parse(adjusted_code)
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/lark.py", line 645, in parse
    return self.parser.parse(text, start=start, on_error=on_error)
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/parser_frontends.py", line 96, in parse
    return self.parser.parse(stream, chosen_start, **kw)
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/parsers/lalr_parser.py", line 41, in parse
    return self.parser.parse(lexer, start)
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/parsers/lalr_parser.py", line 171, in parse
    return self.parse_from_state(parser_state)
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/parsers/lalr_parser.py", line 193, in parse_from_state
    raise e
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/parsers/lalr_parser.py", line 183, in parse_from_state
    for token in state.lexer.lex(state):
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/indenter.py", line 45, in _process
    for token in stream:
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/lexer.py", line 599, in lex
    raise UnexpectedToken(token, e.allowed, state=parser_state, token_history=[last_token], terminals_by_name=self.root_lexer.terminals_by_name)
lark.exceptions.UnexpectedToken: <exception str() failed>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/gdtoolkit/common/exceptions.py", line 14, in lark_unexpected_token_to_str
    return f"{exception.get_context(code)}\n{exception}"
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/exceptions.py", line 256, in __str__
    % (self.token, self.line, self.column, self._format_expected(self.accepts or self.expected)))
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/exceptions.py", line 142, in _format_expected
    expected = [d[t_name].user_repr() if t_name in d else t_name for t_name in expected]
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/exceptions.py", line 142, in <listcomp>
    expected = [d[t_name].user_repr() if t_name in d else t_name for t_name in expected]
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/lexer.py", line 124, in user_repr
    return self.pattern.raw or self.name
AttributeError: 'PatternStr' object has no attribute 'raw'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/jpate/build/escaperoom/.py_venv4/bin/gdformat", line 8, in <module>
    sys.exit(main())
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/gdtoolkit/formatter/__main__.py", line 74, in main
    _check_files_formatting(
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/gdtoolkit/formatter/__main__.py", line 107, in _check_files_formatting
    success, actually_formatted, formatted_code = _format_code(
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/gdtoolkit/formatter/__main__.py", line 234, in _format_code
    lark_unexpected_token_to_str(
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/gdtoolkit/common/exceptions.py", line 16, in lark_unexpected_token_to_str
    return f"{exception}".strip()
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/exceptions.py", line 256, in __str__
    % (self.token, self.line, self.column, self._format_expected(self.accepts or self.expected)))
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/exceptions.py", line 142, in _format_expected
    expected = [d[t_name].user_repr() if t_name in d else t_name for t_name in expected]
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/exceptions.py", line 142, in <listcomp>
    expected = [d[t_name].user_repr() if t_name in d else t_name for t_name in expected]
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/lexer.py", line 124, in user_repr
    return self.pattern.raw or self.name
AttributeError: 'PatternStr' object has no attribute 'raw'

Trying to find a workaround, this also fails.

var race := {complete = null}
var complete = func (promise: Promise): # this creates an unhandled exception in the lexer
    promise.completed.disconnect(race.complete)
race.complete = complete
jamie-pate commented 4 months ago

Also fails when you try to use a lambda as a method argument:

func get_texture():
    return Promise.new(func(resolve: Callable, reject: Callable):
        var t := TimeIt.new(self)
        var texture := ImageTexture.new() # this line also fails
        ...
)
Traceback (most recent call last):
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/lexer.py", line 590, in lex
    yield lexer.next_token(lexer_state, parser_state)
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/lexer.py", line 528, in next_token
    raise UnexpectedCharacters(lex_state.text, line_ctr.char_pos, line_ctr.line, line_ctr.column,
lark.exceptions.UnexpectedCharacters: <exception str() failed>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/gdtoolkit/formatter/__main__.py", line 209, in _format_code
    code_parse_tree = parser.parse(code, gather_metadata=True)
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/gdtoolkit/parser/parser.py", line 62, in parse
    self._parser_with_metadata.parse(adjusted_code)
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/lark.py", line 645, in parse
    return self.parser.parse(text, start=start, on_error=on_error)
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/parser_frontends.py", line 96, in parse
    return self.parser.parse(stream, chosen_start, **kw)
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/parsers/lalr_parser.py", line 41, in parse
    return self.parser.parse(lexer, start)
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/parsers/lalr_parser.py", line 171, in parse
    return self.parse_from_state(parser_state)
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/parsers/lalr_parser.py", line 193, in parse_from_state
    raise e
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/parsers/lalr_parser.py", line 183, in parse_from_state
    for token in state.lexer.lex(state):
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/indenter.py", line 45, in _process
    for token in stream:
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/lexer.py", line 599, in lex
    raise UnexpectedToken(token, e.allowed, state=parser_state, token_history=[last_token], terminals_by_name=self.root_lexer.terminals_by_name)
lark.exceptions.UnexpectedToken: <exception str() failed>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/gdtoolkit/common/exceptions.py", line 14, in lark_unexpected_token_to_str
    return f"{exception.get_context(code)}\n{exception}"
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/exceptions.py", line 256, in __str__
    % (self.token, self.line, self.column, self._format_expected(self.accepts or self.expected)))
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/exceptions.py", line 142, in _format_expected
    expected = [d[t_name].user_repr() if t_name in d else t_name for t_name in expected]
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/exceptions.py", line 142, in <listcomp>
    expected = [d[t_name].user_repr() if t_name in d else t_name for t_name in expected]
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/lexer.py", line 124, in user_repr
    return self.pattern.raw or self.name
AttributeError: 'PatternStr' object has no attribute 'raw'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/jpate/build/escaperoom/.py_venv4/bin/gdformat", line 8, in <module>
    sys.exit(main())
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/gdtoolkit/formatter/__main__.py", line 74, in main
    _check_files_formatting(
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/gdtoolkit/formatter/__main__.py", line 107, in _check_files_formatting
    success, actually_formatted, formatted_code = _format_code(
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/gdtoolkit/formatter/__main__.py", line 234, in _format_code
    lark_unexpected_token_to_str(
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/gdtoolkit/common/exceptions.py", line 16, in lark_unexpected_token_to_str
    return f"{exception}".strip()
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/exceptions.py", line 256, in __str__
    % (self.token, self.line, self.column, self._format_expected(self.accepts or self.expected)))
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/exceptions.py", line 142, in _format_expected
    expected = [d[t_name].user_repr() if t_name in d else t_name for t_name in expected]
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/exceptions.py", line 142, in <listcomp>
    expected = [d[t_name].user_repr() if t_name in d else t_name for t_name in expected]
  File "/home/jpate/build/escaperoom/.py_venv4/lib/python3.10/site-packages/lark/lexer.py", line 124, in user_repr
    return self.pattern.raw or self.name
AttributeError: 'PatternStr' object has no attribute 'raw'
Scony commented 4 months ago

Duplicate of https://github.com/Scony/godot-gdscript-toolkit/issues/191