vex-ast 0.2.5__py3-none-any.whl → 0.2.7__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.
Files changed (63) hide show
  1. vex_ast/README.md +101 -51
  2. vex_ast/READMEAPI.md +133 -318
  3. vex_ast/__init__.py +81 -81
  4. vex_ast/ast/README.md +87 -87
  5. vex_ast/ast/__init__.py +74 -74
  6. vex_ast/ast/core.py +71 -71
  7. vex_ast/ast/expressions.py +276 -276
  8. vex_ast/ast/interfaces.py +208 -208
  9. vex_ast/ast/literals.py +80 -80
  10. vex_ast/ast/navigator.py +241 -225
  11. vex_ast/ast/operators.py +135 -135
  12. vex_ast/ast/statements.py +351 -351
  13. vex_ast/ast/validators.py +121 -121
  14. vex_ast/ast/vex_nodes.py +279 -279
  15. vex_ast/parser/README.md +47 -47
  16. vex_ast/parser/__init__.py +26 -26
  17. vex_ast/parser/factory.py +190 -190
  18. vex_ast/parser/interfaces.py +34 -34
  19. vex_ast/parser/python_parser.py +831 -831
  20. vex_ast/registry/README.md +107 -29
  21. vex_ast/registry/__init__.py +51 -51
  22. vex_ast/registry/api.py +190 -155
  23. vex_ast/registry/categories.py +179 -136
  24. vex_ast/registry/functions/__init__.py +10 -10
  25. vex_ast/registry/functions/constructors.py +71 -35
  26. vex_ast/registry/functions/display.py +146 -146
  27. vex_ast/registry/functions/drivetrain.py +163 -163
  28. vex_ast/registry/functions/initialize.py +31 -31
  29. vex_ast/registry/functions/motor.py +140 -140
  30. vex_ast/registry/functions/sensors.py +194 -194
  31. vex_ast/registry/functions/timing.py +103 -103
  32. vex_ast/registry/language_map.py +77 -77
  33. vex_ast/registry/registry.py +164 -153
  34. vex_ast/registry/signature.py +269 -191
  35. vex_ast/registry/simulation_behavior.py +8 -8
  36. vex_ast/registry/validation.py +43 -43
  37. vex_ast/serialization/__init__.py +37 -37
  38. vex_ast/serialization/json_deserializer.py +284 -284
  39. vex_ast/serialization/json_serializer.py +148 -148
  40. vex_ast/serialization/schema.py +492 -492
  41. vex_ast/types/README.md +78 -26
  42. vex_ast/types/__init__.py +140 -140
  43. vex_ast/types/base.py +83 -83
  44. vex_ast/types/enums.py +122 -122
  45. vex_ast/types/objects.py +64 -64
  46. vex_ast/types/primitives.py +68 -68
  47. vex_ast/types/type_checker.py +31 -31
  48. vex_ast/utils/README.md +39 -39
  49. vex_ast/utils/__init__.py +37 -37
  50. vex_ast/utils/errors.py +112 -112
  51. vex_ast/utils/source_location.py +38 -38
  52. vex_ast/utils/type_definitions.py +8 -8
  53. vex_ast/visitors/README.md +49 -49
  54. vex_ast/visitors/__init__.py +27 -27
  55. vex_ast/visitors/analyzer.py +102 -102
  56. vex_ast/visitors/base.py +133 -133
  57. vex_ast/visitors/printer.py +196 -196
  58. {vex_ast-0.2.5.dist-info → vex_ast-0.2.7.dist-info}/METADATA +206 -174
  59. vex_ast-0.2.7.dist-info/RECORD +64 -0
  60. vex_ast-0.2.5.dist-info/RECORD +0 -64
  61. {vex_ast-0.2.5.dist-info → vex_ast-0.2.7.dist-info}/WHEEL +0 -0
  62. {vex_ast-0.2.5.dist-info → vex_ast-0.2.7.dist-info}/licenses/LICENSE +0 -0
  63. {vex_ast-0.2.5.dist-info → vex_ast-0.2.7.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)