vex-ast 0.2.4__py3-none-any.whl → 0.2.6__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/README.md +101 -51
- vex_ast/READMEAPI.md +133 -318
- vex_ast/__init__.py +81 -72
- vex_ast/ast/README.md +87 -87
- vex_ast/ast/__init__.py +74 -74
- vex_ast/ast/core.py +71 -71
- vex_ast/ast/expressions.py +276 -276
- vex_ast/ast/interfaces.py +208 -208
- vex_ast/ast/literals.py +80 -80
- vex_ast/ast/navigator.py +225 -225
- vex_ast/ast/operators.py +135 -135
- vex_ast/ast/statements.py +351 -351
- vex_ast/ast/validators.py +121 -120
- vex_ast/ast/vex_nodes.py +279 -279
- vex_ast/parser/README.md +47 -47
- vex_ast/parser/__init__.py +26 -26
- vex_ast/parser/factory.py +190 -190
- vex_ast/parser/interfaces.py +34 -34
- vex_ast/parser/python_parser.py +831 -786
- vex_ast/registry/README.md +107 -29
- vex_ast/registry/__init__.py +51 -51
- vex_ast/registry/api.py +190 -155
- vex_ast/registry/categories.py +179 -136
- vex_ast/registry/functions/__init__.py +10 -10
- vex_ast/registry/functions/constructors.py +71 -0
- vex_ast/registry/functions/display.py +146 -146
- vex_ast/registry/functions/drivetrain.py +163 -163
- vex_ast/registry/functions/initialize.py +31 -28
- vex_ast/registry/functions/motor.py +140 -140
- vex_ast/registry/functions/sensors.py +194 -194
- vex_ast/registry/functions/timing.py +103 -103
- vex_ast/registry/language_map.py +77 -77
- vex_ast/registry/registry.py +164 -153
- vex_ast/registry/signature.py +269 -191
- vex_ast/registry/simulation_behavior.py +8 -8
- vex_ast/registry/validation.py +43 -43
- vex_ast/serialization/__init__.py +37 -37
- vex_ast/serialization/json_deserializer.py +284 -275
- vex_ast/serialization/json_serializer.py +148 -148
- vex_ast/serialization/schema.py +492 -470
- vex_ast/types/README.md +78 -26
- vex_ast/types/__init__.py +140 -140
- vex_ast/types/base.py +83 -83
- vex_ast/types/enums.py +122 -97
- vex_ast/types/objects.py +64 -64
- vex_ast/types/primitives.py +68 -68
- vex_ast/types/type_checker.py +31 -31
- vex_ast/utils/README.md +39 -39
- vex_ast/utils/__init__.py +37 -37
- vex_ast/utils/errors.py +112 -112
- vex_ast/utils/source_location.py +38 -38
- vex_ast/utils/type_definitions.py +8 -8
- vex_ast/visitors/README.md +49 -49
- vex_ast/visitors/__init__.py +27 -27
- vex_ast/visitors/analyzer.py +102 -102
- vex_ast/visitors/base.py +133 -133
- vex_ast/visitors/printer.py +196 -146
- {vex_ast-0.2.4.dist-info → vex_ast-0.2.6.dist-info}/METADATA +206 -174
- vex_ast-0.2.6.dist-info/RECORD +64 -0
- vex_ast-0.2.4.dist-info/RECORD +0 -63
- {vex_ast-0.2.4.dist-info → vex_ast-0.2.6.dist-info}/WHEEL +0 -0
- {vex_ast-0.2.4.dist-info → vex_ast-0.2.6.dist-info}/licenses/LICENSE +0 -0
- {vex_ast-0.2.4.dist-info → vex_ast-0.2.6.dist-info}/top_level.txt +0 -0
vex_ast/utils/__init__.py
CHANGED
@@ -1,38 +1,38 @@
|
|
1
|
-
"""
|
2
|
-
Utilities package for VEX AST.
|
3
|
-
|
4
|
-
This package provides utility functions and classes for working with the AST.
|
5
|
-
"""
|
6
|
-
|
7
|
-
from .errors import (
|
8
|
-
ErrorHandler,
|
9
|
-
ErrorType,
|
10
|
-
VexSyntaxError,
|
11
|
-
VexAstError,
|
12
|
-
Error
|
13
|
-
)
|
14
|
-
from .source_location import (
|
15
|
-
SourceLocation,
|
16
|
-
)
|
17
|
-
from .type_definitions import (
|
18
|
-
NodeType,
|
19
|
-
VisitorType,
|
20
|
-
TransformerType
|
21
|
-
)
|
22
|
-
|
23
|
-
__all__ = [
|
24
|
-
# Error handling
|
25
|
-
"ErrorHandler",
|
26
|
-
"ErrorType",
|
27
|
-
"VexSyntaxError",
|
28
|
-
"VexAstError",
|
29
|
-
"Error",
|
30
|
-
|
31
|
-
# Source location
|
32
|
-
"SourceLocation",
|
33
|
-
|
34
|
-
# Type definitions
|
35
|
-
"NodeType",
|
36
|
-
"VisitorType",
|
37
|
-
"TransformerType"
|
1
|
+
"""
|
2
|
+
Utilities package for VEX AST.
|
3
|
+
|
4
|
+
This package provides utility functions and classes for working with the AST.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from .errors import (
|
8
|
+
ErrorHandler,
|
9
|
+
ErrorType,
|
10
|
+
VexSyntaxError,
|
11
|
+
VexAstError,
|
12
|
+
Error
|
13
|
+
)
|
14
|
+
from .source_location import (
|
15
|
+
SourceLocation,
|
16
|
+
)
|
17
|
+
from .type_definitions import (
|
18
|
+
NodeType,
|
19
|
+
VisitorType,
|
20
|
+
TransformerType
|
21
|
+
)
|
22
|
+
|
23
|
+
__all__ = [
|
24
|
+
# Error handling
|
25
|
+
"ErrorHandler",
|
26
|
+
"ErrorType",
|
27
|
+
"VexSyntaxError",
|
28
|
+
"VexAstError",
|
29
|
+
"Error",
|
30
|
+
|
31
|
+
# Source location
|
32
|
+
"SourceLocation",
|
33
|
+
|
34
|
+
# Type definitions
|
35
|
+
"NodeType",
|
36
|
+
"VisitorType",
|
37
|
+
"TransformerType"
|
38
38
|
]
|
vex_ast/utils/errors.py
CHANGED
@@ -1,112 +1,112 @@
|
|
1
|
-
"""Error handling framework for the VEX AST."""
|
2
|
-
|
3
|
-
import logging
|
4
|
-
from enum import Enum, auto
|
5
|
-
from typing import List, Optional, Callable, Protocol, Any, TypeVar, cast
|
6
|
-
|
7
|
-
from .source_location import SourceLocation
|
8
|
-
|
9
|
-
# Configure basic logging
|
10
|
-
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
11
|
-
logger = logging.getLogger(__name__)
|
12
|
-
|
13
|
-
class ErrorType(Enum):
|
14
|
-
"""Types of errors that can occur during AST processing."""
|
15
|
-
LEXER_ERROR = auto()
|
16
|
-
PARSER_ERROR = auto()
|
17
|
-
TYPE_ERROR = auto()
|
18
|
-
SEMANTIC_ERROR = auto()
|
19
|
-
INTERNAL_ERROR = auto()
|
20
|
-
|
21
|
-
class Error:
|
22
|
-
"""Represents a single error detected during processing."""
|
23
|
-
|
24
|
-
def __init__(self,
|
25
|
-
error_type: ErrorType,
|
26
|
-
message: str,
|
27
|
-
location: Optional[SourceLocation] = None,
|
28
|
-
suggestion: Optional[str] = None):
|
29
|
-
self.error_type = error_type
|
30
|
-
self.message = message
|
31
|
-
self.location = location
|
32
|
-
self.suggestion = suggestion
|
33
|
-
|
34
|
-
def __str__(self) -> str:
|
35
|
-
"""Format the error for display."""
|
36
|
-
loc_str = f" at {self.location}" if self.location else ""
|
37
|
-
sugg_str = f"\n Suggestion: {self.suggestion}" if self.suggestion else ""
|
38
|
-
return f"[{self.error_type.name}]{loc_str}: {self.message}{sugg_str}"
|
39
|
-
|
40
|
-
# Error handler callback protocol
|
41
|
-
T_Error = TypeVar('T_Error', bound=Error)
|
42
|
-
|
43
|
-
class ErrorObserver(Protocol[T_Error]):
|
44
|
-
"""Protocol for objects that can observe errors."""
|
45
|
-
|
46
|
-
def on_error(self, error: T_Error) -> None:
|
47
|
-
"""Handle an error notification."""
|
48
|
-
...
|
49
|
-
|
50
|
-
class ErrorHandler:
|
51
|
-
"""Manages error collection and notification."""
|
52
|
-
|
53
|
-
def __init__(self, raise_on_error: bool = True):
|
54
|
-
self._errors: List[Error] = []
|
55
|
-
self._raise_on_error = raise_on_error
|
56
|
-
self._observers: List[ErrorObserver] = []
|
57
|
-
|
58
|
-
def add_error(self,
|
59
|
-
error_type: ErrorType,
|
60
|
-
message: str,
|
61
|
-
location: Optional[SourceLocation] = None,
|
62
|
-
suggestion: Optional[str] = None) -> None:
|
63
|
-
"""Add an error to the collection."""
|
64
|
-
error = Error(error_type, message, location, suggestion)
|
65
|
-
self._errors.append(error)
|
66
|
-
logger.error(str(error))
|
67
|
-
|
68
|
-
# Notify observers
|
69
|
-
for observer in self._observers:
|
70
|
-
try:
|
71
|
-
observer.on_error(error)
|
72
|
-
except Exception as e:
|
73
|
-
logger.exception(f"Error observer failed: {e}")
|
74
|
-
|
75
|
-
if self._raise_on_error:
|
76
|
-
if error_type == ErrorType.PARSER_ERROR:
|
77
|
-
raise VexSyntaxError(message, location)
|
78
|
-
else:
|
79
|
-
raise VexAstError(str(error))
|
80
|
-
|
81
|
-
def get_errors(self) -> List[Error]:
|
82
|
-
"""Get a copy of all collected errors."""
|
83
|
-
return self._errors.copy()
|
84
|
-
|
85
|
-
def has_errors(self) -> bool:
|
86
|
-
"""Check if any errors have been collected."""
|
87
|
-
return bool(self._errors)
|
88
|
-
|
89
|
-
def clear_errors(self) -> None:
|
90
|
-
"""Clear all collected errors."""
|
91
|
-
self._errors.clear()
|
92
|
-
|
93
|
-
def add_observer(self, observer: ErrorObserver) -> None:
|
94
|
-
"""Add an observer to be notified of errors."""
|
95
|
-
if observer not in self._observers:
|
96
|
-
self._observers.append(observer)
|
97
|
-
|
98
|
-
def remove_observer(self, observer: ErrorObserver) -> None:
|
99
|
-
"""Remove an error observer."""
|
100
|
-
if observer in self._observers:
|
101
|
-
self._observers.remove(observer)
|
102
|
-
|
103
|
-
class VexAstError(Exception):
|
104
|
-
"""Base exception class for VEX AST errors."""
|
105
|
-
pass
|
106
|
-
|
107
|
-
class VexSyntaxError(VexAstError):
|
108
|
-
"""Exception raised for syntax errors during parsing."""
|
109
|
-
|
110
|
-
def __init__(self, message: str, location: Optional[SourceLocation] = None):
|
111
|
-
self.location = location
|
112
|
-
super().__init__(message)
|
1
|
+
"""Error handling framework for the VEX AST."""
|
2
|
+
|
3
|
+
import logging
|
4
|
+
from enum import Enum, auto
|
5
|
+
from typing import List, Optional, Callable, Protocol, Any, TypeVar, cast
|
6
|
+
|
7
|
+
from .source_location import SourceLocation
|
8
|
+
|
9
|
+
# Configure basic logging
|
10
|
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
11
|
+
logger = logging.getLogger(__name__)
|
12
|
+
|
13
|
+
class ErrorType(Enum):
|
14
|
+
"""Types of errors that can occur during AST processing."""
|
15
|
+
LEXER_ERROR = auto()
|
16
|
+
PARSER_ERROR = auto()
|
17
|
+
TYPE_ERROR = auto()
|
18
|
+
SEMANTIC_ERROR = auto()
|
19
|
+
INTERNAL_ERROR = auto()
|
20
|
+
|
21
|
+
class Error:
|
22
|
+
"""Represents a single error detected during processing."""
|
23
|
+
|
24
|
+
def __init__(self,
|
25
|
+
error_type: ErrorType,
|
26
|
+
message: str,
|
27
|
+
location: Optional[SourceLocation] = None,
|
28
|
+
suggestion: Optional[str] = None):
|
29
|
+
self.error_type = error_type
|
30
|
+
self.message = message
|
31
|
+
self.location = location
|
32
|
+
self.suggestion = suggestion
|
33
|
+
|
34
|
+
def __str__(self) -> str:
|
35
|
+
"""Format the error for display."""
|
36
|
+
loc_str = f" at {self.location}" if self.location else ""
|
37
|
+
sugg_str = f"\n Suggestion: {self.suggestion}" if self.suggestion else ""
|
38
|
+
return f"[{self.error_type.name}]{loc_str}: {self.message}{sugg_str}"
|
39
|
+
|
40
|
+
# Error handler callback protocol
|
41
|
+
T_Error = TypeVar('T_Error', bound=Error)
|
42
|
+
|
43
|
+
class ErrorObserver(Protocol[T_Error]):
|
44
|
+
"""Protocol for objects that can observe errors."""
|
45
|
+
|
46
|
+
def on_error(self, error: T_Error) -> None:
|
47
|
+
"""Handle an error notification."""
|
48
|
+
...
|
49
|
+
|
50
|
+
class ErrorHandler:
|
51
|
+
"""Manages error collection and notification."""
|
52
|
+
|
53
|
+
def __init__(self, raise_on_error: bool = True):
|
54
|
+
self._errors: List[Error] = []
|
55
|
+
self._raise_on_error = raise_on_error
|
56
|
+
self._observers: List[ErrorObserver] = []
|
57
|
+
|
58
|
+
def add_error(self,
|
59
|
+
error_type: ErrorType,
|
60
|
+
message: str,
|
61
|
+
location: Optional[SourceLocation] = None,
|
62
|
+
suggestion: Optional[str] = None) -> None:
|
63
|
+
"""Add an error to the collection."""
|
64
|
+
error = Error(error_type, message, location, suggestion)
|
65
|
+
self._errors.append(error)
|
66
|
+
logger.error(str(error))
|
67
|
+
|
68
|
+
# Notify observers
|
69
|
+
for observer in self._observers:
|
70
|
+
try:
|
71
|
+
observer.on_error(error)
|
72
|
+
except Exception as e:
|
73
|
+
logger.exception(f"Error observer failed: {e}")
|
74
|
+
|
75
|
+
if self._raise_on_error:
|
76
|
+
if error_type == ErrorType.PARSER_ERROR:
|
77
|
+
raise VexSyntaxError(message, location)
|
78
|
+
else:
|
79
|
+
raise VexAstError(str(error))
|
80
|
+
|
81
|
+
def get_errors(self) -> List[Error]:
|
82
|
+
"""Get a copy of all collected errors."""
|
83
|
+
return self._errors.copy()
|
84
|
+
|
85
|
+
def has_errors(self) -> bool:
|
86
|
+
"""Check if any errors have been collected."""
|
87
|
+
return bool(self._errors)
|
88
|
+
|
89
|
+
def clear_errors(self) -> None:
|
90
|
+
"""Clear all collected errors."""
|
91
|
+
self._errors.clear()
|
92
|
+
|
93
|
+
def add_observer(self, observer: ErrorObserver) -> None:
|
94
|
+
"""Add an observer to be notified of errors."""
|
95
|
+
if observer not in self._observers:
|
96
|
+
self._observers.append(observer)
|
97
|
+
|
98
|
+
def remove_observer(self, observer: ErrorObserver) -> None:
|
99
|
+
"""Remove an error observer."""
|
100
|
+
if observer in self._observers:
|
101
|
+
self._observers.remove(observer)
|
102
|
+
|
103
|
+
class VexAstError(Exception):
|
104
|
+
"""Base exception class for VEX AST errors."""
|
105
|
+
pass
|
106
|
+
|
107
|
+
class VexSyntaxError(VexAstError):
|
108
|
+
"""Exception raised for syntax errors during parsing."""
|
109
|
+
|
110
|
+
def __init__(self, message: str, location: Optional[SourceLocation] = None):
|
111
|
+
self.location = location
|
112
|
+
super().__init__(message)
|
vex_ast/utils/source_location.py
CHANGED
@@ -1,39 +1,39 @@
|
|
1
|
-
"""Source location tracking for AST nodes."""
|
2
|
-
|
3
|
-
from dataclasses import dataclass
|
4
|
-
from typing import Optional
|
5
|
-
|
6
|
-
@dataclass
|
7
|
-
class SourceLocation:
|
8
|
-
"""Represents a location in source code."""
|
9
|
-
|
10
|
-
# Start position
|
11
|
-
line: int
|
12
|
-
column: int
|
13
|
-
|
14
|
-
# End position (optional)
|
15
|
-
end_line: Optional[int] = None
|
16
|
-
end_column: Optional[int] = None
|
17
|
-
|
18
|
-
# Source file
|
19
|
-
filename: Optional[str] = None
|
20
|
-
|
21
|
-
def __post_init__(self):
|
22
|
-
"""Validate and normalize the location data."""
|
23
|
-
# Ensure end line is at least start line if not specified
|
24
|
-
if self.end_line is None:
|
25
|
-
self.end_line = self.line
|
26
|
-
|
27
|
-
def __str__(self) -> str:
|
28
|
-
"""Format the location for display."""
|
29
|
-
file_prefix = f"{self.filename}:" if self.filename else ""
|
30
|
-
|
31
|
-
# Just a point or single line span
|
32
|
-
if self.end_line == self.line:
|
33
|
-
if self.end_column is None or self.end_column == self.column:
|
34
|
-
return f"{file_prefix}L{self.line}:{self.column}"
|
35
|
-
return f"{file_prefix}L{self.line}:{self.column}-{self.end_column}"
|
36
|
-
|
37
|
-
# Multi-line span
|
38
|
-
end_col = f":{self.end_column}" if self.end_column is not None else ""
|
1
|
+
"""Source location tracking for AST nodes."""
|
2
|
+
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from typing import Optional
|
5
|
+
|
6
|
+
@dataclass
|
7
|
+
class SourceLocation:
|
8
|
+
"""Represents a location in source code."""
|
9
|
+
|
10
|
+
# Start position
|
11
|
+
line: int
|
12
|
+
column: int
|
13
|
+
|
14
|
+
# End position (optional)
|
15
|
+
end_line: Optional[int] = None
|
16
|
+
end_column: Optional[int] = None
|
17
|
+
|
18
|
+
# Source file
|
19
|
+
filename: Optional[str] = None
|
20
|
+
|
21
|
+
def __post_init__(self):
|
22
|
+
"""Validate and normalize the location data."""
|
23
|
+
# Ensure end line is at least start line if not specified
|
24
|
+
if self.end_line is None:
|
25
|
+
self.end_line = self.line
|
26
|
+
|
27
|
+
def __str__(self) -> str:
|
28
|
+
"""Format the location for display."""
|
29
|
+
file_prefix = f"{self.filename}:" if self.filename else ""
|
30
|
+
|
31
|
+
# Just a point or single line span
|
32
|
+
if self.end_line == self.line:
|
33
|
+
if self.end_column is None or self.end_column == self.column:
|
34
|
+
return f"{file_prefix}L{self.line}:{self.column}"
|
35
|
+
return f"{file_prefix}L{self.line}:{self.column}-{self.end_column}"
|
36
|
+
|
37
|
+
# Multi-line span
|
38
|
+
end_col = f":{self.end_column}" if self.end_column is not None else ""
|
39
39
|
return f"{file_prefix}L{self.line}:{self.column}-L{self.end_line}{end_col}"
|
@@ -1,9 +1,9 @@
|
|
1
|
-
# vex_ast/utils/type_definitions.py
|
2
|
-
"""Type definitions for type hints in the VEX AST."""
|
3
|
-
|
4
|
-
from typing import Any, Dict, List, Optional, TypeVar, Union, Type, Protocol
|
5
|
-
|
6
|
-
# Type variables for type hints
|
7
|
-
NodeType = TypeVar('NodeType')
|
8
|
-
VisitorType = TypeVar('VisitorType')
|
1
|
+
# vex_ast/utils/type_definitions.py
|
2
|
+
"""Type definitions for type hints in the VEX AST."""
|
3
|
+
|
4
|
+
from typing import Any, Dict, List, Optional, TypeVar, Union, Type, Protocol
|
5
|
+
|
6
|
+
# Type variables for type hints
|
7
|
+
NodeType = TypeVar('NodeType')
|
8
|
+
VisitorType = TypeVar('VisitorType')
|
9
9
|
TransformerType = TypeVar('TransformerType')
|
vex_ast/visitors/README.md
CHANGED
@@ -1,49 +1,49 @@
|
|
1
|
-
AST Visitors (vex_ast.visitors)
|
2
|
-
|
3
|
-
This directory provides implementations of the Visitor design pattern for traversing and operating on the VEX Abstract Syntax Tree (AST).
|
4
|
-
|
5
|
-
Purpose
|
6
|
-
|
7
|
-
Visitors allow you to perform operations on the AST without modifying the AST node classes themselves. They provide a clean and extensible way to implement various forms of analysis, transformation, or code generation based on the AST structure.
|
8
|
-
|
9
|
-
Core Concepts
|
10
|
-
|
11
|
-
Visitor Pattern: The core idea is double dispatch. You call visitor.visit(node), which in turn calls node.accept(visitor). The node's accept method then calls the specific visit_NodeType(node) method on the visitor corresponding to its own type.
|
12
|
-
|
13
|
-
Base Visitor (base.py):
|
14
|
-
|
15
|
-
AstVisitor[T_VisitorResult]: An abstract generic base class for all visitors. It defines the main visit entry point and provides default visit_NodeType methods that typically delegate to a generic_visit method. Subclasses must implement generic_visit and can override specific visit_NodeType methods for custom behavior.
|
16
|
-
|
17
|
-
Traversal: The generic_visit method in concrete visitors often iterates through the node's children (obtained via node.get_children()) and calls self.visit(child) recursively to traverse the tree.
|
18
|
-
|
19
|
-
Provided Visitors
|
20
|
-
|
21
|
-
Printer (printer.py):
|
22
|
-
|
23
|
-
PrintVisitor: Traverses the AST and generates a formatted, indented string representation of the tree structure, including node types, attributes, and source locations (if available). Useful for debugging and understanding the AST structure.
|
24
|
-
|
25
|
-
Analyzers (analyzer.py):
|
26
|
-
|
27
|
-
NodeCounter: Traverses the AST and counts the total number of nodes, optionally keeping track of counts per node type.
|
28
|
-
|
29
|
-
VariableCollector: Traverses the AST and collects the names of all variables referenced (VariableReference nodes).
|
30
|
-
|
31
|
-
Usage
|
32
|
-
|
33
|
-
Instantiate a Visitor: Create an instance of the desired visitor class (e.g., printer = PrintVisitor()).
|
34
|
-
|
35
|
-
Parse Code: Obtain the root node (Program object) of the AST using vex_ast.parse_string or vex_ast.parse_file.
|
36
|
-
|
37
|
-
Start Visitation: Call the visitor's visit method with the root node (e.g., result = printer.visit(ast_root)).
|
38
|
-
|
39
|
-
Process Result: The visit method will return a result whose type depends on the specific visitor (T_VisitorResult). For PrintVisitor, it's a string; for NodeCounter, an integer; for VariableCollector, a set of strings.
|
40
|
-
|
41
|
-
Extensibility
|
42
|
-
|
43
|
-
You can create custom visitors to perform specific tasks (e.g., type checking, code optimization, simulation execution) by:
|
44
|
-
|
45
|
-
Creating a new class that inherits from AstVisitor[YourResultType].
|
46
|
-
|
47
|
-
Implementing the generic_visit method to define default behavior and traversal logic.
|
48
|
-
|
49
|
-
Overriding specific visit_NodeType methods for nodes where specialized logic is required.
|
1
|
+
AST Visitors (vex_ast.visitors)
|
2
|
+
|
3
|
+
This directory provides implementations of the Visitor design pattern for traversing and operating on the VEX Abstract Syntax Tree (AST).
|
4
|
+
|
5
|
+
Purpose
|
6
|
+
|
7
|
+
Visitors allow you to perform operations on the AST without modifying the AST node classes themselves. They provide a clean and extensible way to implement various forms of analysis, transformation, or code generation based on the AST structure.
|
8
|
+
|
9
|
+
Core Concepts
|
10
|
+
|
11
|
+
Visitor Pattern: The core idea is double dispatch. You call visitor.visit(node), which in turn calls node.accept(visitor). The node's accept method then calls the specific visit_NodeType(node) method on the visitor corresponding to its own type.
|
12
|
+
|
13
|
+
Base Visitor (base.py):
|
14
|
+
|
15
|
+
AstVisitor[T_VisitorResult]: An abstract generic base class for all visitors. It defines the main visit entry point and provides default visit_NodeType methods that typically delegate to a generic_visit method. Subclasses must implement generic_visit and can override specific visit_NodeType methods for custom behavior.
|
16
|
+
|
17
|
+
Traversal: The generic_visit method in concrete visitors often iterates through the node's children (obtained via node.get_children()) and calls self.visit(child) recursively to traverse the tree.
|
18
|
+
|
19
|
+
Provided Visitors
|
20
|
+
|
21
|
+
Printer (printer.py):
|
22
|
+
|
23
|
+
PrintVisitor: Traverses the AST and generates a formatted, indented string representation of the tree structure, including node types, attributes, and source locations (if available). Useful for debugging and understanding the AST structure.
|
24
|
+
|
25
|
+
Analyzers (analyzer.py):
|
26
|
+
|
27
|
+
NodeCounter: Traverses the AST and counts the total number of nodes, optionally keeping track of counts per node type.
|
28
|
+
|
29
|
+
VariableCollector: Traverses the AST and collects the names of all variables referenced (VariableReference nodes).
|
30
|
+
|
31
|
+
Usage
|
32
|
+
|
33
|
+
Instantiate a Visitor: Create an instance of the desired visitor class (e.g., printer = PrintVisitor()).
|
34
|
+
|
35
|
+
Parse Code: Obtain the root node (Program object) of the AST using vex_ast.parse_string or vex_ast.parse_file.
|
36
|
+
|
37
|
+
Start Visitation: Call the visitor's visit method with the root node (e.g., result = printer.visit(ast_root)).
|
38
|
+
|
39
|
+
Process Result: The visit method will return a result whose type depends on the specific visitor (T_VisitorResult). For PrintVisitor, it's a string; for NodeCounter, an integer; for VariableCollector, a set of strings.
|
40
|
+
|
41
|
+
Extensibility
|
42
|
+
|
43
|
+
You can create custom visitors to perform specific tasks (e.g., type checking, code optimization, simulation execution) by:
|
44
|
+
|
45
|
+
Creating a new class that inherits from AstVisitor[YourResultType].
|
46
|
+
|
47
|
+
Implementing the generic_visit method to define default behavior and traversal logic.
|
48
|
+
|
49
|
+
Overriding specific visit_NodeType methods for nodes where specialized logic is required.
|
vex_ast/visitors/__init__.py
CHANGED
@@ -1,28 +1,28 @@
|
|
1
|
-
"""
|
2
|
-
Visitors package for VEX AST.
|
3
|
-
|
4
|
-
This package provides visitor pattern implementations for traversing and transforming the AST.
|
5
|
-
"""
|
6
|
-
|
7
|
-
from .base import (
|
8
|
-
AstVisitor,
|
9
|
-
TypedVisitorMixin
|
10
|
-
)
|
11
|
-
from .printer import PrintVisitor
|
12
|
-
from .analyzer import (
|
13
|
-
NodeCounter,
|
14
|
-
VariableCollector
|
15
|
-
)
|
16
|
-
|
17
|
-
__all__ = [
|
18
|
-
# Base visitors
|
19
|
-
"AstVisitor",
|
20
|
-
"TypedVisitorMixin",
|
21
|
-
|
22
|
-
# Concrete visitors
|
23
|
-
"PrintVisitor",
|
24
|
-
|
25
|
-
# Analysis visitors
|
26
|
-
"NodeCounter",
|
27
|
-
"VariableCollector"
|
1
|
+
"""
|
2
|
+
Visitors package for VEX AST.
|
3
|
+
|
4
|
+
This package provides visitor pattern implementations for traversing and transforming the AST.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from .base import (
|
8
|
+
AstVisitor,
|
9
|
+
TypedVisitorMixin
|
10
|
+
)
|
11
|
+
from .printer import PrintVisitor
|
12
|
+
from .analyzer import (
|
13
|
+
NodeCounter,
|
14
|
+
VariableCollector
|
15
|
+
)
|
16
|
+
|
17
|
+
__all__ = [
|
18
|
+
# Base visitors
|
19
|
+
"AstVisitor",
|
20
|
+
"TypedVisitorMixin",
|
21
|
+
|
22
|
+
# Concrete visitors
|
23
|
+
"PrintVisitor",
|
24
|
+
|
25
|
+
# Analysis visitors
|
26
|
+
"NodeCounter",
|
27
|
+
"VariableCollector"
|
28
28
|
]
|