vex-ast 0.1.0__tar.gz
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-0.1.0/PKG-INFO +176 -0
- vex_ast-0.1.0/README.md +148 -0
- vex_ast-0.1.0/setup.cfg +4 -0
- vex_ast-0.1.0/setup.py +29 -0
- vex_ast-0.1.0/tests/test_core.py +86 -0
- vex_ast-0.1.0/tests/test_integration.py +70 -0
- vex_ast-0.1.0/tests/test_literals.py +56 -0
- vex_ast-0.1.0/tests/test_navigator.py +121 -0
- vex_ast-0.1.0/tests/test_parser.py +66 -0
- vex_ast-0.1.0/tests/test_registry.py +75 -0
- vex_ast-0.1.0/tests/test_serialization.py +273 -0
- vex_ast-0.1.0/tests/test_statements.py +103 -0
- vex_ast-0.1.0/tests/test_vex_nodes.py +48 -0
- vex_ast-0.1.0/tests/test_visitors.py +55 -0
- vex_ast-0.1.0/vex_ast/__init__.py +65 -0
- vex_ast-0.1.0/vex_ast/ast/__init__.py +75 -0
- vex_ast-0.1.0/vex_ast/ast/core.py +71 -0
- vex_ast-0.1.0/vex_ast/ast/expressions.py +233 -0
- vex_ast-0.1.0/vex_ast/ast/interfaces.py +192 -0
- vex_ast-0.1.0/vex_ast/ast/literals.py +80 -0
- vex_ast-0.1.0/vex_ast/ast/navigator.py +213 -0
- vex_ast-0.1.0/vex_ast/ast/operators.py +136 -0
- vex_ast-0.1.0/vex_ast/ast/statements.py +351 -0
- vex_ast-0.1.0/vex_ast/ast/validators.py +114 -0
- vex_ast-0.1.0/vex_ast/ast/vex_nodes.py +241 -0
- vex_ast-0.1.0/vex_ast/parser/__init__.py +0 -0
- vex_ast-0.1.0/vex_ast/parser/factory.py +179 -0
- vex_ast-0.1.0/vex_ast/parser/interfaces.py +35 -0
- vex_ast-0.1.0/vex_ast/parser/python_parser.py +725 -0
- vex_ast-0.1.0/vex_ast/parser/strategies.py +0 -0
- vex_ast-0.1.0/vex_ast/registry/__init__.py +51 -0
- vex_ast-0.1.0/vex_ast/registry/api.py +155 -0
- vex_ast-0.1.0/vex_ast/registry/categories.py +136 -0
- vex_ast-0.1.0/vex_ast/registry/language_map.py +78 -0
- vex_ast-0.1.0/vex_ast/registry/registry.py +153 -0
- vex_ast-0.1.0/vex_ast/registry/signature.py +143 -0
- vex_ast-0.1.0/vex_ast/registry/simulation_behavior.py +9 -0
- vex_ast-0.1.0/vex_ast/registry/validation.py +44 -0
- vex_ast-0.1.0/vex_ast/serialization/__init__.py +37 -0
- vex_ast-0.1.0/vex_ast/serialization/json_deserializer.py +264 -0
- vex_ast-0.1.0/vex_ast/serialization/json_serializer.py +148 -0
- vex_ast-0.1.0/vex_ast/serialization/schema.py +471 -0
- vex_ast-0.1.0/vex_ast/utils/__init__.py +0 -0
- vex_ast-0.1.0/vex_ast/utils/errors.py +112 -0
- vex_ast-0.1.0/vex_ast/utils/source_location.py +39 -0
- vex_ast-0.1.0/vex_ast/utils/type_definitions.py +0 -0
- vex_ast-0.1.0/vex_ast/visitors/__init__.py +0 -0
- vex_ast-0.1.0/vex_ast/visitors/analyzer.py +103 -0
- vex_ast-0.1.0/vex_ast/visitors/base.py +130 -0
- vex_ast-0.1.0/vex_ast/visitors/printer.py +145 -0
- vex_ast-0.1.0/vex_ast/visitors/transformer.py +0 -0
- vex_ast-0.1.0/vex_ast.egg-info/PKG-INFO +176 -0
- vex_ast-0.1.0/vex_ast.egg-info/SOURCES.txt +53 -0
- vex_ast-0.1.0/vex_ast.egg-info/dependency_links.txt +1 -0
- vex_ast-0.1.0/vex_ast.egg-info/top_level.txt +1 -0
vex_ast-0.1.0/PKG-INFO
ADDED
@@ -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).
|
vex_ast-0.1.0/README.md
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
# VEX AST Generator
|
2
|
+
|
3
|
+
A Python package for generating Abstract Syntax Trees (ASTs) for VEX V5 Robot Python code.
|
4
|
+
|
5
|
+
## Project Goal
|
6
|
+
|
7
|
+
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.
|
8
|
+
|
9
|
+
## Features (Implemented)
|
10
|
+
|
11
|
+
* Parsing of standard Python syntax relevant to VEX programming.
|
12
|
+
* Generation of a well-defined AST structure using custom node types.
|
13
|
+
* Representation of core Python constructs (variables, functions, loops, conditionals, expressions).
|
14
|
+
* Specific AST nodes for common VEX API patterns (e.g., `MotorControl`, `SensorReading`).
|
15
|
+
* Visitor pattern implementation (`vex_ast.visitors`) for easy AST traversal and manipulation.
|
16
|
+
* Basic analysis visitors (`NodeCounter`, `VariableCollector`).
|
17
|
+
* AST pretty-printing visitor (`PrintVisitor`).
|
18
|
+
* Error handling and reporting with source location information (`vex_ast.utils`).
|
19
|
+
* JSON serialization and deserialization of AST nodes (`vex_ast.serialization`).
|
20
|
+
* JSON Schema generation for AST structure validation and documentation.
|
21
|
+
|
22
|
+
## Library Structure
|
23
|
+
|
24
|
+
The core library is within the `vex_ast` directory:
|
25
|
+
|
26
|
+
* `vex_ast/ast/`: Defines the structure and node types of the Abstract Syntax Tree.
|
27
|
+
* `vex_ast/parser/`: Contains the logic for parsing Python source code into the AST.
|
28
|
+
* `vex_ast/visitors/`: Provides tools for traversing and analyzing the generated AST.
|
29
|
+
* `vex_ast/utils/`: Includes helper modules for error handling and source location tracking.
|
30
|
+
|
31
|
+
## Setup
|
32
|
+
|
33
|
+
1. **Clone the repository:**
|
34
|
+
```bash
|
35
|
+
git clone https://github.com/yourusername/vex_ast.git # Replace with actual URL
|
36
|
+
cd vex_ast
|
37
|
+
```
|
38
|
+
|
39
|
+
2. **Create and activate a virtual environment:**
|
40
|
+
```bash
|
41
|
+
python3 -m venv .venv
|
42
|
+
source .venv/bin/activate # On Windows use `.venv\Scripts\activate`
|
43
|
+
```
|
44
|
+
|
45
|
+
3. **Install dependencies:**
|
46
|
+
```bash
|
47
|
+
pip install -r requirements.txt
|
48
|
+
```
|
49
|
+
|
50
|
+
4. **(Optional) Install for development:**
|
51
|
+
If you plan to contribute to the project, install it in editable mode along with development dependencies:
|
52
|
+
```bash
|
53
|
+
pip install -e .[dev]
|
54
|
+
```
|
55
|
+
|
56
|
+
## Usage Example
|
57
|
+
|
58
|
+
### Basic Parsing and Printing
|
59
|
+
|
60
|
+
```python
|
61
|
+
from vex_ast import parse_string
|
62
|
+
from vex_ast.visitors.printer import PrintVisitor
|
63
|
+
|
64
|
+
# VEX-like Python code
|
65
|
+
code = """
|
66
|
+
left_motor = Motor("port1")
|
67
|
+
right_motor = Motor("port10")
|
68
|
+
|
69
|
+
def drive_forward(speed_percent):
|
70
|
+
left_motor.spin(FORWARD, speed_percent, PERCENT)
|
71
|
+
right_motor.spin(FORWARD, speed_percent, PERCENT)
|
72
|
+
wait(1, SECONDS)
|
73
|
+
left_motor.stop()
|
74
|
+
right_motor.stop()
|
75
|
+
|
76
|
+
drive_forward(50)
|
77
|
+
print("Movement complete!")
|
78
|
+
"""
|
79
|
+
|
80
|
+
try:
|
81
|
+
# Parse the code string into an AST
|
82
|
+
ast_tree = parse_string(code)
|
83
|
+
|
84
|
+
# Use the PrintVisitor to get a textual representation of the AST
|
85
|
+
printer = PrintVisitor()
|
86
|
+
ast_representation = printer.visit(ast_tree)
|
87
|
+
|
88
|
+
print("--- AST Representation ---")
|
89
|
+
print(ast_representation)
|
90
|
+
|
91
|
+
except Exception as e:
|
92
|
+
print(f"An error occurred: {e}")
|
93
|
+
```
|
94
|
+
|
95
|
+
### Serialization and Deserialization
|
96
|
+
|
97
|
+
```python
|
98
|
+
from vex_ast import (
|
99
|
+
parse_string,
|
100
|
+
serialize_ast_to_json,
|
101
|
+
deserialize_ast_from_json,
|
102
|
+
export_schema_to_file
|
103
|
+
)
|
104
|
+
|
105
|
+
# Parse code into an AST
|
106
|
+
code = "x = 10 + 20"
|
107
|
+
ast = parse_string(code)
|
108
|
+
|
109
|
+
# Serialize the AST to JSON
|
110
|
+
json_str = serialize_ast_to_json(ast, indent=2)
|
111
|
+
print(json_str)
|
112
|
+
|
113
|
+
# Save the AST to a file
|
114
|
+
with open("ast.json", "w") as f:
|
115
|
+
f.write(json_str)
|
116
|
+
|
117
|
+
# Later, load the AST from JSON
|
118
|
+
with open("ast.json", "r") as f:
|
119
|
+
loaded_json = f.read()
|
120
|
+
|
121
|
+
# Deserialize back to an AST object
|
122
|
+
loaded_ast = deserialize_ast_from_json(loaded_json)
|
123
|
+
|
124
|
+
# Generate and export a JSON schema
|
125
|
+
export_schema_to_file("ast_schema.json")
|
126
|
+
```
|
127
|
+
|
128
|
+
## Development
|
129
|
+
```bash
|
130
|
+
Running Tests
|
131
|
+
pytest
|
132
|
+
```
|
133
|
+
```bash
|
134
|
+
Type Checking
|
135
|
+
mypy vex_ast
|
136
|
+
```
|
137
|
+
```bash
|
138
|
+
Formatting and Linting
|
139
|
+
black vex_ast tests
|
140
|
+
flake8 vex_ast tests
|
141
|
+
```
|
142
|
+
## Contributing
|
143
|
+
|
144
|
+
Contributions are welcome! Please follow the established coding standards and ensure tests pass before submitting a pull request.
|
145
|
+
|
146
|
+
## License
|
147
|
+
|
148
|
+
This project is licensed under the MIT License - see the LICENSE file for details (You'll need to add a LICENSE file).
|
vex_ast-0.1.0/setup.cfg
ADDED
vex_ast-0.1.0/setup.py
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
from setuptools import setup, find_packages
|
2
|
+
|
3
|
+
setup(
|
4
|
+
name='vex_ast',
|
5
|
+
version='0.1.0',
|
6
|
+
description='A Python package for generating Abstract Syntax Trees for VEX V5 code.',
|
7
|
+
long_description=open('README.md').read(),
|
8
|
+
long_description_content_type='text/markdown',
|
9
|
+
author='Chaze', # Replace with your actual name
|
10
|
+
author_email='chazelexander@example.com', # Replace with your actual email
|
11
|
+
url='https://github.com/teowy/vex_ast', # Replace with your actual repository URL
|
12
|
+
packages=find_packages(exclude=['tests*']),
|
13
|
+
install_requires=[
|
14
|
+
# Add runtime dependencies here if any
|
15
|
+
],
|
16
|
+
classifiers=[
|
17
|
+
'Development Status :: 3 - Alpha',
|
18
|
+
'Intended Audience :: Developers',
|
19
|
+
'License :: OSI Approved :: MIT License',
|
20
|
+
'Programming Language :: Python :: 3',
|
21
|
+
'Programming Language :: Python :: 3.8',
|
22
|
+
'Programming Language :: Python :: 3.9',
|
23
|
+
'Programming Language :: Python :: 3.10',
|
24
|
+
'Programming Language :: Python :: 3.11',
|
25
|
+
'Topic :: Software Development :: Compilers',
|
26
|
+
'Topic :: Software Development :: Libraries :: Python Modules',
|
27
|
+
],
|
28
|
+
python_requires='>=3.8',
|
29
|
+
)
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# tests/test_core.py
|
2
|
+
import pytest
|
3
|
+
from vex_ast.ast.core import Program, Expression, Statement
|
4
|
+
from vex_ast.ast.statements import ExpressionStatement
|
5
|
+
from vex_ast.ast.expressions import Identifier
|
6
|
+
from vex_ast.visitors.base import AstVisitor
|
7
|
+
|
8
|
+
# Simple test visitor for testing
|
9
|
+
class TestVisitor(AstVisitor[str]):
|
10
|
+
def generic_visit(self, node):
|
11
|
+
return "generic"
|
12
|
+
|
13
|
+
def visit_program(self, node):
|
14
|
+
return "program"
|
15
|
+
|
16
|
+
def visit_expression(self, node):
|
17
|
+
return "expression"
|
18
|
+
|
19
|
+
def visit_statement(self, node):
|
20
|
+
return "statement"
|
21
|
+
|
22
|
+
# Implement required methods
|
23
|
+
visit_identifier = generic_visit
|
24
|
+
visit_variablereference = generic_visit
|
25
|
+
visit_binaryoperation = generic_visit
|
26
|
+
visit_unaryoperation = generic_visit
|
27
|
+
visit_functioncall = generic_visit
|
28
|
+
visit_keywordargument = generic_visit
|
29
|
+
visit_numberliteral = generic_visit
|
30
|
+
visit_stringliteral = generic_visit
|
31
|
+
visit_booleanliteral = generic_visit
|
32
|
+
visit_noneliteral = generic_visit
|
33
|
+
visit_expressionstatement = generic_visit
|
34
|
+
visit_assignment = generic_visit
|
35
|
+
visit_ifstatement = generic_visit
|
36
|
+
visit_whileloop = generic_visit
|
37
|
+
visit_forloop = generic_visit
|
38
|
+
visit_functiondefinition = generic_visit
|
39
|
+
visit_argument = generic_visit
|
40
|
+
visit_returnstatement = generic_visit
|
41
|
+
visit_breakstatement = generic_visit
|
42
|
+
visit_continuestatement = generic_visit
|
43
|
+
visit_vexapicall = generic_visit
|
44
|
+
visit_motorcontrol = generic_visit
|
45
|
+
visit_sensorreading = generic_visit
|
46
|
+
visit_timingcontrol = generic_visit
|
47
|
+
visit_displayoutput = generic_visit
|
48
|
+
|
49
|
+
class TestCoreNodes:
|
50
|
+
def test_program_node(self):
|
51
|
+
body = [ExpressionStatement(Identifier("x"))]
|
52
|
+
program = Program(body)
|
53
|
+
|
54
|
+
assert program.body == body
|
55
|
+
assert program.get_children() == body
|
56
|
+
|
57
|
+
# Test visitor pattern
|
58
|
+
visitor = TestVisitor()
|
59
|
+
result = program.accept(visitor)
|
60
|
+
assert result == "program"
|
61
|
+
|
62
|
+
def test_expression_base(self):
|
63
|
+
# Create a simple Expression subclass for testing
|
64
|
+
class TestExpression(Expression):
|
65
|
+
def get_children(self):
|
66
|
+
return []
|
67
|
+
|
68
|
+
expr = TestExpression()
|
69
|
+
|
70
|
+
# Test visitor pattern
|
71
|
+
visitor = TestVisitor()
|
72
|
+
result = expr.accept(visitor)
|
73
|
+
assert result == "expression"
|
74
|
+
|
75
|
+
def test_statement_base(self):
|
76
|
+
# Create a simple Statement subclass for testing
|
77
|
+
class TestStatement(Statement):
|
78
|
+
def get_children(self):
|
79
|
+
return []
|
80
|
+
|
81
|
+
stmt = TestStatement()
|
82
|
+
|
83
|
+
# Test visitor pattern
|
84
|
+
visitor = TestVisitor()
|
85
|
+
result = stmt.accept(visitor)
|
86
|
+
assert result == "statement"
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# tests/test_integration.py
|
2
|
+
import pytest
|
3
|
+
from vex_ast import parse_string
|
4
|
+
from vex_ast.visitors.printer import PrintVisitor
|
5
|
+
from vex_ast.visitors.analyzer import NodeCounter, VariableCollector
|
6
|
+
|
7
|
+
class TestIntegration:
|
8
|
+
def test_full_program_parse(self):
|
9
|
+
# A complete program with multiple features
|
10
|
+
code = """
|
11
|
+
def drive_forward(speed, time_ms):
|
12
|
+
# Set both motors to the specified speed
|
13
|
+
left_motor.set_velocity(speed, PERCENT)
|
14
|
+
right_motor.set_velocity(speed, PERCENT)
|
15
|
+
|
16
|
+
# Start the motors
|
17
|
+
left_motor.spin(FORWARD)
|
18
|
+
right_motor.spin(FORWARD)
|
19
|
+
|
20
|
+
# Wait for the specified time
|
21
|
+
wait(time_ms, MSEC)
|
22
|
+
|
23
|
+
# Stop the motors
|
24
|
+
left_motor.stop()
|
25
|
+
right_motor.stop()
|
26
|
+
|
27
|
+
return True
|
28
|
+
|
29
|
+
# Main program
|
30
|
+
def main():
|
31
|
+
# Display welcome message
|
32
|
+
brain.screen.print("Robot starting...")
|
33
|
+
wait(1, SECONDS)
|
34
|
+
|
35
|
+
# Drive forward at 50% speed for 2 seconds
|
36
|
+
success = drive_forward(50, 2000)
|
37
|
+
|
38
|
+
if success:
|
39
|
+
brain.screen.print("Drive completed!")
|
40
|
+
else:
|
41
|
+
brain.screen.print("Drive failed!")
|
42
|
+
|
43
|
+
return 0
|
44
|
+
"""
|
45
|
+
|
46
|
+
# Just test that parsing doesn't raise exceptions
|
47
|
+
ast = parse_string(code)
|
48
|
+
|
49
|
+
# Check that we have two function definitions
|
50
|
+
assert len(ast.body) == 2
|
51
|
+
assert ast.body[0].__class__.__name__ == "FunctionDefinition"
|
52
|
+
assert ast.body[1].__class__.__name__ == "FunctionDefinition"
|
53
|
+
assert ast.body[0].name == "drive_forward"
|
54
|
+
assert ast.body[1].name == "main"
|
55
|
+
|
56
|
+
# Test that visitors work with the complex AST
|
57
|
+
printer = PrintVisitor()
|
58
|
+
result = printer.visit(ast)
|
59
|
+
assert isinstance(result, str)
|
60
|
+
|
61
|
+
counter = NodeCounter()
|
62
|
+
count = counter.visit(ast)
|
63
|
+
assert count > 30 # Should have many nodes
|
64
|
+
|
65
|
+
collector = VariableCollector()
|
66
|
+
variables = collector.visit(ast)
|
67
|
+
assert "left_motor" in variables
|
68
|
+
assert "right_motor" in variables
|
69
|
+
assert "brain" in variables
|
70
|
+
assert "success" in variables
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# tests/test_literals.py
|
2
|
+
import pytest
|
3
|
+
from vex_ast.ast.literals import NumberLiteral, StringLiteral, BooleanLiteral, NoneLiteral
|
4
|
+
from vex_ast.visitors.printer import PrintVisitor
|
5
|
+
from vex_ast.utils.source_location import SourceLocation
|
6
|
+
|
7
|
+
class TestLiterals:
|
8
|
+
def test_number_literal(self):
|
9
|
+
# Test integer
|
10
|
+
nl = NumberLiteral(42)
|
11
|
+
assert nl.value == 42
|
12
|
+
|
13
|
+
# Test float
|
14
|
+
nl = NumberLiteral(3.14)
|
15
|
+
assert nl.value == 3.14
|
16
|
+
|
17
|
+
# Test with location
|
18
|
+
loc = SourceLocation(1, 5)
|
19
|
+
nl = NumberLiteral(100, loc)
|
20
|
+
assert nl.location == loc
|
21
|
+
|
22
|
+
def test_string_literal(self):
|
23
|
+
sl = StringLiteral("hello")
|
24
|
+
assert sl.value == "hello"
|
25
|
+
|
26
|
+
# Test empty string
|
27
|
+
sl = StringLiteral("")
|
28
|
+
assert sl.value == ""
|
29
|
+
|
30
|
+
def test_boolean_literal(self):
|
31
|
+
# Test True
|
32
|
+
bl = BooleanLiteral(True)
|
33
|
+
assert bl.value is True
|
34
|
+
|
35
|
+
# Test False
|
36
|
+
bl = BooleanLiteral(False)
|
37
|
+
assert bl.value is False
|
38
|
+
|
39
|
+
def test_none_literal(self):
|
40
|
+
nl = NoneLiteral()
|
41
|
+
assert nl.value is None
|
42
|
+
|
43
|
+
def test_visitor_pattern(self):
|
44
|
+
# Test that visitor pattern works correctly
|
45
|
+
visitor = PrintVisitor()
|
46
|
+
|
47
|
+
nl = NumberLiteral(42)
|
48
|
+
sl = StringLiteral("hello")
|
49
|
+
bl = BooleanLiteral(True)
|
50
|
+
none_l = NoneLiteral()
|
51
|
+
|
52
|
+
# Just test that these don't raise exceptions
|
53
|
+
visitor.visit(nl)
|
54
|
+
visitor.visit(sl)
|
55
|
+
visitor.visit(bl)
|
56
|
+
visitor.visit(none_l)
|
@@ -0,0 +1,121 @@
|
|
1
|
+
"""Tests for the AST navigator."""
|
2
|
+
|
3
|
+
import pytest
|
4
|
+
from vex_ast import parse_string, create_navigator
|
5
|
+
from vex_ast.ast.expressions import Identifier, VariableReference, FunctionCall
|
6
|
+
from vex_ast.ast.statements import Assignment, FunctionDefinition
|
7
|
+
from vex_ast.ast.literals import NumberLiteral, StringLiteral
|
8
|
+
from vex_ast.ast.vex_nodes import VexAPICall
|
9
|
+
|
10
|
+
class TestAstNavigator:
|
11
|
+
"""Test the AST navigator functionality."""
|
12
|
+
|
13
|
+
def test_basic_navigation(self):
|
14
|
+
"""Test basic navigation functionality."""
|
15
|
+
code = """
|
16
|
+
# Define a motor
|
17
|
+
motor1 = Motor(PORT1)
|
18
|
+
|
19
|
+
# Define a function
|
20
|
+
def move_forward(speed):
|
21
|
+
motor1.spin(FORWARD, speed, PERCENT)
|
22
|
+
wait(1, SECONDS)
|
23
|
+
motor1.stop()
|
24
|
+
return True
|
25
|
+
|
26
|
+
# Call the function
|
27
|
+
success = move_forward(50)
|
28
|
+
"""
|
29
|
+
|
30
|
+
# Parse the code
|
31
|
+
ast = parse_string(code)
|
32
|
+
|
33
|
+
# Create a navigator
|
34
|
+
navigator = create_navigator(ast)
|
35
|
+
|
36
|
+
# Test finding all identifiers
|
37
|
+
identifiers = navigator.find_identifiers()
|
38
|
+
assert len(identifiers) > 0
|
39
|
+
assert any(ident.name == "motor1" for ident in identifiers)
|
40
|
+
assert any(ident.name == "move_forward" for ident in identifiers)
|
41
|
+
|
42
|
+
# Test finding all function calls
|
43
|
+
function_calls = navigator.find_function_calls()
|
44
|
+
assert len(function_calls) > 0
|
45
|
+
|
46
|
+
# Test finding VEX API calls
|
47
|
+
vex_calls = navigator.find_vex_api_calls()
|
48
|
+
assert len(vex_calls) > 0
|
49
|
+
|
50
|
+
# Test finding function definitions
|
51
|
+
func_defs = navigator.find_function_definitions()
|
52
|
+
assert len(func_defs) == 1
|
53
|
+
assert func_defs[0].name == "move_forward"
|
54
|
+
|
55
|
+
# Test finding assignments
|
56
|
+
assignments = navigator.find_assignments()
|
57
|
+
assert len(assignments) > 0
|
58
|
+
|
59
|
+
# Test finding literals
|
60
|
+
literals = navigator.find_literals()
|
61
|
+
assert len(literals) > 0
|
62
|
+
|
63
|
+
# Test finding a function by name
|
64
|
+
move_forward = navigator.get_function_by_name("move_forward")
|
65
|
+
assert move_forward is not None
|
66
|
+
assert move_forward.name == "move_forward"
|
67
|
+
|
68
|
+
# Test finding variable references
|
69
|
+
motor_refs = navigator.get_variable_references("motor1")
|
70
|
+
assert len(motor_refs) > 0
|
71
|
+
|
72
|
+
def test_parent_child_relationships(self):
|
73
|
+
"""Test parent-child relationship navigation."""
|
74
|
+
code = """
|
75
|
+
x = 10
|
76
|
+
y = 20
|
77
|
+
z = x + y
|
78
|
+
"""
|
79
|
+
|
80
|
+
# Parse the code
|
81
|
+
ast = parse_string(code)
|
82
|
+
|
83
|
+
# Create a navigator
|
84
|
+
navigator = create_navigator(ast)
|
85
|
+
|
86
|
+
# Find the assignment 'z = x + y'
|
87
|
+
assignments = navigator.find_assignments()
|
88
|
+
z_assignment = next(a for a in assignments if hasattr(a.target, 'name') and a.target.name == 'z')
|
89
|
+
|
90
|
+
# The right side should be a binary operation
|
91
|
+
binary_op = z_assignment.value
|
92
|
+
|
93
|
+
# Test parent-child relationship
|
94
|
+
assert binary_op.get_parent() is z_assignment
|
95
|
+
|
96
|
+
# Test finding siblings
|
97
|
+
siblings = navigator.find_siblings(z_assignment)
|
98
|
+
assert len(siblings) == 2 # The other two assignments
|
99
|
+
|
100
|
+
def test_registry_api_integration(self):
|
101
|
+
"""Test integration with the registry API."""
|
102
|
+
code = """
|
103
|
+
motor1 = Motor(PORT1)
|
104
|
+
motor1.spin(FORWARD, 50, PERCENT)
|
105
|
+
"""
|
106
|
+
|
107
|
+
# Parse the code
|
108
|
+
ast = parse_string(code)
|
109
|
+
|
110
|
+
# Create a navigator
|
111
|
+
navigator = create_navigator(ast)
|
112
|
+
|
113
|
+
# Find VEX API calls
|
114
|
+
vex_calls = navigator.find_vex_api_calls()
|
115
|
+
assert len(vex_calls) > 0
|
116
|
+
|
117
|
+
# Test that the signature is resolved correctly
|
118
|
+
spin_call = next(call for call in vex_calls if call.get_function_name() and 'spin' in call.get_function_name())
|
119
|
+
signature = spin_call.resolve_signature()
|
120
|
+
assert signature is not None
|
121
|
+
assert signature.name == "spin"
|