Coverage for src/renaissance/integrations/tree_sitter/adapter.py: 100%

24 statements  

« prev     ^ index     » next       coverage.py v7.16.1, created at 2026-10-02 13:12 +0000

1"""AI: Adapter that parses source code with tree-sitter into the internal LST representation.""" 

2 

3from renaissance.integrations.tree_sitter.lst import LST, LSTNode 

4from renaissance.utils.ast_utils import detect_placeholder, replace_dollar 

5from tree_sitter import Language, Parser 

6 

7 

8class TreeSitterAdapter: 

9 """AI: Adapter that parses source code with tree-sitter into the internal LST representation.""" 

10 

11 def __init__(self, grammar_module): 

12 """AI: Configure a tree-sitter parser for the given language grammar.""" 

13 language = Language(grammar_module.language()) 

14 self.language = language 

15 self.parser = Parser(language) 

16 

17 def parse_code(self, source_code: str): 

18 """AI: Parse source_code with tree-sitter and return the resulting parse tree.""" 

19 return self.parser.parse(bytes(source_code, "utf8")) 

20 

21 def to_lst(self, source_code: str, tree) -> LST: 

22 """AI: Convert a tree-sitter parse tree of source_code into an LST.""" 

23 root_node = tree.root_node 

24 source_code = replace_dollar(source_code) 

25 return LST(self._convert_node(root_node, source_code, None)) 

26 

27 def _convert_node(self, node, source_code: str, parent, root=None) -> LSTNode: 

28 signature = source_code[node.start_byte : node.end_byte] 

29 is_ph, coerced_type, ph_name = detect_placeholder(signature, node.type) 

30 

31 lst_node = LSTNode( 

32 node_type=coerced_type if is_ph else node.type, 

33 properties={ 

34 "start_point": node.start_point, 

35 "end_point": node.end_point, 

36 "source_code": source_code, 

37 "name": ph_name, 

38 "is_named": node.is_named, 

39 **( 

40 { 

41 "placeholder": True, 

42 "placeholder_name": ph_name, 

43 "original_node_type": node.type, 

44 } 

45 if is_ph 

46 else {} 

47 ), 

48 }, 

49 signature=signature, 

50 offset=node.start_byte, 

51 children=[], 

52 parent=parent, 

53 root=root, 

54 ) 

55 if not root: 

56 root = lst_node 

57 

58 for child in node.children: 

59 lst_child = self._convert_node(child, source_code, lst_node, root) 

60 lst_node.add_child(lst_child) 

61 return lst_node