Coverage for src/renaissance/syntax_tree/ast_shower.py: 95%
41 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: Render an AST node tree to the console for debugging and inspection."""
9import io
10from collections.abc import Sequence
11from io import StringIO
12from pathlib import Path
13from typing import Protocol, Self, runtime_checkable
15from termcolor import colored
17from renaissance.utils.ast_utils import display_context
20@runtime_checkable
21class Displayable(Protocol):
22 """AI: Structural protocol describing the shape required for rendering a node via ASTShower."""
24 parser_kind: str
25 semantic_kind: object
26 children: list[Self]
27 is_implicit: bool
28 show_props: bool
31class ASTShower:
32 """AI: Render an AST node tree to the console for debugging and inspection."""
34 focus: str = "NO-FOCUS-DEFINED"
36 @staticmethod
37 def show_node(node, include_properties: bool = False, display_parser_kind: bool = False) -> None:
38 """AI: Print node's rendered tree to the console."""
39 print("\n" + ASTShower.get_node(node, include_properties, display_parser_kind))
41 @staticmethod
42 def show_nodes(ast_nodes: Sequence, include_properties: bool = False, display_parser_kind: bool = False) -> None:
43 """AI: Print each node's rendered tree to the console."""
44 for ast_node in ast_nodes:
45 ASTShower.show_node(ast_node, include_properties, display_parser_kind)
47 @staticmethod
48 def get_node(ast_node: Displayable, include_properties: bool = False, display_parser_kind: bool = False) -> str:
49 """AI: Return the rendered tree text for ast_node, or an empty string if it is not Displayable."""
50 if isinstance(ast_node, Displayable):
51 buffer = io.StringIO()
52 with display_context(display_parser_kind):
53 ASTShower._process_node(buffer, "", ast_node, include_properties)
54 return buffer.getvalue()
55 return ""
57 @staticmethod
58 def store_node(filename: str, ast_node: Displayable, include_properties: bool = False, display_parser_kind: bool = False) -> None:
59 """AI: Write ast_node's rendered tree text to the file named filename."""
60 with Path(filename).open("w") as f:
61 f.write(ASTShower.get_node(ast_node, include_properties, display_parser_kind))
63 @staticmethod
64 def _process_node(output: StringIO, indent: str, node: Displayable, include_properties: bool) -> None:
65 if node.is_implicit:
66 node.indent = indent
67 node.show_props = include_properties
68 raw = str(node)
69 raw = raw.replace(ASTShower.focus, colored(ASTShower.focus, "red", attrs=["bold"]))
70 output.write(raw)
71 if node.children:
72 for child in node.children:
73 ASTShower._process_node(output, indent + " ", child, include_properties)