Skip to content

Commit

Permalink
Add Node.{children_by_field_id,children_by_field_name}
Browse files Browse the repository at this point in the history
This returns an iterator over multiple nodes for the specified field.
  • Loading branch information
andreypopp committed Mar 23, 2021
1 parent 71b8381 commit 823ad50
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 0 deletions.
19 changes: 19 additions & 0 deletions tests/test_tree_sitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,25 @@ def test_child_by_field_id(self):
fn_node.child_by_field_name("name"),
)

def test_children_by_field_id(self):
parser = Parser()
parser.set_language(JAVASCRIPT)
tree = parser.parse(b"<div a={1} b={2} />")
jsx_node = tree.root_node.children[0].children[0]
attribute_field = PYTHON.field_id_for_name("attribute")

attributes = jsx_node.children_by_field_id(attribute_field)
self.assertEqual([a.type for a in attributes], ["jsx_attribute", "jsx_attribute"])

def test_children_by_field_name(self):
parser = Parser()
parser.set_language(JAVASCRIPT)
tree = parser.parse(b"<div a={1} b={2} />")
jsx_node = tree.root_node.children[0].children[0]

attributes = jsx_node.children_by_field_name("attribute")
self.assertEqual([a.type for a in attributes], ["jsx_attribute", "jsx_attribute"])

def test_children(self):
parser = Parser()
parser.set_language(PYTHON)
Expand Down
53 changes: 53 additions & 0 deletions tree_sitter/binding.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,45 @@ static PyObject *node_child_by_field_name(Node *self, PyObject *args) {
return node_new_internal(child, self->tree);
}

static PyObject *node_children_by_field_id_internal(Node *self, TSFieldId field_id) {
PyObject *result = PyList_New(0);
TSTreeCursor cursor = ts_tree_cursor_new(self->node);

int ok = ts_tree_cursor_goto_first_child(&cursor);
while (ok) {
if (ts_tree_cursor_current_field_id(&cursor) == field_id) {
TSNode tsnode = ts_tree_cursor_current_node(&cursor);
PyObject *node = node_new_internal(tsnode, self->tree);
PyList_Append(result, node);
Py_XDECREF(node);
}
ok = ts_tree_cursor_goto_next_sibling(&cursor);
}

return result;
}

static PyObject *node_children_by_field_id(Node *self, PyObject *args) {
TSFieldId field_id;
if (!PyArg_ParseTuple(args, "H", &field_id)) {
return NULL;
}

return node_children_by_field_id_internal(self, field_id);
}

static PyObject *node_children_by_field_name(Node *self, PyObject *args) {
char *name;
Py_ssize_t length;
if (!PyArg_ParseTuple(args, "s#", &name, &length)) {
return NULL;
}

const TSLanguage *lang = ts_tree_language(((Tree*)self->tree)->tree);
TSFieldId field_id = ts_language_field_id_for_name(lang, name, length);
return node_children_by_field_id_internal(self, field_id);
}

static PyObject *node_get_type(Node *self, void *payload) {
return PyUnicode_FromString(ts_node_type(self->node));
}
Expand Down Expand Up @@ -274,6 +313,20 @@ static PyMethodDef node_methods[] = {
.ml_doc = "child_by_field_name(name)\n--\n\n\
Get child for the given field name.",
},
{
.ml_name = "children_by_field_id",
.ml_meth = (PyCFunction)node_children_by_field_id,
.ml_flags = METH_VARARGS,
.ml_doc = "children_by_field_id(id)\n--\n\n\
Get iterator over children for the given field id.",
},
{
.ml_name = "children_by_field_name",
.ml_meth = (PyCFunction)node_children_by_field_name,
.ml_flags = METH_VARARGS,
.ml_doc = "children_by_field_name(name)\n--\n\n\
Get iterator over children for the given field name.",
},
{NULL},
};

Expand Down

0 comments on commit 823ad50

Please sign in to comment.