/* Tree-sitter integration for GNU Emacs. Copyright (C) 2021 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see . */ #include #include #include #include #include #include #include #include #include "buffer.h" #include "coding.h" #include "tree_sitter.h" /* parser.h defines a macro ADVANCE that conflicts with alloc.c. */ #include Lisp_Object make_ts_parser (struct buffer *buffer, TSParser *parser, TSTree *tree) { struct Lisp_TS_Parser *lisp_parser = ALLOCATE_PLAIN_PSEUDOVECTOR (struct Lisp_TS_Parser, PVEC_TS_PARSER); lisp_parser->buffer = buffer; lisp_parser->parser = parser; lisp_parser->tree = tree; // TODO TSInput. return make_lisp_ptr (lisp_parser, Lisp_Vectorlike); } Lisp_Object make_ts_node (Lisp_Object parser, TSNode node) { struct Lisp_TS_Node *lisp_node = ALLOCATE_PSEUDOVECTOR (struct Lisp_TS_Node, parser, PVEC_TS_NODE); lisp_node->parser = parser; lisp_node->node = node; return make_lisp_ptr (lisp_node, Lisp_Vectorlike); } /* Tree-sitter parser. */ DEFUN ("tree-sitter-parse", Ftree_sitter_parse, Stree_sitter_parse, 2, 2, 0, doc: /* Parse STRING and return a parser object. LANGUAGE should be the language provided by a tree-sitter language dynamic module. */) (Lisp_Object string, Lisp_Object language) { CHECK_STRING (string); /* LANGUAGE is a USER_PTR that contains the pointer to a TSLanguage struct. */ TSParser *parser = ts_parser_new (); TSLanguage *lang = (XUSER_PTR (language)->p); ts_parser_set_language (parser, lang); TSTree *tree = ts_parser_parse_string (parser, NULL, SSDATA (string), strlen (SSDATA (string))); /* See comment for ts_parser_parse in tree_sitter/api.h for possible reasons for a failure. */ if (tree == NULL) signal_error ("Failed to parse STRING", string); TSNode root_node = ts_tree_root_node (tree); Lisp_Object lisp_parser = make_ts_parser (NULL, parser, tree); Lisp_Object lisp_node = make_ts_node (lisp_parser, root_node); return lisp_node; } DEFUN ("tree-sitter-node-string", Ftree_sitter_node_string, Stree_sitter_node_string, 1, 1, 0, doc: /* Return the string representation of NODE. */) (Lisp_Object node) { TSNode ts_node = XTS_NODE (node)->node; char *string = ts_node_string(ts_node); return make_string(string, strlen (string)); } DEFUN ("tree-sitter-node-parent", Ftree_sitter_node_parent, Stree_sitter_node_parent, 1, 1, 0, doc: /* Return the immediate parent of NODE. Return nil if couldn't find any. */) (Lisp_Object node) { TSNode ts_node = XTS_NODE (node)->node; TSNode parent = ts_node_parent(ts_node); if (ts_node_is_null(parent)) return Qnil; return make_ts_node(XTS_NODE (node)->parser, parent); } DEFUN ("tree-sitter-node-child", Ftree_sitter_node_child, Stree_sitter_node_child, 2, 2, 0, doc: /* Return the Nth child of NODE. Return nil if couldn't find any. */) (Lisp_Object node, Lisp_Object n) { CHECK_INTEGER (n); EMACS_INT idx = XFIXNUM (n); TSNode ts_node = XTS_NODE (node)->node; // FIXME: Is this cast ok? TSNode child = ts_node_child(ts_node, (uint32_t) idx); if (ts_node_is_null(child)) return Qnil; return make_ts_node(XTS_NODE (node)->parser, child); } /* Initialize the tree-sitter routines. */ void syms_of_tree_sitter (void) { defsubr (&Stree_sitter_parse); defsubr (&Stree_sitter_node_string); defsubr (&Stree_sitter_node_parent); defsubr (&Stree_sitter_node_child); }