Coverage for src/renaissance/syntax_tree/ast_shower.py: 95%
41 statements
« prev ^ index » next coverage.py v7.16.1, created at 2026-10-02 13:12 +0000
« prev ^ index » next coverage.py v7.16.1, created at 2026-10-02 13:12 +0000
1"""AI: Render an AST node tree to the console for debugging and inspection."""
3import io
4from collections.abc import Sequence
5from io import StringIO
6from pathlib import Path
7from typing import Protocol, Self, runtime_checkable
9from termcolor import colored
11from renaissance.utils.ast_utils import display_context
14@runtime_checkable
15class Displayable(Protocol):
16 """AI: Structural protocol describing the shape required for rendering a node via ASTShower."""
18 parser_kind: str
19 semantic_kind: object
20 children: list[Self]
21 is_implicit: bool
22 show_props: bool
25class ASTShower:
26 """AI: Render an AST node tree to the console for debugging and inspection."""
28 focus: str = "NO-FOCUS-DEFINED"
30 @staticmethod
31 def show_node(node, include_properties: bool = False, display_parser_kind: bool = False) -> None:
32 """AI: Print node's rendered tree to the console."""
33 print("\n" + ASTShower.get_node(node, include_properties, display_parser_kind))
35 @staticmethod
36 def show_nodes(ast_nodes: Sequence, include_properties: bool = False, display_parser_kind: bool = False) -> None:
37 """AI: Print each node's rendered tree to the console."""
38 for ast_node in ast_nodes:
39 ASTShower.show_node(ast_node, include_properties, display_parser_kind)
41 @staticmethod
42 def get_node(ast_node: Displayable, include_properties: bool = False, display_parser_kind: bool = False) -> str:
43 """AI: Return the rendered tree text for ast_node, or an empty string if it is not Displayable."""
44 if isinstance(ast_node, Displayable):
45 buffer = io.StringIO()
46 with display_context(display_parser_kind):
47 ASTShower._process_node(buffer, "", ast_node, include_properties)
48 return buffer.getvalue()
49 return ""
51 @staticmethod
52 def store_node(filename: str, ast_node: Displayable, include_properties: bool = False, display_parser_kind: bool = False) -> None:
53 """AI: Write ast_node's rendered tree text to the file named filename."""
54 with Path(filename).open("w") as f:
55 f.write(ASTShower.get_node(ast_node, include_properties, display_parser_kind))
57 @staticmethod
58 def _process_node(output: StringIO, indent: str, node: Displayable, include_properties: bool) -> None:
59 if node.is_implicit:
60 node.indent = indent
61 node.show_props = include_properties
62 raw = str(node)
63 raw = raw.replace(ASTShower.focus, colored(ASTShower.focus, "red", attrs=["bold"]))
64 output.write(raw)
65 if node.children:
66 for child in node.children:
67 ASTShower._process_node(output, indent + " ", child, include_properties)