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.
Files changed (55) hide show
  1. vex_ast-0.1.0/PKG-INFO +176 -0
  2. vex_ast-0.1.0/README.md +148 -0
  3. vex_ast-0.1.0/setup.cfg +4 -0
  4. vex_ast-0.1.0/setup.py +29 -0
  5. vex_ast-0.1.0/tests/test_core.py +86 -0
  6. vex_ast-0.1.0/tests/test_integration.py +70 -0
  7. vex_ast-0.1.0/tests/test_literals.py +56 -0
  8. vex_ast-0.1.0/tests/test_navigator.py +121 -0
  9. vex_ast-0.1.0/tests/test_parser.py +66 -0
  10. vex_ast-0.1.0/tests/test_registry.py +75 -0
  11. vex_ast-0.1.0/tests/test_serialization.py +273 -0
  12. vex_ast-0.1.0/tests/test_statements.py +103 -0
  13. vex_ast-0.1.0/tests/test_vex_nodes.py +48 -0
  14. vex_ast-0.1.0/tests/test_visitors.py +55 -0
  15. vex_ast-0.1.0/vex_ast/__init__.py +65 -0
  16. vex_ast-0.1.0/vex_ast/ast/__init__.py +75 -0
  17. vex_ast-0.1.0/vex_ast/ast/core.py +71 -0
  18. vex_ast-0.1.0/vex_ast/ast/expressions.py +233 -0
  19. vex_ast-0.1.0/vex_ast/ast/interfaces.py +192 -0
  20. vex_ast-0.1.0/vex_ast/ast/literals.py +80 -0
  21. vex_ast-0.1.0/vex_ast/ast/navigator.py +213 -0
  22. vex_ast-0.1.0/vex_ast/ast/operators.py +136 -0
  23. vex_ast-0.1.0/vex_ast/ast/statements.py +351 -0
  24. vex_ast-0.1.0/vex_ast/ast/validators.py +114 -0
  25. vex_ast-0.1.0/vex_ast/ast/vex_nodes.py +241 -0
  26. vex_ast-0.1.0/vex_ast/parser/__init__.py +0 -0
  27. vex_ast-0.1.0/vex_ast/parser/factory.py +179 -0
  28. vex_ast-0.1.0/vex_ast/parser/interfaces.py +35 -0
  29. vex_ast-0.1.0/vex_ast/parser/python_parser.py +725 -0
  30. vex_ast-0.1.0/vex_ast/parser/strategies.py +0 -0
  31. vex_ast-0.1.0/vex_ast/registry/__init__.py +51 -0
  32. vex_ast-0.1.0/vex_ast/registry/api.py +155 -0
  33. vex_ast-0.1.0/vex_ast/registry/categories.py +136 -0
  34. vex_ast-0.1.0/vex_ast/registry/language_map.py +78 -0
  35. vex_ast-0.1.0/vex_ast/registry/registry.py +153 -0
  36. vex_ast-0.1.0/vex_ast/registry/signature.py +143 -0
  37. vex_ast-0.1.0/vex_ast/registry/simulation_behavior.py +9 -0
  38. vex_ast-0.1.0/vex_ast/registry/validation.py +44 -0
  39. vex_ast-0.1.0/vex_ast/serialization/__init__.py +37 -0
  40. vex_ast-0.1.0/vex_ast/serialization/json_deserializer.py +264 -0
  41. vex_ast-0.1.0/vex_ast/serialization/json_serializer.py +148 -0
  42. vex_ast-0.1.0/vex_ast/serialization/schema.py +471 -0
  43. vex_ast-0.1.0/vex_ast/utils/__init__.py +0 -0
  44. vex_ast-0.1.0/vex_ast/utils/errors.py +112 -0
  45. vex_ast-0.1.0/vex_ast/utils/source_location.py +39 -0
  46. vex_ast-0.1.0/vex_ast/utils/type_definitions.py +0 -0
  47. vex_ast-0.1.0/vex_ast/visitors/__init__.py +0 -0
  48. vex_ast-0.1.0/vex_ast/visitors/analyzer.py +103 -0
  49. vex_ast-0.1.0/vex_ast/visitors/base.py +130 -0
  50. vex_ast-0.1.0/vex_ast/visitors/printer.py +145 -0
  51. vex_ast-0.1.0/vex_ast/visitors/transformer.py +0 -0
  52. vex_ast-0.1.0/vex_ast.egg-info/PKG-INFO +176 -0
  53. vex_ast-0.1.0/vex_ast.egg-info/SOURCES.txt +53 -0
  54. vex_ast-0.1.0/vex_ast.egg-info/dependency_links.txt +1 -0
  55. 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).
@@ -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).
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
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"