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
@@ -0,0 +1,103 @@
|
|
1
|
+
"""Analysis visitors for AST."""
|
2
|
+
|
3
|
+
from typing import Any, Dict, List, Optional, Set
|
4
|
+
|
5
|
+
from .base import AstVisitor
|
6
|
+
from ..ast.interfaces import IAstNode
|
7
|
+
|
8
|
+
class NodeCounter(AstVisitor[int]):
|
9
|
+
"""Visitor that counts nodes in the AST."""
|
10
|
+
|
11
|
+
def __init__(self):
|
12
|
+
self.count = 0
|
13
|
+
self.counts_by_type: Dict[str, int] = {}
|
14
|
+
|
15
|
+
def generic_visit(self, node: IAstNode) -> int:
|
16
|
+
"""Count this node and visit its children."""
|
17
|
+
self.count += 1
|
18
|
+
|
19
|
+
# Count by node type
|
20
|
+
node_type = node.__class__.__name__
|
21
|
+
self.counts_by_type[node_type] = self.counts_by_type.get(node_type, 0) + 1
|
22
|
+
|
23
|
+
# Visit all children
|
24
|
+
for child in node.get_children():
|
25
|
+
self.visit(child)
|
26
|
+
|
27
|
+
return self.count
|
28
|
+
|
29
|
+
# Implement all the required visit methods by delegating to generic_visit
|
30
|
+
visit_program = generic_visit
|
31
|
+
visit_expression = generic_visit
|
32
|
+
visit_statement = generic_visit
|
33
|
+
visit_identifier = generic_visit
|
34
|
+
visit_variablereference = generic_visit
|
35
|
+
visit_binaryoperation = generic_visit
|
36
|
+
visit_unaryoperation = generic_visit
|
37
|
+
visit_functioncall = generic_visit
|
38
|
+
visit_keywordargument = generic_visit
|
39
|
+
visit_numberliteral = generic_visit
|
40
|
+
visit_stringliteral = generic_visit
|
41
|
+
visit_booleanliteral = generic_visit
|
42
|
+
visit_noneliteral = generic_visit
|
43
|
+
visit_expressionstatement = generic_visit
|
44
|
+
visit_assignment = generic_visit
|
45
|
+
visit_ifstatement = generic_visit
|
46
|
+
visit_whileloop = generic_visit
|
47
|
+
visit_forloop = generic_visit
|
48
|
+
visit_functiondefinition = generic_visit
|
49
|
+
visit_argument = generic_visit
|
50
|
+
visit_returnstatement = generic_visit
|
51
|
+
visit_breakstatement = generic_visit
|
52
|
+
visit_continuestatement = generic_visit
|
53
|
+
visit_vexapicall = generic_visit
|
54
|
+
visit_motorcontrol = generic_visit
|
55
|
+
visit_sensorreading = generic_visit
|
56
|
+
visit_timingcontrol = generic_visit
|
57
|
+
visit_displayoutput = generic_visit
|
58
|
+
|
59
|
+
class VariableCollector(AstVisitor[Set[str]]):
|
60
|
+
"""Visitor that collects variable names used in the AST."""
|
61
|
+
|
62
|
+
def __init__(self):
|
63
|
+
self.variables: Set[str] = set()
|
64
|
+
|
65
|
+
def generic_visit(self, node: IAstNode) -> Set[str]:
|
66
|
+
"""Collect variables from children."""
|
67
|
+
for child in node.get_children():
|
68
|
+
self.visit(child)
|
69
|
+
return self.variables
|
70
|
+
|
71
|
+
def visit_variablereference(self, node: Any) -> Set[str]:
|
72
|
+
"""Collect a variable reference."""
|
73
|
+
self.variables.add(node.name)
|
74
|
+
return self.generic_visit(node)
|
75
|
+
|
76
|
+
# Delegate all other methods to generic_visit
|
77
|
+
visit_program = generic_visit
|
78
|
+
visit_expression = generic_visit
|
79
|
+
visit_statement = generic_visit
|
80
|
+
visit_identifier = generic_visit
|
81
|
+
visit_binaryoperation = generic_visit
|
82
|
+
visit_unaryoperation = generic_visit
|
83
|
+
visit_functioncall = generic_visit
|
84
|
+
visit_keywordargument = generic_visit
|
85
|
+
visit_numberliteral = generic_visit
|
86
|
+
visit_stringliteral = generic_visit
|
87
|
+
visit_booleanliteral = generic_visit
|
88
|
+
visit_noneliteral = generic_visit
|
89
|
+
visit_expressionstatement = generic_visit
|
90
|
+
visit_assignment = generic_visit
|
91
|
+
visit_ifstatement = generic_visit
|
92
|
+
visit_whileloop = generic_visit
|
93
|
+
visit_forloop = generic_visit
|
94
|
+
visit_functiondefinition = generic_visit
|
95
|
+
visit_argument = generic_visit
|
96
|
+
visit_returnstatement = generic_visit
|
97
|
+
visit_breakstatement = generic_visit
|
98
|
+
visit_continuestatement = generic_visit
|
99
|
+
visit_vexapicall = generic_visit
|
100
|
+
visit_motorcontrol = generic_visit
|
101
|
+
visit_sensorreading = generic_visit
|
102
|
+
visit_timingcontrol = generic_visit
|
103
|
+
visit_displayoutput = generic_visit
|
vex_ast/visitors/base.py
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
"""Base visitor classes for AST traversal."""
|
2
|
+
|
3
|
+
from abc import ABC, abstractmethod
|
4
|
+
from typing import Any, Dict, Generic, List, Optional, TypeVar, cast, Type
|
5
|
+
|
6
|
+
from ..ast.interfaces import IAstNode, T_VisitorResult
|
7
|
+
|
8
|
+
class AstVisitor(Generic[T_VisitorResult], ABC):
|
9
|
+
"""Base class for AST visitors using the Visitor pattern."""
|
10
|
+
|
11
|
+
def visit(self, node: IAstNode) -> T_VisitorResult:
|
12
|
+
"""Visit a node by dispatching to its accept method."""
|
13
|
+
return node.accept(self)
|
14
|
+
|
15
|
+
def visit_children(self, node: IAstNode) -> List[T_VisitorResult]:
|
16
|
+
"""Visit all children of a node and return results."""
|
17
|
+
return [self.visit(child) for child in node.get_children()]
|
18
|
+
|
19
|
+
@abstractmethod
|
20
|
+
def generic_visit(self, node: IAstNode) -> T_VisitorResult:
|
21
|
+
"""Default visitor method for nodes without a specific method."""
|
22
|
+
pass
|
23
|
+
|
24
|
+
# Required visit methods for core node types
|
25
|
+
def visit_program(self, node: Any) -> T_VisitorResult:
|
26
|
+
return self.generic_visit(node)
|
27
|
+
|
28
|
+
def visit_expression(self, node: Any) -> T_VisitorResult:
|
29
|
+
return self.generic_visit(node)
|
30
|
+
|
31
|
+
def visit_statement(self, node: Any) -> T_VisitorResult:
|
32
|
+
return self.generic_visit(node)
|
33
|
+
|
34
|
+
# Visit methods for expressions
|
35
|
+
def visit_identifier(self, node: Any) -> T_VisitorResult:
|
36
|
+
return self.generic_visit(node)
|
37
|
+
|
38
|
+
def visit_variablereference(self, node: Any) -> T_VisitorResult:
|
39
|
+
return self.generic_visit(node)
|
40
|
+
|
41
|
+
def visit_attributeaccess(self, node: Any) -> T_VisitorResult:
|
42
|
+
return self.generic_visit(node)
|
43
|
+
|
44
|
+
def visit_binaryoperation(self, node: Any) -> T_VisitorResult:
|
45
|
+
return self.generic_visit(node)
|
46
|
+
|
47
|
+
def visit_unaryoperation(self, node: Any) -> T_VisitorResult:
|
48
|
+
return self.generic_visit(node)
|
49
|
+
|
50
|
+
def visit_functioncall(self, node: Any) -> T_VisitorResult:
|
51
|
+
return self.generic_visit(node)
|
52
|
+
|
53
|
+
def visit_keywordargument(self, node: Any) -> T_VisitorResult:
|
54
|
+
return self.generic_visit(node)
|
55
|
+
|
56
|
+
# Visit methods for literals
|
57
|
+
def visit_numberliteral(self, node: Any) -> T_VisitorResult:
|
58
|
+
return self.generic_visit(node)
|
59
|
+
|
60
|
+
def visit_stringliteral(self, node: Any) -> T_VisitorResult:
|
61
|
+
return self.generic_visit(node)
|
62
|
+
|
63
|
+
def visit_booleanliteral(self, node: Any) -> T_VisitorResult:
|
64
|
+
return self.generic_visit(node)
|
65
|
+
|
66
|
+
def visit_noneliteral(self, node: Any) -> T_VisitorResult:
|
67
|
+
return self.generic_visit(node)
|
68
|
+
|
69
|
+
# Visit methods for statements
|
70
|
+
def visit_expressionstatement(self, node: Any) -> T_VisitorResult:
|
71
|
+
return self.generic_visit(node)
|
72
|
+
|
73
|
+
def visit_assignment(self, node: Any) -> T_VisitorResult:
|
74
|
+
return self.generic_visit(node)
|
75
|
+
|
76
|
+
def visit_ifstatement(self, node: Any) -> T_VisitorResult:
|
77
|
+
return self.generic_visit(node)
|
78
|
+
|
79
|
+
def visit_whileloop(self, node: Any) -> T_VisitorResult:
|
80
|
+
return self.generic_visit(node)
|
81
|
+
|
82
|
+
def visit_forloop(self, node: Any) -> T_VisitorResult:
|
83
|
+
return self.generic_visit(node)
|
84
|
+
|
85
|
+
def visit_functiondefinition(self, node: Any) -> T_VisitorResult:
|
86
|
+
return self.generic_visit(node)
|
87
|
+
|
88
|
+
def visit_argument(self, node: Any) -> T_VisitorResult:
|
89
|
+
return self.generic_visit(node)
|
90
|
+
|
91
|
+
def visit_returnstatement(self, node: Any) -> T_VisitorResult:
|
92
|
+
return self.generic_visit(node)
|
93
|
+
|
94
|
+
def visit_breakstatement(self, node: Any) -> T_VisitorResult:
|
95
|
+
return self.generic_visit(node)
|
96
|
+
|
97
|
+
def visit_continuestatement(self, node: Any) -> T_VisitorResult:
|
98
|
+
return self.generic_visit(node)
|
99
|
+
|
100
|
+
# Visit methods for VEX-specific nodes
|
101
|
+
def visit_vexapicall(self, node: Any) -> T_VisitorResult:
|
102
|
+
return self.generic_visit(node)
|
103
|
+
|
104
|
+
def visit_motorcontrol(self, node: Any) -> T_VisitorResult:
|
105
|
+
return self.generic_visit(node)
|
106
|
+
|
107
|
+
def visit_sensorreading(self, node: Any) -> T_VisitorResult:
|
108
|
+
return self.generic_visit(node)
|
109
|
+
|
110
|
+
def visit_timingcontrol(self, node: Any) -> T_VisitorResult:
|
111
|
+
return self.generic_visit(node)
|
112
|
+
|
113
|
+
def visit_displayoutput(self, node: Any) -> T_VisitorResult:
|
114
|
+
return self.generic_visit(node)
|
115
|
+
|
116
|
+
|
117
|
+
class TypedVisitorMixin:
|
118
|
+
"""Mixin to provide type-specific dispatch methods."""
|
119
|
+
|
120
|
+
@staticmethod
|
121
|
+
def node_type_to_method_name(node_type: Type) -> str:
|
122
|
+
"""Convert a node type to a visitor method name."""
|
123
|
+
return f"visit_{node_type.__name__.lower()}"
|
124
|
+
|
125
|
+
def dispatch_by_type(self, node: IAstNode) -> Any:
|
126
|
+
"""Dispatch to the appropriate visit method based on the node's type."""
|
127
|
+
method_name = self.node_type_to_method_name(type(node))
|
128
|
+
if hasattr(self, method_name):
|
129
|
+
return getattr(self, method_name)(node)
|
130
|
+
return self.generic_visit(node)
|
@@ -0,0 +1,145 @@
|
|
1
|
+
"""AST printing visitor implementation."""
|
2
|
+
|
3
|
+
import io
|
4
|
+
from typing import Any, List, Optional
|
5
|
+
|
6
|
+
from .base import AstVisitor
|
7
|
+
from ..ast.interfaces import IAstNode
|
8
|
+
|
9
|
+
class PrintVisitor(AstVisitor[str]):
|
10
|
+
"""Visitor that generates a readable string representation of the AST."""
|
11
|
+
|
12
|
+
def __init__(self):
|
13
|
+
self._output = io.StringIO()
|
14
|
+
self._indent_level = 0
|
15
|
+
|
16
|
+
def _indent(self) -> None:
|
17
|
+
"""Write the current indentation."""
|
18
|
+
self._output.write(' ' * self._indent_level)
|
19
|
+
|
20
|
+
def _write_node_header(self, node: IAstNode, name: str) -> None:
|
21
|
+
"""Write a standard node header with location info."""
|
22
|
+
self._indent()
|
23
|
+
self._output.write(f"{name}")
|
24
|
+
if node.location:
|
25
|
+
self._output.write(f" (at {node.location})")
|
26
|
+
self._output.write(":\n")
|
27
|
+
|
28
|
+
def _format_value(self, value: Any) -> str:
|
29
|
+
"""Format a basic value for display."""
|
30
|
+
return repr(value)
|
31
|
+
|
32
|
+
def generic_visit(self, node: IAstNode) -> str:
|
33
|
+
"""Default node visitor that displays type and attributes."""
|
34
|
+
node_name = node.__class__.__name__
|
35
|
+
self._write_node_header(node, node_name)
|
36
|
+
|
37
|
+
# Visit fields if present
|
38
|
+
if hasattr(node, '_fields'):
|
39
|
+
self._indent_level += 1
|
40
|
+
for field_name in node._fields:
|
41
|
+
value = getattr(node, field_name, None)
|
42
|
+
|
43
|
+
# Skip None values
|
44
|
+
if value is None:
|
45
|
+
continue
|
46
|
+
|
47
|
+
self._indent()
|
48
|
+
self._output.write(f"{field_name} = ")
|
49
|
+
|
50
|
+
if isinstance(value, IAstNode):
|
51
|
+
self._output.write("\n")
|
52
|
+
self.visit(value)
|
53
|
+
elif isinstance(value, list):
|
54
|
+
if not value:
|
55
|
+
self._output.write("[]\n")
|
56
|
+
else:
|
57
|
+
self._output.write("[\n")
|
58
|
+
self._indent_level += 1
|
59
|
+
for i, item in enumerate(value):
|
60
|
+
self._indent()
|
61
|
+
self._output.write(f"[{i}]: ")
|
62
|
+
if isinstance(item, IAstNode):
|
63
|
+
self._output.write("\n")
|
64
|
+
self.visit(item)
|
65
|
+
else:
|
66
|
+
self._output.write(f"{self._format_value(item)}\n")
|
67
|
+
self._indent_level -= 1
|
68
|
+
self._indent()
|
69
|
+
self._output.write("]\n")
|
70
|
+
else:
|
71
|
+
self._output.write(f"{self._format_value(value)}\n")
|
72
|
+
self._indent_level -= 1
|
73
|
+
|
74
|
+
# At the root level, return the accumulated output
|
75
|
+
if self._indent_level == 0:
|
76
|
+
return self._output.getvalue()
|
77
|
+
return ""
|
78
|
+
|
79
|
+
# Simple node visitors for concise output
|
80
|
+
def visit_identifier(self, node: Any) -> str:
|
81
|
+
self._output.write(f"Identifier(name={node.name!r})")
|
82
|
+
if node.location:
|
83
|
+
self._output.write(f" (at {node.location})")
|
84
|
+
return ""
|
85
|
+
|
86
|
+
def visit_numberliteral(self, node: Any) -> str:
|
87
|
+
self._output.write(f"NumberLiteral(value={node.value!r})")
|
88
|
+
if node.location:
|
89
|
+
self._output.write(f" (at {node.location})")
|
90
|
+
return ""
|
91
|
+
|
92
|
+
def visit_stringliteral(self, node: Any) -> str:
|
93
|
+
self._output.write(f"StringLiteral(value={node.value!r})")
|
94
|
+
if node.location:
|
95
|
+
self._output.write(f" (at {node.location})")
|
96
|
+
return ""
|
97
|
+
|
98
|
+
def visit_booleanliteral(self, node: Any) -> str:
|
99
|
+
self._output.write(f"BooleanLiteral(value={node.value!r})")
|
100
|
+
if node.location:
|
101
|
+
self._output.write(f" (at {node.location})")
|
102
|
+
return ""
|
103
|
+
|
104
|
+
def visit_noneliteral(self, node: Any) -> str:
|
105
|
+
self._output.write(f"NoneLiteral()")
|
106
|
+
if node.location:
|
107
|
+
self._output.write(f" (at {node.location})")
|
108
|
+
return ""
|
109
|
+
|
110
|
+
# Program node is the entry point
|
111
|
+
def visit_program(self, node: Any) -> str:
|
112
|
+
self._output.write("Program:\n")
|
113
|
+
self._indent_level += 1
|
114
|
+
for i, stmt in enumerate(node.body):
|
115
|
+
self._indent()
|
116
|
+
self._output.write(f"[{i}]: \n")
|
117
|
+
self._indent_level += 1
|
118
|
+
self.visit(stmt)
|
119
|
+
self._indent_level -= 1
|
120
|
+
self._indent_level -= 1
|
121
|
+
return self._output.getvalue()
|
122
|
+
|
123
|
+
# Delegate all other methods to generic_visit
|
124
|
+
visit_expression = generic_visit
|
125
|
+
visit_statement = generic_visit
|
126
|
+
visit_variablereference = generic_visit
|
127
|
+
visit_binaryoperation = generic_visit
|
128
|
+
visit_unaryoperation = generic_visit
|
129
|
+
visit_functioncall = generic_visit
|
130
|
+
visit_keywordargument = generic_visit
|
131
|
+
visit_expressionstatement = generic_visit
|
132
|
+
visit_assignment = generic_visit
|
133
|
+
visit_ifstatement = generic_visit
|
134
|
+
visit_whileloop = generic_visit
|
135
|
+
visit_forloop = generic_visit
|
136
|
+
visit_functiondefinition = generic_visit
|
137
|
+
visit_argument = generic_visit
|
138
|
+
visit_returnstatement = generic_visit
|
139
|
+
visit_breakstatement = generic_visit
|
140
|
+
visit_continuestatement = generic_visit
|
141
|
+
visit_vexapicall = generic_visit
|
142
|
+
visit_motorcontrol = generic_visit
|
143
|
+
visit_sensorreading = generic_visit
|
144
|
+
visit_timingcontrol = generic_visit
|
145
|
+
visit_displayoutput = generic_visit
|
File without changes
|
@@ -0,0 +1,176 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: vex_ast
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: A Python package for generating Abstract Syntax Trees for VEX V5 code.
|
5
|
+
Home-page: https://github.com/teowy/vex_ast
|
6
|
+
Author: Chaze
|
7
|
+
Author-email: chazelexander@example.com
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
9
|
+
Classifier: Intended Audience :: Developers
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
12
|
+
Classifier: Programming Language :: Python :: 3.8
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
16
|
+
Classifier: Topic :: Software Development :: Compilers
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
18
|
+
Requires-Python: >=3.8
|
19
|
+
Description-Content-Type: text/markdown
|
20
|
+
Dynamic: author
|
21
|
+
Dynamic: author-email
|
22
|
+
Dynamic: classifier
|
23
|
+
Dynamic: description
|
24
|
+
Dynamic: description-content-type
|
25
|
+
Dynamic: home-page
|
26
|
+
Dynamic: requires-python
|
27
|
+
Dynamic: summary
|
28
|
+
|
29
|
+
# VEX AST Generator
|
30
|
+
|
31
|
+
A Python package for generating Abstract Syntax Trees (ASTs) for VEX V5 Robot Python code.
|
32
|
+
|
33
|
+
## Project Goal
|
34
|
+
|
35
|
+
The primary goal of this project is to provide a robust and extensible framework for parsing VEX V5 Python code and representing it as an Abstract Syntax Tree (AST). This AST can then be used for various purposes, such as static analysis, code transformation, simulation, or integration with other development tools specific to the VEX ecosystem.
|
36
|
+
|
37
|
+
## Features (Implemented)
|
38
|
+
|
39
|
+
* Parsing of standard Python syntax relevant to VEX programming.
|
40
|
+
* Generation of a well-defined AST structure using custom node types.
|
41
|
+
* Representation of core Python constructs (variables, functions, loops, conditionals, expressions).
|
42
|
+
* Specific AST nodes for common VEX API patterns (e.g., `MotorControl`, `SensorReading`).
|
43
|
+
* Visitor pattern implementation (`vex_ast.visitors`) for easy AST traversal and manipulation.
|
44
|
+
* Basic analysis visitors (`NodeCounter`, `VariableCollector`).
|
45
|
+
* AST pretty-printing visitor (`PrintVisitor`).
|
46
|
+
* Error handling and reporting with source location information (`vex_ast.utils`).
|
47
|
+
* JSON serialization and deserialization of AST nodes (`vex_ast.serialization`).
|
48
|
+
* JSON Schema generation for AST structure validation and documentation.
|
49
|
+
|
50
|
+
## Library Structure
|
51
|
+
|
52
|
+
The core library is within the `vex_ast` directory:
|
53
|
+
|
54
|
+
* `vex_ast/ast/`: Defines the structure and node types of the Abstract Syntax Tree.
|
55
|
+
* `vex_ast/parser/`: Contains the logic for parsing Python source code into the AST.
|
56
|
+
* `vex_ast/visitors/`: Provides tools for traversing and analyzing the generated AST.
|
57
|
+
* `vex_ast/utils/`: Includes helper modules for error handling and source location tracking.
|
58
|
+
|
59
|
+
## Setup
|
60
|
+
|
61
|
+
1. **Clone the repository:**
|
62
|
+
```bash
|
63
|
+
git clone https://github.com/yourusername/vex_ast.git # Replace with actual URL
|
64
|
+
cd vex_ast
|
65
|
+
```
|
66
|
+
|
67
|
+
2. **Create and activate a virtual environment:**
|
68
|
+
```bash
|
69
|
+
python3 -m venv .venv
|
70
|
+
source .venv/bin/activate # On Windows use `.venv\Scripts\activate`
|
71
|
+
```
|
72
|
+
|
73
|
+
3. **Install dependencies:**
|
74
|
+
```bash
|
75
|
+
pip install -r requirements.txt
|
76
|
+
```
|
77
|
+
|
78
|
+
4. **(Optional) Install for development:**
|
79
|
+
If you plan to contribute to the project, install it in editable mode along with development dependencies:
|
80
|
+
```bash
|
81
|
+
pip install -e .[dev]
|
82
|
+
```
|
83
|
+
|
84
|
+
## Usage Example
|
85
|
+
|
86
|
+
### Basic Parsing and Printing
|
87
|
+
|
88
|
+
```python
|
89
|
+
from vex_ast import parse_string
|
90
|
+
from vex_ast.visitors.printer import PrintVisitor
|
91
|
+
|
92
|
+
# VEX-like Python code
|
93
|
+
code = """
|
94
|
+
left_motor = Motor("port1")
|
95
|
+
right_motor = Motor("port10")
|
96
|
+
|
97
|
+
def drive_forward(speed_percent):
|
98
|
+
left_motor.spin(FORWARD, speed_percent, PERCENT)
|
99
|
+
right_motor.spin(FORWARD, speed_percent, PERCENT)
|
100
|
+
wait(1, SECONDS)
|
101
|
+
left_motor.stop()
|
102
|
+
right_motor.stop()
|
103
|
+
|
104
|
+
drive_forward(50)
|
105
|
+
print("Movement complete!")
|
106
|
+
"""
|
107
|
+
|
108
|
+
try:
|
109
|
+
# Parse the code string into an AST
|
110
|
+
ast_tree = parse_string(code)
|
111
|
+
|
112
|
+
# Use the PrintVisitor to get a textual representation of the AST
|
113
|
+
printer = PrintVisitor()
|
114
|
+
ast_representation = printer.visit(ast_tree)
|
115
|
+
|
116
|
+
print("--- AST Representation ---")
|
117
|
+
print(ast_representation)
|
118
|
+
|
119
|
+
except Exception as e:
|
120
|
+
print(f"An error occurred: {e}")
|
121
|
+
```
|
122
|
+
|
123
|
+
### Serialization and Deserialization
|
124
|
+
|
125
|
+
```python
|
126
|
+
from vex_ast import (
|
127
|
+
parse_string,
|
128
|
+
serialize_ast_to_json,
|
129
|
+
deserialize_ast_from_json,
|
130
|
+
export_schema_to_file
|
131
|
+
)
|
132
|
+
|
133
|
+
# Parse code into an AST
|
134
|
+
code = "x = 10 + 20"
|
135
|
+
ast = parse_string(code)
|
136
|
+
|
137
|
+
# Serialize the AST to JSON
|
138
|
+
json_str = serialize_ast_to_json(ast, indent=2)
|
139
|
+
print(json_str)
|
140
|
+
|
141
|
+
# Save the AST to a file
|
142
|
+
with open("ast.json", "w") as f:
|
143
|
+
f.write(json_str)
|
144
|
+
|
145
|
+
# Later, load the AST from JSON
|
146
|
+
with open("ast.json", "r") as f:
|
147
|
+
loaded_json = f.read()
|
148
|
+
|
149
|
+
# Deserialize back to an AST object
|
150
|
+
loaded_ast = deserialize_ast_from_json(loaded_json)
|
151
|
+
|
152
|
+
# Generate and export a JSON schema
|
153
|
+
export_schema_to_file("ast_schema.json")
|
154
|
+
```
|
155
|
+
|
156
|
+
## Development
|
157
|
+
```bash
|
158
|
+
Running Tests
|
159
|
+
pytest
|
160
|
+
```
|
161
|
+
```bash
|
162
|
+
Type Checking
|
163
|
+
mypy vex_ast
|
164
|
+
```
|
165
|
+
```bash
|
166
|
+
Formatting and Linting
|
167
|
+
black vex_ast tests
|
168
|
+
flake8 vex_ast tests
|
169
|
+
```
|
170
|
+
## Contributing
|
171
|
+
|
172
|
+
Contributions are welcome! Please follow the established coding standards and ensure tests pass before submitting a pull request.
|
173
|
+
|
174
|
+
## License
|
175
|
+
|
176
|
+
This project is licensed under the MIT License - see the LICENSE file for details (You'll need to add a LICENSE file).
|
@@ -0,0 +1,41 @@
|
|
1
|
+
vex_ast/__init__.py,sha256=YPsS_1ab9-G3WYmyxQobDA1U8y5KJkj2qxm_p_s9Oow,1724
|
2
|
+
vex_ast/ast/__init__.py,sha256=3ZtTiNeBPWOYgNWmxThn0h7UQx8Z0bHbK6hRHCUuILQ,2435
|
3
|
+
vex_ast/ast/core.py,sha256=q-15q5VfGIVPAmFsSiWeFAZ55MPsXfCRa21rrt2hmlM,2670
|
4
|
+
vex_ast/ast/expressions.py,sha256=b0cDs239wvygCIL9s0W8uuyuPeMZz3DwxQ0wmBta_XM,7758
|
5
|
+
vex_ast/ast/interfaces.py,sha256=DXKdAzts0EBWjCRgYkz_kVSMcYbNIyPdwYpTr7c6P2A,5928
|
6
|
+
vex_ast/ast/literals.py,sha256=PXbOH5Y2fxEngWk_FOiFsx3PC2SEqcx0bcfOGJ3SdbI,2618
|
7
|
+
vex_ast/ast/navigator.py,sha256=2ELYIWTZNuaJHLMDiY9bbRkz8XAEDRnPNN8uKRafNYg,7253
|
8
|
+
vex_ast/ast/operators.py,sha256=I-yWvhsrz-OxmBZs5zIss_GTZF5S-nwcSmIzvAVtddM,3160
|
9
|
+
vex_ast/ast/statements.py,sha256=OWRthjYGmTuNozYAHjh_Enp5t-hR1PphtPnFg31FeWw,11841
|
10
|
+
vex_ast/ast/validators.py,sha256=lhEm1dt-nzMiaUan_AWEOm0NiwXN7wYNkLCl1c3drqc,4455
|
11
|
+
vex_ast/ast/vex_nodes.py,sha256=kVil-ApFIeZ_BoeqYppfVRPSTg1KFUOcvt1vCE6QRgs,10148
|
12
|
+
vex_ast/parser/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
|
+
vex_ast/parser/factory.py,sha256=gaje0jOPu5lpndgX9c3VuQ_q-FJuFz9yC5y2bD69lL4,8770
|
14
|
+
vex_ast/parser/interfaces.py,sha256=Ttc0bD_5X420ZCT9MLUf_wE1aZLWLkaJRQqCwBy9wIs,956
|
15
|
+
vex_ast/parser/python_parser.py,sha256=e1owk-c6Rb4Bt5SYcgB-urZzqsX5xC9tzcK1sB8gkr4,29687
|
16
|
+
vex_ast/parser/strategies.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
|
+
vex_ast/registry/__init__.py,sha256=dXT8OS7uLyBSdQKZDWrtbANzgSWcg9HUQDA1EaLOvjQ,1188
|
18
|
+
vex_ast/registry/api.py,sha256=yyW-TsCIULTzePAoyMvEqD_RNlkFSb4PLpiSkw6ueQk,5460
|
19
|
+
vex_ast/registry/categories.py,sha256=y5tnCzHQ9PPg9hOzOMgyE1ZAhcsjgeFSrgqdJrdqHEg,4885
|
20
|
+
vex_ast/registry/language_map.py,sha256=eekN3k-K9g90GFi4--If3nfJCyarUJxDWDCDvLm7mdU,2656
|
21
|
+
vex_ast/registry/registry.py,sha256=gvsQKyeXWp84T2uDB4O_WQgKCeq8W9udl8TD5MnPZzc,6661
|
22
|
+
vex_ast/registry/signature.py,sha256=m8gQKdc5IaORDdfdBX6_qH1OL5LoTzveGoWlIIaOES0,5763
|
23
|
+
vex_ast/registry/simulation_behavior.py,sha256=WwkVKae0owtv3WTrfnVH93rpsh9lbqJ_RSAVmpIVA_k,313
|
24
|
+
vex_ast/registry/validation.py,sha256=xq5UjSWYAcRxjxsCGg3WU5RtPN-DB-JAqKqDNGvnJGk,1973
|
25
|
+
vex_ast/serialization/__init__.py,sha256=qPTEiMjU8hpVxNH5z4MY7Yj60AxuFurjXZStjhWWf6o,835
|
26
|
+
vex_ast/serialization/json_deserializer.py,sha256=m_xiEUEoFXGfFylK3M8BVs7F2EieQJ9wbUa_ZTpkHtQ,10523
|
27
|
+
vex_ast/serialization/json_serializer.py,sha256=YvMRUpqXjtbxlIvathEIywUqbH3Ne6GSRODfFB0QCGM,4465
|
28
|
+
vex_ast/serialization/schema.py,sha256=zpKujT7u3Qw2kNbwjV09lNzeQAsCxvMx-uAdaRMEstA,14431
|
29
|
+
vex_ast/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
30
|
+
vex_ast/utils/errors.py,sha256=uq_jyu-YasifXjKSpPbVxup-XFf0XSHmp7A0Zd87TUY,3850
|
31
|
+
vex_ast/utils/source_location.py,sha256=r857ypqUBqex2y_R0RzZo7pz5di9qtEeWFFQ4HwzYQE,1297
|
32
|
+
vex_ast/utils/type_definitions.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
33
|
+
vex_ast/visitors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
34
|
+
vex_ast/visitors/analyzer.py,sha256=cBT5PRbtfQ_Dt1qiHN-wdO5KnC2yl-Ul5RasXg9geHY,3668
|
35
|
+
vex_ast/visitors/base.py,sha256=Ph0taTIVMHV_QjXfDd0ipZnCXVJErkyRtPpfwfzo-kY,4859
|
36
|
+
vex_ast/visitors/printer.py,sha256=CUY_73hxm7MoC-63JeIXaVYnZ8QqtfMqbek2R2HMEmE,5411
|
37
|
+
vex_ast/visitors/transformer.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
38
|
+
vex_ast-0.1.0.dist-info/METADATA,sha256=A7JHuJeTux45tRPBF9772gQNdp36fVqv2v_Zc_WZ-Zs,5327
|
39
|
+
vex_ast-0.1.0.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
|
40
|
+
vex_ast-0.1.0.dist-info/top_level.txt,sha256=MoZGrpKgNUDiqL9gWp4q3wMw3q93XPEEjmBNPJQcNAs,8
|
41
|
+
vex_ast-0.1.0.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
vex_ast
|