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.
- vex_ast/__init__.py +65 -0
- vex_ast/ast/__init__.py +75 -0
- vex_ast/ast/core.py +71 -0
- vex_ast/ast/expressions.py +233 -0
- vex_ast/ast/interfaces.py +192 -0
- vex_ast/ast/literals.py +80 -0
- vex_ast/ast/navigator.py +213 -0
- vex_ast/ast/operators.py +136 -0
- vex_ast/ast/statements.py +351 -0
- vex_ast/ast/validators.py +114 -0
- vex_ast/ast/vex_nodes.py +241 -0
- vex_ast/parser/__init__.py +0 -0
- vex_ast/parser/factory.py +179 -0
- vex_ast/parser/interfaces.py +35 -0
- vex_ast/parser/python_parser.py +725 -0
- vex_ast/parser/strategies.py +0 -0
- vex_ast/registry/__init__.py +51 -0
- vex_ast/registry/api.py +155 -0
- vex_ast/registry/categories.py +136 -0
- vex_ast/registry/language_map.py +78 -0
- vex_ast/registry/registry.py +153 -0
- vex_ast/registry/signature.py +143 -0
- vex_ast/registry/simulation_behavior.py +9 -0
- vex_ast/registry/validation.py +44 -0
- vex_ast/serialization/__init__.py +37 -0
- vex_ast/serialization/json_deserializer.py +264 -0
- vex_ast/serialization/json_serializer.py +148 -0
- vex_ast/serialization/schema.py +471 -0
- vex_ast/utils/__init__.py +0 -0
- vex_ast/utils/errors.py +112 -0
- vex_ast/utils/source_location.py +39 -0
- vex_ast/utils/type_definitions.py +0 -0
- vex_ast/visitors/__init__.py +0 -0
- vex_ast/visitors/analyzer.py +103 -0
- vex_ast/visitors/base.py +130 -0
- vex_ast/visitors/printer.py +145 -0
- vex_ast/visitors/transformer.py +0 -0
- vex_ast-0.1.0.dist-info/METADATA +176 -0
- vex_ast-0.1.0.dist-info/RECORD +41 -0
- vex_ast-0.1.0.dist-info/WHEEL +5 -0
- vex_ast-0.1.0.dist-info/top_level.txt +1 -0
vex_ast/ast/literals.py
ADDED
@@ -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)
|
vex_ast/ast/navigator.py
ADDED
@@ -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
|
vex_ast/ast/operators.py
ADDED
@@ -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
|
+
}
|