Skip to content

Commit

Permalink
feat!: update to 0.25
Browse files Browse the repository at this point in the history
  • Loading branch information
amaanq committed Jan 29, 2025
1 parent 4b2c899 commit 03a2308
Show file tree
Hide file tree
Showing 9 changed files with 1,190 additions and 130 deletions.
41 changes: 40 additions & 1 deletion language.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ import (
"unsafe"
)

const LANGUAGE_VERSION = C.TREE_SITTER_LANGUAGE_VERSION

const MIN_COMPATIBLE_LANGUAGE_VERSION = C.TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION

// An opaque object that defines how to parse a particular language. The code
// for each `Language` is generated by the Tree-sitter CLI.
// for each [Language] is generated by the Tree-sitter CLI.
type Language struct {
Inner *C.TSLanguage
}
Expand All @@ -23,16 +27,51 @@ type LanguageError struct {
version uint32
}

// The metadata associated with a language.
//
// Currently, this metadata can be used to check the [Semantic Version](https://semver.org/)
// of the language. This version information should be used to signal if a given parser might
// be incompatible with existing queries when upgrading between major versions, or minor versions
// if it's in zerover.
type LanguageMetadata struct {
MajorVersion uint8
MinorVersion uint8
PatchVersion uint8
}

func NewLanguage(ptr unsafe.Pointer) *Language {
return &Language{Inner: (*C.TSLanguage)(ptr)}
}

// Deprecated: Use [Language.AbiVersion] instead.
//
// Get the ABI version number that indicates which version of the
// Tree-sitter CLI that was used to generate this [Language].
func (l *Language) Version() uint32 {
return uint32(C.ts_language_version(l.Inner))
}

// Get the ABI version number that indicates which version of the
// Tree-sitter CLI that was used to generate this [Language].
func (l *Language) AbiVersion() uint32 {
return uint32(C.ts_language_abi_version(l.Inner))
}

// Get the metadata for this language. This information is generated by the
// CLI, and relies on the language author providing the correct metadata in
// the language's `tree-sitter.json` file.
func (l *Language) Metadata() *LanguageMetadata {
ptr := C.ts_language_metadata(l.Inner)
if ptr == nil {
return nil
}
return &LanguageMetadata{
MajorVersion: uint8(ptr.major_version),
MinorVersion: uint8(ptr.minor_version),
PatchVersion: uint8(ptr.patch_version),
}
}

// Get the number of distinct node types in this language.
func (l *Language) NodeKindCount() uint32 {
return uint32(C.ts_language_symbol_count(l.Inner))
Expand Down
20 changes: 7 additions & 13 deletions node.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,23 +285,14 @@ func (n *Node) ChildrenByFieldName(fieldName string, cursor *TreeCursor) []Node
}

// Get this node's immediate parent.
// Prefer [Node.ChildContainingDescendant]
// Prefer [Node.ChildWithDescendant]
// for iterating over this node's ancestors.
func (n *Node) Parent() *Node {
return newNode(C.ts_node_parent(n._inner))
}

// Deprecated: Prefer [Node.ChildWithDescendant] instead, this will be removed in 0.25
// Get the node's child containing `descendant`. This will not return
// the descendant if it is a direct child of `self`, for that use
// [Node.ChildWithDescendant].
func (n *Node) ChildContainingDescendant(descendant *Node) *Node {
return newNode(C.ts_node_child_containing_descendant(n._inner, descendant._inner))
}

// Get the node that contains `descendant`.
// Note that this can return `descendant` itself, unlike the deprecated function
// [Node.ChildContainingDescendant].
// Note that this can return `descendant` itself.
func (n *Node) ChildWithDescendant(descendant *Node) *Node {
return newNode(C.ts_node_child_with_descendant(n._inner, descendant._inner))
}
Expand All @@ -326,12 +317,12 @@ func (n *Node) PrevNamedSibling() *Node {
return newNode(C.ts_node_prev_named_sibling(n._inner))
}

// Get the node's first child that extends beyond the given byte offset.
// Get the node's first child that contains or starts after the given byte offset.
func (n *Node) FirstChildForByte(byteOffset uint) *Node {
return newNode(C.ts_node_first_child_for_byte(n._inner, C.uint(byteOffset)))
}

// Get the node's first named child that extends beyond the given byte offset.
// Get the node's first named child that contains or starts after the given byte offset.
func (n *Node) FirstNamedChildForByte(byteOffset uint) *Node {
return newNode(C.ts_node_first_named_child_for_byte(n._inner, C.uint(byteOffset)))
}
Expand Down Expand Up @@ -377,6 +368,9 @@ func (n *Node) Utf16Text(source []uint16) []uint16 {
}

// Create a new [TreeCursor] starting from this node.
//
// Note that the given node is considered the root of the cursor,
// and the cursor cannot walk outside this node.
func (n *Node) Walk() *TreeCursor {
return newTreeCursor(*n)
}
Expand Down
86 changes: 80 additions & 6 deletions node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,38 @@ func TestParentOfZeroWithNode(t *testing.T) {
assert.Equal(t, "function_definition", blockParent.Kind())
assert.Equal(t, "(function_definition name: (identifier) parameters: (parameters (identifier)) body: (block))", blockParent.ToSexp())

assert.Equal(t, functionDefinition, root.ChildContainingDescendant(block))
assert.Nil(t, functionDefinition.ChildContainingDescendant(block))
assert.Equal(t, functionDefinition, root.ChildWithDescendant(block))
assert.Equal(t, block, functionDefinition.ChildWithDescendant(block))
assert.Nil(t, block.ChildWithDescendant(block))
}

func TestFirstChildForOffset(t *testing.T) {
parser := NewParser()
defer parser.Close()
parser.SetLanguage(getLanguage("javascript"))
tree := parser.Parse([]byte("x10 + 100"), nil)
defer tree.Close()

sumNode := tree.RootNode().Child(0).Child(0)

assert.Equal(t, "identifier", sumNode.FirstChildForByte(0).Kind())
assert.Equal(t, "identifier", sumNode.FirstChildForByte(1).Kind())
assert.Equal(t, "+", sumNode.FirstChildForByte(3).Kind())
assert.Equal(t, "number", sumNode.FirstChildForByte(5).Kind())
}

func TestFirstNamedChildForOffset(t *testing.T) {
parser := NewParser()
defer parser.Close()
parser.SetLanguage(getLanguage("javascript"))
tree := parser.Parse([]byte("x10 + 100"), nil)
defer tree.Close()

sumNode := tree.RootNode().Child(0).Child(0)

assert.Equal(t, "identifier", sumNode.FirstNamedChildForByte(0).Kind())
assert.Equal(t, "identifier", sumNode.FirstNamedChildForByte(1).Kind())
assert.Equal(t, "number", sumNode.FirstNamedChildForByte(3).Kind())
}

func TestNodeFieldNameForChild(t *testing.T) {
Expand Down Expand Up @@ -406,10 +436,11 @@ func TestNodeNamedChild(t *testing.T) {
assert.Equal(t, tree.RootNode(), arrayNode.Parent())
assert.Nil(t, tree.RootNode().Parent())

assert.Equal(t, arrayNode, tree.RootNode().ChildContainingDescendant(nullNode))
assert.Equal(t, objectNode, arrayNode.ChildContainingDescendant(nullNode))
assert.Equal(t, pairNode, objectNode.ChildContainingDescendant(nullNode))
assert.Nil(t, pairNode.ChildContainingDescendant(nullNode))
assert.Equal(t, arrayNode, tree.RootNode().ChildWithDescendant(nullNode))
assert.Equal(t, objectNode, arrayNode.ChildWithDescendant(nullNode))
assert.Equal(t, pairNode, objectNode.ChildWithDescendant(nullNode))
assert.Equal(t, nullNode, pairNode.ChildWithDescendant(nullNode))
assert.Nil(t, nullNode.ChildWithDescendant(nullNode))
}

func TestNodeDescendantCount(t *testing.T) {
Expand Down Expand Up @@ -550,6 +581,10 @@ func TestNodeDescendantForRange(t *testing.T) {
assert.EqualValues(t, stringIndex+9, pairNode.EndByte())
assert.Equal(t, Point{6, 4}, pairNode.StartPosition())
assert.Equal(t, Point{6, 13}, pairNode.EndPosition())

// Negative test, start > end
assert.Nil(t, arrayNode.DescendantForByteRange(1, 0))
assert.Nil(t, arrayNode.DescendantForPointRange(Point{6, 8}, Point{6, 7}))
}

func TestNodeEdit(t *testing.T) {
Expand Down Expand Up @@ -624,6 +659,22 @@ func TestNodeIsExtra(t *testing.T) {
assert.True(t, commentNode.IsExtra())
}

func TestNodeIsError(t *testing.T) {
parser := NewParser()
defer parser.Close()
parser.SetLanguage(getLanguage("javascript"))
tree := parser.Parse([]byte("foo("), nil)
defer tree.Close()

rootNode := tree.RootNode()
assert.Equal(t, "program", rootNode.Kind())
assert.True(t, rootNode.HasError())

child := rootNode.Child(0)
assert.Equal(t, "ERROR", child.Kind())
assert.True(t, child.IsError())
}

func TestNodeSexp(t *testing.T) {
parser := NewParser()
defer parser.Close()
Expand Down Expand Up @@ -695,6 +746,29 @@ func TestNodeNumericSymbolsRespectSimpleAliases(t *testing.T) {
assert.Equal(t, unaryMinusNode.KindId(), binaryMinusNode.KindId())
}

func TestHiddenZeroWidthNodeWithVisibleChild(t *testing.T) {
code := `
class Foo {
std::
private:
std::string s;
};
`

parser := NewParser()
defer parser.Close()
parser.SetLanguage(getLanguage("cpp"))
tree := parser.Parse([]byte(code), nil)
defer tree.Close()
root := tree.RootNode()

classSpecifier := root.Child(0)
fieldDeclList := classSpecifier.ChildByFieldName("body")
fieldDecl := fieldDeclList.NamedChild(0)
fieldIdent := fieldDecl.ChildByFieldName("declarator")
assert.Equal(t, fieldIdent, fieldDecl.ChildWithDescendant(fieldIdent))
}

func getAllNodes(tree *Tree) []*Node {
var result []*Node
visitedChildren := false
Expand Down
Loading

0 comments on commit 03a2308

Please sign in to comment.