Coverage for src/renaissance/integrations/tree_sitter/adapter.py: 100%
24 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-15 10:34 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-15 10:34 +0000
1# Copyright (C) 2024-2026 TNO
2#
3# Licensed under the terms specified in the LICENSE file in the root directory
4# of this repository, also available at:
5# https://github.com/TNO/Renaissance.Py/blob/main/LICENSE
7"""AI: Adapter that parses source code with tree-sitter into the internal LST representation."""
9from renaissance.integrations.tree_sitter.lst import LST, LSTNode
10from renaissance.utils.ast_utils import detect_placeholder, replace_dollar
11from tree_sitter import Language, Parser
14class TreeSitterAdapter:
15 """AI: Adapter that parses source code with tree-sitter into the internal LST representation."""
17 def __init__(self, grammar_module) -> None:
18 """AI: Configure a tree-sitter parser for the given language grammar."""
19 language = Language(grammar_module.language())
20 self.language = language
21 self.parser = Parser(language)
23 def parse_code(self, source_code: str):
24 """AI: Parse source_code with tree-sitter and return the resulting parse tree."""
25 return self.parser.parse(bytes(source_code, "utf8"))
27 def to_lst(self, source_code: str, tree) -> LST:
28 """AI: Convert a tree-sitter parse tree of source_code into an LST."""
29 root_node = tree.root_node
30 source_code = replace_dollar(source_code)
31 return LST(self._convert_node(root_node, source_code, None))
33 def _convert_node(self, node, source_code: str, parent, root=None) -> LSTNode:
34 signature = source_code[node.start_byte : node.end_byte]
35 is_ph, coerced_type, ph_name = detect_placeholder(signature, node.type)
37 lst_node = LSTNode(
38 node_type=coerced_type if is_ph else node.type,
39 properties={
40 "start_point": node.start_point,
41 "end_point": node.end_point,
42 "source_code": source_code,
43 "name": ph_name,
44 "is_named": node.is_named,
45 **(
46 {
47 "placeholder": True,
48 "placeholder_name": ph_name,
49 "original_node_type": node.type,
50 }
51 if is_ph
52 else {}
53 ),
54 },
55 signature=signature,
56 offset=node.start_byte,
57 children=[],
58 parent=parent,
59 root=root,
60 )
61 if not root:
62 root = lst_node
64 for child in node.children:
65 lst_child = self._convert_node(child, source_code, lst_node, root)
66 lst_node.add_child(lst_child)
67 return lst_node