vex-ast 0.2.5__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 -81
- 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 -121
- 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 -831
- 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 -35
- vex_ast/registry/functions/display.py +146 -146
- vex_ast/registry/functions/drivetrain.py +163 -163
- vex_ast/registry/functions/initialize.py +31 -31
- 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 -284
- vex_ast/serialization/json_serializer.py +148 -148
- vex_ast/serialization/schema.py +492 -492
- 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 -122
- 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 -196
- {vex_ast-0.2.5.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.5.dist-info/RECORD +0 -64
- {vex_ast-0.2.5.dist-info → vex_ast-0.2.6.dist-info}/WHEEL +0 -0
- {vex_ast-0.2.5.dist-info → vex_ast-0.2.6.dist-info}/licenses/LICENSE +0 -0
- {vex_ast-0.2.5.dist-info → vex_ast-0.2.6.dist-info}/top_level.txt +0 -0
@@ -1,37 +1,37 @@
|
|
1
|
-
"""
|
2
|
-
Serialization package for VEX AST.
|
3
|
-
|
4
|
-
This package provides functionality for serializing and deserializing AST nodes
|
5
|
-
to and from JSON format, as well as generating JSON schema for the AST structure.
|
6
|
-
"""
|
7
|
-
|
8
|
-
from .json_serializer import (
|
9
|
-
SerializationVisitor,
|
10
|
-
serialize_ast_to_dict,
|
11
|
-
serialize_ast_to_json
|
12
|
-
)
|
13
|
-
from .json_deserializer import (
|
14
|
-
DeserializationFactory,
|
15
|
-
deserialize_ast_from_dict,
|
16
|
-
deserialize_ast_from_json
|
17
|
-
)
|
18
|
-
from .schema import (
|
19
|
-
generate_ast_schema,
|
20
|
-
export_schema_to_file
|
21
|
-
)
|
22
|
-
|
23
|
-
__all__ = [
|
24
|
-
# Serialization
|
25
|
-
"SerializationVisitor",
|
26
|
-
"serialize_ast_to_dict",
|
27
|
-
"serialize_ast_to_json",
|
28
|
-
|
29
|
-
# Deserialization
|
30
|
-
"DeserializationFactory",
|
31
|
-
"deserialize_ast_from_dict",
|
32
|
-
"deserialize_ast_from_json",
|
33
|
-
|
34
|
-
# Schema
|
35
|
-
"generate_ast_schema",
|
36
|
-
"export_schema_to_file"
|
37
|
-
]
|
1
|
+
"""
|
2
|
+
Serialization package for VEX AST.
|
3
|
+
|
4
|
+
This package provides functionality for serializing and deserializing AST nodes
|
5
|
+
to and from JSON format, as well as generating JSON schema for the AST structure.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from .json_serializer import (
|
9
|
+
SerializationVisitor,
|
10
|
+
serialize_ast_to_dict,
|
11
|
+
serialize_ast_to_json
|
12
|
+
)
|
13
|
+
from .json_deserializer import (
|
14
|
+
DeserializationFactory,
|
15
|
+
deserialize_ast_from_dict,
|
16
|
+
deserialize_ast_from_json
|
17
|
+
)
|
18
|
+
from .schema import (
|
19
|
+
generate_ast_schema,
|
20
|
+
export_schema_to_file
|
21
|
+
)
|
22
|
+
|
23
|
+
__all__ = [
|
24
|
+
# Serialization
|
25
|
+
"SerializationVisitor",
|
26
|
+
"serialize_ast_to_dict",
|
27
|
+
"serialize_ast_to_json",
|
28
|
+
|
29
|
+
# Deserialization
|
30
|
+
"DeserializationFactory",
|
31
|
+
"deserialize_ast_from_dict",
|
32
|
+
"deserialize_ast_from_json",
|
33
|
+
|
34
|
+
# Schema
|
35
|
+
"generate_ast_schema",
|
36
|
+
"export_schema_to_file"
|
37
|
+
]
|
@@ -1,284 +1,284 @@
|
|
1
|
-
"""
|
2
|
-
JSON deserialization for AST nodes.
|
3
|
-
|
4
|
-
This module provides functionality to convert JSON data back to AST nodes.
|
5
|
-
"""
|
6
|
-
|
7
|
-
import json
|
8
|
-
from typing import Any, Dict, List, Optional, Type, Union, cast
|
9
|
-
|
10
|
-
from ..ast.interfaces import IAstNode
|
11
|
-
from ..parser.factory import NodeFactory
|
12
|
-
from ..utils.source_location import SourceLocation
|
13
|
-
from ..utils.errors import ErrorHandler, ErrorType
|
14
|
-
|
15
|
-
|
16
|
-
class DeserializationFactory:
|
17
|
-
"""
|
18
|
-
Factory for deserializing JSON data back to AST nodes.
|
19
|
-
|
20
|
-
This class uses the NodeFactory to create AST nodes from serialized data,
|
21
|
-
handling the reconstruction of the node hierarchy and parent-child relationships.
|
22
|
-
"""
|
23
|
-
|
24
|
-
def __init__(self, error_handler: Optional[ErrorHandler] = None):
|
25
|
-
"""
|
26
|
-
Initialize the deserialization factory.
|
27
|
-
|
28
|
-
Args:
|
29
|
-
error_handler: Optional error handler for reporting deserialization issues
|
30
|
-
"""
|
31
|
-
self.node_factory = NodeFactory(error_handler)
|
32
|
-
self.error_handler = error_handler
|
33
|
-
|
34
|
-
def deserialize_node(self, data: Dict[str, Any]) -> IAstNode:
|
35
|
-
"""
|
36
|
-
Deserialize a dictionary representation back to an AST node.
|
37
|
-
|
38
|
-
Args:
|
39
|
-
data: Dictionary representation of an AST node
|
40
|
-
|
41
|
-
Returns:
|
42
|
-
The reconstructed AST node
|
43
|
-
|
44
|
-
Raises:
|
45
|
-
ValueError: If the data is invalid or missing required fields
|
46
|
-
"""
|
47
|
-
# Extract node type
|
48
|
-
if "type" not in data:
|
49
|
-
raise ValueError("Missing 'type' field in node data")
|
50
|
-
|
51
|
-
node_type = data["type"]
|
52
|
-
|
53
|
-
# Create source location if present
|
54
|
-
location = None
|
55
|
-
if "location" in data:
|
56
|
-
location = self._deserialize_location(data["location"])
|
57
|
-
|
58
|
-
# Dispatch to appropriate creation method based on node type
|
59
|
-
method_name = f"_create_{node_type.lower()}"
|
60
|
-
if hasattr(self, method_name):
|
61
|
-
create_method = getattr(self, method_name)
|
62
|
-
node = create_method(data, location)
|
63
|
-
else:
|
64
|
-
# Fallback to generic creation if no specific method exists
|
65
|
-
node = self._create_generic_node(node_type, data, location)
|
66
|
-
|
67
|
-
return node
|
68
|
-
|
69
|
-
def _deserialize_location(self, data: Dict[str, Any]) -> SourceLocation:
|
70
|
-
"""
|
71
|
-
Deserialize a dictionary to a SourceLocation object.
|
72
|
-
|
73
|
-
Args:
|
74
|
-
data: Dictionary representation of a source location
|
75
|
-
|
76
|
-
Returns:
|
77
|
-
A SourceLocation object
|
78
|
-
"""
|
79
|
-
return SourceLocation(
|
80
|
-
line=data["line"],
|
81
|
-
column=data["column"],
|
82
|
-
end_line=data.get("end_line"),
|
83
|
-
end_column=data.get("end_column"),
|
84
|
-
filename=data.get("filename")
|
85
|
-
)
|
86
|
-
|
87
|
-
def _deserialize_value(self, value: Any) -> Any:
|
88
|
-
"""
|
89
|
-
Deserialize a value based on its type.
|
90
|
-
|
91
|
-
Args:
|
92
|
-
value: The value to deserialize
|
93
|
-
|
94
|
-
Returns:
|
95
|
-
The deserialized value
|
96
|
-
"""
|
97
|
-
# Handle None
|
98
|
-
if value is None:
|
99
|
-
return None
|
100
|
-
|
101
|
-
# Handle dictionaries (potentially nested nodes)
|
102
|
-
if isinstance(value, dict) and "type" in value:
|
103
|
-
return self.deserialize_node(value)
|
104
|
-
|
105
|
-
# Handle lists of values
|
106
|
-
if isinstance(value, list):
|
107
|
-
return [self._deserialize_value(item) for item in value]
|
108
|
-
|
109
|
-
# Handle dictionaries (not nodes)
|
110
|
-
if isinstance(value, dict):
|
111
|
-
return {k: self._deserialize_value(v) for k, v in value.items()}
|
112
|
-
|
113
|
-
# Return basic types as-is
|
114
|
-
return value
|
115
|
-
|
116
|
-
def _create_generic_node(self, node_type: str, data: Dict[str, Any],
|
117
|
-
location: Optional[SourceLocation]) -> IAstNode:
|
118
|
-
"""
|
119
|
-
Generic node creation when no specific method exists.
|
120
|
-
|
121
|
-
Args:
|
122
|
-
node_type: The type of node to create
|
123
|
-
data: Dictionary representation of the node
|
124
|
-
location: Optional source location
|
125
|
-
|
126
|
-
Returns:
|
127
|
-
The created AST node
|
128
|
-
|
129
|
-
Raises:
|
130
|
-
ValueError: If the node type is not supported
|
131
|
-
"""
|
132
|
-
# Map of node types to factory methods
|
133
|
-
factory_methods = {
|
134
|
-
# Literals
|
135
|
-
"NumberLiteral": self.node_factory.create_number_literal,
|
136
|
-
"StringLiteral": self.node_factory.create_string_literal,
|
137
|
-
"BooleanLiteral": self.node_factory.create_boolean_literal,
|
138
|
-
"NoneLiteral": self.node_factory.create_none_literal,
|
139
|
-
|
140
|
-
# Expressions
|
141
|
-
"Identifier": self.node_factory.create_identifier,
|
142
|
-
"VariableReference": self.node_factory.create_variable_reference,
|
143
|
-
"AttributeAccess": self.node_factory.create_attribute_access,
|
144
|
-
"BinaryOperation": self.node_factory.create_binary_operation,
|
145
|
-
"UnaryOperation": self.node_factory.create_unary_operation,
|
146
|
-
"ConditionalExpression": self.node_factory.create_conditional_expression,
|
147
|
-
"FunctionCall": self.node_factory.create_function_call,
|
148
|
-
"KeywordArgument": self.node_factory.create_keyword_argument,
|
149
|
-
|
150
|
-
# Statements
|
151
|
-
"ExpressionStatement": self.node_factory.create_expression_statement,
|
152
|
-
"Assignment": self.node_factory.create_assignment,
|
153
|
-
"IfStatement": self.node_factory.create_if_statement,
|
154
|
-
"WhileLoop": self.node_factory.create_while_loop,
|
155
|
-
"ForLoop": self.node_factory.create_for_loop,
|
156
|
-
"FunctionDefinition": self.node_factory.create_function_definition,
|
157
|
-
"Argument": self.node_factory.create_argument,
|
158
|
-
"ReturnStatement": self.node_factory.create_return_statement,
|
159
|
-
"BreakStatement": self.node_factory.create_break_statement,
|
160
|
-
"ContinueStatement": self.node_factory.create_continue_statement,
|
161
|
-
|
162
|
-
# VEX-specific nodes
|
163
|
-
"VexAPICall": self.node_factory.create_vex_api_call,
|
164
|
-
"MotorControl": self.node_factory.create_motor_control,
|
165
|
-
"SensorReading": self.node_factory.create_sensor_reading,
|
166
|
-
"TimingControl": self.node_factory.create_timing_control,
|
167
|
-
"DisplayOutput": self.node_factory.create_display_output,
|
168
|
-
|
169
|
-
# Core
|
170
|
-
"Program": self.node_factory.create_program,
|
171
|
-
}
|
172
|
-
|
173
|
-
if node_type not in factory_methods:
|
174
|
-
raise ValueError(f"Unsupported node type: {node_type}")
|
175
|
-
|
176
|
-
# Extract and deserialize attributes
|
177
|
-
kwargs = {}
|
178
|
-
for key, value in data.items():
|
179
|
-
if key not in ["type", "location"]:
|
180
|
-
kwargs[key] = self._deserialize_value(value)
|
181
|
-
|
182
|
-
# Create the node using the appropriate factory method
|
183
|
-
factory_method = factory_methods[node_type]
|
184
|
-
|
185
|
-
# Special handling for certain node types
|
186
|
-
if node_type == "Program":
|
187
|
-
return factory_method(kwargs.get("body", []), location)
|
188
|
-
elif node_type in ["NumberLiteral", "StringLiteral", "BooleanLiteral"]:
|
189
|
-
return factory_method(kwargs.get("value"), location)
|
190
|
-
elif node_type == "NoneLiteral":
|
191
|
-
return factory_method(location)
|
192
|
-
elif node_type == "Identifier":
|
193
|
-
return factory_method(kwargs.get("name", ""), location)
|
194
|
-
|
195
|
-
# For other node types, pass all kwargs and location
|
196
|
-
# This is a simplified approach; in a real implementation,
|
197
|
-
# you would need to handle each node type specifically
|
198
|
-
try:
|
199
|
-
return factory_method(**kwargs, location=location)
|
200
|
-
except TypeError as e:
|
201
|
-
# If the factory method doesn't accept the kwargs, report an error
|
202
|
-
if self.error_handler:
|
203
|
-
self.error_handler.add_error(
|
204
|
-
error_type=ErrorType.INTERNAL_ERROR,
|
205
|
-
message=f"Failed to create {node_type}: {str(e)}"
|
206
|
-
)
|
207
|
-
raise ValueError(f"Failed to deserialize {node_type}: {str(e)}")
|
208
|
-
|
209
|
-
# Specific node creation methods for complex cases
|
210
|
-
|
211
|
-
def _create_attributeaccess(self, data: Dict[str, Any],
|
212
|
-
location: Optional[SourceLocation]) -> IAstNode:
|
213
|
-
"""Create an AttributeAccess node from serialized data."""
|
214
|
-
object_expr = self._deserialize_value(data.get("object"))
|
215
|
-
attribute = data.get("attribute", "")
|
216
|
-
return self.node_factory.create_attribute_access(object_expr, attribute, location)
|
217
|
-
|
218
|
-
def _create_program(self, data: Dict[str, Any],
|
219
|
-
location: Optional[SourceLocation]) -> IAstNode:
|
220
|
-
"""Create a Program node from serialized data."""
|
221
|
-
body = [self._deserialize_value(stmt) for stmt in data.get("body", [])]
|
222
|
-
return self.node_factory.create_program(body, location)
|
223
|
-
|
224
|
-
def _create_functioncall(self, data: Dict[str, Any],
|
225
|
-
location: Optional[SourceLocation]) -> IAstNode:
|
226
|
-
"""Create a FunctionCall node from serialized data."""
|
227
|
-
function = self._deserialize_value(data.get("function"))
|
228
|
-
args = [self._deserialize_value(arg) for arg in data.get("args", [])]
|
229
|
-
keywords = [self._deserialize_value(kw) for kw in data.get("keywords", [])]
|
230
|
-
return self.node_factory.create_function_call(function, args, keywords, location)
|
231
|
-
|
232
|
-
def _create_conditionalexpression(self, data: Dict[str, Any],
|
233
|
-
location: Optional[SourceLocation]) -> IAstNode:
|
234
|
-
"""Create a ConditionalExpression node from serialized data."""
|
235
|
-
condition = self._deserialize_value(data.get("condition"))
|
236
|
-
true_expr = self._deserialize_value(data.get("true_expr"))
|
237
|
-
false_expr = self._deserialize_value(data.get("false_expr"))
|
238
|
-
return self.node_factory.create_conditional_expression(condition, true_expr, false_expr, location)
|
239
|
-
|
240
|
-
def _create_ifstatement(self, data: Dict[str, Any],
|
241
|
-
location: Optional[SourceLocation]) -> IAstNode:
|
242
|
-
"""Create an IfStatement node from serialized data."""
|
243
|
-
test = self._deserialize_value(data.get("test"))
|
244
|
-
body = [self._deserialize_value(stmt) for stmt in data.get("body", [])]
|
245
|
-
orelse = None
|
246
|
-
if "orelse" in data:
|
247
|
-
orelse_data = data["orelse"]
|
248
|
-
if isinstance(orelse_data, list):
|
249
|
-
orelse = [self._deserialize_value(stmt) for stmt in orelse_data]
|
250
|
-
else:
|
251
|
-
orelse = self._deserialize_value(orelse_data)
|
252
|
-
return self.node_factory.create_if_statement(test, body, orelse, location)
|
253
|
-
|
254
|
-
|
255
|
-
def deserialize_ast_from_dict(data: Dict[str, Any],
|
256
|
-
error_handler: Optional[ErrorHandler] = None) -> IAstNode:
|
257
|
-
"""
|
258
|
-
Create an AST from a dictionary representation.
|
259
|
-
|
260
|
-
Args:
|
261
|
-
data: Dictionary representation of an AST
|
262
|
-
error_handler: Optional error handler for reporting deserialization issues
|
263
|
-
|
264
|
-
Returns:
|
265
|
-
The reconstructed AST
|
266
|
-
"""
|
267
|
-
factory = DeserializationFactory(error_handler)
|
268
|
-
return factory.deserialize_node(data)
|
269
|
-
|
270
|
-
|
271
|
-
def deserialize_ast_from_json(json_str: str,
|
272
|
-
error_handler: Optional[ErrorHandler] = None) -> IAstNode:
|
273
|
-
"""
|
274
|
-
Create an AST from a JSON string.
|
275
|
-
|
276
|
-
Args:
|
277
|
-
json_str: JSON string representation of an AST
|
278
|
-
error_handler: Optional error handler for reporting deserialization issues
|
279
|
-
|
280
|
-
Returns:
|
281
|
-
The reconstructed AST
|
282
|
-
"""
|
283
|
-
data = json.loads(json_str)
|
284
|
-
return deserialize_ast_from_dict(data, error_handler)
|
1
|
+
"""
|
2
|
+
JSON deserialization for AST nodes.
|
3
|
+
|
4
|
+
This module provides functionality to convert JSON data back to AST nodes.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import json
|
8
|
+
from typing import Any, Dict, List, Optional, Type, Union, cast
|
9
|
+
|
10
|
+
from ..ast.interfaces import IAstNode
|
11
|
+
from ..parser.factory import NodeFactory
|
12
|
+
from ..utils.source_location import SourceLocation
|
13
|
+
from ..utils.errors import ErrorHandler, ErrorType
|
14
|
+
|
15
|
+
|
16
|
+
class DeserializationFactory:
|
17
|
+
"""
|
18
|
+
Factory for deserializing JSON data back to AST nodes.
|
19
|
+
|
20
|
+
This class uses the NodeFactory to create AST nodes from serialized data,
|
21
|
+
handling the reconstruction of the node hierarchy and parent-child relationships.
|
22
|
+
"""
|
23
|
+
|
24
|
+
def __init__(self, error_handler: Optional[ErrorHandler] = None):
|
25
|
+
"""
|
26
|
+
Initialize the deserialization factory.
|
27
|
+
|
28
|
+
Args:
|
29
|
+
error_handler: Optional error handler for reporting deserialization issues
|
30
|
+
"""
|
31
|
+
self.node_factory = NodeFactory(error_handler)
|
32
|
+
self.error_handler = error_handler
|
33
|
+
|
34
|
+
def deserialize_node(self, data: Dict[str, Any]) -> IAstNode:
|
35
|
+
"""
|
36
|
+
Deserialize a dictionary representation back to an AST node.
|
37
|
+
|
38
|
+
Args:
|
39
|
+
data: Dictionary representation of an AST node
|
40
|
+
|
41
|
+
Returns:
|
42
|
+
The reconstructed AST node
|
43
|
+
|
44
|
+
Raises:
|
45
|
+
ValueError: If the data is invalid or missing required fields
|
46
|
+
"""
|
47
|
+
# Extract node type
|
48
|
+
if "type" not in data:
|
49
|
+
raise ValueError("Missing 'type' field in node data")
|
50
|
+
|
51
|
+
node_type = data["type"]
|
52
|
+
|
53
|
+
# Create source location if present
|
54
|
+
location = None
|
55
|
+
if "location" in data:
|
56
|
+
location = self._deserialize_location(data["location"])
|
57
|
+
|
58
|
+
# Dispatch to appropriate creation method based on node type
|
59
|
+
method_name = f"_create_{node_type.lower()}"
|
60
|
+
if hasattr(self, method_name):
|
61
|
+
create_method = getattr(self, method_name)
|
62
|
+
node = create_method(data, location)
|
63
|
+
else:
|
64
|
+
# Fallback to generic creation if no specific method exists
|
65
|
+
node = self._create_generic_node(node_type, data, location)
|
66
|
+
|
67
|
+
return node
|
68
|
+
|
69
|
+
def _deserialize_location(self, data: Dict[str, Any]) -> SourceLocation:
|
70
|
+
"""
|
71
|
+
Deserialize a dictionary to a SourceLocation object.
|
72
|
+
|
73
|
+
Args:
|
74
|
+
data: Dictionary representation of a source location
|
75
|
+
|
76
|
+
Returns:
|
77
|
+
A SourceLocation object
|
78
|
+
"""
|
79
|
+
return SourceLocation(
|
80
|
+
line=data["line"],
|
81
|
+
column=data["column"],
|
82
|
+
end_line=data.get("end_line"),
|
83
|
+
end_column=data.get("end_column"),
|
84
|
+
filename=data.get("filename")
|
85
|
+
)
|
86
|
+
|
87
|
+
def _deserialize_value(self, value: Any) -> Any:
|
88
|
+
"""
|
89
|
+
Deserialize a value based on its type.
|
90
|
+
|
91
|
+
Args:
|
92
|
+
value: The value to deserialize
|
93
|
+
|
94
|
+
Returns:
|
95
|
+
The deserialized value
|
96
|
+
"""
|
97
|
+
# Handle None
|
98
|
+
if value is None:
|
99
|
+
return None
|
100
|
+
|
101
|
+
# Handle dictionaries (potentially nested nodes)
|
102
|
+
if isinstance(value, dict) and "type" in value:
|
103
|
+
return self.deserialize_node(value)
|
104
|
+
|
105
|
+
# Handle lists of values
|
106
|
+
if isinstance(value, list):
|
107
|
+
return [self._deserialize_value(item) for item in value]
|
108
|
+
|
109
|
+
# Handle dictionaries (not nodes)
|
110
|
+
if isinstance(value, dict):
|
111
|
+
return {k: self._deserialize_value(v) for k, v in value.items()}
|
112
|
+
|
113
|
+
# Return basic types as-is
|
114
|
+
return value
|
115
|
+
|
116
|
+
def _create_generic_node(self, node_type: str, data: Dict[str, Any],
|
117
|
+
location: Optional[SourceLocation]) -> IAstNode:
|
118
|
+
"""
|
119
|
+
Generic node creation when no specific method exists.
|
120
|
+
|
121
|
+
Args:
|
122
|
+
node_type: The type of node to create
|
123
|
+
data: Dictionary representation of the node
|
124
|
+
location: Optional source location
|
125
|
+
|
126
|
+
Returns:
|
127
|
+
The created AST node
|
128
|
+
|
129
|
+
Raises:
|
130
|
+
ValueError: If the node type is not supported
|
131
|
+
"""
|
132
|
+
# Map of node types to factory methods
|
133
|
+
factory_methods = {
|
134
|
+
# Literals
|
135
|
+
"NumberLiteral": self.node_factory.create_number_literal,
|
136
|
+
"StringLiteral": self.node_factory.create_string_literal,
|
137
|
+
"BooleanLiteral": self.node_factory.create_boolean_literal,
|
138
|
+
"NoneLiteral": self.node_factory.create_none_literal,
|
139
|
+
|
140
|
+
# Expressions
|
141
|
+
"Identifier": self.node_factory.create_identifier,
|
142
|
+
"VariableReference": self.node_factory.create_variable_reference,
|
143
|
+
"AttributeAccess": self.node_factory.create_attribute_access,
|
144
|
+
"BinaryOperation": self.node_factory.create_binary_operation,
|
145
|
+
"UnaryOperation": self.node_factory.create_unary_operation,
|
146
|
+
"ConditionalExpression": self.node_factory.create_conditional_expression,
|
147
|
+
"FunctionCall": self.node_factory.create_function_call,
|
148
|
+
"KeywordArgument": self.node_factory.create_keyword_argument,
|
149
|
+
|
150
|
+
# Statements
|
151
|
+
"ExpressionStatement": self.node_factory.create_expression_statement,
|
152
|
+
"Assignment": self.node_factory.create_assignment,
|
153
|
+
"IfStatement": self.node_factory.create_if_statement,
|
154
|
+
"WhileLoop": self.node_factory.create_while_loop,
|
155
|
+
"ForLoop": self.node_factory.create_for_loop,
|
156
|
+
"FunctionDefinition": self.node_factory.create_function_definition,
|
157
|
+
"Argument": self.node_factory.create_argument,
|
158
|
+
"ReturnStatement": self.node_factory.create_return_statement,
|
159
|
+
"BreakStatement": self.node_factory.create_break_statement,
|
160
|
+
"ContinueStatement": self.node_factory.create_continue_statement,
|
161
|
+
|
162
|
+
# VEX-specific nodes
|
163
|
+
"VexAPICall": self.node_factory.create_vex_api_call,
|
164
|
+
"MotorControl": self.node_factory.create_motor_control,
|
165
|
+
"SensorReading": self.node_factory.create_sensor_reading,
|
166
|
+
"TimingControl": self.node_factory.create_timing_control,
|
167
|
+
"DisplayOutput": self.node_factory.create_display_output,
|
168
|
+
|
169
|
+
# Core
|
170
|
+
"Program": self.node_factory.create_program,
|
171
|
+
}
|
172
|
+
|
173
|
+
if node_type not in factory_methods:
|
174
|
+
raise ValueError(f"Unsupported node type: {node_type}")
|
175
|
+
|
176
|
+
# Extract and deserialize attributes
|
177
|
+
kwargs = {}
|
178
|
+
for key, value in data.items():
|
179
|
+
if key not in ["type", "location"]:
|
180
|
+
kwargs[key] = self._deserialize_value(value)
|
181
|
+
|
182
|
+
# Create the node using the appropriate factory method
|
183
|
+
factory_method = factory_methods[node_type]
|
184
|
+
|
185
|
+
# Special handling for certain node types
|
186
|
+
if node_type == "Program":
|
187
|
+
return factory_method(kwargs.get("body", []), location)
|
188
|
+
elif node_type in ["NumberLiteral", "StringLiteral", "BooleanLiteral"]:
|
189
|
+
return factory_method(kwargs.get("value"), location)
|
190
|
+
elif node_type == "NoneLiteral":
|
191
|
+
return factory_method(location)
|
192
|
+
elif node_type == "Identifier":
|
193
|
+
return factory_method(kwargs.get("name", ""), location)
|
194
|
+
|
195
|
+
# For other node types, pass all kwargs and location
|
196
|
+
# This is a simplified approach; in a real implementation,
|
197
|
+
# you would need to handle each node type specifically
|
198
|
+
try:
|
199
|
+
return factory_method(**kwargs, location=location)
|
200
|
+
except TypeError as e:
|
201
|
+
# If the factory method doesn't accept the kwargs, report an error
|
202
|
+
if self.error_handler:
|
203
|
+
self.error_handler.add_error(
|
204
|
+
error_type=ErrorType.INTERNAL_ERROR,
|
205
|
+
message=f"Failed to create {node_type}: {str(e)}"
|
206
|
+
)
|
207
|
+
raise ValueError(f"Failed to deserialize {node_type}: {str(e)}")
|
208
|
+
|
209
|
+
# Specific node creation methods for complex cases
|
210
|
+
|
211
|
+
def _create_attributeaccess(self, data: Dict[str, Any],
|
212
|
+
location: Optional[SourceLocation]) -> IAstNode:
|
213
|
+
"""Create an AttributeAccess node from serialized data."""
|
214
|
+
object_expr = self._deserialize_value(data.get("object"))
|
215
|
+
attribute = data.get("attribute", "")
|
216
|
+
return self.node_factory.create_attribute_access(object_expr, attribute, location)
|
217
|
+
|
218
|
+
def _create_program(self, data: Dict[str, Any],
|
219
|
+
location: Optional[SourceLocation]) -> IAstNode:
|
220
|
+
"""Create a Program node from serialized data."""
|
221
|
+
body = [self._deserialize_value(stmt) for stmt in data.get("body", [])]
|
222
|
+
return self.node_factory.create_program(body, location)
|
223
|
+
|
224
|
+
def _create_functioncall(self, data: Dict[str, Any],
|
225
|
+
location: Optional[SourceLocation]) -> IAstNode:
|
226
|
+
"""Create a FunctionCall node from serialized data."""
|
227
|
+
function = self._deserialize_value(data.get("function"))
|
228
|
+
args = [self._deserialize_value(arg) for arg in data.get("args", [])]
|
229
|
+
keywords = [self._deserialize_value(kw) for kw in data.get("keywords", [])]
|
230
|
+
return self.node_factory.create_function_call(function, args, keywords, location)
|
231
|
+
|
232
|
+
def _create_conditionalexpression(self, data: Dict[str, Any],
|
233
|
+
location: Optional[SourceLocation]) -> IAstNode:
|
234
|
+
"""Create a ConditionalExpression node from serialized data."""
|
235
|
+
condition = self._deserialize_value(data.get("condition"))
|
236
|
+
true_expr = self._deserialize_value(data.get("true_expr"))
|
237
|
+
false_expr = self._deserialize_value(data.get("false_expr"))
|
238
|
+
return self.node_factory.create_conditional_expression(condition, true_expr, false_expr, location)
|
239
|
+
|
240
|
+
def _create_ifstatement(self, data: Dict[str, Any],
|
241
|
+
location: Optional[SourceLocation]) -> IAstNode:
|
242
|
+
"""Create an IfStatement node from serialized data."""
|
243
|
+
test = self._deserialize_value(data.get("test"))
|
244
|
+
body = [self._deserialize_value(stmt) for stmt in data.get("body", [])]
|
245
|
+
orelse = None
|
246
|
+
if "orelse" in data:
|
247
|
+
orelse_data = data["orelse"]
|
248
|
+
if isinstance(orelse_data, list):
|
249
|
+
orelse = [self._deserialize_value(stmt) for stmt in orelse_data]
|
250
|
+
else:
|
251
|
+
orelse = self._deserialize_value(orelse_data)
|
252
|
+
return self.node_factory.create_if_statement(test, body, orelse, location)
|
253
|
+
|
254
|
+
|
255
|
+
def deserialize_ast_from_dict(data: Dict[str, Any],
|
256
|
+
error_handler: Optional[ErrorHandler] = None) -> IAstNode:
|
257
|
+
"""
|
258
|
+
Create an AST from a dictionary representation.
|
259
|
+
|
260
|
+
Args:
|
261
|
+
data: Dictionary representation of an AST
|
262
|
+
error_handler: Optional error handler for reporting deserialization issues
|
263
|
+
|
264
|
+
Returns:
|
265
|
+
The reconstructed AST
|
266
|
+
"""
|
267
|
+
factory = DeserializationFactory(error_handler)
|
268
|
+
return factory.deserialize_node(data)
|
269
|
+
|
270
|
+
|
271
|
+
def deserialize_ast_from_json(json_str: str,
|
272
|
+
error_handler: Optional[ErrorHandler] = None) -> IAstNode:
|
273
|
+
"""
|
274
|
+
Create an AST from a JSON string.
|
275
|
+
|
276
|
+
Args:
|
277
|
+
json_str: JSON string representation of an AST
|
278
|
+
error_handler: Optional error handler for reporting deserialization issues
|
279
|
+
|
280
|
+
Returns:
|
281
|
+
The reconstructed AST
|
282
|
+
"""
|
283
|
+
data = json.loads(json_str)
|
284
|
+
return deserialize_ast_from_dict(data, error_handler)
|