Coverage for src/renaissance/integrations/python/ast/ast_node.py: 83%
46 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"""Implementation that patches the native ast using 'traits' mechanism.
9Requires minimum amount of code to make the matcher work.
10"""
12import ast
13from typing import Any
15from renaissance.integrations.python.ast.kinds import PYTHON_KIND_MAP
16from renaissance.syntax_tree.semantic_kind import SemanticKind
19class ASTExtension:
20 """AI: Static trait methods patched onto the stdlib ast.AST class to satisfy the node protocol."""
22 @staticmethod
23 def load_from_ast(text, file) -> ast.Module:
24 """AI: Parse text as Python source (attributed to file) into a native ast.AST tree."""
25 root = ast.parse(text, file)
26 return root
28 @staticmethod
29 @property
30 def ast_node(self) -> ast.AST:
31 """AI: Return this node itself."""
32 return self
34 @staticmethod
35 @property
36 def parser_kind(self) -> str:
37 """AI: Return this node's ast class name as its parser kind."""
38 return type(self).__name__
40 @staticmethod
41 @property
42 def semantic_kind(self) -> SemanticKind:
43 """AI: Return the semantic kind mapped from this node's ast class name."""
44 return PYTHON_KIND_MAP.get(type(self).__name__, SemanticKind.NODE)
46 @staticmethod
47 @property
48 def ast_properties(self) -> dict[str, Any]:
49 """AI: Return this node's non-AST fields as a name-to-value dict."""
50 return {field: getattr(self, field) for field in self._fields if not isinstance(getattr(self, field), ast.AST)}
52 @staticmethod
53 @property
54 def ast_children(self) -> list[ast.AST]:
55 """AI: Return this node's direct child AST nodes, including those held in list fields."""
56 children = [getattr(self, field) for field in self._fields if isinstance(getattr(self, field), (ast.AST))]
57 [children.extend(getattr(self, field)) for field in self._fields if isinstance(getattr(self, field), (list))]
58 return children
60 @staticmethod
61 @property
62 def ast_signature(self) -> str:
63 """AI: Return the unparsed source text of this node."""
64 return ast.unparse(self)
66 @staticmethod
67 @property
68 def ast_name(self) -> str:
69 """AI: Return this node's identifying name, derived from its specific ast node type."""
70 if isinstance(self, ast.arg):
71 signature = self.arg
72 elif isinstance(self, ast.Name):
73 signature = self.id
74 elif isinstance(self, ast.Expr) and isinstance(self.value, ast.Name):
75 signature = self.value.id
76 else:
77 signature = str(self)
78 return signature