Coverage for src / renaissance / integrations / tree_sitter / lst.py: 91%
64 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-09-09 14:04 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-09-09 14:04 +0000
1import sys
2from typing import Any, Self, cast
4from renaissance.integrations.types import KIND_MAP, UnknownType
5from renaissance.utils.ast_utils import format_node, match_children, match_props, next_sibling, preceding_sibling
7IRRELEVANT_PROPS = {"source_code", "end_point", "start_point", "location", "type"}
8IRRELEVANT_NODE = {"comment"}
11class LSTNode:
12 def __init__(
13 self,
14 node_type: str,
15 properties: dict[str, Any],
16 signature: str,
17 offset: int = 0,
18 children: list[Self] | None = None,
19 parent: Self | None = None,
20 root: Self | None = None,
21 ):
23 self.root = root or self
24 self.parent = parent
25 self.children = [] if children is None else children
26 self.properties = properties
27 if node_type == "string" and signature.startswith("f"):
28 node_type = "FormattedString"
30 self.ast_type = KIND_MAP.get(node_type, UnknownType)
31 if self.ast_type == UnknownType:
32 print(f'"{node_type}": {node_type},')
34 self.is_implicit = True
35 self.show_props = False
36 self.indent = ""
38 self.is_statement = node_type == "Expr"
39 self.referenced_by = []
40 self.references = []
42 self.signature = signature
43 self.text = signature
44 self.filename = "unknown"
45 self.length = len(signature)
46 self.offset = offset
47 self.end_offset = self.offset + self.length
48 self.extended_end_offset = self.end_offset
50 def __eq__(self, other):
51 return (
52 isinstance(other, type(self))
53 and self.ast_type == other.ast_type
54 and match_props(self.properties, other.properties, IRRELEVANT_PROPS)
55 and match_children(self.children, other.children, IRRELEVANT_NODE)
56 )
58 def __hash__(self):
59 return hash((self.ast_type.__name__, frozenset(self.properties.items()), tuple(self.children)))
61 def match_props(self, properties) -> bool:
62 all_keys = (self.properties.keys() | properties.keys()) - IRRELEVANT_PROPS
63 return all(self.properties.get(n) == properties.get(n) for n in all_keys)
65 def match_children(self, children):
66 return all(i < len(self.children) and self.children[i] == child for i, child in enumerate(children))
68 def add_child(self, child): # LSTNode):
69 self.children.append(child)
70 child.parent = self
72 @property
73 def preceding_sibling(self) -> Self | None:
74 return preceding_sibling(self)
76 @property
77 def next_sibling(self) -> Self | None:
78 return next_sibling(self)
80 @property
81 def name(self) -> str:
82 return self.properties.get("name", "")
84 def binary_file_content(self):
85 src = cast("str", self.properties.get("source_code"))
86 return src.encode(sys.getfilesystemencoding())
88 @property
89 def node(self):
90 return self.ast_type()
92 def __repr__(self):
93 return format_node(self)
94 # raw_lines = self.signature.splitlines()
95 # properties_text = "" if not self.show_props else self.properties
96 # prefix = " " if len(raw_lines) < 2 else f"\n {self.indent}"
97 # formatted_lines = [f"{prefix}|{line}|" for line in raw_lines]
98 # return (
99 # f"{self.indent}({self.kind}, {self.name},"
100 # f" {self.filename}[{self.offset}:{self.offset + self.length}])"
101 # f"{properties_text}:{''.join(formatted_lines)}\n"
102 # )
104 def is_part_of_translation_unit(self):
105 return self.root is not None
108class LST:
109 def __init__(self, root: LSTNode):
110 self.root = root