Go grammar for tree-sitter.
tree-sitter / tree-sitter-go Goto Github PK
View Code? Open in Web Editor NEWGo grammar for tree-sitter
License: MIT License
Go grammar for tree-sitter
License: MIT License
Go grammar for tree-sitter.
These bloat .git directories in a big, big way.
I've run into the following issue: multiples return values of functions are not always parsed correctly.
For example:
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:
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)))
))
(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)
I have made a query to get SQL syntax highlighting inside strings, the query works on interpreted_string_literal
, but not on raw_string_literal
, the injection only works if I insert a character after the first backtick.
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)
I was wondering what the state of this plugin is, as I seem to be missing a lot of highlights:
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
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 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.
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.
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.
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.
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]
Here is an example of code that should parse:
package Foo
type MyConstraint interface {
[]*MyStruct | []MyInterface
}
Hi! The npm package tree-sitter-go still being updated?
npm shows the last published date is a year ago.
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.
Apoyo para extraer bienes de engaños
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.
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.
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.
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.
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.
From semgrep/semgrep#3993
this program:
_ := os.GetEnv("Test")
without the ending newline is parsed as a type conversion instead of a regular function call.
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
^
(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)))))))
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
}
$ tree-sitter --version
tree-sitter 0.20.8
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]
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:
Lines 105 to 108 in 07d7228
The fix is to remove the reference to _statement here and to add _declaration (var/const/type) to the choices for _top_level_declaration:
Lines 110 to 115 in 07d7228
I wonder whether this was done intentionally because some tools want to process a chunk of statements instead of a complete file.
We currently expect every statement to be terminated by either a ;
or a \n
.
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)))
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
.
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]
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?
The crate is still in version 0.16.0. Can you please bump to the latest?
Go 1.13, incoming release, it has language feature called binary integer literal. It would be good to add support for this one.
Ref: golang/go#19308
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.
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.
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?
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}]
Hi! Would it make sense to add support also for go.mod
file syntax? Happy to contribute if that makes sense.
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:
Line 215 in 07d7228
Copied from helix-editor/helix#5909
In Go, the standard idiom is to begin docstrings with the name of the symbol being described, like so:
// foo performs an action
func foo() {
fmt.Println("bar")
}
// Bar is a struct
type Bar struct {
baz int
}
I propose that, similar to Goland from Jetbrains, the first term of a Go docstring be differentiated.
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!
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:
Line 487 in bbaa67a
Listing such changes conspicuously somewhere would be helpful to users.
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.
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])))))))))
tree-sitter-go/queries/highlights.scm
Lines 67 to 93 in eb306e6
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.
Pls, look at the example:
type A struct{}
func (A)Example(A)(A) {}
In atom using tree-sitter A
in function declaration is not highlited as type. If I understand right it parsed as parameter name. Function declaration go spec.
The following generic function from https://go.dev/doc/tutorial/generics cannot be parsed without error:
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
var s V
for _, v := range m {
s += v
}
return s
}
It doesn't look like Go's built-in functions are defined in tree-sitter-go.
For reference, built-in function functions seem like they're fined here in Go's source: https://github.com/golang/go/blob/master/src/builtin/builtin.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>
Installation ~
tree-sitter
found 0.20.8 (parser generator, only needed for :TSInstallFromGrammar)node
found v16.20.1 (only needed for :TSInstallFromGrammar)git
executable found.cc
executable found. Selected from { vim.NIL, "cc", "gcc", "clang", "cl", "zig" }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
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
((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:
I checkout the tree-sitter grammar repos of both javascript and scala, both of them have scanner.c
to handle automatic semicolon. But tree-sitter-go seems not to have an external scanner, how do you handle automatic semicolon insertion then?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.