PrestonKnopp / tree-sitter-gdscript

Tree sitter grammar for Godot's GDScript
https://www.npmjs.com/package/tree-sitter-gdscript
MIT License
50 stars 11 forks source link

Anonymous functions cause ERROR #11

Closed Cretezy closed 1 year ago

Cretezy commented 1 year ago

Part of Godot 4 support. Anonymous functiosn cause ERROR.

I tried to get this working, but I keep hitting conflicts and I'm not very experienced with tree-sitter :/

============================================
Anonymous functions
============================================

connect("", func():
  print()
)

---

(source
    (expression_statement
      (call
        (identifier)
        (argument_list
          (string)
          (ERROR
            (call
              (identifier)
              (argument_list)))
          (call
            (identifier)
            (argument_list))))))
PrestonKnopp commented 1 year ago

What are the indentation rules for the lambda functions? Can a closing parenthesis end on the same line of the last statement in the lambda?

I wonder if a modified function_definition can be popped into _expression to make this work.

Cretezy commented 1 year ago

As far as I can tell, these are all valid.

var x = func(): print()
var x = y(func(): print())

# Multiple lines
var x = y(func(z: Z) -> void:
    print()
)
var x = func():
    print()

# Named
var x = func y(): print()

However, this is invalid:

# Bare function (simple statement IIRC)
func(): print()

I originally tried making a new anonymous_function_definition and putting that in _expression (with the name optionally, but got a conflict that I didn't know how to fix. I also tried putting function_definition in _expession, but same thing basically. If you can fix that conflict, I believe it should work.

PrestonKnopp commented 1 year ago

@Cretezy, thanks for looking into this. I used your observations as the base for the following commits:

This supports the following syntax

accept(func():
    1 + 1, call())

There is still an issue across all statements or expressions with a body node that I'm not sure how to solve. For example, tree-sitter-gdscript cannot parse the following but Godot can:

var x = func(): if true: pass else: pass

I also noted that Godot parses one line lambdas with an if statement differently than a top level if statement. The following is a parser error in Godot:

if true: pass else: pass

The right hand expression rule is used to fix the conflict between an anonymous function definition in an expression statement and a function definition statement.

Cretezy commented 1 year ago

Great, thank you! I also didn't know this one line lambdas if/else was possible in Godot.

Glad more support is coming in as the rc1 just released :rocket:

PrestonKnopp commented 1 year ago

Unfortunately reverted changes from https://github.com/PrestonKnopp/tree-sitter-gdscript/commit/86e8d449ca8a4a9a685fbd35699990e1d692e1b5 and https://github.com/PrestonKnopp/tree-sitter-gdscript/commit/6f615afc1e74121bf669a7f32c9b775e57d5636e as it broke basic parsing. I will set time aside this week to find a working solution.

PrestonKnopp commented 1 year ago

Lambdas are parsing well enough for general use now. Closing for now.