Coverage for src/m6rclib/metaphor_formatters.py: 100%
30 statements
« prev ^ index » next coverage.py v7.6.1, created at 2025-01-15 09:19 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2025-01-15 09:19 +0000
1"""Functions for formatting Metaphor AST nodes and error messages."""
3import io
4from typing import List, TextIO, Dict, Final
6from .metaphor_ast_node import MetaphorASTNode, MetaphorASTNodeType
7from .metaphor_parser import MetaphorParserSyntaxError
10NODE_TYPE_MAP: Final[Dict[MetaphorASTNodeType, str]] = {
11 MetaphorASTNodeType.ACTION: "Action:",
12 MetaphorASTNodeType.CONTEXT: "Context:",
13 MetaphorASTNodeType.ROLE: "Role:"
14}
17def format_ast(node: MetaphorASTNode) -> str:
18 """Format an AST node and its children as a string.
20 Args:
21 node: The root node to format
23 Returns:
24 Formatted string representation of the AST
25 """
26 output = io.StringIO()
27 _format_node(node, 0, output)
28 return output.getvalue()
31def _format_node(node: MetaphorASTNode, depth: int, out: TextIO) -> None:
32 """Recursively format a node and its children.
34 Args:
35 node: Current node being processed
36 depth: Current tree depth
37 out: Output buffer to write to
38 """
39 if node.node_type != MetaphorASTNodeType.ROOT:
40 indent = " " * ((depth - 1) * 4)
41 if node.node_type == MetaphorASTNodeType.TEXT:
42 out.write(f"{indent}{node.value}\n")
43 return
45 keyword = NODE_TYPE_MAP.get(node.node_type, "")
46 out.write(f"{indent}{keyword}")
47 if node.value:
48 out.write(f" {node.value}")
49 out.write("\n")
51 for child in node.children:
52 _format_node(child, depth + 1, out)
55def format_errors(errors: List[MetaphorParserSyntaxError]) -> str:
56 """Format a list of syntax errors as a string.
58 Args:
59 errors: List of syntax errors to format
61 Returns:
62 Formatted error string with each error on separate lines
63 """
64 output = io.StringIO()
66 for error in errors:
67 caret = " " * (error.column - 1)
68 error_message = (
69 f"{error.message}: line {error.line}, column {error.column}, "
70 f"file {error.filename}\n{caret}|\n{caret}v\n{error.input_text}"
71 )
72 output.write(f"----------------\n{error_message}\n")
74 output.write("----------------\n")
75 return output.getvalue()