Giter VIP home page Giter VIP logo

tree-sitter-go's Introduction

tree-sitter-go's People

Contributors

adonovan avatar amaanq avatar aryx avatar dcreager avatar hendrikvanantwerpen avatar jimeh avatar joshvera avatar kawaemon avatar lmaruvada avatar matoous avatar mattmassicotte avatar maxbrunsfeld avatar mjambon avatar msftenhanceprovenance avatar patrickt avatar rewinfrey avatar superbo avatar tclem avatar tohjustin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tree-sitter-go's Issues

Comments not behaving well with generics

Hey, I've encountered a weird issue where highlighting breaks if a comment appears below a type instantiation.

Sorry for the plethora of images, but hopefully this gives you enough information to resolve this edge-case:
image
image
image
image

"any" type highlight

I don't know if there is a problem with Neovim or with the tree-sitter but apparently, the any type is incorrectly highlighted.

image

In TSPlayground it looks like the TSTypeBuiltin highlight is applied but for some reason, TSType highlight is used.

image

Multiple return values not parsed correctly

I've run into the following issue: multiples return values of functions are not always parsed correctly.

For example:

  • the return values of func notOk() (int, map[int]int) are parsed incorrectly into
(parameter_list (
  (parameter_declaration ... 
     (array_type ...))    // incorrect - should have two parameter_declaration instead of one,
                          // no array_type expected, map_type expected

To reproduce:

  • with Go code
func ok() ([]int, map[int]int) {
    return nil, nil
}

func notOk() (int, map[int]int) {
    return 0, nil
}
  • inspect the tree, I use M-x treesit-explore-mode in emacs. The whole tree is pasted below. EDIT: below in a comment is the tree produced by tree-sitter parse ....

  • the first function "ok" is as expected - ([]int, map[int]int) is parsed into one parameter_list with two parameter_declaration branches:

result:
   (parameter_list (
    (parameter_declaration
     type: (slice_type [ ] element: (type_identifier)))
    ,
    (parameter_declaration
     type: (map_type map [ key: (type_identifier) ] value: (type_identifier)))
))
  • the second function "notOk" is not parsed as expected - (int, map[int]int) is parsed into one parameter_list with one parameter_declaration branches, I expect two parameter_declaration branches.
  result:
   (parameter_list (
    (parameter_declaration name: (identifier) name: , type: (identifier)
     (array_type [ length: (identifier) ] element: (type_identifier)))
    ))

Full tree:

(source_file
 (package_clause package (package_identifier))
 \n (comment)
 (function_declaration func name: (identifier)
  parameters: (parameter_list ( ))
  result:
   (parameter_list (
    (parameter_declaration
     type: (slice_type [ ] element: (type_identifier)))
    ,
    (parameter_declaration
     type: (map_type map [ key: (type_identifier) ] value: (type_identifier)))
    ))
  body:
   (block {
    (return_statement return
     (expression_list (nil) , (nil)))
    \n }))
 \n
 (function_declaration func name: (identifier)
  parameters: (parameter_list ( ))
  result:
   (parameter_list (
    (parameter_declaration name: (identifier) name: , type: (identifier)
     (array_type [ length: (identifier) ] element: (type_identifier)))
    ))
  body:
   (block {
    (return_statement return
     (expression_list (int_literal) , (nil)))
    \n }))
 \n)

indentexpr for switch case behaviour

nvim 0.8.1
nvim-treesitter: latest
indent behaviour wrong

details:

case 1: enable nvim-treesitter with go support
set indentexpr? output => indentexpr=nvim_treesitter#indent()

func abc(v int) {
    switch v {
}
    switch {
}
    for {
        switch {
    }
    }
}

case 2: disable nvim-treesitter, everything going on well: (ps: filetype indent on)

func abc(v int) {
    switch v {

    }
    switch {
    }
    for {
        switch {
        }
    }
}

set indentexpr? output => indentexpr=GoIndent(v:lnum)

A lot of missing highlights... A bug or expected?

I was wondering what the state of this plugin is, as I seem to be missing a lot of highlights:

image

As you can see in this example the method name, function calls, := assignment and * pointer are all not highlighted. When looking at some Rust code (using the Rust plugin of course) it seems to be able to highlight a lot (if no all) things correctly, so I wondered if what I'm seeing is somehow a bug on my system or that this expected for the current Go plugin?

Not sure how relevant it might be, but trying to use this together with neovim and nvim-treesitter

var_spec includes the Comma in the "name" Field.

To determine whether an unnamed node is or isn't interesting, I look at whether it is part of a field. In the case of var_spec, the comma is included in the "name" field, but it isn't interesting in the context of the node. The following is an example:

var a, b, c;

(:SOURCE-FILE ((0 0) (12 0))
 ((:VAR-DECLARATION ((0 0) (11 0))
   ((:VAR ((0 0) (3 0)) NIL)
    (:VAR-SPEC ((4 0) (11 0))
     (((:NAME :IDENTIFIER) ((4 0) (5 0)) NIL) ((:NAME :|,|) ((5 0) (6 0)) NIL)
      ((:NAME :IDENTIFIER) ((7 0) (8 0)) NIL) ((:NAME :|,|) ((8 0) (9 0)) NIL)
      ((:NAME :IDENTIFIER) ((10 0) (11 0)) NIL)
      ((:TYPE :TYPE-IDENTIFIER) ((11 0) (11 0)) NIL)))))
  (:|;| ((11 0) (12 0)) NIL)))

Constant not being recognized after declaration

Constant seems only to be recognized when declared (const_spec). After it has been declared, it is treated just as a normal keyword.

I am pretty sure this is not mean to be the correct behavior? It seems impossible to change the highlight group for a constant that has already being declared.

image

image

image

Not sure if is possible but would be good to have it to be parsed as constant.

Also I have no clue how to implement that, but maybe with some direction and guidance I can start working on that.

Highlight magic comments

Go has some magic comments, that are processed by go toolchain: //go:generate, //go:build and more.

I suggest to inject highlightings in these comments.

For example, the line with //go:generate may have two highlightings injected: highlighting for directive go:generate and injected shell highlighting for the rest of the line (or highlighting for the first shell argument only).

//go:build: see https://pkg.go.dev/cmd/go#hdr-Build_constraints, it may have the same highlight that if condition has.

Also //go:embed shouldn't be forgotten. It may have path highligthing or highlight globs.

`import` syntax bug

Here's a valid Go program (with nonstandard formatting):

$ cat bug.go 
package main
import ("fmt")
func main() {
	fmt.Println("yo")
}

$ go run bug.go
yo

The tree-sitter-go parser doesn't like it:

~/tree-sitter-go $ npx tree-sitter parse bug.go
(source_file [0, 0] - [5, 0]
  (package_clause [0, 0] - [0, 12]
    (package_identifier [0, 8] - [0, 12]))
  (import_declaration [1, 0] - [1, 14]
    (import_spec_list [1, 7] - [1, 14]
      (ERROR [1, 8] - [1, 13]
        (import_spec [1, 8] - [1, 13]
          path: (interpreted_string_literal [1, 8] - [1, 13])))))
  (function_declaration [2, 0] - [4, 1]
    name: (identifier [2, 5] - [2, 9])
    parameters: (parameter_list [2, 9] - [2, 11])
    body: (block [2, 12] - [4, 1]
      (call_expression [3, 1] - [3, 18]
        function: (selector_expression [3, 1] - [3, 12]
          operand: (identifier [3, 1] - [3, 4])
          field: (field_identifier [3, 5] - [3, 12]))
        arguments: (argument_list [3, 12] - [3, 18]
          (interpreted_string_literal [3, 13] - [3, 17]))))))
bug.go	0 ms	(ERROR [1, 8] - [1, 13])

Here's a simpler example. Note that we get different kinds of errors (ERROR vs. MISSING) depending on the string length:

~/tree-sitter-go $ npx tree-sitter parse <(echo 'import ("foooooo")')
(source_file [0, 0] - [1, 0]
  (import_declaration [0, 0] - [0, 18]
    (import_spec_list [0, 7] - [0, 18]
      (ERROR [0, 8] - [0, 17]
        (import_spec [0, 8] - [0, 17]
          path: (interpreted_string_literal [0, 8] - [0, 17]))))))
/dev/fd/63	0 ms	(ERROR [0, 8] - [0, 17])

~/tree-sitter-go $ npx tree-sitter parse <(echo 'import ("fooooooo")')
(source_file [0, 0] - [1, 0]
  (import_declaration [0, 0] - [0, 19]
    (import_spec_list [0, 7] - [0, 19]
      (import_spec [0, 8] - [0, 18]
        path: (interpreted_string_literal [0, 8] - [0, 18])))))
/dev/fd/63	0 ms	(MISSING "\n" [0, 18] - [0, 18])

~/tree-sitter-go $ npx tree-sitter --version
tree-sitter 0.20.8 (d4c1bf7ce78051b7f4a381d1508d68928512ed5f)

This is a minor bug since the Go reformatter will normally reformat this, resulting in parsing success (try go fmt bug.go).

The different behavior ERROR vs. MISSING is intriguing, though.

Suggestion to introduce var_spec_list for improved consistency

Code sample:

package main

import (
    "fmt"
    "flag"
)

var (
    x int = 99
    y int = 100
)

func main() {
    fmt.Println(x)
    fmt.Println(y)
}

Parser output:

(package_clause) ; [1:1 - 12]
 (package_identifier) ; [1:9 - 12]
(import_declaration) ; [3:1 - 6:1]
 (import_spec_list) ; [3:8 - 6:1]       <<< Introduce an equivalent node (var_spec_list) for var_declaration?
  (import_spec) ; [4:5 - 9]
   path: (interpreted_string_literal) ; [4:5 - 9]
  (import_spec) ; [5:5 - 10]
   path: (interpreted_string_literal) ; [5:5 - 10]
(var_declaration) ; [8:1 - 11:1]
 (var_spec) ; [9:5 - 14]
  name: (identifier) ; [9:5 - 5]
  type: (type_identifier) ; [9:7 - 9]
  value: (expression_list) ; [9:13 - 14]
   (int_literal) ; [9:13 - 14]
 (var_spec) ; [10:5 - 15]
  name: (identifier) ; [10:5 - 5]
  type: (type_identifier) ; [10:7 - 9]
  value: (expression_list) ; [10:13 - 15]
   (int_literal) ; [10:13 - 15]

node bindings

Hi! The npm package tree-sitter-go still being updated?
npm shows the last published date is a year ago.

Parse error for nested if statement inside a for statement

I came across some Go code that was not parsing correctly. Minimizing the context to the smallest units, I came up with:

package main

import (
	"fmt"
)

func main() {
  var vectors [10]int
  for i, v := range vectors {
    func() {
      if v == v {
        fmt.Println("something: %v", vectors[i])
      }
    }()
  }
}

This code parses and runs correctly in Go playground (example).

I've spent some time minimizing this example, and appears to be specific to this configuration of a for statement, a function literal containing an if statement whose condition is a binary expression, and whose block contains a call expression with a selector expression with an interpreted string literal. This was found parsing this file in the Go Lang repo.

Based on debug output, it looks like the if statement's block expression is not condensing, and instead the parser is getting stuck in an error state. Changing any of these elements (like parenthesizing the v == v in the if statement, or using a simple call expression without a selector expression) results in this code correctly parsing.

@maxbrunsfeld any insights here would be really appreciated. I'm not sure how to proceed from here.

Extra

Apoyo para extraer bienes de engaños

Issue with Highlighting Function Parameters Inside the Function

It seems to have an issue with the highlighting functionality, specifically related to the highlighting of function parameters within the function body. While the current implementation correctly highlights the parameter declaration, it fails to highlight the parameter when used inside the function.

Go example:
image

I believe it should highlight function parameters consistently, both in the function declaration and within the function body. This behavior is observed in other languages like Rust.

Rust example:
image

I suspect the problem arises because the current implementation only includes a node for parameter_declaration, which may be causing the issue. I have noticed that in languages like Rust, a node named parameter is used, which I assume it might be more generic (?) and may be contributing to the correct highlighting behavior.

It would be beneficial to explore the possibility of implementing a similar approach for Go as well.

Thank you for your attention to this matter. Let me know if any additional information or clarification is needed.

Disambiguate string print verbs.

Currently, the only substring that gets a group is escape_sequence. Go has a collection of "verbs" you can see in the fmt package that should be highlighted as well in their own like print_verb.

It's very difficult to disambiguate placeholders in a string without syntax highlighting.
Here the escape rune is easy to find, but not the print verb.
image

`package_identifier` is missing in some cases

For the following snippet

package main

import "context"

func foo(ctx context.Context) {
	ctx := context.WithCancel(ctx)
}

the tree-sitter AST is

  package_clause:
    package_identifier:
  import_declaration:
    import_spec:
      interpreted_string_literal:
  function_declaration:
    identifier:
    parameter_list:
      parameter_declaration:
        identifier:
        qualified_type:
          package_identifier:
          type_identifier:
    block:
      short_var_declaration:
        expression_list:
          identifier:
        expression_list:
          call_expression:
            selector_expression:
              identifier:
              field_identifier:
            argument_list:
              identifier:

For the function call context.WithCancel, package_identifier is not emitted but its emitted for parameter.

I am using tree-sitter via https://github.com/emacs-tree-sitter, please let me know if you want me to test this in some other way or if you require some other info.

Have a problem with query after pulling latest changes

That query used to work and now it fails. Could somebody please take a look?

I run a command:

tree-sitter query queries/test.scm  many_table_test.go

and error is:

Query compilation failed

Caused by:
    Query error at 40:11. Impossible pattern:
              (call_expression
              ^
Query ;;query ((function_declaration name: (identifier) @test.name) (#match? @test.name "^(Test|Example)")) @test.definition
(method_declaration
  name: (field_identifier) @test.name
  (#match? @test.name "^(Test|Example)")) @test.definition

(call_expression
  function: (selector_expression
    field: (field_identifier) @test.method)
    (#match? @test.method "^Run$")
  arguments: (argument_list . (interpreted_string_literal) @test.name))
  @test.definition

;; query for list table tests
(block
(short_var_declaration
left: (expression_list
(identifier) @test.cases)
right: (expression_list
(composite_literal
(literal_value
(literal_element
(literal_value
(keyed_element
(literal_element
(identifier) @test.field.name)
(literal_element
(interpreted_string_literal) @test.name)))) @test.definition))))
(for_statement
(range_clause
left: (expression_list
(identifier) @test.case)
right: (identifier) @test.cases1
(#eq? @test.cases @test.cases1))
body: (block
(call_expression
function: (selector_expression
field: (field_identifier) @test.method)
(#match? @test.method "^Run$")
arguments: (argument_list
(selector_expression
operand: (identifier) @test.case1
(#eq? @test.case @test.case1)
field: (field_identifier) @test.field.name1
(#eq? @test.field.name @test.field.name1)))))))

;; query for map table tests
(block
(short_var_declaration
left: (expression_list
(identifier) @test.cases)
right: (expression_list
(composite_literal
(literal_value
(keyed_element
(literal_element
(interpreted_string_literal) @test.name)
(literal_element
(literal_value) @test.definition))))))
(for_statement
(range_clause
left: (expression_list
((identifier) @test.key.name)
((identifier) @test.case))
right: (identifier) @test.cases1
(#eq? @test.cases @test.cases1))
body: (block
(call_expression
function: (selector_expression
field: (field_identifier) @test.method)
(#match? @test.method "^Run$")
arguments: (argument_list
((identifier) @test.key.name1
(#eq? @test.key.name @test.key.name1)))))))

Go code package main

import (
"testing"

"github.com/stretchr/testify/assert"

)

//func TestSubtract(t *testing.T) {
// testCases := []struct {
// desc string
// a int
// b int
// want int
// }{
// {
// desc: "test one",
// a: 1,
// b: 2,
// want: 3,
// },
// {
// desc: "test two",
// a: 1,
// b: 2,
// want: 7,
// },
// }
// for _, tC := range testCases {
// t.Run(tC.desc, func(t *testing.T) {
// assert.Equal(t, tC.want, subtract(tC.a, tC.b))
// })
// }
//}

func TestAdd(t *testing.T) {
t.Run("test one", func(t *testing.T) {
assert.Equal(t, 3, add(1, 2))
})

t.Run("test two", func(t *testing.T) {
	assert.Equal(t, 5, add(1, 2))
})

variable := "string"
t.Run(variable, func(t *testing.T) {
	assert.Equal(t, 3, add(1, 2))
})

}

func add(a, b int) int {
return a + b
}

func subtract(a, b int) int {
return a - b
}

Last commit: bbaa67a
$ tree-sitter --version
tree-sitter 0.20.8

How is `type_conversion_expression` generated?

I was playing with the go parser but found out that type_conversion_expression node is not properly generated.

According to tour of go, the type conversion is written like T(a). The grammar.json seems to agree on the same format.

However, the online playground generates call_expression instead. This makes sense to me, as syntactically they are the same, but I wonder if type_conversion_expression ever gets generated.

Thanks!

T(a)
source_file [0, 0] - [1, 0]
  call_expression [0, 0] - [0, 4]
    function: identifier [0, 0] - [0, 1]
    arguments: argument_list [0, 1] - [0, 4]
      identifier [0, 2] - [0, 3]

non-declaration statements are permitted at top level

A Go source file always starts with a package declaration, but the Tree Sitter grammar for Go permits statements at top level:

x = 1

[source_file](https://tree-sitter.github.io/tree-sitter/playground#) [0, 0] - [1, 0]
  [assignment_statement](https://tree-sitter.github.io/tree-sitter/playground#) [0, 0] - [0, 5]
    left: [expression_list](https://tree-sitter.github.io/tree-sitter/playground#) [0, 0] - [0, 1]
      [identifier](https://tree-sitter.github.io/tree-sitter/playground#) [0, 0] - [0, 1]
    right: [expression_list](https://tree-sitter.github.io/tree-sitter/playground#) [0, 4] - [0, 5]
      [int_literal](https://tree-sitter.github.io/tree-sitter/playground#) [0, 4] - [0, 5]

x := <-ch

[source_file](https://tree-sitter.github.io/tree-sitter/playground#) [0, 0] - [1, 0]
  [short_var_declaration](https://tree-sitter.github.io/tree-sitter/playground#) [0, 0] - [0, 9]
    left: [expression_list](https://tree-sitter.github.io/tree-sitter/playground#) [0, 0] - [0, 1]
      [identifier](https://tree-sitter.github.io/tree-sitter/playground#) [0, 0] - [0, 1]
    right: [expression_list](https://tree-sitter.github.io/tree-sitter/playground#) [0, 5] - [0, 9]
      [unary_expression](https://tree-sitter.github.io/tree-sitter/playground#) [0, 5] - [0, 9]
        operand: [identifier](https://tree-sitter.github.io/tree-sitter/playground#) [0, 7] - [0, 9]

The cause is this production:

tree-sitter-go/grammar.js

Lines 105 to 108 in 07d7228

source_file: $ => repeat(choice(
seq($._statement, terminator),
seq($._top_level_declaration, optional(terminator)),
)),

The fix is to remove the reference to _statement here and to add _declaration (var/const/type) to the choices for _top_level_declaration:

tree-sitter-go/grammar.js

Lines 110 to 115 in 07d7228

_top_level_declaration: $ => choice(
$.package_clause,
$.function_declaration,
$.method_declaration,
$.import_declaration
),

I wonder whether this was done intentionally because some tools want to process a chunk of statements instead of a complete file.

How can i get the params with type

I want get function name,param name param type , currently I write this .it just work with function params with builtin type. if use a package.function type that doesn't work or pointer type. I can add (pointer_type) (package_type) . Looks like I have to write multiple expressions? I'm not very familiar with sexpr. Thanks

(function_declaration
  (identifier) @func.name
  (parameter_list
      (parameter_declaration
        (identifier) @param.name
        ("," @param.separator (_))*
        (type_identifier) @param.type)))

Incorrect parsing of function parameters and return values

Description

The parser fails to identify discrete parameter declarations and combines them under a single one. This behavior only occurs in unnamed parameters and when using the language built-in type map.

To reproduce

go mod init treesitter-error

create a main.go file with contents:

// main.go
package main

func namedParameters(s []string, i int, m map[int]int, e error) {
}

func unamedParameters([]string, int, map[int]int, error) {
}

func inReturns() ([]string, int, map[int]int, error) {
	return nil, 0, nil, nil
}

func main() {
	namedParameters(nil, 0, nil, nil)
	unamedParameters(nil, 0, nil, nil)
	_, _, _, _ = inReturns()
}

I am using the latest stable version of neovim, with the latest version of the go parser. The tree looks like this:

package_clause [0, 0] - [0, 12]
  package_identifier [0, 8] - [0, 12]
function_declaration [2, 0] - [3, 1]
  name: identifier [2, 5] - [2, 20]
  parameters: parameter_list [2, 20] - [2, 63]
    parameter_declaration [2, 21] - [2, 31]
      name: identifier [2, 21] - [2, 22]
      type: slice_type [2, 23] - [2, 31]
        element: type_identifier [2, 25] - [2, 31]
    parameter_declaration [2, 33] - [2, 38]
      name: identifier [2, 33] - [2, 34]
      type: type_identifier [2, 35] - [2, 38]
    parameter_declaration [2, 40] - [2, 53]
      name: identifier [2, 40] - [2, 41]
      type: map_type [2, 42] - [2, 53]
        key: type_identifier [2, 46] - [2, 49]
        value: type_identifier [2, 50] - [2, 53]
    parameter_declaration [2, 55] - [2, 62]
      name: identifier [2, 55] - [2, 56]
      type: type_identifier [2, 57] - [2, 62]
  body: block [2, 64] - [3, 1]
function_declaration [5, 0] - [6, 1]
  name: identifier [5, 5] - [5, 21]
  parameters: parameter_list [5, 21] - [5, 56]
    parameter_declaration [5, 22] - [5, 30]
      type: slice_type [5, 22] - [5, 30]
        element: type_identifier [5, 24] - [5, 30]
    parameter_declaration [5, 32] - [5, 48]                             // NOTE THE ERROR HERE
      name: identifier [5, 32] - [5, 35]
      name: identifier [5, 37] - [5, 40]
      type: array_type [5, 40] - [5, 48]
        length: identifier [5, 41] - [5, 44]
        element: type_identifier [5, 45] - [5, 48]
    parameter_declaration [5, 50] - [5, 55]
      type: type_identifier [5, 50] - [5, 55]
  body: block [5, 57] - [6, 1]
function_declaration [8, 0] - [10, 1]
  name: identifier [8, 5] - [8, 14]
  parameters: parameter_list [8, 14] - [8, 16]
  result: parameter_list [8, 17] - [8, 52]
    parameter_declaration [8, 18] - [8, 26]
      type: slice_type [8, 18] - [8, 26]
        element: type_identifier [8, 20] - [8, 26]
    parameter_declaration [8, 28] - [8, 44]                            // NOTE THE ERROR HERE
      name: identifier [8, 28] - [8, 31]
      name: identifier [8, 33] - [8, 36]
      type: array_type [8, 36] - [8, 44]
        length: identifier [8, 37] - [8, 40]
        element: type_identifier [8, 41] - [8, 44]
    parameter_declaration [8, 46] - [8, 51]
      type: type_identifier [8, 46] - [8, 51]
  body: block [8, 53] - [10, 1]
    return_statement [9, 1] - [9, 24]
      expression_list [9, 8] - [9, 24]
        nil [9, 8] - [9, 11]
        int_literal [9, 13] - [9, 14]
        nil [9, 16] - [9, 19]
        nil [9, 21] - [9, 24]
function_declaration [12, 0] - [16, 1]
  name: identifier [12, 5] - [12, 9]
  parameters: parameter_list [12, 9] - [12, 11]
  body: block [12, 12] - [16, 1]
    expression_statement [13, 1] - [13, 34]
      call_expression [13, 1] - [13, 34]
        function: identifier [13, 1] - [13, 16]
        arguments: argument_list [13, 16] - [13, 34]
          nil [13, 17] - [13, 20]
          int_literal [13, 22] - [13, 23]
          nil [13, 25] - [13, 28]
          nil [13, 30] - [13, 33]
    expression_statement [14, 1] - [14, 35]
      call_expression [14, 1] - [14, 35]
        function: identifier [14, 1] - [14, 17]
        arguments: argument_list [14, 17] - [14, 35]
          nil [14, 18] - [14, 21]
          int_literal [14, 23] - [14, 24]
          nil [14, 26] - [14, 29]
          nil [14, 31] - [14, 34]
    assignment_statement [15, 1] - [15, 25]
      left: expression_list [15, 1] - [15, 11]
        identifier [15, 1] - [15, 2]
        identifier [15, 4] - [15, 5]
        identifier [15, 7] - [15, 8]
        identifier [15, 10] - [15, 11]
      right: expression_list [15, 14] - [15, 25]
        call_expression [15, 14] - [15, 25]
          function: identifier [15, 14] - [15, 23]
          arguments: argument_list [15, 23] - [15, 25]

Screenshot from 2023-08-10 12-25-50

"source_file" allows "BLANK" to follow "_top_level_declaration"

source_file allows BLANK to follow _top_level_declaration in src/grammar.json. This is resulting in an AST that doesn't appear to be valid. The following code parses without error or the addition of any zero-width tokens, but it does not compile:

package a package b package c package d

This is due to the optional(terminator) in the relevant section of the source_file rule in grammar.js. Is this intended?

Null character warning

Building from the latest commit results in the following warning:

warning: lib/tree-sitter-go/src/parser.c:242:18: warning: null character(s) preserved in string literal [-Wnull-character]
warning:   [anon_sym_] = "<U+0000>",

This seems to correspond with changes made in 0308e24, which added a null character. Building with cc::Build::new().warnings(false) does not hide this warning.

Parse an incomplete selector expression or call expression?

When the standard Go parser encounters an incomplete selector or call expression, such as:

func main() {
  x := foo.       // incomplete selector expression
  y := foo.bar(   // incomplete call expression
}

it will still generate a selector/call expression node, with the incomplete bits marked as incomplete. This is useful for building IDE features like autocomplete and parameter hints. Whereas when Tree-sitter encounters these cases, it adds the individual tokens as nodes, but they aren't organized as selector/call expressions.

For example, with the standard Go parser, an easy way to implement autocomplete is to just walk the AST, searching for a selector expression node that contains the current cursor position. This isn't currently doable with Tree-sitter.

Is there a way to modify Tree-sitter to behave like the standard Go parser? I was reading that one of Tree-sitter's strengths is its ability to generate useful information in the face of syntax errors. This would be a great use case.

Identifiers not working with Chinese characters

I have this Go function:

func foo中文() {
  // ...
}

I'm using latest tree-sitter & tree-sitter-go. It only grabs foo as the identifier, and puts 中文 in an error node.

It looks like tree-sitter-go specifies a letter as \p{L}, which based on my understanding means every letter in every language. Is this a bug or am I doing something wrong?

Support direct constraint elements outside `interface{...}` in type parameter lists

This code reports errors on the tree-sitter playground:

func f[A int|string, B ~int, C ~int|~string]() {
}
source_file [0, 0] - [2, 0]
  function_declaration [0, 0] - [1, 1]
    name: identifier [0, 5] - [0, 6]
    type_parameters: type_parameter_list [0, 6] - [0, 44]
      parameter_declaration [0, 7] - [0, 19]
        name: identifier [0, 7] - [0, 8]
        ERROR [0, 9] - [0, 13]
          identifier [0, 9] - [0, 12]
        type: type_identifier [0, 13] - [0, 19]
      parameter_declaration [0, 21] - [0, 27]
        name: identifier [0, 21] - [0, 22]
        ERROR [0, 23] - [0, 24]
        type: type_identifier [0, 24] - [0, 27]
      parameter_declaration [0, 29] - [0, 43]
        name: identifier [0, 29] - [0, 30]
        ERROR [0, 31] - [0, 37]
          identifier [0, 32] - [0, 35]
        type: type_identifier [0, 37] - [0, 43]
    parameters: parameter_list [0, 44] - [0, 46]
    body: block [0, 47] - [1, 1]

But it is valid according to the Go 1.18 spec: https://tip.golang.org/ref/spec#Type_constraints

If the constraint is an interface literal containing exactly one embedded type element interface{E}, in a type parameter list the enclosing interface{ … } may be omitted for convenience:

[T *P]                             // = [T interface{*P}]
[T ~int]                           // = [T interface{~int}]
[T int|string]                     // = [T interface{int|string}]

Support for go.mod files

Hi! Would it make sense to add support also for go.mod file syntax? Happy to contribute if that makes sense.

TreeSitter accepts method declarations without bodies

Go permits functions without bodies, when the function is implemented in C or assembly, but methods must always have a body. The Tree Sitter grammar for Go accepts methods without bodies:

func (T) f() 

[source_file](https://tree-sitter.github.io/tree-sitter/playground#) [0, 0] - [1, 0]
  [method_declaration](https://tree-sitter.github.io/tree-sitter/playground#) [0, 0] - [0, 12]
    receiver: [parameter_list](https://tree-sitter.github.io/tree-sitter/playground#) [0, 5] - [0, 8]
      [parameter_declaration](https://tree-sitter.github.io/tree-sitter/playground#) [0, 6] - [0, 7]
        type: [type_identifier](https://tree-sitter.github.io/tree-sitter/playground#) [0, 6] - [0, 7]
    name: [field_identifier](https://tree-sitter.github.io/tree-sitter/playground#) [0, 9] - [0, 10]
    parameters: [parameter_list](https://tree-sitter.github.io/tree-sitter/playground#) [0, 10] - [0, 12]

The fix is to remove optionality here:

field('body', optional($.block))

Investigate performance characteristics

We’ve found in production that the go parser is surprisingly slow: it can pull 1.25 MB/sec, which is no slouch, but in contrast, a language like C#, which has much more syntax, is nearly twice as fast. This isn’t a showstopper, but it might be interesting to look into exactly why this is!

Changelog?

Would it be a huge imposition to include a changelog in this repository?

For example, I noticed that version 0.20.0 added expression_statement nodes:

expression_statement: $ => $._expression,

Listing such changes conspicuously somewhere would be helpful to users.

New Release

Hi!

Could a new release (tag/version) be cut?

Some packagers seem to be using the latest tag, v0.19.1, which came out on March 3, 2021. As a result, we've had to work around certain queries not existing.

Thanks.

Problem with `parameter_list` productions

Currently, the grammar for parameter_list allows for a standalone identifier. This seems innocuous, but in cases where a list of identifiers is annotated with a type, the constructed AST associates the last identifier in the list with the type, making the previous identifiers in the list appear to be disjoint.

This example illustrates the problem:

package main

type A interface {
    B(a, b, c []byte)
}

Here we are defining an interface type called A, requiring a method B, whose parameters are a, b, c and are all considered to have type []byte (a slice type in Go). This is according to my understanding of Go Signatures in the Go language reference.

The AST we currently produce:

(source_file [0, 0] - [5, 0]
  (package_clause [0, 0] - [0, 12]
    (package_identifier [0, 8] - [0, 12]))
  (type_declaration [2, 0] - [4, 1]
    (type_spec [2, 5] - [4, 1]
      (type_identifier [2, 5] - [2, 6])
      (interface_type [2, 7] - [4, 1]
        (method_spec [3, 1] - [3, 18]
          (field_identifier [3, 1] - [3, 2])
          (parameters [3, 2] - [3, 18]
            (identifier [3, 3] - [3, 4])
            (identifier [3, 6] - [3, 7])
            (parameter_declaration [3, 9] - [3, 17]
              (identifier [3, 9] - [3, 10])
              (slice_type [3, 11] - [3, 17]
                (type_identifier [3, 13] - [3, 17])))))))))

The AST I propose we produce:

(source_file [0, 0] - [5, 0]
  (package_clause [0, 0] - [0, 12]
    (package_identifier [0, 8] - [0, 12]))
  (type_declaration [2, 0] - [4, 1]
    (type_spec [2, 5] - [4, 1]
      (type_identifier [2, 5] - [2, 6])
      (interface_type [2, 7] - [4, 1]
        (method_spec [3, 1] - [3, 18]
          (field_identifier [3, 1] - [3, 2])
          (parameters [3, 2] - [3, 18]
            (parameter_declaration [3, 9] - [3, 17]
              (identifier [3, 3] - [3, 4])
              (identifier [3, 6] - [3, 7])
              (identifier [3, 9] - [3, 10])
              (slice_type [3, 11] - [3, 17]
                (type_identifier [3, 13] - [3, 17])))))))))

The diff:

(source_file [0, 0] - [5, 0]
  (package_clause [0, 0] - [0, 12]
    (package_identifier [0, 8] - [0, 12]))
  (type_declaration [2, 0] - [4, 1]
    (type_spec [2, 5] - [4, 1]
      (type_identifier [2, 5] - [2, 6])
      (interface_type [2, 7] - [4, 1]
        (method_spec [3, 1] - [3, 18]
          (field_identifier [3, 1] - [3, 2])
          (parameters [3, 2] - [3, 18]
+           (parameter_declaration [3, 9] - [3, 17]
+             (identifier [3, 3] - [3, 4])
+             (identifier [3, 6] - [3, 7])
-            (parameter_declaration [3, 9] - [3, 17]
              (identifier [3, 9] - [3, 10])
              (slice_type [3, 11] - [3, 17]
                (type_identifier [3, 13] - [3, 17])))))))))

Better Capture Groups

[
"break"
"case"
"chan"
"const"
"continue"
"default"
"defer"
"else"
"fallthrough"
"for"
"func"
"go"
"goto"
"if"
"import"
"interface"
"map"
"package"
"range"
"return"
"select"
"struct"
"switch"
"type"
"var"
] @keyword

Currently, all keywords are aggregated into the capture group keyword, and while they ofcourse are all keywords, it now seems impossible to hightlight the keywords seperately, as they are all in the same capture group, without manually creating a after/ specification (correct me if I'm wrong).

I think it would be nicer if we could give the various keywords different highlight groups, by splititng the single keyword caputure group into seperate more specific ones.

Edit: While I think it might be nicer, after looking at other parsers apparently this is the standard way to do it.

Query: invalid structure at position 1288 for language go

Start getting error after update nvim, nvim-treesitter and go parser:

query: invalid structure at position 1288 for language go
stack traceback:
[C]: in function '_ts_parse_query'
...-d0d132f/share/nvim/runtime/lua/vim/treesitter/query.lua:277: in function 'parse_query'
...packer/start/neotest/lua/neotest/lib/treesitter/init.lua:104: in function 'normalise_query'
...packer/start/neotest/lua/neotest/lib/treesitter/init.lua:161: in function 'parse_positions_from_string'
...packer/start/neotest/lua/neotest/lib/treesitter/init.lua:207: in function 'discover_positions'
...acker/start/neotest-go/lua/spec/neotest-go/init_spec.lua:45: in function <...acker/start/neotest-go/lua/spec/neotest-go/init_spec.lua:43>

Tree-sitter Checkhealth Info nvim-treesitter: require("nvim-treesitter.health").check()

Installation ~

  • OK tree-sitter found 0.20.8 (parser generator, only needed for :TSInstallFromGrammar)
  • OK node found v16.20.1 (only needed for :TSInstallFromGrammar)
  • OK git executable found.
  • OK cc executable found. Selected from { vim.NIL, "cc", "gcc", "clang", "cl", "zig" }
    Version: Apple clang version 14.0.3 (clang-1403.0.22.14.1)
  • OK Neovim was compiled with tree-sitter runtime ABI version 14 (required >=13). Parsers must be compatible with runtime ABI.

OS Info:
{
machine = "arm64",
release = "22.5.0",
sysname = "Darwin",
version = "Darwin Kernel Version 22.5.0: Thu Jun 8 22:22:20 PDT 2023; root:xnu-8796.121.3~7/RELEASE_ARM64_T6000"
} ~

Parser/Features H L F I J

  • c ✓ ✓ ✓ ✓ ✓
  • cpp ✓ ✓ ✓ ✓ ✓
  • fish ✓ ✓ ✓ ✓ ✓
  • go ✓ ✓ ✓ ✓ ✓
  • lua ✓ ✓ ✓ ✓ ✓
  • python ✓ ✓ ✓ ✓ ✓
  • query ✓ ✓ ✓ ✓ ✓
  • rust ✓ ✓ ✓ ✓ ✓
  • typescript ✓ ✓ ✓ ✓ ✓
  • vim ✓ ✓ ✓ . ✓
  • vimdoc ✓ . . . ✓

Legend: H[ighlight], L[ocals], F[olds], I[ndents], In[j]ections
+) multiple parsers found, only one will be used
x) eQurrors found in the query, try to run :TSUpdate {lang} ~

Query

Link

;;query
((function_declaration
  name: (identifier) @test.name)
  (#match? @test.name "^(Test|Example)"))
  @test.definition

(method_declaration
  name: (field_identifier) @test.name
  (#match? @test.name "^(Test|Example)")) @test.definition

(call_expression
  function: (selector_expression
    field: (field_identifier) @test.method)
    (#match? @test.method "^Run$")
  arguments: (argument_list . (interpreted_string_literal) @test.name))
  @test.definition

;; query for list table tests
    (block
      (short_var_declaration
        left: (expression_list
          (identifier) @test.cases)
        right: (expression_list
          (composite_literal
            (literal_value
              (literal_element
                (literal_value
                  (keyed_element
                    (literal_element
                      (identifier) @test.field.name)
                    (literal_element
                      (interpreted_string_literal) @test.name)))) @test.definition))))
      (for_statement
        (range_clause
          left: (expression_list
            (identifier) @test.case)
          right: (identifier) @test.cases1
            (#eq? @test.cases @test.cases1))
        body: (block
          (call_expression
            function: (selector_expression
              field: (field_identifier) @test.method)
              (#match? @test.method "^Run$")
            arguments: (argument_list
              (selector_expression
                operand: (identifier) @test.case1
                (#eq? @test.case @test.case1)
                field: (field_identifier) @test.field.name1
                (#eq? @test.field.name @test.field.name1)))))))

;; query for map table tests 
	(block
      (short_var_declaration
        left: (expression_list
          (identifier) @test.cases)
        right: (expression_list
          (composite_literal
            (literal_value
              (keyed_element
            	(literal_element
                  (interpreted_string_literal)  @test.name)
                (literal_element
                  (literal_value)  @test.definition))))))
	  (for_statement
       (range_clause
          left: (expression_list
            ((identifier) @test.key.name)
            ((identifier) @test.case))
          right: (identifier) @test.cases1
            (#eq? @test.cases @test.cases1))
	      body: (block
            (call_expression
              function: (selector_expression
                field: (field_identifier) @test.method)
                (#match? @test.method "^Run$")
                arguments: (argument_list
                ((identifier) @test.key.name1
                (#eq? @test.key.name @test.key.name1)))))))

Steps to reproduce:

  • clone nvim plugin adapter
  • go to test file
  • run plenary test nmap <leader>t <Plug>PlenaryTestFile

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.