vex-ast 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. vex_ast/__init__.py +65 -0
  2. vex_ast/ast/__init__.py +75 -0
  3. vex_ast/ast/core.py +71 -0
  4. vex_ast/ast/expressions.py +233 -0
  5. vex_ast/ast/interfaces.py +192 -0
  6. vex_ast/ast/literals.py +80 -0
  7. vex_ast/ast/navigator.py +213 -0
  8. vex_ast/ast/operators.py +136 -0
  9. vex_ast/ast/statements.py +351 -0
  10. vex_ast/ast/validators.py +114 -0
  11. vex_ast/ast/vex_nodes.py +241 -0
  12. vex_ast/parser/__init__.py +0 -0
  13. vex_ast/parser/factory.py +179 -0
  14. vex_ast/parser/interfaces.py +35 -0
  15. vex_ast/parser/python_parser.py +725 -0
  16. vex_ast/parser/strategies.py +0 -0
  17. vex_ast/registry/__init__.py +51 -0
  18. vex_ast/registry/api.py +155 -0
  19. vex_ast/registry/categories.py +136 -0
  20. vex_ast/registry/language_map.py +78 -0
  21. vex_ast/registry/registry.py +153 -0
  22. vex_ast/registry/signature.py +143 -0
  23. vex_ast/registry/simulation_behavior.py +9 -0
  24. vex_ast/registry/validation.py +44 -0
  25. vex_ast/serialization/__init__.py +37 -0
  26. vex_ast/serialization/json_deserializer.py +264 -0
  27. vex_ast/serialization/json_serializer.py +148 -0
  28. vex_ast/serialization/schema.py +471 -0
  29. vex_ast/utils/__init__.py +0 -0
  30. vex_ast/utils/errors.py +112 -0
  31. vex_ast/utils/source_location.py +39 -0
  32. vex_ast/utils/type_definitions.py +0 -0
  33. vex_ast/visitors/__init__.py +0 -0
  34. vex_ast/visitors/analyzer.py +103 -0
  35. vex_ast/visitors/base.py +130 -0
  36. vex_ast/visitors/printer.py +145 -0
  37. vex_ast/visitors/transformer.py +0 -0
  38. vex_ast-0.1.0.dist-info/METADATA +176 -0
  39. vex_ast-0.1.0.dist-info/RECORD +41 -0
  40. vex_ast-0.1.0.dist-info/WHEEL +5 -0
  41. vex_ast-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,80 @@
1
+ """Literal value nodes for the AST."""
2
+
3
+ from typing import Any, List, Optional, Union
4
+
5
+ from .interfaces import IAstNode, IVisitor, T_VisitorResult, ILiteral
6
+ from .core import Expression
7
+ from ..utils.source_location import SourceLocation
8
+
9
+ class Literal(Expression, ILiteral):
10
+ """Base class for all literal values."""
11
+
12
+ _fields = ('value',)
13
+
14
+ def __init__(self, value: Any, location: Optional[SourceLocation] = None):
15
+ super().__init__(location)
16
+ self.value = value
17
+
18
+ def get_children(self) -> List[IAstNode]:
19
+ """Literals have no children."""
20
+ return []
21
+
22
+ def get_value(self) -> Any:
23
+ """Get the literal value."""
24
+ return self.value
25
+
26
+ class NumberLiteral(Literal):
27
+ """A numeric literal (integer or float)."""
28
+
29
+ def __init__(self, value: Union[int, float], location: Optional[SourceLocation] = None):
30
+ super().__init__(value, location)
31
+
32
+ def accept(self, visitor: IVisitor[T_VisitorResult]) -> T_VisitorResult:
33
+ return visitor.visit_numberliteral(self)
34
+
35
+ def is_integer(self) -> bool:
36
+ """Check if this is an integer literal."""
37
+ return isinstance(self.value, int)
38
+
39
+ def is_float(self) -> bool:
40
+ """Check if this is a float literal."""
41
+ return isinstance(self.value, float)
42
+
43
+ class StringLiteral(Literal):
44
+ """A string literal."""
45
+
46
+ def __init__(self, value: str, location: Optional[SourceLocation] = None):
47
+ super().__init__(value, location)
48
+
49
+ def accept(self, visitor: IVisitor[T_VisitorResult]) -> T_VisitorResult:
50
+ return visitor.visit_stringliteral(self)
51
+
52
+ def get_length(self) -> int:
53
+ """Get the length of the string."""
54
+ return len(self.value)
55
+
56
+ class BooleanLiteral(Literal):
57
+ """A boolean literal (True or False)."""
58
+
59
+ def __init__(self, value: bool, location: Optional[SourceLocation] = None):
60
+ super().__init__(value, location)
61
+
62
+ def accept(self, visitor: IVisitor[T_VisitorResult]) -> T_VisitorResult:
63
+ return visitor.visit_booleanliteral(self)
64
+
65
+ def is_true(self) -> bool:
66
+ """Check if this is a True literal."""
67
+ return self.value is True
68
+
69
+ def is_false(self) -> bool:
70
+ """Check if this is a False literal."""
71
+ return self.value is False
72
+
73
+ class NoneLiteral(Literal):
74
+ """A None literal."""
75
+
76
+ def __init__(self, location: Optional[SourceLocation] = None):
77
+ super().__init__(None, location)
78
+
79
+ def accept(self, visitor: IVisitor[T_VisitorResult]) -> T_VisitorResult:
80
+ return visitor.visit_noneliteral(self)
@@ -0,0 +1,213 @@
1
+ """AST navigation utilities.
2
+
3
+ This module provides utilities for navigating the AST structure,
4
+ hiding implementation details and providing a more stable interface.
5
+ """
6
+
7
+ from typing import Dict, List, Optional, Set, Iterator, TypeVar, Generic, Type, cast, Any, Union
8
+
9
+ from .interfaces import IAstNode, IExpression, IStatement, ILiteral, IIdentifier, IFunctionCall
10
+ from .core import Program
11
+ from .expressions import (
12
+ Identifier, VariableReference, AttributeAccess,
13
+ BinaryOperation, UnaryOperation, FunctionCall
14
+ )
15
+ from .statements import (
16
+ ExpressionStatement, Assignment, FunctionDefinition,
17
+ IfStatement, WhileLoop, ForLoop, ReturnStatement
18
+ )
19
+ from .literals import NumberLiteral, StringLiteral, BooleanLiteral
20
+ from .vex_nodes import VexAPICall
21
+
22
+ T = TypeVar('T', bound=IAstNode)
23
+
24
+ class AstNavigator:
25
+ """Navigator for traversing and querying the AST."""
26
+
27
+ def __init__(self, root: IAstNode):
28
+ """Initialize with a root node."""
29
+ self.root = root
30
+
31
+ def find_all(self, node_type: Type[T]) -> List[T]:
32
+ """Find all nodes of a specific type in the AST.
33
+
34
+ Args:
35
+ node_type: The type of node to find
36
+
37
+ Returns:
38
+ List of nodes matching the type
39
+ """
40
+ result: List[T] = []
41
+ self._find_all_recursive(self.root, node_type, result)
42
+ return result
43
+
44
+ def _find_all_recursive(self, node: IAstNode, node_type: Type[T], result: List[T]) -> None:
45
+ """Recursively find all nodes of a specific type."""
46
+ if isinstance(node, node_type):
47
+ result.append(cast(T, node))
48
+
49
+ for child in node.get_children():
50
+ self._find_all_recursive(child, node_type, result)
51
+
52
+ def find_first(self, node_type: Type[T]) -> Optional[T]:
53
+ """Find the first node of a specific type in the AST.
54
+
55
+ Args:
56
+ node_type: The type of node to find
57
+
58
+ Returns:
59
+ The first node matching the type, or None if not found
60
+ """
61
+ return next(self.find_iter(node_type), None)
62
+
63
+ def find_iter(self, node_type: Type[T]) -> Iterator[T]:
64
+ """Find all nodes of a specific type as an iterator.
65
+
66
+ Args:
67
+ node_type: The type of node to find
68
+
69
+ Returns:
70
+ Iterator of nodes matching the type
71
+ """
72
+ for node in self._traverse_iter(self.root):
73
+ if isinstance(node, node_type):
74
+ yield cast(T, node)
75
+
76
+ def _traverse_iter(self, node: IAstNode) -> Iterator[IAstNode]:
77
+ """Traverse the AST in pre-order."""
78
+ yield node
79
+ for child in node.get_children():
80
+ yield from self._traverse_iter(child)
81
+
82
+ def find_parent(self, node: IAstNode) -> Optional[IAstNode]:
83
+ """Find the parent of a node.
84
+
85
+ Args:
86
+ node: The node to find the parent of
87
+
88
+ Returns:
89
+ The parent node, or None if not found or if the node is the root
90
+ """
91
+ return node.get_parent()
92
+
93
+ def find_ancestors(self, node: IAstNode) -> List[IAstNode]:
94
+ """Find all ancestors of a node.
95
+
96
+ Args:
97
+ node: The node to find ancestors of
98
+
99
+ Returns:
100
+ List of ancestor nodes, from immediate parent to root
101
+ """
102
+ result: List[IAstNode] = []
103
+ current = node.get_parent()
104
+ while current:
105
+ result.append(current)
106
+ current = current.get_parent()
107
+ return result
108
+
109
+ def find_siblings(self, node: IAstNode) -> List[IAstNode]:
110
+ """Find all siblings of a node.
111
+
112
+ Args:
113
+ node: The node to find siblings of
114
+
115
+ Returns:
116
+ List of sibling nodes, excluding the node itself
117
+ """
118
+ parent = node.get_parent()
119
+ if not parent:
120
+ return []
121
+
122
+ return [child for child in parent.get_children() if child is not node]
123
+
124
+ # Specific node type finders
125
+
126
+ def find_identifiers(self) -> List[IIdentifier]:
127
+ """Find all identifiers in the AST."""
128
+ return self.find_all(Identifier)
129
+
130
+ def find_function_calls(self) -> List[IFunctionCall]:
131
+ """Find all function calls in the AST."""
132
+ return self.find_all(FunctionCall)
133
+
134
+ def find_vex_api_calls(self) -> List[VexAPICall]:
135
+ """Find all VEX API calls in the AST."""
136
+ return self.find_all(VexAPICall)
137
+
138
+ def find_assignments(self) -> List[Assignment]:
139
+ """Find all assignments in the AST."""
140
+ return self.find_all(Assignment)
141
+
142
+ def find_function_definitions(self) -> List[FunctionDefinition]:
143
+ """Find all function definitions in the AST."""
144
+ return self.find_all(FunctionDefinition)
145
+
146
+ def find_if_statements(self) -> List[IfStatement]:
147
+ """Find all if statements in the AST."""
148
+ return self.find_all(IfStatement)
149
+
150
+ def find_loops(self) -> List[Union[WhileLoop, ForLoop]]:
151
+ """Find all loops in the AST."""
152
+ while_loops = self.find_all(WhileLoop)
153
+ for_loops = self.find_all(ForLoop)
154
+ return cast(List[Union[WhileLoop, ForLoop]], while_loops + for_loops)
155
+
156
+ def find_return_statements(self) -> List[ReturnStatement]:
157
+ """Find all return statements in the AST."""
158
+ return self.find_all(ReturnStatement)
159
+
160
+ def find_literals(self) -> List[ILiteral]:
161
+ """Find all literals in the AST."""
162
+ return cast(List[ILiteral],
163
+ self.find_all(NumberLiteral) +
164
+ self.find_all(StringLiteral) +
165
+ self.find_all(BooleanLiteral))
166
+
167
+ # Program-specific methods
168
+
169
+ def get_statements(self) -> List[IStatement]:
170
+ """Get all top-level statements in the program."""
171
+ if isinstance(self.root, Program):
172
+ return self.root.get_statements()
173
+ return []
174
+
175
+ def get_function_by_name(self, name: str) -> Optional[FunctionDefinition]:
176
+ """Find a function definition by name.
177
+
178
+ Args:
179
+ name: The function name
180
+
181
+ Returns:
182
+ The function definition, or None if not found
183
+ """
184
+ for func in self.find_function_definitions():
185
+ if func.get_name() == name:
186
+ return func
187
+ return None
188
+
189
+ def get_variable_references(self, name: str) -> List[VariableReference]:
190
+ """Find all references to a variable.
191
+
192
+ Args:
193
+ name: The variable name
194
+
195
+ Returns:
196
+ List of variable references
197
+ """
198
+ return [ref for ref in self.find_all(VariableReference) if ref.name == name]
199
+
200
+ def get_attribute_accesses(self, object_name: str) -> List[AttributeAccess]:
201
+ """Find all attribute accesses on an object.
202
+
203
+ Args:
204
+ object_name: The object name
205
+
206
+ Returns:
207
+ List of attribute accesses
208
+ """
209
+ result = []
210
+ for access in self.find_all(AttributeAccess):
211
+ if hasattr(access.object, 'name') and getattr(access.object, 'name') == object_name:
212
+ result.append(access)
213
+ return result
@@ -0,0 +1,136 @@
1
+ """Operator definitions for the AST."""
2
+
3
+ from enum import Enum, auto
4
+ from typing import Dict, Set, cast
5
+
6
+ class OperatorType(Enum):
7
+ """Categories of operators."""
8
+ BINARY = auto()
9
+ UNARY = auto()
10
+ COMPARISON = auto()
11
+ LOGICAL = auto()
12
+
13
+ class Operator(Enum):
14
+ """Enumeration of supported operators."""
15
+ # Binary Arithmetic
16
+ ADD = '+'
17
+ SUBTRACT = '-'
18
+ MULTIPLY = '*'
19
+ DIVIDE = '/'
20
+ MODULO = '%'
21
+ POWER = '**'
22
+ FLOOR_DIVIDE = '//'
23
+
24
+ # Binary Bitwise
25
+ BITWISE_AND = '&'
26
+ BITWISE_OR = '|'
27
+ BITWISE_XOR = '^'
28
+ LEFT_SHIFT = '<<'
29
+ RIGHT_SHIFT = '>>'
30
+
31
+ # Binary Comparison
32
+ EQUAL = '=='
33
+ NOT_EQUAL = '!='
34
+ LESS_THAN = '<'
35
+ LESS_EQUAL = '<='
36
+ GREATER_THAN = '>'
37
+ GREATER_EQUAL = '>='
38
+
39
+ # Binary Logical
40
+ LOGICAL_AND = 'and'
41
+ LOGICAL_OR = 'or'
42
+
43
+ # Membership/Identity
44
+ IN = 'in'
45
+ NOT_IN = 'not in'
46
+ IS = 'is'
47
+ IS_NOT = 'is not'
48
+
49
+ # Object access
50
+ MEMBER_ACCESS = '.' # Add this line
51
+
52
+ # Unary Arithmetic
53
+ UNARY_PLUS = '+ (unary)'
54
+ UNARY_MINUS = '- (unary)'
55
+
56
+ # Unary Bitwise
57
+ BITWISE_NOT = '~'
58
+
59
+ # Unary Logical
60
+ LOGICAL_NOT = 'not'
61
+
62
+ @classmethod
63
+ def get_type(cls, op: 'Operator') -> OperatorType:
64
+ """Get the type of an operator."""
65
+ if op in UNARY_OPERATORS:
66
+ return OperatorType.UNARY
67
+ if op in COMPARISON_OPERATORS:
68
+ return OperatorType.COMPARISON
69
+ if op in LOGICAL_OPERATORS:
70
+ return OperatorType.LOGICAL
71
+ return OperatorType.BINARY
72
+
73
+ # Operator sets for validation
74
+ UNARY_OPERATORS: Set[Operator] = {
75
+ Operator.UNARY_PLUS,
76
+ Operator.UNARY_MINUS,
77
+ Operator.BITWISE_NOT,
78
+ Operator.LOGICAL_NOT
79
+ }
80
+
81
+ COMPARISON_OPERATORS: Set[Operator] = {
82
+ Operator.EQUAL,
83
+ Operator.NOT_EQUAL,
84
+ Operator.LESS_THAN,
85
+ Operator.LESS_EQUAL,
86
+ Operator.GREATER_THAN,
87
+ Operator.GREATER_EQUAL,
88
+ Operator.IN,
89
+ Operator.NOT_IN,
90
+ Operator.IS,
91
+ Operator.IS_NOT
92
+ }
93
+
94
+ LOGICAL_OPERATORS: Set[Operator] = {
95
+ Operator.LOGICAL_AND,
96
+ Operator.LOGICAL_OR
97
+ }
98
+
99
+ # Mappings for parser use
100
+ PYTHON_BINARY_OP_MAP: Dict[str, Operator] = {
101
+ '+': Operator.ADD,
102
+ '-': Operator.SUBTRACT,
103
+ '*': Operator.MULTIPLY,
104
+ '/': Operator.DIVIDE,
105
+ '//': Operator.FLOOR_DIVIDE,
106
+ '%': Operator.MODULO,
107
+ '**': Operator.POWER,
108
+ '<<': Operator.LEFT_SHIFT,
109
+ '>>': Operator.RIGHT_SHIFT,
110
+ '|': Operator.BITWISE_OR,
111
+ '^': Operator.BITWISE_XOR,
112
+ '&': Operator.BITWISE_AND,
113
+ '@': Operator.MULTIPLY # Matrix multiplication, maps to regular multiply for now
114
+ }
115
+
116
+ PYTHON_BINARY_OP_MAP['.'] = Operator.MEMBER_ACCESS
117
+
118
+ PYTHON_UNARY_OP_MAP: Dict[str, Operator] = {
119
+ '+': Operator.UNARY_PLUS,
120
+ '-': Operator.UNARY_MINUS,
121
+ 'not': Operator.LOGICAL_NOT,
122
+ '~': Operator.BITWISE_NOT
123
+ }
124
+
125
+ PYTHON_COMP_OP_MAP: Dict[str, Operator] = {
126
+ '==': Operator.EQUAL,
127
+ '!=': Operator.NOT_EQUAL,
128
+ '<': Operator.LESS_THAN,
129
+ '<=': Operator.LESS_EQUAL,
130
+ '>': Operator.GREATER_THAN,
131
+ '>=': Operator.GREATER_EQUAL,
132
+ 'in': Operator.IN,
133
+ 'not in': Operator.NOT_IN,
134
+ 'is': Operator.IS,
135
+ 'is not': Operator.IS_NOT
136
+ }