From c8d0fa76ddb9fa6c259e141526d08ad8f670faba Mon Sep 17 00:00:00 2001 From: Giuliano Macedo Date: Sat, 18 Oct 2025 16:05:45 -0300 Subject: [PATCH 1/2] feat: checking for errors when calling `ts_parser_set_language` --- bindings.go | 11 ++++++++--- bindings_test.go | 34 +++++++++++++++++----------------- markdown/binding.go | 9 +++++++-- predicates_test.go | 2 +- 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/bindings.go b/bindings.go index 5c3cca3a..f6700576 100644 --- a/bindings.go +++ b/bindings.go @@ -33,7 +33,9 @@ func Parse(content []byte, lang *Language) *Node { // returns root node func ParseCtx(ctx context.Context, content []byte, lang *Language) (*Node, error) { p := NewParser() - p.SetLanguage(lang) + if err := p.SetLanguage(lang); err != nil { + return nil, fmt.Errorf("error while setting language: %v", err) + } tree, err := p.ParseCtx(ctx, nil, content) if err != nil { return nil, err @@ -59,9 +61,12 @@ func NewParser() *Parser { } // SetLanguage assignes Language to a parser -func (p *Parser) SetLanguage(lang *Language) { +func (p *Parser) SetLanguage(lang *Language) error { cLang := (*C.struct_TSLanguage)(lang.ptr) - C.ts_parser_set_language(p.c, cLang) + if !C.ts_parser_set_language(p.c, cLang) { + return fmt.Errorf("could not set the language, make sure the language version is compatible with current tree sitter") + } + return nil } // ReadFunc is a function to retrieve a chunk of text at a given byte offset and (row, column) position diff --git a/bindings_test.go b/bindings_test.go index c9f96079..ef353e69 100644 --- a/bindings_test.go +++ b/bindings_test.go @@ -64,7 +64,7 @@ func TestTree(t *testing.T) { parser := NewParser() parser.Debug() - parser.SetLanguage(getTestGrammar()) + assert.Nil(t, parser.SetLanguage(getTestGrammar())) tree, err := parser.ParseCtx(context.Background(), nil, []byte("1 + 2")) assert.NoError(err) n := tree.RootNode() @@ -123,7 +123,7 @@ func TestErrorNodes(t *testing.T) { parser := NewParser() parser.Debug() - parser.SetLanguage(getTestGrammar()) + assert.Nil(t, parser.SetLanguage(getTestGrammar())) tree, err := parser.ParseCtx(context.Background(), nil, []byte("1 + a")) assert.NoError(err) n := tree.RootNode() @@ -176,7 +176,7 @@ func TestGC(t *testing.T) { parser := NewParser() - parser.SetLanguage(getTestGrammar()) + assert.Nil(t, parser.SetLanguage(getTestGrammar())) tree, err := parser.ParseCtx(context.Background(), nil, []byte("1 + 2")) assert.NoError(err) n := tree.RootNode() @@ -206,7 +206,7 @@ func TestOperationLimitParsing(t *testing.T) { parser := NewParser() parser.SetOperationLimit(10) - parser.SetLanguage(getTestGrammar()) + assert.Nil(t, parser.SetLanguage(getTestGrammar())) items := []string{} for i := 0; i < 100; i++ { items = append(items, strconv.Itoa(i)) @@ -223,7 +223,7 @@ func TestContextCancellationParsing(t *testing.T) { defer cancel() parser := NewParser() - parser.SetLanguage(getTestGrammar()) + assert.Nil(t, parser.SetLanguage(getTestGrammar())) items := []string{} // the content needs to be big so that we have enough time to cancel for i := 0; i < 10000; i++ { @@ -267,7 +267,7 @@ func TestIncludedRanges(t *testing.T) { code := "1 + 2\n//3 + 5" parser := NewParser() - parser.SetLanguage(getTestGrammar()) + assert.Nil(t, parser.SetLanguage(getTestGrammar())) mainTree, err := parser.ParseCtx(context.Background(), nil, []byte(code)) assert.NoError(err) assert.Equal( @@ -301,7 +301,7 @@ func TestSameNode(t *testing.T) { assert := assert.New(t) parser := NewParser() - parser.SetLanguage(getTestGrammar()) + assert.Nil(t, parser.SetLanguage(getTestGrammar())) tree, err := parser.ParseCtx(context.Background(), nil, []byte("1 + 2")) assert.NoError(err) @@ -332,7 +332,7 @@ func TestQuery(t *testing.T) { // test match only parser := NewParser() - parser.SetLanguage(getTestGrammar()) + assert.Nil(t, parser.SetLanguage(getTestGrammar())) tree, err := parser.ParseCtx(context.Background(), nil, []byte(js)) assert.NoError(t, err) root := tree.RootNode() @@ -360,7 +360,7 @@ func testCaptures(t *testing.T, body, sq string, expected []string) { assert := assert.New(t) parser := NewParser() - parser.SetLanguage(getTestGrammar()) + assert.Nil(t, parser.SetLanguage(getTestGrammar())) tree, err := parser.ParseCtx(context.Background(), nil, []byte(body)) assert.NoError(err) root := tree.RootNode() @@ -476,7 +476,7 @@ func TestTreeCursor(t *testing.T) { func TestLeakParse(t *testing.T) { ctx := context.Background() parser := NewParser() - parser.SetLanguage(getTestGrammar()) + assert.Nil(t, parser.SetLanguage(getTestGrammar())) for i := 0; i < 100000; i++ { _, _ = parser.ParseCtx(ctx, nil, []byte("1 + 2")) @@ -494,7 +494,7 @@ func TestLeakParse(t *testing.T) { func TestLeakRootNode(t *testing.T) { ctx := context.Background() parser := NewParser() - parser.SetLanguage(getTestGrammar()) + assert.Nil(t, parser.SetLanguage(getTestGrammar())) for i := 0; i < 100000; i++ { tree, err := parser.ParseCtx(ctx, nil, []byte("1 + 2")) @@ -515,7 +515,7 @@ func TestParseInput(t *testing.T) { assert := assert.New(t) parser := NewParser() - parser.SetLanguage(getTestGrammar()) + assert.Nil(t, parser.SetLanguage(getTestGrammar())) // empty input input := Input{ @@ -570,7 +570,7 @@ func TestParseInput(t *testing.T) { func TestLeakParseInput(t *testing.T) { ctx := context.Background() parser := NewParser() - parser.SetLanguage(getTestGrammar()) + assert.Nil(t, parser.SetLanguage(getTestGrammar())) inputData := []byte("1 + 2") input := Input{ @@ -602,7 +602,7 @@ func TestCursorKeepsQuery(t *testing.T) { source := bytes.Repeat([]byte("1 + 1"), 10000) parser := NewParser() - parser.SetLanguage(getTestGrammar()) + assert.Nil(t, parser.SetLanguage(getTestGrammar())) tree := parser.Parse(nil, source) root := tree.RootNode() @@ -630,7 +630,7 @@ func TestCursorKeepsQuery(t *testing.T) { func BenchmarkParse(b *testing.B) { ctx := context.Background() parser := NewParser() - parser.SetLanguage(getTestGrammar()) + assert.Nil(b, parser.SetLanguage(getTestGrammar())) inputData := []byte("1 + 2") b.ResetTimer() @@ -646,7 +646,7 @@ func BenchmarkParseCancellable(b *testing.B) { defer cancel() parser := NewParser() - parser.SetLanguage(getTestGrammar()) + assert.Nil(b, parser.SetLanguage(getTestGrammar())) inputData := []byte("1 + 2") b.ResetTimer() @@ -659,7 +659,7 @@ func BenchmarkParseCancellable(b *testing.B) { func BenchmarkParseInput(b *testing.B) { ctx := context.Background() parser := NewParser() - parser.SetLanguage(getTestGrammar()) + assert.Nil(b, parser.SetLanguage(getTestGrammar())) inputData := []byte("1 + 2") input := Input{ diff --git a/markdown/binding.go b/markdown/binding.go index 5af428db..1862558f 100644 --- a/markdown/binding.go +++ b/markdown/binding.go @@ -2,6 +2,7 @@ package markdown import ( "context" + "fmt" sitter "github.com/smacker/go-tree-sitter" tree_sitter_markdown "github.com/smacker/go-tree-sitter/markdown/tree-sitter-markdown" @@ -82,7 +83,9 @@ type Node struct { func ParseCtx(ctx context.Context, oldTree *MarkdownTree, content []byte) (*MarkdownTree, error) { p := sitter.NewParser() - p.SetLanguage(tree_sitter_markdown.GetLanguage()) + if err := p.SetLanguage(tree_sitter_markdown.GetLanguage()); err != nil { + return nil, fmt.Errorf("could not set markdown language: %v", err) + } var old *sitter.Tree if oldTree != nil { @@ -99,7 +102,9 @@ func ParseCtx(ctx context.Context, oldTree *MarkdownTree, content []byte) (*Mark inlineIndices: map[uintptr]int{}, } - p.SetLanguage(tree_sitter_markdown_inline.GetLanguage()) + if err := p.SetLanguage(tree_sitter_markdown_inline.GetLanguage()); err != nil { + return nil, fmt.Errorf("could not set markdown inline language: %v", err) + } q, err := sitter.NewQuery([]byte(`(inline) @inline`), tree_sitter_markdown.GetLanguage()) if err != nil { diff --git a/predicates_test.go b/predicates_test.go index c985b677..020a1501 100644 --- a/predicates_test.go +++ b/predicates_test.go @@ -380,7 +380,7 @@ func TestFilterPredicates(t *testing.T) { } parser := NewParser() - parser.SetLanguage(getTestGrammar()) + assert.Nil(t, parser.SetLanguage(getTestGrammar())) for testNum, testCase := range testCases { tree := parser.Parse(nil, []byte(testCase.input)) From f5a1443c0d8fa7bdf3f5bcec31eece6a046df0c9 Mon Sep 17 00:00:00 2001 From: Giuliano Macedo Date: Sat, 18 Oct 2025 16:21:58 -0300 Subject: [PATCH 2/2] chores: update examples and readme because of SetLanguage change --- README.md | 2 +- _examples/main.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ff3be65b..bd035625 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ import ( ) parser := sitter.NewParser() -parser.SetLanguage(javascript.GetLanguage()) +_ = parser.SetLanguage(javascript.GetLanguage()) ``` Parse some code: diff --git a/_examples/main.go b/_examples/main.go index 13503a22..1c8d0603 100644 --- a/_examples/main.go +++ b/_examples/main.go @@ -11,7 +11,7 @@ func main() { input := []byte("function hello() { console.log('hello') }; function goodbye(){}") parser := sitter.NewParser() - parser.SetLanguage(javascript.GetLanguage()) + _ = parser.SetLanguage(javascript.GetLanguage()) tree := parser.Parse(nil, input)